Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM soc device tree updates from Olof Johansson:
 "Device tree conversion and enablement branch.  Mostly a bunch of new
  bindings and setup for various platforms, but the Via/Winchip VT8500
  platform is also converted over from being 100% legacy to now use
  device tree for probing.  More of that will come for 3.8."

Trivial conflicts due to removal of vt8500 files, and one documentation
file that was added with slightly different contents both here and in
the USb tree.

* tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (212 commits)
  arm: vt8500: Fixup for missing gpio.h
  ARM: LPC32xx: LED fix in PHY3250 DTS file
  ARM: dt: mmp-dma: add binding file
  arm: vt8500: Update arch-vt8500 to devicetree support.
  arm: vt8500: gpio: Devicetree support for arch-vt8500
  arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices
  arm: vt8500: clk: Add Common Clock Framework support
  video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb
  serial: vt8500: Add devicetree support for vt8500-serial
  rtc: vt8500: Add devicetree support for vt8500-rtc
  arm: vt8500: Add device tree files for VIA/Wondermedia SoC's
  ARM: tegra: Add Avionic Design Tamonten Evaluation Carrier support
  ARM: tegra: Add Avionic Design Medcom-Wide support
  ARM: tegra: Add Avionic Design Plutux support
  ARM: tegra: Add Avionic Design Tamonten support
  ARM: tegra: dts: Add pwm label
  ARM: ux500: Fix SSP register address format
  ARM: ux500: Apply tc3589x's GPIO/IRQ properties to HREF's DT
  ARM: ux500: Remove redundant #gpio-cell properties from Snowball DT
  ARM: ux500: Add all encompassing sound node to the HREF Device Tree
  ...
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 5f75f8f..b6fbe51 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -220,3 +220,10 @@
 		If the device doesn't support LTM, the file will read "no".
 		The file will be present for all speeds of USB devices, and will
 		always read "no" for USB 1.1 and USB 2.0 devices.
+
+What:		/sys/bus/usb/devices/.../(hub interface)/portX
+Date:		August 2012
+Contact:	Lan Tianyu <tianyu.lan@intel.com>
+Description:
+		The /sys/bus/usb/devices/.../(hub interface)/portX
+		is usb port device's sysfs directory.
diff --git a/Documentation/ABI/testing/sysfs-class-extcon b/Documentation/ABI/testing/sysfs-class-extcon
index 20ab361..57a7262 100644
--- a/Documentation/ABI/testing/sysfs-class-extcon
+++ b/Documentation/ABI/testing/sysfs-class-extcon
@@ -13,7 +13,7 @@
 		accessory cables have such capability. For example,
 		the 30-pin port of Nuri board (/arch/arm/mach-exynos)
 		may have both HDMI and Charger attached, or analog audio,
-		video, and USB cables attached simulteneously.
+		video, and USB cables attached simultaneously.
 
 		If there are cables mutually exclusive with each other,
 		such binary relations may be expressed with extcon_dev's
@@ -35,7 +35,7 @@
 		The /sys/class/extcon/.../state shows and stores the cable
 		attach/detach information of the corresponding extcon object.
 		If the extcon object has an optional callback "show_state"
-		defined, the showing function is overriden with the optional
+		defined, the showing function is overridden with the optional
 		callback.
 
 		If the default callback for showing function is used, the
@@ -46,19 +46,19 @@
 		TA=1
 		EAR_JACK=0
 		#
-		In this example, the extcon device have USB_OTG and TA
+		In this example, the extcon device has USB_OTG and TA
 		cables attached and HDMI and EAR_JACK cables detached.
 
 		In order to update the state of an extcon device, enter a hex
-		state number starting with 0x.
-		 echo 0xHEX > state
+		state number starting with 0x:
+		# echo 0xHEX > state
 
-		This updates the whole state of the extcon dev.
+		This updates the whole state of the extcon device.
 		Inputs of all the methods are required to meet the
-		mutually_exclusive contidions if they exist.
+		mutually_exclusive conditions if they exist.
 
 		It is recommended to use this "global" state interface if
-		you need to enter the value atomically. The later state
+		you need to set the value atomically. The later state
 		interface associated with each cable cannot update
 		multiple cable states of an extcon device simultaneously.
 
@@ -73,7 +73,7 @@
 Date:		February 2012
 Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
 Description:
-		The /sys/class/extcon/.../cable.x/name shows and stores the
+		The /sys/class/extcon/.../cable.x/state shows and stores the
 		state of cable "x" (integer between 0 and 31) of an extcon
 		device. The state value is either 0 (detached) or 1
 		(attached).
@@ -83,8 +83,8 @@
 Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
 Description:
 		Shows the relations of mutually exclusiveness. For example,
-		if the mutually_exclusive array of extcon_dev is
-		{0x3, 0x5, 0xC, 0x0}, the, the output is:
+		if the mutually_exclusive array of extcon device is
+		{0x3, 0x5, 0xC, 0x0}, then the output is:
 		# ls mutually_exclusive/
 		0x3
 		0x5
diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
index e091fa8..bc578bc 100644
--- a/Documentation/ABI/testing/sysfs-class-regulator
+++ b/Documentation/ABI/testing/sysfs-class-regulator
@@ -349,3 +349,24 @@
 
 		This will be one of the same strings reported by
 		the "state" attribute.
+
+What:		/sys/class/regulator/.../bypass
+Date:		September 2012
+KernelVersion:	3.7
+Contact:	Mark Brown <broonie@opensource.wolfsonmicro.com>
+Description:
+		Some regulator directories will contain a field called
+		bypass.  This indicates if the device is in bypass mode.
+
+		This will be one of the following strings:
+
+		'enabled'
+		'disabled'
+		'unknown'
+
+		'enabled' means the regulator is in bypass mode.
+
+		'disabled' means that the regulator is regulating.
+
+		'unknown' means software cannot determine the state, or
+		the reported state is invalid.
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index 8d55a83..7fc7810 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -1,3 +1,16 @@
+WWhat:		/sys/class/hidraw/hidraw*/device/oled*_img
+Date:		June 2012
+Contact:	linux-bluetooth@vger.kernel.org
+Description:
+		The /sys/class/hidraw/hidraw*/device/oled*_img files control
+		OLED mocro displays on Intuos4 Wireless tablet. Accepted image
+		has to contain 256 bytes (64x32 px 1 bit colour). The format
+		is the same as PBM image 62x32px without header (64 bits per
+		horizontal line, 32 lines). An example of setting OLED No. 0:
+		dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img
+		The attribute is read only and no local copy of the image is
+		stored.
+
 What:		/sys/class/hidraw/hidraw*/device/speed
 Date:		April 2010
 Kernel Version:	2.6.35
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index fc103d7..cdb20d4 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -310,6 +310,12 @@
 	code under the influence of preempt_disable(), you instead
 	need to use synchronize_irq() or synchronize_sched().
 
+	This same limitation also applies to synchronize_rcu_bh()
+	and synchronize_srcu(), as well as to the asynchronous and
+	expedited forms of the three primitives, namely call_rcu(),
+	call_rcu_bh(), call_srcu(), synchronize_rcu_expedited(),
+	synchronize_rcu_bh_expedited(), and synchronize_srcu_expedited().
+
 12.	Any lock acquired by an RCU callback must be acquired elsewhere
 	with softirq disabled, e.g., via spin_lock_irqsave(),
 	spin_lock_bh(), etc.  Failing to disable irq on a given
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index 523364e..1927151 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -99,7 +99,7 @@
 printed:
 
 	INFO: rcu_preempt detected stall on CPU
-	0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer=-1
+	0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer not pending
 	   (t=65000 jiffies)
 
 The "(64628 ticks this GP)" indicates that this CPU has taken more
@@ -116,13 +116,13 @@
 be a small positive number if in the idle loop and a very large positive
 number (as shown above) otherwise.
 
-For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the
-CPU is not in the process of trying to force itself into dyntick-idle
-state, the "." indicates that the CPU has not given up forcing RCU
-into dyntick-idle mode (it would be "H" otherwise), and the "timer=-1"
-indicates that the CPU has not recented forced RCU into dyntick-idle
-mode (it would otherwise indicate the number of microseconds remaining
-in this forced state).
+For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the CPU is
+not in the process of trying to force itself into dyntick-idle state, the
+"." indicates that the CPU has not given up forcing RCU into dyntick-idle
+mode (it would be "H" otherwise), and the "timer not pending" indicates
+that the CPU has not recently forced RCU into dyntick-idle mode (it
+would otherwise indicate the number of microseconds remaining in this
+forced state).
 
 
 Multiple Warnings From One Stall
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index f6f15ce..672d190 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -333,23 +333,23 @@
 The output of "cat rcu/rcu_pending" looks as follows:
 
 rcu_sched:
-  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741
-  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792
-  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629
-  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723
-  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110
-  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456
-  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834
-  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888
+  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nn=146741
+  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nn=155792
+  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nn=136629
+  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nn=137723
+  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nn=123110
+  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nn=137456
+  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nn=120834
+  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nn=144888
 rcu_bh:
-  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314
-  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180
-  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936
-  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863
-  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671
-  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235
-  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
-  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
+  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nn=145314
+  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nn=143180
+  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nn=117936
+  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nn=134863
+  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nn=110671
+  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nn=133235
+  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nn=110921
+  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nn=118542
 
 As always, this is once again split into "rcu_sched" and "rcu_bh"
 portions, with CONFIG_TREE_PREEMPT_RCU kernels having an additional
@@ -377,17 +377,6 @@
 o	"gps" is the number of times that a new grace period had started,
 	but this CPU was not yet aware of it.
 
-o	"nf" is the number of times that this CPU suspected that the
-	current grace period had run for too long, and thus needed to
-	be forced.
-
-	Please note that "forcing" consists of sending resched IPIs
-	to holdout CPUs.  If that CPU really still is in an old RCU
-	read-side critical section, then we really do have to wait for it.
-	The assumption behing "forcing" is that the CPU is not still in
-	an old RCU read-side critical section, but has not yet responded
-	for some other reason.
-
 o	"nn" is the number of times that this CPU needed nothing.  Alert
 	readers will note that the rcu "nn" number for a given CPU very
 	closely matches the rcu_bh "np" number for that same CPU.  This
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 69ee188..bf0f6de 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -873,7 +873,7 @@
 	and code segments with preemption disabled (whether
 	via preempt_disable(), local_irq_save(), local_bh_disable(),
 	or some other mechanism) as if they were explicit RCU readers?
-	If so, you need RCU-sched.
+	If so, RCU-sched is the only choice that will work for you.
 
 e.	Do you need RCU grace periods to complete even in the face
 	of softirq monopolization of one or more of the CPUs?  For
@@ -884,7 +884,12 @@
 	RCU, but inappropriate for other synchronization mechanisms?
 	If so, consider SLAB_DESTROY_BY_RCU.  But please be careful!
 
-g.	Otherwise, use RCU.
+g.	Do you need read-side critical sections that are respected
+	even though they are in the middle of the idle loop, during
+	user-mode execution, or on an offlined CPU?  If so, SRCU is the
+	only choice that will work for you.
+
+h.	Otherwise, use RCU.
 
 Of course, this all assumes that you have determined that RCU is in fact
 the right tool for your job.
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index f6318f6..6f706ac 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -98,10 +98,9 @@
 	if (rcvbufsz)
 		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
 				&rcvbufsz, sizeof(rcvbufsz)) < 0) {
-			fprintf(stderr, "Unable to set socket rcv buf size "
-					"to %d\n",
+			fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
 				rcvbufsz);
-			return -1;
+			goto error;
 		}
 
 	memset(&local, 0, sizeof(local));
diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
index 816d607..8b46c79 100644
--- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt
+++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
@@ -1,4 +1,4 @@
-			S3C2410 GPIO Control
+			S3C24XX GPIO Control
 			====================
 
 Introduction
@@ -12,7 +12,7 @@
   of the s3c2410 GPIO system, please read the Samsung provided
   data-sheet/users manual to find out the complete list.
 
-  See Documentation/arm/Samsung/GPIO.txt for the core implemetation.
+  See Documentation/arm/Samsung/GPIO.txt for the core implementation.
 
 
 GPIOLIB
@@ -41,8 +41,8 @@
 GPIOLIB conversion
 ------------------
 
-If you need to convert your board or driver to use gpiolib from the exiting
-s3c2410 api, then here are some notes on the process.
+If you need to convert your board or driver to use gpiolib from the phased
+out s3c2410 API, then here are some notes on the process.
 
 1) If your board is exclusively using an GPIO, say to control peripheral
    power, then it will require to claim the gpio with gpio_request() before
@@ -55,7 +55,7 @@
    as they have the same arguments, and can either take the pin specific
    values, or the more generic special-function-number arguments.
 
-3) s3c2410_gpio_pullup() changs have the problem that whilst the 
+3) s3c2410_gpio_pullup() changes have the problem that whilst the
    s3c2410_gpio_pullup(x, 1) can be easily translated to the
    s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0)
    are not so easy.
@@ -74,7 +74,7 @@
    when using gpio_get_value() on an output pin (s3c2410_gpio_getpin
    would return the value the pin is supposed to be outputting).
 
-6) s3c2410_gpio_getirq() should be directly replacable with the
+6) s3c2410_gpio_getirq() should be directly replaceable with the
    gpio_to_irq() call.
 
 The s3c2410_gpio and gpio_ calls have always operated on the same gpio
@@ -105,7 +105,7 @@
 -----------
 
   Each pin has an unique number associated with it in regs-gpio.h,
-  eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
+  e.g. S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
   the GPIO functions which pin is to be used.
 
   With the conversion to gpiolib, there is no longer a direct conversion
@@ -120,31 +120,27 @@
   The following function allows the configuration of a given pin to
   be changed.
 
-    void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
+    void s3c_gpio_cfgpin(unsigned int pin, unsigned int function);
 
-  Eg:
+  e.g.:
 
-     s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
-     s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
+     s3c_gpio_cfgpin(S3C2410_GPA(0), S3C_GPIO_SFN(1));
+     s3c_gpio_cfgpin(S3C2410_GPE(8), S3C_GPIO_SFN(2));
 
    which would turn GPA(0) into the lowest Address line A0, and set
    GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
 
-   The s3c_gpio_cfgpin() call is a functional replacement for this call.
-
 
 Reading the current configuration
 ---------------------------------
 
-  The current configuration of a pin can be read by using:
+  The current configuration of a pin can be read by using standard
+  gpiolib function:
 
-  s3c2410_gpio_getcfg(unsigned int pin);
+  s3c_gpio_getcfg(unsigned int pin);
 
   The return value will be from the same set of values which can be
-  passed to s3c2410_gpio_cfgpin().
-
-  The s3c_gpio_getcfg() call should be a functional replacement for
-  this call.
+  passed to s3c_gpio_cfgpin().
 
 
 Configuring a pull-up resistor
@@ -154,61 +150,33 @@
   pull-up resistors enabled. This can be configured by the following
   function:
 
-    void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
+    void s3c_gpio_setpull(unsigned int pin, unsigned int to);
 
-  Where the to value is zero to set the pull-up off, and 1 to enable
-  the specified pull-up. Any other values are currently undefined.
-
-  The s3c_gpio_setpull() offers similar functionality, but with the
-  ability to encode whether the pull is up or down. Currently there
-  is no 'just on' state, so up or down must be selected.
+  Where the to value is S3C_GPIO_PULL_NONE to set the pull-up off,
+  and S3C_GPIO_PULL_UP to enable the specified pull-up. Any other
+  values are currently undefined.
 
 
-Getting the state of a PIN
---------------------------
+Getting and setting the state of a PIN
+--------------------------------------
 
-  The state of a pin can be read by using the function:
-
-    unsigned int s3c2410_gpio_getpin(unsigned int pin);
-
-  This will return either zero or non-zero. Do not count on this
-  function returning 1 if the pin is set.
-
-  This call is now implemented by the relevant gpiolib calls, convert
-  your board or driver to use gpiolib.
-
-
-Setting the state of a PIN
---------------------------
-
-  The value an pin is outputing can be modified by using the following:
-
-    void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
-
-  Which sets the given pin to the value. Use 0 to write 0, and 1 to
-  set the output to 1.
-
-  This call is now implemented by the relevant gpiolib calls, convert
+  These calls are now implemented by the relevant gpiolib calls, convert
   your board or driver to use gpiolib.
 
 
 Getting the IRQ number associated with a PIN
 --------------------------------------------
 
-  The following function can map the given pin number to an IRQ
+  A standard gpiolib function can map the given pin number to an IRQ
   number to pass to the IRQ system.
 
-   int s3c2410_gpio_getirq(unsigned int pin);
+   int gpio_to_irq(unsigned int pin);
 
   Note, not all pins have an IRQ.
 
-  This call is now implemented by the relevant gpiolib calls, convert
-  your board or driver to use gpiolib.
 
-
-Authour
+Author
 -------
 
-
 Ben Dooks, 03 October 2004
 Copyright 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/Samsung/GPIO.txt b/Documentation/arm/Samsung/GPIO.txt
index 513f256..795adfd 100644
--- a/Documentation/arm/Samsung/GPIO.txt
+++ b/Documentation/arm/Samsung/GPIO.txt
@@ -5,14 +5,14 @@
 ------------
 
 This outlines the Samsung GPIO implementation and the architecture
-specific calls provided alongisde the drivers/gpio core.
+specific calls provided alongside the drivers/gpio core.
 
 
 S3C24XX (Legacy)
 ----------------
 
 See Documentation/arm/Samsung-S3C24XX/GPIO.txt for more information
-about these devices. Their implementation is being brought into line
+about these devices. Their implementation has been brought into line
 with the core samsung implementation described in this document.
 
 
@@ -29,7 +29,7 @@
 PIN configuration
 -----------------
 
-Pin configuration is specific to the Samsung architecutre, with each SoC
+Pin configuration is specific to the Samsung architecture, with each SoC
 registering the necessary information for the core gpio configuration
 implementation to configure pins as necessary.
 
@@ -38,5 +38,3 @@
 
 See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
 on these functions.
-
-
diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
index 208a2d4..4bfb9ff 100644
--- a/Documentation/arm/memory.txt
+++ b/Documentation/arm/memory.txt
@@ -51,6 +51,9 @@
 ff000000	ffbfffff	Reserved for future expansion of DMA
 				mapping region.
 
+fee00000	feffffff	Mapping of PCI I/O space. This is a static
+				mapping within the vmalloc space.
+
 VMALLOC_START	VMALLOC_END-1	vmalloc() / ioremap() space.
 				Memory returned by vmalloc/ioremap will
 				be dynamically placed in this region.
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
new file mode 100644
index 0000000..9c4d388
--- /dev/null
+++ b/Documentation/arm64/booting.txt
@@ -0,0 +1,152 @@
+			Booting AArch64 Linux
+			=====================
+
+Author: Will Deacon <will.deacon@arm.com>
+Date  : 07 September 2012
+
+This document is based on the ARM booting document by Russell King and
+is relevant to all public releases of the AArch64 Linux kernel.
+
+The AArch64 exception model is made up of a number of exception levels
+(EL0 - EL3), with EL0 and EL1 having a secure and a non-secure
+counterpart.  EL2 is the hypervisor level and exists only in non-secure
+mode. EL3 is the highest priority level and exists only in secure mode.
+
+For the purposes of this document, we will use the term `boot loader'
+simply to define all software that executes on the CPU(s) before control
+is passed to the Linux kernel.  This may include secure monitor and
+hypervisor code, or it may just be a handful of instructions for
+preparing a minimal boot environment.
+
+Essentially, the boot loader should provide (as a minimum) the
+following:
+
+1. Setup and initialise the RAM
+2. Setup the device tree
+3. Decompress the kernel image
+4. Call the kernel image
+
+
+1. Setup and initialise RAM
+---------------------------
+
+Requirement: MANDATORY
+
+The boot loader is expected to find and initialise all RAM that the
+kernel will use for volatile data storage in the system.  It performs
+this in a machine dependent manner.  (It may use internal algorithms
+to automatically locate and size all RAM, or it may use knowledge of
+the RAM in the machine, or any other method the boot loader designer
+sees fit.)
+
+
+2. Setup the device tree
+-------------------------
+
+Requirement: MANDATORY
+
+The device tree blob (dtb) must be no bigger than 2 megabytes in size
+and placed at a 2-megabyte boundary within the first 512 megabytes from
+the start of the kernel image. This is to allow the kernel to map the
+blob using a single section mapping in the initial page tables.
+
+
+3. Decompress the kernel image
+------------------------------
+
+Requirement: OPTIONAL
+
+The AArch64 kernel does not currently provide a decompressor and
+therefore requires decompression (gzip etc.) to be performed by the boot
+loader if a compressed Image target (e.g. Image.gz) is used.  For
+bootloaders that do not implement this requirement, the uncompressed
+Image target is available instead.
+
+
+4. Call the kernel image
+------------------------
+
+Requirement: MANDATORY
+
+The decompressed kernel image contains a 32-byte header as follows:
+
+  u32 magic	= 0x14000008;	/* branch to stext, little-endian */
+  u32 res0	= 0;		/* reserved */
+  u64 text_offset;		/* Image load offset */
+  u64 res1	= 0;		/* reserved */
+  u64 res2	= 0;		/* reserved */
+
+The image must be placed at the specified offset (currently 0x80000)
+from the start of the system RAM and called there. The start of the
+system RAM must be aligned to 2MB.
+
+Before jumping into the kernel, the following conditions must be met:
+
+- Quiesce all DMA capable devices so that memory does not get
+  corrupted by bogus network packets or disk data.  This will save
+  you many hours of debug.
+
+- Primary CPU general-purpose register settings
+  x0 = physical address of device tree blob (dtb) in system RAM.
+  x1 = 0 (reserved for future use)
+  x2 = 0 (reserved for future use)
+  x3 = 0 (reserved for future use)
+
+- CPU mode
+  All forms of interrupts must be masked in PSTATE.DAIF (Debug, SError,
+  IRQ and FIQ).
+  The CPU must be in either EL2 (RECOMMENDED in order to have access to
+  the virtualisation extensions) or non-secure EL1.
+
+- Caches, MMUs
+  The MMU must be off.
+  Instruction cache may be on or off.
+  Data cache must be off and invalidated.
+  External caches (if present) must be configured and disabled.
+
+- Architected timers
+  CNTFRQ must be programmed with the timer frequency.
+  If entering the kernel at EL1, CNTHCTL_EL2 must have EL1PCTEN (bit 0)
+  set where available.
+
+- Coherency
+  All CPUs to be booted by the kernel must be part of the same coherency
+  domain on entry to the kernel.  This may require IMPLEMENTATION DEFINED
+  initialisation to enable the receiving of maintenance operations on
+  each CPU.
+
+- System registers
+  All writable architected system registers at the exception level where
+  the kernel image will be entered must be initialised by software at a
+  higher exception level to prevent execution in an UNKNOWN state.
+
+The boot loader is expected to enter the kernel on each CPU in the
+following manner:
+
+- The primary CPU must jump directly to the first instruction of the
+  kernel image.  The device tree blob passed by this CPU must contain
+  for each CPU node:
+
+    1. An 'enable-method' property. Currently, the only supported value
+       for this field is the string "spin-table".
+
+    2. A 'cpu-release-addr' property identifying a 64-bit,
+       zero-initialised memory location.
+
+  It is expected that the bootloader will generate these device tree
+  properties and insert them into the blob prior to kernel entry.
+
+- Any secondary CPUs must spin outside of the kernel in a reserved area
+  of memory (communicated to the kernel by a /memreserve/ region in the
+  device tree) polling their cpu-release-addr location, which must be
+  contained in the reserved region.  A wfe instruction may be inserted
+  to reduce the overhead of the busy-loop and a sev will be issued by
+  the primary CPU.  When a read of the location pointed to by the
+  cpu-release-addr returns a non-zero value, the CPU must jump directly
+  to this value.
+
+- Secondary CPU general-purpose register settings
+  x0 = 0 (reserved for future use)
+  x1 = 0 (reserved for future use)
+  x2 = 0 (reserved for future use)
+  x3 = 0 (reserved for future use)
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
new file mode 100644
index 0000000..dbbdcbb
--- /dev/null
+++ b/Documentation/arm64/memory.txt
@@ -0,0 +1,73 @@
+		     Memory Layout on AArch64 Linux
+		     ==============================
+
+Author: Catalin Marinas <catalin.marinas@arm.com>
+Date  : 20 February 2012
+
+This document describes the virtual memory layout used by the AArch64
+Linux kernel. The architecture allows up to 4 levels of translation
+tables with a 4KB page size and up to 3 levels with a 64KB page size.
+
+AArch64 Linux uses 3 levels of translation tables with the 4KB page
+configuration, allowing 39-bit (512GB) virtual addresses for both user
+and kernel. With 64KB pages, only 2 levels of translation tables are
+used but the memory layout is the same.
+
+User addresses have bits 63:39 set to 0 while the kernel addresses have
+the same bits set to 1. TTBRx selection is given by bit 63 of the
+virtual address. The swapper_pg_dir contains only kernel (global)
+mappings while the user pgd contains only user (non-global) mappings.
+The swapper_pgd_dir address is written to TTBR1 and never written to
+TTBR0.
+
+
+AArch64 Linux memory layout:
+
+Start			End			Size		Use
+-----------------------------------------------------------------------
+0000000000000000	0000007fffffffff	 512GB		user
+
+ffffff8000000000	ffffffbbfffcffff	~240GB		vmalloc
+
+ffffffbbfffd0000	ffffffbcfffdffff	  64KB		[guard page]
+
+ffffffbbfffe0000	ffffffbcfffeffff	  64KB		PCI I/O space
+
+ffffffbbffff0000	ffffffbcffffffff	  64KB		[guard page]
+
+ffffffbc00000000	ffffffbdffffffff	   8GB		vmemmap
+
+ffffffbe00000000	ffffffbffbffffff	  ~8GB		[guard, future vmmemap]
+
+ffffffbffc000000	ffffffbfffffffff	  64MB		modules
+
+ffffffc000000000	ffffffffffffffff	 256GB		memory
+
+
+Translation table lookup with 4KB pages:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ |                 |         |         |         |         |
+ |                 |         |         |         |         v
+ |                 |         |         |         |   [11:0]  in-page offset
+ |                 |         |         |         +-> [20:12] L3 index
+ |                 |         |         +-----------> [29:21] L2 index
+ |                 |         +---------------------> [38:30] L1 index
+ |                 +-------------------------------> [47:39] L0 index (not used)
+ +-------------------------------------------------> [63] TTBR0/1
+
+
+Translation table lookup with 64KB pages:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ |                 |    |               |              |
+ |                 |    |               |              v
+ |                 |    |               |            [15:0]  in-page offset
+ |                 |    |               +----------> [28:16] L3 index
+ |                 |    +--------------------------> [41:29] L2 index (only 38:29 used)
+ |                 +-------------------------------> [47:42] L1 index (not used)
+ +-------------------------------------------------> [63] TTBR0/1
diff --git a/Documentation/devicetree/bindings/arm/bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm2835.txt
new file mode 100644
index 0000000..ac68348
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/bcm2835.txt
@@ -0,0 +1,8 @@
+Broadcom BCM2835 device tree bindings
+-------------------------------------------
+
+Boards with the BCM2835 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "brcm,bcm2835";
diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt
index 1c044eb..343781b 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -7,8 +7,12 @@
 Required properties:
 
 - compatible : should be one of
+	"arm,cortex-a15-pmu"
 	"arm,cortex-a9-pmu"
 	"arm,cortex-a8-pmu"
+	"arm,cortex-a7-pmu"
+	"arm,cortex-a5-pmu"
+	"arm,arm11mpcore-pmu"
 	"arm,arm1176-pmu"
 	"arm,arm1136-pmu"
 - interrupts : 1 combined interrupt or 1 per core.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
new file mode 100644
index 0000000..548892c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
@@ -0,0 +1,110 @@
+BCM2835 Top-Level ("ARMCTRL") Interrupt Controller
+
+The BCM2835 contains a custom top-level interrupt controller, which supports
+72 interrupt sources using a 2-level register scheme. The interrupt
+controller, or the HW block containing it, is referred to occasionally
+as "armctrl" in the SoC documentation, hence naming of this binding.
+
+Required properties:
+
+- compatible : should be "brcm,bcm2835-armctrl-ic.txt"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 2.
+
+  The 1st cell is the interrupt bank; 0 for interrupts in the "IRQ basic
+  pending" register, or 1/2 respectively for interrupts in the "IRQ pending
+  1/2" register.
+
+  The 2nd cell contains the interrupt number within the bank. Valid values
+  are 0..7 for bank 0, and 0..31 for bank 1.
+
+The interrupt sources are as follows:
+
+Bank 0:
+0: ARM_TIMER
+1: ARM_MAILBOX
+2: ARM_DOORBELL_0
+3: ARM_DOORBELL_1
+4: VPU0_HALTED
+5: VPU1_HALTED
+6: ILLEGAL_TYPE0
+7: ILLEGAL_TYPE1
+
+Bank 1:
+0: TIMER0
+1: TIMER1
+2: TIMER2
+3: TIMER3
+4: CODEC0
+5: CODEC1
+6: CODEC2
+7: VC_JPEG
+8: ISP
+9: VC_USB
+10: VC_3D
+11: TRANSPOSER
+12: MULTICORESYNC0
+13: MULTICORESYNC1
+14: MULTICORESYNC2
+15: MULTICORESYNC3
+16: DMA0
+17: DMA1
+18: VC_DMA2
+19: VC_DMA3
+20: DMA4
+21: DMA5
+22: DMA6
+23: DMA7
+24: DMA8
+25: DMA9
+26: DMA10
+27: DMA11
+28: DMA12
+29: AUX
+30: ARM
+31: VPUDMA
+
+Bank 2:
+0: HOSTPORT
+1: VIDEOSCALER
+2: CCP2TX
+3: SDC
+4: DSI0
+5: AVE
+6: CAM0
+7: CAM1
+8: HDMI0
+9: HDMI1
+10: PIXELVALVE1
+11: I2CSPISLV
+12: DSI1
+13: PWA0
+14: PWA1
+15: CPR
+16: SMI
+17: GPIO0
+18: GPIO1
+19: GPIO2
+20: GPIO3
+21: VC_I2C
+22: VC_SPI
+23: VC_I2SPCM
+24: VC_SDIO
+25: VC_UART
+26: SLIMBUS
+27: VEC
+28: CPG
+29: RNG
+30: VC_ARASANSDIO
+31: AVSPMON
+
+Example:
+
+intc: interrupt-controller {
+	compatible = "brcm,bcm2835-armctrl-ic";
+	reg = <0x7e00b200 0x200>;
+	interrupt-controller;
+	#interrupt-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt
index ab3c327..1d34471 100644
--- a/Documentation/devicetree/bindings/misc/at25.txt
+++ b/Documentation/devicetree/bindings/misc/at25.txt
@@ -1,21 +1,35 @@
-Atmel AT25 eeprom
+EEPROMs (SPI) compatible with Atmel at25.
 
 Required properties:
 - compatible : "atmel,at25".
 - reg : chip select number
 - spi-max-frequency : max spi frequency to use
+- pagesize : size of the eeprom page
+- size : total eeprom size in bytes
+- address-width : number of address bits (one of 8, 16, or 24)
 
+Optional properties:
+- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
+- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
+- read-only : this parameter-less property disables writes to the eeprom
+
+Obsolete legacy properties are can be used in place of "size", "pagesize",
+"address-width", and "read-only":
 - at25,byte-len : total eeprom size in bytes
 - at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
 - at25,page-size : size of the eeprom page
 
-Examples:
-at25@0 {
-	compatible = "atmel,at25";
-	reg = <0>
-	spi-max-frequency = <5000000>;
+Additional compatible properties are also allowed.
 
-	at25,byte-len = <0x8000>;
-	at25,addr-mode = <2>;
-	at25,page-size = <64>;
-};
+Example:
+	at25@0 {
+		compatible = "atmel,at25", "st,m95256";
+		reg = <0>
+		spi-max-frequency = <5000000>;
+		spi-cpha;
+		spi-cpol;
+
+		pagesize = <64>;
+		size = <32768>;
+		address-width = <16>;
+	};
diff --git a/Documentation/devicetree/bindings/misc/lis302.txt b/Documentation/devicetree/bindings/misc/lis302.txt
new file mode 100644
index 0000000..6def86f
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/lis302.txt
@@ -0,0 +1,112 @@
+LIS302 accelerometer devicetree bindings
+
+This device is matched via its bus drivers, and has a number of properties
+that apply in on the generic device (independent from the bus).
+
+
+Required properties for the SPI bindings:
+ - compatible: 		should be set to "st,lis3lv02d_spi"
+ - reg:			the chipselect index
+ - spi-max-frequency:	maximal bus speed, should be set to 1000000 unless
+			constrained by external circuitry
+ - interrupts:		the interrupt generated by the device
+
+Required properties for the I2C bindings:
+ - compatible:		should be set to "st,lis3lv02d"
+ - reg:			i2c slave address
+ - Vdd-supply:		The input supply for Vdd
+ - Vdd_IO-supply:	The input supply for Vdd_IO
+
+
+Optional properties for all bus drivers:
+
+ - st,click-single-{x,y,z}:	if present, tells the device to issue an
+				interrupt on single click events on the
+				x/y/z axis.
+ - st,click-double-{x,y,z}:	if present, tells the device to issue an
+				interrupt on double click events on the
+				x/y/z axis.
+ - st,click-thresh-{x,y,z}:	set the x/y/z axis threshold
+ - st,click-click-time-limit:	click time limit, from 0 to 127.5msec
+				with step of 0.5 msec
+ - st,click-latency:		click latency, from 0 to 255 msec with
+				step of 1 msec.
+ - st,click-window:		click window, from 0 to 255 msec with
+				step of 1 msec.
+ - st,irq{1,2}-disable:		disable IRQ 1/2
+ - st,irq{1,2}-ff-wu-1:		raise IRQ 1/2 on FF_WU_1 condition
+ - st,irq{1,2}-ff-wu-2:		raise IRQ 1/2 on FF_WU_2 condition
+ - st,irq{1,2}-data-ready:	raise IRQ 1/2 on data ready contition
+ - st,irq{1,2}-click:		raise IRQ 1/2 on click condition
+ - st,irq-open-drain:		consider IRQ lines open-drain
+ - st,irq-active-low:		make IRQ lines active low
+ - st,wu-duration-1:		duration register for Free-Fall/Wake-Up
+				interrupt 1
+ - st,wu-duration-2:		duration register for Free-Fall/Wake-Up
+				interrupt 2
+ - st,wakeup-{x,y,z}-{lo,hi}:	set wakeup condition on x/y/z axis for
+				upper/lower limit
+ - st,highpass-cutoff-hz=:	1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
+				highpass cut-off frequency
+ - st,hipass{1,2}-disable:	disable highpass 1/2.
+ - st,default-rate=:		set the default rate
+ - st,axis-{x,y,z}=:		set the axis to map to the three coordinates
+ - st,{min,max}-limit-{x,y,z}	set the min/max limits for x/y/z axis
+				(used by self-test)
+
+
+Example for a SPI device node:
+
+	lis302@0 {
+		compatible = "st,lis302dl-spi";
+		reg = <0>;
+		spi-max-frequency = <1000000>;
+		interrupt-parent = <&gpio>;
+		interrupts = <104 0>;
+
+		st,click-single-x;
+		st,click-single-y;
+		st,click-single-z;
+		st,click-thresh-x = <10>;
+		st,click-thresh-y = <10>;
+		st,click-thresh-z = <10>;
+		st,irq1-click;
+		st,irq2-click;
+		st,wakeup-x-lo;
+		st,wakeup-x-hi;
+		st,wakeup-y-lo;
+		st,wakeup-y-hi;
+		st,wakeup-z-lo;
+		st,wakeup-z-hi;
+	};
+
+Example for a I2C device node:
+
+	lis331dlh: lis331dlh@18 {
+		compatible = "st,lis331dlh", "st,lis3lv02d";
+		reg = <0x18>;
+		Vdd-supply = <&lis3_reg>;
+		Vdd_IO-supply = <&lis3_reg>;
+
+		st,click-single-x;
+		st,click-single-y;
+		st,click-single-z;
+		st,click-thresh-x = <10>;
+		st,click-thresh-y = <10>;
+		st,click-thresh-z = <10>;
+		st,irq1-click;
+		st,irq2-click;
+		st,wakeup-x-lo;
+		st,wakeup-x-hi;
+		st,wakeup-y-lo;
+		st,wakeup-y-hi;
+		st,wakeup-z-lo;
+		st,wakeup-z-hi;
+		st,min-limit-x = <120>;
+		st,min-limit-y = <120>;
+		st,min-limit-z = <140>;
+		st,max-limit-x = <550>;
+		st,max-limit-y = <550>;
+		st,max-limit-z = <750>;
+	};
+
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 66ece3f..ecfc6cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -11,10 +11,13 @@
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
 - regulator-ramp-delay: ramp delay for regulator(in uV/uS)
+
+Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
   regulators, and if the chip's binding contains a child node that
   describes each regulator, then this property indicates which regulator
-  this child node is intended to configure.
+  this child node is intended to configure. If this property is missing,
+  the node's name will be used instead.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/regulator/tps65217.txt b/Documentation/devicetree/bindings/regulator/tps65217.txt
index 0487e96..d316fb8 100644
--- a/Documentation/devicetree/bindings/regulator/tps65217.txt
+++ b/Documentation/devicetree/bindings/regulator/tps65217.txt
@@ -22,66 +22,49 @@
 		compatible = "ti,tps65217";
 
 		regulators {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			dcdc1_reg: regulator@0 {
-				reg = <0>;
-				regulator-compatible = "dcdc1";
+			dcdc1_reg: dcdc1 {
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			dcdc2_reg: regulator@1 {
-				reg = <1>;
-				regulator-compatible = "dcdc2";
+			dcdc2_reg: dcdc2 {
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			dcdc3_reg: regulator@2 {
-				reg = <2>;
-				regulator-compatible = "dcdc3";
+			dcdc3_reg: dcc3 {
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1500000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			ldo1_reg: regulator@3 {
-				reg = <3>;
-				regulator-compatible = "ldo1";
+			ldo1_reg: ldo1 {
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			ldo2_reg: regulator@4 {
-				reg = <4>;
-				regulator-compatible = "ldo2";
+			ldo2_reg: ldo2 {
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			ldo3_reg: regulator@5 {
-				reg = <5>;
-				regulator-compatible = "ldo3";
+			ldo3_reg: ldo3 {
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			ldo4_reg: regulator@6 {
-				reg = <6>;
-				regulator-compatible = "ldo4";
+			ldo4_reg: ldo4 {
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt
index da80c2a..07b9ef6 100644
--- a/Documentation/devicetree/bindings/regulator/tps6586x.txt
+++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt
@@ -6,9 +6,13 @@
 - interrupts: the interrupt outputs of the controller
 - #gpio-cells: number of cells to describe a GPIO
 - gpio-controller: mark the device as a GPIO controller
-- regulators: list of regulators provided by this controller, must have
-  property "regulator-compatible" to match their hardware counterparts:
-  sm[0-2], ldo[0-9] and ldo_rtc
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name (or the deprecated
+  regulator-compatible property if present), with valid values listed below.
+  The content of each sub-node is defined by the standard binding for
+  regulators; see regulator.txt.
+  sys, sm[0-2], ldo[0-9] and ldo_rtc
+- sys-supply: The input supply for SYS.
 - vin-sm0-supply: The input supply for the SM0.
 - vin-sm1-supply: The input supply for the SM1.
 - vin-sm2-supply: The input supply for the SM2.
@@ -20,6 +24,9 @@
 
 Each regulator is defined using the standard binding for regulators.
 
+Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver
+      take care of making proper parent child relationship.
+
 Example:
 
 	pmu: tps6586x@34 {
@@ -30,6 +37,7 @@
 		#gpio-cells = <2>;
 		gpio-controller;
 
+		sys-supply = <&some_reg>;
 		vin-sm0-supply = <&some_reg>;
 		vin-sm1-supply = <&some_reg>;
 		vin-sm2-supply = <&some_reg>;
@@ -40,103 +48,80 @@
 		vinldo9-supply = <...>;
 
 		regulators {
-			#address-cells = <1>;
-			#size-cells = <0>;
+			sys_reg: sys {
+				regulator-name = "vdd_sys";
+				regulator-boot-on;
+				regulator-always-on;
+			};
 
-			sm0_reg: regulator@0 {
-				reg = <0>;
-				regulator-compatible = "sm0";
+			sm0_reg: sm0 {
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			sm1_reg: regulator@1 {
-				reg = <1>;
-				regulator-compatible = "sm1";
+			sm1_reg: sm1 {
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			sm2_reg: regulator@2 {
-				reg = <2>;
-				regulator-compatible = "sm2";
+			sm2_reg: sm2 {
 				regulator-min-microvolt = <3000000>;
 				regulator-max-microvolt = <4550000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
-			ldo0_reg: regulator@3 {
-				reg = <3>;
-				regulator-compatible = "ldo0";
+			ldo0_reg: ldo0 {
 				regulator-name = "PCIE CLK";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo1_reg: regulator@4 {
-				reg = <4>;
-				regulator-compatible = "ldo1";
+			ldo1_reg: ldo1 {
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 			};
 
-			ldo2_reg: regulator@5 {
-				reg = <5>;
-				regulator-compatible = "ldo2";
+			ldo2_reg: ldo2 {
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 			};
 
-			ldo3_reg: regulator@6 {
-				reg = <6>;
-				regulator-compatible = "ldo3";
+			ldo3_reg: ldo3 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo4_reg: regulator@7 {
-				reg = <7>;
-				regulator-compatible = "ldo4";
+			ldo4_reg: ldo4 {
 				regulator-min-microvolt = <1700000>;
 				regulator-max-microvolt = <2475000>;
 			};
 
-			ldo5_reg: regulator@8 {
-				reg = <8>;
-				regulator-compatible = "ldo5";
+			ldo5_reg: ldo5 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo6_reg: regulator@9 {
-				reg = <9>;
-				regulator-compatible = "ldo6";
+			ldo6_reg: ldo6 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo7_reg: regulator@10 {
-				reg = <10>;
-				regulator-compatible = "ldo7";
+			ldo7_reg: ldo7 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo8_reg: regulator@11 {
-				reg = <11>;
-				regulator-compatible = "ldo8";
+			ldo8_reg: ldo8 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo9_reg: regulator@12 {
-				reg = <12>;
-				regulator-compatible = "ldo9";
+			ldo9_reg: ldo9 {
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
new file mode 100644
index 0000000..801d58c
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -0,0 +1,15 @@
+* Freescale i.MX28 LRADC device driver
+
+Required properties:
+- compatible: Should be "fsl,imx28-lradc"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the LRADC interrupts
+
+Examples:
+
+	lradc@80050000 {
+		compatible = "fsl,imx28-lradc";
+		reg = <0x80050000 0x2000>;
+		interrupts = <10 14 15 16 17 18 19
+				20 21 22 23 24 25>;
+	};
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
new file mode 100644
index 0000000..07654f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -0,0 +1,41 @@
+Freescale i.MX IPUv3
+====================
+
+Required properties:
+- compatible: Should be "fsl,<chip>-ipu"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain sync interrupt and error interrupt,
+  in this order.
+- #crtc-cells: 1, See below
+
+example:
+
+ipu: ipu@18000000 {
+	#crtc-cells = <1>;
+	compatible = "fsl,imx53-ipu";
+	reg = <0x18000000 0x080000000>;
+	interrupts = <11 10>;
+};
+
+Parallel display support
+========================
+
+Required properties:
+- compatible: Should be "fsl,imx-parallel-display"
+- crtc: the crtc this display is connected to, see below
+Optional properties:
+- interface_pix_fmt: How this display is connected to the
+  crtc. Currently supported types: "rgb24", "rgb565"
+- edid: verbatim EDID data block describing attached display.
+- ddc: phandle describing the i2c bus handling the display data
+  channel
+
+example:
+
+display@di0 {
+	compatible = "fsl,imx-parallel-display";
+	edid = [edid-data];
+	crtc = <&ipu 0>;
+	interface-pix-fmt = "rgb24";
+};
diff --git a/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt
new file mode 100644
index 0000000..2de21c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt
@@ -0,0 +1,22 @@
+BCM2835 System Timer
+
+The System Timer peripheral provides four 32-bit timer channels and a
+single 64-bit free running counter. Each channel has an output compare
+register, which is compared against the 32 least significant bits of the
+free running counter values, and generates an interrupt.
+
+Required properties:
+
+- compatible : should be "brcm,bcm2835-system-timer.txt"
+- reg : Specifies base physical address and size of the registers.
+- interrupts : A list of 4 interrupt sinks; one per timer channel.
+- clock-frequency : The frequency of the clock that drives the counter, in Hz.
+
+Example:
+
+timer {
+	compatible = "brcm,bcm2835-system-timer";
+	reg = <0x7e003000 0x1000>;
+	interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+	clock-frequency = <1000000>;
+};
diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
new file mode 100644
index 0000000..ca8fa56
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
@@ -0,0 +1,14 @@
+AM33XX MUSB GLUE
+ - compatible : Should be "ti,musb-am33xx"
+ - ti,hwmods : must be "usb_otg_hs"
+ - multipoint : Should be "1" indicating the musb controller supports
+   multipoint. This is a MUSB configuration-specific setting.
+ - num_eps : Specifies the number of endpoints. This is also a
+   MUSB configuration-specific setting. Should be set to "16"
+ - ram_bits : Specifies the ram address size. Should be set to "12"
+ - port0_mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
+   represents PERIPHERAL.
+ - port1_mode : Should be "1" to represent HOST. "3" signifies OTG and "2"
+   represents PERIPHERAL.
+ - power : Should be "250". This signifies the controller can supply upto
+   500mA when operating in host mode.
diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
index 2c29041..5778b9c 100644
--- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
+++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
@@ -7,7 +7,10 @@
 
 Optional properties:
 - fsl,usbphy: phandler of usb phy that connects to the only one port
+- fsl,usbmisc: phandler of non-core register device, with one argument
+  that indicate usb controller index
 - vbus-supply: regulator for vbus
+- disable-over-current: disable over current detect
 
 Examples:
 usb@02184000 { /* USB OTG */
@@ -15,4 +18,6 @@
 	reg = <0x02184000 0x200>;
 	interrupts = <0 43 0x04>;
 	fsl,usbphy = <&usbphy1>;
+	fsl,usbmisc = <&usbmisc 0>;
+	disable-over-current;
 };
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
new file mode 100644
index 0000000..29a043e
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -0,0 +1,33 @@
+OMAP GLUE
+
+OMAP MUSB GLUE
+ - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
+ - ti,hwmods : must be "usb_otg_hs"
+ - multipoint : Should be "1" indicating the musb controller supports
+   multipoint. This is a MUSB configuration-specific setting.
+ - num_eps : Specifies the number of endpoints. This is also a
+   MUSB configuration-specific setting. Should be set to "16"
+ - ram_bits : Specifies the ram address size. Should be set to "12"
+ - interface_type : This is a board specific setting to describe the type of
+   interface between the controller and the phy. It should be "0" or "1"
+   specifying ULPI and UTMI respectively.
+ - mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
+   represents PERIPHERAL.
+ - power : Should be "50". This signifies the controller can supply upto
+   100mA when operating in host mode.
+
+SOC specific device node entry
+usb_otg_hs: usb_otg_hs@4a0ab000 {
+	compatible = "ti,omap4-musb";
+	ti,hwmods = "usb_otg_hs";
+	multipoint = <1>;
+	num_eps = <16>;
+	ram_bits = <12>;
+};
+
+Board specific device node entry
+&usb_otg_hs {
+	interface_type = <1>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt
new file mode 100644
index 0000000..79729a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt
@@ -0,0 +1,31 @@
+PXA USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "marvell,pxa-ohci" for USB controllers
+   used in host mode.
+
+Optional properties:
+ - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3"
+   If present, enables the appropriate USB port of the controller.
+ - "marvell,port-mode" selects the mode of the ports:
+	1 = PMM_NPS_MODE
+	2 = PMM_GLOBAL_MODE
+	3 = PMM_PERPORT_MODE
+ - "marvell,power-sense-low" - power sense pin is low-active.
+ - "marvell,power-control-low" - power control pin is low-active.
+ - "marvell,no-oc-protection" - disable over-current protection.
+ - "marvell,oc-mode-perport" - enable per-port over-current protection.
+ - "marvell,power_on_delay" Power On to Power Good time - in ms.
+
+Example:
+
+	usb0: ohci@4c000000 {
+		compatible = "marvell,pxa-ohci", "usb-ohci";
+		reg = <0x4c000000 0x100000>;
+		interrupts = <18>;
+		marvell,enable-port1;
+		marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
+	};
+
diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
new file mode 100644
index 0000000..36b9aed
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -0,0 +1,40 @@
+USB COMPARATOR OF TWL CHIPS
+
+TWL6030 USB COMPARATOR
+ - compatible : Should be "ti,twl6030-usb"
+ - interrupts : Two interrupt numbers to the cpu should be specified. First
+   interrupt number is the otg interrupt number that raises ID interrupts when
+   the controller has to act as host and the second interrupt number is the
+   usb interrupt number that raises VBUS interrupts when the controller has to
+   act as device
+ - usb-supply : phandle to the regulator device tree node. It should be vusb
+   if it is twl6030 or ldousb if it is twl6025 subclass.
+
+twl6030-usb {
+	compatible = "ti,twl6030-usb";
+	interrupts = < 4 10 >;
+};
+
+Board specific device node entry
+&twl6030-usb {
+	usb-supply = <&vusb>;
+};
+
+TWL4030 USB PHY AND COMPARATOR
+ - compatible : Should be "ti,twl4030-usb"
+ - interrupts : The interrupt numbers to the cpu should be specified. First
+   interrupt number is the otg interrupt number that raises ID interrupts
+   and VBUS interrupts. The second interrupt number is optional.
+ - <supply-name>-supply : phandle to the regulator device tree node.
+   <supply-name> should be vusb1v5, vusb1v8 and vusb3v1
+ - usb_mode : The mode used by the phy to connect to the controller. "1"
+   specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
+
+twl4030-usb {
+	compatible = "ti,twl4030-usb";
+	interrupts = < 10 4 >;
+	usb1v5-supply = <&vusb1v5>;
+	usb1v8-supply = <&vusb1v8>;
+	usb3v1-supply = <&vusb3v1>;
+	usb_mode = <1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
new file mode 100644
index 0000000..80d4148
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -0,0 +1,17 @@
+USB PHY
+
+OMAP USB2 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb2"
+ - reg : Address and length of the register set for the device. Also
+add the address of control module dev conf register until a driver for
+control module is added
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb2phy@4a0ad080 {
+	compatible = "ti,omap-usb2";
+	reg = <0x4a0ad080 0x58>,
+	      <0x4a002300 0x4>;
+};
diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt
new file mode 100644
index 0000000..97ce94e
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt
@@ -0,0 +1,14 @@
+* Freescale i.MX non-core registers
+
+Required properties:
+- #index-cells: Cells used to descibe usb controller index. Should be <1>
+- compatible: Should be one of below:
+	"fsl,imx6q-usbmisc" for imx6q
+- reg: Should contain registers location and length
+
+Examples:
+usbmisc@02184800 {
+	#index-cells = <1>;
+	compatible = "fsl,imx6q-usbmisc";
+	reg = <0x02184800 0x200>;
+};
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
new file mode 100644
index 0000000..5fb8fd6
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
@@ -0,0 +1,12 @@
+VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
+
+Required properties:
+ - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
+ - reg: Address range of the ehci registers. size should be 0x200
+ - interrupts: Should contain the ehci interrupt.
+
+usb: ehci@D8007100 {
+	compatible = "wm,prizm-ehci", "usb-ehci";
+	reg = <0xD8007100 0x200>;
+	interrupts = <1>;
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 5c63da2..9de2b9f 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -10,6 +10,7 @@
 arm	ARM Ltd.
 atmel	Atmel Corporation
 bosch	Bosch Sensortec GmbH
+brcm	Broadcom Corporation
 cavium	Cavium, Inc.
 chrp	Common Hardware Reference Platform
 cortina	Cortina Systems, Inc.
diff --git a/Documentation/devicetree/bindings/w1/w1-gpio.txt b/Documentation/devicetree/bindings/w1/w1-gpio.txt
new file mode 100644
index 0000000..6e09c35
--- /dev/null
+++ b/Documentation/devicetree/bindings/w1/w1-gpio.txt
@@ -0,0 +1,22 @@
+w1-gpio devicetree bindings
+
+Required properties:
+
+ - compatible: "w1-gpio"
+ - gpios: one or two GPIO specs:
+		- the first one is used as data I/O pin
+		- the second one is optional. If specified, it is used as
+		  enable pin for an external pin pullup.
+
+Optional properties:
+
+ - linux,open-drain: if specified, the data pin is considered in
+		     open-drain mode.
+
+Examples:
+
+	onewire@0 {
+		compatible = "w1-gpio";
+		gpios = <&gpio 126 0>, <&gpio 105 0>;
+	};
+
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 39462cf..74c25c8 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -162,7 +162,6 @@
 machtypes.h
 map
 map_hugetlb
-maui_boot.h
 media
 mconf
 miboot*
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
deleted file mode 100644
index f4d8c71..0000000
--- a/Documentation/feature-removal-schedule.txt
+++ /dev/null
@@ -1,639 +0,0 @@
-The following is a list of files and features that are going to be
-removed in the kernel source tree.  Every entry should contain what
-exactly is going away, why it is happening, and who is going to be doing
-the work.  When the feature is removed from the kernel, it should also
-be removed from this file.  The suggested deprecation period is 3 releases.
-
----------------------------
-
-What:	ddebug_query="query" boot cmdline param
-When:	v3.8
-Why:	obsoleted by dyndbg="query" and module.dyndbg="query"
-Who:	Jim Cromie <jim.cromie@gmail.com>, Jason Baron <jbaron@redhat.com>
-
----------------------------
-
-What: /proc/sys/vm/nr_pdflush_threads
-When: 2012
-Why: Since pdflush is deprecated, the interface exported in /proc/sys/vm/
-     should be removed.
-Who: Wanpeng Li <liwp@linux.vnet.ibm.com>
-
----------------------------
-
-What:	CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
-When:	2012
-Why:	This optional sub-feature of APM is of dubious reliability,
-	and ancient APM laptops are likely better served by calling HLT.
-	Deleting CONFIG_APM_CPU_IDLE allows x86 to stop exporting
-	the pm_idle function pointer to modules.
-Who:	Len Brown <len.brown@intel.com>
-
-----------------------------
-
-What:	x86_32 "no-hlt" cmdline param
-When:	2012
-Why:	remove a branch from idle path, simplify code used by everybody.
-	This option disabled the use of HLT in idle and machine_halt()
-	for hardware that was flakey 15-years ago.  Today we have
-	"idle=poll" that removed HLT from idle, and so if such a machine
-	is still running the upstream kernel, "idle=poll" is likely sufficient.
-Who:	Len Brown <len.brown@intel.com>
-
-----------------------------
-
-What:	x86 "idle=mwait" cmdline param
-When:	2012
-Why:	simplify x86 idle code
-Who:	Len Brown <len.brown@intel.com>
-
-----------------------------
-
-What:	PRISM54
-When:	2.6.34
-
-Why:	prism54 FullMAC PCI / Cardbus devices used to be supported only by the
-	prism54 wireless driver. After Intersil stopped selling these
-	devices in preference for the newer more flexible SoftMAC devices
-	a SoftMAC device driver was required and prism54 did not support
-	them. The p54pci driver now exists and has been present in the kernel for
-	a while. This driver supports both SoftMAC devices and FullMAC devices.
-	The main difference between these devices was the amount of memory which
-	could be used for the firmware. The SoftMAC devices support a smaller
-	amount of memory. Because of this the SoftMAC firmware fits into FullMAC
-	devices's memory. p54pci supports not only PCI / Cardbus but also USB
-	and SPI. Since p54pci supports all devices prism54 supports
-	you will have a conflict. I'm not quite sure how distributions are
-	handling this conflict right now. prism54 was kept around due to
-	claims users may experience issues when using the SoftMAC driver.
-	Time has passed users have not reported issues. If you use prism54
-	and for whatever reason you cannot use p54pci please let us know!
-	E-mail us at: linux-wireless@vger.kernel.org
-
-	For more information see the p54 wiki page:
-
-	http://wireless.kernel.org/en/users/Drivers/p54
-
-Who:	Luis R. Rodriguez <lrodriguez@atheros.com>
-
----------------------------
-
-What:	The ieee80211_regdom module parameter
-When:	March 2010 / desktop catchup
-
-Why:	This was inherited by the CONFIG_WIRELESS_OLD_REGULATORY code,
-	and currently serves as an option for users to define an
-	ISO / IEC 3166 alpha2 code for the country they are currently
-	present in. Although there are userspace API replacements for this
-	through nl80211 distributions haven't yet caught up with implementing
-	decent alternatives through standard GUIs. Although available as an
-	option through iw or wpa_supplicant its just a matter of time before
-	distributions pick up good GUI options for this. The ideal solution
-	would actually consist of intelligent designs which would do this for
-	the user automatically even when travelling through different countries.
-	Until then we leave this module parameter as a compromise.
-
-	When userspace improves with reasonable widely-available alternatives for
-	this we will no longer need this module parameter. This entry hopes that
-	by the super-futuristically looking date of "March 2010" we will have
-	such replacements widely available.
-
-Who:	Luis R. Rodriguez <lrodriguez@atheros.com>
-
----------------------------
-
-What:	dev->power.power_state
-When:	July 2007
-Why:	Broken design for runtime control over driver power states, confusing
-	driver-internal runtime power management with:  mechanisms to support
-	system-wide sleep state transitions; event codes that distinguish
-	different phases of swsusp "sleep" transitions; and userspace policy
-	inputs.  This framework was never widely used, and most attempts to
-	use it were broken.  Drivers should instead be exposing domain-specific
-	interfaces either to kernel or to userspace.
-Who:	Pavel Machek <pavel@ucw.cz>
-
----------------------------
-
-What:	/proc/<pid>/oom_adj
-When:	August 2012
-Why:	/proc/<pid>/oom_adj allows userspace to influence the oom killer's
-	badness heuristic used to determine which task to kill when the kernel
-	is out of memory.
-
-	The badness heuristic has since been rewritten since the introduction of
-	this tunable such that its meaning is deprecated.  The value was
-	implemented as a bitshift on a score generated by the badness()
-	function that did not have any precise units of measure.  With the
-	rewrite, the score is given as a proportion of available memory to the
-	task allocating pages, so using a bitshift which grows the score
-	exponentially is, thus, impossible to tune with fine granularity.
-
-	A much more powerful interface, /proc/<pid>/oom_score_adj, was
-	introduced with the oom killer rewrite that allows users to increase or
-	decrease the badness score linearly.  This interface will replace
-	/proc/<pid>/oom_adj.
-
-	A warning will be emitted to the kernel log if an application uses this
-	deprecated interface.  After it is printed once, future warnings will be
-	suppressed until the kernel is rebooted.
-
----------------------------
-
-What:	remove EXPORT_SYMBOL(kernel_thread)
-When:	August 2006
-Files:	arch/*/kernel/*_ksyms.c
-Check:	kernel_thread
-Why:	kernel_thread is a low-level implementation detail.  Drivers should
-        use the <linux/kthread.h> API instead which shields them from
-	implementation details and provides a higherlevel interface that
-	prevents bugs and code duplication
-Who:	Christoph Hellwig <hch@lst.de>
-
----------------------------
-
-What:	Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
-	(temporary transition config option provided until then)
-	The transition config option will also be removed at the same time.
-When:	before 2.6.19
-Why:	Unused symbols are both increasing the size of the kernel binary
-	and are often a sign of "wrong API"
-Who:	Arjan van de Ven <arjan@linux.intel.com>
-
----------------------------
-
-What:	PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
-When:	October 2008
-Why:	The stacking of class devices makes these values misleading and
-	inconsistent.
-	Class devices should not carry any of these properties, and bus
-	devices have SUBSYTEM and DRIVER as a replacement.
-Who:	Kay Sievers <kay.sievers@suse.de>
-
----------------------------
-
-What:	ACPI procfs interface
-When:	July 2008
-Why:	ACPI sysfs conversion should be finished by January 2008.
-	ACPI procfs interface will be removed in July 2008 so that
-	there is enough time for the user space to catch up.
-Who:	Zhang Rui <rui.zhang@intel.com>
-
----------------------------
-
-What:	CONFIG_ACPI_PROCFS_POWER
-When:	2.6.39
-Why:	sysfs I/F for ACPI power devices, including AC and Battery,
-        has been working in upstream kernel since 2.6.24, Sep 2007.
-	In 2.6.37, we make the sysfs I/F always built in and this option
-	disabled by default.
-	Remove this option and the ACPI power procfs interface in 2.6.39.
-Who:	Zhang Rui <rui.zhang@intel.com>
-
----------------------------
-
-What:	/proc/acpi/event
-When:	February 2008
-Why:	/proc/acpi/event has been replaced by events via the input layer
-	and netlink since 2.6.23.
-Who:	Len Brown <len.brown@intel.com>
-
----------------------------
-
-What:	i386/x86_64 bzImage symlinks
-When:	April 2010
-
-Why:	The i386/x86_64 merge provides a symlink to the old bzImage
-	location so not yet updated user space tools, e.g. package
-	scripts, do not break.
-Who:	Thomas Gleixner <tglx@linutronix.de>
-
----------------------------
-
-What:	GPIO autorequest on gpio_direction_{input,output}() in gpiolib
-When:	February 2010
-Why:	All callers should use explicit gpio_request()/gpio_free().
-	The autorequest mechanism in gpiolib was provided mostly as a
-	migration aid for legacy GPIO interfaces (for SOC based GPIOs).
-	Those users have now largely migrated.  Platforms implementing
-	the GPIO interfaces without using gpiolib will see no changes.
-Who:	David Brownell <dbrownell@users.sourceforge.net>
----------------------------
-
-What:	b43 support for firmware revision < 410
-When:	The schedule was July 2008, but it was decided that we are going to keep the
-        code as long as there are no major maintanance headaches.
-	So it _could_ be removed _any_ time now, if it conflicts with something new.
-Why:	The support code for the old firmware hurts code readability/maintainability
-	and slightly hurts runtime performance. Bugfixes for the old firmware
-	are not provided by Broadcom anymore.
-Who:	Michael Buesch <m@bues.ch>
-
----------------------------
-
-What:	Ability for non root users to shm_get hugetlb pages based on mlock
-	resource limits
-When:	2.6.31
-Why:	Non root users need to be part of /proc/sys/vm/hugetlb_shm_group or
-	have CAP_IPC_LOCK to be able to allocate shm segments backed by
-	huge pages.  The mlock based rlimit check to allow shm hugetlb is
-	inconsistent with mmap based allocations.  Hence it is being
-	deprecated.
-Who:	Ravikiran Thirumalai <kiran@scalex86.org>
-
----------------------------
-
-What:	sysfs ui for changing p4-clockmod parameters
-When:	September 2009
-Why:	See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
-	e088e4c9cdb618675874becb91b2fd581ee707e6.
-	Removal is subject to fixing any remaining bugs in ACPI which may
-	cause the thermal throttling not to happen at the right time.
-Who:	Dave Jones <davej@redhat.com>, Matthew Garrett <mjg@redhat.com>
-
------------------------------
-
-What:	fakephp and associated sysfs files in /sys/bus/pci/slots/
-When:	2011
-Why:	In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
-	represent a machine's physical PCI slots. The change in semantics
-	had userspace implications, as the hotplug core no longer allowed
-	drivers to create multiple sysfs files per physical slot (required
-	for multi-function devices, e.g.). fakephp was seen as a developer's
-	tool only, and its interface changed. Too late, we learned that
-	there were some users of the fakephp interface.
-
-	In 2.6.30, the original fakephp interface was restored. At the same
-	time, the PCI core gained the ability that fakephp provided, namely
-	function-level hot-remove and hot-add.
-
-	Since the PCI core now provides the same functionality, exposed in:
-
-		/sys/bus/pci/rescan
-		/sys/bus/pci/devices/.../remove
-		/sys/bus/pci/devices/.../rescan
-
-	there is no functional reason to maintain fakephp as well.
-
-	We will keep the existing module so that 'modprobe fakephp' will
-	present the old /sys/bus/pci/slots/... interface for compatibility,
-	but users are urged to migrate their applications to the API above.
-
-	After a reasonable transition period, we will remove the legacy
-	fakephp interface.
-Who:	Alex Chiang <achiang@hp.com>
-
----------------------------
-
-What:	CONFIG_RFKILL_INPUT
-When:	2.6.33
-Why:	Should be implemented in userspace, policy daemon.
-Who:	Johannes Berg <johannes@sipsolutions.net>
-
-----------------------------
-
-What:	sound-slot/service-* module aliases and related clutters in
-	sound/sound_core.c
-When:	August 2010
-Why:	OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR
-	(14) and requests modules using custom sound-slot/service-*
-	module aliases.  The only benefit of doing this is allowing
-	use of custom module aliases which might as well be considered
-	a bug at this point.  This preemptive claiming prevents
-	alternative OSS implementations.
-
-	Till the feature is removed, the kernel will be requesting
-	both sound-slot/service-* and the standard char-major-* module
-	aliases and allow turning off the pre-claiming selectively via
-	CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss
-	kernel parameter.
-
-	After the transition phase is complete, both the custom module
-	aliases and switches to disable it will go away.  This removal
-	will also allow making ALSA OSS emulation independent of
-	sound_core.  The dependency will be broken then too.
-Who:	Tejun Heo <tj@kernel.org>
-
-----------------------------
-
-What:	sysfs-class-rfkill state file
-When:	Feb 2014
-Files:	net/rfkill/core.c
-Why: 	Documented as obsolete since Feb 2010. This file is limited to 3
-	states while the rfkill drivers can have 4 states.
-Who: 	anybody or Florian Mickler <florian@mickler.org>
-
-----------------------------
-
-What: 	sysfs-class-rfkill claim file
-When:	Feb 2012
-Files:	net/rfkill/core.c
-Why:	It is not possible to claim an rfkill driver since 2007. This is
-	Documented as obsolete since Feb 2010.
-Who: 	anybody or Florian Mickler <florian@mickler.org>
-
-----------------------------
-
-What:	iwlwifi 50XX module parameters
-When:	3.0
-Why:	The "..50" modules parameters were used to configure 5000 series and
-	up devices; different set of module parameters also available for 4965
-	with same functionalities. Consolidate both set into single place
-	in drivers/net/wireless/iwlwifi/iwl-agn.c
-
-Who:	Wey-Yi Guy <wey-yi.w.guy@intel.com>
-
-----------------------------
-
-What:	iwl4965 alias support
-When:	3.0
-Why:	Internal alias support has been present in module-init-tools for some
-	time, the MODULE_ALIAS("iwl4965") boilerplate aliases can be removed
-	with no impact.
-
-Who:	Wey-Yi Guy <wey-yi.w.guy@intel.com>
-
----------------------------
-
-What:	xt_NOTRACK
-Files:	net/netfilter/xt_NOTRACK.c
-When:	April 2011
-Why:	Superseded by xt_CT
-Who:	Netfilter developer team <netfilter-devel@vger.kernel.org>
-
-----------------------------
-
-What:	IRQF_DISABLED
-When:	2.6.36
-Why:	The flag is a NOOP as we run interrupt handlers with interrupts disabled
-Who:	Thomas Gleixner <tglx@linutronix.de>
-
-----------------------------
-
-What: 	PCI DMA unmap state API
-When:	August 2012
-Why:	PCI DMA unmap state API (include/linux/pci-dma.h) was replaced
-	with DMA unmap state API (DMA unmap state API can be used for
-	any bus).
-Who:	FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-
-----------------------------
-
-What:	iwlwifi disable_hw_scan module parameters
-When:	3.0
-Why:	Hareware scan is the prefer method for iwlwifi devices for
-	scanning operation. Remove software scan support for all the
-	iwlwifi devices.
-
-Who:	Wey-Yi Guy <wey-yi.w.guy@intel.com>
-
-----------------------------
-
-What:	Legacy, non-standard chassis intrusion detection interface.
-When:	June 2011
-Why:	The adm9240, w83792d and w83793 hardware monitoring drivers have
-	legacy interfaces for chassis intrusion detection. A standard
-	interface has been added to each driver, so the legacy interface
-	can be removed.
-Who:	Jean Delvare <khali@linux-fr.org>
-
-----------------------------
-
-What:	i2c_driver.attach_adapter
-	i2c_driver.detach_adapter
-When:	September 2011
-Why:	These legacy callbacks should no longer be used as i2c-core offers
-	a variety of preferable alternative ways to instantiate I2C devices.
-Who:	Jean Delvare <khali@linux-fr.org>
-
-----------------------------
-
-What:	Opening a radio device node will no longer automatically switch the
-	tuner mode from tv to radio.
-When:	3.3
-Why:	Just opening a V4L device should not change the state of the hardware
-	like that. It's very unexpected and against the V4L spec. Instead, you
-	switch to radio mode by calling VIDIOC_S_FREQUENCY. This is the second
-	and last step of the move to consistent handling of tv and radio tuners.
-Who:	Hans Verkuil <hans.verkuil@cisco.com>
-
-----------------------------
-
-What:	CONFIG_CFG80211_WEXT
-When:	as soon as distributions ship new wireless tools, ie. wpa_supplicant 1.0
-	and NetworkManager/connman/etc. that are able to use nl80211
-Why:	Wireless extensions are deprecated, and userland tools are moving to
-	using nl80211. New drivers are no longer using wireless extensions,
-	and while there might still be old drivers, both new drivers and new
-	userland no longer needs them and they can't be used for an feature
-	developed in the past couple of years. As such, compatibility with
-	wireless extensions in new drivers will be removed.
-Who:	Johannes Berg <johannes@sipsolutions.net>
-
-----------------------------
-
-What:	g_file_storage driver
-When:	3.8
-Why:	This driver has been superseded by g_mass_storage.
-Who:	Alan Stern <stern@rowland.harvard.edu>
-
-----------------------------
-
-What:   threeg and interface sysfs files in /sys/devices/platform/acer-wmi
-When:   2012
-Why:    In 3.0, we can now autodetect internal 3G device and already have
-	the threeg rfkill device. So, we plan to remove threeg sysfs support
-	for it's no longer necessary.
-
-	We also plan to remove interface sysfs file that exposed which ACPI-WMI
-	interface that was used by acer-wmi driver. It will replaced by
-	information log when acer-wmi initial.
-Who:    Lee, Chun-Yi <jlee@novell.com>
-
----------------------------
-
-What:	/sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and
-	is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file.
-When:	3.8
-Why:	The is_dualspeed file is superseded by maximum_speed in the same
-	directory and is_dualspeed line in device file is superseded by
-	max_speed line in the same file.
-
-	The maximum_speed/max_speed specifies maximum speed supported by UDC.
-	To check if dualspeeed is supported, check if the value is >= 3.
-	Various possible speeds are defined in <linux/usb/ch9.h>.
-Who:	Michal Nazarewicz <mina86@mina86.com>
-
-----------------------------
-
-What:	The XFS nodelaylog mount option
-When:	3.3
-Why:	The delaylog mode that has been the default since 2.6.39 has proven
-	stable, and the old code is in the way of additional improvements in
-	the log code.
-Who:	Christoph Hellwig <hch@lst.de>
-
-----------------------------
-
-What:	iwlagn alias support
-When:	3.5
-Why:	The iwlagn module has been renamed iwlwifi.  The alias will be around
-	for backward compatibility for several cycles and then dropped.
-Who:	Don Fry <donald.h.fry@intel.com>
-
-----------------------------
-
-What:	pci_scan_bus_parented()
-When:	3.5
-Why:	The pci_scan_bus_parented() interface creates a new root bus.  The
-	bus is created with default resources (ioport_resource and
-	iomem_resource) that are always wrong, so we rely on arch code to
-	correct them later.  Callers of pci_scan_bus_parented() should
-	convert to using pci_scan_root_bus() so they can supply a list of
-	bus resources when the bus is created.
-Who:	Bjorn Helgaas <bhelgaas@google.com>
-
-----------------------------
-
-What:	Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
-When:	3.6
-Why:	This driver provides support for USB storage devices like "USB
-	sticks". As of now, it is deactivated in Debian, Fedora and
-        Ubuntu. All current users can switch over to usb-storage
-        (CONFIG_USB_STORAGE) which only drawback is the additional SCSI
-        stack.
-Who:	Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
-
-----------------------------
-
-What:	get_robust_list syscall
-When:	2013
-Why:	There appear to be no production users of the get_robust_list syscall,
-	and it runs the risk of leaking address locations, allowing the bypass
-	of ASLR. It was only ever intended for debugging, so it should be
-	removed.
-Who:	Kees Cook <keescook@chromium.org>
-
-----------------------------
-
-What:	Removing the pn544 raw driver.
-When:	3.6
-Why:	With the introduction of the NFC HCI and SHDL kernel layers, pn544.c
-	is being replaced by pn544_hci.c which is accessible through the netlink
-	and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to
-	work properly with the latest Android stacks.
-	Having 2 drivers for the same hardware is confusing and as such we
-	should only keep the one following the kernel NFC APIs.
-Who:	Samuel Ortiz <sameo@linux.intel.com>
-
-----------------------------
-
-What:	setitimer accepts user NULL pointer (value)
-When:	3.6
-Why:	setitimer is not returning -EFAULT if user pointer is NULL. This
-	violates the spec.
-Who:	Sasikantha Babu <sasikanth.v19@gmail.com>
-
-----------------------------
-
-What:	remove bogus DV presets V4L2_DV_1080I29_97, V4L2_DV_1080I30 and
-	V4L2_DV_1080I25
-When:	3.6
-Why:	These HDTV formats do not exist and were added by a confused mind
-	(that was me, to be precise...)
-Who:	Hans Verkuil <hans.verkuil@cisco.com>
-
-----------------------------
-
-What:	V4L2_CID_HCENTER, V4L2_CID_VCENTER V4L2 controls
-When:	3.7
-Why:	The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated
-	for about 4 years and they are not used by any mainline driver.
-	There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide
-	similar	functionality.
-Who:	Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
-
-----------------------------
-
-What:	cgroup option updates via remount
-When:	March 2013
-Why:	Remount currently allows changing bound subsystems and
-	release_agent.  Rebinding is hardly useful as it only works
-	when the hierarchy is empty and release_agent itself should be
-	replaced with conventional fsnotify.
-
-----------------------------
-
-What:  xt_recent rev 0
-When:  2013
-Who:   Pablo Neira Ayuso <pablo@netfilter.org>
-Files: net/netfilter/xt_recent.c
-
-----------------------------
-
-What:	KVM debugfs statistics
-When:	2013
-Why:	KVM tracepoints provide mostly equivalent information in a much more
-        flexible fashion.
-
-----------------------------
-
-What:	at91-mci driver ("CONFIG_MMC_AT91")
-When:	3.8
-Why:	There are two mci drivers: at91-mci and atmel-mci. The PDC support
-	was added to atmel-mci as a first step to support more chips.
-	Then at91-mci was kept only for old IP versions (on at91rm9200 and
-	at91sam9261). The support of these IP versions has just been added
-	to atmel-mci, so atmel-mci can be used for all chips.
-Who:	Ludovic Desroches <ludovic.desroches@atmel.com>
-
-----------------------------
-
-What:	net/wanrouter/
-When:	June 2013
-Why:	Unsupported/unmaintained/unused since 2.6
-
-----------------------------
-
-What:	V4L2 selections API target rectangle and flags unification, the
-	following definitions will be removed: V4L2_SEL_TGT_CROP_ACTIVE,
-	V4L2_SEL_TGT_COMPOSE_ACTIVE, V4L2_SUBDEV_SEL_*, V4L2_SUBDEV_SEL_FLAG_*
-	in favor of common V4L2_SEL_TGT_* and V4L2_SEL_FLAG_* definitions.
-	For more details see include/linux/v4l2-common.h.
-When:	3.8
-Why:	The regular V4L2 selections and the subdev selection API originally
-	defined distinct names for the target rectangles and flags - V4L2_SEL_*
-	and V4L2_SUBDEV_SEL_*. Although, it turned out that the meaning of these
-	target rectangles is virtually identical and the APIs were consolidated
-	to use single set of names - V4L2_SEL_*. This didn't involve any ABI
-	changes. Alias definitions were created for the original ones to avoid
-	any instabilities in the user space interface. After few cycles these
-	backward compatibility definitions will be removed.
-Who:	Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
-
-----------------------------
-
-What:	Using V4L2_CAP_VIDEO_CAPTURE and V4L2_CAP_VIDEO_OUTPUT flags
-	to indicate a V4L2 memory-to-memory device capability
-When:	3.8
-Why:	New drivers should use new V4L2_CAP_VIDEO_M2M capability flag
-	to indicate a V4L2 video memory-to-memory (M2M) device and
-	applications can now identify a M2M video device by checking
-	for V4L2_CAP_VIDEO_M2M, with VIDIOC_QUERYCAP ioctl. Using ORed
-	V4L2_CAP_VIDEO_CAPTURE and V4L2_CAP_VIDEO_OUTPUT flags for M2M
-	devices is ambiguous and may lead, for example, to identifying
-	a M2M device as a video	capture or output device.
-Who:	Sylwester Nawrocki <s.nawrocki@samsung.com>
-
-----------------------------
-
-What:	OMAP private DMA implementation
-When:	2013
-Why:	We have a DMA engine implementation; all users should be updated
-	to use this rather than persisting with the old APIs.  The old APIs
-	block merging the old DMA engine implementation into the DMA
-	engine driver.
-Who:	Russell King <linux@arm.linux.org.uk>,
-	Santosh Shilimkar <santosh.shilimkar@ti.com>
-
-----------------------------
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
index 7a34f82..3a863f6 100644
--- a/Documentation/filesystems/debugfs.txt
+++ b/Documentation/filesystems/debugfs.txt
@@ -15,8 +15,8 @@
     mount -t debugfs none /sys/kernel/debug
 
 (Or an equivalent /etc/fstab line).
-The debugfs root directory is accessible by anyone by default. To
-restrict access to the tree the "uid", "gid" and "mode" mount
+The debugfs root directory is accessible only to the root user by
+default. To change access to the tree the "uid", "gid" and "mode" mount
 options can be used.
 
 Note that the debugfs API is exported GPL-only to modules.
diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt
new file mode 100755
index 0000000..948b098
--- /dev/null
+++ b/Documentation/hid/hid-sensor.txt
@@ -0,0 +1,140 @@
+
+HID Sensors Framework
+======================
+HID sensor framework provides necessary interfaces to implement sensor drivers,
+which are connected to a sensor hub. The sensor hub is a HID device and it provides
+a report descriptor conforming to HID 1.12 sensor usage tables.
+
+Description from the HID 1.12 "HID Sensor Usages" specification:
+"Standardization of HID usages for sensors would allow (but not require) sensor
+hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
+thereby enabling some operating systems to incorporate common device drivers that
+could be reused between vendors, alleviating any need for the vendors to provide
+the drivers themselves."
+
+This specification describes many usage IDs, which describe the type of sensor
+and also the individual data fields. Each sensor can have variable number of
+data fields. The length and order is specified in the report descriptor. For
+example a part of report descriptor can look like:
+
+   INPUT(1)[INPUT]
+ ..
+    Field(2)
+      Physical(0020.0073)
+      Usage(1)
+        0020.045f
+      Logical Minimum(-32767)
+      Logical Maximum(32767)
+      Report Size(8)
+      Report Count(1)
+      Report Offset(16)
+      Flags(Variable Absolute)
+..
+..
+
+The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
+This accelerometer-3D has some fields. Here for example field 2 is motion intensity
+(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
+order of fields and length of each field is important as the input event raw
+data will use this format.
+
+
+Implementation
+=================
+
+This specification defines many different types of sensors with different sets of
+data fields. It is difficult to have a common input event to user space applications,
+for different sensors. For example an accelerometer can send X,Y and Z data, whereas
+an ambient light sensor can send illumination data.
+So the implementation has two parts:
+- Core hid driver
+- Individual sensor processing part (sensor drivers)
+
+Core driver
+-----------
+The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
+report descriptors and identifies all the sensors present. It adds an MFD device
+with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
+For example
+HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
+So if any driver with this name is inserted, then the probe routine for that
+function will be called. So an accelerometer processing driver can register
+with this name and will be probed if there is an accelerometer-3D detected.
+
+The core driver provides a set of APIs which can be used by the processing
+drivers to register and get events for that usage id. Also it provides parsing
+functions, which get and set each input/feature/output report.
+
+Individual sensor processing part (sensor drivers)
+-----------
+The processing driver will use an interface provided by the core driver to parse
+the report and get the indexes of the fields and also can get events. This driver
+can use IIO interface to use the standard ABI defined for a type of sensor.
+
+
+Core driver Interface
+=====================
+
+Callback structure:
+Each processing driver can use this structure to set some callbacks.
+	int (*suspend)(..): Callback when HID suspend is received
+	int (*resume)(..): Callback when HID resume is received
+	int (*capture_sample)(..): Capture a sample for one of its data fields
+	int (*send_event)(..): One complete event is received which can have
+                               multiple data fields.
+
+Registration functions:
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback):
+
+Registers callbacks for an usage id. The callback functions are not allowed
+to sleep.
+
+
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id):
+
+Removes callbacks for an usage id.
+
+
+Parsing function:
+int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
+			u8 type,
+			u32 usage_id, u32 attr_usage_id,
+			struct hid_sensor_hub_attribute_info *info);
+
+A processing driver can look for some field of interest and check if it exists
+in a report descriptor. If it exists it will store necessary information
+so that fields can be set or get individually.
+These indexes avoid searching every time and getting field index to get or set.
+
+
+Set Feature report
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 value);
+
+This interface is used to set a value for a field in feature report. For example
+if there is a field report_interval, which is parsed by a call to
+sensor_hub_input_get_attribute_info before, then it can directly set that individual
+field.
+
+
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 *value);
+
+This interface is used to get a value for a field in input report. For example
+if there is a field report_interval, which is parsed by a call to
+sensor_hub_input_get_attribute_info before, then it can directly get that individual
+field value.
+
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			u32 attr_usage_id, u32 report_id);
+
+This is used to get a particular field value through input reports. For example
+accelerometer wants to poll X axis value, then it can call this function with
+the usage id of X axis. HID sensors can provide events, so this is not necessary
+to poll for any field. If there is some new sample, the core driver will call
+registered callback function to process the sample.
diff --git a/Documentation/hwmon/adt7410 b/Documentation/hwmon/adt7410
new file mode 100644
index 0000000..9600400
--- /dev/null
+++ b/Documentation/hwmon/adt7410
@@ -0,0 +1,51 @@
+Kernel driver adt7410
+=====================
+
+Supported chips:
+  * Analog Devices ADT7410
+    Prefix: 'adt7410'
+    Addresses scanned: I2C 0x48 - 0x4B
+    Datasheet: Publicly available at the Analog Devices website
+               http://www.analog.com/static/imported-files/data_sheets/ADT7410.pdf
+
+Author: Hartmut Knaack <knaack.h@gmx.de>
+
+Description
+-----------
+
+The ADT7410 is a temperature sensor with rated temperature range of -55°C to
++150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
+of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
+indicate that a minimum or maximum temperature set point has been exceeded, as
+well as a critical temperature (CT) pin to indicate that the critical
+temperature set point has been exceeded. Both pins can be set up with a common
+hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
+pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410
+supports continous temperature sampling, as well as sampling one temperature
+value per second or even justget one sample on demand for power saving.
+Besides, it can completely power down its ADC, if power management is
+required.
+
+Configuration Notes
+-------------------
+
+Since the device uses one hysteresis value, which is an offset to minimum,
+maximum and critical temperature, it can only be set for temp#_max_hyst.
+However, temp#_min_hyst and temp#_crit_hyst show their corresponding
+hysteresis.
+The device is set to 16 bit resolution and comparator mode.
+
+sysfs-Interface
+---------------
+
+temp#_input		- temperature input
+temp#_min		- temperature minimum setpoint
+temp#_max		- temperature maximum setpoint
+temp#_crit		- critical temperature setpoint
+temp#_min_hyst		- hysteresis for temperature minimum (read-only)
+temp#_max_hyst		- hysteresis for temperature maximum (read/write)
+temp#_crit_hyst		- hysteresis for critical temperature (read-only)
+temp#_min_alarm		- temperature minimum alarm flag
+temp#_max_alarm		- temperature maximum alarm flag
+temp#_crit_alarm	- critical temperature alarm flag
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index f50a6cc2..03444f9 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -8,12 +8,24 @@
     Datasheet: Publicly available at the Texas Instruments website
                http://www.ti.com/
 
+  * Texas Instruments INA220
+    Prefix: 'ina220'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
   * Texas Instruments INA226
     Prefix: 'ina226'
     Addresses: I2C 0x40 - 0x4f
     Datasheet: Publicly available at the Texas Instruments website
                http://www.ti.com/
 
+  * Texas Instruments INA230
+    Prefix: 'ina230'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
 Author: Lothar Felten <l-felten@ti.com>
 
 Description
@@ -23,7 +35,13 @@
 interface. The INA219 monitors both shunt drop and supply voltage, with
 programmable conversion times and filtering.
 
+The INA220 is a high or low side current shunt and power monitor with an I2C
+interface. The INA220 monitors both shunt drop and supply voltage.
+
 The INA226 is a current shunt and power monitor with an I2C interface.
 The INA226 monitors both a shunt voltage drop and bus supply voltage.
 
+The INA230 is a high or low side current shunt and power monitor with an I2C
+interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
+
 The shunt value in micro-ohms can be set via platform data.
diff --git a/Documentation/hwmon/lm70 b/Documentation/hwmon/lm70
index 0d24029..86d1829 100644
--- a/Documentation/hwmon/lm70
+++ b/Documentation/hwmon/lm70
@@ -6,6 +6,10 @@
     Datasheet: http://www.national.com/pf/LM/LM70.html
   * Texas Instruments TMP121/TMP123
     Information: http://focus.ti.com/docs/prod/folders/print/tmp121.html
+  * National Semiconductor LM71
+    Datasheet: http://www.ti.com/product/LM71
+  * National Semiconductor LM74
+    Datasheet: http://www.ti.com/product/LM74
 
 Author:
         Kaiwan N Billimoria <kaiwan@designergraphix.com>
@@ -31,9 +35,11 @@
 with a "SPI master controller driver", see drivers/spi/spi_lm70llp.c
 and its associated documentation.
 
-The TMP121/TMP123 are very similar; main differences are 4 wire SPI inter-
-face (read only) and 13-bit temperature data (0.0625 degrees celsius reso-
-lution).
+The LM74 and TMP121/TMP123 are very similar; main difference is 13-bit
+temperature data (0.0625 degrees celsius resolution).
+
+The LM71 is also very similar; main difference is 14-bit temperature
+data (0.03125 degrees celsius resolution).
 
 Thanks to
 ---------
diff --git a/Documentation/hwmon/max197 b/Documentation/hwmon/max197
new file mode 100644
index 0000000..8d89b90
--- /dev/null
+++ b/Documentation/hwmon/max197
@@ -0,0 +1,60 @@
+Maxim MAX197 driver
+===================
+
+Author:
+  * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+
+Supported chips:
+  * Maxim MAX197
+    Prefix: 'max197'
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX197.pdf
+
+  * Maxim MAX199
+    Prefix: 'max199'
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX199.pdf
+
+Description
+-----------
+
+The A/D converters MAX197, and MAX199 are both 8-Channel, Multi-Range, 5V,
+12-Bit DAS with 8+4 Bus Interface and Fault Protection.
+
+The available ranges for the MAX197 are {0,-5V} to 5V, and {0,-10V} to 10V,
+while they are {0,-2V} to 2V, and {0,-4V} to 4V on the MAX199.
+
+Platform data
+-------------
+
+The MAX197 platform data (defined in linux/platform_data/max197.h) should be
+filled with a pointer to a conversion function, defined like:
+
+    int convert(u8 ctrl);
+
+ctrl is the control byte to write to start a new conversion.
+On success, the function must return the 12-bit raw value read from the chip,
+or a negative error code otherwise.
+
+Control byte format:
+
+Bit     Name       Description
+7,6     PD1,PD0    Clock and Power-Down modes
+5       ACQMOD     Internal or External Controlled Acquisition
+4       RNG        Full-scale voltage magnitude at the input
+3       BIP        Unipolar or Bipolar conversion mode
+2,1,0   A2,A1,A0   Channel
+
+Sysfs interface
+---------------
+
+* in[0-7]_input: The conversion value for the corresponding channel.
+                 RO
+
+* in[0-7]_min:   The lower limit (in mV) for the corresponding channel.
+                 For the MAX197, it will be adjusted to -10000, -5000, or 0.
+                 For the MAX199, it will be adjusted to -4000, -2000, or 0.
+                 RW
+
+* in[0-7]_max:   The higher limit (in mV) for the corresponding channel.
+                 For the MAX197, it will be adjusted to 0, 5000, or 10000.
+                 For the MAX199, it will be adjusted to 0, 2000, or 4000.
+                 RW
diff --git a/Documentation/hwmon/mcp3021 b/Documentation/hwmon/mcp3021
index 325fd87..74a6b72 100644
--- a/Documentation/hwmon/mcp3021
+++ b/Documentation/hwmon/mcp3021
@@ -5,18 +5,25 @@
   * Microchip Technology MCP3021
     Prefix: 'mcp3021'
     Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
+  * Microchip Technology MCP3221
+    Prefix: 'mcp3221'
+    Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21732c.pdf
 
-Author: Mingkai Hu
+Authors:
+   Mingkai Hu
+   Sven Schuchmann <schuchmann@schleissheimer.de>
 
 Description
 -----------
 
-This driver implements support for the Microchip Technology MCP3021 chip.
+This driver implements support for the Microchip Technology MCP3021 and
+MCP3221 chip.
 
 The Microchip Technology Inc. MCP3021 is a successive approximation A/D
-converter (ADC) with 10-bit resolution.
-This device provides one single-ended input with very low power consumption.
-Communication to the MCP3021 is performed using a 2-wire I2C compatible
-interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
-The default I2C device address is 0x4d (contact the Microchip factory for
-additional address options).
+converter (ADC) with 10-bit resolution. The MCP3221 has 12-bit resolution.
+
+These devices provide one single-ended input with very low power consumption.
+Communication to the MCP3021/MCP3221  is performed using a 2-wire I2C
+compatible interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are
+available. The default I2C device address is 0x4d (contact the Microchip
+factory for additional address options).
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
index 5caa2af3..62a190d 100644
--- a/Documentation/ia64/aliasing-test.c
+++ b/Documentation/ia64/aliasing-test.c
@@ -132,6 +132,7 @@
 
 	rc = write(fd, "1", 2);
 	if (rc <= 0) {
+		close(fd);
 		perror("write");
 		return -1;
 	}
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index ad7e2e5..df43807 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1812,8 +1812,12 @@
 			noexec=on: enable non-executable mappings (default)
 			noexec=off: disable non-executable mappings
 
+	nosmap		[X86]
+			Disable SMAP (Supervisor Mode Access Prevention)
+			even if it is supported by processor.
+
 	nosmep		[X86]
-			Disable SMEP (Supervisor Mode Execution Protection)
+			Disable SMEP (Supervisor Mode Execution Prevention)
 			even if it is supported by processor.
 
 	noexec32	[X86-64]
@@ -1833,6 +1837,12 @@
 			and restore using xsave. The kernel will fallback to
 			enabling legacy floating-point and sse state.
 
+	eagerfpu=	[X86]
+			on	enable eager fpu restore
+			off	disable eager fpu restore
+			auto	selects the default scheme, which automatically
+				enables eagerfpu restore for xsaveopt.
+
 	nohlt		[BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
 			wfi(ARM) instruction doesn't work correctly and not to
 			use it. This is also useful when using JTAG debugger.
@@ -2385,6 +2395,17 @@
 	rcutree.rcu_cpu_stall_timeout= [KNL,BOOT]
 			Set timeout for RCU CPU stall warning messages.
 
+	rcutree.jiffies_till_first_fqs= [KNL,BOOT]
+			Set delay from grace-period initialization to
+			first attempt to force quiescent states.
+			Units are jiffies, minimum value is zero,
+			and maximum value is HZ.
+
+	rcutree.jiffies_till_next_fqs= [KNL,BOOT]
+			Set delay between subsequent attempts to force
+			quiescent states.  Units are jiffies, minimum
+			value is one, and maximum value is HZ.
+
 	rcutorture.fqs_duration= [KNL,BOOT]
 			Set duration of force_quiescent_state bursts.
 
@@ -2638,9 +2659,6 @@
 	smart2=		[HW]
 			Format: <io1>[,<io2>[,...,<io8>]]
 
-	smp-alt-once	[X86-32,SMP] On a hotplug CPU system, only
-			attempt to substitute SMP alternatives once at boot.
-
 	smsc-ircc2.nopnp	[HW] Don't use PNP to discover SMC devices
 	smsc-ircc2.ircc_cfg=	[HW] Device configuration I/O port
 	smsc-ircc2.ircc_sir=	[HW] SIR base I/O port
diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
index 49578cf..c5182bb 100644
--- a/Documentation/kobject.txt
+++ b/Documentation/kobject.txt
@@ -284,9 +284,11 @@
 kobj_type:
 
     struct kobj_type {
-	    void (*release)(struct kobject *);
+	    void (*release)(struct kobject *kobj);
 	    const struct sysfs_ops *sysfs_ops;
-	    struct attribute	**default_attrs;
+	    struct attribute **default_attrs;
+	    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
+	    const void *(*namespace)(struct kobject *kobj);
     };
 
 This structure is used to describe a particular type of kobject (or, more
diff --git a/Documentation/misc-devices/lis3lv02d b/Documentation/misc-devices/lis3lv02d
index f1a4ec8..af815b9 100644
--- a/Documentation/misc-devices/lis3lv02d
+++ b/Documentation/misc-devices/lis3lv02d
@@ -4,7 +4,8 @@
 Supported chips:
 
   * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
-  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits)
+  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and
+    LIS331DLH (16 bits)
 
 Authors:
         Yan Burman <burman.yan@gmail.com>
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 92341b8..0b4b63e 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -53,7 +53,7 @@
 
 Article about goals and implementation of Software Suspend for Linux
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Author: G‚ábor Kuti
+Author: Gábor Kuti
 Last revised: 2003-10-20 by Pavel Machek
 
 Idea and goals to achieve
diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt
index 28aa107..b1b8587 100644
--- a/Documentation/scheduler/sched-arch.txt
+++ b/Documentation/scheduler/sched-arch.txt
@@ -17,16 +17,6 @@
 Unlocked context switches introduce only a very minor performance
 penalty to the core scheduler implementation in the CONFIG_SMP case.
 
-2. Interrupt status
-By default, the switch_to arch function is called with interrupts
-disabled. Interrupts may be enabled over the call if it is likely to
-introduce a significant interrupt latency by adding the line
-`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
-unlocked context switches. This define also implies
-`__ARCH_WANT_UNLOCKED_CTXSW`. See arch/arm/include/asm/system.h for an
-example.
-
-
 CPU idle
 ========
 Your cpu_idle routines need to obey the following rules:
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
index d0d0bb9..d68ea5f 100644
--- a/Documentation/trace/kprobetrace.txt
+++ b/Documentation/trace/kprobetrace.txt
@@ -12,7 +12,7 @@
 functions). Unlike the Tracepoint based event, this can be added and removed
 dynamically, on the fly.
 
-To enable this feature, build your kernel with CONFIG_KPROBE_TRACING=y.
+To enable this feature, build your kernel with CONFIG_KPROBE_EVENT=y.
 
 Similar to the events tracer, this doesn't need to be activated via
 current_tracer. Instead of that, add probe points via
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
index 074b159..35d70ed 100644
--- a/Documentation/usb/persist.txt
+++ b/Documentation/usb/persist.txt
@@ -155,6 +155,9 @@
 data corruption and to crash your system.  You'll have no one to blame
 but yourself.
 
+For those devices with avoid_reset_quirk attribute being set, persist
+maybe fail because they may morph after reset.
+
 YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK!
 
 That having been said, most of the time there shouldn't be any trouble
diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
index 0cb6685..8eda363 100644
--- a/Documentation/vfio.txt
+++ b/Documentation/vfio.txt
@@ -133,7 +133,7 @@
 $ lspci -n -s 0000:06:0d.0
 06:0d.0 0401: 1102:0002 (rev 08)
 # echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
-# echo 1102 0002 > /sys/bus/pci/drivers/vfio/new_id
+# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
 
 Now we need to look at what other devices are in the group to free
 it for use by VFIO:
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index c54b4f5..de38429 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -50,6 +50,13 @@
 		monarchtimeout:
 		Sets the time in us to wait for other CPUs on machine checks. 0
 		to disable.
+   mce=bios_cmci_threshold
+		Don't overwrite the bios-set CMCI threshold. This boot option
+		prevents Linux from overwriting the CMCI threshold set by the
+		bios. Without this option, Linux always sets the CMCI
+		threshold to 1. Enabling this may make memory predictive failure
+		analysis less effective if the bios sets thresholds for memory
+		errors since we will not see details for all errors.
 
    nomce (for compatibility with i386): same as mce=off
 
diff --git a/Documentation/zh_CN/arm/Booting b/Documentation/zh_CN/arm/Booting
new file mode 100644
index 0000000..6158a64
--- /dev/null
+++ b/Documentation/zh_CN/arm/Booting
@@ -0,0 +1,175 @@
+Chinese translated version of Documentation/arm/Booting
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Russell King <linux@arm.linux.org.uk>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/arm/Booting 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Russell King <linux@arm.linux.org.uk>
+中文版维护者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
+中文版翻译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
+中文版校译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+			启动 ARM Linux
+			==============
+
+作者:Russell King
+日期:2002年5月18日
+
+以下文档适用于 2.4.18-rmk6 及以上版本。
+
+为了启动 ARM Linux,你需要一个引导装载程序(boot loader),
+它是一个在主内核启动前运行的一个小程序。引导装载程序需要初始化各种
+设备,并最终调用 Linux 内核,将信息传递给内核。
+
+从本质上讲,引导装载程序应提供(至少)以下功能:
+
+1、设置和初始化 RAM。
+2、初始化一个串口。
+3、检测机器的类型(machine type)。
+4、设置内核标签列表(tagged list)。
+5、调用内核映像。
+
+
+1、设置和初始化 RAM
+-------------------
+
+现有的引导加载程序:		强制
+新开发的引导加载程序:		强制
+
+引导装载程序应该找到并初始化系统中所有内核用于保持系统变量数据的 RAM。
+这个操作的执行是设备依赖的。(它可能使用内部算法来自动定位和计算所有
+RAM,或可能使用对这个设备已知的 RAM 信息,还可能使用任何引导装载程序
+设计者想到的匹配方法。)
+
+
+2、初始化一个串口
+-----------------------------
+
+现有的引导加载程序:		可选、建议
+新开发的引导加载程序:		可选、建议
+
+引导加载程序应该初始化并使能一个目标板上的串口。这允许内核串口驱动
+自动检测哪个串口用于内核控制台。(一般用于调试或与目标板通信。)
+
+作为替代方案,引导加载程序也可以通过标签列表传递相关的'console='
+选项给内核以指定某个串口,而串口数据格式的选项在以下文档中描述:
+
+       Documentation/kernel-parameters.txt。
+
+
+3、检测机器类型
+--------------------------
+
+现有的引导加载程序:		可选
+新开发的引导加载程序:		强制
+
+引导加载程序应该通过某些方式检测自身所处的机器类型。这是一个硬件
+代码或通过查看所连接的硬件用某些算法得到,这些超出了本文档的范围。
+引导加载程序最终必须能提供一个 MACH_TYPE_xxx 值给内核。
+(详见 linux/arch/arm/tools/mach-types )。
+
+4、设置启动数据
+------------------
+
+现有的引导加载程序:		可选、强烈建议
+新开发的引导加载程序:		强制
+
+引导加载程序必须提供标签列表或者 dtb 映像以传递配置数据给内核。启动
+数据的物理地址通过寄存器 r2 传递给内核。
+
+4a、设置内核标签列表
+--------------------------------
+
+bootloader 必须创建和初始化内核标签列表。一个有效的标签列表以
+ATAG_CORE 标签开始,并以 ATAG_NONE 标签结束。ATAG_CORE 标签可以是
+空的,也可以是非空。一个空 ATAG_CORE 标签其 size 域设置为
+‘2’(0x00000002)。ATAG_NONE 标签的 size 域必须设置为零。
+
+在列表中可以保存任意数量的标签。对于一个重复的标签是追加到之前标签
+所携带的信息之后,还是会覆盖原来的信息,是未定义的。某些标签的行为
+是前者,其他是后者。
+
+bootloader 必须传递一个系统内存的位置和最小值,以及根文件系统位置。
+因此,最小的标签列表如下所示:
+
+		+-----------+
+基地址 ->	| ATAG_CORE |  |
+		+-----------+  |
+		| ATAG_MEM  |  | 地址增长方向
+		+-----------+  |
+		| ATAG_NONE |  |
+		+-----------+  v
+
+标签列表应该保存在系统的 RAM 中。
+
+标签列表必须置于内核自解压和 initrd'bootp' 程序都不会覆盖的内存区。
+建议放在 RAM 的头 16KiB 中。
+
+4b、设置设备树
+-------------------------
+
+bootloader 必须以 64bit 地址对齐的形式加载一个设备树映像(dtb)到系统
+RAM 中,并用启动数据初始化它。dtb 格式在文档
+Documentation/devicetree/booting-without-of.txt 中。内核将会在
+dtb 物理地址处查找 dtb 魔数值(0xd00dfeed),以确定 dtb 是否已经代替
+标签列表被传递进来。
+
+bootloader 必须传递一个系统内存的位置和最小值,以及根文件系统位置。
+dtb 必须置于内核自解压不会覆盖的内存区。建议将其放置于 RAM 的头 16KiB
+中。但是不可将其放置于“0”物理地址处,因为内核认为:r2 中为 0,意味着
+没有标签列表和 dtb 传递过来。
+
+5、调用内核映像
+---------------------------
+
+现有的引导加载程序:		强制
+新开发的引导加载程序:		强制
+
+调用内核映像 zImage 有两个选择。如果 zImge 保存在 flash 中,且是为了
+在 flash 中直接运行而被正确链接的。这样引导加载程序就可以在 flash 中
+直接调用 zImage。
+
+zImage 也可以被放在系统 RAM(任意位置)中被调用。注意:内核使用映像
+基地址的前 16KB RAM 空间来保存页表。建议将映像置于 RAM 的 32KB 处。
+
+对于以上任意一种情况,都必须符合以下启动状态:
+
+- 停止所有 DMA 设备,这样内存数据就不会因为虚假网络包或磁盘数据而被破坏。
+  这可能可以节省你许多的调试时间。
+
+- CPU 寄存器配置
+  r0 = 0,
+  r1 = (在上面 3 中获取的)机器类型码。
+  r2 = 标签列表在系统 RAM 中的物理地址,或
+       设备树块(dtb)在系统 RAM 中的物理地址
+
+- CPU 模式
+  所有形式的中断必须被禁止 (IRQs 和 FIQs)
+  CPU 必须处于 SVC 模式。(对于 Angel 调试有特例存在)
+
+- 缓存,MMUs
+  MMU 必须关闭。
+  指令缓存开启或关闭都可以。
+  数据缓存必须关闭。
+
+- 引导加载程序应该通过直接跳转到内核映像的第一条指令来调用内核映像。
+
+  对于支持 ARM 指令集的 CPU,跳入内核入口时必须处在 ARM 状态,即使
+  对于 Thumb-2 内核也是如此。
+
+  对于仅支持 Thumb 指令集的 CPU,比如 Cortex-M 系列的 CPU,跳入
+  内核入口时必须处于 Thumb 状态。
diff --git a/Documentation/zh_CN/basic_profiling.txt b/Documentation/zh_CN/basic_profiling.txt
new file mode 100644
index 0000000..1e6bf0b
--- /dev/null
+++ b/Documentation/zh_CN/basic_profiling.txt
@@ -0,0 +1,71 @@
+Chinese translated version of Documentation/basic_profiling
+
+If you have any comment or update to the content, please post to LKML directly.
+However, if you have problem communicating in English you can also ask the
+Chinese maintainer for help.  Contact the Chinese maintainer, if this
+translation is outdated or there is problem with translation.
+
+Chinese maintainer: Liang Xie <xieliang@xiaomi.com>
+---------------------------------------------------------------------
+Documentation/basic_profiling的中文翻译
+
+如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
+以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
+
+中文版维护者: 谢良 Liang Xie <xieliang007@gmail.com>
+中文版翻译者: 谢良 Liang Xie <xieliang007@gmail.com>
+中文版校译者:
+以下为正文
+---------------------------------------------------------------------
+
+下面这些说明指令都是非常基础的,如果你想进一步了解请阅读相关专业文档:)
+请不要再在本文档增加新的内容,但可以修复文档中的错误:)(mbligh@aracnet.com)
+感谢John Levon,Dave Hansen等在撰写时的帮助
+
+<test> 用于表示要测量的目标
+请先确保您已经有正确的System.map / vmlinux配置!
+
+对于linux系统来说,配置vmlinuz最容易的方法可能就是使用“make install”,然后修改
+/sbin/installkernel将vmlinux拷贝到/boot目录,而System.map通常是默认安装好的
+
+Readprofile
+-----------
+2.6系列内核需要版本相对较新的readprofile,比如util-linux 2.12a中包含的,可以从:
+
+http://www.kernel.org/pub/linux/utils/util-linux/ 下载
+
+大部分linux发行版已经包含了.
+
+启用readprofile需要在kernel启动命令行增加”profile=2“
+
+clear		readprofile -r
+		<test>
+dump output	readprofile -m /boot/System.map > captured_profile
+
+Oprofile
+--------
+
+从http://oprofile.sourceforge.net/获取源代码(请参考Changes以获取匹配的版本)
+在kernel启动命令行增加“idle=poll”
+
+配置CONFIG_PROFILING=y和CONFIG_OPROFILE=y然后重启进入新kernel
+
+./configure --with-kernel-support
+make install
+
+想得到好的测量结果,请确保启用了本地APIC特性。如果opreport显示有0Hz CPU,
+说明APIC特性没有开启。另外注意idle=poll选项可能有损性能。
+
+One time setup:
+		opcontrol --setup --vmlinux=/boot/vmlinux
+
+clear		opcontrol --reset
+start		opcontrol --start
+		<test>
+stop		opcontrol --stop
+dump output	opreport >  output_file
+
+如果只看kernel相关的报告结果,请运行命令 opreport -l /boot/vmlinux > output_file
+
+通过reset选项可以清理过期统计数据,相当于重启的效果。
+
diff --git a/Documentation/zh_CN/filesystems/sysfs.txt b/Documentation/zh_CN/filesystems/sysfs.txt
new file mode 100644
index 0000000..e230eaa
--- /dev/null
+++ b/Documentation/zh_CN/filesystems/sysfs.txt
@@ -0,0 +1,372 @@
+Chinese translated version of Documentation/filesystems/sysfs.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Patrick Mochel	<mochel@osdl.org>
+		Mike Murphy <mamurph@cs.clemson.edu>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/filesystems/sysfs.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+英文版维护者: Patrick Mochel	<mochel@osdl.org>
+		Mike Murphy <mamurph@cs.clemson.edu>
+中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+
+
+以下为正文
+---------------------------------------------------------------------
+sysfs - 用于导出内核对象(kobject)的文件系统
+
+Patrick Mochel	<mochel@osdl.org>
+Mike Murphy <mamurph@cs.clemson.edu>
+
+修订:    16 August 2011
+原始版本:   10 January 2003
+
+
+sysfs 简介:
+~~~~~~~~~~
+
+sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导出内核
+数据结构及其属性,以及它们之间的关联到用户空间的方法。
+
+sysfs 始终与 kobject 的底层结构紧密相关。请阅读
+Documentation/kobject.txt 文档以获得更多关于 kobject 接口的
+信息。
+
+
+使用 sysfs
+~~~~~~~~~~~
+
+只要内核配置中定义了 CONFIG_SYSFS ,sysfs 总是被编译进内核。你可
+通过以下命令挂载它:
+
+    mount -t sysfs sysfs /sys
+
+
+创建目录
+~~~~~~~~
+
+任何 kobject 在系统中注册,就会有一个目录在 sysfs 中被创建。这个
+目录是作为该 kobject 的父对象所在目录的子目录创建的,以准确地传递
+内核的对象层次到用户空间。sysfs 中的顶层目录代表着内核对象层次的
+共同祖先;例如:某些对象属于某个子系统。
+
+Sysfs 在与其目录关联的 sysfs_dirent 对象中内部保存一个指向实现
+目录的 kobject 的指针。以前,这个 kobject 指针被 sysfs 直接用于
+kobject 文件打开和关闭的引用计数。而现在的 sysfs 实现中,kobject
+引用计数只能通过 sysfs_schedule_callback() 函数直接修改。
+
+
+属性
+~~~~
+
+kobject 的属性可在文件系统中以普通文件的形式导出。Sysfs 为属性定义
+了面向文件 I/O 操作的方法,以提供对内核属性的读写。
+
+
+属性应为 ASCII 码文本文件。以一个文件只存储一个属性值为宜。但一个
+文件只包含一个属性值可能影响效率,所以一个包含相同数据类型的属性值
+数组也被广泛地接受。
+
+混合类型、表达多行数据以及一些怪异的数据格式会遭到强烈反对。这样做是
+很丢脸的,而且其代码会在未通知作者的情况下被重写。
+
+
+一个简单的属性结构定义如下:
+
+struct attribute {
+        char                    * name;
+        struct module		*owner;
+        umode_t                 mode;
+};
+
+
+int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
+void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
+
+
+一个单独的属性结构并不包含读写其属性值的方法。子系统最好为增删特定
+对象类型的属性定义自己的属性结构体和封装函数。
+
+例如:驱动程序模型定义的 device_attribute 结构体如下:
+
+struct device_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+			char *buf);
+	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count);
+};
+
+int device_create_file(struct device *, const struct device_attribute *);
+void device_remove_file(struct device *, const struct device_attribute *);
+
+为了定义设备属性,同时定义了一下辅助宏:
+
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
+
+例如:声明
+
+static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
+
+等同于如下代码:
+
+static struct device_attribute dev_attr_foo = {
+       .attr	= {
+		.name = "foo",
+		.mode = S_IWUSR | S_IRUGO,
+		.show = show_foo,
+		.store = store_foo,
+	},
+};
+
+
+子系统特有的回调函数
+~~~~~~~~~~~~~~~~~~~
+
+当一个子系统定义一个新的属性类型时,必须实现一系列的 sysfs 操作,
+以帮助读写调用实现属性所有者的显示和储存方法。
+
+struct sysfs_ops {
+        ssize_t (*show)(struct kobject *, struct attribute *, char *);
+        ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
+};
+
+[子系统应已经定义了一个 struct kobj_type 结构体作为这个类型的
+描述符,并在此保存 sysfs_ops 的指针。更多的信息参见 kobject 的
+文档]
+
+sysfs 会为这个类型调用适当的方法。当一个文件被读写时,这个方法会
+将一般的kobject 和 attribute 结构体指针转换为适当的指针类型后
+调用相关联的函数。
+
+
+示例:
+
+#define to_dev(obj) container_of(obj, struct device, kobj)
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+
+static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+                             char *buf)
+{
+        struct device_attribute *dev_attr = to_dev_attr(attr);
+        struct device *dev = to_dev(kobj);
+        ssize_t ret = -EIO;
+
+        if (dev_attr->show)
+                ret = dev_attr->show(dev, dev_attr, buf);
+        if (ret >= (ssize_t)PAGE_SIZE) {
+                print_symbol("dev_attr_show: %s returned bad count\n",
+                                (unsigned long)dev_attr->show);
+        }
+        return ret;
+}
+
+
+
+读写属性数据
+~~~~~~~~~~~~
+
+在声明属性时,必须指定 show() 或 store() 方法,以实现属性的
+读或写。这些方法的类型应该和以下的设备属性定义一样简单。
+
+ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
+ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                 const char *buf, size_t count);
+
+也就是说,他们应只以一个处理对象、一个属性和一个缓冲指针作为参数。
+
+sysfs 会分配一个大小为 (PAGE_SIZE) 的缓冲区并传递给这个方法。
+Sysfs 将会为每次读写操作调用一次这个方法。这使得这些方法在执行时
+会出现以下的行为:
+
+- 在读方面(read(2)),show() 方法应该填充整个缓冲区。回想属性
+  应只导出了一个属性值或是一个同类型属性值的数组,所以这个代价将
+  不会不太高。
+
+  这使得用户空间可以局部地读和任意的向前搜索整个文件。如果用户空间
+  向后搜索到零或使用‘0’偏移执行一个pread(2)操作,show()方法将
+  再次被调用,以重新填充缓存。
+
+- 在写方面(write(2)),sysfs 希望在第一次写操作时得到整个缓冲区。
+  之后 Sysfs 传递整个缓冲区给 store() 方法。
+
+  当要写 sysfs 文件时,用户空间进程应首先读取整个文件,修该想要
+  改变的值,然后回写整个缓冲区。
+
+  在读写属性值时,属性方法的执行应操作相同的缓冲区。
+
+注记:
+
+- 写操作导致的 show() 方法重载,会忽略当前文件位置。
+
+- 缓冲区应总是 PAGE_SIZE 大小。对于i386,这个值为4096。
+
+- show() 方法应该返回写入缓冲区的字节数,也就是 snprintf()的
+  返回值。
+
+- show() 应始终使用 snprintf()。
+
+- store() 应返回缓冲区的已用字节数。如果整个缓存都已填满,只需返回
+  count 参数。
+
+- show() 或 store() 可以返回错误值。当得到一个非法值,必须返回一个
+  错误值。
+
+- 一个传递给方法的对象将会通过 sysfs 调用对象内嵌的引用计数固定在
+  内存中。尽管如此,对象代表的物理实体(如设备)可能已不存在。如有必要,
+  应该实现一个检测机制。
+
+一个简单的(未经实验证实的)设备属性实现如下:
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
+}
+
+static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+        snprintf(dev->name, sizeof(dev->name), "%.*s",
+                 (int)min(count, sizeof(dev->name) - 1), buf);
+	return count;
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
+
+
+(注意:真正的实现不允许用户空间设置设备名。)
+
+顶层目录布局
+~~~~~~~~~~~~
+
+sysfs 目录的安排显示了内核数据结构之间的关系。
+
+顶层 sysfs 目录如下:
+
+block/
+bus/
+class/
+dev/
+devices/
+firmware/
+net/
+fs/
+
+devices/ 包含了一个设备树的文件系统表示。他直接映射了内部的内核
+设备树,反映了设备的层次结构。
+
+bus/ 包含了内核中各种总线类型的平面目录布局。每个总线目录包含两个
+子目录:
+
+	devices/
+	drivers/
+
+devices/ 包含了系统中出现的每个设备的符号链接,他们指向 root/ 下的
+设备目录。
+
+drivers/ 包含了每个已为特定总线上的设备而挂载的驱动程序的目录(这里
+假定驱动没有跨越多个总线类型)。
+
+fs/ 包含了一个为文件系统设立的目录。现在每个想要导出属性的文件系统必须
+在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.txt)。
+
+dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有以
+<major>:<minor> 格式命名的符号链接。这些符号链接指向 sysfs 目录
+中相应的设备。/sys/dev 提供一个通过一个 stat(2) 操作结果,查找
+设备 sysfs 接口快捷的方法。
+
+更多有关 driver-model 的特性信息可以在 Documentation/driver-model/
+中找到。
+
+
+TODO: 完成这一节。
+
+
+当前接口
+~~~~~~~~
+
+以下的接口层普遍存在于当前的sysfs中:
+
+- 设备 (include/linux/device.h)
+----------------------------------
+结构体:
+
+struct device_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+			char *buf);
+	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count);
+};
+
+声明:
+
+DEVICE_ATTR(_name, _mode, _show, _store);
+
+增/删属性:
+
+int device_create_file(struct device *dev, const struct device_attribute * attr);
+void device_remove_file(struct device *dev, const struct device_attribute * attr);
+
+
+- 总线驱动程序 (include/linux/device.h)
+--------------------------------------
+结构体:
+
+struct bus_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct bus_type *, char * buf);
+        ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+};
+
+声明:
+
+BUS_ATTR(_name, _mode, _show, _store)
+
+增/删属性:
+
+int bus_create_file(struct bus_type *, struct bus_attribute *);
+void bus_remove_file(struct bus_type *, struct bus_attribute *);
+
+
+- 设备驱动程序 (include/linux/device.h)
+-----------------------------------------
+
+结构体:
+
+struct driver_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device_driver *, char * buf);
+        ssize_t (*store)(struct device_driver *, const char * buf,
+                         size_t count);
+};
+
+声明:
+
+DRIVER_ATTR(_name, _mode, _show, _store)
+
+增/删属性:
+
+int driver_create_file(struct device_driver *, const struct driver_attribute *);
+void driver_remove_file(struct device_driver *, const struct driver_attribute *);
+
+
+文档
+~~~~
+
+sysfs 目录结构以及其中包含的属性定义了一个内核与用户空间之间的 ABI。
+对于任何 ABI,其自身的稳定和适当的文档是非常重要的。所有新的 sysfs
+属性必须在 Documentation/ABI 中有文档。详见 Documentation/ABI/README。
diff --git a/Documentation/zh_CN/gpio.txt b/Documentation/zh_CN/gpio.txt
new file mode 100644
index 0000000..4fa7b4e
--- /dev/null
+++ b/Documentation/zh_CN/gpio.txt
@@ -0,0 +1,658 @@
+Chinese translated version of Documentation/gpio.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Grant Likely <grant.likely@secretlab.ca>
+		Linus Walleij <linus.walleij@linaro.org>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/gpio.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+英文版维护者: Grant Likely <grant.likely@secretlab.ca>
+		Linus Walleij <linus.walleij@linaro.org>
+中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+
+
+以下为正文
+---------------------------------------------------------------------
+GPIO 接口
+
+本文档提供了一个在Linux下访问GPIO的公约概述。
+
+这些函数以 gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的
+__gpio_* 前缀。
+
+
+什么是GPIO?
+==========
+"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可
+由多种芯片提供,且对于从事嵌入式和定制硬件的 Linux 开发者来说是
+比较熟悉。每个GPIO 都代表一个连接到特定引脚或球栅阵列(BGA)封装中
+“球珠”的一个位。电路板原理图显示了 GPIO 与外部硬件的连接关系。
+驱动可以编写成通用代码,以使板级启动代码可传递引脚配置数据给驱动。
+
+片上系统 (SOC) 处理器对 GPIO 有很大的依赖。在某些情况下,每个
+非专用引脚都可配置为 GPIO,且大多数芯片都最少有一些 GPIO。
+可编程逻辑器件(类似 FPGA) 可以方便地提供 GPIO。像电源管理和
+音频编解码器这样的多功能芯片经常留有一些这样的引脚来帮助那些引脚
+匮乏的 SOC。同时还有通过 I2C 或 SPI 串行总线连接的“GPIO扩展器”
+芯片。大多数 PC 的南桥有一些拥有 GPIO 能力的引脚 (只有BIOS
+固件才知道如何使用他们)。
+
+GPIO 的实际功能因系统而异。通常用法有:
+
+  - 输出值可写 (高电平=1,低电平=0)。一些芯片也有如何驱动这些值的选项,
+    例如只允许输出一个值、支持“线与”及其他取值类似的模式(值得注意的是
+    “开漏”信号)
+
+  - 输入值可读(1、0)。一些芯片支持引脚在配置为“输出”时回读,这对于类似
+    “线与”的情况(以支持双向信号)是非常有用的。GPIO 控制器可能有输入
+    去毛刺/消抖逻辑,这有时需要软件控制。
+
+  - 输入通常可作为 IRQ 信号,一般是沿触发,但有时是电平触发。这样的 IRQ
+    可能配置为系统唤醒事件,以将系统从低功耗状态下唤醒。
+
+  - 通常一个 GPIO 根据不同产品电路板的需求,可以配置为输入或输出,也有仅
+    支持单向的。
+
+  - 大部分 GPIO 可以在持有自旋锁时访问,但是通常由串行总线扩展的 GPIO
+    不允许持有自旋锁。但某些系统也支持这种类型。
+
+对于给定的电路板,每个 GPIO 都用于某个特定的目的,如监控 MMC/SD 卡的
+插入/移除、检测卡的写保护状态、驱动 LED、配置收发器、模拟串行总线、
+复位硬件看门狗、感知开关状态等等。
+
+
+GPIO 公约
+=========
+注意,这个叫做“公约”,因为这不是强制性的,不遵循这个公约是无伤大雅的,
+因为此时可移植性并不重要。GPIO 常用于板级特定的电路逻辑,甚至可能
+随着电路板的版本而改变,且不可能在不同走线的电路板上使用。仅有在少数
+功能上才具有可移植性,其他功能是平台特定。这也是由于“胶合”的逻辑造成的。
+
+此外,这不需要任何的执行框架,只是一个接口。某个平台可能通过一个简单地
+访问芯片寄存器的内联函数来实现它,其他平台可能通过委托一系列不同的GPIO
+控制器的抽象函数来实现它。(有一些可选的代码能支持这种策略的实现,本文档
+后面会介绍,但作为 GPIO 接口的客户端驱动程序必须与它的实现无关。)
+
+也就是说,如果在他们的平台上支持这个公约,驱动应尽可能的使用它。平台
+必须在 Kconfig 中声明对 GENERIC_GPIO的支持 (布尔型 true),并提供
+一个 <asm/gpio.h> 文件。那些调用标准 GPIO 函数的驱动应该在 Kconfig
+入口中声明依赖GENERIC_GPIO。当驱动包含文件:
+
+	#include <linux/gpio.h>
+
+则 GPIO 函数是可用,无论是“真实代码”还是经优化过的语句。如果你遵守
+这个公约,当你的代码完成后,对其他的开发者来说会更容易看懂和维护。
+
+注意,这些操作包含所用平台的 I/O 屏障代码,驱动无须显式地调用他们。
+
+
+标识 GPIO
+---------
+GPIO 是通过无符号整型来标识的,范围是 0 到 MAX_INT。保留“负”数
+用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层
+硬件的代码会忽略这些整数。
+
+平台会定义这些整数的用法,且通常使用 #define 来定义 GPIO,这样
+板级特定的启动代码可以直接关联相应的原理图。相对来说,驱动应该仅使用
+启动代码传递过来的 GPIO 编号,使用 platform_data 保存板级特定
+引脚配置数据 (同时还有其他须要的板级特定数据),避免可能出现的问题。
+
+例如一个平台使用编号 32-159 来标识 GPIO,而在另一个平台使用编号0-63
+标识一组 GPIO 控制器,64-79标识另一类 GPIO 控制器,且在一个含有
+FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中,也可以
+使用编号2000-2063来标识一个 I2C 接口的 GPIO 扩展器中的 GPIO。
+
+如果你要初始化一个带有无效 GPIO 编号的结构体,可以使用一些负编码
+(如"-EINVAL"),那将使其永远不会是有效。来测试这样一个结构体中的编号
+是否关联一个 GPIO,你可使用以下断言:
+
+	int gpio_is_valid(int number);
+
+如果编号不存在,则请求和释放 GPIO 的函数将拒绝执行相关操作(见下文)。
+其他编号也可能被拒绝,比如一个编号可能存在,但暂时在给定的电路上不可用。
+
+一个平台是否支持多个 GPIO 控制器为平台特定的实现问题,就像是否可以
+在 GPIO 编号空间中有“空洞”和是否可以在运行时添加新的控制器一样。
+这些问题会影响其他事情,包括相邻的 GPIO 编号是否存在等。
+
+使用 GPIO
+---------
+对于一个 GPIO,系统应该做的第一件事情就是通过 gpio_request()
+函数分配它,见下文。
+
+接下来是设置I/O方向,这通常是在板级启动代码中为所使用的 GPIO 设置
+platform_device 时完成。
+
+	/* 设置为输入或输出, 返回 0 或负的错误代码 */
+	int gpio_direction_input(unsigned gpio);
+	int gpio_direction_output(unsigned gpio, int value);
+
+返回值为零代表成功,否则返回一个负的错误代码。这个返回值需要检查,因为
+get/set(获取/设置)函数调用没法返回错误,且有可能是配置错误。通常,
+你应该在进程上下文中调用这些函数。然而,对于自旋锁安全的 GPIO,在板子
+启动的早期、进程启动前使用他们也是可以的。
+
+对于作为输出的 GPIO,为其提供初始输出值,对于避免在系统启动期间出现
+信号毛刺是很有帮助的。
+
+为了与传统的 GPIO 接口兼容, 在设置一个 GPIO 方向时,如果它还未被申请,
+则隐含了申请那个 GPIO 的操作(见下文)。这种兼容性正在从可选的 gpiolib
+框架中移除。
+
+如果这个 GPIO 编码不存在,或者特定的 GPIO 不能用于那种模式,则方向
+设置可能失败。依赖启动固件来正确地设置方向通常是一个坏主意,因为它可能
+除了启动Linux,并没有做更多的验证工作。(同理, 板子的启动代码可能需要
+将这个复用的引脚设置为 GPIO,并正确地配置上拉/下拉电阻。)
+
+
+访问自旋锁安全的 GPIO
+-------------------
+大多数 GPIO 控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以
+安全地在硬(非线程)中断例程和类似的上下文中完成。
+
+对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(见下文),使用
+以下的函数访问:
+
+	/* GPIO 输入:返回零或非零 */
+	int gpio_get_value(unsigned gpio);
+
+	/* GPIO 输出 */
+	void gpio_set_value(unsigned gpio, int value);
+
+GPIO值是布尔值,零表示低电平,非零表示高电平。当读取一个输出引脚的值时,
+返回值应该是引脚上的值。这个值不总是和输出值相符,因为存在开漏输出信号和
+输出延迟问题。
+
+以上的 get/set 函数无错误返回值,因为之前 gpio_direction_*()应已检查过
+其是否为“无效GPIO”。此外,还需要注意的是并不是所有平台都可以从输出引脚
+中读取数据,对于不能读取的引脚应总返回零。另外,对那些在原子上下文中无法
+安全访问的 GPIO (译者注:因为访问可能导致休眠)使用这些函数是不合适的
+(见下文)。
+
+在 GPIO 编号(还有输出、值)为常数的情况下,鼓励通过平台特定的实现来优化
+这两个函数来访问 GPIO 值。这种情况(读写一个硬件寄存器)下只需要几条指令
+是很正常的,且无须自旋锁。这种优化函数比起那些在子程序上花费许多指令的
+函数可以使得模拟接口(译者注:例如 GPIO 模拟 I2C、1-wire 或 SPI)的
+应用(在空间和时间上都)更具效率。
+
+
+访问可能休眠的 GPIO
+-----------------
+某些 GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消息访问。读或写这些
+GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要
+休眠,这不能在 IRQ 例程(中断上下文)中执行。
+
+支持此类 GPIO 的平台通过以下函数返回非零值来区分出这种 GPIO。(此函数需要
+一个之前通过 gpio_request 分配到的有效 GPIO 编号):
+
+	int gpio_cansleep(unsigned gpio);
+
+为了访问这种 GPIO,内核定义了一套不同的函数:
+
+	/* GPIO 输入:返回零或非零 ,可能会休眠 */
+	int gpio_get_value_cansleep(unsigned gpio);
+
+	/* GPIO 输出,可能会休眠 */
+	void gpio_set_value_cansleep(unsigned gpio, int value);
+
+
+访问这样的 GPIO 需要一个允许休眠的上下文,例如线程 IRQ 处理例程,并用以上的
+访问函数替换那些没有 cansleep()后缀的自旋锁安全访问函数。
+
+除了这些访问函数可能休眠,且它们操作的 GPIO 不能在硬件 IRQ 处理例程中访问的
+事实,这些处理例程实际上和自旋锁安全的函数是一样的。
+
+** 除此之外 ** 调用设置和配置此类 GPIO 的函数也必须在允许休眠的上下文中,
+因为它们可能也需要访问 GPIO 控制器芯片: (这些设置函数通常在板级启动代码或者
+驱动探测/断开代码中,所以这是一个容易满足的约束条件。)
+
+	gpio_direction_input()
+	gpio_direction_output()
+	gpio_request()
+
+## 	gpio_request_one()
+##	gpio_request_array()
+## 	gpio_free_array()
+
+	gpio_free()
+	gpio_set_debounce()
+
+
+
+声明和释放 GPIO
+----------------------------
+为了有助于捕获系统配置错误,定义了两个函数。
+
+	/* 申请 GPIO, 返回 0 或负的错误代码.
+	 * 非空标签可能有助于诊断.
+	 */
+	int gpio_request(unsigned gpio, const char *label);
+
+	/* 释放之前声明的 GPIO */
+	void gpio_free(unsigned gpio);
+
+将无效的 GPIO 编码传递给 gpio_request()会导致失败,申请一个已使用这个
+函数声明过的 GPIO 也会失败。gpio_request()的返回值必须检查。你应该在
+进程上下文中调用这些函数。然而,对于自旋锁安全的 GPIO,在板子启动的早期、
+进入进程之前是可以申请的。
+
+这个函数完成两个基本的目标。一是标识那些实际上已作为 GPIO 使用的信号线,
+这样便于更好地诊断;系统可能需要服务几百个可用的 GPIO,但是对于任何一个
+给定的电路板通常只有一些被使用。另一个目的是捕获冲突,查明错误:如两个或
+更多驱动错误地认为他们已经独占了某个信号线,或是错误地认为移除一个管理着
+某个已激活信号的驱动是安全的。也就是说,申请 GPIO 的作用类似一种锁机制。
+
+某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和
+简单地关闭未使用时钟)。
+
+对于 GPIO 使用 pinctrl 子系统已知的引脚,子系统应该被告知其使用情况;
+一个 gpiolib 驱动的 .request()操作应调用 pinctrl_request_gpio(),
+而 gpiolib 驱动的 .free()操作应调用 pinctrl_free_gpio()。pinctrl
+子系统允许 pinctrl_request_gpio()在某个引脚或引脚组以复用形式“属于”
+一个设备时都成功返回。
+
+任何须将 GPIO 信号导向适当引脚的引脚复用硬件的编程应该发生在 GPIO
+驱动的 .direction_input()或 .direction_output()函数中,以及
+任何输出 GPIO 值的设置之后。这样可使从引脚特殊功能到 GPIO 的转换
+不会在引脚产生毛刺波形。有时当用一个 GPIO 实现其信号驱动一个非 GPIO
+硬件模块的解决方案时,就需要这种机制。
+
+某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的
+其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用
+gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映射表,
+使得 GPIO 的用户无须关注这些细节。
+
+还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。
+
+
+注意:申请一个 GPIO 并没有以任何方式配置它,只不过标识那个 GPIO 处于使用
+状态。必须有另外的代码来处理引脚配置(如控制 GPIO 使用的引脚、上拉/下拉)。
+考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数:
+
+	/* 申请一个 GPIO 信号, 同时通过特定的'flags'初始化配置,
+	 * 其他和 gpio_request()的参数和返回值相同
+	 *
+	 */
+	int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
+
+	/* 在单个函数中申请多个 GPIO
+	 */
+	int gpio_request_array(struct gpio *array, size_t num);
+
+	/* 在单个函数中释放多个 GPIO
+	 */
+	void gpio_free_array(struct gpio *array, size_t num);
+
+这里 'flags' 当前定义可指定以下属性:
+
+	* GPIOF_DIR_IN		- 配置方向为输入
+	* GPIOF_DIR_OUT		- 配置方向为输出
+
+	* GPIOF_INIT_LOW	- 在作为输出时,初始值为低电平
+	* GPIOF_INIT_HIGH	- 在作为输出时,初始值为高电平
+	* GPIOF_OPEN_DRAIN	- gpio引脚为开漏信号
+	* GPIOF_OPEN_SOURCE	- gpio引脚为源极开路信号
+
+	* GPIOF_EXPORT_DIR_FIXED	- 将 gpio 导出到 sysfs,并保持方向
+	* GPIOF_EXPORT_DIR_CHANGEABLE	- 同样是导出, 但允许改变方向
+
+因为 GPIOF_INIT_* 仅有在配置为输出的时候才存在,所以有效的组合为:
+
+	* GPIOF_IN		- 配置为输入
+	* GPIOF_OUT_INIT_LOW	- 配置为输出,并初始化为低电平
+	* GPIOF_OUT_INIT_HIGH	- 配置为输出,并初始化为高电平
+
+当设置 flag 为 GPIOF_OPEN_DRAIN 时,则假设引脚是开漏信号。这样的引脚
+将不会在输出模式下置1。这样的引脚需要连接上拉电阻。通过使能这个标志,gpio库
+将会在被要求输出模式下置1时将引脚变为输入状态来使引脚置高。引脚在输出模式下
+通过置0使其输出低电平。
+
+当设置 flag 为 GPIOF_OPEN_SOURCE 时,则假设引脚为源极开路信号。这样的引脚
+将不会在输出模式下置0。这样的引脚需要连接下拉电阻。通过使能这个标志,gpio库
+将会在被要求输出模式下置0时将引脚变为输入状态来使引脚置低。引脚在输出模式下
+通过置1使其输出高电平。
+
+将来这些标志可能扩展到支持更多的属性。
+
+更进一步,为了更简单地声明/释放多个 GPIO,'struct gpio'被引进来封装所有
+这三个领域:
+
+	struct gpio {
+		unsigned	gpio;
+		unsigned long	flags;
+		const char	*label;
+	};
+
+一个典型的用例:
+
+	static struct gpio leds_gpios[] = {
+		{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默认开启 */
+		{ 33, GPIOF_OUT_INIT_LOW,  "Green LED" }, /* 默认关闭 */
+		{ 34, GPIOF_OUT_INIT_LOW,  "Red LED"   }, /* 默认关闭 */
+		{ 35, GPIOF_OUT_INIT_LOW,  "Blue LED"  }, /* 默认关闭 */
+		{ ... },
+	};
+
+	err = gpio_request_one(31, GPIOF_IN, "Reset Button");
+	if (err)
+		...
+
+	err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+	if (err)
+		...
+
+	gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+
+
+GPIO 映射到 IRQ
+--------------------
+GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上不同的命名空间
+(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射:
+
+	/* 映射 GPIO 编号到 IRQ 编号 */
+	int gpio_to_irq(unsigned gpio);
+
+	/* 映射 IRQ 编号到 GPIO 编号 (尽量避免使用) */
+	int irq_to_gpio(unsigned irq);
+
+它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。
+(例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的:使用一个
+未通过 gpio_direction_input()配置为输入的 GPIO 编号,或者使用一个
+并非来源于gpio_to_irq()的 IRQ 编号。
+
+这两个映射函数可能会在信号编号的加减计算过程上花些时间。它们不可休眠。
+
+gpio_to_irq()返回的非错误值可以传递给 request_irq()或者 free_irq()。
+它们通常通过板级特定的初始化代码存放到平台设备的 IRQ 资源中。注意:IRQ
+触发选项是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力
+也是如此。
+
+irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所使用,
+比如在 IRQ 是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以
+你应该尽量避免使用它。
+
+
+模拟开漏信号
+----------------------------
+有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平
+结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语
+适用于 CMOS 管;而 TTL 用“集电极开路”。)一个上拉电阻使信号为高电平。这
+有时被称为“线与”。实际上,从负逻辑(低电平为真)的角度来看,这是一个“线或”。
+
+一个开漏信号的常见例子是共享的低电平使能 IRQ 信号线。此外,有时双向数据总线
+信号也使用漏极开路信号。
+
+某些 GPIO 控制器直接支持开漏输出,还有许多不支持。当你需要开漏信号,但
+硬件又不直接支持的时候,一个常用的方法是用任何即可作输入也可作输出的 GPIO
+引脚来模拟:
+
+ LOW:	gpio_direction_output(gpio, 0) ... 这代码驱动信号并覆盖
+	上拉配置。
+
+ HIGH:	gpio_direction_input(gpio) ... 这代码关闭输出,所以上拉电阻
+	(或其他的一些器件)控制了信号。
+
+如果你将信号线“驱动”为高电平,但是 gpio_get_value(gpio)报告了一个
+低电平(在适当的上升时间后),你就可以知道是其他的一些组件将共享信号线拉低了。
+这不一定是错误的。一个常见的例子就是 I2C 时钟的延长:一个需要较慢时钟的
+从设备延迟 SCK 的上升沿,而 I2C 主设备相应地调整其信号传输速率。
+
+
+这些公约忽略了什么?
+================
+这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且
+没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚
+可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将
+几个引脚中的任何一个作为给定的 GPIO。(是的,这些例子都来自于当前运行
+Linux 的系统。)
+
+在某些系统中,与引脚复用相关的是配置和使能集成的上、下拉模式。并不是所有
+平台都支持这种模式,或者不会以相同的方式来支持这种模式;且任何给定的电路板
+可能使用外置的上拉(或下拉)电阻,这时芯片上的就不应该使用。(当一个电路需要
+5kOhm 的拉动电阻,芯片上的 100 kOhm 电阻就不能做到。)同样的,驱动能力
+(2 mA vs 20 mA)和电压(1.8V vs 3.3V)是平台特定问题,就像模型一样在
+可配置引脚和 GPIO 之间(没)有一一对应的关系。
+
+还有其他一些系统特定的机制没有在这里指出,例如上述的输入去毛刺和线与输出
+选项。硬件可能支持批量读或写 GPIO,但是那一般是配置相关的:对于处于同一
+块区(bank)的GPIO。(GPIO 通常以 16 或 32 个组成一个区块,一个给定的
+片上系统一般有几个这样的区块。)某些系统可以通过输出 GPIO 触发 IRQ,
+或者从并非以 GPIO 管理的引脚取值。这些机制的相关代码没有必要具有可移植性。
+
+当前,动态定义 GPIO 并不是标准的,例如作为配置一个带有某些 GPIO 扩展器的
+附加电路板的副作用。
+
+GPIO 实现者的框架 (可选)
+=====================
+前面提到了,有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持
+不同种类的 GPIO 控制器。这个框架称为"gpiolib"。
+
+作为一个辅助调试功能,如果 debugfs 可用,就会有一个 /sys/kernel/debug/gpio
+文件。通过这个框架,它可以列出所有注册的控制器,以及当前正在使用中的 GPIO
+的状态。
+
+
+控制器驱动: gpio_chip
+-------------------
+在框架中每个 GPIO 控制器都包装为一个 "struct gpio_chip",他包含了
+该类型的每个控制器的常用信息:
+
+ - 设置 GPIO 方向的方法
+ - 用于访问 GPIO 值的方法
+ - 告知调用其方法是否可能休眠的标志
+ - 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态)
+ - 诊断标签
+
+也包含了来自 device.platform_data 的每个实例的数据:它第一个 GPIO 的
+编号和它可用的 GPIO 的数量。
+
+实现 gpio_chip 的代码应支持多控制器实例,这可能使用驱动模型。那些代码要
+配置每个 gpio_chip,并发起gpiochip_add()。卸载一个 GPIO 控制器很少见,
+但在必要的时候可以使用 gpiochip_remove()。
+
+大部分 gpio_chip 是一个实例特定结构体的一部分,而并不将 GPIO 接口单独
+暴露出来,比如编址、电源管理等。类似编解码器这样的芯片会有复杂的非 GPIO
+状态。
+
+任何一个 debugfs 信息导出方法通常应该忽略还未申请作为 GPIO 的信号线。
+他们可以使用 gpiochip_is_requested()测试,当这个 GPIO 已经申请过了
+就返回相关的标签,否则返回 NULL。
+
+
+平台支持
+-------
+为了支持这个框架,一个平台的 Kconfig 文件将会 "select"(选择)
+ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的
+<asm/gpio.h> 包含 <asm-generic/gpio.h>,同时定义三个方法:
+gpio_get_value()、gpio_set_value()和 gpio_cansleep()。
+
+它也应提供一个 ARCH_NR_GPIOS 的定义值,这样可以更好地反映该平台 GPIO
+的实际数量,节省静态表的空间。(这个定义值应该包含片上系统内建 GPIO 和
+GPIO 扩展器中的数据。)
+
+ARCH_REQUIRE_GPIOLIB 意味着 gpiolib 核心在这个构架中将总是编译进内核。
+
+ARCH_WANT_OPTIONAL_GPIOLIB 意味着 gpiolib 核心默认关闭,且用户可以
+使能它,并将其编译进内核(可选)。
+
+如果这些选项都没被选择,该平台就不通过 GPIO-lib 支持 GPIO,且代码不可以
+被用户使能。
+
+以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度:
+
+  #define gpio_get_value	__gpio_get_value
+  #define gpio_set_value	__gpio_set_value
+  #define gpio_cansleep		__gpio_cansleep
+
+这些定义可以用更理想的实现方法替代,那就是使用经过逻辑优化的内联函数来访问
+基于特定片上系统的 GPIO。例如,若引用的 GPIO (寄存器位偏移)是常量“12”,
+读取或设置它可能只需少则两或三个指令,且不会休眠。当这样的优化无法实现时,
+那些函数必须使用框架提供的代码,那就至少要几十条指令才可以实现。对于用 GPIO
+模拟的 I/O 接口, 如此精简指令是很有意义的。
+
+对于片上系统,平台特定代码为片上 GPIO 每个区(bank)定义并注册 gpio_chip
+实例。那些 GPIO 应该根据芯片厂商的文档进行编码/标签,并直接和电路板原理图
+对应。他们应该开始于零并终止于平台特定的限制。这些 GPIO(代码)通常从
+arch_initcall()或者更早的地方集成进平台初始化代码,使这些 GPIO 总是可用,
+且他们通常可以作为 IRQ 使用。
+
+板级支持
+-------
+对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器、专用芯片、多功能器件、FPGA
+或 CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道
+gpiochip_add()所使用的 GPIO 编号。他们的起始编号通常跟在平台特定的 GPIO
+编号之后。
+
+例如板级启动代码应该创建结构体指明芯片公开的 GPIO 范围,并使用 platform_data
+将其传递给每个 GPIO 扩展器芯片。然后芯片驱动中的 probe()例程可以将这个
+数据传递给 gpiochip_add()。
+
+初始化顺序很重要。例如,如果一个设备依赖基于 I2C 的(扩展)GPIO,那么它的
+probe()例程就应该在那个 GPIO 有效以后才可以被调用。这意味着设备应该在
+GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是让这种 gpio_chip
+控制器向板级特定代码提供 setup()和 teardown()回调函数。一旦所有必须的
+资源可用之后,这些板级特定的回调函数将会注册设备,并可以在这些 GPIO 控制器
+设备变成无效时移除它们。
+
+
+用户空间的 Sysfs 接口(可选)
+========================
+使用“gpiolib”实现框架的平台可以选择配置一个 GPIO 的 sysfs 用户接口。
+这不同于 debugfs 接口,因为它提供的是对 GPIO方向和值的控制,而不只显示
+一个GPIO 的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。
+
+例如,通过适当的系统硬件文档,用户空间可以知道 GIOP #23 控制 Flash
+存储器的写保护(用于保护其中 Bootloader 分区)。产品的系统升级可能需要
+临时解除这个保护:首先导入一个 GPIO,改变其输出状态,然后在重新使能写保护
+前升级代码。通常情况下,GPIO #23 是不会被触及的,并且内核也不需要知道他。
+
+根据适当的硬件文档,某些系统的用户空间 GPIO 可以用于确定系统配置数据,
+这些数据是标准内核不知道的。在某些任务中,简单的用户空间 GPIO 驱动可能是
+系统真正需要的。
+
+注意:标准内核驱动中已经存在通用的“LED 和按键”GPIO 任务,分别是:
+"leds-gpio" 和 "gpio_keys"。请使用这些来替代直接访问 GPIO,因为集成在
+内核框架中的这类驱动比你在用户空间的代码更好。
+
+
+Sysfs 中的路径
+--------------
+在/sys/class/gpio 中有 3 类入口:
+
+   -	用于在用户空间控制 GPIO 的控制接口;
+
+   -	GPIOs 本身;以及
+
+   -	GPIO 控制器 ("gpio_chip" 实例)。
+
+除了这些标准的文件,还包含“device”符号链接。
+
+控制接口是只写的:
+
+    /sys/class/gpio/
+
+    	"export" ... 用户空间可以通过写其编号到这个文件,要求内核导出
+		一个 GPIO 的控制到用户空间。
+
+		例如: 如果内核代码没有申请 GPIO #19,"echo 19 > export"
+		将会为 GPIO #19 创建一个 "gpio19" 节点。
+
+    	"unexport" ... 导出到用户空间的逆操作。
+
+		例如: "echo 19 > unexport" 将会移除使用"export"文件导出的
+		"gpio19" 节点。
+
+GPIO 信号的路径类似 /sys/class/gpio/gpio42/ (对于 GPIO #42 来说),
+并有如下的读/写属性:
+
+    /sys/class/gpio/gpioN/
+
+	"direction" ... 读取得到 "in" 或 "out"。这个值通常运行写入。
+		写入"out" 时,其引脚的默认输出为低电平。为了确保无故障运行,
+		"low" 或 "high" 的电平值应该写入 GPIO 的配置,作为初始输出值。
+
+		注意:如果内核不支持改变 GPIO 的方向,或者在导出时内核代码没有
+		明确允许用户空间可以重新配置 GPIO 方向,那么这个属性将不存在。
+
+	"value" ... 读取得到 0 (低电平) 或 1 (高电平)。如果 GPIO 配置为
+		输出,这个值允许写操作。任何非零值都以高电平看待。
+
+		如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式
+		(见"edge"的描述),你可以对这个文件使用轮询操作(poll(2)),
+		且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)),
+		请在 events 中设置 POLLPRI 和 POLLERR。如果你使用轮询操作
+		(select(2)),请在 exceptfds 设置你期望的文件描述符。在
+		轮询操作(poll(2))返回之后,既可以通过 lseek(2)操作读取
+		sysfs 文件的开始部分,也可以关闭这个文件并重新打开它来读取数据。
+
+	"edge" ... 读取得到“none”、“rising”、“falling”或者“both”。
+		将这些字符串写入这个文件可以选择沿触发模式,会使得轮询操作
+		(select(2))在"value"文件中返回。
+
+		这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存在。
+
+	"active_low" ... 读取得到 0 (假) 或 1 (真)。写入任何非零值可以
+		翻转这个属性的(读写)值。已存在或之后通过"edge"属性设置了"rising"
+		和 "falling" 沿触发模式的轮询操作(poll(2))将会遵循这个设置。
+
+GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
+开始实现控制的控制器),并有着以下只读属性:
+
+    /sys/class/gpio/gpiochipN/
+
+    	"base" ... 与以上的 N 相同,代表此芯片管理的第一个 GPIO 的编号
+
+    	"label" ... 用于诊断 (并不总是只有唯一值)
+
+    	"ngpio" ... 此控制器所管理的 GPIO 数量(而 GPIO 编号从 N 到
+    		N + ngpio - 1)
+
+大多数情况下,电路板的文档应当标明每个 GPIO 的使用目的。但是那些编号并不总是
+固定的,例如在扩展卡上的 GPIO会根据所使用的主板或所在堆叠架构中其他的板子而
+有所不同。在这种情况下,你可能需要使用 gpiochip 节点(尽可能地结合电路图)来
+确定给定信号所用的 GPIO 编号。
+
+
+从内核代码中导出
+-------------
+内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出:
+
+	/* 导出 GPIO 到用户空间 */
+	int gpio_export(unsigned gpio, bool direction_may_change);
+
+	/* gpio_export()的逆操作 */
+	void gpio_unexport();
+
+	/* 创建一个 sysfs 连接到已导出的 GPIO 节点 */
+	int gpio_export_link(struct device *dev, const char *name,
+		unsigned gpio)
+
+	/* 改变 sysfs 中的一个 GPIO 节点的极性 */
+	int gpio_sysfs_set_active_low(unsigned gpio, int value);
+
+在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
+接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
+破坏重要的系统状态。
+
+这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口,
+与文档配合作为板级支持包的一部分。
+
+在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
+创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
+名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
+
+驱动可以使用 gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间
+GPIO 线的极性差异。这个仅对 sysfs 接口起作用。极性的改变可以在 gpio_export()
+前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循
+这个设置。
diff --git a/Documentation/zh_CN/video4linux/omap3isp.txt b/Documentation/zh_CN/video4linux/omap3isp.txt
new file mode 100644
index 0000000..67ffbf3
--- /dev/null
+++ b/Documentation/zh_CN/video4linux/omap3isp.txt
@@ -0,0 +1,277 @@
+Chinese translated version of Documentation/video4linux/omap3isp.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+	  Sakari Ailus <sakari.ailus@iki.fi>
+	  David Cohen <dacohen@gmail.com>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/video4linux/omap3isp.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+英文版维护者: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+	  Sakari Ailus <sakari.ailus@iki.fi>
+	  David Cohen <dacohen@gmail.com>
+中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+
+
+以下为正文
+---------------------------------------------------------------------
+OMAP 3 图像信号处理器 (ISP) 驱动
+
+Copyright (C) 2010 Nokia Corporation
+Copyright (C) 2009 Texas Instruments, Inc.
+
+联系人: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+	  Sakari Ailus <sakari.ailus@iki.fi>
+	  David Cohen <dacohen@gmail.com>
+
+
+介绍
+===
+
+本文档介绍了由 drivers/media/video/omap3isp 加载的德州仪器
+(TI)OMAP 3 图像信号处理器 (ISP) 驱动。原始驱动由德州仪器(TI)
+编写,但此后由诺基亚重写了两次。
+
+驱动已在以下 OMAP 3 系列的芯片中成功使用:
+
+	3430
+	3530
+	3630
+
+驱动实现了 V4L2、媒体控制器和 v4l2_subdev 接口。支持内核中使用
+v4l2_subdev 接口的传感器、镜头和闪光灯驱动。
+
+
+拆分为子设备
+==========
+
+OMAP 3 ISP 被拆分为 V4L2 子设备,ISP中的每个模块都由一个子设备
+来表示。每个子设备向用户空间提供一个 V4L2 子设备接口。
+
+	OMAP3 ISP CCP2
+	OMAP3 ISP CSI2a
+	OMAP3 ISP CCDC
+	OMAP3 ISP preview
+	OMAP3 ISP resizer
+	OMAP3 ISP AEWB
+	OMAP3 ISP AF
+	OMAP3 ISP histogram
+
+ISP 中每个可能的连接都通过一个链接嵌入到媒体控制器接口中。详见例程 [2]。
+
+
+控制 OMAP 3 ISP
+==============
+
+通常,对 OMAP 3 ISP 的配置会在下一帧起始时生效。在传感器垂直消隐期间,
+模块变为空闲时完成配置。在内存到内存的操作中,视频管道一次处理一帧。
+应用配置应在帧间完成。
+
+ISP 中的所有模块,除 CSI-2 和 (可能存在的)CCP2 接收器外,都必须
+接收完整的帧数据。因此,传感器必须保证从不发送部分帧数据给ISP。
+
+Autoidle(自动空闲)功能至少在 3430 的 ISP 模块中确实存在一些问题。
+当 omap3isp 模块参数 autoidle 非零时,autoidle(自动空闲)功能
+仅在 3630 中启用了。
+
+
+事件机制
+======
+
+OMAP 3 ISP 驱动在 CCDC 和统计(AEWB、AF 和 直方图)子设备中支持
+V4L2 事件机制接口。
+
+CCDC 子设备通过 HS_VS 中断,处理 V4L2_EVENT_FRAME_SYNC 类型
+事件,用于告知帧起始。早期版本的驱动则使用 V4L2_EVENT_OMAP3ISP_HS_VS。
+当在 CCDC 模块中接收到起始帧的第一行时,会准确地触发事件。这个事件
+可以在 CCDC 子设备中“订阅”。
+
+(当使用并行接口时,必须注意正确地配置 VS 信号极性。而当使用串行接收时
+这个会自动校正。)
+
+每个统计子设备都可以产生事件。每当一个统计缓冲区可由用户空间应用程序
+通过 VIDIOC_OMAP3ISP_STAT_REQ IOCTL 操作获取时,就会产生一个
+事件。当前存在以下事件:
+
+	V4L2_EVENT_OMAP3ISP_AEWB
+	V4L2_EVENT_OMAP3ISP_AF
+	V4L2_EVENT_OMAP3ISP_HIST
+
+这些 ioctl 的事件数据类型为 struct omap3isp_stat_event_status
+结构体。如果出现计算错误的统计,也同样会产生一个事件,但没有相关的统计
+数据缓冲区。这种情况下 omap3isp_stat_event_status.buf_err 会被
+设置为非零值。
+
+
+私有 IOCTL
+==========
+
+OMAP 3 ISP 驱动支持标准的 V4L2 IOCTL 以及可能存在且实用的控制。但
+ISP 提供的许多功能都不在标准 IOCTL 之列,例如 gamma(伽马)表和统计
+数据采集配置等。
+
+通常,会有一个私有 ioctl 用于配置每个包含硬件依赖功能的模块。
+
+支持以下私有 IOCTL:
+
+	VIDIOC_OMAP3ISP_CCDC_CFG
+	VIDIOC_OMAP3ISP_PRV_CFG
+	VIDIOC_OMAP3ISP_AEWB_CFG
+	VIDIOC_OMAP3ISP_HIST_CFG
+	VIDIOC_OMAP3ISP_AF_CFG
+	VIDIOC_OMAP3ISP_STAT_REQ
+	VIDIOC_OMAP3ISP_STAT_EN
+
+在 include/linux/omap3isp.h 中描述了这些 ioctl 使用的参数结构体。
+与特定 ISP 模块相关的 ISP 自身的详细功能在技术参考手册 (TRMs)中有
+描述,详见文档结尾。
+
+虽然在不使用任何私有 IOCTL 的情况下使用 ISP 驱动是可能的,但这样无法
+获得最佳的图像质量。AEWB、AF 和 直方图(译者注:一般用于自动曝光和增益
+控制,以及图像均衡等)模块无法在未使用适当的私有 IOCTL 配置的情况下使用。
+
+
+CCDC 和 preview(预览)模块 IOCTL
+===============================
+
+VIDIOC_OMAP3ISP_CCDC_CFG 和 VIDIOC_OMAP3ISP_PRV_CFG IOCTL
+被分别用于配置、启用和禁用 CCDC 和 preview(预览)模块的功能。在它们
+所控制的模块中,两个 IOCTL 控制多种功能。VIDIOC_OMAP3ISP_CCDC_CFG IOCTL
+接受一个指向 omap3isp_ccdc_update_config 结构体的指针作为它的参数。
+同样的,VIDIOC_OMAP3ISP_PRV_CFG 接受一个指向 omap3isp_prev_update_config
+结构体的指针。以上两个结构体定义位于 [1]。
+
+这些结构体中的 update 域标识是否针对指定的功能更新配置,而 flag 域
+则标识是启用还是禁用此功能。
+
+update 和 flag 位接受以下掩码值。CCDC 和 preview(预览)模块的
+每个单独功能都与一个 flag 关联(禁用或启用;在结构体中 flag 域的
+一部分)和一个指向功能配置数据的指针。
+
+对于 VIDIOC_OMAP3ISP_CCDC_CFG,下面列出了 update 和 flag 域
+中的有效值。 这些值可能会在同一个 IOCTL 调用中配置多个功能。
+
+        OMAP3ISP_CCDC_ALAW
+        OMAP3ISP_CCDC_LPF
+        OMAP3ISP_CCDC_BLCLAMP
+        OMAP3ISP_CCDC_BCOMP
+        OMAP3ISP_CCDC_FPC
+        OMAP3ISP_CCDC_CULL
+        OMAP3ISP_CCDC_CONFIG_LSC
+        OMAP3ISP_CCDC_TBL_LSC
+
+针对 VIDIOC_OMAP3ISP_PRV_CFG 的相应值如下:
+
+        OMAP3ISP_PREV_LUMAENH
+        OMAP3ISP_PREV_INVALAW
+        OMAP3ISP_PREV_HRZ_MED
+        OMAP3ISP_PREV_CFA
+        OMAP3ISP_PREV_CHROMA_SUPP
+        OMAP3ISP_PREV_WB
+        OMAP3ISP_PREV_BLKADJ
+        OMAP3ISP_PREV_RGB2RGB
+        OMAP3ISP_PREV_COLOR_CONV
+        OMAP3ISP_PREV_YC_LIMIT
+        OMAP3ISP_PREV_DEFECT_COR
+        OMAP3ISP_PREV_GAMMABYPASS
+        OMAP3ISP_PREV_DRK_FRM_CAPTURE
+        OMAP3ISP_PREV_DRK_FRM_SUBTRACT
+        OMAP3ISP_PREV_LENS_SHADING
+        OMAP3ISP_PREV_NF
+        OMAP3ISP_PREV_GAMMA
+
+在启用某个功能的时候,相关的配置数据指针不可为 NULL。在禁用某个功能时,
+配置数据指针会被忽略。
+
+
+统计模块 IOCTL
+=============
+
+统计子设备相较于其他子设备提供了更多动态配置选项。在图像处理流水线处于
+工作状态时,它们可以被启用、禁用和重配。
+
+统计模块总是从 CCDC 中获取输入的图像数据(由于直方图内存读取未实现)。
+统计数据可由用户通过统计子设备节点使用私有 IOCTL 获取。
+
+AEWB、AF 和 直方图子设备提供的私有 IOCTL 极大程度上反应了 ISP 硬件
+提供的寄存器级接口。有些方面纯粹和驱动程序的实现相关,这些将在下面讨论。
+
+VIDIOC_OMAP3ISP_STAT_EN
+-----------------------
+
+这个私有 IOCTL 启用/禁用 一个统计模块。如果这个申请在视频流启动前完成,
+它将在视频流水线开始工作时生效。如果视频流水线已经处于工作状态了,它将在
+CCDC 变为空闲时生效。
+
+VIDIOC_OMAP3ISP_AEWB_CFG, VIDIOC_OMAP3ISP_HIST_CFG and VIDIOC_OMAP3ISP_AF_CFG
+-----------------------------------------------------------------------------
+
+这些 IOCTL 用于配置模块。它们要求用户应用程序对硬件有深入的认识。对
+大多数域的解释可以在 OMAP 的 TRM 中找到。以下两个域对于以上所有的
+私有 IOCTL 配置都很常见,由于他们没有在 TRM 中提及,故需要对其有
+更好的认识。
+
+omap3isp_[h3a_af/h3a_aewb/hist]_config.buf_size:
+
+模块在内部处理自身缓冲。对模块数据输出所必需的缓存大小依赖于已申请的配置。
+虽然驱动支持在视频流工作时重新配置,但对于所需缓存量大于模块启用时内部
+所分配数量的情况,则不支持重新配置。在这种情况下将返回 -EBUSY。为了避免
+此类状况,无论是禁用/重配/启用模块,还是第一次配置时申请必须的缓存大小,
+都应在模块禁用的情况下进行。
+
+内部缓冲分配的大小需综合考虑所申请配置的最小缓存量以及 buf_size 域中
+所设的值。如果 buf_size 域在[minimum(最小值), maximum(最大值)]
+缓冲大小范围之外,则应该将其调整到其范围中。驱动则会选择最大值。正确的
+buf_size 值将回写到用户应用程序中。
+
+omap3isp_[h3a_af/h3a_aewb/hist]_config.config_counter:
+
+由于配置并未在申请之后同步生效,驱动必须提供一个跟踪这类信息的方法,
+以提供更准确的数据。在一个配置被申请之后,返回到用户空间应用程序的
+config_counter 是一个与其配置相关的唯一值。当用户应用程序接收到
+一个缓冲可用或一个新的缓冲申请事件时,这个 config_counter 用于
+一个缓冲数据和一个配置的匹配。
+
+VIDIOC_OMAP3ISP_STAT_REQ
+------------------------
+
+将内部缓冲队列中最早的数据发送到用户空间,然后丢弃此缓冲区。
+omap3isp_stat_data.frame_number 域与视频缓冲的 field_count
+域相匹配。
+
+
+技术参考手册 (TRMs) 和其他文档
+==========================
+
+OMAP 3430 TRM:
+<URL:http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZM.zip>
+参考于 2011-03-05.
+
+OMAP 35xx TRM:
+<URL:http://www.ti.com/litv/pdf/spruf98o> 参考于 2011-03-05.
+
+OMAP 3630 TRM:
+<URL:http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vQ.zip>
+参考于 2011-03-05.
+
+DM 3730 TRM:
+<URL:http://www.ti.com/litv/pdf/sprugn4h> 参考于 2011-03-06.
+
+
+参考资料
+=======
+
+[1] include/linux/omap3isp.h
+
+[2] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
diff --git a/Documentation/zh_CN/video4linux/v4l2-framework.txt b/Documentation/zh_CN/video4linux/v4l2-framework.txt
new file mode 100644
index 0000000..3e74f13
--- /dev/null
+++ b/Documentation/zh_CN/video4linux/v4l2-framework.txt
@@ -0,0 +1,983 @@
+Chinese translated version of Documentation/video4linux/v4l2-framework.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Mauro Carvalho Chehab <mchehab@infradead.org>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/video4linux/v4l2-framework.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+英文版维护者: Mauro Carvalho Chehab <mchehab@infradead.org>
+中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+
+
+以下为正文
+---------------------------------------------------------------------
+V4L2 驱动框架概览
+==============
+
+本文档描述 V4L2 框架所提供的各种结构和它们之间的关系。
+
+
+介绍
+----
+
+大部分现代 V4L2 设备由多个 IC 组成,在 /dev 下导出多个设备节点,
+并同时创建非 V4L2 设备(如 DVB、ALSA、FB、I2C 和红外输入设备)。
+由于这种硬件的复杂性,V4L2 驱动也变得非常复杂。
+
+尤其是 V4L2 必须支持 IC 实现音视频的多路复用和编解码,这就更增加了其
+复杂性。通常这些 IC 通过一个或多个 I2C 总线连接到主桥驱动器,但也可
+使用其他总线。这些设备称为“子设备”。
+
+长期以来,这个框架仅限于通过 video_device 结构体创建 V4L 设备节点,
+并使用 video_buf 处理视频缓冲(注:本文不讨论 video_buf 框架)。
+
+这意味着所有驱动必须自己设置设备实例并连接到子设备。其中一部分要正确地
+完成是比较复杂的,使得许多驱动都没有正确地实现。
+
+由于框架的缺失,有很多通用代码都不可重复利用。
+
+因此,这个框架构建所有驱动都需要的基本结构块,而统一的框架将使通用代码
+创建成实用函数并在所有驱动中共享变得更加容易。
+
+
+驱动结构
+-------
+
+所有 V4L2 驱动都有如下结构:
+
+1) 每个设备实例的结构体--包含其设备状态。
+
+2) 初始化和控制子设备的方法(如果有)。
+
+3) 创建 V4L2 设备节点 (/dev/videoX、/dev/vbiX 和 /dev/radioX)
+   并跟踪设备节点的特定数据。
+
+4) 特定文件句柄结构体--包含每个文件句柄的数据。
+
+5) 视频缓冲处理。
+
+以下是它们的初略关系图:
+
+    device instances(设备实例)
+      |
+      +-sub-device instances(子设备实例)
+      |
+      \-V4L2 device nodes(V4L2 设备节点)
+	  |
+	  \-filehandle instances(文件句柄实例)
+
+
+框架结构
+-------
+
+该框架非常类似驱动结构:它有一个 v4l2_device 结构用于保存设备
+实例的数据;一个 v4l2_subdev 结构体代表子设备实例;video_device
+结构体保存 V4L2 设备节点的数据;将来 v4l2_fh 结构体将跟踪文件句柄
+实例(暂未尚未实现)。
+
+V4L2 框架也可与媒体框架整合(可选的)。如果驱动设置了 v4l2_device
+结构体的 mdev 域,子设备和视频节点的入口将自动出现在媒体框架中。
+
+
+v4l2_device 结构体
+----------------
+
+每个设备实例都通过 v4l2_device (v4l2-device.h)结构体来表示。
+简单设备可以仅分配这个结构体,但在大多数情况下,都会将这个结构体
+嵌入到一个更大的结构体中。
+
+你必须注册这个设备实例:
+
+	v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+注册操作将会初始化 v4l2_device 结构体。如果 dev->driver_data 域
+为 NULL,就将其指向 v4l2_dev。
+
+需要与媒体框架整合的驱动必须手动设置 dev->driver_data,指向包含
+v4l2_device 结构体实例的驱动特定设备结构体。这可以在注册 V4L2 设备
+实例前通过 dev_set_drvdata() 函数完成。同时必须设置 v4l2_device
+结构体的 mdev 域,指向适当的初始化并注册过的 media_device 实例。
+
+如果 v4l2_dev->name 为空,则它将被设置为从 dev 中衍生出的值(为了
+更加精确,形式为驱动名后跟 bus_id)。如果你在调用 v4l2_device_register
+前已经设置好了,则不会被修改。如果 dev 为 NULL,则你*必须*在调用
+v4l2_device_register 前设置 v4l2_dev->name。
+
+你可以基于驱动名和驱动的全局 atomic_t 类型的实例编号,通过
+v4l2_device_set_name() 设置 name。这样会生成类似 ivtv0、ivtv1 等
+名字。若驱动名以数字结尾,则会在编号和驱动名间插入一个破折号,如:
+cx18-0、cx18-1 等。此函数返回实例编号。
+
+第一个 “dev” 参数通常是一个指向 pci_dev、usb_interface 或
+platform_device 的指针。很少使其为 NULL,除非是一个ISA设备或者
+当一个设备创建了多个 PCI 设备,使得 v4l2_dev 无法与一个特定的父设备
+关联。
+
+你也可以提供一个 notify() 回调,使子设备可以调用它实现事件通知。
+但这个设置与子设备相关。子设备支持的任何通知必须在
+include/media/<subdevice>.h 中定义一个消息头。
+
+注销 v4l2_device 使用如下函数:
+
+	v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
+如果 dev->driver_data 域指向 v4l2_dev,将会被重置为 NULL。注销同时
+会自动从设备中注销所有子设备。
+
+如果你有一个热插拔设备(如USB设备),则当断开发生时,父设备将无效。
+由于 v4l2_device 有一个指向父设备的指针必须被清除,同时标志父设备
+已消失,所以必须调用以下函数:
+
+	v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+
+这个函数并*不*注销子设备,因此你依然要调用 v4l2_device_unregister()
+函数。如果你的驱动器并非热插拔的,就没有必要调用 v4l2_device_disconnect()。
+
+有时你需要遍历所有被特定驱动注册的设备。这通常发生在多个设备驱动使用
+同一个硬件的情况下。如:ivtvfb 驱动是一个使用 ivtv 硬件的帧缓冲驱动,
+同时 alsa 驱动也使用此硬件。
+
+你可以使用如下例程遍历所有注册的设备:
+
+static int callback(struct device *dev, void *p)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+
+	/* 测试这个设备是否已经初始化 */
+	if (v4l2_dev == NULL)
+		return 0;
+	...
+	return 0;
+}
+
+int iterate(void *p)
+{
+	struct device_driver *drv;
+	int err;
+
+	/* 在PCI 总线上查找ivtv驱动。
+	   pci_bus_type是全局的. 对于USB总线使用usb_bus_type。 */
+	drv = driver_find("ivtv", &pci_bus_type);
+	/* 遍历所有的ivtv设备实例 */
+	err = driver_for_each_device(drv, NULL, p, callback);
+	put_driver(drv);
+	return err;
+}
+
+有时你需要一个设备实例的运行计数。这个通常用于映射一个设备实例到一个
+模块选择数组的索引。
+
+推荐方法如下:
+
+static atomic_t drv_instance = ATOMIC_INIT(0);
+
+static int __devinit drv_probe(struct pci_dev *pdev,
+				const struct pci_device_id *pci_id)
+{
+	...
+	state->instance = atomic_inc_return(&drv_instance) - 1;
+}
+
+如果你有多个设备节点,对于热插拔设备,知道何时注销 v4l2_device 结构体
+就比较困难。为此 v4l2_device 有引用计数支持。当调用 video_register_device
+时增加引用计数,而设备节点释放时减小引用计数。当引用计数为零,则
+v4l2_device 的release() 回调将被执行。你就可以在此时做最后的清理工作。
+
+如果创建了其他设备节点(比如 ALSA),则你可以通过以下函数手动增减
+引用计数:
+
+void v4l2_device_get(struct v4l2_device *v4l2_dev);
+
+或:
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev);
+
+由于引用技术初始化为 1 ,你也需要在 disconnect() 回调(对于 USB 设备)中
+调用 v4l2_device_put,或者 remove() 回调(例如对于 PCI 设备),否则
+引用计数将永远不会为 0 。
+
+v4l2_subdev结构体
+------------------
+
+许多驱动需要与子设备通信。这些设备可以完成各种任务,但通常他们负责
+音视频复用和编解码。如网络摄像头的子设备通常是传感器和摄像头控制器。
+
+这些一般为 I2C 接口设备,但并不一定都是。为了给驱动提供调用子设备的
+统一接口,v4l2_subdev 结构体(v4l2-subdev.h)产生了。
+
+每个子设备驱动都必须有一个 v4l2_subdev 结构体。这个结构体可以单独
+代表一个简单的子设备,也可以嵌入到一个更大的结构体中,与更多设备状态
+信息保存在一起。通常有一个下级设备结构体(比如:i2c_client)包含了
+内核创建的设备数据。建议使用 v4l2_set_subdevdata() 将这个结构体的
+指针保存在 v4l2_subdev 的私有数据域(dev_priv)中。这使得通过 v4l2_subdev
+找到实际的低层总线特定设备数据变得容易。
+
+你同时需要一个从低层结构体获取 v4l2_subdev 指针的方法。对于常用的
+i2c_client 结构体,i2c_set_clientdata() 函数可用于保存一个 v4l2_subdev
+指针;对于其他总线你可能需要使用其他相关函数。
+
+桥驱动中也应保存每个子设备的私有数据,比如一个指向特定桥的各设备私有
+数据的指针。为此 v4l2_subdev 结构体提供主机私有数据域(host_priv),
+并可通过 v4l2_get_subdev_hostdata() 和 v4l2_set_subdev_hostdata()
+访问。
+
+从总线桥驱动的视角,驱动加载子设备模块并以某种方式获得 v4l2_subdev
+结构体指针。对于 i2c 总线设备相对简单:调用 i2c_get_clientdata()。
+对于其他总线也需要做类似的操作。针对 I2C 总线上的子设备辅助函数帮你
+完成了大部分复杂的工作。
+
+每个 v4l2_subdev 都包含子设备驱动需要实现的函数指针(如果对此设备
+不适用,可为NULL)。由于子设备可完成许多不同的工作,而在一个庞大的
+函数指针结构体中通常仅有少数有用的函数实现其功能肯定不合适。所以,
+函数指针根据其实现的功能被分类,每一类都有自己的函数指针结构体。
+
+顶层函数指针结构体包含了指向各类函数指针结构体的指针,如果子设备驱动
+不支持该类函数中的任何一个功能,则指向该类结构体的指针为NULL。
+
+这些结构体定义如下:
+
+struct v4l2_subdev_core_ops {
+	int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
+	int (*log_status)(struct v4l2_subdev *sd);
+	int (*init)(struct v4l2_subdev *sd, u32 val);
+	...
+};
+
+struct v4l2_subdev_tuner_ops {
+	...
+};
+
+struct v4l2_subdev_audio_ops {
+	...
+};
+
+struct v4l2_subdev_video_ops {
+	...
+};
+
+struct v4l2_subdev_pad_ops {
+	...
+};
+
+struct v4l2_subdev_ops {
+	const struct v4l2_subdev_core_ops  *core;
+	const struct v4l2_subdev_tuner_ops *tuner;
+	const struct v4l2_subdev_audio_ops *audio;
+	const struct v4l2_subdev_video_ops *video;
+	const struct v4l2_subdev_pad_ops *video;
+};
+
+其中 core(核心)函数集通常可用于所有子设备,其他类别的实现依赖于
+子设备。如视频设备可能不支持音频操作函数,反之亦然。
+
+这样的设置在限制了函数指针数量的同时,还使增加新的操作函数和分类
+变得较为容易。
+
+子设备驱动可使用如下函数初始化 v4l2_subdev 结构体:
+
+	v4l2_subdev_init(sd, &ops);
+
+然后,你必须用一个唯一的名字初始化 subdev->name,并初始化模块的
+owner 域。若使用 i2c 辅助函数,这些都会帮你处理好。
+
+若需同媒体框架整合,你必须调用 media_entity_init() 初始化 v4l2_subdev
+结构体中的 media_entity 结构体(entity 域):
+
+	struct media_pad *pads = &my_sd->pads;
+	int err;
+
+	err = media_entity_init(&sd->entity, npads, pads, 0);
+
+pads 数组必须预先初始化。无须手动设置 media_entity 的 type 和
+name 域,但如有必要,revision 域必须初始化。
+
+当(任何)子设备节点被打开/关闭,对 entity 的引用将被自动获取/释放。
+
+在子设备被注销之后,不要忘记清理 media_entity 结构体:
+
+	media_entity_cleanup(&sd->entity);
+
+如果子设备驱动趋向于处理视频并整合进了媒体框架,必须使用 v4l2_subdev_pad_ops
+替代 v4l2_subdev_video_ops 实现格式相关的功能。
+
+这种情况下,子设备驱动应该设置 link_validate 域,以提供它自身的链接
+验证函数。链接验证函数应对管道(两端链接的都是 V4L2 子设备)中的每个
+链接调用。驱动还要负责验证子设备和视频节点间格式配置的正确性。
+
+如果 link_validate 操作没有设置,默认的 v4l2_subdev_link_validate_default()
+函数将会被调用。这个函数保证宽、高和媒体总线像素格式在链接的收发两端
+都一致。子设备驱动除了它们自己的检测外,也可以自由使用这个函数以执行
+上面提到的检查。
+
+设备(桥)驱动程序必须向 v4l2_device 注册 v4l2_subdev:
+
+	int err = v4l2_device_register_subdev(v4l2_dev, sd);
+
+如果子设备模块在它注册前消失,这个操作可能失败。在这个函数成功返回后,
+subdev->dev 域就指向了 v4l2_device。
+
+如果 v4l2_device 父设备的 mdev 域为非 NULL 值,则子设备实体将被自动
+注册为媒体设备。
+
+注销子设备则可用如下函数:
+
+	v4l2_device_unregister_subdev(sd);
+
+此后,子设备模块就可卸载,且 sd->dev == NULL。
+
+注册之设备后,可通过以下方式直接调用其操作函数:
+
+	err = sd->ops->core->g_chip_ident(sd, &chip);
+
+但使用如下宏会比较容易且合适:
+
+	err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+
+这个宏将会做 NULL 指针检查,如果 subdev 为 NULL,则返回-ENODEV;如果
+subdev->core 或 subdev->core->g_chip_ident 为 NULL,则返回 -ENOIOCTLCMD;
+否则将返回 subdev->ops->core->g_chip_ident ops 调用的实际结果。
+
+有时也可能同时调用所有或一系列子设备的某个操作函数:
+
+	v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip);
+
+任何不支持此操作的子设备都会被跳过,并忽略错误返回值。但如果你需要
+检查出错码,则可使用如下函数:
+
+	err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip);
+
+除 -ENOIOCTLCMD 外的任何错误都会跳出循环并返回错误值。如果(除 -ENOIOCTLCMD
+外)没有错误发生,则返回 0。
+
+对于以上两个函数的第二个参数为组 ID。如果为 0,则所有子设备都会执行
+这个操作。如果为非 0 值,则只有那些组 ID 匹配的子设备才会执行此操作。
+在桥驱动注册一个子设备前,可以设置 sd->grp_id 为任何期望值(默认值为
+0)。这个值属于桥驱动,且子设备驱动将不会修改和使用它。
+
+组 ID 赋予了桥驱动更多对于如何调用回调的控制。例如,电路板上有多个
+音频芯片,每个都有改变音量的能力。但当用户想要改变音量的时候,通常
+只有一个会被实际使用。你可以对这样的子设备设置组 ID 为(例如 AUDIO_CONTROLLER)
+并在调用 v4l2_device_call_all() 时指定它为组 ID 值。这就保证了只有
+需要的子设备才会执行这个回调。
+
+如果子设备需要通知它的 v4l2_device 父设备一个事件,可以调用
+v4l2_subdev_notify(sd, notification, arg)。这个宏检查是否有一个
+notify() 回调被注册,如果没有,返回 -ENODEV。否则返回 notify() 调用
+结果。
+
+使用 v4l2_subdev 的好处在于它是一个通用结构体,且不包含任何底层硬件
+信息。所有驱动可以包含多个 I2C 总线的子设备,但也有子设备是通过 GPIO
+控制。这个区别仅在配置设备时有关系,一旦子设备注册完成,对于 v4l2
+子系统来说就完全透明了。
+
+
+V4L2 子设备用户空间API
+--------------------
+
+除了通过 v4l2_subdev_ops 结构导出的内核 API,V4L2 子设备也可以直接
+通过用户空间应用程序来控制。
+
+可以在 /dev 中创建名为 v4l-subdevX 设备节点,以通过其直接访问子设备。
+如果子设备支持用户空间直接配置,必须在注册前设置 V4L2_SUBDEV_FL_HAS_DEVNODE
+标志。
+
+注册子设备之后, v4l2_device 驱动会通过调用 v4l2_device_register_subdev_nodes()
+函数为所有已注册并设置了 V4L2_SUBDEV_FL_HAS_DEVNODE 的子设备创建
+设备节点。这些设备节点会在子设备注销时自动删除。
+
+这些设备节点处理 V4L2 API 的一个子集。
+
+VIDIOC_QUERYCTRL
+VIDIOC_QUERYMENU
+VIDIOC_G_CTRL
+VIDIOC_S_CTRL
+VIDIOC_G_EXT_CTRLS
+VIDIOC_S_EXT_CTRLS
+VIDIOC_TRY_EXT_CTRLS
+
+	这些 ioctls 控制与 V4L2 中定义的一致。他们行为相同,唯一的
+	不同是他们只处理子设备的控制实现。根据驱动程序,这些控制也
+	可以通过一个(或多个) V4L2 设备节点访问。
+
+VIDIOC_DQEVENT
+VIDIOC_SUBSCRIBE_EVENT
+VIDIOC_UNSUBSCRIBE_EVENT
+
+	这些  ioctls 事件与 V4L2 中定义的一致。他们行为相同,唯一的
+	不同是他们只处理子设备产生的事件。根据驱动程序,这些事件也
+	可以通过一个(或多个) V4L2 设备节点上报。
+
+	要使用事件通知的子设备驱动,在注册子设备前必须在 v4l2_subdev::flags
+	中设置 V4L2_SUBDEV_USES_EVENTS 并在 v4l2_subdev::nevents
+	中初始化事件队列深度。注册完成后,事件会在 v4l2_subdev::devnode
+	设备节点中像通常一样被排队。
+
+	为正确支持事件机制,poll() 文件操作也应被实现。
+
+私有 ioctls
+
+	不在以上列表中的所有 ioctls 会通过 core::ioctl 操作直接传递
+	给子设备驱动。
+
+
+I2C 子设备驱动
+-------------
+
+由于这些驱动很常见,所以内特提供了特定的辅助函数(v4l2-common.h)让这些
+设备的使用更加容易。
+
+添加 v4l2_subdev 支持的推荐方法是让 I2C 驱动将 v4l2_subdev 结构体
+嵌入到为每个 I2C 设备实例创建的状态结构体中。而最简单的设备没有状态
+结构体,此时可以直接创建一个 v4l2_subdev 结构体。
+
+一个典型的状态结构体如下所示(‘chipname’用芯片名代替):
+
+struct chipname_state {
+	struct v4l2_subdev sd;
+	...  /* 附加的状态域*/
+};
+
+初始化 v4l2_subdev 结构体的方法如下:
+
+	v4l2_i2c_subdev_init(&state->sd, client, subdev_ops);
+
+这个函数将填充 v4l2_subdev 结构体中的所有域,并保证 v4l2_subdev 和
+i2c_client 都指向彼此。
+
+同时,你也应该为从 v4l2_subdev 指针找到 chipname_state 结构体指针
+添加一个辅助内联函数。
+
+static inline struct chipname_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct chipname_state, sd);
+}
+
+使用以下函数可以通过 v4l2_subdev 结构体指针获得 i2c_client 结构体
+指针:
+
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+而以下函数则相反,通过 i2c_client 结构体指针获得 v4l2_subdev 结构体
+指针:
+
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+当 remove()函数被调用前,必须保证先调用 v4l2_device_unregister_subdev(sd)。
+此操作将会从桥驱动中注销子设备。即使子设备没有注册,调用此函数也是
+安全的。
+
+必须这样做的原因是:当桥驱动注销 i2c 适配器时,remove()回调函数
+会被那个适配器上的 i2c 设备调用。此后,相应的 v4l2_subdev 结构体
+就不存在了,所有它们必须先被注销。在 remove()回调函数中调用
+v4l2_device_unregister_subdev(sd),可以保证执行总是正确的。
+
+
+桥驱动也有一些辅组函数可用:
+
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter,
+	       "module_foo", "chipid", 0x36, NULL);
+
+这个函数会加载给定的模块(如果没有模块需要加载,可以为 NULL),
+并用给定的 i2c 适配器结构体指针(i2c_adapter)和 器件地址(chip/address)
+作为参数调用 i2c_new_device()。如果一切顺利,则就在 v4l2_device
+中注册了子设备。
+
+你也可以利用 v4l2_i2c_new_subdev()的最后一个参数,传递一个可能的
+I2C 地址数组,让函数自动探测。这些探测地址只有在前一个参数为 0 的
+情况下使用。非零参数意味着你知道准确的 i2c 地址,所以此时无须进行
+探测。
+
+如果出错,两个函数都返回 NULL。
+
+注意:传递给 v4l2_i2c_new_subdev()的 chipid 通常与模块名一致。
+它允许你指定一个芯片的变体,比如“saa7114”或“saa7115”。一般通过
+i2c 驱动自动探测。chipid 的使用是在今后需要深入了解的事情。这个与
+i2c 驱动不同,较容易混淆。要知道支持哪些芯片变体,你可以查阅 i2c
+驱动代码的 i2c_device_id 表,上面列出了所有可能支持的芯片。
+
+还有两个辅助函数:
+
+v4l2_i2c_new_subdev_cfg:这个函数添加新的 irq 和 platform_data
+参数,并有‘addr’和‘probed_addrs’参数:如果 addr 非零,则被使用
+(不探测变体),否则 probed_addrs 中的地址将用于自动探测。
+
+例如:以下代码将会探测地址(0x10):
+
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter,
+	       "module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10));
+
+v4l2_i2c_new_subdev_board 使用一个 i2c_board_info 结构体,将其
+替代 irq、platform_data 和 add r参数传递给 i2c 驱动。
+
+如果子设备支持 s_config 核心操作,这个操作会在子设备配置好之后以 irq 和
+platform_data 为参数调用。早期的 v4l2_i2c_new_(probed_)subdev 函数
+同样也会调用 s_config,但仅在 irq 为 0 且 platform_data 为 NULL 时。
+
+video_device结构体
+-----------------
+
+在 /dev 目录下的实际设备节点根据 video_device 结构体(v4l2-dev.h)
+创建。此结构体既可以动态分配也可以嵌入到一个更大的结构体中。
+
+动态分配方法如下:
+
+	struct video_device *vdev = video_device_alloc();
+
+	if (vdev == NULL)
+		return -ENOMEM;
+
+	vdev->release = video_device_release;
+
+如果将其嵌入到一个大结构体中,则必须自己实现 release()回调。
+
+	struct video_device *vdev = &my_vdev->vdev;
+
+	vdev->release = my_vdev_release;
+
+release()回调必须被设置,且在最后一个 video_device 用户退出之后
+被调用。
+
+默认的 video_device_release()回调只是调用 kfree 来释放之前分配的
+内存。
+
+你应该设置这些域:
+
+- v4l2_dev: 设置为 v4l2_device 父设备。
+
+- name: 设置为唯一的描述性设备名。
+
+- fops: 设置为已有的 v4l2_file_operations 结构体。
+
+- ioctl_ops: 如果你使用v4l2_ioctl_ops 来简化 ioctl 的维护
+  (强烈建议使用,且将来可能变为强制性的!),然后设置你自己的
+  v4l2_ioctl_ops 结构体.
+
+- lock: 如果你要在驱动中实现所有的锁操作,则设为 NULL 。否则
+  就要设置一个指向 struct mutex_lock 结构体的指针,这个锁将
+  在 unlocked_ioctl 文件操作被调用前由内核获得,并在调用返回后
+  释放。详见下一节。
+
+- prio: 保持对优先级的跟踪。用于实现 VIDIOC_G/S_PRIORITY。如果
+  设置为 NULL,则会使用 v4l2_device 中的 v4l2_prio_state 结构体。
+  如果要对每个设备节点(组)实现独立的优先级,可以将其指向自己
+  实现的 v4l2_prio_state 结构体。
+
+- parent: 仅在使用 NULL 作为父设备结构体参数注册 v4l2_device 时
+  设置此参数。只有在一个硬件设备包含多一个 PCI 设备,共享同一个
+  v4l2_device 核心时才会发生。
+
+  cx88 驱动就是一个例子:一个 v4l2_device 结构体核心,被一个裸的
+  视频 PCI 设备(cx8800)和一个 MPEG PCI 设备(cx8802)共用。由于
+  v4l2_device 无法与特定的 PCI 设备关联,所有没有设置父设备。但当
+  video_device 配置后,就知道使用哪个父 PCI 设备了。
+
+- flags:可选。如果你要让框架处理设置 VIDIOC_G/S_PRIORITY ioctls,
+  请设置 V4L2_FL_USE_FH_PRIO。这要求你使用 v4l2_fh 结构体。
+  一旦所有驱动使用了核心的优先级处理,最终这个标志将消失。但现在它
+  必须被显式设置。
+
+如果你使用 v4l2_ioctl_ops,则应该在 v4l2_file_operations 结构体中
+设置 .unlocked_ioctl 指向 video_ioctl2。
+
+请勿使用 .ioctl!它已被废弃,今后将消失。
+
+某些情况下你要告诉核心:你在 v4l2_ioctl_ops 指定的某个函数应被忽略。
+你可以在 video_device_register 被调用前通过以下函数标记这个 ioctls。
+
+void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd);
+
+基于外部因素(例如某个板卡已被使用),在不创建新结构体的情况下,你想
+要关闭 v4l2_ioctl_ops 中某个特性往往需要这个机制。
+
+v4l2_file_operations 结构体是 file_operations 的一个子集。其主要
+区别在于:因 inode 参数从未被使用,它将被忽略。
+
+如果需要与媒体框架整合,你必须通过调用 media_entity_init() 初始化
+嵌入在 video_device 结构体中的 media_entity(entity 域)结构体:
+
+	struct media_pad *pad = &my_vdev->pad;
+	int err;
+
+	err = media_entity_init(&vdev->entity, 1, pad, 0);
+
+pads 数组必须预先初始化。没有必要手动设置 media_entity 的 type 和
+name 域。
+
+当(任何)子设备节点被打开/关闭,对 entity 的引用将被自动获取/释放。
+
+v4l2_file_operations 与锁
+--------------------------
+
+你可以在 video_device 结构体中设置一个指向 mutex_lock 的指针。通常
+这既可是一个顶层互斥锁也可为设备节点自身的互斥锁。默认情况下,此锁
+用于 unlocked_ioctl,但为了使用 ioctls 你通过以下函数可禁用锁定:
+
+	void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd);
+
+例如: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF);
+
+你必须在注册 video_device 前调用这个函数。
+
+特别是对于 USB 驱动程序,某些命令(如设置控制)需要很长的时间,可能
+需要自行为缓冲区队列的 ioctls 实现锁定。
+
+如果你需要更细粒度的锁,你必须设置 mutex_lock 为 NULL,并完全自己实现
+锁机制。
+
+这完全由驱动开发者决定使用何种方法。然而,如果你的驱动存在长延时操作
+(例如,改变 USB 摄像头的曝光时间可能需要较长时间),而你又想让用户
+在等待长延时操作完成期间做其他的事,则你最好自己实现锁机制。
+
+如果指定一个锁,则所有 ioctl 操作将在这个锁的作用下串行执行。如果你
+使用 videobuf,则必须将同一个锁传递给 videobuf 队列初始化函数;如
+videobuf 必须等待一帧的到达,则可临时解锁并在这之后重新上锁。如果驱动
+也在代码执行期间等待,则可做同样的工作(临时解锁,再上锁)让其他进程
+可以在第一个进程阻塞时访问设备节点。
+
+在使用 videobuf2 的情况下,必须实现 wait_prepare 和 wait_finish 回调
+在适当的时候解锁/加锁。进一步来说,如果你在 video_device 结构体中使用
+锁,则必须在 wait_prepare 和 wait_finish 中对这个互斥锁进行解锁/加锁。
+
+热插拔的断开实现也必须在调用 v4l2_device_disconnect 前获得锁。
+
+video_device注册
+---------------
+
+接下来你需要注册视频设备:这会为你创建一个字符设备。
+
+	err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+	if (err) {
+		video_device_release(vdev); /* or kfree(my_vdev); */
+		return err;
+	}
+
+如果 v4l2_device 父设备的 mdev 域为非 NULL 值,视频设备实体将自动
+注册为媒体设备。
+
+注册哪种设备是根据类型(type)参数。存在以下类型:
+
+VFL_TYPE_GRABBER: 用于视频输入/输出设备的 videoX
+VFL_TYPE_VBI: 用于垂直消隐数据的 vbiX (例如,隐藏式字幕,图文电视)
+VFL_TYPE_RADIO: 用于广播调谐器的 radioX
+
+最后一个参数让你确定一个所控制设备的设备节点号数量(例如 videoX 中的 X)。
+通常你可以传入-1,让 v4l2 框架自己选择第一个空闲的编号。但是有时用户
+需要选择一个特定的节点号。驱动允许用户通过驱动模块参数选择一个特定的
+设备节点号是很普遍的。这个编号将会传递给这个函数,且 video_register_device
+将会试图选择这个设备节点号。如果这个编号被占用,下一个空闲的设备节点
+编号将被选中,并向内核日志中发送一个警告信息。
+
+另一个使用场景是当驱动创建多个设备时。这种情况下,对不同的视频设备在
+编号上使用不同的范围是很有用的。例如,视频捕获设备从 0 开始,视频
+输出设备从 16 开始。所以你可以使用最后一个参数来指定设备节点号最小值,
+而 v4l2 框架会试图选择第一个的空闲编号(等于或大于你提供的编号)。
+如果失败,则它会就选择第一个空闲的编号。
+
+由于这种情况下,你会忽略无法选择特定设备节点号的警告,则可调用
+video_register_device_no_warn() 函数避免警告信息的产生。
+
+只要设备节点被创建,一些属性也会同时创建。在 /sys/class/video4linux
+目录中你会找到这些设备。例如进入其中的 video0 目录,你会看到‘name’和
+‘index’属性。‘name’属性值就是 video_device 结构体中的‘name’域。
+
+‘index’属性值就是设备节点的索引值:每次调用 video_register_device(),
+索引值都递增 1 。第一个视频设备节点总是从索引值 0 开始。
+
+用户可以设置 udev 规则,利用索引属性生成花哨的设备名(例如:用‘mpegX’
+代表 MPEG 视频捕获设备节点)。
+
+在设备成功注册后,就可以使用这些域:
+
+- vfl_type: 传递给 video_register_device 的设备类型。
+- minor: 已指派的次设备号。
+- num: 设备节点编号 (例如 videoX 中的 X)。
+- index: 设备索引号。
+
+如果注册失败,你必须调用 video_device_release() 来释放已分配的
+video_device 结构体;如果 video_device 是嵌入在自己创建的结构体中,
+你也必须释放它。vdev->release() 回调不会在注册失败之后被调用,
+你也不应试图在注册失败后注销设备。
+
+
+video_device 注销
+----------------
+
+当视频设备节点已被移除,不论是卸载驱动还是USB设备断开,你都应注销
+它们:
+
+	video_unregister_device(vdev);
+
+这个操作将从 sysfs 中移除设备节点(导致 udev 将其从 /dev 中移除)。
+
+video_unregister_device() 返回之后,就无法完成打开操作。尽管如此,
+USB 设备的情况则不同,某些应用程序可能依然打开着其中一个已注销设备
+节点。所以在注销之后,所有文件操作(当然除了 release )也应返回错误值。
+
+当最后一个视频设备节点的用户退出,则 vdev->release() 回调会被调用,
+并且你可以做最后的清理操作。
+
+不要忘记清理与视频设备相关的媒体入口(如果被初始化过):
+
+	media_entity_cleanup(&vdev->entity);
+
+这可以在 release 回调中完成。
+
+
+video_device 辅助函数
+---------------------
+
+一些有用的辅助函数如下:
+
+- file/video_device 私有数据
+
+你可以用以下函数在 video_device 结构体中设置/获取驱动私有数据:
+
+void *video_get_drvdata(struct video_device *vdev);
+void video_set_drvdata(struct video_device *vdev, void *data);
+
+注意:在调用 video_register_device() 前执行 video_set_drvdata()
+是安全的。
+
+而以下函数:
+
+struct video_device *video_devdata(struct file *file);
+
+返回 file 结构体中拥有的的 video_device 指针。
+
+video_drvdata 辅助函数结合了 video_get_drvdata 和 video_devdata
+的功能:
+
+void *video_drvdata(struct file *file);
+
+你可以使用如下代码从 video_device 结构体中获取 v4l2_device 结构体
+指针:
+
+struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
+
+- 设备节点名
+
+video_device 设备节点在内核中的名称可以通过以下函数获得
+
+const char *video_device_node_name(struct video_device *vdev);
+
+这个名字被用户空间工具(例如 udev)作为提示信息使用。应尽可能使用
+此功能,而非访问 video_device::num 和 video_device::minor 域。
+
+
+视频缓冲辅助函数
+---------------
+
+v4l2 核心 API 提供了一个处理视频缓冲的标准方法(称为“videobuf”)。
+这些方法使驱动可以通过统一的方式实现 read()、mmap() 和 overlay()。
+目前在设备上支持视频缓冲的方法有分散/聚集 DMA(videobuf-dma-sg)、
+线性 DMA(videobuf-dma-contig)以及大多用于 USB 设备的用 vmalloc
+分配的缓冲(videobuf-vmalloc)。
+
+请参阅 Documentation/video4linux/videobuf,以获得更多关于 videobuf
+层的使用信息。
+
+v4l2_fh 结构体
+-------------
+
+v4l2_fh 结构体提供一个保存用于 V4L2 框架的文件句柄特定数据的简单方法。
+如果 video_device 的 flag 设置了 V4L2_FL_USE_FH_PRIO 标志,新驱动
+必须使用 v4l2_fh 结构体,因为它也用于实现优先级处理(VIDIOC_G/S_PRIORITY)。
+
+v4l2_fh 的用户(位于 V4l2 框架中,并非驱动)可通过测试
+video_device->flags 中的 V4L2_FL_USES_V4L2_FH 位得知驱动是否使用
+v4l2_fh 作为他的 file->private_data 指针。这个位会在调用 v4l2_fh_init()
+时被设置。
+
+v4l2_fh 结构体作为驱动自身文件句柄结构体的一部分被分配,且驱动在
+其打开函数中将 file->private_data 指向它。
+
+在许多情况下,v4l2_fh 结构体会嵌入到一个更大的结构体中。这钟情况下,
+应该在 open() 中调用 v4l2_fh_init+v4l2_fh_add,并在 release() 中
+调用 v4l2_fh_del+v4l2_fh_exit。
+
+驱动可以通过使用 container_of 宏提取他们自己的文件句柄结构体。例如:
+
+struct my_fh {
+	int blah;
+	struct v4l2_fh fh;
+};
+
+...
+
+int my_open(struct file *file)
+{
+	struct my_fh *my_fh;
+	struct video_device *vfd;
+	int ret;
+
+	...
+
+	my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL);
+
+	...
+
+	v4l2_fh_init(&my_fh->fh, vfd);
+
+	...
+
+	file->private_data = &my_fh->fh;
+	v4l2_fh_add(&my_fh->fh);
+	return 0;
+}
+
+int my_release(struct file *file)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct my_fh *my_fh = container_of(fh, struct my_fh, fh);
+
+	...
+	v4l2_fh_del(&my_fh->fh);
+	v4l2_fh_exit(&my_fh->fh);
+	kfree(my_fh);
+	return 0;
+}
+
+以下是 v4l2_fh 函数使用的简介:
+
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+
+  初始化文件句柄。这*必须*在驱动的 v4l2_file_operations->open()
+  函数中执行。
+
+void v4l2_fh_add(struct v4l2_fh *fh)
+
+  添加一个 v4l2_fh 到 video_device 文件句柄列表。一旦文件句柄
+  初始化完成就必须调用。
+
+void v4l2_fh_del(struct v4l2_fh *fh)
+
+  从 video_device() 中解除文件句柄的关联。文件句柄的退出函数也
+  将被调用。
+
+void v4l2_fh_exit(struct v4l2_fh *fh)
+
+  清理文件句柄。在清理完 v4l2_fh 后,相关内存会被释放。
+
+
+如果 v4l2_fh 不是嵌入在其他结构体中的,则可以用这些辅助函数:
+
+int v4l2_fh_open(struct file *filp)
+
+  分配一个 v4l2_fh 结构体空间,初始化并将其添加到 file 结构体相关的
+  video_device 结构体中。
+
+int v4l2_fh_release(struct file *filp)
+
+  从 file 结构体相关的 video_device 结构体中删除 v4l2_fh ,清理
+  v4l2_fh 并释放空间。
+
+这两个函数可以插入到 v4l2_file_operation 的 open() 和 release()
+操作中。
+
+
+某些驱动需要在第一个文件句柄打开和最后一个文件句柄关闭的时候做些
+工作。所以加入了两个辅助函数以检查 v4l2_fh 结构体是否是相关设备
+节点打开的唯一文件句柄。
+
+int v4l2_fh_is_singular(struct v4l2_fh *fh)
+
+  如果此文件句柄是唯一打开的文件句柄,则返回 1 ,否则返回 0 。
+
+int v4l2_fh_is_singular_file(struct file *filp)
+
+  功能相同,但通过 filp->private_data 调用 v4l2_fh_is_singular。
+
+
+V4L2 事件机制
+-----------
+
+V4L2 事件机制提供了一个通用的方法将事件传递到用户空间。驱动必须使用
+v4l2_fh 才能支持 V4L2 事件机制。
+
+
+事件通过一个类型和选择 ID 来定义。ID 对应一个 V4L2 对象,例如
+一个控制 ID。如果未使用,则 ID 为 0。
+
+当用户订阅一个事件,驱动会为此分配一些 kevent 结构体。所以每个
+事件组(类型、ID)都会有自己的一套 kevent 结构体。这保证了如果
+一个驱动短时间内产生了许多同类事件,不会覆盖其他类型的事件。
+
+但如果你收到的事件数量大于同类事件 kevent 的保存数量,则最早的
+事件将被丢弃,并加入新事件。
+
+此外,v4l2_subscribed_event 结构体内部有可供驱动设置的 merge() 和
+replace() 回调,这些回调会在新事件产生且没有多余空间的时候被调用。
+replace() 回调让你可以将早期事件的净荷替换为新事件的净荷,将早期
+净荷的相关数据合并到替换进来的新净荷中。当该类型的事件仅分配了一个
+kevent 结构体时,它将被调用。merge() 回调让你可以合并最早的事件净荷
+到在它之后的那个事件净荷中。当该类型的事件分配了两个或更多 kevent
+结构体时,它将被调用。
+
+这种方法不会有状态信息丢失,只会导致中间步骤信息丢失。
+
+
+关于 replace/merge 回调的一个不错的例子在 v4l2-event.c 中:用于
+控制事件的 ctrls_replace() 和 ctrls_merge() 回调。
+
+注意:这些回调可以在中断上下文中调用,所以它们必须尽快完成并退出。
+
+有用的函数:
+
+void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
+
+  将事件加入视频设备的队列。驱动仅负责填充 type 和 data 域。
+  其他域由 V4L2 填充。
+
+int v4l2_event_subscribe(struct v4l2_fh *fh,
+			 struct v4l2_event_subscription *sub, unsigned elems,
+			 const struct v4l2_subscribed_event_ops *ops)
+
+  video_device->ioctl_ops->vidioc_subscribe_event 必须检测驱动能
+  产生特定 id 的事件。然后调用 v4l2_event_subscribe() 来订阅该事件。
+
+  elems 参数是该事件的队列大小。若为 0,V4L2 框架将会(根据事件类型)
+  填充默认值。
+
+  ops 参数允许驱动指定一系列回调:
+  * add:     当添加一个新监听者时调用(重复订阅同一个事件,此回调
+             仅被执行一次)。
+  * del:     当一个监听者停止监听时调用。
+  * replace: 用‘新’事件替换‘早期‘事件。
+  * merge:   将‘早期‘事件合并到‘新’事件中。
+  这四个调用都是可选的,如果不想指定任何回调,则 ops 可为 NULL。
+
+int v4l2_event_unsubscribe(struct v4l2_fh *fh,
+			   struct v4l2_event_subscription *sub)
+
+  v4l2_ioctl_ops 结构体中的 vidioc_unsubscribe_event 回调函数。
+  驱动程序可以直接使用 v4l2_event_unsubscribe() 实现退订事件过程。
+
+  特殊的 V4L2_EVENT_ALL 类型,可用于退订所有事件。驱动可能在特殊
+  情况下需要做此操作。
+
+int v4l2_event_pending(struct v4l2_fh *fh)
+
+  返回未决事件的数量。有助于实现轮询(poll)操作。
+
+事件通过 poll 系统调用传递到用户空间。驱动可用
+v4l2_fh->wait (wait_queue_head_t 类型)作为参数调用 poll_wait()。
+
+事件分为标准事件和私有事件。新的标准事件必须使用可用的最小事件类型
+编号。驱动必须从他们本类型的编号起始处分配事件。类型的编号起始为
+V4L2_EVENT_PRIVATE_START + n * 1000 ,其中 n 为可用最小编号。每个
+类型中的第一个事件类型编号是为以后的使用保留的,所以第一个可用事件
+类型编号是‘class base + 1’。
+
+V4L2 事件机制的使用实例可以在 OMAP3 ISP 的驱动
+(drivers/media/video/omap3isp)中找到。
diff --git a/MAINTAINERS b/MAINTAINERS
index 53cc13c..140dba1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -595,7 +595,6 @@
 S:	Maintained
 F:	arch/arm/kernel/perf_event*
 F:	arch/arm/oprofile/common.c
-F:	arch/arm/kernel/pmu.c
 F:	arch/arm/include/asm/pmu.h
 F:	arch/arm/kernel/hw_breakpoint.c
 F:	arch/arm/include/asm/hw_breakpoint.h
@@ -913,6 +912,12 @@
 S:	Maintained
 F:	arch/arm/mach-orion5x/ts78xx-*
 
+ARM/MICREL KS8695 ARCHITECTURE
+M:	Greg Ungerer <gerg@uclinux.org>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+F:	arch/arm/mach-ks8695
+S:	Odd Fixes
+
 ARM/MIOA701 MACHINE SUPPORT
 M:	Robert Jarzmik <robert.jarzmik@free.fr>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1209,6 +1214,12 @@
 F:	arch/arm/mach-pxa/z2.c
 F:	arch/arm/mach-pxa/include/mach/z2.h
 
+ARM64 PORT (AARCH64 ARCHITECTURE)
+M:	Catalin Marinas <catalin.marinas@arm.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	arch/arm64/
+
 ASC7621 HARDWARE MONITOR DRIVER
 M:	George Joseph <george.joseph@fairview5.com>
 L:	lm-sensors@lm-sensors.org
@@ -1613,6 +1624,16 @@
 S:	Supported
 F:	drivers/net/ethernet/broadcom/bnx2x/
 
+BROADCOM BCM2835 ARM ARCHICTURE
+M:	Stephen Warren <swarren@wwwdotorg.org>
+L:	linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-rpi.git
+S:	Maintained
+F:	arch/arm/mach-bcm2835/
+F:	arch/arm/boot/dts/bcm2835*
+F:	arch/arm/configs/bcm2835_defconfig
+F:	drivers/*/*bcm2835*
+
 BROADCOM TG3 GIGABIT ETHERNET DRIVER
 M:	Matt Carlson <mcarlson@broadcom.com>
 M:	Michael Chan <mchan@broadcom.com>
@@ -2859,7 +2880,9 @@
 F:	tools/firewire/
 
 FIRMWARE LOADER (request_firmware)
-S:	Orphan
+M:	Ming Lei <ming.lei@canonical.com>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
 F:	Documentation/firmware_class/
 F:	drivers/base/firmware*.c
 F:	include/linux/firmware.h
@@ -3552,11 +3575,12 @@
 
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:	Intel SCU Linux support <intel-linux-scu@intel.com>
+M:	Lukasz Dorau <lukasz.dorau@intel.com>
+M:	Maciej Patelczyk <maciej.patelczyk@intel.com>
 M:	Dave Jiang <dave.jiang@intel.com>
-M:	Ed Nadolski <edmund.nadolski@intel.com>
 L:	linux-scsi@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git
-S:	Maintained
+T:	git git://git.code.sf.net/p/intel-sas/isci
+S:	Supported
 F:	drivers/scsi/isci/
 F:	firmware/isci/
 
@@ -3666,11 +3690,12 @@
 F:	drivers/net/wireless/ipw2x00/
 
 INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
-M:	Joseph Cihula <joseph.cihula@intel.com>
+M:	Richard L Maliszewski <richard.l.maliszewski@intel.com>
+M:	Gang Wei <gang.wei@intel.com>
 M:	Shane Wang <shane.wang@intel.com>
 L:	tboot-devel@lists.sourceforge.net
 W:	http://tboot.sourceforge.net
-T:	Mercurial http://www.bughost.org/repos.hg/tboot.hg
+T:	hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
 S:	Supported
 F:	Documentation/intel_txt.txt
 F:	include/linux/tboot.h
@@ -5320,6 +5345,12 @@
 S:	Maintained
 F:	drivers/mtd/devices/phram.c
 
+PICOLCD HID DRIVER
+M:	Bruno Prémont <bonbons@linux-vserver.org>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/hid-picolcd*
+
 PICOXCELL SUPPORT
 M:	Jamie Iles <jamie@jamieiles.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -5543,6 +5574,8 @@
 F:	include/linux/pwm.h
 F:	include/linux/of_pwm.h
 F:	drivers/pwm/
+F:	drivers/video/backlight/pwm_bl.c
+F:	include/linux/pwm_backlight.h
 
 PXA2xx/PXA3xx SUPPORT
 M:	Eric Miao <eric.y.miao@gmail.com>
@@ -6776,14 +6809,14 @@
 F:	include/linux/if_team.h
 
 TEGRA SUPPORT
-M:	Colin Cross <ccross@android.com>
-M:	Olof Johansson <olof@lixom.net>
 M:	Stephen Warren <swarren@wwwdotorg.org>
 L:	linux-tegra@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/linux-tegra/list/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
 S:	Supported
 F:	arch/arm/mach-tegra
+F:	arch/arm/boot/dts/tegra*
+F:	arch/arm/configs/tegra_defconfig
 
 TEHUTI ETHERNET DRIVER
 M:	Andy Gospodarek <andy@greyhouse.net>
diff --git a/Makefile b/Makefile
index ae6928c..846dd76 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
-NAME = Saber-toothed Squirrel
+EXTRAVERSION =
+NAME = Terrified Chipmunk
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -609,7 +609,11 @@
 endif
 
 ifdef CONFIG_FUNCTION_TRACER
-KBUILD_CFLAGS	+= -pg
+ifdef CONFIG_HAVE_FENTRY
+CC_USING_FENTRY	:= $(call cc-option, -mfentry -DCC_USING_FENTRY)
+endif
+KBUILD_CFLAGS	+= -pg $(CC_USING_FENTRY)
+KBUILD_AFLAGS	+= $(CC_USING_FENTRY)
 ifdef CONFIG_DYNAMIC_FTRACE
 	ifdef CONFIG_HAVE_C_RECORDMCOUNT
 		BUILD_C_RECORDMCOUNT := y
diff --git a/arch/Kconfig b/arch/Kconfig
index 72f2fa1..a62965d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -222,6 +222,19 @@
 	  subsystem.  Also has support for calculating CPU cycle events
 	  to determine how many clock cycles in a given period.
 
+config HAVE_PERF_REGS
+	bool
+	help
+	  Support selective register dumps for perf events. This includes
+	  bit-mapping of each registers and a unique architecture id.
+
+config HAVE_PERF_USER_STACK_DUMP
+	bool
+	help
+	  Support user stack dumps for perf event samples. This needs
+	  access to the user stack pointer which is not unified across
+	  architectures.
+
 config HAVE_ARCH_JUMP_LABEL
 	bool
 
@@ -281,4 +294,23 @@
 
 	  See Documentation/prctl/seccomp_filter.txt for details.
 
+config HAVE_RCU_USER_QS
+	bool
+	help
+	  Provide kernel entry/exit hooks necessary for userspace
+	  RCU extended quiescent state. Syscalls need to be wrapped inside
+	  rcu_user_exit()-rcu_user_enter() through the slow path using
+	  TIF_NOHZ flag. Exceptions handlers must be wrapped as well. Irqs
+	  are already protected inside rcu_irq_enter/rcu_irq_exit() but
+	  preemption or signal handling on irq exit still need to be protected.
+
+config HAVE_VIRT_CPU_ACCOUNTING
+	bool
+
+config HAVE_IRQ_TIME_ACCOUNTING
+	bool
+	help
+	  Archs need to ensure they use a high enough resolution clock to
+	  support irq time accounting and then call enable_sched_clock_irqtime().
+
 source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 9816d5a..ef757147 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -256,12 +256,6 @@
 	}
 }
 
-void __init
-pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 int
 pcibios_enable_device(struct pci_dev *dev, int mask)
 {
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index d6fde98..83638aa 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #include <asm/reg.h>
 #include <asm/uaccess.h>
@@ -54,9 +55,12 @@
 		/* FIXME -- EV6 and LCA45 know how to power down
 		   the CPU.  */
 
+		rcu_idle_enter();
 		while (!need_resched())
 			cpu_relax();
-		schedule();
+
+		rcu_idle_exit();
+		schedule_preempt_disabled();
 	}
 }
 
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 35ddc02..a41ad90 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -166,6 +166,7 @@
 	DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n",
 	      cpuid, current, current->active_mm));
 
+	preempt_disable();
 	/* Do nothing.  */
 	cpu_idle();
 }
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1fd9bcd..7362c92 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -279,7 +279,6 @@
 	select GENERIC_CLOCKEVENTS
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_FPGA_IRQ
-	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
@@ -311,7 +310,6 @@
 	select ICST
 	select GENERIC_CLOCKEVENTS
 	select ARCH_WANT_OPTIONAL_GPIOLIB
-	select NEED_MACH_IO_H if PCI
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_CLOCK
 	select PLAT_VERSATILE_CLCD
@@ -349,6 +347,23 @@
 	  This enables support for systems based on Atmel
 	  AT91RM9200 and AT91SAM9* processors.
 
+config ARCH_BCM2835
+	bool "Broadcom BCM2835 family"
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select ARM_AMBA
+	select ARM_ERRATA_411920
+	select ARM_TIMER_SP804
+	select CLKDEV_LOOKUP
+	select COMMON_CLK
+	select CPU_V6
+	select GENERIC_CLOCKEVENTS
+	select MULTI_IRQ_HANDLER
+	select SPARSE_IRQ
+	select USE_OF
+	help
+	  This enables support for the Broadcom BCM2835 SoC. This SoC is
+	  use in the Raspberry Pi, and Roku 2 devices.
+
 config ARCH_BCMRING
 	bool "Broadcom BCMRING"
 	depends on MMU
@@ -406,9 +421,8 @@
 	help
 	  Support for the Cortina Systems Gemini family SoCs
 
-config ARCH_PRIMA2
-	bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
-	select CPU_V7
+config ARCH_SIRF
+	bool "CSR SiRF"
 	select NO_IOPORT
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
@@ -418,9 +432,8 @@
 	select PINCTRL
 	select PINCTRL_SIRF
 	select USE_OF
-	select ZONE_DMA
 	help
-          Support for CSR SiRFSoC ARM Cortex A9 Platform
+	  Support for CSR SiRFprimaII/Marco/Polo platforms
 
 config ARCH_EBSA110
 	bool "EBSA-110"
@@ -455,7 +468,7 @@
 	select FOOTBRIDGE
 	select GENERIC_CLOCKEVENTS
 	select HAVE_IDE
-	select NEED_MACH_IO_H
+	select NEED_MACH_IO_H if !MMU
 	select NEED_MACH_MEMORY_H
 	help
 	  Support for systems based on the DC21285 companion chip
@@ -512,7 +525,6 @@
 	select PCI
 	select ARCH_SUPPORTS_MSI
 	select VMSPLIT_1G
-	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	select NEED_RET_TO_USER
 	help
@@ -522,7 +534,6 @@
 	bool "IOP32x-based"
 	depends on MMU
 	select CPU_XSCALE
-	select NEED_MACH_IO_H
 	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
@@ -535,7 +546,6 @@
 	bool "IOP33x-based"
 	depends on MMU
 	select CPU_XSCALE
-	select NEED_MACH_IO_H
 	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
@@ -575,7 +585,6 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the Marvell Dove SoC 88AP510
@@ -586,7 +595,6 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell Kirkwood series SoCs:
@@ -613,7 +621,6 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell MV78xx0 series SoCs:
@@ -626,7 +633,6 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell Orion 5x series SoCs:
@@ -651,8 +657,9 @@
 	bool "Micrel/Kendin KS8695"
 	select CPU_ARM922T
 	select ARCH_REQUIRE_GPIOLIB
-	select ARCH_USES_GETTIMEOFFSET
 	select NEED_MACH_MEMORY_H
+	select CLKSRC_MMIO
+	select GENERIC_CLOCKEVENTS
 	help
 	  Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
 	  System-on-Chip devices.
@@ -682,9 +689,9 @@
 	select HAVE_CLK
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
-	select NEED_MACH_IO_H if PCI
 	select ARCH_HAS_CPUFREQ
 	select USE_OF
+	select COMMON_CLK
 	help
 	  This enables support for NVIDIA Tegra based systems (Tegra APX,
 	  Tegra 6xx and Tegra 2 series).
@@ -708,14 +715,6 @@
 	  family of Femtocell devices.  The picoxcell support requires device tree
 	  for all boards.
 
-config ARCH_PNX4008
-	bool "Philips Nexperia PNX4008 Mobile"
-	select CPU_ARM926T
-	select CLKDEV_LOOKUP
-	select ARCH_USES_GETTIMEOFFSET
-	help
-	  This enables support for Philips PNX4008 mobile platform.
-
 config ARCH_PXA
 	bool "PXA2xx/PXA3xx-based"
 	depends on MMU
@@ -911,7 +910,6 @@
 	select PCI
 	select ARCH_USES_GETTIMEOFFSET
 	select NEED_MACH_MEMORY_H
-	select NEED_MACH_IO_H
 	help
 	  Support for the StrongARM based Digital DNARD machine, also known
 	  as "Shark" (<http://www.shark-linux.de/shark.html>).
@@ -930,6 +928,7 @@
 	select COMMON_CLK
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
+	select SPARSE_IRQ
 	help
 	  Support for ST-Ericsson U300 series mobile platforms.
 
@@ -1121,6 +1120,8 @@
 
 source "arch/arm/mach-shmobile/Kconfig"
 
+source "arch/arm/mach-prima2/Kconfig"
+
 source "arch/arm/mach-tegra/Kconfig"
 
 source "arch/arm/mach-u300/Kconfig"
@@ -1180,12 +1181,6 @@
 	depends on CPU_XSCALE
 	default y
 
-config CPU_HAS_PMU
-	depends on (CPU_V6 || CPU_V6K || CPU_V7 || XSCALE_PMU) && \
-		   (!ARCH_OMAP3 || OMAP3_EMU)
-	default y
-	bool
-
 config MULTI_IRQ_HANDLER
 	bool
 	help
@@ -1759,7 +1754,7 @@
 
 config HW_PERF_EVENTS
 	bool "Enable hardware performance counter support for perf events"
-	depends on PERF_EVENTS && CPU_HAS_PMU
+	depends on PERF_EVENTS
 	default y
 	help
 	  Enable hardware performance counter support for perf events. If
@@ -2315,7 +2310,7 @@
 source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
-	depends on !ARCH_S5PC100 && !ARCH_TEGRA
+	depends on !ARCH_S5PC100
 	depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
 		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
 	def_bool y
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a051dfb..f476182 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -136,6 +136,7 @@
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
 machine-$(CONFIG_ARCH_AT91)		:= at91
+machine-$(CONFIG_ARCH_BCM2835)		:= bcm2835
 machine-$(CONFIG_ARCH_BCMRING)		:= bcmring
 machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
 machine-$(CONFIG_ARCH_CNS3XXX)		:= cns3xxx
@@ -167,7 +168,6 @@
 machine-$(CONFIG_ARCH_OMAP2PLUS)	:= omap2
 machine-$(CONFIG_ARCH_ORION5X)		:= orion5x
 machine-$(CONFIG_ARCH_PICOXCELL)	:= picoxcell
-machine-$(CONFIG_ARCH_PNX4008)		:= pnx4008
 machine-$(CONFIG_ARCH_PRIMA2)		:= prima2
 machine-$(CONFIG_ARCH_PXA)		:= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		:= realview
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 81769c1..bc67cbf 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -653,6 +653,7 @@
 		mcrne	p15, 0, r0, c8, c7, 0	@ flush I,D TLBs
 #endif
 		mrc	p15, 0, r0, c1, c0, 0	@ read control reg
+		bic	r0, r0, #1 << 28	@ clear SCTLR.TRE
 		orr	r0, r0, #0x5000		@ I-cache enable, RR cache replacement
 		orr	r0, r0, #0x003c		@ write buffer
 #ifdef CONFIG_MMU
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index 66389c1..7c95f76 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -104,6 +104,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioB: gpio@fffff600 {
@@ -113,6 +114,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioC: gpio@fffff800 {
@@ -122,6 +124,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			dbgu: serial@fffff200 {
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index b460d6c..195019b 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -95,6 +95,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioB: gpio@fffff400 {
@@ -104,6 +105,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioC: gpio@fffff600 {
@@ -113,6 +115,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioD: gpio@fffff800 {
@@ -122,6 +125,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioE: gpio@fffffa00 {
@@ -131,6 +135,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			dbgu: serial@ffffee00 {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index bafa880..63751b1 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -113,6 +113,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioB: gpio@fffff400 {
@@ -122,6 +123,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioC: gpio@fffff600 {
@@ -131,6 +133,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioD: gpio@fffff800 {
@@ -140,6 +143,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioE: gpio@fffffa00 {
@@ -149,6 +153,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			dbgu: serial@ffffee00 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index bfac0df..ef9336a 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -107,6 +107,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioB: gpio@fffff600 {
@@ -116,6 +117,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioC: gpio@fffff800 {
@@ -125,6 +127,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioD: gpio@fffffa00 {
@@ -134,6 +137,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			dbgu: serial@fffff200 {
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 4a18c39..8a387a8 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -115,6 +115,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioB: gpio@fffff600 {
@@ -124,6 +125,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioC: gpio@fffff800 {
@@ -133,6 +135,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			pioD: gpio@fffffa00 {
@@ -142,6 +145,7 @@
 				#gpio-cells = <2>;
 				gpio-controller;
 				interrupt-controller;
+				#interrupt-cells = <2>;
 			};
 
 			dbgu: serial@fffff200 {
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
new file mode 100644
index 0000000..7dd860f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+/memreserve/ 0x0c000000 0x04000000;
+/include/ "bcm2835.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-b", "brcm,bcm2835";
+	model = "Raspberry Pi Model B";
+
+	memory {
+		reg = <0 0x10000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
new file mode 100644
index 0000000..0b61939
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -0,0 +1,39 @@
+/include/ "skeleton.dtsi"
+
+/ {
+	compatible = "brcm,bcm2835";
+	model = "BCM2835";
+	interrupt-parent = <&intc>;
+
+	chosen {
+		bootargs = "earlyprintk console=ttyAMA0";
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x7e000000 0x20000000 0x02000000>;
+
+		timer {
+			compatible = "brcm,bcm2835-system-timer";
+			reg = <0x7e003000 0x1000>;
+			interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+			clock-frequency = <1000000>;
+		};
+
+		intc: interrupt-controller {
+			compatible = "brcm,bcm2835-armctrl-ic";
+			reg = <0x7e00b200 0x200>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		uart@20201000 {
+			compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+			reg = <0x7e201000 0x1000>;
+			interrupts = <2 25>;
+			clock-frequency = <3000000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx27-phytec-phycore.dts b/arch/arm/boot/dts/imx27-phytec-phycore.dts
index 777caa3..af50469 100644
--- a/arch/arm/boot/dts/imx27-phytec-phycore.dts
+++ b/arch/arm/boot/dts/imx27-phytec-phycore.dts
@@ -45,7 +45,7 @@
 			i2c@1001d000 {
 				clock-frequency = <400000>;
 				status = "okay";
-				at24@4c {
+				at24@52 {
 					compatible = "at,24c32";
 					pagesize = <32>;
 					reg = <0x52>;
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index f146dbf6..c3ef1ad 100644
--- a/arch/arm/boot/dts/tegra20-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -275,6 +275,160 @@
 	i2c@7000d000 {
 		status = "okay";
 		clock-frequency = <400000>;
+
+		pmic: tps6586x@34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 86 0x4>;
+
+			ti,system-power-controller;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			sys-supply = <&vdd_5v0_reg>;
+			vin-sm0-supply = <&sys_reg>;
+			vin-sm1-supply = <&sys_reg>;
+			vin-sm2-supply = <&sys_reg>;
+			vinldo01-supply = <&sm2_reg>;
+			vinldo23-supply = <&sm2_reg>;
+			vinldo4-supply = <&sm2_reg>;
+			vinldo678-supply = <&sm2_reg>;
+			vinldo9-supply = <&sm2_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sys_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "sys";
+					regulator-name = "vdd_sys";
+					regulator-always-on;
+				};
+
+				regulator@1 {
+					reg = <1>;
+					regulator-compatible = "sm0";
+					regulator-name = "vdd_sm0,vdd_core";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				regulator@2 {
+					reg = <2>;
+					regulator-compatible = "sm1";
+					regulator-name = "vdd_sm1,vdd_cpu";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				sm2_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "sm2";
+					regulator-name = "vdd_sm2,vin_ldo*";
+					regulator-min-microvolt = <3700000>;
+					regulator-max-microvolt = <3700000>;
+					regulator-always-on;
+				};
+
+				regulator@4 {
+					reg = <4>;
+					regulator-compatible = "ldo0";
+					regulator-name = "vdd_ldo0,vddio_pex_clk";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo1";
+					regulator-name = "vdd_ldo1,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator@6 {
+					reg = <6>;
+					regulator-compatible = "ldo2";
+					regulator-name = "vdd_ldo2,vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo3";
+					regulator-name = "vdd_ldo3,avdd_usb*";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo4";
+					regulator-name = "vdd_ldo4,avdd_osc,vddio_sys";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo5";
+					regulator-name = "vdd_ldo5,vcore_mmc";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo6";
+					regulator-name = "vdd_ldo6,avdd_vdac";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo7";
+					regulator-name = "vdd_ldo7,avdd_hdmi";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@12 {
+					reg = <12>;
+					regulator-compatible = "ldo8";
+					regulator-name = "vdd_ldo8,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@13 {
+					reg = <13>;
+					regulator-compatible = "ldo9";
+					regulator-name = "vdd_ldo9,avdd_2v85,vdd_ddr_rx";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@14 {
+					reg = <14>;
+					regulator-compatible = "ldo_rtc";
+					regulator-name = "vdd_rtc_out,vdd_cell";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+			};
+		};
 	};
 
 	pmc {
@@ -310,6 +464,72 @@
 		bus-width = <8>;
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdd_5v0_reg: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "vdd_5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+
+		regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "vdd_1v5";
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <1500000>;
+			gpio = <&pmic 0 0>;
+		};
+
+		regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "vdd_1v2";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			gpio = <&pmic 1 0>;
+			enable-active-high;
+		};
+
+		regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "vdd_1v05";
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			gpio = <&pmic 2 0>;
+			enable-active-high;
+			/* Hack until board-harmony-pcie.c is removed */
+			status = "disabled";
+		};
+
+		regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "vdd_pnl";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			gpio = <&gpio 22 0>; /* gpio PC6 */
+			enable-active-high;
+		};
+
+		regulator@5 {
+			compatible = "regulator-fixed";
+			reg = <5>;
+			regulator-name = "vdd_bl";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			gpio = <&gpio 176 0>; /* gpio PW0 */
+			enable-active-high;
+		};
+	};
+
 	sound {
 		compatible = "nvidia,tegra-audio-wm8903-harmony",
 			     "nvidia,tegra-audio-wm8903";
diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig
new file mode 100644
index 0000000..7aea702
--- /dev/null
+++ b/arch/arm/configs/bcm2835_defconfig
@@ -0,0 +1,95 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_FHANDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_JUMP_LABEL=y
+# CONFIG_BLOCK is not set
+CONFIG_ARCH_BCM2835=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_AEABI=y
+CONFIG_COMPACTION=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_CLEANCACHE=y
+CONFIG_SECCOMP=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_TTY_PRINTK=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_SCHED_TRACER=y
+CONFIG_STACK_TRACER=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_TEST_KSTRTOX=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/arm/configs/kzm9d_defconfig b/arch/arm/configs/kzm9d_defconfig
index 26146ff..8c49df6 100644
--- a/arch/arm/configs/kzm9d_defconfig
+++ b/arch/arm/configs/kzm9d_defconfig
@@ -8,6 +8,7 @@
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 CONFIG_SLAB=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
index 2388c86..5d0c6670 100644
--- a/arch/arm/configs/kzm9g_defconfig
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -14,6 +14,7 @@
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
diff --git a/arch/arm/configs/pnx4008_defconfig b/arch/arm/configs/pnx4008_defconfig
deleted file mode 100644
index 35a31cc..0000000
--- a/arch/arm/configs/pnx4008_defconfig
+++ /dev/null
@@ -1,472 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_ARCH_PNX4008=y
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200"
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_AOUT=m
-CONFIG_BINFMT_MISC=m
-CONFIG_PM=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_IPV6_PRIVACY=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_NETFILTER=y
-CONFIG_IP_VS=m
-CONFIG_IP_VS_PROTO_TCP=y
-CONFIG_IP_VS_PROTO_UDP=y
-CONFIG_IP_VS_PROTO_ESP=y
-CONFIG_IP_VS_PROTO_AH=y
-CONFIG_IP_VS_RR=m
-CONFIG_IP_VS_WRR=m
-CONFIG_IP_VS_LC=m
-CONFIG_IP_VS_WLC=m
-CONFIG_IP_VS_LBLC=m
-CONFIG_IP_VS_LBLCR=m
-CONFIG_IP_VS_DH=m
-CONFIG_IP_VS_SH=m
-CONFIG_IP_VS_SED=m
-CONFIG_IP_VS_NQ=m
-CONFIG_IP_VS_FTP=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_DECNET_NF_GRABULATOR=m
-CONFIG_BRIDGE_NF_EBTABLES=m
-CONFIG_BRIDGE_EBT_BROUTE=m
-CONFIG_BRIDGE_EBT_T_FILTER=m
-CONFIG_BRIDGE_EBT_T_NAT=m
-CONFIG_BRIDGE_EBT_802_3=m
-CONFIG_BRIDGE_EBT_AMONG=m
-CONFIG_BRIDGE_EBT_ARP=m
-CONFIG_BRIDGE_EBT_IP=m
-CONFIG_BRIDGE_EBT_LIMIT=m
-CONFIG_BRIDGE_EBT_MARK=m
-CONFIG_BRIDGE_EBT_PKTTYPE=m
-CONFIG_BRIDGE_EBT_STP=m
-CONFIG_BRIDGE_EBT_VLAN=m
-CONFIG_BRIDGE_EBT_ARPREPLY=m
-CONFIG_BRIDGE_EBT_DNAT=m
-CONFIG_BRIDGE_EBT_MARK_T=m
-CONFIG_BRIDGE_EBT_REDIRECT=m
-CONFIG_BRIDGE_EBT_SNAT=m
-CONFIG_BRIDGE_EBT_LOG=m
-CONFIG_IP_SCTP=m
-CONFIG_ATM=y
-CONFIG_ATM_CLIP=y
-CONFIG_ATM_LANE=m
-CONFIG_ATM_MPOA=m
-CONFIG_ATM_BR2684=m
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
-CONFIG_LLC2=m
-CONFIG_IPX=m
-CONFIG_ATALK=m
-CONFIG_DEV_APPLETALK=m
-CONFIG_IPDDP=m
-CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
-CONFIG_X25=m
-CONFIG_LAPB=m
-CONFIG_ECONET=m
-CONFIG_ECONET_AUNUDP=y
-CONFIG_ECONET_NATIVE=y
-CONFIG_WAN_ROUTER=m
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_HTB=m
-CONFIG_NET_SCH_HFSC=m
-CONFIG_NET_SCH_ATM=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_NETEM=m
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_NET_PKTGEN=m
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_SLRAM=m
-CONFIG_MTD_PHRAM=m
-CONFIG_MTD_MTDRAM=m
-CONFIG_MTD_DOC2000=m
-CONFIG_MTD_DOC2001=m
-CONFIG_MTD_DOC2001PLUS=m
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_NANDSIM=m
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_EEPROM_LEGACY=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_CHR_DEV_SG=m
-CONFIG_CHR_DEV_SCH=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SPI_ATTRS=m
-CONFIG_SCSI_FC_ATTRS=m
-CONFIG_SCSI_DEBUG=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-# CONFIG_USB_NET_CDC_SUBSET is not set
-CONFIG_WAN=y
-CONFIG_HDLC=m
-CONFIG_HDLC_RAW=m
-CONFIG_HDLC_RAW_ETH=m
-CONFIG_HDLC_CISCO=m
-CONFIG_HDLC_FR=m
-CONFIG_HDLC_PPP=m
-CONFIG_HDLC_X25=m
-CONFIG_DLCI=m
-CONFIG_WAN_ROUTER_DRIVERS=m
-CONFIG_LAPBETHER=m
-CONFIG_X25_ASY=m
-CONFIG_ATM_TCP=m
-CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
-CONFIG_PPPOE=m
-CONFIG_PPPOATM=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_NETCONSOLE=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_JOYDEV=m
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_EVBUG=m
-CONFIG_KEYBOARD_LKKBD=m
-CONFIG_KEYBOARD_NEWTON=m
-CONFIG_KEYBOARD_SUNKBD=m
-CONFIG_KEYBOARD_XTKBD=m
-CONFIG_MOUSE_PS2=m
-CONFIG_MOUSE_SERIAL=m
-CONFIG_MOUSE_VSXXXAA=m
-CONFIG_INPUT_JOYSTICK=y
-CONFIG_JOYSTICK_ANALOG=m
-CONFIG_JOYSTICK_A3D=m
-CONFIG_JOYSTICK_ADI=m
-CONFIG_JOYSTICK_COBRA=m
-CONFIG_JOYSTICK_GF2K=m
-CONFIG_JOYSTICK_GRIP=m
-CONFIG_JOYSTICK_GRIP_MP=m
-CONFIG_JOYSTICK_GUILLEMOT=m
-CONFIG_JOYSTICK_INTERACT=m
-CONFIG_JOYSTICK_SIDEWINDER=m
-CONFIG_JOYSTICK_TMDC=m
-CONFIG_JOYSTICK_IFORCE=m
-CONFIG_JOYSTICK_IFORCE_USB=y
-CONFIG_JOYSTICK_IFORCE_232=y
-CONFIG_JOYSTICK_WARRIOR=m
-CONFIG_JOYSTICK_MAGELLAN=m
-CONFIG_JOYSTICK_SPACEORB=m
-CONFIG_JOYSTICK_SPACEBALL=m
-CONFIG_JOYSTICK_STINGER=m
-CONFIG_JOYSTICK_JOYDUMP=m
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_GUNZE=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=m
-CONFIG_SERIO_SERPORT=m
-CONFIG_SERIO_RAW=m
-CONFIG_GAMEPORT_NS558=m
-CONFIG_GAMEPORT_L4=m
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_SOFT_WATCHDOG=m
-CONFIG_USBPCWATCHDOG=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_MTPAV=m
-CONFIG_SND_SERIAL_U16550=m
-CONFIG_SND_MPU401=m
-CONFIG_SND_USB_AUDIO=m
-CONFIG_SOUND_PRIME=m
-CONFIG_USB_HID=m
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_SL811_HCD=m
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DATAFAB=m
-CONFIG_USB_STORAGE_FREECOM=m
-CONFIG_USB_STORAGE_USBAT=m
-CONFIG_USB_STORAGE_SDDR09=m
-CONFIG_USB_STORAGE_SDDR55=m
-CONFIG_USB_STORAGE_JUMPSHOT=m
-CONFIG_USB_MDC800=m
-CONFIG_USB_MICROTEK=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_BELKIN=m
-CONFIG_USB_SERIAL_WHITEHEAT=m
-CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-CONFIG_USB_SERIAL_CYPRESS_M8=m
-CONFIG_USB_SERIAL_EMPEG=m
-CONFIG_USB_SERIAL_FTDI_SIO=m
-CONFIG_USB_SERIAL_VISOR=m
-CONFIG_USB_SERIAL_IPAQ=m
-CONFIG_USB_SERIAL_IR=m
-CONFIG_USB_SERIAL_EDGEPORT=m
-CONFIG_USB_SERIAL_EDGEPORT_TI=m
-CONFIG_USB_SERIAL_IPW=m
-CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-CONFIG_USB_SERIAL_KEYSPAN=m
-CONFIG_USB_SERIAL_KLSI=m
-CONFIG_USB_SERIAL_KOBIL_SCT=m
-CONFIG_USB_SERIAL_MCT_U232=m
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_SERIAL_SAFE=m
-CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
-CONFIG_USB_SERIAL_OMNINET=m
-CONFIG_USB_RIO500=m
-CONFIG_USB_LEGOTOWER=m
-CONFIG_USB_LCD=m
-CONFIG_USB_LED=m
-CONFIG_USB_CYTHERM=m
-CONFIG_USB_TEST=m
-CONFIG_USB_ATM=m
-CONFIG_USB_SPEEDTOUCH=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_GADGET_DUMMY_HCD=y
-CONFIG_USB_ZERO=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_MMC=m
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=m
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_REISERFS_FS=m
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_JFS_FS=m
-CONFIG_JFS_POSIX_ACL=y
-CONFIG_JFS_STATISTICS=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_XFS_RT=y
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V1=m
-CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_TMPFS=y
-CONFIG_ADFS_FS=m
-CONFIG_AFFS_FS=m
-CONFIG_HFS_FS=m
-CONFIG_HFSPLUS_FS=m
-CONFIG_BEFS_FS=m
-CONFIG_BFS_FS=m
-CONFIG_EFS_FS=m
-CONFIG_JFFS2_FS=m
-CONFIG_CRAMFS=y
-CONFIG_VXFS_FS=m
-CONFIG_MINIX_FS=m
-CONFIG_HPFS_FS=m
-CONFIG_QNX4FS_FS=m
-CONFIG_ROMFS_FS=m
-CONFIG_SYSV_FS=m
-CONFIG_UFS_FS=m
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_SMB_FS=m
-CONFIG_CIFS=m
-CONFIG_NCP_FS=m
-CONFIG_NCPFS_PACKET_SIGNING=y
-CONFIG_NCPFS_IOCTL_LOCKING=y
-CONFIG_NCPFS_STRONG=y
-CONFIG_NCPFS_NFS_NS=y
-CONFIG_NCPFS_OS2_NS=y
-CONFIG_NCPFS_NLS=y
-CONFIG_NCPFS_EXTRAS=y
-CONFIG_CODA_FS=m
-CONFIG_AFS_FS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ICS=y
-CONFIG_ACORN_PARTITION_RISCIX=y
-CONFIG_OSF_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-CONFIG_ATARI_PARTITION=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_LDM_PARTITION=y
-CONFIG_SGI_PARTITION=y
-CONFIG_ULTRIX_PARTITION=y
-CONFIG_SUN_PARTITION=y
-CONFIG_NLS_DEFAULT="cp437"
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_SECURITY=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRC16=m
diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig
index c328ac6..807d4e2 100644
--- a/arch/arm/configs/prima2_defconfig
+++ b/arch/arm/configs/prima2_defconfig
@@ -1,4 +1,6 @@
 CONFIG_EXPERIMENTAL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
@@ -8,9 +10,7 @@
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_ARCH_PRIMA2=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
+CONFIG_ARCH_SIRF=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_KEXEC=y
@@ -36,7 +36,6 @@
 CONFIG_SPI_SIRF=y
 CONFIG_SPI_SPIDEV=y
 # CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_MASS_STORAGE=m
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index db22453..0d6bb738 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -145,6 +145,8 @@
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_EM3027=y
 CONFIG_RTC_DRV_TEGRA=y
+CONFIG_DMADEVICES=y
+CONFIG_TEGRA20_APB_DMA=y
 CONFIG_STAGING=y
 CONFIG_SENSORS_ISL29018=y
 CONFIG_SENSORS_ISL29028=y
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index 2ff2c75..02fe2fb 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -217,18 +217,8 @@
 #define IOP3XX_PCI_LOWER_MEM_PA	0x80000000
 #define IOP3XX_PCI_MEM_WINDOW_SIZE	0x08000000
 
-#define IOP3XX_PCI_IO_WINDOW_SIZE	0x00010000
 #define IOP3XX_PCI_LOWER_IO_PA		0x90000000
-#define IOP3XX_PCI_LOWER_IO_VA		0xfe000000
-#define IOP3XX_PCI_LOWER_IO_BA		0x90000000
-#define IOP3XX_PCI_UPPER_IO_PA		(IOP3XX_PCI_LOWER_IO_PA +\
-					IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_UPPER_IO_VA		(IOP3XX_PCI_LOWER_IO_VA +\
-					IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_IO_PHYS_TO_VIRT(addr) (((u32) (addr) -\
-					IOP3XX_PCI_LOWER_IO_PA) +\
-					IOP3XX_PCI_LOWER_IO_VA)
-
+#define IOP3XX_PCI_LOWER_IO_BA		0x00000000
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 815c669..8f4db67 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -113,11 +113,19 @@
 #define __iowmb()		do { } while (0)
 #endif
 
+/* PCI fixed i/o mapping */
+#define PCI_IO_VIRT_BASE	0xfee00000
+
+extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
 #ifdef CONFIG_NEED_MACH_IO_H
 #include <mach/io.h>
+#elif defined(CONFIG_PCI)
+#define IO_SPACE_LIMIT	((resource_size_t)0xfffff)
+#define __io(a)		__typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
 #else
 #define __io(a)		__typesafe_io((a) & IO_SPACE_LIMIT)
 #endif
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index a6efcdd..195ac2f 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -9,6 +9,9 @@
  *
  *  Page table mapping constructs and function prototypes
  */
+#ifndef __ASM_MACH_MAP_H
+#define __ASM_MACH_MAP_H
+
 #include <asm/io.h>
 
 struct map_desc {
@@ -34,6 +37,8 @@
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
+				  void *caller);
 
 struct mem_type;
 extern const struct mem_type *get_mem_type(unsigned int type);
@@ -44,4 +49,7 @@
 			const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)	do { } while (0)
+#define vm_reserve_area_early(a,s,c)	do { } while (0)
+#endif
+
 #endif
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index 26c511fd..db9fedb 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -11,6 +11,8 @@
 #ifndef __ASM_MACH_PCI_H
 #define __ASM_MACH_PCI_H
 
+#include <linux/ioport.h>
+
 struct pci_sys_data;
 struct pci_ops;
 struct pci_bus;
@@ -42,6 +44,8 @@
 	unsigned long	io_offset;	/* bus->cpu IO mapping offset		*/
 	struct pci_bus	*bus;		/* PCI bus				*/
 	struct list_head resources;	/* root bus resources (apertures)       */
+	struct resource io_res;
+	char		io_res_name[12];
 					/* Bridge swizzling			*/
 	u8		(*swizzle)(struct pci_dev *, u8 *);
 					/* IRQ mapping				*/
@@ -55,6 +59,15 @@
 void pci_common_init(struct hw_pci *);
 
 /*
+ * Setup early fixed I/O mapping.
+ */
+#if defined(CONFIG_PCI)
+extern void pci_map_io_early(unsigned long pfn);
+#else
+static inline void pci_map_io_early(unsigned long pfn) {}
+#endif
+
+/*
  * PCI controllers
  */
 extern struct pci_ops iop3xx_ops;
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index e074948..625cd62 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -12,6 +12,13 @@
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/* Nothing to see here... */
+/*
+ * The ARMv7 CPU PMU supports up to 32 event counters.
+ */
+#define ARMPMU_MAX_HWEVENTS		32
+
+#define HW_OP_UNSUPPORTED		0xFFFF
+#define C(_x)				PERF_COUNT_HW_CACHE_##_x
+#define CACHE_OP_UNSUPPORTED		0xFFFF
 
 #endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 4432305..a26170d 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -16,69 +16,30 @@
 #include <linux/perf_event.h>
 
 /*
- * Types of PMUs that can be accessed directly and require mutual
- * exclusion between profiling tools.
- */
-enum arm_pmu_type {
-	ARM_PMU_DEVICE_CPU	= 0,
-	ARM_NUM_PMU_DEVICES,
-};
-
-/*
  * struct arm_pmu_platdata - ARM PMU platform data
  *
  * @handle_irq: an optional handler which will be called from the
  *	interrupt and passed the address of the low level handler,
  *	and can be used to implement any platform specific handling
  *	before or after calling it.
- * @enable_irq: an optional handler which will be called after
- *	request_irq and be used to handle some platform specific
- *	irq enablement
- * @disable_irq: an optional handler which will be called before
- *	free_irq and be used to handle some platform specific
- *	irq disablement
+ * @runtime_resume: an optional handler which will be called by the
+ *	runtime PM framework following a call to pm_runtime_get().
+ *	Note that if pm_runtime_get() is called more than once in
+ *	succession this handler will only be called once.
+ * @runtime_suspend: an optional handler which will be called by the
+ *	runtime PM framework following a call to pm_runtime_put().
+ *	Note that if pm_runtime_get() is called more than once in
+ *	succession this handler will only be called following the
+ *	final call to pm_runtime_put() that actually disables the
+ *	hardware.
  */
 struct arm_pmu_platdata {
 	irqreturn_t (*handle_irq)(int irq, void *dev,
 				  irq_handler_t pmu_handler);
-	void (*enable_irq)(int irq);
-	void (*disable_irq)(int irq);
+	int (*runtime_resume)(struct device *dev);
+	int (*runtime_suspend)(struct device *dev);
 };
 
-#ifdef CONFIG_CPU_HAS_PMU
-
-/**
- * reserve_pmu() - reserve the hardware performance counters
- *
- * Reserve the hardware performance counters in the system for exclusive use.
- * Returns 0 on success or -EBUSY if the lock is already held.
- */
-extern int
-reserve_pmu(enum arm_pmu_type type);
-
-/**
- * release_pmu() - Relinquish control of the performance counters
- *
- * Release the performance counters and allow someone else to use them.
- */
-extern void
-release_pmu(enum arm_pmu_type type);
-
-#else /* CONFIG_CPU_HAS_PMU */
-
-#include <linux/err.h>
-
-static inline int
-reserve_pmu(enum arm_pmu_type type)
-{
-	return -ENODEV;
-}
-
-static inline void
-release_pmu(enum arm_pmu_type type)	{ }
-
-#endif /* CONFIG_CPU_HAS_PMU */
-
 #ifdef CONFIG_HW_PERF_EVENTS
 
 /* The events for a given PMU register set. */
@@ -103,7 +64,6 @@
 
 struct arm_pmu {
 	struct pmu	pmu;
-	enum arm_pmu_type type;
 	cpumask_t	active_irqs;
 	char		*name;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
@@ -118,6 +78,8 @@
 	void		(*start)(void);
 	void		(*stop)(void);
 	void		(*reset)(void *);
+	int		(*request_irq)(irq_handler_t handler);
+	void		(*free_irq)(void);
 	int		(*map_event)(struct perf_event *event);
 	int		num_events;
 	atomic_t	active_events;
@@ -129,7 +91,9 @@
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+extern const struct dev_pm_ops armpmu_dev_pm_ops;
+
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type);
 
 u64 armpmu_event_update(struct perf_event *event,
 			struct hw_perf_event *hwc,
@@ -139,6 +103,13 @@
 			    struct hw_perf_event *hwc,
 			    int idx);
 
+int armpmu_map_event(struct perf_event *event,
+		     const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+		     const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
+						[PERF_COUNT_HW_CACHE_OP_MAX]
+						[PERF_COUNT_HW_CACHE_RESULT_MAX],
+		     u32 raw_event_mask);
+
 #endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 0cab47d..2fde5fd 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -404,6 +404,7 @@
 #define __NR_setns			(__NR_SYSCALL_BASE+375)
 #define __NR_process_vm_readv		(__NR_SYSCALL_BASE+376)
 #define __NR_process_vm_writev		(__NR_SYSCALL_BASE+377)
+					/* 378 for kcmp */
 
 /*
  * The following SWIs are ARM private.
@@ -483,6 +484,7 @@
  */
 #define __IGNORE_fadvise64_64
 #define __IGNORE_migrate_pages
+#define __IGNORE_kcmp
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_ARM_UNISTD_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 7ad2d5c..1c43214 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -69,8 +69,7 @@
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
 obj-$(CONFIG_CPU_PJ4)		+= pj4-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
-obj-$(CONFIG_CPU_HAS_PMU)	+= pmu.o
-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
+obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2b2f25e..9b72261 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/pci.h>
 
 static int debug_pci;
@@ -270,15 +271,6 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8152, pci_fixup_it8152);
 
-
-
-void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	if (debug_pci)
-		printk("PCI: Assigning IRQ %02d to %s\n", irq, pci_name(dev));
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 /*
  * If the bus contains any of these devices, then we must not turn on
  * parity checking of any kind.  Currently this is CyberPro 20x0 only.
@@ -423,6 +415,38 @@
 	return irq;
 }
 
+static int __init pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+{
+	int ret;
+	struct pci_host_bridge_window *window;
+
+	if (list_empty(&sys->resources)) {
+		pci_add_resource_offset(&sys->resources,
+			 &iomem_resource, sys->mem_offset);
+	}
+
+	list_for_each_entry(window, &sys->resources, list) {
+		if (resource_type(window->res) == IORESOURCE_IO)
+			return 0;
+	}
+
+	sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
+	sys->io_res.end = (busnr + 1) * SZ_64K - 1;
+	sys->io_res.flags = IORESOURCE_IO;
+	sys->io_res.name = sys->io_res_name;
+	sprintf(sys->io_res_name, "PCI%d I/O", busnr);
+
+	ret = request_resource(&ioport_resource, &sys->io_res);
+	if (ret) {
+		pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
+		return ret;
+	}
+	pci_add_resource_offset(&sys->resources, &sys->io_res,
+				sys->io_offset);
+
+	return 0;
+}
+
 static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 {
 	struct pci_sys_data *sys = NULL;
@@ -445,11 +469,10 @@
 		ret = hw->setup(nr, sys);
 
 		if (ret > 0) {
-			if (list_empty(&sys->resources)) {
-				pci_add_resource_offset(&sys->resources,
-					 &ioport_resource, sys->io_offset);
-				pci_add_resource_offset(&sys->resources,
-					 &iomem_resource, sys->mem_offset);
+			ret = pcibios_init_resources(nr, sys);
+			if (ret)  {
+				kfree(sys);
+				break;
 			}
 
 			if (hw->scan)
@@ -627,3 +650,15 @@
 
 	return 0;
 }
+
+void __init pci_map_io_early(unsigned long pfn)
+{
+	struct map_desc pci_io_desc = {
+		.virtual	= PCI_IO_VIRT_BASE,
+		.type		= MT_DEVICE,
+		.length		= SZ_64K,
+	};
+
+	pci_io_desc.pfn = pfn;
+	iotable_init(&pci_io_desc, 1);
+}
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 463ff4a..e337879 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -387,6 +387,7 @@
 /* 375 */	CALL(sys_setns)
 		CALL(sys_process_vm_readv)
 		CALL(sys_process_vm_writev)
+		CALL(sys_ni_syscall)	/* reserved for sys_kcmp */
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index ab243b8..93971b1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -12,68 +12,15 @@
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
-#include <linux/bitmap.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/perf_event.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 
-#include <asm/cputype.h>
-#include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
-/*
- * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
- * another platform that supports more, we need to increase this to be the
- * largest of all platforms.
- *
- * ARMv7 supports up to 32 events:
- *  cycle counter CCNT + 31 events counters CNT0..30.
- *  Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
- */
-#define ARMPMU_MAX_HWEVENTS		32
-
-static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
-static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
-static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
-
-#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-
-/* Set at runtime when we know what CPU type we are. */
-static struct arm_pmu *cpu_pmu;
-
-const char *perf_pmu_name(void)
-{
-	if (!cpu_pmu)
-		return NULL;
-
-	return cpu_pmu->pmu.name;
-}
-EXPORT_SYMBOL_GPL(perf_pmu_name);
-
-int perf_num_counters(void)
-{
-	int max_events = 0;
-
-	if (cpu_pmu != NULL)
-		max_events = cpu_pmu->num_events;
-
-	return max_events;
-}
-EXPORT_SYMBOL_GPL(perf_num_counters);
-
-#define HW_OP_UNSUPPORTED		0xFFFF
-
-#define C(_x) \
-	PERF_COUNT_HW_CACHE_##_x
-
-#define CACHE_OP_UNSUPPORTED		0xFFFF
-
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
 				      [PERF_COUNT_HW_CACHE_MAX]
@@ -104,7 +51,7 @@
 }
 
 static int
-armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
+armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
 	int mapping = (*event_map)[config];
 	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
@@ -116,19 +63,20 @@
 	return (int)(config & raw_event_mask);
 }
 
-static int map_cpu_event(struct perf_event *event,
-			 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
-			 const unsigned (*cache_map)
-					[PERF_COUNT_HW_CACHE_MAX]
-					[PERF_COUNT_HW_CACHE_OP_MAX]
-					[PERF_COUNT_HW_CACHE_RESULT_MAX],
-			 u32 raw_event_mask)
+int
+armpmu_map_event(struct perf_event *event,
+		 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+		 const unsigned (*cache_map)
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX],
+		 u32 raw_event_mask)
 {
 	u64 config = event->attr.config;
 
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
-		return armpmu_map_event(event_map, config);
+		return armpmu_map_hw_event(event_map, config);
 	case PERF_TYPE_HW_CACHE:
 		return armpmu_map_cache_event(cache_map, config);
 	case PERF_TYPE_RAW:
@@ -222,7 +170,6 @@
 	 */
 	if (!(hwc->state & PERF_HES_STOPPED)) {
 		armpmu->disable(hwc, hwc->idx);
-		barrier(); /* why? */
 		armpmu_event_update(event, hwc, hwc->idx);
 		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 	}
@@ -350,99 +297,41 @@
 	return 0;
 }
 
-static irqreturn_t armpmu_platform_irq(int irq, void *dev)
+static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
 {
 	struct arm_pmu *armpmu = (struct arm_pmu *) dev;
 	struct platform_device *plat_device = armpmu->plat_device;
 	struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
 
-	return plat->handle_irq(irq, dev, armpmu->handle_irq);
+	if (plat && plat->handle_irq)
+		return plat->handle_irq(irq, dev, armpmu->handle_irq);
+	else
+		return armpmu->handle_irq(irq, dev);
 }
 
 static void
 armpmu_release_hardware(struct arm_pmu *armpmu)
 {
-	int i, irq, irqs;
-	struct platform_device *pmu_device = armpmu->plat_device;
-	struct arm_pmu_platdata *plat =
-		dev_get_platdata(&pmu_device->dev);
-
-	irqs = min(pmu_device->num_resources, num_possible_cpus());
-
-	for (i = 0; i < irqs; ++i) {
-		if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
-			continue;
-		irq = platform_get_irq(pmu_device, i);
-		if (irq >= 0) {
-			if (plat && plat->disable_irq)
-				plat->disable_irq(irq);
-			free_irq(irq, armpmu);
-		}
-	}
-
-	release_pmu(armpmu->type);
+	armpmu->free_irq();
+	pm_runtime_put_sync(&armpmu->plat_device->dev);
 }
 
 static int
 armpmu_reserve_hardware(struct arm_pmu *armpmu)
 {
-	struct arm_pmu_platdata *plat;
-	irq_handler_t handle_irq;
-	int i, err, irq, irqs;
+	int err;
 	struct platform_device *pmu_device = armpmu->plat_device;
 
 	if (!pmu_device)
 		return -ENODEV;
 
-	err = reserve_pmu(armpmu->type);
+	pm_runtime_get_sync(&pmu_device->dev);
+	err = armpmu->request_irq(armpmu_dispatch_irq);
 	if (err) {
-		pr_warning("unable to reserve pmu\n");
+		armpmu_release_hardware(armpmu);
 		return err;
 	}
 
-	plat = dev_get_platdata(&pmu_device->dev);
-	if (plat && plat->handle_irq)
-		handle_irq = armpmu_platform_irq;
-	else
-		handle_irq = armpmu->handle_irq;
-
-	irqs = min(pmu_device->num_resources, num_possible_cpus());
-	if (irqs < 1) {
-		pr_err("no irqs for PMUs defined\n");
-		return -ENODEV;
-	}
-
-	for (i = 0; i < irqs; ++i) {
-		err = 0;
-		irq = platform_get_irq(pmu_device, i);
-		if (irq < 0)
-			continue;
-
-		/*
-		 * If we have a single PMU interrupt that we can't shift,
-		 * assume that we're running on a uniprocessor machine and
-		 * continue. Otherwise, continue without this interrupt.
-		 */
-		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
-			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
-				    irq, i);
-			continue;
-		}
-
-		err = request_irq(irq, handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "arm-pmu", armpmu);
-		if (err) {
-			pr_err("unable to request IRQ%d for ARM PMU counters\n",
-				irq);
-			armpmu_release_hardware(armpmu);
-			return err;
-		} else if (plat && plat->enable_irq)
-			plat->enable_irq(irq);
-
-		cpumask_set_cpu(i, &armpmu->active_irqs);
-	}
-
 	return 0;
 }
 
@@ -581,6 +470,32 @@
 	armpmu->stop();
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int armpmu_runtime_resume(struct device *dev)
+{
+	struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+	if (plat && plat->runtime_resume)
+		return plat->runtime_resume(dev);
+
+	return 0;
+}
+
+static int armpmu_runtime_suspend(struct device *dev)
+{
+	struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+	if (plat && plat->runtime_suspend)
+		return plat->runtime_suspend(dev);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops armpmu_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
+};
+
 static void __init armpmu_init(struct arm_pmu *armpmu)
 {
 	atomic_set(&armpmu->active_events, 0);
@@ -598,174 +513,14 @@
 	};
 }
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 {
 	armpmu_init(armpmu);
+	pr_info("enabled with %s PMU driver, %d counters available\n",
+			armpmu->name, armpmu->num_events);
 	return perf_pmu_register(&armpmu->pmu, name, type);
 }
 
-/* Include the PMU-specific implementations. */
-#include "perf_event_xscale.c"
-#include "perf_event_v6.c"
-#include "perf_event_v7.c"
-
-/*
- * Ensure the PMU has sane values out of reset.
- * This requires SMP to be available, so exists as a separate initcall.
- */
-static int __init
-cpu_pmu_reset(void)
-{
-	if (cpu_pmu && cpu_pmu->reset)
-		return on_each_cpu(cpu_pmu->reset, NULL, 1);
-	return 0;
-}
-arch_initcall(cpu_pmu_reset);
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static struct of_device_id armpmu_of_device_ids[] = {
-	{.compatible = "arm,cortex-a9-pmu"},
-	{.compatible = "arm,cortex-a8-pmu"},
-	{.compatible = "arm,arm1136-pmu"},
-	{.compatible = "arm,arm1176-pmu"},
-	{},
-};
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
-	{.name = "arm-pmu"},
-	{},
-};
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
-	if (!cpu_pmu)
-		return -ENODEV;
-
-	cpu_pmu->plat_device = pdev;
-	return 0;
-}
-
-static struct platform_driver armpmu_driver = {
-	.driver		= {
-		.name	= "arm-pmu",
-		.of_match_table = armpmu_of_device_ids,
-	},
-	.probe		= armpmu_device_probe,
-	.id_table	= armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
-	return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
-
-static struct pmu_hw_events *armpmu_get_cpu_events(void)
-{
-	return &__get_cpu_var(cpu_hw_events);
-}
-
-static void __init cpu_pmu_init(struct arm_pmu *armpmu)
-{
-	int cpu;
-	for_each_possible_cpu(cpu) {
-		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
-		events->events = per_cpu(hw_events, cpu);
-		events->used_mask = per_cpu(used_mask, cpu);
-		raw_spin_lock_init(&events->pmu_lock);
-	}
-	armpmu->get_hw_events = armpmu_get_cpu_events;
-	armpmu->type = ARM_PMU_DEVICE_CPU;
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
-					unsigned long action, void *hcpu)
-{
-	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
-		return NOTIFY_DONE;
-
-	if (cpu_pmu && cpu_pmu->reset)
-		cpu_pmu->reset(NULL);
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
-	.notifier_call = pmu_cpu_notify,
-};
-
-/*
- * CPU PMU identification and registration.
- */
-static int __init
-init_hw_perf_events(void)
-{
-	unsigned long cpuid = read_cpuid_id();
-	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
-	unsigned long part_number = (cpuid & 0xFFF0);
-
-	/* ARM Ltd CPUs. */
-	if (0x41 == implementor) {
-		switch (part_number) {
-		case 0xB360:	/* ARM1136 */
-		case 0xB560:	/* ARM1156 */
-		case 0xB760:	/* ARM1176 */
-			cpu_pmu = armv6pmu_init();
-			break;
-		case 0xB020:	/* ARM11mpcore */
-			cpu_pmu = armv6mpcore_pmu_init();
-			break;
-		case 0xC080:	/* Cortex-A8 */
-			cpu_pmu = armv7_a8_pmu_init();
-			break;
-		case 0xC090:	/* Cortex-A9 */
-			cpu_pmu = armv7_a9_pmu_init();
-			break;
-		case 0xC050:	/* Cortex-A5 */
-			cpu_pmu = armv7_a5_pmu_init();
-			break;
-		case 0xC0F0:	/* Cortex-A15 */
-			cpu_pmu = armv7_a15_pmu_init();
-			break;
-		case 0xC070:	/* Cortex-A7 */
-			cpu_pmu = armv7_a7_pmu_init();
-			break;
-		}
-	/* Intel CPUs [xscale]. */
-	} else if (0x69 == implementor) {
-		part_number = (cpuid >> 13) & 0x7;
-		switch (part_number) {
-		case 1:
-			cpu_pmu = xscale1pmu_init();
-			break;
-		case 2:
-			cpu_pmu = xscale2pmu_init();
-			break;
-		}
-	}
-
-	if (cpu_pmu) {
-		pr_info("enabled with %s PMU driver, %d counters available\n",
-			cpu_pmu->name, cpu_pmu->num_events);
-		cpu_pmu_init(cpu_pmu);
-		register_cpu_notifier(&pmu_cpu_notifier);
-		armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
-	} else {
-		pr_info("no hardware support available\n");
-	}
-
-	return 0;
-}
-early_initcall(init_hw_perf_events);
-
 /*
  * Callchain handling code.
  */
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
new file mode 100644
index 0000000..8d7d8d4
--- /dev/null
+++ b/arch/arm/kernel/perf_event_cpu.c
@@ -0,0 +1,295 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+#define pr_fmt(fmt) "CPU PMU: " fmt
+
+#include <linux/bitmap.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *cpu_pmu;
+
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
+
+/*
+ * Despite the names, these two functions are CPU-specific and are used
+ * by the OProfile/perf code.
+ */
+const char *perf_pmu_name(void)
+{
+	if (!cpu_pmu)
+		return NULL;
+
+	return cpu_pmu->pmu.name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+	int max_events = 0;
+
+	if (cpu_pmu != NULL)
+		max_events = cpu_pmu->num_events;
+
+	return max_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+/* Include the PMU-specific implementations. */
+#include "perf_event_xscale.c"
+#include "perf_event_v6.c"
+#include "perf_event_v7.c"
+
+static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
+{
+	return &__get_cpu_var(cpu_hw_events);
+}
+
+static void cpu_pmu_free_irq(void)
+{
+	int i, irq, irqs;
+	struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+	for (i = 0; i < irqs; ++i) {
+		if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
+			continue;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq >= 0)
+			free_irq(irq, cpu_pmu);
+	}
+}
+
+static int cpu_pmu_request_irq(irq_handler_t handler)
+{
+	int i, err, irq, irqs;
+	struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+	if (!pmu_device)
+		return -ENODEV;
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+	if (irqs < 1) {
+		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < irqs; ++i) {
+		err = 0;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq < 0)
+			continue;
+
+		/*
+		 * If we have a single PMU interrupt that we can't shift,
+		 * assume that we're running on a uniprocessor machine and
+		 * continue. Otherwise, continue without this interrupt.
+		 */
+		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+				    irq, i);
+			continue;
+		}
+
+		err = request_irq(irq, handler, IRQF_NOBALANCING, "arm-pmu",
+				  cpu_pmu);
+		if (err) {
+			pr_err("unable to request IRQ%d for ARM PMU counters\n",
+				irq);
+			return err;
+		}
+
+		cpumask_set_cpu(i, &cpu_pmu->active_irqs);
+	}
+
+	return 0;
+}
+
+static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
+{
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+		events->events = per_cpu(hw_events, cpu);
+		events->used_mask = per_cpu(used_mask, cpu);
+		raw_spin_lock_init(&events->pmu_lock);
+	}
+
+	cpu_pmu->get_hw_events	= cpu_pmu_get_cpu_events;
+	cpu_pmu->request_irq	= cpu_pmu_request_irq;
+	cpu_pmu->free_irq	= cpu_pmu_free_irq;
+
+	/* Ensure the PMU has sane values out of reset. */
+	if (cpu_pmu && cpu_pmu->reset)
+		on_each_cpu(cpu_pmu->reset, NULL, 1);
+}
+
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
+				    unsigned long action, void *hcpu)
+{
+	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+		return NOTIFY_DONE;
+
+	if (cpu_pmu && cpu_pmu->reset)
+		cpu_pmu->reset(NULL);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
+	.notifier_call = cpu_pmu_notify,
+};
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
+	{.compatible = "arm,cortex-a15-pmu",	.data = armv7_a15_pmu_init},
+	{.compatible = "arm,cortex-a9-pmu",	.data = armv7_a9_pmu_init},
+	{.compatible = "arm,cortex-a8-pmu",	.data = armv7_a8_pmu_init},
+	{.compatible = "arm,cortex-a7-pmu",	.data = armv7_a7_pmu_init},
+	{.compatible = "arm,cortex-a5-pmu",	.data = armv7_a5_pmu_init},
+	{.compatible = "arm,arm11mpcore-pmu",	.data = armv6mpcore_pmu_init},
+	{.compatible = "arm,arm1176-pmu",	.data = armv6pmu_init},
+	{.compatible = "arm,arm1136-pmu",	.data = armv6pmu_init},
+	{},
+};
+
+static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
+	{.name = "arm-pmu"},
+	{},
+};
+
+/*
+ * CPU PMU identification and probing.
+ */
+static struct arm_pmu *__devinit probe_current_pmu(void)
+{
+	struct arm_pmu *pmu = NULL;
+	int cpu = get_cpu();
+	unsigned long cpuid = read_cpuid_id();
+	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
+	unsigned long part_number = (cpuid & 0xFFF0);
+
+	pr_info("probing PMU on CPU %d\n", cpu);
+
+	/* ARM Ltd CPUs. */
+	if (0x41 == implementor) {
+		switch (part_number) {
+		case 0xB360:	/* ARM1136 */
+		case 0xB560:	/* ARM1156 */
+		case 0xB760:	/* ARM1176 */
+			pmu = armv6pmu_init();
+			break;
+		case 0xB020:	/* ARM11mpcore */
+			pmu = armv6mpcore_pmu_init();
+			break;
+		case 0xC080:	/* Cortex-A8 */
+			pmu = armv7_a8_pmu_init();
+			break;
+		case 0xC090:	/* Cortex-A9 */
+			pmu = armv7_a9_pmu_init();
+			break;
+		case 0xC050:	/* Cortex-A5 */
+			pmu = armv7_a5_pmu_init();
+			break;
+		case 0xC0F0:	/* Cortex-A15 */
+			pmu = armv7_a15_pmu_init();
+			break;
+		case 0xC070:	/* Cortex-A7 */
+			pmu = armv7_a7_pmu_init();
+			break;
+		}
+	/* Intel CPUs [xscale]. */
+	} else if (0x69 == implementor) {
+		part_number = (cpuid >> 13) & 0x7;
+		switch (part_number) {
+		case 1:
+			pmu = xscale1pmu_init();
+			break;
+		case 2:
+			pmu = xscale2pmu_init();
+			break;
+		}
+	}
+
+	put_cpu();
+	return pmu;
+}
+
+static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct arm_pmu *(*init_fn)(void);
+	struct device_node *node = pdev->dev.of_node;
+
+	if (cpu_pmu) {
+		pr_info("attempt to register multiple PMU devices!");
+		return -ENOSPC;
+	}
+
+	if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
+		init_fn = of_id->data;
+		cpu_pmu = init_fn();
+	} else {
+		cpu_pmu = probe_current_pmu();
+	}
+
+	if (!cpu_pmu)
+		return -ENODEV;
+
+	cpu_pmu->plat_device = pdev;
+	cpu_pmu_init(cpu_pmu);
+	register_cpu_notifier(&cpu_pmu_hotplug_notifier);
+	armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+
+	return 0;
+}
+
+static struct platform_driver cpu_pmu_driver = {
+	.driver		= {
+		.name	= "arm-pmu",
+		.pm	= &armpmu_dev_pm_ops,
+		.of_match_table = cpu_pmu_of_device_ids,
+	},
+	.probe		= cpu_pmu_device_probe,
+	.id_table	= cpu_pmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+	return platform_driver_register(&cpu_pmu_driver);
+}
+device_initcall(register_pmu_driver);
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index c90fcb2..6ccc079 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -645,7 +645,7 @@
 
 static int armv6_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv6_perf_map,
+	return armpmu_map_event(event, &armv6_perf_map,
 				&armv6_perf_cache_map, 0xFF);
 }
 
@@ -664,7 +664,7 @@
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return &armv6pmu;
 }
@@ -679,7 +679,7 @@
 
 static int armv6mpcore_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv6mpcore_perf_map,
+	return armpmu_map_event(event, &armv6mpcore_perf_map,
 				&armv6mpcore_perf_cache_map, 0xFF);
 }
 
@@ -698,17 +698,17 @@
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return &armv6mpcore_pmu;
 }
 #else
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f04070b..bd4b090 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1204,31 +1204,31 @@
 
 static int armv7_a8_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a8_perf_map,
+	return armpmu_map_event(event, &armv7_a8_perf_map,
 				&armv7_a8_perf_cache_map, 0xFF);
 }
 
 static int armv7_a9_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a9_perf_map,
+	return armpmu_map_event(event, &armv7_a9_perf_map,
 				&armv7_a9_perf_cache_map, 0xFF);
 }
 
 static int armv7_a5_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a5_perf_map,
+	return armpmu_map_event(event, &armv7_a5_perf_map,
 				&armv7_a5_perf_cache_map, 0xFF);
 }
 
 static int armv7_a15_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a15_perf_map,
+	return armpmu_map_event(event, &armv7_a15_perf_map,
 				&armv7_a15_perf_cache_map, 0xFF);
 }
 
 static int armv7_a7_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a7_perf_map,
+	return armpmu_map_event(event, &armv7_a7_perf_map,
 				&armv7_a7_perf_cache_map, 0xFF);
 }
 
@@ -1245,7 +1245,7 @@
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static u32 __init armv7_read_num_pmnc_events(void)
+static u32 __devinit armv7_read_num_pmnc_events(void)
 {
 	u32 nb_cnt;
 
@@ -1256,7 +1256,7 @@
 	return nb_cnt + 1;
 }
 
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A8";
 	armv7pmu.map_event	= armv7_a8_map_event;
@@ -1264,7 +1264,7 @@
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A9";
 	armv7pmu.map_event	= armv7_a9_map_event;
@@ -1272,7 +1272,7 @@
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A5";
 	armv7pmu.map_event	= armv7_a5_map_event;
@@ -1280,7 +1280,7 @@
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A15";
 	armv7pmu.map_event	= armv7_a15_map_event;
@@ -1289,7 +1289,7 @@
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A7";
 	armv7pmu.map_event	= armv7_a7_map_event;
@@ -1298,27 +1298,27 @@
 	return &armv7pmu;
 }
 #else
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index f759fe0..426e19f 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -430,7 +430,7 @@
 
 static int xscale_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &xscale_perf_map,
+	return armpmu_map_event(event, &xscale_perf_map,
 				&xscale_perf_cache_map, 0xFF);
 }
 
@@ -449,7 +449,7 @@
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return &xscale1pmu;
 }
@@ -816,17 +816,17 @@
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return &xscale2pmu;
 }
 #else
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
deleted file mode 100644
index 2334bf8..0000000
--- a/arch/arm/kernel/pmu.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  linux/arch/arm/kernel/pmu.c
- *
- *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
- *  Copyright (C) 2010 ARM Ltd, Will Deacon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <asm/pmu.h>
-
-/*
- * PMU locking to ensure mutual exclusion between different subsystems.
- */
-static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)];
-
-int
-reserve_pmu(enum arm_pmu_type type)
-{
-	return test_and_set_bit_lock(type, pmu_lock) ? -EBUSY : 0;
-}
-EXPORT_SYMBOL_GPL(reserve_pmu);
-
-void
-release_pmu(enum arm_pmu_type type)
-{
-	clear_bit_unlock(type, pmu_lock);
-}
-EXPORT_SYMBOL_GPL(release_pmu);
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index fef42b2..e1f9069 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/clk.h>
-#include <linux/cpufreq.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -96,7 +95,52 @@
 	disable_percpu_irq(clk->irq);
 }
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_COMMON_CLK
+
+/*
+ * Updates clockevent frequency when the cpu frequency changes.
+ * Called on the cpu that is changing frequency with interrupts disabled.
+ */
+static void twd_update_frequency(void *new_rate)
+{
+	twd_timer_rate = *((unsigned long *) new_rate);
+
+	clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
+}
+
+static int twd_rate_change(struct notifier_block *nb,
+	unsigned long flags, void *data)
+{
+	struct clk_notifier_data *cnd = data;
+
+	/*
+	 * The twd clock events must be reprogrammed to account for the new
+	 * frequency.  The timer is local to a cpu, so cross-call to the
+	 * changing cpu.
+	 */
+	if (flags == POST_RATE_CHANGE)
+		smp_call_function(twd_update_frequency,
+				  (void *)&cnd->new_rate, 1);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block twd_clk_nb = {
+	.notifier_call = twd_rate_change,
+};
+
+static int twd_clk_init(void)
+{
+	if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
+		return clk_notifier_register(twd_clk, &twd_clk_nb);
+
+	return 0;
+}
+core_initcall(twd_clk_init);
+
+#elif defined (CONFIG_CPU_FREQ)
+
+#include <linux/cpufreq.h>
 
 /*
  * Updates clockevent frequency when the cpu frequency changes.
diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
index 46090e6..6bd7300 100644
--- a/arch/arm/mach-at91/at91x40.c
+++ b/arch/arm/mach-at91/at91x40.c
@@ -47,7 +47,7 @@
 	 * Disable the processor clock.  The processor will be automatically
 	 * re-enabled by an interrupt or by a reset.
 	 */
-	__raw_writel(AT91_PS_CR_CPU, AT91_PS_CR);
+	__raw_writel(AT91_PS_CR_CPU, AT91_IO_P2V(AT91_PS_CR));
 	cpu_do_idle();
 }
 
diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c
index 6ca680a..ee06d7b 100644
--- a/arch/arm/mach-at91/at91x40_time.c
+++ b/arch/arm/mach-at91/at91x40_time.c
@@ -29,10 +29,10 @@
 #include <mach/at91_tc.h>
 
 #define at91_tc_read(field) \
-	__raw_readl(AT91_TC + field)
+	__raw_readl(AT91_IO_P2V(AT91_TC) + field)
 
 #define at91_tc_write(field, value) \
-	__raw_writel(value, AT91_TC + field);
+	__raw_writel(value, AT91_IO_P2V(AT91_TC) + field);
 
 /*
  *	3 counter/timer units present.
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index 09242b6..711a789 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -67,13 +67,13 @@
  * to 0xFEF78000 .. 0xFF000000.  (544Kb)
  */
 #define AT91_IO_PHYS_BASE	0xFFF78000
-#define AT91_IO_VIRT_BASE	(0xFF000000 - AT91_IO_SIZE)
+#define AT91_IO_VIRT_BASE	IOMEM(0xFF000000 - AT91_IO_SIZE)
 #else
 /*
  * Identity mapping for the non MMU case.
  */
 #define AT91_IO_PHYS_BASE	AT91_BASE_SYS
-#define AT91_IO_VIRT_BASE	AT91_IO_PHYS_BASE
+#define AT91_IO_VIRT_BASE	IOMEM(AT91_IO_PHYS_BASE)
 #endif
 
 #define AT91_IO_SIZE		(0xFFFFFFFF - AT91_IO_PHYS_BASE + 1)
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 6f6118d..97ad68a 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -94,7 +94,7 @@
 	0,
 };
 
-static inline const u32* decomp_soc_detect(u32 dbgu_base)
+static inline const u32* decomp_soc_detect(void __iomem *dbgu_base)
 {
 	u32 cidr, socid;
 
@@ -142,10 +142,10 @@
 	int i = 0;
 	const u32* usarts;
 
-	usarts = decomp_soc_detect(AT91_BASE_DBGU0);
+	usarts = decomp_soc_detect((void __iomem *)AT91_BASE_DBGU0);
 
 	if (!usarts)
-		usarts = decomp_soc_detect(AT91_BASE_DBGU1);
+		usarts = decomp_soc_detect((void __iomem *)AT91_BASE_DBGU1);
 	if (!usarts) {
 		at91_uart = NULL;
 		return;
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 944bffb..e6f52de 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -73,7 +73,7 @@
 {
 	struct map_desc *desc = &sram_desc[bank];
 
-	desc->virtual = AT91_IO_VIRT_BASE - length;
+	desc->virtual = (unsigned long)AT91_IO_VIRT_BASE - length;
 	if (bank > 0)
 		desc->virtual -= sram_desc[bank - 1].length;
 
@@ -88,7 +88,7 @@
 }
 
 static struct map_desc at91_io_desc __initdata = {
-	.virtual	= AT91_VA_BASE_SYS,
+	.virtual	= (unsigned long)AT91_VA_BASE_SYS,
 	.pfn		= __phys_to_pfn(AT91_BASE_SYS),
 	.length		= SZ_16K,
 	.type		= MT_DEVICE,
diff --git a/arch/arm/mach-bcm2835/Makefile b/arch/arm/mach-bcm2835/Makefile
new file mode 100644
index 0000000..4c3892f
--- /dev/null
+++ b/arch/arm/mach-bcm2835/Makefile
@@ -0,0 +1 @@
+obj-y += bcm2835.o
diff --git a/arch/arm/mach-bcm2835/Makefile.boot b/arch/arm/mach-bcm2835/Makefile.boot
new file mode 100644
index 0000000..0831fd1
--- /dev/null
+++ b/arch/arm/mach-bcm2835/Makefile.boot
@@ -0,0 +1,5 @@
+   zreladdr-y := 0x00008000
+params_phys-y := 0x00000100
+initrd_phys-y := 0x00800000
+
+dtb-y += bcm2835-rpi-b.dtb
diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c
new file mode 100644
index 0000000..f6fea49
--- /dev/null
+++ b/arch/arm/mach-bcm2835/bcm2835.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/irqchip/bcm2835.h>
+#include <linux/of_platform.h>
+#include <linux/bcm2835_timer.h>
+#include <linux/clk/bcm2835.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/bcm2835_soc.h>
+
+static struct map_desc io_map __initdata = {
+	.virtual = BCM2835_PERIPH_VIRT,
+	.pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
+	.length = BCM2835_PERIPH_SIZE,
+	.type = MT_DEVICE
+};
+
+void __init bcm2835_map_io(void)
+{
+	iotable_init(&io_map, 1);
+}
+
+void __init bcm2835_init(void)
+{
+	int ret;
+
+	bcm2835_init_clocks();
+
+	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
+				   NULL);
+	if (ret) {
+		pr_err("of_platform_populate failed: %d\n", ret);
+		BUG();
+	}
+}
+
+static const char * const bcm2835_compat[] = {
+	"brcm,bcm2835",
+	NULL
+};
+
+DT_MACHINE_START(BCM2835, "BCM2835")
+	.map_io = bcm2835_map_io,
+	.init_irq = bcm2835_init_irq,
+	.handle_irq = bcm2835_handle_irq,
+	.init_machine = bcm2835_init,
+	.timer = &bcm2835_timer,
+	.dt_compat = bcm2835_compat
+MACHINE_END
diff --git a/arch/arm/mach-bcm2835/include/mach/bcm2835_soc.h b/arch/arm/mach-bcm2835/include/mach/bcm2835_soc.h
new file mode 100644
index 0000000..d4dfcf7
--- /dev/null
+++ b/arch/arm/mach-bcm2835/include/mach/bcm2835_soc.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 Stephen Warren
+ *
+ * Derived from code:
+ * Copyright (C) 2010 Broadcom
+ *
+ * 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.
+ */
+
+#ifndef __MACH_BCM2835_BCM2835_SOC_H__
+#define __MACH_BCM2835_BCM2835_SOC_H__
+
+#include <asm/sizes.h>
+
+#define BCM2835_PERIPH_PHYS	0x20000000
+#define BCM2835_PERIPH_VIRT	0xf0000000
+#define BCM2835_PERIPH_SIZE	SZ_16M
+#define BCM2835_DEBUG_PHYS	0x20201000
+#define BCM2835_DEBUG_VIRT	0xf0201000
+
+#endif
diff --git a/arch/arm/mach-bcm2835/include/mach/debug-macro.S b/arch/arm/mach-bcm2835/include/mach/debug-macro.S
new file mode 100644
index 0000000..8a161e4
--- /dev/null
+++ b/arch/arm/mach-bcm2835/include/mach/debug-macro.S
@@ -0,0 +1,21 @@
+/*
+ * Debugging macro include header
+ *
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <mach/bcm2835_soc.h>
+
+	.macro	addruart, rp, rv, tmp
+	ldr	\rp, =BCM2835_DEBUG_PHYS
+	ldr	\rv, =BCM2835_DEBUG_VIRT
+	.endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-bcm2835/include/mach/timex.h b/arch/arm/mach-bcm2835/include/mach/timex.h
new file mode 100644
index 0000000..6d021e1
--- /dev/null
+++ b/arch/arm/mach-bcm2835/include/mach/timex.h
@@ -0,0 +1,26 @@
+/*
+ *  BCM2835 system clock frequency
+ *
+ *  Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+#define CLOCK_TICK_RATE		(1000000)
+
+#endif
diff --git a/arch/arm/mach-bcm2835/include/mach/uncompress.h b/arch/arm/mach-bcm2835/include/mach/uncompress.h
new file mode 100644
index 0000000..cc46dcc
--- /dev/null
+++ b/arch/arm/mach-bcm2835/include/mach/uncompress.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 2003 ARM Limited
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/amba/serial.h>
+#include <mach/bcm2835_soc.h>
+
+#define UART0_BASE BCM2835_DEBUG_PHYS
+
+#define BCM2835_UART_DR IOMEM(UART0_BASE + UART01x_DR)
+#define BCM2835_UART_FR IOMEM(UART0_BASE + UART01x_FR)
+#define BCM2835_UART_CR IOMEM(UART0_BASE + UART011_CR)
+
+static inline void putc(int c)
+{
+	while (__raw_readl(BCM2835_UART_FR) & UART01x_FR_TXFF)
+		barrier();
+
+	__raw_writel(c, BCM2835_UART_DR);
+}
+
+static inline void flush(void)
+{
+	int fr;
+
+	do {
+		fr = __raw_readl(BCM2835_UART_FR);
+		barrier();
+	} while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
+}
+
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
index 45c97b1..c18a504 100644
--- a/arch/arm/mach-bcmring/arch.c
+++ b/arch/arm/mach-bcmring/arch.c
@@ -29,7 +29,6 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
-#include <asm/pmu.h>
 
 #include <asm/mach/arch.h>
 #include <mach/dma.h>
@@ -38,7 +37,7 @@
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "core.h"
 
@@ -116,7 +115,7 @@
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pmu_resource,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index adbfb19..4b50228 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -43,11 +43,10 @@
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "clock.h"
 
-#include <csp/secHw.h>
 #include <mach/csp/secHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 #include <mach/csp/tmrHw_reg.h>
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
index 96273ff..5050833 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
@@ -26,15 +26,15 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 
@@ -61,21 +61,21 @@
 /****************************************************************************/
 chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configurable clock */
     ) {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-	volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
+	uint32_t __iomem *pDependentClock = NULL;
 	uint32_t vcoFreqPll1Hz = 0;	/* Effective VCO frequency for PLL1 in Hz */
 	uint32_t vcoFreqPll2Hz = 0;	/* Effective VCO frequency for PLL2 in Hz */
 	uint32_t dependentClockType = 0;
 	uint32_t vcoHz = 0;
 
 	/* Get VCO frequencies */
-	if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+	if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
 		uint64_t adjustFreq = 0;
 
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 		/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -86,13 +86,13 @@
 	} else {
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 	}
 	vcoFreqPll2Hz =
 	    chipcHw_XTAL_FREQ_Hz *
 		 chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-	    ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+	    ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 	     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 	switch (clock) {
@@ -187,51 +187,51 @@
 
 	if (pPLLReg) {
 		/* Obtain PLL clock frequency */
-		if (*pPLLReg & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+		if (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
 			/* Return crystal clock frequency when bypassed */
 			return chipcHw_XTAL_FREQ_Hz;
 		} else if (clock == chipcHw_CLOCK_DDR) {
 			/* DDR frequency is configured in PLLDivider register */
-			return chipcHw_divide (vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+			return chipcHw_divide (vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
 		} else {
 			/* From chip revision number B0, LCD clock is internally divided by 2 */
 			if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
 				vcoHz >>= 1;
 			}
 			/* Obtain PLL clock frequency using VCO dividers */
-			return chipcHw_divide(vcoHz, ((*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+			return chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ?  (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
 		}
 	} else if (pClockCtrl) {
 		/* Obtain divider clock frequency */
 		uint32_t div;
 		uint32_t freq = 0;
 
-		if (*pClockCtrl & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+		if (readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
 			/* Return crystal clock frequency when bypassed */
 			return chipcHw_XTAL_FREQ_Hz;
 		} else if (pDependentClock) {
 			/* Identify the dependent clock frequency */
 			switch (dependentClockType) {
 			case PLL_CLOCK:
-				if (*pDependentClock & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+				if (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
 					/* Use crystal clock frequency when dependent PLL clock is bypassed */
 					freq = chipcHw_XTAL_FREQ_Hz;
 				} else {
 					/* Obtain PLL clock frequency using VCO dividers */
-					div = *pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
+					div = readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
 					freq = div ? chipcHw_divide(vcoHz, div) : 0;
 				}
 				break;
 			case NON_PLL_CLOCK:
-				if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+				if (pDependentClock == &pChipcHw->ACLKClock) {
 					freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
 				} else {
-					if (*pDependentClock & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+					if (readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
 						/* Use crystal clock frequency when dependent divider clock is bypassed */
 						freq = chipcHw_XTAL_FREQ_Hz;
 					} else {
 						/* Obtain divider clock frequency using XTAL dividers */
-						div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+						div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 						freq = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, (div ? div : 256));
 					}
 				}
@@ -242,7 +242,7 @@
 			freq = chipcHw_XTAL_FREQ_Hz;
 		}
 
-		div = *pClockCtrl & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+		div = readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 		return chipcHw_divide(freq, (div ? div : 256));
 	}
 	return 0;
@@ -261,9 +261,9 @@
 chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configurable clock */
 				       uint32_t freq	/*  [ IN ] Clock frequency in Hz */
     ) {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-	volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
+	uint32_t __iomem *pDependentClock = NULL;
 	uint32_t vcoFreqPll1Hz = 0;	/* Effective VCO frequency for PLL1 in Hz */
 	uint32_t desVcoFreqPll1Hz = 0;	/* Desired VCO frequency for PLL1 in Hz */
 	uint32_t vcoFreqPll2Hz = 0;	/* Effective VCO frequency for PLL2 in Hz */
@@ -272,12 +272,12 @@
 	uint32_t desVcoHz = 0;
 
 	/* Get VCO frequencies */
-	if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+	if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
 		uint64_t adjustFreq = 0;
 
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 		/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -289,16 +289,16 @@
 		/* Desired VCO frequency */
 		desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    (((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    (((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) + 1);
 	} else {
 		vcoFreqPll1Hz = desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 	}
 	vcoFreqPll2Hz = chipcHw_XTAL_FREQ_Hz * chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-	    ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+	    ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 	     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 	switch (clock) {
@@ -307,8 +307,7 @@
 		{
 			REG_LOCAL_IRQ_SAVE;
 			/* Dvide DDR_phy by two to obtain DDR_ctrl clock */
-			pChipcHw->DDRClock = (pChipcHw->DDRClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-				<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+			writel((readl(&pChipcHw->DDRClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->DDRClock);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 		pPLLReg = &pChipcHw->DDRClock;
@@ -329,8 +328,7 @@
 		/* Configure the VPM:BUS ratio settings */
 		{
 			REG_LOCAL_IRQ_SAVE;
-			pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-				<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+			writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->VPMClock);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 		pPLLReg = &pChipcHw->VPMClock;
@@ -428,9 +426,9 @@
 		/* For DDR settings use only the PLL divider clock */
 		if (pPLLReg == &pChipcHw->DDRClock) {
 			/* Set M1DIV for PLL1, which controls the DDR clock */
-			reg32_write(&pChipcHw->PLLDivider, (pChipcHw->PLLDivider & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
+			reg32_write(&pChipcHw->PLLDivider, (readl(&pChipcHw->PLLDivider) & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
 			/* Calculate expected frequency */
-			freq = chipcHw_divide(vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+			freq = chipcHw_divide(vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
 		} else {
 			/* From chip revision number B0, LCD clock is internally divided by 2 */
 			if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
@@ -441,7 +439,7 @@
 			reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
 			reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
 			/* Calculate expected frequency */
-			freq = chipcHw_divide(vcoHz, ((*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+			freq = chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
 		}
 		/* Wait for for atleast 200ns as per the protocol to change frequency */
 		udelay(1);
@@ -460,16 +458,16 @@
 		if (pDependentClock) {
 			switch (dependentClockType) {
 			case PLL_CLOCK:
-				divider = chipcHw_divide(chipcHw_divide (desVcoHz, (*pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
+				divider = chipcHw_divide(chipcHw_divide (desVcoHz, (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
 				break;
 			case NON_PLL_CLOCK:
 				{
 					uint32_t sourceClock = 0;
 
-					if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+					if (pDependentClock == &pChipcHw->ACLKClock) {
 						sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
 					} else {
-						uint32_t div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+						uint32_t div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 						sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
 					}
 					divider = chipcHw_divide(sourceClock, freq);
@@ -483,7 +481,7 @@
 		if (divider) {
 			REG_LOCAL_IRQ_SAVE;
 			/* Set the divider to obtain the required frequency */
-			*pClockCtrl = (*pClockCtrl & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK);
+			writel((readl(pClockCtrl) & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK), pClockCtrl);
 			REG_LOCAL_IRQ_RESTORE;
 			return freq;
 		}
@@ -515,25 +513,26 @@
 	int count = 0;
 
 	for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
-		phaseControl = (pChipcHw->VPMClock & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
+		phaseControl = (readl(&pChipcHw->VPMClock) & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
 		phaseValue = 0;
 		prevPhaseComp = 0;
 
 		/* Step 1: Look for falling PH_COMP transition */
 
 		/* Read the contents of VPM Clock resgister */
-		phaseValue = pChipcHw->VPMClock;
+		phaseValue = readl(&pChipcHw->VPMClock);
 		do {
 			/* Store previous value of phase comparator */
 			prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Read the contents of  VPM Clock resgister. */
-			phaseValue = pChipcHw->VPMClock;
+			phaseValue = readl(&pChipcHw->VPMClock);
 
 			if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
 				phaseControl = (0x3F & (phaseControl - 1));
@@ -557,12 +556,13 @@
 
 		for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
 			phaseControl = (0x3F & (phaseControl + 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -581,12 +581,13 @@
 
 		for (count = 0; (count < 3) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
 			phaseControl = (0x3F & (phaseControl - 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -605,12 +606,13 @@
 
 		for (count = 0; (count < 5); count++) {
 			phaseControl = (0x3F & (phaseControl - 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -631,14 +633,14 @@
 			/* Store previous value of phase comparator */
 			prevPhaseComp = phaseValue;
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^=
-			    chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Read the contents of  VPM Clock resgister. */
-			phaseValue = pChipcHw->VPMClock;
+			phaseValue = readl(&pChipcHw->VPMClock);
 
 			if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
 				phaseControl = (0x3F & (phaseControl - 1));
@@ -661,13 +663,13 @@
 	}
 
 	/* For VPM Phase should be perfectly aligned. */
-	phaseControl = (((pChipcHw->VPMClock >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
+	phaseControl = (((readl(&pChipcHw->VPMClock) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
 	{
 		REG_LOCAL_IRQ_SAVE;
 
-		pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT);
+		writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT), &pChipcHw->VPMClock);
 		/* Load new phase value */
-		pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+		writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -697,7 +699,7 @@
 		int adjustCount = 0;
 
 		/* Disable VPM access */
-		pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+		writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 		/* Disable HW VPM phase alignment  */
 		chipcHw_vpmHwPhaseAlignDisable();
 		/* Enable SW VPM phase alignment  */
@@ -715,23 +717,24 @@
 				phaseControl--;
 			} else {
 				/* Enable VPM access */
-				pChipcHw->Spare1 |= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+				writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 				/* Return adjust count */
 				return adjustCount;
 			}
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Count adjustment */
 			adjustCount++;
 		}
 	}
 
 	/* Disable VPM access */
-	pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+	writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 	return -1;
 }
 
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
index 367df75..8377d80 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
@@ -26,15 +26,15 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 /* ---- Private Constants and Types --------------------------------------- */
 
 /*
@@ -73,9 +73,9 @@
 
 	{
 		REG_LOCAL_IRQ_SAVE;
-		pChipcHw->PLLConfig2 =
-		    chipcHw_REG_PLL_CONFIG_D_RESET |
-		    chipcHw_REG_PLL_CONFIG_A_RESET;
+		writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+		       chipcHw_REG_PLL_CONFIG_A_RESET,
+			&pChipcHw->PLLConfig2);
 
 		pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
 		    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
@@ -87,28 +87,30 @@
 		     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
 
 		/* Enable CHIPC registers to control the PLL */
-		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+		writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
 		/* Set pre divider to get desired VCO frequency */
-		pChipcHw->PLLPreDivider2 = pllPreDivider2;
+		writel(pllPreDivider2, &pChipcHw->PLLPreDivider2);
 		/* Set NDIV Frac */
-		pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f;
+		writel(chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider2);
 
 		/* This has to be removed once the default values are fixed for PLL2. */
-		pChipcHw->PLLControl12 = 0x38000700;
-		pChipcHw->PLLControl22 = 0x00000015;
+		writel(0x38000700, &pChipcHw->PLLControl12);
+		writel(0x00000015, &pChipcHw->PLLControl22);
 
 		/* Reset PLL2 */
 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET |
 			    chipcHw_REG_PLL_CONFIG_A_RESET |
 			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			    chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+			    &pChipcHw->PLLConfig2);
 		} else {
-			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET |
 			    chipcHw_REG_PLL_CONFIG_A_RESET |
 			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			    chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+			    &pChipcHw->PLLConfig2);
 		}
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -119,22 +121,25 @@
 	{
 		REG_LOCAL_IRQ_SAVE;
 		/* Remove analog reset and Power on the PLL */
-		pChipcHw->PLLConfig2 &=
+		writel(readl(&pChipcHw->PLLConfig2) &
 		    ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-		      chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+		      chipcHw_REG_PLL_CONFIG_POWER_DOWN),
+		      &pChipcHw->PLLConfig2);
 
 		REG_LOCAL_IRQ_RESTORE;
 
 	}
 
 	/* Wait until PLL is locked */
-	while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+	while (!(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
 		;
 
 	{
 		REG_LOCAL_IRQ_SAVE;
 		/* Remove digital reset */
-		pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+		writel(readl(&pChipcHw->PLLConfig2) &
+			~chipcHw_REG_PLL_CONFIG_D_RESET,
+			&pChipcHw->PLLConfig2);
 
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -157,9 +162,9 @@
 	{
 		REG_LOCAL_IRQ_SAVE;
 
-		pChipcHw->PLLConfig =
-		    chipcHw_REG_PLL_CONFIG_D_RESET |
-		    chipcHw_REG_PLL_CONFIG_A_RESET;
+		writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+		    chipcHw_REG_PLL_CONFIG_A_RESET,
+		    &pChipcHw->PLLConfig);
 		/* Setting VCO frequency */
 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
 			pllPreDivider =
@@ -182,30 +187,22 @@
 		}
 
 		/* Enable CHIPC registers to control the PLL */
-		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+		writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
 		/* Set pre divider to get desired VCO frequency */
-		pChipcHw->PLLPreDivider = pllPreDivider;
+		writel(pllPreDivider, &pChipcHw->PLLPreDivider);
 		/* Set NDIV Frac */
 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
-			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-			    chipcHw_REG_PLL_DIVIDER_NDIV_f_SS;
+			writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f_SS, &pChipcHw->PLLDivider);
 		} else {
-			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-			    chipcHw_REG_PLL_DIVIDER_NDIV_f;
+			writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider);
 		}
 
 		/* Reset PLL1 */
 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-			    chipcHw_REG_PLL_CONFIG_A_RESET |
-			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
 		} else {
-			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-			    chipcHw_REG_PLL_CONFIG_A_RESET |
-			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_800_1600 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
 		}
 
 		REG_LOCAL_IRQ_RESTORE;
@@ -216,22 +213,19 @@
 		{
 			REG_LOCAL_IRQ_SAVE;
 			/* Remove analog reset and Power on the PLL */
-			pChipcHw->PLLConfig &=
-			    ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-			      chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+			writel(readl(&pChipcHw->PLLConfig) & ~(chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_POWER_DOWN), &pChipcHw->PLLConfig);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 
 		/* Wait until PLL is locked */
-		while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED)
-		       || !(pChipcHw->
-			    PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+		while (!(readl(&pChipcHw->PLLStatus) & chipcHw_REG_PLL_STATUS_LOCKED)
+		       || !(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
 			;
 
 		/* Remove digital reset */
 		{
 			REG_LOCAL_IRQ_SAVE;
-			pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+			writel(readl(&pChipcHw->PLLConfig) & ~chipcHw_REG_PLL_CONFIG_D_RESET, &pChipcHw->PLLConfig);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 	}
@@ -267,11 +261,7 @@
 	chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
 
 	/* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
-	pChipcHw->ACLKClock =
-	    (pChipcHw->
-	     ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam->
-								 armBusRatio &
-								 chipcHw_REG_ACLKClock_CLK_DIV_MASK);
+	writel((readl(&pChipcHw->ACLKClock) & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> armBusRatio & chipcHw_REG_ACLKClock_CLK_DIV_MASK), &pChipcHw->ACLKClock);
 
 	/* Set various core component frequencies. The order in which this is done is important for some. */
 	/* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
index 2671d88..f95ce91 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
@@ -13,11 +13,11 @@
 *****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
-#include <csp/intcHw.h>
-#include <csp/cache.h>
+#include <mach/csp/intcHw_reg.h>
+#include <asm/cacheflush.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 /* ---- Private Variables ------------------------------------------------- */
@@ -50,17 +50,18 @@
 			chipcHw_softReset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
 		}
 		/* Bypass the PLL clocks before reboot */
-		pChipcHw->UARTClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
-		pChipcHw->SPIClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
+		writel(readl(&pChipcHw->UARTClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+			&pChipcHw->UARTClock);
+		writel(readl(&pChipcHw->SPIClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+			&pChipcHw->SPIClock);
 
 		/* Copy the chipcHw_warmReset_run_from_aram function into ARAM */
 		do {
-			((uint32_t *) MM_IO_BASE_ARAM)[i] =
-			    ((uint32_t *) &chipcHw_reset_run_from_aram)[i];
+			writel(((uint32_t *) &chipcHw_reset_run_from_aram)[i], ((uint32_t __iomem *) MM_IO_BASE_ARAM) + i);
 			i++;
-		} while (((uint32_t *) MM_IO_BASE_ARAM)[i - 1] != 0xe1a0f00f);	/* 0xe1a0f00f == asm ("mov r15, r15"); */
+		} while (readl(((uint32_t __iomem*) MM_IO_BASE_ARAM) + i - 1) != 0xe1a0f00f);	/* 0xe1a0f00f == asm ("mov r15, r15"); */
 
-		CSP_CACHE_FLUSH_ALL;
+		flush_cache_all();
 
 		/* run the function from ARAM */
 		runFunc();
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
index 6b9be2e..547f746 100644
--- a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
@@ -25,11 +25,11 @@
 /****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/string.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 #include <mach/csp/chipcHw_inline.h>
@@ -55,33 +55,32 @@
     ) {
 	uint32_t val = 0;
 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
-	dmacHw_MISC_t *pMiscReg =
-	    (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
+	dmacHw_MISC_t __iomem *pMiscReg = (void __iomem *)dmacHw_REG_MISC_BASE(pCblk->module);
 
 	switch (pCblk->channel) {
 	case 0:
-		val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm2.lo) & 0x70000000) >> 28;
 		break;
 	case 1:
-		val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm3.hi) & 0x70000000) >> 28;
 		break;
 	case 2:
-		val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm3.lo) & 0x70000000) >> 28;
 		break;
 	case 3:
-		val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm4.hi) & 0x70000000) >> 28;
 		break;
 	case 4:
-		val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm4.lo) & 0x70000000) >> 28;
 		break;
 	case 5:
-		val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm5.hi) & 0x70000000) >> 28;
 		break;
 	case 6:
-		val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm5.lo) & 0x70000000) >> 28;
 		break;
 	case 7:
-		val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm6.hi) & 0x70000000) >> 28;
 		break;
 	}
 
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
index a1f3283..fe43869 100644
--- a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
@@ -26,10 +26,10 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 
diff --git a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
index 16225e4..dc4137f 100644
--- a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
+++ b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
@@ -26,10 +26,10 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
+#include <linux/errno.h>
+#include <linux/types.h>
 
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 #include <mach/csp/tmrHw_reg.h>
 
 #define tmrHw_ASSERT(a)                     if (!(a)) *(char *)0 = 0
diff --git a/arch/arm/mach-bcmring/include/cfg_global.h b/arch/arm/mach-bcmring/include/cfg_global.h
deleted file mode 100644
index f01da87..0000000
--- a/arch/arm/mach-bcmring/include/cfg_global.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _CFG_GLOBAL_H_
-#define _CFG_GLOBAL_H_
-
-#include <cfg_global_defines.h>
-
-#define CFG_GLOBAL_CHIP                         BCM11107
-#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
-#define CFG_GLOBAL_CHIP_REV                     0xB0
-#define CFG_GLOBAL_RAM_SIZE                     0x10000000
-#define CFG_GLOBAL_RAM_BASE                     0x00000000
-#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
-
-#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/cfg_global_defines.h b/arch/arm/mach-bcmring/include/cfg_global_defines.h
deleted file mode 100644
index b5beb0b3..0000000
--- a/arch/arm/mach-bcmring/include/cfg_global_defines.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*****************************************************************************
-* Copyright 2006 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CFG_GLOBAL_DEFINES_H
-#define CFG_GLOBAL_DEFINES_H
-
-/* CHIP */
-#define BCM1103 1
-
-#define BCM1191 4
-#define BCM2153 5
-#define BCM2820 6
-
-#define BCM2826 8
-#define FPGA11107 9
-#define BCM11107   10
-#define BCM11109   11
-#define BCM11170   12
-#define BCM11110   13
-#define BCM11211   14
-
-/* CFG_GLOBAL_CHIP_FAMILY types */
-#define CFG_GLOBAL_CHIP_FAMILY_NONE        0
-#define CFG_GLOBAL_CHIP_FAMILY_BCM116X     2
-#define CFG_GLOBAL_CHIP_FAMILY_BCMRING     4
-#define CFG_GLOBAL_CHIP_FAMILY_BCM1103     8
-
-#define IMAGE_HEADER_SIZE_CHECKSUM    4
-#endif
diff --git a/arch/arm/mach-bcmring/include/csp/cache.h b/arch/arm/mach-bcmring/include/csp/cache.h
deleted file mode 100644
index caa20e5..0000000
--- a/arch/arm/mach-bcmring/include/csp/cache.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_CACHE_H
-#define CSP_CACHE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <csp/stdint.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-#include <asm/cacheflush.h>
-
-#define CSP_CACHE_FLUSH_ALL      flush_cache_all()
-
-#else
-
-#define CSP_CACHE_FLUSH_ALL
-
-#endif
-
-#endif /* CSP_CACHE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/delay.h b/arch/arm/mach-bcmring/include/csp/delay.h
deleted file mode 100644
index 8b3d803..0000000
--- a/arch/arm/mach-bcmring/include/csp/delay.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_DELAY_H
-#define CSP_DELAY_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-/* Some CSP routines require use of the following delay routines. Use the OS */
-/* version if available, otherwise use a CSP specific definition. */
-/* void udelay(unsigned long usecs); */
-/* void mdelay(unsigned long msecs); */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-   #include <linux/delay.h>
-#else
-   #include <mach/csp/delay.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /*  CSP_DELAY_H */
diff --git a/arch/arm/mach-bcmring/include/csp/dmacHw.h b/arch/arm/mach-bcmring/include/csp/dmacHw.h
deleted file mode 100644
index e6a1dc4..0000000
--- a/arch/arm/mach-bcmring/include/csp/dmacHw.h
+++ /dev/null
@@ -1,596 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    dmacHw.h
-*
-*  @brief   API definitions for low level DMA controller driver
-*
-*/
-/****************************************************************************/
-#ifndef _DMACHW_H
-#define _DMACHW_H
-
-#include <stddef.h>
-
-#include <csp/stdint.h>
-#include <mach/csp/dmacHw_reg.h>
-
-/* Define DMA Channel ID using DMA controller number (m) and channel number (c).
-
-   System specific channel ID should be defined as follows
-
-   For example:
-
-   #include <dmacHw.h>
-   ...
-   #define systemHw_LCD_CHANNEL_ID                dmacHw_MAKE_CHANNEL_ID(0,5)
-   #define systemHw_SWITCH_RX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,0)
-   #define systemHw_SWITCH_TX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,1)
-   #define systemHw_APM_RX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,3)
-   #define systemHw_APM_TX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,4)
-   ...
-   #define systemHw_SHARED1_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,4)
-   #define systemHw_SHARED2_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,5)
-   #define systemHw_SHARED3_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(0,6)
-   ...
-*/
-#define dmacHw_MAKE_CHANNEL_ID(m, c)         (m << 8 | c)
-
-typedef enum {
-	dmacHw_CHANNEL_PRIORITY_0 = dmacHw_REG_CFG_LO_CH_PRIORITY_0,	/* Channel priority 0. Lowest priority DMA channel */
-	dmacHw_CHANNEL_PRIORITY_1 = dmacHw_REG_CFG_LO_CH_PRIORITY_1,	/* Channel priority 1 */
-	dmacHw_CHANNEL_PRIORITY_2 = dmacHw_REG_CFG_LO_CH_PRIORITY_2,	/* Channel priority 2 */
-	dmacHw_CHANNEL_PRIORITY_3 = dmacHw_REG_CFG_LO_CH_PRIORITY_3,	/* Channel priority 3 */
-	dmacHw_CHANNEL_PRIORITY_4 = dmacHw_REG_CFG_LO_CH_PRIORITY_4,	/* Channel priority 4 */
-	dmacHw_CHANNEL_PRIORITY_5 = dmacHw_REG_CFG_LO_CH_PRIORITY_5,	/* Channel priority 5 */
-	dmacHw_CHANNEL_PRIORITY_6 = dmacHw_REG_CFG_LO_CH_PRIORITY_6,	/* Channel priority 6 */
-	dmacHw_CHANNEL_PRIORITY_7 = dmacHw_REG_CFG_LO_CH_PRIORITY_7	/* Channel priority 7. Highest priority DMA channel */
-} dmacHw_CHANNEL_PRIORITY_e;
-
-/* Source destination master interface */
-typedef enum {
-	dmacHw_SRC_MASTER_INTERFACE_1 = dmacHw_REG_CTL_SMS_1,	/* Source DMA master interface 1 */
-	dmacHw_SRC_MASTER_INTERFACE_2 = dmacHw_REG_CTL_SMS_2,	/* Source DMA master interface 2 */
-	dmacHw_DST_MASTER_INTERFACE_1 = dmacHw_REG_CTL_DMS_1,	/* Destination DMA master interface 1 */
-	dmacHw_DST_MASTER_INTERFACE_2 = dmacHw_REG_CTL_DMS_2	/* Destination DMA master interface 2 */
-} dmacHw_MASTER_INTERFACE_e;
-
-typedef enum {
-	dmacHw_SRC_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_SRC_TR_WIDTH_8,	/* Source 8 bit  (1 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_SRC_TR_WIDTH_16,	/* Source 16 bit (2 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_SRC_TR_WIDTH_32,	/* Source 32 bit (4 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_SRC_TR_WIDTH_64,	/* Source 64 bit (8 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_DST_TR_WIDTH_8,	/* Destination 8 bit  (1 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_DST_TR_WIDTH_16,	/* Destination 16 bit (2 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_DST_TR_WIDTH_32,	/* Destination 32 bit (4 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_DST_TR_WIDTH_64	/* Destination 64 bit (8 byte) per transaction */
-} dmacHw_TRANSACTION_WIDTH_e;
-
-typedef enum {
-	dmacHw_SRC_BURST_WIDTH_0 = dmacHw_REG_CTL_SRC_MSIZE_0,	/* Source No burst */
-	dmacHw_SRC_BURST_WIDTH_4 = dmacHw_REG_CTL_SRC_MSIZE_4,	/* Source 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_SRC_BURST_WIDTH_8 = dmacHw_REG_CTL_SRC_MSIZE_8,	/* Source 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_SRC_BURST_WIDTH_16 = dmacHw_REG_CTL_SRC_MSIZE_16,	/* Source 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_0 = dmacHw_REG_CTL_DST_MSIZE_0,	/* Destination No burst */
-	dmacHw_DST_BURST_WIDTH_4 = dmacHw_REG_CTL_DST_MSIZE_4,	/* Destination 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_8 = dmacHw_REG_CTL_DST_MSIZE_8,	/* Destination 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_16 = dmacHw_REG_CTL_DST_MSIZE_16	/* Destination 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-} dmacHw_BURST_WIDTH_e;
-
-typedef enum {
-	dmacHw_TRANSFER_TYPE_MEM_TO_MEM = dmacHw_REG_CTL_TTFC_MM_DMAC,	/* Memory to memory transfer */
-	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM = dmacHw_REG_CTL_TTFC_PM_DMAC,	/* Peripheral to memory transfer */
-	dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_MP_DMAC,	/* Memory to peripheral transfer */
-	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_PP_DMAC	/* Peripheral to peripheral transfer */
-} dmacHw_TRANSFER_TYPE_e;
-
-typedef enum {
-	dmacHw_TRANSFER_MODE_PERREQUEST,	/* Block transfer per DMA request */
-	dmacHw_TRANSFER_MODE_CONTINUOUS,	/* Continuous transfer of streaming data */
-	dmacHw_TRANSFER_MODE_PERIODIC	/* Periodic transfer of streaming data */
-} dmacHw_TRANSFER_MODE_e;
-
-typedef enum {
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_SINC_INC,	/* Increment source address after every transaction */
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_SINC_DEC,	/* Decrement source address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_DINC_INC,	/* Increment destination address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_DINC_DEC,	/* Decrement destination address after every transaction */
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_SINC_NC,	/* No change in source address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_DINC_NC	/* No change in destination address after every transaction */
-} dmacHw_ADDRESS_UPDATE_MODE_e;
-
-typedef enum {
-	dmacHw_FLOW_CONTROL_DMA,	/* DMA working as flow controller (default) */
-	dmacHw_FLOW_CONTROL_PERIPHERAL	/* Peripheral working as flow controller */
-} dmacHw_FLOW_CONTROL_e;
-
-typedef enum {
-	dmacHw_TRANSFER_STATUS_BUSY,	/* DMA Transfer ongoing */
-	dmacHw_TRANSFER_STATUS_DONE,	/* DMA Transfer completed */
-	dmacHw_TRANSFER_STATUS_ERROR	/* DMA Transfer error */
-} dmacHw_TRANSFER_STATUS_e;
-
-typedef enum {
-	dmacHw_INTERRUPT_DISABLE,	/* Interrupt disable  */
-	dmacHw_INTERRUPT_ENABLE	/* Interrupt enable */
-} dmacHw_INTERRUPT_e;
-
-typedef enum {
-	dmacHw_INTERRUPT_STATUS_NONE = 0x0,	/* No DMA interrupt */
-	dmacHw_INTERRUPT_STATUS_TRANS = 0x1,	/* End of DMA transfer interrupt */
-	dmacHw_INTERRUPT_STATUS_BLOCK = 0x2,	/* End of block transfer interrupt */
-	dmacHw_INTERRUPT_STATUS_ERROR = 0x4	/* Error interrupt */
-} dmacHw_INTERRUPT_STATUS_e;
-
-typedef enum {
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM,	/* Number of DMA channel */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE,	/* Maximum channel burst size */
-	dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM,	/* Number of DMA master interface */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH,	/* Channel Data bus width */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE	/* Channel FIFO size */
-} dmacHw_CONTROLLER_ATTRIB_e;
-
-typedef unsigned long dmacHw_HANDLE_t;	/* DMA channel handle */
-typedef uint32_t dmacHw_ID_t;	/* DMA channel Id.  Must be created using
-				   "dmacHw_MAKE_CHANNEL_ID" macro
-				 */
-/* DMA channel configuration parameters */
-typedef struct {
-	uint32_t srcPeripheralPort;	/* Source peripheral port */
-	uint32_t dstPeripheralPort;	/* Destination peripheral port */
-	uint32_t srcStatusRegisterAddress;	/* Source status register address */
-	uint32_t dstStatusRegisterAddress;	/* Destination status register address of type  */
-
-	uint32_t srcGatherWidth;	/* Number of bytes gathered before successive gather opearation */
-	uint32_t srcGatherJump;	/* Number of bytes jumpped before successive gather opearation */
-	uint32_t dstScatterWidth;	/* Number of bytes sacattered before successive scatter opearation */
-	uint32_t dstScatterJump;	/* Number of bytes jumpped  before successive scatter opearation */
-	uint32_t maxDataPerBlock;	/* Maximum number of bytes to be transferred per block/descrptor.
-					   0 = Maximum possible.
-					 */
-
-	dmacHw_ADDRESS_UPDATE_MODE_e srcUpdate;	/* Source address update mode */
-	dmacHw_ADDRESS_UPDATE_MODE_e dstUpdate;	/* Destination address update mode */
-	dmacHw_TRANSFER_TYPE_e transferType;	/* DMA transfer type  */
-	dmacHw_TRANSFER_MODE_e transferMode;	/* DMA transfer mode */
-	dmacHw_MASTER_INTERFACE_e srcMasterInterface;	/* DMA source interface  */
-	dmacHw_MASTER_INTERFACE_e dstMasterInterface;	/* DMA destination interface */
-	dmacHw_TRANSACTION_WIDTH_e srcMaxTransactionWidth;	/* Source transaction width   */
-	dmacHw_TRANSACTION_WIDTH_e dstMaxTransactionWidth;	/* Destination transaction width */
-	dmacHw_BURST_WIDTH_e srcMaxBurstWidth;	/* Source burst width */
-	dmacHw_BURST_WIDTH_e dstMaxBurstWidth;	/* Destination burst width */
-	dmacHw_INTERRUPT_e blockTransferInterrupt;	/* Block trsnafer interrupt */
-	dmacHw_INTERRUPT_e completeTransferInterrupt;	/* Complete DMA trsnafer interrupt */
-	dmacHw_INTERRUPT_e errorInterrupt;	/* Error interrupt */
-	dmacHw_CHANNEL_PRIORITY_e channelPriority;	/* Channel priority */
-	dmacHw_FLOW_CONTROL_e flowControler;	/* Data flow controller */
-} dmacHw_CONFIG_t;
-
-/****************************************************************************/
-/**
-*  @brief   Initializes DMA
-*
-*  This function initializes DMA CSP driver
-*
-*  @note
-*     Must be called before using any DMA channel
-*/
-/****************************************************************************/
-void dmacHw_initDma(void);
-
-/****************************************************************************/
-/**
-*  @brief   Exit function for  DMA
-*
-*  This function isolates DMA from the system
-*
-*/
-/****************************************************************************/
-void dmacHw_exitDma(void);
-
-/****************************************************************************/
-/**
-*  @brief   Gets a handle to a DMA channel
-*
-*  This function returns a handle, representing a control block of a particular DMA channel
-*
-*  @return  -1       - On Failure
-*            handle  - On Success, representing a channel control block
-*
-*  @note
-*     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
-*/
-/****************************************************************************/
-dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId	/* [ IN ] DMA Channel Id */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Initializes a DMA channel for use
-*
-*  This function initializes and resets a DMA channel for use
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_initChannel(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief  Estimates number of descriptor needed to perform certain DMA transfer
-*
-*
-*  @return  On failure : -1
-*           On success : Number of descriptor count
-*
-*
-*/
-/****************************************************************************/
-int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
-				    void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
-				    void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
-				    size_t dataLen	/*   [ IN ] Data length in bytes */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Initializes descriptor ring
-*
-*  This function will initializes the descriptor ring of a DMA channel
-*
-*
-*  @return   -1 - On failure
-*             0 - On success
-*  @note
-*     - "len" parameter should be obtained from "dmacHw_descriptorLen"
-*     - Descriptor buffer MUST be 32 bit aligned and uncached as it
-*       is accessed by ARM and DMA
-*/
-/****************************************************************************/
-int dmacHw_initDescriptor(void *pDescriptorVirt,	/*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
-			  uint32_t descriptorPhyAddr,	/*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
-			  uint32_t len,	/*  [ IN ] Size of the pBuf */
-			  uint32_t num	/*  [ IN ] Number of descriptor in the ring */
-    );
-
-/****************************************************************************/
-/**
-*  @brief  Finds amount of memory required to form a descriptor ring
-*
-*
-*  @return   Number of bytes required to form a descriptor ring
-*
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-uint32_t dmacHw_descriptorLen(uint32_t descCnt	/*  [ IN ] Number of descriptor in the ring */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Configure DMA channel
-*
-*  @return  0  : On success
-*           -1 : On failure
-*/
-/****************************************************************************/
-int dmacHw_configChannel(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			 dmacHw_CONFIG_t *pConfig	/*   [ IN ] Configuration settings */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Set descriptors for known data length
-*
-*  When DMA has to work as a flow controller, this function prepares the
-*  descriptor chain to transfer data
-*
-*  from:
-*          - Memory to memory
-*          - Peripheral to memory
-*          - Memory to Peripheral
-*          - Peripheral to Peripheral
-*
-*  @return   -1 - On failure
-*             0 - On success
-*
-*/
-/****************************************************************************/
-int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-			     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			     void *pSrcAddr,	/*  [ IN ] Source (Peripheral/Memory) address */
-			     void *pDstAddr,	/*  [ IN ] Destination (Peripheral/Memory) address */
-			     size_t dataLen	/*  [ IN ] Length in bytes   */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Indicates whether DMA transfer is in progress or completed
-*
-*  @return   DMA transfer status
-*          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
-*          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
-*          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
-*
-*/
-/****************************************************************************/
-dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Set descriptor carrying control information
-*
-*  This function will be used to send specific control information to the device
-*  using the DMA channel
-*
-*
-*  @return  -1 - On failure
-*            0 - On success
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-				void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-				uint32_t ctlAddress,	/*  [ IN ] Address of the device control register  */
-				uint32_t control	/*  [ IN ] Device control information */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Read data DMA transferred to memory
-*
-*  This function will read data that has been DMAed to memory while transferring from:
-*          - Memory to memory
-*          - Peripheral to memory
-*
-*  @return  0 - No more data is available to read
-*           1 - More data might be available to read
-*
-*/
-/****************************************************************************/
-int dmacHw_readTransferredData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle    */
-			       dmacHw_CONFIG_t *pConfig,	/*  [ IN ]  Configuration settings */
-			       void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			       void **ppBbuf,	/*  [ OUT ] Data received */
-			       size_t *pLlen	/*  [ OUT ] Length of the data received */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
-*
-*  This function will form the descriptor ring by allocating buffers, when source peripheral
-*  has to work as a flow controller to transfer data from:
-*           - Peripheral to memory.
-*
-*  @return  -1 - On failure
-*            0 - On success
-*
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle   */
-				     dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-				     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-				     uint32_t srcAddr,	/*  [ IN ] Source peripheral address */
-				     void *(*fpAlloc) (int len),	/*  [ IN ] Function pointer  that provides destination memory */
-				     int len,	/*  [ IN ] Number of bytes "fpAlloc" will allocate for destination */
-				     int num	/*  [ IN ] Number of descriptor to set */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Program channel register to initiate transfer
-*
-*  @return  void
-*
-*
-*  @note
-*     - Descriptor buffer MUST ALWAYS be flushed before calling this function
-*     - This function should also be called from ISR to program the channel with
-*       pending descriptors
-*/
-/****************************************************************************/
-void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
-			     dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
-			     void *pDescriptor	/*   [ IN ] Descriptor buffer  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Resets descriptor control information
-*
-*  @return  void
-*/
-/****************************************************************************/
-void dmacHw_resetDescriptorControl(void *pDescriptor	/*   [ IN ] Descriptor buffer  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Program channel register to stop transfer
-*
-*  Ensures the channel is not doing any transfer after calling this function
-*
-*  @return  void
-*
-*/
-/****************************************************************************/
-void dmacHw_stopTransfer(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Check the existence of pending descriptor
-*
-*  This function confirmes if there is any pending descriptor in the chain
-*  to program the channel
-*
-*  @return  1 : Channel need to be programmed with pending descriptor
-*           0 : No more pending descriptor to programe the channel
-*
-*  @note
-*     - This function should be called from ISR in case there are pending
-*       descriptor to program the channel.
-*
-*     Example:
-*
-*     dmac_isr ()
-*     {
-*         ...
-*         if (dmacHw_descriptorPending (handle))
-*         {
-*            dmacHw_initiateTransfer (handle);
-*         }
-*     }
-*
-*/
-/****************************************************************************/
-uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
-				  void *pDescriptor	/*   [ IN ] Descriptor buffer */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Deallocates source or destination memory, allocated
-*
-*  This function can be called to deallocate data memory that was DMAed successfully
-*
-*  @return  -1  - On failure
-*            0  - On success
-*
-*  @note
-*     This function will be called ONLY, when source OR destination address is pointing
-*     to dynamic memory
-*/
-/****************************************************************************/
-int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-		   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-		   void (*fpFree) (void *)	/*  [ IN ] Function pointer to free data memory */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Clears the interrupt
-*
-*  This function clears the DMA channel specific interrupt
-*
-*  @return   N/A
-*
-*  @note
-*     Must be called under the context of ISR
-*/
-/****************************************************************************/
-void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Returns the cause of channel specific DMA interrupt
-*
-*  This function returns the cause of interrupt
-*
-*  @return  Interrupt status, each bit representing a specific type of interrupt
-*           of type dmacHw_INTERRUPT_STATUS_e
-*  @note
-*           This function should be called under the context of ISR
-*/
-/****************************************************************************/
-dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Indentifies a DMA channel causing interrupt
-*
-*  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
-*
-*  @return  NULL   : No channel causing DMA interrupt
-*           ! NULL : Handle to a channel causing DMA interrupt
-*  @note
-*     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
-*/
-/****************************************************************************/
-dmacHw_HANDLE_t dmacHw_getInterruptSource(void);
-
-/****************************************************************************/
-/**
-*  @brief   Sets channel specific user data
-*
-*  This function associates user data to a specific DMA channel
-*
-*/
-/****************************************************************************/
-void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			       void *userData	/*  [ IN ] User data  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Gets channel specific user data
-*
-*  This function returns user data specific to a DMA channel
-*
-*  @return   user data
-*/
-/****************************************************************************/
-void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Displays channel specific registers and other control parameters
-*
-*
-*  @return  void
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			   int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Provides DMA controller attributes
-*
-*
-*  @return  DMA controller attributes
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,	/*  [ IN ]  DMA Channel handle  */
-					  dmacHw_CONTROLLER_ATTRIB_e attr	/*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
-    );
-
-#endif /* _DMACHW_H */
diff --git a/arch/arm/mach-bcmring/include/csp/errno.h b/arch/arm/mach-bcmring/include/csp/errno.h
deleted file mode 100644
index 51357dd..0000000
--- a/arch/arm/mach-bcmring/include/csp/errno.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_ERRNO_H
-#define CSP_ERRNO_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#if   defined(__KERNEL__)
-#include <linux/errno.h>
-#elif defined(CSP_SIMULATION)
-#include <asm-generic/errno.h>
-#else
-#include <errno.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_ERRNO_H */
diff --git a/arch/arm/mach-bcmring/include/csp/intcHw.h b/arch/arm/mach-bcmring/include/csp/intcHw.h
deleted file mode 100644
index 1c639c8..0000000
--- a/arch/arm/mach-bcmring/include/csp/intcHw.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-/****************************************************************************/
-/**
-*  @file    intcHw.h
-*
-*  @brief   generic interrupt controller API
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-
-#ifndef _INTCHW_H
-#define _INTCHW_H
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <mach/csp/intcHw_reg.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask);
-static inline void intcHw_irq_enable(void *basep, uint32_t mask);
-
-#endif /* _INTCHW_H */
-
diff --git a/arch/arm/mach-bcmring/include/csp/module.h b/arch/arm/mach-bcmring/include/csp/module.h
deleted file mode 100644
index c30d2a5..0000000
--- a/arch/arm/mach-bcmring/include/csp/module.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_MODULE_H
-#define CSP_MODULE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-    #include <linux/module.h>
-#else
-    #define EXPORT_SYMBOL(symbol)
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_MODULE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/reg.h b/arch/arm/mach-bcmring/include/csp/reg.h
deleted file mode 100644
index 56654d2..0000000
--- a/arch/arm/mach-bcmring/include/csp/reg.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    reg.h
-*
-*  @brief   Generic register definitions used in CSP
-*/
-/****************************************************************************/
-
-#ifndef CSP_REG_H
-#define CSP_REG_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <csp/stdint.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-
-#define __REG32(x)      (*((volatile uint32_t *)(x)))
-#define __REG16(x)      (*((volatile uint16_t *)(x)))
-#define __REG8(x)       (*((volatile uint8_t *) (x)))
-
-/* Macros used to define a sequence of reserved registers. The start / end */
-/* are byte offsets in the particular register definition, with the "end" */
-/* being the offset of the next un-reserved register. E.g. if offsets */
-/* 0x10 through to 0x1f are reserved, then this reserved area could be */
-/* specified as follows. */
-/*  typedef struct */
-/*  { */
-/*      uint32_t reg1;           offset 0x00 */
-/*      uint32_t reg2;           offset 0x04 */
-/*      uint32_t reg3;           offset 0x08 */
-/*      uint32_t reg4;           offset 0x0c */
-/*      REG32_RSVD(0x10, 0x20); */
-/*      uint32_t reg5;           offset 0x20 */
-/*      ... */
-/*  } EXAMPLE_REG_t; */
-#define REG8_RSVD(start, end)   uint8_t rsvd_##start[(end - start) / sizeof(uint8_t)]
-#define REG16_RSVD(start, end)  uint16_t rsvd_##start[(end - start) / sizeof(uint16_t)]
-#define REG32_RSVD(start, end)  uint32_t rsvd_##start[(end - start) / sizeof(uint32_t)]
-
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-/* Note: When protecting multiple statements, the REG_LOCAL_IRQ_SAVE and */
-/* REG_LOCAL_IRQ_RESTORE must be enclosed in { } to allow the  */
-/* flags variable to be declared locally. */
-/* e.g. */
-/*    statement1; */
-/*    { */
-/*       REG_LOCAL_IRQ_SAVE; */
-/*       <multiple statements here> */
-/*       REG_LOCAL_IRQ_RESTORE; */
-/*    } */
-/*    statement2; */
-/*  */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-#include <mach/hardware.h>
-#include <linux/interrupt.h>
-
-#define REG_LOCAL_IRQ_SAVE      HW_DECLARE_SPINLOCK(reg32) \
-	unsigned long flags; HW_IRQ_SAVE(reg32, flags)
-
-#define REG_LOCAL_IRQ_RESTORE   HW_IRQ_RESTORE(reg32, flags)
-
-#else
-
-#define REG_LOCAL_IRQ_SAVE
-#define REG_LOCAL_IRQ_RESTORE
-
-#endif
-
-static inline void reg32_modify_and(volatile uint32_t *reg, uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg &= value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_modify_or(volatile uint32_t *reg, uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg |= value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_modify_mask(volatile uint32_t *reg, uint32_t mask,
-				     uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg = (*reg & mask) | value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_write(volatile uint32_t *reg, uint32_t value)
-{
-	*reg = value;
-}
-
-#endif /* CSP_REG_H */
diff --git a/arch/arm/mach-bcmring/include/csp/secHw.h b/arch/arm/mach-bcmring/include/csp/secHw.h
deleted file mode 100644
index b9d7e07..0000000
--- a/arch/arm/mach-bcmring/include/csp/secHw.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    secHw.h
-*
-*  @brief   Definitions for accessing low level security features
-*
-*/
-/****************************************************************************/
-#ifndef SECHW_H
-#define SECHW_H
-
-typedef void (*secHw_FUNC_t) (void);
-
-typedef enum {
-	secHw_MODE_SECURE = 0x0,	/* Switches processor into secure mode */
-	secHw_MODE_NONSECURE = 0x1	/* Switches processor into non-secure mode */
-} secHw_MODE;
-
-/****************************************************************************/
-/**
-*  @brief   Requesting to execute the function in secure mode
-*
-*  This function requests the given function to run in secure mode
-*
-*/
-/****************************************************************************/
-void secHw_RunSecure(secHw_FUNC_t	/* Function to run in secure mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Sets the  mode
-*
-*  his function sets the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_SetMode(secHw_MODE	/* Processor mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Get the current mode
-*
-*  This function retieves the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_GetMode(secHw_MODE *);
-
-#endif /* SECHW_H */
diff --git a/arch/arm/mach-bcmring/include/csp/stdint.h b/arch/arm/mach-bcmring/include/csp/stdint.h
deleted file mode 100644
index 3a8718b..0000000
--- a/arch/arm/mach-bcmring/include/csp/stdint.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_STDINT_H
-#define CSP_STDINT_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_STDINT_H */
diff --git a/arch/arm/mach-bcmring/include/csp/string.h b/arch/arm/mach-bcmring/include/csp/string.h
deleted file mode 100644
index ad9e400..0000000
--- a/arch/arm/mach-bcmring/include/csp/string.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-
-#ifndef CSP_STRING_H
-#define CSP_STRING_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-   #include <linux/string.h>
-#else
-   #include <string.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_STRING_H */
-
diff --git a/arch/arm/mach-bcmring/include/csp/tmrHw.h b/arch/arm/mach-bcmring/include/csp/tmrHw.h
deleted file mode 100644
index 2cbb530..0000000
--- a/arch/arm/mach-bcmring/include/csp/tmrHw.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    tmrHw.h
-*
-*  @brief   API definitions for low level Timer driver
-*
-*/
-/****************************************************************************/
-#ifndef _TMRHW_H
-#define _TMRHW_H
-
-#include <csp/stdint.h>
-
-typedef uint32_t tmrHw_ID_t;	/* Timer ID */
-typedef uint32_t tmrHw_COUNT_t;	/* Timer count */
-typedef uint32_t tmrHw_INTERVAL_t;	/* Timer interval */
-typedef uint32_t tmrHw_RATE_t;	/* Timer event (count/interrupt) rate */
-
-typedef enum {
-	tmrHw_INTERRUPT_STATUS_SET,	/* Interrupted  */
-	tmrHw_INTERRUPT_STATUS_UNSET	/* No Interrupt */
-} tmrHw_INTERRUPT_STATUS_e;
-
-typedef enum {
-	tmrHw_CAPABILITY_CLOCK,	/* Clock speed in HHz */
-	tmrHw_CAPABILITY_RESOLUTION	/* Timer resolution in bits */
-} tmrHw_CAPABILITY_e;
-
-/****************************************************************************/
-/**
-*  @brief   Get timer capability
-*
-*  This function returns various capabilities/attributes of a timer
-*
-*  @return  Numeric capability
-*
-*/
-/****************************************************************************/
-uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-				  tmrHw_CAPABILITY_e capability	/*  [ IN ] Timer capability */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer in terms of timer interrupt rate
-*
-*  This function initializes a periodic timer to generate specific number of
-*  timer interrupt per second
-*
-*  @return   On success: Effective timer frequency
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-					tmrHw_RATE_t rate	/*  [ IN ] Number of timer interrupt per second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer to generate timer interrupt after
-*           certain time interval
-*
-*  This function initializes a periodic timer to generate timer interrupt
-*  after every time interval in millisecond
-*
-*  @return   On success: Effective interval set in mili-second
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-						tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer to generate timer interrupt just once
-*           after certain time interval
-*
-*  This function initializes a periodic timer to generate a single ticks after
-*  certain time interval in millisecond
-*
-*  @return   On success: Effective interval set in mili-second
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-					       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a timer to run as a free running timer
-*
-*  This function initializes a timer to run as a free running timer
-*
-*  @return   Timer resolution (count / sec)
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-				       uint32_t divider	/*  [ IN ] Dividing the clock frequency */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Starts a timer
-*
-*  This function starts a preconfigured timer
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*/
-/****************************************************************************/
-int tmrHw_startTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Stops a timer
-*
-*  This function stops a running timer
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*/
-/****************************************************************************/
-int tmrHw_stopTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Gets current timer count
-*
-*  This function returns the current timer value
-*
-*  @return  Current downcounting timer value
-*
-*/
-/****************************************************************************/
-tmrHw_COUNT_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Gets timer count rate
-*
-*  This function returns the number of counts per second
-*
-*  @return  Count rate
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Enables timer interrupt
-*
-*  This function enables the timer interrupt
-*
-*  @return   N/A
-*
-*/
-/****************************************************************************/
-void tmrHw_enableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Disables timer interrupt
-*
-*  This function disable the timer interrupt
-*
-*  @return   N/A
-*/
-/****************************************************************************/
-void tmrHw_disableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Clears the interrupt
-*
-*  This function clears the timer interrupt
-*
-*  @return   N/A
-*
-*  @note
-*     Must be called under the context of ISR
-*/
-/****************************************************************************/
-void tmrHw_clearInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Gets the interrupt status
-*
-*  This function returns timer interrupt status
-*
-*  @return   Interrupt status
-*/
-/****************************************************************************/
-tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Indentifies a timer causing interrupt
-*
-*  This functions returns a timer causing interrupt
-*
-*  @return  0xFFFFFFFF   : No timer causing an interrupt
-*           ! 0xFFFFFFFF : timer causing an interrupt
-*  @note
-*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
-*/
-/****************************************************************************/
-tmrHw_ID_t tmrHw_getInterruptSource(void);
-
-/****************************************************************************/
-/**
-*  @brief   Displays specific timer registers
-*
-*
-*  @return  void
-*
-*/
-/****************************************************************************/
-void tmrHw_printDebugInfo(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
-			  int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
-*
-*  @return   N/A
-*/
-/****************************************************************************/
-void tmrHw_udelay(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
-		  unsigned long usecs	/*  [ IN ] usec to delay */
-) __attribute__ ((section(".aramtext")));
-
-#endif /* _TMRHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/cfg_global.h b/arch/arm/mach-bcmring/include/mach/cfg_global.h
new file mode 100644
index 0000000..449133e
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/cfg_global.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+* Copyright 2006 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#ifndef CFG_GLOBAL_DEFINES_H
+#define CFG_GLOBAL_DEFINES_H
+
+/* CHIP */
+#define BCM1103 1
+
+#define BCM1191 4
+#define BCM2153 5
+#define BCM2820 6
+
+#define BCM2826 8
+#define FPGA11107 9
+#define BCM11107   10
+#define BCM11109   11
+#define BCM11170   12
+#define BCM11110   13
+#define BCM11211   14
+
+/* CFG_GLOBAL_CHIP_FAMILY types */
+#define CFG_GLOBAL_CHIP_FAMILY_NONE        0
+#define CFG_GLOBAL_CHIP_FAMILY_BCM116X     2
+#define CFG_GLOBAL_CHIP_FAMILY_BCMRING     4
+#define CFG_GLOBAL_CHIP_FAMILY_BCM1103     8
+
+#define IMAGE_HEADER_SIZE_CHECKSUM    4
+#endif
+#ifndef _CFG_GLOBAL_H_
+#define _CFG_GLOBAL_H_
+
+#define CFG_GLOBAL_CHIP                         BCM11107
+#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
+#define CFG_GLOBAL_CHIP_REV                     0xB0
+#define CFG_GLOBAL_RAM_SIZE                     0x10000000
+#define CFG_GLOBAL_RAM_BASE                     0x00000000
+#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
+
+#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h b/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
index 933ce68..0a89e0c 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
@@ -17,7 +17,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 #include <mach/csp/cap.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
 #define CAP_CONFIG0_VPM_DIS          0x00000001
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
index 1619733..39f09cb 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
@@ -17,9 +17,9 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 
 /* ---- Public Constants and Types ---------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
index 03238c2..a66f3f7 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
@@ -17,8 +17,8 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 #include <mach/csp/chipcHw_def.h>
 
@@ -47,7 +47,7 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipId(void)
 {
-	return pChipcHw->ChipId;
+	return readl(&pChipcHw->ChipId);
 }
 
 /****************************************************************************/
@@ -59,15 +59,16 @@
 /****************************************************************************/
 static inline void chipcHw_enableSpreadSpectrum(void)
 {
-	if ((pChipcHw->
-	     PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
+	if ((readl(&pChipcHw->
+	     PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
 	    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
-		ddrcReg_PHY_ADDR_CTL_REGP->ssCfg =
-		    (0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
+		writel((0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
 		    (ddrcReg_PHY_ADDR_SS_CFG_MIN_CYCLE_PER_TICK <<
-		     ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT);
-		ddrcReg_PHY_ADDR_CTL_REGP->ssCtl |=
-		    ddrcReg_PHY_ADDR_SS_CTRL_ENABLE;
+		     ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT),
+		     &ddrcReg_PHY_ADDR_CTL_REGP->ssCfg);
+		writel(readl(&ddrcReg_PHY_ADDR_CTL_REGP->ssCtl) |
+		    ddrcReg_PHY_ADDR_SS_CTRL_ENABLE,
+		    &ddrcReg_PHY_ADDR_CTL_REGP->ssCtl);
 	}
 }
 
@@ -93,8 +94,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipProductId(void)
 {
-	return (pChipcHw->
-		 ChipId & chipcHw_REG_CHIPID_BASE_MASK) >>
+	return (readl(&pChipcHw->
+		 ChipId) & chipcHw_REG_CHIPID_BASE_MASK) >>
 		chipcHw_REG_CHIPID_BASE_SHIFT;
 }
 
@@ -109,7 +110,7 @@
 /****************************************************************************/
 static inline chipcHw_REV_NUMBER_e chipcHw_getChipRevisionNumber(void)
 {
-	return pChipcHw->ChipId & chipcHw_REG_CHIPID_REV_MASK;
+	return readl(&pChipcHw->ChipId) & chipcHw_REG_CHIPID_REV_MASK;
 }
 
 /****************************************************************************/
@@ -156,7 +157,7 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getBusInterfaceClockStatus(void)
 {
-	return pChipcHw->BusIntfClock;
+	return readl(&pChipcHw->BusIntfClock);
 }
 
 /****************************************************************************/
@@ -215,8 +216,9 @@
 
 	/* Deassert module soft reset */
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->SoftReset1 ^= ctrl1;
-	pChipcHw->SoftReset2 ^= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+	writel(readl(&pChipcHw->SoftReset1) ^ ctrl1, &pChipcHw->SoftReset1);
+	writel(readl(&pChipcHw->SoftReset2) ^ (ctrl2 &
+		(~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -227,9 +229,10 @@
 	uint32_t unhold = 0;
 
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->SoftReset1 |= ctrl1;
+	writel(readl(&pChipcHw->SoftReset1) | ctrl1, &pChipcHw->SoftReset1);
 	/* Mask out unhold request bits */
-	pChipcHw->SoftReset2 |= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+	writel(readl(&pChipcHw->SoftReset2) | (ctrl2 &
+		(~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
 
 	/* Process unhold requests */
 	if (ctrl2 & chipcHw_REG_SOFT_RESET_VPM_GLOBAL_UNHOLD) {
@@ -246,7 +249,7 @@
 
 	if (unhold) {
 		/* Make sure unhold request is effective */
-		pChipcHw->SoftReset1 &= ~unhold;
+		writel(readl(&pChipcHw->SoftReset1) & ~unhold, &pChipcHw->SoftReset1);
 	}
 	REG_LOCAL_IRQ_RESTORE;
 }
@@ -307,7 +310,7 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getStickyBits(void)
 {
-	return pChipcHw->Sticky;
+	return readl(&pChipcHw->Sticky);
 }
 
 /****************************************************************************/
@@ -328,7 +331,7 @@
 		bits |= chipcHw_REG_STICKY_POR_BROM;
 	} else {
 		uint32_t sticky;
-		sticky = pChipcHw->Sticky;
+		sticky = readl(pChipcHw->Sticky);
 
 		if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
 		    && (sticky & chipcHw_REG_STICKY_BOOT_DONE) == 0) {
@@ -355,7 +358,7 @@
 			bits |= chipcHw_REG_STICKY_GENERAL_5;
 		}
 	}
-	pChipcHw->Sticky = bits;
+	writel(bits, pChipcHw->Sticky);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -377,7 +380,7 @@
 	    (chipcHw_REG_STICKY_BOOT_DONE | chipcHw_REG_STICKY_GENERAL_1 |
 	     chipcHw_REG_STICKY_GENERAL_2 | chipcHw_REG_STICKY_GENERAL_3 |
 	     chipcHw_REG_STICKY_GENERAL_4 | chipcHw_REG_STICKY_GENERAL_5)) {
-		uint32_t sticky = pChipcHw->Sticky;
+		uint32_t sticky = readl(&pChipcHw->Sticky);
 
 		if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
 		    && (sticky & chipcHw_REG_STICKY_BOOT_DONE)) {
@@ -410,7 +413,7 @@
 			mask &= ~chipcHw_REG_STICKY_GENERAL_5;
 		}
 	}
-	pChipcHw->Sticky = bits | mask;
+	writel(bits | mask, &pChipcHw->Sticky);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -426,7 +429,7 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getSoftStraps(void)
 {
-	return pChipcHw->SoftStraps;
+	return readl(&pChipcHw->SoftStraps);
 }
 
 /****************************************************************************/
@@ -456,7 +459,7 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getPinStraps(void)
 {
-	return pChipcHw->PinStraps;
+	return readl(&pChipcHw->PinStraps);
 }
 
 /****************************************************************************/
@@ -671,9 +674,9 @@
 /****************************************************************************/
 static inline chipcHw_GPIO_FUNCTION_e chipcHw_getGpioPinFunction(int pin)
 {
-	return (*((uint32_t *) chipcHw_REG_GPIO_MUX(pin)) &
+	return (readl(chipcHw_REG_GPIO_MUX(pin))) &
 		(chipcHw_REG_GPIO_MUX_MASK <<
-		 chipcHw_REG_GPIO_MUX_POSITION(pin))) >>
+		 chipcHw_REG_GPIO_MUX_POSITION(pin)) >>
 	    chipcHw_REG_GPIO_MUX_POSITION(pin);
 }
 
@@ -841,8 +844,8 @@
 static inline void chipcHw_setClock(chipcHw_CLOCK_e clock,
 				    chipcHw_OPTYPE_e type, int mode)
 {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
 
 	switch (clock) {
 	case chipcHw_CLOCK_DDR:
@@ -1071,7 +1074,7 @@
 /****************************************************************************/
 static inline int chipcHw_isSoftwareStrapsEnable(void)
 {
-	return pChipcHw->SoftStraps & 0x00000001;
+	return readl(&pChipcHw->SoftStraps) & 0x00000001;
 }
 
 /****************************************************************************/
@@ -1138,7 +1141,7 @@
 /****************************************************************************/
 static inline int chipcHw_isPllTestEnable(void)
 {
-	return pChipcHw->PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+	return readl(&pChipcHw->PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1147,7 +1150,7 @@
 /****************************************************************************/
 static inline int chipcHw_isPll2TestEnable(void)
 {
-	return pChipcHw->PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+	return readl(&pChipcHw->PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1183,8 +1186,8 @@
 /****************************************************************************/
 static inline uint8_t chipcHw_getPllTestSelected(void)
 {
-	return (uint8_t) ((pChipcHw->
-			   PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+	return (uint8_t) ((readl(&pChipcHw->
+			   PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
 			  >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1194,8 +1197,8 @@
 /****************************************************************************/
 static inline uint8_t chipcHw_getPll2TestSelected(void)
 {
-	return (uint8_t) ((pChipcHw->
-			   PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+	return (uint8_t) ((readl(&pChipcHw->
+			   PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
 			  >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1208,7 +1211,8 @@
 static inline void chipcHw_pll1Disable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->PLLConfig |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+	writel(readl(&pChipcHw->PLLConfig) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+		&pChipcHw->PLLConfig);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1221,7 +1225,8 @@
 static inline void chipcHw_pll2Disable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->PLLConfig2 |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+	writel(readl(&pChipcHw->PLLConfig2) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+		&pChipcHw->PLLConfig2);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1233,7 +1238,8 @@
 static inline void chipcHw_ddrPhaseAlignInterruptEnable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->Spare1 |= chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+	writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+		&pChipcHw->Spare1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1245,7 +1251,8 @@
 static inline void chipcHw_ddrPhaseAlignInterruptDisable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+	writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+		&pChipcHw->Spare1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1333,7 +1340,8 @@
 static inline void chipcHw_vpmSwPhaseAlignEnable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->VPMPhaseCtrl1 |= chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE;
+	writel(readl(&pChipcHw->VPMPhaseCtrl1) | chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE,
+			&pChipcHw->VPMPhaseCtrl1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1372,7 +1380,8 @@
 static inline void chipcHw_vpmHwPhaseAlignDisable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->VPMPhaseCtrl1 &= ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE;
+	writel(readl(&pChipcHw->VPMPhaseCtrl1) & ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE,
+		&pChipcHw->VPMPhaseCtrl1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1474,8 +1483,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_isDdrHwPhaseAligned(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1488,8 +1497,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_isVpmHwPhaseAligned(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1500,8 +1509,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrHwPhaseAlignStatus(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
 	    chipcHw_REG_DDR_PHASE_STATUS_SHIFT;
 }
 
@@ -1513,8 +1522,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmHwPhaseAlignStatus(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
 	    chipcHw_REG_VPM_PHASE_STATUS_SHIFT;
 }
 
@@ -1526,8 +1535,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrPhaseControl(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
 	    chipcHw_REG_DDR_PHASE_CTRL_SHIFT;
 }
 
@@ -1539,8 +1548,8 @@
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmPhaseControl(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
 	    chipcHw_REG_VPM_PHASE_CTRL_SHIFT;
 }
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
index b162448..26f5d0e 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
@@ -24,7 +24,7 @@
 #define CHIPCHW_REG_H
 
 #include <mach/csp/mm_io.h>
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/ddrcReg.h>
 
 #define chipcHw_BASE_ADDRESS    MM_IO_BASE_CHIPC
@@ -131,8 +131,8 @@
 	uint32_t MiscInput_0_15;	/* Input type for MISC 0 - 16 */
 } chipcHw_REG_t;
 
-#define pChipcHw  ((volatile chipcHw_REG_t *) chipcHw_BASE_ADDRESS)
-#define pChipcPhysical  ((volatile chipcHw_REG_t *) MM_ADDR_IO_CHIPC)
+#define pChipcHw  ((chipcHw_REG_t __iomem *) chipcHw_BASE_ADDRESS)
+#define pChipcPhysical  (MM_ADDR_IO_CHIPC)
 
 #define chipcHw_REG_CHIPID_BASE_MASK                    0xFFFFF000
 #define chipcHw_REG_CHIPID_BASE_SHIFT                   12
diff --git a/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h b/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
index f1b68e2..39da2c1 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
@@ -30,8 +30,8 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/reg.h>
-#include <csp/stdint.h>
+#include <mach/csp/reg.h>
+#include <linux/types.h>
 
 #include <mach/csp/mm_io.h>
 
@@ -416,7 +416,7 @@
 	} ddrcReg_PHY_ADDR_CTL_REG_t;
 
 #define ddrcReg_PHY_ADDR_CTL_REG_OFFSET                 0x0400
-#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t *) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
+#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t __iomem*) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
 
 /* @todo These SS definitions are duplicates of ones below */
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
new file mode 100644
index 0000000..9dc90f46
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
@@ -0,0 +1,596 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    dmacHw.h
+*
+*  @brief   API definitions for low level DMA controller driver
+*
+*/
+/****************************************************************************/
+#ifndef _DMACHW_H
+#define _DMACHW_H
+
+#include <linux/stddef.h>
+
+#include <linux/types.h>
+#include <mach/csp/dmacHw_reg.h>
+
+/* Define DMA Channel ID using DMA controller number (m) and channel number (c).
+
+   System specific channel ID should be defined as follows
+
+   For example:
+
+   #include <dmacHw.h>
+   ...
+   #define systemHw_LCD_CHANNEL_ID                dmacHw_MAKE_CHANNEL_ID(0,5)
+   #define systemHw_SWITCH_RX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,0)
+   #define systemHw_SWITCH_TX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,1)
+   #define systemHw_APM_RX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,3)
+   #define systemHw_APM_TX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,4)
+   ...
+   #define systemHw_SHARED1_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,4)
+   #define systemHw_SHARED2_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,5)
+   #define systemHw_SHARED3_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(0,6)
+   ...
+*/
+#define dmacHw_MAKE_CHANNEL_ID(m, c)         (m << 8 | c)
+
+typedef enum {
+	dmacHw_CHANNEL_PRIORITY_0 = dmacHw_REG_CFG_LO_CH_PRIORITY_0,	/* Channel priority 0. Lowest priority DMA channel */
+	dmacHw_CHANNEL_PRIORITY_1 = dmacHw_REG_CFG_LO_CH_PRIORITY_1,	/* Channel priority 1 */
+	dmacHw_CHANNEL_PRIORITY_2 = dmacHw_REG_CFG_LO_CH_PRIORITY_2,	/* Channel priority 2 */
+	dmacHw_CHANNEL_PRIORITY_3 = dmacHw_REG_CFG_LO_CH_PRIORITY_3,	/* Channel priority 3 */
+	dmacHw_CHANNEL_PRIORITY_4 = dmacHw_REG_CFG_LO_CH_PRIORITY_4,	/* Channel priority 4 */
+	dmacHw_CHANNEL_PRIORITY_5 = dmacHw_REG_CFG_LO_CH_PRIORITY_5,	/* Channel priority 5 */
+	dmacHw_CHANNEL_PRIORITY_6 = dmacHw_REG_CFG_LO_CH_PRIORITY_6,	/* Channel priority 6 */
+	dmacHw_CHANNEL_PRIORITY_7 = dmacHw_REG_CFG_LO_CH_PRIORITY_7	/* Channel priority 7. Highest priority DMA channel */
+} dmacHw_CHANNEL_PRIORITY_e;
+
+/* Source destination master interface */
+typedef enum {
+	dmacHw_SRC_MASTER_INTERFACE_1 = dmacHw_REG_CTL_SMS_1,	/* Source DMA master interface 1 */
+	dmacHw_SRC_MASTER_INTERFACE_2 = dmacHw_REG_CTL_SMS_2,	/* Source DMA master interface 2 */
+	dmacHw_DST_MASTER_INTERFACE_1 = dmacHw_REG_CTL_DMS_1,	/* Destination DMA master interface 1 */
+	dmacHw_DST_MASTER_INTERFACE_2 = dmacHw_REG_CTL_DMS_2	/* Destination DMA master interface 2 */
+} dmacHw_MASTER_INTERFACE_e;
+
+typedef enum {
+	dmacHw_SRC_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_SRC_TR_WIDTH_8,	/* Source 8 bit  (1 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_SRC_TR_WIDTH_16,	/* Source 16 bit (2 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_SRC_TR_WIDTH_32,	/* Source 32 bit (4 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_SRC_TR_WIDTH_64,	/* Source 64 bit (8 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_DST_TR_WIDTH_8,	/* Destination 8 bit  (1 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_DST_TR_WIDTH_16,	/* Destination 16 bit (2 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_DST_TR_WIDTH_32,	/* Destination 32 bit (4 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_DST_TR_WIDTH_64	/* Destination 64 bit (8 byte) per transaction */
+} dmacHw_TRANSACTION_WIDTH_e;
+
+typedef enum {
+	dmacHw_SRC_BURST_WIDTH_0 = dmacHw_REG_CTL_SRC_MSIZE_0,	/* Source No burst */
+	dmacHw_SRC_BURST_WIDTH_4 = dmacHw_REG_CTL_SRC_MSIZE_4,	/* Source 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_SRC_BURST_WIDTH_8 = dmacHw_REG_CTL_SRC_MSIZE_8,	/* Source 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_SRC_BURST_WIDTH_16 = dmacHw_REG_CTL_SRC_MSIZE_16,	/* Source 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_0 = dmacHw_REG_CTL_DST_MSIZE_0,	/* Destination No burst */
+	dmacHw_DST_BURST_WIDTH_4 = dmacHw_REG_CTL_DST_MSIZE_4,	/* Destination 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_8 = dmacHw_REG_CTL_DST_MSIZE_8,	/* Destination 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_16 = dmacHw_REG_CTL_DST_MSIZE_16	/* Destination 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+} dmacHw_BURST_WIDTH_e;
+
+typedef enum {
+	dmacHw_TRANSFER_TYPE_MEM_TO_MEM = dmacHw_REG_CTL_TTFC_MM_DMAC,	/* Memory to memory transfer */
+	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM = dmacHw_REG_CTL_TTFC_PM_DMAC,	/* Peripheral to memory transfer */
+	dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_MP_DMAC,	/* Memory to peripheral transfer */
+	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_PP_DMAC	/* Peripheral to peripheral transfer */
+} dmacHw_TRANSFER_TYPE_e;
+
+typedef enum {
+	dmacHw_TRANSFER_MODE_PERREQUEST,	/* Block transfer per DMA request */
+	dmacHw_TRANSFER_MODE_CONTINUOUS,	/* Continuous transfer of streaming data */
+	dmacHw_TRANSFER_MODE_PERIODIC	/* Periodic transfer of streaming data */
+} dmacHw_TRANSFER_MODE_e;
+
+typedef enum {
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_SINC_INC,	/* Increment source address after every transaction */
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_SINC_DEC,	/* Decrement source address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_DINC_INC,	/* Increment destination address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_DINC_DEC,	/* Decrement destination address after every transaction */
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_SINC_NC,	/* No change in source address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_DINC_NC	/* No change in destination address after every transaction */
+} dmacHw_ADDRESS_UPDATE_MODE_e;
+
+typedef enum {
+	dmacHw_FLOW_CONTROL_DMA,	/* DMA working as flow controller (default) */
+	dmacHw_FLOW_CONTROL_PERIPHERAL	/* Peripheral working as flow controller */
+} dmacHw_FLOW_CONTROL_e;
+
+typedef enum {
+	dmacHw_TRANSFER_STATUS_BUSY,	/* DMA Transfer ongoing */
+	dmacHw_TRANSFER_STATUS_DONE,	/* DMA Transfer completed */
+	dmacHw_TRANSFER_STATUS_ERROR	/* DMA Transfer error */
+} dmacHw_TRANSFER_STATUS_e;
+
+typedef enum {
+	dmacHw_INTERRUPT_DISABLE,	/* Interrupt disable  */
+	dmacHw_INTERRUPT_ENABLE	/* Interrupt enable */
+} dmacHw_INTERRUPT_e;
+
+typedef enum {
+	dmacHw_INTERRUPT_STATUS_NONE = 0x0,	/* No DMA interrupt */
+	dmacHw_INTERRUPT_STATUS_TRANS = 0x1,	/* End of DMA transfer interrupt */
+	dmacHw_INTERRUPT_STATUS_BLOCK = 0x2,	/* End of block transfer interrupt */
+	dmacHw_INTERRUPT_STATUS_ERROR = 0x4	/* Error interrupt */
+} dmacHw_INTERRUPT_STATUS_e;
+
+typedef enum {
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM,	/* Number of DMA channel */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE,	/* Maximum channel burst size */
+	dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM,	/* Number of DMA master interface */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH,	/* Channel Data bus width */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE	/* Channel FIFO size */
+} dmacHw_CONTROLLER_ATTRIB_e;
+
+typedef unsigned long dmacHw_HANDLE_t;	/* DMA channel handle */
+typedef uint32_t dmacHw_ID_t;	/* DMA channel Id.  Must be created using
+				   "dmacHw_MAKE_CHANNEL_ID" macro
+				 */
+/* DMA channel configuration parameters */
+typedef struct {
+	uint32_t srcPeripheralPort;	/* Source peripheral port */
+	uint32_t dstPeripheralPort;	/* Destination peripheral port */
+	uint32_t srcStatusRegisterAddress;	/* Source status register address */
+	uint32_t dstStatusRegisterAddress;	/* Destination status register address of type  */
+
+	uint32_t srcGatherWidth;	/* Number of bytes gathered before successive gather opearation */
+	uint32_t srcGatherJump;	/* Number of bytes jumpped before successive gather opearation */
+	uint32_t dstScatterWidth;	/* Number of bytes sacattered before successive scatter opearation */
+	uint32_t dstScatterJump;	/* Number of bytes jumpped  before successive scatter opearation */
+	uint32_t maxDataPerBlock;	/* Maximum number of bytes to be transferred per block/descrptor.
+					   0 = Maximum possible.
+					 */
+
+	dmacHw_ADDRESS_UPDATE_MODE_e srcUpdate;	/* Source address update mode */
+	dmacHw_ADDRESS_UPDATE_MODE_e dstUpdate;	/* Destination address update mode */
+	dmacHw_TRANSFER_TYPE_e transferType;	/* DMA transfer type  */
+	dmacHw_TRANSFER_MODE_e transferMode;	/* DMA transfer mode */
+	dmacHw_MASTER_INTERFACE_e srcMasterInterface;	/* DMA source interface  */
+	dmacHw_MASTER_INTERFACE_e dstMasterInterface;	/* DMA destination interface */
+	dmacHw_TRANSACTION_WIDTH_e srcMaxTransactionWidth;	/* Source transaction width   */
+	dmacHw_TRANSACTION_WIDTH_e dstMaxTransactionWidth;	/* Destination transaction width */
+	dmacHw_BURST_WIDTH_e srcMaxBurstWidth;	/* Source burst width */
+	dmacHw_BURST_WIDTH_e dstMaxBurstWidth;	/* Destination burst width */
+	dmacHw_INTERRUPT_e blockTransferInterrupt;	/* Block trsnafer interrupt */
+	dmacHw_INTERRUPT_e completeTransferInterrupt;	/* Complete DMA trsnafer interrupt */
+	dmacHw_INTERRUPT_e errorInterrupt;	/* Error interrupt */
+	dmacHw_CHANNEL_PRIORITY_e channelPriority;	/* Channel priority */
+	dmacHw_FLOW_CONTROL_e flowControler;	/* Data flow controller */
+} dmacHw_CONFIG_t;
+
+/****************************************************************************/
+/**
+*  @brief   Initializes DMA
+*
+*  This function initializes DMA CSP driver
+*
+*  @note
+*     Must be called before using any DMA channel
+*/
+/****************************************************************************/
+void dmacHw_initDma(void);
+
+/****************************************************************************/
+/**
+*  @brief   Exit function for  DMA
+*
+*  This function isolates DMA from the system
+*
+*/
+/****************************************************************************/
+void dmacHw_exitDma(void);
+
+/****************************************************************************/
+/**
+*  @brief   Gets a handle to a DMA channel
+*
+*  This function returns a handle, representing a control block of a particular DMA channel
+*
+*  @return  -1       - On Failure
+*            handle  - On Success, representing a channel control block
+*
+*  @note
+*     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
+*/
+/****************************************************************************/
+dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId	/* [ IN ] DMA Channel Id */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Initializes a DMA channel for use
+*
+*  This function initializes and resets a DMA channel for use
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_initChannel(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief  Estimates number of descriptor needed to perform certain DMA transfer
+*
+*
+*  @return  On failure : -1
+*           On success : Number of descriptor count
+*
+*
+*/
+/****************************************************************************/
+int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
+				    void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
+				    void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
+				    size_t dataLen	/*   [ IN ] Data length in bytes */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Initializes descriptor ring
+*
+*  This function will initializes the descriptor ring of a DMA channel
+*
+*
+*  @return   -1 - On failure
+*             0 - On success
+*  @note
+*     - "len" parameter should be obtained from "dmacHw_descriptorLen"
+*     - Descriptor buffer MUST be 32 bit aligned and uncached as it
+*       is accessed by ARM and DMA
+*/
+/****************************************************************************/
+int dmacHw_initDescriptor(void *pDescriptorVirt,	/*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
+			  uint32_t descriptorPhyAddr,	/*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
+			  uint32_t len,	/*  [ IN ] Size of the pBuf */
+			  uint32_t num	/*  [ IN ] Number of descriptor in the ring */
+    );
+
+/****************************************************************************/
+/**
+*  @brief  Finds amount of memory required to form a descriptor ring
+*
+*
+*  @return   Number of bytes required to form a descriptor ring
+*
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+uint32_t dmacHw_descriptorLen(uint32_t descCnt	/*  [ IN ] Number of descriptor in the ring */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Configure DMA channel
+*
+*  @return  0  : On success
+*           -1 : On failure
+*/
+/****************************************************************************/
+int dmacHw_configChannel(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			 dmacHw_CONFIG_t *pConfig	/*   [ IN ] Configuration settings */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Set descriptors for known data length
+*
+*  When DMA has to work as a flow controller, this function prepares the
+*  descriptor chain to transfer data
+*
+*  from:
+*          - Memory to memory
+*          - Peripheral to memory
+*          - Memory to Peripheral
+*          - Peripheral to Peripheral
+*
+*  @return   -1 - On failure
+*             0 - On success
+*
+*/
+/****************************************************************************/
+int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+			     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			     void *pSrcAddr,	/*  [ IN ] Source (Peripheral/Memory) address */
+			     void *pDstAddr,	/*  [ IN ] Destination (Peripheral/Memory) address */
+			     size_t dataLen	/*  [ IN ] Length in bytes   */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Indicates whether DMA transfer is in progress or completed
+*
+*  @return   DMA transfer status
+*          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
+*          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
+*          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
+*
+*/
+/****************************************************************************/
+dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Set descriptor carrying control information
+*
+*  This function will be used to send specific control information to the device
+*  using the DMA channel
+*
+*
+*  @return  -1 - On failure
+*            0 - On success
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+				void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+				uint32_t ctlAddress,	/*  [ IN ] Address of the device control register  */
+				uint32_t control	/*  [ IN ] Device control information */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Read data DMA transferred to memory
+*
+*  This function will read data that has been DMAed to memory while transferring from:
+*          - Memory to memory
+*          - Peripheral to memory
+*
+*  @return  0 - No more data is available to read
+*           1 - More data might be available to read
+*
+*/
+/****************************************************************************/
+int dmacHw_readTransferredData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle    */
+			       dmacHw_CONFIG_t *pConfig,	/*  [ IN ]  Configuration settings */
+			       void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			       void **ppBbuf,	/*  [ OUT ] Data received */
+			       size_t *pLlen	/*  [ OUT ] Length of the data received */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
+*
+*  This function will form the descriptor ring by allocating buffers, when source peripheral
+*  has to work as a flow controller to transfer data from:
+*           - Peripheral to memory.
+*
+*  @return  -1 - On failure
+*            0 - On success
+*
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle   */
+				     dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+				     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+				     uint32_t srcAddr,	/*  [ IN ] Source peripheral address */
+				     void *(*fpAlloc) (int len),	/*  [ IN ] Function pointer  that provides destination memory */
+				     int len,	/*  [ IN ] Number of bytes "fpAlloc" will allocate for destination */
+				     int num	/*  [ IN ] Number of descriptor to set */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Program channel register to initiate transfer
+*
+*  @return  void
+*
+*
+*  @note
+*     - Descriptor buffer MUST ALWAYS be flushed before calling this function
+*     - This function should also be called from ISR to program the channel with
+*       pending descriptors
+*/
+/****************************************************************************/
+void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
+			     dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
+			     void *pDescriptor	/*   [ IN ] Descriptor buffer  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Resets descriptor control information
+*
+*  @return  void
+*/
+/****************************************************************************/
+void dmacHw_resetDescriptorControl(void *pDescriptor	/*   [ IN ] Descriptor buffer  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Program channel register to stop transfer
+*
+*  Ensures the channel is not doing any transfer after calling this function
+*
+*  @return  void
+*
+*/
+/****************************************************************************/
+void dmacHw_stopTransfer(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Check the existence of pending descriptor
+*
+*  This function confirmes if there is any pending descriptor in the chain
+*  to program the channel
+*
+*  @return  1 : Channel need to be programmed with pending descriptor
+*           0 : No more pending descriptor to programe the channel
+*
+*  @note
+*     - This function should be called from ISR in case there are pending
+*       descriptor to program the channel.
+*
+*     Example:
+*
+*     dmac_isr ()
+*     {
+*         ...
+*         if (dmacHw_descriptorPending (handle))
+*         {
+*            dmacHw_initiateTransfer (handle);
+*         }
+*     }
+*
+*/
+/****************************************************************************/
+uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
+				  void *pDescriptor	/*   [ IN ] Descriptor buffer */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Deallocates source or destination memory, allocated
+*
+*  This function can be called to deallocate data memory that was DMAed successfully
+*
+*  @return  -1  - On failure
+*            0  - On success
+*
+*  @note
+*     This function will be called ONLY, when source OR destination address is pointing
+*     to dynamic memory
+*/
+/****************************************************************************/
+int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+		   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+		   void (*fpFree) (void *)	/*  [ IN ] Function pointer to free data memory */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Clears the interrupt
+*
+*  This function clears the DMA channel specific interrupt
+*
+*  @return   N/A
+*
+*  @note
+*     Must be called under the context of ISR
+*/
+/****************************************************************************/
+void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Returns the cause of channel specific DMA interrupt
+*
+*  This function returns the cause of interrupt
+*
+*  @return  Interrupt status, each bit representing a specific type of interrupt
+*           of type dmacHw_INTERRUPT_STATUS_e
+*  @note
+*           This function should be called under the context of ISR
+*/
+/****************************************************************************/
+dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Indentifies a DMA channel causing interrupt
+*
+*  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
+*
+*  @return  NULL   : No channel causing DMA interrupt
+*           ! NULL : Handle to a channel causing DMA interrupt
+*  @note
+*     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
+*/
+/****************************************************************************/
+dmacHw_HANDLE_t dmacHw_getInterruptSource(void);
+
+/****************************************************************************/
+/**
+*  @brief   Sets channel specific user data
+*
+*  This function associates user data to a specific DMA channel
+*
+*/
+/****************************************************************************/
+void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			       void *userData	/*  [ IN ] User data  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Gets channel specific user data
+*
+*  This function returns user data specific to a DMA channel
+*
+*  @return   user data
+*/
+/****************************************************************************/
+void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Displays channel specific registers and other control parameters
+*
+*
+*  @return  void
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			   int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Provides DMA controller attributes
+*
+*
+*  @return  DMA controller attributes
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,	/*  [ IN ]  DMA Channel handle  */
+					  dmacHw_CONTROLLER_ATTRIB_e attr	/*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
+    );
+
+#endif /* _DMACHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
index d67e2f8..9d9455e 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_PRIV_H
 #define _DMACHW_PRIV_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 
 /* Data type for DMA Link List Item */
 typedef struct {
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
index f1ecf96..7cd0aaf 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_REG_H
 #define _DMACHW_REG_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/mm_io.h>
 
 /* Data type for 64 bit little endian register */
@@ -121,75 +121,75 @@
 } dmacHw_MISC_t;
 
 /* Base registers */
-#define dmacHw_0_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA0	/* DMAC 0 module's base address */
-#define dmacHw_1_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA1	/* DMAC 1 module's base address */
+#define dmacHw_0_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA0	/* DMAC 0 module's base address */
+#define dmacHw_1_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA1	/* DMAC 1 module's base address */
 
 extern uint32_t dmaChannelCount_0;
 extern uint32_t dmaChannelCount_1;
 
 /* Define channel specific registers */
-#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t *) ((char *)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
+#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t __iomem*) ((char __iomem*)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
 
 /* Raw interrupt status registers */
-#define dmacHw_REG_INT_RAW_BASE(module)         ((char *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
-#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
-#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
-#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
-#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
-#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
+#define dmacHw_REG_INT_RAW_BASE(module)         ((char __iomem *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
+#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
+#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
+#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
+#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
+#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_STAT_BASE(module)        ((char *)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
-#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
-#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
-#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
-#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
-#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
+#define dmacHw_REG_INT_STAT_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
+#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
+#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
+#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
+#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
+#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_MASK_BASE(module)        ((char *)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
-#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
-#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
-#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
-#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
-#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
+#define dmacHw_REG_INT_MASK_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
+#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
+#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
+#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
+#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
+#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
 
 /* Interrupt clear registers */
-#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char *)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
-#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
-#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
-#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
-#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
-#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
-#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
+#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char __iomem*)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
+#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
+#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
+#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
+#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
+#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
+#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
 
 /* Software handshaking registers */
-#define dmacHw_REG_SW_HS_BASE(module)           ((char *)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
-#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
+#define dmacHw_REG_SW_HS_BASE(module)           ((char __iomem*)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
+#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
 
 /* Miscellaneous registers */
-#define dmacHw_REG_MISC_BASE(module)            ((char *)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
-#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
-#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
-#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
-#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
-#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
-#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
-#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
-#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
-#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
-#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
-#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
-#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
-#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
-#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
+#define dmacHw_REG_MISC_BASE(module)            ((char __iomem*)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
+#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
+#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
+#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
+#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
+#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
+#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
+#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
+#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
+#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
+#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
+#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
+#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
+#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
+#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
 
 /* Channel control registers */
 #define dmacHw_REG_SAR(module, chan)            (dmacHw_CHAN_BASE((module), (chan))->ChannelSar.lo)
diff --git a/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h b/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
index cfa91be..27f59dd 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
@@ -18,7 +18,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/cap_inline.h>
 
 #if defined(__KERNEL__)
diff --git a/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
index 0aeb6a6..f59db25 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
@@ -27,8 +27,8 @@
 #define _INTCHW_REG_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -37,9 +37,9 @@
 #define INTCHW_NUM_INTC           3
 
 /* Defines for interrupt controllers. This simplifies and cleans up the function calls. */
-#define INTCHW_INTC0    ((void *)MM_IO_BASE_INTC0)
-#define INTCHW_INTC1    ((void *)MM_IO_BASE_INTC1)
-#define INTCHW_SINTC    ((void *)MM_IO_BASE_SINTC)
+#define INTCHW_INTC0    (MM_IO_BASE_INTC0)
+#define INTCHW_INTC1    (MM_IO_BASE_INTC1)
+#define INTCHW_SINTC    (MM_IO_BASE_SINTC)
 
 /* INTC0 - interrupt controller 0 */
 #define INTCHW_INTC0_PIF_BITNUM           31	/* Peripheral interface interrupt */
@@ -232,15 +232,15 @@
 /* ---- Public Variable Externs ------------------------------------------ */
 /* ---- Public Function Prototypes --------------------------------------- */
 /* Clear one or more IRQ interrupts. */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask)
+static inline void intcHw_irq_disable(void __iomem *basep, uint32_t mask)
 {
-	__REG32(basep + INTCHW_INTENCLEAR) = mask;
+	writel(mask, basep + INTCHW_INTENCLEAR);
 }
 
 /* Enables one or more IRQ interrupts. */
-static inline void intcHw_irq_enable(void *basep, uint32_t mask)
+static inline void intcHw_irq_enable(void __iomem *basep, uint32_t mask)
 {
-	__REG32(basep + INTCHW_INTENABLE) = mask;
+	writel(mask, basep + INTCHW_INTENABLE);
 }
 
 #endif /* _INTCHW_REG_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
index ad58cf8..d571962 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
@@ -29,7 +29,7 @@
 /* ---- Include Files ---------------------------------------------------- */
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/mm_io.h b/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
index de92ec6..47450c2 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
@@ -30,7 +30,7 @@
 #include <mach/csp/mm_addr.h>
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -49,7 +49,7 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_PHYS_TO_VIRT(phys)       (0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF))
 #else
-#define MM_IO_PHYS_TO_VIRT(phys)       (((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
+#define MM_IO_PHYS_TO_VIRT(phys)       (void __iomem *)(((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
 			(0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF)))
 #endif
 #endif
@@ -60,8 +60,8 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_VIRT_TO_PHYS(virt)       ((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF))
 #else
-#define MM_IO_VIRT_TO_PHYS(virt)       (((virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
-			((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF)))
+#define MM_IO_VIRT_TO_PHYS(virt)       (((unsigned long)(virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
+			((((unsigned long)(virt) & 0x0F000000) << 4) | ((unsigned long)(virt) & 0xFFFFFF)))
 #endif
 #endif
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/reg.h b/arch/arm/mach-bcmring/include/mach/csp/reg.h
new file mode 100644
index 0000000..d9cbdca
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/reg.h
@@ -0,0 +1,115 @@
+/*****************************************************************************
+* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    reg.h
+*
+*  @brief   Generic register definitions used in CSP
+*/
+/****************************************************************************/
+
+#ifndef CSP_REG_H
+#define CSP_REG_H
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/* ---- Public Constants and Types --------------------------------------- */
+
+#define __REG32(x)      (*((volatile uint32_t __iomem *)(x)))
+#define __REG16(x)      (*((volatile uint16_t __iomem *)(x)))
+#define __REG8(x)       (*((volatile uint8_t __iomem *) (x)))
+
+/* Macros used to define a sequence of reserved registers. The start / end */
+/* are byte offsets in the particular register definition, with the "end" */
+/* being the offset of the next un-reserved register. E.g. if offsets */
+/* 0x10 through to 0x1f are reserved, then this reserved area could be */
+/* specified as follows. */
+/*  typedef struct */
+/*  { */
+/*      uint32_t reg1;           offset 0x00 */
+/*      uint32_t reg2;           offset 0x04 */
+/*      uint32_t reg3;           offset 0x08 */
+/*      uint32_t reg4;           offset 0x0c */
+/*      REG32_RSVD(0x10, 0x20); */
+/*      uint32_t reg5;           offset 0x20 */
+/*      ... */
+/*  } EXAMPLE_REG_t; */
+#define REG8_RSVD(start, end)   uint8_t rsvd_##start[(end - start) / sizeof(uint8_t)]
+#define REG16_RSVD(start, end)  uint16_t rsvd_##start[(end - start) / sizeof(uint16_t)]
+#define REG32_RSVD(start, end)  uint32_t rsvd_##start[(end - start) / sizeof(uint32_t)]
+
+/* ---- Public Variable Externs ------------------------------------------ */
+/* ---- Public Function Prototypes --------------------------------------- */
+
+/* Note: When protecting multiple statements, the REG_LOCAL_IRQ_SAVE and */
+/* REG_LOCAL_IRQ_RESTORE must be enclosed in { } to allow the  */
+/* flags variable to be declared locally. */
+/* e.g. */
+/*    statement1; */
+/*    { */
+/*       REG_LOCAL_IRQ_SAVE; */
+/*       <multiple statements here> */
+/*       REG_LOCAL_IRQ_RESTORE; */
+/*    } */
+/*    statement2; */
+/*  */
+
+#if defined(__KERNEL__) && !defined(STANDALONE)
+#include <mach/hardware.h>
+#include <linux/interrupt.h>
+
+#define REG_LOCAL_IRQ_SAVE      HW_DECLARE_SPINLOCK(reg32) \
+	unsigned long flags; HW_IRQ_SAVE(reg32, flags)
+
+#define REG_LOCAL_IRQ_RESTORE   HW_IRQ_RESTORE(reg32, flags)
+
+#else
+
+#define REG_LOCAL_IRQ_SAVE
+#define REG_LOCAL_IRQ_RESTORE
+
+#endif
+
+static inline void reg32_modify_and(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel(__raw_readl(reg) & value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_modify_or(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel(__raw_readl(reg) | value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_modify_mask(volatile uint32_t __iomem *reg, uint32_t mask,
+				     uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel((__raw_readl(reg) & mask) | value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_write(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	__raw_writel(value, reg);
+}
+
+#endif /* CSP_REG_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h b/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
index 9cd6a03..55d3cd4 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
@@ -34,7 +34,7 @@
 /****************************************************************************/
 static inline void secHw_setSecure(uint32_t mask	/*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	if (mask & 0x0000FFFF) {
 		regp->reg[secHw_IDX_LS].setSecure = mask & 0x0000FFFF;
@@ -53,13 +53,13 @@
 /****************************************************************************/
 static inline void secHw_setUnsecure(uint32_t mask	/*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	if (mask & 0x0000FFFF) {
-		regp->reg[secHw_IDX_LS].setUnsecure = mask & 0x0000FFFF;
+		writel(mask & 0x0000FFFF, &regp->reg[secHw_IDX_LS].setUnsecure);
 	}
 	if (mask & 0xFFFF0000) {
-		regp->reg[secHw_IDX_MS].setUnsecure = mask >> 16;
+		writel(mask >> 16, &regp->reg[secHw_IDX_MS].setUnsecure);
 	}
 }
 
@@ -71,7 +71,7 @@
 /****************************************************************************/
 static inline uint32_t secHw_getStatus(void)
 {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	return (regp->reg[1].status << 16) + regp->reg[0].status;
 }
diff --git a/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h b/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
new file mode 100644
index 0000000..1cc882a
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
@@ -0,0 +1,263 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    tmrHw.h
+*
+*  @brief   API definitions for low level Timer driver
+*
+*/
+/****************************************************************************/
+#ifndef _TMRHW_H
+#define _TMRHW_H
+
+#include <linux/types.h>
+
+typedef uint32_t tmrHw_ID_t;	/* Timer ID */
+typedef uint32_t tmrHw_COUNT_t;	/* Timer count */
+typedef uint32_t tmrHw_INTERVAL_t;	/* Timer interval */
+typedef uint32_t tmrHw_RATE_t;	/* Timer event (count/interrupt) rate */
+
+typedef enum {
+	tmrHw_INTERRUPT_STATUS_SET,	/* Interrupted  */
+	tmrHw_INTERRUPT_STATUS_UNSET	/* No Interrupt */
+} tmrHw_INTERRUPT_STATUS_e;
+
+typedef enum {
+	tmrHw_CAPABILITY_CLOCK,	/* Clock speed in HHz */
+	tmrHw_CAPABILITY_RESOLUTION	/* Timer resolution in bits */
+} tmrHw_CAPABILITY_e;
+
+/****************************************************************************/
+/**
+*  @brief   Get timer capability
+*
+*  This function returns various capabilities/attributes of a timer
+*
+*  @return  Numeric capability
+*
+*/
+/****************************************************************************/
+uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+				  tmrHw_CAPABILITY_e capability	/*  [ IN ] Timer capability */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer in terms of timer interrupt rate
+*
+*  This function initializes a periodic timer to generate specific number of
+*  timer interrupt per second
+*
+*  @return   On success: Effective timer frequency
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+					tmrHw_RATE_t rate	/*  [ IN ] Number of timer interrupt per second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer to generate timer interrupt after
+*           certain time interval
+*
+*  This function initializes a periodic timer to generate timer interrupt
+*  after every time interval in millisecond
+*
+*  @return   On success: Effective interval set in mili-second
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+						tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer to generate timer interrupt just once
+*           after certain time interval
+*
+*  This function initializes a periodic timer to generate a single ticks after
+*  certain time interval in millisecond
+*
+*  @return   On success: Effective interval set in mili-second
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+					       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a timer to run as a free running timer
+*
+*  This function initializes a timer to run as a free running timer
+*
+*  @return   Timer resolution (count / sec)
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+				       uint32_t divider	/*  [ IN ] Dividing the clock frequency */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Starts a timer
+*
+*  This function starts a preconfigured timer
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*/
+/****************************************************************************/
+int tmrHw_startTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Stops a timer
+*
+*  This function stops a running timer
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*/
+/****************************************************************************/
+int tmrHw_stopTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Gets current timer count
+*
+*  This function returns the current timer value
+*
+*  @return  Current downcounting timer value
+*
+*/
+/****************************************************************************/
+tmrHw_COUNT_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Gets timer count rate
+*
+*  This function returns the number of counts per second
+*
+*  @return  Count rate
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Enables timer interrupt
+*
+*  This function enables the timer interrupt
+*
+*  @return   N/A
+*
+*/
+/****************************************************************************/
+void tmrHw_enableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Disables timer interrupt
+*
+*  This function disable the timer interrupt
+*
+*  @return   N/A
+*/
+/****************************************************************************/
+void tmrHw_disableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Clears the interrupt
+*
+*  This function clears the timer interrupt
+*
+*  @return   N/A
+*
+*  @note
+*     Must be called under the context of ISR
+*/
+/****************************************************************************/
+void tmrHw_clearInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Gets the interrupt status
+*
+*  This function returns timer interrupt status
+*
+*  @return   Interrupt status
+*/
+/****************************************************************************/
+tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Indentifies a timer causing interrupt
+*
+*  This functions returns a timer causing interrupt
+*
+*  @return  0xFFFFFFFF   : No timer causing an interrupt
+*           ! 0xFFFFFFFF : timer causing an interrupt
+*  @note
+*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
+*/
+/****************************************************************************/
+tmrHw_ID_t tmrHw_getInterruptSource(void);
+
+/****************************************************************************/
+/**
+*  @brief   Displays specific timer registers
+*
+*
+*  @return  void
+*
+*/
+/****************************************************************************/
+void tmrHw_printDebugInfo(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
+			  int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
+*
+*  @return   N/A
+*/
+/****************************************************************************/
+void tmrHw_udelay(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
+		  unsigned long usecs	/*  [ IN ] usec to delay */
+) __attribute__ ((section(".aramtext")));
+
+#endif /* _TMRHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/dma.h b/arch/arm/mach-bcmring/include/mach/dma.h
index 7254378..13e0138 100644
--- a/arch/arm/mach-bcmring/include/mach/dma.h
+++ b/arch/arm/mach-bcmring/include/mach/dma.h
@@ -27,7 +27,7 @@
 
 #include <linux/kernel.h>
 #include <linux/semaphore.h>
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/timer.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/hardware.h b/arch/arm/mach-bcmring/include/mach/hardware.h
index 6ae20a6..a0c92b4 100644
--- a/arch/arm/mach-bcmring/include/mach/hardware.h
+++ b/arch/arm/mach-bcmring/include/mach/hardware.h
@@ -22,7 +22,7 @@
 #define __ASM_ARCH_HARDWARE_H
 
 #include <asm/sizes.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/mm_io.h>
 
 /* Hardware addresses of major areas.
diff --git a/arch/arm/mach-bcmring/include/mach/reg_nand.h b/arch/arm/mach-bcmring/include/mach/reg_nand.h
index 387376f..f8d51a8 100644
--- a/arch/arm/mach-bcmring/include/mach/reg_nand.h
+++ b/arch/arm/mach-bcmring/include/mach/reg_nand.h
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_NAND_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/reg_umi.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/reg_umi.h b/arch/arm/mach-bcmring/include/mach/reg_umi.h
index 0992842..56dd9de 100644
--- a/arch/arm/mach-bcmring/include/mach/reg_umi.h
+++ b/arch/arm/mach-bcmring/include/mach/reg_umi.h
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_UMI_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
@@ -233,5 +233,5 @@
 #define REG_UMI_BCH_ERR_LOC_WORD              0x00000018
 /* location within a page (512 byte) */
 #define REG_UMI_BCH_ERR_LOC_PAGE              0x00001FE0
-#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (__REG32(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
+#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (readl(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
 #endif
diff --git a/arch/arm/mach-bcmring/mm.c b/arch/arm/mach-bcmring/mm.c
index 1adec78e..33824a8 100644
--- a/arch/arm/mach-bcmring/mm.c
+++ b/arch/arm/mach-bcmring/mm.c
@@ -20,12 +20,12 @@
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-#define IO_DESC(va, sz) { .virtual = va, \
+#define IO_DESC(va, sz) { .virtual = (unsigned long)va, \
 	.pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
 	.length = sz, \
 	.type = MT_DEVICE }
 
-#define MEM_DESC(va, sz) { .virtual = va, \
+#define MEM_DESC(va, sz) { .virtual = (unsigned long)va, \
 	.pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
 	.length = sz, \
 	.type = MT_MEMORY }
diff --git a/arch/arm/mach-bcmring/timer.c b/arch/arm/mach-bcmring/timer.c
index af9c3d7e..5941290 100644
--- a/arch/arm/mach-bcmring/timer.c
+++ b/arch/arm/mach-bcmring/timer.c
@@ -14,7 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 
 #include <mach/timer.h>
 /* The core.c file initializes timers 1 and 3 as a linux clocksource. */
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index e5a97d9..bd54d7b 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -49,16 +49,6 @@
 		.pfn		= __phys_to_pfn(DOVE_NB_REGS_PHYS_BASE),
 		.length		= DOVE_NB_REGS_SIZE,
 		.type		= MT_DEVICE,
-	}, {
-		.virtual	= DOVE_PCIE0_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(DOVE_PCIE0_IO_PHYS_BASE),
-		.length		= DOVE_PCIE0_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= DOVE_PCIE1_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(DOVE_PCIE1_IO_PHYS_BASE),
-		.length		= DOVE_PCIE1_IO_SIZE,
-		.type		= MT_DEVICE,
 	},
 };
 
diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h
index d52b0ef..c91e300 100644
--- a/arch/arm/mach-dove/include/mach/dove.h
+++ b/arch/arm/mach-dove/include/mach/dove.h
@@ -50,14 +50,12 @@
 #define DOVE_NB_REGS_SIZE		SZ_8M
 
 #define DOVE_PCIE0_IO_PHYS_BASE		0xf2000000
-#define DOVE_PCIE0_IO_VIRT_BASE		0xfee00000
 #define DOVE_PCIE0_IO_BUS_BASE		0x00000000
-#define DOVE_PCIE0_IO_SIZE		SZ_1M
+#define DOVE_PCIE0_IO_SIZE		SZ_64K
 
 #define DOVE_PCIE1_IO_PHYS_BASE		0xf2100000
-#define DOVE_PCIE1_IO_VIRT_BASE		0xfef00000
-#define DOVE_PCIE1_IO_BUS_BASE		0x00100000
-#define DOVE_PCIE1_IO_SIZE		SZ_1M
+#define DOVE_PCIE1_IO_BUS_BASE		0x00010000
+#define DOVE_PCIE1_IO_SIZE		SZ_64K
 
 /*
  * Dove Core Registers Map
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
deleted file mode 100644
index 29c8b85..0000000
--- a/arch/arm/mach-dove/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "dove.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)  	((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \
-						 DOVE_PCIE0_IO_VIRT_BASE))
-
-#endif
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 47921b0..355332d 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -26,9 +26,8 @@
 	u8			root_bus_nr;
 	void __iomem		*base;
 	spinlock_t		conf_lock;
-	char			io_space_name[16];
 	char			mem_space_name[16];
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static struct pcie_port pcie_port[2];
@@ -53,24 +52,10 @@
 
 	orion_pcie_setup(pp->base);
 
-	/*
-	 * IORESOURCE_IO
-	 */
-	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-		 "PCIe %d I/O", pp->index);
-	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-	pp->res[0].name = pp->io_space_name;
-	if (pp->index == 0) {
-		pp->res[0].start = DOVE_PCIE0_IO_PHYS_BASE;
-		pp->res[0].end = pp->res[0].start + DOVE_PCIE0_IO_SIZE - 1;
-	} else {
-		pp->res[0].start = DOVE_PCIE1_IO_PHYS_BASE;
-		pp->res[0].end = pp->res[0].start + DOVE_PCIE1_IO_SIZE - 1;
-	}
-	pp->res[0].flags = IORESOURCE_IO;
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	if (pp->index == 0)
+		pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE0_IO_PHYS_BASE);
+	else
+		pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE1_IO_PHYS_BASE);
 
 	/*
 	 * IORESOURCE_MEM
@@ -78,18 +63,18 @@
 	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
 		 "PCIe %d MEM", pp->index);
 	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-	pp->res[1].name = pp->mem_space_name;
+	pp->res.name = pp->mem_space_name;
 	if (pp->index == 0) {
-		pp->res[1].start = DOVE_PCIE0_MEM_PHYS_BASE;
-		pp->res[1].end = pp->res[1].start + DOVE_PCIE0_MEM_SIZE - 1;
+		pp->res.start = DOVE_PCIE0_MEM_PHYS_BASE;
+		pp->res.end = pp->res.start + DOVE_PCIE0_MEM_SIZE - 1;
 	} else {
-		pp->res[1].start = DOVE_PCIE1_MEM_PHYS_BASE;
-		pp->res[1].end = pp->res[1].start + DOVE_PCIE1_MEM_SIZE - 1;
+		pp->res.start = DOVE_PCIE1_MEM_PHYS_BASE;
+		pp->res.end = pp->res.start + DOVE_PCIE1_MEM_SIZE - 1;
 	}
-	pp->res[1].flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	pp->res.flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	return 1;
 }
@@ -210,7 +195,7 @@
 		pp->root_bus_nr = -1;
 		pp->base = (void __iomem *)base;
 		spin_lock_init(&pp->conf_lock);
-		memset(pp->res, 0, sizeof(pp->res));
+		memset(&pp->res, 0, sizeof(pp->res));
 	} else {
 		printk(KERN_INFO "link down, ignoring\n");
 	}
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 6f80686..f0fe6b5 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -74,22 +74,22 @@
 	 * sparse external-decode ISAIO space
 	 */
 	{	/* IRQ_STAT/IRQ_MCLR */
-		.virtual	= IRQ_STAT,
+		.virtual	= (unsigned long)IRQ_STAT,
 		.pfn		= __phys_to_pfn(TRICK4_PHYS),
 		.length		= TRICK4_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* IRQ_MASK/IRQ_MSET */
-		.virtual	= IRQ_MASK,
+		.virtual	= (unsigned long)IRQ_MASK,
 		.pfn		= __phys_to_pfn(TRICK3_PHYS),
 		.length		= TRICK3_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* SOFT_BASE */
-		.virtual	= SOFT_BASE,
+		.virtual	= (unsigned long)SOFT_BASE,
 		.pfn		= __phys_to_pfn(TRICK1_PHYS),
 		.length		= TRICK1_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* PIT_BASE */
-		.virtual	= PIT_BASE,
+		.virtual	= (unsigned long)PIT_BASE,
 		.pfn		= __phys_to_pfn(TRICK0_PHYS),
 		.length		= TRICK0_SIZE,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-ebsa110/core.h b/arch/arm/mach-ebsa110/core.h
index c93c9e4..afe137e 100644
--- a/arch/arm/mach-ebsa110/core.h
+++ b/arch/arm/mach-ebsa110/core.h
@@ -31,11 +31,11 @@
 #define TRICK7_PHYS		0xf3c00000
 
 /* Virtual addresses */
-#define PIT_BASE		0xfc000000	/* trick 0 */
-#define SOFT_BASE		0xfd000000	/* trick 1 */
-#define IRQ_MASK		0xfe000000	/* trick 3 - read */
-#define IRQ_MSET		0xfe000000	/* trick 3 - write */
-#define IRQ_STAT		0xff000000	/* trick 4 - read */
-#define IRQ_MCLR		0xff000000	/* trick 4 - write */
+#define PIT_BASE		IOMEM(0xfc000000)	/* trick 0 */
+#define SOFT_BASE		IOMEM(0xfd000000)	/* trick 1 */
+#define IRQ_MASK		IOMEM(0xfe000000)	/* trick 3 - read */
+#define IRQ_MSET		IOMEM(0xfe000000)	/* trick 3 - write */
+#define IRQ_STAT		IOMEM(0xff000000)	/* trick 4 - read */
+#define IRQ_MCLR		IOMEM(0xff000000)	/* trick 4 - write */
 
 #endif
diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c
index a472777..41383bf 100644
--- a/arch/arm/mach-ep93xx/adssphere.c
+++ b/arch/arm/mach-ep93xx/adssphere.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/sizes.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index 437c341..7fd705b 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/sizes.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
deleted file mode 100644
index f1397a1..0000000
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/ts72xx.h
- */
-
-/*
- * TS72xx memory map:
- *
- * virt		phys		size
- * febff000	22000000	4K	model number register (bits 0-2)
- * febfe000	22400000	4K	options register
- * febfd000	22800000	4K	options register #2
- * febf9000	10800000	4K	TS-5620 RTC index register
- * febf8000	11700000	4K	TS-5620 RTC data register
- */
-
-#define TS72XX_MODEL_PHYS_BASE		0x22000000
-#define TS72XX_MODEL_VIRT_BASE		0xfebff000
-#define TS72XX_MODEL_SIZE		0x00001000
-
-#define TS72XX_MODEL_TS7200		0x00
-#define TS72XX_MODEL_TS7250		0x01
-#define TS72XX_MODEL_TS7260		0x02
-#define TS72XX_MODEL_TS7300		0x03
-#define TS72XX_MODEL_TS7400		0x04
-#define TS72XX_MODEL_MASK		0x07
-
-
-#define TS72XX_OPTIONS_PHYS_BASE	0x22400000
-#define TS72XX_OPTIONS_VIRT_BASE	0xfebfe000
-#define TS72XX_OPTIONS_SIZE		0x00001000
-
-#define TS72XX_OPTIONS_COM2_RS485	0x02
-#define TS72XX_OPTIONS_MAX197		0x01
-
-
-#define TS72XX_OPTIONS2_PHYS_BASE	0x22800000
-#define TS72XX_OPTIONS2_VIRT_BASE	0xfebfd000
-#define TS72XX_OPTIONS2_SIZE		0x00001000
-
-#define TS72XX_OPTIONS2_TS9420		0x04
-#define TS72XX_OPTIONS2_TS9420_BOOT	0x02
-
-
-#define TS72XX_RTC_INDEX_VIRT_BASE	0xfebf9000
-#define TS72XX_RTC_INDEX_PHYS_BASE	0x10800000
-#define TS72XX_RTC_INDEX_SIZE		0x00001000
-
-#define TS72XX_RTC_DATA_VIRT_BASE	0xfebf8000
-#define TS72XX_RTC_DATA_PHYS_BASE	0x11700000
-#define TS72XX_RTC_DATA_SIZE		0x00001000
-
-#define TS72XX_WDT_CONTROL_PHYS_BASE	0x23800000
-#define TS72XX_WDT_FEED_PHYS_BASE	0x23c00000
-
-#ifndef __ASSEMBLY__
-
-static inline int ts72xx_model(void)
-{
-	return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK;
-}
-
-static inline int board_is_ts7200(void)
-{
-	return ts72xx_model() == TS72XX_MODEL_TS7200;
-}
-
-static inline int board_is_ts7250(void)
-{
-	return ts72xx_model() == TS72XX_MODEL_TS7250;
-}
-
-static inline int board_is_ts7260(void)
-{
-	return ts72xx_model() == TS72XX_MODEL_TS7260;
-}
-
-static inline int board_is_ts7300(void)
-{
-	return ts72xx_model()  == TS72XX_MODEL_TS7300;
-}
-
-static inline int board_is_ts7400(void)
-{
-	return ts72xx_model() == TS72XX_MODEL_TS7400;
-}
-
-static inline int is_max197_installed(void)
-{
-	return !!(__raw_readb(TS72XX_OPTIONS_VIRT_BASE) &
-					TS72XX_OPTIONS_MAX197);
-}
-
-static inline int is_ts9420_installed(void)
-{
-	return !!(__raw_readb(TS72XX_OPTIONS2_VIRT_BASE) &
-					TS72XX_OPTIONS2_TS9420);
-}
-#endif
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 75cab2d..3c4c233 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -21,7 +21,6 @@
 #include <linux/mtd/partitions.h>
 
 #include <mach/hardware.h>
-#include <mach/ts72xx.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach-types.h>
@@ -29,30 +28,31 @@
 #include <asm/mach/arch.h>
 
 #include "soc.h"
+#include "ts72xx.h"
 
 static struct map_desc ts72xx_io_desc[] __initdata = {
 	{
-		.virtual	= TS72XX_MODEL_VIRT_BASE,
+		.virtual	= (unsigned long)TS72XX_MODEL_VIRT_BASE,
 		.pfn		= __phys_to_pfn(TS72XX_MODEL_PHYS_BASE),
 		.length		= TS72XX_MODEL_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= TS72XX_OPTIONS_VIRT_BASE,
+		.virtual	= (unsigned long)TS72XX_OPTIONS_VIRT_BASE,
 		.pfn		= __phys_to_pfn(TS72XX_OPTIONS_PHYS_BASE),
 		.length		= TS72XX_OPTIONS_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= TS72XX_OPTIONS2_VIRT_BASE,
+		.virtual	= (unsigned long)TS72XX_OPTIONS2_VIRT_BASE,
 		.pfn		= __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE),
 		.length		= TS72XX_OPTIONS2_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= TS72XX_RTC_INDEX_VIRT_BASE,
+		.virtual	= (unsigned long)TS72XX_RTC_INDEX_VIRT_BASE,
 		.pfn		= __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE),
 		.length		= TS72XX_RTC_INDEX_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= TS72XX_RTC_DATA_VIRT_BASE,
+		.virtual	= (unsigned long)TS72XX_RTC_DATA_VIRT_BASE,
 		.pfn		= __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE),
 		.length		= TS72XX_RTC_DATA_SIZE,
 		.type		= MT_DEVICE,
diff --git a/arch/arm/mach-ep93xx/ts72xx.h b/arch/arm/mach-ep93xx/ts72xx.h
new file mode 100644
index 0000000..071feaa
--- /dev/null
+++ b/arch/arm/mach-ep93xx/ts72xx.h
@@ -0,0 +1,98 @@
+/*
+ * arch/arm/mach-ep93xx/include/mach/ts72xx.h
+ */
+
+/*
+ * TS72xx memory map:
+ *
+ * virt		phys		size
+ * febff000	22000000	4K	model number register (bits 0-2)
+ * febfe000	22400000	4K	options register
+ * febfd000	22800000	4K	options register #2
+ * febf9000	10800000	4K	TS-5620 RTC index register
+ * febf8000	11700000	4K	TS-5620 RTC data register
+ */
+
+#define TS72XX_MODEL_PHYS_BASE		0x22000000
+#define TS72XX_MODEL_VIRT_BASE		IOMEM(0xfebff000)
+#define TS72XX_MODEL_SIZE		0x00001000
+
+#define TS72XX_MODEL_TS7200		0x00
+#define TS72XX_MODEL_TS7250		0x01
+#define TS72XX_MODEL_TS7260		0x02
+#define TS72XX_MODEL_TS7300		0x03
+#define TS72XX_MODEL_TS7400		0x04
+#define TS72XX_MODEL_MASK		0x07
+
+
+#define TS72XX_OPTIONS_PHYS_BASE	0x22400000
+#define TS72XX_OPTIONS_VIRT_BASE	IOMEM(0xfebfe000)
+#define TS72XX_OPTIONS_SIZE		0x00001000
+
+#define TS72XX_OPTIONS_COM2_RS485	0x02
+#define TS72XX_OPTIONS_MAX197		0x01
+
+
+#define TS72XX_OPTIONS2_PHYS_BASE	0x22800000
+#define TS72XX_OPTIONS2_VIRT_BASE	IOMEM(0xfebfd000)
+#define TS72XX_OPTIONS2_SIZE		0x00001000
+
+#define TS72XX_OPTIONS2_TS9420		0x04
+#define TS72XX_OPTIONS2_TS9420_BOOT	0x02
+
+
+#define TS72XX_RTC_INDEX_VIRT_BASE	IOMEM(0xfebf9000)
+#define TS72XX_RTC_INDEX_PHYS_BASE	0x10800000
+#define TS72XX_RTC_INDEX_SIZE		0x00001000
+
+#define TS72XX_RTC_DATA_VIRT_BASE	IOMEM(0xfebf8000)
+#define TS72XX_RTC_DATA_PHYS_BASE	0x11700000
+#define TS72XX_RTC_DATA_SIZE		0x00001000
+
+#define TS72XX_WDT_CONTROL_PHYS_BASE	0x23800000
+#define TS72XX_WDT_FEED_PHYS_BASE	0x23c00000
+
+#ifndef __ASSEMBLY__
+
+static inline int ts72xx_model(void)
+{
+	return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK;
+}
+
+static inline int board_is_ts7200(void)
+{
+	return ts72xx_model() == TS72XX_MODEL_TS7200;
+}
+
+static inline int board_is_ts7250(void)
+{
+	return ts72xx_model() == TS72XX_MODEL_TS7250;
+}
+
+static inline int board_is_ts7260(void)
+{
+	return ts72xx_model() == TS72XX_MODEL_TS7260;
+}
+
+static inline int board_is_ts7300(void)
+{
+	return ts72xx_model()  == TS72XX_MODEL_TS7300;
+}
+
+static inline int board_is_ts7400(void)
+{
+	return ts72xx_model() == TS72XX_MODEL_TS7400;
+}
+
+static inline int is_max197_installed(void)
+{
+	return !!(__raw_readb(TS72XX_OPTIONS_VIRT_BASE) &
+					TS72XX_OPTIONS_MAX197);
+}
+
+static inline int is_ts9420_installed(void)
+{
+	return !!(__raw_readb(TS72XX_OPTIONS2_VIRT_BASE) &
+					TS72XX_OPTIONS2_TS9420);
+}
+#endif
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index b5b4c8c..6c3299e 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -418,8 +418,8 @@
 	select USE_OF
 	select ARM_AMBA
 	help
-	  Machine support for Samsung Exynos4 machine with device tree enabled.
-	  Select this if a fdt blob is available for the EXYNOS4 SoC based board.
+	  Machine support for Samsung EXYNOS5 machine with device tree enabled.
+	  Select this if a fdt blob is available for the EXYNOS5 SoC based board.
 
 if ARCH_EXYNOS4
 
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
index 2f51293..6a45c9a 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -501,6 +501,10 @@
 		.enable		= exynos4_clk_ip_cam_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
+		.name		= "tsi",
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
 		.name		= "hsmmc",
 		.devname	= "exynos4-sdhci.0",
 		.parent		= &exynos4_clk_aclk_133.clk,
@@ -530,6 +534,14 @@
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 9),
 	}, {
+		.name		= "onenand",
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "nfcon",
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 16),
+	}, {
 		.name		= "dac",
 		.devname	= "s5p-sdo",
 		.enable		= exynos4_clk_ip_tv_ctrl,
@@ -615,6 +627,25 @@
 		.enable		= exynos4_clk_ip_peril_ctrl,
 		.ctrlbit	= (1 << 21),
 	}, {
+		.name		= "pcm",
+		.devname	= "samsung-pcm.1",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "pcm",
+		.devname	= "samsung-pcm.2",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 23),
+	}, {
+		.name		= "slimbus",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 25),
+	}, {
+		.name		= "spdif",
+		.devname	= "samsung-spdif",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 26),
+	}, {
 		.name		= "ac97",
 		.devname	= "samsung-ac97",
 		.enable		= exynos4_clk_ip_peril_ctrl,
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index 774533c..618d0aa 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -166,11 +166,6 @@
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable);
 }
 
-static int exynos5_clk_ip_gps_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GPS, clk, enable);
-}
-
 static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
@@ -672,10 +667,6 @@
 		.enable		= exynos5_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 7),
 	}, {
-		.name		= "gps",
-		.enable		= exynos5_clk_ip_gps_ctrl,
-		.ctrlbit	= ((1 << 3) | (1 << 2) | (1 << 0)),
-	}, {
 		.name		= "nfcon",
 		.enable		= exynos5_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 22),
@@ -891,6 +882,13 @@
 	.ctrlbit	= (1 << 4),
 };
 
+static struct clk exynos5_clk_fimd1 = {
+	.name		= "fimd",
+	.devname	= "exynos5-fb.1",
+	.enable		= exynos5_clk_ip_disp1_ctrl,
+	.ctrlbit	= (1 << 0),
+};
+
 struct clk *exynos5_clkset_group_list[] = {
 	[0] = &clk_ext_xtal_mux,
 	[1] = NULL,
@@ -1120,6 +1118,18 @@
 	.reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 8, .size = 8 },
 };
 
+struct clksrc_clk exynos5_clk_sclk_fimd1 = {
+	.clk	= {
+		.name		= "sclk_fimd",
+		.devname	= "exynos5-fb.1",
+		.enable		= exynos5_clksrc_mask_disp1_0_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 },
+};
+
 static struct clksrc_clk exynos5_clksrcs[] = {
 	{
 		.clk	= {
@@ -1131,16 +1141,6 @@
 		.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 8, .size = 8 },
 	}, {
 		.clk	= {
-			.name		= "sclk_fimd",
-			.devname	= "s3cfb.1",
-			.enable		= exynos5_clksrc_mask_disp1_0_ctrl,
-			.ctrlbit	= (1 << 0),
-		},
-		.sources = &exynos5_clkset_group,
-		.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 },
-		.reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 },
-	}, {
-		.clk	= {
 			.name		= "aclk_266_gscl",
 		},
 		.sources = &clk_src_gscl_266,
@@ -1240,12 +1240,14 @@
 	&exynos5_clk_mdout_spi0,
 	&exynos5_clk_mdout_spi1,
 	&exynos5_clk_mdout_spi2,
+	&exynos5_clk_sclk_fimd1,
 };
 
 static struct clk *exynos5_clk_cdev[] = {
 	&exynos5_clk_pdma0,
 	&exynos5_clk_pdma1,
 	&exynos5_clk_mdma1,
+	&exynos5_clk_fimd1,
 };
 
 static struct clksrc_clk *exynos5_clksrc_cdev[] = {
@@ -1274,6 +1276,7 @@
 	CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0),
 	CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1),
 	CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1),
+	CLKDEV_INIT("exynos5-fb.1", "lcd", &exynos5_clk_fimd1),
 };
 
 static unsigned long exynos5_epll_get_rate(struct clk *clk)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c72b675..6d33f50 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -89,7 +89,7 @@
 #define EXYNOS4_PA_L2CC			0x10502000
 
 #define EXYNOS4_PA_MDMA0		0x10810000
-#define EXYNOS4_PA_MDMA1		0x12840000
+#define EXYNOS4_PA_MDMA1		0x12850000
 #define EXYNOS4_PA_PDMA0		0x12680000
 #define EXYNOS4_PA_PDMA1		0x12690000
 #define EXYNOS5_PA_MDMA0		0x10800000
@@ -131,7 +131,6 @@
 #define EXYNOS5_PA_SYSMMU_JPEG		0x11F20000
 #define EXYNOS5_PA_SYSMMU_IOP		0x12360000
 #define EXYNOS5_PA_SYSMMU_RTIC		0x12370000
-#define EXYNOS5_PA_SYSMMU_GPS		0x12630000
 #define EXYNOS5_PA_SYSMMU_ISP		0x13260000
 #define EXYNOS5_PA_SYSMMU_DRC		0x12370000
 #define EXYNOS5_PA_SYSMMU_SCALERC	0x13280000
diff --git a/arch/arm/mach-exynos/include/mach/sysmmu.h b/arch/arm/mach-exynos/include/mach/sysmmu.h
index 998daf2..88a4543 100644
--- a/arch/arm/mach-exynos/include/mach/sysmmu.h
+++ b/arch/arm/mach-exynos/include/mach/sysmmu.h
@@ -58,7 +58,7 @@
 #endif
 
 #else /* !CONFIG_EXYNOS_DEV_SYSMMU */
-#define platform_set_sysmmu(dev, sysmmu) do { } while (0)
+#define platform_set_sysmmu(sysmmu, dev) do { } while (0)
 #endif
 
 #define SYSMMU_CLOCK_DEVNAME(ipname, id) (SYSMMU_DEVNAME_BASE "." #id)
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index 3e6aaa6..a42b369 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
- 
+
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
@@ -26,6 +26,7 @@
 
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "common.h"
 
@@ -175,11 +176,6 @@
 		.pfn		= __phys_to_pfn(DC21285_PCI_IACK),
 		.length		= PCIIACK_SIZE,
 		.type		= MT_DEVICE,
-	}, {
-		.virtual	= PCIO_BASE,
-		.pfn		= __phys_to_pfn(DC21285_PCI_IO),
-		.length		= PCIO_SIZE,
-		.type		= MT_DEVICE,
 	},
 #endif
 };
@@ -196,8 +192,10 @@
 	 * Now, work out what we've got to map in addition on this
 	 * platform.
 	 */
-	if (footbridge_cfn_mode())
+	if (footbridge_cfn_mode()) {
 		iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
+		pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO));
+	}
 }
 
 void footbridge_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 9d62e33..a7cd2cf 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -276,8 +276,8 @@
 
 	sys->mem_offset  = DC21285_PCI_MEM;
 
-	pci_add_resource_offset(&sys->resources,
-				&ioport_resource, sys->io_offset);
+	pci_ioremap_io(0, DC21285_PCI_IO);
+
 	pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
@@ -298,7 +298,7 @@
 	mem_size = (unsigned int)high_memory - PAGE_OFFSET;
 	for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
 		if (mem_mask >= mem_size)
-			break;		
+			break;
 
 	/*
 	 * These registers need to be set up whether we're the
@@ -350,14 +350,6 @@
 			    "PCI data parity", NULL);
 
 	if (cfn_mode) {
-		static struct resource csrio;
-
-		csrio.flags  = IORESOURCE_IO;
-		csrio.name   = "Footbridge";
-
-		allocate_resource(&ioport_resource, &csrio, 128,
-				  0xff00, 0xffff, 128, NULL, NULL);
-
 		/*
 		 * Map our SDRAM at a known address in PCI space, just in case
 		 * the firmware had other ideas.  Using a nonzero base is
@@ -365,7 +357,7 @@
 		 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
 		 */
 		*CSR_PCICSRBASE       = 0xf4000000;
-		*CSR_PCICSRIOBASE     = csrio.start;
+		*CSR_PCICSRIOBASE     = 0;
 		*CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
 		*CSR_PCIROMBASE       = 0;
 		*CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
diff --git a/arch/arm/mach-footbridge/include/mach/debug-macro.S b/arch/arm/mach-footbridge/include/mach/debug-macro.S
index e5acde2..c169f0c 100644
--- a/arch/arm/mach-footbridge/include/mach/debug-macro.S
+++ b/arch/arm/mach-footbridge/include/mach/debug-macro.S
@@ -17,7 +17,8 @@
 	/* For NetWinder debugging */
 		.macro	addruart, rp, rv, tmp
 		mov	\rp, #0x000003f8
-		orr	\rv, \rp, #0xff000000	@ virtual
+		orr	\rv, \rp, #0xfe000000	@ virtual
+		orr	\rv, \rv, #0x00e00000	@ virtual
 		orr	\rp, \rp, #0x7c000000	@ physical
 		.endm
 
diff --git a/arch/arm/mach-footbridge/include/mach/io.h b/arch/arm/mach-footbridge/include/mach/io.h
index aba531ee..aba4638 100644
--- a/arch/arm/mach-footbridge/include/mach/io.h
+++ b/arch/arm/mach-footbridge/include/mach/io.h
@@ -14,18 +14,10 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#ifdef CONFIG_MMU
-#define MMU_IO(a, b)	(a)
-#else
-#define MMU_IO(a, b)	(b)
-#endif
-
-#define PCIO_SIZE       0x00100000
-#define PCIO_BASE       MMU_IO(0xff000000, 0x7c000000)
-
 /*
- * Translation of various region addresses to virtual addresses
+ * Translation of various i/o addresses to host addresses for !CONFIG_MMU
  */
+#define PCIO_BASE       0x7c000000
 #define __io(a)			((void __iomem *)(PCIO_BASE + (a)))
 
 #endif
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index f4c0e75..895754a 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -13,7 +13,7 @@
 obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(imx5-pm-y) cpu_op-mx51.o
 
 obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
-			    clk-pfd.o clk-busy.o
+			    clk-pfd.o clk-busy.o clk.o
 
 # Support for CMOS sensor interface
 obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c
index ea13e61..cf65148 100644
--- a/arch/arm/mach-imx/clk-imx21.c
+++ b/arch/arm/mach-imx/clk-imx21.c
@@ -23,7 +23,6 @@
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/clkdev.h>
 #include <linux/err.h>
 
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c
index 4431a62..d20d479 100644
--- a/arch/arm/mach-imx/clk-imx25.c
+++ b/arch/arm/mach-imx/clk-imx25.c
@@ -241,6 +241,6 @@
 	clk_register_clkdev(clk[sdma_ahb], "ahb", "imx35-sdma");
 	clk_register_clkdev(clk[iim_ipg], "iim", NULL);
 
-	mxc_timer_init(MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
+	mxc_timer_init(MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), MX25_INT_GPT1);
 	return 0;
 }
diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c
index 65fb8bc..177259b 100644
--- a/arch/arm/mach-imx/clk-imx35.c
+++ b/arch/arm/mach-imx/clk-imx35.c
@@ -62,8 +62,8 @@
 	kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate,
 	rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate,
 	ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate,
-	wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate,
-	clk_max
+	wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate,
+	gpu2d_gate, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -142,6 +142,9 @@
 
 	clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + MX35_CCM_PDR4, 28, 4);
 
+	clk[csi_sel] = imx_clk_mux("csi_sel", base + MX35_CCM_PDR2, 7, 1, std_sel, ARRAY_SIZE(std_sel));
+	clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MX35_CCM_PDR2, 16, 6);
+
 	clk[asrc_gate] = imx_clk_gate2("asrc_gate", "ipg", base + MX35_CCM_CGR0,  0);
 	clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", base + MX35_CCM_CGR0,  2);
 	clk[audmux_gate] = imx_clk_gate2("audmux_gate", "ipg", base + MX35_CCM_CGR0,  4);
@@ -192,7 +195,7 @@
 	clk[max_gate] = imx_clk_gate2("max_gate", "dummy", base + MX35_CCM_CGR2, 26);
 	clk[admux_gate] = imx_clk_gate2("admux_gate", "ipg", base + MX35_CCM_CGR2, 30);
 
-	clk[csi_gate] = imx_clk_gate2("csi_gate", "ipg", base + MX35_CCM_CGR3,  0);
+	clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MX35_CCM_CGR3,  0);
 	clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MX35_CCM_CGR3,  2);
 	clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "ahb", base + MX35_CCM_CGR3,  4);
 
@@ -228,6 +231,7 @@
 	clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2");
 	clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
 	clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
+	clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
 	clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1");
 	clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma");
 	clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
@@ -253,6 +257,7 @@
 	clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc");
 	clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
 	clk_register_clkdev(clk[nfc_div], NULL, "mxc_nand.0");
+	clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
 
 	clk_prepare_enable(clk[spba_gate]);
 	clk_prepare_enable(clk[gpio1_gate]);
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index 4bdcaa9..e5165a8 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -39,16 +39,17 @@
 static const char *emi_slow_sel[] = { "main_bus", "ahb", };
 static const char *usb_phy_sel_str[] = { "osc", "usb_phy_podf", };
 static const char *mx51_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "tve_di", };
-static const char *mx53_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "di_pll4_podf", "dummy", "ldb_di0", };
+static const char *mx53_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "di_pll4_podf", "dummy", "ldb_di0_gate", };
 static const char *mx53_ldb_di0_sel[] = { "pll3_sw", "pll4_sw", };
 static const char *mx51_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", };
-static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", "ldb_di1", };
+static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", "ldb_di1_gate", };
 static const char *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", };
 static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", };
 static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", };
 static const char *tve_sel[] = { "tve_pred", "tve_ext_sel", };
 static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
 static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
+static const char *mx53_can_sel[] = { "ipg", "ckih1", "ckih2", "lp_apm", };
 
 enum imx5_clks {
 	dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred,
@@ -82,6 +83,7 @@
 	ssi_ext1_podf, ssi_ext2_pred, ssi_ext2_podf, ssi1_root_gate,
 	ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate,
 	epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate,
+	can_sel, can1_serial_gate, can1_ipg_gate,
 	clk_max
 };
 
@@ -421,8 +423,12 @@
 	clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
 	clk[usb_phy1_gate] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10);
 	clk[usb_phy2_gate] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12);
-	clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "ipg", MXC_CCM_CCGR4, 6);
-	clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 8);
+	clk[can_sel] = imx_clk_mux("can_sel", MXC_CCM_CSCMR2, 6, 2,
+				mx53_can_sel, ARRAY_SIZE(mx53_can_sel));
+	clk[can1_serial_gate] = imx_clk_gate2("can1_serial_gate", "can_sel", MXC_CCM_CCGR6, 22);
+	clk[can1_ipg_gate] = imx_clk_gate2("can1_ipg_gate", "ipg", MXC_CCM_CCGR6, 20);
+	clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "can_sel", MXC_CCM_CCGR4, 8);
+	clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 6);
 	clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22);
 
 	for (i = 0; i < ARRAY_SIZE(clk); i++)
@@ -455,6 +461,10 @@
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
 	clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
+	clk_register_clkdev(clk[can1_ipg_gate], "ipg", "53fc8000.can");
+	clk_register_clkdev(clk[can1_serial_gate], "per", "53fc8000.can");
+	clk_register_clkdev(clk[can2_ipg_gate], "ipg", "53fcc000.can");
+	clk_register_clkdev(clk[can2_serial_gate], "per", "53fcc000.can");
 
 	/* set SDHC root clock to 200MHZ*/
 	clk_set_rate(clk[esdhc_a_podf], 200000000);
diff --git a/arch/arm/mach-imx/clk-pllv1.c b/arch/arm/mach-imx/clk-pllv1.c
index 2d856f9c..02be731 100644
--- a/arch/arm/mach-imx/clk-pllv1.c
+++ b/arch/arm/mach-imx/clk-pllv1.c
@@ -6,7 +6,7 @@
 #include <linux/err.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/clock.h>
+
 #include "clk.h"
 
 /**
@@ -29,8 +29,53 @@
 		unsigned long parent_rate)
 {
 	struct clk_pllv1 *pll = to_clk_pllv1(hw);
+	long long ll;
+	int mfn_abs;
+	unsigned int mfi, mfn, mfd, pd;
+	u32 reg;
+	unsigned long rate;
 
-	return mxc_decode_pll(readl(pll->base), parent_rate);
+	reg = readl(pll->base);
+
+	/*
+	 * Get the resulting clock rate from a PLL register value and the input
+	 * frequency. PLLs with this register layout can be found on i.MX1,
+	 * i.MX21, i.MX27 and i,MX31
+	 *
+	 *                  mfi + mfn / (mfd + 1)
+	 *  f = 2 * f_ref * --------------------
+	 *                        pd + 1
+	 */
+
+	mfi = (reg >> 10) & 0xf;
+	mfn = reg & 0x3ff;
+	mfd = (reg >> 16) & 0x3ff;
+	pd =  (reg >> 26) & 0xf;
+
+	mfi = mfi <= 5 ? 5 : mfi;
+
+	mfn_abs = mfn;
+
+	/*
+	 * On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit
+	 * 2's complements number
+	 */
+	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200)
+		mfn_abs = 0x400 - mfn;
+
+	rate = parent_rate * 2;
+	rate /= pd + 1;
+
+	ll = (unsigned long long)rate * mfn_abs;
+
+	do_div(ll, mfd + 1);
+
+	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200)
+		ll = -ll;
+
+	ll = (rate * mfi) + ll;
+
+	return ll;
 }
 
 struct clk_ops clk_pllv1_ops = {
diff --git a/arch/arm/mach-imx/clk.c b/arch/arm/mach-imx/clk.c
new file mode 100644
index 0000000..f5e8be8
--- /dev/null
+++ b/arch/arm/mach-imx/clk.c
@@ -0,0 +1,3 @@
+#include <linux/spinlock.h>
+
+DEFINE_SPINLOCK(imx_ccm_lock);
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 1bf64fe..5f2d8acc 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -3,7 +3,8 @@
 
 #include <linux/spinlock.h>
 #include <linux/clk-provider.h>
-#include <mach/clock.h>
+
+extern spinlock_t imx_ccm_lock;
 
 struct clk *imx_clk_pllv1(const char *name, const char *parent,
 		void __iomem *base);
diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c
index 2c6ab32..5985ed1 100644
--- a/arch/arm/mach-imx/mach-armadillo5x0.c
+++ b/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -526,7 +526,8 @@
 	imx31_add_mxc_nand(&armadillo5x0_nand_board_info);
 
 	/* set NAND page size to 2k if not configured via boot mode pins */
-	__raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR);
+	__raw_writel(__raw_readl(mx3_ccm_base + MXC_CCM_RCSR) |
+					(1 << 30), mx3_ccm_base + MXC_CCM_RCSR);
 
 	/* RTC */
 	/* Get RTC IRQ and register the chip */
diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c
index 5d08533..0330078 100644
--- a/arch/arm/mach-imx/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c
@@ -36,7 +36,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
-#include <mach/clock.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx3.h>
@@ -259,13 +258,13 @@
  */
 static struct map_desc kzm_io_desc[] __initdata = {
 	{
-		.virtual	= MX31_CS4_BASE_ADDR_VIRT,
+		.virtual	= (unsigned long)MX31_CS4_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(MX31_CS4_BASE_ADDR),
 		.length		= MX31_CS4_SIZE,
 		.type		= MT_DEVICE
 	},
 	{
-		.virtual	= MX31_CS5_BASE_ADDR_VIRT,
+		.virtual	= (unsigned long)MX31_CS5_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(MX31_CS5_BASE_ADDR),
 		.length		= MX31_CS5_SIZE,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c
index d37f480..e774b07 100644
--- a/arch/arm/mach-imx/mach-mx31ads.c
+++ b/arch/arm/mach-imx/mach-mx31ads.c
@@ -540,7 +540,7 @@
  */
 static struct map_desc mx31ads_io_desc[] __initdata = {
 	{
-		.virtual	= MX31_CS4_BASE_ADDR_VIRT,
+		.virtual	= (unsigned long)MX31_CS4_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(MX31_CS4_BASE_ADDR),
 		.length		= CS4_CS8900_MMIO_START,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index c8785b3..ef57cff 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -207,7 +207,7 @@
  */
 static struct map_desc mx31lite_io_desc[] __initdata = {
 	{
-		.virtual = MX31_CS4_BASE_ADDR_VIRT,
+		.virtual = (unsigned long)MX31_CS4_BASE_ADDR_VIRT,
 		.pfn = __phys_to_pfn(MX31_CS4_BASE_ADDR),
 		.length = MX31_CS4_SIZE,
 		.type = MT_DEVICE
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 3fa6c51..a432d43 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -95,8 +95,8 @@
  *  UART0  7    6
  *  UART1  5    4
  */
-#define SC_CTRLC	IO_ADDRESS(INTEGRATOR_SC_CTRLC)
-#define SC_CTRLS	IO_ADDRESS(INTEGRATOR_SC_CTRLS)
+#define SC_CTRLC	__io_address(INTEGRATOR_SC_CTRLC)
+#define SC_CTRLS	__io_address(INTEGRATOR_SC_CTRLS)
 
 static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
 {
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
index fbb4577..590c192 100644
--- a/arch/arm/mach-integrator/cpu.c
+++ b/arch/arm/mach-integrator/cpu.c
@@ -25,10 +25,10 @@
 
 static struct cpufreq_driver integrator_driver;
 
-#define CM_ID  	IO_ADDRESS(INTEGRATOR_HDR_ID)
-#define CM_OSC	IO_ADDRESS(INTEGRATOR_HDR_OSC)
-#define CM_STAT IO_ADDRESS(INTEGRATOR_HDR_STAT)
-#define CM_LOCK IO_ADDRESS(INTEGRATOR_HDR_LOCK)
+#define CM_ID  	__io_address(INTEGRATOR_HDR_ID)
+#define CM_OSC	__io_address(INTEGRATOR_HDR_OSC)
+#define CM_STAT __io_address(INTEGRATOR_HDR_STAT)
+#define CM_LOCK __io_address(INTEGRATOR_HDR_LOCK)
 
 static const struct icst_params lclk_params = {
 	.ref		= 24000000,
diff --git a/arch/arm/mach-integrator/include/mach/io.h b/arch/arm/mach-integrator/include/mach/io.h
deleted file mode 100644
index 8de70de..0000000
--- a/arch/arm/mach-integrator/include/mach/io.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-integrator/include/mach/io.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * WARNING: this has to mirror definitions in platform.h
- */
-#define PCI_MEMORY_VADDR        0xe8000000
-#define PCI_CONFIG_VADDR        0xec000000
-#define PCI_V3_VADDR            0xed000000
-#define PCI_IO_VADDR            0xee000000
-
-#define __io(a)			((void __iomem *)(PCI_IO_VADDR + (a)))
-
-#endif
diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h
index ec467ba..4c03475 100644
--- a/arch/arm/mach-integrator/include/mach/platform.h
+++ b/arch/arm/mach-integrator/include/mach/platform.h
@@ -324,6 +324,10 @@
  */
 #define PHYS_PCI_V3_BASE                0x62000000
 
+#define PCI_MEMORY_VADDR		0xe8000000
+#define PCI_CONFIG_VADDR		0xec000000
+#define PCI_V3_VADDR			0xed000000
+
 /* ------------------------------------------------------------------------
  *  Integrator Interrupt Controllers
  * ------------------------------------------------------------------------
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 3b22675..2215d96 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -50,6 +50,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include <asm/mach/time.h>
 
 #include <plat/fpga-irq.h>
@@ -73,7 +74,7 @@
  * e8000000	40000000	PCI memory		PHYS_PCI_MEM_BASE	(max 512M)
  * ec000000	61000000	PCI config space	PHYS_PCI_CONFIG_BASE	(max 16M)
  * ed000000	62000000	PCI V3 regs		PHYS_PCI_V3_BASE	(max 64k)
- * ee000000	60000000	PCI IO			PHYS_PCI_IO_BASE	(max 16M)
+ * fee00000	60000000	PCI IO			PHYS_PCI_IO_BASE	(max 16M)
  * ef000000			Cache flush
  * f1000000	10000000	Core module registers
  * f1100000	11000000	System controller registers
@@ -133,25 +134,20 @@
 		.length		= SZ_4K,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= PCI_MEMORY_VADDR,
+		.virtual	= (unsigned long)PCI_MEMORY_VADDR,
 		.pfn		= __phys_to_pfn(PHYS_PCI_MEM_BASE),
 		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= PCI_CONFIG_VADDR,
+		.virtual	= (unsigned long)PCI_CONFIG_VADDR,
 		.pfn		= __phys_to_pfn(PHYS_PCI_CONFIG_BASE),
 		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= PCI_V3_VADDR,
+		.virtual	= (unsigned long)PCI_V3_VADDR,
 		.pfn		= __phys_to_pfn(PHYS_PCI_V3_BASE),
 		.length		= SZ_64K,
 		.type		= MT_DEVICE
-	}, {
-		.virtual	= PCI_IO_VADDR,
-		.pfn		= __phys_to_pfn(PHYS_PCI_IO_BASE),
-		.length		= SZ_64K,
-		.type		= MT_DEVICE
 	}
 };
 
@@ -159,6 +155,7 @@
 {
 	iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
 	vga_base = PCI_MEMORY_VADDR;
+	pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE));
 }
 
 #define INTEGRATOR_SC_VALID_INT	0x003fffff
@@ -317,9 +314,9 @@
 /*
  * Where is the timer (VA)?
  */
-#define TIMER0_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER0_BASE)
-#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
-#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
+#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
+#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
+#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
 
 static unsigned long timer_reload;
 
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 82d5c83..3df5fc3 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -59,7 +59,7 @@
 
 #define INTCP_ETH_SIZE			0x10
 
-#define INTCP_VA_CTRL_BASE		IO_ADDRESS(INTEGRATOR_CP_CTL_BASE)
+#define INTCP_VA_CTRL_BASE		__io_address(INTEGRATOR_CP_CTL_BASE)
 #define INTCP_FLASHPROG			0x04
 #define CINTEGRATOR_FLASHPROG_FLVPPEN	(1 << 0)
 #define CINTEGRATOR_FLASHPROG_FLWREN	(1 << 1)
@@ -265,8 +265,8 @@
  */
 static unsigned int mmc_status(struct device *dev)
 {
-	unsigned int status = readl(IO_ADDRESS(0xca000000 + 4));
-	writel(8, IO_ADDRESS(INTEGRATOR_CP_CTL_BASE + 8));
+	unsigned int status = readl(__io_address(0xca000000 + 4));
+	writel(8, __io_address(INTEGRATOR_CP_CTL_BASE + 8));
 
 	return status & 8;
 }
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index b866880..bbeca59 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -41,61 +41,61 @@
 /*
  * The V3 PCI interface chip in Integrator provides several windows from
  * local bus memory into the PCI memory areas.   Unfortunately, there
- * are not really enough windows for our usage, therefore we reuse 
+ * are not really enough windows for our usage, therefore we reuse
  * one of the windows for access to PCI configuration space.  The
  * memory map is as follows:
- * 
+ *
  * Local Bus Memory         Usage
- * 
+ *
  * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
  * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
  * 60000000 - 60FFFFFF      PCI IO.  16M
  * 61000000 - 61FFFFFF      PCI Configuration. 16M
- * 
+ *
  * There are three V3 windows, each described by a pair of V3 registers.
  * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
  * Base0 and Base1 can be used for any type of PCI memory access.   Base2
  * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
  * uses this only for PCI IO space.
- * 
+ *
  * Normally these spaces are mapped using the following base registers:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF
- * 
+ *
  * This means that I20 and PCI configuration space accesses will fail.
- * When PCI configuration accesses are needed (via the uHAL PCI 
+ * When PCI configuration accesses are needed (via the uHAL PCI
  * configuration space primitives) we must remap the spaces as follows:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF      LB_BASE1/LB_MAP1
- * 
+ *
  * To make this work, the code depends on overlapping windows working.
- * The V3 chip translates an address by checking its range within 
+ * The V3 chip translates an address by checking its range within
  * each of the BASE/MAP pairs in turn (in ascending register number
  * order).  It will use the first matching pair.   So, for example,
  * if the same address is mapped by both LB_BASE0/LB_MAP0 and
- * LB_BASE1/LB_MAP1, the V3 will use the translation from 
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from
  * LB_BASE0/LB_MAP0.
- * 
+ *
  * To allow PCI Configuration space access, the code enlarges the
  * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
  * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
  * be remapped for use by configuration cycles.
- * 
- * At the end of the PCI Configuration space accesses, 
+ *
+ * At the end of the PCI Configuration space accesses,
  * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
  * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
  * reveal the now restored LB_BASE1/LB_MAP1 window.
- * 
+ *
  * NOTE: We do not set up I2O mapping.  I suspect that this is only
  * for an intelligent (target) device.  Using I2O disables most of
  * the mappings into PCI memory.
@@ -127,8 +127,8 @@
  *
  * returns:	configuration address to play on the PCI bus
  *
- * To generate the appropriate PCI configuration cycles in the PCI 
- * configuration address space, you present the V3 with the following pattern 
+ * To generate the appropriate PCI configuration cycles in the PCI
+ * configuration address space, you present the V3 with the following pattern
  * (which is very nearly a type 1 (except that the lower two bits are 00 and
  * not 01).   In order for this mapping to work you need to set up one of
  * the local to PCI aperatures to 16Mbytes in length translating to
@@ -138,7 +138,7 @@
  *
  * Type 0:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
@@ -150,7 +150,7 @@
  *
  * Type 1:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
@@ -161,7 +161,7 @@
  *	15:11	Device number (5 bits)
  *	10:8	function number
  *	 7:2	register number
- *  
+ *
  */
 static DEFINE_RAW_SPINLOCK(v3_lock);
 
@@ -181,7 +181,7 @@
 #undef V3_LB_BASE_PREFETCH
 #define V3_LB_BASE_PREFETCH 0
 
-static unsigned long v3_open_config_window(struct pci_bus *bus,
+static void __iomem *v3_open_config_window(struct pci_bus *bus,
 					   unsigned int devfn, int offset)
 {
 	unsigned int address, mapaddress, busnr;
@@ -280,7 +280,7 @@
 static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where,
 			  int size, u32 *val)
 {
-	unsigned long addr;
+	void __iomem *addr;
 	unsigned long flags;
 	u32 v;
 
@@ -311,7 +311,7 @@
 static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where,
 			   int size, u32 val)
 {
-	unsigned long addr;
+	void __iomem *addr;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&v3_lock, flags);
@@ -374,12 +374,9 @@
 	}
 
 	/*
-	 * the IO resource for this bus
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource_offset(&sys->resources,
-				&ioport_resource, sys->io_offset);
 	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -391,9 +388,9 @@
  * means I can't get additional information on the reason for the pm2fb
  * problems.  I suppose I'll just have to mind-meld with the machine. ;)
  */
-#define SC_PCI     IO_ADDRESS(INTEGRATOR_SC_PCIENABLE)
-#define SC_LBFADDR IO_ADDRESS(INTEGRATOR_SC_BASE + 0x20)
-#define SC_LBFCODE IO_ADDRESS(INTEGRATOR_SC_BASE + 0x24)
+#define SC_PCI     __io_address(INTEGRATOR_SC_PCIENABLE)
+#define SC_LBFADDR __io_address(INTEGRATOR_SC_BASE + 0x20)
+#define SC_LBFCODE __io_address(INTEGRATOR_SC_BASE + 0x24)
 
 static int
 v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
@@ -498,7 +495,6 @@
 	unsigned int temp;
 	int ret;
 
-	pcibios_min_io = 0x6000;
 	pcibios_min_mem = 0x00100000;
 
 	/*
diff --git a/arch/arm/mach-iop13xx/include/mach/io.h b/arch/arm/mach-iop13xx/include/mach/io.h
deleted file mode 100644
index f131885..0000000
--- a/arch/arm/mach-iop13xx/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * iop13xx custom ioremap implementation
- * Copyright (c) 2005-2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a) __iop13xx_io(a)
-
-extern void __iomem * __iop13xx_io(unsigned long io_addr);
-
-#endif
diff --git a/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
index e190dcd..7480f58 100644
--- a/arch/arm/mach-iop13xx/include/mach/iop13xx.h
+++ b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
@@ -69,21 +69,11 @@
  * 0x8000.0000 + 928M	0x2.8000.0000   (ioremap)	PCIE outbound memory window
  *
  * IO MAP
- * 0x1000 + 64K	0x0.fffb.1000	0xfec6.1000	PCIX outbound i/o window
- * 0x1000 + 64K	0x0.fffd.1000	0xfed7.1000	PCIE outbound i/o window
+ * 0x00000 + 64K	0x0.fffb.0000	0xfee0.0000	PCIX outbound i/o window
+ * 0x10000 + 64K	0x0.fffd.0000	0xfee1.0000	PCIE outbound i/o window
  */
-#define IOP13XX_PCIX_IO_WINDOW_SIZE   0x10000UL
 #define IOP13XX_PCIX_LOWER_IO_PA      0xfffb0000UL
-#define IOP13XX_PCIX_LOWER_IO_VA      0xfec60000UL
 #define IOP13XX_PCIX_LOWER_IO_BA      0x0UL /* OIOTVR */
-#define IOP13XX_PCIX_IO_BUS_OFFSET    0x1000UL
-#define IOP13XX_PCIX_UPPER_IO_PA      (IOP13XX_PCIX_LOWER_IO_PA +\
-				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_UPPER_IO_VA      (IOP13XX_PCIX_LOWER_IO_VA +\
-				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-					   (IOP13XX_PCIX_LOWER_IO_PA\
-					   - IOP13XX_PCIX_LOWER_IO_VA))
 
 #define IOP13XX_PCIX_MEM_PHYS_OFFSET  0x100000000ULL
 #define IOP13XX_PCIX_MEM_WINDOW_SIZE  0x3a000000UL
@@ -103,20 +93,8 @@
 					IOP13XX_PCIX_LOWER_MEM_BA)
 
 /* PCI-E ranges */
-#define IOP13XX_PCIE_IO_WINDOW_SIZE   	 0x10000UL
 #define IOP13XX_PCIE_LOWER_IO_PA      	 0xfffd0000UL
-#define IOP13XX_PCIE_LOWER_IO_VA      	 0xfed70000UL
-#define IOP13XX_PCIE_LOWER_IO_BA      	 0x0UL  /* OIOTVR */
-#define IOP13XX_PCIE_IO_BUS_OFFSET	 0x1000UL
-#define IOP13XX_PCIE_UPPER_IO_PA      	 (IOP13XX_PCIE_LOWER_IO_PA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_VA      	 (IOP13XX_PCIE_LOWER_IO_VA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_BA      	 (IOP13XX_PCIE_LOWER_IO_BA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-					   (IOP13XX_PCIE_LOWER_IO_PA\
-					   - IOP13XX_PCIE_LOWER_IO_VA))
+#define IOP13XX_PCIE_LOWER_IO_BA	 0x10000UL  /* OIOTVR */
 
 #define IOP13XX_PCIE_MEM_PHYS_OFFSET  	 0x200000000ULL
 #define IOP13XX_PCIE_MEM_WINDOW_SIZE  	 0x3a000000UL
@@ -148,18 +126,16 @@
  * IOP13XX chipset registers
  */
 #define IOP13XX_PMMR_PHYS_MEM_BASE	   0xffd80000UL  /* PMMR phys. address */
-#define IOP13XX_PMMR_VIRT_MEM_BASE	   0xfee80000UL  /* PMMR phys. address */
+#define IOP13XX_PMMR_VIRT_MEM_BASE	   (void __iomem *)(0xfee80000UL)  /* PMMR phys. address */
 #define IOP13XX_PMMR_MEM_WINDOW_SIZE	   0x80000
 #define IOP13XX_PMMR_UPPER_MEM_VA	   (IOP13XX_PMMR_VIRT_MEM_BASE +\
 					   IOP13XX_PMMR_MEM_WINDOW_SIZE - 1)
 #define IOP13XX_PMMR_UPPER_MEM_PA	   (IOP13XX_PMMR_PHYS_MEM_BASE +\
 					   IOP13XX_PMMR_MEM_WINDOW_SIZE - 1)
-#define IOP13XX_PMMR_VIRT_TO_PHYS(addr)   (u32) ((u32) addr +\
-					   (IOP13XX_PMMR_PHYS_MEM_BASE\
-					   - IOP13XX_PMMR_VIRT_MEM_BASE))
-#define IOP13XX_PMMR_PHYS_TO_VIRT(addr)   (u32) ((u32) addr -\
-					   (IOP13XX_PMMR_PHYS_MEM_BASE\
-					   - IOP13XX_PMMR_VIRT_MEM_BASE))
+#define IOP13XX_PMMR_VIRT_TO_PHYS(addr)   (((addr) - IOP13XX_PMMR_VIRT_MEM_BASE)\
+					   + IOP13XX_PMMR_PHYS_MEM_BASE)
+#define IOP13XX_PMMR_PHYS_TO_VIRT(addr)   (((addr) - IOP13XX_PMMR_PHYS_MEM_BASE)\
+					   + IOP13XX_PMMR_VIRT_MEM_BASE)
 #define IOP13XX_REG_ADDR32(reg)     	   (IOP13XX_PMMR_VIRT_MEM_BASE + (reg))
 #define IOP13XX_REG_ADDR16(reg)     	   (IOP13XX_PMMR_VIRT_MEM_BASE + (reg))
 #define IOP13XX_REG_ADDR8(reg)      	   (IOP13XX_PMMR_VIRT_MEM_BASE + (reg))
@@ -169,10 +145,10 @@
 #define IOP13XX_PMMR_SIZE		   0x00080000
 
 /*=================== Defines for Platform Devices =====================*/
-#define IOP13XX_UART0_PHYS  (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002300)
-#define IOP13XX_UART1_PHYS  (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002340)
-#define IOP13XX_UART0_VIRT  (IOP13XX_PMMR_VIRT_MEM_BASE | 0x00002300)
-#define IOP13XX_UART1_VIRT  (IOP13XX_PMMR_VIRT_MEM_BASE | 0x00002340)
+#define IOP13XX_UART0_PHYS  (IOP13XX_PMMR_PHYS_MEM_BASE + 0x00002300)
+#define IOP13XX_UART1_PHYS  (IOP13XX_PMMR_PHYS_MEM_BASE + 0x00002340)
+#define IOP13XX_UART0_VIRT  (IOP13XX_PMMR_VIRT_MEM_BASE + 0x00002300)
+#define IOP13XX_UART1_VIRT  (IOP13XX_PMMR_VIRT_MEM_BASE + 0x00002340)
 
 #define IOP13XX_I2C0_PHYS   (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002500)
 #define IOP13XX_I2C1_PHYS   (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002520)
diff --git a/arch/arm/mach-iop13xx/include/mach/memory.h b/arch/arm/mach-iop13xx/include/mach/memory.h
index 1afa99e..7c032d0 100644
--- a/arch/arm/mach-iop13xx/include/mach/memory.h
+++ b/arch/arm/mach-iop13xx/include/mach/memory.h
@@ -16,12 +16,12 @@
 #define IOP13XX_PMMR_P_START (IOP13XX_PMMR_PHYS_MEM_BASE)
 #define IOP13XX_PMMR_P_END   (IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_SIZE)
 
-static inline dma_addr_t __virt_to_lbus(unsigned long x)
+static inline dma_addr_t __virt_to_lbus(void __iomem *x)
 {
 	return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE;
 }
 
-static inline unsigned long __lbus_to_virt(dma_addr_t x)
+static inline void __iomem *__lbus_to_virt(dma_addr_t x)
 {
 	return x + IOP13XX_PMMR_VIRT_MEM_BASE - IOP13XX_PMMR_PHYS_MEM_BASE;
 }
@@ -38,23 +38,23 @@
 
 #define __arch_dma_to_virt(dev, addr)					\
 	({								\
-		unsigned long __virt;					\
+		void * __virt;						\
 		dma_addr_t __dma = addr;				\
 		if (is_lbus_device(dev) && __is_lbus_dma(__dma))	\
 			__virt = __lbus_to_virt(__dma);			\
 		else							\
-			__virt = __phys_to_virt(__dma);			\
-		(void *)__virt;						\
+			__virt = (void *)__phys_to_virt(__dma);		\
+		__virt;							\
 	})
 
 #define __arch_virt_to_dma(dev, addr)					\
 	({								\
-		unsigned long __virt = (unsigned long)addr;		\
+		void * __virt = addr;					\
 		dma_addr_t __dma;					\
 		if (is_lbus_device(dev) && __is_lbus_virt(__virt))	\
 			__dma = __virt_to_lbus(__virt);			\
 		else							\
-			__dma = __virt_to_phys(__virt);			\
+			__dma = __virt_to_phys((unsigned long)__virt);	\
 		__dma;							\
 	})
 
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 3c36419..183dc8b 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -23,25 +23,6 @@
 
 #include "pci.h"
 
-void * __iomem __iop13xx_io(unsigned long io_addr)
-{
-	void __iomem * io_virt;
-
-	switch (io_addr) {
-	case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-		io_virt = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(io_addr);
-		break;
-	case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-		io_virt = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(io_addr);
-		break;
-	default:
-		BUG();
-	}
-
-	return io_virt;
-}
-EXPORT_SYMBOL(__iop13xx_io);
-
 static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
 	size_t size, unsigned int mtype, void *caller)
 {
@@ -52,14 +33,14 @@
 		if (unlikely(!iop13xx_atux_mem_base))
 			retval = NULL;
 		else
-			retval = (void *)(iop13xx_atux_mem_base +
+			retval = (iop13xx_atux_mem_base +
 			         (cookie - IOP13XX_PCIX_LOWER_MEM_RA));
 		break;
 	case IOP13XX_PCIE_LOWER_MEM_RA ... IOP13XX_PCIE_UPPER_MEM_RA:
 		if (unlikely(!iop13xx_atue_mem_base))
 			retval = NULL;
 		else
-			retval = (void *)(iop13xx_atue_mem_base +
+			retval = (iop13xx_atue_mem_base +
 			         (cookie - IOP13XX_PCIE_LOWER_MEM_RA));
 		break;
 	case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
@@ -67,14 +48,8 @@
 				       (cookie - IOP13XX_PBI_LOWER_MEM_RA),
 				       size, mtype, __builtin_return_address(0));
 		break;
-	case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-		retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
-		break;
-	case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-		retval = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(cookie);
-		break;
 	case IOP13XX_PMMR_PHYS_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_PA:
-		retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
+		retval = IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
 		break;
 	default:
 		retval = __arm_ioremap_caller(cookie, size, mtype,
@@ -99,9 +74,7 @@
 		    goto skip;
 
 	switch ((u32) addr) {
-	case IOP13XX_PCIE_LOWER_IO_VA ... IOP13XX_PCIE_UPPER_IO_VA:
-	case IOP13XX_PCIX_LOWER_IO_VA ... IOP13XX_PCIX_UPPER_IO_VA:
-	case IOP13XX_PMMR_VIRT_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_VA:
+	case (u32)IOP13XX_PMMR_VIRT_MEM_BASE ... (u32)IOP13XX_PMMR_UPPER_MEM_VA:
 		goto skip;
 	}
 	__iounmap(addr);
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 861cb12..9082b84 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -36,8 +36,8 @@
 u32 iop13xx_atue_pmmr_offset; /* This offset can change based on strapping */
 static struct pci_bus *pci_bus_atux = 0;
 static struct pci_bus *pci_bus_atue = 0;
-u32 iop13xx_atue_mem_base;
-u32 iop13xx_atux_mem_base;
+void __iomem *iop13xx_atue_mem_base;
+void __iomem *iop13xx_atux_mem_base;
 size_t iop13xx_atue_mem_size;
 size_t iop13xx_atux_mem_size;
 
@@ -88,8 +88,7 @@
 				}
 
 				if (end) {
-					iop13xx_atux_mem_base =
-					(u32) __arm_ioremap_pfn(
+					iop13xx_atux_mem_base = __arm_ioremap_pfn(
 					__phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA)
 					, 0, iop13xx_atux_mem_size, MT_DEVICE);
 					if (!iop13xx_atux_mem_base) {
@@ -99,7 +98,7 @@
 					}
 				} else
 					iop13xx_atux_mem_size = 0;
-				PRINTK("%s: atu: %d bus_size: %d mem_base: %x\n",
+				PRINTK("%s: atu: %d bus_size: %d mem_base: %p\n",
 				__func__, atu, iop13xx_atux_mem_size,
 				iop13xx_atux_mem_base);
 				break;
@@ -114,8 +113,7 @@
 				}
 
 				if (end) {
-					iop13xx_atue_mem_base =
-					(u32) __arm_ioremap_pfn(
+					iop13xx_atue_mem_base = __arm_ioremap_pfn(
 					__phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA)
 					, 0, iop13xx_atue_mem_size, MT_DEVICE);
 					if (!iop13xx_atue_mem_base) {
@@ -125,13 +123,13 @@
 					}
 				} else
 					iop13xx_atue_mem_size = 0;
-				PRINTK("%s: atu: %d bus_size: %d mem_base: %x\n",
+				PRINTK("%s: atu: %d bus_size: %d mem_base: %p\n",
 				__func__, atu, iop13xx_atue_mem_size,
 				iop13xx_atue_mem_base);
 				break;
 			}
 
-			printk("%s: Initialized (%uM @ resource/virtual: %08lx/%08x)\n",
+			printk("%s: Initialized (%uM @ resource/virtual: %08lx/%p)\n",
 			atu ? "ATUE" : "ATUX",
 			(atu ? iop13xx_atue_mem_size : iop13xx_atux_mem_size) /
 			SZ_1M,
@@ -970,7 +968,6 @@
 	__raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, IOP13XX_XBG_BECSR);
 
 	/* Setup the Min Address for PCI memory... */
-	pcibios_min_io = 0;
 	pcibios_min_mem = IOP13XX_PCIX_LOWER_MEM_BA;
 
 	/* if Linux is given control of an ATU
@@ -1003,7 +1000,7 @@
 	if (nr > 1)
 		return 0;
 
-	res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("PCI: unable to alloc resources");
 
@@ -1042,17 +1039,13 @@
 				  << IOP13XX_ATUX_PCIXSR_FUNC_NUM;
 		__raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
 
-		res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
-		res[0].end   = IOP13XX_PCIX_UPPER_IO_PA;
-		res[0].name  = "IQ81340 ATUX PCI I/O Space";
-		res[0].flags = IORESOURCE_IO;
+		pci_ioremap_io(0, IOP13XX_PCIX_LOWER_IO_PA);
 
-		res[1].start = IOP13XX_PCIX_LOWER_MEM_RA;
-		res[1].end   = IOP13XX_PCIX_UPPER_MEM_RA;
-		res[1].name  = "IQ81340 ATUX PCI Memory Space";
-		res[1].flags = IORESOURCE_MEM;
+		res->start = IOP13XX_PCIX_LOWER_MEM_RA;
+		res->end   = IOP13XX_PCIX_UPPER_MEM_RA;
+		res->name  = "IQ81340 ATUX PCI Memory Space";
+		res->flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
 		break;
 	case IOP13XX_INIT_ATU_ATUE:
 		/* Note: the function number field in the PCSR is ro */
@@ -1063,17 +1056,13 @@
 
 		__raw_writel(pcsr, IOP13XX_ATUE_PCSR);
 
-		res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
-		res[0].end   = IOP13XX_PCIE_UPPER_IO_PA;
-		res[0].name  = "IQ81340 ATUE PCI I/O Space";
-		res[0].flags = IORESOURCE_IO;
+		pci_ioremap_io(SZ_64K, IOP13XX_PCIE_LOWER_IO_PA);
 
-		res[1].start = IOP13XX_PCIE_LOWER_MEM_RA;
-		res[1].end   = IOP13XX_PCIE_UPPER_MEM_RA;
-		res[1].name  = "IQ81340 ATUE PCI Memory Space";
-		res[1].flags = IORESOURCE_MEM;
+		res->start = IOP13XX_PCIE_LOWER_MEM_RA;
+		res->end   = IOP13XX_PCIE_UPPER_MEM_RA;
+		res->name  = "IQ81340 ATUE PCI Memory Space";
+		res->flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
 		sys->map_irq = iop13xx_pcie_map_irq;
 		break;
 	default:
@@ -1081,11 +1070,9 @@
 		return 0;
 	}
 
-	request_resource(&ioport_resource, &res[0]);
-	request_resource(&iomem_resource, &res[1]);
+	request_resource(&iomem_resource, res);
 
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h
index c70cf5b4..d45a80b 100644
--- a/arch/arm/mach-iop13xx/pci.h
+++ b/arch/arm/mach-iop13xx/pci.h
@@ -1,6 +1,6 @@
 #include <linux/types.h>
 
-extern u32 iop13xx_atue_mem_base;
-extern u32 iop13xx_atux_mem_base;
+extern void __iomem *iop13xx_atue_mem_base;
+extern void __iomem *iop13xx_atux_mem_base;
 extern size_t iop13xx_atue_mem_size;
 extern size_t iop13xx_atux_mem_size;
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index daabb1f..3181f61 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -36,20 +36,10 @@
  */
 static struct map_desc iop13xx_std_desc[] __initdata = {
 	{    /* mem mapped registers */
-		.virtual = IOP13XX_PMMR_VIRT_MEM_BASE,
+		.virtual = (unsigned long)IOP13XX_PMMR_VIRT_MEM_BASE,
 		.pfn 	 = __phys_to_pfn(IOP13XX_PMMR_PHYS_MEM_BASE),
 		.length  = IOP13XX_PMMR_SIZE,
 		.type	 = MT_DEVICE,
-	}, { /* PCIE IO space */
-		.virtual = IOP13XX_PCIE_LOWER_IO_VA,
-		.pfn 	 = __phys_to_pfn(IOP13XX_PCIE_LOWER_IO_PA),
-		.length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-		.type	 = MT_DEVICE,
-	}, { /* PCIX IO space */
-		.virtual = IOP13XX_PCIX_LOWER_IO_VA,
-		.pfn 	 = __phys_to_pfn(IOP13XX_PCIX_LOWER_IO_PA),
-		.length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-		.type	 = MT_DEVICE,
 	},
 };
 
@@ -81,8 +71,8 @@
 
 static struct plat_serial8250_port iop13xx_uart0_data[] = {
 	{
-       .membase     = (char*)(IOP13XX_UART0_VIRT),
-       .mapbase     = (IOP13XX_UART0_PHYS),
+       .membase     = IOP13XX_UART0_VIRT,
+       .mapbase     = IOP13XX_UART0_PHYS,
        .irq         = IRQ_IOP13XX_UART0,
        .uartclk     = IOP13XX_UART_XTAL,
        .regshift    = 2,
@@ -94,8 +84,8 @@
 
 static struct plat_serial8250_port iop13xx_uart1_data[] = {
 	{
-       .membase     = (char*)(IOP13XX_UART1_VIRT),
-       .mapbase     = (IOP13XX_UART1_PHYS),
+       .membase     = IOP13XX_UART1_VIRT,
+       .mapbase     = IOP13XX_UART1_PHYS,
        .irq         = IRQ_IOP13XX_UART1,
        .uartclk     = IOP13XX_UART_XTAL,
        .regshift    = 2,
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index c15a100..02e20c3 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -183,7 +183,7 @@
 
 static void glantank_power_off(void)
 {
-	__raw_writeb(0x01, 0xfe8d0004);
+	__raw_writeb(0x01, IOMEM(0xfe8d0004));
 
 	while (1)
 		;
diff --git a/arch/arm/mach-iop32x/include/mach/io.h b/arch/arm/mach-iop32x/include/mach/io.h
deleted file mode 100644
index e2ada26..0000000
--- a/arch/arm/mach-iop32x/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/io.h
- *
- * Copyright (C) 2001 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT		0xffffffff
-#define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
diff --git a/arch/arm/mach-iop33x/include/mach/io.h b/arch/arm/mach-iop33x/include/mach/io.h
deleted file mode 100644
index f7c1b65..0000000
--- a/arch/arm/mach-iop33x/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/io.h
- *
- * Copyright (C) 2001  MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT		0xffffffff
-#define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index a9f80943..fdf91a1 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -53,24 +53,24 @@
  *************************************************************************/
 static struct map_desc ixp4xx_io_desc[] __initdata = {
 	{	/* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */
-		.virtual	= IXP4XX_PERIPHERAL_BASE_VIRT,
+		.virtual	= (unsigned long)IXP4XX_PERIPHERAL_BASE_VIRT,
 		.pfn		= __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS),
 		.length		= IXP4XX_PERIPHERAL_REGION_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* Expansion Bus Config Registers */
-		.virtual	= IXP4XX_EXP_CFG_BASE_VIRT,
+		.virtual	= (unsigned long)IXP4XX_EXP_CFG_BASE_VIRT,
 		.pfn		= __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
 		.length		= IXP4XX_EXP_CFG_REGION_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* PCI Registers */
-		.virtual	= IXP4XX_PCI_CFG_BASE_VIRT,
+		.virtual	= (unsigned long)IXP4XX_PCI_CFG_BASE_VIRT,
 		.pfn		= __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
 		.length		= IXP4XX_PCI_CFG_REGION_SIZE,
 		.type		= MT_DEVICE
 	},
 #ifdef CONFIG_DEBUG_LL
 	{	/* Debug UART mapping */
-		.virtual	= IXP4XX_DEBUG_UART_BASE_VIRT,
+		.virtual	= (unsigned long)IXP4XX_DEBUG_UART_BASE_VIRT,
 		.pfn		= __phys_to_pfn(IXP4XX_DEBUG_UART_BASE_PHYS),
 		.length		= IXP4XX_DEBUG_UART_REGION_SIZE,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
index b2ef65d..ebc0ba3 100644
--- a/arch/arm/mach-ixp4xx/include/mach/cpu.h
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -14,6 +14,7 @@
 #ifndef __ASM_ARCH_CPU_H__
 #define __ASM_ARCH_CPU_H__
 
+#include <linux/io.h>
 #include <asm/cputype.h>
 
 /* Processor id value in CP15 Register 0 */
@@ -37,7 +38,7 @@
 
 static inline u32 ixp4xx_read_feature_bits(void)
 {
-	u32 val = ~*IXP4XX_EXP_CFG2;
+	u32 val = ~__raw_readl(IXP4XX_EXP_CFG2);
 
 	if (cpu_is_ixp42x_rev_a0())
 		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
@@ -51,7 +52,7 @@
 
 static inline void ixp4xx_write_feature_bits(u32 value)
 {
-	*IXP4XX_EXP_CFG2 = ~value;
+	__raw_writel(~value, IXP4XX_EXP_CFG2);
 }
 
 #endif  /* _ASM_ARCH_CPU_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
index 97c530f..eb68b61 100644
--- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -49,21 +49,21 @@
  * Expansion BUS Configuration registers
  */
 #define IXP4XX_EXP_CFG_BASE_PHYS	(0xC4000000)
-#define IXP4XX_EXP_CFG_BASE_VIRT	(0xFFBFE000)
+#define IXP4XX_EXP_CFG_BASE_VIRT	IOMEM(0xFFBFE000)
 #define IXP4XX_EXP_CFG_REGION_SIZE	(0x00001000)
 
 /*
  * PCI Config registers
  */
 #define IXP4XX_PCI_CFG_BASE_PHYS	(0xC0000000)
-#define	IXP4XX_PCI_CFG_BASE_VIRT	(0xFFBFF000)
+#define	IXP4XX_PCI_CFG_BASE_VIRT	IOMEM(0xFFBFF000)
 #define IXP4XX_PCI_CFG_REGION_SIZE	(0x00001000)
 
 /*
  * Peripheral space
  */
 #define IXP4XX_PERIPHERAL_BASE_PHYS	(0xC8000000)
-#define IXP4XX_PERIPHERAL_BASE_VIRT	(0xFFBEB000)
+#define IXP4XX_PERIPHERAL_BASE_VIRT	IOMEM(0xFFBEB000)
 #define IXP4XX_PERIPHERAL_REGION_SIZE	(0x00013000)
 
 /*
@@ -73,7 +73,7 @@
  * aligned so that it * can be used with the low-level debug code.
  */
 #define	IXP4XX_DEBUG_UART_BASE_PHYS	(0xC8000000)
-#define	IXP4XX_DEBUG_UART_BASE_VIRT	(0xffb00000)
+#define	IXP4XX_DEBUG_UART_BASE_VIRT	IOMEM(0xffb00000)
 #define	IXP4XX_DEBUG_UART_REGION_SIZE	(0x00001000)
 
 #define IXP4XX_EXP_CS0_OFFSET	0x00
@@ -92,7 +92,7 @@
 /*
  * Expansion Bus Controller registers.
  */
-#define IXP4XX_EXP_REG(x) ((volatile u32 *)(IXP4XX_EXP_CFG_BASE_VIRT+(x)))
+#define IXP4XX_EXP_REG(x) ((volatile u32 __iomem *)(IXP4XX_EXP_CFG_BASE_VIRT+(x)))
 
 #define IXP4XX_EXP_CS0      IXP4XX_EXP_REG(IXP4XX_EXP_CS0_OFFSET)
 #define IXP4XX_EXP_CS1      IXP4XX_EXP_REG(IXP4XX_EXP_CS1_OFFSET)
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 1201191..3f7b05f 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -42,16 +42,6 @@
  ****************************************************************************/
 static struct map_desc kirkwood_io_desc[] __initdata = {
 	{
-		.virtual	= KIRKWOOD_PCIE_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
-		.length		= KIRKWOOD_PCIE_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= KIRKWOOD_PCIE1_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
-		.length		= KIRKWOOD_PCIE1_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= KIRKWOOD_REGS_VIRT_BASE,
 		.pfn		= __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
 		.length		= KIRKWOOD_REGS_SIZE,
diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h
deleted file mode 100644
index 5d0ab617..0000000
--- a/arch/arm/mach-kirkwood/include/mach/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "kirkwood.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)((addr - KIRKWOOD_PCIE_IO_BUS_BASE)
-					+ KIRKWOOD_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)			__io(a)
-
-#endif
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index c5b6851..af4f000 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -37,14 +37,12 @@
 #define KIRKWOOD_NAND_MEM_SIZE		SZ_1K
 
 #define KIRKWOOD_PCIE1_IO_PHYS_BASE	0xf3000000
-#define KIRKWOOD_PCIE1_IO_VIRT_BASE	0xfef00000
-#define KIRKWOOD_PCIE1_IO_BUS_BASE	0x00100000
-#define KIRKWOOD_PCIE1_IO_SIZE		SZ_1M
+#define KIRKWOOD_PCIE1_IO_BUS_BASE	0x00010000
+#define KIRKWOOD_PCIE1_IO_SIZE		SZ_64K
 
 #define KIRKWOOD_PCIE_IO_PHYS_BASE	0xf2000000
-#define KIRKWOOD_PCIE_IO_VIRT_BASE	0xfee00000
 #define KIRKWOOD_PCIE_IO_BUS_BASE	0x00000000
-#define KIRKWOOD_PCIE_IO_SIZE		SZ_1M
+#define KIRKWOOD_PCIE_IO_SIZE		SZ_64K
 
 #define KIRKWOOD_REGS_PHYS_BASE		0xf1000000
 #define KIRKWOOD_REGS_VIRT_BASE		0xfed00000
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 6e8b2ef..532d8ac 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -56,7 +56,7 @@
 	void __iomem		*base;
 	spinlock_t		conf_lock;
 	int			irq;
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static int pcie_port_map[2];
@@ -137,20 +137,12 @@
 	pp->irq	= IRQ_KIRKWOOD_PCIE;
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	pp->res[0].name = "PCIe 0 I/O Space";
-	pp->res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
-	pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
-	pp->res[0].flags = IORESOURCE_IO;
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	pp->res[1].name = "PCIe 0 MEM";
-	pp->res[1].start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
-	pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
-	pp->res[1].flags = IORESOURCE_MEM;
+	pp->res.name = "PCIe 0 MEM";
+	pp->res.start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
+	pp->res.end = pp->res.start + KIRKWOOD_PCIE_MEM_SIZE - 1;
+	pp->res.flags = IORESOURCE_MEM;
 }
 
 static void __init pcie1_ioresources_init(struct pcie_port *pp)
@@ -159,20 +151,12 @@
 	pp->irq	= IRQ_KIRKWOOD_PCIE1;
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	pp->res[0].name = "PCIe 1 I/O Space";
-	pp->res[0].start = KIRKWOOD_PCIE1_IO_BUS_BASE;
-	pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
-	pp->res[0].flags = IORESOURCE_IO;
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	pp->res[1].name = "PCIe 1 MEM";
-	pp->res[1].start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
-	pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
-	pp->res[1].flags = IORESOURCE_MEM;
+	pp->res.name = "PCIe 1 MEM";
+	pp->res.start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
+	pp->res.end = pp->res.start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
+	pp->res.flags = IORESOURCE_MEM;
 }
 
 static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
@@ -197,23 +181,21 @@
 	case 0:
 		kirkwood_enable_pcie_clk("0");
 		pcie0_ioresources_init(pp);
+		pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE_IO_PHYS_BASE);
 		break;
 	case 1:
 		kirkwood_enable_pcie_clk("1");
 		pcie1_ioresources_init(pp);
+		pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE1_IO_PHYS_BASE);
 		break;
 	default:
 		panic("PCIe setup: invalid controller %d", index);
 	}
 
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe%d IO resource failed\n", index);
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	if (request_resource(&iomem_resource, &pp->res))
 		panic("Request PCIe%d Memory resource failed\n", index);
 
-	sys->io_offset = 0;
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	/*
 	 * Generic PCIe unit setup.
diff --git a/arch/arm/mach-ks8695/cpu.c b/arch/arm/mach-ks8695/cpu.c
index 7f3f240..ddb2422 100644
--- a/arch/arm/mach-ks8695/cpu.c
+++ b/arch/arm/mach-ks8695/cpu.c
@@ -36,7 +36,7 @@
 
 static struct __initdata map_desc ks8695_io_desc[] = {
 	{
-		.virtual	= KS8695_IO_VA,
+		.virtual	= (unsigned long)KS8695_IO_VA,
 		.pfn		= __phys_to_pfn(KS8695_IO_PA),
 		.length		= KS8695_IO_SIZE,
 		.type		= MT_DEVICE,
diff --git a/arch/arm/mach-ks8695/include/mach/hardware.h b/arch/arm/mach-ks8695/include/mach/hardware.h
index 5e0c388..5090338 100644
--- a/arch/arm/mach-ks8695/include/mach/hardware.h
+++ b/arch/arm/mach-ks8695/include/mach/hardware.h
@@ -33,7 +33,7 @@
  * head debug code as the initial MMU setup only deals in L1 sections.
  */
 #define KS8695_IO_PA		0x03F00000
-#define KS8695_IO_VA		0xF0000000
+#define KS8695_IO_VA		IOMEM(0xF0000000)
 #define KS8695_IO_SIZE		SZ_1M
 
 #define KS8695_PCIMEM_PA	0x60000000
diff --git a/arch/arm/mach-ks8695/include/mach/regs-timer.h b/arch/arm/mach-ks8695/include/mach/regs-timer.h
deleted file mode 100644
index e620cda..0000000
--- a/arch/arm/mach-ks8695/include/mach/regs-timer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-ks8695/include/mach/regs-timer.h
- *
- * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
- * Copyright (C) 2006 Simtec Electronics
- *
- * KS8695 - Timer registers and bit definitions.
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef KS8695_TIMER_H
-#define KS8695_TIMER_H
-
-#define KS8695_TMR_OFFSET	(0xF0000 + 0xE400)
-#define KS8695_TMR_VA		(KS8695_IO_VA + KS8695_TMR_OFFSET)
-#define KS8695_TMR_PA		(KS8695_IO_PA + KS8695_TMR_OFFSET)
-
-
-/*
- * Timer registers
- */
-#define KS8695_TMCON		(0x00)		/* Timer Control Register */
-#define KS8695_T1TC		(0x04)		/* Timer 1 Timeout Count Register */
-#define KS8695_T0TC		(0x08)		/* Timer 0 Timeout Count Register */
-#define KS8695_T1PD		(0x0C)		/* Timer 1 Pulse Count Register */
-#define KS8695_T0PD		(0x10)		/* Timer 0 Pulse Count Register */
-
-
-/* Timer Control Register */
-#define TMCON_T1EN		(1 << 1)	/* Timer 1 Enable */
-#define TMCON_T0EN		(1 << 0)	/* Timer 0 Enable */
-
-/* Timer0 Timeout Counter Register */
-#define T0TC_WATCHDOG		(0xff)		/* Enable watchdog mode */
-
-
-#endif
diff --git a/arch/arm/mach-ks8695/include/mach/uncompress.h b/arch/arm/mach-ks8695/include/mach/uncompress.h
index 9495cb4..8879d61 100644
--- a/arch/arm/mach-ks8695/include/mach/uncompress.h
+++ b/arch/arm/mach-ks8695/include/mach/uncompress.h
@@ -19,15 +19,15 @@
 
 static void putc(char c)
 {
-	while (!(__raw_readl(KS8695_UART_PA + KS8695_URLS) & URLS_URTHRE))
+	while (!(__raw_readl((void __iomem*)KS8695_UART_PA + KS8695_URLS) & URLS_URTHRE))
 		barrier();
 
-	__raw_writel(c, KS8695_UART_PA + KS8695_URTH);
+	__raw_writel(c, (void __iomem*)KS8695_UART_PA + KS8695_URTH);
 }
 
 static inline void flush(void)
 {
-	while (!(__raw_readl(KS8695_UART_PA + KS8695_URLS) & URLS_URTE))
+	while (!(__raw_readl((void __iomem*)KS8695_UART_PA + KS8695_URLS) & URLS_URTE))
 		barrier();
 }
 
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index ec783a3..46c84bc 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -25,53 +25,98 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/io.h>
+#include <linux/clockchips.h>
 
 #include <asm/mach/time.h>
 #include <asm/system_misc.h>
 
-#include <mach/regs-timer.h>
 #include <mach/regs-irq.h>
 
 #include "generic.h"
 
+#define KS8695_TMR_OFFSET	(0xF0000 + 0xE400)
+#define KS8695_TMR_VA		(KS8695_IO_VA + KS8695_TMR_OFFSET)
+#define KS8695_TMR_PA		(KS8695_IO_PA + KS8695_TMR_OFFSET)
+
 /*
- * Returns number of ms since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
+ * Timer registers
  */
-static unsigned long ks8695_gettimeoffset (void)
+#define KS8695_TMCON		(0x00)		/* Timer Control Register */
+#define KS8695_T1TC		(0x04)		/* Timer 1 Timeout Count Register */
+#define KS8695_T0TC		(0x08)		/* Timer 0 Timeout Count Register */
+#define KS8695_T1PD		(0x0C)		/* Timer 1 Pulse Count Register */
+#define KS8695_T0PD		(0x10)		/* Timer 0 Pulse Count Register */
+
+/* Timer Control Register */
+#define TMCON_T1EN		(1 << 1)	/* Timer 1 Enable */
+#define TMCON_T0EN		(1 << 0)	/* Timer 0 Enable */
+
+/* Timer0 Timeout Counter Register */
+#define T0TC_WATCHDOG		(0xff)		/* Enable watchdog mode */
+
+static void ks8695_set_mode(enum clock_event_mode mode,
+			    struct clock_event_device *evt)
 {
-	unsigned long elapsed, tick2, intpending;
+	u32 tmcon;
 
-	/*
-	 * Get the current number of ticks.  Note that there is a race
-	 * condition between us reading the timer and checking for an
-	 * interrupt.  We solve this by ensuring that the counter has not
-	 * reloaded between our two reads.
-	 */
-	elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
-	do {
-		tick2 = elapsed;
-		intpending = __raw_readl(KS8695_IRQ_VA + KS8695_INTST) & (1 << KS8695_IRQ_TIMER1);
-		elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
-	} while (elapsed > tick2);
+	if (mode == CLOCK_EVT_FEAT_PERIODIC) {
+		u32 rate = DIV_ROUND_CLOSEST(KS8695_CLOCK_RATE, HZ);
+		u32 half = DIV_ROUND_CLOSEST(rate, 2);
 
-	/* Convert to number of ticks expired (not remaining) */
-	elapsed = (CLOCK_TICK_RATE / HZ) - elapsed;
+		/* Disable timer 1 */
+		tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
+		tmcon &= ~TMCON_T1EN;
+		writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
 
-	/* Is interrupt pending?  If so, then timer has been reloaded already. */
-	if (intpending)
-		elapsed += (CLOCK_TICK_RATE / HZ);
+		/* Both registers need to count down */
+		writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC);
+		writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD);
 
-	/* Convert ticks to usecs */
-	return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+		/* Re-enable timer1 */
+		tmcon |= TMCON_T1EN;
+		writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
+	}
 }
 
+static int ks8695_set_next_event(unsigned long cycles,
+				 struct clock_event_device *evt)
+
+{
+	u32 half = DIV_ROUND_CLOSEST(cycles, 2);
+	u32 tmcon;
+
+	/* Disable timer 1 */
+	tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
+	tmcon &= ~TMCON_T1EN;
+	writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
+
+	/* Both registers need to count down */
+	writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC);
+	writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD);
+
+	/* Re-enable timer1 */
+	tmcon |= TMCON_T1EN;
+	writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
+
+	return 0;
+}
+
+static struct clock_event_device clockevent_ks8695 = {
+	.name		= "ks8695_t1tc",
+	.rating		= 300, /* Reasonably fast and accurate clock event */
+	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+	.set_next_event	= ks8695_set_next_event,
+	.set_mode	= ks8695_set_mode,
+};
+
 /*
  * IRQ handler for the timer.
  */
 static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
 {
-	timer_tick();
+	struct clock_event_device *evt = &clockevent_ks8695;
+
+	evt->event_handler(evt);
 	return IRQ_HANDLED;
 }
 
@@ -83,18 +128,22 @@
 
 static void ks8695_timer_setup(void)
 {
-	unsigned long tmout = CLOCK_TICK_RATE / HZ;
 	unsigned long tmcon;
 
-	/* disable timer1 */
-	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
-	__raw_writel(tmcon & ~TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
+	/* Disable timer 0 and 1 */
+	tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
+	tmcon &= ~TMCON_T0EN;
+	tmcon &= ~TMCON_T1EN;
+	writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
 
-	__raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1TC);
-	__raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1PD);
-
-	/* re-enable timer1 */
-	__raw_writel(tmcon | TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
+	/*
+	 * Use timer 1 to fire IRQs on the timeline, minimum 2 cycles
+	 * (one on each counter) maximum 2*2^32, but the API will only
+	 * accept up to a 32bit full word (0xFFFFFFFFU).
+	 */
+	clockevents_config_and_register(&clockevent_ks8695,
+					KS8695_CLOCK_RATE, 2,
+					0xFFFFFFFFU);
 }
 
 static void __init ks8695_timer_init (void)
@@ -107,8 +156,6 @@
 
 struct sys_timer ks8695_timer = {
 	.init		= ks8695_timer_init,
-	.offset		= ks8695_gettimeoffset,
-	.resume		= ks8695_timer_setup,
 };
 
 void ks8695_restart(char mode, const char *cmd)
@@ -119,12 +166,12 @@
 		soft_restart(0);
 
 	/* disable timer0 */
-	reg = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
-	__raw_writel(reg & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
+	reg = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
+	writel_relaxed(reg & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
 
 	/* enable watchdog mode */
-	__raw_writel((10 << 8) | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
+	writel_relaxed((10 << 8) | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
 
 	/* re-enable timer0 */
-	__raw_writel(reg | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
+	writel_relaxed(reg | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
 }
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
index a48dc2d..0d4db8c 100644
--- a/arch/arm/mach-lpc32xx/common.c
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -177,25 +177,25 @@
 
 static struct map_desc lpc32xx_io_desc[] __initdata = {
 	{
-		.virtual	= IO_ADDRESS(LPC32XX_AHB0_START),
+		.virtual	= (unsigned long)IO_ADDRESS(LPC32XX_AHB0_START),
 		.pfn		= __phys_to_pfn(LPC32XX_AHB0_START),
 		.length		= LPC32XX_AHB0_SIZE,
 		.type		= MT_DEVICE
 	},
 	{
-		.virtual	= IO_ADDRESS(LPC32XX_AHB1_START),
+		.virtual	= (unsigned long)IO_ADDRESS(LPC32XX_AHB1_START),
 		.pfn		= __phys_to_pfn(LPC32XX_AHB1_START),
 		.length		= LPC32XX_AHB1_SIZE,
 		.type		= MT_DEVICE
 	},
 	{
-		.virtual	= IO_ADDRESS(LPC32XX_FABAPB_START),
+		.virtual	= (unsigned long)IO_ADDRESS(LPC32XX_FABAPB_START),
 		.pfn		= __phys_to_pfn(LPC32XX_FABAPB_START),
 		.length		= LPC32XX_FABAPB_SIZE,
 		.type		= MT_DEVICE
 	},
 	{
-		.virtual	= IO_ADDRESS(LPC32XX_IRAM_BASE),
+		.virtual	= (unsigned long)IO_ADDRESS(LPC32XX_IRAM_BASE),
 		.pfn		= __phys_to_pfn(LPC32XX_IRAM_BASE),
 		.length		= (LPC32XX_IRAM_BANK_SIZE * 2),
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h b/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h
index 1816e22..a544e96 100644
--- a/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h
+++ b/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h
@@ -30,7 +30,7 @@
 #define LPC32XX_GPIO_P1_MAX 24
 #define LPC32XX_GPIO_P2_MAX 13
 #define LPC32XX_GPIO_P3_MAX 6
-#define LPC32XX_GPI_P3_MAX 28
+#define LPC32XX_GPI_P3_MAX 29
 #define LPC32XX_GPO_P3_MAX 24
 
 #define LPC32XX_GPIO_P0_GRP 0
diff --git a/arch/arm/mach-lpc32xx/include/mach/hardware.h b/arch/arm/mach-lpc32xx/include/mach/hardware.h
index 33e1dde..69065de 100644
--- a/arch/arm/mach-lpc32xx/include/mach/hardware.h
+++ b/arch/arm/mach-lpc32xx/include/mach/hardware.h
@@ -25,7 +25,7 @@
 /*
  * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0
  */
-#define IO_ADDRESS(x)	(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
+#define IO_ADDRESS(x)	IOMEM(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
 			 IO_BASE)
 
 #define io_p2v(x)	((void __iomem *) (unsigned long) IO_ADDRESS(x))
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index 5b1cc35..3c63327 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -283,21 +283,25 @@
 	case IRQ_TYPE_EDGE_RISING:
 		/* Rising edge sensitive */
 		__lpc32xx_set_irq_type(d->hwirq, 1, 1);
+		__irq_set_handler_locked(d->hwirq, handle_edge_irq);
 		break;
 
 	case IRQ_TYPE_EDGE_FALLING:
 		/* Falling edge sensitive */
 		__lpc32xx_set_irq_type(d->hwirq, 0, 1);
+		__irq_set_handler_locked(d->hwirq, handle_edge_irq);
 		break;
 
 	case IRQ_TYPE_LEVEL_LOW:
 		/* Low level sensitive */
 		__lpc32xx_set_irq_type(d->hwirq, 0, 0);
+		__irq_set_handler_locked(d->hwirq, handle_level_irq);
 		break;
 
 	case IRQ_TYPE_LEVEL_HIGH:
 		/* High level sensitive */
 		__lpc32xx_set_irq_type(d->hwirq, 1, 0);
+		__irq_set_handler_locked(d->hwirq, handle_level_irq);
 		break;
 
 	/* Other modes are not supported */
@@ -305,9 +309,6 @@
 		return -EINVAL;
 	}
 
-	/* Ok to use the level handler for all types */
-	irq_set_handler(d->hwirq, handle_level_irq);
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index b07dcc9..e8ff4c3 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -24,12 +24,9 @@
 #include <linux/irq.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/eeprom.h>
 #include <linux/gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
-#include <linux/amba/pl022.h>
 #include <linux/amba/pl08x.h>
 #include <linux/amba/mmci.h>
 #include <linux/of.h>
@@ -37,6 +34,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
+#include <linux/mtd/lpc32xx_slc.h>
+#include <linux/mtd/lpc32xx_mlc.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -156,21 +155,6 @@
 	.remove		= lpc32xx_clcd_remove,
 };
 
-/*
- * AMBA SSP (SPI)
- */
-static struct pl022_ssp_controller lpc32xx_ssp0_data = {
-	.bus_id			= 0,
-	.num_chipselect		= 1,
-	.enable_dma		= 0,
-};
-
-static struct pl022_ssp_controller lpc32xx_ssp1_data = {
-	.bus_id			= 1,
-	.num_chipselect		= 1,
-	.enable_dma		= 0,
-};
-
 static struct pl08x_channel_data pl08x_slave_channels[] = {
 	{
 		.bus_id = "nand-slc",
@@ -223,13 +207,25 @@
 	 * gather, and the MMCI driver doesn't do it this way */
 };
 
+static struct lpc32xx_slc_platform_data lpc32xx_slc_data = {
+	.dma_filter = pl08x_filter_id,
+};
+
+static struct lpc32xx_mlc_platform_data lpc32xx_mlc_data = {
+	.dma_filter = pl08x_filter_id,
+};
+
 static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
-	OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", &lpc32xx_ssp0_data),
-	OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", &lpc32xx_ssp1_data),
+	OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", NULL),
+	OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", NULL),
 	OF_DEV_AUXDATA("arm,pl110", 0x31040000, "dev:clcd", &lpc32xx_clcd_data),
 	OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
 	OF_DEV_AUXDATA("arm,pl18x", 0x20098000, "20098000.sd",
 		       &lpc32xx_mmci_data),
+	OF_DEV_AUXDATA("nxp,lpc3220-slc", 0x20020000, "20020000.flash",
+		       &lpc32xx_slc_data),
+	OF_DEV_AUXDATA("nxp,lpc3220-mlc", 0x200a8000, "200a8000.flash",
+		       &lpc32xx_mlc_data),
 	{ }
 };
 
@@ -253,12 +249,6 @@
 
 	of_platform_populate(NULL, of_default_bus_match_table,
 			     lpc32xx_auxdata_lookup, NULL);
-
-	/* Register GPIOs used on this board */
-	if (gpio_request(MMC_PWR_ENABLE_GPIO, "mmc_power_en"))
-		pr_err("Error requesting gpio %u", MMC_PWR_ENABLE_GPIO);
-	else if (gpio_direction_output(MMC_PWR_ENABLE_GPIO, 1))
-		pr_err("Error setting gpio %u to output", MMC_PWR_ENABLE_GPIO);
 }
 
 static char const *lpc32xx_dt_compat[] __initdata = {
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index b786f7e..095c155 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,13 +2,19 @@
 # Makefile for Marvell's PXA168 processors line
 #
 
-obj-y				+= common.o clock.o devices.o time.o irq.o
+obj-y				+= common.o devices.o time.o irq.o
 
 # SoC support
 obj-$(CONFIG_CPU_PXA168)	+= pxa168.o
 obj-$(CONFIG_CPU_PXA910)	+= pxa910.o
 obj-$(CONFIG_CPU_MMP2)		+= mmp2.o sram.o
 
+ifeq ($(CONFIG_COMMON_CLK), )
+obj-y				+= clock.o
+obj-$(CONFIG_CPU_PXA168)	+= clock-pxa168.o
+obj-$(CONFIG_CPU_PXA910)	+= clock-pxa910.o
+obj-$(CONFIG_CPU_MMP2)		+= clock-mmp2.o
+endif
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_CPU_PXA910)	+= pm-pxa910.o
 obj-$(CONFIG_CPU_MMP2)		+= pm-mmp2.o
diff --git a/arch/arm/mach-mmp/clock-mmp2.c b/arch/arm/mach-mmp/clock-mmp2.c
new file mode 100644
index 0000000..21d2200
--- /dev/null
+++ b/arch/arm/mach-mmp/clock-mmp2.c
@@ -0,0 +1,111 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/addr-map.h>
+
+#include "common.h"
+#include "clock.h"
+
+/*
+ * APB Clock register offsets for MMP2
+ */
+#define APBC_RTC	APBC_REG(0x000)
+#define APBC_TWSI1	APBC_REG(0x004)
+#define APBC_TWSI2	APBC_REG(0x008)
+#define APBC_TWSI3	APBC_REG(0x00c)
+#define APBC_TWSI4	APBC_REG(0x010)
+#define APBC_KPC	APBC_REG(0x018)
+#define APBC_UART1	APBC_REG(0x02c)
+#define APBC_UART2	APBC_REG(0x030)
+#define APBC_UART3	APBC_REG(0x034)
+#define APBC_GPIO	APBC_REG(0x038)
+#define APBC_PWM0	APBC_REG(0x03c)
+#define APBC_PWM1	APBC_REG(0x040)
+#define APBC_PWM2	APBC_REG(0x044)
+#define APBC_PWM3	APBC_REG(0x048)
+#define APBC_SSP0	APBC_REG(0x04c)
+#define APBC_SSP1	APBC_REG(0x050)
+#define APBC_SSP2	APBC_REG(0x054)
+#define APBC_SSP3	APBC_REG(0x058)
+#define APBC_SSP4	APBC_REG(0x05c)
+#define APBC_SSP5	APBC_REG(0x060)
+#define APBC_TWSI5	APBC_REG(0x07c)
+#define APBC_TWSI6	APBC_REG(0x080)
+#define APBC_UART4	APBC_REG(0x088)
+
+#define APMU_USB	APMU_REG(0x05c)
+#define APMU_NAND	APMU_REG(0x060)
+#define APMU_SDH0	APMU_REG(0x054)
+#define APMU_SDH1	APMU_REG(0x058)
+#define APMU_SDH2	APMU_REG(0x0e8)
+#define APMU_SDH3	APMU_REG(0x0ec)
+
+static void sdhc_clk_enable(struct clk *clk)
+{
+	uint32_t clk_rst;
+
+	clk_rst  =  __raw_readl(clk->clk_rst);
+	clk_rst |= clk->enable_val;
+	__raw_writel(clk_rst, clk->clk_rst);
+}
+
+static void sdhc_clk_disable(struct clk *clk)
+{
+	uint32_t clk_rst;
+
+	clk_rst  =  __raw_readl(clk->clk_rst);
+	clk_rst &= ~clk->enable_val;
+	__raw_writel(clk_rst, clk->clk_rst);
+}
+
+struct clkops sdhc_clk_ops = {
+	.enable		= sdhc_clk_enable,
+	.disable	= sdhc_clk_disable,
+};
+
+/* APB peripheral clocks */
+static APBC_CLK(uart1, UART1, 1, 26000000);
+static APBC_CLK(uart2, UART2, 1, 26000000);
+static APBC_CLK(uart3, UART3, 1, 26000000);
+static APBC_CLK(uart4, UART4, 1, 26000000);
+static APBC_CLK(twsi1, TWSI1, 0, 26000000);
+static APBC_CLK(twsi2, TWSI2, 0, 26000000);
+static APBC_CLK(twsi3, TWSI3, 0, 26000000);
+static APBC_CLK(twsi4, TWSI4, 0, 26000000);
+static APBC_CLK(twsi5, TWSI5, 0, 26000000);
+static APBC_CLK(twsi6, TWSI6, 0, 26000000);
+static APBC_CLK(gpio, GPIO, 0, 26000000);
+
+static APMU_CLK(nand, NAND, 0xbf, 100000000);
+static APMU_CLK_OPS(sdh0, SDH0, 0x1b, 200000000, &sdhc_clk_ops);
+static APMU_CLK_OPS(sdh1, SDH1, 0x1b, 200000000, &sdhc_clk_ops);
+static APMU_CLK_OPS(sdh2, SDH2, 0x1b, 200000000, &sdhc_clk_ops);
+static APMU_CLK_OPS(sdh3, SDH3, 0x1b, 200000000, &sdhc_clk_ops);
+
+static struct clk_lookup mmp2_clkregs[] = {
+	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
+	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+	INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
+	INIT_CLKREG(&clk_uart4, "pxa2xx-uart.3", NULL),
+	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.0", NULL),
+	INIT_CLKREG(&clk_twsi2, "pxa2xx-i2c.1", NULL),
+	INIT_CLKREG(&clk_twsi3, "pxa2xx-i2c.2", NULL),
+	INIT_CLKREG(&clk_twsi4, "pxa2xx-i2c.3", NULL),
+	INIT_CLKREG(&clk_twsi5, "pxa2xx-i2c.4", NULL),
+	INIT_CLKREG(&clk_twsi6, "pxa2xx-i2c.5", NULL),
+	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
+	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
+	INIT_CLKREG(&clk_sdh0, "sdhci-pxav3.0", "PXA-SDHCLK"),
+	INIT_CLKREG(&clk_sdh1, "sdhci-pxav3.1", "PXA-SDHCLK"),
+	INIT_CLKREG(&clk_sdh2, "sdhci-pxav3.2", "PXA-SDHCLK"),
+	INIT_CLKREG(&clk_sdh3, "sdhci-pxav3.3", "PXA-SDHCLK"),
+};
+
+void __init mmp2_clk_init(void)
+{
+	clkdev_add_table(ARRAY_AND_SIZE(mmp2_clkregs));
+}
diff --git a/arch/arm/mach-mmp/clock-pxa168.c b/arch/arm/mach-mmp/clock-pxa168.c
new file mode 100644
index 0000000..5e6c18c
--- /dev/null
+++ b/arch/arm/mach-mmp/clock-pxa168.c
@@ -0,0 +1,91 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/addr-map.h>
+
+#include "common.h"
+#include "clock.h"
+
+/*
+ * APB clock register offsets for PXA168
+ */
+#define APBC_UART1	APBC_REG(0x000)
+#define APBC_UART2	APBC_REG(0x004)
+#define APBC_GPIO	APBC_REG(0x008)
+#define APBC_PWM1	APBC_REG(0x00c)
+#define APBC_PWM2	APBC_REG(0x010)
+#define APBC_PWM3	APBC_REG(0x014)
+#define APBC_PWM4	APBC_REG(0x018)
+#define APBC_RTC	APBC_REG(0x028)
+#define APBC_TWSI0	APBC_REG(0x02c)
+#define APBC_KPC	APBC_REG(0x030)
+#define APBC_TWSI1	APBC_REG(0x06c)
+#define APBC_UART3	APBC_REG(0x070)
+#define APBC_SSP1	APBC_REG(0x81c)
+#define APBC_SSP2	APBC_REG(0x820)
+#define APBC_SSP3	APBC_REG(0x84c)
+#define APBC_SSP4	APBC_REG(0x858)
+#define APBC_SSP5	APBC_REG(0x85c)
+
+#define APMU_NAND	APMU_REG(0x060)
+#define APMU_LCD	APMU_REG(0x04c)
+#define APMU_ETH	APMU_REG(0x0fc)
+#define APMU_USB	APMU_REG(0x05c)
+
+/* APB peripheral clocks */
+static APBC_CLK(uart1, UART1, 1, 14745600);
+static APBC_CLK(uart2, UART2, 1, 14745600);
+static APBC_CLK(uart3, UART3, 1, 14745600);
+static APBC_CLK(twsi0, TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PWM4, 1, 13000000);
+static APBC_CLK(ssp1, SSP1, 4, 0);
+static APBC_CLK(ssp2, SSP2, 4, 0);
+static APBC_CLK(ssp3, SSP3, 4, 0);
+static APBC_CLK(ssp4, SSP4, 4, 0);
+static APBC_CLK(ssp5, SSP5, 4, 0);
+static APBC_CLK(gpio, GPIO, 0, 13000000);
+static APBC_CLK(keypad, KPC, 0, 32000);
+static APBC_CLK(rtc, RTC, 8, 32768);
+
+static APMU_CLK(nand, NAND, 0x19b, 156000000);
+static APMU_CLK(lcd, LCD, 0x7f, 312000000);
+static APMU_CLK(eth, ETH, 0x09, 0);
+static APMU_CLK(usb, USB, 0x12, 0);
+
+/* device and clock bindings */
+static struct clk_lookup pxa168_clkregs[] = {
+	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
+	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+	INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
+	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+	INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL),
+	INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
+	INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
+	INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
+	INIT_CLKREG(&clk_ssp1, "pxa168-ssp.0", NULL),
+	INIT_CLKREG(&clk_ssp2, "pxa168-ssp.1", NULL),
+	INIT_CLKREG(&clk_ssp3, "pxa168-ssp.2", NULL),
+	INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
+	INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
+	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
+	INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
+	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
+	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
+	INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
+	INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"),
+	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
+};
+
+void __init pxa168_clk_init(void)
+{
+	clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
+}
diff --git a/arch/arm/mach-mmp/clock-pxa910.c b/arch/arm/mach-mmp/clock-pxa910.c
new file mode 100644
index 0000000..933ea71
--- /dev/null
+++ b/arch/arm/mach-mmp/clock-pxa910.c
@@ -0,0 +1,67 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/addr-map.h>
+
+#include "common.h"
+#include "clock.h"
+
+/*
+ * APB Clock register offsets for PXA910
+ */
+#define APBC_UART0	APBC_REG(0x000)
+#define APBC_UART1	APBC_REG(0x004)
+#define APBC_GPIO	APBC_REG(0x008)
+#define APBC_PWM1	APBC_REG(0x00c)
+#define APBC_PWM2	APBC_REG(0x010)
+#define APBC_PWM3	APBC_REG(0x014)
+#define APBC_PWM4	APBC_REG(0x018)
+#define APBC_SSP1	APBC_REG(0x01c)
+#define APBC_SSP2	APBC_REG(0x020)
+#define APBC_RTC	APBC_REG(0x028)
+#define APBC_TWSI0	APBC_REG(0x02c)
+#define APBC_KPC	APBC_REG(0x030)
+#define APBC_SSP3	APBC_REG(0x04c)
+#define APBC_TWSI1	APBC_REG(0x06c)
+
+#define APMU_NAND	APMU_REG(0x060)
+#define APMU_USB	APMU_REG(0x05c)
+
+static APBC_CLK(uart1, UART0, 1, 14745600);
+static APBC_CLK(uart2, UART1, 1, 14745600);
+static APBC_CLK(twsi0, TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PWM4, 1, 13000000);
+static APBC_CLK(gpio, GPIO, 0, 13000000);
+static APBC_CLK(rtc, RTC, 8, 32768);
+
+static APMU_CLK(nand, NAND, 0x19b, 156000000);
+static APMU_CLK(u2o, USB, 0x1b, 480000000);
+
+/* device and clock bindings */
+static struct clk_lookup pxa910_clkregs[] = {
+	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
+	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+	INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL),
+	INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
+	INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
+	INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
+	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
+	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
+	INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"),
+	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
+};
+
+void __init pxa910_clk_init(void)
+{
+	clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
+}
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 1c9d6c1..bd45327 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -7,3 +7,6 @@
 extern void __init icu_init_irq(void);
 extern void __init mmp_map_io(void);
 extern void mmp_restart(char, const char *);
+extern void __init pxa168_clk_init(void);
+extern void __init pxa910_clk_init(void);
+extern void __init mmp2_clk_init(void);
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 68b0c93..ddc812f 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -13,101 +13,6 @@
 
 #include <mach/addr-map.h>
 
-/*
- * APB clock register offsets for PXA168
- */
-#define APBC_PXA168_UART1	APBC_REG(0x000)
-#define APBC_PXA168_UART2	APBC_REG(0x004)
-#define APBC_PXA168_GPIO	APBC_REG(0x008)
-#define APBC_PXA168_PWM1	APBC_REG(0x00c)
-#define APBC_PXA168_PWM2	APBC_REG(0x010)
-#define APBC_PXA168_PWM3	APBC_REG(0x014)
-#define APBC_PXA168_PWM4	APBC_REG(0x018)
-#define APBC_PXA168_RTC		APBC_REG(0x028)
-#define APBC_PXA168_TWSI0	APBC_REG(0x02c)
-#define APBC_PXA168_KPC		APBC_REG(0x030)
-#define APBC_PXA168_TIMERS	APBC_REG(0x034)
-#define APBC_PXA168_AIB		APBC_REG(0x03c)
-#define APBC_PXA168_SW_JTAG	APBC_REG(0x040)
-#define APBC_PXA168_ONEWIRE	APBC_REG(0x048)
-#define APBC_PXA168_ASFAR	APBC_REG(0x050)
-#define APBC_PXA168_ASSAR	APBC_REG(0x054)
-#define APBC_PXA168_TWSI1	APBC_REG(0x06c)
-#define APBC_PXA168_UART3	APBC_REG(0x070)
-#define APBC_PXA168_AC97	APBC_REG(0x084)
-#define APBC_PXA168_SSP1	APBC_REG(0x81c)
-#define APBC_PXA168_SSP2	APBC_REG(0x820)
-#define APBC_PXA168_SSP3	APBC_REG(0x84c)
-#define APBC_PXA168_SSP4	APBC_REG(0x858)
-#define APBC_PXA168_SSP5	APBC_REG(0x85c)
-
-/*
- * APB Clock register offsets for PXA910
- */
-#define APBC_PXA910_UART0	APBC_REG(0x000)
-#define APBC_PXA910_UART1	APBC_REG(0x004)
-#define APBC_PXA910_GPIO	APBC_REG(0x008)
-#define APBC_PXA910_PWM1	APBC_REG(0x00c)
-#define APBC_PXA910_PWM2	APBC_REG(0x010)
-#define APBC_PXA910_PWM3	APBC_REG(0x014)
-#define APBC_PXA910_PWM4	APBC_REG(0x018)
-#define APBC_PXA910_SSP1	APBC_REG(0x01c)
-#define APBC_PXA910_SSP2	APBC_REG(0x020)
-#define APBC_PXA910_IPC		APBC_REG(0x024)
-#define APBC_PXA910_RTC		APBC_REG(0x028)
-#define APBC_PXA910_TWSI0	APBC_REG(0x02c)
-#define APBC_PXA910_KPC		APBC_REG(0x030)
-#define APBC_PXA910_TIMERS	APBC_REG(0x034)
-#define APBC_PXA910_TBROT	APBC_REG(0x038)
-#define APBC_PXA910_AIB		APBC_REG(0x03c)
-#define APBC_PXA910_SW_JTAG	APBC_REG(0x040)
-#define APBC_PXA910_TIMERS1	APBC_REG(0x044)
-#define APBC_PXA910_ONEWIRE	APBC_REG(0x048)
-#define APBC_PXA910_SSP3	APBC_REG(0x04c)
-#define APBC_PXA910_ASFAR	APBC_REG(0x050)
-#define APBC_PXA910_ASSAR	APBC_REG(0x054)
-
-/*
- * APB Clock register offsets for MMP2
- */
-#define APBC_MMP2_RTC		APBC_REG(0x000)
-#define APBC_MMP2_TWSI1		APBC_REG(0x004)
-#define APBC_MMP2_TWSI2		APBC_REG(0x008)
-#define APBC_MMP2_TWSI3		APBC_REG(0x00c)
-#define APBC_MMP2_TWSI4		APBC_REG(0x010)
-#define APBC_MMP2_ONEWIRE	APBC_REG(0x014)
-#define APBC_MMP2_KPC		APBC_REG(0x018)
-#define APBC_MMP2_TB_ROTARY	APBC_REG(0x01c)
-#define APBC_MMP2_SW_JTAG	APBC_REG(0x020)
-#define APBC_MMP2_TIMERS	APBC_REG(0x024)
-#define APBC_MMP2_UART1		APBC_REG(0x02c)
-#define APBC_MMP2_UART2		APBC_REG(0x030)
-#define APBC_MMP2_UART3		APBC_REG(0x034)
-#define APBC_MMP2_GPIO		APBC_REG(0x038)
-#define APBC_MMP2_PWM0		APBC_REG(0x03c)
-#define APBC_MMP2_PWM1		APBC_REG(0x040)
-#define APBC_MMP2_PWM2		APBC_REG(0x044)
-#define APBC_MMP2_PWM3		APBC_REG(0x048)
-#define APBC_MMP2_SSP0		APBC_REG(0x04c)
-#define APBC_MMP2_SSP1		APBC_REG(0x050)
-#define APBC_MMP2_SSP2		APBC_REG(0x054)
-#define APBC_MMP2_SSP3		APBC_REG(0x058)
-#define APBC_MMP2_SSP4		APBC_REG(0x05c)
-#define APBC_MMP2_SSP5		APBC_REG(0x060)
-#define APBC_MMP2_AIB		APBC_REG(0x064)
-#define APBC_MMP2_ASFAR		APBC_REG(0x068)
-#define APBC_MMP2_ASSAR		APBC_REG(0x06c)
-#define APBC_MMP2_USIM		APBC_REG(0x070)
-#define APBC_MMP2_MPMU		APBC_REG(0x074)
-#define APBC_MMP2_IPC		APBC_REG(0x078)
-#define APBC_MMP2_TWSI5		APBC_REG(0x07c)
-#define APBC_MMP2_TWSI6		APBC_REG(0x080)
-#define APBC_MMP2_TWSI_INTSTS	APBC_REG(0x084)
-#define APBC_MMP2_UART4		APBC_REG(0x088)
-#define APBC_MMP2_RIPC		APBC_REG(0x08c)
-#define APBC_MMP2_THSENS1	APBC_REG(0x090)	/* Thermal Sensor */
-#define APBC_MMP2_THSENS_INTSTS	APBC_REG(0x0a4)
-
 /* Common APB clock register bit definitions */
 #define APBC_APBCLK	(1 << 0)  /* APB Bus Clock Enable */
 #define APBC_FNCLK	(1 << 1)  /* Functional Clock Enable */
diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h
index 7af8deb..93c8d0e 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apmu.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h
@@ -13,21 +13,6 @@
 
 #include <mach/addr-map.h>
 
-/* Clock Reset Control */
-#define APMU_IRE	APMU_REG(0x048)
-#define APMU_LCD	APMU_REG(0x04c)
-#define APMU_CCIC	APMU_REG(0x050)
-#define APMU_SDH0	APMU_REG(0x054)
-#define APMU_SDH1	APMU_REG(0x058)
-#define APMU_USB	APMU_REG(0x05c)
-#define APMU_NAND	APMU_REG(0x060)
-#define APMU_DMA	APMU_REG(0x064)
-#define APMU_GEU	APMU_REG(0x068)
-#define APMU_BUS	APMU_REG(0x06c)
-#define APMU_SDH2	APMU_REG(0x0e8)
-#define APMU_SDH3	APMU_REG(0x0ec)
-#define APMU_ETH	APMU_REG(0x0fc)
-
 #define APMU_FNCLK_EN	(1 << 4)
 #define APMU_AXICLK_EN	(1 << 3)
 #define APMU_FNRST_DIS	(1 << 1)
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
index e60c7d9..3c71246 100644
--- a/arch/arm/mach-mmp/irq.c
+++ b/arch/arm/mach-mmp/irq.c
@@ -153,10 +153,8 @@
 		status = readl_relaxed(data->reg_status) & ~mask;
 		if (status == 0)
 			break;
-		n = find_first_bit(&status, BITS_PER_LONG);
-		while (n < BITS_PER_LONG) {
+		for_each_set_bit(n, &status, BITS_PER_LONG) {
 			generic_handle_irq(icu_data[i].virq_base + n);
-			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
 		}
 	}
 }
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index c2bb95c..3a3768c 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -20,7 +20,6 @@
 #include <asm/mach/time.h>
 #include <mach/addr-map.h>
 #include <mach/regs-apbc.h>
-#include <mach/regs-apmu.h>
 #include <mach/cputype.h>
 #include <mach/irqs.h>
 #include <mach/dma.h>
@@ -29,7 +28,6 @@
 #include <mach/mmp2.h>
 
 #include "common.h"
-#include "clock.h"
 
 #define MFPR_VIRT_BASE	(APB_VIRT_BASE + 0x1e000)
 
@@ -98,67 +96,6 @@
 	mmp2_init_icu();
 }
 
-static void sdhc_clk_enable(struct clk *clk)
-{
-	uint32_t clk_rst;
-
-	clk_rst  =  __raw_readl(clk->clk_rst);
-	clk_rst |= clk->enable_val;
-	__raw_writel(clk_rst, clk->clk_rst);
-}
-
-static void sdhc_clk_disable(struct clk *clk)
-{
-	uint32_t clk_rst;
-
-	clk_rst  =  __raw_readl(clk->clk_rst);
-	clk_rst &= ~clk->enable_val;
-	__raw_writel(clk_rst, clk->clk_rst);
-}
-
-struct clkops sdhc_clk_ops = {
-	.enable		= sdhc_clk_enable,
-	.disable	= sdhc_clk_disable,
-};
-
-/* APB peripheral clocks */
-static APBC_CLK(uart1, MMP2_UART1, 1, 26000000);
-static APBC_CLK(uart2, MMP2_UART2, 1, 26000000);
-static APBC_CLK(uart3, MMP2_UART3, 1, 26000000);
-static APBC_CLK(uart4, MMP2_UART4, 1, 26000000);
-static APBC_CLK(twsi1, MMP2_TWSI1, 0, 26000000);
-static APBC_CLK(twsi2, MMP2_TWSI2, 0, 26000000);
-static APBC_CLK(twsi3, MMP2_TWSI3, 0, 26000000);
-static APBC_CLK(twsi4, MMP2_TWSI4, 0, 26000000);
-static APBC_CLK(twsi5, MMP2_TWSI5, 0, 26000000);
-static APBC_CLK(twsi6, MMP2_TWSI6, 0, 26000000);
-static APBC_CLK(gpio, MMP2_GPIO, 0, 26000000);
-
-static APMU_CLK(nand, NAND, 0xbf, 100000000);
-static APMU_CLK_OPS(sdh0, SDH0, 0x1b, 200000000, &sdhc_clk_ops);
-static APMU_CLK_OPS(sdh1, SDH1, 0x1b, 200000000, &sdhc_clk_ops);
-static APMU_CLK_OPS(sdh2, SDH2, 0x1b, 200000000, &sdhc_clk_ops);
-static APMU_CLK_OPS(sdh3, SDH3, 0x1b, 200000000, &sdhc_clk_ops);
-
-static struct clk_lookup mmp2_clkregs[] = {
-	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
-	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
-	INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
-	INIT_CLKREG(&clk_uart4, "pxa2xx-uart.3", NULL),
-	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.0", NULL),
-	INIT_CLKREG(&clk_twsi2, "pxa2xx-i2c.1", NULL),
-	INIT_CLKREG(&clk_twsi3, "pxa2xx-i2c.2", NULL),
-	INIT_CLKREG(&clk_twsi4, "pxa2xx-i2c.3", NULL),
-	INIT_CLKREG(&clk_twsi5, "pxa2xx-i2c.4", NULL),
-	INIT_CLKREG(&clk_twsi6, "pxa2xx-i2c.5", NULL),
-	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
-	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
-	INIT_CLKREG(&clk_sdh0, "sdhci-pxav3.0", "PXA-SDHCLK"),
-	INIT_CLKREG(&clk_sdh1, "sdhci-pxav3.1", "PXA-SDHCLK"),
-	INIT_CLKREG(&clk_sdh2, "sdhci-pxav3.2", "PXA-SDHCLK"),
-	INIT_CLKREG(&clk_sdh3, "sdhci-pxav3.3", "PXA-SDHCLK"),
-};
-
 static int __init mmp2_init(void)
 {
 	if (cpu_is_mmp2()) {
@@ -168,25 +105,27 @@
 		mfp_init_base(MFPR_VIRT_BASE);
 		mfp_init_addr(mmp2_addr_map);
 		pxa_init_dma(IRQ_MMP2_DMA_RIQ, 16);
-		clkdev_add_table(ARRAY_AND_SIZE(mmp2_clkregs));
+		mmp2_clk_init();
 	}
 
 	return 0;
 }
 postcore_initcall(mmp2_init);
 
+#define APBC_TIMERS	APBC_REG(0x024)
+
 static void __init mmp2_timer_init(void)
 {
 	unsigned long clk_rst;
 
-	__raw_writel(APBC_APBCLK | APBC_RST, APBC_MMP2_TIMERS);
+	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 
 	/*
 	 * enable bus/functional clock, enable 6.5MHz (divider 4),
 	 * release reset
 	 */
 	clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1);
-	__raw_writel(clk_rst, APBC_MMP2_TIMERS);
+	__raw_writel(clk_rst, APBC_TIMERS);
 
 	timer_init(IRQ_MMP2_TIMER1);
 }
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 62d787c..b7f074f 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -18,8 +18,8 @@
 
 #include <asm/mach/time.h>
 #include <asm/system_misc.h>
-#include <mach/addr-map.h>
 #include <mach/cputype.h>
+#include <mach/addr-map.h>
 #include <mach/regs-apbc.h>
 #include <mach/regs-apmu.h>
 #include <mach/irqs.h>
@@ -50,62 +50,13 @@
 	icu_init_irq();
 }
 
-/* APB peripheral clocks */
-static APBC_CLK(uart1, PXA168_UART1, 1, 14745600);
-static APBC_CLK(uart2, PXA168_UART2, 1, 14745600);
-static APBC_CLK(uart3, PXA168_UART3, 1, 14745600);
-static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
-static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
-static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000);
-static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
-static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
-static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
-static APBC_CLK(ssp1, PXA168_SSP1, 4, 0);
-static APBC_CLK(ssp2, PXA168_SSP2, 4, 0);
-static APBC_CLK(ssp3, PXA168_SSP3, 4, 0);
-static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
-static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
-static APBC_CLK(gpio, PXA168_GPIO, 0, 13000000);
-static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
-static APBC_CLK(rtc, PXA168_RTC, 8, 32768);
-
-static APMU_CLK(nand, NAND, 0x19b, 156000000);
-static APMU_CLK(lcd, LCD, 0x7f, 312000000);
-static APMU_CLK(eth, ETH, 0x09, 0);
-static APMU_CLK(usb, USB, 0x12, 0);
-
-/* device and clock bindings */
-static struct clk_lookup pxa168_clkregs[] = {
-	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
-	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
-	INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
-	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
-	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
-	INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL),
-	INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
-	INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
-	INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
-	INIT_CLKREG(&clk_ssp1, "pxa168-ssp.0", NULL),
-	INIT_CLKREG(&clk_ssp2, "pxa168-ssp.1", NULL),
-	INIT_CLKREG(&clk_ssp3, "pxa168-ssp.2", NULL),
-	INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
-	INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
-	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
-	INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
-	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
-	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
-	INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
-	INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"),
-	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
-};
-
 static int __init pxa168_init(void)
 {
 	if (cpu_is_pxa168()) {
 		mfp_init_base(MFPR_VIRT_BASE);
 		mfp_init_addr(pxa168_mfp_addr_map);
 		pxa_init_dma(IRQ_PXA168_DMA_INT0, 32);
-		clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
+		pxa168_clk_init();
 	}
 
 	return 0;
@@ -114,6 +65,7 @@
 
 /* system timer - clock enabled, 3.25MHz */
 #define TIMER_CLK_RST	(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
+#define APBC_TIMERS	APBC_REG(0x34)
 
 static void __init pxa168_timer_init(void)
 {
@@ -121,10 +73,10 @@
 	 * ourselves instead of using clk_* API. Clock rate is defined
 	 * by APBC_TIMERS_CLK_RST (3.25MHz) and enabled free-running
 	 */
-	__raw_writel(APBC_APBCLK | APBC_RST, APBC_PXA168_TIMERS);
+	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 
 	/* 3.25MHz, bus/functional clock enabled, release reset */
-	__raw_writel(TIMER_CLK_RST, APBC_PXA168_TIMERS);
+	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
 	timer_init(IRQ_PXA168_TIMER1);
 }
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 51ac8d1..8b1e16f 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -18,7 +18,6 @@
 #include <asm/mach/time.h>
 #include <mach/addr-map.h>
 #include <mach/regs-apbc.h>
-#include <mach/regs-apmu.h>
 #include <mach/cputype.h>
 #include <mach/irqs.h>
 #include <mach/dma.h>
@@ -26,7 +25,6 @@
 #include <mach/devices.h>
 
 #include "common.h"
-#include "clock.h"
 
 #define MFPR_VIRT_BASE	(APB_VIRT_BASE + 0x1e000)
 
@@ -83,37 +81,6 @@
 	icu_init_irq();
 }
 
-/* APB peripheral clocks */
-static APBC_CLK(uart1, PXA910_UART0, 1, 14745600);
-static APBC_CLK(uart2, PXA910_UART1, 1, 14745600);
-static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
-static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
-static APBC_CLK(pwm1, PXA910_PWM1, 1, 13000000);
-static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
-static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
-static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
-static APBC_CLK(gpio, PXA910_GPIO, 0, 13000000);
-static APBC_CLK(rtc, PXA910_RTC, 8, 32768);
-
-static APMU_CLK(nand, NAND, 0x19b, 156000000);
-static APMU_CLK(u2o, USB, 0x1b, 480000000);
-
-/* device and clock bindings */
-static struct clk_lookup pxa910_clkregs[] = {
-	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
-	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
-	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
-	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
-	INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL),
-	INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
-	INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
-	INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
-	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
-	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
-	INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"),
-	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
-};
-
 static int __init pxa910_init(void)
 {
 	if (cpu_is_pxa910()) {
@@ -123,7 +90,7 @@
 		mfp_init_base(MFPR_VIRT_BASE);
 		mfp_init_addr(pxa910_mfp_addr_map);
 		pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
-		clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
+		pxa910_clk_init();
 	}
 
 	return 0;
@@ -132,12 +99,13 @@
 
 /* system timer - clock enabled, 3.25MHz */
 #define TIMER_CLK_RST	(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
+#define APBC_TIMERS	APBC_REG(0x34)
 
 static void __init pxa910_timer_init(void)
 {
 	/* reset and configure */
-	__raw_writel(APBC_APBCLK | APBC_RST, APBC_PXA910_TIMERS);
-	__raw_writel(TIMER_CLK_RST, APBC_PXA910_TIMERS);
+	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
+	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
 	timer_init(IRQ_PXA910_AP1_TIMER1);
 }
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 84183ed..c5a2edd 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -49,13 +49,14 @@
 
 struct shared_info {
 	int ready;
-	unsigned state;
+	void __iomem *state;
 };
 
 static unsigned dummy_state[SMSM_STATE_COUNT];
 
 static struct shared_info smd_info = {
-	.state = (unsigned) &dummy_state,
+	/* FIXME: not a real __iomem pointer */
+	.state = &dummy_state,
 };
 
 module_param_named(debug_mask, msm_smd_debug_mask,
@@ -789,22 +790,22 @@
 	return smem_find(id, size);
 }
 
-void *smem_item(unsigned id, unsigned *size)
+void __iomem *smem_item(unsigned id, unsigned *size)
 {
 	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
 	struct smem_heap_entry *toc = shared->heap_toc;
 
 	if (id >= SMEM_NUM_ITEMS)
-		return 0;
+		return NULL;
 
 	if (toc[id].allocated) {
 		*size = toc[id].size;
-		return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
+		return (MSM_SHARED_RAM_BASE + toc[id].offset);
 	} else {
 		*size = 0;
 	}
 
-	return 0;
+	return NULL;
 }
 
 void *smem_find(unsigned id, unsigned size_in)
@@ -850,7 +851,7 @@
 int smsm_change_state(enum smsm_state_item item,
 		      uint32_t clear_mask, uint32_t set_mask)
 {
-	unsigned long addr = smd_info.state + item * 4;
+	void __iomem *addr = smd_info.state + item * 4;
 	unsigned long flags;
 	unsigned state;
 
@@ -936,10 +937,10 @@
 	/* wait for essential items to be initialized */
 	for (;;) {
 		unsigned size;
-		void *state;
+		void __iomem *state;
 		state = smem_item(SMEM_SMSM_SHARED_STATE, &size);
 		if (size == SMSM_V1_SIZE || size == SMSM_V2_SIZE) {
-			smd_info.state = (unsigned)state;
+			smd_info.state = state;
 			break;
 		}
 	}
diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c
index a9bc841..137e479 100644
--- a/arch/arm/mach-mv78xx0/addr-map.c
+++ b/arch/arm/mach-mv78xx0/addr-map.c
@@ -13,6 +13,7 @@
 #include <linux/mbus.h>
 #include <linux/io.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 /*
@@ -81,7 +82,7 @@
 				      int maj, int min)
 {
 	orion_setup_cpu_win(&addr_map_cfg, window, base, size,
-			    TARGET_PCIE(maj), ATTR_PCIE_IO(min), -1);
+			    TARGET_PCIE(maj), ATTR_PCIE_IO(min), 0);
 }
 
 void __init mv78xx0_setup_pcie_mem_win(int window, u32 base, u32 size,
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 3057f7d..6b0c387 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -135,11 +135,6 @@
 		.length		= MV78XX0_CORE_REGS_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= MV78XX0_PCIE_IO_VIRT_BASE(0),
-		.pfn		= __phys_to_pfn(MV78XX0_PCIE_IO_PHYS_BASE(0)),
-		.length		= MV78XX0_PCIE_IO_SIZE * 8,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= MV78XX0_REGS_VIRT_BASE,
 		.pfn		= __phys_to_pfn(MV78XX0_REGS_PHYS_BASE),
 		.length		= MV78XX0_REGS_SIZE,
diff --git a/arch/arm/mach-mv78xx0/include/mach/io.h b/arch/arm/mach-mv78xx0/include/mach/io.h
deleted file mode 100644
index c7d9d00..0000000
--- a/arch/arm/mach-mv78xx0/include/mach/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "mv78xx0.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)((addr - MV78XX0_PCIE_IO_PHYS_BASE(0))
-					+ MV78XX0_PCIE_IO_VIRT_BASE(0));
-}
-
-#define __io(a)			__io(a)
-
-#endif
diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
index e807c4c..bd03fed 100644
--- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
@@ -29,15 +29,15 @@
  *
  * virt		phys		size
  * fe400000	f102x000	16K	core-specific peripheral registers
- * fe700000	f0800000	1M	PCIe #0 I/O space
- * fe800000	f0900000	1M	PCIe #1 I/O space
- * fe900000	f0a00000	1M	PCIe #2 I/O space
- * fea00000	f0b00000	1M	PCIe #3 I/O space
- * feb00000	f0c00000	1M	PCIe #4 I/O space
- * fec00000	f0d00000	1M	PCIe #5 I/O space
- * fed00000	f0e00000	1M	PCIe #6 I/O space
- * fee00000	f0f00000	1M	PCIe #7 I/O space
- * fef00000	f1000000	1M	on-chip peripheral registers
+ * fee00000	f0800000	64K	PCIe #0 I/O space
+ * fee10000	f0900000	64K	PCIe #1 I/O space
+ * fee20000	f0a00000	64K	PCIe #2 I/O space
+ * fee30000	f0b00000	64K	PCIe #3 I/O space
+ * fee40000	f0c00000	64K	PCIe #4 I/O space
+ * fee50000	f0d00000	64K	PCIe #5 I/O space
+ * fee60000	f0e00000	64K	PCIe #6 I/O space
+ * fee70000	f0f00000	64K	PCIe #7 I/O space
+ * fd000000	f1000000	1M	on-chip peripheral registers
  */
 #define MV78XX0_CORE0_REGS_PHYS_BASE	0xf1020000
 #define MV78XX0_CORE1_REGS_PHYS_BASE	0xf1024000
@@ -46,11 +46,10 @@
 #define MV78XX0_CORE_REGS_SIZE		SZ_16K
 
 #define MV78XX0_PCIE_IO_PHYS_BASE(i)	(0xf0800000 + ((i) << 20))
-#define MV78XX0_PCIE_IO_VIRT_BASE(i)	(0xfe700000 + ((i) << 20))
 #define MV78XX0_PCIE_IO_SIZE		SZ_1M
 
 #define MV78XX0_REGS_PHYS_BASE		0xf1000000
-#define MV78XX0_REGS_VIRT_BASE		0xfef00000
+#define MV78XX0_REGS_VIRT_BASE		0xfd000000
 #define MV78XX0_REGS_SIZE		SZ_1M
 
 #define MV78XX0_PCIE_MEM_PHYS_BASE	0xc0000000
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 2e56e86..26a059b 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -15,6 +15,7 @@
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 struct pcie_port {
@@ -23,16 +24,13 @@
 	u8			root_bus_nr;
 	void __iomem		*base;
 	spinlock_t		conf_lock;
-	char			io_space_name[16];
 	char			mem_space_name[16];
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static struct pcie_port pcie_port[8];
 static int num_pcie_ports;
 static struct resource pcie_io_space;
-static struct resource pcie_mem_space;
-
 
 void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
 {
@@ -40,102 +38,59 @@
 	*rev = orion_pcie_rev((void __iomem *)PCIE00_VIRT_BASE);
 }
 
+u32 pcie_port_size[8] = {
+	0,
+	0x30000000,
+	0x10000000,
+	0x10000000,
+	0x08000000,
+	0x08000000,
+	0x08000000,
+	0x04000000,
+};
+
 static void __init mv78xx0_pcie_preinit(void)
 {
 	int i;
 	u32 size_each;
 	u32 start;
-	int win;
+	int win = 0;
 
 	pcie_io_space.name = "PCIe I/O Space";
 	pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
 	pcie_io_space.end =
 		MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1;
-	pcie_io_space.flags = IORESOURCE_IO;
+	pcie_io_space.flags = IORESOURCE_MEM;
 	if (request_resource(&iomem_resource, &pcie_io_space))
 		panic("can't allocate PCIe I/O space");
 
-	pcie_mem_space.name = "PCIe MEM Space";
-	pcie_mem_space.start = MV78XX0_PCIE_MEM_PHYS_BASE;
-	pcie_mem_space.end =
-		MV78XX0_PCIE_MEM_PHYS_BASE + MV78XX0_PCIE_MEM_SIZE - 1;
-	pcie_mem_space.flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pcie_mem_space))
-		panic("can't allocate PCIe MEM space");
-
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
-
-		snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-			"PCIe %d.%d I/O", pp->maj, pp->min);
-		pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-		pp->res[0].name = pp->io_space_name;
-		pp->res[0].start = MV78XX0_PCIE_IO_PHYS_BASE(i);
-		pp->res[0].end = pp->res[0].start + MV78XX0_PCIE_IO_SIZE - 1;
-		pp->res[0].flags = IORESOURCE_IO;
-
-		snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
-			"PCIe %d.%d MEM", pp->maj, pp->min);
-		pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-		pp->res[1].name = pp->mem_space_name;
-		pp->res[1].flags = IORESOURCE_MEM;
-	}
-
-	switch (num_pcie_ports) {
-	case 0:
-		size_each = 0;
-		break;
-
-	case 1:
-		size_each = 0x30000000;
-		break;
-
-	case 2 ... 3:
-		size_each = 0x10000000;
-		break;
-
-	case 4 ... 6:
-		size_each = 0x08000000;
-		break;
-
-	case 7:
-		size_each = 0x04000000;
-		break;
-
-	default:
+	if (num_pcie_ports > 7)
 		panic("invalid number of PCIe ports");
-	}
+
+	size_each = pcie_port_size[num_pcie_ports];
 
 	start = MV78XX0_PCIE_MEM_PHYS_BASE;
 	for (i = 0; i < num_pcie_ports; i++) {
 		struct pcie_port *pp = pcie_port + i;
 
-		pp->res[1].start = start;
-		pp->res[1].end = start + size_each - 1;
+		snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+			"PCIe %d.%d MEM", pp->maj, pp->min);
+		pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+		pp->res.name = pp->mem_space_name;
+		pp->res.flags = IORESOURCE_MEM;
+		pp->res.start = start;
+		pp->res.end = start + size_each - 1;
 		start += size_each;
-	}
 
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
-
-		if (request_resource(&pcie_io_space, &pp->res[0]))
-			panic("can't allocate PCIe I/O sub-space");
-
-		if (request_resource(&pcie_mem_space, &pp->res[1]))
+		if (request_resource(&iomem_resource, &pp->res))
 			panic("can't allocate PCIe MEM sub-space");
-	}
 
-	win = 0;
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
-
-		mv78xx0_setup_pcie_io_win(win++, pp->res[0].start,
-					  resource_size(&pp->res[0]),
-					  pp->maj, pp->min);
-
-		mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start,
-					   resource_size(&pp->res[1]),
+		mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start,
+					   resource_size(&pp->res),
 					   pp->maj, pp->min);
+
+		mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K,
+					  pp->maj, pp->min);
 	}
 }
 
@@ -156,8 +111,9 @@
 	orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
 	orion_pcie_setup(pp->base);
 
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_ioremap_io(nr * SZ_64K, MV78XX0_PCIE_IO_PHYS_BASE(nr));
+
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	return 1;
 }
@@ -281,7 +237,7 @@
 		pp->root_bus_nr = -1;
 		pp->base = (void __iomem *)base;
 		spin_lock_init(&pp->conf_lock);
-		memset(pp->res, 0, sizeof(pp->res));
+		memset(&pp->res, 0, sizeof(pp->res));
 	} else {
 		printk("link down, ignoring\n");
 	}
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 433af89..cf43e5e 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -305,7 +305,7 @@
 	enable_clk_enet_out();
 
 	if (IS_BUILTIN(CONFIG_PHYLIB))
-		phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
+		phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK,
 					   apx4devkit_phy_fixup);
 
 	mxsfb_pdata.mode_list = apx4devkit_video_modes;
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index f4535a7..c3841a9 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -112,8 +112,7 @@
 static struct nomadik_nand_platform_data nhk8815_nand_data = {
 	.parts		= nhk8815_partitions,
 	.nparts		= ARRAY_SIZE(nhk8815_partitions),
-	.options	= NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \
-			| NAND_NO_READRDY,
+	.options	= NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING,
 	.init		= nhk8815_nand_init,
 };
 
diff --git a/arch/arm/mach-nomadik/include/mach/hardware.h b/arch/arm/mach-nomadik/include/mach/hardware.h
index 6316dba..02035e4 100644
--- a/arch/arm/mach-nomadik/include/mach/hardware.h
+++ b/arch/arm/mach-nomadik/include/mach/hardware.h
@@ -30,7 +30,7 @@
 			- NOMADIK_IO_VIRTUAL + NOMADIK_IO_PHYSICAL)
 
 /* used in asm code, so no casts */
-#define IO_ADDRESS(x) ((x) - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
+#define IO_ADDRESS(x) IOMEM((x) - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
 
 /*
  *   Base address defination for Nomadik Onchip Logic Block
diff --git a/arch/arm/mach-nomadik/include/mach/uncompress.h b/arch/arm/mach-nomadik/include/mach/uncompress.h
index 071003b..7d4687e 100644
--- a/arch/arm/mach-nomadik/include/mach/uncompress.h
+++ b/arch/arm/mach-nomadik/include/mach/uncompress.h
@@ -27,10 +27,10 @@
 struct amba_device;
 #include <linux/amba/serial.h>
 
-#define NOMADIK_UART_DR		0x101FB000
-#define NOMADIK_UART_LCRH	0x101FB02c
-#define NOMADIK_UART_CR		0x101FB030
-#define NOMADIK_UART_FR		0x101FB018
+#define NOMADIK_UART_DR		(void __iomem *)0x101FB000
+#define NOMADIK_UART_LCRH	(void __iomem *)0x101FB02c
+#define NOMADIK_UART_CR		(void __iomem *)0x101FB030
+#define NOMADIK_UART_FR		(void __iomem *)0x101FB018
 
 static void putc(const char c)
 {
diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index d2b6acc..3d1e1c2 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -16,7 +16,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/irqs.h>
 #include <mach/ams-delta-fiq.h>
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index 68e8e56..f12a12a 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <asm/fiq.h>
 
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 6f192c4..9518bf5 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -35,9 +35,9 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/board-ams-delta.h>
-#include <plat/keypad.h>
-#include <plat/mux.h>
+#include <mach/board-ams-delta.h>
+#include <linux/platform_data/keypad-omap.h>
+#include <mach/mux.h>
 
 #include <mach/hardware.h>
 #include <mach/ams-delta-fiq.h>
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 6d98552..4b6de70 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -28,10 +28,10 @@
 #include <asm/mach/map.h>
 
 #include <plat/tc.h>
-#include <plat/mux.h>
-#include <plat/flash.h>
+#include <mach/mux.h>
+#include <mach/flash.h>
 #include <plat/fpga.h>
-#include <plat/keypad.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 04b5fda..4ec579f 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -22,7 +22,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #include <mach/usb.h>
 
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 44a4ab1..af283a2 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -31,17 +31,18 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/gpio-omap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
 #include <plat/tc.h>
-#include <plat/irda.h>
-#include <plat/keypad.h>
-#include <plat/flash.h>
+#include <mach/irda.h>
+#include <linux/platform_data/keypad-omap.h>
+#include <mach/flash.h>
 
 #include <mach/hardware.h>
 #include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 86cb5a0..06d11b1 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/gpio-omap.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -38,11 +39,11 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
-#include <plat/keypad.h>
+#include <linux/platform_data/keypad-omap.h>
 #include <plat/dma.h>
-#include <plat/flash.h>
+#include <mach/flash.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index a5ac352..87ab208 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -37,12 +37,12 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 #include <mach/omap7xx.h>
-#include <plat/keypad.h>
 #include <plat/mmc.h>
 
 #include <mach/irqs.h>
@@ -475,8 +475,7 @@
 				break;
 		}
 		if (!tries)
-			printk(KERN_WARNING "Timeout waiting for end of frame "
-			       "-- LCD may not be available\n");
+			pr_err("Timeout waiting for end of frame -- LCD may not be available\n");
 
 		/* turn off DMA */
 		reg = omap_readw(OMAP_DMA_LCD_CCR);
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index f21c296..db5f7d2 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -31,11 +31,11 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
-#include <plat/flash.h>
+#include <mach/mux.h>
+#include <mach/flash.h>
 #include <plat/fpga.h>
 #include <plat/tc.h>
-#include <plat/keypad.h>
+#include <linux/platform_data/keypad-omap.h>
 #include <plat/mmc.h>
 
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index ec01f03..7d5c06d6 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -21,13 +21,14 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 
+#include <linux/platform_data/keypad-omap.h>
+#include <linux/platform_data/lcd-mipid.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
-#include <plat/keypad.h>
-#include <plat/lcd_mipid.h>
+#include <mach/mux.h>
 #include <plat/mmc.h>
 #include <plat/clock.h>
 
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 3b2d907..2f1f9b9 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -46,8 +46,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
 
 #include <mach/hardware.h>
@@ -304,7 +304,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
-#include <plat/keypad.h>
+#include <linux/platform_data/keypad-omap.h>
 
 static struct at24_platform_data at24c04 = {
 	.byte_len	= SZ_4K / 8,
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 49f8d74..1c578d5 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -34,12 +34,12 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
 #include <plat/dma.h>
-#include <plat/irda.h>
-#include <plat/keypad.h>
+#include <mach/irda.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <mach/hardware.h>
 #include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 01523cd..9715809 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -34,12 +34,12 @@
 #include <asm/mach/map.h>
 
 #include <plat/led.h>
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
 #include <plat/tc.h>
-#include <plat/irda.h>
-#include <plat/keypad.h>
+#include <mach/irda.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <mach/hardware.h>
 #include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index a7abce6..e311032 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -36,12 +36,12 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
 #include <plat/tc.h>
-#include <plat/irda.h>
-#include <plat/keypad.h>
+#include <mach/irda.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <mach/hardware.h>
 #include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 277e0bc..198b054 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -22,16 +22,16 @@
 #include <linux/input.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <plat/tc.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/fpga.h>
-#include <plat/flash.h>
-#include <plat/keypad.h>
+#include <mach/flash.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
index b59f78850..5932d56 100644
--- a/arch/arm/mach-omap1/board-sx1-mmc.c
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -17,7 +17,7 @@
 
 #include <mach/hardware.h>
 #include <plat/mmc.h>
-#include <plat/board-sx1.h>
+#include <mach/board-sx1.h>
 
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 2e1fff2..13bf2cc 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -28,18 +28,18 @@
 #include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
-#include <plat/irda.h>
+#include <mach/irda.h>
 #include <plat/tc.h>
-#include <plat/keypad.h>
-#include <plat/board-sx1.h>
+#include <mach/board-sx1.h>
 
 #include <mach/hardware.h>
 #include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 1668af3..ad75e34 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -31,9 +31,9 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/board-voiceblue.h>
-#include <plat/flash.h>
-#include <plat/mux.h>
+#include <mach/board-voiceblue.h>
+#include <mach/flash.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
 
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index a9ee06b..638f407 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -587,8 +587,8 @@
 	/* Clocks in the DSP domain need api_ck. Just assume bootloader
 	 * has not enabled any DSP clocks */
 	if (clk->enable_reg == DSP_IDLECT2) {
-		printk(KERN_INFO "Skipping reset check for DSP domain "
-		       "clock \"%s\"\n", clk->name);
+		pr_info("Skipping reset check for DSP domain clock \"%s\"\n",
+			clk->name);
 		return;
 	}
 
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
index 6a32b9b..9b45f4b 100644
--- a/arch/arm/mach-omap1/clock_data.c
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -775,11 +775,10 @@
 
 static void __init omap1_show_rates(void)
 {
-	pr_notice("Clocking rate (xtal/DPLL1/MPU): "
-			"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
-		ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
-		ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
-		arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
+	pr_notice("Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
+		  ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+		  ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
+		  arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
 }
 
 u32 cpu_mask;
@@ -840,8 +839,8 @@
 	if (cpu_is_omap16xx() && crystal_type == 2)
 		ck_ref.rate = 19200000;
 
-	pr_info("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: "
-		"0x%04x\n", omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+	pr_info("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+		omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
 		omap_readw(ARM_CKCTL));
 
 	/* We want to be in syncronous scalable mode */
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 05fdbd9..0cc54dd 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -20,7 +20,7 @@
 #include <asm/mach/map.h>
 
 #include <plat/tc.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
 #include <plat/mmc.h>
 
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index b0b0f0f..29007fe 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -331,8 +331,9 @@
 	d->chan = kzalloc(sizeof(struct omap_dma_lch) *
 					(d->lch_count), GFP_KERNEL);
 	if (!d->chan) {
-		dev_err(&pdev->dev, "%s: Memory allocation failed"
-					"for d->chan!!!\n", __func__);
+		dev_err(&pdev->dev,
+			"%s: Memory allocation failed for d->chan!\n",
+			__func__);
 		goto exit_release_d;
 	}
 
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
index 401eb3c..73ae616 100644
--- a/arch/arm/mach-omap1/flash.c
+++ b/arch/arm/mach-omap1/flash.c
@@ -11,7 +11,7 @@
 #include <linux/mtd/map.h>
 
 #include <plat/tc.h>
-#include <plat/flash.h>
+#include <mach/flash.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c
index 5446c99..a0551a6 100644
--- a/arch/arm/mach-omap1/i2c.c
+++ b/arch/arm/mach-omap1/i2c.c
@@ -20,7 +20,7 @@
  */
 
 #include <plat/i2c.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/cpu.h>
 
 void __init omap1_i2c_mux_pins(int bus_id)
diff --git a/arch/arm/plat-omap/include/plat/board-ams-delta.h b/arch/arm/mach-omap1/include/mach/board-ams-delta.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/board-ams-delta.h
rename to arch/arm/mach-omap1/include/mach/board-ams-delta.h
diff --git a/arch/arm/plat-omap/include/plat/board-sx1.h b/arch/arm/mach-omap1/include/mach/board-sx1.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/board-sx1.h
rename to arch/arm/mach-omap1/include/mach/board-sx1.h
diff --git a/arch/arm/plat-omap/include/plat/board-voiceblue.h b/arch/arm/mach-omap1/include/mach/board-voiceblue.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/board-voiceblue.h
rename to arch/arm/mach-omap1/include/mach/board-voiceblue.h
diff --git a/arch/arm/plat-omap/include/plat/flash.h b/arch/arm/mach-omap1/include/mach/flash.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/flash.h
rename to arch/arm/mach-omap1/include/mach/flash.h
diff --git a/arch/arm/plat-omap/include/plat/irda.h b/arch/arm/mach-omap1/include/mach/irda.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/irda.h
rename to arch/arm/mach-omap1/include/mach/irda.h
diff --git a/arch/arm/plat-omap/include/plat/mux.h b/arch/arm/mach-omap1/include/mach/mux.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/mux.h
rename to arch/arm/mach-omap1/include/mach/mux.h
diff --git a/arch/arm/mach-omap1/include/mach/smp.h b/arch/arm/mach-omap1/include/mach/smp.h
deleted file mode 100644
index 80a371c..0000000
--- a/arch/arm/mach-omap1/include/mach/smp.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap1/include/mach/smp.h
- */
-
-#include <plat/smp.h>
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 6c95a59..6a5baab 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -16,7 +16,7 @@
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
 #include <plat/dma.h>
 
diff --git a/arch/arm/mach-omap1/lcd_dma.c b/arch/arm/mach-omap1/lcd_dma.c
index 5769c71..ed42628 100644
--- a/arch/arm/mach-omap1/lcd_dma.c
+++ b/arch/arm/mach-omap1/lcd_dma.c
@@ -113,8 +113,7 @@
 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
 {
 	if (cpu_is_omap15xx()) {
-		printk(KERN_ERR "DMA virtual resolution is not supported "
-				"in 1510 mode\n");
+		pr_err("DMA virtual resolution is not supported in 1510 mode\n");
 		BUG();
 	}
 	lcd_dma.vxres = vxres;
@@ -437,8 +436,7 @@
 	r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
 			"LCD DMA", NULL);
 	if (r != 0)
-		printk(KERN_ERR "unable to request IRQ for LCD DMA "
-			       "(error %d)\n", r);
+		pr_err("unable to request IRQ for LCD DMA (error %d)\n", r);
 
 	return r;
 }
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index 7f4bba9..6f958ae 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -69,11 +69,13 @@
 			gpio_set_value(GPIO_IDLE, 0);
 		}
 
-		__raw_writew(~0, &fpga->leds);
 		led_state &= ~LED_STATE_ENABLED;
-		if (evt == led_halted) {
-			iounmap(fpga);
-			fpga = NULL;
+		if (fpga) {
+			__raw_writew(~0, &fpga->leds);
+			if (evt == led_halted) {
+				iounmap(fpga);
+				fpga = NULL;
+			}
 		}
 
 		goto done;
@@ -159,7 +161,7 @@
 	/*
 	 *  Actually burn the LEDs
 	 */
-	if (led_state & LED_STATE_ENABLED)
+	if (led_state & LED_STATE_ENABLED && fpga)
 		__raw_writew(~hw_led_state, &fpga->leds);
 
 done:
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
index 7b1a383..4071479 100644
--- a/arch/arm/mach-omap1/leds.c
+++ b/arch/arm/mach-omap1/leds.c
@@ -11,7 +11,7 @@
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index adf0097..bdc2e75 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -20,9 +20,9 @@
 #include <linux/slab.h>
 
 #include <plat/dma.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/cpu.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include <mach/irqs.h>
 
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index e9cc52d..667ce50 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -29,7 +29,7 @@
 
 #include <mach/hardware.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
 
@@ -451,6 +451,56 @@
 #endif
 }
 
+static struct omap_mux_cfg *mux_cfg;
+
+int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
+{
+	if (!arch_mux_cfg || !arch_mux_cfg->pins || arch_mux_cfg->size == 0
+			|| !arch_mux_cfg->cfg_reg) {
+		printk(KERN_ERR "Invalid pin table\n");
+		return -EINVAL;
+	}
+
+	mux_cfg = arch_mux_cfg;
+
+	return 0;
+}
+
+/*
+ * Sets the Omap MUX and PULL_DWN registers based on the table
+ */
+int __init_or_module omap_cfg_reg(const unsigned long index)
+{
+	struct pin_config *reg;
+
+	if (!cpu_class_is_omap1()) {
+		printk(KERN_ERR "mux: Broken omap_cfg_reg(%lu) entry\n",
+				index);
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (mux_cfg == NULL) {
+		printk(KERN_ERR "Pin mux table not initialized\n");
+		return -ENODEV;
+	}
+
+	if (index >= mux_cfg->size) {
+		printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
+		       index, mux_cfg->size);
+		dump_stack();
+		return -ENODEV;
+	}
+
+	reg = &mux_cfg->pins[index];
+
+	if (!mux_cfg->cfg_reg)
+		return -ENODEV;
+
+	return mux_cfg->cfg_reg(reg);
+}
+EXPORT_SYMBOL(omap_cfg_reg);
+
 int __init omap1_mux_init(void)
 {
 	if (cpu_is_omap7xx()) {
@@ -468,4 +518,8 @@
 	return omap_mux_register(&arch_mux_cfg);
 }
 
-#endif
+#else
+#define omap_mux_init() do {} while(0)
+#define omap_cfg_reg(x)	do {} while(0)
+#endif	/* CONFIG_OMAP_MUX */
+
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index b2560d3..47ec161 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -53,7 +53,7 @@
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/tc.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 0d1709b..b9d6834 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -22,7 +22,7 @@
 
 #include <asm/mach-types.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/fpga.h>
 
 #include "pm.h"
diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c
index 65f8817..84267ed 100644
--- a/arch/arm/mach-omap1/usb.c
+++ b/arch/arm/mach-omap1/usb.c
@@ -26,7 +26,7 @@
 
 #include <asm/irq.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #include <mach/usb.h>
 
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 34c2c7f..84520235 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -4,36 +4,30 @@
 
 # Common support
 obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
-	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o
+	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o
 
-omap-2-3-common				= irq.o
-hwmod-common				= omap_hwmod.o \
-					  omap_hwmod_common_data.o
-clock-common				= clock.o clock_common_data.o \
-					  clkt_dpll.o clkt_clksel.o
-secure-common				= omap-smc.o omap-secure.o
+# INTCPS IP block support - XXX should be moved to drivers/
+obj-$(CONFIG_ARCH_OMAP2)		+= irq.o
+obj-$(CONFIG_ARCH_OMAP3)		+= irq.o
+obj-$(CONFIG_SOC_AM33XX)		+= irq.o
 
-obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
-obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common)
-obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common)
-obj-$(CONFIG_SOC_OMAP5)	 += prm44xx.o $(hwmod-common) $(secure-common)
+# Secure monitor API support
+obj-$(CONFIG_ARCH_OMAP3)		+= omap-smc.o omap-secure.o
+obj-$(CONFIG_ARCH_OMAP4)		+= omap-smc.o omap-secure.o
+obj-$(CONFIG_SOC_OMAP5)			+= omap-smc.o omap-secure.o
 
 ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
 obj-y += mcbsp.o
 endif
 
-obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
-obj-$(CONFIG_SOC_HAS_OMAP2_SDRC)	+= sdrc.o
+obj-$(CONFIG_TWL4030_CORE)		+= omap_twl.o
 
 # SMP support ONLY available for OMAP4
 
 obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= omap-hotplug.o
-omap-4-5-common				=  omap4-common.o omap-wakeupgen.o \
-					   sleep44xx.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-common)
-obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-common)
+obj-$(CONFIG_ARCH_OMAP4)		+= omap4-common.o omap-wakeupgen.o
+obj-$(CONFIG_SOC_OMAP5)			+= omap4-common.o omap-wakeupgen.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_omap-headsmp.o			:=-Wa,-march=armv7-a$(plus_sec)
@@ -58,6 +52,7 @@
 # SMS/SDRC
 obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
 # obj-$(CONFIG_ARCH_OMAP3)		+= sdrc3xxx.o
+obj-$(CONFIG_SOC_HAS_OMAP2_SDRC)	+= sdrc.o
 
 # OPP table initialization
 ifeq ($(CONFIG_PM_OPP),y)
@@ -68,15 +63,15 @@
 
 # Power Management
 ifeq ($(CONFIG_PM),y)
-obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o sleep24xx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o omap-mpuss-lowpower.o
-obj-$(CONFIG_SOC_OMAP5)			+= omap-mpuss-lowpower.o
+obj-$(CONFIG_ARCH_OMAP4)		+= sleep44xx.o
+obj-$(CONFIG_SOC_OMAP5)			+= omap-mpuss-lowpower.o sleep44xx.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
 obj-$(CONFIG_POWER_AVS_OMAP)		+= sr_device.o
-obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
+obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)	+= smartreflex-class3.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a$(plus_sec)
@@ -88,92 +83,76 @@
 endif
 
 ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_OMAP3)                += cpuidle34xx.o
-obj-$(CONFIG_ARCH_OMAP4)                += cpuidle44xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP4)		+= cpuidle44xx.o
 endif
 
 # PRCM
-omap-prcm-4-5-common			=  prcm.o cminst44xx.o cm44xx.o \
-					   prcm_mpu44xx.o prminst44xx.o \
-					   vc44xx_data.o vp44xx_data.o
-obj-y					+= prm_common.o
-obj-$(CONFIG_ARCH_OMAP2)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
-obj-$(CONFIG_ARCH_OMAP3)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
+obj-y					+= prcm.o prm_common.o
+obj-$(CONFIG_ARCH_OMAP2)		+= cm2xxx_3xxx.o prm2xxx_3xxx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= cm2xxx_3xxx.o prm2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= vc3xxx_data.o vp3xxx_data.o
-obj-$(CONFIG_SOC_AM33XX)		+= prcm.o prm33xx.o cm33xx.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-prcm-4-5-common) prm44xx.o
+obj-$(CONFIG_SOC_AM33XX)		+= prm33xx.o cm33xx.o
+omap-prcm-4-5-common			=  cminst44xx.o cm44xx.o prm44xx.o \
+					   prcm_mpu44xx.o prminst44xx.o \
+					   vc44xx_data.o vp44xx_data.o \
+					   prm44xx.o
+obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-prcm-4-5-common)
 obj-$(CONFIG_SOC_OMAP5)			+= $(omap-prcm-4-5-common)
 
 # OMAP voltage domains
-voltagedomain-common			:= voltage.o vc.o vp.o
-obj-$(CONFIG_ARCH_OMAP2)		+= $(voltagedomain-common)
+obj-y					+= voltage.o vc.o vp.o
 obj-$(CONFIG_ARCH_OMAP2)		+= voltagedomains2xxx_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= $(voltagedomain-common)
 obj-$(CONFIG_ARCH_OMAP3)		+= voltagedomains3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(voltagedomain-common)
 obj-$(CONFIG_ARCH_OMAP4)		+= voltagedomains44xx_data.o
-obj-$(CONFIG_SOC_AM33XX)		+= $(voltagedomain-common)
-obj-$(CONFIG_SOC_AM33XX)                += voltagedomains33xx_data.o
-obj-$(CONFIG_SOC_OMAP5)			+= $(voltagedomain-common)
+obj-$(CONFIG_SOC_AM33XX)		+= voltagedomains33xx_data.o
 
 # OMAP powerdomain framework
-powerdomain-common			+= powerdomain.o powerdomain-common.o
-obj-$(CONFIG_ARCH_OMAP2)		+= $(powerdomain-common)
+obj-y					+= powerdomain.o powerdomain-common.o
 obj-$(CONFIG_ARCH_OMAP2)		+= powerdomains2xxx_data.o
 obj-$(CONFIG_ARCH_OMAP2)		+= powerdomain2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= powerdomains2xxx_3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= $(powerdomain-common)
 obj-$(CONFIG_ARCH_OMAP3)		+= powerdomain2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= powerdomains3xxx_data.o
 obj-$(CONFIG_ARCH_OMAP3)		+= powerdomains2xxx_3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(powerdomain-common)
 obj-$(CONFIG_ARCH_OMAP4)		+= powerdomain44xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= powerdomains44xx_data.o
-obj-$(CONFIG_SOC_AM33XX)		+= $(powerdomain-common)
 obj-$(CONFIG_SOC_AM33XX)		+= powerdomain33xx.o
 obj-$(CONFIG_SOC_AM33XX)		+= powerdomains33xx_data.o
-obj-$(CONFIG_SOC_OMAP5)			+= $(powerdomain-common)
 obj-$(CONFIG_SOC_OMAP5)			+= powerdomain44xx.o
 
 # PRCM clockdomain control
-clockdomain-common			+= clockdomain.o
-obj-$(CONFIG_ARCH_OMAP2)		+= $(clockdomain-common)
+obj-y					+= clockdomain.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clockdomain2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clockdomains2xxx_3xxx_data.o
 obj-$(CONFIG_SOC_OMAP2420)		+= clockdomains2420_data.o
 obj-$(CONFIG_SOC_OMAP2430)		+= clockdomains2430_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= $(clockdomain-common)
 obj-$(CONFIG_ARCH_OMAP3)		+= clockdomain2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains2xxx_3xxx_data.o
 obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(clockdomain-common)
 obj-$(CONFIG_ARCH_OMAP4)		+= clockdomain44xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= clockdomains44xx_data.o
-obj-$(CONFIG_SOC_AM33XX)		+= $(clockdomain-common)
 obj-$(CONFIG_SOC_AM33XX)		+= clockdomain33xx.o
 obj-$(CONFIG_SOC_AM33XX)		+= clockdomains33xx_data.o
-obj-$(CONFIG_SOC_OMAP5)			+= $(clockdomain-common)
 obj-$(CONFIG_SOC_OMAP5)			+= clockdomain44xx.o
 
 # Clock framework
-obj-$(CONFIG_ARCH_OMAP2)		+= $(clock-common) clock2xxx.o
-obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_sys.o
-obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpllcore.o
+obj-y					+= clock.o clock_common_data.o \
+					   clkt_dpll.o clkt_clksel.o
+obj-$(CONFIG_ARCH_OMAP2)		+= clock2xxx.o
+obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpllcore.o clkt2xxx_sys.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_virt_prcm_set.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_apll.o clkt2xxx_osc.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpll.o clkt_iclk.o
 obj-$(CONFIG_SOC_OMAP2420)		+= clock2420_data.o
 obj-$(CONFIG_SOC_OMAP2430)		+= clock2430.o clock2430_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= $(clock-common) clock3xxx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= clock3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= clock34xx.o clkt34xx_dpll3m2.o
-obj-$(CONFIG_ARCH_OMAP3)		+= clock3517.o clock36xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= clock3517.o clock36xx.o clkt_iclk.o
 obj-$(CONFIG_ARCH_OMAP3)		+= dpll3xxx.o clock3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP3)		+= clkt_iclk.o
-obj-$(CONFIG_ARCH_OMAP4)		+= $(clock-common) clock44xx_data.o
+obj-$(CONFIG_ARCH_OMAP4)		+= clock44xx_data.o
 obj-$(CONFIG_ARCH_OMAP4)		+= dpll3xxx.o dpll44xx.o
-obj-$(CONFIG_SOC_AM33XX)		+= $(clock-common) dpll3xxx.o
-obj-$(CONFIG_SOC_AM33XX)		+= clock33xx_data.o
-obj-$(CONFIG_SOC_OMAP5)			+= $(clock-common)
+obj-$(CONFIG_SOC_AM33XX)		+= dpll3xxx.o clock33xx_data.o
 obj-$(CONFIG_SOC_OMAP5)			+= dpll3xxx.o dpll44xx.o
 
 # OMAP2 clock rate set data (old "OPP" data)
@@ -181,6 +160,7 @@
 obj-$(CONFIG_SOC_OMAP2430)		+= opp2430_data.o
 
 # hwmod data
+obj-y					+= omap_hwmod_common_data.o
 obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_ipblock_data.o
 obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_3xxx_ipblock_data.o
 obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_interconnect_data.o
@@ -194,6 +174,7 @@
 obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_2xxx_3xxx_ipblock_data.o
 obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_2xxx_3xxx_interconnect_data.o
 obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_3xxx_data.o
+obj-$(CONFIG_SOC_AM33XX)		+= omap_hwmod_33xx_data.o
 obj-$(CONFIG_ARCH_OMAP4)		+= omap_hwmod_44xx_data.o
 
 # EMU peripherals
@@ -229,10 +210,10 @@
 obj-$(CONFIG_MACH_OMAP_2430SDP)		+= board-2430sdp.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)		+= board-apollon.o
 obj-$(CONFIG_MACH_OMAP3_BEAGLE)		+= board-omap3beagle.o
-obj-$(CONFIG_MACH_DEVKIT8000)     	+= board-devkit8000.o
+obj-$(CONFIG_MACH_DEVKIT8000)		+= board-devkit8000.o
 obj-$(CONFIG_MACH_OMAP_LDP)		+= board-ldp.o
-obj-$(CONFIG_MACH_OMAP3530_LV_SOM)      += board-omap3logic.o
-obj-$(CONFIG_MACH_OMAP3_TORPEDO)        += board-omap3logic.o
+obj-$(CONFIG_MACH_OMAP3530_LV_SOM)	+= board-omap3logic.o
+obj-$(CONFIG_MACH_OMAP3_TORPEDO)	+= board-omap3logic.o
 obj-$(CONFIG_MACH_ENCORE)		+= board-omap3encore.o
 obj-$(CONFIG_MACH_OVERO)		+= board-overo.o
 obj-$(CONFIG_MACH_OMAP3EVM)		+= board-omap3evm.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
index 2c90ac6..d0c54c5 100644
--- a/arch/arm/mach-omap2/am35xx-emac.c
+++ b/arch/arm/mach-omap2/am35xx-emac.c
@@ -19,7 +19,7 @@
 #include <linux/davinci_emac.h>
 #include <asm/system.h>
 #include <plat/omap_device.h>
-#include <mach/am35xx.h>
+#include "am35xx.h"
 #include "control.h"
 #include "am35xx-emac.h"
 
diff --git a/arch/arm/mach-omap2/include/mach/am35xx.h b/arch/arm/mach-omap2/am35xx.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/am35xx.h
rename to arch/arm/mach-omap2/am35xx.h
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 0900eac..95b384d 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -36,7 +36,7 @@
 #include "common.h"
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/gpmc-smc91x.h>
+#include "gpmc-smc91x.h"
 
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 5453173..96cd369 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -24,12 +24,12 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/mmc/host.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mcspi.h>
 #include <plat/usb.h>
 #include "common.h"
 #include <plat/dma.h>
@@ -37,7 +37,7 @@
 #include <video/omapdss.h>
 #include <video/omap-panel-tfp410.h>
 
-#include <plat/gpmc-smc91x.h>
+#include "gpmc-smc91x.h"
 
 #include "board-flash.h"
 #include "mux.h"
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index 8518b13..fc224ad 100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -17,7 +17,7 @@
 #include <asm/mach/arch.h>
 
 #include "common.h"
-#include <plat/gpmc-smc91x.h>
+#include "gpmc-smc91x.h"
 #include <plat/usb.h>
 
 #include <mach/board-zoom.h>
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index db43e225..749ce96 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -36,7 +36,7 @@
 #include "common.h"
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <plat/omap4-keypad.h>
+#include "omap4-keypad.h"
 #include <video/omapdss.h>
 #include <video/omap-panel-nokia-dsi.h>
 #include <video/omap-panel-picodlp.h>
@@ -545,6 +545,14 @@
 	.audpwron_gpio	= 127,
 };
 
+static struct i2c_board_info __initdata sdp4430_i2c_1_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl6040", 0x4b),
+		.irq = 119 + OMAP44XX_IRQ_GIC_START,
+		.platform_data = &twl6040_data,
+	},
+};
+
 static struct twl4030_platform_data sdp4430_twldata = {
 	/* Regulators */
 	.vusim		= &sdp4430_vusim,
@@ -578,8 +586,8 @@
 			TWL_COMMON_REGULATOR_CLK32KG |
 			TWL_COMMON_REGULATOR_V1V8 |
 			TWL_COMMON_REGULATOR_V2V1);
-	omap4_pmic_init("twl6030", &sdp4430_twldata,
-			&twl6040_data, 119 + OMAP44XX_IRQ_GIC_START);
+	omap4_pmic_init("twl6030", &sdp4430_twldata, sdp4430_i2c_1_boardinfo,
+			ARRAY_SIZE(sdp4430_i2c_1_boardinfo));
 	omap_register_i2c_bus(2, 400, NULL, 0);
 	omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
 				ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 403d048..0d99c91 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -27,7 +27,7 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_data/gpio-omap.h>
 
-#include <mach/am35xx.h>
+#include "am35xx.h"
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 34cb904..8ffd612 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -39,13 +39,13 @@
 #include <asm/mach/map.h>
 
 #include "common.h"
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-tfp410.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include <mach/hardware.h>
 
@@ -64,7 +64,7 @@
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = {
 	.id		= 0,
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index 27a5450..59c0a45 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -40,10 +40,10 @@
 
 #include "common.h"
 #include <plat/usb.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/gpmc.h>
 
-#include <mach/am35xx.h>
+#include "am35xx.h"
 
 #include "mux.h"
 #include "control.h"
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 18b63ad..7bb8056 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -32,7 +32,7 @@
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
-#include <mach/id.h>
+#include "id.h"
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -40,13 +40,13 @@
 
 #include "common.h"
 #include <plat/gpmc.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-tfp410.h>
 
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/dm9000.h>
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 9017813..0cabe61 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -19,8 +19,8 @@
 
 #include <plat/cpu.h>
 #include <plat/gpmc.h>
-#include <plat/nand.h>
-#include <plat/onenand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 #include <plat/tc.h>
 
 #include "common.h"
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 12569cb..f6c48dd 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -34,7 +34,7 @@
 #include <plat/menelaus.h>
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/debug-devices.h>
+#include "debug-devices.h"
 
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 8408bb2..fb8bd83 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -35,7 +35,7 @@
 
 #include <video/omapdss.h>
 #include <video/omap-panel-tfp410.h>
-#include <plat/onenand.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -192,7 +192,7 @@
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 
 #include <linux/smsc911x.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 static struct omap_smsc911x_platform_data smsc911x_cfg = {
 	.cs             = IGEP2_SMSC911X_CS,
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 3f3a552..ee8c3cf 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -28,17 +28,17 @@
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 #include <linux/mmc/host.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mcspi.h>
 #include "common.h"
 #include <plat/gpmc.h>
 #include <mach/board-zoom.h>
 #include <plat/usb.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index d8deaea..d95f727 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -20,6 +20,8 @@
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/usb/musb.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 #include <sound/tlv320aic3x.h>
 
 #include <asm/mach/arch.h>
@@ -27,8 +29,6 @@
 
 #include "common.h"
 #include <plat/menelaus.h>
-#include <plat/mcspi.h>
-#include <plat/onenand.h>
 #include <plat/mmc.h>
 
 #include "mux.h"
@@ -550,8 +550,8 @@
 
 	ret = menelaus_set_regulator_sleep(1, val);
 	if (ret < 0) {
-		printk(KERN_ERR "Could not set regulators to sleep on "
-			"menelaus: %u\n", ret);
+		pr_err("Could not set regulators to sleep on menelaus: %u\n",
+		       ret);
 		return ret;
 	}
 	return 0;
@@ -563,8 +563,7 @@
 
 	ret = menelaus_set_vcore_hw(1400, 1050);
 	if (ret < 0) {
-		printk(KERN_ERR "Could not set VCORE voltage on "
-			"menelaus: %u\n", ret);
+		pr_err("Could not set VCORE voltage on menelaus: %u\n", ret);
 		return ret;
 	}
 	return 0;
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 801bcb4..68ff8d51 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -42,7 +42,7 @@
 #include <video/omapdss.h>
 #include <video/omap-panel-tfp410.h>
 #include <plat/gpmc.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/usb.h>
 #include <plat/omap_device.h>
 
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index b94873d..c64e565 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -32,6 +32,7 @@
 #include <linux/spi/ads7846.h>
 #include <linux/i2c/twl.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 #include <linux/smsc911x.h>
 
 #include <linux/wl12xx.h>
@@ -45,9 +46,9 @@
 #include <asm/mach/map.h>
 
 #include <plat/usb.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include "common.h"
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-tfp410.h>
 
@@ -118,7 +119,7 @@
 }
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 static struct omap_smsc911x_platform_data smsc911x_cfg = {
 	.cs             = OMAP3EVM_SMSC911X_CS,
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index b5e56fa..7bd8253 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -34,7 +34,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 #include <plat/gpmc.h>
 #include <plat/sdrc.h>
 #include <plat/usb.h>
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index e700a98..00a1f4a 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -35,16 +35,16 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/regulator/fixed.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include "common.h"
-#include <plat/mcspi.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index b8756f0..c7f3d02 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -41,13 +41,13 @@
 
 #include "common.h"
 #include <plat/gpmc.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-tfp410.h>
 
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
@@ -60,7 +60,7 @@
 #include "common-board-devices.h"
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 #define OMAP3STALKER_ETHR_START	0x2c000000
 #define OMAP3STALKER_ETHR_SIZE	1024
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 0e2f838..944ffc4 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -29,7 +29,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/spi/spi.h>
 
 #include <linux/spi/ads7846.h>
@@ -45,7 +45,7 @@
 
 #include "common.h"
 #include <plat/gpmc.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 #include <plat/usb.h>
 
 #include "mux.h"
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 45fe2d3..7b592d3 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -264,6 +264,14 @@
 	.audpwron_gpio	= 127,
 };
 
+static struct i2c_board_info __initdata panda_i2c_1_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl6040", 0x4b),
+		.irq = 119 + OMAP44XX_IRQ_GIC_START,
+		.platform_data = &twl6040_data,
+	},
+};
+
 /* Panda board uses the common PMIC configuration */
 static struct twl4030_platform_data omap4_panda_twldata;
 
@@ -291,8 +299,8 @@
 			TWL_COMMON_REGULATOR_CLK32KG |
 			TWL_COMMON_REGULATOR_V1V8 |
 			TWL_COMMON_REGULATOR_V2V1);
-	omap4_pmic_init("twl6030", &omap4_panda_twldata,
-			&twl6040_data, 119 + OMAP44XX_IRQ_GIC_START);
+	omap4_pmic_init("twl6030", &omap4_panda_twldata, panda_i2c_1_boardinfo,
+			ARRAY_SIZE(panda_i2c_1_boardinfo));
 	omap_register_i2c_bus(2, 400, NULL, 0);
 	/*
 	 * Bus 3 is attached to the DVI port where devices like the pico DLP
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 7a62d13..2e7f240 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -37,6 +37,9 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 
+#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -47,8 +50,6 @@
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-tfp410.h>
 #include <plat/gpmc.h>
-#include <plat/nand.h>
-#include <plat/mcspi.h>
 #include <plat/usb.h>
 
 #include "mux.h"
@@ -113,7 +114,7 @@
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 
 #include <linux/smsc911x.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 static struct omap_smsc911x_platform_data smsc911x_cfg = {
 	.id		= 0,
@@ -516,8 +517,7 @@
 		udelay(10);
 		gpio_set_value(OVERO_GPIO_W2W_NRESET, 1);
 	} else {
-		printk(KERN_ERR "could not obtain gpio for "
-					"OVERO_GPIO_W2W_NRESET\n");
+		pr_err("could not obtain gpio for OVERO_GPIO_W2W_NRESET\n");
 	}
 
 	ret = gpio_request_array(overo_bt_gpios, ARRAY_SIZE(overo_bt_gpios));
@@ -536,8 +536,7 @@
 	if (ret == 0)
 		gpio_export(OVERO_GPIO_USBH_CPEN, 0);
 	else
-		printk(KERN_ERR "could not obtain gpio for "
-					"OVERO_GPIO_USBH_CPEN\n");
+		pr_err("could not obtain gpio for OVERO_GPIO_USBH_CPEN\n");
 }
 
 MACHINE_START(OVERO, "Gumstix Overo")
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index 00773a3..45997bf 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -17,6 +17,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -26,7 +27,6 @@
 #include <plat/usb.h>
 #include <plat/gpmc.h>
 #include "common.h"
-#include <plat/onenand.h>
 #include <plat/serial.h>
 
 #include "mux.h"
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 4560490..3945c50 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -25,16 +25,17 @@
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
 #include <linux/power/isp1704_charger.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
+
 #include <asm/system_info.h>
 
-#include <plat/mcspi.h>
 #include "common.h"
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/onenand.h>
-#include <plat/gpmc-smc91x.h>
+#include "gpmc-smc91x.h"
 
-#include <mach/board-rx51.h>
+#include "board-rx51.h"
 
 #include <sound/tlv320aic3x.h>
 #include <sound/tpa6130a2-plat.h>
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
index 2c1289b..c22e111 100644
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -17,9 +17,9 @@
 #include <asm/mach-types.h>
 #include <video/omapdss.h>
 #include <plat/vram.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
-#include <mach/board-rx51.h>
+#include "board-rx51.h"
 
 #include "mux.h"
 
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index 93b4661..7bbb05d 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -17,12 +17,12 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/mcspi.h>
 #include "common.h"
 #include <plat/dma.h>
 #include <plat/gpmc.h>
diff --git a/arch/arm/mach-omap2/include/mach/board-rx51.h b/arch/arm/mach-omap2/board-rx51.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/board-rx51.h
rename to arch/arm/mach-omap2/board-rx51.h
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
index 5ec069e..afb2278 100644
--- a/arch/arm/mach-omap2/board-zoom-debugboard.c
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -18,7 +18,7 @@
 #include <linux/regulator/machine.h>
 
 #include <plat/gpmc.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 #include <mach/board-zoom.h>
 
@@ -84,8 +84,7 @@
 	quart_cs = ZOOM_QUADUART_CS;
 
 	if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem"
-				"for Quad UART(TL16CP754C)\n");
+		pr_err("Failed to request GPMC mem for Quad UART(TL16CP754C)\n");
 		return;
 	}
 
@@ -107,8 +106,8 @@
 
 	if (gpio_request_one(debug_board_detect, GPIOF_IN,
 			     "Zoom debug board detect") < 0) {
-		printk(KERN_ERR "Failed to request GPIO%d for Zoom debug"
-		"board detect\n", debug_board_detect);
+		pr_err("Failed to request GPIO%d for Zoom debug board detect\n",
+		       debug_board_detect);
 		return 0;
 	}
 
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index ea79bc2..b940ab2 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -14,7 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl.h>
 #include <linux/spi/spi.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <video/omapdss.h>
 #include <mach/board-zoom.h>
 
diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c
index d6e34dd..298887b 100644
--- a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c
+++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c
@@ -92,15 +92,13 @@
 
 	pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
 		 validrate);
-	pr_debug("clock: SDRC CS0 timing params used:"
-		 " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
+	pr_debug("clock: SDRC CS0 timing params used: RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
 		 sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla,
 		 sdrc_cs0->actim_ctrlb, sdrc_cs0->mr);
 	if (sdrc_cs1)
-		pr_debug("clock: SDRC CS1 timing params used: "
-		 " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
-		 sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla,
-		 sdrc_cs1->actim_ctrlb, sdrc_cs1->mr);
+		pr_debug("clock: SDRC CS1 timing params used: RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
+			 sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla,
+			 sdrc_cs1->actim_ctrlb, sdrc_cs1->mr);
 
 	if (sdrc_cs1)
 		omap3_configure_core_dpll(
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index 04d551b..19a9809 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -71,8 +71,8 @@
 
 	if (!clks->parent) {
 		/* This indicates a data problem */
-		WARN(1, "clock: Could not find parent clock %s in clksel array "
-		     "of clock %s\n", src_clk->name, clk->name);
+		WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
+		     clk->name, src_clk->name);
 		return NULL;
 	}
 
@@ -126,8 +126,8 @@
 
 	if (max_div == 0) {
 		/* This indicates an error in the clksel data */
-		WARN(1, "clock: Could not find divisor for clock %s parent %s"
-		     "\n", clk->name, src_clk->parent->name);
+		WARN(1, "clock: %s: could not find divisor for parent %s\n",
+		     clk->name, src_clk->parent->name);
 		return 0;
 	}
 
@@ -191,8 +191,8 @@
 
 	if (!clkr->div) {
 		/* This indicates a data error */
-		WARN(1, "clock: Could not find fieldval %d for clock %s parent "
-		     "%s\n", field_val, clk->name, clk->parent->name);
+		WARN(1, "clock: %s: could not find fieldval %d parent %s\n",
+		     clk->name, field_val, clk->parent->name);
 		return 0;
 	}
 
@@ -230,8 +230,8 @@
 	}
 
 	if (!clkr->div) {
-		pr_err("clock: Could not find divisor %d for clock %s parent "
-		       "%s\n", div, clk->name, clk->parent->name);
+		pr_err("clock: %s: could not find divisor %d parent %s\n",
+		       clk->name, div, clk->parent->name);
 		return ~0;
 	}
 
@@ -300,8 +300,8 @@
 
 		/* Sanity check */
 		if (clkr->div <= last_div)
-			pr_err("clock: clksel_rate table not sorted "
-			       "for clock %s", clk->name);
+			pr_err("clock: %s: clksel_rate table not sorted",
+			       clk->name);
 
 		last_div = clkr->div;
 
@@ -312,9 +312,8 @@
 	}
 
 	if (!clkr->div) {
-		pr_err("clock: Could not find divisor for target "
-		       "rate %ld for clock %s parent %s\n", target_rate,
-		       clk->name, clk->parent->name);
+		pr_err("clock: %s: could not find divisor for target rate %ld parent %s\n",
+		       clk->name, target_rate, clk->parent->name);
 		return ~0;
 	}
 
@@ -359,8 +358,7 @@
 
 			if (clkr->val == r) {
 				if (clk->parent != clks->parent) {
-					pr_debug("clock: inited %s parent "
-						 "to %s (was %s)\n",
+					pr_debug("clock: %s: inited parent to %s (was %s)\n",
 						 clk->name, clks->parent->name,
 						 ((clk->parent) ?
 						  clk->parent->name : "NULL"));
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index ae624c3..83b658b 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -105,13 +105,13 @@
 	}
 
 	if (fint < fint_min) {
-		pr_debug("rejecting n=%d due to Fint failure, "
-			 "lowering max_divider\n", n);
+		pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
+			 n);
 		dd->max_divider = n;
 		ret = DPLL_FINT_UNDERFLOW;
 	} else if (fint > fint_max) {
-		pr_debug("rejecting n=%d due to Fint failure, "
-			 "boosting min_divider\n", n);
+		pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
+			 n);
 		dd->min_divider = n;
 		ret = DPLL_FINT_INVALID;
 	} else if (cpu_is_omap3430() && fint > OMAP3430_DPLL_FINT_BAND1_MAX &&
@@ -211,7 +211,7 @@
 		if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
 		    v == OMAP3XXX_EN_DPLL_FRBYPASS)
 			clk_reparent(clk, dd->clk_bypass);
-	} else if (cpu_is_omap44xx()) {
+	} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
 		if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
 		    v == OMAP4XXX_EN_DPLL_FRBYPASS ||
 		    v == OMAP4XXX_EN_DPLL_MNBYPASS)
@@ -257,7 +257,7 @@
 		if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
 		    v == OMAP3XXX_EN_DPLL_FRBYPASS)
 			return dd->clk_bypass->rate;
-	} else if (cpu_is_omap44xx()) {
+	} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
 		if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
 		    v == OMAP4XXX_EN_DPLL_FRBYPASS ||
 		    v == OMAP4XXX_EN_DPLL_MNBYPASS)
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 1a1f97f..e97f98f 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -104,8 +104,8 @@
 			 clk->name, clk->clkdm_name);
 		clk->clkdm = clkdm;
 	} else {
-		pr_debug("clock: could not associate clk %s to "
-			 "clkdm %s\n", clk->name, clk->clkdm_name);
+		pr_debug("clock: could not associate clk %s to clkdm %s\n",
+			 clk->name, clk->clkdm_name);
 	}
 }
 
@@ -228,8 +228,7 @@
 		 * 'Independent' here refers to a clock which is not
 		 * controlled by its parent.
 		 */
-		printk(KERN_ERR "clock: clk_disable called on independent "
-		       "clock %s which has no enable_reg\n", clk->name);
+		pr_err("clock: clk_disable called on independent clock %s which has no enable_reg\n", clk->name);
 		return;
 	}
 
@@ -272,8 +271,7 @@
 void omap2_clk_disable(struct clk *clk)
 {
 	if (clk->usecount == 0) {
-		WARN(1, "clock: %s: omap2_clk_disable() called, but usecount "
-		     "already 0?", clk->name);
+		WARN(1, "clock: %s: omap2_clk_disable() called, but usecount already 0?", clk->name);
 		return;
 	}
 
@@ -334,8 +332,8 @@
 	if (clkdm_control && clk->clkdm) {
 		ret = clkdm_clk_enable(clk->clkdm, clk);
 		if (ret) {
-			WARN(1, "clock: %s: could not enable clockdomain %s: "
-			     "%d\n", clk->name, clk->clkdm->name, ret);
+			WARN(1, "clock: %s: could not enable clockdomain %s: %d\n",
+			     clk->name, clk->clkdm->name, ret);
 			goto oce_err2;
 		}
 	}
@@ -503,10 +501,8 @@
 
 	hfclkin_rate = clk_get_rate(hfclkin_ck);
 
-	pr_info("Switched to new clocking rate (Crystal/Core/MPU): "
-		"%ld.%01ld/%ld/%ld MHz\n",
-		(hfclkin_rate / 1000000),
-		((hfclkin_rate / 100000) % 10),
+	pr_info("Switched to new clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
+		(hfclkin_rate / 1000000), ((hfclkin_rate / 100000) % 10),
 		(clk_get_rate(core_ck) / 1000000),
 		(clk_get_rate(mpu_ck) / 1000000));
 }
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index 02fe1f2..7ea9139 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -1856,6 +1856,7 @@
 	CLK(NULL,	"func_32k_ck",	&func_32k_ck,	CK_243X),
 	CLK(NULL,	"secure_32k_ck", &secure_32k_ck, CK_243X),
 	CLK(NULL,	"osc_ck",	&osc_ck,	CK_243X),
+	CLK("twl",	"fck",		&osc_ck,	CK_243X),
 	CLK(NULL,	"sys_ck",	&sys_ck,	CK_243X),
 	CLK(NULL,	"alt_ck",	&alt_ck,	CK_243X),
 	CLK(NULL,	"mcbsp_clks",	&mcbsp_clks,	CK_243X),
diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
index 8e06de6..2026311 100644
--- a/arch/arm/mach-omap2/clock33xx_data.c
+++ b/arch/arm/mach-omap2/clock33xx_data.c
@@ -1027,7 +1027,9 @@
 	CLK(NULL,	"cefuse_fck",		&cefuse_fck,	CK_AM33XX),
 	CLK(NULL,	"clkdiv32k_ick",	&clkdiv32k_ick,	CK_AM33XX),
 	CLK(NULL,	"dcan0_fck",		&dcan0_fck,	CK_AM33XX),
+	CLK("481cc000.d_can",	NULL,		&dcan0_fck,	CK_AM33XX),
 	CLK(NULL,	"dcan1_fck",		&dcan1_fck,	CK_AM33XX),
+	CLK("481d0000.d_can",	NULL,		&dcan1_fck,	CK_AM33XX),
 	CLK(NULL,	"debugss_ick",		&debugss_ick,	CK_AM33XX),
 	CLK(NULL,	"pruss_ocp_gclk",	&pruss_ocp_gclk,	CK_AM33XX),
 	CLK("davinci-mcasp.0",  NULL,           &mcasp0_fck,    CK_AM33XX),
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index fc2765b..15cdc647 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -49,8 +49,7 @@
 	 * on DPLL4.
 	 */
 	if (omap_rev() == OMAP3430_REV_ES1_0) {
-		pr_err("clock: DPLL4 cannot change rate due to "
-		       "silicon 'Limitation 2.5' on 3430ES1.\n");
+		pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
 		return -EINVAL;
 	}
 
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index 10a2398..700317a 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3226,6 +3226,7 @@
 	CLK(NULL,	"virt_26000000_ck",	&virt_26000000_ck,	CK_3XXX),
 	CLK(NULL,	"virt_38_4m_ck", &virt_38_4m_ck, CK_3XXX),
 	CLK(NULL,	"osc_sys_ck",	&osc_sys_ck,	CK_3XXX),
+	CLK("twl",	"fck",		&osc_sys_ck,	CK_3XXX),
 	CLK(NULL,	"sys_ck",	&sys_ck,	CK_3XXX),
 	CLK(NULL,	"sys_altclk",	&sys_altclk,	CK_3XXX),
 	CLK(NULL,	"mcbsp_clks",	&mcbsp_clks,	CK_3XXX),
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 8664f5a..a155562 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -174,9 +174,8 @@
 		if (IS_ERR(autodep->clkdm.ptr))
 			continue;
 
-		pr_debug("clockdomain: adding %s sleepdep/wkdep for "
-			 "clkdm %s\n", autodep->clkdm.ptr->name,
-			 clkdm->name);
+		pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
+			 clkdm->name, autodep->clkdm.ptr->name);
 
 		clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
 		clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
@@ -205,9 +204,8 @@
 		if (IS_ERR(autodep->clkdm.ptr))
 			continue;
 
-		pr_debug("clockdomain: removing %s sleepdep/wkdep for "
-			 "clkdm %s\n", autodep->clkdm.ptr->name,
-			 clkdm->name);
+		pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
+			 clkdm->name, autodep->clkdm.ptr->name);
 
 		clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
 		clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
@@ -469,14 +467,14 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear wake up of "
-			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
 	if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
-		pr_debug("clockdomain: hardware will wake up %s when %s wakes "
-			 "up\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
+			 clkdm1->name, clkdm2->name);
 
 		ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
 	}
@@ -510,14 +508,14 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear wake up of "
-			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
 	if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
-		pr_debug("clockdomain: hardware will no longer wake up %s "
-			 "after %s wakes up\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
+			 clkdm1->name, clkdm2->name);
 
 		ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
 	}
@@ -555,8 +553,8 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear wake up of "
-			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
@@ -613,15 +611,14 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear sleep "
-			 "dependency affecting %s from %s\n", clkdm1->name,
-			 clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
 	if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
-		pr_debug("clockdomain: will prevent %s from sleeping if %s "
-			 "is active\n", clkdm1->name, clkdm2->name);
+		pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
+			 clkdm1->name, clkdm2->name);
 
 		ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
 	}
@@ -657,16 +654,14 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear sleep "
-			 "dependency affecting %s from %s\n", clkdm1->name,
-			 clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
 	if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
-		pr_debug("clockdomain: will no longer prevent %s from "
-			 "sleeping if %s is active\n", clkdm1->name,
-			 clkdm2->name);
+		pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
+			 clkdm1->name, clkdm2->name);
 
 		ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
 	}
@@ -706,9 +701,8 @@
 		ret = -EINVAL;
 
 	if (ret) {
-		pr_debug("clockdomain: hardware cannot set/clear sleep "
-			 "dependency affecting %s from %s\n", clkdm1->name,
-			 clkdm2->name);
+		pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
+			 clkdm1->name, clkdm2->name);
 		return ret;
 	}
 
@@ -755,8 +749,8 @@
 		return -EINVAL;
 
 	if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
-		pr_debug("clockdomain: %s does not support forcing "
-			 "sleep via software\n", clkdm->name);
+		pr_debug("clockdomain: %s does not support forcing sleep via software\n",
+			 clkdm->name);
 		return -EINVAL;
 	}
 
@@ -790,8 +784,8 @@
 		return -EINVAL;
 
 	if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
-		pr_debug("clockdomain: %s does not support forcing "
-			 "wakeup via software\n", clkdm->name);
+		pr_debug("clockdomain: %s does not support forcing wakeup via software\n",
+			 clkdm->name);
 		return -EINVAL;
 	}
 
@@ -826,8 +820,8 @@
 		return;
 
 	if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
-		pr_debug("clock: automatic idle transitions cannot be enabled "
-			 "on clockdomain %s\n", clkdm->name);
+		pr_debug("clock: %s: automatic idle transitions cannot be enabled\n",
+			 clkdm->name);
 		return;
 	}
 
@@ -861,8 +855,8 @@
 		return;
 
 	if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
-		pr_debug("clockdomain: automatic idle transitions cannot be "
-			 "disabled on %s\n", clkdm->name);
+		pr_debug("clockdomain: %s: automatic idle transitions cannot be disabled\n",
+			 clkdm->name);
 		return;
 	}
 
@@ -927,7 +921,7 @@
 	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 
-	pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
+	pr_debug("clockdomain: %s: enabled\n", clkdm->name);
 
 	return 0;
 }
@@ -952,7 +946,7 @@
 	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 
-	pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
+	pr_debug("clockdomain: %s: disabled\n", clkdm->name);
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
index 013fedc..48daac2 100644
--- a/arch/arm/mach-omap2/common-board-devices.c
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -24,8 +24,8 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
-#include <plat/mcspi.h>
-#include <plat/nand.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 
 #include "common.h"
 #include "common-board-devices.h"
@@ -120,8 +120,7 @@
 	}
 
 	if (nandcs > GPMC_CS_NUM) {
-		printk(KERN_INFO "NAND: Unable to find configuration "
-				 "in GPMC\n ");
+		pr_info("NAND: Unable to find configuration in GPMC\n");
 		return;
 	}
 
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
index 8e43c4d8..17950c6 100644
--- a/arch/arm/mach-omap2/common.c
+++ b/arch/arm/mach-omap2/common.c
@@ -17,7 +17,6 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <plat/mux.h>
 #include <plat/clock.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index c1a5cab..123186a 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -16,10 +16,10 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
 #define __ARCH_ARM_MACH_OMAP2_CONTROL_H
 
-#include <mach/ctrl_module_core_44xx.h>
-#include <mach/ctrl_module_wkup_44xx.h>
-#include <mach/ctrl_module_pad_core_44xx.h>
-#include <mach/ctrl_module_pad_wkup_44xx.h>
+#include "ctrl_module_core_44xx.h"
+#include "ctrl_module_wkup_44xx.h"
+#include "ctrl_module_pad_core_44xx.h"
+#include "ctrl_module_pad_wkup_44xx.h"
 
 #include "am33xx.h"
 
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/ctrl_module_core_44xx.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
rename to arch/arm/mach-omap2/ctrl_module_core_44xx.h
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h b/arch/arm/mach-omap2/ctrl_module_pad_core_44xx.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h
rename to arch/arm/mach-omap2/ctrl_module_pad_core_44xx.h
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h b/arch/arm/mach-omap2/ctrl_module_pad_wkup_44xx.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h
rename to arch/arm/mach-omap2/ctrl_module_pad_wkup_44xx.h
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h b/arch/arm/mach-omap2/ctrl_module_wkup_44xx.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
rename to arch/arm/mach-omap2/ctrl_module_wkup_44xx.h
diff --git a/arch/arm/plat-omap/include/plat/debug-devices.h b/arch/arm/mach-omap2/debug-devices.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/debug-devices.h
rename to arch/arm/mach-omap2/debug-devices.h
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 1efa984..d092d2a8 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -17,17 +17,17 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/pinctrl/machine.h>
 #include <linux/platform_data/omap4-keypad.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
-#include <asm/pmu.h>
 
 #include "iomap.h"
 #include <plat/dma.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
-#include <plat/omap4-keypad.h>
+#include "omap4-keypad.h"
 
 #include "soc.h"
 #include "common.h"
@@ -384,7 +384,7 @@
 
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused)
 {
@@ -445,7 +445,7 @@
 
 static struct platform_device omap_pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= 1,
 };
 
@@ -628,6 +628,10 @@
 
 static int __init omap2_init_devices(void)
 {
+	/* Enable dummy states for those platforms without pinctrl support */
+	if (!of_have_populated_dt())
+		pinctrl_provide_dummies();
+
 	/*
 	 * please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index d8318dc..27d79de 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -311,7 +311,7 @@
 	 * Set jitter correction. No jitter correction for OMAP4 and 3630
 	 * since freqsel field is no longer present
 	 */
-	if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
+	if (!soc_is_am33xx() && !cpu_is_omap44xx() && !cpu_is_omap3630()) {
 		v = __raw_readl(dd->control_reg);
 		v &= ~dd->freqsel_mask;
 		v |= freqsel << __ffs(dd->freqsel_mask);
@@ -471,7 +471,7 @@
 			return -EINVAL;
 
 		/* No freqsel on OMAP4 and OMAP3630 */
-		if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
+		if (!soc_is_am33xx() && !cpu_is_omap44xx() && !cpu_is_omap3630()) {
 			freqsel = _omap3_dpll_compute_freqsel(clk,
 						dd->last_rounded_n);
 			if (!freqsel)
@@ -623,8 +623,11 @@
 	while (pclk && !pclk->dpll_data)
 		pclk = pclk->parent;
 
-	/* clk does not have a DPLL as a parent? */
-	WARN_ON(!pclk);
+	/* clk does not have a DPLL as a parent?  error in the clock data */
+	if (!pclk) {
+		WARN_ON(1);
+		return 0;
+	}
 
 	dd = pclk->dpll_data;
 
diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c
index a636ebc..9838810 100644
--- a/arch/arm/mach-omap2/dsp.c
+++ b/arch/arm/mach-omap2/dsp.c
@@ -30,7 +30,7 @@
 #include <plat/omap-pm.h>
 #endif
 
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 
 static struct platform_device *omap_dsp_pdev;
 
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 7b52bdf..d1058f1 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -61,6 +61,7 @@
 	pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
 	if (!pdata->regs) {
 		pr_err("gpio%d: Memory allocation failed\n", id);
+		kfree(pdata);
 		return -ENOMEM;
 	}
 
@@ -122,6 +123,7 @@
 		break;
 	default:
 		WARN(1, "Invalid gpio bank_type\n");
+		kfree(pdata->regs);
 		kfree(pdata);
 		return -EINVAL;
 	}
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 9e9f47a..4acf497 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -13,10 +13,10 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/mtd/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 
 #include <asm/mach/flash.h>
 
-#include <plat/nand.h>
 #include <plat/gpmc.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index b66fb8e..916716e 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -15,10 +15,10 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/onenand_regs.h>
 #include <linux/io.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 
 #include <asm/mach/flash.h>
 
-#include <plat/onenand.h>
 #include <plat/gpmc.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 245839d..5654753 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -18,7 +18,7 @@
 #include <linux/smc91x.h>
 
 #include <plat/gpmc.h>
-#include <plat/gpmc-smc91x.h>
+#include "gpmc-smc91x.h"
 
 #include "soc.h"
 
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smc91x.h b/arch/arm/mach-omap2/gpmc-smc91x.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/gpmc-smc91x.h
rename to arch/arm/mach-omap2/gpmc-smc91x.h
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index a3a2887..249a0b4 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -21,7 +21,7 @@
 #include <linux/smsc911x.h>
 
 #include <plat/gpmc.h>
-#include <plat/gpmc-smsc911x.h>
+#include "gpmc-smsc911x.h"
 
 static struct resource gpmc_smsc911x_resources[] = {
 	[0] = {
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h b/arch/arm/mach-omap2/gpmc-smsc911x.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
rename to arch/arm/mach-omap2/gpmc-smsc911x.h
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 055ae8b..72428bd 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -297,7 +297,7 @@
 
 	div = gpmc_cs_calc_divider(cs, t->sync_clk);
 	if (div < 0)
-		return -1;
+		return div;
 
 	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
 	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c
index cdd6dda..e003f2b 100644
--- a/arch/arm/mach-omap2/hdq1w.c
+++ b/arch/arm/mach-omap2/hdq1w.c
@@ -29,7 +29,7 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
-#include <plat/hdq1w.h>
+#include "hdq1w.h"
 
 #include "common.h"
 
diff --git a/arch/arm/plat-omap/include/plat/hdq1w.h b/arch/arm/mach-omap2/hdq1w.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/hdq1w.h
rename to arch/arm/mach-omap2/hdq1w.h
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 80399d7..03ebf47 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -19,7 +19,6 @@
 
 #include <plat/mmc.h>
 #include <plat/omap-pm.h>
-#include <plat/mux.h>
 #include <plat/omap_device.h>
 
 #include "mux.h"
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 7219df0..cf2362c 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -23,7 +23,7 @@
 
 #include "common.h"
 
-#include <mach/id.h>
+#include "id.h"
 
 #include "soc.h"
 #include "control.h"
@@ -161,9 +161,8 @@
 	}
 
 	if (j == ARRAY_SIZE(omap_ids)) {
-		printk(KERN_ERR "Unknown OMAP device type. "
-				"Handling it as OMAP%04x\n",
-				omap_ids[i].type >> 16);
+		pr_err("Unknown OMAP device type. Handling it as OMAP%04x\n",
+		       omap_ids[i].type >> 16);
 		j = i;
 	}
 
diff --git a/arch/arm/mach-omap2/include/mach/id.h b/arch/arm/mach-omap2/id.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/id.h
rename to arch/arm/mach-omap2/id.h
diff --git a/arch/arm/mach-omap2/include/mach/smp.h b/arch/arm/mach-omap2/include/mach/smp.h
deleted file mode 100644
index 323675f..0000000
--- a/arch/arm/mach-omap2/include/mach/smp.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap2/include/mach/smp.h
- */
-
-#include <plat/smp.h>
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 0d79c23..4234d28 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -524,6 +524,8 @@
 	am33xx_voltagedomains_init();
 	am33xx_powerdomains_init();
 	am33xx_clockdomains_init();
+	am33xx_hwmod_init();
+	omap_hwmod_init_postsetup();
 	am33xx_clk_init();
 }
 #endif
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index efed4f5..3926f37 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -108,9 +108,8 @@
 	unsigned long tmp;
 
 	tmp = intc_bank_read_reg(bank, INTC_REVISION) & 0xff;
-	printk(KERN_INFO "IRQ: Found an INTC at 0x%p "
-			 "(revision %ld.%ld) with %d interrupts\n",
-			 bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
+	pr_info("IRQ: Found an INTC at 0x%p (revision %ld.%ld) with %d interrupts\n",
+		bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
 
 	tmp = intc_bank_read_reg(bank, INTC_SYSCONFIG);
 	tmp |= 1 << 1;	/* soft reset */
diff --git a/arch/arm/plat-omap/include/plat/l3_2xxx.h b/arch/arm/mach-omap2/l3_2xxx.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/l3_2xxx.h
rename to arch/arm/mach-omap2/l3_2xxx.h
diff --git a/arch/arm/plat-omap/include/plat/l3_3xxx.h b/arch/arm/mach-omap2/l3_3xxx.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/l3_3xxx.h
rename to arch/arm/mach-omap2/l3_3xxx.h
diff --git a/arch/arm/plat-omap/include/plat/l4_2xxx.h b/arch/arm/mach-omap2/l4_2xxx.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/l4_2xxx.h
rename to arch/arm/mach-omap2/l4_2xxx.h
diff --git a/arch/arm/plat-omap/include/plat/l4_3xxx.h b/arch/arm/mach-omap2/l4_3xxx.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/l4_3xxx.h
rename to arch/arm/mach-omap2/l4_3xxx.h
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index d493727..7d47407 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -17,9 +17,9 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include <plat/dma.h>
-#include <plat/mcbsp.h>
 #include <plat/omap_device.h>
 #include <linux/pm_runtime.h>
 
diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
index 414083b..765a2ac 100644
--- a/arch/arm/mach-omap2/omap-hotplug.c
+++ b/arch/arm/mach-omap2/omap-hotplug.c
@@ -20,7 +20,7 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
-#include <mach/omap-wakeupgen.h>
+#include "omap-wakeupgen.h"
 
 #include "common.h"
 
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index d9ae4a5..a004cb9 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -19,7 +19,7 @@
 #include <asm/memblock.h>
 
 #include <plat/omap-secure.h>
-#include <mach/omap-secure.h>
+#include "omap-secure.h"
 
 static phys_addr_t omap_secure_memblock_base;
 
diff --git a/arch/arm/mach-omap2/include/mach/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/omap-secure.h
rename to arch/arm/mach-omap2/omap-secure.h
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 19cc5f5..06d8bc3 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -24,8 +24,8 @@
 #include <asm/hardware/gic.h>
 #include <asm/smp_scu.h>
 
-#include <mach/omap-secure.h>
-#include <mach/omap-wakeupgen.h>
+#include "omap-secure.h"
+#include "omap-wakeupgen.h"
 #include <asm/cputype.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index ecaad7d..5d3b4f4 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -27,8 +27,8 @@
 
 #include <asm/hardware/gic.h>
 
-#include <mach/omap-wakeupgen.h>
-#include <mach/omap-secure.h>
+#include "omap-wakeupgen.h"
+#include "omap-secure.h"
 
 #include "soc.h"
 #include "omap4-sar-layout.h"
@@ -230,13 +230,7 @@
 	/* Save AuxBoot* registers */
 	val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
 	__raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET);
-	val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
-	__raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET);
-
-	/* Save SyncReq generation logic */
-	val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
-	__raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET);
-	val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
+	val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_1);
 	__raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET);
 
 	/* Save SyncReq generation logic */
diff --git a/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h b/arch/arm/mach-omap2/omap-wakeupgen.h
similarity index 100%
rename from arch/arm/mach-omap2/include/mach/omap-wakeupgen.h
rename to arch/arm/mach-omap2/omap-wakeupgen.h
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 3cd2564..e1f2897 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -29,7 +29,7 @@
 #include <plat/omap-secure.h>
 #include <plat/mmc.h>
 
-#include <mach/omap-wakeupgen.h>
+#include "omap-wakeupgen.h"
 
 #include "soc.h"
 #include "common.h"
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/mach-omap2/omap4-keypad.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/omap4-keypad.h
rename to arch/arm/mach-omap2/omap4-keypad.h
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 4a810f6..00c0066 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -149,8 +149,10 @@
 #include "powerdomain.h"
 #include "cm2xxx_3xxx.h"
 #include "cminst44xx.h"
+#include "cm33xx.h"
 #include "prm2xxx_3xxx.h"
 #include "prm44xx.h"
+#include "prm33xx.h"
 #include "prminst44xx.h"
 #include "mux.h"
 #include "pm.h"
@@ -868,6 +870,26 @@
 }
 
 /**
+ * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX
+ * @oh: struct omap_hwmod *
+ *
+ * Enables the PRCM module mode related to the hwmod @oh.
+ * No return value.
+ */
+static void _am33xx_enable_module(struct omap_hwmod *oh)
+{
+	if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+		return;
+
+	pr_debug("omap_hwmod: %s: %s: %d\n",
+		 oh->name, __func__, oh->prcm.omap4.modulemode);
+
+	am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst,
+				oh->clkdm->clkdm_offs,
+				oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
  * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4
  * @oh: struct omap_hwmod *
  *
@@ -894,6 +916,31 @@
 }
 
 /**
+ * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX
+ * @oh: struct omap_hwmod *
+ *
+ * Wait for a module @oh to enter slave idle.  Returns 0 if the module
+ * does not have an IDLEST bit or if the module successfully enters
+ * slave idle; otherwise, pass along the return value of the
+ * appropriate *_cm*_wait_module_idle() function.
+ */
+static int _am33xx_wait_target_disable(struct omap_hwmod *oh)
+{
+	if (!oh)
+		return -EINVAL;
+
+	if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+		return 0;
+
+	if (oh->flags & HWMOD_NO_IDLEST)
+		return 0;
+
+	return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst,
+					     oh->clkdm->clkdm_offs,
+					     oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
  * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
  * @oh: struct omap_hwmod *oh
  *
@@ -1438,8 +1485,8 @@
  * Return the bit position of the reset line that match the
  * input name. Return -ENOENT if not found.
  */
-static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name,
-			    struct omap_hwmod_rst_info *ohri)
+static int _lookup_hardreset(struct omap_hwmod *oh, const char *name,
+			     struct omap_hwmod_rst_info *ohri)
 {
 	int i;
 
@@ -1475,7 +1522,7 @@
 static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
 {
 	struct omap_hwmod_rst_info ohri;
-	u8 ret = -EINVAL;
+	int ret = -EINVAL;
 
 	if (!oh)
 		return -EINVAL;
@@ -1484,7 +1531,7 @@
 		return -ENOSYS;
 
 	ret = _lookup_hardreset(oh, name, &ohri);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		return ret;
 
 	ret = soc_ops.assert_hardreset(oh, &ohri);
@@ -1542,7 +1589,7 @@
 static int _read_hardreset(struct omap_hwmod *oh, const char *name)
 {
 	struct omap_hwmod_rst_info ohri;
-	u8 ret = -EINVAL;
+	int ret = -EINVAL;
 
 	if (!oh)
 		return -EINVAL;
@@ -1551,7 +1598,7 @@
 		return -ENOSYS;
 
 	ret = _lookup_hardreset(oh, name, &ohri);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		return ret;
 
 	return soc_ops.is_hardreset_asserted(oh, &ohri);
@@ -1614,6 +1661,36 @@
 }
 
 /**
+ * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX
+ * @oh: struct omap_hwmod *
+ *
+ * Disable the PRCM module mode related to the hwmod @oh.
+ * Return EINVAL if the modulemode is not supported and 0 in case of success.
+ */
+static int _am33xx_disable_module(struct omap_hwmod *oh)
+{
+	int v;
+
+	if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+		return -EINVAL;
+
+	pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
+
+	am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs,
+				 oh->prcm.omap4.clkctrl_offs);
+
+	if (_are_any_hardreset_lines_asserted(oh))
+		return 0;
+
+	v = _am33xx_wait_target_disable(oh);
+	if (v)
+		pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+			oh->name);
+
+	return 0;
+}
+
+/**
  * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
  * @oh: struct omap_hwmod *
  *
@@ -1641,8 +1718,8 @@
 
 	/* clocks must be on for this operation */
 	if (oh->_state != _HWMOD_STATE_ENABLED) {
-		pr_warning("omap_hwmod: %s: reset can only be entered from "
-			   "enabled state\n", oh->name);
+		pr_warn("omap_hwmod: %s: reset can only be entered from enabled state\n",
+			oh->name);
 		return -EINVAL;
 	}
 
@@ -2549,6 +2626,33 @@
 }
 
 /**
+ * _am33xx_wait_target_ready - wait for a module to leave slave idle
+ * @oh: struct omap_hwmod *
+ *
+ * Wait for a module @oh to leave slave idle.  Returns 0 if the module
+ * does not have an IDLEST bit or if the module successfully leaves
+ * slave idle; otherwise, pass along the return value of the
+ * appropriate *_cm*_wait_module_ready() function.
+ */
+static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
+{
+	if (!oh || !oh->clkdm)
+		return -EINVAL;
+
+	if (oh->flags & HWMOD_NO_IDLEST)
+		return 0;
+
+	if (!_find_mpu_rt_port(oh))
+		return 0;
+
+	/* XXX check module SIDLEMODE, hardreset status */
+
+	return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst,
+					      oh->clkdm->clkdm_offs,
+					      oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
  * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
  * @oh: struct omap_hwmod * to assert hardreset
  * @ohri: hardreset line data
@@ -2679,6 +2783,72 @@
 				oh->prcm.omap4.rstctrl_offs);
 }
 
+/**
+ * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args
+ * @oh: struct omap_hwmod * to assert hardreset
+ * @ohri: hardreset line data
+ *
+ * Call am33xx_prminst_assert_hardreset() with parameters extracted
+ * from the hwmod @oh and the hardreset line data @ohri.  Only
+ * intended for use as an soc_ops function pointer.  Passes along the
+ * return value from am33xx_prminst_assert_hardreset().  XXX This
+ * function is scheduled for removal when the PRM code is moved into
+ * drivers/.
+ */
+static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
+				   struct omap_hwmod_rst_info *ohri)
+
+{
+	return am33xx_prm_assert_hardreset(ohri->rst_shift,
+				oh->clkdm->pwrdm.ptr->prcm_offs,
+				oh->prcm.omap4.rstctrl_offs);
+}
+
+/**
+ * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args
+ * @oh: struct omap_hwmod * to deassert hardreset
+ * @ohri: hardreset line data
+ *
+ * Call am33xx_prminst_deassert_hardreset() with parameters extracted
+ * from the hwmod @oh and the hardreset line data @ohri.  Only
+ * intended for use as an soc_ops function pointer.  Passes along the
+ * return value from am33xx_prminst_deassert_hardreset().  XXX This
+ * function is scheduled for removal when the PRM code is moved into
+ * drivers/.
+ */
+static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
+				     struct omap_hwmod_rst_info *ohri)
+{
+	if (ohri->st_shift)
+		pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
+		       oh->name, ohri->name);
+
+	return am33xx_prm_deassert_hardreset(ohri->rst_shift,
+				oh->clkdm->pwrdm.ptr->prcm_offs,
+				oh->prcm.omap4.rstctrl_offs,
+				oh->prcm.omap4.rstst_offs);
+}
+
+/**
+ * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args
+ * @oh: struct omap_hwmod * to test hardreset
+ * @ohri: hardreset line data
+ *
+ * Call am33xx_prminst_is_hardreset_asserted() with parameters
+ * extracted from the hwmod @oh and the hardreset line data @ohri.
+ * Only intended for use as an soc_ops function pointer.  Passes along
+ * the return value from am33xx_prminst_is_hardreset_asserted().  XXX
+ * This function is scheduled for removal when the PRM code is moved
+ * into drivers/.
+ */
+static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh,
+					struct omap_hwmod_rst_info *ohri)
+{
+	return am33xx_prm_is_hardreset_asserted(ohri->rst_shift,
+				oh->clkdm->pwrdm.ptr->prcm_offs,
+				oh->prcm.omap4.rstctrl_offs);
+}
+
 /* Public functions */
 
 u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
@@ -3705,6 +3875,14 @@
 		soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
 		soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
 		soc_ops.init_clkdm = _init_clkdm;
+	} else if (soc_is_am33xx()) {
+		soc_ops.enable_module = _am33xx_enable_module;
+		soc_ops.disable_module = _am33xx_disable_module;
+		soc_ops.wait_target_ready = _am33xx_wait_target_ready;
+		soc_ops.assert_hardreset = _am33xx_assert_hardreset;
+		soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
+		soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
+		soc_ops.init_clkdm = _init_clkdm;
 	} else {
 		WARN(1, "omap_hwmod: unknown SoC type\n");
 	}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index 4e81637..10575a1 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -12,14 +12,15 @@
  * XXX handle crossbar/shared link difference for L3?
  * XXX these should be marked initdata for multi-OMAP kernels
  */
+#include <linux/platform_data/spi-omap2-mcspi.h>
+
 #include <plat/omap_hwmod.h>
 #include <plat/dma.h>
 #include <plat/serial.h>
 #include <plat/i2c.h>
-#include <plat/mcspi.h>
 #include <plat/dmtimer.h>
-#include <plat/l3_2xxx.h>
-#include <plat/l4_2xxx.h>
+#include "l3_2xxx.h"
+#include "l4_2xxx.h"
 #include <plat/mmc.h>
 
 #include "omap_hwmod_common_data.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index ceb23c3f..60de70f 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -12,15 +12,16 @@
  * XXX handle crossbar/shared link difference for L3?
  * XXX these should be marked initdata for multi-OMAP kernels
  */
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+
 #include <plat/omap_hwmod.h>
 #include <plat/dma.h>
 #include <plat/serial.h>
 #include <plat/i2c.h>
-#include <plat/mcbsp.h>
-#include <plat/mcspi.h>
 #include <plat/dmtimer.h>
 #include <plat/mmc.h>
-#include <plat/l3_2xxx.h>
+#include "l3_2xxx.h"
 
 #include "soc.h"
 #include "omap_hwmod_common_data.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
index bea700e..8851bbb 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
@@ -13,7 +13,7 @@
 #include <plat/serial.h>
 #include <plat/dma.h>
 #include <plat/common.h>
-#include <plat/hdq1w.h>
+#include "hdq1w.h"
 
 #include "omap_hwmod_common_data.h"
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
index 5178e40..f853a0b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
@@ -15,8 +15,8 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/serial.h>
-#include <plat/l3_2xxx.h>
-#include <plat/l4_2xxx.h>
+#include "l3_2xxx.h"
+#include "l4_2xxx.h"
 
 #include "omap_hwmod_common_data.h"
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index ceb3052..feeb401 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -13,7 +13,7 @@
 #include <linux/platform_data/gpio-omap.h>
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include "omap_hwmod_common_data.h"
 #include "cm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
new file mode 100644
index 0000000..59d5c1c
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -0,0 +1,3381 @@
+/*
+ * omap_hwmod_33xx_data.c: Hardware modules present on the AM33XX chips
+ *
+ * Copyright (C) {2012} Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is automatically generated from the AM33XX hardware databases.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <plat/omap_hwmod.h>
+#include <plat/cpu.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <plat/dma.h>
+#include <plat/mmc.h>
+#include <plat/i2c.h>
+
+#include "omap_hwmod_common_data.h"
+
+#include "control.h"
+#include "cm33xx.h"
+#include "prm33xx.h"
+#include "prm-regbits-33xx.h"
+
+/*
+ * IP blocks
+ */
+
+/*
+ * 'emif_fw' class
+ * instance(s): emif_fw
+ */
+static struct omap_hwmod_class am33xx_emif_fw_hwmod_class = {
+	.name		= "emif_fw",
+};
+
+/* emif_fw */
+static struct omap_hwmod am33xx_emif_fw_hwmod = {
+	.name		= "emif_fw",
+	.class		= &am33xx_emif_fw_hwmod_class,
+	.clkdm_name	= "l4fw_clkdm",
+	.main_clk	= "l4fw_gclk",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EMIF_FW_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'emif' class
+ * instance(s): emif
+ */
+static struct omap_hwmod_class_sysconfig am33xx_emif_sysc = {
+	.rev_offs	= 0x0000,
+};
+
+static struct omap_hwmod_class am33xx_emif_hwmod_class = {
+	.name		= "emif",
+	.sysc		= &am33xx_emif_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_emif_irqs[] = {
+	{ .name = "ddrerr0", .irq = 101 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+/* emif */
+static struct omap_hwmod am33xx_emif_hwmod = {
+	.name		= "emif",
+	.class		= &am33xx_emif_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= am33xx_emif_irqs,
+	.main_clk	= "dpll_ddr_m2_div2_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'l3' class
+ * instance(s): l3_main, l3_s, l3_instr
+ */
+static struct omap_hwmod_class am33xx_l3_hwmod_class = {
+	.name		= "l3",
+};
+
+/* l3_main (l3_fast) */
+static struct omap_hwmod_irq_info am33xx_l3_main_irqs[] = {
+	{ .name = "l3debug", .irq = 9 + OMAP_INTC_START, },
+	{ .name = "l3appint", .irq = 10 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_l3_main_hwmod = {
+	.name		= "l3_main",
+	.class		= &am33xx_l3_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= am33xx_l3_main_irqs,
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_L3_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* l3_s */
+static struct omap_hwmod am33xx_l3_s_hwmod = {
+	.name		= "l3_s",
+	.class		= &am33xx_l3_hwmod_class,
+	.clkdm_name	= "l3s_clkdm",
+};
+
+/* l3_instr */
+static struct omap_hwmod am33xx_l3_instr_hwmod = {
+	.name		= "l3_instr",
+	.class		= &am33xx_l3_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_L3_INSTR_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_ls, l4_hs, l4_wkup, l4_fw
+ */
+static struct omap_hwmod_class am33xx_l4_hwmod_class = {
+	.name		= "l4",
+};
+
+/* l4_ls */
+static struct omap_hwmod am33xx_l4_ls_hwmod = {
+	.name		= "l4_ls",
+	.class		= &am33xx_l4_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_L4LS_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* l4_hs */
+static struct omap_hwmod am33xx_l4_hs_hwmod = {
+	.name		= "l4_hs",
+	.class		= &am33xx_l4_hwmod_class,
+	.clkdm_name	= "l4hs_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.main_clk	= "l4hs_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_L4HS_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+
+/* l4_wkup */
+static struct omap_hwmod am33xx_l4_wkup_hwmod = {
+	.name		= "l4_wkup",
+	.class		= &am33xx_l4_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_L4WKUP_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* l4_fw */
+static struct omap_hwmod am33xx_l4_fw_hwmod = {
+	.name		= "l4_fw",
+	.class		= &am33xx_l4_hwmod_class,
+	.clkdm_name	= "l4fw_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_L4FW_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mpu' class
+ */
+static struct omap_hwmod_class am33xx_mpu_hwmod_class = {
+	.name	= "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod_irq_info am33xx_mpu_irqs[] = {
+	{ .name = "emuint", .irq = 0 + OMAP_INTC_START, },
+	{ .name = "commtx", .irq = 1 + OMAP_INTC_START, },
+	{ .name = "commrx", .irq = 2 + OMAP_INTC_START, },
+	{ .name = "bench", .irq = 3 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_mpu_hwmod = {
+	.name		= "mpu",
+	.class		= &am33xx_mpu_hwmod_class,
+	.clkdm_name	= "mpu_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= am33xx_mpu_irqs,
+	.main_clk	= "dpll_mpu_m2_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_MPU_MPU_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'wakeup m3' class
+ * Wakeup controller sub-system under wakeup domain
+ */
+static struct omap_hwmod_class am33xx_wkup_m3_hwmod_class = {
+	.name		= "wkup_m3",
+};
+
+static struct omap_hwmod_rst_info am33xx_wkup_m3_resets[] = {
+	{ .name = "wkup_m3", .rst_shift = 3, .st_shift = 5 },
+};
+
+static struct omap_hwmod_irq_info am33xx_wkup_m3_irqs[] = {
+	{ .name = "txev", .irq = 78 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+/* wkup_m3  */
+static struct omap_hwmod am33xx_wkup_m3_hwmod = {
+	.name		= "wkup_m3",
+	.class		= &am33xx_wkup_m3_hwmod_class,
+	.clkdm_name	= "l4_wkup_aon_clkdm",
+	.flags		= HWMOD_INIT_NO_RESET,	/* Keep hardreset asserted */
+	.mpu_irqs	= am33xx_wkup_m3_irqs,
+	.main_clk	= "dpll_core_m4_div2_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_WKUP_M3_CLKCTRL_OFFSET,
+			.rstctrl_offs	= AM33XX_RM_WKUP_RSTCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.rst_lines	= am33xx_wkup_m3_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(am33xx_wkup_m3_resets),
+};
+
+/*
+ * 'pru-icss' class
+ * Programmable Real-Time Unit and Industrial Communication Subsystem
+ */
+static struct omap_hwmod_class am33xx_pruss_hwmod_class = {
+	.name	= "pruss",
+};
+
+static struct omap_hwmod_rst_info am33xx_pruss_resets[] = {
+	{ .name = "pruss", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_irq_info am33xx_pruss_irqs[] = {
+	{ .name = "evtout0", .irq = 20 + OMAP_INTC_START, },
+	{ .name = "evtout1", .irq = 21 + OMAP_INTC_START, },
+	{ .name = "evtout2", .irq = 22 + OMAP_INTC_START, },
+	{ .name = "evtout3", .irq = 23 + OMAP_INTC_START, },
+	{ .name = "evtout4", .irq = 24 + OMAP_INTC_START, },
+	{ .name = "evtout5", .irq = 25 + OMAP_INTC_START, },
+	{ .name = "evtout6", .irq = 26 + OMAP_INTC_START, },
+	{ .name = "evtout7", .irq = 27 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+/* pru-icss */
+/* Pseudo hwmod for reset control purpose only */
+static struct omap_hwmod am33xx_pruss_hwmod = {
+	.name		= "pruss",
+	.class		= &am33xx_pruss_hwmod_class,
+	.clkdm_name	= "pruss_ocp_clkdm",
+	.mpu_irqs	= am33xx_pruss_irqs,
+	.main_clk	= "pruss_ocp_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_PRUSS_CLKCTRL_OFFSET,
+			.rstctrl_offs	= AM33XX_RM_PER_RSTCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.rst_lines	= am33xx_pruss_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(am33xx_pruss_resets),
+};
+
+/* gfx */
+/* Pseudo hwmod for reset control purpose only */
+static struct omap_hwmod_class am33xx_gfx_hwmod_class = {
+	.name	= "gfx",
+};
+
+static struct omap_hwmod_rst_info am33xx_gfx_resets[] = {
+	{ .name = "gfx", .rst_shift = 0 },
+};
+
+static struct omap_hwmod_irq_info am33xx_gfx_irqs[] = {
+	{ .name = "gfxint", .irq = 37 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_gfx_hwmod = {
+	.name		= "gfx",
+	.class		= &am33xx_gfx_hwmod_class,
+	.clkdm_name	= "gfx_l3_clkdm",
+	.mpu_irqs	= am33xx_gfx_irqs,
+	.main_clk	= "gfx_fck_div_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_GFX_GFX_CLKCTRL_OFFSET,
+			.rstctrl_offs	= AM33XX_RM_GFX_RSTCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.rst_lines	= am33xx_gfx_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(am33xx_gfx_resets),
+};
+
+/*
+ * 'prcm' class
+ * power and reset manager (whole prcm infrastructure)
+ */
+static struct omap_hwmod_class am33xx_prcm_hwmod_class = {
+	.name	= "prcm",
+};
+
+/* prcm */
+static struct omap_hwmod am33xx_prcm_hwmod = {
+	.name		= "prcm",
+	.class		= &am33xx_prcm_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/*
+ * 'adc/tsc' class
+ * TouchScreen Controller (Anolog-To-Digital Converter)
+ */
+static struct omap_hwmod_class_sysconfig am33xx_adc_tsc_sysc = {
+	.rev_offs	= 0x00,
+	.sysc_offs	= 0x10,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_adc_tsc_hwmod_class = {
+	.name		= "adc_tsc",
+	.sysc		= &am33xx_adc_tsc_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_adc_tsc_irqs[] = {
+	{ .irq = 16 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_adc_tsc_hwmod = {
+	.name		= "adc_tsc",
+	.class		= &am33xx_adc_tsc_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= am33xx_adc_tsc_irqs,
+	.main_clk	= "adc_tsc_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_ADC_TSC_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * Modules omap_hwmod structures
+ *
+ * The following IPs are excluded for the moment because:
+ * - They do not need an explicit SW control using omap_hwmod API.
+ * - They still need to be validated with the driver
+ *   properly adapted to omap_hwmod / omap_device
+ *
+ *    - cEFUSE (doesn't fall under any ocp_if)
+ *    - clkdiv32k
+ *    - debugss
+ *    - ocmc ram
+ *    - ocp watch point
+ *    - aes0
+ *    - sha0
+ */
+#if 0
+/*
+ * 'cefuse' class
+ */
+static struct omap_hwmod_class am33xx_cefuse_hwmod_class = {
+	.name		= "cefuse",
+};
+
+static struct omap_hwmod am33xx_cefuse_hwmod = {
+	.name		= "cefuse",
+	.class		= &am33xx_cefuse_hwmod_class,
+	.clkdm_name	= "l4_cefuse_clkdm",
+	.main_clk	= "cefuse_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'clkdiv32k' class
+ */
+static struct omap_hwmod_class am33xx_clkdiv32k_hwmod_class = {
+	.name		= "clkdiv32k",
+};
+
+static struct omap_hwmod am33xx_clkdiv32k_hwmod = {
+	.name		= "clkdiv32k",
+	.class		= &am33xx_clkdiv32k_hwmod_class,
+	.clkdm_name	= "clk_24mhz_clkdm",
+	.main_clk	= "clkdiv32k_ick",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_CLKDIV32K_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'debugss' class
+ * debug sub system
+ */
+static struct omap_hwmod_class am33xx_debugss_hwmod_class = {
+	.name		= "debugss",
+};
+
+static struct omap_hwmod am33xx_debugss_hwmod = {
+	.name		= "debugss",
+	.class		= &am33xx_debugss_hwmod_class,
+	.clkdm_name	= "l3_aon_clkdm",
+	.main_clk	= "debugss_ick",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_DEBUGSS_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ocmcram */
+static struct omap_hwmod_class am33xx_ocmcram_hwmod_class = {
+	.name = "ocmcram",
+};
+
+static struct omap_hwmod am33xx_ocmcram_hwmod = {
+	.name		= "ocmcram",
+	.class		= &am33xx_ocmcram_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_OCMCRAM_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ocpwp */
+static struct omap_hwmod_class am33xx_ocpwp_hwmod_class = {
+	.name		= "ocpwp",
+};
+
+static struct omap_hwmod am33xx_ocpwp_hwmod = {
+	.name		= "ocpwp",
+	.class		= &am33xx_ocpwp_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_OCPWP_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'aes' class
+ */
+static struct omap_hwmod_class am33xx_aes_hwmod_class = {
+	.name		= "aes",
+};
+
+static struct omap_hwmod_irq_info am33xx_aes0_irqs[] = {
+	{ .irq = 102 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_aes0_hwmod = {
+	.name		= "aes0",
+	.class		= &am33xx_aes_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_aes0_irqs,
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_AES0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* sha0 */
+static struct omap_hwmod_class am33xx_sha0_hwmod_class = {
+	.name		= "sha0",
+};
+
+static struct omap_hwmod_irq_info am33xx_sha0_irqs[] = {
+	{ .irq = 108 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_sha0_hwmod = {
+	.name		= "sha0",
+	.class		= &am33xx_sha0_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_sha0_irqs,
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_SHA0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+#endif
+
+/* 'smartreflex' class */
+static struct omap_hwmod_class am33xx_smartreflex_hwmod_class = {
+	.name		= "smartreflex",
+};
+
+/* smartreflex0 */
+static struct omap_hwmod_irq_info am33xx_smartreflex0_irqs[] = {
+	{ .irq = 120 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_smartreflex0_hwmod = {
+	.name		= "smartreflex0",
+	.class		= &am33xx_smartreflex_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= am33xx_smartreflex0_irqs,
+	.main_clk	= "smartreflex0_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_SMARTREFLEX0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* smartreflex1 */
+static struct omap_hwmod_irq_info am33xx_smartreflex1_irqs[] = {
+	{ .irq = 121 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_smartreflex1_hwmod = {
+	.name		= "smartreflex1",
+	.class		= &am33xx_smartreflex_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= am33xx_smartreflex1_irqs,
+	.main_clk	= "smartreflex1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_SMARTREFLEX1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'control' module class
+ */
+static struct omap_hwmod_class am33xx_control_hwmod_class = {
+	.name		= "control",
+};
+
+static struct omap_hwmod_irq_info am33xx_control_irqs[] = {
+	{ .irq = 8 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_control_hwmod = {
+	.name		= "control",
+	.class		= &am33xx_control_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= am33xx_control_irqs,
+	.main_clk	= "dpll_core_m4_div2_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_CONTROL_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'cpgmac' class
+ * cpsw/cpgmac sub system
+ */
+static struct omap_hwmod_class_sysconfig am33xx_cpgmac_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x8,
+	.syss_offs	= 0x4,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
+			   SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | MSTANDBY_FORCE |
+			   MSTANDBY_NO),
+	.sysc_fields	= &omap_hwmod_sysc_type3,
+};
+
+static struct omap_hwmod_class am33xx_cpgmac0_hwmod_class = {
+	.name		= "cpgmac0",
+	.sysc		= &am33xx_cpgmac_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_cpgmac0_irqs[] = {
+	{ .name = "c0_rx_thresh_pend", .irq = 40 + OMAP_INTC_START, },
+	{ .name = "c0_rx_pend", .irq = 41 + OMAP_INTC_START, },
+	{ .name = "c0_tx_pend", .irq = 42 + OMAP_INTC_START, },
+	{ .name = "c0_misc_pend", .irq = 43 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_cpgmac0_hwmod = {
+	.name		= "cpgmac0",
+	.class		= &am33xx_cpgmac0_hwmod_class,
+	.clkdm_name	= "cpsw_125mhz_clkdm",
+	.mpu_irqs	= am33xx_cpgmac0_irqs,
+	.main_clk	= "cpsw_125mhz_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_CPGMAC0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * dcan class
+ */
+static struct omap_hwmod_class am33xx_dcan_hwmod_class = {
+	.name = "d_can",
+};
+
+/* dcan0 */
+static struct omap_hwmod_irq_info am33xx_dcan0_irqs[] = {
+	{ .name = "d_can_ms", .irq = 52 + OMAP_INTC_START, },
+	{ .name = "d_can_mo", .irq = 53 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_dcan0_hwmod = {
+	.name		= "d_can0",
+	.class		= &am33xx_dcan_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_dcan0_irqs,
+	.main_clk	= "dcan0_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_DCAN0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* dcan1 */
+static struct omap_hwmod_irq_info am33xx_dcan1_irqs[] = {
+	{ .name = "d_can_ms", .irq = 55 + OMAP_INTC_START, },
+	{ .name = "d_can_mo", .irq = 56 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+static struct omap_hwmod am33xx_dcan1_hwmod = {
+	.name		= "d_can1",
+	.class		= &am33xx_dcan_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_dcan1_irqs,
+	.main_clk	= "dcan1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_DCAN1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* elm */
+static struct omap_hwmod_class_sysconfig am33xx_elm_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_elm_hwmod_class = {
+	.name		= "elm",
+	.sysc		= &am33xx_elm_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_elm_irqs[] = {
+	{ .irq = 4 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_elm_hwmod = {
+	.name		= "elm",
+	.class		= &am33xx_elm_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_elm_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_ELM_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'epwmss' class: ecap0,1,2,  ehrpwm0,1,2
+ */
+static struct omap_hwmod_class_sysconfig am33xx_epwmss_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x4,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+			MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_epwmss_hwmod_class = {
+	.name		= "epwmss",
+	.sysc		= &am33xx_epwmss_sysc,
+};
+
+/* ehrpwm0 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm0_irqs[] = {
+	{ .name = "int", .irq = 86 + OMAP_INTC_START, },
+	{ .name = "tzint", .irq = 58 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
+	.name		= "ehrpwm0",
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_ehrpwm0_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ehrpwm1 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm1_irqs[] = {
+	{ .name = "int", .irq = 87 + OMAP_INTC_START, },
+	{ .name = "tzint", .irq = 59 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ehrpwm1_hwmod = {
+	.name		= "ehrpwm1",
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_ehrpwm1_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ehrpwm2 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm2_irqs[] = {
+	{ .name = "int", .irq = 39 + OMAP_INTC_START, },
+	{ .name = "tzint", .irq = 60 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ehrpwm2_hwmod = {
+	.name		= "ehrpwm2",
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_ehrpwm2_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ecap0 */
+static struct omap_hwmod_irq_info am33xx_ecap0_irqs[] = {
+	{ .irq = 31 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ecap0_hwmod = {
+	.name		= "ecap0",
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_ecap0_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ecap1 */
+static struct omap_hwmod_irq_info am33xx_ecap1_irqs[] = {
+	{ .irq = 47 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ecap1_hwmod = {
+	.name		= "ecap1",
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_ecap1_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* ecap2 */
+static struct omap_hwmod_irq_info am33xx_ecap2_irqs[] = {
+	{ .irq = 61 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_ecap2_hwmod = {
+	.name		= "ecap2",
+	.mpu_irqs	= am33xx_ecap2_irqs,
+	.class		= &am33xx_epwmss_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'gpio' class: for gpio 0,1,2,3
+ */
+static struct omap_hwmod_class_sysconfig am33xx_gpio_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0114,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+			  SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			  SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_gpio_hwmod_class = {
+	.name		= "gpio",
+	.sysc		= &am33xx_gpio_sysc,
+	.rev		= 2,
+};
+
+static struct omap_gpio_dev_attr gpio_dev_attr = {
+	.bank_width	= 32,
+	.dbck_flag	= true,
+};
+
+/* gpio0 */
+static struct omap_hwmod_opt_clk gpio0_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio0_dbclk" },
+};
+
+static struct omap_hwmod_irq_info am33xx_gpio0_irqs[] = {
+	{ .irq = 96 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_gpio0_hwmod = {
+	.name		= "gpio1",
+	.class		= &am33xx_gpio_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= am33xx_gpio0_irqs,
+	.main_clk	= "dpll_core_m4_div2_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_GPIO0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= gpio0_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio0_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio1 */
+static struct omap_hwmod_irq_info am33xx_gpio1_irqs[] = {
+	{ .irq = 98 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio1_dbclk" },
+};
+
+static struct omap_hwmod am33xx_gpio1_hwmod = {
+	.name		= "gpio2",
+	.class		= &am33xx_gpio_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= am33xx_gpio1_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_GPIO1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= gpio1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio2 */
+static struct omap_hwmod_irq_info am33xx_gpio2_irqs[] = {
+	{ .irq = 32 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio2_dbclk" },
+};
+
+static struct omap_hwmod am33xx_gpio2_hwmod = {
+	.name		= "gpio3",
+	.class		= &am33xx_gpio_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= am33xx_gpio2_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_GPIO2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= gpio2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpio3 */
+static struct omap_hwmod_irq_info am33xx_gpio3_irqs[] = {
+	{ .irq = 62 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
+	{ .role = "dbclk", .clk = "gpio3_dbclk" },
+};
+
+static struct omap_hwmod am33xx_gpio3_hwmod = {
+	.name		= "gpio4",
+	.class		= &am33xx_gpio_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.flags		= HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+	.mpu_irqs	= am33xx_gpio3_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_GPIO3_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.opt_clks	= gpio3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
+	.dev_attr	= &gpio_dev_attr,
+};
+
+/* gpmc */
+static struct omap_hwmod_class_sysconfig gpmc_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x14,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+			SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_gpmc_hwmod_class = {
+	.name		= "gpmc",
+	.sysc		= &gpmc_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_gpmc_irqs[] = {
+	{ .irq = 100 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_gpmc_hwmod = {
+	.name		= "gpmc",
+	.class		= &am33xx_gpmc_hwmod_class,
+	.clkdm_name	= "l3s_clkdm",
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= am33xx_gpmc_irqs,
+	.main_clk	= "l3s_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_GPMC_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'i2c' class */
+static struct omap_hwmod_class_sysconfig am33xx_i2c_sysc = {
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0090,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+			  SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			  SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class i2c_class = {
+	.name		= "i2c",
+	.sysc		= &am33xx_i2c_sysc,
+	.rev		= OMAP_I2C_IP_VERSION_2,
+	.reset		= &omap_i2c_reset,
+};
+
+static struct omap_i2c_dev_attr i2c_dev_attr = {
+	.flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE |
+		  OMAP_I2C_FLAG_RESET_REGS_POSTIDLE,
+};
+
+/* i2c1 */
+static struct omap_hwmod_irq_info i2c1_mpu_irqs[] = {
+	{ .irq = 70 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info i2c1_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 0, },
+	{ .name = "rx", .dma_req = 0, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod am33xx_i2c1_hwmod = {
+	.name		= "i2c1",
+	.class		= &i2c_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= i2c1_mpu_irqs,
+	.sdma_reqs	= i2c1_edma_reqs,
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.main_clk	= "dpll_per_m2_div4_wkupdm_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_I2C0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/* i2c1 */
+static struct omap_hwmod_irq_info i2c2_mpu_irqs[] = {
+	{ .irq = 71 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info i2c2_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 0, },
+	{ .name = "rx", .dma_req = 0, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod am33xx_i2c2_hwmod = {
+	.name		= "i2c2",
+	.class		= &i2c_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= i2c2_mpu_irqs,
+	.sdma_reqs	= i2c2_edma_reqs,
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs	= AM33XX_CM_PER_I2C1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+/* i2c3 */
+static struct omap_hwmod_dma_info i2c3_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 0, },
+	{ .name = "rx", .dma_req = 0, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = {
+	{ .irq = 30 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_i2c3_hwmod = {
+	.name		= "i2c3",
+	.class		= &i2c_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= i2c3_mpu_irqs,
+	.sdma_reqs	= i2c3_edma_reqs,
+	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_I2C2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &i2c_dev_attr,
+};
+
+
+/* lcdc */
+static struct omap_hwmod_class_sysconfig lcdc_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x54,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_lcdc_hwmod_class = {
+	.name		= "lcdc",
+	.sysc		= &lcdc_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_lcdc_irqs[] = {
+	{ .irq = 36 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_lcdc_hwmod = {
+	.name		= "lcdc",
+	.class		= &am33xx_lcdc_hwmod_class,
+	.clkdm_name	= "lcdc_clkdm",
+	.mpu_irqs	= am33xx_lcdc_irqs,
+	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+	.main_clk	= "lcd_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_LCDC_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors using a
+ * queued mailbox-interrupt mechanism.
+ */
+static struct omap_hwmod_class_sysconfig am33xx_mailbox_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.sysc_flags	= (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+			  SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_mailbox_hwmod_class = {
+	.name	= "mailbox",
+	.sysc	= &am33xx_mailbox_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_mailbox_irqs[] = {
+	{ .irq = 77 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_mailbox_hwmod = {
+	.name		= "mailbox",
+	.class		= &am33xx_mailbox_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_mailbox_irqs,
+	.main_clk	= "l4ls_gclk",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs	= AM33XX_CM_PER_MAILBOX0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'mcasp' class
+ */
+static struct omap_hwmod_class_sysconfig am33xx_mcasp_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x4,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type3,
+};
+
+static struct omap_hwmod_class am33xx_mcasp_hwmod_class = {
+	.name		= "mcasp",
+	.sysc		= &am33xx_mcasp_sysc,
+};
+
+/* mcasp0 */
+static struct omap_hwmod_irq_info am33xx_mcasp0_irqs[] = {
+	{ .name = "ax", .irq = 80 + OMAP_INTC_START, },
+	{ .name = "ar", .irq = 81 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mcasp0_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 8, },
+	{ .name = "rx", .dma_req = 9, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod am33xx_mcasp0_hwmod = {
+	.name		= "mcasp0",
+	.class		= &am33xx_mcasp_hwmod_class,
+	.clkdm_name	= "l3s_clkdm",
+	.mpu_irqs	= am33xx_mcasp0_irqs,
+	.sdma_reqs	= am33xx_mcasp0_edma_reqs,
+	.main_clk	= "mcasp0_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_MCASP0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* mcasp1 */
+static struct omap_hwmod_irq_info am33xx_mcasp1_irqs[] = {
+	{ .name = "ax", .irq = 82 + OMAP_INTC_START, },
+	{ .name = "ar", .irq = 83 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mcasp1_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 10, },
+	{ .name = "rx", .dma_req = 11, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod am33xx_mcasp1_hwmod = {
+	.name		= "mcasp1",
+	.class		= &am33xx_mcasp_hwmod_class,
+	.clkdm_name	= "l3s_clkdm",
+	.mpu_irqs	= am33xx_mcasp1_irqs,
+	.sdma_reqs	= am33xx_mcasp1_edma_reqs,
+	.main_clk	= "mcasp1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_MCASP1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'mmc' class */
+static struct omap_hwmod_class_sysconfig am33xx_mmc_sysc = {
+	.rev_offs	= 0x1fc,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x14,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			  SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			  SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_mmc_hwmod_class = {
+	.name		= "mmc",
+	.sysc		= &am33xx_mmc_sysc,
+};
+
+/* mmc0 */
+static struct omap_hwmod_irq_info am33xx_mmc0_irqs[] = {
+	{ .irq = 64 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mmc0_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 24, },
+	{ .name = "rx", .dma_req = 25, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_mmc_dev_attr am33xx_mmc0_dev_attr = {
+	.flags		= OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod am33xx_mmc0_hwmod = {
+	.name		= "mmc1",
+	.class		= &am33xx_mmc_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_mmc0_irqs,
+	.sdma_reqs	= am33xx_mmc0_edma_reqs,
+	.main_clk	= "mmc_clk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_MMC0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &am33xx_mmc0_dev_attr,
+};
+
+/* mmc1 */
+static struct omap_hwmod_irq_info am33xx_mmc1_irqs[] = {
+	{ .irq = 28 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mmc1_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 2, },
+	{ .name = "rx", .dma_req = 3, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_mmc_dev_attr am33xx_mmc1_dev_attr = {
+	.flags		= OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod am33xx_mmc1_hwmod = {
+	.name		= "mmc2",
+	.class		= &am33xx_mmc_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_mmc1_irqs,
+	.sdma_reqs	= am33xx_mmc1_edma_reqs,
+	.main_clk	= "mmc_clk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_MMC1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &am33xx_mmc1_dev_attr,
+};
+
+/* mmc2 */
+static struct omap_hwmod_irq_info am33xx_mmc2_irqs[] = {
+	{ .irq = 29 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mmc2_edma_reqs[] = {
+	{ .name = "tx", .dma_req = 64, },
+	{ .name = "rx", .dma_req = 65, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_mmc_dev_attr am33xx_mmc2_dev_attr = {
+	.flags		= OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+static struct omap_hwmod am33xx_mmc2_hwmod = {
+	.name		= "mmc3",
+	.class		= &am33xx_mmc_hwmod_class,
+	.clkdm_name	= "l3s_clkdm",
+	.mpu_irqs	= am33xx_mmc2_irqs,
+	.sdma_reqs	= am33xx_mmc2_edma_reqs,
+	.main_clk	= "mmc_clk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_MMC2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &am33xx_mmc2_dev_attr,
+};
+
+/*
+ * 'rtc' class
+ * rtc subsystem
+ */
+static struct omap_hwmod_class_sysconfig am33xx_rtc_sysc = {
+	.rev_offs	= 0x0074,
+	.sysc_offs	= 0x0078,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO |
+			  SIDLE_SMART | SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type3,
+};
+
+static struct omap_hwmod_class am33xx_rtc_hwmod_class = {
+	.name		= "rtc",
+	.sysc		= &am33xx_rtc_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_rtc_irqs[] = {
+	{ .name = "rtcint", .irq = 75 + OMAP_INTC_START, },
+	{ .name = "rtcalarmint", .irq = 76 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_rtc_hwmod = {
+	.name		= "rtc",
+	.class		= &am33xx_rtc_hwmod_class,
+	.clkdm_name	= "l4_rtc_clkdm",
+	.mpu_irqs	= am33xx_rtc_irqs,
+	.main_clk	= "clk_32768_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_RTC_RTC_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'spi' class */
+static struct omap_hwmod_class_sysconfig am33xx_mcspi_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0110,
+	.syss_offs	= 0x0114,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			  SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			  SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_spi_hwmod_class = {
+	.name		= "mcspi",
+	.sysc		= &am33xx_mcspi_sysc,
+	.rev		= OMAP4_MCSPI_REV,
+};
+
+/* spi0 */
+static struct omap_hwmod_irq_info am33xx_spi0_irqs[] = {
+	{ .irq = 65 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mcspi0_edma_reqs[] = {
+	{ .name = "rx0", .dma_req = 17 },
+	{ .name = "tx0", .dma_req = 16 },
+	{ .name = "rx1", .dma_req = 19 },
+	{ .name = "tx1", .dma_req = 18 },
+	{ .dma_req = -1 }
+};
+
+static struct omap2_mcspi_dev_attr mcspi_attrib = {
+	.num_chipselect	= 2,
+};
+static struct omap_hwmod am33xx_spi0_hwmod = {
+	.name		= "spi0",
+	.class		= &am33xx_spi_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_spi0_irqs,
+	.sdma_reqs	= am33xx_mcspi0_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_SPI0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi_attrib,
+};
+
+/* spi1 */
+static struct omap_hwmod_irq_info am33xx_spi1_irqs[] = {
+	{ .irq = 125 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod_dma_info am33xx_mcspi1_edma_reqs[] = {
+	{ .name = "rx0", .dma_req = 43 },
+	{ .name = "tx0", .dma_req = 42 },
+	{ .name = "rx1", .dma_req = 45 },
+	{ .name = "tx1", .dma_req = 44 },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod am33xx_spi1_hwmod = {
+	.name		= "spi1",
+	.class		= &am33xx_spi_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_spi1_irqs,
+	.sdma_reqs	= am33xx_mcspi1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_SPI1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mcspi_attrib,
+};
+
+/*
+ * 'spinlock' class
+ * spinlock provides hardware assistance for synchronizing the
+ * processes running on multiple processors
+ */
+static struct omap_hwmod_class am33xx_spinlock_hwmod_class = {
+	.name		= "spinlock",
+};
+
+static struct omap_hwmod am33xx_spinlock_hwmod = {
+	.name		= "spinlock",
+	.class		= &am33xx_spinlock_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.main_clk	= "l4ls_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_SPINLOCK_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'timer 2-7' class */
+static struct omap_hwmod_class_sysconfig am33xx_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_timer_hwmod_class = {
+	.name		= "timer",
+	.sysc		= &am33xx_timer_sysc,
+};
+
+/* timer1 1ms */
+static struct omap_hwmod_class_sysconfig am33xx_timer1ms_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+			SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+			SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am33xx_timer1ms_hwmod_class = {
+	.name		= "timer",
+	.sysc		= &am33xx_timer1ms_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_timer1_irqs[] = {
+	{ .irq = 67 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer1_hwmod = {
+	.name		= "timer1",
+	.class		= &am33xx_timer1ms_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= am33xx_timer1_irqs,
+	.main_clk	= "timer1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_TIMER1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer2_irqs[] = {
+	{ .irq = 68 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer2_hwmod = {
+	.name		= "timer2",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer2_irqs,
+	.main_clk	= "timer2_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer3_irqs[] = {
+	{ .irq = 69 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer3_hwmod = {
+	.name		= "timer3",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer3_irqs,
+	.main_clk	= "timer3_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER3_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer4_irqs[] = {
+	{ .irq = 92 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer4_hwmod = {
+	.name		= "timer4",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer4_irqs,
+	.main_clk	= "timer4_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER4_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer5_irqs[] = {
+	{ .irq = 93 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer5_hwmod = {
+	.name		= "timer5",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer5_irqs,
+	.main_clk	= "timer5_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER5_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer6_irqs[] = {
+	{ .irq = 94 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer6_hwmod = {
+	.name		= "timer6",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer6_irqs,
+	.main_clk	= "timer6_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER6_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_timer7_irqs[] = {
+	{ .irq = 95 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_timer7_hwmod = {
+	.name		= "timer7",
+	.class		= &am33xx_timer_hwmod_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_timer7_irqs,
+	.main_clk	= "timer7_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TIMER7_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* tpcc */
+static struct omap_hwmod_class am33xx_tpcc_hwmod_class = {
+	.name		= "tpcc",
+};
+
+static struct omap_hwmod_irq_info am33xx_tpcc_irqs[] = {
+	{ .name	= "edma0", .irq = 12 + OMAP_INTC_START, },
+	{ .name = "edma0_mperr", .irq = 13 + OMAP_INTC_START, },
+	{ .name	= "edma0_err", .irq = 14 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_tpcc_hwmod = {
+	.name		= "tpcc",
+	.class		= &am33xx_tpcc_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_tpcc_irqs,
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TPCC_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_class_sysconfig am33xx_tptc_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+			  SYSC_HAS_MIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_SMART | MSTANDBY_FORCE),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+/* 'tptc' class */
+static struct omap_hwmod_class am33xx_tptc_hwmod_class = {
+	.name		= "tptc",
+	.sysc		= &am33xx_tptc_sysc,
+};
+
+/* tptc0 */
+static struct omap_hwmod_irq_info am33xx_tptc0_irqs[] = {
+	{ .irq = 112 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_tptc0_hwmod = {
+	.name		= "tptc0",
+	.class		= &am33xx_tptc_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_tptc0_irqs,
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TPTC0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* tptc1 */
+static struct omap_hwmod_irq_info am33xx_tptc1_irqs[] = {
+	{ .irq = 113 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_tptc1_hwmod = {
+	.name		= "tptc1",
+	.class		= &am33xx_tptc_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_tptc1_irqs,
+	.flags		= (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TPTC1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* tptc2 */
+static struct omap_hwmod_irq_info am33xx_tptc2_irqs[] = {
+	{ .irq = 114 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_tptc2_hwmod = {
+	.name		= "tptc2",
+	.class		= &am33xx_tptc_hwmod_class,
+	.clkdm_name	= "l3_clkdm",
+	.mpu_irqs	= am33xx_tptc2_irqs,
+	.flags		= (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
+	.main_clk	= "l3_gclk",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_TPTC2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'uart' class */
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+			  SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  SIDLE_SMART_WKUP),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name		= "uart",
+	.sysc		= &uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod_dma_info uart1_edma_reqs[] = {
+	{ .name = "tx",	.dma_req = 26, },
+	{ .name = "rx",	.dma_req = 27, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_irq_info am33xx_uart1_irqs[] = {
+	{ .irq = 72 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart1_hwmod = {
+	.name		= "uart1",
+	.class		= &uart_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.mpu_irqs	= am33xx_uart1_irqs,
+	.sdma_reqs	= uart1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_wkupdm_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_UART0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_uart2_irqs[] = {
+	{ .irq = 73 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart2_hwmod = {
+	.name		= "uart2",
+	.class		= &uart_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_uart2_irqs,
+	.sdma_reqs	= uart1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_UART1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* uart3 */
+static struct omap_hwmod_dma_info uart3_edma_reqs[] = {
+	{ .name = "tx",	.dma_req = 30, },
+	{ .name = "rx",	.dma_req = 31, },
+	{ .dma_req = -1 }
+};
+
+static struct omap_hwmod_irq_info am33xx_uart3_irqs[] = {
+	{ .irq = 74 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart3_hwmod = {
+	.name		= "uart3",
+	.class		= &uart_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_uart3_irqs,
+	.sdma_reqs	= uart3_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_UART2_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_uart4_irqs[] = {
+	{ .irq = 44 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart4_hwmod = {
+	.name		= "uart4",
+	.class		= &uart_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_uart4_irqs,
+	.sdma_reqs	= uart1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_UART3_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_uart5_irqs[] = {
+	{ .irq = 45 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart5_hwmod = {
+	.name		= "uart5",
+	.class		= &uart_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_uart5_irqs,
+	.sdma_reqs	= uart1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_UART4_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_irq_info am33xx_uart6_irqs[] = {
+	{ .irq = 46 + OMAP_INTC_START, },
+	{ .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_uart6_hwmod = {
+	.name		= "uart6",
+	.class		= &uart_class,
+	.clkdm_name	= "l4ls_clkdm",
+	.mpu_irqs	= am33xx_uart6_irqs,
+	.sdma_reqs	= uart1_edma_reqs,
+	.main_clk	= "dpll_per_m2_div4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_UART5_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/* 'wd_timer' class */
+static struct omap_hwmod_class am33xx_wd_timer_hwmod_class = {
+	.name		= "wd_timer",
+};
+
+/*
+ * XXX: device.c file uses hardcoded name for watchdog timer
+ * driver "wd_timer2, so we are also using same name as of now...
+ */
+static struct omap_hwmod am33xx_wd_timer1_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &am33xx_wd_timer_hwmod_class,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.main_clk	= "wdt1_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_WKUP_WDT1_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+/*
+ * 'usb_otg' class
+ * high-speed on-the-go universal serial bus (usb_otg) controller
+ */
+static struct omap_hwmod_class_sysconfig am33xx_usbhsotg_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+			  MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am33xx_usbotg_class = {
+	.name		= "usbotg",
+	.sysc		= &am33xx_usbhsotg_sysc,
+};
+
+static struct omap_hwmod_irq_info am33xx_usbss_mpu_irqs[] = {
+	{ .name = "usbss-irq", .irq = 17 + OMAP_INTC_START, },
+	{ .name = "musb0-irq", .irq = 18 + OMAP_INTC_START, },
+	{ .name = "musb1-irq", .irq = 19 + OMAP_INTC_START, },
+	{ .irq = -1 + OMAP_INTC_START, },
+};
+
+static struct omap_hwmod am33xx_usbss_hwmod = {
+	.name		= "usb_otg_hs",
+	.class		= &am33xx_usbotg_class,
+	.clkdm_name	= "l3s_clkdm",
+	.mpu_irqs	= am33xx_usbss_mpu_irqs,
+	.flags		= HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+	.main_clk	= "usbotg_fck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= AM33XX_CM_PER_USB0_CLKCTRL_OFFSET,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+
+/*
+ * Interfaces
+ */
+
+/* l4 fw -> emif fw */
+static struct omap_hwmod_ocp_if am33xx_l4_fw__emif_fw = {
+	.master		= &am33xx_l4_fw_hwmod,
+	.slave		= &am33xx_emif_fw_hwmod,
+	.clk		= "l4fw_gclk",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_emif_addrs[] = {
+	{
+		.pa_start	= 0x4c000000,
+		.pa_end		= 0x4c000fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+/* l3 main -> emif */
+static struct omap_hwmod_ocp_if am33xx_l3_main__emif = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_emif_hwmod,
+	.clk		= "dpll_core_m4_ck",
+	.addr		= am33xx_emif_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l3 main */
+static struct omap_hwmod_ocp_if am33xx_mpu__l3_main = {
+	.master		= &am33xx_mpu_hwmod,
+	.slave		= &am33xx_l3_main_hwmod,
+	.clk		= "dpll_mpu_m2_ck",
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 main -> l4 hs */
+static struct omap_hwmod_ocp_if am33xx_l3_main__l4_hs = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_l4_hs_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 main -> l3 s */
+static struct omap_hwmod_ocp_if am33xx_l3_main__l3_s = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_l3_s_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 s -> l4 per/ls */
+static struct omap_hwmod_ocp_if am33xx_l3_s__l4_ls = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_l4_ls_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 s -> l4 wkup */
+static struct omap_hwmod_ocp_if am33xx_l3_s__l4_wkup = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_l4_wkup_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 s -> l4 fw */
+static struct omap_hwmod_ocp_if am33xx_l3_s__l4_fw = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_l4_fw_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 main -> l3 instr */
+static struct omap_hwmod_ocp_if am33xx_l3_main__l3_instr = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_l3_instr_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> prcm */
+static struct omap_hwmod_ocp_if am33xx_mpu__prcm = {
+	.master		= &am33xx_mpu_hwmod,
+	.slave		= &am33xx_prcm_hwmod,
+	.clk		= "dpll_mpu_m2_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 s -> l3 main*/
+static struct omap_hwmod_ocp_if am33xx_l3_s__l3_main = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_l3_main_hwmod,
+	.clk		= "l3s_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* pru-icss -> l3 main */
+static struct omap_hwmod_ocp_if am33xx_pruss__l3_main = {
+	.master		= &am33xx_pruss_hwmod,
+	.slave		= &am33xx_l3_main_hwmod,
+	.clk		= "l3_gclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* wkup m3 -> l4 wkup */
+static struct omap_hwmod_ocp_if am33xx_wkup_m3__l4_wkup = {
+	.master		= &am33xx_wkup_m3_hwmod,
+	.slave		= &am33xx_l4_wkup_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* gfx -> l3 main */
+static struct omap_hwmod_ocp_if am33xx_gfx__l3_main = {
+	.master		= &am33xx_gfx_hwmod,
+	.slave		= &am33xx_l3_main_hwmod,
+	.clk		= "dpll_core_m4_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 wkup -> wkup m3 */
+static struct omap_hwmod_addr_space am33xx_wkup_m3_addrs[] = {
+	{
+		.name		= "umem",
+		.pa_start	= 0x44d00000,
+		.pa_end		= 0x44d00000 + SZ_16K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.name		= "dmem",
+		.pa_start	= 0x44d80000,
+		.pa_end		= 0x44d80000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__wkup_m3 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_wkup_m3_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_wkup_m3_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 hs -> pru-icss */
+static struct omap_hwmod_addr_space am33xx_pruss_addrs[] = {
+	{
+		.pa_start	= 0x4a300000,
+		.pa_end		= 0x4a300000 + SZ_512K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_hs__pruss = {
+	.master		= &am33xx_l4_hs_hwmod,
+	.slave		= &am33xx_pruss_hwmod,
+	.clk		= "dpll_core_m4_ck",
+	.addr		= am33xx_pruss_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3 main -> gfx */
+static struct omap_hwmod_addr_space am33xx_gfx_addrs[] = {
+	{
+		.pa_start	= 0x56000000,
+		.pa_end		= 0x56000000 + SZ_16M - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__gfx = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_gfx_hwmod,
+	.clk		= "dpll_core_m4_ck",
+	.addr		= am33xx_gfx_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 wkup -> smartreflex0 */
+static struct omap_hwmod_addr_space am33xx_smartreflex0_addrs[] = {
+	{
+		.pa_start	= 0x44e37000,
+		.pa_end		= 0x44e37000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__smartreflex0 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_smartreflex0_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_smartreflex0_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> smartreflex1 */
+static struct omap_hwmod_addr_space am33xx_smartreflex1_addrs[] = {
+	{
+		.pa_start	= 0x44e39000,
+		.pa_end		= 0x44e39000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__smartreflex1 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_smartreflex1_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_smartreflex1_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> control */
+static struct omap_hwmod_addr_space am33xx_control_addrs[] = {
+	{
+		.pa_start	= 0x44e10000,
+		.pa_end		= 0x44e10000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__control = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_control_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_control_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> rtc */
+static struct omap_hwmod_addr_space am33xx_rtc_addrs[] = {
+	{
+		.pa_start	= 0x44e3e000,
+		.pa_end		= 0x44e3e000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__rtc = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_rtc_hwmod,
+	.clk		= "clkdiv32k_ick",
+	.addr		= am33xx_rtc_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per/ls -> DCAN0 */
+static struct omap_hwmod_addr_space am33xx_dcan0_addrs[] = {
+	{
+		.pa_start	= 0x481CC000,
+		.pa_end		= 0x481CC000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__dcan0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_dcan0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_dcan0_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 per/ls -> DCAN1 */
+static struct omap_hwmod_addr_space am33xx_dcan1_addrs[] = {
+	{
+		.pa_start	= 0x481D0000,
+		.pa_end		= 0x481D0000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__dcan1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_dcan1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_dcan1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 per/ls -> GPIO2 */
+static struct omap_hwmod_addr_space am33xx_gpio1_addrs[] = {
+	{
+		.pa_start	= 0x4804C000,
+		.pa_end		= 0x4804C000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__gpio1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_gpio1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_gpio1_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 per/ls -> gpio3 */
+static struct omap_hwmod_addr_space am33xx_gpio2_addrs[] = {
+	{
+		.pa_start	= 0x481AC000,
+		.pa_end		= 0x481AC000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__gpio2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_gpio2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_gpio2_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 per/ls -> gpio4 */
+static struct omap_hwmod_addr_space am33xx_gpio3_addrs[] = {
+	{
+		.pa_start	= 0x481AE000,
+		.pa_end		= 0x481AE000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__gpio3 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_gpio3_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_gpio3_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 WKUP -> I2C1 */
+static struct omap_hwmod_addr_space am33xx_i2c1_addr_space[] = {
+	{
+		.pa_start	= 0x44E0B000,
+		.pa_end		= 0x44E0B000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__i2c1 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_i2c1_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_i2c1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* L4 WKUP -> GPIO1 */
+static struct omap_hwmod_addr_space am33xx_gpio0_addrs[] = {
+	{
+		.pa_start	= 0x44E07000,
+		.pa_end		= 0x44E07000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__gpio0 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_gpio0_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_gpio0_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 WKUP -> ADC_TSC */
+static struct omap_hwmod_addr_space am33xx_adc_tsc_addrs[] = {
+	{
+		.pa_start	= 0x44E0D000,
+		.pa_end		= 0x44E0D000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__adc_tsc = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_adc_tsc_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_adc_tsc_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_cpgmac0_addr_space[] = {
+	/* cpsw ss */
+	{
+		.pa_start	= 0x4a100000,
+		.pa_end		= 0x4a100000 + SZ_2K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	/* cpsw wr */
+	{
+		.pa_start	= 0x4a101200,
+		.pa_end		= 0x4a101200 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_hs__cpgmac0 = {
+	.master		= &am33xx_l4_hs_hwmod,
+	.slave		= &am33xx_cpgmac0_hwmod,
+	.clk		= "cpsw_125mhz_gclk",
+	.addr		= am33xx_cpgmac0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_elm_addr_space[] = {
+	{
+		.pa_start	= 0x48080000,
+		.pa_end		= 0x48080000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_elm_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_elm_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
+	{
+		.pa_start	= 0x48300000,
+		.pa_end		= 0x48300000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48300200,
+		.pa_end		= 0x48300200 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ehrpwm0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ehrpwm0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = {
+	{
+		.pa_start	= 0x48302000,
+		.pa_end		= 0x48302000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48302200,
+		.pa_end		= 0x48302200 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ehrpwm1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ehrpwm1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = {
+	{
+		.pa_start	= 0x48304000,
+		.pa_end		= 0x48304000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48304200,
+		.pa_end		= 0x48304200 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ehrpwm2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ehrpwm2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
+	{
+		.pa_start	= 0x48300000,
+		.pa_end		= 0x48300000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48300100,
+		.pa_end		= 0x48300100 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ecap0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ecap0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = {
+	{
+		.pa_start	= 0x48302000,
+		.pa_end		= 0x48302000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48302100,
+		.pa_end		= 0x48302100 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ecap1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ecap1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/*
+ * Splitting the resources to handle access of PWMSS config space
+ * and module specific part independently
+ */
+static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = {
+	{
+		.pa_start	= 0x48304000,
+		.pa_end		= 0x48304000 + SZ_16 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.pa_start	= 0x48304100,
+		.pa_end		= 0x48304100 + SZ_256 - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_ecap2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_ecap2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3s cfg -> gpmc */
+static struct omap_hwmod_addr_space am33xx_gpmc_addr_space[] = {
+	{
+		.pa_start	= 0x50000000,
+		.pa_end		= 0x50000000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_s__gpmc = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_gpmc_hwmod,
+	.clk		= "l3s_gclk",
+	.addr		= am33xx_gpmc_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* i2c2 */
+static struct omap_hwmod_addr_space am33xx_i2c2_addr_space[] = {
+	{
+		.pa_start	= 0x4802A000,
+		.pa_end		= 0x4802A000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__i2c2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_i2c2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_i2c2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_i2c3_addr_space[] = {
+	{
+		.pa_start	= 0x4819C000,
+		.pa_end		= 0x4819C000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_per__i2c3 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_i2c3_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_i2c3_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_lcdc_addr_space[] = {
+	{
+		.pa_start	= 0x4830E000,
+		.pa_end		= 0x4830E000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__lcdc = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_lcdc_hwmod,
+	.clk		= "dpll_core_m4_ck",
+	.addr		= am33xx_lcdc_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_mailbox_addrs[] = {
+	{
+		.pa_start	= 0x480C8000,
+		.pa_end		= 0x480C8000 + (SZ_4K - 1),
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* l4 ls -> mailbox */
+static struct omap_hwmod_ocp_if am33xx_l4_per__mailbox = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_mailbox_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mailbox_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> spinlock */
+static struct omap_hwmod_addr_space am33xx_spinlock_addrs[] = {
+	{
+		.pa_start	= 0x480Ca000,
+		.pa_end		= 0x480Ca000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__spinlock = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_spinlock_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_spinlock_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> mcasp0 */
+static struct omap_hwmod_addr_space am33xx_mcasp0_addr_space[] = {
+	{
+		.pa_start	= 0x48038000,
+		.pa_end		= 0x48038000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_mcasp0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mcasp0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 s -> mcasp0 data */
+static struct omap_hwmod_addr_space am33xx_mcasp0_data_addr_space[] = {
+	{
+		.pa_start	= 0x46000000,
+		.pa_end		= 0x46000000 + SZ_4M - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_s__mcasp0_data = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_mcasp0_hwmod,
+	.clk		= "l3s_gclk",
+	.addr		= am33xx_mcasp0_data_addr_space,
+	.user		= OCP_USER_SDMA,
+};
+
+/* l4 ls -> mcasp1 */
+static struct omap_hwmod_addr_space am33xx_mcasp1_addr_space[] = {
+	{
+		.pa_start	= 0x4803C000,
+		.pa_end		= 0x4803C000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_mcasp1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mcasp1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 s -> mcasp1 data */
+static struct omap_hwmod_addr_space am33xx_mcasp1_data_addr_space[] = {
+	{
+		.pa_start	= 0x46400000,
+		.pa_end		= 0x46400000 + SZ_4M - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_s__mcasp1_data = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_mcasp1_hwmod,
+	.clk		= "l3s_gclk",
+	.addr		= am33xx_mcasp1_data_addr_space,
+	.user		= OCP_USER_SDMA,
+};
+
+/* l4 ls -> mmc0 */
+static struct omap_hwmod_addr_space am33xx_mmc0_addr_space[] = {
+	{
+		.pa_start	= 0x48060100,
+		.pa_end		= 0x48060100 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mmc0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_mmc0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mmc0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> mmc1 */
+static struct omap_hwmod_addr_space am33xx_mmc1_addr_space[] = {
+	{
+		.pa_start	= 0x481d8100,
+		.pa_end		= 0x481d8100 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mmc1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_mmc1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mmc1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 s -> mmc2 */
+static struct omap_hwmod_addr_space am33xx_mmc2_addr_space[] = {
+	{
+		.pa_start	= 0x47810100,
+		.pa_end		= 0x47810100 + SZ_64K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_s__mmc2 = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_mmc2_hwmod,
+	.clk		= "l3s_gclk",
+	.addr		= am33xx_mmc2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> mcspi0 */
+static struct omap_hwmod_addr_space am33xx_mcspi0_addr_space[] = {
+	{
+		.pa_start	= 0x48030000,
+		.pa_end		= 0x48030000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi0 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_spi0_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mcspi0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> mcspi1 */
+static struct omap_hwmod_addr_space am33xx_mcspi1_addr_space[] = {
+	{
+		.pa_start	= 0x481A0000,
+		.pa_end		= 0x481A0000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi1 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_spi1_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_mcspi1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> timer1 */
+static struct omap_hwmod_addr_space am33xx_timer1_addr_space[] = {
+	{
+		.pa_start	= 0x44E31000,
+		.pa_end		= 0x44E31000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__timer1 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_timer1_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_timer1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer2 */
+static struct omap_hwmod_addr_space am33xx_timer2_addr_space[] = {
+	{
+		.pa_start	= 0x48040000,
+		.pa_end		= 0x48040000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer3 */
+static struct omap_hwmod_addr_space am33xx_timer3_addr_space[] = {
+	{
+		.pa_start	= 0x48042000,
+		.pa_end		= 0x48042000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer3 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer3_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer3_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer4 */
+static struct omap_hwmod_addr_space am33xx_timer4_addr_space[] = {
+	{
+		.pa_start	= 0x48044000,
+		.pa_end		= 0x48044000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer4 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer4_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer4_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer5 */
+static struct omap_hwmod_addr_space am33xx_timer5_addr_space[] = {
+	{
+		.pa_start	= 0x48046000,
+		.pa_end		= 0x48046000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer5 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer5_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer5_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer6 */
+static struct omap_hwmod_addr_space am33xx_timer6_addr_space[] = {
+	{
+		.pa_start	= 0x48048000,
+		.pa_end		= 0x48048000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer6 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer6_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer6_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 per -> timer7 */
+static struct omap_hwmod_addr_space am33xx_timer7_addr_space[] = {
+	{
+		.pa_start	= 0x4804A000,
+		.pa_end		= 0x4804A000 + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__timer7 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_timer7_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_timer7_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 main -> tpcc */
+static struct omap_hwmod_addr_space am33xx_tpcc_addr_space[] = {
+	{
+		.pa_start	= 0x49000000,
+		.pa_end		= 0x49000000 + SZ_32K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__tpcc = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_tpcc_hwmod,
+	.clk		= "l3_gclk",
+	.addr		= am33xx_tpcc_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 main -> tpcc0 */
+static struct omap_hwmod_addr_space am33xx_tptc0_addr_space[] = {
+	{
+		.pa_start	= 0x49800000,
+		.pa_end		= 0x49800000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__tptc0 = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_tptc0_hwmod,
+	.clk		= "l3_gclk",
+	.addr		= am33xx_tptc0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 main -> tpcc1 */
+static struct omap_hwmod_addr_space am33xx_tptc1_addr_space[] = {
+	{
+		.pa_start	= 0x49900000,
+		.pa_end		= 0x49900000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__tptc1 = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_tptc1_hwmod,
+	.clk		= "l3_gclk",
+	.addr		= am33xx_tptc1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l3 main -> tpcc2 */
+static struct omap_hwmod_addr_space am33xx_tptc2_addr_space[] = {
+	{
+		.pa_start	= 0x49a00000,
+		.pa_end		= 0x49a00000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__tptc2 = {
+	.master		= &am33xx_l3_main_hwmod,
+	.slave		= &am33xx_tptc2_hwmod,
+	.clk		= "l3_gclk",
+	.addr		= am33xx_tptc2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> uart1 */
+static struct omap_hwmod_addr_space am33xx_uart1_addr_space[] = {
+	{
+		.pa_start	= 0x44E09000,
+		.pa_end		= 0x44E09000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__uart1 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_uart1_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_uart1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> uart2 */
+static struct omap_hwmod_addr_space am33xx_uart2_addr_space[] = {
+	{
+		.pa_start	= 0x48022000,
+		.pa_end		= 0x48022000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__uart2 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_uart2_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_uart2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> uart3 */
+static struct omap_hwmod_addr_space am33xx_uart3_addr_space[] = {
+	{
+		.pa_start	= 0x48024000,
+		.pa_end		= 0x48024000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__uart3 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_uart3_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_uart3_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> uart4 */
+static struct omap_hwmod_addr_space am33xx_uart4_addr_space[] = {
+	{
+		.pa_start	= 0x481A6000,
+		.pa_end		= 0x481A6000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__uart4 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_uart4_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_uart4_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> uart5 */
+static struct omap_hwmod_addr_space am33xx_uart5_addr_space[] = {
+	{
+		.pa_start	= 0x481A8000,
+		.pa_end		= 0x481A8000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__uart5 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_uart5_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_uart5_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 ls -> uart6 */
+static struct omap_hwmod_addr_space am33xx_uart6_addr_space[] = {
+	{
+		.pa_start	= 0x481aa000,
+		.pa_end		= 0x481aa000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__uart6 = {
+	.master		= &am33xx_l4_ls_hwmod,
+	.slave		= &am33xx_uart6_hwmod,
+	.clk		= "l4ls_gclk",
+	.addr		= am33xx_uart6_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+/* l4 wkup -> wd_timer1 */
+static struct omap_hwmod_addr_space am33xx_wd_timer1_addrs[] = {
+	{
+		.pa_start	= 0x44e35000,
+		.pa_end		= 0x44e35000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_wkup__wd_timer1 = {
+	.master		= &am33xx_l4_wkup_hwmod,
+	.slave		= &am33xx_wd_timer1_hwmod,
+	.clk		= "dpll_core_m4_div2_ck",
+	.addr		= am33xx_wd_timer1_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* usbss */
+/* l3 s -> USBSS interface */
+static struct omap_hwmod_addr_space am33xx_usbss_addr_space[] = {
+	{
+		.name		= "usbss",
+		.pa_start	= 0x47400000,
+		.pa_end		= 0x47400000 + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.name		= "musb0",
+		.pa_start	= 0x47401000,
+		.pa_end		= 0x47401000 + SZ_2K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{
+		.name		= "musb1",
+		.pa_start	= 0x47401800,
+		.pa_end		= 0x47401800 + SZ_2K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_s__usbss = {
+	.master		= &am33xx_l3_s_hwmod,
+	.slave		= &am33xx_usbss_hwmod,
+	.clk		= "l3s_gclk",
+	.addr		= am33xx_usbss_addr_space,
+	.user		= OCP_USER_MPU,
+	.flags		= OCPIF_SWSUP_IDLE,
+};
+
+static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
+	&am33xx_l4_fw__emif_fw,
+	&am33xx_l3_main__emif,
+	&am33xx_mpu__l3_main,
+	&am33xx_mpu__prcm,
+	&am33xx_l3_s__l4_ls,
+	&am33xx_l3_s__l4_wkup,
+	&am33xx_l3_s__l4_fw,
+	&am33xx_l3_main__l4_hs,
+	&am33xx_l3_main__l3_s,
+	&am33xx_l3_main__l3_instr,
+	&am33xx_l3_main__gfx,
+	&am33xx_l3_s__l3_main,
+	&am33xx_pruss__l3_main,
+	&am33xx_wkup_m3__l4_wkup,
+	&am33xx_gfx__l3_main,
+	&am33xx_l4_wkup__wkup_m3,
+	&am33xx_l4_wkup__control,
+	&am33xx_l4_wkup__smartreflex0,
+	&am33xx_l4_wkup__smartreflex1,
+	&am33xx_l4_wkup__uart1,
+	&am33xx_l4_wkup__timer1,
+	&am33xx_l4_wkup__rtc,
+	&am33xx_l4_wkup__i2c1,
+	&am33xx_l4_wkup__gpio0,
+	&am33xx_l4_wkup__adc_tsc,
+	&am33xx_l4_wkup__wd_timer1,
+	&am33xx_l4_hs__pruss,
+	&am33xx_l4_per__dcan0,
+	&am33xx_l4_per__dcan1,
+	&am33xx_l4_per__gpio1,
+	&am33xx_l4_per__gpio2,
+	&am33xx_l4_per__gpio3,
+	&am33xx_l4_per__i2c2,
+	&am33xx_l4_per__i2c3,
+	&am33xx_l4_per__mailbox,
+	&am33xx_l4_ls__mcasp0,
+	&am33xx_l3_s__mcasp0_data,
+	&am33xx_l4_ls__mcasp1,
+	&am33xx_l3_s__mcasp1_data,
+	&am33xx_l4_ls__mmc0,
+	&am33xx_l4_ls__mmc1,
+	&am33xx_l3_s__mmc2,
+	&am33xx_l4_ls__timer2,
+	&am33xx_l4_ls__timer3,
+	&am33xx_l4_ls__timer4,
+	&am33xx_l4_ls__timer5,
+	&am33xx_l4_ls__timer6,
+	&am33xx_l4_ls__timer7,
+	&am33xx_l3_main__tpcc,
+	&am33xx_l4_ls__uart2,
+	&am33xx_l4_ls__uart3,
+	&am33xx_l4_ls__uart4,
+	&am33xx_l4_ls__uart5,
+	&am33xx_l4_ls__uart6,
+	&am33xx_l4_ls__spinlock,
+	&am33xx_l4_ls__elm,
+	&am33xx_l4_ls__ehrpwm0,
+	&am33xx_l4_ls__ehrpwm1,
+	&am33xx_l4_ls__ehrpwm2,
+	&am33xx_l4_ls__ecap0,
+	&am33xx_l4_ls__ecap1,
+	&am33xx_l4_ls__ecap2,
+	&am33xx_l3_s__gpmc,
+	&am33xx_l3_main__lcdc,
+	&am33xx_l4_ls__mcspi0,
+	&am33xx_l4_ls__mcspi1,
+	&am33xx_l3_main__tptc0,
+	&am33xx_l3_main__tptc1,
+	&am33xx_l3_main__tptc2,
+	&am33xx_l3_s__usbss,
+	&am33xx_l4_hs__cpgmac0,
+	NULL,
+};
+
+int __init am33xx_hwmod_init(void)
+{
+	omap_hwmod_init();
+	return omap_hwmod_register_links(am33xx_hwmod_ocp_ifs);
+}
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 8fec2ce..94b38af 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -20,15 +20,15 @@
 #include <plat/omap_hwmod.h>
 #include <plat/dma.h>
 #include <plat/serial.h>
-#include <plat/l3_3xxx.h>
-#include <plat/l4_3xxx.h>
+#include "l3_3xxx.h"
+#include "l4_3xxx.h"
 #include <plat/i2c.h>
 #include <plat/mmc.h>
-#include <plat/mcbsp.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <plat/dmtimer.h>
 
-#include <mach/am35xx.h>
+#include "am35xx.h"
 
 #include "soc.h"
 #include "omap_hwmod_common_data.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 110be87..c7dcb60 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -25,8 +25,8 @@
 #include <plat/omap_hwmod.h>
 #include <plat/i2c.h>
 #include <plat/dma.h>
-#include <plat/mcspi.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 #include <plat/mmc.h>
 #include <plat/dmtimer.h>
 #include <plat/common.h>
@@ -5889,6 +5889,12 @@
 		.pa_end		= 0x4a0ab003,
 		.flags		= ADDR_TYPE_RT
 	},
+	{
+		/* XXX: Remove this once control module driver is in place */
+		.pa_start	= 0x4a00233c,
+		.pa_end		= 0x4a00233f,
+		.flags		= ADDR_TYPE_RT
+	},
 	{ }
 };
 
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index 593eaea..d992db8f 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -33,144 +33,6 @@
 #include "soc.h"
 #include "control.h"
 
-/* OMAP control module register for UTMI PHY */
-#define CONTROL_DEV_CONF		0x300
-#define PHY_PD				0x1
-
-#define USBOTGHS_CONTROL		0x33c
-#define	AVALID				BIT(0)
-#define	BVALID				BIT(1)
-#define	VBUSVALID			BIT(2)
-#define	SESSEND				BIT(3)
-#define	IDDIG				BIT(4)
-
-static struct clk *phyclk, *clk48m, *clk32k;
-static void __iomem *ctrl_base;
-static int usbotghs_control;
-
-int omap4430_phy_init(struct device *dev)
-{
-	ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
-	if (!ctrl_base) {
-		pr_err("control module ioremap failed\n");
-		return -ENOMEM;
-	}
-	/* Power down the phy */
-	__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
-	if (!dev) {
-		iounmap(ctrl_base);
-		return 0;
-	}
-
-	phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
-	if (IS_ERR(phyclk)) {
-		dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
-		iounmap(ctrl_base);
-		return PTR_ERR(phyclk);
-	}
-
-	clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m");
-	if (IS_ERR(clk48m)) {
-		dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n");
-		clk_put(phyclk);
-		iounmap(ctrl_base);
-		return PTR_ERR(clk48m);
-	}
-
-	clk32k = clk_get(dev, "usb_phy_cm_clk32k");
-	if (IS_ERR(clk32k)) {
-		dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n");
-		clk_put(phyclk);
-		clk_put(clk48m);
-		iounmap(ctrl_base);
-		return PTR_ERR(clk32k);
-	}
-	return 0;
-}
-
-int omap4430_phy_set_clk(struct device *dev, int on)
-{
-	static int state;
-
-	if (on && !state) {
-		/* Enable the phy clocks */
-		clk_enable(phyclk);
-		clk_enable(clk48m);
-		clk_enable(clk32k);
-		state = 1;
-	} else if (state) {
-		/* Disable the phy clocks */
-		clk_disable(phyclk);
-		clk_disable(clk48m);
-		clk_disable(clk32k);
-		state = 0;
-	}
-	return 0;
-}
-
-int omap4430_phy_power(struct device *dev, int ID, int on)
-{
-	if (on) {
-		if (ID)
-			/* enable VBUS valid, IDDIG groung */
-			__raw_writel(AVALID | VBUSVALID, ctrl_base +
-							USBOTGHS_CONTROL);
-		else
-			/*
-			 * Enable VBUS Valid, AValid and IDDIG
-			 * high impedance
-			 */
-			__raw_writel(IDDIG | AVALID | VBUSVALID,
-						ctrl_base + USBOTGHS_CONTROL);
-	} else {
-		/* Enable session END and IDIG to high impedance. */
-		__raw_writel(SESSEND | IDDIG, ctrl_base +
-					USBOTGHS_CONTROL);
-	}
-	return 0;
-}
-
-int omap4430_phy_suspend(struct device *dev, int suspend)
-{
-	if (suspend) {
-		/* Disable the clocks */
-		omap4430_phy_set_clk(dev, 0);
-		/* Power down the phy */
-		__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
-		/* save the context */
-		usbotghs_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL);
-	} else {
-		/* Enable the internel phy clcoks */
-		omap4430_phy_set_clk(dev, 1);
-		/* power on the phy */
-		if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
-			__raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-			mdelay(200);
-		}
-
-		/* restore the context */
-		__raw_writel(usbotghs_control, ctrl_base + USBOTGHS_CONTROL);
-	}
-
-	return 0;
-}
-
-int omap4430_phy_exit(struct device *dev)
-{
-	if (ctrl_base)
-		iounmap(ctrl_base);
-	if (phyclk)
-		clk_put(phyclk);
-	if (clk48m)
-		clk_put(clk48m);
-	if (clk32k)
-		clk_put(clk32k);
-
-	return 0;
-}
-
 void am35x_musb_reset(void)
 {
 	u32	regval;
diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c
index d8f6dbf..45ad7f7 100644
--- a/arch/arm/mach-omap2/opp.c
+++ b/arch/arm/mach-omap2/opp.c
@@ -64,25 +64,22 @@
 		}
 		oh = omap_hwmod_lookup(opp_def->hwmod_name);
 		if (!oh || !oh->od) {
-			pr_debug("%s: no hwmod or odev for %s, [%d] "
-				"cannot add OPPs.\n", __func__,
-				opp_def->hwmod_name, i);
+			pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n",
+				 __func__, opp_def->hwmod_name, i);
 			continue;
 		}
 		dev = &oh->od->pdev->dev;
 
 		r = opp_add(dev, opp_def->freq, opp_def->u_volt);
 		if (r) {
-			dev_err(dev, "%s: add OPP %ld failed for %s [%d] "
-				"result=%d\n",
-			       __func__, opp_def->freq,
-			       opp_def->hwmod_name, i, r);
+			dev_err(dev, "%s: add OPP %ld failed for %s [%d] result=%d\n",
+				__func__, opp_def->freq,
+				opp_def->hwmod_name, i, r);
 		} else {
 			if (!opp_def->default_available)
 				r = opp_disable(dev, opp_def->freq);
 			if (r)
-				dev_err(dev, "%s: disable %ld failed for %s "
-					"[%d] result=%d\n",
+				dev_err(dev, "%s: disable %ld failed for %s [%d] result=%d\n",
 					__func__, opp_def->freq,
 					opp_def->hwmod_name, i, r);
 		}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 9cb5cede..939bd6f 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -203,8 +203,8 @@
 	bootup_volt = opp_get_voltage(opp);
 	rcu_read_unlock();
 	if (!bootup_volt) {
-		pr_err("%s: unable to find voltage corresponding "
-			"to the bootup OPP for vdd_%s\n", __func__, vdd_name);
+		pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n",
+		       __func__, vdd_name);
 		goto exit;
 	}
 
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 90480f7..ba670db 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -391,9 +391,8 @@
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
 		if (state > pwrst->next_state) {
-			pr_info("Powerdomain (%s) didn't enter "
-				"target state %d\n",
-			       pwrst->pwrdm->name, pwrst->next_state);
+			pr_info("Powerdomain (%s) didn't enter target state %d\n",
+				pwrst->pwrdm->name, pwrst->next_state);
 			ret = -1;
 		}
 		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
@@ -733,8 +732,7 @@
 		omap3_secure_ram_storage =
 			kmalloc(0x803F, GFP_KERNEL);
 		if (!omap3_secure_ram_storage)
-			pr_err("Memory allocation failed when "
-			       "allocating for secure sram context\n");
+			pr_err("Memory allocation failed when allocating for secure sram context\n");
 
 		local_irq_disable();
 		local_fiq_disable();
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index ea24174..04922d1 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -69,9 +69,8 @@
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
 		if (state > pwrst->next_state) {
-			pr_info("Powerdomain (%s) didn't enter "
-			       "target state %d\n",
-			       pwrst->pwrdm->name, pwrst->next_state);
+			pr_info("Powerdomain (%s) didn't enter target state %d\n",
+				pwrst->pwrdm->name, pwrst->next_state);
 			ret = -1;
 		}
 		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
@@ -189,8 +188,7 @@
 	ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
 	ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
 	if (ret) {
-		pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 "
-				"wakeup dependency\n");
+		pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
 		goto err2;
 	}
 
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index ca5be83..1678a32 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -341,8 +341,8 @@
 	if (!pwrdm || !clkdm)
 		return -EINVAL;
 
-	pr_debug("powerdomain: associating clockdomain %s with powerdomain "
-		 "%s\n", clkdm->name, pwrdm->name);
+	pr_debug("powerdomain: %s: associating clockdomain %s\n",
+		 pwrdm->name, clkdm->name);
 
 	for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
 		if (!pwrdm->pwrdm_clkdms[i])
@@ -356,8 +356,8 @@
 	}
 
 	if (i == PWRDM_MAX_CLKDMS) {
-		pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
-			 "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
+		pr_debug("powerdomain: %s: increase PWRDM_MAX_CLKDMS for clkdm %s\n",
+			 pwrdm->name, clkdm->name);
 		WARN_ON(1);
 		ret = -ENOMEM;
 		goto pac_exit;
@@ -389,16 +389,16 @@
 	if (!pwrdm || !clkdm)
 		return -EINVAL;
 
-	pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
-		 "%s\n", clkdm->name, pwrdm->name);
+	pr_debug("powerdomain: %s: dissociating clockdomain %s\n",
+		 pwrdm->name, clkdm->name);
 
 	for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
 		if (pwrdm->pwrdm_clkdms[i] == clkdm)
 			break;
 
 	if (i == PWRDM_MAX_CLKDMS) {
-		pr_debug("powerdomain: clkdm %s not associated with pwrdm "
-			 "%s ?!\n", clkdm->name, pwrdm->name);
+		pr_debug("powerdomain: %s: clkdm %s not associated?!\n",
+			 pwrdm->name, clkdm->name);
 		ret = -ENOENT;
 		goto pdc_exit;
 	}
@@ -487,7 +487,7 @@
 	if (!(pwrdm->pwrsts & (1 << pwrst)))
 		return -EINVAL;
 
-	pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
+	pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
 		 pwrdm->name, pwrst);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
@@ -589,7 +589,7 @@
 	if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
 		return -EINVAL;
 
-	pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
+	pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
 		 pwrdm->name, pwrst);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
@@ -626,8 +626,8 @@
 	if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
 		return -EINVAL;
 
-	pr_debug("powerdomain: setting next memory powerstate for domain %s "
-		 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
+	pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
+		 pwrdm->name, bank, pwrst);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
 		ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
@@ -664,8 +664,8 @@
 	if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
 		return -EINVAL;
 
-	pr_debug("powerdomain: setting next memory powerstate for domain %s "
-		 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
+	pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
+		 pwrdm->name, bank, pwrst);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
 		ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
@@ -843,7 +843,7 @@
 	 * warn & fail if it is not ON.
 	 */
 
-	pr_debug("powerdomain: clearing previous power state reg for %s\n",
+	pr_debug("powerdomain: %s: clearing previous power state reg\n",
 		 pwrdm->name);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
@@ -873,8 +873,7 @@
 	if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
 		return ret;
 
-	pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
-		 pwrdm->name);
+	pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
 		ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
@@ -903,8 +902,7 @@
 	if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
 		return ret;
 
-	pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
-		 pwrdm->name);
+	pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
 		ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
diff --git a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
index 0f0a9f1..3950ccf 100644
--- a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
@@ -122,8 +122,8 @@
 			udelay(1);
 
 	if (c > PWRDM_TRANSITION_BAILOUT) {
-		printk(KERN_ERR "powerdomain: waited too long for "
-			"powerdomain %s to complete transition\n", pwrdm->name);
+		pr_err("powerdomain: %s: waited too long to complete transition\n",
+		       pwrdm->name);
 		return -EAGAIN;
 	}
 
diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
index 601325b..aeac6f3 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -198,8 +198,8 @@
 		udelay(1);
 
 	if (c > PWRDM_TRANSITION_BAILOUT) {
-		printk(KERN_ERR "powerdomain: waited too long for "
-		       "powerdomain %s to complete transition\n", pwrdm->name);
+		pr_err("powerdomain: %s: waited too long to complete transition\n",
+		       pwrdm->name);
 		return -EAGAIN;
 	}
 
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 9c9d23c..0f51e03 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -139,11 +139,11 @@
 			  MAX_MODULE_ENABLE_WAIT, i);
 
 	if (i < MAX_MODULE_ENABLE_WAIT)
-		pr_debug("cm: Module associated with clock %s ready after %d "
-			 "loops\n", name, i);
+		pr_debug("cm: Module associated with clock %s ready after %d loops\n",
+			 name, i);
 	else
-		pr_err("cm: Module associated with clock %s didn't enable in "
-		       "%d tries\n", name, MAX_MODULE_ENABLE_WAIT);
+		pr_err("cm: Module associated with clock %s didn't enable in %d tries\n",
+		       name, MAX_MODULE_ENABLE_WAIT);
 
 	return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
 };
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 7ca266e..0405c81 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -232,9 +232,8 @@
 
 			if (console_loglevel >= 10) {
 				uart_debug = true;
-				pr_info("%s used as console in debug mode"
-						" uart%d clocks will not be"
-						" gated", uart_name, uart->num);
+				pr_info("%s used as console in debug mode: uart%d clocks will not be gated",
+					uart_name, uart->num);
 			}
 
 			if (cmdline_find_option("no_console_suspend"))
@@ -319,8 +318,11 @@
 
 	pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,
 				 NULL, 0, false);
-	WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.\n",
-	     name, oh->name);
+	if (IS_ERR(pdev)) {
+		WARN(1, "Could not build omap_device for %s: %s.\n", name,
+		     oh->name);
+		return;
+	}
 
 	if ((console_uart_id == bdata->id) && no_console_suspend)
 		omap_device_disable_idle_on_suspend(pdev);
diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
index b7d8ead..88ff83a 100644
--- a/arch/arm/mach-omap2/sleep44xx.S
+++ b/arch/arm/mach-omap2/sleep44xx.S
@@ -14,7 +14,7 @@
 #include <asm/memory.h>
 #include <asm/hardware/cache-l2x0.h>
 
-#include <mach/omap-secure.h>
+#include "omap-secure.h"
 
 #include "common.h"
 #include "omap44xx.h"
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index d033a65..cbeae56 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -104,16 +104,15 @@
 
 	sr_data = kzalloc(sizeof(struct omap_sr_data), GFP_KERNEL);
 	if (!sr_data) {
-		pr_err("%s: Unable to allocate memory for %s sr_data.Error!\n",
-			__func__, oh->name);
+		pr_err("%s: Unable to allocate memory for %s sr_data\n",
+		       __func__, oh->name);
 		return -ENOMEM;
 	}
 
 	sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
 	if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
-		pr_err("%s: No voltage domain specified for %s."
-				"Cannot initialize\n", __func__,
-					oh->name);
+		pr_err("%s: No voltage domain specified for %s. Cannot initialize\n",
+		       __func__, oh->name);
 		goto exit;
 	}
 
@@ -131,8 +130,8 @@
 
 	omap_voltage_get_volttable(sr_data->voltdm, &volt_data);
 	if (!volt_data) {
-		pr_warning("%s: No Voltage table registered fo VDD%d."
-			"Something really wrong\n\n", __func__, i + 1);
+		pr_err("%s: No Voltage table registered for VDD%d\n",
+		       __func__, i + 1);
 		goto exit;
 	}
 
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index a9c9b3d..8847d6e 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -220,7 +220,7 @@
 	res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source);
 	BUG_ON(res);
 
-	omap2_gp_timer_irq.dev_id = (void *)&clkev;
+	omap2_gp_timer_irq.dev_id = &clkev;
 	setup_irq(clkev.irq, &omap2_gp_timer_irq);
 
 	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 99be94e..45f7741 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -40,16 +40,6 @@
 	.flags		= I2C_CLIENT_WAKE,
 };
 
-static struct i2c_board_info __initdata omap4_i2c1_board_info[] = {
-	{
-		.addr		= 0x48,
-		.flags		= I2C_CLIENT_WAKE,
-	},
-	{
-		I2C_BOARD_INFO("twl6040", 0x4b),
-	},
-};
-
 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 static int twl_set_voltage(void *data, int target_uV)
 {
@@ -79,30 +69,25 @@
 
 void __init omap4_pmic_init(const char *pmic_type,
 		    struct twl4030_platform_data *pmic_data,
-		    struct twl6040_platform_data *twl6040_data, int twl6040_irq)
+		    struct i2c_board_info *devices, int nr_devices)
 {
 	/* PMIC part*/
 	omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
-	strncpy(omap4_i2c1_board_info[0].type, pmic_type,
-		sizeof(omap4_i2c1_board_info[0].type));
-	omap4_i2c1_board_info[0].irq = 7 + OMAP44XX_IRQ_GIC_START;
-	omap4_i2c1_board_info[0].platform_data = pmic_data;
+	omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data);
 
-	/* TWL6040 audio IC part */
-	omap4_i2c1_board_info[1].irq = twl6040_irq;
-	omap4_i2c1_board_info[1].platform_data = twl6040_data;
-
-	omap_register_i2c_bus(1, 400, omap4_i2c1_board_info, 2);
-
+	/* Register additional devices on i2c1 bus if needed */
+	if (devices)
+		i2c_register_board_info(1, devices, nr_devices);
 }
 
 void __init omap_pmic_late_init(void)
 {
-	/* Init the OMAP TWL parameters (if PMIC has been registered) */
-	if (pmic_i2c_board_info.irq)
-		omap3_twl_init();
-	if (omap4_i2c1_board_info[0].irq)
-		omap4_twl_init();
+	/* Init the OMAP TWL parameters (if PMIC has been registerd) */
+	if (!pmic_i2c_board_info.irq)
+		return;
+
+	omap3_twl_init();
+	omap4_twl_init();
 }
 
 #if defined(CONFIG_ARCH_OMAP3)
@@ -252,11 +237,6 @@
 
 #if defined(CONFIG_ARCH_OMAP4)
 static struct twl4030_usb_data omap4_usb_pdata = {
-	.phy_init	= omap4430_phy_init,
-	.phy_exit	= omap4430_phy_exit,
-	.phy_power	= omap4430_phy_power,
-	.phy_set_clock	= omap4430_phy_set_clk,
-	.phy_suspend	= omap4430_phy_suspend,
 };
 
 static struct regulator_init_data omap4_vdac_idata = {
diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
index d109c09..2256efe 100644
--- a/arch/arm/mach-omap2/twl-common.h
+++ b/arch/arm/mach-omap2/twl-common.h
@@ -32,6 +32,7 @@
 
 struct twl4030_platform_data;
 struct twl6040_platform_data;
+struct i2c_board_info;
 
 void omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq,
 		    struct twl4030_platform_data *pmic_data);
@@ -51,7 +52,7 @@
 
 void omap4_pmic_init(const char *pmic_type,
 		    struct twl4030_platform_data *pmic_data,
-		    struct twl6040_platform_data *audio_data, int twl6040_irq);
+		    struct i2c_board_info *devices, int nr_devices);
 
 void omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
 			   u32 pdata_flags, u32 regulators_flags);
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 89150b2..51da21c 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -28,7 +28,7 @@
 #include <plat/usb.h>
 #include <plat/omap_device.h>
 
-#include <mach/am35xx.h>
+#include "am35xx.h"
 
 #include "mux.h"
 
@@ -116,7 +116,4 @@
 	dev->dma_mask = &musb_dmamask;
 	dev->coherent_dma_mask = musb_dmamask;
 	put_device(dev);
-
-	if (cpu_is_omap44xx())
-		omap4430_phy_init(dev);
 }
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index b451f3c..880249b 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -115,9 +115,8 @@
 	}
 
 	if (!voltdm->pmic->uv_to_vsel) {
-		pr_err("%s: PMIC function to convert voltage in uV to"
-			"vsel not registered. Hence unable to scale voltage"
-			"for vdd_%s\n", __func__, voltdm->name);
+		pr_err("%s: PMIC function to convert voltage in uV to vsel not registered. Hence unable to scale voltage for vdd_%s\n",
+		       __func__, voltdm->name);
 		return -ENODATA;
 	}
 
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 4dc60e8..3ac8fe1 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -195,8 +195,8 @@
 			return &voltdm->volt_data[i];
 	}
 
-	pr_notice("%s: Unable to match the current voltage with the voltage"
-		"table for vdd_%s\n", __func__, voltdm->name);
+	pr_notice("%s: Unable to match the current voltage with the voltage table for vdd_%s\n",
+		  __func__, voltdm->name);
 
 	return ERR_PTR(-ENODATA);
 }
@@ -249,8 +249,8 @@
 		voltdm->scale = omap_vc_bypass_scale;
 		return;
 	default:
-		pr_warning("%s: Trying to change the method of voltage scaling"
-			"to an unsupported one!\n", __func__);
+		pr_warn("%s: Trying to change the method of voltage scaling to an unsupported one!\n",
+			__func__);
 	}
 }
 
@@ -331,8 +331,8 @@
 	if (!voltdm || !pwrdm)
 		return -EINVAL;
 
-	pr_debug("voltagedomain: associating powerdomain %s with voltagedomain "
-		 "%s\n", pwrdm->name, voltdm->name);
+	pr_debug("voltagedomain: %s: associating powerdomain %s\n",
+		 voltdm->name, pwrdm->name);
 
 	list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list);
 
diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h
index 0ac2caf..7283b7e 100644
--- a/arch/arm/mach-omap2/voltage.h
+++ b/arch/arm/mach-omap2/voltage.h
@@ -16,7 +16,7 @@
 
 #include <linux/err.h>
 
-#include <plat/voltage.h>
+#include <linux/platform_data/voltage-omap.h>
 
 #include "vc.h"
 #include "vp.h"
diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c
index f95c1ba..85241b8 100644
--- a/arch/arm/mach-omap2/vp.c
+++ b/arch/arm/mach-omap2/vp.c
@@ -138,8 +138,8 @@
 		udelay(1);
 	}
 	if (timeout >= VP_TRANXDONE_TIMEOUT) {
-		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
-			"Voltage change aborted", __func__, voltdm->name);
+		pr_warn("%s: vdd_%s TRANXDONE timeout exceeded. Voltage change aborted",
+			__func__, voltdm->name);
 		return -ETIMEDOUT;
 	}
 
@@ -157,9 +157,8 @@
 	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
 			  VP_TRANXDONE_TIMEOUT, timeout);
 	if (timeout >= VP_TRANXDONE_TIMEOUT)
-		pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
-			"TRANXDONE never got set after the voltage update\n",
-			__func__, voltdm->name);
+		pr_err("%s: vdd_%s TRANXDONE timeout exceeded. TRANXDONE never got set after the voltage update\n",
+		       __func__, voltdm->name);
 
 	omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);
 
@@ -176,8 +175,7 @@
 	}
 
 	if (timeout >= VP_TRANXDONE_TIMEOUT)
-		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
-			"to clear the TRANXDONE status\n",
+		pr_warn("%s: vdd_%s TRANXDONE timeout exceeded while trying to clear the TRANXDONE status\n",
 			__func__, voltdm->name);
 
 	/* Clear force bit */
@@ -257,8 +255,8 @@
 
 	/* If VP is already disabled, do nothing. Return */
 	if (!vp->enabled) {
-		pr_warning("%s: Trying to disable VP for vdd_%s when"
-			"it is already disabled\n", __func__, voltdm->name);
+		pr_warn("%s: Trying to disable VP for vdd_%s when it is already disabled\n",
+			__func__, voltdm->name);
 		return;
 	}
 
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 410291c..2fdd4e4 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -47,16 +47,6 @@
 		.length		= ORION5X_REGS_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= ORION5X_PCIE_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE),
-		.length		= ORION5X_PCIE_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= ORION5X_PCI_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE),
-		.length		= ORION5X_PCI_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= ORION5X_PCIE_WA_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE),
 		.length		= ORION5X_PCIE_WA_SIZE,
@@ -204,6 +194,13 @@
 void __init orion5x_init_early(void)
 {
 	orion_time_set_base(TIMER_VIRT_BASE);
+
+	/*
+	 * Some Orion5x devices allocate their coherent buffers from atomic
+	 * context. Increase size of atomic coherent pool to make sure such
+	 * the allocations won't fail.
+	 */
+	init_dma_coherent_pool_size(SZ_1M);
 }
 
 int orion5x_tclk;
diff --git a/arch/arm/mach-orion5x/include/mach/io.h b/arch/arm/mach-orion5x/include/mach/io.h
deleted file mode 100644
index 1aa5d0a..0000000
--- a/arch/arm/mach-orion5x/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include <mach/orion5x.h>
-#include <asm/sizes.h>
-
-#define IO_SPACE_LIMIT		SZ_2M
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)(addr + ORION5X_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)			 __io(a)
-#endif
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index 683e085..1b60131 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -31,31 +31,29 @@
  * fc000000	device bus mappings (cs0/cs1)
  *
  * virt		phys		size
- * fdd00000	f1000000	1M	on-chip peripheral registers
- * fde00000	f2000000	1M	PCIe I/O space
- * fdf00000	f2100000	1M	PCI I/O space
- * fe000000	f0000000	16M	PCIe WA space (Orion-1/Orion-NAS only)
+ * fe000000	f1000000	1M	on-chip peripheral registers
+ * fee00000	f2000000	64K	PCIe I/O space
+ * fee10000	f2100000	64K	PCI I/O space
+ * fd000000	f0000000	16M	PCIe WA space (Orion-1/Orion-NAS only)
  ****************************************************************************/
 #define ORION5X_REGS_PHYS_BASE		0xf1000000
-#define ORION5X_REGS_VIRT_BASE		0xfdd00000
+#define ORION5X_REGS_VIRT_BASE		0xfe000000
 #define ORION5X_REGS_SIZE		SZ_1M
 
 #define ORION5X_PCIE_IO_PHYS_BASE	0xf2000000
-#define ORION5X_PCIE_IO_VIRT_BASE	0xfde00000
 #define ORION5X_PCIE_IO_BUS_BASE	0x00000000
-#define ORION5X_PCIE_IO_SIZE		SZ_1M
+#define ORION5X_PCIE_IO_SIZE		SZ_64K
 
 #define ORION5X_PCI_IO_PHYS_BASE	0xf2100000
-#define ORION5X_PCI_IO_VIRT_BASE	0xfdf00000
-#define ORION5X_PCI_IO_BUS_BASE		0x00100000
-#define ORION5X_PCI_IO_SIZE		SZ_1M
+#define ORION5X_PCI_IO_BUS_BASE		0x00010000
+#define ORION5X_PCI_IO_SIZE		SZ_64K
 
 #define ORION5X_SRAM_PHYS_BASE		(0xf2200000)
 #define ORION5X_SRAM_SIZE		SZ_8K
 
 /* Relevant only for Orion-1/Orion-NAS */
 #define ORION5X_PCIE_WA_PHYS_BASE	0xf0000000
-#define ORION5X_PCIE_WA_VIRT_BASE	0xfe000000
+#define ORION5X_PCIE_WA_VIRT_BASE	0xfd000000
 #define ORION5X_PCIE_WA_SIZE		SZ_16M
 
 #define ORION5X_PCIE_MEM_PHYS_BASE	0xe0000000
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index cb19e16..6921d49 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -162,35 +162,25 @@
 		pcie_ops.read = pcie_rd_conf_wa;
 	}
 
+	pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCIE_IO_PHYS_BASE);
+
 	/*
 	 * Request resources.
 	 */
-	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("pcie_setup unable to alloc resources");
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	sys->io_offset = 0;
-	res[0].name = "PCIe I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	res[0].start = ORION5X_PCIE_IO_BUS_BASE;
-	res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
-	if (request_resource(&ioport_resource, &res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	res[1].name = "PCIe Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	res[1].start = ORION5X_PCIE_MEM_PHYS_BASE;
-	res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
-	if (request_resource(&iomem_resource, &res[1]))
+	res->name = "PCIe Memory Space";
+	res->flags = IORESOURCE_MEM;
+	res->start = ORION5X_PCIE_MEM_PHYS_BASE;
+	res->end = res->start + ORION5X_PCIE_MEM_SIZE - 1;
+	if (request_resource(&iomem_resource, res))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
@@ -489,35 +479,25 @@
 	 */
 	orion5x_setbits(PCI_CMD, PCI_CMD_HOST_REORDER);
 
+	pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCI_IO_PHYS_BASE);
+
 	/*
 	 * Request resources
 	 */
-	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("pci_setup unable to alloc resources");
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	sys->io_offset = 0;
-	res[0].name = "PCI I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	res[0].start = ORION5X_PCI_IO_BUS_BASE;
-	res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
-	if (request_resource(&ioport_resource, &res[0]))
-		panic("Request PCI IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	res[1].name = "PCI Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	res[1].start = ORION5X_PCI_MEM_PHYS_BASE;
-	res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
-	if (request_resource(&iomem_resource, &res[1]))
+	res->name = "PCI Memory Space";
+	res->flags = IORESOURCE_MEM;
+	res->start = ORION5X_PCI_MEM_PHYS_BASE;
+	res->end = res->start + ORION5X_PCI_MEM_SIZE - 1;
+	if (request_resource(&iomem_resource, res))
 		panic("Request PCI Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-pnx4008/Makefile b/arch/arm/mach-pnx4008/Makefile
deleted file mode 100644
index 777564c..0000000
--- a/arch/arm/mach-pnx4008/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-obj-y			:= core.o irq.o time.o clock.o gpio.o serial.o dma.o i2c.o
-obj-m			:=
-obj-n			:=
-obj-			:=
-
-# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
-
diff --git a/arch/arm/mach-pnx4008/Makefile.boot b/arch/arm/mach-pnx4008/Makefile.boot
deleted file mode 100644
index 9fa19ba..0000000
--- a/arch/arm/mach-pnx4008/Makefile.boot
+++ /dev/null
@@ -1,4 +0,0 @@
-   zreladdr-y		+= 0x80008000
-params_phys-y		:= 0x80000100
-initrd_phys-y		:= 0x80800000
-
diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
deleted file mode 100644
index a4a3819..0000000
--- a/arch/arm/mach-pnx4008/clock.c
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/clock.c
- *
- * Clock control driver for PNX4008
- *
- * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
- * Generic clock management functions are partially based on:
- *  linux/arch/arm/mach-omap/clock.c
- *
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-
-#include <mach/hardware.h>
-#include <mach/clock.h>
-#include "clock.h"
-
-/*forward declaration*/
-static struct clk per_ck;
-static struct clk hclk_ck;
-static struct clk ck_1MHz;
-static struct clk ck_13MHz;
-static struct clk ck_pll1;
-static int local_set_rate(struct clk *clk, u32 rate);
-
-static inline void clock_lock(void)
-{
-	local_irq_disable();
-}
-
-static inline void clock_unlock(void)
-{
-	local_irq_enable();
-}
-
-static void propagate_rate(struct clk *clk)
-{
-	struct clk *tmp_clk;
-
-	tmp_clk = clk;
-	while (tmp_clk->propagate_next) {
-		tmp_clk = tmp_clk->propagate_next;
-		local_set_rate(tmp_clk, tmp_clk->user_rate);
-	}
-}
-
-static void clk_reg_disable(struct clk *clk)
-{
-	if (clk->enable_reg)
-		__raw_writel(__raw_readl(clk->enable_reg) &
-			     ~(1 << clk->enable_shift), clk->enable_reg);
-}
-
-static int clk_reg_enable(struct clk *clk)
-{
-	if (clk->enable_reg)
-		__raw_writel(__raw_readl(clk->enable_reg) |
-			     (1 << clk->enable_shift), clk->enable_reg);
-	return 0;
-}
-
-static inline void clk_reg_disable1(struct clk *clk)
-{
-	if (clk->enable_reg1)
-		__raw_writel(__raw_readl(clk->enable_reg1) &
-			     ~(1 << clk->enable_shift1), clk->enable_reg1);
-}
-
-static inline void clk_reg_enable1(struct clk *clk)
-{
-	if (clk->enable_reg1)
-		__raw_writel(__raw_readl(clk->enable_reg1) |
-			     (1 << clk->enable_shift1), clk->enable_reg1);
-}
-
-static int clk_wait_for_pll_lock(struct clk *clk)
-{
-	int i;
-	i = 0;
-	while (i++ < 0xFFF && !(__raw_readl(clk->scale_reg) & 1)) ;	/*wait for PLL to lock */
-
-	if (!(__raw_readl(clk->scale_reg) & 1)) {
-		printk(KERN_ERR
-		       "%s ERROR: failed to lock, scale reg data: %x\n",
-		       clk->name, __raw_readl(clk->scale_reg));
-		return -1;
-	}
-	return 0;
-}
-
-static int switch_to_dirty_13mhz(struct clk *clk)
-{
-	int i;
-	int ret;
-	u32 tmp_reg;
-
-	ret = 0;
-
-	if (!clk->rate)
-		clk_reg_enable1(clk);
-
-	tmp_reg = __raw_readl(clk->parent_switch_reg);
-	/*if 13Mhz clock selected, select 13'MHz (dirty) source from OSC */
-	if (!(tmp_reg & 1)) {
-		tmp_reg |= (1 << 1);	/* Trigger switch to 13'MHz (dirty) clock */
-		__raw_writel(tmp_reg, clk->parent_switch_reg);
-		i = 0;
-		while (i++ < 0xFFF && !(__raw_readl(clk->parent_switch_reg) & 1)) ;	/*wait for 13'MHz selection status */
-
-		if (!(__raw_readl(clk->parent_switch_reg) & 1)) {
-			printk(KERN_ERR
-			       "%s ERROR: failed to select 13'MHz, parent sw reg data: %x\n",
-			       clk->name, __raw_readl(clk->parent_switch_reg));
-			ret = -1;
-		}
-	}
-
-	if (!clk->rate)
-		clk_reg_disable1(clk);
-
-	return ret;
-}
-
-static int switch_to_clean_13mhz(struct clk *clk)
-{
-	int i;
-	int ret;
-	u32 tmp_reg;
-
-	ret = 0;
-
-	if (!clk->rate)
-		clk_reg_enable1(clk);
-
-	tmp_reg = __raw_readl(clk->parent_switch_reg);
-	/*if 13'Mhz clock selected, select 13MHz (clean) source from OSC */
-	if (tmp_reg & 1) {
-		tmp_reg &= ~(1 << 1);	/* Trigger switch to 13MHz (clean) clock */
-		__raw_writel(tmp_reg, clk->parent_switch_reg);
-		i = 0;
-		while (i++ < 0xFFF && (__raw_readl(clk->parent_switch_reg) & 1)) ;	/*wait for 13MHz selection status */
-
-		if (__raw_readl(clk->parent_switch_reg) & 1) {
-			printk(KERN_ERR
-			       "%s ERROR: failed to select 13MHz, parent sw reg data: %x\n",
-			       clk->name, __raw_readl(clk->parent_switch_reg));
-			ret = -1;
-		}
-	}
-
-	if (!clk->rate)
-		clk_reg_disable1(clk);
-
-	return ret;
-}
-
-static int set_13MHz_parent(struct clk *clk, struct clk *parent)
-{
-	int ret = -EINVAL;
-
-	if (parent == &ck_13MHz)
-		ret = switch_to_clean_13mhz(clk);
-	else if (parent == &ck_pll1)
-		ret = switch_to_dirty_13mhz(clk);
-
-	return ret;
-}
-
-#define PLL160_MIN_FCCO 156000
-#define PLL160_MAX_FCCO 320000
-
-/*
- * Calculate pll160 settings.
- * Possible input: up to 320MHz with step of clk->parent->rate.
- * In PNX4008 parent rate for pll160s may be either 1 or 13MHz.
- * Ignored paths: "feedback" (bit 13 set), "div-by-N".
- * Setting ARM PLL4 rate to 0 will put CPU into direct run mode.
- * Setting PLL5 and PLL3 rate to 0 will disable USB and DSP clock input.
- * Please refer to PNX4008 IC manual for details.
- */
-
-static int pll160_set_rate(struct clk *clk, u32 rate)
-{
-	u32 tmp_reg, tmp_m, tmp_2p, i;
-	u32 parent_rate;
-	int ret = -EINVAL;
-
-	parent_rate = clk->parent->rate;
-
-	if (!parent_rate)
-		goto out;
-
-	/* set direct run for ARM or disable output for others  */
-	clk_reg_disable(clk);
-
-	/* disable source input as well (ignored for ARM) */
-	clk_reg_disable1(clk);
-
-	tmp_reg = __raw_readl(clk->scale_reg);
-	tmp_reg &= ~0x1ffff;	/*clear all settings, power down */
-	__raw_writel(tmp_reg, clk->scale_reg);
-
-	rate -= rate % parent_rate;	/*round down the input */
-
-	if (rate > PLL160_MAX_FCCO)
-		rate = PLL160_MAX_FCCO;
-
-	if (!rate) {
-		clk->rate = 0;
-		ret = 0;
-		goto out;
-	}
-
-	clk_reg_enable1(clk);
-	tmp_reg = __raw_readl(clk->scale_reg);
-
-	if (rate == parent_rate) {
-		/*enter direct bypass mode */
-		tmp_reg |= ((1 << 14) | (1 << 15));
-		__raw_writel(tmp_reg, clk->scale_reg);
-		clk->rate = parent_rate;
-		clk_reg_enable(clk);
-		ret = 0;
-		goto out;
-	}
-
-	i = 0;
-	for (tmp_2p = 1; tmp_2p < 16; tmp_2p <<= 1) {
-		if (rate * tmp_2p >= PLL160_MIN_FCCO)
-			break;
-		i++;
-	}
-
-	if (tmp_2p > 1)
-		tmp_reg |= ((i - 1) << 11);
-	else
-		tmp_reg |= (1 << 14);	/*direct mode, no divide */
-
-	tmp_m = rate * tmp_2p;
-	tmp_m /= parent_rate;
-
-	tmp_reg |= (tmp_m - 1) << 1;	/*calculate M */
-	tmp_reg |= (1 << 16);	/*power up PLL */
-	__raw_writel(tmp_reg, clk->scale_reg);
-
-	if (clk_wait_for_pll_lock(clk) < 0) {
-		clk_reg_disable(clk);
-		clk_reg_disable1(clk);
-
-		tmp_reg = __raw_readl(clk->scale_reg);
-		tmp_reg &= ~0x1ffff;	/*clear all settings, power down */
-		__raw_writel(tmp_reg, clk->scale_reg);
-		clk->rate = 0;
-		ret = -EFAULT;
-		goto out;
-	}
-
-	clk->rate = (tmp_m * parent_rate) / tmp_2p;
-
-	if (clk->flags & RATE_PROPAGATES)
-		propagate_rate(clk);
-
-	clk_reg_enable(clk);
-	ret = 0;
-
-out:
-	return ret;
-}
-
-/*configure PER_CLK*/
-static int per_clk_set_rate(struct clk *clk, u32 rate)
-{
-	u32 tmp;
-
-	tmp = __raw_readl(clk->scale_reg);
-	tmp &= ~(0x1f << 2);
-	tmp |= ((clk->parent->rate / clk->rate) - 1) << 2;
-	__raw_writel(tmp, clk->scale_reg);
-	clk->rate = rate;
-	return 0;
-}
-
-/*configure HCLK*/
-static int hclk_set_rate(struct clk *clk, u32 rate)
-{
-	u32 tmp;
-	tmp = __raw_readl(clk->scale_reg);
-	tmp = tmp & ~0x3;
-	switch (rate) {
-	case 1:
-		break;
-	case 2:
-		tmp |= 1;
-		break;
-	case 4:
-		tmp |= 2;
-		break;
-	}
-
-	__raw_writel(tmp, clk->scale_reg);
-	clk->rate = rate;
-	return 0;
-}
-
-static u32 hclk_round_rate(struct clk *clk, u32 rate)
-{
-	switch (rate) {
-	case 1:
-	case 4:
-		return rate;
-	}
-	return 2;
-}
-
-static u32 per_clk_round_rate(struct clk *clk, u32 rate)
-{
-	return CLK_RATE_13MHZ;
-}
-
-static int on_off_set_rate(struct clk *clk, u32 rate)
-{
-	if (rate) {
-		clk_reg_enable(clk);
-		clk->rate = 1;
-	} else {
-		clk_reg_disable(clk);
-		clk->rate = 0;
-	}
-	return 0;
-}
-
-static int on_off_inv_set_rate(struct clk *clk, u32 rate)
-{
-	if (rate) {
-		clk_reg_disable(clk);	/*enable bit is inverted */
-		clk->rate = 1;
-	} else {
-		clk_reg_enable(clk);
-		clk->rate = 0;
-	}
-	return 0;
-}
-
-static u32 on_off_round_rate(struct clk *clk, u32 rate)
-{
-	return (rate ? 1 : 0);
-}
-
-static u32 pll4_round_rate(struct clk *clk, u32 rate)
-{
-	if (rate > CLK_RATE_208MHZ)
-		rate = CLK_RATE_208MHZ;
-	if (rate == CLK_RATE_208MHZ && hclk_ck.user_rate == 1)
-		rate = CLK_RATE_208MHZ - CLK_RATE_13MHZ;
-	return (rate - (rate % (hclk_ck.user_rate * CLK_RATE_13MHZ)));
-}
-
-static u32 pll3_round_rate(struct clk *clk, u32 rate)
-{
-	if (rate > CLK_RATE_208MHZ)
-		rate = CLK_RATE_208MHZ;
-	return (rate - rate % CLK_RATE_13MHZ);
-}
-
-static u32 pll5_round_rate(struct clk *clk, u32 rate)
-{
-	return (rate ? CLK_RATE_48MHZ : 0);
-}
-
-static u32 ck_13MHz_round_rate(struct clk *clk, u32 rate)
-{
-	return (rate ? CLK_RATE_13MHZ : 0);
-}
-
-static int ck_13MHz_set_rate(struct clk *clk, u32 rate)
-{
-	if (rate) {
-		clk_reg_disable(clk);	/*enable bit is inverted */
-		udelay(500);
-		clk->rate = CLK_RATE_13MHZ;
-		ck_1MHz.rate = CLK_RATE_1MHZ;
-	} else {
-		clk_reg_enable(clk);
-		clk->rate = 0;
-		ck_1MHz.rate = 0;
-	}
-	return 0;
-}
-
-static int pll1_set_rate(struct clk *clk, u32 rate)
-{
-#if 0 /* doesn't work on some boards, probably a HW BUG */
-	if (rate) {
-		clk_reg_disable(clk);	/*enable bit is inverted */
-		if (!clk_wait_for_pll_lock(clk)) {
-			clk->rate = CLK_RATE_13MHZ;
-		} else {
-			clk_reg_enable(clk);
-			clk->rate = 0;
-		}
-
-	} else {
-		clk_reg_enable(clk);
-		clk->rate = 0;
-	}
-#endif
-	return 0;
-}
-
-/* Clock sources */
-
-static struct clk osc_13MHz = {
-	.name = "osc_13MHz",
-	.flags = FIXED_RATE,
-	.rate = CLK_RATE_13MHZ,
-};
-
-static struct clk ck_13MHz = {
-	.name = "ck_13MHz",
-	.parent = &osc_13MHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &ck_13MHz_round_rate,
-	.set_rate = &ck_13MHz_set_rate,
-	.enable_reg = OSC13CTRL_REG,
-	.enable_shift = 0,
-	.rate = CLK_RATE_13MHZ,
-};
-
-static struct clk osc_32KHz = {
-	.name = "osc_32KHz",
-	.flags = FIXED_RATE,
-	.rate = CLK_RATE_32KHZ,
-};
-
-/*attached to PLL5*/
-static struct clk ck_1MHz = {
-	.name = "ck_1MHz",
-	.flags = FIXED_RATE | PARENT_SET_RATE,
-	.parent = &ck_13MHz,
-};
-
-/* PLL1 (397) - provides 13' MHz clock */
-static struct clk ck_pll1 = {
-	.name = "ck_pll1",
-	.parent = &osc_32KHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &ck_13MHz_round_rate,
-	.set_rate = &pll1_set_rate,
-	.enable_reg = PLLCTRL_REG,
-	.enable_shift = 1,
-	.scale_reg = PLLCTRL_REG,
-	.rate = CLK_RATE_13MHZ,
-};
-
-/* CPU/Bus PLL */
-static struct clk ck_pll4 = {
-	.name = "ck_pll4",
-	.parent = &ck_pll1,
-	.flags = RATE_PROPAGATES | NEEDS_INITIALIZATION,
-	.propagate_next = &per_ck,
-	.round_rate = &pll4_round_rate,
-	.set_rate = &pll160_set_rate,
-	.rate = CLK_RATE_208MHZ,
-	.scale_reg = HCLKPLLCTRL_REG,
-	.enable_reg = PWRCTRL_REG,
-	.enable_shift = 2,
-	.parent_switch_reg = SYSCLKCTRL_REG,
-	.set_parent = &set_13MHz_parent,
-};
-
-/* USB PLL */
-static struct clk ck_pll5 = {
-	.name = "ck_pll5",
-	.parent = &ck_1MHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &pll5_round_rate,
-	.set_rate = &pll160_set_rate,
-	.scale_reg = USBCTRL_REG,
-	.enable_reg = USBCTRL_REG,
-	.enable_shift = 18,
-	.enable_reg1 = USBCTRL_REG,
-	.enable_shift1 = 17,
-};
-
-/* XPERTTeak DSP PLL */
-static struct clk ck_pll3 = {
-	.name = "ck_pll3",
-	.parent = &ck_pll1,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &pll3_round_rate,
-	.set_rate = &pll160_set_rate,
-	.scale_reg = DSPPLLCTRL_REG,
-	.enable_reg = DSPCLKCTRL_REG,
-	.enable_shift = 3,
-	.enable_reg1 = DSPCLKCTRL_REG,
-	.enable_shift1 = 2,
-	.parent_switch_reg = DSPCLKCTRL_REG,
-	.set_parent = &set_13MHz_parent,
-};
-
-static struct clk hclk_ck = {
-	.name = "hclk_ck",
-	.parent = &ck_pll4,
-	.flags = PARENT_SET_RATE,
-	.set_rate = &hclk_set_rate,
-	.round_rate = &hclk_round_rate,
-	.scale_reg = HCLKDIVCTRL_REG,
-	.rate = 2,
-	.user_rate = 2,
-};
-
-static struct clk per_ck = {
-	.name = "per_ck",
-	.parent = &ck_pll4,
-	.flags = FIXED_RATE,
-	.propagate_next = &hclk_ck,
-	.set_rate = &per_clk_set_rate,
-	.round_rate = &per_clk_round_rate,
-	.scale_reg = HCLKDIVCTRL_REG,
-	.rate = CLK_RATE_13MHZ,
-	.user_rate = CLK_RATE_13MHZ,
-};
-
-static struct clk m2hclk_ck = {
-	.name = "m2hclk_ck",
-	.parent = &hclk_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_inv_set_rate,
-	.rate = 1,
-	.enable_shift = 6,
-	.enable_reg = PWRCTRL_REG,
-};
-
-static struct clk vfp9_ck = {
-	.name = "vfp9_ck",
-	.parent = &ck_pll4,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.rate = 1,
-	.enable_shift = 4,
-	.enable_reg = VFP9CLKCTRL_REG,
-};
-
-static struct clk keyscan_ck = {
-	.name = "keyscan_ck",
-	.parent = &osc_32KHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = KEYCLKCTRL_REG,
-};
-
-static struct clk touch_ck = {
-	.name = "touch_ck",
-	.parent = &osc_32KHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = TSCLKCTRL_REG,
-};
-
-static struct clk pwm1_ck = {
-	.name = "pwm1_ck",
-	.parent = &osc_32KHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = PWMCLKCTRL_REG,
-};
-
-static struct clk pwm2_ck = {
-	.name = "pwm2_ck",
-	.parent = &osc_32KHz,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 2,
-	.enable_reg = PWMCLKCTRL_REG,
-};
-
-static struct clk jpeg_ck = {
-	.name = "jpeg_ck",
-	.parent = &hclk_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = JPEGCLKCTRL_REG,
-};
-
-static struct clk ms_ck = {
-	.name = "ms_ck",
-	.parent = &ck_pll4,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 5,
-	.enable_reg = MSCTRL_REG,
-};
-
-static struct clk dum_ck = {
-	.name = "dum_ck",
-	.parent = &hclk_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = DUMCLKCTRL_REG,
-};
-
-static struct clk flash_ck = {
-	.name = "flash_ck",
-	.parent = &hclk_ck,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 1,	/* Only MLC clock supported */
-	.enable_reg = FLASHCLKCTRL_REG,
-};
-
-static struct clk i2c0_ck = {
-	.name = "i2c0_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION | FIXED_RATE,
-	.enable_shift = 0,
-	.enable_reg = I2CCLKCTRL_REG,
-	.rate = 13000000,
-	.enable = clk_reg_enable,
-	.disable = clk_reg_disable,
-};
-
-static struct clk i2c1_ck = {
-	.name = "i2c1_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION | FIXED_RATE,
-	.enable_shift = 1,
-	.enable_reg = I2CCLKCTRL_REG,
-	.rate = 13000000,
-	.enable = clk_reg_enable,
-	.disable = clk_reg_disable,
-};
-
-static struct clk i2c2_ck = {
-	.name = "i2c2_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION | FIXED_RATE,
-	.enable_shift = 2,
-	.enable_reg = USB_OTG_CLKCTRL_REG,
-	.rate = 13000000,
-	.enable = clk_reg_enable,
-	.disable = clk_reg_disable,
-};
-
-static struct clk spi0_ck = {
-	.name = "spi0_ck",
-	.parent = &hclk_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = SPICTRL_REG,
-};
-
-static struct clk spi1_ck = {
-	.name = "spi1_ck",
-	.parent = &hclk_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 4,
-	.enable_reg = SPICTRL_REG,
-};
-
-static struct clk dma_ck = {
-	.name = "dma_ck",
-	.parent = &hclk_ck,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 0,
-	.enable_reg = DMACLKCTRL_REG,
-};
-
-static struct clk uart3_ck = {
-	.name = "uart3_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.rate = 1,
-	.enable_shift = 0,
-	.enable_reg = UARTCLKCTRL_REG,
-};
-
-static struct clk uart4_ck = {
-	.name = "uart4_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 1,
-	.enable_reg = UARTCLKCTRL_REG,
-};
-
-static struct clk uart5_ck = {
-	.name = "uart5_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.rate = 1,
-	.enable_shift = 2,
-	.enable_reg = UARTCLKCTRL_REG,
-};
-
-static struct clk uart6_ck = {
-	.name = "uart6_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.round_rate = &on_off_round_rate,
-	.set_rate = &on_off_set_rate,
-	.enable_shift = 3,
-	.enable_reg = UARTCLKCTRL_REG,
-};
-
-static struct clk wdt_ck = {
-	.name = "wdt_ck",
-	.parent = &per_ck,
-	.flags = NEEDS_INITIALIZATION,
-	.enable_shift = 0,
-	.enable_reg = TIMCLKCTRL_REG,
-	.enable = clk_reg_enable,
-	.disable = clk_reg_disable,
-};
-
-/* These clocks are visible outside this module
- * and can be initialized
- */
-static struct clk *onchip_clks[] __initdata = {
-	&ck_13MHz,
-	&ck_pll1,
-	&ck_pll4,
-	&ck_pll5,
-	&ck_pll3,
-	&vfp9_ck,
-	&m2hclk_ck,
-	&hclk_ck,
-	&dma_ck,
-	&flash_ck,
-	&dum_ck,
-	&keyscan_ck,
-	&pwm1_ck,
-	&pwm2_ck,
-	&jpeg_ck,
-	&ms_ck,
-	&touch_ck,
-	&i2c0_ck,
-	&i2c1_ck,
-	&i2c2_ck,
-	&spi0_ck,
-	&spi1_ck,
-	&uart3_ck,
-	&uart4_ck,
-	&uart5_ck,
-	&uart6_ck,
-	&wdt_ck,
-};
-
-static struct clk_lookup onchip_clkreg[] = {
-	{ .clk = &ck_13MHz,	.con_id = "ck_13MHz"	},
-	{ .clk = &ck_pll1,	.con_id = "ck_pll1"	},
-	{ .clk = &ck_pll4,	.con_id = "ck_pll4"	},
-	{ .clk = &ck_pll5,	.con_id = "ck_pll5"	},
-	{ .clk = &ck_pll3,	.con_id = "ck_pll3"	},
-	{ .clk = &vfp9_ck,	.con_id = "vfp9_ck"	},
-	{ .clk = &m2hclk_ck,	.con_id = "m2hclk_ck"	},
-	{ .clk = &hclk_ck,	.con_id = "hclk_ck"	},
-	{ .clk = &dma_ck,	.con_id = "dma_ck"	},
-	{ .clk = &flash_ck,	.con_id = "flash_ck"	},
-	{ .clk = &dum_ck,	.con_id = "dum_ck"	},
-	{ .clk = &keyscan_ck,	.con_id = "keyscan_ck"	},
-	{ .clk = &pwm1_ck,	.con_id = "pwm1_ck"	},
-	{ .clk = &pwm2_ck,	.con_id = "pwm2_ck"	},
-	{ .clk = &jpeg_ck,	.con_id = "jpeg_ck"	},
-	{ .clk = &ms_ck,	.con_id = "ms_ck"	},
-	{ .clk = &touch_ck,	.con_id = "touch_ck"	},
-	{ .clk = &i2c0_ck,	.dev_id = "pnx-i2c.0"	},
-	{ .clk = &i2c1_ck,	.dev_id = "pnx-i2c.1"	},
-	{ .clk = &i2c2_ck,	.dev_id = "pnx-i2c.2"	},
-	{ .clk = &spi0_ck,	.con_id = "spi0_ck"	},
-	{ .clk = &spi1_ck,	.con_id = "spi1_ck"	},
-	{ .clk = &uart3_ck,	.con_id = "uart3_ck"	},
-	{ .clk = &uart4_ck,	.con_id = "uart4_ck"	},
-	{ .clk = &uart5_ck,	.con_id = "uart5_ck"	},
-	{ .clk = &uart6_ck,	.con_id = "uart6_ck"	},
-	{ .clk = &wdt_ck,	.dev_id = "pnx4008-watchdog" },
-};
-
-static void local_clk_disable(struct clk *clk)
-{
-	if (WARN_ON(clk->usecount == 0))
-		return;
-
-	if (!(--clk->usecount)) {
-		if (clk->disable)
-			clk->disable(clk);
-		else if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
-			clk->set_rate(clk, 0);
-		if (clk->parent)
-			local_clk_disable(clk->parent);
-	}
-}
-
-static int local_clk_enable(struct clk *clk)
-{
-	int ret = 0;
-
-	if (clk->usecount == 0) {
-		if (clk->parent) {
-			ret = local_clk_enable(clk->parent);
-			if (ret != 0)
-				goto out;
-		}
-
-		if (clk->enable)
-			ret = clk->enable(clk);
-		else if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
-			    && clk->user_rate)
-			ret = clk->set_rate(clk, clk->user_rate);
-
-		if (ret != 0 && clk->parent) {
-			local_clk_disable(clk->parent);
-			goto out;
-		}
-
-		clk->usecount++;
-	}
-out:
-	return ret;
-}
-
-static int local_set_rate(struct clk *clk, u32 rate)
-{
-	int ret = -EINVAL;
-	if (clk->set_rate) {
-
-		if (clk->user_rate == clk->rate && clk->parent->rate) {
-			/* if clock enabled or rate not set */
-			clk->user_rate = clk->round_rate(clk, rate);
-			ret = clk->set_rate(clk, clk->user_rate);
-		} else
-			clk->user_rate = clk->round_rate(clk, rate);
-		ret = 0;
-	}
-	return ret;
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	int ret = -EINVAL;
-
-	if (clk->flags & FIXED_RATE)
-		goto out;
-
-	clock_lock();
-	if ((clk->flags & PARENT_SET_RATE) && clk->parent) {
-
-		clk->user_rate = clk->round_rate(clk, rate);
-		/* parent clock needs to be refreshed
-		   for the setting to take effect */
-	} else {
-		ret = local_set_rate(clk, rate);
-	}
-	ret = 0;
-	clock_unlock();
-
-out:
-	return ret;
-}
-
-EXPORT_SYMBOL(clk_set_rate);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-	unsigned long ret;
-	clock_lock();
-	ret = clk->rate;
-	clock_unlock();
-	return ret;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_enable(struct clk *clk)
-{
-	int ret;
-
-	clock_lock();
-	ret = local_clk_enable(clk);
-	clock_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-	clock_lock();
-	local_clk_disable(clk);
-	clock_unlock();
-}
-
-EXPORT_SYMBOL(clk_disable);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-	long ret;
-	clock_lock();
-	if (clk->round_rate)
-		ret = clk->round_rate(clk, rate);
-	else
-		ret = clk->rate;
-	clock_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	int ret = -ENODEV;
-	if (!clk->set_parent)
-		goto out;
-
-	clock_lock();
-	ret = clk->set_parent(clk, parent);
-	if (!ret)
-		clk->parent = parent;
-	clock_unlock();
-
-out:
-	return ret;
-}
-
-EXPORT_SYMBOL(clk_set_parent);
-
-static int __init clk_init(void)
-{
-	struct clk **clkp;
-
-	/* Disable autoclocking, as it doesn't seem to work */
-	__raw_writel(0xff, AUTOCLK_CTRL);
-
-	for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
-	     clkp++) {
-		struct clk *clk = *clkp;
-		if (clk->flags & NEEDS_INITIALIZATION) {
-			if (clk->set_rate) {
-				clk->user_rate = clk->rate;
-				local_set_rate(clk, clk->user_rate);
-				if (clk->set_parent)
-					clk->set_parent(clk, clk->parent);
-			}
-			if (clk->enable && clk->usecount)
-				clk->enable(clk);
-			if (clk->disable && !clk->usecount)
-				clk->disable(clk);
-		}
-		pr_debug("%s: clock %s, rate %ld\n",
-			__func__, clk->name, clk->rate);
-	}
-
-	local_clk_enable(&ck_pll4);
-
-	/* if ck_13MHz is not used, disable it. */
-	if (ck_13MHz.usecount == 0)
-		local_clk_disable(&ck_13MHz);
-
-	/* Disable autoclocking */
-	__raw_writeb(0xff, AUTOCLK_CTRL);
-
-	clkdev_add_table(onchip_clkreg, ARRAY_SIZE(onchip_clkreg));
-
-	return 0;
-}
-
-arch_initcall(clk_init);
diff --git a/arch/arm/mach-pnx4008/clock.h b/arch/arm/mach-pnx4008/clock.h
deleted file mode 100644
index 39720d6..0000000
--- a/arch/arm/mach-pnx4008/clock.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/clock.h
- *
- * Clock control driver for PNX4008 - internal header file
- *
- * Author: Vitaly Wool <source@mvista.com>
- *
- * 2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ARCH_ARM_PNX4008_CLOCK_H__
-#define __ARCH_ARM_PNX4008_CLOCK_H__
-
-struct clk {
-	const char *name;
-	struct clk *parent;
-	struct clk *propagate_next;
-	u32 rate;
-	u32 user_rate;
-	s8 usecount;
-	u32 flags;
-	u32 scale_reg;
-	u8 enable_shift;
-	u32 enable_reg;
-	u8 enable_shift1;
-	u32 enable_reg1;
-	u32 parent_switch_reg;
-	u32(*round_rate) (struct clk *, u32);
-	int (*set_rate) (struct clk *, u32);
-	int (*set_parent) (struct clk * clk, struct clk * parent);
-	int (*enable)(struct clk *);
-	void (*disable)(struct clk *);
-};
-
-/* Flags */
-#define RATE_PROPAGATES      (1<<0)
-#define NEEDS_INITIALIZATION (1<<1)
-#define PARENT_SET_RATE      (1<<2)
-#define FIXED_RATE           (1<<3)
-
-#endif
diff --git a/arch/arm/mach-pnx4008/core.c b/arch/arm/mach-pnx4008/core.c
deleted file mode 100644
index a00d2f1..0000000
--- a/arch/arm/mach-pnx4008/core.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/core.c
- *
- * PNX4008 core startup code
- *
- * Authors: Vitaly Wool, Dmitry Chigirev,
- * Grigory Tolstolytkin, Dmitry Pervushin <source@mvista.com>
- *
- * Based on reference code received from Philips:
- * Copyright (C) 2003 Philips Semiconductors
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/system_misc.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include <mach/irq.h>
-#include <mach/clock.h>
-#include <mach/dma.h>
-
-struct resource spipnx_0_resources[] = {
-	{
-		.start = PNX4008_SPI1_BASE,
-		.end = PNX4008_SPI1_BASE + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = PER_SPI1_REC_XMIT,
-		.flags = IORESOURCE_DMA,
-	}, {
-		.start = SPI1_INT,
-		.flags = IORESOURCE_IRQ,
-	}, {
-		.flags = 0,
-	},
-};
-
-struct resource spipnx_1_resources[] = {
-	{
-		.start = PNX4008_SPI2_BASE,
-		.end = PNX4008_SPI2_BASE + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = PER_SPI2_REC_XMIT,
-		.flags = IORESOURCE_DMA,
-	}, {
-		.start = SPI2_INT,
-		.flags = IORESOURCE_IRQ,
-	}, {
-		.flags = 0,
-	}
-};
-
-static struct spi_board_info spi_board_info[] __initdata = {
-	{
-		.modalias	= "m25p80",
-		.max_speed_hz	= 1000000,
-		.bus_num	= 1,
-		.chip_select	= 0,
-	},
-};
-
-static struct platform_device spipnx_1 = {
-	.name = "spipnx",
-	.id = 1,
-	.num_resources = ARRAY_SIZE(spipnx_0_resources),
-	.resource = spipnx_0_resources,
-	.dev = {
-		.coherent_dma_mask = 0xFFFFFFFF,
-		},
-};
-
-static struct platform_device spipnx_2 = {
-	.name = "spipnx",
-	.id = 2,
-	.num_resources = ARRAY_SIZE(spipnx_1_resources),
-	.resource = spipnx_1_resources,
-	.dev = {
-		.coherent_dma_mask = 0xFFFFFFFF,
-		},
-};
-
-static struct plat_serial8250_port platform_serial_ports[] = {
-	{
-		.membase = (void *)__iomem(IO_ADDRESS(PNX4008_UART5_BASE)),
-		.mapbase = (unsigned long)PNX4008_UART5_BASE,
-		.irq = IIR5_INT,
-		.uartclk = PNX4008_UART_CLK,
-		.regshift = 2,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST,
-	},
-	{
-		.membase = (void *)__iomem(IO_ADDRESS(PNX4008_UART3_BASE)),
-		.mapbase = (unsigned long)PNX4008_UART3_BASE,
-		.irq = IIR3_INT,
-		.uartclk = PNX4008_UART_CLK,
-		.regshift = 2,
-		.iotype = UPIO_MEM,
-		.flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST,
-	 },
-	{}
-};
-
-static struct platform_device serial_device = {
-	.name = "serial8250",
-	.id = PLAT8250_DEV_PLATFORM,
-	.dev = {
-		.platform_data = &platform_serial_ports,
-	},
-};
-
-static struct platform_device nand_flash_device = {
-	.name = "pnx4008-flash",
-	.id = -1,
-	.dev = {
-		.coherent_dma_mask = 0xFFFFFFFF,
-	},
-};
-
-/* The dmamask must be set for OHCI to work */
-static u64 ohci_dmamask = ~(u32) 0;
-
-static struct resource ohci_resources[] = {
-	{
-		.start = IO_ADDRESS(PNX4008_USB_CONFIG_BASE),
-		.end = IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x100),
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = USB_HOST_INT,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device ohci_device = {
-	.name = "pnx4008-usb-ohci",
-	.id = -1,
-	.dev = {
-		.dma_mask = &ohci_dmamask,
-		.coherent_dma_mask = 0xffffffff,
-		},
-	.num_resources = ARRAY_SIZE(ohci_resources),
-	.resource = ohci_resources,
-};
-
-static struct platform_device sdum_device = {
-	.name = "pnx4008-sdum",
-	.id = 0,
-	.dev = {
-		.coherent_dma_mask = 0xffffffff,
-	},
-};
-
-static struct platform_device rgbfb_device = {
-	.name = "pnx4008-rgbfb",
-	.id = 0,
-	.dev = {
-		.coherent_dma_mask = 0xffffffff,
-	}
-};
-
-struct resource watchdog_resources[] = {
-	{
-		.start = PNX4008_WDOG_BASE,
-		.end = PNX4008_WDOG_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device watchdog_device = {
-	.name = "pnx4008-watchdog",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(watchdog_resources),
-	.resource = watchdog_resources,
-};
-
-static struct platform_device *devices[] __initdata = {
-	&spipnx_1,
-	&spipnx_2,
-	&serial_device,
-	&ohci_device,
-	&nand_flash_device,
-	&sdum_device,
-	&rgbfb_device,
-	&watchdog_device,
-};
-
-
-extern void pnx4008_uart_init(void);
-
-static void __init pnx4008_init(void)
-{
-	/*disable all START interrupt sources,
-	   and clear all START interrupt flags */
-	__raw_writel(0, START_INT_ER_REG(SE_PIN_BASE_INT));
-	__raw_writel(0, START_INT_ER_REG(SE_INT_BASE_INT));
-	__raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT));
-	__raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT));
-
-	platform_add_devices(devices, ARRAY_SIZE(devices));
-	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
-	/* Switch on the UART clocks */
-	pnx4008_uart_init();
-}
-
-static struct map_desc pnx4008_io_desc[] __initdata = {
-	{
-		.virtual 	= IO_ADDRESS(PNX4008_IRAM_BASE),
-		.pfn 		= __phys_to_pfn(PNX4008_IRAM_BASE),
-		.length		= SZ_64K,
-		.type 		= MT_DEVICE,
-	}, {
-		.virtual 	= IO_ADDRESS(PNX4008_NDF_FLASH_BASE),
-		.pfn 		= __phys_to_pfn(PNX4008_NDF_FLASH_BASE),
-		.length		= SZ_1M - SZ_128K,
-		.type 		= MT_DEVICE,
-	}, {
-		.virtual 	= IO_ADDRESS(PNX4008_JPEG_CONFIG_BASE),
-		.pfn 		= __phys_to_pfn(PNX4008_JPEG_CONFIG_BASE),
-		.length		= SZ_128K * 3,
-		.type 		= MT_DEVICE,
-	}, {
-		.virtual 	= IO_ADDRESS(PNX4008_DMA_CONFIG_BASE),
-		.pfn 		= __phys_to_pfn(PNX4008_DMA_CONFIG_BASE),
-		.length		= SZ_1M,
-		.type 		= MT_DEVICE,
-	}, {
-		.virtual 	= IO_ADDRESS(PNX4008_AHB2FAB_BASE),
-		.pfn 		= __phys_to_pfn(PNX4008_AHB2FAB_BASE),
-		.length		= SZ_1M,
-		.type 		= MT_DEVICE,
-	},
-};
-
-void __init pnx4008_map_io(void)
-{
-	iotable_init(pnx4008_io_desc, ARRAY_SIZE(pnx4008_io_desc));
-}
-
-static void pnx4008_restart(char mode, const char *cmd)
-{
-	soft_restart(0);
-}
-
-#ifdef CONFIG_PM
-extern int pnx4008_pm_init(void);
-#else
-static inline int pnx4008_pm_init(void) { return 0; }
-#endif
-
-void __init pnx4008_init_late(void)
-{
-	pnx4008_pm_init();
-}
-
-extern struct sys_timer pnx4008_timer;
-
-MACHINE_START(PNX4008, "Philips PNX4008")
-	/* Maintainer: MontaVista Software Inc. */
-	.atag_offset		= 0x100,
-	.map_io 		= pnx4008_map_io,
-	.init_irq 		= pnx4008_init_irq,
-	.init_machine 		= pnx4008_init,
-	.init_late		= pnx4008_init_late,
-	.timer 			= &pnx4008_timer,
-	.restart		= pnx4008_restart,
-MACHINE_END
diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
deleted file mode 100644
index a4739e9..0000000
--- a/arch/arm/mach-pnx4008/dma.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- *  linux/arch/arm/mach-pnx4008/dma.c
- *
- *  PNX4008 DMA registration and IRQ dispatching
- *
- *  Author:	Vitaly Wool
- *  Copyright:	MontaVista Software Inc. (c) 2005
- *
- *  Based on the code from Nicolas Pitre
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gfp.h>
-
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <asm/dma-mapping.h>
-#include <mach/clock.h>
-
-static struct dma_channel {
-	char *name;
-	void (*irq_handler) (int, int, void *);
-	void *data;
-	struct pnx4008_dma_ll *ll;
-	u32 ll_dma;
-	void *target_addr;
-	int target_id;
-} dma_channels[MAX_DMA_CHANNELS];
-
-static struct ll_pool {
-	void *vaddr;
-	void *cur;
-	dma_addr_t dma_addr;
-	int count;
-} ll_pool;
-
-static DEFINE_SPINLOCK(ll_lock);
-
-struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
-{
-	struct pnx4008_dma_ll *ll = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ll_lock, flags);
-	if (ll_pool.count > 4) { /* can give one more */
-		ll = *(struct pnx4008_dma_ll **) ll_pool.cur;
-		*ll_dma = ll_pool.dma_addr + ((void *)ll - ll_pool.vaddr);
-		*(void **)ll_pool.cur = **(void ***)ll_pool.cur;
-		memset(ll, 0, sizeof(*ll));
-		ll_pool.count--;
-	}
-	spin_unlock_irqrestore(&ll_lock, flags);
-
-	return ll;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
-
-void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
-{
-	unsigned long flags;
-
-	if (ll) {
-		if ((unsigned long)((long)ll - (long)ll_pool.vaddr) > 0x4000) {
-			printk(KERN_ERR "Trying to free entry not allocated by DMA\n");
-			BUG();
-		}
-
-		if (ll->flags & DMA_BUFFER_ALLOCATED)
-			ll->free(ll->alloc_data);
-
-		spin_lock_irqsave(&ll_lock, flags);
-		*(long *)ll = *(long *)ll_pool.cur;
-		*(long *)ll_pool.cur = (long)ll;
-		ll_pool.count++;
-		spin_unlock_irqrestore(&ll_lock, flags);
-	}
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
-
-void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
-{
-	struct pnx4008_dma_ll *ptr;
-	u32 dma;
-
-	while (ll) {
-		dma = ll->next_dma;
-		ptr = ll->next;
-		pnx4008_free_ll_entry(ll, ll_dma);
-
-		ll_dma = dma;
-		ll = ptr;
-	}
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_free_ll);
-
-static int dma_channels_requested = 0;
-
-static inline void dma_increment_usage(void)
-{
-	if (!dma_channels_requested++) {
-		struct clk *clk = clk_get(0, "dma_ck");
-		if (!IS_ERR(clk)) {
-			clk_set_rate(clk, 1);
-			clk_put(clk);
-		}
-		pnx4008_config_dma(-1, -1, 1);
-	}
-}
-static inline void dma_decrement_usage(void)
-{
-	if (!--dma_channels_requested) {
-		struct clk *clk = clk_get(0, "dma_ck");
-		if (!IS_ERR(clk)) {
-			clk_set_rate(clk, 0);
-			clk_put(clk);
-		}
-		pnx4008_config_dma(-1, -1, 0);
-
-	}
-}
-
-static DEFINE_SPINLOCK(dma_lock);
-
-static inline void pnx4008_dma_lock(void)
-{
-	spin_lock_irq(&dma_lock);
-}
-
-static inline void pnx4008_dma_unlock(void)
-{
-	spin_unlock_irq(&dma_lock);
-}
-
-#define VALID_CHANNEL(c)	(((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
-
-int pnx4008_request_channel(char *name, int ch,
-			    void (*irq_handler) (int, int, void *), void *data)
-{
-	int i, found = 0;
-
-	/* basic sanity checks */
-	if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-
-	/* try grabbing a DMA channel with the requested priority */
-	for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
-		if (!dma_channels[i].name && (ch == -1 || ch == i)) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (found) {
-		dma_increment_usage();
-		dma_channels[i].name = name;
-		dma_channels[i].irq_handler = irq_handler;
-		dma_channels[i].data = data;
-		dma_channels[i].ll = NULL;
-		dma_channels[i].ll_dma = 0;
-	} else {
-		printk(KERN_WARNING "No more available DMA channels for %s\n",
-		       name);
-		i = -ENODEV;
-	}
-
-	pnx4008_dma_unlock();
-	return i;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_request_channel);
-
-void pnx4008_free_channel(int ch)
-{
-	if (!dma_channels[ch].name) {
-		printk(KERN_CRIT
-		       "%s: trying to free channel %d which is already freed\n",
-		       __func__, ch);
-		return;
-	}
-
-	pnx4008_dma_lock();
-	pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
-	dma_channels[ch].ll = NULL;
-	dma_decrement_usage();
-
-	dma_channels[ch].name = NULL;
-	pnx4008_dma_unlock();
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_free_channel);
-
-int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
-{
-	unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
-
-	switch (ahb_m1_be) {
-	case 0:
-		dma_cfg &= ~(1 << 1);
-		break;
-	case 1:
-		dma_cfg |= (1 << 1);
-		break;
-	default:
-		break;
-	}
-
-	switch (ahb_m2_be) {
-	case 0:
-		dma_cfg &= ~(1 << 2);
-		break;
-	case 1:
-		dma_cfg |= (1 << 2);
-		break;
-	default:
-		break;
-	}
-
-	switch (enable) {
-	case 0:
-		dma_cfg &= ~(1 << 0);
-		break;
-	case 1:
-		dma_cfg |= (1 << 0);
-		break;
-	default:
-		break;
-	}
-
-	pnx4008_dma_lock();
-	__raw_writel(dma_cfg, DMAC_CONFIG);
-	pnx4008_dma_unlock();
-
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_config_dma);
-
-int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
-			     unsigned long *ctrl)
-{
-	int i = 0, dbsize, sbsize, err = 0;
-
-	if (!ctrl || !ch_ctrl) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	*ctrl = 0;
-
-	switch (ch_ctrl->tc_mask) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 31);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-
-	switch (ch_ctrl->cacheable) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 30);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->bufferable) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 29);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->priv_mode) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 28);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->di) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 27);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->si) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 26);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->dest_ahb1) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 25);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->src_ahb1) {
-	case 0:
-		break;
-	case 1:
-		*ctrl |= (1 << 24);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->dwidth) {
-	case WIDTH_BYTE:
-		*ctrl &= ~(7 << 21);
-		break;
-	case WIDTH_HWORD:
-		*ctrl &= ~(7 << 21);
-		*ctrl |= (1 << 21);
-		break;
-	case WIDTH_WORD:
-		*ctrl &= ~(7 << 21);
-		*ctrl |= (2 << 21);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_ctrl->swidth) {
-	case WIDTH_BYTE:
-		*ctrl &= ~(7 << 18);
-		break;
-	case WIDTH_HWORD:
-		*ctrl &= ~(7 << 18);
-		*ctrl |= (1 << 18);
-		break;
-	case WIDTH_WORD:
-		*ctrl &= ~(7 << 18);
-		*ctrl |= (2 << 18);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	dbsize = ch_ctrl->dbsize;
-	while (!(dbsize & 1)) {
-		i++;
-		dbsize >>= 1;
-	}
-	if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
-		err = -EINVAL;
-		goto out;
-	} else if (i > 1)
-		i--;
-	*ctrl &= ~(7 << 15);
-	*ctrl |= (i << 15);
-
-	sbsize = ch_ctrl->sbsize;
-	while (!(sbsize & 1)) {
-		i++;
-		sbsize >>= 1;
-	}
-	if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
-		err = -EINVAL;
-		goto out;
-	} else if (i > 1)
-		i--;
-	*ctrl &= ~(7 << 12);
-	*ctrl |= (i << 12);
-
-	if (ch_ctrl->tr_size > 0x7ff) {
-		err = -E2BIG;
-		goto out;
-	}
-	*ctrl &= ~0x7ff;
-	*ctrl |= ch_ctrl->tr_size & 0x7ff;
-
-out:
-	return err;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
-
-int pnx4008_dma_parse_control(unsigned long ctrl,
-			      struct pnx4008_dma_ch_ctrl * ch_ctrl)
-{
-	int err = 0;
-
-	if (!ch_ctrl) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	ch_ctrl->tr_size = ctrl & 0x7ff;
-	ctrl >>= 12;
-
-	ch_ctrl->sbsize = 1 << (ctrl & 7);
-	if (ch_ctrl->sbsize > 1)
-		ch_ctrl->sbsize <<= 1;
-	ctrl >>= 3;
-
-	ch_ctrl->dbsize = 1 << (ctrl & 7);
-	if (ch_ctrl->dbsize > 1)
-		ch_ctrl->dbsize <<= 1;
-	ctrl >>= 3;
-
-	switch (ctrl & 7) {
-	case 0:
-		ch_ctrl->swidth = WIDTH_BYTE;
-		break;
-	case 1:
-		ch_ctrl->swidth = WIDTH_HWORD;
-		break;
-	case 2:
-		ch_ctrl->swidth = WIDTH_WORD;
-		break;
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	ctrl >>= 3;
-
-	switch (ctrl & 7) {
-	case 0:
-		ch_ctrl->dwidth = WIDTH_BYTE;
-		break;
-	case 1:
-		ch_ctrl->dwidth = WIDTH_HWORD;
-		break;
-	case 2:
-		ch_ctrl->dwidth = WIDTH_WORD;
-		break;
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	ctrl >>= 3;
-
-	ch_ctrl->src_ahb1 = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->dest_ahb1 = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->si = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->di = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->priv_mode = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->bufferable = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->cacheable = ctrl & 1;
-	ctrl >>= 1;
-
-	ch_ctrl->tc_mask = ctrl & 1;
-
-out:
-	return err;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
-
-int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
-			    unsigned long *cfg)
-{
-	int err = 0;
-
-	if (!cfg || !ch_cfg) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	*cfg = 0;
-
-	switch (ch_cfg->halt) {
-	case 0:
-		break;
-	case 1:
-		*cfg |= (1 << 18);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_cfg->active) {
-	case 0:
-		break;
-	case 1:
-		*cfg |= (1 << 17);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_cfg->lock) {
-	case 0:
-		break;
-	case 1:
-		*cfg |= (1 << 16);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_cfg->itc) {
-	case 0:
-		break;
-	case 1:
-		*cfg |= (1 << 15);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_cfg->ie) {
-	case 0:
-		break;
-	case 1:
-		*cfg |= (1 << 14);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	switch (ch_cfg->flow_cntrl) {
-	case FC_MEM2MEM_DMA:
-		*cfg &= ~(7 << 11);
-		break;
-	case FC_MEM2PER_DMA:
-		*cfg &= ~(7 << 11);
-		*cfg |= (1 << 11);
-		break;
-	case FC_PER2MEM_DMA:
-		*cfg &= ~(7 << 11);
-		*cfg |= (2 << 11);
-		break;
-	case FC_PER2PER_DMA:
-		*cfg &= ~(7 << 11);
-		*cfg |= (3 << 11);
-		break;
-	case FC_PER2PER_DPER:
-		*cfg &= ~(7 << 11);
-		*cfg |= (4 << 11);
-		break;
-	case FC_MEM2PER_PER:
-		*cfg &= ~(7 << 11);
-		*cfg |= (5 << 11);
-		break;
-	case FC_PER2MEM_PER:
-		*cfg &= ~(7 << 11);
-		*cfg |= (6 << 11);
-		break;
-	case FC_PER2PER_SPER:
-		*cfg |= (7 << 11);
-		break;
-
-	default:
-		err = -EINVAL;
-		goto out;
-	}
-	*cfg &= ~(0x1f << 6);
-	*cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
-
-	*cfg &= ~(0x1f << 1);
-	*cfg |= ((ch_cfg->src_per & 0x1f) << 1);
-
-out:
-	return err;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
-
-int pnx4008_dma_parse_config(unsigned long cfg,
-			     struct pnx4008_dma_ch_config * ch_cfg)
-{
-	int err = 0;
-
-	if (!ch_cfg) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	cfg >>= 1;
-
-	ch_cfg->src_per = cfg & 0x1f;
-	cfg >>= 5;
-
-	ch_cfg->dest_per = cfg & 0x1f;
-	cfg >>= 5;
-
-	switch (cfg & 7) {
-	case 0:
-		ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
-		break;
-	case 1:
-		ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
-		break;
-	case 2:
-		ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
-		break;
-	case 3:
-		ch_cfg->flow_cntrl = FC_PER2PER_DMA;
-		break;
-	case 4:
-		ch_cfg->flow_cntrl = FC_PER2PER_DPER;
-		break;
-	case 5:
-		ch_cfg->flow_cntrl = FC_MEM2PER_PER;
-		break;
-	case 6:
-		ch_cfg->flow_cntrl = FC_PER2MEM_PER;
-		break;
-	case 7:
-		ch_cfg->flow_cntrl = FC_PER2PER_SPER;
-	}
-	cfg >>= 3;
-
-	ch_cfg->ie = cfg & 1;
-	cfg >>= 1;
-
-	ch_cfg->itc = cfg & 1;
-	cfg >>= 1;
-
-	ch_cfg->lock = cfg & 1;
-	cfg >>= 1;
-
-	ch_cfg->active = cfg & 1;
-	cfg >>= 1;
-
-	ch_cfg->halt = cfg & 1;
-
-out:
-	return err;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
-
-void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
-				  struct pnx4008_dma_ch_ctrl * ctrl)
-{
-	int new_len = ctrl->tr_size, num_entries = 0;
-	int old_len = new_len;
-	int src_width, dest_width, count = 1;
-
-	switch (ctrl->swidth) {
-	case WIDTH_BYTE:
-		src_width = 1;
-		break;
-	case WIDTH_HWORD:
-		src_width = 2;
-		break;
-	case WIDTH_WORD:
-		src_width = 4;
-		break;
-	default:
-		return;
-	}
-
-	switch (ctrl->dwidth) {
-	case WIDTH_BYTE:
-		dest_width = 1;
-		break;
-	case WIDTH_HWORD:
-		dest_width = 2;
-		break;
-	case WIDTH_WORD:
-		dest_width = 4;
-		break;
-	default:
-		return;
-	}
-
-	while (new_len > 0x7FF) {
-		num_entries++;
-		new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
-	}
-	if (num_entries != 0) {
-		struct pnx4008_dma_ll *ll = NULL;
-		config->ch_ctrl &= ~0x7ff;
-		config->ch_ctrl |= new_len;
-		if (!config->is_ll) {
-			config->is_ll = 1;
-			while (num_entries) {
-				if (!ll) {
-					config->ll =
-					    pnx4008_alloc_ll_entry(&config->
-								   ll_dma);
-					ll = config->ll;
-				} else {
-					ll->next =
-					    pnx4008_alloc_ll_entry(&ll->
-								   next_dma);
-					ll = ll->next;
-				}
-
-				if (ctrl->si)
-					ll->src_addr =
-					    config->src_addr +
-					    src_width * new_len * count;
-				else
-					ll->src_addr = config->src_addr;
-				if (ctrl->di)
-					ll->dest_addr =
-					    config->dest_addr +
-					    dest_width * new_len * count;
-				else
-					ll->dest_addr = config->dest_addr;
-				ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
-				ll->next_dma = 0;
-				ll->next = NULL;
-				num_entries--;
-				count++;
-			}
-		} else {
-			struct pnx4008_dma_ll *ll_old = config->ll;
-			unsigned long ll_dma_old = config->ll_dma;
-			while (num_entries) {
-				if (!ll) {
-					config->ll =
-					    pnx4008_alloc_ll_entry(&config->
-								   ll_dma);
-					ll = config->ll;
-				} else {
-					ll->next =
-					    pnx4008_alloc_ll_entry(&ll->
-								   next_dma);
-					ll = ll->next;
-				}
-
-				if (ctrl->si)
-					ll->src_addr =
-					    config->src_addr +
-					    src_width * new_len * count;
-				else
-					ll->src_addr = config->src_addr;
-				if (ctrl->di)
-					ll->dest_addr =
-					    config->dest_addr +
-					    dest_width * new_len * count;
-				else
-					ll->dest_addr = config->dest_addr;
-				ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
-				ll->next_dma = 0;
-				ll->next = NULL;
-				num_entries--;
-				count++;
-			}
-			ll->next_dma = ll_dma_old;
-			ll->next = ll_old;
-		}
-		/* adjust last length/tc */
-		ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
-		ll->ch_ctrl |= old_len - new_len * (count - 1);
-		config->ch_ctrl &= 0x7fffffff;
-	}
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
-
-void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
-				struct pnx4008_dma_ch_ctrl * ctrl)
-{
-	int new_len = ctrl->tr_size, num_entries = 0;
-	int old_len = new_len;
-	int src_width, dest_width, count = 1;
-
-	switch (ctrl->swidth) {
-	case WIDTH_BYTE:
-		src_width = 1;
-		break;
-	case WIDTH_HWORD:
-		src_width = 2;
-		break;
-	case WIDTH_WORD:
-		src_width = 4;
-		break;
-	default:
-		return;
-	}
-
-	switch (ctrl->dwidth) {
-	case WIDTH_BYTE:
-		dest_width = 1;
-		break;
-	case WIDTH_HWORD:
-		dest_width = 2;
-		break;
-	case WIDTH_WORD:
-		dest_width = 4;
-		break;
-	default:
-		return;
-	}
-
-	while (new_len > 0x7FF) {
-		num_entries++;
-		new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
-	}
-	if (num_entries != 0) {
-		struct pnx4008_dma_ll *ll = NULL;
-		cur_ll->ch_ctrl &= ~0x7ff;
-		cur_ll->ch_ctrl |= new_len;
-		if (!cur_ll->next) {
-			while (num_entries) {
-				if (!ll) {
-					cur_ll->next =
-					    pnx4008_alloc_ll_entry(&cur_ll->
-								   next_dma);
-					ll = cur_ll->next;
-				} else {
-					ll->next =
-					    pnx4008_alloc_ll_entry(&ll->
-								   next_dma);
-					ll = ll->next;
-				}
-
-				if (ctrl->si)
-					ll->src_addr =
-					    cur_ll->src_addr +
-					    src_width * new_len * count;
-				else
-					ll->src_addr = cur_ll->src_addr;
-				if (ctrl->di)
-					ll->dest_addr =
-					    cur_ll->dest_addr +
-					    dest_width * new_len * count;
-				else
-					ll->dest_addr = cur_ll->dest_addr;
-				ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
-				ll->next_dma = 0;
-				ll->next = NULL;
-				num_entries--;
-				count++;
-			}
-		} else {
-			struct pnx4008_dma_ll *ll_old = cur_ll->next;
-			unsigned long ll_dma_old = cur_ll->next_dma;
-			while (num_entries) {
-				if (!ll) {
-					cur_ll->next =
-					    pnx4008_alloc_ll_entry(&cur_ll->
-								   next_dma);
-					ll = cur_ll->next;
-				} else {
-					ll->next =
-					    pnx4008_alloc_ll_entry(&ll->
-								   next_dma);
-					ll = ll->next;
-				}
-
-				if (ctrl->si)
-					ll->src_addr =
-					    cur_ll->src_addr +
-					    src_width * new_len * count;
-				else
-					ll->src_addr = cur_ll->src_addr;
-				if (ctrl->di)
-					ll->dest_addr =
-					    cur_ll->dest_addr +
-					    dest_width * new_len * count;
-				else
-					ll->dest_addr = cur_ll->dest_addr;
-				ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
-				ll->next_dma = 0;
-				ll->next = NULL;
-				num_entries--;
-				count++;
-			}
-
-			ll->next_dma = ll_dma_old;
-			ll->next = ll_old;
-		}
-		/* adjust last length/tc */
-		ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
-		ll->ch_ctrl |= old_len - new_len * (count - 1);
-		cur_ll->ch_ctrl &= 0x7fffffff;
-	}
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
-
-int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
-{
-	if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-	__raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
-	__raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
-
-	if (config->is_ll)
-		__raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
-	else
-		__raw_writel(0, DMAC_Cx_LLI(ch));
-
-	__raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
-	__raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
-	pnx4008_dma_unlock();
-
-	return 0;
-
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_config_channel);
-
-int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
-{
-	if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-	config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
-	config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
-
-	config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
-	config->is_ll = config->ll_dma ? 1 : 0;
-
-	config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
-	config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
-	pnx4008_dma_unlock();
-
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
-
-int pnx4008_dma_ch_enable(int ch)
-{
-	unsigned long ch_cfg;
-
-	if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-	ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
-	ch_cfg |= 1;
-	__raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
-	pnx4008_dma_unlock();
-
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
-
-int pnx4008_dma_ch_disable(int ch)
-{
-	unsigned long ch_cfg;
-
-	if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-	ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
-	ch_cfg &= ~1;
-	__raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
-	pnx4008_dma_unlock();
-
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
-
-int pnx4008_dma_ch_enabled(int ch)
-{
-	unsigned long ch_cfg;
-
-	if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
-		return -EINVAL;
-
-	pnx4008_dma_lock();
-	ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
-	pnx4008_dma_unlock();
-
-	return ch_cfg & 1;
-}
-
-EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-	int i;
-	unsigned long dint = __raw_readl(DMAC_INT_STAT);
-	unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
-	unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
-	unsigned long i_bit;
-
-	for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
-		i_bit = 1 << i;
-		if (dint & i_bit) {
-			struct dma_channel *channel = &dma_channels[i];
-
-			if (channel->name && channel->irq_handler) {
-				int cause = 0;
-
-				if (eint & i_bit)
-					cause |= DMA_ERR_INT;
-				if (tcint & i_bit)
-					cause |= DMA_TC_INT;
-				channel->irq_handler(i, cause, channel->data);
-			} else {
-				/*
-				 * IRQ for an unregistered DMA channel
-				 */
-				printk(KERN_WARNING
-				       "spurious IRQ for DMA channel %d\n", i);
-			}
-			if (tcint & i_bit)
-				__raw_writel(i_bit, DMAC_INT_TC_CLEAR);
-			if (eint & i_bit)
-				__raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-static int __init pnx4008_dma_init(void)
-{
-	int ret, i;
-
-	ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
-	if (ret) {
-		printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
-		goto out;
-	}
-
-	ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
-	ll_pool.cur = ll_pool.vaddr =
-	    dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
-			       &ll_pool.dma_addr, GFP_KERNEL);
-
-	if (!ll_pool.vaddr) {
-		ret = -ENOMEM;
-		free_irq(DMA_INT, NULL);
-		goto out;
-	}
-
-	for (i = 0; i < ll_pool.count - 1; i++) {
-		void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
-		*addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
-	}
-	*(long *)(ll_pool.vaddr +
-		  (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
-	    (long)ll_pool.vaddr;
-
-	__raw_writel(1, DMAC_CONFIG);
-
-out:
-	return ret;
-}
-arch_initcall(pnx4008_dma_init);
diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c
deleted file mode 100644
index d3e71d3..0000000
--- a/arch/arm/mach-pnx4008/gpio.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/gpio.c
- *
- * PNX4008 GPIO driver
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips:
- * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <mach/gpio-pnx4008.h>
-
-/* register definitions */
-#define PIO_VA_BASE	IO_ADDRESS(PNX4008_PIO_BASE)
-
-#define PIO_INP_STATE	(0x00U)
-#define PIO_OUTP_SET	(0x04U)
-#define PIO_OUTP_CLR	(0x08U)
-#define PIO_OUTP_STATE	(0x0CU)
-#define PIO_DRV_SET	(0x10U)
-#define PIO_DRV_CLR	(0x14U)
-#define PIO_DRV_STATE	(0x18U)
-#define PIO_SDINP_STATE	(0x1CU)
-#define PIO_SDOUTP_SET	(0x20U)
-#define PIO_SDOUTP_CLR	(0x24U)
-#define PIO_MUX_SET	(0x28U)
-#define PIO_MUX_CLR	(0x2CU)
-#define PIO_MUX_STATE	(0x30U)
-
-static inline void gpio_lock(void)
-{
-	local_irq_disable();
-}
-
-static inline void gpio_unlock(void)
-{
-	local_irq_enable();
-}
-
-/* Inline functions */
-static inline int gpio_read_bit(u32 reg, int gpio)
-{
-	u32 bit, val;
-	int ret = -EFAULT;
-
-	if (gpio < 0)
-		goto out;
-
-	bit = GPIO_BIT(gpio);
-	if (bit) {
-		val = __raw_readl(PIO_VA_BASE + reg);
-		ret = (val & bit) ? 1 : 0;
-	}
-out:
-	return ret;
-}
-
-static inline int gpio_set_bit(u32 reg, int gpio)
-{
-	u32 bit, val;
-	int ret = -EFAULT;
-
-	if (gpio < 0)
-		goto out;
-
-	bit = GPIO_BIT(gpio);
-	if (bit) {
-		val = __raw_readl(PIO_VA_BASE + reg);
-		val |= bit;
-		__raw_writel(val, PIO_VA_BASE + reg);
-		ret = 0;
-	}
-out:
-	return ret;
-}
-
-/* Very simple access control, bitmap for allocated/free */
-static unsigned long access_map[4];
-#define INP_INDEX	0
-#define OUTP_INDEX	1
-#define GPIO_INDEX	2
-#define MUX_INDEX	3
-
-/*GPIO to Input Mapping */
-static short gpio_to_inp_map[32] = {
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, 10, 11, 12, 13, 14, 24, -1
-};
-
-/*GPIO to Mux Mapping */
-static short gpio_to_mux_map[32] = {
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, 0, 1, 4, 5, -1
-};
-
-/*Output to Mux Mapping */
-static short outp_to_mux_map[32] = {
-	-1, -1, -1, 6, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, 2, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1
-};
-
-int pnx4008_gpio_register_pin(unsigned short pin)
-{
-	unsigned long bit = GPIO_BIT(pin);
-	int ret = -EBUSY;	/* Already in use */
-
-	gpio_lock();
-
-	if (GPIO_ISBID(pin)) {
-		if (access_map[GPIO_INDEX] & bit)
-			goto out;
-		access_map[GPIO_INDEX] |= bit;
-
-	} else if (GPIO_ISRAM(pin)) {
-		if (access_map[GPIO_INDEX] & bit)
-			goto out;
-		access_map[GPIO_INDEX] |= bit;
-
-	} else if (GPIO_ISMUX(pin)) {
-		if (access_map[MUX_INDEX] & bit)
-			goto out;
-		access_map[MUX_INDEX] |= bit;
-
-	} else if (GPIO_ISOUT(pin)) {
-		if (access_map[OUTP_INDEX] & bit)
-			goto out;
-		access_map[OUTP_INDEX] |= bit;
-
-	} else if (GPIO_ISIN(pin)) {
-		if (access_map[INP_INDEX] & bit)
-			goto out;
-		access_map[INP_INDEX] |= bit;
-	} else
-		goto out;
-	ret = 0;
-
-out:
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_register_pin);
-
-int pnx4008_gpio_unregister_pin(unsigned short pin)
-{
-	unsigned long bit = GPIO_BIT(pin);
-	int ret = -EFAULT;	/* Not registered */
-
-	gpio_lock();
-
-	if (GPIO_ISBID(pin)) {
-		if (~access_map[GPIO_INDEX] & bit)
-			goto out;
-		access_map[GPIO_INDEX] &= ~bit;
-	} else if (GPIO_ISRAM(pin)) {
-		if (~access_map[GPIO_INDEX] & bit)
-			goto out;
-		access_map[GPIO_INDEX] &= ~bit;
-	} else if (GPIO_ISMUX(pin)) {
-		if (~access_map[MUX_INDEX] & bit)
-			goto out;
-		access_map[MUX_INDEX] &= ~bit;
-	} else if (GPIO_ISOUT(pin)) {
-		if (~access_map[OUTP_INDEX] & bit)
-			goto out;
-		access_map[OUTP_INDEX] &= ~bit;
-	} else if (GPIO_ISIN(pin)) {
-		if (~access_map[INP_INDEX] & bit)
-			goto out;
-		access_map[INP_INDEX] &= ~bit;
-	} else
-		goto out;
-	ret = 0;
-
-out:
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_unregister_pin);
-
-unsigned long pnx4008_gpio_read_pin(unsigned short pin)
-{
-	unsigned long ret = -EFAULT;
-	int gpio = GPIO_BIT_MASK(pin);
-	gpio_lock();
-	if (GPIO_ISOUT(pin)) {
-		ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
-	} else if (GPIO_ISRAM(pin)) {
-		if (gpio_read_bit(PIO_DRV_STATE, gpio) == 0) {
-			ret = gpio_read_bit(PIO_SDINP_STATE, gpio);
-		}
-	} else if (GPIO_ISBID(pin)) {
-		ret = gpio_read_bit(PIO_DRV_STATE, gpio);
-		if (ret > 0)
-			ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
-		else if (ret == 0)
-			ret =
-			    gpio_read_bit(PIO_INP_STATE, gpio_to_inp_map[gpio]);
-	} else if (GPIO_ISIN(pin)) {
-		ret = gpio_read_bit(PIO_INP_STATE, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_read_pin);
-
-/* Write Value to output */
-int pnx4008_gpio_write_pin(unsigned short pin, int output)
-{
-	int gpio = GPIO_BIT_MASK(pin);
-	int ret = -EFAULT;
-
-	gpio_lock();
-	if (GPIO_ISOUT(pin)) {
-		printk( "writing '%x' to '%x'\n",
-				gpio, output ? PIO_OUTP_SET : PIO_OUTP_CLR );
-		ret = gpio_set_bit(output ? PIO_OUTP_SET : PIO_OUTP_CLR, gpio);
-	} else if (GPIO_ISRAM(pin)) {
-		if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
-			ret = gpio_set_bit(output ? PIO_SDOUTP_SET :
-					   PIO_SDOUTP_CLR, gpio);
-	} else if (GPIO_ISBID(pin)) {
-		if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
-			ret = gpio_set_bit(output ? PIO_OUTP_SET :
-					   PIO_OUTP_CLR, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_write_pin);
-
-/* Value = 1 : Set GPIO pin as output */
-/* Value = 0 : Set GPIO pin as input */
-int pnx4008_gpio_set_pin_direction(unsigned short pin, int output)
-{
-	int gpio = GPIO_BIT_MASK(pin);
-	int ret = -EFAULT;
-
-	gpio_lock();
-	if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
-		ret = gpio_set_bit(output ? PIO_DRV_SET : PIO_DRV_CLR, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_set_pin_direction);
-
-/* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/
-int pnx4008_gpio_read_pin_direction(unsigned short pin)
-{
-	int gpio = GPIO_BIT_MASK(pin);
-	int ret = -EFAULT;
-
-	gpio_lock();
-	if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
-		ret = gpio_read_bit(PIO_DRV_STATE, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_read_pin_direction);
-
-/* Value = 1 : Set pin to muxed function  */
-/* Value = 0 : Set pin as GPIO */
-int pnx4008_gpio_set_pin_mux(unsigned short pin, int output)
-{
-	int gpio = GPIO_BIT_MASK(pin);
-	int ret = -EFAULT;
-
-	gpio_lock();
-	if (GPIO_ISBID(pin)) {
-		ret =
-		    gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
-				 gpio_to_mux_map[gpio]);
-	} else if (GPIO_ISOUT(pin)) {
-		ret =
-		    gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
-				 outp_to_mux_map[gpio]);
-	} else if (GPIO_ISMUX(pin)) {
-		ret = gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_set_pin_mux);
-
-/* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/
-int pnx4008_gpio_read_pin_mux(unsigned short pin)
-{
-	int gpio = GPIO_BIT_MASK(pin);
-	int ret = -EFAULT;
-
-	gpio_lock();
-	if (GPIO_ISBID(pin)) {
-		ret = gpio_read_bit(PIO_MUX_STATE, gpio_to_mux_map[gpio]);
-	} else if (GPIO_ISOUT(pin)) {
-		ret = gpio_read_bit(PIO_MUX_STATE, outp_to_mux_map[gpio]);
-	} else if (GPIO_ISMUX(pin)) {
-		ret = gpio_read_bit(PIO_MUX_STATE, gpio);
-	}
-	gpio_unlock();
-	return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_gpio_read_pin_mux);
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c
deleted file mode 100644
index 550cfc2..0000000
--- a/arch/arm/mach-pnx4008/i2c.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * I2C initialization for PNX4008.
- *
- * Author: Vitaly Wool <vitalywool@gmail.com>
- *
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <linux/i2c-pnx.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <mach/platform.h>
-#include <mach/irqs.h>
-
-static struct resource i2c0_resources[] = {
-	{
-		.start = PNX4008_I2C1_BASE,
-		.end = PNX4008_I2C1_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = I2C_1_INT,
-		.end = I2C_1_INT,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct resource i2c1_resources[] = {
-	{
-		.start = PNX4008_I2C2_BASE,
-		.end = PNX4008_I2C2_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = I2C_2_INT,
-		.end = I2C_2_INT,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct resource i2c2_resources[] = {
-	{
-		.start = PNX4008_USB_CONFIG_BASE + 0x300,
-		.end = PNX4008_USB_CONFIG_BASE + 0x300 + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = USB_I2C_INT,
-		.end = USB_I2C_INT,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device i2c0_device = {
-	.name = "pnx-i2c.0",
-	.id = 0,
-	.resource = i2c0_resources,
-	.num_resources = ARRAY_SIZE(i2c0_resources),
-};
-
-static struct platform_device i2c1_device = {
-	.name = "pnx-i2c.1",
-	.id = 1,
-	.resource = i2c1_resources,
-	.num_resources = ARRAY_SIZE(i2c1_resources),
-};
-
-static struct platform_device i2c2_device = {
-	.name = "pnx-i2c.2",
-	.id = 2,
-	.resource = i2c2_resources,
-	.num_resources = ARRAY_SIZE(i2c2_resources),
-};
-
-static struct platform_device *devices[] __initdata = {
-	&i2c0_device,
-	&i2c1_device,
-	&i2c2_device,
-};
-
-void __init pnx4008_register_i2c_devices(void)
-{
-	platform_add_devices(devices, ARRAY_SIZE(devices));
-}
diff --git a/arch/arm/mach-pnx4008/include/mach/clock.h b/arch/arm/mach-pnx4008/include/mach/clock.h
deleted file mode 100644
index 8d2a5ef..0000000
--- a/arch/arm/mach-pnx4008/include/mach/clock.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/clock.h
- *
- * Clock control driver for PNX4008 - header file
- *
- * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __PNX4008_CLOCK_H__
-#define __PNX4008_CLOCK_H__
-
-struct module;
-struct clk;
-
-#define PWRMAN_VA_BASE		IO_ADDRESS(PNX4008_PWRMAN_BASE)
-#define HCLKDIVCTRL_REG		(PWRMAN_VA_BASE + 0x40)
-#define PWRCTRL_REG		(PWRMAN_VA_BASE + 0x44)
-#define PLLCTRL_REG		(PWRMAN_VA_BASE + 0x48)
-#define OSC13CTRL_REG		(PWRMAN_VA_BASE + 0x4c)
-#define SYSCLKCTRL_REG		(PWRMAN_VA_BASE + 0x50)
-#define HCLKPLLCTRL_REG		(PWRMAN_VA_BASE + 0x58)
-#define USBCTRL_REG		(PWRMAN_VA_BASE + 0x64)
-#define SDRAMCLKCTRL_REG	(PWRMAN_VA_BASE + 0x68)
-#define MSCTRL_REG		(PWRMAN_VA_BASE + 0x80)
-#define BTCLKCTRL		(PWRMAN_VA_BASE + 0x84)
-#define DUMCLKCTRL_REG		(PWRMAN_VA_BASE + 0x90)
-#define I2CCLKCTRL_REG		(PWRMAN_VA_BASE + 0xac)
-#define KEYCLKCTRL_REG		(PWRMAN_VA_BASE + 0xb0)
-#define TSCLKCTRL_REG		(PWRMAN_VA_BASE + 0xb4)
-#define PWMCLKCTRL_REG		(PWRMAN_VA_BASE + 0xb8)
-#define TIMCLKCTRL_REG		(PWRMAN_VA_BASE + 0xbc)
-#define SPICTRL_REG		(PWRMAN_VA_BASE + 0xc4)
-#define FLASHCLKCTRL_REG	(PWRMAN_VA_BASE + 0xc8)
-#define UART3CLK_REG		(PWRMAN_VA_BASE + 0xd0)
-#define UARTCLKCTRL_REG		(PWRMAN_VA_BASE + 0xe4)
-#define DMACLKCTRL_REG		(PWRMAN_VA_BASE + 0xe8)
-#define AUTOCLK_CTRL		(PWRMAN_VA_BASE + 0xec)
-#define JPEGCLKCTRL_REG		(PWRMAN_VA_BASE + 0xfc)
-
-#define AUDIOCONFIG_VA_BASE	IO_ADDRESS(PNX4008_AUDIOCONFIG_BASE)
-#define DSPPLLCTRL_REG		(AUDIOCONFIG_VA_BASE + 0x60)
-#define DSPCLKCTRL_REG		(AUDIOCONFIG_VA_BASE + 0x64)
-#define AUDIOCLKCTRL_REG	(AUDIOCONFIG_VA_BASE + 0x68)
-#define AUDIOPLLCTRL_REG	(AUDIOCONFIG_VA_BASE + 0x6C)
-
-#define USB_OTG_CLKCTRL_REG	IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xff4)
-
-#define VFP9CLKCTRL_REG		IO_ADDRESS(PNX4008_DEBUG_BASE)
-
-#define CLK_RATE_13MHZ 13000
-#define CLK_RATE_1MHZ 1000
-#define CLK_RATE_208MHZ 208000
-#define CLK_RATE_48MHZ 48000
-#define CLK_RATE_32KHZ 32
-
-#define PNX4008_UART_CLK CLK_RATE_13MHZ * 1000 /* in MHz */
-
-#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/debug-macro.S b/arch/arm/mach-pnx4008/include/mach/debug-macro.S
deleted file mode 100644
index 469d60d..0000000
--- a/arch/arm/mach-pnx4008/include/mach/debug-macro.S
+++ /dev/null
@@ -1,21 +0,0 @@
-/* arch/arm/mach-pnx4008/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-		.macro	addruart, rp, rv, tmp
-		mov	\rp, #0x00090000
-		add	\rv, \rp, #0xf4000000	@ virtual
-		add	\rp, \rp, #0x40000000	@ physical
-		.endm
-
-#define UART_SHIFT	2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-pnx4008/include/mach/dma.h b/arch/arm/mach-pnx4008/include/mach/dma.h
deleted file mode 100644
index f094bf8..0000000
--- a/arch/arm/mach-pnx4008/include/mach/dma.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- *  arch/arm/mach-pnx4008/include/mach/dma.h
- *
- *  PNX4008 DMA header file
- *
- *  Author:	Vitaly Wool
- *  Copyright:	MontaVista Software Inc. (c) 2005
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#include "platform.h"
-
-#define MAX_DMA_CHANNELS	8
-
-#define DMAC_BASE		IO_ADDRESS(PNX4008_DMA_CONFIG_BASE)
-#define DMAC_INT_STAT		(DMAC_BASE + 0x0000)
-#define DMAC_INT_TC_STAT	(DMAC_BASE + 0x0004)
-#define DMAC_INT_TC_CLEAR	(DMAC_BASE + 0x0008)
-#define DMAC_INT_ERR_STAT	(DMAC_BASE + 0x000c)
-#define DMAC_INT_ERR_CLEAR	(DMAC_BASE + 0x0010)
-#define DMAC_SOFT_SREQ		(DMAC_BASE + 0x0024)
-#define DMAC_CONFIG		(DMAC_BASE + 0x0030)
-#define DMAC_Cx_SRC_ADDR(c)	(DMAC_BASE + 0x0100 + (c) * 0x20)
-#define DMAC_Cx_DEST_ADDR(c)	(DMAC_BASE + 0x0104 + (c) * 0x20)
-#define DMAC_Cx_LLI(c)		(DMAC_BASE + 0x0108 + (c) * 0x20)
-#define DMAC_Cx_CONTROL(c)	(DMAC_BASE + 0x010c + (c) * 0x20)
-#define DMAC_Cx_CONFIG(c)	(DMAC_BASE + 0x0110 + (c) * 0x20)
-
-enum {
-	WIDTH_BYTE = 0,
-	WIDTH_HWORD,
-	WIDTH_WORD
-};
-
-enum {
-	FC_MEM2MEM_DMA,
-	FC_MEM2PER_DMA,
-	FC_PER2MEM_DMA,
-	FC_PER2PER_DMA,
-	FC_PER2PER_DPER,
-	FC_MEM2PER_PER,
-	FC_PER2MEM_PER,
-	FC_PER2PER_SPER
-};
-
-enum {
-	DMA_INT_UNKNOWN = 0,
-	DMA_ERR_INT = 1,
-	DMA_TC_INT = 2,
-};
-
-enum {
-	DMA_BUFFER_ALLOCATED = 1,
-	DMA_HAS_LL = 2,
-};
-
-enum {
-	PER_CAM_DMA_1 = 0,
-	PER_NDF_FLASH = 1,
-	PER_MBX_SLAVE_FIFO = 2,
-	PER_SPI2_REC_XMIT = 3,
-	PER_MS_SD_RX_XMIT = 4,
-	PER_HS_UART_1_XMIT = 5,
-	PER_HS_UART_1_RX = 6,
-	PER_HS_UART_2_XMIT = 7,
-	PER_HS_UART_2_RX = 8,
-	PER_HS_UART_7_XMIT = 9,
-	PER_HS_UART_7_RX = 10,
-	PER_SPI1_REC_XMIT = 11,
-	PER_MLC_NDF_SREC = 12,
-	PER_CAM_DMA_2 = 13,
-	PER_PRNG_INFIFO = 14,
-	PER_PRNG_OUTFIFO = 15,
-};
-
-struct pnx4008_dma_ch_ctrl {
-	int tc_mask;
-	int cacheable;
-	int bufferable;
-	int priv_mode;
-	int di;
-	int si;
-	int dest_ahb1;
-	int src_ahb1;
-	int dwidth;
-	int swidth;
-	int dbsize;
-	int sbsize;
-	int tr_size;
-};
-
-struct pnx4008_dma_ch_config {
-	int halt;
-	int active;
-	int lock;
-	int itc;
-	int ie;
-	int flow_cntrl;
-	int dest_per;
-	int src_per;
-};
-
-struct pnx4008_dma_ll {
-	unsigned long src_addr;
-	unsigned long dest_addr;
-	u32 next_dma;
-	unsigned long ch_ctrl;
-	struct pnx4008_dma_ll *next;
-	int flags;
-	void *alloc_data;
-	int (*free) (void *);
-};
-
-struct pnx4008_dma_config {
-	int is_ll;
-	unsigned long src_addr;
-	unsigned long dest_addr;
-	unsigned long ch_ctrl;
-	unsigned long ch_cfg;
-	struct pnx4008_dma_ll *ll;
-	u32 ll_dma;
-	int flags;
-	void *alloc_data;
-	int (*free) (void *);
-};
-
-extern struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t *);
-extern void pnx4008_free_ll_entry(struct pnx4008_dma_ll *, dma_addr_t);
-extern void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll *);
-
-extern int pnx4008_request_channel(char *, int,
-				   void (*)(int, int, void *),
-				   void *);
-extern void pnx4008_free_channel(int);
-extern int pnx4008_config_dma(int, int, int);
-extern int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl *,
-				    unsigned long *);
-extern int pnx4008_dma_parse_control(unsigned long,
-				     struct pnx4008_dma_ch_ctrl *);
-extern int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config *,
-				   unsigned long *);
-extern int pnx4008_dma_parse_config(unsigned long,
-				    struct pnx4008_dma_ch_config *);
-extern int pnx4008_config_channel(int, struct pnx4008_dma_config *);
-extern int pnx4008_channel_get_config(int, struct pnx4008_dma_config *);
-extern int pnx4008_dma_ch_enable(int);
-extern int pnx4008_dma_ch_disable(int);
-extern int pnx4008_dma_ch_enabled(int);
-extern void pnx4008_dma_split_head_entry(struct pnx4008_dma_config *,
-					 struct pnx4008_dma_ch_ctrl *);
-extern void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll *,
-				       struct pnx4008_dma_ch_ctrl *);
-
-#endif				/* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-pnx4008/include/mach/entry-macro.S b/arch/arm/mach-pnx4008/include/mach/entry-macro.S
deleted file mode 100644
index 77a5558..0000000
--- a/arch/arm/mach-pnx4008/include/mach/entry-macro.S
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for PNX4008-based platforms
- *
- * 2005-2006 (c) MontaVista Software, Inc.
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include "platform.h"
-
-#define IO_BASE         0xF0000000
-#define IO_ADDRESS(x)  (((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) | IO_BASE)
-
-#define INTRC_MASK			0x00
-#define INTRC_RAW_STAT			0x04
-#define INTRC_STAT			0x08
-#define INTRC_POLAR			0x0C
-#define INTRC_ACT_TYPE			0x10
-#define INTRC_TYPE			0x14
-
-#define SIC1_BASE_INT   32
-#define SIC2_BASE_INT   64
-
-		.macro  get_irqnr_preamble, base, tmp
-		.endm
-
-		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-/* decode the MIC interrupt numbers */
-		ldr	\base, =IO_ADDRESS(PNX4008_INTCTRLMIC_BASE)
-		ldr	\irqstat, [\base, #INTRC_STAT]
-
-		cmp	\irqstat,#1<<16
-		movhs	\irqnr,#16
-		movlo	\irqnr,#0
-		movhs	\irqstat,\irqstat,lsr#16
-		cmp	\irqstat,#1<<8
-		addhs	\irqnr,\irqnr,#8
-		movhs	\irqstat,\irqstat,lsr#8
-		cmp	\irqstat,#1<<4
-		addhs	\irqnr,\irqnr,#4
-		movhs	\irqstat,\irqstat,lsr#4
-		cmp	\irqstat,#1<<2
-		addhs	\irqnr,\irqnr,#2
-		movhs	\irqstat,\irqstat,lsr#2
-		cmp	\irqstat,#1<<1
-		addhs	\irqnr,\irqnr,#1
-
-/* was there an interrupt ? if not then drop out with EQ status */
-		teq	\irqstat,#0
-		beq	1003f
-
-/* and now check for extended IRQ reasons */
-		cmp	\irqnr,#1
-		bls	1003f
-		cmp	\irqnr,#30
-		blo	1002f
-
-/* IRQ 31,30  : High priority cascade IRQ handle */
-/* read the correct SIC */
-/* decoding status after compare : eq is 30 (SIC1) , ne is 31 (SIC2) */
-/* set the base IRQ number */
-		ldreq	\base, =IO_ADDRESS(PNX4008_INTCTRLSIC1_BASE)
-		moveq  \irqnr,#SIC1_BASE_INT
-		ldrne	\base, =IO_ADDRESS(PNX4008_INTCTRLSIC2_BASE)
-		movne   \irqnr,#SIC2_BASE_INT
-		ldr	\irqstat, [\base, #INTRC_STAT]
-		ldr	\tmp,	  [\base, #INTRC_TYPE]
-/* and with inverted mask : low priority interrupts  */
-		and	\irqstat,\irqstat,\tmp
-		b	1004f
-
-1003:
-/* IRQ 1,0  : Low priority cascade IRQ handle */
-/* read the correct SIC */
-/* decoding status after compare : eq is 1 (SIC2) , ne is 0 (SIC1)*/
-/* read the correct SIC */
-/* set the base IRQ number  */
-		ldrne	\base, =IO_ADDRESS(PNX4008_INTCTRLSIC1_BASE)
-		movne   \irqnr,#SIC1_BASE_INT
-		ldreq	\base, =IO_ADDRESS(PNX4008_INTCTRLSIC2_BASE)
-		moveq   \irqnr,#SIC2_BASE_INT
-		ldr	\irqstat, [\base, #INTRC_STAT]
-		ldr	\tmp,	  [\base, #INTRC_TYPE]
-/* and with inverted mask : low priority interrupts  */
-		bic	\irqstat,\irqstat,\tmp
-
-1004:
-
-		cmp	\irqstat,#1<<16
-		addhs	\irqnr,\irqnr,#16
-		movhs	\irqstat,\irqstat,lsr#16
-		cmp	\irqstat,#1<<8
-		addhs	\irqnr,\irqnr,#8
-		movhs	\irqstat,\irqstat,lsr#8
-		cmp	\irqstat,#1<<4
-		addhs	\irqnr,\irqnr,#4
-		movhs	\irqstat,\irqstat,lsr#4
-		cmp	\irqstat,#1<<2
-		addhs	\irqnr,\irqnr,#2
-		movhs	\irqstat,\irqstat,lsr#2
-		cmp	\irqstat,#1<<1
-		addhs	\irqnr,\irqnr,#1
-
-
-/* is irqstat not zero */
-
-1002:
-/* we assert that irqstat is not equal to zero and return ne status if true*/
-		teq	\irqstat,#0
-1003:
-		.endm
-
diff --git a/arch/arm/mach-pnx4008/include/mach/gpio-pnx4008.h b/arch/arm/mach-pnx4008/include/mach/gpio-pnx4008.h
deleted file mode 100644
index 41027dd..0000000
--- a/arch/arm/mach-pnx4008/include/mach/gpio-pnx4008.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/gpio-pnx4008.h
- *
- * PNX4008 GPIO driver - header file
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips:
- * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef _PNX4008_GPIO_H_
-#define _PNX4008_GPIO_H_
-
-
-/* Block numbers */
-#define GPIO_IN		(0)
-#define GPIO_OUT		(0x100)
-#define GPIO_BID		(0x200)
-#define GPIO_RAM		(0x300)
-#define GPIO_MUX		(0x400)
-
-#define GPIO_TYPE_MASK(K) ((K) & 0x700)
-
-/* INPUT GPIOs */
-/* GPI */
-#define GPI_00		(GPIO_IN | 0)
-#define GPI_01		(GPIO_IN | 1)
-#define GPI_02   	(GPIO_IN | 2)
-#define GPI_03 	 	(GPIO_IN | 3)
-#define GPI_04   	(GPIO_IN | 4)
-#define GPI_05   	(GPIO_IN | 5)
-#define GPI_06   	(GPIO_IN | 6)
-#define GPI_07   	(GPIO_IN | 7)
-#define GPI_08   	(GPIO_IN | 8)
-#define GPI_09   	(GPIO_IN | 9)
-#define U1_RX 		(GPIO_IN | 15)
-#define U2_HTCS 	(GPIO_IN | 16)
-#define U2_RX	 	(GPIO_IN | 17)
-#define U3_RX		(GPIO_IN | 18)
-#define U4_RX		(GPIO_IN | 19)
-#define U5_RX		(GPIO_IN | 20)
-#define U6_IRRX 	(GPIO_IN | 21)
-#define U7_HCTS 	(GPIO_IN | 22)
-#define U7_RX		(GPIO_IN | 23)
-/* MISC IN */
-#define SPI1_DATIN	(GPIO_IN | 25)
-#define DISP_SYNC	(GPIO_IN | 26)
-#define SPI2_DATIN	(GPIO_IN | 27)
-#define GPI_11  	(GPIO_IN | 28)
-
-#define GPIO_IN_MASK   0x1eff83ff
-
-/* OUTPUT GPIOs */
-/* GPO */
-#define GPO_00		(GPIO_OUT | 0)
-#define GPO_01   	(GPIO_OUT | 1)
-#define GPO_02   	(GPIO_OUT | 2)
-#define GPO_03 	 	(GPIO_OUT | 3)
-#define GPO_04   	(GPIO_OUT | 4)
-#define GPO_05   	(GPIO_OUT | 5)
-#define GPO_06   	(GPIO_OUT | 6)
-#define GPO_07   	(GPIO_OUT | 7)
-#define GPO_08		(GPIO_OUT | 8)
-#define GPO_09   	(GPIO_OUT | 9)
-#define GPO_10   	(GPIO_OUT | 10)
-#define GPO_11 	 	(GPIO_OUT | 11)
-#define GPO_12   	(GPIO_OUT | 12)
-#define GPO_13   	(GPIO_OUT | 13)
-#define GPO_14   	(GPIO_OUT | 14)
-#define GPO_15   	(GPIO_OUT | 15)
-#define GPO_16  	(GPIO_OUT | 16)
-#define GPO_17 	 	(GPIO_OUT | 17)
-#define GPO_18   	(GPIO_OUT | 18)
-#define GPO_19   	(GPIO_OUT | 19)
-#define GPO_20   	(GPIO_OUT | 20)
-#define GPO_21   	(GPIO_OUT | 21)
-#define GPO_22   	(GPIO_OUT | 22)
-#define GPO_23   	(GPIO_OUT | 23)
-
-#define GPIO_OUT_MASK   0xffffff
-
-/* BIDIRECTIONAL GPIOs */
-/* RAM pins */
-#define RAM_D19		(GPIO_RAM | 0)
-#define RAM_D20  	(GPIO_RAM | 1)
-#define RAM_D21  	(GPIO_RAM | 2)
-#define RAM_D22 	(GPIO_RAM | 3)
-#define RAM_D23  	(GPIO_RAM | 4)
-#define RAM_D24  	(GPIO_RAM | 5)
-#define RAM_D25  	(GPIO_RAM | 6)
-#define RAM_D26  	(GPIO_RAM | 7)
-#define RAM_D27		(GPIO_RAM | 8)
-#define RAM_D28  	(GPIO_RAM | 9)
-#define RAM_D29  	(GPIO_RAM | 10)
-#define RAM_D30 	(GPIO_RAM | 11)
-#define RAM_D31  	(GPIO_RAM | 12)
-
-#define GPIO_RAM_MASK   0x1fff
-
-/* I/O pins */
-#define GPIO_00  	(GPIO_BID | 25)
-#define GPIO_01 	(GPIO_BID | 26)
-#define GPIO_02  	(GPIO_BID | 27)
-#define GPIO_03  	(GPIO_BID | 28)
-#define GPIO_04 	(GPIO_BID | 29)
-#define GPIO_05  	(GPIO_BID | 30)
-
-#define GPIO_BID_MASK   0x7e000000
-
-/* Non-GPIO multiplexed PIOs. For multiplexing with GPIO, please use GPIO macros */
-#define GPIO_SDRAM_SEL 	(GPIO_MUX | 3)
-
-#define GPIO_MUX_MASK   0x8
-
-/* Extraction/assembly macros */
-#define GPIO_BIT_MASK(K) ((K) & 0x1F)
-#define GPIO_BIT(K) (1 << GPIO_BIT_MASK(K))
-#define GPIO_ISMUX(K) ((GPIO_TYPE_MASK(K) == GPIO_MUX) && (GPIO_BIT(K) & GPIO_MUX_MASK))
-#define GPIO_ISRAM(K) ((GPIO_TYPE_MASK(K) == GPIO_RAM) && (GPIO_BIT(K) & GPIO_RAM_MASK))
-#define GPIO_ISBID(K) ((GPIO_TYPE_MASK(K) == GPIO_BID) && (GPIO_BIT(K) & GPIO_BID_MASK))
-#define GPIO_ISOUT(K) ((GPIO_TYPE_MASK(K) == GPIO_OUT) && (GPIO_BIT(K) & GPIO_OUT_MASK))
-#define GPIO_ISIN(K)  ((GPIO_TYPE_MASK(K) == GPIO_IN) && (GPIO_BIT(K) & GPIO_IN_MASK))
-
-/* Start Enable Pin Interrupts - table 58 page 66 */
-
-#define SE_PIN_BASE_INT   32
-
-#define SE_U7_RX_INT            63
-#define SE_U7_HCTS_INT          62
-#define SE_BT_CLKREQ_INT        61
-#define SE_U6_IRRX_INT          60
-/*59 unused*/
-#define SE_U5_RX_INT            58
-#define SE_GPI_11_INT           57
-#define SE_U3_RX_INT            56
-#define SE_U2_HCTS_INT          55
-#define SE_U2_RX_INT            54
-#define SE_U1_RX_INT            53
-#define SE_DISP_SYNC_INT        52
-/*51 unused*/
-#define SE_SDIO_INT_N           50
-#define SE_MSDIO_START_INT      49
-#define SE_GPI_06_INT           48
-#define SE_GPI_05_INT           47
-#define SE_GPI_04_INT           46
-#define SE_GPI_03_INT           45
-#define SE_GPI_02_INT           44
-#define SE_GPI_01_INT           43
-#define SE_GPI_00_INT           42
-#define SE_SYSCLKEN_PIN_INT     41
-#define SE_SPI1_DATAIN_INT      40
-#define SE_GPI_07_INT           39
-#define SE_SPI2_DATAIN_INT      38
-#define SE_GPI_10_INT           37
-#define SE_GPI_09_INT           36
-#define SE_GPI_08_INT           35
-/*34-32 unused*/
-
-/* Start Enable Internal Interrupts - table 57 page 65 */
-
-#define SE_INT_BASE_INT   0
-
-#define SE_TS_IRQ               31
-#define SE_TS_P_INT             30
-#define SE_TS_AUX_INT           29
-/*27-28 unused*/
-#define SE_USB_AHB_NEED_CLK_INT 26
-#define SE_MSTIMER_INT          25
-#define SE_RTC_INT              24
-#define SE_USB_NEED_CLK_INT     23
-#define SE_USB_INT              22
-#define SE_USB_I2C_INT          21
-#define SE_USB_OTG_TIMER_INT    20
-#define SE_USB_OTG_ATX_INT_N    19
-/*18 unused*/
-#define SE_DSP_GPIO4_INT        17
-#define SE_KEY_IRQ              16
-#define SE_DSP_SLAVEPORT_INT    15
-#define SE_DSP_GPIO1_INT        14
-#define SE_DSP_GPIO0_INT        13
-#define SE_DSP_AHB_INT          12
-/*11-6 unused*/
-#define SE_GPIO_05_INT          5
-#define SE_GPIO_04_INT          4
-#define SE_GPIO_03_INT          3
-#define SE_GPIO_02_INT          2
-#define SE_GPIO_01_INT          1
-#define SE_GPIO_00_INT          0
-
-#define START_INT_REG_BIT(irq) (1<<((irq)&0x1F))
-
-#define START_INT_ER_REG(irq)     IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x20 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_RSR_REG(irq)    IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x24 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_SR_REG(irq)     IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x28 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_APR_REG(irq)    IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x2C + (((irq)&(0x1<<5))>>1)))
-
-extern int pnx4008_gpio_register_pin(unsigned short pin);
-extern int pnx4008_gpio_unregister_pin(unsigned short pin);
-extern unsigned long pnx4008_gpio_read_pin(unsigned short pin);
-extern int pnx4008_gpio_write_pin(unsigned short pin, int output);
-extern int pnx4008_gpio_set_pin_direction(unsigned short pin, int output);
-extern int pnx4008_gpio_read_pin_direction(unsigned short pin);
-extern int pnx4008_gpio_set_pin_mux(unsigned short pin, int output);
-extern int pnx4008_gpio_read_pin_mux(unsigned short pin);
-
-static inline void start_int_umask(u8 irq)
-{
-	__raw_writel(__raw_readl(START_INT_ER_REG(irq)) |
-		     START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
-}
-
-static inline void start_int_mask(u8 irq)
-{
-	__raw_writel(__raw_readl(START_INT_ER_REG(irq)) &
-		     ~START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
-}
-
-static inline void start_int_ack(u8 irq)
-{
-	__raw_writel(START_INT_REG_BIT(irq), START_INT_RSR_REG(irq));
-}
-
-static inline void start_int_set_falling_edge(u8 irq)
-{
-	__raw_writel(__raw_readl(START_INT_APR_REG(irq)) &
-		     ~START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
-}
-
-static inline void start_int_set_rising_edge(u8 irq)
-{
-	__raw_writel(__raw_readl(START_INT_APR_REG(irq)) |
-		     START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
-}
-
-#endif				/* _PNX4008_GPIO_H_ */
diff --git a/arch/arm/mach-pnx4008/include/mach/hardware.h b/arch/arm/mach-pnx4008/include/mach/hardware.h
deleted file mode 100644
index 7b98b82..0000000
--- a/arch/arm/mach-pnx4008/include/mach/hardware.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/hardware.h
- *
- * Copyright (c) 2005 MontaVista Software, Inc. <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/sizes.h>
-#include <mach/platform.h>
-
-/* Start of virtual addresses for IO devices */
-#define IO_BASE         0xF0000000
-
-/* This macro relies on fact that for all HW i/o addresses bits 20-23 are 0 */
-#define IO_ADDRESS(x)  (((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) | IO_BASE)
-
-#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/irq.h b/arch/arm/mach-pnx4008/include/mach/irq.h
deleted file mode 100644
index 2a690ca..0000000
--- a/arch/arm/mach-pnx4008/include/mach/irq.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/irq.h
- *
- * PNX4008 IRQ controller driver - header file
- * this one is used in entry-arnv.S as well so it cannot contain C code
- *
- * Copyright (c) 2005 Philips Semiconductors
- * Copyright (c) 2005 MontaVista Software, Inc.
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-#ifndef __PNX4008_IRQ_H__
-#define __PNX4008_IRQ_H__
-
-#define MIC_VA_BASE             IO_ADDRESS(PNX4008_INTCTRLMIC_BASE)
-#define SIC1_VA_BASE            IO_ADDRESS(PNX4008_INTCTRLSIC1_BASE)
-#define SIC2_VA_BASE            IO_ADDRESS(PNX4008_INTCTRLSIC2_BASE)
-
-/* Manual: Chapter 20, page 195 */
-
-#define INTC_BIT(irq) (1<< ((irq) & 0x1F))
-
-#define INTC_ER(irq)    IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0x0 + (((irq)&(0x3<<5))<<9)))
-#define INTC_RSR(irq)   IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0x4 + (((irq)&(0x3<<5))<<9)))
-#define INTC_SR(irq)    IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0x8 + (((irq)&(0x3<<5))<<9)))
-#define INTC_APR(irq)   IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0xC + (((irq)&(0x3<<5))<<9)))
-#define INTC_ATR(irq)   IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0x10 + (((irq)&(0x3<<5))<<9)))
-#define INTC_ITR(irq)   IO_ADDRESS((PNX4008_INTCTRLMIC_BASE + 0x14 + (((irq)&(0x3<<5))<<9)))
-
-#define START_INT_REG_BIT(irq) (1<<((irq)&0x1F))
-
-#define START_INT_ER_REG(irq)     IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x20 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_RSR_REG(irq)    IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x24 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_SR_REG(irq)     IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x28 + (((irq)&(0x1<<5))>>1)))
-#define START_INT_APR_REG(irq)    IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x2C + (((irq)&(0x1<<5))>>1)))
-
-extern void __init pnx4008_init_irq(void);
-
-#endif /* __PNX4008_IRQ_H__ */
diff --git a/arch/arm/mach-pnx4008/include/mach/irqs.h b/arch/arm/mach-pnx4008/include/mach/irqs.h
deleted file mode 100644
index f6b33cf..0000000
--- a/arch/arm/mach-pnx4008/include/mach/irqs.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/irqs.h
- *
- * PNX4008 IRQ controller driver - header file
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __PNX4008_IRQS_h__
-#define __PNX4008_IRQS_h__
-
-#define NR_IRQS         96
-
-/*Manual: table 259, page 199*/
-
-/*SUB2 Interrupt Routing (SIC2)*/
-
-#define SIC2_BASE_INT   64
-
-#define CLK_SWITCH_ARM_INT 95	/*manual: Clkswitch ARM  */
-#define CLK_SWITCH_DSP_INT 94	/*manual: ClkSwitch DSP  */
-#define CLK_SWITCH_AUD_INT 93	/*manual: Clkswitch AUD  */
-#define GPI_06_INT         92
-#define GPI_05_INT         91
-#define GPI_04_INT         90
-#define GPI_03_INT         89
-#define GPI_02_INT         88
-#define GPI_01_INT         87
-#define GPI_00_INT         86
-#define BT_CLKREQ_INT      85
-#define SPI1_DATIN_INT     84
-#define U5_RX_INT          83
-#define SDIO_INT_N         82
-#define CAM_HS_INT         81
-#define CAM_VS_INT         80
-#define GPI_07_INT         79
-#define DISP_SYNC_INT      78
-#define DSP_INT8           77
-#define U7_HCTS_INT        76
-#define GPI_10_INT         75
-#define GPI_09_INT         74
-#define GPI_08_INT         73
-#define DSP_INT7           72
-#define U2_HCTS_INT        71
-#define SPI2_DATIN_INT     70
-#define GPIO_05_INT        69
-#define GPIO_04_INT        68
-#define GPIO_03_INT        67
-#define GPIO_02_INT        66
-#define GPIO_01_INT        65
-#define GPIO_00_INT        64
-
-/*Manual: table 258, page 198*/
-
-/*SUB1 Interrupt Routing (SIC1)*/
-
-#define SIC1_BASE_INT   32
-
-#define USB_I2C_INT        63
-#define USB_DEV_HP_INT     62
-#define USB_DEV_LP_INT     61
-#define USB_DEV_DMA_INT    60
-#define USB_HOST_INT       59
-#define USB_OTG_ATX_INT_N  58
-#define USB_OTG_TIMER_INT  57
-#define SW_INT             56
-#define SPI1_INT           55
-#define KEY_IRQ            54
-#define DSP_M_INT          53
-#define RTC_INT            52
-#define I2C_1_INT          51
-#define I2C_2_INT          50
-#define PLL1_LOCK_INT      49
-#define PLL2_LOCK_INT      48
-#define PLL3_LOCK_INT      47
-#define PLL4_LOCK_INT      46
-#define PLL5_LOCK_INT      45
-#define SPI2_INT           44
-#define DSP_INT1           43
-#define DSP_INT2           42
-#define DSP_TDM_INT2       41
-#define TS_AUX_INT         40
-#define TS_IRQ             39
-#define TS_P_INT           38
-#define UOUT1_TO_PAD_INT   37
-#define GPI_11_INT         36
-#define DSP_INT4           35
-#define JTAG_COMM_RX_INT   34
-#define JTAG_COMM_TX_INT   33
-#define DSP_INT3           32
-
-/*Manual: table 257, page 197*/
-
-/*MAIN Interrupt Routing*/
-
-#define MAIN_BASE_INT   0
-
-#define SUB2_FIQ_N         31	/*active low */
-#define SUB1_FIQ_N         30	/*active low */
-#define JPEG_INT           29
-#define DMA_INT            28
-#define MSTIMER_INT        27
-#define IIR1_INT           26
-#define IIR2_INT           25
-#define IIR7_INT           24
-#define DSP_TDM_INT0       23
-#define DSP_TDM_INT1       22
-#define DSP_P_INT          21
-#define DSP_INT0           20
-#define DUM_INT            19
-#define UOUT0_TO_PAD_INT   18
-#define MP4_ENC_INT        17
-#define MP4_DEC_INT        16
-#define SD0_INT            15
-#define MBX_INT            14
-#define SD1_INT            13
-#define MS_INT_N           12
-#define FLASH_INT          11 /*NAND*/
-#define IIR6_INT           10
-#define IIR5_INT           9
-#define IIR4_INT           8
-#define IIR3_INT           7
-#define WATCH_INT          6
-#define HSTIMER_INT        5
-#define ARCH_TIMER_IRQ     HSTIMER_INT
-#define CAM_INT            4
-#define PRNG_INT           3
-#define CRYPTO_INT         2
-#define SUB2_IRQ_N         1	/*active low */
-#define SUB1_IRQ_N         0	/*active low */
-
-#define PNX4008_IRQ_TYPES \
-{                                           /*IRQ #'s: */         \
-IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_HIGH, /*  0, 1, 2, 3 */     \
-IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /*  4, 5, 6, 7 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /*  8, 9,10,11 */     \
-IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 12,13,14,15 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 16,17,18,19 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 20,21,22,23 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 24,25,26,27 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_LOW,  /* 28,29,30,31 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 32,33,34,35 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_HIGH, /* 36,37,38,39 */  \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 40,41,42,43 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 44,45,46,47 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_LOW,  /* 48,49,50,51 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 52,53,54,55 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW,  IRQ_TYPE_LEVEL_HIGH, /* 56,57,58,59 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 60,61,62,63 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 64,65,66,67 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 68,69,70,71 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 72,73,74,75 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 76,77,78,79 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 80,81,82,83 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 84,85,86,87 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 88,89,90,91 */     \
-IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_HIGH, /* 92,93,94,95 */     \
-}
-
-/* Start Enable Pin Interrupts - table 58 page 66 */
-
-#define SE_PIN_BASE_INT   32
-
-#define SE_U7_RX_INT            63
-#define SE_U7_HCTS_INT          62
-#define SE_BT_CLKREQ_INT        61
-#define SE_U6_IRRX_INT          60
-/*59 unused*/
-#define SE_U5_RX_INT            58
-#define SE_GPI_11_INT           57
-#define SE_U3_RX_INT            56
-#define SE_U2_HCTS_INT          55
-#define SE_U2_RX_INT            54
-#define SE_U1_RX_INT            53
-#define SE_DISP_SYNC_INT        52
-/*51 unused*/
-#define SE_SDIO_INT_N           50
-#define SE_MSDIO_START_INT      49
-#define SE_GPI_06_INT           48
-#define SE_GPI_05_INT           47
-#define SE_GPI_04_INT           46
-#define SE_GPI_03_INT           45
-#define SE_GPI_02_INT           44
-#define SE_GPI_01_INT           43
-#define SE_GPI_00_INT           42
-#define SE_SYSCLKEN_PIN_INT     41
-#define SE_SPI1_DATAIN_INT      40
-#define SE_GPI_07_INT           39
-#define SE_SPI2_DATAIN_INT      38
-#define SE_GPI_10_INT           37
-#define SE_GPI_09_INT           36
-#define SE_GPI_08_INT           35
-/*34-32 unused*/
-
-/* Start Enable Internal Interrupts - table 57 page 65 */
-
-#define SE_INT_BASE_INT   0
-
-#define SE_TS_IRQ               31
-#define SE_TS_P_INT             30
-#define SE_TS_AUX_INT           29
-/*27-28 unused*/
-#define SE_USB_AHB_NEED_CLK_INT 26
-#define SE_MSTIMER_INT          25
-#define SE_RTC_INT              24
-#define SE_USB_NEED_CLK_INT     23
-#define SE_USB_INT              22
-#define SE_USB_I2C_INT          21
-#define SE_USB_OTG_TIMER_INT    20
-
-#endif /* __PNX4008_IRQS_h__ */
diff --git a/arch/arm/mach-pnx4008/include/mach/param.h b/arch/arm/mach-pnx4008/include/mach/param.h
deleted file mode 100644
index 6ea02f2..0000000
--- a/arch/arm/mach-pnx4008/include/mach/param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *  arch/arm/mach-pnx4008/include/mach/param.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#define HZ 100
diff --git a/arch/arm/mach-pnx4008/include/mach/platform.h b/arch/arm/mach-pnx4008/include/mach/platform.h
deleted file mode 100644
index 368c2c1..0000000
--- a/arch/arm/mach-pnx4008/include/mach/platform.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/platform.h
- *
- * PNX4008 Base addresses - header file
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * Based on reference code received from Philips:
- * Copyright (C) 2003 Philips Semiconductors
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-
-#ifndef __ASM_ARCH_PLATFORM_H__
-#define __ASM_ARCH_PLATFORM_H__
-
-#define PNX4008_IRAM_BASE		0x08000000
-#define PNX4008_IRAM_SIZE		0x00010000
-#define PNX4008_YUV_SLAVE_BASE		0x10000000
-#define PNX4008_DUM_SLAVE_BASE		0x18000000
-#define PNX4008_NDF_FLASH_BASE		0x20020000
-#define PNX4008_SPI1_BASE		0x20088000
-#define PNX4008_SPI2_BASE		0x20090000
-#define PNX4008_SD_CONFIG_BASE		0x20098000
-#define PNX4008_FLASH_DATA		0x200B0000
-#define PNX4008_MLC_FLASH_BASE		0x200B8000
-#define PNX4008_JPEG_CONFIG_BASE	0x300A0000
-#define PNX4008_DMA_CONFIG_BASE		0x31000000
-#define PNX4008_USB_CONFIG_BASE		0x31020000
-#define PNX4008_SDRAM_CFG_BASE		0x31080000
-#define PNX4008_AHB2FAB_BASE		0x40000000
-#define PNX4008_PWRMAN_BASE		0x40004000
-#define PNX4008_INTCTRLMIC_BASE		0x40008000
-#define PNX4008_INTCTRLSIC1_BASE	0x4000C000
-#define PNX4008_INTCTRLSIC2_BASE	0x40010000
-#define PNX4008_HSUART1_BASE		0x40014000
-#define PNX4008_HSUART2_BASE		0x40018000
-#define PNX4008_HSUART7_BASE		0x4001C000
-#define PNX4008_RTC_BASE		0x40024000
-#define PNX4008_PIO_BASE		0x40028000
-#define PNX4008_MSTIMER_BASE		0x40034000
-#define PNX4008_HSTIMER_BASE		0x40038000
-#define PNX4008_WDOG_BASE		0x4003C000
-#define PNX4008_DEBUG_BASE		0x40040000
-#define PNX4008_TOUCH1_BASE		0x40048000
-#define PNX4008_KEYSCAN_BASE		0x40050000
-#define PNX4008_UARTCTRL_BASE		0x40054000
-#define PNX4008_PWM_BASE		0x4005C000
-#define PNX4008_UART3_BASE		0x40080000
-#define PNX4008_UART4_BASE		0x40088000
-#define PNX4008_UART5_BASE		0x40090000
-#define PNX4008_UART6_BASE		0x40098000
-#define PNX4008_I2C1_BASE		0x400A0000
-#define PNX4008_I2C2_BASE		0x400A8000
-#define PNX4008_MAGICGATE_BASE		0x400B0000
-#define PNX4008_DUMCONF_BASE		0x400B8000
-#define PNX4008_DUM_MAINCFG_BASE       	0x400BC000
-#define PNX4008_DSP_BASE		0x400C0000
-#define PNX4008_PROFCOUNTER_BASE	0x400C8000
-#define PNX4008_CRYPTO_BASE		0x400D0000
-#define PNX4008_CAMIFCONF_BASE		0x400D8000
-#define PNX4008_YUV2RGB_BASE		0x400E0000
-#define PNX4008_AUDIOCONFIG_BASE	0x400E8000
-
-#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/pm.h b/arch/arm/mach-pnx4008/include/mach/pm.h
deleted file mode 100644
index 2fa685b..0000000
--- a/arch/arm/mach-pnx4008/include/mach/pm.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/pm.h
- *
- * PNX4008 Power Management Routiness - header file
- *
- * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASM_ARCH_PNX4008_PM_H
-#define __ASM_ARCH_PNX4008_PM_H
-
-#ifndef __ASSEMBLER__
-#include "irq.h"
-#include "irqs.h"
-#include "clock.h"
-
-extern void pnx4008_pm_idle(void);
-extern void pnx4008_pm_suspend(void);
-extern unsigned int pnx4008_cpu_suspend_sz;
-extern void pnx4008_cpu_suspend(void);
-extern unsigned int pnx4008_cpu_standby_sz;
-extern void pnx4008_cpu_standby(void);
-
-extern int pnx4008_startup_pll(struct clk *);
-extern int pnx4008_shutdown_pll(struct clk *);
-
-#endif				/* ASSEMBLER */
-#endif				/* __ASM_ARCH_PNX4008_PM_H */
diff --git a/arch/arm/mach-pnx4008/include/mach/timex.h b/arch/arm/mach-pnx4008/include/mach/timex.h
deleted file mode 100644
index b383c7d..0000000
--- a/arch/arm/mach-pnx4008/include/mach/timex.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/timex.h
- *
- * PNX4008 timers header file
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PNX4008_TIMEX_H
-#define __PNX4008_TIMEX_H
-
-#define CLOCK_TICK_RATE		1000000
-
-#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/uncompress.h b/arch/arm/mach-pnx4008/include/mach/uncompress.h
deleted file mode 100644
index bb4751e..0000000
--- a/arch/arm/mach-pnx4008/include/mach/uncompress.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  arch/arm/mach-pnx4008/include/mach/uncompress.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2006 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#define UART5_BASE 0x40090000
-
-#define UART5_DR    (*(volatile unsigned char *) (UART5_BASE))
-#define UART5_FR    (*(volatile unsigned char *) (UART5_BASE + 18))
-
-static __inline__ void putc(char c)
-{
-	while (UART5_FR & (1 << 5))
-		barrier();
-
-	UART5_DR = c;
-}
-
-/*
- * This does not append a newline
- */
-static inline void flush(void)
-{
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-pnx4008/irq.c b/arch/arm/mach-pnx4008/irq.c
deleted file mode 100644
index 41e4201..0000000
--- a/arch/arm/mach-pnx4008/irq.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/irq.c
- *
- * PNX4008 IRQ controller driver
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * Based on reference code received from Philips:
- * Copyright (C) 2003 Philips Semiconductors
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-#include <mach/irq.h>
-
-static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES;
-
-static void pnx4008_mask_irq(struct irq_data *d)
-{
-	__raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq));	/* mask interrupt */
-}
-
-static void pnx4008_unmask_irq(struct irq_data *d)
-{
-	__raw_writel(__raw_readl(INTC_ER(d->irq)) | INTC_BIT(d->irq), INTC_ER(d->irq));	/* unmask interrupt */
-}
-
-static void pnx4008_mask_ack_irq(struct irq_data *d)
-{
-	__raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq));	/* mask interrupt */
-	__raw_writel(INTC_BIT(d->irq), INTC_SR(d->irq));	/* clear interrupt status */
-}
-
-static int pnx4008_set_irq_type(struct irq_data *d, unsigned int type)
-{
-	switch (type) {
-	case IRQ_TYPE_EDGE_RISING:
-		__raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq));	/*edge sensitive */
-		__raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq));	/*rising edge */
-		irq_set_handler(d->irq, handle_edge_irq);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		__raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq));	/*edge sensitive */
-		__raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq));	/*falling edge */
-		irq_set_handler(d->irq, handle_edge_irq);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		__raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq));	/*level sensitive */
-		__raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq));	/*low level */
-		irq_set_handler(d->irq, handle_level_irq);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		__raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq));	/*level sensitive */
-		__raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq));	/* high level */
-		irq_set_handler(d->irq, handle_level_irq);
-		break;
-
-	/* IRQ_TYPE_EDGE_BOTH is not supported */
-	default:
-		printk(KERN_ERR "PNX4008 IRQ: Unsupported irq type %d\n", type);
-		return -1;
-	}
-	return 0;
-}
-
-static struct irq_chip pnx4008_irq_chip = {
-	.irq_ack = pnx4008_mask_ack_irq,
-	.irq_mask = pnx4008_mask_irq,
-	.irq_unmask = pnx4008_unmask_irq,
-	.irq_set_type = pnx4008_set_irq_type,
-};
-
-void __init pnx4008_init_irq(void)
-{
-	unsigned int i;
-
-	/* configure IRQ's */
-	for (i = 0; i < NR_IRQS; i++) {
-		set_irq_flags(i, IRQF_VALID);
-		irq_set_chip(i, &pnx4008_irq_chip);
-		pnx4008_set_irq_type(irq_get_irq_data(i), pnx4008_irq_type[i]);
-	}
-
-	/* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
-	pnx4008_set_irq_type(irq_get_irq_data(SUB1_IRQ_N),
-			     pnx4008_irq_type[SUB1_IRQ_N]);
-	pnx4008_set_irq_type(irq_get_irq_data(SUB2_IRQ_N),
-			     pnx4008_irq_type[SUB2_IRQ_N]);
-	pnx4008_set_irq_type(irq_get_irq_data(SUB1_FIQ_N),
-			     pnx4008_irq_type[SUB1_FIQ_N]);
-	pnx4008_set_irq_type(irq_get_irq_data(SUB2_FIQ_N),
-			     pnx4008_irq_type[SUB2_FIQ_N]);
-
-	/* mask all others */
-	__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
-			(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
-		INTC_ER(MAIN_BASE_INT));
-	__raw_writel(0, INTC_ER(SIC1_BASE_INT));
-	__raw_writel(0, INTC_ER(SIC2_BASE_INT));
-}
-
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
deleted file mode 100644
index 26f8d06..0000000
--- a/arch/arm/mach-pnx4008/pm.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/pm.c
- *
- * Power Management driver for PNX4008
- *
- * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/pm.h>
-#include <linux/rtc.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/suspend.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <asm/cacheflush.h>
-
-#include <mach/hardware.h>
-#include <mach/pm.h>
-#include <mach/clock.h>
-
-#define SRAM_VA IO_ADDRESS(PNX4008_IRAM_BASE)
-
-static void *saved_sram;
-
-static struct clk *pll4_clk;
-
-static inline void pnx4008_standby(void)
-{
-	void (*pnx4008_cpu_standby_ptr) (void);
-
-	local_irq_disable();
-	local_fiq_disable();
-
-	clk_disable(pll4_clk);
-
-	/*saving portion of SRAM to be used by suspend function. */
-	memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_standby_sz);
-
-	/*make sure SRAM copy gets physically written into SDRAM.
-	   SDRAM will be placed into self-refresh during power down */
-	flush_cache_all();
-
-	/*copy suspend function into SRAM */
-	memcpy((void *)SRAM_VA, pnx4008_cpu_standby, pnx4008_cpu_standby_sz);
-
-	/*do suspend */
-	pnx4008_cpu_standby_ptr = (void *)SRAM_VA;
-	pnx4008_cpu_standby_ptr();
-
-	/*restoring portion of SRAM that was used by suspend function */
-	memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_standby_sz);
-
-	clk_enable(pll4_clk);
-
-	local_fiq_enable();
-	local_irq_enable();
-}
-
-static inline void pnx4008_suspend(void)
-{
-	void (*pnx4008_cpu_suspend_ptr) (void);
-
-	local_irq_disable();
-	local_fiq_disable();
-
-	clk_disable(pll4_clk);
-
-	__raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT));
-	__raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT));
-
-	/*saving portion of SRAM to be used by suspend function. */
-	memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_suspend_sz);
-
-	/*make sure SRAM copy gets physically written into SDRAM.
-	   SDRAM will be placed into self-refresh during power down */
-	flush_cache_all();
-
-	/*copy suspend function into SRAM */
-	memcpy((void *)SRAM_VA, pnx4008_cpu_suspend, pnx4008_cpu_suspend_sz);
-
-	/*do suspend */
-	pnx4008_cpu_suspend_ptr = (void *)SRAM_VA;
-	pnx4008_cpu_suspend_ptr();
-
-	/*restoring portion of SRAM that was used by suspend function */
-	memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_suspend_sz);
-
-	clk_enable(pll4_clk);
-
-	local_fiq_enable();
-	local_irq_enable();
-}
-
-static int pnx4008_pm_enter(suspend_state_t state)
-{
-	switch (state) {
-	case PM_SUSPEND_STANDBY:
-		pnx4008_standby();
-		break;
-	case PM_SUSPEND_MEM:
-		pnx4008_suspend();
-		break;
-	}
-	return 0;
-}
-
-static int pnx4008_pm_valid(suspend_state_t state)
-{
-	return (state == PM_SUSPEND_STANDBY) ||
-	       (state == PM_SUSPEND_MEM);
-}
-
-static const struct platform_suspend_ops pnx4008_pm_ops = {
-	.enter = pnx4008_pm_enter,
-	.valid = pnx4008_pm_valid,
-};
-
-int __init pnx4008_pm_init(void)
-{
-	u32 sram_size_to_allocate;
-
-	pll4_clk = clk_get(0, "ck_pll4");
-	if (IS_ERR(pll4_clk)) {
-		printk(KERN_ERR
-		       "PM Suspend cannot acquire ARM(PLL4) clock control\n");
-		return PTR_ERR(pll4_clk);
-	}
-
-	if (pnx4008_cpu_standby_sz > pnx4008_cpu_suspend_sz)
-		sram_size_to_allocate = pnx4008_cpu_standby_sz;
-	else
-		sram_size_to_allocate = pnx4008_cpu_suspend_sz;
-
-	saved_sram = kmalloc(sram_size_to_allocate, GFP_ATOMIC);
-	if (!saved_sram) {
-		printk(KERN_ERR
-		       "PM Suspend: cannot allocate memory to save portion of SRAM\n");
-		clk_put(pll4_clk);
-		return -ENOMEM;
-	}
-
-	suspend_set_ops(&pnx4008_pm_ops);
-	return 0;
-}
diff --git a/arch/arm/mach-pnx4008/serial.c b/arch/arm/mach-pnx4008/serial.c
deleted file mode 100644
index 374c138..0000000
--- a/arch/arm/mach-pnx4008/serial.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  linux/arch/arm/mach-pnx4008/serial.c
- *
- *  PNX4008 UART initialization
- *
- *  Copyright:	MontaVista Software Inc. (c) 2005
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-
-#include <mach/platform.h>
-#include <mach/hardware.h>
-
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-#include <mach/gpio-pnx4008.h>
-#include <mach/clock.h>
-
-#define UART_3		0
-#define UART_4		1
-#define UART_5		2
-#define UART_6		3
-#define UART_UNKNOWN	(-1)
-
-#define UART3_BASE_VA	IO_ADDRESS(PNX4008_UART3_BASE)
-#define UART4_BASE_VA	IO_ADDRESS(PNX4008_UART4_BASE)
-#define UART5_BASE_VA	IO_ADDRESS(PNX4008_UART5_BASE)
-#define UART6_BASE_VA	IO_ADDRESS(PNX4008_UART6_BASE)
-
-#define UART_FCR_OFFSET		8
-#define UART_FIFO_SIZE		64
-
-void pnx4008_uart_init(void)
-{
-	u32 tmp;
-	int i = UART_FIFO_SIZE;
-
-	__raw_writel(0xC1, UART5_BASE_VA + UART_FCR_OFFSET);
-	__raw_writel(0xC1, UART3_BASE_VA + UART_FCR_OFFSET);
-
-	/* Send a NULL to fix the UART HW bug */
-	__raw_writel(0x00, UART5_BASE_VA);
-	__raw_writel(0x00, UART3_BASE_VA);
-
-	while (i--) {
-		tmp = __raw_readl(UART5_BASE_VA);
-		tmp = __raw_readl(UART3_BASE_VA);
-	}
-	__raw_writel(0, UART5_BASE_VA + UART_FCR_OFFSET);
-	__raw_writel(0, UART3_BASE_VA + UART_FCR_OFFSET);
-
-	/* setup wakeup interrupt */
-	start_int_set_rising_edge(SE_U3_RX_INT);
-	start_int_ack(SE_U3_RX_INT);
-	start_int_umask(SE_U3_RX_INT);
-
-	start_int_set_rising_edge(SE_U5_RX_INT);
-	start_int_ack(SE_U5_RX_INT);
-	start_int_umask(SE_U5_RX_INT);
-}
-
diff --git a/arch/arm/mach-pnx4008/sleep.S b/arch/arm/mach-pnx4008/sleep.S
deleted file mode 100644
index f4eed49..0000000
--- a/arch/arm/mach-pnx4008/sleep.S
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * linux/arch/arm/mach-pnx4008/sleep.S
- *
- * PNX4008 support for STOP mode and SDRAM self-refresh
- *
- * Authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <mach/hardware.h>
-
-#define PWRMAN_VA_BASE IO_ADDRESS(PNX4008_PWRMAN_BASE)
-#define PWR_CTRL_REG_OFFS 0x44
-
-#define SDRAM_CFG_VA_BASE IO_ADDRESS(PNX4008_SDRAM_CFG_BASE)
-#define MPMC_STATUS_REG_OFFS 0x4
-
-		.text
-
-ENTRY(pnx4008_cpu_suspend)
-	@this function should be entered in Direct run mode.
-
-	@ save registers on stack
-	stmfd	sp!, {r0 - r6, lr}
-
-	@ setup Power Manager base address in r4
-	@ and put it's value in r5
-	mov	r4, #(PWRMAN_VA_BASE & 0xff000000)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x00ff0000)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x0000ff00)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x000000ff)
-	ldr	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ setup SDRAM controller base address in r2
-	@ and put it's value in r3
-	mov	r2, #(SDRAM_CFG_VA_BASE & 0xff000000)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x00ff0000)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x0000ff00)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x000000ff)
-	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS] @extra read - HW bug workaround
-
-	@ clear SDRAM self-refresh bit latch
-	and	r5, r5, #(~(1 << 8))
-	@ clear SDRAM self-refresh bit
-	and	r5, r5, #(~(1 << 9))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ do save current bit settings in r1
-	mov	r1, r5
-
-	@ set SDRAM self-refresh bit
-	orr	r5, r5, #(1 << 9)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ set SDRAM self-refresh bit latch
-	orr	r5, r5, #(1 << 8)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ clear SDRAM self-refresh bit latch
-	and	r5, r5, #(~(1 << 8))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ clear SDRAM self-refresh bit
-	and	r5, r5, #(~(1 << 9))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ wait for SDRAM to get into self-refresh mode
-2:	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS]
-	tst	r3, #(1 << 2)
-	beq	2b
-
-	@ to prepare SDRAM to get out of self-refresh mode after wakeup
-	orr	r5, r5, #(1 << 7)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ do enter stop mode
-	orr	r5, r5, #(1 << 0)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-
-	@ sleeping now...
-
-	@ coming out of STOP mode into Direct Run mode
-	@ clear STOP mode and SDRAM self-refresh bits
-	str	r1, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ wait for SDRAM to get out self-refresh mode
-3:	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS]
-	tst	r3, #5
-	bne	3b
-
-	@ restore regs and return
-	ldmfd   sp!, {r0 - r6, pc}
-
-ENTRY(pnx4008_cpu_suspend_sz)
-	.word	. - pnx4008_cpu_suspend
-
-ENTRY(pnx4008_cpu_standby)
-	@ save registers on stack
-	stmfd	sp!, {r0 - r6, lr}
-
-	@ setup Power Manager base address in r4
-	@ and put it's value in r5
-	mov	r4, #(PWRMAN_VA_BASE & 0xff000000)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x00ff0000)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x0000ff00)
-	orr	r4, r4, #(PWRMAN_VA_BASE & 0x000000ff)
-	ldr	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ setup SDRAM controller base address in r2
-	@ and put it's value in r3
-	mov	r2, #(SDRAM_CFG_VA_BASE & 0xff000000)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x00ff0000)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x0000ff00)
-	orr	r2, r2, #(SDRAM_CFG_VA_BASE & 0x000000ff)
-	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS] @extra read - HW bug workaround
-
-	@ clear SDRAM self-refresh bit latch
-	and	r5, r5, #(~(1 << 8))
-	@ clear SDRAM self-refresh bit
-	and	r5, r5, #(~(1 << 9))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ do save current bit settings in r1
-	mov	r1, r5
-
-	@ set SDRAM self-refresh bit
-	orr	r5, r5, #(1 << 9)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ set SDRAM self-refresh bit latch
-	orr	r5, r5, #(1 << 8)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ clear SDRAM self-refresh bit latch
-	and	r5, r5, #(~(1 << 8))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ clear SDRAM self-refresh bit
-	and	r5, r5, #(~(1 << 9))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ wait for SDRAM to get into self-refresh mode
-2:	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS]
-	tst	r3, #(1 << 2)
-	beq	2b
-
-	@ set 'get out of self-refresh mode after wakeup' bit
-	orr	r5, r5, #(1 << 7)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	mcr     p15, 0, r0, c7, c0, 4	@ kinda sleeping now...
-
-	@ set SDRAM self-refresh bit latch
-	orr	r5, r5, #(1 << 8)
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ clear SDRAM self-refresh bit latch
-	and	r5, r5, #(~(1 << 8))
-	str	r5, [r4, #PWR_CTRL_REG_OFFS]
-
-	@ wait for SDRAM to get out self-refresh mode
-3:	ldr	r3, [r2, #MPMC_STATUS_REG_OFFS]
-	tst	r3, #5
-	bne	3b
-
-	@ restore regs and return
-	ldmfd   sp!, {r0 - r6, pc}
-
-ENTRY(pnx4008_cpu_standby_sz)
-	.word	. - pnx4008_cpu_standby
-
-ENTRY(pnx4008_cache_clean_invalidate)
-	stmfd	sp!, {r0 - r6, lr}
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
-	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
-#else
-1:	mrc	p15, 0, r15, c7, c14, 3		@ test,clean,invalidate
-	bne     1b
-#endif
-	ldmfd   sp!, {r0 - r6, pc}
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
deleted file mode 100644
index 0cfe8af3..0000000
--- a/arch/arm/mach-pnx4008/time.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/time.c
- *
- * PNX4008 Timers
- *
- * Authors: Vitaly Wool, Dmitry Chigirev, Grigory Tolstolytkin <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach/time.h>
-#include <asm/errno.h>
-
-#include "time.h"
-
-/*! Note: all timers are UPCOUNTING */
-
-/*!
- * Returns number of us since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long pnx4008_gettimeoffset(void)
-{
-	u32 ticks_to_match =
-	    __raw_readl(HSTIM_MATCH0) - __raw_readl(HSTIM_COUNTER);
-	u32 elapsed = LATCH - ticks_to_match;
-	return (elapsed * (tick_nsec / 1000)) / LATCH;
-}
-
-/*!
- * IRQ handler for the timer
- */
-static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
-{
-	if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
-
-		do {
-			timer_tick();
-
-			/*
-			 * this algorithm takes care of possible delay
-			 * for this interrupt handling longer than a normal
-			 * timer period
-			 */
-			__raw_writel(__raw_readl(HSTIM_MATCH0) + LATCH,
-				     HSTIM_MATCH0);
-			__raw_writel(MATCH0_INT, HSTIM_INT);	/* clear interrupt */
-
-			/*
-			 * The goal is to keep incrementing HSTIM_MATCH0
-			 * register until HSTIM_MATCH0 indicates time after
-			 * what HSTIM_COUNTER indicates.
-			 */
-		} while ((signed)
-			 (__raw_readl(HSTIM_MATCH0) -
-			  __raw_readl(HSTIM_COUNTER)) < 0);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static struct irqaction pnx4008_timer_irq = {
-	.name = "PNX4008 Tick Timer",
-	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler = pnx4008_timer_interrupt
-};
-
-/*!
- * Set up timer and timer interrupt.
- */
-static __init void pnx4008_setup_timer(void)
-{
-	__raw_writel(RESET_COUNT, MSTIM_CTRL);
-	while (__raw_readl(MSTIM_COUNTER)) ;	/* wait for reset to complete. 100% guarantee event */
-	__raw_writel(0, MSTIM_CTRL);	/* stop the timer */
-	__raw_writel(0, MSTIM_MCTRL);
-
-	__raw_writel(RESET_COUNT, HSTIM_CTRL);
-	while (__raw_readl(HSTIM_COUNTER)) ;	/* wait for reset to complete. 100% guarantee event */
-	__raw_writel(0, HSTIM_CTRL);
-	__raw_writel(0, HSTIM_MCTRL);
-	__raw_writel(0, HSTIM_CCR);
-	__raw_writel(12, HSTIM_PMATCH);	/* scale down to 1 MHZ */
-	__raw_writel(LATCH, HSTIM_MATCH0);
-	__raw_writel(MR0_INT, HSTIM_MCTRL);
-
-	setup_irq(HSTIMER_INT, &pnx4008_timer_irq);
-
-	__raw_writel(COUNT_ENAB | DEBUG_EN, HSTIM_CTRL);	/*start timer, stop when JTAG active */
-}
-
-/* Timer Clock Control in PM register */
-#define TIMCLK_CTRL_REG  IO_ADDRESS((PNX4008_PWRMAN_BASE + 0xBC))
-#define WATCHDOG_CLK_EN                   1
-#define TIMER_CLK_EN                      2	/* HS and MS timers? */
-
-static u32 timclk_ctrl_reg_save;
-
-void pnx4008_timer_suspend(void)
-{
-	timclk_ctrl_reg_save = __raw_readl(TIMCLK_CTRL_REG);
-	__raw_writel(0, TIMCLK_CTRL_REG);	/* disable timers */
-}
-
-void pnx4008_timer_resume(void)
-{
-	__raw_writel(timclk_ctrl_reg_save, TIMCLK_CTRL_REG);	/* enable timers */
-}
-
-struct sys_timer pnx4008_timer = {
-	.init = pnx4008_setup_timer,
-	.offset = pnx4008_gettimeoffset,
-	.suspend = pnx4008_timer_suspend,
-	.resume = pnx4008_timer_resume,
-};
-
diff --git a/arch/arm/mach-pnx4008/time.h b/arch/arm/mach-pnx4008/time.h
deleted file mode 100644
index 75e88c5..0000000
--- a/arch/arm/mach-pnx4008/time.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/timex.h
- *
- * PNX4008 timers header file
- *
- * Author: Dmitry Chigirev <source@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef PNX_TIME_H
-#define PNX_TIME_H
-
-#include <linux/io.h>
-#include <mach/hardware.h>
-
-#define TICKS2USECS(x)	(x)
-
-/* MilliSecond Timer - Chapter 21 Page 202 */
-
-#define MSTIM_INT     IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0))
-#define MSTIM_CTRL    IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4))
-#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8))
-#define MSTIM_MCTRL   IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14))
-#define MSTIM_MATCH0  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18))
-#define MSTIM_MATCH1  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c))
-
-/* High Speed Timer - Chpater 22, Page 205 */
-
-#define HSTIM_INT     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0))
-#define HSTIM_CTRL    IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4))
-#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8))
-#define HSTIM_PMATCH  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC))
-#define HSTIM_PCOUNT  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10))
-#define HSTIM_MCTRL   IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14))
-#define HSTIM_MATCH0  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18))
-#define HSTIM_MATCH1  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c))
-#define HSTIM_MATCH2  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20))
-#define HSTIM_CCR     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28))
-#define HSTIM_CR0     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C))
-#define HSTIM_CR1     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30))
-
-/* IMPORTANT: both timers are UPCOUNTING */
-
-/* xSTIM_MCTRL bit definitions */
-#define MR0_INT        1
-#define RESET_COUNT0   (1<<1)
-#define STOP_COUNT0    (1<<2)
-#define MR1_INT        (1<<3)
-#define RESET_COUNT1   (1<<4)
-#define STOP_COUNT1    (1<<5)
-#define MR2_INT        (1<<6)
-#define RESET_COUNT2   (1<<7)
-#define STOP_COUNT2    (1<<8)
-
-/* xSTIM_CTRL bit definitions */
-#define COUNT_ENAB     1
-#define RESET_COUNT    (1<<1)
-#define DEBUG_EN       (1<<2)
-
-/* xSTIM_INT bit definitions */
-#define MATCH0_INT     1
-#define MATCH1_INT     (1<<1)
-#define MATCH2_INT     (1<<2)
-#define RTC_TICK0      (1<<4)
-#define RTC_TICK1      (1<<5)
-
-#endif
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
new file mode 100644
index 0000000..41fc853
--- /dev/null
+++ b/arch/arm/mach-prima2/Kconfig
@@ -0,0 +1,19 @@
+if ARCH_SIRF
+
+menu "CSR SiRF primaII/Marco/Polo Specific Features"
+
+config ARCH_PRIMA2
+	bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
+	default y
+	select CPU_V7
+	select ZONE_DMA
+	select SIRF_IRQ
+	help
+          Support for CSR SiRFSoC ARM Cortex A9 Platform
+
+endmenu
+
+config SIRF_IRQ
+	bool
+
+endif
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index 841847d..fc9ce22 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -1,8 +1,8 @@
 obj-y := timer.o
-obj-y += irq.o
 obj-y += rstc.o
-obj-y += prima2.o
+obj-y += common.o
 obj-y += rtciobrg.o
 obj-$(CONFIG_DEBUG_LL) += lluart.o
 obj-$(CONFIG_CACHE_L2X0) += l2x0.o
 obj-$(CONFIG_SUSPEND) += pm.o sleep.o
+obj-$(CONFIG_SIRF_IRQ) += irq.o
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
new file mode 100644
index 0000000..f25a541
--- /dev/null
+++ b/arch/arm/mach-prima2/common.c
@@ -0,0 +1,50 @@
+/*
+ * Defines machines for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sizes.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include "common.h"
+
+static struct of_device_id sirfsoc_of_bus_ids[] __initdata = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
+void __init sirfsoc_mach_init(void)
+{
+	of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL);
+}
+
+void __init sirfsoc_init_late(void)
+{
+	sirfsoc_pm_init();
+}
+
+#ifdef CONFIG_ARCH_PRIMA2
+static const char *prima2_dt_match[] __initdata = {
+       "sirf,prima2",
+       NULL
+};
+
+DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
+	/* Maintainer: Barry Song <baohua.song@csr.com> */
+	.map_io         = sirfsoc_map_lluart,
+	.init_irq	= sirfsoc_of_irq_init,
+	.timer		= &sirfsoc_timer,
+	.dma_zone_size	= SZ_256M,
+	.init_machine	= sirfsoc_mach_init,
+	.init_late	= sirfsoc_init_late,
+	.dt_compat      = prima2_dt_match,
+	.restart	= sirfsoc_restart,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h
index 83125c6..0c898fc 100644
--- a/arch/arm/mach-prima2/include/mach/uncompress.h
+++ b/arch/arm/mach-prima2/include/mach/uncompress.h
@@ -25,11 +25,11 @@
 	 * during kernel decompression, all mappings are flat:
 	 *  virt_addr == phys_addr
 	 */
-	while (__raw_readl(SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS)
+	while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS)
 		& SIRFSOC_UART1_TXFIFO_FULL)
 		barrier();
 
-	__raw_writel(c, SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA);
+	__raw_writel(c, (void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA);
 }
 
 static inline void flush(void)
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index a7b9415..7dee917 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -63,7 +63,7 @@
 
 	np = of_find_matching_node(NULL, intc_ids);
 	if (!np)
-		panic("unable to find compatible intc node in dtb\n");
+		return;
 
 	sirfsoc_intc_base = of_iomap(np, 0);
 	if (!sirfsoc_intc_base)
diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c
deleted file mode 100644
index e9a17ae..0000000
--- a/arch/arm/mach-prima2/prima2.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Defines machines for CSR SiRFprimaII
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/sizes.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include "common.h"
-
-static struct of_device_id sirfsoc_of_bus_ids[] __initdata = {
-	{ .compatible = "simple-bus", },
-	{},
-};
-
-void __init sirfsoc_mach_init(void)
-{
-	of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL);
-}
-
-void __init sirfsoc_init_late(void)
-{
-	sirfsoc_pm_init();
-}
-
-static const char *prima2cb_dt_match[] __initdata = {
-       "sirf,prima2-cb",
-       NULL
-};
-
-MACHINE_START(PRIMA2_EVB, "prima2cb")
-	/* Maintainer: Barry Song <baohua.song@csr.com> */
-	.atag_offset	= 0x100,
-	.map_io         = sirfsoc_map_lluart,
-	.init_irq	= sirfsoc_of_irq_init,
-	.timer		= &sirfsoc_timer,
-	.dma_zone_size	= SZ_256M,
-	.init_machine	= sirfsoc_mach_init,
-	.init_late	= sirfsoc_init_late,
-	.dt_compat      = prima2cb_dt_match,
-	.restart	= sirfsoc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 166eee5..c1f3b12 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -6,7 +6,6 @@
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/i2c/pxa-i2c.h>
 
-#include <asm/pmu.h>
 #include <mach/udc.h>
 #include <mach/pxa3xx-u2d.h>
 #include <mach/pxafb.h>
@@ -42,7 +41,7 @@
 
 struct platform_device pxa_device_pmu = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pxa_resource_pmu,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index 30b1b0b..0701ca7 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -52,7 +52,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/mfd/da903x.h>
-#include <linux/sht15.h>
+#include <linux/platform_data/sht15.h>
 
 #include "devices.h"
 #include "generic.h"
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index a33e33b..ce77476 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -33,7 +33,6 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -298,7 +297,7 @@
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index f0298cb..e21711d 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -35,7 +35,6 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -281,7 +280,7 @@
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
 };
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 1f019f7..b442fb2 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -33,7 +33,6 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -264,7 +263,7 @@
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 5032775..1435cd8 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -32,7 +32,6 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 
@@ -242,7 +241,7 @@
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
 };
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index de64ba0..5d2c8be 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -31,7 +31,6 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/smp_twd.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
@@ -281,7 +280,7 @@
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2440.c b/arch/arm/mach-s3c24xx/clock-s3c2440.c
index cb2883d..749220f 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2440.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2440.c
@@ -87,6 +87,19 @@
 	return 0;
 }
 
+static unsigned long s3c2440_camif_upll_getrate(struct clk *clk)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
+
+	if (!(camdivn & S3C2440_CAMDIVN_CAMCLK_SEL))
+		return parent_rate;
+
+	camdivn &= S3C2440_CAMDIVN_CAMCLK_MASK;
+
+	return parent_rate / (camdivn + 1) / 2;
+}
+
 /* Extra S3C2440 clocks */
 
 static struct clk s3c2440_clk_cam = {
@@ -99,6 +112,7 @@
 	.name		= "camif-upll",
 	.ops		= &(struct clk_ops) {
 		.set_rate	= s3c2440_camif_upll_setrate,
+		.get_rate	= s3c2440_camif_upll_getrate,
 		.round_rate	= s3c2440_camif_upll_round,
 	},
 };
diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
index a5eeb62..57aee91 100644
--- a/arch/arm/mach-s3c24xx/h1940-bluetooth.c
+++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
@@ -138,19 +138,7 @@
 	.remove		= h1940bt_remove,
 };
 
-
-static int __init h1940bt_init(void)
-{
-	return platform_driver_register(&h1940bt_driver);
-}
-
-static void __exit h1940bt_exit(void)
-{
-	platform_driver_unregister(&h1940bt_driver);
-}
-
-module_init(h1940bt_init);
-module_exit(h1940bt_exit);
+module_platform_driver(h1940bt_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Driver for the iPAQ H1940 bluetooth chip");
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index 5a7d0c0..0c7ed7a 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -424,7 +424,8 @@
 		anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
 	} else {
 		/* ensure that the GPIO is setup */
-		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
+		gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL);
+		gpio_free(S3C2410_GPA(0));
 	}
 }
 
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index bb8d008..7e15cc4 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -380,7 +380,7 @@
 	default:
 		blink_gpio = S3C2410_GPA(3);
 		check_gpio1 = S3C2410_GPA(1);
-		check_gpio1 = S3C2410_GPA(7);
+		check_gpio2 = S3C2410_GPA(7);
 		break;
 	}
 
@@ -460,7 +460,7 @@
 		break;
 	default:
 		break;
-	};
+	}
 }
 
 static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index ae73ba3..4713347 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -512,8 +512,8 @@
 {
 	printk(KERN_INFO "powering system down...\n");
 
-	s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
-	s3c_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT);
+	gpio_request_one(S3C2410_GPC(5), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPC(5));
 }
 
 static void __init jive_machine_init(void)
@@ -623,11 +623,11 @@
 	gpio_request(S3C2410_GPB(7), "jive spi");
 	gpio_direction_output(S3C2410_GPB(7), 1);
 
-	s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
-	s3c_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
+	gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL);
+	gpio_free(S3C2410_GPB(6));
 
-	s3c2410_gpio_setpin(S3C2410_GPG(8), 1);
-	s3c_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPIO_OUTPUT);
+	gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPG(8));
 
 	/* initialise the WM8750 spi */
 
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index bd6d252..734bbfe 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -638,9 +638,9 @@
 	gpio_free(S3C2410_GPG(4));
 
 	/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
+	gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);
 	s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
-	s3c2410_gpio_setpin(S3C2410_GPB(1), 0);
-	s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);
+	gpio_free(S3C2410_GPB(1));
 
 	/* mark the key as input, without pullups (there is one on the board) */
 	for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
index 5c05ba1..a71a551 100644
--- a/arch/arm/mach-s3c24xx/mach-nexcoder.c
+++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c
@@ -119,17 +119,17 @@
 
 static void __init nexcoder_sensorboard_init(void)
 {
-	// Initialize SCCB bus
-	s3c2410_gpio_setpin(S3C2410_GPE(14), 1); // IICSCL
-	s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPIO_OUTPUT);
-	s3c2410_gpio_setpin(S3C2410_GPE(15), 1); // IICSDA
-	s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPIO_OUTPUT);
+	/* Initialize SCCB bus */
+	gpio_request_one(S3C2410_GPE(14), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPE(14)); /* IICSCL */
+	gpio_request_one(S3C2410_GPE(15), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPE(15)); /* IICSDA */
 
-	// Power up the sensor board
-	s3c2410_gpio_setpin(S3C2410_GPF(1), 1);
-	s3c_gpio_cfgpin(S3C2410_GPF(1), S3C2410_GPIO_OUTPUT); // CAM_GPIO7 => nLDO_PWRDN
-	s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
-	s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); // CAM_GPIO6 => CAM_PWRDN
+	/* Power up the sensor board */
+	gpio_request_one(S3C2410_GPF(1), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPF(1)); /* CAM_GPIO7 => nLDO_PWRDN */
+	gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_LOW, NULL);
+	gpio_free(S3C2410_GPF(2)); /* CAM_GPIO6 => CAM_PWRDN */
 }
 
 static void __init nexcoder_map_io(void)
diff --git a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
index ad2792d..5876c6b 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
@@ -175,18 +175,7 @@
 	},
 };
 
-static int __init osiris_dvs_init(void)
-{
-	return platform_driver_register(&osiris_dvs_driver);
-}
-
-static void __exit osiris_dvs_exit(void)
-{
-	platform_driver_unregister(&osiris_dvs_driver);
-}
-
-module_init(osiris_dvs_init);
-module_exit(osiris_dvs_exit);
+module_platform_driver(osiris_dvs_driver);
 
 MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index 95d0772..c0fb3c1 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -274,8 +274,8 @@
 	__raw_writeb(tmp, OSIRIS_VA_CTRL0);
 
 	/* ensure that an nRESET is not generated on resume. */
-	s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
-	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
+	gpio_request_one(S3C2410_GPA(21), GPIOF_OUT_INIT_HIGH, NULL);
+	gpio_free(S3C2410_GPA(21));
 
 	return 0;
 }
@@ -396,7 +396,8 @@
 		osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
 	} else {
 		/* write-protect line to the NAND */
-		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
+		gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL);
+		gpio_free(S3C2410_GPA(0));
 	}
 
 	/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
diff --git a/arch/arm/mach-sa1100/include/mach/simpad.h b/arch/arm/mach-sa1100/include/mach/simpad.h
index cdea671..ac2ea76 100644
--- a/arch/arm/mach-sa1100/include/mach/simpad.h
+++ b/arch/arm/mach-sa1100/include/mach/simpad.h
@@ -87,7 +87,7 @@
 #define SIMPAD_CS3_PCMCIA_SHORT		(SIMPAD_CS3_GPIO_BASE + 22)
 #define SIMPAD_CS3_GPIO_23		(SIMPAD_CS3_GPIO_BASE + 23)
 
-#define CS3_BASE        0xf1000000
+#define CS3_BASE        IOMEM(0xf1000000)
 
 long simpad_get_cs3_ro(void);
 long simpad_get_cs3_shadow(void);
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index fbd5359..6ca92d0 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -124,7 +124,7 @@
 		.length		= 0x00800000,
 		.type		= MT_DEVICE
 	}, {	/* Simpad CS3 */
-		.virtual	= CS3_BASE,
+		.virtual	= (unsigned long)CS3_BASE,
 		.pfn		= __phys_to_pfn(SA1100_CS3_PHYS),
 		.length		= 0x00100000,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 2704bcd..d35b94e 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -21,9 +21,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
-#define IO_BASE                 0xe0000000
-#define IO_SIZE                 0x08000000
-#define IO_START                0x40000000
 #define ROMCARD_SIZE            0x08000000
 #define ROMCARD_START           0x10000000
 
@@ -104,20 +101,6 @@
 
 extern void shark_init_irq(void);
 
-static struct map_desc shark_io_desc[] __initdata = {
-	{
-		.virtual	= IO_BASE,
-		.pfn		= __phys_to_pfn(IO_START),
-		.length		= IO_SIZE,
-		.type		= MT_DEVICE
-	}
-};
-
-static void __init shark_map_io(void)
-{
-	iotable_init(shark_io_desc, ARRAY_SIZE(shark_io_desc));
-}
-
 #define IRQ_TIMER 0
 #define HZ_TIME ((1193180 + HZ/2) / HZ)
 
@@ -158,7 +141,6 @@
 MACHINE_START(SHARK, "Shark")
 	/* Maintainer: Alexander Schulz */
 	.atag_offset	= 0x3000,
-	.map_io		= shark_map_io,
 	.init_early	= shark_init_early,
 	.init_irq	= shark_init_irq,
 	.timer		= &shark_timer,
diff --git a/arch/arm/mach-shark/include/mach/debug-macro.S b/arch/arm/mach-shark/include/mach/debug-macro.S
index 20eb2bf..d129119 100644
--- a/arch/arm/mach-shark/include/mach/debug-macro.S
+++ b/arch/arm/mach-shark/include/mach/debug-macro.S
@@ -12,9 +12,10 @@
 */
 
 		.macro	addruart, rp, rv, tmp
-		mov	\rp, #0xe0000000
-		orr	\rp, \rp, #0x000003f8
-		mov	\rv, \rp
+		mov	\rp, #0x3f8
+		orr	\rv, \rp, #0xfe000000
+		orr	\rv, \rv, #0x00e00000
+		orr	\rp, \rp, #0x40000000
 		.endm
 
 		.macro	senduart,rd,rx
diff --git a/arch/arm/mach-shark/include/mach/entry-macro.S b/arch/arm/mach-shark/include/mach/entry-macro.S
index 5901b09..c9e49f0 100644
--- a/arch/arm/mach-shark/include/mach/entry-macro.S
+++ b/arch/arm/mach-shark/include/mach/entry-macro.S
@@ -8,7 +8,8 @@
  * warranty of any kind, whether express or implied.
  */
 		.macro  get_irqnr_preamble, base, tmp
-		mov	\base, #0xe0000000
+		mov	\base, #0xfe000000
+		orr	\base, \base, #0x00e00000
 		.endm
 
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
diff --git a/arch/arm/mach-shark/include/mach/io.h b/arch/arm/mach-shark/include/mach/io.h
deleted file mode 100644
index 1a45fc0..0000000
--- a/arch/arm/mach-shark/include/mach/io.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-shark/include/mach/io.h
- *
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/mach-ebsa110/include/mach/io.h
- * Copyright (C) 1997,1998 Russell King
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)                 ((void __iomem *)(0xe0000000 + (a)))
-
-#endif
diff --git a/arch/arm/mach-shark/pci.c b/arch/arm/mach-shark/pci.c
index 9089407..b8b4ab3 100644
--- a/arch/arm/mach-shark/pci.c
+++ b/arch/arm/mach-shark/pci.c
@@ -8,12 +8,15 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <video/vga.h>
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#define IO_START	0x40000000
+
 static int __init shark_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	if (dev->bus->number == 0)
@@ -44,6 +47,8 @@
 	pcibios_min_mem = 0x50000000;
 	vga_base = 0xe8000000;
 
+	pci_ioremap_io(0, IO_START);
+
 	pci_common_init(&shark_pci);
 
 	return 0;
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index d82c010..cfc3b5c 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -40,7 +40,6 @@
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/mfd/tmio.h>
 #include <linux/sh_clk.h>
-#include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mipi_dsi.h>
 #include <sound/sh_fsi.h>
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index f172ca8..1089ee5 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -432,7 +432,7 @@
 		return;
 
 	/* set VBOUT/PWEN and EXTLP1 in DVSTCTR */
-	__raw_writew(__raw_readw(0xE68B0008) | 0x600, 0xE68B0008);
+	__raw_writew(__raw_readw(IOMEM(0xE68B0008)) | 0x600, IOMEM(0xE68B0008));
 }
 
 static struct r8a66597_platdata usb1_host_data = {
@@ -1224,9 +1224,9 @@
 };
 
 
-#define GPIO_PORT9CR	0xE6051009
-#define GPIO_PORT10CR	0xE605100A
-#define USCCR1		0xE6058144
+#define GPIO_PORT9CR	IOMEM(0xE6051009)
+#define GPIO_PORT10CR	IOMEM(0xE605100A)
+#define USCCR1		IOMEM(0xE6058144)
 static void __init ap4evb_init(void)
 {
 	u32 srcr4;
@@ -1304,7 +1304,7 @@
 	gpio_request(GPIO_FN_OVCN2_1,    NULL);
 
 	/* setup USB phy */
-	__raw_writew(0x8a0a, 0xE6058130);	/* USBCR4 */
+	__raw_writew(0x8a0a, IOMEM(0xE6058130));	/* USBCR4 */
 
 	/* enable FSI2 port A (ak4643) */
 	gpio_request(GPIO_FN_FSIAIBT,	NULL);
@@ -1453,7 +1453,7 @@
 	gpio_request(GPIO_FN_HDMI_CEC, NULL);
 
 	/* Reset HDMI, must be held at least one EXTALR (32768Hz) period */
-#define SRCR4 0xe61580bc
+#define SRCR4 IOMEM(0xe61580bc)
 	srcr4 = __raw_readl(SRCR4);
 	__raw_writel(srcr4 | (1 << 13), SRCR4);
 	udelay(50);
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 453a6e5..45b33e0 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -135,7 +135,7 @@
  *	usbhsf_power_ctrl()
  */
 #define IRQ7		evt2irq(0x02e0)
-#define USBCR1		0xe605810a
+#define USBCR1		IOMEM(0xe605810a)
 #define USBH		0xC6700000
 #define USBH_USBCTR	0x10834
 
@@ -950,8 +950,8 @@
 /*
  * board init
  */
-#define GPIO_PORT7CR	0xe6050007
-#define GPIO_PORT8CR	0xe6050008
+#define GPIO_PORT7CR	IOMEM(0xe6050007)
+#define GPIO_PORT8CR	IOMEM(0xe6050008)
 static void __init eva_init(void)
 {
 	struct platform_device *usb = NULL;
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 4129008..cb8c994 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -108,12 +108,12 @@
 #define FPGA_ETH_IRQ		(FPGA_IRQ0 + 15)
 static u16 bonito_fpga_read(u32 offset)
 {
-	return __raw_readw(0xf0003000 + offset);
+	return __raw_readw(IOMEM(0xf0003000) + offset);
 }
 
 static void bonito_fpga_write(u32 offset, u16 val)
 {
-	__raw_writew(val, 0xf0003000 + offset);
+	__raw_writew(val, IOMEM(0xf0003000) + offset);
 }
 
 static void bonito_fpga_irq_disable(struct irq_data *data)
@@ -361,8 +361,8 @@
 #define BIT_ON(sw, bit)		(sw & (1 << bit))
 #define BIT_OFF(sw, bit)	(!(sw & (1 << bit)))
 
-#define VCCQ1CR		0xE6058140
-#define VCCQ1LCDCR	0xE6058186
+#define VCCQ1CR		IOMEM(0xE6058140)
+#define VCCQ1LCDCR	IOMEM(0xE6058186)
 
 static void __init bonito_init(void)
 {
diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c
index 796fa00..b179d4c 100644
--- a/arch/arm/mach-shmobile/board-g3evm.c
+++ b/arch/arm/mach-shmobile/board-g3evm.c
@@ -106,7 +106,7 @@
 		return;
 
 	/* set VBOUT/PWEN and EXTLP0 in DVSTCTR */
-	__raw_writew(__raw_readw(0xe6890008) | 0x600, 0xe6890008);
+	__raw_writew(__raw_readw(IOMEM(0xe6890008)) | 0x600, IOMEM(0xe6890008));
 }
 
 static struct r8a66597_platdata usb_host_data = {
@@ -279,10 +279,10 @@
 	gpio_request(GPIO_FN_IDIN, NULL);
 
 	/* setup USB phy */
-	__raw_writew(0x0300, 0xe605810a);	/* USBCR1 */
-	__raw_writew(0x00e0, 0xe60581c0);	/* CPFCH */
-	__raw_writew(0x6010, 0xe60581c6);	/* CGPOSR */
-	__raw_writew(0x8a0a, 0xe605810c);	/* USBCR2 */
+	__raw_writew(0x0300, IOMEM(0xe605810a));	/* USBCR1 */
+	__raw_writew(0x00e0, IOMEM(0xe60581c0));	/* CPFCH */
+	__raw_writew(0x6010, IOMEM(0xe60581c6));	/* CGPOSR */
+	__raw_writew(0x8a0a, IOMEM(0xe605810c));	/* USBCR2 */
 
 	/* KEYSC @ CN7 */
 	gpio_request(GPIO_FN_PORT42_KEYOUT0, NULL);
@@ -320,7 +320,7 @@
 	gpio_request(GPIO_FN_WE0_XWR0_FWE, NULL);
 	gpio_request(GPIO_FN_FRB, NULL);
 	/* FOE, FCDE, FSC on dedicated pins */
-	__raw_writel(__raw_readl(0xe6158048) & ~(1 << 15), 0xe6158048);
+	__raw_writel(__raw_readl(IOMEM(0xe6158048)) & ~(1 << 15), IOMEM(0xe6158048));
 
 	/* IrDA */
 	gpio_request(GPIO_FN_IRDA_OUT, NULL);
diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c
index fa5dfc5..22d6893 100644
--- a/arch/arm/mach-shmobile/board-g4evm.c
+++ b/arch/arm/mach-shmobile/board-g4evm.c
@@ -126,7 +126,7 @@
 		return;
 
 	/* set VBOUT/PWEN and EXTLP0 in DVSTCTR */
-	__raw_writew(__raw_readw(0xe6890008) | 0x600, 0xe6890008);
+	__raw_writew(__raw_readw(IOMEM(0xe6890008)) | 0x600, IOMEM(0xe6890008));
 }
 
 static struct r8a66597_platdata usb_host_data = {
@@ -270,17 +270,17 @@
 	&sdhi1_device,
 };
 
-#define GPIO_SDHID0_D0	0xe60520fc
-#define GPIO_SDHID0_D1	0xe60520fd
-#define GPIO_SDHID0_D2	0xe60520fe
-#define GPIO_SDHID0_D3	0xe60520ff
-#define GPIO_SDHICMD0	0xe6052100
+#define GPIO_SDHID0_D0	IOMEM(0xe60520fc)
+#define GPIO_SDHID0_D1	IOMEM(0xe60520fd)
+#define GPIO_SDHID0_D2	IOMEM(0xe60520fe)
+#define GPIO_SDHID0_D3	IOMEM(0xe60520ff)
+#define GPIO_SDHICMD0	IOMEM(0xe6052100)
 
-#define GPIO_SDHID1_D0	0xe6052103
-#define GPIO_SDHID1_D1	0xe6052104
-#define GPIO_SDHID1_D2	0xe6052105
-#define GPIO_SDHID1_D3	0xe6052106
-#define GPIO_SDHICMD1	0xe6052107
+#define GPIO_SDHID1_D0	IOMEM(0xe6052103)
+#define GPIO_SDHID1_D1	IOMEM(0xe6052104)
+#define GPIO_SDHID1_D2	IOMEM(0xe6052105)
+#define GPIO_SDHID1_D3	IOMEM(0xe6052106)
+#define GPIO_SDHICMD1	IOMEM(0xe6052107)
 
 static void __init g4evm_init(void)
 {
@@ -318,10 +318,10 @@
 	gpio_request(GPIO_FN_IDIN, NULL);
 
 	/* setup USB phy */
-	__raw_writew(0x0200, 0xe605810a);       /* USBCR1 */
-	__raw_writew(0x00e0, 0xe60581c0);       /* CPFCH */
-	__raw_writew(0x6010, 0xe60581c6);       /* CGPOSR */
-	__raw_writew(0x8a0a, 0xe605810c);       /* USBCR2 */
+	__raw_writew(0x0200, IOMEM(0xe605810a));       /* USBCR1 */
+	__raw_writew(0x00e0, IOMEM(0xe60581c0));       /* CPFCH */
+	__raw_writew(0x6010, IOMEM(0xe60581c6));       /* CGPOSR */
+	__raw_writew(0x8a0a, IOMEM(0xe605810c));       /* USBCR2 */
 
 	/* KEYSC @ CN31 */
 	gpio_request(GPIO_FN_PORT60_KEYOUT5, NULL);
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 53b7ea9..1a413f0 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -133,8 +133,8 @@
 
 /* USB Func CN17 */
 struct usbhs_private {
-	unsigned int phy;
-	unsigned int cr2;
+	void __iomem *phy;
+	void __iomem *cr2;
 	struct renesas_usbhs_platform_info info;
 };
 
@@ -232,8 +232,8 @@
 };
 
 static struct usbhs_private usbhs_private = {
-	.phy	= 0xe60781e0,		/* USBPHYINT */
-	.cr2	= 0xe605810c,		/* USBCR2 */
+	.phy	= IOMEM(0xe60781e0),		/* USBPHYINT */
+	.cr2	= IOMEM(0xe605810c),		/* USBCR2 */
 	.info = {
 		.platform_callback = {
 			.hardware_init	= usbhs_hardware_init,
@@ -346,11 +346,11 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= gic_spi(141),
+		.start	= gic_spi(140),
 		.flags	= IORESOURCE_IRQ,
 	},
 	[2] = {
-		.start	= gic_spi(140),
+		.start	= gic_spi(141),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -763,6 +763,13 @@
 	platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
 }
 
+static void kzm9g_restart(char mode, const char *cmd)
+{
+#define RESCNT2 IOMEM(0xe6188020)
+	/* Do soft power on reset */
+	writel((1 << 31), RESCNT2);
+}
+
 static const char *kzm9g_boards_compat_dt[] __initdata = {
 	"renesas,kzm9g",
 	NULL,
@@ -777,5 +784,6 @@
 	.init_machine	= kzm_init,
 	.init_late	= shmobile_init_late,
 	.timer		= &shmobile_timer,
+	.restart	= kzm9g_restart,
 	.dt_compat	= kzm9g_boards_compat_dt,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index c129542..0dce90e 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -583,8 +583,8 @@
 #define USBHS0_POLL_INTERVAL (HZ * 5)
 
 struct usbhs_private {
-	unsigned int usbphyaddr;
-	unsigned int usbcrcaddr;
+	void __iomem *usbphyaddr;
+	void __iomem *usbcrcaddr;
 	struct renesas_usbhs_platform_info info;
 	struct delayed_work work;
 	struct platform_device *pdev;
@@ -642,7 +642,7 @@
 }
 
 static struct usbhs_private usbhs0_private = {
-	.usbcrcaddr	= 0xe605810c,		/* USBCR2 */
+	.usbcrcaddr	= IOMEM(0xe605810c),		/* USBCR2 */
 	.info = {
 		.platform_callback = {
 			.hardware_init	= usbhs0_hardware_init,
@@ -776,8 +776,8 @@
 };
 
 static struct usbhs_private usbhs1_private = {
-	.usbphyaddr	= 0xe60581e2,		/* USBPHY1INTAP */
-	.usbcrcaddr	= 0xe6058130,		/* USBCR4 */
+	.usbphyaddr	= IOMEM(0xe60581e2),	/* USBPHY1INTAP */
+	.usbcrcaddr	= IOMEM(0xe6058130),	/* USBCR4 */
 	.info = {
 		.platform_callback = {
 			.hardware_init	= usbhs1_hardware_init,
@@ -1402,12 +1402,12 @@
 	},
 };
 
-#define GPIO_PORT9CR	0xE6051009
-#define GPIO_PORT10CR	0xE605100A
-#define GPIO_PORT167CR	0xE60520A7
-#define GPIO_PORT168CR	0xE60520A8
-#define SRCR4		0xe61580bc
-#define USCCR1		0xE6058144
+#define GPIO_PORT9CR	IOMEM(0xE6051009)
+#define GPIO_PORT10CR	IOMEM(0xE605100A)
+#define GPIO_PORT167CR	IOMEM(0xE60520A7)
+#define GPIO_PORT168CR	IOMEM(0xE60520A8)
+#define SRCR4		IOMEM(0xe61580bc)
+#define USCCR1		IOMEM(0xE6058144)
 static void __init mackerel_init(void)
 {
 	u32 srcr4;
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index ad5fccc..6729e00 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -41,29 +41,29 @@
  */
 
 /* CPG registers */
-#define FRQCRA		0xe6150000
-#define FRQCRB		0xe6150004
-#define VCLKCR1		0xE6150008
-#define VCLKCR2		0xE615000c
-#define FRQCRC		0xe61500e0
-#define FSIACKCR	0xe6150018
-#define PLLC01CR	0xe6150028
+#define FRQCRA		IOMEM(0xe6150000)
+#define FRQCRB		IOMEM(0xe6150004)
+#define VCLKCR1		IOMEM(0xE6150008)
+#define VCLKCR2		IOMEM(0xE615000c)
+#define FRQCRC		IOMEM(0xe61500e0)
+#define FSIACKCR	IOMEM(0xe6150018)
+#define PLLC01CR	IOMEM(0xe6150028)
 
-#define SUBCKCR		0xe6150080
-#define USBCKCR		0xe615008c
+#define SUBCKCR		IOMEM(0xe6150080)
+#define USBCKCR		IOMEM(0xe615008c)
 
-#define MSTPSR0		0xe6150030
-#define MSTPSR1		0xe6150038
-#define MSTPSR2		0xe6150040
-#define MSTPSR3		0xe6150048
-#define MSTPSR4		0xe615004c
-#define FSIBCKCR	0xe6150090
-#define HDMICKCR	0xe6150094
-#define SMSTPCR0	0xe6150130
-#define SMSTPCR1	0xe6150134
-#define SMSTPCR2	0xe6150138
-#define SMSTPCR3	0xe615013c
-#define SMSTPCR4	0xe6150140
+#define MSTPSR0		IOMEM(0xe6150030)
+#define MSTPSR1		IOMEM(0xe6150038)
+#define MSTPSR2		IOMEM(0xe6150040)
+#define MSTPSR3		IOMEM(0xe6150048)
+#define MSTPSR4		IOMEM(0xe615004c)
+#define FSIBCKCR	IOMEM(0xe6150090)
+#define HDMICKCR	IOMEM(0xe6150094)
+#define SMSTPCR0	IOMEM(0xe6150130)
+#define SMSTPCR1	IOMEM(0xe6150134)
+#define SMSTPCR2	IOMEM(0xe6150138)
+#define SMSTPCR3	IOMEM(0xe615013c)
+#define SMSTPCR4	IOMEM(0xe6150140)
 
 /* Fixed 32 KHz root clock from EXTALR pin */
 static struct clk extalr_clk = {
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
index 339c62c..3cafb6a 100644
--- a/arch/arm/mach-shmobile/clock-r8a7779.c
+++ b/arch/arm/mach-shmobile/clock-r8a7779.c
@@ -86,11 +86,16 @@
 				      0x0300, CLK_ENABLE_ON_INIT),
 };
 
-enum { MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
+enum { MSTP323, MSTP322, MSTP321, MSTP320,
+	MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
 	MSTP016, MSTP015, MSTP014,
 	MSTP_NR };
 
 static struct clk mstp_clks[MSTP_NR] = {
+	[MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0), /* SDHI0 */
+	[MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0), /* SDHI1 */
+	[MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0), /* SDHI2 */
+	[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0), /* SDHI3 */
 	[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0), /* SCIF0 */
 	[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0), /* SCIF1 */
 	[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0), /* SCIF2 */
@@ -149,6 +154,10 @@
 	CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP023]), /* SCIF3 */
 	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP022]), /* SCIF4 */
 	CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP021]), /* SCIF6 */
+	CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP323]), /* SDHI0 */
+	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */
+	CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
+	CLKDEV_DEV_ID("sh_mobile_sdhi.3", &mstp_clks[MSTP320]), /* SDHI3 */
 };
 
 void __init r8a7779_clock_init(void)
diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c
index 162b791..ef0a95e 100644
--- a/arch/arm/mach-shmobile/clock-sh7367.c
+++ b/arch/arm/mach-shmobile/clock-sh7367.c
@@ -24,28 +24,28 @@
 #include <mach/common.h>
 
 /* SH7367 registers */
-#define RTFRQCR    0xe6150000
-#define SYFRQCR    0xe6150004
-#define CMFRQCR    0xe61500E0
-#define VCLKCR1    0xe6150008
-#define VCLKCR2    0xe615000C
-#define VCLKCR3    0xe615001C
-#define SCLKACR    0xe6150010
-#define SCLKBCR    0xe6150014
-#define SUBUSBCKCR 0xe6158080
-#define SPUCKCR    0xe6150084
-#define MSUCKCR    0xe6150088
-#define MVI3CKCR   0xe6150090
-#define VOUCKCR    0xe6150094
-#define MFCK1CR    0xe6150098
-#define MFCK2CR    0xe615009C
-#define PLLC1CR    0xe6150028
-#define PLLC2CR    0xe615002C
-#define RTMSTPCR0  0xe6158030
-#define RTMSTPCR2  0xe6158038
-#define SYMSTPCR0  0xe6158040
-#define SYMSTPCR2  0xe6158048
-#define CMMSTPCR0  0xe615804c
+#define RTFRQCR    IOMEM(0xe6150000)
+#define SYFRQCR    IOMEM(0xe6150004)
+#define CMFRQCR    IOMEM(0xe61500E0)
+#define VCLKCR1    IOMEM(0xe6150008)
+#define VCLKCR2    IOMEM(0xe615000C)
+#define VCLKCR3    IOMEM(0xe615001C)
+#define SCLKACR    IOMEM(0xe6150010)
+#define SCLKBCR    IOMEM(0xe6150014)
+#define SUBUSBCKCR IOMEM(0xe6158080)
+#define SPUCKCR    IOMEM(0xe6150084)
+#define MSUCKCR    IOMEM(0xe6150088)
+#define MVI3CKCR   IOMEM(0xe6150090)
+#define VOUCKCR    IOMEM(0xe6150094)
+#define MFCK1CR    IOMEM(0xe6150098)
+#define MFCK2CR    IOMEM(0xe615009C)
+#define PLLC1CR    IOMEM(0xe6150028)
+#define PLLC2CR    IOMEM(0xe615002C)
+#define RTMSTPCR0  IOMEM(0xe6158030)
+#define RTMSTPCR2  IOMEM(0xe6158038)
+#define SYMSTPCR0  IOMEM(0xe6158040)
+#define SYMSTPCR2  IOMEM(0xe6158048)
+#define CMMSTPCR0  IOMEM(0xe615804c)
 
 /* Fixed 32 KHz root clock from EXTALR pin */
 static struct clk r_clk = {
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 5a2894b1..430a90f 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -24,36 +24,36 @@
 #include <mach/common.h>
 
 /* SH7372 registers */
-#define FRQCRA		0xe6150000
-#define FRQCRB		0xe6150004
-#define FRQCRC		0xe61500e0
-#define FRQCRD		0xe61500e4
-#define VCLKCR1		0xe6150008
-#define VCLKCR2		0xe615000c
-#define VCLKCR3		0xe615001c
-#define FMSICKCR	0xe6150010
-#define FMSOCKCR	0xe6150014
-#define FSIACKCR	0xe6150018
-#define FSIBCKCR	0xe6150090
-#define SUBCKCR		0xe6150080
-#define SPUCKCR		0xe6150084
-#define VOUCKCR		0xe6150088
-#define HDMICKCR	0xe6150094
-#define DSITCKCR	0xe6150060
-#define DSI0PCKCR	0xe6150064
-#define DSI1PCKCR	0xe6150098
-#define PLLC01CR	0xe6150028
-#define PLLC2CR		0xe615002c
-#define RMSTPCR0	0xe6150110
-#define RMSTPCR1	0xe6150114
-#define RMSTPCR2	0xe6150118
-#define RMSTPCR3	0xe615011c
-#define RMSTPCR4	0xe6150120
-#define SMSTPCR0	0xe6150130
-#define SMSTPCR1	0xe6150134
-#define SMSTPCR2	0xe6150138
-#define SMSTPCR3	0xe615013c
-#define SMSTPCR4	0xe6150140
+#define FRQCRA		IOMEM(0xe6150000)
+#define FRQCRB		IOMEM(0xe6150004)
+#define FRQCRC		IOMEM(0xe61500e0)
+#define FRQCRD		IOMEM(0xe61500e4)
+#define VCLKCR1		IOMEM(0xe6150008)
+#define VCLKCR2		IOMEM(0xe615000c)
+#define VCLKCR3		IOMEM(0xe615001c)
+#define FMSICKCR	IOMEM(0xe6150010)
+#define FMSOCKCR	IOMEM(0xe6150014)
+#define FSIACKCR	IOMEM(0xe6150018)
+#define FSIBCKCR	IOMEM(0xe6150090)
+#define SUBCKCR		IOMEM(0xe6150080)
+#define SPUCKCR		IOMEM(0xe6150084)
+#define VOUCKCR		IOMEM(0xe6150088)
+#define HDMICKCR	IOMEM(0xe6150094)
+#define DSITCKCR	IOMEM(0xe6150060)
+#define DSI0PCKCR	IOMEM(0xe6150064)
+#define DSI1PCKCR	IOMEM(0xe6150098)
+#define PLLC01CR	IOMEM(0xe6150028)
+#define PLLC2CR		IOMEM(0xe615002c)
+#define RMSTPCR0	IOMEM(0xe6150110)
+#define RMSTPCR1	IOMEM(0xe6150114)
+#define RMSTPCR2	IOMEM(0xe6150118)
+#define RMSTPCR3	IOMEM(0xe615011c)
+#define RMSTPCR4	IOMEM(0xe6150120)
+#define SMSTPCR0	IOMEM(0xe6150130)
+#define SMSTPCR1	IOMEM(0xe6150134)
+#define SMSTPCR2	IOMEM(0xe6150138)
+#define SMSTPCR3	IOMEM(0xe615013c)
+#define SMSTPCR4	IOMEM(0xe6150140)
 
 #define FSIDIVA		0xFE1F8000
 #define FSIDIVB		0xFE1F8008
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c
index 85f2a3e..b8480d1 100644
--- a/arch/arm/mach-shmobile/clock-sh7377.c
+++ b/arch/arm/mach-shmobile/clock-sh7377.c
@@ -24,31 +24,31 @@
 #include <mach/common.h>
 
 /* SH7377 registers */
-#define RTFRQCR    0xe6150000
-#define SYFRQCR    0xe6150004
-#define CMFRQCR    0xe61500E0
-#define VCLKCR1    0xe6150008
-#define VCLKCR2    0xe615000C
-#define VCLKCR3    0xe615001C
-#define FMSICKCR   0xe6150010
-#define FMSOCKCR   0xe6150014
-#define FSICKCR    0xe6150018
-#define PLLC1CR    0xe6150028
-#define PLLC2CR    0xe615002C
-#define SUBUSBCKCR 0xe6150080
-#define SPUCKCR    0xe6150084
-#define MSUCKCR    0xe6150088
-#define MVI3CKCR   0xe6150090
-#define HDMICKCR   0xe6150094
-#define MFCK1CR    0xe6150098
-#define MFCK2CR    0xe615009C
-#define DSITCKCR   0xe6150060
-#define DSIPCKCR   0xe6150064
-#define SMSTPCR0   0xe6150130
-#define SMSTPCR1   0xe6150134
-#define SMSTPCR2   0xe6150138
-#define SMSTPCR3   0xe615013C
-#define SMSTPCR4   0xe6150140
+#define RTFRQCR    IOMEM(0xe6150000)
+#define SYFRQCR    IOMEM(0xe6150004)
+#define CMFRQCR    IOMEM(0xe61500E0)
+#define VCLKCR1    IOMEM(0xe6150008)
+#define VCLKCR2    IOMEM(0xe615000C)
+#define VCLKCR3    IOMEM(0xe615001C)
+#define FMSICKCR   IOMEM(0xe6150010)
+#define FMSOCKCR   IOMEM(0xe6150014)
+#define FSICKCR    IOMEM(0xe6150018)
+#define PLLC1CR    IOMEM(0xe6150028)
+#define PLLC2CR    IOMEM(0xe615002C)
+#define SUBUSBCKCR IOMEM(0xe6150080)
+#define SPUCKCR    IOMEM(0xe6150084)
+#define MSUCKCR    IOMEM(0xe6150088)
+#define MVI3CKCR   IOMEM(0xe6150090)
+#define HDMICKCR   IOMEM(0xe6150094)
+#define MFCK1CR    IOMEM(0xe6150098)
+#define MFCK2CR    IOMEM(0xe615009C)
+#define DSITCKCR   IOMEM(0xe6150060)
+#define DSIPCKCR   IOMEM(0xe6150064)
+#define SMSTPCR0   IOMEM(0xe6150130)
+#define SMSTPCR1   IOMEM(0xe6150134)
+#define SMSTPCR2   IOMEM(0xe6150138)
+#define SMSTPCR3   IOMEM(0xe615013C)
+#define SMSTPCR4   IOMEM(0xe6150140)
 
 /* Fixed 32 KHz root clock from EXTALR pin */
 static struct clk r_clk = {
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 7f8da18..516ff7f 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -23,43 +23,43 @@
 #include <linux/clkdev.h>
 #include <mach/common.h>
 
-#define FRQCRA		0xe6150000
-#define FRQCRB		0xe6150004
-#define FRQCRD		0xe61500e4
-#define VCLKCR1		0xe6150008
-#define VCLKCR2		0xe615000C
-#define VCLKCR3		0xe615001C
-#define ZBCKCR		0xe6150010
-#define FLCKCR		0xe6150014
-#define SD0CKCR		0xe6150074
-#define SD1CKCR		0xe6150078
-#define SD2CKCR		0xe615007C
-#define FSIACKCR	0xe6150018
-#define FSIBCKCR	0xe6150090
-#define SUBCKCR		0xe6150080
-#define SPUACKCR	0xe6150084
-#define SPUVCKCR	0xe6150094
-#define MSUCKCR		0xe6150088
-#define HSICKCR		0xe615008C
-#define MFCK1CR		0xe6150098
-#define MFCK2CR		0xe615009C
-#define DSITCKCR	0xe6150060
-#define DSI0PCKCR	0xe6150064
-#define DSI1PCKCR	0xe6150068
+#define FRQCRA		IOMEM(0xe6150000)
+#define FRQCRB		IOMEM(0xe6150004)
+#define FRQCRD		IOMEM(0xe61500e4)
+#define VCLKCR1		IOMEM(0xe6150008)
+#define VCLKCR2		IOMEM(0xe615000C)
+#define VCLKCR3		IOMEM(0xe615001C)
+#define ZBCKCR		IOMEM(0xe6150010)
+#define FLCKCR		IOMEM(0xe6150014)
+#define SD0CKCR		IOMEM(0xe6150074)
+#define SD1CKCR		IOMEM(0xe6150078)
+#define SD2CKCR		IOMEM(0xe615007C)
+#define FSIACKCR	IOMEM(0xe6150018)
+#define FSIBCKCR	IOMEM(0xe6150090)
+#define SUBCKCR		IOMEM(0xe6150080)
+#define SPUACKCR	IOMEM(0xe6150084)
+#define SPUVCKCR	IOMEM(0xe6150094)
+#define MSUCKCR		IOMEM(0xe6150088)
+#define HSICKCR		IOMEM(0xe615008C)
+#define MFCK1CR		IOMEM(0xe6150098)
+#define MFCK2CR		IOMEM(0xe615009C)
+#define DSITCKCR	IOMEM(0xe6150060)
+#define DSI0PCKCR	IOMEM(0xe6150064)
+#define DSI1PCKCR	IOMEM(0xe6150068)
 #define DSI0PHYCR	0xe615006C
 #define DSI1PHYCR	0xe6150070
-#define PLLECR		0xe61500d0
-#define PLL0CR		0xe61500d8
-#define PLL1CR		0xe6150028
-#define PLL2CR		0xe615002c
-#define PLL3CR		0xe61500dc
-#define SMSTPCR0	0xe6150130
-#define SMSTPCR1	0xe6150134
-#define SMSTPCR2	0xe6150138
-#define SMSTPCR3	0xe615013c
-#define SMSTPCR4	0xe6150140
-#define SMSTPCR5	0xe6150144
-#define CKSCR		0xe61500c0
+#define PLLECR		IOMEM(0xe61500d0)
+#define PLL0CR		IOMEM(0xe61500d8)
+#define PLL1CR		IOMEM(0xe6150028)
+#define PLL2CR		IOMEM(0xe615002c)
+#define PLL3CR		IOMEM(0xe61500dc)
+#define SMSTPCR0	IOMEM(0xe6150130)
+#define SMSTPCR1	IOMEM(0xe6150134)
+#define SMSTPCR2	IOMEM(0xe6150138)
+#define SMSTPCR3	IOMEM(0xe615013c)
+#define SMSTPCR4	IOMEM(0xe6150140)
+#define SMSTPCR5	IOMEM(0xe6150144)
+#define CKSCR		IOMEM(0xe61500c0)
 
 /* Fixed 32 KHz root clock from EXTALR pin */
 static struct clk r_clk = {
diff --git a/arch/arm/mach-shmobile/include/mach/gpio.h b/arch/arm/mach-shmobile/include/mach/gpio.h
index 844507d..90a92b2 100644
--- a/arch/arm/mach-shmobile/include/mach/gpio.h
+++ b/arch/arm/mach-shmobile/include/mach/gpio.h
@@ -35,12 +35,12 @@
  * the method to control only pull up/down/free.
  * this function should be replaced by correct gpio function
  */
-static inline void __init gpio_direction_none(u32 addr)
+static inline void __init gpio_direction_none(void __iomem * addr)
 {
 	__raw_writeb(0x00, addr);
 }
 
-static inline void __init gpio_request_pullup(u32 addr)
+static inline void __init gpio_request_pullup(void __iomem * addr)
 {
 	u8 data = __raw_readb(addr);
 
@@ -49,7 +49,7 @@
 	__raw_writeb(data, addr);
 }
 
-static inline void __init gpio_request_pulldown(u32 addr)
+static inline void __init gpio_request_pulldown(void __iomem * addr)
 {
 	u8 data = __raw_readb(addr);
 
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
index f04fad4..ef66f1a 100644
--- a/arch/arm/mach-shmobile/intc-r8a7779.c
+++ b/arch/arm/mach-shmobile/intc-r8a7779.c
@@ -29,14 +29,14 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#define INT2SMSKCR0 0xfe7822a0
-#define INT2SMSKCR1 0xfe7822a4
-#define INT2SMSKCR2 0xfe7822a8
-#define INT2SMSKCR3 0xfe7822ac
-#define INT2SMSKCR4 0xfe7822b0
+#define INT2SMSKCR0 IOMEM(0xfe7822a0)
+#define INT2SMSKCR1 IOMEM(0xfe7822a4)
+#define INT2SMSKCR2 IOMEM(0xfe7822a8)
+#define INT2SMSKCR3 IOMEM(0xfe7822ac)
+#define INT2SMSKCR4 IOMEM(0xfe7822b0)
 
-#define INT2NTSR0 0xfe700060
-#define INT2NTSR1 0xfe700064
+#define INT2NTSR0 IOMEM(0xfe700060)
+#define INT2NTSR1 IOMEM(0xfe700064)
 
 static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
 {
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 2587a22..a91caad 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -624,6 +624,9 @@
 		__raw_writeb(ffd5[k], intcs_ffd5 + k);
 }
 
+#define E694_BASE IOMEM(0xe6940000)
+#define E695_BASE IOMEM(0xe6950000)
+
 static unsigned short e694[0x200];
 static unsigned short e695[0x200];
 
@@ -632,22 +635,22 @@
 	int k;
 
 	for (k = 0x00; k <= 0x38; k += 4)
-		e694[k] = __raw_readw(0xe6940000 + k);
+		e694[k] = __raw_readw(E694_BASE + k);
 
 	for (k = 0x80; k <= 0xb4; k += 4)
-		e694[k] = __raw_readb(0xe6940000 + k);
+		e694[k] = __raw_readb(E694_BASE + k);
 
 	for (k = 0x180; k <= 0x1b4; k += 4)
-		e694[k] = __raw_readb(0xe6940000 + k);
+		e694[k] = __raw_readb(E694_BASE + k);
 
 	for (k = 0x00; k <= 0x50; k += 4)
-		e695[k] = __raw_readw(0xe6950000 + k);
+		e695[k] = __raw_readw(E695_BASE + k);
 
 	for (k = 0x80; k <= 0xa8; k += 4)
-		e695[k] = __raw_readb(0xe6950000 + k);
+		e695[k] = __raw_readb(E695_BASE + k);
 
 	for (k = 0x180; k <= 0x1a8; k += 4)
-		e695[k] = __raw_readb(0xe6950000 + k);
+		e695[k] = __raw_readb(E695_BASE + k);
 }
 
 void sh7372_intca_resume(void)
@@ -655,20 +658,20 @@
 	int k;
 
 	for (k = 0x00; k <= 0x38; k += 4)
-		__raw_writew(e694[k], 0xe6940000 + k);
+		__raw_writew(e694[k], E694_BASE + k);
 
 	for (k = 0x80; k <= 0xb4; k += 4)
-		__raw_writeb(e694[k], 0xe6940000 + k);
+		__raw_writeb(e694[k], E694_BASE + k);
 
 	for (k = 0x180; k <= 0x1b4; k += 4)
-		__raw_writeb(e694[k], 0xe6940000 + k);
+		__raw_writeb(e694[k], E694_BASE + k);
 
 	for (k = 0x00; k <= 0x50; k += 4)
-		__raw_writew(e695[k], 0xe6950000 + k);
+		__raw_writew(e695[k], E695_BASE + k);
 
 	for (k = 0x80; k <= 0xa8; k += 4)
-		__raw_writeb(e695[k], 0xe6950000 + k);
+		__raw_writeb(e695[k], E695_BASE + k);
 
 	for (k = 0x180; k <= 0x1a8; k += 4)
-		__raw_writeb(e695[k], 0xe6950000 + k);
+		__raw_writeb(e695[k], E695_BASE + k);
 }
diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c
index 588555a..f0c5e51 100644
--- a/arch/arm/mach-shmobile/intc-sh73a0.c
+++ b/arch/arm/mach-shmobile/intc-sh73a0.c
@@ -366,10 +366,12 @@
 
 static struct irqaction sh73a0_irq_pin_cascade[32];
 
-#define PINTER0 0xe69000a0
-#define PINTER1 0xe69000a4
-#define PINTRR0 0xe69000d0
-#define PINTRR1 0xe69000d4
+#define PINTER0_PHYS 0xe69000a0
+#define PINTER1_PHYS 0xe69000a4
+#define PINTER0_VIRT IOMEM(0xe69000a0)
+#define PINTER1_VIRT IOMEM(0xe69000a4)
+#define PINTRR0 IOMEM(0xe69000d0)
+#define PINTRR1 IOMEM(0xe69000d4)
 
 #define PINT0A_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq))
 #define PINT0B_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 8))
@@ -377,14 +379,14 @@
 #define PINT0D_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 24))
 #define PINT1E_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT1_IRQ(irq))
 
-INTC_PINT(intc_pint0, PINTER0, 0xe69000b0, "sh73a0-pint0",		\
+INTC_PINT(intc_pint0, PINTER0_PHYS, 0xe69000b0, "sh73a0-pint0",		\
   INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D),	\
   INTC_PINT_V(A, PINT0A_IRQ), INTC_PINT_V(B, PINT0B_IRQ),		\
   INTC_PINT_V(C, PINT0C_IRQ), INTC_PINT_V(D, PINT0D_IRQ),		\
   INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D),	\
   INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D));
 
-INTC_PINT(intc_pint1, PINTER1, 0xe69000c0, "sh73a0-pint1",		\
+INTC_PINT(intc_pint1, PINTER1_PHYS, 0xe69000c0, "sh73a0-pint1",		\
   INTC_PINT_E(E), INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, \
   INTC_PINT_V(E, PINT1E_IRQ), INTC_PINT_V_NONE,				\
   INTC_PINT_V_NONE, INTC_PINT_V_NONE,					\
@@ -394,7 +396,7 @@
 static struct irqaction sh73a0_pint0_cascade;
 static struct irqaction sh73a0_pint1_cascade;
 
-static void pint_demux(unsigned long rr, unsigned long er, int base_irq)
+static void pint_demux(void __iomem *rr, void __iomem *er, int base_irq)
 {
 	unsigned long value =  ioread32(rr) & ioread32(er);
 	int k;
@@ -409,13 +411,13 @@
 
 static irqreturn_t sh73a0_pint0_demux(int irq, void *dev_id)
 {
-	pint_demux(PINTRR0, PINTER0, SH73A0_PINT0_IRQ(0));
+	pint_demux(PINTRR0, PINTER0_VIRT, SH73A0_PINT0_IRQ(0));
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t sh73a0_pint1_demux(int irq, void *dev_id)
 {
-	pint_demux(PINTRR1, PINTER1, SH73A0_PINT1_IRQ(0));
+	pint_demux(PINTRR1, PINTER1_VIRT, SH73A0_PINT1_IRQ(0));
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index a856254..32e1772 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -20,9 +20,9 @@
 #include <mach/pm-rmobile.h>
 
 /* SYSC */
-#define SPDCR		0xe6180008
-#define SWUCR		0xe6180014
-#define PSTR		0xe6180080
+#define SPDCR		IOMEM(0xe6180008)
+#define SWUCR		IOMEM(0xe6180014)
+#define PSTR		IOMEM(0xe6180080)
 
 #define PSTR_RETRIES	100
 #define PSTR_DELAY_US	10
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 7920370..1621218 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -29,45 +29,46 @@
 #include <mach/pm-rmobile.h>
 
 /* DBG */
-#define DBGREG1 0xe6100020
-#define DBGREG9 0xe6100040
+#define DBGREG1 IOMEM(0xe6100020)
+#define DBGREG9 IOMEM(0xe6100040)
 
 /* CPGA */
-#define SYSTBCR 0xe6150024
-#define MSTPSR0 0xe6150030
-#define MSTPSR1 0xe6150038
-#define MSTPSR2 0xe6150040
-#define MSTPSR3 0xe6150048
-#define MSTPSR4 0xe615004c
-#define PLLC01STPCR 0xe61500c8
+#define SYSTBCR IOMEM(0xe6150024)
+#define MSTPSR0 IOMEM(0xe6150030)
+#define MSTPSR1 IOMEM(0xe6150038)
+#define MSTPSR2 IOMEM(0xe6150040)
+#define MSTPSR3 IOMEM(0xe6150048)
+#define MSTPSR4 IOMEM(0xe615004c)
+#define PLLC01STPCR IOMEM(0xe61500c8)
 
 /* SYSC */
-#define SBAR 0xe6180020
-#define WUPRMSK 0xe6180028
-#define WUPSMSK 0xe618002c
-#define WUPSMSK2 0xe6180048
-#define WUPSFAC 0xe6180098
-#define IRQCR 0xe618022c
-#define IRQCR2 0xe6180238
-#define IRQCR3 0xe6180244
-#define IRQCR4 0xe6180248
-#define PDNSEL 0xe6180254
+#define SBAR IOMEM(0xe6180020)
+#define WUPRMSK IOMEM(0xe6180028)
+#define WUPSMSK IOMEM(0xe618002c)
+#define WUPSMSK2 IOMEM(0xe6180048)
+#define WUPSFAC IOMEM(0xe6180098)
+#define IRQCR IOMEM(0xe618022c)
+#define IRQCR2 IOMEM(0xe6180238)
+#define IRQCR3 IOMEM(0xe6180244)
+#define IRQCR4 IOMEM(0xe6180248)
+#define PDNSEL IOMEM(0xe6180254)
 
 /* INTC */
-#define ICR1A 0xe6900000
-#define ICR2A 0xe6900004
-#define ICR3A 0xe6900008
-#define ICR4A 0xe690000c
-#define INTMSK00A 0xe6900040
-#define INTMSK10A 0xe6900044
-#define INTMSK20A 0xe6900048
-#define INTMSK30A 0xe690004c
+#define ICR1A IOMEM(0xe6900000)
+#define ICR2A IOMEM(0xe6900004)
+#define ICR3A IOMEM(0xe6900008)
+#define ICR4A IOMEM(0xe690000c)
+#define INTMSK00A IOMEM(0xe6900040)
+#define INTMSK10A IOMEM(0xe6900044)
+#define INTMSK20A IOMEM(0xe6900048)
+#define INTMSK30A IOMEM(0xe690004c)
 
 /* MFIS */
+/* FIXME: pointing where? */
 #define SMFRAM 0xe6a70000
 
 /* AP-System Core */
-#define APARMBAREA 0xe6f10020
+#define APARMBAREA IOMEM(0xe6f10020)
 
 #ifdef CONFIG_PM
 
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
index dae9aa6..61446f3 100644
--- a/arch/arm/mach-shmobile/setup-emev2.c
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -356,6 +356,26 @@
 	},
 };
 
+static struct resource pmu_resources[] = {
+	[0] = {
+		.start	= 152,
+		.end	= 152,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[1] = {
+		.start	= 153,
+		.end	= 153,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device pmu_device = {
+	.name		= "arm-pmu",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(pmu_resources),
+	.resource	= pmu_resources,
+};
+
 static struct platform_device *emev2_early_devices[] __initdata = {
 	&uart0_device,
 	&uart1_device,
@@ -370,6 +390,7 @@
 	&gio2_device,
 	&gio3_device,
 	&gio4_device,
+	&pmu_device,
 };
 
 void __init emev2_add_standard_devices(void)
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c
index 2e3074a..e647f54 100644
--- a/arch/arm/mach-shmobile/setup-sh7367.c
+++ b/arch/arm/mach-shmobile/setup-sh7367.c
@@ -462,7 +462,7 @@
 	shmobile_earlytimer_init();
 }
 
-#define SYMSTPCR2 0xe6158048
+#define SYMSTPCR2 IOMEM(0xe6158048)
 #define SYMSTPCR2_CMT1 (1 << 29)
 
 void __init sh7367_add_early_devices(void)
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c
index 855b150..edcf98b 100644
--- a/arch/arm/mach-shmobile/setup-sh7377.c
+++ b/arch/arm/mach-shmobile/setup-sh7377.c
@@ -484,7 +484,7 @@
 	shmobile_earlytimer_init();
 }
 
-#define SMSTPCR3 0xe615013c
+#define SMSTPCR3 IOMEM(0xe615013c)
 #define SMSTPCR3_CMT1 (1 << 29)
 
 void __init sh7377_add_early_devices(void)
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index d230af6..db99a4a 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -734,6 +734,26 @@
 	},
 };
 
+static struct resource pmu_resources[] = {
+	[0] = {
+		.start	= gic_spi(55),
+		.end	= gic_spi(55),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[1] = {
+		.start	= gic_spi(56),
+		.end	= gic_spi(56),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device pmu_device = {
+	.name		= "arm-pmu",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(pmu_resources),
+	.resource	= pmu_resources,
+};
+
 static struct platform_device *sh73a0_early_devices[] __initdata = {
 	&scif0_device,
 	&scif1_device,
@@ -757,9 +777,10 @@
 	&i2c4_device,
 	&dma0_device,
 	&mpdma0_device,
+	&pmu_device,
 };
 
-#define SRCR2          0xe61580b0
+#define SRCR2          IOMEM(0xe61580b0)
 
 void __init sh73a0_add_standard_devices(void)
 {
diff --git a/arch/arm/mach-spear13xx/include/mach/spear.h b/arch/arm/mach-spear13xx/include/mach/spear.h
index 65f27de..07d90ac 100644
--- a/arch/arm/mach-spear13xx/include/mach/spear.h
+++ b/arch/arm/mach-spear13xx/include/mach/spear.h
@@ -17,26 +17,26 @@
 #include <asm/memory.h>
 
 #define PERIP_GRP2_BASE				UL(0xB3000000)
-#define VA_PERIP_GRP2_BASE			UL(0xFE000000)
+#define VA_PERIP_GRP2_BASE			IOMEM(0xFE000000)
 #define MCIF_SDHCI_BASE				UL(0xB3000000)
 #define SYSRAM0_BASE				UL(0xB3800000)
-#define VA_SYSRAM0_BASE				UL(0xFE800000)
+#define VA_SYSRAM0_BASE				IOMEM(0xFE800000)
 #define SYS_LOCATION				(VA_SYSRAM0_BASE + 0x600)
 
 #define PERIP_GRP1_BASE				UL(0xE0000000)
-#define VA_PERIP_GRP1_BASE			UL(0xFD000000)
+#define VA_PERIP_GRP1_BASE			IOMEM(0xFD000000)
 #define UART_BASE				UL(0xE0000000)
-#define VA_UART_BASE				UL(0xFD000000)
+#define VA_UART_BASE				IOMEM(0xFD000000)
 #define SSP_BASE				UL(0xE0100000)
 #define MISC_BASE				UL(0xE0700000)
-#define VA_MISC_BASE				IOMEM(UL(0xFD700000))
+#define VA_MISC_BASE				IOMEM(0xFD700000)
 
 #define A9SM_AND_MPMC_BASE			UL(0xEC000000)
-#define VA_A9SM_AND_MPMC_BASE			UL(0xFC000000)
+#define VA_A9SM_AND_MPMC_BASE			IOMEM(0xFC000000)
 
 /* A9SM peripheral offsets */
 #define A9SM_PERIP_BASE				UL(0xEC800000)
-#define VA_A9SM_PERIP_BASE			UL(0xFC800000)
+#define VA_A9SM_PERIP_BASE			IOMEM(0xFC800000)
 #define VA_SCU_BASE				(VA_A9SM_PERIP_BASE + 0x00)
 
 #define L2CC_BASE				UL(0xED000000)
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index cf936b1..e106488 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -114,17 +114,17 @@
  */
 struct map_desc spear13xx_io_desc[] __initdata = {
 	{
-		.virtual	= VA_PERIP_GRP2_BASE,
+		.virtual	= (unsigned long)VA_PERIP_GRP2_BASE,
 		.pfn		= __phys_to_pfn(PERIP_GRP2_BASE),
 		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= VA_PERIP_GRP1_BASE,
+		.virtual	= (unsigned long)VA_PERIP_GRP1_BASE,
 		.pfn		= __phys_to_pfn(PERIP_GRP1_BASE),
 		.length		= SZ_16M,
 		.type		= MT_DEVICE
 	}, {
-		.virtual	= VA_A9SM_AND_MPMC_BASE,
+		.virtual	= (unsigned long)VA_A9SM_AND_MPMC_BASE,
 		.pfn		= __phys_to_pfn(A9SM_AND_MPMC_BASE),
 		.length		= SZ_16M,
 		.type		= MT_DEVICE
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 9077aaa..5f3c03b 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -34,7 +34,6 @@
 	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 	select USB_ULPI if USB
 	select USB_ULPI_VIEWPORT if USB_SUPPORT
-	select USE_OF
 	select ARM_ERRATA_743622
 	select ARM_ERRATA_751472
 	select ARM_ERRATA_754322
@@ -60,25 +59,6 @@
 
 comment "Tegra board type"
 
-config MACH_HARMONY
-       bool "Harmony board"
-       depends on ARCH_TEGRA_2x_SOC
-       help
-         Support for nVidia Harmony development platform
-
-config MACH_PAZ00
-       bool "Paz00 board"
-       depends on ARCH_TEGRA_2x_SOC
-       help
-         Support for the Toshiba AC100/Dynabook AZ netbook
-
-config MACH_TRIMSLICE
-       bool "TrimSlice board"
-       depends on ARCH_TEGRA_2x_SOC
-       select TEGRA_PCI
-       help
-         Support for CompuLab TrimSlice platform
-
 choice
         prompt "Default low-level debug console UART"
         default TEGRA_DEBUG_UART_NONE
@@ -130,13 +110,6 @@
 
 endchoice
 
-config TEGRA_SYSTEM_DMA
-	bool "Enable system DMA driver for NVIDIA Tegra SoCs"
-	default y
-	help
-	  Adds system DMA functionality for NVIDIA Tegra SoCs, used by
-	  several Tegra device drivers
-
 config TEGRA_EMC_SCALING_ENABLE
 	bool "Enable scaling the memory frequency"
 
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index c3d7303..77b1970 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -12,27 +12,22 @@
 obj-y					+= apbio.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_CPU_IDLE)			+= sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks_data.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-t30.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
-obj-$(CONFIG_USB_SUPPORT)		+= usb_phy.o
 
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-dt-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
 
-obj-$(CONFIG_MACH_HARMONY)              += board-harmony.o
-obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pinmux.o
-obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pcie.o
-obj-$(CONFIG_MACH_HARMONY)              += board-harmony-power.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-harmony-pcie.o
 
-obj-$(CONFIG_MACH_PAZ00)		+= board-paz00.o
-obj-$(CONFIG_MACH_PAZ00)		+= board-paz00-pinmux.o
-
-obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice.o
-obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice-pinmux.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-paz00.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index dc0fe38..b5015d0 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -28,7 +28,7 @@
 
 #include "apbio.h"
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA) || defined(CONFIG_TEGRA20_APB_DMA)
+#if defined(CONFIG_TEGRA20_APB_DMA)
 static DEFINE_MUTEX(tegra_apb_dma_lock);
 static u32 *tegra_apb_bb;
 static dma_addr_t tegra_apb_bb_phys;
@@ -37,121 +37,6 @@
 static u32 tegra_apb_readl_direct(unsigned long offset);
 static void tegra_apb_writel_direct(u32 value, unsigned long offset);
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-static struct tegra_dma_channel *tegra_apb_dma;
-
-bool tegra_apb_init(void)
-{
-	struct tegra_dma_channel *ch;
-
-	mutex_lock(&tegra_apb_dma_lock);
-
-	/* Check to see if we raced to setup */
-	if (tegra_apb_dma)
-		goto out;
-
-	ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
-		TEGRA_DMA_SHARED);
-
-	if (!ch)
-		goto out_fail;
-
-	tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
-		&tegra_apb_bb_phys, GFP_KERNEL);
-	if (!tegra_apb_bb) {
-		pr_err("%s: can not allocate bounce buffer\n", __func__);
-		tegra_dma_free_channel(ch);
-		goto out_fail;
-	}
-
-	tegra_apb_dma = ch;
-out:
-	mutex_unlock(&tegra_apb_dma_lock);
-	return true;
-
-out_fail:
-	mutex_unlock(&tegra_apb_dma_lock);
-	return false;
-}
-
-static void apb_dma_complete(struct tegra_dma_req *req)
-{
-	complete(&tegra_apb_wait);
-}
-
-static u32 tegra_apb_readl_using_dma(unsigned long offset)
-{
-	struct tegra_dma_req req;
-	int ret;
-
-	if (!tegra_apb_dma && !tegra_apb_init())
-		return tegra_apb_readl_direct(offset);
-
-	mutex_lock(&tegra_apb_dma_lock);
-	req.complete = apb_dma_complete;
-	req.to_memory = 1;
-	req.dest_addr = tegra_apb_bb_phys;
-	req.dest_bus_width = 32;
-	req.dest_wrap = 1;
-	req.source_addr = offset;
-	req.source_bus_width = 32;
-	req.source_wrap = 4;
-	req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
-	req.size = 4;
-
-	INIT_COMPLETION(tegra_apb_wait);
-
-	tegra_dma_enqueue_req(tegra_apb_dma, &req);
-
-	ret = wait_for_completion_timeout(&tegra_apb_wait,
-		msecs_to_jiffies(50));
-
-	if (WARN(ret == 0, "apb read dma timed out")) {
-		tegra_dma_dequeue_req(tegra_apb_dma, &req);
-		*(u32 *)tegra_apb_bb = 0;
-	}
-
-	mutex_unlock(&tegra_apb_dma_lock);
-	return *((u32 *)tegra_apb_bb);
-}
-
-static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
-{
-	struct tegra_dma_req req;
-	int ret;
-
-	if (!tegra_apb_dma && !tegra_apb_init()) {
-		tegra_apb_writel_direct(value, offset);
-		return;
-	}
-
-	mutex_lock(&tegra_apb_dma_lock);
-	*((u32 *)tegra_apb_bb) = value;
-	req.complete = apb_dma_complete;
-	req.to_memory = 0;
-	req.dest_addr = offset;
-	req.dest_wrap = 4;
-	req.dest_bus_width = 32;
-	req.source_addr = tegra_apb_bb_phys;
-	req.source_bus_width = 32;
-	req.source_wrap = 1;
-	req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
-	req.size = 4;
-
-	INIT_COMPLETION(tegra_apb_wait);
-
-	tegra_dma_enqueue_req(tegra_apb_dma, &req);
-
-	ret = wait_for_completion_timeout(&tegra_apb_wait,
-		msecs_to_jiffies(50));
-
-	if (WARN(ret == 0, "apb write dma timed out"))
-		tegra_dma_dequeue_req(tegra_apb_dma, &req);
-
-	mutex_unlock(&tegra_apb_dma_lock);
-}
-
-#else
 static struct dma_chan *tegra_apb_dma_chan;
 static struct dma_slave_config dma_sconfig;
 
@@ -279,7 +164,6 @@
 		pr_err("error in writing offset 0x%08lx using dma\n", offset);
 	mutex_unlock(&tegra_apb_dma_lock);
 }
-#endif
 #else
 #define tegra_apb_readl_using_dma tegra_apb_readl_direct
 #define tegra_apb_writel_using_dma tegra_apb_writel_direct
@@ -293,12 +177,12 @@
 
 static u32 tegra_apb_readl_direct(unsigned long offset)
 {
-	return readl(IO_TO_VIRT(offset));
+	return readl(IO_ADDRESS(offset));
 }
 
 static void tegra_apb_writel_direct(u32 value, unsigned long offset)
 {
-	writel(value, IO_TO_VIRT(offset));
+	writel(value, IO_ADDRESS(offset));
 }
 
 void tegra_apb_io_init(void)
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index c099963..5957ffb 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -42,7 +42,6 @@
 #include <mach/irqs.h>
 
 #include "board.h"
-#include "board-harmony.h"
 #include "clock.h"
 #include "devices.h"
 
@@ -71,6 +70,7 @@
 
 static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
 	/* name		parent		rate		enabled */
+	{ "uarta",	"pll_p",	216000000,	true },
 	{ "uartd",	"pll_p",	216000000,	true },
 	{ "usbd",	"clk_m",	12000000,	false },
 	{ "usb2",	"clk_m",	12000000,	false },
@@ -95,54 +95,40 @@
 				tegra20_auxdata_lookup, NULL);
 }
 
-#ifdef CONFIG_MACH_TRIMSLICE
 static void __init trimslice_init(void)
 {
+#ifdef CONFIG_TEGRA_PCI
 	int ret;
 
 	ret = tegra_pcie_init(true, true);
 	if (ret)
 		pr_err("tegra_pci_init() failed: %d\n", ret);
-}
 #endif
+}
 
-#ifdef CONFIG_MACH_HARMONY
 static void __init harmony_init(void)
 {
+#ifdef CONFIG_TEGRA_PCI
 	int ret;
 
-	ret = harmony_regulator_init();
-	if (ret) {
-		pr_err("harmony_regulator_init() failed: %d\n", ret);
-		return;
-	}
-
 	ret = harmony_pcie_init();
 	if (ret)
 		pr_err("harmony_pcie_init() failed: %d\n", ret);
-}
 #endif
+}
 
-#ifdef CONFIG_MACH_PAZ00
 static void __init paz00_init(void)
 {
 	tegra_paz00_wifikill_init();
 }
-#endif
 
 static struct {
 	char *machine;
 	void (*init)(void);
 } board_init_funcs[] = {
-#ifdef CONFIG_MACH_TRIMSLICE
 	{ "compulab,trimslice", trimslice_init },
-#endif
-#ifdef CONFIG_MACH_HARMONY
 	{ "nvidia,harmony", harmony_init },
-#endif
-#ifdef CONFIG_MACH_PAZ00
 	{ "compal,paz00", paz00_init },
-#endif
 };
 
 static void __init tegra_dt_init_late(void)
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
index e8c3fda..3cdc1bb 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -18,35 +18,57 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <linux/err.h>
+#include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
 
 #include <asm/mach-types.h>
 
 #include "board.h"
-#include "board-harmony.h"
 
 #ifdef CONFIG_TEGRA_PCI
 
 int __init harmony_pcie_init(void)
 {
+	struct device_node *np;
+	int en_vdd_1v05;
 	struct regulator *regulator = NULL;
 	int err;
 
-	err = gpio_request(TEGRA_GPIO_EN_VDD_1V05_GPIO, "EN_VDD_1V05");
-	if (err)
+	np = of_find_node_by_path("/regulators/regulator@3");
+	if (!np) {
+		pr_err("%s: of_find_node_by_path failed\n", __func__);
+		return -ENODEV;
+	}
+
+	en_vdd_1v05 = of_get_named_gpio(np, "gpio", 0);
+	if (en_vdd_1v05 < 0) {
+		pr_err("%s: of_get_named_gpio failed: %d\n", __func__,
+		       en_vdd_1v05);
+		return en_vdd_1v05;
+	}
+
+	err = gpio_request(en_vdd_1v05, "EN_VDD_1V05");
+	if (err) {
+		pr_err("%s: gpio_request failed: %d\n", __func__, err);
 		return err;
+	}
 
-	gpio_direction_output(TEGRA_GPIO_EN_VDD_1V05_GPIO, 1);
+	gpio_direction_output(en_vdd_1v05, 1);
 
-	regulator = regulator_get(NULL, "pex_clk");
-	if (IS_ERR_OR_NULL(regulator))
+	regulator = regulator_get(NULL, "vdd_ldo0,vddio_pex_clk");
+	if (IS_ERR_OR_NULL(regulator)) {
+		pr_err("%s: regulator_get failed: %d\n", __func__,
+		       (int)PTR_ERR(regulator));
 		goto err_reg;
+	}
 
 	regulator_enable(regulator);
 
 	err = tegra_pcie_init(true, true);
-	if (err)
+	if (err) {
+		pr_err("%s: tegra_pcie_init failed: %d\n", __func__, err);
 		goto err_pcie;
+	}
 
 	return 0;
 
@@ -54,20 +76,9 @@
 	regulator_disable(regulator);
 	regulator_put(regulator);
 err_reg:
-	gpio_free(TEGRA_GPIO_EN_VDD_1V05_GPIO);
+	gpio_free(en_vdd_1v05);
 
 	return err;
 }
 
-static int __init harmony_pcie_initcall(void)
-{
-	if (!machine_is_harmony())
-		return 0;
-
-	return harmony_pcie_init();
-}
-
-/* PCI should be initialized after I2C, mfd and regulators */
-subsys_initcall_sync(harmony_pcie_initcall);
-
 #endif
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
deleted file mode 100644
index 83d420f..0000000
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-harmony-pinmux.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-
-#include "board-harmony.h"
-#include "board-pinmux.h"
-
-static struct pinctrl_map harmony_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "ide",           none, driven),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "nand",          none, driven),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, tristate),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
-	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", down, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
-	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
-	TEGRA_MAP_MUXCONF("dta",   "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("dtb",   "rsvd1",         none, driven),
-	TEGRA_MAP_MUXCONF("dtc",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtd",   "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("dte",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, tristate),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gmc",   "uartd",         none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
-	TEGRA_MAP_MUXCONF("irrx",  "uarta",         up,   tristate),
-	TEGRA_MAP_MUXCONF("irtx",  "uarta",         up,   tristate),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         na,   tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
-	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
-	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   tristate),
-	TEGRA_MAP_MUXCONF("sdc",   "pwm",           up,   driven),
-	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   tristate),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("slxc",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("spia",  "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("spib",  "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   tristate),
-	TEGRA_MAP_MUXCONF("spid",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "spi1",          up,   tristate),
-	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      none, tristate),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("uad",   "irda",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, tristate),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct tegra_board_pinmux_conf conf = {
-	.maps = harmony_map,
-	.map_count = ARRAY_SIZE(harmony_map),
-};
-
-void harmony_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&conf, NULL);
-}
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
deleted file mode 100644
index b7344be..0000000
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2010 NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307, USA
- */
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/mfd/tps6586x.h>
-#include <linux/of.h>
-#include <linux/of_i2c.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/irqs.h>
-
-#include "board-harmony.h"
-
-static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
-	REGULATOR_SUPPLY("pex_clk", NULL),
-};
-
-static struct regulator_init_data ldo0_data = {
-	.supply_regulator = "vdd_sm2",
-	.constraints = {
-		.name = "vdd_ldo0",
-		.min_uV = 3300 * 1000,
-		.max_uV = 3300 * 1000,
-		.valid_modes_mask = (REGULATOR_MODE_NORMAL |
-				     REGULATOR_MODE_STANDBY),
-		.valid_ops_mask = (REGULATOR_CHANGE_MODE |
-				   REGULATOR_CHANGE_STATUS |
-				   REGULATOR_CHANGE_VOLTAGE),
-		.apply_uV = 1,
-	},
-	.num_consumer_supplies = ARRAY_SIZE(tps658621_ldo0_supply),
-	.consumer_supplies = tps658621_ldo0_supply,
-};
-
-#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv, _on)\
-	static struct regulator_init_data _id##_data = {		\
-		.supply_regulator = _supply,				\
-		.constraints = {					\
-			.name = _name,					\
-			.min_uV = (_minmv)*1000,			\
-			.max_uV = (_maxmv)*1000,			\
-			.valid_modes_mask = (REGULATOR_MODE_NORMAL |	\
-					     REGULATOR_MODE_STANDBY),	\
-			.valid_ops_mask = (REGULATOR_CHANGE_MODE |	\
-					   REGULATOR_CHANGE_STATUS |	\
-					   REGULATOR_CHANGE_VOLTAGE),	\
-			.always_on = _on,				\
-		},							\
-	}
-
-HARMONY_REGULATOR_INIT(sm0,  "vdd_sm0",  "vdd_sys", 725, 1500, 1);
-HARMONY_REGULATOR_INIT(sm1,  "vdd_sm1",  "vdd_sys", 725, 1500, 1);
-HARMONY_REGULATOR_INIT(sm2,  "vdd_sm2",  "vdd_sys", 3000, 4550, 1);
-HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500, 1);
-HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500, 0);
-HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300, 1);
-HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475, 1);
-HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL,	    1250, 3300, 1);
-HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300, 0);
-HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300, 0);
-HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300, 0);
-HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300, 1);
-
-#define TPS_REG(_id, _data)			\
-	{					\
-		.id = TPS6586X_ID_##_id,	\
-		.name = "tps6586x-regulator",	\
-		.platform_data = _data,		\
-	}
-
-static struct tps6586x_subdev_info tps_devs[] = {
-	TPS_REG(SM_0, &sm0_data),
-	TPS_REG(SM_1, &sm1_data),
-	TPS_REG(SM_2, &sm2_data),
-	TPS_REG(LDO_0, &ldo0_data),
-	TPS_REG(LDO_1, &ldo1_data),
-	TPS_REG(LDO_2, &ldo2_data),
-	TPS_REG(LDO_3, &ldo3_data),
-	TPS_REG(LDO_4, &ldo4_data),
-	TPS_REG(LDO_5, &ldo5_data),
-	TPS_REG(LDO_6, &ldo6_data),
-	TPS_REG(LDO_7, &ldo7_data),
-	TPS_REG(LDO_8, &ldo8_data),
-	TPS_REG(LDO_9, &ldo9_data),
-};
-
-static struct tps6586x_platform_data tps_platform = {
-	.irq_base	= TEGRA_NR_IRQS,
-	.num_subdevs	= ARRAY_SIZE(tps_devs),
-	.subdevs	= tps_devs,
-	.gpio_base	= HARMONY_GPIO_TPS6586X(0),
-};
-
-static struct i2c_board_info __initdata harmony_regulators[] = {
-	{
-		I2C_BOARD_INFO("tps6586x", 0x34),
-		.irq		= INT_EXTERNAL_PMU,
-		.platform_data	= &tps_platform,
-	},
-};
-
-int __init harmony_regulator_init(void)
-{
-	regulator_register_always_on(0, "vdd_sys",
-		NULL, 0, 5000000);
-
-	if (machine_is_harmony()) {
-		i2c_register_board_info(3, harmony_regulators, 1);
-	} else { /* Harmony, booted using device tree */
-		struct device_node *np;
-		struct i2c_adapter *adapter;
-
-		np = of_find_node_by_path("/i2c@7000d000");
-		if (np == NULL) {
-			pr_err("Could not find device_node for DVC I2C\n");
-			return -ENODEV;
-		}
-
-		adapter = of_find_i2c_adapter_by_node(np);
-		if (!adapter) {
-			pr_err("Could not find i2c_adapter for DVC I2C\n");
-			return -ENODEV;
-		}
-
-		i2c_new_device(adapter, harmony_regulators);
-	}
-
-	return 0;
-}
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
deleted file mode 100644
index e65e837f..0000000
--- a/arch/arm/mach-tegra/board-harmony.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-harmony.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/pda_power.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-
-#include <sound/wm8903.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/hardware/gic.h>
-#include <asm/setup.h>
-
-#include <mach/tegra_wm8903_pdata.h>
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-#include <mach/sdhci.h>
-
-#include "board.h"
-#include "board-harmony.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		.membase	= IO_ADDRESS(TEGRA_UARTD_BASE),
-		.mapbase	= TEGRA_UARTD_BASE,
-		.irq		= INT_UARTD,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name = "serial8250",
-	.id = PLAT8250_DEV_PLATFORM,
-	.dev = {
-		.platform_data = debug_uart_platform_data,
-	},
-};
-
-static struct tegra_wm8903_platform_data harmony_audio_pdata = {
-	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
-	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
-	.gpio_hp_mute		= -1,
-	.gpio_int_mic_en	= TEGRA_GPIO_INT_MIC_EN,
-	.gpio_ext_mic_en	= TEGRA_GPIO_EXT_MIC_EN,
-};
-
-static struct platform_device harmony_audio_device = {
-	.name	= "tegra-snd-wm8903",
-	.id	= 0,
-	.dev	= {
-		.platform_data  = &harmony_audio_pdata,
-	},
-};
-
-static struct wm8903_platform_data harmony_wm8903_pdata = {
-	.irq_active_low = 0,
-	.micdet_cfg = 0,
-	.micdet_delay = 100,
-	.gpio_base = HARMONY_GPIO_WM8903(0),
-	.gpio_cfg = {
-		0,
-		0,
-		WM8903_GPIO_CONFIG_ZERO,
-		0,
-		0,
-	},
-};
-
-static struct i2c_board_info __initdata wm8903_board_info = {
-	I2C_BOARD_INFO("wm8903", 0x1a),
-	.platform_data = &harmony_wm8903_pdata,
-};
-
-static void __init harmony_i2c_init(void)
-{
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device3);
-	platform_device_register(&tegra_i2c_device4);
-
-	wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
-	i2c_register_board_info(0, &wm8903_board_info, 1);
-}
-
-static struct platform_device *harmony_devices[] __initdata = {
-	&debug_uart,
-	&tegra_sdhci_device1,
-	&tegra_sdhci_device2,
-	&tegra_sdhci_device4,
-	&tegra_ehci3_device,
-	&tegra_i2s_device1,
-	&tegra_das_device,
-	&harmony_audio_device,
-};
-
-static void __init tegra_harmony_fixup(struct tag *tags, char **cmdline,
-	struct meminfo *mi)
-{
-	mi->nr_banks = 2;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].size = 448 * SZ_1M;
-	mi->bank[1].start = SZ_512M;
-	mi->bank[1].size = SZ_512M;
-}
-
-static __initdata struct tegra_clk_init_table harmony_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uartd",	"pll_p",	216000000,	true },
-	{ "pll_a",	"pll_p_out1",	56448000,	true },
-	{ "pll_a_out0",	"pll_a",	11289600,	true },
-	{ "cdev1",	NULL,		0,		true },
-	{ "i2s1",	"pll_a_out0",	11289600,	false},
-	{ "usb3",	"clk_m",	12000000,	true },
-	{ NULL,		NULL,		0,		0},
-};
-
-
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata2 = {
-	.cd_gpio	= TEGRA_GPIO_SD2_CD,
-	.wp_gpio	= TEGRA_GPIO_SD2_WP,
-	.power_gpio	= TEGRA_GPIO_SD2_POWER,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= TEGRA_GPIO_SD4_CD,
-	.wp_gpio	= TEGRA_GPIO_SD4_WP,
-	.power_gpio	= TEGRA_GPIO_SD4_POWER,
-	.is_8bit	= 1,
-};
-
-static void __init tegra_harmony_init(void)
-{
-	tegra_clk_init_from_table(harmony_clk_init_table);
-
-	harmony_pinmux_init();
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device2.dev.platform_data = &sdhci_pdata2;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices));
-	harmony_i2c_init();
-	harmony_regulator_init();
-}
-
-MACHINE_START(HARMONY, "harmony")
-	.atag_offset	= 0x100,
-	.fixup		= tegra_harmony_fixup,
-	.map_io         = tegra_map_common_io,
-	.init_early	= tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_harmony_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-harmony.h b/arch/arm/mach-tegra/board-harmony.h
deleted file mode 100644
index 139d96c9..0000000
--- a/arch/arm/mach-tegra/board-harmony.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-harmony.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef _MACH_TEGRA_BOARD_HARMONY_H
-#define _MACH_TEGRA_BOARD_HARMONY_H
-
-#include <mach/gpio-tegra.h>
-
-#define HARMONY_GPIO_TPS6586X(_x_)	(TEGRA_NR_GPIOS + (_x_))
-#define HARMONY_GPIO_WM8903(_x_)	(HARMONY_GPIO_TPS6586X(4) + (_x_))
-
-#define TEGRA_GPIO_SD2_CD		TEGRA_GPIO_PI5
-#define TEGRA_GPIO_SD2_WP		TEGRA_GPIO_PH1
-#define TEGRA_GPIO_SD2_POWER		TEGRA_GPIO_PT3
-#define TEGRA_GPIO_SD4_CD		TEGRA_GPIO_PH2
-#define TEGRA_GPIO_SD4_WP		TEGRA_GPIO_PH3
-#define TEGRA_GPIO_SD4_POWER		TEGRA_GPIO_PI6
-#define TEGRA_GPIO_CDC_IRQ		TEGRA_GPIO_PX3
-#define TEGRA_GPIO_SPKR_EN		HARMONY_GPIO_WM8903(2)
-#define TEGRA_GPIO_HP_DET		TEGRA_GPIO_PW2
-#define TEGRA_GPIO_INT_MIC_EN		TEGRA_GPIO_PX0
-#define TEGRA_GPIO_EXT_MIC_EN		TEGRA_GPIO_PX1
-#define TEGRA_GPIO_EN_VDD_1V05_GPIO	HARMONY_GPIO_TPS6586X(2)
-
-void harmony_pinmux_init(void);
-int harmony_regulator_init(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
deleted file mode 100644
index 6f1111b..0000000
--- a/arch/arm/mach-tegra/board-paz00-pinmux.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-paz00-pinmux.c
- *
- * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-
-#include "board-paz00.h"
-#include "board-pinmux.h"
-
-static struct pinctrl_map paz00_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, driven),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
-	TEGRA_MAP_MUXCONF("csus",  "pllc_out1",     down, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
-	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
-	TEGRA_MAP_MUXCONF("dta",   "rsvd1",         up,   tristate),
-	TEGRA_MAP_MUXCONF("dtb",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtc",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtd",   "rsvd1",         up,   tristate),
-	TEGRA_MAP_MUXCONF("dte",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, driven),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gmc",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu",   "pwm",           none, driven),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   driven),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
-	TEGRA_MAP_MUXCONF("irrx",  "uarta",         up,   driven),
-	TEGRA_MAP_MUXCONF("irtx",  "uarta",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcb",  "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcd",  "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "owr",           up,   tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
-	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
-	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   tristate),
-	TEGRA_MAP_MUXCONF("sdc",   "twc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   tristate),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxc",  "spi4",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "spi4",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("spia",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spib",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   driven),
-	TEGRA_MAP_MUXCONF("spid",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "gmi",           up,   tristate),
-	TEGRA_MAP_MUXCONF("spif",  "rsvd4",         down, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   driven),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd4",         none, driven),
-	TEGRA_MAP_MUXCONF("uad",   "spdif",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, driven),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct tegra_board_pinmux_conf conf = {
-	.maps = paz00_map,
-	.map_count = ARRAY_SIZE(paz00_map),
-};
-
-void paz00_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&conf, NULL);
-}
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index 4b64af5..5930551 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -17,72 +17,10 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio_keys.h>
-#include <linux/pda_power.h>
-#include <linux/io.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
 #include <linux/rfkill-gpio.h>
 
-#include <asm/hardware/gic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/setup.h>
-
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-#include <mach/sdhci.h>
-
-#include "board.h"
 #include "board-paz00.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		/* serial port on JP1 */
-		.membase	= IO_ADDRESS(TEGRA_UARTA_BASE),
-		.mapbase	= TEGRA_UARTA_BASE,
-		.irq		= INT_UARTA,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		/* serial port on mini-pcie */
-		.membase	= IO_ADDRESS(TEGRA_UARTC_BASE),
-		.mapbase	= TEGRA_UARTC_BASE,
-		.irq		= INT_UARTC,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name = "serial8250",
-	.id = PLAT8250_DEV_PLATFORM,
-	.dev = {
-		.platform_data = debug_uart_platform_data,
-	},
-};
 
 static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
 	.name		= "wifi_rfkill",
@@ -99,137 +37,7 @@
 	},
 };
 
-static struct gpio_led gpio_leds[] = {
-	{
-		.name			= "wifi-led",
-		.default_trigger	= "rfkill0",
-		.gpio			= TEGRA_WIFI_LED,
-	},
-};
-
-static struct gpio_led_platform_data gpio_led_info = {
-	.leds		= gpio_leds,
-	.num_leds	= ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device leds_gpio = {
-	.name	= "leds-gpio",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &gpio_led_info,
-        },
-};
-
-static struct gpio_keys_button paz00_gpio_keys_buttons[] = {
-	{
-		.code		= KEY_POWER,
-		.gpio		= TEGRA_GPIO_POWERKEY,
-		.active_low	= 1,
-		.desc		= "Power",
-		.type		= EV_KEY,
-		.wakeup		= 1,
-	},
-};
-
-static struct gpio_keys_platform_data paz00_gpio_keys = {
-	.buttons	= paz00_gpio_keys_buttons,
-	.nbuttons	= ARRAY_SIZE(paz00_gpio_keys_buttons),
-};
-
-static struct platform_device gpio_keys_device = {
-	.name	= "gpio-keys",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &paz00_gpio_keys,
-	},
-};
-
-static struct platform_device *paz00_devices[] __initdata = {
-	&debug_uart,
-	&tegra_sdhci_device4,
-	&tegra_sdhci_device1,
-	&leds_gpio,
-	&gpio_keys_device,
-};
-
-static void paz00_i2c_init(void)
-{
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device4);
-}
-
-static void paz00_usb_init(void)
-{
-	tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_ULPI_RST;
-
-	platform_device_register(&tegra_ehci2_device);
-	platform_device_register(&tegra_ehci3_device);
-}
-
-static void __init tegra_paz00_fixup(struct tag *tags, char **cmdline,
-	struct meminfo *mi)
-{
-	mi->nr_banks = 1;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].size = 448 * SZ_1M;
-}
-
-static __initdata struct tegra_clk_init_table paz00_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uarta",	"pll_p",	216000000,	true },
-	{ "uartc",	"pll_p",	216000000,	true },
-
-	{ "usbd",	"clk_m",	12000000,	false },
-	{ "usb2",	"clk_m",	12000000,	false },
-	{ "usb3",	"clk_m",	12000000,	false },
-
-	{ NULL,		NULL,		0,		0},
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= TEGRA_GPIO_SD1_CD,
-	.wp_gpio	= TEGRA_GPIO_SD1_WP,
-	.power_gpio	= TEGRA_GPIO_SD1_POWER,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-	.is_8bit	= 1,
-};
-
 void __init tegra_paz00_wifikill_init(void)
 {
 	platform_device_register(&wifi_rfkill_device);
 }
-
-static void __init tegra_paz00_init(void)
-{
-	tegra_clk_init_from_table(paz00_clk_init_table);
-
-	paz00_pinmux_init();
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(paz00_devices, ARRAY_SIZE(paz00_devices));
-	tegra_paz00_wifikill_init();
-
-	paz00_i2c_init();
-	paz00_usb_init();
-}
-
-MACHINE_START(PAZ00, "Toshiba AC100 / Dynabook AZ")
-	.atag_offset	= 0x100,
-	.fixup		= tegra_paz00_fixup,
-	.map_io         = tegra_map_common_io,
-	.init_early	= tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_paz00_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-paz00.h b/arch/arm/mach-tegra/board-paz00.h
index 3c9f8da..25c08ec 100644
--- a/arch/arm/mach-tegra/board-paz00.h
+++ b/arch/arm/mach-tegra/board-paz00.h
@@ -17,24 +17,9 @@
 #ifndef _MACH_TEGRA_BOARD_PAZ00_H
 #define _MACH_TEGRA_BOARD_PAZ00_H
 
-#include <mach/gpio-tegra.h>
+#include "gpio-names.h"
 
-/* SDCARD */
-#define TEGRA_GPIO_SD1_CD		TEGRA_GPIO_PV5
-#define TEGRA_GPIO_SD1_WP		TEGRA_GPIO_PH1
-#define TEGRA_GPIO_SD1_POWER		TEGRA_GPIO_PV1
-
-/* ULPI */
-#define TEGRA_ULPI_RST			TEGRA_GPIO_PV0
-
-/* WIFI */
 #define TEGRA_WIFI_PWRN			TEGRA_GPIO_PK5
 #define TEGRA_WIFI_RST			TEGRA_GPIO_PD1
-#define TEGRA_WIFI_LED			TEGRA_GPIO_PD0
-
-/* WakeUp */
-#define TEGRA_GPIO_POWERKEY	TEGRA_GPIO_PJ7
-
-void paz00_pinmux_init(void);
 
 #endif
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
deleted file mode 100644
index 7b39511..0000000
--- a/arch/arm/mach-tegra/board-trimslice-pinmux.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice-pinmux.c
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/kernel.h>
-
-#include "board-trimslice.h"
-#include "board-pinmux.h"
-
-static struct pinctrl_map trimslice_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "ide",           none, tristate),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "nand",          none, tristate),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, tristate),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
-	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", down, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
-	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
-	TEGRA_MAP_MUXCONF("dta",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtb",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtc",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtd",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dte",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          up,   driven),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "nand",          none, tristate),
-	TEGRA_MAP_MUXCONF("gmc",   "sflash",        none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("gpu",   "uarta",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, tristate),
-	TEGRA_MAP_MUXCONF("irrx",  "uartb",         up,   tristate),
-	TEGRA_MAP_MUXCONF("irtx",  "uartb",         up,   tristate),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         up,   tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   tristate),
-	TEGRA_MAP_MUXCONF("pta",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          up,   driven),
-	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   driven),
-	TEGRA_MAP_MUXCONF("sdc",   "pwm",           up,   driven),
-	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   driven),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("slxc",  "sdio3",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "sdio3",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("spdo",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("spia",  "spi2",          down, tristate),
-	TEGRA_MAP_MUXCONF("spib",  "spi2",          down, tristate),
-	TEGRA_MAP_MUXCONF("spic",  "spi2",          up,   tristate),
-	TEGRA_MAP_MUXCONF("spid",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "spi1",          up,   tristate),
-	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("uad",   "irda",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, tristate),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct tegra_board_pinmux_conf conf = {
-	.maps = trimslice_map,
-	.map_count = ARRAY_SIZE(trimslice_map),
-};
-
-void trimslice_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&conf, NULL);
-}
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
deleted file mode 100644
index 776aa95..0000000
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice.c
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- * Author: Mike Rapoport <mike@compulab.co.il>
- *
- * Based on board-harmony.c
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/tegra_usb.h>
-
-#include <asm/hardware/gic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/setup.h>
-
-#include <mach/iomap.h>
-#include <mach/sdhci.h>
-
-#include "board.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-#include "board-trimslice.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		.membase	= IO_ADDRESS(TEGRA_UARTA_BASE),
-		.mapbase	= TEGRA_UARTA_BASE,
-		.irq		= INT_UARTA,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name	= "serial8250",
-	.id	= PLAT8250_DEV_PLATFORM,
-	.dev	= {
-		.platform_data	= debug_uart_platform_data,
-	},
-};
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= TRIMSLICE_GPIO_SD4_CD,
-	.wp_gpio	= TRIMSLICE_GPIO_SD4_WP,
-	.power_gpio	= -1,
-};
-
-static struct platform_device trimslice_audio_device = {
-	.name	= "tegra-snd-trimslice",
-	.id	= 0,
-};
-
-static struct platform_device *trimslice_devices[] __initdata = {
-	&debug_uart,
-	&tegra_sdhci_device1,
-	&tegra_sdhci_device4,
-	&tegra_i2s_device1,
-	&tegra_das_device,
-	&trimslice_audio_device,
-};
-
-static struct i2c_board_info trimslice_i2c3_board_info[] = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	},
-	{
-		I2C_BOARD_INFO("em3027", 0x56),
-	},
-};
-
-static void trimslice_i2c_init(void)
-{
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device3);
-
-	i2c_register_board_info(2, trimslice_i2c3_board_info,
-				ARRAY_SIZE(trimslice_i2c3_board_info));
-}
-
-static void trimslice_usb_init(void)
-{
-	struct tegra_ehci_platform_data *pdata;
-
-	pdata = tegra_ehci1_device.dev.platform_data;
-	pdata->vbus_gpio = TRIMSLICE_GPIO_USB1_MODE;
-
-	tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_GPIO_PV0;
-
-	platform_device_register(&tegra_ehci3_device);
-	platform_device_register(&tegra_ehci2_device);
-	platform_device_register(&tegra_ehci1_device);
-}
-
-static void __init tegra_trimslice_fixup(struct tag *tags, char **cmdline,
-	struct meminfo *mi)
-{
-	mi->nr_banks = 2;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].size = 448 * SZ_1M;
-	mi->bank[1].start = SZ_512M;
-	mi->bank[1].size = SZ_512M;
-}
-
-static __initdata struct tegra_clk_init_table trimslice_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uarta",	"pll_p",	216000000,	true },
-	{ "pll_a",	"pll_p_out1",	56448000,	true },
-	{ "pll_a_out0",	"pll_a",	11289600,	true },
-	{ "cdev1",	NULL,		0,		true },
-	{ "i2s1",	"pll_a_out0",	11289600,	false},
-	{ NULL,		NULL,		0,		0},
-};
-
-static int __init tegra_trimslice_pci_init(void)
-{
-	if (!machine_is_trimslice())
-		return 0;
-
-	return tegra_pcie_init(true, true);
-}
-subsys_initcall(tegra_trimslice_pci_init);
-
-static void __init tegra_trimslice_init(void)
-{
-	tegra_clk_init_from_table(trimslice_clk_init_table);
-
-	trimslice_pinmux_init();
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(trimslice_devices, ARRAY_SIZE(trimslice_devices));
-
-	trimslice_i2c_init();
-	trimslice_usb_init();
-}
-
-MACHINE_START(TRIMSLICE, "trimslice")
-	.atag_offset	= 0x100,
-	.fixup		= tegra_trimslice_fixup,
-	.map_io         = tegra_map_common_io,
-	.init_early	= tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_trimslice_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-trimslice.h b/arch/arm/mach-tegra/board-trimslice.h
deleted file mode 100644
index 50f128d..0000000
--- a/arch/arm/mach-tegra/board-trimslice.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice.h
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef _MACH_TEGRA_BOARD_TRIMSLICE_H
-#define _MACH_TEGRA_BOARD_TRIMSLICE_H
-
-#include <mach/gpio-tegra.h>
-
-#define TRIMSLICE_GPIO_SD4_CD	TEGRA_GPIO_PP1	/* mmc4 cd */
-#define TRIMSLICE_GPIO_SD4_WP	TEGRA_GPIO_PP2	/* mmc4 wp */
-
-#define TRIMSLICE_GPIO_USB1_MODE	TEGRA_GPIO_PV2 /* USB1 mode */
-#define TRIMSLICE_GPIO_USB2_RST		TEGRA_GPIO_PV0 /* USB2 PHY reset */
-
-void trimslice_pinmux_init(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 58f981c..fd82085 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -1,6 +1,7 @@
 /*
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
@@ -19,8 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -32,44 +31,38 @@
 
 #include "board.h"
 #include "clock.h"
+#include "tegra_cpu_car.h"
+
+/* Global data of Tegra CPU CAR ops */
+struct tegra_cpu_car_ops *tegra_cpu_car_ops;
 
 /*
  * Locking:
  *
- * Each struct clk has a spinlock.
- *
- * To avoid AB-BA locking problems, locks must always be traversed from child
- * clock to parent clock.  For example, when enabling a clock, the clock's lock
- * is taken, and then clk_enable is called on the parent, which take's the
- * parent clock's lock.  There is one exceptions to this ordering: When dumping
- * the clock tree through debugfs.  In this case, clk_lock_all is called,
- * which attemps to iterate through the entire list of clocks and take every
- * clock lock.  If any call to spin_trylock fails, all locked clocks are
- * unlocked, and the process is retried.  When all the locks are held,
- * the only clock operation that can be called is clk_get_rate_all_locked.
- *
- * Within a single clock, no clock operation can call another clock operation
- * on itself, except for clk_get_rate_locked and clk_set_rate_locked.  Any
- * clock operation can call any other clock operation on any of it's possible
- * parents.
- *
  * An additional mutex, clock_list_lock, is used to protect the list of all
  * clocks.
  *
- * The clock operations must lock internally to protect against
- * read-modify-write on registers that are shared by multiple clocks
  */
 static DEFINE_MUTEX(clock_list_lock);
 static LIST_HEAD(clocks);
 
+void tegra_clk_add(struct clk *clk)
+{
+	struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
+
+	mutex_lock(&clock_list_lock);
+	list_add(&c->node, &clocks);
+	mutex_unlock(&clock_list_lock);
+}
+
 struct clk *tegra_get_clock_by_name(const char *name)
 {
-	struct clk *c;
+	struct clk_tegra *c;
 	struct clk *ret = NULL;
 	mutex_lock(&clock_list_lock);
 	list_for_each_entry(c, &clocks, node) {
-		if (strcmp(c->name, name) == 0) {
-			ret = c;
+		if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
+			ret = c->hw.clk;
 			break;
 		}
 	}
@@ -77,280 +70,36 @@
 	return ret;
 }
 
-/* Must be called with c->spinlock held */
-static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
-{
-	u64 rate;
-
-	rate = clk_get_rate(p);
-
-	if (c->mul != 0 && c->div != 0) {
-		rate *= c->mul;
-		rate += c->div - 1; /* round up */
-		do_div(rate, c->div);
-	}
-
-	return rate;
-}
-
-/* Must be called with c->spinlock held */
-unsigned long clk_get_rate_locked(struct clk *c)
-{
-	unsigned long rate;
-
-	if (c->parent)
-		rate = clk_predict_rate_from_parent(c, c->parent);
-	else
-		rate = c->rate;
-
-	return rate;
-}
-
-unsigned long clk_get_rate(struct clk *c)
-{
-	unsigned long flags;
-	unsigned long rate;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	rate = clk_get_rate_locked(c);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
-	return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_reparent(struct clk *c, struct clk *parent)
-{
-	c->parent = parent;
-	return 0;
-}
-
-void clk_init(struct clk *c)
-{
-	spin_lock_init(&c->spinlock);
-
-	if (c->ops && c->ops->init)
-		c->ops->init(c);
-
-	if (!c->ops || !c->ops->enable) {
-		c->refcnt++;
-		c->set = true;
-		if (c->parent)
-			c->state = c->parent->state;
-		else
-			c->state = ON;
-	}
-
-	mutex_lock(&clock_list_lock);
-	list_add(&c->node, &clocks);
-	mutex_unlock(&clock_list_lock);
-}
-
-int clk_enable(struct clk *c)
-{
-	int ret = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (c->refcnt == 0) {
-		if (c->parent) {
-			ret = clk_enable(c->parent);
-			if (ret)
-				goto out;
-		}
-
-		if (c->ops && c->ops->enable) {
-			ret = c->ops->enable(c);
-			if (ret) {
-				if (c->parent)
-					clk_disable(c->parent);
-				goto out;
-			}
-			c->state = ON;
-			c->set = true;
-		}
-	}
-	c->refcnt++;
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (c->refcnt == 0) {
-		WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
-		spin_unlock_irqrestore(&c->spinlock, flags);
-		return;
-	}
-	if (c->refcnt == 1) {
-		if (c->ops && c->ops->disable)
-			c->ops->disable(c);
-
-		if (c->parent)
-			clk_disable(c->parent);
-
-		c->state = OFF;
-	}
-	c->refcnt--;
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-int clk_set_parent(struct clk *c, struct clk *parent)
-{
-	int ret;
-	unsigned long flags;
-	unsigned long new_rate;
-	unsigned long old_rate;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->set_parent) {
-		ret = -ENOSYS;
-		goto out;
-	}
-
-	new_rate = clk_predict_rate_from_parent(c, parent);
-	old_rate = clk_get_rate_locked(c);
-
-	ret = c->ops->set_parent(c, parent);
-	if (ret)
-		goto out;
-
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *c)
-{
-	return c->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-int clk_set_rate_locked(struct clk *c, unsigned long rate)
-{
-	long new_rate;
-
-	if (!c->ops || !c->ops->set_rate)
-		return -ENOSYS;
-
-	if (rate > c->max_rate)
-		rate = c->max_rate;
-
-	if (c->ops && c->ops->round_rate) {
-		new_rate = c->ops->round_rate(c, rate);
-
-		if (new_rate < 0)
-			return new_rate;
-
-		rate = new_rate;
-	}
-
-	return c->ops->set_rate(c, rate);
-}
-
-int clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	ret = clk_set_rate_locked(c, rate);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-
-/* Must be called with clocks lock and all indvidual clock locks held */
-unsigned long clk_get_rate_all_locked(struct clk *c)
-{
-	u64 rate;
-	int mul = 1;
-	int div = 1;
-	struct clk *p = c;
-
-	while (p) {
-		c = p;
-		if (c->mul != 0 && c->div != 0) {
-			mul *= c->mul;
-			div *= c->div;
-		}
-		p = c->parent;
-	}
-
-	rate = c->rate;
-	rate *= mul;
-	do_div(rate, div);
-
-	return rate;
-}
-
-long clk_round_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long flags;
-	long ret;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->round_rate) {
-		ret = -ENOSYS;
-		goto out;
-	}
-
-	if (rate > c->max_rate)
-		rate = c->max_rate;
-
-	ret = c->ops->round_rate(c, rate);
-
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
 static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
 {
 	struct clk *c;
 	struct clk *p;
+	struct clk *parent;
 
 	int ret = 0;
 
 	c = tegra_get_clock_by_name(table->name);
 
 	if (!c) {
-		pr_warning("Unable to initialize clock %s\n",
+		pr_warn("Unable to initialize clock %s\n",
 			table->name);
 		return -ENODEV;
 	}
 
+	parent = clk_get_parent(c);
+
 	if (table->parent) {
 		p = tegra_get_clock_by_name(table->parent);
 		if (!p) {
-			pr_warning("Unable to find parent %s of clock %s\n",
+			pr_warn("Unable to find parent %s of clock %s\n",
 				table->parent, table->name);
 			return -ENODEV;
 		}
 
-		if (c->parent != p) {
+		if (parent != p) {
 			ret = clk_set_parent(c, p);
 			if (ret) {
-				pr_warning("Unable to set parent %s of clock %s: %d\n",
+				pr_warn("Unable to set parent %s of clock %s: %d\n",
 					table->parent, table->name, ret);
 				return -EINVAL;
 			}
@@ -360,16 +109,16 @@
 	if (table->rate && table->rate != clk_get_rate(c)) {
 		ret = clk_set_rate(c, table->rate);
 		if (ret) {
-			pr_warning("Unable to set clock %s to rate %lu: %d\n",
+			pr_warn("Unable to set clock %s to rate %lu: %d\n",
 				table->name, table->rate, ret);
 			return -EINVAL;
 		}
 	}
 
 	if (table->enabled) {
-		ret = clk_enable(c);
+		ret = clk_prepare_enable(c);
 		if (ret) {
-			pr_warning("Unable to enable clock %s: %d\n",
+			pr_warn("Unable to enable clock %s: %d\n",
 				table->name, ret);
 			return -EINVAL;
 		}
@@ -383,19 +132,20 @@
 	for (; table->name; table++)
 		tegra_clk_init_one_from_table(table);
 }
-EXPORT_SYMBOL(tegra_clk_init_from_table);
 
 void tegra_periph_reset_deassert(struct clk *c)
 {
-	BUG_ON(!c->ops->reset);
-	c->ops->reset(c, false);
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+	BUG_ON(!clk->reset);
+	clk->reset(__clk_get_hw(c), false);
 }
 EXPORT_SYMBOL(tegra_periph_reset_deassert);
 
 void tegra_periph_reset_assert(struct clk *c)
 {
-	BUG_ON(!c->ops->reset);
-	c->ops->reset(c, true);
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+	BUG_ON(!clk->reset);
+	clk->reset(__clk_get_hw(c), true);
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
@@ -405,268 +155,14 @@
 int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
 {
 	int ret = 0;
-	unsigned long flags;
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
 
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->clk_cfg_ex) {
+	if (!clk->clk_cfg_ex) {
 		ret = -ENOSYS;
 		goto out;
 	}
-	ret = c->ops->clk_cfg_ex(c, p, setting);
+	ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
 
 out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
 	return ret;
 }
-
-#ifdef CONFIG_DEBUG_FS
-
-static int __clk_lock_all_spinlocks(void)
-{
-	struct clk *c;
-
-	list_for_each_entry(c, &clocks, node)
-		if (!spin_trylock(&c->spinlock))
-			goto unlock_spinlocks;
-
-	return 0;
-
-unlock_spinlocks:
-	list_for_each_entry_continue_reverse(c, &clocks, node)
-		spin_unlock(&c->spinlock);
-
-	return -EAGAIN;
-}
-
-static void __clk_unlock_all_spinlocks(void)
-{
-	struct clk *c;
-
-	list_for_each_entry_reverse(c, &clocks, node)
-		spin_unlock(&c->spinlock);
-}
-
-/*
- * This function retries until it can take all locks, and may take
- * an arbitrarily long time to complete.
- * Must be called with irqs enabled, returns with irqs disabled
- * Must be called with clock_list_lock held
- */
-static void clk_lock_all(void)
-{
-	int ret;
-retry:
-	local_irq_disable();
-
-	ret = __clk_lock_all_spinlocks();
-	if (ret)
-		goto failed_spinlocks;
-
-	/* All locks taken successfully, return */
-	return;
-
-failed_spinlocks:
-	local_irq_enable();
-	yield();
-	goto retry;
-}
-
-/*
- * Unlocks all clocks after a clk_lock_all
- * Must be called with irqs disabled, returns with irqs enabled
- * Must be called with clock_list_lock held
- */
-static void clk_unlock_all(void)
-{
-	__clk_unlock_all_spinlocks();
-
-	local_irq_enable();
-}
-
-static struct dentry *clk_debugfs_root;
-
-
-static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
-{
-	struct clk *child;
-	const char *state = "uninit";
-	char div[8] = {0};
-
-	if (c->state == ON)
-		state = "on";
-	else if (c->state == OFF)
-		state = "off";
-
-	if (c->mul != 0 && c->div != 0) {
-		if (c->mul > c->div) {
-			int mul = c->mul / c->div;
-			int mul2 = (c->mul * 10 / c->div) % 10;
-			int mul3 = (c->mul * 10) % c->div;
-			if (mul2 == 0 && mul3 == 0)
-				snprintf(div, sizeof(div), "x%d", mul);
-			else if (mul3 == 0)
-				snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
-			else
-				snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
-		} else {
-			snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
-				(c->div % c->mul) ? ".5" : "");
-		}
-	}
-
-	seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
-		level * 3 + 1, "",
-		c->rate > c->max_rate ? '!' : ' ',
-		!c->set ? '*' : ' ',
-		30 - level * 3, c->name,
-		state, c->refcnt, div, clk_get_rate_all_locked(c));
-
-	list_for_each_entry(child, &clocks, node) {
-		if (child->parent != c)
-			continue;
-
-		clock_tree_show_one(s, child, level + 1);
-	}
-}
-
-static int clock_tree_show(struct seq_file *s, void *data)
-{
-	struct clk *c;
-	seq_printf(s, "   clock                          state  ref div      rate\n");
-	seq_printf(s, "--------------------------------------------------------------\n");
-
-	mutex_lock(&clock_list_lock);
-
-	clk_lock_all();
-
-	list_for_each_entry(c, &clocks, node)
-		if (c->parent == NULL)
-			clock_tree_show_one(s, c, 0);
-
-	clk_unlock_all();
-
-	mutex_unlock(&clock_list_lock);
-	return 0;
-}
-
-static int clock_tree_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, clock_tree_show, inode->i_private);
-}
-
-static const struct file_operations clock_tree_fops = {
-	.open		= clock_tree_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int possible_parents_show(struct seq_file *s, void *data)
-{
-	struct clk *c = s->private;
-	int i;
-
-	for (i = 0; c->inputs[i].input; i++) {
-		char *first = (i == 0) ? "" : " ";
-		seq_printf(s, "%s%s", first, c->inputs[i].input->name);
-	}
-	seq_printf(s, "\n");
-	return 0;
-}
-
-static int possible_parents_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, possible_parents_show, inode->i_private);
-}
-
-static const struct file_operations possible_parents_fops = {
-	.open		= possible_parents_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int clk_debugfs_register_one(struct clk *c)
-{
-	struct dentry *d;
-
-	d = debugfs_create_dir(c->name, clk_debugfs_root);
-	if (!d)
-		return -ENOMEM;
-	c->dent = d;
-
-	d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
-	if (!d)
-		goto err_out;
-
-	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
-	if (!d)
-		goto err_out;
-
-	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
-	if (!d)
-		goto err_out;
-
-	if (c->inputs) {
-		d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
-			c, &possible_parents_fops);
-		if (!d)
-			goto err_out;
-	}
-
-	return 0;
-
-err_out:
-	debugfs_remove_recursive(c->dent);
-	return -ENOMEM;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
-	int err;
-	struct clk *pa = c->parent;
-
-	if (pa && !pa->dent) {
-		err = clk_debugfs_register(pa);
-		if (err)
-			return err;
-	}
-
-	if (!c->dent) {
-		err = clk_debugfs_register_one(c);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
-int __init tegra_clk_debugfs_init(void)
-{
-	struct clk *c;
-	struct dentry *d;
-	int err = -ENOMEM;
-
-	d = debugfs_create_dir("clock", NULL);
-	if (!d)
-		return -ENOMEM;
-	clk_debugfs_root = d;
-
-	d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
-		&clock_tree_fops);
-	if (!d)
-		goto err_out;
-
-	list_for_each_entry(c, &clocks, node) {
-		err = clk_debugfs_register(c);
-		if (err)
-			goto err_out;
-	}
-	return 0;
-err_out:
-	debugfs_remove_recursive(clk_debugfs_root);
-	return err;
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bc30065..2aa37f5 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/include/mach/clock.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
@@ -20,9 +21,9 @@
 #ifndef __MACH_TEGRA_CLOCK_H
 #define __MACH_TEGRA_CLOCK_H
 
+#include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/list.h>
-#include <linux/spinlock.h>
 
 #include <mach/clk.h>
 
@@ -52,7 +53,8 @@
 #define ENABLE_ON_INIT		(1 << 28)
 #define PERIPH_ON_APB           (1 << 29)
 
-struct clk;
+struct clk_tegra;
+#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
 
 struct clk_mux_sel {
 	struct clk	*input;
@@ -68,47 +70,29 @@
 	u8		cpcon;
 };
 
-struct clk_ops {
-	void		(*init)(struct clk *);
-	int		(*enable)(struct clk *);
-	void		(*disable)(struct clk *);
-	int		(*set_parent)(struct clk *, struct clk *);
-	int		(*set_rate)(struct clk *, unsigned long);
-	long		(*round_rate)(struct clk *, unsigned long);
-	void		(*reset)(struct clk *, bool);
-	int		(*clk_cfg_ex)(struct clk *,
-				enum tegra_clk_ex_param, u32);
-};
-
 enum clk_state {
 	UNINITIALIZED = 0,
 	ON,
 	OFF,
 };
 
-struct clk {
+struct clk_tegra {
 	/* node for master clocks list */
-	struct list_head	node;		/* node for list of all clocks */
+	struct list_head	node;	/* node for list of all clocks */
 	struct clk_lookup	lookup;
+	struct clk_hw		hw;
 
-#ifdef CONFIG_DEBUG_FS
-	struct dentry		*dent;
-#endif
 	bool			set;
-	struct clk_ops		*ops;
-	unsigned long		rate;
+	unsigned long		fixed_rate;
 	unsigned long		max_rate;
 	unsigned long		min_rate;
 	u32			flags;
 	const char		*name;
 
-	u32			refcnt;
 	enum clk_state		state;
-	struct clk		*parent;
 	u32			div;
 	u32			mul;
 
-	const struct clk_mux_sel	*inputs;
 	u32				reg;
 	u32				reg_shift;
 
@@ -144,7 +128,8 @@
 		} shared_bus_user;
 	} u;
 
-	spinlock_t spinlock;
+	void (*reset)(struct clk_hw *, bool);
+	int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
 };
 
 struct clk_duplicate {
@@ -159,13 +144,10 @@
 	bool enabled;
 };
 
+void tegra_clk_add(struct clk *c);
 void tegra2_init_clocks(void);
 void tegra30_init_clocks(void);
-void clk_init(struct clk *clk);
 struct clk *tegra_get_clock_by_name(const char *name);
-int clk_reparent(struct clk *c, struct clk *parent);
 void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
-unsigned long clk_get_rate_locked(struct clk *c);
-int clk_set_rate_locked(struct clk *c, unsigned long rate);
 
 #endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 96fef6b..0560538 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -34,6 +34,7 @@
 #include "fuse.h"
 #include "pmc.h"
 #include "apbio.h"
+#include "sleep.h"
 
 /*
  * Storage for debug-macro.S's state.
@@ -135,6 +136,7 @@
 	tegra_init_cache(0x331, 0x441);
 	tegra_pmc_init();
 	tegra_powergate_init();
+	tegra20_hotplug_init();
 }
 #endif
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -147,11 +149,11 @@
 	tegra_init_cache(0x441, 0x551);
 	tegra_pmc_init();
 	tegra_powergate_init();
+	tegra30_hotplug_init();
 }
 #endif
 
 void __init tegra_init_late(void)
 {
-	tegra_clk_debugfs_init();
 	tegra_powergate_debugfs_init();
 }
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index ceb52db..627bf0f 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -49,6 +49,8 @@
 #define NUM_CPUS	2
 
 static struct clk *cpu_clk;
+static struct clk *pll_x_clk;
+static struct clk *pll_p_clk;
 static struct clk *emc_clk;
 
 static unsigned long target_cpu_speed[NUM_CPUS];
@@ -71,6 +73,42 @@
 	return rate;
 }
 
+static int tegra_cpu_clk_set_rate(unsigned long rate)
+{
+	int ret;
+
+	/*
+	 * Take an extra reference to the main pll so it doesn't turn
+	 * off when we move the cpu off of it
+	 */
+	clk_prepare_enable(pll_x_clk);
+
+	ret = clk_set_parent(cpu_clk, pll_p_clk);
+	if (ret) {
+		pr_err("Failed to switch cpu to clock pll_p\n");
+		goto out;
+	}
+
+	if (rate == clk_get_rate(pll_p_clk))
+		goto out;
+
+	ret = clk_set_rate(pll_x_clk, rate);
+	if (ret) {
+		pr_err("Failed to change pll_x to %lu\n", rate);
+		goto out;
+	}
+
+	ret = clk_set_parent(cpu_clk, pll_x_clk);
+	if (ret) {
+		pr_err("Failed to switch cpu to clock pll_x\n");
+		goto out;
+	}
+
+out:
+	clk_disable_unprepare(pll_x_clk);
+	return ret;
+}
+
 static int tegra_update_cpu_speed(unsigned long rate)
 {
 	int ret = 0;
@@ -101,7 +139,7 @@
 	       freqs.old, freqs.new);
 #endif
 
-	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
 	if (ret) {
 		pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
 			freqs.new);
@@ -183,6 +221,14 @@
 	if (IS_ERR(cpu_clk))
 		return PTR_ERR(cpu_clk);
 
+	pll_x_clk = clk_get_sys(NULL, "pll_x");
+	if (IS_ERR(pll_x_clk))
+		return PTR_ERR(pll_x_clk);
+
+	pll_p_clk = clk_get_sys(NULL, "pll_p");
+	if (IS_ERR(pll_p_clk))
+		return PTR_ERR(pll_p_clk);
+
 	emc_clk = clk_get_sys("cpu", "emc");
 	if (IS_ERR(emc_clk)) {
 		clk_put(cpu_clk);
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index c70e65f..63cc280 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -23,11 +23,10 @@
 #include <linux/fsl_devices.h>
 #include <linux/serial_8250.h>
 #include <linux/i2c-tegra.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/iomap.h>
 #include <mach/dma.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 
 #include "gpio-names.h"
 #include "devices.h"
@@ -516,7 +515,7 @@
 
 struct platform_device tegra_pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(tegra_pmu_resources),
 	.resource	= tegra_pmu_resources,
 };
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index 4f50527..906a61f 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -22,7 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_data/tegra_usb.h>
 
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 
 extern struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config;
 
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
deleted file mode 100644
index 29c5114..0000000
--- a/arch/arm/mach-tegra/dma.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * arch/arm/mach-tegra/dma.c
- *
- * System DMA driver for NVIDIA Tegra SoCs
- *
- * Copyright (c) 2008-2009, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/err.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <mach/dma.h>
-#include <mach/irqs.h>
-#include <mach/iomap.h>
-#include <mach/suspend.h>
-
-#include "apbio.h"
-
-#define APB_DMA_GEN				0x000
-#define GEN_ENABLE				(1<<31)
-
-#define APB_DMA_CNTRL				0x010
-
-#define APB_DMA_IRQ_MASK			0x01c
-
-#define APB_DMA_IRQ_MASK_SET			0x020
-
-#define APB_DMA_CHAN_CSR			0x000
-#define CSR_ENB					(1<<31)
-#define CSR_IE_EOC				(1<<30)
-#define CSR_HOLD				(1<<29)
-#define CSR_DIR					(1<<28)
-#define CSR_ONCE				(1<<27)
-#define CSR_FLOW				(1<<21)
-#define CSR_REQ_SEL_SHIFT			16
-#define CSR_WCOUNT_SHIFT			2
-#define CSR_WCOUNT_MASK				0xFFFC
-
-#define APB_DMA_CHAN_STA				0x004
-#define STA_BUSY				(1<<31)
-#define STA_ISE_EOC				(1<<30)
-#define STA_HALT				(1<<29)
-#define STA_PING_PONG				(1<<28)
-#define STA_COUNT_SHIFT				2
-#define STA_COUNT_MASK				0xFFFC
-
-#define APB_DMA_CHAN_AHB_PTR				0x010
-
-#define APB_DMA_CHAN_AHB_SEQ				0x014
-#define AHB_SEQ_INTR_ENB			(1<<31)
-#define AHB_SEQ_BUS_WIDTH_SHIFT			28
-#define AHB_SEQ_BUS_WIDTH_MASK			(0x7<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_BUS_WIDTH_8			(0<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_BUS_WIDTH_16			(1<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_BUS_WIDTH_32			(2<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_BUS_WIDTH_64			(3<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_BUS_WIDTH_128			(4<<AHB_SEQ_BUS_WIDTH_SHIFT)
-#define AHB_SEQ_DATA_SWAP			(1<<27)
-#define AHB_SEQ_BURST_MASK			(0x7<<24)
-#define AHB_SEQ_BURST_1				(4<<24)
-#define AHB_SEQ_BURST_4				(5<<24)
-#define AHB_SEQ_BURST_8				(6<<24)
-#define AHB_SEQ_DBL_BUF				(1<<19)
-#define AHB_SEQ_WRAP_SHIFT			16
-#define AHB_SEQ_WRAP_MASK			(0x7<<AHB_SEQ_WRAP_SHIFT)
-
-#define APB_DMA_CHAN_APB_PTR				0x018
-
-#define APB_DMA_CHAN_APB_SEQ				0x01c
-#define APB_SEQ_BUS_WIDTH_SHIFT			28
-#define APB_SEQ_BUS_WIDTH_MASK			(0x7<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_BUS_WIDTH_8			(0<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_BUS_WIDTH_16			(1<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_BUS_WIDTH_32			(2<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_BUS_WIDTH_64			(3<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_BUS_WIDTH_128			(4<<APB_SEQ_BUS_WIDTH_SHIFT)
-#define APB_SEQ_DATA_SWAP			(1<<27)
-#define APB_SEQ_WRAP_SHIFT			16
-#define APB_SEQ_WRAP_MASK			(0x7<<APB_SEQ_WRAP_SHIFT)
-
-#define TEGRA_SYSTEM_DMA_CH_NR			16
-#define TEGRA_SYSTEM_DMA_AVP_CH_NUM		4
-#define TEGRA_SYSTEM_DMA_CH_MIN			0
-#define TEGRA_SYSTEM_DMA_CH_MAX	\
-	(TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1)
-
-#define NV_DMA_MAX_TRASFER_SIZE 0x10000
-
-static const unsigned int ahb_addr_wrap_table[8] = {
-	0, 32, 64, 128, 256, 512, 1024, 2048
-};
-
-static const unsigned int apb_addr_wrap_table[8] = {
-	0, 1, 2, 4, 8, 16, 32, 64
-};
-
-static const unsigned int bus_width_table[5] = {
-	8, 16, 32, 64, 128
-};
-
-#define TEGRA_DMA_NAME_SIZE 16
-struct tegra_dma_channel {
-	struct list_head	list;
-	int			id;
-	spinlock_t		lock;
-	char			name[TEGRA_DMA_NAME_SIZE];
-	void  __iomem		*addr;
-	int			mode;
-	int			irq;
-	int			req_transfer_count;
-};
-
-#define  NV_DMA_MAX_CHANNELS  32
-
-static bool tegra_dma_initialized;
-static DEFINE_MUTEX(tegra_dma_lock);
-static DEFINE_SPINLOCK(enable_lock);
-
-static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
-static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
-
-static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req);
-static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req);
-static void tegra_dma_stop(struct tegra_dma_channel *ch);
-
-void tegra_dma_flush(struct tegra_dma_channel *ch)
-{
-}
-EXPORT_SYMBOL(tegra_dma_flush);
-
-void tegra_dma_dequeue(struct tegra_dma_channel *ch)
-{
-	struct tegra_dma_req *req;
-
-	if (tegra_dma_is_empty(ch))
-		return;
-
-	req = list_entry(ch->list.next, typeof(*req), node);
-
-	tegra_dma_dequeue_req(ch, req);
-	return;
-}
-
-static void tegra_dma_stop(struct tegra_dma_channel *ch)
-{
-	u32 csr;
-	u32 status;
-
-	csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-	csr &= ~CSR_IE_EOC;
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
-	csr &= ~CSR_ENB;
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
-	status = readl(ch->addr + APB_DMA_CHAN_STA);
-	if (status & STA_ISE_EOC)
-		writel(status, ch->addr + APB_DMA_CHAN_STA);
-}
-
-static int tegra_dma_cancel(struct tegra_dma_channel *ch)
-{
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-	while (!list_empty(&ch->list))
-		list_del(ch->list.next);
-
-	tegra_dma_stop(ch);
-
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-	return 0;
-}
-
-static unsigned int get_channel_status(struct tegra_dma_channel *ch,
-			struct tegra_dma_req *req, bool is_stop_dma)
-{
-	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
-	unsigned int status;
-
-	if (is_stop_dma) {
-		/*
-		 * STOP the DMA and get the transfer count.
-		 * Getting the transfer count is tricky.
-		 *  - Globally disable DMA on all channels
-		 *  - Read the channel's status register to know the number
-		 *    of pending bytes to be transfered.
-		 *  - Stop the dma channel
-		 *  - Globally re-enable DMA to resume other transfers
-		 */
-		spin_lock(&enable_lock);
-		writel(0, addr + APB_DMA_GEN);
-		udelay(20);
-		status = readl(ch->addr + APB_DMA_CHAN_STA);
-		tegra_dma_stop(ch);
-		writel(GEN_ENABLE, addr + APB_DMA_GEN);
-		spin_unlock(&enable_lock);
-		if (status & STA_ISE_EOC) {
-			pr_err("Got Dma Int here clearing");
-			writel(status, ch->addr + APB_DMA_CHAN_STA);
-		}
-		req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
-	} else {
-		status = readl(ch->addr + APB_DMA_CHAN_STA);
-	}
-	return status;
-}
-
-/* should be called with the channel lock held */
-static unsigned int dma_active_count(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req, unsigned int status)
-{
-	unsigned int to_transfer;
-	unsigned int req_transfer_count;
-	unsigned int bytes_transferred;
-
-	to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
-	req_transfer_count = ch->req_transfer_count + 1;
-	bytes_transferred = req_transfer_count;
-	if (status & STA_BUSY)
-		bytes_transferred -= to_transfer;
-	/*
-	 * In continuous transfer mode, DMA only tracks the count of the
-	 * half DMA buffer. So, if the DMA already finished half the DMA
-	 * then add the half buffer to the completed count.
-	 */
-	if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
-		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
-			bytes_transferred += req_transfer_count;
-		if (status & STA_ISE_EOC)
-			bytes_transferred += req_transfer_count;
-	}
-	bytes_transferred *= 4;
-	return bytes_transferred;
-}
-
-int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *_req)
-{
-	unsigned int status;
-	struct tegra_dma_req *req = NULL;
-	int found = 0;
-	unsigned long irq_flags;
-	int stop = 0;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-
-	if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
-		stop = 1;
-
-	list_for_each_entry(req, &ch->list, node) {
-		if (req == _req) {
-			list_del(&req->node);
-			found = 1;
-			break;
-		}
-	}
-	if (!found) {
-		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		return 0;
-	}
-
-	if (!stop)
-		goto skip_stop_dma;
-
-	status = get_channel_status(ch, req, true);
-	req->bytes_transferred = dma_active_count(ch, req, status);
-
-	if (!list_empty(&ch->list)) {
-		/* if the list is not empty, queue the next request */
-		struct tegra_dma_req *next_req;
-		next_req = list_entry(ch->list.next,
-			typeof(*next_req), node);
-		tegra_dma_update_hw(ch, next_req);
-	}
-
-skip_stop_dma:
-	req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
-
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-
-	/* Callback should be called without any lock */
-	req->complete(req);
-	return 0;
-}
-EXPORT_SYMBOL(tegra_dma_dequeue_req);
-
-bool tegra_dma_is_empty(struct tegra_dma_channel *ch)
-{
-	unsigned long irq_flags;
-	bool is_empty;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-	if (list_empty(&ch->list))
-		is_empty = true;
-	else
-		is_empty = false;
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-	return is_empty;
-}
-EXPORT_SYMBOL(tegra_dma_is_empty);
-
-bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *_req)
-{
-	unsigned long irq_flags;
-	struct tegra_dma_req *req;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-	list_for_each_entry(req, &ch->list, node) {
-		if (req == _req) {
-			spin_unlock_irqrestore(&ch->lock, irq_flags);
-			return true;
-		}
-	}
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-	return false;
-}
-EXPORT_SYMBOL(tegra_dma_is_req_inflight);
-
-int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req)
-{
-	unsigned long irq_flags;
-	struct tegra_dma_req *_req;
-	int start_dma = 0;
-
-	if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
-		req->source_addr & 0x3 || req->dest_addr & 0x3) {
-		pr_err("Invalid DMA request for channel %d\n", ch->id);
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-
-	list_for_each_entry(_req, &ch->list, node) {
-		if (req == _req) {
-		    spin_unlock_irqrestore(&ch->lock, irq_flags);
-		    return -EEXIST;
-		}
-	}
-
-	req->bytes_transferred = 0;
-	req->status = 0;
-	req->buffer_status = 0;
-	if (list_empty(&ch->list))
-		start_dma = 1;
-
-	list_add_tail(&req->node, &ch->list);
-
-	if (start_dma)
-		tegra_dma_update_hw(ch, req);
-
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-
-	return 0;
-}
-EXPORT_SYMBOL(tegra_dma_enqueue_req);
-
-struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
-{
-	int channel;
-	struct tegra_dma_channel *ch = NULL;
-
-	if (!tegra_dma_initialized)
-		return NULL;
-
-	mutex_lock(&tegra_dma_lock);
-
-	/* first channel is the shared channel */
-	if (mode & TEGRA_DMA_SHARED) {
-		channel = TEGRA_SYSTEM_DMA_CH_MIN;
-	} else {
-		channel = find_first_zero_bit(channel_usage,
-			ARRAY_SIZE(dma_channels));
-		if (channel >= ARRAY_SIZE(dma_channels))
-			goto out;
-	}
-	__set_bit(channel, channel_usage);
-	ch = &dma_channels[channel];
-	ch->mode = mode;
-
-out:
-	mutex_unlock(&tegra_dma_lock);
-	return ch;
-}
-EXPORT_SYMBOL(tegra_dma_allocate_channel);
-
-void tegra_dma_free_channel(struct tegra_dma_channel *ch)
-{
-	if (ch->mode & TEGRA_DMA_SHARED)
-		return;
-	tegra_dma_cancel(ch);
-	mutex_lock(&tegra_dma_lock);
-	__clear_bit(ch->id, channel_usage);
-	mutex_unlock(&tegra_dma_lock);
-}
-EXPORT_SYMBOL(tegra_dma_free_channel);
-
-static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req)
-{
-	u32 apb_ptr;
-	u32 ahb_ptr;
-
-	if (req->to_memory) {
-		apb_ptr = req->source_addr;
-		ahb_ptr = req->dest_addr;
-	} else {
-		apb_ptr = req->dest_addr;
-		ahb_ptr = req->source_addr;
-	}
-	writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
-	writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
-
-	req->status = TEGRA_DMA_REQ_INFLIGHT;
-	return;
-}
-
-static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req)
-{
-	int ahb_addr_wrap;
-	int apb_addr_wrap;
-	int ahb_bus_width;
-	int apb_bus_width;
-	int index;
-
-	u32 ahb_seq;
-	u32 apb_seq;
-	u32 ahb_ptr;
-	u32 apb_ptr;
-	u32 csr;
-
-	csr = CSR_IE_EOC | CSR_FLOW;
-	ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1;
-	apb_seq = 0;
-
-	csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
-
-	/* One shot mode is always single buffered,
-	 * continuous mode is always double buffered
-	 * */
-	if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
-		csr |= CSR_ONCE;
-		ch->req_transfer_count = (req->size >> 2) - 1;
-	} else {
-		ahb_seq |= AHB_SEQ_DBL_BUF;
-
-		/* In double buffered mode, we set the size to half the
-		 * requested size and interrupt when half the buffer
-		 * is full */
-		ch->req_transfer_count = (req->size >> 3) - 1;
-	}
-
-	csr |= ch->req_transfer_count << CSR_WCOUNT_SHIFT;
-
-	if (req->to_memory) {
-		apb_ptr = req->source_addr;
-		ahb_ptr = req->dest_addr;
-
-		apb_addr_wrap = req->source_wrap;
-		ahb_addr_wrap = req->dest_wrap;
-		apb_bus_width = req->source_bus_width;
-		ahb_bus_width = req->dest_bus_width;
-
-	} else {
-		csr |= CSR_DIR;
-		apb_ptr = req->dest_addr;
-		ahb_ptr = req->source_addr;
-
-		apb_addr_wrap = req->dest_wrap;
-		ahb_addr_wrap = req->source_wrap;
-		apb_bus_width = req->dest_bus_width;
-		ahb_bus_width = req->source_bus_width;
-	}
-
-	apb_addr_wrap >>= 2;
-	ahb_addr_wrap >>= 2;
-
-	/* set address wrap for APB size */
-	index = 0;
-	do  {
-		if (apb_addr_wrap_table[index] == apb_addr_wrap)
-			break;
-		index++;
-	} while (index < ARRAY_SIZE(apb_addr_wrap_table));
-	BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
-	apb_seq |= index << APB_SEQ_WRAP_SHIFT;
-
-	/* set address wrap for AHB size */
-	index = 0;
-	do  {
-		if (ahb_addr_wrap_table[index] == ahb_addr_wrap)
-			break;
-		index++;
-	} while (index < ARRAY_SIZE(ahb_addr_wrap_table));
-	BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
-	ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
-
-	for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
-		if (bus_width_table[index] == ahb_bus_width)
-			break;
-	}
-	BUG_ON(index == ARRAY_SIZE(bus_width_table));
-	ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
-
-	for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
-		if (bus_width_table[index] == apb_bus_width)
-			break;
-	}
-	BUG_ON(index == ARRAY_SIZE(bus_width_table));
-	apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
-
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-	writel(apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
-	writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
-	writel(ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
-	writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
-
-	csr |= CSR_ENB;
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
-	req->status = TEGRA_DMA_REQ_INFLIGHT;
-}
-
-static void handle_oneshot_dma(struct tegra_dma_channel *ch)
-{
-	struct tegra_dma_req *req;
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-	if (list_empty(&ch->list)) {
-		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		return;
-	}
-
-	req = list_entry(ch->list.next, typeof(*req), node);
-	if (req) {
-		int bytes_transferred;
-
-		bytes_transferred = ch->req_transfer_count;
-		bytes_transferred += 1;
-		bytes_transferred <<= 2;
-
-		list_del(&req->node);
-		req->bytes_transferred = bytes_transferred;
-		req->status = TEGRA_DMA_REQ_SUCCESS;
-
-		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		/* Callback should be called without any lock */
-		pr_debug("%s: transferred %d bytes\n", __func__,
-			req->bytes_transferred);
-		req->complete(req);
-		spin_lock_irqsave(&ch->lock, irq_flags);
-	}
-
-	if (!list_empty(&ch->list)) {
-		req = list_entry(ch->list.next, typeof(*req), node);
-		/* the complete function we just called may have enqueued
-		   another req, in which case dma has already started */
-		if (req->status != TEGRA_DMA_REQ_INFLIGHT)
-			tegra_dma_update_hw(ch, req);
-	}
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-}
-
-static void handle_continuous_dma(struct tegra_dma_channel *ch)
-{
-	struct tegra_dma_req *req;
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&ch->lock, irq_flags);
-	if (list_empty(&ch->list)) {
-		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		return;
-	}
-
-	req = list_entry(ch->list.next, typeof(*req), node);
-	if (req) {
-		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
-			bool is_dma_ping_complete;
-			is_dma_ping_complete = (readl(ch->addr + APB_DMA_CHAN_STA)
-						& STA_PING_PONG) ? true : false;
-			if (req->to_memory)
-				is_dma_ping_complete = !is_dma_ping_complete;
-			/* Out of sync - Release current buffer */
-			if (!is_dma_ping_complete) {
-				int bytes_transferred;
-
-				bytes_transferred = ch->req_transfer_count;
-				bytes_transferred += 1;
-				bytes_transferred <<= 3;
-				req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
-				req->bytes_transferred = bytes_transferred;
-				req->status = TEGRA_DMA_REQ_SUCCESS;
-				tegra_dma_stop(ch);
-
-				if (!list_is_last(&req->node, &ch->list)) {
-					struct tegra_dma_req *next_req;
-
-					next_req = list_entry(req->node.next,
-						typeof(*next_req), node);
-					tegra_dma_update_hw(ch, next_req);
-				}
-
-				list_del(&req->node);
-
-				/* DMA lock is NOT held when callbak is called */
-				spin_unlock_irqrestore(&ch->lock, irq_flags);
-				req->complete(req);
-				return;
-			}
-			/* Load the next request into the hardware, if available
-			 * */
-			if (!list_is_last(&req->node, &ch->list)) {
-				struct tegra_dma_req *next_req;
-
-				next_req = list_entry(req->node.next,
-					typeof(*next_req), node);
-				tegra_dma_update_hw_partial(ch, next_req);
-			}
-			req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
-			req->status = TEGRA_DMA_REQ_SUCCESS;
-			/* DMA lock is NOT held when callback is called */
-			spin_unlock_irqrestore(&ch->lock, irq_flags);
-			if (likely(req->threshold))
-				req->threshold(req);
-			return;
-
-		} else if (req->buffer_status ==
-			TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
-			/* Callback when the buffer is completely full (i.e on
-			 * the second  interrupt */
-			int bytes_transferred;
-
-			bytes_transferred = ch->req_transfer_count;
-			bytes_transferred += 1;
-			bytes_transferred <<= 3;
-
-			req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
-			req->bytes_transferred = bytes_transferred;
-			req->status = TEGRA_DMA_REQ_SUCCESS;
-			list_del(&req->node);
-
-			/* DMA lock is NOT held when callbak is called */
-			spin_unlock_irqrestore(&ch->lock, irq_flags);
-			req->complete(req);
-			return;
-
-		} else {
-			BUG();
-		}
-	}
-	spin_unlock_irqrestore(&ch->lock, irq_flags);
-}
-
-static irqreturn_t dma_isr(int irq, void *data)
-{
-	struct tegra_dma_channel *ch = data;
-	unsigned long status;
-
-	status = readl(ch->addr + APB_DMA_CHAN_STA);
-	if (status & STA_ISE_EOC)
-		writel(status, ch->addr + APB_DMA_CHAN_STA);
-	else {
-		pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id);
-		return IRQ_HANDLED;
-	}
-	return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t dma_thread_fn(int irq, void *data)
-{
-	struct tegra_dma_channel *ch = data;
-
-	if (ch->mode & TEGRA_DMA_MODE_ONESHOT)
-		handle_oneshot_dma(ch);
-	else
-		handle_continuous_dma(ch);
-
-
-	return IRQ_HANDLED;
-}
-
-int __init tegra_dma_init(void)
-{
-	int ret = 0;
-	int i;
-	unsigned int irq;
-	void __iomem *addr;
-	struct clk *c;
-
-	bitmap_fill(channel_usage, NV_DMA_MAX_CHANNELS);
-
-	c = clk_get_sys("tegra-apbdma", NULL);
-	if (IS_ERR(c)) {
-		pr_err("Unable to get clock for APB DMA\n");
-		ret = PTR_ERR(c);
-		goto fail;
-	}
-	ret = clk_prepare_enable(c);
-	if (ret != 0) {
-		pr_err("Unable to enable clock for APB DMA\n");
-		goto fail;
-	}
-
-	addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
-	writel(GEN_ENABLE, addr + APB_DMA_GEN);
-	writel(0, addr + APB_DMA_CNTRL);
-	writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
-	       addr + APB_DMA_IRQ_MASK_SET);
-
-	for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
-		struct tegra_dma_channel *ch = &dma_channels[i];
-
-		ch->id = i;
-		snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
-
-		ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
-			TEGRA_APB_DMA_CH0_SIZE * i);
-
-		spin_lock_init(&ch->lock);
-		INIT_LIST_HEAD(&ch->list);
-
-		irq = INT_APB_DMA_CH0 + i;
-		ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
-			dma_channels[i].name, ch);
-		if (ret) {
-			pr_err("Failed to register IRQ %d for DMA %d\n",
-				irq, i);
-			goto fail;
-		}
-		ch->irq = irq;
-
-		__clear_bit(i, channel_usage);
-	}
-	/* mark the shared channel allocated */
-	__set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
-
-	tegra_dma_initialized = true;
-
-	return 0;
-fail:
-	writel(0, addr + APB_DMA_GEN);
-	for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
-		struct tegra_dma_channel *ch = &dma_channels[i];
-		if (ch->irq)
-			free_irq(ch->irq, ch);
-	}
-	return ret;
-}
-postcore_initcall(tegra_dma_init);
-
-#ifdef CONFIG_PM
-static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
-
-void tegra_dma_suspend(void)
-{
-	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
-	u32 *ctx = apb_dma;
-	int i;
-
-	*ctx++ = readl(addr + APB_DMA_GEN);
-	*ctx++ = readl(addr + APB_DMA_CNTRL);
-	*ctx++ = readl(addr + APB_DMA_IRQ_MASK);
-
-	for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
-		addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
-				  TEGRA_APB_DMA_CH0_SIZE * i);
-
-		*ctx++ = readl(addr + APB_DMA_CHAN_CSR);
-		*ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR);
-		*ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ);
-		*ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR);
-		*ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ);
-	}
-}
-
-void tegra_dma_resume(void)
-{
-	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
-	u32 *ctx = apb_dma;
-	int i;
-
-	writel(*ctx++, addr + APB_DMA_GEN);
-	writel(*ctx++, addr + APB_DMA_CNTRL);
-	writel(*ctx++, addr + APB_DMA_IRQ_MASK);
-
-	for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
-		addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
-				  TEGRA_APB_DMA_CH0_SIZE * i);
-
-		writel(*ctx++, addr + APB_DMA_CHAN_CSR);
-		writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR);
-		writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ);
-		writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR);
-		writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ);
-	}
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index f946d12..0b7db17 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -93,9 +93,9 @@
 {
 	u32 id;
 
-	u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+	u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
 	reg |= 1 << 28;
-	writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+	writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
 
 	reg = tegra_fuse_readl(FUSE_SKU_INFO);
 	tegra_sku_id = reg & 0xFF;
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index fef9c2c..6addc78 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -7,17 +7,13 @@
 
 #include "flowctrl.h"
 #include "reset.h"
+#include "sleep.h"
 
 #define APB_MISC_GP_HIDREV	0x804
 #define PMC_SCRATCH41	0x140
 
 #define RESET_DATA(x)	((TEGRA_RESET_##x)*4)
 
-	.macro mov32, reg, val
-	movw	\reg, #:lower16:\val
-	movt	\reg, #:upper16:\val
-	.endm
-
         .section ".text.head", "ax"
 	__CPUINIT
 
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index d8dc9dd..d02a354 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -1,91 +1,23 @@
 /*
- *  linux/arch/arm/mach-realview/hotplug.c
  *
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
+ *  Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
-#include <linux/errno.h>
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
-#include <asm/cp15.h>
+#include <asm/smp_plat.h>
 
-static inline void cpu_enter_lowpower(void)
-{
-	unsigned int v;
+#include "sleep.h"
+#include "tegra_cpu_car.h"
 
-	flush_cache_all();
-	asm volatile(
-	"	mcr	p15, 0, %1, c7, c5, 0\n"
-	"	mcr	p15, 0, %1, c7, c10, 4\n"
-	/*
-	 * Turn off coherency
-	 */
-	"	mrc	p15, 0, %0, c1, c0, 1\n"
-	"	bic	%0, %0, #0x20\n"
-	"	mcr	p15, 0, %0, c1, c0, 1\n"
-	"	mrc	p15, 0, %0, c1, c0, 0\n"
-	"	bic	%0, %0, %2\n"
-	"	mcr	p15, 0, %0, c1, c0, 0\n"
-	  : "=&r" (v)
-	  : "r" (0), "Ir" (CR_C)
-	  : "cc");
-}
-
-static inline void cpu_leave_lowpower(void)
-{
-	unsigned int v;
-
-	asm volatile(
-	"mrc	p15, 0, %0, c1, c0, 0\n"
-	"	orr	%0, %0, %1\n"
-	"	mcr	p15, 0, %0, c1, c0, 0\n"
-	"	mrc	p15, 0, %0, c1, c0, 1\n"
-	"	orr	%0, %0, #0x20\n"
-	"	mcr	p15, 0, %0, c1, c0, 1\n"
-	  : "=&r" (v)
-	  : "Ir" (CR_C)
-	  : "cc");
-}
-
-static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
-{
-	/*
-	 * there is no power-control hardware on this platform, so all
-	 * we can do is put the core into WFI; this is safe as the calling
-	 * code will have already disabled interrupts
-	 */
-	for (;;) {
-		/*
-		 * here's the WFI
-		 */
-		asm(".word	0xe320f003\n"
-		    :
-		    :
-		    : "memory", "cc");
-
-		/*if (pen_release == cpu) {*/
-			/*
-			 * OK, proper wakeup, we're done
-			 */
-			break;
-		/*}*/
-
-		/*
-		 * Getting here, means that we have come out of WFI without
-		 * having been woken up - this shouldn't happen
-		 *
-		 * Just note it happening - when we're woken, we can report
-		 * its occurrence.
-		 */
-		(*spurious)++;
-	}
-}
+static void (*tegra_hotplug_shutdown)(void);
 
 int platform_cpu_kill(unsigned int cpu)
 {
@@ -99,22 +31,20 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
-	int spurious = 0;
+	cpu = cpu_logical_map(cpu);
 
-	/*
-	 * we're ready for shutdown now, so do it
-	 */
-	cpu_enter_lowpower();
-	platform_do_lowpower(cpu, &spurious);
+	/* Flush the L1 data cache. */
+	flush_cache_all();
 
-	/*
-	 * bring this CPU back into the world of cache
-	 * coherency, and then restore interrupts
-	 */
-	cpu_leave_lowpower();
+	/* Shut down the current CPU. */
+	tegra_hotplug_shutdown();
 
-	if (spurious)
-		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+	/* Clock gate the CPU */
+	tegra_wait_cpu_in_reset(cpu);
+	tegra_disable_cpu_clock(cpu);
+
+	/* Should never return here. */
+	BUG();
 }
 
 int platform_cpu_disable(unsigned int cpu)
@@ -125,3 +55,19 @@
 	 */
 	return cpu == 0 ? -EPERM : 0;
 }
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+extern void tegra20_hotplug_shutdown(void);
+void __init tegra20_hotplug_init(void)
+{
+	tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
+}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+extern void tegra30_hotplug_shutdown(void);
+void __init tegra30_hotplug_init(void)
+{
+	tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
+}
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index d97e403..95f3a54 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -34,7 +34,10 @@
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
+#ifndef CONFIG_COMMON_CLK
 unsigned long clk_get_rate_all_locked(struct clk *c);
+#endif
+
 void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
 int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
 
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index 9077092..3081cc6 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -51,101 +51,4 @@
 #define TEGRA_DMA_REQ_SEL_OWR			25
 #define TEGRA_DMA_REQ_SEL_INVALID		31
 
-struct tegra_dma_req;
-struct tegra_dma_channel;
-
-enum tegra_dma_mode {
-	TEGRA_DMA_SHARED = 1,
-	TEGRA_DMA_MODE_CONTINOUS = 2,
-	TEGRA_DMA_MODE_ONESHOT = 4,
-};
-
-enum tegra_dma_req_error {
-	TEGRA_DMA_REQ_SUCCESS = 0,
-	TEGRA_DMA_REQ_ERROR_ABORTED,
-	TEGRA_DMA_REQ_INFLIGHT,
-};
-
-enum tegra_dma_req_buff_status {
-	TEGRA_DMA_REQ_BUF_STATUS_EMPTY = 0,
-	TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL,
-	TEGRA_DMA_REQ_BUF_STATUS_FULL,
-};
-
-struct tegra_dma_req {
-	struct list_head node;
-	unsigned int modid;
-	int instance;
-
-	/* Called when the req is complete and from the DMA ISR context.
-	 * When this is called the req structure is no longer queued by
-	 * the DMA channel.
-	 *
-	 * State of the DMA depends on the number of req it has. If there are
-	 * no DMA requests queued up, then it will STOP the DMA. It there are
-	 * more requests in the DMA, then it will queue the next request.
-	 */
-	void (*complete)(struct tegra_dma_req *req);
-
-	/*  This is a called from the DMA ISR context when the DMA is still in
-	 *  progress and is actively filling same buffer.
-	 *
-	 *  In case of continuous mode receive, this threshold is 1/2 the buffer
-	 *  size. In other cases, this will not even be called as there is no
-	 *  hardware support for it.
-	 *
-	 * In the case of continuous mode receive, if there is next req already
-	 * queued, DMA programs the HW to use that req when this req is
-	 * completed. If there is no "next req" queued, then DMA ISR doesn't do
-	 * anything before calling this callback.
-	 *
-	 *	This is mainly used by the cases, where the clients has queued
-	 *	only one req and want to get some sort of DMA threshold
-	 *	callback to program the next buffer.
-	 *
-	 */
-	void (*threshold)(struct tegra_dma_req *req);
-
-	/* 1 to copy to memory.
-	 * 0 to copy from the memory to device FIFO */
-	int to_memory;
-
-	void *virt_addr;
-
-	unsigned long source_addr;
-	unsigned long dest_addr;
-	unsigned long dest_wrap;
-	unsigned long source_wrap;
-	unsigned long source_bus_width;
-	unsigned long dest_bus_width;
-	unsigned long req_sel;
-	unsigned int size;
-
-	/* Updated by the DMA driver on the conpletion of the request. */
-	int bytes_transferred;
-	int status;
-
-	/* DMA completion tracking information */
-	int buffer_status;
-
-	/* Client specific data */
-	void *dev;
-};
-
-int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req);
-int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req);
-void tegra_dma_dequeue(struct tegra_dma_channel *ch);
-void tegra_dma_flush(struct tegra_dma_channel *ch);
-
-bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
-	struct tegra_dma_req *req);
-bool tegra_dma_is_empty(struct tegra_dma_channel *ch);
-
-struct tegra_dma_channel *tegra_dma_allocate_channel(int mode);
-void tegra_dma_free_channel(struct tegra_dma_channel *ch);
-
-int __init tegra_dma_init(void);
-
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
deleted file mode 100644
index fe700f9..0000000
--- a/arch/arm/mach-tegra/include/mach/io.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/io.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *	Erik Gilling <konkers@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __MACH_TEGRA_IO_H
-#define __MACH_TEGRA_IO_H
-
-#define IO_SPACE_LIMIT 0xffff
-
-#ifndef __ASSEMBLER__
-
-#ifdef CONFIG_TEGRA_PCI
-extern void __iomem *tegra_pcie_io_base;
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
-}
-#else
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)addr;
-}
-#endif
-
-#define __io(a)         __io(a)
-
-#endif
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 7e76da7..fee3a94 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -303,6 +303,9 @@
 #define IO_APB_VIRT	IOMEM(0xFE300000)
 #define IO_APB_SIZE	SZ_1M
 
+#define TEGRA_PCIE_BASE		0x80000000
+#define TEGRA_PCIE_IO_BASE	(TEGRA_PCIE_BASE + SZ_4M)
+
 #define IO_TO_VIRT_BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
 #define IO_TO_VIRT_XLATE(p, pst, vst)	(((p) - (pst) + (vst)))
 
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
deleted file mode 100644
index 935ce9f..0000000
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/usb_phy.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __MACH_USB_PHY_H
-#define __MACH_USB_PHY_H
-
-#include <linux/clk.h>
-#include <linux/usb/otg.h>
-
-struct tegra_utmip_config {
-	u8 hssync_start_delay;
-	u8 elastic_limit;
-	u8 idle_wait_delay;
-	u8 term_range_adj;
-	u8 xcvr_setup;
-	u8 xcvr_lsfslew;
-	u8 xcvr_lsrslew;
-};
-
-struct tegra_ulpi_config {
-	int reset_gpio;
-	const char *clk;
-};
-
-enum tegra_usb_phy_port_speed {
-	TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
-	TEGRA_USB_PHY_PORT_SPEED_LOW,
-	TEGRA_USB_PHY_PORT_SPEED_HIGH,
-};
-
-enum tegra_usb_phy_mode {
-	TEGRA_USB_PHY_MODE_DEVICE,
-	TEGRA_USB_PHY_MODE_HOST,
-};
-
-struct tegra_xtal_freq;
-
-struct tegra_usb_phy {
-	int instance;
-	const struct tegra_xtal_freq *freq;
-	void __iomem *regs;
-	void __iomem *pad_regs;
-	struct clk *clk;
-	struct clk *pll_u;
-	struct clk *pad_clk;
-	enum tegra_usb_phy_mode mode;
-	void *config;
-	struct usb_phy *ulpi;
-};
-
-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
-	void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
-
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
-				 enum tegra_usb_phy_port_speed port_speed);
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_close(struct tegra_usb_phy *phy);
-
-#endif /* __MACH_USB_PHY_H */
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index d3ad515..a8dba64 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -171,8 +171,6 @@
  * 0x90000000 - 0x9fffffff - non-prefetchable memory
  * 0xa0000000 - 0xbfffffff - prefetchable memory
  */
-#define TEGRA_PCIE_BASE		0x80000000
-
 #define PCIE_REGS_SZ		SZ_16K
 #define PCIE_CFG_OFF		PCIE_REGS_SZ
 #define PCIE_CFG_SZ		SZ_1M
@@ -180,8 +178,6 @@
 #define PCIE_EXT_CFG_SZ		SZ_1M
 #define PCIE_IOMAP_SZ		(PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
 
-#define MMIO_BASE		(TEGRA_PCIE_BASE + SZ_4M)
-#define MMIO_SIZE		SZ_64K
 #define MEM_BASE_0		(TEGRA_PCIE_BASE + SZ_256M)
 #define MEM_SIZE_0		SZ_128M
 #define MEM_BASE_1		(MEM_BASE_0 + MEM_SIZE_0)
@@ -204,10 +200,9 @@
 
 	bool			link_up;
 
-	char			io_space_name[16];
 	char			mem_space_name[16];
 	char			prefetch_space_name[20];
-	struct resource		res[3];
+	struct resource		res[2];
 };
 
 struct tegra_pcie_info {
@@ -223,17 +218,7 @@
 	struct clk		*pll_e;
 };
 
-static struct tegra_pcie_info tegra_pcie = {
-	.res_mmio = {
-		.name = "PCI IO",
-		.start = MMIO_BASE,
-		.end = MMIO_BASE + MMIO_SIZE - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-void __iomem *tegra_pcie_io_base;
-EXPORT_SYMBOL(tegra_pcie_io_base);
+static struct tegra_pcie_info tegra_pcie;
 
 static inline void afi_writel(u32 value, unsigned long offset)
 {
@@ -367,17 +352,7 @@
 /* Tegra PCIE requires relaxed ordering */
 static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
 {
-	u16 val16;
-	int pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-
-	if (pos <= 0) {
-		dev_err(&dev->dev, "skipping relaxed ordering fixup\n");
-		return;
-	}
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &val16);
-	val16 |= PCI_EXP_DEVCTL_RELAX_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, val16);
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
 
@@ -391,24 +366,7 @@
 	pp = tegra_pcie.port + nr;
 	pp->root_bus_nr = sys->busnr;
 
-	/*
-	 * IORESOURCE_IO
-	 */
-	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-		 "PCIe %d I/O", pp->index);
-	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-	pp->res[0].name = pp->io_space_name;
-	if (pp->index == 0) {
-		pp->res[0].start = PCIBIOS_MIN_IO;
-		pp->res[0].end = pp->res[0].start + SZ_32K - 1;
-	} else {
-		pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
-		pp->res[0].end = IO_SPACE_LIMIT;
-	}
-	pp->res[0].flags = IORESOURCE_IO;
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	pci_ioremap_io(nr * SZ_64K, TEGRA_PCIE_IO_BASE);
 
 	/*
 	 * IORESOURCE_MEM
@@ -416,18 +374,18 @@
 	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
 		 "PCIe %d MEM", pp->index);
 	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-	pp->res[1].name = pp->mem_space_name;
+	pp->res[0].name = pp->mem_space_name;
 	if (pp->index == 0) {
-		pp->res[1].start = MEM_BASE_0;
-		pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+		pp->res[0].start = MEM_BASE_0;
+		pp->res[0].end = pp->res[0].start + MEM_SIZE_0 - 1;
 	} else {
-		pp->res[1].start = MEM_BASE_1;
-		pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+		pp->res[0].start = MEM_BASE_1;
+		pp->res[0].end = pp->res[0].start + MEM_SIZE_1 - 1;
 	}
-	pp->res[1].flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	pp->res[0].flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res[0]))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->mem_offset);
 
 	/*
 	 * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -435,18 +393,18 @@
 	snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
 		 "PCIe %d PREFETCH MEM", pp->index);
 	pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
-	pp->res[2].name = pp->prefetch_space_name;
+	pp->res[1].name = pp->prefetch_space_name;
 	if (pp->index == 0) {
-		pp->res[2].start = PREFETCH_MEM_BASE_0;
-		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+		pp->res[1].start = PREFETCH_MEM_BASE_0;
+		pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_0 - 1;
 	} else {
-		pp->res[2].start = PREFETCH_MEM_BASE_1;
-		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+		pp->res[1].start = PREFETCH_MEM_BASE_1;
+		pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_1 - 1;
 	}
-	pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-	if (request_resource(&iomem_resource, &pp->res[2]))
+	pp->res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+	if (request_resource(&iomem_resource, &pp->res[1]))
 		panic("Request PCIe Prefetch Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	return 1;
 }
@@ -541,8 +499,8 @@
 
 	/* Bar 2: downstream IO bar */
 	fpci_bar = ((__u32)0xfdfc << 16);
-	size = MMIO_SIZE;
-	axi_address = MMIO_BASE;
+	size = SZ_128K;
+	axi_address = TEGRA_PCIE_IO_BASE;
 	afi_writel(axi_address, AFI_AXI_BAR2_START);
 	afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
 	afi_writel(fpci_bar, AFI_FPCI_BAR2);
@@ -776,7 +734,6 @@
 
 static int __init tegra_pcie_get_resources(void)
 {
-	struct resource *res_mmio = &tegra_pcie.res_mmio;
 	int err;
 
 	err = tegra_pcie_clocks_get();
@@ -798,34 +755,16 @@
 		goto err_map_reg;
 	}
 
-	err = request_resource(&iomem_resource, res_mmio);
-	if (err) {
-		pr_err("PCIE: Failed to request resources: %d\n", err);
-		goto err_req_io;
-	}
-
-	tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
-					     resource_size(res_mmio));
-	if (tegra_pcie_io_base == NULL) {
-		pr_err("PCIE: Failed to map IO\n");
-		err = -ENOMEM;
-		goto err_map_io;
-	}
-
 	err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
 			  IRQF_SHARED, "PCIE", &tegra_pcie);
 	if (err) {
 		pr_err("PCIE: Failed to register IRQ: %d\n", err);
-		goto err_irq;
+		goto err_req_io;
 	}
 	set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
 
 	return 0;
 
-err_irq:
-	iounmap(tegra_pcie_io_base);
-err_map_io:
-	release_resource(&tegra_pcie.res_mmio);
 err_req_io:
 	iounmap(tegra_pcie.regs);
 err_map_reg:
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1a208db..96ed171 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -31,6 +31,7 @@
 #include "fuse.h"
 #include "flowctrl.h"
 #include "reset.h"
+#include "tegra_cpu_car.h"
 
 extern void tegra_secondary_startup(void);
 
@@ -38,17 +39,6 @@
 
 #define EVP_CPU_RESET_VECTOR \
 	(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
-#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
-#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
-#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
-#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
-
-#define CPU_CLOCK(cpu)	(0x1<<(8+cpu))
-#define CPU_RESET(cpu)	(0x1111ul<<(cpu))
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
@@ -63,13 +53,8 @@
 
 static int tegra20_power_up_cpu(unsigned int cpu)
 {
-	u32 reg;
-
 	/* Enable the CPU clock. */
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-	writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-	barrier();
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	tegra_enable_cpu_clock(cpu);
 
 	/* Clear flow controller CSR. */
 	flowctrl_write_cpu_csr(cpu, 0);
@@ -79,7 +64,6 @@
 
 static int tegra30_power_up_cpu(unsigned int cpu)
 {
-	u32 reg;
 	int ret, pwrgateid;
 	unsigned long timeout;
 
@@ -103,8 +87,7 @@
 	}
 
 	/* CPU partition is powered. Enable the CPU clock. */
-	writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	tegra_enable_cpu_clock(cpu);
 	udelay(10);
 
 	/* Remove I/O clamps. */
@@ -128,8 +111,7 @@
 	 * via the flow controller). This will have no effect on first boot
 	 * of the CPU since it should already be in reset.
 	 */
-	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
-	dmb();
+	tegra_put_cpu_in_reset(cpu);
 
 	/*
 	 * Unhalt the CPU. If the flow controller was used to power-gate the
@@ -155,8 +137,7 @@
 		goto done;
 
 	/* Take the CPU out of reset. */
-	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
-	wmb();
+	tegra_cpu_out_of_reset(cpu);
 done:
 	return status;
 }
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 15d5065..de0662d 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -199,7 +199,9 @@
 
 #ifdef CONFIG_DEBUG_FS
 
-static const char * const powergate_name[] = {
+static const char * const *powergate_name;
+
+static const char * const powergate_name_t20[] = {
 	[TEGRA_POWERGATE_CPU]	= "cpu",
 	[TEGRA_POWERGATE_3D]	= "3d",
 	[TEGRA_POWERGATE_VENC]	= "venc",
@@ -209,6 +211,23 @@
 	[TEGRA_POWERGATE_MPE]	= "mpe",
 };
 
+static const char * const powergate_name_t30[] = {
+	[TEGRA_POWERGATE_CPU]	= "cpu0",
+	[TEGRA_POWERGATE_3D]	= "3d0",
+	[TEGRA_POWERGATE_VENC]	= "venc",
+	[TEGRA_POWERGATE_VDEC]	= "vdec",
+	[TEGRA_POWERGATE_PCIE]	= "pcie",
+	[TEGRA_POWERGATE_L2]	= "l2",
+	[TEGRA_POWERGATE_MPE]	= "mpe",
+	[TEGRA_POWERGATE_HEG]	= "heg",
+	[TEGRA_POWERGATE_SATA]	= "sata",
+	[TEGRA_POWERGATE_CPU1]	= "cpu1",
+	[TEGRA_POWERGATE_CPU2]	= "cpu2",
+	[TEGRA_POWERGATE_CPU3]	= "cpu3",
+	[TEGRA_POWERGATE_CELP]	= "celp",
+	[TEGRA_POWERGATE_3D1]	= "3d1",
+};
+
 static int powergate_show(struct seq_file *s, void *data)
 {
 	int i;
@@ -237,14 +256,24 @@
 int __init tegra_powergate_debugfs_init(void)
 {
 	struct dentry *d;
-	int err = -ENOMEM;
 
-	d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
-		&powergate_fops);
-	if (!d)
-		return -ENOMEM;
+	switch (tegra_chip_id) {
+	case TEGRA20:
+		powergate_name = powergate_name_t20;
+		break;
+	case TEGRA30:
+		powergate_name = powergate_name_t30;
+		break;
+	}
 
-	return err;
+	if (powergate_name) {
+		d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
+			&powergate_fops);
+		if (!d)
+			return -ENOMEM;
+	}
+
+	return 0;
 }
 
 #endif
diff --git a/arch/arm/mach-tegra/sleep-t20.S b/arch/arm/mach-tegra/sleep-t20.S
new file mode 100644
index 0000000..a36ae41
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t20.S
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include <mach/iomap.h>
+
+#include "sleep.h"
+#include "flowctrl.h"
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+/*
+ * tegra20_hotplug_shutdown(void)
+ *
+ * puts the current cpu in reset
+ * should never return
+ */
+ENTRY(tegra20_hotplug_shutdown)
+	/* Turn off SMP coherency */
+	exit_smp r4, r5
+
+	/* Put this CPU down */
+	cpu_id	r0
+	bl	tegra20_cpu_shutdown
+	mov	pc, lr			@ should never get here
+ENDPROC(tegra20_hotplug_shutdown)
+
+/*
+ * tegra20_cpu_shutdown(int cpu)
+ *
+ * r0 is cpu to reset
+ *
+ * puts the specified CPU in wait-for-event mode on the flow controller
+ * and puts the CPU in reset
+ * can be called on the current cpu or another cpu
+ * if called on the current cpu, does not return
+ * MUST NOT BE CALLED FOR CPU 0.
+ *
+ * corrupts r0-r3, r12
+ */
+ENTRY(tegra20_cpu_shutdown)
+	cmp	r0, #0
+	moveq	pc, lr			@ must not be called for CPU 0
+
+	cpu_to_halt_reg r1, r0
+	ldr	r3, =TEGRA_FLOW_CTRL_VIRT
+	mov	r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
+	str	r2, [r3, r1]		@ put flow controller in wait event mode
+	ldr	r2, [r3, r1]
+	isb
+	dsb
+	movw	r1, 0x1011
+	mov	r1, r1, lsl r0
+	ldr	r3, =TEGRA_CLK_RESET_VIRT
+	str	r1, [r3, #0x340]	@ put slave CPU in reset
+	isb
+	dsb
+	cpu_id	r3
+	cmp	r3, r0
+	beq	.
+	mov	pc, lr
+ENDPROC(tegra20_cpu_shutdown)
+#endif
diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-t30.S
new file mode 100644
index 0000000..777d9ce
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t30.S
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include <mach/iomap.h>
+
+#include "sleep.h"
+#include "flowctrl.h"
+
+#define TEGRA30_POWER_HOTPLUG_SHUTDOWN	(1 << 27) /* Hotplug shutdown */
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+/*
+ * tegra30_hotplug_shutdown(void)
+ *
+ * Powergates the current CPU.
+ * Should never return.
+ */
+ENTRY(tegra30_hotplug_shutdown)
+	/* Turn off SMP coherency */
+	exit_smp r4, r5
+
+	/* Powergate this CPU */
+	mov	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
+	bl	tegra30_cpu_shutdown
+	mov	pc, lr			@ should never get here
+ENDPROC(tegra30_hotplug_shutdown)
+
+/*
+ * tegra30_cpu_shutdown(unsigned long flags)
+ *
+ * Puts the current CPU in wait-for-event mode on the flow controller
+ * and powergates it -- flags (in R0) indicate the request type.
+ * Must never be called for CPU 0.
+ *
+ * corrupts r0-r4, r12
+ */
+ENTRY(tegra30_cpu_shutdown)
+	cpu_id	r3
+	cmp	r3, #0
+	moveq	pc, lr		@ Must never be called for CPU 0
+
+	ldr	r12, =TEGRA_FLOW_CTRL_VIRT
+	cpu_to_csr_reg r1, r3
+	add	r1, r1, r12	@ virtual CSR address for this CPU
+	cpu_to_halt_reg r2, r3
+	add	r2, r2, r12	@ virtual HALT_EVENTS address for this CPU
+
+	/*
+	 * Clear this CPU's "event" and "interrupt" flags and power gate
+	 * it when halting but not before it is in the "WFE" state.
+	 */
+	movw	r12, \
+		FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
+		FLOW_CTRL_CSR_ENABLE
+	mov	r4, #(1 << 4)
+	orr	r12, r12, r4, lsl r3
+	str	r12, [r1]
+
+	/* Halt this CPU. */
+	mov	r3, #0x400
+delay_1:
+	subs	r3, r3, #1			@ delay as a part of wfe war.
+	bge	delay_1;
+	cpsid	a				@ disable imprecise aborts.
+	ldr	r3, [r1]			@ read CSR
+	str	r3, [r1]			@ clear CSR
+	tst	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
+	movne	r3, #FLOW_CTRL_WAITEVENT		@ For hotplug
+	str	r3, [r2]
+	ldr	r0, [r2]
+	b	wfe_war
+
+__cpu_reset_again:
+	dsb
+	.align 5
+	wfe					@ CPU should be power gated here
+wfe_war:
+	b	__cpu_reset_again
+
+	/*
+	 * 38 nop's, which fills reset of wfe cache line and
+	 * 4 more cachelines with nop
+	 */
+	.rept 38
+	nop
+	.endr
+	b	.				@ should never get here
+
+ENDPROC(tegra30_cpu_shutdown)
+#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index d29b156..ea81554 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -29,36 +29,5 @@
 #include <mach/iomap.h>
 
 #include "flowctrl.h"
+#include "sleep.h"
 
-#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
-					+ IO_PPSB_VIRT)
-
-/* returns the offset of the flow controller halt register for a cpu */
-.macro cpu_to_halt_reg rd, rcpu
-	cmp	\rcpu, #0
-	subne	\rd, \rcpu, #1
-	movne	\rd, \rd, lsl #3
-	addne	\rd, \rd, #0x14
-	moveq	\rd, #0
-.endm
-
-/* returns the offset of the flow controller csr register for a cpu */
-.macro cpu_to_csr_reg rd, rcpu
-	cmp	\rcpu, #0
-	subne	\rd, \rcpu, #1
-	movne	\rd, \rd, lsl #3
-	addne	\rd, \rd, #0x18
-	moveq	\rd, #8
-.endm
-
-/* returns the ID of the current processor */
-.macro cpu_id, rd
-	mrc	p15, 0, \rd, c0, c0, 5
-	and	\rd, \rd, #0xF
-.endm
-
-/* loads a 32-bit value into a register without a data access */
-.macro mov32, reg, val
-	movw	\reg, #:lower16:\val
-	movt	\reg, #:upper16:\val
-.endm
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
new file mode 100644
index 0000000..e25a7cd
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_SLEEP_H
+#define __MACH_TEGRA_SLEEP_H
+
+#include <mach/iomap.h>
+
+#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
+					+ IO_CPU_VIRT)
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+					+ IO_PPSB_VIRT)
+#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
+					+ IO_PPSB_VIRT)
+
+#ifdef __ASSEMBLY__
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x14
+	moveq	\rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x18
+	moveq	\rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+	mrc	p15, 0, \rd, c0, c0, 5
+	and	\rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+	movw	\reg, #:lower16:\val
+	movt	\reg, #:upper16:\val
+.endm
+
+/* Macro to exit SMP coherency. */
+.macro exit_smp, tmp1, tmp2
+	mrc	p15, 0, \tmp1, c1, c0, 1	@ ACTLR
+	bic	\tmp1, \tmp1, #(1<<6) | (1<<0)	@ clear ACTLR.SMP | ACTLR.FW
+	mcr	p15, 0, \tmp1, c1, c0, 1	@ ACTLR
+	isb
+	cpu_id	\tmp1
+	mov	\tmp1, \tmp1, lsl #2
+	mov	\tmp2, #0xf
+	mov	\tmp2, \tmp2, lsl \tmp1
+	mov32	\tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
+	str	\tmp2, [\tmp1]			@ invalidate SCU tags for CPU
+	dsb
+.endm
+#else
+
+#ifdef CONFIG_HOTPLUG_CPU
+void tegra20_hotplug_init(void);
+void tegra30_hotplug_init(void);
+#else
+static inline void tegra20_hotplug_init(void) {}
+static inline void tegra30_hotplug_init(void) {}
+#endif
+
+#endif
+#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
new file mode 100644
index 0000000..9273b0df
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.c
@@ -0,0 +1,1625 @@
+/*
+ * arch/arm/mach-tegra/tegra20_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+#include "tegra_cpu_car.h"
+
+#define RST_DEVICES			0x004
+#define RST_DEVICES_SET			0x300
+#define RST_DEVICES_CLR			0x304
+#define RST_DEVICES_NUM			3
+
+#define CLK_OUT_ENB			0x010
+#define CLK_OUT_ENB_SET			0x320
+#define CLK_OUT_ENB_CLR			0x324
+#define CLK_OUT_ENB_NUM			3
+
+#define CLK_MASK_ARM			0x44
+#define MISC_CLK_ENB			0x48
+
+#define OSC_CTRL			0x50
+#define OSC_CTRL_OSC_FREQ_MASK		(3<<30)
+#define OSC_CTRL_OSC_FREQ_13MHZ		(0<<30)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ	(1<<30)
+#define OSC_CTRL_OSC_FREQ_12MHZ		(2<<30)
+#define OSC_CTRL_OSC_FREQ_26MHZ		(3<<30)
+#define OSC_CTRL_MASK			(0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_FREQ_DET			0x58
+#define OSC_FREQ_DET_TRIG		(1<<31)
+
+#define OSC_FREQ_DET_STATUS		0x5C
+#define OSC_FREQ_DET_BUSY		(1<<31)
+#define OSC_FREQ_DET_CNT_MASK		0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1		0x100
+#define PERIPH_CLK_SOURCE_EMC		0x19c
+#define PERIPH_CLK_SOURCE_OSC		0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_MASK		(3<<30)
+#define PERIPH_CLK_SOURCE_SHIFT		30
+#define PERIPH_CLK_SOURCE_PWM_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_PWM_SHIFT	28
+#define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
+#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT	0
+
+#define SDMMC_CLK_INT_FB_SEL		(1 << 23)
+#define SDMMC_CLK_INT_FB_DLY_SHIFT	16
+#define SDMMC_CLK_INT_FB_DLY_MASK	(0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
+
+#define PLL_BASE			0x0
+#define PLL_BASE_BYPASS			(1<<31)
+#define PLL_BASE_ENABLE			(1<<30)
+#define PLL_BASE_REF_ENABLE		(1<<29)
+#define PLL_BASE_OVERRIDE		(1<<28)
+#define PLL_BASE_DIVP_MASK		(0x7<<20)
+#define PLL_BASE_DIVP_SHIFT		20
+#define PLL_BASE_DIVN_MASK		(0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT		8
+#define PLL_BASE_DIVM_MASK		(0x1F)
+#define PLL_BASE_DIVM_SHIFT		0
+
+#define PLL_OUT_RATIO_MASK		(0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT		8
+#define PLL_OUT_OVERRIDE		(1<<2)
+#define PLL_OUT_CLKEN			(1<<1)
+#define PLL_OUT_RESET_DISABLE		(1<<0)
+
+#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+
+#define PLL_MISC_DCCON_SHIFT		20
+#define PLL_MISC_CPCON_SHIFT		8
+#define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT		4
+#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT		0
+#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
+
+#define PLLU_BASE_POST_DIV		(1<<20)
+
+#define PLLD_MISC_CLKENABLE		(1<<30)
+#define PLLD_MISC_DIV_RST		(1<<23)
+#define PLLD_MISC_DCCON_SHIFT		12
+
+#define PLLE_MISC_READY			(1 << 15)
+
+#define PERIPH_CLK_TO_ENB_REG(c)	((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->u.periph.clk_num % 32))
+
+#define SUPER_CLK_MUX			0x00
+#define SUPER_STATE_SHIFT		28
+#define SUPER_STATE_MASK		(0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY		(0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE		(0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN			(0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ			(0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ			(0x4 << SUPER_STATE_SHIFT)
+#define SUPER_SOURCE_MASK		0xF
+#define	SUPER_FIQ_SOURCE_SHIFT		12
+#define	SUPER_IRQ_SOURCE_SHIFT		8
+#define	SUPER_RUN_SOURCE_SHIFT		4
+#define	SUPER_IDLE_SOURCE_SHIFT		0
+
+#define SUPER_CLK_DIVIDER		0x04
+
+#define BUS_CLK_DISABLE			(1<<3)
+#define BUS_CLK_DIV_MASK		0x3
+
+#define PMC_CTRL			0x0
+ #define PMC_CTRL_BLINK_ENB		(1 << 7)
+
+#define PMC_DPD_PADS_ORIDE		0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB	(1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT	0
+#define PMC_BLINK_TIMER_DATA_ON_MASK	0x7fff
+#define PMC_BLINK_TIMER_ENB		(1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT	16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK	0xffff
+
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX		0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET	0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR	0x344
+
+#define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))
+#define CPU_RESET(cpu)	(0x1111ul << (cpu))
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+/*
+ * Some clocks share a register with other clocks.  Any clock op that
+ * non-atomically modifies a register used by another clock must lock
+ * clock_register_lock first.
+ */
+static DEFINE_SPINLOCK(clock_register_lock);
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
+ */
+static int tegra_periph_clk_enable_refcount[3 * 32];
+
+#define clk_writel(value, reg) \
+	__raw_writel(value, reg_clk_base + (reg))
+#define clk_readl(reg) \
+	__raw_readl(reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+	__raw_writel(value, reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+	__raw_readl(reg_pmc_base + (reg))
+
+static unsigned long clk_measure_input_freq(void)
+{
+	u32 clock_autodetect;
+	clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+	do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+	clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+	if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+		return 12000000;
+	} else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+		return 13000000;
+	} else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+		return 19200000;
+	} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+		return 26000000;
+	} else {
+		pr_err("%s: Unexpected clock autodetect value %d",
+						__func__, clock_autodetect);
+		BUG();
+		return 0;
+	}
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+	s64 divider_u71 = parent_rate * 2;
+	divider_u71 += rate - 1;
+	do_div(divider_u71, rate);
+
+	if (divider_u71 - 2 < 0)
+		return 0;
+
+	if (divider_u71 - 2 > 255)
+		return -EINVAL;
+
+	return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+	s64 divider_u16;
+
+	divider_u16 = parent_rate;
+	divider_u16 += rate - 1;
+	do_div(divider_u16, rate);
+
+	if (divider_u16 - 1 < 0)
+		return 0;
+
+	if (divider_u16 - 1 > 0xFFFF)
+		return -EINVAL;
+
+	return divider_u16 - 1;
+}
+
+static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_clk_32k_ops = {
+	.recalc_rate = tegra_clk_fixed_recalc_rate,
+};
+
+/* clk_m functions */
+static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	if (!to_clk_tegra(hw)->fixed_rate)
+		to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra20_clk_m_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 osc_ctrl = clk_readl(OSC_CTRL);
+	u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+
+	switch (c->fixed_rate) {
+	case 12000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+		break;
+	case 13000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+		break;
+	case 19200000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+		break;
+	case 26000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+		break;
+	default:
+		BUG();
+	}
+	clk_writel(auto_clock_control, OSC_CTRL);
+}
+
+struct clk_ops tegra_clk_m_ops = {
+	.init = tegra20_clk_m_init,
+	.recalc_rate = tegra20_clk_m_recalc_rate,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra have two-stage muxes and a clock skipping
+ * super divider.  We will ignore the clock skipping divider, since we
+ * can't lower the voltage when using the clock skip, but we can if we
+ * lower the PLL frequency.
+ */
+static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg + SUPER_CLK_MUX);
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	c->state = ON;
+	return c->state;
+}
+
+static int tegra20_super_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+	return 0;
+}
+
+static void tegra20_super_clk_disable(struct clk_hw *hw)
+{
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	/* oops - don't disable the CPU clock! */
+	BUG();
+}
+
+static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	int val = clk_readl(c->reg + SUPER_CLK_MUX);
+	int source;
+	int shift;
+
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	source = (val >> shift) & SUPER_SOURCE_MASK;
+	return source;
+}
+
+static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
+	int shift;
+
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	val &= ~(SUPER_SOURCE_MASK << shift);
+	val |= index << shift;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+/* FIX ME: Need to switch parents to change the source PLL rate */
+static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	return prate;
+}
+
+static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	return *prate;
+}
+
+static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	return 0;
+}
+
+struct clk_ops tegra_super_ops = {
+	.is_enabled = tegra20_super_clk_is_enabled,
+	.enable = tegra20_super_clk_enable,
+	.disable = tegra20_super_clk_disable,
+	.set_parent = tegra20_super_clk_set_parent,
+	.get_parent = tegra20_super_clk_get_parent,
+	.set_rate = tegra20_super_clk_set_rate,
+	.round_rate = tegra20_super_clk_round_rate,
+	.recalc_rate = tegra20_super_clk_recalc_rate,
+};
+
+static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+struct clk_ops tegra_twd_ops = {
+	.recalc_rate = tegra20_twd_clk_recalc_rate,
+};
+
+static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
+{
+	return 0;
+}
+
+struct clk_ops tegra_cop_ops = {
+	.get_parent = tegra20_cop_clk_get_parent,
+};
+
+/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
+ * reset the COP block (i.e. AVP) */
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
+{
+	unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+	pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
+	clk_writel(1 << 1, reg);
+}
+
+/* bus clock functions */
+static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
+	return c->state;
+}
+
+static int tegra20_bus_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	val &= ~(BUS_CLK_DISABLE << c->reg_shift);
+	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return 0;
+}
+
+static void tegra20_bus_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	val |= BUS_CLK_DISABLE << c->reg_shift;
+	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	u64 rate = prate;
+
+	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
+	c->mul = 1;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	int ret = -EINVAL;
+	unsigned long flags;
+	u32 val;
+	int i;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	for (i = 1; i <= 4; i++) {
+		if (rate == parent_rate / i) {
+			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
+			val |= (i - 1) << c->reg_shift;
+			clk_writel(val, c->reg);
+			c->div = i;
+			c->mul = 1;
+			ret = 0;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return ret;
+}
+
+static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	unsigned long parent_rate = *prate;
+	s64 divider;
+
+	if (rate >= parent_rate)
+		return rate;
+
+	divider = parent_rate;
+	divider += rate - 1;
+	do_div(divider, rate);
+
+	if (divider < 0)
+		return divider;
+
+	if (divider > 4)
+		divider = 4;
+	do_div(parent_rate, divider);
+
+	return parent_rate;
+}
+
+struct clk_ops tegra_bus_ops = {
+	.is_enabled = tegra20_bus_clk_is_enabled,
+	.enable = tegra20_bus_clk_enable,
+	.disable = tegra20_bus_clk_disable,
+	.set_rate = tegra20_bus_clk_set_rate,
+	.round_rate = tegra20_bus_clk_round_rate,
+	.recalc_rate = tegra20_bus_clk_recalc_rate,
+};
+
+/* Blink output functions */
+static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+	u32 val;
+
+	c->mul = 1;
+	val = pmc_readl(c->reg);
+
+	if (val & PMC_BLINK_TIMER_ENB) {
+		unsigned int on_off;
+
+		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+			PMC_BLINK_TIMER_DATA_ON_MASK;
+		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off += val;
+		/* each tick in the blink timer is 4 32KHz clocks */
+		c->div = on_off * 4;
+	} else {
+		c->div = 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_blink_clk_enable(struct clk_hw *hw)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	return 0;
+}
+
+static void tegra20_blink_clk_disable(struct clk_hw *hw)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	if (rate >= parent_rate) {
+		c->div = 1;
+		pmc_writel(0, c->reg);
+	} else {
+		unsigned int on_off;
+		u32 val;
+
+		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+		c->div = on_off * 8;
+
+		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+			PMC_BLINK_TIMER_DATA_ON_SHIFT;
+		on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val |= on_off;
+		val |= PMC_BLINK_TIMER_ENB;
+		pmc_writel(val, c->reg);
+	}
+
+	return 0;
+}
+
+static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	int div;
+	int mul;
+	long round_rate = *prate;
+
+	mul = 1;
+
+	if (rate >= *prate) {
+		div = 1;
+	} else {
+		div = DIV_ROUND_UP(*prate / 8, rate);
+		div *= 8;
+	}
+
+	round_rate *= mul;
+	round_rate += div - 1;
+	do_div(round_rate, div);
+
+	return round_rate;
+}
+
+struct clk_ops tegra_blink_clk_ops = {
+	.is_enabled = tegra20_blink_clk_is_enabled,
+	.enable = tegra20_blink_clk_enable,
+	.disable = tegra20_blink_clk_disable,
+	.set_rate = tegra20_blink_clk_set_rate,
+	.round_rate = tegra20_blink_clk_round_rate,
+	.recalc_rate = tegra20_blink_clk_recalc_rate,
+};
+
+/* PLL Functions */
+static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
+{
+	udelay(c->u.pll.lock_delay);
+	return 0;
+}
+
+static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + PLL_BASE);
+
+	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
+				unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + PLL_BASE);
+	u64 rate = prate;
+
+	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+		const struct clk_pll_freq_table *sel;
+		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+			if (sel->input_rate == prate &&
+				sel->output_rate == c->u.pll.fixed_rate) {
+				c->mul = sel->n;
+				c->div = sel->m * sel->p;
+				break;
+			}
+		}
+		pr_err("Clock %s has unknown fixed frequency\n",
+			__clk_get_name(hw->clk));
+		BUG();
+	} else if (val & PLL_BASE_BYPASS) {
+		c->mul = 1;
+		c->div = 1;
+	} else {
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_pll_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~PLL_BASE_BYPASS;
+	val |= PLL_BASE_ENABLE;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	tegra20_pll_clk_wait_for_lock(c);
+
+	return 0;
+}
+
+static void tegra20_pll_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	val = clk_readl(c->reg);
+	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+	clk_writel(val, c->reg);
+}
+
+static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long input_rate = parent_rate;
+	const struct clk_pll_freq_table *sel;
+	u32 val;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & PLL_FIXED) {
+		int ret = 0;
+		if (rate != c->u.pll.fixed_rate) {
+			pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+				__func__, __clk_get_name(hw->clk),
+				c->u.pll.fixed_rate, rate);
+			ret = -EINVAL;
+		}
+		return ret;
+	}
+
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			c->mul = sel->n;
+			c->div = sel->m * sel->p;
+
+			val = clk_readl(c->reg + PLL_BASE);
+			if (c->flags & PLL_FIXED)
+				val |= PLL_BASE_OVERRIDE;
+			val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
+				 PLL_BASE_DIVM_MASK);
+			val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+				(sel->n << PLL_BASE_DIVN_SHIFT);
+			BUG_ON(sel->p < 1 || sel->p > 2);
+			if (c->flags & PLLU) {
+				if (sel->p == 1)
+					val |= PLLU_BASE_POST_DIV;
+			} else {
+				if (sel->p == 2)
+					val |= 1 << PLL_BASE_DIVP_SHIFT;
+			}
+			clk_writel(val, c->reg + PLL_BASE);
+
+			if (c->flags & PLL_HAS_CPCON) {
+				val = clk_readl(c->reg + PLL_MISC(c));
+				val &= ~PLL_MISC_CPCON_MASK;
+				val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+				clk_writel(val, c->reg + PLL_MISC(c));
+			}
+
+			if (c->state == ON)
+				tegra20_pll_clk_enable(hw);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	const struct clk_pll_freq_table *sel;
+	unsigned long input_rate = *prate;
+	u64 output_rate = *prate;
+	int mul;
+	int div;
+
+	if (c->flags & PLL_FIXED)
+		return c->u.pll.fixed_rate;
+
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			mul = sel->n;
+			div = sel->m * sel->p;
+			break;
+		}
+
+	if (sel->input_rate == 0)
+		return -EINVAL;
+
+	output_rate *= mul;
+	output_rate += div - 1; /* round up */
+	do_div(output_rate, div);
+
+	return output_rate;
+}
+
+struct clk_ops tegra_pll_ops = {
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_pll_clk_enable,
+	.disable = tegra20_pll_clk_disable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+static void tegra20_pllx_clk_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	if (tegra_sku_id == 7)
+		c->max_rate = 750000000;
+}
+
+struct clk_ops tegra_pllx_ops = {
+	.init = tegra20_pllx_clk_init,
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_pll_clk_enable,
+	.disable = tegra20_pll_clk_disable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+static int tegra20_plle_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	mdelay(1);
+
+	val = clk_readl(c->reg + PLL_BASE);
+	if (!(val & PLLE_MISC_READY))
+		return -EBUSY;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	return 0;
+}
+
+struct clk_ops tegra_plle_ops = {
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_plle_clk_enable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+/* Clock divider ops */
+static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	val >>= c->reg_shift;
+	c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+	if (!(val & PLL_OUT_RESET_DISABLE))
+		c->state = OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+	u32 val = clk_readl(c->reg);
+	u32 divu71;
+
+	val >>= c->reg_shift;
+
+	if (c->flags & DIV_U71) {
+		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+		c->div = (divu71 + 2);
+		c->mul = 2;
+	} else if (c->flags & DIV_2) {
+		c->div = 2;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+
+	rate *= c->mul;
+	rate += c->div - 1; /* round up */
+	do_div(rate, c->div);
+
+	return rate;
+}
+
+static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+		return 0;
+	} else if (c->flags & DIV_2) {
+		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		val &= ~PLLD_MISC_DIV_RST;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+	} else if (c->flags & DIV_2) {
+		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		val |= PLLD_MISC_DIV_RST;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+	}
+}
+
+static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	int divider_u71;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & DIV_U71) {
+		divider_u71 = clk_div71_get_divider(parent_rate, rate);
+		if (divider_u71 >= 0) {
+			spin_lock_irqsave(&clock_register_lock, flags);
+			val = clk_readl(c->reg);
+			new_val = val >> c->reg_shift;
+			new_val &= 0xFFFF;
+			if (c->flags & DIV_U71_FIXED)
+				new_val |= PLL_OUT_OVERRIDE;
+			new_val &= ~PLL_OUT_RATIO_MASK;
+			new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+			val &= ~(0xFFFF << c->reg_shift);
+			val |= new_val << c->reg_shift;
+			clk_writel(val, c->reg);
+			c->div = divider_u71 + 2;
+			c->mul = 2;
+			spin_unlock_irqrestore(&clock_register_lock, flags);
+			return 0;
+		}
+	} else if (c->flags & DIV_2) {
+		if (parent_rate == rate * 2)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = *prate;
+	int divider;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_2) {
+		return DIV_ROUND_UP(parent_rate, 2);
+	}
+	return -EINVAL;
+}
+
+struct clk_ops tegra_pll_div_ops = {
+	.is_enabled = tegra20_pll_div_clk_is_enabled,
+	.enable = tegra20_pll_div_clk_enable,
+	.disable = tegra20_pll_div_clk_disable,
+	.set_rate = tegra20_pll_div_clk_set_rate,
+	.round_rate = tegra20_pll_div_clk_round_rate,
+	.recalc_rate = tegra20_pll_div_clk_recalc_rate,
+};
+
+/* Periph clk ops */
+
+static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	c->state = ON;
+
+	if (!c->u.periph.clk_num)
+		goto out;
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+
+	if (!(c->flags & PERIPH_NO_RESET))
+		if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
+				PERIPH_CLK_TO_ENB_BIT(c))
+			c->state = OFF;
+
+out:
+	return c->state;
+}
+
+static int tegra20_periph_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (!c->u.periph.clk_num)
+		return 0;
+
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+		return 0;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+	if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
+		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+			RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+	if (c->flags & PERIPH_EMC_ENB) {
+		/* The EMC peripheral clock has 2 extra enable bits */
+		/* FIXME: Do they need to be disabled? */
+		val = clk_readl(c->reg);
+		val |= 0x3 << 24;
+		clk_writel(val, c->reg);
+	}
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return 0;
+}
+
+static void tegra20_periph_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (!c->u.periph.clk_num)
+		return;
+
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+		return;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+	pr_debug("%s %s on clock %s\n", __func__,
+		assert ? "assert" : "deassert", __clk_get_name(hw->clk));
+
+	BUG_ON(!c->u.periph.clk_num);
+
+	if (!(c->flags & PERIPH_NO_RESET))
+		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+			   base + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	u32 mask;
+	u32 shift;
+
+	pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
+
+	if (c->flags & MUX_PWM) {
+		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+		mask = PERIPH_CLK_SOURCE_PWM_MASK;
+	} else {
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+		mask = PERIPH_CLK_SOURCE_MASK;
+	}
+
+	val = clk_readl(c->reg);
+	val &= ~mask;
+	val |= (index) << shift;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	u32 mask;
+	u32 shift;
+
+	if (c->flags & MUX_PWM) {
+		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+		mask = PERIPH_CLK_SOURCE_PWM_MASK;
+	} else {
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+		mask = PERIPH_CLK_SOURCE_MASK;
+	}
+
+	if (c->flags & MUX)
+		return (val & mask) >> shift;
+	else
+		return 0;
+}
+
+static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = prate;
+	u32 val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+		c->div = divu71 + 2;
+		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+		return rate;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	int divider;
+
+	val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+			val |= divider;
+			clk_writel(val, c->reg);
+			c->div = divider + 2;
+			c->mul = 2;
+			return 0;
+		}
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+			val |= divider;
+			clk_writel(val, c->reg);
+			c->div = divider + 1;
+			c->mul = 1;
+			return 0;
+		}
+	} else if (parent_rate <= rate) {
+		c->div = 1;
+		c->mul = 1;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
+	unsigned long rate, unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+	int divider;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (prate)
+		parent_rate = *prate;
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate, divider + 1);
+	}
+	return -EINVAL;
+}
+
+struct clk_ops tegra_periph_clk_ops = {
+	.is_enabled = tegra20_periph_clk_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_parent = tegra20_periph_clk_set_parent,
+	.get_parent = tegra20_periph_clk_get_parent,
+	.set_rate = tegra20_periph_clk_set_rate,
+	.round_rate = tegra20_periph_clk_round_rate,
+	.recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* External memory controller clock ops */
+static void tegra20_emc_clk_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	c->max_rate = __clk_get_rate(hw->clk);
+}
+
+static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	long emc_rate;
+	long clk_rate;
+
+	/*
+	 * The slowest entry in the EMC clock table that is at least as
+	 * fast as rate.
+	 */
+	emc_rate = tegra_emc_round_rate(rate);
+	if (emc_rate < 0)
+		return c->max_rate;
+
+	/*
+	 * The fastest rate the PLL will generate that is at most the
+	 * requested rate.
+	 */
+	clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
+
+	/*
+	 * If this fails, and emc_rate > clk_rate, it's because the maximum
+	 * rate in the EMC tables is larger than the maximum rate of the EMC
+	 * clock. The EMC clock's max rate is the rate it was running when the
+	 * kernel booted. Such a mismatch is probably due to using the wrong
+	 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+	 */
+	WARN_ONCE(emc_rate != clk_rate,
+		"emc_rate %ld != clk_rate %ld",
+		emc_rate, clk_rate);
+
+	return emc_rate;
+}
+
+static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	int ret;
+
+	/*
+	 * The Tegra2 memory controller has an interlock with the clock
+	 * block that allows memory shadowed registers to be updated,
+	 * and then transfer them to the main registers at the same
+	 * time as the clock update without glitches.
+	 */
+	ret = tegra_emc_set_rate(rate);
+	if (ret < 0)
+		return ret;
+
+	ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
+	udelay(1);
+
+	return ret;
+}
+
+struct clk_ops tegra_emc_clk_ops = {
+	.init = tegra20_emc_clk_init,
+	.is_enabled = tegra20_periph_clk_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_parent = tegra20_periph_clk_set_parent,
+	.get_parent = tegra20_periph_clk_get_parent,
+	.set_rate = tegra20_emc_clk_set_rate,
+	.round_rate = tegra20_emc_clk_round_rate,
+	.recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* Clock doubler ops */
+static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	c->state = ON;
+
+	if (!c->u.periph.clk_num)
+		goto out;
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+
+out:
+	return c->state;
+};
+
+static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+
+	c->mul = 2;
+	c->div = 1;
+
+	rate *= c->mul;
+	rate += c->div - 1; /* round up */
+	do_div(rate, c->div);
+
+	return rate;
+}
+
+static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	unsigned long output_rate = *prate;
+
+	do_div(output_rate, 2);
+	return output_rate;
+}
+
+static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	if (rate != 2 * parent_rate)
+		return -EINVAL;
+	return 0;
+}
+
+struct clk_ops tegra_clk_double_ops = {
+	.is_enabled = tegra20_clk_double_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_rate = tegra20_clk_double_set_rate,
+	.recalc_rate = tegra20_clk_double_recalc_rate,
+	.round_rate = tegra20_clk_double_round_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	c->state = (val & (1<<4)) ? OFF : ON;
+	return c->state;
+}
+
+static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	clk_writel(0, c->reg);
+	return 0;
+}
+
+static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	clk_writel(1, c->reg);
+}
+
+static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source;
+
+	source = val & 0xf;
+	return source;
+}
+
+static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg);
+	val &= ~0xf;
+	val |= index;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+struct clk_ops tegra_audio_sync_clk_ops = {
+	.is_enabled = tegra20_audio_sync_clk_is_enabled,
+	.enable = tegra20_audio_sync_clk_enable,
+	.disable = tegra20_audio_sync_clk_disable,
+	.set_parent = tegra20_audio_sync_clk_set_parent,
+	.get_parent = tegra20_audio_sync_clk_get_parent,
+};
+
+/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
+
+static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
+	 * currently done in the pinmux code. */
+	c->state = ON;
+
+	BUG_ON(!c->u.periph.clk_num);
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+	return c->state;
+}
+
+static int tegra20_cdev_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	BUG_ON(!c->u.periph.clk_num);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+	return 0;
+}
+
+static void tegra20_cdev_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	BUG_ON(!c->u.periph.clk_num);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_cdev_clk_ops = {
+	.is_enabled = tegra20_cdev_clk_is_enabled,
+	.enable = tegra20_cdev_clk_enable,
+	.disable = tegra20_cdev_clk_disable,
+	.recalc_rate = tegra20_cdev_recalc_rate,
+};
+
+/* Tegra20 CPU clock and reset control functions */
+static void tegra20_wait_cpu_in_reset(u32 cpu)
+{
+	unsigned int reg;
+
+	do {
+		reg = readl(reg_clk_base +
+			    TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+		cpu_relax();
+	} while (!(reg & (1 << cpu)));	/* check CPU been reset or not */
+
+	return;
+}
+
+static void tegra20_put_cpu_in_reset(u32 cpu)
+{
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+	dmb();
+}
+
+static void tegra20_cpu_out_of_reset(u32 cpu)
+{
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+	wmb();
+}
+
+static void tegra20_enable_cpu_clock(u32 cpu)
+{
+	unsigned int reg;
+
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg & ~CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	barrier();
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+static void tegra20_disable_cpu_clock(u32 cpu)
+{
+	unsigned int reg;
+
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg | CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
+	.wait_for_reset	= tegra20_wait_cpu_in_reset,
+	.put_in_reset	= tegra20_put_cpu_in_reset,
+	.out_of_reset	= tegra20_cpu_out_of_reset,
+	.enable_clock	= tegra20_enable_cpu_clock,
+	.disable_clock	= tegra20_disable_cpu_clock,
+};
+
+void __init tegra20_cpu_car_ops_init(void)
+{
+	tegra_cpu_car_ops = &tegra20_cpu_car_ops;
+}
diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h
new file mode 100644
index 0000000..8bfd31b
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA20_CLOCK_H
+#define __MACH_TEGRA20_CLOCK_H
+
+extern struct clk_ops tegra_clk_32k_ops;
+extern struct clk_ops tegra_pll_ops;
+extern struct clk_ops tegra_clk_m_ops;
+extern struct clk_ops tegra_pll_div_ops;
+extern struct clk_ops tegra_pllx_ops;
+extern struct clk_ops tegra_plle_ops;
+extern struct clk_ops tegra_clk_double_ops;
+extern struct clk_ops tegra_cdev_clk_ops;
+extern struct clk_ops tegra_audio_sync_clk_ops;
+extern struct clk_ops tegra_super_ops;
+extern struct clk_ops tegra_cpu_ops;
+extern struct clk_ops tegra_twd_ops;
+extern struct clk_ops tegra_cop_ops;
+extern struct clk_ops tegra_bus_ops;
+extern struct clk_ops tegra_blink_clk_ops;
+extern struct clk_ops tegra_emc_clk_ops;
+extern struct clk_ops tegra_periph_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
new file mode 100644
index 0000000..e81dcd2
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks_data.c
@@ -0,0 +1,1144 @@
+/*
+ * arch/arm/mach-tegra/tegra2_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+#include "tegra20_clocks.h"
+#include "tegra_cpu_car.h"
+
+/* Clock definitions */
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags,		\
+		   _parent_names, _parents, _parent)		\
+	static struct clk tegra_##_name = {			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.name = #_name,					\
+		.rate = _rate,					\
+		.ops = _ops,					\
+		.flags = _flags,				\
+		.parent_names = _parent_names,			\
+		.parents = _parents,				\
+		.num_parents = ARRAY_SIZE(_parent_names),	\
+		.parent = _parent,				\
+	};
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+	.hw = {
+		.clk = &tegra_clk_32k,
+	},
+	.fixed_rate = 32768,
+};
+
+static struct clk tegra_clk_32k = {
+	.name = "clk_32k",
+	.rate = 32768,
+	.ops = &tegra_clk_32k_ops,
+	.hw = &tegra_clk_32k_hw.hw,
+	.flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+	.hw = {
+		.clk = &tegra_clk_m,
+	},
+	.flags = ENABLE_ON_INIT,
+	.reg = 0x1fc,
+	.reg_shift = 28,
+	.max_rate = 26000000,
+	.fixed_rate = 0,
+};
+
+static struct clk tegra_clk_m = {
+	.name = "clk_m",
+	.ops = &tegra_clk_m_ops,
+	.hw = &tegra_clk_m_hw.hw,
+	.flags = CLK_IS_ROOT,
+};
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min,	\
+		   _input_max, _cf_min, _cf_max, _vco_min,	\
+		   _vco_max, _freq_table, _lock_delay, _ops,	\
+		   _fixed_rate, _parent)			\
+	static const char *tegra_##_name##_parent_names[] = {	\
+		#_parent,					\
+	};							\
+	static struct clk *tegra_##_name##_parents[] = {	\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.u.pll = {					\
+			.input_min = _input_min,		\
+			.input_max = _input_max,		\
+			.cf_min = _cf_min,			\
+			.cf_max = _cf_max,			\
+			.vco_min = _vco_min,			\
+			.vco_max = _vco_max,			\
+			.freq_table = _freq_table,		\
+			.lock_delay = _lock_delay,		\
+			.fixed_rate = _fixed_rate,		\
+		},						\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &_ops,					\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent = &tegra_##_parent,			\
+		.parent_names = tegra_##_name##_parent_names,	\
+		.parents = tegra_##_name##_parents,		\
+		.num_parents = 1,				\
+	};
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift,		\
+		_max_rate, _ops, _parent, _clk_flags)		\
+	static const char *tegra_##_name##_parent_names[] = {	\
+		#_parent,					\
+	};							\
+	static struct clk *tegra_##_name##_parents[] = {	\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.reg_shift = _reg_shift,			\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &tegra_pll_div_ops,			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent = &tegra_##_parent,			\
+		.parent_names = tegra_##_name##_parent_names,	\
+		.parents = tegra_##_name##_parents,		\
+		.num_parents = 1,				\
+		.flags = _clk_flags,				\
+	};
+
+
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
+	{32768, 12000000, 366, 1, 1, 0},
+	{32768, 13000000, 397, 1, 1, 0},
+	{32768, 19200000, 586, 1, 1, 0},
+	{32768, 26000000, 793, 1, 1, 0},
+	{0, 0, 0, 0, 0, 0},
+};
+
+DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0,
+		0, 12000000, 26000000, tegra_pll_s_freq_table, 300,
+		tegra_pll_ops, 0, clk_32k);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+	{ 12000000, 600000000, 600, 12, 1, 8 },
+	{ 13000000, 600000000, 600, 13, 1, 8 },
+	{ 19200000, 600000000, 500, 16, 1, 6 },
+	{ 26000000, 600000000, 600, 26, 1, 8 },
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+		tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000,
+		tegra_pll_div_ops, pll_c, 0);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300,
+		tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+		tegra_pll_div_ops, pll_m, 0);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 19200000, 216000000, 90,   4, 2, 1},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 12000000, 432000000, 432, 12, 1, 8},
+	{ 13000000, 432000000, 432, 13, 1, 8},
+	{ 19200000, 432000000, 90,   4, 1, 1},
+	{ 26000000, 432000000, 432, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+		tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300,
+		tegra_pll_ops, 0, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000,
+		tegra_pll_div_ops, pll_a, 0);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+	{ 12000000, 216000000, 216, 12, 1, 4},
+	{ 13000000, 216000000, 216, 13, 1, 4},
+	{ 19200000, 216000000, 135, 12, 1, 3},
+	{ 26000000, 216000000, 216, 26, 1, 4},
+
+	{ 12000000, 594000000, 594, 12, 1, 8},
+	{ 13000000, 594000000, 594, 13, 1, 8},
+	{ 19200000, 594000000, 495, 16, 1, 8},
+	{ 26000000, 594000000, 594, 26, 1, 8},
+
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+		1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+		1000, tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000,
+		tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+	{ 12000000, 480000000, 960, 12, 2, 0},
+	{ 13000000, 480000000, 960, 13, 2, 0},
+	{ 19200000, 480000000, 200, 4,  2, 0},
+	{ 26000000, 480000000, 960, 26, 2, 0},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000,
+		48000000, 960000000, tegra_pll_u_freq_table, 1000,
+		tegra_pll_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+	/* 1 GHz */
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	/* 912 MHz */
+	{ 12000000, 912000000,  912,  12, 1, 12},
+	{ 13000000, 912000000,  912,  13, 1, 12},
+	{ 19200000, 912000000,  760,  16, 1, 8},
+	{ 26000000, 912000000,  912,  26, 1, 12},
+
+	/* 816 MHz */
+	{ 12000000, 816000000,  816,  12, 1, 12},
+	{ 13000000, 816000000,  816,  13, 1, 12},
+	{ 19200000, 816000000,  680,  16, 1, 8},
+	{ 26000000, 816000000,  816,  26, 1, 12},
+
+	/* 760 MHz */
+	{ 12000000, 760000000,  760,  12, 1, 12},
+	{ 13000000, 760000000,  760,  13, 1, 12},
+	{ 19200000, 760000000,  950,  24, 1, 8},
+	{ 26000000, 760000000,  760,  26, 1, 12},
+
+	/* 750 MHz */
+	{ 12000000, 750000000,  750,  12, 1, 12},
+	{ 13000000, 750000000,  750,  13, 1, 12},
+	{ 19200000, 750000000,  625,  16, 1, 8},
+	{ 26000000, 750000000,  750,  26, 1, 12},
+
+	/* 608 MHz */
+	{ 12000000, 608000000,  608,  12, 1, 12},
+	{ 13000000, 608000000,  608,  13, 1, 12},
+	{ 19200000, 608000000,  380,  12, 1, 8},
+	{ 26000000, 608000000,  608,  26, 1, 12},
+
+	/* 456 MHz */
+	{ 12000000, 456000000,  456,  12, 1, 12},
+	{ 13000000, 456000000,  456,  13, 1, 12},
+	{ 19200000, 456000000,  380,  16, 1, 8},
+	{ 26000000, 456000000,  456,  26, 1, 12},
+
+	/* 312 MHz */
+	{ 12000000, 312000000,  312,  12, 1, 12},
+	{ 13000000, 312000000,  312,  13, 1, 12},
+	{ 19200000, 312000000,  260,  16, 1, 8},
+	{ 26000000, 312000000,  312,  26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000,
+		31000000, 1000000, 6000000, 20000000, 1200000000,
+		tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+	{ 12000000, 100000000,  200,  24, 1, 0 },
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0,
+		0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m);
+
+static const char *tegra_common_parent_names[] = {
+	"clk_m",
+};
+
+static struct clk *tegra_common_parents[] = {
+	&tegra_clk_m,
+};
+
+static struct clk tegra_clk_d;
+static struct clk_tegra tegra_clk_d_hw = {
+	.hw = {
+		.clk = &tegra_clk_d,
+	},
+	.flags = PERIPH_NO_RESET,
+	.reg = 0x34,
+	.reg_shift = 12,
+	.max_rate = 52000000,
+	.u.periph = {
+		.clk_num = 90,
+	},
+};
+
+static struct clk tegra_clk_d = {
+	.name = "clk_d",
+	.hw = &tegra_clk_d_hw.hw,
+	.ops = &tegra_clk_double_ops,
+	.parent = &tegra_clk_m,
+	.parent_names = tegra_common_parent_names,
+	.parents = tegra_common_parents,
+	.num_parents = ARRAY_SIZE(tegra_common_parent_names),
+};
+
+static struct clk tegra_cdev1;
+static struct clk_tegra tegra_cdev1_hw = {
+	.hw = {
+		.clk = &tegra_cdev1,
+	},
+	.fixed_rate = 26000000,
+	.u.periph = {
+		.clk_num = 94,
+	},
+};
+static struct clk tegra_cdev1 = {
+	.name = "cdev1",
+	.hw = &tegra_cdev1_hw.hw,
+	.ops = &tegra_cdev_clk_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+/* dap_mclk2, belongs to the cdev2 pingroup. */
+static struct clk tegra_cdev2;
+static struct clk_tegra tegra_cdev2_hw = {
+	.hw = {
+		.clk = &tegra_cdev2,
+	},
+	.fixed_rate = 26000000,
+	.u.periph = {
+		.clk_num  = 93,
+	},
+};
+static struct clk tegra_cdev2 = {
+	.name = "cdev2",
+	.hw = &tegra_cdev2_hw.hw,
+	.ops = &tegra_cdev_clk_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+	const char *name;
+	int value;
+} mux_audio_sync_clk_sources[] = {
+	{ .name = "spdif_in", .value = 0 },
+	{ .name = "i2s1", .value = 1 },
+	{ .name = "i2s2", .value = 2 },
+	{ .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+	{ .name = "ac97", .value = 3 },
+	{ .name = "ext_audio_clk2", .value = 5 },
+	{ .name = "ext_audio_clk1", .value = 6 },
+	{ .name = "ext_vimclk", .value = 7 },
+#endif
+	{ NULL, 0 }
+};
+
+static const char *audio_parent_names[] = {
+	"spdif_in",
+	"i2s1",
+	"i2s2",
+	"dummy",
+	"pll_a_out0",
+	"dummy",
+	"dummy",
+	"dummy",
+};
+
+static struct clk *audio_parents[] = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+};
+
+static struct clk tegra_audio;
+static struct clk_tegra tegra_audio_hw = {
+	.hw = {
+		.clk = &tegra_audio,
+	},
+	.reg = 0x38,
+	.max_rate = 73728000,
+};
+DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names,
+		audio_parents, NULL);
+
+static const char *audio_2x_parent_names[] = {
+	"audio",
+};
+
+static struct clk *audio_2x_parents[] = {
+	&tegra_audio,
+};
+
+static struct clk tegra_audio_2x;
+static struct clk_tegra tegra_audio_2x_hw = {
+	.hw = {
+		.clk = &tegra_audio_2x,
+	},
+	.flags = PERIPH_NO_RESET,
+	.max_rate = 48000000,
+	.reg = 0x34,
+	.reg_shift = 8,
+	.u.periph = {
+		.clk_num = 89,
+	},
+};
+DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names,
+		audio_2x_parents, &tegra_audio);
+
+static struct clk_lookup tegra_audio_clk_lookups[] = {
+	{ .con_id = "audio", .clk = &tegra_audio },
+	{ .con_id = "audio_2x", .clk = &tegra_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+	int i;
+	struct clk_mux_sel *sel = mux_audio_sync_clk;
+	const struct audio_sources *src = mux_audio_sync_clk_sources;
+	struct clk_lookup *lookup;
+
+	for (i = 0; src->name; i++, sel++, src++) {
+		sel->input = tegra_get_clock_by_name(src->name);
+		if (!sel->input)
+			pr_err("%s: could not find clk %s\n", __func__,
+				src->name);
+		audio_parents[src->value] = sel->input;
+		sel->value = src->value;
+	}
+
+	lookup = tegra_audio_clk_lookups;
+	for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+		struct clk *c = lookup->clk;
+		struct clk_tegra *clk = to_clk_tegra(c->hw);
+		__clk_init(NULL, c);
+		INIT_LIST_HEAD(&clk->shared_bus_list);
+		clk->lookup.con_id = lookup->con_id;
+		clk->lookup.clk = c;
+		clkdev_add(&clk->lookup);
+		tegra_clk_add(c);
+	}
+}
+
+static const char *mux_cclk[] = {
+	"clk_m",
+	"pll_c",
+	"clk_32k",
+	"pll_m",
+	"pll_p",
+	"pll_p_out4",
+	"pll_p_out3",
+	"clk_d",
+	"pll_x",
+};
+
+
+static struct clk *mux_cclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_pll_m,
+	&tegra_pll_p,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_clk_d,
+	&tegra_pll_x,
+};
+
+static const char *mux_sclk[] = {
+	"clk_m",
+	"pll_c_out1",
+	"pll_p_out4",
+	"pllp_p_out3",
+	"pll_p_out2",
+	"clk_d",
+	"clk_32k",
+	"pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c_out1,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out2,
+	&tegra_clk_d,
+	&tegra_clk_32k,
+	&tegra_pll_m_out1,
+};
+
+static struct clk tegra_cclk;
+static struct clk_tegra tegra_cclk_hw = {
+	.hw = {
+		.clk = &tegra_cclk,
+	},
+	.reg = 0x20,
+	.max_rate = 1000000000,
+};
+DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk,
+		mux_cclk_p, NULL);
+
+static const char *mux_twd[] = {
+	"cclk",
+};
+
+static struct clk *mux_twd_p[] = {
+	&tegra_cclk,
+};
+
+static struct clk tegra_clk_twd;
+static struct clk_tegra tegra_clk_twd_hw = {
+	.hw = {
+		.clk = &tegra_clk_twd,
+	},
+	.max_rate = 1000000000,
+	.mul = 1,
+	.div = 4,
+};
+
+static struct clk tegra_clk_twd = {
+	.name = "twd",
+	.ops = &tegra_twd_ops,
+	.hw = &tegra_clk_twd_hw.hw,
+	.parent = &tegra_cclk,
+	.parent_names = mux_twd,
+	.parents = mux_twd_p,
+	.num_parents = ARRAY_SIZE(mux_twd),
+};
+
+static struct clk tegra_sclk;
+static struct clk_tegra tegra_sclk_hw = {
+	.hw = {
+		.clk = &tegra_sclk,
+	},
+	.reg = 0x28,
+	.max_rate = 240000000,
+	.min_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk,
+		mux_sclk_p, NULL);
+
+static const char *tegra_cop_parent_names[] = {
+	"tegra_sclk",
+};
+
+static struct clk *tegra_cop_parents[] = {
+	&tegra_sclk,
+};
+
+static struct clk tegra_cop;
+static struct clk_tegra tegra_cop_hw = {
+	.hw = {
+		.clk = &tegra_cop,
+	},
+	.max_rate  = 240000000,
+	.reset = &tegra2_cop_clk_reset,
+};
+DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT,
+		tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk);
+
+static const char *tegra_hclk_parent_names[] = {
+	"tegra_sclk",
+};
+
+static struct clk *tegra_hclk_parents[] = {
+	&tegra_sclk,
+};
+
+static struct clk tegra_hclk;
+static struct clk_tegra tegra_hclk_hw = {
+	.hw = {
+		.clk = &tegra_hclk,
+	},
+	.flags = DIV_BUS,
+	.reg = 0x30,
+	.reg_shift = 4,
+	.max_rate = 240000000,
+};
+DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names,
+		tegra_hclk_parents, &tegra_sclk);
+
+static const char *tegra_pclk_parent_names[] = {
+	"tegra_hclk",
+};
+
+static struct clk *tegra_pclk_parents[] = {
+	&tegra_hclk,
+};
+
+static struct clk tegra_pclk;
+static struct clk_tegra tegra_pclk_hw = {
+	.hw = {
+		.clk = &tegra_pclk,
+	},
+	.flags = DIV_BUS,
+	.reg = 0x30,
+	.reg_shift = 0,
+	.max_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names,
+		tegra_pclk_parents, &tegra_hclk);
+
+static const char *tegra_blink_parent_names[] = {
+	"clk_32k",
+};
+
+static struct clk *tegra_blink_parents[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk tegra_blink;
+static struct clk_tegra tegra_blink_hw = {
+	.hw = {
+		.clk = &tegra_blink,
+	},
+	.reg = 0x40,
+	.max_rate = 32768,
+};
+DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names,
+		tegra_blink_parents, &tegra_clk_32k);
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"pll_a_out0",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_pll_a_out0,
+};
+
+static const char *mux_pllm_pllc_pllp_clkm[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"clk_m",
+};
+
+static struct clk *mux_pllm_pllc_pllp_clkm_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+	"clk_m",
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllaout0_audio2x_pllp_clkm[] = {
+	"pll_a_out0",
+	"audio_2x",
+	"pll_p",
+	"clk_m",
+};
+
+static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = {
+	&tegra_pll_a_out0,
+	&tegra_audio_2x,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+	"pllp",
+	"pll_d_out0",
+	"pll_c",
+	"clk_m",
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_d_out0,
+	&tegra_pll_c,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_audio_clkm_clk32[] = {
+	"pll_p",
+	"pll_c",
+	"audio",
+	"clk_m",
+	"clk_32k",
+};
+
+static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_audio,
+	&tegra_clk_m,
+	&tegra_clk_32k,
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m"
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+};
+
+static const char *mux_clk_m[] = {
+	"clk_m",
+};
+
+static struct clk *mux_clk_m_p[] = {
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_out3[] = {
+	"pll_p_out3",
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+	&tegra_pll_p_out3,
+};
+
+static const char *mux_plld[] = {
+	"pll_d",
+};
+
+static struct clk *mux_plld_p[] = {
+	&tegra_pll_d,
+};
+
+static const char *mux_clk_32k[] = {
+	"clk_32k",
+};
+
+static struct clk *mux_clk_32k_p[] = {
+	&tegra_clk_32k,
+};
+
+static const char *mux_pclk[] = {
+	"pclk",
+};
+
+static struct clk *mux_pclk_p[] = {
+	&tegra_pclk,
+};
+
+static struct clk tegra_emc;
+static struct clk_tegra tegra_emc_hw = {
+	.hw = {
+		.clk = &tegra_emc,
+	},
+	.reg = 0x19c,
+	.max_rate = 800000000,
+	.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
+	.reset = &tegra2_periph_clk_reset,
+	.u.periph = {
+		.clk_num = 57,
+	},
+};
+DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm,
+		mux_pllm_pllc_pllp_clkm_p, NULL);
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg,	\
+		_max, _inputs, _flags) 			\
+	static struct clk tegra_##_name;		\
+	static struct clk_tegra tegra_##_name##_hw = {	\
+		.hw = {					\
+			.clk = &tegra_##_name,		\
+		},					\
+		.lookup = {				\
+			.dev_id = _dev,			\
+			.con_id = _con,			\
+		},					\
+		.reg = _reg,				\
+		.flags = _flags,			\
+		.max_rate = _max,			\
+		.u.periph = {				\
+			.clk_num = _clk_num,		\
+		},					\
+		.reset = tegra2_periph_clk_reset,	\
+	};						\
+	static struct clk tegra_##_name = {		\
+		.name = #_name,				\
+		.ops = &tegra_periph_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,		\
+		.parent_names = _inputs,		\
+		.parents = _inputs##_p,			\
+		.num_parents = ARRAY_SIZE(_inputs),	\
+	};
+
+PERIPH_CLK(apbdma,	"tegra-apbdma",		NULL,	34,	0,	108000000, mux_pclk,			0);
+PERIPH_CLK(rtc,		"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET);
+PERIPH_CLK(timer,	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(i2s1,	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(i2s2,	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(spdif_out,	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(spdif_in,	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71);
+PERIPH_CLK(pwm,		"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | MUX_PWM);
+PERIPH_CLK(spi,		"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(xio,		"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(twc,		"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc1,	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc2,	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc3,	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc4,	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(ide,		"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(ndflash,	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vfir,	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sdmmc1,	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2,	"sdhci-tegra.1",	NULL,	9,	0x154,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3,	"sdhci-tegra.2",	NULL,	69,	0x1bc,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4,	"sdhci-tegra.3",	NULL,	15,	0x164,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp,		"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsea,	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsev,	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(vde,		"tegra-avp",		"vde",	61,	0x1c8,	250000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(csite,	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* max rate ??? */
+/* FIXME: what is la? */
+PERIPH_CLK(la,		"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(owr,		"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(nor,		"nor",			NULL,	42,	0x1d0,	92000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(mipi,	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(i2c1,	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(i2c2,	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(i2c3,	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(dvc,		"tegra-i2c.3",		NULL,	47,	0x128,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(i2c1_i2c,	"tegra-i2c.0",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0);
+PERIPH_CLK(i2c2_i2c,	"tegra-i2c.1",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0);
+PERIPH_CLK(i2c3_i2c,	"tegra-i2c.2",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0);
+PERIPH_CLK(dvc_i2c,	"tegra-i2c.3",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0);
+PERIPH_CLK(uarta,	"tegra-uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartb,	"tegra-uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartc,	"tegra-uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartd,	"tegra-uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uarte,	"tegra-uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(3d,		"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(2d,		"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi,		"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi_sensor,	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(epp,		"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(mpe,		"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(host1x,	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(cve,		"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo,		"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(hdmi,	"hdmi",			NULL,	51,	0x18c,	600000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvdac,	"tvdac",		NULL,	53,	0x194,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1,	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_plld_pllc_clkm,	MUX); /* scales with voltage and process_id */
+PERIPH_CLK(disp2,	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_plld_pllc_clkm,	MUX); /* scales with voltage and process_id */
+PERIPH_CLK(usbd,	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb2,	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb3,	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(dsi,		"dsi",			NULL,	48,	0,	500000000, mux_plld,			0); /* scales with voltage */
+PERIPH_CLK(csi,		"tegra_camera",		"csi",	52,	0,	72000000,  mux_pllp_out3,		0);
+PERIPH_CLK(isp,		"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0); /* same frequency as VI */
+PERIPH_CLK(csus,	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET);
+PERIPH_CLK(pex,		NULL,			"pex",  70,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+PERIPH_CLK(afi,		NULL,			"afi",  72,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+PERIPH_CLK(pcie_xclk,	NULL,		  "pcie_xclk",  74,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+
+static struct clk *tegra_list_clks[] = {
+	&tegra_apbdma,
+	&tegra_rtc,
+	&tegra_i2s1,
+	&tegra_i2s2,
+	&tegra_spdif_out,
+	&tegra_spdif_in,
+	&tegra_pwm,
+	&tegra_spi,
+	&tegra_xio,
+	&tegra_twc,
+	&tegra_sbc1,
+	&tegra_sbc2,
+	&tegra_sbc3,
+	&tegra_sbc4,
+	&tegra_ide,
+	&tegra_ndflash,
+	&tegra_vfir,
+	&tegra_sdmmc1,
+	&tegra_sdmmc2,
+	&tegra_sdmmc3,
+	&tegra_sdmmc4,
+	&tegra_vcp,
+	&tegra_bsea,
+	&tegra_bsev,
+	&tegra_vde,
+	&tegra_csite,
+	&tegra_la,
+	&tegra_owr,
+	&tegra_nor,
+	&tegra_mipi,
+	&tegra_i2c1,
+	&tegra_i2c2,
+	&tegra_i2c3,
+	&tegra_dvc,
+	&tegra_i2c1_i2c,
+	&tegra_i2c2_i2c,
+	&tegra_i2c3_i2c,
+	&tegra_dvc_i2c,
+	&tegra_uarta,
+	&tegra_uartb,
+	&tegra_uartc,
+	&tegra_uartd,
+	&tegra_uarte,
+	&tegra_3d,
+	&tegra_2d,
+	&tegra_vi,
+	&tegra_vi_sensor,
+	&tegra_epp,
+	&tegra_mpe,
+	&tegra_host1x,
+	&tegra_cve,
+	&tegra_tvo,
+	&tegra_hdmi,
+	&tegra_tvdac,
+	&tegra_disp1,
+	&tegra_disp2,
+	&tegra_usbd,
+	&tegra_usb2,
+	&tegra_usb3,
+	&tegra_dsi,
+	&tegra_csi,
+	&tegra_isp,
+	&tegra_csus,
+	&tegra_pex,
+	&tegra_afi,
+	&tegra_pcie_xclk,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)	\
+	{					\
+		.name	= _name,		\
+		.lookup	= {			\
+			.dev_id	= _dev,		\
+			.con_id	= _con,		\
+		},				\
+	}
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+static struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("uarta",	"serial8250.0",	NULL),
+	CLK_DUPLICATE("uartb",	"serial8250.1",	NULL),
+	CLK_DUPLICATE("uartc",	"serial8250.2",	NULL),
+	CLK_DUPLICATE("uartd",	"serial8250.3",	NULL),
+	CLK_DUPLICATE("uarte",	"serial8250.4",	NULL),
+	CLK_DUPLICATE("usbd",	"utmip-pad",	NULL),
+	CLK_DUPLICATE("usbd",	"tegra-ehci.0",	NULL),
+	CLK_DUPLICATE("usbd",	"tegra-otg",	NULL),
+	CLK_DUPLICATE("hdmi",	"tegradc.0",	"hdmi"),
+	CLK_DUPLICATE("hdmi",	"tegradc.1",	"hdmi"),
+	CLK_DUPLICATE("host1x",	"tegra_grhost",	"host1x"),
+	CLK_DUPLICATE("2d",	"tegra_grhost",	"gr2d"),
+	CLK_DUPLICATE("3d",	"tegra_grhost",	"gr3d"),
+	CLK_DUPLICATE("epp",	"tegra_grhost",	"epp"),
+	CLK_DUPLICATE("mpe",	"tegra_grhost",	"mpe"),
+	CLK_DUPLICATE("cop",	"tegra-avp",	"cop"),
+	CLK_DUPLICATE("vde",	"tegra-aes",	"vde"),
+	CLK_DUPLICATE("cclk",	NULL,		"cpu"),
+	CLK_DUPLICATE("twd",	"smp_twd",	NULL),
+};
+
+#define CLK(dev, con, ck)	\
+	{			\
+		.dev_id	= dev,	\
+		.con_id	= con,	\
+		.clk	= ck,	\
+	}
+
+static struct clk *tegra_ptr_clks[] = {
+	&tegra_clk_32k,
+	&tegra_pll_s,
+	&tegra_clk_m,
+	&tegra_pll_m,
+	&tegra_pll_m_out1,
+	&tegra_pll_c,
+	&tegra_pll_c_out1,
+	&tegra_pll_p,
+	&tegra_pll_p_out1,
+	&tegra_pll_p_out2,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out4,
+	&tegra_pll_a,
+	&tegra_pll_a_out0,
+	&tegra_pll_d,
+	&tegra_pll_d_out0,
+	&tegra_pll_u,
+	&tegra_pll_x,
+	&tegra_pll_e,
+	&tegra_cclk,
+	&tegra_clk_twd,
+	&tegra_sclk,
+	&tegra_hclk,
+	&tegra_pclk,
+	&tegra_clk_d,
+	&tegra_cdev1,
+	&tegra_cdev2,
+	&tegra_blink,
+	&tegra_cop,
+	&tegra_emc,
+};
+
+static void tegra2_init_one_clock(struct clk *c)
+{
+	struct clk_tegra *clk = to_clk_tegra(c->hw);
+	int ret;
+
+	ret = __clk_init(NULL, c);
+	if (ret)
+		pr_err("clk init failed %s\n", __clk_get_name(c));
+
+	INIT_LIST_HEAD(&clk->shared_bus_list);
+	if (!clk->lookup.dev_id && !clk->lookup.con_id)
+		clk->lookup.con_id = c->name;
+	clk->lookup.clk = c;
+	clkdev_add(&clk->lookup);
+	tegra_clk_add(c);
+}
+
+void __init tegra2_init_clocks(void)
+{
+	int i;
+	struct clk *c;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+		tegra2_init_one_clock(tegra_ptr_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+		tegra2_init_one_clock(tegra_list_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+		if (!c) {
+			pr_err("%s: Unknown duplicate clock %s\n", __func__,
+				tegra_clk_duplicates[i].name);
+			continue;
+		}
+
+		tegra_clk_duplicates[i].lookup.clk = c;
+		clkdev_add(&tegra_clk_duplicates[i].lookup);
+	}
+
+	init_audio_sync_clock_mux();
+	tegra20_cpu_car_ops_init();
+}
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
deleted file mode 100644
index a703844..0000000
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ /dev/null
@@ -1,2484 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_clocks.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/clk.h>
-
-#include <mach/iomap.h>
-#include <mach/suspend.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "tegra2_emc.h"
-
-#define RST_DEVICES			0x004
-#define RST_DEVICES_SET			0x300
-#define RST_DEVICES_CLR			0x304
-#define RST_DEVICES_NUM			3
-
-#define CLK_OUT_ENB			0x010
-#define CLK_OUT_ENB_SET			0x320
-#define CLK_OUT_ENB_CLR			0x324
-#define CLK_OUT_ENB_NUM			3
-
-#define CLK_MASK_ARM			0x44
-#define MISC_CLK_ENB			0x48
-
-#define OSC_CTRL			0x50
-#define OSC_CTRL_OSC_FREQ_MASK		(3<<30)
-#define OSC_CTRL_OSC_FREQ_13MHZ		(0<<30)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ	(1<<30)
-#define OSC_CTRL_OSC_FREQ_12MHZ		(2<<30)
-#define OSC_CTRL_OSC_FREQ_26MHZ		(3<<30)
-#define OSC_CTRL_MASK			(0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_FREQ_DET			0x58
-#define OSC_FREQ_DET_TRIG		(1<<31)
-
-#define OSC_FREQ_DET_STATUS		0x5C
-#define OSC_FREQ_DET_BUSY		(1<<31)
-#define OSC_FREQ_DET_CNT_MASK		0xFFFF
-
-#define PERIPH_CLK_SOURCE_I2S1		0x100
-#define PERIPH_CLK_SOURCE_EMC		0x19c
-#define PERIPH_CLK_SOURCE_OSC		0x1fc
-#define PERIPH_CLK_SOURCE_NUM \
-	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-
-#define PERIPH_CLK_SOURCE_MASK		(3<<30)
-#define PERIPH_CLK_SOURCE_SHIFT		30
-#define PERIPH_CLK_SOURCE_PWM_MASK	(7<<28)
-#define PERIPH_CLK_SOURCE_PWM_SHIFT	28
-#define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
-#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
-#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
-#define PERIPH_CLK_SOURCE_DIV_SHIFT	0
-
-#define SDMMC_CLK_INT_FB_SEL		(1 << 23)
-#define SDMMC_CLK_INT_FB_DLY_SHIFT	16
-#define SDMMC_CLK_INT_FB_DLY_MASK	(0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
-
-#define PLL_BASE			0x0
-#define PLL_BASE_BYPASS			(1<<31)
-#define PLL_BASE_ENABLE			(1<<30)
-#define PLL_BASE_REF_ENABLE		(1<<29)
-#define PLL_BASE_OVERRIDE		(1<<28)
-#define PLL_BASE_DIVP_MASK		(0x7<<20)
-#define PLL_BASE_DIVP_SHIFT		20
-#define PLL_BASE_DIVN_MASK		(0x3FF<<8)
-#define PLL_BASE_DIVN_SHIFT		8
-#define PLL_BASE_DIVM_MASK		(0x1F)
-#define PLL_BASE_DIVM_SHIFT		0
-
-#define PLL_OUT_RATIO_MASK		(0xFF<<8)
-#define PLL_OUT_RATIO_SHIFT		8
-#define PLL_OUT_OVERRIDE		(1<<2)
-#define PLL_OUT_CLKEN			(1<<1)
-#define PLL_OUT_RESET_DISABLE		(1<<0)
-
-#define PLL_MISC(c)			(((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-
-#define PLL_MISC_DCCON_SHIFT		20
-#define PLL_MISC_CPCON_SHIFT		8
-#define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
-#define PLL_MISC_LFCON_SHIFT		4
-#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT)
-#define PLL_MISC_VCOCON_SHIFT		0
-#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
-
-#define PLLU_BASE_POST_DIV		(1<<20)
-
-#define PLLD_MISC_CLKENABLE		(1<<30)
-#define PLLD_MISC_DIV_RST		(1<<23)
-#define PLLD_MISC_DCCON_SHIFT		12
-
-#define PLLE_MISC_READY			(1 << 15)
-
-#define PERIPH_CLK_TO_ENB_REG(c)	((c->u.periph.clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->u.periph.clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->u.periph.clk_num % 32))
-
-#define SUPER_CLK_MUX			0x00
-#define SUPER_STATE_SHIFT		28
-#define SUPER_STATE_MASK		(0xF << SUPER_STATE_SHIFT)
-#define SUPER_STATE_STANDBY		(0x0 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IDLE		(0x1 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_RUN			(0x2 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IRQ			(0x3 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_FIQ			(0x4 << SUPER_STATE_SHIFT)
-#define SUPER_SOURCE_MASK		0xF
-#define	SUPER_FIQ_SOURCE_SHIFT		12
-#define	SUPER_IRQ_SOURCE_SHIFT		8
-#define	SUPER_RUN_SOURCE_SHIFT		4
-#define	SUPER_IDLE_SOURCE_SHIFT		0
-
-#define SUPER_CLK_DIVIDER		0x04
-
-#define BUS_CLK_DISABLE			(1<<3)
-#define BUS_CLK_DIV_MASK		0x3
-
-#define PMC_CTRL			0x0
- #define PMC_CTRL_BLINK_ENB		(1 << 7)
-
-#define PMC_DPD_PADS_ORIDE		0x1c
- #define PMC_DPD_PADS_ORIDE_BLINK_ENB	(1 << 20)
-
-#define PMC_BLINK_TIMER_DATA_ON_SHIFT	0
-#define PMC_BLINK_TIMER_DATA_ON_MASK	0x7fff
-#define PMC_BLINK_TIMER_ENB		(1 << 15)
-#define PMC_BLINK_TIMER_DATA_OFF_SHIFT	16
-#define PMC_BLINK_TIMER_DATA_OFF_MASK	0xffff
-
-static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
-/*
- * Some clocks share a register with other clocks.  Any clock op that
- * non-atomically modifies a register used by another clock must lock
- * clock_register_lock first.
- */
-static DEFINE_SPINLOCK(clock_register_lock);
-
-/*
- * Some peripheral clocks share an enable bit, so refcount the enable bits
- * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
- */
-static int tegra_periph_clk_enable_refcount[3 * 32];
-
-#define clk_writel(value, reg) \
-	__raw_writel(value, reg_clk_base + (reg))
-#define clk_readl(reg) \
-	__raw_readl(reg_clk_base + (reg))
-#define pmc_writel(value, reg) \
-	__raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
-	__raw_readl(reg_pmc_base + (reg))
-
-static unsigned long clk_measure_input_freq(void)
-{
-	u32 clock_autodetect;
-	clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
-	do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
-	clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
-	if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
-		return 12000000;
-	} else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
-		return 13000000;
-	} else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
-		return 19200000;
-	} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
-		return 26000000;
-	} else {
-		pr_err("%s: Unexpected clock autodetect value %d", __func__, clock_autodetect);
-		BUG();
-		return 0;
-	}
-}
-
-static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
-{
-	s64 divider_u71 = parent_rate * 2;
-	divider_u71 += rate - 1;
-	do_div(divider_u71, rate);
-
-	if (divider_u71 - 2 < 0)
-		return 0;
-
-	if (divider_u71 - 2 > 255)
-		return -EINVAL;
-
-	return divider_u71 - 2;
-}
-
-static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
-{
-	s64 divider_u16;
-
-	divider_u16 = parent_rate;
-	divider_u16 += rate - 1;
-	do_div(divider_u16, rate);
-
-	if (divider_u16 - 1 < 0)
-		return 0;
-
-	if (divider_u16 - 1 > 255)
-		return -EINVAL;
-
-	return divider_u16 - 1;
-}
-
-/* clk_m functions */
-static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
-{
-	u32 auto_clock_control = clk_readl(OSC_CTRL) & ~OSC_CTRL_OSC_FREQ_MASK;
-
-	c->rate = clk_measure_input_freq();
-	switch (c->rate) {
-	case 12000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
-		break;
-	case 13000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
-		break;
-	case 19200000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
-		break;
-	case 26000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
-		break;
-	default:
-		pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
-		BUG();
-	}
-	clk_writel(auto_clock_control, OSC_CTRL);
-	return c->rate;
-}
-
-static void tegra2_clk_m_init(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	tegra2_clk_m_autodetect_rate(c);
-}
-
-static int tegra2_clk_m_enable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return 0;
-}
-
-static void tegra2_clk_m_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	BUG();
-}
-
-static struct clk_ops tegra_clk_m_ops = {
-	.init		= tegra2_clk_m_init,
-	.enable		= tegra2_clk_m_enable,
-	.disable	= tegra2_clk_m_disable,
-};
-
-/* super clock functions */
-/* "super clocks" on tegra have two-stage muxes and a clock skipping
- * super divider.  We will ignore the clock skipping divider, since we
- * can't lower the voltage when using the clock skip, but we can if we
- * lower the PLL frequency.
- */
-static void tegra2_super_clk_init(struct clk *c)
-{
-	u32 val;
-	int source;
-	int shift;
-	const struct clk_mux_sel *sel;
-	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	c->state = ON;
-	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
-		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
-	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
-		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	source = (val >> shift) & SUPER_SOURCE_MASK;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->value == source)
-			break;
-	}
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
-}
-
-static int tegra2_super_clk_enable(struct clk *c)
-{
-	clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
-	return 0;
-}
-
-static void tegra2_super_clk_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	/* oops - don't disable the CPU clock! */
-	BUG();
-}
-
-static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	int shift;
-
-	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
-		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
-	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
-		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val &= ~(SUPER_SOURCE_MASK << shift);
-			val |= sel->value << shift;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-/*
- * Super clocks have "clock skippers" instead of dividers.  Dividing using
- * a clock skipper does not allow the voltage to be scaled down, so instead
- * adjust the rate of the parent clock.  This requires that the parent of a
- * super clock have no other children, otherwise the rate will change
- * underneath the other children.
- */
-static int tegra2_super_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	return clk_set_rate(c->parent, rate);
-}
-
-static struct clk_ops tegra_super_ops = {
-	.init			= tegra2_super_clk_init,
-	.enable			= tegra2_super_clk_enable,
-	.disable		= tegra2_super_clk_disable,
-	.set_parent		= tegra2_super_clk_set_parent,
-	.set_rate		= tegra2_super_clk_set_rate,
-};
-
-/* virtual cpu clock functions */
-/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
-   To change the frequency of these clocks, the parent pll may need to be
-   reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
-   and then the clock moved back to the pll.  To hide this sequence, a virtual
-   clock handles it.
- */
-static void tegra2_cpu_clk_init(struct clk *c)
-{
-}
-
-static int tegra2_cpu_clk_enable(struct clk *c)
-{
-	return 0;
-}
-
-static void tegra2_cpu_clk_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	/* oops - don't disable the CPU clock! */
-	BUG();
-}
-
-static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	/*
-	 * Take an extra reference to the main pll so it doesn't turn
-	 * off when we move the cpu off of it
-	 */
-	clk_enable(c->u.cpu.main);
-
-	ret = clk_set_parent(c->parent, c->u.cpu.backup);
-	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
-		goto out;
-	}
-
-	if (rate == clk_get_rate(c->u.cpu.backup))
-		goto out;
-
-	ret = clk_set_rate(c->u.cpu.main, rate);
-	if (ret) {
-		pr_err("Failed to change cpu pll to %lu\n", rate);
-		goto out;
-	}
-
-	ret = clk_set_parent(c->parent, c->u.cpu.main);
-	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
-		goto out;
-	}
-
-out:
-	clk_disable(c->u.cpu.main);
-	return ret;
-}
-
-static struct clk_ops tegra_cpu_ops = {
-	.init     = tegra2_cpu_clk_init,
-	.enable   = tegra2_cpu_clk_enable,
-	.disable  = tegra2_cpu_clk_disable,
-	.set_rate = tegra2_cpu_clk_set_rate,
-};
-
-/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
- * reset the COP block (i.e. AVP) */
-static void tegra2_cop_clk_reset(struct clk *c, bool assert)
-{
-	unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
-	pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
-	clk_writel(1 << 1, reg);
-}
-
-static struct clk_ops tegra_cop_ops = {
-	.reset    = tegra2_cop_clk_reset,
-};
-
-/* bus clock functions */
-static void tegra2_bus_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
-	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
-	c->mul = 1;
-}
-
-static int tegra2_bus_clk_enable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	val &= ~(BUS_CLK_DISABLE << c->reg_shift);
-	clk_writel(val, c->reg);
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return 0;
-}
-
-static void tegra2_bus_clk_disable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	val |= BUS_CLK_DISABLE << c->reg_shift;
-	clk_writel(val, c->reg);
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	unsigned long flags;
-	int ret = -EINVAL;
-	int i;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	for (i = 1; i <= 4; i++) {
-		if (rate == parent_rate / i) {
-			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
-			val |= (i - 1) << c->reg_shift;
-			clk_writel(val, c->reg);
-			c->div = i;
-			c->mul = 1;
-			ret = 0;
-			break;
-		}
-	}
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return ret;
-}
-
-static struct clk_ops tegra_bus_ops = {
-	.init			= tegra2_bus_clk_init,
-	.enable			= tegra2_bus_clk_enable,
-	.disable		= tegra2_bus_clk_disable,
-	.set_rate		= tegra2_bus_clk_set_rate,
-};
-
-/* Blink output functions */
-
-static void tegra2_blink_clk_init(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_CTRL);
-	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
-	c->mul = 1;
-	val = pmc_readl(c->reg);
-
-	if (val & PMC_BLINK_TIMER_ENB) {
-		unsigned int on_off;
-
-		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
-			PMC_BLINK_TIMER_DATA_ON_MASK;
-		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off += val;
-		/* each tick in the blink timer is 4 32KHz clocks */
-		c->div = on_off * 4;
-	} else {
-		c->div = 1;
-	}
-}
-
-static int tegra2_blink_clk_enable(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_DPD_PADS_ORIDE);
-	pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-
-	val = pmc_readl(PMC_CTRL);
-	pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
-	return 0;
-}
-
-static void tegra2_blink_clk_disable(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_CTRL);
-	pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
-	val = pmc_readl(PMC_DPD_PADS_ORIDE);
-	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-}
-
-static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	if (rate >= parent_rate) {
-		c->div = 1;
-		pmc_writel(0, c->reg);
-	} else {
-		unsigned int on_off;
-		u32 val;
-
-		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
-		c->div = on_off * 8;
-
-		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
-			PMC_BLINK_TIMER_DATA_ON_SHIFT;
-		on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val |= on_off;
-		val |= PMC_BLINK_TIMER_ENB;
-		pmc_writel(val, c->reg);
-	}
-
-	return 0;
-}
-
-static struct clk_ops tegra_blink_clk_ops = {
-	.init			= &tegra2_blink_clk_init,
-	.enable			= &tegra2_blink_clk_enable,
-	.disable		= &tegra2_blink_clk_disable,
-	.set_rate		= &tegra2_blink_clk_set_rate,
-};
-
-/* PLL Functions */
-static int tegra2_pll_clk_wait_for_lock(struct clk *c)
-{
-	udelay(c->u.pll.lock_delay);
-
-	return 0;
-}
-
-static void tegra2_pll_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg + PLL_BASE);
-
-	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
-
-	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
-		pr_warning("Clock %s has unknown fixed frequency\n", c->name);
-		c->mul = 1;
-		c->div = 1;
-	} else if (val & PLL_BASE_BYPASS) {
-		c->mul = 1;
-		c->div = 1;
-	} else {
-		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-		if (c->flags & PLLU)
-			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
-		else
-			c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
-	}
-}
-
-static int tegra2_pll_clk_enable(struct clk *c)
-{
-	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	val = clk_readl(c->reg + PLL_BASE);
-	val &= ~PLL_BASE_BYPASS;
-	val |= PLL_BASE_ENABLE;
-	clk_writel(val, c->reg + PLL_BASE);
-
-	tegra2_pll_clk_wait_for_lock(c);
-
-	return 0;
-}
-
-static void tegra2_pll_clk_disable(struct clk *c)
-{
-	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	val = clk_readl(c->reg);
-	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
-	clk_writel(val, c->reg);
-}
-
-static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	unsigned long input_rate;
-	const struct clk_pll_freq_table *sel;
-
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	input_rate = clk_get_rate(c->parent);
-	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
-		if (sel->input_rate == input_rate && sel->output_rate == rate) {
-			c->mul = sel->n;
-			c->div = sel->m * sel->p;
-
-			val = clk_readl(c->reg + PLL_BASE);
-			if (c->flags & PLL_FIXED)
-				val |= PLL_BASE_OVERRIDE;
-			val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
-				 PLL_BASE_DIVM_MASK);
-			val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
-				(sel->n << PLL_BASE_DIVN_SHIFT);
-			BUG_ON(sel->p < 1 || sel->p > 2);
-			if (c->flags & PLLU) {
-				if (sel->p == 1)
-					val |= PLLU_BASE_POST_DIV;
-			} else {
-				if (sel->p == 2)
-					val |= 1 << PLL_BASE_DIVP_SHIFT;
-			}
-			clk_writel(val, c->reg + PLL_BASE);
-
-			if (c->flags & PLL_HAS_CPCON) {
-				val = clk_readl(c->reg + PLL_MISC(c));
-				val &= ~PLL_MISC_CPCON_MASK;
-				val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
-				clk_writel(val, c->reg + PLL_MISC(c));
-			}
-
-			if (c->state == ON)
-				tegra2_pll_clk_enable(c);
-
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_ops = {
-	.init			= tegra2_pll_clk_init,
-	.enable			= tegra2_pll_clk_enable,
-	.disable		= tegra2_pll_clk_disable,
-	.set_rate		= tegra2_pll_clk_set_rate,
-};
-
-static void tegra2_pllx_clk_init(struct clk *c)
-{
-	tegra2_pll_clk_init(c);
-
-	if (tegra_sku_id == 7)
-		c->max_rate = 750000000;
-}
-
-static struct clk_ops tegra_pllx_ops = {
-	.init     = tegra2_pllx_clk_init,
-	.enable   = tegra2_pll_clk_enable,
-	.disable  = tegra2_pll_clk_disable,
-	.set_rate = tegra2_pll_clk_set_rate,
-};
-
-static int tegra2_plle_clk_enable(struct clk *c)
-{
-	u32 val;
-
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	mdelay(1);
-
-	val = clk_readl(c->reg + PLL_BASE);
-	if (!(val & PLLE_MISC_READY))
-		return -EBUSY;
-
-	val = clk_readl(c->reg + PLL_BASE);
-	val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
-	clk_writel(val, c->reg + PLL_BASE);
-
-	return 0;
-}
-
-static struct clk_ops tegra_plle_ops = {
-	.init       = tegra2_pll_clk_init,
-	.enable     = tegra2_plle_clk_enable,
-	.set_rate   = tegra2_pll_clk_set_rate,
-};
-
-/* Clock divider ops */
-static void tegra2_pll_div_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	u32 divu71;
-	val >>= c->reg_shift;
-	c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
-	if (!(val & PLL_OUT_RESET_DISABLE))
-		c->state = OFF;
-
-	if (c->flags & DIV_U71) {
-		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
-		c->div = (divu71 + 2);
-		c->mul = 2;
-	} else if (c->flags & DIV_2) {
-		c->div = 2;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
-}
-
-static int tegra2_pll_div_clk_enable(struct clk *c)
-{
-	u32 val;
-	u32 new_val;
-	unsigned long flags;
-
-	pr_debug("%s: %s\n", __func__, c->name);
-	if (c->flags & DIV_U71) {
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		new_val = val >> c->reg_shift;
-		new_val &= 0xFFFF;
-
-		new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
-
-		val &= ~(0xFFFF << c->reg_shift);
-		val |= new_val << c->reg_shift;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-		return 0;
-	} else if (c->flags & DIV_2) {
-		BUG_ON(!(c->flags & PLLD));
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		val &= ~PLLD_MISC_DIV_RST;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static void tegra2_pll_div_clk_disable(struct clk *c)
-{
-	u32 val;
-	u32 new_val;
-	unsigned long flags;
-
-	pr_debug("%s: %s\n", __func__, c->name);
-	if (c->flags & DIV_U71) {
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		new_val = val >> c->reg_shift;
-		new_val &= 0xFFFF;
-
-		new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
-
-		val &= ~(0xFFFF << c->reg_shift);
-		val |= new_val << c->reg_shift;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-	} else if (c->flags & DIV_2) {
-		BUG_ON(!(c->flags & PLLD));
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		val |= PLLD_MISC_DIV_RST;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-	}
-}
-
-static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	u32 new_val;
-	int divider_u71;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	unsigned long flags;
-
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-	if (c->flags & DIV_U71) {
-		divider_u71 = clk_div71_get_divider(parent_rate, rate);
-		if (divider_u71 >= 0) {
-			spin_lock_irqsave(&clock_register_lock, flags);
-			val = clk_readl(c->reg);
-			new_val = val >> c->reg_shift;
-			new_val &= 0xFFFF;
-			if (c->flags & DIV_U71_FIXED)
-				new_val |= PLL_OUT_OVERRIDE;
-			new_val &= ~PLL_OUT_RATIO_MASK;
-			new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
-
-			val &= ~(0xFFFF << c->reg_shift);
-			val |= new_val << c->reg_shift;
-			clk_writel(val, c->reg);
-			c->div = divider_u71 + 2;
-			c->mul = 2;
-			spin_unlock_irqrestore(&clock_register_lock, flags);
-			return 0;
-		}
-	} else if (c->flags & DIV_2) {
-		if (parent_rate == rate * 2)
-			return 0;
-	}
-	return -EINVAL;
-}
-
-static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
-{
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_2) {
-		return DIV_ROUND_UP(parent_rate, 2);
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_div_ops = {
-	.init			= tegra2_pll_div_clk_init,
-	.enable			= tegra2_pll_div_clk_enable,
-	.disable		= tegra2_pll_div_clk_disable,
-	.set_rate		= tegra2_pll_div_clk_set_rate,
-	.round_rate		= tegra2_pll_div_clk_round_rate,
-};
-
-/* Periph clk ops */
-
-static void tegra2_periph_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	const struct clk_mux_sel *mux = NULL;
-	const struct clk_mux_sel *sel;
-	u32 shift;
-	u32 mask;
-
-	if (c->flags & MUX_PWM) {
-		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
-		mask = PERIPH_CLK_SOURCE_PWM_MASK;
-	} else {
-		shift = PERIPH_CLK_SOURCE_SHIFT;
-		mask = PERIPH_CLK_SOURCE_MASK;
-	}
-
-	if (c->flags & MUX) {
-		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if ((val & mask) >> shift == sel->value)
-				mux = sel;
-		}
-		BUG_ON(!mux);
-
-		c->parent = mux->input;
-	} else {
-		c->parent = c->inputs[0].input;
-	}
-
-	if (c->flags & DIV_U71) {
-		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
-		c->div = divu71 + 2;
-		c->mul = 2;
-	} else if (c->flags & DIV_U16) {
-		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
-		c->div = divu16 + 1;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
-
-	c->state = ON;
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-
-	if (!(c->flags & PERIPH_NO_RESET))
-		if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
-				PERIPH_CLK_TO_ENB_BIT(c))
-			c->state = OFF;
-}
-
-static int tegra2_periph_clk_enable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-	int refcount;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	if (!c->u.periph.clk_num)
-		return 0;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
-
-	if (refcount > 1)
-		goto out;
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
-	if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-	if (c->flags & PERIPH_EMC_ENB) {
-		/* The EMC peripheral clock has 2 extra enable bits */
-		/* FIXME: Do they need to be disabled? */
-		val = clk_readl(c->reg);
-		val |= 0x3 << 24;
-		clk_writel(val, c->reg);
-	}
-
-out:
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return 0;
-}
-
-static void tegra2_periph_clk_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	if (c->refcnt)
-		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
-
-	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static void tegra2_periph_clk_reset(struct clk *c, bool assert)
-{
-	unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
-	pr_debug("%s %s on clock %s\n", __func__,
-		 assert ? "assert" : "deassert", c->name);
-
-	BUG_ON(!c->u.periph.clk_num);
-
-	if (!(c->flags & PERIPH_NO_RESET))
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			   base + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	u32 mask, shift;
-
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
-	if (c->flags & MUX_PWM) {
-		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
-		mask = PERIPH_CLK_SOURCE_PWM_MASK;
-	} else {
-		shift = PERIPH_CLK_SOURCE_SHIFT;
-		mask = PERIPH_CLK_SOURCE_MASK;
-	}
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~mask;
-			val |= (sel->value) << shift;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider >= 0) {
-			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
-			val |= divider;
-			clk_writel(val, c->reg);
-			c->div = divider + 2;
-			c->mul = 2;
-			return 0;
-		}
-	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(parent_rate, rate);
-		if (divider >= 0) {
-			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
-			val |= divider;
-			clk_writel(val, c->reg);
-			c->div = divider + 1;
-			c->mul = 1;
-			return 0;
-		}
-	} else if (parent_rate <= rate) {
-		c->div = 1;
-		c->mul = 1;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static long tegra2_periph_clk_round_rate(struct clk *c,
-	unsigned long rate)
-{
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-
-		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-		return DIV_ROUND_UP(parent_rate, divider + 1);
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_periph_clk_ops = {
-	.init			= &tegra2_periph_clk_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_parent		= &tegra2_periph_clk_set_parent,
-	.set_rate		= &tegra2_periph_clk_set_rate,
-	.round_rate		= &tegra2_periph_clk_round_rate,
-	.reset			= &tegra2_periph_clk_reset,
-};
-
-/* The SDMMC controllers have extra bits in the clock source register that
- * adjust the delay between the clock and data to compenstate for delays
- * on the PCB. */
-void tegra2_sdmmc_tap_delay(struct clk *c, int delay)
-{
-	u32 reg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	delay = clamp(delay, 0, 15);
-	reg = clk_readl(c->reg);
-	reg &= ~SDMMC_CLK_INT_FB_DLY_MASK;
-	reg |= SDMMC_CLK_INT_FB_SEL;
-	reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT;
-	clk_writel(reg, c->reg);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-}
-
-/* External memory controller clock ops */
-static void tegra2_emc_clk_init(struct clk *c)
-{
-	tegra2_periph_clk_init(c);
-	c->max_rate = clk_get_rate_locked(c);
-}
-
-static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
-{
-	long emc_rate;
-	long clk_rate;
-
-	/*
-	 * The slowest entry in the EMC clock table that is at least as
-	 * fast as rate.
-	 */
-	emc_rate = tegra_emc_round_rate(rate);
-	if (emc_rate < 0)
-		return c->max_rate;
-
-	/*
-	 * The fastest rate the PLL will generate that is at most the
-	 * requested rate.
-	 */
-	clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
-
-	/*
-	 * If this fails, and emc_rate > clk_rate, it's because the maximum
-	 * rate in the EMC tables is larger than the maximum rate of the EMC
-	 * clock. The EMC clock's max rate is the rate it was running when the
-	 * kernel booted. Such a mismatch is probably due to using the wrong
-	 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
-	 */
-	WARN_ONCE(emc_rate != clk_rate,
-		"emc_rate %ld != clk_rate %ld",
-		emc_rate, clk_rate);
-
-	return emc_rate;
-}
-
-static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	/*
-	 * The Tegra2 memory controller has an interlock with the clock
-	 * block that allows memory shadowed registers to be updated,
-	 * and then transfer them to the main registers at the same
-	 * time as the clock update without glitches.
-	 */
-	ret = tegra_emc_set_rate(rate);
-	if (ret < 0)
-		return ret;
-
-	ret = tegra2_periph_clk_set_rate(c, rate);
-	udelay(1);
-
-	return ret;
-}
-
-static struct clk_ops tegra_emc_clk_ops = {
-	.init			= &tegra2_emc_clk_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_parent		= &tegra2_periph_clk_set_parent,
-	.set_rate		= &tegra2_emc_clk_set_rate,
-	.round_rate		= &tegra2_emc_clk_round_rate,
-	.reset			= &tegra2_periph_clk_reset,
-};
-
-/* Clock doubler ops */
-static void tegra2_clk_double_init(struct clk *c)
-{
-	c->mul = 2;
-	c->div = 1;
-	c->state = ON;
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-};
-
-static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
-{
-	if (rate != 2 * clk_get_rate(c->parent))
-		return -EINVAL;
-	c->mul = 2;
-	c->div = 1;
-	return 0;
-}
-
-static struct clk_ops tegra_clk_double_ops = {
-	.init			= &tegra2_clk_double_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_rate		= &tegra2_clk_double_set_rate,
-};
-
-/* Audio sync clock ops */
-static void tegra2_audio_sync_clk_init(struct clk *c)
-{
-	int source;
-	const struct clk_mux_sel *sel;
-	u32 val = clk_readl(c->reg);
-	c->state = (val & (1<<4)) ? OFF : ON;
-	source = val & 0xf;
-	for (sel = c->inputs; sel->input != NULL; sel++)
-		if (sel->value == source)
-			break;
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
-}
-
-static int tegra2_audio_sync_clk_enable(struct clk *c)
-{
-	clk_writel(0, c->reg);
-	return 0;
-}
-
-static void tegra2_audio_sync_clk_disable(struct clk *c)
-{
-	clk_writel(1, c->reg);
-}
-
-static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~0xf;
-			val |= sel->value;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_audio_sync_clk_ops = {
-	.init       = tegra2_audio_sync_clk_init,
-	.enable     = tegra2_audio_sync_clk_enable,
-	.disable    = tegra2_audio_sync_clk_disable,
-	.set_parent = tegra2_audio_sync_clk_set_parent,
-};
-
-/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
-
-static void tegra2_cdev_clk_init(struct clk *c)
-{
-	/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
-	 * currently done in the pinmux code. */
-	c->state = ON;
-
-	BUG_ON(!c->u.periph.clk_num);
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-}
-
-static int tegra2_cdev_clk_enable(struct clk *c)
-{
-	BUG_ON(!c->u.periph.clk_num);
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
-	return 0;
-}
-
-static void tegra2_cdev_clk_disable(struct clk *c)
-{
-	BUG_ON(!c->u.periph.clk_num);
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static struct clk_ops tegra_cdev_clk_ops = {
-	.init			= &tegra2_cdev_clk_init,
-	.enable			= &tegra2_cdev_clk_enable,
-	.disable		= &tegra2_cdev_clk_disable,
-};
-
-/* shared bus ops */
-/*
- * Some clocks may have multiple downstream users that need to request a
- * higher clock rate.  Shared bus clocks provide a unique shared_bus_user
- * clock to each user.  The frequency of the bus is set to the highest
- * enabled shared_bus_user clock, with a minimum value set by the
- * shared bus.
- */
-static int tegra_clk_shared_bus_update(struct clk *bus)
-{
-	struct clk *c;
-	unsigned long rate = bus->min_rate;
-
-	list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
-		if (c->u.shared_bus_user.enabled)
-			rate = max(c->u.shared_bus_user.rate, rate);
-
-	if (rate == clk_get_rate_locked(bus))
-		return 0;
-
-	return clk_set_rate_locked(bus, rate);
-};
-
-static void tegra_clk_shared_bus_init(struct clk *c)
-{
-	unsigned long flags;
-
-	c->max_rate = c->parent->max_rate;
-	c->u.shared_bus_user.rate = c->parent->max_rate;
-	c->state = OFF;
-	c->set = true;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	list_add_tail(&c->u.shared_bus_user.node,
-		&c->parent->shared_bus_list);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long flags;
-	int ret;
-	long new_rate = rate;
-
-	new_rate = clk_round_rate(c->parent, new_rate);
-	if (new_rate < 0)
-		return new_rate;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.rate = new_rate;
-	ret = tegra_clk_shared_bus_update(c->parent);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
-	return ret;
-}
-
-static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
-{
-	return clk_round_rate(c->parent, rate);
-}
-
-static int tegra_clk_shared_bus_enable(struct clk *c)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.enabled = true;
-	ret = tegra_clk_shared_bus_update(c->parent);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
-	return ret;
-}
-
-static void tegra_clk_shared_bus_disable(struct clk *c)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.enabled = false;
-	ret = tegra_clk_shared_bus_update(c->parent);
-	WARN_ON_ONCE(ret);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static struct clk_ops tegra_clk_shared_bus_ops = {
-	.init = tegra_clk_shared_bus_init,
-	.enable = tegra_clk_shared_bus_enable,
-	.disable = tegra_clk_shared_bus_disable,
-	.set_rate = tegra_clk_shared_bus_set_rate,
-	.round_rate = tegra_clk_shared_bus_round_rate,
-};
-
-
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
-	.name = "clk_32k",
-	.rate = 32768,
-	.ops  = NULL,
-	.max_rate = 32768,
-};
-
-static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
-	{32768, 12000000, 366, 1, 1, 0},
-	{32768, 13000000, 397, 1, 1, 0},
-	{32768, 19200000, 586, 1, 1, 0},
-	{32768, 26000000, 793, 1, 1, 0},
-	{0, 0, 0, 0, 0, 0},
-};
-
-static struct clk tegra_pll_s = {
-	.name      = "pll_s",
-	.flags     = PLL_ALT_MISC_REG,
-	.ops       = &tegra_pll_ops,
-	.parent    = &tegra_clk_32k,
-	.max_rate  = 26000000,
-	.reg       = 0xf0,
-	.u.pll = {
-		.input_min = 32768,
-		.input_max = 32768,
-		.cf_min    = 0, /* FIXME */
-		.cf_max    = 0, /* FIXME */
-		.vco_min   = 12000000,
-		.vco_max   = 26000000,
-		.freq_table = tegra_pll_s_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk_mux_sel tegra_clk_m_sel[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ .input = &tegra_pll_s,  .value = 1},
-	{ NULL , 0},
-};
-
-static struct clk tegra_clk_m = {
-	.name      = "clk_m",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_clk_m_ops,
-	.inputs    = tegra_clk_m_sel,
-	.reg       = 0x1fc,
-	.reg_shift = 28,
-	.max_rate  = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
-	{ 12000000, 600000000, 600, 12, 1, 8 },
-	{ 13000000, 600000000, 600, 13, 1, 8 },
-	{ 19200000, 600000000, 500, 16, 1, 6 },
-	{ 26000000, 600000000, 600, 26, 1, 8 },
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
-	.name      = "pll_c",
-	.flags	   = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x80,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 600000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_c_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_c_out1 = {
-	.name      = "pll_c_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_c,
-	.reg       = 0x84,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 1, 8},
-	{ 13000000, 666000000, 666, 13, 1, 8},
-	{ 19200000, 666000000, 555, 16, 1, 8},
-	{ 26000000, 666000000, 666, 26, 1, 8},
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
-	.name      = "pll_m",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x90,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 800000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_m_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_m_out1 = {
-	.name      = "pll_m_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_m,
-	.reg       = 0x94,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 2, 8},
-	{ 13000000, 216000000, 432, 13, 2, 8},
-	{ 19200000, 216000000, 90,   4, 2, 1},
-	{ 26000000, 216000000, 432, 26, 2, 8},
-	{ 12000000, 432000000, 432, 12, 1, 8},
-	{ 13000000, 432000000, 432, 13, 1, 8},
-	{ 19200000, 432000000, 90,   4, 1, 1},
-	{ 26000000, 432000000, 432, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
-	.name      = "pll_p",
-	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xa0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 432000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_p_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_p_out1 = {
-	.name      = "pll_p_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
-	.name      = "pll_p_out2",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
-	.name      = "pll_p_out3",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
-	.name      = "pll_p_out4",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
-	{ 28800000, 56448000, 49, 25, 1, 1},
-	{ 28800000, 73728000, 64, 25, 1, 1},
-	{ 28800000, 24000000,  5,  6, 1, 1},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
-	.name      = "pll_a",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xb0,
-	.parent    = &tegra_pll_p_out1,
-	.max_rate  = 73728000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_a_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_a_out0 = {
-	.name      = "pll_a_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_a,
-	.reg       = 0xb4,
-	.reg_shift = 0,
-	.max_rate  = 73728000,
-};
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 1, 4},
-	{ 13000000, 216000000, 216, 13, 1, 4},
-	{ 19200000, 216000000, 135, 12, 1, 3},
-	{ 26000000, 216000000, 216, 26, 1, 4},
-
-	{ 12000000, 594000000, 594, 12, 1, 8},
-	{ 13000000, 594000000, 594, 13, 1, 8},
-	{ 19200000, 594000000, 495, 16, 1, 8},
-	{ 26000000, 594000000, 594, 26, 1, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
-	.name      = "pll_d",
-	.flags     = PLL_HAS_CPCON | PLLD,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xd0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d_out0 = {
-	.name      = "pll_d_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d,
-	.max_rate  = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 2, 0},
-	{ 13000000, 480000000, 960, 13, 2, 0},
-	{ 19200000, 480000000, 200, 4,  2, 0},
-	{ 26000000, 480000000, 960, 26, 2, 0},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
-	.name      = "pll_u",
-	.flags     = PLLU,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xc0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 480000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 480000000,
-		.vco_max   = 960000000,
-		.freq_table = tegra_pll_u_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
-	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	/* 912 MHz */
-	{ 12000000, 912000000,  912,  12, 1, 12},
-	{ 13000000, 912000000,  912,  13, 1, 12},
-	{ 19200000, 912000000,  760,  16, 1, 8},
-	{ 26000000, 912000000,  912,  26, 1, 12},
-
-	/* 816 MHz */
-	{ 12000000, 816000000,  816,  12, 1, 12},
-	{ 13000000, 816000000,  816,  13, 1, 12},
-	{ 19200000, 816000000,  680,  16, 1, 8},
-	{ 26000000, 816000000,  816,  26, 1, 12},
-
-	/* 760 MHz */
-	{ 12000000, 760000000,  760,  12, 1, 12},
-	{ 13000000, 760000000,  760,  13, 1, 12},
-	{ 19200000, 760000000,  950,  24, 1, 8},
-	{ 26000000, 760000000,  760,  26, 1, 12},
-
-	/* 750 MHz */
-	{ 12000000, 750000000,  750,  12, 1, 12},
-	{ 13000000, 750000000,  750,  13, 1, 12},
-	{ 19200000, 750000000,  625,  16, 1, 8},
-	{ 26000000, 750000000,  750,  26, 1, 12},
-
-	/* 608 MHz */
-	{ 12000000, 608000000,  608,  12, 1, 12},
-	{ 13000000, 608000000,  608,  13, 1, 12},
-	{ 19200000, 608000000,  380,  12, 1, 8},
-	{ 26000000, 608000000,  608,  26, 1, 12},
-
-	/* 456 MHz */
-	{ 12000000, 456000000,  456,  12, 1, 12},
-	{ 13000000, 456000000,  456,  13, 1, 12},
-	{ 19200000, 456000000,  380,  16, 1, 8},
-	{ 26000000, 456000000,  456,  26, 1, 12},
-
-	/* 312 MHz */
-	{ 12000000, 312000000,  312,  12, 1, 12},
-	{ 13000000, 312000000,  312,  13, 1, 12},
-	{ 19200000, 312000000,  260,  16, 1, 8},
-	{ 26000000, 312000000,  312,  26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
-	.name      = "pll_x",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
-	.ops       = &tegra_pllx_ops,
-	.reg       = 0xe0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_x_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
-	{ 12000000, 100000000,  200,  24, 1, 0 },
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
-	.name      = "pll_e",
-	.flags	   = PLL_ALT_MISC_REG,
-	.ops       = &tegra_plle_ops,
-	.parent    = &tegra_clk_m,
-	.reg       = 0xe8,
-	.max_rate  = 100000000,
-	.u.pll = {
-		.input_min = 12000000,
-		.input_max = 12000000,
-		.freq_table = tegra_pll_e_freq_table,
-	},
-};
-
-static struct clk tegra_clk_d = {
-	.name      = "clk_d",
-	.flags     = PERIPH_NO_RESET,
-	.ops       = &tegra_clk_double_ops,
-	.reg       = 0x34,
-	.reg_shift = 12,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 52000000,
-	.u.periph  = {
-		.clk_num = 90,
-	},
-};
-
-/* dap_mclk1, belongs to the cdev1 pingroup. */
-static struct clk tegra_clk_cdev1 = {
-	.name      = "cdev1",
-	.ops       = &tegra_cdev_clk_ops,
-	.rate      = 26000000,
-	.max_rate  = 26000000,
-	.u.periph  = {
-		.clk_num = 94,
-	},
-};
-
-/* dap_mclk2, belongs to the cdev2 pingroup. */
-static struct clk tegra_clk_cdev2 = {
-	.name      = "cdev2",
-	.ops       = &tegra_cdev_clk_ops,
-	.rate      = 26000000,
-	.max_rate  = 26000000,
-	.u.periph  = {
-		.clk_num   = 93,
-	},
-};
-
-/* initialized before peripheral clocks */
-static struct clk_mux_sel mux_audio_sync_clk[8+1];
-static const struct audio_sources {
-	const char *name;
-	int value;
-} mux_audio_sync_clk_sources[] = {
-	{ .name = "spdif_in", .value = 0 },
-	{ .name = "i2s1", .value = 1 },
-	{ .name = "i2s2", .value = 2 },
-	{ .name = "pll_a_out0", .value = 4 },
-#if 0 /* FIXME: not implemented */
-	{ .name = "ac97", .value = 3 },
-	{ .name = "ext_audio_clk2", .value = 5 },
-	{ .name = "ext_audio_clk1", .value = 6 },
-	{ .name = "ext_vimclk", .value = 7 },
-#endif
-	{ NULL, 0 }
-};
-
-static struct clk tegra_clk_audio = {
-	.name      = "audio",
-	.inputs    = mux_audio_sync_clk,
-	.reg       = 0x38,
-	.max_rate  = 73728000,
-	.ops       = &tegra_audio_sync_clk_ops
-};
-
-static struct clk tegra_clk_audio_2x = {
-	.name      = "audio_2x",
-	.flags     = PERIPH_NO_RESET,
-	.max_rate  = 48000000,
-	.ops       = &tegra_clk_double_ops,
-	.reg       = 0x34,
-	.reg_shift = 8,
-	.parent    = &tegra_clk_audio,
-	.u.periph = {
-		.clk_num = 89,
-	},
-};
-
-static struct clk_lookup tegra_audio_clk_lookups[] = {
-	{ .con_id = "audio", .clk = &tegra_clk_audio },
-	{ .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
-};
-
-/* This is called after peripheral clocks are initialized, as the
- * audio_sync clock depends on some of the peripheral clocks.
- */
-
-static void init_audio_sync_clock_mux(void)
-{
-	int i;
-	struct clk_mux_sel *sel = mux_audio_sync_clk;
-	const struct audio_sources *src = mux_audio_sync_clk_sources;
-	struct clk_lookup *lookup;
-
-	for (i = 0; src->name; i++, sel++, src++) {
-		sel->input = tegra_get_clock_by_name(src->name);
-		if (!sel->input)
-			pr_err("%s: could not find clk %s\n", __func__,
-				src->name);
-		sel->value = src->value;
-	}
-
-	lookup = tegra_audio_clk_lookups;
-	for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
-		clk_init(lookup->clk);
-		clkdev_add(lookup);
-	}
-}
-
-static struct clk_mux_sel mux_cclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c,	.value = 1},
-	{ .input = &tegra_clk_32k,	.value = 2},
-	{ .input = &tegra_pll_m,	.value = 3},
-	{ .input = &tegra_pll_p,	.value = 4},
-	{ .input = &tegra_pll_p_out4,	.value = 5},
-	{ .input = &tegra_pll_p_out3,	.value = 6},
-	{ .input = &tegra_clk_d,	.value = 7},
-	{ .input = &tegra_pll_x,	.value = 8},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_sclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c_out1,	.value = 1},
-	{ .input = &tegra_pll_p_out4,	.value = 2},
-	{ .input = &tegra_pll_p_out3,	.value = 3},
-	{ .input = &tegra_pll_p_out2,	.value = 4},
-	{ .input = &tegra_clk_d,	.value = 5},
-	{ .input = &tegra_clk_32k,	.value = 6},
-	{ .input = &tegra_pll_m_out1,	.value = 7},
-	{ NULL, 0},
-};
-
-static struct clk tegra_clk_cclk = {
-	.name	= "cclk",
-	.inputs	= mux_cclk,
-	.reg	= 0x20,
-	.ops	= &tegra_super_ops,
-	.max_rate = 1000000000,
-};
-
-static struct clk tegra_clk_sclk = {
-	.name	= "sclk",
-	.inputs	= mux_sclk,
-	.reg	= 0x28,
-	.ops	= &tegra_super_ops,
-	.max_rate = 240000000,
-	.min_rate = 120000000,
-};
-
-static struct clk tegra_clk_virtual_cpu = {
-	.name      = "cpu",
-	.parent    = &tegra_clk_cclk,
-	.ops       = &tegra_cpu_ops,
-	.max_rate  = 1000000000,
-	.u.cpu = {
-		.main      = &tegra_pll_x,
-		.backup    = &tegra_pll_p,
-	},
-};
-
-static struct clk tegra_clk_cop = {
-	.name      = "cop",
-	.parent    = &tegra_clk_sclk,
-	.ops       = &tegra_cop_ops,
-	.max_rate  = 240000000,
-};
-
-static struct clk tegra_clk_hclk = {
-	.name		= "hclk",
-	.flags		= DIV_BUS,
-	.parent		= &tegra_clk_sclk,
-	.reg		= 0x30,
-	.reg_shift	= 4,
-	.ops		= &tegra_bus_ops,
-	.max_rate       = 240000000,
-};
-
-static struct clk tegra_clk_pclk = {
-	.name		= "pclk",
-	.flags		= DIV_BUS,
-	.parent		= &tegra_clk_hclk,
-	.reg		= 0x30,
-	.reg_shift	= 0,
-	.ops		= &tegra_bus_ops,
-	.max_rate       = 120000000,
-};
-
-static struct clk tegra_clk_blink = {
-	.name		= "blink",
-	.parent		= &tegra_clk_32k,
-	.reg		= 0x40,
-	.ops		= &tegra_blink_clk_ops,
-	.max_rate	= 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_pll_a_out0, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_m, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
-	{.input = &tegra_pll_a_out0, .value = 0},
-	{.input = &tegra_clk_audio_2x, .value = 1},
-	{.input = &tegra_pll_p, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_d_out0, .value = 1},
-	{.input = &tegra_pll_c, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_audio,     .value = 2},
-	{.input = &tegra_clk_m,     .value = 3},
-	{.input = &tegra_clk_32k,   .value = 4},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_pll_m,     .value = 2},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
-	{ .input = &tegra_clk_m, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
-	{ .input = &tegra_pll_p_out3, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_plld[] = {
-	{ .input = &tegra_pll_d, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pclk[] = {
-	{ .input = &tegra_clk_pclk, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk tegra_clk_emc = {
-	.name = "emc",
-	.ops = &tegra_emc_clk_ops,
-	.reg = 0x19c,
-	.max_rate = 800000000,
-	.inputs = mux_pllm_pllc_pllp_clkm,
-	.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
-	.u.periph = {
-		.clk_num = 57,
-	},
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = &tegra_periph_clk_ops,	\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define SHARED_CLK(_name, _dev, _con, _parent)		\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id    = _con,		\
-		},					\
-		.ops       = &tegra_clk_shared_bus_ops,	\
-		.parent = _parent,			\
-	}
-
-static struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	108000000, mux_pclk,			0),
-	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
-	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s1",	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2s2",	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
-	PERIPH_CLK("pwm",	"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | MUX_PWM),
-	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("ide",	"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("ndflash",	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x164,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vcp",	"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsea",	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsev",	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("vde",	"tegra-avp",		"vde",	61,	0x1c8,	250000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
-	/* FIXME: what is la? */
-	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	92000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("dvc",	"tegra-i2c.3",		NULL,	47,	0x128,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c1_i2c",	"tegra-i2c.0",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("i2c2_i2c",	"tegra-i2c.1",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("i2c3_i2c",	"tegra-i2c.2",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("dvc_i2c",	"tegra-i2c.3",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
-	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("vi",	"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("vi_sensor",	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
-	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	600000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("disp1",	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_plld_pllc_clkm,	MUX), /* scales with voltage and process_id */
-	PERIPH_CLK("disp2",	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_plld_pllc_clkm,	MUX), /* scales with voltage and process_id */
-	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("dsi",	"dsi",			NULL,	48,	0,	500000000, mux_plld,			0), /* scales with voltage */
-	PERIPH_CLK("csi",	"tegra_camera",		"csi",	52,	0,	72000000,  mux_pllp_out3,		0),
-	PERIPH_CLK("isp",	"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
-	PERIPH_CLK("csus",	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
-	PERIPH_CLK("pex",       NULL,			"pex",  70,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-	PERIPH_CLK("afi",       NULL,			"afi",  72,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-	PERIPH_CLK("pcie_xclk", NULL,		  "pcie_xclk",  74,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-
-	SHARED_CLK("avp.sclk",	"tegra-avp",		"sclk",	&tegra_clk_sclk),
-	SHARED_CLK("avp.emc",	"tegra-avp",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("cpu.emc",	"cpu",			"emc",	&tegra_clk_emc),
-	SHARED_CLK("disp1.emc",	"tegradc.0",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("disp2.emc",	"tegradc.1",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("hdmi.emc",	"hdmi",			"emc",	&tegra_clk_emc),
-	SHARED_CLK("host.emc",	"tegra_grhost",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usbd.emc",	"fsl-tegra-udc",	"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb1.emc",	"tegra-ehci.0",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb2.emc",	"tegra-ehci.1",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb3.emc",	"tegra-ehci.2",		"emc",	&tegra_clk_emc),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con)		\
-	{						\
-		.name	= _name,			\
-		.lookup	= {				\
-			.dev_id	= _dev,			\
-			.con_id		= _con,		\
-		},					\
-	}
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration.  List those here to register them twice in the clock lookup
- * table under two names.
- */
-static struct clk_duplicate tegra_clk_duplicates[] = {
-	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
-	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
-	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
-	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
-	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
-	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
-	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
-	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
-	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
-	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
-	CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
-	CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
-	CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
-	CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
-	CLK_DUPLICATE("cop", "tegra-avp", "cop"),
-	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
-};
-
-#define CLK(dev, con, ck)	\
-	{			\
-		.dev_id = dev,	\
-		.con_id = con,	\
-		.clk = ck,	\
-	}
-
-static struct clk *tegra_ptr_clks[] = {
-	&tegra_clk_32k,
-	&tegra_pll_s,
-	&tegra_clk_m,
-	&tegra_pll_m,
-	&tegra_pll_m_out1,
-	&tegra_pll_c,
-	&tegra_pll_c_out1,
-	&tegra_pll_p,
-	&tegra_pll_p_out1,
-	&tegra_pll_p_out2,
-	&tegra_pll_p_out3,
-	&tegra_pll_p_out4,
-	&tegra_pll_a,
-	&tegra_pll_a_out0,
-	&tegra_pll_d,
-	&tegra_pll_d_out0,
-	&tegra_pll_u,
-	&tegra_pll_x,
-	&tegra_pll_e,
-	&tegra_clk_cclk,
-	&tegra_clk_sclk,
-	&tegra_clk_hclk,
-	&tegra_clk_pclk,
-	&tegra_clk_d,
-	&tegra_clk_cdev1,
-	&tegra_clk_cdev2,
-	&tegra_clk_virtual_cpu,
-	&tegra_clk_blink,
-	&tegra_clk_cop,
-	&tegra_clk_emc,
-};
-
-static void tegra2_init_one_clock(struct clk *c)
-{
-	clk_init(c);
-	INIT_LIST_HEAD(&c->shared_bus_list);
-	if (!c->lookup.dev_id && !c->lookup.con_id)
-		c->lookup.con_id = c->name;
-	c->lookup.clk = c;
-	clkdev_add(&c->lookup);
-}
-
-void __init tegra2_init_clocks(void)
-{
-	int i;
-	struct clk *c;
-
-	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
-		tegra2_init_one_clock(tegra_ptr_clks[i]);
-
-	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
-		tegra2_init_one_clock(&tegra_list_clks[i]);
-
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
-		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
-		if (!c) {
-			pr_err("%s: Unknown duplicate clock %s\n", __func__,
-				tegra_clk_duplicates[i].name);
-			continue;
-		}
-
-		tegra_clk_duplicates[i].lookup.clk = c;
-		clkdev_add(&tegra_clk_duplicates[i].lookup);
-	}
-
-	init_audio_sync_clock_mux();
-}
-
-#ifdef CONFIG_PM
-static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
-			   PERIPH_CLK_SOURCE_NUM + 22];
-
-void tegra_clk_suspend(void)
-{
-	unsigned long off, i;
-	u32 *ctx = clk_rst_suspend;
-
-	*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
-	*ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
-	*ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
-	*ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
-	*ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
-	*ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
-
-	*ctx++ = clk_readl(tegra_pll_m_out1.reg);
-	*ctx++ = clk_readl(tegra_pll_a_out0.reg);
-	*ctx++ = clk_readl(tegra_pll_c_out1.reg);
-
-	*ctx++ = clk_readl(tegra_clk_cclk.reg);
-	*ctx++ = clk_readl(tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
-	*ctx++ = clk_readl(tegra_clk_sclk.reg);
-	*ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
-	*ctx++ = clk_readl(tegra_clk_pclk.reg);
-
-	*ctx++ = clk_readl(tegra_clk_audio.reg);
-
-	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
-			off += 4) {
-		if (off == PERIPH_CLK_SOURCE_EMC)
-			continue;
-		*ctx++ = clk_readl(off);
-	}
-
-	off = RST_DEVICES;
-	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
-		*ctx++ = clk_readl(off);
-
-	off = CLK_OUT_ENB;
-	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
-		*ctx++ = clk_readl(off);
-
-	*ctx++ = clk_readl(MISC_CLK_ENB);
-	*ctx++ = clk_readl(CLK_MASK_ARM);
-
-	BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
-}
-
-void tegra_clk_resume(void)
-{
-	unsigned long off, i;
-	const u32 *ctx = clk_rst_suspend;
-	u32 val;
-
-	val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
-	val |= *ctx++;
-	clk_writel(val, OSC_CTRL);
-
-	clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
-	clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
-	clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
-	clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
-	clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
-	udelay(1000);
-
-	clk_writel(*ctx++, tegra_pll_m_out1.reg);
-	clk_writel(*ctx++, tegra_pll_a_out0.reg);
-	clk_writel(*ctx++, tegra_pll_c_out1.reg);
-
-	clk_writel(*ctx++, tegra_clk_cclk.reg);
-	clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
-	clk_writel(*ctx++, tegra_clk_sclk.reg);
-	clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
-	clk_writel(*ctx++, tegra_clk_pclk.reg);
-
-	clk_writel(*ctx++, tegra_clk_audio.reg);
-
-	/* enable all clocks before configuring clock sources */
-	clk_writel(0xbffffff9ul, CLK_OUT_ENB);
-	clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
-	clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
-	wmb();
-
-	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
-			off += 4) {
-		if (off == PERIPH_CLK_SOURCE_EMC)
-			continue;
-		clk_writel(*ctx++, off);
-	}
-	wmb();
-
-	off = RST_DEVICES;
-	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
-		clk_writel(*ctx++, off);
-	wmb();
-
-	off = CLK_OUT_ENB;
-	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
-		clk_writel(*ctx++, off);
-	wmb();
-
-	clk_writel(*ctx++, MISC_CLK_ENB);
-	clk_writel(*ctx++, CLK_MASK_ARM);
-}
-#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index 6674f10..5cd502c 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/tegra30_clocks.c
  *
- * Copyright (c) 2010-2011 NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
 
 #include "clock.h"
 #include "fuse.h"
+#include "tegra_cpu_car.h"
 
 #define USE_PLL_LOCK_BITS 0
 
@@ -299,6 +300,16 @@
 /* FIXME: recommended safety delay after lock is detected */
 #define PLL_POST_LOCK_DELAY		100
 
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX		0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET	0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR	0x344
+#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR	0x34c
+#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS	0x470
+
+#define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))
+#define CPU_RESET(cpu)	(0x1111ul << (cpu))
+
 /**
 * Structure defining the fields for USB UTMI clocks Parameters.
 */
@@ -365,30 +376,32 @@
 static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
 
 #define clk_writel(value, reg) \
-	__raw_writel(value, (u32)reg_clk_base + (reg))
+	__raw_writel(value, reg_clk_base + (reg))
 #define clk_readl(reg) \
-	__raw_readl((u32)reg_clk_base + (reg))
+	__raw_readl(reg_clk_base + (reg))
 #define pmc_writel(value, reg) \
-	__raw_writel(value, (u32)reg_pmc_base + (reg))
+	__raw_writel(value, reg_pmc_base + (reg))
 #define pmc_readl(reg) \
-	__raw_readl((u32)reg_pmc_base + (reg))
+	__raw_readl(reg_pmc_base + (reg))
 #define chipid_readl() \
-	__raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+	__raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV)
 
 #define clk_writel_delay(value, reg)					\
 	do {								\
-		__raw_writel((value), (u32)reg_clk_base + (reg));	\
+		__raw_writel((value), reg_clk_base + (reg));	\
 		udelay(2);						\
 	} while (0)
 
-
-static inline int clk_set_div(struct clk *c, u32 n)
+static inline int clk_set_div(struct clk_tegra *c, u32 n)
 {
-	return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+	struct clk *clk = c->hw.clk;
+
+	return clk_set_rate(clk,
+			(__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n);
 }
 
 static inline u32 periph_clk_to_reg(
-	struct clk *c, u32 reg_L, u32 reg_V, int offs)
+	struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs)
 {
 	u32 reg = c->u.periph.clk_num / 32;
 	BUG_ON(reg >= RST_DEVICES_NUM);
@@ -470,15 +483,32 @@
 	return divider_u16 - 1;
 }
 
+static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra30_clk_32k_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
+};
+
 /* clk_m functions */
-static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	if (!to_clk_tegra(hw)->fixed_rate)
+		to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra30_clk_m_init(struct clk_hw *hw)
 {
 	u32 osc_ctrl = clk_readl(OSC_CTRL);
 	u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
 	u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
 
-	c->rate = clk_measure_input_freq();
-	switch (c->rate) {
+	switch (to_clk_tegra(hw)->fixed_rate) {
 	case 12000000:
 		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
 		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
@@ -508,46 +538,44 @@
 		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
 		break;
 	default:
-		pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+		pr_err("%s: Unexpected clock rate %ld", __func__,
+				to_clk_tegra(hw)->fixed_rate);
 		BUG();
 	}
 	clk_writel(auto_clock_control, OSC_CTRL);
-	return c->rate;
 }
 
-static void tegra30_clk_m_init(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	tegra30_clk_m_autodetect_rate(c);
-}
-
-static int tegra30_clk_m_enable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return 0;
-}
-
-static void tegra30_clk_m_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	WARN(1, "Attempting to disable main SoC clock\n");
-}
-
-static struct clk_ops tegra_clk_m_ops = {
-	.init		= tegra30_clk_m_init,
-	.enable		= tegra30_clk_m_enable,
-	.disable	= tegra30_clk_m_disable,
+struct clk_ops tegra30_clk_m_ops = {
+	.init = tegra30_clk_m_init,
+	.recalc_rate = tegra30_clk_m_recalc_rate,
 };
 
-static struct clk_ops tegra_clk_m_div_ops = {
-	.enable		= tegra30_clk_m_enable,
+static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+struct clk_ops tegra_clk_m_div_ops = {
+	.recalc_rate = tegra30_clk_m_div_recalc_rate,
 };
 
 /* PLL reference divider functions */
-static void tegra30_pll_ref_init(struct clk *c)
+static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = parent_rate;
 	u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
-	pr_debug("%s on clock %s\n", __func__, c->name);
 
 	switch (pll_ref_div) {
 	case OSC_CTRL_PLL_REF_DIV_1:
@@ -564,13 +592,18 @@
 		BUG();
 	}
 	c->mul = 1;
-	c->state = ON;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
 }
 
-static struct clk_ops tegra_pll_ref_ops = {
-	.init		= tegra30_pll_ref_init,
-	.enable		= tegra30_clk_m_enable,
-	.disable	= tegra30_clk_m_disable,
+struct clk_ops tegra_pll_ref_ops = {
+	.recalc_rate = tegra30_pll_ref_recalc_rate,
 };
 
 /* super clock functions */
@@ -581,14 +614,33 @@
  * only when its parent is a fixed rate PLL, since we can't change PLL rate
  * in this case.
  */
-static void tegra30_super_clk_init(struct clk *c)
+static void tegra30_super_clk_init(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk_tegra *p =
+			to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk)));
+
+	c->state = ON;
+	if (c->flags & DIV_U71) {
+		/* Init safe 7.1 divider value (does not affect PLLX path) */
+		clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
+			   c->reg + SUPER_CLK_DIVIDER);
+		c->mul = 2;
+		c->div = 2;
+		if (!(p->flags & PLLX))
+			c->div += SUPER_CLOCK_DIV_U71_MIN;
+	} else
+		clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+}
+
+static u8 tegra30_super_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	int source;
 	int shift;
-	const struct clk_mux_sel *sel;
+
 	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	c->state = ON;
 	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
 		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
 	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
@@ -596,41 +648,16 @@
 	source = (val >> shift) & SUPER_SOURCE_MASK;
 	if (c->flags & DIV_2)
 		source |= val & SUPER_LP_DIV2_BYPASS;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->value == source)
-			break;
-	}
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
 
-	if (c->flags & DIV_U71) {
-		/* Init safe 7.1 divider value (does not affect PLLX path) */
-		clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
-			   c->reg + SUPER_CLK_DIVIDER);
-		c->mul = 2;
-		c->div = 2;
-		if (!(c->parent->flags & PLLX))
-			c->div += SUPER_CLOCK_DIV_U71_MIN;
-	} else
-		clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+	return source;
 }
 
-static int tegra30_super_clk_enable(struct clk *c)
+static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index)
 {
-	return 0;
-}
-
-static void tegra30_super_clk_disable(struct clk *c)
-{
-	/* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
-	   geared up g-mode super clock - mode switch may request to disable
-	   either of them; accept request with no affect on h/w */
-}
-
-static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
-{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk_tegra *p =
+			to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk)));
 	u32 val;
-	const struct clk_mux_sel *sel;
 	int shift;
 
 	val = clk_readl(c->reg + SUPER_CLK_MUX);
@@ -638,48 +665,36 @@
 		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
 	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
 		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			/* For LP mode super-clock switch between PLLX direct
-			   and divided-by-2 outputs is allowed only when other
-			   than PLLX clock source is current parent */
-			if ((c->flags & DIV_2) && (p->flags & PLLX) &&
-			    ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
-				if (c->parent->flags & PLLX)
-					return -EINVAL;
-				val ^= SUPER_LP_DIV2_BYPASS;
-				clk_writel_delay(val, c->reg);
-			}
-			val &= ~(SUPER_SOURCE_MASK << shift);
-			val |= (sel->value & SUPER_SOURCE_MASK) << shift;
 
-			/* 7.1 divider for CPU super-clock does not affect
-			   PLLX path */
-			if (c->flags & DIV_U71) {
-				u32 div = 0;
-				if (!(p->flags & PLLX)) {
-					div = clk_readl(c->reg +
-							SUPER_CLK_DIVIDER);
-					div &= SUPER_CLOCK_DIV_U71_MASK;
-					div >>= SUPER_CLOCK_DIV_U71_SHIFT;
-				}
-				c->div = div + 2;
-				c->mul = 2;
-			}
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel_delay(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
+	/* For LP mode super-clock switch between PLLX direct
+	   and divided-by-2 outputs is allowed only when other
+	   than PLLX clock source is current parent */
+	if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+	    ((index ^ val) & SUPER_LP_DIV2_BYPASS)) {
+		if (p->flags & PLLX)
+			return -EINVAL;
+		val ^= SUPER_LP_DIV2_BYPASS;
+		clk_writel_delay(val, c->reg);
 	}
-	return -EINVAL;
+	val &= ~(SUPER_SOURCE_MASK << shift);
+	val |= (index & SUPER_SOURCE_MASK) << shift;
+
+	/* 7.1 divider for CPU super-clock does not affect
+	   PLLX path */
+	if (c->flags & DIV_U71) {
+		u32 div = 0;
+		if (!(p->flags & PLLX)) {
+			div = clk_readl(c->reg +
+					SUPER_CLK_DIVIDER);
+			div &= SUPER_CLOCK_DIV_U71_MASK;
+			div >>= SUPER_CLOCK_DIV_U71_SHIFT;
+		}
+		c->div = div + 2;
+		c->mul = 2;
+	}
+	clk_writel_delay(val, c->reg);
+
+	return 0;
 }
 
 /*
@@ -691,10 +706,15 @@
  * rate of this PLL can't be changed, and it has many other children. In
  * this case use 7.1 fractional divider to adjust the super clock rate.
  */
-static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
-	if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
-		int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
+	struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+
+	if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+		int div = clk_div71_get_divider(parent_rate,
 					rate, c->flags, ROUND_DIVIDER_DOWN);
 		div = max(div, SUPER_CLOCK_DIV_U71_MIN);
 
@@ -704,55 +724,86 @@
 		c->mul = 2;
 		return 0;
 	}
-	return clk_set_rate(c->parent, rate);
-}
-
-static struct clk_ops tegra_super_ops = {
-	.init			= tegra30_super_clk_init,
-	.enable			= tegra30_super_clk_enable,
-	.disable		= tegra30_super_clk_disable,
-	.set_parent		= tegra30_super_clk_set_parent,
-	.set_rate		= tegra30_super_clk_set_rate,
-};
-
-static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	/* The input value 'rate' is the clock rate of the CPU complex. */
-	c->rate = (rate * c->mul) / c->div;
 	return 0;
 }
 
-static struct clk_ops tegra30_twd_ops = {
-	.set_rate	= tegra30_twd_clk_set_rate,
+static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
+	struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+	int mul = 2;
+	int div;
+
+	if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+		div = clk_div71_get_divider(*prate,
+				rate, c->flags, ROUND_DIVIDER_DOWN);
+		div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2;
+		rate = *prate * mul;
+		rate += div - 1; /* round up */
+		do_div(rate, c->div);
+
+		return rate;
+	}
+	return *prate;
+}
+
+struct clk_ops tegra30_super_ops = {
+	.init = tegra30_super_clk_init,
+	.set_parent = tegra30_super_clk_set_parent,
+	.get_parent = tegra30_super_clk_get_parent,
+	.recalc_rate = tegra30_super_clk_recalc_rate,
+	.round_rate = tegra30_super_clk_round_rate,
+	.set_rate = tegra30_super_clk_set_rate,
+};
+
+static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+struct clk_ops tegra30_twd_ops = {
+	.recalc_rate = tegra30_twd_clk_recalc_rate,
 };
 
 /* Blink output functions */
-
-static void tegra30_blink_clk_init(struct clk *c)
+static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 
 	val = pmc_readl(PMC_CTRL);
 	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
-	c->mul = 1;
-	val = pmc_readl(c->reg);
-
-	if (val & PMC_BLINK_TIMER_ENB) {
-		unsigned int on_off;
-
-		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
-			PMC_BLINK_TIMER_DATA_ON_MASK;
-		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off += val;
-		/* each tick in the blink timer is 4 32KHz clocks */
-		c->div = on_off * 4;
-	} else {
-		c->div = 1;
-	}
+	return c->state;
 }
 
-static int tegra30_blink_clk_enable(struct clk *c)
+static int tegra30_blink_clk_enable(struct clk_hw *hw)
 {
 	u32 val;
 
@@ -765,7 +816,7 @@
 	return 0;
 }
 
-static void tegra30_blink_clk_disable(struct clk *c)
+static void tegra30_blink_clk_disable(struct clk_hw *hw)
 {
 	u32 val;
 
@@ -776,9 +827,11 @@
 	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
 }
 
-static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
-	unsigned long parent_rate = clk_get_rate(c->parent);
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (rate >= parent_rate) {
 		c->div = 1;
 		pmc_writel(0, c->reg);
@@ -801,41 +854,77 @@
 	return 0;
 }
 
-static struct clk_ops tegra_blink_clk_ops = {
-	.init			= &tegra30_blink_clk_init,
-	.enable			= &tegra30_blink_clk_enable,
-	.disable		= &tegra30_blink_clk_disable,
-	.set_rate		= &tegra30_blink_clk_set_rate,
-};
-
-/* PLL Functions */
-static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
-					 u32 lock_bit)
+static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
 {
-#if USE_PLL_LOCK_BITS
-	int i;
-	for (i = 0; i < c->u.pll.lock_delay; i++) {
-		if (clk_readl(lock_reg) & lock_bit) {
-			udelay(PLL_POST_LOCK_DELAY);
-			return 0;
-		}
-		udelay(2);		/* timeout = 2 * lock time */
-	}
-	pr_err("Timed out waiting for lock bit on pll %s", c->name);
-	return -1;
-#endif
-	udelay(c->u.pll.lock_delay);
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val;
+	u32 mul;
+	u32 div;
+	u32 on_off;
 
-	return 0;
+	mul = 1;
+	val = pmc_readl(c->reg);
+
+	if (val & PMC_BLINK_TIMER_ENB) {
+		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+			PMC_BLINK_TIMER_DATA_ON_MASK;
+		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off += val;
+		/* each tick in the blink timer is 4 32KHz clocks */
+		div = on_off * 4;
+	} else {
+		div = 1;
+	}
+
+	if (mul != 0 && div != 0) {
+		rate *= mul;
+		rate += div - 1; /* round up */
+		do_div(rate, div);
+	}
+	return rate;
 }
 
-
-static void tegra30_utmi_param_configure(struct clk *c)
+static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
+	int div;
+	int mul;
+	long round_rate = *prate;
+
+	mul = 1;
+
+	if (rate >= *prate) {
+		div = 1;
+	} else {
+		div = DIV_ROUND_UP(*prate / 8, rate);
+		div *= 8;
+	}
+
+	round_rate *= mul;
+	round_rate += div - 1;
+	do_div(round_rate, div);
+
+	return round_rate;
+}
+
+struct clk_ops tegra30_blink_clk_ops = {
+	.is_enabled = tegra30_blink_clk_is_enabled,
+	.enable = tegra30_blink_clk_enable,
+	.disable = tegra30_blink_clk_disable,
+	.recalc_rate = tegra30_blink_clk_recalc_rate,
+	.round_rate = tegra30_blink_clk_round_rate,
+	.set_rate = tegra30_blink_clk_set_rate,
+};
+
+static void tegra30_utmi_param_configure(struct clk_hw *hw)
+{
+	unsigned long main_rate =
+		__clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
 	u32 reg;
 	int i;
-	unsigned long main_rate =
-		clk_get_rate(c->parent->parent);
 
 	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
 		if (main_rate == utmi_parameters[i].osc_frequency)
@@ -886,50 +975,52 @@
 	clk_writel(reg, UTMIP_PLL_CFG1);
 }
 
-static void tegra30_pll_clk_init(struct clk *c)
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg,
+					 u32 lock_bit)
 {
+	int ret = 0;
+
+#if USE_PLL_LOCK_BITS
+	int i;
+	for (i = 0; i < c->u.pll.lock_delay; i++) {
+		if (clk_readl(lock_reg) & lock_bit) {
+			udelay(PLL_POST_LOCK_DELAY);
+			return 0;
+		}
+		udelay(2);	/* timeout = 2 * lock time */
+	}
+	pr_err("Timed out waiting for lock bit on pll %s",
+					__clk_get_name(hw->clk));
+	ret = -1;
+#else
+	udelay(c->u.pll.lock_delay);
+#endif
+	return ret;
+}
+
+static int tegra30_pll_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg + PLL_BASE);
 
 	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
-
-	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
-		const struct clk_pll_freq_table *sel;
-		unsigned long input_rate = clk_get_rate(c->parent);
-		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
-			if (sel->input_rate == input_rate &&
-				sel->output_rate == c->u.pll.fixed_rate) {
-				c->mul = sel->n;
-				c->div = sel->m * sel->p;
-				return;
-			}
-		}
-		pr_err("Clock %s has unknown fixed frequency\n", c->name);
-		BUG();
-	} else if (val & PLL_BASE_BYPASS) {
-		c->mul = 1;
-		c->div = 1;
-	} else {
-		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-		if (c->flags & PLLU)
-			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
-		else
-			c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
-					PLL_BASE_DIVP_SHIFT));
-		if (c->flags & PLL_FIXED) {
-			unsigned long rate = clk_get_rate_locked(c);
-			BUG_ON(rate != c->u.pll.fixed_rate);
-		}
-	}
-
-	if (c->flags & PLLU)
-		tegra30_utmi_param_configure(c);
+	return c->state;
 }
 
-static int tegra30_pll_clk_enable(struct clk *c)
+static void tegra30_pll_clk_init(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	if (c->flags & PLLU)
+		tegra30_utmi_param_configure(hw);
+}
+
+static int tegra30_pll_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
 
 #if USE_PLL_LOCK_BITS
 	val = clk_readl(c->reg + PLL_MISC(c));
@@ -952,10 +1043,11 @@
 	return 0;
 }
 
-static void tegra30_pll_clk_disable(struct clk *c)
+static void tegra30_pll_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
 
 	val = clk_readl(c->reg);
 	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
@@ -968,36 +1060,36 @@
 	}
 }
 
-static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val, p_div, old_base;
 	unsigned long input_rate;
 	const struct clk_pll_freq_table *sel;
 	struct clk_pll_freq_table cfg;
 
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
 	if (c->flags & PLL_FIXED) {
 		int ret = 0;
 		if (rate != c->u.pll.fixed_rate) {
 			pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
-			       __func__, c->name, c->u.pll.fixed_rate, rate);
+			       __func__, __clk_get_name(hw->clk),
+				c->u.pll.fixed_rate, rate);
 			ret = -EINVAL;
 		}
 		return ret;
 	}
 
 	if (c->flags & PLLM) {
-		if (rate != clk_get_rate_locked(c)) {
+		if (rate != __clk_get_rate(hw->clk)) {
 			pr_err("%s: Can not change memory %s rate in flight\n",
-			       __func__, c->name);
+				__func__, __clk_get_name(hw->clk));
 			return -EINVAL;
 		}
-		return 0;
 	}
 
 	p_div = 0;
-	input_rate = clk_get_rate(c->parent);
+	input_rate = parent_rate;
 
 	/* Check if the target rate is tabulated */
 	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
@@ -1055,7 +1147,7 @@
 		    (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
 		    (cfg.output_rate > c->u.pll.vco_max)) {
 			pr_err("%s: Failed to set %s out-of-table rate %lu\n",
-			       __func__, c->name, rate);
+			       __func__, __clk_get_name(hw->clk), rate);
 			return -EINVAL;
 		}
 		p_div <<= PLL_BASE_DIVP_SHIFT;
@@ -1073,7 +1165,7 @@
 		return 0;
 
 	if (c->state == ON) {
-		tegra30_pll_clk_disable(c);
+		tegra30_pll_clk_disable(hw);
 		val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
 	}
 	clk_writel(val, c->reg + PLL_BASE);
@@ -1095,21 +1187,149 @@
 	}
 
 	if (c->state == ON)
-		tegra30_pll_clk_enable(c);
+		tegra30_pll_clk_enable(hw);
+
+	c->u.pll.fixed_rate = rate;
 
 	return 0;
 }
 
-static struct clk_ops tegra_pll_ops = {
-	.init			= tegra30_pll_clk_init,
-	.enable			= tegra30_pll_clk_enable,
-	.disable		= tegra30_pll_clk_disable,
-	.set_rate		= tegra30_pll_clk_set_rate,
+static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long input_rate = *prate;
+	unsigned long output_rate = *prate;
+	const struct clk_pll_freq_table *sel;
+	struct clk_pll_freq_table cfg;
+	int mul;
+	int div;
+	u32 p_div;
+	u32 val;
+
+	if (c->flags & PLL_FIXED)
+		return c->u.pll.fixed_rate;
+
+	if (c->flags & PLLM)
+		return __clk_get_rate(hw->clk);
+
+	p_div = 0;
+	/* Check if the target rate is tabulated */
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			if (c->flags & PLLU) {
+				BUG_ON(sel->p < 1 || sel->p > 2);
+				if (sel->p == 1)
+					p_div = PLLU_BASE_POST_DIV;
+			} else {
+				BUG_ON(sel->p < 1);
+				for (val = sel->p; val > 1; val >>= 1)
+					p_div++;
+				p_div <<= PLL_BASE_DIVP_SHIFT;
+			}
+			break;
+		}
+	}
+
+	if (sel->input_rate == 0) {
+		unsigned long cfreq;
+		BUG_ON(c->flags & PLLU);
+		sel = &cfg;
+
+		switch (input_rate) {
+		case 12000000:
+		case 26000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+			break;
+		case 13000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+			break;
+		case 16800000:
+		case 19200000:
+			cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+			break;
+		default:
+			pr_err("%s: Unexpected reference rate %lu\n",
+			       __func__, input_rate);
+			BUG();
+		}
+
+		/* Raise VCO to guarantee 0.5% accuracy */
+		for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+		      cfg.output_rate <<= 1)
+			p_div++;
+
+		cfg.p = 0x1 << p_div;
+		cfg.m = input_rate / cfreq;
+		cfg.n = cfg.output_rate / cfreq;
+	}
+
+	mul = sel->n;
+	div = sel->m * sel->p;
+
+	output_rate *= mul;
+	output_rate += div - 1; /* round up */
+	do_div(output_rate, div);
+
+	return output_rate;
+}
+
+static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val = clk_readl(c->reg + PLL_BASE);
+
+	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+		const struct clk_pll_freq_table *sel;
+		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+			if (sel->input_rate == parent_rate &&
+				sel->output_rate == c->u.pll.fixed_rate) {
+				c->mul = sel->n;
+				c->div = sel->m * sel->p;
+				break;
+			}
+		}
+		pr_err("Clock %s has unknown fixed frequency\n",
+						__clk_get_name(hw->clk));
+		BUG();
+	} else if (val & PLL_BASE_BYPASS) {
+		c->mul = 1;
+		c->div = 1;
+	} else {
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+					PLL_BASE_DIVP_SHIFT));
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+struct clk_ops tegra30_pll_ops = {
+	.is_enabled = tegra30_pll_clk_is_enabled,
+	.init = tegra30_pll_clk_init,
+	.enable = tegra30_pll_clk_enable,
+	.disable = tegra30_pll_clk_disable,
+	.recalc_rate = tegra30_pll_recalc_rate,
+	.round_rate = tegra30_pll_round_rate,
+	.set_rate = tegra30_pll_clk_set_rate,
 };
 
-static int
-tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val, mask, reg;
 
 	switch (p) {
@@ -1141,41 +1361,27 @@
 	return 0;
 }
 
-static struct clk_ops tegra_plld_ops = {
-	.init			= tegra30_pll_clk_init,
-	.enable			= tegra30_pll_clk_enable,
-	.disable		= tegra30_pll_clk_disable,
-	.set_rate		= tegra30_pll_clk_set_rate,
-	.clk_cfg_ex		= tegra30_plld_clk_cfg_ex,
-};
-
-static void tegra30_plle_clk_init(struct clk *c)
+static int tegra30_plle_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 
-	val = clk_readl(PLLE_AUX);
-	c->parent = (val & PLLE_AUX_PLLP_SEL) ?
-		tegra_get_clock_by_name("pll_p") :
-		tegra_get_clock_by_name("pll_ref");
-
 	val = clk_readl(c->reg + PLL_BASE);
 	c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
-	c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
-	c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
-	c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+	return c->state;
 }
 
-static void tegra30_plle_clk_disable(struct clk *c)
+static void tegra30_plle_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
 
 	val = clk_readl(c->reg + PLL_BASE);
 	val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
 	clk_writel(val, c->reg + PLL_BASE);
 }
 
-static void tegra30_plle_training(struct clk *c)
+static void tegra30_plle_training(struct clk_tegra *c)
 {
 	u32 val;
 
@@ -1198,12 +1404,15 @@
 	} while (!(val & PLLE_MISC_READY));
 }
 
-static int tegra30_plle_configure(struct clk *c, bool force_training)
+static int tegra30_plle_configure(struct clk_hw *hw, bool force_training)
 {
-	u32 val;
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
 	const struct clk_pll_freq_table *sel;
+	u32 val;
+
 	unsigned long rate = c->u.pll.fixed_rate;
-	unsigned long input_rate = clk_get_rate(c->parent);
+	unsigned long input_rate = __clk_get_rate(parent);
 
 	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
 		if (sel->input_rate == input_rate && sel->output_rate == rate)
@@ -1214,7 +1423,7 @@
 		return -ENOSYS;
 
 	/* disable PLLE, clear setup fiels */
-	tegra30_plle_clk_disable(c);
+	tegra30_plle_clk_disable(hw);
 
 	val = clk_readl(c->reg + PLL_MISC(c));
 	val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
@@ -1252,52 +1461,64 @@
 	return 0;
 }
 
-static int tegra30_plle_clk_enable(struct clk *c)
+static int tegra30_plle_clk_enable(struct clk_hw *hw)
 {
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return tegra30_plle_configure(c, !c->set);
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	return tegra30_plle_configure(hw, !c->set);
 }
 
-static struct clk_ops tegra_plle_ops = {
-	.init			= tegra30_plle_clk_init,
-	.enable			= tegra30_plle_clk_enable,
-	.disable		= tegra30_plle_clk_disable,
+static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = parent_rate;
+	u32 val;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+	c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+	c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+struct clk_ops tegra30_plle_ops = {
+	.is_enabled = tegra30_plle_clk_is_enabled,
+	.enable = tegra30_plle_clk_enable,
+	.disable = tegra30_plle_clk_disable,
+	.recalc_rate = tegra30_plle_clk_recalc_rate,
 };
 
 /* Clock divider ops */
-static void tegra30_pll_div_clk_init(struct clk *c)
+static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (c->flags & DIV_U71) {
-		u32 divu71;
 		u32 val = clk_readl(c->reg);
 		val >>= c->reg_shift;
 		c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
 		if (!(val & PLL_OUT_RESET_DISABLE))
 			c->state = OFF;
-
-		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
-		c->div = (divu71 + 2);
-		c->mul = 2;
-	} else if (c->flags & DIV_2) {
-		c->state = ON;
-		if (c->flags & (PLLD | PLLX)) {
-			c->div = 2;
-			c->mul = 1;
-		} else
-			BUG();
 	} else {
 		c->state = ON;
-		c->div = 1;
-		c->mul = 1;
 	}
+	return c->state;
 }
 
-static int tegra30_pll_div_clk_enable(struct clk *c)
+static int tegra30_pll_div_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 
-	pr_debug("%s: %s\n", __func__, c->name);
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
 	if (c->flags & DIV_U71) {
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
@@ -1315,12 +1536,13 @@
 	return -EINVAL;
 }
 
-static void tegra30_pll_div_clk_disable(struct clk *c)
+static void tegra30_pll_div_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 
-	pr_debug("%s: %s\n", __func__, c->name);
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
 	if (c->flags & DIV_U71) {
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
@@ -1334,14 +1556,14 @@
 	}
 }
 
-static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 	int divider_u71;
-	unsigned long parent_rate = clk_get_rate(c->parent);
 
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 	if (c->flags & DIV_U71) {
 		divider_u71 = clk_div71_get_divider(
 			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
@@ -1359,19 +1581,59 @@
 			clk_writel_delay(val, c->reg);
 			c->div = divider_u71 + 2;
 			c->mul = 2;
+			c->fixed_rate = rate;
 			return 0;
 		}
-	} else if (c->flags & DIV_2)
-		return clk_set_rate(c->parent, rate * 2);
+	} else if (c->flags & DIV_2) {
+		c->fixed_rate = rate;
+		return 0;
+	}
 
 	return -EINVAL;
 }
 
-static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->flags & DIV_U71) {
+		u32 divu71;
+		u32 val = clk_readl(c->reg);
+		val >>= c->reg_shift;
+
+		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+		c->div = (divu71 + 2);
+		c->mul = 2;
+	} else if (c->flags & DIV_2) {
+		if (c->flags & (PLLD | PLLX)) {
+			c->div = 2;
+			c->mul = 1;
+		} else
+			BUG();
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw,
+				unsigned long rate, unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (prate)
+		parent_rate = *prate;
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1379,23 +1641,25 @@
 		if (divider < 0)
 			return divider;
 		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_2)
-		/* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+	} else if (c->flags & DIV_2) {
+		*prate = rate * 2;
 		return rate;
+	}
 
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_pll_div_ops = {
-	.init			= tegra30_pll_div_clk_init,
-	.enable			= tegra30_pll_div_clk_enable,
-	.disable		= tegra30_pll_div_clk_disable,
-	.set_rate		= tegra30_pll_div_clk_set_rate,
-	.round_rate		= tegra30_pll_div_clk_round_rate,
+struct clk_ops tegra30_pll_div_ops = {
+	.is_enabled = tegra30_pll_div_clk_is_enabled,
+	.enable = tegra30_pll_div_clk_enable,
+	.disable = tegra30_pll_div_clk_disable,
+	.set_rate = tegra30_pll_div_clk_set_rate,
+	.recalc_rate = tegra30_pll_div_clk_recalc_rate,
+	.round_rate = tegra30_pll_div_clk_round_rate,
 };
 
 /* Periph clk ops */
-static inline u32 periph_clk_source_mask(struct clk *c)
+static inline u32 periph_clk_source_mask(struct clk_tegra *c)
 {
 	if (c->flags & MUX8)
 		return 7 << 29;
@@ -1409,7 +1673,7 @@
 		return 3 << 30;
 }
 
-static inline u32 periph_clk_source_shift(struct clk *c)
+static inline u32 periph_clk_source_shift(struct clk_tegra *c)
 {
 	if (c->flags & MUX8)
 		return 29;
@@ -1423,47 +1687,9 @@
 		return 30;
 }
 
-static void tegra30_periph_clk_init(struct clk *c)
+static int tegra30_periph_clk_is_enabled(struct clk_hw *hw)
 {
-	u32 val = clk_readl(c->reg);
-	const struct clk_mux_sel *mux = 0;
-	const struct clk_mux_sel *sel;
-	if (c->flags & MUX) {
-		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if (((val & periph_clk_source_mask(c)) >>
-			    periph_clk_source_shift(c)) == sel->value)
-				mux = sel;
-		}
-		BUG_ON(!mux);
-
-		c->parent = mux->input;
-	} else {
-		c->parent = c->inputs[0].input;
-	}
-
-	if (c->flags & DIV_U71) {
-		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
-		if ((c->flags & DIV_U71_UART) &&
-		    (!(val & PERIPH_CLK_UART_DIV_ENB))) {
-			divu71 = 0;
-		}
-		if (c->flags & DIV_U71_IDLE) {
-			val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
-				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
-			val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
-				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
-			clk_writel(val, c->reg);
-		}
-		c->div = divu71 + 2;
-		c->mul = 2;
-	} else if (c->flags & DIV_U16) {
-		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
-		c->div = divu16 + 1;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
+	struct clk_tegra *c = to_clk_tegra(hw);
 
 	c->state = ON;
 	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
@@ -1471,11 +1697,12 @@
 	if (!(c->flags & PERIPH_NO_RESET))
 		if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
 			c->state = OFF;
+	return c->state;
 }
 
-static int tegra30_periph_clk_enable(struct clk *c)
+static int tegra30_periph_clk_enable(struct clk_hw *hw)
 {
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	struct clk_tegra *c = to_clk_tegra(hw);
 
 	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
 	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
@@ -1494,31 +1721,29 @@
 	return 0;
 }
 
-static void tegra30_periph_clk_disable(struct clk *c)
+static void tegra30_periph_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	unsigned long val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
 
-	if (c->refcnt)
-		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
 
-	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
-		/* If peripheral is in the APB bus then read the APB bus to
-		 * flush the write operation in apb bus. This will avoid the
-		 * peripheral access after disabling clock*/
-		if (c->flags & PERIPH_ON_APB)
-			val = chipid_readl();
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+		return;
 
-		clk_writel_delay(
-			PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
-	}
+	/* If peripheral is in the APB bus then read the APB bus to
+	 * flush the write operation in apb bus. This will avoid the
+	 * peripheral access after disabling clock*/
+	if (c->flags & PERIPH_ON_APB)
+		val = chipid_readl();
+
+	clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
 }
 
-static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	unsigned long val;
-	pr_debug("%s %s on clock %s\n", __func__,
-		 assert ? "assert" : "deassert", c->name);
 
 	if (!(c->flags & PERIPH_NO_RESET)) {
 		if (assert) {
@@ -1537,42 +1762,40 @@
 	}
 }
 
-static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	const struct clk_mux_sel *sel;
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
 
 	if (!(c->flags & MUX))
-		return (p == c->parent) ? 0 : (-EINVAL);
+		return (index == 0) ? 0 : (-EINVAL);
 
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~periph_clk_source_mask(c);
-			val |= (sel->value << periph_clk_source_shift(c));
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel_delay(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
+	val = clk_readl(c->reg);
+	val &= ~periph_clk_source_mask(c);
+	val |= (index << periph_clk_source_shift(c));
+	clk_writel_delay(val, c->reg);
+	return 0;
 }
 
-static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source  = (val & periph_clk_source_mask(c)) >>
+					periph_clk_source_shift(c);
+
+	if (!(c->flags & MUX))
+		return 0;
+
+	return source;
+}
+
+static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1611,12 +1834,15 @@
 	return -EINVAL;
 }
 
-static long tegra30_periph_clk_round_rate(struct clk *c,
-	unsigned long rate)
+static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (prate)
+		parent_rate = *prate;
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1634,21 +1860,85 @@
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_periph_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.reset			= &tegra30_periph_clk_reset,
+static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+		if ((c->flags & DIV_U71_UART) &&
+		    (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+			divu71 = 0;
+		}
+		if (c->flags & DIV_U71_IDLE) {
+			val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			clk_writel(val, c->reg);
+		}
+		c->div = divu71 + 2;
+		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+struct clk_ops tegra30_periph_clk_ops = {
+	.is_enabled = tegra30_periph_clk_is_enabled,
+	.enable = tegra30_periph_clk_enable,
+	.disable = tegra30_periph_clk_disable,
+	.set_parent = tegra30_periph_clk_set_parent,
+	.get_parent = tegra30_periph_clk_get_parent,
+	.set_rate = tegra30_periph_clk_set_rate,
+	.round_rate = tegra30_periph_clk_round_rate,
+	.recalc_rate = tegra30_periph_clk_recalc_rate,
 };
 
+static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk *d = clk_get_sys(NULL, "pll_d");
+	/* The DSIB parent selection bit is in PLLD base
+	   register - can not do direct r-m-w, must be
+	   protected by PLLD lock */
+	tegra_clk_cfg_ex(
+		d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
+
+	return 0;
+}
+
+struct clk_ops tegra30_dsib_clk_ops = {
+	.is_enabled = tegra30_periph_clk_is_enabled,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_dsib_clk_set_parent,
+	.get_parent		= &tegra30_periph_clk_get_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.recalc_rate		= &tegra30_periph_clk_recalc_rate,
+};
 
 /* Periph extended clock configuration ops */
-static int
-tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_VI_INP_SEL) {
 		u32 val = clk_readl(c->reg);
 		val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
@@ -1660,20 +1950,11 @@
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_vi_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_vi_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-static int
-tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
 		u32 val = clk_readl(c->reg);
 		if (setting)
@@ -1686,21 +1967,11 @@
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_nand_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_nand_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-
-static int
-tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_DTV_INVERT) {
 		u32 val = clk_readl(c->reg);
 		if (setting)
@@ -1713,91 +1984,27 @@
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_dtv_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_dtv_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
-{
-	const struct clk_mux_sel *sel;
-	struct clk *d = tegra_get_clock_by_name("pll_d");
-
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			if (c->refcnt)
-				clk_enable(p);
-
-			/* The DSIB parent selection bit is in PLLD base
-			   register - can not do direct r-m-w, must be
-			   protected by PLLD lock */
-			tegra_clk_cfg_ex(
-				d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_dsib_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_dsib_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-/* pciex clock support only reset function */
-static struct clk_ops tegra_pciex_clk_ops = {
-	.reset    = tegra30_periph_clk_reset,
-};
-
 /* Output clock ops */
 
 static DEFINE_SPINLOCK(clk_out_lock);
 
-static void tegra30_clk_out_init(struct clk *c)
+static int tegra30_clk_out_is_enabled(struct clk_hw *hw)
 {
-	const struct clk_mux_sel *mux = 0;
-	const struct clk_mux_sel *sel;
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = pmc_readl(c->reg);
 
 	c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
 	c->mul = 1;
 	c->div = 1;
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (((val & periph_clk_source_mask(c)) >>
-		     periph_clk_source_shift(c)) == sel->value)
-			mux = sel;
-	}
-	BUG_ON(!mux);
-	c->parent = mux->input;
+	return c->state;
 }
 
-static int tegra30_clk_out_enable(struct clk *c)
+static int tegra30_clk_out_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
 
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
 	spin_lock_irqsave(&clk_out_lock, flags);
 	val = pmc_readl(c->reg);
 	val |= (0x1 << c->u.periph.clk_num);
@@ -1807,13 +2014,12 @@
 	return 0;
 }
 
-static void tegra30_clk_out_disable(struct clk *c)
+static void tegra30_clk_out_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
 
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
 	spin_lock_irqsave(&clk_out_lock, flags);
 	val = pmc_readl(c->reg);
 	val &= ~(0x1 << c->u.periph.clk_num);
@@ -1821,59 +2027,59 @@
 	spin_unlock_irqrestore(&clk_out_lock, flags);
 }
 
-static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
-	const struct clk_mux_sel *sel;
 
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+	spin_lock_irqsave(&clk_out_lock, flags);
+	val = pmc_readl(c->reg);
+	val &= ~periph_clk_source_mask(c);
+	val |= (index << periph_clk_source_shift(c));
+	pmc_writel(val, c->reg);
+	spin_unlock_irqrestore(&clk_out_lock, flags);
 
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			if (c->refcnt)
-				clk_enable(p);
-
-			spin_lock_irqsave(&clk_out_lock, flags);
-			val = pmc_readl(c->reg);
-			val &= ~periph_clk_source_mask(c);
-			val |= (sel->value << periph_clk_source_shift(c));
-			pmc_writel(val, c->reg);
-			spin_unlock_irqrestore(&clk_out_lock, flags);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-	return -EINVAL;
+	return 0;
 }
 
-static struct clk_ops tegra_clk_out_ops = {
-	.init			= &tegra30_clk_out_init,
-	.enable			= &tegra30_clk_out_enable,
-	.disable		= &tegra30_clk_out_disable,
-	.set_parent		= &tegra30_clk_out_set_parent,
+static u8 tegra30_clk_out_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = pmc_readl(c->reg);
+	int source;
+
+	source = (val & periph_clk_source_mask(c)) >>
+				periph_clk_source_shift(c);
+	return source;
+}
+
+struct clk_ops tegra_clk_out_ops = {
+	.is_enabled = tegra30_clk_out_is_enabled,
+	.enable = tegra30_clk_out_enable,
+	.disable = tegra30_clk_out_disable,
+	.set_parent = tegra30_clk_out_set_parent,
+	.get_parent = tegra30_clk_out_get_parent,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-
 /* Clock doubler ops */
-static void tegra30_clk_double_init(struct clk *c)
+static int tegra30_clk_double_is_enabled(struct clk_hw *hw)
 {
-	u32 val = clk_readl(c->reg);
-	c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
-	c->div = 1;
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	c->state = ON;
 	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
 		c->state = OFF;
+	return c->state;
 };
 
-static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	unsigned long parent_rate = clk_get_rate(c->parent);
+
 	if (rate == parent_rate) {
 		val = clk_readl(c->reg) | (0x1 << c->reg_shift);
 		clk_writel(val, c->reg);
@@ -1890,1215 +2096,200 @@
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_clk_double_ops = {
-	.init			= &tegra30_clk_double_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_rate		= &tegra30_clk_double_set_rate,
+static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	u32 val = clk_readl(c->reg);
+	c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+	c->div = 1;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	unsigned long output_rate = *prate;
+
+	do_div(output_rate, 2);
+	return output_rate;
+}
+
+struct clk_ops tegra30_clk_double_ops = {
+	.is_enabled = tegra30_clk_double_is_enabled,
+	.enable = tegra30_periph_clk_enable,
+	.disable = tegra30_periph_clk_disable,
+	.recalc_rate = tegra30_clk_double_recalc_rate,
+	.round_rate = tegra30_clk_double_round_rate,
+	.set_rate = tegra30_clk_double_set_rate,
 };
 
 /* Audio sync clock ops */
-static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
-{
-	c->rate = rate;
-	return 0;
-}
-
-static struct clk_ops tegra_sync_source_ops = {
-	.set_rate		= &tegra30_sync_source_set_rate,
+struct clk_ops tegra_sync_source_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-static void tegra30_audio_sync_clk_init(struct clk *c)
+static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw)
 {
-	int source;
-	const struct clk_mux_sel *sel;
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
-	source = val & AUDIO_SYNC_SOURCE_MASK;
-	for (sel = c->inputs; sel->input != NULL; sel++)
-		if (sel->value == source)
-			break;
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
+	return c->state;
 }
 
-static int tegra30_audio_sync_clk_enable(struct clk *c)
+static int tegra30_audio_sync_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
 	return 0;
 }
 
-static void tegra30_audio_sync_clk_disable(struct clk *c)
+static void tegra30_audio_sync_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
 }
 
-static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	const struct clk_mux_sel *sel;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~AUDIO_SYNC_SOURCE_MASK;
-			val |= sel->value;
 
-			if (c->refcnt)
-				clk_enable(p);
+	val = clk_readl(c->reg);
+	val &= ~AUDIO_SYNC_SOURCE_MASK;
+	val |= index;
 
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_audio_sync_clk_ops = {
-	.init       = tegra30_audio_sync_clk_init,
-	.enable     = tegra30_audio_sync_clk_enable,
-	.disable    = tegra30_audio_sync_clk_disable,
-	.set_parent = tegra30_audio_sync_clk_set_parent,
-};
-
-/* cml0 (pcie), and cml1 (sata) clock ops */
-static void tegra30_cml_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
-}
-
-static int tegra30_cml_clk_enable(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	val |= (0x1 << c->u.periph.clk_num);
 	clk_writel(val, c->reg);
 	return 0;
 }
 
-static void tegra30_cml_clk_disable(struct clk *c)
+static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source;
+
+	source = val & AUDIO_SYNC_SOURCE_MASK;
+	return source;
+}
+
+struct clk_ops tegra30_audio_sync_clk_ops = {
+	.is_enabled = tegra30_audio_sync_clk_is_enabled,
+	.enable = tegra30_audio_sync_clk_enable,
+	.disable = tegra30_audio_sync_clk_disable,
+	.set_parent = tegra30_audio_sync_clk_set_parent,
+	.get_parent = tegra30_audio_sync_clk_get_parent,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
+};
+
+/* cml0 (pcie), and cml1 (sata) clock ops */
+static int tegra30_cml_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+	return c->state;
+}
+
+static int tegra30_cml_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	u32 val = clk_readl(c->reg);
+	val |= (0x1 << c->u.periph.clk_num);
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+static void tegra30_cml_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	u32 val = clk_readl(c->reg);
 	val &= ~(0x1 << c->u.periph.clk_num);
 	clk_writel(val, c->reg);
 }
 
-static struct clk_ops tegra_cml_clk_ops = {
-	.init			= &tegra30_cml_clk_init,
-	.enable			= &tegra30_cml_clk_enable,
-	.disable		= &tegra30_cml_clk_disable,
+struct clk_ops tegra_cml_clk_ops = {
+	.is_enabled = tegra30_cml_clk_is_enabled,
+	.enable = tegra30_cml_clk_enable,
+	.disable = tegra30_cml_clk_disable,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
-	.name = "clk_32k",
-	.rate = 32768,
-	.ops  = NULL,
-	.max_rate = 32768,
+struct clk_ops tegra_pciex_clk_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-static struct clk tegra_clk_m = {
-	.name      = "clk_m",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_clk_m_ops,
-	.reg       = 0x1fc,
-	.reg_shift = 28,
-	.max_rate  = 48000000,
-};
-
-static struct clk tegra_clk_m_div2 = {
-	.name      = "clk_m_div2",
-	.ops       = &tegra_clk_m_div_ops,
-	.parent    = &tegra_clk_m,
-	.mul       = 1,
-	.div       = 2,
-	.state     = ON,
-	.max_rate  = 24000000,
-};
-
-static struct clk tegra_clk_m_div4 = {
-	.name      = "clk_m_div4",
-	.ops       = &tegra_clk_m_div_ops,
-	.parent    = &tegra_clk_m,
-	.mul       = 1,
-	.div       = 4,
-	.state     = ON,
-	.max_rate  = 12000000,
-};
-
-static struct clk tegra_pll_ref = {
-	.name      = "pll_ref",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_pll_ref_ops,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
-	{ 12000000, 1040000000, 520,  6, 1, 8},
-	{ 13000000, 1040000000, 480,  6, 1, 8},
-	{ 16800000, 1040000000, 495,  8, 1, 8},		/* actual: 1039.5 MHz */
-	{ 19200000, 1040000000, 325,  6, 1, 6},
-	{ 26000000, 1040000000, 520, 13, 1, 8},
-
-	{ 12000000, 832000000, 416,  6, 1, 8},
-	{ 13000000, 832000000, 832, 13, 1, 8},
-	{ 16800000, 832000000, 396,  8, 1, 8},		/* actual: 831.6 MHz */
-	{ 19200000, 832000000, 260,  6, 1, 8},
-	{ 26000000, 832000000, 416, 13, 1, 8},
-
-	{ 12000000, 624000000, 624, 12, 1, 8},
-	{ 13000000, 624000000, 624, 13, 1, 8},
-	{ 16800000, 600000000, 520, 14, 1, 8},
-	{ 19200000, 624000000, 520, 16, 1, 8},
-	{ 26000000, 624000000, 624, 26, 1, 8},
-
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 16800000, 600000000, 500, 14, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-
-	{ 12000000, 520000000, 520, 12, 1, 8},
-	{ 13000000, 520000000, 520, 13, 1, 8},
-	{ 16800000, 520000000, 495, 16, 1, 8},		/* actual: 519.75 MHz */
-	{ 19200000, 520000000, 325, 12, 1, 6},
-	{ 26000000, 520000000, 520, 26, 1, 8},
-
-	{ 12000000, 416000000, 416, 12, 1, 8},
-	{ 13000000, 416000000, 416, 13, 1, 8},
-	{ 16800000, 416000000, 396, 16, 1, 8},		/* actual: 415.8 MHz */
-	{ 19200000, 416000000, 260, 12, 1, 6},
-	{ 26000000, 416000000, 416, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
-	.name      = "pll_c",
-	.flags	   = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x80,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1400000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_c_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_c_out1 = {
-	.name      = "pll_c_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_c,
-	.reg       = 0x84,
-	.reg_shift = 0,
-	.max_rate  = 700000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 1, 8},
-	{ 13000000, 666000000, 666, 13, 1, 8},
-	{ 16800000, 666000000, 555, 14, 1, 8},
-	{ 19200000, 666000000, 555, 16, 1, 8},
-	{ 26000000, 666000000, 666, 26, 1, 8},
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 16800000, 600000000, 500, 14, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
-	.name      = "pll_m",
-	.flags     = PLL_HAS_CPCON | PLLM,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x90,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 800000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_m_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_m_out1 = {
-	.name      = "pll_m_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_m,
-	.reg       = 0x94,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 2, 8},
-	{ 13000000, 216000000, 432, 13, 2, 8},
-	{ 16800000, 216000000, 360, 14, 2, 8},
-	{ 19200000, 216000000, 360, 16, 2, 8},
-	{ 26000000, 216000000, 432, 26, 2, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
-	.name      = "pll_p",
-	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xa0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 432000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_p_freq_table,
-		.lock_delay = 300,
-		.fixed_rate = 408000000,
-	},
-};
-
-static struct clk tegra_pll_p_out1 = {
-	.name      = "pll_p_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
-	.name      = "pll_p_out2",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
-	.name      = "pll_p_out3",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
-	.name      = "pll_p_out4",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
-	{ 9600000, 564480000, 294, 5, 1, 4},
-	{ 9600000, 552960000, 288, 5, 1, 4},
-	{ 9600000, 24000000,  5,   2, 1, 1},
-
-	{ 28800000, 56448000, 49, 25, 1, 1},
-	{ 28800000, 73728000, 64, 25, 1, 1},
-	{ 28800000, 24000000,  5,  6, 1, 1},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
-	.name      = "pll_a",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xb0,
-	.parent    = &tegra_pll_p_out1,
-	.max_rate  = 700000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_a_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_a_out0 = {
-	.name      = "pll_a_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_a,
-	.reg       = 0xb4,
-	.reg_shift = 0,
-	.max_rate  = 100000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 1, 4},
-	{ 13000000, 216000000, 216, 13, 1, 4},
-	{ 16800000, 216000000, 180, 14, 1, 4},
-	{ 19200000, 216000000, 180, 16, 1, 4},
-	{ 26000000, 216000000, 216, 26, 1, 4},
-
-	{ 12000000, 594000000, 594, 12, 1, 8},
-	{ 13000000, 594000000, 594, 13, 1, 8},
-	{ 16800000, 594000000, 495, 14, 1, 8},
-	{ 19200000, 594000000, 495, 16, 1, 8},
-	{ 26000000, 594000000, 594, 26, 1, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
-	.name      = "pll_d",
-	.flags     = PLL_HAS_CPCON | PLLD,
-	.ops       = &tegra_plld_ops,
-	.reg       = 0xd0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d_out0 = {
-	.name      = "pll_d_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d,
-	.max_rate  = 500000000,
-};
-
-static struct clk tegra_pll_d2 = {
-	.name      = "pll_d2",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
-	.ops       = &tegra_plld_ops,
-	.reg       = 0x4b8,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d2_out0 = {
-	.name      = "pll_d2_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d2,
-	.max_rate  = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 2, 12},
-	{ 13000000, 480000000, 960, 13, 2, 12},
-	{ 16800000, 480000000, 400, 7,  2, 5},
-	{ 19200000, 480000000, 200, 4,  2, 3},
-	{ 26000000, 480000000, 960, 26, 2, 12},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
-	.name      = "pll_u",
-	.flags     = PLL_HAS_CPCON | PLLU,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xc0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 480000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 480000000,
-		.vco_max   = 960000000,
-		.freq_table = tegra_pll_u_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
-	/* 1.7 GHz */
-	{ 12000000, 1700000000, 850,  6,  1, 8},
-	{ 13000000, 1700000000, 915,  7,  1, 8},	/* actual: 1699.2 MHz */
-	{ 16800000, 1700000000, 708,  7,  1, 8},	/* actual: 1699.2 MHz */
-	{ 19200000, 1700000000, 885,  10, 1, 8},	/* actual: 1699.2 MHz */
-	{ 26000000, 1700000000, 850,  13, 1, 8},
-
-	/* 1.6 GHz */
-	{ 12000000, 1600000000, 800,  6,  1, 8},
-	{ 13000000, 1600000000, 738,  6,  1, 8},	/* actual: 1599.0 MHz */
-	{ 16800000, 1600000000, 857,  9,  1, 8},	/* actual: 1599.7 MHz */
-	{ 19200000, 1600000000, 500,  6,  1, 8},
-	{ 26000000, 1600000000, 800,  13, 1, 8},
-
-	/* 1.5 GHz */
-	{ 12000000, 1500000000, 750,  6,  1, 8},
-	{ 13000000, 1500000000, 923,  8,  1, 8},	/* actual: 1499.8 MHz */
-	{ 16800000, 1500000000, 625,  7,  1, 8},
-	{ 19200000, 1500000000, 625,  8,  1, 8},
-	{ 26000000, 1500000000, 750,  13, 1, 8},
-
-	/* 1.4 GHz */
-	{ 12000000, 1400000000, 700,  6,  1, 8},
-	{ 13000000, 1400000000, 969,  9,  1, 8},	/* actual: 1399.7 MHz */
-	{ 16800000, 1400000000, 1000, 12, 1, 8},
-	{ 19200000, 1400000000, 875,  12, 1, 8},
-	{ 26000000, 1400000000, 700,  13, 1, 8},
-
-	/* 1.3 GHz */
-	{ 12000000, 1300000000, 975,  9,  1, 8},
-	{ 13000000, 1300000000, 1000, 10, 1, 8},
-	{ 16800000, 1300000000, 928,  12, 1, 8},	/* actual: 1299.2 MHz */
-	{ 19200000, 1300000000, 812,  12, 1, 8},	/* actual: 1299.2 MHz */
-	{ 26000000, 1300000000, 650,  13, 1, 8},
-
-	/* 1.2 GHz */
-	{ 12000000, 1200000000, 1000, 10, 1, 8},
-	{ 13000000, 1200000000, 923,  10, 1, 8},	/* actual: 1199.9 MHz */
-	{ 16800000, 1200000000, 1000, 14, 1, 8},
-	{ 19200000, 1200000000, 1000, 16, 1, 8},
-	{ 26000000, 1200000000, 600,  13, 1, 8},
-
-	/* 1.1 GHz */
-	{ 12000000, 1100000000, 825,  9,  1, 8},
-	{ 13000000, 1100000000, 846,  10, 1, 8},	/* actual: 1099.8 MHz */
-	{ 16800000, 1100000000, 982,  15, 1, 8},	/* actual: 1099.8 MHz */
-	{ 19200000, 1100000000, 859,  15, 1, 8},	/* actual: 1099.5 MHz */
-	{ 26000000, 1100000000, 550,  13, 1, 8},
-
-	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 1, 8},
-	{ 13000000, 1000000000, 1000, 13, 1, 8},
-	{ 16800000, 1000000000, 833,  14, 1, 8},	/* actual: 999.6 MHz */
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 8},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
-	.name      = "pll_x",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xe0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1700000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1700000000,
-		.freq_table = tegra_pll_x_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_x_out0 = {
-	.name      = "pll_x_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLX,
-	.parent    = &tegra_pll_x,
-	.max_rate  = 850000000,
-};
-
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
-	/* PLLE special case: use cpcon field to store cml divider value */
-	{ 12000000,  100000000, 150, 1,  18, 11},
-	{ 216000000, 100000000, 200, 18, 24, 13},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
-	.name      = "pll_e",
-	.flags     = PLL_ALT_MISC_REG,
-	.ops       = &tegra_plle_ops,
-	.reg       = 0xe8,
-	.max_rate  = 100000000,
-	.u.pll = {
-		.input_min = 12000000,
-		.input_max = 216000000,
-		.cf_min    = 12000000,
-		.cf_max    = 12000000,
-		.vco_min   = 1200000000,
-		.vco_max   = 2400000000U,
-		.freq_table = tegra_pll_e_freq_table,
-		.lock_delay = 300,
-		.fixed_rate = 100000000,
-	},
-};
-
-static struct clk tegra_cml0_clk = {
-	.name      = "cml0",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_cml_clk_ops,
-	.reg       = PLLE_AUX,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num = 0,
-	},
-};
-
-static struct clk tegra_cml1_clk = {
-	.name      = "cml1",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_cml_clk_ops,
-	.reg       = PLLE_AUX,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num   = 1,
-	},
-};
-
-static struct clk tegra_pciex_clk = {
-	.name      = "pciex",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_pciex_clk_ops,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num   = 74,
-	},
-};
-
-/* Audio sync clocks */
-#define SYNC_SOURCE(_id)				\
-	{						\
-		.name      = #_id "_sync",		\
-		.rate      = 24000000,			\
-		.max_rate  = 24000000,			\
-		.ops       = &tegra_sync_source_ops	\
-	}
-static struct clk tegra_sync_source_list[] = {
-	SYNC_SOURCE(spdif_in),
-	SYNC_SOURCE(i2s0),
-	SYNC_SOURCE(i2s1),
-	SYNC_SOURCE(i2s2),
-	SYNC_SOURCE(i2s3),
-	SYNC_SOURCE(i2s4),
-	SYNC_SOURCE(vimclk),
-};
-
-static struct clk_mux_sel mux_audio_sync_clk[] = {
-	{ .input = &tegra_sync_source_list[0],	.value = 0},
-	{ .input = &tegra_sync_source_list[1],	.value = 1},
-	{ .input = &tegra_sync_source_list[2],	.value = 2},
-	{ .input = &tegra_sync_source_list[3],	.value = 3},
-	{ .input = &tegra_sync_source_list[4],	.value = 4},
-	{ .input = &tegra_sync_source_list[5],	.value = 5},
-	{ .input = &tegra_pll_a_out0,		.value = 6},
-	{ .input = &tegra_sync_source_list[6],	.value = 7},
-	{ 0, 0 }
-};
-
-#define AUDIO_SYNC_CLK(_id, _index)			\
-	{						\
-		.name      = #_id,			\
-		.inputs    = mux_audio_sync_clk,	\
-		.reg       = 0x4A0 + (_index) * 4,	\
-		.max_rate  = 24000000,			\
-		.ops       = &tegra_audio_sync_clk_ops	\
-	}
-static struct clk tegra_clk_audio_list[] = {
-	AUDIO_SYNC_CLK(audio0, 0),
-	AUDIO_SYNC_CLK(audio1, 1),
-	AUDIO_SYNC_CLK(audio2, 2),
-	AUDIO_SYNC_CLK(audio3, 3),
-	AUDIO_SYNC_CLK(audio4, 4),
-	AUDIO_SYNC_CLK(audio, 5),	/* SPDIF */
-};
-
-#define AUDIO_SYNC_2X_CLK(_id, _index)				\
-	{							\
-		.name      = #_id "_2x",			\
-		.flags     = PERIPH_NO_RESET,			\
-		.max_rate  = 48000000,				\
-		.ops       = &tegra_clk_double_ops,		\
-		.reg       = 0x49C,				\
-		.reg_shift = 24 + (_index),			\
-		.parent    = &tegra_clk_audio_list[(_index)],	\
-		.u.periph = {					\
-			.clk_num = 113 + (_index),		\
-		},						\
-	}
-static struct clk tegra_clk_audio_2x_list[] = {
-	AUDIO_SYNC_2X_CLK(audio0, 0),
-	AUDIO_SYNC_2X_CLK(audio1, 1),
-	AUDIO_SYNC_2X_CLK(audio2, 2),
-	AUDIO_SYNC_2X_CLK(audio3, 3),
-	AUDIO_SYNC_2X_CLK(audio4, 4),
-	AUDIO_SYNC_2X_CLK(audio, 5),	/* SPDIF */
-};
-
-#define MUX_I2S_SPDIF(_id, _index)					\
-static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = {	\
-	{.input = &tegra_pll_a_out0, .value = 0},			\
-	{.input = &tegra_clk_audio_2x_list[(_index)], .value = 1},	\
-	{.input = &tegra_pll_p, .value = 2},				\
-	{.input = &tegra_clk_m, .value = 3},				\
-	{ 0, 0},							\
-}
-MUX_I2S_SPDIF(audio0, 0);
-MUX_I2S_SPDIF(audio1, 1);
-MUX_I2S_SPDIF(audio2, 2);
-MUX_I2S_SPDIF(audio3, 3);
-MUX_I2S_SPDIF(audio4, 4);
-MUX_I2S_SPDIF(audio, 5);		/* SPDIF */
-
-/* External clock outputs (through PMC) */
-#define MUX_EXTERN_OUT(_id)						\
-static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = {	\
-	{.input = &tegra_clk_m,		.value = 0},			\
-	{.input = &tegra_clk_m_div2,	.value = 1},			\
-	{.input = &tegra_clk_m_div4,	.value = 2},			\
-	{.input = NULL,			.value = 3}, /* placeholder */	\
-	{ 0, 0},							\
-}
-MUX_EXTERN_OUT(1);
-MUX_EXTERN_OUT(2);
-MUX_EXTERN_OUT(3);
-
-static struct clk_mux_sel *mux_extern_out_list[] = {
-	mux_clkm_clkm2_clkm4_extern1,
-	mux_clkm_clkm2_clkm4_extern2,
-	mux_clkm_clkm2_clkm4_extern3,
-};
-
-#define CLK_OUT_CLK(_id)					\
-	{							\
-		.name      = "clk_out_" #_id,			\
-		.lookup    = {					\
-			.dev_id    = "clk_out_" #_id,		\
-			.con_id	   = "extern" #_id,		\
-		},						\
-		.ops       = &tegra_clk_out_ops,		\
-		.reg       = 0x1a8,				\
-		.inputs    = mux_clkm_clkm2_clkm4_extern##_id,	\
-		.flags     = MUX_CLK_OUT,			\
-		.max_rate  = 216000000,				\
-		.u.periph = {					\
-			.clk_num   = (_id - 1) * 8 + 2,		\
-		},						\
-	}
-static struct clk tegra_clk_out_list[] = {
-	CLK_OUT_CLK(1),
-	CLK_OUT_CLK(2),
-	CLK_OUT_CLK(3),
-};
-
-/* called after peripheral external clocks are initialized */
-static void init_clk_out_mux(void)
+/* Tegra30 CPU clock and reset control functions */
+static void tegra30_wait_cpu_in_reset(u32 cpu)
 {
-	int i;
-	struct clk *c;
+	unsigned int reg;
 
-	/* output clock con_id is the name of peripheral
-	   external clock connected to input 3 of the output mux */
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
-		c = tegra_get_clock_by_name(
-			tegra_clk_out_list[i].lookup.con_id);
-		if (!c)
-			pr_err("%s: could not find clk %s\n", __func__,
-			       tegra_clk_out_list[i].lookup.con_id);
-		mux_extern_out_list[i][3].input = c;
-	}
+	do {
+		reg = readl(reg_clk_base +
+			    TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+		cpu_relax();
+	} while (!(reg & (1 << cpu)));	/* check CPU been reset or not */
+
+	return;
 }
 
-/* Peripheral muxes */
-static struct clk_mux_sel mux_sclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c_out1,	.value = 1},
-	{ .input = &tegra_pll_p_out4,	.value = 2},
-	{ .input = &tegra_pll_p_out3,	.value = 3},
-	{ .input = &tegra_pll_p_out2,	.value = 4},
-	/* { .input = &tegra_clk_d,	.value = 5}, - no use on tegra30 */
-	{ .input = &tegra_clk_32k,	.value = 6},
-	{ .input = &tegra_pll_m_out1,	.value = 7},
-	{ 0, 0},
-};
-
-static struct clk tegra_clk_sclk = {
-	.name	= "sclk",
-	.inputs	= mux_sclk,
-	.reg	= 0x28,
-	.ops	= &tegra_super_ops,
-	.max_rate = 334000000,
-	.min_rate = 40000000,
-};
-
-static struct clk tegra_clk_blink = {
-	.name		= "blink",
-	.parent		= &tegra_clk_32k,
-	.reg		= 0x40,
-	.ops		= &tegra_blink_clk_ops,
-	.max_rate	= 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_pll_a_out0, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_m, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_d_out0, .value = 1},
-	{.input = &tegra_pll_c, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_m, .value = 1},
-	{.input = &tegra_pll_d_out0, .value = 2},
-	{.input = &tegra_pll_a_out0, .value = 3},
-	{.input = &tegra_pll_c, .value = 4},
-	{.input = &tegra_pll_d2_out0, .value = 5},
-	{.input = &tegra_clk_m, .value = 6},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
-	{ .input = &tegra_pll_a_out0, .value = 0},
-	/* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_32k,   .value = 2},
-	{.input = &tegra_clk_m,     .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_m,     .value = 2},
-	{.input = &tegra_clk_32k,   .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_pll_m,     .value = 2},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
-	{ .input = &tegra_clk_m, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
-	{ .input = &tegra_pll_p_out3, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0[] = {
-	{ .input = &tegra_pll_d_out0, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
-	{ .input = &tegra_pll_d_out0,  .value = 0},
-	{ .input = &tegra_pll_d2_out0, .value = 1},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
-	{ .input = &tegra_pll_a_out0, .value = 0},
-	{ .input = &tegra_clk_32k,    .value = 1},
-	{ .input = &tegra_pll_p,      .value = 2},
-	{ .input = &tegra_clk_m,      .value = 3},
-	{ .input = &tegra_pll_e,      .value = 4},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_cclk_g[] = {
-	{ .input = &tegra_clk_m,        .value = 0},
-	{ .input = &tegra_pll_c,        .value = 1},
-	{ .input = &tegra_clk_32k,      .value = 2},
-	{ .input = &tegra_pll_m,        .value = 3},
-	{ .input = &tegra_pll_p,        .value = 4},
-	{ .input = &tegra_pll_p_out4,   .value = 5},
-	{ .input = &tegra_pll_p_out3,   .value = 6},
-	{ .input = &tegra_pll_x,        .value = 8},
-	{ 0, 0},
-};
-
-static struct clk tegra_clk_cclk_g = {
-	.name	= "cclk_g",
-	.flags	= DIV_U71 | DIV_U71_INT,
-	.inputs = mux_cclk_g,
-	.reg	= 0x368,
-	.ops	= &tegra_super_ops,
-	.max_rate = 1700000000,
-};
-
-static struct clk tegra30_clk_twd = {
-	.parent	  = &tegra_clk_cclk_g,
-	.name     = "twd",
-	.ops      = &tegra30_twd_ops,
-	.max_rate = 1400000000,	/* Same as tegra_clk_cpu_cmplx.max_rate */
-	.mul      = 1,
-	.div      = 2,
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = &tegra_periph_clk_ops,	\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs,	\
-			_flags, _ops)					\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = _ops,			\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id    = _con,		\
-		},					\
-		.ops       = &tegra_clk_shared_bus_ops,	\
-		.parent = _parent,			\
-		.u.shared_bus_user = {			\
-			.client_id = _id,		\
-			.client_div = _div,		\
-			.mode = _mode,			\
-		},					\
-	}
-struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
-	PERIPH_CLK("kbc",	"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
-	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("kfuse",	"kfuse-tegra",		NULL,	40,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("fuse",	"fuse-tegra",		"fuse",	39,	0,	26000000,  mux_clk_m,			PERIPH_ON_APB),
-	PERIPH_CLK("fuse_burn",	"fuse-tegra",		"fuse_burn",	39,	0,	26000000,  mux_clk_m,		PERIPH_ON_APB),
-	PERIPH_CLK("apbif",	"tegra30-ahub",		"apbif", 107,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s0",	"tegra30-i2s.0",	NULL,	30,	0x1d8,	26000000,  mux_pllaout0_audio0_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s1",	"tegra30-i2s.1",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio1_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s2",	"tegra30-i2s.2",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s3",	"tegra30-i2s.3",	NULL,	101,	0x3bc,	26000000,  mux_pllaout0_audio3_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s4",	"tegra30-i2s.4",	NULL,	102,	0x3c0,	26000000,  mux_pllaout0_audio4_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("spdif_out",	"tegra30-spdif",	"spdif_out",	10,	0x108,	100000000, mux_pllaout0_audio_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("spdif_in",	"tegra30-spdif",	"spdif_in",	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("pwm",	"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_clk32_clkm,	MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("d_audio",	"tegra30-ahub",		"d_audio", 106,	0x3d0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam0",	"tegra30-dam.0",	NULL,   108,	0x3d8,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam1",	"tegra30-dam.1",	NULL,   109,	0x3dc,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam2",	"tegra30-dam.2",	NULL,   110,	0x3e0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda",	"tegra30-hda",		"hda",   125,	0x428,	108000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda2codec_2x",	"tegra30-hda",	"hda2codec",   111,	0x3e4,	48000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda2hdmi",	"tegra30-hda",		"hda2hdmi",	128,	0,	48000000,  mux_clk_m,			0),
-	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc5",	"spi_tegra.4",		NULL,	104,	0x3c8,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc6",	"spi_tegra.5",		NULL,	105,	0x3cc,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sata_oob",	"tegra_sata_oob",	NULL,	123,	0x420,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sata",	"tegra_sata",		NULL,	124,	0x424,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sata_cold",	"tegra_sata_cold",	NULL,	129,	0,	48000000,  mux_clk_m,			0),
-	PERIPH_CLK_EX("ndflash", "tegra_nand",		NULL,	13,	0x160,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71,	&tegra_nand_clk_ops),
-	PERIPH_CLK("ndspeed",	"tegra_nand_speed",	NULL,	80,	0x3f8,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x164,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vcp",	"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsea",	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsev",	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("vde",	"vde",			NULL,	61,	0x1c8,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
-	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	127000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
-	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c4",	"tegra-i2c.3",		NULL,	103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c5",	"tegra-i2c.4",		NULL,	47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK_EX("vi",	"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT,	&tegra_vi_clk_ops),
-	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
-	PERIPH_CLK("3d2",       "3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
-	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
-	PERIPH_CLK("vi_sensor",	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET),
-	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	260000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK_EX("dtv",	"dtv",			NULL,	79,	0x1dc,	250000000, mux_clk_m,			0,		&tegra_dtv_clk_ops),
-	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	220000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("disp1",	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
-	PERIPH_CLK("disp2",	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
-	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("dsia",	"tegradc.0",		"dsia",	48,	0,	500000000, mux_plld_out0,		0),
-	PERIPH_CLK_EX("dsib",	"tegradc.1",		"dsib",	82,	0xd0,	500000000, mux_plld_out0_plld2_out0,	MUX | PLLD,	&tegra_dsib_clk_ops),
-	PERIPH_CLK("csi",	"tegra_camera",		"csi",	52,	0,	102000000, mux_pllp_out3,		0),
-	PERIPH_CLK("isp",	"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
-	PERIPH_CLK("csus",	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
-
-	PERIPH_CLK("tsensor",	"tegra-tsensor",	NULL,	100,	0x3b8,	216000000, mux_pllp_pllc_clkm_clk32,	MUX | DIV_U71),
-	PERIPH_CLK("actmon",	"actmon",		NULL,	119,	0x3e8,	216000000, mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("extern1",	"extern1",		NULL,	120,	0x3ec,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("extern2",	"extern2",		NULL,	121,	0x3f0,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("extern3",	"extern3",		NULL,	122,	0x3f4,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("i2cslow",	"i2cslow",		NULL,	81,	0x3fc,	26000000,  mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("pcie",	"tegra-pcie",		"pcie",	70,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("afi",	"tegra-pcie",		"afi",	72,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("se",	"se",			NULL,	127,	0x42c,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con)		\
-	{						\
-		.name	= _name,			\
-		.lookup	= {				\
-			.dev_id	= _dev,			\
-			.con_id		= _con,		\
-		},					\
-	}
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration.  List those here to register them twice in the clock lookup
- * table under two names.
- */
-struct clk_duplicate tegra_clk_duplicates[] = {
-	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
-	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
-	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
-	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
-	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
-	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
-	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
-	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
-	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
-	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
-	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
-	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
-	CLK_DUPLICATE("bsev", "nvavp", "bsev"),
-	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
-	CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
-	CLK_DUPLICATE("bsea", "nvavp", "bsea"),
-	CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
-	CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
-	CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
-	CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
-	CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
-	CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
-	CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
-	CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
-	CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
-	CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
-	CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
-	CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
-	CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
-	CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
-	CLK_DUPLICATE("twd", "smp_twd", NULL),
-	CLK_DUPLICATE("vcp", "nvavp", "vcp"),
-	CLK_DUPLICATE("i2s0", NULL, "i2s0"),
-	CLK_DUPLICATE("i2s1", NULL, "i2s1"),
-	CLK_DUPLICATE("i2s2", NULL, "i2s2"),
-	CLK_DUPLICATE("i2s3", NULL, "i2s3"),
-	CLK_DUPLICATE("i2s4", NULL, "i2s4"),
-	CLK_DUPLICATE("dam0", NULL, "dam0"),
-	CLK_DUPLICATE("dam1", NULL, "dam1"),
-	CLK_DUPLICATE("dam2", NULL, "dam2"),
-	CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
-};
-
-struct clk *tegra_ptr_clks[] = {
-	&tegra_clk_32k,
-	&tegra_clk_m,
-	&tegra_clk_m_div2,
-	&tegra_clk_m_div4,
-	&tegra_pll_ref,
-	&tegra_pll_m,
-	&tegra_pll_m_out1,
-	&tegra_pll_c,
-	&tegra_pll_c_out1,
-	&tegra_pll_p,
-	&tegra_pll_p_out1,
-	&tegra_pll_p_out2,
-	&tegra_pll_p_out3,
-	&tegra_pll_p_out4,
-	&tegra_pll_a,
-	&tegra_pll_a_out0,
-	&tegra_pll_d,
-	&tegra_pll_d_out0,
-	&tegra_pll_d2,
-	&tegra_pll_d2_out0,
-	&tegra_pll_u,
-	&tegra_pll_x,
-	&tegra_pll_x_out0,
-	&tegra_pll_e,
-	&tegra_clk_cclk_g,
-	&tegra_cml0_clk,
-	&tegra_cml1_clk,
-	&tegra_pciex_clk,
-	&tegra_clk_sclk,
-	&tegra_clk_blink,
-	&tegra30_clk_twd,
-};
-
-
-static void tegra30_init_one_clock(struct clk *c)
+static void tegra30_put_cpu_in_reset(u32 cpu)
 {
-	clk_init(c);
-	INIT_LIST_HEAD(&c->shared_bus_list);
-	if (!c->lookup.dev_id && !c->lookup.con_id)
-		c->lookup.con_id = c->name;
-	c->lookup.clk = c;
-	clkdev_add(&c->lookup);
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+	dmb();
 }
 
-void __init tegra30_init_clocks(void)
+static void tegra30_cpu_out_of_reset(u32 cpu)
 {
-	int i;
-	struct clk *c;
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+	wmb();
+}
 
-	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
-		tegra30_init_one_clock(tegra_ptr_clks[i]);
+static void tegra30_enable_cpu_clock(u32 cpu)
+{
+	unsigned int reg;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
-		tegra30_init_one_clock(&tegra_list_clks[i]);
+	writel(CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	reg = readl(reg_clk_base +
+		    TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+}
 
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
-		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
-		if (!c) {
-			pr_err("%s: Unknown duplicate clock %s\n", __func__,
-				tegra_clk_duplicates[i].name);
-			continue;
-		}
+static void tegra30_disable_cpu_clock(u32 cpu)
+{
 
-		tegra_clk_duplicates[i].lookup.clk = c;
-		clkdev_add(&tegra_clk_duplicates[i].lookup);
-	}
+	unsigned int reg;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
-		tegra30_init_one_clock(&tegra_sync_source_list[i]);
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
-		tegra30_init_one_clock(&tegra_clk_audio_list[i]);
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
-		tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg | CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
 
-	init_clk_out_mux();
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
-		tegra30_init_one_clock(&tegra_clk_out_list[i]);
+static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
+	.wait_for_reset	= tegra30_wait_cpu_in_reset,
+	.put_in_reset	= tegra30_put_cpu_in_reset,
+	.out_of_reset	= tegra30_cpu_out_of_reset,
+	.enable_clock	= tegra30_enable_cpu_clock,
+	.disable_clock	= tegra30_disable_cpu_clock,
+};
 
+void __init tegra30_cpu_car_ops_init(void)
+{
+	tegra_cpu_car_ops = &tegra30_cpu_car_ops;
 }
diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h
new file mode 100644
index 0000000..f2f88fe
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA30_CLOCK_H
+#define __MACH_TEGRA30_CLOCK_H
+
+extern struct clk_ops tegra30_clk_32k_ops;
+extern struct clk_ops tegra30_clk_m_ops;
+extern struct clk_ops tegra_clk_m_div_ops;
+extern struct clk_ops tegra_pll_ref_ops;
+extern struct clk_ops tegra30_pll_ops;
+extern struct clk_ops tegra30_pll_div_ops;
+extern struct clk_ops tegra_plld_ops;
+extern struct clk_ops tegra30_plle_ops;
+extern struct clk_ops tegra_cml_clk_ops;
+extern struct clk_ops tegra_pciex_clk_ops;
+extern struct clk_ops tegra_sync_source_ops;
+extern struct clk_ops tegra30_audio_sync_clk_ops;
+extern struct clk_ops tegra30_clk_double_ops;
+extern struct clk_ops tegra_clk_out_ops;
+extern struct clk_ops tegra30_super_ops;
+extern struct clk_ops tegra30_blink_clk_ops;
+extern struct clk_ops tegra30_twd_ops;
+extern struct clk_ops tegra30_periph_clk_ops;
+extern struct clk_ops tegra30_dsib_clk_ops;
+extern struct clk_ops tegra_nand_clk_ops;
+extern struct clk_ops tegra_vi_clk_ops;
+extern struct clk_ops tegra_dtv_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
new file mode 100644
index 0000000..c1044960
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks_data.c
@@ -0,0 +1,1372 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <linux/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra30_clocks.h"
+#include "tegra_cpu_car.h"
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags,		\
+		   _parent_names, _parents, _parent)		\
+	static struct clk tegra_##_name = {			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.name = #_name,					\
+		.rate = _rate,					\
+		.ops = _ops,					\
+		.flags = _flags,				\
+		.parent_names = _parent_names,			\
+		.parents = _parents,				\
+		.num_parents = ARRAY_SIZE(_parent_names),	\
+		.parent	= _parent,				\
+	};
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+	.hw = {
+		.clk = &tegra_clk_32k,
+	},
+	.fixed_rate = 32768,
+};
+static struct clk tegra_clk_32k = {
+	.name = "clk_32k",
+	.hw = &tegra_clk_32k_hw.hw,
+	.ops = &tegra30_clk_32k_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+	.hw = {
+		.clk = &tegra_clk_m,
+	},
+	.flags = ENABLE_ON_INIT,
+	.reg = 0x1fc,
+	.reg_shift = 28,
+	.max_rate = 48000000,
+};
+static struct clk tegra_clk_m = {
+	.name = "clk_m",
+	.hw = &tegra_clk_m_hw.hw,
+	.ops = &tegra30_clk_m_ops,
+	.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
+};
+
+static const char *clk_m_div_parent_names[] = {
+	"clk_m",
+};
+
+static struct clk *clk_m_div_parents[] = {
+	&tegra_clk_m,
+};
+
+static struct clk tegra_clk_m_div2;
+static struct clk_tegra tegra_clk_m_div2_hw = {
+	.hw = {
+		.clk = &tegra_clk_m_div2,
+	},
+	.mul = 1,
+	.div = 2,
+	.max_rate = 24000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0,
+		clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_clk_m_div4;
+static struct clk_tegra tegra_clk_m_div4_hw = {
+	.hw = {
+		.clk = &tegra_clk_m_div4,
+	},
+	.mul = 1,
+	.div = 4,
+	.max_rate = 12000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0,
+		clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_pll_ref;
+static struct clk_tegra tegra_pll_ref_hw = {
+	.hw = {
+		.clk = &tegra_pll_ref,
+	},
+	.flags = ENABLE_ON_INIT,
+	.max_rate = 26000000,
+};
+DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names,
+		clk_m_div_parents, &tegra_clk_m);
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min,	\
+		   _input_max, _cf_min, _cf_max, _vco_min,	\
+		   _vco_max, _freq_table, _lock_delay, _ops,	\
+		   _fixed_rate, _clk_cfg_ex, _parent)		\
+	static struct clk tegra_##_name;			\
+	static const char *_name##_parent_names[] = {		\
+		#_parent,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.u.pll = {					\
+			.input_min = _input_min,		\
+			.input_max = _input_max,		\
+			.cf_min = _cf_min,			\
+			.cf_max = _cf_max,			\
+			.vco_min = _vco_min,			\
+			.vco_max = _vco_max,			\
+			.freq_table = _freq_table,		\
+			.lock_delay = _lock_delay,		\
+			.fixed_rate = _fixed_rate,		\
+		},						\
+		.clk_cfg_ex = _clk_cfg_ex,			\
+	};							\
+	DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED,	\
+			 _name##_parent_names, _name##_parents,	\
+			&tegra_##_parent);
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift,		\
+		_max_rate, _ops, _parent, _clk_flags)		\
+	static const char *_name##_parent_names[] = {		\
+		#_parent,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.reg_shift = _reg_shift,			\
+	};							\
+	DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops,	\
+		_clk_flags,  _name##_parent_names,		\
+		_name##_parents, &tegra_##_parent);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+	{ 12000000, 1040000000, 520,  6, 1, 8},
+	{ 13000000, 1040000000, 480,  6, 1, 8},
+	{ 16800000, 1040000000, 495,  8, 1, 8},	/* actual: 1039.5 MHz */
+	{ 19200000, 1040000000, 325,  6, 1, 6},
+	{ 26000000, 1040000000, 520, 13, 1, 8},
+
+	{ 12000000, 832000000, 416,  6, 1, 8},
+	{ 13000000, 832000000, 832, 13, 1, 8},
+	{ 16800000, 832000000, 396,  8, 1, 8},	/* actual: 831.6 MHz */
+	{ 19200000, 832000000, 260,  6, 1, 8},
+	{ 26000000, 832000000, 416, 13, 1, 8},
+
+	{ 12000000, 624000000, 624, 12, 1, 8},
+	{ 13000000, 624000000, 624, 13, 1, 8},
+	{ 16800000, 600000000, 520, 14, 1, 8},
+	{ 19200000, 624000000, 520, 16, 1, 8},
+	{ 26000000, 624000000, 624, 26, 1, 8},
+
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+
+	{ 12000000, 520000000, 520, 12, 1, 8},
+	{ 13000000, 520000000, 520, 13, 1, 8},
+	{ 16800000, 520000000, 495, 16, 1, 8},	/* actual: 519.75 MHz */
+	{ 19200000, 520000000, 325, 12, 1, 6},
+	{ 26000000, 520000000, 520, 26, 1, 8},
+
+	{ 12000000, 416000000, 416, 12, 1, 8},
+	{ 13000000, 416000000, 416, 13, 1, 8},
+	{ 16800000, 416000000, 396, 16, 1, 8},	/* actual: 415.8 MHz */
+	{ 19200000, 416000000, 260, 12, 1, 6},
+	{ 26000000, 416000000, 416, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+		tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000,
+		tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 16800000, 666000000, 555, 14, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000,
+		1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table,
+		300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+		tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 16800000, 216000000, 360, 14, 2, 8},
+	{ 19200000, 216000000, 360, 16, 2, 8},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+		tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL,
+		pll_ref);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+		0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+		16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+		0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+		16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+	{ 9600000, 564480000, 294, 5, 1, 4},
+	{ 9600000, 552960000, 288, 5, 1, 4},
+	{ 9600000, 24000000,  5,   2, 1, 1},
+
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_a_freq_table,
+		300, tegra30_pll_ops, 0, NULL, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops,
+		pll_a, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+	{ 12000000, 216000000, 216, 12, 1, 4},
+	{ 13000000, 216000000, 216, 13, 1, 4},
+	{ 16800000, 216000000, 180, 14, 1, 4},
+	{ 19200000, 216000000, 180, 16, 1, 4},
+	{ 26000000, 216000000, 216, 26, 1, 4},
+
+	{ 12000000, 594000000, 594, 12, 1, 8},
+	{ 13000000, 594000000, 594, 13, 1, 8},
+	{ 16800000, 594000000, 495, 14, 1, 8},
+	{ 19200000, 594000000, 495, 16, 1, 8},
+	{ 26000000, 594000000, 594, 26, 1, 8},
+
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+		1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+		1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+		pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000,
+		2000000, 40000000, 1000000, 6000000, 40000000, 1000000000,
+		tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL,
+		pll_ref);
+
+DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+		pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+	{ 12000000, 480000000, 960, 12, 2, 12},
+	{ 13000000, 480000000, 960, 13, 2, 12},
+	{ 16800000, 480000000, 400, 7,  2, 5},
+	{ 19200000, 480000000, 200, 4,  2, 3},
+	{ 26000000, 480000000, 960, 26, 2, 12},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000,
+		1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table,
+		1000, tegra30_pll_ops, 0, NULL, pll_ref);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+	/* 1.7 GHz */
+	{ 12000000, 1700000000, 850,  6,  1, 8},
+	{ 13000000, 1700000000, 915,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 16800000, 1700000000, 708,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 19200000, 1700000000, 885,  10, 1, 8},	/* actual: 1699.2 MHz */
+	{ 26000000, 1700000000, 850,  13, 1, 8},
+
+	/* 1.6 GHz */
+	{ 12000000, 1600000000, 800,  6,  1, 8},
+	{ 13000000, 1600000000, 738,  6,  1, 8},	/* actual: 1599.0 MHz */
+	{ 16800000, 1600000000, 857,  9,  1, 8},	/* actual: 1599.7 MHz */
+	{ 19200000, 1600000000, 500,  6,  1, 8},
+	{ 26000000, 1600000000, 800,  13, 1, 8},
+
+	/* 1.5 GHz */
+	{ 12000000, 1500000000, 750,  6,  1, 8},
+	{ 13000000, 1500000000, 923,  8,  1, 8},	/* actual: 1499.8 MHz */
+	{ 16800000, 1500000000, 625,  7,  1, 8},
+	{ 19200000, 1500000000, 625,  8,  1, 8},
+	{ 26000000, 1500000000, 750,  13, 1, 8},
+
+	/* 1.4 GHz */
+	{ 12000000, 1400000000, 700,  6,  1, 8},
+	{ 13000000, 1400000000, 969,  9,  1, 8},	/* actual: 1399.7 MHz */
+	{ 16800000, 1400000000, 1000, 12, 1, 8},
+	{ 19200000, 1400000000, 875,  12, 1, 8},
+	{ 26000000, 1400000000, 700,  13, 1, 8},
+
+	/* 1.3 GHz */
+	{ 12000000, 1300000000, 975,  9,  1, 8},
+	{ 13000000, 1300000000, 1000, 10, 1, 8},
+	{ 16800000, 1300000000, 928,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 19200000, 1300000000, 812,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 26000000, 1300000000, 650,  13, 1, 8},
+
+	/* 1.2 GHz */
+	{ 12000000, 1200000000, 1000, 10, 1, 8},
+	{ 13000000, 1200000000, 923,  10, 1, 8},	/* actual: 1199.9 MHz */
+	{ 16800000, 1200000000, 1000, 14, 1, 8},
+	{ 19200000, 1200000000, 1000, 16, 1, 8},
+	{ 26000000, 1200000000, 600,  13, 1, 8},
+
+	/* 1.1 GHz */
+	{ 12000000, 1100000000, 825,  9,  1, 8},
+	{ 13000000, 1100000000, 846,  10, 1, 8},	/* actual: 1099.8 MHz */
+	{ 16800000, 1100000000, 982,  15, 1, 8},	/* actual: 1099.8 MHz */
+	{ 19200000, 1100000000, 859,  15, 1, 8},	/* actual: 1099.5 MHz */
+	{ 26000000, 1100000000, 550,  13, 1, 8},
+
+	/* 1 GHz */
+	{ 12000000, 1000000000, 1000, 12, 1, 8},
+	{ 13000000, 1000000000, 1000, 13, 1, 8},
+	{ 16800000, 1000000000, 833,  14, 1, 8},	/* actual: 999.6 MHz */
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 8},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1700000000,
+		tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops,
+		pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+	/* PLLE special case: use cpcon field to store cml divider value */
+	{ 12000000,  100000000, 150, 1,  18, 11},
+	{ 216000000, 100000000, 200, 18, 24, 13},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000,
+		12000000, 12000000, 1200000000, 2400000000U,
+		tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL,
+		pll_ref);
+
+static const char *mux_plle[] = {
+	"pll_e",
+};
+
+static struct clk *mux_plle_p[] = {
+	&tegra_pll_e,
+};
+
+static struct clk tegra_cml0;
+static struct clk_tegra tegra_cml0_hw = {
+	.hw = {
+		.clk = &tegra_cml0,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.u.periph = {
+		.clk_num = 0,
+	},
+};
+DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_cml1;
+static struct clk_tegra tegra_cml1_hw = {
+	.hw = {
+		.clk = &tegra_cml1,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.u.periph = {
+		.clk_num = 1,
+	},
+};
+DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_pciex;
+static struct clk_tegra tegra_pciex_hw = {
+	.hw = {
+		.clk = &tegra_pciex,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.reset = tegra30_periph_clk_reset,
+	.u.periph = {
+		.clk_num = 74,
+	},
+};
+DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+#define SYNC_SOURCE(_name)					\
+	static struct clk tegra_##_name##_sync;			\
+	static struct clk_tegra tegra_##_name##_sync_hw = {	\
+		.hw = {						\
+			.clk = &tegra_##_name##_sync,		\
+		},						\
+		.max_rate = 24000000,				\
+		.fixed_rate = 24000000,				\
+	};							\
+	static struct clk tegra_##_name##_sync = {		\
+		.name = #_name "_sync",				\
+		.hw = &tegra_##_name##_sync_hw.hw,		\
+		.ops = &tegra_sync_source_ops,			\
+		.flags = CLK_IS_ROOT,				\
+	};
+
+SYNC_SOURCE(spdif_in);
+SYNC_SOURCE(i2s0);
+SYNC_SOURCE(i2s1);
+SYNC_SOURCE(i2s2);
+SYNC_SOURCE(i2s3);
+SYNC_SOURCE(i2s4);
+SYNC_SOURCE(vimclk);
+
+static struct clk *tegra_sync_source_list[] = {
+	&tegra_spdif_in_sync,
+	&tegra_i2s0_sync,
+	&tegra_i2s1_sync,
+	&tegra_i2s2_sync,
+	&tegra_i2s3_sync,
+	&tegra_i2s4_sync,
+	&tegra_vimclk_sync,
+};
+
+static const char *mux_audio_sync_clk[] = {
+	"spdif_in_sync",
+	"i2s0_sync",
+	"i2s1_sync",
+	"i2s2_sync",
+	"i2s3_sync",
+	"i2s4_sync",
+	"vimclk_sync",
+};
+
+#define AUDIO_SYNC_CLK(_name, _index)				\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.max_rate = 24000000,				\
+		.reg = 0x4A0 + (_index) * 4,			\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &tegra30_audio_sync_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent_names = mux_audio_sync_clk,		\
+		.parents = tegra_sync_source_list,		\
+		.num_parents = ARRAY_SIZE(mux_audio_sync_clk),	\
+	};
+
+AUDIO_SYNC_CLK(audio0, 0);
+AUDIO_SYNC_CLK(audio1, 1);
+AUDIO_SYNC_CLK(audio2, 2);
+AUDIO_SYNC_CLK(audio3, 3);
+AUDIO_SYNC_CLK(audio4, 4);
+AUDIO_SYNC_CLK(audio5, 5);
+
+static struct clk *tegra_clk_audio_list[] = {
+	&tegra_audio0,
+	&tegra_audio1,
+	&tegra_audio2,
+	&tegra_audio3,
+	&tegra_audio4,
+	&tegra_audio5,	/* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_name, _index)			\
+	static const char *_name##_parent_names[] = {		\
+		"tegra_" #_name,				\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_name,					\
+	};							\
+	static struct clk tegra_##_name##_2x;			\
+	static struct clk_tegra tegra_##_name##_2x_hw = {	\
+		.hw = {						\
+			.clk = &tegra_##_name##_2x,		\
+		},						\
+		.flags = PERIPH_NO_RESET,			\
+		.max_rate = 48000000,				\
+		.reg = 0x49C,					\
+		.reg_shift = 24 + (_index),			\
+		.u.periph = {					\
+			.clk_num = 113 + (_index),		\
+		},						\
+	};							\
+	static struct clk tegra_##_name##_2x = {		\
+		.name = #_name "_2x",				\
+		.ops = &tegra30_clk_double_ops,			\
+		.hw = &tegra_##_name##_2x_hw.hw,		\
+		.parent_names = _name##_parent_names,		\
+		.parents = _name##_parents,			\
+		.parent = &tegra_##_name,			\
+		.num_parents = 1,				\
+	};
+
+AUDIO_SYNC_2X_CLK(audio0, 0);
+AUDIO_SYNC_2X_CLK(audio1, 1);
+AUDIO_SYNC_2X_CLK(audio2, 2);
+AUDIO_SYNC_2X_CLK(audio3, 3);
+AUDIO_SYNC_2X_CLK(audio4, 4);
+AUDIO_SYNC_2X_CLK(audio5, 5);	/* SPDIF */
+
+static struct clk *tegra_clk_audio_2x_list[] = {
+	&tegra_audio0_2x,
+	&tegra_audio1_2x,
+	&tegra_audio2_2x,
+	&tegra_audio3_2x,
+	&tegra_audio4_2x,
+	&tegra_audio5_2x,	/* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id)					\
+static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = {	\
+	"pll_a_out0",						\
+	#_id "_2x",						\
+	"pll_p",						\
+	"clk_m",						\
+};								\
+static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = {	\
+	&tegra_pll_a_out0,					\
+	&tegra_##_id##_2x,					\
+	&tegra_pll_p,						\
+	&tegra_clk_m,						\
+};
+
+MUX_I2S_SPDIF(audio0);
+MUX_I2S_SPDIF(audio1);
+MUX_I2S_SPDIF(audio2);
+MUX_I2S_SPDIF(audio3);
+MUX_I2S_SPDIF(audio4);
+MUX_I2S_SPDIF(audio5);		/* SPDIF */
+
+static struct clk tegra_extern1;
+static struct clk tegra_extern2;
+static struct clk tegra_extern3;
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id)					\
+static const char *mux_clkm_clkm2_clkm4_extern##_id[] = {	\
+	"clk_m",						\
+	"clk_m_div2",						\
+	"clk_m_div4",						\
+	"extern" #_id,						\
+};								\
+static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = {	\
+	&tegra_clk_m,						\
+	&tegra_clk_m_div2,					\
+	&tegra_clk_m_div4,					\
+	&tegra_extern##_id,					\
+};
+
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+#define CLK_OUT_CLK(_name, _index)					\
+	static struct clk tegra_##_name;				\
+	static struct clk_tegra tegra_##_name##_hw = {			\
+		.hw = {							\
+			.clk = &tegra_##_name,				\
+		},							\
+		.lookup = {						\
+			.dev_id	= #_name,				\
+			.con_id	= "extern" #_index,			\
+		},							\
+		.flags = MUX_CLK_OUT,					\
+		.fixed_rate = 216000000,					\
+		.reg = 0x1a8,						\
+		.u.periph = {						\
+			.clk_num = (_index - 1) * 8 + 2,		\
+		},							\
+	};								\
+	static struct clk tegra_##_name = {				\
+		.name = #_name,						\
+		.ops = &tegra_clk_out_ops,				\
+		.hw = &tegra_##_name##_hw.hw,				\
+		.parent_names = mux_clkm_clkm2_clkm4_extern##_index,	\
+		.parents = mux_clkm_clkm2_clkm4_extern##_index##_p,	\
+		.num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\
+	};
+
+CLK_OUT_CLK(clk_out_1, 1);
+CLK_OUT_CLK(clk_out_2, 2);
+CLK_OUT_CLK(clk_out_3, 3);
+
+static struct clk *tegra_clk_out_list[] = {
+	&tegra_clk_out_1,
+	&tegra_clk_out_2,
+	&tegra_clk_out_3,
+};
+
+static const char *mux_sclk[] = {
+	"clk_m",
+	"pll_c_out1",
+	"pll_p_out4",
+	"pll_p_out3",
+	"pll_p_out2",
+	"dummy",
+	"clk_32k",
+	"pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c_out1,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out2,
+	NULL,
+	&tegra_clk_32k,
+	&tegra_pll_m_out1,
+};
+
+static struct clk tegra_clk_sclk;
+static struct clk_tegra tegra_clk_sclk_hw = {
+	.hw = {
+		.clk = &tegra_clk_sclk,
+	},
+	.reg = 0x28,
+	.max_rate = 334000000,
+	.min_rate = 40000000,
+};
+
+static struct clk tegra_clk_sclk = {
+	.name = "sclk",
+	.ops = &tegra30_super_ops,
+	.hw = &tegra_clk_sclk_hw.hw,
+	.parent_names = mux_sclk,
+	.parents = mux_sclk_p,
+	.num_parents = ARRAY_SIZE(mux_sclk),
+};
+
+static const char *mux_blink[] = {
+	"clk_32k",
+};
+
+static struct clk *mux_blink_p[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk tegra_clk_blink;
+static struct clk_tegra tegra_clk_blink_hw = {
+	.hw = {
+		.clk = &tegra_clk_blink,
+	},
+	.reg = 0x40,
+	.max_rate = 32768,
+};
+static struct clk tegra_clk_blink = {
+	.name = "blink",
+	.ops = &tegra30_blink_clk_ops,
+	.hw = &tegra_clk_blink_hw.hw,
+	.parent = &tegra_clk_32k,
+	.parent_names = mux_blink,
+	.parents = mux_blink_p,
+	.num_parents = ARRAY_SIZE(mux_blink),
+};
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"pll_a_out0",
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+	"clk_m",
+};
+
+static const char *mux_pllp_clkm[] = {
+	"pll_p",
+	"dummy",
+	"dummy",
+	"clk_m",
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+	"pll_p",
+	"pll_d_out0",
+	"pll_c",
+	"clk_m",
+};
+
+static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+	"pll_p",
+	"pll_m",
+	"pll_d_out0",
+	"pll_a_out0",
+	"pll_c",
+	"pll_d2_out0",
+	"clk_m",
+};
+
+static const char *mux_plla_pllc_pllp_clkm[] = {
+	"pll_a_out0",
+	"dummy",
+	"pll_p",
+	"clk_m"
+};
+
+static const char *mux_pllp_pllc_clk32_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"clk_32k",
+	"clk_m",
+};
+
+static const char *mux_pllp_pllc_clkm_clk32[] = {
+	"pll_p",
+	"pll_c",
+	"clk_m",
+	"clk_32k",
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+};
+
+static const char *mux_clk_m[] = {
+	"clk_m",
+};
+
+static const char *mux_pllp_out3[] = {
+	"pll_p_out3",
+};
+
+static const char *mux_plld_out0[] = {
+	"pll_d_out0",
+};
+
+static const char *mux_plld_out0_plld2_out0[] = {
+	"pll_d_out0",
+	"pll_d2_out0",
+};
+
+static const char *mux_clk_32k[] = {
+	"clk_32k",
+};
+
+static const char *mux_plla_clk32_pllp_clkm_plle[] = {
+	"pll_a_out0",
+	"clk_32k",
+	"pll_p",
+	"clk_m",
+	"pll_e",
+};
+
+static const char *mux_cclk_g[] = {
+	"clk_m",
+	"pll_c",
+	"clk_32k",
+	"pll_m",
+	"pll_p",
+	"pll_p_out4",
+	"pll_p_out3",
+	"dummy",
+	"pll_x",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_pll_a_out0,
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_clkm_p[] = {
+	&tegra_pll_p,
+	NULL,
+	NULL,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_d_out0,
+	&tegra_pll_c,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_m,
+	&tegra_pll_d_out0,
+	&tegra_pll_a_out0,
+	&tegra_pll_c,
+	&tegra_pll_d2_out0,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_plla_pllc_pllp_clkm_p[] = {
+	&tegra_pll_a_out0,
+	NULL,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clk32_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clkm_clk32_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_clk_m,
+	&tegra_clk_32k,
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+};
+
+static struct clk *mux_clk_m_p[] = {
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+	&tegra_pll_p_out3,
+};
+
+static struct clk *mux_plld_out0_p[] = {
+	&tegra_pll_d_out0,
+};
+
+static struct clk *mux_plld_out0_plld2_out0_p[] = {
+	&tegra_pll_d_out0,
+	&tegra_pll_d2_out0,
+};
+
+static struct clk *mux_clk_32k_p[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = {
+	&tegra_pll_a_out0,
+	&tegra_clk_32k,
+	&tegra_pll_p,
+	&tegra_clk_m,
+	&tegra_pll_e,
+};
+
+static struct clk *mux_cclk_g_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_pll_m,
+	&tegra_pll_p,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	NULL,
+	&tegra_pll_x,
+};
+
+static struct clk tegra_clk_cclk_g;
+static struct clk_tegra tegra_clk_cclk_g_hw = {
+	.hw = {
+		.clk = &tegra_clk_cclk_g,
+	},
+	.flags = DIV_U71 | DIV_U71_INT,
+	.reg = 0x368,
+	.max_rate = 1700000000,
+};
+static struct clk tegra_clk_cclk_g = {
+	.name = "cclk_g",
+	.ops = &tegra30_super_ops,
+	.hw = &tegra_clk_cclk_g_hw.hw,
+	.parent_names = mux_cclk_g,
+	.parents = mux_cclk_g_p,
+	.num_parents = ARRAY_SIZE(mux_cclk_g),
+};
+
+static const char *mux_twd[] = {
+	"cclk_g",
+};
+
+static struct clk *mux_twd_p[] = {
+	&tegra_clk_cclk_g,
+};
+
+static struct clk tegra30_clk_twd;
+static struct clk_tegra tegra30_clk_twd_hw = {
+	.hw = {
+		.clk = &tegra30_clk_twd,
+	},
+	.max_rate = 1400000000,
+	.mul = 1,
+	.div = 2,
+};
+
+static struct clk tegra30_clk_twd = {
+	.name = "twd",
+	.ops = &tegra30_twd_ops,
+	.hw = &tegra30_clk_twd_hw.hw,
+	.parent = &tegra_clk_cclk_g,
+	.parent_names = mux_twd,
+	.parents = mux_twd_p,
+	.num_parents = ARRAY_SIZE(mux_twd),
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg,	\
+		_max, _inputs, _flags)	 		\
+	static struct clk tegra_##_name;		\
+	static struct clk_tegra tegra_##_name##_hw = {	\
+		.hw = {					\
+			.clk = &tegra_##_name,		\
+		},					\
+		.lookup = {				\
+			.dev_id	= _dev,			\
+			.con_id	= _con,			\
+		},					\
+		.reg = _reg,				\
+		.flags = _flags,			\
+		.max_rate = _max,			\
+		.u.periph = {				\
+			.clk_num = _clk_num,		\
+		},					\
+		.reset = &tegra30_periph_clk_reset,	\
+	};						\
+	static struct clk tegra_##_name = {		\
+		.name = #_name,				\
+		.ops = &tegra30_periph_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,		\
+		.parent_names = _inputs,		\
+		.parents = _inputs##_p,			\
+		.num_parents = ARRAY_SIZE(_inputs),	\
+	};
+
+PERIPH_CLK(apbdma,	"tegra-apbdma",		NULL,	34,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(rtc,		"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(kbc,		"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(timer,	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(kfuse,	"kfuse-tegra",		NULL,	40,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(fuse,	"fuse-tegra",		"fuse",	39,	0,	26000000,  mux_clk_m,			PERIPH_ON_APB);
+PERIPH_CLK(fuse_burn,	"fuse-tegra",		"fuse_burn",	39,	0,	26000000,  mux_clk_m,		PERIPH_ON_APB);
+PERIPH_CLK(apbif,	"tegra30-ahub",		"apbif", 107,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(i2s0,	"tegra30-i2s.0",	NULL,	30,	0x1d8,	26000000,  mux_pllaout0_audio0_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s1,	"tegra30-i2s.1",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio1_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s2,	"tegra30-i2s.2",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s3,	"tegra30-i2s.3",	NULL,	101,	0x3bc,	26000000,  mux_pllaout0_audio3_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s4,	"tegra30-i2s.4",	NULL,	102,	0x3c0,	26000000,  mux_pllaout0_audio4_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_out,	"tegra30-spdif",	"spdif_out",	10,	0x108,	100000000, mux_pllaout0_audio5_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_in,	"tegra30-spdif",	"spdif_in",	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pwm,		"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_clk32_clkm,	MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(d_audio,	"tegra30-ahub",		"d_audio", 106,	0x3d0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam0,	"tegra30-dam.0",	NULL,	108,	0x3d8,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam1,	"tegra30-dam.1",	NULL,	109,	0x3dc,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam2,	"tegra30-dam.2",	NULL,	110,	0x3e0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda,		"tegra30-hda",		"hda",	125,	0x428,	108000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda2codec_2x,	"tegra30-hda",	"hda2codec",	111,	0x3e4,	48000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda2hdmi,	"tegra30-hda",		"hda2hdmi",	128,	0,	48000000,  mux_clk_m,			0);
+PERIPH_CLK(sbc1,	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc2,	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc3,	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc4,	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc5,	"spi_tegra.4",		NULL,	104,	0x3c8,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc6,	"spi_tegra.5",		NULL,	105,	0x3cc,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sata_oob,	"tegra_sata_oob",	NULL,	123,	0x420,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sata,	"tegra_sata",		NULL,	124,	0x424,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sata_cold,	"tegra_sata_cold",	NULL,	129,	0,	48000000,  mux_clk_m,			0);
+PERIPH_CLK(ndflash,	"tegra_nand",		NULL,	13,	0x160,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(ndspeed,	"tegra_nand_speed",	NULL,	80,	0x3f8,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(vfir,	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sdmmc1,	"sdhci-tegra.0",	NULL,	14,	0x150,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2,	"sdhci-tegra.1",	NULL,	9,	0x154,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3,	"sdhci-tegra.2",	NULL,	69,	0x1bc,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4,	"sdhci-tegra.3",	NULL,	15,	0x164,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp,		"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsea,	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsev,	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(vde,		"vde",			NULL,	61,	0x1c8,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(csite,	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* max rate ??? */
+PERIPH_CLK(la,		"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(owr,		"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(nor,		"nor",			NULL,	42,	0x1d0,	127000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(mipi,	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */
+PERIPH_CLK(i2c1,	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c2,	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c3,	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c4,	"tegra-i2c.3",		NULL,	103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c5,	"tegra-i2c.4",		NULL,	47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(uarta,	"tegra-uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartb,	"tegra-uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartc,	"tegra-uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartd,	"tegra-uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uarte,	"tegra-uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(vi,		"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(3d,		"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(3d2,		"3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(2d,		"2d",			NULL,	21,	0x15c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE);
+PERIPH_CLK(vi_sensor,	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET);
+PERIPH_CLK(epp,		"epp",			NULL,	19,	0x16c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(mpe,		"mpe",			NULL,	60,	0x170,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(host1x,	"host1x",		NULL,	28,	0x180,	260000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(cve,		"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo,		"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(dtv,		"dtv",			NULL,	79,	0x1dc,	250000000, mux_clk_m,			0);
+PERIPH_CLK(hdmi,	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(tvdac,	"tvdac",		NULL,	53,	0x194,	220000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1,	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8);
+PERIPH_CLK(disp2,	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8);
+PERIPH_CLK(usbd,	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb2,	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb3,	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(dsia,	"tegradc.0",		"dsia",	48,	0,	500000000, mux_plld_out0,		0);
+PERIPH_CLK(csi,		"tegra_camera",		"csi",	52,	0,	102000000, mux_pllp_out3,		0);
+PERIPH_CLK(isp,		"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0); /* same frequency as VI */
+PERIPH_CLK(csus,	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET);
+PERIPH_CLK(tsensor,	"tegra-tsensor",	NULL,	100,	0x3b8,	216000000, mux_pllp_pllc_clkm_clk32,	MUX | DIV_U71);
+PERIPH_CLK(actmon,	"actmon",		NULL,	119,	0x3e8,	216000000, mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71);
+PERIPH_CLK(extern1,	"extern1",		NULL,	120,	0x3ec,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern2,	"extern2",		NULL,	121,	0x3f0,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern3,	"extern3",		NULL,	122,	0x3f4,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(i2cslow,	"i2cslow",		NULL,	81,	0x3fc,	26000000,  mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pcie,	"tegra-pcie",		"pcie",	70,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(afi,		"tegra-pcie",		"afi",	72,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(se,		"se",			NULL,	127,	0x42c,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT);
+
+static struct clk tegra_dsib;
+static struct clk_tegra tegra_dsib_hw = {
+	.hw = {
+		.clk = &tegra_dsib,
+	},
+	.lookup = {
+		.dev_id	= "tegradc.1",
+		.con_id	= "dsib",
+	},
+	.reg = 0xd0,
+	.flags = MUX | PLLD,
+	.max_rate = 500000000,
+	.u.periph = {
+		.clk_num = 82,
+	},
+	.reset = &tegra30_periph_clk_reset,
+};
+static struct clk tegra_dsib = {
+	.name = "dsib",
+	.ops = &tegra30_dsib_clk_ops,
+	.hw = &tegra_dsib_hw.hw,
+	.parent_names = mux_plld_out0_plld2_out0,
+	.parents = mux_plld_out0_plld2_out0_p,
+	.num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0),
+};
+
+struct clk *tegra_list_clks[] = {
+	&tegra_apbdma,
+	&tegra_rtc,
+	&tegra_kbc,
+	&tegra_kfuse,
+	&tegra_fuse,
+	&tegra_fuse_burn,
+	&tegra_apbif,
+	&tegra_i2s0,
+	&tegra_i2s1,
+	&tegra_i2s2,
+	&tegra_i2s3,
+	&tegra_i2s4,
+	&tegra_spdif_out,
+	&tegra_spdif_in,
+	&tegra_pwm,
+	&tegra_d_audio,
+	&tegra_dam0,
+	&tegra_dam1,
+	&tegra_dam2,
+	&tegra_hda,
+	&tegra_hda2codec_2x,
+	&tegra_hda2hdmi,
+	&tegra_sbc1,
+	&tegra_sbc2,
+	&tegra_sbc3,
+	&tegra_sbc4,
+	&tegra_sbc5,
+	&tegra_sbc6,
+	&tegra_sata_oob,
+	&tegra_sata,
+	&tegra_sata_cold,
+	&tegra_ndflash,
+	&tegra_ndspeed,
+	&tegra_vfir,
+	&tegra_sdmmc1,
+	&tegra_sdmmc2,
+	&tegra_sdmmc3,
+	&tegra_sdmmc4,
+	&tegra_vcp,
+	&tegra_bsea,
+	&tegra_bsev,
+	&tegra_vde,
+	&tegra_csite,
+	&tegra_la,
+	&tegra_owr,
+	&tegra_nor,
+	&tegra_mipi,
+	&tegra_i2c1,
+	&tegra_i2c2,
+	&tegra_i2c3,
+	&tegra_i2c4,
+	&tegra_i2c5,
+	&tegra_uarta,
+	&tegra_uartb,
+	&tegra_uartc,
+	&tegra_uartd,
+	&tegra_uarte,
+	&tegra_vi,
+	&tegra_3d,
+	&tegra_3d2,
+	&tegra_2d,
+	&tegra_vi_sensor,
+	&tegra_epp,
+	&tegra_mpe,
+	&tegra_host1x,
+	&tegra_cve,
+	&tegra_tvo,
+	&tegra_dtv,
+	&tegra_hdmi,
+	&tegra_tvdac,
+	&tegra_disp1,
+	&tegra_disp2,
+	&tegra_usbd,
+	&tegra_usb2,
+	&tegra_usb3,
+	&tegra_dsia,
+	&tegra_dsib,
+	&tegra_csi,
+	&tegra_isp,
+	&tegra_csus,
+	&tegra_tsensor,
+	&tegra_actmon,
+	&tegra_extern1,
+	&tegra_extern2,
+	&tegra_extern3,
+	&tegra_i2cslow,
+	&tegra_pcie,
+	&tegra_afi,
+	&tegra_se,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)	\
+	{					\
+		.name	= _name,		\
+		.lookup	= {			\
+			.dev_id	= _dev,		\
+			.con_id	= _con,		\
+		},				\
+	}
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
+	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
+	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
+	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
+	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
+	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
+	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
+	CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+	CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+	CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+	CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+	CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+	CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+	CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+	CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+	CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+	CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+	CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+	CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+	CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+	CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+	CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+	CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+	CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+	CLK_DUPLICATE("twd", "smp_twd", NULL),
+	CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+	CLK_DUPLICATE("i2s0", NULL, "i2s0"),
+	CLK_DUPLICATE("i2s1", NULL, "i2s1"),
+	CLK_DUPLICATE("i2s2", NULL, "i2s2"),
+	CLK_DUPLICATE("i2s3", NULL, "i2s3"),
+	CLK_DUPLICATE("i2s4", NULL, "i2s4"),
+	CLK_DUPLICATE("dam0", NULL, "dam0"),
+	CLK_DUPLICATE("dam1", NULL, "dam1"),
+	CLK_DUPLICATE("dam2", NULL, "dam2"),
+	CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
+};
+
+struct clk *tegra_ptr_clks[] = {
+	&tegra_clk_32k,
+	&tegra_clk_m,
+	&tegra_clk_m_div2,
+	&tegra_clk_m_div4,
+	&tegra_pll_ref,
+	&tegra_pll_m,
+	&tegra_pll_m_out1,
+	&tegra_pll_c,
+	&tegra_pll_c_out1,
+	&tegra_pll_p,
+	&tegra_pll_p_out1,
+	&tegra_pll_p_out2,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out4,
+	&tegra_pll_a,
+	&tegra_pll_a_out0,
+	&tegra_pll_d,
+	&tegra_pll_d_out0,
+	&tegra_pll_d2,
+	&tegra_pll_d2_out0,
+	&tegra_pll_u,
+	&tegra_pll_x,
+	&tegra_pll_x_out0,
+	&tegra_pll_e,
+	&tegra_clk_cclk_g,
+	&tegra_cml0,
+	&tegra_cml1,
+	&tegra_pciex,
+	&tegra_clk_sclk,
+	&tegra_clk_blink,
+	&tegra30_clk_twd,
+};
+
+static void tegra30_init_one_clock(struct clk *c)
+{
+	struct clk_tegra *clk = to_clk_tegra(c->hw);
+	__clk_init(NULL, c);
+	INIT_LIST_HEAD(&clk->shared_bus_list);
+	if (!clk->lookup.dev_id && !clk->lookup.con_id)
+		clk->lookup.con_id = c->name;
+	clk->lookup.clk = c;
+	clkdev_add(&clk->lookup);
+	tegra_clk_add(c);
+}
+
+void __init tegra30_init_clocks(void)
+{
+	int i;
+	struct clk *c;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+		tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+		tegra30_init_one_clock(tegra_list_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+		if (!c) {
+			pr_err("%s: Unknown duplicate clock %s\n", __func__,
+				tegra_clk_duplicates[i].name);
+			continue;
+		}
+
+		tegra_clk_duplicates[i].lookup.clk = c;
+		clkdev_add(&tegra_clk_duplicates[i].lookup);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+		tegra30_init_one_clock(tegra_sync_source_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+		tegra30_init_one_clock(tegra_clk_audio_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+		tegra30_init_one_clock(tegra_clk_audio_2x_list[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+		tegra30_init_one_clock(tegra_clk_out_list[i]);
+
+	tegra30_cpu_car_ops_init();
+}
diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h
new file mode 100644
index 0000000..30d063a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra_cpu_car.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_CPU_CAR_H
+#define __MACH_TEGRA_CPU_CAR_H
+
+/*
+ * Tegra CPU clock and reset control ops
+ *
+ * wait_for_reset:
+ *	keep waiting until the CPU in reset state
+ * put_in_reset:
+ *	put the CPU in reset state
+ * out_of_reset:
+ *	release the CPU from reset state
+ * enable_clock:
+ *	CPU clock un-gate
+ * disable_clock:
+ *	CPU clock gate
+ */
+struct tegra_cpu_car_ops {
+	void (*wait_for_reset)(u32 cpu);
+	void (*put_in_reset)(u32 cpu);
+	void (*out_of_reset)(u32 cpu);
+	void (*enable_clock)(u32 cpu);
+	void (*disable_clock)(u32 cpu);
+};
+
+extern struct tegra_cpu_car_ops *tegra_cpu_car_ops;
+
+static inline void tegra_wait_cpu_in_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->wait_for_reset))
+		return;
+
+	tegra_cpu_car_ops->wait_for_reset(cpu);
+}
+
+static inline void tegra_put_cpu_in_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->put_in_reset))
+		return;
+
+	tegra_cpu_car_ops->put_in_reset(cpu);
+}
+
+static inline void tegra_cpu_out_of_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->out_of_reset))
+		return;
+
+	tegra_cpu_car_ops->out_of_reset(cpu);
+}
+
+static inline void tegra_enable_cpu_clock(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->enable_clock))
+		return;
+
+	tegra_cpu_car_ops->enable_clock(cpu);
+}
+
+static inline void tegra_disable_cpu_clock(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->disable_clock))
+		return;
+
+	tegra_cpu_car_ops->disable_clock(cpu);
+}
+
+void tegra20_cpu_car_ops_init(void);
+void tegra30_cpu_car_ops_init(void);
+
+#endif /* __MACH_TEGRA_CPU_CAR_H */
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
deleted file mode 100644
index 022b33a..0000000
--- a/arch/arm/mach-tegra/usb_phy.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * arch/arm/mach-tegra/usb_phy.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Erik Gilling <konkers@google.com>
- *	Benoit Goby <benoit@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/resource.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <asm/mach-types.h>
-#include <mach/gpio-tegra.h>
-#include <mach/usb_phy.h>
-#include <mach/iomap.h>
-
-#define ULPI_VIEWPORT		0x170
-
-#define USB_PORTSC1		0x184
-#define   USB_PORTSC1_PTS(x)	(((x) & 0x3) << 30)
-#define   USB_PORTSC1_PSPD(x)	(((x) & 0x3) << 26)
-#define   USB_PORTSC1_PHCD	(1 << 23)
-#define   USB_PORTSC1_WKOC	(1 << 22)
-#define   USB_PORTSC1_WKDS	(1 << 21)
-#define   USB_PORTSC1_WKCN	(1 << 20)
-#define   USB_PORTSC1_PTC(x)	(((x) & 0xf) << 16)
-#define   USB_PORTSC1_PP	(1 << 12)
-#define   USB_PORTSC1_SUSP	(1 << 7)
-#define   USB_PORTSC1_PE	(1 << 2)
-#define   USB_PORTSC1_CCS	(1 << 0)
-
-#define USB_SUSP_CTRL		0x400
-#define   USB_WAKE_ON_CNNT_EN_DEV	(1 << 3)
-#define   USB_WAKE_ON_DISCON_EN_DEV	(1 << 4)
-#define   USB_SUSP_CLR		(1 << 5)
-#define   USB_PHY_CLK_VALID	(1 << 7)
-#define   UTMIP_RESET			(1 << 11)
-#define   UHSIC_RESET			(1 << 11)
-#define   UTMIP_PHY_ENABLE		(1 << 12)
-#define   ULPI_PHY_ENABLE	(1 << 13)
-#define   USB_SUSP_SET		(1 << 14)
-#define   USB_WAKEUP_DEBOUNCE_COUNT(x)	(((x) & 0x7) << 16)
-
-#define USB1_LEGACY_CTRL	0x410
-#define   USB1_NO_LEGACY_MODE			(1 << 0)
-#define   USB1_VBUS_SENSE_CTL_MASK		(3 << 1)
-#define   USB1_VBUS_SENSE_CTL_VBUS_WAKEUP	(0 << 1)
-#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
-						(1 << 1)
-#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD	(2 << 1)
-#define   USB1_VBUS_SENSE_CTL_A_SESS_VLD	(3 << 1)
-
-#define ULPI_TIMING_CTRL_0	0x424
-#define   ULPI_OUTPUT_PINMUX_BYP	(1 << 10)
-#define   ULPI_CLKOUT_PINMUX_BYP	(1 << 11)
-
-#define ULPI_TIMING_CTRL_1	0x428
-#define   ULPI_DATA_TRIMMER_LOAD	(1 << 0)
-#define   ULPI_DATA_TRIMMER_SEL(x)	(((x) & 0x7) << 1)
-#define   ULPI_STPDIRNXT_TRIMMER_LOAD	(1 << 16)
-#define   ULPI_STPDIRNXT_TRIMMER_SEL(x)	(((x) & 0x7) << 17)
-#define   ULPI_DIR_TRIMMER_LOAD		(1 << 24)
-#define   ULPI_DIR_TRIMMER_SEL(x)	(((x) & 0x7) << 25)
-
-#define UTMIP_PLL_CFG1		0x804
-#define   UTMIP_XTAL_FREQ_COUNT(x)		(((x) & 0xfff) << 0)
-#define   UTMIP_PLLU_ENABLE_DLY_COUNT(x)	(((x) & 0x1f) << 27)
-
-#define UTMIP_XCVR_CFG0		0x808
-#define   UTMIP_XCVR_SETUP(x)			(((x) & 0xf) << 0)
-#define   UTMIP_XCVR_LSRSLEW(x)			(((x) & 0x3) << 8)
-#define   UTMIP_XCVR_LSFSLEW(x)			(((x) & 0x3) << 10)
-#define   UTMIP_FORCE_PD_POWERDOWN		(1 << 14)
-#define   UTMIP_FORCE_PD2_POWERDOWN		(1 << 16)
-#define   UTMIP_FORCE_PDZI_POWERDOWN		(1 << 18)
-#define   UTMIP_XCVR_HSSLEW_MSB(x)		(((x) & 0x7f) << 25)
-
-#define UTMIP_BIAS_CFG0		0x80c
-#define   UTMIP_OTGPD			(1 << 11)
-#define   UTMIP_BIASPD			(1 << 10)
-
-#define UTMIP_HSRX_CFG0		0x810
-#define   UTMIP_ELASTIC_LIMIT(x)	(((x) & 0x1f) << 10)
-#define   UTMIP_IDLE_WAIT(x)		(((x) & 0x1f) << 15)
-
-#define UTMIP_HSRX_CFG1		0x814
-#define   UTMIP_HS_SYNC_START_DLY(x)	(((x) & 0x1f) << 1)
-
-#define UTMIP_TX_CFG0		0x820
-#define   UTMIP_FS_PREABMLE_J		(1 << 19)
-#define   UTMIP_HS_DISCON_DISABLE	(1 << 8)
-
-#define UTMIP_MISC_CFG0		0x824
-#define   UTMIP_DPDM_OBSERVE		(1 << 26)
-#define   UTMIP_DPDM_OBSERVE_SEL(x)	(((x) & 0xf) << 27)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_J	UTMIP_DPDM_OBSERVE_SEL(0xf)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_K	UTMIP_DPDM_OBSERVE_SEL(0xe)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
-#define   UTMIP_SUSPEND_EXIT_ON_EDGE	(1 << 22)
-
-#define UTMIP_MISC_CFG1		0x828
-#define   UTMIP_PLL_ACTIVE_DLY_COUNT(x)	(((x) & 0x1f) << 18)
-#define   UTMIP_PLLU_STABLE_COUNT(x)	(((x) & 0xfff) << 6)
-
-#define UTMIP_DEBOUNCE_CFG0	0x82c
-#define   UTMIP_BIAS_DEBOUNCE_A(x)	(((x) & 0xffff) << 0)
-
-#define UTMIP_BAT_CHRG_CFG0	0x830
-#define   UTMIP_PD_CHRG			(1 << 0)
-
-#define UTMIP_SPARE_CFG0	0x834
-#define   FUSE_SETUP_SEL		(1 << 3)
-
-#define UTMIP_XCVR_CFG1		0x838
-#define   UTMIP_FORCE_PDDISC_POWERDOWN	(1 << 0)
-#define   UTMIP_FORCE_PDCHRP_POWERDOWN	(1 << 2)
-#define   UTMIP_FORCE_PDDR_POWERDOWN	(1 << 4)
-#define   UTMIP_XCVR_TERM_RANGE_ADJ(x)	(((x) & 0xf) << 18)
-
-#define UTMIP_BIAS_CFG1		0x83c
-#define   UTMIP_BIAS_PDTRK_COUNT(x)	(((x) & 0x1f) << 3)
-
-static DEFINE_SPINLOCK(utmip_pad_lock);
-static int utmip_pad_count;
-
-struct tegra_xtal_freq {
-	int freq;
-	u8 enable_delay;
-	u8 stable_count;
-	u8 active_delay;
-	u8 xtal_freq_count;
-	u16 debounce;
-};
-
-static const struct tegra_xtal_freq tegra_freq_table[] = {
-	{
-		.freq = 12000000,
-		.enable_delay = 0x02,
-		.stable_count = 0x2F,
-		.active_delay = 0x04,
-		.xtal_freq_count = 0x76,
-		.debounce = 0x7530,
-	},
-	{
-		.freq = 13000000,
-		.enable_delay = 0x02,
-		.stable_count = 0x33,
-		.active_delay = 0x05,
-		.xtal_freq_count = 0x7F,
-		.debounce = 0x7EF4,
-	},
-	{
-		.freq = 19200000,
-		.enable_delay = 0x03,
-		.stable_count = 0x4B,
-		.active_delay = 0x06,
-		.xtal_freq_count = 0xBB,
-		.debounce = 0xBB80,
-	},
-	{
-		.freq = 26000000,
-		.enable_delay = 0x04,
-		.stable_count = 0x66,
-		.active_delay = 0x09,
-		.xtal_freq_count = 0xFE,
-		.debounce = 0xFDE8,
-	},
-};
-
-static struct tegra_utmip_config utmip_default[] = {
-	[0] = {
-		.hssync_start_delay = 9,
-		.idle_wait_delay = 17,
-		.elastic_limit = 16,
-		.term_range_adj = 6,
-		.xcvr_setup = 9,
-		.xcvr_lsfslew = 1,
-		.xcvr_lsrslew = 1,
-	},
-	[2] = {
-		.hssync_start_delay = 9,
-		.idle_wait_delay = 17,
-		.elastic_limit = 16,
-		.term_range_adj = 6,
-		.xcvr_setup = 9,
-		.xcvr_lsfslew = 2,
-		.xcvr_lsrslew = 2,
-	},
-};
-
-static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
-{
-	return (phy->instance == 1);
-}
-
-static int utmip_pad_open(struct tegra_usb_phy *phy)
-{
-	phy->pad_clk = clk_get_sys("utmip-pad", NULL);
-	if (IS_ERR(phy->pad_clk)) {
-		pr_err("%s: can't get utmip pad clock\n", __func__);
-		return PTR_ERR(phy->pad_clk);
-	}
-
-	if (phy->instance == 0) {
-		phy->pad_regs = phy->regs;
-	} else {
-		phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
-		if (!phy->pad_regs) {
-			pr_err("%s: can't remap usb registers\n", __func__);
-			clk_put(phy->pad_clk);
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-static void utmip_pad_close(struct tegra_usb_phy *phy)
-{
-	if (phy->instance != 0)
-		iounmap(phy->pad_regs);
-	clk_put(phy->pad_clk);
-}
-
-static void utmip_pad_power_on(struct tegra_usb_phy *phy)
-{
-	unsigned long val, flags;
-	void __iomem *base = phy->pad_regs;
-
-	clk_prepare_enable(phy->pad_clk);
-
-	spin_lock_irqsave(&utmip_pad_lock, flags);
-
-	if (utmip_pad_count++ == 0) {
-		val = readl(base + UTMIP_BIAS_CFG0);
-		val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
-		writel(val, base + UTMIP_BIAS_CFG0);
-	}
-
-	spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
-	clk_disable_unprepare(phy->pad_clk);
-}
-
-static int utmip_pad_power_off(struct tegra_usb_phy *phy)
-{
-	unsigned long val, flags;
-	void __iomem *base = phy->pad_regs;
-
-	if (!utmip_pad_count) {
-		pr_err("%s: utmip pad already powered off\n", __func__);
-		return -EINVAL;
-	}
-
-	clk_prepare_enable(phy->pad_clk);
-
-	spin_lock_irqsave(&utmip_pad_lock, flags);
-
-	if (--utmip_pad_count == 0) {
-		val = readl(base + UTMIP_BIAS_CFG0);
-		val |= UTMIP_OTGPD | UTMIP_BIASPD;
-		writel(val, base + UTMIP_BIAS_CFG0);
-	}
-
-	spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
-	clk_disable_unprepare(phy->pad_clk);
-
-	return 0;
-}
-
-static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
-{
-	unsigned long timeout = 2000;
-	do {
-		if ((readl(reg) & mask) == result)
-			return 0;
-		udelay(1);
-		timeout--;
-	} while (timeout);
-	return -1;
-}
-
-static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	if (phy->instance == 0) {
-		val = readl(base + USB_SUSP_CTRL);
-		val |= USB_SUSP_SET;
-		writel(val, base + USB_SUSP_CTRL);
-
-		udelay(10);
-
-		val = readl(base + USB_SUSP_CTRL);
-		val &= ~USB_SUSP_SET;
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	if (phy->instance == 2) {
-		val = readl(base + USB_PORTSC1);
-		val |= USB_PORTSC1_PHCD;
-		writel(val, base + USB_PORTSC1);
-	}
-
-	if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
-		pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-}
-
-static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	if (phy->instance == 0) {
-		val = readl(base + USB_SUSP_CTRL);
-		val |= USB_SUSP_CLR;
-		writel(val, base + USB_SUSP_CTRL);
-
-		udelay(10);
-
-		val = readl(base + USB_SUSP_CTRL);
-		val &= ~USB_SUSP_CLR;
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	if (phy->instance == 2) {
-		val = readl(base + USB_PORTSC1);
-		val &= ~USB_PORTSC1_PHCD;
-		writel(val, base + USB_PORTSC1);
-	}
-
-	if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
-						     USB_PHY_CLK_VALID))
-		pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-}
-
-static int utmi_phy_power_on(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-	struct tegra_utmip_config *config = phy->config;
-
-	val = readl(base + USB_SUSP_CTRL);
-	val |= UTMIP_RESET;
-	writel(val, base + USB_SUSP_CTRL);
-
-	if (phy->instance == 0) {
-		val = readl(base + USB1_LEGACY_CTRL);
-		val |= USB1_NO_LEGACY_MODE;
-		writel(val, base + USB1_LEGACY_CTRL);
-	}
-
-	val = readl(base + UTMIP_TX_CFG0);
-	val &= ~UTMIP_FS_PREABMLE_J;
-	writel(val, base + UTMIP_TX_CFG0);
-
-	val = readl(base + UTMIP_HSRX_CFG0);
-	val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
-	val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
-	val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
-	writel(val, base + UTMIP_HSRX_CFG0);
-
-	val = readl(base + UTMIP_HSRX_CFG1);
-	val &= ~UTMIP_HS_SYNC_START_DLY(~0);
-	val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
-	writel(val, base + UTMIP_HSRX_CFG1);
-
-	val = readl(base + UTMIP_DEBOUNCE_CFG0);
-	val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
-	val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
-	writel(val, base + UTMIP_DEBOUNCE_CFG0);
-
-	val = readl(base + UTMIP_MISC_CFG0);
-	val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
-	writel(val, base + UTMIP_MISC_CFG0);
-
-	val = readl(base + UTMIP_MISC_CFG1);
-	val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
-	val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
-		UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
-	writel(val, base + UTMIP_MISC_CFG1);
-
-	val = readl(base + UTMIP_PLL_CFG1);
-	val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
-	val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
-		UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
-	writel(val, base + UTMIP_PLL_CFG1);
-
-	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
-		val = readl(base + USB_SUSP_CTRL);
-		val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	utmip_pad_power_on(phy);
-
-	val = readl(base + UTMIP_XCVR_CFG0);
-	val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-		 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
-		 UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
-		 UTMIP_XCVR_HSSLEW_MSB(~0));
-	val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
-	val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
-	val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
-	writel(val, base + UTMIP_XCVR_CFG0);
-
-	val = readl(base + UTMIP_XCVR_CFG1);
-	val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
-		 UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
-	val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
-	writel(val, base + UTMIP_XCVR_CFG1);
-
-	val = readl(base + UTMIP_BAT_CHRG_CFG0);
-	val &= ~UTMIP_PD_CHRG;
-	writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
-	val = readl(base + UTMIP_BIAS_CFG1);
-	val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
-	val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
-	writel(val, base + UTMIP_BIAS_CFG1);
-
-	if (phy->instance == 0) {
-		val = readl(base + UTMIP_SPARE_CFG0);
-		if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
-			val &= ~FUSE_SETUP_SEL;
-		else
-			val |= FUSE_SETUP_SEL;
-		writel(val, base + UTMIP_SPARE_CFG0);
-	}
-
-	if (phy->instance == 2) {
-		val = readl(base + USB_SUSP_CTRL);
-		val |= UTMIP_PHY_ENABLE;
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	val = readl(base + USB_SUSP_CTRL);
-	val &= ~UTMIP_RESET;
-	writel(val, base + USB_SUSP_CTRL);
-
-	if (phy->instance == 0) {
-		val = readl(base + USB1_LEGACY_CTRL);
-		val &= ~USB1_VBUS_SENSE_CTL_MASK;
-		val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
-		writel(val, base + USB1_LEGACY_CTRL);
-
-		val = readl(base + USB_SUSP_CTRL);
-		val &= ~USB_SUSP_SET;
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	utmi_phy_clk_enable(phy);
-
-	if (phy->instance == 2) {
-		val = readl(base + USB_PORTSC1);
-		val &= ~USB_PORTSC1_PTS(~0);
-		writel(val, base + USB_PORTSC1);
-	}
-
-	return 0;
-}
-
-static void utmi_phy_power_off(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	utmi_phy_clk_disable(phy);
-
-	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
-		val = readl(base + USB_SUSP_CTRL);
-		val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
-		val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
-		writel(val, base + USB_SUSP_CTRL);
-	}
-
-	val = readl(base + USB_SUSP_CTRL);
-	val |= UTMIP_RESET;
-	writel(val, base + USB_SUSP_CTRL);
-
-	val = readl(base + UTMIP_BAT_CHRG_CFG0);
-	val |= UTMIP_PD_CHRG;
-	writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
-	val = readl(base + UTMIP_XCVR_CFG0);
-	val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-	       UTMIP_FORCE_PDZI_POWERDOWN;
-	writel(val, base + UTMIP_XCVR_CFG0);
-
-	val = readl(base + UTMIP_XCVR_CFG1);
-	val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
-	       UTMIP_FORCE_PDDR_POWERDOWN;
-	writel(val, base + UTMIP_XCVR_CFG1);
-
-	utmip_pad_power_off(phy);
-}
-
-static void utmi_phy_preresume(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	val = readl(base + UTMIP_TX_CFG0);
-	val |= UTMIP_HS_DISCON_DISABLE;
-	writel(val, base + UTMIP_TX_CFG0);
-}
-
-static void utmi_phy_postresume(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	val = readl(base + UTMIP_TX_CFG0);
-	val &= ~UTMIP_HS_DISCON_DISABLE;
-	writel(val, base + UTMIP_TX_CFG0);
-}
-
-static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
-				   enum tegra_usb_phy_port_speed port_speed)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	val = readl(base + UTMIP_MISC_CFG0);
-	val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
-	if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
-		val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
-	else
-		val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
-	writel(val, base + UTMIP_MISC_CFG0);
-	udelay(1);
-
-	val = readl(base + UTMIP_MISC_CFG0);
-	val |= UTMIP_DPDM_OBSERVE;
-	writel(val, base + UTMIP_MISC_CFG0);
-	udelay(10);
-}
-
-static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-
-	val = readl(base + UTMIP_MISC_CFG0);
-	val &= ~UTMIP_DPDM_OBSERVE;
-	writel(val, base + UTMIP_MISC_CFG0);
-	udelay(10);
-}
-
-static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
-{
-	int ret;
-	unsigned long val;
-	void __iomem *base = phy->regs;
-	struct tegra_ulpi_config *config = phy->config;
-
-	gpio_direction_output(config->reset_gpio, 0);
-	msleep(5);
-	gpio_direction_output(config->reset_gpio, 1);
-
-	clk_prepare_enable(phy->clk);
-	msleep(1);
-
-	val = readl(base + USB_SUSP_CTRL);
-	val |= UHSIC_RESET;
-	writel(val, base + USB_SUSP_CTRL);
-
-	val = readl(base + ULPI_TIMING_CTRL_0);
-	val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
-	writel(val, base + ULPI_TIMING_CTRL_0);
-
-	val = readl(base + USB_SUSP_CTRL);
-	val |= ULPI_PHY_ENABLE;
-	writel(val, base + USB_SUSP_CTRL);
-
-	val = 0;
-	writel(val, base + ULPI_TIMING_CTRL_1);
-
-	val |= ULPI_DATA_TRIMMER_SEL(4);
-	val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
-	val |= ULPI_DIR_TRIMMER_SEL(4);
-	writel(val, base + ULPI_TIMING_CTRL_1);
-	udelay(10);
-
-	val |= ULPI_DATA_TRIMMER_LOAD;
-	val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
-	val |= ULPI_DIR_TRIMMER_LOAD;
-	writel(val, base + ULPI_TIMING_CTRL_1);
-
-	/* Fix VbusInvalid due to floating VBUS */
-	ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
-	if (ret) {
-		pr_err("%s: ulpi write failed\n", __func__);
-		return ret;
-	}
-
-	ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
-	if (ret) {
-		pr_err("%s: ulpi write failed\n", __func__);
-		return ret;
-	}
-
-	val = readl(base + USB_PORTSC1);
-	val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
-	writel(val, base + USB_PORTSC1);
-
-	val = readl(base + USB_SUSP_CTRL);
-	val |= USB_SUSP_CLR;
-	writel(val, base + USB_SUSP_CTRL);
-	udelay(100);
-
-	val = readl(base + USB_SUSP_CTRL);
-	val &= ~USB_SUSP_CLR;
-	writel(val, base + USB_SUSP_CTRL);
-
-	return 0;
-}
-
-static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
-{
-	unsigned long val;
-	void __iomem *base = phy->regs;
-	struct tegra_ulpi_config *config = phy->config;
-
-	/* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
-	 * Controller to immediately bring the ULPI PHY out of low power
-	 */
-	val = readl(base + USB_PORTSC1);
-	val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
-	writel(val, base + USB_PORTSC1);
-
-	gpio_direction_output(config->reset_gpio, 0);
-	clk_disable(phy->clk);
-}
-
-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
-	void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
-{
-	struct tegra_usb_phy *phy;
-	struct tegra_ulpi_config *ulpi_config;
-	unsigned long parent_rate;
-	int i;
-	int err;
-
-	phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
-	if (!phy)
-		return ERR_PTR(-ENOMEM);
-
-	phy->instance = instance;
-	phy->regs = regs;
-	phy->config = config;
-	phy->mode = phy_mode;
-
-	if (!phy->config) {
-		if (phy_is_ulpi(phy)) {
-			pr_err("%s: ulpi phy configuration missing", __func__);
-			err = -EINVAL;
-			goto err0;
-		} else {
-			phy->config = &utmip_default[instance];
-		}
-	}
-
-	phy->pll_u = clk_get_sys(NULL, "pll_u");
-	if (IS_ERR(phy->pll_u)) {
-		pr_err("Can't get pll_u clock\n");
-		err = PTR_ERR(phy->pll_u);
-		goto err0;
-	}
-	clk_prepare_enable(phy->pll_u);
-
-	parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
-	for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
-		if (tegra_freq_table[i].freq == parent_rate) {
-			phy->freq = &tegra_freq_table[i];
-			break;
-		}
-	}
-	if (!phy->freq) {
-		pr_err("invalid pll_u parent rate %ld\n", parent_rate);
-		err = -EINVAL;
-		goto err1;
-	}
-
-	if (phy_is_ulpi(phy)) {
-		ulpi_config = config;
-		phy->clk = clk_get_sys(NULL, ulpi_config->clk);
-		if (IS_ERR(phy->clk)) {
-			pr_err("%s: can't get ulpi clock\n", __func__);
-			err = -ENXIO;
-			goto err1;
-		}
-		if (!gpio_is_valid(ulpi_config->reset_gpio))
-			ulpi_config->reset_gpio =
-				of_get_named_gpio(dev->of_node,
-						  "nvidia,phy-reset-gpio", 0);
-		if (!gpio_is_valid(ulpi_config->reset_gpio)) {
-			pr_err("%s: invalid reset gpio: %d\n", __func__,
-			       ulpi_config->reset_gpio);
-			err = -EINVAL;
-			goto err1;
-		}
-		gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
-		gpio_direction_output(ulpi_config->reset_gpio, 0);
-		phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
-		phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
-	} else {
-		err = utmip_pad_open(phy);
-		if (err < 0)
-			goto err1;
-	}
-
-	return phy;
-
-err1:
-	clk_disable_unprepare(phy->pll_u);
-	clk_put(phy->pll_u);
-err0:
-	kfree(phy);
-	return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
-{
-	if (phy_is_ulpi(phy))
-		return ulpi_phy_power_on(phy);
-	else
-		return utmi_phy_power_on(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
-{
-	if (phy_is_ulpi(phy))
-		ulpi_phy_power_off(phy);
-	else
-		utmi_phy_power_off(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_preresume(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_postresume(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
-
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
-				 enum tegra_usb_phy_port_speed port_speed)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_restore_start(phy, port_speed);
-}
-EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_restore_end(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
-
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_clk_disable(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
-
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
-{
-	if (!phy_is_ulpi(phy))
-		utmi_phy_clk_enable(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
-
-void tegra_usb_phy_close(struct tegra_usb_phy *phy)
-{
-	if (phy_is_ulpi(phy))
-		clk_put(phy->clk);
-	else
-		utmip_pad_close(phy);
-	clk_disable_unprepare(phy->pll_u);
-	clk_put(phy->pll_u);
-	kfree(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index 54d8f34..f7e12ed 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -1,6 +1,6 @@
 if ARCH_U300
 
-menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+menu "ST-Ericsson AB U300/U335 Platform"
 
 comment "ST-Ericsson Mobile Platform Products"
 
@@ -10,46 +10,7 @@
 	select PINCTRL_U300
 	select PINCTRL_COH901
 
-comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
-
-choice
-	prompt "U300/U330/U335/U365 system type"
-	default MACH_U300_BS2X
-	---help---
-	You need to select the target system, i.e. the
-	U300/U330/U335/U365 board that you want to compile your kernel
-	for.
-
-config MACH_U300_BS2X
-	bool "S26/S26/B25/B26 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S26/S25 test products. (Also works on
-		B26/B25 big boards.)
-
-config MACH_U300_BS330
-	bool "S330/B330 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S330/B330 test products.
-
-config MACH_U300_BS335
-	bool "S335/B335 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S335/B335 test products.
-
-config MACH_U300_BS365
-	bool "S365/B365 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S365/B365 test products.
-
-endchoice
+comment "ST-Ericsson U300/U335 Feature Selections"
 
 config U300_DEBUG
 	bool "Debug support for U300"
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 7e47d37..5a86c58 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -7,7 +7,6 @@
 obj-n		:=
 obj-		:=
 
-obj-$(CONFIG_ARCH_U300)	          += u300.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 03acf18..ef6f602 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/core.c
  *
  *
- * Copyright (C) 2007-2010 ST-Ericsson SA
+ * Copyright (C) 2007-2012 ST-Ericsson SA
  * License terms: GNU General Public License (GPL) version 2
  * Core platform support, IRQ handling and device definitions.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -31,23 +31,26 @@
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/clk-u300.h>
+#include <linux/platform_data/pinctrl-coh901.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/hardware/vic.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
 
 #include <mach/coh901318.h>
 #include <mach/hardware.h>
 #include <mach/syscon.h>
-#include <mach/dma_channels.h>
-#include <mach/gpio-u300.h>
+#include <mach/irqs.h>
 
+#include "timer.h"
 #include "spi.h"
 #include "i2c.h"
 #include "u300-gpio.h"
+#include "dma_channels.h"
 
 /*
  * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -76,7 +79,7 @@
 	},
 };
 
-void __init u300_map_io(void)
+static void __init u300_map_io(void)
 {
 	iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
 	/* We enable a real big DMA buffer if need be. */
@@ -101,7 +104,6 @@
 	{ IRQ_U300_UART0 }, &uart0_plat_data);
 
 /* The U335 have an additional UART1 on the APP CPU */
-#ifdef CONFIG_MACH_U300_BS335
 static struct amba_pl011_data uart1_plat_data = {
 #ifdef CONFIG_COH901318
 	.dma_filter = coh901318_filter_id,
@@ -113,7 +115,6 @@
 /* Fast device at 0x7000 offset */
 static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
 	{ IRQ_U300_UART1 }, &uart1_plat_data);
-#endif
 
 /* AHB device at 0x4000 offset */
 static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
@@ -152,9 +153,7 @@
  */
 static struct amba_device *amba_devs[] __initdata = {
 	&uart0_device,
-#ifdef CONFIG_MACH_U300_BS335
 	&uart1_device,
-#endif
 	&pl022_device,
 	&pl172_device,
 	&mmcsd_device,
@@ -188,7 +187,6 @@
 		.end   = IRQ_U300_GPIO_PORT2,
 		.flags = IORESOURCE_IRQ,
 	},
-#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335)
 	{
 		.name  = "gpio3",
 		.start = IRQ_U300_GPIO_PORT3,
@@ -201,8 +199,6 @@
 		.end   = IRQ_U300_GPIO_PORT4,
 		.flags = IORESOURCE_IRQ,
 	},
-#endif
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.name  = "gpio5",
 		.start = IRQ_U300_GPIO_PORT5,
@@ -215,7 +211,6 @@
 		.end   = IRQ_U300_GPIO_PORT6,
 		.flags = IORESOURCE_IRQ,
 	},
-#endif /* CONFIG_MACH_U300_BS335 */
 };
 
 static struct resource keypad_resources[] = {
@@ -323,7 +318,6 @@
 	}
 };
 
-#ifdef CONFIG_MACH_U300_BS335
 /* points out all dma slave channels.
  * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
  * Select all channels from A to B, end of list is marked with -1,-1
@@ -336,14 +330,6 @@
 static int dma_memcpy_channels[] = {
 	U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
 
-#else /* CONFIG_MACH_U300_BS335 */
-
-static int dma_slave_channels[] = {U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, -1, -1};
-static int dma_memcpy_channels[] = {
-	U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_10, -1, -1};
-
-#endif
-
 /** register dma for memory access
  *
  * active  1 means dma intends to access memory
@@ -1395,7 +1381,6 @@
 		.param.ctrl_lli = flags_memcpy_lli,
 		.param.ctrl_lli_last = flags_memcpy_lli_last,
 	},
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.number = U300_DMA_UART1_TX,
 		.name = "UART1 TX",
@@ -1406,28 +1391,6 @@
 		.name = "UART1 RX",
 		.priority_high = 0,
 	}
-#else
-	{
-		.number = U300_DMA_GENERAL_PURPOSE_9,
-		.name = "GENERAL 09",
-		.priority_high = 0,
-
-		.param.config = flags_memcpy_config,
-		.param.ctrl_lli_chained = flags_memcpy_lli_chained,
-		.param.ctrl_lli = flags_memcpy_lli,
-		.param.ctrl_lli_last = flags_memcpy_lli_last,
-	},
-	{
-		.number = U300_DMA_GENERAL_PURPOSE_10,
-		.name = "GENERAL 10",
-		.priority_high = 0,
-
-		.param.config = flags_memcpy_config,
-		.param.ctrl_lli_chained = flags_memcpy_lli_chained,
-		.param.ctrl_lli = flags_memcpy_lli,
-		.param.ctrl_lli_last = flags_memcpy_lli_last,
-	}
-#endif
 };
 
 
@@ -1480,18 +1443,7 @@
  * GPIO block, with different number of ports.
  */
 static struct u300_gpio_platform u300_gpio_plat = {
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-	.variant = U300_GPIO_COH901335,
-	.ports = 3,
-#endif
-#ifdef CONFIG_MACH_U300_BS335
-	.variant = U300_GPIO_COH901571_3_BS335,
 	.ports = 7,
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-	.variant = U300_GPIO_COH901571_3_BS365,
-	.ports = 5,
-#endif
 	.gpio_base = 0,
 	.gpio_irq_base = IRQ_U300_GPIO_BASE,
 	.pinctrl_device = &pinctrl_device,
@@ -1651,7 +1603,7 @@
  * together so some interrupts are connected to the first one and some
  * to the second one.
  */
-void __init u300_init_irq(void)
+static void __init u300_init_irq(void)
 {
 	u32 mask[2] = {0, 0};
 	struct clk *clk;
@@ -1756,29 +1708,11 @@
 	printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
 	       "(chip ID 0x%04x)\n", chipname, val);
 
-#ifdef CONFIG_MACH_U300_BS330
-	if ((val & 0xFF00U) != 0xd800) {
-		printk(KERN_ERR "Platform configured for BS330 " \
-		       "with DB3200 but %s detected, expect problems!",
-		       chipname);
-	}
-#endif
-#ifdef CONFIG_MACH_U300_BS335
 	if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
 		printk(KERN_ERR "Platform configured for BS335 " \
 		       " with DB3350 but %s detected, expect problems!",
 		       chipname);
 	}
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-	if ((val & 0xFF00U) != 0xe800) {
-		printk(KERN_ERR "Platform configured for BS365 " \
-		       "with DB3210 but %s detected, expect problems!",
-		       chipname);
-	}
-#endif
-
-
 }
 
 /*
@@ -1811,7 +1745,7 @@
 	}
 }
 
-void __init u300_init_devices(void)
+static void __init u300_init_machine(void)
 {
 	int i;
 	u16 val;
@@ -1852,7 +1786,7 @@
 /* Forward declare this function from the watchdog */
 void coh901327_watchdog_reset(void);
 
-void u300_restart(char mode, const char *cmd)
+static void u300_restart(char mode, const char *cmd)
 {
 	switch (mode) {
 	case 's':
@@ -1868,3 +1802,15 @@
 	/* Wait for system do die/reset. */
 	while (1);
 }
+
+MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
+	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
+	.atag_offset	= 0x100,
+	.map_io		= u300_map_io,
+	.nr_irqs	= NR_IRQS_U300,
+	.init_irq	= u300_init_irq,
+	.handle_irq	= vic_handle_irq,
+	.timer		= &u300_timer,
+	.init_machine	= u300_init_machine,
+	.restart	= u300_restart,
+MACHINE_END
diff --git a/arch/arm/mach-u300/dma_channels.h b/arch/arm/mach-u300/dma_channels.h
new file mode 100644
index 0000000..4e8a88f
--- /dev/null
+++ b/arch/arm/mach-u300/dma_channels.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/dma_channels.h
+ *
+ *
+ * Copyright (C) 2007-2012 ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ * Map file for the U300 dma driver.
+ * Author: Per Friden <per.friden@stericsson.com>
+ */
+
+#ifndef DMA_CHANNELS_H
+#define DMA_CHANNELS_H
+
+#define U300_DMA_MSL_TX_0             0
+#define U300_DMA_MSL_TX_1             1
+#define U300_DMA_MSL_TX_2             2
+#define U300_DMA_MSL_TX_3             3
+#define U300_DMA_MSL_TX_4             4
+#define U300_DMA_MSL_TX_5             5
+#define U300_DMA_MSL_TX_6             6
+#define U300_DMA_MSL_RX_0             7
+#define U300_DMA_MSL_RX_1             8
+#define U300_DMA_MSL_RX_2             9
+#define U300_DMA_MSL_RX_3             10
+#define U300_DMA_MSL_RX_4             11
+#define U300_DMA_MSL_RX_5             12
+#define U300_DMA_MSL_RX_6             13
+#define U300_DMA_MMCSD_RX_TX          14
+#define U300_DMA_MSPRO_TX             15
+#define U300_DMA_MSPRO_RX             16
+#define U300_DMA_UART0_TX             17
+#define U300_DMA_UART0_RX             18
+#define U300_DMA_APEX_TX              19
+#define U300_DMA_APEX_RX              20
+#define U300_DMA_PCM_I2S0_TX          21
+#define U300_DMA_PCM_I2S0_RX          22
+#define U300_DMA_PCM_I2S1_TX          23
+#define U300_DMA_PCM_I2S1_RX          24
+#define U300_DMA_XGAM_CDI             25
+#define U300_DMA_XGAM_PDI             26
+#define U300_DMA_SPI_TX               27
+#define U300_DMA_SPI_RX               28
+#define U300_DMA_GENERAL_PURPOSE_0    29
+#define U300_DMA_GENERAL_PURPOSE_1    30
+#define U300_DMA_GENERAL_PURPOSE_2    31
+#define U300_DMA_GENERAL_PURPOSE_3    32
+#define U300_DMA_GENERAL_PURPOSE_4    33
+#define U300_DMA_GENERAL_PURPOSE_5    34
+#define U300_DMA_GENERAL_PURPOSE_6    35
+#define U300_DMA_GENERAL_PURPOSE_7    36
+#define U300_DMA_GENERAL_PURPOSE_8    37
+#define U300_DMA_UART1_TX             38
+#define U300_DMA_UART1_RX             39
+
+#define U300_DMA_DEVICE_CHANNELS      32
+#define U300_DMA_CHANNELS             40
+
+
+#endif /* DMA_CHANNELS_H */
diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c
index cb04bd6..0d4620e 100644
--- a/arch/arm/mach-u300/i2c.c
+++ b/arch/arm/mach-u300/i2c.c
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-u300/i2c.c
  *
- * Copyright (C) 2009 ST-Ericsson AB
+ * Copyright (C) 2009-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  *
  * Register board i2c devices
@@ -261,7 +261,6 @@
 };
 
 static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.type = "fwcam",
 		.addr = 0x10,
@@ -270,9 +269,6 @@
 		.type = "fwcam",
 		.addr = 0x5d,
 	},
-#else
-	{ },
-#endif
 };
 
 void __init u300_i2c_register_board_devices(void)
diff --git a/arch/arm/mach-u300/include/mach/clkdev.h b/arch/arm/mach-u300/include/mach/clkdev.h
deleted file mode 100644
index 92e3cc8..0000000
--- a/arch/arm/mach-u300/include/mach/clkdev.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MACH_CLKDEV_H
-#define __MACH_CLKDEV_H
-
-int __clk_get(struct clk *clk);
-void __clk_put(struct clk *clk);
-
-#endif
diff --git a/arch/arm/mach-u300/include/mach/dma_channels.h b/arch/arm/mach-u300/include/mach/dma_channels.h
deleted file mode 100644
index b239149..0000000
--- a/arch/arm/mach-u300/include/mach/dma_channels.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/dma_channels.h
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Map file for the U300 dma driver.
- * Author: Per Friden <per.friden@stericsson.com>
- */
-
-#ifndef DMA_CHANNELS_H
-#define DMA_CHANNELS_H
-
-#define U300_DMA_MSL_TX_0             0
-#define U300_DMA_MSL_TX_1             1
-#define U300_DMA_MSL_TX_2             2
-#define U300_DMA_MSL_TX_3             3
-#define U300_DMA_MSL_TX_4             4
-#define U300_DMA_MSL_TX_5             5
-#define U300_DMA_MSL_TX_6             6
-#define U300_DMA_MSL_RX_0             7
-#define U300_DMA_MSL_RX_1             8
-#define U300_DMA_MSL_RX_2             9
-#define U300_DMA_MSL_RX_3             10
-#define U300_DMA_MSL_RX_4             11
-#define U300_DMA_MSL_RX_5             12
-#define U300_DMA_MSL_RX_6             13
-#define U300_DMA_MMCSD_RX_TX          14
-#define U300_DMA_MSPRO_TX             15
-#define U300_DMA_MSPRO_RX             16
-#define U300_DMA_UART0_TX             17
-#define U300_DMA_UART0_RX             18
-#define U300_DMA_APEX_TX              19
-#define U300_DMA_APEX_RX              20
-#define U300_DMA_PCM_I2S0_TX          21
-#define U300_DMA_PCM_I2S0_RX          22
-#define U300_DMA_PCM_I2S1_TX          23
-#define U300_DMA_PCM_I2S1_RX          24
-#define U300_DMA_XGAM_CDI             25
-#define U300_DMA_XGAM_PDI             26
-#define U300_DMA_SPI_TX               27
-#define U300_DMA_SPI_RX               28
-#define U300_DMA_GENERAL_PURPOSE_0    29
-#define U300_DMA_GENERAL_PURPOSE_1    30
-#define U300_DMA_GENERAL_PURPOSE_2    31
-#define U300_DMA_GENERAL_PURPOSE_3    32
-#define U300_DMA_GENERAL_PURPOSE_4    33
-#define U300_DMA_GENERAL_PURPOSE_5    34
-#define U300_DMA_GENERAL_PURPOSE_6    35
-#define U300_DMA_GENERAL_PURPOSE_7    36
-#define U300_DMA_GENERAL_PURPOSE_8    37
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_DMA_UART1_TX             38
-#define U300_DMA_UART1_RX             39
-#else
-#define U300_DMA_GENERAL_PURPOSE_9    38
-#define U300_DMA_GENERAL_PURPOSE_10   39
-#endif
-
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_DMA_DEVICE_CHANNELS      32
-#else
-#define U300_DMA_DEVICE_CHANNELS      30
-#endif
-#define U300_DMA_CHANNELS             40
-
-
-#endif /* DMA_CHANNELS_H */
diff --git a/arch/arm/mach-u300/include/mach/gpio-u300.h b/arch/arm/mach-u300/include/mach/gpio-u300.h
deleted file mode 100644
index e81400c..0000000
--- a/arch/arm/mach-u300/include/mach/gpio-u300.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007-2011 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * GPIO block resgister definitions and inline macros for
- * U300 GPIO COH 901 335 or COH 901 571/3
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#ifndef __MACH_U300_GPIO_U300_H
-#define __MACH_U300_GPIO_U300_H
-
-/**
- * enum u300_gpio_variant - the type of U300 GPIO employed
- */
-enum u300_gpio_variant {
-	U300_GPIO_COH901335,
-	U300_GPIO_COH901571_3_BS335,
-	U300_GPIO_COH901571_3_BS365,
-};
-
-/**
- * struct u300_gpio_platform - U300 GPIO platform data
- * @variant: IP block variant
- * @ports: number of GPIO block ports
- * @gpio_base: first GPIO number for this block (use a free range)
- * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
- * @pinctrl_device: pin control device to spawn as child
- */
-struct u300_gpio_platform {
-	enum u300_gpio_variant variant;
-	u8 ports;
-	int gpio_base;
-	int gpio_irq_base;
-	struct platform_device *pinctrl_device;
-};
-
-#endif /* __MACH_U300_GPIO_U300_H */
diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h
index ec09c1e..e27425a 100644
--- a/arch/arm/mach-u300/include/mach/irqs.h
+++ b/arch/arm/mach-u300/include/mach/irqs.h
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/irqs.h
  *
  *
- * Copyright (C) 2006-2009 ST-Ericsson AB
+ * Copyright (C) 2006-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * IRQ channel definitions for the U300 platforms.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -31,10 +31,6 @@
 #define IRQ_U300_XGAM_GAMCON		14
 #define IRQ_U300_XGAM_CDI		15
 #define IRQ_U300_XGAM_CDICON		16
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-/* MMIACC not used on the DB3210 or DB3350 chips */
-#define IRQ_U300_XGAM_MMIACC		17
-#endif
 #define IRQ_U300_XGAM_PDI		18
 #define IRQ_U300_XGAM_PDICON		19
 #define IRQ_U300_XGAM_GAMEACC		20
@@ -55,8 +51,6 @@
 #define IRQ_U300_GPIO_PORT1		34
 #define IRQ_U300_GPIO_PORT2		35
 
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) || \
-    defined(CONFIG_MACH_U300_BS335)
 /* These are for DB3150, DB3200 and DB3350 */
 #define IRQ_U300_WDOG			36
 #define IRQ_U300_EVHIST			37
@@ -68,15 +62,8 @@
 #define IRQ_U300_RTC			43
 #define IRQ_U300_NFIF			44
 #define IRQ_U300_NFIF2			45
-#endif
-
-/* DB3150 and DB3200 have only 45 IRQs */
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-#define U300_VIC_IRQS_END		46
-#endif
 
 /* The DB3350-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS335
 #define IRQ_U300_ISP_F0			46
 #define IRQ_U300_ISP_F1			47
 #define IRQ_U300_ISP_F2			48
@@ -89,25 +76,6 @@
 #define IRQ_U300_GPIO_PORT5		55
 #define IRQ_U300_GPIO_PORT6		56
 #define U300_VIC_IRQS_END		57
-#endif
-
-/* The DB3210-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS365
-#define IRQ_U300_GPIO_PORT3		36
-#define IRQ_U300_GPIO_PORT4		37
-#define IRQ_U300_WDOG			38
-#define IRQ_U300_EVHIST			39
-#define IRQ_U300_MSPRO			40
-#define IRQ_U300_MMCSD_MCIINTR0		41
-#define IRQ_U300_MMCSD_MCIINTR1		42
-#define IRQ_U300_I2C0			43
-#define IRQ_U300_I2C1			44
-#define IRQ_U300_RTC			45
-#define IRQ_U300_NFIF			46
-#define IRQ_U300_NFIF2			47
-#define IRQ_U300_SYSCON_PLL_LOCK	48
-#define U300_VIC_IRQS_END		49
-#endif
 
 /* Maximum 8*7 GPIO lines */
 #ifdef CONFIG_PINCTRL_COH901
@@ -117,6 +85,6 @@
 #define IRQ_U300_GPIO_END		(U300_VIC_IRQS_END)
 #endif
 
-#define NR_IRQS				(IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
+#define NR_IRQS_U300			(IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
 
 #endif
diff --git a/arch/arm/mach-u300/include/mach/platform.h b/arch/arm/mach-u300/include/mach/platform.h
deleted file mode 100644
index 096333f..0000000
--- a/arch/arm/mach-u300/include/mach/platform.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/platform.h
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Basic platform init and mapping functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#ifndef __ASSEMBLY__
-
-void u300_map_io(void);
-void u300_init_irq(void);
-void u300_init_devices(void);
-void u300_restart(char, const char *);
-extern struct sys_timer u300_timer;
-
-#endif
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
index 6e84f07..10bdd0b 100644
--- a/arch/arm/mach-u300/include/mach/syscon.h
+++ b/arch/arm/mach-u300/include/mach/syscon.h
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/syscon.h
  *
  *
- * Copyright (C) 2008 ST-Ericsson AB
+ * Copyright (C) 2008-2012 ST-Ericsson AB
  *
  * Author: Rickard Andersson <rickard.andersson@stericsson.com>
  */
@@ -36,9 +36,7 @@
 #define U300_SYSCON_CSR_PLL13_LOCK_IND				(0x0001)
 /* Reset lines for SLOW devices 16bit (R/W) */
 #define U300_SYSCON_RSR						(0x0014)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RSR_PPM_RESET_EN				(0x0200)
-#endif
 #define U300_SYSCON_RSR_ACC_TMR_RESET_EN			(0x0100)
 #define U300_SYSCON_RSR_APP_TMR_RESET_EN			(0x0080)
 #define U300_SYSCON_RSR_RTC_RESET_EN				(0x0040)
@@ -50,9 +48,7 @@
 #define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN			(0x0001)
 /* Reset lines for FAST devices 16bit (R/W) */
 #define U300_SYSCON_RFR						(0x0018)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RFR_UART1_RESET_ENABLE			(0x0080)
-#endif
 #define U300_SYSCON_RFR_SPI_RESET_ENABLE			(0x0040)
 #define U300_SYSCON_RFR_MMC_RESET_ENABLE			(0x0020)
 #define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE			(0x0010)
@@ -62,10 +58,8 @@
 #define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE		(0x0001)
 /* Reset lines for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_RRR						(0x001c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RRR_CDS_RESET_EN				(0x4000)
 #define U300_SYSCON_RRR_ISP_RESET_EN				(0x2000)
-#endif
 #define U300_SYSCON_RRR_INTCON_RESET_EN				(0x1000)
 #define U300_SYSCON_RRR_MSPRO_RESET_EN				(0x0800)
 #define U300_SYSCON_RRR_XGAM_RESET_EN				(0x0100)
@@ -79,9 +73,7 @@
 #define U300_SYSCON_RRR_AAIF_RESET_EN				(0x0001)
 /* Clock enable for SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CESR					(0x0020)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CESR_PPM_CLK_EN				(0x0200)
-#endif
 #define U300_SYSCON_CESR_ACC_TMR_CLK_EN				(0x0100)
 #define U300_SYSCON_CESR_APP_TMR_CLK_EN				(0x0080)
 #define U300_SYSCON_CESR_KEYPAD_CLK_EN				(0x0040)
@@ -92,24 +84,20 @@
 #define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN			(0x0001)
 /* Clock enable for FAST peripherals 16bit (R/W) */
 #define U300_SYSCON_CEFR					(0x0024)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CEFR_UART1_CLK_EN				(0x0200)
-#endif
 #define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN			(0x0100)
 #define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN			(0x0080)
 #define U300_SYSCON_CEFR_SPI_CLK_EN				(0x0040)
 #define U300_SYSCON_CEFR_MMC_CLK_EN				(0x0020)
-#define U300_SYSCON_CEFR_I2S1_CLK_EN    			(0x0010)
-#define U300_SYSCON_CEFR_I2S0_CLK_EN     			(0x0008)
-#define U300_SYSCON_CEFR_I2C1_CLK_EN     			(0x0004)
-#define U300_SYSCON_CEFR_I2C0_CLK_EN     			(0x0002)
+#define U300_SYSCON_CEFR_I2S1_CLK_EN				(0x0010)
+#define U300_SYSCON_CEFR_I2S0_CLK_EN				(0x0008)
+#define U300_SYSCON_CEFR_I2C1_CLK_EN				(0x0004)
+#define U300_SYSCON_CEFR_I2C0_CLK_EN				(0x0002)
 #define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN			(0x0001)
 /* Clock enable for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CERR					(0x0028)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CERR_CDS_CLK_EN				(0x2000)
 #define U300_SYSCON_CERR_ISP_CLK_EN				(0x1000)
-#endif
 #define U300_SYSCON_CERR_MSPRO_CLK_EN				(0x0800)
 #define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN		(0x0400)
 #define U300_SYSCON_CERR_SEMI_CLK_EN				(0x0200)
@@ -124,9 +112,7 @@
 #define U300_SYSCON_CERR_AAIF_CLK_EN				(0x0001)
 /* Single block clock enable 16bit (-/W) */
 #define U300_SYSCON_SBCER					(0x002c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_PPM_CLK_EN				(0x0009)
-#endif
 #define U300_SYSCON_SBCER_ACC_TMR_CLK_EN			(0x0008)
 #define U300_SYSCON_SBCER_APP_TMR_CLK_EN			(0x0007)
 #define U300_SYSCON_SBCER_KEYPAD_CLK_EN				(0x0006)
@@ -135,9 +121,7 @@
 #define U300_SYSCON_SBCER_BTR_CLK_EN				(0x0002)
 #define U300_SYSCON_SBCER_UART_CLK_EN				(0x0001)
 #define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN			(0x0000)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_UART1_CLK_EN				(0x0019)
-#endif
 #define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN			(0x0018)
 #define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN			(0x0017)
 #define U300_SYSCON_SBCER_SPI_CLK_EN				(0x0016)
@@ -147,10 +131,8 @@
 #define U300_SYSCON_SBCER_I2C1_CLK_EN				(0x0012)
 #define U300_SYSCON_SBCER_I2C0_CLK_EN				(0x0011)
 #define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN			(0x0010)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_CDS_CLK_EN				(0x002D)
 #define U300_SYSCON_SBCER_ISP_CLK_EN				(0x002C)
-#endif
 #define U300_SYSCON_SBCER_MSPRO_CLK_EN				(0x002B)
 #define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN		(0x002A)
 #define U300_SYSCON_SBCER_SEMI_CLK_EN				(0x0029)
@@ -168,9 +150,7 @@
 /* Same values as above for SBCER */
 /* Clock force SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CFSR					(0x003c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN			(0x0200)
-#endif
 #define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN			(0x0100)
 #define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN			(0x0080)
 #define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN			(0x0020)
@@ -184,10 +164,8 @@
 /* Values not defined. Define if you want to use them. */
 /* Clock force the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CFRR					(0x44)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN			(0x2000)
 #define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN			(0x1000)
-#endif
 #define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN			(0x0800)
 #define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN		(0x0400)
 #define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN			(0x0200)
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
index 65f87c5..1e49d90 100644
--- a/arch/arm/mach-u300/include/mach/u300-regs.h
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
@@ -28,7 +28,6 @@
 #define PLAT_NAND_CLE			(1 << 16)
 #define PLAT_NAND_ALE			(1 << 17)
 
-
 /* AHB Peripherals */
 #define U300_AHB_PER_PHYS_BASE		0xa0000000
 #define U300_AHB_PER_VIRT_BASE		0xff010000
@@ -46,11 +45,7 @@
 #define U300_BOOTROM_VIRT_BASE		0xffff0000
 
 /* SEMI config base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SEMI_CONFIG_BASE		0x2FFE0000
-#else
-#define U300_SEMI_CONFIG_BASE		0x30000000
-#endif
 
 /*
  * AHB peripherals
@@ -99,10 +94,8 @@
 /* SPI controller */
 #define U300_SPI_BASE			(U300_FAST_PER_PHYS_BASE+0x6000)
 
-#ifdef CONFIG_MACH_U300_BS335
 /* Fast UART1 on U335 only */
 #define U300_UART1_BASE			(U300_SLOW_PER_PHYS_BASE+0x7000)
-#endif
 
 /*
  * SLOW peripherals
@@ -151,10 +144,8 @@
  * REST peripherals
  */
 
-/* ISP (image signal processor) is only available in U335 */
-#ifdef CONFIG_MACH_U300_BS335
+/* ISP (image signal processor) */
 #define U300_ISP_BASE			(0xA0008000)
-#endif
 
 /* DMA Controller base */
 #define U300_DMAC_BASE			(0xC0020000)
@@ -166,17 +157,9 @@
 #define U300_APEX_BASE			(0xc0030000)
 
 /* Video Encoder Base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_VIDEOENC_BASE		(0xc0080000)
-#else
-#define U300_VIDEOENC_BASE		(0xc0040000)
-#endif
 
 /* XGAM Base */
 #define U300_XGAM_BASE			(0xd0000000)
 
-/*
- * Virtual accessor macros for static devices
- */
-
 #endif
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index a1affac..02e6659 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -12,7 +12,7 @@
 #include <linux/amba/pl022.h>
 #include <linux/err.h>
 #include <mach/coh901318.h>
-#include <mach/dma_channels.h>
+#include "dma_channels.h"
 
 /*
  * The following is for the actual devices on the SSP/SPI bus
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 56ac06d..1da10e2 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -17,14 +17,17 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 /* Generic stuff */
 #include <asm/sched_clock.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+
+#include "timer.h"
 
 /*
  * APP side special timer registers
diff --git a/arch/arm/mach-u300/timer.h b/arch/arm/mach-u300/timer.h
new file mode 100644
index 0000000..b5e9791
--- /dev/null
+++ b/arch/arm/mach-u300/timer.h
@@ -0,0 +1 @@
+extern struct sys_timer u300_timer;
diff --git a/arch/arm/mach-u300/u300-gpio.h b/arch/arm/mach-u300/u300-gpio.h
index 847dc25..83f50772 100644
--- a/arch/arm/mach-u300/u300-gpio.h
+++ b/arch/arm/mach-u300/u300-gpio.h
@@ -1,50 +1,11 @@
 /*
- * Individual pin assignments for the B26/S26. Notice that the
- * actual usage of these pins depends on the PAD MUX settings, that
- * is why the same number can potentially appear several times.
- * In the reference design each pin is only used for one purpose.
- * These were determined by inspecting the B26/S26 schematic:
- * 2/1911-ROA 128 1603
- */
-#ifdef CONFIG_MACH_U300_BS2X
-#define U300_GPIO_PIN_UART_RX		0
-#define U300_GPIO_PIN_UART_TX		1
-#define U300_GPIO_PIN_GPIO02		2  /* Unrouted */
-#define U300_GPIO_PIN_GPIO03		3  /* Unrouted */
-#define U300_GPIO_PIN_CAM_SLEEP		4
-#define U300_GPIO_PIN_CAM_REG_EN	5
-#define U300_GPIO_PIN_GPIO06		6  /* Unrouted */
-#define U300_GPIO_PIN_GPIO07		7  /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO08		8  /* Service point SP2321 */
-#define U300_GPIO_PIN_GPIO09		9  /* Service point SP2322 */
-#define U300_GPIO_PIN_PHFSENSE		10 /* Headphone jack sensing */
-#define U300_GPIO_PIN_MMC_CLKRET	11 /* Clock return from MMC/SD card */
-#define U300_GPIO_PIN_MMC_CD		12 /* MMC Card insertion detection */
-#define U300_GPIO_PIN_FLIPSENSE		13 /* Mechanical flip sensing */
-#define U300_GPIO_PIN_GPIO14		14 /* DSP JTAG Port RTCK */
-#define U300_GPIO_PIN_GPIO15		15 /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO16		16 /* Unrouted */
-#define U300_GPIO_PIN_GPIO17		17 /* Unrouted */
-#define U300_GPIO_PIN_GPIO18		18 /* Unrouted */
-#define U300_GPIO_PIN_GPIO19		19 /* Unrouted */
-#define U300_GPIO_PIN_GPIO20		20 /* Unrouted */
-#define U300_GPIO_PIN_GPIO21		21 /* Unrouted */
-#define U300_GPIO_PIN_GPIO22		22 /* Unrouted */
-#define U300_GPIO_PIN_GPIO23		23 /* Unrouted */
-#endif
-
-/*
- * Individual pin assignments for the B330/S330 and B365/S365.
+ * Individual pin assignments for the B335/S335.
  * Notice that the actual usage of these pins depends on the
  * PAD MUX settings, that is why the same number can potentially
  * appear several times. In the reference design each pin is only
  * used for one purpose. These were determined by inspecting the
  * S365 schematic.
  */
-#if defined(CONFIG_MACH_U300_BS330) || defined(CONFIG_MACH_U300_BS365) || \
-    defined(CONFIG_MACH_U300_BS335)
 #define U300_GPIO_PIN_UART_RX		0
 #define U300_GPIO_PIN_UART_TX		1
 #define U300_GPIO_PIN_UART_CTS		2
@@ -90,8 +51,6 @@
 #define U300_GPIO_PIN_GPIO38		38 /* Unrouted */
 #define U300_GPIO_PIN_GPIO39		39 /* Unrouted */
 
-#ifdef CONFIG_MACH_U300_BS335
-
 #define U300_GPIO_PIN_GPIO40		40 /* Unrouted */
 #define U300_GPIO_PIN_GPIO41		41 /* Unrouted */
 #define U300_GPIO_PIN_GPIO42		42 /* Unrouted */
@@ -109,6 +68,3 @@
 #define U300_GPIO_PIN_GPIO53		53 /* Unrouted */
 #define U300_GPIO_PIN_GPIO54		54 /* Unrouted */
 #define U300_GPIO_PIN_GPIO55		55 /* Unrouted */
-#endif
-
-#endif
diff --git a/arch/arm/mach-u300/u300.c b/arch/arm/mach-u300/u300.c
deleted file mode 100644
index f30c69d..0000000
--- a/arch/arm/mach-u300/u300.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/u300.c
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Platform machine definition.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/memblock.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <asm/hardware/vic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/memory.h>
-
-static void __init u300_init_machine(void)
-{
-	u300_init_devices();
-}
-
-#ifdef CONFIG_MACH_U300_BS2X
-#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS330
-#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS335
-#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS365
-#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
-#endif
-
-MACHINE_START(U300, MACH_U300_STRING)
-	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
-	.atag_offset	= 0x100,
-	.map_io		= u300_map_io,
-	.init_irq	= u300_init_irq,
-	.handle_irq	= vic_handle_irq,
-	.timer		= &u300_timer,
-	.init_machine	= u300_init_machine,
-	.restart	= u300_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index a258996..c77c86c4 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -29,6 +29,7 @@
 	select I2C
 	select I2C_NOMADIK
 	select SOC_BUS
+	select REGULATOR_FIXED_VOLTAGE
 	help
 	  Include support for the MOP500 development platform.
 
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
index 52426a4..2a17bc5 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.c
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -13,6 +13,21 @@
 #include <linux/regulator/ab8500.h>
 #include "board-mop500-regulators.h"
 
+static struct regulator_consumer_supply gpio_en_3v3_consumers[] = {
+       REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
+struct regulator_init_data gpio_en_3v3_regulator = {
+       .constraints = {
+               .name = "EN-3V3",
+               .min_uV = 3300000,
+               .max_uV = 3300000,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(gpio_en_3v3_consumers),
+       .consumer_supplies = gpio_en_3v3_consumers,
+};
+
 /*
  * TPS61052 regulator
  */
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h
index 9499215..78a0642 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.h
+++ b/arch/arm/mach-ux500/board-mop500-regulators.h
@@ -18,5 +18,6 @@
 ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS];
 extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS];
 extern struct regulator_init_data tps61052_regulator;
+extern struct regulator_init_data gpio_en_3v3_regulator;
 
 #endif
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 12ab21d..0747913 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -23,6 +23,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
+#include <linux/regulator/fixed.h>
 #include <linux/mfd/tc3589x.h>
 #include <linux/mfd/tps6105x.h>
 #include <linux/mfd/abx500/ab8500-gpio.h>
@@ -75,6 +76,23 @@
 	},
 };
 
+static struct fixed_voltage_config snowball_gpio_en_3v3_data = {
+       .supply_name            = "EN-3V3",
+       .gpio                   = SNOWBALL_EN_3V3_ETH_GPIO,
+       .microvolts             = 3300000,
+       .enable_high            = 1,
+       .init_data              = &gpio_en_3v3_regulator,
+       .startup_delay          = 5000, /* 1200us */
+};
+
+static struct platform_device snowball_gpio_en_3v3_regulator_dev = {
+       .name   = "reg-fixed-voltage",
+       .id     = 1,
+       .dev    = {
+               .platform_data  = &snowball_gpio_en_3v3_data,
+       },
+};
+
 static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
 	.gpio_base		= MOP500_AB8500_PIN_GPIO(1),
 	.irq_base		= MOP500_AB8500_VIR_GPIO_IRQ_BASE,
@@ -564,6 +582,7 @@
 	&snowball_led_dev,
 	&snowball_key_dev,
 	&snowball_sbnet_dev,
+	&snowball_gpio_en_3v3_regulator_dev,
 };
 
 static void __init mop500_init_machine(void)
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index dc12394..75d5b51 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -38,7 +38,7 @@
 {
 	u32 aux_val = 0x3e000000;
 
-	if (cpu_is_u8500_family())
+	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		l2x0_base = __io_address(U8500_L2CC_BASE);
 	else
 		ux500_unknown_soc();
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 38b7f9c..27a397f 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -18,8 +18,8 @@
 #include <linux/io.h>
 #include <linux/mfd/abx500/ab8500.h>
 
-#include <asm/mach/map.h>
 #include <asm/pmu.h>
+#include <asm/mach/map.h>
 #include <plat/gpio-nomadik.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -80,7 +80,7 @@
 
 	iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
 
-	if (cpu_is_u9540())
+	if (cpu_is_ux540_family())
 		iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
 	else
 		iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
@@ -122,7 +122,7 @@
 
 static struct platform_device db8500_pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(db8500_pmu_resources),
 	.resource		= db8500_pmu_resources,
 	.dev.platform_data	= &db8500_pmu_platdata,
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 17a78ec..2236cbd 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -49,7 +49,9 @@
 	void __iomem *dist_base;
 	void __iomem *cpu_base;
 
-	if (cpu_is_u8500_family()) {
+	gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
+
+	if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
 		dist_base = __io_address(U8500_GIC_DIST_BASE);
 		cpu_base = __io_address(U8500_GIC_CPU_BASE);
 	} else
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h
index c6e2db9..9c42642 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/include/mach/id.h
@@ -41,43 +41,29 @@
 	return dbx500_partnumber() == 0x8500;
 }
 
+static inline bool __attribute_const__ cpu_is_u8520(void)
+{
+	return dbx500_partnumber() == 0x8520;
+}
+
+static inline bool cpu_is_u8500_family(void)
+{
+	return cpu_is_u8500() || cpu_is_u8520();
+}
+
 static inline bool __attribute_const__ cpu_is_u9540(void)
 {
 	return dbx500_partnumber() == 0x9540;
 }
 
-static inline bool cpu_is_u8500_family(void)
+static inline bool __attribute_const__ cpu_is_u8540(void)
 {
-	return cpu_is_u8500() || cpu_is_u9540();
+	return dbx500_partnumber() == 0x8540;
 }
 
-static inline bool __attribute_const__ cpu_is_u5500(void)
+static inline bool cpu_is_ux540_family(void)
 {
-	return dbx500_partnumber() == 0x5500;
-}
-
-/*
- * 5500 revisions
- */
-
-static inline bool __attribute_const__ cpu_is_u5500v1(void)
-{
-	return cpu_is_u5500() && (dbx500_revision() & 0xf0) == 0xA0;
-}
-
-static inline bool __attribute_const__ cpu_is_u5500v2(void)
-{
-	return (dbx500_id.revision & 0xf0) == 0xB0;
-}
-
-static inline bool __attribute_const__ cpu_is_u5500v20(void)
-{
-	return cpu_is_u5500() && ((dbx500_revision() & 0xf0) == 0xB0);
-}
-
-static inline bool __attribute_const__ cpu_is_u5500v21(void)
-{
-	return cpu_is_u5500() && (dbx500_revision() == 0xB1);
+	return cpu_is_u9540() || cpu_is_u8540();
 }
 
 /*
@@ -119,14 +105,14 @@
 	return cpu_is_u8500() && (dbx500_revision() == 0xB1);
 }
 
+static inline bool cpu_is_u8500v22(void)
+{
+	return cpu_is_u8500() && (dbx500_revision() == 0xB2);
+}
+
 static inline bool cpu_is_u8500v20_or_later(void)
 {
-	/*
-	 * U9540 has so much in common with U8500 that is is considered a
-	 * U8500 variant.
-	 */
-	return cpu_is_u9540() ||
-		(cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
+	return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
 }
 
 static inline bool ux500_is_svp(void)
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index da1d5ad..a5dda68444 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -48,7 +48,7 @@
 
 static void __iomem *scu_base_addr(void)
 {
-	if (cpu_is_u8500_family())
+	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		return __io_address(U8500_SCU_BASE);
 	else
 		ux500_unknown_soc();
@@ -118,7 +118,7 @@
 {
 	void __iomem *backupram;
 
-	if (cpu_is_u8500_family())
+	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		backupram = __io_address(U8500_BACKUPRAM0_BASE);
 	else
 		ux500_unknown_soc();
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index 66e7f00..6f39731 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -54,7 +54,7 @@
 	void __iomem *tmp_base;
 	struct device_node *np;
 
-	if (cpu_is_u8500_family()) {
+	if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
 		mtu_timer_base = __io_address(U8500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
 	} else {
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index cd8ea35..ca7902c 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -169,11 +169,6 @@
 		.pfn		= __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
 		.length		= VERSATILE_PCI_CFG_BASE_SIZE,
 		.type		= MT_DEVICE
-	}, {
-		.virtual	=  (unsigned long)VERSATILE_PCI_VIRT_MEM_BASE0,
-		.pfn		= __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
-		.length		= IO_SPACE_LIMIT,
-		.type		= MT_DEVICE
 	},
 #endif
 };
diff --git a/arch/arm/mach-versatile/include/mach/hardware.h b/arch/arm/mach-versatile/include/mach/hardware.h
index 408e58d..3e5d425 100644
--- a/arch/arm/mach-versatile/include/mach/hardware.h
+++ b/arch/arm/mach-versatile/include/mach/hardware.h
@@ -29,7 +29,6 @@
  */
 #define VERSATILE_PCI_VIRT_BASE		(void __iomem *)0xe8000000ul
 #define VERSATILE_PCI_CFG_VIRT_BASE	(void __iomem *)0xe9000000ul
-#define VERSATILE_PCI_VIRT_MEM_BASE0	(void __iomem *)PCIO_BASE
 
 /* macro to get at MMIO space when running virtually */
 #define IO_ADDRESS(x)		(((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
diff --git a/arch/arm/mach-versatile/include/mach/io.h b/arch/arm/mach-versatile/include/mach/io.h
deleted file mode 100644
index 0406513..0000000
--- a/arch/arm/mach-versatile/include/mach/io.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define PCIO_BASE	0xeb000000ul
-
-#define __io(a)		((a) + PCIO_BASE)
-
-#endif
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index e95bf84..2f84f40 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -169,13 +169,6 @@
 	.write	= versatile_write_config,
 };
 
-static struct resource io_port = {
-	.name	= "PCI",
-	.start	= 0,
-	.end	= IO_SPACE_LIMIT,
-	.flags	= IORESOURCE_IO,
-};
-
 static struct resource io_mem = {
 	.name	= "PCI I/O space",
 	.start	= VERSATILE_PCI_MEM_BASE0,
@@ -207,12 +200,6 @@
 		       "memory region (%d)\n", ret);
 		goto out;
 	}
-	ret = request_resource(&ioport_resource, &io_port);
-	if (ret) {
-		printk(KERN_ERR "PCI: unable to allocate I/O "
-		       "port region (%d)\n", ret);
-		goto out;
-	}
 	ret = request_resource(&iomem_resource, &non_mem);
 	if (ret) {
 		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
@@ -227,11 +214,9 @@
 	}
 
 	/*
-	 * the IO resource for this bus
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource_offset(&sys->resources, &io_port, sys->io_offset);
 	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -260,9 +245,11 @@
 		goto out;
 	}
 
+	ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
+	if (ret)
+		goto out;
+
 	if (nr == 0) {
-		sys->mem_offset = 0;
-		sys->io_offset = 0;
 		ret = pci_versatile_setup_resources(sys);
 		if (ret < 0) {
 			printk("pci_versatile_setup: resources... oops?\n");
@@ -319,7 +306,6 @@
 
 void __init pci_versatile_preinit(void)
 {
-	pcibios_min_io = 0x44000000;
 	pcibios_min_mem = 0x50000000;
 
 	__raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 61c4924..e4073a60 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -13,7 +13,6 @@
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
-#include <asm/pmu.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
 
@@ -144,7 +143,7 @@
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(pmu_resources),
 	.resource	= pmu_resources,
 };
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 2a8e380..577baf7 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -554,7 +554,7 @@
 int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
 	struct device_node *np;
-	struct l2x0_of_data *data;
+	const struct l2x0_of_data *data;
 	struct resource res;
 
 	np = of_find_matching_node(NULL, l2x0_ids);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index e59c4ab..13f555d 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -346,6 +346,8 @@
 		       (unsigned)pool->size / 1024);
 		return 0;
 	}
+
+	kfree(pages);
 no_pages:
 	kfree(bitmap);
 no_bitmap:
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 566750f..9d869f9 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -36,6 +36,7 @@
 #include <asm/system_info.h>
 
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include "mm.h"
 
 int ioremap_page(unsigned long virt, unsigned long phys,
@@ -383,3 +384,16 @@
 	arch_iounmap(io_addr);
 }
 EXPORT_SYMBOL(__arm_iounmap);
+
+#ifdef CONFIG_PCI
+int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
+{
+	BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
+
+	return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
+				  PCI_IO_VIRT_BASE + offset + SZ_64K,
+				  phys_addr,
+				  __pgprot(get_mem_type(MT_DEVICE)->prot_pte));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_io);
+#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index c2fa21d..18144e6 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -31,6 +31,7 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "mm.h"
 
@@ -216,7 +217,7 @@
 		.prot_l1	= PMD_TYPE_TABLE,
 		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_WB,
 		.domain		= DOMAIN_IO,
-	},	
+	},
 	[MT_DEVICE_WC] = {	/* ioremap_wc */
 		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
 		.prot_l1	= PMD_TYPE_TABLE,
@@ -777,14 +778,27 @@
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
 		vm_area_add_early(vm++);
 	}
 }
 
+void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
+				  void *caller)
+{
+	struct vm_struct *vm;
+
+	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+	vm->addr = (void *)addr;
+	vm->size = size;
+	vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
+	vm->caller = caller;
+	vm_area_add_early(vm);
+}
+
 #ifndef CONFIG_ARM_LPAE
 
 /*
@@ -802,14 +816,7 @@
 
 static void __init pmd_empty_section_gap(unsigned long addr)
 {
-	struct vm_struct *vm;
-
-	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
-	vm->addr = (void *)addr;
-	vm->size = SECTION_SIZE;
-	vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
-	vm->caller = pmd_empty_section_gap;
-	vm_area_add_early(vm);
+	vm_reserve_area_early(addr, SECTION_SIZE, pmd_empty_section_gap);
 }
 
 static void __init fill_pmd_gaps(void)
@@ -858,6 +865,28 @@
 #define fill_pmd_gaps() do { } while (0)
 #endif
 
+#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
+static void __init pci_reserve_io(void)
+{
+	struct vm_struct *vm;
+	unsigned long addr;
+
+	/* we're still single threaded hence no lock needed here */
+	for (vm = vmlist; vm; vm = vm->next) {
+		if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+			continue;
+		addr = (unsigned long)vm->addr;
+		addr &= ~(SZ_2M - 1);
+		if (addr == PCI_IO_VIRT_BASE)
+			return;
+
+	}
+	vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
+}
+#else
+#define pci_reserve_io() do { } while (0)
+#endif
+
 static void * __initdata vmalloc_min =
 	(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
 
@@ -1141,6 +1170,9 @@
 		mdesc->map_io();
 	fill_pmd_gaps();
 
+	/* Reserve fixed i/o space in VMALLOC region */
+	pci_reserve_io();
+
 	/*
 	 * Finally flush the caches and tlb to ensure that we're in a
 	 * consistent state wrt the writebuffer.  This also ensures that
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index 8daae9b..362474b 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -192,30 +192,24 @@
 	if (nr != 0)
 		return 0;
 
-	res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("PCI: unable to alloc resources");
 
-	res[0].start = IOP3XX_PCI_LOWER_IO_PA;
-	res[0].end   = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1;
-	res[0].name  = "IOP3XX PCI I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	request_resource(&ioport_resource, &res[0]);
-
-	res[1].start = IOP3XX_PCI_LOWER_MEM_PA;
-	res[1].end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
-	res[1].name  = "IOP3XX PCI Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	request_resource(&iomem_resource, &res[1]);
+	res->start = IOP3XX_PCI_LOWER_MEM_PA;
+	res->end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
+	res->name  = "IOP3XX PCI Memory Space";
+	res->flags = IORESOURCE_MEM;
+	request_resource(&iomem_resource, res);
 
 	/*
 	 * Use whatever translation is already setup.
 	 */
 	sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
-	sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
+
+	pci_ioremap_io(0, IOP3XX_PCI_LOWER_IO_PA);
 
 	return 1;
 }
@@ -367,7 +361,6 @@
 
 void __init iop3xx_pci_preinit(void)
 {
-	pcibios_min_io = 0;
 	pcibios_min_mem = 0;
 
 	iop3xx_atu_disable();
diff --git a/arch/arm/plat-iop/pmu.c b/arch/arm/plat-iop/pmu.c
index a2024b8..ad9f974 100644
--- a/arch/arm/plat-iop/pmu.c
+++ b/arch/arm/plat-iop/pmu.c
@@ -9,7 +9,6 @@
  */
 
 #include <linux/platform_device.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 
 static struct resource pmu_resource = {
@@ -26,7 +25,7 @@
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pmu_resource,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c
index bade586..5b217f4 100644
--- a/arch/arm/plat-iop/setup.c
+++ b/arch/arm/plat-iop/setup.c
@@ -25,11 +25,6 @@
 		.pfn		= __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
 		.length		= IOP3XX_PERIPHERAL_SIZE,
 		.type		= MT_UNCACHED,
-	 }, {	/* PCI IO space */
-		.virtual	= IOP3XX_PCI_LOWER_IO_VA,
-		.pfn		= __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
-		.length		= IOP3XX_PCI_IO_WINDOW_SIZE,
-		.type		= MT_DEVICE,
 	 },
 };
 
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 6ac7200..149237e2 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := clock.o time.o devices.o cpu.o system.o irq-common.o
+obj-y := time.o devices.o cpu.o system.o irq-common.o
 
 obj-$(CONFIG_MXC_TZIC) += tzic.o
 obj-$(CONFIG_MXC_AVIC) += avic.o
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
deleted file mode 100644
index 5079787..0000000
--- a/arch/arm/plat-mxc/clock.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Based on arch/arm/plat-omap/clock.c
- *
- * Copyright (C) 2004 - 2005 Nokia corporation
- * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
- * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
- * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301, USA.
- */
-
-/* #define DEBUG */
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/proc_fs.h>
-#include <linux/semaphore.h>
-#include <linux/string.h>
-
-#include <mach/clock.h>
-#include <mach/hardware.h>
-
-#ifndef CONFIG_COMMON_CLK
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-/*-------------------------------------------------------------------------
- * Standard clock functions defined in include/linux/clk.h
- *-------------------------------------------------------------------------*/
-
-static void __clk_disable(struct clk *clk)
-{
-	if (clk == NULL || IS_ERR(clk))
-		return;
-	WARN_ON(!clk->usecount);
-
-	if (!(--clk->usecount)) {
-		if (clk->disable)
-			clk->disable(clk);
-		__clk_disable(clk->parent);
-		__clk_disable(clk->secondary);
-	}
-}
-
-static int __clk_enable(struct clk *clk)
-{
-	if (clk == NULL || IS_ERR(clk))
-		return -EINVAL;
-
-	if (clk->usecount++ == 0) {
-		__clk_enable(clk->parent);
-		__clk_enable(clk->secondary);
-
-		if (clk->enable)
-			clk->enable(clk);
-	}
-	return 0;
-}
-
-/* This function increments the reference count on the clock and enables the
- * clock if not already enabled. The parent clock tree is recursively enabled
- */
-int clk_enable(struct clk *clk)
-{
-	int ret = 0;
-
-	if (clk == NULL || IS_ERR(clk))
-		return -EINVAL;
-
-	mutex_lock(&clocks_mutex);
-	ret = __clk_enable(clk);
-	mutex_unlock(&clocks_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-/* This function decrements the reference count on the clock and disables
- * the clock when reference count is 0. The parent clock tree is
- * recursively disabled
- */
-void clk_disable(struct clk *clk)
-{
-	if (clk == NULL || IS_ERR(clk))
-		return;
-
-	mutex_lock(&clocks_mutex);
-	__clk_disable(clk);
-	mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_disable);
-
-/* Retrieve the *current* clock rate. If the clock itself
- * does not provide a special calculation routine, ask
- * its parent and so on, until one is able to return
- * a valid clock rate
- */
-unsigned long clk_get_rate(struct clk *clk)
-{
-	if (clk == NULL || IS_ERR(clk))
-		return 0UL;
-
-	if (clk->get_rate)
-		return clk->get_rate(clk);
-
-	return clk_get_rate(clk->parent);
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/* Round the requested clock rate to the nearest supported
- * rate that is less than or equal to the requested rate.
- * This is dependent on the clock's current parent.
- */
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-	if (clk == NULL || IS_ERR(clk) || !clk->round_rate)
-		return 0;
-
-	return clk->round_rate(clk, rate);
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-/* Set the clock to the requested clock rate. The rate must
- * match a supported rate exactly based on what clk_round_rate returns
- */
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	int ret = -EINVAL;
-
-	if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0)
-		return ret;
-
-	mutex_lock(&clocks_mutex);
-	ret = clk->set_rate(clk, rate);
-	mutex_unlock(&clocks_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-/* Set the clock's parent to another clock source */
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	int ret = -EINVAL;
-	struct clk *old;
-
-	if (clk == NULL || IS_ERR(clk) || parent == NULL ||
-	    IS_ERR(parent) || clk->set_parent == NULL)
-		return ret;
-
-	if (clk->usecount)
-		clk_enable(parent);
-
-	mutex_lock(&clocks_mutex);
-	ret = clk->set_parent(clk, parent);
-	if (ret == 0) {
-		old = clk->parent;
-		clk->parent = parent;
-	} else {
-		old = parent;
-	}
-	mutex_unlock(&clocks_mutex);
-
-	if (clk->usecount)
-		clk_disable(old);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-/* Retrieve the clock's parent clock source */
-struct clk *clk_get_parent(struct clk *clk)
-{
-	struct clk *ret = NULL;
-
-	if (clk == NULL || IS_ERR(clk))
-		return ret;
-
-	return clk->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-#else
-
-/*
- * Lock to protect the clock module (ccm) registers. Used
- * on all i.MXs
- */
-DEFINE_SPINLOCK(imx_ccm_lock);
-
-#endif /* CONFIG_COMMON_CLK */
-
-/*
- * Get the resulting clock rate from a PLL register value and the input
- * frequency. PLLs with this register layout can at least be found on
- * MX1, MX21, MX27 and MX31
- *
- *                  mfi + mfn / (mfd + 1)
- *  f = 2 * f_ref * --------------------
- *                        pd + 1
- */
-unsigned long mxc_decode_pll(unsigned int reg_val, u32 freq)
-{
-	long long ll;
-	int mfn_abs;
-	unsigned int mfi, mfn, mfd, pd;
-
-	mfi = (reg_val >> 10) & 0xf;
-	mfn = reg_val & 0x3ff;
-	mfd = (reg_val >> 16) & 0x3ff;
-	pd =  (reg_val >> 26) & 0xf;
-
-	mfi = mfi <= 5 ? 5 : mfi;
-
-	mfn_abs = mfn;
-
-	/* On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit
-	 * 2's complements number
-	 */
-	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200)
-		mfn_abs = 0x400 - mfn;
-
-	freq *= 2;
-	freq /= pd + 1;
-
-	ll = (unsigned long long)freq * mfn_abs;
-
-	do_div(ll, mfd + 1);
-
-	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200)
-		ll = -ll;
-
-	ll = (freq * mfi) + ll;
-
-	return ll;
-}
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 73db34b..b5b6f80 100644
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -23,7 +23,6 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <mach/hardware.h>
-#include <mach/clock.h>
 
 #define CLK32_FREQ	32768
 #define NANOSECOND	(1000 * 1000 * 1000)
diff --git a/arch/arm/plat-mxc/devices/platform-imx-uart.c b/arch/arm/plat-mxc/devices/platform-imx-uart.c
index 2020d84..d390f00 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-uart.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-uart.c
@@ -87,7 +87,7 @@
 #ifdef CONFIG_SOC_IMX35
 const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst = {
 #define imx35_imx_uart_data_entry(_id, _hwid)				\
-	imx_imx_uart_1irq_data_entry(MX31, _id, _hwid, SZ_16K)
+	imx_imx_uart_1irq_data_entry(MX35, _id, _hwid, SZ_16K)
 	imx35_imx_uart_data_entry(0, 1),
 	imx35_imx_uart_data_entry(1, 2),
 	imx35_imx_uart_data_entry(2, 3),
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h
deleted file mode 100644
index bd940c7..0000000
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301, USA.
- */
-
-#ifndef __ASM_ARCH_MXC_CLOCK_H__
-#define __ASM_ARCH_MXC_CLOCK_H__
-
-#ifndef __ASSEMBLY__
-#include <linux/list.h>
-
-#ifndef CONFIG_COMMON_CLK
-struct module;
-
-struct clk {
-	int id;
-	/* Source clock this clk depends on */
-	struct clk *parent;
-	/* Secondary clock to enable/disable with this clock */
-	struct clk *secondary;
-	/* Reference count of clock enable/disable */
-	__s8 usecount;
-	/* Register bit position for clock's enable/disable control. */
-	u8 enable_shift;
-	/* Register address for clock's enable/disable control. */
-	void __iomem *enable_reg;
-	u32 flags;
-	/* get the current clock rate (always a fresh value) */
-	unsigned long (*get_rate) (struct clk *);
-	/* Function ptr to set the clock to a new rate. The rate must match a
-	   supported rate returned from round_rate. Leave blank if clock is not
-	   programmable */
-	int (*set_rate) (struct clk *, unsigned long);
-	/* Function ptr to round the requested clock rate to the nearest
-	   supported rate that is less than or equal to the requested rate. */
-	unsigned long (*round_rate) (struct clk *, unsigned long);
-	/* Function ptr to enable the clock. Leave blank if clock can not
-	   be gated. */
-	int (*enable) (struct clk *);
-	/* Function ptr to disable the clock. Leave blank if clock can not
-	   be gated. */
-	void (*disable) (struct clk *);
-	/* Function ptr to set the parent clock of the clock. */
-	int (*set_parent) (struct clk *, struct clk *);
-};
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
-#endif /* CONFIG_COMMON_CLK */
-
-extern spinlock_t imx_ccm_lock;
-
-unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref);
-
-#endif /* __ASSEMBLY__ */
-#endif /* __ASM_ARCH_MXC_CLOCK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
index d8b65b5..f79f78a 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
@@ -512,12 +512,16 @@
 #define MX31_PIN_CSPI3_SPI_RDY__CTS3	IOMUX_MODE(MX31_PIN_CSPI3_SPI_RDY, IOMUX_CONFIG_ALT1)
 #define MX31_PIN_CTS1__CTS1		IOMUX_MODE(MX31_PIN_CTS1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RTS1__RTS1		IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_RTS1__SFS		IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_TXD1__TXD1		IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_TXD1__SCK		IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_RXD1__RXD1		IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_RXD1__STXDA		IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_DCD_DCE1__DCD_DCE1	IOMUX_MODE(MX31_PIN_DCD_DCE1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RI_DCE1__RI_DCE1	IOMUX_MODE(MX31_PIN_RI_DCE1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_DSR_DCE1__DSR_DCE1	IOMUX_MODE(MX31_PIN_DSR_DCE1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_DTR_DCE1__DTR_DCE1	IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DTR_DCE1__SRXDA	IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_CTS2__CTS2		IOMUX_MODE(MX31_PIN_CTS2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RTS2__RTS2		IOMUX_MODE(MX31_PIN_RTS2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_TXD2__TXD2		IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_FUNC)
@@ -721,6 +725,7 @@
 #define MX31_PIN_KEY_ROW2_KEY_ROW2	IOMUX_MODE(MX31_PIN_KEY_ROW2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_KEY_ROW3_KEY_ROW3	IOMUX_MODE(MX31_PIN_KEY_ROW3, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_KEY_ROW4_KEY_ROW4	IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW4_GPIO		IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_KEY_ROW5_KEY_ROW5	IOMUX_MODE(MX31_PIN_KEY_ROW5, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_KEY_ROW6_KEY_ROW6	IOMUX_MODE(MX31_PIN_KEY_ROW6, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_KEY_ROW7_KEY_ROW7	IOMUX_MODE(MX31_PIN_KEY_ROW7, IOMUX_CONFIG_FUNC)
diff --git a/arch/arm/plat-mxc/include/mach/mx25.h b/arch/arm/plat-mxc/include/mach/mx25.h
index 627d94f..ec46640 100644
--- a/arch/arm/plat-mxc/include/mach/mx25.h
+++ b/arch/arm/plat-mxc/include/mach/mx25.h
@@ -98,6 +98,7 @@
 #define MX25_INT_UART1		(NR_IRQS_LEGACY + 45)
 #define MX25_INT_GPIO2		(NR_IRQS_LEGACY + 51)
 #define MX25_INT_GPIO1		(NR_IRQS_LEGACY + 52)
+#define MX25_INT_GPT1		(NR_IRQS_LEGACY + 54)
 #define MX25_INT_FEC		(NR_IRQS_LEGACY + 57)
 
 #define MX25_DMA_REQ_SSI2_RX1	22
diff --git a/arch/arm/plat-mxc/include/mach/mx2_cam.h b/arch/arm/plat-mxc/include/mach/mx2_cam.h
index 3c080a3..7ded6f1 100644
--- a/arch/arm/plat-mxc/include/mach/mx2_cam.h
+++ b/arch/arm/plat-mxc/include/mach/mx2_cam.h
@@ -23,7 +23,6 @@
 #ifndef __MACH_MX2_CAM_H_
 #define __MACH_MX2_CAM_H_
 
-#define MX2_CAMERA_SWAP16		(1 << 0)
 #define MX2_CAMERA_EXT_VSYNC		(1 << 1)
 #define MX2_CAMERA_CCIR			(1 << 2)
 #define MX2_CAMERA_CCIR_INTERLACE	(1 << 3)
@@ -31,7 +30,6 @@
 #define MX2_CAMERA_GATED_CLOCK		(1 << 5)
 #define MX2_CAMERA_INV_DATA		(1 << 6)
 #define MX2_CAMERA_PCLK_SAMPLE_RISING	(1 << 7)
-#define MX2_CAMERA_PACK_DIR_MSB		(1 << 8)
 
 /**
  * struct mx2_camera_platform_data - optional platform data for mx2_camera
diff --git a/arch/arm/plat-mxc/include/mach/mx31.h b/arch/arm/plat-mxc/include/mach/mx31.h
index dbced61..ee9b1f9 100644
--- a/arch/arm/plat-mxc/include/mach/mx31.h
+++ b/arch/arm/plat-mxc/include/mach/mx31.h
@@ -76,7 +76,7 @@
 #define MX31_RTIC_BASE_ADDR			(MX31_AIPS2_BASE_ADDR + 0xec000)
 
 #define MX31_ROMP_BASE_ADDR		0x60000000
-#define MX31_ROMP_BASE_ADDR_VIRT	0xfc500000
+#define MX31_ROMP_BASE_ADDR_VIRT	IOMEM(0xfc500000)
 #define MX31_ROMP_SIZE			SZ_1M
 
 #define MX31_AVIC_BASE_ADDR		0x68000000
@@ -92,11 +92,11 @@
 #define MX31_CS3_BASE_ADDR		0xb2000000
 
 #define MX31_CS4_BASE_ADDR		0xb4000000
-#define MX31_CS4_BASE_ADDR_VIRT		0xf6000000
+#define MX31_CS4_BASE_ADDR_VIRT		IOMEM(0xf6000000)
 #define MX31_CS4_SIZE			SZ_32M
 
 #define MX31_CS5_BASE_ADDR		0xb6000000
-#define MX31_CS5_BASE_ADDR_VIRT		0xf8000000
+#define MX31_CS5_BASE_ADDR_VIRT		IOMEM(0xf8000000)
 #define MX31_CS5_SIZE			SZ_32M
 
 #define MX31_X_MEMC_BASE_ADDR		0xb8000000
diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S
index 8397a2d..a8b93c5 100644
--- a/arch/arm/plat-mxc/ssi-fiq.S
+++ b/arch/arm/plat-mxc/ssi-fiq.S
@@ -34,91 +34,98 @@
 		.global imx_ssi_fiq_rx_buffer
 		.global imx_ssi_fiq_tx_buffer
 
+/*
+ * imx_ssi_fiq_start is _intentionally_ not marked as a function symbol
+ * using ENDPROC().  imx_ssi_fiq_start and imx_ssi_fiq_end are used to
+ * mark the function body so that it can be copied to the FIQ vector in
+ * the vectors page.  imx_ssi_fiq_start should only be called as the result
+ * of an FIQ: calling it directly will not work.
+ */
 imx_ssi_fiq_start:
-		ldr r12, imx_ssi_fiq_base
+		ldr r12, .L_imx_ssi_fiq_base
 
 		/* TX */
-		ldr r11, imx_ssi_fiq_tx_buffer
+		ldr r13, .L_imx_ssi_fiq_tx_buffer
 
 		/* shall we send? */
-		ldr r13, [r12, #SSI_SIER]
-		tst r13, #SSI_SIER_TFE0_EN
+		ldr r11, [r12, #SSI_SIER]
+		tst r11, #SSI_SIER_TFE0_EN
 		beq 1f
 
 		/* TX FIFO empty? */
-		ldr r13, [r12, #SSI_SISR]
-		tst r13, #SSI_SISR_TFE0
+		ldr r11, [r12, #SSI_SISR]
+		tst r11, #SSI_SISR_TFE0
 		beq 1f
 
 		mov r10, #0x10000
 		sub r10, #1
 		and r10, r10, r8	/* r10: current buffer offset */
 
-		add r11, r11, r10
+		add r13, r13, r10
 
-		ldrh r13, [r11]
-		strh r13, [r12, #SSI_STX0]
+		ldrh r11, [r13]
+		strh r11, [r12, #SSI_STX0]
 
-		ldrh r13, [r11, #2]
-		strh r13, [r12, #SSI_STX0]
+		ldrh r11, [r13, #2]
+		strh r11, [r12, #SSI_STX0]
 
-		ldrh r13, [r11, #4]
-		strh r13, [r12, #SSI_STX0]
+		ldrh r11, [r13, #4]
+		strh r11, [r12, #SSI_STX0]
 
-		ldrh r13, [r11, #6]
-		strh r13, [r12, #SSI_STX0]
+		ldrh r11, [r13, #6]
+		strh r11, [r12, #SSI_STX0]
 
 		add r10, #8
-		lsr r13, r8, #16	/* r13: buffer size */
-		cmp r10, r13
-		lslgt r8, r13, #16
+		lsr r11, r8, #16	/* r11: buffer size */
+		cmp r10, r11
+		lslgt r8, r11, #16
 		addle r8, #8
 1:
 		/* RX */
 
 		/* shall we receive? */
-		ldr r13, [r12, #SSI_SIER]
-		tst r13, #SSI_SIER_RFF0_EN
+		ldr r11, [r12, #SSI_SIER]
+		tst r11, #SSI_SIER_RFF0_EN
 		beq 1f
 
 		/* RX FIFO full? */
-		ldr r13, [r12, #SSI_SISR]
-		tst r13, #SSI_SISR_RFF0
+		ldr r11, [r12, #SSI_SISR]
+		tst r11, #SSI_SISR_RFF0
 		beq 1f
 
-		ldr r11, imx_ssi_fiq_rx_buffer
+		ldr r13, .L_imx_ssi_fiq_rx_buffer
 
 		mov r10, #0x10000
 		sub r10, #1
 		and r10, r10, r9	/* r10: current buffer offset */
 
-		add r11, r11, r10
+		add r13, r13, r10
 
-		ldr r13, [r12, #SSI_SACNT]
-		tst r13, #SSI_SACNT_AC97EN
+		ldr r11, [r12, #SSI_SACNT]
+		tst r11, #SSI_SACNT_AC97EN
 
-		ldr r13, [r12, #SSI_SRX0]
-		strh r13, [r11]
+		ldr r11, [r12, #SSI_SRX0]
+		strh r11, [r13]
 
-		ldr r13, [r12, #SSI_SRX0]
-		strh r13, [r11, #2]
+		ldr r11, [r12, #SSI_SRX0]
+		strh r11, [r13, #2]
 
 		/* dummy read to skip slot 12 */
-		ldrne r13, [r12, #SSI_SRX0]
+		ldrne r11, [r12, #SSI_SRX0]
 
-		ldr r13, [r12, #SSI_SRX0]
-		strh r13, [r11, #4]
+		ldr r11, [r12, #SSI_SRX0]
+		strh r11, [r13, #4]
 
-		ldr r13, [r12, #SSI_SRX0]
-		strh r13, [r11, #6]
+		ldr r11, [r12, #SSI_SRX0]
+		strh r11, [r13, #6]
 
 		/* dummy read to skip slot 12 */
-		ldrne r13, [r12, #SSI_SRX0]
+		ldrne r11, [r12, #SSI_SRX0]
 
 		add r10, #8
-		lsr r13, r9, #16	/* r13: buffer size */
-		cmp r10, r13
-		lslgt r9, r13, #16
+		lsr r11, r9, #16	/* r11: buffer size */
+		cmp r10, r11
+		lslgt r9, r11, #16
 		addle r9, #8
 
 1:
@@ -126,11 +133,15 @@
 		subs	pc, lr, #4
 
 		.align
+.L_imx_ssi_fiq_base:
 imx_ssi_fiq_base:
 		.word 0x0
+.L_imx_ssi_fiq_rx_buffer:
 imx_ssi_fiq_rx_buffer:
 		.word 0x0
+.L_imx_ssi_fiq_tx_buffer:
 imx_ssi_fiq_tx_buffer:
 		.word 0x0
+.L_imx_ssi_fiq_end:
 imx_ssi_fiq_end:
 
diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c
index 1996c3e..3da78cf 100644
--- a/arch/arm/plat-mxc/system.c
+++ b/arch/arm/plat-mxc/system.c
@@ -21,7 +21,6 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/delay.h>
-#include <linux/module.h>
 
 #include <mach/hardware.h>
 #include <mach/common.h>
@@ -29,9 +28,6 @@
 #include <asm/proc-fns.h>
 #include <asm/mach-types.h>
 
-void __iomem *(*imx_ioremap)(unsigned long, size_t, unsigned int) = NULL;
-EXPORT_SYMBOL_GPL(imx_ioremap);
-
 static void __iomem *wdog_base;
 
 /*
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index a017e99..dacaee0 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := common.o sram.o clock.o dma.o mux.o fb.o counter_32k.o
+obj-y := common.o sram.o clock.o dma.o fb.o counter_32k.o
 obj-m :=
 obj-n :=
 obj-  :=
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index e5778ed..111315a 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -18,7 +18,7 @@
 
 #include <plat/common.h>
 #include <plat/vram.h>
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 #include <plat/dma.h>
 
 #include <plat/omap-secure.h>
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 6dcad58..c76ed8b 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -968,8 +968,7 @@
 			l = p->dma_read(CCR, lch);
 		}
 		if (i >= 100)
-			printk(KERN_ERR "DMA drain did not complete on "
-					"lch %d\n", lch);
+			pr_err("DMA drain did not complete on lch %d\n", lch);
 		/* Restore OCP_SYSCONFIG */
 		p->dma_write(sys_cf, OCP_SYSCONFIG, lch);
 	} else {
@@ -1153,8 +1152,7 @@
 
 	if ((dma_chan[lch_head].dev_id == -1) ||
 	    (dma_chan[lch_queue].dev_id == -1)) {
-		printk(KERN_ERR "omap_dma: trying to link "
-		       "non requested channels\n");
+		pr_err("omap_dma: trying to link non requested channels\n");
 		dump_stack();
 	}
 
@@ -1180,15 +1178,13 @@
 
 	if (dma_chan[lch_head].next_lch != lch_queue ||
 	    dma_chan[lch_head].next_lch == -1) {
-		printk(KERN_ERR "omap_dma: trying to unlink "
-		       "non linked channels\n");
+		pr_err("omap_dma: trying to unlink non linked channels\n");
 		dump_stack();
 	}
 
 	if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) ||
 	    (dma_chan[lch_queue].flags & OMAP_DMA_ACTIVE)) {
-		printk(KERN_ERR "omap_dma: You need to stop the DMA channels "
-		       "before unlinking\n");
+		pr_err("omap_dma: You need to stop the DMA channels before unlinking\n");
 		dump_stack();
 	}
 
@@ -1830,16 +1826,15 @@
 	if ((csr & 0x3f) == 0)
 		return 0;
 	if (unlikely(dma_chan[ch].dev_id == -1)) {
-		printk(KERN_WARNING "Spurious interrupt from DMA channel "
-		       "%d (CSR %04x)\n", ch, csr);
+		pr_warn("Spurious interrupt from DMA channel %d (CSR %04x)\n",
+			ch, csr);
 		return 0;
 	}
 	if (unlikely(csr & OMAP1_DMA_TOUT_IRQ))
-		printk(KERN_WARNING "DMA timeout with device %d\n",
-		       dma_chan[ch].dev_id);
+		pr_warn("DMA timeout with device %d\n", dma_chan[ch].dev_id);
 	if (unlikely(csr & OMAP_DMA_DROP_IRQ))
-		printk(KERN_WARNING "DMA synchronization event drop occurred "
-		       "with device %d\n", dma_chan[ch].dev_id);
+		pr_warn("DMA synchronization event drop occurred with device %d\n",
+			dma_chan[ch].dev_id);
 	if (likely(csr & OMAP_DMA_BLOCK_IRQ))
 		dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
 	if (likely(dma_chan[ch].callback != NULL))
@@ -1879,21 +1874,19 @@
 
 	if (!status) {
 		if (printk_ratelimit())
-			printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n",
-				ch);
+			pr_warn("Spurious DMA IRQ for lch %d\n", ch);
 		p->dma_write(1 << ch, IRQSTATUS_L0, ch);
 		return 0;
 	}
 	if (unlikely(dma_chan[ch].dev_id == -1)) {
 		if (printk_ratelimit())
-			printk(KERN_WARNING "IRQ %04x for non-allocated DMA"
-					"channel %d\n", status, ch);
+			pr_warn("IRQ %04x for non-allocated DMA channel %d\n",
+				status, ch);
 		return 0;
 	}
 	if (unlikely(status & OMAP_DMA_DROP_IRQ))
-		printk(KERN_INFO
-		       "DMA synchronization event drop occurred with device "
-		       "%d\n", dma_chan[ch].dev_id);
+		pr_info("DMA synchronization event drop occurred with device %d\n",
+			dma_chan[ch].dev_id);
 	if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ)) {
 		printk(KERN_INFO "DMA transaction error with device %d\n",
 		       dma_chan[ch].dev_id);
@@ -2013,8 +2006,9 @@
 
 	p = pdev->dev.platform_data;
 	if (!p) {
-		dev_err(&pdev->dev, "%s: System DMA initialized without"
-			"platform data\n", __func__);
+		dev_err(&pdev->dev,
+			"%s: System DMA initialized without platform data\n",
+			__func__);
 		return -EINVAL;
 	}
 
@@ -2089,8 +2083,8 @@
 		}
 		ret = setup_irq(dma_irq, &omap24xx_dma_irq);
 		if (ret) {
-			dev_err(&pdev->dev, "set_up failed for IRQ %d"
-				"for DMA (error %d)\n", dma_irq, ret);
+			dev_err(&pdev->dev, "set_up failed for IRQ %d for DMA (error %d)\n",
+				dma_irq, ret);
 			goto exit_dma_lch_fail;
 		}
 	}
@@ -2098,8 +2092,7 @@
 	/* reserve dma channels 0 and 1 in high security devices */
 	if (cpu_is_omap34xx() &&
 		(omap_type() != OMAP2_DEVICE_TYPE_GP)) {
-		printk(KERN_INFO "Reserving DMA channels 0 and 1 for "
-				"HS ROM code\n");
+		pr_info("Reserving DMA channels 0 and 1 for HS ROM code\n");
 		dma_chan[0].dev_id = 0;
 		dma_chan[1].dev_id = 1;
 	}
@@ -2107,8 +2100,8 @@
 	return 0;
 
 exit_dma_irq_fail:
-	dev_err(&pdev->dev, "unable to request IRQ %d"
-			"for DMA (error %d)\n", dma_irq, ret);
+	dev_err(&pdev->dev, "unable to request IRQ %d for DMA (error %d)\n",
+		dma_irq, ret);
 	for (irq_rel = 0; irq_rel < ch;	irq_rel++) {
 		dma_irq = platform_get_irq(pdev, irq_rel);
 		free_irq(dma_irq, (void *)(irq_rel + 1));
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 40bc06a..6013831 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -32,7 +32,6 @@
 #include <linux/clk.h>
 
 #include <mach/irqs.h>
-#include <plat/mux.h>
 #include <plat/i2c.h>
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index a531149..f4a4cd0 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -21,8 +21,6 @@
 #include <linux/device.h>
 #include <linux/pm_qos.h>
 
-#include <plat/mux.h>
-
 #define DRIVER_NAME	"omap_uart"
 
 /*
@@ -54,7 +52,7 @@
 
 #define OMAP_UART_DMA_CH_FREE	-1
 
-#define OMAP_MAX_HSUART_PORTS	4
+#define OMAP_MAX_HSUART_PORTS	6
 
 #define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
 
diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index 4327b2c..e7259c0 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -60,6 +60,7 @@
  * @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM
  * @_state: one of OMAP_DEVICE_STATE_* (see above)
  * @flags: device flags
+ * @_driver_status: one of BUS_NOTIFY_*_DRIVER from <linux/device.h>
  *
  * Integrates omap_hwmod data into Linux platform_device.
  *
@@ -73,6 +74,7 @@
 	struct omap_device_pm_latency	*pm_lats;
 	u32				dev_wakeup_lat;
 	u32				_dev_wakeup_lat_limit;
+	unsigned long			_driver_status;
 	u8				pm_lats_cnt;
 	s8				pm_lat_level;
 	u8				hwmods_cnt;
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 5857b9c..0533073 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -659,6 +659,7 @@
 extern int omap2430_hwmod_init(void);
 extern int omap3xxx_hwmod_init(void);
 extern int omap44xx_hwmod_init(void);
+extern int am33xx_hwmod_init(void);
 
 extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
 
diff --git a/arch/arm/plat-omap/include/plat/param.h b/arch/arm/plat-omap/include/plat/param.h
deleted file mode 100644
index 1eb4dc3..0000000
--- a/arch/arm/plat-omap/include/plat/param.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- *  arch/arm/plat-omap/include/mach/param.h
- *
- */
-
-#ifdef CONFIG_OMAP_32K_TIMER_HZ
-#define HZ	CONFIG_OMAP_32K_TIMER_HZ
-#endif
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
deleted file mode 100644
index cff8712..0000000
--- a/arch/arm/plat-omap/mux.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/mux.c
- *
- * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
- *
- * Copyright (C) 2003 - 2008 Nokia Corporation
- *
- * Written by Tony Lindgren
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-
-#include <asm/system.h>
-
-#include <plat/cpu.h>
-#include <plat/mux.h>
-
-#ifdef CONFIG_OMAP_MUX
-
-static struct omap_mux_cfg *mux_cfg;
-
-int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
-{
-	if (!arch_mux_cfg || !arch_mux_cfg->pins || arch_mux_cfg->size == 0
-			|| !arch_mux_cfg->cfg_reg) {
-		printk(KERN_ERR "Invalid pin table\n");
-		return -EINVAL;
-	}
-
-	mux_cfg = arch_mux_cfg;
-
-	return 0;
-}
-
-/*
- * Sets the Omap MUX and PULL_DWN registers based on the table
- */
-int __init_or_module omap_cfg_reg(const unsigned long index)
-{
-	struct pin_config *reg;
-
-	if (!cpu_class_is_omap1()) {
-		printk(KERN_ERR "mux: Broken omap_cfg_reg(%lu) entry\n",
-				index);
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	if (mux_cfg == NULL) {
-		printk(KERN_ERR "Pin mux table not initialized\n");
-		return -ENODEV;
-	}
-
-	if (index >= mux_cfg->size) {
-		printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
-		       index, mux_cfg->size);
-		dump_stack();
-		return -ENODEV;
-	}
-
-	reg = (struct pin_config *)&mux_cfg->pins[index];
-
-	if (!mux_cfg->cfg_reg)
-		return -ENODEV;
-
-	return mux_cfg->cfg_reg(reg);
-}
-EXPORT_SYMBOL(omap_cfg_reg);
-#else
-#define omap_mux_init() do {} while(0)
-#define omap_cfg_reg(x)	do {} while(0)
-#endif	/* CONFIG_OMAP_MUX */
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index 5a97b4d..9f641332 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -41,11 +41,11 @@
 	};
 
 	if (t == -1)
-		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
-			 "dev %s\n", dev_name(dev));
+		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: dev %s\n",
+			 dev_name(dev));
 	else
-		pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+		pr_debug("OMAP PM: add max MPU wakeup latency constraint: dev %s, t = %ld usec\n",
+			 dev_name(dev), t);
 
 	/*
 	 * For current Linux, this needs to map the MPU to a
@@ -70,11 +70,10 @@
 	};
 
 	if (r == 0)
-		pr_debug("OMAP PM: remove min bus tput constraint: "
-			 "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+		pr_debug("OMAP PM: remove min bus tput constraint: dev %s for agent_id %d\n",
+			 dev_name(dev), agent_id);
 	else
-		pr_debug("OMAP PM: add min bus tput constraint: "
-			 "dev %s for agent_id %d: rate %ld KiB\n",
+		pr_debug("OMAP PM: add min bus tput constraint: dev %s for agent_id %d: rate %ld KiB\n",
 			 dev_name(dev), agent_id, r);
 
 	/*
@@ -97,11 +96,11 @@
 	};
 
 	if (t == -1)
-		pr_debug("OMAP PM: remove max device latency constraint: "
-			 "dev %s\n", dev_name(dev));
+		pr_debug("OMAP PM: remove max device latency constraint: dev %s\n",
+			 dev_name(dev));
 	else
-		pr_debug("OMAP PM: add max device latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+		pr_debug("OMAP PM: add max device latency constraint: dev %s, t = %ld usec\n",
+			 dev_name(dev), t);
 
 	/*
 	 * For current Linux, this needs to map the device to a
@@ -127,11 +126,11 @@
 	};
 
 	if (t == -1)
-		pr_debug("OMAP PM: remove max DMA latency constraint: "
-			 "dev %s\n", dev_name(dev));
+		pr_debug("OMAP PM: remove max DMA latency constraint: dev %s\n",
+			 dev_name(dev));
 	else
-		pr_debug("OMAP PM: add max DMA latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+		pr_debug("OMAP PM: add max DMA latency constraint: dev %s, t = %ld usec\n",
+			 dev_name(dev), t);
 
 	/*
 	 * For current Linux PM QOS params, this code should scan the
@@ -156,11 +155,11 @@
 	}
 
 	if (r == 0)
-		pr_debug("OMAP PM: remove min clk rate constraint: "
-			 "dev %s\n", dev_name(dev));
+		pr_debug("OMAP PM: remove min clk rate constraint: dev %s\n",
+			 dev_name(dev));
 	else
-		pr_debug("OMAP PM: add min clk rate constraint: "
-			 "dev %s, rate = %ld Hz\n", dev_name(dev), r);
+		pr_debug("OMAP PM: add min clk rate constraint: dev %s, rate = %ld Hz\n",
+			 dev_name(dev), r);
 
 	/*
 	 * Code in a real implementation should keep track of these
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 6f5c580..d5f617c 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -1,4 +1,3 @@
-
 /*
  * omap_device implementation
  *
@@ -153,21 +152,19 @@
 		act_lat = timespec_to_ns(&c);
 
 		dev_dbg(&od->pdev->dev,
-			"omap_device: pm_lat %d: activate: elapsed time "
-			"%llu nsec\n", od->pm_lat_level, act_lat);
+			"omap_device: pm_lat %d: activate: elapsed time %llu nsec\n",
+			od->pm_lat_level, act_lat);
 
 		if (act_lat > odpl->activate_lat) {
 			odpl->activate_lat_worst = act_lat;
 			if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 				odpl->activate_lat = act_lat;
 				dev_dbg(&od->pdev->dev,
-					"new worst case activate latency "
-					"%d: %llu\n",
+					"new worst case activate latency %d: %llu\n",
 					od->pm_lat_level, act_lat);
 			} else
 				dev_warn(&od->pdev->dev,
-					 "activate latency %d "
-					 "higher than exptected. (%llu > %d)\n",
+					 "activate latency %d higher than expected. (%llu > %d)\n",
 					 od->pm_lat_level, act_lat,
 					 odpl->activate_lat);
 		}
@@ -220,21 +217,19 @@
 		deact_lat = timespec_to_ns(&c);
 
 		dev_dbg(&od->pdev->dev,
-			"omap_device: pm_lat %d: deactivate: elapsed time "
-			"%llu nsec\n", od->pm_lat_level, deact_lat);
+			"omap_device: pm_lat %d: deactivate: elapsed time %llu nsec\n",
+			od->pm_lat_level, deact_lat);
 
 		if (deact_lat > odpl->deactivate_lat) {
 			odpl->deactivate_lat_worst = deact_lat;
 			if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 				odpl->deactivate_lat = deact_lat;
 				dev_dbg(&od->pdev->dev,
-					"new worst case deactivate latency "
-					"%d: %llu\n",
+					"new worst case deactivate latency %d: %llu\n",
 					od->pm_lat_level, deact_lat);
 			} else
 				dev_warn(&od->pdev->dev,
-					 "deactivate latency %d "
-					 "higher than exptected. (%llu > %d)\n",
+					 "deactivate latency %d higher than expected. (%llu > %d)\n",
 					 od->pm_lat_level, deact_lat,
 					 odpl->deactivate_lat);
 		}
@@ -393,17 +388,21 @@
 				      unsigned long event, void *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *od;
 
 	switch (event) {
-	case BUS_NOTIFY_ADD_DEVICE:
-		if (pdev->dev.of_node)
-			omap_device_build_from_dt(pdev);
-		break;
-
 	case BUS_NOTIFY_DEL_DEVICE:
 		if (pdev->archdata.od)
 			omap_device_delete(pdev->archdata.od);
 		break;
+	case BUS_NOTIFY_ADD_DEVICE:
+		if (pdev->dev.of_node)
+			omap_device_build_from_dt(pdev);
+		/* fall through */
+	default:
+		od = to_omap_device(pdev);
+		if (od)
+			od->_driver_status = event;
 	}
 
 	return NOTIFY_DONE;
@@ -457,8 +456,8 @@
 	for (i = 0; i < od->hwmods_cnt; i++)
 		c += omap_hwmod_count_resources(od->hwmods[i]);
 
-	pr_debug("omap_device: %s: counted %d total resources across %d "
-		 "hwmods\n", od->pdev->name, c, od->hwmods_cnt);
+	pr_debug("omap_device: %s: counted %d total resources across %d hwmods\n",
+		 od->pdev->name, c, od->hwmods_cnt);
 
 	return c;
 }
@@ -807,6 +806,10 @@
 	struct omap_device *od = to_omap_device(pdev);
 	int ret;
 
+	/* Don't attempt late suspend on a driver that is not bound */
+	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
+		return 0;
+
 	ret = pm_generic_suspend_noirq(dev);
 
 	if (!ret && !pm_runtime_status_suspended(dev)) {
@@ -1180,3 +1183,41 @@
 	return 0;
 }
 core_initcall(omap_device_init);
+
+/**
+ * omap_device_late_idle - idle devices without drivers
+ * @dev: struct device * associated with omap_device
+ * @data: unused
+ *
+ * Check the driver bound status of this device, and idle it
+ * if there is no driver attached.
+ */
+static int __init omap_device_late_idle(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *od = to_omap_device(pdev);
+
+	if (!od)
+		return 0;
+
+	/*
+	 * If omap_device state is enabled, but has no driver bound,
+	 * idle it.
+	 */
+	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+		if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
+			dev_warn(dev, "%s: enabled but no driver.  Idling\n",
+				 __func__);
+			omap_device_idle(pdev);
+		}
+	}
+
+	return 0;
+}
+
+static int __init omap_device_late_init(void)
+{
+	bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
+	return 0;
+}
+late_initcall(omap_device_late_init);
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 65c5eca..012bbd0 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -119,7 +119,7 @@
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-	if (IS_ERR(clk))
+	if (IS_ERR_OR_NULL(clk))
 		return 0;
 
 	if (clk->rate != 0)
@@ -136,7 +136,7 @@
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-	if (!IS_ERR(clk) && clk->ops && clk->ops->round_rate)
+	if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate)
 		return (clk->ops->round_rate)(clk, rate);
 
 	return rate;
@@ -144,9 +144,10 @@
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
+	unsigned long flags;
 	int ret;
 
-	if (IS_ERR(clk))
+	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
 
 	/* We do not default just do a clk->rate = rate as
@@ -159,9 +160,9 @@
 	if (clk->ops == NULL || clk->ops->set_rate == NULL)
 		return -EINVAL;
 
-	spin_lock(&clocks_lock);
+	spin_lock_irqsave(&clocks_lock, flags);
 	ret = (clk->ops->set_rate)(clk, rate);
-	spin_unlock(&clocks_lock);
+	spin_unlock_irqrestore(&clocks_lock, flags);
 
 	return ret;
 }
@@ -173,17 +174,18 @@
 
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
+	unsigned long flags;
 	int ret = 0;
 
-	if (IS_ERR(clk))
+	if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(parent))
 		return -EINVAL;
 
-	spin_lock(&clocks_lock);
+	spin_lock_irqsave(&clocks_lock, flags);
 
 	if (clk->ops && clk->ops->set_parent)
 		ret = (clk->ops->set_parent)(clk, parent);
 
-	spin_unlock(&clocks_lock);
+	spin_unlock_irqrestore(&clocks_lock, flags);
 
 	return ret;
 }
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index fc49f3d..8d26ce6 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -35,7 +35,6 @@
 #include <media/s5p_hdmi.h>
 
 #include <asm/irq.h>
-#include <asm/pmu.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -52,6 +51,7 @@
 #include <plat/ehci.h>
 #include <plat/fb.h>
 #include <plat/fb-s3c2410.h>
+#include <plat/hdmi.h>
 #include <plat/hwmon.h>
 #include <plat/iic.h>
 #include <plat/keypad.h>
@@ -763,7 +763,7 @@
 			       &s5p_device_i2c_hdmiphy);
 }
 
-struct s5p_hdmi_platform_data s5p_hdmi_def_platdata;
+static struct s5p_hdmi_platform_data s5p_hdmi_def_platdata;
 
 void __init s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info,
 				  struct i2c_board_info *mhl_info, int mhl_bus)
@@ -1132,7 +1132,7 @@
 
 static struct platform_device s5p_device_pmu = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(s5p_pmu_resource),
 	.resource	= s5p_pmu_resource,
 };
@@ -1591,6 +1591,8 @@
 void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 						int num_cs)
 {
+	struct s3c64xx_spi_info pd;
+
 	/* Reject invalid configuration */
 	if (!num_cs || src_clk_nr < 0) {
 		pr_err("%s: Invalid SPI configuration\n", __func__);
diff --git a/arch/arm/plat-samsung/include/plat/gpio-fns.h b/arch/arm/plat-samsung/include/plat/gpio-fns.h
index bab1392..d1ecef0 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-fns.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-fns.h
@@ -1,98 +1 @@
-/* arch/arm/mach-s3c2410/include/mach/gpio-fns.h
- *
- * Copyright (c) 2003-2009 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - hardware
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __MACH_GPIO_FNS_H
-#define __MACH_GPIO_FNS_H __FILE__
-
-/* These functions are in the to-be-removed category and it is strongly
- * encouraged not to use these in new code. They will be marked deprecated
- * very soon.
- *
- * Most of the functionality can be either replaced by the gpiocfg calls
- * for the s3c platform or by the generic GPIOlib API.
- *
- * As of 2.6.35-rc, these will be removed, with the few drivers using them
- * either replaced or given a wrapper until the calls can be removed.
-*/
-
 #include <plat/gpio-cfg.h>
-
-static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg)
-{
-	/* 1:1 mapping between cfgpin and setcfg calls at the moment */
-	s3c_gpio_cfgpin(pin, cfg);
-}
-
-/* external functions for GPIO support
- *
- * These allow various different clients to access the same GPIO
- * registers without conflicting. If your driver only owns the entire
- * GPIO register, then it is safe to ioremap/__raw_{read|write} to it.
-*/
-
-extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
-
-/* s3c2410_gpio_getirq
- *
- * turn the given pin number into the corresponding IRQ number
- *
- * returns:
- *	< 0 = no interrupt for this pin
- *	>=0 = interrupt number for the pin
-*/
-
-extern int s3c2410_gpio_getirq(unsigned int pin);
-
-/* s3c2410_gpio_irqfilter
- *
- * set the irq filtering on the given pin
- *
- * on = 0 => disable filtering
- *      1 => enable filtering
- *
- * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
- *          width of filter (0 through 63)
- *
- *
-*/
-
-extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
-				  unsigned int config);
-
-/* s3c2410_gpio_pullup
- *
- * This call should be replaced with s3c_gpio_setpull().
- *
- * As a note, there is currently no distinction between pull-up and pull-down
- * in the s3c24xx series devices with only an on/off configuration.
- */
-
-/* s3c2410_gpio_pullup
- *
- * configure the pull-up control on the given pin
- *
- * to = 1 => disable the pull-up
- *      0 => enable the pull-up
- *
- * eg;
- *
- *   s3c2410_gpio_pullup(S3C2410_GPB(0), 0);
- *   s3c2410_gpio_pullup(S3C2410_GPE(8), 0);
-*/
-
-extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
-
-extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
-
-extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
-
-#endif /* __MACH_GPIO_FNS_H */
diff --git a/arch/arm/plat-samsung/s5p-irq-gpioint.c b/arch/arm/plat-samsung/s5p-irq-gpioint.c
index f9431fe..23557d3 100644
--- a/arch/arm/plat-samsung/s5p-irq-gpioint.c
+++ b/arch/arm/plat-samsung/s5p-irq-gpioint.c
@@ -24,7 +24,7 @@
 
 #include <asm/mach/irq.h>
 
-#define GPIO_BASE(chip)		(((unsigned long)(chip)->base) & 0xFFFFF000u)
+#define GPIO_BASE(chip)		((void __iomem *)((unsigned long)((chip)->base) & 0xFFFFF000u))
 
 #define CON_OFFSET		0x700
 #define MASK_OFFSET		0x900
@@ -153,7 +153,7 @@
 	bank->chips[group - bank->start] = chip;
 
 	gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
-				    (void __iomem *)GPIO_BASE(chip),
+				    GPIO_BASE(chip),
 				    handle_level_irq);
 	if (!gc)
 		return -ENOMEM;
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2997e56..7bc7948 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -158,7 +158,6 @@
 stargate2		MACH_STARGATE2		STARGATE2		774
 intelmote2		MACH_INTELMOTE2		INTELMOTE2		775
 trizeps4		MACH_TRIZEPS4		TRIZEPS4		776
-pnx4008			MACH_PNX4008		PNX4008			782
 cpuat91			MACH_CPUAT91		CPUAT91			787
 iq81340sc		MACH_IQ81340SC		IQ81340SC		799
 iq81340mc		MACH_IQ81340MC		IQ81340MC		801
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
new file mode 100644
index 0000000..767ba56
--- /dev/null
+++ b/arch/arm64/Kconfig
@@ -0,0 +1,222 @@
+config ARM64
+	def_bool y
+	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+	select GENERIC_CLOCKEVENTS
+	select GENERIC_HARDIRQS_NO_DEPRECATED
+	select GENERIC_IOMAP
+	select GENERIC_IRQ_PROBE
+	select GENERIC_IRQ_SHOW
+	select GENERIC_SMP_IDLE_THREAD
+	select GENERIC_TIME_VSYSCALL
+	select HARDIRQS_SW_RESEND
+	select HAVE_ARCH_TRACEHOOK
+	select HAVE_DMA_API_DEBUG
+	select HAVE_DMA_ATTRS
+	select HAVE_GENERIC_DMA_COHERENT
+	select HAVE_GENERIC_HARDIRQS
+	select HAVE_HW_BREAKPOINT if PERF_EVENTS
+	select HAVE_IRQ_WORK
+	select HAVE_MEMBLOCK
+	select HAVE_PERF_EVENTS
+	select HAVE_SPARSE_IRQ
+	select IRQ_DOMAIN
+	select NO_BOOTMEM
+	select OF
+	select OF_EARLY_FLATTREE
+	select PERF_USE_VMALLOC
+	select RTC_LIB
+	select SPARSE_IRQ
+	help
+	  ARM 64-bit (AArch64) Linux support.
+
+config 64BIT
+	def_bool y
+
+config ARCH_PHYS_ADDR_T_64BIT
+	def_bool y
+
+config MMU
+	def_bool y
+
+config NO_IOPORT
+	def_bool y
+
+config STACKTRACE_SUPPORT
+	def_bool y
+
+config LOCKDEP_SUPPORT
+	def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+	def_bool y
+
+config GENERIC_LOCKBREAK
+	def_bool y
+	depends on SMP && PREEMPT
+
+config RWSEM_GENERIC_SPINLOCK
+	def_bool y
+
+config GENERIC_HWEIGHT
+	def_bool y
+
+config GENERIC_CSUM
+        def_bool y
+
+config GENERIC_CALIBRATE_DELAY
+	def_bool y
+
+config ZONE_DMA32
+	def_bool y
+
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool y
+
+config NEED_DMA_MAP_STATE
+	def_bool y
+
+config NEED_SG_DMA_LENGTH
+	def_bool y
+
+config SWIOTLB
+	def_bool y
+
+config IOMMU_HELPER
+	def_bool SWIOTLB
+
+source "init/Kconfig"
+
+source "kernel/Kconfig.freezer"
+
+menu "System Type"
+
+endmenu
+
+menu "Bus support"
+
+config ARM_AMBA
+	bool
+
+endmenu
+
+menu "Kernel Features"
+
+source "kernel/time/Kconfig"
+
+config ARM64_64K_PAGES
+	bool "Enable 64KB pages support"
+	help
+	  This feature enables 64KB pages support (4KB by default)
+	  allowing only two levels of page tables and faster TLB
+	  look-up. AArch32 emulation is not available when this feature
+	  is enabled.
+
+config SMP
+	bool "Symmetric Multi-Processing"
+	select USE_GENERIC_SMP_HELPERS
+	help
+	  This enables support for systems with more than one CPU.  If
+	  you say N here, the kernel will run on single and
+	  multiprocessor machines, but will use only one CPU of a
+	  multiprocessor machine. If you say Y here, the kernel will run
+	  on many, but not all, single processor machines. On a single
+	  processor machine, the kernel will run faster if you say N
+	  here.
+
+	  If you don't know what to do here, say N.
+
+config NR_CPUS
+	int "Maximum number of CPUs (2-32)"
+	range 2 32
+	depends on SMP
+	default "4"
+
+source kernel/Kconfig.preempt
+
+config HZ
+	int
+	default 100
+
+config ARCH_HAS_HOLES_MEMORYMODEL
+	def_bool y if SPARSEMEM
+
+config ARCH_SPARSEMEM_ENABLE
+	def_bool y
+	select SPARSEMEM_VMEMMAP_ENABLE
+
+config ARCH_SPARSEMEM_DEFAULT
+	def_bool ARCH_SPARSEMEM_ENABLE
+
+config ARCH_SELECT_MEMORY_MODEL
+	def_bool ARCH_SPARSEMEM_ENABLE
+
+config HAVE_ARCH_PFN_VALID
+	def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
+
+config HW_PERF_EVENTS
+	bool "Enable hardware performance counter support for perf events"
+	depends on PERF_EVENTS
+	default y
+	help
+	  Enable hardware performance counter support for perf events. If
+	  disabled, perf events will use software events only.
+
+source "mm/Kconfig"
+
+endmenu
+
+menu "Boot options"
+
+config CMDLINE
+	string "Default kernel command string"
+	default ""
+	help
+	  Provide a set of default command-line options at build time by
+	  entering them here. As a minimum, you should specify the the
+	  root device (e.g. root=/dev/nfs).
+
+config CMDLINE_FORCE
+	bool "Always use the default kernel command string"
+	help
+	  Always use the default kernel command string, even if the boot
+	  loader passes other arguments to the kernel.
+	  This is useful if you cannot or don't want to change the
+	  command-line options your boot loader passes to the kernel.
+
+endmenu
+
+menu "Userspace binary formats"
+
+source "fs/Kconfig.binfmt"
+
+config COMPAT
+	bool "Kernel support for 32-bit EL0"
+	depends on !ARM64_64K_PAGES
+	select COMPAT_BINFMT_ELF
+	help
+	  This option enables support for a 32-bit EL0 running under a 64-bit
+	  kernel at EL1. AArch32-specific components such as system calls,
+	  the user helper functions, VFP support and the ptrace interface are
+	  handled appropriately by the kernel.
+
+	  If you want to execute 32-bit userspace applications, say Y.
+
+config SYSVIPC_COMPAT
+	def_bool y
+	depends on COMPAT && SYSVIPC
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/arm64/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
new file mode 100644
index 0000000..d7553f2
--- /dev/null
+++ b/arch/arm64/Kconfig.debug
@@ -0,0 +1,27 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config FRAME_POINTER
+	bool
+	default y
+
+config DEBUG_ERRORS
+	bool "Verbose kernel error messages"
+	depends on DEBUG_KERNEL
+	help
+	  This option controls verbose debugging information which can be
+	  printed when the kernel detects an internal error. This debugging
+	  information is useful to kernel hackers when tracking down problems,
+	  but mostly meaningless to other people. It's safe to say Y unless
+	  you are concerned with the code size or don't want to see these
+	  messages.
+
+config DEBUG_STACK_USAGE
+	bool "Enable stack utilization instrumentation"
+	depends on DEBUG_KERNEL
+	help
+	  Enables the display of the minimum amount of free stack which each
+	  task has ever had available in the sysrq-T output.
+
+endmenu
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
new file mode 100644
index 0000000..364191f
--- /dev/null
+++ b/arch/arm64/Makefile
@@ -0,0 +1,71 @@
+#
+# arch/arm64/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies.
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995-2001 by Russell King
+
+LDFLAGS_vmlinux	:=-p --no-undefined -X
+CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
+OBJCOPYFLAGS	:=-O binary -R .note -R .note.gnu.build-id -R .comment -S
+GZFLAGS		:=-9
+
+LIBGCC 		:= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+
+KBUILD_DEFCONFIG := defconfig
+
+KBUILD_CFLAGS	+= -mgeneral-regs-only
+KBUILD_CPPFLAGS	+= -mlittle-endian
+AS		+= -EL
+LD		+= -EL
+
+comma = ,
+
+CHECKFLAGS	+= -D__aarch64__
+
+# Default value
+head-y		:= arch/arm64/kernel/head.o
+
+# The byte offset of the kernel image in RAM from the start of RAM.
+TEXT_OFFSET := 0x00080000
+
+export	TEXT_OFFSET GZFLAGS
+
+core-y		+= arch/arm64/kernel/ arch/arm64/mm/
+libs-y		:= arch/arm64/lib/ $(libs-y)
+libs-y		+= $(LIBGCC)
+
+# Default target when executing plain make
+KBUILD_IMAGE := Image.gz
+
+all:	$(KBUILD_IMAGE)
+
+boot := arch/arm64/boot
+
+Image Image.gz: vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
+zinstall install: vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
+
+%.dtb:
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
+# We use MRPROPER_FILES and CLEAN_FILES now
+archclean:
+	$(Q)$(MAKE) $(clean)=$(boot)
+
+define archhelp
+  echo  '* Image.gz      - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
+  echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
+  echo  '  install       - Install uncompressed kernel'
+  echo  '  zinstall      - Install compressed kernel'
+  echo  '                  Install using (your) ~/bin/installkernel or'
+  echo  '                  (distribution) /sbin/installkernel or'
+  echo  '                  install to $$(INSTALL_PATH) and run lilo'
+endef
diff --git a/arch/arm64/boot/.gitignore b/arch/arm64/boot/.gitignore
new file mode 100644
index 0000000..8dab0bb
--- /dev/null
+++ b/arch/arm64/boot/.gitignore
@@ -0,0 +1,2 @@
+Image
+Image.gz
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
new file mode 100644
index 0000000..eca209b
--- /dev/null
+++ b/arch/arm64/boot/Makefile
@@ -0,0 +1,36 @@
+#
+# arch/arm64/boot/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies.
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2012, ARM Ltd.
+# Author: Will Deacon <will.deacon@arm.com>
+#
+# Based on the ia64 boot/Makefile.
+#
+
+targets := Image Image.gz
+
+$(obj)/Image: vmlinux FORCE
+	$(call if_changed,objcopy)
+
+$(obj)/Image.gz: $(obj)/Image FORCE
+	$(call if_changed,gzip)
+
+$(obj)/%.dtb: $(src)/dts/%.dts
+	$(call cmd,dtc)
+
+install: $(obj)/Image
+	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+	$(obj)/Image System.map "$(INSTALL_PATH)"
+
+zinstall: $(obj)/Image.gz
+	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+	$(obj)/Image.gz System.map "$(INSTALL_PATH)"
+
+clean-files += *.dtb
diff --git a/arch/arm64/boot/install.sh b/arch/arm64/boot/install.sh
new file mode 100644
index 0000000..12ed78a
--- /dev/null
+++ b/arch/arm64/boot/install.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# arch/arm64/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+# Adapted from code in arch/i386/boot/install.sh by Russell King
+#
+# "make install" script for the AArch64 Linux port
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
+if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
+
+if [ "$(basename $2)" = "Image.gz" ]; then
+# Compressed install
+  echo "Installing compressed kernel"
+  base=vmlinuz
+else
+# Normal install
+  echo "Installing normal kernel"
+  base=vmlinux
+fi
+
+if [ -f $4/$base-$1 ]; then
+  mv $4/$base-$1 $4/$base-$1.old
+fi
+cat $2 > $4/$base-$1
+
+# Install system map file
+if [ -f $4/System.map-$1 ]; then
+  mv $4/System.map-$1 $4/System.map-$1.old
+fi
+cp $3 $4/System.map-$1
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
new file mode 100644
index 0000000..9212c78
--- /dev/null
+++ b/arch/arm64/configs/defconfig
@@ -0,0 +1,85 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_SMP=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_CMDLINE="console=ttyAMA0"
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_FTRACE is not set
+CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_DEBUG_ERRORS=y
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
new file mode 100644
index 0000000..35924a5
--- /dev/null
+++ b/arch/arm64/include/asm/Kbuild
@@ -0,0 +1,51 @@
+include include/asm-generic/Kbuild.asm
+
+header-y += hwcap.h
+
+generic-y += bug.h
+generic-y += bugs.h
+generic-y += checksum.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += delay.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += ftrace.h
+generic-y += hw_irq.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += mutex.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += segment.h
+generic-y += sembuf.h
+generic-y += serial.h
+generic-y += shmbuf.h
+generic-y += sizes.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += string.h
+generic-y += switch_to.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += topology.h
+generic-y += types.h
+generic-y += unaligned.h
+generic-y += user.h
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
new file mode 100644
index 0000000..e4cec9d
--- /dev/null
+++ b/arch/arm64/include/asm/arm_generic.h
@@ -0,0 +1,100 @@
+/*
+ * arch/arm64/include/asm/arm_generic.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARM_GENERIC_H
+#define __ASM_ARM_GENERIC_H
+
+#include <linux/clocksource.h>
+
+#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
+#define ARCH_TIMER_CTRL_IMASK		(1 << 1)
+#define ARCH_TIMER_CTRL_ISTATUS		(1 << 2)
+
+#define ARCH_TIMER_REG_CTRL		0
+#define ARCH_TIMER_REG_FREQ		1
+#define ARCH_TIMER_REG_TVAL		2
+
+static inline void arch_timer_reg_write(int reg, u32 val)
+{
+	switch (reg) {
+	case ARCH_TIMER_REG_CTRL:
+		asm volatile("msr cntp_ctl_el0,  %0" : : "r" (val));
+		break;
+	case ARCH_TIMER_REG_TVAL:
+		asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
+		break;
+	default:
+		BUILD_BUG();
+	}
+
+	isb();
+}
+
+static inline u32 arch_timer_reg_read(int reg)
+{
+	u32 val;
+
+	switch (reg) {
+	case ARCH_TIMER_REG_CTRL:
+		asm volatile("mrs %0,  cntp_ctl_el0" : "=r" (val));
+		break;
+	case ARCH_TIMER_REG_FREQ:
+		asm volatile("mrs %0,   cntfrq_el0" : "=r" (val));
+		break;
+	case ARCH_TIMER_REG_TVAL:
+		asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
+		break;
+	default:
+		BUILD_BUG();
+	}
+
+	return val;
+}
+
+static inline void __cpuinit arch_counter_enable_user_access(void)
+{
+	u32 cntkctl;
+
+	/* Disable user access to the timers and the virtual counter. */
+	asm volatile("mrs	%0, cntkctl_el1" : "=r" (cntkctl));
+	cntkctl &= ~((3 << 8) | (1 << 1));
+
+	/* Enable user access to the physical counter and frequency. */
+	cntkctl |= 1;
+	asm volatile("msr	cntkctl_el1, %0" : : "r" (cntkctl));
+}
+
+static inline cycle_t arch_counter_get_cntpct(void)
+{
+	cycle_t cval;
+
+	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
+
+	return cval;
+}
+
+static inline cycle_t arch_counter_get_cntvct(void)
+{
+	cycle_t cval;
+
+	asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
+
+	return cval;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/asm-offsets.h b/arch/arm64/include/asm/asm-offsets.h
new file mode 100644
index 0000000..d370ee3
--- /dev/null
+++ b/arch/arm64/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
new file mode 100644
index 0000000..da2a13e
--- /dev/null
+++ b/arch/arm64/include/asm/assembler.h
@@ -0,0 +1,109 @@
+/*
+ * Based on arch/arm/include/asm/assembler.h
+ *
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
+
+#include <asm/ptrace.h>
+
+/*
+ * Stack pushing/popping (register pairs only). Equivalent to store decrement
+ * before, load increment after.
+ */
+	.macro	push, xreg1, xreg2
+	stp	\xreg1, \xreg2, [sp, #-16]!
+	.endm
+
+	.macro	pop, xreg1, xreg2
+	ldp	\xreg1, \xreg2, [sp], #16
+	.endm
+
+/*
+ * Enable and disable interrupts.
+ */
+	.macro	disable_irq
+	msr	daifset, #2
+	.endm
+
+	.macro	enable_irq
+	msr	daifclr, #2
+	.endm
+
+/*
+ * Save/disable and restore interrupts.
+ */
+	.macro	save_and_disable_irqs, olddaif
+	mrs	\olddaif, daif
+	disable_irq
+	.endm
+
+	.macro	restore_irqs, olddaif
+	msr	daif, \olddaif
+	.endm
+
+/*
+ * Enable and disable debug exceptions.
+ */
+	.macro	disable_dbg
+	msr	daifset, #8
+	.endm
+
+	.macro	enable_dbg
+	msr	daifclr, #8
+	.endm
+
+	.macro	disable_step, tmp
+	mrs	\tmp, mdscr_el1
+	bic	\tmp, \tmp, #1
+	msr	mdscr_el1, \tmp
+	.endm
+
+	.macro	enable_step, tmp
+	mrs	\tmp, mdscr_el1
+	orr	\tmp, \tmp, #1
+	msr	mdscr_el1, \tmp
+	.endm
+
+	.macro	enable_dbg_if_not_stepping, tmp
+	mrs	\tmp, mdscr_el1
+	tbnz	\tmp, #1, 9990f
+	enable_dbg
+9990:
+	.endm
+
+/*
+ * SMP data memory barrier
+ */
+	.macro	smp_dmb, opt
+#ifdef CONFIG_SMP
+	dmb	\opt
+#endif
+	.endm
+
+#define USER(l, x...)				\
+9999:	x;					\
+	.section __ex_table,"a";		\
+	.align	3;				\
+	.quad	9999b,l;			\
+	.previous
+
+/*
+ * Register aliases.
+ */
+lr	.req	x30		// link register
diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h
new file mode 100644
index 0000000..407717b
--- /dev/null
+++ b/arch/arm64/include/asm/atomic.h
@@ -0,0 +1,305 @@
+/*
+ * Based on arch/arm/include/asm/atomic.h
+ *
+ * Copyright (C) 1996 Russell King.
+ * Copyright (C) 2002 Deep Blue Solutions Ltd.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ATOMIC_H
+#define __ASM_ATOMIC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#ifdef __KERNEL__
+
+/*
+ * On ARM, ordinary assignment (str instruction) doesn't clear the local
+ * strex/ldrex monitor on some implementations. The reason we can use it for
+ * atomic_set() is the clrex or dummy strex done on every exception return.
+ */
+#define atomic_read(v)	(*(volatile int *)&(v)->counter)
+#define atomic_set(v,i)	(((v)->counter) = (i))
+
+/*
+ * AArch64 UP and SMP safe atomic ops.  We use load exclusive and
+ * store exclusive to ensure that these are atomic.  We may loop
+ * to ensure that the update happens.
+ */
+static inline void atomic_add(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile("// atomic_add\n"
+"1:	ldxr	%w0, [%3]\n"
+"	add	%w0, %w0, %w4\n"
+"	stxr	%w1, %w0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile("// atomic_add_return\n"
+"1:	ldaxr	%w0, [%3]\n"
+"	add	%w0, %w0, %w4\n"
+"	stlxr	%w1, %w0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	return result;
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile("// atomic_sub\n"
+"1:	ldxr	%w0, [%3]\n"
+"	sub	%w0, %w0, %w4\n"
+"	stxr	%w1, %w0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile("// atomic_sub_return\n"
+"1:	ldaxr	%w0, [%3]\n"
+"	sub	%w0, %w0, %w4\n"
+"	stlxr	%w1, %w0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	return result;
+}
+
+static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
+{
+	unsigned long tmp;
+	int oldval;
+
+	asm volatile("// atomic_cmpxchg\n"
+"1:	ldaxr	%w1, [%3]\n"
+"	cmp	%w1, %w4\n"
+"	b.ne	2f\n"
+"	stlxr	%w0, %w5, [%3]\n"
+"	cbnz	%w0, 1b\n"
+"2:"
+	: "=&r" (tmp), "=&r" (oldval), "+o" (ptr->counter)
+	: "r" (&ptr->counter), "Ir" (old), "r" (new)
+	: "cc");
+
+	return oldval;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+	unsigned long tmp, tmp2;
+
+	asm volatile("// atomic_clear_mask\n"
+"1:	ldxr	%0, [%3]\n"
+"	bic	%0, %0, %4\n"
+"	stxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (tmp), "=&r" (tmp2), "+o" (*addr)
+	: "r" (addr), "Ir" (mask)
+	: "cc");
+}
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline int __atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+
+	c = atomic_read(v);
+	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+		c = old;
+	return c;
+}
+
+#define atomic_inc(v)		atomic_add(1, v)
+#define atomic_dec(v)		atomic_sub(1, v)
+
+#define atomic_inc_and_test(v)	(atomic_add_return(1, v) == 0)
+#define atomic_dec_and_test(v)	(atomic_sub_return(1, v) == 0)
+#define atomic_inc_return(v)    (atomic_add_return(1, v))
+#define atomic_dec_return(v)    (atomic_sub_return(1, v))
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
+
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
+
+/*
+ * 64-bit atomic operations.
+ */
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v)	(*(volatile long long *)&(v)->counter)
+#define atomic64_set(v,i)	(((v)->counter) = (i))
+
+static inline void atomic64_add(u64 i, atomic64_t *v)
+{
+	long result;
+	unsigned long tmp;
+
+	asm volatile("// atomic64_add\n"
+"1:	ldxr	%0, [%3]\n"
+"	add	%0, %0, %4\n"
+"	stxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+}
+
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+	long result;
+	unsigned long tmp;
+
+	asm volatile("// atomic64_add_return\n"
+"1:	ldaxr	%0, [%3]\n"
+"	add	%0, %0, %4\n"
+"	stlxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	return result;
+}
+
+static inline void atomic64_sub(u64 i, atomic64_t *v)
+{
+	long result;
+	unsigned long tmp;
+
+	asm volatile("// atomic64_sub\n"
+"1:	ldxr	%0, [%3]\n"
+"	sub	%0, %0, %4\n"
+"	stxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+}
+
+static inline long atomic64_sub_return(long i, atomic64_t *v)
+{
+	long result;
+	unsigned long tmp;
+
+	asm volatile("// atomic64_sub_return\n"
+"1:	ldaxr	%0, [%3]\n"
+"	sub	%0, %0, %4\n"
+"	stlxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	return result;
+}
+
+static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new)
+{
+	long oldval;
+	unsigned long res;
+
+	asm volatile("// atomic64_cmpxchg\n"
+"1:	ldaxr	%1, [%3]\n"
+"	cmp	%1, %4\n"
+"	b.ne	2f\n"
+"	stlxr	%w0, %5, [%3]\n"
+"	cbnz	%w0, 1b\n"
+"2:"
+	: "=&r" (res), "=&r" (oldval), "+o" (ptr->counter)
+	: "r" (&ptr->counter), "Ir" (old), "r" (new)
+	: "cc");
+
+	return oldval;
+}
+
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline long atomic64_dec_if_positive(atomic64_t *v)
+{
+	long result;
+	unsigned long tmp;
+
+	asm volatile("// atomic64_dec_if_positive\n"
+"1:	ldaxr	%0, [%3]\n"
+"	subs	%0, %0, #1\n"
+"	b.mi	2f\n"
+"	stlxr	%w1, %0, [%3]\n"
+"	cbnz	%w1, 1b\n"
+"2:"
+	: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
+	: "r" (&v->counter)
+	: "cc");
+
+	return result;
+}
+
+static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+
+	c = atomic64_read(v);
+	while (c != u && (old = atomic64_cmpxchg((v), c, c + a)) != c)
+		c = old;
+
+	return c != u;
+}
+
+#define atomic64_add_negative(a, v)	(atomic64_add_return((a), (v)) < 0)
+#define atomic64_inc(v)			atomic64_add(1LL, (v))
+#define atomic64_inc_return(v)		atomic64_add_return(1LL, (v))
+#define atomic64_inc_and_test(v)	(atomic64_inc_return(v) == 0)
+#define atomic64_sub_and_test(a, v)	(atomic64_sub_return((a), (v)) == 0)
+#define atomic64_dec(v)			atomic64_sub(1LL, (v))
+#define atomic64_dec_return(v)		atomic64_sub_return(1LL, (v))
+#define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
+#define atomic64_inc_not_zero(v)	atomic64_add_unless((v), 1LL, 0LL)
+
+#endif
+#endif
diff --git a/arch/arm64/include/asm/auxvec.h b/arch/arm64/include/asm/auxvec.h
new file mode 100644
index 0000000..22d6d88
--- /dev/null
+++ b/arch/arm64/include/asm/auxvec.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* vDSO location */
+#define AT_SYSINFO_EHDR	33
+
+#endif
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
new file mode 100644
index 0000000..d4a6333
--- /dev/null
+++ b/arch/arm64/include/asm/barrier.h
@@ -0,0 +1,52 @@
+/*
+ * Based on arch/arm/include/asm/barrier.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+#ifndef __ASSEMBLY__
+
+#define sev()		asm volatile("sev" : : : "memory")
+#define wfe()		asm volatile("wfe" : : : "memory")
+#define wfi()		asm volatile("wfi" : : : "memory")
+
+#define isb()		asm volatile("isb" : : : "memory")
+#define dsb()		asm volatile("dsb sy" : : : "memory")
+
+#define mb()		dsb()
+#define rmb()		asm volatile("dsb ld" : : : "memory")
+#define wmb()		asm volatile("dsb st" : : : "memory")
+
+#ifndef CONFIG_SMP
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#else
+#define smp_mb()	asm volatile("dmb ish" : : : "memory")
+#define smp_rmb()	asm volatile("dmb ishld" : : : "memory")
+#define smp_wmb()	asm volatile("dmb ishst" : : : "memory")
+#endif
+
+#define read_barrier_depends()		do { } while(0)
+#define smp_read_barrier_depends()	do { } while(0)
+
+#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
+#define nop()		asm volatile("nop");
+
+#endif	/* __ASSEMBLY__ */
+
+#endif	/* __ASM_BARRIER_H */
diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h
new file mode 100644
index 0000000..5e69307
--- /dev/null
+++ b/arch/arm64/include/asm/bitops.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_BITOPS_H
+#define __ASM_BITOPS_H
+
+#include <linux/compiler.h>
+
+#include <asm/barrier.h>
+
+/*
+ * clear_bit may not imply a memory barrier
+ */
+#ifndef smp_mb__before_clear_bit
+#define smp_mb__before_clear_bit()	smp_mb()
+#define smp_mb__after_clear_bit()	smp_mb()
+#endif
+
+#ifndef _LINUX_BITOPS_H
+#error only <linux/bitops.h> can be included directly
+#endif
+
+#include <asm-generic/bitops/builtin-__ffs.h>
+#include <asm-generic/bitops/builtin-ffs.h>
+#include <asm-generic/bitops/builtin-__fls.h>
+#include <asm-generic/bitops/builtin-fls.h>
+
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
+
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/lock.h>
+
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
+#include <asm-generic/bitops/le.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+
+#endif /* __ASM_BITOPS_H */
diff --git a/arch/arm64/include/asm/bitsperlong.h b/arch/arm64/include/asm/bitsperlong.h
new file mode 100644
index 0000000..fce9c29
--- /dev/null
+++ b/arch/arm64/include/asm/bitsperlong.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_BITSPERLONG_H
+#define __ASM_BITSPERLONG_H
+
+#define __BITS_PER_LONG 64
+
+#include <asm-generic/bitsperlong.h>
+
+#endif	/* __ASM_BITSPERLONG_H */
diff --git a/arch/arm64/include/asm/byteorder.h b/arch/arm64/include/asm/byteorder.h
new file mode 100644
index 0000000..2b92046
--- /dev/null
+++ b/arch/arm64/include/asm/byteorder.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_BYTEORDER_H
+#define __ASM_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif	/* __ASM_BYTEORDER_H */
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
new file mode 100644
index 0000000..390308a
--- /dev/null
+++ b/arch/arm64/include/asm/cache.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CACHE_H
+#define __ASM_CACHE_H
+
+#define L1_CACHE_SHIFT		6
+#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+
+/*
+ * Memory returned by kmalloc() may be used for DMA, so we must make
+ * sure that all such allocations are cache aligned. Otherwise,
+ * unrelated code may cause parts of the buffer to be read into the
+ * cache before the transfer is done, causing old data to be seen by
+ * the CPU.
+ */
+#define ARCH_DMA_MINALIGN	L1_CACHE_BYTES
+#define ARCH_SLAB_MINALIGN	8
+
+#endif
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
new file mode 100644
index 0000000..aa3132a
--- /dev/null
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -0,0 +1,148 @@
+/*
+ * Based on arch/arm/include/asm/cacheflush.h
+ *
+ * Copyright (C) 1999-2002 Russell King.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CACHEFLUSH_H
+#define __ASM_CACHEFLUSH_H
+
+#include <linux/mm.h>
+
+/*
+ * This flag is used to indicate that the page pointed to by a pte is clean
+ * and does not require cleaning before returning it to the user.
+ */
+#define PG_dcache_clean PG_arch_1
+
+/*
+ *	MM Cache Management
+ *	===================
+ *
+ *	The arch/arm64/mm/cache.S implements these methods.
+ *
+ *	Start addresses are inclusive and end addresses are exclusive; start
+ *	addresses should be rounded down, end addresses up.
+ *
+ *	See Documentation/cachetlb.txt for more information. Please note that
+ *	the implementation assumes non-aliasing VIPT D-cache and (aliasing)
+ *	VIPT or ASID-tagged VIVT I-cache.
+ *
+ *	flush_cache_all()
+ *
+ *		Unconditionally clean and invalidate the entire cache.
+ *
+ *	flush_cache_mm(mm)
+ *
+ *		Clean and invalidate all user space cache entries
+ *		before a change of page tables.
+ *
+ *	flush_icache_range(start, end)
+ *
+ *		Ensure coherency between the I-cache and the D-cache in the
+ *		region described by start, end.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
+ *	__flush_cache_user_range(start, end)
+ *
+ *		Ensure coherency between the I-cache and the D-cache in the
+ *		region described by start, end.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
+ *	__flush_dcache_area(kaddr, size)
+ *
+ *		Ensure that the data held in page is written back.
+ *		- kaddr  - page address
+ *		- size   - region size
+ */
+extern void flush_cache_all(void);
+extern void flush_cache_mm(struct mm_struct *mm);
+extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
+extern void flush_icache_range(unsigned long start, unsigned long end);
+extern void __flush_dcache_area(void *addr, size_t len);
+extern void __flush_cache_user_range(unsigned long start, unsigned long end);
+
+/*
+ * Copy user data from/to a page which is mapped into a different
+ * processes address space.  Really, we want to allow our "user
+ * space" model to handle this.
+ */
+extern void copy_to_user_page(struct vm_area_struct *, struct page *,
+	unsigned long, void *, const void *, unsigned long);
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+	do {							\
+		memcpy(dst, src, len);				\
+	} while (0)
+
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
+/*
+ * flush_dcache_page is used when the kernel has written to the page
+ * cache page at virtual address page->virtual.
+ *
+ * If this page isn't mapped (ie, page_mapping == NULL), or it might
+ * have userspace mappings, then we _must_ always clean + invalidate
+ * the dcache entries associated with the kernel mapping.
+ *
+ * Otherwise we can defer the operation, and clean the cache when we are
+ * about to change to user space.  This is the same method as used on SPARC64.
+ * See update_mmu_cache for the user space part.
+ */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+extern void flush_dcache_page(struct page *);
+
+static inline void __flush_icache_all(void)
+{
+	asm("ic	ialluis");
+}
+
+#define flush_dcache_mmap_lock(mapping) \
+	spin_lock_irq(&(mapping)->tree_lock)
+#define flush_dcache_mmap_unlock(mapping) \
+	spin_unlock_irq(&(mapping)->tree_lock)
+
+#define flush_icache_user_range(vma,page,addr,len) \
+	flush_dcache_page(page)
+
+/*
+ * We don't appear to need to do anything here.  In fact, if we did, we'd
+ * duplicate cache flushing elsewhere performed by flush_dcache_page().
+ */
+#define flush_icache_page(vma,page)	do { } while (0)
+
+/*
+ * flush_cache_vmap() is used when creating mappings (eg, via vmap,
+ * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
+ * caches, since the direct-mappings of these pages may contain cached
+ * data, we need to do a full cache flush to ensure that writebacks
+ * don't corrupt data placed into these pages via the new mappings.
+ */
+static inline void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+	/*
+	 * set_pte_at() called from vmap_pte_range() does not
+	 * have a DSB after cleaning the cache line.
+	 */
+	dsb();
+}
+
+static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+}
+
+#endif
diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h
new file mode 100644
index 0000000..85f5f51
--- /dev/null
+++ b/arch/arm64/include/asm/cachetype.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CACHETYPE_H
+#define __ASM_CACHETYPE_H
+
+#include <asm/cputype.h>
+
+#define CTR_L1IP_SHIFT		14
+#define CTR_L1IP_MASK		3
+
+#define ICACHE_POLICY_RESERVED	0
+#define ICACHE_POLICY_AIVIVT	1
+#define ICACHE_POLICY_VIPT	2
+#define ICACHE_POLICY_PIPT	3
+
+static inline u32 icache_policy(void)
+{
+	return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK;
+}
+
+/*
+ * Whilst the D-side always behaves as PIPT on AArch64, aliasing is
+ * permitted in the I-cache.
+ */
+static inline int icache_is_aliasing(void)
+{
+	return icache_policy() != ICACHE_POLICY_PIPT;
+}
+
+static inline int icache_is_aivivt(void)
+{
+	return icache_policy() == ICACHE_POLICY_AIVIVT;
+}
+
+#endif	/* __ASM_CACHETYPE_H */
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
new file mode 100644
index 0000000..e0e65b0
--- /dev/null
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -0,0 +1,173 @@
+/*
+ * Based on arch/arm/include/asm/cmpxchg.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <linux/bug.h>
+
+#include <asm/barrier.h>
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+	unsigned long ret, tmp;
+
+	switch (size) {
+	case 1:
+		asm volatile("//	__xchg1\n"
+		"1:	ldaxrb	%w0, [%3]\n"
+		"	stlxrb	%w1, %w2, [%3]\n"
+		"	cbnz	%w1, 1b\n"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 2:
+		asm volatile("//	__xchg2\n"
+		"1:	ldaxrh	%w0, [%3]\n"
+		"	stlxrh	%w1, %w2, [%3]\n"
+		"	cbnz	%w1, 1b\n"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 4:
+		asm volatile("//	__xchg4\n"
+		"1:	ldaxr	%w0, [%3]\n"
+		"	stlxr	%w1, %w2, [%3]\n"
+		"	cbnz	%w1, 1b\n"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 8:
+		asm volatile("//	__xchg8\n"
+		"1:	ldaxr	%0, [%3]\n"
+		"	stlxr	%w1, %2, [%3]\n"
+		"	cbnz	%w1, 1b\n"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	default:
+		BUILD_BUG();
+	}
+
+	return ret;
+}
+
+#define xchg(ptr,x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long oldval = 0, res;
+
+	switch (size) {
+	case 1:
+		do {
+			asm volatile("// __cmpxchg1\n"
+			"	ldxrb	%w1, [%2]\n"
+			"	mov	%w0, #0\n"
+			"	cmp	%w1, %w3\n"
+			"	b.ne	1f\n"
+			"	stxrb	%w0, %w4, [%2]\n"
+			"1:\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "cc");
+		} while (res);
+		break;
+
+	case 2:
+		do {
+			asm volatile("// __cmpxchg2\n"
+			"	ldxrh	%w1, [%2]\n"
+			"	mov	%w0, #0\n"
+			"	cmp	%w1, %w3\n"
+			"	b.ne	1f\n"
+			"	stxrh	%w0, %w4, [%2]\n"
+			"1:\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "memory", "cc");
+		} while (res);
+		break;
+
+	case 4:
+		do {
+			asm volatile("// __cmpxchg4\n"
+			"	ldxr	%w1, [%2]\n"
+			"	mov	%w0, #0\n"
+			"	cmp	%w1, %w3\n"
+			"	b.ne	1f\n"
+			"	stxr	%w0, %w4, [%2]\n"
+			"1:\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "cc");
+		} while (res);
+		break;
+
+	case 8:
+		do {
+			asm volatile("// __cmpxchg8\n"
+			"	ldxr	%1, [%2]\n"
+			"	mov	%w0, #0\n"
+			"	cmp	%1, %3\n"
+			"	b.ne	1f\n"
+			"	stxr	%w0, %4, [%2]\n"
+			"1:\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "cc");
+		} while (res);
+		break;
+
+	default:
+		BUILD_BUG();
+	}
+
+	return oldval;
+}
+
+static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
+					 unsigned long new, int size)
+{
+	unsigned long ret;
+
+	smp_mb();
+	ret = __cmpxchg(ptr, old, new, size);
+	smp_mb();
+
+	return ret;
+}
+
+#define cmpxchg(ptr,o,n)						\
+	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
+					  (unsigned long)(o),		\
+					  (unsigned long)(n),		\
+					  sizeof(*(ptr))))
+
+#define cmpxchg_local(ptr,o,n)						\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),				\
+				       (unsigned long)(o),		\
+				       (unsigned long)(n),		\
+				       sizeof(*(ptr))))
+
+#endif	/* __ASM_CMPXCHG_H */
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
new file mode 100644
index 0000000..a670a33
--- /dev/null
+++ b/arch/arm64/include/asm/compat.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_COMPAT_H
+#define __ASM_COMPAT_H
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+
+/*
+ * Architecture specific compatibility types
+ */
+#include <linux/types.h>
+#include <linux/sched.h>
+
+#define COMPAT_USER_HZ		100
+#define COMPAT_UTS_MACHINE	"armv8l\0\0"
+
+typedef u32		compat_size_t;
+typedef s32		compat_ssize_t;
+typedef s32		compat_time_t;
+typedef s32		compat_clock_t;
+typedef s32		compat_pid_t;
+typedef u32		__compat_uid_t;
+typedef u32		__compat_gid_t;
+typedef u32		__compat_uid32_t;
+typedef u32		__compat_gid32_t;
+typedef u32		compat_mode_t;
+typedef u32		compat_ino_t;
+typedef u32		compat_dev_t;
+typedef s32		compat_off_t;
+typedef s64		compat_loff_t;
+typedef s16		compat_nlink_t;
+typedef u16		compat_ipc_pid_t;
+typedef s32		compat_daddr_t;
+typedef u32		compat_caddr_t;
+typedef __kernel_fsid_t	compat_fsid_t;
+typedef s32		compat_key_t;
+typedef s32		compat_timer_t;
+
+typedef s32		compat_int_t;
+typedef s32		compat_long_t;
+typedef s64		compat_s64;
+typedef u32		compat_uint_t;
+typedef u32		compat_ulong_t;
+typedef u64		compat_u64;
+
+struct compat_timespec {
+	compat_time_t	tv_sec;
+	s32		tv_nsec;
+};
+
+struct compat_timeval {
+	compat_time_t	tv_sec;
+	s32		tv_usec;
+};
+
+struct compat_stat {
+	compat_dev_t	st_dev;
+	compat_ino_t	st_ino;
+	compat_mode_t	st_mode;
+	compat_nlink_t	st_nlink;
+	__compat_uid32_t	st_uid;
+	__compat_gid32_t	st_gid;
+	compat_dev_t	st_rdev;
+	compat_off_t	st_size;
+	compat_off_t	st_blksize;
+	compat_off_t	st_blocks;
+	compat_time_t	st_atime;
+	u32		st_atime_nsec;
+	compat_time_t	st_mtime;
+	u32		st_mtime_nsec;
+	compat_time_t	st_ctime;
+	u32		st_ctime_nsec;
+	u32		__unused4[2];
+};
+
+struct compat_flock {
+	short		l_type;
+	short		l_whence;
+	compat_off_t	l_start;
+	compat_off_t	l_len;
+	compat_pid_t	l_pid;
+};
+
+#define F_GETLK64	12	/*  using 'struct flock64' */
+#define F_SETLK64	13
+#define F_SETLKW64	14
+
+struct compat_flock64 {
+	short		l_type;
+	short		l_whence;
+	compat_loff_t	l_start;
+	compat_loff_t	l_len;
+	compat_pid_t	l_pid;
+};
+
+struct compat_statfs {
+	int		f_type;
+	int		f_bsize;
+	int		f_blocks;
+	int		f_bfree;
+	int		f_bavail;
+	int		f_files;
+	int		f_ffree;
+	compat_fsid_t	f_fsid;
+	int		f_namelen;	/* SunOS ignores this field. */
+	int		f_frsize;
+	int		f_flags;
+	int		f_spare[4];
+};
+
+#define COMPAT_RLIM_INFINITY		0xffffffff
+
+typedef u32		compat_old_sigset_t;
+
+#define _COMPAT_NSIG		64
+#define _COMPAT_NSIG_BPW	32
+
+typedef u32		compat_sigset_word;
+
+#define COMPAT_OFF_T_MAX	0x7fffffff
+#define COMPAT_LOFF_T_MAX	0x7fffffffffffffffL
+
+/*
+ * A pointer passed in from user mode. This should not
+ * be used for syscall parameters, just declare them
+ * as pointers because the syscall entry code will have
+ * appropriately converted them already.
+ */
+typedef	u32		compat_uptr_t;
+
+static inline void __user *compat_ptr(compat_uptr_t uptr)
+{
+	return (void __user *)(unsigned long)uptr;
+}
+
+static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+{
+	return (u32)(unsigned long)uptr;
+}
+
+static inline void __user *arch_compat_alloc_user_space(long len)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+	return (void __user *)regs->compat_sp - len;
+}
+
+struct compat_ipc64_perm {
+	compat_key_t key;
+	__compat_uid32_t uid;
+	__compat_gid32_t gid;
+	__compat_uid32_t cuid;
+	__compat_gid32_t cgid;
+	unsigned short mode;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	compat_ulong_t unused1;
+	compat_ulong_t unused2;
+};
+
+struct compat_semid64_ds {
+	struct compat_ipc64_perm sem_perm;
+	compat_time_t  sem_otime;
+	compat_ulong_t __unused1;
+	compat_time_t  sem_ctime;
+	compat_ulong_t __unused2;
+	compat_ulong_t sem_nsems;
+	compat_ulong_t __unused3;
+	compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+	struct compat_ipc64_perm msg_perm;
+	compat_time_t  msg_stime;
+	compat_ulong_t __unused1;
+	compat_time_t  msg_rtime;
+	compat_ulong_t __unused2;
+	compat_time_t  msg_ctime;
+	compat_ulong_t __unused3;
+	compat_ulong_t msg_cbytes;
+	compat_ulong_t msg_qnum;
+	compat_ulong_t msg_qbytes;
+	compat_pid_t   msg_lspid;
+	compat_pid_t   msg_lrpid;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+	struct compat_ipc64_perm shm_perm;
+	compat_size_t  shm_segsz;
+	compat_time_t  shm_atime;
+	compat_ulong_t __unused1;
+	compat_time_t  shm_dtime;
+	compat_ulong_t __unused2;
+	compat_time_t  shm_ctime;
+	compat_ulong_t __unused3;
+	compat_pid_t   shm_cpid;
+	compat_pid_t   shm_lpid;
+	compat_ulong_t shm_nattch;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
+static inline int is_compat_task(void)
+{
+	return test_thread_flag(TIF_32BIT);
+}
+
+static inline int is_compat_thread(struct thread_info *thread)
+{
+	return test_ti_thread_flag(thread, TIF_32BIT);
+}
+
+#else /* !CONFIG_COMPAT */
+
+static inline int is_compat_task(void)
+{
+	return 0;
+}
+
+static inline int is_compat_thread(struct thread_info *thread)
+{
+	return 0;
+}
+
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+#endif /* __ASM_COMPAT_H */
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h
new file mode 100644
index 0000000..ee35fd0
--- /dev/null
+++ b/arch/arm64/include/asm/compiler.h
@@ -0,0 +1,30 @@
+/*
+ * Based on arch/arm/include/asm/compiler.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_COMPILER_H
+#define __ASM_COMPILER_H
+
+/*
+ * This is used to ensure the compiler did actually allocate the register we
+ * asked it for some inline assembly sequences.  Apparently we can't trust the
+ * compiler from one version to another so a bit of paranoia won't hurt.  This
+ * string is meant to be concatenated with the inline asm string and will
+ * cause compilation to stop on mismatch.  (for details, see gcc PR 15089)
+ */
+#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
+
+#endif	/* __ASM_COMPILER_H */
diff --git a/arch/arm64/include/asm/cputable.h b/arch/arm64/include/asm/cputable.h
new file mode 100644
index 0000000..e3bd983
--- /dev/null
+++ b/arch/arm64/include/asm/cputable.h
@@ -0,0 +1,30 @@
+/*
+ * arch/arm64/include/asm/cputable.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CPUTABLE_H
+#define __ASM_CPUTABLE_H
+
+struct cpu_info {
+	unsigned int	cpu_id_val;
+	unsigned int	cpu_id_mask;
+	const char	*cpu_name;
+	unsigned long	(*cpu_setup)(void);
+};
+
+extern struct cpu_info *lookup_processor_type(unsigned int);
+
+#endif
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
new file mode 100644
index 0000000..ef54125
--- /dev/null
+++ b/arch/arm64/include/asm/cputype.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CPUTYPE_H
+#define __ASM_CPUTYPE_H
+
+#define ID_MIDR_EL1		"midr_el1"
+#define ID_CTR_EL0		"ctr_el0"
+
+#define ID_AA64PFR0_EL1		"id_aa64pfr0_el1"
+#define ID_AA64DFR0_EL1		"id_aa64dfr0_el1"
+#define ID_AA64AFR0_EL1		"id_aa64afr0_el1"
+#define ID_AA64ISAR0_EL1	"id_aa64isar0_el1"
+#define ID_AA64MMFR0_EL1	"id_aa64mmfr0_el1"
+
+#define read_cpuid(reg) ({						\
+	u64 __val;							\
+	asm("mrs	%0, " reg : "=r" (__val));			\
+	__val;								\
+})
+
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant.  Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline u32 __attribute_const__ read_cpuid_id(void)
+{
+	return read_cpuid(ID_MIDR_EL1);
+}
+
+static inline u32 __attribute_const__ read_cpuid_cachetype(void)
+{
+	return read_cpuid(ID_CTR_EL0);
+}
+
+#endif
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
new file mode 100644
index 0000000..7eaa0b3
--- /dev/null
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_DEBUG_MONITORS_H
+#define __ASM_DEBUG_MONITORS_H
+
+#ifdef __KERNEL__
+
+#define	DBG_ESR_EVT(x)		(((x) >> 27) & 0x7)
+
+/* AArch64 */
+#define DBG_ESR_EVT_HWBP	0x0
+#define DBG_ESR_EVT_HWSS	0x1
+#define DBG_ESR_EVT_HWWP	0x2
+#define DBG_ESR_EVT_BRK		0x6
+
+enum debug_el {
+	DBG_ACTIVE_EL0 = 0,
+	DBG_ACTIVE_EL1,
+};
+
+/* AArch32 */
+#define DBG_ESR_EVT_BKPT	0x4
+#define DBG_ESR_EVT_VECC	0x5
+
+#define AARCH32_BREAK_ARM	0x07f001f0
+#define AARCH32_BREAK_THUMB	0xde01
+#define AARCH32_BREAK_THUMB2_LO	0xf7f0
+#define AARCH32_BREAK_THUMB2_HI	0xa000
+
+#ifndef __ASSEMBLY__
+struct task_struct;
+
+#define local_dbg_save(flags)							\
+	do {									\
+		typecheck(unsigned long, flags);				\
+		asm volatile(							\
+		"mrs	%0, daif			// local_dbg_save\n"	\
+		"msr	daifset, #8"						\
+		: "=r" (flags) : : "memory");					\
+	} while (0)
+
+#define local_dbg_restore(flags)						\
+	do {									\
+		typecheck(unsigned long, flags);				\
+		asm volatile(							\
+		"msr	daif, %0			// local_dbg_restore\n"	\
+		: : "r" (flags) : "memory");					\
+	} while (0)
+
+#define DBG_ARCH_ID_RESERVED	0	/* In case of ptrace ABI updates. */
+
+u8 debug_monitors_arch(void);
+
+void enable_debug_monitors(enum debug_el el);
+void disable_debug_monitors(enum debug_el el);
+
+void user_rewind_single_step(struct task_struct *task);
+void user_fastforward_single_step(struct task_struct *task);
+
+void kernel_enable_single_step(struct pt_regs *regs);
+void kernel_disable_single_step(void);
+int kernel_active_single_step(void);
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+int reinstall_suspended_bps(struct pt_regs *regs);
+#else
+static inline int reinstall_suspended_bps(struct pt_regs *regs)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif	/* __ASSEMBLY */
+#endif	/* __KERNEL__ */
+#endif	/* __ASM_DEBUG_MONITORS_H */
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h
new file mode 100644
index 0000000..0d8453c
--- /dev/null
+++ b/arch/arm64/include/asm/device.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_DEVICE_H
+#define __ASM_DEVICE_H
+
+struct dev_archdata {
+	struct dma_map_ops *dma_ops;
+};
+
+struct pdev_archdata {
+};
+
+#endif
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
new file mode 100644
index 0000000..538f4b4
--- /dev/null
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_DMA_MAPPING_H
+#define __ASM_DMA_MAPPING_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include <asm-generic/dma-coherent.h>
+
+#define ARCH_HAS_DMA_GET_REQUIRED_MASK
+
+extern struct dma_map_ops *dma_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+	if (unlikely(!dev) || !dev->archdata.dma_ops)
+		return dma_ops;
+	else
+		return dev->archdata.dma_ops;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return (dma_addr_t)paddr;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+{
+	return (phys_addr_t)dev_addr;
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	return ops->mapping_error(dev, dev_addr);
+}
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	return ops->dma_supported(dev, mask);
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+	*dev->dma_mask = mask;
+
+	return 0;
+}
+
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size - 1 <= *dev->dma_mask;
+}
+
+static inline void dma_mark_clean(void *addr, size_t size)
+{
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flags)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	void *vaddr;
+
+	if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr))
+		return vaddr;
+
+	vaddr = ops->alloc(dev, size, dma_handle, flags, NULL);
+	debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr);
+	return vaddr;
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t dev_addr)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+
+	if (dma_release_from_coherent(dev, get_order(size), vaddr))
+		return;
+
+	debug_dma_free_coherent(dev, size, vaddr, dev_addr);
+	ops->free(dev, size, vaddr, dev_addr, NULL);
+}
+
+/*
+ * There is no dma_cache_sync() implementation, so just return NULL here.
+ */
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+					  dma_addr_t *handle, gfp_t flags)
+{
+	return NULL;
+}
+
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+					void *cpu_addr, dma_addr_t handle)
+{
+}
+
+#endif	/* __KERNEL__ */
+#endif	/* __ASM_DMA_MAPPING_H */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
new file mode 100644
index 0000000..cf28464
--- /dev/null
+++ b/arch/arm64/include/asm/elf.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ELF_H
+#define __ASM_ELF_H
+
+#include <asm/hwcap.h>
+
+/*
+ * ELF register definitions..
+ */
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+typedef unsigned long elf_greg_t;
+typedef unsigned long elf_freg_t[3];
+
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_fp elf_fpregset_t;
+
+#define EM_AARCH64		183
+
+/*
+ * AArch64 static relocation types.
+ */
+
+/* Miscellaneous. */
+#define R_ARM_NONE			0
+#define R_AARCH64_NONE			256
+
+/* Data. */
+#define R_AARCH64_ABS64			257
+#define R_AARCH64_ABS32			258
+#define R_AARCH64_ABS16			259
+#define R_AARCH64_PREL64		260
+#define R_AARCH64_PREL32		261
+#define R_AARCH64_PREL16		262
+
+/* Instructions. */
+#define R_AARCH64_MOVW_UABS_G0		263
+#define R_AARCH64_MOVW_UABS_G0_NC	264
+#define R_AARCH64_MOVW_UABS_G1		265
+#define R_AARCH64_MOVW_UABS_G1_NC	266
+#define R_AARCH64_MOVW_UABS_G2		267
+#define R_AARCH64_MOVW_UABS_G2_NC	268
+#define R_AARCH64_MOVW_UABS_G3		269
+
+#define R_AARCH64_MOVW_SABS_G0		270
+#define R_AARCH64_MOVW_SABS_G1		271
+#define R_AARCH64_MOVW_SABS_G2		272
+
+#define R_AARCH64_LD_PREL_LO19		273
+#define R_AARCH64_ADR_PREL_LO21		274
+#define R_AARCH64_ADR_PREL_PG_HI21	275
+#define R_AARCH64_ADR_PREL_PG_HI21_NC	276
+#define R_AARCH64_ADD_ABS_LO12_NC	277
+#define R_AARCH64_LDST8_ABS_LO12_NC	278
+
+#define R_AARCH64_TSTBR14		279
+#define R_AARCH64_CONDBR19		280
+#define R_AARCH64_JUMP26		282
+#define R_AARCH64_CALL26		283
+#define R_AARCH64_LDST16_ABS_LO12_NC	284
+#define R_AARCH64_LDST32_ABS_LO12_NC	285
+#define R_AARCH64_LDST64_ABS_LO12_NC	286
+#define R_AARCH64_LDST128_ABS_LO12_NC	299
+
+#define R_AARCH64_MOVW_PREL_G0		287
+#define R_AARCH64_MOVW_PREL_G0_NC	288
+#define R_AARCH64_MOVW_PREL_G1		289
+#define R_AARCH64_MOVW_PREL_G1_NC	290
+#define R_AARCH64_MOVW_PREL_G2		291
+#define R_AARCH64_MOVW_PREL_G2_NC	292
+#define R_AARCH64_MOVW_PREL_G3		293
+
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS64
+#define ELF_DATA	ELFDATA2LSB
+#define ELF_ARCH	EM_AARCH64
+
+#define ELF_PLATFORM_SIZE	16
+#define ELF_PLATFORM		("aarch64")
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x)		((x)->e_machine == EM_AARCH64)
+
+#define elf_read_implies_exec(ex,stk)	(stk != EXSTACK_DISABLE_X)
+
+#define CORE_DUMP_USE_REGSET
+#define ELF_EXEC_PAGESIZE	PAGE_SIZE
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader.  We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE	(randomize_et_dyn(2 * TASK_SIZE_64 / 3))
+
+/*
+ * When the program starts, a1 contains a pointer to a function to be
+ * registered with atexit, as per the SVR4 ABI.  A value of 0 means we have no
+ * such handler.
+ */
+#define ELF_PLAT_INIT(_r, load_addr)	(_r)->regs[0] = 0
+
+#define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
+
+#define ARCH_DLINFO							\
+do {									\
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
+		    (elf_addr_t)current->mm->context.vdso);		\
+} while (0)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+				       int uses_interp);
+
+/* 1GB of VA */
+#ifdef CONFIG_COMPAT
+#define STACK_RND_MASK			(test_thread_flag(TIF_32BIT) ? \
+						0x7ff >> (PAGE_SHIFT - 12) : \
+						0x3ffff >> (PAGE_SHIFT - 12))
+#else
+#define STACK_RND_MASK			(0x3ffff >> (PAGE_SHIFT - 12))
+#endif
+
+struct mm_struct;
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
+#ifdef CONFIG_COMPAT
+#define EM_ARM				40
+#define COMPAT_ELF_PLATFORM		("v8l")
+
+#define COMPAT_ELF_ET_DYN_BASE		(randomize_et_dyn(2 * TASK_SIZE_32 / 3))
+
+/* AArch32 registers. */
+#define COMPAT_ELF_NGREG		18
+typedef unsigned int			compat_elf_greg_t;
+typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
+
+/* AArch32 EABI. */
+#define EF_ARM_EABI_MASK		0xff000000
+#define compat_elf_check_arch(x)	(((x)->e_machine == EM_ARM) && \
+					 ((x)->e_flags & EF_ARM_EABI_MASK))
+
+#define compat_start_thread		compat_start_thread
+#define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
+#define COMPAT_ARCH_DLINFO
+extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
+				      int uses_interp);
+#define compat_arch_setup_additional_pages \
+					aarch32_setup_vectors_page
+
+#endif /* CONFIG_COMPAT */
+
+#endif
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h
new file mode 100644
index 0000000..ac63519
--- /dev/null
+++ b/arch/arm64/include/asm/exception.h
@@ -0,0 +1,23 @@
+/*
+ * Based on arch/arm/include/asm/exception.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_EXCEPTION_H
+#define __ASM_EXCEPTION_H
+
+#define __exception	__attribute__((section(".exception.text")))
+
+#endif	/* __ASM_EXCEPTION_H */
diff --git a/arch/arm64/include/asm/exec.h b/arch/arm64/include/asm/exec.h
new file mode 100644
index 0000000..db0563c
--- /dev/null
+++ b/arch/arm64/include/asm/exec.h
@@ -0,0 +1,23 @@
+/*
+ * Based on arch/arm/include/asm/exec.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_EXEC_H
+#define __ASM_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif	/* __ASM_EXEC_H */
diff --git a/arch/arm64/include/asm/fb.h b/arch/arm64/include/asm/fb.h
new file mode 100644
index 0000000..adb88a6
--- /dev/null
+++ b/arch/arm64/include/asm/fb.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_FB_H_
+#define __ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+				unsigned long off)
+{
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+	return 0;
+}
+
+#endif /* __ASM_FB_H_ */
diff --git a/arch/arm64/include/asm/fcntl.h b/arch/arm64/include/asm/fcntl.h
new file mode 100644
index 0000000..cd2e630
--- /dev/null
+++ b/arch/arm64/include/asm/fcntl.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_FCNTL_H
+#define __ASM_FCNTL_H
+
+/*
+ * Using our own definitions for AArch32 (compat) support.
+ */
+#define O_DIRECTORY	 040000	/* must be a directory */
+#define O_NOFOLLOW	0100000	/* don't follow links */
+#define O_DIRECT	0200000	/* direct disk access hint - currently ignored */
+#define O_LARGEFILE	0400000
+
+#include <asm-generic/fcntl.h>
+
+#endif
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
new file mode 100644
index 0000000..b42fab9
--- /dev/null
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_FP_H
+#define __ASM_FP_H
+
+#include <asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+
+/*
+ * FP/SIMD storage area has:
+ *  - FPSR and FPCR
+ *  - 32 128-bit data registers
+ *
+ * Note that user_fp forms a prefix of this structure, which is relied
+ * upon in the ptrace FP/SIMD accessors. struct user_fpsimd_state must
+ * form a prefix of struct fpsimd_state.
+ */
+struct fpsimd_state {
+	union {
+		struct user_fpsimd_state user_fpsimd;
+		struct {
+			__uint128_t vregs[32];
+			u32 fpsr;
+			u32 fpcr;
+		};
+	};
+};
+
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+/* Masks for extracting the FPSR and FPCR from the FPSCR */
+#define VFP_FPSCR_STAT_MASK	0xf800009f
+#define VFP_FPSCR_CTRL_MASK	0x07f79f00
+/*
+ * The VFP state has 32x64-bit registers and a single 32-bit
+ * control/status register.
+ */
+#define VFP_STATE_SIZE		((32 * 8) + 4)
+#endif
+
+struct task_struct;
+
+extern void fpsimd_save_state(struct fpsimd_state *state);
+extern void fpsimd_load_state(struct fpsimd_state *state);
+
+extern void fpsimd_thread_switch(struct task_struct *next);
+extern void fpsimd_flush_thread(void);
+
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
new file mode 100644
index 0000000..3468ae84
--- /dev/null
+++ b/arch/arm64/include/asm/futex.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_FUTEX_H
+#define __ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg)		\
+	asm volatile(							\
+"1:	ldaxr	%w1, %2\n"						\
+	insn "\n"							\
+"2:	stlxr	%w3, %w0, %2\n"						\
+"	cbnz	%w3, 1b\n"						\
+"3:\n"									\
+"	.pushsection .fixup,\"ax\"\n"					\
+"4:	mov	%w0, %w5\n"						\
+"	b	3b\n"							\
+"	.popsection\n"							\
+"	.pushsection __ex_table,\"a\"\n"				\
+"	.align	3\n"							\
+"	.quad	1b, 4b, 2b, 4b\n"					\
+"	.popsection\n"							\
+	: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp)	\
+	: "r" (oparg), "Ir" (-EFAULT)					\
+	: "cc")
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+{
+	int op = (encoded_op >> 28) & 7;
+	int cmp = (encoded_op >> 24) & 15;
+	int oparg = (encoded_op << 8) >> 20;
+	int cmparg = (encoded_op << 20) >> 20;
+	int oldval = 0, ret, tmp;
+
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+		oparg = 1 << oparg;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	pagefault_disable();	/* implies preempt_disable() */
+
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("mov	%w0, %w4",
+				  ret, oldval, uaddr, tmp, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("add	%w0, %w1, %w4",
+				  ret, oldval, uaddr, tmp, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("orr	%w0, %w1, %w4",
+				  ret, oldval, uaddr, tmp, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("and	%w0, %w1, %w4",
+				  ret, oldval, uaddr, tmp, ~oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("eor	%w0, %w1, %w4",
+				  ret, oldval, uaddr, tmp, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	pagefault_enable();	/* subsumes preempt_enable() */
+
+	if (!ret) {
+		switch (cmp) {
+		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+		default: ret = -ENOSYS;
+		}
+	}
+	return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+			      u32 oldval, u32 newval)
+{
+	int ret = 0;
+	u32 val, tmp;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	asm volatile("// futex_atomic_cmpxchg_inatomic\n"
+"1:	ldaxr	%w1, %2\n"
+"	sub	%w3, %w1, %w4\n"
+"	cbnz	%w3, 3f\n"
+"2:	stlxr	%w3, %w5, %2\n"
+"	cbnz	%w3, 1b\n"
+"3:\n"
+"	.pushsection .fixup,\"ax\"\n"
+"4:	mov	%w0, %w6\n"
+"	b	3b\n"
+"	.popsection\n"
+"	.pushsection __ex_table,\"a\"\n"
+"	.align	3\n"
+"	.quad	1b, 4b, 2b, 4b\n"
+"	.popsection\n"
+	: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
+	: "r" (oldval), "r" (newval), "Ir" (-EFAULT)
+	: "cc", "memory");
+
+	*uval = val;
+	return ret;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_FUTEX_H */
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
new file mode 100644
index 0000000..5075463
--- /dev/null
+++ b/arch/arm64/include/asm/hardirq.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+
+#define NR_IPI	4
+
+typedef struct {
+	unsigned int __softirq_pending;
+#ifdef CONFIG_SMP
+	unsigned int ipi_irqs[NR_IPI];
+#endif
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+
+#define __inc_irq_stat(cpu, member)	__IRQ_STAT(cpu, member)++
+#define __get_irq_stat(cpu, member)	__IRQ_STAT(cpu, member)
+
+#ifdef CONFIG_SMP
+u64 smp_irq_stat_cpu(unsigned int cpu);
+#define arch_irq_stat_cpu	smp_irq_stat_cpu
+#endif
+
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
+
+static inline void ack_bad_irq(unsigned int irq)
+{
+	extern unsigned long irq_err_count;
+	irq_err_count++;
+}
+
+extern void handle_IRQ(unsigned int, struct pt_regs *);
+
+#endif /* __ASM_HARDIRQ_H */
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
new file mode 100644
index 0000000..d064047
--- /dev/null
+++ b/arch/arm64/include/asm/hw_breakpoint.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_HW_BREAKPOINT_H
+#define __ASM_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+
+struct arch_hw_breakpoint_ctrl {
+	u32 __reserved	: 19,
+	len		: 8,
+	type		: 2,
+	privilege	: 2,
+	enabled		: 1;
+};
+
+struct arch_hw_breakpoint {
+	u64 address;
+	u64 trigger;
+	struct arch_hw_breakpoint_ctrl ctrl;
+};
+
+static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
+{
+	return (ctrl.len << 5) | (ctrl.type << 3) | (ctrl.privilege << 1) |
+		ctrl.enabled;
+}
+
+static inline void decode_ctrl_reg(u32 reg,
+				   struct arch_hw_breakpoint_ctrl *ctrl)
+{
+	ctrl->enabled	= reg & 0x1;
+	reg >>= 1;
+	ctrl->privilege	= reg & 0x3;
+	reg >>= 2;
+	ctrl->type	= reg & 0x3;
+	reg >>= 2;
+	ctrl->len	= reg & 0xff;
+}
+
+/* Breakpoint */
+#define ARM_BREAKPOINT_EXECUTE	0
+
+/* Watchpoints */
+#define ARM_BREAKPOINT_LOAD	1
+#define ARM_BREAKPOINT_STORE	2
+#define AARCH64_ESR_ACCESS_MASK	(1 << 6)
+
+/* Privilege Levels */
+#define AARCH64_BREAKPOINT_EL1	1
+#define AARCH64_BREAKPOINT_EL0	2
+
+/* Lengths */
+#define ARM_BREAKPOINT_LEN_1	0x1
+#define ARM_BREAKPOINT_LEN_2	0x3
+#define ARM_BREAKPOINT_LEN_4	0xf
+#define ARM_BREAKPOINT_LEN_8	0xff
+
+/* Kernel stepping */
+#define ARM_KERNEL_STEP_NONE	0
+#define ARM_KERNEL_STEP_ACTIVE	1
+#define ARM_KERNEL_STEP_SUSPEND	2
+
+/*
+ * Limits.
+ * Changing these will require modifications to the register accessors.
+ */
+#define ARM_MAX_BRP		16
+#define ARM_MAX_WRP		16
+#define ARM_MAX_HBP_SLOTS	(ARM_MAX_BRP + ARM_MAX_WRP)
+
+/* Virtual debug register bases. */
+#define AARCH64_DBG_REG_BVR	0
+#define AARCH64_DBG_REG_BCR	(AARCH64_DBG_REG_BVR + ARM_MAX_BRP)
+#define AARCH64_DBG_REG_WVR	(AARCH64_DBG_REG_BCR + ARM_MAX_BRP)
+#define AARCH64_DBG_REG_WCR	(AARCH64_DBG_REG_WVR + ARM_MAX_WRP)
+
+/* Debug register names. */
+#define AARCH64_DBG_REG_NAME_BVR	"bvr"
+#define AARCH64_DBG_REG_NAME_BCR	"bcr"
+#define AARCH64_DBG_REG_NAME_WVR	"wvr"
+#define AARCH64_DBG_REG_NAME_WCR	"wcr"
+
+/* Accessor macros for the debug registers. */
+#define AARCH64_DBG_READ(N, REG, VAL) do {\
+	asm volatile("mrs %0, dbg" REG #N "_el1" : "=r" (VAL));\
+} while (0)
+
+#define AARCH64_DBG_WRITE(N, REG, VAL) do {\
+	asm volatile("msr dbg" REG #N "_el1, %0" :: "r" (VAL));\
+} while (0)
+
+struct task_struct;
+struct notifier_block;
+struct perf_event;
+struct pmu;
+
+extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+				  int *gen_len, int *gen_type);
+extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+					   unsigned long val, void *data);
+
+extern int arch_install_hw_breakpoint(struct perf_event *bp);
+extern void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+extern void hw_breakpoint_pmu_read(struct perf_event *bp);
+extern int hw_breakpoint_slots(int type);
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+extern void hw_breakpoint_thread_switch(struct task_struct *next);
+extern void ptrace_hw_copy_thread(struct task_struct *task);
+#else
+static inline void hw_breakpoint_thread_switch(struct task_struct *next)
+{
+}
+static inline void ptrace_hw_copy_thread(struct task_struct *task)
+{
+}
+#endif
+
+extern struct pmu perf_ops_bp;
+
+#endif	/* __KERNEL__ */
+#endif	/* __ASM_BREAKPOINT_H */
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
new file mode 100644
index 0000000..f8190ba
--- /dev/null
+++ b/arch/arm64/include/asm/hwcap.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_HWCAP_H
+#define __ASM_HWCAP_H
+
+/*
+ * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
+ */
+#define HWCAP_FP		(1 << 0)
+#define HWCAP_ASIMD		(1 << 1)
+
+#define COMPAT_HWCAP_HALF	(1 << 1)
+#define COMPAT_HWCAP_THUMB	(1 << 2)
+#define COMPAT_HWCAP_FAST_MULT	(1 << 4)
+#define COMPAT_HWCAP_VFP	(1 << 6)
+#define COMPAT_HWCAP_EDSP	(1 << 7)
+#define COMPAT_HWCAP_NEON	(1 << 12)
+#define COMPAT_HWCAP_VFPv3	(1 << 13)
+#define COMPAT_HWCAP_TLS	(1 << 15)
+#define COMPAT_HWCAP_VFPv4	(1 << 16)
+#define COMPAT_HWCAP_IDIVA	(1 << 17)
+#define COMPAT_HWCAP_IDIVT	(1 << 18)
+#define COMPAT_HWCAP_IDIV	(COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this cpu supports.
+ */
+#define ELF_HWCAP		(elf_hwcap)
+#define COMPAT_ELF_HWCAP	(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
+				 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
+				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
+				 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
+				 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
+
+extern unsigned int elf_hwcap;
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
new file mode 100644
index 0000000..74a2a7d3
--- /dev/null
+++ b/arch/arm64/include/asm/io.h
@@ -0,0 +1,258 @@
+/*
+ * Based on arch/arm/include/asm/io.h
+ *
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_IO_H
+#define __ASM_IO_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+#include <asm/barrier.h>
+#include <asm/pgtable.h>
+
+/*
+ * Generic IO read/write.  These perform native-endian accesses.
+ */
+static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+{
+	asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+{
+	asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+{
+	asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
+{
+	asm volatile("str %0, [%1]" : : "r" (val), "r" (addr));
+}
+
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+	u8 val;
+	asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+	u16 val;
+	asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+	u32 val;
+	asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+static inline u64 __raw_readq(const volatile void __iomem *addr)
+{
+	u64 val;
+	asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+/* IO barriers */
+#define __iormb()		rmb()
+#define __iowmb()		wmb()
+
+#define mmiowb()		do { } while (0)
+
+/*
+ * Relaxed I/O memory access primitives. These follow the Device memory
+ * ordering rules but do not guarantee any ordering relative to Normal memory
+ * accesses.
+ */
+#define readb_relaxed(c)	({ u8  __v = __raw_readb(c); __v; })
+#define readw_relaxed(c)	({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; })
+#define readl_relaxed(c)	({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; })
+
+#define writeb_relaxed(v,c)	((void)__raw_writeb((v),(c)))
+#define writew_relaxed(v,c)	((void)__raw_writew((__force u16)cpu_to_le16(v),(c)))
+#define writel_relaxed(v,c)	((void)__raw_writel((__force u32)cpu_to_le32(v),(c)))
+
+/*
+ * I/O memory access primitives. Reads are ordered relative to any
+ * following Normal memory access. Writes are ordered relative to any prior
+ * Normal memory access.
+ */
+#define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
+#define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
+#define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+
+#define writeb(v,c)		({ __iowmb(); writeb_relaxed((v),(c)); })
+#define writew(v,c)		({ __iowmb(); writew_relaxed((v),(c)); })
+#define writel(v,c)		({ __iowmb(); writel_relaxed((v),(c)); })
+
+/*
+ *  I/O port access primitives.
+ */
+#define IO_SPACE_LIMIT		0xffff
+#define PCI_IOBASE		((void __iomem *)0xffffffbbfffe0000UL)
+
+static inline u8 inb(unsigned long addr)
+{
+	return readb(addr + PCI_IOBASE);
+}
+
+static inline u16 inw(unsigned long addr)
+{
+	return readw(addr + PCI_IOBASE);
+}
+
+static inline u32 inl(unsigned long addr)
+{
+	return readl(addr + PCI_IOBASE);
+}
+
+static inline void outb(u8 b, unsigned long addr)
+{
+	writeb(b, addr + PCI_IOBASE);
+}
+
+static inline void outw(u16 b, unsigned long addr)
+{
+	writew(b, addr + PCI_IOBASE);
+}
+
+static inline void outl(u32 b, unsigned long addr)
+{
+	writel(b, addr + PCI_IOBASE);
+}
+
+#define inb_p(addr)	inb(addr)
+#define inw_p(addr)	inw(addr)
+#define inl_p(addr)	inl(addr)
+
+#define outb_p(x, addr)	outb((x), (addr))
+#define outw_p(x, addr)	outw((x), (addr))
+#define outl_p(x, addr)	outl((x), (addr))
+
+static inline void insb(unsigned long addr, void *buffer, int count)
+{
+	u8 *buf = buffer;
+	while (count--)
+		*buf++ = __raw_readb(addr + PCI_IOBASE);
+}
+
+static inline void insw(unsigned long addr, void *buffer, int count)
+{
+	u16 *buf = buffer;
+	while (count--)
+		*buf++ = __raw_readw(addr + PCI_IOBASE);
+}
+
+static inline void insl(unsigned long addr, void *buffer, int count)
+{
+	u32 *buf = buffer;
+	while (count--)
+		*buf++ = __raw_readl(addr + PCI_IOBASE);
+}
+
+static inline void outsb(unsigned long addr, const void *buffer, int count)
+{
+	const u8 *buf = buffer;
+	while (count--)
+		__raw_writeb(*buf++, addr + PCI_IOBASE);
+}
+
+static inline void outsw(unsigned long addr, const void *buffer, int count)
+{
+	const u16 *buf = buffer;
+	while (count--)
+		__raw_writew(*buf++, addr + PCI_IOBASE);
+}
+
+static inline void outsl(unsigned long addr, const void *buffer, int count)
+{
+	const u32 *buf = buffer;
+	while (count--)
+		__raw_writel(*buf++, addr + PCI_IOBASE);
+}
+
+#define insb_p(port,to,len)	insb(port,to,len)
+#define insw_p(port,to,len)	insw(port,to,len)
+#define insl_p(port,to,len)	insl(port,to,len)
+
+#define outsb_p(port,from,len)	outsb(port,from,len)
+#define outsw_p(port,from,len)	outsw(port,from,len)
+#define outsl_p(port,from,len)	outsl(port,from,len)
+
+/*
+ * String version of I/O memory access operations.
+ */
+extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t);
+extern void __memcpy_toio(volatile void __iomem *, const void *, size_t);
+extern void __memset_io(volatile void __iomem *, int, size_t);
+
+#define memset_io(c,v,l)	__memset_io((c),(v),(l))
+#define memcpy_fromio(a,c,l)	__memcpy_fromio((a),(c),(l))
+#define memcpy_toio(c,a,l)	__memcpy_toio((c),(a),(l))
+
+/*
+ * I/O memory mapping functions.
+ */
+extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot);
+extern void __iounmap(volatile void __iomem *addr);
+
+#define PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY)
+#define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
+#define PROT_NORMAL_NC		(PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC))
+
+#define ioremap(addr, size)		__ioremap((addr), (size), PROT_DEVICE_nGnRE)
+#define ioremap_nocache(addr, size)	__ioremap((addr), (size), PROT_DEVICE_nGnRE)
+#define ioremap_wc(addr, size)		__ioremap((addr), (size), PROT_NORMAL_NC)
+#define iounmap				__iounmap
+
+#define ARCH_HAS_IOREMAP_WC
+#include <asm-generic/iomap.h>
+
+/*
+ * More restrictive address range checking than the default implementation
+ * (PHYS_OFFSET and PHYS_MASK taken into account).
+ */
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern int valid_phys_addr_range(unsigned long addr, size_t size);
+extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+
+extern int devmem_is_allowed(unsigned long pfn);
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
+#endif	/* __KERNEL__ */
+#endif	/* __ASM_IO_H */
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
new file mode 100644
index 0000000..a4e1cad
--- /dev/null
+++ b/arch/arm64/include/asm/irq.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_IRQ_H
+#define __ASM_IRQ_H
+
+#include <asm-generic/irq.h>
+
+extern void (*handle_arch_irq)(struct pt_regs *);
+
+#endif
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
new file mode 100644
index 0000000..aa11943
--- /dev/null
+++ b/arch/arm64/include/asm/irqflags.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_IRQFLAGS_H
+#define __ASM_IRQFLAGS_H
+
+#ifdef __KERNEL__
+
+#include <asm/ptrace.h>
+
+/*
+ * CPU interrupt mask handling.
+ */
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	asm volatile(
+		"mrs	%0, daif		// arch_local_irq_save\n"
+		"msr	daifset, #2"
+		: "=r" (flags)
+		:
+		: "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile(
+		"msr	daifclr, #2		// arch_local_irq_enable"
+		:
+		:
+		: "memory");
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile(
+		"msr	daifset, #2		// arch_local_irq_disable"
+		:
+		:
+		: "memory");
+}
+
+#define local_fiq_enable()	asm("msr	daifclr, #1" : : : "memory")
+#define local_fiq_disable()	asm("msr	daifset, #1" : : : "memory")
+
+/*
+ * Save the current interrupt enable state.
+ */
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile(
+		"mrs	%0, daif		// arch_local_save_flags"
+		: "=r" (flags)
+		:
+		: "memory");
+	return flags;
+}
+
+/*
+ * restore saved IRQ state
+ */
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile(
+		"msr	daif, %0		// arch_local_irq_restore"
+	:
+	: "r" (flags)
+	: "memory");
+}
+
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags & PSR_I_BIT;
+}
+
+#endif
+#endif
diff --git a/arch/arm64/include/asm/memblock.h b/arch/arm64/include/asm/memblock.h
new file mode 100644
index 0000000..6afeed2
--- /dev/null
+++ b/arch/arm64/include/asm/memblock.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_MEMBLOCK_H
+#define __ASM_MEMBLOCK_H
+
+extern void arm64_memblock_init(void);
+
+#endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
new file mode 100644
index 0000000..1cac16a
--- /dev/null
+++ b/arch/arm64/include/asm/memory.h
@@ -0,0 +1,144 @@
+/*
+ * Based on arch/arm/include/asm/memory.h
+ *
+ * Copyright (C) 2000-2002 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Note: this file should not be included by non-asm/.h files
+ */
+#ifndef __ASM_MEMORY_H
+#define __ASM_MEMORY_H
+
+#include <linux/compiler.h>
+#include <linux/const.h>
+#include <linux/types.h>
+#include <asm/sizes.h>
+
+/*
+ * Allow for constants defined here to be used from assembly code
+ * by prepending the UL suffix only with actual C code compilation.
+ */
+#define UL(x) _AC(x, UL)
+
+/*
+ * PAGE_OFFSET - the virtual address of the start of the kernel image.
+ * VA_BITS - the maximum number of bits for virtual addresses.
+ * TASK_SIZE - the maximum size of a user space task.
+ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
+ * The module space lives between the addresses given by TASK_SIZE
+ * and PAGE_OFFSET - it must be within 128MB of the kernel text.
+ */
+#define PAGE_OFFSET		UL(0xffffffc000000000)
+#define MODULES_END		(PAGE_OFFSET)
+#define MODULES_VADDR		(MODULES_END - SZ_64M)
+#define VA_BITS			(39)
+#define TASK_SIZE_64		(UL(1) << VA_BITS)
+
+#ifdef CONFIG_COMPAT
+#define TASK_SIZE_32		UL(0x100000000)
+#define TASK_SIZE		(test_thread_flag(TIF_32BIT) ? \
+				TASK_SIZE_32 : TASK_SIZE_64)
+#else
+#define TASK_SIZE		TASK_SIZE_64
+#endif /* CONFIG_COMPAT */
+
+#define TASK_UNMAPPED_BASE	(PAGE_ALIGN(TASK_SIZE / 4))
+
+#if TASK_SIZE_64 > MODULES_VADDR
+#error Top of 64-bit user space clashes with start of module space
+#endif
+
+/*
+ * Physical vs virtual RAM address space conversion.  These are
+ * private definitions which should NOT be used outside memory.h
+ * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
+ */
+#define __virt_to_phys(x)	(((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
+#define __phys_to_virt(x)	((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
+
+/*
+ * Convert a physical address to a Page Frame Number and back
+ */
+#define	__phys_to_pfn(paddr)	((unsigned long)((paddr) >> PAGE_SHIFT))
+#define	__pfn_to_phys(pfn)	((phys_addr_t)(pfn) << PAGE_SHIFT)
+
+/*
+ * Convert a page to/from a physical address
+ */
+#define page_to_phys(page)	(__pfn_to_phys(page_to_pfn(page)))
+#define phys_to_page(phys)	(pfn_to_page(__phys_to_pfn(phys)))
+
+/*
+ * Memory types available.
+ */
+#define MT_DEVICE_nGnRnE	0
+#define MT_DEVICE_nGnRE		1
+#define MT_DEVICE_GRE		2
+#define MT_NORMAL_NC		3
+#define MT_NORMAL		4
+
+#ifndef __ASSEMBLY__
+
+extern phys_addr_t		memstart_addr;
+/* PHYS_OFFSET - the physical address of the start of memory. */
+#define PHYS_OFFSET		({ memstart_addr; })
+
+/*
+ * PFNs are used to describe any physical page; this means
+ * PFN 0 == physical address 0.
+ *
+ * This is the PFN of the first RAM page in the kernel
+ * direct-mapped view.  We assume this is the first page
+ * of RAM in the mem_map as well.
+ */
+#define PHYS_PFN_OFFSET	(PHYS_OFFSET >> PAGE_SHIFT)
+
+/*
+ * Note: Drivers should NOT use these.  They are the wrong
+ * translation for translating DMA addresses.  Use the driver
+ * DMA support - see dma-mapping.h.
+ */
+static inline phys_addr_t virt_to_phys(const volatile void *x)
+{
+	return __virt_to_phys((unsigned long)(x));
+}
+
+static inline void *phys_to_virt(phys_addr_t x)
+{
+	return (void *)(__phys_to_virt(x));
+}
+
+/*
+ * Drivers should NOT use these either.
+ */
+#define __pa(x)			__virt_to_phys((unsigned long)(x))
+#define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))
+#define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+
+/*
+ *  virt_to_page(k)	convert a _valid_ virtual address to struct page *
+ *  virt_addr_valid(k)	indicates whether a virtual address is valid
+ */
+#define ARCH_PFN_OFFSET		PHYS_PFN_OFFSET
+
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define	virt_addr_valid(kaddr)	(((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+				 ((void *)(kaddr) < (void *)high_memory))
+
+#endif
+
+#include <asm-generic/memory_model.h>
+
+#endif
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
new file mode 100644
index 0000000..d4f7fd5
--- /dev/null
+++ b/arch/arm64/include/asm/mmu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_MMU_H
+#define __ASM_MMU_H
+
+typedef struct {
+	unsigned int id;
+	raw_spinlock_t id_lock;
+	void *vdso;
+} mm_context_t;
+
+#define ASID(mm)	((mm)->context.id & 0xffff)
+
+extern void paging_init(void);
+extern void setup_mm_for_reboot(void);
+
+#endif
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
new file mode 100644
index 0000000..f68465d
--- /dev/null
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -0,0 +1,152 @@
+/*
+ * Based on arch/arm/include/asm/mmu_context.h
+ *
+ * Copyright (C) 1996 Russell King.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_MMU_CONTEXT_H
+#define __ASM_MMU_CONTEXT_H
+
+#include <linux/compiler.h>
+#include <linux/sched.h>
+
+#include <asm/cacheflush.h>
+#include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
+#include <asm/cputype.h>
+#include <asm/pgtable.h>
+
+#define MAX_ASID_BITS	16
+
+extern unsigned int cpu_last_asid;
+
+void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+void __new_context(struct mm_struct *mm);
+
+/*
+ * Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0.
+ */
+static inline void cpu_set_reserved_ttbr0(void)
+{
+	unsigned long ttbr = page_to_phys(empty_zero_page);
+
+	asm(
+	"	msr	ttbr0_el1, %0			// set TTBR0\n"
+	"	isb"
+	:
+	: "r" (ttbr));
+}
+
+static inline void switch_new_context(struct mm_struct *mm)
+{
+	unsigned long flags;
+
+	__new_context(mm);
+
+	local_irq_save(flags);
+	cpu_switch_mm(mm->pgd, mm);
+	local_irq_restore(flags);
+}
+
+static inline void check_and_switch_context(struct mm_struct *mm,
+					    struct task_struct *tsk)
+{
+	/*
+	 * Required during context switch to avoid speculative page table
+	 * walking with the wrong TTBR.
+	 */
+	cpu_set_reserved_ttbr0();
+
+	if (!((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS))
+		/*
+		 * The ASID is from the current generation, just switch to the
+		 * new pgd. This condition is only true for calls from
+		 * context_switch() and interrupts are already disabled.
+		 */
+		cpu_switch_mm(mm->pgd, mm);
+	else if (irqs_disabled())
+		/*
+		 * Defer the new ASID allocation until after the context
+		 * switch critical region since __new_context() cannot be
+		 * called with interrupts disabled.
+		 */
+		set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
+	else
+		/*
+		 * That is a direct call to switch_mm() or activate_mm() with
+		 * interrupts enabled and a new context.
+		 */
+		switch_new_context(mm);
+}
+
+#define init_new_context(tsk,mm)	(__init_new_context(tsk,mm),0)
+#define destroy_context(mm)		do { } while(0)
+
+#define finish_arch_post_lock_switch \
+	finish_arch_post_lock_switch
+static inline void finish_arch_post_lock_switch(void)
+{
+	if (test_and_clear_thread_flag(TIF_SWITCH_MM)) {
+		struct mm_struct *mm = current->mm;
+		unsigned long flags;
+
+		__new_context(mm);
+
+		local_irq_save(flags);
+		cpu_switch_mm(mm->pgd, mm);
+		local_irq_restore(flags);
+	}
+}
+
+/*
+ * This is called when "tsk" is about to enter lazy TLB mode.
+ *
+ * mm:  describes the currently active mm context
+ * tsk: task which is entering lazy tlb
+ * cpu: cpu number which is entering lazy tlb
+ *
+ * tsk->mm will be NULL
+ */
+static inline void
+enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/*
+ * This is the actual mm switch as far as the scheduler
+ * is concerned.  No registers are touched.  We avoid
+ * calling the CPU specific function when the mm hasn't
+ * actually changed.
+ */
+static inline void
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+	  struct task_struct *tsk)
+{
+	unsigned int cpu = smp_processor_id();
+
+#ifdef CONFIG_SMP
+	/* check for possible thread migration */
+	if (!cpumask_empty(mm_cpumask(next)) &&
+	    !cpumask_test_cpu(cpu, mm_cpumask(next)))
+		__flush_icache_all();
+#endif
+	if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
+		check_and_switch_context(next, tsk);
+}
+
+#define deactivate_mm(tsk,mm)	do { } while (0)
+#define activate_mm(prev,next)	switch_mm(prev, next, NULL)
+
+#endif
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
new file mode 100644
index 0000000..e80e232
--- /dev/null
+++ b/arch/arm64/include/asm/module.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_MODULE_H
+#define __ASM_MODULE_H
+
+#include <asm-generic/module.h>
+
+#define MODULE_ARCH_VERMAGIC	"aarch64"
+
+#endif /* __ASM_MODULE_H */
diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
new file mode 100644
index 0000000..46bf666
--- /dev/null
+++ b/arch/arm64/include/asm/page.h
@@ -0,0 +1,67 @@
+/*
+ * Based on arch/arm/include/asm/page.h
+ *
+ * Copyright (C) 1995-2003 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PAGE_H
+#define __ASM_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#ifdef CONFIG_ARM64_64K_PAGES
+#define PAGE_SHIFT		16
+#else
+#define PAGE_SHIFT		12
+#endif
+#define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK		(~(PAGE_SIZE-1))
+
+/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
+#define __HAVE_ARCH_GATE_AREA		1
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_ARM64_64K_PAGES
+#include <asm/pgtable-2level-types.h>
+#else
+#include <asm/pgtable-3level-types.h>
+#endif
+
+extern void __cpu_clear_user_page(void *p, unsigned long user);
+extern void __cpu_copy_user_page(void *to, const void *from,
+				 unsigned long user);
+extern void copy_page(void *to, const void *from);
+extern void clear_page(void *to);
+
+#define clear_user_page(addr,vaddr,pg)  __cpu_clear_user_page(addr, vaddr)
+#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
+
+typedef struct page *pgtable_t;
+
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
+extern int pfn_valid(unsigned long);
+#endif
+
+#include <asm/memory.h>
+
+#endif /* !__ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS \
+	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#include <asm-generic/getorder.h>
+
+#endif
diff --git a/arch/arm64/include/asm/param.h b/arch/arm64/include/asm/param.h
new file mode 100644
index 0000000..8e3a281
--- /dev/null
+++ b/arch/arm64/include/asm/param.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PARAM_H
+#define __ASM_PARAM_H
+
+#define EXEC_PAGESIZE	65536
+
+#include <asm-generic/param.h>
+
+#endif
diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
new file mode 100644
index 0000000..a6fffd5
--- /dev/null
+++ b/arch/arm64/include/asm/perf_event.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_PERF_EVENT_H
+#define __ASM_PERF_EVENT_H
+
+/* It's quiet around here... */
+
+#endif
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
new file mode 100644
index 0000000..f214069
--- /dev/null
+++ b/arch/arm64/include/asm/pgalloc.h
@@ -0,0 +1,113 @@
+/*
+ * Based on arch/arm/include/asm/pgalloc.h
+ *
+ * Copyright (C) 2000-2001 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGALLOC_H
+#define __ASM_PGALLOC_H
+
+#include <asm/pgtable-hwdef.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+#define check_pgt_cache()		do { } while (0)
+
+#ifndef CONFIG_ARM64_64K_PAGES
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	return (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
+}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+	BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
+	free_page((unsigned long)pmd);
+}
+
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+	set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
+}
+
+#endif	/* CONFIG_ARM64_64K_PAGES */
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
+
+#define PGALLOC_GFP	(GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
+
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
+{
+	return (pte_t *)__get_free_page(PGALLOC_GFP);
+}
+
+static inline pgtable_t
+pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	struct page *pte;
+
+	pte = alloc_pages(PGALLOC_GFP, 0);
+	if (pte)
+		pgtable_page_ctor(pte);
+
+	return pte;
+}
+
+/*
+ * Free a PTE table.
+ */
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+	if (pte)
+		free_page((unsigned long)pte);
+}
+
+static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
+{
+	pgtable_page_dtor(pte);
+	__free_page(pte);
+}
+
+static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
+				  pmdval_t prot)
+{
+	set_pmd(pmdp, __pmd(pte | prot));
+}
+
+/*
+ * Populate the pmdp entry with a pointer to the pte.  This pmd is part
+ * of the mm address space.
+ */
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
+{
+	/*
+	 * The pmd must be loaded with the physical address of the PTE table
+	 */
+	__pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE);
+}
+
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
+{
+	__pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE);
+}
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+#endif
diff --git a/arch/arm64/include/asm/pgtable-2level-hwdef.h b/arch/arm64/include/asm/pgtable-2level-hwdef.h
new file mode 100644
index 0000000..0a8ed3f
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable-2level-hwdef.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_2LEVEL_HWDEF_H
+#define __ASM_PGTABLE_2LEVEL_HWDEF_H
+
+/*
+ * With LPAE and 64KB pages, there are 2 levels of page tables. Each level has
+ * 8192 entries of 8 bytes each, occupying a 64KB page. Levels 0 and 1 are not
+ * used. The 2nd level table (PGD for Linux) can cover a range of 4TB, each
+ * entry representing 512MB. The user and kernel address spaces are limited to
+ * 512GB and therefore we only use 1024 entries in the PGD.
+ */
+#define PTRS_PER_PTE		8192
+#define PTRS_PER_PGD		1024
+
+/*
+ * PGDIR_SHIFT determines the size a top-level page table entry can map.
+ */
+#define PGDIR_SHIFT		29
+#define PGDIR_SIZE		(_AC(1, UL) << PGDIR_SHIFT)
+#define PGDIR_MASK		(~(PGDIR_SIZE-1))
+
+/*
+ * section address mask and size definitions.
+ */
+#define SECTION_SHIFT		29
+#define SECTION_SIZE		(_AC(1, UL) << SECTION_SHIFT)
+#define SECTION_MASK		(~(SECTION_SIZE-1))
+
+#endif
diff --git a/arch/arm64/include/asm/pgtable-2level-types.h b/arch/arm64/include/asm/pgtable-2level-types.h
new file mode 100644
index 0000000..3c3ca7d
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable-2level-types.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_2LEVEL_TYPES_H
+#define __ASM_PGTABLE_2LEVEL_TYPES_H
+
+typedef u64 pteval_t;
+typedef u64 pgdval_t;
+typedef pgdval_t pmdval_t;
+
+#undef STRICT_MM_TYPECHECKS
+
+#ifdef STRICT_MM_TYPECHECKS
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { pteval_t pte; } pte_t;
+typedef struct { pgdval_t pgd; } pgd_t;
+typedef struct { pteval_t pgprot; } pgprot_t;
+
+#define pte_val(x)      ((x).pte)
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x)        ((pte_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)     ((pgprot_t) { (x) } )
+
+#else	/* !STRICT_MM_TYPECHECKS */
+
+typedef pteval_t pte_t;
+typedef pgdval_t pgd_t;
+typedef pteval_t pgprot_t;
+
+#define pte_val(x)	(x)
+#define pgd_val(x)	(x)
+#define pgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __pgd(x)	(x)
+#define __pgprot(x)	(x)
+
+#endif	/* STRICT_MM_TYPECHECKS */
+
+#include <asm-generic/pgtable-nopmd.h>
+
+#endif	/* __ASM_PGTABLE_2LEVEL_TYPES_H */
diff --git a/arch/arm64/include/asm/pgtable-3level-hwdef.h b/arch/arm64/include/asm/pgtable-3level-hwdef.h
new file mode 100644
index 0000000..3dbf941
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable-3level-hwdef.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_3LEVEL_HWDEF_H
+#define __ASM_PGTABLE_3LEVEL_HWDEF_H
+
+/*
+ * With LPAE and 4KB pages, there are 3 levels of page tables. Each level has
+ * 512 entries of 8 bytes each, occupying a 4K page. The first level table
+ * covers a range of 512GB, each entry representing 1GB. The user and kernel
+ * address spaces are limited to 512GB each.
+ */
+#define PTRS_PER_PTE		512
+#define PTRS_PER_PMD		512
+#define PTRS_PER_PGD		512
+
+/*
+ * PGDIR_SHIFT determines the size a top-level page table entry can map.
+ */
+#define PGDIR_SHIFT		30
+#define PGDIR_SIZE		(_AC(1, UL) << PGDIR_SHIFT)
+#define PGDIR_MASK		(~(PGDIR_SIZE-1))
+
+/*
+ * PMD_SHIFT determines the size a middle-level page table entry can map.
+ */
+#define PMD_SHIFT		21
+#define PMD_SIZE		(_AC(1, UL) << PMD_SHIFT)
+#define PMD_MASK		(~(PMD_SIZE-1))
+
+/*
+ * section address mask and size definitions.
+ */
+#define SECTION_SHIFT		21
+#define SECTION_SIZE		(_AC(1, UL) << SECTION_SHIFT)
+#define SECTION_MASK		(~(SECTION_SIZE-1))
+
+#endif
diff --git a/arch/arm64/include/asm/pgtable-3level-types.h b/arch/arm64/include/asm/pgtable-3level-types.h
new file mode 100644
index 0000000..4489615
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable-3level-types.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_3LEVEL_TYPES_H
+#define __ASM_PGTABLE_3LEVEL_TYPES_H
+
+typedef u64 pteval_t;
+typedef u64 pmdval_t;
+typedef u64 pgdval_t;
+
+#undef STRICT_MM_TYPECHECKS
+
+#ifdef STRICT_MM_TYPECHECKS
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { pteval_t pte; } pte_t;
+typedef struct { pmdval_t pmd; } pmd_t;
+typedef struct { pgdval_t pgd; } pgd_t;
+typedef struct { pteval_t pgprot; } pgprot_t;
+
+#define pte_val(x)      ((x).pte)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x)        ((pte_t) { (x) } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)     ((pgprot_t) { (x) } )
+
+#else	/* !STRICT_MM_TYPECHECKS */
+
+typedef pteval_t pte_t;
+typedef pmdval_t pmd_t;
+typedef pgdval_t pgd_t;
+typedef pteval_t pgprot_t;
+
+#define pte_val(x)	(x)
+#define pmd_val(x)	(x)
+#define pgd_val(x)	(x)
+#define pgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __pmd(x)	(x)
+#define __pgd(x)	(x)
+#define __pgprot(x)	(x)
+
+#endif	/* STRICT_MM_TYPECHECKS */
+
+#include <asm-generic/pgtable-nopud.h>
+
+#endif	/* __ASM_PGTABLE_3LEVEL_TYPES_H */
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
new file mode 100644
index 0000000..0f3b458
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_HWDEF_H
+#define __ASM_PGTABLE_HWDEF_H
+
+#ifdef CONFIG_ARM64_64K_PAGES
+#include <asm/pgtable-2level-hwdef.h>
+#else
+#include <asm/pgtable-3level-hwdef.h>
+#endif
+
+/*
+ * Hardware page table definitions.
+ *
+ * Level 2 descriptor (PMD).
+ */
+#define PMD_TYPE_MASK		(_AT(pmdval_t, 3) << 0)
+#define PMD_TYPE_FAULT		(_AT(pmdval_t, 0) << 0)
+#define PMD_TYPE_TABLE		(_AT(pmdval_t, 3) << 0)
+#define PMD_TYPE_SECT		(_AT(pmdval_t, 1) << 0)
+
+/*
+ * Section
+ */
+#define PMD_SECT_S		(_AT(pmdval_t, 3) << 8)
+#define PMD_SECT_AF		(_AT(pmdval_t, 1) << 10)
+#define PMD_SECT_NG		(_AT(pmdval_t, 1) << 11)
+#define PMD_SECT_XN		(_AT(pmdval_t, 1) << 54)
+
+/*
+ * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers).
+ */
+#define PMD_ATTRINDX(t)		(_AT(pmdval_t, (t)) << 2)
+#define PMD_ATTRINDX_MASK	(_AT(pmdval_t, 7) << 2)
+
+/*
+ * Level 3 descriptor (PTE).
+ */
+#define PTE_TYPE_MASK		(_AT(pteval_t, 3) << 0)
+#define PTE_TYPE_FAULT		(_AT(pteval_t, 0) << 0)
+#define PTE_TYPE_PAGE		(_AT(pteval_t, 3) << 0)
+#define PTE_USER		(_AT(pteval_t, 1) << 6)		/* AP[1] */
+#define PTE_RDONLY		(_AT(pteval_t, 1) << 7)		/* AP[2] */
+#define PTE_SHARED		(_AT(pteval_t, 3) << 8)		/* SH[1:0], inner shareable */
+#define PTE_AF			(_AT(pteval_t, 1) << 10)	/* Access Flag */
+#define PTE_NG			(_AT(pteval_t, 1) << 11)	/* nG */
+#define PTE_XN			(_AT(pteval_t, 1) << 54)	/* XN */
+
+/*
+ * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers).
+ */
+#define PTE_ATTRINDX(t)		(_AT(pteval_t, (t)) << 2)
+#define PTE_ATTRINDX_MASK	(_AT(pteval_t, 7) << 2)
+
+/*
+ * 40-bit physical address supported.
+ */
+#define PHYS_MASK_SHIFT		(40)
+#define PHYS_MASK		((UL(1) << PHYS_MASK_SHIFT) - 1)
+
+/*
+ * TCR flags.
+ */
+#define TCR_TxSZ(x)		(((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0))
+#define TCR_IRGN_NC		((UL(0) << 8) | (UL(0) << 24))
+#define TCR_IRGN_WBWA		((UL(1) << 8) | (UL(1) << 24))
+#define TCR_IRGN_WT		((UL(2) << 8) | (UL(2) << 24))
+#define TCR_IRGN_WBnWA		((UL(3) << 8) | (UL(3) << 24))
+#define TCR_IRGN_MASK		((UL(3) << 8) | (UL(3) << 24))
+#define TCR_ORGN_NC		((UL(0) << 10) | (UL(0) << 26))
+#define TCR_ORGN_WBWA		((UL(1) << 10) | (UL(1) << 26))
+#define TCR_ORGN_WT		((UL(2) << 10) | (UL(2) << 26))
+#define TCR_ORGN_WBnWA		((UL(3) << 10) | (UL(3) << 26))
+#define TCR_ORGN_MASK		((UL(3) << 10) | (UL(3) << 26))
+#define TCR_SHARED		((UL(3) << 12) | (UL(3) << 28))
+#define TCR_TG0_64K		(UL(1) << 14)
+#define TCR_TG1_64K		(UL(1) << 30)
+#define TCR_IPS_40BIT		(UL(2) << 32)
+#define TCR_ASID16		(UL(1) << 36)
+
+#endif
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
new file mode 100644
index 0000000..8960239
--- /dev/null
+++ b/arch/arm64/include/asm/pgtable.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PGTABLE_H
+#define __ASM_PGTABLE_H
+
+#include <asm/proc-fns.h>
+
+#include <asm/memory.h>
+#include <asm/pgtable-hwdef.h>
+
+/*
+ * Software defined PTE bits definition.
+ */
+#define PTE_VALID		(_AT(pteval_t, 1) << 0)	/* pte_present() check */
+#define PTE_FILE		(_AT(pteval_t, 1) << 2)	/* only when !pte_present() */
+#define PTE_DIRTY		(_AT(pteval_t, 1) << 55)
+#define PTE_SPECIAL		(_AT(pteval_t, 1) << 56)
+
+/*
+ * VMALLOC and SPARSEMEM_VMEMMAP ranges.
+ */
+#define VMALLOC_START		UL(0xffffff8000000000)
+#define VMALLOC_END		(PAGE_OFFSET - UL(0x400000000) - SZ_64K)
+
+#define vmemmap			((struct page *)(VMALLOC_END + SZ_64K))
+
+#define FIRST_USER_ADDRESS	0
+
+#ifndef __ASSEMBLY__
+extern void __pte_error(const char *file, int line, unsigned long val);
+extern void __pmd_error(const char *file, int line, unsigned long val);
+extern void __pgd_error(const char *file, int line, unsigned long val);
+
+#define pte_ERROR(pte)		__pte_error(__FILE__, __LINE__, pte_val(pte))
+#ifndef CONFIG_ARM64_64K_PAGES
+#define pmd_ERROR(pmd)		__pmd_error(__FILE__, __LINE__, pmd_val(pmd))
+#endif
+#define pgd_ERROR(pgd)		__pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+
+/*
+ * The pgprot_* and protection_map entries will be fixed up at runtime to
+ * include the cachable and bufferable bits based on memory policy, as well as
+ * any architecture dependent bits like global/ASID and SMP shared mapping
+ * bits.
+ */
+#define _PAGE_DEFAULT		PTE_TYPE_PAGE | PTE_AF
+
+extern pgprot_t pgprot_default;
+
+#define _MOD_PROT(p, b)	__pgprot(pgprot_val(p) | (b))
+
+#define PAGE_NONE		_MOD_PROT(pgprot_default, PTE_NG | PTE_XN | PTE_RDONLY)
+#define PAGE_SHARED		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN)
+#define PAGE_SHARED_EXEC	_MOD_PROT(pgprot_default, PTE_USER | PTE_NG)
+#define PAGE_COPY		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
+#define PAGE_COPY_EXEC		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY)
+#define PAGE_READONLY		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
+#define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY)
+#define PAGE_KERNEL		_MOD_PROT(pgprot_default, PTE_XN | PTE_DIRTY)
+#define PAGE_KERNEL_EXEC	_MOD_PROT(pgprot_default, PTE_DIRTY)
+
+#define __PAGE_NONE		__pgprot(_PAGE_DEFAULT | PTE_NG | PTE_XN | PTE_RDONLY)
+#define __PAGE_SHARED		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN)
+#define __PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG)
+#define __PAGE_COPY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
+#define __PAGE_COPY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY)
+#define __PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
+#define __PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY)
+
+#endif /* __ASSEMBLY__ */
+
+#define __P000  __PAGE_NONE
+#define __P001  __PAGE_READONLY
+#define __P010  __PAGE_COPY
+#define __P011  __PAGE_COPY
+#define __P100  __PAGE_READONLY_EXEC
+#define __P101  __PAGE_READONLY_EXEC
+#define __P110  __PAGE_COPY_EXEC
+#define __P111  __PAGE_COPY_EXEC
+
+#define __S000  __PAGE_NONE
+#define __S001  __PAGE_READONLY
+#define __S010  __PAGE_SHARED
+#define __S011  __PAGE_SHARED
+#define __S100  __PAGE_READONLY_EXEC
+#define __S101  __PAGE_READONLY_EXEC
+#define __S110  __PAGE_SHARED_EXEC
+#define __S111  __PAGE_SHARED_EXEC
+
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern struct page *empty_zero_page;
+#define ZERO_PAGE(vaddr)	(empty_zero_page)
+
+#define pte_pfn(pte)		((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
+
+#define pfn_pte(pfn,prot)	(__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+
+#define pte_none(pte)		(!pte_val(pte))
+#define pte_clear(mm,addr,ptep)	set_pte(ptep, __pte(0))
+#define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
+#define pte_offset_kernel(dir,addr)	(pmd_page_vaddr(*(dir)) + __pte_index(addr))
+
+#define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
+#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte)			do { } while (0)
+#define pte_unmap_nested(pte)		do { } while (0)
+
+/*
+ * The following only work if pte_present(). Undefined behaviour otherwise.
+ */
+#define pte_present(pte)	(pte_val(pte) & PTE_VALID)
+#define pte_dirty(pte)		(pte_val(pte) & PTE_DIRTY)
+#define pte_young(pte)		(pte_val(pte) & PTE_AF)
+#define pte_special(pte)	(pte_val(pte) & PTE_SPECIAL)
+#define pte_write(pte)		(!(pte_val(pte) & PTE_RDONLY))
+#define pte_exec(pte)		(!(pte_val(pte) & PTE_XN))
+
+#define pte_present_exec_user(pte) \
+	((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_XN)) == \
+	 (PTE_VALID | PTE_USER))
+
+#define PTE_BIT_FUNC(fn,op) \
+static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
+
+PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY);
+PTE_BIT_FUNC(mkwrite,   &= ~PTE_RDONLY);
+PTE_BIT_FUNC(mkclean,   &= ~PTE_DIRTY);
+PTE_BIT_FUNC(mkdirty,   |= PTE_DIRTY);
+PTE_BIT_FUNC(mkold,     &= ~PTE_AF);
+PTE_BIT_FUNC(mkyoung,   |= PTE_AF);
+PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL);
+
+static inline void set_pte(pte_t *ptep, pte_t pte)
+{
+	*ptep = pte;
+}
+
+extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pte)
+{
+	if (pte_present_exec_user(pte))
+		__sync_icache_dcache(pte, addr);
+	set_pte(ptep, pte);
+}
+
+/*
+ * Huge pte definitions.
+ */
+#define pte_huge(pte)		((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE)
+#define pte_mkhuge(pte)		(__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE))
+
+#define __pgprot_modify(prot,mask,bits)		\
+	__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
+
+#define __HAVE_ARCH_PTE_SPECIAL
+
+/*
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+#define pgprot_noncached(prot) \
+	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+#define pgprot_writecombine(prot) \
+	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE))
+#define pgprot_dmacoherent(prot) \
+	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+				     unsigned long size, pgprot_t vma_prot);
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define pmd_present(pmd)	(pmd_val(pmd))
+
+#define pmd_bad(pmd)		(!(pmd_val(pmd) & 2))
+
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+	*pmdp = pmd;
+	dsb();
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+	set_pmd(pmdp, __pmd(0));
+}
+
+static inline pte_t *pmd_page_vaddr(pmd_t pmd)
+{
+	return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK);
+}
+
+#define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define mk_pte(page,prot)	pfn_pte(page_to_pfn(page),prot)
+
+#ifndef CONFIG_ARM64_64K_PAGES
+
+#define pud_none(pud)		(!pud_val(pud))
+#define pud_bad(pud)		(!(pud_val(pud) & 2))
+#define pud_present(pud)	(pud_val(pud))
+
+static inline void set_pud(pud_t *pudp, pud_t pud)
+{
+	*pudp = pud;
+	dsb();
+}
+
+static inline void pud_clear(pud_t *pudp)
+{
+	set_pud(pudp, __pud(0));
+}
+
+static inline pmd_t *pud_page_vaddr(pud_t pud)
+{
+	return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK);
+}
+
+#endif	/* CONFIG_ARM64_64K_PAGES */
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(addr)		(((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+#define pgd_offset(mm, addr)	((mm)->pgd+pgd_index(addr))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(addr)	pgd_offset(&init_mm, addr)
+
+/* Find an entry in the second-level page table.. */
+#ifndef CONFIG_ARM64_64K_PAGES
+#define pmd_index(addr)		(((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
+{
+	return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
+}
+#endif
+
+/* Find an entry in the third-level page table.. */
+#define __pte_index(addr)	(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+	const pteval_t mask = PTE_USER | PTE_XN | PTE_RDONLY;
+	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
+	return pte;
+}
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
+
+#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
+#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
+
+/*
+ * Encode and decode a swap entry:
+ *	bits 0-1:	present (must be zero)
+ *	bit  2:		PTE_FILE
+ *	bits 3-8:	swap type
+ *	bits 9-63:	swap offset
+ */
+#define __SWP_TYPE_SHIFT	3
+#define __SWP_TYPE_BITS		6
+#define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
+#define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
+
+#define __swp_type(x)		(((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
+#define __swp_offset(x)		((x).val >> __SWP_OFFSET_SHIFT)
+#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
+
+#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
+
+/*
+ * Ensure that there are not more swap files than can be encoded in the kernel
+ * the PTEs.
+ */
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
+
+/*
+ * Encode and decode a file entry:
+ *	bits 0-1:	present (must be zero)
+ *	bit  2:		PTE_FILE
+ *	bits 3-63:	file offset / PAGE_SIZE
+ */
+#define pte_file(pte)		(pte_val(pte) & PTE_FILE)
+#define pte_to_pgoff(x)		(pte_val(x) >> 3)
+#define pgoff_to_pte(x)		__pte(((x) << 3) | PTE_FILE)
+
+#define PTE_FILE_MAX_BITS	61
+
+extern int kern_addr_valid(unsigned long addr);
+
+#include <asm-generic/pgtable.h>
+
+/*
+ * remap a physical page `pfn' of size `size' with page protection `prot'
+ * into virtual address `from'
+ */
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+		remap_pfn_range(vma, from, pfn, size, prot)
+
+#define pgtable_cache_init() do { } while (0)
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __ASM_PGTABLE_H */
diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
new file mode 100644
index 0000000..e6f0878
--- /dev/null
+++ b/arch/arm64/include/asm/pmu.h
@@ -0,0 +1,82 @@
+/*
+ * Based on arch/arm/include/asm/pmu.h
+ *
+ * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PMU_H
+#define __ASM_PMU_H
+
+#ifdef CONFIG_HW_PERF_EVENTS
+
+/* The events for a given PMU register set. */
+struct pmu_hw_events {
+	/*
+	 * The events that are active on the PMU for the given index.
+	 */
+	struct perf_event	**events;
+
+	/*
+	 * A 1 bit for an index indicates that the counter is being used for
+	 * an event. A 0 means that the counter can be used.
+	 */
+	unsigned long           *used_mask;
+
+	/*
+	 * Hardware lock to serialize accesses to PMU registers. Needed for the
+	 * read/modify/write sequences.
+	 */
+	raw_spinlock_t		pmu_lock;
+};
+
+struct arm_pmu {
+	struct pmu		pmu;
+	cpumask_t		active_irqs;
+	const char		*name;
+	irqreturn_t		(*handle_irq)(int irq_num, void *dev);
+	void			(*enable)(struct hw_perf_event *evt, int idx);
+	void			(*disable)(struct hw_perf_event *evt, int idx);
+	int			(*get_event_idx)(struct pmu_hw_events *hw_events,
+						 struct hw_perf_event *hwc);
+	int			(*set_event_filter)(struct hw_perf_event *evt,
+						    struct perf_event_attr *attr);
+	u32			(*read_counter)(int idx);
+	void			(*write_counter)(int idx, u32 val);
+	void			(*start)(void);
+	void			(*stop)(void);
+	void			(*reset)(void *);
+	int			(*map_event)(struct perf_event *event);
+	int			num_events;
+	atomic_t		active_events;
+	struct mutex		reserve_mutex;
+	u64			max_period;
+	struct platform_device	*plat_device;
+	struct pmu_hw_events	*(*get_hw_events)(void);
+};
+
+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
+
+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+
+u64 armpmu_event_update(struct perf_event *event,
+			struct hw_perf_event *hwc,
+			int idx);
+
+int armpmu_event_set_period(struct perf_event *event,
+			    struct hw_perf_event *hwc,
+			    int idx);
+
+#endif /* CONFIG_HW_PERF_EVENTS */
+#endif /* __ASM_PMU_H */
diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h
new file mode 100644
index 0000000..7cdf466
--- /dev/null
+++ b/arch/arm64/include/asm/proc-fns.h
@@ -0,0 +1,50 @@
+/*
+ * Based on arch/arm/include/asm/proc-fns.h
+ *
+ * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PROCFNS_H
+#define __ASM_PROCFNS_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <asm/page.h>
+
+struct mm_struct;
+
+extern void cpu_cache_off(void);
+extern void cpu_do_idle(void);
+extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
+extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
+
+#include <asm/memory.h>
+
+#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
+
+#define cpu_get_pgd()					\
+({							\
+	unsigned long pg;				\
+	asm("mrs	%0, ttbr0_el1\n"		\
+	    : "=r" (pg));				\
+	pg &= ~0xffff000000003ffful;			\
+	(pgd_t *)phys_to_virt(pg);			\
+})
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* __ASM_PROCFNS_H */
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
new file mode 100644
index 0000000..39a208a
--- /dev/null
+++ b/arch/arm64/include/asm/processor.h
@@ -0,0 +1,175 @@
+/*
+ * Based on arch/arm/include/asm/processor.h
+ *
+ * Copyright (C) 1995-1999 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PROCESSOR_H
+#define __ASM_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#ifdef __KERNEL__
+
+#include <linux/string.h>
+
+#include <asm/fpsimd.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/ptrace.h>
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+#define STACK_TOP_MAX		TASK_SIZE_64
+#ifdef CONFIG_COMPAT
+#define AARCH32_VECTORS_BASE	0xffff0000
+#define STACK_TOP		(test_thread_flag(TIF_32BIT) ? \
+				AARCH32_VECTORS_BASE : STACK_TOP_MAX)
+#else
+#define STACK_TOP		STACK_TOP_MAX
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+
+struct debug_info {
+	/* Have we suspended stepping by a debugger? */
+	int			suspended_step;
+	/* Allow breakpoints and watchpoints to be disabled for this thread. */
+	int			bps_disabled;
+	int			wps_disabled;
+	/* Hardware breakpoints pinned to this task. */
+	struct perf_event	*hbp_break[ARM_MAX_BRP];
+	struct perf_event	*hbp_watch[ARM_MAX_WRP];
+};
+
+struct cpu_context {
+	unsigned long x19;
+	unsigned long x20;
+	unsigned long x21;
+	unsigned long x22;
+	unsigned long x23;
+	unsigned long x24;
+	unsigned long x25;
+	unsigned long x26;
+	unsigned long x27;
+	unsigned long x28;
+	unsigned long fp;
+	unsigned long sp;
+	unsigned long pc;
+};
+
+struct thread_struct {
+	struct cpu_context	cpu_context;	/* cpu context */
+	unsigned long		tp_value;
+	struct fpsimd_state	fpsimd_state;
+	unsigned long		fault_address;	/* fault info */
+	struct debug_info	debug;		/* debugging */
+};
+
+#define INIT_THREAD  {	}
+
+static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
+{
+	memset(regs, 0, sizeof(*regs));
+	regs->syscallno = ~0UL;
+	regs->pc = pc;
+}
+
+static inline void start_thread(struct pt_regs *regs, unsigned long pc,
+				unsigned long sp)
+{
+	unsigned long *stack = (unsigned long *)sp;
+
+	start_thread_common(regs, pc);
+	regs->pstate = PSR_MODE_EL0t;
+	regs->sp = sp;
+	regs->regs[2] = stack[2];	/* x2 (envp) */
+	regs->regs[1] = stack[1];	/* x1 (argv) */
+	regs->regs[0] = stack[0];	/* x0 (argc) */
+}
+
+#ifdef CONFIG_COMPAT
+static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
+				       unsigned long sp)
+{
+	unsigned int *stack = (unsigned int *)sp;
+
+	start_thread_common(regs, pc);
+	regs->pstate = COMPAT_PSR_MODE_USR;
+	if (pc & 1)
+		regs->pstate |= COMPAT_PSR_T_BIT;
+	regs->compat_sp = sp;
+	regs->regs[2] = stack[2];	/* x2 (envp) */
+	regs->regs[1] = stack[1];	/* x1 (argv) */
+	regs->regs[0] = stack[0];	/* x0 (argc) */
+}
+#endif
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk)	do { } while (0)
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define cpu_relax()			barrier()
+
+/* Thread switching */
+extern struct task_struct *cpu_switch_to(struct task_struct *prev,
+					 struct task_struct *next);
+
+/*
+ * Create a new kernel thread
+ */
+extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#define task_pt_regs(p) \
+	((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
+
+#define KSTK_EIP(tsk)	task_pt_regs(tsk)->pc
+#define KSTK_ESP(tsk)	task_pt_regs(tsk)->sp
+
+/*
+ * Prefetching support
+ */
+#define ARCH_HAS_PREFETCH
+static inline void prefetch(const void *ptr)
+{
+	asm volatile("prfm pldl1keep, %a0\n" : : "p" (ptr));
+}
+
+#define ARCH_HAS_PREFETCHW
+static inline void prefetchw(const void *ptr)
+{
+	asm volatile("prfm pstl1keep, %a0\n" : : "p" (ptr));
+}
+
+#define ARCH_HAS_SPINLOCK_PREFETCH
+static inline void spin_lock_prefetch(const void *x)
+{
+	prefetchw(x);
+}
+
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
+#endif
+
+#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/include/asm/prom.h b/arch/arm64/include/asm/prom.h
new file mode 100644
index 0000000..68b90e6
--- /dev/null
+++ b/arch/arm64/include/asm/prom.h
@@ -0,0 +1 @@
+/* Empty for now */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
new file mode 100644
index 0000000..0fa5d6c
--- /dev/null
+++ b/arch/arm64/include/asm/ptrace.h
@@ -0,0 +1,207 @@
+/*
+ * Based on arch/arm/include/asm/ptrace.h
+ *
+ * Copyright (C) 1996-2003 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PTRACE_H
+#define __ASM_PTRACE_H
+
+#include <linux/types.h>
+
+#include <asm/hwcap.h>
+
+/* AArch32-specific ptrace requests */
+#define COMPAT_PTRACE_GETREGS		12
+#define COMPAT_PTRACE_SETREGS		13
+#define COMPAT_PTRACE_GET_THREAD_AREA	22
+#define COMPAT_PTRACE_SET_SYSCALL	23
+#define COMPAT_PTRACE_GETVFPREGS	27
+#define COMPAT_PTRACE_SETVFPREGS	28
+#define COMPAT_PTRACE_GETHBPREGS	29
+#define COMPAT_PTRACE_SETHBPREGS	30
+
+/*
+ * PSR bits
+ */
+#define PSR_MODE_EL0t	0x00000000
+#define PSR_MODE_EL1t	0x00000004
+#define PSR_MODE_EL1h	0x00000005
+#define PSR_MODE_EL2t	0x00000008
+#define PSR_MODE_EL2h	0x00000009
+#define PSR_MODE_EL3t	0x0000000c
+#define PSR_MODE_EL3h	0x0000000d
+#define PSR_MODE_MASK	0x0000000f
+
+/* AArch32 CPSR bits */
+#define PSR_MODE32_BIT		0x00000010
+#define COMPAT_PSR_MODE_USR	0x00000010
+#define COMPAT_PSR_T_BIT	0x00000020
+#define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+
+/* AArch64 SPSR bits */
+#define PSR_F_BIT	0x00000040
+#define PSR_I_BIT	0x00000080
+#define PSR_A_BIT	0x00000100
+#define PSR_D_BIT	0x00000200
+#define PSR_Q_BIT	0x08000000
+#define PSR_V_BIT	0x10000000
+#define PSR_C_BIT	0x20000000
+#define PSR_Z_BIT	0x40000000
+#define PSR_N_BIT	0x80000000
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f		0xff000000	/* Flags		*/
+#define PSR_s		0x00ff0000	/* Status		*/
+#define PSR_x		0x0000ff00	/* Extension		*/
+#define PSR_c		0x000000ff	/* Control		*/
+
+/*
+ * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
+ * process is located in memory.
+ */
+#define PT_TEXT_ADDR		0x10000
+#define PT_DATA_ADDR		0x10004
+#define PT_TEXT_END_ADDR	0x10008
+
+#ifndef __ASSEMBLY__
+
+/*
+ * User structures for general purpose, floating point and debug registers.
+ */
+struct user_pt_regs {
+	__u64		regs[31];
+	__u64		sp;
+	__u64		pc;
+	__u64		pstate;
+};
+
+struct user_fpsimd_state {
+	__uint128_t	vregs[32];
+	__u32		fpsr;
+	__u32		fpcr;
+};
+
+struct user_hwdebug_state {
+	__u32		dbg_info;
+	struct {
+		__u64	addr;
+		__u32	ctrl;
+	}		dbg_regs[16];
+};
+
+#ifdef __KERNEL__
+
+/* sizeof(struct user) for AArch32 */
+#define COMPAT_USER_SZ	296
+/* AArch32 uses x13 as the stack pointer... */
+#define compat_sp	regs[13]
+/* ... and x14 as the link register. */
+#define compat_lr	regs[14]
+
+/*
+ * This struct defines the way the registers are stored on the stack during an
+ * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for
+ * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.
+ */
+struct pt_regs {
+	union {
+		struct user_pt_regs user_regs;
+		struct {
+			u64 regs[31];
+			u64 sp;
+			u64 pc;
+			u64 pstate;
+		};
+	};
+	u64 orig_x0;
+	u64 syscallno;
+};
+
+#define arch_has_single_step()	(1)
+
+#ifdef CONFIG_COMPAT
+#define compat_thumb_mode(regs) \
+	(((regs)->pstate & COMPAT_PSR_T_BIT))
+#else
+#define compat_thumb_mode(regs) (0)
+#endif
+
+#define user_mode(regs)	\
+	(((regs)->pstate & PSR_MODE_MASK) == PSR_MODE_EL0t)
+
+#define compat_user_mode(regs)	\
+	(((regs)->pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) == \
+	 (PSR_MODE32_BIT | PSR_MODE_EL0t))
+
+#define processor_mode(regs) \
+	((regs)->pstate & PSR_MODE_MASK)
+
+#define interrupts_enabled(regs) \
+	(!((regs)->pstate & PSR_I_BIT))
+
+#define fast_interrupts_enabled(regs) \
+	(!((regs)->pstate & PSR_F_BIT))
+
+#define user_stack_pointer(regs) \
+	((regs)->sp)
+
+/*
+ * Are the current registers suitable for user mode? (used to maintain
+ * security in signal handlers)
+ */
+static inline int valid_user_regs(struct user_pt_regs *regs)
+{
+	if (user_mode(regs) && (regs->pstate & PSR_I_BIT) == 0) {
+		regs->pstate &= ~(PSR_F_BIT | PSR_A_BIT);
+
+		/* The T bit is reserved for AArch64 */
+		if (!(regs->pstate & PSR_MODE32_BIT))
+			regs->pstate &= ~COMPAT_PSR_T_BIT;
+
+		return 1;
+	}
+
+	/*
+	 * Force PSR to something logical...
+	 */
+	regs->pstate &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | \
+			COMPAT_PSR_T_BIT | PSR_MODE32_BIT;
+
+	if (!(regs->pstate & PSR_MODE32_BIT)) {
+		regs->pstate &= ~COMPAT_PSR_T_BIT;
+		regs->pstate |= PSR_MODE_EL0t;
+	}
+
+	return 0;
+}
+
+#define instruction_pointer(regs)	(regs)->pc
+
+#ifdef CONFIG_SMP
+extern unsigned long profile_pc(struct pt_regs *regs);
+#else
+#define profile_pc(regs) instruction_pointer(regs)
+#endif
+
+extern int aarch32_break_trap(struct pt_regs *regs);
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h
new file mode 100644
index 0000000..9cf2e46f
--- /dev/null
+++ b/arch/arm64/include/asm/setup.h
@@ -0,0 +1,26 @@
+/*
+ * Based on arch/arm/include/asm/setup.h
+ *
+ * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SETUP_H
+#define __ASM_SETUP_H
+
+#include <linux/types.h>
+
+#define COMMAND_LINE_SIZE	2048
+
+#endif
diff --git a/arch/arm64/include/asm/shmparam.h b/arch/arm64/include/asm/shmparam.h
new file mode 100644
index 0000000..4df608a
--- /dev/null
+++ b/arch/arm64/include/asm/shmparam.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SHMPARAM_H
+#define __ASM_SHMPARAM_H
+
+/*
+ * For IPC syscalls from compat tasks, we need to use the legacy 16k
+ * alignment value. Since we don't have aliasing D-caches, the rest of
+ * the time we can safely use PAGE_SIZE.
+ */
+#define COMPAT_SHMLBA	0x4000
+
+#include <asm-generic/shmparam.h>
+
+#endif /* __ASM_SHMPARAM_H */
diff --git a/arch/arm64/include/asm/sigcontext.h b/arch/arm64/include/asm/sigcontext.h
new file mode 100644
index 0000000..573cec7
--- /dev/null
+++ b/arch/arm64/include/asm/sigcontext.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SIGCONTEXT_H
+#define __ASM_SIGCONTEXT_H
+
+#include <linux/types.h>
+
+/*
+ * Signal context structure - contains all info to do with the state
+ * before the signal handler was invoked.
+ */
+struct sigcontext {
+	__u64 fault_address;
+	/* AArch64 registers */
+	__u64 regs[31];
+	__u64 sp;
+	__u64 pc;
+	__u64 pstate;
+	/* 4K reserved for FP/SIMD state and future expansion */
+	__u8 __reserved[4096] __attribute__((__aligned__(16)));
+};
+
+/*
+ * Header to be used at the beginning of structures extending the user
+ * context. Such structures must be placed after the rt_sigframe on the stack
+ * and be 16-byte aligned. The last structure must be a dummy one with the
+ * magic and size set to 0.
+ */
+struct _aarch64_ctx {
+	__u32 magic;
+	__u32 size;
+};
+
+#define FPSIMD_MAGIC	0x46508001
+
+struct fpsimd_context {
+	struct _aarch64_ctx head;
+	__u32 fpsr;
+	__u32 fpcr;
+	__uint128_t vregs[32];
+};
+
+#ifdef __KERNEL__
+/*
+ * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
+ * user space as it will change with the addition of new context. User space
+ * should check the magic/size information.
+ */
+struct aux_context {
+	struct fpsimd_context fpsimd;
+	/* additional context to be added before "end" */
+	struct _aarch64_ctx end;
+};
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/siginfo.h b/arch/arm64/include/asm/siginfo.h
new file mode 100644
index 0000000..5a74a08
--- /dev/null
+++ b/arch/arm64/include/asm/siginfo.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SIGINFO_H
+#define __ASM_SIGINFO_H
+
+#define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
+
+#include <asm-generic/siginfo.h>
+
+#endif
diff --git a/arch/arm64/include/asm/signal.h b/arch/arm64/include/asm/signal.h
new file mode 100644
index 0000000..8d1e723
--- /dev/null
+++ b/arch/arm64/include/asm/signal.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SIGNAL_H
+#define __ASM_SIGNAL_H
+
+/* Required for AArch32 compatibility. */
+#define SA_RESTORER	0x04000000
+
+#include <asm-generic/signal.h>
+
+#endif
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
new file mode 100644
index 0000000..7c275e3
--- /dev/null
+++ b/arch/arm64/include/asm/signal32.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SIGNAL32_H
+#define __ASM_SIGNAL32_H
+
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+
+#define AARCH32_KERN_SIGRET_CODE_OFFSET	0x500
+
+extern const compat_ulong_t aarch32_sigret_code[6];
+
+int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
+		       struct pt_regs *regs);
+int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+			  sigset_t *set, struct pt_regs *regs);
+
+void compat_setup_restart_syscall(struct pt_regs *regs);
+#else
+
+static inline int compat_setup_frame(int usid, struct k_sigaction *ka,
+				     sigset_t *set, struct pt_regs *regs)
+{
+	return -ENOSYS;
+}
+
+static inline int compat_setup_rt_frame(int usig, struct k_sigaction *ka,
+					siginfo_t *info, sigset_t *set,
+					struct pt_regs *regs)
+{
+	return -ENOSYS;
+}
+
+static inline void compat_setup_restart_syscall(struct pt_regs *regs)
+{
+}
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+#endif /* __ASM_SIGNAL32_H */
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
new file mode 100644
index 0000000..7e34295
--- /dev/null
+++ b/arch/arm64/include/asm/smp.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/thread_info.h>
+
+#ifndef CONFIG_SMP
+# error "<asm/smp.h> included in non-SMP build"
+#endif
+
+#define raw_smp_processor_id() (current_thread_info()->cpu)
+
+struct seq_file;
+
+/*
+ * generate IPI list text
+ */
+extern void show_ipi_list(struct seq_file *p, int prec);
+
+/*
+ * Called from C code, this handles an IPI.
+ */
+extern void handle_IPI(int ipinr, struct pt_regs *regs);
+
+/*
+ * Setup the set of possible CPUs (via set_cpu_possible)
+ */
+extern void smp_init_cpus(void);
+
+/*
+ * Provide a function to raise an IPI cross call on CPUs in callmap.
+ */
+extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
+
+/*
+ * Called from the secondary holding pen, this is the secondary CPU entry point.
+ */
+asmlinkage void secondary_start_kernel(void);
+
+/*
+ * Initial data for bringing up a secondary CPU.
+ */
+struct secondary_data {
+	void *stack;
+};
+extern struct secondary_data secondary_data;
+extern void secondary_holding_pen(void);
+extern volatile unsigned long secondary_holding_pen_release;
+
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+#endif /* ifndef __ASM_SMP_H */
diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h
new file mode 100644
index 0000000..1be62bc
--- /dev/null
+++ b/arch/arm64/include/asm/sparsemem.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SPARSEMEM_H
+#define __ASM_SPARSEMEM_H
+
+#ifdef CONFIG_SPARSEMEM
+#define MAX_PHYSMEM_BITS	40
+#define SECTION_SIZE_BITS	30
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
new file mode 100644
index 0000000..41112fe
--- /dev/null
+++ b/arch/arm64/include/asm/spinlock.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <asm/spinlock_types.h>
+#include <asm/processor.h>
+
+/*
+ * Spinlock implementation.
+ *
+ * The old value is read exclusively and the new one, if unlocked, is written
+ * exclusively. In case of failure, the loop is restarted.
+ *
+ * The memory barriers are implicit with the load-acquire and store-release
+ * instructions.
+ *
+ * Unlocked value: 0
+ * Locked value: 1
+ */
+
+#define arch_spin_is_locked(x)		((x)->lock != 0)
+#define arch_spin_unlock_wait(lock) \
+	do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
+
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+	unsigned int tmp;
+
+	asm volatile(
+	"	sevl\n"
+	"1:	wfe\n"
+	"2:	ldaxr	%w0, [%1]\n"
+	"	cbnz	%w0, 1b\n"
+	"	stxr	%w0, %w2, [%1]\n"
+	"	cbnz	%w0, 2b\n"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "memory");
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+	unsigned int tmp;
+
+	asm volatile(
+	"	ldaxr	%w0, [%1]\n"
+	"	cbnz	%w0, 1f\n"
+	"	stxr	%w0, %w2, [%1]\n"
+	"1:\n"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "memory");
+
+	return !tmp;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+	asm volatile(
+	"	stlr	%w1, [%0]\n"
+	: : "r" (&lock->lock), "r" (0) : "memory");
+}
+
+/*
+ * Write lock implementation.
+ *
+ * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
+ * exclusively held.
+ *
+ * The memory barriers are implicit with the load-acquire and store-release
+ * instructions.
+ */
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	asm volatile(
+	"	sevl\n"
+	"1:	wfe\n"
+	"2:	ldaxr	%w0, [%1]\n"
+	"	cbnz	%w0, 1b\n"
+	"	stxr	%w0, %w2, [%1]\n"
+	"	cbnz	%w0, 2b\n"
+	: "=&r" (tmp)
+	: "r" (&rw->lock), "r" (0x80000000)
+	: "memory");
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	asm volatile(
+	"	ldaxr	%w0, [%1]\n"
+	"	cbnz	%w0, 1f\n"
+	"	stxr	%w0, %w2, [%1]\n"
+	"1:\n"
+	: "=&r" (tmp)
+	: "r" (&rw->lock), "r" (0x80000000)
+	: "memory");
+
+	return !tmp;
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+	asm volatile(
+	"	stlr	%w1, [%0]\n"
+	: : "r" (&rw->lock), "r" (0) : "memory");
+}
+
+/* write_can_lock - would write_trylock() succeed? */
+#define arch_write_can_lock(x)		((x)->lock == 0)
+
+/*
+ * Read lock implementation.
+ *
+ * It exclusively loads the lock value, increments it and stores the new value
+ * back if positive and the CPU still exclusively owns the location. If the
+ * value is negative, the lock is already held.
+ *
+ * During unlocking there may be multiple active read locks but no write lock.
+ *
+ * The memory barriers are implicit with the load-acquire and store-release
+ * instructions.
+ */
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+	unsigned int tmp, tmp2;
+
+	asm volatile(
+	"	sevl\n"
+	"1:	wfe\n"
+	"2:	ldaxr	%w0, [%2]\n"
+	"	add	%w0, %w0, #1\n"
+	"	tbnz	%w0, #31, 1b\n"
+	"	stxr	%w1, %w0, [%2]\n"
+	"	cbnz	%w1, 2b\n"
+	: "=&r" (tmp), "=&r" (tmp2)
+	: "r" (&rw->lock)
+	: "memory");
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+	unsigned int tmp, tmp2;
+
+	asm volatile(
+	"1:	ldxr	%w0, [%2]\n"
+	"	sub	%w0, %w0, #1\n"
+	"	stlxr	%w1, %w0, [%2]\n"
+	"	cbnz	%w1, 1b\n"
+	: "=&r" (tmp), "=&r" (tmp2)
+	: "r" (&rw->lock)
+	: "memory");
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+	unsigned int tmp, tmp2 = 1;
+
+	asm volatile(
+	"	ldaxr	%w0, [%2]\n"
+	"	add	%w0, %w0, #1\n"
+	"	tbnz	%w0, #31, 1f\n"
+	"	stxr	%w1, %w0, [%2]\n"
+	"1:\n"
+	: "=&r" (tmp), "+r" (tmp2)
+	: "r" (&rw->lock)
+	: "memory");
+
+	return !tmp2;
+}
+
+/* read_can_lock - would read_trylock() succeed? */
+#define arch_read_can_lock(x)		((x)->lock < 0x80000000)
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define arch_spin_relax(lock)	cpu_relax()
+#define arch_read_relax(lock)	cpu_relax()
+#define arch_write_relax(lock)	cpu_relax()
+
+#endif /* __ASM_SPINLOCK_H */
diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h
new file mode 100644
index 0000000..9a49434
--- /dev/null
+++ b/arch/arm64/include/asm/spinlock_types.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SPINLOCK_TYPES_H
+#define __ASM_SPINLOCK_TYPES_H
+
+#if !defined(__LINUX_SPINLOCK_TYPES_H) && !defined(__ASM_SPINLOCK_H)
+# error "please don't include this file directly"
+#endif
+
+/* We only require natural alignment for exclusive accesses. */
+#define __lock_aligned
+
+typedef struct {
+	volatile unsigned int lock;
+} arch_spinlock_t;
+
+#define __ARCH_SPIN_LOCK_UNLOCKED	{ 0 }
+
+typedef struct {
+	volatile unsigned int lock;
+} arch_rwlock_t;
+
+#define __ARCH_RW_LOCK_UNLOCKED		{ 0 }
+
+#endif
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
new file mode 100644
index 0000000..7318f6d
--- /dev/null
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_STACKTRACE_H
+#define __ASM_STACKTRACE_H
+
+struct stackframe {
+	unsigned long fp;
+	unsigned long sp;
+	unsigned long pc;
+};
+
+extern int unwind_frame(struct stackframe *frame);
+extern void walk_stackframe(struct stackframe *frame,
+			    int (*fn)(struct stackframe *, void *), void *data);
+
+#endif	/* __ASM_STACKTRACE_H */
diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
new file mode 100644
index 0000000..d87225c
--- /dev/null
+++ b/arch/arm64/include/asm/stat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_STAT_H
+#define __ASM_STAT_H
+
+#include <asm-generic/stat.h>
+
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+
+#include <asm/compat.h>
+
+/*
+ * struct stat64 is needed for compat tasks only. Its definition is different
+ * from the generic struct stat64.
+ */
+struct stat64 {
+	compat_u64	st_dev;
+	unsigned char   __pad0[4];
+
+#define STAT64_HAS_BROKEN_ST_INO	1
+	compat_ulong_t	__st_ino;
+	compat_uint_t	st_mode;
+	compat_uint_t	st_nlink;
+
+	compat_ulong_t	st_uid;
+	compat_ulong_t	st_gid;
+
+	compat_u64	st_rdev;
+	unsigned char   __pad3[4];
+
+	compat_s64	st_size;
+	compat_ulong_t	st_blksize;
+	compat_u64	st_blocks;	/* Number of 512-byte blocks allocated. */
+
+	compat_ulong_t	st_atime;
+	compat_ulong_t	st_atime_nsec;
+
+	compat_ulong_t	st_mtime;
+	compat_ulong_t	st_mtime_nsec;
+
+	compat_ulong_t	st_ctime;
+	compat_ulong_t	st_ctime_nsec;
+
+	compat_u64	st_ino;
+};
+
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/statfs.h b/arch/arm64/include/asm/statfs.h
new file mode 100644
index 0000000..6f62190
--- /dev/null
+++ b/arch/arm64/include/asm/statfs.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_STATFS_H
+#define __ASM_STATFS_H
+
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
+
+#include <asm-generic/statfs.h>
+
+#endif
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
new file mode 100644
index 0000000..89c047f
--- /dev/null
+++ b/arch/arm64/include/asm/syscall.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SYSCALL_H
+#define __ASM_SYSCALL_H
+
+#include <linux/err.h>
+
+
+static inline int syscall_get_nr(struct task_struct *task,
+				 struct pt_regs *regs)
+{
+	return regs->syscallno;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->regs[0] = regs->orig_x0;
+}
+
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	unsigned long error = regs->regs[0];
+	return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->regs[0];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	regs->regs[0] = (long) error ? error : val;
+}
+
+#define SYSCALL_MAX_ARGS 6
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	if (i + n > SYSCALL_MAX_ARGS) {
+		unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
+		unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
+		pr_warning("%s called with max args %d, handling only %d\n",
+			   __func__, i + n, SYSCALL_MAX_ARGS);
+		memset(args_bad, 0, n_bad * sizeof(args[0]));
+	}
+
+	if (i == 0) {
+		args[0] = regs->orig_x0;
+		args++;
+		i++;
+		n--;
+	}
+
+	memcpy(args, &regs->regs[i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	if (i + n > SYSCALL_MAX_ARGS) {
+		pr_warning("%s called with max args %d, handling only %d\n",
+			   __func__, i + n, SYSCALL_MAX_ARGS);
+		n = SYSCALL_MAX_ARGS - i;
+	}
+
+	if (i == 0) {
+		regs->orig_x0 = args[0];
+		args++;
+		i++;
+		n--;
+	}
+
+	memcpy(&regs->regs[i], args, n * sizeof(args[0]));
+}
+
+#endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h
new file mode 100644
index 0000000..09ff335
--- /dev/null
+++ b/arch/arm64/include/asm/syscalls.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SYSCALLS_H
+#define __ASM_SYSCALLS_H
+
+#include <linux/linkage.h>
+#include <linux/compiler.h>
+#include <linux/signal.h>
+
+/*
+ * System call wrappers implemented in kernel/entry.S.
+ */
+asmlinkage long sys_execve_wrapper(const char __user *filename,
+				   const char __user *const __user *argv,
+				   const char __user *const __user *envp);
+asmlinkage long sys_clone_wrapper(unsigned long clone_flags,
+				  unsigned long newsp,
+				  void __user *parent_tid,
+				  unsigned long tls_val,
+				  void __user *child_tid);
+asmlinkage long sys_rt_sigreturn_wrapper(void);
+asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss,
+					stack_t __user *uoss);
+
+#include <asm-generic/syscalls.h>
+
+#endif	/* __ASM_SYSCALLS_H */
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
new file mode 100644
index 0000000..95e4072
--- /dev/null
+++ b/arch/arm64/include/asm/system_misc.h
@@ -0,0 +1,54 @@
+/*
+ * Based on arch/arm/include/asm/system_misc.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_SYSTEM_MISC_H
+#define __ASM_SYSTEM_MISC_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/irqflags.h>
+
+struct pt_regs;
+
+void die(const char *msg, struct pt_regs *regs, int err);
+
+struct siginfo;
+void arm64_notify_die(const char *str, struct pt_regs *regs,
+		      struct siginfo *info, int err);
+
+void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
+					     struct pt_regs *),
+			   int sig, int code, const char *name);
+
+struct mm_struct;
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
+extern void __show_regs(struct pt_regs *);
+
+void soft_restart(unsigned long);
+extern void (*pm_restart)(const char *cmd);
+
+#define UDBG_UNDEFINED	(1 << 0)
+#define UDBG_SYSCALL	(1 << 1)
+#define UDBG_BADABORT	(1 << 2)
+#define UDBG_SEGV	(1 << 3)
+#define UDBG_BUS	(1 << 4)
+
+#endif	/* __ASSEMBLY__ */
+
+#endif	/* __ASM_SYSTEM_MISC_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
new file mode 100644
index 0000000..3659e46
--- /dev/null
+++ b/arch/arm64/include/asm/thread_info.h
@@ -0,0 +1,127 @@
+/*
+ * Based on arch/arm/include/asm/thread_info.h
+ *
+ * Copyright (C) 2002 Russell King.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_THREAD_INFO_H
+#define __ASM_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#include <linux/compiler.h>
+
+#ifndef CONFIG_ARM64_64K_PAGES
+#define THREAD_SIZE_ORDER	1
+#endif
+
+#define THREAD_SIZE		8192
+#define THREAD_START_SP		(THREAD_SIZE - 16)
+
+#ifndef __ASSEMBLY__
+
+struct task_struct;
+struct exec_domain;
+
+#include <asm/types.h>
+
+typedef unsigned long mm_segment_t;
+
+/*
+ * low level task data that entry.S needs immediate access to.
+ * __switch_to() assumes cpu_context follows immediately after cpu_domain.
+ */
+struct thread_info {
+	unsigned long		flags;		/* low level flags */
+	mm_segment_t		addr_limit;	/* address limit */
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	struct restart_block	restart_block;
+	int			preempt_count;	/* 0 => preemptable, <0 => bug */
+	int			cpu;		/* cpu */
+};
+
+#define INIT_THREAD_INFO(tsk)						\
+{									\
+	.task		= &tsk,						\
+	.exec_domain	= &default_exec_domain,				\
+	.flags		= 0,						\
+	.preempt_count	= INIT_PREEMPT_COUNT,				\
+	.addr_limit	= KERNEL_DS,					\
+	.restart_block	= {						\
+		.fn	= do_no_restart_syscall,			\
+	},								\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/*
+ * how to get the thread information struct from C
+ */
+static inline struct thread_info *current_thread_info(void) __attribute_const__;
+
+static inline struct thread_info *current_thread_info(void)
+{
+	register unsigned long sp asm ("sp");
+	return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
+}
+
+#define thread_saved_pc(tsk)	\
+	((unsigned long)(tsk->thread.cpu_context.pc))
+#define thread_saved_sp(tsk)	\
+	((unsigned long)(tsk->thread.cpu_context.sp))
+#define thread_saved_fp(tsk)	\
+	((unsigned long)(tsk->thread.cpu_context.fp))
+
+#endif
+
+/*
+ * We use bit 30 of the preempt_count to indicate that kernel
+ * preemption is occurring.  See <asm/hardirq.h>.
+ */
+#define PREEMPT_ACTIVE	0x40000000
+
+/*
+ * thread information flags:
+ *  TIF_SYSCALL_TRACE	- syscall trace active
+ *  TIF_SIGPENDING	- signal pending
+ *  TIF_NEED_RESCHED	- rescheduling necessary
+ *  TIF_NOTIFY_RESUME	- callback before returning to user
+ *  TIF_USEDFPU		- FPU was used by this task this quantum (SMP)
+ *  TIF_POLLING_NRFLAG	- true if poll_idle() is polling TIF_NEED_RESCHED
+ */
+#define TIF_SIGPENDING		0
+#define TIF_NEED_RESCHED	1
+#define TIF_NOTIFY_RESUME	2	/* callback before returning to user */
+#define TIF_SYSCALL_TRACE	8
+#define TIF_POLLING_NRFLAG	16
+#define TIF_MEMDIE		18	/* is terminating due to OOM killer */
+#define TIF_FREEZE		19
+#define TIF_RESTORE_SIGMASK	20
+#define TIF_SINGLESTEP		21
+#define TIF_32BIT		22	/* 32bit process */
+#define TIF_SWITCH_MM		23	/* deferred switch_mm */
+
+#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
+#define _TIF_32BIT		(1 << TIF_32BIT)
+
+#define _TIF_WORK_MASK		(_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
+				 _TIF_NOTIFY_RESUME)
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_THREAD_INFO_H */
diff --git a/arch/arm64/include/asm/timex.h b/arch/arm64/include/asm/timex.h
new file mode 100644
index 0000000..b24a31a
--- /dev/null
+++ b/arch/arm64/include/asm/timex.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_TIMEX_H
+#define __ASM_TIMEX_H
+
+/*
+ * Use the current timer as a cycle counter since this is what we use for
+ * the delay loop.
+ */
+#define get_cycles()	({ cycles_t c; read_current_timer(&c); c; })
+
+#include <asm-generic/timex.h>
+
+#define ARCH_HAS_READ_CURRENT_TIMER
+
+#endif
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
new file mode 100644
index 0000000..654f096
--- /dev/null
+++ b/arch/arm64/include/asm/tlb.h
@@ -0,0 +1,190 @@
+/*
+ * Based on arch/arm/include/asm/tlb.h
+ *
+ * Copyright (C) 2002 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_TLB_H
+#define __ASM_TLB_H
+
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#define MMU_GATHER_BUNDLE	8
+
+/*
+ * TLB handling.  This allows us to remove pages from the page
+ * tables, and efficiently handle the TLB issues.
+ */
+struct mmu_gather {
+	struct mm_struct	*mm;
+	unsigned int		fullmm;
+	struct vm_area_struct	*vma;
+	unsigned long		range_start;
+	unsigned long		range_end;
+	unsigned int		nr;
+	unsigned int		max;
+	struct page		**pages;
+	struct page		*local[MMU_GATHER_BUNDLE];
+};
+
+/*
+ * This is unnecessarily complex.  There's three ways the TLB shootdown
+ * code is used:
+ *  1. Unmapping a range of vmas.  See zap_page_range(), unmap_region().
+ *     tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.
+ *  2. Unmapping all vmas.  See exit_mmap().
+ *     tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.  Additionally, page tables will be freed.
+ *  3. Unmapping argument pages.  See shift_arg_pages().
+ *     tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
+ *     tlb->vma will be NULL.
+ */
+static inline void tlb_flush(struct mmu_gather *tlb)
+{
+	if (tlb->fullmm || !tlb->vma)
+		flush_tlb_mm(tlb->mm);
+	else if (tlb->range_end > 0) {
+		flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
+		tlb->range_start = TASK_SIZE;
+		tlb->range_end = 0;
+	}
+}
+
+static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
+{
+	if (!tlb->fullmm) {
+		if (addr < tlb->range_start)
+			tlb->range_start = addr;
+		if (addr + PAGE_SIZE > tlb->range_end)
+			tlb->range_end = addr + PAGE_SIZE;
+	}
+}
+
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
+{
+	unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+
+	if (addr) {
+		tlb->pages = (void *)addr;
+		tlb->max = PAGE_SIZE / sizeof(struct page *);
+	}
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+	tlb_flush(tlb);
+	free_pages_and_swap_cache(tlb->pages, tlb->nr);
+	tlb->nr = 0;
+	if (tlb->pages == tlb->local)
+		__tlb_alloc_page(tlb);
+}
+
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
+{
+	tlb->mm = mm;
+	tlb->fullmm = fullmm;
+	tlb->vma = NULL;
+	tlb->max = ARRAY_SIZE(tlb->local);
+	tlb->pages = tlb->local;
+	tlb->nr = 0;
+	__tlb_alloc_page(tlb);
+}
+
+static inline void
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+	tlb_flush_mmu(tlb);
+
+	/* keep the page table cache within bounds */
+	check_pgt_cache();
+
+	if (tlb->pages != tlb->local)
+		free_pages((unsigned long)tlb->pages, 0);
+}
+
+/*
+ * Memorize the range for the TLB flush.
+ */
+static inline void
+tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
+{
+	tlb_add_flush(tlb, addr);
+}
+
+/*
+ * In the case of tlb vma handling, we can optimise these away in the
+ * case where we're doing a full MM flush.  When we're doing a munmap,
+ * the vmas are adjusted to only cover the region to be torn down.
+ */
+static inline void
+tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+	if (!tlb->fullmm) {
+		tlb->vma = vma;
+		tlb->range_start = TASK_SIZE;
+		tlb->range_end = 0;
+	}
+}
+
+static inline void
+tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+	if (!tlb->fullmm)
+		tlb_flush(tlb);
+}
+
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+	tlb->pages[tlb->nr++] = page;
+	VM_BUG_ON(tlb->nr > tlb->max);
+	return tlb->max - tlb->nr;
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+	if (!__tlb_remove_page(tlb, page))
+		tlb_flush_mmu(tlb);
+}
+
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+	unsigned long addr)
+{
+	pgtable_page_dtor(pte);
+	tlb_add_flush(tlb, addr);
+	tlb_remove_page(tlb, pte);
+}
+
+#ifndef CONFIG_ARM64_64K_PAGES
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
+				  unsigned long addr)
+{
+	tlb_add_flush(tlb, addr);
+	tlb_remove_page(tlb, virt_to_page(pmdp));
+}
+#endif
+
+#define pte_free_tlb(tlb, ptep, addr)	__pte_free_tlb(tlb, ptep, addr)
+#define pmd_free_tlb(tlb, pmdp, addr)	__pmd_free_tlb(tlb, pmdp, addr)
+#define pud_free_tlb(tlb, pudp, addr)	pud_free((tlb)->mm, pudp)
+
+#define tlb_migrate_finish(mm)		do { } while (0)
+
+#endif
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
new file mode 100644
index 0000000..122d632
--- /dev/null
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -0,0 +1,122 @@
+/*
+ * Based on arch/arm/include/asm/tlbflush.h
+ *
+ * Copyright (C) 1999-2003 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_TLBFLUSH_H
+#define __ASM_TLBFLUSH_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <asm/cputype.h>
+
+extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
+extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
+
+extern struct cpu_tlb_fns cpu_tlb;
+
+/*
+ *	TLB Management
+ *	==============
+ *
+ *	The arch/arm64/mm/tlb.S files implement these methods.
+ *
+ *	The TLB specific code is expected to perform whatever tests it needs
+ *	to determine if it should invalidate the TLB for each call.  Start
+ *	addresses are inclusive and end addresses are exclusive; it is safe to
+ *	round these addresses down.
+ *
+ *	flush_tlb_all()
+ *
+ *		Invalidate the entire TLB.
+ *
+ *	flush_tlb_mm(mm)
+ *
+ *		Invalidate all TLB entries in a particular address space.
+ *		- mm	- mm_struct describing address space
+ *
+ *	flush_tlb_range(mm,start,end)
+ *
+ *		Invalidate a range of TLB entries in the specified address
+ *		space.
+ *		- mm	- mm_struct describing address space
+ *		- start - start address (may not be aligned)
+ *		- end	- end address (exclusive, may not be aligned)
+ *
+ *	flush_tlb_page(vaddr,vma)
+ *
+ *		Invalidate the specified page in the specified address range.
+ *		- vaddr - virtual address (may not be aligned)
+ *		- vma	- vma_struct describing address range
+ *
+ *	flush_kern_tlb_page(kaddr)
+ *
+ *		Invalidate the TLB entry for the specified page.  The address
+ *		will be in the kernels virtual memory space.  Current uses
+ *		only require the D-TLB to be invalidated.
+ *		- kaddr - Kernel virtual memory address
+ */
+static inline void flush_tlb_all(void)
+{
+	dsb();
+	asm("tlbi	vmalle1is");
+	dsb();
+	isb();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	unsigned long asid = (unsigned long)ASID(mm) << 48;
+
+	dsb();
+	asm("tlbi	aside1is, %0" : : "r" (asid));
+	dsb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long uaddr)
+{
+	unsigned long addr = uaddr >> 12 |
+		((unsigned long)ASID(vma->vm_mm) << 48);
+
+	dsb();
+	asm("tlbi	vae1is, %0" : : "r" (addr));
+	dsb();
+}
+
+/*
+ * Convert calls to our calling convention.
+ */
+#define flush_tlb_range(vma,start,end)	__cpu_flush_user_tlb_range(start,end,vma)
+#define flush_tlb_kernel_range(s,e)	__cpu_flush_kern_tlb_range(s,e)
+
+/*
+ * On AArch64, the cache coherency is handled via the set_pte_at() function.
+ */
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+				    unsigned long addr, pte_t *ptep)
+{
+	/*
+	 * set_pte() does not have a DSB, so make sure that the page table
+	 * write is visible.
+	 */
+	dsb();
+}
+
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
new file mode 100644
index 0000000..10ca8ff
--- /dev/null
+++ b/arch/arm64/include/asm/traps.h
@@ -0,0 +1,30 @@
+/*
+ * Based on arch/arm/include/asm/traps.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_TRAP_H
+#define __ASM_TRAP_H
+
+static inline int in_exception_text(unsigned long ptr)
+{
+	extern char __exception_text_start[];
+	extern char __exception_text_end[];
+
+	return ptr >= (unsigned long)&__exception_text_start &&
+	       ptr < (unsigned long)&__exception_text_end;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
new file mode 100644
index 0000000..008f848
--- /dev/null
+++ b/arch/arm64/include/asm/uaccess.h
@@ -0,0 +1,297 @@
+/*
+ * Based on arch/arm/include/asm/uaccess.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_UACCESS_H
+#define __ASM_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/string.h>
+#include <linux/thread_info.h>
+
+#include <asm/ptrace.h>
+#include <asm/errno.h>
+#include <asm/memory.h>
+#include <asm/compiler.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+#define KERNEL_DS	(-1UL)
+#define get_ds()	(KERNEL_DS)
+
+#define USER_DS		TASK_SIZE_64
+#define get_fs()	(current_thread_info()->addr_limit)
+
+static inline void set_fs(mm_segment_t fs)
+{
+	current_thread_info()->addr_limit = fs;
+}
+
+#define segment_eq(a,b)	((a) == (b))
+
+/*
+ * Return 1 if addr < current->addr_limit, 0 otherwise.
+ */
+#define __addr_ok(addr)							\
+({									\
+	unsigned long flag;						\
+	asm("cmp %1, %0; cset %0, lo"					\
+		: "=&r" (flag)						\
+		: "r" (addr), "0" (current_thread_info()->addr_limit)	\
+		: "cc");						\
+	flag;								\
+})
+
+/*
+ * Test whether a block of memory is a valid user space address.
+ * Returns 1 if the range is valid, 0 otherwise.
+ *
+ * This is equivalent to the following test:
+ * (u65)addr + (u65)size < (u65)current->addr_limit
+ *
+ * This needs 65-bit arithmetic.
+ */
+#define __range_ok(addr, size)						\
+({									\
+	unsigned long flag, roksum;					\
+	__chk_user_ptr(addr);						\
+	asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, cc"		\
+		: "=&r" (flag), "=&r" (roksum)				\
+		: "1" (addr), "Ir" (size),				\
+		  "r" (current_thread_info()->addr_limit)		\
+		: "cc");						\
+	flag;								\
+})
+
+#define access_ok(type, addr, size)	__range_ok(addr, size)
+
+/*
+ * The "__xxx" versions of the user access functions do not verify the address
+ * space - it must have been done previously with a separate "access_ok()"
+ * call.
+ *
+ * The "__xxx_error" versions set the third argument to -EFAULT if an error
+ * occurs, and leave it unchanged on success.
+ */
+#define __get_user_asm(instr, reg, x, addr, err)			\
+	asm volatile(							\
+	"1:	" instr "	" reg "1, [%2]\n"			\
+	"2:\n"								\
+	"	.section .fixup, \"ax\"\n"				\
+	"	.align	2\n"						\
+	"3:	mov	%w0, %3\n"					\
+	"	mov	%1, #0\n"					\
+	"	b	2b\n"						\
+	"	.previous\n"						\
+	"	.section __ex_table,\"a\"\n"				\
+	"	.align	3\n"						\
+	"	.quad	1b, 3b\n"					\
+	"	.previous"						\
+	: "+r" (err), "=&r" (x)						\
+	: "r" (addr), "i" (-EFAULT))
+
+#define __get_user_err(x, ptr, err)					\
+do {									\
+	unsigned long __gu_val;						\
+	__chk_user_ptr(ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		__get_user_asm("ldrb", "%w", __gu_val, (ptr), (err));	\
+		break;							\
+	case 2:								\
+		__get_user_asm("ldrh", "%w", __gu_val, (ptr), (err));	\
+		break;							\
+	case 4:								\
+		__get_user_asm("ldr", "%w", __gu_val, (ptr), (err));	\
+		break;							\
+	case 8:								\
+		__get_user_asm("ldr", "%",  __gu_val, (ptr), (err));	\
+		break;							\
+	default:							\
+		BUILD_BUG();						\
+	}								\
+	(x) = (__typeof__(*(ptr)))__gu_val;				\
+} while (0)
+
+#define __get_user(x, ptr)						\
+({									\
+	int __gu_err = 0;						\
+	__get_user_err((x), (ptr), __gu_err);				\
+	__gu_err;							\
+})
+
+#define __get_user_error(x, ptr, err)					\
+({									\
+	__get_user_err((x), (ptr), (err));				\
+	(void)0;							\
+})
+
+#define __get_user_unaligned __get_user
+
+#define get_user(x, ptr)						\
+({									\
+	might_sleep();							\
+	access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) ?			\
+		__get_user((x), (ptr)) :				\
+		((x) = 0, -EFAULT);					\
+})
+
+#define __put_user_asm(instr, reg, x, addr, err)			\
+	asm volatile(							\
+	"1:	" instr "	" reg "1, [%2]\n"			\
+	"2:\n"								\
+	"	.section .fixup,\"ax\"\n"				\
+	"	.align	2\n"						\
+	"3:	mov	%w0, %3\n"					\
+	"	b	2b\n"						\
+	"	.previous\n"						\
+	"	.section __ex_table,\"a\"\n"				\
+	"	.align	3\n"						\
+	"	.quad	1b, 3b\n"					\
+	"	.previous"						\
+	: "+r" (err)							\
+	: "r" (x), "r" (addr), "i" (-EFAULT))
+
+#define __put_user_err(x, ptr, err)					\
+do {									\
+	__typeof__(*(ptr)) __pu_val = (x);				\
+	__chk_user_ptr(ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		__put_user_asm("strb", "%w", __pu_val, (ptr), (err));	\
+		break;							\
+	case 2:								\
+		__put_user_asm("strh", "%w", __pu_val, (ptr), (err));	\
+		break;							\
+	case 4:								\
+		__put_user_asm("str",  "%w", __pu_val, (ptr), (err));	\
+		break;							\
+	case 8:								\
+		__put_user_asm("str",  "%", __pu_val, (ptr), (err));	\
+		break;							\
+	default:							\
+		BUILD_BUG();						\
+	}								\
+} while (0)
+
+#define __put_user(x, ptr)						\
+({									\
+	int __pu_err = 0;						\
+	__put_user_err((x), (ptr), __pu_err);				\
+	__pu_err;							\
+})
+
+#define __put_user_error(x, ptr, err)					\
+({									\
+	__put_user_err((x), (ptr), (err));				\
+	(void)0;							\
+})
+
+#define __put_user_unaligned __put_user
+
+#define put_user(x, ptr)						\
+({									\
+	might_sleep();							\
+	access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ?		\
+		__put_user((x), (ptr)) :				\
+		-EFAULT;						\
+})
+
+extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
+extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
+extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+
+extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count);
+extern unsigned long __must_check __strnlen_user(const char __user *s, long n);
+
+static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n))
+		n = __copy_from_user(to, from, n);
+	else /* security hole - plug it */
+		memset(to, 0, n);
+	return n;
+}
+
+static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+		n = __copy_to_user(to, from, n);
+	return n;
+}
+
+static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))
+		n = __copy_in_user(to, from, n);
+	return n;
+}
+
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+		n = __clear_user(to, n);
+	return n;
+}
+
+static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count)
+{
+	long res = -EFAULT;
+	if (access_ok(VERIFY_READ, src, 1))
+		res = __strncpy_from_user(dst, src, count);
+	return res;
+}
+
+#define strlen_user(s)	strnlen_user(s, ~0UL >> 1)
+
+static inline long __must_check strnlen_user(const char __user *s, long n)
+{
+	unsigned long res = 0;
+
+	if (__addr_ok(s))
+		res = __strnlen_user(s, n);
+
+	return res;
+}
+
+#endif /* __ASM_UACCESS_H */
diff --git a/arch/arm64/include/asm/ucontext.h b/arch/arm64/include/asm/ucontext.h
new file mode 100644
index 0000000..bde9607
--- /dev/null
+++ b/arch/arm64/include/asm/ucontext.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_UCONTEXT_H
+#define __ASM_UCONTEXT_H
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext	 *uc_link;
+	stack_t		  uc_stack;
+	sigset_t	  uc_sigmask;
+	/* glibc uses a 1024-bit sigset_t */
+	__u8		  __unused[(1024 - sizeof(sigset_t)) / 8];
+	/* last for future expansion */
+	struct sigcontext uc_mcontext;
+};
+
+#endif /* __ASM_UCONTEXT_H */
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
new file mode 100644
index 0000000..fe18a68
--- /dev/null
+++ b/arch/arm64/include/asm/unistd.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined(__ASM_UNISTD_H) || defined(__SYSCALL)
+#define __ASM_UNISTD_H
+
+#ifndef __SYSCALL_COMPAT
+#include <asm-generic/unistd.h>
+#endif
+
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+#include <asm/unistd32.h>
+#endif
+
+#endif /* __ASM_UNISTD_H */
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
new file mode 100644
index 0000000..a50405f
--- /dev/null
+++ b/arch/arm64/include/asm/unistd32.h
@@ -0,0 +1,758 @@
+/*
+ * Based on arch/arm/include/asm/unistd.h
+ *
+ * Copyright (C) 2001-2005 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined(__ASM_UNISTD32_H) || defined(__SYSCALL)
+#define __ASM_UNISTD32_H
+
+#ifndef __SYSCALL
+#define __SYSCALL(x, y)
+#endif
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#ifdef __SYSCALL_COMPAT
+
+#define __NR_restart_syscall		0
+__SYSCALL(__NR_restart_syscall, sys_restart_syscall)
+#define __NR_exit			1
+__SYSCALL(__NR_exit, sys_exit)
+#define __NR_fork			2
+__SYSCALL(__NR_fork, sys_fork)
+#define __NR_read			3
+__SYSCALL(__NR_read, sys_read)
+#define __NR_write			4
+__SYSCALL(__NR_write, sys_write)
+#define __NR_open			5
+__SYSCALL(__NR_open, sys_open)
+#define __NR_close			6
+__SYSCALL(__NR_close, sys_close)
+__SYSCALL(7, sys_ni_syscall)		/* 7 was sys_waitpid */
+#define __NR_creat			8
+__SYSCALL(__NR_creat, sys_creat)
+#define __NR_link			9
+__SYSCALL(__NR_link, sys_link)
+#define __NR_unlink			10
+__SYSCALL(__NR_unlink, sys_unlink)
+#define __NR_execve			11
+__SYSCALL(__NR_execve, sys_execve)
+#define __NR_chdir			12
+__SYSCALL(__NR_chdir, sys_chdir)
+__SYSCALL(13, sys_ni_syscall)		/* 13 was sys_time */
+#define __NR_mknod			14
+__SYSCALL(__NR_mknod, sys_mknod)
+#define __NR_chmod			15
+__SYSCALL(__NR_chmod, sys_chmod)
+#define __NR_lchown			16
+__SYSCALL(__NR_lchown, sys_lchown16)
+__SYSCALL(17, sys_ni_syscall)		/* 17 was sys_break */
+__SYSCALL(18, sys_ni_syscall)		/* 18 was sys_stat */
+#define __NR_lseek			19
+__SYSCALL(__NR_lseek, sys_lseek)
+#define __NR_getpid			20
+__SYSCALL(__NR_getpid, sys_getpid)
+#define __NR_mount			21
+__SYSCALL(__NR_mount, sys_mount)
+__SYSCALL(22, sys_ni_syscall)		/* 22 was sys_umount */
+#define __NR_setuid			23
+__SYSCALL(__NR_setuid, sys_setuid16)
+#define __NR_getuid			24
+__SYSCALL(__NR_getuid, sys_getuid16)
+__SYSCALL(25, sys_ni_syscall)		/* 25 was sys_stime */
+#define __NR_ptrace			26
+__SYSCALL(__NR_ptrace, sys_ptrace)
+__SYSCALL(27, sys_ni_syscall)		/* 27 was sys_alarm */
+__SYSCALL(28, sys_ni_syscall)		/* 28 was sys_fstat */
+#define __NR_pause			29
+__SYSCALL(__NR_pause, sys_pause)
+__SYSCALL(30, sys_ni_syscall)		/* 30 was sys_utime */
+__SYSCALL(31, sys_ni_syscall)		/* 31 was sys_stty */
+__SYSCALL(32, sys_ni_syscall)		/* 32 was sys_gtty */
+#define __NR_access			33
+__SYSCALL(__NR_access, sys_access)
+#define __NR_nice			34
+__SYSCALL(__NR_nice, sys_nice)
+__SYSCALL(35, sys_ni_syscall)		/* 35 was sys_ftime */
+#define __NR_sync			36
+__SYSCALL(__NR_sync, sys_sync)
+#define __NR_kill			37
+__SYSCALL(__NR_kill, sys_kill)
+#define __NR_rename			38
+__SYSCALL(__NR_rename, sys_rename)
+#define __NR_mkdir			39
+__SYSCALL(__NR_mkdir, sys_mkdir)
+#define __NR_rmdir			40
+__SYSCALL(__NR_rmdir, sys_rmdir)
+#define __NR_dup			41
+__SYSCALL(__NR_dup, sys_dup)
+#define __NR_pipe			42
+__SYSCALL(__NR_pipe, sys_pipe)
+#define __NR_times			43
+__SYSCALL(__NR_times, sys_times)
+__SYSCALL(44, sys_ni_syscall)		/* 44 was sys_prof */
+#define __NR_brk			45
+__SYSCALL(__NR_brk, sys_brk)
+#define __NR_setgid			46
+__SYSCALL(__NR_setgid, sys_setgid16)
+#define __NR_getgid			47
+__SYSCALL(__NR_getgid, sys_getgid16)
+__SYSCALL(48, sys_ni_syscall)		/* 48 was sys_signal */
+#define __NR_geteuid			49
+__SYSCALL(__NR_geteuid, sys_geteuid16)
+#define __NR_getegid			50
+__SYSCALL(__NR_getegid, sys_getegid16)
+#define __NR_acct			51
+__SYSCALL(__NR_acct, sys_acct)
+#define __NR_umount2			52
+__SYSCALL(__NR_umount2, sys_umount)
+__SYSCALL(53, sys_ni_syscall)		/* 53 was sys_lock */
+#define __NR_ioctl			54
+__SYSCALL(__NR_ioctl, sys_ioctl)
+#define __NR_fcntl			55
+__SYSCALL(__NR_fcntl, sys_fcntl)
+__SYSCALL(56, sys_ni_syscall)		/* 56 was sys_mpx */
+#define __NR_setpgid			57
+__SYSCALL(__NR_setpgid, sys_setpgid)
+__SYSCALL(58, sys_ni_syscall)		/* 58 was sys_ulimit */
+__SYSCALL(59, sys_ni_syscall)		/* 59 was sys_olduname */
+#define __NR_umask			60
+__SYSCALL(__NR_umask, sys_umask)
+#define __NR_chroot			61
+__SYSCALL(__NR_chroot, sys_chroot)
+#define __NR_ustat			62
+__SYSCALL(__NR_ustat, sys_ustat)
+#define __NR_dup2			63
+__SYSCALL(__NR_dup2, sys_dup2)
+#define __NR_getppid			64
+__SYSCALL(__NR_getppid, sys_getppid)
+#define __NR_getpgrp			65
+__SYSCALL(__NR_getpgrp, sys_getpgrp)
+#define __NR_setsid			66
+__SYSCALL(__NR_setsid, sys_setsid)
+#define __NR_sigaction			67
+__SYSCALL(__NR_sigaction, sys_sigaction)
+__SYSCALL(68, sys_ni_syscall)		/* 68 was sys_sgetmask */
+__SYSCALL(69, sys_ni_syscall)		/* 69 was sys_ssetmask */
+#define __NR_setreuid			70
+__SYSCALL(__NR_setreuid, sys_setreuid16)
+#define __NR_setregid			71
+__SYSCALL(__NR_setregid, sys_setregid16)
+#define __NR_sigsuspend			72
+__SYSCALL(__NR_sigsuspend, sys_sigsuspend)
+#define __NR_sigpending			73
+__SYSCALL(__NR_sigpending, sys_sigpending)
+#define __NR_sethostname		74
+__SYSCALL(__NR_sethostname, sys_sethostname)
+#define __NR_setrlimit			75
+__SYSCALL(__NR_setrlimit, sys_setrlimit)
+__SYSCALL(76, sys_ni_syscall)		/* 76 was sys_getrlimit */
+#define __NR_getrusage			77
+__SYSCALL(__NR_getrusage, sys_getrusage)
+#define __NR_gettimeofday		78
+__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+#define __NR_settimeofday		79
+__SYSCALL(__NR_settimeofday, sys_settimeofday)
+#define __NR_getgroups			80
+__SYSCALL(__NR_getgroups, sys_getgroups16)
+#define __NR_setgroups			81
+__SYSCALL(__NR_setgroups, sys_setgroups16)
+__SYSCALL(82, sys_ni_syscall)		/* 82 was sys_select */
+#define __NR_symlink			83
+__SYSCALL(__NR_symlink, sys_symlink)
+__SYSCALL(84, sys_ni_syscall)		/* 84 was sys_lstat */
+#define __NR_readlink			85
+__SYSCALL(__NR_readlink, sys_readlink)
+#define __NR_uselib			86
+__SYSCALL(__NR_uselib, sys_uselib)
+#define __NR_swapon			87
+__SYSCALL(__NR_swapon, sys_swapon)
+#define __NR_reboot			88
+__SYSCALL(__NR_reboot, sys_reboot)
+__SYSCALL(89, sys_ni_syscall)		/* 89 was sys_readdir */
+__SYSCALL(90, sys_ni_syscall)		/* 90 was sys_mmap */
+#define __NR_munmap			91
+__SYSCALL(__NR_munmap, sys_munmap)
+#define __NR_truncate			92
+__SYSCALL(__NR_truncate, sys_truncate)
+#define __NR_ftruncate			93
+__SYSCALL(__NR_ftruncate, sys_ftruncate)
+#define __NR_fchmod			94
+__SYSCALL(__NR_fchmod, sys_fchmod)
+#define __NR_fchown			95
+__SYSCALL(__NR_fchown, sys_fchown16)
+#define __NR_getpriority		96
+__SYSCALL(__NR_getpriority, sys_getpriority)
+#define __NR_setpriority		97
+__SYSCALL(__NR_setpriority, sys_setpriority)
+__SYSCALL(98, sys_ni_syscall)		/* 98 was sys_profil */
+#define __NR_statfs			99
+__SYSCALL(__NR_statfs, sys_statfs)
+#define __NR_fstatfs			100
+__SYSCALL(__NR_fstatfs, sys_fstatfs)
+__SYSCALL(101, sys_ni_syscall)		/* 101 was sys_ioperm */
+__SYSCALL(102, sys_ni_syscall)		/* 102 was sys_socketcall */
+#define __NR_syslog			103
+__SYSCALL(__NR_syslog, sys_syslog)
+#define __NR_setitimer			104
+__SYSCALL(__NR_setitimer, sys_setitimer)
+#define __NR_getitimer			105
+__SYSCALL(__NR_getitimer, sys_getitimer)
+#define __NR_stat			106
+__SYSCALL(__NR_stat, sys_newstat)
+#define __NR_lstat			107
+__SYSCALL(__NR_lstat, sys_newlstat)
+#define __NR_fstat			108
+__SYSCALL(__NR_fstat, sys_newfstat)
+__SYSCALL(109, sys_ni_syscall)		/* 109 was sys_uname */
+__SYSCALL(110, sys_ni_syscall)		/* 110 was sys_iopl */
+#define __NR_vhangup			111
+__SYSCALL(__NR_vhangup, sys_vhangup)
+__SYSCALL(112, sys_ni_syscall)		/* 112 was sys_idle */
+__SYSCALL(113, sys_ni_syscall)		/* 113 was sys_syscall */
+#define __NR_wait4			114
+__SYSCALL(__NR_wait4, sys_wait4)
+#define __NR_swapoff			115
+__SYSCALL(__NR_swapoff, sys_swapoff)
+#define __NR_sysinfo			116
+__SYSCALL(__NR_sysinfo, sys_sysinfo)
+__SYSCALL(117, sys_ni_syscall)		/* 117 was sys_ipc */
+#define __NR_fsync			118
+__SYSCALL(__NR_fsync, sys_fsync)
+#define __NR_sigreturn			119
+__SYSCALL(__NR_sigreturn, sys_sigreturn)
+#define __NR_clone			120
+__SYSCALL(__NR_clone, sys_clone)
+#define __NR_setdomainname		121
+__SYSCALL(__NR_setdomainname, sys_setdomainname)
+#define __NR_uname			122
+__SYSCALL(__NR_uname, sys_newuname)
+__SYSCALL(123, sys_ni_syscall)		/* 123 was sys_modify_ldt */
+#define __NR_adjtimex			124
+__SYSCALL(__NR_adjtimex, sys_adjtimex)
+#define __NR_mprotect			125
+__SYSCALL(__NR_mprotect, sys_mprotect)
+#define __NR_sigprocmask		126
+__SYSCALL(__NR_sigprocmask, sys_sigprocmask)
+__SYSCALL(127, sys_ni_syscall)		/* 127 was sys_create_module */
+#define __NR_init_module		128
+__SYSCALL(__NR_init_module, sys_init_module)
+#define __NR_delete_module		129
+__SYSCALL(__NR_delete_module, sys_delete_module)
+__SYSCALL(130, sys_ni_syscall)		/* 130 was sys_get_kernel_syms */
+#define __NR_quotactl			131
+__SYSCALL(__NR_quotactl, sys_quotactl)
+#define __NR_getpgid			132
+__SYSCALL(__NR_getpgid, sys_getpgid)
+#define __NR_fchdir			133
+__SYSCALL(__NR_fchdir, sys_fchdir)
+#define __NR_bdflush			134
+__SYSCALL(__NR_bdflush, sys_bdflush)
+#define __NR_sysfs			135
+__SYSCALL(__NR_sysfs, sys_sysfs)
+#define __NR_personality		136
+__SYSCALL(__NR_personality, sys_personality)
+__SYSCALL(137, sys_ni_syscall)		/* 137 was sys_afs_syscall */
+#define __NR_setfsuid			138
+__SYSCALL(__NR_setfsuid, sys_setfsuid16)
+#define __NR_setfsgid			139
+__SYSCALL(__NR_setfsgid, sys_setfsgid16)
+#define __NR__llseek			140
+__SYSCALL(__NR__llseek, sys_llseek)
+#define __NR_getdents			141
+__SYSCALL(__NR_getdents, sys_getdents)
+#define __NR__newselect			142
+__SYSCALL(__NR__newselect, sys_select)
+#define __NR_flock			143
+__SYSCALL(__NR_flock, sys_flock)
+#define __NR_msync			144
+__SYSCALL(__NR_msync, sys_msync)
+#define __NR_readv			145
+__SYSCALL(__NR_readv, sys_readv)
+#define __NR_writev			146
+__SYSCALL(__NR_writev, sys_writev)
+#define __NR_getsid			147
+__SYSCALL(__NR_getsid, sys_getsid)
+#define __NR_fdatasync			148
+__SYSCALL(__NR_fdatasync, sys_fdatasync)
+#define __NR__sysctl			149
+__SYSCALL(__NR__sysctl, sys_sysctl)
+#define __NR_mlock			150
+__SYSCALL(__NR_mlock, sys_mlock)
+#define __NR_munlock			151
+__SYSCALL(__NR_munlock, sys_munlock)
+#define __NR_mlockall			152
+__SYSCALL(__NR_mlockall, sys_mlockall)
+#define __NR_munlockall			153
+__SYSCALL(__NR_munlockall, sys_munlockall)
+#define __NR_sched_setparam		154
+__SYSCALL(__NR_sched_setparam, sys_sched_setparam)
+#define __NR_sched_getparam		155
+__SYSCALL(__NR_sched_getparam, sys_sched_getparam)
+#define __NR_sched_setscheduler		156
+__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler)
+#define __NR_sched_getscheduler		157
+__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
+#define __NR_sched_yield		158
+__SYSCALL(__NR_sched_yield, sys_sched_yield)
+#define __NR_sched_get_priority_max	159
+__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
+#define __NR_sched_get_priority_min	160
+__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
+#define __NR_sched_rr_get_interval	161
+__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+#define __NR_nanosleep			162
+__SYSCALL(__NR_nanosleep, sys_nanosleep)
+#define __NR_mremap			163
+__SYSCALL(__NR_mremap, sys_mremap)
+#define __NR_setresuid			164
+__SYSCALL(__NR_setresuid, sys_setresuid16)
+#define __NR_getresuid			165
+__SYSCALL(__NR_getresuid, sys_getresuid16)
+__SYSCALL(166, sys_ni_syscall)		/* 166 was sys_vm86 */
+__SYSCALL(167, sys_ni_syscall)		/* 167 was sys_query_module */
+#define __NR_poll			168
+__SYSCALL(__NR_poll, sys_poll)
+#define __NR_nfsservctl			169
+__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
+#define __NR_setresgid			170
+__SYSCALL(__NR_setresgid, sys_setresgid16)
+#define __NR_getresgid			171
+__SYSCALL(__NR_getresgid, sys_getresgid16)
+#define __NR_prctl			172
+__SYSCALL(__NR_prctl, sys_prctl)
+#define __NR_rt_sigreturn		173
+__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn)
+#define __NR_rt_sigaction		174
+__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction)
+#define __NR_rt_sigprocmask		175
+__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
+#define __NR_rt_sigpending		176
+__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
+#define __NR_rt_sigtimedwait		177
+__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+#define __NR_rt_sigqueueinfo		178
+__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+#define __NR_rt_sigsuspend		179
+__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend)
+#define __NR_pread64			180
+__SYSCALL(__NR_pread64, sys_pread64)
+#define __NR_pwrite64			181
+__SYSCALL(__NR_pwrite64, sys_pwrite64)
+#define __NR_chown			182
+__SYSCALL(__NR_chown, sys_chown16)
+#define __NR_getcwd			183
+__SYSCALL(__NR_getcwd, sys_getcwd)
+#define __NR_capget			184
+__SYSCALL(__NR_capget, sys_capget)
+#define __NR_capset			185
+__SYSCALL(__NR_capset, sys_capset)
+#define __NR_sigaltstack		186
+__SYSCALL(__NR_sigaltstack, sys_sigaltstack)
+#define __NR_sendfile			187
+__SYSCALL(__NR_sendfile, sys_sendfile)
+__SYSCALL(188, sys_ni_syscall)		/* 188 reserved */
+__SYSCALL(189, sys_ni_syscall)		/* 189 reserved */
+#define __NR_vfork			190
+__SYSCALL(__NR_vfork, sys_vfork)
+#define __NR_ugetrlimit			191	/* SuS compliant getrlimit */
+__SYSCALL(__NR_ugetrlimit, sys_getrlimit)
+#define __NR_mmap2			192
+__SYSCALL(__NR_mmap2, sys_mmap2)
+#define __NR_truncate64			193
+__SYSCALL(__NR_truncate64, sys_truncate64)
+#define __NR_ftruncate64		194
+__SYSCALL(__NR_ftruncate64, sys_ftruncate64)
+#define __NR_stat64			195
+__SYSCALL(__NR_stat64, sys_stat64)
+#define __NR_lstat64			196
+__SYSCALL(__NR_lstat64, sys_lstat64)
+#define __NR_fstat64			197
+__SYSCALL(__NR_fstat64, sys_fstat64)
+#define __NR_lchown32			198
+__SYSCALL(__NR_lchown32, sys_lchown)
+#define __NR_getuid32			199
+__SYSCALL(__NR_getuid32, sys_getuid)
+#define __NR_getgid32			200
+__SYSCALL(__NR_getgid32, sys_getgid)
+#define __NR_geteuid32			201
+__SYSCALL(__NR_geteuid32, sys_geteuid)
+#define __NR_getegid32			202
+__SYSCALL(__NR_getegid32, sys_getegid)
+#define __NR_setreuid32			203
+__SYSCALL(__NR_setreuid32, sys_setreuid)
+#define __NR_setregid32			204
+__SYSCALL(__NR_setregid32, sys_setregid)
+#define __NR_getgroups32		205
+__SYSCALL(__NR_getgroups32, sys_getgroups)
+#define __NR_setgroups32		206
+__SYSCALL(__NR_setgroups32, sys_setgroups)
+#define __NR_fchown32			207
+__SYSCALL(__NR_fchown32, sys_fchown)
+#define __NR_setresuid32		208
+__SYSCALL(__NR_setresuid32, sys_setresuid)
+#define __NR_getresuid32		209
+__SYSCALL(__NR_getresuid32, sys_getresuid)
+#define __NR_setresgid32		210
+__SYSCALL(__NR_setresgid32, sys_setresgid)
+#define __NR_getresgid32		211
+__SYSCALL(__NR_getresgid32, sys_getresgid)
+#define __NR_chown32			212
+__SYSCALL(__NR_chown32, sys_chown)
+#define __NR_setuid32			213
+__SYSCALL(__NR_setuid32, sys_setuid)
+#define __NR_setgid32			214
+__SYSCALL(__NR_setgid32, sys_setgid)
+#define __NR_setfsuid32			215
+__SYSCALL(__NR_setfsuid32, sys_setfsuid)
+#define __NR_setfsgid32			216
+__SYSCALL(__NR_setfsgid32, sys_setfsgid)
+#define __NR_getdents64			217
+__SYSCALL(__NR_getdents64, sys_getdents64)
+#define __NR_pivot_root			218
+__SYSCALL(__NR_pivot_root, sys_pivot_root)
+#define __NR_mincore			219
+__SYSCALL(__NR_mincore, sys_mincore)
+#define __NR_madvise			220
+__SYSCALL(__NR_madvise, sys_madvise)
+#define __NR_fcntl64			221
+__SYSCALL(__NR_fcntl64, sys_fcntl64)
+__SYSCALL(222, sys_ni_syscall)		/* 222 for tux */
+__SYSCALL(223, sys_ni_syscall)		/* 223 is unused */
+#define __NR_gettid			224
+__SYSCALL(__NR_gettid, sys_gettid)
+#define __NR_readahead			225
+__SYSCALL(__NR_readahead, sys_readahead)
+#define __NR_setxattr			226
+__SYSCALL(__NR_setxattr, sys_setxattr)
+#define __NR_lsetxattr			227
+__SYSCALL(__NR_lsetxattr, sys_lsetxattr)
+#define __NR_fsetxattr			228
+__SYSCALL(__NR_fsetxattr, sys_fsetxattr)
+#define __NR_getxattr			229
+__SYSCALL(__NR_getxattr, sys_getxattr)
+#define __NR_lgetxattr			230
+__SYSCALL(__NR_lgetxattr, sys_lgetxattr)
+#define __NR_fgetxattr			231
+__SYSCALL(__NR_fgetxattr, sys_fgetxattr)
+#define __NR_listxattr			232
+__SYSCALL(__NR_listxattr, sys_listxattr)
+#define __NR_llistxattr			233
+__SYSCALL(__NR_llistxattr, sys_llistxattr)
+#define __NR_flistxattr			234
+__SYSCALL(__NR_flistxattr, sys_flistxattr)
+#define __NR_removexattr		235
+__SYSCALL(__NR_removexattr, sys_removexattr)
+#define __NR_lremovexattr		236
+__SYSCALL(__NR_lremovexattr, sys_lremovexattr)
+#define __NR_fremovexattr		237
+__SYSCALL(__NR_fremovexattr, sys_fremovexattr)
+#define __NR_tkill			238
+__SYSCALL(__NR_tkill, sys_tkill)
+#define __NR_sendfile64			239
+__SYSCALL(__NR_sendfile64, sys_sendfile64)
+#define __NR_futex			240
+__SYSCALL(__NR_futex, sys_futex)
+#define __NR_sched_setaffinity		241
+__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
+#define __NR_sched_getaffinity		242
+__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+#define __NR_io_setup			243
+__SYSCALL(__NR_io_setup, sys_io_setup)
+#define __NR_io_destroy			244
+__SYSCALL(__NR_io_destroy, sys_io_destroy)
+#define __NR_io_getevents		245
+__SYSCALL(__NR_io_getevents, sys_io_getevents)
+#define __NR_io_submit			246
+__SYSCALL(__NR_io_submit, sys_io_submit)
+#define __NR_io_cancel			247
+__SYSCALL(__NR_io_cancel, sys_io_cancel)
+#define __NR_exit_group			248
+__SYSCALL(__NR_exit_group, sys_exit_group)
+#define __NR_lookup_dcookie		249
+__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
+#define __NR_epoll_create		250
+__SYSCALL(__NR_epoll_create, sys_epoll_create)
+#define __NR_epoll_ctl			251
+__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
+#define __NR_epoll_wait			252
+__SYSCALL(__NR_epoll_wait, sys_epoll_wait)
+#define __NR_remap_file_pages		253
+__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
+__SYSCALL(254, sys_ni_syscall)		/* 254 for set_thread_area */
+__SYSCALL(255, sys_ni_syscall)		/* 255 for get_thread_area */
+#define __NR_set_tid_address		256
+__SYSCALL(__NR_set_tid_address, sys_set_tid_address)
+#define __NR_timer_create		257
+__SYSCALL(__NR_timer_create, sys_timer_create)
+#define __NR_timer_settime		258
+__SYSCALL(__NR_timer_settime, sys_timer_settime)
+#define __NR_timer_gettime		259
+__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
+#define __NR_timer_getoverrun		260
+__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
+#define __NR_timer_delete		261
+__SYSCALL(__NR_timer_delete, sys_timer_delete)
+#define __NR_clock_settime		262
+__SYSCALL(__NR_clock_settime, sys_clock_settime)
+#define __NR_clock_gettime		263
+__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
+#define __NR_clock_getres		264
+__SYSCALL(__NR_clock_getres, sys_clock_getres)
+#define __NR_clock_nanosleep		265
+__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
+#define __NR_statfs64			266
+__SYSCALL(__NR_statfs64, sys_statfs64)
+#define __NR_fstatfs64			267
+__SYSCALL(__NR_fstatfs64, sys_fstatfs64)
+#define __NR_tgkill			268
+__SYSCALL(__NR_tgkill, sys_tgkill)
+#define __NR_utimes			269
+__SYSCALL(__NR_utimes, sys_utimes)
+#define __NR_fadvise64			270
+__SYSCALL(__NR_fadvise64, sys_fadvise64_64)
+#define __NR_pciconfig_iobase		271
+__SYSCALL(__NR_pciconfig_iobase, sys_pciconfig_iobase)
+#define __NR_pciconfig_read		272
+__SYSCALL(__NR_pciconfig_read, sys_pciconfig_read)
+#define __NR_pciconfig_write		273
+__SYSCALL(__NR_pciconfig_write, sys_pciconfig_write)
+#define __NR_mq_open			274
+__SYSCALL(__NR_mq_open, sys_mq_open)
+#define __NR_mq_unlink			275
+__SYSCALL(__NR_mq_unlink, sys_mq_unlink)
+#define __NR_mq_timedsend		276
+__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
+#define __NR_mq_timedreceive		277
+__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
+#define __NR_mq_notify			278
+__SYSCALL(__NR_mq_notify, sys_mq_notify)
+#define __NR_mq_getsetattr		279
+__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
+#define __NR_waitid			280
+__SYSCALL(__NR_waitid, sys_waitid)
+#define __NR_socket			281
+__SYSCALL(__NR_socket, sys_socket)
+#define __NR_bind			282
+__SYSCALL(__NR_bind, sys_bind)
+#define __NR_connect			283
+__SYSCALL(__NR_connect, sys_connect)
+#define __NR_listen			284
+__SYSCALL(__NR_listen, sys_listen)
+#define __NR_accept			285
+__SYSCALL(__NR_accept, sys_accept)
+#define __NR_getsockname		286
+__SYSCALL(__NR_getsockname, sys_getsockname)
+#define __NR_getpeername		287
+__SYSCALL(__NR_getpeername, sys_getpeername)
+#define __NR_socketpair			288
+__SYSCALL(__NR_socketpair, sys_socketpair)
+#define __NR_send			289
+__SYSCALL(__NR_send, sys_send)
+#define __NR_sendto			290
+__SYSCALL(__NR_sendto, sys_sendto)
+#define __NR_recv			291
+__SYSCALL(__NR_recv, sys_recv)
+#define __NR_recvfrom			292
+__SYSCALL(__NR_recvfrom, sys_recvfrom)
+#define __NR_shutdown			293
+__SYSCALL(__NR_shutdown, sys_shutdown)
+#define __NR_setsockopt			294
+__SYSCALL(__NR_setsockopt, sys_setsockopt)
+#define __NR_getsockopt			295
+__SYSCALL(__NR_getsockopt, sys_getsockopt)
+#define __NR_sendmsg			296
+__SYSCALL(__NR_sendmsg, sys_sendmsg)
+#define __NR_recvmsg			297
+__SYSCALL(__NR_recvmsg, sys_recvmsg)
+#define __NR_semop			298
+__SYSCALL(__NR_semop, sys_semop)
+#define __NR_semget			299
+__SYSCALL(__NR_semget, sys_semget)
+#define __NR_semctl			300
+__SYSCALL(__NR_semctl, sys_semctl)
+#define __NR_msgsnd			301
+__SYSCALL(__NR_msgsnd, sys_msgsnd)
+#define __NR_msgrcv			302
+__SYSCALL(__NR_msgrcv, sys_msgrcv)
+#define __NR_msgget			303
+__SYSCALL(__NR_msgget, sys_msgget)
+#define __NR_msgctl			304
+__SYSCALL(__NR_msgctl, sys_msgctl)
+#define __NR_shmat			305
+__SYSCALL(__NR_shmat, sys_shmat)
+#define __NR_shmdt			306
+__SYSCALL(__NR_shmdt, sys_shmdt)
+#define __NR_shmget			307
+__SYSCALL(__NR_shmget, sys_shmget)
+#define __NR_shmctl			308
+__SYSCALL(__NR_shmctl, sys_shmctl)
+#define __NR_add_key			309
+__SYSCALL(__NR_add_key, sys_add_key)
+#define __NR_request_key		310
+__SYSCALL(__NR_request_key, sys_request_key)
+#define __NR_keyctl			311
+__SYSCALL(__NR_keyctl, sys_keyctl)
+#define __NR_semtimedop			312
+__SYSCALL(__NR_semtimedop, sys_semtimedop)
+#define __NR_vserver			313
+__SYSCALL(__NR_vserver, sys_ni_syscall)
+#define __NR_ioprio_set			314
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get			315
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
+#define __NR_inotify_init		316
+__SYSCALL(__NR_inotify_init, sys_inotify_init)
+#define __NR_inotify_add_watch		317
+__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
+#define __NR_inotify_rm_watch		318
+__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
+#define __NR_mbind			319
+__SYSCALL(__NR_mbind, sys_mbind)
+#define __NR_get_mempolicy		320
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
+#define __NR_set_mempolicy		321
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
+#define __NR_openat			322
+__SYSCALL(__NR_openat, sys_openat)
+#define __NR_mkdirat			323
+__SYSCALL(__NR_mkdirat, sys_mkdirat)
+#define __NR_mknodat			324
+__SYSCALL(__NR_mknodat, sys_mknodat)
+#define __NR_fchownat			325
+__SYSCALL(__NR_fchownat, sys_fchownat)
+#define __NR_futimesat			326
+__SYSCALL(__NR_futimesat, sys_futimesat)
+#define __NR_fstatat64			327
+__SYSCALL(__NR_fstatat64, sys_fstatat64)
+#define __NR_unlinkat			328
+__SYSCALL(__NR_unlinkat, sys_unlinkat)
+#define __NR_renameat			329
+__SYSCALL(__NR_renameat, sys_renameat)
+#define __NR_linkat			330
+__SYSCALL(__NR_linkat, sys_linkat)
+#define __NR_symlinkat			331
+__SYSCALL(__NR_symlinkat, sys_symlinkat)
+#define __NR_readlinkat			332
+__SYSCALL(__NR_readlinkat, sys_readlinkat)
+#define __NR_fchmodat			333
+__SYSCALL(__NR_fchmodat, sys_fchmodat)
+#define __NR_faccessat			334
+__SYSCALL(__NR_faccessat, sys_faccessat)
+#define __NR_pselect6			335
+__SYSCALL(__NR_pselect6, sys_pselect6)
+#define __NR_ppoll			336
+__SYSCALL(__NR_ppoll, sys_ppoll)
+#define __NR_unshare			337
+__SYSCALL(__NR_unshare, sys_unshare)
+#define __NR_set_robust_list		338
+__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+#define __NR_get_robust_list		339
+__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+#define __NR_splice			340
+__SYSCALL(__NR_splice, sys_splice)
+#define __NR_sync_file_range2		341
+__SYSCALL(__NR_sync_file_range2, sys_sync_file_range2)
+#define __NR_tee			342
+__SYSCALL(__NR_tee, sys_tee)
+#define __NR_vmsplice			343
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
+#define __NR_move_pages			344
+__SYSCALL(__NR_move_pages, sys_move_pages)
+#define __NR_getcpu			345
+__SYSCALL(__NR_getcpu, sys_getcpu)
+#define __NR_epoll_pwait		346
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+#define __NR_kexec_load			347
+__SYSCALL(__NR_kexec_load, sys_kexec_load)
+#define __NR_utimensat			348
+__SYSCALL(__NR_utimensat, sys_utimensat)
+#define __NR_signalfd			349
+__SYSCALL(__NR_signalfd, sys_signalfd)
+#define __NR_timerfd_create		350
+__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
+#define __NR_eventfd			351
+__SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_fallocate			352
+__SYSCALL(__NR_fallocate, sys_fallocate)
+#define __NR_timerfd_settime		353
+__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+#define __NR_timerfd_gettime		354
+__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+#define __NR_signalfd4			355
+__SYSCALL(__NR_signalfd4, sys_signalfd4)
+#define __NR_eventfd2			356
+__SYSCALL(__NR_eventfd2, sys_eventfd2)
+#define __NR_epoll_create1		357
+__SYSCALL(__NR_epoll_create1, sys_epoll_create1)
+#define __NR_dup3			358
+__SYSCALL(__NR_dup3, sys_dup3)
+#define __NR_pipe2			359
+__SYSCALL(__NR_pipe2, sys_pipe2)
+#define __NR_inotify_init1		360
+__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
+#define __NR_preadv			361
+__SYSCALL(__NR_preadv, sys_preadv)
+#define __NR_pwritev			362
+__SYSCALL(__NR_pwritev, sys_pwritev)
+#define __NR_rt_tgsigqueueinfo		363
+__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
+#define __NR_perf_event_open		364
+__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
+#define __NR_recvmmsg			365
+__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+#define __NR_accept4			366
+__SYSCALL(__NR_accept4, sys_accept4)
+#define __NR_fanotify_init		367
+__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
+#define __NR_fanotify_mark		368
+__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
+#define __NR_prlimit64			369
+__SYSCALL(__NR_prlimit64, sys_prlimit64)
+#define __NR_name_to_handle_at		370
+__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
+#define __NR_open_by_handle_at		371
+__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
+#define __NR_clock_adjtime		372
+__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+#define __NR_syncfs			373
+__SYSCALL(__NR_syncfs, sys_syncfs)
+
+/*
+ * The following SVCs are ARM private.
+ */
+#define __ARM_NR_COMPAT_BASE		0x0f0000
+#define __ARM_NR_compat_cacheflush	(__ARM_NR_COMPAT_BASE+2)
+#define __ARM_NR_compat_set_tls		(__ARM_NR_COMPAT_BASE+5)
+
+#endif	/* __SYSCALL_COMPAT */
+
+#define __NR_compat_syscalls		374
+
+#define __ARCH_WANT_COMPAT_IPC_PARSE_VERSION
+#define __ARCH_WANT_COMPAT_STAT64
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+
+#endif /* __ASM_UNISTD32_H */
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
new file mode 100644
index 0000000..839ce00
--- /dev/null
+++ b/arch/arm64/include/asm/vdso.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+/*
+ * Default link address for the vDSO.
+ * Since we randomise the VDSO mapping, there's little point in trying
+ * to prelink this.
+ */
+#define VDSO_LBASE	0x0
+
+#ifndef __ASSEMBLY__
+
+#include <generated/vdso-offsets.h>
+
+#define VDSO_SYMBOL(base, name)						   \
+({									   \
+	(void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
+})
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/arm64/include/asm/vdso_datapage.h b/arch/arm64/include/asm/vdso_datapage.h
new file mode 100644
index 0000000..de66199
--- /dev/null
+++ b/arch/arm64/include/asm/vdso_datapage.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_VDSO_DATAPAGE_H
+#define __ASM_VDSO_DATAPAGE_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+struct vdso_data {
+	__u64 cs_cycle_last;	/* Timebase at clocksource init */
+	__u64 xtime_clock_sec;	/* Kernel time */
+	__u64 xtime_clock_nsec;
+	__u64 xtime_coarse_sec;	/* Coarse time */
+	__u64 xtime_coarse_nsec;
+	__u64 wtm_clock_sec;	/* Wall to monotonic time */
+	__u64 wtm_clock_nsec;
+	__u32 tb_seq_count;	/* Timebase sequence counter */
+	__u32 cs_mult;		/* Clocksource multiplier */
+	__u32 cs_shift;		/* Clocksource shift */
+	__u32 tz_minuteswest;	/* Whacky timezone stuff */
+	__u32 tz_dsttime;
+	__u32 use_syscall;
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_DATAPAGE_H */
diff --git a/arch/arm64/kernel/.gitignore b/arch/arm64/kernel/.gitignore
new file mode 100644
index 0000000..c5f676c
--- /dev/null
+++ b/arch/arm64/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
new file mode 100644
index 0000000..e2caff1
--- /dev/null
+++ b/arch/arm64/kernel/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile for the linux kernel.
+#
+
+CPPFLAGS_vmlinux.lds	:= -DTEXT_OFFSET=$(TEXT_OFFSET)
+AFLAGS_head.o		:= -DTEXT_OFFSET=$(TEXT_OFFSET)
+
+# Object file lists.
+arm64-obj-y		:= cputable.o debug-monitors.o entry.o irq.o fpsimd.o	\
+			   entry-fpsimd.o process.o ptrace.o setup.o signal.o	\
+			   sys.o stacktrace.o time.o traps.o io.o vdso.o
+
+arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
+					   sys_compat.o
+arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
+arm64-obj-$(CONFIG_SMP)			+= smp.o
+arm64-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
+arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
+
+obj-y					+= $(arm64-obj-y) vdso/
+obj-m					+= $(arm64-obj-m)
+head-y					:= head.o
+extra-y					:= $(head-y) vmlinux.lds
+
+# vDSO - this must be built first to generate the symbol offsets
+$(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h
+$(obj)/vdso/vdso-offsets.h: $(obj)/vdso
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
new file mode 100644
index 0000000..cef3925
--- /dev/null
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -0,0 +1,46 @@
+/*
+ * Based on arch/arm/kernel/armksyms.c
+ *
+ * Copyright (C) 2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/cryptohash.h>
+#include <linux/delay.h>
+#include <linux/in6.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/checksum.h>
+
+	/* user mem (segment) */
+EXPORT_SYMBOL(__strnlen_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+
+EXPORT_SYMBOL(copy_page);
+
+EXPORT_SYMBOL(__copy_from_user);
+EXPORT_SYMBOL(__copy_to_user);
+EXPORT_SYMBOL(__clear_user);
+
+	/* bitops */
+EXPORT_SYMBOL(__atomic_hash);
+
+	/* physical memory */
+EXPORT_SYMBOL(memstart_addr);
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
new file mode 100644
index 0000000..a2a4d81
--- /dev/null
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -0,0 +1,108 @@
+/*
+ * Based on arch/arm/kernel/asm-offsets.c
+ *
+ * Copyright (C) 1995-2003 Russell King
+ *               2001-2002 Keith Owens
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <asm/thread_info.h>
+#include <asm/memory.h>
+#include <asm/cputable.h>
+#include <asm/vdso_datapage.h>
+#include <linux/kbuild.h>
+
+int main(void)
+{
+  DEFINE(TSK_ACTIVE_MM,		offsetof(struct task_struct, active_mm));
+  BLANK();
+  DEFINE(TI_FLAGS,		offsetof(struct thread_info, flags));
+  DEFINE(TI_PREEMPT,		offsetof(struct thread_info, preempt_count));
+  DEFINE(TI_ADDR_LIMIT,		offsetof(struct thread_info, addr_limit));
+  DEFINE(TI_TASK,		offsetof(struct thread_info, task));
+  DEFINE(TI_EXEC_DOMAIN,	offsetof(struct thread_info, exec_domain));
+  DEFINE(TI_CPU,		offsetof(struct thread_info, cpu));
+  BLANK();
+  DEFINE(THREAD_CPU_CONTEXT,	offsetof(struct task_struct, thread.cpu_context));
+  BLANK();
+  DEFINE(S_X0,			offsetof(struct pt_regs, regs[0]));
+  DEFINE(S_X1,			offsetof(struct pt_regs, regs[1]));
+  DEFINE(S_X2,			offsetof(struct pt_regs, regs[2]));
+  DEFINE(S_X3,			offsetof(struct pt_regs, regs[3]));
+  DEFINE(S_X4,			offsetof(struct pt_regs, regs[4]));
+  DEFINE(S_X5,			offsetof(struct pt_regs, regs[5]));
+  DEFINE(S_X6,			offsetof(struct pt_regs, regs[6]));
+  DEFINE(S_X7,			offsetof(struct pt_regs, regs[7]));
+  DEFINE(S_LR,			offsetof(struct pt_regs, regs[30]));
+  DEFINE(S_SP,			offsetof(struct pt_regs, sp));
+#ifdef CONFIG_COMPAT
+  DEFINE(S_COMPAT_SP,		offsetof(struct pt_regs, compat_sp));
+#endif
+  DEFINE(S_PSTATE,		offsetof(struct pt_regs, pstate));
+  DEFINE(S_PC,			offsetof(struct pt_regs, pc));
+  DEFINE(S_ORIG_X0,		offsetof(struct pt_regs, orig_x0));
+  DEFINE(S_SYSCALLNO,		offsetof(struct pt_regs, syscallno));
+  DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
+  BLANK();
+  DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id));
+  BLANK();
+  DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
+  DEFINE(VMA_VM_FLAGS,		offsetof(struct vm_area_struct, vm_flags));
+  BLANK();
+  DEFINE(VM_EXEC,	       	VM_EXEC);
+  BLANK();
+  DEFINE(PAGE_SZ,	       	PAGE_SIZE);
+  BLANK();
+  DEFINE(CPU_INFO_SZ,		sizeof(struct cpu_info));
+  DEFINE(CPU_INFO_SETUP,	offsetof(struct cpu_info, cpu_setup));
+  BLANK();
+  DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
+  DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
+  DEFINE(DMA_FROM_DEVICE,	DMA_FROM_DEVICE);
+  BLANK();
+  DEFINE(CLOCK_REALTIME,	CLOCK_REALTIME);
+  DEFINE(CLOCK_MONOTONIC,	CLOCK_MONOTONIC);
+  DEFINE(CLOCK_REALTIME_RES,	MONOTONIC_RES_NSEC);
+  DEFINE(CLOCK_REALTIME_COARSE,	CLOCK_REALTIME_COARSE);
+  DEFINE(CLOCK_MONOTONIC_COARSE,CLOCK_MONOTONIC_COARSE);
+  DEFINE(CLOCK_COARSE_RES,	LOW_RES_NSEC);
+  DEFINE(NSEC_PER_SEC,		NSEC_PER_SEC);
+  BLANK();
+  DEFINE(VDSO_CS_CYCLE_LAST,	offsetof(struct vdso_data, cs_cycle_last));
+  DEFINE(VDSO_XTIME_CLK_SEC,	offsetof(struct vdso_data, xtime_clock_sec));
+  DEFINE(VDSO_XTIME_CLK_NSEC,	offsetof(struct vdso_data, xtime_clock_nsec));
+  DEFINE(VDSO_XTIME_CRS_SEC,	offsetof(struct vdso_data, xtime_coarse_sec));
+  DEFINE(VDSO_XTIME_CRS_NSEC,	offsetof(struct vdso_data, xtime_coarse_nsec));
+  DEFINE(VDSO_WTM_CLK_SEC,	offsetof(struct vdso_data, wtm_clock_sec));
+  DEFINE(VDSO_WTM_CLK_NSEC,	offsetof(struct vdso_data, wtm_clock_nsec));
+  DEFINE(VDSO_TB_SEQ_COUNT,	offsetof(struct vdso_data, tb_seq_count));
+  DEFINE(VDSO_CS_MULT,		offsetof(struct vdso_data, cs_mult));
+  DEFINE(VDSO_CS_SHIFT,		offsetof(struct vdso_data, cs_shift));
+  DEFINE(VDSO_TZ_MINWEST,	offsetof(struct vdso_data, tz_minuteswest));
+  DEFINE(VDSO_TZ_DSTTIME,	offsetof(struct vdso_data, tz_dsttime));
+  DEFINE(VDSO_USE_SYSCALL,	offsetof(struct vdso_data, use_syscall));
+  BLANK();
+  DEFINE(TVAL_TV_SEC,		offsetof(struct timeval, tv_sec));
+  DEFINE(TVAL_TV_USEC,		offsetof(struct timeval, tv_usec));
+  DEFINE(TSPEC_TV_SEC,		offsetof(struct timespec, tv_sec));
+  DEFINE(TSPEC_TV_NSEC,		offsetof(struct timespec, tv_nsec));
+  BLANK();
+  DEFINE(TZ_MINWEST,		offsetof(struct timezone, tz_minuteswest));
+  DEFINE(TZ_DSTTIME,		offsetof(struct timezone, tz_dsttime));
+  return 0;
+}
diff --git a/arch/arm64/kernel/cputable.c b/arch/arm64/kernel/cputable.c
new file mode 100644
index 0000000..63cfc4a
--- /dev/null
+++ b/arch/arm64/kernel/cputable.c
@@ -0,0 +1,33 @@
+/*
+ * arch/arm64/kernel/cputable.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+
+#include <asm/cputable.h>
+
+extern unsigned long __cpu_setup(void);
+
+struct cpu_info __initdata cpu_table[] = {
+	{
+		.cpu_id_val	= 0x000f0000,
+		.cpu_id_mask	= 0x000f0000,
+		.cpu_name	= "AArch64 Processor",
+		.cpu_setup	= __cpu_setup,
+	},
+	{ /* Empty */ },
+};
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
new file mode 100644
index 0000000..0c3ba9f
--- /dev/null
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -0,0 +1,288 @@
+/*
+ * ARMv8 single-step debug support and mdscr context switching.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/cpu.h>
+#include <linux/debugfs.h>
+#include <linux/hardirq.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/stat.h>
+
+#include <asm/debug-monitors.h>
+#include <asm/local.h>
+#include <asm/cputype.h>
+#include <asm/system_misc.h>
+
+/* Low-level stepping controls. */
+#define DBG_MDSCR_SS		(1 << 0)
+#define DBG_SPSR_SS		(1 << 21)
+
+/* MDSCR_EL1 enabling bits */
+#define DBG_MDSCR_KDE		(1 << 13)
+#define DBG_MDSCR_MDE		(1 << 15)
+#define DBG_MDSCR_MASK		~(DBG_MDSCR_KDE | DBG_MDSCR_MDE)
+
+/* Determine debug architecture. */
+u8 debug_monitors_arch(void)
+{
+	return read_cpuid(ID_AA64DFR0_EL1) & 0xf;
+}
+
+/*
+ * MDSCR access routines.
+ */
+static void mdscr_write(u32 mdscr)
+{
+	unsigned long flags;
+	local_dbg_save(flags);
+	asm volatile("msr mdscr_el1, %0" :: "r" (mdscr));
+	local_dbg_restore(flags);
+}
+
+static u32 mdscr_read(void)
+{
+	u32 mdscr;
+	asm volatile("mrs %0, mdscr_el1" : "=r" (mdscr));
+	return mdscr;
+}
+
+/*
+ * Allow root to disable self-hosted debug from userspace.
+ * This is useful if you want to connect an external JTAG debugger.
+ */
+static u32 debug_enabled = 1;
+
+static int create_debug_debugfs_entry(void)
+{
+	debugfs_create_bool("debug_enabled", 0644, NULL, &debug_enabled);
+	return 0;
+}
+fs_initcall(create_debug_debugfs_entry);
+
+static int __init early_debug_disable(char *buf)
+{
+	debug_enabled = 0;
+	return 0;
+}
+
+early_param("nodebugmon", early_debug_disable);
+
+/*
+ * Keep track of debug users on each core.
+ * The ref counts are per-cpu so we use a local_t type.
+ */
+static DEFINE_PER_CPU(local_t, mde_ref_count);
+static DEFINE_PER_CPU(local_t, kde_ref_count);
+
+void enable_debug_monitors(enum debug_el el)
+{
+	u32 mdscr, enable = 0;
+
+	WARN_ON(preemptible());
+
+	if (local_inc_return(&__get_cpu_var(mde_ref_count)) == 1)
+		enable = DBG_MDSCR_MDE;
+
+	if (el == DBG_ACTIVE_EL1 &&
+	    local_inc_return(&__get_cpu_var(kde_ref_count)) == 1)
+		enable |= DBG_MDSCR_KDE;
+
+	if (enable && debug_enabled) {
+		mdscr = mdscr_read();
+		mdscr |= enable;
+		mdscr_write(mdscr);
+	}
+}
+
+void disable_debug_monitors(enum debug_el el)
+{
+	u32 mdscr, disable = 0;
+
+	WARN_ON(preemptible());
+
+	if (local_dec_and_test(&__get_cpu_var(mde_ref_count)))
+		disable = ~DBG_MDSCR_MDE;
+
+	if (el == DBG_ACTIVE_EL1 &&
+	    local_dec_and_test(&__get_cpu_var(kde_ref_count)))
+		disable &= ~DBG_MDSCR_KDE;
+
+	if (disable) {
+		mdscr = mdscr_read();
+		mdscr &= disable;
+		mdscr_write(mdscr);
+	}
+}
+
+/*
+ * OS lock clearing.
+ */
+static void clear_os_lock(void *unused)
+{
+	asm volatile("msr mdscr_el1, %0" : : "r" (0));
+	isb();
+	asm volatile("msr oslar_el1, %0" : : "r" (0));
+	isb();
+}
+
+static int __cpuinit os_lock_notify(struct notifier_block *self,
+				    unsigned long action, void *data)
+{
+	int cpu = (unsigned long)data;
+	if (action == CPU_ONLINE)
+		smp_call_function_single(cpu, clear_os_lock, NULL, 1);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata os_lock_nb = {
+	.notifier_call = os_lock_notify,
+};
+
+static int __cpuinit debug_monitors_init(void)
+{
+	/* Clear the OS lock. */
+	smp_call_function(clear_os_lock, NULL, 1);
+	clear_os_lock(NULL);
+
+	/* Register hotplug handler. */
+	register_cpu_notifier(&os_lock_nb);
+	return 0;
+}
+postcore_initcall(debug_monitors_init);
+
+/*
+ * Single step API and exception handling.
+ */
+static void set_regs_spsr_ss(struct pt_regs *regs)
+{
+	unsigned long spsr;
+
+	spsr = regs->pstate;
+	spsr &= ~DBG_SPSR_SS;
+	spsr |= DBG_SPSR_SS;
+	regs->pstate = spsr;
+}
+
+static void clear_regs_spsr_ss(struct pt_regs *regs)
+{
+	unsigned long spsr;
+
+	spsr = regs->pstate;
+	spsr &= ~DBG_SPSR_SS;
+	regs->pstate = spsr;
+}
+
+static int single_step_handler(unsigned long addr, unsigned int esr,
+			       struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	/*
+	 * If we are stepping a pending breakpoint, call the hw_breakpoint
+	 * handler first.
+	 */
+	if (!reinstall_suspended_bps(regs))
+		return 0;
+
+	if (user_mode(regs)) {
+		info.si_signo = SIGTRAP;
+		info.si_errno = 0;
+		info.si_code  = TRAP_HWBKPT;
+		info.si_addr  = (void __user *)instruction_pointer(regs);
+		force_sig_info(SIGTRAP, &info, current);
+
+		/*
+		 * ptrace will disable single step unless explicitly
+		 * asked to re-enable it. For other clients, it makes
+		 * sense to leave it enabled (i.e. rewind the controls
+		 * to the active-not-pending state).
+		 */
+		user_rewind_single_step(current);
+	} else {
+		/* TODO: route to KGDB */
+		pr_warning("Unexpected kernel single-step exception at EL1\n");
+		/*
+		 * Re-enable stepping since we know that we will be
+		 * returning to regs.
+		 */
+		set_regs_spsr_ss(regs);
+	}
+
+	return 0;
+}
+
+static int __init single_step_init(void)
+{
+	hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
+			      TRAP_HWBKPT, "single-step handler");
+	return 0;
+}
+arch_initcall(single_step_init);
+
+/* Re-enable single step for syscall restarting. */
+void user_rewind_single_step(struct task_struct *task)
+{
+	/*
+	 * If single step is active for this thread, then set SPSR.SS
+	 * to 1 to avoid returning to the active-pending state.
+	 */
+	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+		set_regs_spsr_ss(task_pt_regs(task));
+}
+
+void user_fastforward_single_step(struct task_struct *task)
+{
+	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+		clear_regs_spsr_ss(task_pt_regs(task));
+}
+
+/* Kernel API */
+void kernel_enable_single_step(struct pt_regs *regs)
+{
+	WARN_ON(!irqs_disabled());
+	set_regs_spsr_ss(regs);
+	mdscr_write(mdscr_read() | DBG_MDSCR_SS);
+	enable_debug_monitors(DBG_ACTIVE_EL1);
+}
+
+void kernel_disable_single_step(void)
+{
+	WARN_ON(!irqs_disabled());
+	mdscr_write(mdscr_read() & ~DBG_MDSCR_SS);
+	disable_debug_monitors(DBG_ACTIVE_EL1);
+}
+
+int kernel_active_single_step(void)
+{
+	WARN_ON(!irqs_disabled());
+	return mdscr_read() & DBG_MDSCR_SS;
+}
+
+/* ptrace API */
+void user_enable_single_step(struct task_struct *task)
+{
+	set_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
+	set_regs_spsr_ss(task_pt_regs(task));
+}
+
+void user_disable_single_step(struct task_struct *task)
+{
+	clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
+}
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
new file mode 100644
index 0000000..17988a6
--- /dev/null
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -0,0 +1,80 @@
+/*
+ * FP/SIMD state saving and restoring
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+/*
+ * Save the FP registers.
+ *
+ * x0 - pointer to struct fpsimd_state
+ */
+ENTRY(fpsimd_save_state)
+	stp	q0, q1, [x0, #16 * 0]
+	stp	q2, q3, [x0, #16 * 2]
+	stp	q4, q5, [x0, #16 * 4]
+	stp	q6, q7, [x0, #16 * 6]
+	stp	q8, q9, [x0, #16 * 8]
+	stp	q10, q11, [x0, #16 * 10]
+	stp	q12, q13, [x0, #16 * 12]
+	stp	q14, q15, [x0, #16 * 14]
+	stp	q16, q17, [x0, #16 * 16]
+	stp	q18, q19, [x0, #16 * 18]
+	stp	q20, q21, [x0, #16 * 20]
+	stp	q22, q23, [x0, #16 * 22]
+	stp	q24, q25, [x0, #16 * 24]
+	stp	q26, q27, [x0, #16 * 26]
+	stp	q28, q29, [x0, #16 * 28]
+	stp	q30, q31, [x0, #16 * 30]!
+	mrs	x8, fpsr
+	str	w8, [x0, #16 * 2]
+	mrs	x8, fpcr
+	str	w8, [x0, #16 * 2 + 4]
+	ret
+ENDPROC(fpsimd_save_state)
+
+/*
+ * Load the FP registers.
+ *
+ * x0 - pointer to struct fpsimd_state
+ */
+ENTRY(fpsimd_load_state)
+	ldp	q0, q1, [x0, #16 * 0]
+	ldp	q2, q3, [x0, #16 * 2]
+	ldp	q4, q5, [x0, #16 * 4]
+	ldp	q6, q7, [x0, #16 * 6]
+	ldp	q8, q9, [x0, #16 * 8]
+	ldp	q10, q11, [x0, #16 * 10]
+	ldp	q12, q13, [x0, #16 * 12]
+	ldp	q14, q15, [x0, #16 * 14]
+	ldp	q16, q17, [x0, #16 * 16]
+	ldp	q18, q19, [x0, #16 * 18]
+	ldp	q20, q21, [x0, #16 * 20]
+	ldp	q22, q23, [x0, #16 * 22]
+	ldp	q24, q25, [x0, #16 * 24]
+	ldp	q26, q27, [x0, #16 * 26]
+	ldp	q28, q29, [x0, #16 * 28]
+	ldp	q30, q31, [x0, #16 * 30]!
+	ldr	w8, [x0, #16 * 2]
+	ldr	w9, [x0, #16 * 2 + 4]
+	msr	fpsr, x8
+	msr	fpcr, x9
+	ret
+ENDPROC(fpsimd_load_state)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
new file mode 100644
index 0000000..38cf853
--- /dev/null
+++ b/arch/arm64/kernel/entry.S
@@ -0,0 +1,695 @@
+/*
+ * Low-level exception handling code
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Authors:	Catalin Marinas <catalin.marinas@arm.com>
+ *		Will Deacon <will.deacon@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+
+/*
+ * Bad Abort numbers
+ *-----------------
+ */
+#define BAD_SYNC	0
+#define BAD_IRQ		1
+#define BAD_FIQ		2
+#define BAD_ERROR	3
+
+	.macro	kernel_entry, el, regsize = 64
+	sub	sp, sp, #S_FRAME_SIZE - S_LR	// room for LR, SP, SPSR, ELR
+	.if	\regsize == 32
+	mov	w0, w0				// zero upper 32 bits of x0
+	.endif
+	push	x28, x29
+	push	x26, x27
+	push	x24, x25
+	push	x22, x23
+	push	x20, x21
+	push	x18, x19
+	push	x16, x17
+	push	x14, x15
+	push	x12, x13
+	push	x10, x11
+	push	x8, x9
+	push	x6, x7
+	push	x4, x5
+	push	x2, x3
+	push	x0, x1
+	.if	\el == 0
+	mrs	x21, sp_el0
+	.else
+	add	x21, sp, #S_FRAME_SIZE
+	.endif
+	mrs	x22, elr_el1
+	mrs	x23, spsr_el1
+	stp	lr, x21, [sp, #S_LR]
+	stp	x22, x23, [sp, #S_PC]
+
+	/*
+	 * Set syscallno to -1 by default (overridden later if real syscall).
+	 */
+	.if	\el == 0
+	mvn	x21, xzr
+	str	x21, [sp, #S_SYSCALLNO]
+	.endif
+
+	/*
+	 * Registers that may be useful after this macro is invoked:
+	 *
+	 * x21 - aborted SP
+	 * x22 - aborted PC
+	 * x23 - aborted PSTATE
+	*/
+	.endm
+
+	.macro	kernel_exit, el, ret = 0
+	ldp	x21, x22, [sp, #S_PC]		// load ELR, SPSR
+	.if	\el == 0
+	ldr	x23, [sp, #S_SP]		// load return stack pointer
+	.endif
+	.if	\ret
+	ldr	x1, [sp, #S_X1]			// preserve x0 (syscall return)
+	add	sp, sp, S_X2
+	.else
+	pop	x0, x1
+	.endif
+	pop	x2, x3				// load the rest of the registers
+	pop	x4, x5
+	pop	x6, x7
+	pop	x8, x9
+	msr	elr_el1, x21			// set up the return data
+	msr	spsr_el1, x22
+	.if	\el == 0
+	msr	sp_el0, x23
+	.endif
+	pop	x10, x11
+	pop	x12, x13
+	pop	x14, x15
+	pop	x16, x17
+	pop	x18, x19
+	pop	x20, x21
+	pop	x22, x23
+	pop	x24, x25
+	pop	x26, x27
+	pop	x28, x29
+	ldr	lr, [sp], #S_FRAME_SIZE - S_LR	// load LR and restore SP
+	eret					// return to kernel
+	.endm
+
+	.macro	get_thread_info, rd
+	mov	\rd, sp
+	and	\rd, \rd, #~((1 << 13) - 1)	// top of 8K stack
+	.endm
+
+/*
+ * These are the registers used in the syscall handler, and allow us to
+ * have in theory up to 7 arguments to a function - x0 to x6.
+ *
+ * x7 is reserved for the system call number in 32-bit mode.
+ */
+sc_nr	.req	x25		// number of system calls
+scno	.req	x26		// syscall number
+stbl	.req	x27		// syscall table pointer
+tsk	.req	x28		// current thread_info
+
+/*
+ * Interrupt handling.
+ */
+	.macro	irq_handler
+	ldr	x1, handle_arch_irq
+	mov	x0, sp
+	blr	x1
+	.endm
+
+	.text
+
+/*
+ * Exception vectors.
+ */
+	.macro	ventry	label
+	.align	7
+	b	\label
+	.endm
+
+	.align	11
+ENTRY(vectors)
+	ventry	el1_sync_invalid		// Synchronous EL1t
+	ventry	el1_irq_invalid			// IRQ EL1t
+	ventry	el1_fiq_invalid			// FIQ EL1t
+	ventry	el1_error_invalid		// Error EL1t
+
+	ventry	el1_sync			// Synchronous EL1h
+	ventry	el1_irq				// IRQ EL1h
+	ventry	el1_fiq_invalid			// FIQ EL1h
+	ventry	el1_error_invalid		// Error EL1h
+
+	ventry	el0_sync			// Synchronous 64-bit EL0
+	ventry	el0_irq				// IRQ 64-bit EL0
+	ventry	el0_fiq_invalid			// FIQ 64-bit EL0
+	ventry	el0_error_invalid		// Error 64-bit EL0
+
+#ifdef CONFIG_COMPAT
+	ventry	el0_sync_compat			// Synchronous 32-bit EL0
+	ventry	el0_irq_compat			// IRQ 32-bit EL0
+	ventry	el0_fiq_invalid_compat		// FIQ 32-bit EL0
+	ventry	el0_error_invalid_compat	// Error 32-bit EL0
+#else
+	ventry	el0_sync_invalid		// Synchronous 32-bit EL0
+	ventry	el0_irq_invalid			// IRQ 32-bit EL0
+	ventry	el0_fiq_invalid			// FIQ 32-bit EL0
+	ventry	el0_error_invalid		// Error 32-bit EL0
+#endif
+END(vectors)
+
+/*
+ * Invalid mode handlers
+ */
+	.macro	inv_entry, el, reason, regsize = 64
+	kernel_entry el, \regsize
+	mov	x0, sp
+	mov	x1, #\reason
+	mrs	x2, esr_el1
+	b	bad_mode
+	.endm
+
+el0_sync_invalid:
+	inv_entry 0, BAD_SYNC
+ENDPROC(el0_sync_invalid)
+
+el0_irq_invalid:
+	inv_entry 0, BAD_IRQ
+ENDPROC(el0_irq_invalid)
+
+el0_fiq_invalid:
+	inv_entry 0, BAD_FIQ
+ENDPROC(el0_fiq_invalid)
+
+el0_error_invalid:
+	inv_entry 0, BAD_ERROR
+ENDPROC(el0_error_invalid)
+
+#ifdef CONFIG_COMPAT
+el0_fiq_invalid_compat:
+	inv_entry 0, BAD_FIQ, 32
+ENDPROC(el0_fiq_invalid_compat)
+
+el0_error_invalid_compat:
+	inv_entry 0, BAD_ERROR, 32
+ENDPROC(el0_error_invalid_compat)
+#endif
+
+el1_sync_invalid:
+	inv_entry 1, BAD_SYNC
+ENDPROC(el1_sync_invalid)
+
+el1_irq_invalid:
+	inv_entry 1, BAD_IRQ
+ENDPROC(el1_irq_invalid)
+
+el1_fiq_invalid:
+	inv_entry 1, BAD_FIQ
+ENDPROC(el1_fiq_invalid)
+
+el1_error_invalid:
+	inv_entry 1, BAD_ERROR
+ENDPROC(el1_error_invalid)
+
+/*
+ * EL1 mode handlers.
+ */
+	.align	6
+el1_sync:
+	kernel_entry 1
+	mrs	x1, esr_el1			// read the syndrome register
+	lsr	x24, x1, #26			// exception class
+	cmp	x24, #0x25			// data abort in EL1
+	b.eq	el1_da
+	cmp	x24, #0x18			// configurable trap
+	b.eq	el1_undef
+	cmp	x24, #0x26			// stack alignment exception
+	b.eq	el1_sp_pc
+	cmp	x24, #0x22			// pc alignment exception
+	b.eq	el1_sp_pc
+	cmp	x24, #0x00			// unknown exception in EL1
+	b.eq	el1_undef
+	cmp	x24, #0x30			// debug exception in EL1
+	b.ge	el1_dbg
+	b	el1_inv
+el1_da:
+	/*
+	 * Data abort handling
+	 */
+	mrs	x0, far_el1
+	enable_dbg_if_not_stepping x2
+	// re-enable interrupts if they were enabled in the aborted context
+	tbnz	x23, #7, 1f			// PSR_I_BIT
+	enable_irq
+1:
+	mov	x2, sp				// struct pt_regs
+	bl	do_mem_abort
+
+	// disable interrupts before pulling preserved data off the stack
+	disable_irq
+	kernel_exit 1
+el1_sp_pc:
+	/*
+	 * Stack or PC alignment exception handling
+	 */
+	mrs	x0, far_el1
+	mov	x1, x25
+	mov	x2, sp
+	b	do_sp_pc_abort
+el1_undef:
+	/*
+	 * Undefined instruction
+	 */
+	mov	x0, sp
+	b	do_undefinstr
+el1_dbg:
+	/*
+	 * Debug exception handling
+	 */
+	tbz	x24, #0, el1_inv		// EL1 only
+	mrs	x0, far_el1
+	mov	x2, sp				// struct pt_regs
+	bl	do_debug_exception
+
+	kernel_exit 1
+el1_inv:
+	// TODO: add support for undefined instructions in kernel mode
+	mov	x0, sp
+	mov	x1, #BAD_SYNC
+	mrs	x2, esr_el1
+	b	bad_mode
+ENDPROC(el1_sync)
+
+	.align	6
+el1_irq:
+	kernel_entry 1
+	enable_dbg_if_not_stepping x0
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+#ifdef CONFIG_PREEMPT
+	get_thread_info tsk
+	ldr	x24, [tsk, #TI_PREEMPT]		// get preempt count
+	add	x0, x24, #1			// increment it
+	str	x0, [tsk, #TI_PREEMPT]
+#endif
+	irq_handler
+#ifdef CONFIG_PREEMPT
+	str	x24, [tsk, #TI_PREEMPT]		// restore preempt count
+	cbnz	x24, 1f				// preempt count != 0
+	ldr	x0, [tsk, #TI_FLAGS]		// get flags
+	tbz	x0, #TIF_NEED_RESCHED, 1f	// needs rescheduling?
+	bl	el1_preempt
+1:
+#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_on
+#endif
+	kernel_exit 1
+ENDPROC(el1_irq)
+
+#ifdef CONFIG_PREEMPT
+el1_preempt:
+	mov	x24, lr
+1:	enable_dbg
+	bl	preempt_schedule_irq		// irq en/disable is done inside
+	ldr	x0, [tsk, #TI_FLAGS]		// get new tasks TI_FLAGS
+	tbnz	x0, #TIF_NEED_RESCHED, 1b	// needs rescheduling?
+	ret	x24
+#endif
+
+/*
+ * EL0 mode handlers.
+ */
+	.align	6
+el0_sync:
+	kernel_entry 0
+	mrs	x25, esr_el1			// read the syndrome register
+	lsr	x24, x25, #26			// exception class
+	cmp	x24, #0x15			// SVC in 64-bit state
+	b.eq	el0_svc
+	adr	lr, ret_from_exception
+	cmp	x24, #0x24			// data abort in EL0
+	b.eq	el0_da
+	cmp	x24, #0x20			// instruction abort in EL0
+	b.eq	el0_ia
+	cmp	x24, #0x07			// FP/ASIMD access
+	b.eq	el0_fpsimd_acc
+	cmp	x24, #0x2c			// FP/ASIMD exception
+	b.eq	el0_fpsimd_exc
+	cmp	x24, #0x18			// configurable trap
+	b.eq	el0_undef
+	cmp	x24, #0x26			// stack alignment exception
+	b.eq	el0_sp_pc
+	cmp	x24, #0x22			// pc alignment exception
+	b.eq	el0_sp_pc
+	cmp	x24, #0x00			// unknown exception in EL0
+	b.eq	el0_undef
+	cmp	x24, #0x30			// debug exception in EL0
+	b.ge	el0_dbg
+	b	el0_inv
+
+#ifdef CONFIG_COMPAT
+	.align	6
+el0_sync_compat:
+	kernel_entry 0, 32
+	mrs	x25, esr_el1			// read the syndrome register
+	lsr	x24, x25, #26			// exception class
+	cmp	x24, #0x11			// SVC in 32-bit state
+	b.eq	el0_svc_compat
+	adr	lr, ret_from_exception
+	cmp	x24, #0x24			// data abort in EL0
+	b.eq	el0_da
+	cmp	x24, #0x20			// instruction abort in EL0
+	b.eq	el0_ia
+	cmp	x24, #0x07			// FP/ASIMD access
+	b.eq	el0_fpsimd_acc
+	cmp	x24, #0x28			// FP/ASIMD exception
+	b.eq	el0_fpsimd_exc
+	cmp	x24, #0x00			// unknown exception in EL0
+	b.eq	el0_undef
+	cmp	x24, #0x30			// debug exception in EL0
+	b.ge	el0_dbg
+	b	el0_inv
+el0_svc_compat:
+	/*
+	 * AArch32 syscall handling
+	 */
+	adr	stbl, compat_sys_call_table	// load compat syscall table pointer
+	uxtw	scno, w7			// syscall number in w7 (r7)
+	mov     sc_nr, #__NR_compat_syscalls
+	b	el0_svc_naked
+
+	.align	6
+el0_irq_compat:
+	kernel_entry 0, 32
+	b	el0_irq_naked
+#endif
+
+el0_da:
+	/*
+	 * Data abort handling
+	 */
+	mrs	x0, far_el1
+	disable_step x1
+	isb
+	enable_dbg
+	// enable interrupts before calling the main handler
+	enable_irq
+	mov	x1, x25
+	mov	x2, sp
+	b	do_mem_abort
+el0_ia:
+	/*
+	 * Instruction abort handling
+	 */
+	mrs	x0, far_el1
+	disable_step x1
+	isb
+	enable_dbg
+	// enable interrupts before calling the main handler
+	enable_irq
+	orr	x1, x25, #1 << 24		// use reserved ISS bit for instruction aborts
+	mov	x2, sp
+	b	do_mem_abort
+el0_fpsimd_acc:
+	/*
+	 * Floating Point or Advanced SIMD access
+	 */
+	mov	x0, x25
+	mov	x1, sp
+	b	do_fpsimd_acc
+el0_fpsimd_exc:
+	/*
+	 * Floating Point or Advanced SIMD exception
+	 */
+	mov	x0, x25
+	mov	x1, sp
+	b	do_fpsimd_exc
+el0_sp_pc:
+	/*
+	 * Stack or PC alignment exception handling
+	 */
+	mrs	x0, far_el1
+	disable_step x1
+	isb
+	enable_dbg
+	// enable interrupts before calling the main handler
+	enable_irq
+	mov	x1, x25
+	mov	x2, sp
+	b	do_sp_pc_abort
+el0_undef:
+	/*
+	 * Undefined instruction
+	 */
+	mov	x0, sp
+	b	do_undefinstr
+el0_dbg:
+	/*
+	 * Debug exception handling
+	 */
+	tbnz	x24, #0, el0_inv		// EL0 only
+	mrs	x0, far_el1
+	disable_step x1
+	mov	x1, x25
+	mov	x2, sp
+	b	do_debug_exception
+el0_inv:
+	mov	x0, sp
+	mov	x1, #BAD_SYNC
+	mrs	x2, esr_el1
+	b	bad_mode
+ENDPROC(el0_sync)
+
+	.align	6
+el0_irq:
+	kernel_entry 0
+el0_irq_naked:
+	disable_step x1
+	isb
+	enable_dbg
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	get_thread_info tsk
+#ifdef CONFIG_PREEMPT
+	ldr	x24, [tsk, #TI_PREEMPT]		// get preempt count
+	add	x23, x24, #1			// increment it
+	str	x23, [tsk, #TI_PREEMPT]
+#endif
+	irq_handler
+#ifdef CONFIG_PREEMPT
+	ldr	x0, [tsk, #TI_PREEMPT]
+	str	x24, [tsk, #TI_PREEMPT]
+	cmp	x0, x23
+	b.eq	1f
+	mov	x1, #0
+	str	x1, [x1]			// BUG
+1:
+#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_on
+#endif
+	b	ret_to_user
+ENDPROC(el0_irq)
+
+/*
+ * This is the return code to user mode for abort handlers
+ */
+ret_from_exception:
+	get_thread_info tsk
+	b	ret_to_user
+ENDPROC(ret_from_exception)
+
+/*
+ * Register switch for AArch64. The callee-saved registers need to be saved
+ * and restored. On entry:
+ *   x0 = previous task_struct (must be preserved across the switch)
+ *   x1 = next task_struct
+ * Previous and next are guaranteed not to be the same.
+ *
+ */
+ENTRY(cpu_switch_to)
+	add	x8, x0, #THREAD_CPU_CONTEXT
+	mov	x9, sp
+	stp	x19, x20, [x8], #16		// store callee-saved registers
+	stp	x21, x22, [x8], #16
+	stp	x23, x24, [x8], #16
+	stp	x25, x26, [x8], #16
+	stp	x27, x28, [x8], #16
+	stp	x29, x9, [x8], #16
+	str	lr, [x8]
+	add	x8, x1, #THREAD_CPU_CONTEXT
+	ldp	x19, x20, [x8], #16		// restore callee-saved registers
+	ldp	x21, x22, [x8], #16
+	ldp	x23, x24, [x8], #16
+	ldp	x25, x26, [x8], #16
+	ldp	x27, x28, [x8], #16
+	ldp	x29, x9, [x8], #16
+	ldr	lr, [x8]
+	mov	sp, x9
+	ret
+ENDPROC(cpu_switch_to)
+
+/*
+ * This is the fast syscall return path.  We do as little as possible here,
+ * and this includes saving x0 back into the kernel stack.
+ */
+ret_fast_syscall:
+	disable_irq				// disable interrupts
+	ldr	x1, [tsk, #TI_FLAGS]
+	and	x2, x1, #_TIF_WORK_MASK
+	cbnz	x2, fast_work_pending
+	tbz	x1, #TIF_SINGLESTEP, fast_exit
+	disable_dbg
+	enable_step x2
+fast_exit:
+	kernel_exit 0, ret = 1
+
+/*
+ * Ok, we need to do extra processing, enter the slow path.
+ */
+fast_work_pending:
+	str	x0, [sp, #S_X0]			// returned x0
+work_pending:
+	tbnz	x1, #TIF_NEED_RESCHED, work_resched
+	/* TIF_SIGPENDING or TIF_NOTIFY_RESUME case */
+	ldr	x2, [sp, #S_PSTATE]
+	mov	x0, sp				// 'regs'
+	tst	x2, #PSR_MODE_MASK		// user mode regs?
+	b.ne	no_work_pending			// returning to kernel
+	bl	do_notify_resume
+	b	ret_to_user
+work_resched:
+	enable_dbg
+	bl	schedule
+
+/*
+ * "slow" syscall return path.
+ */
+ENTRY(ret_to_user)
+	disable_irq				// disable interrupts
+	ldr	x1, [tsk, #TI_FLAGS]
+	and	x2, x1, #_TIF_WORK_MASK
+	cbnz	x2, work_pending
+	tbz	x1, #TIF_SINGLESTEP, no_work_pending
+	disable_dbg
+	enable_step x2
+no_work_pending:
+	kernel_exit 0, ret = 0
+ENDPROC(ret_to_user)
+
+/*
+ * This is how we return from a fork.
+ */
+ENTRY(ret_from_fork)
+	bl	schedule_tail
+	get_thread_info tsk
+	b	ret_to_user
+ENDPROC(ret_from_fork)
+
+/*
+ * SVC handler.
+ */
+	.align	6
+el0_svc:
+	adrp	stbl, sys_call_table		// load syscall table pointer
+	uxtw	scno, w8			// syscall number in w8
+	mov	sc_nr, #__NR_syscalls
+el0_svc_naked:					// compat entry point
+	stp	x0, scno, [sp, #S_ORIG_X0]	// save the original x0 and syscall number
+	disable_step x16
+	isb
+	enable_dbg
+	enable_irq
+
+	get_thread_info tsk
+	ldr	x16, [tsk, #TI_FLAGS]		// check for syscall tracing
+	tbnz	x16, #TIF_SYSCALL_TRACE, __sys_trace // are we tracing syscalls?
+	adr	lr, ret_fast_syscall		// return address
+	cmp     scno, sc_nr                     // check upper syscall limit
+	b.hs	ni_sys
+	ldr	x16, [stbl, scno, lsl #3]	// address in the syscall table
+	br	x16				// call sys_* routine
+ni_sys:
+	mov	x0, sp
+	b	do_ni_syscall
+ENDPROC(el0_svc)
+
+	/*
+	 * This is the really slow path.  We're going to be doing context
+	 * switches, and waiting for our parent to respond.
+	 */
+__sys_trace:
+	mov	x1, sp
+	mov	w0, #0				// trace entry
+	bl	syscall_trace
+	adr	lr, __sys_trace_return		// return address
+	uxtw	scno, w0			// syscall number (possibly new)
+	mov	x1, sp				// pointer to regs
+	cmp	scno, sc_nr			// check upper syscall limit
+	b.hs	ni_sys
+	ldp	x0, x1, [sp]			// restore the syscall args
+	ldp	x2, x3, [sp, #S_X2]
+	ldp	x4, x5, [sp, #S_X4]
+	ldp	x6, x7, [sp, #S_X6]
+	ldr	x16, [stbl, scno, lsl #3]	// address in the syscall table
+	br	x16				// call sys_* routine
+
+__sys_trace_return:
+	str	x0, [sp]			// save returned x0
+	mov	x1, sp
+	mov	w0, #1				// trace exit
+	bl	syscall_trace
+	b	ret_to_user
+
+/*
+ * Special system call wrappers.
+ */
+ENTRY(sys_execve_wrapper)
+	mov	x3, sp
+	b	sys_execve
+ENDPROC(sys_execve_wrapper)
+
+ENTRY(sys_clone_wrapper)
+	mov	x5, sp
+	b	sys_clone
+ENDPROC(sys_clone_wrapper)
+
+ENTRY(sys_rt_sigreturn_wrapper)
+	mov	x0, sp
+	b	sys_rt_sigreturn
+ENDPROC(sys_rt_sigreturn_wrapper)
+
+ENTRY(sys_sigaltstack_wrapper)
+	ldr	x2, [sp, #S_SP]
+	b	sys_sigaltstack
+ENDPROC(sys_sigaltstack_wrapper)
+
+ENTRY(handle_arch_irq)
+	.quad	0
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
new file mode 100644
index 0000000..e8b8357
--- /dev/null
+++ b/arch/arm64/kernel/fpsimd.c
@@ -0,0 +1,106 @@
+/*
+ * FP/SIMD context switching and fault handling
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+
+#include <asm/fpsimd.h>
+#include <asm/cputype.h>
+
+#define FPEXC_IOF	(1 << 0)
+#define FPEXC_DZF	(1 << 1)
+#define FPEXC_OFF	(1 << 2)
+#define FPEXC_UFF	(1 << 3)
+#define FPEXC_IXF	(1 << 4)
+#define FPEXC_IDF	(1 << 7)
+
+/*
+ * Trapped FP/ASIMD access.
+ */
+void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
+{
+	/* TODO: implement lazy context saving/restoring */
+	WARN_ON(1);
+}
+
+/*
+ * Raise a SIGFPE for the current process.
+ */
+void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
+{
+	siginfo_t info;
+	unsigned int si_code = 0;
+
+	if (esr & FPEXC_IOF)
+		si_code = FPE_FLTINV;
+	else if (esr & FPEXC_DZF)
+		si_code = FPE_FLTDIV;
+	else if (esr & FPEXC_OFF)
+		si_code = FPE_FLTOVF;
+	else if (esr & FPEXC_UFF)
+		si_code = FPE_FLTUND;
+	else if (esr & FPEXC_IXF)
+		si_code = FPE_FLTRES;
+
+	memset(&info, 0, sizeof(info));
+	info.si_signo = SIGFPE;
+	info.si_code = si_code;
+	info.si_addr = (void __user *)instruction_pointer(regs);
+
+	send_sig_info(SIGFPE, &info, current);
+}
+
+void fpsimd_thread_switch(struct task_struct *next)
+{
+	/* check if not kernel threads */
+	if (current->mm)
+		fpsimd_save_state(&current->thread.fpsimd_state);
+	if (next->mm)
+		fpsimd_load_state(&next->thread.fpsimd_state);
+}
+
+void fpsimd_flush_thread(void)
+{
+	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
+	fpsimd_load_state(&current->thread.fpsimd_state);
+}
+
+/*
+ * FP/SIMD support code initialisation.
+ */
+static int __init fpsimd_init(void)
+{
+	u64 pfr = read_cpuid(ID_AA64PFR0_EL1);
+
+	if (pfr & (0xf << 16)) {
+		pr_notice("Floating-point is not implemented\n");
+		return 0;
+	}
+	elf_hwcap |= HWCAP_FP;
+
+	if (pfr & (0xf << 20))
+		pr_notice("Advanced SIMD is not implemented\n");
+	else
+		elf_hwcap |= HWCAP_ASIMD;
+
+	return 0;
+}
+late_initcall(fpsimd_init);
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
new file mode 100644
index 0000000..a2f02b6
--- /dev/null
+++ b/arch/arm64/kernel/head.S
@@ -0,0 +1,510 @@
+/*
+ * Low-level CPU initialisation
+ * Based on arch/arm/kernel/head.S
+ *
+ * Copyright (C) 1994-2002 Russell King
+ * Copyright (C) 2003-2012 ARM Ltd.
+ * Authors:	Catalin Marinas <catalin.marinas@arm.com>
+ *		Will Deacon <will.deacon@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/assembler.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <asm/memory.h>
+#include <asm/thread_info.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+/*
+ * swapper_pg_dir is the virtual address of the initial page table. We place
+ * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has
+ * 2 pages and is placed below swapper_pg_dir.
+ */
+#define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
+
+#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
+#error KERNEL_RAM_VADDR must start at 0xXXX80000
+#endif
+
+#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
+#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
+
+	.globl	swapper_pg_dir
+	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE
+
+	.globl	idmap_pg_dir
+	.equ	idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE
+
+	.macro	pgtbl, ttb0, ttb1, phys
+	add	\ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE
+	sub	\ttb0, \ttb1, #IDMAP_DIR_SIZE
+	.endm
+
+#ifdef CONFIG_ARM64_64K_PAGES
+#define BLOCK_SHIFT	PAGE_SHIFT
+#define BLOCK_SIZE	PAGE_SIZE
+#else
+#define BLOCK_SHIFT	SECTION_SHIFT
+#define BLOCK_SIZE	SECTION_SIZE
+#endif
+
+#define KERNEL_START	KERNEL_RAM_VADDR
+#define KERNEL_END	_end
+
+/*
+ * Initial memory map attributes.
+ */
+#ifndef CONFIG_SMP
+#define PTE_FLAGS	PTE_TYPE_PAGE | PTE_AF
+#define PMD_FLAGS	PMD_TYPE_SECT | PMD_SECT_AF
+#else
+#define PTE_FLAGS	PTE_TYPE_PAGE | PTE_AF | PTE_SHARED
+#define PMD_FLAGS	PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S
+#endif
+
+#ifdef CONFIG_ARM64_64K_PAGES
+#define MM_MMUFLAGS	PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS
+#define IO_MMUFLAGS	PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS
+#else
+#define MM_MMUFLAGS	PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS
+#define IO_MMUFLAGS	PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS
+#endif
+
+/*
+ * Kernel startup entry point.
+ * ---------------------------
+ *
+ * The requirements are:
+ *   MMU = off, D-cache = off, I-cache = on or off,
+ *   x0 = physical address to the FDT blob.
+ *
+ * This code is mostly position independent so you call this at
+ * __pa(PAGE_OFFSET + TEXT_OFFSET).
+ *
+ * Note that the callee-saved registers are used for storing variables
+ * that are useful before the MMU is enabled. The allocations are described
+ * in the entry routines.
+ */
+	__HEAD
+
+	/*
+	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
+	 */
+	b	stext				// branch to kernel start, magic
+	.long	0				// reserved
+	.quad	TEXT_OFFSET			// Image load offset from start of RAM
+	.quad	0				// reserved
+	.quad	0				// reserved
+
+ENTRY(stext)
+	mov	x21, x0				// x21=FDT
+	bl	el2_setup			// Drop to EL1
+	mrs	x22, midr_el1			// x22=cpuid
+	mov	x0, x22
+	bl	lookup_processor_type
+	mov	x23, x0				// x23=current cpu_table
+	cbz	x23, __error_p			// invalid processor (x23=0)?
+	bl	__calc_phys_offset		// x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
+	bl	__vet_fdt
+	bl	__create_page_tables		// x25=TTBR0, x26=TTBR1
+	/*
+	 * The following calls CPU specific code in a position independent
+	 * manner. See arch/arm64/mm/proc.S for details. x23 = base of
+	 * cpu_info structure selected by lookup_processor_type above.
+	 * On return, the CPU will be ready for the MMU to be turned on and
+	 * the TCR will have been set.
+	 */
+	ldr	x27, __switch_data		// address to jump to after
+						// MMU has been enabled
+	adr	lr, __enable_mmu		// return (PIC) address
+	ldr	x12, [x23, #CPU_INFO_SETUP]
+	add	x12, x12, x28			// __virt_to_phys
+	br	x12				// initialise processor
+ENDPROC(stext)
+
+/*
+ * If we're fortunate enough to boot at EL2, ensure that the world is
+ * sane before dropping to EL1.
+ */
+ENTRY(el2_setup)
+	mrs	x0, CurrentEL
+	cmp	x0, #PSR_MODE_EL2t
+	ccmp	x0, #PSR_MODE_EL2h, #0x4, ne
+	b.eq	1f
+	ret
+
+	/* Hyp configuration. */
+1:	mov	x0, #(1 << 31)			// 64-bit EL1
+	msr	hcr_el2, x0
+
+	/* Generic timers. */
+	mrs	x0, cnthctl_el2
+	orr	x0, x0, #3			// Enable EL1 physical timers
+	msr	cnthctl_el2, x0
+
+	/* Populate ID registers. */
+	mrs	x0, midr_el1
+	mrs	x1, mpidr_el1
+	msr	vpidr_el2, x0
+	msr	vmpidr_el2, x1
+
+	/* sctlr_el1 */
+	mov	x0, #0x0800			// Set/clear RES{1,0} bits
+	movk	x0, #0x30d0, lsl #16
+	msr	sctlr_el1, x0
+
+	/* Coprocessor traps. */
+	mov	x0, #0x33ff
+	msr	cptr_el2, x0			// Disable copro. traps to EL2
+
+#ifdef CONFIG_COMPAT
+	msr	hstr_el2, xzr			// Disable CP15 traps to EL2
+#endif
+
+	/* spsr */
+	mov	x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
+		      PSR_MODE_EL1h)
+	msr	spsr_el2, x0
+	msr	elr_el2, lr
+	eret
+ENDPROC(el2_setup)
+
+	.align	3
+2:	.quad	.
+	.quad	PAGE_OFFSET
+
+#ifdef CONFIG_SMP
+	.pushsection    .smp.pen.text, "ax"
+	.align	3
+1:	.quad	.
+	.quad	secondary_holding_pen_release
+
+	/*
+	 * This provides a "holding pen" for platforms to hold all secondary
+	 * cores are held until we're ready for them to initialise.
+	 */
+ENTRY(secondary_holding_pen)
+	bl	el2_setup			// Drop to EL1
+	mrs	x0, mpidr_el1
+	and	x0, x0, #15			// CPU number
+	adr	x1, 1b
+	ldp	x2, x3, [x1]
+	sub	x1, x1, x2
+	add	x3, x3, x1
+pen:	ldr	x4, [x3]
+	cmp	x4, x0
+	b.eq	secondary_startup
+	wfe
+	b	pen
+ENDPROC(secondary_holding_pen)
+	.popsection
+
+ENTRY(secondary_startup)
+	/*
+	 * Common entry point for secondary CPUs.
+	 */
+	mrs	x22, midr_el1			// x22=cpuid
+	mov	x0, x22
+	bl	lookup_processor_type
+	mov	x23, x0				// x23=current cpu_table
+	cbz	x23, __error_p			// invalid processor (x23=0)?
+
+	bl	__calc_phys_offset		// x24=phys offset
+	pgtbl	x25, x26, x24			// x25=TTBR0, x26=TTBR1
+	ldr	x12, [x23, #CPU_INFO_SETUP]
+	add	x12, x12, x28			// __virt_to_phys
+	blr	x12				// initialise processor
+
+	ldr	x21, =secondary_data
+	ldr	x27, =__secondary_switched	// address to jump to after enabling the MMU
+	b	__enable_mmu
+ENDPROC(secondary_startup)
+
+ENTRY(__secondary_switched)
+	ldr	x0, [x21]			// get secondary_data.stack
+	mov	sp, x0
+	mov	x29, #0
+	b	secondary_start_kernel
+ENDPROC(__secondary_switched)
+#endif	/* CONFIG_SMP */
+
+/*
+ * Setup common bits before finally enabling the MMU. Essentially this is just
+ * loading the page table pointer and vector base registers.
+ *
+ * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on
+ * the MMU.
+ */
+__enable_mmu:
+	ldr	x5, =vectors
+	msr	vbar_el1, x5
+	msr	ttbr0_el1, x25			// load TTBR0
+	msr	ttbr1_el1, x26			// load TTBR1
+	isb
+	b	__turn_mmu_on
+ENDPROC(__enable_mmu)
+
+/*
+ * Enable the MMU. This completely changes the structure of the visible memory
+ * space. You will not be able to trace execution through this.
+ *
+ *  x0  = system control register
+ *  x27 = *virtual* address to jump to upon completion
+ *
+ * other registers depend on the function called upon completion
+ */
+	.align	6
+__turn_mmu_on:
+	msr	sctlr_el1, x0
+	isb
+	br	x27
+ENDPROC(__turn_mmu_on)
+
+/*
+ * Calculate the start of physical memory.
+ */
+__calc_phys_offset:
+	adr	x0, 1f
+	ldp	x1, x2, [x0]
+	sub	x28, x0, x1			// x28 = PHYS_OFFSET - PAGE_OFFSET
+	add	x24, x2, x28			// x24 = PHYS_OFFSET
+	ret
+ENDPROC(__calc_phys_offset)
+
+	.align 3
+1:	.quad	.
+	.quad	PAGE_OFFSET
+
+/*
+ * Macro to populate the PGD for the corresponding block entry in the next
+ * level (tbl) for the given virtual address.
+ *
+ * Preserves:	pgd, tbl, virt
+ * Corrupts:	tmp1, tmp2
+ */
+	.macro	create_pgd_entry, pgd, tbl, virt, tmp1, tmp2
+	lsr	\tmp1, \virt, #PGDIR_SHIFT
+	and	\tmp1, \tmp1, #PTRS_PER_PGD - 1	// PGD index
+	orr	\tmp2, \tbl, #3			// PGD entry table type
+	str	\tmp2, [\pgd, \tmp1, lsl #3]
+	.endm
+
+/*
+ * Macro to populate block entries in the page table for the start..end
+ * virtual range (inclusive).
+ *
+ * Preserves:	tbl, flags
+ * Corrupts:	phys, start, end, pstate
+ */
+	.macro	create_block_map, tbl, flags, phys, start, end, idmap=0
+	lsr	\phys, \phys, #BLOCK_SHIFT
+	.if	\idmap
+	and	\start, \phys, #PTRS_PER_PTE - 1	// table index
+	.else
+	lsr	\start, \start, #BLOCK_SHIFT
+	and	\start, \start, #PTRS_PER_PTE - 1	// table index
+	.endif
+	orr	\phys, \flags, \phys, lsl #BLOCK_SHIFT	// table entry
+	.ifnc	\start,\end
+	lsr	\end, \end, #BLOCK_SHIFT
+	and	\end, \end, #PTRS_PER_PTE - 1		// table end index
+	.endif
+9999:	str	\phys, [\tbl, \start, lsl #3]		// store the entry
+	.ifnc	\start,\end
+	add	\start, \start, #1			// next entry
+	add	\phys, \phys, #BLOCK_SIZE		// next block
+	cmp	\start, \end
+	b.ls	9999b
+	.endif
+	.endm
+
+/*
+ * Setup the initial page tables. We only setup the barest amount which is
+ * required to get the kernel running. The following sections are required:
+ *   - identity mapping to enable the MMU (low address, TTBR0)
+ *   - first few MB of the kernel linear mapping to jump to once the MMU has
+ *     been enabled, including the FDT blob (TTBR1)
+ */
+__create_page_tables:
+	pgtbl	x25, x26, x24			// idmap_pg_dir and swapper_pg_dir addresses
+
+	/*
+	 * Clear the idmap and swapper page tables.
+	 */
+	mov	x0, x25
+	add	x6, x26, #SWAPPER_DIR_SIZE
+1:	stp	xzr, xzr, [x0], #16
+	stp	xzr, xzr, [x0], #16
+	stp	xzr, xzr, [x0], #16
+	stp	xzr, xzr, [x0], #16
+	cmp	x0, x6
+	b.lo	1b
+
+	ldr	x7, =MM_MMUFLAGS
+
+	/*
+	 * Create the identity mapping.
+	 */
+	add	x0, x25, #PAGE_SIZE		// section table address
+	adr	x3, __turn_mmu_on		// virtual/physical address
+	create_pgd_entry x25, x0, x3, x5, x6
+	create_block_map x0, x7, x3, x5, x5, idmap=1
+
+	/*
+	 * Map the kernel image (starting with PHYS_OFFSET).
+	 */
+	add	x0, x26, #PAGE_SIZE		// section table address
+	mov	x5, #PAGE_OFFSET
+	create_pgd_entry x26, x0, x5, x3, x6
+	ldr	x6, =KERNEL_END - 1
+	mov	x3, x24				// phys offset
+	create_block_map x0, x7, x3, x5, x6
+
+	/*
+	 * Map the FDT blob (maximum 2MB; must be within 512MB of
+	 * PHYS_OFFSET).
+	 */
+	mov	x3, x21				// FDT phys address
+	and	x3, x3, #~((1 << 21) - 1)	// 2MB aligned
+	mov	x6, #PAGE_OFFSET
+	sub	x5, x3, x24			// subtract PHYS_OFFSET
+	tst	x5, #~((1 << 29) - 1)		// within 512MB?
+	csel	x21, xzr, x21, ne		// zero the FDT pointer
+	b.ne	1f
+	add	x5, x5, x6			// __va(FDT blob)
+	add	x6, x5, #1 << 21		// 2MB for the FDT blob
+	sub	x6, x6, #1			// inclusive range
+	create_block_map x0, x7, x3, x5, x6
+1:
+	ret
+ENDPROC(__create_page_tables)
+	.ltorg
+
+	.align	3
+	.type	__switch_data, %object
+__switch_data:
+	.quad	__mmap_switched
+	.quad	__data_loc			// x4
+	.quad	_data				// x5
+	.quad	__bss_start			// x6
+	.quad	_end				// x7
+	.quad	processor_id			// x4
+	.quad	__fdt_pointer			// x5
+	.quad	memstart_addr			// x6
+	.quad	init_thread_union + THREAD_START_SP // sp
+
+/*
+ * The following fragment of code is executed with the MMU on in MMU mode, and
+ * uses absolute addresses; this is not position independent.
+ */
+__mmap_switched:
+	adr	x3, __switch_data + 8
+
+	ldp	x4, x5, [x3], #16
+	ldp	x6, x7, [x3], #16
+	cmp	x4, x5				// Copy data segment if needed
+1:	ccmp	x5, x6, #4, ne
+	b.eq	2f
+	ldr	x16, [x4], #8
+	str	x16, [x5], #8
+	b	1b
+2:
+1:	cmp	x6, x7
+	b.hs	2f
+	str	xzr, [x6], #8			// Clear BSS
+	b	1b
+2:
+	ldp	x4, x5, [x3], #16
+	ldr	x6, [x3], #8
+	ldr	x16, [x3]
+	mov	sp, x16
+	str	x22, [x4]			// Save processor ID
+	str	x21, [x5]			// Save FDT pointer
+	str	x24, [x6]			// Save PHYS_OFFSET
+	mov	x29, #0
+	b	start_kernel
+ENDPROC(__mmap_switched)
+
+/*
+ * Exception handling. Something went wrong and we can't proceed. We ought to
+ * tell the user, but since we don't have any guarantee that we're even
+ * running on the right architecture, we do virtually nothing.
+ */
+__error_p:
+ENDPROC(__error_p)
+
+__error:
+1:	nop
+	b	1b
+ENDPROC(__error)
+
+/*
+ * This function gets the processor ID in w0 and searches the cpu_table[] for
+ * a match. It returns a pointer to the struct cpu_info it found. The
+ * cpu_table[] must end with an empty (all zeros) structure.
+ *
+ * This routine can be called via C code and it needs to work with the MMU
+ * both disabled and enabled (the offset is calculated automatically).
+ */
+ENTRY(lookup_processor_type)
+	adr	x1, __lookup_processor_type_data
+	ldp	x2, x3, [x1]
+	sub	x1, x1, x2			// get offset between VA and PA
+	add	x3, x3, x1			// convert VA to PA
+1:
+	ldp	w5, w6, [x3]			// load cpu_id_val and cpu_id_mask
+	cbz	w5, 2f				// end of list?
+	and	w6, w6, w0
+	cmp	w5, w6
+	b.eq	3f
+	add	x3, x3, #CPU_INFO_SZ
+	b	1b
+2:
+	mov	x3, #0				// unknown processor
+3:
+	mov	x0, x3
+	ret
+ENDPROC(lookup_processor_type)
+
+	.align	3
+	.type	__lookup_processor_type_data, %object
+__lookup_processor_type_data:
+	.quad	.
+	.quad	cpu_table
+	.size	__lookup_processor_type_data, . - __lookup_processor_type_data
+
+/*
+ * Determine validity of the x21 FDT pointer.
+ * The dtb must be 8-byte aligned and live in the first 512M of memory.
+ */
+__vet_fdt:
+	tst	x21, #0x7
+	b.ne	1f
+	cmp	x21, x24
+	b.lt	1f
+	mov	x0, #(1 << 29)
+	add	x0, x0, x24
+	cmp	x21, x0
+	b.ge	1f
+	ret
+1:
+	mov	x21, #0
+	ret
+ENDPROC(__vet_fdt)
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
new file mode 100644
index 0000000..5ab825c
--- /dev/null
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -0,0 +1,880 @@
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "hw-breakpoint: " fmt
+
+#include <linux/errno.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+
+#include <asm/compat.h>
+#include <asm/current.h>
+#include <asm/debug-monitors.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/kdebug.h>
+#include <asm/traps.h>
+#include <asm/cputype.h>
+#include <asm/system_misc.h>
+
+/* Breakpoint currently in use for each BRP. */
+static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
+
+/* Watchpoint currently in use for each WRP. */
+static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]);
+
+/* Currently stepping a per-CPU kernel breakpoint. */
+static DEFINE_PER_CPU(int, stepping_kernel_bp);
+
+/* Number of BRP/WRP registers on this CPU. */
+static int core_num_brps;
+static int core_num_wrps;
+
+/* Determine number of BRP registers available. */
+static int get_num_brps(void)
+{
+	return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1;
+}
+
+/* Determine number of WRP registers available. */
+static int get_num_wrps(void)
+{
+	return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1;
+}
+
+int hw_breakpoint_slots(int type)
+{
+	/*
+	 * We can be called early, so don't rely on
+	 * our static variables being initialised.
+	 */
+	switch (type) {
+	case TYPE_INST:
+		return get_num_brps();
+	case TYPE_DATA:
+		return get_num_wrps();
+	default:
+		pr_warning("unknown slot type: %d\n", type);
+		return 0;
+	}
+}
+
+#define READ_WB_REG_CASE(OFF, N, REG, VAL)	\
+	case (OFF + N):				\
+		AARCH64_DBG_READ(N, REG, VAL);	\
+		break
+
+#define WRITE_WB_REG_CASE(OFF, N, REG, VAL)	\
+	case (OFF + N):				\
+		AARCH64_DBG_WRITE(N, REG, VAL);	\
+		break
+
+#define GEN_READ_WB_REG_CASES(OFF, REG, VAL)	\
+	READ_WB_REG_CASE(OFF,  0, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  1, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  2, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  3, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  4, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  5, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  6, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  7, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  8, REG, VAL);	\
+	READ_WB_REG_CASE(OFF,  9, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 10, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 11, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 12, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 13, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 14, REG, VAL);	\
+	READ_WB_REG_CASE(OFF, 15, REG, VAL)
+
+#define GEN_WRITE_WB_REG_CASES(OFF, REG, VAL)	\
+	WRITE_WB_REG_CASE(OFF,  0, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  1, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  2, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  3, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  4, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  5, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  6, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  7, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  8, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF,  9, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 10, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 11, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 12, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 13, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 14, REG, VAL);	\
+	WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
+
+static u64 read_wb_reg(int reg, int n)
+{
+	u64 val = 0;
+
+	switch (reg + n) {
+	GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
+	GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
+	GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
+	GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
+	default:
+		pr_warning("attempt to read from unknown breakpoint register %d\n", n);
+	}
+
+	return val;
+}
+
+static void write_wb_reg(int reg, int n, u64 val)
+{
+	switch (reg + n) {
+	GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
+	GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
+	GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
+	GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
+	default:
+		pr_warning("attempt to write to unknown breakpoint register %d\n", n);
+	}
+	isb();
+}
+
+/*
+ * Convert a breakpoint privilege level to the corresponding exception
+ * level.
+ */
+static enum debug_el debug_exception_level(int privilege)
+{
+	switch (privilege) {
+	case AARCH64_BREAKPOINT_EL0:
+		return DBG_ACTIVE_EL0;
+	case AARCH64_BREAKPOINT_EL1:
+		return DBG_ACTIVE_EL1;
+	default:
+		pr_warning("invalid breakpoint privilege level %d\n", privilege);
+		return -EINVAL;
+	}
+}
+
+/*
+ * Install a perf counter breakpoint.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	struct perf_event **slot, **slots;
+	struct debug_info *debug_info = &current->thread.debug;
+	int i, max_slots, ctrl_reg, val_reg, reg_enable;
+	u32 ctrl;
+
+	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+		/* Breakpoint */
+		ctrl_reg = AARCH64_DBG_REG_BCR;
+		val_reg = AARCH64_DBG_REG_BVR;
+		slots = __get_cpu_var(bp_on_reg);
+		max_slots = core_num_brps;
+		reg_enable = !debug_info->bps_disabled;
+	} else {
+		/* Watchpoint */
+		ctrl_reg = AARCH64_DBG_REG_WCR;
+		val_reg = AARCH64_DBG_REG_WVR;
+		slots = __get_cpu_var(wp_on_reg);
+		max_slots = core_num_wrps;
+		reg_enable = !debug_info->wps_disabled;
+	}
+
+	for (i = 0; i < max_slots; ++i) {
+		slot = &slots[i];
+
+		if (!*slot) {
+			*slot = bp;
+			break;
+		}
+	}
+
+	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+		return -ENOSPC;
+
+	/* Ensure debug monitors are enabled at the correct exception level.  */
+	enable_debug_monitors(debug_exception_level(info->ctrl.privilege));
+
+	/* Setup the address register. */
+	write_wb_reg(val_reg, i, info->address);
+
+	/* Setup the control register. */
+	ctrl = encode_ctrl_reg(info->ctrl);
+	write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1);
+
+	return 0;
+}
+
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	struct perf_event **slot, **slots;
+	int i, max_slots, base;
+
+	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+		/* Breakpoint */
+		base = AARCH64_DBG_REG_BCR;
+		slots = __get_cpu_var(bp_on_reg);
+		max_slots = core_num_brps;
+	} else {
+		/* Watchpoint */
+		base = AARCH64_DBG_REG_WCR;
+		slots = __get_cpu_var(wp_on_reg);
+		max_slots = core_num_wrps;
+	}
+
+	/* Remove the breakpoint. */
+	for (i = 0; i < max_slots; ++i) {
+		slot = &slots[i];
+
+		if (*slot == bp) {
+			*slot = NULL;
+			break;
+		}
+	}
+
+	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+		return;
+
+	/* Reset the control register. */
+	write_wb_reg(base, i, 0);
+
+	/* Release the debug monitors for the correct exception level.  */
+	disable_debug_monitors(debug_exception_level(info->ctrl.privilege));
+}
+
+static int get_hbp_len(u8 hbp_len)
+{
+	unsigned int len_in_bytes = 0;
+
+	switch (hbp_len) {
+	case ARM_BREAKPOINT_LEN_1:
+		len_in_bytes = 1;
+		break;
+	case ARM_BREAKPOINT_LEN_2:
+		len_in_bytes = 2;
+		break;
+	case ARM_BREAKPOINT_LEN_4:
+		len_in_bytes = 4;
+		break;
+	case ARM_BREAKPOINT_LEN_8:
+		len_in_bytes = 8;
+		break;
+	}
+
+	return len_in_bytes;
+}
+
+/*
+ * Check whether bp virtual address is in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct perf_event *bp)
+{
+	unsigned int len;
+	unsigned long va;
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+	va = info->address;
+	len = get_hbp_len(info->ctrl.len);
+
+	return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl.
+ * Hopefully this will disappear when ptrace can bypass the conversion
+ * to generic breakpoint descriptions.
+ */
+int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+			   int *gen_len, int *gen_type)
+{
+	/* Type */
+	switch (ctrl.type) {
+	case ARM_BREAKPOINT_EXECUTE:
+		*gen_type = HW_BREAKPOINT_X;
+		break;
+	case ARM_BREAKPOINT_LOAD:
+		*gen_type = HW_BREAKPOINT_R;
+		break;
+	case ARM_BREAKPOINT_STORE:
+		*gen_type = HW_BREAKPOINT_W;
+		break;
+	case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE:
+		*gen_type = HW_BREAKPOINT_RW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Len */
+	switch (ctrl.len) {
+	case ARM_BREAKPOINT_LEN_1:
+		*gen_len = HW_BREAKPOINT_LEN_1;
+		break;
+	case ARM_BREAKPOINT_LEN_2:
+		*gen_len = HW_BREAKPOINT_LEN_2;
+		break;
+	case ARM_BREAKPOINT_LEN_4:
+		*gen_len = HW_BREAKPOINT_LEN_4;
+		break;
+	case ARM_BREAKPOINT_LEN_8:
+		*gen_len = HW_BREAKPOINT_LEN_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Construct an arch_hw_breakpoint from a perf_event.
+ */
+static int arch_build_bp_info(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+	/* Type */
+	switch (bp->attr.bp_type) {
+	case HW_BREAKPOINT_X:
+		info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
+		break;
+	case HW_BREAKPOINT_R:
+		info->ctrl.type = ARM_BREAKPOINT_LOAD;
+		break;
+	case HW_BREAKPOINT_W:
+		info->ctrl.type = ARM_BREAKPOINT_STORE;
+		break;
+	case HW_BREAKPOINT_RW:
+		info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Len */
+	switch (bp->attr.bp_len) {
+	case HW_BREAKPOINT_LEN_1:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_1;
+		break;
+	case HW_BREAKPOINT_LEN_2:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_2;
+		break;
+	case HW_BREAKPOINT_LEN_4:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+		break;
+	case HW_BREAKPOINT_LEN_8:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * On AArch64, we only permit breakpoints of length 4, whereas
+	 * AArch32 also requires breakpoints of length 2 for Thumb.
+	 * Watchpoints can be of length 1, 2, 4 or 8 bytes.
+	 */
+	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+		if (is_compat_task()) {
+			if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
+			    info->ctrl.len != ARM_BREAKPOINT_LEN_4)
+				return -EINVAL;
+		} else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) {
+			/*
+			 * FIXME: Some tools (I'm looking at you perf) assume
+			 *	  that breakpoints should be sizeof(long). This
+			 *	  is nonsense. For now, we fix up the parameter
+			 *	  but we should probably return -EINVAL instead.
+			 */
+			info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+		}
+	}
+
+	/* Address */
+	info->address = bp->attr.bp_addr;
+
+	/*
+	 * Privilege
+	 * Note that we disallow combined EL0/EL1 breakpoints because
+	 * that would complicate the stepping code.
+	 */
+	if (arch_check_bp_in_kernelspace(bp))
+		info->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
+	else
+		info->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
+
+	/* Enabled? */
+	info->ctrl.enabled = !bp->attr.disabled;
+
+	return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings.
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	int ret;
+	u64 alignment_mask, offset;
+
+	/* Build the arch_hw_breakpoint. */
+	ret = arch_build_bp_info(bp);
+	if (ret)
+		return ret;
+
+	/*
+	 * Check address alignment.
+	 * We don't do any clever alignment correction for watchpoints
+	 * because using 64-bit unaligned addresses is deprecated for
+	 * AArch64.
+	 *
+	 * AArch32 tasks expect some simple alignment fixups, so emulate
+	 * that here.
+	 */
+	if (is_compat_task()) {
+		if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+			alignment_mask = 0x7;
+		else
+			alignment_mask = 0x3;
+		offset = info->address & alignment_mask;
+		switch (offset) {
+		case 0:
+			/* Aligned */
+			break;
+		case 1:
+			/* Allow single byte watchpoint. */
+			if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+				break;
+		case 2:
+			/* Allow halfword watchpoints and breakpoints. */
+			if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
+				break;
+		default:
+			return -EINVAL;
+		}
+
+		info->address &= ~alignment_mask;
+		info->ctrl.len <<= offset;
+	} else {
+		if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
+			alignment_mask = 0x3;
+		else
+			alignment_mask = 0x7;
+		if (info->address & alignment_mask)
+			return -EINVAL;
+	}
+
+	/*
+	 * Disallow per-task kernel breakpoints since these would
+	 * complicate the stepping code.
+	 */
+	if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.bp_target)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Enable/disable all of the breakpoints active at the specified
+ * exception level at the register level.
+ * This is used when single-stepping after a breakpoint exception.
+ */
+static void toggle_bp_registers(int reg, enum debug_el el, int enable)
+{
+	int i, max_slots, privilege;
+	u32 ctrl;
+	struct perf_event **slots;
+
+	switch (reg) {
+	case AARCH64_DBG_REG_BCR:
+		slots = __get_cpu_var(bp_on_reg);
+		max_slots = core_num_brps;
+		break;
+	case AARCH64_DBG_REG_WCR:
+		slots = __get_cpu_var(wp_on_reg);
+		max_slots = core_num_wrps;
+		break;
+	default:
+		return;
+	}
+
+	for (i = 0; i < max_slots; ++i) {
+		if (!slots[i])
+			continue;
+
+		privilege = counter_arch_bp(slots[i])->ctrl.privilege;
+		if (debug_exception_level(privilege) != el)
+			continue;
+
+		ctrl = read_wb_reg(reg, i);
+		if (enable)
+			ctrl |= 0x1;
+		else
+			ctrl &= ~0x1;
+		write_wb_reg(reg, i, ctrl);
+	}
+}
+
+/*
+ * Debug exception handlers.
+ */
+static int breakpoint_handler(unsigned long unused, unsigned int esr,
+			      struct pt_regs *regs)
+{
+	int i, step = 0, *kernel_step;
+	u32 ctrl_reg;
+	u64 addr, val;
+	struct perf_event *bp, **slots;
+	struct debug_info *debug_info;
+	struct arch_hw_breakpoint_ctrl ctrl;
+
+	slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
+	addr = instruction_pointer(regs);
+	debug_info = &current->thread.debug;
+
+	for (i = 0; i < core_num_brps; ++i) {
+		rcu_read_lock();
+
+		bp = slots[i];
+
+		if (bp == NULL)
+			goto unlock;
+
+		/* Check if the breakpoint value matches. */
+		val = read_wb_reg(AARCH64_DBG_REG_BVR, i);
+		if (val != (addr & ~0x3))
+			goto unlock;
+
+		/* Possible match, check the byte address select to confirm. */
+		ctrl_reg = read_wb_reg(AARCH64_DBG_REG_BCR, i);
+		decode_ctrl_reg(ctrl_reg, &ctrl);
+		if (!((1 << (addr & 0x3)) & ctrl.len))
+			goto unlock;
+
+		counter_arch_bp(bp)->trigger = addr;
+		perf_bp_event(bp, regs);
+
+		/* Do we need to handle the stepping? */
+		if (!bp->overflow_handler)
+			step = 1;
+unlock:
+		rcu_read_unlock();
+	}
+
+	if (!step)
+		return 0;
+
+	if (user_mode(regs)) {
+		debug_info->bps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0);
+
+		/* If we're already stepping a watchpoint, just return. */
+		if (debug_info->wps_disabled)
+			return 0;
+
+		if (test_thread_flag(TIF_SINGLESTEP))
+			debug_info->suspended_step = 1;
+		else
+			user_enable_single_step(current);
+	} else {
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL1, 0);
+		kernel_step = &__get_cpu_var(stepping_kernel_bp);
+
+		if (*kernel_step != ARM_KERNEL_STEP_NONE)
+			return 0;
+
+		if (kernel_active_single_step()) {
+			*kernel_step = ARM_KERNEL_STEP_SUSPEND;
+		} else {
+			*kernel_step = ARM_KERNEL_STEP_ACTIVE;
+			kernel_enable_single_step(regs);
+		}
+	}
+
+	return 0;
+}
+
+static int watchpoint_handler(unsigned long addr, unsigned int esr,
+			      struct pt_regs *regs)
+{
+	int i, step = 0, *kernel_step, access;
+	u32 ctrl_reg;
+	u64 val, alignment_mask;
+	struct perf_event *wp, **slots;
+	struct debug_info *debug_info;
+	struct arch_hw_breakpoint *info;
+	struct arch_hw_breakpoint_ctrl ctrl;
+
+	slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
+	debug_info = &current->thread.debug;
+
+	for (i = 0; i < core_num_wrps; ++i) {
+		rcu_read_lock();
+
+		wp = slots[i];
+
+		if (wp == NULL)
+			goto unlock;
+
+		info = counter_arch_bp(wp);
+		/* AArch32 watchpoints are either 4 or 8 bytes aligned. */
+		if (is_compat_task()) {
+			if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+				alignment_mask = 0x7;
+			else
+				alignment_mask = 0x3;
+		} else {
+			alignment_mask = 0x7;
+		}
+
+		/* Check if the watchpoint value matches. */
+		val = read_wb_reg(AARCH64_DBG_REG_WVR, i);
+		if (val != (addr & ~alignment_mask))
+			goto unlock;
+
+		/* Possible match, check the byte address select to confirm. */
+		ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i);
+		decode_ctrl_reg(ctrl_reg, &ctrl);
+		if (!((1 << (addr & alignment_mask)) & ctrl.len))
+			goto unlock;
+
+		/*
+		 * Check that the access type matches.
+		 * 0 => load, otherwise => store
+		 */
+		access = (esr & AARCH64_ESR_ACCESS_MASK) ? HW_BREAKPOINT_W :
+			 HW_BREAKPOINT_R;
+		if (!(access & hw_breakpoint_type(wp)))
+			goto unlock;
+
+		info->trigger = addr;
+		perf_bp_event(wp, regs);
+
+		/* Do we need to handle the stepping? */
+		if (!wp->overflow_handler)
+			step = 1;
+
+unlock:
+		rcu_read_unlock();
+	}
+
+	if (!step)
+		return 0;
+
+	/*
+	 * We always disable EL0 watchpoints because the kernel can
+	 * cause these to fire via an unprivileged access.
+	 */
+	toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0);
+
+	if (user_mode(regs)) {
+		debug_info->wps_disabled = 1;
+
+		/* If we're already stepping a breakpoint, just return. */
+		if (debug_info->bps_disabled)
+			return 0;
+
+		if (test_thread_flag(TIF_SINGLESTEP))
+			debug_info->suspended_step = 1;
+		else
+			user_enable_single_step(current);
+	} else {
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL1, 0);
+		kernel_step = &__get_cpu_var(stepping_kernel_bp);
+
+		if (*kernel_step != ARM_KERNEL_STEP_NONE)
+			return 0;
+
+		if (kernel_active_single_step()) {
+			*kernel_step = ARM_KERNEL_STEP_SUSPEND;
+		} else {
+			*kernel_step = ARM_KERNEL_STEP_ACTIVE;
+			kernel_enable_single_step(regs);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Handle single-step exception.
+ */
+int reinstall_suspended_bps(struct pt_regs *regs)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+	int handled_exception = 0, *kernel_step;
+
+	kernel_step = &__get_cpu_var(stepping_kernel_bp);
+
+	/*
+	 * Called from single-step exception handler.
+	 * Return 0 if execution can resume, 1 if a SIGTRAP should be
+	 * reported.
+	 */
+	if (user_mode(regs)) {
+		if (debug_info->bps_disabled) {
+			debug_info->bps_disabled = 0;
+			toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1);
+			handled_exception = 1;
+		}
+
+		if (debug_info->wps_disabled) {
+			debug_info->wps_disabled = 0;
+			toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+			handled_exception = 1;
+		}
+
+		if (handled_exception) {
+			if (debug_info->suspended_step) {
+				debug_info->suspended_step = 0;
+				/* Allow exception handling to fall-through. */
+				handled_exception = 0;
+			} else {
+				user_disable_single_step(current);
+			}
+		}
+	} else if (*kernel_step != ARM_KERNEL_STEP_NONE) {
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL1, 1);
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL1, 1);
+
+		if (!debug_info->wps_disabled)
+			toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+
+		if (*kernel_step != ARM_KERNEL_STEP_SUSPEND) {
+			kernel_disable_single_step();
+			handled_exception = 1;
+		} else {
+			handled_exception = 0;
+		}
+
+		*kernel_step = ARM_KERNEL_STEP_NONE;
+	}
+
+	return !handled_exception;
+}
+
+/*
+ * Context-switcher for restoring suspended breakpoints.
+ */
+void hw_breakpoint_thread_switch(struct task_struct *next)
+{
+	/*
+	 *           current        next
+	 * disabled: 0              0     => The usual case, NOTIFY_DONE
+	 *           0              1     => Disable the registers
+	 *           1              0     => Enable the registers
+	 *           1              1     => NOTIFY_DONE. per-task bps will
+	 *                                   get taken care of by perf.
+	 */
+
+	struct debug_info *current_debug_info, *next_debug_info;
+
+	current_debug_info = &current->thread.debug;
+	next_debug_info = &next->thread.debug;
+
+	/* Update breakpoints. */
+	if (current_debug_info->bps_disabled != next_debug_info->bps_disabled)
+		toggle_bp_registers(AARCH64_DBG_REG_BCR,
+				    DBG_ACTIVE_EL0,
+				    !next_debug_info->bps_disabled);
+
+	/* Update watchpoints. */
+	if (current_debug_info->wps_disabled != next_debug_info->wps_disabled)
+		toggle_bp_registers(AARCH64_DBG_REG_WCR,
+				    DBG_ACTIVE_EL0,
+				    !next_debug_info->wps_disabled);
+}
+
+/*
+ * CPU initialisation.
+ */
+static void reset_ctrl_regs(void *unused)
+{
+	int i;
+
+	for (i = 0; i < core_num_brps; ++i) {
+		write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL);
+		write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL);
+	}
+
+	for (i = 0; i < core_num_wrps; ++i) {
+		write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL);
+		write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
+	}
+}
+
+static int __cpuinit hw_breakpoint_reset_notify(struct notifier_block *self,
+						unsigned long action,
+						void *hcpu)
+{
+	int cpu = (long)hcpu;
+	if (action == CPU_ONLINE)
+		smp_call_function_single(cpu, reset_ctrl_regs, NULL, 1);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata hw_breakpoint_reset_nb = {
+	.notifier_call = hw_breakpoint_reset_notify,
+};
+
+/*
+ * One-time initialisation.
+ */
+static int __init arch_hw_breakpoint_init(void)
+{
+	core_num_brps = get_num_brps();
+	core_num_wrps = get_num_wrps();
+
+	pr_info("found %d breakpoint and %d watchpoint registers.\n",
+		core_num_brps, core_num_wrps);
+
+	/*
+	 * Reset the breakpoint resources. We assume that a halting
+	 * debugger will leave the world in a nice state for us.
+	 */
+	smp_call_function(reset_ctrl_regs, NULL, 1);
+	reset_ctrl_regs(NULL);
+
+	/* Register debug fault handlers. */
+	hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
+			      TRAP_HWBKPT, "hw-breakpoint handler");
+	hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP,
+			      TRAP_HWBKPT, "hw-watchpoint handler");
+
+	/* Register hotplug notifier. */
+	register_cpu_notifier(&hw_breakpoint_reset_nb);
+
+	return 0;
+}
+arch_initcall(arch_hw_breakpoint_init);
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+}
+
+/*
+ * Dummy function to register with die_notifier.
+ */
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+				    unsigned long val, void *data)
+{
+	return NOTIFY_DONE;
+}
diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c
new file mode 100644
index 0000000..7d37ead
--- /dev/null
+++ b/arch/arm64/kernel/io.c
@@ -0,0 +1,64 @@
+/*
+ * Based on arch/arm/kernel/io.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ */
+void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
+{
+	unsigned char *t = to;
+	while (count) {
+		count--;
+		*t = readb(from);
+		t++;
+		from++;
+	}
+}
+EXPORT_SYMBOL(__memcpy_fromio);
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ */
+void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
+{
+	const unsigned char *f = from;
+	while (count) {
+		count--;
+		writeb(*f, to);
+		f++;
+		to++;
+	}
+}
+EXPORT_SYMBOL(__memcpy_toio);
+
+/*
+ * "memset" on IO memory space.
+ */
+void __memset_io(volatile void __iomem *dst, int c, size_t count)
+{
+	while (count) {
+		count--;
+		writeb(c, dst);
+		dst++;
+	}
+}
+EXPORT_SYMBOL(__memset_io);
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
new file mode 100644
index 0000000..0373c66
--- /dev/null
+++ b/arch/arm64/kernel/irq.c
@@ -0,0 +1,84 @@
+/*
+ * Based on arch/arm/kernel/irq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
+ * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
+ * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/seq_file.h>
+#include <linux/ratelimit.h>
+
+unsigned long irq_err_count;
+
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+#ifdef CONFIG_SMP
+	show_ipi_list(p, prec);
+#endif
+	seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
+	return 0;
+}
+
+/*
+ * handle_IRQ handles all hardware IRQ's.  Decoded IRQs should
+ * not come via this function.  Instead, they should provide their
+ * own 'handler'.  Used by platform code implementing C-based 1st
+ * level decoding.
+ */
+void handle_IRQ(unsigned int irq, struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	irq_enter();
+
+	/*
+	 * Some hardware gives randomly wrong interrupts.  Rather
+	 * than crashing, do something sensible.
+	 */
+	if (unlikely(irq >= nr_irqs)) {
+		pr_warn_ratelimited("Bad IRQ%u\n", irq);
+		ack_bad_irq(irq);
+	} else {
+		generic_handle_irq(irq);
+	}
+
+	irq_exit();
+	set_irq_regs(old_regs);
+}
+
+/*
+ * Interrupt controllers supported by the kernel.
+ */
+static const struct of_device_id intctrl_of_match[] __initconst = {
+	/* IRQ controllers { .compatible, .data } info to go here */
+	{}
+};
+
+void __init init_IRQ(void)
+{
+	of_irq_init(intctrl_of_match);
+
+	if (!handle_arch_irq)
+		panic("No interrupt controller found.");
+}
diff --git a/arch/arm64/kernel/kuser32.S b/arch/arm64/kernel/kuser32.S
new file mode 100644
index 0000000..8b69ecb
--- /dev/null
+++ b/arch/arm64/kernel/kuser32.S
@@ -0,0 +1,77 @@
+/*
+ * Low-level user helpers placed in the vectors page for AArch32.
+ * Based on the kuser helpers in arch/arm/kernel/entry-armv.S.
+ *
+ * Copyright (C) 2005-2011 Nicolas Pitre <nico@fluxnic.net>
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * AArch32 user helpers.
+ *
+ * Each segment is 32-byte aligned and will be moved to the top of the high
+ * vector page.  New segments (if ever needed) must be added in front of
+ * existing ones.  This mechanism should be used only for things that are
+ * really small and justified, and not be abused freely.
+ *
+ * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
+ */
+	.align	5
+	.globl	__kuser_helper_start
+__kuser_helper_start:
+
+__kuser_cmpxchg64:			// 0xffff0f60
+	.inst	0xe92d00f0		//	push		{r4, r5, r6, r7}
+	.inst	0xe1c040d0		//	ldrd		r4, r5, [r0]
+	.inst	0xe1c160d0		//	ldrd		r6, r7, [r1]
+	.inst	0xf57ff05f		//	dmb		sy
+	.inst	0xe1b20f9f		// 1:	ldrexd		r0, r1, [r2]
+	.inst	0xe0303004		//	eors		r3, r0, r4
+	.inst	0x00313005		//	eoreqs		r3, r1, r5
+	.inst	0x01a23f96		//	strexdeq	r3, r6, [r2]
+	.inst	0x03330001		//	teqeq		r3, #1
+	.inst	0x0afffff9		//	beq		1b
+	.inst	0xf57ff05f		//	dmb		sy
+	.inst	0xe2730000		//	rsbs		r0, r3, #0
+	.inst	0xe8bd00f0		//	pop		{r4, r5, r6, r7}
+	.inst	0xe12fff1e		//	bx		lr
+
+	.align	5
+__kuser_memory_barrier:			// 0xffff0fa0
+	.inst	0xf57ff05f		//	dmb		sy
+	.inst	0xe12fff1e		//	bx		lr
+
+	.align	5
+__kuser_cmpxchg:			// 0xffff0fc0
+	.inst	0xf57ff05f		//	dmb		sy
+	.inst	0xe1923f9f		// 1:	ldrex		r3, [r2]
+	.inst	0xe0533000		//	subs		r3, r3, r0
+	.inst	0x01823f91		//	strexeq	r3, r1, [r2]
+	.inst	0x03330001		//	teqeq		r3, #1
+	.inst	0x0afffffa		//	beq		1b
+	.inst	0xe2730000		//	rsbs		r0, r3, #0
+	.inst	0xeaffffef		//	b		<__kuser_memory_barrier>
+
+	.align	5
+__kuser_get_tls:			// 0xffff0fe0
+	.inst	0xee1d0f70		//	mrc		p15, 0, r0, c13, c0, 3
+	.inst	0xe12fff1e		//	bx		lr
+	.rep	5
+	.word	0
+	.endr
+
+__kuser_helper_version:			// 0xffff0ffc
+	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)
+	.globl	__kuser_helper_end
+__kuser_helper_end:
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
new file mode 100644
index 0000000..ca0e3d5
--- /dev/null
+++ b/arch/arm64/kernel/module.c
@@ -0,0 +1,456 @@
+/*
+ * AArch64 loadable module support.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/elf.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleloader.h>
+#include <linux/vmalloc.h>
+
+void *module_alloc(unsigned long size)
+{
+	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+				    GFP_KERNEL, PAGE_KERNEL_EXEC, -1,
+				    __builtin_return_address(0));
+}
+
+enum aarch64_reloc_op {
+	RELOC_OP_NONE,
+	RELOC_OP_ABS,
+	RELOC_OP_PREL,
+	RELOC_OP_PAGE,
+};
+
+static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val)
+{
+	switch (reloc_op) {
+	case RELOC_OP_ABS:
+		return val;
+	case RELOC_OP_PREL:
+		return val - (u64)place;
+	case RELOC_OP_PAGE:
+		return (val & ~0xfff) - ((u64)place & ~0xfff);
+	case RELOC_OP_NONE:
+		return 0;
+	}
+
+	pr_err("do_reloc: unknown relocation operation %d\n", reloc_op);
+	return 0;
+}
+
+static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
+{
+	u64 imm_mask = (1 << len) - 1;
+	s64 sval = do_reloc(op, place, val);
+
+	switch (len) {
+	case 16:
+		*(s16 *)place = sval;
+		break;
+	case 32:
+		*(s32 *)place = sval;
+		break;
+	case 64:
+		*(s64 *)place = sval;
+		break;
+	default:
+		pr_err("Invalid length (%d) for data relocation\n", len);
+		return 0;
+	}
+
+	/*
+	 * Extract the upper value bits (including the sign bit) and
+	 * shift them to bit 0.
+	 */
+	sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+	/*
+	 * Overflow has occurred if the value is not representable in
+	 * len bits (i.e the bottom len bits are not sign-extended and
+	 * the top bits are not all zero).
+	 */
+	if ((u64)(sval + 1) > 2)
+		return -ERANGE;
+
+	return 0;
+}
+
+enum aarch64_imm_type {
+	INSN_IMM_MOVNZ,
+	INSN_IMM_MOVK,
+	INSN_IMM_ADR,
+	INSN_IMM_26,
+	INSN_IMM_19,
+	INSN_IMM_16,
+	INSN_IMM_14,
+	INSN_IMM_12,
+	INSN_IMM_9,
+};
+
+static u32 encode_insn_immediate(enum aarch64_imm_type type, u32 insn, u64 imm)
+{
+	u32 immlo, immhi, lomask, himask, mask;
+	int shift;
+
+	switch (type) {
+	case INSN_IMM_MOVNZ:
+		/*
+		 * For signed MOVW relocations, we have to manipulate the
+		 * instruction encoding depending on whether or not the
+		 * immediate is less than zero.
+		 */
+		insn &= ~(3 << 29);
+		if ((s64)imm >= 0) {
+			/* >=0: Set the instruction to MOVZ (opcode 10b). */
+			insn |= 2 << 29;
+		} else {
+			/*
+			 * <0: Set the instruction to MOVN (opcode 00b).
+			 *     Since we've masked the opcode already, we
+			 *     don't need to do anything other than
+			 *     inverting the new immediate field.
+			 */
+			imm = ~imm;
+		}
+	case INSN_IMM_MOVK:
+		mask = BIT(16) - 1;
+		shift = 5;
+		break;
+	case INSN_IMM_ADR:
+		lomask = 0x3;
+		himask = 0x7ffff;
+		immlo = imm & lomask;
+		imm >>= 2;
+		immhi = imm & himask;
+		imm = (immlo << 24) | (immhi);
+		mask = (lomask << 24) | (himask);
+		shift = 5;
+		break;
+	case INSN_IMM_26:
+		mask = BIT(26) - 1;
+		shift = 0;
+		break;
+	case INSN_IMM_19:
+		mask = BIT(19) - 1;
+		shift = 5;
+		break;
+	case INSN_IMM_16:
+		mask = BIT(16) - 1;
+		shift = 5;
+		break;
+	case INSN_IMM_14:
+		mask = BIT(14) - 1;
+		shift = 5;
+		break;
+	case INSN_IMM_12:
+		mask = BIT(12) - 1;
+		shift = 10;
+		break;
+	case INSN_IMM_9:
+		mask = BIT(9) - 1;
+		shift = 12;
+		break;
+	default:
+		pr_err("encode_insn_immediate: unknown immediate encoding %d\n",
+			type);
+		return 0;
+	}
+
+	/* Update the immediate field. */
+	insn &= ~(mask << shift);
+	insn |= (imm & mask) << shift;
+
+	return insn;
+}
+
+static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
+			   int lsb, enum aarch64_imm_type imm_type)
+{
+	u64 imm, limit = 0;
+	s64 sval;
+	u32 insn = *(u32 *)place;
+
+	sval = do_reloc(op, place, val);
+	sval >>= lsb;
+	imm = sval & 0xffff;
+
+	/* Update the instruction with the new encoding. */
+	*(u32 *)place = encode_insn_immediate(imm_type, insn, imm);
+
+	/* Shift out the immediate field. */
+	sval >>= 16;
+
+	/*
+	 * For unsigned immediates, the overflow check is straightforward.
+	 * For signed immediates, the sign bit is actually the bit past the
+	 * most significant bit of the field.
+	 * The INSN_IMM_16 immediate type is unsigned.
+	 */
+	if (imm_type != INSN_IMM_16) {
+		sval++;
+		limit++;
+	}
+
+	/* Check the upper bits depending on the sign of the immediate. */
+	if ((u64)sval > limit)
+		return -ERANGE;
+
+	return 0;
+}
+
+static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val,
+			  int lsb, int len, enum aarch64_imm_type imm_type)
+{
+	u64 imm, imm_mask;
+	s64 sval;
+	u32 insn = *(u32 *)place;
+
+	/* Calculate the relocation value. */
+	sval = do_reloc(op, place, val);
+	sval >>= lsb;
+
+	/* Extract the value bits and shift them to bit 0. */
+	imm_mask = (BIT(lsb + len) - 1) >> lsb;
+	imm = sval & imm_mask;
+
+	/* Update the instruction's immediate field. */
+	*(u32 *)place = encode_insn_immediate(imm_type, insn, imm);
+
+	/*
+	 * Extract the upper value bits (including the sign bit) and
+	 * shift them to bit 0.
+	 */
+	sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+	/*
+	 * Overflow has occurred if the upper bits are not all equal to
+	 * the sign bit of the value.
+	 */
+	if ((u64)(sval + 1) >= 2)
+		return -ERANGE;
+
+	return 0;
+}
+
+int apply_relocate_add(Elf64_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	unsigned int i;
+	int ovf;
+	bool overflow_check;
+	Elf64_Sym *sym;
+	void *loc;
+	u64 val;
+	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* loc corresponds to P in the AArch64 ELF document. */
+		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+
+		/* sym is the ELF symbol we're referring to. */
+		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+			+ ELF64_R_SYM(rel[i].r_info);
+
+		/* val corresponds to (S + A) in the AArch64 ELF document. */
+		val = sym->st_value + rel[i].r_addend;
+
+		/* Check for overflow by default. */
+		overflow_check = true;
+
+		/* Perform the static relocation. */
+		switch (ELF64_R_TYPE(rel[i].r_info)) {
+		/* Null relocations. */
+		case R_ARM_NONE:
+		case R_AARCH64_NONE:
+			ovf = 0;
+			break;
+
+		/* Data relocations. */
+		case R_AARCH64_ABS64:
+			overflow_check = false;
+			ovf = reloc_data(RELOC_OP_ABS, loc, val, 64);
+			break;
+		case R_AARCH64_ABS32:
+			ovf = reloc_data(RELOC_OP_ABS, loc, val, 32);
+			break;
+		case R_AARCH64_ABS16:
+			ovf = reloc_data(RELOC_OP_ABS, loc, val, 16);
+			break;
+		case R_AARCH64_PREL64:
+			overflow_check = false;
+			ovf = reloc_data(RELOC_OP_PREL, loc, val, 64);
+			break;
+		case R_AARCH64_PREL32:
+			ovf = reloc_data(RELOC_OP_PREL, loc, val, 32);
+			break;
+		case R_AARCH64_PREL16:
+			ovf = reloc_data(RELOC_OP_PREL, loc, val, 16);
+			break;
+
+		/* MOVW instruction relocations. */
+		case R_AARCH64_MOVW_UABS_G0_NC:
+			overflow_check = false;
+		case R_AARCH64_MOVW_UABS_G0:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
+					      INSN_IMM_16);
+			break;
+		case R_AARCH64_MOVW_UABS_G1_NC:
+			overflow_check = false;
+		case R_AARCH64_MOVW_UABS_G1:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
+					      INSN_IMM_16);
+			break;
+		case R_AARCH64_MOVW_UABS_G2_NC:
+			overflow_check = false;
+		case R_AARCH64_MOVW_UABS_G2:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
+					      INSN_IMM_16);
+			break;
+		case R_AARCH64_MOVW_UABS_G3:
+			/* We're using the top bits so we can't overflow. */
+			overflow_check = false;
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48,
+					      INSN_IMM_16);
+			break;
+		case R_AARCH64_MOVW_SABS_G0:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_SABS_G1:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_SABS_G2:
+			ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_PREL_G0_NC:
+			overflow_check = false;
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
+					      INSN_IMM_MOVK);
+			break;
+		case R_AARCH64_MOVW_PREL_G0:
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_PREL_G1_NC:
+			overflow_check = false;
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
+					      INSN_IMM_MOVK);
+			break;
+		case R_AARCH64_MOVW_PREL_G1:
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_PREL_G2_NC:
+			overflow_check = false;
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
+					      INSN_IMM_MOVK);
+			break;
+		case R_AARCH64_MOVW_PREL_G2:
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
+					      INSN_IMM_MOVNZ);
+			break;
+		case R_AARCH64_MOVW_PREL_G3:
+			/* We're using the top bits so we can't overflow. */
+			overflow_check = false;
+			ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48,
+					      INSN_IMM_MOVNZ);
+			break;
+
+		/* Immediate instruction relocations. */
+		case R_AARCH64_LD_PREL_LO19:
+			ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19,
+					     INSN_IMM_19);
+			break;
+		case R_AARCH64_ADR_PREL_LO21:
+			ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21,
+					     INSN_IMM_ADR);
+			break;
+		case R_AARCH64_ADR_PREL_PG_HI21_NC:
+			overflow_check = false;
+		case R_AARCH64_ADR_PREL_PG_HI21:
+			ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21,
+					     INSN_IMM_ADR);
+			break;
+		case R_AARCH64_ADD_ABS_LO12_NC:
+		case R_AARCH64_LDST8_ABS_LO12_NC:
+			overflow_check = false;
+			ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12,
+					     INSN_IMM_12);
+			break;
+		case R_AARCH64_LDST16_ABS_LO12_NC:
+			overflow_check = false;
+			ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11,
+					     INSN_IMM_12);
+			break;
+		case R_AARCH64_LDST32_ABS_LO12_NC:
+			overflow_check = false;
+			ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10,
+					     INSN_IMM_12);
+			break;
+		case R_AARCH64_LDST64_ABS_LO12_NC:
+			overflow_check = false;
+			ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9,
+					     INSN_IMM_12);
+			break;
+		case R_AARCH64_LDST128_ABS_LO12_NC:
+			overflow_check = false;
+			ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8,
+					     INSN_IMM_12);
+			break;
+		case R_AARCH64_TSTBR14:
+			ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14,
+					     INSN_IMM_14);
+			break;
+		case R_AARCH64_CONDBR19:
+			ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19,
+					     INSN_IMM_19);
+			break;
+		case R_AARCH64_JUMP26:
+		case R_AARCH64_CALL26:
+			ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26,
+					     INSN_IMM_26);
+			break;
+
+		default:
+			pr_err("module %s: unsupported RELA relocation: %llu\n",
+			       me->name, ELF64_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+
+		if (overflow_check && ovf == -ERANGE)
+			goto overflow;
+
+	}
+
+	return 0;
+
+overflow:
+	pr_err("module %s: overflow in relocation type %d val %Lx\n",
+	       me->name, (int)ELF64_R_TYPE(rel[i].r_info), val);
+	return -ENOEXEC;
+}
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
new file mode 100644
index 0000000..ecbf2d8
--- /dev/null
+++ b/arch/arm64/kernel/perf_event.c
@@ -0,0 +1,1368 @@
+/*
+ * PMU support
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This code is based heavily on the ARMv7 perf event code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#define pr_fmt(fmt) "hw perfevents: " fmt
+
+#include <linux/bitmap.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#include <asm/cputype.h>
+#include <asm/irq.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+#include <asm/stacktrace.h>
+
+/*
+ * ARMv8 supports a maximum of 32 events.
+ * The cycle counter is included in this total.
+ */
+#define ARMPMU_MAX_HWEVENTS		32
+
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
+
+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
+
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *cpu_pmu;
+
+int
+armpmu_get_max_events(void)
+{
+	int max_events = 0;
+
+	if (cpu_pmu != NULL)
+		max_events = cpu_pmu->num_events;
+
+	return max_events;
+}
+EXPORT_SYMBOL_GPL(armpmu_get_max_events);
+
+int perf_num_counters(void)
+{
+	return armpmu_get_max_events();
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+#define HW_OP_UNSUPPORTED		0xFFFF
+
+#define C(_x) \
+	PERF_COUNT_HW_CACHE_##_x
+
+#define CACHE_OP_UNSUPPORTED		0xFFFF
+
+static int
+armpmu_map_cache_event(const unsigned (*cache_map)
+				      [PERF_COUNT_HW_CACHE_MAX]
+				      [PERF_COUNT_HW_CACHE_OP_MAX]
+				      [PERF_COUNT_HW_CACHE_RESULT_MAX],
+		       u64 config)
+{
+	unsigned int cache_type, cache_op, cache_result, ret;
+
+	cache_type = (config >>  0) & 0xff;
+	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+		return -EINVAL;
+
+	cache_op = (config >>  8) & 0xff;
+	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+		return -EINVAL;
+
+	cache_result = (config >> 16) & 0xff;
+	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+
+	ret = (int)(*cache_map)[cache_type][cache_op][cache_result];
+
+	if (ret == CACHE_OP_UNSUPPORTED)
+		return -ENOENT;
+
+	return ret;
+}
+
+static int
+armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
+{
+	int mapping = (*event_map)[config];
+	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
+}
+
+static int
+armpmu_map_raw_event(u32 raw_event_mask, u64 config)
+{
+	return (int)(config & raw_event_mask);
+}
+
+static int map_cpu_event(struct perf_event *event,
+			 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+			 const unsigned (*cache_map)
+					[PERF_COUNT_HW_CACHE_MAX]
+					[PERF_COUNT_HW_CACHE_OP_MAX]
+					[PERF_COUNT_HW_CACHE_RESULT_MAX],
+			 u32 raw_event_mask)
+{
+	u64 config = event->attr.config;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		return armpmu_map_event(event_map, config);
+	case PERF_TYPE_HW_CACHE:
+		return armpmu_map_cache_event(cache_map, config);
+	case PERF_TYPE_RAW:
+		return armpmu_map_raw_event(raw_event_mask, config);
+	}
+
+	return -ENOENT;
+}
+
+int
+armpmu_event_set_period(struct perf_event *event,
+			struct hw_perf_event *hwc,
+			int idx)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int ret = 0;
+
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (unlikely(left <= 0)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (left > (s64)armpmu->max_period)
+		left = armpmu->max_period;
+
+	local64_set(&hwc->prev_count, (u64)-left);
+
+	armpmu->write_counter(idx, (u64)(-left) & 0xffffffff);
+
+	perf_event_update_userpage(event);
+
+	return ret;
+}
+
+u64
+armpmu_event_update(struct perf_event *event,
+		    struct hw_perf_event *hwc,
+		    int idx)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	u64 delta, prev_raw_count, new_raw_count;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	new_raw_count = armpmu->read_counter(idx);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+			     new_raw_count) != prev_raw_count)
+		goto again;
+
+	delta = (new_raw_count - prev_raw_count) & armpmu->max_period;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	return new_raw_count;
+}
+
+static void
+armpmu_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	/* Don't read disabled counters! */
+	if (hwc->idx < 0)
+		return;
+
+	armpmu_event_update(event, hwc, hwc->idx);
+}
+
+static void
+armpmu_stop(struct perf_event *event, int flags)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	/*
+	 * ARM pmu always has to update the counter, so ignore
+	 * PERF_EF_UPDATE, see comments in armpmu_start().
+	 */
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		armpmu->disable(hwc, hwc->idx);
+		barrier(); /* why? */
+		armpmu_event_update(event, hwc, hwc->idx);
+		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	}
+}
+
+static void
+armpmu_start(struct perf_event *event, int flags)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	/*
+	 * ARM pmu always has to reprogram the period, so ignore
+	 * PERF_EF_RELOAD, see the comment below.
+	 */
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
+	/*
+	 * Set the period again. Some counters can't be stopped, so when we
+	 * were stopped we simply disabled the IRQ source and the counter
+	 * may have been left counting. If we don't do this step then we may
+	 * get an interrupt too soon or *way* too late if the overflow has
+	 * happened since disabling.
+	 */
+	armpmu_event_set_period(event, hwc, hwc->idx);
+	armpmu->enable(hwc, hwc->idx);
+}
+
+static void
+armpmu_del(struct perf_event *event, int flags)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+
+	WARN_ON(idx < 0);
+
+	armpmu_stop(event, PERF_EF_UPDATE);
+	hw_events->events[idx] = NULL;
+	clear_bit(idx, hw_events->used_mask);
+
+	perf_event_update_userpage(event);
+}
+
+static int
+armpmu_add(struct perf_event *event, int flags)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+	struct hw_perf_event *hwc = &event->hw;
+	int idx;
+	int err = 0;
+
+	perf_pmu_disable(event->pmu);
+
+	/* If we don't have a space for the counter then finish early. */
+	idx = armpmu->get_event_idx(hw_events, hwc);
+	if (idx < 0) {
+		err = idx;
+		goto out;
+	}
+
+	/*
+	 * If there is an event in the counter we are going to use then make
+	 * sure it is disabled.
+	 */
+	event->hw.idx = idx;
+	armpmu->disable(hwc, idx);
+	hw_events->events[idx] = event;
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	if (flags & PERF_EF_START)
+		armpmu_start(event, PERF_EF_RELOAD);
+
+	/* Propagate our changes to the userspace mapping. */
+	perf_event_update_userpage(event);
+
+out:
+	perf_pmu_enable(event->pmu);
+	return err;
+}
+
+static int
+validate_event(struct pmu_hw_events *hw_events,
+	       struct perf_event *event)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct hw_perf_event fake_event = event->hw;
+	struct pmu *leader_pmu = event->group_leader->pmu;
+
+	if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
+		return 1;
+
+	return armpmu->get_event_idx(hw_events, &fake_event) >= 0;
+}
+
+static int
+validate_group(struct perf_event *event)
+{
+	struct perf_event *sibling, *leader = event->group_leader;
+	struct pmu_hw_events fake_pmu;
+	DECLARE_BITMAP(fake_used_mask, ARMPMU_MAX_HWEVENTS);
+
+	/*
+	 * Initialise the fake PMU. We only need to populate the
+	 * used_mask for the purposes of validation.
+	 */
+	memset(fake_used_mask, 0, sizeof(fake_used_mask));
+	fake_pmu.used_mask = fake_used_mask;
+
+	if (!validate_event(&fake_pmu, leader))
+		return -EINVAL;
+
+	list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+		if (!validate_event(&fake_pmu, sibling))
+			return -EINVAL;
+	}
+
+	if (!validate_event(&fake_pmu, event))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void
+armpmu_release_hardware(struct arm_pmu *armpmu)
+{
+	int i, irq, irqs;
+	struct platform_device *pmu_device = armpmu->plat_device;
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+	for (i = 0; i < irqs; ++i) {
+		if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
+			continue;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq >= 0)
+			free_irq(irq, armpmu);
+	}
+}
+
+static int
+armpmu_reserve_hardware(struct arm_pmu *armpmu)
+{
+	int i, err, irq, irqs;
+	struct platform_device *pmu_device = armpmu->plat_device;
+
+	if (!pmu_device) {
+		pr_err("no PMU device registered\n");
+		return -ENODEV;
+	}
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+	if (irqs < 1) {
+		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < irqs; ++i) {
+		err = 0;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq < 0)
+			continue;
+
+		/*
+		 * If we have a single PMU interrupt that we can't shift,
+		 * assume that we're running on a uniprocessor machine and
+		 * continue. Otherwise, continue without this interrupt.
+		 */
+		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+				    irq, i);
+			continue;
+		}
+
+		err = request_irq(irq, armpmu->handle_irq,
+				  IRQF_NOBALANCING,
+				  "arm-pmu", armpmu);
+		if (err) {
+			pr_err("unable to request IRQ%d for ARM PMU counters\n",
+				irq);
+			armpmu_release_hardware(armpmu);
+			return err;
+		}
+
+		cpumask_set_cpu(i, &armpmu->active_irqs);
+	}
+
+	return 0;
+}
+
+static void
+hw_perf_event_destroy(struct perf_event *event)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	atomic_t *active_events	 = &armpmu->active_events;
+	struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex;
+
+	if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) {
+		armpmu_release_hardware(armpmu);
+		mutex_unlock(pmu_reserve_mutex);
+	}
+}
+
+static int
+event_requires_mode_exclusion(struct perf_event_attr *attr)
+{
+	return attr->exclude_idle || attr->exclude_user ||
+	       attr->exclude_kernel || attr->exclude_hv;
+}
+
+static int
+__hw_perf_event_init(struct perf_event *event)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	int mapping, err;
+
+	mapping = armpmu->map_event(event);
+
+	if (mapping < 0) {
+		pr_debug("event %x:%llx not supported\n", event->attr.type,
+			 event->attr.config);
+		return mapping;
+	}
+
+	/*
+	 * We don't assign an index until we actually place the event onto
+	 * hardware. Use -1 to signify that we haven't decided where to put it
+	 * yet. For SMP systems, each core has it's own PMU so we can't do any
+	 * clever allocation or constraints checking at this point.
+	 */
+	hwc->idx		= -1;
+	hwc->config_base	= 0;
+	hwc->config		= 0;
+	hwc->event_base		= 0;
+
+	/*
+	 * Check whether we need to exclude the counter from certain modes.
+	 */
+	if ((!armpmu->set_event_filter ||
+	     armpmu->set_event_filter(hwc, &event->attr)) &&
+	     event_requires_mode_exclusion(&event->attr)) {
+		pr_debug("ARM performance counters do not support mode exclusion\n");
+		return -EPERM;
+	}
+
+	/*
+	 * Store the event encoding into the config_base field.
+	 */
+	hwc->config_base	    |= (unsigned long)mapping;
+
+	if (!hwc->sample_period) {
+		/*
+		 * For non-sampling runs, limit the sample_period to half
+		 * of the counter width. That way, the new counter value
+		 * is far less likely to overtake the previous one unless
+		 * you have some serious IRQ latency issues.
+		 */
+		hwc->sample_period  = armpmu->max_period >> 1;
+		hwc->last_period    = hwc->sample_period;
+		local64_set(&hwc->period_left, hwc->sample_period);
+	}
+
+	err = 0;
+	if (event->group_leader != event) {
+		err = validate_group(event);
+		if (err)
+			return -EINVAL;
+	}
+
+	return err;
+}
+
+static int armpmu_event_init(struct perf_event *event)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+	int err = 0;
+	atomic_t *active_events = &armpmu->active_events;
+
+	if (armpmu->map_event(event) == -ENOENT)
+		return -ENOENT;
+
+	event->destroy = hw_perf_event_destroy;
+
+	if (!atomic_inc_not_zero(active_events)) {
+		mutex_lock(&armpmu->reserve_mutex);
+		if (atomic_read(active_events) == 0)
+			err = armpmu_reserve_hardware(armpmu);
+
+		if (!err)
+			atomic_inc(active_events);
+		mutex_unlock(&armpmu->reserve_mutex);
+	}
+
+	if (err)
+		return err;
+
+	err = __hw_perf_event_init(event);
+	if (err)
+		hw_perf_event_destroy(event);
+
+	return err;
+}
+
+static void armpmu_enable(struct pmu *pmu)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(pmu);
+	struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
+
+	if (enabled)
+		armpmu->start();
+}
+
+static void armpmu_disable(struct pmu *pmu)
+{
+	struct arm_pmu *armpmu = to_arm_pmu(pmu);
+	armpmu->stop();
+}
+
+static void __init armpmu_init(struct arm_pmu *armpmu)
+{
+	atomic_set(&armpmu->active_events, 0);
+	mutex_init(&armpmu->reserve_mutex);
+
+	armpmu->pmu = (struct pmu) {
+		.pmu_enable	= armpmu_enable,
+		.pmu_disable	= armpmu_disable,
+		.event_init	= armpmu_event_init,
+		.add		= armpmu_add,
+		.del		= armpmu_del,
+		.start		= armpmu_start,
+		.stop		= armpmu_stop,
+		.read		= armpmu_read,
+	};
+}
+
+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+{
+	armpmu_init(armpmu);
+	return perf_pmu_register(&armpmu->pmu, name, type);
+}
+
+/*
+ * ARMv8 PMUv3 Performance Events handling code.
+ * Common event types.
+ */
+enum armv8_pmuv3_perf_types {
+	/* Required events. */
+	ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR			= 0x00,
+	ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL			= 0x03,
+	ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS			= 0x04,
+	ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED			= 0x10,
+	ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES			= 0x11,
+	ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED			= 0x12,
+
+	/* At least one of the following is required. */
+	ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED			= 0x08,
+	ARMV8_PMUV3_PERFCTR_OP_SPEC				= 0x1B,
+
+	/* Common architectural events. */
+	ARMV8_PMUV3_PERFCTR_MEM_READ				= 0x06,
+	ARMV8_PMUV3_PERFCTR_MEM_WRITE				= 0x07,
+	ARMV8_PMUV3_PERFCTR_EXC_TAKEN				= 0x09,
+	ARMV8_PMUV3_PERFCTR_EXC_EXECUTED			= 0x0A,
+	ARMV8_PMUV3_PERFCTR_CID_WRITE				= 0x0B,
+	ARMV8_PMUV3_PERFCTR_PC_WRITE				= 0x0C,
+	ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH			= 0x0D,
+	ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN			= 0x0E,
+	ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS		= 0x0F,
+	ARMV8_PMUV3_PERFCTR_TTBR_WRITE				= 0x1C,
+
+	/* Common microarchitectural events. */
+	ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL			= 0x01,
+	ARMV8_PMUV3_PERFCTR_ITLB_REFILL				= 0x02,
+	ARMV8_PMUV3_PERFCTR_DTLB_REFILL				= 0x05,
+	ARMV8_PMUV3_PERFCTR_MEM_ACCESS				= 0x13,
+	ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS			= 0x14,
+	ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB			= 0x15,
+	ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS			= 0x16,
+	ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL			= 0x17,
+	ARMV8_PMUV3_PERFCTR_L2_CACHE_WB				= 0x18,
+	ARMV8_PMUV3_PERFCTR_BUS_ACCESS				= 0x19,
+	ARMV8_PMUV3_PERFCTR_MEM_ERROR				= 0x1A,
+	ARMV8_PMUV3_PERFCTR_BUS_CYCLES				= 0x1D,
+
+	/*
+	 * This isn't an architected event.
+	 * We detect this event number and use the cycle counter instead.
+	 */
+	ARMV8_PMUV3_PERFCTR_CPU_CYCLES				= 0xFF,
+};
+
+/* PMUv3 HW events mapping. */
+static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV8_PMUV3_PERFCTR_CPU_CYCLES,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
+	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]		= HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
+};
+
+static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+						[PERF_COUNT_HW_CACHE_OP_MAX]
+						[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	[C(L1D)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(L1I)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(LL)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(DTLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(ITLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(BPU)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(NODE)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+};
+
+/*
+ * Perf Events' indices
+ */
+#define	ARMV8_IDX_CYCLE_COUNTER	0
+#define	ARMV8_IDX_COUNTER0	1
+#define	ARMV8_IDX_COUNTER_LAST	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
+
+#define	ARMV8_MAX_COUNTERS	32
+#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
+
+/*
+ * ARMv8 low level PMU access
+ */
+
+/*
+ * Perf Event to low level counters mapping
+ */
+#define	ARMV8_IDX_TO_COUNTER(x)	\
+	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
+#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
+#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
+#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
+#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
+#define	ARMV8_PMCR_N_MASK	0x1f
+#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
+#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define	ARMV8_EVTYPE_MASK	0xc00000ff	/* Mask for writable bits */
+#define	ARMV8_EVTYPE_EVENT	0xff		/* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv3
+ */
+#define	ARMV8_EXCLUDE_EL1	(1 << 31)
+#define	ARMV8_EXCLUDE_EL0	(1 << 30)
+#define	ARMV8_INCLUDE_EL2	(1 << 27)
+
+static inline u32 armv8pmu_pmcr_read(void)
+{
+	u32 val;
+	asm volatile("mrs %0, pmcr_el0" : "=r" (val));
+	return val;
+}
+
+static inline void armv8pmu_pmcr_write(u32 val)
+{
+	val &= ARMV8_PMCR_MASK;
+	isb();
+	asm volatile("msr pmcr_el0, %0" :: "r" (val));
+}
+
+static inline int armv8pmu_has_overflowed(u32 pmovsr)
+{
+	return pmovsr & ARMV8_OVERFLOWED_MASK;
+}
+
+static inline int armv8pmu_counter_valid(int idx)
+{
+	return idx >= ARMV8_IDX_CYCLE_COUNTER && idx <= ARMV8_IDX_COUNTER_LAST;
+}
+
+static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx)
+{
+	int ret = 0;
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u checking wrong counter %d overflow status\n",
+			smp_processor_id(), idx);
+	} else {
+		counter = ARMV8_IDX_TO_COUNTER(idx);
+		ret = pmnc & BIT(counter);
+	}
+
+	return ret;
+}
+
+static inline int armv8pmu_select_counter(int idx)
+{
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u selecting wrong PMNC counter %d\n",
+			smp_processor_id(), idx);
+		return -EINVAL;
+	}
+
+	counter = ARMV8_IDX_TO_COUNTER(idx);
+	asm volatile("msr pmselr_el0, %0" :: "r" (counter));
+	isb();
+
+	return idx;
+}
+
+static inline u32 armv8pmu_read_counter(int idx)
+{
+	u32 value = 0;
+
+	if (!armv8pmu_counter_valid(idx))
+		pr_err("CPU%u reading wrong counter %d\n",
+			smp_processor_id(), idx);
+	else if (idx == ARMV8_IDX_CYCLE_COUNTER)
+		asm volatile("mrs %0, pmccntr_el0" : "=r" (value));
+	else if (armv8pmu_select_counter(idx) == idx)
+		asm volatile("mrs %0, pmxevcntr_el0" : "=r" (value));
+
+	return value;
+}
+
+static inline void armv8pmu_write_counter(int idx, u32 value)
+{
+	if (!armv8pmu_counter_valid(idx))
+		pr_err("CPU%u writing wrong counter %d\n",
+			smp_processor_id(), idx);
+	else if (idx == ARMV8_IDX_CYCLE_COUNTER)
+		asm volatile("msr pmccntr_el0, %0" :: "r" (value));
+	else if (armv8pmu_select_counter(idx) == idx)
+		asm volatile("msr pmxevcntr_el0, %0" :: "r" (value));
+}
+
+static inline void armv8pmu_write_evtype(int idx, u32 val)
+{
+	if (armv8pmu_select_counter(idx) == idx) {
+		val &= ARMV8_EVTYPE_MASK;
+		asm volatile("msr pmxevtyper_el0, %0" :: "r" (val));
+	}
+}
+
+static inline int armv8pmu_enable_counter(int idx)
+{
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u enabling wrong PMNC counter %d\n",
+			smp_processor_id(), idx);
+		return -EINVAL;
+	}
+
+	counter = ARMV8_IDX_TO_COUNTER(idx);
+	asm volatile("msr pmcntenset_el0, %0" :: "r" (BIT(counter)));
+	return idx;
+}
+
+static inline int armv8pmu_disable_counter(int idx)
+{
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u disabling wrong PMNC counter %d\n",
+			smp_processor_id(), idx);
+		return -EINVAL;
+	}
+
+	counter = ARMV8_IDX_TO_COUNTER(idx);
+	asm volatile("msr pmcntenclr_el0, %0" :: "r" (BIT(counter)));
+	return idx;
+}
+
+static inline int armv8pmu_enable_intens(int idx)
+{
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",
+			smp_processor_id(), idx);
+		return -EINVAL;
+	}
+
+	counter = ARMV8_IDX_TO_COUNTER(idx);
+	asm volatile("msr pmintenset_el1, %0" :: "r" (BIT(counter)));
+	return idx;
+}
+
+static inline int armv8pmu_disable_intens(int idx)
+{
+	u32 counter;
+
+	if (!armv8pmu_counter_valid(idx)) {
+		pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",
+			smp_processor_id(), idx);
+		return -EINVAL;
+	}
+
+	counter = ARMV8_IDX_TO_COUNTER(idx);
+	asm volatile("msr pmintenclr_el1, %0" :: "r" (BIT(counter)));
+	isb();
+	/* Clear the overflow flag in case an interrupt is pending. */
+	asm volatile("msr pmovsclr_el0, %0" :: "r" (BIT(counter)));
+	isb();
+	return idx;
+}
+
+static inline u32 armv8pmu_getreset_flags(void)
+{
+	u32 value;
+
+	/* Read */
+	asm volatile("mrs %0, pmovsclr_el0" : "=r" (value));
+
+	/* Write to clear flags */
+	value &= ARMV8_OVSR_MASK;
+	asm volatile("msr pmovsclr_el0, %0" :: "r" (value));
+
+	return value;
+}
+
+static void armv8pmu_enable_event(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long flags;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+	/*
+	 * Enable counter and interrupt, and set the counter to count
+	 * the event that we're interested in.
+	 */
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+	/*
+	 * Disable counter
+	 */
+	armv8pmu_disable_counter(idx);
+
+	/*
+	 * Set event (if destined for PMNx counters).
+	 */
+	armv8pmu_write_evtype(idx, hwc->config_base);
+
+	/*
+	 * Enable interrupt for this counter
+	 */
+	armv8pmu_enable_intens(idx);
+
+	/*
+	 * Enable counter
+	 */
+	armv8pmu_enable_counter(idx);
+
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void armv8pmu_disable_event(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long flags;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+	/*
+	 * Disable counter and interrupt
+	 */
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+	/*
+	 * Disable counter
+	 */
+	armv8pmu_disable_counter(idx);
+
+	/*
+	 * Disable interrupt for this counter
+	 */
+	armv8pmu_disable_intens(idx);
+
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev)
+{
+	u32 pmovsr;
+	struct perf_sample_data data;
+	struct pmu_hw_events *cpuc;
+	struct pt_regs *regs;
+	int idx;
+
+	/*
+	 * Get and reset the IRQ flags
+	 */
+	pmovsr = armv8pmu_getreset_flags();
+
+	/*
+	 * Did an overflow occur?
+	 */
+	if (!armv8pmu_has_overflowed(pmovsr))
+		return IRQ_NONE;
+
+	/*
+	 * Handle the counter(s) overflow(s)
+	 */
+	regs = get_irq_regs();
+
+	cpuc = &__get_cpu_var(cpu_hw_events);
+	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
+		struct perf_event *event = cpuc->events[idx];
+		struct hw_perf_event *hwc;
+
+		/* Ignore if we don't have an event. */
+		if (!event)
+			continue;
+
+		/*
+		 * We have a single interrupt for all counters. Check that
+		 * each counter has overflowed before we process it.
+		 */
+		if (!armv8pmu_counter_has_overflowed(pmovsr, idx))
+			continue;
+
+		hwc = &event->hw;
+		armpmu_event_update(event, hwc, idx);
+		perf_sample_data_init(&data, 0, hwc->last_period);
+		if (!armpmu_event_set_period(event, hwc, idx))
+			continue;
+
+		if (perf_event_overflow(event, &data, regs))
+			cpu_pmu->disable(hwc, idx);
+	}
+
+	/*
+	 * Handle the pending perf events.
+	 *
+	 * Note: this call *must* be run with interrupts disabled. For
+	 * platforms that can have the PMU interrupts raised as an NMI, this
+	 * will not work.
+	 */
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static void armv8pmu_start(void)
+{
+	unsigned long flags;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+	/* Enable all counters */
+	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E);
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void armv8pmu_stop(void)
+{
+	unsigned long flags;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+	/* Disable all counters */
+	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMCR_E);
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				  struct hw_perf_event *event)
+{
+	int idx;
+	unsigned long evtype = event->config_base & ARMV8_EVTYPE_EVENT;
+
+	/* Always place a cycle counter into the cycle counter. */
+	if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) {
+		if (test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
+			return -EAGAIN;
+
+		return ARMV8_IDX_CYCLE_COUNTER;
+	}
+
+	/*
+	 * For anything other than a cycle counter, try and use
+	 * the events counters
+	 */
+	for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; ++idx) {
+		if (!test_and_set_bit(idx, cpuc->used_mask))
+			return idx;
+	}
+
+	/* The counters are all in use. */
+	return -EAGAIN;
+}
+
+/*
+ * Add an event filter to a given event. This will only work for PMUv2 PMUs.
+ */
+static int armv8pmu_set_event_filter(struct hw_perf_event *event,
+				     struct perf_event_attr *attr)
+{
+	unsigned long config_base = 0;
+
+	if (attr->exclude_idle)
+		return -EPERM;
+	if (attr->exclude_user)
+		config_base |= ARMV8_EXCLUDE_EL0;
+	if (attr->exclude_kernel)
+		config_base |= ARMV8_EXCLUDE_EL1;
+	if (!attr->exclude_hv)
+		config_base |= ARMV8_INCLUDE_EL2;
+
+	/*
+	 * Install the filter into config_base as this is used to
+	 * construct the event type.
+	 */
+	event->config_base = config_base;
+
+	return 0;
+}
+
+static void armv8pmu_reset(void *info)
+{
+	u32 idx, nb_cnt = cpu_pmu->num_events;
+
+	/* The counter and interrupt enable registers are unknown at reset. */
+	for (idx = ARMV8_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx)
+		armv8pmu_disable_event(NULL, idx);
+
+	/* Initialize & Reset PMNC: C and P bits. */
+	armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C);
+
+	/* Disable access from userspace. */
+	asm volatile("msr pmuserenr_el0, %0" :: "r" (0));
+}
+
+static int armv8_pmuv3_map_event(struct perf_event *event)
+{
+	return map_cpu_event(event, &armv8_pmuv3_perf_map,
+				&armv8_pmuv3_perf_cache_map, 0xFF);
+}
+
+static struct arm_pmu armv8pmu = {
+	.handle_irq		= armv8pmu_handle_irq,
+	.enable			= armv8pmu_enable_event,
+	.disable		= armv8pmu_disable_event,
+	.read_counter		= armv8pmu_read_counter,
+	.write_counter		= armv8pmu_write_counter,
+	.get_event_idx		= armv8pmu_get_event_idx,
+	.start			= armv8pmu_start,
+	.stop			= armv8pmu_stop,
+	.reset			= armv8pmu_reset,
+	.max_period		= (1LLU << 32) - 1,
+};
+
+static u32 __init armv8pmu_read_num_pmnc_events(void)
+{
+	u32 nb_cnt;
+
+	/* Read the nb of CNTx counters supported from PMNC */
+	nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+
+	/* Add the CPU cycles counter and return */
+	return nb_cnt + 1;
+}
+
+static struct arm_pmu *__init armv8_pmuv3_pmu_init(void)
+{
+	armv8pmu.name			= "arm/armv8-pmuv3";
+	armv8pmu.map_event		= armv8_pmuv3_map_event;
+	armv8pmu.num_events		= armv8pmu_read_num_pmnc_events();
+	armv8pmu.set_event_filter	= armv8pmu_set_event_filter;
+	return &armv8pmu;
+}
+
+/*
+ * Ensure the PMU has sane values out of reset.
+ * This requires SMP to be available, so exists as a separate initcall.
+ */
+static int __init
+cpu_pmu_reset(void)
+{
+	if (cpu_pmu && cpu_pmu->reset)
+		return on_each_cpu(cpu_pmu->reset, NULL, 1);
+	return 0;
+}
+arch_initcall(cpu_pmu_reset);
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id armpmu_of_device_ids[] = {
+	{.compatible = "arm,armv8-pmuv3"},
+	{},
+};
+
+static int __devinit armpmu_device_probe(struct platform_device *pdev)
+{
+	if (!cpu_pmu)
+		return -ENODEV;
+
+	cpu_pmu->plat_device = pdev;
+	return 0;
+}
+
+static struct platform_driver armpmu_driver = {
+	.driver		= {
+		.name	= "arm-pmu",
+		.of_match_table = armpmu_of_device_ids,
+	},
+	.probe		= armpmu_device_probe,
+};
+
+static int __init register_pmu_driver(void)
+{
+	return platform_driver_register(&armpmu_driver);
+}
+device_initcall(register_pmu_driver);
+
+static struct pmu_hw_events *armpmu_get_cpu_events(void)
+{
+	return &__get_cpu_var(cpu_hw_events);
+}
+
+static void __init cpu_pmu_init(struct arm_pmu *armpmu)
+{
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+		events->events = per_cpu(hw_events, cpu);
+		events->used_mask = per_cpu(used_mask, cpu);
+		raw_spin_lock_init(&events->pmu_lock);
+	}
+	armpmu->get_hw_events = armpmu_get_cpu_events;
+}
+
+static int __init init_hw_perf_events(void)
+{
+	u64 dfr = read_cpuid(ID_AA64DFR0_EL1);
+
+	switch ((dfr >> 8) & 0xf) {
+	case 0x1:	/* PMUv3 */
+		cpu_pmu = armv8_pmuv3_pmu_init();
+		break;
+	}
+
+	if (cpu_pmu) {
+		pr_info("enabled with %s PMU driver, %d counters available\n",
+			cpu_pmu->name, cpu_pmu->num_events);
+		cpu_pmu_init(cpu_pmu);
+		armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
+	} else {
+		pr_info("no hardware support available\n");
+	}
+
+	return 0;
+}
+early_initcall(init_hw_perf_events);
+
+/*
+ * Callchain handling code.
+ */
+struct frame_tail {
+	struct frame_tail   __user *fp;
+	unsigned long	    lr;
+} __attribute__((packed));
+
+/*
+ * Get the return address for a single stackframe and return a pointer to the
+ * next frame tail.
+ */
+static struct frame_tail __user *
+user_backtrace(struct frame_tail __user *tail,
+	       struct perf_callchain_entry *entry)
+{
+	struct frame_tail buftail;
+	unsigned long err;
+
+	/* Also check accessibility of one struct frame_tail beyond */
+	if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+		return NULL;
+
+	pagefault_disable();
+	err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+	pagefault_enable();
+
+	if (err)
+		return NULL;
+
+	perf_callchain_store(entry, buftail.lr);
+
+	/*
+	 * Frame pointers should strictly progress back up the stack
+	 * (towards higher addresses).
+	 */
+	if (tail >= buftail.fp)
+		return NULL;
+
+	return buftail.fp;
+}
+
+void perf_callchain_user(struct perf_callchain_entry *entry,
+			 struct pt_regs *regs)
+{
+	struct frame_tail __user *tail;
+
+	tail = (struct frame_tail __user *)regs->regs[29];
+
+	while (entry->nr < PERF_MAX_STACK_DEPTH &&
+	       tail && !((unsigned long)tail & 0xf))
+		tail = user_backtrace(tail, entry);
+}
+
+/*
+ * Gets called by walk_stackframe() for every stackframe. This will be called
+ * whist unwinding the stackframe and is like a subroutine return so we use
+ * the PC.
+ */
+static int callchain_trace(struct stackframe *frame, void *data)
+{
+	struct perf_callchain_entry *entry = data;
+	perf_callchain_store(entry, frame->pc);
+	return 0;
+}
+
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+			   struct pt_regs *regs)
+{
+	struct stackframe frame;
+
+	frame.fp = regs->regs[29];
+	frame.sp = regs->sp;
+	frame.pc = regs->pc;
+	walk_stackframe(&frame, callchain_trace, entry);
+}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
new file mode 100644
index 0000000..f22965e
--- /dev/null
+++ b/arch/arm64/kernel/process.c
@@ -0,0 +1,408 @@
+/*
+ * Based on arch/arm/kernel/process.c
+ *
+ * Original Copyright (C) 1995  Linus Torvalds
+ * Copyright (C) 1996-2000 Russell King - Converted to ARM.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/user.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/elfcore.h>
+#include <linux/pm.h>
+#include <linux/tick.h>
+#include <linux/utsname.h>
+#include <linux/uaccess.h>
+#include <linux/random.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/personality.h>
+#include <linux/notifier.h>
+
+#include <asm/compat.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/stacktrace.h>
+#include <asm/fpsimd.h>
+
+static void setup_restart(void)
+{
+	/*
+	 * Tell the mm system that we are going to reboot -
+	 * we may need it to insert some 1:1 mappings so that
+	 * soft boot works.
+	 */
+	setup_mm_for_reboot();
+
+	/* Clean and invalidate caches */
+	flush_cache_all();
+
+	/* Turn D-cache off */
+	cpu_cache_off();
+
+	/* Push out any further dirty data, and ensure cache is empty */
+	flush_cache_all();
+}
+
+void soft_restart(unsigned long addr)
+{
+	setup_restart();
+	cpu_reset(addr);
+}
+
+/*
+ * Function pointers to optional machine specific functions
+ */
+void (*pm_power_off)(void);
+EXPORT_SYMBOL_GPL(pm_power_off);
+
+void (*pm_restart)(const char *cmd);
+EXPORT_SYMBOL_GPL(pm_restart);
+
+
+/*
+ * This is our default idle handler.
+ */
+static void default_idle(void)
+{
+	/*
+	 * This should do all the clock switching and wait for interrupt
+	 * tricks
+	 */
+	cpu_do_idle();
+	local_irq_enable();
+}
+
+void (*pm_idle)(void) = default_idle;
+EXPORT_SYMBOL_GPL(pm_idle);
+
+/*
+ * The idle thread, has rather strange semantics for calling pm_idle,
+ * but this is what x86 does and we need to do the same, so that
+ * things like cpuidle get called in the same way.  The only difference
+ * is that we always respect 'hlt_counter' to prevent low power idle.
+ */
+void cpu_idle(void)
+{
+	local_fiq_enable();
+
+	/* endless idle loop with no priority at all */
+	while (1) {
+		tick_nohz_idle_enter();
+		rcu_idle_enter();
+		while (!need_resched()) {
+			/*
+			 * We need to disable interrupts here to ensure
+			 * we don't miss a wakeup call.
+			 */
+			local_irq_disable();
+			if (!need_resched()) {
+				stop_critical_timings();
+				pm_idle();
+				start_critical_timings();
+				/*
+				 * pm_idle functions should always return
+				 * with IRQs enabled.
+				 */
+				WARN_ON(irqs_disabled());
+			} else {
+				local_irq_enable();
+			}
+		}
+		rcu_idle_exit();
+		tick_nohz_idle_exit();
+		schedule_preempt_disabled();
+	}
+}
+
+void machine_shutdown(void)
+{
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+}
+
+void machine_halt(void)
+{
+	machine_shutdown();
+	while (1);
+}
+
+void machine_power_off(void)
+{
+	machine_shutdown();
+	if (pm_power_off)
+		pm_power_off();
+}
+
+void machine_restart(char *cmd)
+{
+	machine_shutdown();
+
+	/* Disable interrupts first */
+	local_irq_disable();
+	local_fiq_disable();
+
+	/* Now call the architecture specific reboot code. */
+	if (pm_restart)
+		pm_restart(cmd);
+
+	/*
+	 * Whoops - the architecture was unable to reboot.
+	 */
+	printk("Reboot failed -- System halted\n");
+	while (1);
+}
+
+void __show_regs(struct pt_regs *regs)
+{
+	int i;
+
+	printk("CPU: %d    %s  (%s %.*s)\n",
+		raw_smp_processor_id(), print_tainted(),
+		init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	print_symbol("PC is at %s\n", instruction_pointer(regs));
+	print_symbol("LR is at %s\n", regs->regs[30]);
+	printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
+	       regs->pc, regs->regs[30], regs->pstate);
+	printk("sp : %016llx\n", regs->sp);
+	for (i = 29; i >= 0; i--) {
+		printk("x%-2d: %016llx ", i, regs->regs[i]);
+		if (i % 2 == 0)
+			printk("\n");
+	}
+	printk("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
+	__show_regs(regs);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+	fpsimd_flush_thread();
+	flush_ptrace_hw_breakpoint(current);
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
+{
+	fpsimd_save_state(&current->thread.fpsimd_state);
+	*dst = *src;
+	return 0;
+}
+
+asmlinkage void ret_from_fork(void) asm("ret_from_fork");
+
+int copy_thread(unsigned long clone_flags, unsigned long stack_start,
+		unsigned long stk_sz, struct task_struct *p,
+		struct pt_regs *regs)
+{
+	struct pt_regs *childregs = task_pt_regs(p);
+	unsigned long tls = p->thread.tp_value;
+
+	*childregs = *regs;
+	childregs->regs[0] = 0;
+
+	if (is_compat_thread(task_thread_info(p)))
+		childregs->compat_sp = stack_start;
+	else {
+		/*
+		 * Read the current TLS pointer from tpidr_el0 as it may be
+		 * out-of-sync with the saved value.
+		 */
+		asm("mrs %0, tpidr_el0" : "=r" (tls));
+		childregs->sp = stack_start;
+	}
+
+	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
+	p->thread.cpu_context.sp = (unsigned long)childregs;
+	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+
+	/* If a TLS pointer was passed to clone, use that for the new thread. */
+	if (clone_flags & CLONE_SETTLS)
+		tls = regs->regs[3];
+	p->thread.tp_value = tls;
+
+	ptrace_hw_copy_thread(p);
+
+	return 0;
+}
+
+static void tls_thread_switch(struct task_struct *next)
+{
+	unsigned long tpidr, tpidrro;
+
+	if (!is_compat_task()) {
+		asm("mrs %0, tpidr_el0" : "=r" (tpidr));
+		current->thread.tp_value = tpidr;
+	}
+
+	if (is_compat_thread(task_thread_info(next))) {
+		tpidr = 0;
+		tpidrro = next->thread.tp_value;
+	} else {
+		tpidr = next->thread.tp_value;
+		tpidrro = 0;
+	}
+
+	asm(
+	"	msr	tpidr_el0, %0\n"
+	"	msr	tpidrro_el0, %1"
+	: : "r" (tpidr), "r" (tpidrro));
+}
+
+/*
+ * Thread switching.
+ */
+struct task_struct *__switch_to(struct task_struct *prev,
+				struct task_struct *next)
+{
+	struct task_struct *last;
+
+	fpsimd_thread_switch(next);
+	tls_thread_switch(next);
+	hw_breakpoint_thread_switch(next);
+
+	/* the actual thread switch */
+	last = cpu_switch_to(prev, next);
+
+	return last;
+}
+
+/*
+ * Fill in the task's elfregs structure for a core dump.
+ */
+int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)
+{
+	elf_core_copy_regs(elfregs, task_pt_regs(t));
+	return 1;
+}
+
+/*
+ * fill in the fpe structure for a core dump...
+ */
+int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
+{
+	return 0;
+}
+EXPORT_SYMBOL(dump_fpu);
+
+/*
+ * Shuffle the argument into the correct register before calling the
+ * thread function.  x1 is the thread argument, x2 is the pointer to
+ * the thread function, and x3 points to the exit function.
+ */
+extern void kernel_thread_helper(void);
+asm(	".section .text\n"
+"	.align\n"
+"	.type	kernel_thread_helper, #function\n"
+"kernel_thread_helper:\n"
+"	mov	x0, x1\n"
+"	mov	x30, x3\n"
+"	br	x2\n"
+"	.size	kernel_thread_helper, . - kernel_thread_helper\n"
+"	.previous");
+
+#define kernel_thread_exit	do_exit
+
+/*
+ * Create a kernel thread.
+ */
+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+	regs.regs[1] = (unsigned long)arg;
+	regs.regs[2] = (unsigned long)fn;
+	regs.regs[3] = (unsigned long)kernel_thread_exit;
+	regs.pc = (unsigned long)kernel_thread_helper;
+	regs.pstate = PSR_MODE_EL1h;
+
+	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	struct stackframe frame;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	frame.fp = thread_saved_fp(p);
+	frame.sp = thread_saved_sp(p);
+	frame.pc = thread_saved_pc(p);
+	do {
+		int ret = unwind_frame(&frame);
+		if (ret < 0)
+			return 0;
+		if (!in_sched_functions(frame.pc))
+			return frame.pc;
+	} while (count ++ < 16);
+	return 0;
+}
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+		sp -= get_random_int() & ~PAGE_MASK;
+	return sp & ~0xf;
+}
+
+static unsigned long randomize_base(unsigned long base)
+{
+	unsigned long range_end = base + (STACK_RND_MASK << PAGE_SHIFT) + 1;
+	return randomize_range(base, range_end, 0) ? : base;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+	return randomize_base(mm->brk);
+}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+	return randomize_base(base);
+}
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
new file mode 100644
index 0000000..ac3550e
--- /dev/null
+++ b/arch/arm64/kernel/ptrace.c
@@ -0,0 +1,1126 @@
+/*
+ * Based on arch/arm/kernel/ptrace.c
+ *
+ * By Ross Biro 1/23/92
+ * edited by Linus Torvalds
+ * ARM modifications Copyright (C) 2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/regset.h>
+#include <linux/tracehook.h>
+#include <linux/elf.h>
+
+#include <asm/compat.h>
+#include <asm/debug-monitors.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/system_misc.h>
+
+/*
+ * TODO: does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+}
+
+/*
+ * Handle hitting a breakpoint.
+ */
+static int ptrace_break(struct pt_regs *regs)
+{
+	siginfo_t info = {
+		.si_signo = SIGTRAP,
+		.si_errno = 0,
+		.si_code  = TRAP_BRKPT,
+		.si_addr  = (void __user *)instruction_pointer(regs),
+	};
+
+	force_sig_info(SIGTRAP, &info, current);
+	return 0;
+}
+
+static int arm64_break_trap(unsigned long addr, unsigned int esr,
+			    struct pt_regs *regs)
+{
+	return ptrace_break(regs);
+}
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+/*
+ * Handle hitting a HW-breakpoint.
+ */
+static void ptrace_hbptriggered(struct perf_event *bp,
+				struct perf_sample_data *data,
+				struct pt_regs *regs)
+{
+	struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
+	siginfo_t info = {
+		.si_signo	= SIGTRAP,
+		.si_errno	= 0,
+		.si_code	= TRAP_HWBKPT,
+		.si_addr	= (void __user *)(bkpt->trigger),
+	};
+
+#ifdef CONFIG_COMPAT
+	int i;
+
+	if (!is_compat_task())
+		goto send_sig;
+
+	for (i = 0; i < ARM_MAX_BRP; ++i) {
+		if (current->thread.debug.hbp_break[i] == bp) {
+			info.si_errno = (i << 1) + 1;
+			break;
+		}
+	}
+	for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) {
+		if (current->thread.debug.hbp_watch[i] == bp) {
+			info.si_errno = -((i << 1) + 1);
+			break;
+		}
+	}
+
+send_sig:
+#endif
+	force_sig_info(SIGTRAP, &info, current);
+}
+
+/*
+ * Unregister breakpoints from this task and reset the pointers in
+ * the thread_struct.
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+	int i;
+	struct thread_struct *t = &tsk->thread;
+
+	for (i = 0; i < ARM_MAX_BRP; i++) {
+		if (t->debug.hbp_break[i]) {
+			unregister_hw_breakpoint(t->debug.hbp_break[i]);
+			t->debug.hbp_break[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < ARM_MAX_WRP; i++) {
+		if (t->debug.hbp_watch[i]) {
+			unregister_hw_breakpoint(t->debug.hbp_watch[i]);
+			t->debug.hbp_watch[i] = NULL;
+		}
+	}
+}
+
+void ptrace_hw_copy_thread(struct task_struct *tsk)
+{
+	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
+}
+
+static struct perf_event *ptrace_hbp_get_event(unsigned int note_type,
+					       struct task_struct *tsk,
+					       unsigned long idx)
+{
+	struct perf_event *bp = ERR_PTR(-EINVAL);
+
+	switch (note_type) {
+	case NT_ARM_HW_BREAK:
+		if (idx < ARM_MAX_BRP)
+			bp = tsk->thread.debug.hbp_break[idx];
+		break;
+	case NT_ARM_HW_WATCH:
+		if (idx < ARM_MAX_WRP)
+			bp = tsk->thread.debug.hbp_watch[idx];
+		break;
+	}
+
+	return bp;
+}
+
+static int ptrace_hbp_set_event(unsigned int note_type,
+				struct task_struct *tsk,
+				unsigned long idx,
+				struct perf_event *bp)
+{
+	int err = -EINVAL;
+
+	switch (note_type) {
+	case NT_ARM_HW_BREAK:
+		if (idx < ARM_MAX_BRP) {
+			tsk->thread.debug.hbp_break[idx] = bp;
+			err = 0;
+		}
+		break;
+	case NT_ARM_HW_WATCH:
+		if (idx < ARM_MAX_WRP) {
+			tsk->thread.debug.hbp_watch[idx] = bp;
+			err = 0;
+		}
+		break;
+	}
+
+	return err;
+}
+
+static struct perf_event *ptrace_hbp_create(unsigned int note_type,
+					    struct task_struct *tsk,
+					    unsigned long idx)
+{
+	struct perf_event *bp;
+	struct perf_event_attr attr;
+	int err, type;
+
+	switch (note_type) {
+	case NT_ARM_HW_BREAK:
+		type = HW_BREAKPOINT_X;
+		break;
+	case NT_ARM_HW_WATCH:
+		type = HW_BREAKPOINT_RW;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	ptrace_breakpoint_init(&attr);
+
+	/*
+	 * Initialise fields to sane defaults
+	 * (i.e. values that will pass validation).
+	 */
+	attr.bp_addr	= 0;
+	attr.bp_len	= HW_BREAKPOINT_LEN_4;
+	attr.bp_type	= type;
+	attr.disabled	= 1;
+
+	bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk);
+	if (IS_ERR(bp))
+		return bp;
+
+	err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
+	if (err)
+		return ERR_PTR(err);
+
+	return bp;
+}
+
+static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
+				     struct arch_hw_breakpoint_ctrl ctrl,
+				     struct perf_event_attr *attr)
+{
+	int err, len, type;
+
+	err = arch_bp_generic_fields(ctrl, &len, &type);
+	if (err)
+		return err;
+
+	switch (note_type) {
+	case NT_ARM_HW_BREAK:
+		if ((type & HW_BREAKPOINT_X) != type)
+			return -EINVAL;
+		break;
+	case NT_ARM_HW_WATCH:
+		if ((type & HW_BREAKPOINT_RW) != type)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	attr->bp_len	= len;
+	attr->bp_type	= type;
+	attr->disabled	= !ctrl.enabled;
+
+	return 0;
+}
+
+static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info)
+{
+	u8 num;
+	u32 reg = 0;
+
+	switch (note_type) {
+	case NT_ARM_HW_BREAK:
+		num = hw_breakpoint_slots(TYPE_INST);
+		break;
+	case NT_ARM_HW_WATCH:
+		num = hw_breakpoint_slots(TYPE_DATA);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg |= debug_monitors_arch();
+	reg <<= 8;
+	reg |= num;
+
+	*info = reg;
+	return 0;
+}
+
+static int ptrace_hbp_get_ctrl(unsigned int note_type,
+			       struct task_struct *tsk,
+			       unsigned long idx,
+			       u32 *ctrl)
+{
+	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
+
+	if (IS_ERR(bp))
+		return PTR_ERR(bp);
+
+	*ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
+	return 0;
+}
+
+static int ptrace_hbp_get_addr(unsigned int note_type,
+			       struct task_struct *tsk,
+			       unsigned long idx,
+			       u64 *addr)
+{
+	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
+
+	if (IS_ERR(bp))
+		return PTR_ERR(bp);
+
+	*addr = bp ? bp->attr.bp_addr : 0;
+	return 0;
+}
+
+static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type,
+							struct task_struct *tsk,
+							unsigned long idx)
+{
+	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
+
+	if (!bp)
+		bp = ptrace_hbp_create(note_type, tsk, idx);
+
+	return bp;
+}
+
+static int ptrace_hbp_set_ctrl(unsigned int note_type,
+			       struct task_struct *tsk,
+			       unsigned long idx,
+			       u32 uctrl)
+{
+	int err;
+	struct perf_event *bp;
+	struct perf_event_attr attr;
+	struct arch_hw_breakpoint_ctrl ctrl;
+
+	bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
+	if (IS_ERR(bp)) {
+		err = PTR_ERR(bp);
+		return err;
+	}
+
+	attr = bp->attr;
+	decode_ctrl_reg(uctrl, &ctrl);
+	err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
+	if (err)
+		return err;
+
+	return modify_user_hw_breakpoint(bp, &attr);
+}
+
+static int ptrace_hbp_set_addr(unsigned int note_type,
+			       struct task_struct *tsk,
+			       unsigned long idx,
+			       u64 addr)
+{
+	int err;
+	struct perf_event *bp;
+	struct perf_event_attr attr;
+
+	bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
+	if (IS_ERR(bp)) {
+		err = PTR_ERR(bp);
+		return err;
+	}
+
+	attr = bp->attr;
+	attr.bp_addr = addr;
+	err = modify_user_hw_breakpoint(bp, &attr);
+	return err;
+}
+
+#define PTRACE_HBP_ADDR_SZ	sizeof(u64)
+#define PTRACE_HBP_CTRL_SZ	sizeof(u32)
+#define PTRACE_HBP_REG_OFF	sizeof(u32)
+
+static int hw_break_get(struct task_struct *target,
+			const struct user_regset *regset,
+			unsigned int pos, unsigned int count,
+			void *kbuf, void __user *ubuf)
+{
+	unsigned int note_type = regset->core_note_type;
+	int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit;
+	u32 info, ctrl;
+	u64 addr;
+
+	/* Resource info */
+	ret = ptrace_hbp_get_resource_info(note_type, &info);
+	if (ret)
+		return ret;
+
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, 4);
+	if (ret)
+		return ret;
+
+	/* (address, ctrl) registers */
+	limit = regset->n * regset->size;
+	while (count && offset < limit) {
+		ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
+		if (ret)
+			return ret;
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
+					  offset, offset + PTRACE_HBP_ADDR_SZ);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_ADDR_SZ;
+
+		ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
+		if (ret)
+			return ret;
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
+					  offset, offset + PTRACE_HBP_CTRL_SZ);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_CTRL_SZ;
+		idx++;
+	}
+
+	return 0;
+}
+
+static int hw_break_set(struct task_struct *target,
+			const struct user_regset *regset,
+			unsigned int pos, unsigned int count,
+			const void *kbuf, const void __user *ubuf)
+{
+	unsigned int note_type = regset->core_note_type;
+	int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit;
+	u32 ctrl;
+	u64 addr;
+
+	/* Resource info */
+	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
+	if (ret)
+		return ret;
+
+	/* (address, ctrl) registers */
+	limit = regset->n * regset->size;
+	while (count && offset < limit) {
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
+					 offset, offset + PTRACE_HBP_ADDR_SZ);
+		if (ret)
+			return ret;
+		ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_ADDR_SZ;
+
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
+					 offset, offset + PTRACE_HBP_CTRL_SZ);
+		if (ret)
+			return ret;
+		ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_CTRL_SZ;
+		idx++;
+	}
+
+	return 0;
+}
+#endif	/* CONFIG_HAVE_HW_BREAKPOINT */
+
+static int gpr_get(struct task_struct *target,
+		   const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
+}
+
+static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	struct user_pt_regs newregs;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
+	if (ret)
+		return ret;
+
+	if (!valid_user_regs(&newregs))
+		return -EINVAL;
+
+	task_pt_regs(target)->user_regs = newregs;
+	return 0;
+}
+
+/*
+ * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
+ */
+static int fpr_get(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	struct user_fpsimd_state *uregs;
+	uregs = &target->thread.fpsimd_state.user_fpsimd;
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
+}
+
+static int fpr_set(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	struct user_fpsimd_state newstate;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
+	if (ret)
+		return ret;
+
+	target->thread.fpsimd_state.user_fpsimd = newstate;
+	return ret;
+}
+
+static int tls_get(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	unsigned long *tls = &target->thread.tp_value;
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
+}
+
+static int tls_set(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	unsigned long tls;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+	if (ret)
+		return ret;
+
+	target->thread.tp_value = tls;
+	return ret;
+}
+
+enum aarch64_regset {
+	REGSET_GPR,
+	REGSET_FPR,
+	REGSET_TLS,
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+	REGSET_HW_BREAK,
+	REGSET_HW_WATCH,
+#endif
+};
+
+static const struct user_regset aarch64_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type = NT_PRSTATUS,
+		.n = sizeof(struct user_pt_regs) / sizeof(u64),
+		.size = sizeof(u64),
+		.align = sizeof(u64),
+		.get = gpr_get,
+		.set = gpr_set
+	},
+	[REGSET_FPR] = {
+		.core_note_type = NT_PRFPREG,
+		.n = sizeof(struct user_fpsimd_state) / sizeof(u32),
+		/*
+		 * We pretend we have 32-bit registers because the fpsr and
+		 * fpcr are 32-bits wide.
+		 */
+		.size = sizeof(u32),
+		.align = sizeof(u32),
+		.get = fpr_get,
+		.set = fpr_set
+	},
+	[REGSET_TLS] = {
+		.core_note_type = NT_ARM_TLS,
+		.n = 1,
+		.size = sizeof(void *),
+		.align = sizeof(void *),
+		.get = tls_get,
+		.set = tls_set,
+	},
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+	[REGSET_HW_BREAK] = {
+		.core_note_type = NT_ARM_HW_BREAK,
+		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
+		.size = sizeof(u32),
+		.align = sizeof(u32),
+		.get = hw_break_get,
+		.set = hw_break_set,
+	},
+	[REGSET_HW_WATCH] = {
+		.core_note_type = NT_ARM_HW_WATCH,
+		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
+		.size = sizeof(u32),
+		.align = sizeof(u32),
+		.get = hw_break_get,
+		.set = hw_break_set,
+	},
+#endif
+};
+
+static const struct user_regset_view user_aarch64_view = {
+	.name = "aarch64", .e_machine = EM_AARCH64,
+	.regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
+};
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+
+enum compat_regset {
+	REGSET_COMPAT_GPR,
+	REGSET_COMPAT_VFP,
+};
+
+static int compat_gpr_get(struct task_struct *target,
+			  const struct user_regset *regset,
+			  unsigned int pos, unsigned int count,
+			  void *kbuf, void __user *ubuf)
+{
+	int ret = 0;
+	unsigned int i, start, num_regs;
+
+	/* Calculate the number of AArch32 registers contained in count */
+	num_regs = count / regset->size;
+
+	/* Convert pos into an register number */
+	start = pos / regset->size;
+
+	if (start + num_regs > regset->n)
+		return -EIO;
+
+	for (i = 0; i < num_regs; ++i) {
+		unsigned int idx = start + i;
+		void *reg;
+
+		switch (idx) {
+		case 15:
+			reg = (void *)&task_pt_regs(target)->pc;
+			break;
+		case 16:
+			reg = (void *)&task_pt_regs(target)->pstate;
+			break;
+		case 17:
+			reg = (void *)&task_pt_regs(target)->orig_x0;
+			break;
+		default:
+			reg = (void *)&task_pt_regs(target)->regs[idx];
+		}
+
+		ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t));
+
+		if (ret)
+			break;
+		else
+			ubuf += sizeof(compat_ulong_t);
+	}
+
+	return ret;
+}
+
+static int compat_gpr_set(struct task_struct *target,
+			  const struct user_regset *regset,
+			  unsigned int pos, unsigned int count,
+			  const void *kbuf, const void __user *ubuf)
+{
+	struct pt_regs newregs;
+	int ret = 0;
+	unsigned int i, start, num_regs;
+
+	/* Calculate the number of AArch32 registers contained in count */
+	num_regs = count / regset->size;
+
+	/* Convert pos into an register number */
+	start = pos / regset->size;
+
+	if (start + num_regs > regset->n)
+		return -EIO;
+
+	newregs = *task_pt_regs(target);
+
+	for (i = 0; i < num_regs; ++i) {
+		unsigned int idx = start + i;
+		void *reg;
+
+		switch (idx) {
+		case 15:
+			reg = (void *)&newregs.pc;
+			break;
+		case 16:
+			reg = (void *)&newregs.pstate;
+			break;
+		case 17:
+			reg = (void *)&newregs.orig_x0;
+			break;
+		default:
+			reg = (void *)&newregs.regs[idx];
+		}
+
+		ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t));
+
+		if (ret)
+			goto out;
+		else
+			ubuf += sizeof(compat_ulong_t);
+	}
+
+	if (valid_user_regs(&newregs.user_regs))
+		*task_pt_regs(target) = newregs;
+	else
+		ret = -EINVAL;
+
+out:
+	return ret;
+}
+
+static int compat_vfp_get(struct task_struct *target,
+			  const struct user_regset *regset,
+			  unsigned int pos, unsigned int count,
+			  void *kbuf, void __user *ubuf)
+{
+	struct user_fpsimd_state *uregs;
+	compat_ulong_t fpscr;
+	int ret;
+
+	uregs = &target->thread.fpsimd_state.user_fpsimd;
+
+	/*
+	 * The VFP registers are packed into the fpsimd_state, so they all sit
+	 * nicely together for us. We just need to create the fpscr separately.
+	 */
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
+				  VFP_STATE_SIZE - sizeof(compat_ulong_t));
+
+	if (count && !ret) {
+		fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
+			(uregs->fpcr & VFP_FPSCR_CTRL_MASK);
+		ret = put_user(fpscr, (compat_ulong_t *)ubuf);
+	}
+
+	return ret;
+}
+
+static int compat_vfp_set(struct task_struct *target,
+			  const struct user_regset *regset,
+			  unsigned int pos, unsigned int count,
+			  const void *kbuf, const void __user *ubuf)
+{
+	struct user_fpsimd_state *uregs;
+	compat_ulong_t fpscr;
+	int ret;
+
+	if (pos + count > VFP_STATE_SIZE)
+		return -EIO;
+
+	uregs = &target->thread.fpsimd_state.user_fpsimd;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
+				 VFP_STATE_SIZE - sizeof(compat_ulong_t));
+
+	if (count && !ret) {
+		ret = get_user(fpscr, (compat_ulong_t *)ubuf);
+		uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK;
+		uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
+	}
+
+	return ret;
+}
+
+static const struct user_regset aarch32_regsets[] = {
+	[REGSET_COMPAT_GPR] = {
+		.core_note_type = NT_PRSTATUS,
+		.n = COMPAT_ELF_NGREG,
+		.size = sizeof(compat_elf_greg_t),
+		.align = sizeof(compat_elf_greg_t),
+		.get = compat_gpr_get,
+		.set = compat_gpr_set
+	},
+	[REGSET_COMPAT_VFP] = {
+		.core_note_type = NT_ARM_VFP,
+		.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
+		.size = sizeof(compat_ulong_t),
+		.align = sizeof(compat_ulong_t),
+		.get = compat_vfp_get,
+		.set = compat_vfp_set
+	},
+};
+
+static const struct user_regset_view user_aarch32_view = {
+	.name = "aarch32", .e_machine = EM_ARM,
+	.regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
+};
+
+int aarch32_break_trap(struct pt_regs *regs)
+{
+	unsigned int instr;
+	bool bp = false;
+	void __user *pc = (void __user *)instruction_pointer(regs);
+
+	if (compat_thumb_mode(regs)) {
+		/* get 16-bit Thumb instruction */
+		get_user(instr, (u16 __user *)pc);
+		if (instr == AARCH32_BREAK_THUMB2_LO) {
+			/* get second half of 32-bit Thumb-2 instruction */
+			get_user(instr, (u16 __user *)(pc + 2));
+			bp = instr == AARCH32_BREAK_THUMB2_HI;
+		} else {
+			bp = instr == AARCH32_BREAK_THUMB;
+		}
+	} else {
+		/* 32-bit ARM instruction */
+		get_user(instr, (u32 __user *)pc);
+		bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
+	}
+
+	if (bp)
+		return ptrace_break(regs);
+	return 1;
+}
+
+static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
+				   compat_ulong_t __user *ret)
+{
+	compat_ulong_t tmp;
+
+	if (off & 3)
+		return -EIO;
+
+	if (off == PT_TEXT_ADDR)
+		tmp = tsk->mm->start_code;
+	else if (off == PT_DATA_ADDR)
+		tmp = tsk->mm->start_data;
+	else if (off == PT_TEXT_END_ADDR)
+		tmp = tsk->mm->end_code;
+	else if (off < sizeof(compat_elf_gregset_t))
+		return copy_regset_to_user(tsk, &user_aarch32_view,
+					   REGSET_COMPAT_GPR, off,
+					   sizeof(compat_ulong_t), ret);
+	else if (off >= COMPAT_USER_SZ)
+		return -EIO;
+	else
+		tmp = 0;
+
+	return put_user(tmp, ret);
+}
+
+static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
+				    compat_ulong_t val)
+{
+	int ret;
+
+	if (off & 3 || off >= COMPAT_USER_SZ)
+		return -EIO;
+
+	if (off >= sizeof(compat_elf_gregset_t))
+		return 0;
+
+	ret = copy_regset_from_user(tsk, &user_aarch32_view,
+				    REGSET_COMPAT_GPR, off,
+				    sizeof(compat_ulong_t),
+				    &val);
+	return ret;
+}
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+/*
+ * Convert a virtual register number into an index for a thread_info
+ * breakpoint array. Breakpoints are identified using positive numbers
+ * whilst watchpoints are negative. The registers are laid out as pairs
+ * of (address, control), each pair mapping to a unique hw_breakpoint struct.
+ * Register 0 is reserved for describing resource information.
+ */
+static int compat_ptrace_hbp_num_to_idx(compat_long_t num)
+{
+	return (abs(num) - 1) >> 1;
+}
+
+static int compat_ptrace_hbp_get_resource_info(u32 *kdata)
+{
+	u8 num_brps, num_wrps, debug_arch, wp_len;
+	u32 reg = 0;
+
+	num_brps	= hw_breakpoint_slots(TYPE_INST);
+	num_wrps	= hw_breakpoint_slots(TYPE_DATA);
+
+	debug_arch	= debug_monitors_arch();
+	wp_len		= 8;
+	reg		|= debug_arch;
+	reg		<<= 8;
+	reg		|= wp_len;
+	reg		<<= 8;
+	reg		|= num_wrps;
+	reg		<<= 8;
+	reg		|= num_brps;
+
+	*kdata = reg;
+	return 0;
+}
+
+static int compat_ptrace_hbp_get(unsigned int note_type,
+				 struct task_struct *tsk,
+				 compat_long_t num,
+				 u32 *kdata)
+{
+	u64 addr = 0;
+	u32 ctrl = 0;
+
+	int err, idx = compat_ptrace_hbp_num_to_idx(num);;
+
+	if (num & 1) {
+		err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
+		*kdata = (u32)addr;
+	} else {
+		err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl);
+		*kdata = ctrl;
+	}
+
+	return err;
+}
+
+static int compat_ptrace_hbp_set(unsigned int note_type,
+				 struct task_struct *tsk,
+				 compat_long_t num,
+				 u32 *kdata)
+{
+	u64 addr;
+	u32 ctrl;
+
+	int err, idx = compat_ptrace_hbp_num_to_idx(num);
+
+	if (num & 1) {
+		addr = *kdata;
+		err = ptrace_hbp_set_addr(note_type, tsk, idx, addr);
+	} else {
+		ctrl = *kdata;
+		err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl);
+	}
+
+	return err;
+}
+
+static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num,
+				    compat_ulong_t __user *data)
+{
+	int ret;
+	u32 kdata;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	/* Watchpoint */
+	if (num < 0) {
+		ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata);
+	/* Resource info */
+	} else if (num == 0) {
+		ret = compat_ptrace_hbp_get_resource_info(&kdata);
+	/* Breakpoint */
+	} else {
+		ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata);
+	}
+	set_fs(old_fs);
+
+	if (!ret)
+		ret = put_user(kdata, data);
+
+	return ret;
+}
+
+static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
+				    compat_ulong_t __user *data)
+{
+	int ret;
+	u32 kdata = 0;
+	mm_segment_t old_fs = get_fs();
+
+	if (num == 0)
+		return 0;
+
+	ret = get_user(kdata, data);
+	if (ret)
+		return ret;
+
+	set_fs(KERNEL_DS);
+	if (num < 0)
+		ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata);
+	else
+		ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata);
+	set_fs(old_fs);
+
+	return ret;
+}
+#endif	/* CONFIG_HAVE_HW_BREAKPOINT */
+
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+			compat_ulong_t caddr, compat_ulong_t cdata)
+{
+	unsigned long addr = caddr;
+	unsigned long data = cdata;
+	void __user *datap = compat_ptr(data);
+	int ret;
+
+	switch (request) {
+		case PTRACE_PEEKUSR:
+			ret = compat_ptrace_read_user(child, addr, datap);
+			break;
+
+		case PTRACE_POKEUSR:
+			ret = compat_ptrace_write_user(child, addr, data);
+			break;
+
+		case COMPAT_PTRACE_GETREGS:
+			ret = copy_regset_to_user(child,
+						  &user_aarch32_view,
+						  REGSET_COMPAT_GPR,
+						  0, sizeof(compat_elf_gregset_t),
+						  datap);
+			break;
+
+		case COMPAT_PTRACE_SETREGS:
+			ret = copy_regset_from_user(child,
+						    &user_aarch32_view,
+						    REGSET_COMPAT_GPR,
+						    0, sizeof(compat_elf_gregset_t),
+						    datap);
+			break;
+
+		case COMPAT_PTRACE_GET_THREAD_AREA:
+			ret = put_user((compat_ulong_t)child->thread.tp_value,
+				       (compat_ulong_t __user *)datap);
+			break;
+
+		case COMPAT_PTRACE_SET_SYSCALL:
+			task_pt_regs(child)->syscallno = data;
+			ret = 0;
+			break;
+
+		case COMPAT_PTRACE_GETVFPREGS:
+			ret = copy_regset_to_user(child,
+						  &user_aarch32_view,
+						  REGSET_COMPAT_VFP,
+						  0, VFP_STATE_SIZE,
+						  datap);
+			break;
+
+		case COMPAT_PTRACE_SETVFPREGS:
+			ret = copy_regset_from_user(child,
+						    &user_aarch32_view,
+						    REGSET_COMPAT_VFP,
+						    0, VFP_STATE_SIZE,
+						    datap);
+			break;
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+		case COMPAT_PTRACE_GETHBPREGS:
+			ret = compat_ptrace_gethbpregs(child, addr, datap);
+			break;
+
+		case COMPAT_PTRACE_SETHBPREGS:
+			ret = compat_ptrace_sethbpregs(child, addr, datap);
+			break;
+#endif
+
+		default:
+			ret = compat_ptrace_request(child, request, addr,
+						    data);
+			break;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_COMPAT
+	if (is_compat_thread(task_thread_info(task)))
+		return &user_aarch32_view;
+#endif
+	return &user_aarch64_view;
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
+{
+	return ptrace_request(child, request, addr, data);
+}
+
+
+static int __init ptrace_break_init(void)
+{
+	hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
+			      TRAP_BRKPT, "ptrace BRK handler");
+	return 0;
+}
+core_initcall(ptrace_break_init);
+
+
+asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return regs->syscallno;
+
+	if (is_compat_task()) {
+		/* AArch32 uses ip (r12) for scratch */
+		saved_reg = regs->regs[12];
+		regs->regs[12] = dir;
+	} else {
+		/*
+		 * Save X7. X7 is used to denote syscall entry/exit:
+		 *   X7 = 0 -> entry, = 1 -> exit
+		 */
+		saved_reg = regs->regs[7];
+		regs->regs[7] = dir;
+	}
+
+	if (dir)
+		tracehook_report_syscall_exit(regs, 0);
+	else if (tracehook_report_syscall_entry(regs))
+		regs->syscallno = ~0UL;
+
+	if (is_compat_task())
+		regs->regs[12] = saved_reg;
+	else
+		regs->regs[7] = saved_reg;
+
+	return regs->syscallno;
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
new file mode 100644
index 0000000..48ffb9f
--- /dev/null
+++ b/arch/arm64/kernel/setup.c
@@ -0,0 +1,347 @@
+/*
+ * Based on arch/arm/kernel/setup.c
+ *
+ * Copyright (C) 1995-2001 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/utsname.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/screen_info.h>
+#include <linux/init.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
+#include <linux/root_dev.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/memblock.h>
+#include <linux/of_fdt.h>
+
+#include <asm/cputype.h>
+#include <asm/elf.h>
+#include <asm/cputable.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/traps.h>
+#include <asm/memblock.h>
+
+unsigned int processor_id;
+EXPORT_SYMBOL(processor_id);
+
+unsigned int elf_hwcap __read_mostly;
+EXPORT_SYMBOL_GPL(elf_hwcap);
+
+static const char *cpu_name;
+static const char *machine_name;
+phys_addr_t __fdt_pointer __initdata;
+
+/*
+ * Standard memory resources
+ */
+static struct resource mem_res[] = {
+	{
+		.name = "Kernel code",
+		.start = 0,
+		.end = 0,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.name = "Kernel data",
+		.start = 0,
+		.end = 0,
+		.flags = IORESOURCE_MEM
+	}
+};
+
+#define kernel_code mem_res[0]
+#define kernel_data mem_res[1]
+
+void __init early_print(const char *str, ...)
+{
+	char buf[256];
+	va_list ap;
+
+	va_start(ap, str);
+	vsnprintf(buf, sizeof(buf), str, ap);
+	va_end(ap);
+
+	printk("%s", buf);
+}
+
+static void __init setup_processor(void)
+{
+	struct cpu_info *cpu_info;
+
+	/*
+	 * locate processor in the list of supported processor
+	 * types.  The linker builds this table for us from the
+	 * entries in arch/arm/mm/proc.S
+	 */
+	cpu_info = lookup_processor_type(read_cpuid_id());
+	if (!cpu_info) {
+		printk("CPU configuration botched (ID %08x), unable to continue.\n",
+		       read_cpuid_id());
+		while (1);
+	}
+
+	cpu_name = cpu_info->cpu_name;
+
+	printk("CPU: %s [%08x] revision %d\n",
+	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
+
+	sprintf(init_utsname()->machine, "aarch64");
+	elf_hwcap = 0;
+}
+
+static void __init setup_machine_fdt(phys_addr_t dt_phys)
+{
+	struct boot_param_header *devtree;
+	unsigned long dt_root;
+
+	/* Check we have a non-NULL DT pointer */
+	if (!dt_phys) {
+		early_print("\n"
+			"Error: NULL or invalid device tree blob\n"
+			"The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
+			"\nPlease check your bootloader.\n");
+
+		while (true)
+			cpu_relax();
+
+	}
+
+	devtree = phys_to_virt(dt_phys);
+
+	/* Check device tree validity */
+	if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) {
+		early_print("\n"
+			"Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
+			"Expected 0x%x, found 0x%x\n"
+			"\nPlease check your bootloader.\n",
+			dt_phys, devtree, OF_DT_HEADER,
+			be32_to_cpu(devtree->magic));
+
+		while (true)
+			cpu_relax();
+	}
+
+	initial_boot_params = devtree;
+	dt_root = of_get_flat_dt_root();
+
+	machine_name = of_get_flat_dt_prop(dt_root, "model", NULL);
+	if (!machine_name)
+		machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
+	if (!machine_name)
+		machine_name = "<unknown>";
+	pr_info("Machine: %s\n", machine_name);
+
+	/* Retrieve various information from the /chosen node */
+	of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
+	/* Initialize {size,address}-cells info */
+	of_scan_flat_dt(early_init_dt_scan_root, NULL);
+	/* Setup memory, calling early_init_dt_add_memory_arch */
+	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+	size &= PAGE_MASK;
+	memblock_add(base, size);
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+	return __va(memblock_alloc(size, align));
+}
+
+/*
+ * Limit the memory size that was specified via FDT.
+ */
+static int __init early_mem(char *p)
+{
+	phys_addr_t limit;
+
+	if (!p)
+		return 1;
+
+	limit = memparse(p, &p) & PAGE_MASK;
+	pr_notice("Memory limited to %lldMB\n", limit >> 20);
+
+	memblock_enforce_memory_limit(limit);
+
+	return 0;
+}
+early_param("mem", early_mem);
+
+static void __init request_standard_resources(void)
+{
+	struct memblock_region *region;
+	struct resource *res;
+
+	kernel_code.start   = virt_to_phys(_text);
+	kernel_code.end     = virt_to_phys(_etext - 1);
+	kernel_data.start   = virt_to_phys(_sdata);
+	kernel_data.end     = virt_to_phys(_end - 1);
+
+	for_each_memblock(memory, region) {
+		res = alloc_bootmem_low(sizeof(*res));
+		res->name  = "System RAM";
+		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
+		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+		request_resource(&iomem_resource, res);
+
+		if (kernel_code.start >= res->start &&
+		    kernel_code.end <= res->end)
+			request_resource(res, &kernel_code);
+		if (kernel_data.start >= res->start &&
+		    kernel_data.end <= res->end)
+			request_resource(res, &kernel_data);
+	}
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	setup_processor();
+
+	setup_machine_fdt(__fdt_pointer);
+
+	init_mm.start_code = (unsigned long) _text;
+	init_mm.end_code   = (unsigned long) _etext;
+	init_mm.end_data   = (unsigned long) _edata;
+	init_mm.brk	   = (unsigned long) _end;
+
+	*cmdline_p = boot_command_line;
+
+	parse_early_param();
+
+	arm64_memblock_init();
+
+	paging_init();
+	request_standard_resources();
+
+	unflatten_device_tree();
+
+#ifdef CONFIG_SMP
+	smp_init_cpus();
+#endif
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+#endif
+}
+
+static DEFINE_PER_CPU(struct cpu, cpu_data);
+
+static int __init topology_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		struct cpu *cpu = &per_cpu(cpu_data, i);
+		cpu->hotpluggable = 1;
+		register_cpu(cpu, i);
+	}
+
+	return 0;
+}
+subsys_initcall(topology_init);
+
+static const char *hwcap_str[] = {
+	"fp",
+	"asimd",
+	NULL
+};
+
+static int c_show(struct seq_file *m, void *v)
+{
+	int i;
+
+	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
+		   cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
+
+	for_each_online_cpu(i) {
+		/*
+		 * glibc reads /proc/cpuinfo to determine the number of
+		 * online processors, looking for lines beginning with
+		 * "processor".  Give glibc what it expects.
+		 */
+#ifdef CONFIG_SMP
+		seq_printf(m, "processor\t: %d\n", i);
+#endif
+		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
+			   loops_per_jiffy / (500000UL/HZ),
+			   loops_per_jiffy / (5000UL/HZ) % 100);
+	}
+
+	/* dump out the processor features */
+	seq_puts(m, "Features\t: ");
+
+	for (i = 0; hwcap_str[i]; i++)
+		if (elf_hwcap & (1 << i))
+			seq_printf(m, "%s ", hwcap_str[i]);
+
+	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
+	seq_printf(m, "CPU architecture: AArch64\n");
+	seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
+	seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
+	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
+
+	seq_puts(m, "\n");
+
+	seq_printf(m, "Hardware\t: %s\n", machine_name);
+
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= c_show
+};
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
new file mode 100644
index 0000000..8807ba2
--- /dev/null
+++ b/arch/arm64/kernel/signal.c
@@ -0,0 +1,437 @@
+/*
+ * Based on arch/arm/kernel/signal.c
+ *
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/personality.h>
+#include <linux/freezer.h>
+#include <linux/uaccess.h>
+#include <linux/tracehook.h>
+#include <linux/ratelimit.h>
+
+#include <asm/compat.h>
+#include <asm/debug-monitors.h>
+#include <asm/elf.h>
+#include <asm/cacheflush.h>
+#include <asm/ucontext.h>
+#include <asm/unistd.h>
+#include <asm/fpsimd.h>
+#include <asm/signal32.h>
+#include <asm/vdso.h>
+
+/*
+ * Do a signal return; undo the signal stack. These are aligned to 128-bit.
+ */
+struct rt_sigframe {
+	struct siginfo info;
+	struct ucontext uc;
+};
+
+static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
+{
+	struct fpsimd_state *fpsimd = &current->thread.fpsimd_state;
+	int err;
+
+	/* dump the hardware registers to the fpsimd_state structure */
+	fpsimd_save_state(fpsimd);
+
+	/* copy the FP and status/control registers */
+	err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
+	__put_user_error(fpsimd->fpsr, &ctx->fpsr, err);
+	__put_user_error(fpsimd->fpcr, &ctx->fpcr, err);
+
+	/* copy the magic/size information */
+	__put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err);
+	__put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err);
+
+	return err ? -EFAULT : 0;
+}
+
+static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
+{
+	struct fpsimd_state fpsimd;
+	__u32 magic, size;
+	int err = 0;
+
+	/* check the magic/size information */
+	__get_user_error(magic, &ctx->head.magic, err);
+	__get_user_error(size, &ctx->head.size, err);
+	if (err)
+		return -EFAULT;
+	if (magic != FPSIMD_MAGIC || size != sizeof(struct fpsimd_context))
+		return -EINVAL;
+
+	/* copy the FP and status/control registers */
+	err = __copy_from_user(fpsimd.vregs, ctx->vregs,
+			       sizeof(fpsimd.vregs));
+	__get_user_error(fpsimd.fpsr, &ctx->fpsr, err);
+	__get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
+
+	/* load the hardware registers from the fpsimd_state structure */
+	if (!err) {
+		preempt_disable();
+		fpsimd_load_state(&fpsimd);
+		preempt_enable();
+	}
+
+	return err ? -EFAULT : 0;
+}
+
+static int restore_sigframe(struct pt_regs *regs,
+			    struct rt_sigframe __user *sf)
+{
+	sigset_t set;
+	int i, err;
+	struct aux_context __user *aux =
+		(struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
+
+	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+	if (err == 0)
+		set_current_blocked(&set);
+
+	for (i = 0; i < 31; i++)
+		__get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+				 err);
+	__get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+	__get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+	__get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+	/*
+	 * Avoid sys_rt_sigreturn() restarting.
+	 */
+	regs->syscallno = ~0UL;
+
+	err |= !valid_user_regs(&regs->user_regs);
+
+	if (err == 0)
+		err |= restore_fpsimd_context(&aux->fpsimd);
+
+	return err;
+}
+
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/*
+	 * Since we stacked the signal on a 128-bit boundary, then 'sp' should
+	 * be word aligned here.
+	 */
+	if (regs->sp & 15)
+		goto badframe;
+
+	frame = (struct rt_sigframe __user *)regs->sp;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
+		goto badframe;
+
+	if (restore_sigframe(regs, frame))
+		goto badframe;
+
+	if (do_sigaltstack(&frame->uc.uc_stack,
+			   NULL, regs->sp) == -EFAULT)
+		goto badframe;
+
+	return regs->regs[0];
+
+badframe:
+	if (show_unhandled_signals)
+		pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
+				    current->comm, task_pid_nr(current), __func__,
+				    regs->pc, regs->sp);
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+				unsigned long sp)
+{
+	return do_sigaltstack(uss, uoss, sp);
+}
+
+static int setup_sigframe(struct rt_sigframe __user *sf,
+			  struct pt_regs *regs, sigset_t *set)
+{
+	int i, err = 0;
+	struct aux_context __user *aux =
+		(struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
+
+	for (i = 0; i < 31; i++)
+		__put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+				 err);
+	__put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+	__put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+	__put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+	__put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
+
+	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+
+	if (err == 0)
+		err |= preserve_fpsimd_context(&aux->fpsimd);
+
+	/* set the "end" magic */
+	__put_user_error(0, &aux->end.magic, err);
+	__put_user_error(0, &aux->end.size, err);
+
+	return err;
+}
+
+static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+				 int framesize)
+{
+	unsigned long sp, sp_top;
+	void __user *frame;
+
+	sp = sp_top = regs->sp;
+
+	/*
+	 * This is the X/Open sanctioned signal stack switching.
+	 */
+	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
+		sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
+
+	/* room for stack frame (FP, LR) */
+	sp -= 16;
+
+	sp = (sp - framesize) & ~15;
+	frame = (void __user *)sp;
+
+	/*
+	 * Check that we can actually write to the signal frame.
+	 */
+	if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
+		frame = NULL;
+
+	return frame;
+}
+
+static int setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+			void __user *frame, int usig)
+{
+	int err = 0;
+	__sigrestore_t sigtramp;
+	unsigned long __user *sp = (unsigned long __user *)regs->sp;
+
+	/* set up the stack frame */
+	__put_user_error(regs->regs[29], sp - 2, err);
+	__put_user_error(regs->regs[30], sp - 1, err);
+
+	regs->regs[0] = usig;
+	regs->regs[29] = regs->sp - 16;
+	regs->sp = (unsigned long)frame;
+	regs->pc = (unsigned long)ka->sa.sa_handler;
+
+	if (ka->sa.sa_flags & SA_RESTORER)
+		sigtramp = ka->sa.sa_restorer;
+	else
+		sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
+
+	regs->regs[30] = (unsigned long)sigtramp;
+
+	return err;
+}
+
+static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+			  sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame;
+	stack_t stack;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!frame)
+		return 1;
+
+	__put_user_error(0, &frame->uc.uc_flags, err);
+	__put_user_error(NULL, &frame->uc.uc_link, err);
+
+	memset(&stack, 0, sizeof(stack));
+	stack.ss_sp = (void __user *)current->sas_ss_sp;
+	stack.ss_flags = sas_ss_flags(regs->sp);
+	stack.ss_size = current->sas_ss_size;
+	err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
+
+	err |= setup_sigframe(frame, regs, set);
+	if (err == 0)
+		err = setup_return(regs, ka, frame, usig);
+
+	if (err == 0 && ka->sa.sa_flags & SA_SIGINFO) {
+		err |= copy_siginfo_to_user(&frame->info, info);
+		regs->regs[1] = (unsigned long)&frame->info;
+		regs->regs[2] = (unsigned long)&frame->uc;
+	}
+
+	return err;
+}
+
+static void setup_restart_syscall(struct pt_regs *regs)
+{
+	if (is_compat_task())
+		compat_setup_restart_syscall(regs);
+	else
+		regs->regs[8] = __NR_restart_syscall;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void handle_signal(unsigned long sig, struct k_sigaction *ka,
+			  siginfo_t *info, struct pt_regs *regs)
+{
+	struct thread_info *thread = current_thread_info();
+	struct task_struct *tsk = current;
+	sigset_t *oldset = sigmask_to_save();
+	int usig = sig;
+	int ret;
+
+	/*
+	 * translate the signal
+	 */
+	if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
+		usig = thread->exec_domain->signal_invmap[usig];
+
+	/*
+	 * Set up the stack frame
+	 */
+	if (is_compat_task()) {
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			ret = compat_setup_rt_frame(usig, ka, info, oldset,
+						    regs);
+		else
+			ret = compat_setup_frame(usig, ka, oldset, regs);
+	} else {
+		ret = setup_rt_frame(usig, ka, info, oldset, regs);
+	}
+
+	/*
+	 * Check that the resulting registers are actually sane.
+	 */
+	ret |= !valid_user_regs(&regs->user_regs);
+
+	if (ret != 0) {
+		force_sigsegv(sig, tsk);
+		return;
+	}
+
+	/*
+	 * Fast forward the stepping logic so we step into the signal
+	 * handler.
+	 */
+	user_fastforward_single_step(tsk);
+
+	signal_delivered(sig, info, ka, regs, 0);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+static void do_signal(struct pt_regs *regs)
+{
+	unsigned long continue_addr = 0, restart_addr = 0;
+	struct k_sigaction ka;
+	siginfo_t info;
+	int signr, retval = 0;
+	int syscall = (int)regs->syscallno;
+
+	/*
+	 * If we were from a system call, check for system call restarting...
+	 */
+	if (syscall >= 0) {
+		continue_addr = regs->pc;
+		restart_addr = continue_addr - (compat_thumb_mode(regs) ? 2 : 4);
+		retval = regs->regs[0];
+
+		/*
+		 * Avoid additional syscall restarting via ret_to_user.
+		 */
+		regs->syscallno = ~0UL;
+
+		/*
+		 * Prepare for system call restart. We do this here so that a
+		 * debugger will see the already changed PC.
+		 */
+		switch (retval) {
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
+		case -ERESTART_RESTARTBLOCK:
+			regs->regs[0] = regs->orig_x0;
+			regs->pc = restart_addr;
+			break;
+		}
+	}
+
+	/*
+	 * Get the signal to deliver. When running under ptrace, at this point
+	 * the debugger may change all of our registers.
+	 */
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		/*
+		 * Depending on the signal settings, we may need to revert the
+		 * decision to restart the system call, but skip this if a
+		 * debugger has chosen to restart at a different PC.
+		 */
+		if (regs->pc == restart_addr &&
+		    (retval == -ERESTARTNOHAND ||
+		     retval == -ERESTART_RESTARTBLOCK ||
+		     (retval == -ERESTARTSYS &&
+		      !(ka.sa.sa_flags & SA_RESTART)))) {
+			regs->regs[0] = -EINTR;
+			regs->pc = continue_addr;
+		}
+
+		handle_signal(signr, &ka, &info, regs);
+		return;
+	}
+
+	/*
+	 * Handle restarting a different system call. As above, if a debugger
+	 * has chosen to restart at a different PC, ignore the restart.
+	 */
+	if (syscall >= 0 && regs->pc == restart_addr) {
+		if (retval == -ERESTART_RESTARTBLOCK)
+			setup_restart_syscall(regs);
+		user_rewind_single_step(current);
+	}
+
+	restore_saved_sigmask();
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs,
+				 unsigned int thread_flags)
+{
+	if (thread_flags & _TIF_SIGPENDING)
+		do_signal(regs);
+
+	if (thread_flags & _TIF_NOTIFY_RESUME) {
+		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
+	}
+}
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
new file mode 100644
index 0000000..ac74c2f
--- /dev/null
+++ b/arch/arm64/kernel/signal32.c
@@ -0,0 +1,876 @@
+/*
+ * Based on arch/arm/kernel/signal.c
+ *
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ * Modified by Will Deacon <will.deacon@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __SYSCALL_COMPAT
+
+#include <linux/compat.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/ratelimit.h>
+
+#include <asm/fpsimd.h>
+#include <asm/signal32.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+typedef struct compat_siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		/* The padding is the same size as AArch64. */
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			__compat_uid32_t _uid;	/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			compat_timer_t _tid;	/* timer id */
+			int _overrun;		/* overrun count */
+			compat_sigval_t _sigval;	/* same as below */
+			int _sys_private;       /* not to be passed to user */
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			__compat_uid32_t _uid;	/* sender's uid */
+			compat_sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			compat_pid_t _pid;	/* which child */
+			__compat_uid32_t _uid;	/* sender's uid */
+			int _status;		/* exit code */
+			compat_clock_t _utime;
+			compat_clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			compat_uptr_t _addr; /* faulting insn/memory ref. */
+			short _addr_lsb; /* LSB of the reported address */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			compat_long_t _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} compat_siginfo_t;
+
+struct compat_sigaction {
+	compat_uptr_t			sa_handler;
+	compat_ulong_t			sa_flags;
+	compat_uptr_t			sa_restorer;
+	compat_sigset_t			sa_mask;
+};
+
+struct compat_old_sigaction {
+	compat_uptr_t			sa_handler;
+	compat_old_sigset_t		sa_mask;
+	compat_ulong_t			sa_flags;
+	compat_uptr_t			sa_restorer;
+};
+
+typedef struct compat_sigaltstack {
+	compat_uptr_t			ss_sp;
+	int				ss_flags;
+	compat_size_t			ss_size;
+} compat_stack_t;
+
+struct compat_sigcontext {
+	/* We always set these two fields to 0 */
+	compat_ulong_t			trap_no;
+	compat_ulong_t			error_code;
+
+	compat_ulong_t			oldmask;
+	compat_ulong_t			arm_r0;
+	compat_ulong_t			arm_r1;
+	compat_ulong_t			arm_r2;
+	compat_ulong_t			arm_r3;
+	compat_ulong_t			arm_r4;
+	compat_ulong_t			arm_r5;
+	compat_ulong_t			arm_r6;
+	compat_ulong_t			arm_r7;
+	compat_ulong_t			arm_r8;
+	compat_ulong_t			arm_r9;
+	compat_ulong_t			arm_r10;
+	compat_ulong_t			arm_fp;
+	compat_ulong_t			arm_ip;
+	compat_ulong_t			arm_sp;
+	compat_ulong_t			arm_lr;
+	compat_ulong_t			arm_pc;
+	compat_ulong_t			arm_cpsr;
+	compat_ulong_t			fault_address;
+};
+
+struct compat_ucontext {
+	compat_ulong_t			uc_flags;
+	struct compat_ucontext		*uc_link;
+	compat_stack_t			uc_stack;
+	struct compat_sigcontext	uc_mcontext;
+	compat_sigset_t			uc_sigmask;
+	int		__unused[32 - (sizeof (compat_sigset_t) / sizeof (int))];
+	compat_ulong_t	uc_regspace[128] __attribute__((__aligned__(8)));
+};
+
+struct compat_vfp_sigframe {
+	compat_ulong_t	magic;
+	compat_ulong_t	size;
+	struct compat_user_vfp {
+		compat_u64	fpregs[32];
+		compat_ulong_t	fpscr;
+	} ufp;
+	struct compat_user_vfp_exc {
+		compat_ulong_t	fpexc;
+		compat_ulong_t	fpinst;
+		compat_ulong_t	fpinst2;
+	} ufp_exc;
+} __attribute__((__aligned__(8)));
+
+#define VFP_MAGIC		0x56465001
+#define VFP_STORAGE_SIZE	sizeof(struct compat_vfp_sigframe)
+
+struct compat_aux_sigframe {
+	struct compat_vfp_sigframe	vfp;
+
+	/* Something that isn't a valid magic number for any coprocessor.  */
+	unsigned long			end_magic;
+} __attribute__((__aligned__(8)));
+
+struct compat_sigframe {
+	struct compat_ucontext	uc;
+	compat_ulong_t		retcode[2];
+};
+
+struct compat_rt_sigframe {
+	struct compat_siginfo info;
+	struct compat_sigframe sig;
+};
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * For ARM syscalls, the syscall number has to be loaded into r7.
+ * We do not support an OABI userspace.
+ */
+#define MOV_R7_NR_SIGRETURN	(0xe3a07000 | __NR_sigreturn)
+#define SVC_SYS_SIGRETURN	(0xef000000 | __NR_sigreturn)
+#define MOV_R7_NR_RT_SIGRETURN	(0xe3a07000 | __NR_rt_sigreturn)
+#define SVC_SYS_RT_SIGRETURN	(0xef000000 | __NR_rt_sigreturn)
+
+/*
+ * For Thumb syscalls, we also pass the syscall number via r7. We therefore
+ * need two 16-bit instructions.
+ */
+#define SVC_THUMB_SIGRETURN	(((0xdf00 | __NR_sigreturn) << 16) | \
+				   0x2700 | __NR_sigreturn)
+#define SVC_THUMB_RT_SIGRETURN	(((0xdf00 | __NR_rt_sigreturn) << 16) | \
+				   0x2700 | __NR_rt_sigreturn)
+
+const compat_ulong_t aarch32_sigret_code[6] = {
+	/*
+	 * AArch32 sigreturn code.
+	 * We don't construct an OABI SWI - instead we just set the imm24 field
+	 * to the EABI syscall number so that we create a sane disassembly.
+	 */
+	MOV_R7_NR_SIGRETURN,    SVC_SYS_SIGRETURN,    SVC_THUMB_SIGRETURN,
+	MOV_R7_NR_RT_SIGRETURN, SVC_SYS_RT_SIGRETURN, SVC_THUMB_RT_SIGRETURN,
+};
+
+static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
+{
+	compat_sigset_t	cset;
+
+	cset.sig[0] = set->sig[0] & 0xffffffffull;
+	cset.sig[1] = set->sig[0] >> 32;
+
+	return copy_to_user(uset, &cset, sizeof(*uset));
+}
+
+static inline int get_sigset_t(sigset_t *set,
+			       const compat_sigset_t __user *uset)
+{
+	compat_sigset_t s32;
+
+	if (copy_from_user(&s32, uset, sizeof(*uset)))
+		return -EFAULT;
+
+	set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+	return 0;
+}
+
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
+		return -EFAULT;
+
+	/* If you change siginfo_t structure, please be sure
+	 * this code is fixed accordingly.
+	 * It should never copy any pad contained in the structure
+	 * to avoid security leaks, but must copy the generic
+	 * 3 ints plus the relevant union member.
+	 * This routine must convert siginfo from 64bit to 32bit as well
+	 * at the same time.
+	 */
+	err = __put_user(from->si_signo, &to->si_signo);
+	err |= __put_user(from->si_errno, &to->si_errno);
+	err |= __put_user((short)from->si_code, &to->si_code);
+	if (from->si_code < 0)
+		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
+				      SI_PAD_SIZE);
+	else switch (from->si_code & __SI_MASK) {
+	case __SI_KILL:
+		err |= __put_user(from->si_pid, &to->si_pid);
+		err |= __put_user(from->si_uid, &to->si_uid);
+		break;
+	case __SI_TIMER:
+		 err |= __put_user(from->si_tid, &to->si_tid);
+		 err |= __put_user(from->si_overrun, &to->si_overrun);
+		 err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
+				   &to->si_ptr);
+		break;
+	case __SI_POLL:
+		err |= __put_user(from->si_band, &to->si_band);
+		err |= __put_user(from->si_fd, &to->si_fd);
+		break;
+	case __SI_FAULT:
+		err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
+				  &to->si_addr);
+#ifdef BUS_MCEERR_AO
+		/*
+		 * Other callers might not initialize the si_lsb field,
+		 * so check explicitely for the right codes here.
+		 */
+		if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+			err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
+		break;
+	case __SI_CHLD:
+		err |= __put_user(from->si_pid, &to->si_pid);
+		err |= __put_user(from->si_uid, &to->si_uid);
+		err |= __put_user(from->si_status, &to->si_status);
+		err |= __put_user(from->si_utime, &to->si_utime);
+		err |= __put_user(from->si_stime, &to->si_stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+	case __SI_MESGQ: /* But this is */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		err |= __put_user(from->si_uid, &to->si_uid);
+		err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
+		break;
+	default: /* this is just in case for now ... */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		err |= __put_user(from->si_uid, &to->si_uid);
+		break;
+	}
+	return err;
+}
+
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+	memset(to, 0, sizeof *to);
+
+	if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
+	    copy_from_user(to->_sifields._pad,
+			   from->_sifields._pad, SI_PAD_SIZE))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * VFP save/restore code.
+ */
+static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
+{
+	struct fpsimd_state *fpsimd = &current->thread.fpsimd_state;
+	compat_ulong_t magic = VFP_MAGIC;
+	compat_ulong_t size = VFP_STORAGE_SIZE;
+	compat_ulong_t fpscr, fpexc;
+	int err = 0;
+
+	/*
+	 * Save the hardware registers to the fpsimd_state structure.
+	 * Note that this also saves V16-31, which aren't visible
+	 * in AArch32.
+	 */
+	fpsimd_save_state(fpsimd);
+
+	/* Place structure header on the stack */
+	__put_user_error(magic, &frame->magic, err);
+	__put_user_error(size, &frame->size, err);
+
+	/*
+	 * Now copy the FP registers. Since the registers are packed,
+	 * we can copy the prefix we want (V0-V15) as it is.
+	 * FIXME: Won't work if big endian.
+	 */
+	err |= __copy_to_user(&frame->ufp.fpregs, fpsimd->vregs,
+			      sizeof(frame->ufp.fpregs));
+
+	/* Create an AArch32 fpscr from the fpsr and the fpcr. */
+	fpscr = (fpsimd->fpsr & VFP_FPSCR_STAT_MASK) |
+		(fpsimd->fpcr & VFP_FPSCR_CTRL_MASK);
+	__put_user_error(fpscr, &frame->ufp.fpscr, err);
+
+	/*
+	 * The exception register aren't available so we fake up a
+	 * basic FPEXC and zero everything else.
+	 */
+	fpexc = (1 << 30);
+	__put_user_error(fpexc, &frame->ufp_exc.fpexc, err);
+	__put_user_error(0, &frame->ufp_exc.fpinst, err);
+	__put_user_error(0, &frame->ufp_exc.fpinst2, err);
+
+	return err ? -EFAULT : 0;
+}
+
+static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame)
+{
+	struct fpsimd_state fpsimd;
+	compat_ulong_t magic = VFP_MAGIC;
+	compat_ulong_t size = VFP_STORAGE_SIZE;
+	compat_ulong_t fpscr;
+	int err = 0;
+
+	__get_user_error(magic, &frame->magic, err);
+	__get_user_error(size, &frame->size, err);
+
+	if (err)
+		return -EFAULT;
+	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
+		return -EINVAL;
+
+	/*
+	 * Copy the FP registers into the start of the fpsimd_state.
+	 * FIXME: Won't work if big endian.
+	 */
+	err |= __copy_from_user(fpsimd.vregs, frame->ufp.fpregs,
+				sizeof(frame->ufp.fpregs));
+
+	/* Extract the fpsr and the fpcr from the fpscr */
+	__get_user_error(fpscr, &frame->ufp.fpscr, err);
+	fpsimd.fpsr = fpscr & VFP_FPSCR_STAT_MASK;
+	fpsimd.fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
+
+	/*
+	 * We don't need to touch the exception register, so
+	 * reload the hardware state.
+	 */
+	if (!err) {
+		preempt_disable();
+		fpsimd_load_state(&fpsimd);
+		preempt_enable();
+	}
+
+	return err ? -EFAULT : 0;
+}
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int compat_sys_sigsuspend(int restart, compat_ulong_t oldmask,
+				     compat_old_sigset_t mask)
+{
+	sigset_t blocked;
+
+	siginitset(&current->blocked, mask);
+	return sigsuspend(&blocked);
+}
+
+asmlinkage int compat_sys_sigaction(int sig,
+				    const struct compat_old_sigaction __user *act,
+				    struct compat_old_sigaction __user *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	compat_old_sigset_t mask;
+	compat_uptr_t handler, restorer;
+
+	if (act) {
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(handler, &act->sa_handler) ||
+		    __get_user(restorer, &act->sa_restorer) ||
+		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+		    __get_user(mask, &act->sa_mask))
+			return -EFAULT;
+
+		new_ka.sa.sa_handler = compat_ptr(handler);
+		new_ka.sa.sa_restorer = compat_ptr(restorer);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
+			       &oact->sa_handler) ||
+		    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
+			       &oact->sa_restorer) ||
+		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+			return -EFAULT;
+	}
+
+	return ret;
+}
+
+asmlinkage int compat_sys_rt_sigaction(int sig,
+				       const struct compat_sigaction __user *act,
+				       struct compat_sigaction __user *oact,
+				       compat_size_t sigsetsize)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(compat_sigset_t))
+		return -EINVAL;
+
+	if (act) {
+		compat_uptr_t handler, restorer;
+
+		ret = get_user(handler, &act->sa_handler);
+		new_ka.sa.sa_handler = compat_ptr(handler);
+		ret |= get_user(restorer, &act->sa_restorer);
+		new_ka.sa.sa_restorer = compat_ptr(restorer);
+		ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask);
+		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		if (ret)
+			return -EFAULT;
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+	if (!ret && oact) {
+		ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
+		ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask);
+		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+	}
+	return ret;
+}
+
+int compat_do_sigaltstack(compat_uptr_t compat_uss, compat_uptr_t compat_uoss,
+			  compat_ulong_t sp)
+{
+	compat_stack_t __user *newstack = compat_ptr(compat_uss);
+	compat_stack_t __user *oldstack = compat_ptr(compat_uoss);
+	compat_uptr_t ss_sp;
+	int ret;
+	mm_segment_t old_fs;
+	stack_t uss, uoss;
+
+	/* Marshall the compat new stack into a stack_t */
+	if (newstack) {
+		if (get_user(ss_sp, &newstack->ss_sp) ||
+		    __get_user(uss.ss_flags, &newstack->ss_flags) ||
+		    __get_user(uss.ss_size, &newstack->ss_size))
+			return -EFAULT;
+		uss.ss_sp = compat_ptr(ss_sp);
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	/* The __user pointer casts are valid because of the set_fs() */
+	ret = do_sigaltstack(
+		newstack ? (stack_t __user *) &uss : NULL,
+		oldstack ? (stack_t __user *) &uoss : NULL,
+		(unsigned long)sp);
+	set_fs(old_fs);
+
+	/* Convert the old stack_t into a compat stack. */
+	if (!ret && oldstack &&
+		(put_user(ptr_to_compat(uoss.ss_sp), &oldstack->ss_sp) ||
+		 __put_user(uoss.ss_flags, &oldstack->ss_flags) ||
+		 __put_user(uoss.ss_size, &oldstack->ss_size)))
+		return -EFAULT;
+	return ret;
+}
+
+static int compat_restore_sigframe(struct pt_regs *regs,
+				   struct compat_sigframe __user *sf)
+{
+	int err;
+	sigset_t set;
+	struct compat_aux_sigframe __user *aux;
+
+	err = get_sigset_t(&set, &sf->uc.uc_sigmask);
+	if (err == 0) {
+		sigdelsetmask(&set, ~_BLOCKABLE);
+		set_current_blocked(&set);
+	}
+
+	__get_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err);
+	__get_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err);
+	__get_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err);
+	__get_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err);
+	__get_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err);
+	__get_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err);
+	__get_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err);
+	__get_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err);
+	__get_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err);
+	__get_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err);
+	__get_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err);
+	__get_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err);
+	__get_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err);
+	__get_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err);
+	__get_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err);
+	__get_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err);
+	__get_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
+
+	/*
+	 * Avoid compat_sys_sigreturn() restarting.
+	 */
+	regs->syscallno = ~0UL;
+
+	err |= !valid_user_regs(&regs->user_regs);
+
+	aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
+	if (err == 0)
+		err |= compat_restore_vfp_context(&aux->vfp);
+
+	return err;
+}
+
+asmlinkage int compat_sys_sigreturn(struct pt_regs *regs)
+{
+	struct compat_sigframe __user *frame;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (regs->compat_sp & 7)
+		goto badframe;
+
+	frame = (struct compat_sigframe __user *)regs->compat_sp;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
+		goto badframe;
+
+	if (compat_restore_sigframe(regs, frame))
+		goto badframe;
+
+	return regs->regs[0];
+
+badframe:
+	if (show_unhandled_signals)
+		pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
+				    current->comm, task_pid_nr(current), __func__,
+				    regs->pc, regs->sp);
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct compat_rt_sigframe __user *frame;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (regs->compat_sp & 7)
+		goto badframe;
+
+	frame = (struct compat_rt_sigframe __user *)regs->compat_sp;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
+		goto badframe;
+
+	if (compat_restore_sigframe(regs, &frame->sig))
+		goto badframe;
+
+	if (compat_do_sigaltstack(ptr_to_compat(&frame->sig.uc.uc_stack),
+				 ptr_to_compat((void __user *)NULL),
+				 regs->compat_sp) == -EFAULT)
+		goto badframe;
+
+	return regs->regs[0];
+
+badframe:
+	if (show_unhandled_signals)
+		pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
+				    current->comm, task_pid_nr(current), __func__,
+				    regs->pc, regs->sp);
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
+					       struct pt_regs *regs,
+					       int framesize)
+{
+	compat_ulong_t sp = regs->compat_sp;
+	void __user *frame;
+
+	/*
+	 * This is the X/Open sanctioned signal stack switching.
+	 */
+	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	/*
+	 * ATPCS B01 mandates 8-byte alignment
+	 */
+	frame = compat_ptr((compat_uptr_t)((sp - framesize) & ~7));
+
+	/*
+	 * Check that we can actually write to the signal frame.
+	 */
+	if (!access_ok(VERIFY_WRITE, frame, framesize))
+		frame = NULL;
+
+	return frame;
+}
+
+static int compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+			       compat_ulong_t __user *rc, void __user *frame,
+			       int usig)
+{
+	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
+	compat_ulong_t retcode;
+	compat_ulong_t spsr = regs->pstate & ~PSR_f;
+	int thumb;
+
+	/* Check if the handler is written for ARM or Thumb */
+	thumb = handler & 1;
+
+	if (thumb) {
+		spsr |= COMPAT_PSR_T_BIT;
+		spsr &= ~COMPAT_PSR_IT_MASK;
+	} else {
+		spsr &= ~COMPAT_PSR_T_BIT;
+	}
+
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		retcode = ptr_to_compat(ka->sa.sa_restorer);
+	} else {
+		/* Set up sigreturn pointer */
+		unsigned int idx = thumb << 1;
+
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			idx += 3;
+
+		retcode = AARCH32_VECTORS_BASE +
+			  AARCH32_KERN_SIGRET_CODE_OFFSET +
+			  (idx << 2) + thumb;
+	}
+
+	regs->regs[0]	= usig;
+	regs->compat_sp	= ptr_to_compat(frame);
+	regs->compat_lr	= retcode;
+	regs->pc	= handler;
+	regs->pstate	= spsr;
+
+	return 0;
+}
+
+static int compat_setup_sigframe(struct compat_sigframe __user *sf,
+				 struct pt_regs *regs, sigset_t *set)
+{
+	struct compat_aux_sigframe __user *aux;
+	int err = 0;
+
+	__put_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err);
+	__put_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err);
+	__put_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err);
+	__put_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err);
+	__put_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err);
+	__put_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err);
+	__put_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err);
+	__put_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err);
+	__put_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err);
+	__put_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err);
+	__put_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err);
+	__put_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err);
+	__put_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err);
+	__put_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err);
+	__put_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err);
+	__put_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err);
+	__put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
+
+	__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err);
+	__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.error_code, err);
+	__put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
+	__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
+
+	err |= put_sigset_t(&sf->uc.uc_sigmask, set);
+
+	aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
+
+	if (err == 0)
+		err |= compat_preserve_vfp_context(&aux->vfp);
+	__put_user_error(0, &aux->end_magic, err);
+
+	return err;
+}
+
+/*
+ * 32-bit signal handling routines called from signal.c
+ */
+int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+			  sigset_t *set, struct pt_regs *regs)
+{
+	struct compat_rt_sigframe __user *frame;
+	compat_stack_t stack;
+	int err = 0;
+
+	frame = compat_get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!frame)
+		return 1;
+
+	err |= copy_siginfo_to_user32(&frame->info, info);
+
+	__put_user_error(0, &frame->sig.uc.uc_flags, err);
+	__put_user_error(NULL, &frame->sig.uc.uc_link, err);
+
+	memset(&stack, 0, sizeof(stack));
+	stack.ss_sp = (compat_uptr_t)current->sas_ss_sp;
+	stack.ss_flags = sas_ss_flags(regs->compat_sp);
+	stack.ss_size = current->sas_ss_size;
+	err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
+
+	err |= compat_setup_sigframe(&frame->sig, regs, set);
+	if (err == 0)
+		err = compat_setup_return(regs, ka, frame->sig.retcode, frame,
+					  usig);
+
+	if (err == 0) {
+		regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info;
+		regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc;
+	}
+
+	return err;
+}
+
+int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
+		       struct pt_regs *regs)
+{
+	struct compat_sigframe __user *frame;
+	int err = 0;
+
+	frame = compat_get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!frame)
+		return 1;
+
+	__put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
+
+	err |= compat_setup_sigframe(frame, regs, set);
+	if (err == 0)
+		err = compat_setup_return(regs, ka, frame->retcode, frame, usig);
+
+	return err;
+}
+
+/*
+ * RT signals don't have generic compat wrappers.
+ * See arch/powerpc/kernel/signal_32.c
+ */
+asmlinkage int compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set,
+					 compat_sigset_t __user *oset,
+					 compat_size_t sigsetsize)
+{
+	sigset_t s;
+	sigset_t __user *up;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	if (set) {
+		if (get_sigset_t(&s, set))
+			return -EFAULT;
+	}
+
+	set_fs(KERNEL_DS);
+	/* This is valid because of the set_fs() */
+	up = (sigset_t __user *) &s;
+	ret = sys_rt_sigprocmask(how, set ? up : NULL, oset ? up : NULL,
+				 sigsetsize);
+	set_fs(old_fs);
+	if (ret)
+		return ret;
+	if (oset) {
+		if (put_sigset_t(oset, &s))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage int compat_sys_rt_sigpending(compat_sigset_t __user *set,
+					compat_size_t sigsetsize)
+{
+	sigset_t s;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	/* The __user pointer cast is valid because of the set_fs() */
+	ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
+	set_fs(old_fs);
+	if (!ret) {
+		if (put_sigset_t(set, &s))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage int compat_sys_rt_sigqueueinfo(int pid, int sig,
+					  compat_siginfo_t __user *uinfo)
+{
+	siginfo_t info;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	ret = copy_siginfo_from_user32(&info, uinfo);
+	if (unlikely(ret))
+		return ret;
+
+	set_fs (KERNEL_DS);
+	/* The __user pointer cast is valid because of the set_fs() */
+	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
+	set_fs (old_fs);
+	return ret;
+}
+
+void compat_setup_restart_syscall(struct pt_regs *regs)
+{
+       regs->regs[7] = __NR_restart_syscall;
+}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
new file mode 100644
index 0000000..b711525
--- /dev/null
+++ b/arch/arm64/kernel/smp.c
@@ -0,0 +1,469 @@
+/*
+ * SMP initialisation and IPI support
+ * Based on arch/arm/kernel/smp.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/cache.h>
+#include <linux/profile.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+
+#include <asm/atomic.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/tlbflush.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+/*
+ * as from 2.5, kernels no longer have an init_tasks structure
+ * so we need some other way of telling a new secondary core
+ * where to place its SVC stack
+ */
+struct secondary_data secondary_data;
+volatile unsigned long secondary_holding_pen_release = -1;
+
+enum ipi_msg_type {
+	IPI_RESCHEDULE,
+	IPI_CALL_FUNC,
+	IPI_CALL_FUNC_SINGLE,
+	IPI_CPU_STOP,
+};
+
+static DEFINE_RAW_SPINLOCK(boot_lock);
+
+/*
+ * Write secondary_holding_pen_release in a way that is guaranteed to be
+ * visible to all observers, irrespective of whether they're taking part
+ * in coherency or not.  This is necessary for the hotplug code to work
+ * reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	void *start = (void *)&secondary_holding_pen_release;
+	unsigned long size = sizeof(secondary_holding_pen_release);
+
+	secondary_holding_pen_release = val;
+	__flush_dcache_area(start, size);
+}
+
+/*
+ * Boot a secondary CPU, and assign it the specified idle task.
+ * This also gives us the initial stack to use for this CPU.
+ */
+static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	raw_spin_lock(&boot_lock);
+
+	/*
+	 * Update the pen release flag.
+	 */
+	write_pen_release(cpu);
+
+	/*
+	 * Send an event, causing the secondaries to read pen_release.
+	 */
+	sev();
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		if (secondary_holding_pen_release == -1UL)
+			break;
+		udelay(10);
+	}
+
+	/*
+	 * Now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	raw_spin_unlock(&boot_lock);
+
+	return secondary_holding_pen_release != -1 ? -ENOSYS : 0;
+}
+
+static DECLARE_COMPLETION(cpu_running);
+
+int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+{
+	int ret;
+
+	/*
+	 * We need to tell the secondary core where to find its stack and the
+	 * page tables.
+	 */
+	secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
+	__flush_dcache_area(&secondary_data, sizeof(secondary_data));
+
+	/*
+	 * Now bring the CPU into our world.
+	 */
+	ret = boot_secondary(cpu, idle);
+	if (ret == 0) {
+		/*
+		 * CPU was successfully started, wait for it to come online or
+		 * time out.
+		 */
+		wait_for_completion_timeout(&cpu_running,
+					    msecs_to_jiffies(1000));
+
+		if (!cpu_online(cpu)) {
+			pr_crit("CPU%u: failed to come online\n", cpu);
+			ret = -EIO;
+		}
+	} else {
+		pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
+	}
+
+	secondary_data.stack = NULL;
+
+	return ret;
+}
+
+/*
+ * This is the secondary CPU boot entry.  We're using this CPUs
+ * idle thread stack, but a set of temporary page tables.
+ */
+asmlinkage void __cpuinit secondary_start_kernel(void)
+{
+	struct mm_struct *mm = &init_mm;
+	unsigned int cpu = smp_processor_id();
+
+	printk("CPU%u: Booted secondary processor\n", cpu);
+
+	/*
+	 * All kernel threads share the same mm context; grab a
+	 * reference and switch to it.
+	 */
+	atomic_inc(&mm->mm_count);
+	current->active_mm = mm;
+	cpumask_set_cpu(cpu, mm_cpumask(mm));
+
+	/*
+	 * TTBR0 is only used for the identity mapping at this stage. Make it
+	 * point to zero page to avoid speculatively fetching new entries.
+	 */
+	cpu_set_reserved_ttbr0();
+	flush_tlb_all();
+
+	preempt_disable();
+	trace_hardirqs_off();
+
+	/*
+	 * Let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	raw_spin_lock(&boot_lock);
+	raw_spin_unlock(&boot_lock);
+
+	/*
+	 * Enable local interrupts.
+	 */
+	notify_cpu_starting(cpu);
+	local_irq_enable();
+	local_fiq_enable();
+
+	/*
+	 * OK, now it's safe to let the boot CPU continue.  Wait for
+	 * the CPU migration code to notice that the CPU is online
+	 * before we continue.
+	 */
+	set_cpu_online(cpu, true);
+	while (!cpu_active(cpu))
+		cpu_relax();
+
+	/*
+	 * OK, it's off to the idle thread for us
+	 */
+	cpu_idle();
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+	unsigned long bogosum = loops_per_jiffy * num_online_cpus();
+
+	pr_info("SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+		num_online_cpus(), bogosum / (500000/HZ),
+		(bogosum / (5000/HZ)) % 100);
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+}
+
+static void (*smp_cross_call)(const struct cpumask *, unsigned int);
+static phys_addr_t cpu_release_addr[NR_CPUS];
+
+/*
+ * Enumerate the possible CPU set from the device tree.
+ */
+void __init smp_init_cpus(void)
+{
+	const char *enable_method;
+	struct device_node *dn = NULL;
+	int cpu = 0;
+
+	while ((dn = of_find_node_by_type(dn, "cpu"))) {
+		if (cpu >= NR_CPUS)
+			goto next;
+
+		/*
+		 * We currently support only the "spin-table" enable-method.
+		 */
+		enable_method = of_get_property(dn, "enable-method", NULL);
+		if (!enable_method || strcmp(enable_method, "spin-table")) {
+			pr_err("CPU %d: missing or invalid enable-method property: %s\n",
+			       cpu, enable_method);
+			goto next;
+		}
+
+		/*
+		 * Determine the address from which the CPU is polling.
+		 */
+		if (of_property_read_u64(dn, "cpu-release-addr",
+					 &cpu_release_addr[cpu])) {
+			pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
+			       cpu);
+			goto next;
+		}
+
+		set_cpu_possible(cpu, true);
+next:
+		cpu++;
+	}
+
+	/* sanity check */
+	if (cpu > NR_CPUS)
+		pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n",
+			   cpu, NR_CPUS);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	int cpu;
+	void **release_addr;
+	unsigned int ncores = num_possible_cpus();
+
+	/*
+	 * are we trying to boot more cores than exist?
+	 */
+	if (max_cpus > ncores)
+		max_cpus = ncores;
+
+	/*
+	 * Initialise the present map (which describes the set of CPUs
+	 * actually populated at the present time) and release the
+	 * secondaries from the bootloader.
+	 */
+	for_each_possible_cpu(cpu) {
+		if (max_cpus == 0)
+			break;
+
+		if (!cpu_release_addr[cpu])
+			continue;
+
+		release_addr = __va(cpu_release_addr[cpu]);
+		release_addr[0] = (void *)__pa(secondary_holding_pen);
+		__flush_dcache_area(release_addr, sizeof(release_addr[0]));
+
+		set_cpu_present(cpu, true);
+		max_cpus--;
+	}
+
+	/*
+	 * Send an event to wake up the secondaries.
+	 */
+	sev();
+}
+
+
+void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
+{
+	smp_cross_call = fn;
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_CALL_FUNC);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+}
+
+static const char *ipi_types[NR_IPI] = {
+#define S(x,s)	[x - IPI_RESCHEDULE] = s
+	S(IPI_RESCHEDULE, "Rescheduling interrupts"),
+	S(IPI_CALL_FUNC, "Function call interrupts"),
+	S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
+	S(IPI_CPU_STOP, "CPU stop interrupts"),
+};
+
+void show_ipi_list(struct seq_file *p, int prec)
+{
+	unsigned int cpu, i;
+
+	for (i = 0; i < NR_IPI; i++) {
+		seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE,
+			   prec >= 4 ? " " : "");
+		for_each_present_cpu(cpu)
+			seq_printf(p, "%10u ",
+				   __get_irq_stat(cpu, ipi_irqs[i]));
+		seq_printf(p, "      %s\n", ipi_types[i]);
+	}
+}
+
+u64 smp_irq_stat_cpu(unsigned int cpu)
+{
+	u64 sum = 0;
+	int i;
+
+	for (i = 0; i < NR_IPI; i++)
+		sum += __get_irq_stat(cpu, ipi_irqs[i]);
+
+	return sum;
+}
+
+static DEFINE_RAW_SPINLOCK(stop_lock);
+
+/*
+ * ipi_cpu_stop - handle IPI from smp_send_stop()
+ */
+static void ipi_cpu_stop(unsigned int cpu)
+{
+	if (system_state == SYSTEM_BOOTING ||
+	    system_state == SYSTEM_RUNNING) {
+		raw_spin_lock(&stop_lock);
+		pr_crit("CPU%u: stopping\n", cpu);
+		dump_stack();
+		raw_spin_unlock(&stop_lock);
+	}
+
+	set_cpu_online(cpu, false);
+
+	local_fiq_disable();
+	local_irq_disable();
+
+	while (1)
+		cpu_relax();
+}
+
+/*
+ * Main handler for inter-processor interrupts
+ */
+void handle_IPI(int ipinr, struct pt_regs *regs)
+{
+	unsigned int cpu = smp_processor_id();
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI)
+		__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]);
+
+	switch (ipinr) {
+	case IPI_RESCHEDULE:
+		scheduler_ipi();
+		break;
+
+	case IPI_CALL_FUNC:
+		irq_enter();
+		generic_smp_call_function_interrupt();
+		irq_exit();
+		break;
+
+	case IPI_CALL_FUNC_SINGLE:
+		irq_enter();
+		generic_smp_call_function_single_interrupt();
+		irq_exit();
+		break;
+
+	case IPI_CPU_STOP:
+		irq_enter();
+		ipi_cpu_stop(cpu);
+		irq_exit();
+		break;
+
+	default:
+		pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
+		break;
+	}
+	set_irq_regs(old_regs);
+}
+
+void smp_send_reschedule(int cpu)
+{
+	smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
+}
+
+void smp_send_stop(void)
+{
+	unsigned long timeout;
+
+	if (num_online_cpus() > 1) {
+		cpumask_t mask;
+
+		cpumask_copy(&mask, cpu_online_mask);
+		cpu_clear(smp_processor_id(), mask);
+
+		smp_cross_call(&mask, IPI_CPU_STOP);
+	}
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warning("SMP: failed to stop secondary CPUs\n");
+}
+
+/*
+ * not supported here
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	return -EINVAL;
+}
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
new file mode 100644
index 0000000..d25459f
--- /dev/null
+++ b/arch/arm64/kernel/stacktrace.c
@@ -0,0 +1,127 @@
+/*
+ * Stack tracing support
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+
+#include <asm/stacktrace.h>
+
+/*
+ * AArch64 PCS assigns the frame pointer to x29.
+ *
+ * A simple function prologue looks like this:
+ * 	sub	sp, sp, #0x10
+ *   	stp	x29, x30, [sp]
+ *	mov	x29, sp
+ *
+ * A simple function epilogue looks like this:
+ *	mov	sp, x29
+ *	ldp	x29, x30, [sp]
+ *	add	sp, sp, #0x10
+ */
+int unwind_frame(struct stackframe *frame)
+{
+	unsigned long high, low;
+	unsigned long fp = frame->fp;
+
+	low  = frame->sp;
+	high = ALIGN(low, THREAD_SIZE);
+
+	if (fp < low || fp > high || fp & 0xf)
+		return -EINVAL;
+
+	frame->sp = fp + 0x10;
+	frame->fp = *(unsigned long *)(fp);
+	frame->pc = *(unsigned long *)(fp + 8);
+
+	return 0;
+}
+
+void notrace walk_stackframe(struct stackframe *frame,
+		     int (*fn)(struct stackframe *, void *), void *data)
+{
+	while (1) {
+		int ret;
+
+		if (fn(frame, data))
+			break;
+		ret = unwind_frame(frame);
+		if (ret < 0)
+			break;
+	}
+}
+EXPORT_SYMBOL(walk_stackframe);
+
+#ifdef CONFIG_STACKTRACE
+struct stack_trace_data {
+	struct stack_trace *trace;
+	unsigned int no_sched_functions;
+	unsigned int skip;
+};
+
+static int save_trace(struct stackframe *frame, void *d)
+{
+	struct stack_trace_data *data = d;
+	struct stack_trace *trace = data->trace;
+	unsigned long addr = frame->pc;
+
+	if (data->no_sched_functions && in_sched_functions(addr))
+		return 0;
+	if (data->skip) {
+		data->skip--;
+		return 0;
+	}
+
+	trace->entries[trace->nr_entries++] = addr;
+
+	return trace->nr_entries >= trace->max_entries;
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+	struct stack_trace_data data;
+	struct stackframe frame;
+
+	data.trace = trace;
+	data.skip = trace->skip;
+
+	if (tsk != current) {
+		data.no_sched_functions = 1;
+		frame.fp = thread_saved_fp(tsk);
+		frame.sp = thread_saved_sp(tsk);
+		frame.pc = thread_saved_pc(tsk);
+	} else {
+		register unsigned long current_sp asm("sp");
+		data.no_sched_functions = 0;
+		frame.fp = (unsigned long)__builtin_frame_address(0);
+		frame.sp = current_sp;
+		frame.pc = (unsigned long)save_stack_trace_tsk;
+	}
+
+	walk_stackframe(&frame, save_trace, &data);
+	if (trace->nr_entries < trace->max_entries)
+		trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+	save_stack_trace_tsk(current, trace);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+#endif
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
new file mode 100644
index 0000000..905fcfb
--- /dev/null
+++ b/arch/arm64/kernel/sys.c
@@ -0,0 +1,138 @@
+/*
+ * AArch64-specific system calls implementation
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+
+/*
+ * Clone a task - this clones the calling program thread.
+ */
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
+			  int __user *parent_tidptr, unsigned long tls_val,
+			  int __user *child_tidptr, struct pt_regs *regs)
+{
+	if (!newsp)
+		newsp = regs->sp;
+	/* 16-byte aligned stack mandatory on AArch64 */
+	if (newsp & 15)
+		return -EINVAL;
+	return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage long sys_execve(const char __user *filenamei,
+			   const char __user *const __user *argv,
+			   const char __user *const __user *envp,
+			   struct pt_regs *regs)
+{
+	long error;
+	char * filename;
+
+	filename = getname(filenamei);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+out:
+	return error;
+}
+
+int kernel_execve(const char *filename,
+		  const char *const argv[],
+		  const char *const envp[])
+{
+	struct pt_regs regs;
+	int ret;
+
+	memset(&regs, 0, sizeof(struct pt_regs));
+	ret = do_execve(filename,
+			(const char __user *const __user *)argv,
+			(const char __user *const __user *)envp, &regs);
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * Save argc to the register structure for userspace.
+	 */
+	regs.regs[0] = ret;
+
+	/*
+	 * We were successful.  We won't be returning to our caller, but
+	 * instead to user space by manipulating the kernel stack.
+	 */
+	asm(	"add	x0, %0, %1\n\t"
+		"mov	x1, %2\n\t"
+		"mov	x2, %3\n\t"
+		"bl	memmove\n\t"	/* copy regs to top of stack */
+		"mov	x27, #0\n\t"	/* not a syscall */
+		"mov	x28, %0\n\t"	/* thread structure */
+		"mov	sp, x0\n\t"	/* reposition stack pointer */
+		"b	ret_to_user"
+		:
+		: "r" (current_thread_info()),
+		  "Ir" (THREAD_START_SP - sizeof(regs)),
+		  "r" (&regs),
+		  "Ir" (sizeof(regs))
+		: "x0", "x1", "x2", "x27", "x28", "x30", "memory");
+
+ out:
+	return ret;
+}
+EXPORT_SYMBOL(kernel_execve);
+
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
+			 unsigned long prot, unsigned long flags,
+			 unsigned long fd, off_t off)
+{
+	if (offset_in_page(off) != 0)
+		return -EINVAL;
+
+	return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+}
+
+/*
+ * Wrappers to pass the pt_regs argument.
+ */
+#define sys_execve		sys_execve_wrapper
+#define sys_clone		sys_clone_wrapper
+#define sys_rt_sigreturn	sys_rt_sigreturn_wrapper
+#define sys_sigaltstack		sys_sigaltstack_wrapper
+
+#include <asm/syscalls.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym)	[nr] = sym,
+
+/*
+ * The sys_call_table array must be 4K aligned to be accessible from
+ * kernel/entry.S.
+ */
+void *sys_call_table[__NR_syscalls] __aligned(4096) = {
+	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S
new file mode 100644
index 0000000..5e4dc93
--- /dev/null
+++ b/arch/arm64/kernel/sys32.S
@@ -0,0 +1,282 @@
+/*
+ * Compat system call wrappers
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Authors: Will Deacon <will.deacon@arm.com>
+ *	    Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * System call wrappers for the AArch32 compatibility layer.
+ */
+compat_sys_fork_wrapper:
+	mov	x0, sp
+	b	compat_sys_fork
+ENDPROC(compat_sys_fork_wrapper)
+
+compat_sys_vfork_wrapper:
+	mov	x0, sp
+	b	compat_sys_vfork
+ENDPROC(compat_sys_vfork_wrapper)
+
+compat_sys_execve_wrapper:
+	mov	x3, sp
+	b	compat_sys_execve
+ENDPROC(compat_sys_execve_wrapper)
+
+compat_sys_clone_wrapper:
+	mov	x5, sp
+	b	compat_sys_clone
+ENDPROC(compat_sys_clone_wrapper)
+
+compat_sys_sigreturn_wrapper:
+	mov	x0, sp
+	mov	x27, #0		// prevent syscall restart handling (why)
+	b	compat_sys_sigreturn
+ENDPROC(compat_sys_sigreturn_wrapper)
+
+compat_sys_rt_sigreturn_wrapper:
+	mov	x0, sp
+	mov	x27, #0		// prevent syscall restart handling (why)
+	b	compat_sys_rt_sigreturn
+ENDPROC(compat_sys_rt_sigreturn_wrapper)
+
+compat_sys_sigaltstack_wrapper:
+	ldr	x2, [sp, #S_COMPAT_SP]
+	b	compat_do_sigaltstack
+ENDPROC(compat_sys_sigaltstack_wrapper)
+
+compat_sys_statfs64_wrapper:
+	mov	w3, #84
+	cmp	w1, #88
+	csel	w1, w3, w1, eq
+	b	compat_sys_statfs64
+ENDPROC(compat_sys_statfs64_wrapper)
+
+compat_sys_fstatfs64_wrapper:
+	mov	w3, #84
+	cmp	w1, #88
+	csel	w1, w3, w1, eq
+	b	compat_sys_fstatfs64
+ENDPROC(compat_sys_fstatfs64_wrapper)
+
+/*
+ * Wrappers for AArch32 syscalls that either take 64-bit parameters
+ * in registers or that take 32-bit parameters which require sign
+ * extension.
+ */
+compat_sys_lseek_wrapper:
+	sxtw	x1, w1
+	b	sys_lseek
+ENDPROC(compat_sys_lseek_wrapper)
+
+compat_sys_pread64_wrapper:
+	orr	x3, x4, x5, lsl #32
+	b	sys_pread64
+ENDPROC(compat_sys_pread64_wrapper)
+
+compat_sys_pwrite64_wrapper:
+	orr	x3, x4, x5, lsl #32
+	b	sys_pwrite64
+ENDPROC(compat_sys_pwrite64_wrapper)
+
+compat_sys_truncate64_wrapper:
+	orr	x1, x2, x3, lsl #32
+	b	sys_truncate
+ENDPROC(compat_sys_truncate64_wrapper)
+
+compat_sys_ftruncate64_wrapper:
+	orr	x1, x2, x3, lsl #32
+	b	sys_ftruncate
+ENDPROC(compat_sys_ftruncate64_wrapper)
+
+compat_sys_readahead_wrapper:
+	orr	x1, x2, x3, lsl #32
+	mov	w2, w4
+	b	sys_readahead
+ENDPROC(compat_sys_readahead_wrapper)
+
+compat_sys_lookup_dcookie:
+	orr	x0, x0, x1, lsl #32
+	mov	w1, w2
+	mov	w2, w3
+	b	sys_lookup_dcookie
+ENDPROC(compat_sys_lookup_dcookie)
+
+compat_sys_fadvise64_64_wrapper:
+	mov	w6, w1
+	orr	x1, x2, x3, lsl #32
+	orr	x2, x4, x5, lsl #32
+	mov	w3, w6
+	b	sys_fadvise64_64
+ENDPROC(compat_sys_fadvise64_64_wrapper)
+
+compat_sys_sync_file_range2_wrapper:
+	orr	x2, x2, x3, lsl #32
+	orr	x3, x4, x5, lsl #32
+	b	sys_sync_file_range2
+ENDPROC(compat_sys_sync_file_range2_wrapper)
+
+compat_sys_fallocate_wrapper:
+	orr	x2, x2, x3, lsl #32
+	orr	x3, x4, x5, lsl #32
+	b	sys_fallocate
+ENDPROC(compat_sys_fallocate_wrapper)
+
+compat_sys_fanotify_mark_wrapper:
+	orr	x2, x2, x3, lsl #32
+	mov	w3, w4
+	mov	w4, w5
+	b	sys_fanotify_mark
+ENDPROC(compat_sys_fanotify_mark_wrapper)
+
+/*
+ * Use the compat system call wrappers.
+ */
+#define sys_fork		compat_sys_fork_wrapper
+#define sys_open		compat_sys_open
+#define sys_execve		compat_sys_execve_wrapper
+#define sys_lseek		compat_sys_lseek_wrapper
+#define sys_mount		compat_sys_mount
+#define sys_ptrace		compat_sys_ptrace
+#define sys_times		compat_sys_times
+#define sys_ioctl		compat_sys_ioctl
+#define sys_fcntl		compat_sys_fcntl
+#define sys_ustat		compat_sys_ustat
+#define sys_sigaction		compat_sys_sigaction
+#define sys_sigsuspend		compat_sys_sigsuspend
+#define sys_sigpending		compat_sys_sigpending
+#define sys_setrlimit		compat_sys_setrlimit
+#define sys_getrusage		compat_sys_getrusage
+#define sys_gettimeofday	compat_sys_gettimeofday
+#define sys_settimeofday	compat_sys_settimeofday
+#define sys_statfs		compat_sys_statfs
+#define sys_fstatfs		compat_sys_fstatfs
+#define sys_setitimer		compat_sys_setitimer
+#define sys_getitimer		compat_sys_getitimer
+#define sys_newstat		compat_sys_newstat
+#define sys_newlstat		compat_sys_newlstat
+#define sys_newfstat		compat_sys_newfstat
+#define sys_wait4		compat_sys_wait4
+#define sys_sysinfo		compat_sys_sysinfo
+#define sys_sigreturn		compat_sys_sigreturn_wrapper
+#define sys_clone		compat_sys_clone_wrapper
+#define sys_adjtimex		compat_sys_adjtimex
+#define sys_sigprocmask		compat_sys_sigprocmask
+#define sys_getdents		compat_sys_getdents
+#define sys_select		compat_sys_select
+#define sys_readv		compat_sys_readv
+#define sys_writev		compat_sys_writev
+#define sys_sysctl		compat_sys_sysctl
+#define sys_sched_rr_get_interval compat_sys_sched_rr_get_interval
+#define sys_nanosleep		compat_sys_nanosleep
+#define sys_rt_sigreturn	compat_sys_rt_sigreturn_wrapper
+#define sys_rt_sigaction	compat_sys_rt_sigaction
+#define sys_rt_sigprocmask	compat_sys_rt_sigprocmask
+#define sys_rt_sigpending	compat_sys_rt_sigpending
+#define sys_rt_sigtimedwait	compat_sys_rt_sigtimedwait
+#define sys_rt_sigqueueinfo	compat_sys_rt_sigqueueinfo
+#define sys_rt_sigsuspend	compat_sys_rt_sigsuspend
+#define sys_pread64		compat_sys_pread64_wrapper
+#define sys_pwrite64		compat_sys_pwrite64_wrapper
+#define sys_sigaltstack		compat_sys_sigaltstack_wrapper
+#define sys_sendfile		compat_sys_sendfile
+#define sys_vfork		compat_sys_vfork_wrapper
+#define sys_getrlimit		compat_sys_getrlimit
+#define sys_mmap2		sys_mmap_pgoff
+#define sys_truncate64		compat_sys_truncate64_wrapper
+#define sys_ftruncate64		compat_sys_ftruncate64_wrapper
+#define sys_getdents64		compat_sys_getdents64
+#define sys_fcntl64		compat_sys_fcntl64
+#define sys_readahead		compat_sys_readahead_wrapper
+#define sys_futex		compat_sys_futex
+#define sys_sched_setaffinity	compat_sys_sched_setaffinity
+#define sys_sched_getaffinity	compat_sys_sched_getaffinity
+#define sys_io_setup		compat_sys_io_setup
+#define sys_io_getevents	compat_sys_io_getevents
+#define sys_io_submit		compat_sys_io_submit
+#define sys_lookup_dcookie	compat_sys_lookup_dcookie
+#define sys_timer_create	compat_sys_timer_create
+#define sys_timer_settime	compat_sys_timer_settime
+#define sys_timer_gettime	compat_sys_timer_gettime
+#define sys_clock_settime	compat_sys_clock_settime
+#define sys_clock_gettime	compat_sys_clock_gettime
+#define sys_clock_getres	compat_sys_clock_getres
+#define sys_clock_nanosleep	compat_sys_clock_nanosleep
+#define sys_statfs64		compat_sys_statfs64_wrapper
+#define sys_fstatfs64		compat_sys_fstatfs64_wrapper
+#define sys_utimes		compat_sys_utimes
+#define sys_fadvise64_64	compat_sys_fadvise64_64_wrapper
+#define sys_mq_open		compat_sys_mq_open
+#define sys_mq_timedsend	compat_sys_mq_timedsend
+#define sys_mq_timedreceive	compat_sys_mq_timedreceive
+#define sys_mq_notify		compat_sys_mq_notify
+#define sys_mq_getsetattr	compat_sys_mq_getsetattr
+#define sys_waitid		compat_sys_waitid
+#define sys_recv		compat_sys_recv
+#define sys_recvfrom		compat_sys_recvfrom
+#define sys_setsockopt		compat_sys_setsockopt
+#define sys_getsockopt		compat_sys_getsockopt
+#define sys_sendmsg		compat_sys_sendmsg
+#define sys_recvmsg		compat_sys_recvmsg
+#define sys_semctl		compat_sys_semctl
+#define sys_msgsnd		compat_sys_msgsnd
+#define sys_msgrcv		compat_sys_msgrcv
+#define sys_msgctl		compat_sys_msgctl
+#define sys_shmat		compat_sys_shmat
+#define sys_shmctl		compat_sys_shmctl
+#define sys_keyctl		compat_sys_keyctl
+#define sys_semtimedop		compat_sys_semtimedop
+#define sys_mbind		compat_sys_mbind
+#define sys_get_mempolicy	compat_sys_get_mempolicy
+#define sys_set_mempolicy	compat_sys_set_mempolicy
+#define sys_openat		compat_sys_openat
+#define sys_futimesat		compat_sys_futimesat
+#define sys_pselect6		compat_sys_pselect6
+#define sys_ppoll		compat_sys_ppoll
+#define sys_set_robust_list	compat_sys_set_robust_list
+#define sys_get_robust_list	compat_sys_get_robust_list
+#define sys_sync_file_range2	compat_sys_sync_file_range2_wrapper
+#define sys_vmsplice		compat_sys_vmsplice
+#define sys_move_pages		compat_sys_move_pages
+#define sys_epoll_pwait		compat_sys_epoll_pwait
+#define sys_kexec_load		compat_sys_kexec_load
+#define sys_utimensat		compat_sys_utimensat
+#define sys_signalfd		compat_sys_signalfd
+#define sys_fallocate		compat_sys_fallocate_wrapper
+#define sys_timerfd_settime	compat_sys_timerfd_settime
+#define sys_timerfd_gettime	compat_sys_timerfd_gettime
+#define sys_signalfd4		compat_sys_signalfd4
+#define sys_preadv		compat_sys_preadv
+#define sys_pwritev		compat_sys_pwritev
+#define sys_rt_tgsigqueueinfo	compat_sys_rt_tgsigqueueinfo
+#define sys_recvmmsg		compat_sys_recvmmsg
+#define sys_fanotify_mark	compat_sys_fanotify_mark_wrapper
+
+#undef __SYSCALL
+#define __SYSCALL(x, y)		.quad	y	// x
+#define __SYSCALL_COMPAT
+
+/*
+ * The system calls table must be 4KB aligned.
+ */
+	.align	12
+ENTRY(compat_sys_call_table)
+#include <asm/unistd.h>
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
new file mode 100644
index 0000000..967e92f
--- /dev/null
+++ b/arch/arm64/kernel/sys_compat.c
@@ -0,0 +1,164 @@
+/*
+ * Based on arch/arm/kernel/sys_arm.c
+ *
+ * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c
+ * Copyright (C) 1995, 1996 Russell King.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __SYSCALL_COMPAT
+
+#include <linux/compat.h>
+#include <linux/personality.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+#include <asm/unistd.h>
+
+asmlinkage int compat_sys_fork(struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, regs->compat_sp, regs, 0, NULL, NULL);
+}
+
+asmlinkage int compat_sys_clone(unsigned long clone_flags, unsigned long newsp,
+			  int __user *parent_tidptr, int tls_val,
+			  int __user *child_tidptr, struct pt_regs *regs)
+{
+	if (!newsp)
+		newsp = regs->compat_sp;
+
+	return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
+}
+
+asmlinkage int compat_sys_vfork(struct pt_regs *regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->compat_sp,
+		       regs, 0, NULL, NULL);
+}
+
+asmlinkage int compat_sys_execve(const char __user *filenamei,
+				 compat_uptr_t argv, compat_uptr_t envp,
+				 struct pt_regs *regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname(filenamei);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = compat_do_execve(filename, compat_ptr(argv), compat_ptr(envp),
+				 regs);
+	putname(filename);
+out:
+	return error;
+}
+
+asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid,
+						struct compat_timespec __user *interval)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
+	set_fs(old_fs);
+	if (put_compat_timespec(&t, interval))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage int compat_sys_sendfile(int out_fd, int in_fd,
+				   compat_off_t __user *offset, s32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	off_t of;
+
+	if (offset && get_user(of, offset))
+		return -EFAULT;
+
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
+			   count);
+	set_fs(old_fs);
+
+	if (offset && put_user(of, offset))
+		return -EFAULT;
+	return ret;
+}
+
+static inline void
+do_compat_cache_op(unsigned long start, unsigned long end, int flags)
+{
+	struct mm_struct *mm = current->active_mm;
+	struct vm_area_struct *vma;
+
+	if (end < start || flags)
+		return;
+
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, start);
+	if (vma && vma->vm_start < end) {
+		if (start < vma->vm_start)
+			start = vma->vm_start;
+		if (end > vma->vm_end)
+			end = vma->vm_end;
+		up_read(&mm->mmap_sem);
+		__flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end));
+		return;
+	}
+	up_read(&mm->mmap_sem);
+}
+
+/*
+ * Handle all unrecognised system calls.
+ */
+long compat_arm_syscall(struct pt_regs *regs)
+{
+	unsigned int no = regs->regs[7];
+
+	switch (no) {
+	/*
+	 * Flush a region from virtual address 'r0' to virtual address 'r1'
+	 * _exclusive_.  There is no alignment requirement on either address;
+	 * user space does not need to know the hardware cache layout.
+	 *
+	 * r2 contains flags.  It should ALWAYS be passed as ZERO until it
+	 * is defined to be something else.  For now we ignore it, but may
+	 * the fires of hell burn in your belly if you break this rule. ;)
+	 *
+	 * (at a later date, we may want to allow this call to not flush
+	 * various aspects of the cache.  Passing '0' will guarantee that
+	 * everything necessary gets flushed to maintain consistency in
+	 * the specified region).
+	 */
+	case __ARM_NR_compat_cacheflush:
+		do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
+		return 0;
+
+	case __ARM_NR_compat_set_tls:
+		current->thread.tp_value = regs->regs[0];
+		asm ("msr tpidrro_el0, %0" : : "r" (regs->regs[0]));
+		return 0;
+
+	default:
+		return -ENOSYS;
+	}
+}
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
new file mode 100644
index 0000000..3b4b725
--- /dev/null
+++ b/arch/arm64/kernel/time.c
@@ -0,0 +1,65 @@
+/*
+ * Based on arch/arm/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ * Modifications for ARM (C) 1994-2001 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/timex.h>
+#include <linux/errno.h>
+#include <linux/profile.h>
+#include <linux/syscore_ops.h>
+#include <linux/timer.h>
+#include <linux/irq.h>
+
+#include <clocksource/arm_generic.h>
+
+#include <asm/thread_info.h>
+#include <asm/stacktrace.h>
+
+#ifdef CONFIG_SMP
+unsigned long profile_pc(struct pt_regs *regs)
+{
+	struct stackframe frame;
+
+	if (!in_lock_functions(regs->pc))
+		return regs->pc;
+
+	frame.fp = regs->regs[29];
+	frame.sp = regs->sp;
+	frame.pc = regs->pc;
+	do {
+		int ret = unwind_frame(&frame);
+		if (ret < 0)
+			return 0;
+	} while (in_lock_functions(frame.pc));
+
+	return frame.pc;
+}
+EXPORT_SYMBOL(profile_pc);
+#endif
+
+void __init time_init(void)
+{
+	arm_generic_timer_init();
+}
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
new file mode 100644
index 0000000..3883f84
--- /dev/null
+++ b/arch/arm64/kernel/traps.c
@@ -0,0 +1,348 @@
+/*
+ * Based on arch/arm/kernel/traps.c
+ *
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/signal.h>
+#include <linux/personality.h>
+#include <linux/kallsyms.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+
+#include <asm/atomic.h>
+#include <asm/traps.h>
+#include <asm/stacktrace.h>
+#include <asm/exception.h>
+#include <asm/system_misc.h>
+
+static const char *handler[]= {
+	"Synchronous Abort",
+	"IRQ",
+	"FIQ",
+	"Error"
+};
+
+int show_unhandled_signals = 1;
+
+/*
+ * Dump out the contents of some memory nicely...
+ */
+static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
+		     unsigned long top)
+{
+	unsigned long first;
+	mm_segment_t fs;
+	int i;
+
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	printk("%s%s(0x%016lx to 0x%016lx)\n", lvl, str, bottom, top);
+
+	for (first = bottom & ~31; first < top; first += 32) {
+		unsigned long p;
+		char str[sizeof(" 12345678") * 8 + 1];
+
+		memset(str, ' ', sizeof(str));
+		str[sizeof(str) - 1] = '\0';
+
+		for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
+			if (p >= bottom && p < top) {
+				unsigned int val;
+				if (__get_user(val, (unsigned int *)p) == 0)
+					sprintf(str + i * 9, " %08x", val);
+				else
+					sprintf(str + i * 9, " ????????");
+			}
+		}
+		printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
+	}
+
+	set_fs(fs);
+}
+
+static void dump_backtrace_entry(unsigned long where, unsigned long stack)
+{
+	print_ip_sym(where);
+	if (in_exception_text(where))
+		dump_mem("", "Exception stack", stack,
+			 stack + sizeof(struct pt_regs));
+}
+
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+	unsigned long addr = instruction_pointer(regs);
+	mm_segment_t fs;
+	char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
+	int i;
+
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	for (i = -4; i < 1; i++) {
+		unsigned int val, bad;
+
+		bad = __get_user(val, &((u32 *)addr)[i]);
+
+		if (!bad)
+			p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);
+		else {
+			p += sprintf(p, "bad PC value");
+			break;
+		}
+	}
+	printk("%sCode: %s\n", lvl, str);
+
+	set_fs(fs);
+}
+
+static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
+{
+	struct stackframe frame;
+	const register unsigned long current_sp asm ("sp");
+
+	pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
+
+	if (!tsk)
+		tsk = current;
+
+	if (regs) {
+		frame.fp = regs->regs[29];
+		frame.sp = regs->sp;
+		frame.pc = regs->pc;
+	} else if (tsk == current) {
+		frame.fp = (unsigned long)__builtin_frame_address(0);
+		frame.sp = current_sp;
+		frame.pc = (unsigned long)dump_backtrace;
+	} else {
+		/*
+		 * task blocked in __switch_to
+		 */
+		frame.fp = thread_saved_fp(tsk);
+		frame.sp = thread_saved_sp(tsk);
+		frame.pc = thread_saved_pc(tsk);
+	}
+
+	printk("Call trace:\n");
+	while (1) {
+		unsigned long where = frame.pc;
+		int ret;
+
+		ret = unwind_frame(&frame);
+		if (ret < 0)
+			break;
+		dump_backtrace_entry(where, frame.sp);
+	}
+}
+
+void dump_stack(void)
+{
+	dump_backtrace(NULL, NULL);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_stack(struct task_struct *tsk, unsigned long *sp)
+{
+	dump_backtrace(NULL, tsk);
+	barrier();
+}
+
+#ifdef CONFIG_PREEMPT
+#define S_PREEMPT " PREEMPT"
+#else
+#define S_PREEMPT ""
+#endif
+#ifdef CONFIG_SMP
+#define S_SMP " SMP"
+#else
+#define S_SMP ""
+#endif
+
+static int __die(const char *str, int err, struct thread_info *thread,
+		 struct pt_regs *regs)
+{
+	struct task_struct *tsk = thread->task;
+	static int die_counter;
+	int ret;
+
+	pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
+		 str, err, ++die_counter);
+
+	/* trap and error numbers are mostly meaningless on ARM */
+	ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV);
+	if (ret == NOTIFY_STOP)
+		return ret;
+
+	print_modules();
+	__show_regs(regs);
+	pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
+		 TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
+
+	if (!user_mode(regs) || in_interrupt()) {
+		dump_mem(KERN_EMERG, "Stack: ", regs->sp,
+			 THREAD_SIZE + (unsigned long)task_stack_page(tsk));
+		dump_backtrace(regs, tsk);
+		dump_instr(KERN_EMERG, regs);
+	}
+
+	return ret;
+}
+
+static DEFINE_RAW_SPINLOCK(die_lock);
+
+/*
+ * This function is protected against re-entrancy.
+ */
+void die(const char *str, struct pt_regs *regs, int err)
+{
+	struct thread_info *thread = current_thread_info();
+	int ret;
+
+	oops_enter();
+
+	raw_spin_lock_irq(&die_lock);
+	console_verbose();
+	bust_spinlocks(1);
+	ret = __die(str, err, thread, regs);
+
+	if (regs && kexec_should_crash(thread->task))
+		crash_kexec(regs);
+
+	bust_spinlocks(0);
+	add_taint(TAINT_DIE);
+	raw_spin_unlock_irq(&die_lock);
+	oops_exit();
+
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+	if (panic_on_oops)
+		panic("Fatal exception");
+	if (ret != NOTIFY_STOP)
+		do_exit(SIGSEGV);
+}
+
+void arm64_notify_die(const char *str, struct pt_regs *regs,
+		      struct siginfo *info, int err)
+{
+	if (user_mode(regs))
+		force_sig_info(info->si_signo, info, current);
+	else
+		die(str, regs, err);
+}
+
+asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
+{
+	siginfo_t info;
+	void __user *pc = (void __user *)instruction_pointer(regs);
+
+#ifdef CONFIG_COMPAT
+	/* check for AArch32 breakpoint instructions */
+	if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0)
+		return;
+#endif
+
+	if (show_unhandled_signals) {
+		pr_info("%s[%d]: undefined instruction: pc=%p\n",
+			current->comm, task_pid_nr(current), pc);
+		dump_instr(KERN_INFO, regs);
+	}
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code  = ILL_ILLOPC;
+	info.si_addr  = pc;
+
+	arm64_notify_die("Oops - undefined instruction", regs, &info, 0);
+}
+
+long compat_arm_syscall(struct pt_regs *regs);
+
+asmlinkage long do_ni_syscall(struct pt_regs *regs)
+{
+#ifdef CONFIG_COMPAT
+	long ret;
+	if (is_compat_task()) {
+		ret = compat_arm_syscall(regs);
+		if (ret != -ENOSYS)
+			return ret;
+	}
+#endif
+
+	if (show_unhandled_signals) {
+		pr_info("%s[%d]: syscall %d\n", current->comm,
+			task_pid_nr(current), (int)regs->syscallno);
+		dump_instr("", regs);
+		if (user_mode(regs))
+			__show_regs(regs);
+	}
+
+	return sys_ni_syscall();
+}
+
+/*
+ * bad_mode handles the impossible case in the exception vector.
+ */
+asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
+{
+	console_verbose();
+
+	pr_crit("Bad mode in %s handler detected, code 0x%08x\n",
+		handler[reason], esr);
+
+	die("Oops - bad mode", regs, 0);
+	local_irq_disable();
+	panic("bad mode");
+}
+
+void __pte_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pte %016lx.\n", file, line, val);
+}
+
+void __pmd_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pmd %016lx.\n", file, line, val);
+}
+
+void __pgd_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pgd %016lx.\n", file, line, val);
+}
+
+void __init trap_init(void)
+{
+	return;
+}
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
new file mode 100644
index 0000000..17948fc
--- /dev/null
+++ b/arch/arm64/kernel/vdso.c
@@ -0,0 +1,261 @@
+/*
+ * VDSO implementation for AArch64 and vector page setup for AArch32.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/cacheflush.h>
+#include <asm/signal32.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+
+extern char vdso_start, vdso_end;
+static unsigned long vdso_pages;
+static struct page **vdso_pagelist;
+
+/*
+ * The vDSO data page.
+ */
+static union {
+	struct vdso_data	data;
+	u8			page[PAGE_SIZE];
+} vdso_data_store __page_aligned_data;
+struct vdso_data *vdso_data = &vdso_data_store.data;
+
+#ifdef CONFIG_COMPAT
+/*
+ * Create and map the vectors page for AArch32 tasks.
+ */
+static struct page *vectors_page[1];
+
+static int alloc_vectors_page(void)
+{
+	extern char __kuser_helper_start[], __kuser_helper_end[];
+	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+	unsigned long vpage;
+
+	vpage = get_zeroed_page(GFP_ATOMIC);
+
+	if (!vpage)
+		return -ENOMEM;
+
+	/* kuser helpers */
+	memcpy((void *)vpage + 0x1000 - kuser_sz, __kuser_helper_start,
+		kuser_sz);
+
+	/* sigreturn code */
+	memcpy((void *)vpage + AARCH32_KERN_SIGRET_CODE_OFFSET,
+		aarch32_sigret_code, sizeof(aarch32_sigret_code));
+
+	flush_icache_range(vpage, vpage + PAGE_SIZE);
+	vectors_page[0] = virt_to_page(vpage);
+
+	return 0;
+}
+arch_initcall(alloc_vectors_page);
+
+int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr = AARCH32_VECTORS_BASE;
+	int ret;
+
+	down_write(&mm->mmap_sem);
+	current->mm->context.vdso = (void *)addr;
+
+	/* Map vectors page at the high address. */
+	ret = install_special_mapping(mm, addr, PAGE_SIZE,
+				      VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC,
+				      vectors_page);
+
+	up_write(&mm->mmap_sem);
+
+	return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+static int __init vdso_init(void)
+{
+	struct page *pg;
+	char *vbase;
+	int i, ret = 0;
+
+	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+	pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
+		vdso_pages + 1, vdso_pages, 1L, &vdso_start);
+
+	/* Allocate the vDSO pagelist, plus a page for the data. */
+	vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1),
+				GFP_KERNEL);
+	if (vdso_pagelist == NULL) {
+		pr_err("Failed to allocate vDSO pagelist!\n");
+		return -ENOMEM;
+	}
+
+	/* Grab the vDSO code pages. */
+	for (i = 0; i < vdso_pages; i++) {
+		pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+		vdso_pagelist[i] = pg;
+	}
+
+	/* Sanity check the shared object header. */
+	vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
+	if (vbase == NULL) {
+		pr_err("Failed to map vDSO pagelist!\n");
+		return -ENOMEM;
+	} else if (memcmp(vbase, "\177ELF", 4)) {
+		pr_err("vDSO is not a valid ELF object!\n");
+		ret = -EINVAL;
+		goto unmap;
+	}
+
+	/* Grab the vDSO data page. */
+	pg = virt_to_page(vdso_data);
+	get_page(pg);
+	vdso_pagelist[i] = pg;
+
+unmap:
+	vunmap(vbase);
+	return ret;
+}
+arch_initcall(vdso_init);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+				int uses_interp)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long vdso_base, vdso_mapping_len;
+	int ret;
+
+	/* Be sure to map the data page */
+	vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+
+	down_write(&mm->mmap_sem);
+	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	if (IS_ERR_VALUE(vdso_base)) {
+		ret = vdso_base;
+		goto up_fail;
+	}
+	mm->context.vdso = (void *)vdso_base;
+
+	ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
+				      VM_READ|VM_EXEC|
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				      vdso_pagelist);
+	if (ret) {
+		mm->context.vdso = NULL;
+		goto up_fail;
+	}
+
+up_fail:
+	up_write(&mm->mmap_sem);
+
+	return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+	/*
+	 * We can re-use the vdso pointer in mm_context_t for identifying
+	 * the vectors page for compat applications. The vDSO will always
+	 * sit above TASK_UNMAPPED_BASE and so we don't need to worry about
+	 * it conflicting with the vectors base.
+	 */
+	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) {
+#ifdef CONFIG_COMPAT
+		if (vma->vm_start == AARCH32_VECTORS_BASE)
+			return "[vectors]";
+#endif
+		return "[vdso]";
+	}
+
+	return NULL;
+}
+
+/*
+ * We define AT_SYSINFO_EHDR, so we need these function stubs to keep
+ * Linux happy.
+ */
+int in_gate_area_no_mm(unsigned long addr)
+{
+	return 0;
+}
+
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
+{
+	return 0;
+}
+
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
+{
+	return NULL;
+}
+
+/*
+ * Update the vDSO data page to keep in sync with kernel timekeeping.
+ */
+void update_vsyscall(struct timespec *ts, struct timespec *wtm,
+		     struct clocksource *clock, u32 mult)
+{
+	struct timespec xtime_coarse;
+	u32 use_syscall = strcmp(clock->name, "arch_sys_counter");
+
+	++vdso_data->tb_seq_count;
+	smp_wmb();
+
+	xtime_coarse = __current_kernel_time();
+	vdso_data->use_syscall			= use_syscall;
+	vdso_data->xtime_coarse_sec		= xtime_coarse.tv_sec;
+	vdso_data->xtime_coarse_nsec		= xtime_coarse.tv_nsec;
+
+	if (!use_syscall) {
+		vdso_data->cs_cycle_last	= clock->cycle_last;
+		vdso_data->xtime_clock_sec	= ts->tv_sec;
+		vdso_data->xtime_clock_nsec	= ts->tv_nsec;
+		vdso_data->cs_mult		= mult;
+		vdso_data->cs_shift		= clock->shift;
+		vdso_data->wtm_clock_sec	= wtm->tv_sec;
+		vdso_data->wtm_clock_nsec	= wtm->tv_nsec;
+	}
+
+	smp_wmb();
+	++vdso_data->tb_seq_count;
+}
+
+void update_vsyscall_tz(void)
+{
+	++vdso_data->tb_seq_count;
+	smp_wmb();
+	vdso_data->tz_minuteswest	= sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime		= sys_tz.tz_dsttime;
+	smp_wmb();
+	++vdso_data->tb_seq_count;
+}
diff --git a/arch/arm64/kernel/vdso/.gitignore b/arch/arm64/kernel/vdso/.gitignore
new file mode 100644
index 0000000..b8cc94e
--- /dev/null
+++ b/arch/arm64/kernel/vdso/.gitignore
@@ -0,0 +1,2 @@
+vdso.lds
+vdso-offsets.h
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
new file mode 100644
index 0000000..d8064af
--- /dev/null
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -0,0 +1,63 @@
+#
+# Building a vDSO image for AArch64.
+#
+# Author: Will Deacon <will.deacon@arm.com>
+# Heavily based on the vDSO Makefiles for other archs.
+#
+
+obj-vdso := gettimeofday.o note.o sigreturn.o
+
+# Build rules
+targets := $(obj-vdso) vdso.so vdso.so.dbg
+obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
+
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
+		$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdso.o
+extra-y += vdso.lds vdso-offsets.h
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+# Force dependency (incbin is bad)
+$(obj)/vdso.o : $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
+	$(call if_changed,vdsold)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+define cmd_vdsosym
+	$(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \
+	cp $@ include/generated/
+endef
+
+$(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
+# Assembly rules for the .S files
+$(obj-vdso): %.o: %.S
+	$(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdsoas = VDSOA $@
+      cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso.so: $(obj)/vdso.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm64/kernel/vdso/gen_vdso_offsets.sh b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh
new file mode 100755
index 0000000..01924ff
--- /dev/null
+++ b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <will.deacon@arm.com
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p'
diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S
new file mode 100644
index 0000000..dcb8c20
--- /dev/null
+++ b/arch/arm64/kernel/vdso/gettimeofday.S
@@ -0,0 +1,242 @@
+/*
+ * Userspace implementations of gettimeofday() and friends.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+#define NSEC_PER_SEC_LO16	0xca00
+#define NSEC_PER_SEC_HI16	0x3b9a
+
+vdso_data	.req	x6
+use_syscall	.req	w7
+seqcnt		.req	w8
+
+	.macro	seqcnt_acquire
+9999:	ldr	seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
+	tbnz	seqcnt, #0, 9999b
+	dmb	ishld
+	ldr	use_syscall, [vdso_data, #VDSO_USE_SYSCALL]
+	.endm
+
+	.macro	seqcnt_read, cnt
+	dmb	ishld
+	ldr	\cnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
+	.endm
+
+	.macro	seqcnt_check, cnt, fail
+	cmp	\cnt, seqcnt
+	b.ne	\fail
+	.endm
+
+	.text
+
+/* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */
+ENTRY(__kernel_gettimeofday)
+	.cfi_startproc
+	mov	x2, x30
+	.cfi_register x30, x2
+
+	/* Acquire the sequence counter and get the timespec. */
+	adr	vdso_data, _vdso_data
+1:	seqcnt_acquire
+	cbnz	use_syscall, 4f
+
+	/* If tv is NULL, skip to the timezone code. */
+	cbz	x0, 2f
+	bl	__do_get_tspec
+	seqcnt_check w13, 1b
+
+	/* Convert ns to us. */
+	mov	x11, #1000
+	udiv	x10, x10, x11
+	stp	x9, x10, [x0, #TVAL_TV_SEC]
+2:
+	/* If tz is NULL, return 0. */
+	cbz	x1, 3f
+	ldp	w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
+	seqcnt_read w13
+	seqcnt_check w13, 1b
+	stp	w4, w5, [x1, #TZ_MINWEST]
+3:
+	mov	x0, xzr
+	ret	x2
+4:
+	/* Syscall fallback. */
+	mov	x8, #__NR_gettimeofday
+	svc	#0
+	ret	x2
+	.cfi_endproc
+ENDPROC(__kernel_gettimeofday)
+
+/* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
+ENTRY(__kernel_clock_gettime)
+	.cfi_startproc
+	cmp	w0, #CLOCK_REALTIME
+	ccmp	w0, #CLOCK_MONOTONIC, #0x4, ne
+	b.ne	2f
+
+	mov	x2, x30
+	.cfi_register x30, x2
+
+	/* Get kernel timespec. */
+	adr	vdso_data, _vdso_data
+1:	seqcnt_acquire
+	cbnz	use_syscall, 7f
+
+	bl	__do_get_tspec
+	seqcnt_check w13, 1b
+
+	cmp	w0, #CLOCK_MONOTONIC
+	b.ne	6f
+
+	/* Get wtm timespec. */
+	ldp	x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
+
+	/* Check the sequence counter. */
+	seqcnt_read w13
+	seqcnt_check w13, 1b
+	b	4f
+2:
+	cmp	w0, #CLOCK_REALTIME_COARSE
+	ccmp	w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
+	b.ne	8f
+
+	/* Get coarse timespec. */
+	adr	vdso_data, _vdso_data
+3:	seqcnt_acquire
+	ldp	x9, x10, [vdso_data, #VDSO_XTIME_CRS_SEC]
+
+	cmp	w0, #CLOCK_MONOTONIC_COARSE
+	b.ne	6f
+
+	/* Get wtm timespec. */
+	ldp	x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
+
+	/* Check the sequence counter. */
+	seqcnt_read w13
+	seqcnt_check w13, 3b
+4:
+	/* Add on wtm timespec. */
+	add	x9, x9, x14
+	add	x10, x10, x15
+
+	/* Normalise the new timespec. */
+	mov	x14, #NSEC_PER_SEC_LO16
+	movk	x14, #NSEC_PER_SEC_HI16, lsl #16
+	cmp	x10, x14
+	b.lt	5f
+	sub	x10, x10, x14
+	add	x9, x9, #1
+5:
+	cmp	x10, #0
+	b.ge	6f
+	add	x10, x10, x14
+	sub	x9, x9, #1
+
+6:	/* Store to the user timespec. */
+	stp	x9, x10, [x1, #TSPEC_TV_SEC]
+	mov	x0, xzr
+	ret	x2
+7:
+	mov	x30, x2
+8:	/* Syscall fallback. */
+	mov	x8, #__NR_clock_gettime
+	svc	#0
+	ret
+	.cfi_endproc
+ENDPROC(__kernel_clock_gettime)
+
+/* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
+ENTRY(__kernel_clock_getres)
+	.cfi_startproc
+	cbz	w1, 3f
+
+	cmp	w0, #CLOCK_REALTIME
+	ccmp	w0, #CLOCK_MONOTONIC, #0x4, ne
+	b.ne	1f
+
+	ldr	x2, 5f
+	b	2f
+1:
+	cmp	w0, #CLOCK_REALTIME_COARSE
+	ccmp	w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
+	b.ne	4f
+	ldr	x2, 6f
+2:
+	stp	xzr, x2, [x1]
+
+3:	/* res == NULL. */
+	mov	w0, wzr
+	ret
+
+4:	/* Syscall fallback. */
+	mov	x8, #__NR_clock_getres
+	svc	#0
+	ret
+5:
+	.quad	CLOCK_REALTIME_RES
+6:
+	.quad	CLOCK_COARSE_RES
+	.cfi_endproc
+ENDPROC(__kernel_clock_getres)
+
+/*
+ * Read the current time from the architected counter.
+ * Expects vdso_data to be initialised.
+ * Clobbers the temporary registers (x9 - x15).
+ * Returns:
+ *  - (x9, x10) = (ts->tv_sec, ts->tv_nsec)
+ *  - (x11, x12) = (xtime->tv_sec, xtime->tv_nsec)
+ *  - w13 = vDSO sequence counter
+ */
+ENTRY(__do_get_tspec)
+	.cfi_startproc
+
+	/* Read from the vDSO data page. */
+	ldr	x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
+	ldp	x11, x12, [vdso_data, #VDSO_XTIME_CLK_SEC]
+	ldp	w14, w15, [vdso_data, #VDSO_CS_MULT]
+	seqcnt_read w13
+
+	/* Read the physical counter. */
+	isb
+	mrs	x9, cntpct_el0
+
+	/* Calculate cycle delta and convert to ns. */
+	sub	x10, x9, x10
+	/* We can only guarantee 56 bits of precision. */
+	movn	x9, #0xff0, lsl #48
+	and	x10, x9, x10
+	mul	x10, x10, x14
+	lsr	x10, x10, x15
+
+	/* Use the kernel time to calculate the new timespec. */
+	add	x10, x12, x10
+	mov	x14, #NSEC_PER_SEC_LO16
+	movk	x14, #NSEC_PER_SEC_HI16, lsl #16
+	udiv	x15, x10, x14
+	add	x9, x15, x11
+	mul	x14, x14, x15
+	sub	x10, x10, x14
+
+	ret
+	.cfi_endproc
+ENDPROC(__do_get_tspec)
diff --git a/arch/arm64/kernel/vdso/note.S b/arch/arm64/kernel/vdso/note.S
new file mode 100644
index 0000000..b82c85e
--- /dev/null
+++ b/arch/arm64/kernel/vdso/note.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+	.long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S
new file mode 100644
index 0000000..20d98ef
--- /dev/null
+++ b/arch/arm64/kernel/vdso/sigreturn.S
@@ -0,0 +1,37 @@
+/*
+ * Sigreturn trampoline for returning from a signal when the SA_RESTORER
+ * flag is not set.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+	.text
+
+	nop
+ENTRY(__kernel_rt_sigreturn)
+	.cfi_startproc
+	.cfi_signal_frame
+	.cfi_def_cfa	x29, 0
+	.cfi_offset	x29, 0 * 8
+	.cfi_offset	x30, 1 * 8
+	mov	x8, #__NR_rt_sigreturn
+	svc	#0
+	.cfi_endproc
+ENDPROC(__kernel_rt_sigreturn)
diff --git a/arch/arm64/kernel/vdso/vdso.S b/arch/arm64/kernel/vdso/vdso.S
new file mode 100644
index 0000000..60c1db5
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vdso.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+	__PAGE_ALIGNED_DATA
+
+	.globl vdso_start, vdso_end
+	.balign PAGE_SIZE
+vdso_start:
+	.incbin "arch/arm64/kernel/vdso/vdso.so"
+	.balign PAGE_SIZE
+vdso_end:
+
+	.previous
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
new file mode 100644
index 0000000..8154b8d
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -0,0 +1,100 @@
+/*
+ * GNU linker script for the VDSO library.
+*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+
+SECTIONS
+{
+	. = VDSO_LBASE + SIZEOF_HEADERS;
+
+	.hash		: { *(.hash) }			:text
+	.gnu.hash	: { *(.gnu.hash) }
+	.dynsym		: { *(.dynsym) }
+	.dynstr		: { *(.dynstr) }
+	.gnu.version	: { *(.gnu.version) }
+	.gnu.version_d	: { *(.gnu.version_d) }
+	.gnu.version_r	: { *(.gnu.version_r) }
+
+	.note		: { *(.note.*) }		:text	:note
+
+	. = ALIGN(16);
+
+	.text		: { *(.text*) }			:text	=0xd503201f
+	PROVIDE (__etext = .);
+	PROVIDE (_etext = .);
+	PROVIDE (etext = .);
+
+	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+	.eh_frame	: { KEEP (*(.eh_frame)) }	:text
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.rodata		: { *(.rodata*) }		:text
+
+	_end = .;
+	PROVIDE(end = .);
+
+	. = ALIGN(PAGE_SIZE);
+	PROVIDE(_vdso_data = .);
+
+	/DISCARD/	: {
+		*(.note.GNU-stack)
+		*(.data .data.* .gnu.linkonce.d.* .sdata*)
+		*(.bss .sbss .dynbss .dynsbss)
+	}
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+	text		PT_LOAD		FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+	dynamic		PT_DYNAMIC	FLAGS(4);		/* PF_R */
+	note		PT_NOTE		FLAGS(4);		/* PF_R */
+	eh_frame_hdr	PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+	LINUX_2.6.39 {
+	global:
+		__kernel_rt_sigreturn;
+		__kernel_gettimeofday;
+		__kernel_clock_gettime;
+		__kernel_clock_getres;
+	local: *;
+	};
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp		= __kernel_rt_sigreturn;
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..3fae2be
--- /dev/null
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -0,0 +1,126 @@
+/*
+ * ld script to make ARM Linux kernel
+ * taken from the i386 version by Russell King
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/thread_info.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+
+#define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x)	x
+
+OUTPUT_ARCH(aarch64)
+ENTRY(stext)
+
+jiffies = jiffies_64;
+
+SECTIONS
+{
+	/*
+	 * XXX: The linker does not define how output sections are
+	 * assigned to input sections when there are multiple statements
+	 * matching the same input section name.  There is no documented
+	 * order of matching.
+	 */
+	/DISCARD/ : {
+		ARM_EXIT_DISCARD(EXIT_TEXT)
+		ARM_EXIT_DISCARD(EXIT_DATA)
+		EXIT_CALL
+		*(.discard)
+		*(.discard.*)
+	}
+
+	. = PAGE_OFFSET + TEXT_OFFSET;
+
+	.head.text : {
+		_text = .;
+		HEAD_TEXT
+	}
+	.text : {			/* Real text segment		*/
+		_stext = .;		/* Text and read-only data	*/
+			*(.smp.pen.text)
+			__exception_text_start = .;
+			*(.exception.text)
+			__exception_text_end = .;
+			IRQENTRY_TEXT
+			TEXT_TEXT
+			SCHED_TEXT
+			LOCK_TEXT
+			*(.fixup)
+			*(.gnu.warning)
+		. = ALIGN(16);
+		*(.got)			/* Global offset table		*/
+	}
+
+	RO_DATA(PAGE_SIZE)
+
+	_etext = .;			/* End of text and rodata section */
+
+	. = ALIGN(PAGE_SIZE);
+	__init_begin = .;
+
+	INIT_TEXT_SECTION(8)
+	.exit.text : {
+		ARM_EXIT_KEEP(EXIT_TEXT)
+	}
+	. = ALIGN(16);
+	.init.data : {
+		INIT_DATA
+		INIT_SETUP(16)
+		INIT_CALLS
+		CON_INITCALL
+		SECURITY_INITCALL
+		INIT_RAM_FS
+	}
+	.exit.data : {
+		ARM_EXIT_KEEP(EXIT_DATA)
+	}
+
+	PERCPU_SECTION(64)
+
+	__init_end = .;
+	. = ALIGN(THREAD_SIZE);
+	__data_loc = .;
+
+	.data : AT(__data_loc) {
+		_data = .;		/* address in memory */
+		_sdata = .;
+
+		/*
+		 * first, the init task union, aligned
+		 * to an 8192 byte boundary.
+		 */
+		INIT_TASK_DATA(THREAD_SIZE)
+		NOSAVE_DATA
+		CACHELINE_ALIGNED_DATA(64)
+		READ_MOSTLY_DATA(64)
+
+		/*
+		 * The exception fixup table (might need resorting at runtime)
+		 */
+		. = ALIGN(32);
+		__start___ex_table = .;
+		*(__ex_table)
+		__stop___ex_table = .;
+
+		/*
+		 * and the usual data section
+		 */
+		DATA_DATA
+		CONSTRUCTORS
+
+		_edata = .;
+	}
+	_edata_loc = __data_loc + SIZEOF(.data);
+
+	NOTES
+
+	BSS_SECTION(0, 0, 0)
+	_end = .;
+
+	STABS_DEBUG
+	.comment 0 : { *(.comment) }
+}
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
new file mode 100644
index 0000000..2fb7f60
--- /dev/null
+++ b/arch/arm64/lib/Makefile
@@ -0,0 +1,4 @@
+lib-y		:= bitops.o delay.o					\
+		   strncpy_from_user.o strnlen_user.o clear_user.o	\
+		   copy_from_user.o copy_to_user.o copy_in_user.o	\
+		   copy_page.o clear_page.o
diff --git a/arch/arm64/lib/bitops.c b/arch/arm64/lib/bitops.c
new file mode 100644
index 0000000..aa4965e
--- /dev/null
+++ b/arch/arm64/lib/bitops.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+
+#ifdef CONFIG_SMP
+arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
+       [0 ... (ATOMIC_HASH_SIZE-1)]  = __ARCH_SPIN_LOCK_UNLOCKED
+};
+#endif
diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
new file mode 100644
index 0000000..ef08e90
--- /dev/null
+++ b/arch/arm64/lib/clear_page.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/assembler.h>
+#include <asm/page.h>
+
+/*
+ * Clear page @dest
+ *
+ * Parameters:
+ *	x0 - dest
+ */
+ENTRY(clear_page)
+	mrs	x1, dczid_el0
+	and	w1, w1, #0xf
+	mov	x2, #4
+	lsl	x1, x2, x1
+
+1:	dc	zva, x0
+	add	x0, x0, x1
+	tst	x0, #(PAGE_SIZE - 1)
+	b.ne	1b
+	ret
+ENDPROC(clear_page)
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
new file mode 100644
index 0000000..6e0ed93
--- /dev/null
+++ b/arch/arm64/lib/clear_user.S
@@ -0,0 +1,58 @@
+/*
+ * Based on arch/arm/lib/clear_user.S
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+	.text
+
+/* Prototype: int __clear_user(void *addr, size_t sz)
+ * Purpose  : clear some user memory
+ * Params   : addr - user memory address to clear
+ *          : sz   - number of bytes to clear
+ * Returns  : number of bytes NOT cleared
+ *
+ * Alignment fixed up by hardware.
+ */
+ENTRY(__clear_user)
+	mov	x2, x1			// save the size for fixup return
+	subs	x1, x1, #8
+	b.mi	2f
+1:
+USER(9f, str	xzr, [x0], #8	)
+	subs	x1, x1, #8
+	b.pl	1b
+2:	adds	x1, x1, #4
+	b.mi	3f
+USER(9f, str	wzr, [x0], #4	)
+	sub	x1, x1, #4
+3:	adds	x1, x1, #2
+	b.mi	4f
+USER(9f, strh	wzr, [x0], #2	)
+	sub	x1, x1, #2
+4:	adds	x1, x1, #1
+	b.mi	5f
+	strb	wzr, [x0]
+5:	mov	x0, #0
+	ret
+ENDPROC(__clear_user)
+
+	.section .fixup,"ax"
+	.align	2
+9:	mov	x0, x2			// return the original size
+	ret
+	.previous
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
new file mode 100644
index 0000000..5e27add
--- /dev/null
+++ b/arch/arm64/lib/copy_from_user.S
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Copy from user space to a kernel buffer (alignment handled by the hardware)
+ *
+ * Parameters:
+ *	x0 - to
+ *	x1 - from
+ *	x2 - n
+ * Returns:
+ *	x0 - bytes not copied
+ */
+ENTRY(__copy_from_user)
+	add	x4, x1, x2			// upper user buffer boundary
+	subs	x2, x2, #8
+	b.mi	2f
+1:
+USER(9f, ldr	x3, [x1], #8	)
+	subs	x2, x2, #8
+	str	x3, [x0], #8
+	b.pl	1b
+2:	adds	x2, x2, #4
+	b.mi	3f
+USER(9f, ldr	w3, [x1], #4	)
+	sub	x2, x2, #4
+	str	w3, [x0], #4
+3:	adds	x2, x2, #2
+	b.mi	4f
+USER(9f, ldrh	w3, [x1], #2	)
+	sub	x2, x2, #2
+	strh	w3, [x0], #2
+4:	adds	x2, x2, #1
+	b.mi	5f
+USER(9f, ldrb	w3, [x1]	)
+	strb	w3, [x0]
+5:	mov	x0, #0
+	ret
+ENDPROC(__copy_from_user)
+
+	.section .fixup,"ax"
+	.align	2
+9:	sub	x2, x4, x1
+	mov	x3, x2
+10:	strb	wzr, [x0], #1			// zero remaining buffer space
+	subs	x3, x3, #1
+	b.ne	10b
+	mov	x0, x2				// bytes not copied
+	ret
+	.previous
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
new file mode 100644
index 0000000..84b6c9b
--- /dev/null
+++ b/arch/arm64/lib/copy_in_user.S
@@ -0,0 +1,63 @@
+/*
+ * Copy from user space to user space
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Copy from user space to user space (alignment handled by the hardware)
+ *
+ * Parameters:
+ *	x0 - to
+ *	x1 - from
+ *	x2 - n
+ * Returns:
+ *	x0 - bytes not copied
+ */
+ENTRY(__copy_in_user)
+	add	x4, x0, x2			// upper user buffer boundary
+	subs	x2, x2, #8
+	b.mi	2f
+1:
+USER(9f, ldr	x3, [x1], #8	)
+	subs	x2, x2, #8
+USER(9f, str	x3, [x0], #8	)
+	b.pl	1b
+2:	adds	x2, x2, #4
+	b.mi	3f
+USER(9f, ldr	w3, [x1], #4	)
+	sub	x2, x2, #4
+USER(9f, str	w3, [x0], #4	)
+3:	adds	x2, x2, #2
+	b.mi	4f
+USER(9f, ldrh	w3, [x1], #2	)
+	sub	x2, x2, #2
+USER(9f, strh	w3, [x0], #2	)
+4:	adds	x2, x2, #1
+	b.mi	5f
+USER(9f, ldrb	w3, [x1]	)
+USER(9f, strb	w3, [x0]	)
+5:	mov	x0, #0
+	ret
+ENDPROC(__copy_in_user)
+
+	.section .fixup,"ax"
+	.align	2
+9:	sub	x0, x4, x0			// bytes not copied
+	ret
+	.previous
diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
new file mode 100644
index 0000000..512b9a7
--- /dev/null
+++ b/arch/arm64/lib/copy_page.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/assembler.h>
+#include <asm/page.h>
+
+/*
+ * Copy a page from src to dest (both are page aligned)
+ *
+ * Parameters:
+ *	x0 - dest
+ *	x1 - src
+ */
+ENTRY(copy_page)
+	/* Assume cache line size is 64 bytes. */
+	prfm	pldl1strm, [x1, #64]
+1:	ldp	x2, x3, [x1]
+	ldp	x4, x5, [x1, #16]
+	ldp	x6, x7, [x1, #32]
+	ldp	x8, x9, [x1, #48]
+	add	x1, x1, #64
+	prfm	pldl1strm, [x1, #64]
+	stnp	x2, x3, [x0]
+	stnp	x4, x5, [x0, #16]
+	stnp	x6, x7, [x0, #32]
+	stnp	x8, x9, [x0, #48]
+	add	x0, x0, #64
+	tst	x1, #(PAGE_SIZE - 1)
+	b.ne	1b
+	ret
+ENDPROC(copy_page)
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
new file mode 100644
index 0000000..a0aeeb9
--- /dev/null
+++ b/arch/arm64/lib/copy_to_user.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Copy to user space from a kernel buffer (alignment handled by the hardware)
+ *
+ * Parameters:
+ *	x0 - to
+ *	x1 - from
+ *	x2 - n
+ * Returns:
+ *	x0 - bytes not copied
+ */
+ENTRY(__copy_to_user)
+	add	x4, x0, x2			// upper user buffer boundary
+	subs	x2, x2, #8
+	b.mi	2f
+1:
+	ldr	x3, [x1], #8
+	subs	x2, x2, #8
+USER(9f, str	x3, [x0], #8	)
+	b.pl	1b
+2:	adds	x2, x2, #4
+	b.mi	3f
+	ldr	w3, [x1], #4
+	sub	x2, x2, #4
+USER(9f, str	w3, [x0], #4	)
+3:	adds	x2, x2, #2
+	b.mi	4f
+	ldrh	w3, [x1], #2
+	sub	x2, x2, #2
+USER(9f, strh	w3, [x0], #2	)
+4:	adds	x2, x2, #1
+	b.mi	5f
+	ldrb	w3, [x1]
+USER(9f, strb	w3, [x0]	)
+5:	mov	x0, #0
+	ret
+ENDPROC(__copy_to_user)
+
+	.section .fixup,"ax"
+	.align	2
+9:	sub	x0, x4, x0			// bytes not copied
+	ret
+	.previous
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
new file mode 100644
index 0000000..dad4ec9
--- /dev/null
+++ b/arch/arm64/lib/delay.c
@@ -0,0 +1,55 @@
+/*
+ * Delay loops based on the OpenRISC implementation.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timex.h>
+
+void __delay(unsigned long cycles)
+{
+	cycles_t start = get_cycles();
+
+	while ((get_cycles() - start) < cycles)
+		cpu_relax();
+}
+EXPORT_SYMBOL(__delay);
+
+inline void __const_udelay(unsigned long xloops)
+{
+	unsigned long loops;
+
+	loops = xloops * loops_per_jiffy * HZ;
+	__delay(loops >> 32);
+}
+EXPORT_SYMBOL(__const_udelay);
+
+void __udelay(unsigned long usecs)
+{
+	__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned long nsecs)
+{
+	__const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
+}
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/arm64/lib/strncpy_from_user.S b/arch/arm64/lib/strncpy_from_user.S
new file mode 100644
index 0000000..56e448a
--- /dev/null
+++ b/arch/arm64/lib/strncpy_from_user.S
@@ -0,0 +1,50 @@
+/*
+ * Based on arch/arm/lib/strncpy_from_user.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+
+	.text
+	.align	5
+
+/*
+ * Copy a string from user space to kernel space.
+ *  x0 = dst, x1 = src, x2 = byte length
+ * returns the number of characters copied (strlen of copied string),
+ *  -EFAULT on exception, or "len" if we fill the whole buffer
+ */
+ENTRY(__strncpy_from_user)
+	mov	x4, x1
+1:	subs	x2, x2, #1
+	bmi	2f
+USER(9f, ldrb	w3, [x1], #1	)
+	strb	w3, [x0], #1
+	cbnz	w3, 1b
+	sub	x1, x1, #1	// take NUL character out of count
+2:	sub	x0, x1, x4
+	ret
+ENDPROC(__strncpy_from_user)
+
+	.section .fixup,"ax"
+	.align	0
+9:	strb	wzr, [x0]	// null terminate
+	mov	x0, #-EFAULT
+	ret
+	.previous
diff --git a/arch/arm64/lib/strnlen_user.S b/arch/arm64/lib/strnlen_user.S
new file mode 100644
index 0000000..7f7b176
--- /dev/null
+++ b/arch/arm64/lib/strnlen_user.S
@@ -0,0 +1,47 @@
+/*
+ * Based on arch/arm/lib/strnlen_user.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+
+	.text
+	.align	5
+
+/* Prototype: unsigned long __strnlen_user(const char *str, long n)
+ * Purpose  : get length of a string in user memory
+ * Params   : str - address of string in user memory
+ * Returns  : length of string *including terminator*
+ *	      or zero on exception, or n if too long
+ */
+ENTRY(__strnlen_user)
+	mov	x2, x0
+1:	subs	x1, x1, #1
+	b.mi	2f
+USER(9f, ldrb	w3, [x0], #1	)
+	cbnz	w3, 1b
+2:	sub	x0, x0, x2
+	ret
+ENDPROC(__strnlen_user)
+
+	.section .fixup,"ax"
+	.align	0
+9:	mov	x0, #0
+	ret
+	.previous
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
new file mode 100644
index 0000000..3140a2a
--- /dev/null
+++ b/arch/arm64/mm/Makefile
@@ -0,0 +1,4 @@
+obj-y				:= dma-mapping.o extable.o fault.o init.o \
+				   cache.o copypage.o flush.o \
+				   ioremap.o mmap.o pgd.o mmu.o \
+				   context.o tlb.o proc.o
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
new file mode 100644
index 0000000..abe69b8
--- /dev/null
+++ b/arch/arm64/mm/cache.S
@@ -0,0 +1,168 @@
+/*
+ * Cache maintenance
+ *
+ * Copyright (C) 2001 Deep Blue Solutions Ltd.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+#include "proc-macros.S"
+
+/*
+ *	__flush_dcache_all()
+ *
+ *	Flush the whole D-cache.
+ *
+ *	Corrupted registers: x0-x7, x9-x11
+ */
+ENTRY(__flush_dcache_all)
+	dsb	sy				// ensure ordering with previous memory accesses
+	mrs	x0, clidr_el1			// read clidr
+	and	x3, x0, #0x7000000		// extract loc from clidr
+	lsr	x3, x3, #23			// left align loc bit field
+	cbz	x3, finished			// if loc is 0, then no need to clean
+	mov	x10, #0				// start clean at cache level 0
+loop1:
+	add	x2, x10, x10, lsr #1		// work out 3x current cache level
+	lsr	x1, x0, x2			// extract cache type bits from clidr
+	and	x1, x1, #7			// mask of the bits for current cache only
+	cmp	x1, #2				// see what cache we have at this level
+	b.lt	skip				// skip if no cache, or just i-cache
+	save_and_disable_irqs x9		// make CSSELR and CCSIDR access atomic
+	msr	csselr_el1, x10			// select current cache level in csselr
+	isb					// isb to sych the new cssr&csidr
+	mrs	x1, ccsidr_el1			// read the new ccsidr
+	restore_irqs x9
+	and	x2, x1, #7			// extract the length of the cache lines
+	add	x2, x2, #4			// add 4 (line length offset)
+	mov	x4, #0x3ff
+	and	x4, x4, x1, lsr #3		// find maximum number on the way size
+	clz	x5, x4				// find bit position of way size increment
+	mov	x7, #0x7fff
+	and	x7, x7, x1, lsr #13		// extract max number of the index size
+loop2:
+	mov	x9, x4				// create working copy of max way size
+loop3:
+	lsl	x6, x9, x5
+	orr	x11, x10, x6			// factor way and cache number into x11
+	lsl	x6, x7, x2
+	orr	x11, x11, x6			// factor index number into x11
+	dc	cisw, x11			// clean & invalidate by set/way
+	subs	x9, x9, #1			// decrement the way
+	b.ge	loop3
+	subs	x7, x7, #1			// decrement the index
+	b.ge	loop2
+skip:
+	add	x10, x10, #2			// increment cache number
+	cmp	x3, x10
+	b.gt	loop1
+finished:
+	mov	x10, #0				// swith back to cache level 0
+	msr	csselr_el1, x10			// select current cache level in csselr
+	dsb	sy
+	isb
+	ret
+ENDPROC(__flush_dcache_all)
+
+/*
+ *	flush_cache_all()
+ *
+ *	Flush the entire cache system.  The data cache flush is now achieved
+ *	using atomic clean / invalidates working outwards from L1 cache. This
+ *	is done using Set/Way based cache maintainance instructions.  The
+ *	instruction cache can still be invalidated back to the point of
+ *	unification in a single instruction.
+ */
+ENTRY(flush_cache_all)
+	mov	x12, lr
+	bl	__flush_dcache_all
+	mov	x0, #0
+	ic	ialluis				// I+BTB cache invalidate
+	ret	x12
+ENDPROC(flush_cache_all)
+
+/*
+ *	flush_icache_range(start,end)
+ *
+ *	Ensure that the I and D caches are coherent within specified region.
+ *	This is typically used when code has been written to a memory region,
+ *	and will be executed.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(flush_icache_range)
+	/* FALLTHROUGH */
+
+/*
+ *	__flush_cache_user_range(start,end)
+ *
+ *	Ensure that the I and D caches are coherent within specified region.
+ *	This is typically used when code has been written to a memory region,
+ *	and will be executed.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(__flush_cache_user_range)
+	dcache_line_size x2, x3
+	sub	x3, x2, #1
+	bic	x4, x0, x3
+1:
+USER(9f, dc	cvau, x4	)		// clean D line to PoU
+	add	x4, x4, x2
+	cmp	x4, x1
+	b.lo	1b
+	dsb	sy
+
+	icache_line_size x2, x3
+	sub	x3, x2, #1
+	bic	x4, x0, x3
+1:
+USER(9f, ic	ivau, x4	)		// invalidate I line PoU
+	add	x4, x4, x2
+	cmp	x4, x1
+	b.lo	1b
+9:						// ignore any faulting cache operation
+	dsb	sy
+	isb
+	ret
+ENDPROC(flush_icache_range)
+ENDPROC(__flush_cache_user_range)
+
+/*
+ *	__flush_kern_dcache_page(kaddr)
+ *
+ *	Ensure that the data held in the page kaddr is written back to the
+ *	page in question.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__flush_dcache_area)
+	dcache_line_size x2, x3
+	add	x1, x0, x1
+	sub	x3, x2, #1
+	bic	x0, x0, x3
+1:	dc	civac, x0			// clean & invalidate D line / unified line
+	add	x0, x0, x2
+	cmp	x0, x1
+	b.lo	1b
+	dsb	sy
+	ret
+ENDPROC(__flush_dcache_area)
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
new file mode 100644
index 0000000..baa758d
--- /dev/null
+++ b/arch/arm64/mm/context.c
@@ -0,0 +1,159 @@
+/*
+ * Based on arch/arm/mm/context.c
+ *
+ * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/cachetype.h>
+
+#define asid_bits(reg) \
+	(((read_cpuid(ID_AA64MMFR0_EL1) & 0xf0) >> 2) + 8)
+
+#define ASID_FIRST_VERSION	(1 << MAX_ASID_BITS)
+
+static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
+unsigned int cpu_last_asid = ASID_FIRST_VERSION;
+
+/*
+ * We fork()ed a process, and we need a new context for the child to run in.
+ */
+void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	mm->context.id = 0;
+	raw_spin_lock_init(&mm->context.id_lock);
+}
+
+static void flush_context(void)
+{
+	/* set the reserved TTBR0 before flushing the TLB */
+	cpu_set_reserved_ttbr0();
+	flush_tlb_all();
+	if (icache_is_aivivt())
+		__flush_icache_all();
+}
+
+#ifdef CONFIG_SMP
+
+static void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+	unsigned long flags;
+
+	/*
+	 * Locking needed for multi-threaded applications where the same
+	 * mm->context.id could be set from different CPUs during the
+	 * broadcast. This function is also called via IPI so the
+	 * mm->context.id_lock has to be IRQ-safe.
+	 */
+	raw_spin_lock_irqsave(&mm->context.id_lock, flags);
+	if (likely((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS)) {
+		/*
+		 * Old version of ASID found. Set the new one and reset
+		 * mm_cpumask(mm).
+		 */
+		mm->context.id = asid;
+		cpumask_clear(mm_cpumask(mm));
+	}
+	raw_spin_unlock_irqrestore(&mm->context.id_lock, flags);
+
+	/*
+	 * Set the mm_cpumask(mm) bit for the current CPU.
+	 */
+	cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+}
+
+/*
+ * Reset the ASID on the current CPU. This function call is broadcast from the
+ * CPU handling the ASID rollover and holding cpu_asid_lock.
+ */
+static void reset_context(void *info)
+{
+	unsigned int asid;
+	unsigned int cpu = smp_processor_id();
+	struct mm_struct *mm = current->active_mm;
+
+	smp_rmb();
+	asid = cpu_last_asid + cpu;
+
+	flush_context();
+	set_mm_context(mm, asid);
+
+	/* set the new ASID */
+	cpu_switch_mm(mm->pgd, mm);
+}
+
+#else
+
+static inline void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+	mm->context.id = asid;
+	cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id()));
+}
+
+#endif
+
+void __new_context(struct mm_struct *mm)
+{
+	unsigned int asid;
+	unsigned int bits = asid_bits();
+
+	raw_spin_lock(&cpu_asid_lock);
+#ifdef CONFIG_SMP
+	/*
+	 * Check the ASID again, in case the change was broadcast from another
+	 * CPU before we acquired the lock.
+	 */
+	if (!unlikely((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS)) {
+		cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+		raw_spin_unlock(&cpu_asid_lock);
+		return;
+	}
+#endif
+	/*
+	 * At this point, it is guaranteed that the current mm (with an old
+	 * ASID) isn't active on any other CPU since the ASIDs are changed
+	 * simultaneously via IPI.
+	 */
+	asid = ++cpu_last_asid;
+
+	/*
+	 * If we've used up all our ASIDs, we need to start a new version and
+	 * flush the TLB.
+	 */
+	if (unlikely((asid & ((1 << bits) - 1)) == 0)) {
+		/* increment the ASID version */
+		cpu_last_asid += (1 << MAX_ASID_BITS) - (1 << bits);
+		if (cpu_last_asid == 0)
+			cpu_last_asid = ASID_FIRST_VERSION;
+		asid = cpu_last_asid + smp_processor_id();
+		flush_context();
+#ifdef CONFIG_SMP
+		smp_wmb();
+		smp_call_function(reset_context, NULL, 1);
+#endif
+		cpu_last_asid += NR_CPUS - 1;
+	}
+
+	set_mm_context(mm, asid);
+	raw_spin_unlock(&cpu_asid_lock);
+}
diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c
new file mode 100644
index 0000000..9aecbac
--- /dev/null
+++ b/arch/arm64/mm/copypage.c
@@ -0,0 +1,34 @@
+/*
+ * Based on arch/arm/mm/copypage.c
+ *
+ * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+
+void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+{
+	copy_page(kto, kfrom);
+	__flush_dcache_area(kto, PAGE_SIZE);
+}
+
+void __cpu_clear_user_page(void *kaddr, unsigned long vaddr)
+{
+	clear_page(kaddr);
+}
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
new file mode 100644
index 0000000..5eb2444
--- /dev/null
+++ b/arch/arm64/mm/dma-mapping.c
@@ -0,0 +1,79 @@
+/*
+ * SWIOTLB-based DMA API implementation
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/swiotlb.h>
+
+#include <asm/cacheflush.h>
+
+struct dma_map_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
+static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
+					  dma_addr_t *dma_handle, gfp_t flags,
+					  struct dma_attrs *attrs)
+{
+	if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+	    dev->coherent_dma_mask <= DMA_BIT_MASK(32))
+		flags |= GFP_DMA32;
+	return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+}
+
+static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
+					void *vaddr, dma_addr_t dma_handle,
+					struct dma_attrs *attrs)
+{
+	swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+static struct dma_map_ops arm64_swiotlb_dma_ops = {
+	.alloc = arm64_swiotlb_alloc_coherent,
+	.free = arm64_swiotlb_free_coherent,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device,
+	.dma_supported = swiotlb_dma_supported,
+	.mapping_error = swiotlb_dma_mapping_error,
+};
+
+void __init swiotlb_init_with_default_size(size_t default_size, int verbose);
+
+void __init arm64_swiotlb_init(size_t max_size)
+{
+	dma_ops = &arm64_swiotlb_dma_ops;
+	swiotlb_init_with_default_size(min((size_t)SZ_64M, max_size), 1);
+}
+
+#define PREALLOC_DMA_DEBUG_ENTRIES	4096
+
+static int __init dma_debug_do_init(void)
+{
+	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+	return 0;
+}
+fs_initcall(dma_debug_do_init);
diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
new file mode 100644
index 0000000..7944427
--- /dev/null
+++ b/arch/arm64/mm/extable.c
@@ -0,0 +1,17 @@
+/*
+ * Based on arch/arm/mm/extable.c
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *fixup;
+
+	fixup = search_exception_tables(instruction_pointer(regs));
+	if (fixup)
+		regs->pc = fixup->fixup;
+
+	return fixup != NULL;
+}
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
new file mode 100644
index 0000000..1909a69
--- /dev/null
+++ b/arch/arm64/mm/fault.c
@@ -0,0 +1,534 @@
+/*
+ * Based on arch/arm/mm/fault.c
+ *
+ * Copyright (C) 1995  Linus Torvalds
+ * Copyright (C) 1995-2004 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/hardirq.h>
+#include <linux/init.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/page-flags.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/perf_event.h>
+
+#include <asm/exception.h>
+#include <asm/debug-monitors.h>
+#include <asm/system_misc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Dump out the page tables associated with 'addr' in mm 'mm'.
+ */
+void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+
+	if (!mm)
+		mm = &init_mm;
+
+	pr_alert("pgd = %p\n", mm->pgd);
+	pgd = pgd_offset(mm, addr);
+	pr_alert("[%08lx] *pgd=%016llx", addr, pgd_val(*pgd));
+
+	do {
+		pud_t *pud;
+		pmd_t *pmd;
+		pte_t *pte;
+
+		if (pgd_none_or_clear_bad(pgd))
+			break;
+
+		pud = pud_offset(pgd, addr);
+		if (pud_none_or_clear_bad(pud))
+			break;
+
+		pmd = pmd_offset(pud, addr);
+		printk(", *pmd=%016llx", pmd_val(*pmd));
+		if (pmd_none_or_clear_bad(pmd))
+			break;
+
+		pte = pte_offset_map(pmd, addr);
+		printk(", *pte=%016llx", pte_val(*pte));
+		pte_unmap(pte);
+	} while(0);
+
+	printk("\n");
+}
+
+/*
+ * The kernel tried to access some page that wasn't present.
+ */
+static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
+			      unsigned int esr, struct pt_regs *regs)
+{
+	/*
+	 * Are we prepared to handle this kernel fault?
+	 */
+	if (fixup_exception(regs))
+		return;
+
+	/*
+	 * No handler, we'll have to terminate things with extreme prejudice.
+	 */
+	bust_spinlocks(1);
+	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
+		 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+		 "paging request", addr);
+
+	show_pte(mm, addr);
+	die("Oops", regs, esr);
+	bust_spinlocks(0);
+	do_exit(SIGKILL);
+}
+
+/*
+ * Something tried to access memory that isn't in our memory map. User mode
+ * accesses just cause a SIGSEGV
+ */
+static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
+			    unsigned int esr, unsigned int sig, int code,
+			    struct pt_regs *regs)
+{
+	struct siginfo si;
+
+	if (show_unhandled_signals) {
+		pr_info("%s[%d]: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
+			tsk->comm, task_pid_nr(tsk), sig, addr, esr);
+		show_pte(tsk->mm, addr);
+		show_regs(regs);
+	}
+
+	tsk->thread.fault_address = addr;
+	si.si_signo = sig;
+	si.si_errno = 0;
+	si.si_code = code;
+	si.si_addr = (void __user *)addr;
+	force_sig_info(sig, &si, tsk);
+}
+
+void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
+{
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->active_mm;
+
+	/*
+	 * If we are in kernel mode at this point, we have no context to
+	 * handle this fault with.
+	 */
+	if (user_mode(regs))
+		__do_user_fault(tsk, addr, esr, SIGSEGV, SEGV_MAPERR, regs);
+	else
+		__do_kernel_fault(mm, addr, esr, regs);
+}
+
+#define VM_FAULT_BADMAP		0x010000
+#define VM_FAULT_BADACCESS	0x020000
+
+#define ESR_WRITE		(1 << 6)
+#define ESR_LNX_EXEC		(1 << 24)
+
+/*
+ * Check that the permissions on the VMA allow for the fault which occurred.
+ * If we encountered a write fault, we must have write permission, otherwise
+ * we allow any permission.
+ */
+static inline bool access_error(unsigned int esr, struct vm_area_struct *vma)
+{
+	unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+
+	if (esr & ESR_WRITE)
+		mask = VM_WRITE;
+	if (esr & ESR_LNX_EXEC)
+		mask = VM_EXEC;
+
+	return vma->vm_flags & mask ? false : true;
+}
+
+static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
+			   unsigned int esr, unsigned int flags,
+			   struct task_struct *tsk)
+{
+	struct vm_area_struct *vma;
+	int fault;
+
+	vma = find_vma(mm, addr);
+	fault = VM_FAULT_BADMAP;
+	if (unlikely(!vma))
+		goto out;
+	if (unlikely(vma->vm_start > addr))
+		goto check_stack;
+
+	/*
+	 * Ok, we have a good vm_area for this memory access, so we can handle
+	 * it.
+	 */
+good_area:
+	if (access_error(esr, vma)) {
+		fault = VM_FAULT_BADACCESS;
+		goto out;
+	}
+
+	return handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
+
+check_stack:
+	if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
+		goto good_area;
+out:
+	return fault;
+}
+
+static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
+				   struct pt_regs *regs)
+{
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	int fault, sig, code;
+	int write = esr & ESR_WRITE;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+		(write ? FAULT_FLAG_WRITE : 0);
+
+	tsk = current;
+	mm  = tsk->mm;
+
+	/* Enable interrupts if they were enabled in the parent context. */
+	if (interrupts_enabled(regs))
+		local_irq_enable();
+
+	/*
+	 * If we're in an interrupt or have no user context, we must not take
+	 * the fault.
+	 */
+	if (in_atomic() || !mm)
+		goto no_context;
+
+	/*
+	 * As per x86, we may deadlock here. However, since the kernel only
+	 * validly references user space from well defined areas of the code,
+	 * we can bug out early if this is from code which shouldn't.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if (!user_mode(regs) && !search_exception_tables(regs->pc))
+			goto no_context;
+retry:
+		down_read(&mm->mmap_sem);
+	} else {
+		/*
+		 * The above down_read_trylock() might have succeeded in which
+		 * case, we'll have missed the might_sleep() from down_read().
+		 */
+		might_sleep();
+#ifdef CONFIG_DEBUG_VM
+		if (!user_mode(regs) && !search_exception_tables(regs->pc))
+			goto no_context;
+#endif
+	}
+
+	fault = __do_page_fault(mm, addr, esr, flags, tsk);
+
+	/*
+	 * If we need to retry but a fatal signal is pending, handle the
+	 * signal first. We do not need to release the mmap_sem because it
+	 * would already be released in __lock_page_or_retry in mm/filemap.c.
+	 */
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return 0;
+
+	/*
+	 * Major/minor page fault accounting is only done on the initial
+	 * attempt. If we go through a retry, it is extremely likely that the
+	 * page will be found in page cache at that point.
+	 */
+
+	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR) {
+			tsk->maj_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs,
+				      addr);
+		} else {
+			tsk->min_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs,
+				      addr);
+		}
+		if (fault & VM_FAULT_RETRY) {
+			/*
+			 * Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk of
+			 * starvation.
+			 */
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+			goto retry;
+		}
+	}
+
+	up_read(&mm->mmap_sem);
+
+	/*
+	 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
+	 */
+	if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP |
+			      VM_FAULT_BADACCESS))))
+		return 0;
+
+	if (fault & VM_FAULT_OOM) {
+		/*
+		 * We ran out of memory, call the OOM killer, and return to
+		 * userspace (which will retry the fault, or kill us if we got
+		 * oom-killed).
+		 */
+		pagefault_out_of_memory();
+		return 0;
+	}
+
+	/*
+	 * If we are in kernel mode at this point, we have no context to
+	 * handle this fault with.
+	 */
+	if (!user_mode(regs))
+		goto no_context;
+
+	if (fault & VM_FAULT_SIGBUS) {
+		/*
+		 * We had some memory, but were unable to successfully fix up
+		 * this page fault.
+		 */
+		sig = SIGBUS;
+		code = BUS_ADRERR;
+	} else {
+		/*
+		 * Something tried to access memory that isn't in our memory
+		 * map.
+		 */
+		sig = SIGSEGV;
+		code = fault == VM_FAULT_BADACCESS ?
+			SEGV_ACCERR : SEGV_MAPERR;
+	}
+
+	__do_user_fault(tsk, addr, esr, sig, code, regs);
+	return 0;
+
+no_context:
+	__do_kernel_fault(mm, addr, esr, regs);
+	return 0;
+}
+
+/*
+ * First Level Translation Fault Handler
+ *
+ * We enter here because the first level page table doesn't contain a valid
+ * entry for the address.
+ *
+ * If the address is in kernel space (>= TASK_SIZE), then we are probably
+ * faulting in the vmalloc() area.
+ *
+ * If the init_task's first level page tables contains the relevant entry, we
+ * copy the it to this task.  If not, we send the process a signal, fixup the
+ * exception, or oops the kernel.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may be in an interrupt
+ * or a critical region, and should only copy the information from the master
+ * page table, nothing more.
+ */
+static int __kprobes do_translation_fault(unsigned long addr,
+					  unsigned int esr,
+					  struct pt_regs *regs)
+{
+	if (addr < TASK_SIZE)
+		return do_page_fault(addr, esr, regs);
+
+	do_bad_area(addr, esr, regs);
+	return 0;
+}
+
+/*
+ * Some section permission faults need to be handled gracefully.  They can
+ * happen due to a __{get,put}_user during an oops.
+ */
+static int do_sect_fault(unsigned long addr, unsigned int esr,
+			 struct pt_regs *regs)
+{
+	do_bad_area(addr, esr, regs);
+	return 0;
+}
+
+/*
+ * This abort handler always returns "fault".
+ */
+static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
+{
+	return 1;
+}
+
+static struct fault_info {
+	int	(*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
+	int	sig;
+	int	code;
+	const char *name;
+} fault_info[] = {
+	{ do_bad,		SIGBUS,  0,		"ttbr address size fault"	},
+	{ do_bad,		SIGBUS,  0,		"level 1 address size fault"	},
+	{ do_bad,		SIGBUS,  0,		"level 2 address size fault"	},
+	{ do_bad,		SIGBUS,  0,		"level 3 address size fault"	},
+	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"input address range fault"	},
+	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 1 translation fault"	},
+	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 2 translation fault"	},
+	{ do_page_fault,	SIGSEGV, SEGV_MAPERR,	"level 3 translation fault"	},
+	{ do_bad,		SIGBUS,  0,		"reserved access flag fault"	},
+	{ do_bad,		SIGSEGV, SEGV_ACCERR,	"level 1 access flag fault"	},
+	{ do_bad,		SIGSEGV, SEGV_ACCERR,	"level 2 access flag fault"	},
+	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 3 access flag fault"	},
+	{ do_bad,		SIGBUS,  0,		"reserved permission fault"	},
+	{ do_bad,		SIGSEGV, SEGV_ACCERR,	"level 1 permission fault"	},
+	{ do_sect_fault,	SIGSEGV, SEGV_ACCERR,	"level 2 permission fault"	},
+	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 3 permission fault"	},
+	{ do_bad,		SIGBUS,  0,		"synchronous external abort"	},
+	{ do_bad,		SIGBUS,  0,		"asynchronous external abort"	},
+	{ do_bad,		SIGBUS,  0,		"unknown 18"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 19"			},
+	{ do_bad,		SIGBUS,  0,		"synchronous abort (translation table walk)" },
+	{ do_bad,		SIGBUS,  0,		"synchronous abort (translation table walk)" },
+	{ do_bad,		SIGBUS,  0,		"synchronous abort (translation table walk)" },
+	{ do_bad,		SIGBUS,  0,		"synchronous abort (translation table walk)" },
+	{ do_bad,		SIGBUS,  0,		"synchronous parity error"	},
+	{ do_bad,		SIGBUS,  0,		"asynchronous parity error"	},
+	{ do_bad,		SIGBUS,  0,		"unknown 26"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 27"			},
+	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk" },
+	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk" },
+	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk" },
+	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk" },
+	{ do_bad,		SIGBUS,  0,		"unknown 32"			},
+	{ do_bad,		SIGBUS,  BUS_ADRALN,	"alignment fault"		},
+	{ do_bad,		SIGBUS,  0,		"debug event"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 35"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 36"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 37"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 38"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 39"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 40"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 41"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 42"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 43"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 44"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 45"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 46"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 47"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 48"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 49"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 50"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 51"			},
+	{ do_bad,		SIGBUS,  0,		"implementation fault (lockdown abort)" },
+	{ do_bad,		SIGBUS,  0,		"unknown 53"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 54"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 55"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 56"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 57"			},
+	{ do_bad,		SIGBUS,  0,		"implementation fault (coprocessor abort)" },
+	{ do_bad,		SIGBUS,  0,		"unknown 59"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 60"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 61"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 62"			},
+	{ do_bad,		SIGBUS,  0,		"unknown 63"			},
+};
+
+/*
+ * Dispatch a data abort to the relevant handler.
+ */
+asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
+					 struct pt_regs *regs)
+{
+	const struct fault_info *inf = fault_info + (esr & 63);
+	struct siginfo info;
+
+	if (!inf->fn(addr, esr, regs))
+		return;
+
+	pr_alert("Unhandled fault: %s (0x%08x) at 0x%016lx\n",
+		 inf->name, esr, addr);
+
+	info.si_signo = inf->sig;
+	info.si_errno = 0;
+	info.si_code  = inf->code;
+	info.si_addr  = (void __user *)addr;
+	arm64_notify_die("", regs, &info, esr);
+}
+
+/*
+ * Handle stack alignment exceptions.
+ */
+asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
+					   unsigned int esr,
+					   struct pt_regs *regs)
+{
+	struct siginfo info;
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code  = BUS_ADRALN;
+	info.si_addr  = (void __user *)addr;
+	arm64_notify_die("", regs, &info, esr);
+}
+
+static struct fault_info debug_fault_info[] = {
+	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware breakpoint"	},
+	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware single-step"	},
+	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware watchpoint"	},
+	{ do_bad,	SIGBUS,		0,		"unknown 3"		},
+	{ do_bad,	SIGTRAP,	TRAP_BRKPT,	"aarch32 BKPT"		},
+	{ do_bad,	SIGTRAP,	0,		"aarch32 vector catch"	},
+	{ do_bad,	SIGTRAP,	TRAP_BRKPT,	"aarch64 BRK"		},
+	{ do_bad,	SIGBUS,		0,		"unknown 7"		},
+};
+
+void __init hook_debug_fault_code(int nr,
+				  int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+				  int sig, int code, const char *name)
+{
+	BUG_ON(nr < 0 || nr >= ARRAY_SIZE(debug_fault_info));
+
+	debug_fault_info[nr].fn		= fn;
+	debug_fault_info[nr].sig	= sig;
+	debug_fault_info[nr].code	= code;
+	debug_fault_info[nr].name	= name;
+}
+
+asmlinkage int __exception do_debug_exception(unsigned long addr,
+					      unsigned int esr,
+					      struct pt_regs *regs)
+{
+	const struct fault_info *inf = debug_fault_info + DBG_ESR_EVT(esr);
+	struct siginfo info;
+
+	if (!inf->fn(addr, esr, regs))
+		return 1;
+
+	pr_alert("Unhandled debug exception: %s (0x%08x) at 0x%016lx\n",
+		 inf->name, esr, addr);
+
+	info.si_signo = inf->sig;
+	info.si_errno = 0;
+	info.si_code  = inf->code;
+	info.si_addr  = (void __user *)addr;
+	arm64_notify_die("", regs, &info, esr);
+
+	return 0;
+}
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
new file mode 100644
index 0000000..c144adb
--- /dev/null
+++ b/arch/arm64/mm/flush.c
@@ -0,0 +1,135 @@
+/*
+ * Based on arch/arm/mm/flush.c
+ *
+ * Copyright (C) 1995-2002 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cachetype.h>
+#include <asm/tlbflush.h>
+
+#include "mm.h"
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+		       unsigned long end)
+{
+	if (vma->vm_flags & VM_EXEC)
+		__flush_icache_all();
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr,
+		      unsigned long pfn)
+{
+}
+
+static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
+				unsigned long uaddr, void *kaddr,
+				unsigned long len)
+{
+	if (vma->vm_flags & VM_EXEC) {
+		unsigned long addr = (unsigned long)kaddr;
+		if (icache_is_aliasing()) {
+			__flush_dcache_area(kaddr, len);
+			__flush_icache_all();
+		} else {
+			flush_icache_range(addr, addr + len);
+		}
+	}
+}
+
+/*
+ * Copy user data from/to a page which is mapped into a different processes
+ * address space.  Really, we want to allow our "user space" model to handle
+ * this.
+ *
+ * Note that this code needs to run on the current CPU.
+ */
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+		       unsigned long uaddr, void *dst, const void *src,
+		       unsigned long len)
+{
+#ifdef CONFIG_SMP
+	preempt_disable();
+#endif
+	memcpy(dst, src, len);
+	flush_ptrace_access(vma, page, uaddr, dst, len);
+#ifdef CONFIG_SMP
+	preempt_enable();
+#endif
+}
+
+void __flush_dcache_page(struct page *page)
+{
+	__flush_dcache_area(page_address(page), PAGE_SIZE);
+}
+
+void __sync_icache_dcache(pte_t pte, unsigned long addr)
+{
+	unsigned long pfn;
+	struct page *page;
+
+	pfn = pte_pfn(pte);
+	if (!pfn_valid(pfn))
+		return;
+
+	page = pfn_to_page(pfn);
+	if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
+		__flush_dcache_page(page);
+		__flush_icache_all();
+	} else if (icache_is_aivivt()) {
+		__flush_icache_all();
+	}
+}
+
+/*
+ * Ensure cache coherency between kernel mapping and userspace mapping of this
+ * page.
+ */
+void flush_dcache_page(struct page *page)
+{
+	struct address_space *mapping;
+
+	/*
+	 * The zero page is never written to, so never has any dirty cache
+	 * lines, and therefore never needs to be flushed.
+	 */
+	if (page == ZERO_PAGE(0))
+		return;
+
+	mapping = page_mapping(page);
+	if (mapping && mapping_mapped(mapping)) {
+		__flush_dcache_page(page);
+		__flush_icache_all();
+		set_bit(PG_dcache_clean, &page->flags);
+	} else {
+		clear_bit(PG_dcache_clean, &page->flags);
+	}
+}
+EXPORT_SYMBOL(flush_dcache_page);
+
+/*
+ * Additional functions defined in assembly.
+ */
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_icache_range);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
new file mode 100644
index 0000000..5f719ba
--- /dev/null
+++ b/arch/arm64/mm/init.c
@@ -0,0 +1,437 @@
+/*
+ * Based on arch/arm/mm/init.c
+ *
+ * Copyright (C) 1995-2005 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/initrd.h>
+#include <linux/gfp.h>
+#include <linux/memblock.h>
+#include <linux/sort.h>
+#include <linux/of_fdt.h>
+
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/sizes.h>
+#include <asm/tlb.h>
+
+#include "mm.h"
+
+static unsigned long phys_initrd_start __initdata = 0;
+static unsigned long phys_initrd_size __initdata = 0;
+
+phys_addr_t memstart_addr __read_mostly = 0;
+
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+					    unsigned long end)
+{
+	phys_initrd_start = start;
+	phys_initrd_size = end - start;
+}
+
+static int __init early_initrd(char *p)
+{
+	unsigned long start, size;
+	char *endp;
+
+	start = memparse(p, &endp);
+	if (*endp == ',') {
+		size = memparse(endp + 1, NULL);
+
+		phys_initrd_start = start;
+		phys_initrd_size = size;
+	}
+	return 0;
+}
+early_param("initrd", early_initrd);
+
+#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
+
+static void __init zone_sizes_init(unsigned long min, unsigned long max)
+{
+	struct memblock_region *reg;
+	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
+	unsigned long max_dma32 = min;
+
+	memset(zone_size, 0, sizeof(zone_size));
+
+#ifdef CONFIG_ZONE_DMA32
+	/* 4GB maximum for 32-bit only capable devices */
+	max_dma32 = min(max, MAX_DMA32_PFN);
+	zone_size[ZONE_DMA32] = max_dma32 - min;
+#endif
+	zone_size[ZONE_NORMAL] = max - max_dma32;
+
+	memcpy(zhole_size, zone_size, sizeof(zhole_size));
+
+	for_each_memblock(memory, reg) {
+		unsigned long start = memblock_region_memory_base_pfn(reg);
+		unsigned long end = memblock_region_memory_end_pfn(reg);
+
+		if (start >= max)
+			continue;
+#ifdef CONFIG_ZONE_DMA32
+		if (start < max_dma32) {
+			unsigned long dma_end = min(end, max_dma32);
+			zhole_size[ZONE_DMA32] -= dma_end - start;
+		}
+#endif
+		if (end > max_dma32) {
+			unsigned long normal_end = min(end, max);
+			unsigned long normal_start = max(start, max_dma32);
+			zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
+		}
+	}
+
+	free_area_init_node(0, zone_size, min, zhole_size);
+}
+
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
+int pfn_valid(unsigned long pfn)
+{
+	return memblock_is_memory(pfn << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(pfn_valid);
+#endif
+
+#ifndef CONFIG_SPARSEMEM
+static void arm64_memory_present(void)
+{
+}
+#else
+static void arm64_memory_present(void)
+{
+	struct memblock_region *reg;
+
+	for_each_memblock(memory, reg)
+		memory_present(0, memblock_region_memory_base_pfn(reg),
+			       memblock_region_memory_end_pfn(reg));
+}
+#endif
+
+void __init arm64_memblock_init(void)
+{
+	u64 *reserve_map, base, size;
+
+	/* Register the kernel text, kernel data and initrd with memblock */
+	memblock_reserve(__pa(_text), _end - _text);
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (phys_initrd_size) {
+		memblock_reserve(phys_initrd_start, phys_initrd_size);
+
+		/* Now convert initrd to virtual addresses */
+		initrd_start = __phys_to_virt(phys_initrd_start);
+		initrd_end = initrd_start + phys_initrd_size;
+	}
+#endif
+
+	/*
+	 * Reserve the page tables.  These are already in use,
+	 * and can only be in node 0.
+	 */
+	memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
+	memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
+
+	/* Reserve the dtb region */
+	memblock_reserve(virt_to_phys(initial_boot_params),
+			 be32_to_cpu(initial_boot_params->totalsize));
+
+	/*
+	 * Process the reserve map.  This will probably overlap the initrd
+	 * and dtb locations which are already reserved, but overlapping
+	 * doesn't hurt anything
+	 */
+	reserve_map = ((void*)initial_boot_params) +
+			be32_to_cpu(initial_boot_params->off_mem_rsvmap);
+	while (1) {
+		base = be64_to_cpup(reserve_map++);
+		size = be64_to_cpup(reserve_map++);
+		if (!size)
+			break;
+		memblock_reserve(base, size);
+	}
+
+	memblock_allow_resize();
+	memblock_dump_all();
+}
+
+void __init bootmem_init(void)
+{
+	unsigned long min, max;
+
+	min = PFN_UP(memblock_start_of_DRAM());
+	max = PFN_DOWN(memblock_end_of_DRAM());
+
+	/*
+	 * Sparsemem tries to allocate bootmem in memory_present(), so must be
+	 * done after the fixed reservations.
+	 */
+	arm64_memory_present();
+
+	sparse_init();
+	zone_sizes_init(min, max);
+
+	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+	max_pfn = max_low_pfn = max;
+}
+
+static inline int free_area(unsigned long pfn, unsigned long end, char *s)
+{
+	unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
+
+	for (; pfn < end; pfn++) {
+		struct page *page = pfn_to_page(pfn);
+		ClearPageReserved(page);
+		init_page_count(page);
+		__free_page(page);
+		pages++;
+	}
+
+	if (size && s)
+		pr_info("Freeing %s memory: %dK\n", s, size);
+
+	return pages;
+}
+
+/*
+ * Poison init memory with an undefined instruction (0x0).
+ */
+static inline void poison_init_mem(void *s, size_t count)
+{
+	memset(s, 0, count);
+}
+
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
+static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
+{
+	struct page *start_pg, *end_pg;
+	unsigned long pg, pgend;
+
+	/*
+	 * Convert start_pfn/end_pfn to a struct page pointer.
+	 */
+	start_pg = pfn_to_page(start_pfn - 1) + 1;
+	end_pg = pfn_to_page(end_pfn - 1) + 1;
+
+	/*
+	 * Convert to physical addresses, and round start upwards and end
+	 * downwards.
+	 */
+	pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
+	pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
+
+	/*
+	 * If there are free pages between these, free the section of the
+	 * memmap array.
+	 */
+	if (pg < pgend)
+		free_bootmem(pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big. Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap(void)
+{
+	unsigned long start, prev_end = 0;
+	struct memblock_region *reg;
+
+	for_each_memblock(memory, reg) {
+		start = __phys_to_pfn(reg->base);
+
+#ifdef CONFIG_SPARSEMEM
+		/*
+		 * Take care not to free memmap entries that don't exist due
+		 * to SPARSEMEM sections which aren't present.
+		 */
+		start = min(start, ALIGN(prev_end, PAGES_PER_SECTION));
+#endif
+		/*
+		 * If we had a previous bank, and there is a space between the
+		 * current bank and the previous, free it.
+		 */
+		if (prev_end && prev_end < start)
+			free_memmap(prev_end, start);
+
+		/*
+		 * Align up here since the VM subsystem insists that the
+		 * memmap entries are valid from the bank end aligned to
+		 * MAX_ORDER_NR_PAGES.
+		 */
+		prev_end = ALIGN(start + __phys_to_pfn(reg->size),
+				 MAX_ORDER_NR_PAGES);
+	}
+
+#ifdef CONFIG_SPARSEMEM
+	if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
+		free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION));
+#endif
+}
+#endif	/* !CONFIG_SPARSEMEM_VMEMMAP */
+
+/*
+ * mem_init() marks the free areas in the mem_map and tells us how much memory
+ * is free.  This is done after various parts of the system have claimed their
+ * memory after the kernel image.
+ */
+void __init mem_init(void)
+{
+	unsigned long reserved_pages, free_pages;
+	struct memblock_region *reg;
+
+#if CONFIG_SWIOTLB
+	extern void __init arm64_swiotlb_init(size_t max_size);
+	arm64_swiotlb_init(max_pfn << (PAGE_SHIFT - 1));
+#endif
+
+	max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
+
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
+	/* this will put all unused low memory onto the freelists */
+	free_unused_memmap();
+#endif
+
+	totalram_pages += free_all_bootmem();
+
+	reserved_pages = free_pages = 0;
+
+	for_each_memblock(memory, reg) {
+		unsigned int pfn1, pfn2;
+		struct page *page, *end;
+
+		pfn1 = __phys_to_pfn(reg->base);
+		pfn2 = pfn1 + __phys_to_pfn(reg->size);
+
+		page = pfn_to_page(pfn1);
+		end  = pfn_to_page(pfn2 - 1) + 1;
+
+		do {
+			if (PageReserved(page))
+				reserved_pages++;
+			else if (!page_count(page))
+				free_pages++;
+			page++;
+		} while (page < end);
+	}
+
+	/*
+	 * Since our memory may not be contiguous, calculate the real number
+	 * of pages we have in this system.
+	 */
+	pr_info("Memory:");
+	num_physpages = 0;
+	for_each_memblock(memory, reg) {
+		unsigned long pages = memblock_region_memory_end_pfn(reg) -
+			memblock_region_memory_base_pfn(reg);
+		num_physpages += pages;
+		printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
+	}
+	printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
+
+	pr_notice("Memory: %luk/%luk available, %luk reserved\n",
+		  nr_free_pages() << (PAGE_SHIFT-10),
+		  free_pages << (PAGE_SHIFT-10),
+		  reserved_pages << (PAGE_SHIFT-10));
+
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+	pr_notice("Virtual kernel memory layout:\n"
+		  "    vmalloc : 0x%16lx - 0x%16lx   (%6ld MB)\n"
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+		  "    vmemmap : 0x%16lx - 0x%16lx   (%6ld MB)\n"
+#endif
+		  "    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n"
+		  "    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n"
+		  "      .init : 0x%p" " - 0x%p" "   (%6ld kB)\n"
+		  "      .text : 0x%p" " - 0x%p" "   (%6ld kB)\n"
+		  "      .data : 0x%p" " - 0x%p" "   (%6ld kB)\n",
+		  MLM(VMALLOC_START, VMALLOC_END),
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+		  MLM((unsigned long)virt_to_page(PAGE_OFFSET),
+		      (unsigned long)virt_to_page(high_memory)),
+#endif
+		  MLM(MODULES_VADDR, MODULES_END),
+		  MLM(PAGE_OFFSET, (unsigned long)high_memory),
+
+		  MLK_ROUNDUP(__init_begin, __init_end),
+		  MLK_ROUNDUP(_text, _etext),
+		  MLK_ROUNDUP(_sdata, _edata));
+
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
+
+	/*
+	 * Check boundaries twice: Some fundamental inconsistencies can be
+	 * detected at build time already.
+	 */
+#ifdef CONFIG_COMPAT
+	BUILD_BUG_ON(TASK_SIZE_32			> TASK_SIZE_64);
+#endif
+	BUILD_BUG_ON(TASK_SIZE_64			> MODULES_VADDR);
+	BUG_ON(TASK_SIZE_64				> MODULES_VADDR);
+
+	if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+		extern int sysctl_overcommit_memory;
+		/*
+		 * On a machine this small we won't get anywhere without
+		 * overcommit, so turn it on by default.
+		 */
+		sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
+	}
+}
+
+void free_initmem(void)
+{
+	poison_init_mem(__init_begin, __init_end - __init_begin);
+	totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
+				    __phys_to_pfn(__pa(__init_end)),
+				    "init");
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int keep_initrd;
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	if (!keep_initrd) {
+		poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
+		totalram_pages += free_area(__phys_to_pfn(__pa(start)),
+					    __phys_to_pfn(__pa(end)),
+					    "initrd");
+	}
+}
+
+static int __init keepinitrd_setup(char *__unused)
+{
+	keep_initrd = 1;
+	return 1;
+}
+
+__setup("keepinitrd", keepinitrd_setup);
+#endif
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
new file mode 100644
index 0000000..1725cd6
--- /dev/null
+++ b/arch/arm64/mm/ioremap.c
@@ -0,0 +1,84 @@
+/*
+ * Based on arch/arm/mm/ioremap.c
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * Hacked for ARM by Phil Blundell <philb@gnu.org>
+ * Hacked to allow all architectures to build, and various cleanups
+ * by Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+
+static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
+				      pgprot_t prot, void *caller)
+{
+	unsigned long last_addr;
+	unsigned long offset = phys_addr & ~PAGE_MASK;
+	int err;
+	unsigned long addr;
+	struct vm_struct *area;
+
+	/*
+	 * Page align the mapping address and size, taking account of any
+	 * offset.
+	 */
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(size + offset);
+
+	/*
+	 * Don't allow wraparound, zero size or outside PHYS_MASK.
+	 */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK))
+		return NULL;
+
+	/*
+	 * Don't allow RAM to be mapped.
+	 */
+	if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr))))
+		return NULL;
+
+	area = get_vm_area_caller(size, VM_IOREMAP, caller);
+	if (!area)
+		return NULL;
+	addr = (unsigned long)area->addr;
+
+	err = ioremap_page_range(addr, addr + size, phys_addr, prot);
+	if (err) {
+		vunmap((void *)addr);
+		return NULL;
+	}
+
+	return (void __iomem *)(offset + addr);
+}
+
+void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
+{
+	return __ioremap_caller(phys_addr, size, prot,
+				__builtin_return_address(0));
+}
+EXPORT_SYMBOL(__ioremap);
+
+void __iounmap(volatile void __iomem *io_addr)
+{
+	void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
+
+	vunmap(addr);
+}
+EXPORT_SYMBOL(__iounmap);
diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h
new file mode 100644
index 0000000..d8d6e78
--- /dev/null
+++ b/arch/arm64/mm/mm.h
@@ -0,0 +1,2 @@
+extern void __flush_dcache_page(struct page *page);
+extern void __init bootmem_init(void);
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
new file mode 100644
index 0000000..7c7be78
--- /dev/null
+++ b/arch/arm64/mm/mmap.c
@@ -0,0 +1,144 @@
+/*
+ * Based on arch/arm/mm/mmap.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/elf.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/export.h>
+#include <linux/shm.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/personality.h>
+#include <linux/random.h>
+
+#include <asm/cputype.h>
+
+/*
+ * Leave enough space between the mmap area and the stack to honour ulimit in
+ * the face of randomisation.
+ */
+#define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1))
+#define MAX_GAP	(STACK_TOP/6*5)
+
+static int mmap_is_legacy(void)
+{
+	if (current->personality & ADDR_COMPAT_LAYOUT)
+		return 1;
+
+	if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+		return 1;
+
+	return sysctl_legacy_va_layout;
+}
+
+/*
+ * Since get_random_int() returns the same value within a 1 jiffy window, we
+ * will almost always get the same randomisation for the stack and mmap
+ * region. This will mean the relative distance between stack and mmap will be
+ * the same.
+ *
+ * To avoid this we can shift the randomness by 1 bit.
+ */
+static unsigned long mmap_rnd(void)
+{
+	unsigned long rnd = 0;
+
+	if (current->flags & PF_RANDOMIZE)
+		rnd = (long)get_random_int() & (STACK_RND_MASK >> 1);
+
+	return rnd << (PAGE_SHIFT + 1);
+}
+
+static unsigned long mmap_base(void)
+{
+	unsigned long gap = rlimit(RLIMIT_STACK);
+
+	if (gap < MIN_GAP)
+		gap = MIN_GAP;
+	else if (gap > MAX_GAP)
+		gap = MAX_GAP;
+
+	return PAGE_ALIGN(STACK_TOP - gap - mmap_rnd());
+}
+
+/*
+ * This function, called very early during the creation of a new process VM
+ * image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+	/*
+	 * Fall back to the standard layout if the personality bit is set, or
+	 * if the expected stack growth is unlimited:
+	 */
+	if (mmap_is_legacy()) {
+		mm->mmap_base = TASK_UNMAPPED_BASE;
+		mm->get_unmapped_area = arch_get_unmapped_area;
+		mm->unmap_area = arch_unmap_area;
+	} else {
+		mm->mmap_base = mmap_base();
+		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+		mm->unmap_area = arch_unmap_area_topdown;
+	}
+}
+EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
+
+
+/*
+ * You really shouldn't be using read() or write() on /dev/mem.  This might go
+ * away in the future.
+ */
+int valid_phys_addr_range(unsigned long addr, size_t size)
+{
+	if (addr < PHYS_OFFSET)
+		return 0;
+	if (addr + size > __pa(high_memory - 1) + 1)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Do not allow /dev/mem mappings beyond the supported physical range.
+ */
+int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
+{
+	return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
+}
+
+#ifdef CONFIG_STRICT_DEVMEM
+
+#include <linux/ioport.h>
+
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.  We mimic x86 here by
+ * disallowing access to system RAM as well as device-exclusive MMIO regions.
+ * This effectively disable read()/write() on /dev/mem.
+ */
+int devmem_is_allowed(unsigned long pfn)
+{
+	if (iomem_is_exclusive(pfn << PAGE_SHIFT))
+		return 0;
+	if (!page_is_ram(pfn))
+		return 1;
+	return 0;
+}
+
+#endif
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
new file mode 100644
index 0000000..a6885d8
--- /dev/null
+++ b/arch/arm64/mm/mmu.c
@@ -0,0 +1,395 @@
+/*
+ * Based on arch/arm/mm/mmu.c
+ *
+ * Copyright (C) 1995-2005 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/memblock.h>
+#include <linux/fs.h>
+
+#include <asm/cputype.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/sizes.h>
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+
+#include "mm.h"
+
+/*
+ * Empty_zero_page is a special page that is used for zero-initialized data
+ * and COW.
+ */
+struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
+
+pgprot_t pgprot_default;
+EXPORT_SYMBOL(pgprot_default);
+
+static pmdval_t prot_sect_kernel;
+
+struct cachepolicy {
+	const char	policy[16];
+	u64		mair;
+	u64		tcr;
+};
+
+static struct cachepolicy cache_policies[] __initdata = {
+	{
+		.policy		= "uncached",
+		.mair		= 0x44,			/* inner, outer non-cacheable */
+		.tcr		= TCR_IRGN_NC | TCR_ORGN_NC,
+	}, {
+		.policy		= "writethrough",
+		.mair		= 0xaa,			/* inner, outer write-through, read-allocate */
+		.tcr		= TCR_IRGN_WT | TCR_ORGN_WT,
+	}, {
+		.policy		= "writeback",
+		.mair		= 0xee,			/* inner, outer write-back, read-allocate */
+		.tcr		= TCR_IRGN_WBnWA | TCR_ORGN_WBnWA,
+	}
+};
+
+/*
+ * These are useful for identifying cache coherency problems by allowing the
+ * cache or the cache and writebuffer to be turned off. It changes the Normal
+ * memory caching attributes in the MAIR_EL1 register.
+ */
+static int __init early_cachepolicy(char *p)
+{
+	int i;
+	u64 tmp;
+
+	for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
+		int len = strlen(cache_policies[i].policy);
+
+		if (memcmp(p, cache_policies[i].policy, len) == 0)
+			break;
+	}
+	if (i == ARRAY_SIZE(cache_policies)) {
+		pr_err("ERROR: unknown or unsupported cache policy: %s\n", p);
+		return 0;
+	}
+
+	flush_cache_all();
+
+	/*
+	 * Modify MT_NORMAL attributes in MAIR_EL1.
+	 */
+	asm volatile(
+	"	mrs	%0, mair_el1\n"
+	"	bfi	%0, %1, #%2, #8\n"
+	"	msr	mair_el1, %0\n"
+	"	isb\n"
+	: "=&r" (tmp)
+	: "r" (cache_policies[i].mair), "i" (MT_NORMAL * 8));
+
+	/*
+	 * Modify TCR PTW cacheability attributes.
+	 */
+	asm volatile(
+	"	mrs	%0, tcr_el1\n"
+	"	bic	%0, %0, %2\n"
+	"	orr	%0, %0, %1\n"
+	"	msr	tcr_el1, %0\n"
+	"	isb\n"
+	: "=&r" (tmp)
+	: "r" (cache_policies[i].tcr), "r" (TCR_IRGN_MASK | TCR_ORGN_MASK));
+
+	flush_cache_all();
+
+	return 0;
+}
+early_param("cachepolicy", early_cachepolicy);
+
+/*
+ * Adjust the PMD section entries according to the CPU in use.
+ */
+static void __init init_mem_pgprot(void)
+{
+	pteval_t default_pgprot;
+	int i;
+
+	default_pgprot = PTE_ATTRINDX(MT_NORMAL);
+	prot_sect_kernel = PMD_TYPE_SECT | PMD_SECT_AF | PMD_ATTRINDX(MT_NORMAL);
+
+#ifdef CONFIG_SMP
+	/*
+	 * Mark memory with the "shared" attribute for SMP systems
+	 */
+	default_pgprot |= PTE_SHARED;
+	prot_sect_kernel |= PMD_SECT_S;
+#endif
+
+	for (i = 0; i < 16; i++) {
+		unsigned long v = pgprot_val(protection_map[i]);
+		protection_map[i] = __pgprot(v | default_pgprot);
+	}
+
+	pgprot_default = __pgprot(PTE_TYPE_PAGE | PTE_AF | default_pgprot);
+}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+			      unsigned long size, pgprot_t vma_prot)
+{
+	if (!pfn_valid(pfn))
+		return pgprot_noncached(vma_prot);
+	else if (file->f_flags & O_SYNC)
+		return pgprot_writecombine(vma_prot);
+	return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
+
+static void __init *early_alloc(unsigned long sz)
+{
+	void *ptr = __va(memblock_alloc(sz, sz));
+	memset(ptr, 0, sz);
+	return ptr;
+}
+
+static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
+				  unsigned long end, unsigned long pfn)
+{
+	pte_t *pte;
+
+	if (pmd_none(*pmd)) {
+		pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t));
+		__pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE);
+	}
+	BUG_ON(pmd_bad(*pmd));
+
+	pte = pte_offset_kernel(pmd, addr);
+	do {
+		set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+		pfn++;
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+}
+
+static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
+				  unsigned long end, phys_addr_t phys)
+{
+	pmd_t *pmd;
+	unsigned long next;
+
+	/*
+	 * Check for initial section mappings in the pgd/pud and remove them.
+	 */
+	if (pud_none(*pud) || pud_bad(*pud)) {
+		pmd = early_alloc(PTRS_PER_PMD * sizeof(pmd_t));
+		pud_populate(&init_mm, pud, pmd);
+	}
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		/* try section mapping first */
+		if (((addr | next | phys) & ~SECTION_MASK) == 0)
+			set_pmd(pmd, __pmd(phys | prot_sect_kernel));
+		else
+			alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys));
+		phys += next - addr;
+	} while (pmd++, addr = next, addr != end);
+}
+
+static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
+				  unsigned long end, unsigned long phys)
+{
+	pud_t *pud = pud_offset(pgd, addr);
+	unsigned long next;
+
+	do {
+		next = pud_addr_end(addr, end);
+		alloc_init_pmd(pud, addr, next, phys);
+		phys += next - addr;
+	} while (pud++, addr = next, addr != end);
+}
+
+/*
+ * Create the page directory entries and any necessary page tables for the
+ * mapping specified by 'md'.
+ */
+static void __init create_mapping(phys_addr_t phys, unsigned long virt,
+				  phys_addr_t size)
+{
+	unsigned long addr, length, end, next;
+	pgd_t *pgd;
+
+	if (virt < VMALLOC_START) {
+		pr_warning("BUG: not creating mapping for 0x%016llx at 0x%016lx - outside kernel range\n",
+			   phys, virt);
+		return;
+	}
+
+	addr = virt & PAGE_MASK;
+	length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
+
+	pgd = pgd_offset_k(addr);
+	end = addr + length;
+	do {
+		next = pgd_addr_end(addr, end);
+		alloc_init_pud(pgd, addr, next, phys);
+		phys += next - addr;
+	} while (pgd++, addr = next, addr != end);
+}
+
+static void __init map_mem(void)
+{
+	struct memblock_region *reg;
+
+	/* map all the memory banks */
+	for_each_memblock(memory, reg) {
+		phys_addr_t start = reg->base;
+		phys_addr_t end = start + reg->size;
+
+		if (start >= end)
+			break;
+
+		create_mapping(start, __phys_to_virt(start), end - start);
+	}
+}
+
+/*
+ * paging_init() sets up the page tables, initialises the zone memory
+ * maps and sets up the zero page.
+ */
+void __init paging_init(void)
+{
+	void *zero_page;
+
+	/*
+	 * Maximum PGDIR_SIZE addressable via the initial direct kernel
+	 * mapping in swapper_pg_dir.
+	 */
+	memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
+
+	init_mem_pgprot();
+	map_mem();
+
+	/*
+	 * Finally flush the caches and tlb to ensure that we're in a
+	 * consistent state.
+	 */
+	flush_cache_all();
+	flush_tlb_all();
+
+	/* allocate the zero page. */
+	zero_page = early_alloc(PAGE_SIZE);
+
+	bootmem_init();
+
+	empty_zero_page = virt_to_page(zero_page);
+	__flush_dcache_page(empty_zero_page);
+
+	/*
+	 * TTBR0 is only used for the identity mapping at this stage. Make it
+	 * point to zero page to avoid speculatively fetching new entries.
+	 */
+	cpu_set_reserved_ttbr0();
+	flush_tlb_all();
+}
+
+/*
+ * Enable the identity mapping to allow the MMU disabling.
+ */
+void setup_mm_for_reboot(void)
+{
+	cpu_switch_mm(idmap_pg_dir, &init_mm);
+	flush_tlb_all();
+}
+
+/*
+ * Check whether a kernel address is valid (derived from arch/x86/).
+ */
+int kern_addr_valid(unsigned long addr)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	if ((((long)addr) >> VA_BITS) != -1UL)
+		return 0;
+
+	pgd = pgd_offset_k(addr);
+	if (pgd_none(*pgd))
+		return 0;
+
+	pud = pud_offset(pgd, addr);
+	if (pud_none(*pud))
+		return 0;
+
+	pmd = pmd_offset(pud, addr);
+	if (pmd_none(*pmd))
+		return 0;
+
+	pte = pte_offset_kernel(pmd, addr);
+	if (pte_none(*pte))
+		return 0;
+
+	return pfn_valid(pte_pfn(*pte));
+}
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#ifdef CONFIG_ARM64_64K_PAGES
+int __meminit vmemmap_populate(struct page *start_page,
+			       unsigned long size, int node)
+{
+	return vmemmap_populate_basepages(start_page, size, node);
+}
+#else	/* !CONFIG_ARM64_64K_PAGES */
+int __meminit vmemmap_populate(struct page *start_page,
+			       unsigned long size, int node)
+{
+	unsigned long addr = (unsigned long)start_page;
+	unsigned long end = (unsigned long)(start_page + size);
+	unsigned long next;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	do {
+		next = pmd_addr_end(addr, end);
+
+		pgd = vmemmap_pgd_populate(addr, node);
+		if (!pgd)
+			return -ENOMEM;
+
+		pud = vmemmap_pud_populate(pgd, addr, node);
+		if (!pud)
+			return -ENOMEM;
+
+		pmd = pmd_offset(pud, addr);
+		if (pmd_none(*pmd)) {
+			void *p = NULL;
+
+			p = vmemmap_alloc_block_buf(PMD_SIZE, node);
+			if (!p)
+				return -ENOMEM;
+
+			set_pmd(pmd, __pmd(__pa(p) | prot_sect_kernel));
+		} else
+			vmemmap_verify((pte_t *)pmd, node, addr, next);
+	} while (addr = next, addr != end);
+
+	return 0;
+}
+#endif	/* CONFIG_ARM64_64K_PAGES */
+#endif	/* CONFIG_SPARSEMEM_VMEMMAP */
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
new file mode 100644
index 0000000..7083cda
--- /dev/null
+++ b/arch/arm64/mm/pgd.c
@@ -0,0 +1,54 @@
+/*
+ * PGD allocation/freeing
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+
+#include "mm.h"
+
+#define PGD_SIZE	(PTRS_PER_PGD * sizeof(pgd_t))
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	pgd_t *new_pgd;
+
+	if (PGD_SIZE == PAGE_SIZE)
+		new_pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL);
+	else
+		new_pgd = kzalloc(PGD_SIZE, GFP_KERNEL);
+
+	if (!new_pgd)
+		return NULL;
+
+	return new_pgd;
+}
+
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+	if (PGD_SIZE == PAGE_SIZE)
+		free_page((unsigned long)pgd);
+	else
+		kfree(pgd);
+}
diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S
new file mode 100644
index 0000000..8957b82
--- /dev/null
+++ b/arch/arm64/mm/proc-macros.S
@@ -0,0 +1,55 @@
+/*
+ * Based on arch/arm/mm/proc-macros.S
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+
+/*
+ * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
+ */
+	.macro	vma_vm_mm, rd, rn
+	ldr	\rd, [\rn, #VMA_VM_MM]
+	.endm
+
+/*
+ * mmid - get context id from mm pointer (mm->context.id)
+ */
+	.macro	mmid, rd, rn
+	ldr	\rd, [\rn, #MM_CONTEXT_ID]
+	.endm
+
+/*
+ * dcache_line_size - get the minimum D-cache line size from the CTR register.
+ */
+	.macro	dcache_line_size, reg, tmp
+	mrs	\tmp, ctr_el0			// read CTR
+	lsr	\tmp, \tmp, #16
+	and	\tmp, \tmp, #0xf		// cache line size encoding
+	mov	\reg, #4			// bytes per word
+	lsl	\reg, \reg, \tmp		// actual cache line size
+	.endm
+
+/*
+ * icache_line_size - get the minimum I-cache line size from the CTR register.
+ */
+	.macro	icache_line_size, reg, tmp
+	mrs	\tmp, ctr_el0			// read CTR
+	and	\tmp, \tmp, #0xf		// cache line size encoding
+	mov	\reg, #4			// bytes per word
+	lsl	\reg, \reg, \tmp		// actual cache line size
+	.endm
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
new file mode 100644
index 0000000..f1d8b9b
--- /dev/null
+++ b/arch/arm64/mm/proc.S
@@ -0,0 +1,175 @@
+/*
+ * Based on arch/arm/mm/proc.S
+ *
+ * Copyright (C) 2001 Deep Blue Solutions Ltd.
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hwcap.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+
+#include "proc-macros.S"
+
+#ifndef CONFIG_SMP
+/* PTWs cacheable, inner/outer WBWA not shareable */
+#define TCR_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA
+#else
+/* PTWs cacheable, inner/outer WBWA shareable */
+#define TCR_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED
+#endif
+
+#define MAIR(attr, mt)	((attr) << ((mt) * 8))
+
+/*
+ *	cpu_cache_off()
+ *
+ *	Turn the CPU D-cache off.
+ */
+ENTRY(cpu_cache_off)
+	mrs	x0, sctlr_el1
+	bic	x0, x0, #1 << 2			// clear SCTLR.C
+	msr	sctlr_el1, x0
+	isb
+	ret
+ENDPROC(cpu_cache_off)
+
+/*
+ *	cpu_reset(loc)
+ *
+ *	Perform a soft reset of the system.  Put the CPU into the same state
+ *	as it would be if it had been reset, and branch to what would be the
+ *	reset vector. It must be executed with the flat identity mapping.
+ *
+ *	- loc   - location to jump to for soft reset
+ */
+	.align	5
+ENTRY(cpu_reset)
+	mrs	x1, sctlr_el1
+	bic	x1, x1, #1
+	msr	sctlr_el1, x1			// disable the MMU
+	isb
+	ret	x0
+ENDPROC(cpu_reset)
+
+/*
+ *	cpu_do_idle()
+ *
+ *	Idle the processor (wait for interrupt).
+ */
+ENTRY(cpu_do_idle)
+	dsb	sy				// WFI may enter a low-power mode
+	wfi
+	ret
+ENDPROC(cpu_do_idle)
+
+/*
+ *	cpu_switch_mm(pgd_phys, tsk)
+ *
+ *	Set the translation table base pointer to be pgd_phys.
+ *
+ *	- pgd_phys - physical address of new TTB
+ */
+ENTRY(cpu_do_switch_mm)
+	mmid	w1, x1				// get mm->context.id
+	bfi	x0, x1, #48, #16		// set the ASID
+	msr	ttbr0_el1, x0			// set TTBR0
+	isb
+	ret
+ENDPROC(cpu_do_switch_mm)
+
+cpu_name:
+	.ascii	"AArch64 Processor"
+	.align
+
+	.section ".text.init", #alloc, #execinstr
+
+/*
+ *	__cpu_setup
+ *
+ *	Initialise the processor for turning the MMU on.  Return in x0 the
+ *	value of the SCTLR_EL1 register.
+ */
+ENTRY(__cpu_setup)
+	/*
+	 * Preserve the link register across the function call.
+	 */
+	mov	x28, lr
+	bl	__flush_dcache_all
+	mov	lr, x28
+	ic	iallu				// I+BTB cache invalidate
+	dsb	sy
+
+	mov	x0, #3 << 20
+	msr	cpacr_el1, x0			// Enable FP/ASIMD
+	mov	x0, #1
+	msr	oslar_el1, x0			// Set the debug OS lock
+	tlbi	vmalle1is			// invalidate I + D TLBs
+	/*
+	 * Memory region attributes for LPAE:
+	 *
+	 *   n = AttrIndx[2:0]
+	 *			n	MAIR
+	 *   DEVICE_nGnRnE	000	00000000
+	 *   DEVICE_nGnRE	001	00000100
+	 *   DEVICE_GRE		010	00001100
+	 *   NORMAL_NC		011	01000100
+	 *   NORMAL		100	11111111
+	 */
+	ldr	x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \
+		     MAIR(0x04, MT_DEVICE_nGnRE) | \
+		     MAIR(0x0c, MT_DEVICE_GRE) | \
+		     MAIR(0x44, MT_NORMAL_NC) | \
+		     MAIR(0xff, MT_NORMAL)
+	msr	mair_el1, x5
+	/*
+	 * Prepare SCTLR
+	 */
+	adr	x5, crval
+	ldp	w5, w6, [x5]
+	mrs	x0, sctlr_el1
+	bic	x0, x0, x5			// clear bits
+	orr	x0, x0, x6			// set bits
+	/*
+	 * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
+	 * both user and kernel.
+	 */
+	ldr	x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \
+		      TCR_ASID16 | (1 << 31)
+#ifdef CONFIG_ARM64_64K_PAGES
+	orr	x10, x10, TCR_TG0_64K
+	orr	x10, x10, TCR_TG1_64K
+#endif
+	msr	tcr_el1, x10
+	ret					// return to head.S
+ENDPROC(__cpu_setup)
+
+	/*
+	 *                 n n            T
+	 *       U E      WT T UD     US IHBS
+	 *       CE0      XWHW CZ     ME TEEA S
+	 * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM
+	 * 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved
+	 * .... .100 .... 01.1 11.1 ..01 0001 1101 < software settings
+	 */
+	.type	crval, #object
+crval:
+	.word	0x030802e2			// clear
+	.word	0x0405d11d			// set
diff --git a/arch/arm64/mm/tlb.S b/arch/arm64/mm/tlb.S
new file mode 100644
index 0000000..8ae80a1
--- /dev/null
+++ b/arch/arm64/mm/tlb.S
@@ -0,0 +1,71 @@
+/*
+ * Based on arch/arm/mm/tlb.S
+ *
+ * Copyright (C) 1997-2002 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ * Written by Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include "proc-macros.S"
+
+/*
+ *	__cpu_flush_user_tlb_range(start, end, vma)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+ENTRY(__cpu_flush_user_tlb_range)
+	vma_vm_mm x3, x2			// get vma->vm_mm
+	mmid	x3, x3				// get vm_mm->context.id
+	dsb	sy
+	lsr	x0, x0, #12			// align address
+	lsr	x1, x1, #12
+	bfi	x0, x3, #48, #16		// start VA and ASID
+	bfi	x1, x3, #48, #16		// end VA and ASID
+1:	tlbi	vae1is, x0			// TLB invalidate by address and ASID
+	add	x0, x0, #1
+	cmp	x0, x1
+	b.lo	1b
+	dsb	sy
+	ret
+ENDPROC(__cpu_flush_user_tlb_range)
+
+/*
+ *	__cpu_flush_kern_tlb_range(start,end)
+ *
+ *	Invalidate a range of kernel TLB entries.
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ */
+ENTRY(__cpu_flush_kern_tlb_range)
+	dsb	sy
+	lsr	x0, x0, #12			// align address
+	lsr	x1, x1, #12
+1:	tlbi	vaae1is, x0			// TLB invalidate by address
+	add	x0, x0, #1
+	cmp	x0, x1
+	b.lo	1b
+	dsb	sy
+	isb
+	ret
+ENDPROC(__cpu_flush_kern_tlb_range)
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index 3af601e..f08e891 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -2,6 +2,7 @@
 
 generic-y += atomic.h
 generic-y += auxvec.h
+generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += cputime.h
diff --git a/arch/c6x/include/asm/barrier.h b/arch/c6x/include/asm/barrier.h
deleted file mode 100644
index 538240e..0000000
--- a/arch/c6x/include/asm/barrier.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  Port on Texas Instruments TMS320C6x architecture
- *
- *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
- *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-#ifndef _ASM_C6X_BARRIER_H
-#define _ASM_C6X_BARRIER_H
-
-#define nop()                    asm("NOP\n");
-
-#define mb()                     barrier()
-#define rmb()                    barrier()
-#define wmb()                    barrier()
-#define set_mb(var, value)       do { var = value;  mb(); } while (0)
-#define set_wmb(var, value)      do { var = value; wmb(); } while (0)
-
-#define smp_mb()	         barrier()
-#define smp_rmb()	         barrier()
-#define smp_wmb()	         barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-
-#endif /* _ASM_C6X_BARRIER_H */
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 66fd017..7f65be6 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -25,6 +25,7 @@
 #include <linux/elfcore.h>
 #include <linux/mqueue.h>
 #include <linux/reboot.h>
+#include <linux/rcupdate.h>
 
 //#define DEBUG
 
@@ -74,6 +75,7 @@
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched()) {
 			void (*idle)(void);
 			/*
@@ -86,6 +88,7 @@
 				idle = default_idle;
 			idle();
 		}
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index ff95f50..2eb7fa5 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -25,6 +25,7 @@
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
 #include <linux/pagemap.h>
+#include <linux/rcupdate.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/uaccess.h>
@@ -69,12 +70,14 @@
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched()) {
 			check_pgt_cache();
 
 			if (!frv_dma_inprogress && idle)
 				idle();
 		}
+		rcu_idle_exit();
 
 		schedule_preempt_disabled();
 	}
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index d04ed14..71e9bcf 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -330,10 +330,8 @@
 	pci_read_bridge_bases(bus);
 
 	if (bus->number == 0) {
-		struct list_head *ln;
 		struct pci_dev *dev;
-		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-			dev = pci_dev_b(ln);
+		list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (dev->devfn == 0) {
 				dev->resource[0].start = 0;
 				dev->resource[0].end = 0;
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 0e9c315..f153ed1 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -36,6 +36,7 @@
 #include <linux/reboot.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/traps.h>
@@ -78,8 +79,10 @@
 void cpu_idle(void)
 {
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched())
 			idle();
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 310cf57..3c720ef 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -25,6 +25,7 @@
 	select HAVE_GENERIC_HARDIRQS
 	select HAVE_MEMBLOCK
 	select HAVE_MEMBLOCK_NODE_MAP
+	select HAVE_VIRT_CPU_ACCOUNTING
 	select ARCH_DISCARD_MEMBLOCK
 	select GENERIC_IRQ_PROBE
 	select GENERIC_PENDING_IRQ if SMP
@@ -340,17 +341,6 @@
 	default "17" if HUGETLB_PAGE
 	default "11"
 
-config VIRT_CPU_ACCOUNTING
-	bool "Deterministic task and CPU time accounting"
-	default n
-	help
-	  Select this option to enable more accurate task and CPU time
-	  accounting.  This is done by reading a CPU counter on each
-	  kernel entry and exit and on transitions within the kernel
-	  between system, softirq and hardirq state, so there is a
-	  small performance impact.
-	  If in doubt, say N here.
-
 config SMP
 	bool "Symmetric multi-processing support"
 	select USE_GENERIC_SMP_HELPERS
diff --git a/arch/ia64/include/asm/numa.h b/arch/ia64/include/asm/numa.h
index 6a8a27c..2e27ef1 100644
--- a/arch/ia64/include/asm/numa.h
+++ b/arch/ia64/include/asm/numa.h
@@ -59,7 +59,7 @@
  */
 
 extern u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];
-#define node_distance(from,to) (numa_slit[(from) * num_online_nodes() + (to)])
+#define node_distance(from,to) (numa_slit[(from) * MAX_NUMNODES + (to)])
 
 extern int paddr_to_nid(unsigned long paddr);
 
diff --git a/arch/ia64/include/asm/switch_to.h b/arch/ia64/include/asm/switch_to.h
index cb2412f..d38c7ea 100644
--- a/arch/ia64/include/asm/switch_to.h
+++ b/arch/ia64/include/asm/switch_to.h
@@ -30,13 +30,6 @@
 extern void ia64_save_extra (struct task_struct *task);
 extern void ia64_load_extra (struct task_struct *task);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct *next);
-# define IA64_ACCOUNT_ON_SWITCH(p,n) ia64_account_on_switch(p,n)
-#else
-# define IA64_ACCOUNT_ON_SWITCH(p,n)
-#endif
-
 #ifdef CONFIG_PERFMON
   DECLARE_PER_CPU(unsigned long, pfm_syst_info);
 # define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1)
@@ -49,7 +42,6 @@
 	 || PERFMON_IS_SYSWIDE())
 
 #define __switch_to(prev,next,last) do {							 \
-	IA64_ACCOUNT_ON_SWITCH(prev, next);							 \
 	if (IA64_HAS_EXTRA_STATE(prev))								 \
 		ia64_save_extra(prev);								 \
 	if (IA64_HAS_EXTRA_STATE(next))								 \
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index 070e8ef..5151a64 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -85,12 +85,13 @@
 	struct kimage *image = arg;
 	relocate_new_kernel_t rnk;
 	void *pal_addr = efi_get_pal_addr();
-	unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
+	unsigned long code_addr;
 	int ii;
 	u64 fp, gp;
 	ia64_fptr_t *init_handler = (ia64_fptr_t *)ia64_os_init_on_kdump;
 
 	BUG_ON(!image);
+	code_addr = (unsigned long)page_address(image->control_code_page);
 	if (image->type == KEXEC_TYPE_CRASH) {
 		crash_save_this_cpu();
 		current->thread.ksp = (__u64)info->sw - 16;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index dd6fc14..ee31fe9 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -29,6 +29,7 @@
 #include <linux/kdebug.h>
 #include <linux/utsname.h>
 #include <linux/tracehook.h>
+#include <linux/rcupdate.h>
 
 #include <asm/cpu.h>
 #include <asm/delay.h>
@@ -196,8 +197,8 @@
 		ia64_do_signal(scr, in_syscall);
 	}
 
-	if (test_thread_flag(TIF_NOTIFY_RESUME)) {
-		clear_thread_flag(TIF_NOTIFY_RESUME);
+	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+		local_irq_enable();	/* force interrupt enable */
 		tracehook_notify_resume(&scr->pt);
 	}
 
@@ -279,6 +280,7 @@
 
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		if (can_do_pal_halt) {
 			current_thread_info()->status &= ~TS_POLLING;
 			/*
@@ -309,6 +311,7 @@
 			normal_xtp();
 #endif
 		}
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 		check_pgt_cache();
 		if (cpu_is_offline(cpu))
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index ecc904b..80ff9ac 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -83,32 +83,36 @@
 
 extern cputime_t cycle_to_cputime(u64 cyc);
 
+static void vtime_account_user(struct task_struct *tsk)
+{
+	cputime_t delta_utime;
+	struct thread_info *ti = task_thread_info(tsk);
+
+	if (ti->ac_utime) {
+		delta_utime = cycle_to_cputime(ti->ac_utime);
+		account_user_time(tsk, delta_utime, delta_utime);
+		ti->ac_utime = 0;
+	}
+}
+
 /*
  * Called from the context switch with interrupts disabled, to charge all
  * accumulated times to the current process, and to prepare accounting on
  * the next process.
  */
-void ia64_account_on_switch(struct task_struct *prev, struct task_struct *next)
+void vtime_task_switch(struct task_struct *prev)
 {
 	struct thread_info *pi = task_thread_info(prev);
-	struct thread_info *ni = task_thread_info(next);
-	cputime_t delta_stime, delta_utime;
-	__u64 now;
+	struct thread_info *ni = task_thread_info(current);
 
-	now = ia64_get_itc();
-
-	delta_stime = cycle_to_cputime(pi->ac_stime + (now - pi->ac_stamp));
 	if (idle_task(smp_processor_id()) != prev)
-		account_system_time(prev, 0, delta_stime, delta_stime);
+		vtime_account_system(prev);
 	else
-		account_idle_time(delta_stime);
+		vtime_account_idle(prev);
 
-	if (pi->ac_utime) {
-		delta_utime = cycle_to_cputime(pi->ac_utime);
-		account_user_time(prev, delta_utime, delta_utime);
-	}
+	vtime_account_user(prev);
 
-	pi->ac_stamp = ni->ac_stamp = now;
+	pi->ac_stamp = ni->ac_stamp;
 	ni->ac_stime = ni->ac_utime = 0;
 }
 
@@ -116,29 +120,32 @@
  * Account time for a transition between system, hard irq or soft irq state.
  * Note that this function is called with interrupts enabled.
  */
-void account_system_vtime(struct task_struct *tsk)
+static cputime_t vtime_delta(struct task_struct *tsk)
 {
 	struct thread_info *ti = task_thread_info(tsk);
-	unsigned long flags;
 	cputime_t delta_stime;
 	__u64 now;
 
-	local_irq_save(flags);
-
 	now = ia64_get_itc();
 
 	delta_stime = cycle_to_cputime(ti->ac_stime + (now - ti->ac_stamp));
-	if (irq_count() || idle_task(smp_processor_id()) != tsk)
-		account_system_time(tsk, 0, delta_stime, delta_stime);
-	else
-		account_idle_time(delta_stime);
 	ti->ac_stime = 0;
-
 	ti->ac_stamp = now;
 
-	local_irq_restore(flags);
+	return delta_stime;
 }
-EXPORT_SYMBOL_GPL(account_system_vtime);
+
+void vtime_account_system(struct task_struct *tsk)
+{
+	cputime_t delta = vtime_delta(tsk);
+
+	account_system_time(tsk, 0, delta, delta);
+}
+
+void vtime_account_idle(struct task_struct *tsk)
+{
+	account_idle_time(vtime_delta(tsk));
+}
 
 /*
  * Called from the timer interrupt handler to charge accumulated user time
@@ -146,14 +153,7 @@
  */
 void account_process_tick(struct task_struct *p, int user_tick)
 {
-	struct thread_info *ti = task_thread_info(p);
-	cputime_t delta_utime;
-
-	if (ti->ac_utime) {
-		delta_utime = cycle_to_cputime(ti->ac_utime);
-		account_user_time(p, delta_utime, delta_utime);
-		ti->ac_utime = 0;
-	}
+	vtime_account_user(p);
 }
 
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING */
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 81acc7a..5faa66c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -295,7 +295,6 @@
 	window->resource.flags = flags;
 	window->resource.start = addr.minimum + offset;
 	window->resource.end = window->resource.start + addr.address_length - 1;
-	window->resource.child = NULL;
 	window->offset = offset;
 
 	if (insert_resource(root, &window->resource)) {
@@ -357,7 +356,7 @@
 			&windows);
 	if (windows) {
 		controller->window =
-			kmalloc_node(sizeof(*controller->window) * windows,
+			kzalloc_node(sizeof(*controller->window) * windows,
 				     GFP_KERNEL, controller->node);
 		if (!controller->window)
 			goto out2;
@@ -461,14 +460,6 @@
 	/* No special bus mastering setup handling */
 }
 
-void __devinit
-pcibios_update_irq (struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-
-	/* ??? FIXME -- record old value for shutdown.  */
-}
-
 int
 pcibios_enable_device (struct pci_dev *dev, int mask)
 {
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
index fbb5f2f..8630875 100644
--- a/arch/ia64/sn/kernel/io_common.c
+++ b/arch/ia64/sn/kernel/io_common.c
@@ -229,7 +229,6 @@
 {
 	int segment = pci_domain_nr(dev->bus);
 	struct pcibus_bussoft *bs;
-	struct pci_bus *host_pci_bus;
 	struct pci_dev *host_pci_dev;
 	unsigned int bus_no, devfn;
 
@@ -245,8 +244,7 @@
 
 	bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
 	devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
- 	host_pci_bus = pci_find_bus(segment, bus_no);
- 	host_pci_dev = pci_get_slot(host_pci_bus, devfn);
+	host_pci_dev = pci_get_domain_bus_and_slot(segment, bus_no, devfn);
 
 	pcidev_info->host_pci_dev = host_pci_dev;
 	pcidev_info->pdi_linux_pcidev = dev;
diff --git a/arch/ia64/xen/xencomm.c b/arch/ia64/xen/xencomm.c
index 1f5d7ac..73d903c 100644
--- a/arch/ia64/xen/xencomm.c
+++ b/arch/ia64/xen/xencomm.c
@@ -17,6 +17,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/err.h>
 
 static unsigned long kernel_virtual_offset;
 static int is_xencomm_initialized;
@@ -98,7 +99,7 @@
 
 	/* We assume the page is modified.  */
 	page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
-	if (!page)
+	if (IS_ERR_OR_NULL(page))
 		return ~0UL;
 
 	return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 3a4a32b..384e63f 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -26,6 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/hardirq.h>
+#include <linux/rcupdate.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -82,6 +83,7 @@
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched()) {
 			void (*idle)(void) = pm_idle;
 
@@ -90,6 +92,7 @@
 
 			idle();
 		}
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c
index 80076d3..6083088 100644
--- a/arch/m68k/amiga/platform.c
+++ b/arch/m68k/amiga/platform.c
@@ -56,10 +56,7 @@
 	n = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2;
 	pdev = platform_device_register_simple("amiga-zorro", -1,
 					       zorro_resources, n);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 
 subsys_initcall(amiga_init_bus);
diff --git a/arch/m68k/include/asm/apollohw.h b/arch/m68k/include/asm/apollohw.h
index 635ef4f..6c19e0c 100644
--- a/arch/m68k/include/asm/apollohw.h
+++ b/arch/m68k/include/asm/apollohw.h
@@ -46,18 +46,6 @@
 
 };
 
-#if 0
-struct mc146818 {
-
-	unsigned int second1:4, second2:4, alarm_second1:4, alarm_second2:4,
-		     minute1:4, minute2:4, alarm_minute1:4, alarm_minute2:4;
-	unsigned int hours1:4, hours2:4, alarm_hours1:4, alarm_hours2:4,
-		     day_of_week1:4, day_of_week2:4, day_of_month1:4, day_of_month2:4;
-	unsigned int month1:4, month2:4, year1:4, year2:4, :16;
-
-};
-#endif
-
 struct mc146818 {
         unsigned char second, alarm_second;
         unsigned char minute, alarm_minute;
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index b2988aa..73fa0b56 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -87,11 +87,6 @@
 	return 0;
 }
 
-void pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index c488e3c..ac2892e 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -25,6 +25,7 @@
 #include <linux/reboot.h>
 #include <linux/init_task.h>
 #include <linux/mqueue.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/traps.h>
@@ -75,8 +76,10 @@
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched())
 			idle();
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 707f057..5d0bcaa 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -100,10 +100,7 @@
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 
 module_init(rtc_init);
diff --git a/arch/m68k/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c
index 75f9ee9..9cd13b4 100644
--- a/arch/m68k/platform/coldfire/clk.c
+++ b/arch/m68k/platform/coldfire/clk.c
@@ -146,9 +146,3 @@
 };
 #endif /* MCFPM_PPMCR1 */
 #endif /* MCFPM_PPMCR0 */
-
-struct clk *devm_clk_get(struct device *dev, const char *id)
-{
-	return NULL;
-}
-EXPORT_SYMBOL(devm_clk_get);
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 8a1ce32..1adb5b7 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -338,9 +338,6 @@
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 arch_initcall(q40_add_kbd_device);
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
index e7e03ec..afc379c 100644
--- a/arch/mips/kernel/smp-cmp.c
+++ b/arch/mips/kernel/smp-cmp.c
@@ -102,7 +102,7 @@
 	c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
 #endif
 #ifdef CONFIG_MIPS_MT_SMTC
-	c->tc_id  = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
+	c->tc_id  = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
 #endif
 }
 
diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
index 33aadbc..dcfd573 100644
--- a/arch/mips/mm/gup.c
+++ b/arch/mips/mm/gup.c
@@ -152,6 +152,8 @@
 	do {
 		VM_BUG_ON(compound_head(page) != head);
 		pages[*nr] = page;
+		if (PageTail(page))
+			get_huge_page_tail(page);
 		(*nr)++;
 		page++;
 		refs++;
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 7b13a4ca..fea823f 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -273,16 +273,19 @@
 	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
 	int irq;
 
+	if (unlikely(!pending)) {
+		spurious_interrupt();
+		return;
+	}
+
 	irq = irq_ffs(pending);
 
 	if (irq == MIPSCPU_INT_I8259A)
 		malta_hw0_irqdispatch();
 	else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
 		malta_ipi_irqdispatch();
-	else if (irq >= 0)
-		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
 	else
-		spurious_interrupt();
+		do_IRQ(MIPS_CPU_IRQ_BASE + irq);
 }
 
 #ifdef CONFIG_MIPS_MT_SMP
diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c
index 4c353017..80562b8 100644
--- a/arch/mips/mti-malta/malta-platform.c
+++ b/arch/mips/mti-malta/malta-platform.c
@@ -138,11 +138,6 @@
 	if (err)
 		return err;
 
-	/*
-	 * Set RTC to BCD mode to support current alarm code.
-	 */
-	CMOS_WRITE(CMOS_READ(RTC_CONTROL) & ~RTC_DM_BINARY, RTC_CONTROL);
-
 	return 0;
 }
 
diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c
index 52a1ba7..c5dfb2c 100644
--- a/arch/mips/pci/pci-octeon.c
+++ b/arch/mips/pci/pci-octeon.c
@@ -117,16 +117,11 @@
 	}
 
 	/* Enable the PCIe normal error reporting */
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (pos) {
-		/* Update Device Control */
-		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
-		config |= PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */
-		config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */
-		config |= PCI_EXP_DEVCTL_FERE;  /* Fatal Error Reporting */
-		config |= PCI_EXP_DEVCTL_URRE;  /* Unsupported Request */
-		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
-	}
+	config = PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */
+	config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */
+	config |= PCI_EXP_DEVCTL_FERE;  /* Fatal Error Reporting */
+	config |= PCI_EXP_DEVCTL_URRE;  /* Unsupported Request */
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, config);
 
 	/* Find the Advanced Error Reporting capability */
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 6903568..04e35bc 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -313,12 +313,6 @@
 	}
 }
 
-void __init
-pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 #ifdef CONFIG_HOTPLUG
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 7dab0cd..e9cceba 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -107,6 +108,7 @@
 {
 	/* endless idle loop with no priority at all */
 	for (;;) {
+		rcu_idle_enter();
 		while (!need_resched()) {
 			void (*idle)(void);
 
@@ -121,6 +123,7 @@
 			}
 			idle();
 		}
+		rcu_idle_exit();
 
 		schedule_preempt_disabled();
 	}
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 2c05a929..8c6b6b6 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -48,6 +48,7 @@
 #include <linux/unistd.h>
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
+#include <linux/rcupdate.h>
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
@@ -69,8 +70,10 @@
 
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched())
 			barrier();
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 		check_pgt_cache();
 	}
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 1c1aadc..c32ae5c 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -1,10 +1,6 @@
 addnote
 empty.c
 hack-coff
-infblock.c
-infblock.h
-infcodes.c
-infcodes.h
 inffast.c
 inffast.h
 inffixed.h
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 42ce570..f7706d7 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -214,6 +214,9 @@
 	/* Called after scan and before resource survey */
 	void (*pcibios_fixup_phb)(struct pci_controller *hose);
 
+	/* Called during PCI resource reassignment */
+	resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type);
+
 	/* Called to shutdown machine specific hardware not already controlled
 	 * by other drivers.
 	 */
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 3b4b4a8..c1f2676 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -197,12 +197,6 @@
 
 DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
 
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING)
-#define account_process_vtime(tsk)		account_process_tick(tsk, 0)
-#else
-#define account_process_vtime(tsk)		do { } while (0)
-#endif
-
 extern void secondary_cpu_time_init(void);
 
 DECLARE_PER_CPU(u64, decrementers_next_tb);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 2aa04f2..43fea54 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -99,6 +99,26 @@
 		kfree(phb);
 }
 
+/*
+ * The function is used to return the minimal alignment
+ * for memory or I/O windows of the associated P2P bridge.
+ * By default, 4KiB alignment for I/O windows and 1MiB for
+ * memory windows.
+ */
+resource_size_t pcibios_window_alignment(struct pci_bus *bus,
+					 unsigned long type)
+{
+	if (ppc_md.pcibios_window_alignment)
+		return ppc_md.pcibios_window_alignment(bus, type);
+
+	/*
+	 * PCI core will figure out the default
+	 * alignment: 4KiB for I/O and 1MiB for
+	 * memory window.
+	 */
+	return 1;
+}
+
 static resource_size_t pcibios_io_size(const struct pci_controller *hose)
 {
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1a1f2dd..e9cb51f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -514,9 +514,6 @@
 
 	local_irq_save(flags);
 
-	account_system_vtime(current);
-	account_process_vtime(current);
-
 	/*
 	 * We can't take a PMU exception inside _switch() since there is a
 	 * window where the kernel stack SLB and the kernel stack are out
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index e49e931..eaa9d0e 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -291,13 +291,12 @@
  * Account time for a transition between system, hard irq
  * or soft irq state.
  */
-void account_system_vtime(struct task_struct *tsk)
+static u64 vtime_delta(struct task_struct *tsk,
+			u64 *sys_scaled, u64 *stolen)
 {
-	u64 now, nowscaled, delta, deltascaled;
-	unsigned long flags;
-	u64 stolen, udelta, sys_scaled, user_scaled;
+	u64 now, nowscaled, deltascaled;
+	u64 udelta, delta, user_scaled;
 
-	local_irq_save(flags);
 	now = mftb();
 	nowscaled = read_spurr(now);
 	get_paca()->system_time += now - get_paca()->starttime;
@@ -305,7 +304,7 @@
 	deltascaled = nowscaled - get_paca()->startspurr;
 	get_paca()->startspurr = nowscaled;
 
-	stolen = calculate_stolen_time(now);
+	*stolen = calculate_stolen_time(now);
 
 	delta = get_paca()->system_time;
 	get_paca()->system_time = 0;
@@ -322,35 +321,45 @@
 	 * the user ticks get saved up in paca->user_time_scaled to be
 	 * used by account_process_tick.
 	 */
-	sys_scaled = delta;
+	*sys_scaled = delta;
 	user_scaled = udelta;
 	if (deltascaled != delta + udelta) {
 		if (udelta) {
-			sys_scaled = deltascaled * delta / (delta + udelta);
-			user_scaled = deltascaled - sys_scaled;
+			*sys_scaled = deltascaled * delta / (delta + udelta);
+			user_scaled = deltascaled - *sys_scaled;
 		} else {
-			sys_scaled = deltascaled;
+			*sys_scaled = deltascaled;
 		}
 	}
 	get_paca()->user_time_scaled += user_scaled;
 
-	if (in_interrupt() || idle_task(smp_processor_id()) != tsk) {
-		account_system_time(tsk, 0, delta, sys_scaled);
-		if (stolen)
-			account_steal_time(stolen);
-	} else {
-		account_idle_time(delta + stolen);
-	}
-	local_irq_restore(flags);
+	return delta;
 }
-EXPORT_SYMBOL_GPL(account_system_vtime);
+
+void vtime_account_system(struct task_struct *tsk)
+{
+	u64 delta, sys_scaled, stolen;
+
+	delta = vtime_delta(tsk, &sys_scaled, &stolen);
+	account_system_time(tsk, 0, delta, sys_scaled);
+	if (stolen)
+		account_steal_time(stolen);
+}
+
+void vtime_account_idle(struct task_struct *tsk)
+{
+	u64 delta, sys_scaled, stolen;
+
+	delta = vtime_delta(tsk, &sys_scaled, &stolen);
+	account_idle_time(delta + stolen);
+}
 
 /*
  * Transfer the user and system times accumulated in the paca
  * by the exception entry and exit code to the generic process
  * user and system time records.
  * Must be called with interrupts disabled.
- * Assumes that account_system_vtime() has been called recently
+ * Assumes that vtime_account() has been called recently
  * (i.e. since the last entry from usermode) so that
  * get_paca()->user_time_scaled is up to date.
  */
@@ -366,6 +375,12 @@
 	account_user_time(tsk, utime, utimescaled);
 }
 
+void vtime_task_switch(struct task_struct *prev)
+{
+	vtime_account(prev);
+	account_process_tick(prev, 0);
+}
+
 #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
 #define calc_cputime_factors()
 #endif
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index 1a04671..1d769a2 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -326,7 +326,7 @@
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
 	struct resource res;
-	struct pmc_type *type;
+	const struct pmc_type *type;
 	int ret = 0;
 
 	match = of_match_device(pmc_match, &ofdev->dev);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 30fd01d..72afd28 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -1,6 +1,7 @@
 config PPC64
 	bool "64-bit kernel"
 	default n
+	select HAVE_VIRT_CPU_ACCOUNTING
 	help
 	  This option selects whether a 32-bit or a 64-bit kernel
 	  will be built.
@@ -337,21 +338,6 @@
 	default y if (!PPC_FSL_BOOK3E && PPC64 && HUGETLB_PAGE) || (PPC_STD_MMU_64 && PPC_64K_PAGES)
 	default n
 
-config VIRT_CPU_ACCOUNTING
-	bool "Deterministic task and CPU time accounting"
-	depends on PPC64
-	default y
-	help
-	  Select this option to enable more accurate task and CPU time
-	  accounting.  This is done by reading a CPU counter on each
-	  kernel entry and exit and on transitions within the kernel
-	  between system, softirq and hardirq state, so there is a
-	  small performance impact.  This also enables accounting of
-	  stolen time on logically-partitioned systems running on
-	  IBM POWER5-based machines.
-
-	  If in doubt, say Y here.
-
 config PPC_HAVE_PMU_SUPPORT
        bool
 
diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 5822141..abc8af4 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -472,7 +472,7 @@
 {
 	struct device_node *dev = phb->dn;
 	const struct of_device_id *match;
-	struct celleb_phb_spec *phb_spec;
+	const struct celleb_phb_spec *phb_spec;
 	int rc;
 
 	match = of_match_node(celleb_phb_match, dev);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 9cda6a1..0e7eccc 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -855,7 +855,7 @@
 		if (pe == NULL)
 			continue;
 		/* Leaving the PCIe domain ... single PE# */
-		if (dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
+		if (pci_pcie_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE)
 			pnv_ioda_setup_bus_PE(dev, pe);
 		else if (dev->subordinate)
 			pnv_ioda_setup_PEs(dev->subordinate);
@@ -1139,6 +1139,44 @@
 	}
 }
 
+/*
+ * Returns the alignment for I/O or memory windows for P2P
+ * bridges. That actually depends on how PEs are segmented.
+ * For now, we return I/O or M32 segment size for PE sensitive
+ * P2P bridges. Otherwise, the default values (4KiB for I/O,
+ * 1MiB for memory) will be returned.
+ *
+ * The current PCI bus might be put into one PE, which was
+ * create against the parent PCI bridge. For that case, we
+ * needn't enlarge the alignment so that we can save some
+ * resources.
+ */
+static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
+						unsigned long type)
+{
+	struct pci_dev *bridge;
+	struct pci_controller *hose = pci_bus_to_host(bus);
+	struct pnv_phb *phb = hose->private_data;
+	int num_pci_bridges = 0;
+
+	bridge = bus->self;
+	while (bridge) {
+		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE) {
+			num_pci_bridges++;
+			if (num_pci_bridges >= 2)
+				return 1;
+		}
+
+		bridge = bridge->bus->self;
+	}
+
+	/* We need support prefetchable memory window later */
+	if (type & IORESOURCE_MEM)
+		return phb->ioda.m32_segsize;
+
+	return phb->ioda.io_segsize;
+}
+
 /* Prevent enabling devices for which we couldn't properly
  * assign a PE
  */
@@ -1306,6 +1344,7 @@
 	 */
 	ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
 	ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
+	ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
 	pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
 
 	/* Reset IODA tables to a clean state */
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 6e097de..51ffafa 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -368,7 +368,7 @@
 	int err, i, j, irq_index, count;
 	int rc;
 	const u32 *p;
-	struct fsl_msi_feature *features;
+	const struct fsl_msi_feature *features;
 	int len;
 	u32 offset;
 	static const u32 all_avail[] = { 0, NR_MSI_IRQS };
@@ -502,15 +502,15 @@
 static const struct of_device_id fsl_of_msi_ids[] = {
 	{
 		.compatible = "fsl,mpic-msi",
-		.data = (void *)&mpic_msi_feature,
+		.data = &mpic_msi_feature,
 	},
 	{
 		.compatible = "fsl,ipic-msi",
-		.data = (void *)&ipic_msi_feature,
+		.data = &ipic_msi_feature,
 	},
 	{
 		.compatible = "fsl,vmpic-msi",
-		.data = (void *)&vmpic_msi_feature,
+		.data = &vmpic_msi_feature,
 	},
 	{}
 };
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild
index 9858476..cc45d25 100644
--- a/arch/s390/Kbuild
+++ b/arch/s390/Kbuild
@@ -5,3 +5,4 @@
 obj-$(CONFIG_S390_HYPFS_FS)	+= hypfs/
 obj-$(CONFIG_APPLDATA_BASE)	+= appldata/
 obj-$(CONFIG_MATHEMU)		+= math-emu/
+obj-y				+= net/
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 107610e..f9acddd 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -49,10 +49,13 @@
 config PGSTE
 	def_bool y if KVM
 
-config VIRT_CPU_ACCOUNTING
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 	def_bool y
 
-config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+config KEXEC
+	def_bool y
+
+config AUDIT_ARCH
 	def_bool y
 
 config S390
@@ -84,11 +87,15 @@
 	select HAVE_KERNEL_XZ
 	select HAVE_ARCH_MUTEX_CPU_RELAX
 	select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
+	select HAVE_BPF_JIT if 64BIT && PACK_STACK
 	select ARCH_SAVE_PAGE_KEYS if HIBERNATION
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select HAVE_MEMBLOCK
 	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_CMPXCHG_LOCAL
+	select HAVE_CMPXCHG_DOUBLE
+	select HAVE_VIRT_CPU_ACCOUNTING
+	select VIRT_CPU_ACCOUNTING
 	select ARCH_DISCARD_MEMBLOCK
 	select BUILDTIME_EXTABLE_SORT
 	select ARCH_INLINE_SPIN_TRYLOCK
@@ -133,9 +140,79 @@
 
 source "kernel/Kconfig.freezer"
 
-menu "Base setup"
+menu "Processor type and features"
 
-comment "Processor type and features"
+config HAVE_MARCH_Z900_FEATURES
+	def_bool n
+
+config HAVE_MARCH_Z990_FEATURES
+	def_bool n
+	select HAVE_MARCH_Z900_FEATURES
+
+config HAVE_MARCH_Z9_109_FEATURES
+	def_bool n
+	select HAVE_MARCH_Z990_FEATURES
+
+config HAVE_MARCH_Z10_FEATURES
+	def_bool n
+	select HAVE_MARCH_Z9_109_FEATURES
+
+config HAVE_MARCH_Z196_FEATURES
+	def_bool n
+	select HAVE_MARCH_Z10_FEATURES
+
+choice
+	prompt "Processor type"
+	default MARCH_G5
+
+config MARCH_G5
+	bool "System/390 model G5 and G6"
+	depends on !64BIT
+	help
+	  Select this to build a 31 bit kernel that works
+	  on all ESA/390 and z/Architecture machines.
+
+config MARCH_Z900
+	bool "IBM zSeries model z800 and z900"
+	select HAVE_MARCH_Z900_FEATURES if 64BIT
+	help
+	  Select this to enable optimizations for model z800/z900 (2064 and
+	  2066 series). This will enable some optimizations that are not
+	  available on older ESA/390 (31 Bit) only CPUs.
+
+config MARCH_Z990
+	bool "IBM zSeries model z890 and z990"
+	select HAVE_MARCH_Z990_FEATURES if 64BIT
+	help
+	  Select this to enable optimizations for model z890/z990 (2084 and
+	  2086 series). The kernel will be slightly faster but will not work
+	  on older machines.
+
+config MARCH_Z9_109
+	bool "IBM System z9"
+	select HAVE_MARCH_Z9_109_FEATURES if 64BIT
+	help
+	  Select this to enable optimizations for IBM System z9 (2094 and
+	  2096 series). The kernel will be slightly faster but will not work
+	  on older machines.
+
+config MARCH_Z10
+	bool "IBM System z10"
+	select HAVE_MARCH_Z10_FEATURES if 64BIT
+	help
+	  Select this to enable optimizations for IBM System z10 (2097 and
+	  2098 series). The kernel will be slightly faster but will not work
+	  on older machines.
+
+config MARCH_Z196
+	bool "IBM zEnterprise 114 and 196"
+	select HAVE_MARCH_Z196_FEATURES if 64BIT
+	help
+	  Select this to enable optimizations for IBM zEnterprise 114 and 196
+	  (2818 and 2817 series). The kernel will be slightly faster but will
+	  not work on older machines.
+
+endchoice
 
 config 64BIT
 	def_bool y
@@ -147,6 +224,24 @@
 config 32BIT
 	def_bool y if !64BIT
 
+config COMPAT
+	def_bool y
+	prompt "Kernel support for 31 bit emulation"
+	depends on 64BIT
+	select COMPAT_BINFMT_ELF if BINFMT_ELF
+	select ARCH_WANT_OLD_COMPAT_IPC
+	help
+	  Select this option if you want to enable your system kernel to
+	  handle system-calls from ELF binaries for 31 bit ESA.  This option
+	  (and some other stuff like libraries and such) is needed for
+	  executing 31 bit applications.  It is safe to say "Y".
+
+config SYSVIPC_COMPAT
+	def_bool y if COMPAT && SYSVIPC
+
+config KEYS_COMPAT
+	def_bool y if COMPAT && KEYS
+
 config SMP
 	def_bool y
 	prompt "Symmetric multi-processing support"
@@ -202,6 +297,8 @@
 	  Book scheduler support improves the CPU scheduler's decision making
 	  when dealing with machines that have several books.
 
+source kernel/Kconfig.preempt
+
 config MATHEMU
 	def_bool y
 	prompt "IEEE FPU emulation"
@@ -211,100 +308,35 @@
 	  on older ESA/390 machines. Say Y unless you know your machine doesn't
 	  need this.
 
-config COMPAT
+source kernel/Kconfig.hz
+
+endmenu
+
+menu "Memory setup"
+
+config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	prompt "Kernel support for 31 bit emulation"
-	depends on 64BIT
-	select COMPAT_BINFMT_ELF if BINFMT_ELF
-	select ARCH_WANT_OLD_COMPAT_IPC
-	help
-	  Select this option if you want to enable your system kernel to
-	  handle system-calls from ELF binaries for 31 bit ESA.  This option
-	  (and some other stuff like libraries and such) is needed for
-	  executing 31 bit applications.  It is safe to say "Y".
+	select SPARSEMEM_VMEMMAP_ENABLE
+	select SPARSEMEM_VMEMMAP
+	select SPARSEMEM_STATIC if !64BIT
 
-config SYSVIPC_COMPAT
-	def_bool y if COMPAT && SYSVIPC
-
-config KEYS_COMPAT
-	def_bool y if COMPAT && KEYS
-
-config AUDIT_ARCH
+config ARCH_SPARSEMEM_DEFAULT
 	def_bool y
 
-config HAVE_MARCH_Z900_FEATURES
-	def_bool n
+config ARCH_SELECT_MEMORY_MODEL
+	def_bool y
 
-config HAVE_MARCH_Z990_FEATURES
-	def_bool n
-	select HAVE_MARCH_Z900_FEATURES
+config ARCH_ENABLE_MEMORY_HOTPLUG
+	def_bool y if SPARSEMEM
 
-config HAVE_MARCH_Z9_109_FEATURES
-	def_bool n
-	select HAVE_MARCH_Z990_FEATURES
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+	def_bool y
 
-config HAVE_MARCH_Z10_FEATURES
-	def_bool n
-	select HAVE_MARCH_Z9_109_FEATURES
+config FORCE_MAX_ZONEORDER
+	int
+	default "9"
 
-config HAVE_MARCH_Z196_FEATURES
-	def_bool n
-	select HAVE_MARCH_Z10_FEATURES
-
-comment "Code generation options"
-
-choice
-	prompt "Processor type"
-	default MARCH_G5
-
-config MARCH_G5
-	bool "System/390 model G5 and G6"
-	depends on !64BIT
-	help
-	  Select this to build a 31 bit kernel that works
-	  on all ESA/390 and z/Architecture machines.
-
-config MARCH_Z900
-	bool "IBM zSeries model z800 and z900"
-	select HAVE_MARCH_Z900_FEATURES if 64BIT
-	help
-	  Select this to enable optimizations for model z800/z900 (2064 and
-	  2066 series). This will enable some optimizations that are not
-	  available on older ESA/390 (31 Bit) only CPUs.
-
-config MARCH_Z990
-	bool "IBM zSeries model z890 and z990"
-	select HAVE_MARCH_Z990_FEATURES if 64BIT
-	help
-	  Select this to enable optimizations for model z890/z990 (2084 and
-	  2086 series). The kernel will be slightly faster but will not work
-	  on older machines.
-
-config MARCH_Z9_109
-	bool "IBM System z9"
-	select HAVE_MARCH_Z9_109_FEATURES if 64BIT
-	help
-	  Select this to enable optimizations for IBM System z9 (2094 and
-	  2096 series). The kernel will be slightly faster but will not work
-	  on older machines.
-
-config MARCH_Z10
-	bool "IBM System z10"
-	select HAVE_MARCH_Z10_FEATURES if 64BIT
-	help
-	  Select this to enable optimizations for IBM System z10 (2097 and
-	  2098 series). The kernel will be slightly faster but will not work
-	  on older machines.
-
-config MARCH_Z196
-	bool "IBM zEnterprise 114 and 196"
-	select HAVE_MARCH_Z196_FEATURES if 64BIT
-	help
-	  Select this to enable optimizations for IBM zEnterprise 114 and 196
-	  (2818 and 2817 series). The kernel will be slightly faster but will
-	  not work on older machines.
-
-endchoice
+source "mm/Kconfig"
 
 config PACK_STACK
 	def_bool y
@@ -368,34 +400,9 @@
 
 	  Say N if you are unsure.
 
-comment "Kernel preemption"
+endmenu
 
-source "kernel/Kconfig.preempt"
-
-config ARCH_SPARSEMEM_ENABLE
-	def_bool y
-	select SPARSEMEM_VMEMMAP_ENABLE
-	select SPARSEMEM_VMEMMAP
-	select SPARSEMEM_STATIC if !64BIT
-
-config ARCH_SPARSEMEM_DEFAULT
-	def_bool y
-
-config ARCH_SELECT_MEMORY_MODEL
-	def_bool y
-
-config ARCH_ENABLE_MEMORY_HOTPLUG
-	def_bool y if SPARSEMEM
-
-config ARCH_ENABLE_MEMORY_HOTREMOVE
-	def_bool y
-
-config ARCH_HIBERNATION_POSSIBLE
-	def_bool y if 64BIT
-
-source "mm/Kconfig"
-
-comment "I/O subsystem configuration"
+menu "I/O subsystem"
 
 config QDIO
 	def_tristate y
@@ -426,13 +433,102 @@
 
 	  If unsure, say N.
 
-comment "Misc"
+config SCM_BUS
+	def_bool y
+	depends on 64BIT
+	prompt "SCM bus driver"
+	help
+	  Bus driver for Storage Class Memory.
+
+config EADM_SCH
+	def_tristate m
+	prompt "Support for EADM subchannels"
+	depends on SCM_BUS
+	help
+	  This driver allows usage of EADM subchannels. EADM subchannels act
+	  as a communication vehicle for SCM increments.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called eadm_sch.
+
+endmenu
+
+menu "Dump support"
+
+config CRASH_DUMP
+	bool "kernel crash dumps"
+	depends on 64BIT && SMP
+	select KEXEC
+	help
+	  Generate crash dump after being started by kexec.
+	  Crash dump kernels are loaded in the main kernel with kexec-tools
+	  into a specially reserved region and then later executed after
+	  a crash by kdump/kexec.
+	  For more details see Documentation/kdump/kdump.txt
+
+config ZFCPDUMP
+	def_bool n
+	prompt "zfcpdump support"
+	select SMP
+	help
+	  Select this option if you want to build an zfcpdump enabled kernel.
+	  Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+
+endmenu
+
+menu "Executable file formats / Emulations"
 
 source "fs/Kconfig.binfmt"
 
-config FORCE_MAX_ZONEORDER
-	int
-	default "9"
+config SECCOMP
+	def_bool y
+	prompt "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y.
+
+endmenu
+
+menu "Power Management"
+
+config ARCH_HIBERNATION_POSSIBLE
+	def_bool y if 64BIT
+
+source "kernel/power/Kconfig"
+
+endmenu
+
+source "net/Kconfig"
+
+config PCMCIA
+	def_bool n
+
+config CCW
+	def_bool y
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/s390/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+menu "Virtualization"
 
 config PFAULT
 	def_bool y
@@ -448,8 +544,8 @@
 	  this option.
 
 config SHARED_KERNEL
-	def_bool y
-	prompt "VM shared kernel support"
+	bool "VM shared kernel support"
+	depends on !JUMP_LABEL
 	help
 	  Select this option, if you want to share the text segment of the
 	  Linux kernel between different VM guests. This reduces memory
@@ -544,8 +640,6 @@
 	  This can also be compiled as a module, which will be called
 	  appldata_net_sum.o.
 
-source kernel/Kconfig.hz
-
 config S390_HYPFS_FS
 	def_bool y
 	prompt "s390 hypervisor file system support"
@@ -554,90 +648,21 @@
 	  This is a virtual file system intended to provide accounting
 	  information in an s390 hypervisor environment.
 
-config KEXEC
-	def_bool n
-	prompt "kexec system call"
-	help
-	  kexec is a system call that implements the ability to shutdown your
-	  current kernel, and to start another kernel.  It is like a reboot
-	  but is independent of hardware/microcode support.
-
-config CRASH_DUMP
-	bool "kernel crash dumps"
-	depends on 64BIT && SMP
-	select KEXEC
-	help
-	  Generate crash dump after being started by kexec.
-	  Crash dump kernels are loaded in the main kernel with kexec-tools
-	  into a specially reserved region and then later executed after
-	  a crash by kdump/kexec.
-	  For more details see Documentation/kdump/kdump.txt
-
-config ZFCPDUMP
-	def_bool n
-	prompt "zfcpdump support"
-	select SMP
-	help
-	  Select this option if you want to build an zfcpdump enabled kernel.
-	  Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+source "arch/s390/kvm/Kconfig"
 
 config S390_GUEST
 	def_bool y
-	prompt "s390 guest support for KVM (EXPERIMENTAL)"
+	prompt "s390 support for virtio devices (EXPERIMENTAL)"
 	depends on 64BIT && EXPERIMENTAL
 	select VIRTUALIZATION
 	select VIRTIO
 	select VIRTIO_RING
 	select VIRTIO_CONSOLE
 	help
+	  Enabling this option adds support for virtio based paravirtual device
+	  drivers on s390.
+
 	  Select this option if you want to run the kernel as a guest under
-	  the KVM hypervisor. This will add detection for KVM as well  as a
-	  virtio transport. If KVM is detected, the virtio console will be
-	  the default console.
-
-config SECCOMP
-	def_bool y
-	prompt "Enable seccomp to safely compute untrusted bytecode"
-	depends on PROC_FS
-	help
-	  This kernel feature is useful for number crunching applications
-	  that may need to compute untrusted bytecode during their
-	  execution. By using pipes or other transports made available to
-	  the process as file descriptors supporting the read/write
-	  syscalls, it's possible to isolate those applications in
-	  their own address space using seccomp. Once seccomp is
-	  enabled via /proc/<pid>/seccomp, it cannot be disabled
-	  and the task is only allowed to execute a few safe syscalls
-	  defined by each seccomp mode.
-
-	  If unsure, say Y.
+	  the KVM hypervisor.
 
 endmenu
-
-menu "Power Management"
-
-source "kernel/power/Kconfig"
-
-endmenu
-
-source "net/Kconfig"
-
-config PCMCIA
-	def_bool n
-
-config CCW
-	def_bool y
-
-source "drivers/Kconfig"
-
-source "fs/Kconfig"
-
-source "arch/s390/Kconfig.debug"
-
-source "security/Kconfig"
-
-source "crypto/Kconfig"
-
-source "lib/Kconfig"
-
-source "arch/s390/kvm/Kconfig"
diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile
index 10e22c4..3ad8f61c 100644
--- a/arch/s390/boot/compressed/Makefile
+++ b/arch/s390/boot/compressed/Makefile
@@ -11,6 +11,7 @@
 	   sizes.h head$(BITS).o
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 KBUILD_CFLAGS += $(cflags-y)
 KBUILD_CFLAGS += $(call cc-option,-mpacked-stack)
 KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c
index 465eca7..c4c6a1c 100644
--- a/arch/s390/boot/compressed/misc.c
+++ b/arch/s390/boot/compressed/misc.c
@@ -71,34 +71,37 @@
 {
 	char *xs;
 
-	if (c == 0)
-		return __builtin_memset(s, 0, n);
-
-	xs = (char *) s;
-	if (n > 0)
-		do {
-			*xs++ = c;
-		} while (--n > 0);
+	xs = s;
+	while (n--)
+		*xs++ = c;
 	return s;
 }
 
-void *memcpy(void *__dest, __const void *__src, size_t __n)
+void *memcpy(void *dest, const void *src, size_t n)
 {
-	return __builtin_memcpy(__dest, __src, __n);
+	const char *s = src;
+	char *d = dest;
+
+	while (n--)
+		*d++ = *s++;
+	return dest;
 }
 
-void *memmove(void *__dest, __const void *__src, size_t __n)
+void *memmove(void *dest, const void *src, size_t n)
 {
-	char *d;
-	const char *s;
+	const char *s = src;
+	char *d = dest;
 
-	if (__dest <= __src)
-		return __builtin_memcpy(__dest, __src, __n);
-	d = __dest + __n;
-	s = __src + __n;
-	while (__n--)
-		*--d = *--s;
-	return __dest;
+	if (d <= s) {
+		while (n--)
+			*d++ = *s++;
+	} else {
+		d += n;
+		s += n;
+		while (n--)
+			*--d = *--s;
+	}
+	return dest;
 }
 
 static void error(char *x)
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index f39cd71..b74400e 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -16,8 +16,8 @@
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_MEMCG=y
-CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
 CONFIG_CGROUP_SCHED=y
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_CGROUP=y
@@ -32,20 +32,19 @@
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_IBM_PARTITION=y
 CONFIG_DEFAULT_DEADLINE=y
-CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
-CONFIG_BINFMT_MISC=m
-CONFIG_CMM=m
-CONFIG_HZ_100=y
 CONFIG_CRASH_DUMP=y
+CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -75,6 +74,7 @@
 CONFIG_NET_CLS_RSVP6=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=y
+CONFIG_BPF_JIT=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_LOOP=m
@@ -121,7 +121,6 @@
 CONFIG_RCU_TRACE=y
 CONFIG_KPROBES_SANITY_TEST=y
 CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
-CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
 CONFIG_LATENCYTOP=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_BLK_DEV_IO_TRACE=y
@@ -173,3 +172,4 @@
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRC7=m
+CONFIG_CMM=m
diff --git a/arch/s390/include/asm/appldata.h b/arch/s390/include/asm/appldata.h
index f328294..32a7059 100644
--- a/arch/s390/include/asm/appldata.h
+++ b/arch/s390/include/asm/appldata.h
@@ -70,7 +70,7 @@
 	int ry;
 
 	if (!MACHINE_IS_VM)
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 	parm_list.diag = 0xdc;
 	parm_list.function = fn;
 	parm_list.parlist_length = sizeof(parm_list);
diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/asm/chsc.h
index bf115b4..aea451f 100644
--- a/arch/s390/include/asm/chsc.h
+++ b/arch/s390/include/asm/chsc.h
@@ -125,32 +125,4 @@
 #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info)
 #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal)
 
-#ifdef __KERNEL__
-
-struct css_general_char {
-	u64 : 12;
-	u32 dynio : 1;	 /* bit 12 */
-	u32 : 28;
-	u32 aif : 1;	 /* bit 41 */
-	u32 : 3;
-	u32 mcss : 1;	 /* bit 45 */
-	u32 fcs : 1;	 /* bit 46 */
-	u32 : 1;
-	u32 ext_mb : 1;  /* bit 48 */
-	u32 : 7;
-	u32 aif_tdd : 1; /* bit 56 */
-	u32 : 1;
-	u32 qebsm : 1;	 /* bit 58 */
-	u32 : 8;
-	u32 aif_osa : 1; /* bit 67 */
-	u32 : 14;
-	u32 cib : 1;	 /* bit 82 */
-	u32 : 5;
-	u32 fcx : 1;	 /* bit 88 */
-	u32 : 7;
-}__attribute__((packed));
-
-extern struct css_general_char css_general_characteristics;
-
-#endif /* __KERNEL__ */
 #endif
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index 77043aa..55bde60 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -80,6 +80,18 @@
 } __attribute__ ((packed));
 
 /**
+ * struct erw_eadm - EADM Subchannel extended report word
+ * @b: aob error
+ * @r: arsb error
+ */
+struct erw_eadm {
+	__u32 : 16;
+	__u32 b : 1;
+	__u32 r : 1;
+	__u32  : 14;
+} __packed;
+
+/**
  * struct sublog - subchannel logout area
  * @res0: reserved
  * @esf: extended status flags
@@ -170,9 +182,22 @@
 } __attribute__ ((packed));
 
 /**
+ * struct esw_eadm - EADM Subchannel Extended Status Word (ESW)
+ * @sublog: subchannel logout
+ * @erw: extended report word
+ */
+struct esw_eadm {
+	__u32 sublog;
+	struct erw_eadm erw;
+	__u32 : 32;
+	__u32 : 32;
+	__u32 : 32;
+} __packed;
+
+/**
  * struct irb - interruption response block
  * @scsw: subchannel status word
- * @esw: extened status word, 4 formats
+ * @esw: extened status word
  * @ecw: extended control word
  *
  * The irb that is handed to the device driver when an interrupt occurs. For
@@ -191,6 +216,7 @@
 		struct esw1 esw1;
 		struct esw2 esw2;
 		struct esw3 esw3;
+		struct esw_eadm eadm;
 	} esw;
 	__u8   ecw[32];
 } __attribute__ ((packed,aligned(4)));
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h
index 8d798e9..0f636cb 100644
--- a/arch/s390/include/asm/cmpxchg.h
+++ b/arch/s390/include/asm/cmpxchg.h
@@ -7,7 +7,9 @@
 #ifndef __ASM_CMPXCHG_H
 #define __ASM_CMPXCHG_H
 
+#include <linux/mmdebug.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 
 extern void __xchg_called_with_bad_pointer(void);
 
@@ -203,6 +205,65 @@
 })
 #endif /* CONFIG_64BIT */
 
+#define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn)		\
+({									\
+	register __typeof__(*(p1)) __old1 asm("2") = (o1);		\
+	register __typeof__(*(p2)) __old2 asm("3") = (o2);		\
+	register __typeof__(*(p1)) __new1 asm("4") = (n1);		\
+	register __typeof__(*(p2)) __new2 asm("5") = (n2);		\
+	int cc;								\
+	asm volatile(							\
+			insn   " %[old],%[new],%[ptr]\n"		\
+		"	ipm	%[cc]\n"				\
+		"	srl	%[cc],28"				\
+		: [cc] "=d" (cc), [old] "+d" (__old1), "+d" (__old2)	\
+		: [new] "d" (__new1), "d" (__new2),			\
+		  [ptr] "Q" (*(p1)), "Q" (*(p2))			\
+		: "memory", "cc");					\
+	!cc;								\
+})
+
+#define __cmpxchg_double_4(p1, p2, o1, o2, n1, n2) \
+	__cmpxchg_double_op(p1, p2, o1, o2, n1, n2, "cds")
+
+#define __cmpxchg_double_8(p1, p2, o1, o2, n1, n2) \
+	__cmpxchg_double_op(p1, p2, o1, o2, n1, n2, "cdsg")
+
+extern void __cmpxchg_double_called_with_bad_pointer(void);
+
+#define __cmpxchg_double(p1, p2, o1, o2, n1, n2)			\
+({									\
+	int __ret;							\
+	switch (sizeof(*(p1))) {					\
+	case 4:								\
+		__ret = __cmpxchg_double_4(p1, p2, o1, o2, n1, n2);	\
+		break;							\
+	case 8:								\
+		__ret = __cmpxchg_double_8(p1, p2, o1, o2, n1, n2);	\
+		break;							\
+	default:							\
+		__cmpxchg_double_called_with_bad_pointer();		\
+	}								\
+	__ret;								\
+})
+
+#define cmpxchg_double(p1, p2, o1, o2, n1, n2)				\
+({									\
+	__typeof__(p1) __p1 = (p1);					\
+	__typeof__(p2) __p2 = (p2);					\
+	int __ret;							\
+	BUILD_BUG_ON(sizeof(*(p1)) != sizeof(long));			\
+	BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long));			\
+	VM_BUG_ON((unsigned long)((__p1) + 1) != (unsigned long)(__p2));\
+	if (sizeof(long) == 4)						\
+		__ret = __cmpxchg_double_4(__p1, __p2, o1, o2, n1, n2);	\
+	else								\
+		__ret = __cmpxchg_double_8(__p1, __p2, o1, o2, n1, n2);	\
+	__ret;								\
+})
+
+#define system_has_cmpxchg_double()	1
+
 #include <asm-generic/cmpxchg-local.h>
 
 static inline unsigned long __cmpxchg_local(void *ptr,
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
index a3afecd..35f0020 100644
--- a/arch/s390/include/asm/cpu_mf.h
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -21,11 +21,15 @@
 #define CPU_MF_INT_SF_LSDA	(1 << 22)	/* loss of sample data alert */
 #define CPU_MF_INT_CF_CACA	(1 <<  7)	/* counter auth. change alert */
 #define CPU_MF_INT_CF_LCDA	(1 <<  6)	/* loss of counter data alert */
+#define CPU_MF_INT_RI_HALTED	(1 <<  5)	/* run-time instr. halted */
+#define CPU_MF_INT_RI_BUF_FULL	(1 <<  4)	/* run-time instr. program
+						   buffer full */
 
 #define CPU_MF_INT_CF_MASK	(CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA)
 #define CPU_MF_INT_SF_MASK	(CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE|	\
 				 CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA|	\
 				 CPU_MF_INT_SF_LSDA)
+#define CPU_MF_INT_RI_MASK	(CPU_MF_INT_RI_HALTED|CPU_MF_INT_RI_BUF_FULL)
 
 /* CPU measurement facility support */
 static inline int cpum_cf_avail(void)
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index 8709bde..023d5ae 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -12,6 +12,9 @@
 #include <linux/spinlock.h>
 #include <asm/div64.h>
 
+
+#define __ARCH_HAS_VTIME_ACCOUNT
+
 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
 
 typedef unsigned long long __nocast cputime_t;
diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h
new file mode 100644
index 0000000..a06ebc2
--- /dev/null
+++ b/arch/s390/include/asm/css_chars.h
@@ -0,0 +1,39 @@
+#ifndef _ASM_CSS_CHARS_H
+#define _ASM_CSS_CHARS_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+struct css_general_char {
+	u64 : 12;
+	u32 dynio : 1;	 /* bit 12 */
+	u32 : 4;
+	u32 eadm : 1;	 /* bit 17 */
+	u32 : 23;
+	u32 aif : 1;	 /* bit 41 */
+	u32 : 3;
+	u32 mcss : 1;	 /* bit 45 */
+	u32 fcs : 1;	 /* bit 46 */
+	u32 : 1;
+	u32 ext_mb : 1;  /* bit 48 */
+	u32 : 7;
+	u32 aif_tdd : 1; /* bit 56 */
+	u32 : 1;
+	u32 qebsm : 1;	 /* bit 58 */
+	u32 : 8;
+	u32 aif_osa : 1; /* bit 67 */
+	u32 : 12;
+	u32 eadm_rf : 1; /* bit 80 */
+	u32 : 1;
+	u32 cib : 1;	 /* bit 82 */
+	u32 : 5;
+	u32 fcx : 1;	 /* bit 88 */
+	u32 : 19;
+	u32 alt_ssi : 1; /* bit 108 */
+} __packed;
+
+extern struct css_general_char css_general_characteristics;
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/arch/s390/include/asm/eadm.h b/arch/s390/include/asm/eadm.h
new file mode 100644
index 0000000..8d48471
--- /dev/null
+++ b/arch/s390/include/asm/eadm.h
@@ -0,0 +1,124 @@
+#ifndef _ASM_S390_EADM_H
+#define _ASM_S390_EADM_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct arqb {
+	u64 data;
+	u16 fmt:4;
+	u16:12;
+	u16 cmd_code;
+	u16:16;
+	u16 msb_count;
+	u32 reserved[12];
+} __packed;
+
+#define ARQB_CMD_MOVE	1
+
+struct arsb {
+	u16 fmt:4;
+	u32:28;
+	u8 ef;
+	u8:8;
+	u8 ecbi;
+	u8:8;
+	u8 fvf;
+	u16:16;
+	u8 eqc;
+	u32:32;
+	u64 fail_msb;
+	u64 fail_aidaw;
+	u64 fail_ms;
+	u64 fail_scm;
+	u32 reserved[4];
+} __packed;
+
+struct msb {
+	u8 fmt:4;
+	u8 oc:4;
+	u8 flags;
+	u16:12;
+	u16 bs:4;
+	u32 blk_count;
+	u64 data_addr;
+	u64 scm_addr;
+	u64:64;
+} __packed;
+
+struct aidaw {
+	u8 flags;
+	u32 :24;
+	u32 :32;
+	u64 data_addr;
+} __packed;
+
+#define MSB_OC_CLEAR	0
+#define MSB_OC_READ	1
+#define MSB_OC_WRITE	2
+#define MSB_OC_RELEASE	3
+
+#define MSB_FLAG_BNM	0x80
+#define MSB_FLAG_IDA	0x40
+
+#define MSB_BS_4K	0
+#define MSB_BS_1M	1
+
+#define AOB_NR_MSB	124
+
+struct aob {
+	struct arqb request;
+	struct arsb response;
+	struct msb msb[AOB_NR_MSB];
+} __packed __aligned(PAGE_SIZE);
+
+struct aob_rq_header {
+	struct scm_device *scmdev;
+	char data[0];
+};
+
+struct scm_device {
+	u64 address;
+	u64 size;
+	unsigned int nr_max_block;
+	struct device dev;
+	struct {
+		unsigned int persistence:4;
+		unsigned int oper_state:4;
+		unsigned int data_state:4;
+		unsigned int rank:4;
+		unsigned int release:1;
+		unsigned int res_id:8;
+	} __packed attrs;
+};
+
+#define OP_STATE_GOOD		1
+#define OP_STATE_TEMP_ERR	2
+#define OP_STATE_PERM_ERR	3
+
+struct scm_driver {
+	struct device_driver drv;
+	int (*probe) (struct scm_device *scmdev);
+	int (*remove) (struct scm_device *scmdev);
+	void (*notify) (struct scm_device *scmdev);
+	void (*handler) (struct scm_device *scmdev, void *data, int error);
+};
+
+int scm_driver_register(struct scm_driver *scmdrv);
+void scm_driver_unregister(struct scm_driver *scmdrv);
+
+int scm_start_aob(struct aob *aob);
+void scm_irq_handler(struct aob *aob, int error);
+
+struct eadm_ops {
+	int (*eadm_start) (struct aob *aob);
+	struct module *owner;
+};
+
+int scm_get_ref(void);
+void scm_put_ref(void);
+
+void register_eadm_ops(struct eadm_ops *ops);
+void unregister_eadm_ops(struct eadm_ops *ops);
+
+#endif /* _ASM_S390_EADM_H */
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 9b94a16..178ff96 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -101,6 +101,7 @@
 #define HWCAP_S390_HPAGE	128
 #define HWCAP_S390_ETF3EH	256
 #define HWCAP_S390_HIGH_GPRS	512
+#define HWCAP_S390_TE		1024
 
 /*
  * These are used to set parameters in the core dumps.
@@ -212,4 +213,6 @@
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+void *fill_cpu_elf_notes(void *ptr, struct save_area *sa);
+
 #endif
diff --git a/arch/s390/include/asm/etr.h b/arch/s390/include/asm/etr.h
index a24b03b..629b79a 100644
--- a/arch/s390/include/asm/etr.h
+++ b/arch/s390/include/asm/etr.h
@@ -140,7 +140,7 @@
 /* Inline assembly helper functions */
 static inline int etr_setr(struct etr_eacr *ctrl)
 {
-	int rc = -ENOSYS;
+	int rc = -EOPNOTSUPP;
 
 	asm volatile(
 		"	.insn	s,0xb2160000,%1\n"
@@ -154,7 +154,7 @@
 /* Stores a format 1 aib with 64 bytes */
 static inline int etr_stetr(struct etr_aib *aib)
 {
-	int rc = -ENOSYS;
+	int rc = -EOPNOTSUPP;
 
 	asm volatile(
 		"	.insn	s,0xb2170000,%1\n"
@@ -169,7 +169,7 @@
 static inline int etr_steai(struct etr_aib *aib, unsigned int func)
 {
 	register unsigned int reg0 asm("0") = func;
-	int rc = -ENOSYS;
+	int rc = -EOPNOTSUPP;
 
 	asm volatile(
 		"	.insn	s,0xb2b30000,%1\n"
@@ -190,7 +190,7 @@
 {
 	register unsigned int reg0 asm("0") = func;
 	register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
-	int rc = -ENOSYS;
+	int rc = -EOPNOTSUPP;
 
 	asm volatile(
 		"	.word	0x0104\n"
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index 799ed0f..2d6e6e3 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -66,16 +66,6 @@
 	return pte;
 }
 
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
-					    unsigned long addr, pte_t *ptep)
-{
-	pte_t pte = huge_ptep_get(ptep);
-
-	mm->context.flush_mm = 1;
-	pmd_clear((pmd_t *) ptep);
-	return pte;
-}
-
 static inline void __pmd_csp(pmd_t *pmdp)
 {
 	register unsigned long reg2 asm("2") = pmd_val(*pmdp);
@@ -117,6 +107,15 @@
 		__pmd_csp(pmdp);
 }
 
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+					    unsigned long addr, pte_t *ptep)
+{
+	pte_t pte = huge_ptep_get(ptep);
+
+	huge_ptep_invalidate(mm, addr, ptep);
+	return pte;
+}
+
 #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
 ({									    \
 	int __changed = !pte_same(huge_ptep_get(__ptep), __entry);	    \
@@ -131,10 +130,7 @@
 ({									\
 	pte_t __pte = huge_ptep_get(__ptep);				\
 	if (pte_write(__pte)) {						\
-		(__mm)->context.flush_mm = 1;				\
-		if (atomic_read(&(__mm)->context.attach_count) > 1 ||	\
-		    (__mm) != current->active_mm)			\
-			huge_ptep_invalidate(__mm, __addr, __ptep);	\
+		huge_ptep_invalidate(__mm, __addr, __ptep);		\
 		set_huge_pte_at(__mm, __addr, __ptep,			\
 				huge_pte_wrprotect(__pte));		\
 	}								\
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 2b9d418..6703dd9 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -19,6 +19,7 @@
 	EXTINT_IUC,
 	EXTINT_CMS,
 	EXTINT_CMC,
+	EXTINT_CMR,
 	IOINT_CIO,
 	IOINT_QAI,
 	IOINT_DAS,
@@ -30,6 +31,7 @@
 	IOINT_CLW,
 	IOINT_CTC,
 	IOINT_APB,
+	IOINT_ADM,
 	IOINT_CSC,
 	NMI_NMI,
 	NR_IRQS,
diff --git a/arch/s390/include/asm/isc.h b/arch/s390/include/asm/isc.h
index 1420a11..5ae6064 100644
--- a/arch/s390/include/asm/isc.h
+++ b/arch/s390/include/asm/isc.h
@@ -14,6 +14,7 @@
 /* Regular I/O interrupts. */
 #define IO_SCH_ISC 3			/* regular I/O subchannels */
 #define CONSOLE_ISC 1			/* console I/O subchannel */
+#define EADM_SCH_ISC 4			/* EADM subchannels */
 #define CHSC_SCH_ISC 7			/* CHSC subchannels */
 /* Adapter interrupts. */
 #define QDIO_AIRQ_ISC IO_SCH_ISC	/* I/O subchannel in qdio mode */
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index aab5555..bbf8141 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -329,9 +329,13 @@
 	__u8	pad_0x1338[0x1340-0x1338];	/* 0x1338 */
 	__u32	access_regs_save_area[16];	/* 0x1340 */
 	__u64	cregs_save_area[16];		/* 0x1380 */
+	__u8	pad_0x1400[0x1800-0x1400];	/* 0x1400 */
+
+	/* Transaction abort diagnostic block */
+	__u8	pgm_tdb[256];			/* 0x1800 */
 
 	/* align to the top of the prefix area */
-	__u8	pad_0x1400[0x2000-0x1400];	/* 0x1400 */
+	__u8	pad_0x1900[0x2000-0x1900];	/* 0x1900 */
 } __packed;
 
 #endif /* CONFIG_32BIT */
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index b749c57..084e775 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -57,7 +57,7 @@
 	pgd_t *pgd = mm->pgd;
 
 	S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
-	if (addressing_mode != HOME_SPACE_MODE) {
+	if (s390_user_mode != HOME_SPACE_MODE) {
 		/* Load primary space page table origin. */
 		asm volatile(LCTL_OPCODE" 1,1,%0\n"
 			     : : "m" (S390_lowcore.user_asce) );
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h
index 6537e72..86fe0ee 100644
--- a/arch/s390/include/asm/percpu.h
+++ b/arch/s390/include/asm/percpu.h
@@ -20,7 +20,7 @@
 #endif
 
 #define arch_this_cpu_to_op(pcp, val, op)				\
-do {									\
+({									\
 	typedef typeof(pcp) pcp_op_T__;					\
 	pcp_op_T__ old__, new__, prev__;				\
 	pcp_op_T__ *ptr__;						\
@@ -39,13 +39,19 @@
 		}							\
 	} while (prev__ != old__);					\
 	preempt_enable();						\
-} while (0)
+	new__;								\
+})
 
 #define this_cpu_add_1(pcp, val) arch_this_cpu_to_op(pcp, val, +)
 #define this_cpu_add_2(pcp, val) arch_this_cpu_to_op(pcp, val, +)
 #define this_cpu_add_4(pcp, val) arch_this_cpu_to_op(pcp, val, +)
 #define this_cpu_add_8(pcp, val) arch_this_cpu_to_op(pcp, val, +)
 
+#define this_cpu_add_return_1(pcp, val) arch_this_cpu_to_op(pcp, val, +)
+#define this_cpu_add_return_2(pcp, val) arch_this_cpu_to_op(pcp, val, +)
+#define this_cpu_add_return_4(pcp, val) arch_this_cpu_to_op(pcp, val, +)
+#define this_cpu_add_return_8(pcp, val) arch_this_cpu_to_op(pcp, val, +)
+
 #define this_cpu_and_1(pcp, val) arch_this_cpu_to_op(pcp, val, &)
 #define this_cpu_and_2(pcp, val) arch_this_cpu_to_op(pcp, val, &)
 #define this_cpu_and_4(pcp, val) arch_this_cpu_to_op(pcp, val, &)
@@ -61,7 +67,7 @@
 #define this_cpu_xor_4(pcp, val) arch_this_cpu_to_op(pcp, val, ^)
 #define this_cpu_xor_8(pcp, val) arch_this_cpu_to_op(pcp, val, ^)
 
-#define arch_this_cpu_cmpxchg(pcp, oval, nval)			\
+#define arch_this_cpu_cmpxchg(pcp, oval, nval)				\
 ({									\
 	typedef typeof(pcp) pcp_op_T__;					\
 	pcp_op_T__ ret__;						\
@@ -84,6 +90,44 @@
 #define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
 #define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
 
+#define arch_this_cpu_xchg(pcp, nval)					\
+({									\
+	typeof(pcp) *ptr__;						\
+	typeof(pcp) ret__;						\
+	preempt_disable();						\
+	ptr__ = __this_cpu_ptr(&(pcp));					\
+	ret__ = xchg(ptr__, nval);					\
+	preempt_enable();						\
+	ret__;								\
+})
+
+#define this_cpu_xchg_1(pcp, nval) arch_this_cpu_xchg(pcp, nval)
+#define this_cpu_xchg_2(pcp, nval) arch_this_cpu_xchg(pcp, nval)
+#define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval)
+#ifdef CONFIG_64BIT
+#define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval)
+#endif
+
+#define arch_this_cpu_cmpxchg_double(pcp1, pcp2, o1, o2, n1, n2)	\
+({									\
+	typeof(pcp1) o1__ = (o1), n1__ = (n1);				\
+	typeof(pcp2) o2__ = (o2), n2__ = (n2);				\
+	typeof(pcp1) *p1__;						\
+	typeof(pcp2) *p2__;						\
+	int ret__;							\
+	preempt_disable();						\
+	p1__ = __this_cpu_ptr(&(pcp1));					\
+	p2__ = __this_cpu_ptr(&(pcp2));					\
+	ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__);	\
+	preempt_enable();						\
+	ret__;								\
+})
+
+#define this_cpu_cmpxchg_double_4 arch_this_cpu_cmpxchg_double
+#ifdef CONFIG_64BIT
+#define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double
+#endif
+
 #include <asm-generic/percpu.h>
 
 #endif /* __ARCH_S390_PERCPU__ */
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 11e4e32..f3e0aab 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -11,12 +11,15 @@
 #ifndef __ASM_S390_PROCESSOR_H
 #define __ASM_S390_PROCESSOR_H
 
+#ifndef __ASSEMBLY__
+
 #include <linux/linkage.h>
 #include <linux/irqflags.h>
 #include <asm/cpu.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
+#include <asm/runtime_instr.h>
 
 /*
  * Default implementation of macro that returns current
@@ -75,11 +78,20 @@
 	unsigned long gmap_addr;	/* address of last gmap fault. */
 	struct per_regs per_user;	/* User specified PER registers */
 	struct per_event per_event;	/* Cause of the last PER trap */
+	unsigned long per_flags;	/* Flags to control debug behavior */
         /* pfault_wait is used to block the process on a pfault event */
 	unsigned long pfault_wait;
 	struct list_head list;
+	/* cpu runtime instrumentation */
+	struct runtime_instr_cb *ri_cb;
+	int ri_signum;
+#ifdef CONFIG_64BIT
+	unsigned char trap_tdb[256];	/* Transaction abort diagnose block */
+#endif
 };
 
+#define PER_FLAG_NO_TE		1UL	/* Flag to disable transactions. */
+
 typedef struct thread_struct thread_struct;
 
 /*
@@ -130,6 +142,12 @@
 struct mm_struct;
 struct seq_file;
 
+#ifdef CONFIG_64BIT
+extern void show_cacheinfo(struct seq_file *m);
+#else
+static inline void show_cacheinfo(struct seq_file *m) { }
+#endif
+
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
@@ -140,6 +158,7 @@
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern void show_code(struct pt_regs *regs);
+extern void print_fn_code(unsigned char *code, unsigned long len);
 
 unsigned long get_wchan(struct task_struct *p);
 #define task_pt_regs(tsk) ((struct pt_regs *) \
@@ -331,23 +350,6 @@
 
 #define ARCH_LOW_ADDRESS_LIMIT	0x7fffffffUL
 
-/*
- * Helper macro for exception table entries
- */
-#ifndef CONFIG_64BIT
-#define EX_TABLE(_fault,_target)			\
-	".section __ex_table,\"a\"\n"			\
-	"	.align 4\n"				\
-	"	.long  " #_fault "," #_target "\n"	\
-	".previous\n"
-#else
-#define EX_TABLE(_fault,_target)			\
-	".section __ex_table,\"a\"\n"			\
-	"	.align 8\n"				\
-	"	.quad  " #_fault "," #_target "\n"	\
-	".previous\n"
-#endif
-
 extern int memcpy_real(void *, void *, size_t);
 extern void memcpy_absolute(void *, void *, size_t);
 
@@ -358,4 +360,25 @@
 	memcpy_absolute(&(dest), &__tmp, sizeof(__tmp));	\
 }
 
-#endif                                 /* __ASM_S390_PROCESSOR_H           */
+/*
+ * Helper macro for exception table entries
+ */
+#define EX_TABLE(_fault, _target)	\
+	".section __ex_table,\"a\"\n"	\
+	".align	4\n"			\
+	".long	(" #_fault ") - .\n"	\
+	".long	(" #_target ") - .\n"	\
+	".previous\n"
+
+#else /* __ASSEMBLY__ */
+
+#define EX_TABLE(_fault, _target)	\
+	.section __ex_table,"a"	;	\
+	.align	4 ;			\
+	.long	(_fault) - . ;		\
+	.long	(_target) - . ;		\
+	.previous
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_S390_PROCESSOR_H */
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index d5f08ea..ce20a53 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -235,6 +235,7 @@
 #define PSW_MASK_ASC		0x0000C000UL
 #define PSW_MASK_CC		0x00003000UL
 #define PSW_MASK_PM		0x00000F00UL
+#define PSW_MASK_RI		0x00000000UL
 #define PSW_MASK_EA		0x00000000UL
 #define PSW_MASK_BA		0x00000000UL
 
@@ -264,10 +265,11 @@
 #define PSW_MASK_ASC		0x0000C00000000000UL
 #define PSW_MASK_CC		0x0000300000000000UL
 #define PSW_MASK_PM		0x00000F0000000000UL
+#define PSW_MASK_RI		0x0000008000000000UL
 #define PSW_MASK_EA		0x0000000100000000UL
 #define PSW_MASK_BA		0x0000000080000000UL
 
-#define PSW_MASK_USER		0x00003F0180000000UL
+#define PSW_MASK_USER		0x00003F8180000000UL
 
 #define PSW_ADDR_AMODE		0x0000000000000000UL
 #define PSW_ADDR_INSN		0xFFFFFFFFFFFFFFFFUL
@@ -359,17 +361,19 @@
 	unsigned char access_id;	/* PER trap access identification */
 };
 
-#define PER_EVENT_MASK			0xE9000000UL
+#define PER_EVENT_MASK			0xEB000000UL
 
 #define PER_EVENT_BRANCH		0x80000000UL
 #define PER_EVENT_IFETCH		0x40000000UL
 #define PER_EVENT_STORE			0x20000000UL
 #define PER_EVENT_STORE_REAL		0x08000000UL
+#define PER_EVENT_TRANSACTION_END	0x02000000UL
 #define PER_EVENT_NULLIFICATION		0x01000000UL
 
-#define PER_CONTROL_MASK		0x00a00000UL
+#define PER_CONTROL_MASK		0x00e00000UL
 
 #define PER_CONTROL_BRANCH_ADDRESS	0x00800000UL
+#define PER_CONTROL_SUSPENSION		0x00400000UL
 #define PER_CONTROL_ALTERATION		0x00200000UL
 
 #endif
@@ -483,6 +487,8 @@
 #define PTRACE_GET_LAST_BREAK	      0x5006
 #define PTRACE_PEEK_SYSTEM_CALL       0x5007
 #define PTRACE_POKE_SYSTEM_CALL	      0x5008
+#define PTRACE_ENABLE_TE	      0x5009
+#define PTRACE_DISABLE_TE	      0x5010
 
 /*
  * PT_PROT definition is loosely based on hppa bsd definition in
diff --git a/arch/s390/include/asm/runtime_instr.h b/arch/s390/include/asm/runtime_instr.h
new file mode 100644
index 0000000..830da73
--- /dev/null
+++ b/arch/s390/include/asm/runtime_instr.h
@@ -0,0 +1,98 @@
+#ifndef _RUNTIME_INSTR_H
+#define _RUNTIME_INSTR_H
+
+#define S390_RUNTIME_INSTR_START	0x1
+#define S390_RUNTIME_INSTR_STOP		0x2
+
+struct runtime_instr_cb {
+	__u64 buf_current;
+	__u64 buf_origin;
+	__u64 buf_limit;
+
+	__u32 valid		: 1;
+	__u32 pstate		: 1;
+	__u32 pstate_set_buf	: 1;
+	__u32 home_space	: 1;
+	__u32 altered		: 1;
+	__u32			: 3;
+	__u32 pstate_sample	: 1;
+	__u32 sstate_sample	: 1;
+	__u32 pstate_collect	: 1;
+	__u32 sstate_collect	: 1;
+	__u32			: 1;
+	__u32 halted_int	: 1;
+	__u32 int_requested	: 1;
+	__u32 buffer_full_int	: 1;
+	__u32 key		: 4;
+	__u32			: 9;
+	__u32 rgs		: 3;
+
+	__u32 mode		: 4;
+	__u32 next		: 1;
+	__u32 mae		: 1;
+	__u32			: 2;
+	__u32 call_type_br	: 1;
+	__u32 return_type_br	: 1;
+	__u32 other_type_br	: 1;
+	__u32 bc_other_type	: 1;
+	__u32 emit		: 1;
+	__u32 tx_abort		: 1;
+	__u32			: 2;
+	__u32 bp_xn		: 1;
+	__u32 bp_xt		: 1;
+	__u32 bp_ti		: 1;
+	__u32 bp_ni		: 1;
+	__u32 suppr_y		: 1;
+	__u32 suppr_z		: 1;
+
+	__u32 dc_miss_extra	: 1;
+	__u32 lat_lev_ignore	: 1;
+	__u32 ic_lat_lev	: 4;
+	__u32 dc_lat_lev	: 4;
+
+	__u64 reserved1;
+	__u64 scaling_factor;
+	__u64 rsic;
+	__u64 reserved2;
+} __packed __aligned(8);
+
+extern struct runtime_instr_cb runtime_instr_empty_cb;
+
+static inline void load_runtime_instr_cb(struct runtime_instr_cb *cb)
+{
+	asm volatile(".insn	rsy,0xeb0000000060,0,0,%0"	/* LRIC */
+		: : "Q" (*cb));
+}
+
+static inline void store_runtime_instr_cb(struct runtime_instr_cb *cb)
+{
+	asm volatile(".insn	rsy,0xeb0000000061,0,0,%0"	/* STRIC */
+		: "=Q" (*cb) : : "cc");
+}
+
+static inline void save_ri_cb(struct runtime_instr_cb *cb_prev)
+{
+#ifdef CONFIG_64BIT
+	if (cb_prev)
+		store_runtime_instr_cb(cb_prev);
+#endif
+}
+
+static inline void restore_ri_cb(struct runtime_instr_cb *cb_next,
+				 struct runtime_instr_cb *cb_prev)
+{
+#ifdef CONFIG_64BIT
+	if (cb_next)
+		load_runtime_instr_cb(cb_next);
+	else if (cb_prev)
+		load_runtime_instr_cb(&runtime_instr_empty_cb);
+#endif
+}
+
+#ifdef CONFIG_64BIT
+extern void exit_thread_runtime_instr(void);
+#else
+static inline void exit_thread_runtime_instr(void) { }
+#endif
+
+#endif /* _RUNTIME_INSTR_H */
diff --git a/arch/s390/include/asm/scsw.h b/arch/s390/include/asm/scsw.h
index 4071d00..4af99cd 100644
--- a/arch/s390/include/asm/scsw.h
+++ b/arch/s390/include/asm/scsw.h
@@ -1,7 +1,7 @@
 /*
  *  Helper functions for scsw access.
  *
- *    Copyright IBM Corp. 2008, 2009
+ *    Copyright IBM Corp. 2008, 2012
  *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
@@ -9,7 +9,7 @@
 #define _ASM_S390_SCSW_H_
 
 #include <linux/types.h>
-#include <asm/chsc.h>
+#include <asm/css_chars.h>
 #include <asm/cio.h>
 
 /**
@@ -100,14 +100,46 @@
 } __attribute__ ((packed));
 
 /**
+ * struct eadm_scsw - subchannel status word for eadm subchannels
+ * @key: subchannel key
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @ectl: extended control
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @aob: AOB address
+ * @dstat: device status
+ * @cstat: subchannel status
+ */
+struct eadm_scsw {
+	u32 key:4;
+	u32:1;
+	u32 eswf:1;
+	u32 cc:2;
+	u32:6;
+	u32 ectl:1;
+	u32:2;
+	u32 fctl:3;
+	u32 actl:7;
+	u32 stctl:5;
+	u32 aob;
+	u32 dstat:8;
+	u32 cstat:8;
+	u32:16;
+} __packed;
+
+/**
  * union scsw - subchannel status word
  * @cmd: command-mode SCSW
  * @tm: transport-mode SCSW
+ * @eadm: eadm SCSW
  */
 union scsw {
 	struct cmd_scsw cmd;
 	struct tm_scsw tm;
-} __attribute__ ((packed));
+	struct eadm_scsw eadm;
+} __packed;
 
 #define SCSW_FCTL_CLEAR_FUNC	 0x1
 #define SCSW_FCTL_HALT_FUNC	 0x2
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index e6859d1..87b47ca 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -60,7 +60,7 @@
 #define SECONDARY_SPACE_MODE	2
 #define HOME_SPACE_MODE		3
 
-extern unsigned int addressing_mode;
+extern unsigned int s390_user_mode;
 
 /*
  * Machine features detected in head.S
@@ -80,6 +80,7 @@
 #define MACHINE_FLAG_LPAR	(1UL << 12)
 #define MACHINE_FLAG_SPP	(1UL << 13)
 #define MACHINE_FLAG_TOPOLOGY	(1UL << 14)
+#define MACHINE_FLAG_TE		(1UL << 15)
 
 #define MACHINE_IS_VM		(S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM		(S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -98,6 +99,7 @@
 #define MACHINE_HAS_PFMF	(0)
 #define MACHINE_HAS_SPP		(0)
 #define MACHINE_HAS_TOPOLOGY	(0)
+#define MACHINE_HAS_TE		      (0)
 #else /* CONFIG_64BIT */
 #define MACHINE_HAS_IEEE	(1)
 #define MACHINE_HAS_CSP		(1)
@@ -109,6 +111,7 @@
 #define MACHINE_HAS_PFMF	(S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
 #define MACHINE_HAS_SPP		(S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
 #define MACHINE_HAS_TOPOLOGY	(S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
+#define MACHINE_HAS_TE		(S390_lowcore.machine_flags & MACHINE_FLAG_TE)
 #endif /* CONFIG_64BIT */
 
 #define ZFCPDUMP_HSA_SIZE	(32UL<<20)
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index ce26ac3..b64f15c 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -30,6 +30,8 @@
 extern void smp_yield_cpu(int cpu);
 extern void smp_yield(void);
 extern void smp_stop_cpu(void);
+extern void smp_cpu_set_polarization(int cpu, int val);
+extern int smp_cpu_get_polarization(int cpu);
 
 #else /* CONFIG_SMP */
 
@@ -43,7 +45,7 @@
 	func(data);
 }
 
-static inline int smp_find_processor_id(int address) { return 0; }
+static inline int smp_find_processor_id(u16 address) { return 0; }
 static inline int smp_store_status(int cpu) { return 0; }
 static inline int smp_vcpu_scheduled(int cpu) { return 1; }
 static inline void smp_yield_cpu(int cpu) { }
diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h
index 1bd1352..7e2dcd7 100644
--- a/arch/s390/include/asm/string.h
+++ b/arch/s390/include/asm/string.h
@@ -96,7 +96,6 @@
 
 static inline char *strcpy(char *dst, const char *src)
 {
-#if __GNUC__ < 4
 	register int r0 asm("0") = 0;
 	char *ret = dst;
 
@@ -106,14 +105,10 @@
 		: "+&a" (dst), "+&a" (src) : "d" (r0)
 		: "cc", "memory");
 	return ret;
-#else
-	return __builtin_strcpy(dst, src);
-#endif
 }
 
 static inline size_t strlen(const char *s)
 {
-#if __GNUC__ < 4
 	register unsigned long r0 asm("0") = 0;
 	const char *tmp = s;
 
@@ -122,9 +117,6 @@
 		"	jo	0b"
 		: "+d" (r0), "+a" (tmp) :  : "cc");
 	return r0 - (unsigned long) s;
-#else
-	return __builtin_strlen(s);
-#endif
 }
 
 static inline size_t strnlen(const char * s, size_t n)
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
index f223068..f3a9e0f 100644
--- a/arch/s390/include/asm/switch_to.h
+++ b/arch/s390/include/asm/switch_to.h
@@ -80,21 +80,19 @@
 	if (prev->mm) {							\
 		save_fp_regs(&prev->thread.fp_regs);			\
 		save_access_regs(&prev->thread.acrs[0]);		\
+		save_ri_cb(prev->thread.ri_cb);				\
 	}								\
 	if (next->mm) {							\
 		restore_fp_regs(&next->thread.fp_regs);			\
 		restore_access_regs(&next->thread.acrs[0]);		\
+		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
 		update_per_regs(next);					\
 	}								\
 	prev = __switch_to(prev,next);					\
 } while (0)
 
-extern void account_vtime(struct task_struct *, struct task_struct *);
-extern void account_tick_vtime(struct task_struct *);
-
 #define finish_arch_switch(prev) do {					     \
 	set_fs(current->thread.mm_segment);				     \
-	account_vtime(prev, current);					     \
 } while (0)
 
 #endif /* __ASM_SWITCH_TO_H */
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index 282ee36..f92428e 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -17,7 +17,10 @@
 #include <asm/bitsperlong.h>
 
 struct sysinfo_1_1_1 {
-	unsigned short :16;
+	unsigned char p:1;
+	unsigned char :6;
+	unsigned char t:1;
+	unsigned char :8;
 	unsigned char ccr;
 	unsigned char cai;
 	char reserved_0[28];
@@ -30,9 +33,14 @@
 	char model[16];
 	char model_perm_cap[16];
 	char model_temp_cap[16];
-	char model_cap_rating[4];
-	char model_perm_cap_rating[4];
-	char model_temp_cap_rating[4];
+	unsigned int model_cap_rating;
+	unsigned int model_perm_cap_rating;
+	unsigned int model_temp_cap_rating;
+	unsigned char typepct[5];
+	unsigned char reserved_2[3];
+	unsigned int ncr;
+	unsigned int npr;
+	unsigned int ntr;
 };
 
 struct sysinfo_1_2_1 {
@@ -47,8 +55,9 @@
 	char format;
 	char reserved_0[1];
 	unsigned short acc_offset;
-	char reserved_1[24];
-	unsigned int secondary_capability;
+	char reserved_1[20];
+	unsigned int nominal_cap;
+	unsigned int secondary_cap;
 	unsigned int capability;
 	unsigned short cpus_total;
 	unsigned short cpus_configured;
@@ -109,6 +118,8 @@
 	char reserved_544[3552];
 };
 
+extern int topology_max_mnest;
+
 #define TOPOLOGY_CPU_BITS	64
 #define TOPOLOGY_NR_MAG		6
 
@@ -142,21 +153,7 @@
 	union topology_entry tle[0];
 };
 
-static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
-{
-	register int r0 asm("0") = (fc << 28) | sel1;
-	register int r1 asm("1") = sel2;
-
-	asm volatile(
-		"   stsi 0(%2)\n"
-		"0: jz   2f\n"
-		"1: lhi  %0,%3\n"
-		"2:\n"
-		EX_TABLE(0b, 1b)
-		: "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS)
-		: "cc", "memory");
-	return r0;
-}
+int stsi(void *sysinfo, int fc, int sel1, int sel2);
 
 /*
  * Service level reporting interface.
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h
index 9fde315..1d8fe2b 100644
--- a/arch/s390/include/asm/tlbflush.h
+++ b/arch/s390/include/asm/tlbflush.h
@@ -90,12 +90,10 @@
 
 static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
 {
-	spin_lock(&mm->page_table_lock);
 	if (mm->context.flush_mm) {
 		__tlb_flush_mm(mm);
 		mm->context.flush_mm = 0;
 	}
-	spin_unlock(&mm->page_table_lock);
 }
 
 /*
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 0837de8..9ca3053 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -2,8 +2,8 @@
 #define _ASM_S390_TOPOLOGY_H
 
 #include <linux/cpumask.h>
-#include <asm/sysinfo.h>
 
+struct sysinfo_15_1_x;
 struct cpu;
 
 #ifdef CONFIG_SCHED_BOOK
@@ -51,24 +51,6 @@
 #define POLARIZATION_VM		(2)
 #define POLARIZATION_VH		(3)
 
-extern int cpu_polarization[];
-
-static inline void cpu_set_polarization(int cpu, int val)
-{
-#ifdef CONFIG_SCHED_BOOK
-	cpu_polarization[cpu] = val;
-#endif
-}
-
-static inline int cpu_read_polarization(int cpu)
-{
-#ifdef CONFIG_SCHED_BOOK
-	return cpu_polarization[cpu];
-#else
-	return POLARIZATION_HRZ;
-#endif
-}
-
 #ifdef CONFIG_SCHED_BOOK
 void s390_init_cpu_topology(void);
 #else
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index a8ab18b..34268df 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -76,9 +76,22 @@
 
 struct exception_table_entry
 {
-        unsigned long insn, fixup;
+	int insn, fixup;
 };
 
+static inline unsigned long extable_insn(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->insn + x->insn;
+}
+
+static inline unsigned long extable_fixup(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->fixup + x->fixup;
+}
+
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
+
 struct uaccess_ops {
 	size_t (*copy_from_user)(size_t, const void __user *, void *);
 	size_t (*copy_from_user_small)(size_t, const void __user *, void *);
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index 6756e78..4e64b5c 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -277,7 +277,9 @@
 #define __NR_setns		339
 #define __NR_process_vm_readv	340
 #define __NR_process_vm_writev	341
-#define NR_syscalls 342
+#define __NR_s390_runtime_instr 342
+#define __NR_kcmp		343
+#define NR_syscalls 344
 
 /* 
  * There are some system calls that are not present on 64 bit, some
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 9733b3f..4da52fe 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -23,10 +23,11 @@
 obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
 	    processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
 	    debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
-	    sysinfo.o jump_label.o lgr.o os_info.o
+	    sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
+obj-y	+= $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
 
 extra-y				+= head.o vmlinux.lds
 extra-y				+= $(if $(CONFIG_64BIT),head64.o,head31.o)
@@ -48,12 +49,11 @@
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
-obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o
 
-# Kexec part
-S390_KEXEC_OBJS := machine_kexec.o crash.o
-S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
-obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+ifdef CONFIG_64BIT
+obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o
+obj-y				+= runtime_instr.o cache.o
+endif
 
 # vdso
 obj-$(CONFIG_64BIT)		+= vdso64/
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 45ef1a7..fface87 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -157,6 +157,8 @@
 	DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr));
 	DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
 	DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
+	DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
+	DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
 	DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
 #endif /* CONFIG_32BIT */
 	return 0;
diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
new file mode 100644
index 0000000..8df8d8a1
--- /dev/null
+++ b/arch/s390/kernel/cache.c
@@ -0,0 +1,385 @@
+/*
+ * Extract CPU cache information and expose them via sysfs.
+ *
+ *    Copyright IBM Corp. 2012
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/notifier.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <asm/facility.h>
+
+struct cache {
+	unsigned long size;
+	unsigned int line_size;
+	unsigned int associativity;
+	unsigned int nr_sets;
+	unsigned int level   : 3;
+	unsigned int type    : 2;
+	unsigned int private : 1;
+	struct list_head list;
+};
+
+struct cache_dir {
+	struct kobject *kobj;
+	struct cache_index_dir *index;
+};
+
+struct cache_index_dir {
+	struct kobject kobj;
+	int cpu;
+	struct cache *cache;
+	struct cache_index_dir *next;
+};
+
+enum {
+	CACHE_SCOPE_NOTEXISTS,
+	CACHE_SCOPE_PRIVATE,
+	CACHE_SCOPE_SHARED,
+	CACHE_SCOPE_RESERVED,
+};
+
+enum {
+	CACHE_TYPE_SEPARATE,
+	CACHE_TYPE_DATA,
+	CACHE_TYPE_INSTRUCTION,
+	CACHE_TYPE_UNIFIED,
+};
+
+enum {
+	EXTRACT_TOPOLOGY,
+	EXTRACT_LINE_SIZE,
+	EXTRACT_SIZE,
+	EXTRACT_ASSOCIATIVITY,
+};
+
+enum {
+	CACHE_TI_UNIFIED = 0,
+	CACHE_TI_INSTRUCTION = 0,
+	CACHE_TI_DATA,
+};
+
+struct cache_info {
+	unsigned char	    : 4;
+	unsigned char scope : 2;
+	unsigned char type  : 2;
+};
+
+#define CACHE_MAX_LEVEL 8
+
+union cache_topology {
+	struct cache_info ci[CACHE_MAX_LEVEL];
+	unsigned long long raw;
+};
+
+static const char * const cache_type_string[] = {
+	"Data",
+	"Instruction",
+	"Unified",
+};
+
+static struct cache_dir *cache_dir_cpu[NR_CPUS];
+static LIST_HEAD(cache_list);
+
+void show_cacheinfo(struct seq_file *m)
+{
+	struct cache *cache;
+	int index = 0;
+
+	list_for_each_entry(cache, &cache_list, list) {
+		seq_printf(m, "cache%-11d: ", index);
+		seq_printf(m, "level=%d ", cache->level);
+		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
+		seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared");
+		seq_printf(m, "size=%luK ", cache->size >> 10);
+		seq_printf(m, "line_size=%u ", cache->line_size);
+		seq_printf(m, "associativity=%d", cache->associativity);
+		seq_puts(m, "\n");
+		index++;
+	}
+}
+
+static inline unsigned long ecag(int ai, int li, int ti)
+{
+	unsigned long cmd, val;
+
+	cmd = ai << 4 | li << 1 | ti;
+	asm volatile(".insn	rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */
+		     : "=d" (val) : "a" (cmd));
+	return val;
+}
+
+static int __init cache_add(int level, int private, int type)
+{
+	struct cache *cache;
+	int ti;
+
+	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
+	if (!cache)
+		return -ENOMEM;
+	ti = type == CACHE_TYPE_DATA ? CACHE_TI_DATA : CACHE_TI_UNIFIED;
+	cache->size = ecag(EXTRACT_SIZE, level, ti);
+	cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
+	cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
+	cache->nr_sets = cache->size / cache->associativity;
+	cache->nr_sets /= cache->line_size;
+	cache->private = private;
+	cache->level = level + 1;
+	cache->type = type - 1;
+	list_add_tail(&cache->list, &cache_list);
+	return 0;
+}
+
+static void __init cache_build_info(void)
+{
+	struct cache *cache, *next;
+	union cache_topology ct;
+	int level, private, rc;
+
+	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
+	for (level = 0; level < CACHE_MAX_LEVEL; level++) {
+		switch (ct.ci[level].scope) {
+		case CACHE_SCOPE_NOTEXISTS:
+		case CACHE_SCOPE_RESERVED:
+			return;
+		case CACHE_SCOPE_SHARED:
+			private = 0;
+			break;
+		case CACHE_SCOPE_PRIVATE:
+			private = 1;
+			break;
+		}
+		if (ct.ci[level].type == CACHE_TYPE_SEPARATE) {
+			rc  = cache_add(level, private, CACHE_TYPE_DATA);
+			rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION);
+		} else {
+			rc = cache_add(level, private, ct.ci[level].type);
+		}
+		if (rc)
+			goto error;
+	}
+	return;
+error:
+	list_for_each_entry_safe(cache, next, &cache_list, list) {
+		list_del(&cache->list);
+		kfree(cache);
+	}
+}
+
+static struct cache_dir *__cpuinit cache_create_cache_dir(int cpu)
+{
+	struct cache_dir *cache_dir;
+	struct kobject *kobj = NULL;
+	struct device *dev;
+
+	dev = get_cpu_device(cpu);
+	if (!dev)
+		goto out;
+	kobj = kobject_create_and_add("cache", &dev->kobj);
+	if (!kobj)
+		goto out;
+	cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL);
+	if (!cache_dir)
+		goto out;
+	cache_dir->kobj = kobj;
+	cache_dir_cpu[cpu] = cache_dir;
+	return cache_dir;
+out:
+	kobject_put(kobj);
+	return NULL;
+}
+
+static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj)
+{
+	return container_of(kobj, struct cache_index_dir, kobj);
+}
+
+static void cache_index_release(struct kobject *kobj)
+{
+	struct cache_index_dir *index;
+
+	index = kobj_to_cache_index_dir(kobj);
+	kfree(index);
+}
+
+static ssize_t cache_index_show(struct kobject *kobj,
+				struct attribute *attr, char *buf)
+{
+	struct kobj_attribute *kobj_attr;
+
+	kobj_attr = container_of(attr, struct kobj_attribute, attr);
+	return kobj_attr->show(kobj, kobj_attr, buf);
+}
+
+#define DEFINE_CACHE_ATTR(_name, _format, _value)			\
+static ssize_t cache_##_name##_show(struct kobject *kobj,		\
+				    struct kobj_attribute *attr,	\
+				    char *buf)				\
+{									\
+	struct cache_index_dir *index;					\
+									\
+	index = kobj_to_cache_index_dir(kobj);				\
+	return sprintf(buf, _format, _value);				\
+}									\
+static struct kobj_attribute cache_##_name##_attr =			\
+	__ATTR(_name, 0444, cache_##_name##_show, NULL);
+
+DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10);
+DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size);
+DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets);
+DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity);
+DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]);
+DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level);
+
+static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf)
+{
+	struct cache_index_dir *index;
+	int len;
+
+	index = kobj_to_cache_index_dir(kobj);
+	len = type ?
+		cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) :
+		cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu));
+	len += sprintf(&buf[len], "\n");
+	return len;
+}
+
+static ssize_t shared_cpu_map_show(struct kobject *kobj,
+				   struct kobj_attribute *attr, char *buf)
+{
+	return shared_cpu_map_func(kobj, 0, buf);
+}
+static struct kobj_attribute cache_shared_cpu_map_attr =
+	__ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL);
+
+static ssize_t shared_cpu_list_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	return shared_cpu_map_func(kobj, 1, buf);
+}
+static struct kobj_attribute cache_shared_cpu_list_attr =
+	__ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL);
+
+static struct attribute *cache_index_default_attrs[] = {
+	&cache_type_attr.attr,
+	&cache_size_attr.attr,
+	&cache_number_of_sets_attr.attr,
+	&cache_ways_of_associativity_attr.attr,
+	&cache_level_attr.attr,
+	&cache_coherency_line_size_attr.attr,
+	&cache_shared_cpu_map_attr.attr,
+	&cache_shared_cpu_list_attr.attr,
+	NULL,
+};
+
+static const struct sysfs_ops cache_index_ops = {
+	.show = cache_index_show,
+};
+
+static struct kobj_type cache_index_type = {
+	.sysfs_ops = &cache_index_ops,
+	.release = cache_index_release,
+	.default_attrs = cache_index_default_attrs,
+};
+
+static int __cpuinit cache_create_index_dir(struct cache_dir *cache_dir,
+					    struct cache *cache, int index,
+					    int cpu)
+{
+	struct cache_index_dir *index_dir;
+	int rc;
+
+	index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL);
+	if (!index_dir)
+		return -ENOMEM;
+	index_dir->cache = cache;
+	index_dir->cpu = cpu;
+	rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type,
+				  cache_dir->kobj, "index%d", index);
+	if (rc)
+		goto out;
+	index_dir->next = cache_dir->index;
+	cache_dir->index = index_dir;
+	return 0;
+out:
+	kfree(index_dir);
+	return rc;
+}
+
+static int __cpuinit cache_add_cpu(int cpu)
+{
+	struct cache_dir *cache_dir;
+	struct cache *cache;
+	int rc, index = 0;
+
+	if (list_empty(&cache_list))
+		return 0;
+	cache_dir = cache_create_cache_dir(cpu);
+	if (!cache_dir)
+		return -ENOMEM;
+	list_for_each_entry(cache, &cache_list, list) {
+		if (!cache->private)
+			break;
+		rc = cache_create_index_dir(cache_dir, cache, index, cpu);
+		if (rc)
+			return rc;
+		index++;
+	}
+	return 0;
+}
+
+static void __cpuinit cache_remove_cpu(int cpu)
+{
+	struct cache_index_dir *index, *next;
+	struct cache_dir *cache_dir;
+
+	cache_dir = cache_dir_cpu[cpu];
+	if (!cache_dir)
+		return;
+	index = cache_dir->index;
+	while (index) {
+		next = index->next;
+		kobject_put(&index->kobj);
+		index = next;
+	}
+	kobject_put(cache_dir->kobj);
+	kfree(cache_dir);
+	cache_dir_cpu[cpu] = NULL;
+}
+
+static int __cpuinit cache_hotplug(struct notifier_block *nfb,
+				   unsigned long action, void *hcpu)
+{
+	int cpu = (long)hcpu;
+	int rc = 0;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_ONLINE:
+		rc = cache_add_cpu(cpu);
+		if (rc)
+			cache_remove_cpu(cpu);
+		break;
+	case CPU_DEAD:
+		cache_remove_cpu(cpu);
+		break;
+	}
+	return rc ? NOTIFY_BAD : NOTIFY_OK;
+}
+
+static int __init cache_init(void)
+{
+	int cpu;
+
+	if (!test_facility(34))
+		return 0;
+	cache_build_info();
+	for_each_online_cpu(cpu)
+		cache_add_cpu(cpu);
+	hotcpu_notifier(cache_hotplug, 0);
+	return 0;
+}
+device_initcall(cache_init);
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 2d82cfc..3afba80 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1646,3 +1646,16 @@
 	llgf	%r0,164(%r15)		# unsigned long
 	stg	%r0,160(%r15)
 	jg	compat_sys_process_vm_writev
+
+ENTRY(sys_s390_runtime_instr_wrapper)
+	lgfr	%r2,%r2			# int
+	lgfr	%r3,%r3			# int
+	jg	sys_s390_runtime_instr
+
+ENTRY(sys_kcmp_wrapper)
+	lgfr	%r2,%r2			# pid_t
+	lgfr	%r3,%r3			# pid_t
+	lgfr	%r4,%r4			# int
+	llgfr	%r5,%r5			# unsigned long
+	llgfr	%r6,%r6			# unsigned long
+	jg	sys_kcmp
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
deleted file mode 100644
index 3819153..0000000
--- a/arch/s390/kernel/crash.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright IBM Corp. 2005
- *
- * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- *
- */
-
-#include <linux/threads.h>
-#include <linux/kexec.h>
-#include <linux/reboot.h>
-
-void machine_crash_shutdown(struct pt_regs *regs)
-{
-}
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index cc1172b..fb8d878 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -13,8 +13,9 @@
 #include <linux/slab.h>
 #include <linux/bootmem.h>
 #include <linux/elf.h>
-#include <asm/ipl.h>
 #include <asm/os_info.h>
+#include <asm/elf.h>
+#include <asm/ipl.h>
 
 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 619c5d3..cc84a24 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -315,6 +315,11 @@
 	LONG_INSN_POPCNT,
 	LONG_INSN_RISBHG,
 	LONG_INSN_RISBLG,
+	LONG_INSN_RINEXT,
+	LONG_INSN_RIEMIT,
+	LONG_INSN_TABORT,
+	LONG_INSN_TBEGIN,
+	LONG_INSN_TBEGINC,
 };
 
 static char *long_insn_name[] = {
@@ -329,7 +334,12 @@
 	[LONG_INSN_LLGHRL] = "llghrl",
 	[LONG_INSN_POPCNT] = "popcnt",
 	[LONG_INSN_RISBHG] = "risbhg",
-	[LONG_INSN_RISBLG] = "risblk",
+	[LONG_INSN_RISBLG] = "risblg",
+	[LONG_INSN_RINEXT] = "rinext",
+	[LONG_INSN_RIEMIT] = "riemit",
+	[LONG_INSN_TABORT] = "tabort",
+	[LONG_INSN_TBEGIN] = "tbegin",
+	[LONG_INSN_TBEGINC] = "tbeginc",
 };
 
 static struct insn opcode[] = {
@@ -582,6 +592,17 @@
 	{ "", 0, INSTR_INVALID }
 };
 
+static struct insn opcode_aa[] = {
+#ifdef CONFIG_64BIT
+	{ { 0, LONG_INSN_RINEXT }, 0x00, INSTR_RI_RI },
+	{ "rion", 0x01, INSTR_RI_RI },
+	{ "tric", 0x02, INSTR_RI_RI },
+	{ "rioff", 0x03, INSTR_RI_RI },
+	{ { 0, LONG_INSN_RIEMIT }, 0x04, INSTR_RI_RI },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
 static struct insn opcode_b2[] = {
 #ifdef CONFIG_64BIT
 	{ "sske", 0x2b, INSTR_RRF_M0RR },
@@ -594,6 +615,9 @@
 	{ "lpswe", 0xb2, INSTR_S_RD },
 	{ "srnmt", 0xb9, INSTR_S_RD },
 	{ "lfas", 0xbd, INSTR_S_RD },
+	{ "etndg", 0xec, INSTR_RRE_R0 },
+	{ { 0, LONG_INSN_TABORT }, 0xfc, INSTR_S_RD },
+	{ "tend", 0xf8, INSTR_S_RD },
 #endif
 	{ "stidp", 0x02, INSTR_S_RD },
 	{ "sck", 0x04, INSTR_S_RD },
@@ -1150,6 +1174,7 @@
 	{ "stfh", 0xcb, INSTR_RXY_RRRD },
 	{ "chf", 0xcd, INSTR_RXY_RRRD },
 	{ "clhf", 0xcf, INSTR_RXY_RRRD },
+	{ "ntstg", 0x25, INSTR_RXY_RRRD },
 #endif
 	{ "lrv", 0x1e, INSTR_RXY_RRRD },
 	{ "lrvh", 0x1f, INSTR_RXY_RRRD },
@@ -1173,6 +1198,8 @@
 	{ "mvhhi", 0x44, INSTR_SIL_RDI },
 	{ "mvhi", 0x4c, INSTR_SIL_RDI },
 	{ "mvghi", 0x48, INSTR_SIL_RDI },
+	{ { 0, LONG_INSN_TBEGIN }, 0x60, INSTR_SIL_RDU },
+	{ { 0, LONG_INSN_TBEGINC }, 0x61, INSTR_SIL_RDU },
 #endif
 	{ "lasp", 0x00, INSTR_SSE_RDRD },
 	{ "tprot", 0x01, INSTR_SSE_RDRD },
@@ -1210,6 +1237,9 @@
 	{ "cliy", 0x55, INSTR_SIY_URD },
 	{ "oiy", 0x56, INSTR_SIY_URD },
 	{ "xiy", 0x57, INSTR_SIY_URD },
+	{ "lric", 0x60, INSTR_RSY_RDRM },
+	{ "stric", 0x61, INSTR_RSY_RDRM },
+	{ "mric", 0x62, INSTR_RSY_RDRM },
 	{ "icmh", 0x80, INSTR_RSE_RURD },
 	{ "icmh", 0x80, INSTR_RSY_RURD },
 	{ "icmy", 0x81, INSTR_RSY_RURD },
@@ -1408,6 +1438,9 @@
 	case 0xa7:
 		table = opcode_a7;
 		break;
+	case 0xaa:
+		table = opcode_aa;
+		break;
 	case 0xb2:
 		table = opcode_b2;
 		break;
@@ -1601,3 +1634,26 @@
 	}
 	printk("\n");
 }
+
+void print_fn_code(unsigned char *code, unsigned long len)
+{
+	char buffer[64], *ptr;
+	int opsize, i;
+
+	while (len) {
+		ptr = buffer;
+		opsize = insn_length(*code);
+		ptr += sprintf(ptr, "%p: ", code);
+		for (i = 0; i < opsize; i++)
+			ptr += sprintf(ptr, "%02x", code[i]);
+		*ptr++ = '\t';
+		if (i < 4)
+			*ptr++ = '\t';
+		ptr += print_insn(ptr, code, (unsigned long) code);
+		*ptr++ = '\n';
+		*ptr++ = 0;
+		printk(buffer);
+		code += opsize;
+		len -= opsize;
+	}
+}
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 83c3271..7f47176 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -215,36 +215,54 @@
 				     PAGE_DEFAULT_KEY, 0);
 }
 
-static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
+static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE);
 
 static noinline __init void detect_machine_type(void)
 {
+	struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page;
+
 	/* Check current-configuration-level */
-	if ((stsi(NULL, 0, 0, 0) >> 28) <= 2) {
+	if (stsi(NULL, 0, 0, 0) <= 2) {
 		S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR;
 		return;
 	}
 	/* Get virtual-machine cpu information. */
-	if (stsi(&vmms, 3, 2, 2) == -ENOSYS || !vmms.count)
+	if (stsi(vmms, 3, 2, 2) || !vmms->count)
 		return;
 
 	/* Running under KVM? If not we assume z/VM */
-	if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))
+	if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_KVM;
 	else
 		S390_lowcore.machine_flags |= MACHINE_FLAG_VM;
 }
 
+static __init void setup_topology(void)
+{
+#ifdef CONFIG_64BIT
+	int max_mnest;
+
+	if (!test_facility(11))
+		return;
+	S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
+	for (max_mnest = 6; max_mnest > 1; max_mnest--) {
+		if (stsi(&sysinfo_page, 15, 1, max_mnest) == 0)
+			break;
+	}
+	topology_max_mnest = max_mnest;
+#endif
+}
+
 static void early_pgm_check_handler(void)
 {
-	unsigned long addr;
 	const struct exception_table_entry *fixup;
+	unsigned long addr;
 
 	addr = S390_lowcore.program_old_psw.addr;
 	fixup = search_exception_tables(addr & PSW_ADDR_INSN);
 	if (!fixup)
 		disabled_wait(0);
-	S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+	S390_lowcore.program_old_psw.addr = extable_fixup(fixup)|PSW_ADDR_AMODE;
 }
 
 static noinline __init void setup_lowcore_early(void)
@@ -267,12 +285,10 @@
 
 static noinline __init void setup_hpage(void)
 {
-#ifndef CONFIG_DEBUG_PAGEALLOC
 	if (!test_facility(2) || !test_facility(8))
 		return;
 	S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
 	__ctl_set_bit(0, 23);
-#endif
 }
 
 static __init void detect_mvpg(void)
@@ -366,12 +382,12 @@
 		S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
 	if (test_facility(8))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
-	if (test_facility(11))
-		S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
 	if (test_facility(27))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
 	if (test_facility(40))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
+	if (test_facility(50) && test_facility(73))
+		S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
 #endif
 }
 
@@ -441,7 +457,6 @@
 	append_to_cmdline(append_ipl_scpdata);
 }
 
-
 /*
  * Save ipl parameters, clear bss memory, initialize storage keys
  * and create a kernel NSS at startup if the SAVESYS= parm is defined
@@ -468,6 +483,7 @@
 	detect_diag44();
 	detect_machine_facilities();
 	setup_hpage();
+	setup_topology();
 	sclp_facilities_detect();
 	detect_memory_layout(memory_chunk);
 #ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 349b7ee..7549985 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <asm/processor.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
 #include <asm/ptrace.h>
@@ -412,6 +413,11 @@
 1:	UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER
 	LAST_BREAK %r14
 	lg	%r15,__LC_KERNEL_STACK
+	lg	%r14,__TI_task(%r12)
+	lghi	%r13,__LC_PGM_TDB
+	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
+	jz	2f
+	mvc	__THREAD_trap_tdb(256,%r14),0(%r13)
 2:	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
 	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	stmg	%r0,%r7,__PT_R0(%r11)
@@ -422,13 +428,12 @@
 	stg	%r10,__PT_ARGS(%r11)
 	tm	__LC_PGM_ILC+3,0x80	# check for per exception
 	jz	0f
-	lg	%r1,__TI_task(%r12)
 	tmhh	%r8,0x0001		# kernel per event ?
 	jz	pgm_kprobe
 	oi	__TI_flags+7(%r12),_TIF_PER_TRAP
-	mvc	__THREAD_per_address(8,%r1),__LC_PER_ADDRESS
-	mvc	__THREAD_per_cause(2,%r1),__LC_PER_CAUSE
-	mvc	__THREAD_per_paid(1,%r1),__LC_PER_PAID
+	mvc	__THREAD_per_address(8,%r14),__LC_PER_ADDRESS
+	mvc	__THREAD_per_cause(2,%r14),__LC_PER_CAUSE
+	mvc	__THREAD_per_paid(1,%r14),__LC_PER_PAID
 0:	REENABLE_IRQS
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 	larl	%r1,pgm_check_table
@@ -1004,9 +1009,7 @@
 .Lhost_id:
 	.quad	0
 
-	.section __ex_table,"a"
-	.quad	sie_loop,sie_fault
-	.previous
+	EX_TABLE(sie_loop,sie_fault)
 #endif
 
 		.section .rodata, "a"
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index dd7630d..6cdc55b 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -30,33 +30,35 @@
 };
 
 static const struct irq_class intrclass_names[] = {
-	{.name = "EXT" },
-	{.name = "I/O" },
-	{.name = "CLK", .desc = "[EXT] Clock Comparator" },
-	{.name = "EXC", .desc = "[EXT] External Call" },
-	{.name = "EMS", .desc = "[EXT] Emergency Signal" },
-	{.name = "TMR", .desc = "[EXT] CPU Timer" },
-	{.name = "TAL", .desc = "[EXT] Timing Alert" },
-	{.name = "PFL", .desc = "[EXT] Pseudo Page Fault" },
-	{.name = "DSD", .desc = "[EXT] DASD Diag" },
-	{.name = "VRT", .desc = "[EXT] Virtio" },
-	{.name = "SCP", .desc = "[EXT] Service Call" },
-	{.name = "IUC", .desc = "[EXT] IUCV" },
-	{.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling" },
-	{.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter" },
-	{.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" },
-	{.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" },
-	{.name = "DAS", .desc = "[I/O] DASD" },
-	{.name = "C15", .desc = "[I/O] 3215" },
-	{.name = "C70", .desc = "[I/O] 3270" },
-	{.name = "TAP", .desc = "[I/O] Tape" },
-	{.name = "VMR", .desc = "[I/O] Unit Record Devices" },
-	{.name = "LCS", .desc = "[I/O] LCS" },
-	{.name = "CLW", .desc = "[I/O] CLAW" },
-	{.name = "CTC", .desc = "[I/O] CTC" },
-	{.name = "APB", .desc = "[I/O] AP Bus" },
-	{.name = "CSC", .desc = "[I/O] CHSC Subchannel" },
-	{.name = "NMI", .desc = "[NMI] Machine Check" },
+	[EXTERNAL_INTERRUPT] = {.name = "EXT"},
+	[IO_INTERRUPT]	     = {.name = "I/O"},
+	[EXTINT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"},
+	[EXTINT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"},
+	[EXTINT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"},
+	[EXTINT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"},
+	[EXTINT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"},
+	[EXTINT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"},
+	[EXTINT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"},
+	[EXTINT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"},
+	[EXTINT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"},
+	[EXTINT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"},
+	[EXTINT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"},
+	[EXTINT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
+	[EXTINT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"},
+	[IOINT_CIO]  = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
+	[IOINT_QAI]  = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
+	[IOINT_DAS]  = {.name = "DAS", .desc = "[I/O] DASD"},
+	[IOINT_C15]  = {.name = "C15", .desc = "[I/O] 3215"},
+	[IOINT_C70]  = {.name = "C70", .desc = "[I/O] 3270"},
+	[IOINT_TAP]  = {.name = "TAP", .desc = "[I/O] Tape"},
+	[IOINT_VMR]  = {.name = "VMR", .desc = "[I/O] Unit Record Devices"},
+	[IOINT_LCS]  = {.name = "LCS", .desc = "[I/O] LCS"},
+	[IOINT_CLW]  = {.name = "CLW", .desc = "[I/O] CLAW"},
+	[IOINT_CTC]  = {.name = "CTC", .desc = "[I/O] CTC"},
+	[IOINT_APB]  = {.name = "APB", .desc = "[I/O] AP Bus"},
+	[IOINT_ADM]  = {.name = "ADM", .desc = "[I/O] EADM Subchannel"},
+	[IOINT_CSC]  = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"},
+	[NMI_NMI]    = {.name = "NMI", .desc = "[NMI] Machine Check"},
 };
 
 /*
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 8aa634f..d1c7214 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -547,7 +547,7 @@
 		 */
 		entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
 		if (entry) {
-			regs->psw.addr = entry->fixup | PSW_ADDR_AMODE;
+			regs->psw.addr = extable_fixup(entry) | PSW_ADDR_AMODE;
 			return 1;
 		}
 
diff --git a/arch/s390/kernel/lgr.c b/arch/s390/kernel/lgr.c
index eca94e7..6ea6d69 100644
--- a/arch/s390/kernel/lgr.c
+++ b/arch/s390/kernel/lgr.c
@@ -51,16 +51,6 @@
 static struct debug_info *lgr_dbf;
 
 /*
- * Return number of valid stsi levels
- */
-static inline int stsi_0(void)
-{
-	int rc = stsi(NULL, 0, 0, 0);
-
-	return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
-}
-
-/*
  * Copy buffer and then convert it to ASCII
  */
 static void cpascii(char *dst, char *src, int size)
@@ -76,7 +66,7 @@
 {
 	struct sysinfo_1_1_1 *si = (void *) lgr_page;
 
-	if (stsi(si, 1, 1, 1) == -ENOSYS)
+	if (stsi(si, 1, 1, 1))
 		return;
 	cpascii(lgr_info->manufacturer, si->manufacturer,
 		sizeof(si->manufacturer));
@@ -93,7 +83,7 @@
 {
 	struct sysinfo_2_2_2 *si = (void *) lgr_page;
 
-	if (stsi(si, 2, 2, 2) == -ENOSYS)
+	if (stsi(si, 2, 2, 2))
 		return;
 	cpascii(lgr_info->name, si->name, sizeof(si->name));
 	memcpy(&lgr_info->lpar_number, &si->lpar_number,
@@ -108,7 +98,7 @@
 	struct sysinfo_3_2_2 *si = (void *) lgr_page;
 	int i;
 
-	if (stsi(si, 3, 2, 2) == -ENOSYS)
+	if (stsi(si, 3, 2, 2))
 		return;
 	for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) {
 		cpascii(lgr_info->vm[i].name, si->vm[i].name,
@@ -124,16 +114,17 @@
  */
 static void lgr_info_get(struct lgr_info *lgr_info)
 {
+	int level;
+
 	memset(lgr_info, 0, sizeof(*lgr_info));
 	stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list));
-	lgr_info->level = stsi_0();
-	if (lgr_info->level == -ENOSYS)
-		return;
-	if (lgr_info->level >= 1)
+	level = stsi(NULL, 0, 0, 0);
+	lgr_info->level = level;
+	if (level >= 1)
 		lgr_stsi_1_1_1(lgr_info);
-	if (lgr_info->level >= 2)
+	if (level >= 2)
 		lgr_stsi_2_2_2(lgr_info);
-	if (lgr_info->level >= 3)
+	if (level >= 3)
 		lgr_stsi_3_2_2(lgr_info);
 }
 
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index 493304b..b3de277 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -21,6 +21,7 @@
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/diag.h>
+#include <asm/elf.h>
 #include <asm/asm-offsets.h>
 #include <asm/os_info.h>
 
@@ -31,8 +32,6 @@
 
 #ifdef CONFIG_CRASH_DUMP
 
-void *fill_cpu_elf_notes(void *ptr, struct save_area *sa);
-
 /*
  * Create ELF notes for one CPU
  */
@@ -159,7 +158,7 @@
 
 	/* Can't replace kernel image since it is read-only. */
 	if (ipl_flags & IPL_NSS_VALID)
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
 	if (image->type == KEXEC_TYPE_CRASH)
 		return machine_kexec_prepare_kdump();
@@ -191,6 +190,10 @@
 {
 }
 
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
 /*
  * Do normal kexec
  */
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 7331753..5024be2 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -26,10 +26,12 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/vtimer.h>
+#include <asm/exec.h>
 #include <asm/irq.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/switch_to.h>
+#include <asm/runtime_instr.h>
 #include "entry.h"
 
 asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
@@ -132,6 +134,7 @@
  */
 void exit_thread(void)
 {
+	exit_thread_runtime_instr();
 }
 
 void flush_thread(void)
@@ -170,6 +173,11 @@
 	/* Save access registers to new thread structure. */
 	save_access_regs(&p->thread.acrs[0]);
 
+	/* Don't copy runtime instrumentation info */
+	p->thread.ri_cb = NULL;
+	p->thread.ri_signum = 0;
+	frame->childregs.psw.mask &= ~PSW_MASK_RI;
+
 #ifndef CONFIG_64BIT
 	/*
 	 * save fprs to current->thread.fp_regs to merge them with
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index 572d4c9..753c41d 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -39,9 +39,9 @@
  */
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-	static const char *hwcap_str[10] = {
+	static const char *hwcap_str[] = {
 		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
-		"edat", "etf3eh", "highgprs"
+		"edat", "etf3eh", "highgprs", "te"
 	};
 	unsigned long n = (unsigned long) v - 1;
 	int i;
@@ -54,10 +54,11 @@
 			   num_online_cpus(), loops_per_jiffy/(500000/HZ),
 			   (loops_per_jiffy/(5000/HZ))%100);
 		seq_puts(m, "features\t: ");
-		for (i = 0; i < 10; i++)
+		for (i = 0; i < ARRAY_SIZE(hwcap_str); i++)
 			if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
 				seq_printf(m, "%s ", hwcap_str[i]);
 		seq_puts(m, "\n");
+		show_cacheinfo(m);
 	}
 	get_online_cpus();
 	if (cpu_online(n)) {
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index e4be113..a314c57 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -42,6 +42,7 @@
 	REGSET_GENERAL,
 	REGSET_FP,
 	REGSET_LAST_BREAK,
+	REGSET_TDB,
 	REGSET_SYSTEM_CALL,
 	REGSET_GENERAL_EXTENDED,
 };
@@ -52,6 +53,22 @@
 	struct thread_struct *thread = &task->thread;
 	struct per_regs old, new;
 
+#ifdef CONFIG_64BIT
+	/* Take care of the enable/disable of transactional execution. */
+	if (MACHINE_HAS_TE) {
+		unsigned long cr0, cr0_new;
+
+		__ctl_store(cr0, 0, 0);
+		/* set or clear transaction execution bits 8 and 9. */
+		if (task->thread.per_flags & PER_FLAG_NO_TE)
+			cr0_new = cr0 & ~(3UL << 54);
+		else
+			cr0_new = cr0 | (3UL << 54);
+		/* Only load control register 0 if necessary. */
+		if (cr0 != cr0_new)
+			__ctl_load(cr0_new, 0, 0);
+	}
+#endif
 	/* Copy user specified PER registers */
 	new.control = thread->per_user.control;
 	new.start = thread->per_user.start;
@@ -60,6 +77,10 @@
 	/* merge TIF_SINGLE_STEP into user specified PER registers. */
 	if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
 		new.control |= PER_EVENT_IFETCH;
+#ifdef CONFIG_64BIT
+		new.control |= PER_CONTROL_SUSPENSION;
+		new.control |= PER_EVENT_TRANSACTION_END;
+#endif
 		new.start = 0;
 		new.end = PSW_ADDR_INSN;
 	}
@@ -100,6 +121,7 @@
 	memset(&task->thread.per_event, 0, sizeof(task->thread.per_event));
 	clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
 	clear_tsk_thread_flag(task, TIF_PER_TRAP);
+	task->thread.per_flags = 0;
 }
 
 #ifndef CONFIG_64BIT
@@ -416,6 +438,16 @@
 		put_user(task_thread_info(child)->last_break,
 			 (unsigned long __user *) data);
 		return 0;
+	case PTRACE_ENABLE_TE:
+		if (!MACHINE_HAS_TE)
+			return -EIO;
+		child->thread.per_flags &= ~PER_FLAG_NO_TE;
+		return 0;
+	case PTRACE_DISABLE_TE:
+		if (!MACHINE_HAS_TE)
+			return -EIO;
+		child->thread.per_flags |= PER_FLAG_NO_TE;
+		return 0;
 	default:
 		/* Removing high order bit from addr (only for 31 bit). */
 		addr &= PSW_ADDR_INSN;
@@ -903,6 +935,28 @@
 	return 0;
 }
 
+static int s390_tdb_get(struct task_struct *target,
+			const struct user_regset *regset,
+			unsigned int pos, unsigned int count,
+			void *kbuf, void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+	unsigned char *data;
+
+	if (!(regs->int_code & 0x200))
+		return -ENODATA;
+	data = target->thread.trap_tdb;
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256);
+}
+
+static int s390_tdb_set(struct task_struct *target,
+			const struct user_regset *regset,
+			unsigned int pos, unsigned int count,
+			const void *kbuf, const void __user *ubuf)
+{
+	return 0;
+}
+
 #endif
 
 static int s390_system_call_get(struct task_struct *target,
@@ -951,6 +1005,14 @@
 		.get = s390_last_break_get,
 		.set = s390_last_break_set,
 	},
+	[REGSET_TDB] = {
+		.core_note_type = NT_S390_TDB,
+		.n = 1,
+		.size = 256,
+		.align = 1,
+		.get = s390_tdb_get,
+		.set = s390_tdb_set,
+	},
 #endif
 	[REGSET_SYSTEM_CALL] = {
 		.core_note_type = NT_S390_SYSTEM_CALL,
@@ -1148,6 +1210,14 @@
 		.get = s390_compat_last_break_get,
 		.set = s390_compat_last_break_set,
 	},
+	[REGSET_TDB] = {
+		.core_note_type = NT_S390_TDB,
+		.n = 1,
+		.size = 256,
+		.align = 1,
+		.get = s390_tdb_get,
+		.set = s390_tdb_set,
+	},
 	[REGSET_SYSTEM_CALL] = {
 		.core_note_type = NT_S390_SYSTEM_CALL,
 		.n = 1,
diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c
new file mode 100644
index 0000000..61066f6
--- /dev/null
+++ b/arch/s390/kernel/runtime_instr.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright IBM Corp. 2012
+ * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <asm/runtime_instr.h>
+#include <asm/cpu_mf.h>
+#include <asm/irq.h>
+
+/* empty control block to disable RI by loading it */
+struct runtime_instr_cb runtime_instr_empty_cb;
+
+static int runtime_instr_avail(void)
+{
+	return test_facility(64);
+}
+
+static void disable_runtime_instr(void)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+
+	load_runtime_instr_cb(&runtime_instr_empty_cb);
+
+	/*
+	 * Make sure the RI bit is deleted from the PSW. If the user did not
+	 * switch off RI before the system call the process will get a
+	 * specification exception otherwise.
+	 */
+	regs->psw.mask &= ~PSW_MASK_RI;
+}
+
+static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
+{
+	cb->buf_limit = 0xfff;
+	if (s390_user_mode == HOME_SPACE_MODE)
+		cb->home_space = 1;
+	cb->int_requested = 1;
+	cb->pstate = 1;
+	cb->pstate_set_buf = 1;
+	cb->pstate_sample = 1;
+	cb->pstate_collect = 1;
+	cb->key = PAGE_DEFAULT_KEY;
+	cb->valid = 1;
+}
+
+void exit_thread_runtime_instr(void)
+{
+	struct task_struct *task = current;
+
+	if (!task->thread.ri_cb)
+		return;
+	disable_runtime_instr();
+	kfree(task->thread.ri_cb);
+	task->thread.ri_signum = 0;
+	task->thread.ri_cb = NULL;
+}
+
+static void runtime_instr_int_handler(struct ext_code ext_code,
+				unsigned int param32, unsigned long param64)
+{
+	struct siginfo info;
+
+	if (!(param32 & CPU_MF_INT_RI_MASK))
+		return;
+
+	kstat_cpu(smp_processor_id()).irqs[EXTINT_CMR]++;
+
+	if (!current->thread.ri_cb)
+		return;
+	if (current->thread.ri_signum < SIGRTMIN ||
+	    current->thread.ri_signum > SIGRTMAX) {
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.si_signo = current->thread.ri_signum;
+	info.si_code = SI_QUEUE;
+	if (param32 & CPU_MF_INT_RI_BUF_FULL)
+		info.si_int = ENOBUFS;
+	else if (param32 & CPU_MF_INT_RI_HALTED)
+		info.si_int = ECANCELED;
+	else
+		return; /* unknown reason */
+
+	send_sig_info(current->thread.ri_signum, &info, current);
+}
+
+SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum)
+{
+	struct runtime_instr_cb *cb;
+
+	if (!runtime_instr_avail())
+		return -EOPNOTSUPP;
+
+	if (command == S390_RUNTIME_INSTR_STOP) {
+		preempt_disable();
+		exit_thread_runtime_instr();
+		preempt_enable();
+		return 0;
+	}
+
+	if (command != S390_RUNTIME_INSTR_START ||
+	    (signum < SIGRTMIN || signum > SIGRTMAX))
+		return -EINVAL;
+
+	if (!current->thread.ri_cb) {
+		cb = kzalloc(sizeof(*cb), GFP_KERNEL);
+		if (!cb)
+			return -ENOMEM;
+	} else {
+		cb = current->thread.ri_cb;
+		memset(cb, 0, sizeof(*cb));
+	}
+
+	init_runtime_instr_cb(cb);
+	current->thread.ri_signum = signum;
+
+	/* now load the control block to make it available */
+	preempt_disable();
+	current->thread.ri_cb = cb;
+	load_runtime_instr_cb(cb);
+	preempt_enable();
+	return 0;
+}
+
+static int __init runtime_instr_init(void)
+{
+	int rc;
+
+	if (!runtime_instr_avail())
+		return 0;
+
+	measurement_alert_subclass_register();
+	rc = register_external_interrupt(0x1407, runtime_instr_int_handler);
+	if (rc)
+		measurement_alert_subclass_unregister();
+	else
+		pr_info("Runtime instrumentation facility initialized\n");
+	return rc;
+}
+device_initcall(runtime_instr_init);
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 57b5366..9bdbcef 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -8,3 +8,5 @@
 #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
 EXPORT_SYMBOL(sie64a);
 #endif
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index f86c81e..afa9fdb 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -302,10 +302,10 @@
 }
 early_param("vmalloc", parse_vmalloc);
 
-unsigned int addressing_mode = HOME_SPACE_MODE;
-EXPORT_SYMBOL_GPL(addressing_mode);
+unsigned int s390_user_mode = PRIMARY_SPACE_MODE;
+EXPORT_SYMBOL_GPL(s390_user_mode);
 
-static int set_amode_primary(void)
+static void __init set_user_mode_primary(void)
 {
 	psw_kernel_bits = (psw_kernel_bits & ~PSW_MASK_ASC) | PSW_ASC_HOME;
 	psw_user_bits = (psw_user_bits & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY;
@@ -313,48 +313,30 @@
 	psw32_user_bits =
 		(psw32_user_bits & ~PSW32_MASK_ASC) | PSW32_ASC_PRIMARY;
 #endif
-
-	if (MACHINE_HAS_MVCOS) {
-		memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
-		return 1;
-	} else {
-		memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
-		return 0;
-	}
+	uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos_switch : uaccess_pt;
 }
 
-/*
- * Switch kernel/user addressing modes?
- */
-static int __init early_parse_switch_amode(char *p)
-{
-	addressing_mode = PRIMARY_SPACE_MODE;
-	return 0;
-}
-early_param("switch_amode", early_parse_switch_amode);
-
 static int __init early_parse_user_mode(char *p)
 {
 	if (p && strcmp(p, "primary") == 0)
-		addressing_mode = PRIMARY_SPACE_MODE;
+		s390_user_mode = PRIMARY_SPACE_MODE;
 	else if (!p || strcmp(p, "home") == 0)
-		addressing_mode = HOME_SPACE_MODE;
+		s390_user_mode = HOME_SPACE_MODE;
 	else
 		return 1;
 	return 0;
 }
 early_param("user_mode", early_parse_user_mode);
 
-static void setup_addressing_mode(void)
+static void __init setup_addressing_mode(void)
 {
-	if (addressing_mode == PRIMARY_SPACE_MODE) {
-		if (set_amode_primary())
-			pr_info("Address spaces switched, "
-				"mvcos available\n");
-		else
-			pr_info("Address spaces switched, "
-				"mvcos not available\n");
-	}
+	if (s390_user_mode != PRIMARY_SPACE_MODE)
+		return;
+	set_user_mode_primary();
+	if (MACHINE_HAS_MVCOS)
+		pr_info("Address spaces switched, mvcos available\n");
+	else
+		pr_info("Address spaces switched, mvcos not available\n");
 }
 
 void *restart_stack __attribute__((__section__(".data")));
@@ -602,9 +584,7 @@
 
 static void __init setup_vmcoreinfo(void)
 {
-#ifdef CONFIG_KEXEC
 	mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
-#endif
 }
 
 #ifdef CONFIG_CRASH_DUMP
@@ -974,12 +954,20 @@
 	if (MACHINE_HAS_HPAGE)
 		elf_hwcap |= HWCAP_S390_HPAGE;
 
+#if defined(CONFIG_64BIT)
 	/*
 	 * 64-bit register support for 31-bit processes
 	 * HWCAP_S390_HIGH_GPRS is bit 9.
 	 */
 	elf_hwcap |= HWCAP_S390_HIGH_GPRS;
 
+	/*
+	 * Transactional execution support HWCAP_S390_TE is bit 10.
+	 */
+	if (test_facility(50) && test_facility(73))
+		elf_hwcap |= HWCAP_S390_TE;
+#endif
+
 	get_cpu_id(&cpu_id);
 	switch (cpu_id.machine) {
 	case 0x9672:
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 720fda1..ea431e5 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -66,7 +66,7 @@
 	unsigned long panic_stack;	/* panic stack for the cpu */
 	unsigned long ec_mask;		/* bit mask for ec_xxx functions */
 	int state;			/* physical cpu state */
-	u32 status;			/* last status received via sigp */
+	int polarization;		/* physical polarization */
 	u16 address;			/* physical cpu address */
 };
 
@@ -74,6 +74,10 @@
 static u16 boot_cpu_address;
 static struct pcpu pcpu_devices[NR_CPUS];
 
+/*
+ * The smp_cpu_state_mutex must be held when changing the state or polarization
+ * member of a pcpu data structure within the pcpu_devices arreay.
+ */
 DEFINE_MUTEX(smp_cpu_state_mutex);
 
 /*
@@ -99,7 +103,7 @@
 	int cc;
 
 	while (1) {
-		cc = __pcpu_sigp(addr, order, parm, status);
+		cc = __pcpu_sigp(addr, order, parm, NULL);
 		if (cc != SIGP_CC_BUSY)
 			return cc;
 		cpu_relax();
@@ -111,7 +115,7 @@
 	int cc, retry;
 
 	for (retry = 0; ; retry++) {
-		cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status);
+		cc = __pcpu_sigp(pcpu->address, order, parm, NULL);
 		if (cc != SIGP_CC_BUSY)
 			break;
 		if (retry >= 3)
@@ -122,16 +126,18 @@
 
 static inline int pcpu_stopped(struct pcpu *pcpu)
 {
+	u32 uninitialized_var(status);
+
 	if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
-			0, &pcpu->status) != SIGP_CC_STATUS_STORED)
+			0, &status) != SIGP_CC_STATUS_STORED)
 		return 0;
-	return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
+	return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
 }
 
 static inline int pcpu_running(struct pcpu *pcpu)
 {
 	if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
-			0, &pcpu->status) != SIGP_CC_STATUS_STORED)
+			0, NULL) != SIGP_CC_STATUS_STORED)
 		return 1;
 	/* Status stored condition code is equivalent to cpu not running. */
 	return 0;
@@ -586,6 +592,16 @@
 
 #endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
 
+void smp_cpu_set_polarization(int cpu, int val)
+{
+	pcpu_devices[cpu].polarization = val;
+}
+
+int smp_cpu_get_polarization(int cpu)
+{
+	return pcpu_devices[cpu].polarization;
+}
+
 static struct sclp_cpu_info *smp_get_cpu_info(void)
 {
 	static int use_sigp_detection;
@@ -628,7 +644,7 @@
 		pcpu->address = info->cpu[i].address;
 		pcpu->state = (cpu >= info->configured) ?
 			CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
-		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 		set_cpu_present(cpu, true);
 		if (sysfs_add && smp_add_present_cpu(cpu) != 0)
 			set_cpu_present(cpu, false);
@@ -796,7 +812,7 @@
 	pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE;
 	pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE;
 	S390_lowcore.percpu_offset = __per_cpu_offset[0];
-	cpu_set_polarization(0, POLARIZATION_UNKNOWN);
+	smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
 	set_cpu_present(0, true);
 	set_cpu_online(0, true);
 }
@@ -862,7 +878,7 @@
 		if (rc)
 			break;
 		pcpu->state = CPU_STATE_STANDBY;
-		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 		topology_expect_change();
 		break;
 	case 1:
@@ -872,7 +888,7 @@
 		if (rc)
 			break;
 		pcpu->state = CPU_STATE_CONFIGURED;
-		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 		topology_expect_change();
 		break;
 	default:
@@ -959,23 +975,17 @@
 	struct device *s = &c->dev;
 	int err = 0;
 
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
 		err = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
 		break;
 	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
 		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
 		break;
 	}
 	return notifier_from_errno(err);
 }
 
-static struct notifier_block __cpuinitdata smp_cpu_nb = {
-	.notifier_call = smp_cpu_notify,
-};
-
 static int __devinit smp_add_present_cpu(int cpu)
 {
 	struct cpu *c = &pcpu_devices[cpu].cpu;
@@ -1050,7 +1060,7 @@
 {
 	int cpu, rc;
 
-	register_cpu_notifier(&smp_cpu_nb);
+	hotcpu_notifier(smp_cpu_notify, 0);
 #ifdef CONFIG_HOTPLUG_CPU
 	rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan);
 	if (rc)
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index bcab2f0..4817485 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -350,3 +350,5 @@
 SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
 SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
 SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
+SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
+SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c
index fa0eb23..62f89d9 100644
--- a/arch/s390/kernel/sysinfo.c
+++ b/arch/s390/kernel/sysinfo.c
@@ -22,17 +22,41 @@
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 
-static inline int stsi_0(void)
+int topology_max_mnest;
+
+/*
+ * stsi - store system information
+ *
+ * Returns the current configuration level if function code 0 was specified.
+ * Otherwise returns 0 on success or a negative value on error.
+ */
+int stsi(void *sysinfo, int fc, int sel1, int sel2)
 {
-	int rc = stsi(NULL, 0, 0, 0);
-	return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
+	register int r0 asm("0") = (fc << 28) | sel1;
+	register int r1 asm("1") = sel2;
+	int rc = 0;
+
+	asm volatile(
+		"	stsi	0(%3)\n"
+		"0:	jz	2f\n"
+		"1:	lhi	%1,%4\n"
+		"2:\n"
+		EX_TABLE(0b, 1b)
+		: "+d" (r0), "+d" (rc)
+		: "d" (r1), "a" (sysinfo), "K" (-EOPNOTSUPP)
+		: "cc", "memory");
+	if (rc)
+		return rc;
+	return fc ? 0 : ((unsigned int) r0) >> 28;
 }
+EXPORT_SYMBOL(stsi);
 
-static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
+static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
 {
-	if (stsi(info, 1, 1, 1) == -ENOSYS)
-		return len;
+	int i;
 
+	if (stsi(info, 1, 1, 1))
+		return;
 	EBCASC(info->manufacturer, sizeof(info->manufacturer));
 	EBCASC(info->type, sizeof(info->type));
 	EBCASC(info->model, sizeof(info->model));
@@ -41,242 +65,197 @@
 	EBCASC(info->model_capacity, sizeof(info->model_capacity));
 	EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
 	EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
-	len += sprintf(page + len, "Manufacturer:         %-16.16s\n",
-		       info->manufacturer);
-	len += sprintf(page + len, "Type:                 %-4.4s\n",
-		       info->type);
+	seq_printf(m, "Manufacturer:         %-16.16s\n", info->manufacturer);
+	seq_printf(m, "Type:                 %-4.4s\n", info->type);
+	/*
+	 * Sigh: the model field has been renamed with System z9
+	 * to model_capacity and a new model field has been added
+	 * after the plant field. To avoid confusing older programs
+	 * the "Model:" prints "model_capacity model" or just
+	 * "model_capacity" if the model string is empty .
+	 */
+	seq_printf(m, "Model:                %-16.16s", info->model_capacity);
 	if (info->model[0] != '\0')
-		/*
-		 * Sigh: the model field has been renamed with System z9
-		 * to model_capacity and a new model field has been added
-		 * after the plant field. To avoid confusing older programs
-		 * the "Model:" prints "model_capacity model" or just
-		 * "model_capacity" if the model string is empty .
-		 */
-		len += sprintf(page + len,
-			       "Model:                %-16.16s %-16.16s\n",
-			       info->model_capacity, info->model);
-	else
-		len += sprintf(page + len, "Model:                %-16.16s\n",
-			       info->model_capacity);
-	len += sprintf(page + len, "Sequence Code:        %-16.16s\n",
-		       info->sequence);
-	len += sprintf(page + len, "Plant:                %-4.4s\n",
-		       info->plant);
-	len += sprintf(page + len, "Model Capacity:       %-16.16s %08u\n",
-		       info->model_capacity, *(u32 *) info->model_cap_rating);
-	if (info->model_perm_cap[0] != '\0')
-		len += sprintf(page + len,
-			       "Model Perm. Capacity: %-16.16s %08u\n",
-			       info->model_perm_cap,
-			       *(u32 *) info->model_perm_cap_rating);
-	if (info->model_temp_cap[0] != '\0')
-		len += sprintf(page + len,
-			       "Model Temp. Capacity: %-16.16s %08u\n",
-			       info->model_temp_cap,
-			       *(u32 *) info->model_temp_cap_rating);
+		seq_printf(m, " %-16.16s", info->model);
+	seq_putc(m, '\n');
+	seq_printf(m, "Sequence Code:        %-16.16s\n", info->sequence);
+	seq_printf(m, "Plant:                %-4.4s\n", info->plant);
+	seq_printf(m, "Model Capacity:       %-16.16s %08u\n",
+		   info->model_capacity, info->model_cap_rating);
+	if (info->model_perm_cap_rating)
+		seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n",
+			   info->model_perm_cap,
+			   info->model_perm_cap_rating);
+	if (info->model_temp_cap_rating)
+		seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n",
+			   info->model_temp_cap,
+			   info->model_temp_cap_rating);
+	if (info->ncr)
+		seq_printf(m, "Nominal Cap. Rating:  %08u\n", info->ncr);
+	if (info->npr)
+		seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr);
+	if (info->ntr)
+		seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr);
 	if (info->cai) {
-		len += sprintf(page + len,
-			       "Capacity Adj. Ind.:   %d\n",
-			       info->cai);
-		len += sprintf(page + len, "Capacity Ch. Reason:  %d\n",
-			       info->ccr);
+		seq_printf(m, "Capacity Adj. Ind.:   %d\n", info->cai);
+		seq_printf(m, "Capacity Ch. Reason:  %d\n", info->ccr);
+		seq_printf(m, "Capacity Transient:   %d\n", info->t);
 	}
-	return len;
+	if (info->p) {
+		for (i = 1; i <= ARRAY_SIZE(info->typepct); i++) {
+			seq_printf(m, "Type %d Percentage:    %d\n",
+				   i, info->typepct[i - 1]);
+		}
+	}
 }
 
-static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
+static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
 {
 	static int max_mnest;
 	int i, rc;
 
-	len += sprintf(page + len, "\n");
+	seq_putc(m, '\n');
 	if (!MACHINE_HAS_TOPOLOGY)
-		return len;
-	if (max_mnest) {
-		stsi(info, 15, 1, max_mnest);
-	} else {
-		for (max_mnest = 6; max_mnest > 1; max_mnest--) {
-			rc = stsi(info, 15, 1, max_mnest);
-			if (rc != -ENOSYS)
-				break;
-		}
-	}
-	len += sprintf(page + len, "CPU Topology HW:     ");
+		return;
+	if (stsi(info, 15, 1, topology_max_mnest))
+		return;
+	seq_printf(m, "CPU Topology HW:     ");
 	for (i = 0; i < TOPOLOGY_NR_MAG; i++)
-		len += sprintf(page + len, " %d", info->mag[i]);
-	len += sprintf(page + len, "\n");
+		seq_printf(m, " %d", info->mag[i]);
+	seq_putc(m, '\n');
 #ifdef CONFIG_SCHED_MC
 	store_topology(info);
-	len += sprintf(page + len, "CPU Topology SW:     ");
+	seq_printf(m, "CPU Topology SW:     ");
 	for (i = 0; i < TOPOLOGY_NR_MAG; i++)
-		len += sprintf(page + len, " %d", info->mag[i]);
-	len += sprintf(page + len, "\n");
+		seq_printf(m, " %d", info->mag[i]);
+	seq_putc(m, '\n');
 #endif
-	return len;
 }
 
-static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
+static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info)
 {
 	struct sysinfo_1_2_2_extension *ext;
 	int i;
 
-	if (stsi(info, 1, 2, 2) == -ENOSYS)
-		return len;
+	if (stsi(info, 1, 2, 2))
+		return;
 	ext = (struct sysinfo_1_2_2_extension *)
 		((unsigned long) info + info->acc_offset);
-
-	len += sprintf(page + len, "CPUs Total:           %d\n",
-		       info->cpus_total);
-	len += sprintf(page + len, "CPUs Configured:      %d\n",
-		       info->cpus_configured);
-	len += sprintf(page + len, "CPUs Standby:         %d\n",
-		       info->cpus_standby);
-	len += sprintf(page + len, "CPUs Reserved:        %d\n",
-		       info->cpus_reserved);
-
-	if (info->format == 1) {
-		/*
-		 * Sigh 2. According to the specification the alternate
-		 * capability field is a 32 bit floating point number
-		 * if the higher order 8 bits are not zero. Printing
-		 * a floating point number in the kernel is a no-no,
-		 * always print the number as 32 bit unsigned integer.
-		 * The user-space needs to know about the strange
-		 * encoding of the alternate cpu capability.
-		 */
-		len += sprintf(page + len, "Capability:           %u %u\n",
-			       info->capability, ext->alt_capability);
-		for (i = 2; i <= info->cpus_total; i++)
-			len += sprintf(page + len,
-				       "Adjustment %02d-way:    %u %u\n",
-				       i, info->adjustment[i-2],
-				       ext->alt_adjustment[i-2]);
-
-	} else {
-		len += sprintf(page + len, "Capability:           %u\n",
-			       info->capability);
-		for (i = 2; i <= info->cpus_total; i++)
-			len += sprintf(page + len,
-				       "Adjustment %02d-way:    %u\n",
-				       i, info->adjustment[i-2]);
+	seq_printf(m, "CPUs Total:           %d\n", info->cpus_total);
+	seq_printf(m, "CPUs Configured:      %d\n", info->cpus_configured);
+	seq_printf(m, "CPUs Standby:         %d\n", info->cpus_standby);
+	seq_printf(m, "CPUs Reserved:        %d\n", info->cpus_reserved);
+	/*
+	 * Sigh 2. According to the specification the alternate
+	 * capability field is a 32 bit floating point number
+	 * if the higher order 8 bits are not zero. Printing
+	 * a floating point number in the kernel is a no-no,
+	 * always print the number as 32 bit unsigned integer.
+	 * The user-space needs to know about the strange
+	 * encoding of the alternate cpu capability.
+	 */
+	seq_printf(m, "Capability:           %u", info->capability);
+	if (info->format == 1)
+		seq_printf(m, " %u", ext->alt_capability);
+	seq_putc(m, '\n');
+	if (info->nominal_cap)
+		seq_printf(m, "Nominal Capability:   %d\n", info->nominal_cap);
+	if (info->secondary_cap)
+		seq_printf(m, "Secondary Capability: %d\n", info->secondary_cap);
+	for (i = 2; i <= info->cpus_total; i++) {
+		seq_printf(m, "Adjustment %02d-way:    %u",
+			   i, info->adjustment[i-2]);
+		if (info->format == 1)
+			seq_printf(m, " %u", ext->alt_adjustment[i-2]);
+		seq_putc(m, '\n');
 	}
-
-	if (info->secondary_capability != 0)
-		len += sprintf(page + len, "Secondary Capability: %d\n",
-			       info->secondary_capability);
-	return len;
 }
 
-static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
+static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
 {
-	if (stsi(info, 2, 2, 2) == -ENOSYS)
-		return len;
-
+	if (stsi(info, 2, 2, 2))
+		return;
 	EBCASC(info->name, sizeof(info->name));
-
-	len += sprintf(page + len, "\n");
-	len += sprintf(page + len, "LPAR Number:          %d\n",
-		       info->lpar_number);
-
-	len += sprintf(page + len, "LPAR Characteristics: ");
+	seq_putc(m, '\n');
+	seq_printf(m, "LPAR Number:          %d\n", info->lpar_number);
+	seq_printf(m, "LPAR Characteristics: ");
 	if (info->characteristics & LPAR_CHAR_DEDICATED)
-		len += sprintf(page + len, "Dedicated ");
+		seq_printf(m, "Dedicated ");
 	if (info->characteristics & LPAR_CHAR_SHARED)
-		len += sprintf(page + len, "Shared ");
+		seq_printf(m, "Shared ");
 	if (info->characteristics & LPAR_CHAR_LIMITED)
-		len += sprintf(page + len, "Limited ");
-	len += sprintf(page + len, "\n");
-
-	len += sprintf(page + len, "LPAR Name:            %-8.8s\n",
-		       info->name);
-
-	len += sprintf(page + len, "LPAR Adjustment:      %d\n",
-		       info->caf);
-
-	len += sprintf(page + len, "LPAR CPUs Total:      %d\n",
-		       info->cpus_total);
-	len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
-		       info->cpus_configured);
-	len += sprintf(page + len, "LPAR CPUs Standby:    %d\n",
-		       info->cpus_standby);
-	len += sprintf(page + len, "LPAR CPUs Reserved:   %d\n",
-		       info->cpus_reserved);
-	len += sprintf(page + len, "LPAR CPUs Dedicated:  %d\n",
-		       info->cpus_dedicated);
-	len += sprintf(page + len, "LPAR CPUs Shared:     %d\n",
-		       info->cpus_shared);
-	return len;
+		seq_printf(m, "Limited ");
+	seq_putc(m, '\n');
+	seq_printf(m, "LPAR Name:            %-8.8s\n", info->name);
+	seq_printf(m, "LPAR Adjustment:      %d\n", info->caf);
+	seq_printf(m, "LPAR CPUs Total:      %d\n", info->cpus_total);
+	seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured);
+	seq_printf(m, "LPAR CPUs Standby:    %d\n", info->cpus_standby);
+	seq_printf(m, "LPAR CPUs Reserved:   %d\n", info->cpus_reserved);
+	seq_printf(m, "LPAR CPUs Dedicated:  %d\n", info->cpus_dedicated);
+	seq_printf(m, "LPAR CPUs Shared:     %d\n", info->cpus_shared);
 }
 
-static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
+static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
 {
 	int i;
 
-	if (stsi(info, 3, 2, 2) == -ENOSYS)
-		return len;
+	if (stsi(info, 3, 2, 2))
+		return;
 	for (i = 0; i < info->count; i++) {
 		EBCASC(info->vm[i].name, sizeof(info->vm[i].name));
 		EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi));
-		len += sprintf(page + len, "\n");
-		len += sprintf(page + len, "VM%02d Name:            %-8.8s\n",
-			       i, info->vm[i].name);
-		len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
-			       i, info->vm[i].cpi);
-
-		len += sprintf(page + len, "VM%02d Adjustment:      %d\n",
-			       i, info->vm[i].caf);
-
-		len += sprintf(page + len, "VM%02d CPUs Total:      %d\n",
-			       i, info->vm[i].cpus_total);
-		len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
-			       i, info->vm[i].cpus_configured);
-		len += sprintf(page + len, "VM%02d CPUs Standby:    %d\n",
-			       i, info->vm[i].cpus_standby);
-		len += sprintf(page + len, "VM%02d CPUs Reserved:   %d\n",
-			       i, info->vm[i].cpus_reserved);
+		seq_putc(m, '\n');
+		seq_printf(m, "VM%02d Name:            %-8.8s\n", i, info->vm[i].name);
+		seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi);
+		seq_printf(m, "VM%02d Adjustment:      %d\n", i, info->vm[i].caf);
+		seq_printf(m, "VM%02d CPUs Total:      %d\n", i, info->vm[i].cpus_total);
+		seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured);
+		seq_printf(m, "VM%02d CPUs Standby:    %d\n", i, info->vm[i].cpus_standby);
+		seq_printf(m, "VM%02d CPUs Reserved:   %d\n", i, info->vm[i].cpus_reserved);
 	}
-	return len;
 }
 
-static int proc_read_sysinfo(char *page, char **start,
-			     off_t off, int count,
-			     int *eof, void *data)
+static int sysinfo_show(struct seq_file *m, void *v)
 {
-	unsigned long info = get_zeroed_page(GFP_KERNEL);
-	int level, len;
+	void *info = (void *)get_zeroed_page(GFP_KERNEL);
+	int level;
 
 	if (!info)
 		return 0;
-
-	len = 0;
-	level = stsi_0();
+	level = stsi(NULL, 0, 0, 0);
 	if (level >= 1)
-		len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
-
+		stsi_1_1_1(m, info);
 	if (level >= 1)
-		len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len);
-
+		stsi_15_1_x(m, info);
 	if (level >= 1)
-		len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
-
+		stsi_1_2_2(m, info);
 	if (level >= 2)
-		len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
-
+		stsi_2_2_2(m, info);
 	if (level >= 3)
-		len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
-
-	free_page(info);
-	return len;
-}
-
-static __init int create_proc_sysinfo(void)
-{
-	create_proc_read_entry("sysinfo", 0444, NULL,
-			       proc_read_sysinfo, NULL);
+		stsi_3_2_2(m, info);
+	free_page((unsigned long)info);
 	return 0;
 }
-device_initcall(create_proc_sysinfo);
+
+static int sysinfo_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, sysinfo_show, NULL);
+}
+
+static const struct file_operations sysinfo_fops = {
+	.open		= sysinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init sysinfo_create_proc(void)
+{
+	proc_create("sysinfo", 0444, NULL, &sysinfo_fops);
+	return 0;
+}
+device_initcall(sysinfo_create_proc);
 
 /*
  * Service levels interface.
@@ -407,7 +386,7 @@
 	if (!info)
 		return;
 
-	if (stsi(info, 1, 2, 2) != -ENOSYS) {
+	if (stsi(info, 1, 2, 2) == 0) {
 		/*
 		 * Major sigh. The cpu capability encoding is "special".
 		 * If the first 9 bits of info->capability are 0 then it
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index dcec960..2db1011 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -329,7 +329,7 @@
  * The synchronous get_clock function. It will write the current clock
  * value to the clock pointer and return 0 if the clock is in sync with
  * the external time source. If the clock mode is local it will return
- * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * -EOPNOTSUPP and -EAGAIN if the clock is not in sync with the external
  * reference.
  */
 int get_sync_clock(unsigned long long *clock)
@@ -347,7 +347,7 @@
 		return 0;
 	if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) &&
 	    !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 	if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) &&
 	    !test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
 		return -EACCES;
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 05151e0..54d93f4 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -17,6 +17,7 @@
 #include <linux/cpu.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
+#include <asm/sysinfo.h>
 
 #define PTF_HORIZONTAL	(0UL)
 #define PTF_VERTICAL	(1UL)
@@ -44,9 +45,6 @@
 cpumask_t cpu_book_map[NR_CPUS];
 unsigned char cpu_book_id[NR_CPUS];
 
-/* smp_cpu_state_mutex must be held when accessing this array */
-int cpu_polarization[NR_CPUS];
-
 static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
 	cpumask_t mask;
@@ -75,10 +73,7 @@
 {
 	unsigned int cpu;
 
-	for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS);
-	     cpu < TOPOLOGY_CPU_BITS;
-	     cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1))
-	{
+	for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) {
 		unsigned int rcpu;
 		int lcpu;
 
@@ -94,7 +89,7 @@
 			} else {
 				cpu_core_id[lcpu] = core->id;
 			}
-			cpu_set_polarization(lcpu, tl_cpu->pp);
+			smp_cpu_set_polarization(lcpu, tl_cpu->pp);
 		}
 	}
 	return core;
@@ -201,7 +196,7 @@
 
 	mutex_lock(&smp_cpu_state_mutex);
 	for_each_possible_cpu(cpu)
-		cpu_set_polarization(cpu, POLARIZATION_HRZ);
+		smp_cpu_set_polarization(cpu, POLARIZATION_HRZ);
 	mutex_unlock(&smp_cpu_state_mutex);
 }
 
@@ -231,7 +226,7 @@
 	if (rc)
 		return -EBUSY;
 	for_each_possible_cpu(cpu)
-		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 	return rc;
 }
 
@@ -250,12 +245,10 @@
 
 void store_topology(struct sysinfo_15_1_x *info)
 {
-	int rc;
-
-	rc = stsi(info, 15, 1, 3);
-	if (rc != -ENOSYS)
-		return;
-	stsi(info, 15, 1, 2);
+	if (topology_max_mnest >= 3)
+		stsi(info, 15, 1, 3);
+	else
+		stsi(info, 15, 1, 2);
 }
 
 int arch_update_cpu_topology(void)
@@ -415,7 +408,7 @@
 	ssize_t count;
 
 	mutex_lock(&smp_cpu_state_mutex);
-	switch (cpu_read_polarization(cpu)) {
+	switch (smp_cpu_get_polarization(cpu)) {
 	case POLARIZATION_HRZ:
 		count = sprintf(buf, "horizontal\n");
 		break;
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 01775c0..3d2b0fa3 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -57,6 +57,23 @@
 static int kstack_depth_to_print = 20;
 #endif /* CONFIG_64BIT */
 
+static inline void __user *get_trap_ip(struct pt_regs *regs)
+{
+#ifdef CONFIG_64BIT
+	unsigned long address;
+
+	if (regs->int_code & 0x200)
+		address = *(unsigned long *)(current->thread.trap_tdb + 24);
+	else
+		address = regs->psw.addr;
+	return (void __user *)
+		((address - (regs->int_code >> 16)) & PSW_ADDR_INSN);
+#else
+	return (void __user *)
+		((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
+#endif
+}
+
 /*
  * For show_trace we have tree different stack to consider:
  *   - the panic stack which is used if the kernel stack has overflown
@@ -214,7 +231,6 @@
 
 void show_regs(struct pt_regs *regs)
 {
-	print_modules();
 	printk("CPU: %d %s %s %.*s\n",
 	       task_thread_info(current)->cpu, print_tainted(),
 	       init_utsname()->release,
@@ -254,6 +270,7 @@
 #endif
 	printk("\n");
 	notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
+	print_modules();
 	show_regs(regs);
 	bust_spinlocks(0);
 	add_taint(TAINT_DIE);
@@ -285,12 +302,6 @@
 	return 1;
 }
 
-static inline void __user *get_psw_address(struct pt_regs *regs)
-{
-	return (void __user *)
-		((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
-}
-
 static void __kprobes do_trap(struct pt_regs *regs,
 			      int si_signo, int si_code, char *str)
 {
@@ -304,14 +315,14 @@
 		info.si_signo = si_signo;
 		info.si_errno = 0;
 		info.si_code = si_code;
-		info.si_addr = get_psw_address(regs);
+		info.si_addr = get_trap_ip(regs);
 		force_sig_info(si_signo, &info, current);
 		report_user_fault(regs, si_signo);
         } else {
                 const struct exception_table_entry *fixup;
                 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
                 if (fixup)
-                        regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+			regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE;
 		else {
 			enum bug_trap_type btt;
 
@@ -381,6 +392,11 @@
 DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
 	      "translation exception")
 
+#ifdef CONFIG_64BIT
+DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
+	      "transaction constraint exception")
+#endif
+
 static inline void do_fp_trap(struct pt_regs *regs, int fpc)
 {
 	int si_code = 0;
@@ -408,7 +424,7 @@
 	__u16 __user *location;
 	int signal = 0;
 
-	location = get_psw_address(regs);
+	location = get_trap_ip(regs);
 
 	if (user_mode(regs)) {
 		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -476,7 +492,7 @@
 	__u16 __user *location = NULL;
 	int signal = 0;
 
-	location = (__u16 __user *) get_psw_address(regs);
+	location = (__u16 __user *) get_trap_ip(regs);
 
 	if (user_mode(regs)) {
 		get_user(*((__u16 *) opcode), location);
@@ -525,7 +541,7 @@
 	__u16 __user *location;
 	int signal = 0;
 
-	location = get_psw_address(regs);
+	location = get_trap_ip(regs);
 
 	if (MACHINE_HAS_IEEE)
 		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -641,6 +657,7 @@
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
 #ifdef CONFIG_64BIT
+	pgm_check_table[0x18] = &transaction_exception;
 	pgm_check_table[0x38] = &do_asce_exception;
 	pgm_check_table[0x39] = &do_dat_exception;
 	pgm_check_table[0x3A] = &do_dat_exception;
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 9a19ca3..d777628 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -85,7 +85,7 @@
 static void vdso_init_data(struct vdso_data *vd)
 {
 	vd->ectg_available =
-		addressing_mode != HOME_SPACE_MODE && test_facility(31);
+		s390_user_mode != HOME_SPACE_MODE && test_facility(31);
 }
 
 #ifdef CONFIG_64BIT
@@ -102,7 +102,7 @@
 
 	lowcore->vdso_per_cpu_data = __LC_PASTE;
 
-	if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
+	if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled)
 		return 0;
 
 	segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
@@ -147,7 +147,7 @@
 	unsigned long segment_table, page_table, page_frame;
 	u32 *psal, *aste;
 
-	if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
+	if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled)
 		return;
 
 	psal = (u32 *)(addr_t) lowcore->paste[4];
@@ -165,7 +165,7 @@
 {
 	unsigned long cr5;
 
-	if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
+	if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled)
 		return;
 	cr5 = offsetof(struct _lowcore, paste);
 	__ctl_load(cr5, 5, 5);
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 4fc97b4..7903344 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -99,7 +99,7 @@
 	return virt_timer_forward(user + system);
 }
 
-void account_vtime(struct task_struct *prev, struct task_struct *next)
+void vtime_task_switch(struct task_struct *prev)
 {
 	struct thread_info *ti;
 
@@ -107,7 +107,7 @@
 	ti = task_thread_info(prev);
 	ti->user_timer = S390_lowcore.user_timer;
 	ti->system_timer = S390_lowcore.system_timer;
-	ti = task_thread_info(next);
+	ti = task_thread_info(current);
 	S390_lowcore.user_timer = ti->user_timer;
 	S390_lowcore.system_timer = ti->system_timer;
 }
@@ -122,7 +122,7 @@
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
-void account_system_vtime(struct task_struct *tsk)
+void vtime_account(struct task_struct *tsk)
 {
 	struct thread_info *ti = task_thread_info(tsk);
 	u64 timer, system;
@@ -138,7 +138,7 @@
 
 	virt_timer_forward(system);
 }
-EXPORT_SYMBOL_GPL(account_system_vtime);
+EXPORT_SYMBOL_GPL(vtime_account);
 
 void __kprobes vtime_stop_cpu(void)
 {
@@ -378,9 +378,8 @@
 	long cpu = (long) hcpu;
 
 	idle = &per_cpu(s390_idle, cpu);
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DYING:
-	case CPU_DYING_FROZEN:
 		idle->nohz_delay = 0;
 	default:
 		break;
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 78eb984..9b04a32 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -5,7 +5,7 @@
 
 menuconfig VIRTUALIZATION
 	def_bool y
-	prompt "Virtualization"
+	prompt "KVM"
 	---help---
 	  Say Y here to get to see options for using your Linux host to run other
 	  operating systems inside virtual machines (guests).
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 60da903..310be61 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -211,7 +211,7 @@
 	spin_unlock(&fi->lock);
 
 	/* deal with other level 3 hypervisors */
-	if (stsi(mem, 3, 2, 2) == -ENOSYS)
+	if (stsi(mem, 3, 2, 2))
 		mem->count = 0;
 	if (mem->count < 8)
 		mem->count++;
@@ -259,7 +259,7 @@
 		mem = get_zeroed_page(GFP_KERNEL);
 		if (!mem)
 			goto out_fail;
-		if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS)
+		if (stsi((void *) mem, fc, sel1, sel2))
 			goto out_mem;
 		break;
 	case 3:
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index 761ab8b..6ab0d0b 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,6 +4,7 @@
 
 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
 obj-y += usercopy.o
-obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o
+obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
+obj-$(CONFIG_64BIT) += mem64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/mem32.S b/arch/s390/lib/mem32.S
new file mode 100644
index 0000000..14ca924
--- /dev/null
+++ b/arch/s390/lib/mem32.S
@@ -0,0 +1,92 @@
+/*
+ * String handling functions.
+ *
+ * Copyright IBM Corp. 2012
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * memset implementation
+ *
+ * This code corresponds to the C construct below. We do distinguish
+ * between clearing (c == 0) and setting a memory array (c != 0) simply
+ * because nearly all memset invocations in the kernel clear memory and
+ * the xc instruction is preferred in such cases.
+ *
+ * void *memset(void *s, int c, size_t n)
+ * {
+ *	if (likely(c == 0))
+ *		return __builtin_memset(s, 0, n);
+ *	return __builtin_memset(s, c, n);
+ * }
+ */
+ENTRY(memset)
+	basr	%r5,%r0
+.Lmemset_base:
+	ltr	%r4,%r4
+	bzr	%r14
+	ltr	%r3,%r3
+	jnz	.Lmemset_fill
+	ahi	%r4,-1
+	lr	%r3,%r4
+	srl	%r3,8
+	ltr	%r3,%r3
+	lr	%r1,%r2
+	je	.Lmemset_clear_rest
+.Lmemset_clear_loop:
+	xc	0(256,%r1),0(%r1)
+	la	%r1,256(%r1)
+	brct	%r3,.Lmemset_clear_loop
+.Lmemset_clear_rest:
+	ex	%r4,.Lmemset_xc-.Lmemset_base(%r5)
+	br	%r14
+.Lmemset_fill:
+	stc	%r3,0(%r2)
+	chi	%r4,1
+	lr	%r1,%r2
+	ber	%r14
+	ahi	%r4,-2
+	lr	%r3,%r4
+	srl	%r3,8
+	ltr	%r3,%r3
+	je	.Lmemset_fill_rest
+.Lmemset_fill_loop:
+	mvc	1(256,%r1),0(%r1)
+	la	%r1,256(%r1)
+	brct	%r3,.Lmemset_fill_loop
+.Lmemset_fill_rest:
+	ex	%r4,.Lmemset_mvc-.Lmemset_base(%r5)
+	br	%r14
+.Lmemset_xc:
+	xc	0(1,%r1),0(%r1)
+.Lmemset_mvc:
+	mvc	1(1,%r1),0(%r1)
+
+/*
+ * memcpy implementation
+ *
+ * void *memcpy(void *dest, const void *src, size_t n)
+ */
+ENTRY(memcpy)
+	basr	%r5,%r0
+.Lmemcpy_base:
+	ltr	%r4,%r4
+	bzr	%r14
+	ahi	%r4,-1
+	lr	%r0,%r4
+	srl	%r0,8
+	ltr	%r0,%r0
+	lr	%r1,%r2
+	jnz	.Lmemcpy_loop
+.Lmemcpy_rest:
+	ex	%r4,.Lmemcpy_mvc-.Lmemcpy_base(%r5)
+	br	%r14
+.Lmemcpy_loop:
+	mvc	0(256,%r1),0(%r3)
+	la	%r1,256(%r1)
+	la	%r3,256(%r3)
+	brct	%r0,.Lmemcpy_loop
+	j	.Lmemcpy_rest
+.Lmemcpy_mvc:
+	mvc	0(1,%r1),0(%r3)
diff --git a/arch/s390/lib/mem64.S b/arch/s390/lib/mem64.S
new file mode 100644
index 0000000..c6d553e
--- /dev/null
+++ b/arch/s390/lib/mem64.S
@@ -0,0 +1,88 @@
+/*
+ * String handling functions.
+ *
+ * Copyright IBM Corp. 2012
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * memset implementation
+ *
+ * This code corresponds to the C construct below. We do distinguish
+ * between clearing (c == 0) and setting a memory array (c != 0) simply
+ * because nearly all memset invocations in the kernel clear memory and
+ * the xc instruction is preferred in such cases.
+ *
+ * void *memset(void *s, int c, size_t n)
+ * {
+ *	if (likely(c == 0))
+ *		return __builtin_memset(s, 0, n);
+ *	return __builtin_memset(s, c, n);
+ * }
+ */
+ENTRY(memset)
+	ltgr	%r4,%r4
+	bzr	%r14
+	ltgr	%r3,%r3
+	jnz	.Lmemset_fill
+	aghi	%r4,-1
+	srlg	%r3,%r4,8
+	ltgr	%r3,%r3
+	lgr	%r1,%r2
+	jz	.Lmemset_clear_rest
+.Lmemset_clear_loop:
+	xc	0(256,%r1),0(%r1)
+	la	%r1,256(%r1)
+	brctg	%r3,.Lmemset_clear_loop
+.Lmemset_clear_rest:
+	larl	%r3,.Lmemset_xc
+	ex	%r4,0(%r3)
+	br	%r14
+.Lmemset_fill:
+	stc	%r3,0(%r2)
+	cghi	%r4,1
+	lgr	%r1,%r2
+	ber	%r14
+	aghi	%r4,-2
+	srlg	%r3,%r4,8
+	ltgr	%r3,%r3
+	jz	.Lmemset_fill_rest
+.Lmemset_fill_loop:
+	mvc	1(256,%r1),0(%r1)
+	la	%r1,256(%r1)
+	brctg	%r3,.Lmemset_fill_loop
+.Lmemset_fill_rest:
+	larl	%r3,.Lmemset_mvc
+	ex	%r4,0(%r3)
+	br	%r14
+.Lmemset_xc:
+	xc	0(1,%r1),0(%r1)
+.Lmemset_mvc:
+	mvc	1(1,%r1),0(%r1)
+
+/*
+ * memcpy implementation
+ *
+ * void *memcpy(void *dest, const void *src, size_t n)
+ */
+ENTRY(memcpy)
+	ltgr	%r4,%r4
+	bzr	%r14
+	aghi	%r4,-1
+	srlg	%r5,%r4,8
+	ltgr	%r5,%r5
+	lgr	%r1,%r2
+	jnz	.Lmemcpy_loop
+.Lmemcpy_rest:
+	larl	%r5,.Lmemcpy_mvc
+	ex	%r4,0(%r5)
+	br	%r14
+.Lmemcpy_loop:
+	mvc	0(256,%r1),0(%r3)
+	la	%r1,256(%r1)
+	la	%r3,256(%r3)
+	brctg	%r5,.Lmemcpy_loop
+	j	.Lmemcpy_rest
+.Lmemcpy_mvc:
+	mvc	0(1,%r1),0(%r3)
diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c
index 846ec64..b647d5f 100644
--- a/arch/s390/lib/string.c
+++ b/arch/s390/lib/string.c
@@ -43,11 +43,7 @@
  */
 size_t strlen(const char *s)
 {
-#if __GNUC__ < 4
 	return __strend(s) - s;
-#else
-	return __builtin_strlen(s);
-#endif
 }
 EXPORT_SYMBOL(strlen);
 
@@ -73,7 +69,6 @@
  */
 char *strcpy(char *dest, const char *src)
 {
-#if __GNUC__ < 4
 	register int r0 asm("0") = 0;
 	char *ret = dest;
 
@@ -82,9 +77,6 @@
 		      : "+&a" (dest), "+&a" (src) : "d" (r0)
 		      : "cc", "memory" );
 	return ret;
-#else
-	return __builtin_strcpy(dest, src);
-#endif
 }
 EXPORT_SYMBOL(strcpy);
 
@@ -106,7 +98,7 @@
 	if (size) {
 		size_t len = (ret >= size) ? size-1 : ret;
 		dest[len] = '\0';
-		__builtin_memcpy(dest, src, len);
+		memcpy(dest, src, len);
 	}
 	return ret;
 }
@@ -124,8 +116,8 @@
 char *strncpy(char *dest, const char *src, size_t n)
 {
 	size_t len = __strnend(src, n) - src;
-	__builtin_memset(dest + len, 0, n - len);
-	__builtin_memcpy(dest, src, len);
+	memset(dest + len, 0, n - len);
+	memcpy(dest, src, len);
 	return dest;
 }
 EXPORT_SYMBOL(strncpy);
@@ -171,7 +163,7 @@
 		if (len >= n)
 			len = n - 1;
 		dest[len] = '\0';
-		__builtin_memcpy(dest, src, len);
+		memcpy(dest, src, len);
 	}
 	return res;
 }
@@ -194,7 +186,7 @@
 	char *p = __strend(dest);
 
 	p[len] = '\0';
-	__builtin_memcpy(p, src, len);
+	memcpy(p, src, len);
 	return dest;
 }
 EXPORT_SYMBOL(strncat);
@@ -348,41 +340,3 @@
 	return (void *) ret;
 }
 EXPORT_SYMBOL(memscan);
-
-/**
- * memcpy - Copy one area of memory to another
- * @dest: Where to copy to
- * @src: Where to copy from
- * @n: The size of the area.
- *
- * returns a pointer to @dest
- */
-void *memcpy(void *dest, const void *src, size_t n)
-{
-	return __builtin_memcpy(dest, src, n);
-}
-EXPORT_SYMBOL(memcpy);
-
-/**
- * memset - Fill a region of memory with the given value
- * @s: Pointer to the start of the area.
- * @c: The byte to fill the area with
- * @n: The size of the area.
- *
- * returns a pointer to @s
- */
-void *memset(void *s, int c, size_t n)
-{
-	char *xs;
-
-	if (c == 0)
-		return __builtin_memset(s, 0, n);
-
-	xs = (char *) s;
-	if (n > 0)
-		do {
-			*xs++ = c;
-		} while (--n > 0);
-	return s;
-}
-EXPORT_SYMBOL(memset);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 60ee2b8..2d37bb8 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -2,69 +2,82 @@
  *  User access functions based on page table walks for enhanced
  *  system layout without hardware support.
  *
- *    Copyright IBM Corp. 2006
+ *    Copyright IBM Corp. 2006, 2012
  *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
  */
 
 #include <linux/errno.h>
 #include <linux/hardirq.h>
 #include <linux/mm.h>
+#include <linux/hugetlb.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
 #include "uaccess.h"
 
-static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
+
+/*
+ * Returns kernel address for user virtual address. If the returned address is
+ * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address
+ * contains the (negative) exception code.
+ */
+static __always_inline unsigned long follow_table(struct mm_struct *mm,
+						  unsigned long addr, int write)
 {
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
+	pte_t *ptep;
 
 	pgd = pgd_offset(mm, addr);
 	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-		return (pte_t *) 0x3a;
+		return -0x3aUL;
 
 	pud = pud_offset(pgd, addr);
 	if (pud_none(*pud) || unlikely(pud_bad(*pud)))
-		return (pte_t *) 0x3b;
+		return -0x3bUL;
 
 	pmd = pmd_offset(pud, addr);
-	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-		return (pte_t *) 0x10;
+	if (pmd_none(*pmd))
+		return -0x10UL;
+	if (pmd_huge(*pmd)) {
+		if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO))
+			return -0x04UL;
+		return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK);
+	}
+	if (unlikely(pmd_bad(*pmd)))
+		return -0x10UL;
 
-	return pte_offset_map(pmd, addr);
+	ptep = pte_offset_map(pmd, addr);
+	if (!pte_present(*ptep))
+		return -0x11UL;
+	if (write && !pte_write(*ptep))
+		return -0x04UL;
+
+	return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);
 }
 
 static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
 					     size_t n, int write_user)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long offset, pfn, done, size;
-	pte_t *pte;
+	unsigned long offset, done, size, kaddr;
 	void *from, *to;
 
 	done = 0;
 retry:
 	spin_lock(&mm->page_table_lock);
 	do {
-		pte = follow_table(mm, uaddr);
-		if ((unsigned long) pte < 0x1000)
+		kaddr = follow_table(mm, uaddr, write_user);
+		if (IS_ERR_VALUE(kaddr))
 			goto fault;
-		if (!pte_present(*pte)) {
-			pte = (pte_t *) 0x11;
-			goto fault;
-		} else if (write_user && !pte_write(*pte)) {
-			pte = (pte_t *) 0x04;
-			goto fault;
-		}
 
-		pfn = pte_pfn(*pte);
-		offset = uaddr & (PAGE_SIZE - 1);
+		offset = uaddr & ~PAGE_MASK;
 		size = min(n - done, PAGE_SIZE - offset);
 		if (write_user) {
-			to = (void *)((pfn << PAGE_SHIFT) + offset);
+			to = (void *) kaddr;
 			from = kptr + done;
 		} else {
-			from = (void *)((pfn << PAGE_SHIFT) + offset);
+			from = (void *) kaddr;
 			to = kptr + done;
 		}
 		memcpy(to, from, size);
@@ -75,7 +88,7 @@
 	return n - done;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(uaddr, (unsigned long) pte, write_user))
+	if (__handle_fault(uaddr, -kaddr, write_user))
 		return n - done;
 	goto retry;
 }
@@ -84,27 +97,22 @@
  * Do DAT for user address by page table walk, return kernel address.
  * This function needs to be called with current->mm->page_table_lock held.
  */
-static __always_inline unsigned long __dat_user_addr(unsigned long uaddr)
+static __always_inline unsigned long __dat_user_addr(unsigned long uaddr,
+						     int write)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long pfn;
-	pte_t *pte;
+	unsigned long kaddr;
 	int rc;
 
 retry:
-	pte = follow_table(mm, uaddr);
-	if ((unsigned long) pte < 0x1000)
+	kaddr = follow_table(mm, uaddr, write);
+	if (IS_ERR_VALUE(kaddr))
 		goto fault;
-	if (!pte_present(*pte)) {
-		pte = (pte_t *) 0x11;
-		goto fault;
-	}
 
-	pfn = pte_pfn(*pte);
-	return (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+	return kaddr;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	rc = __handle_fault(uaddr, (unsigned long) pte, 0);
+	rc = __handle_fault(uaddr, -kaddr, write);
 	spin_lock(&mm->page_table_lock);
 	if (!rc)
 		goto retry;
@@ -159,11 +167,9 @@
 
 static size_t strnlen_user_pt(size_t count, const char __user *src)
 {
-	char *addr;
 	unsigned long uaddr = (unsigned long) src;
 	struct mm_struct *mm = current->mm;
-	unsigned long offset, pfn, done, len;
-	pte_t *pte;
+	unsigned long offset, done, len, kaddr;
 	size_t len_str;
 
 	if (segment_eq(get_fs(), KERNEL_DS))
@@ -172,19 +178,13 @@
 retry:
 	spin_lock(&mm->page_table_lock);
 	do {
-		pte = follow_table(mm, uaddr);
-		if ((unsigned long) pte < 0x1000)
+		kaddr = follow_table(mm, uaddr, 0);
+		if (IS_ERR_VALUE(kaddr))
 			goto fault;
-		if (!pte_present(*pte)) {
-			pte = (pte_t *) 0x11;
-			goto fault;
-		}
 
-		pfn = pte_pfn(*pte);
-		offset = uaddr & (PAGE_SIZE-1);
-		addr = (char *)(pfn << PAGE_SHIFT) + offset;
+		offset = uaddr & ~PAGE_MASK;
 		len = min(count - done, PAGE_SIZE - offset);
-		len_str = strnlen(addr, len);
+		len_str = strnlen((char *) kaddr, len);
 		done += len_str;
 		uaddr += len_str;
 	} while ((len_str == len) && (done < count));
@@ -192,7 +192,7 @@
 	return done + 1;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(uaddr, (unsigned long) pte, 0))
+	if (__handle_fault(uaddr, -kaddr, 0))
 		return 0;
 	goto retry;
 }
@@ -225,11 +225,10 @@
 			      const void __user *from)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
-		      uaddr, done, size, error_code;
+	unsigned long offset_max, uaddr, done, size, error_code;
 	unsigned long uaddr_from = (unsigned long) from;
 	unsigned long uaddr_to = (unsigned long) to;
-	pte_t *pte_from, *pte_to;
+	unsigned long kaddr_to, kaddr_from;
 	int write_user;
 
 	if (segment_eq(get_fs(), KERNEL_DS)) {
@@ -242,38 +241,23 @@
 	do {
 		write_user = 0;
 		uaddr = uaddr_from;
-		pte_from = follow_table(mm, uaddr_from);
-		error_code = (unsigned long) pte_from;
-		if (error_code < 0x1000)
+		kaddr_from = follow_table(mm, uaddr_from, 0);
+		error_code = kaddr_from;
+		if (IS_ERR_VALUE(error_code))
 			goto fault;
-		if (!pte_present(*pte_from)) {
-			error_code = 0x11;
-			goto fault;
-		}
 
 		write_user = 1;
 		uaddr = uaddr_to;
-		pte_to = follow_table(mm, uaddr_to);
-		error_code = (unsigned long) pte_to;
-		if (error_code < 0x1000)
+		kaddr_to = follow_table(mm, uaddr_to, 1);
+		error_code = (unsigned long) kaddr_to;
+		if (IS_ERR_VALUE(error_code))
 			goto fault;
-		if (!pte_present(*pte_to)) {
-			error_code = 0x11;
-			goto fault;
-		} else if (!pte_write(*pte_to)) {
-			error_code = 0x04;
-			goto fault;
-		}
 
-		pfn_from = pte_pfn(*pte_from);
-		pfn_to = pte_pfn(*pte_to);
-		offset_from = uaddr_from & (PAGE_SIZE-1);
-		offset_to = uaddr_from & (PAGE_SIZE-1);
-		offset_max = max(offset_from, offset_to);
+		offset_max = max(uaddr_from & ~PAGE_MASK,
+				 uaddr_to & ~PAGE_MASK);
 		size = min(n - done, PAGE_SIZE - offset_max);
 
-		memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
-		       (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+		memcpy((void *) kaddr_to, (void *) kaddr_from, size);
 		done += size;
 		uaddr_from += size;
 		uaddr_to += size;
@@ -282,7 +266,7 @@
 	return n - done;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(uaddr, error_code, write_user))
+	if (__handle_fault(uaddr, -error_code, write_user))
 		return n - done;
 	goto retry;
 }
@@ -341,7 +325,7 @@
 		return __futex_atomic_op_pt(op, uaddr, oparg, old);
 	spin_lock(&current->mm->page_table_lock);
 	uaddr = (u32 __force __user *)
-		__dat_user_addr((__force unsigned long) uaddr);
+		__dat_user_addr((__force unsigned long) uaddr, 1);
 	if (!uaddr) {
 		spin_unlock(&current->mm->page_table_lock);
 		return -EFAULT;
@@ -378,7 +362,7 @@
 		return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
 	spin_lock(&current->mm->page_table_lock);
 	uaddr = (u32 __force __user *)
-		__dat_user_addr((__force unsigned long) uaddr);
+		__dat_user_addr((__force unsigned long) uaddr, 1);
 	if (!uaddr) {
 		spin_unlock(&current->mm->page_table_lock);
 		return -EFAULT;
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index d98fe90..0f5536b 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y	 := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
-	    page-states.o gup.o
+	    page-states.o gup.o extable.o
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c
new file mode 100644
index 0000000..4d1ee88
--- /dev/null
+++ b/arch/s390/mm/extable.c
@@ -0,0 +1,81 @@
+#include <linux/module.h>
+#include <linux/sort.h>
+#include <asm/uaccess.h>
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+	       const struct exception_table_entry *last,
+	       unsigned long value)
+{
+	const struct exception_table_entry *mid;
+	unsigned long addr;
+
+	while (first <= last) {
+		mid = ((last - first) >> 1) + first;
+		addr = extable_insn(mid);
+		if (addr < value)
+			first = mid + 1;
+		else if (addr > value)
+			last = mid - 1;
+		else
+			return mid;
+	}
+	return NULL;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+static int cmp_ex(const void *a, const void *b)
+{
+	const struct exception_table_entry *x = a, *y = b;
+
+	/* This compare is only valid after normalization. */
+	return x->insn - y->insn;
+}
+
+void sort_extable(struct exception_table_entry *start,
+		  struct exception_table_entry *finish)
+{
+	struct exception_table_entry *p;
+	int i;
+
+	/* Normalize entries to being relative to the start of the section */
+	for (p = start, i = 0; p < finish; p++, i += 8)
+		p->insn += i;
+	sort(start, finish - start, sizeof(*start), cmp_ex, NULL);
+	/* Denormalize all entries */
+	for (p = start, i = 0; p < finish; p++, i += 8)
+		p->insn -= i;
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+	/* Trim the beginning */
+	while (m->num_exentries &&
+	       within_module_init(extable_insn(&m->extable[0]), m)) {
+		m->extable++;
+		m->num_exentries--;
+	}
+	/* Trim the end */
+	while (m->num_exentries &&
+	       within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m))
+		m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 6c013f5..ac9122c 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -111,7 +111,7 @@
 	if (trans_exc_code == 2)
 		/* Access via secondary space, set_fs setting decides */
 		return current->thread.mm_segment.ar4;
-	if (addressing_mode == HOME_SPACE_MODE)
+	if (s390_user_mode == HOME_SPACE_MODE)
 		/* User space if the access has been done via home space. */
 		return trans_exc_code == 3;
 	/*
@@ -163,7 +163,7 @@
 	/* Are we prepared to handle this kernel fault?  */
 	fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
 	if (fixup) {
-		regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+		regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE;
 		return;
 	}
 
@@ -628,9 +628,8 @@
 	struct thread_struct *thread, *next;
 	struct task_struct *tsk;
 
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
 		spin_lock_irq(&pfault_lock);
 		list_for_each_entry_safe(thread, next, &pfault_list, list) {
 			thread->pfault_wait = 0;
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 65cb06e2..eeaf802 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -154,6 +154,43 @@
 	return 1;
 }
 
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+			  struct page **pages)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr, len, end;
+	unsigned long next, flags;
+	pgd_t *pgdp, pgd;
+	int nr = 0;
+
+	start &= PAGE_MASK;
+	addr = start;
+	len = (unsigned long) nr_pages << PAGE_SHIFT;
+	end = start + len;
+	if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+					(void __user *)start, len)))
+		return 0;
+
+	local_irq_save(flags);
+	pgdp = pgd_offset(mm, addr);
+	do {
+		pgd = *pgdp;
+		barrier();
+		next = pgd_addr_end(addr, end);
+		if (pgd_none(pgd))
+			break;
+		if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr))
+			break;
+	} while (pgdp++, addr = next, addr != end);
+	local_irq_restore(flags);
+
+	return nr;
+}
+
 /**
  * get_user_pages_fast() - pin user pages in memory
  * @start:	starting user address
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 6adbc08..81e596c 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -42,7 +42,7 @@
 unsigned long empty_zero_page, zero_page_mask;
 EXPORT_SYMBOL(empty_zero_page);
 
-static unsigned long setup_zero_pages(void)
+static unsigned long __init setup_zero_pages(void)
 {
 	struct cpuid cpu_id;
 	unsigned int order;
@@ -212,7 +212,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
+void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
 	free_init_pages("initrd memory", start, end);
 }
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 18df31d..b402991 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -609,8 +609,8 @@
  */
 unsigned long *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr)
 {
-	struct page *page;
-	unsigned long *table;
+	unsigned long *uninitialized_var(table);
+	struct page *uninitialized_var(page);
 	unsigned int mask, bit;
 
 	if (mm_has_pgste(mm))
@@ -796,7 +796,7 @@
 	struct mm_struct *mm, *old_mm;
 
 	/* Do we have switched amode? If no, we cannot do sie */
-	if (addressing_mode == HOME_SPACE_MODE)
+	if (s390_user_mode == HOME_SPACE_MODE)
 		return -EINVAL;
 
 	/* Do we have pgstes? if yes, we are done */
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 6f896e7..c22abf9 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -107,7 +107,7 @@
 		pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
 		pm_dir = pmd_offset(pu_dir, address);
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
 		if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
 		    (address + HPAGE_SIZE <= start + size) &&
 		    (address >= HPAGE_SIZE)) {
diff --git a/arch/s390/net/Makefile b/arch/s390/net/Makefile
new file mode 100644
index 0000000..90568c3
--- /dev/null
+++ b/arch/s390/net/Makefile
@@ -0,0 +1,4 @@
+#
+# Arch-specific network modules
+#
+obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S
new file mode 100644
index 0000000..7e45d13
--- /dev/null
+++ b/arch/s390/net/bpf_jit.S
@@ -0,0 +1,130 @@
+/*
+ * BPF Jit compiler for s390, help functions.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/linkage.h>
+
+/*
+ * Calling convention:
+ * registers %r2, %r6-%r8, %r10-%r11, %r13, %r15 are call saved
+ *   %r2: skb pointer
+ *   %r3: offset parameter
+ *   %r5: BPF A accumulator
+ *   %r8: return address
+ *   %r9: save register for skb pointer
+ *   %r10: skb->data
+ *   %r11: skb->len - skb->data_len (headlen)
+ *   %r12: BPF X accumulator
+ *
+ * skb_copy_bits takes 4 parameters:
+ *   %r2 = skb pointer
+ *   %r3 = offset into skb data
+ *   %r4 = length to copy
+ *   %r5 = pointer to temp buffer
+ */
+#define SKBDATA	%r8
+
+	/* A = *(u32 *) (skb->data+K+X) */
+ENTRY(sk_load_word_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u32 *) (skb->data+K) */
+ENTRY(sk_load_word)
+	llgfr	%r1,%r3			# extend offset
+	ahi	%r3,4			# offset + 4
+	clr	%r11,%r3		# hlen <= offset + 4 ?
+	jl	sk_load_word_slow
+	l	%r5,0(%r1,%r10)		# get word from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_word_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,4			# 4 bytes
+	la	%r5,160(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = *(u16 *) (skb->data+K+X) */
+ENTRY(sk_load_half_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u16 *) (skb->data+K) */
+ENTRY(sk_load_half)
+	llgfr	%r1,%r3			# extend offset
+	ahi	%r3,2			# offset + 2
+	clr	%r11,%r3		# hlen <= offset + 2 ?
+	jl	sk_load_half_slow
+	llgh	%r5,0(%r1,%r10)		# get half from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_half_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,2			# 2 bytes
+	la	%r5,162(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(2,%r15),160(%r15)
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = *(u8 *) (skb->data+K+X) */
+ENTRY(sk_load_byte_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u8 *) (skb->data+K) */
+ENTRY(sk_load_byte)
+	llgfr	%r1,%r3			# extend offset
+	clr	%r11,%r3		# hlen < offset ?
+	jle	sk_load_byte_slow
+	lhi	%r5,0
+	ic	%r5,0(%r1,%r10)		# get byte from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_byte_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,1			# 1 bytes
+	la	%r5,163(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(3,%r15),160(%r15)
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+ENTRY(sk_load_byte_msh)
+	llgfr	%r1,%r3			# extend offset
+	clr	%r11,%r3		# hlen < offset ?
+	jle	sk_load_byte_slow
+	lhi	%r12,0
+	ic	%r12,0(%r1,%r10)	# get byte from skb
+	nill	%r12,0x0f
+	sll	%r12,2
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_byte_msh_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,2			# 2 bytes
+	la	%r5,162(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(3,%r15),160(%r15)
+	l	%r12,160(%r15)		# load result from temp buffer
+	nill	%r12,0x0f
+	sll	%r12,2
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
new file mode 100644
index 0000000..9b355b4
--- /dev/null
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -0,0 +1,776 @@
+/*
+ * BPF Jit compiler for s390.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/facility.h>
+
+/*
+ * Conventions:
+ *   %r2 = skb pointer
+ *   %r3 = offset parameter
+ *   %r4 = scratch register / length parameter
+ *   %r5 = BPF A accumulator
+ *   %r8 = return address
+ *   %r9 = save register for skb pointer
+ *   %r10 = skb->data
+ *   %r11 = skb->len - skb->data_len (headlen)
+ *   %r12 = BPF X accumulator
+ *   %r13 = literal pool pointer
+ *   0(%r15) - 63(%r15) scratch memory array with BPF_MEMWORDS
+ */
+int bpf_jit_enable __read_mostly;
+
+/*
+ * assembly code in arch/x86/net/bpf_jit.S
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+
+struct bpf_jit {
+	unsigned int seen;
+	u8 *start;
+	u8 *prg;
+	u8 *mid;
+	u8 *lit;
+	u8 *end;
+	u8 *base_ip;
+	u8 *ret0_ip;
+	u8 *exit_ip;
+	unsigned int off_load_word;
+	unsigned int off_load_half;
+	unsigned int off_load_byte;
+	unsigned int off_load_bmsh;
+	unsigned int off_load_iword;
+	unsigned int off_load_ihalf;
+	unsigned int off_load_ibyte;
+};
+
+#define BPF_SIZE_MAX	4096	/* Max size for program */
+
+#define SEEN_DATAREF	1	/* might call external helpers */
+#define SEEN_XREG	2	/* ebx is used */
+#define SEEN_MEM	4	/* use mem[] for temporary storage */
+#define SEEN_RET0	8	/* pc_ret0 points to a valid return 0 */
+#define SEEN_LITERAL	16	/* code uses literals */
+#define SEEN_LOAD_WORD	32	/* code uses sk_load_word */
+#define SEEN_LOAD_HALF	64	/* code uses sk_load_half */
+#define SEEN_LOAD_BYTE	128	/* code uses sk_load_byte */
+#define SEEN_LOAD_BMSH	256	/* code uses sk_load_byte_msh */
+#define SEEN_LOAD_IWORD	512	/* code uses sk_load_word_ind */
+#define SEEN_LOAD_IHALF	1024	/* code uses sk_load_half_ind */
+#define SEEN_LOAD_IBYTE	2048	/* code uses sk_load_byte_ind */
+
+#define EMIT2(op)					\
+({							\
+	if (jit->prg + 2 <= jit->mid)			\
+		*(u16 *) jit->prg = op;			\
+	jit->prg += 2;					\
+})
+
+#define EMIT4(op)					\
+({							\
+	if (jit->prg + 4 <= jit->mid)			\
+		*(u32 *) jit->prg = op;			\
+	jit->prg += 4;					\
+})
+
+#define EMIT4_DISP(op, disp)				\
+({							\
+	unsigned int __disp = (disp) & 0xfff;		\
+	EMIT4(op | __disp);				\
+})
+
+#define EMIT4_IMM(op, imm)				\
+({							\
+	unsigned int __imm = (imm) & 0xffff;		\
+	EMIT4(op | __imm);				\
+})
+
+#define EMIT4_PCREL(op, pcrel)				\
+({							\
+	long __pcrel = ((pcrel) >> 1) & 0xffff;		\
+	EMIT4(op | __pcrel);				\
+})
+
+#define EMIT6(op1, op2)					\
+({							\
+	if (jit->prg + 6 <= jit->mid) {			\
+		*(u32 *) jit->prg = op1;		\
+		*(u16 *) (jit->prg + 4) = op2;		\
+	}						\
+	jit->prg += 6;					\
+})
+
+#define EMIT6_DISP(op1, op2, disp)			\
+({							\
+	unsigned int __disp = (disp) & 0xfff;		\
+	EMIT6(op1 | __disp, op2);			\
+})
+
+#define EMIT6_IMM(op, imm)				\
+({							\
+	unsigned int __imm = (imm);			\
+	EMIT6(op | (__imm >> 16), __imm & 0xffff);	\
+})
+
+#define EMIT_CONST(val)					\
+({							\
+	unsigned int ret;				\
+	ret = (unsigned int) (jit->lit - jit->base_ip);	\
+	jit->seen |= SEEN_LITERAL;			\
+	if (jit->lit + 4 <= jit->end)			\
+		*(u32 *) jit->lit = val;		\
+	jit->lit += 4;					\
+	ret;						\
+})
+
+#define EMIT_FN_CONST(bit, fn)				\
+({							\
+	unsigned int ret;				\
+	ret = (unsigned int) (jit->lit - jit->base_ip);	\
+	if (jit->seen & bit) {				\
+		jit->seen |= SEEN_LITERAL;		\
+		if (jit->lit + 8 <= jit->end)		\
+			*(void **) jit->lit = fn;	\
+		jit->lit += 8;				\
+	}						\
+	ret;						\
+})
+
+static void bpf_jit_prologue(struct bpf_jit *jit)
+{
+	/* Save registers and create stack frame if necessary */
+	if (jit->seen & SEEN_DATAREF) {
+		/* stmg %r8,%r15,88(%r15) */
+		EMIT6(0xeb8ff058, 0x0024);
+		/* lgr %r14,%r15 */
+		EMIT4(0xb90400ef);
+		/* ahi %r15,<offset> */
+		EMIT4_IMM(0xa7fa0000, (jit->seen & SEEN_MEM) ? -112 : -80);
+		/* stg %r14,152(%r15) */
+		EMIT6(0xe3e0f098, 0x0024);
+	} else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+		/* stmg %r12,%r13,120(%r15) */
+		EMIT6(0xebcdf078, 0x0024);
+	else if (jit->seen & SEEN_XREG)
+		/* stg %r12,120(%r15) */
+		EMIT6(0xe3c0f078, 0x0024);
+	else if (jit->seen & SEEN_LITERAL)
+		/* stg %r13,128(%r15) */
+		EMIT6(0xe3d0f080, 0x0024);
+
+	/* Setup literal pool */
+	if (jit->seen & SEEN_LITERAL) {
+		/* basr %r13,0 */
+		EMIT2(0x0dd0);
+		jit->base_ip = jit->prg;
+	}
+	jit->off_load_word = EMIT_FN_CONST(SEEN_LOAD_WORD, sk_load_word);
+	jit->off_load_half = EMIT_FN_CONST(SEEN_LOAD_HALF, sk_load_half);
+	jit->off_load_byte = EMIT_FN_CONST(SEEN_LOAD_BYTE, sk_load_byte);
+	jit->off_load_bmsh = EMIT_FN_CONST(SEEN_LOAD_BMSH, sk_load_byte_msh);
+	jit->off_load_iword = EMIT_FN_CONST(SEEN_LOAD_IWORD, sk_load_word_ind);
+	jit->off_load_ihalf = EMIT_FN_CONST(SEEN_LOAD_IHALF, sk_load_half_ind);
+	jit->off_load_ibyte = EMIT_FN_CONST(SEEN_LOAD_IBYTE, sk_load_byte_ind);
+
+	/* Filter needs to access skb data */
+	if (jit->seen & SEEN_DATAREF) {
+		/* l %r11,<len>(%r2) */
+		EMIT4_DISP(0x58b02000, offsetof(struct sk_buff, len));
+		/* s %r11,<data_len>(%r2) */
+		EMIT4_DISP(0x5bb02000, offsetof(struct sk_buff, data_len));
+		/* lg %r10,<data>(%r2) */
+		EMIT6_DISP(0xe3a02000, 0x0004,
+			   offsetof(struct sk_buff, data));
+	}
+}
+
+static void bpf_jit_epilogue(struct bpf_jit *jit)
+{
+	/* Return 0 */
+	if (jit->seen & SEEN_RET0) {
+		jit->ret0_ip = jit->prg;
+		/* lghi %r2,0 */
+		EMIT4(0xa7290000);
+	}
+	jit->exit_ip = jit->prg;
+	/* Restore registers */
+	if (jit->seen & SEEN_DATAREF)
+		/* lmg %r8,%r15,<offset>(%r15) */
+		EMIT6_DISP(0xeb8ff000, 0x0004,
+			   (jit->seen & SEEN_MEM) ? 200 : 168);
+	else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+		/* lmg %r12,%r13,120(%r15) */
+		EMIT6(0xebcdf078, 0x0004);
+	else if (jit->seen & SEEN_XREG)
+		/* lg %r12,120(%r15) */
+		EMIT6(0xe3c0f078, 0x0004);
+	else if (jit->seen & SEEN_LITERAL)
+		/* lg %r13,128(%r15) */
+		EMIT6(0xe3d0f080, 0x0004);
+	/* br %r14 */
+	EMIT2(0x07fe);
+}
+
+/*
+ * make sure we dont leak kernel information to user
+ */
+static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
+{
+	/* Clear temporary memory if (seen & SEEN_MEM) */
+	if (jit->seen & SEEN_MEM)
+		/* xc 0(64,%r15),0(%r15) */
+		EMIT6(0xd73ff000, 0xf000);
+	/* Clear X if (seen & SEEN_XREG) */
+	if (jit->seen & SEEN_XREG)
+		/* lhi %r12,0 */
+		EMIT4(0xa7c80000);
+	/* Clear A if the first register does not set it. */
+	switch (filter[0].code) {
+	case BPF_S_LD_W_ABS:
+	case BPF_S_LD_H_ABS:
+	case BPF_S_LD_B_ABS:
+	case BPF_S_LD_W_LEN:
+	case BPF_S_LD_W_IND:
+	case BPF_S_LD_H_IND:
+	case BPF_S_LD_B_IND:
+	case BPF_S_LDX_B_MSH:
+	case BPF_S_LD_IMM:
+	case BPF_S_LD_MEM:
+	case BPF_S_MISC_TXA:
+	case BPF_S_ANC_PROTOCOL:
+	case BPF_S_ANC_PKTTYPE:
+	case BPF_S_ANC_IFINDEX:
+	case BPF_S_ANC_MARK:
+	case BPF_S_ANC_QUEUE:
+	case BPF_S_ANC_HATYPE:
+	case BPF_S_ANC_RXHASH:
+	case BPF_S_ANC_CPU:
+	case BPF_S_RET_K:
+		/* first instruction sets A register */
+		break;
+	default: /* A = 0 */
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+	}
+}
+
+static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
+			unsigned int *addrs, int i, int last)
+{
+	unsigned int K;
+	int offset;
+	unsigned int mask;
+
+	K = filter->k;
+	switch (filter->code) {
+	case BPF_S_ALU_ADD_X: /* A += X */
+		jit->seen |= SEEN_XREG;
+		/* ar %r5,%r12 */
+		EMIT2(0x1a5c);
+		break;
+	case BPF_S_ALU_ADD_K: /* A += K */
+		if (!K)
+			break;
+		if (K <= 16383)
+			/* ahi %r5,<K> */
+			EMIT4_IMM(0xa75a0000, K);
+		else if (test_facility(21))
+			/* alfi %r5,<K> */
+			EMIT6_IMM(0xc25b0000, K);
+		else
+			/* a %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5a50d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_SUB_X: /* A -= X */
+		jit->seen |= SEEN_XREG;
+		/* sr %r5,%r12 */
+		EMIT2(0x1b5c);
+		break;
+	case BPF_S_ALU_SUB_K: /* A -= K */
+		if (!K)
+			break;
+		if (K <= 16384)
+			/* ahi %r5,-K */
+			EMIT4_IMM(0xa75a0000, -K);
+		else if (test_facility(21))
+			/* alfi %r5,-K */
+			EMIT6_IMM(0xc25b0000, -K);
+		else
+			/* s %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5b50d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_MUL_X: /* A *= X */
+		jit->seen |= SEEN_XREG;
+		/* msr %r5,%r12 */
+		EMIT4(0xb252005c);
+		break;
+	case BPF_S_ALU_MUL_K: /* A *= K */
+		if (K <= 16383)
+			/* mhi %r5,K */
+			EMIT4_IMM(0xa75c0000, K);
+		else if (test_facility(34))
+			/* msfi %r5,<K> */
+			EMIT6_IMM(0xc2510000, K);
+		else
+			/* ms %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x7150d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_DIV_X: /* A /= X */
+		jit->seen |= SEEN_XREG | SEEN_RET0;
+		/* ltr %r12,%r12 */
+		EMIT2(0x12cc);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, (jit->ret0_ip - jit->prg));
+		/* lhi %r4,0 */
+		EMIT4(0xa7480000);
+		/* dr %r4,%r12 */
+		EMIT2(0x1d4c);
+		break;
+	case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K) */
+		/* m %r4,<d(K)>(%r13) */
+		EMIT4_DISP(0x5c40d000, EMIT_CONST(K));
+		/* lr %r5,%r4 */
+		EMIT2(0x1854);
+		break;
+	case BPF_S_ALU_AND_X: /* A &= X */
+		jit->seen |= SEEN_XREG;
+		/* nr %r5,%r12 */
+		EMIT2(0x145c);
+		break;
+	case BPF_S_ALU_AND_K: /* A &= K */
+		if (test_facility(21))
+			/* nilf %r5,<K> */
+			EMIT6_IMM(0xc05b0000, K);
+		else
+			/* n %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5450d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_OR_X: /* A |= X */
+		jit->seen |= SEEN_XREG;
+		/* or %r5,%r12 */
+		EMIT2(0x165c);
+		break;
+	case BPF_S_ALU_OR_K: /* A |= K */
+		if (test_facility(21))
+			/* oilf %r5,<K> */
+			EMIT6_IMM(0xc05d0000, K);
+		else
+			/* o %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5650d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
+		jit->seen |= SEEN_XREG;
+		/* xr %r5,%r12 */
+		EMIT2(0x175c);
+		break;
+	case BPF_S_ALU_LSH_X: /* A <<= X; */
+		jit->seen |= SEEN_XREG;
+		/* sll %r5,0(%r12) */
+		EMIT4(0x8950c000);
+		break;
+	case BPF_S_ALU_LSH_K: /* A <<= K */
+		if (K == 0)
+			break;
+		/* sll %r5,K */
+		EMIT4_DISP(0x89500000, K);
+		break;
+	case BPF_S_ALU_RSH_X: /* A >>= X; */
+		jit->seen |= SEEN_XREG;
+		/* srl %r5,0(%r12) */
+		EMIT4(0x8850c000);
+		break;
+	case BPF_S_ALU_RSH_K: /* A >>= K; */
+		if (K == 0)
+			break;
+		/* srl %r5,K */
+		EMIT4_DISP(0x88500000, K);
+		break;
+	case BPF_S_ALU_NEG: /* A = -A */
+		/* lnr %r5,%r5 */
+		EMIT2(0x1155);
+		break;
+	case BPF_S_JMP_JA: /* ip += K */
+		offset = addrs[i + K] + jit->start - jit->prg;
+		EMIT4_PCREL(0xa7f40000, offset);
+		break;
+	case BPF_S_JMP_JGT_K: /* ip += (A > K) ? jt : jf */
+		mask = 0x200000; /* jh */
+		goto kbranch;
+	case BPF_S_JMP_JGE_K: /* ip += (A >= K) ? jt : jf */
+		mask = 0xa00000; /* jhe */
+		goto kbranch;
+	case BPF_S_JMP_JEQ_K: /* ip += (A == K) ? jt : jf */
+		mask = 0x800000; /* je */
+kbranch:	/* Emit compare if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			if (K <= 16383)
+				/* chi %r5,<K> */
+				EMIT4_IMM(0xa75e0000, K);
+			else if (test_facility(21))
+				/* clfi %r5,<K> */
+				EMIT6_IMM(0xc25f0000, K);
+			else
+				/* c %r5,<d(K)>(%r13) */
+				EMIT4_DISP(0x5950d000, EMIT_CONST(K));
+		}
+branch:		if (filter->jt == filter->jf) {
+			if (filter->jt == 0)
+				break;
+			/* j <jt> */
+			offset = addrs[i + filter->jt] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7f40000, offset);
+			break;
+		}
+		if (filter->jt != 0) {
+			/* brc	<mask>,<jt> */
+			offset = addrs[i + filter->jt] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7040000 | mask, offset);
+		}
+		if (filter->jf != 0) {
+			/* brc	<mask^15>,<jf> */
+			offset = addrs[i + filter->jf] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7040000 | (mask ^ 0xf00000), offset);
+		}
+		break;
+	case BPF_S_JMP_JSET_K: /* ip += (A & K) ? jt : jf */
+		mask = 0x700000; /* jnz */
+		/* Emit test if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			if (K > 65535) {
+				/* lr %r4,%r5 */
+				EMIT2(0x1845);
+				/* n %r4,<d(K)>(%r13) */
+				EMIT4_DISP(0x5440d000, EMIT_CONST(K));
+			} else
+				/* tmll %r5,K */
+				EMIT4_IMM(0xa7510000, K);
+		}
+		goto branch;
+	case BPF_S_JMP_JGT_X: /* ip += (A > X) ? jt : jf */
+		mask = 0x200000; /* jh */
+		goto xbranch;
+	case BPF_S_JMP_JGE_X: /* ip += (A >= X) ? jt : jf */
+		mask = 0xa00000; /* jhe */
+		goto xbranch;
+	case BPF_S_JMP_JEQ_X: /* ip += (A == X) ? jt : jf */
+		mask = 0x800000; /* je */
+xbranch:	/* Emit compare if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			jit->seen |= SEEN_XREG;
+			/* cr %r5,%r12 */
+			EMIT2(0x195c);
+		}
+		goto branch;
+	case BPF_S_JMP_JSET_X: /* ip += (A & X) ? jt : jf */
+		mask = 0x700000; /* jnz */
+		/* Emit test if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			jit->seen |= SEEN_XREG;
+			/* lr %r4,%r5 */
+			EMIT2(0x1845);
+			/* nr %r4,%r12 */
+			EMIT2(0x144c);
+		}
+		goto branch;
+	case BPF_S_LD_W_ABS: /* A = *(u32 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_WORD;
+		offset = jit->off_load_word;
+		goto load_abs;
+	case BPF_S_LD_H_ABS: /* A = *(u16 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_HALF;
+		offset = jit->off_load_half;
+		goto load_abs;
+	case BPF_S_LD_B_ABS: /* A = *(u8 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_BYTE;
+		offset = jit->off_load_byte;
+load_abs:	if ((int) K < 0)
+			goto out;
+call_fn:	/* lg %r1,<d(function)>(%r13) */
+		EMIT6_DISP(0xe310d000, 0x0004, offset);
+		/* l %r3,<d(K)>(%r13) */
+		EMIT4_DISP(0x5830d000, EMIT_CONST(K));
+		/* basr %r8,%r1 */
+		EMIT2(0x0d81);
+		/* jnz <ret0> */
+		EMIT4_PCREL(0xa7740000, (jit->ret0_ip - jit->prg));
+		break;
+	case BPF_S_LD_W_IND: /* A = *(u32 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IWORD;
+		offset = jit->off_load_iword;
+		goto call_fn;
+	case BPF_S_LD_H_IND: /* A = *(u16 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IHALF;
+		offset = jit->off_load_ihalf;
+		goto call_fn;
+	case BPF_S_LD_B_IND: /* A = *(u8 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IBYTE;
+		offset = jit->off_load_ibyte;
+		goto call_fn;
+	case BPF_S_LDX_B_MSH:
+		/* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+		jit->seen |= SEEN_RET0;
+		if ((int) K < 0) {
+			/* j <ret0> */
+			EMIT4_PCREL(0xa7f40000, (jit->ret0_ip - jit->prg));
+			break;
+		}
+		jit->seen |= SEEN_DATAREF | SEEN_LOAD_BMSH;
+		offset = jit->off_load_bmsh;
+		goto call_fn;
+	case BPF_S_LD_W_LEN: /*	A = skb->len; */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+		/* l %r5,<d(len)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, len));
+		break;
+	case BPF_S_LDX_W_LEN: /* X = skb->len; */
+		jit->seen |= SEEN_XREG;
+		/* l %r12,<d(len)>(%r2) */
+		EMIT4_DISP(0x58c02000, offsetof(struct sk_buff, len));
+		break;
+	case BPF_S_LD_IMM: /* A = K */
+		if (K <= 16383)
+			/* lhi %r5,K */
+			EMIT4_IMM(0xa7580000, K);
+		else if (test_facility(21))
+			/* llilf %r5,<K> */
+			EMIT6_IMM(0xc05f0000, K);
+		else
+			/* l %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5850d000, EMIT_CONST(K));
+		break;
+	case BPF_S_LDX_IMM: /* X = K */
+		jit->seen |= SEEN_XREG;
+		if (K <= 16383)
+			/* lhi %r12,<K> */
+			EMIT4_IMM(0xa7c80000, K);
+		else if (test_facility(21))
+			/* llilf %r12,<K> */
+			EMIT6_IMM(0xc0cf0000, K);
+		else
+			/* l %r12,<d(K)>(%r13) */
+			EMIT4_DISP(0x58c0d000, EMIT_CONST(K));
+		break;
+	case BPF_S_LD_MEM: /* A = mem[K] */
+		jit->seen |= SEEN_MEM;
+		/* l %r5,<K>(%r15) */
+		EMIT4_DISP(0x5850f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_LDX_MEM: /* X = mem[K] */
+		jit->seen |= SEEN_XREG | SEEN_MEM;
+		/* l %r12,<K>(%r15) */
+		EMIT4_DISP(0x58c0f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_MISC_TAX: /* X = A */
+		jit->seen |= SEEN_XREG;
+		/* lr %r12,%r5 */
+		EMIT2(0x18c5);
+		break;
+	case BPF_S_MISC_TXA: /* A = X */
+		jit->seen |= SEEN_XREG;
+		/* lr %r5,%r12 */
+		EMIT2(0x185c);
+		break;
+	case BPF_S_RET_K:
+		if (K == 0) {
+			jit->seen |= SEEN_RET0;
+			if (last)
+				break;
+			/* j <ret0> */
+			EMIT4_PCREL(0xa7f40000, jit->ret0_ip - jit->prg);
+		} else {
+			if (K <= 16383)
+				/* lghi %r2,K */
+				EMIT4_IMM(0xa7290000, K);
+			else
+				/* llgf %r2,<K>(%r13) */
+				EMIT6_DISP(0xe320d000, 0x0016, EMIT_CONST(K));
+			/* j <exit> */
+			if (last && !(jit->seen & SEEN_RET0))
+				break;
+			EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+		}
+		break;
+	case BPF_S_RET_A:
+		/* llgfr %r2,%r5 */
+		EMIT4(0xb9160025);
+		/* j <exit> */
+		EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+		break;
+	case BPF_S_ST: /* mem[K] = A */
+		jit->seen |= SEEN_MEM;
+		/* st %r5,<K>(%r15) */
+		EMIT4_DISP(0x5050f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
+		jit->seen |= SEEN_XREG | SEEN_MEM;
+		/* st %r12,<K>(%r15) */
+		EMIT4_DISP(0x50c0f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(protocol)>(%r2) */
+		EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, protocol));
+		break;
+	case BPF_S_ANC_IFINDEX:	/* if (!skb->dev) return 0;
+				 * A = skb->dev->ifindex */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+		jit->seen |= SEEN_RET0;
+		/* lg %r1,<d(dev)>(%r2) */
+		EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+		/* ltgr %r1,%r1 */
+		EMIT4(0xb9020011);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+		/* l %r5,<d(ifindex)>(%r1) */
+		EMIT4_DISP(0x58501000, offsetof(struct net_device, ifindex));
+		break;
+	case BPF_S_ANC_MARK: /* A = skb->mark */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+		/* l %r5,<d(mark)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, mark));
+		break;
+	case BPF_S_ANC_QUEUE: /* A = skb->queue_mapping */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(queue_mapping)>(%r2) */
+		EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, queue_mapping));
+		break;
+	case BPF_S_ANC_HATYPE:	/* if (!skb->dev) return 0;
+				 * A = skb->dev->type */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
+		jit->seen |= SEEN_RET0;
+		/* lg %r1,<d(dev)>(%r2) */
+		EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+		/* ltgr %r1,%r1 */
+		EMIT4(0xb9020011);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(type)>(%r1) */
+		EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
+		break;
+	case BPF_S_ANC_RXHASH: /* A = skb->rxhash */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+		/* l %r5,<d(rxhash)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
+		break;
+	case BPF_S_ANC_CPU: /* A = smp_processor_id() */
+#ifdef CONFIG_SMP
+		/* l %r5,<d(cpu_nr)> */
+		EMIT4_DISP(0x58500000, offsetof(struct _lowcore, cpu_nr));
+#else
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+#endif
+		break;
+	default: /* too complex, give up */
+		goto out;
+	}
+	addrs[i] = jit->prg - jit->start;
+	return 0;
+out:
+	return -1;
+}
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+	unsigned long size, prg_len, lit_len;
+	struct bpf_jit jit, cjit;
+	unsigned int *addrs;
+	int pass, i;
+
+	if (!bpf_jit_enable)
+		return;
+	addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL);
+	if (addrs == NULL)
+		return;
+	memset(addrs, 0, fp->len * sizeof(*addrs));
+	memset(&jit, 0, sizeof(cjit));
+	memset(&cjit, 0, sizeof(cjit));
+
+	for (pass = 0; pass < 10; pass++) {
+		jit.prg = jit.start;
+		jit.lit = jit.mid;
+
+		bpf_jit_prologue(&jit);
+		bpf_jit_noleaks(&jit, fp->insns);
+		for (i = 0; i < fp->len; i++) {
+			if (bpf_jit_insn(&jit, fp->insns + i, addrs, i,
+					 i == fp->len - 1))
+				goto out;
+		}
+		bpf_jit_epilogue(&jit);
+		if (jit.start) {
+			WARN_ON(jit.prg > cjit.prg || jit.lit > cjit.lit);
+			if (memcmp(&jit, &cjit, sizeof(jit)) == 0)
+				break;
+		} else if (jit.prg == cjit.prg && jit.lit == cjit.lit) {
+			prg_len = jit.prg - jit.start;
+			lit_len = jit.lit - jit.mid;
+			size = max_t(unsigned long, prg_len + lit_len,
+				     sizeof(struct work_struct));
+			if (size >= BPF_SIZE_MAX)
+				goto out;
+			jit.start = module_alloc(size);
+			if (!jit.start)
+				goto out;
+			jit.prg = jit.mid = jit.start + prg_len;
+			jit.lit = jit.end = jit.start + prg_len + lit_len;
+			jit.base_ip += (unsigned long) jit.start;
+			jit.exit_ip += (unsigned long) jit.start;
+			jit.ret0_ip += (unsigned long) jit.start;
+		}
+		cjit = jit;
+	}
+	if (bpf_jit_enable > 1) {
+		pr_err("flen=%d proglen=%lu pass=%d image=%p\n",
+		       fp->len, jit.end - jit.start, pass, jit.start);
+		if (jit.start) {
+			printk(KERN_ERR "JIT code:\n");
+			print_fn_code(jit.start, jit.mid - jit.start);
+			print_hex_dump(KERN_ERR, "JIT literals:\n",
+				       DUMP_PREFIX_ADDRESS, 16, 1,
+				       jit.mid, jit.end - jit.mid, false);
+		}
+	}
+	if (jit.start)
+		fp->bpf_func = (void *) jit.start;
+out:
+	kfree(addrs);
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+	module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+	struct work_struct *work;
+
+	if (fp->bpf_func == sk_run_filter)
+		return;
+	work = (struct work_struct *)fp->bpf_func;
+	INIT_WORK(work, jit_free_defer);
+	schedule_work(work);
+}
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c
index 2707023..637970c 100644
--- a/arch/score/kernel/process.c
+++ b/arch/score/kernel/process.c
@@ -27,6 +27,7 @@
 #include <linux/reboot.h>
 #include <linux/elfcore.h>
 #include <linux/pm.h>
+#include <linux/rcupdate.h>
 
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
@@ -50,9 +51,10 @@
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched())
 			barrier();
-
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 40db2d0..a7e078f 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -192,11 +192,6 @@
 	return pci_enable_resources(dev, mask);
 }
 
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 static void __init
 pcibios_bus_report_status_early(struct pci_channel *hose,
 				int top_bus, int current_bus,
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b7cf6a5..7e605b9 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@
 
 	pta	restore_all, tr1
 
-	movi	_TIF_SIGPENDING, r8
+	movi	(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME), r8
 	and	r8, r7, r8
 	pta	work_notifysig, tr0
 	bne	r8, ZERO, tr0
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index f67601c..b96489d 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -139,7 +139,7 @@
 	! r8: current_thread_info
 	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
 	bf/s	work_resched
-	 tst	#_TIF_SIGPENDING, r0
+	 tst	#(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME), r0
 work_notifysig:
 	bt/s	__restore_all
 	 mov	r15, r4
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 21dcda7..fc05211 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -102,15 +102,6 @@
 	return pci_enable_resources(dev, mask);
 }
 
-void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-#ifdef CONFIG_PCI_DEBUG
-	printk(KERN_DEBUG "LEONPCI: Assigning IRQ %02d to %s\n", irq,
-		pci_name(dev));
-#endif
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 /* in/out routines taken from pcic.c
  *
  * This probably belongs here rather than ioport.c because
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 15e0a16..f1ddc0d 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -48,9 +48,7 @@
 		return NULL;
 
 	ret = module_map(size);
-	if (!ret)
-		ret = ERR_PTR(-ENOMEM);
-	else
+	if (ret)
 		memset(ret, 0, size);
 
 	return ret;
@@ -116,6 +114,10 @@
 		v = sym->st_value + rel[i].r_addend;
 
 		switch (ELF_R_TYPE(rel[i].r_info) & 0xff) {
+		case R_SPARC_DISP32:
+			v -= (Elf_Addr) location;
+			*loc32 = v;
+			break;
 #ifdef CONFIG_SPARC64
 		case R_SPARC_64:
 			location[0] = v >> 56;
@@ -128,11 +130,6 @@
 			location[7] = v >>  0;
 			break;
 
-		case R_SPARC_DISP32:
-			v -= (Elf_Addr) location;
-			*loc32 = v;
-			break;
-
 		case R_SPARC_WDISP19:
 			v -= (Elf_Addr) location;
 			*loc32 = (*loc32 & ~0x7ffff) |
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 065b88c..acc8c83 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -622,10 +622,6 @@
 {
 }
 
-void pcibios_update_irq(struct pci_dev *pdev, int irq)
-{
-}
-
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 				resource_size_t size, resource_size_t align)
 {
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 932e443..c9a3c1f 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -412,14 +412,6 @@
 config NEED_BOUNCE_POOL
 	def_bool USB_OHCI_HCD
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-	  One well-known example of this is USB.
-
 source "drivers/pci/hotplug/Kconfig"
 
 endmenu
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 7a7ce390..d5e86c9 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -69,7 +69,6 @@
 				| 1*SD_BALANCE_FORK			\
 				| 0*SD_BALANCE_WAKE			\
 				| 0*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
 				| 0*SD_SHARE_CPUPOWER			\
 				| 0*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
diff --git a/arch/tile/include/gxio/iorpc_trio.h b/arch/tile/include/gxio/iorpc_trio.h
index 15fb779..58105c3 100644
--- a/arch/tile/include/gxio/iorpc_trio.h
+++ b/arch/tile/include/gxio/iorpc_trio.h
@@ -25,21 +25,23 @@
 #include <linux/module.h>
 #include <asm/pgtable.h>
 
-#define GXIO_TRIO_OP_ALLOC_ASIDS       IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
+#define GXIO_TRIO_OP_DEALLOC_ASID      IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
+#define GXIO_TRIO_OP_ALLOC_ASIDS       IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1401)
 
-#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1402)
+#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404)
 
-#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
-#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140f)
+#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412)
 
-#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1417)
-#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1418)
-#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1419)
-#define GXIO_TRIO_OP_CONFIG_MSI_INTR   IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x141a)
+#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414)
 
-#define GXIO_TRIO_OP_SET_MPS_MRS       IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141c)
-#define GXIO_TRIO_OP_FORCE_RC_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141d)
-#define GXIO_TRIO_OP_FORCE_EP_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
+#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
+#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141f)
+#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1420)
+#define GXIO_TRIO_OP_CONFIG_MSI_INTR   IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1421)
+
+#define GXIO_TRIO_OP_SET_MPS_MRS       IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1423)
+#define GXIO_TRIO_OP_FORCE_RC_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1424)
+#define GXIO_TRIO_OP_FORCE_EP_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1425)
 #define GXIO_TRIO_OP_GET_MMIO_BASE     IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index 33c1086..7598226 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -246,16 +246,13 @@
 
 	/* Scan for the smallest maximum payload size. */
 	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		int pcie_caps_offset;
 		u32 devcap;
 		int max_payload;
 
-		pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
-		if (pcie_caps_offset == 0)
+		if (!pci_is_pcie(dev))
 			continue;
 
-		pci_read_config_dword(dev, pcie_caps_offset + PCI_EXP_DEVCAP,
-				      &devcap);
+		pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &devcap);
 		max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
 		if (max_payload < smallest_max_payload)
 			smallest_max_payload = max_payload;
@@ -263,21 +260,10 @@
 
 	/* Now, set the max_payload_size for all devices to that value. */
 	new_values = (max_read_size << 12) | (smallest_max_payload << 5);
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		int pcie_caps_offset;
-		u16 devctl;
-
-		pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
-		if (pcie_caps_offset == 0)
-			continue;
-
-		pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
-				     &devctl);
-		devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ);
-		devctl |= new_values;
-		pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
-				      devctl);
-	}
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+				PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ,
+				new_values);
 }
 
 
@@ -404,14 +390,6 @@
 }
 
 /*
- * This is called from the generic Linux layer.
- */
-void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
-/*
  * Enable memory and/or address decoding, as appropriate, for the
  * device described by the 'dev' struct.
  *
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index 0e213e3..2ba6d05 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -1034,14 +1034,6 @@
 }
 
 /*
- * This is called from the generic Linux layer.
- */
-void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
-/*
  * Enable memory address decoding, as appropriate, for the
  * device described by the 'dev' struct. The I/O decoding
  * is disabled, though the TILE-Gx supports I/O addressing.
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 664a60e..c17de0d 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -705,6 +705,7 @@
 	struct task_struct *from = current, *to = arg;
 
 	to->thread.saved_task = from;
+	rcu_switch(from, to);
 	switch_to(from, to, from);
 }
 
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index 69f1c57..33a6a24 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -20,14 +20,6 @@
 
 struct thread_struct {
 	struct task_struct *saved_task;
-	/*
-	 * This flag is set to 1 before calling do_fork (and analyzed in
-	 * copy_thread) to mark that we are begin called from userspace (fork /
-	 * vfork / clone), and reset to 0 after. It is left to 0 when called
-	 * from kernelspace (i.e. kernel_thread() or fork_idle(),
-	 * as of 2.6.11).
-	 */
-	int forking;
 	struct pt_regs regs;
 	int singlestep_syscall;
 	void *fault_addr;
@@ -58,7 +50,6 @@
 
 #define INIT_THREAD \
 { \
-	.forking		= 0, \
 	.regs		   	= EMPTY_REGS,	\
 	.fault_addr		= NULL, \
 	.prev_sched		= NULL, \
diff --git a/arch/um/include/shared/common-offsets.h b/arch/um/include/shared/common-offsets.h
index 40db8f7..2df313b 100644
--- a/arch/um/include/shared/common-offsets.h
+++ b/arch/um/include/shared/common-offsets.h
@@ -7,16 +7,6 @@
 DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT);
 DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
 
-DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
-DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
-DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
-DEFINE_STR(UM_KERN_ERR, KERN_ERR);
-DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
-DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
-DEFINE_STR(UM_KERN_INFO, KERN_INFO);
-DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
-DEFINE_STR(UM_KERN_CONT, KERN_CONT);
-
 DEFINE(UM_ELF_CLASS, ELF_CLASS);
 DEFINE(UM_ELFCLASS32, ELFCLASS32);
 DEFINE(UM_ELFCLASS64, ELFCLASS64);
diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h
index 4fa82c0..cef0685 100644
--- a/arch/um/include/shared/user.h
+++ b/arch/um/include/shared/user.h
@@ -26,6 +26,17 @@
 extern void panic(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 
+/* Requires preincluding include/linux/kern_levels.h */
+#define UM_KERN_EMERG	KERN_EMERG
+#define UM_KERN_ALERT	KERN_ALERT
+#define UM_KERN_CRIT	KERN_CRIT
+#define UM_KERN_ERR	KERN_ERR
+#define UM_KERN_WARNING	KERN_WARNING
+#define UM_KERN_NOTICE	KERN_NOTICE
+#define UM_KERN_INFO	KERN_INFO
+#define UM_KERN_DEBUG	KERN_DEBUG
+#define UM_KERN_CONT	KERN_CONT
+
 #ifdef UML_CONFIG_PRINTK
 extern int printk(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 6cade93..8c82786 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -39,34 +39,21 @@
 
 void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
 {
+	get_safe_registers(regs->regs.gp, regs->regs.fp);
 	PT_REGS_IP(regs) = eip;
 	PT_REGS_SP(regs) = esp;
+	current->ptrace &= ~PT_DTRACE;
+#ifdef SUBARCH_EXECVE1
+	SUBARCH_EXECVE1(regs->regs);
+#endif
 }
 EXPORT_SYMBOL(start_thread);
 
-static long execve1(const char *file,
-		    const char __user *const __user *argv,
-		    const char __user *const __user *env)
-{
-	long error;
-
-	error = do_execve(file, argv, env, &current->thread.regs);
-	if (error == 0) {
-		task_lock(current);
-		current->ptrace &= ~PT_DTRACE;
-#ifdef SUBARCH_EXECVE1
-		SUBARCH_EXECVE1(&current->thread.regs.regs);
-#endif
-		task_unlock(current);
-	}
-	return error;
-}
-
 long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env)
 {
 	long err;
 
-	err = execve1(file, argv, env);
+	err = do_execve(file, argv, env, &current->thread.regs);
 	if (!err)
 		UML_LONGJMP(current->thread.exec_buf, 1);
 	return err;
@@ -81,7 +68,7 @@
 	filename = getname(file);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename)) goto out;
-	error = execve1(filename, argv, env);
+	error = do_execve(filename, argv, env, &current->thread.regs);
 	putname(filename);
  out:
 	return error;
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 57fc702..c5f5afa 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -181,11 +181,12 @@
 		struct pt_regs *regs)
 {
 	void (*handler)(void);
+	int kthread = current->flags & PF_KTHREAD;
 	int ret = 0;
 
 	p->thread = (struct thread_struct) INIT_THREAD;
 
-	if (current->thread.forking) {
+	if (!kthread) {
 	  	memcpy(&p->thread.regs.regs, &regs->regs,
 		       sizeof(p->thread.regs.regs));
 		PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
@@ -195,8 +196,7 @@
 		handler = fork_handler;
 
 		arch_copy_thread(&current->thread.arch, &p->thread.arch);
-	}
-	else {
+	} else {
 		get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
 		p->thread.request.u.thread = current->thread.request.u.thread;
 		handler = new_thread_handler;
@@ -204,7 +204,7 @@
 
 	new_thread(task_stack_page(p), &p->thread.switch_buf, handler);
 
-	if (current->thread.forking) {
+	if (!kthread) {
 		clear_flushed_tls(p);
 
 		/*
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 7362d58..cc9c235 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -22,9 +22,13 @@
 			 struct k_sigaction *ka, siginfo_t *info)
 {
 	sigset_t *oldset = sigmask_to_save();
+	int singlestep = 0;
 	unsigned long sp;
 	int err;
 
+	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+		singlestep = 1;
+
 	/* Did we come from a system call? */
 	if (PT_REGS_SYSCALL_NR(regs) >= 0) {
 		/* If so, check system call restarting.. */
@@ -61,7 +65,7 @@
 	if (err)
 		force_sigsegv(signr, current);
 	else
-		signal_delivered(signr, info, ka, regs, 0);
+		signal_delivered(signr, info, ka, regs, singlestep);
 }
 
 static int kern_do_signal(struct pt_regs *regs)
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index f958cb8..a4c6d8e 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -17,25 +17,25 @@
 
 long sys_fork(void)
 {
-	long ret;
-
-	current->thread.forking = 1;
-	ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+	return do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
 		      &current->thread.regs, 0, NULL, NULL);
-	current->thread.forking = 0;
-	return ret;
 }
 
 long sys_vfork(void)
 {
-	long ret;
-
-	current->thread.forking = 1;
-	ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
 		      UPT_SP(&current->thread.regs.regs),
 		      &current->thread.regs, 0, NULL, NULL);
-	current->thread.forking = 0;
-	return ret;
+}
+
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+	       void __user *parent_tid, void __user *child_tid)
+{
+	if (!newsp)
+		newsp = UPT_SP(&current->thread.regs.regs);
+
+	return do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+		      child_tid);
 }
 
 long old_mmap(unsigned long addr, unsigned long len,
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index d50270d..15889df 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -8,7 +8,7 @@
 USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 $(USER_OBJS:.o=.%): \
-	c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include user.h $(CFLAGS_$(basetarget).o)
+	c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o)
 
 # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of
 # using it directly.
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index 46cb6c9..b0056f6 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -154,14 +154,6 @@
 	zhole_size[0] = 0;
 }
 
-void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	if (debug_pci)
-		printk(KERN_DEBUG "PCI: Assigning IRQ %02d to %s\n",
-				irq, pci_name(dev));
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 /*
  * If the bus contains any of these devices, then we must not turn on
  * parity checking of any kind.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8ec3a1a..7f9a395 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -7,11 +7,13 @@
 	  Say no to build a 32-bit kernel - formerly known as i386
 
 config X86_32
-	def_bool !64BIT
+	def_bool y
+	depends on !64BIT
 	select CLKSRC_I8253
 
 config X86_64
-	def_bool 64BIT
+	def_bool y
+	depends on 64BIT
 	select X86_DEV_DMA_OPS
 
 ### Arch settings
@@ -36,6 +38,7 @@
 	select HAVE_KRETPROBES
 	select HAVE_OPTPROBES
 	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_FENTRY if X86_64
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FUNCTION_TRACER
@@ -60,6 +63,8 @@
 	select HAVE_MIXED_BREAKPOINTS_REGS
 	select PERF_EVENTS
 	select HAVE_PERF_EVENTS_NMI
+	select HAVE_PERF_REGS
+	select HAVE_PERF_USER_STACK_DUMP
 	select ANON_INODES
 	select HAVE_ALIGNED_STRUCT_PAGE if SLUB && !M386
 	select HAVE_CMPXCHG_LOCAL if !M386
@@ -97,9 +102,12 @@
 	select KTIME_SCALAR if X86_32
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select HAVE_RCU_USER_QS if X86_64
+	select HAVE_IRQ_TIME_ACCOUNTING
 
 config INSTRUCTION_DECODER
-	def_bool (KPROBES || PERF_EVENTS || UPROBES)
+	def_bool y
+	depends on KPROBES || PERF_EVENTS || UPROBES
 
 config OUTPUT_FORMAT
 	string
@@ -127,13 +135,15 @@
 	bool
 
 config NEED_DMA_MAP_STATE
-       def_bool (X86_64 || INTEL_IOMMU || DMA_API_DEBUG)
+	def_bool y
+	depends on X86_64 || INTEL_IOMMU || DMA_API_DEBUG
 
 config NEED_SG_DMA_LENGTH
 	def_bool y
 
 config GENERIC_ISA_DMA
-	def_bool ISA_DMA_API
+	def_bool y
+	depends on ISA_DMA_API
 
 config GENERIC_BUG
 	def_bool y
@@ -150,13 +160,16 @@
 	bool
 
 config ARCH_MAY_HAVE_PC_FDC
-	def_bool ISA_DMA_API
+	def_bool y
+	depends on ISA_DMA_API
 
 config RWSEM_GENERIC_SPINLOCK
-	def_bool !X86_XADD
+	def_bool y
+	depends on !X86_XADD
 
 config RWSEM_XCHGADD_ALGORITHM
-	def_bool X86_XADD
+	def_bool y
+	depends on X86_XADD
 
 config GENERIC_CALIBRATE_DELAY
 	def_bool y
@@ -746,13 +759,14 @@
 	def_bool y if X86_64
 	---help---
 	  Support for software bounce buffers used on x86-64 systems
-	  which don't have a hardware IOMMU (e.g. the current generation
-	  of Intel's x86-64 CPUs). Using this PCI devices which can only
-	  access 32-bits of memory can be used on systems with more than
-	  3 GB of memory. If unsure, say Y.
+	  which don't have a hardware IOMMU. Using this PCI devices
+	  which can only access 32-bits of memory can be used on systems
+	  with more than 3 GB of memory.
+	  If unsure, say Y.
 
 config IOMMU_HELPER
-	def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB || AMD_IOMMU)
+	def_bool y
+	depends on CALGARY_IOMMU || GART_IOMMU || SWIOTLB || AMD_IOMMU
 
 config MAXSMP
 	bool "Enable Maximum number of SMP Processors and NUMA Nodes"
@@ -796,17 +810,6 @@
 	  making when dealing with multi-core CPU chips at a cost of slightly
 	  increased overhead in some places. If unsure say N here.
 
-config IRQ_TIME_ACCOUNTING
-	bool "Fine granularity task level IRQ time accounting"
-	default n
-	---help---
-	  Select this option to enable fine granularity task irq time
-	  accounting. This is done by reading a timestamp on each
-	  transitions between softirq and hardirq state, so there can be a
-	  small performance impact.
-
-	  If in doubt, say N here.
-
 source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
@@ -871,6 +874,7 @@
 
 config X86_MCE
 	bool "Machine Check / overheating reporting"
+	default y
 	---help---
 	  Machine Check support allows the processor to notify the
 	  kernel if it detects a problem (e.g. overheating, data corruption).
@@ -982,25 +986,25 @@
 	  Say N otherwise.
 
 config MICROCODE
-	tristate "/dev/cpu/microcode - microcode support"
+	tristate "CPU microcode loading support"
 	select FW_LOADER
 	---help---
+
 	  If you say Y here, you will be able to update the microcode on
 	  certain Intel and AMD processors. The Intel support is for the
-	  IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
-	  Pentium 4, Xeon etc. The AMD support is for family 0x10 and
-	  0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
-	  You will obviously need the actual microcode binary data itself
-	  which is not shipped with the Linux kernel.
+	  IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
+	  Xeon etc. The AMD support is for families 0x10 and later. You will
+	  obviously need the actual microcode binary data itself which is not
+	  shipped with the Linux kernel.
 
 	  This option selects the general module only, you need to select
 	  at least one vendor specific module as well.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called microcode.
+	  To compile this driver as a module, choose M here: the module
+	  will be called microcode.
 
 config MICROCODE_INTEL
-	bool "Intel microcode patch loading support"
+	bool "Intel microcode loading support"
 	depends on MICROCODE
 	default MICROCODE
 	select FW_LOADER
@@ -1013,7 +1017,7 @@
 	  <http://www.urbanmyth.org/microcode/>.
 
 config MICROCODE_AMD
-	bool "AMD microcode patch loading support"
+	bool "AMD microcode loading support"
 	depends on MICROCODE
 	select FW_LOADER
 	---help---
@@ -1159,10 +1163,12 @@
 	  consumes more pagetable space per process.
 
 config ARCH_PHYS_ADDR_T_64BIT
-	def_bool X86_64 || X86_PAE
+	def_bool y
+	depends on X86_64 || X86_PAE
 
 config ARCH_DMA_ADDR_T_64BIT
-	def_bool X86_64 || HIGHMEM64G
+	def_bool y
+	depends on X86_64 || HIGHMEM64G
 
 config DIRECT_GBPAGES
 	bool "Enable 1GB pages for kernel pagetables" if EXPERT
@@ -1285,8 +1291,8 @@
 	depends on ARCH_SPARSEMEM_ENABLE
 
 config ARCH_MEMORY_PROBE
-	def_bool X86_64
-	depends on MEMORY_HOTPLUG
+	def_bool y
+	depends on X86_64 && MEMORY_HOTPLUG
 
 config ARCH_PROC_KCORE_TEXT
 	def_bool y
@@ -1487,6 +1493,17 @@
 	  If supported, this is a high bandwidth, cryptographically
 	  secure hardware random number generator.
 
+config X86_SMAP
+	def_bool y
+	prompt "Supervisor Mode Access Prevention" if EXPERT
+	---help---
+	  Supervisor Mode Access Prevention (SMAP) is a security
+	  feature in newer Intel processors.  There is a small
+	  performance cost if this enabled and turned on; there is
+	  also a small increase in the kernel size if this is enabled.
+
+	  If unsure, say Y.
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
@@ -1975,7 +1992,6 @@
 
 config PCI_CNB20LE_QUIRK
 	bool "Read CNB20LE Host Bridge Windows" if EXPERT
-	default n
 	depends on PCI && EXPERIMENTAL
 	help
 	  Read the PCI windows out of the CNB20LE host bridge. This allows
@@ -2186,18 +2202,18 @@
 	depends on IA32_EMULATION || X86_X32
 	select ARCH_WANT_OLD_COMPAT_IPC
 
+if COMPAT
 config COMPAT_FOR_U64_ALIGNMENT
-	def_bool COMPAT
-	depends on X86_64
+	def_bool y
 
 config SYSVIPC_COMPAT
 	def_bool y
-	depends on COMPAT && SYSVIPC
+	depends on SYSVIPC
 
 config KEYS_COMPAT
-	bool
-	depends on COMPAT && KEYS
-	default y
+	def_bool y
+	depends on KEYS
+endif
 
 endmenu
 
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 706e12e..f3b86d0df 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -306,7 +306,8 @@
 	default X86_L1_CACHE_SHIFT
 
 config X86_CMPXCHG
-	def_bool X86_64 || (X86_32 && !M386)
+	def_bool y
+	depends on X86_64 || (X86_32 && !M386)
 
 config X86_L1_CACHE_SHIFT
 	int
@@ -317,7 +318,7 @@
 
 config X86_XADD
 	def_bool y
-	depends on X86_64 || !M386
+	depends on !M386
 
 config X86_PPRO_FENCE
 	bool "PentiumPro memory ordering errata workaround"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 682e9c2..474ca35 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -142,7 +142,7 @@
 KBUILD_CFLAGS += $(mflags-y)
 KBUILD_AFLAGS += $(mflags-y)
 
-archscripts:
+archscripts: scripts_basic
 	$(Q)$(MAKE) $(build)=arch/x86/tools relocs
 
 ###
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index e398bb5..8a84501 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -28,6 +28,9 @@
 	$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
 	$(obj)/piggy.o
 
+$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
+$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone
+
 ifeq ($(CONFIG_EFI_STUB), y)
 	VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
 endif
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index b3e0227..c760e07 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -276,8 +276,9 @@
 	nr_gops = size / sizeof(void *);
 	for (i = 0; i < nr_gops; i++) {
 		struct efi_graphics_output_mode_info *info;
-		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
-		void *pciio;
+		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+		bool conout_found = false;
+		void *dummy;
 		void *h = gop_handle[i];
 
 		status = efi_call_phys3(sys_table->boottime->handle_protocol,
@@ -285,19 +286,21 @@
 		if (status != EFI_SUCCESS)
 			continue;
 
-		efi_call_phys3(sys_table->boottime->handle_protocol,
-			       h, &pciio_proto, &pciio);
+		status = efi_call_phys3(sys_table->boottime->handle_protocol,
+					h, &conout_proto, &dummy);
+
+		if (status == EFI_SUCCESS)
+			conout_found = true;
 
 		status = efi_call_phys4(gop->query_mode, gop,
 					gop->mode->mode, &size, &info);
-		if (status == EFI_SUCCESS && (!first_gop || pciio)) {
+		if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
 			/*
-			 * Apple provide GOPs that are not backed by
-			 * real hardware (they're used to handle
-			 * multiple displays). The workaround is to
-			 * search for a GOP implementing the PCIIO
-			 * protocol, and if one isn't found, to just
-			 * fallback to the first GOP.
+			 * Systems that use the UEFI Console Splitter may
+			 * provide multiple GOP devices, not all of which are
+			 * backed by real hardware. The workaround is to search
+			 * for a GOP implementing the ConOut protocol, and if
+			 * one isn't found, to just fall back to the first GOP.
 			 */
 			width = info->horizontal_resolution;
 			height = info->vertical_resolution;
@@ -308,10 +311,10 @@
 			pixels_per_scan_line = info->pixels_per_scan_line;
 
 			/*
-			 * Once we've found a GOP supporting PCIIO,
+			 * Once we've found a GOP supporting ConOut,
 			 * don't bother looking any further.
 			 */
-			if (pciio)
+			if (conout_found)
 				break;
 
 			first_gop = gop;
@@ -328,7 +331,6 @@
 	si->lfb_width = width;
 	si->lfb_height = height;
 	si->lfb_base = fb_base;
-	si->lfb_size = fb_size;
 	si->pages = 1;
 
 	if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
@@ -376,6 +378,10 @@
 		si->rsvd_pos = 0;
 	}
 
+	si->lfb_size = si->lfb_linelength * si->lfb_height;
+
+	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+
 free_handle:
 	efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
 	return status;
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index 3b6e156..e5b0a8f 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -14,6 +14,10 @@
 #define EFI_PAGE_SIZE		(1UL << EFI_PAGE_SHIFT)
 #define EFI_READ_CHUNK_SIZE	(1024 * 1024)
 
+#define EFI_CONSOLE_OUT_DEVICE_GUID    \
+	EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
+		  0x3f, 0xc1, 0x4d)
+
 #define PIXEL_RGB_RESERVED_8BIT_PER_COLOR		0
 #define PIXEL_BGR_RESERVED_8BIT_PER_COLOR		1
 #define PIXEL_BIT_MASK					2
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index b4e15dd..2a01744 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -32,10 +32,6 @@
 #define SVGA_MODE ASK_VGA
 #endif
 
-#ifndef RAMDISK
-#define RAMDISK 0
-#endif
-
 #ifndef ROOT_RDONLY
 #define ROOT_RDONLY 1
 #endif
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 119db67..5598547 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -8,6 +8,8 @@
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_FREEZER=y
@@ -34,8 +36,6 @@
 CONFIG_SUN_PARTITION=y
 CONFIG_KARMA_PARTITION=y
 CONFIG_EFI_PARTITION=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 CONFIG_X86_GENERIC=y
 CONFIG_HPET_TIMER=y
@@ -144,8 +144,6 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_CONNECTOR=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
@@ -231,8 +229,6 @@
 CONFIG_SND_HDA_INTEL=y
 CONFIG_SND_HDA_HWDEP=y
 CONFIG_HIDRAW=y
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
 CONFIG_HID_GYRATION=y
 CONFIG_LOGITECH_FF=y
 CONFIG_HID_NTRIG=y
@@ -243,11 +239,11 @@
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
 CONFIG_HID_TOPSEED=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -262,10 +258,9 @@
 CONFIG_DMADEVICES=y
 CONFIG_EEEPC_LAPTOP=y
 CONFIG_EFI_VARS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
@@ -280,7 +275,6 @@
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
@@ -299,13 +293,11 @@
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_RODATA_TEST is not set
-CONFIG_DEBUG_NX_TEST=m
 CONFIG_DEBUG_BOOT_PARAMS=y
 CONFIG_OPTIMIZE_INLINING=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
@@ -316,4 +308,3 @@
 CONFIG_SECURITY_SELINUX_DISABLE=y
 CONFIG_CRYPTO_AES_586=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_T10DIF=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index 76eb290..671524d 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -8,6 +8,8 @@
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_FREEZER=y
@@ -34,8 +36,6 @@
 CONFIG_SUN_PARTITION=y
 CONFIG_KARMA_PARTITION=y
 CONFIG_EFI_PARTITION=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 CONFIG_CALGARY_IOMMU=y
 CONFIG_NR_CPUS=64
@@ -144,8 +144,6 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_CONNECTOR=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
@@ -227,8 +225,6 @@
 CONFIG_SND_HDA_INTEL=y
 CONFIG_SND_HDA_HWDEP=y
 CONFIG_HIDRAW=y
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
 CONFIG_HID_GYRATION=y
 CONFIG_LOGITECH_FF=y
 CONFIG_HID_NTRIG=y
@@ -239,11 +235,11 @@
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
 CONFIG_HID_TOPSEED=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -262,10 +258,9 @@
 CONFIG_INTEL_IOMMU=y
 # CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
 CONFIG_EFI_VARS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
@@ -280,7 +275,6 @@
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
@@ -298,13 +292,11 @@
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_RODATA_TEST is not set
-CONFIG_DEBUG_NX_TEST=m
 CONFIG_DEBUG_BOOT_PARAMS=y
 CONFIG_OPTIMIZE_INLINING=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
@@ -314,4 +306,3 @@
 CONFIG_SECURITY_SELINUX_BOOTPARAM=y
 CONFIG_SECURITY_SELINUX_DISABLE=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_T10DIF=y
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 673ac9b..efc6a95 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -32,6 +32,7 @@
 #include <asm/sigframe.h>
 #include <asm/sighandling.h>
 #include <asm/sys_ia32.h>
+#include <asm/smap.h>
 
 #define FIX_EFLAGS	__FIX_EFLAGS
 
@@ -162,7 +163,8 @@
 	}
 	seg = get_fs();
 	set_fs(KERNEL_DS);
-	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
+	ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
+			     (stack_t __force __user *) &uoss, regs->sp);
 	set_fs(seg);
 	if (ret >= 0 && uoss_ptr)  {
 		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
@@ -250,11 +252,12 @@
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-		err |= restore_i387_xstate_ia32(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_xstate_sig(buf, 1);
+
 	return err;
 }
 
@@ -361,7 +364,7 @@
  */
 static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
 				 size_t frame_size,
-				 void **fpstate)
+				 void __user **fpstate)
 {
 	unsigned long sp;
 
@@ -381,9 +384,12 @@
 		sp = (unsigned long) ka->sa.sa_restorer;
 
 	if (used_math()) {
-		sp = sp - sig_xstate_ia32_size;
-		*fpstate = (struct _fpstate_ia32 *) sp;
-		if (save_i387_xstate_ia32(*fpstate) < 0)
+		unsigned long fx_aligned, math_size;
+
+		sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
+		*fpstate = (struct _fpstate_ia32 __user *) sp;
+		if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
+				    math_size) < 0)
 			return (void __user *) -1L;
 	}
 
@@ -448,7 +454,7 @@
 		 * These are actually not used anymore, but left because some
 		 * gdb versions depend on them as a marker.
 		 */
-		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
+		put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
 	} put_user_catch(err);
 
 	if (err)
@@ -502,7 +508,6 @@
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
 		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
-		err |= copy_siginfo_to_user32(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -514,9 +519,6 @@
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					     regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		if (ka->sa.sa_flags & SA_RESTORER)
 			restorer = ka->sa.sa_restorer;
@@ -529,9 +531,14 @@
 		 * Not actually used anymore, but left because some gdb
 		 * versions need it.
 		 */
-		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
+		put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
 	} put_user_catch(err);
 
+	err |= copy_siginfo_to_user32(&frame->info, info);
+	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				     regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 20e5f7b..9c28950 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -14,6 +14,7 @@
 #include <asm/segment.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
@@ -146,8 +147,10 @@
 	SAVE_ARGS 0,1,0
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
+	ASM_STAC
 1:	movl	(%rbp),%ebp
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -301,8 +304,10 @@
 	/* no need to do an access_ok check here because r8 has been
 	   32bit zero extended */ 
 	/* hardware stack frame is complete now */	
+	ASM_STAC
 1:	movl	(%r8),%r9d
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -365,6 +370,7 @@
 END(ia32_cstar_target)
 				
 ia32_badarg:
+	ASM_CLAC
 	movq $-EFAULT,%rax
 	jmp ia32_sysret
 	CFI_ENDPROC
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index 4540bec..c5b938d 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -287,7 +287,7 @@
 	return ret;
 }
 
-asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
+asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
 			      int options)
 {
 	return compat_sys_wait4(pid, stat_addr, options, NULL);
diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h
index 952bd01..372231c 100644
--- a/arch/x86/include/asm/alternative-asm.h
+++ b/arch/x86/include/asm/alternative-asm.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_ALTERNATIVE_ASM_H
+#define _ASM_X86_ALTERNATIVE_ASM_H
+
 #ifdef __ASSEMBLY__
 
 #include <asm/asm.h>
@@ -5,10 +8,10 @@
 #ifdef CONFIG_SMP
 	.macro LOCK_PREFIX
 672:	lock
-	.section .smp_locks,"a"
+	.pushsection .smp_locks,"a"
 	.balign 4
 	.long 672b - .
-	.previous
+	.popsection
 	.endm
 #else
 	.macro LOCK_PREFIX
@@ -24,3 +27,5 @@
 .endm
 
 #endif  /*  __ASSEMBLY__  */
+
+#endif /* _ASM_X86_ALTERNATIVE_ASM_H */
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 7078068..58ed6d9 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -29,10 +29,10 @@
 
 #ifdef CONFIG_SMP
 #define LOCK_PREFIX_HERE \
-		".section .smp_locks,\"a\"\n"	\
-		".balign 4\n"			\
-		".long 671f - .\n" /* offset */	\
-		".previous\n"			\
+		".pushsection .smp_locks,\"a\"\n"	\
+		".balign 4\n"				\
+		".long 671f - .\n" /* offset */		\
+		".popsection\n"				\
 		"671:"
 
 #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
@@ -60,7 +60,7 @@
 					void *locks, void *locks_end,
 					void *text, void *text_end);
 extern void alternatives_smp_module_del(struct module *mod);
-extern void alternatives_smp_switch(int smp);
+extern void alternatives_enable_smp(void);
 extern int alternatives_text_reserved(void *start, void *end);
 extern bool skip_smp_alternatives;
 #else
@@ -68,7 +68,7 @@
 					       void *locks, void *locks_end,
 					       void *text, void *text_end) {}
 static inline void alternatives_smp_module_del(struct module *mod) {}
-static inline void alternatives_smp_switch(int smp) {}
+static inline void alternatives_enable_smp(void) {}
 static inline int alternatives_text_reserved(void *start, void *end)
 {
 	return 0;
@@ -99,30 +99,30 @@
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)			\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature, 1)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr, feature, 1)			\
-	".previous"
+	".popsection"
 
 #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature1, 1)					\
 	ALTINSTR_ENTRY(feature2, 2)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
 	DISCARD_ENTRY(2)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)			\
 	ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)			\
-	".previous"
+	".popsection"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index 72f5009..6dfd019 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -355,7 +355,7 @@
  */
 static inline unsigned long __ffs(unsigned long word)
 {
-	asm("bsf %1,%0"
+	asm("rep; bsf %1,%0"
 		: "=r" (word)
 		: "rm" (word));
 	return word;
@@ -369,7 +369,7 @@
  */
 static inline unsigned long ffz(unsigned long word)
 {
-	asm("bsf %1,%0"
+	asm("rep; bsf %1,%0"
 		: "=r" (word)
 		: "r" (~word));
 	return word;
@@ -417,10 +417,9 @@
 	 * We cannot do this on 32 bits because at the very least some
 	 * 486 CPUs did not behave this way.
 	 */
-	long tmp = -1;
 	asm("bsfl %1,%0"
 	    : "=r" (r)
-	    : "rm" (x), "0" (tmp));
+	    : "rm" (x), "0" (-1));
 #elif defined(CONFIG_X86_CMOV)
 	asm("bsfl %1,%0\n\t"
 	    "cmovzl %2,%0"
@@ -459,10 +458,9 @@
 	 * We cannot do this on 32 bits because at the very least some
 	 * 486 CPUs did not behave this way.
 	 */
-	long tmp = -1;
 	asm("bsrl %1,%0"
 	    : "=r" (r)
-	    : "rm" (x), "0" (tmp));
+	    : "rm" (x), "0" (-1));
 #elif defined(CONFIG_X86_CMOV)
 	asm("bsrl %1,%0\n\t"
 	    "cmovzl %2,%0"
@@ -490,13 +488,13 @@
 #ifdef CONFIG_X86_64
 static __always_inline int fls64(__u64 x)
 {
-	long bitpos = -1;
+	int bitpos = -1;
 	/*
 	 * AMD64 says BSRQ won't clobber the dest reg if x==0; Intel64 says the
 	 * dest reg is undefined if x==0, but their CPU architect says its
 	 * value is written to set it to the same as before.
 	 */
-	asm("bsrq %1,%0"
+	asm("bsrq %1,%q0"
 	    : "+r" (bitpos)
 	    : "rm" (x));
 	return bitpos + 1;
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h
index a9e3a74..7f8422a 100644
--- a/arch/x86/include/asm/calling.h
+++ b/arch/x86/include/asm/calling.h
@@ -49,38 +49,36 @@
 #include "dwarf2.h"
 
 /*
- * 64-bit system call stack frame layout defines and helpers, for
- * assembly code (note that the seemingly unnecessary parentheses
- * are to prevent cpp from inserting spaces in expressions that get
- * passed to macros):
+ * 64-bit system call stack frame layout defines and helpers,
+ * for assembly code:
  */
 
-#define R15		  (0)
-#define R14		  (8)
-#define R13		 (16)
-#define R12		 (24)
-#define RBP		 (32)
-#define RBX		 (40)
+#define R15		  0
+#define R14		  8
+#define R13		 16
+#define R12		 24
+#define RBP		 32
+#define RBX		 40
 
 /* arguments: interrupts/non tracing syscalls only save up to here: */
-#define R11		 (48)
-#define R10		 (56)
-#define R9		 (64)
-#define R8		 (72)
-#define RAX		 (80)
-#define RCX		 (88)
-#define RDX		 (96)
-#define RSI		(104)
-#define RDI		(112)
-#define ORIG_RAX	(120)       /* + error_code */
+#define R11		 48
+#define R10		 56
+#define R9		 64
+#define R8		 72
+#define RAX		 80
+#define RCX		 88
+#define RDX		 96
+#define RSI		104
+#define RDI		112
+#define ORIG_RAX	120       /* + error_code */
 /* end of arguments */
 
 /* cpu exception frame or undefined in case of fast syscall: */
-#define RIP		(128)
-#define CS		(136)
-#define EFLAGS		(144)
-#define RSP		(152)
-#define SS		(160)
+#define RIP		128
+#define CS		136
+#define EFLAGS		144
+#define RSP		152
+#define SS		160
 
 #define ARGOFFSET	R11
 #define SWFRAME		ORIG_RAX
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 6b7ee5f..16cae425 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -97,6 +97,7 @@
 #define X86_FEATURE_EXTD_APICID	(3*32+26) /* has extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM     (3*32+27) /* multi-node processor */
 #define X86_FEATURE_APERFMPERF	(3*32+28) /* APERFMPERF */
+#define X86_FEATURE_EAGER_FPU	(3*32+29) /* "eagerfpu" Non lazy FPU restore */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* "pni" SSE-3 */
@@ -209,6 +210,7 @@
 #define X86_FEATURE_RTM		(9*32+11) /* Restricted Transactional Memory */
 #define X86_FEATURE_RDSEED	(9*32+18) /* The RDSEED instruction */
 #define X86_FEATURE_ADX		(9*32+19) /* The ADCX and ADOX instructions */
+#define X86_FEATURE_SMAP	(9*32+20) /* Supervisor Mode Access Prevention */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
@@ -299,12 +301,14 @@
 #define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
 #define cpu_has_x2apic		boot_cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave		boot_cpu_has(X86_FEATURE_XSAVE)
+#define cpu_has_xsaveopt	boot_cpu_has(X86_FEATURE_XSAVEOPT)
 #define cpu_has_osxsave		boot_cpu_has(X86_FEATURE_OSXSAVE)
 #define cpu_has_hypervisor	boot_cpu_has(X86_FEATURE_HYPERVISOR)
 #define cpu_has_pclmulqdq	boot_cpu_has(X86_FEATURE_PCLMULQDQ)
 #define cpu_has_perfctr_core	boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
 #define cpu_has_cx8		boot_cpu_has(X86_FEATURE_CX8)
 #define cpu_has_cx16		boot_cpu_has(X86_FEATURE_CX16)
+#define cpu_has_eager_fpu	boot_cpu_has(X86_FEATURE_EAGER_FPU)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg		1
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 75f4c6d..831dbb9 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -12,6 +12,7 @@
 
 #include <linux/kernel_stat.h>
 #include <linux/regset.h>
+#include <linux/compat.h>
 #include <linux/slab.h>
 #include <asm/asm.h>
 #include <asm/cpufeature.h>
@@ -20,43 +21,76 @@
 #include <asm/user.h>
 #include <asm/uaccess.h>
 #include <asm/xsave.h>
+#include <asm/smap.h>
 
-extern unsigned int sig_xstate_size;
+#ifdef CONFIG_X86_64
+# include <asm/sigcontext32.h>
+# include <asm/user32.h>
+int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			compat_sigset_t *set, struct pt_regs *regs);
+int ia32_setup_frame(int sig, struct k_sigaction *ka,
+		     compat_sigset_t *set, struct pt_regs *regs);
+#else
+# define user_i387_ia32_struct	user_i387_struct
+# define user32_fxsr_struct	user_fxsr_struct
+# define ia32_setup_frame	__setup_frame
+# define ia32_setup_rt_frame	__setup_rt_frame
+#endif
+
+extern unsigned int mxcsr_feature_mask;
 extern void fpu_init(void);
+extern void eager_fpu_init(void);
 
 DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
 
+extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
+			      struct task_struct *tsk);
+extern void convert_to_fxsr(struct task_struct *tsk,
+			    const struct user_i387_ia32_struct *env);
+
 extern user_regset_active_fn fpregs_active, xfpregs_active;
 extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
 				xstateregs_get;
 extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
 				 xstateregs_set;
 
-
 /*
  * xstateregs_active == fpregs_active. Please refer to the comment
  * at the definition of fpregs_active.
  */
 #define xstateregs_active	fpregs_active
 
-extern struct _fpx_sw_bytes fx_sw_reserved;
-#ifdef CONFIG_IA32_EMULATION
-extern unsigned int sig_xstate_ia32_size;
-extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
-struct _fpstate_ia32;
-struct _xstate_ia32;
-extern int save_i387_xstate_ia32(void __user *buf);
-extern int restore_i387_xstate_ia32(void __user *buf);
-#endif
-
 #ifdef CONFIG_MATH_EMULATION
+# define HAVE_HWFP		(boot_cpu_data.hard_math)
 extern void finit_soft_fpu(struct i387_soft_struct *soft);
 #else
+# define HAVE_HWFP		1
 static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
 #endif
 
+static inline int is_ia32_compat_frame(void)
+{
+	return config_enabled(CONFIG_IA32_EMULATION) &&
+	       test_thread_flag(TIF_IA32);
+}
+
+static inline int is_ia32_frame(void)
+{
+	return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
+}
+
+static inline int is_x32_frame(void)
+{
+	return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
+}
+
 #define X87_FSW_ES (1 << 7)	/* Exception Summary */
 
+static __always_inline __pure bool use_eager_fpu(void)
+{
+	return static_cpu_has(X86_FEATURE_EAGER_FPU);
+}
+
 static __always_inline __pure bool use_xsaveopt(void)
 {
 	return static_cpu_has(X86_FEATURE_XSAVEOPT);
@@ -72,6 +106,13 @@
         return static_cpu_has(X86_FEATURE_FXSR);
 }
 
+static inline void fx_finit(struct i387_fxsave_struct *fx)
+{
+	memset(fx, 0, xstate_size);
+	fx->cwd = 0x37f;
+	fx->mxcsr = MXCSR_DEFAULT;
+}
+
 extern void __sanitize_i387_state(struct task_struct *);
 
 static inline void sanitize_i387_state(struct task_struct *tsk)
@@ -81,131 +122,121 @@
 	__sanitize_i387_state(tsk);
 }
 
-#ifdef CONFIG_X86_64
-static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
-{
-	int err;
+#define user_insn(insn, output, input...)				\
+({									\
+	int err;							\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:" #insn "\n\t"					\
+		     "2: " ASM_CLAC "\n"				\
+		     ".section .fixup,\"ax\"\n"				\
+		     "3:  movl $-1,%[err]\n"				\
+		     "    jmp  2b\n"					\
+		     ".previous\n"					\
+		     _ASM_EXTABLE(1b, 3b)				\
+		     : [err] "=r" (err), output				\
+		     : "0"(0), input);					\
+	err;								\
+})
 
-	/* See comment in fxsave() below. */
-#ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxrstorq %[fx]\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err)
-		     : [fx] "m" (*fx), "0" (0));
-#else
-	asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err)
-		     : [fx] "R" (fx), "m" (*fx), "0" (0));
-#endif
-	return err;
+#define check_insn(insn, output, input...)				\
+({									\
+	int err;							\
+	asm volatile("1:" #insn "\n\t"					\
+		     "2:\n"						\
+		     ".section .fixup,\"ax\"\n"				\
+		     "3:  movl $-1,%[err]\n"				\
+		     "    jmp  2b\n"					\
+		     ".previous\n"					\
+		     _ASM_EXTABLE(1b, 3b)				\
+		     : [err] "=r" (err), output				\
+		     : "0"(0), input);					\
+	err;								\
+})
+
+static inline int fsave_user(struct i387_fsave_struct __user *fx)
+{
+	return user_insn(fnsave %[fx]; fwait,  [fx] "=m" (*fx), "m" (*fx));
 }
 
 static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
-	int err;
+	if (config_enabled(CONFIG_X86_32))
+		return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
+	else if (config_enabled(CONFIG_AS_FXSAVEQ))
+		return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
 
-	/*
-	 * Clear the bytes not touched by the fxsave and reserved
-	 * for the SW usage.
-	 */
-	err = __clear_user(&fx->sw_reserved,
-			   sizeof(struct _fpx_sw_bytes));
-	if (unlikely(err))
-		return -EFAULT;
-
-	/* See comment in fxsave() below. */
-#ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxsaveq %[fx]\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err), [fx] "=m" (*fx)
-		     : "0" (0));
-#else
-	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err), "=m" (*fx)
-		     : [fx] "R" (fx), "0" (0));
-#endif
-	if (unlikely(err) &&
-	    __clear_user(fx, sizeof(struct i387_fxsave_struct)))
-		err = -EFAULT;
-	/* No need to clear here because the caller clears USED_MATH */
-	return err;
+	/* See comment in fpu_fxsave() below. */
+	return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
 }
 
-static inline void fpu_fxsave(struct fpu *fpu)
-{
-	/* Using "rex64; fxsave %0" is broken because, if the memory operand
-	   uses any extended registers for addressing, a second REX prefix
-	   will be generated (to the assembler, rex64 followed by semicolon
-	   is a separate instruction), and hence the 64-bitness is lost. */
-
-#ifdef CONFIG_AS_FXSAVEQ
-	/* Using "fxsaveq %0" would be the ideal choice, but is only supported
-	   starting with gas 2.16. */
-	__asm__ __volatile__("fxsaveq %0"
-			     : "=m" (fpu->state->fxsave));
-#else
-	/* Using, as a workaround, the properly prefixed form below isn't
-	   accepted by any binutils version so far released, complaining that
-	   the same type of prefix is used twice if an extended register is
-	   needed for addressing (fix submitted to mainline 2005-11-21).
-	asm volatile("rex64/fxsave %0"
-		     : "=m" (fpu->state->fxsave));
-	   This, however, we can work around by forcing the compiler to select
-	   an addressing mode that doesn't require extended registers. */
-	asm volatile("rex64/fxsave (%[fx])"
-		     : "=m" (fpu->state->fxsave)
-		     : [fx] "R" (&fpu->state->fxsave));
-#endif
-}
-
-#else  /* CONFIG_X86_32 */
-
-/* perform fxrstor iff the processor has extended states, otherwise frstor */
 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
-	/*
-	 * The "nop" is needed to make the instructions the same
-	 * length.
-	 */
-	alternative_input(
-		"nop ; frstor %1",
-		"fxrstor %1",
-		X86_FEATURE_FXSR,
-		"m" (*fx));
+	if (config_enabled(CONFIG_X86_32))
+		return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+	else if (config_enabled(CONFIG_AS_FXSAVEQ))
+		return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
 
-	return 0;
+	/* See comment in fpu_fxsave() below. */
+	return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
+			  "m" (*fx));
+}
+
+static inline int fxrstor_user(struct i387_fxsave_struct __user *fx)
+{
+	if (config_enabled(CONFIG_X86_32))
+		return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+	else if (config_enabled(CONFIG_AS_FXSAVEQ))
+		return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
+
+	/* See comment in fpu_fxsave() below. */
+	return user_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
+			  "m" (*fx));
+}
+
+static inline int frstor_checking(struct i387_fsave_struct *fx)
+{
+	return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+}
+
+static inline int frstor_user(struct i387_fsave_struct __user *fx)
+{
+	return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
 }
 
 static inline void fpu_fxsave(struct fpu *fpu)
 {
-	asm volatile("fxsave %[fx]"
-		     : [fx] "=m" (fpu->state->fxsave));
+	if (config_enabled(CONFIG_X86_32))
+		asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
+	else if (config_enabled(CONFIG_AS_FXSAVEQ))
+		asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave));
+	else {
+		/* Using "rex64; fxsave %0" is broken because, if the memory
+		 * operand uses any extended registers for addressing, a second
+		 * REX prefix will be generated (to the assembler, rex64
+		 * followed by semicolon is a separate instruction), and hence
+		 * the 64-bitness is lost.
+		 *
+		 * Using "fxsaveq %0" would be the ideal choice, but is only
+		 * supported starting with gas 2.16.
+		 *
+		 * Using, as a workaround, the properly prefixed form below
+		 * isn't accepted by any binutils version so far released,
+		 * complaining that the same type of prefix is used twice if
+		 * an extended register is needed for addressing (fix submitted
+		 * to mainline 2005-11-21).
+		 *
+		 *  asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
+		 *
+		 * This, however, we can work around by forcing the compiler to
+		 * select an addressing mode that doesn't require extended
+		 * registers.
+		 */
+		asm volatile( "rex64/fxsave (%[fx])"
+			     : "=m" (fpu->state->fxsave)
+			     : [fx] "R" (&fpu->state->fxsave));
+	}
 }
 
-#endif	/* CONFIG_X86_64 */
-
 /*
  * These must be called with preempt disabled. Returns
  * 'true' if the FPU state is still intact.
@@ -248,17 +279,14 @@
 	return fpu_save_init(&tsk->thread.fpu);
 }
 
-static inline int fpu_fxrstor_checking(struct fpu *fpu)
-{
-	return fxrstor_checking(&fpu->state->fxsave);
-}
-
 static inline int fpu_restore_checking(struct fpu *fpu)
 {
 	if (use_xsave())
-		return fpu_xrstor_checking(fpu);
+		return fpu_xrstor_checking(&fpu->state->xsave);
+	else if (use_fxsr())
+		return fxrstor_checking(&fpu->state->fxsave);
 	else
-		return fpu_fxrstor_checking(fpu);
+		return frstor_checking(&fpu->state->fsave);
 }
 
 static inline int restore_fpu_checking(struct task_struct *tsk)
@@ -310,15 +338,52 @@
 static inline void __thread_fpu_end(struct task_struct *tsk)
 {
 	__thread_clear_has_fpu(tsk);
-	stts();
+	if (!use_eager_fpu())
+		stts();
 }
 
 static inline void __thread_fpu_begin(struct task_struct *tsk)
 {
-	clts();
+	if (!use_eager_fpu())
+		clts();
 	__thread_set_has_fpu(tsk);
 }
 
+static inline void __drop_fpu(struct task_struct *tsk)
+{
+	if (__thread_has_fpu(tsk)) {
+		/* Ignore delayed exceptions from user space */
+		asm volatile("1: fwait\n"
+			     "2:\n"
+			     _ASM_EXTABLE(1b, 2b));
+		__thread_fpu_end(tsk);
+	}
+}
+
+static inline void drop_fpu(struct task_struct *tsk)
+{
+	/*
+	 * Forget coprocessor state..
+	 */
+	preempt_disable();
+	tsk->fpu_counter = 0;
+	__drop_fpu(tsk);
+	clear_used_math();
+	preempt_enable();
+}
+
+static inline void drop_init_fpu(struct task_struct *tsk)
+{
+	if (!use_eager_fpu())
+		drop_fpu(tsk);
+	else {
+		if (use_xsave())
+			xrstor_state(init_xstate_buf, -1);
+		else
+			fxrstor_checking(&init_xstate_buf->i387);
+	}
+}
+
 /*
  * FPU state switching for scheduling.
  *
@@ -352,7 +417,12 @@
 {
 	fpu_switch_t fpu;
 
-	fpu.preload = tsk_used_math(new) && new->fpu_counter > 5;
+	/*
+	 * If the task has used the math, pre-load the FPU on xsave processors
+	 * or if the past 5 consecutive context-switches used math.
+	 */
+	fpu.preload = tsk_used_math(new) && (use_eager_fpu() ||
+					     new->fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
 			cpu = ~0;
@@ -364,14 +434,14 @@
 			new->fpu_counter++;
 			__thread_set_has_fpu(new);
 			prefetch(new->thread.fpu.state);
-		} else
+		} else if (!use_eager_fpu())
 			stts();
 	} else {
 		old->fpu_counter = 0;
 		old->thread.fpu.last_cpu = ~0;
 		if (fpu.preload) {
 			new->fpu_counter++;
-			if (fpu_lazy_restore(new, cpu))
+			if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
 				fpu.preload = 0;
 			else
 				prefetch(new->thread.fpu.state);
@@ -391,44 +461,40 @@
 {
 	if (fpu.preload) {
 		if (unlikely(restore_fpu_checking(new)))
-			__thread_fpu_end(new);
+			drop_init_fpu(new);
 	}
 }
 
 /*
  * Signal frame handlers...
  */
-extern int save_i387_xstate(void __user *buf);
-extern int restore_i387_xstate(void __user *buf);
+extern int save_xstate_sig(void __user *buf, void __user *fx, int size);
+extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size);
 
-static inline void __clear_fpu(struct task_struct *tsk)
+static inline int xstate_sigframe_size(void)
 {
-	if (__thread_has_fpu(tsk)) {
-		/* Ignore delayed exceptions from user space */
-		asm volatile("1: fwait\n"
-			     "2:\n"
-			     _ASM_EXTABLE(1b, 2b));
-		__thread_fpu_end(tsk);
+	return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
+}
+
+static inline int restore_xstate_sig(void __user *buf, int ia32_frame)
+{
+	void __user *buf_fx = buf;
+	int size = xstate_sigframe_size();
+
+	if (ia32_frame && use_fxsr()) {
+		buf_fx = buf + sizeof(struct i387_fsave_struct);
+		size += sizeof(struct i387_fsave_struct);
 	}
+
+	return __restore_xstate_sig(buf, buf_fx, size);
 }
 
 /*
- * The actual user_fpu_begin/end() functions
- * need to be preemption-safe.
+ * Need to be preemption-safe.
  *
- * NOTE! user_fpu_end() must be used only after you
- * have saved the FP state, and user_fpu_begin() must
- * be used only immediately before restoring it.
- * These functions do not do any save/restore on
- * their own.
+ * NOTE! user_fpu_begin() must be used only immediately before restoring
+ * it. This function does not do any save/restore on their own.
  */
-static inline void user_fpu_end(void)
-{
-	preempt_disable();
-	__thread_fpu_end(current);
-	preempt_enable();
-}
-
 static inline void user_fpu_begin(void)
 {
 	preempt_disable();
@@ -437,25 +503,32 @@
 	preempt_enable();
 }
 
+static inline void __save_fpu(struct task_struct *tsk)
+{
+	if (use_xsave())
+		xsave_state(&tsk->thread.fpu.state->xsave, -1);
+	else
+		fpu_fxsave(&tsk->thread.fpu);
+}
+
 /*
  * These disable preemption on their own and are safe
  */
 static inline void save_init_fpu(struct task_struct *tsk)
 {
 	WARN_ON_ONCE(!__thread_has_fpu(tsk));
+
+	if (use_eager_fpu()) {
+		__save_fpu(tsk);
+		return;
+	}
+
 	preempt_disable();
 	__save_init_fpu(tsk);
 	__thread_fpu_end(tsk);
 	preempt_enable();
 }
 
-static inline void clear_fpu(struct task_struct *tsk)
-{
-	preempt_disable();
-	__clear_fpu(tsk);
-	preempt_enable();
-}
-
 /*
  * i387 state interaction
  */
@@ -510,11 +583,34 @@
 	}
 }
 
-static inline void fpu_copy(struct fpu *dst, struct fpu *src)
+static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
 {
-	memcpy(dst->state, src->state, xstate_size);
+	if (use_eager_fpu()) {
+		memset(&dst->thread.fpu.state->xsave, 0, xstate_size);
+		__save_fpu(dst);
+	} else {
+		struct fpu *dfpu = &dst->thread.fpu;
+		struct fpu *sfpu = &src->thread.fpu;
+
+		unlazy_fpu(src);
+		memcpy(dfpu->state, sfpu->state, xstate_size);
+	}
 }
 
-extern void fpu_finit(struct fpu *fpu);
+static inline unsigned long
+alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx,
+		unsigned long *size)
+{
+	unsigned long frame_size = xstate_sigframe_size();
+
+	*buf_fx = sp = round_down(sp - frame_size, 64);
+	if (ia32_frame && use_fxsr()) {
+		frame_size += sizeof(struct i387_fsave_struct);
+		sp -= sizeof(struct i387_fsave_struct);
+	}
+
+	*size = frame_size;
+	return sp;
+}
 
 #endif
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index b0767bc..9a25b52 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -3,38 +3,54 @@
 
 #ifdef __ASSEMBLY__
 
-	.macro MCOUNT_SAVE_FRAME
-	/* taken from glibc */
-	subq $0x38, %rsp
-	movq %rax, (%rsp)
-	movq %rcx, 8(%rsp)
-	movq %rdx, 16(%rsp)
-	movq %rsi, 24(%rsp)
-	movq %rdi, 32(%rsp)
-	movq %r8, 40(%rsp)
-	movq %r9, 48(%rsp)
+	/* skip is set if the stack was already partially adjusted */
+	.macro MCOUNT_SAVE_FRAME skip=0
+	 /*
+	  * We add enough stack to save all regs.
+	  */
+	subq $(SS+8-\skip), %rsp
+	movq %rax, RAX(%rsp)
+	movq %rcx, RCX(%rsp)
+	movq %rdx, RDX(%rsp)
+	movq %rsi, RSI(%rsp)
+	movq %rdi, RDI(%rsp)
+	movq %r8, R8(%rsp)
+	movq %r9, R9(%rsp)
+	 /* Move RIP to its proper location */
+	movq SS+8(%rsp), %rdx
+	movq %rdx, RIP(%rsp)
 	.endm
 
-	.macro MCOUNT_RESTORE_FRAME
-	movq 48(%rsp), %r9
-	movq 40(%rsp), %r8
-	movq 32(%rsp), %rdi
-	movq 24(%rsp), %rsi
-	movq 16(%rsp), %rdx
-	movq 8(%rsp), %rcx
-	movq (%rsp), %rax
-	addq $0x38, %rsp
+	.macro MCOUNT_RESTORE_FRAME skip=0
+	movq R9(%rsp), %r9
+	movq R8(%rsp), %r8
+	movq RDI(%rsp), %rdi
+	movq RSI(%rsp), %rsi
+	movq RDX(%rsp), %rdx
+	movq RCX(%rsp), %rcx
+	movq RAX(%rsp), %rax
+	addq $(SS+8-\skip), %rsp
 	.endm
 
 #endif
 
 #ifdef CONFIG_FUNCTION_TRACER
-#define MCOUNT_ADDR		((long)(mcount))
+#ifdef CC_USING_FENTRY
+# define MCOUNT_ADDR		((long)(__fentry__))
+#else
+# define MCOUNT_ADDR		((long)(mcount))
+#endif
 #define MCOUNT_INSN_SIZE	5 /* sizeof mcount call */
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+#define ARCH_SUPPORTS_FTRACE_SAVE_REGS
+#endif
+
 #ifndef __ASSEMBLY__
 extern void mcount(void);
 extern atomic_t modifying_ftrace_code;
+extern void __fentry__(void);
 
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 71ecbcb..f373046 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -9,10 +9,13 @@
 #include <asm/asm.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
+#include <asm/smap.h>
 
 #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\t" insn "\n"				\
-		     "2:\t.section .fixup,\"ax\"\n"		\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\t" insn "\n"				\
+		     "2:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "3:\tmov\t%3, %1\n"			\
 		     "\tjmp\t2b\n"				\
 		     "\t.previous\n"				\
@@ -21,12 +24,14 @@
 		     : "i" (-EFAULT), "0" (oparg), "1" (0))
 
 #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\tmovl	%2, %0\n"			\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\tmovl	%2, %0\n"			\
 		     "\tmovl\t%0, %3\n"				\
 		     "\t" insn "\n"				\
 		     "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"	\
 		     "\tjnz\t1b\n"				\
-		     "3:\t.section .fixup,\"ax\"\n"		\
+		     "3:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "4:\tmov\t%5, %1\n"			\
 		     "\tjmp\t3b\n"				\
 		     "\t.previous\n"				\
@@ -122,8 +127,10 @@
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
-	asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
-		     "2:\t.section .fixup, \"ax\"\n"
+	asm volatile("\t" ASM_STAC "\n"
+		     "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
+		     "2:\t" ASM_CLAC "\n"
+		     "\t.section .fixup, \"ax\"\n"
 		     "3:\tmov     %3, %0\n"
 		     "\tjmp     2b\n"
 		     "\t.previous\n"
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index d3895db..81f04ce 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -18,6 +18,10 @@
 #ifdef CONFIG_SMP
 	unsigned int irq_resched_count;
 	unsigned int irq_call_count;
+	/*
+	 * irq_tlb_count is double-counted in irq_call_count, so it must be
+	 * subtracted from irq_call_count when displaying irq_call_count
+	 */
 	unsigned int irq_tlb_count;
 #endif
 #ifdef CONFIG_X86_THERMAL_VECTOR
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 2c392d6..434e210 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -35,8 +35,6 @@
 #define	HPET_ID_NUMBER_SHIFT	8
 #define HPET_ID_VENDOR_SHIFT	16
 
-#define HPET_ID_VENDOR_8086	0x8086
-
 #define HPET_CFG_ENABLE		0x001
 #define HPET_CFG_LEGACY		0x002
 #define	HPET_LEGACY_8254	2
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index 257d9cc..ed8089d6 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -19,12 +19,37 @@
 struct user_i387_struct;
 
 extern int init_fpu(struct task_struct *child);
+extern void fpu_finit(struct fpu *fpu);
 extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
 extern void math_state_restore(void);
 
 extern bool irq_fpu_usable(void);
-extern void kernel_fpu_begin(void);
-extern void kernel_fpu_end(void);
+
+/*
+ * Careful: __kernel_fpu_begin/end() must be called with preempt disabled
+ * and they don't touch the preempt state on their own.
+ * If you enable preemption after __kernel_fpu_begin(), preempt notifier
+ * should call the __kernel_fpu_end() to prevent the kernel/user FPU
+ * state from getting corrupted. KVM for example uses this model.
+ *
+ * All other cases use kernel_fpu_begin/end() which disable preemption
+ * during kernel FPU usage.
+ */
+extern void __kernel_fpu_begin(void);
+extern void __kernel_fpu_end(void);
+
+static inline void kernel_fpu_begin(void)
+{
+	WARN_ON_ONCE(!irq_fpu_usable());
+	preempt_disable();
+	__kernel_fpu_begin();
+}
+
+static inline void kernel_fpu_end(void)
+{
+	__kernel_fpu_end();
+	preempt_enable();
+}
 
 /*
  * Some instructions like VIA's padlock instructions generate a spurious
diff --git a/arch/x86/include/asm/iommu_table.h b/arch/x86/include/asm/iommu_table.h
index f229b13..f42a047 100644
--- a/arch/x86/include/asm/iommu_table.h
+++ b/arch/x86/include/asm/iommu_table.h
@@ -48,7 +48,7 @@
 
 
 #define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
-	static const struct iommu_table_entry const			\
+	static const struct iommu_table_entry				\
 		__iommu_entry_##_detect __used				\
 	__attribute__ ((unused, __section__(".iommu_table"),		\
 			aligned((sizeof(void *)))))	\
@@ -63,10 +63,10 @@
  * to stop detecting the other IOMMUs after yours has been detected.
  */
 #define IOMMU_INIT_POST(_detect)					\
-	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 0)
+	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  NULL, NULL, 0)
 
 #define IOMMU_INIT_POST_FINISH(detect)					\
-	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 1)
+	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  NULL, NULL, 1)
 
 /*
  * A more sophisticated version of IOMMU_INIT. This variant requires:
diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h
index 5478825..d3ddd17 100644
--- a/arch/x86/include/asm/kprobes.h
+++ b/arch/x86/include/asm/kprobes.h
@@ -27,6 +27,7 @@
 #include <asm/insn.h>
 
 #define  __ARCH_WANT_KPROBES_INSN_SLOT
+#define  ARCH_SUPPORTS_KPROBES_ON_FTRACE
 
 struct pt_regs;
 struct kprobe;
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 246617e..41e08cb 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -9,6 +9,22 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
+#define DE_VECTOR 0
+#define DB_VECTOR 1
+#define BP_VECTOR 3
+#define OF_VECTOR 4
+#define BR_VECTOR 5
+#define UD_VECTOR 6
+#define NM_VECTOR 7
+#define DF_VECTOR 8
+#define TS_VECTOR 10
+#define NP_VECTOR 11
+#define SS_VECTOR 12
+#define GP_VECTOR 13
+#define PF_VECTOR 14
+#define MF_VECTOR 16
+#define MC_VECTOR 18
+
 /* Select x86 specific features in <linux/kvm.h> */
 #define __KVM_HAVE_PIT
 #define __KVM_HAVE_IOAPIC
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 09155d6..1eaa6b0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -75,22 +75,6 @@
 #define KVM_HPAGE_MASK(x)	(~(KVM_HPAGE_SIZE(x) - 1))
 #define KVM_PAGES_PER_HPAGE(x)	(KVM_HPAGE_SIZE(x) / PAGE_SIZE)
 
-#define DE_VECTOR 0
-#define DB_VECTOR 1
-#define BP_VECTOR 3
-#define OF_VECTOR 4
-#define BR_VECTOR 5
-#define UD_VECTOR 6
-#define NM_VECTOR 7
-#define DF_VECTOR 8
-#define TS_VECTOR 10
-#define NP_VECTOR 11
-#define SS_VECTOR 12
-#define GP_VECTOR 13
-#define PF_VECTOR 14
-#define MF_VECTOR 16
-#define MC_VECTOR 18
-
 #define SELECTOR_TI_MASK (1 << 2)
 #define SELECTOR_RPL_MASK 0x03
 
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index a3ac52b..54d73b1 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -116,19 +116,9 @@
 /* Software defined banks */
 #define MCE_EXTENDED_BANK	128
 #define MCE_THERMAL_BANK	MCE_EXTENDED_BANK + 0
-
-#define K8_MCE_THRESHOLD_BASE      (MCE_EXTENDED_BANK + 1)      /* MCE_AMD */
-#define K8_MCE_THRESHOLD_BANK_0    (MCE_THRESHOLD_BASE + 0 * 9)
-#define K8_MCE_THRESHOLD_BANK_1    (MCE_THRESHOLD_BASE + 1 * 9)
-#define K8_MCE_THRESHOLD_BANK_2    (MCE_THRESHOLD_BASE + 2 * 9)
-#define K8_MCE_THRESHOLD_BANK_3    (MCE_THRESHOLD_BASE + 3 * 9)
-#define K8_MCE_THRESHOLD_BANK_4    (MCE_THRESHOLD_BASE + 4 * 9)
-#define K8_MCE_THRESHOLD_BANK_5    (MCE_THRESHOLD_BASE + 5 * 9)
-#define K8_MCE_THRESHOLD_DRAM_ECC  (MCE_THRESHOLD_BANK_4 + 0)
-
+#define K8_MCE_THRESHOLD_BASE      (MCE_EXTENDED_BANK + 1)
 
 #ifdef __KERNEL__
-
 extern void mce_register_decode_chain(struct notifier_block *nb);
 extern void mce_unregister_decode_chain(struct notifier_block *nb);
 
@@ -171,6 +161,7 @@
 #ifdef CONFIG_X86_MCE_INTEL
 extern int mce_cmci_disabled;
 extern int mce_ignore_ce;
+extern int mce_bios_cmci_threshold;
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
 void cmci_clear(void);
 void cmci_reenable(void);
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 4ebe157..43d921b 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -15,8 +15,8 @@
 	enum ucode_state (*request_microcode_user) (int cpu,
 				const void __user *buf, size_t size);
 
-	enum ucode_state (*request_microcode_fw) (int cpu,
-				struct device *device);
+	enum ucode_state (*request_microcode_fw) (int cpu, struct device *,
+						  bool refresh_fw);
 
 	void (*microcode_fini_cpu) (int cpu);
 
@@ -49,12 +49,6 @@
 #ifdef CONFIG_MICROCODE_AMD
 extern struct microcode_ops * __init init_amd_microcode(void);
 extern void __exit exit_amd_microcode(void);
-
-static inline void get_ucode_data(void *to, const u8 *from, size_t n)
-{
-	memcpy(to, from, n);
-}
-
 #else
 static inline struct microcode_ops * __init init_amd_microcode(void)
 {
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index cb4e43b..4fabcdf 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -262,4 +262,6 @@
  static inline void amd_pmu_disable_virt(void) { }
 #endif
 
+#define arch_perf_out_copy_user copy_from_user_nmi
+
 #endif /* _ASM_X86_PERF_EVENT_H */
diff --git a/arch/x86/include/asm/perf_regs.h b/arch/x86/include/asm/perf_regs.h
new file mode 100644
index 0000000..3f2207b
--- /dev/null
+++ b/arch/x86/include/asm/perf_regs.h
@@ -0,0 +1,33 @@
+#ifndef _ASM_X86_PERF_REGS_H
+#define _ASM_X86_PERF_REGS_H
+
+enum perf_event_x86_regs {
+	PERF_REG_X86_AX,
+	PERF_REG_X86_BX,
+	PERF_REG_X86_CX,
+	PERF_REG_X86_DX,
+	PERF_REG_X86_SI,
+	PERF_REG_X86_DI,
+	PERF_REG_X86_BP,
+	PERF_REG_X86_SP,
+	PERF_REG_X86_IP,
+	PERF_REG_X86_FLAGS,
+	PERF_REG_X86_CS,
+	PERF_REG_X86_SS,
+	PERF_REG_X86_DS,
+	PERF_REG_X86_ES,
+	PERF_REG_X86_FS,
+	PERF_REG_X86_GS,
+	PERF_REG_X86_R8,
+	PERF_REG_X86_R9,
+	PERF_REG_X86_R10,
+	PERF_REG_X86_R11,
+	PERF_REG_X86_R12,
+	PERF_REG_X86_R13,
+	PERF_REG_X86_R14,
+	PERF_REG_X86_R15,
+
+	PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1,
+	PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1,
+};
+#endif /* _ASM_X86_PERF_REGS_H */
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 013286a1..db8fec6d 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -303,11 +303,9 @@
 
 extern void native_pagetable_reserve(u64 start, u64 end);
 #ifdef CONFIG_X86_32
-extern void native_pagetable_setup_start(pgd_t *base);
-extern void native_pagetable_setup_done(pgd_t *base);
+extern void native_pagetable_init(void);
 #else
-#define native_pagetable_setup_start x86_init_pgd_noop
-#define native_pagetable_setup_done  x86_init_pgd_noop
+#define native_pagetable_init        paging_init
 #endif
 
 struct seq_file;
diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h
index aea1d1d..680cf09 100644
--- a/arch/x86/include/asm/processor-flags.h
+++ b/arch/x86/include/asm/processor-flags.h
@@ -65,6 +65,7 @@
 #define X86_CR4_PCIDE	0x00020000 /* enable PCID support */
 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 #define X86_CR4_SMEP	0x00100000 /* enable SMEP support */
+#define X86_CR4_SMAP	0x00200000 /* enable SMAP support */
 
 /*
  * x86-64 Task Priority Register, CR8
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index d048cad..b98c0d9 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -423,7 +423,6 @@
 
 DECLARE_PER_CPU(char *, irq_stack_ptr);
 DECLARE_PER_CPU(unsigned int, irq_count);
-extern unsigned long kernel_eflags;
 extern asmlinkage void ignore_sysret(void);
 #else	/* X86_64 */
 #ifdef CONFIG_CC_STACKPROTECTOR
@@ -759,6 +758,8 @@
 	wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
 }
 
+extern void set_task_blockstep(struct task_struct *task, bool on);
+
 /*
  * from system description table in BIOS. Mostly for MCA use, but
  * others may find it useful:
diff --git a/arch/x86/include/asm/rcu.h b/arch/x86/include/asm/rcu.h
new file mode 100644
index 0000000..d1ac07a
--- /dev/null
+++ b/arch/x86/include/asm/rcu.h
@@ -0,0 +1,32 @@
+#ifndef _ASM_X86_RCU_H
+#define _ASM_X86_RCU_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/rcupdate.h>
+#include <asm/ptrace.h>
+
+static inline void exception_enter(struct pt_regs *regs)
+{
+	rcu_user_exit();
+}
+
+static inline void exception_exit(struct pt_regs *regs)
+{
+#ifdef CONFIG_RCU_USER_QS
+	if (user_mode(regs))
+		rcu_user_enter();
+#endif
+}
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_RCU_USER_QS
+# define SCHEDULE_USER call schedule_user
+#else
+# define SCHEDULE_USER call schedule
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 598457c..323973f 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -31,6 +31,10 @@
 	unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
+#ifndef CONFIG_COMPAT
+typedef sigset_t compat_sigset_t;
+#endif
+
 #else
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h
new file mode 100644
index 0000000..8d3120f
--- /dev/null
+++ b/arch/x86/include/asm/smap.h
@@ -0,0 +1,91 @@
+/*
+ * Supervisor Mode Access Prevention support
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Author: H. Peter Anvin <hpa@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef _ASM_X86_SMAP_H
+#define _ASM_X86_SMAP_H
+
+#include <linux/stringify.h>
+#include <asm/nops.h>
+#include <asm/cpufeature.h>
+
+/* "Raw" instruction opcodes */
+#define __ASM_CLAC	.byte 0x0f,0x01,0xca
+#define __ASM_STAC	.byte 0x0f,0x01,0xcb
+
+#ifdef __ASSEMBLY__
+
+#include <asm/alternative-asm.h>
+
+#ifdef CONFIG_X86_SMAP
+
+#define ASM_CLAC							\
+	661: ASM_NOP3 ;							\
+	.pushsection .altinstr_replacement, "ax" ;			\
+	662: __ASM_CLAC ;						\
+	.popsection ;							\
+	.pushsection .altinstructions, "a" ;				\
+	altinstruction_entry 661b, 662b, X86_FEATURE_SMAP, 3, 3 ;	\
+	.popsection
+
+#define ASM_STAC							\
+	661: ASM_NOP3 ;							\
+	.pushsection .altinstr_replacement, "ax" ;			\
+	662: __ASM_STAC ;						\
+	.popsection ;							\
+	.pushsection .altinstructions, "a" ;				\
+	altinstruction_entry 661b, 662b, X86_FEATURE_SMAP, 3, 3 ;	\
+	.popsection
+
+#else /* CONFIG_X86_SMAP */
+
+#define ASM_CLAC
+#define ASM_STAC
+
+#endif /* CONFIG_X86_SMAP */
+
+#else /* __ASSEMBLY__ */
+
+#include <asm/alternative.h>
+
+#ifdef CONFIG_X86_SMAP
+
+static __always_inline void clac(void)
+{
+	/* Note: a barrier is implicit in alternative() */
+	alternative(ASM_NOP3, __stringify(__ASM_CLAC), X86_FEATURE_SMAP);
+}
+
+static __always_inline void stac(void)
+{
+	/* Note: a barrier is implicit in alternative() */
+	alternative(ASM_NOP3, __stringify(__ASM_STAC), X86_FEATURE_SMAP);
+}
+
+/* These macros can be used in asm() statements */
+#define ASM_CLAC \
+	ALTERNATIVE(ASM_NOP3, __stringify(__ASM_CLAC), X86_FEATURE_SMAP)
+#define ASM_STAC \
+	ALTERNATIVE(ASM_NOP3, __stringify(__ASM_STAC), X86_FEATURE_SMAP)
+
+#else /* CONFIG_X86_SMAP */
+
+static inline void clac(void) { }
+static inline void stac(void) { }
+
+#define ASM_CLAC
+#define ASM_STAC
+
+#endif /* CONFIG_X86_SMAP */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_SMAP_H */
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index f2b83bc..cdf5674 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -1,6 +1,135 @@
 #ifndef __SVM_H
 #define __SVM_H
 
+#define SVM_EXIT_READ_CR0      0x000
+#define SVM_EXIT_READ_CR3      0x003
+#define SVM_EXIT_READ_CR4      0x004
+#define SVM_EXIT_READ_CR8      0x008
+#define SVM_EXIT_WRITE_CR0     0x010
+#define SVM_EXIT_WRITE_CR3     0x013
+#define SVM_EXIT_WRITE_CR4     0x014
+#define SVM_EXIT_WRITE_CR8     0x018
+#define SVM_EXIT_READ_DR0      0x020
+#define SVM_EXIT_READ_DR1      0x021
+#define SVM_EXIT_READ_DR2      0x022
+#define SVM_EXIT_READ_DR3      0x023
+#define SVM_EXIT_READ_DR4      0x024
+#define SVM_EXIT_READ_DR5      0x025
+#define SVM_EXIT_READ_DR6      0x026
+#define SVM_EXIT_READ_DR7      0x027
+#define SVM_EXIT_WRITE_DR0     0x030
+#define SVM_EXIT_WRITE_DR1     0x031
+#define SVM_EXIT_WRITE_DR2     0x032
+#define SVM_EXIT_WRITE_DR3     0x033
+#define SVM_EXIT_WRITE_DR4     0x034
+#define SVM_EXIT_WRITE_DR5     0x035
+#define SVM_EXIT_WRITE_DR6     0x036
+#define SVM_EXIT_WRITE_DR7     0x037
+#define SVM_EXIT_EXCP_BASE     0x040
+#define SVM_EXIT_INTR          0x060
+#define SVM_EXIT_NMI           0x061
+#define SVM_EXIT_SMI           0x062
+#define SVM_EXIT_INIT          0x063
+#define SVM_EXIT_VINTR         0x064
+#define SVM_EXIT_CR0_SEL_WRITE 0x065
+#define SVM_EXIT_IDTR_READ     0x066
+#define SVM_EXIT_GDTR_READ     0x067
+#define SVM_EXIT_LDTR_READ     0x068
+#define SVM_EXIT_TR_READ       0x069
+#define SVM_EXIT_IDTR_WRITE    0x06a
+#define SVM_EXIT_GDTR_WRITE    0x06b
+#define SVM_EXIT_LDTR_WRITE    0x06c
+#define SVM_EXIT_TR_WRITE      0x06d
+#define SVM_EXIT_RDTSC         0x06e
+#define SVM_EXIT_RDPMC         0x06f
+#define SVM_EXIT_PUSHF         0x070
+#define SVM_EXIT_POPF          0x071
+#define SVM_EXIT_CPUID         0x072
+#define SVM_EXIT_RSM           0x073
+#define SVM_EXIT_IRET          0x074
+#define SVM_EXIT_SWINT         0x075
+#define SVM_EXIT_INVD          0x076
+#define SVM_EXIT_PAUSE         0x077
+#define SVM_EXIT_HLT           0x078
+#define SVM_EXIT_INVLPG        0x079
+#define SVM_EXIT_INVLPGA       0x07a
+#define SVM_EXIT_IOIO          0x07b
+#define SVM_EXIT_MSR           0x07c
+#define SVM_EXIT_TASK_SWITCH   0x07d
+#define SVM_EXIT_FERR_FREEZE   0x07e
+#define SVM_EXIT_SHUTDOWN      0x07f
+#define SVM_EXIT_VMRUN         0x080
+#define SVM_EXIT_VMMCALL       0x081
+#define SVM_EXIT_VMLOAD        0x082
+#define SVM_EXIT_VMSAVE        0x083
+#define SVM_EXIT_STGI          0x084
+#define SVM_EXIT_CLGI          0x085
+#define SVM_EXIT_SKINIT        0x086
+#define SVM_EXIT_RDTSCP        0x087
+#define SVM_EXIT_ICEBP         0x088
+#define SVM_EXIT_WBINVD        0x089
+#define SVM_EXIT_MONITOR       0x08a
+#define SVM_EXIT_MWAIT         0x08b
+#define SVM_EXIT_MWAIT_COND    0x08c
+#define SVM_EXIT_XSETBV        0x08d
+#define SVM_EXIT_NPF           0x400
+
+#define SVM_EXIT_ERR           -1
+
+#define SVM_EXIT_REASONS \
+	{ SVM_EXIT_READ_CR0,    "read_cr0" }, \
+	{ SVM_EXIT_READ_CR3,    "read_cr3" }, \
+	{ SVM_EXIT_READ_CR4,    "read_cr4" }, \
+	{ SVM_EXIT_READ_CR8,    "read_cr8" }, \
+	{ SVM_EXIT_WRITE_CR0,   "write_cr0" }, \
+	{ SVM_EXIT_WRITE_CR3,   "write_cr3" }, \
+	{ SVM_EXIT_WRITE_CR4,   "write_cr4" }, \
+	{ SVM_EXIT_WRITE_CR8,   "write_cr8" }, \
+	{ SVM_EXIT_READ_DR0,    "read_dr0" }, \
+	{ SVM_EXIT_READ_DR1,    "read_dr1" }, \
+	{ SVM_EXIT_READ_DR2,    "read_dr2" }, \
+	{ SVM_EXIT_READ_DR3,    "read_dr3" }, \
+	{ SVM_EXIT_WRITE_DR0,   "write_dr0" }, \
+	{ SVM_EXIT_WRITE_DR1,   "write_dr1" }, \
+	{ SVM_EXIT_WRITE_DR2,   "write_dr2" }, \
+	{ SVM_EXIT_WRITE_DR3,   "write_dr3" }, \
+	{ SVM_EXIT_WRITE_DR5,   "write_dr5" }, \
+	{ SVM_EXIT_WRITE_DR7,   "write_dr7" }, \
+	{ SVM_EXIT_EXCP_BASE + DB_VECTOR,       "DB excp" }, \
+	{ SVM_EXIT_EXCP_BASE + BP_VECTOR,       "BP excp" }, \
+	{ SVM_EXIT_EXCP_BASE + UD_VECTOR,       "UD excp" }, \
+	{ SVM_EXIT_EXCP_BASE + PF_VECTOR,       "PF excp" }, \
+	{ SVM_EXIT_EXCP_BASE + NM_VECTOR,       "NM excp" }, \
+	{ SVM_EXIT_EXCP_BASE + MC_VECTOR,       "MC excp" }, \
+	{ SVM_EXIT_INTR,        "interrupt" }, \
+	{ SVM_EXIT_NMI,         "nmi" }, \
+	{ SVM_EXIT_SMI,         "smi" }, \
+	{ SVM_EXIT_INIT,        "init" }, \
+	{ SVM_EXIT_VINTR,       "vintr" }, \
+	{ SVM_EXIT_CPUID,       "cpuid" }, \
+	{ SVM_EXIT_INVD,        "invd" }, \
+	{ SVM_EXIT_HLT,         "hlt" }, \
+	{ SVM_EXIT_INVLPG,      "invlpg" }, \
+	{ SVM_EXIT_INVLPGA,     "invlpga" }, \
+	{ SVM_EXIT_IOIO,        "io" }, \
+	{ SVM_EXIT_MSR,         "msr" }, \
+	{ SVM_EXIT_TASK_SWITCH, "task_switch" }, \
+	{ SVM_EXIT_SHUTDOWN,    "shutdown" }, \
+	{ SVM_EXIT_VMRUN,       "vmrun" }, \
+	{ SVM_EXIT_VMMCALL,     "hypercall" }, \
+	{ SVM_EXIT_VMLOAD,      "vmload" }, \
+	{ SVM_EXIT_VMSAVE,      "vmsave" }, \
+	{ SVM_EXIT_STGI,        "stgi" }, \
+	{ SVM_EXIT_CLGI,        "clgi" }, \
+	{ SVM_EXIT_SKINIT,      "skinit" }, \
+	{ SVM_EXIT_WBINVD,      "wbinvd" }, \
+	{ SVM_EXIT_MONITOR,     "monitor" }, \
+	{ SVM_EXIT_MWAIT,       "mwait" }, \
+	{ SVM_EXIT_XSETBV,      "xsetbv" }, \
+	{ SVM_EXIT_NPF,         "npf" }
+
+#ifdef __KERNEL__
+
 enum {
 	INTERCEPT_INTR,
 	INTERCEPT_NMI,
@@ -264,81 +393,6 @@
 
 #define SVM_EXITINFO_REG_MASK 0x0F
 
-#define	SVM_EXIT_READ_CR0 	0x000
-#define	SVM_EXIT_READ_CR3 	0x003
-#define	SVM_EXIT_READ_CR4 	0x004
-#define	SVM_EXIT_READ_CR8 	0x008
-#define	SVM_EXIT_WRITE_CR0 	0x010
-#define	SVM_EXIT_WRITE_CR3 	0x013
-#define	SVM_EXIT_WRITE_CR4 	0x014
-#define	SVM_EXIT_WRITE_CR8 	0x018
-#define	SVM_EXIT_READ_DR0 	0x020
-#define	SVM_EXIT_READ_DR1 	0x021
-#define	SVM_EXIT_READ_DR2 	0x022
-#define	SVM_EXIT_READ_DR3 	0x023
-#define	SVM_EXIT_READ_DR4 	0x024
-#define	SVM_EXIT_READ_DR5 	0x025
-#define	SVM_EXIT_READ_DR6 	0x026
-#define	SVM_EXIT_READ_DR7 	0x027
-#define	SVM_EXIT_WRITE_DR0 	0x030
-#define	SVM_EXIT_WRITE_DR1 	0x031
-#define	SVM_EXIT_WRITE_DR2 	0x032
-#define	SVM_EXIT_WRITE_DR3 	0x033
-#define	SVM_EXIT_WRITE_DR4 	0x034
-#define	SVM_EXIT_WRITE_DR5 	0x035
-#define	SVM_EXIT_WRITE_DR6 	0x036
-#define	SVM_EXIT_WRITE_DR7 	0x037
-#define SVM_EXIT_EXCP_BASE      0x040
-#define SVM_EXIT_INTR		0x060
-#define SVM_EXIT_NMI		0x061
-#define SVM_EXIT_SMI		0x062
-#define SVM_EXIT_INIT		0x063
-#define SVM_EXIT_VINTR		0x064
-#define SVM_EXIT_CR0_SEL_WRITE	0x065
-#define SVM_EXIT_IDTR_READ	0x066
-#define SVM_EXIT_GDTR_READ	0x067
-#define SVM_EXIT_LDTR_READ	0x068
-#define SVM_EXIT_TR_READ	0x069
-#define SVM_EXIT_IDTR_WRITE	0x06a
-#define SVM_EXIT_GDTR_WRITE	0x06b
-#define SVM_EXIT_LDTR_WRITE	0x06c
-#define SVM_EXIT_TR_WRITE	0x06d
-#define SVM_EXIT_RDTSC		0x06e
-#define SVM_EXIT_RDPMC		0x06f
-#define SVM_EXIT_PUSHF		0x070
-#define SVM_EXIT_POPF		0x071
-#define SVM_EXIT_CPUID		0x072
-#define SVM_EXIT_RSM		0x073
-#define SVM_EXIT_IRET		0x074
-#define SVM_EXIT_SWINT		0x075
-#define SVM_EXIT_INVD		0x076
-#define SVM_EXIT_PAUSE		0x077
-#define SVM_EXIT_HLT		0x078
-#define SVM_EXIT_INVLPG		0x079
-#define SVM_EXIT_INVLPGA	0x07a
-#define SVM_EXIT_IOIO		0x07b
-#define SVM_EXIT_MSR		0x07c
-#define SVM_EXIT_TASK_SWITCH	0x07d
-#define SVM_EXIT_FERR_FREEZE	0x07e
-#define SVM_EXIT_SHUTDOWN	0x07f
-#define SVM_EXIT_VMRUN		0x080
-#define SVM_EXIT_VMMCALL	0x081
-#define SVM_EXIT_VMLOAD		0x082
-#define SVM_EXIT_VMSAVE		0x083
-#define SVM_EXIT_STGI		0x084
-#define SVM_EXIT_CLGI		0x085
-#define SVM_EXIT_SKINIT		0x086
-#define SVM_EXIT_RDTSCP		0x087
-#define SVM_EXIT_ICEBP		0x088
-#define SVM_EXIT_WBINVD		0x089
-#define SVM_EXIT_MONITOR	0x08a
-#define SVM_EXIT_MWAIT		0x08b
-#define SVM_EXIT_MWAIT_COND	0x08c
-#define SVM_EXIT_XSETBV		0x08d
-#define SVM_EXIT_NPF  		0x400
-
-#define SVM_EXIT_ERR		-1
-
 #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP)
 
 #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
@@ -350,3 +404,4 @@
 
 #endif
 
+#endif
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index 3fda9db4..4ca1c61 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -40,7 +40,7 @@
 				struct old_sigaction32 __user *);
 asmlinkage long sys32_alarm(unsigned int);
 
-asmlinkage long sys32_waitpid(compat_pid_t, unsigned int *, int);
+asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
 asmlinkage long sys32_sysfs(int, u32, u32);
 
 asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 89f794f..c535d847 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -89,6 +89,7 @@
 #define TIF_NOTSC		16	/* TSC is not accessible in userland */
 #define TIF_IA32		17	/* IA32 compatibility process */
 #define TIF_FORK		18	/* ret_from_fork */
+#define TIF_NOHZ		19	/* in adaptive nohz mode */
 #define TIF_MEMDIE		20	/* is terminating due to OOM killer */
 #define TIF_DEBUG		21	/* uses debug registers */
 #define TIF_IO_BITMAP		22	/* uses I/O bitmap */
@@ -114,6 +115,7 @@
 #define _TIF_NOTSC		(1 << TIF_NOTSC)
 #define _TIF_IA32		(1 << TIF_IA32)
 #define _TIF_FORK		(1 << TIF_FORK)
+#define _TIF_NOHZ		(1 << TIF_NOHZ)
 #define _TIF_DEBUG		(1 << TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1 << TIF_IO_BITMAP)
 #define _TIF_FORCED_TF		(1 << TIF_FORCED_TF)
@@ -126,12 +128,13 @@
 /* work to do in syscall_trace_enter() */
 #define _TIF_WORK_SYSCALL_ENTRY	\
 	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT |	\
-	 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
+	 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT |	\
+	 _TIF_NOHZ)
 
 /* work to do in syscall_trace_leave() */
 #define _TIF_WORK_SYSCALL_EXIT	\
 	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP |	\
-	 _TIF_SYSCALL_TRACEPOINT)
+	 _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK							\
@@ -141,7 +144,8 @@
 
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK						\
-	((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT)
+	((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT |	\
+	_TIF_NOHZ)
 
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK						\
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index e1f3a17..a91acfb 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <asm/asm.h>
 #include <asm/page.h>
+#include <asm/smap.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -192,9 +193,10 @@
 
 #ifdef CONFIG_X86_32
 #define __put_user_asm_u64(x, addr, err, errret)			\
-	asm volatile("1:	movl %%eax,0(%2)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%2)\n"			\
 		     "2:	movl %%edx,4(%2)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "4:	movl %3,%0\n"				\
 		     "	jmp 3b\n"					\
@@ -205,9 +207,10 @@
 		     : "A" (x), "r" (addr), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex_u64(x, addr)					\
-	asm volatile("1:	movl %%eax,0(%1)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%1)\n"			\
 		     "2:	movl %%edx,4(%1)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     _ASM_EXTABLE_EX(2b, 3b)				\
 		     : : "A" (x), "r" (addr))
@@ -379,8 +382,9 @@
 } while (0)
 
 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %2,%"rtype"1\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	xor"itype" %"rtype"1,%"rtype"1\n"		\
@@ -443,8 +447,9 @@
  * aliasing issues.
  */
 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %"rtype"1,%2\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %"rtype"1,%2\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	jmp 2b\n"					\
@@ -463,13 +468,13 @@
  * uaccess_try and catch
  */
 #define uaccess_try	do {						\
-	int prev_err = current_thread_info()->uaccess_err;		\
 	current_thread_info()->uaccess_err = 0;				\
+	stac();								\
 	barrier();
 
 #define uaccess_catch(err)						\
+	clac();								\
 	(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0);	\
-	current_thread_info()->uaccess_err = prev_err;			\
 } while (0)
 
 /**
@@ -569,6 +574,9 @@
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+unsigned long __must_check clear_user(void __user *mem, unsigned long len);
+unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
+
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 576e39b..7f760a9 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -213,7 +213,4 @@
 	return n;
 }
 
-unsigned long __must_check clear_user(void __user *mem, unsigned long len);
-unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
-
 #endif /* _ASM_X86_UACCESS_32_H */
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index d8def8b..142810c 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -217,9 +217,6 @@
 	}
 }
 
-__must_check unsigned long clear_user(void __user *mem, unsigned long len);
-__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
-
 static __must_check __always_inline int
 __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
 {
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index f3971bb..8ff8be7 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -42,10 +42,11 @@
 };
 
 struct arch_uprobe_task {
-	unsigned long			saved_trap_nr;
 #ifdef CONFIG_X86_64
 	unsigned long			saved_scratch_register;
 #endif
+	unsigned int			saved_trap_nr;
+	unsigned int			saved_tf;
 };
 
 extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index bb05228..fddb53d 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -11,7 +11,8 @@
 #define VDSO32_SYMBOL(base, name)					\
 ({									\
 	extern const char VDSO32_##name[];				\
-	(void *)(VDSO32_##name - VDSO32_PRELINK + (unsigned long)(base)); \
+	(void __user *)(VDSO32_##name - VDSO32_PRELINK +		\
+			(unsigned long)(base));				\
 })
 #endif
 
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 74fcb96..36ec21c 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -25,6 +25,88 @@
  *
  */
 
+#define VMX_EXIT_REASONS_FAILED_VMENTRY         0x80000000
+
+#define EXIT_REASON_EXCEPTION_NMI       0
+#define EXIT_REASON_EXTERNAL_INTERRUPT  1
+#define EXIT_REASON_TRIPLE_FAULT        2
+
+#define EXIT_REASON_PENDING_INTERRUPT   7
+#define EXIT_REASON_NMI_WINDOW          8
+#define EXIT_REASON_TASK_SWITCH         9
+#define EXIT_REASON_CPUID               10
+#define EXIT_REASON_HLT                 12
+#define EXIT_REASON_INVD                13
+#define EXIT_REASON_INVLPG              14
+#define EXIT_REASON_RDPMC               15
+#define EXIT_REASON_RDTSC               16
+#define EXIT_REASON_VMCALL              18
+#define EXIT_REASON_VMCLEAR             19
+#define EXIT_REASON_VMLAUNCH            20
+#define EXIT_REASON_VMPTRLD             21
+#define EXIT_REASON_VMPTRST             22
+#define EXIT_REASON_VMREAD              23
+#define EXIT_REASON_VMRESUME            24
+#define EXIT_REASON_VMWRITE             25
+#define EXIT_REASON_VMOFF               26
+#define EXIT_REASON_VMON                27
+#define EXIT_REASON_CR_ACCESS           28
+#define EXIT_REASON_DR_ACCESS           29
+#define EXIT_REASON_IO_INSTRUCTION      30
+#define EXIT_REASON_MSR_READ            31
+#define EXIT_REASON_MSR_WRITE           32
+#define EXIT_REASON_INVALID_STATE       33
+#define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_MONITOR_INSTRUCTION 39
+#define EXIT_REASON_PAUSE_INSTRUCTION   40
+#define EXIT_REASON_MCE_DURING_VMENTRY  41
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
+#define EXIT_REASON_APIC_ACCESS         44
+#define EXIT_REASON_EPT_VIOLATION       48
+#define EXIT_REASON_EPT_MISCONFIG       49
+#define EXIT_REASON_WBINVD              54
+#define EXIT_REASON_XSETBV              55
+#define EXIT_REASON_INVPCID             58
+
+#define VMX_EXIT_REASONS \
+	{ EXIT_REASON_EXCEPTION_NMI,         "EXCEPTION_NMI" }, \
+	{ EXIT_REASON_EXTERNAL_INTERRUPT,    "EXTERNAL_INTERRUPT" }, \
+	{ EXIT_REASON_TRIPLE_FAULT,          "TRIPLE_FAULT" }, \
+	{ EXIT_REASON_PENDING_INTERRUPT,     "PENDING_INTERRUPT" }, \
+	{ EXIT_REASON_NMI_WINDOW,            "NMI_WINDOW" }, \
+	{ EXIT_REASON_TASK_SWITCH,           "TASK_SWITCH" }, \
+	{ EXIT_REASON_CPUID,                 "CPUID" }, \
+	{ EXIT_REASON_HLT,                   "HLT" }, \
+	{ EXIT_REASON_INVLPG,                "INVLPG" }, \
+	{ EXIT_REASON_RDPMC,                 "RDPMC" }, \
+	{ EXIT_REASON_RDTSC,                 "RDTSC" }, \
+	{ EXIT_REASON_VMCALL,                "VMCALL" }, \
+	{ EXIT_REASON_VMCLEAR,               "VMCLEAR" }, \
+	{ EXIT_REASON_VMLAUNCH,              "VMLAUNCH" }, \
+	{ EXIT_REASON_VMPTRLD,               "VMPTRLD" }, \
+	{ EXIT_REASON_VMPTRST,               "VMPTRST" }, \
+	{ EXIT_REASON_VMREAD,                "VMREAD" }, \
+	{ EXIT_REASON_VMRESUME,              "VMRESUME" }, \
+	{ EXIT_REASON_VMWRITE,               "VMWRITE" }, \
+	{ EXIT_REASON_VMOFF,                 "VMOFF" }, \
+	{ EXIT_REASON_VMON,                  "VMON" }, \
+	{ EXIT_REASON_CR_ACCESS,             "CR_ACCESS" }, \
+	{ EXIT_REASON_DR_ACCESS,             "DR_ACCESS" }, \
+	{ EXIT_REASON_IO_INSTRUCTION,        "IO_INSTRUCTION" }, \
+	{ EXIT_REASON_MSR_READ,              "MSR_READ" }, \
+	{ EXIT_REASON_MSR_WRITE,             "MSR_WRITE" }, \
+	{ EXIT_REASON_MWAIT_INSTRUCTION,     "MWAIT_INSTRUCTION" }, \
+	{ EXIT_REASON_MONITOR_INSTRUCTION,   "MONITOR_INSTRUCTION" }, \
+	{ EXIT_REASON_PAUSE_INSTRUCTION,     "PAUSE_INSTRUCTION" }, \
+	{ EXIT_REASON_MCE_DURING_VMENTRY,    "MCE_DURING_VMENTRY" }, \
+	{ EXIT_REASON_TPR_BELOW_THRESHOLD,   "TPR_BELOW_THRESHOLD" }, \
+	{ EXIT_REASON_APIC_ACCESS,           "APIC_ACCESS" }, \
+	{ EXIT_REASON_EPT_VIOLATION,         "EPT_VIOLATION" }, \
+	{ EXIT_REASON_EPT_MISCONFIG,         "EPT_MISCONFIG" }, \
+	{ EXIT_REASON_WBINVD,                "WBINVD" }
+
+#ifdef __KERNEL__
+
 #include <linux/types.h>
 
 /*
@@ -241,49 +323,6 @@
 	HOST_RIP                        = 0x00006c16,
 };
 
-#define VMX_EXIT_REASONS_FAILED_VMENTRY         0x80000000
-
-#define EXIT_REASON_EXCEPTION_NMI       0
-#define EXIT_REASON_EXTERNAL_INTERRUPT  1
-#define EXIT_REASON_TRIPLE_FAULT        2
-
-#define EXIT_REASON_PENDING_INTERRUPT   7
-#define EXIT_REASON_NMI_WINDOW		8
-#define EXIT_REASON_TASK_SWITCH         9
-#define EXIT_REASON_CPUID               10
-#define EXIT_REASON_HLT                 12
-#define EXIT_REASON_INVD                13
-#define EXIT_REASON_INVLPG              14
-#define EXIT_REASON_RDPMC               15
-#define EXIT_REASON_RDTSC               16
-#define EXIT_REASON_VMCALL              18
-#define EXIT_REASON_VMCLEAR             19
-#define EXIT_REASON_VMLAUNCH            20
-#define EXIT_REASON_VMPTRLD             21
-#define EXIT_REASON_VMPTRST             22
-#define EXIT_REASON_VMREAD              23
-#define EXIT_REASON_VMRESUME            24
-#define EXIT_REASON_VMWRITE             25
-#define EXIT_REASON_VMOFF               26
-#define EXIT_REASON_VMON                27
-#define EXIT_REASON_CR_ACCESS           28
-#define EXIT_REASON_DR_ACCESS           29
-#define EXIT_REASON_IO_INSTRUCTION      30
-#define EXIT_REASON_MSR_READ            31
-#define EXIT_REASON_MSR_WRITE           32
-#define EXIT_REASON_INVALID_STATE	33
-#define EXIT_REASON_MWAIT_INSTRUCTION   36
-#define EXIT_REASON_MONITOR_INSTRUCTION 39
-#define EXIT_REASON_PAUSE_INSTRUCTION   40
-#define EXIT_REASON_MCE_DURING_VMENTRY	 41
-#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
-#define EXIT_REASON_APIC_ACCESS         44
-#define EXIT_REASON_EPT_VIOLATION       48
-#define EXIT_REASON_EPT_MISCONFIG       49
-#define EXIT_REASON_WBINVD		54
-#define EXIT_REASON_XSETBV		55
-#define EXIT_REASON_INVPCID		58
-
 /*
  * Interruption-information format
  */
@@ -488,3 +527,5 @@
 };
 
 #endif
+
+#endif
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 38155f6..5769349 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -81,12 +81,13 @@
 
 /**
  * struct x86_init_paging - platform specific paging functions
- * @pagetable_setup_start:	platform specific pre paging_init() call
- * @pagetable_setup_done:	platform specific post paging_init() call
+ * @pagetable_init:	platform specific paging initialization call to setup
+ *			the kernel pagetables and prepare accessors functions.
+ *			Callback must call paging_init(). Called once after the
+ *			direct mapping for phys memory is available.
  */
 struct x86_init_paging {
-	void (*pagetable_setup_start)(pgd_t *base);
-	void (*pagetable_setup_done)(pgd_t *base);
+	void (*pagetable_init)(void);
 };
 
 /**
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 93971e8..472b9b7 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -51,7 +51,8 @@
 
 extern int m2p_add_override(unsigned long mfn, struct page *page,
 			    struct gnttab_map_grant_ref *kmap_op);
-extern int m2p_remove_override(struct page *page, bool clear_pte);
+extern int m2p_remove_override(struct page *page,
+				struct gnttab_map_grant_ref *kmap_op);
 extern struct page *m2p_find_override(unsigned long mfn);
 extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
 
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index 4545708..aabd585 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -534,38 +534,6 @@
  * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
  */
 
-#define XMMS_SAVE				\
-do {						\
-	preempt_disable();			\
-	cr0 = read_cr0();			\
-	clts();					\
-	asm volatile(				\
-		"movups %%xmm0,(%0)	;\n\t"	\
-		"movups %%xmm1,0x10(%0)	;\n\t"	\
-		"movups %%xmm2,0x20(%0)	;\n\t"	\
-		"movups %%xmm3,0x30(%0)	;\n\t"	\
-		:				\
-		: "r" (xmm_save) 		\
-		: "memory");			\
-} while (0)
-
-#define XMMS_RESTORE				\
-do {						\
-	asm volatile(				\
-		"sfence			;\n\t"	\
-		"movups (%0),%%xmm0	;\n\t"	\
-		"movups 0x10(%0),%%xmm1	;\n\t"	\
-		"movups 0x20(%0),%%xmm2	;\n\t"	\
-		"movups 0x30(%0),%%xmm3	;\n\t"	\
-		:				\
-		: "r" (xmm_save)		\
-		: "memory");			\
-	write_cr0(cr0);				\
-	preempt_enable();			\
-} while (0)
-
-#define ALIGN16 __attribute__((aligned(16)))
-
 #define OFFS(x)		"16*("#x")"
 #define PF_OFFS(x)	"256+16*("#x")"
 #define	PF0(x)		"	prefetchnta "PF_OFFS(x)"(%1)		;\n"
@@ -587,10 +555,8 @@
 xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
 {
 	unsigned long lines = bytes >> 8;
-	char xmm_save[16*4] ALIGN16;
-	int cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -633,7 +599,7 @@
 	:
 	: "memory");
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -641,10 +607,8 @@
 	  unsigned long *p3)
 {
 	unsigned long lines = bytes >> 8;
-	char xmm_save[16*4] ALIGN16;
-	int cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -694,7 +658,7 @@
 	:
 	: "memory" );
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -702,10 +666,8 @@
 	  unsigned long *p3, unsigned long *p4)
 {
 	unsigned long lines = bytes >> 8;
-	char xmm_save[16*4] ALIGN16;
-	int cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -762,7 +724,7 @@
 	:
 	: "memory" );
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -770,10 +732,8 @@
 	  unsigned long *p3, unsigned long *p4, unsigned long *p5)
 {
 	unsigned long lines = bytes >> 8;
-	char xmm_save[16*4] ALIGN16;
-	int cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	/* Make sure GCC forgets anything it knows about p4 or p5,
 	   such that it won't pass to the asm volatile below a
@@ -850,7 +810,7 @@
 	   like assuming they have some legal value.  */
 	asm("" : "=r" (p4), "=r" (p5));
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static struct xor_block_template xor_block_pIII_sse = {
diff --git a/arch/x86/include/asm/xor_64.h b/arch/x86/include/asm/xor_64.h
index b9b2323..5fc06d0 100644
--- a/arch/x86/include/asm/xor_64.h
+++ b/arch/x86/include/asm/xor_64.h
@@ -34,41 +34,7 @@
  * no advantages to be gotten from x86-64 here anyways.
  */
 
-typedef struct {
-	unsigned long a, b;
-} __attribute__((aligned(16))) xmm_store_t;
-
-/* Doesn't use gcc to save the XMM registers, because there is no easy way to
-   tell it to do a clts before the register saving. */
-#define XMMS_SAVE				\
-do {						\
-	preempt_disable();			\
-	asm volatile(				\
-		"movq %%cr0,%0		;\n\t"	\
-		"clts			;\n\t"	\
-		"movups %%xmm0,(%1)	;\n\t"	\
-		"movups %%xmm1,0x10(%1)	;\n\t"	\
-		"movups %%xmm2,0x20(%1)	;\n\t"	\
-		"movups %%xmm3,0x30(%1)	;\n\t"	\
-		: "=&r" (cr0)			\
-		: "r" (xmm_save) 		\
-		: "memory");			\
-} while (0)
-
-#define XMMS_RESTORE				\
-do {						\
-	asm volatile(				\
-		"sfence			;\n\t"	\
-		"movups (%1),%%xmm0	;\n\t"	\
-		"movups 0x10(%1),%%xmm1	;\n\t"	\
-		"movups 0x20(%1),%%xmm2	;\n\t"	\
-		"movups 0x30(%1),%%xmm3	;\n\t"	\
-		"movq 	%0,%%cr0	;\n\t"	\
-		:				\
-		: "r" (cr0), "r" (xmm_save)	\
-		: "memory");			\
-	preempt_enable();			\
-} while (0)
+#include <asm/i387.h>
 
 #define OFFS(x)		"16*("#x")"
 #define PF_OFFS(x)	"256+16*("#x")"
@@ -91,10 +57,8 @@
 xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
 {
 	unsigned int lines = bytes >> 8;
-	unsigned long cr0;
-	xmm_store_t xmm_save[4];
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -135,7 +99,7 @@
 	: [inc] "r" (256UL)
 	: "memory");
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -143,11 +107,8 @@
 	  unsigned long *p3)
 {
 	unsigned int lines = bytes >> 8;
-	xmm_store_t xmm_save[4];
-	unsigned long cr0;
 
-	XMMS_SAVE;
-
+	kernel_fpu_begin();
 	asm volatile(
 #undef BLOCK
 #define BLOCK(i) \
@@ -194,7 +155,7 @@
 	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
 	: [inc] "r" (256UL)
 	: "memory");
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -202,10 +163,8 @@
 	  unsigned long *p3, unsigned long *p4)
 {
 	unsigned int lines = bytes >> 8;
-	xmm_store_t xmm_save[4];
-	unsigned long cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -261,7 +220,7 @@
 	: [inc] "r" (256UL)
 	: "memory" );
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static void
@@ -269,10 +228,8 @@
 	  unsigned long *p3, unsigned long *p4, unsigned long *p5)
 {
 	unsigned int lines = bytes >> 8;
-	xmm_store_t xmm_save[4];
-	unsigned long cr0;
 
-	XMMS_SAVE;
+	kernel_fpu_begin();
 
 	asm volatile(
 #undef BLOCK
@@ -336,7 +293,7 @@
 	: [inc] "r" (256UL)
 	: "memory");
 
-	XMMS_RESTORE;
+	kernel_fpu_end();
 }
 
 static struct xor_block_template xor_block_sse = {
diff --git a/arch/x86/include/asm/xor_avx.h b/arch/x86/include/asm/xor_avx.h
index 2510d35..7ea79c5 100644
--- a/arch/x86/include/asm/xor_avx.h
+++ b/arch/x86/include/asm/xor_avx.h
@@ -20,32 +20,6 @@
 #include <linux/compiler.h>
 #include <asm/i387.h>
 
-#define ALIGN32 __aligned(32)
-
-#define YMM_SAVED_REGS 4
-
-#define YMMS_SAVE \
-do { \
-	preempt_disable(); \
-	cr0 = read_cr0(); \
-	clts(); \
-	asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
-	asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
-	asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
-	asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
-} while (0);
-
-#define YMMS_RESTORE \
-do { \
-	asm volatile("sfence" : : : "memory"); \
-	asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
-	asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
-	asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
-	asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
-	write_cr0(cr0); \
-	preempt_enable(); \
-} while (0);
-
 #define BLOCK4(i) \
 		BLOCK(32 * i, 0) \
 		BLOCK(32 * (i + 1), 1) \
@@ -60,10 +34,9 @@
 
 static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
 {
-	unsigned long cr0, lines = bytes >> 9;
-	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+	unsigned long lines = bytes >> 9;
 
-	YMMS_SAVE
+	kernel_fpu_begin();
 
 	while (lines--) {
 #undef BLOCK
@@ -82,16 +55,15 @@
 		p1 = (unsigned long *)((uintptr_t)p1 + 512);
 	}
 
-	YMMS_RESTORE
+	kernel_fpu_end();
 }
 
 static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
 	unsigned long *p2)
 {
-	unsigned long cr0, lines = bytes >> 9;
-	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+	unsigned long lines = bytes >> 9;
 
-	YMMS_SAVE
+	kernel_fpu_begin();
 
 	while (lines--) {
 #undef BLOCK
@@ -113,16 +85,15 @@
 		p2 = (unsigned long *)((uintptr_t)p2 + 512);
 	}
 
-	YMMS_RESTORE
+	kernel_fpu_end();
 }
 
 static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
 	unsigned long *p2, unsigned long *p3)
 {
-	unsigned long cr0, lines = bytes >> 9;
-	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+	unsigned long lines = bytes >> 9;
 
-	YMMS_SAVE
+	kernel_fpu_begin();
 
 	while (lines--) {
 #undef BLOCK
@@ -147,16 +118,15 @@
 		p3 = (unsigned long *)((uintptr_t)p3 + 512);
 	}
 
-	YMMS_RESTORE
+	kernel_fpu_end();
 }
 
 static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
 	unsigned long *p2, unsigned long *p3, unsigned long *p4)
 {
-	unsigned long cr0, lines = bytes >> 9;
-	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+	unsigned long lines = bytes >> 9;
 
-	YMMS_SAVE
+	kernel_fpu_begin();
 
 	while (lines--) {
 #undef BLOCK
@@ -184,7 +154,7 @@
 		p4 = (unsigned long *)((uintptr_t)p4 + 512);
 	}
 
-	YMMS_RESTORE
+	kernel_fpu_end();
 }
 
 static struct xor_block_template xor_block_avx = {
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 8a1b6f9..0415cda 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -34,17 +34,14 @@
 extern unsigned int xstate_size;
 extern u64 pcntxt_mask;
 extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
+extern struct xsave_struct *init_xstate_buf;
 
 extern void xsave_init(void);
 extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
 extern int init_fpu(struct task_struct *child);
-extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
-			    void __user *fpstate,
-			    struct _fpx_sw_bytes *sw);
 
-static inline int fpu_xrstor_checking(struct fpu *fpu)
+static inline int fpu_xrstor_checking(struct xsave_struct *fx)
 {
-	struct xsave_struct *fx = &fpu->state->xsave;
 	int err;
 
 	asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
@@ -69,13 +66,13 @@
 	 * Clear the xsave header first, so that reserved fields are
 	 * initialized to zero.
 	 */
-	err = __clear_user(&buf->xsave_hdr,
-			   sizeof(struct xsave_hdr_struct));
+	err = __clear_user(&buf->xsave_hdr, sizeof(buf->xsave_hdr));
 	if (unlikely(err))
 		return -EFAULT;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
@@ -84,9 +81,6 @@
 			     : [err] "=r" (err)
 			     : "D" (buf), "a" (-1), "d" (-1), "0" (0)
 			     : "memory");
-	if (unlikely(err) && __clear_user(buf, xstate_size))
-		err = -EFAULT;
-	/* No need to clear here because the caller clears USED_MATH */
 	return err;
 }
 
@@ -97,8 +91,9 @@
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 8215e56..8d7a619 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -100,6 +100,8 @@
 obj-$(CONFIG_OF)			+= devicetree.o
 obj-$(CONFIG_UPROBES)			+= uprobes.o
 
+obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index b2297e5..e651f7a 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -656,7 +656,7 @@
 	acpi_register_lapic(physid, ACPI_MADT_ENABLED);
 
 	/*
-	 * If mp_register_lapic successfully generates a new logical cpu
+	 * If acpi_register_lapic successfully generates a new logical cpu
 	 * number, then the following will get us exactly what was mapped
 	 */
 	cpumask_andnot(new_map, cpu_present_mask, tmp_map);
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 1b8e5a0..11676cf 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -43,17 +43,22 @@
 
 	header->video_mode = saved_video_mode;
 
+	header->pmode_behavior = 0;
+
 #ifndef CONFIG_64BIT
 	store_gdt((struct desc_ptr *)&header->pmode_gdt);
 
-	if (rdmsr_safe(MSR_EFER, &header->pmode_efer_low,
-		       &header->pmode_efer_high))
-		header->pmode_efer_low = header->pmode_efer_high = 0;
+	if (!rdmsr_safe(MSR_EFER,
+			&header->pmode_efer_low,
+			&header->pmode_efer_high))
+		header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
 #endif /* !CONFIG_64BIT */
 
 	header->pmode_cr0 = read_cr0();
-	header->pmode_cr4 = read_cr4_safe();
-	header->pmode_behavior = 0;
+	if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
+		header->pmode_cr4 = read_cr4();
+		header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
+	}
 	if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
 			&header->pmode_misc_en_low,
 			&header->pmode_misc_en_high))
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index ced4534..ef5ccca 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -23,19 +23,6 @@
 
 #define MAX_PATCH_LEN (255-1)
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int smp_alt_once;
-
-static int __init bootonly(char *str)
-{
-	smp_alt_once = 1;
-	return 1;
-}
-__setup("smp-alt-boot", bootonly);
-#else
-#define smp_alt_once 1
-#endif
-
 static int __initdata_or_module debug_alternative;
 
 static int __init debug_alt(char *str)
@@ -317,7 +304,7 @@
 		/* turn DS segment override prefix into lock prefix */
 		if (*ptr == 0x3e)
 			text_poke(ptr, ((unsigned char []){0xf0}), 1);
-	};
+	}
 	mutex_unlock(&text_mutex);
 }
 
@@ -326,9 +313,6 @@
 {
 	const s32 *poff;
 
-	if (noreplace_smp)
-		return;
-
 	mutex_lock(&text_mutex);
 	for (poff = start; poff < end; poff++) {
 		u8 *ptr = (u8 *)poff + *poff;
@@ -338,7 +322,7 @@
 		/* turn lock prefix into DS segment override prefix */
 		if (*ptr == 0xf0)
 			text_poke(ptr, ((unsigned char []){0x3E}), 1);
-	};
+	}
 	mutex_unlock(&text_mutex);
 }
 
@@ -359,7 +343,7 @@
 };
 static LIST_HEAD(smp_alt_modules);
 static DEFINE_MUTEX(smp_alt);
-static int smp_mode = 1;	/* protected by smp_alt */
+static bool uniproc_patched = false;	/* protected by smp_alt */
 
 void __init_or_module alternatives_smp_module_add(struct module *mod,
 						  char *name,
@@ -368,19 +352,18 @@
 {
 	struct smp_alt_module *smp;
 
-	if (noreplace_smp)
-		return;
+	mutex_lock(&smp_alt);
+	if (!uniproc_patched)
+		goto unlock;
 
-	if (smp_alt_once) {
-		if (boot_cpu_has(X86_FEATURE_UP))
-			alternatives_smp_unlock(locks, locks_end,
-						text, text_end);
-		return;
-	}
+	if (num_possible_cpus() == 1)
+		/* Don't bother remembering, we'll never have to undo it. */
+		goto smp_unlock;
 
 	smp = kzalloc(sizeof(*smp), GFP_KERNEL);
 	if (NULL == smp)
-		return; /* we'll run the (safe but slow) SMP code then ... */
+		/* we'll run the (safe but slow) SMP code then ... */
+		goto unlock;
 
 	smp->mod	= mod;
 	smp->name	= name;
@@ -392,11 +375,10 @@
 		__func__, smp->locks, smp->locks_end,
 		smp->text, smp->text_end, smp->name);
 
-	mutex_lock(&smp_alt);
 	list_add_tail(&smp->next, &smp_alt_modules);
-	if (boot_cpu_has(X86_FEATURE_UP))
-		alternatives_smp_unlock(smp->locks, smp->locks_end,
-					smp->text, smp->text_end);
+smp_unlock:
+	alternatives_smp_unlock(locks, locks_end, text, text_end);
+unlock:
 	mutex_unlock(&smp_alt);
 }
 
@@ -404,24 +386,18 @@
 {
 	struct smp_alt_module *item;
 
-	if (smp_alt_once || noreplace_smp)
-		return;
-
 	mutex_lock(&smp_alt);
 	list_for_each_entry(item, &smp_alt_modules, next) {
 		if (mod != item->mod)
 			continue;
 		list_del(&item->next);
-		mutex_unlock(&smp_alt);
-		DPRINTK("%s: %s\n", __func__, item->name);
 		kfree(item);
-		return;
+		break;
 	}
 	mutex_unlock(&smp_alt);
 }
 
-bool skip_smp_alternatives;
-void alternatives_smp_switch(int smp)
+void alternatives_enable_smp(void)
 {
 	struct smp_alt_module *mod;
 
@@ -436,34 +412,21 @@
 	pr_info("lockdep: fixing up alternatives\n");
 #endif
 
-	if (noreplace_smp || smp_alt_once || skip_smp_alternatives)
-		return;
-	BUG_ON(!smp && (num_online_cpus() > 1));
+	/* Why bother if there are no other CPUs? */
+	BUG_ON(num_possible_cpus() == 1);
 
 	mutex_lock(&smp_alt);
 
-	/*
-	 * Avoid unnecessary switches because it forces JIT based VMs to
-	 * throw away all cached translations, which can be quite costly.
-	 */
-	if (smp == smp_mode) {
-		/* nothing */
-	} else if (smp) {
+	if (uniproc_patched) {
 		pr_info("switching to SMP code\n");
+		BUG_ON(num_online_cpus() != 1);
 		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
 		clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
 		list_for_each_entry(mod, &smp_alt_modules, next)
 			alternatives_smp_lock(mod->locks, mod->locks_end,
 					      mod->text, mod->text_end);
-	} else {
-		pr_info("switching to UP code\n");
-		set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
-		set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
-		list_for_each_entry(mod, &smp_alt_modules, next)
-			alternatives_smp_unlock(mod->locks, mod->locks_end,
-						mod->text, mod->text_end);
+		uniproc_patched = false;
 	}
-	smp_mode = smp;
 	mutex_unlock(&smp_alt);
 }
 
@@ -540,40 +503,22 @@
 
 	apply_alternatives(__alt_instructions, __alt_instructions_end);
 
-	/* switch to patch-once-at-boottime-only mode and free the
-	 * tables in case we know the number of CPUs will never ever
-	 * change */
-#ifdef CONFIG_HOTPLUG_CPU
-	if (num_possible_cpus() < 2)
-		smp_alt_once = 1;
-#endif
-
 #ifdef CONFIG_SMP
-	if (smp_alt_once) {
-		if (1 == num_possible_cpus()) {
-			pr_info("switching to UP code\n");
-			set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
-			set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
-
-			alternatives_smp_unlock(__smp_locks, __smp_locks_end,
-						_text, _etext);
-		}
-	} else {
+	/* Patch to UP if other cpus not imminent. */
+	if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) {
+		uniproc_patched = true;
 		alternatives_smp_module_add(NULL, "core kernel",
 					    __smp_locks, __smp_locks_end,
 					    _text, _etext);
-
-		/* Only switch to UP mode if we don't immediately boot others */
-		if (num_present_cpus() == 1 || setup_max_cpus <= 1)
-			alternatives_smp_switch(0);
 	}
-#endif
- 	apply_paravirt(__parainstructions, __parainstructions_end);
 
-	if (smp_alt_once)
+	if (!uniproc_patched || num_possible_cpus() == 1)
 		free_init_pages("SMP alternatives",
 				(unsigned long)__smp_locks,
 				(unsigned long)__smp_locks_end);
+#endif
+
+	apply_paravirt(__parainstructions, __parainstructions_end);
 
 	restart_nmi();
 }
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 24deb30..b17416e 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1934,7 +1934,7 @@
 			apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
 		i++;
 		v1 >>= 1;
-	};
+	}
 
 	apic_printk(APIC_DEBUG, KERN_CONT "\n");
 
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 9d92e19..f7e98a2 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -737,6 +737,72 @@
 }
 #endif
 
+static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)
+{
+	if (!cpu_has_invlpg)
+		return;
+
+	tlb_flushall_shift = 5;
+
+	if (c->x86 <= 0x11)
+		tlb_flushall_shift = 4;
+}
+
+static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
+{
+	u32 ebx, eax, ecx, edx;
+	u16 mask = 0xfff;
+
+	if (c->x86 < 0xf)
+		return;
+
+	if (c->extended_cpuid_level < 0x80000006)
+		return;
+
+	cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
+
+	tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask;
+	tlb_lli_4k[ENTRIES] = ebx & mask;
+
+	/*
+	 * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
+	 * characteristics from the CPUID function 0x80000005 instead.
+	 */
+	if (c->x86 == 0xf) {
+		cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+		mask = 0xff;
+	}
+
+	/* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+	if (!((eax >> 16) & mask)) {
+		u32 a, b, c, d;
+
+		cpuid(0x80000005, &a, &b, &c, &d);
+		tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff;
+	} else {
+		tlb_lld_2m[ENTRIES] = (eax >> 16) & mask;
+	}
+
+	/* a 4M entry uses two 2M entries */
+	tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1;
+
+	/* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+	if (!(eax & mask)) {
+		/* Erratum 658 */
+		if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
+			tlb_lli_2m[ENTRIES] = 1024;
+		} else {
+			cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+			tlb_lli_2m[ENTRIES] = eax & 0xff;
+		}
+	} else
+		tlb_lli_2m[ENTRIES] = eax & mask;
+
+	tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1;
+
+	cpu_set_tlb_flushall_shift(c);
+}
+
 static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
 	.c_vendor	= "AMD",
 	.c_ident	= { "AuthenticAMD" },
@@ -756,6 +822,7 @@
 	.c_size_cache	= amd_size_cache,
 #endif
 	.c_early_init   = early_init_amd,
+	.c_detect_tlb	= cpu_detect_tlb_amd,
 	.c_bsp_init	= bsp_init_amd,
 	.c_init		= init_amd,
 	.c_x86_vendor	= X86_VENDOR_AMD,
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index c97bb7b..d0e910d 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -165,10 +165,15 @@
 	print_cpu_info(&boot_cpu_data);
 #endif
 	check_config();
-	check_fpu();
 	check_hlt();
 	check_popad();
 	init_utsname()->machine[1] =
 		'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
 	alternative_instructions();
+
+	/*
+	 * kernel_fpu_begin/end() in check_fpu() relies on the patched
+	 * alternative instructions.
+	 */
+	check_fpu();
 }
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a5fbc3c..7505f7b 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -259,23 +259,36 @@
 }
 #endif
 
-static int disable_smep __cpuinitdata;
 static __init int setup_disable_smep(char *arg)
 {
-	disable_smep = 1;
+	setup_clear_cpu_cap(X86_FEATURE_SMEP);
 	return 1;
 }
 __setup("nosmep", setup_disable_smep);
 
-static __cpuinit void setup_smep(struct cpuinfo_x86 *c)
+static __always_inline void setup_smep(struct cpuinfo_x86 *c)
 {
-	if (cpu_has(c, X86_FEATURE_SMEP)) {
-		if (unlikely(disable_smep)) {
-			setup_clear_cpu_cap(X86_FEATURE_SMEP);
-			clear_in_cr4(X86_CR4_SMEP);
-		} else
-			set_in_cr4(X86_CR4_SMEP);
-	}
+	if (cpu_has(c, X86_FEATURE_SMEP))
+		set_in_cr4(X86_CR4_SMEP);
+}
+
+static __init int setup_disable_smap(char *arg)
+{
+	setup_clear_cpu_cap(X86_FEATURE_SMAP);
+	return 1;
+}
+__setup("nosmap", setup_disable_smap);
+
+static __always_inline void setup_smap(struct cpuinfo_x86 *c)
+{
+	unsigned long eflags;
+
+	/* This should have been cleared long ago */
+	raw_local_save_flags(eflags);
+	BUG_ON(eflags & X86_EFLAGS_AC);
+
+	if (cpu_has(c, X86_FEATURE_SMAP))
+		set_in_cr4(X86_CR4_SMAP);
 }
 
 /*
@@ -476,7 +489,7 @@
 
 	printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
 		"Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n"	     \
-		"tlb_flushall_shift is 0x%x\n",
+		"tlb_flushall_shift: %d\n",
 		tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES],
 		tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES],
 		tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES],
@@ -712,8 +725,6 @@
 	c->cpu_index = 0;
 	filter_cpuid_features(c, false);
 
-	setup_smep(c);
-
 	if (this_cpu->c_bsp_init)
 		this_cpu->c_bsp_init(c);
 }
@@ -798,8 +809,6 @@
 		c->phys_proc_id = c->initial_apicid;
 	}
 
-	setup_smep(c);
-
 	get_model_name(c); /* Default name */
 
 	detect_nopl(c);
@@ -864,6 +873,10 @@
 	/* Disable the PN if appropriate */
 	squash_the_stupid_serial_number(c);
 
+	/* Set up SMEP/SMAP */
+	setup_smep(c);
+	setup_smap(c);
+
 	/*
 	 * The vendor-specific functions might have changed features.
 	 * Now we do "generic changes."
@@ -942,8 +955,7 @@
 #else
 	vgetcpu_set_mode();
 #endif
-	if (boot_cpu_data.cpuid_level >= 2)
-		cpu_detect_tlb(&boot_cpu_data);
+	cpu_detect_tlb(&boot_cpu_data);
 }
 
 void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
@@ -1023,14 +1035,16 @@
 		printk(KERN_CONT "%s ", vendor);
 
 	if (c->x86_model_id[0])
-		printk(KERN_CONT "%s", c->x86_model_id);
+		printk(KERN_CONT "%s", strim(c->x86_model_id));
 	else
 		printk(KERN_CONT "%d86", c->x86);
 
+	printk(KERN_CONT " (fam: %02x, model: %02x", c->x86, c->x86_model);
+
 	if (c->x86_mask || c->cpuid_level >= 0)
-		printk(KERN_CONT " stepping %02x\n", c->x86_mask);
+		printk(KERN_CONT ", stepping: %02x)\n", c->x86_mask);
 	else
-		printk(KERN_CONT "\n");
+		printk(KERN_CONT ")\n");
 
 	print_cpu_msr(c);
 }
@@ -1113,11 +1127,10 @@
 
 	/* Flags to clear on syscall */
 	wrmsrl(MSR_SYSCALL_MASK,
-	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
+	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
+	       X86_EFLAGS_IOPL|X86_EFLAGS_AC);
 }
 
-unsigned long kernel_eflags;
-
 /*
  * Copies of the original ist values from the tss are only accessed during
  * debugging, no special alignment required.
@@ -1297,9 +1310,6 @@
 	dbg_restore_debug_regs();
 
 	fpu_init();
-	xsave_init();
-
-	raw_local_save_flags(kernel_eflags);
 
 	if (is_uv_system())
 		uv_cpu_init();
@@ -1352,6 +1362,5 @@
 	dbg_restore_debug_regs();
 
 	fpu_init();
-	xsave_init();
 }
 #endif
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 0a4ce29..198e019 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -648,6 +648,10 @@
 	int i, j, n;
 	unsigned int regs[4];
 	unsigned char *desc = (unsigned char *)regs;
+
+	if (c->cpuid_level < 2)
+		return;
+
 	/* Number of times to iterate */
 	n = cpuid_eax(2) & 0xFF;
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
index fc4beb3..ddc72f8 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-inject.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -78,6 +78,7 @@
 }
 
 static cpumask_var_t mce_inject_cpumask;
+static DEFINE_MUTEX(mce_inject_mutex);
 
 static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs)
 {
@@ -194,7 +195,11 @@
 		put_online_cpus();
 	} else
 #endif
+	{
+		preempt_disable();
 		raise_local();
+		preempt_enable();
+	}
 }
 
 /* Error injection interface */
@@ -225,7 +230,10 @@
 	 * so do it a jiffie or two later everywhere.
 	 */
 	schedule_timeout(2);
+
+	mutex_lock(&mce_inject_mutex);
 	raise_mce(&m);
+	mutex_unlock(&mce_inject_mutex);
 	return usize;
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index ed44c8a..6a05c1d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -28,6 +28,18 @@
 
 extern struct mce_bank *mce_banks;
 
+#ifdef CONFIG_X86_MCE_INTEL
+unsigned long mce_intel_adjust_timer(unsigned long interval);
+void mce_intel_cmci_poll(void);
+void mce_intel_hcpu_update(unsigned long cpu);
+#else
+# define mce_intel_adjust_timer mce_adjust_timer_default
+static inline void mce_intel_cmci_poll(void) { }
+static inline void mce_intel_hcpu_update(unsigned long cpu) { }
+#endif
+
+void mce_timer_kick(unsigned long interval);
+
 #ifdef CONFIG_ACPI_APEI
 int apei_write_mce(struct mce *m);
 ssize_t apei_read_mce(struct mce *m, u64 *record_id);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 292d025..29e87d3 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -83,6 +83,7 @@
 int				mce_cmci_disabled	__read_mostly;
 int				mce_ignore_ce		__read_mostly;
 int				mce_ser			__read_mostly;
+int				mce_bios_cmci_threshold	__read_mostly;
 
 struct mce_bank                *mce_banks		__read_mostly;
 
@@ -1266,6 +1267,14 @@
 static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */
 static DEFINE_PER_CPU(struct timer_list, mce_timer);
 
+static unsigned long mce_adjust_timer_default(unsigned long interval)
+{
+	return interval;
+}
+
+static unsigned long (*mce_adjust_timer)(unsigned long interval) =
+	mce_adjust_timer_default;
+
 static void mce_timer_fn(unsigned long data)
 {
 	struct timer_list *t = &__get_cpu_var(mce_timer);
@@ -1276,6 +1285,7 @@
 	if (mce_available(__this_cpu_ptr(&cpu_info))) {
 		machine_check_poll(MCP_TIMESTAMP,
 				&__get_cpu_var(mce_poll_banks));
+		mce_intel_cmci_poll();
 	}
 
 	/*
@@ -1283,14 +1293,38 @@
 	 * polling interval, otherwise increase the polling interval.
 	 */
 	iv = __this_cpu_read(mce_next_interval);
-	if (mce_notify_irq())
+	if (mce_notify_irq()) {
 		iv = max(iv / 2, (unsigned long) HZ/100);
-	else
+	} else {
 		iv = min(iv * 2, round_jiffies_relative(check_interval * HZ));
+		iv = mce_adjust_timer(iv);
+	}
 	__this_cpu_write(mce_next_interval, iv);
+	/* Might have become 0 after CMCI storm subsided */
+	if (iv) {
+		t->expires = jiffies + iv;
+		add_timer_on(t, smp_processor_id());
+	}
+}
 
-	t->expires = jiffies + iv;
-	add_timer_on(t, smp_processor_id());
+/*
+ * Ensure that the timer is firing in @interval from now.
+ */
+void mce_timer_kick(unsigned long interval)
+{
+	struct timer_list *t = &__get_cpu_var(mce_timer);
+	unsigned long when = jiffies + interval;
+	unsigned long iv = __this_cpu_read(mce_next_interval);
+
+	if (timer_pending(t)) {
+		if (time_before(when, t->expires))
+			mod_timer_pinned(t, when);
+	} else {
+		t->expires = round_jiffies(when);
+		add_timer_on(t, smp_processor_id());
+	}
+	if (interval < iv)
+		__this_cpu_write(mce_next_interval, interval);
 }
 
 /* Must not be called in IRQ context where del_timer_sync() can deadlock */
@@ -1585,6 +1619,7 @@
 	switch (c->x86_vendor) {
 	case X86_VENDOR_INTEL:
 		mce_intel_feature_init(c);
+		mce_adjust_timer = mce_intel_adjust_timer;
 		break;
 	case X86_VENDOR_AMD:
 		mce_amd_feature_init(c);
@@ -1594,21 +1629,26 @@
 	}
 }
 
+static void mce_start_timer(unsigned int cpu, struct timer_list *t)
+{
+	unsigned long iv = mce_adjust_timer(check_interval * HZ);
+
+	__this_cpu_write(mce_next_interval, iv);
+
+	if (mce_ignore_ce || !iv)
+		return;
+
+	t->expires = round_jiffies(jiffies + iv);
+	add_timer_on(t, smp_processor_id());
+}
+
 static void __mcheck_cpu_init_timer(void)
 {
 	struct timer_list *t = &__get_cpu_var(mce_timer);
-	unsigned long iv = check_interval * HZ;
+	unsigned int cpu = smp_processor_id();
 
-	setup_timer(t, mce_timer_fn, smp_processor_id());
-
-	if (mce_ignore_ce)
-		return;
-
-	__this_cpu_write(mce_next_interval, iv);
-	if (!iv)
-		return;
-	t->expires = round_jiffies(jiffies + iv);
-	add_timer_on(t, smp_processor_id());
+	setup_timer(t, mce_timer_fn, cpu);
+	mce_start_timer(cpu, t);
 }
 
 /* Handle unconfigured int18 (should never happen) */
@@ -1907,6 +1947,7 @@
  *	check, or 0 to not wait
  * mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
  * mce=nobootlog Don't log MCEs from before booting.
+ * mce=bios_cmci_threshold Don't program the CMCI threshold
  */
 static int __init mcheck_enable(char *str)
 {
@@ -1926,6 +1967,8 @@
 		mce_ignore_ce = 1;
 	else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog"))
 		mce_bootlog = (str[0] == 'b');
+	else if (!strcmp(str, "bios_cmci_threshold"))
+		mce_bios_cmci_threshold = 1;
 	else if (isdigit(str[0])) {
 		get_option(&str, &tolerant);
 		if (*str == ',') {
@@ -2166,6 +2209,11 @@
 	&mce_cmci_disabled
 };
 
+static struct dev_ext_attribute dev_attr_bios_cmci_threshold = {
+	__ATTR(bios_cmci_threshold, 0444, device_show_int, NULL),
+	&mce_bios_cmci_threshold
+};
+
 static struct device_attribute *mce_device_attrs[] = {
 	&dev_attr_tolerant.attr,
 	&dev_attr_check_interval.attr,
@@ -2174,6 +2222,7 @@
 	&dev_attr_dont_log_ce.attr,
 	&dev_attr_ignore_ce.attr,
 	&dev_attr_cmci_disabled.attr,
+	&dev_attr_bios_cmci_threshold.attr,
 	NULL
 };
 
@@ -2294,38 +2343,33 @@
 	unsigned int cpu = (unsigned long)hcpu;
 	struct timer_list *t = &per_cpu(mce_timer, cpu);
 
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
 		mce_device_create(cpu);
 		if (threshold_cpu_callback)
 			threshold_cpu_callback(action, cpu);
 		break;
 	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
 		if (threshold_cpu_callback)
 			threshold_cpu_callback(action, cpu);
 		mce_device_remove(cpu);
+		mce_intel_hcpu_update(cpu);
 		break;
 	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
-		del_timer_sync(t);
 		smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
+		del_timer_sync(t);
 		break;
 	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
-		if (!mce_ignore_ce && check_interval) {
-			t->expires = round_jiffies(jiffies +
-					per_cpu(mce_next_interval, cpu));
-			add_timer_on(t, cpu);
-		}
 		smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
-		break;
-	case CPU_POST_DEAD:
-		/* intentionally ignoring frozen here */
-		cmci_rediscover(cpu);
+		mce_start_timer(cpu, t);
 		break;
 	}
+
+	if (action == CPU_POST_DEAD) {
+		/* intentionally ignoring frozen here */
+		cmci_rediscover(cpu);
+	}
+
 	return NOTIFY_OK;
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index 38e49bc9..5f88abf 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -15,6 +15,8 @@
 #include <asm/msr.h>
 #include <asm/mce.h>
 
+#include "mce-internal.h"
+
 /*
  * Support for Intel Correct Machine Check Interrupts. This allows
  * the CPU to raise an interrupt when a corrected machine check happened.
@@ -30,7 +32,22 @@
  */
 static DEFINE_RAW_SPINLOCK(cmci_discover_lock);
 
-#define CMCI_THRESHOLD 1
+#define CMCI_THRESHOLD		1
+#define CMCI_POLL_INTERVAL	(30 * HZ)
+#define CMCI_STORM_INTERVAL	(1 * HZ)
+#define CMCI_STORM_THRESHOLD	15
+
+static DEFINE_PER_CPU(unsigned long, cmci_time_stamp);
+static DEFINE_PER_CPU(unsigned int, cmci_storm_cnt);
+static DEFINE_PER_CPU(unsigned int, cmci_storm_state);
+
+enum {
+	CMCI_STORM_NONE,
+	CMCI_STORM_ACTIVE,
+	CMCI_STORM_SUBSIDED,
+};
+
+static atomic_t cmci_storm_on_cpus;
 
 static int cmci_supported(int *banks)
 {
@@ -53,6 +70,93 @@
 	return !!(cap & MCG_CMCI_P);
 }
 
+void mce_intel_cmci_poll(void)
+{
+	if (__this_cpu_read(cmci_storm_state) == CMCI_STORM_NONE)
+		return;
+	machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
+}
+
+void mce_intel_hcpu_update(unsigned long cpu)
+{
+	if (per_cpu(cmci_storm_state, cpu) == CMCI_STORM_ACTIVE)
+		atomic_dec(&cmci_storm_on_cpus);
+
+	per_cpu(cmci_storm_state, cpu) = CMCI_STORM_NONE;
+}
+
+unsigned long mce_intel_adjust_timer(unsigned long interval)
+{
+	int r;
+
+	if (interval < CMCI_POLL_INTERVAL)
+		return interval;
+
+	switch (__this_cpu_read(cmci_storm_state)) {
+	case CMCI_STORM_ACTIVE:
+		/*
+		 * We switch back to interrupt mode once the poll timer has
+		 * silenced itself. That means no events recorded and the
+		 * timer interval is back to our poll interval.
+		 */
+		__this_cpu_write(cmci_storm_state, CMCI_STORM_SUBSIDED);
+		r = atomic_sub_return(1, &cmci_storm_on_cpus);
+		if (r == 0)
+			pr_notice("CMCI storm subsided: switching to interrupt mode\n");
+		/* FALLTHROUGH */
+
+	case CMCI_STORM_SUBSIDED:
+		/*
+		 * We wait for all cpus to go back to SUBSIDED
+		 * state. When that happens we switch back to
+		 * interrupt mode.
+		 */
+		if (!atomic_read(&cmci_storm_on_cpus)) {
+			__this_cpu_write(cmci_storm_state, CMCI_STORM_NONE);
+			cmci_reenable();
+			cmci_recheck();
+		}
+		return CMCI_POLL_INTERVAL;
+	default:
+		/*
+		 * We have shiny weather. Let the poll do whatever it
+		 * thinks.
+		 */
+		return interval;
+	}
+}
+
+static bool cmci_storm_detect(void)
+{
+	unsigned int cnt = __this_cpu_read(cmci_storm_cnt);
+	unsigned long ts = __this_cpu_read(cmci_time_stamp);
+	unsigned long now = jiffies;
+	int r;
+
+	if (__this_cpu_read(cmci_storm_state) != CMCI_STORM_NONE)
+		return true;
+
+	if (time_before_eq(now, ts + CMCI_STORM_INTERVAL)) {
+		cnt++;
+	} else {
+		cnt = 1;
+		__this_cpu_write(cmci_time_stamp, now);
+	}
+	__this_cpu_write(cmci_storm_cnt, cnt);
+
+	if (cnt <= CMCI_STORM_THRESHOLD)
+		return false;
+
+	cmci_clear();
+	__this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE);
+	r = atomic_add_return(1, &cmci_storm_on_cpus);
+	mce_timer_kick(CMCI_POLL_INTERVAL);
+
+	if (r == 1)
+		pr_notice("CMCI storm detected: switching to poll mode\n");
+	return true;
+}
+
 /*
  * The interrupt handler. This is called on every event.
  * Just call the poller directly to log any events.
@@ -61,33 +165,28 @@
  */
 static void intel_threshold_interrupt(void)
 {
+	if (cmci_storm_detect())
+		return;
 	machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
 	mce_notify_irq();
 }
 
-static void print_update(char *type, int *hdr, int num)
-{
-	if (*hdr == 0)
-		printk(KERN_INFO "CPU %d MCA banks", smp_processor_id());
-	*hdr = 1;
-	printk(KERN_CONT " %s:%d", type, num);
-}
-
 /*
  * Enable CMCI (Corrected Machine Check Interrupt) for available MCE banks
  * on this CPU. Use the algorithm recommended in the SDM to discover shared
  * banks.
  */
-static void cmci_discover(int banks, int boot)
+static void cmci_discover(int banks)
 {
 	unsigned long *owned = (void *)&__get_cpu_var(mce_banks_owned);
 	unsigned long flags;
-	int hdr = 0;
 	int i;
+	int bios_wrong_thresh = 0;
 
 	raw_spin_lock_irqsave(&cmci_discover_lock, flags);
 	for (i = 0; i < banks; i++) {
 		u64 val;
+		int bios_zero_thresh = 0;
 
 		if (test_bit(i, owned))
 			continue;
@@ -96,29 +195,52 @@
 
 		/* Already owned by someone else? */
 		if (val & MCI_CTL2_CMCI_EN) {
-			if (test_and_clear_bit(i, owned) && !boot)
-				print_update("SHD", &hdr, i);
+			clear_bit(i, owned);
 			__clear_bit(i, __get_cpu_var(mce_poll_banks));
 			continue;
 		}
 
-		val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK;
-		val |= MCI_CTL2_CMCI_EN | CMCI_THRESHOLD;
+		if (!mce_bios_cmci_threshold) {
+			val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK;
+			val |= CMCI_THRESHOLD;
+		} else if (!(val & MCI_CTL2_CMCI_THRESHOLD_MASK)) {
+			/*
+			 * If bios_cmci_threshold boot option was specified
+			 * but the threshold is zero, we'll try to initialize
+			 * it to 1.
+			 */
+			bios_zero_thresh = 1;
+			val |= CMCI_THRESHOLD;
+		}
+
+		val |= MCI_CTL2_CMCI_EN;
 		wrmsrl(MSR_IA32_MCx_CTL2(i), val);
 		rdmsrl(MSR_IA32_MCx_CTL2(i), val);
 
 		/* Did the enable bit stick? -- the bank supports CMCI */
 		if (val & MCI_CTL2_CMCI_EN) {
-			if (!test_and_set_bit(i, owned) && !boot)
-				print_update("CMCI", &hdr, i);
+			set_bit(i, owned);
 			__clear_bit(i, __get_cpu_var(mce_poll_banks));
+			/*
+			 * We are able to set thresholds for some banks that
+			 * had a threshold of 0. This means the BIOS has not
+			 * set the thresholds properly or does not work with
+			 * this boot option. Note down now and report later.
+			 */
+			if (mce_bios_cmci_threshold && bios_zero_thresh &&
+					(val & MCI_CTL2_CMCI_THRESHOLD_MASK))
+				bios_wrong_thresh = 1;
 		} else {
 			WARN_ON(!test_bit(i, __get_cpu_var(mce_poll_banks)));
 		}
 	}
 	raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
-	if (hdr)
-		printk(KERN_CONT "\n");
+	if (mce_bios_cmci_threshold && bios_wrong_thresh) {
+		pr_info_once(
+			"bios_cmci_threshold: Some banks do not have valid thresholds set\n");
+		pr_info_once(
+			"bios_cmci_threshold: Make sure your BIOS supports this boot option\n");
+	}
 }
 
 /*
@@ -156,7 +278,7 @@
 			continue;
 		/* Disable CMCI */
 		rdmsrl(MSR_IA32_MCx_CTL2(i), val);
-		val &= ~(MCI_CTL2_CMCI_EN|MCI_CTL2_CMCI_THRESHOLD_MASK);
+		val &= ~MCI_CTL2_CMCI_EN;
 		wrmsrl(MSR_IA32_MCx_CTL2(i), val);
 		__clear_bit(i, __get_cpu_var(mce_banks_owned));
 	}
@@ -186,7 +308,7 @@
 			continue;
 		/* Recheck banks in case CPUs don't all have the same */
 		if (cmci_supported(&banks))
-			cmci_discover(banks, 0);
+			cmci_discover(banks);
 	}
 
 	set_cpus_allowed_ptr(current, old);
@@ -200,7 +322,7 @@
 {
 	int banks;
 	if (cmci_supported(&banks))
-		cmci_discover(banks, 0);
+		cmci_discover(banks);
 }
 
 static void intel_init_cmci(void)
@@ -211,7 +333,7 @@
 		return;
 
 	mce_threshold_vector = intel_threshold_interrupt;
-	cmci_discover(banks, 1);
+	cmci_discover(banks);
 	/*
 	 * For CPU #0 this runs with still disabled APIC, but that's
 	 * ok because only the vector is set up. We still do another
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 6605a81..8b6defe 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -586,6 +586,8 @@
 
 extern struct event_constraint intel_snb_pebs_event_constraints[];
 
+extern struct event_constraint intel_ivb_pebs_event_constraints[];
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event);
 
 void intel_pmu_pebs_enable(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 7bfb5be..eebd5ff 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -209,6 +209,15 @@
 	return -EOPNOTSUPP;
 }
 
+static const struct perf_event_attr ibs_notsupp = {
+	.exclude_user	= 1,
+	.exclude_kernel	= 1,
+	.exclude_hv	= 1,
+	.exclude_idle	= 1,
+	.exclude_host	= 1,
+	.exclude_guest	= 1,
+};
+
 static int perf_ibs_init(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
@@ -229,6 +238,9 @@
 	if (event->pmu != &perf_ibs->pmu)
 		return -ENOENT;
 
+	if (perf_flags(&event->attr) & perf_flags(&ibs_notsupp))
+		return -EINVAL;
+
 	if (config & ~perf_ibs->config_mask)
 		return -EINVAL;
 
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 0d3d63a..6bca492 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -2048,7 +2048,6 @@
 	case 42: /* SandyBridge */
 	case 45: /* SandyBridge, "Romely-EP" */
 		x86_add_quirk(intel_sandybridge_quirk);
-	case 58: /* IvyBridge */
 		memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
 		       sizeof(hw_cache_event_ids));
 		memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
@@ -2073,6 +2072,29 @@
 
 		pr_cont("SandyBridge events, ");
 		break;
+	case 58: /* IvyBridge */
+		memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
+		       sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_snb();
+
+		x86_pmu.event_constraints = intel_snb_event_constraints;
+		x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
+		x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+		x86_pmu.extra_regs = intel_snb_extra_regs;
+		/* all extra regs are per-cpu when HT is on */
+		x86_pmu.er_flags |= ERF_HAS_RSP_1;
+		x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+
+		/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
+		intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+			X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
+
+		pr_cont("IvyBridge events, ");
+		break;
+
 
 	default:
 		switch (x86_pmu.version) {
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index e38d97b..826054a 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -407,6 +407,20 @@
 	EVENT_CONSTRAINT_END
 };
 
+struct event_constraint intel_ivb_pebs_event_constraints[] = {
+        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+        INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+        INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
+        INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xcd, 0x8),    /* MEM_TRANS_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+        INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+        EVENT_CONSTRAINT_END
+};
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event)
 {
 	struct event_constraint *c;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 0a55710..99d96a49 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -661,6 +661,11 @@
 	}
 }
 
+static struct uncore_event_desc snb_uncore_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
+	{ /* end: all zeroes */ },
+};
+
 static struct attribute *snb_uncore_formats_attr[] = {
 	&format_attr_event.attr,
 	&format_attr_umask.attr,
@@ -704,6 +709,7 @@
 	.constraints	= snb_uncore_cbox_constraints,
 	.ops		= &snb_uncore_msr_ops,
 	.format_group	= &snb_uncore_format_group,
+	.event_descs	= snb_uncore_events,
 };
 
 static struct intel_uncore_type *snb_msr_uncores[] = {
@@ -1944,7 +1950,7 @@
 static struct intel_uncore_box *
 uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
 {
-	static struct intel_uncore_box *box;
+	struct intel_uncore_box *box;
 
 	box = *per_cpu_ptr(pmu->box, cpu);
 	if (box)
@@ -2341,6 +2347,27 @@
 	return ret;
 }
 
+static ssize_t uncore_get_attr_cpumask(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &uncore_cpu_mask);
+
+	buf[n++] = '\n';
+	buf[n] = '\0';
+	return n;
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL);
+
+static struct attribute *uncore_pmu_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group uncore_pmu_attr_group = {
+	.attrs = uncore_pmu_attrs,
+};
+
 static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
 {
 	int ret;
@@ -2378,8 +2405,8 @@
 		free_percpu(type->pmus[i].box);
 	kfree(type->pmus);
 	type->pmus = NULL;
-	kfree(type->attr_groups[1]);
-	type->attr_groups[1] = NULL;
+	kfree(type->events_group);
+	type->events_group = NULL;
 }
 
 static void __init uncore_types_exit(struct intel_uncore_type **types)
@@ -2431,9 +2458,10 @@
 		for (j = 0; j < i; j++)
 			attrs[j] = &type->event_descs[j].attr.attr;
 
-		type->attr_groups[1] = events_group;
+		type->events_group = events_group;
 	}
 
+	type->pmu_group = &uncore_pmu_attr_group;
 	type->pmus = pmus;
 	return 0;
 fail:
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index 5b81c18..e68a455 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -369,10 +369,12 @@
 	struct intel_uncore_pmu *pmus;
 	struct intel_uncore_ops *ops;
 	struct uncore_event_desc *event_descs;
-	const struct attribute_group *attr_groups[3];
+	const struct attribute_group *attr_groups[4];
 };
 
-#define format_group attr_groups[0]
+#define pmu_group attr_groups[0]
+#define format_group attr_groups[1]
+#define events_group attr_groups[2]
 
 struct intel_uncore_ops {
 	void (*init_box)(struct intel_uncore_box *);
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 8022c66..fbd8955 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -140,10 +140,7 @@
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-	if (*pos == 0)	/* just in case, cpu 0 is not the first */
-		*pos = cpumask_first(cpu_online_mask);
-	else
-		*pos = cpumask_next(*pos - 1, cpu_online_mask);
+	*pos = cpumask_next(*pos - 1, cpu_online_mask);
 	if ((*pos) < nr_cpu_ids)
 		return &cpu_data(*pos);
 	return NULL;
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 39472dd..60c7891 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -199,12 +199,14 @@
 		goto out_chrdev;
 	}
 	cpuid_class->devnode = cpuid_devnode;
+	get_online_cpus();
 	for_each_online_cpu(i) {
 		err = cpuid_device_create(i);
 		if (err != 0)
 			goto out_class;
 	}
 	register_hotcpu_notifier(&cpuid_class_cpu_notifier);
+	put_online_cpus();
 
 	err = 0;
 	goto out;
@@ -214,6 +216,7 @@
 	for_each_online_cpu(i) {
 		cpuid_device_destroy(i);
 	}
+	put_online_cpus();
 	class_destroy(cpuid_class);
 out_chrdev:
 	__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
@@ -225,11 +228,13 @@
 {
 	int cpu = 0;
 
+	get_online_cpus();
 	for_each_online_cpu(cpu)
 		cpuid_device_destroy(cpu);
 	class_destroy(cpuid_class);
 	__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
 	unregister_hotcpu_notifier(&cpuid_class_cpu_notifier);
+	put_online_cpus();
 }
 
 module_init(cpuid_init);
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 3ae2ced..b158152 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -342,6 +342,47 @@
 	.xlate = ioapic_xlate,
 };
 
+static void dt_add_ioapic_domain(unsigned int ioapic_num,
+		struct device_node *np)
+{
+	struct irq_domain *id;
+	struct mp_ioapic_gsi *gsi_cfg;
+	int ret;
+	int num;
+
+	gsi_cfg = mp_ioapic_gsi_routing(ioapic_num);
+	num = gsi_cfg->gsi_end - gsi_cfg->gsi_base + 1;
+
+	id = irq_domain_add_linear(np, num, &ioapic_irq_domain_ops,
+			(void *)ioapic_num);
+	BUG_ON(!id);
+	if (gsi_cfg->gsi_base == 0) {
+		/*
+		 * The first NR_IRQS_LEGACY irq descs are allocated in
+		 * early_irq_init() and need just a mapping. The
+		 * remaining irqs need both. All of them are preallocated
+		 * and assigned so we can keep the 1:1 mapping which the ioapic
+		 * is having.
+		 */
+		ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
+		if (ret)
+			pr_err("Error mapping legacy IRQs: %d\n", ret);
+
+		if (num > NR_IRQS_LEGACY) {
+			ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
+					NR_IRQS_LEGACY, num - NR_IRQS_LEGACY);
+			if (ret)
+				pr_err("Error creating mapping for the "
+						"remaining IRQs: %d\n", ret);
+		}
+		irq_set_default_host(id);
+	} else {
+		ret = irq_create_strict_mappings(id, gsi_cfg->gsi_base, 0, num);
+		if (ret)
+			pr_err("Error creating IRQ mapping: %d\n", ret);
+	}
+}
+
 static void __init ioapic_add_ofnode(struct device_node *np)
 {
 	struct resource r;
@@ -356,15 +397,7 @@
 
 	for (i = 0; i < nr_ioapics; i++) {
 		if (r.start == mpc_ioapic_addr(i)) {
-			struct irq_domain *id;
-			struct mp_ioapic_gsi *gsi_cfg;
-
-			gsi_cfg = mp_ioapic_gsi_routing(i);
-
-			id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0,
-						   &ioapic_irq_domain_ops,
-						   (void*)i);
-			BUG_ON(!id);
+			dt_add_ioapic_domain(i, np);
 			return;
 		}
 	}
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 623f288..0750e3b 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -57,6 +57,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -407,7 +408,9 @@
  */
 	cmpl $__PAGE_OFFSET-3,%ebp
 	jae syscall_fault
+	ASM_STAC
 1:	movl (%ebp),%ebp
+	ASM_CLAC
 	movl %ebp,PT_EBP(%esp)
 	_ASM_EXTABLE(1b,syscall_fault)
 
@@ -488,6 +491,7 @@
 	# system call handler stub
 ENTRY(system_call)
 	RING0_INT_FRAME			# can't unwind into user space anyway
+	ASM_CLAC
 	pushl_cfi %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
@@ -670,6 +674,7 @@
 
 	RING0_INT_FRAME			# can't unwind into user space anyway
 syscall_fault:
+	ASM_CLAC
 	GET_THREAD_INFO(%ebp)
 	movl $-EFAULT,PT_EAX(%esp)
 	jmp resume_userspace
@@ -825,6 +830,7 @@
  */
 	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	ASM_CLAC
 	addl $-0x80,(%esp)	/* Adjust vector into the [-256,-1] range */
 	SAVE_ALL
 	TRACE_IRQS_OFF
@@ -841,6 +847,7 @@
 #define BUILD_INTERRUPT3(name, nr, fn)	\
 ENTRY(name)				\
 	RING0_INT_FRAME;		\
+	ASM_CLAC;			\
 	pushl_cfi $~(nr);		\
 	SAVE_ALL;			\
 	TRACE_IRQS_OFF			\
@@ -857,6 +864,7 @@
 
 ENTRY(coprocessor_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_coprocessor_error
 	jmp error_code
@@ -865,6 +873,7 @@
 
 ENTRY(simd_coprocessor_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 #ifdef CONFIG_X86_INVD_BUG
 	/* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
@@ -886,6 +895,7 @@
 
 ENTRY(device_not_available)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $-1			# mark this as an int
 	pushl_cfi $do_device_not_available
 	jmp error_code
@@ -906,6 +916,7 @@
 
 ENTRY(overflow)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_overflow
 	jmp error_code
@@ -914,6 +925,7 @@
 
 ENTRY(bounds)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_bounds
 	jmp error_code
@@ -922,6 +934,7 @@
 
 ENTRY(invalid_op)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_invalid_op
 	jmp error_code
@@ -930,6 +943,7 @@
 
 ENTRY(coprocessor_segment_overrun)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_coprocessor_segment_overrun
 	jmp error_code
@@ -938,6 +952,7 @@
 
 ENTRY(invalid_TSS)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_invalid_TSS
 	jmp error_code
 	CFI_ENDPROC
@@ -945,6 +960,7 @@
 
 ENTRY(segment_not_present)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_segment_not_present
 	jmp error_code
 	CFI_ENDPROC
@@ -952,6 +968,7 @@
 
 ENTRY(stack_segment)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_stack_segment
 	jmp error_code
 	CFI_ENDPROC
@@ -959,6 +976,7 @@
 
 ENTRY(alignment_check)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_alignment_check
 	jmp error_code
 	CFI_ENDPROC
@@ -966,6 +984,7 @@
 
 ENTRY(divide_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0			# no error code
 	pushl_cfi $do_divide_error
 	jmp error_code
@@ -975,6 +994,7 @@
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi machine_check_vector
 	jmp error_code
@@ -984,6 +1004,7 @@
 
 ENTRY(spurious_interrupt_bug)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_spurious_interrupt_bug
 	jmp error_code
@@ -1109,17 +1130,21 @@
 	pushl %eax
 	pushl %ecx
 	pushl %edx
-	movl 0xc(%esp), %eax
+	pushl $0	/* Pass NULL as regs pointer */
+	movl 4*4(%esp), %eax
 	movl 0x4(%ebp), %edx
+	leal function_trace_op, %ecx
 	subl $MCOUNT_INSN_SIZE, %eax
 
 .globl ftrace_call
 ftrace_call:
 	call ftrace_stub
 
+	addl $4,%esp	/* skip NULL pointer */
 	popl %edx
 	popl %ecx
 	popl %eax
+ftrace_ret:
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 .globl ftrace_graph_call
 ftrace_graph_call:
@@ -1131,6 +1156,71 @@
 	ret
 END(ftrace_caller)
 
+ENTRY(ftrace_regs_caller)
+	pushf	/* push flags before compare (in cs location) */
+	cmpl $0, function_trace_stop
+	jne ftrace_restore_flags
+
+	/*
+	 * i386 does not save SS and ESP when coming from kernel.
+	 * Instead, to get sp, &regs->sp is used (see ptrace.h).
+	 * Unfortunately, that means eflags must be at the same location
+	 * as the current return ip is. We move the return ip into the
+	 * ip location, and move flags into the return ip location.
+	 */
+	pushl 4(%esp)	/* save return ip into ip slot */
+
+	pushl $0	/* Load 0 into orig_ax */
+	pushl %gs
+	pushl %fs
+	pushl %es
+	pushl %ds
+	pushl %eax
+	pushl %ebp
+	pushl %edi
+	pushl %esi
+	pushl %edx
+	pushl %ecx
+	pushl %ebx
+
+	movl 13*4(%esp), %eax	/* Get the saved flags */
+	movl %eax, 14*4(%esp)	/* Move saved flags into regs->flags location */
+				/* clobbering return ip */
+	movl $__KERNEL_CS,13*4(%esp)
+
+	movl 12*4(%esp), %eax	/* Load ip (1st parameter) */
+	subl $MCOUNT_INSN_SIZE, %eax	/* Adjust ip */
+	movl 0x4(%ebp), %edx	/* Load parent ip (2nd parameter) */
+	leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
+	pushl %esp		/* Save pt_regs as 4th parameter */
+
+GLOBAL(ftrace_regs_call)
+	call ftrace_stub
+
+	addl $4, %esp		/* Skip pt_regs */
+	movl 14*4(%esp), %eax	/* Move flags back into cs */
+	movl %eax, 13*4(%esp)	/* Needed to keep addl from modifying flags */
+	movl 12*4(%esp), %eax	/* Get return ip from regs->ip */
+	movl %eax, 14*4(%esp)	/* Put return ip back for ret */
+
+	popl %ebx
+	popl %ecx
+	popl %edx
+	popl %esi
+	popl %edi
+	popl %ebp
+	popl %eax
+	popl %ds
+	popl %es
+	popl %fs
+	popl %gs
+	addl $8, %esp		/* Skip orig_ax and ip */
+	popf			/* Pop flags at end (no addl to corrupt flags) */
+	jmp ftrace_ret
+
+ftrace_restore_flags:
+	popf
+	jmp  ftrace_stub
 #else /* ! CONFIG_DYNAMIC_FTRACE */
 
 ENTRY(mcount)
@@ -1171,9 +1261,6 @@
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
-	cmpl $0, function_trace_stop
-	jne ftrace_stub
-
 	pushl %eax
 	pushl %ecx
 	pushl %edx
@@ -1207,6 +1294,7 @@
 
 ENTRY(page_fault)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_page_fault
 	ALIGN
 error_code:
@@ -1279,6 +1367,7 @@
 
 ENTRY(debug)
 	RING0_INT_FRAME
+	ASM_CLAC
 	cmpl $ia32_sysenter_target,(%esp)
 	jne debug_stack_correct
 	FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
@@ -1303,6 +1392,7 @@
  */
 ENTRY(nmi)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi %eax
 	movl %ss, %eax
 	cmpw $__ESPFIX_SS, %ax
@@ -1373,6 +1463,7 @@
 
 ENTRY(int3)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $-1			# mark this as an int
 	SAVE_ALL
 	TRACE_IRQS_OFF
@@ -1393,6 +1484,7 @@
 #ifdef CONFIG_KVM_GUEST
 ENTRY(async_page_fault)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_async_page_fault
 	jmp error_code
 	CFI_ENDPROC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 69babd8..44531ac 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -56,6 +56,8 @@
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
 #include <asm/asm.h>
+#include <asm/rcu.h>
+#include <asm/smap.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -68,25 +70,51 @@
 	.section .entry.text, "ax"
 
 #ifdef CONFIG_FUNCTION_TRACER
+
+#ifdef CC_USING_FENTRY
+# define function_hook	__fentry__
+#else
+# define function_hook	mcount
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(mcount)
+
+ENTRY(function_hook)
 	retq
-END(mcount)
+END(function_hook)
+
+/* skip is set if stack has been adjusted */
+.macro ftrace_caller_setup skip=0
+	MCOUNT_SAVE_FRAME \skip
+
+	/* Load the ftrace_ops into the 3rd parameter */
+	leaq function_trace_op, %rdx
+
+	/* Load ip into the first parameter */
+	movq RIP(%rsp), %rdi
+	subq $MCOUNT_INSN_SIZE, %rdi
+	/* Load the parent_ip into the second parameter */
+#ifdef CC_USING_FENTRY
+	movq SS+16(%rsp), %rsi
+#else
+	movq 8(%rbp), %rsi
+#endif
+.endm
 
 ENTRY(ftrace_caller)
+	/* Check if tracing was disabled (quick check) */
 	cmpl $0, function_trace_stop
 	jne  ftrace_stub
 
-	MCOUNT_SAVE_FRAME
-
-	movq 0x38(%rsp), %rdi
-	movq 8(%rbp), %rsi
-	subq $MCOUNT_INSN_SIZE, %rdi
+	ftrace_caller_setup
+	/* regs go into 4th parameter (but make it NULL) */
+	movq $0, %rcx
 
 GLOBAL(ftrace_call)
 	call ftrace_stub
 
 	MCOUNT_RESTORE_FRAME
+ftrace_return:
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 GLOBAL(ftrace_graph_call)
@@ -97,8 +125,78 @@
 	retq
 END(ftrace_caller)
 
+ENTRY(ftrace_regs_caller)
+	/* Save the current flags before compare (in SS location)*/
+	pushfq
+
+	/* Check if tracing was disabled (quick check) */
+	cmpl $0, function_trace_stop
+	jne  ftrace_restore_flags
+
+	/* skip=8 to skip flags saved in SS */
+	ftrace_caller_setup 8
+
+	/* Save the rest of pt_regs */
+	movq %r15, R15(%rsp)
+	movq %r14, R14(%rsp)
+	movq %r13, R13(%rsp)
+	movq %r12, R12(%rsp)
+	movq %r11, R11(%rsp)
+	movq %r10, R10(%rsp)
+	movq %rbp, RBP(%rsp)
+	movq %rbx, RBX(%rsp)
+	/* Copy saved flags */
+	movq SS(%rsp), %rcx
+	movq %rcx, EFLAGS(%rsp)
+	/* Kernel segments */
+	movq $__KERNEL_DS, %rcx
+	movq %rcx, SS(%rsp)
+	movq $__KERNEL_CS, %rcx
+	movq %rcx, CS(%rsp)
+	/* Stack - skipping return address */
+	leaq SS+16(%rsp), %rcx
+	movq %rcx, RSP(%rsp)
+
+	/* regs go into 4th parameter */
+	leaq (%rsp), %rcx
+
+GLOBAL(ftrace_regs_call)
+	call ftrace_stub
+
+	/* Copy flags back to SS, to restore them */
+	movq EFLAGS(%rsp), %rax
+	movq %rax, SS(%rsp)
+
+	/* Handlers can change the RIP */
+	movq RIP(%rsp), %rax
+	movq %rax, SS+8(%rsp)
+
+	/* restore the rest of pt_regs */
+	movq R15(%rsp), %r15
+	movq R14(%rsp), %r14
+	movq R13(%rsp), %r13
+	movq R12(%rsp), %r12
+	movq R10(%rsp), %r10
+	movq RBP(%rsp), %rbp
+	movq RBX(%rsp), %rbx
+
+	/* skip=8 to skip flags saved in SS */
+	MCOUNT_RESTORE_FRAME 8
+
+	/* Restore flags */
+	popfq
+
+	jmp ftrace_return
+ftrace_restore_flags:
+	popfq
+	jmp  ftrace_stub
+
+END(ftrace_regs_caller)
+
+
 #else /* ! CONFIG_DYNAMIC_FTRACE */
-ENTRY(mcount)
+
+ENTRY(function_hook)
 	cmpl $0, function_trace_stop
 	jne  ftrace_stub
 
@@ -119,8 +217,12 @@
 trace:
 	MCOUNT_SAVE_FRAME
 
-	movq 0x38(%rsp), %rdi
+	movq RIP(%rsp), %rdi
+#ifdef CC_USING_FENTRY
+	movq SS+16(%rsp), %rsi
+#else
 	movq 8(%rbp), %rsi
+#endif
 	subq $MCOUNT_INSN_SIZE, %rdi
 
 	call   *ftrace_trace_function
@@ -128,20 +230,22 @@
 	MCOUNT_RESTORE_FRAME
 
 	jmp ftrace_stub
-END(mcount)
+END(function_hook)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
-	cmpl $0, function_trace_stop
-	jne ftrace_stub
-
 	MCOUNT_SAVE_FRAME
 
+#ifdef CC_USING_FENTRY
+	leaq SS+16(%rsp), %rdi
+	movq $0, %rdx	/* No framepointers needed */
+#else
 	leaq 8(%rbp), %rdi
-	movq 0x38(%rsp), %rsi
 	movq (%rbp), %rdx
+#endif
+	movq RIP(%rsp), %rsi
 	subq $MCOUNT_INSN_SIZE, %rsi
 
 	call	prepare_ftrace_return
@@ -342,15 +446,15 @@
 	.macro SAVE_ARGS_IRQ
 	cld
 	/* start from rbp in pt_regs and jump over */
-	movq_cfi rdi, RDI-RBP
-	movq_cfi rsi, RSI-RBP
-	movq_cfi rdx, RDX-RBP
-	movq_cfi rcx, RCX-RBP
-	movq_cfi rax, RAX-RBP
-	movq_cfi  r8,  R8-RBP
-	movq_cfi  r9,  R9-RBP
-	movq_cfi r10, R10-RBP
-	movq_cfi r11, R11-RBP
+	movq_cfi rdi, (RDI-RBP)
+	movq_cfi rsi, (RSI-RBP)
+	movq_cfi rdx, (RDX-RBP)
+	movq_cfi rcx, (RCX-RBP)
+	movq_cfi rax, (RAX-RBP)
+	movq_cfi  r8,  (R8-RBP)
+	movq_cfi  r9,  (R9-RBP)
+	movq_cfi r10, (R10-RBP)
+	movq_cfi r11, (R11-RBP)
 
 	/* Save rbp so that we can unwind from get_irq_regs() */
 	movq_cfi rbp, 0
@@ -384,7 +488,7 @@
 	.endm
 
 ENTRY(save_rest)
-	PARTIAL_FRAME 1 REST_SKIP+8
+	PARTIAL_FRAME 1 (REST_SKIP+8)
 	movq 5*8+16(%rsp), %r11	/* save return address */
 	movq_cfi rbx, RBX+16
 	movq_cfi rbp, RBP+16
@@ -440,7 +544,7 @@
 
 	LOCK ; btr $TIF_FORK,TI_flags(%r8)
 
-	pushq_cfi kernel_eflags(%rip)
+	pushq_cfi $0x0002
 	popfq_cfi				# reset kernel eflags
 
 	call schedule_tail			# rdi: 'prev' task parameter
@@ -465,7 +569,8 @@
  * System call entry. Up to 6 arguments in registers are supported.
  *
  * SYSCALL does not save anything on the stack and does not change the
- * stack pointer.
+ * stack pointer.  However, it does mask the flags register for us, so
+ * CLD and CLAC are not needed.
  */
 
 /*
@@ -565,7 +670,7 @@
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call schedule
+	SCHEDULE_USER
 	popq_cfi %rdi
 	jmp sysret_check
 
@@ -678,7 +783,7 @@
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call schedule
+	SCHEDULE_USER
 	popq_cfi %rdi
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
@@ -884,6 +989,7 @@
 	 */
 	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	ASM_CLAC
 	XCPT_FRAME
 	addq $-0x80,(%rsp)		/* Adjust vector to [-256,-1] range */
 	interrupt do_IRQ
@@ -974,7 +1080,7 @@
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call  schedule
+	SCHEDULE_USER
 	popq_cfi %rdi
 	GET_THREAD_INFO(%rcx)
 	DISABLE_INTERRUPTS(CLBR_NONE)
@@ -1023,6 +1129,7 @@
  */
 .macro apicinterrupt num sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	pushq_cfi $~(\num)
 .Lcommon_\sym:
@@ -1077,6 +1184,7 @@
  */
 .macro zeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1094,6 +1202,7 @@
 
 .macro paranoidzeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1112,6 +1221,7 @@
 #define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
 .macro paranoidzeroentry_ist sym do_sym ist
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1131,6 +1241,7 @@
 
 .macro errorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
@@ -1149,6 +1260,7 @@
 	/* error code is on the stack already */
 .macro paranoiderrorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
@@ -1449,7 +1561,7 @@
 paranoid_schedule:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_ANY)
-	call schedule
+	SCHEDULE_USER
 	DISABLE_INTERRUPTS(CLBR_ANY)
 	TRACE_IRQS_OFF
 	jmp paranoid_userspace
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index c3a7cb4..1d41402 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -206,6 +206,21 @@
 ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
 		   unsigned const char *new_code);
 
+/*
+ * Should never be called:
+ *  As it is only called by __ftrace_replace_code() which is called by
+ *  ftrace_replace_code() that x86 overrides, and by ftrace_update_code()
+ *  which is called to turn mcount into nops or nops into function calls
+ *  but not to convert a function from not using regs to one that uses
+ *  regs, which ftrace_modify_call() is for.
+ */
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+				 unsigned long addr)
+{
+	WARN_ON(1);
+	return -EINVAL;
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
 	unsigned long ip = (unsigned long)(&ftrace_call);
@@ -220,6 +235,14 @@
 
 	ret = ftrace_modify_code(ip, old, new);
 
+	/* Also update the regs callback function */
+	if (!ret) {
+		ip = (unsigned long)(&ftrace_regs_call);
+		memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE);
+		new = ftrace_call_replace(ip, (unsigned long)func);
+		ret = ftrace_modify_code(ip, old, new);
+	}
+
 	atomic_dec(&modifying_ftrace_code);
 
 	return ret;
@@ -299,6 +322,32 @@
 	return add_break(rec->ip, old);
 }
 
+/*
+ * If the record has the FTRACE_FL_REGS set, that means that it
+ * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS
+ * is not not set, then it wants to convert to the normal callback.
+ */
+static unsigned long get_ftrace_addr(struct dyn_ftrace *rec)
+{
+	if (rec->flags & FTRACE_FL_REGS)
+		return (unsigned long)FTRACE_REGS_ADDR;
+	else
+		return (unsigned long)FTRACE_ADDR;
+}
+
+/*
+ * The FTRACE_FL_REGS_EN is set when the record already points to
+ * a function that saves all the regs. Basically the '_EN' version
+ * represents the current state of the function.
+ */
+static unsigned long get_ftrace_old_addr(struct dyn_ftrace *rec)
+{
+	if (rec->flags & FTRACE_FL_REGS_EN)
+		return (unsigned long)FTRACE_REGS_ADDR;
+	else
+		return (unsigned long)FTRACE_ADDR;
+}
+
 static int add_breakpoints(struct dyn_ftrace *rec, int enable)
 {
 	unsigned long ftrace_addr;
@@ -306,7 +355,7 @@
 
 	ret = ftrace_test_record(rec, enable);
 
-	ftrace_addr = (unsigned long)FTRACE_ADDR;
+	ftrace_addr = get_ftrace_addr(rec);
 
 	switch (ret) {
 	case FTRACE_UPDATE_IGNORE:
@@ -316,6 +365,10 @@
 		/* converting nop to call */
 		return add_brk_on_nop(rec);
 
+	case FTRACE_UPDATE_MODIFY_CALL_REGS:
+	case FTRACE_UPDATE_MODIFY_CALL:
+		ftrace_addr = get_ftrace_old_addr(rec);
+		/* fall through */
 	case FTRACE_UPDATE_MAKE_NOP:
 		/* converting a call to a nop */
 		return add_brk_on_call(rec, ftrace_addr);
@@ -360,13 +413,21 @@
 		 * If not, don't touch the breakpoint, we make just create
 		 * a disaster.
 		 */
-		ftrace_addr = (unsigned long)FTRACE_ADDR;
+		ftrace_addr = get_ftrace_addr(rec);
+		nop = ftrace_call_replace(ip, ftrace_addr);
+
+		if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
+			goto update;
+
+		/* Check both ftrace_addr and ftrace_old_addr */
+		ftrace_addr = get_ftrace_old_addr(rec);
 		nop = ftrace_call_replace(ip, ftrace_addr);
 
 		if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
 			return -EINVAL;
 	}
 
+ update:
 	return probe_kernel_write((void *)ip, &nop[0], 1);
 }
 
@@ -405,12 +466,14 @@
 
 	ret = ftrace_test_record(rec, enable);
 
-	ftrace_addr = (unsigned long)FTRACE_ADDR;
+	ftrace_addr  = get_ftrace_addr(rec);
 
 	switch (ret) {
 	case FTRACE_UPDATE_IGNORE:
 		return 0;
 
+	case FTRACE_UPDATE_MODIFY_CALL_REGS:
+	case FTRACE_UPDATE_MODIFY_CALL:
 	case FTRACE_UPDATE_MAKE_CALL:
 		/* converting nop to call */
 		return add_update_call(rec, ftrace_addr);
@@ -455,12 +518,14 @@
 
 	ret = ftrace_update_record(rec, enable);
 
-	ftrace_addr = (unsigned long)FTRACE_ADDR;
+	ftrace_addr = get_ftrace_addr(rec);
 
 	switch (ret) {
 	case FTRACE_UPDATE_IGNORE:
 		return 0;
 
+	case FTRACE_UPDATE_MODIFY_CALL_REGS:
+	case FTRACE_UPDATE_MODIFY_CALL:
 	case FTRACE_UPDATE_MAKE_CALL:
 		/* converting nop to call */
 		return finish_update_call(rec, ftrace_addr);
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index d42ab17..957a47a 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -287,27 +287,28 @@
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no CR4
+
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 
 	testb $X86_CR4_PAE, %al		# check if PAE is enabled
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index f250431..675a050 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -19,24 +19,17 @@
 #include <asm/fpu-internal.h>
 #include <asm/user.h>
 
-#ifdef CONFIG_X86_64
-# include <asm/sigcontext32.h>
-# include <asm/user32.h>
-#else
-# define save_i387_xstate_ia32		save_i387_xstate
-# define restore_i387_xstate_ia32	restore_i387_xstate
-# define _fpstate_ia32		_fpstate
-# define _xstate_ia32		_xstate
-# define sig_xstate_ia32_size   sig_xstate_size
-# define fx_sw_reserved_ia32	fx_sw_reserved
-# define user_i387_ia32_struct	user_i387_struct
-# define user32_fxsr_struct	user_fxsr_struct
-#endif
-
 /*
  * Were we in an interrupt that interrupted kernel mode?
  *
- * We can do a kernel_fpu_begin/end() pair *ONLY* if that
+ * For now, with eagerfpu we will return interrupted kernel FPU
+ * state as not-idle. TBD: Ideally we can change the return value
+ * to something like __thread_has_fpu(current). But we need to
+ * be careful of doing __thread_clear_has_fpu() before saving
+ * the FPU etc for supporting nested uses etc. For now, take
+ * the simple route!
+ *
+ * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
  * pair does nothing at all: the thread must not have fpu (so
  * that we don't try to save the FPU state), and TS must
  * be set (so that the clts/stts pair does nothing that is
@@ -44,6 +37,9 @@
  */
 static inline bool interrupted_kernel_fpu_idle(void)
 {
+	if (use_eager_fpu())
+		return 0;
+
 	return !__thread_has_fpu(current) &&
 		(read_cr0() & X86_CR0_TS);
 }
@@ -77,29 +73,29 @@
 }
 EXPORT_SYMBOL(irq_fpu_usable);
 
-void kernel_fpu_begin(void)
+void __kernel_fpu_begin(void)
 {
 	struct task_struct *me = current;
 
-	WARN_ON_ONCE(!irq_fpu_usable());
-	preempt_disable();
 	if (__thread_has_fpu(me)) {
 		__save_init_fpu(me);
 		__thread_clear_has_fpu(me);
-		/* We do 'stts()' in kernel_fpu_end() */
-	} else {
+		/* We do 'stts()' in __kernel_fpu_end() */
+	} else if (!use_eager_fpu()) {
 		this_cpu_write(fpu_owner_task, NULL);
 		clts();
 	}
 }
-EXPORT_SYMBOL(kernel_fpu_begin);
+EXPORT_SYMBOL(__kernel_fpu_begin);
 
-void kernel_fpu_end(void)
+void __kernel_fpu_end(void)
 {
-	stts();
-	preempt_enable();
+	if (use_eager_fpu())
+		math_state_restore();
+	else
+		stts();
 }
-EXPORT_SYMBOL(kernel_fpu_end);
+EXPORT_SYMBOL(__kernel_fpu_end);
 
 void unlazy_fpu(struct task_struct *tsk)
 {
@@ -113,23 +109,15 @@
 }
 EXPORT_SYMBOL(unlazy_fpu);
 
-#ifdef CONFIG_MATH_EMULATION
-# define HAVE_HWFP		(boot_cpu_data.hard_math)
-#else
-# define HAVE_HWFP		1
-#endif
-
-static unsigned int		mxcsr_feature_mask __read_mostly = 0xffffffffu;
+unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
-unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
 static struct i387_fxsave_struct fx_scratch __cpuinitdata;
 
 static void __cpuinit mxcsr_feature_mask_init(void)
 {
 	unsigned long mask = 0;
 
-	clts();
 	if (cpu_has_fxsr) {
 		memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
 		asm volatile("fxsave %0" : : "m" (fx_scratch));
@@ -138,7 +126,6 @@
 			mask = 0x0000ffbf;
 	}
 	mxcsr_feature_mask &= mask;
-	stts();
 }
 
 static void __cpuinit init_thread_xstate(void)
@@ -192,9 +179,8 @@
 		init_thread_xstate();
 
 	mxcsr_feature_mask_init();
-	/* clean state in init */
-	current_thread_info()->status = 0;
-	clear_used_math();
+	xsave_init();
+	eager_fpu_init();
 }
 
 void fpu_finit(struct fpu *fpu)
@@ -205,12 +191,7 @@
 	}
 
 	if (cpu_has_fxsr) {
-		struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-
-		memset(fx, 0, xstate_size);
-		fx->cwd = 0x37f;
-		if (cpu_has_xmm)
-			fx->mxcsr = MXCSR_DEFAULT;
+		fx_finit(&fpu->state->fxsave);
 	} else {
 		struct i387_fsave_struct *fp = &fpu->state->fsave;
 		memset(fp, 0, xstate_size);
@@ -454,7 +435,7 @@
  * FXSR floating point environment conversions.
  */
 
-static void
+void
 convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
 {
 	struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
@@ -491,8 +472,8 @@
 		memcpy(&to[i], &from[i], sizeof(to[0]));
 }
 
-static void convert_to_fxsr(struct task_struct *tsk,
-			    const struct user_i387_ia32_struct *env)
+void convert_to_fxsr(struct task_struct *tsk,
+		     const struct user_i387_ia32_struct *env)
 
 {
 	struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
@@ -589,223 +570,6 @@
 }
 
 /*
- * Signal frame handlers.
- */
-
-static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
-{
-	struct task_struct *tsk = current;
-	struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave;
-
-	fp->status = fp->swd;
-	if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
-		return -1;
-	return 1;
-}
-
-static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
-{
-	struct task_struct *tsk = current;
-	struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
-	struct user_i387_ia32_struct env;
-	int err = 0;
-
-	convert_from_fxsr(&env, tsk);
-	if (__copy_to_user(buf, &env, sizeof(env)))
-		return -1;
-
-	err |= __put_user(fx->swd, &buf->status);
-	err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
-	if (err)
-		return -1;
-
-	if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
-		return -1;
-	return 1;
-}
-
-static int save_i387_xsave(void __user *buf)
-{
-	struct task_struct *tsk = current;
-	struct _fpstate_ia32 __user *fx = buf;
-	int err = 0;
-
-
-	sanitize_i387_state(tsk);
-
-	/*
-	 * For legacy compatible, we always set FP/SSE bits in the bit
-	 * vector while saving the state to the user context.
-	 * This will enable us capturing any changes(during sigreturn) to
-	 * the FP/SSE bits by the legacy applications which don't touch
-	 * xstate_bv in the xsave header.
-	 *
-	 * xsave aware applications can change the xstate_bv in the xsave
-	 * header as well as change any contents in the memory layout.
-	 * xrestore as part of sigreturn will capture all the changes.
-	 */
-	tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
-
-	if (save_i387_fxsave(fx) < 0)
-		return -1;
-
-	err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
-			     sizeof(struct _fpx_sw_bytes));
-	err |= __put_user(FP_XSTATE_MAGIC2,
-			  (__u32 __user *) (buf + sig_xstate_ia32_size
-					    - FP_XSTATE_MAGIC2_SIZE));
-	if (err)
-		return -1;
-
-	return 1;
-}
-
-int save_i387_xstate_ia32(void __user *buf)
-{
-	struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
-	struct task_struct *tsk = current;
-
-	if (!used_math())
-		return 0;
-
-	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
-		return -EACCES;
-	/*
-	 * This will cause a "finit" to be triggered by the next
-	 * attempted FPU operation by the 'current' process.
-	 */
-	clear_used_math();
-
-	if (!HAVE_HWFP) {
-		return fpregs_soft_get(current, NULL,
-				       0, sizeof(struct user_i387_ia32_struct),
-				       NULL, fp) ? -1 : 1;
-	}
-
-	unlazy_fpu(tsk);
-
-	if (cpu_has_xsave)
-		return save_i387_xsave(fp);
-	if (cpu_has_fxsr)
-		return save_i387_fxsave(fp);
-	else
-		return save_i387_fsave(fp);
-}
-
-static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
-{
-	struct task_struct *tsk = current;
-
-	return __copy_from_user(&tsk->thread.fpu.state->fsave, buf,
-				sizeof(struct i387_fsave_struct));
-}
-
-static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
-			       unsigned int size)
-{
-	struct task_struct *tsk = current;
-	struct user_i387_ia32_struct env;
-	int err;
-
-	err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0],
-			       size);
-	/* mxcsr reserved bits must be masked to zero for security reasons */
-	tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
-	if (err || __copy_from_user(&env, buf, sizeof(env)))
-		return 1;
-	convert_to_fxsr(tsk, &env);
-
-	return 0;
-}
-
-static int restore_i387_xsave(void __user *buf)
-{
-	struct _fpx_sw_bytes fx_sw_user;
-	struct _fpstate_ia32 __user *fx_user =
-			((struct _fpstate_ia32 __user *) buf);
-	struct i387_fxsave_struct __user *fx =
-		(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
-	struct xsave_hdr_struct *xsave_hdr =
-				&current->thread.fpu.state->xsave.xsave_hdr;
-	u64 mask;
-	int err;
-
-	if (check_for_xstate(fx, buf, &fx_sw_user))
-		goto fx_only;
-
-	mask = fx_sw_user.xstate_bv;
-
-	err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
-
-	xsave_hdr->xstate_bv &= pcntxt_mask;
-	/*
-	 * These bits must be zero.
-	 */
-	xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
-
-	/*
-	 * Init the state that is not present in the memory layout
-	 * and enabled by the OS.
-	 */
-	mask = ~(pcntxt_mask & ~mask);
-	xsave_hdr->xstate_bv &= mask;
-
-	return err;
-fx_only:
-	/*
-	 * Couldn't find the extended state information in the memory
-	 * layout. Restore the FP/SSE and init the other extended state
-	 * enabled by the OS.
-	 */
-	xsave_hdr->xstate_bv = XSTATE_FPSSE;
-	return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
-}
-
-int restore_i387_xstate_ia32(void __user *buf)
-{
-	int err;
-	struct task_struct *tsk = current;
-	struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
-
-	if (HAVE_HWFP)
-		clear_fpu(tsk);
-
-	if (!buf) {
-		if (used_math()) {
-			clear_fpu(tsk);
-			clear_used_math();
-		}
-
-		return 0;
-	} else
-		if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
-			return -EACCES;
-
-	if (!used_math()) {
-		err = init_fpu(tsk);
-		if (err)
-			return err;
-	}
-
-	if (HAVE_HWFP) {
-		if (cpu_has_xsave)
-			err = restore_i387_xsave(buf);
-		else if (cpu_has_fxsr)
-			err = restore_i387_fxsave(fp, sizeof(struct
-							   i387_fxsave_struct));
-		else
-			err = restore_i387_fsave(fp);
-	} else {
-		err = fpregs_soft_set(current, NULL,
-				      0, sizeof(struct user_i387_ia32_struct),
-				      NULL, fp) != 0;
-	}
-	set_used_math();
-
-	return err;
-}
-
-/*
  * FPU state for core dumps.
  * This is only used for a.out dumps now.
  * It is declared generically using elf_fpregset_t (which is
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index 36d1853..9a5c460 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -263,7 +263,7 @@
 	 * out of.
 	 */
 	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
-	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-1 */
+	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
 }
 
 static struct syscore_ops i8259_syscore_ops = {
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index d44f782..e4595f1 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -92,7 +92,8 @@
 	seq_printf(p, "  Rescheduling interrupts\n");
 	seq_printf(p, "%*s: ", prec, "CAL");
 	for_each_online_cpu(j)
-		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
+		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count -
+					irq_stats(j)->irq_tlb_count);
 	seq_printf(p, "  Function call interrupts\n");
 	seq_printf(p, "%*s: ", prec, "TLB");
 	for_each_online_cpu(j)
@@ -147,7 +148,6 @@
 #ifdef CONFIG_SMP
 	sum += irq_stats(cpu)->irq_resched_count;
 	sum += irq_stats(cpu)->irq_call_count;
-	sum += irq_stats(cpu)->irq_tlb_count;
 #endif
 #ifdef CONFIG_X86_THERMAL_VECTOR
 	sum += irq_stats(cpu)->irq_thermal_count;
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index e2f751e..57916c0 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -541,6 +541,23 @@
 	return 1;
 }
 
+#ifdef KPROBES_CAN_USE_FTRACE
+static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+				      struct kprobe_ctlblk *kcb)
+{
+	/*
+	 * Emulate singlestep (and also recover regs->ip)
+	 * as if there is a 5byte nop
+	 */
+	regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
+	if (unlikely(p->post_handler)) {
+		kcb->kprobe_status = KPROBE_HIT_SSDONE;
+		p->post_handler(p, regs, 0);
+	}
+	__this_cpu_write(current_kprobe, NULL);
+}
+#endif
+
 /*
  * Interrupts are disabled on entry as trap3 is an interrupt gate and they
  * remain disabled throughout this function.
@@ -599,6 +616,12 @@
 	} else if (kprobe_running()) {
 		p = __this_cpu_read(current_kprobe);
 		if (p->break_handler && p->break_handler(p, regs)) {
+#ifdef KPROBES_CAN_USE_FTRACE
+			if (kprobe_ftrace(p)) {
+				skip_singlestep(p, regs, kcb);
+				return 1;
+			}
+#endif
 			setup_singlestep(p, regs, kcb, 0);
 			return 1;
 		}
@@ -1052,6 +1075,50 @@
 	return 0;
 }
 
+#ifdef KPROBES_CAN_USE_FTRACE
+/* Ftrace callback handler for kprobes */
+void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+				     struct ftrace_ops *ops, struct pt_regs *regs)
+{
+	struct kprobe *p;
+	struct kprobe_ctlblk *kcb;
+	unsigned long flags;
+
+	/* Disable irq for emulating a breakpoint and avoiding preempt */
+	local_irq_save(flags);
+
+	p = get_kprobe((kprobe_opcode_t *)ip);
+	if (unlikely(!p) || kprobe_disabled(p))
+		goto end;
+
+	kcb = get_kprobe_ctlblk();
+	if (kprobe_running()) {
+		kprobes_inc_nmissed_count(p);
+	} else {
+		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
+		regs->ip = ip + sizeof(kprobe_opcode_t);
+
+		__this_cpu_write(current_kprobe, p);
+		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+		if (!p->pre_handler || !p->pre_handler(p, regs))
+			skip_singlestep(p, regs, kcb);
+		/*
+		 * If pre_handler returns !0, it sets regs->ip and
+		 * resets current kprobe.
+		 */
+	}
+end:
+	local_irq_restore(flags);
+}
+
+int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+	p->ainsn.insn = NULL;
+	p->ainsn.boostable = -1;
+	return 0;
+}
+#endif
+
 int __init arch_init_kprobes(void)
 {
 	return arch_init_optprobes();
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index 82746f9..7720ff5 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -75,20 +75,113 @@
 
 static struct equiv_cpu_entry *equiv_cpu_table;
 
-/* page-sized ucode patch buffer */
-void *patch;
+struct ucode_patch {
+	struct list_head plist;
+	void *data;
+	u32 patch_id;
+	u16 equiv_cpu;
+};
+
+static LIST_HEAD(pcache);
+
+static u16 find_equiv_id(unsigned int cpu)
+{
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	int i = 0;
+
+	if (!equiv_cpu_table)
+		return 0;
+
+	while (equiv_cpu_table[i].installed_cpu != 0) {
+		if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu)
+			return equiv_cpu_table[i].equiv_cpu;
+
+		i++;
+	}
+	return 0;
+}
+
+static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu)
+{
+	int i = 0;
+
+	BUG_ON(!equiv_cpu_table);
+
+	while (equiv_cpu_table[i].equiv_cpu != 0) {
+		if (equiv_cpu == equiv_cpu_table[i].equiv_cpu)
+			return equiv_cpu_table[i].installed_cpu;
+		i++;
+	}
+	return 0;
+}
+
+/*
+ * a small, trivial cache of per-family ucode patches
+ */
+static struct ucode_patch *cache_find_patch(u16 equiv_cpu)
+{
+	struct ucode_patch *p;
+
+	list_for_each_entry(p, &pcache, plist)
+		if (p->equiv_cpu == equiv_cpu)
+			return p;
+	return NULL;
+}
+
+static void update_cache(struct ucode_patch *new_patch)
+{
+	struct ucode_patch *p;
+
+	list_for_each_entry(p, &pcache, plist) {
+		if (p->equiv_cpu == new_patch->equiv_cpu) {
+			if (p->patch_id >= new_patch->patch_id)
+				/* we already have the latest patch */
+				return;
+
+			list_replace(&p->plist, &new_patch->plist);
+			kfree(p->data);
+			kfree(p);
+			return;
+		}
+	}
+	/* no patch found, add it */
+	list_add_tail(&new_patch->plist, &pcache);
+}
+
+static void free_cache(void)
+{
+	struct ucode_patch *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp, &pcache, plist) {
+		__list_del(p->plist.prev, p->plist.next);
+		kfree(p->data);
+		kfree(p);
+	}
+}
+
+static struct ucode_patch *find_patch(unsigned int cpu)
+{
+	u16 equiv_id;
+
+	equiv_id = find_equiv_id(cpu);
+	if (!equiv_id)
+		return NULL;
+
+	return cache_find_patch(equiv_id);
+}
 
 static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
 {
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
+	csig->sig = cpuid_eax(0x00000001);
 	csig->rev = c->microcode;
 	pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
 
 	return 0;
 }
 
-static unsigned int verify_ucode_size(int cpu, u32 patch_size,
+static unsigned int verify_patch_size(int cpu, u32 patch_size,
 				      unsigned int size)
 {
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -118,95 +211,37 @@
 	return patch_size;
 }
 
-static u16 find_equiv_id(void)
-{
-	unsigned int current_cpu_id, i = 0;
-
-	BUG_ON(equiv_cpu_table == NULL);
-
-	current_cpu_id = cpuid_eax(0x00000001);
-
-	while (equiv_cpu_table[i].installed_cpu != 0) {
-		if (current_cpu_id == equiv_cpu_table[i].installed_cpu)
-			return equiv_cpu_table[i].equiv_cpu;
-
-		i++;
-	}
-	return 0;
-}
-
-/*
- * we signal a good patch is found by returning its size > 0
- */
-static int get_matching_microcode(int cpu, const u8 *ucode_ptr,
-				  unsigned int leftover_size, int rev,
-				  unsigned int *current_size)
-{
-	struct microcode_header_amd *mc_hdr;
-	unsigned int actual_size, patch_size;
-	u16 equiv_cpu_id;
-
-	/* size of the current patch we're staring at */
-	patch_size = *(u32 *)(ucode_ptr + 4);
-	*current_size = patch_size + SECTION_HDR_SIZE;
-
-	equiv_cpu_id = find_equiv_id();
-	if (!equiv_cpu_id)
-		return 0;
-
-	/*
-	 * let's look at the patch header itself now
-	 */
-	mc_hdr = (struct microcode_header_amd *)(ucode_ptr + SECTION_HDR_SIZE);
-
-	if (mc_hdr->processor_rev_id != equiv_cpu_id)
-		return 0;
-
-	/* ucode might be chipset specific -- currently we don't support this */
-	if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
-		pr_err("CPU%d: chipset specific code not yet supported\n",
-		       cpu);
-		return 0;
-	}
-
-	if (mc_hdr->patch_id <= rev)
-		return 0;
-
-	/*
-	 * now that the header looks sane, verify its size
-	 */
-	actual_size = verify_ucode_size(cpu, patch_size, leftover_size);
-	if (!actual_size)
-		return 0;
-
-	/* clear the patch buffer */
-	memset(patch, 0, PAGE_SIZE);
-
-	/* all looks ok, get the binary patch */
-	get_ucode_data(patch, ucode_ptr + SECTION_HDR_SIZE, actual_size);
-
-	return actual_size;
-}
-
 static int apply_microcode_amd(int cpu)
 {
-	u32 rev, dummy;
-	int cpu_num = raw_smp_processor_id();
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-	struct microcode_amd *mc_amd = uci->mc;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct microcode_amd *mc_amd;
+	struct ucode_cpu_info *uci;
+	struct ucode_patch *p;
+	u32 rev, dummy;
 
-	/* We should bind the task to the CPU */
-	BUG_ON(cpu_num != cpu);
+	BUG_ON(raw_smp_processor_id() != cpu);
 
-	if (mc_amd == NULL)
+	uci = ucode_cpu_info + cpu;
+
+	p = find_patch(cpu);
+	if (!p)
 		return 0;
 
-	wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
-	/* get patch id after patching */
+	mc_amd  = p->data;
+	uci->mc = p->data;
+
 	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 
-	/* check current patch id and patch's id for match */
+	/* need to apply patch? */
+	if (rev >= mc_amd->hdr.patch_id) {
+		c->microcode = rev;
+		return 0;
+	}
+
+	wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
+
+	/* verify patch application was successful */
+	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 	if (rev != mc_amd->hdr.patch_id) {
 		pr_err("CPU%d: update failed for patch_level=0x%08x\n",
 		       cpu, mc_amd->hdr.patch_id);
@@ -238,7 +273,7 @@
 		return -ENOMEM;
 	}
 
-	get_ucode_data(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size);
+	memcpy(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size);
 
 	/* add header length */
 	return size + CONTAINER_HDR_SZ;
@@ -250,61 +285,113 @@
 	equiv_cpu_table = NULL;
 }
 
-static enum ucode_state
-generic_load_microcode(int cpu, const u8 *data, size_t size)
+static void cleanup(void)
 {
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-	struct microcode_header_amd *mc_hdr = NULL;
-	unsigned int mc_size, leftover, current_size = 0;
-	int offset;
-	const u8 *ucode_ptr = data;
-	void *new_mc = NULL;
-	unsigned int new_rev = uci->cpu_sig.rev;
-	enum ucode_state state = UCODE_ERROR;
+	free_equiv_cpu_table();
+	free_cache();
+}
 
-	offset = install_equiv_cpu_table(ucode_ptr);
+/*
+ * We return the current size even if some of the checks failed so that
+ * we can skip over the next patch. If we return a negative value, we
+ * signal a grave error like a memory allocation has failed and the
+ * driver cannot continue functioning normally. In such cases, we tear
+ * down everything we've used up so far and exit.
+ */
+static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
+{
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	struct microcode_header_amd *mc_hdr;
+	struct ucode_patch *patch;
+	unsigned int patch_size, crnt_size, ret;
+	u32 proc_fam;
+	u16 proc_id;
+
+	patch_size  = *(u32 *)(fw + 4);
+	crnt_size   = patch_size + SECTION_HDR_SIZE;
+	mc_hdr	    = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
+	proc_id	    = mc_hdr->processor_rev_id;
+
+	proc_fam = find_cpu_family_by_equiv_cpu(proc_id);
+	if (!proc_fam) {
+		pr_err("No patch family for equiv ID: 0x%04x\n", proc_id);
+		return crnt_size;
+	}
+
+	/* check if patch is for the current family */
+	proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff);
+	if (proc_fam != c->x86)
+		return crnt_size;
+
+	if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
+		pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n",
+			mc_hdr->patch_id);
+		return crnt_size;
+	}
+
+	ret = verify_patch_size(cpu, patch_size, leftover);
+	if (!ret) {
+		pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id);
+		return crnt_size;
+	}
+
+	patch = kzalloc(sizeof(*patch), GFP_KERNEL);
+	if (!patch) {
+		pr_err("Patch allocation failure.\n");
+		return -EINVAL;
+	}
+
+	patch->data = kzalloc(patch_size, GFP_KERNEL);
+	if (!patch->data) {
+		pr_err("Patch data allocation failure.\n");
+		kfree(patch);
+		return -EINVAL;
+	}
+
+	/* All looks ok, copy patch... */
+	memcpy(patch->data, fw + SECTION_HDR_SIZE, patch_size);
+	INIT_LIST_HEAD(&patch->plist);
+	patch->patch_id  = mc_hdr->patch_id;
+	patch->equiv_cpu = proc_id;
+
+	/* ... and add to cache. */
+	update_cache(patch);
+
+	return crnt_size;
+}
+
+static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
+{
+	enum ucode_state ret = UCODE_ERROR;
+	unsigned int leftover;
+	u8 *fw = (u8 *)data;
+	int crnt_size = 0;
+	int offset;
+
+	offset = install_equiv_cpu_table(data);
 	if (offset < 0) {
 		pr_err("failed to create equivalent cpu table\n");
-		goto out;
+		return ret;
 	}
-	ucode_ptr += offset;
+	fw += offset;
 	leftover = size - offset;
 
-	if (*(u32 *)ucode_ptr != UCODE_UCODE_TYPE) {
+	if (*(u32 *)fw != UCODE_UCODE_TYPE) {
 		pr_err("invalid type field in container file section header\n");
-		goto free_table;
+		free_equiv_cpu_table();
+		return ret;
 	}
 
 	while (leftover) {
-		mc_size = get_matching_microcode(cpu, ucode_ptr, leftover,
-						 new_rev, &current_size);
-		if (mc_size) {
-			mc_hdr  = patch;
-			new_mc  = patch;
-			new_rev = mc_hdr->patch_id;
-			goto out_ok;
-		}
+		crnt_size = verify_and_add_patch(cpu, fw, leftover);
+		if (crnt_size < 0)
+			return ret;
 
-		ucode_ptr += current_size;
-		leftover  -= current_size;
+		fw	 += crnt_size;
+		leftover -= crnt_size;
 	}
 
-	if (!new_mc) {
-		state = UCODE_NFOUND;
-		goto free_table;
-	}
-
-out_ok:
-	uci->mc = new_mc;
-	state = UCODE_OK;
-	pr_debug("CPU%d update ucode (0x%08x -> 0x%08x)\n",
-		 cpu, uci->cpu_sig.rev, new_rev);
-
-free_table:
-	free_equiv_cpu_table();
-
-out:
-	return state;
+	return UCODE_OK;
 }
 
 /*
@@ -315,7 +402,7 @@
  *
  * This legacy file is always smaller than 2K in size.
  *
- * Starting at family 15h they are in family specific firmware files:
+ * Beginning with family 15h, they are in family-specific firmware files:
  *
  *    amd-ucode/microcode_amd_fam15h.bin
  *    amd-ucode/microcode_amd_fam16h.bin
@@ -323,12 +410,17 @@
  *
  * These might be larger than 2K.
  */
-static enum ucode_state request_microcode_amd(int cpu, struct device *device)
+static enum ucode_state request_microcode_amd(int cpu, struct device *device,
+					      bool refresh_fw)
 {
 	char fw_name[36] = "amd-ucode/microcode_amd.bin";
-	const struct firmware *fw;
-	enum ucode_state ret = UCODE_NFOUND;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	enum ucode_state ret = UCODE_NFOUND;
+	const struct firmware *fw;
+
+	/* reload ucode container only on the boot cpu */
+	if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
+		return UCODE_OK;
 
 	if (c->x86 >= 0x15)
 		snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
@@ -344,12 +436,17 @@
 		goto fw_release;
 	}
 
-	ret = generic_load_microcode(cpu, fw->data, fw->size);
+	/* free old equiv table */
+	free_equiv_cpu_table();
 
-fw_release:
+	ret = load_microcode_amd(cpu, fw->data, fw->size);
+	if (ret != UCODE_OK)
+		cleanup();
+
+ fw_release:
 	release_firmware(fw);
 
-out:
+ out:
 	return ret;
 }
 
@@ -383,14 +480,10 @@
 		return NULL;
 	}
 
-	patch = (void *)get_zeroed_page(GFP_KERNEL);
-	if (!patch)
-		return NULL;
-
 	return &microcode_amd_ops;
 }
 
 void __exit exit_amd_microcode(void)
 {
-	free_page((unsigned long)patch);
+	cleanup();
 }
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 9e5bcf1..3a04b22 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -279,19 +279,18 @@
 static int reload_for_cpu(int cpu)
 {
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+	enum ucode_state ustate;
 	int err = 0;
 
-	if (uci->valid) {
-		enum ucode_state ustate;
+	if (!uci->valid)
+		return err;
 
-		ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev);
-		if (ustate == UCODE_OK)
-			apply_microcode_on_target(cpu);
-		else
-			if (ustate == UCODE_ERROR)
-				err = -EINVAL;
-	}
-
+	ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, true);
+	if (ustate == UCODE_OK)
+		apply_microcode_on_target(cpu);
+	else
+		if (ustate == UCODE_ERROR)
+			err = -EINVAL;
 	return err;
 }
 
@@ -373,18 +372,15 @@
 
 static enum ucode_state microcode_resume_cpu(int cpu)
 {
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-	if (!uci->mc)
-		return UCODE_NFOUND;
-
 	pr_debug("CPU%d updated upon resume\n", cpu);
-	apply_microcode_on_target(cpu);
+
+	if (apply_microcode_on_target(cpu))
+		return UCODE_ERROR;
 
 	return UCODE_OK;
 }
 
-static enum ucode_state microcode_init_cpu(int cpu)
+static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
 {
 	enum ucode_state ustate;
 
@@ -395,7 +391,8 @@
 	if (system_state != SYSTEM_RUNNING)
 		return UCODE_NFOUND;
 
-	ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev);
+	ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev,
+						     refresh_fw);
 
 	if (ustate == UCODE_OK) {
 		pr_debug("CPU%d updated upon init\n", cpu);
@@ -408,14 +405,11 @@
 static enum ucode_state microcode_update_cpu(int cpu)
 {
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-	enum ucode_state ustate;
 
 	if (uci->valid)
-		ustate = microcode_resume_cpu(cpu);
-	else
-		ustate = microcode_init_cpu(cpu);
+		return microcode_resume_cpu(cpu);
 
-	return ustate;
+	return microcode_init_cpu(cpu, false);
 }
 
 static int mc_device_add(struct device *dev, struct subsys_interface *sif)
@@ -431,7 +425,7 @@
 	if (err)
 		return err;
 
-	if (microcode_init_cpu(cpu) == UCODE_ERROR)
+	if (microcode_init_cpu(cpu, true) == UCODE_ERROR)
 		return -EINVAL;
 
 	return err;
@@ -480,34 +474,41 @@
 	struct device *dev;
 
 	dev = get_cpu_device(cpu);
-	switch (action) {
+
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
 		microcode_update_cpu(cpu);
-	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
 		pr_debug("CPU%d added\n", cpu);
+		/*
+		 * "break" is missing on purpose here because we want to fall
+		 * through in order to create the sysfs group.
+		 */
+
+	case CPU_DOWN_FAILED:
 		if (sysfs_create_group(&dev->kobj, &mc_attr_group))
 			pr_err("Failed to create group for CPU%d\n", cpu);
 		break;
+
 	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
 		/* Suspend is in progress, only remove the interface */
 		sysfs_remove_group(&dev->kobj, &mc_attr_group);
 		pr_debug("CPU%d removed\n", cpu);
 		break;
 
 	/*
+	 * case CPU_DEAD:
+	 *
 	 * When a CPU goes offline, don't free up or invalidate the copy of
 	 * the microcode in kernel memory, so that we can reuse it when the
 	 * CPU comes back online without unnecessarily requesting the userspace
 	 * for it again.
 	 */
-	case CPU_UP_CANCELED_FROZEN:
-		/* The CPU refused to come up during a system resume */
-		microcode_fini_cpu(cpu);
-		break;
 	}
+
+	/* The CPU refused to come up during a system resume */
+	if (action == CPU_UP_CANCELED_FROZEN)
+		microcode_fini_cpu(cpu);
+
 	return NOTIFY_OK;
 }
 
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 0327e2b..3544aed 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -405,7 +405,8 @@
 	return 0;
 }
 
-static enum ucode_state request_microcode_fw(int cpu, struct device *device)
+static enum ucode_state request_microcode_fw(int cpu, struct device *device,
+					     bool refresh_fw)
 {
 	char name[30];
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index eb11369..a7c5661 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -257,12 +257,14 @@
 		goto out_chrdev;
 	}
 	msr_class->devnode = msr_devnode;
+	get_online_cpus();
 	for_each_online_cpu(i) {
 		err = msr_device_create(i);
 		if (err != 0)
 			goto out_class;
 	}
 	register_hotcpu_notifier(&msr_class_cpu_notifier);
+	put_online_cpus();
 
 	err = 0;
 	goto out;
@@ -271,6 +273,7 @@
 	i = 0;
 	for_each_online_cpu(i)
 		msr_device_destroy(i);
+	put_online_cpus();
 	class_destroy(msr_class);
 out_chrdev:
 	__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
@@ -281,11 +284,13 @@
 static void __exit msr_exit(void)
 {
 	int cpu = 0;
+	get_online_cpus();
 	for_each_online_cpu(cpu)
 		msr_device_destroy(cpu);
 	class_destroy(msr_class);
 	__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
 	unregister_hotcpu_notifier(&msr_class_cpu_notifier);
+	put_online_cpus();
 }
 
 module_init(msr_init);
diff --git a/arch/x86/kernel/perf_regs.c b/arch/x86/kernel/perf_regs.c
new file mode 100644
index 0000000..e309cc5
--- /dev/null
+++ b/arch/x86/kernel/perf_regs.c
@@ -0,0 +1,105 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <linux/stddef.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+#ifdef CONFIG_X86_32
+#define PERF_REG_X86_MAX PERF_REG_X86_32_MAX
+#else
+#define PERF_REG_X86_MAX PERF_REG_X86_64_MAX
+#endif
+
+#define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
+
+static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
+	PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
+	PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
+	PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
+	PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
+	PT_REGS_OFFSET(PERF_REG_X86_SI, si),
+	PT_REGS_OFFSET(PERF_REG_X86_DI, di),
+	PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
+	PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
+	PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
+	PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
+	PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
+	PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
+#ifdef CONFIG_X86_32
+	PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
+	PT_REGS_OFFSET(PERF_REG_X86_ES, es),
+	PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
+	PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
+#else
+	/*
+	 * The pt_regs struct does not store
+	 * ds, es, fs, gs in 64 bit mode.
+	 */
+	(unsigned int) -1,
+	(unsigned int) -1,
+	(unsigned int) -1,
+	(unsigned int) -1,
+#endif
+#ifdef CONFIG_X86_64
+	PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
+	PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
+	PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
+	PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
+	PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
+	PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
+	PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
+	PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
+#endif
+};
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
+		return 0;
+
+	return regs_get_register(regs, pt_regs_offset[idx]);
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_X86_MAX) - 1ULL))
+
+#ifdef CONFIG_X86_32
+int perf_reg_validate(u64 mask)
+{
+	if (!mask || mask & REG_RESERVED)
+		return -EINVAL;
+
+	return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+	return PERF_SAMPLE_REGS_ABI_32;
+}
+#else /* CONFIG_X86_64 */
+#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
+		       (1ULL << PERF_REG_X86_ES) | \
+		       (1ULL << PERF_REG_X86_FS) | \
+		       (1ULL << PERF_REG_X86_GS))
+
+int perf_reg_validate(u64 mask)
+{
+	if (!mask || mask & REG_RESERVED)
+		return -EINVAL;
+
+	if (mask & REG_NOSUPPORT)
+		return -EINVAL;
+
+	return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+	if (test_tsk_thread_flag(task, TIF_IA32))
+		return PERF_SAMPLE_REGS_ABI_32;
+	else
+		return PERF_SAMPLE_REGS_ABI_64;
+}
+#endif /* CONFIG_X86_32 */
diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c
index 0bc72e2..d5f15c3f 100644
--- a/arch/x86/kernel/probe_roms.c
+++ b/arch/x86/kernel/probe_roms.c
@@ -150,7 +150,7 @@
 	return oprom;
 }
 
-void *pci_map_biosrom(struct pci_dev *pdev)
+void __iomem *pci_map_biosrom(struct pci_dev *pdev)
 {
 	struct resource *oprom = find_oprom(pdev);
 
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index ef6a845..dc3567e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -66,15 +66,13 @@
 {
 	int ret;
 
-	unlazy_fpu(src);
-
 	*dst = *src;
 	if (fpu_allocated(&src->thread.fpu)) {
 		memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
 		ret = fpu_alloc(&dst->thread.fpu);
 		if (ret)
 			return ret;
-		fpu_copy(&dst->thread.fpu, &src->thread.fpu);
+		fpu_copy(dst, src);
 	}
 	return 0;
 }
@@ -97,16 +95,6 @@
 				  SLAB_PANIC | SLAB_NOTRACK, NULL);
 }
 
-static inline void drop_fpu(struct task_struct *tsk)
-{
-	/*
-	 * Forget coprocessor state..
-	 */
-	tsk->fpu_counter = 0;
-	clear_fpu(tsk);
-	clear_used_math();
-}
-
 /*
  * Free current thread data structures etc..
  */
@@ -163,7 +151,13 @@
 
 	flush_ptrace_hw_breakpoint(tsk);
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
-	drop_fpu(tsk);
+	drop_init_fpu(tsk);
+	/*
+	 * Free the FPU state for non xsave platforms. They get reallocated
+	 * lazily at the first use.
+	 */
+	if (!use_eager_fpu())
+		free_thread_xstate(tsk);
 }
 
 static void hard_disable_TSC(void)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 516fa18..b9ff83c 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -190,10 +190,6 @@
 	regs->cs		= __USER_CS;
 	regs->ip		= new_ip;
 	regs->sp		= new_sp;
-	/*
-	 * Free the old FP and other extended state
-	 */
-	free_thread_xstate(current);
 }
 EXPORT_SYMBOL_GPL(start_thread);
 
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 0a980c9..8a6d20c 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -232,10 +232,6 @@
 	regs->cs		= _cs;
 	regs->ss		= _ss;
 	regs->flags		= X86_EFLAGS_IF;
-	/*
-	 * Free the old FP and other extended state
-	 */
-	free_thread_xstate(current);
 }
 
 void
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index c4c6a5c..b00b33a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -21,6 +21,7 @@
 #include <linux/signal.h>
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -1332,9 +1333,6 @@
 #define genregs32_get		genregs_get
 #define genregs32_set		genregs_set
 
-#define user_i387_ia32_struct	user_i387_struct
-#define user32_fxsr_struct	user_fxsr_struct
-
 #endif	/* CONFIG_X86_64 */
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@ -1463,6 +1461,8 @@
 {
 	long ret = 0;
 
+	rcu_user_exit();
+
 	/*
 	 * If we stepped into a sysenter/syscall insn, it trapped in
 	 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
@@ -1526,4 +1526,6 @@
 			!test_thread_flag(TIF_SYSCALL_EMU);
 	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
 		tracehook_report_syscall_exit(regs, step);
+
+	rcu_user_enter();
 }
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f4b9b80..4f16547 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -961,9 +961,7 @@
 	kvmclock_init();
 #endif
 
-	x86_init.paging.pagetable_setup_start(swapper_pg_dir);
-	paging_init();
-	x86_init.paging.pagetable_setup_done(swapper_pg_dir);
+	x86_init.paging.pagetable_init();
 
 	if (boot_cpu_data.cpuid_level >= 0) {
 		/* A CPU has %cr4 if and only if it has CPUID */
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index b280908..b33144c 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -114,11 +114,12 @@
 		regs->orig_ax = -1;		/* disable syscall checks */
 
 		get_user_ex(buf, &sc->fpstate);
-		err |= restore_i387_xstate(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
+
 	return err;
 }
 
@@ -206,35 +207,32 @@
 	     void __user **fpstate)
 {
 	/* Default to using normal stack */
+	unsigned long math_size = 0;
 	unsigned long sp = regs->sp;
+	unsigned long buf_fx = 0;
 	int onsigstack = on_sig_stack(sp);
 
-#ifdef CONFIG_X86_64
 	/* redzone */
-	sp -= 128;
-#endif /* CONFIG_X86_64 */
+	if (config_enabled(CONFIG_X86_64))
+		sp -= 128;
 
 	if (!onsigstack) {
 		/* This is the X/Open sanctioned signal stack switching.  */
 		if (ka->sa.sa_flags & SA_ONSTACK) {
 			if (current->sas_ss_size)
 				sp = current->sas_ss_sp + current->sas_ss_size;
-		} else {
-#ifdef CONFIG_X86_32
-			/* This is the legacy signal stack switching. */
-			if ((regs->ss & 0xffff) != __USER_DS &&
-				!(ka->sa.sa_flags & SA_RESTORER) &&
-					ka->sa.sa_restorer)
+		} else if (config_enabled(CONFIG_X86_32) &&
+			   (regs->ss & 0xffff) != __USER_DS &&
+			   !(ka->sa.sa_flags & SA_RESTORER) &&
+			   ka->sa.sa_restorer) {
+				/* This is the legacy signal stack switching. */
 				sp = (unsigned long) ka->sa.sa_restorer;
-#endif /* CONFIG_X86_32 */
 		}
 	}
 
 	if (used_math()) {
-		sp -= sig_xstate_size;
-#ifdef CONFIG_X86_64
-		sp = round_down(sp, 64);
-#endif /* CONFIG_X86_64 */
+		sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
+				     &buf_fx, &math_size);
 		*fpstate = (void __user *)sp;
 	}
 
@@ -247,8 +245,9 @@
 	if (onsigstack && !likely(on_sig_stack(sp)))
 		return (void __user *)-1L;
 
-	/* save i387 state */
-	if (used_math() && save_i387_xstate(*fpstate) < 0)
+	/* save i387 and extended state */
+	if (used_math() &&
+	    save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)
 		return (void __user *)-1L;
 
 	return (void __user *)sp;
@@ -357,7 +356,6 @@
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(&frame->info, &frame->pinfo);
 		put_user_ex(&frame->uc, &frame->puc);
-		err |= copy_siginfo_to_user(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -369,9 +367,6 @@
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  */
 		restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -388,6 +383,11 @@
 		 */
 		put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
 	} put_user_catch(err);
+	
+	err |= copy_siginfo_to_user(&frame->info, info);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	if (err)
 		return -EFAULT;
@@ -436,8 +436,6 @@
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  If provided, use a stub
 		   already in userspace.  */
@@ -450,6 +448,9 @@
 		}
 	} put_user_catch(err);
 
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
@@ -474,6 +475,75 @@
 }
 #endif /* CONFIG_X86_32 */
 
+static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
+			      siginfo_t *info, compat_sigset_t *set,
+			      struct pt_regs *regs)
+{
+#ifdef CONFIG_X86_X32_ABI
+	struct rt_sigframe_x32 __user *frame;
+	void __user *restorer;
+	int err = 0;
+	void __user *fpstate = NULL;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return -EFAULT;
+
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		if (copy_siginfo_to_user32(&frame->info, info))
+			return -EFAULT;
+	}
+
+	put_user_try {
+		/* Create the ucontext.  */
+		if (cpu_has_xsave)
+			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
+		else
+			put_user_ex(0, &frame->uc.uc_flags);
+		put_user_ex(0, &frame->uc.uc_link);
+		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+		put_user_ex(sas_ss_flags(regs->sp),
+			    &frame->uc.uc_stack.ss_flags);
+		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+		put_user_ex(0, &frame->uc.uc__pad0);
+
+		if (ka->sa.sa_flags & SA_RESTORER) {
+			restorer = ka->sa.sa_restorer;
+		} else {
+			/* could use a vstub here */
+			restorer = NULL;
+			err |= -EFAULT;
+		}
+		put_user_ex(restorer, &frame->pretcode);
+	} put_user_catch(err);
+
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		return -EFAULT;
+
+	/* Set up registers for signal handler */
+	regs->sp = (unsigned long) frame;
+	regs->ip = (unsigned long) ka->sa.sa_handler;
+
+	/* We use the x32 calling convention here... */
+	regs->di = sig;
+	regs->si = (unsigned long) &frame->info;
+	regs->dx = (unsigned long) &frame->uc;
+
+	loadsegment(ds, __USER_DS);
+	loadsegment(es, __USER_DS);
+
+	regs->cs = __USER_CS;
+	regs->ss = __USER_DS;
+#endif	/* CONFIG_X86_X32_ABI */
+
+	return 0;
+}
+
 #ifdef CONFIG_X86_32
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
@@ -612,55 +682,22 @@
 	return sig;
 }
 
-#ifdef CONFIG_X86_32
-
-#define is_ia32	1
-#define ia32_setup_frame	__setup_frame
-#define ia32_setup_rt_frame	__setup_rt_frame
-
-#else /* !CONFIG_X86_32 */
-
-#ifdef CONFIG_IA32_EMULATION
-#define is_ia32	test_thread_flag(TIF_IA32)
-#else /* !CONFIG_IA32_EMULATION */
-#define is_ia32	0
-#endif /* CONFIG_IA32_EMULATION */
-
-#ifdef CONFIG_X86_X32_ABI
-#define is_x32	test_thread_flag(TIF_X32)
-
-static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
-			      siginfo_t *info, compat_sigset_t *set,
-			      struct pt_regs *regs);
-#else /* !CONFIG_X86_X32_ABI */
-#define is_x32	0
-#endif /* CONFIG_X86_X32_ABI */
-
-int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-		sigset_t *set, struct pt_regs *regs);
-int ia32_setup_frame(int sig, struct k_sigaction *ka,
-		sigset_t *set, struct pt_regs *regs);
-
-#endif /* CONFIG_X86_32 */
-
 static int
 setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		struct pt_regs *regs)
 {
 	int usig = signr_convert(sig);
 	sigset_t *set = sigmask_to_save();
+	compat_sigset_t *cset = (compat_sigset_t *) set;
 
 	/* Set up the stack frame */
-	if (is_ia32) {
+	if (is_ia32_frame()) {
 		if (ka->sa.sa_flags & SA_SIGINFO)
-			return ia32_setup_rt_frame(usig, ka, info, set, regs);
+			return ia32_setup_rt_frame(usig, ka, info, cset, regs);
 		else
-			return ia32_setup_frame(usig, ka, set, regs);
-#ifdef CONFIG_X86_X32_ABI
-	} else if (is_x32) {
-		return x32_setup_rt_frame(usig, ka, info,
-					 (compat_sigset_t *)set, regs);
-#endif
+			return ia32_setup_frame(usig, ka, cset, regs);
+	} else if (is_x32_frame()) {
+		return x32_setup_rt_frame(usig, ka, info, cset, regs);
 	} else {
 		return __setup_rt_frame(sig, ka, info, set, regs);
 	}
@@ -779,6 +816,8 @@
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+	rcu_user_exit();
+
 #ifdef CONFIG_X86_MCE
 	/* notify userspace of pending MCEs */
 	if (thread_info_flags & _TIF_MCE_NOTIFY)
@@ -804,6 +843,8 @@
 #ifdef CONFIG_X86_32
 	clear_thread_flag(TIF_IRET);
 #endif /* CONFIG_X86_32 */
+
+	rcu_user_enter();
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
@@ -824,72 +865,6 @@
 }
 
 #ifdef CONFIG_X86_X32_ABI
-static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
-			      siginfo_t *info, compat_sigset_t *set,
-			      struct pt_regs *regs)
-{
-	struct rt_sigframe_x32 __user *frame;
-	void __user *restorer;
-	int err = 0;
-	void __user *fpstate = NULL;
-
-	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
-
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		return -EFAULT;
-
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		if (copy_siginfo_to_user32(&frame->info, info))
-			return -EFAULT;
-	}
-
-	put_user_try {
-		/* Create the ucontext.  */
-		if (cpu_has_xsave)
-			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
-		else
-			put_user_ex(0, &frame->uc.uc_flags);
-		put_user_ex(0, &frame->uc.uc_link);
-		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-		put_user_ex(sas_ss_flags(regs->sp),
-			    &frame->uc.uc_stack.ss_flags);
-		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		put_user_ex(0, &frame->uc.uc__pad0);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-
-		if (ka->sa.sa_flags & SA_RESTORER) {
-			restorer = ka->sa.sa_restorer;
-		} else {
-			/* could use a vstub here */
-			restorer = NULL;
-			err |= -EFAULT;
-		}
-		put_user_ex(restorer, &frame->pretcode);
-	} put_user_catch(err);
-
-	if (err)
-		return -EFAULT;
-
-	/* Set up registers for signal handler */
-	regs->sp = (unsigned long) frame;
-	regs->ip = (unsigned long) ka->sa.sa_handler;
-
-	/* We use the x32 calling convention here... */
-	regs->di = sig;
-	regs->si = (unsigned long) &frame->info;
-	regs->dx = (unsigned long) &frame->uc;
-
-	loadsegment(ds, __USER_DS);
-	loadsegment(es, __USER_DS);
-
-	regs->cs = __USER_CS;
-	regs->ss = __USER_DS;
-
-	return 0;
-}
-
 asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
 {
 	struct rt_sigframe_x32 __user *frame;
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 7c5a8c3..c80a33b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -665,7 +665,8 @@
 	unsigned long boot_error = 0;
 	int timeout;
 
-	alternatives_smp_switch(1);
+	/* Just in case we booted with a single CPU. */
+	alternatives_enable_smp();
 
 	idle->thread.sp = (unsigned long) (((struct pt_regs *)
 			  (THREAD_SIZE +  task_stack_page(idle))) - 1);
@@ -1053,20 +1054,6 @@
 	preempt_enable();
 }
 
-void arch_disable_nonboot_cpus_begin(void)
-{
-	/*
-	 * Avoid the smp alternatives switch during the disable_nonboot_cpus().
-	 * In the suspend path, we will be back in the SMP mode shortly anyways.
-	 */
-	skip_smp_alternatives = true;
-}
-
-void arch_disable_nonboot_cpus_end(void)
-{
-	skip_smp_alternatives = false;
-}
-
 void arch_enable_nonboot_cpus_begin(void)
 {
 	set_mtrr_aps_delayed_init();
@@ -1256,9 +1243,6 @@
 		if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
 			if (system_state == SYSTEM_RUNNING)
 				pr_info("CPU %u is now offline\n", cpu);
-
-			if (1 == num_online_cpus())
-				alternatives_smp_switch(0);
 			return;
 		}
 		msleep(100);
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index c346d11..cd3b243 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -157,6 +157,33 @@
 	return 1;
 }
 
+void set_task_blockstep(struct task_struct *task, bool on)
+{
+	unsigned long debugctl;
+
+	/*
+	 * Ensure irq/preemption can't change debugctl in between.
+	 * Note also that both TIF_BLOCKSTEP and debugctl should
+	 * be changed atomically wrt preemption.
+	 * FIXME: this means that set/clear TIF_BLOCKSTEP is simply
+	 * wrong if task != current, SIGKILL can wakeup the stopped
+	 * tracee and set/clear can play with the running task, this
+	 * can confuse the next __switch_to_xtra().
+	 */
+	local_irq_disable();
+	debugctl = get_debugctlmsr();
+	if (on) {
+		debugctl |= DEBUGCTLMSR_BTF;
+		set_tsk_thread_flag(task, TIF_BLOCKSTEP);
+	} else {
+		debugctl &= ~DEBUGCTLMSR_BTF;
+		clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
+	}
+	if (task == current)
+		update_debugctlmsr(debugctl);
+	local_irq_enable();
+}
+
 /*
  * Enable single or block step.
  */
@@ -169,19 +196,10 @@
 	 * So no one should try to use debugger block stepping in a program
 	 * that uses user-mode single stepping itself.
 	 */
-	if (enable_single_step(child) && block) {
-		unsigned long debugctl = get_debugctlmsr();
-
-		debugctl |= DEBUGCTLMSR_BTF;
-		update_debugctlmsr(debugctl);
-		set_tsk_thread_flag(child, TIF_BLOCKSTEP);
-	} else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
-		unsigned long debugctl = get_debugctlmsr();
-
-		debugctl &= ~DEBUGCTLMSR_BTF;
-		update_debugctlmsr(debugctl);
-		clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
-	}
+	if (enable_single_step(child) && block)
+		set_task_blockstep(child, true);
+	else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
+		set_task_blockstep(child, false);
 }
 
 void user_enable_single_step(struct task_struct *child)
@@ -199,13 +217,8 @@
 	/*
 	 * Make sure block stepping (BTF) is disabled.
 	 */
-	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
-		unsigned long debugctl = get_debugctlmsr();
-
-		debugctl &= ~DEBUGCTLMSR_BTF;
-		update_debugctlmsr(debugctl);
-		clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
-	}
+	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
+		set_task_blockstep(child, false);
 
 	/* Always clear TIF_SINGLESTEP... */
 	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index b481341..8276dc6 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -55,6 +55,7 @@
 #include <asm/i387.h>
 #include <asm/fpu-internal.h>
 #include <asm/mce.h>
+#include <asm/rcu.h>
 
 #include <asm/mach_traps.h>
 
@@ -107,30 +108,45 @@
 	dec_preempt_count();
 }
 
+static int __kprobes
+do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
+		  struct pt_regs *regs,	long error_code)
+{
+#ifdef CONFIG_X86_32
+	if (regs->flags & X86_VM_MASK) {
+		/*
+		 * Traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+		 * On nmi (interrupt 2), do_trap should not be called.
+		 */
+		if (trapnr < X86_TRAP_UD) {
+			if (!handle_vm86_trap((struct kernel_vm86_regs *) regs,
+						error_code, trapnr))
+				return 0;
+		}
+		return -1;
+	}
+#endif
+	if (!user_mode(regs)) {
+		if (!fixup_exception(regs)) {
+			tsk->thread.error_code = error_code;
+			tsk->thread.trap_nr = trapnr;
+			die(str, regs, error_code);
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
 static void __kprobes
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 	long error_code, siginfo_t *info)
 {
 	struct task_struct *tsk = current;
 
-#ifdef CONFIG_X86_32
-	if (regs->flags & X86_VM_MASK) {
-		/*
-		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
-		 * On nmi (interrupt 2), do_trap should not be called.
-		 */
-		if (trapnr < X86_TRAP_UD)
-			goto vm86_trap;
-		goto trap_signal;
-	}
-#endif
 
-	if (!user_mode(regs))
-		goto kernel_trap;
-
-#ifdef CONFIG_X86_32
-trap_signal:
-#endif
+	if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
+		return;
 	/*
 	 * We want error_code and trap_nr set for userspace faults and
 	 * kernelspace faults which result in die(), but not
@@ -158,33 +174,20 @@
 		force_sig_info(signr, info, tsk);
 	else
 		force_sig(signr, tsk);
-	return;
-
-kernel_trap:
-	if (!fixup_exception(regs)) {
-		tsk->thread.error_code = error_code;
-		tsk->thread.trap_nr = trapnr;
-		die(str, regs, error_code);
-	}
-	return;
-
-#ifdef CONFIG_X86_32
-vm86_trap:
-	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
-						error_code, trapnr))
-		goto trap_signal;
-	return;
-#endif
 }
 
 #define DO_ERROR(trapnr, signr, str, name)				\
 dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
 {									\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
+	exception_enter(regs);						\
+	if (notify_die(DIE_TRAP, str, regs, error_code,			\
+			trapnr, signr) == NOTIFY_STOP) {		\
+		exception_exit(regs);					\
 		return;							\
+	}								\
 	conditional_sti(regs);						\
 	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
+	exception_exit(regs);						\
 }
 
 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
@@ -195,11 +198,15 @@
 	info.si_errno = 0;						\
 	info.si_code = sicode;						\
 	info.si_addr = (void __user *)siaddr;				\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
+	exception_enter(regs);						\
+	if (notify_die(DIE_TRAP, str, regs, error_code,			\
+			trapnr, signr) == NOTIFY_STOP) {		\
+		exception_exit(regs);					\
 		return;							\
+	}								\
 	conditional_sti(regs);						\
 	do_trap(trapnr, signr, str, regs, error_code, &info);		\
+	exception_exit(regs);						\
 }
 
 DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -222,12 +229,14 @@
 /* Runs on IST stack */
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
 {
+	exception_enter(regs);
 	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-			X86_TRAP_SS, SIGBUS) == NOTIFY_STOP)
-		return;
-	preempt_conditional_sti(regs);
-	do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
-	preempt_conditional_cli(regs);
+		       X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
+		preempt_conditional_sti(regs);
+		do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
+		preempt_conditional_cli(regs);
+	}
+	exception_exit(regs);
 }
 
 dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -235,6 +244,7 @@
 	static const char str[] = "double fault";
 	struct task_struct *tsk = current;
 
+	exception_enter(regs);
 	/* Return not checked because double check cannot be ignored */
 	notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
 
@@ -255,16 +265,29 @@
 {
 	struct task_struct *tsk;
 
+	exception_enter(regs);
 	conditional_sti(regs);
 
 #ifdef CONFIG_X86_32
-	if (regs->flags & X86_VM_MASK)
-		goto gp_in_vm86;
+	if (regs->flags & X86_VM_MASK) {
+		local_irq_enable();
+		handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+		goto exit;
+	}
 #endif
 
 	tsk = current;
-	if (!user_mode(regs))
-		goto gp_in_kernel;
+	if (!user_mode(regs)) {
+		if (fixup_exception(regs))
+			goto exit;
+
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_nr = X86_TRAP_GP;
+		if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
+			       X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
+			die("general protection fault", regs, error_code);
+		goto exit;
+	}
 
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_nr = X86_TRAP_GP;
@@ -279,25 +302,8 @@
 	}
 
 	force_sig(SIGSEGV, tsk);
-	return;
-
-#ifdef CONFIG_X86_32
-gp_in_vm86:
-	local_irq_enable();
-	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
-	return;
-#endif
-
-gp_in_kernel:
-	if (fixup_exception(regs))
-		return;
-
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_nr = X86_TRAP_GP;
-	if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
-			X86_TRAP_GP, SIGSEGV) == NOTIFY_STOP)
-		return;
-	die("general protection fault", regs, error_code);
+exit:
+	exception_exit(regs);
 }
 
 /* May run on IST stack. */
@@ -312,15 +318,16 @@
 	    ftrace_int3_handler(regs))
 		return;
 #endif
+	exception_enter(regs);
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
 	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
 				SIGTRAP) == NOTIFY_STOP)
-		return;
+		goto exit;
 #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
 
 	if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
 			SIGTRAP) == NOTIFY_STOP)
-		return;
+		goto exit;
 
 	/*
 	 * Let others (NMI) know that the debug stack is in use
@@ -331,6 +338,8 @@
 	do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
 	debug_stack_usage_dec();
+exit:
+	exception_exit(regs);
 }
 
 #ifdef CONFIG_X86_64
@@ -391,6 +400,8 @@
 	unsigned long dr6;
 	int si_code;
 
+	exception_enter(regs);
+
 	get_debugreg(dr6, 6);
 
 	/* Filter out all the reserved bits which are preset to 1 */
@@ -406,7 +417,7 @@
 
 	/* Catch kmemcheck conditions first of all! */
 	if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
-		return;
+		goto exit;
 
 	/* DR6 may or may not be cleared by the CPU */
 	set_debugreg(0, 6);
@@ -421,7 +432,7 @@
 
 	if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
 							SIGTRAP) == NOTIFY_STOP)
-		return;
+		goto exit;
 
 	/*
 	 * Let others (NMI) know that the debug stack is in use
@@ -437,7 +448,7 @@
 					X86_TRAP_DB);
 		preempt_conditional_cli(regs);
 		debug_stack_usage_dec();
-		return;
+		goto exit;
 	}
 
 	/*
@@ -458,7 +469,8 @@
 	preempt_conditional_cli(regs);
 	debug_stack_usage_dec();
 
-	return;
+exit:
+	exception_exit(regs);
 }
 
 /*
@@ -555,14 +567,17 @@
 #ifdef CONFIG_X86_32
 	ignore_fpu_irq = 1;
 #endif
-
+	exception_enter(regs);
 	math_error(regs, error_code, X86_TRAP_MF);
+	exception_exit(regs);
 }
 
 dotraplinkage void
 do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
+	exception_enter(regs);
 	math_error(regs, error_code, X86_TRAP_XF);
+	exception_exit(regs);
 }
 
 dotraplinkage void
@@ -613,11 +628,12 @@
 	}
 
 	__thread_fpu_begin(tsk);
+
 	/*
 	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
 	 */
 	if (unlikely(restore_fpu_checking(tsk))) {
-		__thread_fpu_end(tsk);
+		drop_init_fpu(tsk);
 		force_sig(SIGSEGV, tsk);
 		return;
 	}
@@ -629,6 +645,9 @@
 dotraplinkage void __kprobes
 do_device_not_available(struct pt_regs *regs, long error_code)
 {
+	exception_enter(regs);
+	BUG_ON(use_eager_fpu());
+
 #ifdef CONFIG_MATH_EMULATION
 	if (read_cr0() & X86_CR0_EM) {
 		struct math_emu_info info = { };
@@ -637,6 +656,7 @@
 
 		info.regs = regs;
 		math_emulate(&info);
+		exception_exit(regs);
 		return;
 	}
 #endif
@@ -644,12 +664,15 @@
 #ifdef CONFIG_X86_32
 	conditional_sti(regs);
 #endif
+	exception_exit(regs);
 }
 
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
 {
 	siginfo_t info;
+
+	exception_enter(regs);
 	local_irq_enable();
 
 	info.si_signo = SIGILL;
@@ -657,10 +680,11 @@
 	info.si_code = ILL_BADSTK;
 	info.si_addr = NULL;
 	if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
-			X86_TRAP_IRET, SIGILL) == NOTIFY_STOP)
-		return;
-	do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
-		&info);
+			X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
+		do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
+			&info);
+	}
+	exception_exit(regs);
 }
 #endif
 
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 36fd420..9538f00 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -41,6 +41,9 @@
 /* Adjust the return address of a call insn */
 #define UPROBE_FIX_CALL	0x2
 
+/* Instruction will modify TF, don't change it */
+#define UPROBE_FIX_SETF	0x4
+
 #define UPROBE_FIX_RIP_AX	0x8000
 #define UPROBE_FIX_RIP_CX	0x4000
 
@@ -239,6 +242,10 @@
 	insn_get_opcode(insn);	/* should be a nop */
 
 	switch (OPCODE1(insn)) {
+	case 0x9d:
+		/* popf */
+		auprobe->fixups |= UPROBE_FIX_SETF;
+		break;
 	case 0xc3:		/* ret/lret */
 	case 0xcb:
 	case 0xc2:
@@ -646,7 +653,7 @@
  * Skip these instructions as per the currently known x86 ISA.
  * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 }
  */
-bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 {
 	int i;
 
@@ -673,3 +680,46 @@
 	}
 	return false;
 }
+
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	bool ret = __skip_sstep(auprobe, regs);
+	if (ret && (regs->flags & X86_EFLAGS_TF))
+		send_sig(SIGTRAP, current, 0);
+	return ret;
+}
+
+void arch_uprobe_enable_step(struct arch_uprobe *auprobe)
+{
+	struct task_struct *task = current;
+	struct arch_uprobe_task	*autask	= &task->utask->autask;
+	struct pt_regs *regs = task_pt_regs(task);
+
+	autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);
+
+	regs->flags |= X86_EFLAGS_TF;
+	if (test_tsk_thread_flag(task, TIF_BLOCKSTEP))
+		set_task_blockstep(task, false);
+}
+
+void arch_uprobe_disable_step(struct arch_uprobe *auprobe)
+{
+	struct task_struct *task = current;
+	struct arch_uprobe_task	*autask	= &task->utask->autask;
+	bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED);
+	struct pt_regs *regs = task_pt_regs(task);
+	/*
+	 * The state of TIF_BLOCKSTEP was not saved so we can get an extra
+	 * SIGTRAP if we do not clear TF. We need to examine the opcode to
+	 * make it right.
+	 */
+	if (unlikely(trapped)) {
+		if (!autask->saved_tf)
+			regs->flags &= ~X86_EFLAGS_TF;
+	} else {
+		if (autask->saved_tf)
+			send_sig(SIGTRAP, task, 0);
+		else if (!(auprobe->fixups & UPROBE_FIX_SETF))
+			regs->flags &= ~X86_EFLAGS_TF;
+	}
+}
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 6020f6f..1330dd1 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -13,9 +13,13 @@
 #include <asm/ftrace.h>
 
 #ifdef CONFIG_FUNCTION_TRACER
-/* mcount is defined in assembly */
+/* mcount and __fentry__ are defined in assembly */
+#ifdef CC_USING_FENTRY
+EXPORT_SYMBOL(__fentry__);
+#else
 EXPORT_SYMBOL(mcount);
 #endif
+#endif
 
 EXPORT_SYMBOL(__get_user_1);
 EXPORT_SYMBOL(__get_user_2);
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 9f3167e..7a3d075 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -26,7 +26,6 @@
 
 void __cpuinit x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
-void __init x86_init_pgd_noop(pgd_t *unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
 
@@ -68,8 +67,7 @@
 	},
 
 	.paging = {
-		.pagetable_setup_start	= native_pagetable_setup_start,
-		.pagetable_setup_done	= native_pagetable_setup_done,
+		.pagetable_init		= native_pagetable_init,
 	},
 
 	.timers = {
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 3d3e207..ada87a3 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -10,9 +10,7 @@
 #include <linux/compat.h>
 #include <asm/i387.h>
 #include <asm/fpu-internal.h>
-#ifdef CONFIG_IA32_EMULATION
-#include <asm/sigcontext32.h>
-#endif
+#include <asm/sigframe.h>
 #include <asm/xcr.h>
 
 /*
@@ -23,13 +21,9 @@
 /*
  * Represents init state for the supported extended state.
  */
-static struct xsave_struct *init_xstate_buf;
+struct xsave_struct *init_xstate_buf;
 
-struct _fpx_sw_bytes fx_sw_reserved;
-#ifdef CONFIG_IA32_EMULATION
-struct _fpx_sw_bytes fx_sw_reserved_ia32;
-#endif
-
+static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
 static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
 
 /*
@@ -44,9 +38,9 @@
  */
 void __sanitize_i387_state(struct task_struct *tsk)
 {
-	u64 xstate_bv;
-	int feature_bit = 0x2;
 	struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
+	int feature_bit = 0x2;
+	u64 xstate_bv;
 
 	if (!fx)
 		return;
@@ -104,213 +98,326 @@
  * Check for the presence of extended state information in the
  * user fpstate pointer in the sigcontext.
  */
-int check_for_xstate(struct i387_fxsave_struct __user *buf,
-		     void __user *fpstate,
-		     struct _fpx_sw_bytes *fx_sw_user)
+static inline int check_for_xstate(struct i387_fxsave_struct __user *buf,
+				   void __user *fpstate,
+				   struct _fpx_sw_bytes *fx_sw)
 {
 	int min_xstate_size = sizeof(struct i387_fxsave_struct) +
 			      sizeof(struct xsave_hdr_struct);
 	unsigned int magic2;
-	int err;
 
-	err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
-			       sizeof(struct _fpx_sw_bytes));
-	if (err)
-		return -EFAULT;
+	if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
+		return -1;
 
-	/*
-	 * First Magic check failed.
-	 */
-	if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
-		return -EINVAL;
+	/* Check for the first magic field and other error scenarios. */
+	if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
+	    fx_sw->xstate_size < min_xstate_size ||
+	    fx_sw->xstate_size > xstate_size ||
+	    fx_sw->xstate_size > fx_sw->extended_size)
+		return -1;
 
 	/*
-	 * Check for error scenarios.
-	 */
-	if (fx_sw_user->xstate_size < min_xstate_size ||
-	    fx_sw_user->xstate_size > xstate_size ||
-	    fx_sw_user->xstate_size > fx_sw_user->extended_size)
-		return -EINVAL;
-
-	err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
-					    fx_sw_user->extended_size -
-					    FP_XSTATE_MAGIC2_SIZE));
-	if (err)
-		return err;
-	/*
 	 * Check for the presence of second magic word at the end of memory
 	 * layout. This detects the case where the user just copied the legacy
 	 * fpstate layout with out copying the extended state information
 	 * in the memory layout.
 	 */
-	if (magic2 != FP_XSTATE_MAGIC2)
-		return -EFAULT;
+	if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
+	    || magic2 != FP_XSTATE_MAGIC2)
+		return -1;
 
 	return 0;
 }
 
-#ifdef CONFIG_X86_64
 /*
  * Signal frame handlers.
  */
-
-int save_i387_xstate(void __user *buf)
+static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
 {
-	struct task_struct *tsk = current;
-	int err = 0;
+	if (use_fxsr()) {
+		struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+		struct user_i387_ia32_struct env;
+		struct _fpstate_ia32 __user *fp = buf;
 
-	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
-		return -EACCES;
+		convert_from_fxsr(&env, tsk);
 
-	BUG_ON(sig_xstate_size < xstate_size);
-
-	if ((unsigned long)buf % 64)
-		pr_err("%s: bad fpstate %p\n", __func__, buf);
-
-	if (!used_math())
-		return 0;
-
-	if (user_has_fpu()) {
-		if (use_xsave())
-			err = xsave_user(buf);
-		else
-			err = fxsave_user(buf);
-
-		if (err)
-			return err;
-		user_fpu_end();
+		if (__copy_to_user(buf, &env, sizeof(env)) ||
+		    __put_user(xsave->i387.swd, &fp->status) ||
+		    __put_user(X86_FXSR_MAGIC, &fp->magic))
+			return -1;
 	} else {
-		sanitize_i387_state(tsk);
-		if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave,
-				   xstate_size))
+		struct i387_fsave_struct __user *fp = buf;
+		u32 swd;
+		if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
 			return -1;
 	}
 
-	clear_used_math(); /* trigger finit */
-
-	if (use_xsave()) {
-		struct _fpstate __user *fx = buf;
-		struct _xstate __user *x = buf;
-		u64 xstate_bv;
-
-		err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
-				     sizeof(struct _fpx_sw_bytes));
-
-		err |= __put_user(FP_XSTATE_MAGIC2,
-				  (__u32 __user *) (buf + sig_xstate_size
-						    - FP_XSTATE_MAGIC2_SIZE));
-
-		/*
-		 * Read the xstate_bv which we copied (directly from the cpu or
-		 * from the state in task struct) to the user buffers and
-		 * set the FP/SSE bits.
-		 */
-		err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
-
-		/*
-		 * For legacy compatible, we always set FP/SSE bits in the bit
-		 * vector while saving the state to the user context. This will
-		 * enable us capturing any changes(during sigreturn) to
-		 * the FP/SSE bits by the legacy applications which don't touch
-		 * xstate_bv in the xsave header.
-		 *
-		 * xsave aware apps can change the xstate_bv in the xsave
-		 * header as well as change any contents in the memory layout.
-		 * xrestore as part of sigreturn will capture all the changes.
-		 */
-		xstate_bv |= XSTATE_FPSSE;
-
-		err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
-
-		if (err)
-			return err;
-	}
-
-	return 1;
+	return 0;
 }
 
-/*
- * Restore the extended state if present. Otherwise, restore the FP/SSE
- * state.
- */
-static int restore_user_xstate(void __user *buf)
+static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
 {
-	struct _fpx_sw_bytes fx_sw_user;
-	u64 mask;
+	struct xsave_struct __user *x = buf;
+	struct _fpx_sw_bytes *sw_bytes;
+	u32 xstate_bv;
 	int err;
 
-	if (((unsigned long)buf % 64) ||
-	     check_for_xstate(buf, buf, &fx_sw_user))
-		goto fx_only;
+	/* Setup the bytes not touched by the [f]xsave and reserved for SW. */
+	sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
+	err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
 
-	mask = fx_sw_user.xstate_bv;
-
-	/*
-	 * restore the state passed by the user.
-	 */
-	err = xrestore_user(buf, mask);
-	if (err)
+	if (!use_xsave())
 		return err;
 
-	/*
-	 * init the state skipped by the user.
-	 */
-	mask = pcntxt_mask & ~mask;
-	if (unlikely(mask))
-		xrstor_state(init_xstate_buf, mask);
+	err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
 
-	return 0;
-
-fx_only:
 	/*
-	 * couldn't find the extended state information in the
-	 * memory layout. Restore just the FP/SSE and init all
-	 * the other extended state.
+	 * Read the xstate_bv which we copied (directly from the cpu or
+	 * from the state in task struct) to the user buffers.
 	 */
-	xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
-	return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
+	err |= __get_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
+
+	/*
+	 * For legacy compatible, we always set FP/SSE bits in the bit
+	 * vector while saving the state to the user context. This will
+	 * enable us capturing any changes(during sigreturn) to
+	 * the FP/SSE bits by the legacy applications which don't touch
+	 * xstate_bv in the xsave header.
+	 *
+	 * xsave aware apps can change the xstate_bv in the xsave
+	 * header as well as change any contents in the memory layout.
+	 * xrestore as part of sigreturn will capture all the changes.
+	 */
+	xstate_bv |= XSTATE_FPSSE;
+
+	err |= __put_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
+
+	return err;
+}
+
+static inline int save_user_xstate(struct xsave_struct __user *buf)
+{
+	int err;
+
+	if (use_xsave())
+		err = xsave_user(buf);
+	else if (use_fxsr())
+		err = fxsave_user((struct i387_fxsave_struct __user *) buf);
+	else
+		err = fsave_user((struct i387_fsave_struct __user *) buf);
+
+	if (unlikely(err) && __clear_user(buf, xstate_size))
+		err = -EFAULT;
+	return err;
 }
 
 /*
- * This restores directly out of user space. Exceptions are handled.
+ * Save the fpu, extended register state to the user signal frame.
+ *
+ * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
+ *  state is copied.
+ *  'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
+ *
+ *	buf == buf_fx for 64-bit frames and 32-bit fsave frame.
+ *	buf != buf_fx for 32-bit frames with fxstate.
+ *
+ * If the fpu, extended register state is live, save the state directly
+ * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
+ * copy the thread's fpu state to the user frame starting at 'buf_fx'.
+ *
+ * If this is a 32-bit frame with fxstate, put a fsave header before
+ * the aligned state at 'buf_fx'.
+ *
+ * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
+ * indicating the absence/presence of the extended state to the user.
  */
-int restore_i387_xstate(void __user *buf)
+int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
 {
+	struct xsave_struct *xsave = &current->thread.fpu.state->xsave;
 	struct task_struct *tsk = current;
-	int err = 0;
+	int ia32_fxstate = (buf != buf_fx);
+
+	ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
+			 config_enabled(CONFIG_IA32_EMULATION));
+
+	if (!access_ok(VERIFY_WRITE, buf, size))
+		return -EACCES;
+
+	if (!HAVE_HWFP)
+		return fpregs_soft_get(current, NULL, 0,
+			sizeof(struct user_i387_ia32_struct), NULL,
+			(struct _fpstate_ia32 __user *) buf) ? -1 : 1;
+
+	if (user_has_fpu()) {
+		/* Save the live register state to the user directly. */
+		if (save_user_xstate(buf_fx))
+			return -1;
+		/* Update the thread's fxstate to save the fsave header. */
+		if (ia32_fxstate)
+			fpu_fxsave(&tsk->thread.fpu);
+	} else {
+		sanitize_i387_state(tsk);
+		if (__copy_to_user(buf_fx, xsave, xstate_size))
+			return -1;
+	}
+
+	/* Save the fsave header for the 32-bit frames. */
+	if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
+		return -1;
+
+	if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
+		return -1;
+
+	drop_init_fpu(tsk);	/* trigger finit */
+
+	return 0;
+}
+
+static inline void
+sanitize_restored_xstate(struct task_struct *tsk,
+			 struct user_i387_ia32_struct *ia32_env,
+			 u64 xstate_bv, int fx_only)
+{
+	struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+	struct xsave_hdr_struct *xsave_hdr = &xsave->xsave_hdr;
+
+	if (use_xsave()) {
+		/* These bits must be zero. */
+		xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
+
+		/*
+		 * Init the state that is not present in the memory
+		 * layout and not enabled by the OS.
+		 */
+		if (fx_only)
+			xsave_hdr->xstate_bv = XSTATE_FPSSE;
+		else
+			xsave_hdr->xstate_bv &= (pcntxt_mask & xstate_bv);
+	}
+
+	if (use_fxsr()) {
+		/*
+		 * mscsr reserved bits must be masked to zero for security
+		 * reasons.
+		 */
+		xsave->i387.mxcsr &= mxcsr_feature_mask;
+
+		convert_to_fxsr(tsk, ia32_env);
+	}
+}
+
+/*
+ * Restore the extended state if present. Otherwise, restore the FP/SSE state.
+ */
+static inline int restore_user_xstate(void __user *buf, u64 xbv, int fx_only)
+{
+	if (use_xsave()) {
+		if ((unsigned long)buf % 64 || fx_only) {
+			u64 init_bv = pcntxt_mask & ~XSTATE_FPSSE;
+			xrstor_state(init_xstate_buf, init_bv);
+			return fxrstor_user(buf);
+		} else {
+			u64 init_bv = pcntxt_mask & ~xbv;
+			if (unlikely(init_bv))
+				xrstor_state(init_xstate_buf, init_bv);
+			return xrestore_user(buf, xbv);
+		}
+	} else if (use_fxsr()) {
+		return fxrstor_user(buf);
+	} else
+		return frstor_user(buf);
+}
+
+int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
+{
+	int ia32_fxstate = (buf != buf_fx);
+	struct task_struct *tsk = current;
+	int state_size = xstate_size;
+	u64 xstate_bv = 0;
+	int fx_only = 0;
+
+	ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
+			 config_enabled(CONFIG_IA32_EMULATION));
 
 	if (!buf) {
-		if (used_math())
-			goto clear;
+		drop_init_fpu(tsk);
 		return 0;
-	} else
-		if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
-			return -EACCES;
-
-	if (!used_math()) {
-		err = init_fpu(tsk);
-		if (err)
-			return err;
 	}
 
-	user_fpu_begin();
-	if (use_xsave())
-		err = restore_user_xstate(buf);
-	else
-		err = fxrstor_checking((__force struct i387_fxsave_struct *)
-				       buf);
-	if (unlikely(err)) {
+	if (!access_ok(VERIFY_READ, buf, size))
+		return -EACCES;
+
+	if (!used_math() && init_fpu(tsk))
+		return -1;
+
+	if (!HAVE_HWFP) {
+		return fpregs_soft_set(current, NULL,
+				       0, sizeof(struct user_i387_ia32_struct),
+				       NULL, buf) != 0;
+	}
+
+	if (use_xsave()) {
+		struct _fpx_sw_bytes fx_sw_user;
+		if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
+			/*
+			 * Couldn't find the extended state information in the
+			 * memory layout. Restore just the FP/SSE and init all
+			 * the other extended state.
+			 */
+			state_size = sizeof(struct i387_fxsave_struct);
+			fx_only = 1;
+		} else {
+			state_size = fx_sw_user.xstate_size;
+			xstate_bv = fx_sw_user.xstate_bv;
+		}
+	}
+
+	if (ia32_fxstate) {
 		/*
-		 * Encountered an error while doing the restore from the
-		 * user buffer, clear the fpu state.
+		 * For 32-bit frames with fxstate, copy the user state to the
+		 * thread's fpu state, reconstruct fxstate from the fsave
+		 * header. Sanitize the copied state etc.
 		 */
-clear:
-		clear_fpu(tsk);
-		clear_used_math();
+		struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+		struct user_i387_ia32_struct env;
+		int err = 0;
+
+		/*
+		 * Drop the current fpu which clears used_math(). This ensures
+		 * that any context-switch during the copy of the new state,
+		 * avoids the intermediate state from getting restored/saved.
+		 * Thus avoiding the new restored state from getting corrupted.
+		 * We will be ready to restore/save the state only after
+		 * set_used_math() is again set.
+		 */
+		drop_fpu(tsk);
+
+		if (__copy_from_user(xsave, buf_fx, state_size) ||
+		    __copy_from_user(&env, buf, sizeof(env))) {
+			err = -1;
+		} else {
+			sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
+			set_used_math();
+		}
+
+		if (use_eager_fpu())
+			math_state_restore();
+
+		return err;
+	} else {
+		/*
+		 * For 64-bit frames and 32-bit fsave frames, restore the user
+		 * state to the registers directly (with exceptions handled).
+		 */
+		user_fpu_begin();
+		if (restore_user_xstate(buf_fx, xstate_bv, fx_only)) {
+			drop_init_fpu(tsk);
+			return -1;
+		}
 	}
-	return err;
+
+	return 0;
 }
-#endif
 
 /*
  * Prepare the SW reserved portion of the fxsave memory layout, indicating
@@ -321,31 +428,22 @@
  */
 static void prepare_fx_sw_frame(void)
 {
-	int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
-			     FP_XSTATE_MAGIC2_SIZE;
+	int fsave_header_size = sizeof(struct i387_fsave_struct);
+	int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
 
-	sig_xstate_size = sizeof(struct _fpstate) + size_extended;
-
-#ifdef CONFIG_IA32_EMULATION
-	sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
-#endif
-
-	memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
+	if (config_enabled(CONFIG_X86_32))
+		size += fsave_header_size;
 
 	fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
-	fx_sw_reserved.extended_size = sig_xstate_size;
+	fx_sw_reserved.extended_size = size;
 	fx_sw_reserved.xstate_bv = pcntxt_mask;
 	fx_sw_reserved.xstate_size = xstate_size;
-#ifdef CONFIG_IA32_EMULATION
-	memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
-	       sizeof(struct _fpx_sw_bytes));
-	fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
-#endif
-}
 
-#ifdef CONFIG_X86_64
-unsigned int sig_xstate_size = sizeof(struct _fpstate);
-#endif
+	if (config_enabled(CONFIG_IA32_EMULATION)) {
+		fx_sw_reserved_ia32 = fx_sw_reserved;
+		fx_sw_reserved_ia32.extended_size += fsave_header_size;
+	}
+}
 
 /*
  * Enable the extended processor state save/restore feature
@@ -384,19 +482,21 @@
 /*
  * setup the xstate image representing the init state
  */
-static void __init setup_xstate_init(void)
+static void __init setup_init_fpu_buf(void)
 {
-	setup_xstate_features();
-
 	/*
 	 * Setup init_xstate_buf to represent the init state of
 	 * all the features managed by the xsave
 	 */
 	init_xstate_buf = alloc_bootmem_align(xstate_size,
 					      __alignof__(struct xsave_struct));
-	init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
+	fx_finit(&init_xstate_buf->i387);
 
-	clts();
+	if (!cpu_has_xsave)
+		return;
+
+	setup_xstate_features();
+
 	/*
 	 * Init all the features state with header_bv being 0x0
 	 */
@@ -406,9 +506,21 @@
 	 * of any feature which is not represented by all zero's.
 	 */
 	xsave_state(init_xstate_buf, -1);
-	stts();
 }
 
+static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
+static int __init eager_fpu_setup(char *s)
+{
+	if (!strcmp(s, "on"))
+		eagerfpu = ENABLE;
+	else if (!strcmp(s, "off"))
+		eagerfpu = DISABLE;
+	else if (!strcmp(s, "auto"))
+		eagerfpu = AUTO;
+	return 1;
+}
+__setup("eagerfpu=", eager_fpu_setup);
+
 /*
  * Enable and initialize the xsave feature.
  */
@@ -445,8 +557,11 @@
 
 	update_regset_xstate_info(xstate_size, pcntxt_mask);
 	prepare_fx_sw_frame();
+	setup_init_fpu_buf();
 
-	setup_xstate_init();
+	/* Auto enable eagerfpu for xsaveopt */
+	if (cpu_has_xsaveopt && eagerfpu != DISABLE)
+		eagerfpu = ENABLE;
 
 	pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
 		pcntxt_mask, xstate_size);
@@ -471,3 +586,43 @@
 	next_func = xstate_enable;
 	this_func();
 }
+
+static inline void __init eager_fpu_init_bp(void)
+{
+	current->thread.fpu.state =
+	    alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
+	if (!init_xstate_buf)
+		setup_init_fpu_buf();
+}
+
+void __cpuinit eager_fpu_init(void)
+{
+	static __refdata void (*boot_func)(void) = eager_fpu_init_bp;
+
+	clear_used_math();
+	current_thread_info()->status = 0;
+
+	if (eagerfpu == ENABLE)
+		setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
+
+	if (!cpu_has_eager_fpu) {
+		stts();
+		return;
+	}
+
+	if (boot_func) {
+		boot_func();
+		boot_func = NULL;
+	}
+
+	/*
+	 * This is same as math_state_restore(). But use_xsave() is
+	 * not yet patched to use math_state_restore().
+	 */
+	init_fpu(current);
+	__thread_fpu_begin(current);
+	if (cpu_has_xsave)
+		xrstor_state(init_xstate_buf, -1);
+	else
+		fxrstor_checking(&init_xstate_buf->i387);
+}
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index a71faf7..bca63f0 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -183,95 +183,6 @@
 #define KVM_ISA_VMX   1
 #define KVM_ISA_SVM   2
 
-#define VMX_EXIT_REASONS \
-	{ EXIT_REASON_EXCEPTION_NMI,		"EXCEPTION_NMI" }, \
-	{ EXIT_REASON_EXTERNAL_INTERRUPT,	"EXTERNAL_INTERRUPT" }, \
-	{ EXIT_REASON_TRIPLE_FAULT,		"TRIPLE_FAULT" }, \
-	{ EXIT_REASON_PENDING_INTERRUPT,	"PENDING_INTERRUPT" }, \
-	{ EXIT_REASON_NMI_WINDOW,		"NMI_WINDOW" }, \
-	{ EXIT_REASON_TASK_SWITCH,		"TASK_SWITCH" }, \
-	{ EXIT_REASON_CPUID,			"CPUID" }, \
-	{ EXIT_REASON_HLT,			"HLT" }, \
-	{ EXIT_REASON_INVLPG,			"INVLPG" }, \
-	{ EXIT_REASON_RDPMC,			"RDPMC" }, \
-	{ EXIT_REASON_RDTSC,			"RDTSC" }, \
-	{ EXIT_REASON_VMCALL,			"VMCALL" }, \
-	{ EXIT_REASON_VMCLEAR,			"VMCLEAR" }, \
-	{ EXIT_REASON_VMLAUNCH,			"VMLAUNCH" }, \
-	{ EXIT_REASON_VMPTRLD,			"VMPTRLD" }, \
-	{ EXIT_REASON_VMPTRST,			"VMPTRST" }, \
-	{ EXIT_REASON_VMREAD,			"VMREAD" }, \
-	{ EXIT_REASON_VMRESUME,			"VMRESUME" }, \
-	{ EXIT_REASON_VMWRITE,			"VMWRITE" }, \
-	{ EXIT_REASON_VMOFF,			"VMOFF" }, \
-	{ EXIT_REASON_VMON,			"VMON" }, \
-	{ EXIT_REASON_CR_ACCESS,		"CR_ACCESS" }, \
-	{ EXIT_REASON_DR_ACCESS,		"DR_ACCESS" }, \
-	{ EXIT_REASON_IO_INSTRUCTION,		"IO_INSTRUCTION" }, \
-	{ EXIT_REASON_MSR_READ,			"MSR_READ" }, \
-	{ EXIT_REASON_MSR_WRITE,		"MSR_WRITE" }, \
-	{ EXIT_REASON_MWAIT_INSTRUCTION,	"MWAIT_INSTRUCTION" }, \
-	{ EXIT_REASON_MONITOR_INSTRUCTION,	"MONITOR_INSTRUCTION" }, \
-	{ EXIT_REASON_PAUSE_INSTRUCTION,	"PAUSE_INSTRUCTION" }, \
-	{ EXIT_REASON_MCE_DURING_VMENTRY,	"MCE_DURING_VMENTRY" }, \
-	{ EXIT_REASON_TPR_BELOW_THRESHOLD,	"TPR_BELOW_THRESHOLD" },	\
-	{ EXIT_REASON_APIC_ACCESS,		"APIC_ACCESS" }, \
-	{ EXIT_REASON_EPT_VIOLATION,		"EPT_VIOLATION" }, \
-	{ EXIT_REASON_EPT_MISCONFIG,		"EPT_MISCONFIG" }, \
-	{ EXIT_REASON_WBINVD,			"WBINVD" }
-
-#define SVM_EXIT_REASONS \
-	{ SVM_EXIT_READ_CR0,			"read_cr0" }, \
-	{ SVM_EXIT_READ_CR3,			"read_cr3" }, \
-	{ SVM_EXIT_READ_CR4,			"read_cr4" }, \
-	{ SVM_EXIT_READ_CR8,			"read_cr8" }, \
-	{ SVM_EXIT_WRITE_CR0,			"write_cr0" }, \
-	{ SVM_EXIT_WRITE_CR3,			"write_cr3" }, \
-	{ SVM_EXIT_WRITE_CR4,			"write_cr4" }, \
-	{ SVM_EXIT_WRITE_CR8,			"write_cr8" }, \
-	{ SVM_EXIT_READ_DR0,			"read_dr0" }, \
-	{ SVM_EXIT_READ_DR1,			"read_dr1" }, \
-	{ SVM_EXIT_READ_DR2,			"read_dr2" }, \
-	{ SVM_EXIT_READ_DR3,			"read_dr3" }, \
-	{ SVM_EXIT_WRITE_DR0,			"write_dr0" }, \
-	{ SVM_EXIT_WRITE_DR1,			"write_dr1" }, \
-	{ SVM_EXIT_WRITE_DR2,			"write_dr2" }, \
-	{ SVM_EXIT_WRITE_DR3,			"write_dr3" }, \
-	{ SVM_EXIT_WRITE_DR5,			"write_dr5" }, \
-	{ SVM_EXIT_WRITE_DR7,			"write_dr7" }, \
-	{ SVM_EXIT_EXCP_BASE + DB_VECTOR,	"DB excp" }, \
-	{ SVM_EXIT_EXCP_BASE + BP_VECTOR,	"BP excp" }, \
-	{ SVM_EXIT_EXCP_BASE + UD_VECTOR,	"UD excp" }, \
-	{ SVM_EXIT_EXCP_BASE + PF_VECTOR,	"PF excp" }, \
-	{ SVM_EXIT_EXCP_BASE + NM_VECTOR,	"NM excp" }, \
-	{ SVM_EXIT_EXCP_BASE + MC_VECTOR,	"MC excp" }, \
-	{ SVM_EXIT_INTR,			"interrupt" }, \
-	{ SVM_EXIT_NMI,				"nmi" }, \
-	{ SVM_EXIT_SMI,				"smi" }, \
-	{ SVM_EXIT_INIT,			"init" }, \
-	{ SVM_EXIT_VINTR,			"vintr" }, \
-	{ SVM_EXIT_CPUID,			"cpuid" }, \
-	{ SVM_EXIT_INVD,			"invd" }, \
-	{ SVM_EXIT_HLT,				"hlt" }, \
-	{ SVM_EXIT_INVLPG,			"invlpg" }, \
-	{ SVM_EXIT_INVLPGA,			"invlpga" }, \
-	{ SVM_EXIT_IOIO,			"io" }, \
-	{ SVM_EXIT_MSR,				"msr" }, \
-	{ SVM_EXIT_TASK_SWITCH,			"task_switch" }, \
-	{ SVM_EXIT_SHUTDOWN,			"shutdown" }, \
-	{ SVM_EXIT_VMRUN,			"vmrun" }, \
-	{ SVM_EXIT_VMMCALL,			"hypercall" }, \
-	{ SVM_EXIT_VMLOAD,			"vmload" }, \
-	{ SVM_EXIT_VMSAVE,			"vmsave" }, \
-	{ SVM_EXIT_STGI,			"stgi" }, \
-	{ SVM_EXIT_CLGI,			"clgi" }, \
-	{ SVM_EXIT_SKINIT,			"skinit" }, \
-	{ SVM_EXIT_WBINVD,			"wbinvd" }, \
-	{ SVM_EXIT_MONITOR,			"monitor" }, \
-	{ SVM_EXIT_MWAIT,			"mwait" }, \
-	{ SVM_EXIT_XSETBV,			"xsetbv" }, \
-	{ SVM_EXIT_NPF,				"npf" }
-
 /*
  * Tracepoint for kvm guest exit:
  */
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b1eb202..851aa7c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1493,8 +1493,12 @@
 #ifdef CONFIG_X86_64
 	wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 #endif
-	if (user_has_fpu())
-		clts();
+	/*
+	 * If the FPU is not active (through the host task or
+	 * the guest vcpu), then restore the cr0.TS bit.
+	 */
+	if (!user_has_fpu() && !vmx->vcpu.guest_fpu_loaded)
+		stts();
 	load_gdt(&__get_cpu_var(host_gdt));
 }
 
@@ -3743,7 +3747,7 @@
 	unsigned long tmpl;
 	struct desc_ptr dt;
 
-	vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS);  /* 22.2.3 */
+	vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS);  /* 22.2.3 */
 	vmcs_writel(HOST_CR4, read_cr4());  /* 22.2.3, 22.2.5 */
 	vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
 
@@ -4543,7 +4547,7 @@
 				vcpu->run->exit_reason = KVM_EXIT_SET_TPR;
 				return 0;
 			}
-		};
+		}
 		break;
 	case 2: /* clts */
 		handle_clts(vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2966c84..1f09552 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5979,7 +5979,7 @@
 	 */
 	kvm_put_guest_xcr0(vcpu);
 	vcpu->guest_fpu_loaded = 1;
-	unlazy_fpu(current);
+	__kernel_fpu_begin();
 	fpu_restore_checking(&vcpu->arch.guest_fpu);
 	trace_kvm_fpu(1);
 }
@@ -5993,6 +5993,7 @@
 
 	vcpu->guest_fpu_loaded = 0;
 	fpu_save_init(&vcpu->arch.guest_fpu);
+	__kernel_fpu_end();
 	++vcpu->stat.fpu_reload;
 	kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
 	trace_kvm_fpu(0);
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 5b2995f..a30ca15 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -17,6 +17,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 /*
  * By placing feature2 after feature1 in altinstructions section, we logically
@@ -130,6 +131,7 @@
  */
 ENTRY(copy_user_generic_unrolled)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -177,6 +179,7 @@
 	decl %ecx
 	jnz 21b
 23:	xor %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -232,6 +235,7 @@
  */
 ENTRY(copy_user_generic_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 4f
 	cmpl $8,%edx
@@ -246,6 +250,7 @@
 3:	rep
 	movsb
 4:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -273,12 +278,14 @@
  */
 ENTRY(copy_user_enhanced_fast_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 2f
 	movl %edx,%ecx
 1:	rep
 	movsb
 2:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
index cacddc7..6a4f43c 100644
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ b/arch/x86/lib/copy_user_nocache_64.S
@@ -15,6 +15,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
@@ -48,6 +49,7 @@
  */
 ENTRY(__copy_user_nocache)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -95,6 +97,7 @@
 	decl %ecx
 	jnz 21b
 23:	xorl %eax,%eax
+	ASM_CLAC
 	sfence
 	ret
 
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index b33b1fb..156b9c8 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -33,6 +33,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.text
 ENTRY(__get_user_1)
@@ -40,8 +41,10 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 1:	movzb (%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_1)
@@ -53,8 +56,10 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 2:	movzwl -1(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_2)
@@ -66,8 +71,10 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 3:	mov -3(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_4)
@@ -80,8 +87,10 @@
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae	bad_get_user
+	ASM_STAC
 4:	movq -7(%_ASM_AX),%_ASM_DX
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_8)
@@ -91,6 +100,7 @@
 	CFI_STARTPROC
 	xor %edx,%edx
 	mov $(-EFAULT),%_ASM_AX
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 END(bad_get_user)
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index 7f951c8..fc6ba17 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -15,6 +15,7 @@
 #include <asm/thread_info.h>
 #include <asm/errno.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 
 /*
@@ -31,7 +32,8 @@
 
 #define ENTER	CFI_STARTPROC ; \
 		GET_THREAD_INFO(%_ASM_BX)
-#define EXIT	ret ; \
+#define EXIT	ASM_CLAC ;	\
+		ret ;		\
 		CFI_ENDPROC
 
 .text
@@ -39,6 +41,7 @@
 	ENTER
 	cmp TI_addr_limit(%_ASM_BX),%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 1:	movb %al,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -50,6 +53,7 @@
 	sub $1,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 2:	movw %ax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -61,6 +65,7 @@
 	sub $3,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 3:	movl %eax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -72,6 +77,7 @@
 	sub $7,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 4:	mov %_ASM_AX,(%_ASM_CX)
 #ifdef CONFIG_X86_32
 5:	movl %edx,4(%_ASM_CX)
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 1781b2f..98f6d6b6 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -42,10 +42,11 @@
 	int __d0;							\
 	might_fault();							\
 	__asm__ __volatile__(						\
+		ASM_STAC "\n"						\
 		"0:	rep; stosl\n"					\
 		"	movl %2,%0\n"					\
 		"1:	rep; stosb\n"					\
-		"2:\n"							\
+		"2: " ASM_CLAC "\n"					\
 		".section .fixup,\"ax\"\n"				\
 		"3:	lea 0(%2,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
@@ -626,10 +627,12 @@
 		return n;
 	}
 #endif
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_to_user_ll);
@@ -637,10 +640,12 @@
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user_zeroing(to, from, n);
 	else
 		n = __copy_user_zeroing_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
@@ -648,11 +653,13 @@
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
 					 unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel((void __user *)to,
 				      (const void *)from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nozero);
@@ -660,6 +667,7 @@
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -668,6 +676,7 @@
 #else
 	__copy_user_zeroing(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache);
@@ -675,6 +684,7 @@
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_intel_nocache(to, from, n);
@@ -683,6 +693,7 @@
 #else
 	__copy_user(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c
index e5b130b..05928aa 100644
--- a/arch/x86/lib/usercopy_64.c
+++ b/arch/x86/lib/usercopy_64.c
@@ -18,6 +18,7 @@
 	might_fault();
 	/* no memory constraint because it doesn't change any memory gcc knows
 	   about */
+	stac();
 	asm volatile(
 		"	testq  %[size8],%[size8]\n"
 		"	jz     4f\n"
@@ -40,6 +41,7 @@
 		: [size8] "=&c"(size), [dst] "=&D" (__d0)
 		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
 		  [zero] "r" (0UL), [eight] "r" (8UL));
+	clac();
 	return size;
 }
 EXPORT_SYMBOL(__clear_user);
@@ -82,5 +84,6 @@
 	for (c = 0, zero_len = len; zerorest && zero_len; --zero_len)
 		if (__put_user_nocheck(c, to++, sizeof(char)))
 			break;
+	clac();
 	return len;
 }
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 76dcd9d..a530b23 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -18,6 +18,7 @@
 #include <asm/pgalloc.h>		/* pgd_*(), ...			*/
 #include <asm/kmemcheck.h>		/* kmemcheck_*(), ...		*/
 #include <asm/fixmap.h>			/* VSYSCALL_START		*/
+#include <asm/rcu.h>			/* exception_enter(), ...	*/
 
 /*
  * Page fault error code bits:
@@ -995,13 +996,24 @@
 	return address >= TASK_SIZE_MAX;
 }
 
+static inline bool smap_violation(int error_code, struct pt_regs *regs)
+{
+	if (error_code & PF_USER)
+		return false;
+
+	if (!user_mode_vm(regs) && (regs->flags & X86_EFLAGS_AC))
+		return false;
+
+	return true;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-dotraplinkage void __kprobes
-do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes
+__do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
 	struct vm_area_struct *vma;
 	struct task_struct *tsk;
@@ -1088,6 +1100,13 @@
 	if (unlikely(error_code & PF_RSVD))
 		pgtable_bad(regs, error_code, address);
 
+	if (static_cpu_has(X86_FEATURE_SMAP)) {
+		if (unlikely(smap_violation(error_code, regs))) {
+			bad_area_nosemaphore(regs, error_code, address);
+			return;
+		}
+	}
+
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 	/*
@@ -1209,3 +1228,11 @@
 
 	up_read(&mm->mmap_sem);
 }
+
+dotraplinkage void __kprobes
+do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+	exception_enter(regs);
+	__do_page_fault(regs, error_code);
+	exception_exit(regs);
+}
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index e0e6990..ab1f6a9 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -319,7 +319,7 @@
  */
 int devmem_is_allowed(unsigned long pagenr)
 {
-	if (pagenr <= 256)
+	if (pagenr < 256)
 		return 1;
 	if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
 		return 0;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 575d86f..11a5800 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -445,10 +445,10 @@
 }
 #endif /* CONFIG_HIGHMEM */
 
-void __init native_pagetable_setup_start(pgd_t *base)
+void __init native_pagetable_init(void)
 {
 	unsigned long pfn, va;
-	pgd_t *pgd;
+	pgd_t *pgd, *base = swapper_pg_dir;
 	pud_t *pud;
 	pmd_t *pmd;
 	pte_t *pte;
@@ -475,10 +475,7 @@
 		pte_clear(NULL, va, pte);
 	}
 	paravirt_alloc_pmd(&init_mm, __pa(base) >> PAGE_SHIFT);
-}
-
-void __init native_pagetable_setup_done(pgd_t *base)
-{
+	paging_init();
 }
 
 /*
@@ -493,7 +490,7 @@
  * If we're booting paravirtualized under a hypervisor, then there are
  * more options: we may already be running PAE, and the pagetable may
  * or may not be based in swapper_pg_dir.  In any case,
- * paravirt_pagetable_setup_start() will set up swapper_pg_dir
+ * paravirt_pagetable_init() will set up swapper_pg_dir
  * appropriately for the rest of the initialization to work.
  *
  * In general, pagetable_init() assumes that the pagetable may already
@@ -712,7 +709,7 @@
   "Checking if this processor honours the WP bit even in supervisor mode...");
 
 	/* Any page-aligned address will do, the test is non-destructive */
-	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
+	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_KERNEL_RO);
 	boot_cpu_data.wp_works_ok = do_test_wp_bit();
 	clear_fixmap(FIX_WP_TEST);
 
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 613cd83..0777f04 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -98,6 +98,8 @@
 {
 	struct flush_tlb_info *f = info;
 
+	inc_irq_stat(irq_tlb_count);
+
 	if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
 		return;
 
@@ -320,7 +322,7 @@
 	if (kstrtos8(buf, 0, &shift))
 		return -EINVAL;
 
-	if (shift > 64)
+	if (shift < -1 || shift >= BITS_PER_LONG)
 		return -EINVAL;
 
 	tlb_flushall_shift = shift;
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 505acdd6..192397c 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -305,7 +305,6 @@
 	res->flags = flags;
 	res->start = start;
 	res->end = end;
-	res->child = NULL;
 
 	if (!pci_use_crs) {
 		dev_printk(KERN_DEBUG, &info->bridge->dev,
@@ -434,7 +433,7 @@
 
 	size = sizeof(*info->res) * info->res_num;
 	info->res_num = 0;
-	info->res = kmalloc(size, GFP_KERNEL);
+	info->res = kzalloc(size, GFP_KERNEL);
 	if (!info->res)
 		return;
 
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 937bcec..704b9ec 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -585,7 +585,7 @@
 	while (i >= sizeof(struct acpi_mcfg_allocation)) {
 		entries++;
 		i -= sizeof(struct acpi_mcfg_allocation);
-	};
+	}
 	if (entries == 0) {
 		pr_err(PREFIX "MMCONFIG has no entries\n");
 		return -ENODEV;
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c
index 6f2f8ee..3e6d2a6 100644
--- a/arch/x86/pci/visws.c
+++ b/arch/x86/pci/visws.c
@@ -62,11 +62,6 @@
 	return irq;
 }
 
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 int __init pci_visws_init(void)
 {
 	pcibios_enable_irq = &pci_visws_enable_irq;
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index 73b8be0..6db1cc4 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
+obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
new file mode 100644
index 0000000..f6a0c1b
--- /dev/null
+++ b/arch/x86/platform/efi/efi-bgrt.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Intel Corporation
+ * Author: Josh Triplett <josh@joshtriplett.org>
+ *
+ * Based on the bgrt driver:
+ * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ * Author: Matthew Garrett
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <linux/efi-bgrt.h>
+
+struct acpi_table_bgrt *bgrt_tab;
+void *bgrt_image;
+size_t bgrt_image_size;
+
+struct bmp_header {
+	u16 id;
+	u32 size;
+} __packed;
+
+void efi_bgrt_init(void)
+{
+	acpi_status status;
+	void __iomem *image;
+	bool ioremapped = false;
+	struct bmp_header bmp_header;
+
+	if (acpi_disabled)
+		return;
+
+	status = acpi_get_table("BGRT", 0,
+	                        (struct acpi_table_header **)&bgrt_tab);
+	if (ACPI_FAILURE(status))
+		return;
+
+	if (bgrt_tab->version != 1)
+		return;
+	if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address)
+		return;
+
+	image = efi_lookup_mapped_addr(bgrt_tab->image_address);
+	if (!image) {
+		image = ioremap(bgrt_tab->image_address, sizeof(bmp_header));
+		ioremapped = true;
+		if (!image)
+			return;
+	}
+
+	memcpy_fromio(&bmp_header, image, sizeof(bmp_header));
+	if (ioremapped)
+		iounmap(image);
+	bgrt_image_size = bmp_header.size;
+
+	bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL);
+	if (!bgrt_image)
+		return;
+
+	if (ioremapped) {
+		image = ioremap(bgrt_tab->image_address, bmp_header.size);
+		if (!image) {
+			kfree(bgrt_image);
+			bgrt_image = NULL;
+			return;
+		}
+	}
+
+	memcpy_fromio(bgrt_image, image, bgrt_image_size);
+	if (ioremapped)
+		iounmap(image);
+}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 92660eda..aded2a9 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/efi.h>
+#include <linux/efi-bgrt.h>
 #include <linux/export.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
@@ -419,10 +420,21 @@
 	}
 }
 
-static void __init efi_free_boot_services(void)
+static void __init efi_unmap_memmap(void)
+{
+	if (memmap.map) {
+		early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
+		memmap.map = NULL;
+	}
+}
+
+void __init efi_free_boot_services(void)
 {
 	void *p;
 
+	if (!efi_native)
+		return;
+
 	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
 		efi_memory_desc_t *md = p;
 		unsigned long long start = md->phys_addr;
@@ -438,6 +450,8 @@
 
 		free_bootmem_late(start, size);
 	}
+
+	efi_unmap_memmap();
 }
 
 static int __init efi_systab_init(void *phys)
@@ -732,6 +746,11 @@
 #endif
 }
 
+void __init efi_late_init(void)
+{
+	efi_bgrt_init();
+}
+
 void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
 {
 	u64 addr, npages;
@@ -764,6 +783,34 @@
 }
 
 /*
+ * We can't ioremap data in EFI boot services RAM, because we've already mapped
+ * it as RAM.  So, look it up in the existing EFI memory map instead.  Only
+ * callable after efi_enter_virtual_mode and before efi_free_boot_services.
+ */
+void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
+{
+	void *p;
+	if (WARN_ON(!memmap.map))
+		return NULL;
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		efi_memory_desc_t *md = p;
+		u64 size = md->num_pages << EFI_PAGE_SHIFT;
+		u64 end = md->phys_addr + size;
+		if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+		    md->type != EFI_BOOT_SERVICES_CODE &&
+		    md->type != EFI_BOOT_SERVICES_DATA)
+			continue;
+		if (!md->virt_addr)
+			continue;
+		if (phys_addr >= md->phys_addr && phys_addr < end) {
+			phys_addr += md->virt_addr - md->phys_addr;
+			return (__force void __iomem *)(unsigned long)phys_addr;
+		}
+	}
+	return NULL;
+}
+
+/*
  * This function will switch the EFI runtime services to virtual mode.
  * Essentially, look through the EFI memmap and map every region that
  * has the runtime attribute bit set in its memory descriptor and update
@@ -787,8 +834,10 @@
 	 * non-native EFI
 	 */
 
-	if (!efi_native)
-		goto out;
+	if (!efi_native) {
+		efi_unmap_memmap();
+		return;
+	}
 
 	/* Merge contiguous regions of the same type and attribute */
 	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
@@ -878,18 +927,12 @@
 	}
 
 	/*
-	 * Thankfully, it does seem that no runtime services other than
-	 * SetVirtualAddressMap() will touch boot services code, so we can
-	 * get rid of it all at this point
-	 */
-	efi_free_boot_services();
-
-	/*
 	 * Now that EFI is in virtual mode, update the function
 	 * pointers in the runtime service table to the new virtual addresses.
 	 *
 	 * Call EFI services through wrapper functions.
 	 */
+	efi.runtime_version = efi_systab.fw_revision;
 	efi.get_time = virt_efi_get_time;
 	efi.set_time = virt_efi_set_time;
 	efi.get_wakeup_time = virt_efi_get_wakeup_time;
@@ -906,9 +949,6 @@
 	if (__supported_pte_mask & _PAGE_NX)
 		runtime_code_page_mkexec();
 
-out:
-	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
-	memmap.map = NULL;
 	kfree(new_memmap);
 }
 
diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h
index 9317e00..7dd86a4 100644
--- a/arch/x86/realmode/rm/wakeup.h
+++ b/arch/x86/realmode/rm/wakeup.h
@@ -36,5 +36,7 @@
 
 /* Wakeup behavior bits */
 #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE     0
+#define WAKEUP_BEHAVIOR_RESTORE_CR4		1
+#define WAKEUP_BEHAVIOR_RESTORE_EFER		2
 
 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
index 8905166..e56479e 100644
--- a/arch/x86/realmode/rm/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -74,9 +74,18 @@
 
 	lidtl	wakeup_idt
 
-	/* Clear the EFLAGS */
-	pushl	$0
+	/* Clear the EFLAGS but remember if we have EFLAGS.ID */
+	movl $X86_EFLAGS_ID, %ecx
+	pushl %ecx
 	popfl
+	pushfl
+	popl %edi
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx, %edi
+	andl %ecx, %edi		/* %edi is zero iff CPUID & %cr4 are missing */
 
 	/* Check header signature... */
 	movl	signature, %eax
@@ -93,8 +102,8 @@
 
 	/* Restore MISC_ENABLE before entering protected mode, in case
 	   BIOS decided to clear XD_DISABLE during S3. */
-	movl	pmode_behavior, %eax
-	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+	movl	pmode_behavior, %edi
+	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
 	jnc	1f
 
 	movl	pmode_misc_en, %eax
@@ -110,15 +119,15 @@
 	movl	pmode_cr3, %eax
 	movl	%eax, %cr3
 
-	movl	pmode_cr4, %ecx
-	jecxz	1f
-	movl	%ecx, %cr4
+	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
+	jz	1f
+	movl	pmode_cr4, %eax
+	movl	%eax, %cr4
 1:
+	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
+	jz	1f
 	movl	pmode_efer, %eax
 	movl	pmode_efer + 4, %edx
-	movl	%eax, %ecx
-	orl	%edx, %ecx
-	jz	1f
 	movl	$MSR_EFER, %ecx
 	wrmsr
 1:
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index 9926e11..aeaff8b 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -21,6 +21,7 @@
 config X86_32
 	def_bool !64BIT
 	select HAVE_AOUT
+	select ARCH_WANT_IPC_PARSE_VERSION
 
 config X86_64
 	def_bool 64BIT
diff --git a/arch/x86/um/shared/sysdep/kernel-offsets.h b/arch/x86/um/shared/sysdep/kernel-offsets.h
index 5868526..46a9df9 100644
--- a/arch/x86/um/shared/sysdep/kernel-offsets.h
+++ b/arch/x86/um/shared/sysdep/kernel-offsets.h
@@ -7,9 +7,6 @@
 #define DEFINE(sym, val) \
 	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
-#define STR(x) #x
-#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
-
 #define BLANK() asm volatile("\n->" : : )
 
 #define OFFSET(sym, str, mem) \
diff --git a/arch/x86/um/shared/sysdep/syscalls.h b/arch/x86/um/shared/sysdep/syscalls.h
index bd9a89b..ca255a8 100644
--- a/arch/x86/um/shared/sysdep/syscalls.h
+++ b/arch/x86/um/shared/sysdep/syscalls.h
@@ -1,3 +1,5 @@
+extern long sys_clone(unsigned long clone_flags, unsigned long newsp,
+	       void __user *parent_tid, void __user *child_tid);
 #ifdef __i386__
 #include "syscalls_32.h"
 #else
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index a508cea1..ba7363e 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -416,9 +416,6 @@
 	PT_REGS_AX(regs) = (unsigned long) sig;
 	PT_REGS_DX(regs) = (unsigned long) 0;
 	PT_REGS_CX(regs) = (unsigned long) 0;
-
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 }
 
@@ -466,9 +463,6 @@
 	PT_REGS_AX(regs) = (unsigned long) sig;
 	PT_REGS_DX(regs) = (unsigned long) &frame->info;
 	PT_REGS_CX(regs) = (unsigned long) &frame->uc;
-
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 }
 
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c
index 68d1dc9..b5408ce 100644
--- a/arch/x86/um/sys_call_table_32.c
+++ b/arch/x86/um/sys_call_table_32.c
@@ -28,7 +28,7 @@
 #define ptregs_execve sys_execve
 #define ptregs_iopl sys_iopl
 #define ptregs_vm86old sys_vm86old
-#define ptregs_clone sys_clone
+#define ptregs_clone i386_clone
 #define ptregs_vm86 sys_vm86
 #define ptregs_sigaltstack sys_sigaltstack
 #define ptregs_vfork sys_vfork
diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c
index b853e86..db444c7 100644
--- a/arch/x86/um/syscalls_32.c
+++ b/arch/x86/um/syscalls_32.c
@@ -3,37 +3,24 @@
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/shm.h"
-#include "linux/ipc.h"
-#include "linux/syscalls.h"
-#include "asm/mman.h"
-#include "asm/uaccess.h"
-#include "asm/unistd.h"
+#include <linux/syscalls.h>
+#include <sysdep/syscalls.h>
 
 /*
  * The prototype on i386 is:
  *
- *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
+ *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls
  *
  * and the "newtls" arg. on i386 is read by copy_thread directly from the
  * register saved on the stack.
  */
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       int __user *parent_tid, void *newtls, int __user *child_tid)
+long i386_clone(unsigned long clone_flags, unsigned long newsp,
+		int __user *parent_tid, void *newtls, int __user *child_tid)
 {
-	long ret;
-
-	if (!newsp)
-		newsp = UPT_SP(&current->thread.regs.regs);
-
-	current->thread.forking = 1;
-	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
-		      child_tid);
-	current->thread.forking = 0;
-	return ret;
+	return sys_clone(clone_flags, newsp, parent_tid, child_tid);
 }
 
+
 long sys_sigaction(int sig, const struct old_sigaction __user *act,
 			 struct old_sigaction __user *oact)
 {
diff --git a/arch/x86/um/syscalls_64.c b/arch/x86/um/syscalls_64.c
index f3d82bb..adb08eb 100644
--- a/arch/x86/um/syscalls_64.c
+++ b/arch/x86/um/syscalls_64.c
@@ -5,12 +5,9 @@
  * Licensed under the GPL
  */
 
-#include "linux/linkage.h"
-#include "linux/personality.h"
-#include "linux/utsname.h"
-#include "asm/prctl.h" /* XXX This should get the constants from libc */
-#include "asm/uaccess.h"
-#include "os.h"
+#include <linux/sched.h>
+#include <asm/prctl.h> /* XXX This should get the constants from libc */
+#include <os.h>
 
 long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
 {
@@ -79,20 +76,6 @@
 	return arch_prctl(current, code, (unsigned long __user *) addr);
 }
 
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       void __user *parent_tid, void __user *child_tid)
-{
-	long ret;
-
-	if (!newsp)
-		newsp = UPT_SP(&current->thread.regs.regs);
-	current->thread.forking = 1;
-	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
-		      child_tid);
-	current->thread.forking = 0;
-	return ret;
-}
-
 void arch_switch_to(struct task_struct *to)
 {
 	if ((to->thread.arch.fs == 0) || (to->mm == NULL))
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 9642d4a..1fbe75a 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1452,6 +1452,10 @@
 		pci_request_acs();
 
 		xen_acpi_sleep_register();
+
+		/* Avoid searching for BIOS MP tables */
+		x86_init.mpparse.find_smp_config = x86_init_noop;
+		x86_init.mpparse.get_smp_config = x86_init_uint_noop;
 	}
 #ifdef CONFIG_PCI
 	/* PCI BIOS service won't work from a PV guest. */
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 5141d80..7a769b7 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1174,8 +1174,13 @@
 	spin_unlock(&mm->page_table_lock);
 }
 
-static void __init xen_pagetable_setup_start(pgd_t *base)
+static void xen_post_allocator_init(void);
+
+static void __init xen_pagetable_init(void)
 {
+	paging_init();
+	xen_setup_shared_info();
+	xen_post_allocator_init();
 }
 
 static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
@@ -1192,14 +1197,6 @@
 	}
 }
 
-static void xen_post_allocator_init(void);
-
-static void __init xen_pagetable_setup_done(pgd_t *base)
-{
-	xen_setup_shared_info();
-	xen_post_allocator_init();
-}
-
 static void xen_write_cr2(unsigned long cr2)
 {
 	this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
@@ -2068,8 +2065,7 @@
 void __init xen_init_mmu_ops(void)
 {
 	x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve;
-	x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start;
-	x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
+	x86_init.paging.pagetable_init = xen_pagetable_init;
 	pv_mmu_ops = xen_mmu_ops;
 
 	memset(dummy_mapping, 0xff, PAGE_SIZE);
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 76ba0e9..72213da 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -828,9 +828,6 @@
 
 			xen_mc_issue(PARAVIRT_LAZY_MMU);
 		}
-		/* let's use dev_bus_addr to record the old mfn instead */
-		kmap_op->dev_bus_addr = page->index;
-		page->index = (unsigned long) kmap_op;
 	}
 	spin_lock_irqsave(&m2p_override_lock, flags);
 	list_add(&page->lru,  &m2p_overrides[mfn_hash(mfn)]);
@@ -857,7 +854,8 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(m2p_add_override);
-int m2p_remove_override(struct page *page, bool clear_pte)
+int m2p_remove_override(struct page *page,
+		struct gnttab_map_grant_ref *kmap_op)
 {
 	unsigned long flags;
 	unsigned long mfn;
@@ -887,10 +885,8 @@
 	WARN_ON(!PagePrivate(page));
 	ClearPagePrivate(page);
 
-	if (clear_pte) {
-		struct gnttab_map_grant_ref *map_op =
-			(struct gnttab_map_grant_ref *) page->index;
-		set_phys_to_machine(pfn, map_op->dev_bus_addr);
+	set_phys_to_machine(pfn, page->index);
+	if (kmap_op != NULL) {
 		if (!PageHighMem(page)) {
 			struct multicall_space mcs;
 			struct gnttab_unmap_grant_ref *unmap_op;
@@ -902,13 +898,13 @@
 			 * issued. In this case handle is going to -1 because
 			 * it hasn't been modified yet.
 			 */
-			if (map_op->handle == -1)
+			if (kmap_op->handle == -1)
 				xen_mc_flush();
 			/*
-			 * Now if map_op->handle is negative it means that the
+			 * Now if kmap_op->handle is negative it means that the
 			 * hypercall actually returned an error.
 			 */
-			if (map_op->handle == GNTST_general_error) {
+			if (kmap_op->handle == GNTST_general_error) {
 				printk(KERN_WARNING "m2p_remove_override: "
 						"pfn %lx mfn %lx, failed to modify kernel mappings",
 						pfn, mfn);
@@ -918,8 +914,8 @@
 			mcs = xen_mc_entry(
 					sizeof(struct gnttab_unmap_grant_ref));
 			unmap_op = mcs.args;
-			unmap_op->host_addr = map_op->host_addr;
-			unmap_op->handle = map_op->handle;
+			unmap_op->host_addr = kmap_op->host_addr;
+			unmap_op->handle = kmap_op->handle;
 			unmap_op->dev_bus_addr = 0;
 
 			MULTI_grant_table_op(mcs.mc,
@@ -930,10 +926,9 @@
 			set_pte_at(&init_mm, address, ptep,
 					pfn_pte(pfn, PAGE_KERNEL));
 			__flush_tlb_single(address);
-			map_op->host_addr = 0;
+			kmap_op->host_addr = 0;
 		}
-	} else
-		set_phys_to_machine(pfn, page->index);
+	}
 
 	/* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present
 	 * somewhere in this domain, even before being added to the
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index d11ca11d..e2d62d6 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -17,6 +17,7 @@
 #include <asm/e820.h>
 #include <asm/setup.h>
 #include <asm/acpi.h>
+#include <asm/numa.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
@@ -544,4 +545,7 @@
 	disable_cpufreq();
 	WARN_ON(set_pm_idle_to_default());
 	fiddle_vdso();
+#ifdef CONFIG_NUMA
+	numa_off = 1;
+#endif
 }
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index f58dca7..353c50f 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -377,7 +377,8 @@
 		return rc;
 
 	if (num_online_cpus() == 1)
-		alternatives_smp_switch(1);
+		/* Just in case we booted with a single CPU. */
+		alternatives_enable_smp();
 
 	rc = xen_smp_intr_init(cpu);
 	if (rc)
@@ -424,9 +425,6 @@
 	unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
 	xen_uninit_lock_cpu(cpu);
 	xen_teardown_timer(cpu);
-
-	if (num_online_cpus() == 1)
-		alternatives_smp_switch(0);
 }
 
 static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 8ed64cf..744f5ee 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -172,24 +172,6 @@
 
 source "mm/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	help
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and build a modular kernel.  Get agent software
-	  (from <http://linux-hotplug.sourceforge.net/>) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 69759e9..54354de 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -210,14 +210,6 @@
 	/* No special bus mastering setup handling */
 }
 
-/* the next one is stolen from the alpha port... */
-
-void __init
-pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 2c8d6a3..bc44311 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -31,6 +31,7 @@
 #include <linux/mqueue.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -110,8 +111,10 @@
 
 	/* endless idle loop with no priority at all */
 	while (1) {
+		rcu_idle_enter();
 		while (!need_resched())
 			platform_idle();
+		rcu_idle_exit();
 		schedule_preempt_disabled();
 	}
 }
diff --git a/block/blk-core.c b/block/blk-core.c
index 4b4dbdf..ee3cb3a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2254,9 +2254,11 @@
 			error_type = "I/O";
 			break;
 		}
-		printk(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
-		       error_type, req->rq_disk ? req->rq_disk->disk_name : "?",
-		       (unsigned long long)blk_rq_pos(req));
+		printk_ratelimited(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
+				   error_type, req->rq_disk ?
+				   req->rq_disk->disk_name : "?",
+				   (unsigned long long)blk_rq_pos(req));
+
 	}
 
 	blk_account_io_completion(req, nr_bytes);
diff --git a/block/ioctl.c b/block/ioctl.c
index 4476e0e8..4a85096 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -41,7 +41,7 @@
 			    sizeof(long long) > sizeof(long)) {
 				long pstart = start, plength = length;
 				if (pstart != start || plength != length
-				    || pstart < 0 || plength < 0)
+				    || pstart < 0 || plength < 0 || partno > 65535)
 					return -EINVAL;
 			}
 
diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c
index 1104aca..47a6147 100644
--- a/block/partitions/ibm.c
+++ b/block/partitions/ibm.c
@@ -1,9 +1,8 @@
 /*
- * File...........: linux/fs/partitions/ibm.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  *                  Volker Sameske <sameske@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * Copyright IBM Corp. 1999, 2012
  */
 
 #include <linux/buffer_head.h>
@@ -17,17 +16,23 @@
 #include "check.h"
 #include "ibm.h"
 
+
+union label_t {
+	struct vtoc_volume_label_cdl vol;
+	struct vtoc_volume_label_ldl lnx;
+	struct vtoc_cms_label cms;
+};
+
 /*
  * compute the block number from a
  * cyl-cyl-head-head structure
  */
-static sector_t
-cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
-
+static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
+{
 	sector_t cyl;
 	__u16 head;
 
-	/*decode cylinder and heads for large volumes */
+	/* decode cylinder and heads for large volumes */
 	cyl = ptr->hh & 0xFFF0;
 	cyl <<= 12;
 	cyl |= ptr->cc;
@@ -40,13 +45,12 @@
  * compute the block number from a
  * cyl-cyl-head-head-block structure
  */
-static sector_t
-cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
-
+static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
+{
 	sector_t cyl;
 	__u16 head;
 
-	/*decode cylinder and heads for large volumes */
+	/* decode cylinder and heads for large volumes */
 	cyl = ptr->hh & 0xFFF0;
 	cyl <<= 12;
 	cyl |= ptr->cc;
@@ -56,26 +60,243 @@
 		ptr->b;
 }
 
+static int find_label(struct parsed_partitions *state,
+		      dasd_information2_t *info,
+		      struct hd_geometry *geo,
+		      int blocksize,
+		      sector_t *labelsect,
+		      char name[],
+		      char type[],
+		      union label_t *label)
+{
+	Sector sect;
+	unsigned char *data;
+	sector_t testsect[3];
+	unsigned char temp[5];
+	int found = 0;
+	int i, testcount;
+
+	/* There a three places where we may find a valid label:
+	 * - on an ECKD disk it's block 2
+	 * - on an FBA disk it's block 1
+	 * - on an CMS formatted FBA disk it is sector 1, even if the block size
+	 *   is larger than 512 bytes (possible if the DIAG discipline is used)
+	 * If we have a valid info structure, then we know exactly which case we
+	 * have, otherwise we just search through all possebilities.
+	 */
+	if (info) {
+		if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
+		    (info->cu_type == 0x3880 && info->dev_type == 0x3370))
+			testsect[0] = info->label_block;
+		else
+			testsect[0] = info->label_block * (blocksize >> 9);
+		testcount = 1;
+	} else {
+		testsect[0] = 1;
+		testsect[1] = (blocksize >> 9);
+		testsect[2] = 2 * (blocksize >> 9);
+		testcount = 3;
+	}
+	for (i = 0; i < testcount; ++i) {
+		data = read_part_sector(state, testsect[i], &sect);
+		if (data == NULL)
+			continue;
+		memcpy(label, data, sizeof(*label));
+		memcpy(temp, data, 4);
+		temp[4] = 0;
+		EBCASC(temp, 4);
+		put_dev_sector(sect);
+		if (!strcmp(temp, "VOL1") ||
+		    !strcmp(temp, "LNX1") ||
+		    !strcmp(temp, "CMS1")) {
+			if (!strcmp(temp, "VOL1")) {
+				strncpy(type, label->vol.vollbl, 4);
+				strncpy(name, label->vol.volid, 6);
+			} else {
+				strncpy(type, label->lnx.vollbl, 4);
+				strncpy(name, label->lnx.volid, 6);
+			}
+			EBCASC(type, 4);
+			EBCASC(name, 6);
+			*labelsect = testsect[i];
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		memset(label, 0, sizeof(*label));
+
+	return found;
+}
+
+static int find_vol1_partitions(struct parsed_partitions *state,
+				struct hd_geometry *geo,
+				int blocksize,
+				char name[],
+				union label_t *label)
+{
+	sector_t blk;
+	int counter;
+	char tmp[64];
+	Sector sect;
+	unsigned char *data;
+	loff_t offset, size;
+	struct vtoc_format1_label f1;
+	int secperblk;
+
+	snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
+	strlcat(state->pp_buf, tmp, PAGE_SIZE);
+	/*
+	 * get start of VTOC from the disk label and then search for format1
+	 * and format8 labels
+	 */
+	secperblk = blocksize >> 9;
+	blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
+	counter = 0;
+	data = read_part_sector(state, blk * secperblk, &sect);
+	while (data != NULL) {
+		memcpy(&f1, data, sizeof(struct vtoc_format1_label));
+		put_dev_sector(sect);
+		/* skip FMT4 / FMT5 / FMT7 labels */
+		if (f1.DS1FMTID == _ascebc['4']
+		    || f1.DS1FMTID == _ascebc['5']
+		    || f1.DS1FMTID == _ascebc['7']
+		    || f1.DS1FMTID == _ascebc['9']) {
+			blk++;
+			data = read_part_sector(state, blk * secperblk, &sect);
+			continue;
+		}
+		/* only FMT1 and 8 labels valid at this point */
+		if (f1.DS1FMTID != _ascebc['1'] &&
+		    f1.DS1FMTID != _ascebc['8'])
+			break;
+		/* OK, we got valid partition data */
+		offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
+		size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
+			offset + geo->sectors;
+		offset *= secperblk;
+		size *= secperblk;
+		if (counter >= state->limit)
+			break;
+		put_partition(state, counter + 1, offset, size);
+		counter++;
+		blk++;
+		data = read_part_sector(state, blk * secperblk, &sect);
+	}
+	strlcat(state->pp_buf, "\n", PAGE_SIZE);
+
+	if (!data)
+		return -1;
+
+	return 1;
+}
+
+static int find_lnx1_partitions(struct parsed_partitions *state,
+				struct hd_geometry *geo,
+				int blocksize,
+				char name[],
+				union label_t *label,
+				sector_t labelsect,
+				loff_t i_size,
+				dasd_information2_t *info)
+{
+	loff_t offset, geo_size, size;
+	char tmp[64];
+	int secperblk;
+
+	snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
+	strlcat(state->pp_buf, tmp, PAGE_SIZE);
+	secperblk = blocksize >> 9;
+	if (label->lnx.ldl_version == 0xf2) {
+		size = label->lnx.formatted_blocks * secperblk;
+	} else {
+		/*
+		 * Formated w/o large volume support. If the sanity check
+		 * 'size based on geo == size based on i_size' is true, then
+		 * we can safely assume that we know the formatted size of
+		 * the disk, otherwise we need additional information
+		 * that we can only get from a real DASD device.
+		 */
+		geo_size = geo->cylinders * geo->heads
+			* geo->sectors * secperblk;
+		size = i_size >> 9;
+		if (size != geo_size) {
+			if (!info) {
+				strlcat(state->pp_buf, "\n", PAGE_SIZE);
+				return 1;
+			}
+			if (!strcmp(info->type, "ECKD"))
+				if (geo_size < size)
+					size = geo_size;
+			/* else keep size based on i_size */
+		}
+	}
+	/* first and only partition starts in the first block after the label */
+	offset = labelsect + secperblk;
+	put_partition(state, 1, offset, size - offset);
+	strlcat(state->pp_buf, "\n", PAGE_SIZE);
+	return 1;
+}
+
+static int find_cms1_partitions(struct parsed_partitions *state,
+				struct hd_geometry *geo,
+				int blocksize,
+				char name[],
+				union label_t *label,
+				sector_t labelsect)
+{
+	loff_t offset, size;
+	char tmp[64];
+	int secperblk;
+
+	/*
+	 * VM style CMS1 labeled disk
+	 */
+	blocksize = label->cms.block_size;
+	secperblk = blocksize >> 9;
+	if (label->cms.disk_offset != 0) {
+		snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
+		strlcat(state->pp_buf, tmp, PAGE_SIZE);
+		/* disk is reserved minidisk */
+		offset = label->cms.disk_offset * secperblk;
+		size = (label->cms.block_count - 1) * secperblk;
+	} else {
+		snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
+		strlcat(state->pp_buf, tmp, PAGE_SIZE);
+		/*
+		 * Special case for FBA devices:
+		 * If an FBA device is CMS formatted with blocksize > 512 byte
+		 * and the DIAG discipline is used, then the CMS label is found
+		 * in sector 1 instead of block 1. However, the partition is
+		 * still supposed to start in block 2.
+		 */
+		if (labelsect == 1)
+			offset = 2 * secperblk;
+		else
+			offset = labelsect + secperblk;
+		size = label->cms.block_count * secperblk;
+	}
+
+	put_partition(state, 1, offset, size-offset);
+	strlcat(state->pp_buf, "\n", PAGE_SIZE);
+	return 1;
+}
+
+
 /*
+ * This is the main function, called by check.c
  */
 int ibm_partition(struct parsed_partitions *state)
 {
 	struct block_device *bdev = state->bdev;
 	int blocksize, res;
-	loff_t i_size, offset, size, fmt_size;
+	loff_t i_size, offset, size;
 	dasd_information2_t *info;
 	struct hd_geometry *geo;
 	char type[5] = {0,};
 	char name[7] = {0,};
-	union label_t {
-		struct vtoc_volume_label_cdl vol;
-		struct vtoc_volume_label_ldl lnx;
-		struct vtoc_cms_label cms;
-	} *label;
-	unsigned char *data;
-	Sector sect;
 	sector_t labelsect;
-	char tmp[64];
+	union label_t *label;
 
 	res = 0;
 	blocksize = bdev_logical_block_size(bdev);
@@ -84,7 +305,6 @@
 	i_size = i_size_read(bdev->bd_inode);
 	if (i_size == 0)
 		goto out_exit;
-
 	info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
 	if (info == NULL)
 		goto out_exit;
@@ -94,176 +314,45 @@
 	label = kmalloc(sizeof(union label_t), GFP_KERNEL);
 	if (label == NULL)
 		goto out_nolab;
-
-	if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
-	    ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
+	if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
 		goto out_freeall;
-
-	/*
-	 * Special case for FBA disks: label sector does not depend on
-	 * blocksize.
-	 */
-	if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
-	    (info->cu_type == 0x3880 && info->dev_type == 0x3370))
-		labelsect = info->label_block;
-	else
-		labelsect = info->label_block * (blocksize >> 9);
-
-	/*
-	 * Get volume label, extract name and type.
-	 */
-	data = read_part_sector(state, labelsect, &sect);
-	if (data == NULL)
-		goto out_readerr;
-
-	memcpy(label, data, sizeof(union label_t));
-	put_dev_sector(sect);
-
-	if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
-		strncpy(type, label->vol.vollbl, 4);
-		strncpy(name, label->vol.volid, 6);
-	} else {
-		strncpy(type, label->lnx.vollbl, 4);
-		strncpy(name, label->lnx.volid, 6);
+	if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0) {
+		kfree(info);
+		info = NULL;
 	}
-	EBCASC(type, 4);
-	EBCASC(name, 6);
 
-	res = 1;
-
-	/*
-	 * Three different formats: LDL, CDL and unformated disk
-	 *
-	 * identified by info->format
-	 *
-	 * unformated disks we do not have to care about
-	 */
-	if (info->format == DASD_FORMAT_LDL) {
-		if (strncmp(type, "CMS1", 4) == 0) {
-			/*
-			 * VM style CMS1 labeled disk
-			 */
-			blocksize = label->cms.block_size;
-			if (label->cms.disk_offset != 0) {
-				snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
-				strlcat(state->pp_buf, tmp, PAGE_SIZE);
-				/* disk is reserved minidisk */
-				offset = label->cms.disk_offset;
-				size = (label->cms.block_count - 1)
-					* (blocksize >> 9);
-			} else {
-				snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
-				strlcat(state->pp_buf, tmp, PAGE_SIZE);
-				offset = (info->label_block + 1);
-				size = label->cms.block_count
-					* (blocksize >> 9);
-			}
-			put_partition(state, 1, offset*(blocksize >> 9),
-				      size-offset*(blocksize >> 9));
-		} else {
-			if (strncmp(type, "LNX1", 4) == 0) {
-				snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
-				strlcat(state->pp_buf, tmp, PAGE_SIZE);
-				if (label->lnx.ldl_version == 0xf2) {
-					fmt_size = label->lnx.formatted_blocks
-						* (blocksize >> 9);
-				} else if (!strcmp(info->type, "ECKD")) {
-					/* formated w/o large volume support */
-					fmt_size = geo->cylinders * geo->heads
-					      * geo->sectors * (blocksize >> 9);
-				} else {
-					/* old label and no usable disk geometry
-					 * (e.g. DIAG) */
-					fmt_size = i_size >> 9;
-				}
-				size = i_size >> 9;
-				if (fmt_size < size)
-					size = fmt_size;
-				offset = (info->label_block + 1);
-			} else {
-				/* unlabeled disk */
-				strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
-				size = i_size >> 9;
-				offset = (info->label_block + 1);
-			}
-			put_partition(state, 1, offset*(blocksize >> 9),
-				      size-offset*(blocksize >> 9));
+	if (find_label(state, info, geo, blocksize, &labelsect, name, type,
+		       label)) {
+		if (!strncmp(type, "VOL1", 4)) {
+			res = find_vol1_partitions(state, geo, blocksize, name,
+						   label);
+		} else if (!strncmp(type, "LNX1", 4)) {
+			res = find_lnx1_partitions(state, geo, blocksize, name,
+						   label, labelsect, i_size,
+						   info);
+		} else if (!strncmp(type, "CMS1", 4)) {
+			res = find_cms1_partitions(state, geo, blocksize, name,
+						   label, labelsect);
 		}
-	} else if (info->format == DASD_FORMAT_CDL) {
+	} else if (info) {
 		/*
-		 * New style CDL formatted disk
+		 * ugly but needed for backward compatibility:
+		 * If the block device is a DASD (i.e. BIODASDINFO2 works),
+		 * then we claim it in any case, even though it has no valid
+		 * label. If it has the LDL format, then we simply define a
+		 * partition as if it had an LNX1 label.
 		 */
-		sector_t blk;
-		int counter;
+		res = 1;
+		if (info->format == DASD_FORMAT_LDL) {
+			strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
+			size = i_size >> 9;
+			offset = (info->label_block + 1) * (blocksize >> 9);
+			put_partition(state, 1, offset, size-offset);
+			strlcat(state->pp_buf, "\n", PAGE_SIZE);
+		}
+	} else
+		res = 0;
 
-		/*
-		 * check if VOL1 label is available
-		 * if not, something is wrong, skipping partition detection
-		 */
-		if (strncmp(type, "VOL1",  4) == 0) {
-			snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
-			strlcat(state->pp_buf, tmp, PAGE_SIZE);
-			/*
-			 * get block number and read then go through format1
-			 * labels
-			 */
-			blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
-			counter = 0;
-			data = read_part_sector(state, blk * (blocksize/512),
-						&sect);
-			while (data != NULL) {
-				struct vtoc_format1_label f1;
-
-				memcpy(&f1, data,
-				       sizeof(struct vtoc_format1_label));
-				put_dev_sector(sect);
-
-				/* skip FMT4 / FMT5 / FMT7 labels */
-				if (f1.DS1FMTID == _ascebc['4']
-				    || f1.DS1FMTID == _ascebc['5']
-				    || f1.DS1FMTID == _ascebc['7']
-				    || f1.DS1FMTID == _ascebc['9']) {
-					blk++;
-					data = read_part_sector(state,
-						blk * (blocksize/512), &sect);
-					continue;
-				}
-
-				/* only FMT1 and 8 labels valid at this point */
-				if (f1.DS1FMTID != _ascebc['1'] &&
-				    f1.DS1FMTID != _ascebc['8'])
-					break;
-
-				/* OK, we got valid partition data */
-				offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
-				size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
-					offset + geo->sectors;
-				if (counter >= state->limit)
-					break;
-				put_partition(state, counter + 1,
-					      offset * (blocksize >> 9),
-					      size * (blocksize >> 9));
-				counter++;
-				blk++;
-				data = read_part_sector(state,
-						blk * (blocksize/512), &sect);
-			}
-
-			if (!data)
-				/* Are we not supposed to report this ? */
-				goto out_readerr;
-		} else
-			printk(KERN_INFO "Expected Label VOL1 not "
-			       "found, treating as CDL formated Disk");
-
-	}
-
-	strlcat(state->pp_buf, "\n", PAGE_SIZE);
-	goto out_freeall;
-
-
-out_readerr:
-	res = -1;
 out_freeall:
 	kfree(label);
 out_nolab:
diff --git a/drivers/Kconfig b/drivers/Kconfig
index ece958d..36d3daa 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -152,4 +152,6 @@
 
 source "drivers/pwm/Kconfig"
 
+source "drivers/irqchip/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 5b42184..8c30e73 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,8 @@
 # Rewritten to use lists instead of if-statements.
 #
 
+obj-y				+= irqchip/
+
 # GPIO must come after pinctrl as gpios may need to mux pins etc
 obj-y				+= pinctrl/
 obj-y				+= gpio/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 8099895..119d58d 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -385,8 +385,8 @@
 	  to override that restriction).
 
 config ACPI_BGRT
-        tristate "Boottime Graphics Resource Table support"
-        default n
+	bool "Boottime Graphics Resource Table support"
+	depends on EFI
         help
 	  This driver adds support for exposing the ACPI Boottime Graphics
 	  Resource Table, which allows the operating system to obtain
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index 6680df3..be60399 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ * Copyright 2012 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,20 +12,10 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/sysfs.h>
-#include <linux/io.h>
-#include <acpi/acpi.h>
-#include <acpi/acpi_bus.h>
+#include <linux/efi-bgrt.h>
 
-static struct acpi_table_bgrt *bgrt_tab;
 static struct kobject *bgrt_kobj;
 
-struct bmp_header {
-	u16 id;
-	u32 size;
-} __attribute ((packed));
-
-static struct bmp_header bmp_header;
-
 static ssize_t show_version(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
@@ -63,18 +54,7 @@
 static ssize_t show_image(struct file *file, struct kobject *kobj,
 	       struct bin_attribute *attr, char *buf, loff_t off, size_t count)
 {
-	int size = attr->size;
-	void __iomem *image = attr->private;
-
-	if (off >= size) {
-		count = 0;
-	} else {
-		if (off + count > size)
-			count = size - off;
-
-		memcpy_fromio(buf, image+off, count);
-	}
-
+	memcpy(buf, attr->private + off, count);
 	return count;
 }
 
@@ -101,45 +81,18 @@
 
 static int __init bgrt_init(void)
 {
-	acpi_status status;
 	int ret;
-	void __iomem *bgrt;
 
-	if (acpi_disabled)
-		return -ENODEV;
-
-	status = acpi_get_table("BGRT", 0,
-				(struct acpi_table_header **)&bgrt_tab);
-
-	if (ACPI_FAILURE(status))
+	if (!bgrt_image)
 		return -ENODEV;
 
 	sysfs_bin_attr_init(&image_attr);
-
-	bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header));
-
-	if (!bgrt) {
-		ret = -EINVAL;
-		goto out_err;
-	}
-
-	memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header));
-	image_attr.size = bmp_header.size;
-	iounmap(bgrt);
-
-	image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size);
-
-	if (!image_attr.private) {
-		ret = -EINVAL;
-		goto out_err;
-	}
-
+	image_attr.private = bgrt_image;
+	image_attr.size = bgrt_image_size;
 
 	bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
-	if (!bgrt_kobj) {
-		ret = -EINVAL;
-		goto out_iounmap;
-	}
+	if (!bgrt_kobj)
+		return -EINVAL;
 
 	ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group);
 	if (ret)
@@ -155,22 +108,11 @@
 	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
 out_kobject:
 	kobject_put(bgrt_kobj);
-out_iounmap:
-	iounmap(image_attr.private);
-out_err:
 	return ret;
 }
 
-static void __exit bgrt_exit(void)
-{
-	iounmap(image_attr.private);
-	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
-	sysfs_remove_bin_file(bgrt_kobj, &image_attr);
-}
-
 module_init(bgrt_init);
-module_exit(bgrt_exit);
 
-MODULE_AUTHOR("Matthew Garrett");
+MODULE_AUTHOR("Matthew Garrett, Josh Triplett <josh@joshtriplett.org>");
 MODULE_DESCRIPTION("BGRT boot graphic support");
 MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 72a2c98..bce469c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
@@ -71,9 +71,11 @@
 		},
 };
 
+/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
+static DEFINE_MUTEX(acpi_pci_root_lock);
 static LIST_HEAD(acpi_pci_roots);
+static LIST_HEAD(acpi_pci_drivers);
 
-static struct acpi_pci_driver *sub_driver;
 static DEFINE_MUTEX(osc_lock);
 
 int acpi_pci_register_driver(struct acpi_pci_driver *driver)
@@ -81,55 +83,46 @@
 	int n = 0;
 	struct acpi_pci_root *root;
 
-	struct acpi_pci_driver **pptr = &sub_driver;
-	while (*pptr)
-		pptr = &(*pptr)->next;
-	*pptr = driver;
-
-	if (!driver->add)
-		return 0;
-
-	list_for_each_entry(root, &acpi_pci_roots, node) {
-		driver->add(root->device->handle);
-		n++;
-	}
+	mutex_lock(&acpi_pci_root_lock);
+	list_add_tail(&driver->node, &acpi_pci_drivers);
+	if (driver->add)
+		list_for_each_entry(root, &acpi_pci_roots, node) {
+			driver->add(root);
+			n++;
+		}
+	mutex_unlock(&acpi_pci_root_lock);
 
 	return n;
 }
-
 EXPORT_SYMBOL(acpi_pci_register_driver);
 
 void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
 {
 	struct acpi_pci_root *root;
 
-	struct acpi_pci_driver **pptr = &sub_driver;
-	while (*pptr) {
-		if (*pptr == driver)
-			break;
-		pptr = &(*pptr)->next;
-	}
-	BUG_ON(!*pptr);
-	*pptr = (*pptr)->next;
-
-	if (!driver->remove)
-		return;
-
-	list_for_each_entry(root, &acpi_pci_roots, node)
-		driver->remove(root->device->handle);
+	mutex_lock(&acpi_pci_root_lock);
+	list_del(&driver->node);
+	if (driver->remove)
+		list_for_each_entry(root, &acpi_pci_roots, node)
+			driver->remove(root);
+	mutex_unlock(&acpi_pci_root_lock);
 }
-
 EXPORT_SYMBOL(acpi_pci_unregister_driver);
 
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
 {
 	struct acpi_pci_root *root;
+	acpi_handle handle = NULL;
 	
+	mutex_lock(&acpi_pci_root_lock);
 	list_for_each_entry(root, &acpi_pci_roots, node)
 		if ((root->segment == (u16) seg) &&
-		    (root->secondary.start == (u16) bus))
-			return root->device->handle;
-	return NULL;		
+		    (root->secondary.start == (u16) bus)) {
+			handle = root->device->handle;
+			break;
+		}
+	mutex_unlock(&acpi_pci_root_lock);
+	return handle;
 }
 
 EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
@@ -277,12 +270,15 @@
 struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
 {
 	struct acpi_pci_root *root;
+	struct acpi_device *device;
 
-	list_for_each_entry(root, &acpi_pci_roots, node) {
-		if (root->device->handle == handle)
-			return root;
-	}
-	return NULL;
+	if (acpi_bus_get_device(handle, &device) ||
+	    acpi_match_device_ids(device, root_device_ids))
+		return NULL;
+
+	root = acpi_driver_data(device);
+
+	return root;
 }
 EXPORT_SYMBOL_GPL(acpi_pci_find_root);
 
@@ -518,8 +514,9 @@
 	 * TBD: Need PCI interface for enumeration/configuration of roots.
 	 */
 
-	/* TBD: Locking */
+	mutex_lock(&acpi_pci_root_lock);
 	list_add_tail(&root->node, &acpi_pci_roots);
+	mutex_unlock(&acpi_pci_root_lock);
 
 	printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
 	       acpi_device_name(device), acpi_device_bid(device),
@@ -538,7 +535,7 @@
 			    "Bus %04x:%02x not present in PCI namespace\n",
 			    root->segment, (unsigned int)root->secondary.start);
 		result = -ENODEV;
-		goto end;
+		goto out_del_root;
 	}
 
 	/*
@@ -548,7 +545,7 @@
 	 */
 	result = acpi_pci_bind_root(device);
 	if (result)
-		goto end;
+		goto out_del_root;
 
 	/*
 	 * PCI Routing Table
@@ -633,9 +630,11 @@
 
 	return 0;
 
+out_del_root:
+	mutex_lock(&acpi_pci_root_lock);
+	list_del(&root->node);
+	mutex_unlock(&acpi_pci_root_lock);
 end:
-	if (!list_empty(&root->node))
-		list_del(&root->node);
 	kfree(root);
 	return result;
 }
@@ -643,18 +642,34 @@
 static int acpi_pci_root_start(struct acpi_device *device)
 {
 	struct acpi_pci_root *root = acpi_driver_data(device);
+	struct acpi_pci_driver *driver;
+
+	mutex_lock(&acpi_pci_root_lock);
+	list_for_each_entry(driver, &acpi_pci_drivers, node)
+		if (driver->add)
+			driver->add(root);
+	mutex_unlock(&acpi_pci_root_lock);
 
 	pci_bus_add_devices(root->bus);
+
 	return 0;
 }
 
 static int acpi_pci_root_remove(struct acpi_device *device, int type)
 {
 	struct acpi_pci_root *root = acpi_driver_data(device);
+	struct acpi_pci_driver *driver;
+
+	mutex_lock(&acpi_pci_root_lock);
+	list_for_each_entry(driver, &acpi_pci_drivers, node)
+		if (driver->remove)
+			driver->remove(root);
 
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
+	list_del(&root->node);
+	mutex_unlock(&acpi_pci_root_lock);
 	kfree(root);
 	return 0;
 }
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index e50e31a..d22585f 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -67,8 +67,8 @@
 	struct list_head list;		/* node in the list of slots */
 };
 
-static int acpi_pci_slot_add(acpi_handle handle);
-static void acpi_pci_slot_remove(acpi_handle handle);
+static int acpi_pci_slot_add(struct acpi_pci_root *root);
+static void acpi_pci_slot_remove(struct acpi_pci_root *root);
 
 static LIST_HEAD(slot_list);
 static DEFINE_MUTEX(slot_list_lock);
@@ -233,45 +233,20 @@
 
 /*
  * walk_root_bridge - generic root bridge walker
- * @handle: points to an acpi_pci_root
+ * @root: poiner of an acpi_pci_root
  * @user_function: user callback for slot objects
  *
  * Call user_function for all objects underneath this root bridge.
  * Walk p2p bridges underneath us and call user_function on those too.
  */
 static int
-walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
+walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
 {
-	int seg, bus;
-	unsigned long long tmp;
 	acpi_status status;
-	acpi_handle dummy_handle;
-	struct pci_bus *pci_bus;
+	acpi_handle handle = root->device->handle;
+	struct pci_bus *pci_bus = root->bus;
 	struct callback_args context;
 
-	/* If the bridge doesn't have _STA, we assume it is always there */
-	status = acpi_get_handle(handle, "_STA", &dummy_handle);
-	if (ACPI_SUCCESS(status)) {
-		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-		if (ACPI_FAILURE(status)) {
-			info("%s: _STA evaluation failure\n", __func__);
-			return 0;
-		}
-		if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0)
-			/* don't register this object */
-			return 0;
-	}
-
-	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
-	seg = ACPI_SUCCESS(status) ? tmp : 0;
-
-	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
-	bus = ACPI_SUCCESS(status) ? tmp : 0;
-
-	pci_bus = pci_find_bus(seg, bus);
-	if (!pci_bus)
-		return 0;
-
 	context.pci_bus = pci_bus;
 	context.user_function = user_function;
 	context.root_handle = handle;
@@ -295,11 +270,11 @@
  * @handle: points to an acpi_pci_root
  */
 static int
-acpi_pci_slot_add(acpi_handle handle)
+acpi_pci_slot_add(struct acpi_pci_root *root)
 {
 	acpi_status status;
 
-	status = walk_root_bridge(handle, register_slot);
+	status = walk_root_bridge(root, register_slot);
 	if (ACPI_FAILURE(status))
 		err("%s: register_slot failure - %d\n", __func__, status);
 
@@ -311,10 +286,11 @@
  * @handle: points to an acpi_pci_root
  */
 static void
-acpi_pci_slot_remove(acpi_handle handle)
+acpi_pci_slot_remove(struct acpi_pci_root *root)
 {
 	struct acpi_pci_slot *slot, *tmp;
 	struct pci_bus *pbus;
+	acpi_handle handle = root->device->handle;
 
 	mutex_lock(&slot_list_lock);
 	list_for_each_entry_safe(slot, tmp, &slot_list, list) {
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5e6e00b..abea76c 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -184,6 +184,17 @@
 	struct device *dev = kobj_to_dev(kobj);
 	struct device_private *p = dev->p;
 
+	/*
+	 * Some platform devices are driven without driver attached
+	 * and managed resources may have been acquired.  Make sure
+	 * all resources are released.
+	 *
+	 * Drivers still can add resources into device after device
+	 * is deleted but alive, so release devres here to avoid
+	 * possible memory leak.
+	 */
+	devres_release_all(dev);
+
 	if (dev->release)
 		dev->release(dev);
 	else if (dev->type && dev->type->release)
@@ -1196,13 +1207,6 @@
 	bus_remove_device(dev);
 	driver_deferred_probe_del(dev);
 
-	/*
-	 * Some platform devices are driven without driver attached
-	 * and managed resources may have been acquired.  Make sure
-	 * all resources are released.
-	 */
-	devres_release_all(dev);
-
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
 	 */
@@ -1861,26 +1865,20 @@
  */
 
 #ifdef CONFIG_PRINTK
-int __dev_printk(const char *level, const struct device *dev,
-		 struct va_format *vaf)
+static int
+create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
 {
-	char dict[128];
-	const char *level_extra = "";
-	size_t dictlen = 0;
 	const char *subsys;
-
-	if (!dev)
-		return printk("%s(NULL device *): %pV", level, vaf);
+	size_t pos = 0;
 
 	if (dev->class)
 		subsys = dev->class->name;
 	else if (dev->bus)
 		subsys = dev->bus->name;
 	else
-		goto skip;
+		return 0;
 
-	dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
-			    "SUBSYSTEM=%s", subsys);
+	pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys);
 
 	/*
 	 * Add device identifier DEVICE=:
@@ -1896,32 +1894,63 @@
 			c = 'b';
 		else
 			c = 'c';
-		dictlen++;
-		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
-				   "DEVICE=%c%u:%u",
-				   c, MAJOR(dev->devt), MINOR(dev->devt));
+		pos++;
+		pos += snprintf(hdr + pos, hdrlen - pos,
+				"DEVICE=%c%u:%u",
+				c, MAJOR(dev->devt), MINOR(dev->devt));
 	} else if (strcmp(subsys, "net") == 0) {
 		struct net_device *net = to_net_dev(dev);
 
-		dictlen++;
-		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
-				    "DEVICE=n%u", net->ifindex);
+		pos++;
+		pos += snprintf(hdr + pos, hdrlen - pos,
+				"DEVICE=n%u", net->ifindex);
 	} else {
-		dictlen++;
-		dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
-				    "DEVICE=+%s:%s", subsys, dev_name(dev));
+		pos++;
+		pos += snprintf(hdr + pos, hdrlen - pos,
+				"DEVICE=+%s:%s", subsys, dev_name(dev));
 	}
-skip:
-	if (level[2])
-		level_extra = &level[2]; /* skip past KERN_SOH "L" */
 
-	return printk_emit(0, level[1] - '0',
-			   dictlen ? dict : NULL, dictlen,
-			   "%s %s: %s%pV",
-			   dev_driver_string(dev), dev_name(dev),
-			   level_extra, vaf);
+	return pos;
 }
-EXPORT_SYMBOL(__dev_printk);
+EXPORT_SYMBOL(create_syslog_header);
+
+int dev_vprintk_emit(int level, const struct device *dev,
+		     const char *fmt, va_list args)
+{
+	char hdr[128];
+	size_t hdrlen;
+
+	hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
+
+	return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args);
+}
+EXPORT_SYMBOL(dev_vprintk_emit);
+
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+
+	r = dev_vprintk_emit(level, dev, fmt, args);
+
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(dev_printk_emit);
+
+static int __dev_printk(const char *level, const struct device *dev,
+			struct va_format *vaf)
+{
+	if (!dev)
+		return printk("%s(NULL device *): %pV", level, vaf);
+
+	return dev_printk_emit(level[1] - '0', dev,
+			       "%s %s: %pV",
+			       dev_driver_string(dev), dev_name(dev), vaf);
+}
 
 int dev_printk(const char *level, const struct device *dev,
 	       const char *fmt, ...)
@@ -1936,6 +1965,7 @@
 	vaf.va = &args;
 
 	r = __dev_printk(level, dev, &vaf);
+
 	va_end(args);
 
 	return r;
@@ -1955,6 +1985,7 @@
 	vaf.va = &args;						\
 								\
 	r = __dev_printk(kern_level, dev, &vaf);		\
+								\
 	va_end(args);						\
 								\
 	return r;						\
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 2360adb..8731979 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -144,6 +144,48 @@
 #endif
 
 /**
+ * devres_for_each_res - Resource iterator
+ * @dev: Device to iterate resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ * @fn: Function to be called for each matched resource.
+ * @data: Data for @fn, the 3rd parameter of @fn
+ *
+ * Call @fn for each devres of @dev which is associated with @release
+ * and for which @match returns 1.
+ *
+ * RETURNS:
+ * 	void
+ */
+void devres_for_each_res(struct device *dev, dr_release_t release,
+			dr_match_t match, void *match_data,
+			void (*fn)(struct device *, void *, void *),
+			void *data)
+{
+	struct devres_node *node;
+	struct devres_node *tmp;
+	unsigned long flags;
+
+	if (!fn)
+		return;
+
+	spin_lock_irqsave(&dev->devres_lock, flags);
+	list_for_each_entry_safe_reverse(node, tmp,
+			&dev->devres_head, entry) {
+		struct devres *dr = container_of(node, struct devres, node);
+
+		if (node->release != release)
+			continue;
+		if (match && !match(dev, dr->data, match_data))
+			continue;
+		fn(dev, dr->data, data);
+	}
+	spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_for_each_res);
+
+/**
  * devres_free - Free device resource data
  * @res: Pointer to devres data to free
  *
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 803cfc1..6e21080 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -21,6 +21,13 @@
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/async.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
+
+#include "base.h"
 
 MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
@@ -85,22 +92,167 @@
 	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
 }
 
+struct firmware_cache {
+	/* firmware_buf instance will be added into the below list */
+	spinlock_t lock;
+	struct list_head head;
+	int state;
+
+#ifdef CONFIG_PM_SLEEP
+	/*
+	 * Names of firmware images which have been cached successfully
+	 * will be added into the below list so that device uncache
+	 * helper can trace which firmware images have been cached
+	 * before.
+	 */
+	spinlock_t name_lock;
+	struct list_head fw_names;
+
+	wait_queue_head_t wait_queue;
+	int cnt;
+	struct delayed_work work;
+
+	struct notifier_block   pm_notify;
+#endif
+};
+
+struct firmware_buf {
+	struct kref ref;
+	struct list_head list;
+	struct completion completion;
+	struct firmware_cache *fwc;
+	unsigned long status;
+	void *data;
+	size_t size;
+	struct page **pages;
+	int nr_pages;
+	int page_array_size;
+	char fw_id[];
+};
+
+struct fw_cache_entry {
+	struct list_head list;
+	char name[];
+};
+
+struct firmware_priv {
+	struct timer_list timeout;
+	bool nowait;
+	struct device dev;
+	struct firmware_buf *buf;
+	struct firmware *fw;
+};
+
+struct fw_name_devm {
+	unsigned long magic;
+	char name[];
+};
+
+#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
+
+#define	FW_LOADER_NO_CACHE	0
+#define	FW_LOADER_START_CACHE	1
+
+static int fw_cache_piggyback_on_request(const char *name);
+
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
 static DEFINE_MUTEX(fw_lock);
 
-struct firmware_priv {
-	struct completion completion;
-	struct firmware *fw;
-	unsigned long status;
-	struct page **pages;
-	int nr_pages;
-	int page_array_size;
-	struct timer_list timeout;
-	struct device dev;
-	bool nowait;
-	char fw_id[];
-};
+static struct firmware_cache fw_cache;
+
+static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
+					      struct firmware_cache *fwc)
+{
+	struct firmware_buf *buf;
+
+	buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1 , GFP_ATOMIC);
+
+	if (!buf)
+		return buf;
+
+	kref_init(&buf->ref);
+	strcpy(buf->fw_id, fw_name);
+	buf->fwc = fwc;
+	init_completion(&buf->completion);
+
+	pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
+
+	return buf;
+}
+
+static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
+{
+	struct firmware_buf *tmp;
+	struct firmware_cache *fwc = &fw_cache;
+
+	list_for_each_entry(tmp, &fwc->head, list)
+		if (!strcmp(tmp->fw_id, fw_name))
+			return tmp;
+	return NULL;
+}
+
+static int fw_lookup_and_allocate_buf(const char *fw_name,
+				      struct firmware_cache *fwc,
+				      struct firmware_buf **buf)
+{
+	struct firmware_buf *tmp;
+
+	spin_lock(&fwc->lock);
+	tmp = __fw_lookup_buf(fw_name);
+	if (tmp) {
+		kref_get(&tmp->ref);
+		spin_unlock(&fwc->lock);
+		*buf = tmp;
+		return 1;
+	}
+	tmp = __allocate_fw_buf(fw_name, fwc);
+	if (tmp)
+		list_add(&tmp->list, &fwc->head);
+	spin_unlock(&fwc->lock);
+
+	*buf = tmp;
+
+	return tmp ? 0 : -ENOMEM;
+}
+
+static struct firmware_buf *fw_lookup_buf(const char *fw_name)
+{
+	struct firmware_buf *tmp;
+	struct firmware_cache *fwc = &fw_cache;
+
+	spin_lock(&fwc->lock);
+	tmp = __fw_lookup_buf(fw_name);
+	spin_unlock(&fwc->lock);
+
+	return tmp;
+}
+
+static void __fw_free_buf(struct kref *ref)
+{
+	struct firmware_buf *buf = to_fwbuf(ref);
+	struct firmware_cache *fwc = buf->fwc;
+	int i;
+
+	pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
+		 __func__, buf->fw_id, buf, buf->data,
+		 (unsigned int)buf->size);
+
+	spin_lock(&fwc->lock);
+	list_del(&buf->list);
+	spin_unlock(&fwc->lock);
+
+	vunmap(buf->data);
+	for (i = 0; i < buf->nr_pages; i++)
+		__free_page(buf->pages[i]);
+	kfree(buf->pages);
+	kfree(buf);
+}
+
+static void fw_free_buf(struct firmware_buf *buf)
+{
+	kref_put(&buf->ref, __fw_free_buf);
+}
 
 static struct firmware_priv *to_firmware_priv(struct device *dev)
 {
@@ -109,9 +261,10 @@
 
 static void fw_load_abort(struct firmware_priv *fw_priv)
 {
-	set_bit(FW_STATUS_ABORT, &fw_priv->status);
-	wmb();
-	complete(&fw_priv->completion);
+	struct firmware_buf *buf = fw_priv->buf;
+
+	set_bit(FW_STATUS_ABORT, &buf->status);
+	complete_all(&buf->completion);
 }
 
 static ssize_t firmware_timeout_show(struct class *class,
@@ -154,11 +307,7 @@
 static void fw_dev_release(struct device *dev)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	int i;
 
-	for (i = 0; i < fw_priv->nr_pages; i++)
-		__free_page(fw_priv->pages[i]);
-	kfree(fw_priv->pages);
 	kfree(fw_priv);
 
 	module_put(THIS_MODULE);
@@ -168,7 +317,7 @@
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 
-	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
+	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id))
 		return -ENOMEM;
 	if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
 		return -ENOMEM;
@@ -189,20 +338,16 @@
 				     struct device_attribute *attr, char *buf)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status);
 
 	return sprintf(buf, "%d\n", loading);
 }
 
+/* firmware holds the ownership of pages */
 static void firmware_free_data(const struct firmware *fw)
 {
-	int i;
-	vunmap(fw->data);
-	if (fw->pages) {
-		for (i = 0; i < PFN_UP(fw->size); i++)
-			__free_page(fw->pages[i]);
-		kfree(fw->pages);
-	}
+	WARN_ON(!fw->priv);
+	fw_free_buf(fw->priv);
 }
 
 /* Some architectures don't have PAGE_KERNEL_RO */
@@ -227,45 +372,33 @@
 				      const char *buf, size_t count)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
+	struct firmware_buf *fw_buf = fw_priv->buf;
 	int loading = simple_strtol(buf, NULL, 10);
 	int i;
 
 	mutex_lock(&fw_lock);
 
-	if (!fw_priv->fw)
+	if (!fw_buf)
 		goto out;
 
 	switch (loading) {
 	case 1:
-		firmware_free_data(fw_priv->fw);
-		memset(fw_priv->fw, 0, sizeof(struct firmware));
-		/* If the pages are not owned by 'struct firmware' */
-		for (i = 0; i < fw_priv->nr_pages; i++)
-			__free_page(fw_priv->pages[i]);
-		kfree(fw_priv->pages);
-		fw_priv->pages = NULL;
-		fw_priv->page_array_size = 0;
-		fw_priv->nr_pages = 0;
-		set_bit(FW_STATUS_LOADING, &fw_priv->status);
+		/* discarding any previous partial load */
+		if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) {
+			for (i = 0; i < fw_buf->nr_pages; i++)
+				__free_page(fw_buf->pages[i]);
+			kfree(fw_buf->pages);
+			fw_buf->pages = NULL;
+			fw_buf->page_array_size = 0;
+			fw_buf->nr_pages = 0;
+			set_bit(FW_STATUS_LOADING, &fw_buf->status);
+		}
 		break;
 	case 0:
-		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
-			vunmap(fw_priv->fw->data);
-			fw_priv->fw->data = vmap(fw_priv->pages,
-						 fw_priv->nr_pages,
-						 0, PAGE_KERNEL_RO);
-			if (!fw_priv->fw->data) {
-				dev_err(dev, "%s: vmap() failed\n", __func__);
-				goto err;
-			}
-			/* Pages are now owned by 'struct firmware' */
-			fw_priv->fw->pages = fw_priv->pages;
-			fw_priv->pages = NULL;
-
-			fw_priv->page_array_size = 0;
-			fw_priv->nr_pages = 0;
-			complete(&fw_priv->completion);
-			clear_bit(FW_STATUS_LOADING, &fw_priv->status);
+		if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
+			set_bit(FW_STATUS_DONE, &fw_buf->status);
+			clear_bit(FW_STATUS_LOADING, &fw_buf->status);
+			complete_all(&fw_buf->completion);
 			break;
 		}
 		/* fallthrough */
@@ -273,7 +406,6 @@
 		dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
 		/* fallthrough */
 	case -1:
-	err:
 		fw_load_abort(fw_priv);
 		break;
 	}
@@ -290,21 +422,21 @@
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	struct firmware *fw;
+	struct firmware_buf *buf;
 	ssize_t ret_count;
 
 	mutex_lock(&fw_lock);
-	fw = fw_priv->fw;
-	if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+	buf = fw_priv->buf;
+	if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
 		ret_count = -ENODEV;
 		goto out;
 	}
-	if (offset > fw->size) {
+	if (offset > buf->size) {
 		ret_count = 0;
 		goto out;
 	}
-	if (count > fw->size - offset)
-		count = fw->size - offset;
+	if (count > buf->size - offset)
+		count = buf->size - offset;
 
 	ret_count = count;
 
@@ -314,11 +446,11 @@
 		int page_ofs = offset & (PAGE_SIZE-1);
 		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
 
-		page_data = kmap(fw_priv->pages[page_nr]);
+		page_data = kmap(buf->pages[page_nr]);
 
 		memcpy(buffer, page_data + page_ofs, page_cnt);
 
-		kunmap(fw_priv->pages[page_nr]);
+		kunmap(buf->pages[page_nr]);
 		buffer += page_cnt;
 		offset += page_cnt;
 		count -= page_cnt;
@@ -330,12 +462,13 @@
 
 static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
+	struct firmware_buf *buf = fw_priv->buf;
 	int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
 
 	/* If the array of pages is too small, grow it... */
-	if (fw_priv->page_array_size < pages_needed) {
+	if (buf->page_array_size < pages_needed) {
 		int new_array_size = max(pages_needed,
-					 fw_priv->page_array_size * 2);
+					 buf->page_array_size * 2);
 		struct page **new_pages;
 
 		new_pages = kmalloc(new_array_size * sizeof(void *),
@@ -344,24 +477,24 @@
 			fw_load_abort(fw_priv);
 			return -ENOMEM;
 		}
-		memcpy(new_pages, fw_priv->pages,
-		       fw_priv->page_array_size * sizeof(void *));
-		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
-		       (new_array_size - fw_priv->page_array_size));
-		kfree(fw_priv->pages);
-		fw_priv->pages = new_pages;
-		fw_priv->page_array_size = new_array_size;
+		memcpy(new_pages, buf->pages,
+		       buf->page_array_size * sizeof(void *));
+		memset(&new_pages[buf->page_array_size], 0, sizeof(void *) *
+		       (new_array_size - buf->page_array_size));
+		kfree(buf->pages);
+		buf->pages = new_pages;
+		buf->page_array_size = new_array_size;
 	}
 
-	while (fw_priv->nr_pages < pages_needed) {
-		fw_priv->pages[fw_priv->nr_pages] =
+	while (buf->nr_pages < pages_needed) {
+		buf->pages[buf->nr_pages] =
 			alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
 
-		if (!fw_priv->pages[fw_priv->nr_pages]) {
+		if (!buf->pages[buf->nr_pages]) {
 			fw_load_abort(fw_priv);
 			return -ENOMEM;
 		}
-		fw_priv->nr_pages++;
+		buf->nr_pages++;
 	}
 	return 0;
 }
@@ -384,18 +517,19 @@
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	struct firmware *fw;
+	struct firmware_buf *buf;
 	ssize_t retval;
 
 	if (!capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
 	mutex_lock(&fw_lock);
-	fw = fw_priv->fw;
-	if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+	buf = fw_priv->buf;
+	if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
 		retval = -ENODEV;
 		goto out;
 	}
+
 	retval = fw_realloc_buffer(fw_priv, offset + count);
 	if (retval)
 		goto out;
@@ -408,17 +542,17 @@
 		int page_ofs = offset & (PAGE_SIZE - 1);
 		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
 
-		page_data = kmap(fw_priv->pages[page_nr]);
+		page_data = kmap(buf->pages[page_nr]);
 
 		memcpy(page_data + page_ofs, buffer, page_cnt);
 
-		kunmap(fw_priv->pages[page_nr]);
+		kunmap(buf->pages[page_nr]);
 		buffer += page_cnt;
 		offset += page_cnt;
 		count -= page_cnt;
 	}
 
-	fw->size = max_t(size_t, offset, fw->size);
+	buf->size = max_t(size_t, offset, buf->size);
 out:
 	mutex_unlock(&fw_lock);
 	return retval;
@@ -445,35 +579,120 @@
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
 
-	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+	fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		return ERR_PTR(-ENOMEM);
+		fw_priv = ERR_PTR(-ENOMEM);
+		goto exit;
 	}
 
-	fw_priv->fw = firmware;
 	fw_priv->nowait = nowait;
-	strcpy(fw_priv->fw_id, fw_name);
-	init_completion(&fw_priv->completion);
+	fw_priv->fw = firmware;
 	setup_timer(&fw_priv->timeout,
 		    firmware_class_timeout, (u_long) fw_priv);
 
 	f_dev = &fw_priv->dev;
 
 	device_initialize(f_dev);
-	dev_set_name(f_dev, "%s", dev_name(device));
+	dev_set_name(f_dev, "%s", fw_name);
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
-
+exit:
 	return fw_priv;
 }
 
+/* one pages buffer is mapped/unmapped only once */
+static int fw_map_pages_buf(struct firmware_buf *buf)
+{
+	buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO);
+	if (!buf->data)
+		return -ENOMEM;
+	return 0;
+}
+
+/* store the pages buffer info firmware from buf */
+static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
+{
+	fw->priv = buf;
+	fw->pages = buf->pages;
+	fw->size = buf->size;
+	fw->data = buf->data;
+
+	pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
+		 __func__, buf->fw_id, buf, buf->data,
+		 (unsigned int)buf->size);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void fw_name_devm_release(struct device *dev, void *res)
+{
+	struct fw_name_devm *fwn = res;
+
+	if (fwn->magic == (unsigned long)&fw_cache)
+		pr_debug("%s: fw_name-%s devm-%p released\n",
+				__func__, fwn->name, res);
+}
+
+static int fw_devm_match(struct device *dev, void *res,
+		void *match_data)
+{
+	struct fw_name_devm *fwn = res;
+
+	return (fwn->magic == (unsigned long)&fw_cache) &&
+		!strcmp(fwn->name, match_data);
+}
+
+static struct fw_name_devm *fw_find_devm_name(struct device *dev,
+		const char *name)
+{
+	struct fw_name_devm *fwn;
+
+	fwn = devres_find(dev, fw_name_devm_release,
+			  fw_devm_match, (void *)name);
+	return fwn;
+}
+
+/* add firmware name into devres list */
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+	struct fw_name_devm *fwn;
+
+	fwn = fw_find_devm_name(dev, name);
+	if (fwn)
+		return 1;
+
+	fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
+			   strlen(name) + 1, GFP_KERNEL);
+	if (!fwn)
+		return -ENOMEM;
+
+	fwn->magic = (unsigned long)&fw_cache;
+	strcpy(fwn->name, name);
+	devres_add(dev, fwn);
+
+	return 0;
+}
+#else
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+	return 0;
+}
+#endif
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
 static struct firmware_priv *
 _request_firmware_prepare(const struct firmware **firmware_p, const char *name,
 			  struct device *device, bool uevent, bool nowait)
 {
 	struct firmware *firmware;
-	struct firmware_priv *fw_priv;
+	struct firmware_priv *fw_priv = NULL;
+	struct firmware_buf *buf;
+	int ret;
 
 	if (!firmware_p)
 		return ERR_PTR(-EINVAL);
@@ -490,18 +709,46 @@
 		return NULL;
 	}
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-	return fw_priv;
-}
+	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+	if (!ret)
+		fw_priv = fw_create_instance(firmware, name, device,
+				uevent, nowait);
 
-static void _request_firmware_cleanup(const struct firmware **firmware_p)
-{
-	release_firmware(*firmware_p);
-	*firmware_p = NULL;
+	if (IS_ERR(fw_priv) || ret < 0) {
+		kfree(firmware);
+		*firmware_p = NULL;
+		return ERR_PTR(-ENOMEM);
+	} else if (fw_priv) {
+		fw_priv->buf = buf;
+
+		/*
+		 * bind with 'buf' now to avoid warning in failure path
+		 * of requesting firmware.
+		 */
+		firmware->priv = buf;
+		return fw_priv;
+	}
+
+	/* share the cached buf, which is inprogessing or completed */
+ check_status:
+	mutex_lock(&fw_lock);
+	if (test_bit(FW_STATUS_ABORT, &buf->status)) {
+		fw_priv = ERR_PTR(-ENOENT);
+		firmware->priv = buf;
+		_request_firmware_cleanup(firmware_p);
+		goto exit;
+	} else if (test_bit(FW_STATUS_DONE, &buf->status)) {
+		fw_priv = NULL;
+		fw_set_page_data(buf, firmware);
+		goto exit;
+	}
+	mutex_unlock(&fw_lock);
+	wait_for_completion(&buf->completion);
+	goto check_status;
+
+exit:
+	mutex_unlock(&fw_lock);
+	return fw_priv;
 }
 
 static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
@@ -509,6 +756,8 @@
 {
 	int retval = 0;
 	struct device *f_dev = &fw_priv->dev;
+	struct firmware_buf *buf = fw_priv->buf;
+	struct firmware_cache *fwc = &fw_cache;
 
 	dev_set_uevent_suppress(f_dev, true);
 
@@ -535,7 +784,7 @@
 
 	if (uevent) {
 		dev_set_uevent_suppress(f_dev, false);
-		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
+		dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
 		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
 				  round_jiffies_up(jiffies + timeout));
@@ -543,15 +792,40 @@
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
 
-	wait_for_completion(&fw_priv->completion);
+	wait_for_completion(&buf->completion);
 
-	set_bit(FW_STATUS_DONE, &fw_priv->status);
 	del_timer_sync(&fw_priv->timeout);
 
 	mutex_lock(&fw_lock);
-	if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
+	if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
 		retval = -ENOENT;
-	fw_priv->fw = NULL;
+
+	/*
+	 * add firmware name into devres list so that we can auto cache
+	 * and uncache firmware for device.
+	 *
+	 * f_dev->parent may has been deleted already, but the problem
+	 * should be fixed in devres or driver core.
+	 */
+	if (!retval && f_dev->parent)
+		fw_add_devm_name(f_dev->parent, buf->fw_id);
+
+	if (!retval)
+		retval = fw_map_pages_buf(buf);
+
+	/*
+	 * After caching firmware image is started, let it piggyback
+	 * on request firmware.
+	 */
+	if (!retval && fwc->state == FW_LOADER_START_CACHE) {
+		if (fw_cache_piggyback_on_request(buf->fw_id))
+			kref_get(&buf->ref);
+	}
+
+	/* pass the pages buffer to driver at the last minute */
+	fw_set_page_data(buf, fw_priv->fw);
+
+	fw_priv->buf = NULL;
 	mutex_unlock(&fw_lock);
 
 	device_remove_file(f_dev, &dev_attr_loading);
@@ -578,6 +852,8 @@
  *      @name will be used as $FIRMWARE in the uevent environment and
  *      should be distinctive enough not to be confused with any other
  *      firmware image for this or any other device.
+ *
+ *	Caller must hold the reference count of @device.
  **/
 int
 request_firmware(const struct firmware **firmware_p, const char *name,
@@ -659,6 +935,7 @@
 
  out:
 	fw_work->cont(fw, fw_work->context);
+	put_device(fw_work->device);
 
 	module_put(fw_work->module);
 	kfree(fw_work);
@@ -677,9 +954,15 @@
  * @cont: function will be called asynchronously when the firmware
  *	request is over.
  *
- *	Asynchronous variant of request_firmware() for user contexts where
- *	it is not possible to sleep for long time. It can't be called
- *	in atomic contexts.
+ *	Caller must hold the reference count of @device.
+ *
+ *	Asynchronous variant of request_firmware() for user contexts:
+ *		- sleep for as small periods as possible since it may
+ *		increase kernel boot time of built-in device drivers
+ *		requesting firmware in their ->probe() methods, if
+ *		@gfp is GFP_KERNEL.
+ *
+ *		- can't sleep at all if @gfp is GFP_ATOMIC.
  **/
 int
 request_firmware_nowait(
@@ -705,18 +988,363 @@
 		return -EFAULT;
 	}
 
+	get_device(fw_work->device);
 	INIT_WORK(&fw_work->work, request_firmware_work_func);
 	schedule_work(&fw_work->work);
 	return 0;
 }
 
+/**
+ * cache_firmware - cache one firmware image in kernel memory space
+ * @fw_name: the firmware image name
+ *
+ * Cache firmware in kernel memory so that drivers can use it when
+ * system isn't ready for them to request firmware image from userspace.
+ * Once it returns successfully, driver can use request_firmware or its
+ * nowait version to get the cached firmware without any interacting
+ * with userspace
+ *
+ * Return 0 if the firmware image has been cached successfully
+ * Return !0 otherwise
+ *
+ */
+int cache_firmware(const char *fw_name)
+{
+	int ret;
+	const struct firmware *fw;
+
+	pr_debug("%s: %s\n", __func__, fw_name);
+
+	ret = request_firmware(&fw, fw_name, NULL);
+	if (!ret)
+		kfree(fw);
+
+	pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret);
+
+	return ret;
+}
+
+/**
+ * uncache_firmware - remove one cached firmware image
+ * @fw_name: the firmware image name
+ *
+ * Uncache one firmware image which has been cached successfully
+ * before.
+ *
+ * Return 0 if the firmware cache has been removed successfully
+ * Return !0 otherwise
+ *
+ */
+int uncache_firmware(const char *fw_name)
+{
+	struct firmware_buf *buf;
+	struct firmware fw;
+
+	pr_debug("%s: %s\n", __func__, fw_name);
+
+	if (fw_get_builtin_firmware(&fw, fw_name))
+		return 0;
+
+	buf = fw_lookup_buf(fw_name);
+	if (buf) {
+		fw_free_buf(buf);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
+{
+	struct fw_cache_entry *fce;
+
+	fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
+	if (!fce)
+		goto exit;
+
+	strcpy(fce->name, name);
+exit:
+	return fce;
+}
+
+static int fw_cache_piggyback_on_request(const char *name)
+{
+	struct firmware_cache *fwc = &fw_cache;
+	struct fw_cache_entry *fce;
+	int ret = 0;
+
+	spin_lock(&fwc->name_lock);
+	list_for_each_entry(fce, &fwc->fw_names, list) {
+		if (!strcmp(fce->name, name))
+			goto found;
+	}
+
+	fce = alloc_fw_cache_entry(name);
+	if (fce) {
+		ret = 1;
+		list_add(&fce->list, &fwc->fw_names);
+		pr_debug("%s: fw: %s\n", __func__, name);
+	}
+found:
+	spin_unlock(&fwc->name_lock);
+	return ret;
+}
+
+static void free_fw_cache_entry(struct fw_cache_entry *fce)
+{
+	kfree(fce);
+}
+
+static void __async_dev_cache_fw_image(void *fw_entry,
+				       async_cookie_t cookie)
+{
+	struct fw_cache_entry *fce = fw_entry;
+	struct firmware_cache *fwc = &fw_cache;
+	int ret;
+
+	ret = cache_firmware(fce->name);
+	if (ret) {
+		spin_lock(&fwc->name_lock);
+		list_del(&fce->list);
+		spin_unlock(&fwc->name_lock);
+
+		free_fw_cache_entry(fce);
+	}
+
+	spin_lock(&fwc->name_lock);
+	fwc->cnt--;
+	spin_unlock(&fwc->name_lock);
+
+	wake_up(&fwc->wait_queue);
+}
+
+/* called with dev->devres_lock held */
+static void dev_create_fw_entry(struct device *dev, void *res,
+				void *data)
+{
+	struct fw_name_devm *fwn = res;
+	const char *fw_name = fwn->name;
+	struct list_head *head = data;
+	struct fw_cache_entry *fce;
+
+	fce = alloc_fw_cache_entry(fw_name);
+	if (fce)
+		list_add(&fce->list, head);
+}
+
+static int devm_name_match(struct device *dev, void *res,
+			   void *match_data)
+{
+	struct fw_name_devm *fwn = res;
+	return (fwn->magic == (unsigned long)match_data);
+}
+
+static void dev_cache_fw_image(struct device *dev, void *data)
+{
+	LIST_HEAD(todo);
+	struct fw_cache_entry *fce;
+	struct fw_cache_entry *fce_next;
+	struct firmware_cache *fwc = &fw_cache;
+
+	devres_for_each_res(dev, fw_name_devm_release,
+			    devm_name_match, &fw_cache,
+			    dev_create_fw_entry, &todo);
+
+	list_for_each_entry_safe(fce, fce_next, &todo, list) {
+		list_del(&fce->list);
+
+		spin_lock(&fwc->name_lock);
+		fwc->cnt++;
+		list_add(&fce->list, &fwc->fw_names);
+		spin_unlock(&fwc->name_lock);
+
+		async_schedule(__async_dev_cache_fw_image, (void *)fce);
+	}
+}
+
+static void __device_uncache_fw_images(void)
+{
+	struct firmware_cache *fwc = &fw_cache;
+	struct fw_cache_entry *fce;
+
+	spin_lock(&fwc->name_lock);
+	while (!list_empty(&fwc->fw_names)) {
+		fce = list_entry(fwc->fw_names.next,
+				struct fw_cache_entry, list);
+		list_del(&fce->list);
+		spin_unlock(&fwc->name_lock);
+
+		uncache_firmware(fce->name);
+		free_fw_cache_entry(fce);
+
+		spin_lock(&fwc->name_lock);
+	}
+	spin_unlock(&fwc->name_lock);
+}
+
+/**
+ * device_cache_fw_images - cache devices' firmware
+ *
+ * If one device called request_firmware or its nowait version
+ * successfully before, the firmware names are recored into the
+ * device's devres link list, so device_cache_fw_images can call
+ * cache_firmware() to cache these firmwares for the device,
+ * then the device driver can load its firmwares easily at
+ * time when system is not ready to complete loading firmware.
+ */
+static void device_cache_fw_images(void)
+{
+	struct firmware_cache *fwc = &fw_cache;
+	int old_timeout;
+	DEFINE_WAIT(wait);
+
+	pr_debug("%s\n", __func__);
+
+	/*
+	 * use small loading timeout for caching devices' firmware
+	 * because all these firmware images have been loaded
+	 * successfully at lease once, also system is ready for
+	 * completing firmware loading now. The maximum size of
+	 * firmware in current distributions is about 2M bytes,
+	 * so 10 secs should be enough.
+	 */
+	old_timeout = loading_timeout;
+	loading_timeout = 10;
+
+	mutex_lock(&fw_lock);
+	fwc->state = FW_LOADER_START_CACHE;
+	dpm_for_each_dev(NULL, dev_cache_fw_image);
+	mutex_unlock(&fw_lock);
+
+	/* wait for completion of caching firmware for all devices */
+	spin_lock(&fwc->name_lock);
+	for (;;) {
+		prepare_to_wait(&fwc->wait_queue, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!fwc->cnt)
+			break;
+
+		spin_unlock(&fwc->name_lock);
+
+		schedule();
+
+		spin_lock(&fwc->name_lock);
+	}
+	spin_unlock(&fwc->name_lock);
+	finish_wait(&fwc->wait_queue, &wait);
+
+	loading_timeout = old_timeout;
+}
+
+/**
+ * device_uncache_fw_images - uncache devices' firmware
+ *
+ * uncache all firmwares which have been cached successfully
+ * by device_uncache_fw_images earlier
+ */
+static void device_uncache_fw_images(void)
+{
+	pr_debug("%s\n", __func__);
+	__device_uncache_fw_images();
+}
+
+static void device_uncache_fw_images_work(struct work_struct *work)
+{
+	device_uncache_fw_images();
+}
+
+/**
+ * device_uncache_fw_images_delay - uncache devices firmwares
+ * @delay: number of milliseconds to delay uncache device firmwares
+ *
+ * uncache all devices's firmwares which has been cached successfully
+ * by device_cache_fw_images after @delay milliseconds.
+ */
+static void device_uncache_fw_images_delay(unsigned long delay)
+{
+	schedule_delayed_work(&fw_cache.work,
+			msecs_to_jiffies(delay));
+}
+
+static int fw_pm_notify(struct notifier_block *notify_block,
+			unsigned long mode, void *unused)
+{
+	switch (mode) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		device_cache_fw_images();
+		break;
+
+	case PM_POST_SUSPEND:
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
+		/*
+		 * In case that system sleep failed and syscore_suspend is
+		 * not called.
+		 */
+		mutex_lock(&fw_lock);
+		fw_cache.state = FW_LOADER_NO_CACHE;
+		mutex_unlock(&fw_lock);
+
+		device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
+		break;
+	}
+
+	return 0;
+}
+
+/* stop caching firmware once syscore_suspend is reached */
+static int fw_suspend(void)
+{
+	fw_cache.state = FW_LOADER_NO_CACHE;
+	return 0;
+}
+
+static struct syscore_ops fw_syscore_ops = {
+	.suspend = fw_suspend,
+};
+#else
+static int fw_cache_piggyback_on_request(const char *name)
+{
+	return 0;
+}
+#endif
+
+static void __init fw_cache_init(void)
+{
+	spin_lock_init(&fw_cache.lock);
+	INIT_LIST_HEAD(&fw_cache.head);
+	fw_cache.state = FW_LOADER_NO_CACHE;
+
+#ifdef CONFIG_PM_SLEEP
+	spin_lock_init(&fw_cache.name_lock);
+	INIT_LIST_HEAD(&fw_cache.fw_names);
+	fw_cache.cnt = 0;
+
+	init_waitqueue_head(&fw_cache.wait_queue);
+	INIT_DELAYED_WORK(&fw_cache.work,
+			  device_uncache_fw_images_work);
+
+	fw_cache.pm_notify.notifier_call = fw_pm_notify;
+	register_pm_notifier(&fw_cache.pm_notify);
+
+	register_syscore_ops(&fw_syscore_ops);
+#endif
+}
+
 static int __init firmware_class_init(void)
 {
+	fw_cache_init();
 	return class_register(&firmware_class);
 }
 
 static void __exit firmware_class_exit(void)
 {
+#ifdef CONFIG_PM_SLEEP
+	unregister_syscore_ops(&fw_syscore_ops);
+	unregister_pm_notifier(&fw_cache.pm_notify);
+#endif
 	class_unregister(&firmware_class);
 }
 
@@ -726,3 +1354,5 @@
 EXPORT_SYMBOL(release_firmware);
 EXPORT_SYMBOL(request_firmware);
 EXPORT_SYMBOL(request_firmware_nowait);
+EXPORT_SYMBOL_GPL(cache_firmware);
+EXPORT_SYMBOL_GPL(uncache_firmware);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index a1a7225..ddeca14 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -20,9 +20,13 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/idr.h>
 
 #include "base.h"
 
+/* For automatically allocated device IDs */
+static DEFINE_IDA(platform_devid_ida);
+
 #define to_platform_driver(drv)	(container_of((drv), struct platform_driver, \
 				 driver))
 
@@ -99,6 +103,9 @@
 	for (i = 0; i < dev->num_resources; i++) {
 		struct resource *r = &dev->resource[i];
 
+		if (unlikely(!r->name))
+			continue;
+
 		if (type == resource_type(r) && !strcmp(r->name, name))
 			return r;
 	}
@@ -263,7 +270,7 @@
  */
 int platform_device_add(struct platform_device *pdev)
 {
-	int i, ret = 0;
+	int i, ret;
 
 	if (!pdev)
 		return -EINVAL;
@@ -273,10 +280,27 @@
 
 	pdev->dev.bus = &platform_bus_type;
 
-	if (pdev->id != -1)
+	switch (pdev->id) {
+	default:
 		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
-	else
+		break;
+	case PLATFORM_DEVID_NONE:
 		dev_set_name(&pdev->dev, "%s", pdev->name);
+		break;
+	case PLATFORM_DEVID_AUTO:
+		/*
+		 * Automatically allocated device ID. We mark it as such so
+		 * that we remember it must be freed, and we append a suffix
+		 * to avoid namespace collision with explicit IDs.
+		 */
+		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
+		if (ret < 0)
+			goto err_out;
+		pdev->id = ret;
+		pdev->id_auto = true;
+		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
+		break;
+	}
 
 	for (i = 0; i < pdev->num_resources; i++) {
 		struct resource *p, *r = &pdev->resource[i];
@@ -309,6 +333,11 @@
 		return ret;
 
  failed:
+	if (pdev->id_auto) {
+		ida_simple_remove(&platform_devid_ida, pdev->id);
+		pdev->id = PLATFORM_DEVID_AUTO;
+	}
+
 	while (--i >= 0) {
 		struct resource *r = &pdev->resource[i];
 		unsigned long type = resource_type(r);
@@ -317,6 +346,7 @@
 			release_resource(r);
 	}
 
+ err_out:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(platform_device_add);
@@ -336,6 +366,11 @@
 	if (pdev) {
 		device_del(&pdev->dev);
 
+		if (pdev->id_auto) {
+			ida_simple_remove(&platform_devid_ida, pdev->id);
+			pdev->id = PLATFORM_DEVID_AUTO;
+		}
+
 		for (i = 0; i < pdev->num_resources; i++) {
 			struct resource *r = &pdev->resource[i];
 			unsigned long type = resource_type(r);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 0113adc..b0b072a8 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1324,3 +1324,25 @@
 	return async_error;
 }
 EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
+
+/**
+ * dpm_for_each_dev - device iterator.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
+ *
+ * Iterate over devices in dpm_list, and call @fn for each device,
+ * passing it @data.
+ */
+void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *))
+{
+	struct device *dev;
+
+	if (!fn)
+		return;
+
+	device_pm_lock();
+	list_for_each_entry(dev, &dpm_list, power.entry)
+		fn(dev, data);
+	device_pm_unlock();
+}
+EXPORT_SYMBOL_GPL(dpm_for_each_dev);
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index a897346..5b6b1d8e 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -16,12 +16,14 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
 struct regmap_irq_chip_data {
 	struct mutex lock;
+	struct irq_chip irq_chip;
 
 	struct regmap *map;
 	const struct regmap_irq_chip *chip;
@@ -59,6 +61,14 @@
 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
 	struct regmap *map = d->map;
 	int i, ret;
+	u32 reg;
+
+	if (d->chip->runtime_pm) {
+		ret = pm_runtime_get_sync(map->dev);
+		if (ret < 0)
+			dev_err(map->dev, "IRQ sync failed to resume: %d\n",
+				ret);
+	}
 
 	/*
 	 * If there's been a change in the mask write it back to the
@@ -66,15 +76,22 @@
 	 * suppress pointless writes.
 	 */
 	for (i = 0; i < d->chip->num_regs; i++) {
-		ret = regmap_update_bits(d->map, d->chip->mask_base +
-						(i * map->reg_stride *
-						d->irq_reg_stride),
+		reg = d->chip->mask_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		if (d->chip->mask_invert)
+			ret = regmap_update_bits(d->map, reg,
+					 d->mask_buf_def[i], ~d->mask_buf[i]);
+		else
+			ret = regmap_update_bits(d->map, reg,
 					 d->mask_buf_def[i], d->mask_buf[i]);
 		if (ret != 0)
 			dev_err(d->map->dev, "Failed to sync masks in %x\n",
-				d->chip->mask_base + (i * map->reg_stride));
+				reg);
 	}
 
+	if (d->chip->runtime_pm)
+		pm_runtime_put(map->dev);
+
 	/* If we've changed our wakeup count propagate it to the parent */
 	if (d->wake_count < 0)
 		for (i = d->wake_count; i < 0; i++)
@@ -128,8 +145,7 @@
 	return 0;
 }
 
-static struct irq_chip regmap_irq_chip = {
-	.name			= "regmap",
+static const struct irq_chip regmap_irq_chip = {
 	.irq_bus_lock		= regmap_irq_lock,
 	.irq_bus_sync_unlock	= regmap_irq_sync_unlock,
 	.irq_disable		= regmap_irq_disable,
@@ -144,6 +160,16 @@
 	struct regmap *map = data->map;
 	int ret, i;
 	bool handled = false;
+	u32 reg;
+
+	if (chip->runtime_pm) {
+		ret = pm_runtime_get_sync(map->dev);
+		if (ret < 0) {
+			dev_err(map->dev, "IRQ thread failed to resume: %d\n",
+				ret);
+			return IRQ_NONE;
+		}
+	}
 
 	/*
 	 * Ignore masked IRQs and ack if we need to; we ack early so
@@ -160,20 +186,20 @@
 		if (ret != 0) {
 			dev_err(map->dev, "Failed to read IRQ status: %d\n",
 					ret);
+			if (chip->runtime_pm)
+				pm_runtime_put(map->dev);
 			return IRQ_NONE;
 		}
 
 		data->status_buf[i] &= ~data->mask_buf[i];
 
 		if (data->status_buf[i] && chip->ack_base) {
-			ret = regmap_write(map, chip->ack_base +
-						(i * map->reg_stride *
-						data->irq_reg_stride),
-					   data->status_buf[i]);
+			reg = chip->ack_base +
+				(i * map->reg_stride * data->irq_reg_stride);
+			ret = regmap_write(map, reg, data->status_buf[i]);
 			if (ret != 0)
 				dev_err(map->dev, "Failed to ack 0x%x: %d\n",
-					chip->ack_base + (i * map->reg_stride),
-					ret);
+					reg, ret);
 		}
 	}
 
@@ -185,6 +211,9 @@
 		}
 	}
 
+	if (chip->runtime_pm)
+		pm_runtime_put(map->dev);
+
 	if (handled)
 		return IRQ_HANDLED;
 	else
@@ -197,7 +226,7 @@
 	struct regmap_irq_chip_data *data = h->host_data;
 
 	irq_set_chip_data(virq, data);
-	irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+	irq_set_chip(virq, &data->irq_chip);
 	irq_set_nested_thread(virq, 1);
 
 	/* ARM needs us to explicitly flag the IRQ as valid
@@ -238,6 +267,7 @@
 	struct regmap_irq_chip_data *d;
 	int i;
 	int ret = -ENOMEM;
+	u32 reg;
 
 	for (i = 0; i < chip->num_irqs; i++) {
 		if (chip->irqs[i].reg_offset % map->reg_stride)
@@ -284,6 +314,13 @@
 			goto err_alloc;
 	}
 
+	d->irq_chip = regmap_irq_chip;
+	d->irq_chip.name = chip->name;
+	if (!chip->wake_base) {
+		d->irq_chip.irq_set_wake = NULL;
+		d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
+				     IRQCHIP_SKIP_SET_WAKE;
+	}
 	d->irq = irq;
 	d->map = map;
 	d->chip = chip;
@@ -303,16 +340,37 @@
 	/* Mask all the interrupts by default */
 	for (i = 0; i < chip->num_regs; i++) {
 		d->mask_buf[i] = d->mask_buf_def[i];
-		ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
-				   * d->irq_reg_stride),
-				   d->mask_buf[i]);
+		reg = chip->mask_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		if (chip->mask_invert)
+			ret = regmap_update_bits(map, reg,
+					 d->mask_buf[i], ~d->mask_buf[i]);
+		else
+			ret = regmap_update_bits(map, reg,
+					 d->mask_buf[i], d->mask_buf[i]);
 		if (ret != 0) {
 			dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
-				chip->mask_base + (i * map->reg_stride), ret);
+				reg, ret);
 			goto err_alloc;
 		}
 	}
 
+	/* Wake is disabled by default */
+	if (d->wake_buf) {
+		for (i = 0; i < chip->num_regs; i++) {
+			d->wake_buf[i] = d->mask_buf_def[i];
+			reg = chip->wake_base +
+				(i * map->reg_stride * d->irq_reg_stride);
+			ret = regmap_update_bits(map, reg, d->wake_buf[i],
+						 d->wake_buf[i]);
+			if (ret != 0) {
+				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+					reg, ret);
+				goto err_alloc;
+			}
+		}
+	}
+
 	if (irq_base)
 		d->domain = irq_domain_add_legacy(map->dev->of_node,
 						  chip->num_irqs, irq_base, 0,
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c241ae2..52069d2 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -659,13 +659,12 @@
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-	int ret;
-
-	map->lock(map);
-
 	regcache_exit(map);
 	regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@
 	map->cache_bypass = false;
 	map->cache_only = false;
 
-	ret = regcache_init(map, config);
-
-	map->unlock(map);
-
-	return ret;
+	return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a796407..f529407 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -353,18 +353,6 @@
 
 	  Use devices /dev/sx8/$N and /dev/sx8/$Np$M.
 
-config BLK_DEV_UB
-	tristate "Low Performance USB Block driver (deprecated)"
-	depends on USB
-	help
-	  This driver supports certain USB attached storage devices
-	  such as flash keys.
-
-	  If you enable this driver, it is recommended to avoid conflicts
-	  with usb-storage by enabling USB_LIBUSUAL.
-
-	  If unsure, say N.
-
 config BLK_DEV_RAM
 	tristate "RAM block device support"
 	---help---
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 5b79505..17e82df 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -33,7 +33,6 @@
 
 obj-$(CONFIG_VIODASD)		+= viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
-obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
 obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= xen-blkfront.o
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index de0435e..887f68f 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -35,6 +35,7 @@
 		skb_reset_mac_header(skb);
 		skb_reset_network_header(skb);
 		skb->protocol = __constant_htons(ETH_P_AOE);
+		skb_checksum_none_assert(skb);
 	}
 	return skb;
 }
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 38aa6dd..da33111 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -795,6 +795,7 @@
 				}
 			break;
 			case CMD_PROTOCOL_ERR:
+				cmd->result = DID_ERROR << 16;
 				dev_warn(&h->pdev->dev,
 					"%p has protocol error\n", c);
                         break;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index a8fddeb..f946d31 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1148,11 +1148,15 @@
 	reply = port->rxfis + RX_FIS_D2H_REG;
 	task_file_data = readl(port->mmio+PORT_TFDATA);
 
-	if ((task_file_data & 1) || (fis->command == ATA_CMD_SEC_ERASE_UNIT))
+	if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
+		clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+
+	if ((task_file_data & 1))
 		return false;
 
 	if (fis->command == ATA_CMD_SEC_ERASE_PREP) {
 		set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+		set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
 		port->ic_pause_timer = jiffies;
 		return true;
 	} else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) &&
@@ -1900,7 +1904,7 @@
 	int rv = 0, xfer_sz = command[3];
 
 	if (xfer_sz) {
-		if (user_buffer)
+		if (!user_buffer)
 			return -EFAULT;
 
 		buf = dmam_alloc_coherent(&port->dd->pdev->dev,
@@ -2043,7 +2047,7 @@
 		*timeout = 240000; /* 4 minutes */
 		break;
 	case ATA_CMD_STANDBYNOW1:
-		*timeout = 10000;  /* 10 seconds */
+		*timeout = 120000;  /* 2 minutes */
 		break;
 	case 0xF7:
 	case 0xFA:
@@ -2588,9 +2592,6 @@
 	if (!len || size)
 		return 0;
 
-	if (size < 0)
-		return -EINVAL;
-
 	size += sprintf(&buf[size], "H/ S ACTive      : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--)
@@ -2660,9 +2661,6 @@
 	if (!len || size)
 		return 0;
 
-	if (size < 0)
-		return -EINVAL;
-
 	size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
 							dd->port->flags);
 	size += sprintf(&buf[size], "Flag-dd   : [ %08lX ]\n",
@@ -3214,8 +3212,8 @@
 				"Unable to check write protect progress\n");
 	else
 		dev_info(&dd->pdev->dev,
-				"Write protect progress: %d%% (%d blocks)\n",
-				attr242.cur, attr242.data);
+				"Write protect progress: %u%% (%u blocks)\n",
+				attr242.cur, le32_to_cpu(attr242.data));
 	return rv;
 
 out3:
@@ -3619,6 +3617,10 @@
 			bio_endio(bio, -ENODATA);
 			return;
 		}
+		if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) {
+			bio_endio(bio, -ENODATA);
+			return;
+		}
 	}
 
 	if (unlikely(!bio_has_data(bio))) {
@@ -4168,7 +4170,13 @@
 
 /* Table of device ids supported by this driver. */
 static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = {
-	{  PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320H_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320M_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320S_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P325M_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420H_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420M_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P425M_DEVICE_ID) },
 	{ 0 }
 };
 
@@ -4199,12 +4207,12 @@
 {
 	int error;
 
-	printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
+	pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
 
 	/* Allocate a major block device number to use with this driver. */
 	error = register_blkdev(0, MTIP_DRV_NAME);
 	if (error <= 0) {
-		printk(KERN_ERR "Unable to register block device (%d)\n",
+		pr_err("Unable to register block device (%d)\n",
 		error);
 		return -EBUSY;
 	}
@@ -4213,7 +4221,7 @@
 	if (!dfs_parent) {
 		dfs_parent = debugfs_create_dir("rssd", NULL);
 		if (IS_ERR_OR_NULL(dfs_parent)) {
-			printk(KERN_WARNING "Error creating debugfs parent\n");
+			pr_warn("Error creating debugfs parent\n");
 			dfs_parent = NULL;
 		}
 	}
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index f51fc23..18627a1 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -76,7 +76,13 @@
 
 /* Micron Vendor ID & P320x SSD Device ID */
 #define PCI_VENDOR_ID_MICRON    0x1344
-#define P320_DEVICE_ID		0x5150
+#define P320H_DEVICE_ID		0x5150
+#define P320M_DEVICE_ID		0x5151
+#define P320S_DEVICE_ID		0x5152
+#define P325M_DEVICE_ID		0x5153
+#define P420H_DEVICE_ID		0x5160
+#define P420M_DEVICE_ID		0x5161
+#define P425M_DEVICE_ID		0x5163
 
 /* Driver name and version strings */
 #define MTIP_DRV_NAME		"mtip32xx"
@@ -131,10 +137,12 @@
 	MTIP_PF_SVC_THD_STOP_BIT    = 8,
 
 	/* below are bit numbers in 'dd_flag' defined in driver_data */
+	MTIP_DDF_SEC_LOCK_BIT	    = 0,
 	MTIP_DDF_REMOVE_PENDING_BIT = 1,
 	MTIP_DDF_OVER_TEMP_BIT      = 2,
 	MTIP_DDF_WRITE_PROTECT_BIT  = 3,
 	MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \
+				(1 << MTIP_DDF_SEC_LOCK_BIT) | \
 				(1 << MTIP_DDF_OVER_TEMP_BIT) | \
 				(1 << MTIP_DDF_WRITE_PROTECT_BIT)),
 
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index d07c9f7..0c03411 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -449,6 +449,14 @@
 		req->errors++;
 		nbd_end_request(req);
 	}
+
+	while (!list_empty(&nbd->waiting_queue)) {
+		req = list_entry(nbd->waiting_queue.next, struct request,
+				 queuelist);
+		list_del_init(&req->queuelist);
+		req->errors++;
+		nbd_end_request(req);
+	}
 }
 
 
@@ -598,6 +606,7 @@
 		nbd->file = NULL;
 		nbd_clear_que(nbd);
 		BUG_ON(!list_empty(&nbd->queue_head));
+		BUG_ON(!list_empty(&nbd->waiting_queue));
 		if (file)
 			fput(file);
 		return 0;
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 38a2d06..931769e 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -79,6 +79,7 @@
 	char serial[20];
 	char model[40];
 	char firmware_rev[8];
+	u32 max_hw_sectors;
 };
 
 /*
@@ -835,15 +836,15 @@
 }
 
 static int nvme_get_features(struct nvme_dev *dev, unsigned fid,
-				unsigned dword11, dma_addr_t dma_addr)
+				unsigned nsid, dma_addr_t dma_addr)
 {
 	struct nvme_command c;
 
 	memset(&c, 0, sizeof(c));
 	c.features.opcode = nvme_admin_get_features;
+	c.features.nsid = cpu_to_le32(nsid);
 	c.features.prp1 = cpu_to_le64(dma_addr);
 	c.features.fid = cpu_to_le32(fid);
-	c.features.dword11 = cpu_to_le32(dword11);
 
 	return nvme_submit_admin_cmd(dev, &c, NULL);
 }
@@ -862,11 +863,51 @@
 	return nvme_submit_admin_cmd(dev, &c, result);
 }
 
+/**
+ * nvme_cancel_ios - Cancel outstanding I/Os
+ * @queue: The queue to cancel I/Os on
+ * @timeout: True to only cancel I/Os which have timed out
+ */
+static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
+{
+	int depth = nvmeq->q_depth - 1;
+	struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+	unsigned long now = jiffies;
+	int cmdid;
+
+	for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
+		void *ctx;
+		nvme_completion_fn fn;
+		static struct nvme_completion cqe = {
+			.status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1,
+		};
+
+		if (timeout && !time_after(now, info[cmdid].timeout))
+			continue;
+		dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid);
+		ctx = cancel_cmdid(nvmeq, cmdid, &fn);
+		fn(nvmeq->dev, ctx, &cqe);
+	}
+}
+
+static void nvme_free_queue_mem(struct nvme_queue *nvmeq)
+{
+	dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
+				(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
+	dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
+					nvmeq->sq_cmds, nvmeq->sq_dma_addr);
+	kfree(nvmeq);
+}
+
 static void nvme_free_queue(struct nvme_dev *dev, int qid)
 {
 	struct nvme_queue *nvmeq = dev->queues[qid];
 	int vector = dev->entry[nvmeq->cq_vector].vector;
 
+	spin_lock_irq(&nvmeq->q_lock);
+	nvme_cancel_ios(nvmeq, false);
+	spin_unlock_irq(&nvmeq->q_lock);
+
 	irq_set_affinity_hint(vector, NULL);
 	free_irq(vector, nvmeq);
 
@@ -876,18 +917,15 @@
 		adapter_delete_cq(dev, qid);
 	}
 
-	dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
-				(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
-	dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
-					nvmeq->sq_cmds, nvmeq->sq_dma_addr);
-	kfree(nvmeq);
+	nvme_free_queue_mem(nvmeq);
 }
 
 static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
 							int depth, int vector)
 {
 	struct device *dmadev = &dev->pci_dev->dev;
-	unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info));
+	unsigned extra = DIV_ROUND_UP(depth, 8) + (depth *
+						sizeof(struct nvme_cmd_info));
 	struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL);
 	if (!nvmeq)
 		return NULL;
@@ -975,7 +1013,7 @@
 
 static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
 {
-	int result;
+	int result = 0;
 	u32 aqa;
 	u64 cap;
 	unsigned long timeout;
@@ -1005,17 +1043,22 @@
 	timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
 	dev->db_stride = NVME_CAP_STRIDE(cap);
 
-	while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
+	while (!result && !(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
 		msleep(100);
 		if (fatal_signal_pending(current))
-			return -EINTR;
+			result = -EINTR;
 		if (time_after(jiffies, timeout)) {
 			dev_err(&dev->pci_dev->dev,
 				"Device not ready; aborting initialisation\n");
-			return -ENODEV;
+			result = -ENODEV;
 		}
 	}
 
+	if (result) {
+		nvme_free_queue_mem(nvmeq);
+		return result;
+	}
+
 	result = queue_request_irq(dev, nvmeq, "nvme admin");
 	dev->queues[0] = nvmeq;
 	return result;
@@ -1037,6 +1080,8 @@
 	offset = offset_in_page(addr);
 	count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
 	pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
+	if (!pages)
+		return ERR_PTR(-ENOMEM);
 
 	err = get_user_pages_fast(addr, count, 1, pages);
 	if (err < count) {
@@ -1146,14 +1191,13 @@
 	return status;
 }
 
-static int nvme_user_admin_cmd(struct nvme_ns *ns,
+static int nvme_user_admin_cmd(struct nvme_dev *dev,
 					struct nvme_admin_cmd __user *ucmd)
 {
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_admin_cmd cmd;
 	struct nvme_command c;
 	int status, length;
-	struct nvme_iod *iod;
+	struct nvme_iod *uninitialized_var(iod);
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -1204,7 +1248,7 @@
 	case NVME_IOCTL_ID:
 		return ns->ns_id;
 	case NVME_IOCTL_ADMIN_CMD:
-		return nvme_user_admin_cmd(ns, (void __user *)arg);
+		return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
 	case NVME_IOCTL_SUBMIT_IO:
 		return nvme_submit_io(ns, (void __user *)arg);
 	default:
@@ -1218,26 +1262,6 @@
 	.compat_ioctl	= nvme_ioctl,
 };
 
-static void nvme_timeout_ios(struct nvme_queue *nvmeq)
-{
-	int depth = nvmeq->q_depth - 1;
-	struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
-	unsigned long now = jiffies;
-	int cmdid;
-
-	for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
-		void *ctx;
-		nvme_completion_fn fn;
-		static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, };
-
-		if (!time_after(now, info[cmdid].timeout))
-			continue;
-		dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid);
-		ctx = cancel_cmdid(nvmeq, cmdid, &fn);
-		fn(nvmeq->dev, ctx, &cqe);
-	}
-}
-
 static void nvme_resubmit_bios(struct nvme_queue *nvmeq)
 {
 	while (bio_list_peek(&nvmeq->sq_cong)) {
@@ -1269,7 +1293,7 @@
 				spin_lock_irq(&nvmeq->q_lock);
 				if (nvme_process_cq(nvmeq))
 					printk("process_cq did something\n");
-				nvme_timeout_ios(nvmeq);
+				nvme_cancel_ios(nvmeq, true);
 				nvme_resubmit_bios(nvmeq);
 				spin_unlock_irq(&nvmeq->q_lock);
 			}
@@ -1339,6 +1363,9 @@
 	ns->disk = disk;
 	lbaf = id->flbas & 0xf;
 	ns->lba_shift = id->lbaf[lbaf].ds;
+	blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
+	if (dev->max_hw_sectors)
+		blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
 
 	disk->major = nvme_major;
 	disk->minors = NVME_MINORS;
@@ -1383,7 +1410,7 @@
 
 static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
 {
-	int result, cpu, i, nr_io_queues, db_bar_size;
+	int result, cpu, i, nr_io_queues, db_bar_size, q_depth;
 
 	nr_io_queues = num_online_cpus();
 	result = set_queue_count(dev, nr_io_queues);
@@ -1429,9 +1456,10 @@
 		cpu = cpumask_next(cpu, cpu_online_mask);
 	}
 
+	q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1,
+								NVME_Q_DEPTH);
 	for (i = 0; i < nr_io_queues; i++) {
-		dev->queues[i + 1] = nvme_create_queue(dev, i + 1,
-							NVME_Q_DEPTH, i);
+		dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i);
 		if (IS_ERR(dev->queues[i + 1]))
 			return PTR_ERR(dev->queues[i + 1]);
 		dev->queue_count++;
@@ -1480,6 +1508,10 @@
 	memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
 	memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
 	memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
+	if (ctrl->mdts) {
+		int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
+		dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9);
+	}
 
 	id_ns = mem;
 	for (i = 1; i <= nn; i++) {
@@ -1523,8 +1555,6 @@
 	list_del(&dev->node);
 	spin_unlock(&dev_list_lock);
 
-	/* TODO: wait all I/O finished or cancel them */
-
 	list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
 		list_del(&ns->list);
 		del_gendisk(ns->disk);
@@ -1560,15 +1590,33 @@
 	dma_pool_destroy(dev->prp_small_pool);
 }
 
-/* XXX: Use an ida or something to let remove / add work correctly */
-static void nvme_set_instance(struct nvme_dev *dev)
+static DEFINE_IDA(nvme_instance_ida);
+
+static int nvme_set_instance(struct nvme_dev *dev)
 {
-	static int instance;
-	dev->instance = instance++;
+	int instance, error;
+
+	do {
+		if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL))
+			return -ENODEV;
+
+		spin_lock(&dev_list_lock);
+		error = ida_get_new(&nvme_instance_ida, &instance);
+		spin_unlock(&dev_list_lock);
+	} while (error == -EAGAIN);
+
+	if (error)
+		return -ENODEV;
+
+	dev->instance = instance;
+	return 0;
 }
 
 static void nvme_release_instance(struct nvme_dev *dev)
 {
+	spin_lock(&dev_list_lock);
+	ida_remove(&nvme_instance_ida, dev->instance);
+	spin_unlock(&dev_list_lock);
 }
 
 static int __devinit nvme_probe(struct pci_dev *pdev,
@@ -1601,7 +1649,10 @@
 	pci_set_drvdata(pdev, dev);
 	dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
 	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-	nvme_set_instance(dev);
+	result = nvme_set_instance(dev);
+	if (result)
+		goto disable;
+
 	dev->entry[0].vector = pdev->irq;
 
 	result = nvme_setup_prp_pools(dev);
@@ -1675,7 +1726,7 @@
 #define nvme_suspend NULL
 #define nvme_resume NULL
 
-static struct pci_error_handlers nvme_err_handler = {
+static const struct pci_error_handlers nvme_err_handler = {
 	.error_detected	= nvme_error_detected,
 	.mmio_enabled	= nvme_dump_registers,
 	.link_reset	= nvme_link_reset,
@@ -1704,15 +1755,17 @@
 
 static int __init nvme_init(void)
 {
-	int result = -EBUSY;
+	int result;
 
 	nvme_thread = kthread_run(nvme_kthread, NULL, "nvme");
 	if (IS_ERR(nvme_thread))
 		return PTR_ERR(nvme_thread);
 
-	nvme_major = register_blkdev(nvme_major, "nvme");
-	if (nvme_major <= 0)
+	result = register_blkdev(nvme_major, "nvme");
+	if (result < 0)
 		goto kill_kthread;
+	else if (result > 0)
+		nvme_major = result;
 
 	result = pci_register_driver(&nvme_driver);
 	if (result)
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 9917943..54a55f0 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -246,13 +246,12 @@
 {
 	struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
 
-	rbd_get_dev(rbd_dev);
-
-	set_device_ro(bdev, rbd_dev->read_only);
-
 	if ((mode & FMODE_WRITE) && rbd_dev->read_only)
 		return -EROFS;
 
+	rbd_get_dev(rbd_dev);
+	set_device_ro(bdev, rbd_dev->read_only);
+
 	return 0;
 }
 
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
deleted file mode 100644
index fcec022..0000000
--- a/drivers/block/ub.c
+++ /dev/null
@@ -1,2474 +0,0 @@
-/*
- * The low performance USB storage driver (ub).
- *
- * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
- * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com)
- *
- * This work is a part of Linux kernel, is derived from it,
- * and is not licensed separately. See file COPYING for details.
- *
- * TODO (sorted by decreasing priority)
- *  -- Return sense now that rq allows it (we always auto-sense anyway).
- *  -- set readonly flag for CDs, set removable flag for CF readers
- *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
- *  -- verify the 13 conditions and do bulk resets
- *  -- highmem
- *  -- move top_sense and work_bcs into separate allocations (if they survive)
- *     for cache purists and esoteric architectures.
- *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
- *  -- prune comments, they are too volumnous
- *  -- Resove XXX's
- *  -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb_usual.h>
-#include <linux/blkdev.h>
-#include <linux/timer.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <scsi/scsi.h>
-
-#define DRV_NAME "ub"
-
-#define UB_MAJOR 180
-
-/*
- * The command state machine is the key model for understanding of this driver.
- *
- * The general rule is that all transitions are done towards the bottom
- * of the diagram, thus preventing any loops.
- *
- * An exception to that is how the STAT state is handled. A counter allows it
- * to be re-entered along the path marked with [C].
- *
- *       +--------+
- *       ! INIT   !
- *       +--------+
- *           !
- *        ub_scsi_cmd_start fails ->--------------------------------------\
- *           !                                                            !
- *           V                                                            !
- *       +--------+                                                       !
- *       ! CMD    !                                                       !
- *       +--------+                                                       !
- *           !                                            +--------+      !
- *         was -EPIPE -->-------------------------------->! CLEAR  !      !
- *           !                                            +--------+      !
- *           !                                                !           !
- *         was error -->------------------------------------- ! --------->\
- *           !                                                !           !
- *  /--<-- cmd->dir == NONE ?                                 !           !
- *  !        !                                                !           !
- *  !        V                                                !           !
- *  !    +--------+                                           !           !
- *  !    ! DATA   !                                           !           !
- *  !    +--------+                                           !           !
- *  !        !                           +---------+          !           !
- *  !      was -EPIPE -->--------------->! CLR2STS !          !           !
- *  !        !                           +---------+          !           !
- *  !        !                                !               !           !
- *  !        !                              was error -->---- ! --------->\
- *  !      was error -->--------------------- ! ------------- ! --------->\
- *  !        !                                !               !           !
- *  !        V                                !               !           !
- *  \--->+--------+                           !               !           !
- *       ! STAT   !<--------------------------/               !           !
- *  /--->+--------+                                           !           !
- *  !        !                                                !           !
- * [C]     was -EPIPE -->-----------\                         !           !
- *  !        !                      !                         !           !
- *  +<---- len == 0                 !                         !           !
- *  !        !                      !                         !           !
- *  !      was error -->--------------------------------------!---------->\
- *  !        !                      !                         !           !
- *  +<---- bad CSW                  !                         !           !
- *  +<---- bad tag                  !                         !           !
- *  !        !                      V                         !           !
- *  !        !                 +--------+                     !           !
- *  !        !                 ! CLRRS  !                     !           !
- *  !        !                 +--------+                     !           !
- *  !        !                      !                         !           !
- *  \------- ! --------------------[C]--------\               !           !
- *           !                                !               !           !
- *         cmd->error---\                +--------+           !           !
- *           !          +--------------->! SENSE  !<----------/           !
- *         STAT_FAIL----/                +--------+                       !
- *           !                                !                           V
- *           !                                V                      +--------+
- *           \--------------------------------\--------------------->! DONE   !
- *                                                                   +--------+
- */
-
-/*
- * This many LUNs per USB device.
- * Every one of them takes a host, see UB_MAX_HOSTS.
- */
-#define UB_MAX_LUNS   9
-
-/*
- */
-
-#define UB_PARTS_PER_LUN      8
-
-#define UB_MAX_CDB_SIZE      16		/* Corresponds to Bulk */
-
-#define UB_SENSE_SIZE  18
-
-/*
- */
-struct ub_dev;
-
-#define UB_MAX_REQ_SG	9	/* cdrecord requires 32KB and maybe a header */
-#define UB_MAX_SECTORS 64
-
-/*
- * A second is more than enough for a 32K transfer (UB_MAX_SECTORS)
- * even if a webcam hogs the bus, but some devices need time to spin up.
- */
-#define UB_URB_TIMEOUT	(HZ*2)
-#define UB_DATA_TIMEOUT	(HZ*5)	/* ZIP does spin-ups in the data phase */
-#define UB_STAT_TIMEOUT	(HZ*5)	/* Same spinups and eject for a dataless cmd. */
-#define UB_CTRL_TIMEOUT	(HZ/2)	/* 500ms ought to be enough to clear a stall */
-
-/*
- * An instance of a SCSI command in transit.
- */
-#define UB_DIR_NONE	0
-#define UB_DIR_READ	1
-#define UB_DIR_ILLEGAL2	2
-#define UB_DIR_WRITE	3
-
-#define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
-			 (((c)==UB_DIR_READ)? 'r': 'n'))
-
-enum ub_scsi_cmd_state {
-	UB_CMDST_INIT,			/* Initial state */
-	UB_CMDST_CMD,			/* Command submitted */
-	UB_CMDST_DATA,			/* Data phase */
-	UB_CMDST_CLR2STS,		/* Clearing before requesting status */
-	UB_CMDST_STAT,			/* Status phase */
-	UB_CMDST_CLEAR,			/* Clearing a stall (halt, actually) */
-	UB_CMDST_CLRRS,			/* Clearing before retrying status */
-	UB_CMDST_SENSE,			/* Sending Request Sense */
-	UB_CMDST_DONE			/* Final state */
-};
-
-struct ub_scsi_cmd {
-	unsigned char cdb[UB_MAX_CDB_SIZE];
-	unsigned char cdb_len;
-
-	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
-	enum ub_scsi_cmd_state state;
-	unsigned int tag;
-	struct ub_scsi_cmd *next;
-
-	int error;			/* Return code - valid upon done */
-	unsigned int act_len;		/* Return size */
-	unsigned char key, asc, ascq;	/* May be valid if error==-EIO */
-
-	int stat_count;			/* Retries getting status. */
-	unsigned int timeo;		/* jiffies until rq->timeout changes */
-
-	unsigned int len;		/* Requested length */
-	unsigned int current_sg;
-	unsigned int nsg;		/* sgv[nsg] */
-	struct scatterlist sgv[UB_MAX_REQ_SG];
-
-	struct ub_lun *lun;
-	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
-	void *back;
-};
-
-struct ub_request {
-	struct request *rq;
-	unsigned int current_try;
-	unsigned int nsg;		/* sgv[nsg] */
-	struct scatterlist sgv[UB_MAX_REQ_SG];
-};
-
-/*
- */
-struct ub_capacity {
-	unsigned long nsec;		/* Linux size - 512 byte sectors */
-	unsigned int bsize;		/* Linux hardsect_size */
-	unsigned int bshift;		/* Shift between 512 and hard sects */
-};
-
-/*
- * This is a direct take-off from linux/include/completion.h
- * The difference is that I do not wait on this thing, just poll.
- * When I want to wait (ub_probe), I just use the stock completion.
- *
- * Note that INIT_COMPLETION takes no lock. It is correct. But why
- * in the bloody hell that thing takes struct instead of pointer to struct
- * is quite beyond me. I just copied it from the stock completion.
- */
-struct ub_completion {
-	unsigned int done;
-	spinlock_t lock;
-};
-
-static DEFINE_MUTEX(ub_mutex);
-static inline void ub_init_completion(struct ub_completion *x)
-{
-	x->done = 0;
-	spin_lock_init(&x->lock);
-}
-
-#define UB_INIT_COMPLETION(x)	((x).done = 0)
-
-static void ub_complete(struct ub_completion *x)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&x->lock, flags);
-	x->done++;
-	spin_unlock_irqrestore(&x->lock, flags);
-}
-
-static int ub_is_completed(struct ub_completion *x)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&x->lock, flags);
-	ret = x->done;
-	spin_unlock_irqrestore(&x->lock, flags);
-	return ret;
-}
-
-/*
- */
-struct ub_scsi_cmd_queue {
-	int qlen, qmax;
-	struct ub_scsi_cmd *head, *tail;
-};
-
-/*
- * The block device instance (one per LUN).
- */
-struct ub_lun {
-	struct ub_dev *udev;
-	struct list_head link;
-	struct gendisk *disk;
-	int id;				/* Host index */
-	int num;			/* LUN number */
-	char name[16];
-
-	int changed;			/* Media was changed */
-	int removable;
-	int readonly;
-
-	struct ub_request urq;
-
-	/* Use Ingo's mempool if or when we have more than one command. */
-	/*
-	 * Currently we never need more than one command for the whole device.
-	 * However, giving every LUN a command is a cheap and automatic way
-	 * to enforce fairness between them.
-	 */
-	int cmda[1];
-	struct ub_scsi_cmd cmdv[1];
-
-	struct ub_capacity capacity; 
-};
-
-/*
- * The USB device instance.
- */
-struct ub_dev {
-	spinlock_t *lock;
-	atomic_t poison;		/* The USB device is disconnected */
-	int openc;			/* protected by ub_lock! */
-					/* kref is too implicit for our taste */
-	int reset;			/* Reset is running */
-	int bad_resid;
-	unsigned int tagcnt;
-	char name[12];
-	struct usb_device *dev;
-	struct usb_interface *intf;
-
-	struct list_head luns;
-
-	unsigned int send_bulk_pipe;	/* cached pipe values */
-	unsigned int recv_bulk_pipe;
-	unsigned int send_ctrl_pipe;
-	unsigned int recv_ctrl_pipe;
-
-	struct tasklet_struct tasklet;
-
-	struct ub_scsi_cmd_queue cmd_queue;
-	struct ub_scsi_cmd top_rqs_cmd;	/* REQUEST SENSE */
-	unsigned char top_sense[UB_SENSE_SIZE];
-
-	struct ub_completion work_done;
-	struct urb work_urb;
-	struct timer_list work_timer;
-	int last_pipe;			/* What might need clearing */
-	__le32 signature;		/* Learned signature */
-	struct bulk_cb_wrap work_bcb;
-	struct bulk_cs_wrap work_bcs;
-	struct usb_ctrlrequest work_cr;
-
-	struct work_struct reset_work;
-	wait_queue_head_t reset_wait;
-};
-
-/*
- */
-static void ub_cleanup(struct ub_dev *sc);
-static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
-static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq);
-static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq);
-static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_end_rq(struct request *rq, unsigned int status);
-static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_request *urq, struct ub_scsi_cmd *cmd);
-static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_urb_complete(struct urb *urb);
-static void ub_scsi_action(unsigned long _dev);
-static void ub_scsi_dispatch(struct ub_dev *sc);
-static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
-static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    int stalled_pipe);
-static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
-static void ub_reset_enter(struct ub_dev *sc, int try);
-static void ub_reset_task(struct work_struct *work);
-static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_capacity *ret);
-static int ub_sync_reset(struct ub_dev *sc);
-static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
-static int ub_probe_lun(struct ub_dev *sc, int lnum);
-
-/*
- */
-#ifdef CONFIG_USB_LIBUSUAL
-
-#define ub_usb_ids  usb_storage_usb_ids
-#else
-
-static const struct usb_device_id ub_usb_ids[] = {
-	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, ub_usb_ids);
-#endif /* CONFIG_USB_LIBUSUAL */
-
-/*
- * Find me a way to identify "next free minor" for add_disk(),
- * and the array disappears the next day. However, the number of
- * hosts has something to do with the naming and /proc/partitions.
- * This has to be thought out in detail before changing.
- * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure.
- */
-#define UB_MAX_HOSTS  26
-static char ub_hostv[UB_MAX_HOSTS];
-
-#define UB_QLOCK_NUM 5
-static spinlock_t ub_qlockv[UB_QLOCK_NUM];
-static int ub_qlock_next = 0;
-
-static DEFINE_SPINLOCK(ub_lock);	/* Locks globals and ->openc */
-
-/*
- * The id allocator.
- *
- * This also stores the host for indexing by minor, which is somewhat dirty.
- */
-static int ub_id_get(void)
-{
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&ub_lock, flags);
-	for (i = 0; i < UB_MAX_HOSTS; i++) {
-		if (ub_hostv[i] == 0) {
-			ub_hostv[i] = 1;
-			spin_unlock_irqrestore(&ub_lock, flags);
-			return i;
-		}
-	}
-	spin_unlock_irqrestore(&ub_lock, flags);
-	return -1;
-}
-
-static void ub_id_put(int id)
-{
-	unsigned long flags;
-
-	if (id < 0 || id >= UB_MAX_HOSTS) {
-		printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
-		return;
-	}
-
-	spin_lock_irqsave(&ub_lock, flags);
-	if (ub_hostv[id] == 0) {
-		spin_unlock_irqrestore(&ub_lock, flags);
-		printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
-		return;
-	}
-	ub_hostv[id] = 0;
-	spin_unlock_irqrestore(&ub_lock, flags);
-}
-
-/*
- * This is necessitated by the fact that blk_cleanup_queue does not
- * necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
- * Since our blk_init_queue() passes a spinlock common with ub_dev,
- * we have life time issues when ub_cleanup frees ub_dev.
- */
-static spinlock_t *ub_next_lock(void)
-{
-	unsigned long flags;
-	spinlock_t *ret;
-
-	spin_lock_irqsave(&ub_lock, flags);
-	ret = &ub_qlockv[ub_qlock_next];
-	ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
-	spin_unlock_irqrestore(&ub_lock, flags);
-	return ret;
-}
-
-/*
- * Downcount for deallocation. This rides on two assumptions:
- *  - once something is poisoned, its refcount cannot grow
- *  - opens cannot happen at this time (del_gendisk was done)
- * If the above is true, we can drop the lock, which we need for
- * blk_cleanup_queue(): the silly thing may attempt to sleep.
- * [Actually, it never needs to sleep for us, but it calls might_sleep()]
- */
-static void ub_put(struct ub_dev *sc)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ub_lock, flags);
-	--sc->openc;
-	if (sc->openc == 0 && atomic_read(&sc->poison)) {
-		spin_unlock_irqrestore(&ub_lock, flags);
-		ub_cleanup(sc);
-	} else {
-		spin_unlock_irqrestore(&ub_lock, flags);
-	}
-}
-
-/*
- * Final cleanup and deallocation.
- */
-static void ub_cleanup(struct ub_dev *sc)
-{
-	struct list_head *p;
-	struct ub_lun *lun;
-	struct request_queue *q;
-
-	while (!list_empty(&sc->luns)) {
-		p = sc->luns.next;
-		lun = list_entry(p, struct ub_lun, link);
-		list_del(p);
-
-		/* I don't think queue can be NULL. But... Stolen from sx8.c */
-		if ((q = lun->disk->queue) != NULL)
-			blk_cleanup_queue(q);
-		/*
-		 * If we zero disk->private_data BEFORE put_disk, we have
-		 * to check for NULL all over the place in open, release,
-		 * check_media and revalidate, because the block level
-		 * semaphore is well inside the put_disk.
-		 * But we cannot zero after the call, because *disk is gone.
-		 * The sd.c is blatantly racy in this area.
-		 */
-		/* disk->private_data = NULL; */
-		put_disk(lun->disk);
-		lun->disk = NULL;
-
-		ub_id_put(lun->id);
-		kfree(lun);
-	}
-
-	usb_set_intfdata(sc->intf, NULL);
-	usb_put_intf(sc->intf);
-	usb_put_dev(sc->dev);
-	kfree(sc);
-}
-
-/*
- * The "command allocator".
- */
-static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun)
-{
-	struct ub_scsi_cmd *ret;
-
-	if (lun->cmda[0])
-		return NULL;
-	ret = &lun->cmdv[0];
-	lun->cmda[0] = 1;
-	return ret;
-}
-
-static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd)
-{
-	if (cmd != &lun->cmdv[0]) {
-		printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
-		    lun->name, cmd);
-		return;
-	}
-	if (!lun->cmda[0]) {
-		printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name);
-		return;
-	}
-	lun->cmda[0] = 0;
-}
-
-/*
- * The command queue.
- */
-static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-
-	if (t->qlen++ == 0) {
-		t->head = cmd;
-		t->tail = cmd;
-	} else {
-		t->tail->next = cmd;
-		t->tail = cmd;
-	}
-
-	if (t->qlen > t->qmax)
-		t->qmax = t->qlen;
-}
-
-static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-
-	if (t->qlen++ == 0) {
-		t->head = cmd;
-		t->tail = cmd;
-	} else {
-		cmd->next = t->head;
-		t->head = cmd;
-	}
-
-	if (t->qlen > t->qmax)
-		t->qmax = t->qlen;
-}
-
-static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
-{
-	struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-	struct ub_scsi_cmd *cmd;
-
-	if (t->qlen == 0)
-		return NULL;
-	if (--t->qlen == 0)
-		t->tail = NULL;
-	cmd = t->head;
-	t->head = cmd->next;
-	cmd->next = NULL;
-	return cmd;
-}
-
-#define ub_cmdq_peek(sc)  ((sc)->cmd_queue.head)
-
-/*
- * The request function is our main entry point
- */
-
-static void ub_request_fn(struct request_queue *q)
-{
-	struct ub_lun *lun = q->queuedata;
-	struct request *rq;
-
-	while ((rq = blk_peek_request(q)) != NULL) {
-		if (ub_request_fn_1(lun, rq) != 0) {
-			blk_stop_queue(q);
-			break;
-		}
-	}
-}
-
-static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
-{
-	struct ub_dev *sc = lun->udev;
-	struct ub_scsi_cmd *cmd;
-	struct ub_request *urq;
-	int n_elem;
-
-	if (atomic_read(&sc->poison)) {
-		blk_start_request(rq);
-		ub_end_rq(rq, DID_NO_CONNECT << 16);
-		return 0;
-	}
-
-	if (lun->changed && rq->cmd_type != REQ_TYPE_BLOCK_PC) {
-		blk_start_request(rq);
-		ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
-		return 0;
-	}
-
-	if (lun->urq.rq != NULL)
-		return -1;
-	if ((cmd = ub_get_cmd(lun)) == NULL)
-		return -1;
-	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
-
-	blk_start_request(rq);
-
-	urq = &lun->urq;
-	memset(urq, 0, sizeof(struct ub_request));
-	urq->rq = rq;
-
-	/*
-	 * get scatterlist from block layer
-	 */
-	sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG);
-	n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
-	if (n_elem < 0) {
-		/* Impossible, because blk_rq_map_sg should not hit ENOMEM. */
-		printk(KERN_INFO "%s: failed request map (%d)\n",
-		    lun->name, n_elem);
-		goto drop;
-	}
-	if (n_elem > UB_MAX_REQ_SG) {	/* Paranoia */
-		printk(KERN_WARNING "%s: request with %d segments\n",
-		    lun->name, n_elem);
-		goto drop;
-	}
-	urq->nsg = n_elem;
-
-	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-		ub_cmd_build_packet(sc, lun, cmd, urq);
-	} else {
-		ub_cmd_build_block(sc, lun, cmd, urq);
-	}
-	cmd->state = UB_CMDST_INIT;
-	cmd->lun = lun;
-	cmd->done = ub_rw_cmd_done;
-	cmd->back = urq;
-
-	cmd->tag = sc->tagcnt++;
-	if (ub_submit_scsi(sc, cmd) != 0)
-		goto drop;
-
-	return 0;
-
-drop:
-	ub_put_cmd(lun, cmd);
-	ub_end_rq(rq, DID_ERROR << 16);
-	return 0;
-}
-
-static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq)
-{
-	struct request *rq = urq->rq;
-	unsigned int block, nblks;
-
-	if (rq_data_dir(rq) == WRITE)
-		cmd->dir = UB_DIR_WRITE;
-	else
-		cmd->dir = UB_DIR_READ;
-
-	cmd->nsg = urq->nsg;
-	memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
-
-	/*
-	 * build the command
-	 *
-	 * The call to blk_queue_logical_block_size() guarantees that request
-	 * is aligned, but it is given in terms of 512 byte units, always.
-	 */
-	block = blk_rq_pos(rq) >> lun->capacity.bshift;
-	nblks = blk_rq_sectors(rq) >> lun->capacity.bshift;
-
-	cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
-	/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
-	cmd->cdb[2] = block >> 24;
-	cmd->cdb[3] = block >> 16;
-	cmd->cdb[4] = block >> 8;
-	cmd->cdb[5] = block;
-	cmd->cdb[7] = nblks >> 8;
-	cmd->cdb[8] = nblks;
-	cmd->cdb_len = 10;
-
-	cmd->len = blk_rq_bytes(rq);
-}
-
-static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq)
-{
-	struct request *rq = urq->rq;
-
-	if (blk_rq_bytes(rq) == 0) {
-		cmd->dir = UB_DIR_NONE;
-	} else {
-		if (rq_data_dir(rq) == WRITE)
-			cmd->dir = UB_DIR_WRITE;
-		else
-			cmd->dir = UB_DIR_READ;
-	}
-
-	cmd->nsg = urq->nsg;
-	memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
-
-	memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
-	cmd->cdb_len = rq->cmd_len;
-
-	cmd->len = blk_rq_bytes(rq);
-
-	/*
-	 * To reapply this to every URB is not as incorrect as it looks.
-	 * In return, we avoid any complicated tracking calculations.
-	 */
-	cmd->timeo = rq->timeout;
-}
-
-static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct ub_lun *lun = cmd->lun;
-	struct ub_request *urq = cmd->back;
-	struct request *rq;
-	unsigned int scsi_status;
-
-	rq = urq->rq;
-
-	if (cmd->error == 0) {
-		if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-			if (cmd->act_len >= rq->resid_len)
-				rq->resid_len = 0;
-			else
-				rq->resid_len -= cmd->act_len;
-			scsi_status = 0;
-		} else {
-			if (cmd->act_len != cmd->len) {
-				scsi_status = SAM_STAT_CHECK_CONDITION;
-			} else {
-				scsi_status = 0;
-			}
-		}
-	} else {
-		if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-			/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
-			memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
-			rq->sense_len = UB_SENSE_SIZE;
-			if (sc->top_sense[0] != 0)
-				scsi_status = SAM_STAT_CHECK_CONDITION;
-			else
-				scsi_status = DID_ERROR << 16;
-		} else {
-			if (cmd->error == -EIO &&
-			    (cmd->key == 0 ||
-			     cmd->key == MEDIUM_ERROR ||
-			     cmd->key == UNIT_ATTENTION)) {
-				if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
-					return;
-			}
-			scsi_status = SAM_STAT_CHECK_CONDITION;
-		}
-	}
-
-	urq->rq = NULL;
-
-	ub_put_cmd(lun, cmd);
-	ub_end_rq(rq, scsi_status);
-	blk_start_queue(lun->disk->queue);
-}
-
-static void ub_end_rq(struct request *rq, unsigned int scsi_status)
-{
-	int error;
-
-	if (scsi_status == 0) {
-		error = 0;
-	} else {
-		error = -EIO;
-		rq->errors = scsi_status;
-	}
-	__blk_end_request_all(rq, error);
-}
-
-static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_request *urq, struct ub_scsi_cmd *cmd)
-{
-
-	if (atomic_read(&sc->poison))
-		return -ENXIO;
-
-	ub_reset_enter(sc, urq->current_try);
-
-	if (urq->current_try >= 3)
-		return -EIO;
-	urq->current_try++;
-
-	/* Remove this if anyone complains of flooding. */
-	printk(KERN_DEBUG "%s: dir %c len/act %d/%d "
-	    "[sense %x %02x %02x] retry %d\n",
-	    sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
-	    cmd->key, cmd->asc, cmd->ascq, urq->current_try);
-
-	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
-	ub_cmd_build_block(sc, lun, cmd, urq);
-
-	cmd->state = UB_CMDST_INIT;
-	cmd->lun = lun;
-	cmd->done = ub_rw_cmd_done;
-	cmd->back = urq;
-
-	cmd->tag = sc->tagcnt++;
-
-#if 0 /* Wasteful */
-	return ub_submit_scsi(sc, cmd);
-#else
-	ub_cmdq_add(sc, cmd);
-	return 0;
-#endif
-}
-
-/*
- * Submit a regular SCSI operation (not an auto-sense).
- *
- * The Iron Law of Good Submit Routine is:
- * Zero return - callback is done, Nonzero return - callback is not done.
- * No exceptions.
- *
- * Host is assumed locked.
- */
-static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-	if (cmd->state != UB_CMDST_INIT ||
-	    (cmd->dir != UB_DIR_NONE && cmd->len == 0)) {
-		return -EINVAL;
-	}
-
-	ub_cmdq_add(sc, cmd);
-	/*
-	 * We can call ub_scsi_dispatch(sc) right away here, but it's a little
-	 * safer to jump to a tasklet, in case upper layers do something silly.
-	 */
-	tasklet_schedule(&sc->tasklet);
-	return 0;
-}
-
-/*
- * Submit the first URB for the queued command.
- * This function does not deal with queueing in any way.
- */
-static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct bulk_cb_wrap *bcb;
-	int rc;
-
-	bcb = &sc->work_bcb;
-
-	/*
-	 * ``If the allocation length is eighteen or greater, and a device
-	 * server returns less than eithteen bytes of data, the application
-	 * client should assume that the bytes not transferred would have been
-	 * zeroes had the device server returned those bytes.''
-	 *
-	 * We zero sense for all commands so that when a packet request
-	 * fails it does not return a stale sense.
-	 */
-	memset(&sc->top_sense, 0, UB_SENSE_SIZE);
-
-	/* set up the command wrapper */
-	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
-	bcb->Tag = cmd->tag;		/* Endianness is not important */
-	bcb->DataTransferLength = cpu_to_le32(cmd->len);
-	bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
-	bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;
-	bcb->Length = cmd->cdb_len;
-
-	/* copy the command payload */
-	memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE);
-
-	UB_INIT_COMPLETION(sc->work_done);
-
-	sc->last_pipe = sc->send_bulk_pipe;
-	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
-	    bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-		/* XXX Clear stalls */
-		ub_complete(&sc->work_done);
-		return rc;
-	}
-
-	sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
-	add_timer(&sc->work_timer);
-
-	cmd->state = UB_CMDST_CMD;
-	return 0;
-}
-
-/*
- * Timeout handler.
- */
-static void ub_urb_timeout(unsigned long arg)
-{
-	struct ub_dev *sc = (struct ub_dev *) arg;
-	unsigned long flags;
-
-	spin_lock_irqsave(sc->lock, flags);
-	if (!ub_is_completed(&sc->work_done))
-		usb_unlink_urb(&sc->work_urb);
-	spin_unlock_irqrestore(sc->lock, flags);
-}
-
-/*
- * Completion routine for the work URB.
- *
- * This can be called directly from usb_submit_urb (while we have
- * the sc->lock taken) and from an interrupt (while we do NOT have
- * the sc->lock taken). Therefore, bounce this off to a tasklet.
- */
-static void ub_urb_complete(struct urb *urb)
-{
-	struct ub_dev *sc = urb->context;
-
-	ub_complete(&sc->work_done);
-	tasklet_schedule(&sc->tasklet);
-}
-
-static void ub_scsi_action(unsigned long _dev)
-{
-	struct ub_dev *sc = (struct ub_dev *) _dev;
-	unsigned long flags;
-
-	spin_lock_irqsave(sc->lock, flags);
-	ub_scsi_dispatch(sc);
-	spin_unlock_irqrestore(sc->lock, flags);
-}
-
-static void ub_scsi_dispatch(struct ub_dev *sc)
-{
-	struct ub_scsi_cmd *cmd;
-	int rc;
-
-	while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) {
-		if (cmd->state == UB_CMDST_DONE) {
-			ub_cmdq_pop(sc);
-			(*cmd->done)(sc, cmd);
-		} else if (cmd->state == UB_CMDST_INIT) {
-			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
-				break;
-			cmd->error = rc;
-			cmd->state = UB_CMDST_DONE;
-		} else {
-			if (!ub_is_completed(&sc->work_done))
-				break;
-			del_timer(&sc->work_timer);
-			ub_scsi_urb_compl(sc, cmd);
-		}
-	}
-}
-
-static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct urb *urb = &sc->work_urb;
-	struct bulk_cs_wrap *bcs;
-	int endp;
-	int len;
-	int rc;
-
-	if (atomic_read(&sc->poison)) {
-		ub_state_done(sc, cmd, -ENODEV);
-		return;
-	}
-
-	endp = usb_pipeendpoint(sc->last_pipe);
-	if (usb_pipein(sc->last_pipe))
-		endp |= USB_DIR_IN;
-
-	if (cmd->state == UB_CMDST_CLEAR) {
-		if (urb->status == -EPIPE) {
-			/*
-			 * STALL while clearning STALL.
-			 * The control pipe clears itself - nothing to do.
-			 */
-			printk(KERN_NOTICE "%s: stall on control pipe\n",
-			    sc->name);
-			goto Bad_End;
-		}
-
-		/*
-		 * We ignore the result for the halt clear.
-		 */
-
-		usb_reset_endpoint(sc->dev, endp);
-
-		ub_state_sense(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_CLR2STS) {
-		if (urb->status == -EPIPE) {
-			printk(KERN_NOTICE "%s: stall on control pipe\n",
-			    sc->name);
-			goto Bad_End;
-		}
-
-		/*
-		 * We ignore the result for the halt clear.
-		 */
-
-		usb_reset_endpoint(sc->dev, endp);
-
-		ub_state_stat(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_CLRRS) {
-		if (urb->status == -EPIPE) {
-			printk(KERN_NOTICE "%s: stall on control pipe\n",
-			    sc->name);
-			goto Bad_End;
-		}
-
-		/*
-		 * We ignore the result for the halt clear.
-		 */
-
-		usb_reset_endpoint(sc->dev, endp);
-
-		ub_state_stat_counted(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_CMD) {
-		switch (urb->status) {
-		case 0:
-			break;
-		case -EOVERFLOW:
-			goto Bad_End;
-		case -EPIPE:
-			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-			if (rc != 0) {
-				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear (%d)\n",
-				    sc->name, rc);
-				/*
-				 * This is typically ENOMEM or some other such shit.
-				 * Retrying is pointless. Just do Bad End on it...
-				 */
-				ub_state_done(sc, cmd, rc);
-				return;
-			}
-			cmd->state = UB_CMDST_CLEAR;
-			return;
-		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
-			ub_state_done(sc, cmd, -ENODEV);
-			return;
-		default:
-			goto Bad_End;
-		}
-		if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
-			goto Bad_End;
-		}
-
-		if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
-			ub_state_stat(sc, cmd);
-			return;
-		}
-
-		// udelay(125);		// usb-storage has this
-		ub_data_start(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_DATA) {
-		if (urb->status == -EPIPE) {
-			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-			if (rc != 0) {
-				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear (%d)\n",
-				    sc->name, rc);
-				ub_state_done(sc, cmd, rc);
-				return;
-			}
-			cmd->state = UB_CMDST_CLR2STS;
-			return;
-		}
-		if (urb->status == -EOVERFLOW) {
-			/*
-			 * A babble? Failure, but we must transfer CSW now.
-			 */
-			cmd->error = -EOVERFLOW;	/* A cheap trick... */
-			ub_state_stat(sc, cmd);
-			return;
-		}
-
-		if (cmd->dir == UB_DIR_WRITE) {
-			/*
-			 * Do not continue writes in case of a failure.
-			 * Doing so would cause sectors to be mixed up,
-			 * which is worse than sectors lost.
-			 *
-			 * We must try to read the CSW, or many devices
-			 * get confused.
-			 */
-			len = urb->actual_length;
-			if (urb->status != 0 ||
-			    len != cmd->sgv[cmd->current_sg].length) {
-				cmd->act_len += len;
-
-				cmd->error = -EIO;
-				ub_state_stat(sc, cmd);
-				return;
-			}
-
-		} else {
-			/*
-			 * If an error occurs on read, we record it, and
-			 * continue to fetch data in order to avoid bubble.
-			 *
-			 * As a small shortcut, we stop if we detect that
-			 * a CSW mixed into data.
-			 */
-			if (urb->status != 0)
-				cmd->error = -EIO;
-
-			len = urb->actual_length;
-			if (urb->status != 0 ||
-			    len != cmd->sgv[cmd->current_sg].length) {
-				if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)
-					goto Bad_End;
-			}
-		}
-
-		cmd->act_len += urb->actual_length;
-
-		if (++cmd->current_sg < cmd->nsg) {
-			ub_data_start(sc, cmd);
-			return;
-		}
-		ub_state_stat(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_STAT) {
-		if (urb->status == -EPIPE) {
-			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-			if (rc != 0) {
-				printk(KERN_NOTICE "%s: "
-				    "unable to submit clear (%d)\n",
-				    sc->name, rc);
-				ub_state_done(sc, cmd, rc);
-				return;
-			}
-
-			/*
-			 * Having a stall when getting CSW is an error, so
-			 * make sure uppper levels are not oblivious to it.
-			 */
-			cmd->error = -EIO;		/* A cheap trick... */
-
-			cmd->state = UB_CMDST_CLRRS;
-			return;
-		}
-
-		/* Catch everything, including -EOVERFLOW and other nasties. */
-		if (urb->status != 0)
-			goto Bad_End;
-
-		if (urb->actual_length == 0) {
-			ub_state_stat_counted(sc, cmd);
-			return;
-		}
-
-		/*
-		 * Check the returned Bulk protocol status.
-		 * The status block has to be validated first.
-		 */
-
-		bcs = &sc->work_bcs;
-
-		if (sc->signature == cpu_to_le32(0)) {
-			/*
-			 * This is the first reply, so do not perform the check.
-			 * Instead, remember the signature the device uses
-			 * for future checks. But do not allow a nul.
-			 */
-			sc->signature = bcs->Signature;
-			if (sc->signature == cpu_to_le32(0)) {
-				ub_state_stat_counted(sc, cmd);
-				return;
-			}
-		} else {
-			if (bcs->Signature != sc->signature) {
-				ub_state_stat_counted(sc, cmd);
-				return;
-			}
-		}
-
-		if (bcs->Tag != cmd->tag) {
-			/*
-			 * This usually happens when we disagree with the
-			 * device's microcode about something. For instance,
-			 * a few of them throw this after timeouts. They buffer
-			 * commands and reply at commands we timed out before.
-			 * Without flushing these replies we loop forever.
-			 */
-			ub_state_stat_counted(sc, cmd);
-			return;
-		}
-
-		if (!sc->bad_resid) {
-			len = le32_to_cpu(bcs->Residue);
-			if (len != cmd->len - cmd->act_len) {
-				/*
-				 * Only start ignoring if this cmd ended well.
-				 */
-				if (cmd->len == cmd->act_len) {
-					printk(KERN_NOTICE "%s: "
-					    "bad residual %d of %d, ignoring\n",
-					    sc->name, len, cmd->len);
-					sc->bad_resid = 1;
-				}
-			}
-		}
-
-		switch (bcs->Status) {
-		case US_BULK_STAT_OK:
-			break;
-		case US_BULK_STAT_FAIL:
-			ub_state_sense(sc, cmd);
-			return;
-		case US_BULK_STAT_PHASE:
-			goto Bad_End;
-		default:
-			printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
-			    sc->name, bcs->Status);
-			ub_state_done(sc, cmd, -EINVAL);
-			return;
-		}
-
-		/* Not zeroing error to preserve a babble indicator */
-		if (cmd->error != 0) {
-			ub_state_sense(sc, cmd);
-			return;
-		}
-		cmd->state = UB_CMDST_DONE;
-		ub_cmdq_pop(sc);
-		(*cmd->done)(sc, cmd);
-
-	} else if (cmd->state == UB_CMDST_SENSE) {
-		ub_state_done(sc, cmd, -EIO);
-
-	} else {
-		printk(KERN_WARNING "%s: wrong command state %d\n",
-		    sc->name, cmd->state);
-		ub_state_done(sc, cmd, -EINVAL);
-		return;
-	}
-	return;
-
-Bad_End: /* Little Excel is dead */
-	ub_state_done(sc, cmd, -EIO);
-}
-
-/*
- * Factorization helper for the command state machine:
- * Initiate a data segment transfer.
- */
-static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
-	int pipe;
-	int rc;
-
-	UB_INIT_COMPLETION(sc->work_done);
-
-	if (cmd->dir == UB_DIR_READ)
-		pipe = sc->recv_bulk_pipe;
-	else
-		pipe = sc->send_bulk_pipe;
-	sc->last_pipe = pipe;
-	usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
-	    sg->length, ub_urb_complete, sc);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-		/* XXX Clear stalls */
-		ub_complete(&sc->work_done);
-		ub_state_done(sc, cmd, rc);
-		return;
-	}
-
-	if (cmd->timeo)
-		sc->work_timer.expires = jiffies + cmd->timeo;
-	else
-		sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
-	add_timer(&sc->work_timer);
-
-	cmd->state = UB_CMDST_DATA;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Finish the command.
- */
-static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
-{
-
-	cmd->error = rc;
-	cmd->state = UB_CMDST_DONE;
-	ub_cmdq_pop(sc);
-	(*cmd->done)(sc, cmd);
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read.
- */
-static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	int rc;
-
-	UB_INIT_COMPLETION(sc->work_done);
-
-	sc->last_pipe = sc->recv_bulk_pipe;
-	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
-	    &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-		/* XXX Clear stalls */
-		ub_complete(&sc->work_done);
-		ub_state_done(sc, cmd, rc);
-		return -1;
-	}
-
-	if (cmd->timeo)
-		sc->work_timer.expires = jiffies + cmd->timeo;
-	else
-		sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
-	add_timer(&sc->work_timer);
-	return 0;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read and go to STAT state.
- */
-static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-	if (__ub_state_stat(sc, cmd) != 0)
-		return;
-
-	cmd->stat_count = 0;
-	cmd->state = UB_CMDST_STAT;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read and go to STAT state with counter (along [C] path).
- */
-static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-	if (++cmd->stat_count >= 4) {
-		ub_state_sense(sc, cmd);
-		return;
-	}
-
-	if (__ub_state_stat(sc, cmd) != 0)
-		return;
-
-	cmd->state = UB_CMDST_STAT;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a REQUEST SENSE and go to SENSE state.
- */
-static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct ub_scsi_cmd *scmd;
-	struct scatterlist *sg;
-	int rc;
-
-	if (cmd->cdb[0] == REQUEST_SENSE) {
-		rc = -EPIPE;
-		goto error;
-	}
-
-	scmd = &sc->top_rqs_cmd;
-	memset(scmd, 0, sizeof(struct ub_scsi_cmd));
-	scmd->cdb[0] = REQUEST_SENSE;
-	scmd->cdb[4] = UB_SENSE_SIZE;
-	scmd->cdb_len = 6;
-	scmd->dir = UB_DIR_READ;
-	scmd->state = UB_CMDST_INIT;
-	scmd->nsg = 1;
-	sg = &scmd->sgv[0];
-	sg_init_table(sg, UB_MAX_REQ_SG);
-	sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE,
-			(unsigned long)sc->top_sense & (PAGE_SIZE-1));
-	scmd->len = UB_SENSE_SIZE;
-	scmd->lun = cmd->lun;
-	scmd->done = ub_top_sense_done;
-	scmd->back = cmd;
-
-	scmd->tag = sc->tagcnt++;
-
-	cmd->state = UB_CMDST_SENSE;
-
-	ub_cmdq_insert(sc, scmd);
-	return;
-
-error:
-	ub_state_done(sc, cmd, rc);
-}
-
-/*
- * A helper for the command's state machine:
- * Submit a stall clear.
- */
-static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    int stalled_pipe)
-{
-	int endp;
-	struct usb_ctrlrequest *cr;
-	int rc;
-
-	endp = usb_pipeendpoint(stalled_pipe);
-	if (usb_pipein (stalled_pipe))
-		endp |= USB_DIR_IN;
-
-	cr = &sc->work_cr;
-	cr->bRequestType = USB_RECIP_ENDPOINT;
-	cr->bRequest = USB_REQ_CLEAR_FEATURE;
-	cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
-	cr->wIndex = cpu_to_le16(endp);
-	cr->wLength = cpu_to_le16(0);
-
-	UB_INIT_COMPLETION(sc->work_done);
-
-	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-		ub_complete(&sc->work_done);
-		return rc;
-	}
-
-	sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
-	add_timer(&sc->work_timer);
-	return 0;
-}
-
-/*
- */
-static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
-{
-	unsigned char *sense = sc->top_sense;
-	struct ub_scsi_cmd *cmd;
-
-	/*
-	 * Find the command which triggered the unit attention or a check,
-	 * save the sense into it, and advance its state machine.
-	 */
-	if ((cmd = ub_cmdq_peek(sc)) == NULL) {
-		printk(KERN_WARNING "%s: sense done while idle\n", sc->name);
-		return;
-	}
-	if (cmd != scmd->back) {
-		printk(KERN_WARNING "%s: "
-		    "sense done for wrong command 0x%x\n",
-		    sc->name, cmd->tag);
-		return;
-	}
-	if (cmd->state != UB_CMDST_SENSE) {
-		printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
-		    sc->name, cmd->state);
-		return;
-	}
-
-	/*
-	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-	 */
-	cmd->key = sense[2] & 0x0F;
-	cmd->asc = sense[12];
-	cmd->ascq = sense[13];
-
-	ub_scsi_urb_compl(sc, cmd);
-}
-
-/*
- * Reset management
- */
-
-static void ub_reset_enter(struct ub_dev *sc, int try)
-{
-
-	if (sc->reset) {
-		/* This happens often on multi-LUN devices. */
-		return;
-	}
-	sc->reset = try + 1;
-
-#if 0 /* Not needed because the disconnect waits for us. */
-	unsigned long flags;
-	spin_lock_irqsave(&ub_lock, flags);
-	sc->openc++;
-	spin_unlock_irqrestore(&ub_lock, flags);
-#endif
-
-#if 0 /* We let them stop themselves. */
-	struct ub_lun *lun;
-	list_for_each_entry(lun, &sc->luns, link) {
-		blk_stop_queue(lun->disk->queue);
-	}
-#endif
-
-	schedule_work(&sc->reset_work);
-}
-
-static void ub_reset_task(struct work_struct *work)
-{
-	struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
-	unsigned long flags;
-	struct ub_lun *lun;
-	int rc;
-
-	if (!sc->reset) {
-		printk(KERN_WARNING "%s: Running reset unrequested\n",
-		    sc->name);
-		return;
-	}
-
-	if (atomic_read(&sc->poison)) {
-		;
-	} else if ((sc->reset & 1) == 0) {
-		ub_sync_reset(sc);
-		msleep(700);	/* usb-storage sleeps 6s (!) */
-		ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-		ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-	} else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
-		;
-	} else {
-		rc = usb_lock_device_for_reset(sc->dev, sc->intf);
-		if (rc < 0) {
-			printk(KERN_NOTICE
-			    "%s: usb_lock_device_for_reset failed (%d)\n",
-			    sc->name, rc);
-		} else {
-			rc = usb_reset_device(sc->dev);
-			if (rc < 0) {
-				printk(KERN_NOTICE "%s: "
-				    "usb_lock_device_for_reset failed (%d)\n",
-				    sc->name, rc);
-			}
-			usb_unlock_device(sc->dev);
-		}
-	}
-
-	/*
-	 * In theory, no commands can be running while reset is active,
-	 * so nobody can ask for another reset, and so we do not need any
-	 * queues of resets or anything. We do need a spinlock though,
-	 * to interact with block layer.
-	 */
-	spin_lock_irqsave(sc->lock, flags);
-	sc->reset = 0;
-	tasklet_schedule(&sc->tasklet);
-	list_for_each_entry(lun, &sc->luns, link) {
-		blk_start_queue(lun->disk->queue);
-	}
-	wake_up(&sc->reset_wait);
-	spin_unlock_irqrestore(sc->lock, flags);
-}
-
-/*
- * XXX Reset brackets are too much hassle to implement, so just stub them
- * in order to prevent forced unbinding (which deadlocks solid when our
- * ->disconnect method waits for the reset to complete and this kills keventd).
- *
- * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device,
- * or else the post_reset is invoked, and restats I/O on a locked device.
- */
-static int ub_pre_reset(struct usb_interface *iface) {
-	return 0;
-}
-
-static int ub_post_reset(struct usb_interface *iface) {
-	return 0;
-}
-
-/*
- * This is called from a process context.
- */
-static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
-{
-
-	lun->readonly = 0;	/* XXX Query this from the device */
-
-	lun->capacity.nsec = 0;
-	lun->capacity.bsize = 512;
-	lun->capacity.bshift = 0;
-
-	if (ub_sync_tur(sc, lun) != 0)
-		return;			/* Not ready */
-	lun->changed = 0;
-
-	if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
-		/*
-		 * The retry here means something is wrong, either with the
-		 * device, with the transport, or with our code.
-		 * We keep this because sd.c has retries for capacity.
-		 */
-		if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
-			lun->capacity.nsec = 0;
-			lun->capacity.bsize = 512;
-			lun->capacity.bshift = 0;
-		}
-	}
-}
-
-/*
- * The open funcion.
- * This is mostly needed to keep refcounting, but also to support
- * media checks on removable media drives.
- */
-static int ub_bd_open(struct block_device *bdev, fmode_t mode)
-{
-	struct ub_lun *lun = bdev->bd_disk->private_data;
-	struct ub_dev *sc = lun->udev;
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&ub_lock, flags);
-	if (atomic_read(&sc->poison)) {
-		spin_unlock_irqrestore(&ub_lock, flags);
-		return -ENXIO;
-	}
-	sc->openc++;
-	spin_unlock_irqrestore(&ub_lock, flags);
-
-	if (lun->removable || lun->readonly)
-		check_disk_change(bdev);
-
-	/*
-	 * The sd.c considers ->media_present and ->changed not equivalent,
-	 * under some pretty murky conditions (a failure of READ CAPACITY).
-	 * We may need it one day.
-	 */
-	if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) {
-		rc = -ENOMEDIUM;
-		goto err_open;
-	}
-
-	if (lun->readonly && (mode & FMODE_WRITE)) {
-		rc = -EROFS;
-		goto err_open;
-	}
-
-	return 0;
-
-err_open:
-	ub_put(sc);
-	return rc;
-}
-
-static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
-	int ret;
-
-	mutex_lock(&ub_mutex);
-	ret = ub_bd_open(bdev, mode);
-	mutex_unlock(&ub_mutex);
-
-	return ret;
-}
-
-
-/*
- */
-static int ub_bd_release(struct gendisk *disk, fmode_t mode)
-{
-	struct ub_lun *lun = disk->private_data;
-	struct ub_dev *sc = lun->udev;
-
-	mutex_lock(&ub_mutex);
-	ub_put(sc);
-	mutex_unlock(&ub_mutex);
-
-	return 0;
-}
-
-/*
- * The ioctl interface.
- */
-static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
-    unsigned int cmd, unsigned long arg)
-{
-	void __user *usermem = (void __user *) arg;
-	int ret;
-
-	mutex_lock(&ub_mutex);
-	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem);
-	mutex_unlock(&ub_mutex);
-
-	return ret;
-}
-
-/*
- * This is called by check_disk_change if we reported a media change.
- * The main onjective here is to discover the features of the media such as
- * the capacity, read-only status, etc. USB storage generally does not
- * need to be spun up, but if we needed it, this would be the place.
- *
- * This call can sleep.
- *
- * The return code is not used.
- */
-static int ub_bd_revalidate(struct gendisk *disk)
-{
-	struct ub_lun *lun = disk->private_data;
-
-	ub_revalidate(lun->udev, lun);
-
-	/* XXX Support sector size switching like in sr.c */
-	blk_queue_logical_block_size(disk->queue, lun->capacity.bsize);
-	set_capacity(disk, lun->capacity.nsec);
-	// set_disk_ro(sdkp->disk, lun->readonly);
-
-	return 0;
-}
-
-/*
- * The check is called by the block layer to verify if the media
- * is still available. It is supposed to be harmless, lightweight and
- * non-intrusive in case the media was not changed.
- *
- * This call can sleep.
- *
- * The return code is bool!
- */
-static unsigned int ub_bd_check_events(struct gendisk *disk,
-				       unsigned int clearing)
-{
-	struct ub_lun *lun = disk->private_data;
-
-	if (!lun->removable)
-		return 0;
-
-	/*
-	 * We clean checks always after every command, so this is not
-	 * as dangerous as it looks. If the TEST_UNIT_READY fails here,
-	 * the device is actually not ready with operator or software
-	 * intervention required. One dangerous item might be a drive which
-	 * spins itself down, and come the time to write dirty pages, this
-	 * will fail, then block layer discards the data. Since we never
-	 * spin drives up, such devices simply cannot be used with ub anyway.
-	 */
-	if (ub_sync_tur(lun->udev, lun) != 0) {
-		lun->changed = 1;
-		return DISK_EVENT_MEDIA_CHANGE;
-	}
-
-	return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static const struct block_device_operations ub_bd_fops = {
-	.owner		= THIS_MODULE,
-	.open		= ub_bd_unlocked_open,
-	.release	= ub_bd_release,
-	.ioctl		= ub_bd_ioctl,
-	.check_events	= ub_bd_check_events,
-	.revalidate_disk = ub_bd_revalidate,
-};
-
-/*
- * Common ->done routine for commands executed synchronously.
- */
-static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct completion *cop = cmd->back;
-	complete(cop);
-}
-
-/*
- * Test if the device has a check condition on it, synchronously.
- */
-static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
-{
-	struct ub_scsi_cmd *cmd;
-	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };
-	unsigned long flags;
-	struct completion compl;
-	int rc;
-
-	init_completion(&compl);
-
-	rc = -ENOMEM;
-	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-		goto err_alloc;
-
-	cmd->cdb[0] = TEST_UNIT_READY;
-	cmd->cdb_len = 6;
-	cmd->dir = UB_DIR_NONE;
-	cmd->state = UB_CMDST_INIT;
-	cmd->lun = lun;			/* This may be NULL, but that's ok */
-	cmd->done = ub_probe_done;
-	cmd->back = &compl;
-
-	spin_lock_irqsave(sc->lock, flags);
-	cmd->tag = sc->tagcnt++;
-
-	rc = ub_submit_scsi(sc, cmd);
-	spin_unlock_irqrestore(sc->lock, flags);
-
-	if (rc != 0)
-		goto err_submit;
-
-	wait_for_completion(&compl);
-
-	rc = cmd->error;
-
-	if (rc == -EIO && cmd->key != 0)	/* Retries for benh's key */
-		rc = cmd->key;
-
-err_submit:
-	kfree(cmd);
-err_alloc:
-	return rc;
-}
-
-/*
- * Read the SCSI capacity synchronously (for probing).
- */
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_capacity *ret)
-{
-	struct ub_scsi_cmd *cmd;
-	struct scatterlist *sg;
-	char *p;
-	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
-	unsigned long flags;
-	unsigned int bsize, shift;
-	unsigned long nsec;
-	struct completion compl;
-	int rc;
-
-	init_completion(&compl);
-
-	rc = -ENOMEM;
-	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-		goto err_alloc;
-	p = (char *)cmd + sizeof(struct ub_scsi_cmd);
-
-	cmd->cdb[0] = 0x25;
-	cmd->cdb_len = 10;
-	cmd->dir = UB_DIR_READ;
-	cmd->state = UB_CMDST_INIT;
-	cmd->nsg = 1;
-	sg = &cmd->sgv[0];
-	sg_init_table(sg, UB_MAX_REQ_SG);
-	sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1));
-	cmd->len = 8;
-	cmd->lun = lun;
-	cmd->done = ub_probe_done;
-	cmd->back = &compl;
-
-	spin_lock_irqsave(sc->lock, flags);
-	cmd->tag = sc->tagcnt++;
-
-	rc = ub_submit_scsi(sc, cmd);
-	spin_unlock_irqrestore(sc->lock, flags);
-
-	if (rc != 0)
-		goto err_submit;
-
-	wait_for_completion(&compl);
-
-	if (cmd->error != 0) {
-		rc = -EIO;
-		goto err_read;
-	}
-	if (cmd->act_len != 8) {
-		rc = -EIO;
-		goto err_read;
-	}
-
-	/* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */
-	nsec = be32_to_cpu(*(__be32 *)p) + 1;
-	bsize = be32_to_cpu(*(__be32 *)(p + 4));
-	switch (bsize) {
-	case 512:	shift = 0;	break;
-	case 1024:	shift = 1;	break;
-	case 2048:	shift = 2;	break;
-	case 4096:	shift = 3;	break;
-	default:
-		rc = -EDOM;
-		goto err_inv_bsize;
-	}
-
-	ret->bsize = bsize;
-	ret->bshift = shift;
-	ret->nsec = nsec << shift;
-	rc = 0;
-
-err_inv_bsize:
-err_read:
-err_submit:
-	kfree(cmd);
-err_alloc:
-	return rc;
-}
-
-/*
- */
-static void ub_probe_urb_complete(struct urb *urb)
-{
-	struct completion *cop = urb->context;
-	complete(cop);
-}
-
-static void ub_probe_timeout(unsigned long arg)
-{
-	struct completion *cop = (struct completion *) arg;
-	complete(cop);
-}
-
-/*
- * Reset with a Bulk reset.
- */
-static int ub_sync_reset(struct ub_dev *sc)
-{
-	int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
-	struct usb_ctrlrequest *cr;
-	struct completion compl;
-	struct timer_list timer;
-	int rc;
-
-	init_completion(&compl);
-
-	cr = &sc->work_cr;
-	cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	cr->bRequest = US_BULK_RESET_REQUEST;
-	cr->wValue = cpu_to_le16(0);
-	cr->wIndex = cpu_to_le16(ifnum);
-	cr->wLength = cpu_to_le16(0);
-
-	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-	    (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
-		printk(KERN_WARNING
-		     "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
-		return rc;
-	}
-
-	init_timer(&timer);
-	timer.function = ub_probe_timeout;
-	timer.data = (unsigned long) &compl;
-	timer.expires = jiffies + UB_CTRL_TIMEOUT;
-	add_timer(&timer);
-
-	wait_for_completion(&compl);
-
-	del_timer_sync(&timer);
-	usb_kill_urb(&sc->work_urb);
-
-	return sc->work_urb.status;
-}
-
-/*
- * Get number of LUNs by the way of Bulk GetMaxLUN command.
- */
-static int ub_sync_getmaxlun(struct ub_dev *sc)
-{
-	int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
-	unsigned char *p;
-	enum { ALLOC_SIZE = 1 };
-	struct usb_ctrlrequest *cr;
-	struct completion compl;
-	struct timer_list timer;
-	int nluns;
-	int rc;
-
-	init_completion(&compl);
-
-	rc = -ENOMEM;
-	if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-		goto err_alloc;
-	*p = 55;
-
-	cr = &sc->work_cr;
-	cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	cr->bRequest = US_BULK_GET_MAX_LUN;
-	cr->wValue = cpu_to_le16(0);
-	cr->wIndex = cpu_to_le16(ifnum);
-	cr->wLength = cpu_to_le16(1);
-
-	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
-	    (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
-		goto err_submit;
-
-	init_timer(&timer);
-	timer.function = ub_probe_timeout;
-	timer.data = (unsigned long) &compl;
-	timer.expires = jiffies + UB_CTRL_TIMEOUT;
-	add_timer(&timer);
-
-	wait_for_completion(&compl);
-
-	del_timer_sync(&timer);
-	usb_kill_urb(&sc->work_urb);
-
-	if ((rc = sc->work_urb.status) < 0)
-		goto err_io;
-
-	if (sc->work_urb.actual_length != 1) {
-		nluns = 0;
-	} else {
-		if ((nluns = *p) == 55) {
-			nluns = 0;
-		} else {
-  			/* GetMaxLUN returns the maximum LUN number */
-			nluns += 1;
-			if (nluns > UB_MAX_LUNS)
-				nluns = UB_MAX_LUNS;
-		}
-	}
-
-	kfree(p);
-	return nluns;
-
-err_io:
-err_submit:
-	kfree(p);
-err_alloc:
-	return rc;
-}
-
-/*
- * Clear initial stalls.
- */
-static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
-{
-	int endp;
-	struct usb_ctrlrequest *cr;
-	struct completion compl;
-	struct timer_list timer;
-	int rc;
-
-	init_completion(&compl);
-
-	endp = usb_pipeendpoint(stalled_pipe);
-	if (usb_pipein (stalled_pipe))
-		endp |= USB_DIR_IN;
-
-	cr = &sc->work_cr;
-	cr->bRequestType = USB_RECIP_ENDPOINT;
-	cr->bRequest = USB_REQ_CLEAR_FEATURE;
-	cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
-	cr->wIndex = cpu_to_le16(endp);
-	cr->wLength = cpu_to_le16(0);
-
-	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-	    (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-
-	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
-		printk(KERN_WARNING
-		     "%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
-		return rc;
-	}
-
-	init_timer(&timer);
-	timer.function = ub_probe_timeout;
-	timer.data = (unsigned long) &compl;
-	timer.expires = jiffies + UB_CTRL_TIMEOUT;
-	add_timer(&timer);
-
-	wait_for_completion(&compl);
-
-	del_timer_sync(&timer);
-	usb_kill_urb(&sc->work_urb);
-
-	usb_reset_endpoint(sc->dev, endp);
-
-	return 0;
-}
-
-/*
- * Get the pipe settings.
- */
-static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
-    struct usb_interface *intf)
-{
-	struct usb_host_interface *altsetting = intf->cur_altsetting;
-	struct usb_endpoint_descriptor *ep_in = NULL;
-	struct usb_endpoint_descriptor *ep_out = NULL;
-	struct usb_endpoint_descriptor *ep;
-	int i;
-
-	/*
-	 * Find the endpoints we need.
-	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
-	 * We will ignore any others.
-	 */
-	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
-		ep = &altsetting->endpoint[i].desc;
-
-		/* Is it a BULK endpoint? */
-		if (usb_endpoint_xfer_bulk(ep)) {
-			/* BULK in or out? */
-			if (usb_endpoint_dir_in(ep)) {
-				if (ep_in == NULL)
-					ep_in = ep;
-			} else {
-				if (ep_out == NULL)
-					ep_out = ep;
-			}
-		}
-	}
-
-	if (ep_in == NULL || ep_out == NULL) {
-		printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
-		return -ENODEV;
-	}
-
-	/* Calculate and store the pipe values */
-	sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
-	sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
-	sc->send_bulk_pipe = usb_sndbulkpipe(dev,
-		usb_endpoint_num(ep_out));
-	sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, 
-		usb_endpoint_num(ep_in));
-
-	return 0;
-}
-
-/*
- * Probing is done in the process context, which allows us to cheat
- * and not to build a state machine for the discovery.
- */
-static int ub_probe(struct usb_interface *intf,
-    const struct usb_device_id *dev_id)
-{
-	struct ub_dev *sc;
-	int nluns;
-	int rc;
-	int i;
-
-	if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
-		return -ENXIO;
-
-	rc = -ENOMEM;
-	if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
-		goto err_core;
-	sc->lock = ub_next_lock();
-	INIT_LIST_HEAD(&sc->luns);
-	usb_init_urb(&sc->work_urb);
-	tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
-	atomic_set(&sc->poison, 0);
-	INIT_WORK(&sc->reset_work, ub_reset_task);
-	init_waitqueue_head(&sc->reset_wait);
-
-	init_timer(&sc->work_timer);
-	sc->work_timer.data = (unsigned long) sc;
-	sc->work_timer.function = ub_urb_timeout;
-
-	ub_init_completion(&sc->work_done);
-	sc->work_done.done = 1;		/* A little yuk, but oh well... */
-
-	sc->dev = interface_to_usbdev(intf);
-	sc->intf = intf;
-	// sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-	usb_set_intfdata(intf, sc);
-	usb_get_dev(sc->dev);
-	/*
-	 * Since we give the interface struct to the block level through
-	 * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent
-	 * oopses on close after a disconnect (kernels 2.6.16 and up).
-	 */
-	usb_get_intf(sc->intf);
-
-	snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
-	    sc->dev->bus->busnum, sc->dev->devnum);
-
-	/* XXX Verify that we can handle the device (from descriptors) */
-
-	if (ub_get_pipes(sc, sc->dev, intf) != 0)
-		goto err_dev_desc;
-
-	/*
-	 * At this point, all USB initialization is done, do upper layer.
-	 * We really hate halfway initialized structures, so from the
-	 * invariants perspective, this ub_dev is fully constructed at
-	 * this point.
-	 */
-
-	/*
-	 * This is needed to clear toggles. It is a problem only if we do
-	 * `rmmod ub && modprobe ub` without disconnects, but we like that.
-	 */
-#if 0 /* iPod Mini fails if we do this (big white iPod works) */
-	ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-	ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-#endif
-
-	/*
-	 * The way this is used by the startup code is a little specific.
-	 * A SCSI check causes a USB stall. Our common case code sees it
-	 * and clears the check, after which the device is ready for use.
-	 * But if a check was not present, any command other than
-	 * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE).
-	 *
-	 * If we neglect to clear the SCSI check, the first real command fails
-	 * (which is the capacity readout). We clear that and retry, but why
-	 * causing spurious retries for no reason.
-	 *
-	 * Revalidation may start with its own TEST_UNIT_READY, but that one
-	 * has to succeed, so we clear checks with an additional one here.
-	 * In any case it's not our business how revaliadation is implemented.
-	 */
-	for (i = 0; i < 3; i++) {  /* Retries for the schwag key from KS'04 */
-		if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
-		if (rc != 0x6) break;
-		msleep(10);
-	}
-
-	nluns = 1;
-	for (i = 0; i < 3; i++) {
-		if ((rc = ub_sync_getmaxlun(sc)) < 0)
-			break;
-		if (rc != 0) {
-			nluns = rc;
-			break;
-		}
-		msleep(100);
-	}
-
-	for (i = 0; i < nluns; i++) {
-		ub_probe_lun(sc, i);
-	}
-	return 0;
-
-err_dev_desc:
-	usb_set_intfdata(intf, NULL);
-	usb_put_intf(sc->intf);
-	usb_put_dev(sc->dev);
-	kfree(sc);
-err_core:
-	return rc;
-}
-
-static int ub_probe_lun(struct ub_dev *sc, int lnum)
-{
-	struct ub_lun *lun;
-	struct request_queue *q;
-	struct gendisk *disk;
-	int rc;
-
-	rc = -ENOMEM;
-	if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
-		goto err_alloc;
-	lun->num = lnum;
-
-	rc = -ENOSR;
-	if ((lun->id = ub_id_get()) == -1)
-		goto err_id;
-
-	lun->udev = sc;
-
-	snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
-	    lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
-
-	lun->removable = 1;		/* XXX Query this from the device */
-	lun->changed = 1;		/* ub_revalidate clears only */
-	ub_revalidate(sc, lun);
-
-	rc = -ENOMEM;
-	if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
-		goto err_diskalloc;
-
-	sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
-	disk->major = UB_MAJOR;
-	disk->first_minor = lun->id * UB_PARTS_PER_LUN;
-	disk->fops = &ub_bd_fops;
-	disk->private_data = lun;
-	disk->driverfs_dev = &sc->intf->dev;
-
-	rc = -ENOMEM;
-	if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
-		goto err_blkqinit;
-
-	disk->queue = q;
-
-	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-	blk_queue_max_segments(q, UB_MAX_REQ_SG);
-	blk_queue_segment_boundary(q, 0xffffffff);	/* Dubious. */
-	blk_queue_max_hw_sectors(q, UB_MAX_SECTORS);
-	blk_queue_logical_block_size(q, lun->capacity.bsize);
-
-	lun->disk = disk;
-	q->queuedata = lun;
-	list_add(&lun->link, &sc->luns);
-
-	set_capacity(disk, lun->capacity.nsec);
-	if (lun->removable)
-		disk->flags |= GENHD_FL_REMOVABLE;
-
-	add_disk(disk);
-
-	return 0;
-
-err_blkqinit:
-	put_disk(disk);
-err_diskalloc:
-	ub_id_put(lun->id);
-err_id:
-	kfree(lun);
-err_alloc:
-	return rc;
-}
-
-static void ub_disconnect(struct usb_interface *intf)
-{
-	struct ub_dev *sc = usb_get_intfdata(intf);
-	struct ub_lun *lun;
-	unsigned long flags;
-
-	/*
-	 * Prevent ub_bd_release from pulling the rug from under us.
-	 * XXX This is starting to look like a kref.
-	 * XXX Why not to take this ref at probe time?
-	 */
-	spin_lock_irqsave(&ub_lock, flags);
-	sc->openc++;
-	spin_unlock_irqrestore(&ub_lock, flags);
-
-	/*
-	 * Fence stall clearings, operations triggered by unlinkings and so on.
-	 * We do not attempt to unlink any URBs, because we do not trust the
-	 * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
-	 */
-	atomic_set(&sc->poison, 1);
-
-	/*
-	 * Wait for reset to end, if any.
-	 */
-	wait_event(sc->reset_wait, !sc->reset);
-
-	/*
-	 * Blow away queued commands.
-	 *
-	 * Actually, this never works, because before we get here
-	 * the HCD terminates outstanding URB(s). It causes our
-	 * SCSI command queue to advance, commands fail to submit,
-	 * and the whole queue drains. So, we just use this code to
-	 * print warnings.
-	 */
-	spin_lock_irqsave(sc->lock, flags);
-	{
-		struct ub_scsi_cmd *cmd;
-		int cnt = 0;
-		while ((cmd = ub_cmdq_peek(sc)) != NULL) {
-			cmd->error = -ENOTCONN;
-			cmd->state = UB_CMDST_DONE;
-			ub_cmdq_pop(sc);
-			(*cmd->done)(sc, cmd);
-			cnt++;
-		}
-		if (cnt != 0) {
-			printk(KERN_WARNING "%s: "
-			    "%d was queued after shutdown\n", sc->name, cnt);
-		}
-	}
-	spin_unlock_irqrestore(sc->lock, flags);
-
-	/*
-	 * Unregister the upper layer.
-	 */
-	list_for_each_entry(lun, &sc->luns, link) {
-		del_gendisk(lun->disk);
-		/*
-		 * I wish I could do:
-		 *    queue_flag_set(QUEUE_FLAG_DEAD, q);
-		 * As it is, we rely on our internal poisoning and let
-		 * the upper levels to spin furiously failing all the I/O.
-		 */
-	}
-
-	/*
-	 * Testing for -EINPROGRESS is always a bug, so we are bending
-	 * the rules a little.
-	 */
-	spin_lock_irqsave(sc->lock, flags);
-	if (sc->work_urb.status == -EINPROGRESS) {	/* janitors: ignore */
-		printk(KERN_WARNING "%s: "
-		    "URB is active after disconnect\n", sc->name);
-	}
-	spin_unlock_irqrestore(sc->lock, flags);
-
-	/*
-	 * There is virtually no chance that other CPU runs a timeout so long
-	 * after ub_urb_complete should have called del_timer, but only if HCD
-	 * didn't forget to deliver a callback on unlink.
-	 */
-	del_timer_sync(&sc->work_timer);
-
-	/*
-	 * At this point there must be no commands coming from anyone
-	 * and no URBs left in transit.
-	 */
-
-	ub_put(sc);
-}
-
-static struct usb_driver ub_driver = {
-	.name =		"ub",
-	.probe =	ub_probe,
-	.disconnect =	ub_disconnect,
-	.id_table =	ub_usb_ids,
-	.pre_reset =	ub_pre_reset,
-	.post_reset =	ub_post_reset,
-};
-
-static int __init ub_init(void)
-{
-	int rc;
-	int i;
-
-	pr_info("'Low Performance USB Block' driver is deprecated. "
-			"Please switch to usb-storage\n");
-	for (i = 0; i < UB_QLOCK_NUM; i++)
-		spin_lock_init(&ub_qlockv[i]);
-
-	if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
-		goto err_regblkdev;
-
-	if ((rc = usb_register(&ub_driver)) != 0)
-		goto err_register;
-
-	usb_usual_set_present(USB_US_TYPE_UB);
-	return 0;
-
-err_register:
-	unregister_blkdev(UB_MAJOR, DRV_NAME);
-err_regblkdev:
-	return rc;
-}
-
-static void __exit ub_exit(void)
-{
-	usb_deregister(&ub_driver);
-
-	unregister_blkdev(UB_MAJOR, DRV_NAME);
-	usb_usual_clear_present(USB_US_TYPE_UB);
-}
-
-module_init(ub_init);
-module_exit(ub_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 73f196c..c6decb9 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -337,7 +337,7 @@
 		invcount++;
 	}
 
-	ret = gnttab_unmap_refs(unmap, pages, invcount, false);
+	ret = gnttab_unmap_refs(unmap, NULL, pages, invcount);
 	BUG_ON(ret);
 }
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ea6f632..72bedad 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -418,8 +418,8 @@
 	  If unsure, say N.
 
 config SONYPI
-	tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT
+	tristate "Sony Vaio Programmable I/O Control Device support"
+	depends on X86 && PCI && INPUT && !64BIT
 	---help---
 	  This driver enables access to the Sony Programmable I/O Control
 	  Device which can be found in many (all ?) Sony Vaio laptops.
@@ -566,7 +566,7 @@
 
 config TELCLOCK
 	tristate "Telecom clock driver for ATCA SBC"
-	depends on EXPERIMENTAL && X86
+	depends on X86
 	default n
 	help
 	  The telecom clock device is specific to the MPCBL0010 and MPCBL0050
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 1920003..3a5af2f 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -289,12 +289,11 @@
 
 	j = 0;
 	list_for_each_entry(info, &tioca_list, ca_list) {
-		struct list_head *tmp;
 		if (list_empty(info->ca_devices))
 			continue;
-		list_for_each(tmp, info->ca_devices) {
+		list_for_each_entry(pdev, info->ca_devices, bus_list) {
 			u8 cap_ptr;
-			pdev = pci_dev_b(tmp);
+
 			if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
 				continue;
 			cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 33dc229..3d6c067 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -826,7 +826,7 @@
 
 	/* Allocate list of node ptrs to mmtimer_t's */
 	timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
-	if (timers == NULL) {
+	if (!timers) {
 		printk(KERN_ERR "%s: failed to allocate memory for device\n",
 				MMTIMER_NAME);
 		goto out3;
@@ -848,7 +848,6 @@
 	return 0;
 
 out3:
-	kfree(timers);
 	misc_deregister(&mmtimer_miscdev);
 out2:
 	free_irq(SGI_MMTIMER_VECTOR, NULL);
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 04a480f..cfdfe49 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -93,9 +93,9 @@
 			button_callback_list [lp].count = 0;
 			callback_count--;
 			return 0;
-		};
+		}
 		lp--;
-	};
+	}
 	return -EINVAL;
 }
 
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 3f57d5de..21721d2 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -891,6 +891,14 @@
 	int work = 0;
  	struct mgsl_icount *icount = &info->icount;
 
+	if (!tty) {
+		/* tty is not available anymore */
+		issue_command(info, CHA, CMD_RXRESET);
+		if (debug_level >= DEBUG_LEVEL_ISR)
+			printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__);
+		return;
+	}
+
 	if (tcd) {
 		/* early termination, get FIFO count from RBCL register */
 		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
@@ -980,7 +988,7 @@
 	else
 #endif
 	{
-		if (tty->stopped || tty->hw_stopped) {
+		if (tty && (tty->stopped || tty->hw_stopped)) {
 			tx_stop(info);
 			return;
 		}
@@ -1000,7 +1008,7 @@
 		if (!info->tx_active)
 			return;
 	} else {
-		if (tty->stopped || tty->hw_stopped) {
+		if (tty && (tty->stopped || tty->hw_stopped)) {
 			tx_stop(info);
 			return;
 		}
@@ -1050,13 +1058,12 @@
 	wake_up_interruptible(&info->status_event_wait_q);
 	wake_up_interruptible(&info->event_wait_q);
 
-	if (tty_port_cts_enabled(&info->port)) {
+	if (tty && tty_port_cts_enabled(&info->port)) {
 		if (tty->hw_stopped) {
 			if (info->serial_signals & SerialSignal_CTS) {
 				if (debug_level >= DEBUG_LEVEL_ISR)
 					printk("CTS tx start...");
-				if (tty)
-					tty->hw_stopped = 0;
+				tty->hw_stopped = 0;
 				tx_start(info, tty);
 				info->pending_bh |= BH_TRANSMIT;
 				return;
@@ -1065,8 +1072,7 @@
 			if (!(info->serial_signals & SerialSignal_CTS)) {
 				if (debug_level >= DEBUG_LEVEL_ISR)
 					printk("CTS tx stop...");
-				if (tty)
-					tty->hw_stopped = 1;
+				tty->hw_stopped = 1;
 				tx_stop(info);
 			}
 		}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 3fcf80f..d0d824e 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -783,7 +783,8 @@
 		err = PTR_ERR(ppdev_class);
 		goto out_chrdev;
 	}
-	if (parport_register_driver(&pp_driver)) {
+	err = parport_register_driver(&pp_driver);
+	if (err < 0) {
 		printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
 		goto out_class;
 	}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index af94374..91470fd 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -411,7 +411,7 @@
 		case RTC_IRQP_READ:
 		case RTC_IRQP_SET:
 			return -EINVAL;
-		};
+		}
 	}
 #endif
 
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index ce29e7c..e95e0ab 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -784,8 +784,10 @@
 	}
 	tlclk_major = ret;
 	alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
-	if (!alarm_events)
+	if (!alarm_events) {
+		ret = -ENOMEM;
 		goto out1;
+	}
 
 	/* Read telecom clock IRQ number (Set by BIOS) */
 	if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..060a672 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1941,7 +1941,17 @@
 	INIT_LIST_HEAD(&pdrvdata.consoles);
 	INIT_LIST_HEAD(&pdrvdata.portdevs);
 
-	return register_virtio_driver(&virtio_console);
+	err = register_virtio_driver(&virtio_console);
+	if (err < 0) {
+		pr_err("Error %d registering virtio driver\n", err);
+		goto free;
+	}
+	return 0;
+free:
+	if (pdrvdata.debugfs_dir)
+		debugfs_remove_recursive(pdrvdata.debugfs_dir);
+	class_destroy(pdrvdata.class);
+	return err;
 }
 
 static void __exit fini(void)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e48e0da..71a25b9 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,8 +1,10 @@
 # common clock types
+obj-$(CONFIG_HAVE_CLK)		+= clk-devres.o
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
 obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed-rate.o clk-gate.o \
 				   clk-mux.o clk-divider.o clk-fixed-factor.o
 # SoCs specific
+obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
 obj-$(CONFIG_ARCH_NOMADIK)	+= clk-nomadik.o
 obj-$(CONFIG_ARCH_HIGHBANK)	+= clk-highbank.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs/
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c
new file mode 100644
index 0000000..67ad16b
--- /dev/null
+++ b/drivers/clk/clk-bcm2835.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 2012 Stephen Warren
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/bcm2835.h>
+
+/*
+ * These are fixed clocks. They're probably not all root clocks and it may
+ * be possible to turn them on and off but until this is mapped out better
+ * it's the only way they can be used.
+ */
+void __init bcm2835_init_clocks(void)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
+					250000000);
+	if (!clk)
+		pr_err("sys_pclk not registered\n");
+
+	clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
+					126000000);
+	if (!clk)
+		pr_err("apb_pclk not registered\n");
+
+	clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT,
+					3000000);
+	if (!clk)
+		pr_err("uart0_pclk not registered\n");
+	ret = clk_register_clkdev(clk, NULL, "20201000.uart");
+	if (ret)
+		pr_err("uart0_pclk alias not registered\n");
+
+	clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT,
+					125000000);
+	if (!clk)
+		pr_err("uart1_pclk not registered\n");
+	ret = clk_register_clkdev(clk, NULL, "20215000.uart");
+	if (ret)
+		pr_err("uart0_pclk alias not registered\n");
+}
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
new file mode 100644
index 0000000..8f57154
--- /dev/null
+++ b/drivers/clk/clk-devres.c
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+
+static void devm_clk_release(struct device *dev, void *res)
+{
+	clk_put(*(struct clk **)res);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+	struct clk **ptr, *clk;
+
+	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	clk = clk_get(dev, id);
+	if (!IS_ERR(clk)) {
+		*ptr = clk;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return clk;
+}
+EXPORT_SYMBOL(devm_clk_get);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+	struct clk **c = res;
+	if (!c || !*c) {
+		WARN_ON(!c || !*c);
+		return 0;
+	}
+	return *c == data;
+}
+
+void devm_clk_put(struct device *dev, struct clk *clk)
+{
+	int ret;
+
+	ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
+
+	WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_clk_put);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index d423c9b..442a313 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -171,51 +171,6 @@
 }
 EXPORT_SYMBOL(clk_put);
 
-static void devm_clk_release(struct device *dev, void *res)
-{
-	clk_put(*(struct clk **)res);
-}
-
-struct clk *devm_clk_get(struct device *dev, const char *id)
-{
-	struct clk **ptr, *clk;
-
-	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
-		return ERR_PTR(-ENOMEM);
-
-	clk = clk_get(dev, id);
-	if (!IS_ERR(clk)) {
-		*ptr = clk;
-		devres_add(dev, ptr);
-	} else {
-		devres_free(ptr);
-	}
-
-	return clk;
-}
-EXPORT_SYMBOL(devm_clk_get);
-
-static int devm_clk_match(struct device *dev, void *res, void *data)
-{
-	struct clk **c = res;
-	if (!c || !*c) {
-		WARN_ON(!c || !*c);
-		return 0;
-	}
-	return *c == data;
-}
-
-void devm_clk_put(struct device *dev, struct clk *clk)
-{
-	int ret;
-
-	ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk);
-
-	WARN_ON(ret);
-}
-EXPORT_SYMBOL(devm_clk_put);
-
 void clkdev_add(struct clk_lookup *cl)
 {
 	mutex_lock(&clocks_mutex);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d53cd0a..6a78073 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -35,3 +35,8 @@
 	default y
 	help
 	  Use the always on PRCMU Timer as sched_clock
+
+config CLKSRC_ARM_GENERIC
+	def_bool y if ARM64
+	help
+	  This option enables support for the ARM generic timer.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index b65d0c5..603be36 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -13,3 +13,6 @@
 obj-$(CONFIG_DW_APB_TIMER_OF)	+= dw_apb_timer_of.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
+obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
+
+obj-$(CONFIG_CLKSRC_ARM_GENERIC)	+= arm_generic.o
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c
new file mode 100644
index 0000000..c4d9f95
--- /dev/null
+++ b/drivers/clocksource/arm_generic.c
@@ -0,0 +1,232 @@
+/*
+ * Generic timers support
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+#include <clocksource/arm_generic.h>
+
+#include <asm/arm_generic.h>
+
+static u32 arch_timer_rate;
+static u64 sched_clock_mult __read_mostly;
+static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt);
+static int arch_timer_ppi;
+
+static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	if (ctrl & ARCH_TIMER_CTRL_ISTATUS) {
+		ctrl |= ARCH_TIMER_CTRL_IMASK;
+		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+		evt->event_handler(evt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static void arch_timer_stop(void)
+{
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static void arch_timer_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *clk)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		arch_timer_stop();
+		break;
+	default:
+		break;
+	}
+}
+
+static int arch_timer_set_next_event(unsigned long evt,
+				     struct clock_event_device *unused)
+{
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	ctrl |= ARCH_TIMER_CTRL_ENABLE;
+	ctrl &= ~ARCH_TIMER_CTRL_IMASK;
+
+	arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
+	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+
+	return 0;
+}
+
+static void __cpuinit arch_timer_setup(struct clock_event_device *clk)
+{
+	/* Let's make sure the timer is off before doing anything else */
+	arch_timer_stop();
+
+	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
+	clk->name = "arch_sys_timer";
+	clk->rating = 400;
+	clk->set_mode = arch_timer_set_mode;
+	clk->set_next_event = arch_timer_set_next_event;
+	clk->irq = arch_timer_ppi;
+	clk->cpumask = cpumask_of(smp_processor_id());
+
+	clockevents_config_and_register(clk, arch_timer_rate,
+					0xf, 0x7fffffff);
+
+	enable_percpu_irq(clk->irq, 0);
+
+	/* Ensure the physical counter is visible to userspace for the vDSO. */
+	arch_counter_enable_user_access();
+}
+
+static void __init arch_timer_calibrate(void)
+{
+	if (arch_timer_rate == 0) {
+		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
+		arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
+
+		/* Check the timer frequency. */
+		if (arch_timer_rate == 0)
+			panic("Architected timer frequency is set to zero.\n"
+			      "You must set this in your .dts file\n");
+	}
+
+	/* Cache the sched_clock multiplier to save a divide in the hot path. */
+
+	sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
+
+	pr_info("Architected local timer running at %u.%02uMHz.\n",
+		 arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
+}
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+	return arch_counter_get_cntpct();
+}
+
+static struct clocksource clocksource_counter = {
+	.name	= "arch_sys_counter",
+	.rating	= 400,
+	.read	= arch_counter_read,
+	.mask	= CLOCKSOURCE_MASK(56),
+	.flags	= (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES),
+};
+
+int read_current_timer(unsigned long *timer_value)
+{
+	*timer_value = arch_counter_get_cntpct();
+	return 0;
+}
+
+unsigned long long notrace sched_clock(void)
+{
+	return arch_counter_get_cntvct() * sched_clock_mult;
+}
+
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	int cpu = (long)hcpu;
+	struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu);
+
+	switch(action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		arch_timer_setup(clk);
+		break;
+
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+			 clk->irq, cpu);
+		disable_percpu_irq(clk->irq);
+		arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
+	.notifier_call = arch_timer_cpu_notify,
+};
+
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+	{ .compatible = "arm,armv8-timer" },
+	{},
+};
+
+int __init arm_generic_timer_init(void)
+{
+	struct device_node *np;
+	int err;
+	u32 freq;
+
+	np = of_find_matching_node(NULL, arch_timer_of_match);
+	if (!np) {
+		pr_err("arch_timer: can't find DT node\n");
+		return -ENODEV;
+	}
+
+	/* Try to determine the frequency from the device tree or CNTFRQ */
+	if (!of_property_read_u32(np, "clock-frequency", &freq))
+		arch_timer_rate = freq;
+	arch_timer_calibrate();
+
+	arch_timer_ppi = irq_of_parse_and_map(np, 0);
+	pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi);
+
+	err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq,
+				 np->name, &arch_timer_evt);
+	if (err) {
+		pr_err("arch_timer: can't register interrupt %d (%d)\n",
+		       arch_timer_ppi, err);
+		return err;
+	}
+
+	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+
+	/* Calibrate the delay loop directly */
+	lpj_fine = arch_timer_rate / HZ;
+
+	/* Immediately configure the timer on the boot CPU */
+	arch_timer_setup(per_cpu_ptr(&arch_timer_evt, smp_processor_id()));
+
+	register_cpu_notifier(&arch_timer_cpu_nb);
+
+	return 0;
+}
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
new file mode 100644
index 0000000..bc19f12
--- /dev/null
+++ b/drivers/clocksource/bcm2835_timer.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2012 Simon Arlott
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/bcm2835_timer.h>
+#include <linux/bitops.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <asm/sched_clock.h>
+#include <asm/irq.h>
+
+#define REG_CONTROL	0x00
+#define REG_COUNTER_LO	0x04
+#define REG_COUNTER_HI	0x08
+#define REG_COMPARE(n)	(0x0c + (n) * 4)
+#define MAX_TIMER	3
+#define DEFAULT_TIMER	3
+
+struct bcm2835_timer {
+	void __iomem *control;
+	void __iomem *compare;
+	int match_mask;
+	struct clock_event_device evt;
+	struct irqaction act;
+};
+
+static void __iomem *system_clock __read_mostly;
+
+static u32 notrace bcm2835_sched_read(void)
+{
+	return readl_relaxed(system_clock);
+}
+
+static void bcm2835_time_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *evt_dev)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	default:
+		WARN(1, "%s: unhandled event mode %d\n", __func__, mode);
+		break;
+	}
+}
+
+static int bcm2835_time_set_next_event(unsigned long event,
+	struct clock_event_device *evt_dev)
+{
+	struct bcm2835_timer *timer = container_of(evt_dev,
+		struct bcm2835_timer, evt);
+	writel_relaxed(readl_relaxed(system_clock) + event,
+		timer->compare);
+	return 0;
+}
+
+static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
+{
+	struct bcm2835_timer *timer = dev_id;
+	void (*event_handler)(struct clock_event_device *);
+	if (readl_relaxed(timer->control) & timer->match_mask) {
+		writel_relaxed(timer->match_mask, timer->control);
+
+		event_handler = ACCESS_ONCE(timer->evt.event_handler);
+		if (event_handler)
+			event_handler(&timer->evt);
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static struct of_device_id bcm2835_time_match[] __initconst = {
+	{ .compatible = "brcm,bcm2835-system-timer" },
+	{}
+};
+
+static void __init bcm2835_time_init(void)
+{
+	struct device_node *node;
+	void __iomem *base;
+	u32 freq;
+	int irq;
+	struct bcm2835_timer *timer;
+
+	node = of_find_matching_node(NULL, bcm2835_time_match);
+	if (!node)
+		panic("No bcm2835 timer node");
+
+	base = of_iomap(node, 0);
+	if (!base)
+		panic("Can't remap registers");
+
+	if (of_property_read_u32(node, "clock-frequency", &freq))
+		panic("Can't read clock-frequency");
+
+	system_clock = base + REG_COUNTER_LO;
+	setup_sched_clock(bcm2835_sched_read, 32, freq);
+
+	clocksource_mmio_init(base + REG_COUNTER_LO, node->name,
+		freq, 300, 32, clocksource_mmio_readl_up);
+
+	irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
+	if (irq <= 0)
+		panic("Can't parse IRQ");
+
+	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
+	if (!timer)
+		panic("Can't allocate timer struct\n");
+
+	timer->control = base + REG_CONTROL;
+	timer->compare = base + REG_COMPARE(DEFAULT_TIMER);
+	timer->match_mask = BIT(DEFAULT_TIMER);
+	timer->evt.name = node->name;
+	timer->evt.rating = 300;
+	timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
+	timer->evt.set_mode = bcm2835_time_set_mode;
+	timer->evt.set_next_event = bcm2835_time_set_next_event;
+	timer->evt.cpumask = cpumask_of(0);
+	timer->act.name = node->name;
+	timer->act.flags = IRQF_TIMER | IRQF_SHARED;
+	timer->act.dev_id = timer;
+	timer->act.handler = bcm2835_time_interrupt;
+
+	if (setup_irq(irq, &timer->act))
+		panic("Can't set up timer IRQ\n");
+
+	clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
+
+	pr_info("bcm2835: system timer (irq = %d)\n", irq);
+}
+
+struct sys_timer bcm2835_timer = {
+	.init = bcm2835_time_init,
+};
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index c0e8164..1a40935 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -35,7 +35,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/cpumask.h>
-#include <linux/sched.h>	/* for current / set_cpus_allowed() */
 #include <linux/io.h>
 #include <linux/delay.h>
 
@@ -1139,16 +1138,23 @@
 	return res;
 }
 
-/* Driver entry point to switch to the target frequency */
-static int powernowk8_target(struct cpufreq_policy *pol,
-		unsigned targfreq, unsigned relation)
+struct powernowk8_target_arg {
+	struct cpufreq_policy		*pol;
+	unsigned			targfreq;
+	unsigned			relation;
+};
+
+static long powernowk8_target_fn(void *arg)
 {
-	cpumask_var_t oldmask;
+	struct powernowk8_target_arg *pta = arg;
+	struct cpufreq_policy *pol = pta->pol;
+	unsigned targfreq = pta->targfreq;
+	unsigned relation = pta->relation;
 	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
 	u32 checkfid;
 	u32 checkvid;
 	unsigned int newstate;
-	int ret = -EIO;
+	int ret;
 
 	if (!data)
 		return -EINVAL;
@@ -1156,29 +1162,16 @@
 	checkfid = data->currfid;
 	checkvid = data->currvid;
 
-	/* only run on specific CPU from here on. */
-	/* This is poor form: use a workqueue or smp_call_function_single */
-	if (!alloc_cpumask_var(&oldmask, GFP_KERNEL))
-		return -ENOMEM;
-
-	cpumask_copy(oldmask, tsk_cpus_allowed(current));
-	set_cpus_allowed_ptr(current, cpumask_of(pol->cpu));
-
-	if (smp_processor_id() != pol->cpu) {
-		printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
-		goto err_out;
-	}
-
 	if (pending_bit_stuck()) {
 		printk(KERN_ERR PFX "failing targ, change pending bit set\n");
-		goto err_out;
+		return -EIO;
 	}
 
 	pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
 		pol->cpu, targfreq, pol->min, pol->max, relation);
 
 	if (query_current_values_with_pending_wait(data))
-		goto err_out;
+		return -EIO;
 
 	if (cpu_family != CPU_HW_PSTATE) {
 		pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
@@ -1196,7 +1189,7 @@
 
 	if (cpufreq_frequency_table_target(pol, data->powernow_table,
 				targfreq, relation, &newstate))
-		goto err_out;
+		return -EIO;
 
 	mutex_lock(&fidvid_mutex);
 
@@ -1209,9 +1202,8 @@
 		ret = transition_frequency_fidvid(data, newstate);
 	if (ret) {
 		printk(KERN_ERR PFX "transition frequency failed\n");
-		ret = 1;
 		mutex_unlock(&fidvid_mutex);
-		goto err_out;
+		return 1;
 	}
 	mutex_unlock(&fidvid_mutex);
 
@@ -1220,12 +1212,25 @@
 				data->powernow_table[newstate].index);
 	else
 		pol->cur = find_khz_freq_from_fid(data->currfid);
-	ret = 0;
 
-err_out:
-	set_cpus_allowed_ptr(current, oldmask);
-	free_cpumask_var(oldmask);
-	return ret;
+	return 0;
+}
+
+/* Driver entry point to switch to the target frequency */
+static int powernowk8_target(struct cpufreq_policy *pol,
+		unsigned targfreq, unsigned relation)
+{
+	struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq,
+					     .relation = relation };
+
+	/*
+	 * Must run on @pol->cpu.  cpufreq core is responsible for ensuring
+	 * that we're bound to the current CPU and pol->cpu stays online.
+	 */
+	if (smp_processor_id() == pol->cpu)
+		return powernowk8_target_fn(&pta);
+	else
+		return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
 }
 
 /* Driver entry point to verify the policy and range of frequencies */
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 3934fcc..17d6958 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -168,9 +168,9 @@
 }
 
 /**
- * atc_desc_chain - build chain adding a descripor
- * @first: address of first descripor of the chain
- * @prev: address of previous descripor of the chain
+ * atc_desc_chain - build chain adding a descriptor
+ * @first: address of first descriptor of the chain
+ * @prev: address of previous descriptor of the chain
  * @desc: descriptor to queue
  *
  * Called from prep_* functions
@@ -661,7 +661,7 @@
 			flags);
 
 	if (unlikely(!atslave || !sg_len)) {
-		dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+		dev_dbg(chan2dev(chan), "prep_slave_sg: sg length is zero!\n");
 		return NULL;
 	}
 
@@ -689,6 +689,11 @@
 
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
+			if (unlikely(!len)) {
+				dev_dbg(chan2dev(chan),
+					"prep_slave_sg: sg(%d) data length is zero\n", i);
+				goto err;
+			}
 			mem_width = 2;
 			if (unlikely(mem & 3 || len & 3))
 				mem_width = 0;
@@ -724,6 +729,11 @@
 
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
+			if (unlikely(!len)) {
+				dev_dbg(chan2dev(chan),
+					"prep_slave_sg: sg(%d) data length is zero\n", i);
+				goto err;
+			}
 			mem_width = 2;
 			if (unlikely(mem & 3 || len & 3))
 				mem_width = 0;
@@ -757,6 +767,7 @@
 
 err_desc_get:
 	dev_err(chan2dev(chan), "not enough descriptors available\n");
+err:
 	atc_desc_put(atchan, first);
 	return NULL;
 }
@@ -785,7 +796,7 @@
 }
 
 /**
- * atc_dma_cyclic_fill_desc - Fill one period decriptor
+ * atc_dma_cyclic_fill_desc - Fill one period descriptor
  */
 static int
 atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index c64917e..bb02fd9 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -1118,7 +1118,7 @@
  * @chan: channel
  * @dma_addr: DMA mapped address of the buffer
  * @buf_len: length of the buffer (in bytes)
- * @period_len: lenght of a single period
+ * @period_len: length of a single period
  * @dir: direction of the operation
  * @context: operation context (ignored)
  *
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 8f84761..094437b 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1015,7 +1015,7 @@
 	/*
 	 * Programming Error
 	 * The DMA_INTERRUPT async_tx is a NULL transfer, which will
-	 * triger a PE interrupt.
+	 * trigger a PE interrupt.
 	 */
 	if (stat & FSL_DMA_SR_PE) {
 		chan_dbg(chan, "irq: Programming Error INT\n");
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 5084975..54f580b 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -572,8 +572,8 @@
 	if (desc->desc.callback)
 		desc->desc.callback(desc->desc.callback_param);
 
-	/* If we are dealing with a cyclic descriptor keep it on ld_active
-	 * and dont mark the descripor as complete.
+	/* If we are dealing with a cyclic descriptor, keep it on ld_active
+	 * and dont mark the descriptor as complete.
 	 * Only in non-cyclic cases it would be marked as complete
 	 */
 	if (imxdma_chan_is_doing_cyclic(imxdmac))
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 222e907..02b21d7 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -427,7 +427,7 @@
  * intel_mid_dma_tx_submit -	callback to submit DMA transaction
  * @tx: dma engine descriptor
  *
- * Submit the DMA trasaction for this descriptor, start if ch idle
+ * Submit the DMA transaction for this descriptor, start if ch idle
  */
 static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
index 1bfa926..17b4219 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -168,9 +168,9 @@
  * @active_list: current active descriptors
  * @queue: current queued up descriptors
  * @free_list: current free descriptors
- * @slave: dma slave struture
- * @descs_allocated: total number of decsiptors allocated
- * @dma: dma device struture pointer
+ * @slave: dma slave structure
+ * @descs_allocated: total number of descriptors allocated
+ * @dma: dma device structure pointer
  * @busy: bool representing if ch is busy (active txn) or not
  * @in_use: bool representing if ch is in use or not
  * @raw_tfr: raw trf interrupt received
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
index 60e6754..d2ff3fd 100644
--- a/drivers/dma/ioat/hw.h
+++ b/drivers/dma/ioat/hw.h
@@ -22,7 +22,6 @@
 #define _IOAT_HW_H_
 
 /* PCI Configuration Space Values */
-#define IOAT_PCI_VID            0x8086
 #define IOAT_MMIO_BAR		0
 
 /* CB device ID's */
@@ -31,9 +30,6 @@
 #define IOAT_PCI_DID_SCNB       0x65FF
 #define IOAT_PCI_DID_SNB        0x402F
 
-#define IOAT_PCI_RID            0x00
-#define IOAT_PCI_SVID           0x8086
-#define IOAT_PCI_SID            0x8086
 #define IOAT_VER_1_2            0x12    /* Version 1.2 */
 #define IOAT_VER_2_0            0x20    /* Version 2.0 */
 #define IOAT_VER_3_0            0x30    /* Version 3.0 */
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index e4feba6..5d3bbcd 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -522,7 +522,7 @@
 	/* In the DMAC pool */
 	FREE,
 	/*
-	 * Allocted to some channel during prep_xxx
+	 * Allocated to some channel during prep_xxx
 	 * Also may be sitting on the work_list.
 	 */
 	PREP,
@@ -1567,17 +1567,19 @@
 		goto xfer_exit;
 	}
 
-	/* Prefer Secure Channel */
-	if (!_manager_ns(thrd))
-		r->cfg->nonsecure = 0;
-	else
-		r->cfg->nonsecure = 1;
 
 	/* Use last settings, if not provided */
-	if (r->cfg)
+	if (r->cfg) {
+		/* Prefer Secure Channel */
+		if (!_manager_ns(thrd))
+			r->cfg->nonsecure = 0;
+		else
+			r->cfg->nonsecure = 1;
+
 		ccr = _prepare_ccr(r->cfg);
-	else
+	} else {
 		ccr = readl(regs + CC(thrd->id));
+	}
 
 	/* If this req doesn't have valid xfer settings */
 	if (!_is_valid(ccr)) {
@@ -2928,6 +2930,11 @@
 		num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan);
 
 	pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
+	if (!pdmac->peripherals) {
+		ret = -ENOMEM;
+		dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n");
+		goto probe_err5;
+	}
 
 	for (i = 0; i < num_chan; i++) {
 		pch = &pdmac->peripherals[i];
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index ced9882..f72348d 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4446,7 +4446,7 @@
 		ret = -ENOMEM;
 		goto err_dma_alloc;
 	}
-	dev_dbg(&ofdev->dev, "allocted descriptor pool virt 0x%p phys 0x%llx\n",
+	dev_dbg(&ofdev->dev, "allocated descriptor pool virt 0x%p phys 0x%llx\n",
 		adev->dma_desc_pool_virt, (u64)adev->dma_desc_pool);
 
 	regs = ioremap(res.start, resource_size(&res));
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h
index 51e8e53..6d47373 100644
--- a/drivers/dma/ste_dma40_ll.h
+++ b/drivers/dma/ste_dma40_ll.h
@@ -202,7 +202,7 @@
 /* LLI related structures */
 
 /**
- * struct d40_phy_lli - The basic configration register for each physical
+ * struct d40_phy_lli - The basic configuration register for each physical
  * channel.
  *
  * @reg_cfg: The configuration register.
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 24acd71..4708467 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -201,7 +201,7 @@
 	struct clk			*dma_clk;
 	spinlock_t			global_lock;
 	void __iomem			*base_addr;
-	struct tegra_dma_chip_data	*chip_data;
+	const struct tegra_dma_chip_data *chip_data;
 
 	/* Some register need to be cache before suspend */
 	u32				reg_gen;
@@ -1173,14 +1173,14 @@
 }
 
 /* Tegra20 specific DMA controller information */
-static struct tegra_dma_chip_data tegra20_dma_chip_data = {
+static const struct tegra_dma_chip_data tegra20_dma_chip_data = {
 	.nr_channels		= 16,
 	.max_dma_count		= 1024UL * 64,
 };
 
 #if defined(CONFIG_OF)
 /* Tegra30 specific DMA controller information */
-static struct tegra_dma_chip_data tegra30_dma_chip_data = {
+static const struct tegra_dma_chip_data tegra30_dma_chip_data = {
 	.nr_channels		= 32,
 	.max_dma_count		= 1024UL * 64,
 };
@@ -1204,7 +1204,7 @@
 	struct tegra_dma *tdma;
 	int ret;
 	int i;
-	struct tegra_dma_chip_data *cdata = NULL;
+	const struct tegra_dma_chip_data *cdata = NULL;
 
 	if (pdev->dev.of_node) {
 		const struct of_device_id *match;
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 616d90b..d5dc9da 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -199,6 +199,36 @@
 	return (void *)(((unsigned long)ptr) + align - r);
 }
 
+static void _edac_mc_free(struct mem_ctl_info *mci)
+{
+	int i, chn, row;
+	struct csrow_info *csr;
+	const unsigned int tot_dimms = mci->tot_dimms;
+	const unsigned int tot_channels = mci->num_cschannel;
+	const unsigned int tot_csrows = mci->nr_csrows;
+
+	if (mci->dimms) {
+		for (i = 0; i < tot_dimms; i++)
+			kfree(mci->dimms[i]);
+		kfree(mci->dimms);
+	}
+	if (mci->csrows) {
+		for (row = 0; row < tot_csrows; row++) {
+			csr = mci->csrows[row];
+			if (csr) {
+				if (csr->channels) {
+					for (chn = 0; chn < tot_channels; chn++)
+						kfree(csr->channels[chn]);
+					kfree(csr->channels);
+				}
+				kfree(csr);
+			}
+		}
+		kfree(mci->csrows);
+	}
+	kfree(mci);
+}
+
 /**
  * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
  * @mc_num:		Memory controller number
@@ -413,24 +443,7 @@
 	return mci;
 
 error:
-	if (mci->dimms) {
-		for (i = 0; i < tot_dimms; i++)
-			kfree(mci->dimms[i]);
-		kfree(mci->dimms);
-	}
-	if (mci->csrows) {
-		for (chn = 0; chn < tot_channels; chn++) {
-			csr = mci->csrows[chn];
-			if (csr) {
-				for (chn = 0; chn < tot_channels; chn++)
-					kfree(csr->channels[chn]);
-				kfree(csr);
-			}
-			kfree(mci->csrows[i]);
-		}
-		kfree(mci->csrows);
-	}
-	kfree(mci);
+	_edac_mc_free(mci);
 
 	return NULL;
 }
@@ -445,6 +458,14 @@
 {
 	edac_dbg(1, "\n");
 
+	/* If we're not yet registered with sysfs free only what was allocated
+	 * in edac_mc_alloc().
+	 */
+	if (!device_is_registered(&mci->dev)) {
+		_edac_mc_free(mci);
+		return;
+	}
+
 	/* the mci instance is freed here, when the sysfs object is dropped */
 	edac_unregister_sysfs(mci);
 }
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 47180a0..b6653a6 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -391,7 +391,7 @@
 		for (j = 0; j < nr_channels; j++) {
 			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
-			dimm->nr_pages = nr_pages / nr_channels;
+			dimm->nr_pages = nr_pages;
 			dimm->grain = nr_pages << PAGE_SHIFT;
 			dimm->mtype = MEM_DDR2;
 			dimm->dtype = DEV_UNKNOWN;
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 39c6375..6a49dd0 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -1012,6 +1012,10 @@
 			/* add the number of COLUMN bits */
 			addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
 
+			/* Dual-rank memories have twice the size */
+			if (dinfo->dual_rank)
+				addrBits++;
+
 			addrBits += 6;	/* add 64 bits per DIMM */
 			addrBits -= 20;	/* divide by 2^^20 */
 			addrBits -= 3;	/* 8 bits per bytes */
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index f3b1f9f..5715b7c 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -513,7 +513,8 @@
 {
 	struct sbridge_pvt *pvt = mci->pvt_info;
 	struct dimm_info *dimm;
-	int i, j, banks, ranks, rows, cols, size, npages;
+	unsigned i, j, banks, ranks, rows, cols, npages;
+	u64 size;
 	u32 reg;
 	enum edac_type mode;
 	enum mem_type mtype;
@@ -585,10 +586,10 @@
 				cols = numcol(mtr);
 
 				/* DDR3 has 8 I/O banks */
-				size = (rows * cols * banks * ranks) >> (20 - 3);
+				size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
 				npages = MiB_TO_PAGES(size);
 
-				edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+				edac_dbg(0, "mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
 					 pvt->sbridge_dev->mc, i, j,
 					 size, npages,
 					 banks, ranks, rows, cols);
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index e175c8e..07122a9 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -21,6 +21,12 @@
 	  Say Y here to enable GPIO based extcon support. Note that GPIO
 	  extcon supports single state per extcon instance.
 
+config EXTCON_ADC_JACK
+	tristate "ADC Jack extcon support"
+	depends on IIO
+	help
+	  Say Y here to enable extcon device driver based on ADC values.
+
 config EXTCON_MAX77693
 	tristate "MAX77693 EXTCON Support"
 	depends on MFD_MAX77693
@@ -41,7 +47,7 @@
 
 config EXTCON_ARIZONA
 	tristate "Wolfson Arizona EXTCON support"
-	depends on MFD_ARIZONA
+	depends on MFD_ARIZONA && INPUT
 	help
 	  Say Y here to enable support for external accessory detection
 	  with Wolfson Arizona devices. These are audio CODECs with
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 88961b3..f98a3c4 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,8 +2,9 @@
 # Makefile for external connector class (extcon) devices
 #
 
-obj-$(CONFIG_EXTCON)		+= extcon_class.o
-obj-$(CONFIG_EXTCON_GPIO)	+= extcon_gpio.o
+obj-$(CONFIG_EXTCON)		+= extcon-class.o
+obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
+obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o
 obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
 obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
 obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
new file mode 100644
index 0000000..60ac3fb
--- /dev/null
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -0,0 +1,198 @@
+/*
+ * drivers/extcon/extcon-adc-jack.c
+ *
+ * Analog Jack extcon driver with ADC-based detection capability.
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * Modified for calling to IIO to get adc by <anish.singh@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/iio/consumer.h>
+#include <linux/extcon/extcon-adc-jack.h>
+#include <linux/extcon.h>
+
+/**
+ * struct adc_jack_data - internal data for adc_jack device driver
+ * @edev        - extcon device.
+ * @cable_names - list of supported cables.
+ * @num_cables  - size of cable_names.
+ * @adc_conditions       - list of adc value conditions.
+ * @num_conditions       - size of adc_conditions.
+ * @irq         - irq number of attach/detach event (0 if not exist).
+ * @handling_delay      - interrupt handler will schedule extcon event
+ *                      handling at handling_delay jiffies.
+ * @handler     - extcon event handler called by interrupt handler.
+ * @chan       - iio channel being queried.
+ */
+struct adc_jack_data {
+	struct extcon_dev edev;
+
+	const char **cable_names;
+	int num_cables;
+	struct adc_jack_cond *adc_conditions;
+	int num_conditions;
+
+	int irq;
+	unsigned long handling_delay; /* in jiffies */
+	struct delayed_work handler;
+
+	struct iio_channel *chan;
+};
+
+static void adc_jack_handler(struct work_struct *work)
+{
+	struct adc_jack_data *data = container_of(to_delayed_work(work),
+			struct adc_jack_data,
+			handler);
+	u32 state = 0;
+	int ret, adc_val;
+	int i;
+
+	ret = iio_read_channel_raw(data->chan, &adc_val);
+	if (ret < 0) {
+		dev_err(data->edev.dev, "read channel() error: %d\n", ret);
+		return;
+	}
+
+	/* Get state from adc value with adc_conditions */
+	for (i = 0; i < data->num_conditions; i++) {
+		struct adc_jack_cond *def = &data->adc_conditions[i];
+		if (!def->state)
+			break;
+		if (def->min_adc <= adc_val && def->max_adc >= adc_val) {
+			state = def->state;
+			break;
+		}
+	}
+	/* if no def has met, it means state = 0 (no cables attached) */
+
+	extcon_set_state(&data->edev, state);
+}
+
+static irqreturn_t adc_jack_irq_thread(int irq, void *_data)
+{
+	struct adc_jack_data *data = _data;
+
+	schedule_delayed_work(&data->handler, data->handling_delay);
+	return IRQ_HANDLED;
+}
+
+static int __devinit adc_jack_probe(struct platform_device *pdev)
+{
+	struct adc_jack_data *data;
+	struct adc_jack_pdata *pdata = pdev->dev.platform_data;
+	int i, err = 0;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->edev.name = pdata->name;
+
+	if (!pdata->cable_names) {
+		err = -EINVAL;
+		dev_err(&pdev->dev, "error: cable_names not defined.\n");
+		goto out;
+	}
+
+	data->edev.supported_cable = pdata->cable_names;
+
+	/* Check the length of array and set num_cables */
+	for (i = 0; data->edev.supported_cable[i]; i++)
+		;
+	if (i == 0 || i > SUPPORTED_CABLE_MAX) {
+		err = -EINVAL;
+		dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n",
+				i - 1);
+		goto out;
+	}
+	data->num_cables = i;
+
+	if (!pdata->adc_conditions ||
+			!pdata->adc_conditions[0].state) {
+		err = -EINVAL;
+		dev_err(&pdev->dev, "error: adc_conditions not defined.\n");
+		goto out;
+	}
+	data->adc_conditions = pdata->adc_conditions;
+
+	/* Check the length of array and set num_conditions */
+	for (i = 0; data->adc_conditions[i].state; i++)
+		;
+	data->num_conditions = i;
+
+	data->chan = iio_channel_get(dev_name(&pdev->dev),
+			pdata->consumer_channel);
+	if (IS_ERR(data->chan)) {
+		err = PTR_ERR(data->chan);
+		goto out;
+	}
+
+	data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms);
+
+	INIT_DELAYED_WORK_DEFERRABLE(&data->handler, adc_jack_handler);
+
+	platform_set_drvdata(pdev, data);
+
+	err = extcon_dev_register(&data->edev, &pdev->dev);
+	if (err)
+		goto out;
+
+	data->irq = platform_get_irq(pdev, 0);
+	if (!data->irq) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		err = -ENODEV;
+		goto err_irq;
+	}
+
+	err = request_any_context_irq(data->irq, adc_jack_irq_thread,
+			pdata->irq_flags, pdata->name, data);
+
+	if (err) {
+		dev_err(&pdev->dev, "error: irq %d\n", data->irq);
+		err = -EINVAL;
+		goto err_irq;
+	}
+
+	goto out;
+
+err_irq:
+	extcon_dev_unregister(&data->edev);
+out:
+	return err;
+}
+
+static int __devexit adc_jack_remove(struct platform_device *pdev)
+{
+	struct adc_jack_data *data = platform_get_drvdata(pdev);
+
+	free_irq(data->irq, data);
+	cancel_work_sync(&data->handler.work);
+	extcon_dev_unregister(&data->edev);
+
+	return 0;
+}
+
+static struct platform_driver adc_jack_driver = {
+	.probe          = adc_jack_probe,
+	.remove         = __devexit_p(adc_jack_remove),
+	.driver         = {
+		.name   = "adc-jack",
+		.owner  = THIS_MODULE,
+	},
+};
+
+module_platform_driver(adc_jack_driver);
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 427a289..cdab9e5 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
@@ -30,11 +31,14 @@
 #include <linux/mfd/arizona/pdata.h>
 #include <linux/mfd/arizona/registers.h>
 
+#define ARIZONA_NUM_BUTTONS 6
+
 struct arizona_extcon_info {
 	struct device *dev;
 	struct arizona *arizona;
 	struct mutex lock;
 	struct regulator *micvdd;
+	struct input_dev *input;
 
 	int micd_mode;
 	const struct arizona_micd_config *micd_modes;
@@ -54,6 +58,18 @@
 	{ 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
 };
 
+static struct {
+	u16 status;
+	int report;
+} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
+	{  0x1, BTN_0 },
+	{  0x2, BTN_1 },
+	{  0x4, BTN_2 },
+	{  0x8, BTN_3 },
+	{ 0x10, BTN_4 },
+	{ 0x20, BTN_5 },
+};
+
 #define ARIZONA_CABLE_MECHANICAL 0
 #define ARIZONA_CABLE_MICROPHONE 1
 #define ARIZONA_CABLE_HEADPHONE  2
@@ -133,6 +149,7 @@
 
 	if (change) {
 		regulator_disable(info->micvdd);
+		pm_runtime_mark_last_busy(info->dev);
 		pm_runtime_put_autosuspend(info->dev);
 	}
 }
@@ -141,8 +158,8 @@
 {
 	struct arizona_extcon_info *info = data;
 	struct arizona *arizona = info->arizona;
-	unsigned int val;
-	int ret;
+	unsigned int val, lvl;
+	int ret, i;
 
 	mutex_lock(&info->lock);
 
@@ -219,13 +236,22 @@
 
 	/*
 	 * If we're still detecting and we detect a short then we've
-	 * got a headphone.  Otherwise it's a button press, the
-	 * button reporting is stubbed out for now.
+	 * got a headphone.  Otherwise it's a button press.
 	 */
 	if (val & 0x3fc) {
 		if (info->mic) {
 			dev_dbg(arizona->dev, "Mic button detected\n");
 
+			lvl = val & ARIZONA_MICD_LVL_MASK;
+			lvl >>= ARIZONA_MICD_LVL_SHIFT;
+
+			for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+				if (lvl & arizona_lvl_to_key[i].status)
+					input_report_key(info->input,
+							 arizona_lvl_to_key[i].report,
+							 1);
+			input_sync(info->input);
+
 		} else if (info->detecting) {
 			dev_dbg(arizona->dev, "Headphone detected\n");
 			info->detecting = false;
@@ -244,6 +270,10 @@
 		}
 	} else {
 		dev_dbg(arizona->dev, "Mic button released\n");
+		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+			input_report_key(info->input,
+					 arizona_lvl_to_key[i].report, 0);
+		input_sync(info->input);
 	}
 
 handled:
@@ -258,7 +288,7 @@
 	struct arizona_extcon_info *info = data;
 	struct arizona *arizona = info->arizona;
 	unsigned int val;
-	int ret;
+	int ret, i;
 
 	pm_runtime_get_sync(info->dev);
 
@@ -288,6 +318,11 @@
 
 		arizona_stop_mic(info);
 
+		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+			input_report_key(info->input,
+					 arizona_lvl_to_key[i].report, 0);
+		input_sync(info->input);
+
 		ret = extcon_update_state(&info->edev, 0xffffffff, 0);
 		if (ret != 0)
 			dev_err(arizona->dev, "Removal report failed: %d\n",
@@ -307,13 +342,13 @@
 	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
 	struct arizona_pdata *pdata;
 	struct arizona_extcon_info *info;
-	int ret, mode;
+	int ret, mode, i;
 
 	pdata = dev_get_platdata(arizona->dev);
 
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
+		dev_err(&pdev->dev, "Failed to allocate memory\n");
 		ret = -ENOMEM;
 		goto err;
 	}
@@ -350,7 +385,7 @@
 
 	ret = extcon_dev_register(&info->edev, arizona->dev);
 	if (ret < 0) {
-		dev_err(arizona->dev, "extcon_dev_regster() failed: %d\n",
+		dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
 			ret);
 		goto err;
 	}
@@ -382,6 +417,20 @@
 
 	arizona_extcon_set_mode(info, 0);
 
+	info->input = input_allocate_device();
+	if (!info->input) {
+		dev_err(arizona->dev, "Can't allocate input dev\n");
+		ret = -ENOMEM;
+		goto err_register;
+	}
+
+	for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+		input_set_capability(info->input, EV_KEY,
+				     arizona_lvl_to_key[i].report);
+	info->input->name = "Headset";
+	info->input->phys = "arizona/extcon";
+	info->input->dev.parent = &pdev->dev;
+
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_idle(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
@@ -391,7 +440,7 @@
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
 			ret);
-		goto err_register;
+		goto err_input;
 	}
 
 	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
@@ -434,10 +483,23 @@
 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
 			   ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
 
+	ret = regulator_allow_bypass(info->micvdd, true);
+	if (ret != 0)
+		dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
+			 ret);
+
 	pm_runtime_put(&pdev->dev);
 
+	ret = input_register_device(info->input);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
+		goto err_micdet;
+	}
+
 	return 0;
 
+err_micdet:
+	arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
 err_fall_wake:
 	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
 err_fall:
@@ -446,6 +508,8 @@
 	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
 err_rise:
 	arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
+err_input:
+	input_free_device(info->input);
 err_register:
 	pm_runtime_disable(&pdev->dev);
 	extcon_dev_unregister(&info->edev);
@@ -468,6 +532,7 @@
 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
 			   ARIZONA_JD1_ENA, 0);
 	arizona_clk32k_disable(arizona);
+	input_unregister_device(info->input);
 	extcon_dev_unregister(&info->edev);
 
 	return 0;
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
new file mode 100644
index 0000000..946a318
--- /dev/null
+++ b/drivers/extcon/extcon-class.c
@@ -0,0 +1,836 @@
+/*
+ *  drivers/extcon/extcon_class.c
+ *
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+/*
+ * extcon_cable_name suggests the standard cable names for commonly used
+ * cable types.
+ *
+ * However, please do not use extcon_cable_name directly for extcon_dev
+ * struct's supported_cable pointer unless your device really supports
+ * every single port-type of the following cable names. Please choose cable
+ * names that are actually used in your extcon device.
+ */
+const char *extcon_cable_name[] = {
+	[EXTCON_USB]		= "USB",
+	[EXTCON_USB_HOST]	= "USB-Host",
+	[EXTCON_TA]		= "TA",
+	[EXTCON_FAST_CHARGER]	= "Fast-charger",
+	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
+	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
+	[EXTCON_HDMI]		= "HDMI",
+	[EXTCON_MHL]		= "MHL",
+	[EXTCON_DVI]		= "DVI",
+	[EXTCON_VGA]		= "VGA",
+	[EXTCON_DOCK]		= "Dock",
+	[EXTCON_LINE_IN]	= "Line-in",
+	[EXTCON_LINE_OUT]	= "Line-out",
+	[EXTCON_MIC_IN]		= "Microphone",
+	[EXTCON_HEADPHONE_OUT]	= "Headphone",
+	[EXTCON_SPDIF_IN]	= "SPDIF-in",
+	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
+	[EXTCON_VIDEO_IN]	= "Video-in",
+	[EXTCON_VIDEO_OUT]	= "Video-out",
+	[EXTCON_MECHANICAL]	= "Mechanical",
+
+	NULL,
+};
+
+static struct class *extcon_class;
+#if defined(CONFIG_ANDROID)
+static struct class_compat *switch_class;
+#endif /* CONFIG_ANDROID */
+
+static LIST_HEAD(extcon_dev_list);
+static DEFINE_MUTEX(extcon_dev_list_lock);
+
+/**
+ * check_mutually_exclusive - Check if new_state violates mutually_exclusive
+ *			    condition.
+ * @edev:	the extcon device
+ * @new_state:	new cable attach status for @edev
+ *
+ * Returns 0 if nothing violates. Returns the index + 1 for the first
+ * violated condition.
+ */
+static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
+{
+	int i = 0;
+
+	if (!edev->mutually_exclusive)
+		return 0;
+
+	for (i = 0; edev->mutually_exclusive[i]; i++) {
+		int count = 0, j;
+		u32 correspondants = new_state & edev->mutually_exclusive[i];
+		u32 exp = 1;
+
+		for (j = 0; j < 32; j++) {
+			if (exp & correspondants)
+				count++;
+			if (count > 1)
+				return i + 1;
+			exp <<= 1;
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int i, count = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	if (edev->print_state) {
+		int ret = edev->print_state(edev, buf);
+
+		if (ret >= 0)
+			return ret;
+		/* Use default if failed */
+	}
+
+	if (edev->max_supported == 0)
+		return sprintf(buf, "%u\n", edev->state);
+
+	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
+		if (!edev->supported_cable[i])
+			break;
+		count += sprintf(buf + count, "%s=%d\n",
+				 edev->supported_cable[i],
+				 !!(edev->state & (1 << i)));
+	}
+
+	return count;
+}
+
+int extcon_set_state(struct extcon_dev *edev, u32 state);
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	u32 state;
+	ssize_t ret = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	ret = sscanf(buf, "0x%x", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_state(edev, state);
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	/* Optional callback given by the user */
+	if (edev->print_name) {
+		int ret = edev->print_name(edev, buf);
+		if (ret >= 0)
+			return ret;
+	}
+
+	return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+static ssize_t cable_name_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_name);
+
+	return sprintf(buf, "%s\n",
+		       cable->edev->supported_cable[cable->cable_index]);
+}
+
+static ssize_t cable_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+
+	return sprintf(buf, "%d\n",
+		       extcon_get_cable_state_(cable->edev,
+					       cable->cable_index));
+}
+
+static ssize_t cable_state_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+	int ret, state;
+
+	ret = sscanf(buf, "%d", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
+					      state);
+
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+/**
+ * extcon_update_state() - Update the cable attach states of the extcon device
+ *			only for the masked bits.
+ * @edev:	the extcon device
+ * @mask:	the bit mask to designate updated bits.
+ * @state:	new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ *
+ * Note that the notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+{
+	char name_buf[120];
+	char state_buf[120];
+	char *prop_buf;
+	char *envp[3];
+	int env_offset = 0;
+	int length;
+	unsigned long flags;
+
+	spin_lock_irqsave(&edev->lock, flags);
+
+	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+		u32 old_state = edev->state;
+
+		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
+						   (state & mask))) {
+			spin_unlock_irqrestore(&edev->lock, flags);
+			return -EPERM;
+		}
+
+		edev->state &= ~mask;
+		edev->state |= state & mask;
+
+		raw_notifier_call_chain(&edev->nh, old_state, edev);
+
+		/* This could be in interrupt handler */
+		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+		if (prop_buf) {
+			length = name_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(name_buf, sizeof(name_buf),
+					"NAME=%s", prop_buf);
+				envp[env_offset++] = name_buf;
+			}
+			length = state_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(state_buf, sizeof(state_buf),
+					"STATE=%s", prop_buf);
+				envp[env_offset++] = state_buf;
+			}
+			envp[env_offset] = NULL;
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+			free_page((unsigned long)prop_buf);
+		} else {
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			dev_err(edev->dev, "out of memory in extcon_set_state\n");
+			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+		}
+	} else {
+		/* No changes */
+		spin_unlock_irqrestore(&edev->lock, flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(extcon_update_state);
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev:	the extcon device
+ * @state:	new cable attach status for @edev
+ *
+ * Note that notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+	return extcon_update_state(edev, 0xffffffff, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+/**
+ * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name to be searched.
+ *
+ * Note that accessing a cable state based on cable_index is faster than
+ * cable_name because using cable_name induces a loop with strncmp().
+ * Thus, when get/set_cable_state is repeatedly used, using cable_index
+ * is recommended.
+ */
+int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+{
+	int i;
+
+	if (edev->supported_cable) {
+		for (i = 0; edev->supported_cable[i]; i++) {
+			if (!strncmp(edev->supported_cable[i],
+				cable_name, CABLE_NAME_MAX))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(extcon_find_cable_index);
+
+/**
+ * extcon_get_cable_state_() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ */
+int extcon_get_cable_state_(struct extcon_dev *edev, int index)
+{
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	return !!(edev->state & (1 << index));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ *
+ * Note that this is slower than extcon_get_cable_state_.
+ */
+int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
+{
+	return extcon_get_cable_state_(edev, extcon_find_cable_index
+						(edev, cable_name));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state);
+
+/**
+ * extcon_get_cable_state_() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ */
+int extcon_set_cable_state_(struct extcon_dev *edev,
+			int index, bool cable_state)
+{
+	u32 state;
+
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	state = cable_state ? (1 << index) : 0;
+	return extcon_update_state(edev, 1 << index, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ *
+ * Note that this is slower than extcon_set_cable_state_.
+ */
+int extcon_set_cable_state(struct extcon_dev *edev,
+			const char *cable_name, bool cable_state)
+{
+	return extcon_set_cable_state_(edev, extcon_find_cable_index
+					(edev, cable_name), cable_state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state);
+
+/**
+ * extcon_get_extcon_dev() - Get the extcon device instance from the name
+ * @extcon_name:	The extcon name provided with extcon_dev_register()
+ */
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+	struct extcon_dev *sd;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_for_each_entry(sd, &extcon_dev_list, entry) {
+		if (!strcmp(sd->name, extcon_name))
+			goto out;
+	}
+	sd = NULL;
+out:
+	mutex_unlock(&extcon_dev_list_lock);
+	return sd;
+}
+EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
+
+static int _call_per_cable(struct notifier_block *nb, unsigned long val,
+			   void *ptr)
+{
+	struct extcon_specific_cable_nb *obj = container_of(nb,
+			struct extcon_specific_cable_nb, internal_nb);
+	struct extcon_dev *edev = ptr;
+
+	if ((val & (1 << obj->cable_index)) !=
+	    (edev->state & (1 << obj->cable_index))) {
+		bool cable_state = true;
+
+		obj->previous_value = val;
+
+		if (val & (1 << obj->cable_index))
+			cable_state = false;
+
+		return obj->user_nb->notifier_call(obj->user_nb,
+				cable_state, ptr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * extcon_register_interest() - Register a notifier for a state change of a
+ *			      specific cable, not an entier set of cables of a
+ *			      extcon device.
+ * @obj:	an empty extcon_specific_cable_nb object to be returned.
+ * @extcon_name:	the name of extcon device.
+ * @cable_name:		the target cable name.
+ * @nb:		the notifier block to get notified.
+ *
+ * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
+ * the struct for you.
+ *
+ * extcon_register_interest is a helper function for those who want to get
+ * notification for a single specific cable's status change. If a user wants
+ * to get notification for any changes of all cables of a extcon device,
+ * he/she should use the general extcon_register_notifier().
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+			     const char *extcon_name, const char *cable_name,
+			     struct notifier_block *nb)
+{
+	if (!obj || !extcon_name || !cable_name || !nb)
+		return -EINVAL;
+
+	obj->edev = extcon_get_extcon_dev(extcon_name);
+	if (!obj->edev)
+		return -ENODEV;
+
+	obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
+	if (obj->cable_index < 0)
+		return -ENODEV;
+
+	obj->user_nb = nb;
+
+	obj->internal_nb.notifier_call = _call_per_cable;
+
+	return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_unregister_interest() - Unregister the notifier registered by
+ *				extcon_register_interest().
+ * @obj:	the extcon_specific_cable_nb object returned by
+ *		extcon_register_interest().
+ */
+int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
+{
+	if (!obj)
+		return -EINVAL;
+
+	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_register_notifier() - Register a notifiee to get notified by
+ *			      any attach status changes from the extcon.
+ * @edev:	the extcon device.
+ * @nb:		a notifier block to be registered.
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_register_notifier);
+
+/**
+ * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
+ * @edev:	the extcon device.
+ * @nb:		a registered notifier block to be unregistered.
+ */
+int extcon_unregister_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_unregister(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
+
+static struct device_attribute extcon_attrs[] = {
+	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
+	__ATTR_RO(name),
+	__ATTR_NULL,
+};
+
+static int create_extcon_class(void)
+{
+	if (!extcon_class) {
+		extcon_class = class_create(THIS_MODULE, "extcon");
+		if (IS_ERR(extcon_class))
+			return PTR_ERR(extcon_class);
+		extcon_class->dev_attrs = extcon_attrs;
+
+#if defined(CONFIG_ANDROID)
+		switch_class = class_compat_register("switch");
+		if (WARN(!switch_class, "cannot allocate"))
+			return -ENOMEM;
+#endif /* CONFIG_ANDROID */
+	}
+
+	return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+	mutex_lock(&extcon_dev_list_lock);
+	list_del(&edev->entry);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	if (!skip && get_device(edev->dev)) {
+		int index;
+
+		if (edev->mutually_exclusive && edev->max_supported) {
+			for (index = 0; edev->mutually_exclusive[index];
+			     index++)
+				kfree(edev->d_attrs_muex[index].attr.name);
+			kfree(edev->d_attrs_muex);
+			kfree(edev->attrs_muex);
+		}
+
+		for (index = 0; index < edev->max_supported; index++)
+			kfree(edev->cables[index].attr_g.name);
+
+		if (edev->max_supported) {
+			kfree(edev->extcon_dev_type.groups);
+			kfree(edev->cables);
+		}
+
+		device_unregister(edev->dev);
+		put_device(edev->dev);
+	}
+
+	kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	extcon_cleanup(edev, true);
+}
+
+static const char *muex_name = "mutually_exclusive";
+static void dummy_sysfs_dev_release(struct device *dev)
+{
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev	: the new extcon device (should be allocated before calling)
+ * @dev		: the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+	int ret, index = 0;
+
+	if (!extcon_class) {
+		ret = create_extcon_class();
+		if (ret < 0)
+			return ret;
+	}
+
+	if (edev->supported_cable) {
+		/* Get size of array */
+		for (index = 0; edev->supported_cable[index]; index++)
+			;
+		edev->max_supported = index;
+	} else {
+		edev->max_supported = 0;
+	}
+
+	if (index > SUPPORTED_CABLE_MAX) {
+		dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+		return -EINVAL;
+	}
+
+	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!edev->dev)
+		return -ENOMEM;
+	edev->dev->parent = dev;
+	edev->dev->class = extcon_class;
+	edev->dev->release = extcon_dev_release;
+
+	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+
+	if (edev->max_supported) {
+		char buf[10];
+		char *str;
+		struct extcon_cable *cable;
+
+		edev->cables = kzalloc(sizeof(struct extcon_cable) *
+				       edev->max_supported, GFP_KERNEL);
+		if (!edev->cables) {
+			ret = -ENOMEM;
+			goto err_sysfs_alloc;
+		}
+		for (index = 0; index < edev->max_supported; index++) {
+			cable = &edev->cables[index];
+
+			snprintf(buf, 10, "cable.%d", index);
+			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				      GFP_KERNEL);
+			if (!str) {
+				for (index--; index >= 0; index--) {
+					cable = &edev->cables[index];
+					kfree(cable->attr_g.name);
+				}
+				ret = -ENOMEM;
+
+				goto err_alloc_cables;
+			}
+			strcpy(str, buf);
+
+			cable->edev = edev;
+			cable->cable_index = index;
+			cable->attrs[0] = &cable->attr_name.attr;
+			cable->attrs[1] = &cable->attr_state.attr;
+			cable->attrs[2] = NULL;
+			cable->attr_g.name = str;
+			cable->attr_g.attrs = cable->attrs;
+
+			sysfs_attr_init(&cable->attr_name.attr);
+			cable->attr_name.attr.name = "name";
+			cable->attr_name.attr.mode = 0444;
+			cable->attr_name.show = cable_name_show;
+
+			sysfs_attr_init(&cable->attr_state.attr);
+			cable->attr_state.attr.name = "state";
+			cable->attr_state.attr.mode = 0644;
+			cable->attr_state.show = cable_state_show;
+			cable->attr_state.store = cable_state_store;
+		}
+	}
+
+	if (edev->max_supported && edev->mutually_exclusive) {
+		char buf[80];
+		char *name;
+
+		/* Count the size of mutually_exclusive array */
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			;
+
+		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
+					   (index + 1), GFP_KERNEL);
+		if (!edev->attrs_muex) {
+			ret = -ENOMEM;
+			goto err_muex;
+		}
+
+		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
+					     index, GFP_KERNEL);
+		if (!edev->d_attrs_muex) {
+			ret = -ENOMEM;
+			kfree(edev->attrs_muex);
+			goto err_muex;
+		}
+
+		for (index = 0; edev->mutually_exclusive[index]; index++) {
+			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
+			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				       GFP_KERNEL);
+			if (!name) {
+				for (index--; index >= 0; index--) {
+					kfree(edev->d_attrs_muex[index].attr.
+					      name);
+				}
+				kfree(edev->d_attrs_muex);
+				kfree(edev->attrs_muex);
+				ret = -ENOMEM;
+				goto err_muex;
+			}
+			strcpy(name, buf);
+			sysfs_attr_init(&edev->d_attrs_muex[index].attr);
+			edev->d_attrs_muex[index].attr.name = name;
+			edev->d_attrs_muex[index].attr.mode = 0000;
+			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
+							.attr;
+		}
+		edev->attr_g_muex.name = muex_name;
+		edev->attr_g_muex.attrs = edev->attrs_muex;
+
+	}
+
+	if (edev->max_supported) {
+		edev->extcon_dev_type.groups =
+			kzalloc(sizeof(struct attribute_group *) *
+				(edev->max_supported + 2), GFP_KERNEL);
+		if (!edev->extcon_dev_type.groups) {
+			ret = -ENOMEM;
+			goto err_alloc_groups;
+		}
+
+		edev->extcon_dev_type.name = dev_name(edev->dev);
+		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+		for (index = 0; index < edev->max_supported; index++)
+			edev->extcon_dev_type.groups[index] =
+				&edev->cables[index].attr_g;
+		if (edev->mutually_exclusive)
+			edev->extcon_dev_type.groups[index] =
+				&edev->attr_g_muex;
+
+		edev->dev->type = &edev->extcon_dev_type;
+	}
+
+	ret = device_register(edev->dev);
+	if (ret) {
+		put_device(edev->dev);
+		goto err_dev;
+	}
+#if defined(CONFIG_ANDROID)
+	if (switch_class)
+		ret = class_compat_create_link(switch_class, edev->dev,
+					       NULL);
+#endif /* CONFIG_ANDROID */
+
+	spin_lock_init(&edev->lock);
+
+	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+
+	dev_set_drvdata(edev->dev, edev);
+	edev->state = 0;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_add(&edev->entry, &extcon_dev_list);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	return 0;
+
+err_dev:
+	if (edev->max_supported)
+		kfree(edev->extcon_dev_type.groups);
+err_alloc_groups:
+	if (edev->max_supported && edev->mutually_exclusive) {
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			kfree(edev->d_attrs_muex[index].attr.name);
+		kfree(edev->d_attrs_muex);
+		kfree(edev->attrs_muex);
+	}
+err_muex:
+	for (index = 0; index < edev->max_supported; index++)
+		kfree(edev->cables[index].attr_g.name);
+err_alloc_cables:
+	if (edev->max_supported)
+		kfree(edev->cables);
+err_sysfs_alloc:
+	kfree(edev->dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev:	the extcon device instance to be unregistered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+	extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+	return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+	class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon-gpio.c
similarity index 100%
rename from drivers/extcon/extcon_gpio.c
rename to drivers/extcon/extcon-gpio.c
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 38f9e52..e21387e 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -356,7 +356,7 @@
 		extcon_set_cable_state(info->edev, "MHL", attached);
 		break;
 	default:
-		dev_err(info->dev, "faild to detect %s accessory\n",
+		dev_err(info->dev, "failed to detect %s accessory\n",
 			attached ? "attached" : "detached");
 		dev_err(info->dev, "- adc:0x%x, adclow:0x%x, adc1k:0x%x\n",
 			adc, adclow, adc1k);
@@ -548,7 +548,7 @@
 		curr_adc = info->status[0] & STATUS1_ADC_MASK;
 		curr_adc >>= STATUS1_ADC_SHIFT;
 
-		/* Check accossory state which is either detached or attached */
+		/* Check accessory state which is either detached or attached */
 		if (curr_adc == MAX77693_MUIC_ADC_OPEN)
 			attached = false;
 
@@ -564,7 +564,7 @@
 		curr_chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
 		curr_chg_type >>= STATUS2_CHGTYP_SHIFT;
 
-		/* Check charger accossory state which
+		/* Check charger accessory state which
 		   is either detached or attached */
 		if (curr_chg_type == MAX77693_CHARGER_TYPE_NONE)
 			attached = false;
@@ -699,7 +699,7 @@
 
 		ret = request_threaded_irq(virq, NULL,
 				max77693_muic_irq_handler,
-				0, muic_irq->name, info);
+				IRQF_ONESHOT, muic_irq->name, info);
 		if (ret) {
 			dev_err(&pdev->dev,
 				"failed: irq request (IRQ: %d,"
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
deleted file mode 100644
index f6419f9..0000000
--- a/drivers/extcon/extcon_class.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- *  drivers/extcon/extcon_class.c
- *
- *  External connector (extcon) class driver
- *
- * Copyright (C) 2012 Samsung Electronics
- * Author: Donggeun Kim <dg77.kim@samsung.com>
- * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * based on android/drivers/switch/switch_class.c
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/extcon.h>
-#include <linux/slab.h>
-
-/*
- * extcon_cable_name suggests the standard cable names for commonly used
- * cable types.
- *
- * However, please do not use extcon_cable_name directly for extcon_dev
- * struct's supported_cable pointer unless your device really supports
- * every single port-type of the following cable names. Please choose cable
- * names that are actually used in your extcon device.
- */
-const char *extcon_cable_name[] = {
-	[EXTCON_USB]		= "USB",
-	[EXTCON_USB_HOST]	= "USB-Host",
-	[EXTCON_TA]		= "TA",
-	[EXTCON_FAST_CHARGER]	= "Fast-charger",
-	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
-	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
-	[EXTCON_HDMI]		= "HDMI",
-	[EXTCON_MHL]		= "MHL",
-	[EXTCON_DVI]		= "DVI",
-	[EXTCON_VGA]		= "VGA",
-	[EXTCON_DOCK]		= "Dock",
-	[EXTCON_LINE_IN]	= "Line-in",
-	[EXTCON_LINE_OUT]	= "Line-out",
-	[EXTCON_MIC_IN]		= "Microphone",
-	[EXTCON_HEADPHONE_OUT]	= "Headphone",
-	[EXTCON_SPDIF_IN]	= "SPDIF-in",
-	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
-	[EXTCON_VIDEO_IN]	= "Video-in",
-	[EXTCON_VIDEO_OUT]	= "Video-out",
-	[EXTCON_MECHANICAL]	= "Mechanical",
-
-	NULL,
-};
-
-static struct class *extcon_class;
-#if defined(CONFIG_ANDROID)
-static struct class_compat *switch_class;
-#endif /* CONFIG_ANDROID */
-
-static LIST_HEAD(extcon_dev_list);
-static DEFINE_MUTEX(extcon_dev_list_lock);
-
-/**
- * check_mutually_exclusive - Check if new_state violates mutually_exclusive
- *			    condition.
- * @edev:	the extcon device
- * @new_state:	new cable attach status for @edev
- *
- * Returns 0 if nothing violates. Returns the index + 1 for the first
- * violated condition.
- */
-static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
-{
-	int i = 0;
-
-	if (!edev->mutually_exclusive)
-		return 0;
-
-	for (i = 0; edev->mutually_exclusive[i]; i++) {
-		int count = 0, j;
-		u32 correspondants = new_state & edev->mutually_exclusive[i];
-		u32 exp = 1;
-
-		for (j = 0; j < 32; j++) {
-			if (exp & correspondants)
-				count++;
-			if (count > 1)
-				return i + 1;
-			exp <<= 1;
-		}
-	}
-
-	return 0;
-}
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-			  char *buf)
-{
-	int i, count = 0;
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	if (edev->print_state) {
-		int ret = edev->print_state(edev, buf);
-
-		if (ret >= 0)
-			return ret;
-		/* Use default if failed */
-	}
-
-	if (edev->max_supported == 0)
-		return sprintf(buf, "%u\n", edev->state);
-
-	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
-		if (!edev->supported_cable[i])
-			break;
-		count += sprintf(buf + count, "%s=%d\n",
-				 edev->supported_cable[i],
-				 !!(edev->state & (1 << i)));
-	}
-
-	return count;
-}
-
-int extcon_set_state(struct extcon_dev *edev, u32 state);
-static ssize_t state_store(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
-{
-	u32 state;
-	ssize_t ret = 0;
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	ret = sscanf(buf, "0x%x", &state);
-	if (ret == 0)
-		ret = -EINVAL;
-	else
-		ret = extcon_set_state(edev, state);
-
-	if (ret < 0)
-		return ret;
-
-	return count;
-}
-
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	/* Optional callback given by the user */
-	if (edev->print_name) {
-		int ret = edev->print_name(edev, buf);
-		if (ret >= 0)
-			return ret;
-	}
-
-	return sprintf(buf, "%s\n", dev_name(edev->dev));
-}
-
-static ssize_t cable_name_show(struct device *dev,
-			       struct device_attribute *attr, char *buf)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_name);
-
-	return sprintf(buf, "%s\n",
-		       cable->edev->supported_cable[cable->cable_index]);
-}
-
-static ssize_t cable_state_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_state);
-
-	return sprintf(buf, "%d\n",
-		       extcon_get_cable_state_(cable->edev,
-					       cable->cable_index));
-}
-
-static ssize_t cable_state_store(struct device *dev,
-				 struct device_attribute *attr, const char *buf,
-				 size_t count)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_state);
-	int ret, state;
-
-	ret = sscanf(buf, "%d", &state);
-	if (ret == 0)
-		ret = -EINVAL;
-	else
-		ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
-					      state);
-
-	if (ret < 0)
-		return ret;
-	return count;
-}
-
-/**
- * extcon_update_state() - Update the cable attach states of the extcon device
- *			only for the masked bits.
- * @edev:	the extcon device
- * @mask:	the bit mask to designate updated bits.
- * @state:	new cable attach status for @edev
- *
- * Changing the state sends uevent with environment variable containing
- * the name of extcon device (envp[0]) and the state output (envp[1]).
- * Tizen uses this format for extcon device to get events from ports.
- * Android uses this format as well.
- *
- * Note that the notifier provides which bits are changed in the state
- * variable with the val parameter (second) to the callback.
- */
-int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
-{
-	char name_buf[120];
-	char state_buf[120];
-	char *prop_buf;
-	char *envp[3];
-	int env_offset = 0;
-	int length;
-	unsigned long flags;
-
-	spin_lock_irqsave(&edev->lock, flags);
-
-	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
-		u32 old_state = edev->state;
-
-		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
-						   (state & mask))) {
-			spin_unlock_irqrestore(&edev->lock, flags);
-			return -EPERM;
-		}
-
-		edev->state &= ~mask;
-		edev->state |= state & mask;
-
-		raw_notifier_call_chain(&edev->nh, old_state, edev);
-
-		/* This could be in interrupt handler */
-		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
-		if (prop_buf) {
-			length = name_show(edev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(name_buf, sizeof(name_buf),
-					"NAME=%s", prop_buf);
-				envp[env_offset++] = name_buf;
-			}
-			length = state_show(edev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(state_buf, sizeof(state_buf),
-					"STATE=%s", prop_buf);
-				envp[env_offset++] = state_buf;
-			}
-			envp[env_offset] = NULL;
-			/* Unlock early before uevent */
-			spin_unlock_irqrestore(&edev->lock, flags);
-
-			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
-			free_page((unsigned long)prop_buf);
-		} else {
-			/* Unlock early before uevent */
-			spin_unlock_irqrestore(&edev->lock, flags);
-
-			dev_err(edev->dev, "out of memory in extcon_set_state\n");
-			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
-		}
-	} else {
-		/* No changes */
-		spin_unlock_irqrestore(&edev->lock, flags);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(extcon_update_state);
-
-/**
- * extcon_set_state() - Set the cable attach states of the extcon device.
- * @edev:	the extcon device
- * @state:	new cable attach status for @edev
- *
- * Note that notifier provides which bits are changed in the state
- * variable with the val parameter (second) to the callback.
- */
-int extcon_set_state(struct extcon_dev *edev, u32 state)
-{
-	return extcon_update_state(edev, 0xffffffff, state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_state);
-
-/**
- * extcon_find_cable_index() - Get the cable index based on the cable name.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name to be searched.
- *
- * Note that accessing a cable state based on cable_index is faster than
- * cable_name because using cable_name induces a loop with strncmp().
- * Thus, when get/set_cable_state is repeatedly used, using cable_index
- * is recommended.
- */
-int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
-{
-	int i;
-
-	if (edev->supported_cable) {
-		for (i = 0; edev->supported_cable[i]; i++) {
-			if (!strncmp(edev->supported_cable[i],
-				cable_name, CABLE_NAME_MAX))
-				return i;
-		}
-	}
-
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(extcon_find_cable_index);
-
-/**
- * extcon_get_cable_state_() - Get the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @index:	cable index that can be retrieved by extcon_find_cable_index().
- */
-int extcon_get_cable_state_(struct extcon_dev *edev, int index)
-{
-	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
-		return -EINVAL;
-
-	return !!(edev->state & (1 << index));
-}
-EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
-
-/**
- * extcon_get_cable_state() - Get the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name.
- *
- * Note that this is slower than extcon_get_cable_state_.
- */
-int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
-{
-	return extcon_get_cable_state_(edev, extcon_find_cable_index
-						(edev, cable_name));
-}
-EXPORT_SYMBOL_GPL(extcon_get_cable_state);
-
-/**
- * extcon_get_cable_state_() - Set the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @index:	cable index that can be retrieved by extcon_find_cable_index().
- * @cable_state:	the new cable status. The default semantics is
- *			true: attached / false: detached.
- */
-int extcon_set_cable_state_(struct extcon_dev *edev,
-			int index, bool cable_state)
-{
-	u32 state;
-
-	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
-		return -EINVAL;
-
-	state = cable_state ? (1 << index) : 0;
-	return extcon_update_state(edev, 1 << index, state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
-
-/**
- * extcon_get_cable_state() - Set the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name.
- * @cable_state:	the new cable status. The default semantics is
- *			true: attached / false: detached.
- *
- * Note that this is slower than extcon_set_cable_state_.
- */
-int extcon_set_cable_state(struct extcon_dev *edev,
-			const char *cable_name, bool cable_state)
-{
-	return extcon_set_cable_state_(edev, extcon_find_cable_index
-					(edev, cable_name), cable_state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_cable_state);
-
-/**
- * extcon_get_extcon_dev() - Get the extcon device instance from the name
- * @extcon_name:	The extcon name provided with extcon_dev_register()
- */
-struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
-{
-	struct extcon_dev *sd;
-
-	mutex_lock(&extcon_dev_list_lock);
-	list_for_each_entry(sd, &extcon_dev_list, entry) {
-		if (!strcmp(sd->name, extcon_name))
-			goto out;
-	}
-	sd = NULL;
-out:
-	mutex_unlock(&extcon_dev_list_lock);
-	return sd;
-}
-EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
-
-static int _call_per_cable(struct notifier_block *nb, unsigned long val,
-			   void *ptr)
-{
-	struct extcon_specific_cable_nb *obj = container_of(nb,
-			struct extcon_specific_cable_nb, internal_nb);
-	struct extcon_dev *edev = ptr;
-
-	if ((val & (1 << obj->cable_index)) !=
-	    (edev->state & (1 << obj->cable_index))) {
-		bool cable_state = true;
-
-		obj->previous_value = val;
-
-		if (val & (1 << obj->cable_index))
-			cable_state = false;
-
-		return obj->user_nb->notifier_call(obj->user_nb,
-				cable_state, ptr);
-	}
-
-	return NOTIFY_OK;
-}
-
-/**
- * extcon_register_interest() - Register a notifier for a state change of a
- *			      specific cable, not a entier set of cables of a
- *			      extcon device.
- * @obj:	an empty extcon_specific_cable_nb object to be returned.
- * @extcon_name:	the name of extcon device.
- * @cable_name:		the target cable name.
- * @nb:		the notifier block to get notified.
- *
- * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
- * the struct for you.
- *
- * extcon_register_interest is a helper function for those who want to get
- * notification for a single specific cable's status change. If a user wants
- * to get notification for any changes of all cables of a extcon device,
- * he/she should use the general extcon_register_notifier().
- *
- * Note that the second parameter given to the callback of nb (val) is
- * "old_state", not the current state. The current state can be retrieved
- * by looking at the third pameter (edev pointer)'s state value.
- */
-int extcon_register_interest(struct extcon_specific_cable_nb *obj,
-			     const char *extcon_name, const char *cable_name,
-			     struct notifier_block *nb)
-{
-	if (!obj || !extcon_name || !cable_name || !nb)
-		return -EINVAL;
-
-	obj->edev = extcon_get_extcon_dev(extcon_name);
-	if (!obj->edev)
-		return -ENODEV;
-
-	obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
-	if (obj->cable_index < 0)
-		return -ENODEV;
-
-	obj->user_nb = nb;
-
-	obj->internal_nb.notifier_call = _call_per_cable;
-
-	return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
-}
-
-/**
- * extcon_unregister_interest() - Unregister the notifier registered by
- *				extcon_register_interest().
- * @obj:	the extcon_specific_cable_nb object returned by
- *		extcon_register_interest().
- */
-int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
-{
-	if (!obj)
-		return -EINVAL;
-
-	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
-}
-
-/**
- * extcon_register_notifier() - Register a notifee to get notified by
- *			      any attach status changes from the extcon.
- * @edev:	the extcon device.
- * @nb:		a notifier block to be registered.
- *
- * Note that the second parameter given to the callback of nb (val) is
- * "old_state", not the current state. The current state can be retrieved
- * by looking at the third pameter (edev pointer)'s state value.
- */
-int extcon_register_notifier(struct extcon_dev *edev,
-			struct notifier_block *nb)
-{
-	return raw_notifier_chain_register(&edev->nh, nb);
-}
-EXPORT_SYMBOL_GPL(extcon_register_notifier);
-
-/**
- * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
- * @edev:	the extcon device.
- * @nb:		a registered notifier block to be unregistered.
- */
-int extcon_unregister_notifier(struct extcon_dev *edev,
-			struct notifier_block *nb)
-{
-	return raw_notifier_chain_unregister(&edev->nh, nb);
-}
-EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
-
-static struct device_attribute extcon_attrs[] = {
-	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
-	__ATTR_RO(name),
-	__ATTR_NULL,
-};
-
-static int create_extcon_class(void)
-{
-	if (!extcon_class) {
-		extcon_class = class_create(THIS_MODULE, "extcon");
-		if (IS_ERR(extcon_class))
-			return PTR_ERR(extcon_class);
-		extcon_class->dev_attrs = extcon_attrs;
-
-#if defined(CONFIG_ANDROID)
-		switch_class = class_compat_register("switch");
-		if (WARN(!switch_class, "cannot allocate"))
-			return -ENOMEM;
-#endif /* CONFIG_ANDROID */
-	}
-
-	return 0;
-}
-
-static void extcon_cleanup(struct extcon_dev *edev, bool skip)
-{
-	mutex_lock(&extcon_dev_list_lock);
-	list_del(&edev->entry);
-	mutex_unlock(&extcon_dev_list_lock);
-
-	if (!skip && get_device(edev->dev)) {
-		int index;
-
-		if (edev->mutually_exclusive && edev->max_supported) {
-			for (index = 0; edev->mutually_exclusive[index];
-			     index++)
-				kfree(edev->d_attrs_muex[index].attr.name);
-			kfree(edev->d_attrs_muex);
-			kfree(edev->attrs_muex);
-		}
-
-		for (index = 0; index < edev->max_supported; index++)
-			kfree(edev->cables[index].attr_g.name);
-
-		if (edev->max_supported) {
-			kfree(edev->extcon_dev_type.groups);
-			kfree(edev->cables);
-		}
-
-		device_unregister(edev->dev);
-		put_device(edev->dev);
-	}
-
-	kfree(edev->dev);
-}
-
-static void extcon_dev_release(struct device *dev)
-{
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	extcon_cleanup(edev, true);
-}
-
-static const char *muex_name = "mutually_exclusive";
-static void dummy_sysfs_dev_release(struct device *dev)
-{
-}
-
-/**
- * extcon_dev_register() - Register a new extcon device
- * @edev	: the new extcon device (should be allocated before calling)
- * @dev		: the parent device for this extcon device.
- *
- * Among the members of edev struct, please set the "user initializing data"
- * in any case and set the "optional callbacks" if required. However, please
- * do not set the values of "internal data", which are initialized by
- * this function.
- */
-int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
-{
-	int ret, index = 0;
-
-	if (!extcon_class) {
-		ret = create_extcon_class();
-		if (ret < 0)
-			return ret;
-	}
-
-	if (edev->supported_cable) {
-		/* Get size of array */
-		for (index = 0; edev->supported_cable[index]; index++)
-			;
-		edev->max_supported = index;
-	} else {
-		edev->max_supported = 0;
-	}
-
-	if (index > SUPPORTED_CABLE_MAX) {
-		dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
-		return -EINVAL;
-	}
-
-	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-	if (!edev->dev)
-		return -ENOMEM;
-	edev->dev->parent = dev;
-	edev->dev->class = extcon_class;
-	edev->dev->release = extcon_dev_release;
-
-	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
-
-	if (edev->max_supported) {
-		char buf[10];
-		char *str;
-		struct extcon_cable *cable;
-
-		edev->cables = kzalloc(sizeof(struct extcon_cable) *
-				       edev->max_supported, GFP_KERNEL);
-		if (!edev->cables) {
-			ret = -ENOMEM;
-			goto err_sysfs_alloc;
-		}
-		for (index = 0; index < edev->max_supported; index++) {
-			cable = &edev->cables[index];
-
-			snprintf(buf, 10, "cable.%d", index);
-			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
-				      GFP_KERNEL);
-			if (!str) {
-				for (index--; index >= 0; index--) {
-					cable = &edev->cables[index];
-					kfree(cable->attr_g.name);
-				}
-				ret = -ENOMEM;
-
-				goto err_alloc_cables;
-			}
-			strcpy(str, buf);
-
-			cable->edev = edev;
-			cable->cable_index = index;
-			cable->attrs[0] = &cable->attr_name.attr;
-			cable->attrs[1] = &cable->attr_state.attr;
-			cable->attrs[2] = NULL;
-			cable->attr_g.name = str;
-			cable->attr_g.attrs = cable->attrs;
-
-			cable->attr_name.attr.name = "name";
-			cable->attr_name.attr.mode = 0444;
-			cable->attr_name.show = cable_name_show;
-
-			cable->attr_state.attr.name = "state";
-			cable->attr_state.attr.mode = 0644;
-			cable->attr_state.show = cable_state_show;
-			cable->attr_state.store = cable_state_store;
-		}
-	}
-
-	if (edev->max_supported && edev->mutually_exclusive) {
-		char buf[80];
-		char *name;
-
-		/* Count the size of mutually_exclusive array */
-		for (index = 0; edev->mutually_exclusive[index]; index++)
-			;
-
-		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
-					   (index + 1), GFP_KERNEL);
-		if (!edev->attrs_muex) {
-			ret = -ENOMEM;
-			goto err_muex;
-		}
-
-		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
-					     index, GFP_KERNEL);
-		if (!edev->d_attrs_muex) {
-			ret = -ENOMEM;
-			kfree(edev->attrs_muex);
-			goto err_muex;
-		}
-
-		for (index = 0; edev->mutually_exclusive[index]; index++) {
-			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
-			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
-				       GFP_KERNEL);
-			if (!name) {
-				for (index--; index >= 0; index--) {
-					kfree(edev->d_attrs_muex[index].attr.
-					      name);
-				}
-				kfree(edev->d_attrs_muex);
-				kfree(edev->attrs_muex);
-				ret = -ENOMEM;
-				goto err_muex;
-			}
-			strcpy(name, buf);
-			edev->d_attrs_muex[index].attr.name = name;
-			edev->d_attrs_muex[index].attr.mode = 0000;
-			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
-							.attr;
-		}
-		edev->attr_g_muex.name = muex_name;
-		edev->attr_g_muex.attrs = edev->attrs_muex;
-
-	}
-
-	if (edev->max_supported) {
-		edev->extcon_dev_type.groups =
-			kzalloc(sizeof(struct attribute_group *) *
-				(edev->max_supported + 2), GFP_KERNEL);
-		if (!edev->extcon_dev_type.groups) {
-			ret = -ENOMEM;
-			goto err_alloc_groups;
-		}
-
-		edev->extcon_dev_type.name = dev_name(edev->dev);
-		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
-
-		for (index = 0; index < edev->max_supported; index++)
-			edev->extcon_dev_type.groups[index] =
-				&edev->cables[index].attr_g;
-		if (edev->mutually_exclusive)
-			edev->extcon_dev_type.groups[index] =
-				&edev->attr_g_muex;
-
-		edev->dev->type = &edev->extcon_dev_type;
-	}
-
-	ret = device_register(edev->dev);
-	if (ret) {
-		put_device(edev->dev);
-		goto err_dev;
-	}
-#if defined(CONFIG_ANDROID)
-	if (switch_class)
-		ret = class_compat_create_link(switch_class, edev->dev,
-					       NULL);
-#endif /* CONFIG_ANDROID */
-
-	spin_lock_init(&edev->lock);
-
-	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
-
-	dev_set_drvdata(edev->dev, edev);
-	edev->state = 0;
-
-	mutex_lock(&extcon_dev_list_lock);
-	list_add(&edev->entry, &extcon_dev_list);
-	mutex_unlock(&extcon_dev_list_lock);
-
-	return 0;
-
-err_dev:
-	if (edev->max_supported)
-		kfree(edev->extcon_dev_type.groups);
-err_alloc_groups:
-	if (edev->max_supported && edev->mutually_exclusive) {
-		for (index = 0; edev->mutually_exclusive[index]; index++)
-			kfree(edev->d_attrs_muex[index].attr.name);
-		kfree(edev->d_attrs_muex);
-		kfree(edev->attrs_muex);
-	}
-err_muex:
-	for (index = 0; index < edev->max_supported; index++)
-		kfree(edev->cables[index].attr_g.name);
-err_alloc_cables:
-	if (edev->max_supported)
-		kfree(edev->cables);
-err_sysfs_alloc:
-	kfree(edev->dev);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(extcon_dev_register);
-
-/**
- * extcon_dev_unregister() - Unregister the extcon device.
- * @edev:	the extcon device instance to be unregitered.
- *
- * Note that this does not call kfree(edev) because edev was not allocated
- * by this class.
- */
-void extcon_dev_unregister(struct extcon_dev *edev)
-{
-	extcon_cleanup(edev, false);
-}
-EXPORT_SYMBOL_GPL(extcon_dev_unregister);
-
-static int __init extcon_class_init(void)
-{
-	return create_extcon_class();
-}
-module_init(extcon_class_init);
-
-static void __exit extcon_class_exit(void)
-{
-	class_destroy(extcon_class);
-}
-module_exit(extcon_class_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
-MODULE_DESCRIPTION("External connector (extcon) class driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 47408e8..d10c987 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -435,12 +435,23 @@
 	if (status != EFI_SUCCESS)
 		return -EIO;
 
-	if (var->Attributes & 0x1)
+	if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
 		str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
-	if (var->Attributes & 0x2)
+	if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
 		str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
-	if (var->Attributes & 0x4)
+	if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
 		str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
+	if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+		str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
+	if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+		str += sprintf(str,
+			"EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
+	if (var->Attributes &
+			EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+		str += sprintf(str,
+			"EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
+	if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
+		str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
 	return str - buf;
 }
 
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 8a420f1..ed94b4e 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -308,6 +308,7 @@
 {
 	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
 
+	__set_gpio_level_p012(group, pin, value);
 	__set_gpio_dir_p012(group, pin, 0);
 
 	return 0;
@@ -318,6 +319,7 @@
 {
 	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
 
+	__set_gpio_level_p3(group, pin, value);
 	__set_gpio_dir_p3(group, pin, 0);
 
 	return 0;
@@ -326,6 +328,9 @@
 static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpo_level_p3(group, pin, value);
 	return 0;
 }
 
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 5a1817e..9ae29cc 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -38,7 +38,7 @@
 	 */
 	u32 data;
 	struct irq_domain *irq;
-	void *of_dev_id_data;
+	const void *of_dev_id_data;
 };
 
 static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 64fbce3..94cbc84 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1059,7 +1059,7 @@
 	struct device *dev = &pdev->dev;
 	struct device_node *node = dev->of_node;
 	const struct of_device_id *match;
-	struct omap_gpio_platform_data *pdata;
+	const struct omap_gpio_platform_data *pdata;
 	struct resource *res;
 	struct gpio_bank *bank;
 	int ret = 0;
@@ -1441,19 +1441,19 @@
 	.fallingdetect =	OMAP4_GPIO_FALLINGDETECT,
 };
 
-static struct omap_gpio_platform_data omap2_pdata = {
+const static struct omap_gpio_platform_data omap2_pdata = {
 	.regs = &omap2_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = false,
 };
 
-static struct omap_gpio_platform_data omap3_pdata = {
+const static struct omap_gpio_platform_data omap3_pdata = {
 	.regs = &omap2_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = true,
 };
 
-static struct omap_gpio_platform_data omap4_pdata = {
+const static struct omap_gpio_platform_data omap4_pdata = {
 	.regs = &omap4_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = true,
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index f4814a8..8af4b06 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -3194,46 +3194,6 @@
 }
 EXPORT_SYMBOL(s3c_gpio_getpull);
 
-/* gpiolib wrappers until these are totally eliminated */
-
-void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
-{
-	int ret;
-
-	WARN_ON(to);	/* should be none of these left */
-
-	if (!to) {
-		/* if pull is enabled, try first with up, and if that
-		 * fails, try using down */
-
-		ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP);
-		if (ret)
-			s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN);
-	} else {
-		s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE);
-	}
-}
-EXPORT_SYMBOL(s3c2410_gpio_pullup);
-
-void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
-{
-	/* do this via gpiolib until all users removed */
-
-	gpio_request(pin, "temporary");
-	gpio_set_value(pin, to);
-	gpio_free(pin);
-}
-EXPORT_SYMBOL(s3c2410_gpio_setpin);
-
-unsigned int s3c2410_gpio_getpin(unsigned int pin)
-{
-	struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
-	unsigned long offs = pin - chip->chip.base;
-
-	return __raw_readl(chip->base + 0x04) & (1 << offs);
-}
-EXPORT_SYMBOL(s3c2410_gpio_getpin);
-
 #ifdef CONFIG_S5P_GPIO_DRVSTR
 s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
 {
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index dc5184d..d982593 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -30,9 +30,6 @@
 
 #include <asm/mach/irq.h>
 
-#include <mach/iomap.h>
-#include <mach/suspend.h>
-
 #define GPIO_BANK(x)		((x) >> 5)
 #define GPIO_PORT(x)		(((x) >> 3) & 0x3)
 #define GPIO_BIT(x)		((x) & 0x7)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 489e2b1..274d25d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3242,7 +3242,8 @@
 {
 	int ret;
 
-	BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+	if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
+		return -EBUSY;
 
 	if (obj->gtt_space != NULL) {
 		if ((alignment && obj->gtt_offset & (alignment - 1)) ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bc2ad34..c040aee 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4191,12 +4191,6 @@
 	POSTING_READ(DPLL(pipe));
 	udelay(150);
 
-	I915_WRITE(DPLL(pipe), dpll);
-
-	/* Wait for the clocks to stabilize. */
-	POSTING_READ(DPLL(pipe));
-	udelay(150);
-
 	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
 	 * This is an exception to the general rule that mode_set doesn't turn
 	 * things on.
@@ -4204,6 +4198,12 @@
 	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
 		intel_update_lvds(crtc, clock, adjusted_mode);
 
+	I915_WRITE(DPLL(pipe), dpll);
+
+	/* Wait for the clocks to stabilize. */
+	POSTING_READ(DPLL(pipe));
+	udelay(150);
+
 	/* The pixel multiplier can only be updated once the
 	 * DPLL is enabled and the clocks are stable.
 	 *
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 98f6024..12dc330 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -609,7 +609,7 @@
 	u32 temp;
 	u32 enable_bits = SDVO_ENABLE;
 
-	if (intel_hdmi->has_audio)
+	if (intel_hdmi->has_audio || mode != DRM_MODE_DPMS_ON)
 		enable_bits |= SDVO_AUDIO_ENABLE;
 
 	temp = I915_READ(intel_hdmi->sdvox_reg);
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index ff23d88..3ca240b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -179,7 +179,7 @@
 			return 0;
 	} else
 	if (init->class == 0x906e) {
-		NV_ERROR(dev, "906e not supported yet\n");
+		NV_DEBUG(dev, "906e not supported yet\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
index f034905..c399d51 100644
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 
+#include <linux/dmi.h>
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
@@ -110,13 +111,25 @@
 		nv_wr32(dev, 0xe074, intr1);
 }
 
+static struct dmi_system_id gpio_reset_ids[] = {
+	{
+		.ident = "Apple Macbook 10,1",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
+		}
+	},
+	{ }
+};
+
 int
 nv50_gpio_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
 	/* initialise gpios and routing to vbios defaults */
-	nouveau_gpio_reset(dev);
+	if (dmi_check_system(gpio_reset_ids))
+		nouveau_gpio_reset(dev);
 
 	/* disable, and ack any pending gpio interrupts */
 	nv_wr32(dev, 0xe050, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c
index f704e94..f376c39 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fb.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fb.c
@@ -124,6 +124,7 @@
 	priv = dev_priv->engine.fb.priv;
 
 	nv_wr32(dev, 0x100c10, priv->r100c10 >> 8);
+	nv_mask(dev, 0x17e820, 0x00100000, 0x00000000); /* NV_PLTCG_INTR_EN */
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 7d85553..cd39eb9 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -373,7 +373,8 @@
 static void
 nvc0_fifo_isr(struct drm_device *dev)
 {
-	u32 stat = nv_rd32(dev, 0x002100);
+	u32 mask = nv_rd32(dev, 0x002140);
+	u32 stat = nv_rd32(dev, 0x002100) & mask;
 
 	if (stat & 0x00000100) {
 		NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
diff --git a/drivers/gpu/drm/nouveau/nve0_fifo.c b/drivers/gpu/drm/nouveau/nve0_fifo.c
index e98d144..281bece 100644
--- a/drivers/gpu/drm/nouveau/nve0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nve0_fifo.c
@@ -345,7 +345,8 @@
 static void
 nve0_fifo_isr(struct drm_device *dev)
 {
-	u32 stat = nv_rd32(dev, 0x002100);
+	u32 mask = nv_rd32(dev, 0x002140);
+	u32 stat = nv_rd32(dev, 0x002100) & mask;
 
 	if (stat & 0x00000100) {
 		NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index e721e30..2817101 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1479,98 +1479,14 @@
 	}
 }
 
-/**
- * radeon_get_pll_use_mask - look up a mask of which pplls are in use
- *
- * @crtc: drm crtc
- *
- * Returns the mask of which PPLLs (Pixel PLLs) are in use.
- */
-static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_crtc *test_crtc;
-	struct radeon_crtc *radeon_test_crtc;
-	u32 pll_in_use = 0;
-
-	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc == test_crtc)
-			continue;
-
-		radeon_test_crtc = to_radeon_crtc(test_crtc);
-		if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
-			pll_in_use |= (1 << radeon_test_crtc->pll_id);
-	}
-	return pll_in_use;
-}
-
-/**
- * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP
- *
- * @crtc: drm crtc
- *
- * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is
- * also in DP mode.  For DP, a single PPLL can be used for all DP
- * crtcs/encoders.
- */
-static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_encoder *test_encoder;
-	struct radeon_crtc *radeon_test_crtc;
-
-	list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
-		if (test_encoder->crtc && (test_encoder->crtc != crtc)) {
-			if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
-				/* for DP use the same PLL for all */
-				radeon_test_crtc = to_radeon_crtc(test_encoder->crtc);
-				if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
-					return radeon_test_crtc->pll_id;
-			}
-		}
-	}
-	return ATOM_PPLL_INVALID;
-}
-
-/**
- * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc.
- *
- * @crtc: drm crtc
- *
- * Returns the PPLL (Pixel PLL) to be used by the crtc.  For DP monitors
- * a single PPLL can be used for all DP crtcs/encoders.  For non-DP
- * monitors a dedicated PPLL must be used.  If a particular board has
- * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
- * as there is no need to program the PLL itself.  If we are not able to
- * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
- * avoid messing up an existing monitor.
- *
- * Asic specific PLL information
- *
- * DCE 6.1
- * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
- * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
- *
- * DCE 6.0
- * - PPLL0 is available to all UNIPHY (DP only)
- * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
- *
- * DCE 5.0
- * - DCPLL is available to all UNIPHY (DP only)
- * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
- *
- * DCE 3.0/4.0/4.1
- * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
- *
- */
 static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_encoder *test_encoder;
-	u32 pll_in_use;
-	int pll;
+	struct drm_crtc *test_crtc;
+	uint32_t pll_in_use = 0;
 
 	if (ASIC_IS_DCE61(rdev)) {
 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
@@ -1582,40 +1498,32 @@
 
 				if ((test_radeon_encoder->encoder_id ==
 				     ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
-				    (dig->linkb == false))
-					/* UNIPHY A uses PPLL2 */
+				    (dig->linkb == false)) /* UNIPHY A uses PPLL2 */
 					return ATOM_PPLL2;
-				else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
-					/* UNIPHY B/C/D/E/F */
-					if (rdev->clock.dp_extclk)
-						/* skip PPLL programming if using ext clock */
-						return ATOM_PPLL_INVALID;
-					else {
-						/* use the same PPLL for all DP monitors */
-						pll = radeon_get_shared_dp_ppll(crtc);
-						if (pll != ATOM_PPLL_INVALID)
-							return pll;
-					}
-				}
-				break;
 			}
 		}
 		/* UNIPHY B/C/D/E/F */
-		pll_in_use = radeon_get_pll_use_mask(crtc);
-		if (!(pll_in_use & (1 << ATOM_PPLL0)))
+		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+			struct radeon_crtc *radeon_test_crtc;
+
+			if (crtc == test_crtc)
+				continue;
+
+			radeon_test_crtc = to_radeon_crtc(test_crtc);
+			if ((radeon_test_crtc->pll_id == ATOM_PPLL0) ||
+			    (radeon_test_crtc->pll_id == ATOM_PPLL1))
+				pll_in_use |= (1 << radeon_test_crtc->pll_id);
+		}
+		if (!(pll_in_use & 4))
 			return ATOM_PPLL0;
-		if (!(pll_in_use & (1 << ATOM_PPLL1)))
-			return ATOM_PPLL1;
-		DRM_ERROR("unable to allocate a PPLL\n");
-		return ATOM_PPLL_INVALID;
+		return ATOM_PPLL1;
 	} else if (ASIC_IS_DCE4(rdev)) {
 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
 			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
 				/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
 				 * depending on the asic:
 				 * DCE4: PPLL or ext clock
-				 * DCE5: PPLL, DCPLL, or ext clock
-				 * DCE6: PPLL, PPLL0, or ext clock
+				 * DCE5: DCPLL or ext clock
 				 *
 				 * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
 				 * PPLL/DCPLL programming and only program the DP DTO for the
@@ -1623,34 +1531,31 @@
 				 */
 				if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
 					if (rdev->clock.dp_extclk)
-						/* skip PPLL programming if using ext clock */
 						return ATOM_PPLL_INVALID;
 					else if (ASIC_IS_DCE6(rdev))
-						/* use PPLL0 for all DP */
 						return ATOM_PPLL0;
 					else if (ASIC_IS_DCE5(rdev))
-						/* use DCPLL for all DP */
 						return ATOM_DCPLL;
-					else {
-						/* use the same PPLL for all DP monitors */
-						pll = radeon_get_shared_dp_ppll(crtc);
-						if (pll != ATOM_PPLL_INVALID)
-							return pll;
-					}
 				}
-				break;
 			}
 		}
-		/* all other cases */
-		pll_in_use = radeon_get_pll_use_mask(crtc);
-		if (!(pll_in_use & (1 << ATOM_PPLL2)))
-			return ATOM_PPLL2;
-		if (!(pll_in_use & (1 << ATOM_PPLL1)))
+
+		/* otherwise, pick one of the plls */
+		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+			struct radeon_crtc *radeon_test_crtc;
+
+			if (crtc == test_crtc)
+				continue;
+
+			radeon_test_crtc = to_radeon_crtc(test_crtc);
+			if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
+			    (radeon_test_crtc->pll_id <= ATOM_PPLL2))
+				pll_in_use |= (1 << radeon_test_crtc->pll_id);
+		}
+		if (!(pll_in_use & 1))
 			return ATOM_PPLL1;
-		DRM_ERROR("unable to allocate a PPLL\n");
-		return ATOM_PPLL_INVALID;
+		return ATOM_PPLL2;
 	} else
-		/* use PPLL1 or PPLL2 */
 		return radeon_crtc->crtc_id;
 
 }
@@ -1792,7 +1697,7 @@
 		break;
 	}
 done:
-	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
+	radeon_crtc->pll_id = -1;
 }
 
 static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@@ -1841,6 +1746,6 @@
 		else
 			radeon_crtc->crtc_offset = 0;
 	}
-	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
+	radeon_crtc->pll_id = -1;
 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
 }
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index e93b80a..ed3340a 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -77,13 +77,9 @@
 void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
 {
 	u16 ctl, v;
-	int cap, err;
+	int err;
 
-	cap = pci_pcie_cap(rdev->pdev);
-	if (!cap)
-		return;
-
-	err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl);
+	err = pcie_capability_read_word(rdev->pdev, PCI_EXP_DEVCTL, &ctl);
 	if (err)
 		return;
 
@@ -95,7 +91,7 @@
 	if ((v == 0) || (v == 6) || (v == 7)) {
 		ctl &= ~PCI_EXP_DEVCTL_READRQ;
 		ctl |= (2 << 12);
-		pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl);
+		pcie_capability_write_word(rdev->pdev, PCI_EXP_DEVCTL, ctl);
 	}
 }
 
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 8acb34f..8d7e33a 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -1182,7 +1182,8 @@
 	ring->ready = true;
 	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
-	if (radeon_ring_supports_scratch_reg(rdev, ring)) {
+	if (!ring->rptr_save_reg /* not resuming from suspend */
+	    && radeon_ring_supports_scratch_reg(rdev, ring)) {
 		r = radeon_scratch_get(rdev, &ring->rptr_save_reg);
 		if (r) {
 			DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r);
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index ba055e9..8d9dc44 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -69,6 +69,13 @@
 static int udl_mode_valid(struct drm_connector *connector,
 			  struct drm_display_mode *mode)
 {
+	struct udl_device *udl = connector->dev->dev_private;
+	if (!udl->sku_pixel_limit)
+		return 0;
+
+	if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit)
+		return MODE_VIRTUAL_Y;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index f2fb8f1..7e07433 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -1018,7 +1018,7 @@
 	}
 
 
-	event = kzalloc(sizeof(event->event), GFP_KERNEL);
+	event = kzalloc(sizeof(*event), GFP_KERNEL);
 	if (unlikely(event == NULL)) {
 		DRM_ERROR("Failed to allocate an event.\n");
 		ret = -ENOMEM;
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 3df8fc0..e893f6e 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -141,7 +141,11 @@
 
 void vga_set_default_device(struct pci_dev *pdev)
 {
-	vga_default = pdev;
+	if (vga_default == pdev)
+		return;
+
+	pci_dev_put(vga_default);
+	vga_default = pci_dev_get(pdev);
 }
 #endif
 
@@ -577,7 +581,7 @@
 #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
 	if (vga_default == NULL &&
 	    ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK))
-		vga_default = pci_dev_get(pdev);
+		vga_set_default_device(pdev);
 #endif
 
 	vga_arbiter_check_bridge_sharing(vgadev);
@@ -613,10 +617,8 @@
 	}
 
 #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
-	if (vga_default == pdev) {
-		pci_dev_put(vga_default);
-		vga_default = NULL;
-	}
+	if (vga_default == pdev)
+		vga_set_default_device(NULL);
 #endif
 
 	if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM))
@@ -1066,7 +1068,6 @@
 		}
 
 	} else if (strncmp(curr_pos, "target ", 7) == 0) {
-		struct pci_bus *pbus;
 		unsigned int domain, bus, devfn;
 		struct vga_device *vgadev;
 
@@ -1085,19 +1086,11 @@
 			pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos,
 				domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 
-			pbus = pci_find_bus(domain, bus);
-			pr_debug("vgaarb: pbus %p\n", pbus);
-			if (pbus == NULL) {
-				pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n",
-					domain, bus);
-				ret_val = -ENODEV;
-				goto done;
-			}
-			pdev = pci_get_slot(pbus, devfn);
+			pdev = pci_get_domain_bus_and_slot(domain, bus, devfn);
 			pr_debug("vgaarb: pdev %p\n", pdev);
 			if (!pdev) {
-				pr_err("vgaarb: invalid PCI address %x:%x\n",
-					bus, devfn);
+				pr_err("vgaarb: invalid PCI address %x:%x:%x\n",
+					domain, bus, devfn);
 				ret_val = -ENODEV;
 				goto done;
 			}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fbf4950..1630150 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -307,7 +307,6 @@
 config HID_LOGITECH_DJ
 	tristate "Logitech Unifying receivers full support"
 	depends on HID_LOGITECH
-	default m
 	---help---
 	Say Y if you want support for Logitech Unifying receivers and devices.
 	Unifying receivers are capable of pairing up to 6 Logitech compliant
@@ -527,6 +526,14 @@
 	---help---
 	  Provide access to PicoLCD's GPO pins via leds class.
 
+config HID_PICOLCD_CIR
+	bool "CIR via RC class" if EXPERT
+	default !EXPERT
+	depends on HID_PICOLCD
+	depends on HID_PICOLCD=RC_CORE || RC_CORE=y
+	---help---
+	  Provide access to PicoLCD's CIR interface via remote control (LIRC).
+
 config HID_PRIMAX
 	tristate "Primax non-fully HID-compliant devices"
 	depends on USB_HID
@@ -534,6 +541,15 @@
 	Support for Primax devices that are not fully compliant with the
 	HID standard.
 
+config HID_PS3REMOTE
+	tristate "Sony PS3 BD Remote Control"
+	depends on BT_HIDP
+	---help---
+	Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
+	Harmony Adapter for PS3, which connect over Bluetooth.
+
+	Support for the 6-axis controllers is provided by HID_SONY.
+
 config HID_ROCCAT
 	tristate "Roccat device support"
 	depends on USB_HID
@@ -561,7 +577,9 @@
 	tristate "Sony PS3 controller"
 	depends on USB_HID
 	---help---
-	Support for Sony PS3 controller.
+	Support for Sony PS3 6-axis controllers.
+
+	Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
 
 config HID_SPEEDLINK
 	tristate "Speedlink VAD Cezanne mouse support"
@@ -690,6 +708,20 @@
 	---help---
 	Support for Zydacron remote control.
 
+config HID_SENSOR_HUB
+	tristate "HID Sensors framework support"
+	depends on USB_HID
+	select MFD_CORE
+	default n
+	-- help---
+	  Support for HID Sensor framework. This creates a MFD instance
+	  for a sensor hub and identifies all the sensors connected to it.
+	  Each sensor is registered as a MFD cell, so that sensor specific
+	  processing can be done in a separate driver. Each sensor
+	  drivers can use the service provided by this driver to register
+	  for events and handle data streams. Each sensor driver can format
+	  data and present to user mode using input or IIO interface.
+
 endmenu
 
 endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index f975485..cef68ca 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -69,7 +69,28 @@
 obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)	+= hid-picolcd.o
+hid-picolcd-y			+= hid-picolcd_core.o
+ifdef CONFIG_HID_PICOLCD_FB
+hid-picolcd-y			+= hid-picolcd_fb.o
+endif
+ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+hid-picolcd-y			+= hid-picolcd_backlight.o
+endif
+ifdef CONFIG_HID_PICOLCD_LCD
+hid-picolcd-y			+= hid-picolcd_lcd.o
+endif
+ifdef CONFIG_HID_PICOLCD_LEDS
+hid-picolcd-y			+= hid-picolcd_leds.o
+endif
+ifdef CONFIG_HID_PICOLCD_CIR
+hid-picolcd-y			+= hid-picolcd_cir.o
+endif
+ifdef CONFIG_DEBUG_FS
+hid-picolcd-y			+= hid-picolcd_debugfs.o
+endif
+
 obj-$(CONFIG_HID_PRIMAX)	+= hid-primax.o
+obj-$(CONFIG_HID_PS3REMOTE)	+= hid-ps3remote.o
 obj-$(CONFIG_HID_ROCCAT)	+= hid-roccat.o hid-roccat-common.o \
 	hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
 	hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
@@ -91,6 +112,7 @@
 obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
+obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 902d1df..0a23988 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 585344b..06ebdbb 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
  */
 
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
index ba64b04..7968187 100644
--- a/drivers/hid/hid-aureal.c
+++ b/drivers/hid/hid-aureal.c
@@ -9,7 +9,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 #include <linux/device.h>
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index a1a765a..a1a5a12 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index 888ece6..af034d3 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8bcd168..bd3971b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -126,7 +126,7 @@
 
 	if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
 		hid_err(parser->device, "collection stack overflow\n");
-		return -1;
+		return -EINVAL;
 	}
 
 	if (parser->device->maxcollection == parser->device->collection_size) {
@@ -134,7 +134,7 @@
 				parser->device->collection_size * 2, GFP_KERNEL);
 		if (collection == NULL) {
 			hid_err(parser->device, "failed to reallocate collection array\n");
-			return -1;
+			return -ENOMEM;
 		}
 		memcpy(collection, parser->device->collection,
 			sizeof(struct hid_collection) *
@@ -170,7 +170,7 @@
 {
 	if (!parser->collection_stack_ptr) {
 		hid_err(parser->device, "collection stack underflow\n");
-		return -1;
+		return -EINVAL;
 	}
 	parser->collection_stack_ptr--;
 	return 0;
@@ -374,7 +374,7 @@
 
 	case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
 		parser->global.report_size = item_udata(item);
-		if (parser->global.report_size > 96) {
+		if (parser->global.report_size > 128) {
 			hid_err(parser->device, "invalid report_size %d\n",
 					parser->global.report_size);
 			return -1;
@@ -757,6 +757,7 @@
 	struct hid_item item;
 	unsigned int size;
 	__u8 *start;
+	__u8 *buf;
 	__u8 *end;
 	int ret;
 	static int (*dispatch_type[])(struct hid_parser *parser,
@@ -775,12 +776,21 @@
 		return -ENODEV;
 	size = device->dev_rsize;
 
-	if (device->driver->report_fixup)
-		start = device->driver->report_fixup(device, start, &size);
-
-	device->rdesc = kmemdup(start, size, GFP_KERNEL);
-	if (device->rdesc == NULL)
+	buf = kmemdup(start, size, GFP_KERNEL);
+	if (buf == NULL)
 		return -ENOMEM;
+
+	if (device->driver->report_fixup)
+		start = device->driver->report_fixup(device, buf, &size);
+	else
+		start = buf;
+
+	start = kmemdup(start, size, GFP_KERNEL);
+	kfree(buf);
+	if (start == NULL)
+		return -ENOMEM;
+
+	device->rdesc = start;
 	device->rsize = size;
 
 	parser = vzalloc(sizeof(struct hid_parser));
@@ -1448,7 +1458,14 @@
 }
 EXPORT_SYMBOL_GPL(hid_disconnect);
 
-/* a list of devices for which there is a specialized driver on HID bus */
+/*
+ * A list of devices for which there is a specialized driver on HID bus.
+ *
+ * Please note that for multitouch devices (driven by hid-multitouch driver),
+ * there is a proper autodetection and autoloading in place (based on presence
+ * of HID_DG_CONTACTID), so those devices don't need to be added to this list,
+ * as we are doing the right thing in hid_scan_usage().
+ */
 static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
@@ -1551,6 +1568,10 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1566,6 +1587,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
@@ -1627,6 +1649,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
+#if IS_ENABLED(CONFIG_HID_ROCCAT)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
@@ -1635,15 +1658,18 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
+#endif
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
@@ -1663,6 +1689,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 9e43aac..3e159a5 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 01dd9a7..933fff0 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -911,15 +911,21 @@
 
 }
 
-
 static int hid_debug_rdesc_show(struct seq_file *f, void *p)
 {
 	struct hid_device *hdev = f->private;
+	const __u8 *rdesc = hdev->rdesc;
+	unsigned rsize = hdev->rsize;
 	int i;
 
+	if (!rdesc) {
+		rdesc = hdev->dev_rdesc;
+		rsize = hdev->dev_rsize;
+	}
+
 	/* dump HID report descriptor */
-	for (i = 0; i < hdev->rsize; i++)
-		seq_printf(f, "%02x ", hdev->rdesc[i]);
+	for (i = 0; i < rsize; i++)
+		seq_printf(f, "%02x ", rdesc[i]);
 	seq_printf(f, "\n\n");
 
 	/* dump parsed data and input mappings */
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
index ca1163e..6540af2 100644
--- a/drivers/hid/hid-ezkey.c
+++ b/drivers/hid/hid-ezkey.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index e88b951..4442c30 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -4,7 +4,6 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2006-2008 Jiri Kosina
  */
diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c
index 4e75421..ff295e6 100644
--- a/drivers/hid/hid-holtekff.c
+++ b/drivers/hid/hid-holtekff.c
@@ -100,8 +100,7 @@
 		holtekff->field->value[i] = data[i];
 	}
 
-	dbg_hid("sending %02x %02x %02x %02x %02x %02x %02x\n", data[0],
-		data[1], data[2], data[3], data[4], data[5], data[6]);
+	dbg_hid("sending %*ph\n", 7, data);
 
 	usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT);
 }
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 1dcb76f..269b509 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  */
 
 /*
@@ -269,7 +268,11 @@
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA	0x72fa
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302	0x7302
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349	0x7349
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7	0x73f7
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001	0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224      0x7224
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0      0x72d0
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4      0x72c4
 
 #define USB_VENDOR_ID_ELECOM		0x056e
 #define USB_DEVICE_ID_ELECOM_BM084	0x0061
@@ -283,6 +286,9 @@
 #define USB_VENDOR_ID_EMS		0x2006
 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
 
+#define USB_VENDOR_ID_FLATFROG		0x25b5
+#define USB_DEVICE_ID_MULTITOUCH_3200	0x0002
+
 #define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
@@ -296,6 +302,9 @@
 #define USB_VENDOR_ID_EZKEY		0x0518
 #define USB_DEVICE_ID_BTC_8193		0x0002
 
+#define USB_VENDOR_ID_FREESCALE		0x15A2
+#define USB_DEVICE_ID_FREESCALE_MX28	0x004F
+
 #define USB_VENDOR_ID_FRUCTEL	0x25B6
 #define USB_DEVICE_ID_GAMETEL_MT_MODE	0x0002
 
@@ -305,6 +314,7 @@
 
 #define USB_VENDOR_ID_GENERAL_TOUCH	0x0dfc
 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100
 
 #define USB_VENDOR_ID_GLAB		0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30	0x0038
@@ -419,6 +429,11 @@
 #define USB_VENDOR_ID_IMATION		0x0718
 #define USB_DEVICE_ID_DISC_STAKKA	0xd000
 
+#define USB_VENDOR_ID_INTEL_8086	0x8086
+#define USB_VENDOR_ID_INTEL_8087	0x8087
+#define USB_DEVICE_ID_SENSOR_HUB_1020	0x1020
+#define USB_DEVICE_ID_SENSOR_HUB_09FA	0x09FA
+
 #define USB_VENDOR_ID_IRTOUCHSYSTEMS	0x6615
 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB	0x0070
 
@@ -496,6 +511,7 @@
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD	0xc20a
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD	0xc211
 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
@@ -652,7 +668,6 @@
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH		0x3000
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001		0x3001
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008		0x3008
-#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN	0x3001
 
 #define USB_VENDOR_ID_ROCCAT		0x1e7d
 #define USB_DEVICE_ID_ROCCAT_ARVO	0x30d4
@@ -683,6 +698,7 @@
 
 #define USB_VENDOR_ID_SONY			0x054c
 #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE	0x024b
+#define USB_DEVICE_ID_SONY_PS3_BDREMOTE		0x0306
 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER	0x042f
 
@@ -695,6 +711,7 @@
 
 #define USB_VENDOR_ID_STANTUM_STM		0x0483
 #define USB_DEVICE_ID_MTP_STM		0x3261
+#define USB_DEVICE_ID_SENSOR_HUB_7014	0x7014
 
 #define USB_VENDOR_ID_STANTUM_SITRONIX		0x1403
 #define USB_DEVICE_ID_MTP_SITRONIX		0x5001
@@ -758,6 +775,7 @@
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U	0x0005
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062	0x0064
 #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850	0x0522
+#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60	0x0781
 
 #define USB_VENDOR_ID_UNITEC	0x227d
 #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709	0x0709
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 811bfad..d917c0d 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1154,6 +1154,7 @@
 
 int hidinput_connect(struct hid_device *hid, unsigned int force)
 {
+	struct hid_driver *drv = hid->driver;
 	struct hid_report *report;
 	struct hid_input *hidinput = NULL;
 	struct input_dev *input_dev;
@@ -1228,6 +1229,8 @@
 				 * UGCI) cram a lot of unrelated inputs into the
 				 * same interface. */
 				hidinput->report = report;
+				if (drv->input_configured)
+					drv->input_configured(hid, hidinput);
 				if (input_register_device(hidinput->input))
 					goto out_cleanup;
 				hidinput = NULL;
@@ -1235,8 +1238,12 @@
 		}
 	}
 
-	if (hidinput && input_register_device(hidinput->input))
-		goto out_cleanup;
+	if (hidinput) {
+		if (drv->input_configured)
+			drv->input_configured(hid, hidinput);
+		if (input_register_device(hidinput->input))
+			goto out_cleanup;
+	}
 
 	return 0;
 
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c
index c4fe9bd0..22bc14a 100644
--- a/drivers/hid/hid-lcpower.c
+++ b/drivers/hid/hid-lcpower.c
@@ -24,7 +24,7 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 		return 0;
 
 	switch (usage->hid & HID_USAGE) {
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 77d2df0..cea016e 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -56,9 +56,8 @@
 static int tpkbd_features_set(struct hid_device *hdev)
 {
 	struct hid_report *report;
-	struct tpkbd_data_pointer *data_pointer;
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
 	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
 
 	report->field[0]->value[0]  = data_pointer->press_to_select   ? 0x01 : 0x02;
@@ -77,14 +76,8 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
-
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
 }
@@ -94,16 +87,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value))
 		return -EINVAL;
 	if (value < 0 || value > 1)
@@ -119,14 +106,8 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
-
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
 }
@@ -136,16 +117,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value))
 		return -EINVAL;
 	if (value < 0 || value > 1)
@@ -161,14 +136,8 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
-
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
 }
@@ -178,16 +147,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value))
 		return -EINVAL;
 	if (value < 0 || value > 1)
@@ -203,14 +166,8 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
-
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
 }
@@ -220,16 +177,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value))
 		return -EINVAL;
 	if (value < 0 || value > 1)
@@ -245,14 +196,8 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
-
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n",
 		data_pointer->sensitivity);
@@ -263,16 +208,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
 		return -EINVAL;
 
@@ -286,14 +225,10 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	data_pointer = hid_get_drvdata(hdev);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n",
 		data_pointer->press_speed);
@@ -304,16 +239,10 @@
 		const char *buf,
 		size_t count)
 {
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int value;
 
-	hdev = container_of(dev, struct hid_device, dev);
-	if (hdev == NULL)
-		return -ENODEV;
-
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
 		return -EINVAL;
 
@@ -370,15 +299,11 @@
 static enum led_brightness tpkbd_led_brightness_get(
 			struct led_classdev *led_cdev)
 {
-	struct device *dev;
-	struct hid_device *hdev;
-	struct tpkbd_data_pointer *data_pointer;
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	int led_nr = 0;
 
-	dev = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (led_cdev == &data_pointer->led_micmute)
 		led_nr = 1;
 
@@ -390,16 +315,12 @@
 static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
 			enum led_brightness value)
 {
-	struct device *dev;
-	struct hid_device *hdev;
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 	struct hid_report *report;
-	struct tpkbd_data_pointer *data_pointer;
 	int led_nr = 0;
 
-	dev = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	if (led_cdev == &data_pointer->led_micmute)
 		led_nr = 1;
 
@@ -508,17 +429,17 @@
 
 static void tpkbd_remove_tp(struct hid_device *hdev)
 {
-	struct tpkbd_data_pointer *data_pointer;
+	struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
 
 	sysfs_remove_group(&hdev->dev.kobj,
 			&tpkbd_attr_group_pointer);
 
-	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
-
 	led_classdev_unregister(&data_pointer->led_micmute);
 	led_classdev_unregister(&data_pointer->led_mute);
 
 	hid_set_drvdata(hdev, NULL);
+	kfree(data_pointer->led_micmute.name);
+	kfree(data_pointer->led_mute.name);
 	kfree(data_pointer);
 }
 
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index fc37ed6..a2f8e88 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2010 Hendrik Iben
  */
@@ -109,7 +108,7 @@
 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 
 	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
@@ -278,7 +277,7 @@
 		  0,  0,  0,  0,  0,183,184,185,186,187,
 		188,189,190,191,192,193,194,  0,  0,  0
 	};
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 	unsigned int hid = usage->hid;
 
 	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
@@ -319,7 +318,7 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 
 	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 			(field->flags & HID_MAIN_ITEM_RELATIVE))
@@ -335,13 +334,16 @@
 static int lg_event(struct hid_device *hdev, struct hid_field *field,
 		struct hid_usage *usage, __s32 value)
 {
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 
 	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 		input_event(field->hidinput->input, usage->type, usage->code,
 				-value);
 		return 1;
 	}
+	if (drv_data->quirks & LG_FF4) {
+		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
+	}
 
 	return 0;
 }
@@ -358,7 +360,7 @@
 		return -ENOMEM;
 	}
 	drv_data->quirks = id->driver_data;
-	
+
 	hid_set_drvdata(hdev, (void *)drv_data);
 
 	if (drv_data->quirks & LG_NOGET)
@@ -380,7 +382,7 @@
 	}
 
 	/* Setup wireless link with Logitech Wii wheel */
-	if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
+	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
 		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 		ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
@@ -416,7 +418,7 @@
 
 static void lg_remove(struct hid_device *hdev)
 {
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 	if (drv_data->quirks & LG_FF4)
 		lg4ff_deinit(hdev);
 
@@ -476,7 +478,7 @@
 		.driver_data = LG_NOGET | LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
 		.driver_data = LG_FF4 },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
 		.driver_data = LG_FF },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
 		.driver_data = LG_FF2 },
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index d64cf8d..142ce3f 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -25,9 +25,13 @@
 #endif
 
 #ifdef CONFIG_LOGIWHEELS_FF
+int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
+			     struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data);
 int lg4ff_init(struct hid_device *hdev);
 int lg4ff_deinit(struct hid_device *hdev);
 #else
+static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
+					   struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; }
 static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
 static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
 #endif
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index f3390ee..d7947c7 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -43,6 +43,11 @@
 #define G27_REV_MAJ 0x12
 #define G27_REV_MIN 0x38
 
+#define DFP_X_MIN 0
+#define DFP_X_MAX 16383
+#define DFP_PEDAL_MIN 0
+#define DFP_PEDAL_MAX 255
+
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
@@ -53,6 +58,7 @@
 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
 
 struct lg4ff_device_entry {
+	__u32 product_id;
 	__u16 range;
 	__u16 min_range;
 	__u16 max_range;
@@ -129,26 +135,77 @@
 	{G27_REV_MAJ,  G27_REV_MIN,  &native_g27},	/* G27 */
 };
 
+/* Recalculates X axis value accordingly to currently selected range */
+static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range)
+{
+	__u16 max_range;
+	__s32 new_value;
+
+	if (range == 900)
+		return value;
+	else if (range == 200)
+		return value;
+	else if (range < 200)
+		max_range = 200;
+	else
+		max_range = 900;
+
+	new_value = 8192 + mult_frac(value - 8192, max_range, range);
+	if (new_value < 0)
+		return 0;
+	else if (new_value > 16383)
+		return 16383;
+	else
+		return new_value;
+}
+
+int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
+			     struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data)
+{
+	struct lg4ff_device_entry *entry = drv_data->device_props;
+	__s32 new_value = 0;
+
+	if (!entry) {
+		hid_err(hid, "Device properties not found");
+		return 0;
+	}
+
+	switch (entry->product_id) {
+	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
+		switch (usage->code) {
+		case ABS_X:
+			new_value = lg4ff_adjust_dfp_x_axis(value, entry->range);
+			input_event(field->hidinput->input, usage->type, usage->code, new_value);
+			return 1;
+		default:
+			return 0;
+		}
+	default:
+		return 0;
+	}
+}
+
 static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
 	int x;
 
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0)
 
 	switch (effect->type) {
 	case FF_CONSTANT:
 		x = effect->u.ramp.start_level + 0x80;	/* 0x80 is no force */
 		CLAMP(x);
-		report->field[0]->value[0] = 0x11;	/* Slot 1 */
-		report->field[0]->value[1] = 0x08;
-		report->field[0]->value[2] = x;
-		report->field[0]->value[3] = 0x80;
-		report->field[0]->value[4] = 0x00;
-		report->field[0]->value[5] = 0x00;
-		report->field[0]->value[6] = 0x00;
+		value[0] = 0x11;	/* Slot 1 */
+		value[1] = 0x08;
+		value[2] = x;
+		value[3] = 0x80;
+		value[4] = 0x00;
+		value[5] = 0x00;
+		value[6] = 0x00;
 
 		usbhid_submit_report(hid, report, USB_DIR_OUT);
 		break;
@@ -163,14 +220,15 @@
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
 
-	report->field[0]->value[0] = 0xfe;
-	report->field[0]->value[1] = 0x0d;
-	report->field[0]->value[2] = magnitude >> 13;
-	report->field[0]->value[3] = magnitude >> 13;
-	report->field[0]->value[4] = magnitude >> 8;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0xfe;
+	value[1] = 0x0d;
+	value[2] = magnitude >> 13;
+	value[3] = magnitude >> 13;
+	value[4] = magnitude >> 8;
+	value[5] = 0x00;
+	value[6] = 0x00;
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
@@ -181,16 +239,16 @@
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
 	magnitude = magnitude * 90 / 65535;
-	
 
-	report->field[0]->value[0] = 0xfe;
-	report->field[0]->value[1] = 0x03;
-	report->field[0]->value[2] = magnitude >> 14;
-	report->field[0]->value[3] = magnitude >> 14;
-	report->field[0]->value[4] = magnitude;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0xfe;
+	value[1] = 0x03;
+	value[2] = magnitude >> 14;
+	value[3] = magnitude >> 14;
+	value[4] = magnitude;
+	value[5] = 0x00;
+	value[6] = 0x00;
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
@@ -200,15 +258,17 @@
 {
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
+
 	dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
 
-	report->field[0]->value[0] = 0xf8;
-	report->field[0]->value[1] = 0x81;
-	report->field[0]->value[2] = range & 0x00ff;
-	report->field[0]->value[3] = (range & 0xff00) >> 8;
-	report->field[0]->value[4] = 0x00;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0xf8;
+	value[1] = 0x81;
+	value[2] = range & 0x00ff;
+	value[3] = (range & 0xff00) >> 8;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
@@ -219,16 +279,18 @@
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
 	int start_left, start_right, full_range;
+	__s32 *value = report->field[0]->value;
+
 	dbg_hid("Driving Force Pro: setting range to %u\n", range);
 
 	/* Prepare "coarse" limit command */
-	report->field[0]->value[0] = 0xf8;
-	report->field[0]->value[1] = 0x00; 	/* Set later */
-	report->field[0]->value[2] = 0x00;
-	report->field[0]->value[3] = 0x00;
-	report->field[0]->value[4] = 0x00;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0xf8;
+	value[1] = 0x00;	/* Set later */
+	value[2] = 0x00;
+	value[3] = 0x00;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
 
 	if (range > 200) {
 		report->field[0]->value[1] = 0x03;
@@ -240,13 +302,13 @@
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 
 	/* Prepare "fine" limit command */
-	report->field[0]->value[0] = 0x81;
-	report->field[0]->value[1] = 0x0b;
-	report->field[0]->value[2] = 0x00;
-	report->field[0]->value[3] = 0x00;
-	report->field[0]->value[4] = 0x00;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0x81;
+	value[1] = 0x0b;
+	value[2] = 0x00;
+	value[3] = 0x00;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
 
 	if (range == 200 || range == 900) {	/* Do not apply any fine limit */
 		usbhid_submit_report(hid, report, USB_DIR_OUT);
@@ -257,11 +319,11 @@
 	start_left = (((full_range - range + 1) * 2047) / full_range);
 	start_right = 0xfff - start_left;
 
-	report->field[0]->value[2] = start_left >> 4;
-	report->field[0]->value[3] = start_right >> 4;
-	report->field[0]->value[4] = 0xff;
-	report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
-	report->field[0]->value[6] = 0xff;
+	value[2] = start_left >> 4;
+	value[3] = start_right >> 4;
+	value[4] = 0xff;
+	value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
+	value[6] = 0xff;
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
@@ -344,14 +406,15 @@
 {
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
 
-	report->field[0]->value[0] = 0xf8;
-	report->field[0]->value[1] = 0x12;
-	report->field[0]->value[2] = leds;
-	report->field[0]->value[3] = 0x00;
-	report->field[0]->value[4] = 0x00;
-	report->field[0]->value[5] = 0x00;
-	report->field[0]->value[6] = 0x00;
+	value[0] = 0xf8;
+	value[1] = 0x12;
+	value[2] = leds;
+	value[3] = 0x00;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
 
@@ -360,7 +423,7 @@
 {
 	struct device *dev = led_cdev->dev->parent;
 	struct hid_device *hid = container_of(dev, struct hid_device, dev);
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hid);
 	struct lg4ff_device_entry *entry;
 	int i, state = 0;
 
@@ -395,7 +458,7 @@
 {
 	struct device *dev = led_cdev->dev->parent;
 	struct hid_device *hid = container_of(dev, struct hid_device, dev);
-	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+	struct lg_drv_data *drv_data = hid_get_drvdata(hid);
 	struct lg4ff_device_entry *entry;
 	int i, value = 0;
 
@@ -501,7 +564,7 @@
 	/* Check if autocentering is available and
 	 * set the centering force to zero by default */
 	if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
-		if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN)	/* Formula Force EX expects different autocentering command */
+		if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN)	/* Formula Force EX expects different autocentering command */
 			dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
 		else
 			dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
@@ -524,6 +587,7 @@
 	}
 	drv_data->device_props = entry;
 
+	entry->product_id = lg4ff_devices[i].product_id;
 	entry->min_range = lg4ff_devices[i].min_range;
 	entry->max_range = lg4ff_devices[i].max_range;
 	entry->set_range = lg4ff_devices[i].set_range;
@@ -534,6 +598,18 @@
 		return error;
 	dbg_hid("sysfs interface created\n");
 
+	/* Set default axes parameters */
+	switch (lg4ff_devices[i].product_id) {
+	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
+		dbg_hid("Setting axes parameters for Driving Force Pro\n");
+		input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0);
+		input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
+		input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
+		break;
+	default:
+		break;
+	}
+
 	/* Set the maximum range to start with */
 	entry->range = entry->max_range;
 	if (entry->set_range != NULL)
@@ -594,6 +670,8 @@
 	return 0;
 }
 
+
+
 int lg4ff_deinit(struct hid_device *hid)
 {
 	struct lg4ff_device_entry *entry;
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 4d524b5..9500f2f 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -193,6 +193,7 @@
 static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
 					size_t count,
 					unsigned char report_type);
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
 
 static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
 						struct dj_report *dj_report)
@@ -233,6 +234,7 @@
 	if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
 	    SPFUNCTION_DEVICE_LIST_EMPTY) {
 		dbg_hid("%s: device list is empty\n", __func__);
+		djrcv_dev->querying_devices = false;
 		return;
 	}
 
@@ -243,6 +245,12 @@
 		return;
 	}
 
+	if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
+		/* The device is already known. No need to reallocate it. */
+		dbg_hid("%s: device is already known\n", __func__);
+		return;
+	}
+
 	dj_hiddev = hid_allocate_device();
 	if (IS_ERR(dj_hiddev)) {
 		dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@ -306,6 +314,7 @@
 	struct dj_report dj_report;
 	unsigned long flags;
 	int count;
+	int retval;
 
 	dbg_hid("%s\n", __func__);
 
@@ -338,6 +347,25 @@
 		logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
 		break;
 	default:
+	/* A normal report (i. e. not belonging to a pair/unpair notification)
+	 * arriving here, means that the report arrived but we did not have a
+	 * paired dj_device associated to the report's device_index, this
+	 * means that the original "device paired" notification corresponding
+	 * to this dj_device never arrived to this driver. The reason is that
+	 * hid-core discards all packets coming from a device while probe() is
+	 * executing. */
+	if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
+		/* ok, we don't know the device, just re-ask the
+		 * receiver for the list of connected devices. */
+		retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+		if (!retval) {
+			/* everything went fine, so just leave */
+			break;
+		}
+		dev_err(&djrcv_dev->hdev->dev,
+			"%s:logi_dj_recv_query_paired_devices "
+			"error:%d\n", __func__, retval);
+		}
 		dbg_hid("%s: unexpected report type\n", __func__);
 	}
 }
@@ -368,6 +396,12 @@
 	if (!djdev) {
 		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
 			" is NULL, index %d\n", dj_report->device_index);
+		kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+		if (schedule_work(&djrcv_dev->work) == 0) {
+			dbg_hid("%s: did not schedule the work item, was already "
+			"queued\n", __func__);
+		}
 		return;
 	}
 
@@ -398,6 +432,12 @@
 	if (dj_device == NULL) {
 		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
 			" is NULL, index %d\n", dj_report->device_index);
+		kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+		if (schedule_work(&djrcv_dev->work) == 0) {
+			dbg_hid("%s: did not schedule the work item, was already "
+			"queued\n", __func__);
+		}
 		return;
 	}
 
@@ -439,6 +479,10 @@
 	struct dj_report *dj_report;
 	int retval;
 
+	/* no need to protect djrcv_dev->querying_devices */
+	if (djrcv_dev->querying_devices)
+		return 0;
+
 	dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
 	if (!dj_report)
 		return -ENOMEM;
@@ -450,6 +494,7 @@
 	return retval;
 }
 
+
 static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
 					  unsigned timeout)
 {
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
index fd28a5e..4a40003 100644
--- a/drivers/hid/hid-logitech-dj.h
+++ b/drivers/hid/hid-logitech-dj.h
@@ -101,6 +101,7 @@
 	struct work_struct work;
 	struct kfifo notif_fifo;
 	spinlock_t lock;
+	bool querying_devices;
 };
 
 struct dj_device {
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 7364726..25ddf3e 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -392,7 +392,7 @@
 
 	__set_bit(EV_ABS, input->evbit);
 
-	error = input_mt_init_slots(input, 16);
+	error = input_mt_init_slots(input, 16, 0);
 	if (error)
 		return error;
 	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index e5c699b..3acdcfc 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index dedf757..cd3643e 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 59c8b5c..3eb02b9 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -51,12 +51,12 @@
 #define MT_QUIRK_VALID_IS_INRANGE	(1 << 5)
 #define MT_QUIRK_VALID_IS_CONFIDENCE	(1 << 6)
 #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	(1 << 8)
+#define MT_QUIRK_NO_AREA		(1 << 9)
 
 struct mt_slot {
 	__s32 x, y, p, w, h;
 	__s32 contactid;	/* the device ContactID assigned to this slot */
 	bool touch_state;	/* is the touch valid? */
-	bool seen_in_this_frame;/* has this slot been updated */
 };
 
 struct mt_class {
@@ -92,8 +92,9 @@
 	__u8 touches_by_report;	/* how many touches are present in one report:
 				* 1 means we should use a serial protocol
 				* > 1 means hybrid (multitouch) protocol */
+	bool serial_maybe;	/* need to check for serial protocol */
 	bool curvalid;		/* is the current contact valid? */
-	struct mt_slot *slots;
+	unsigned mt_flags;	/* flags to pass to input-mt */
 };
 
 /* classes of device behavior */
@@ -115,6 +116,9 @@
 #define MT_CLS_EGALAX_SERIAL			0x0104
 #define MT_CLS_TOPSEED				0x0105
 #define MT_CLS_PANASONIC			0x0106
+#define MT_CLS_FLATFROG				0x0107
+#define MT_CLS_GENERALTOUCH_TWOFINGERS		0x0108
+#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS	0x0109
 
 #define MT_DEFAULT_MAXCONTACT	10
 
@@ -134,25 +138,6 @@
 		return -1;
 }
 
-static int find_slot_from_contactid(struct mt_device *td)
-{
-	int i;
-	for (i = 0; i < td->maxcontacts; ++i) {
-		if (td->slots[i].contactid == td->curdata.contactid &&
-			td->slots[i].touch_state)
-			return i;
-	}
-	for (i = 0; i < td->maxcontacts; ++i) {
-		if (!td->slots[i].seen_in_this_frame &&
-			!td->slots[i].touch_state)
-			return i;
-	}
-	/* should not occurs. If this happens that means
-	 * that the device sent more touches that it says
-	 * in the report descriptor. It is ignored then. */
-	return -1;
-}
-
 static struct mt_class mt_classes[] = {
 	{ .name = MT_CLS_DEFAULT,
 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
@@ -190,7 +175,9 @@
 			MT_QUIRK_SLOT_IS_CONTACTID,
 		.sn_move = 2048,
 		.sn_width = 128,
-		.sn_height = 128 },
+		.sn_height = 128,
+		.maxcontacts = 60,
+	},
 	{ .name = MT_CLS_CYPRESS,
 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
 			MT_QUIRK_CYPRESS,
@@ -215,7 +202,24 @@
 	{ .name = MT_CLS_PANASONIC,
 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
 		.maxcontacts = 4 },
+	{ .name	= MT_CLS_GENERALTOUCH_TWOFINGERS,
+		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |
+			MT_QUIRK_VALID_IS_INRANGE |
+			MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+		.maxcontacts = 2
+	},
+	{ .name	= MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
+		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |
+			MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+		.maxcontacts = 10
+	},
 
+	{ .name = MT_CLS_FLATFROG,
+		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+			MT_QUIRK_NO_AREA,
+		.sn_move = 2048,
+		.maxcontacts = 40,
+	},
 	{ }
 };
 
@@ -319,24 +323,16 @@
 	* We need to ignore fields that belong to other collections
 	* such as Mouse that might have the same GenericDesktop usages. */
 	if (field->application == HID_DG_TOUCHSCREEN)
-		set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+		td->mt_flags |= INPUT_MT_DIRECT;
 	else if (field->application != HID_DG_TOUCHPAD)
 		return 0;
 
-	/* In case of an indirect device (touchpad), we need to add
-	 * specific BTN_TOOL_* to be handled by the synaptics xorg
-	 * driver.
-	 * We also consider that touchscreens providing buttons are touchpads.
+	/*
+	 * Model touchscreens providing buttons as touchpads.
 	 */
 	if (field->application == HID_DG_TOUCHPAD ||
-	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON ||
-	    cls->is_indirect) {
-		set_bit(INPUT_PROP_POINTER, hi->input->propbit);
-		set_bit(BTN_TOOL_FINGER, hi->input->keybit);
-		set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit);
-		set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit);
-		set_bit(BTN_TOOL_QUADTAP, hi->input->keybit);
-	}
+	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
+		td->mt_flags |= INPUT_MT_POINTER;
 
 	/* eGalax devices provide a Digitizer.Stylus input which overrides
 	 * the correct Digitizers.Finger X/Y ranges.
@@ -353,8 +349,6 @@
 					EV_ABS, ABS_MT_POSITION_X);
 			set_abs(hi->input, ABS_MT_POSITION_X, field,
 				cls->sn_move);
-			/* touchscreen emulation */
-			set_abs(hi->input, ABS_X, field, cls->sn_move);
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
@@ -363,8 +357,6 @@
 					EV_ABS, ABS_MT_POSITION_Y);
 			set_abs(hi->input, ABS_MT_POSITION_Y, field,
 				cls->sn_move);
-			/* touchscreen emulation */
-			set_abs(hi->input, ABS_Y, field, cls->sn_move);
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
@@ -388,9 +380,6 @@
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_CONTACTID:
-			if (!td->maxcontacts)
-				td->maxcontacts = MT_DEFAULT_MAXCONTACT;
-			input_mt_init_slots(hi->input, td->maxcontacts);
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			td->touches_by_report++;
@@ -398,18 +387,21 @@
 		case HID_DG_WIDTH:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MAJOR);
-			set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
-				cls->sn_width);
+			if (!(cls->quirks & MT_QUIRK_NO_AREA))
+				set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
+					cls->sn_width);
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_HEIGHT:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MINOR);
-			set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
-				cls->sn_height);
-			input_set_abs_params(hi->input,
+			if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
+				set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
+					cls->sn_height);
+				input_set_abs_params(hi->input,
 					ABS_MT_ORIENTATION, 0, 1, 0, 0);
+			}
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
@@ -418,9 +410,6 @@
 					EV_ABS, ABS_MT_PRESSURE);
 			set_abs(hi->input, ABS_MT_PRESSURE, field,
 				cls->sn_pressure);
-			/* touchscreen emulation */
-			set_abs(hi->input, ABS_PRESSURE, field,
-				cls->sn_pressure);
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
@@ -464,7 +453,7 @@
 	return -1;
 }
 
-static int mt_compute_slot(struct mt_device *td)
+static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
 {
 	__s32 quirks = td->mtclass.quirks;
 
@@ -480,42 +469,23 @@
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
 		return td->curdata.contactid - 1;
 
-	return find_slot_from_contactid(td);
+	return input_mt_get_slot_by_key(input, td->curdata.contactid);
 }
 
 /*
  * this function is called when a whole contact has been processed,
  * so that it can assign it to a slot and store the data there
  */
-static void mt_complete_slot(struct mt_device *td)
+static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 {
-	td->curdata.seen_in_this_frame = true;
 	if (td->curvalid) {
-		int slotnum = mt_compute_slot(td);
+		int slotnum = mt_compute_slot(td, input);
+		struct mt_slot *s = &td->curdata;
 
-		if (slotnum >= 0 && slotnum < td->maxcontacts)
-			td->slots[slotnum] = td->curdata;
-	}
-	td->num_received++;
-}
+		if (slotnum < 0 || slotnum >= td->maxcontacts)
+			return;
 
-
-/*
- * this function is called when a whole packet has been received and processed,
- * so that it can decide what to send to the input layer.
- */
-static void mt_emit_event(struct mt_device *td, struct input_dev *input)
-{
-	int i;
-
-	for (i = 0; i < td->maxcontacts; ++i) {
-		struct mt_slot *s = &(td->slots[i]);
-		if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
-			!s->seen_in_this_frame) {
-			s->touch_state = false;
-		}
-
-		input_mt_slot(input, i);
+		input_mt_slot(input, slotnum);
 		input_mt_report_slot_state(input, MT_TOOL_FINGER,
 			s->touch_state);
 		if (s->touch_state) {
@@ -532,24 +502,29 @@
 			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
 			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
 		}
-		s->seen_in_this_frame = false;
-
 	}
 
-	input_mt_report_pointer_emulation(input, true);
+	td->num_received++;
+}
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
+{
+	input_mt_sync_frame(input);
 	input_sync(input);
 	td->num_received = 0;
 }
 
-
-
 static int mt_event(struct hid_device *hid, struct hid_field *field,
 				struct hid_usage *usage, __s32 value)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
 	__s32 quirks = td->mtclass.quirks;
 
-	if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
+	if (hid->claimed & HID_CLAIMED_INPUT) {
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
 			if (quirks & MT_QUIRK_ALWAYS_VALID)
@@ -602,11 +577,11 @@
 		}
 
 		if (usage->hid == td->last_slot_field)
-			mt_complete_slot(td);
+			mt_complete_slot(td, field->hidinput->input);
 
 		if (field->index == td->last_field_index
 			&& td->num_received >= td->num_expected)
-			mt_emit_event(td, field->hidinput->input);
+			mt_sync_frame(td, field->hidinput->input);
 
 	}
 
@@ -685,18 +660,45 @@
 	}
 }
 
+static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+
+{
+	struct mt_device *td = hid_get_drvdata(hdev);
+	struct mt_class *cls = &td->mtclass;
+	struct input_dev *input = hi->input;
+
+	/* Only initialize slots for MT input devices */
+	if (!test_bit(ABS_MT_POSITION_X, input->absbit))
+		return;
+
+	if (!td->maxcontacts)
+		td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+	mt_post_parse(td);
+	if (td->serial_maybe)
+		mt_post_parse_default_settings(td);
+
+	if (cls->is_indirect)
+		td->mt_flags |= INPUT_MT_POINTER;
+
+	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+		td->mt_flags |= INPUT_MT_DROP_UNUSED;
+
+	input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+
+	td->mt_flags = 0;
+}
+
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret, i;
 	struct mt_device *td;
 	struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
 
-	if (id) {
-		for (i = 0; mt_classes[i].name ; i++) {
-			if (id->driver_data == mt_classes[i].name) {
-				mtclass = &(mt_classes[i]);
-				break;
-			}
+	for (i = 0; mt_classes[i].name ; i++) {
+		if (id->driver_data == mt_classes[i].name) {
+			mtclass = &(mt_classes[i]);
+			break;
 		}
 	}
 
@@ -722,6 +724,9 @@
 		goto fail;
 	}
 
+	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+		td->serial_maybe = true;
+
 	ret = hid_parse(hdev);
 	if (ret != 0)
 		goto fail;
@@ -730,20 +735,6 @@
 	if (ret)
 		goto fail;
 
-	mt_post_parse(td);
-
-	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
-		mt_post_parse_default_settings(td);
-
-	td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
-				GFP_KERNEL);
-	if (!td->slots) {
-		dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
-		hid_hw_stop(hdev);
-		ret = -ENOMEM;
-		goto fail;
-	}
-
 	ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
 
 	mt_set_maxcontacts(hdev);
@@ -767,6 +758,32 @@
 	mt_set_input_mode(hdev);
 	return 0;
 }
+
+static int mt_resume(struct hid_device *hdev)
+{
+	struct usb_interface *intf;
+	struct usb_host_interface *interface;
+	struct usb_device *dev;
+
+	if (hdev->bus != BUS_USB)
+		return 0;
+
+	intf = to_usb_interface(hdev->dev.parent);
+	interface = intf->cur_altsetting;
+	dev = hid_to_usb_dev(hdev);
+
+	/* Some Elan legacy devices require SET_IDLE to be set on resume.
+	 * It should be safe to send it to other devices too.
+	 * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
+
+	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			HID_REQ_SET_IDLE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			0, interface->desc.bInterfaceNumber,
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+	return 0;
+}
 #endif
 
 static void mt_remove(struct hid_device *hdev)
@@ -774,7 +791,6 @@
 	struct mt_device *td = hid_get_drvdata(hdev);
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
-	kfree(td->slots);
 	kfree(td);
 	hid_set_drvdata(hdev, NULL);
 }
@@ -885,17 +901,37 @@
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) },
+	{ .driver_data = MT_CLS_EGALAX_SERIAL,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
 
 	/* Elo TouchSystems IntelliTouch Plus panel */
 	{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
 		MT_USB_DEVICE(USB_VENDOR_ID_ELO,
 			USB_DEVICE_ID_ELO_TS2515) },
 
+	/* Flatfrog Panels */
+	{ .driver_data = MT_CLS_FLATFROG,
+		MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
+			USB_DEVICE_ID_MULTITOUCH_3200) },
+
 	/* GeneralTouch panel */
-	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+	{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
 			USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
+		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
 
 	/* Gametel game controller */
 	{ .driver_data = MT_CLS_DEFAULT,
@@ -1087,11 +1123,13 @@
 	.remove = mt_remove,
 	.input_mapping = mt_input_mapping,
 	.input_mapped = mt_input_mapped,
+	.input_configured = mt_input_configured,
 	.feature_mapping = mt_feature_mapping,
 	.usage_table = mt_grabbed_usages,
 	.event = mt_event,
 #ifdef CONFIG_PM
 	.reset_resume = mt_reset_resume,
+	.resume = mt_resume,
 #endif
 };
 
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 9fae2eb..86a969f 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -882,10 +882,10 @@
 	nd->activate_slack = activate_slack;
 	nd->act_state = activate_slack;
 	nd->deactivate_slack = -deactivate_slack;
-	nd->sensor_logical_width = 0;
-	nd->sensor_logical_height = 0;
-	nd->sensor_physical_width = 0;
-	nd->sensor_physical_height = 0;
+	nd->sensor_logical_width = 1;
+	nd->sensor_logical_height = 1;
+	nd->sensor_physical_width = 1;
+	nd->sensor_physical_height = 1;
 
 	hid_set_drvdata(hdev, nd);
 
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index f1ea3ff..4c521de 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
deleted file mode 100644
index 27c8ebd..0000000
--- a/drivers/hid/hid-picolcd.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org>       *
- *                                                                         *
- *   Based on Logitech G13 driver (v0.4)                                   *
- *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
- *                                                                         *
- *   This program is free software: you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation, version 2 of the License.               *
- *                                                                         *
- *   This driver is distributed in the hope that it will be useful, but    *
- *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
- *   General Public License for more details.                              *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
- ***************************************************************************/
-
-#include <linux/hid.h>
-#include <linux/hid-debug.h>
-#include <linux/input.h>
-#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
-
-#include <linux/fb.h>
-#include <linux/vmalloc.h>
-#include <linux/backlight.h>
-#include <linux/lcd.h>
-
-#include <linux/leds.h>
-
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-
-#include <linux/completion.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#define PICOLCD_NAME "PicoLCD (graphic)"
-
-/* Report numbers */
-#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
-#define   ERR_SUCCESS            0x00
-#define   ERR_PARAMETER_MISSING  0x01
-#define   ERR_DATA_MISSING       0x02
-#define   ERR_BLOCK_READ_ONLY    0x03
-#define   ERR_BLOCK_NOT_ERASABLE 0x04
-#define   ERR_BLOCK_TOO_BIG      0x05
-#define   ERR_SECTION_OVERFLOW   0x06
-#define   ERR_INVALID_CMD_LEN    0x07
-#define   ERR_INVALID_DATA_LEN   0x08
-#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
-#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
-#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
-#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
-#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
-#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
-#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
-#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
-#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
-#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
-#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
-#define	REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
-#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
-#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
-#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
-#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
-#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
-#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
-#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
-#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
-#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
-#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
-#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
-#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Framebuffer
- *
- * The PicoLCD use a Topway LCD module of 256x64 pixel
- * This display area is tiled over 4 controllers with 8 tiles
- * each. Each tile has 8x64 pixel, each data byte representing
- * a 1-bit wide vertical line of the tile.
- *
- * The display can be updated at a tile granularity.
- *
- *       Chip 1           Chip 2           Chip 3           Chip 4
- * +----------------+----------------+----------------+----------------+
- * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
- * +----------------+----------------+----------------+----------------+
- * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
- * +----------------+----------------+----------------+----------------+
- *                                  ...
- * +----------------+----------------+----------------+----------------+
- * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
- * +----------------+----------------+----------------+----------------+
- */
-#define PICOLCDFB_NAME "picolcdfb"
-#define PICOLCDFB_WIDTH (256)
-#define PICOLCDFB_HEIGHT (64)
-#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
-
-#define PICOLCDFB_UPDATE_RATE_LIMIT   10
-#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
-
-/* Framebuffer visual structures */
-static const struct fb_fix_screeninfo picolcdfb_fix = {
-	.id          = PICOLCDFB_NAME,
-	.type        = FB_TYPE_PACKED_PIXELS,
-	.visual      = FB_VISUAL_MONO01,
-	.xpanstep    = 0,
-	.ypanstep    = 0,
-	.ywrapstep   = 0,
-	.line_length = PICOLCDFB_WIDTH / 8,
-	.accel       = FB_ACCEL_NONE,
-};
-
-static const struct fb_var_screeninfo picolcdfb_var = {
-	.xres           = PICOLCDFB_WIDTH,
-	.yres           = PICOLCDFB_HEIGHT,
-	.xres_virtual   = PICOLCDFB_WIDTH,
-	.yres_virtual   = PICOLCDFB_HEIGHT,
-	.width          = 103,
-	.height         = 26,
-	.bits_per_pixel = 1,
-	.grayscale      = 1,
-	.red            = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.green          = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.blue           = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.transp         = {
-		.offset = 0,
-		.length = 0,
-		.msb_right = 0,
-	},
-};
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-/* Input device
- *
- * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
- * and header for 4x4 key matrix. The built-in keys are part of the matrix.
- */
-static const unsigned short def_keymap[] = {
-	KEY_RESERVED,	/* none */
-	KEY_BACK,	/* col 4 + row 1 */
-	KEY_HOMEPAGE,	/* col 3 + row 1 */
-	KEY_RESERVED,	/* col 2 + row 1 */
-	KEY_RESERVED,	/* col 1 + row 1 */
-	KEY_SCROLLUP,	/* col 4 + row 2 */
-	KEY_OK,		/* col 3 + row 2 */
-	KEY_SCROLLDOWN,	/* col 2 + row 2 */
-	KEY_RESERVED,	/* col 1 + row 2 */
-	KEY_RESERVED,	/* col 4 + row 3 */
-	KEY_RESERVED,	/* col 3 + row 3 */
-	KEY_RESERVED,	/* col 2 + row 3 */
-	KEY_RESERVED,	/* col 1 + row 3 */
-	KEY_RESERVED,	/* col 4 + row 4 */
-	KEY_RESERVED,	/* col 3 + row 4 */
-	KEY_RESERVED,	/* col 2 + row 4 */
-	KEY_RESERVED,	/* col 1 + row 4 */
-};
-#define PICOLCD_KEYS ARRAY_SIZE(def_keymap)
-
-/* Description of in-progress IO operation, used for operations
- * that trigger response from device */
-struct picolcd_pending {
-	struct hid_report *out_report;
-	struct hid_report *in_report;
-	struct completion ready;
-	int raw_size;
-	u8 raw_data[64];
-};
-
-/* Per device data structure */
-struct picolcd_data {
-	struct hid_device *hdev;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *debug_reset;
-	struct dentry *debug_eeprom;
-	struct dentry *debug_flash;
-	struct mutex mutex_flash;
-	int addr_sz;
-#endif
-	u8 version[2];
-	unsigned short opmode_delay;
-	/* input stuff */
-	u8 pressed_keys[2];
-	struct input_dev *input_keys;
-	struct input_dev *input_cir;
-	unsigned short keycode[PICOLCD_KEYS];
-
-#ifdef CONFIG_HID_PICOLCD_FB
-	/* Framebuffer stuff */
-	u8 fb_update_rate;
-	u8 fb_bpp;
-	u8 fb_force;
-	u8 *fb_vbitmap;		/* local copy of what was sent to PicoLCD */
-	u8 *fb_bitmap;		/* framebuffer */
-	struct fb_info *fb_info;
-	struct fb_deferred_io fb_defio;
-#endif /* CONFIG_HID_PICOLCD_FB */
-#ifdef CONFIG_HID_PICOLCD_LCD
-	struct lcd_device *lcd;
-	u8 lcd_contrast;
-#endif /* CONFIG_HID_PICOLCD_LCD */
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-	struct backlight_device *backlight;
-	u8 lcd_brightness;
-	u8 lcd_power;
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-#ifdef CONFIG_HID_PICOLCD_LEDS
-	/* LED stuff */
-	u8 led_state;
-	struct led_classdev *led[8];
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-	/* Housekeeping stuff */
-	spinlock_t lock;
-	struct mutex mutex;
-	struct picolcd_pending *pending;
-	int status;
-#define PICOLCD_BOOTLOADER 1
-#define PICOLCD_FAILED 2
-#define PICOLCD_READY_FB 4
-};
-
-
-/* Find a given report */
-#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
-#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
-
-static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
-{
-	struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
-	struct hid_report *report = NULL;
-
-	list_for_each_entry(report, feature_report_list, list) {
-		if (report->id == id)
-			return report;
-	}
-	hid_warn(hdev, "No report with id 0x%x found\n", id);
-	return NULL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void picolcd_debug_out_report(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report);
-#define usbhid_submit_report(a, b, c) \
-	do { \
-		picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
-		usbhid_submit_report(a, b, c); \
-	} while (0)
-#endif
-
-/* Submit a report and wait for a reply from device - if device fades away
- * or does not respond in time, return NULL */
-static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
-		int report_id, const u8 *raw_data, int size)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct picolcd_pending *work;
-	struct hid_report *report = picolcd_out_report(report_id, hdev);
-	unsigned long flags;
-	int i, j, k;
-
-	if (!report || !data)
-		return NULL;
-	if (data->status & PICOLCD_FAILED)
-		return NULL;
-	work = kzalloc(sizeof(*work), GFP_KERNEL);
-	if (!work)
-		return NULL;
-
-	init_completion(&work->ready);
-	work->out_report = report;
-	work->in_report  = NULL;
-	work->raw_size   = 0;
-
-	mutex_lock(&data->mutex);
-	spin_lock_irqsave(&data->lock, flags);
-	for (i = k = 0; i < report->maxfield; i++)
-		for (j = 0; j < report->field[i]->report_count; j++) {
-			hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
-			k++;
-		}
-	data->pending = work;
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
-	spin_lock_irqsave(&data->lock, flags);
-	data->pending = NULL;
-	spin_unlock_irqrestore(&data->lock, flags);
-	mutex_unlock(&data->mutex);
-	return work;
-}
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Send a given tile to PicoLCD */
-static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
-	struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
-	unsigned long flags;
-	u8 *tdata;
-	int i;
-
-	if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report1->field[0],  0, chip << 2);
-	hid_set_field(report1->field[0],  1, 0x02);
-	hid_set_field(report1->field[0],  2, 0x00);
-	hid_set_field(report1->field[0],  3, 0x00);
-	hid_set_field(report1->field[0],  4, 0xb8 | tile);
-	hid_set_field(report1->field[0],  5, 0x00);
-	hid_set_field(report1->field[0],  6, 0x00);
-	hid_set_field(report1->field[0],  7, 0x40);
-	hid_set_field(report1->field[0],  8, 0x00);
-	hid_set_field(report1->field[0],  9, 0x00);
-	hid_set_field(report1->field[0], 10,   32);
-
-	hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
-	hid_set_field(report2->field[0],  1, 0x00);
-	hid_set_field(report2->field[0],  2, 0x00);
-	hid_set_field(report2->field[0],  3,   32);
-
-	tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
-	for (i = 0; i < 64; i++)
-		if (i < 32)
-			hid_set_field(report1->field[0], 11 + i, tdata[i]);
-		else
-			hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
-
-	usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
-	usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-/* Translate a single tile*/
-static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
-		int chip, int tile)
-{
-	int i, b, changed = 0;
-	u8 tdata[64];
-	u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
-
-	if (bpp == 1) {
-		for (b = 7; b >= 0; b--) {
-			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
-			for (i = 0; i < 64; i++) {
-				tdata[i] <<= 1;
-				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
-			}
-		}
-	} else if (bpp == 8) {
-		for (b = 7; b >= 0; b--) {
-			const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
-			for (i = 0; i < 64; i++) {
-				tdata[i] <<= 1;
-				tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
-			}
-		}
-	} else {
-		/* Oops, we should never get here! */
-		WARN_ON(1);
-		return 0;
-	}
-
-	for (i = 0; i < 64; i++)
-		if (tdata[i] != vdata[i]) {
-			changed = 1;
-			vdata[i] = tdata[i];
-		}
-	return changed;
-}
-
-/* Reconfigure LCD display */
-static int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
-	int i, j;
-	unsigned long flags;
-	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
-
-	if (!report || report->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	for (i = 0; i < 4; i++) {
-		for (j = 0; j < report->field[0]->maxusage; j++)
-			if (j == 0)
-				hid_set_field(report->field[0], j, i << 2);
-			else if (j < sizeof(mapcmd))
-				hid_set_field(report->field[0], j, mapcmd[j]);
-			else
-				hid_set_field(report->field[0], j, 0);
-		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	}
-
-	data->status |= PICOLCD_READY_FB;
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	if (data->fb_bitmap) {
-		if (clear) {
-			memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
-			memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
-		}
-		data->fb_force = 1;
-	}
-
-	/* schedule first output of framebuffer */
-	if (data->fb_info)
-		schedule_delayed_work(&data->fb_info->deferred_work, 0);
-
-	return 0;
-}
-
-/* Update fb_vbitmap from the screen_base and send changed tiles to device */
-static void picolcd_fb_update(struct picolcd_data *data)
-{
-	int chip, tile, n;
-	unsigned long flags;
-
-	if (!data)
-		return;
-
-	spin_lock_irqsave(&data->lock, flags);
-	if (!(data->status & PICOLCD_READY_FB)) {
-		spin_unlock_irqrestore(&data->lock, flags);
-		picolcd_fb_reset(data, 0);
-	} else {
-		spin_unlock_irqrestore(&data->lock, flags);
-	}
-
-	/*
-	 * Translate the framebuffer into the format needed by the PicoLCD.
-	 * See display layout above.
-	 * Do this one tile after the other and push those tiles that changed.
-	 *
-	 * Wait for our IO to complete as otherwise we might flood the queue!
-	 */
-	n = 0;
-	for (chip = 0; chip < 4; chip++)
-		for (tile = 0; tile < 8; tile++)
-			if (picolcd_fb_update_tile(data->fb_vbitmap,
-					data->fb_bitmap, data->fb_bpp, chip, tile) ||
-				data->fb_force) {
-				n += 2;
-				if (!data->fb_info->par)
-					return; /* device lost! */
-				if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
-					usbhid_wait_io(data->hdev);
-					n = 0;
-				}
-				picolcd_fb_send_tile(data->hdev, chip, tile);
-			}
-	data->fb_force = false;
-	if (n)
-		usbhid_wait_io(data->hdev);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_fillrect(struct fb_info *info,
-		const struct fb_fillrect *rect)
-{
-	if (!info->par)
-		return;
-	sys_fillrect(info, rect);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_copyarea(struct fb_info *info,
-		const struct fb_copyarea *area)
-{
-	if (!info->par)
-		return;
-	sys_copyarea(info, area);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
-	if (!info->par)
-		return;
-	sys_imageblit(info, image);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/*
- * this is the slow path from userspace. they can seek and write to
- * the fb. it's inefficient to do anything less than a full screen draw
- */
-static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
-		size_t count, loff_t *ppos)
-{
-	ssize_t ret;
-	if (!info->par)
-		return -ENODEV;
-	ret = fb_sys_write(info, buf, count, ppos);
-	if (ret >= 0)
-		schedule_delayed_work(&info->deferred_work, 0);
-	return ret;
-}
-
-static int picolcd_fb_blank(int blank, struct fb_info *info)
-{
-	if (!info->par)
-		return -ENODEV;
-	/* We let fb notification do this for us via lcd/backlight device */
-	return 0;
-}
-
-static void picolcd_fb_destroy(struct fb_info *info)
-{
-	struct picolcd_data *data = info->par;
-	u32 *ref_cnt = info->pseudo_palette;
-	int may_release;
-
-	info->par = NULL;
-	if (data)
-		data->fb_info = NULL;
-	fb_deferred_io_cleanup(info);
-
-	ref_cnt--;
-	mutex_lock(&info->lock);
-	(*ref_cnt)--;
-	may_release = !*ref_cnt;
-	mutex_unlock(&info->lock);
-	if (may_release) {
-		vfree((u8 *)info->fix.smem_start);
-		framebuffer_release(info);
-	}
-}
-
-static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	__u32 bpp      = var->bits_per_pixel;
-	__u32 activate = var->activate;
-
-	/* only allow 1/8 bit depth (8-bit is grayscale) */
-	*var = picolcdfb_var;
-	var->activate = activate;
-	if (bpp >= 8) {
-		var->bits_per_pixel = 8;
-		var->red.length     = 8;
-		var->green.length   = 8;
-		var->blue.length    = 8;
-	} else {
-		var->bits_per_pixel = 1;
-		var->red.length     = 1;
-		var->green.length   = 1;
-		var->blue.length    = 1;
-	}
-	return 0;
-}
-
-static int picolcd_set_par(struct fb_info *info)
-{
-	struct picolcd_data *data = info->par;
-	u8 *tmp_fb, *o_fb;
-	if (!data)
-		return -ENODEV;
-	if (info->var.bits_per_pixel == data->fb_bpp)
-		return 0;
-	/* switch between 1/8 bit depths */
-	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
-		return -EINVAL;
-
-	o_fb   = data->fb_bitmap;
-	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
-	if (!tmp_fb)
-		return -ENOMEM;
-
-	/* translate FB content to new bits-per-pixel */
-	if (info->var.bits_per_pixel == 1) {
-		int i, b;
-		for (i = 0; i < PICOLCDFB_SIZE; i++) {
-			u8 p = 0;
-			for (b = 0; b < 8; b++) {
-				p <<= 1;
-				p |= o_fb[i*8+b] ? 0x01 : 0x00;
-			}
-			tmp_fb[i] = p;
-		}
-		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
-		info->fix.visual = FB_VISUAL_MONO01;
-		info->fix.line_length = PICOLCDFB_WIDTH / 8;
-	} else {
-		int i;
-		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
-		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
-			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
-		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
-		info->fix.line_length = PICOLCDFB_WIDTH;
-	}
-
-	kfree(tmp_fb);
-	data->fb_bpp      = info->var.bits_per_pixel;
-	return 0;
-}
-
-/* Do refcounting on our FB and cleanup per worker if FB is
- * closed after unplug of our device
- * (fb_release holds info->lock and still touches info after
- *  we return so we can't release it immediately.
- */
-struct picolcd_fb_cleanup_item {
-	struct fb_info *info;
-	struct picolcd_fb_cleanup_item *next;
-};
-static struct picolcd_fb_cleanup_item *fb_pending;
-static DEFINE_SPINLOCK(fb_pending_lock);
-
-static void picolcd_fb_do_cleanup(struct work_struct *data)
-{
-	struct picolcd_fb_cleanup_item *item;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&fb_pending_lock, flags);
-		item = fb_pending;
-		fb_pending = item ? item->next : NULL;
-		spin_unlock_irqrestore(&fb_pending_lock, flags);
-
-		if (item) {
-			u8 *fb = (u8 *)item->info->fix.smem_start;
-			/* make sure we do not race against fb core when
-			 * releasing */
-			mutex_lock(&item->info->lock);
-			mutex_unlock(&item->info->lock);
-			framebuffer_release(item->info);
-			vfree(fb);
-		}
-	} while (item);
-}
-
-static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
-
-static int picolcd_fb_open(struct fb_info *info, int u)
-{
-	u32 *ref_cnt = info->pseudo_palette;
-	ref_cnt--;
-
-	(*ref_cnt)++;
-	return 0;
-}
-
-static int picolcd_fb_release(struct fb_info *info, int u)
-{
-	u32 *ref_cnt = info->pseudo_palette;
-	ref_cnt--;
-
-	(*ref_cnt)++;
-	if (!*ref_cnt) {
-		unsigned long flags;
-		struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
-		item--;
-		spin_lock_irqsave(&fb_pending_lock, flags);
-		item->next = fb_pending;
-		fb_pending = item;
-		spin_unlock_irqrestore(&fb_pending_lock, flags);
-		schedule_work(&picolcd_fb_cleanup);
-	}
-	return 0;
-}
-
-/* Note this can't be const because of struct fb_info definition */
-static struct fb_ops picolcdfb_ops = {
-	.owner        = THIS_MODULE,
-	.fb_destroy   = picolcd_fb_destroy,
-	.fb_open      = picolcd_fb_open,
-	.fb_release   = picolcd_fb_release,
-	.fb_read      = fb_sys_read,
-	.fb_write     = picolcd_fb_write,
-	.fb_blank     = picolcd_fb_blank,
-	.fb_fillrect  = picolcd_fb_fillrect,
-	.fb_copyarea  = picolcd_fb_copyarea,
-	.fb_imageblit = picolcd_fb_imageblit,
-	.fb_check_var = picolcd_fb_check_var,
-	.fb_set_par   = picolcd_set_par,
-};
-
-
-/* Callback from deferred IO workqueue */
-static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
-{
-	picolcd_fb_update(info->par);
-}
-
-static const struct fb_deferred_io picolcd_fb_defio = {
-	.delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
-	.deferred_io = picolcd_fb_deferred_io,
-};
-
-
-/*
- * The "fb_update_rate" sysfs attribute
- */
-static ssize_t picolcd_fb_update_rate_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	unsigned i, fb_update_rate = data->fb_update_rate;
-	size_t ret = 0;
-
-	for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
-		if (ret >= PAGE_SIZE)
-			break;
-		else if (i == fb_update_rate)
-			ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
-		else
-			ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
-	if (ret > 0)
-		buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
-	return ret;
-}
-
-static ssize_t picolcd_fb_update_rate_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	int i;
-	unsigned u;
-
-	if (count < 1 || count > 10)
-		return -EINVAL;
-
-	i = sscanf(buf, "%u", &u);
-	if (i != 1)
-		return -EINVAL;
-
-	if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
-		return -ERANGE;
-	else if (u == 0)
-		u = PICOLCDFB_UPDATE_RATE_DEFAULT;
-
-	data->fb_update_rate = u;
-	data->fb_defio.delay = HZ / data->fb_update_rate;
-	return count;
-}
-
-static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
-		picolcd_fb_update_rate_store);
-
-/* initialize Framebuffer device */
-static int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-	struct device *dev = &data->hdev->dev;
-	struct fb_info *info = NULL;
-	int i, error = -ENOMEM;
-	u8 *fb_vbitmap = NULL;
-	u8 *fb_bitmap  = NULL;
-	u32 *palette;
-
-	fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
-	if (fb_bitmap == NULL) {
-		dev_err(dev, "can't get a free page for framebuffer\n");
-		goto err_nomem;
-	}
-
-	fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
-	if (fb_vbitmap == NULL) {
-		dev_err(dev, "can't alloc vbitmap image buffer\n");
-		goto err_nomem;
-	}
-
-	data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
-	data->fb_defio = picolcd_fb_defio;
-	/* The extra memory is:
-	 * - struct picolcd_fb_cleanup_item
-	 * - u32 for ref_count
-	 * - 256*u32 for pseudo_palette
-	 */
-	info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
-	if (info == NULL) {
-		dev_err(dev, "failed to allocate a framebuffer\n");
-		goto err_nomem;
-	}
-
-	palette  = info->par + sizeof(struct picolcd_fb_cleanup_item);
-	*palette = 1;
-	palette++;
-	for (i = 0; i < 256; i++)
-		palette[i] = i > 0 && i < 16 ? 0xff : 0;
-	info->pseudo_palette = palette;
-	info->fbdefio = &data->fb_defio;
-	info->screen_base = (char __force __iomem *)fb_bitmap;
-	info->fbops = &picolcdfb_ops;
-	info->var = picolcdfb_var;
-	info->fix = picolcdfb_fix;
-	info->fix.smem_len   = PICOLCDFB_SIZE*8;
-	info->fix.smem_start = (unsigned long)fb_bitmap;
-	info->par = data;
-	info->flags = FBINFO_FLAG_DEFAULT;
-
-	data->fb_vbitmap = fb_vbitmap;
-	data->fb_bitmap  = fb_bitmap;
-	data->fb_bpp     = picolcdfb_var.bits_per_pixel;
-	error = picolcd_fb_reset(data, 1);
-	if (error) {
-		dev_err(dev, "failed to configure display\n");
-		goto err_cleanup;
-	}
-	error = device_create_file(dev, &dev_attr_fb_update_rate);
-	if (error) {
-		dev_err(dev, "failed to create sysfs attributes\n");
-		goto err_cleanup;
-	}
-	fb_deferred_io_init(info);
-	data->fb_info    = info;
-	error = register_framebuffer(info);
-	if (error) {
-		dev_err(dev, "failed to register framebuffer\n");
-		goto err_sysfs;
-	}
-	/* schedule first output of framebuffer */
-	data->fb_force = 1;
-	schedule_delayed_work(&info->deferred_work, 0);
-	return 0;
-
-err_sysfs:
-	fb_deferred_io_cleanup(info);
-	device_remove_file(dev, &dev_attr_fb_update_rate);
-err_cleanup:
-	data->fb_vbitmap = NULL;
-	data->fb_bitmap  = NULL;
-	data->fb_bpp     = 0;
-	data->fb_info    = NULL;
-
-err_nomem:
-	framebuffer_release(info);
-	vfree(fb_bitmap);
-	kfree(fb_vbitmap);
-	return error;
-}
-
-static void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-	struct fb_info *info = data->fb_info;
-	u8 *fb_vbitmap = data->fb_vbitmap;
-
-	if (!info)
-		return;
-
-	info->par = NULL;
-	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
-	unregister_framebuffer(info);
-	data->fb_vbitmap = NULL;
-	data->fb_bitmap  = NULL;
-	data->fb_bpp     = 0;
-	data->fb_info    = NULL;
-	kfree(fb_vbitmap);
-}
-
-#define picolcd_fbinfo(d) ((d)->fb_info)
-#else
-static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-	return 0;
-}
-static inline int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-	return 0;
-}
-static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-}
-#define picolcd_fbinfo(d) NULL
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-/*
- * backlight class device
- */
-static int picolcd_get_brightness(struct backlight_device *bdev)
-{
-	struct picolcd_data *data = bl_get_data(bdev);
-	return data->lcd_brightness;
-}
-
-static int picolcd_set_brightness(struct backlight_device *bdev)
-{
-	struct picolcd_data *data = bl_get_data(bdev);
-	struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
-	unsigned long flags;
-
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return -ENODEV;
-
-	data->lcd_brightness = bdev->props.brightness & 0x0ff;
-	data->lcd_power      = bdev->props.power;
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
-{
-	return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
-}
-
-static const struct backlight_ops picolcd_blops = {
-	.update_status  = picolcd_set_brightness,
-	.get_brightness = picolcd_get_brightness,
-	.check_fb       = picolcd_check_bl_fb,
-};
-
-static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct backlight_device *bdev;
-	struct backlight_properties props;
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported BRIGHTNESS report");
-		return -EINVAL;
-	}
-
-	memset(&props, 0, sizeof(props));
-	props.type = BACKLIGHT_RAW;
-	props.max_brightness = 0xff;
-	bdev = backlight_device_register(dev_name(dev), dev, data,
-			&picolcd_blops, &props);
-	if (IS_ERR(bdev)) {
-		dev_err(dev, "failed to register backlight\n");
-		return PTR_ERR(bdev);
-	}
-	bdev->props.brightness     = 0xff;
-	data->lcd_brightness       = 0xff;
-	data->backlight            = bdev;
-	picolcd_set_brightness(bdev);
-	return 0;
-}
-
-static void picolcd_exit_backlight(struct picolcd_data *data)
-{
-	struct backlight_device *bdev = data->backlight;
-
-	data->backlight = NULL;
-	if (bdev)
-		backlight_device_unregister(bdev);
-}
-
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-	if (!data->backlight)
-		return 0;
-	return picolcd_set_brightness(data->backlight);
-}
-
-#ifdef CONFIG_PM
-static void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-	int bl_power = data->lcd_power;
-	if (!data->backlight)
-		return;
-
-	data->backlight->props.power = FB_BLANK_POWERDOWN;
-	picolcd_set_brightness(data->backlight);
-	data->lcd_power = data->backlight->props.power = bl_power;
-}
-#endif /* CONFIG_PM */
-#else
-static inline int picolcd_init_backlight(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_backlight(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-	return 0;
-}
-static inline void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-
-#ifdef CONFIG_HID_PICOLCD_LCD
-/*
- * lcd class device
- */
-static int picolcd_get_contrast(struct lcd_device *ldev)
-{
-	struct picolcd_data *data = lcd_get_data(ldev);
-	return data->lcd_contrast;
-}
-
-static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
-{
-	struct picolcd_data *data = lcd_get_data(ldev);
-	struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
-	unsigned long flags;
-
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return -ENODEV;
-
-	data->lcd_contrast = contrast & 0x0ff;
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->lcd_contrast);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
-{
-	return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
-}
-
-static struct lcd_ops picolcd_lcdops = {
-	.get_contrast   = picolcd_get_contrast,
-	.set_contrast   = picolcd_set_contrast,
-	.check_fb       = picolcd_check_lcd_fb,
-};
-
-static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct lcd_device *ldev;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported CONTRAST report");
-		return -EINVAL;
-	}
-
-	ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
-	if (IS_ERR(ldev)) {
-		dev_err(dev, "failed to register LCD\n");
-		return PTR_ERR(ldev);
-	}
-	ldev->props.max_contrast = 0x0ff;
-	data->lcd_contrast = 0xe5;
-	data->lcd = ldev;
-	picolcd_set_contrast(ldev, 0xe5);
-	return 0;
-}
-
-static void picolcd_exit_lcd(struct picolcd_data *data)
-{
-	struct lcd_device *ldev = data->lcd;
-
-	data->lcd = NULL;
-	if (ldev)
-		lcd_device_unregister(ldev);
-}
-
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-	if (!data->lcd)
-		return 0;
-	return picolcd_set_contrast(data->lcd, data->lcd_contrast);
-}
-#else
-static inline int picolcd_init_lcd(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_lcd(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-	return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LCD */
-
-#ifdef CONFIG_HID_PICOLCD_LEDS
-/**
- * LED class device
- */
-static void picolcd_leds_set(struct picolcd_data *data)
-{
-	struct hid_report *report;
-	unsigned long flags;
-
-	if (!data->led[0])
-		return;
-	report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->led_state);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
-			enum led_brightness value)
-{
-	struct device *dev;
-	struct hid_device *hdev;
-	struct picolcd_data *data;
-	int i, state = 0;
-
-	dev  = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data = hid_get_drvdata(hdev);
-	for (i = 0; i < 8; i++) {
-		if (led_cdev != data->led[i])
-			continue;
-		state = (data->led_state >> i) & 1;
-		if (value == LED_OFF && state) {
-			data->led_state &= ~(1 << i);
-			picolcd_leds_set(data);
-		} else if (value != LED_OFF && !state) {
-			data->led_state |= 1 << i;
-			picolcd_leds_set(data);
-		}
-		break;
-	}
-}
-
-static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
-{
-	struct device *dev;
-	struct hid_device *hdev;
-	struct picolcd_data *data;
-	int i, value = 0;
-
-	dev  = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data = hid_get_drvdata(hdev);
-	for (i = 0; i < 8; i++)
-		if (led_cdev == data->led[i]) {
-			value = (data->led_state >> i) & 1;
-			break;
-		}
-	return value ? LED_FULL : LED_OFF;
-}
-
-static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct led_classdev *led;
-	size_t name_sz = strlen(dev_name(dev)) + 8;
-	char *name;
-	int i, ret = 0;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported LED_STATE report");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < 8; i++) {
-		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
-		if (!led) {
-			dev_err(dev, "can't allocate memory for LED %d\n", i);
-			ret = -ENOMEM;
-			goto err;
-		}
-		name = (void *)(&led[1]);
-		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
-		led->name = name;
-		led->brightness = 0;
-		led->max_brightness = 1;
-		led->brightness_get = picolcd_led_get_brightness;
-		led->brightness_set = picolcd_led_set_brightness;
-
-		data->led[i] = led;
-		ret = led_classdev_register(dev, data->led[i]);
-		if (ret) {
-			data->led[i] = NULL;
-			kfree(led);
-			dev_err(dev, "can't register LED %d\n", i);
-			goto err;
-		}
-	}
-	return 0;
-err:
-	for (i = 0; i < 8; i++)
-		if (data->led[i]) {
-			led = data->led[i];
-			data->led[i] = NULL;
-			led_classdev_unregister(led);
-			kfree(led);
-		}
-	return ret;
-}
-
-static void picolcd_exit_leds(struct picolcd_data *data)
-{
-	struct led_classdev *led;
-	int i;
-
-	for (i = 0; i < 8; i++) {
-		led = data->led[i];
-		data->led[i] = NULL;
-		if (!led)
-			continue;
-		led_classdev_unregister(led);
-		kfree(led);
-	}
-}
-
-#else
-static inline int picolcd_init_leds(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_leds(struct picolcd_data *data)
-{
-}
-static inline int picolcd_leds_set(struct picolcd_data *data)
-{
-	return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-/*
- * input class device
- */
-static int picolcd_raw_keypad(struct picolcd_data *data,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	/*
-	 * Keypad event
-	 * First and second data bytes list currently pressed keys,
-	 * 0x00 means no key and at most 2 keys may be pressed at same time
-	 */
-	int i, j;
-
-	/* determine newly pressed keys */
-	for (i = 0; i < size; i++) {
-		unsigned int key_code;
-		if (raw_data[i] == 0)
-			continue;
-		for (j = 0; j < sizeof(data->pressed_keys); j++)
-			if (data->pressed_keys[j] == raw_data[i])
-				goto key_already_down;
-		for (j = 0; j < sizeof(data->pressed_keys); j++)
-			if (data->pressed_keys[j] == 0) {
-				data->pressed_keys[j] = raw_data[i];
-				break;
-			}
-		input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
-		if (raw_data[i] < PICOLCD_KEYS)
-			key_code = data->keycode[raw_data[i]];
-		else
-			key_code = KEY_UNKNOWN;
-		if (key_code != KEY_UNKNOWN) {
-			dbg_hid(PICOLCD_NAME " got key press for %u:%d",
-					raw_data[i], key_code);
-			input_report_key(data->input_keys, key_code, 1);
-		}
-		input_sync(data->input_keys);
-key_already_down:
-		continue;
-	}
-
-	/* determine newly released keys */
-	for (j = 0; j < sizeof(data->pressed_keys); j++) {
-		unsigned int key_code;
-		if (data->pressed_keys[j] == 0)
-			continue;
-		for (i = 0; i < size; i++)
-			if (data->pressed_keys[j] == raw_data[i])
-				goto key_still_down;
-		input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
-		if (data->pressed_keys[j] < PICOLCD_KEYS)
-			key_code = data->keycode[data->pressed_keys[j]];
-		else
-			key_code = KEY_UNKNOWN;
-		if (key_code != KEY_UNKNOWN) {
-			dbg_hid(PICOLCD_NAME " got key release for %u:%d",
-					data->pressed_keys[j], key_code);
-			input_report_key(data->input_keys, key_code, 0);
-		}
-		input_sync(data->input_keys);
-		data->pressed_keys[j] = 0;
-key_still_down:
-		continue;
-	}
-	return 1;
-}
-
-static int picolcd_raw_cir(struct picolcd_data *data,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	/* Need understanding of CIR data format to implement ... */
-	return 1;
-}
-
-static int picolcd_check_version(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct picolcd_pending *verinfo;
-	int ret = 0;
-
-	if (!data)
-		return -ENODEV;
-
-	verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
-	if (!verinfo) {
-		hid_err(hdev, "no version response from PicoLCD\n");
-		return -ENODEV;
-	}
-
-	if (verinfo->raw_size == 2) {
-		data->version[0] = verinfo->raw_data[1];
-		data->version[1] = verinfo->raw_data[0];
-		if (data->status & PICOLCD_BOOTLOADER) {
-			hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
-				 verinfo->raw_data[1], verinfo->raw_data[0]);
-		} else {
-			hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
-				 verinfo->raw_data[1], verinfo->raw_data[0]);
-		}
-	} else {
-		hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
-		ret = -EINVAL;
-	}
-	kfree(verinfo);
-	return ret;
-}
-
-/*
- * Reset our device and wait for answer to VERSION request
- */
-static int picolcd_reset(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
-	unsigned long flags;
-	int error;
-
-	if (!data || !report || report->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-		data->status |= PICOLCD_BOOTLOADER;
-
-	/* perform the reset */
-	hid_set_field(report->field[0], 0, 1);
-	usbhid_submit_report(hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	picolcd_resume_lcd(data);
-	picolcd_resume_backlight(data);
-#ifdef CONFIG_HID_PICOLCD_FB
-	if (data->fb_info)
-		schedule_delayed_work(&data->fb_info->deferred_work, 0);
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-	picolcd_leds_set(data);
-	return 0;
-}
-
-/*
- * The "operation_mode" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
-	else
-		return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
-}
-
-static ssize_t picolcd_operation_mode_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	struct hid_report *report = NULL;
-	size_t cnt = count;
-	int timeout = data->opmode_delay;
-	unsigned long flags;
-
-	if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
-		if (data->status & PICOLCD_BOOTLOADER)
-			report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
-		buf += 3;
-		cnt -= 3;
-	} else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
-		if (!(data->status & PICOLCD_BOOTLOADER))
-			report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
-		buf += 10;
-		cnt -= 10;
-	}
-	if (!report)
-		return -EINVAL;
-
-	while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
-		cnt--;
-	if (cnt != 0)
-		return -EINVAL;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, timeout & 0xff);
-	hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return count;
-}
-
-static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
-		picolcd_operation_mode_store);
-
-/*
- * The "operation_mode_delay" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-
-	return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
-}
-
-static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	unsigned u;
-	if (sscanf(buf, "%u", &u) != 1)
-		return -EINVAL;
-	if (u > 30000)
-		return -EINVAL;
-	else
-		data->opmode_delay = u;
-	return count;
-}
-
-static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
-		picolcd_operation_mode_delay_store);
-
-
-#ifdef CONFIG_DEBUG_FS
-/*
- * The "reset" file
- */
-static int picolcd_debug_reset_show(struct seq_file *f, void *p)
-{
-	if (picolcd_fbinfo((struct picolcd_data *)f->private))
-		seq_printf(f, "all fb\n");
-	else
-		seq_printf(f, "all\n");
-	return 0;
-}
-
-static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
-{
-	return single_open(f, picolcd_debug_reset_show, inode->i_private);
-}
-
-static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
-		size_t count, loff_t *ppos)
-{
-	struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
-	char buf[32];
-	size_t cnt = min(count, sizeof(buf)-1);
-	if (copy_from_user(buf, user_buf, cnt))
-		return -EFAULT;
-
-	while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
-		cnt--;
-	buf[cnt] = '\0';
-	if (strcmp(buf, "all") == 0) {
-		picolcd_reset(data->hdev);
-		picolcd_fb_reset(data, 1);
-	} else if (strcmp(buf, "fb") == 0) {
-		picolcd_fb_reset(data, 1);
-	} else {
-		return -EINVAL;
-	}
-	return count;
-}
-
-static const struct file_operations picolcd_debug_reset_fops = {
-	.owner    = THIS_MODULE,
-	.open     = picolcd_debug_reset_open,
-	.read     = seq_read,
-	.llseek   = seq_lseek,
-	.write    = picolcd_debug_reset_write,
-	.release  = single_release,
-};
-
-/*
- * The "eeprom" file
- */
-static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	struct picolcd_pending *resp;
-	u8 raw_data[3];
-	ssize_t ret = -EIO;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x0ff)
-		return 0;
-
-	/* prepare buffer with info about what we want to read (addr & len) */
-	raw_data[0] = *off & 0xff;
-	raw_data[1] = (*off >> 8) & 0xff;
-	raw_data[2] = s < 20 ? s : 20;
-	if (*off + raw_data[2] > 0xff)
-		raw_data[2] = 0x100 - *off;
-	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
-			sizeof(raw_data));
-	if (!resp)
-		return -EIO;
-
-	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-		/* successful read :) */
-		ret = resp->raw_data[2];
-		if (ret > s)
-			ret = s;
-		if (copy_to_user(u, resp->raw_data+3, ret))
-			ret = -EFAULT;
-		else
-			*off += ret;
-	} /* anything else is some kind of IO error */
-
-	kfree(resp);
-	return ret;
-}
-
-static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	struct picolcd_pending *resp;
-	ssize_t ret = -EIO;
-	u8 raw_data[23];
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x0ff)
-		return -ENOSPC;
-
-	memset(raw_data, 0, sizeof(raw_data));
-	raw_data[0] = *off & 0xff;
-	raw_data[1] = (*off >> 8) & 0xff;
-	raw_data[2] = min((size_t)20, s);
-	if (*off + raw_data[2] > 0xff)
-		raw_data[2] = 0x100 - *off;
-
-	if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
-		return -EFAULT;
-	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
-			sizeof(raw_data));
-
-	if (!resp)
-		return -EIO;
-
-	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-		/* check if written data matches */
-		if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
-			*off += raw_data[2];
-			ret = raw_data[2];
-		}
-	}
-	kfree(resp);
-	return ret;
-}
-
-/*
- * Notes:
- * - read/write happens in chunks of at most 20 bytes, it's up to userspace
- *   to loop in order to get more data.
- * - on write errors on otherwise correct write request the bytes
- *   that should have been written are in undefined state.
- */
-static const struct file_operations picolcd_debug_eeprom_fops = {
-	.owner    = THIS_MODULE,
-	.open     = simple_open,
-	.read     = picolcd_debug_eeprom_read,
-	.write    = picolcd_debug_eeprom_write,
-	.llseek   = generic_file_llseek,
-};
-
-/*
- * The "flash" file
- */
-/* record a flash address to buf (bounds check to be done by caller) */
-static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
-{
-	buf[0] = off & 0xff;
-	buf[1] = (off >> 8) & 0xff;
-	if (data->addr_sz == 3)
-		buf[2] = (off >> 16) & 0xff;
-	return data->addr_sz == 2 ? 2 : 3;
-}
-
-/* read a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
-		char __user *u, size_t s, loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[4];
-	ssize_t ret = 0;
-	int len_off, err = -EIO;
-
-	while (s > 0) {
-		err = -EIO;
-		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-		raw_data[len_off] = s > 32 ? 32 : s;
-		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
-		if (!resp || !resp->in_report)
-			goto skip;
-		if (resp->in_report->id == REPORT_MEMORY ||
-			resp->in_report->id == REPORT_BL_READ_MEMORY) {
-			if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
-				goto skip;
-			if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
-				err = -EFAULT;
-				goto skip;
-			}
-			*off += raw_data[len_off];
-			s    -= raw_data[len_off];
-			ret  += raw_data[len_off];
-			err   = 0;
-		}
-skip:
-		kfree(resp);
-		if (err)
-			return ret > 0 ? ret : err;
-	}
-	return ret;
-}
-
-static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x05fff)
-		return 0;
-	if (*off + s > 0x05fff)
-		s = 0x06000 - *off;
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
-	else
-		return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
-}
-
-/* erase block aligned to 64bytes boundary */
-static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
-		loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[3];
-	int len_off;
-	ssize_t ret = -EIO;
-
-	if (*off & 0x3f)
-		return -EINVAL;
-
-	len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-	resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
-	if (!resp || !resp->in_report)
-		goto skip;
-	if (resp->in_report->id == REPORT_MEMORY ||
-		resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
-		if (memcmp(raw_data, resp->raw_data, len_off) != 0)
-			goto skip;
-		ret = 0;
-	}
-skip:
-	kfree(resp);
-	return ret;
-}
-
-/* write a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
-		const char __user *u, size_t s, loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[36];
-	ssize_t ret = 0;
-	int len_off, err = -EIO;
-
-	while (s > 0) {
-		err = -EIO;
-		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-		raw_data[len_off] = s > 32 ? 32 : s;
-		if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
-			err = -EFAULT;
-			break;
-		}
-		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
-				len_off+1+raw_data[len_off]);
-		if (!resp || !resp->in_report)
-			goto skip;
-		if (resp->in_report->id == REPORT_MEMORY ||
-			resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
-			if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
-				goto skip;
-			*off += raw_data[len_off];
-			s    -= raw_data[len_off];
-			ret  += raw_data[len_off];
-			err   = 0;
-		}
-skip:
-		kfree(resp);
-		if (err)
-			break;
-	}
-	return ret > 0 ? ret : err;
-}
-
-static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	ssize_t err, ret = 0;
-	int report_erase, report_write;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x5fff)
-		return -ENOSPC;
-	if (s & 0x3f)
-		return -EINVAL;
-	if (*off & 0x3f)
-		return -EINVAL;
-
-	if (data->status & PICOLCD_BOOTLOADER) {
-		report_erase = REPORT_BL_ERASE_MEMORY;
-		report_write = REPORT_BL_WRITE_MEMORY;
-	} else {
-		report_erase = REPORT_ERASE_MEMORY;
-		report_write = REPORT_WRITE_MEMORY;
-	}
-	mutex_lock(&data->mutex_flash);
-	while (s > 0) {
-		err = _picolcd_flash_erase64(data, report_erase, off);
-		if (err)
-			break;
-		err = _picolcd_flash_write(data, report_write, u, 64, off);
-		if (err < 0)
-			break;
-		ret += err;
-		*off += err;
-		s -= err;
-		if (err != 64)
-			break;
-	}
-	mutex_unlock(&data->mutex_flash);
-	return ret > 0 ? ret : err;
-}
-
-/*
- * Notes:
- * - concurrent writing is prevented by mutex and all writes must be
- *   n*64 bytes and 64-byte aligned, each write being preceded by an
- *   ERASE which erases a 64byte block.
- *   If less than requested was written or an error is returned for an
- *   otherwise correct write request the next 64-byte block which should
- *   have been written is in undefined state (mostly: original, erased,
- *   (half-)written with write error)
- * - reading can happen without special restriction
- */
-static const struct file_operations picolcd_debug_flash_fops = {
-	.owner    = THIS_MODULE,
-	.open     = simple_open,
-	.read     = picolcd_debug_flash_read,
-	.write    = picolcd_debug_flash_write,
-	.llseek   = generic_file_llseek,
-};
-
-
-/*
- * Helper code for HID report level dumping/debugging
- */
-static const char *error_codes[] = {
-	"success", "parameter missing", "data_missing", "block readonly",
-	"block not erasable", "block too big", "section overflow",
-	"invalid command length", "invalid data length",
-};
-
-static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
-		const size_t data_len)
-{
-	int i, j;
-	for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
-		dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
-		dst[j++] = hex_asc[data[i] & 0x0f];
-		dst[j++] = ' ';
-	}
-	if (j < dst_sz) {
-		dst[j--] = '\0';
-		dst[j] = '\n';
-	} else
-		dst[j] = '\0';
-}
-
-static void picolcd_debug_out_report(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report)
-{
-	u8 raw_data[70];
-	int raw_size = (report->size >> 3) + 1;
-	char *buff;
-#define BUFF_SZ 256
-
-	/* Avoid unnecessary overhead if debugfs is disabled */
-	if (list_empty(&hdev->debug_list))
-		return;
-
-	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-	if (!buff)
-		return;
-
-	snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
-			report->id, raw_size);
-	hid_debug_event(hdev, buff);
-	if (raw_size + 5 > sizeof(raw_data)) {
-		kfree(buff);
-		hid_debug_event(hdev, " TOO BIG\n");
-		return;
-	} else {
-		raw_data[0] = report->id;
-		hid_output_report(report, raw_data);
-		dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
-		hid_debug_event(hdev, buff);
-	}
-
-	switch (report->id) {
-	case REPORT_LED_STATE:
-		/* 1 data byte with GPO state */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LED_STATE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_BRIGHTNESS:
-		/* 1 data byte with brightness */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_BRIGHTNESS", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_CONTRAST:
-		/* 1 data byte with contrast */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_CONTRAST", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_RESET:
-		/* 2 data bytes with reset duration in ms */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_RESET", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
-				raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_LCD_CMD:
-		/* 63 data bytes with LCD commands */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO: format decoding */
-		break;
-	case REPORT_LCD_DATA:
-		/* 63 data bytes with LCD data */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		/* TODO: format decoding */
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_LCD_CMD_DATA:
-		/* 63 data bytes with LCD commands and data */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		/* TODO: format decoding */
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EE_READ:
-		/* 3 data bytes with read area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EE_READ", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EE_WRITE:
-		/* 3+1..20 data bytes with write area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EE_WRITE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		if (raw_data[3] == 0) {
-			snprintf(buff, BUFF_SZ, "\tNo data\n");
-		} else if (raw_data[3] + 4 <= raw_size) {
-			snprintf(buff, BUFF_SZ, "\tData: ");
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_ERASE_MEMORY:
-	case REPORT_BL_ERASE_MEMORY:
-		/* 3 data bytes with pointer inside erase block */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_ERASE_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_READ_MEMORY:
-	case REPORT_BL_READ_MEMORY:
-		/* 4 data bytes with read area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_READ_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_WRITE_MEMORY:
-	case REPORT_BL_WRITE_MEMORY:
-		/* 4+1..32 data bytes with write adrea description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_WRITE_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[3] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[3] + 4 <= raw_size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[4] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[4] + 5 <= raw_size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_RESTART:
-		/* TODO */
-		break;
-	case REPORT_EXIT_KEYBOARD:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-				raw_data[1] | (raw_data[2] << 8),
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_VERSION:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_DEVID:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_DEVID", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_SIZE:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_SPLASH_SIZE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_HOOK_VERSION:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_HOOK_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EXIT_FLASHER:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-				raw_data[1] | (raw_data[2] << 8),
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	default:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"<unknown>", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	}
-	wake_up_interruptible(&hdev->debug_wait);
-	kfree(buff);
-}
-
-static void picolcd_debug_raw_event(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report,
-		u8 *raw_data, int size)
-{
-	char *buff;
-
-#define BUFF_SZ 256
-	/* Avoid unnecessary overhead if debugfs is disabled */
-	if (!hdev->debug_events)
-		return;
-
-	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-	if (!buff)
-		return;
-
-	switch (report->id) {
-	case REPORT_ERROR_CODE:
-		/* 2 data bytes with affected report and error code */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_ERROR_CODE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[2] < ARRAY_SIZE(error_codes))
-			snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
-					raw_data[2], error_codes[raw_data[2]], raw_data[1]);
-		else
-			snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
-					raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_KEY_STATE:
-		/* 2 data bytes with key state */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_KEY_STATE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[1] == 0)
-			snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
-		else if (raw_data[2] == 0)
-			snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
-					raw_data[1], raw_data[1]);
-		else
-			snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
-					raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_IR_DATA:
-		/* Up to 20 byes of IR scancode data */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_IR_DATA", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[1] == 0) {
-			snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
-			hid_debug_event(hdev, buff);
-		} else if (raw_data[1] + 1 <= size) {
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
-					raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
-					raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-		}
-		break;
-	case REPORT_EE_DATA:
-		/* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_EE_DATA", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		if (raw_data[3] == 0) {
-			snprintf(buff, BUFF_SZ, "\tNo data\n");
-			hid_debug_event(hdev, buff);
-		} else if (raw_data[3] + 4 <= size) {
-			snprintf(buff, BUFF_SZ, "\tData: ");
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			hid_debug_event(hdev, buff);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			hid_debug_event(hdev, buff);
-		}
-		break;
-	case REPORT_MEMORY:
-		/* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[3] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[3] + 4 <= size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[4] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[4] + 5 <= size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_VERSION:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_BL_ERASE_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_ERASE_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_BL_READ_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_READ_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_BL_WRITE_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_WRITE_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_DEVID:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_DEVID", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
-				raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
-				raw_data[5]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_SIZE:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_SPLASH_SIZE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
-				(raw_data[2] << 8) | raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
-				(raw_data[4] << 8) | raw_data[3]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_HOOK_VERSION:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_HOOK_VERSION", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-				raw_data[1], raw_data[2]);
-		hid_debug_event(hdev, buff);
-		break;
-	default:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"<unknown>", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	}
-	wake_up_interruptible(&hdev->debug_wait);
-	kfree(buff);
-}
-
-static void picolcd_init_devfs(struct picolcd_data *data,
-		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-		struct hid_report *flash_r, struct hid_report *flash_w,
-		struct hid_report *reset)
-{
-	struct hid_device *hdev = data->hdev;
-
-	mutex_init(&data->mutex_flash);
-
-	/* reset */
-	if (reset)
-		data->debug_reset = debugfs_create_file("reset", 0600,
-				hdev->debug_dir, data, &picolcd_debug_reset_fops);
-
-	/* eeprom */
-	if (eeprom_r || eeprom_w)
-		data->debug_eeprom = debugfs_create_file("eeprom",
-			(eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
-			hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
-
-	/* flash */
-	if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
-		data->addr_sz = flash_r->field[0]->report_count - 1;
-	else
-		data->addr_sz = -1;
-	if (data->addr_sz == 2 || data->addr_sz == 3) {
-		data->debug_flash = debugfs_create_file("flash",
-			(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
-			hdev->debug_dir, data, &picolcd_debug_flash_fops);
-	} else if (flash_r || flash_w)
-		hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
-}
-
-static void picolcd_exit_devfs(struct picolcd_data *data)
-{
-	struct dentry *dent;
-
-	dent = data->debug_reset;
-	data->debug_reset = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	dent = data->debug_eeprom;
-	data->debug_eeprom = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	dent = data->debug_flash;
-	data->debug_flash = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	mutex_destroy(&data->mutex_flash);
-}
-#else
-static inline void picolcd_debug_raw_event(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report,
-		u8 *raw_data, int size)
-{
-}
-static inline void picolcd_init_devfs(struct picolcd_data *data,
-		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-		struct hid_report *flash_r, struct hid_report *flash_w,
-		struct hid_report *reset)
-{
-}
-static inline void picolcd_exit_devfs(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-/*
- * Handle raw report as sent by device
- */
-static int picolcd_raw_event(struct hid_device *hdev,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	unsigned long flags;
-	int ret = 0;
-
-	if (!data)
-		return 1;
-
-	if (report->id == REPORT_KEY_STATE) {
-		if (data->input_keys)
-			ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
-	} else if (report->id == REPORT_IR_DATA) {
-		if (data->input_cir)
-			ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
-	} else {
-		spin_lock_irqsave(&data->lock, flags);
-		/*
-		 * We let the caller of picolcd_send_and_wait() check if the
-		 * report we got is one of the expected ones or not.
-		 */
-		if (data->pending) {
-			memcpy(data->pending->raw_data, raw_data+1, size-1);
-			data->pending->raw_size  = size-1;
-			data->pending->in_report = report;
-			complete(&data->pending->ready);
-		}
-		spin_unlock_irqrestore(&data->lock, flags);
-	}
-
-	picolcd_debug_raw_event(data, hdev, report, raw_data, size);
-	return 1;
-}
-
-#ifdef CONFIG_PM
-static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
-{
-	if (PMSG_IS_AUTO(message))
-		return 0;
-
-	picolcd_suspend_backlight(hid_get_drvdata(hdev));
-	dbg_hid(PICOLCD_NAME " device ready for suspend\n");
-	return 0;
-}
-
-static int picolcd_resume(struct hid_device *hdev)
-{
-	int ret;
-	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-	return 0;
-}
-
-static int picolcd_reset_resume(struct hid_device *hdev)
-{
-	int ret;
-	ret = picolcd_reset(hdev);
-	if (ret)
-		dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
-	ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
-	ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
-	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-	picolcd_leds_set(hid_get_drvdata(hdev));
-	return 0;
-}
-#endif
-
-/* initialize keypad input device */
-static int picolcd_init_keys(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	struct hid_device *hdev = data->hdev;
-	struct input_dev *idev;
-	int error, i;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
-			report->field[0]->report_size != 8) {
-		hid_err(hdev, "unsupported KEY_STATE report\n");
-		return -EINVAL;
-	}
-
-	idev = input_allocate_device();
-	if (idev == NULL) {
-		hid_err(hdev, "failed to allocate input device\n");
-		return -ENOMEM;
-	}
-	input_set_drvdata(idev, hdev);
-	memcpy(data->keycode, def_keymap, sizeof(def_keymap));
-	idev->name = hdev->name;
-	idev->phys = hdev->phys;
-	idev->uniq = hdev->uniq;
-	idev->id.bustype = hdev->bus;
-	idev->id.vendor  = hdev->vendor;
-	idev->id.product = hdev->product;
-	idev->id.version = hdev->version;
-	idev->dev.parent = hdev->dev.parent;
-	idev->keycode     = &data->keycode;
-	idev->keycodemax  = PICOLCD_KEYS;
-	idev->keycodesize = sizeof(data->keycode[0]);
-	input_set_capability(idev, EV_MSC, MSC_SCAN);
-	set_bit(EV_REP, idev->evbit);
-	for (i = 0; i < PICOLCD_KEYS; i++)
-		input_set_capability(idev, EV_KEY, data->keycode[i]);
-	error = input_register_device(idev);
-	if (error) {
-		hid_err(hdev, "error registering the input device\n");
-		input_free_device(idev);
-		return error;
-	}
-	data->input_keys = idev;
-	return 0;
-}
-
-static void picolcd_exit_keys(struct picolcd_data *data)
-{
-	struct input_dev *idev = data->input_keys;
-
-	data->input_keys = NULL;
-	if (idev)
-		input_unregister_device(idev);
-}
-
-/* initialize CIR input device */
-static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
-{
-	/* support not implemented yet */
-	return 0;
-}
-
-static inline void picolcd_exit_cir(struct picolcd_data *data)
-{
-}
-
-static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
-{
-	int error;
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	if (data->version[0] != 0 && data->version[1] != 3)
-		hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-			 dev_name(&hdev->dev));
-
-	/* Setup keypad input device */
-	error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
-	if (error)
-		goto err;
-
-	/* Setup CIR input device */
-	error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
-	if (error)
-		goto err;
-
-	/* Set up the framebuffer device */
-	error = picolcd_init_framebuffer(data);
-	if (error)
-		goto err;
-
-	/* Setup lcd class device */
-	error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
-	if (error)
-		goto err;
-
-	/* Setup backlight class device */
-	error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
-	if (error)
-		goto err;
-
-	/* Setup the LED class devices */
-	error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
-	if (error)
-		goto err;
-
-	picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
-			picolcd_out_report(REPORT_EE_WRITE, hdev),
-			picolcd_out_report(REPORT_READ_MEMORY, hdev),
-			picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
-			picolcd_out_report(REPORT_RESET, hdev));
-	return 0;
-err:
-	picolcd_exit_leds(data);
-	picolcd_exit_backlight(data);
-	picolcd_exit_lcd(data);
-	picolcd_exit_framebuffer(data);
-	picolcd_exit_cir(data);
-	picolcd_exit_keys(data);
-	return error;
-}
-
-static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
-{
-	int error;
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	if (data->version[0] != 1 && data->version[1] != 0)
-		hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-			 dev_name(&hdev->dev));
-
-	picolcd_init_devfs(data, NULL, NULL,
-			picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
-			picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
-	return 0;
-}
-
-static int picolcd_probe(struct hid_device *hdev,
-		     const struct hid_device_id *id)
-{
-	struct picolcd_data *data;
-	int error = -ENOMEM;
-
-	dbg_hid(PICOLCD_NAME " hardware probe...\n");
-
-	/*
-	 * Let's allocate the picolcd data structure, set some reasonable
-	 * defaults, and associate it with the device
-	 */
-	data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
-	if (data == NULL) {
-		hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
-		error = -ENOMEM;
-		goto err_no_cleanup;
-	}
-
-	spin_lock_init(&data->lock);
-	mutex_init(&data->mutex);
-	data->hdev = hdev;
-	data->opmode_delay = 5000;
-	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-		data->status |= PICOLCD_BOOTLOADER;
-	hid_set_drvdata(hdev, data);
-
-	/* Parse the device reports and start it up */
-	error = hid_parse(hdev);
-	if (error) {
-		hid_err(hdev, "device report parse failed\n");
-		goto err_cleanup_data;
-	}
-
-	error = hid_hw_start(hdev, 0);
-	if (error) {
-		hid_err(hdev, "hardware start failed\n");
-		goto err_cleanup_data;
-	}
-
-	error = hid_hw_open(hdev);
-	if (error) {
-		hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
-		goto err_cleanup_hid_hw;
-	}
-
-	error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
-	if (error) {
-		hid_err(hdev, "failed to create sysfs attributes\n");
-		goto err_cleanup_hid_ll;
-	}
-
-	error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
-	if (error) {
-		hid_err(hdev, "failed to create sysfs attributes\n");
-		goto err_cleanup_sysfs1;
-	}
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		error = picolcd_probe_bootloader(hdev, data);
-	else
-		error = picolcd_probe_lcd(hdev, data);
-	if (error)
-		goto err_cleanup_sysfs2;
-
-	dbg_hid(PICOLCD_NAME " activated and initialized\n");
-	return 0;
-
-err_cleanup_sysfs2:
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-err_cleanup_sysfs1:
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-err_cleanup_hid_ll:
-	hid_hw_close(hdev);
-err_cleanup_hid_hw:
-	hid_hw_stop(hdev);
-err_cleanup_data:
-	kfree(data);
-err_no_cleanup:
-	hid_set_drvdata(hdev, NULL);
-
-	return error;
-}
-
-static void picolcd_remove(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	unsigned long flags;
-
-	dbg_hid(PICOLCD_NAME " hardware remove...\n");
-	spin_lock_irqsave(&data->lock, flags);
-	data->status |= PICOLCD_FAILED;
-	spin_unlock_irqrestore(&data->lock, flags);
-#ifdef CONFIG_HID_PICOLCD_FB
-	/* short-circuit FB as early as possible in order to
-	 * avoid long delays if we host console.
-	 */
-	if (data->fb_info)
-		data->fb_info->par = NULL;
-#endif
-
-	picolcd_exit_devfs(data);
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-	hid_hw_close(hdev);
-	hid_hw_stop(hdev);
-	hid_set_drvdata(hdev, NULL);
-
-	/* Shortcut potential pending reply that will never arrive */
-	spin_lock_irqsave(&data->lock, flags);
-	if (data->pending)
-		complete(&data->pending->ready);
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	/* Cleanup LED */
-	picolcd_exit_leds(data);
-	/* Clean up the framebuffer */
-	picolcd_exit_backlight(data);
-	picolcd_exit_lcd(data);
-	picolcd_exit_framebuffer(data);
-	/* Cleanup input */
-	picolcd_exit_cir(data);
-	picolcd_exit_keys(data);
-
-	mutex_destroy(&data->mutex);
-	/* Finally, clean up the picolcd data itself */
-	kfree(data);
-}
-
-static const struct hid_device_id picolcd_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
-	{ }
-};
-MODULE_DEVICE_TABLE(hid, picolcd_devices);
-
-static struct hid_driver picolcd_driver = {
-	.name =          "hid-picolcd",
-	.id_table =      picolcd_devices,
-	.probe =         picolcd_probe,
-	.remove =        picolcd_remove,
-	.raw_event =     picolcd_raw_event,
-#ifdef CONFIG_PM
-	.suspend =       picolcd_suspend,
-	.resume =        picolcd_resume,
-	.reset_resume =  picolcd_reset_resume,
-#endif
-};
-
-static int __init picolcd_init(void)
-{
-	return hid_register_driver(&picolcd_driver);
-}
-
-static void __exit picolcd_exit(void)
-{
-	hid_unregister_driver(&picolcd_driver);
-#ifdef CONFIG_HID_PICOLCD_FB
-	flush_work_sync(&picolcd_fb_cleanup);
-	WARN_ON(fb_pending);
-#endif
-}
-
-module_init(picolcd_init);
-module_exit(picolcd_exit);
-MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h
new file mode 100644
index 0000000..020cef6
--- /dev/null
+++ b/drivers/hid/hid-picolcd.h
@@ -0,0 +1,309 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#define PICOLCD_NAME "PicoLCD (graphic)"
+
+/* Report numbers */
+#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
+#define   ERR_SUCCESS            0x00
+#define   ERR_PARAMETER_MISSING  0x01
+#define   ERR_DATA_MISSING       0x02
+#define   ERR_BLOCK_READ_ONLY    0x03
+#define   ERR_BLOCK_NOT_ERASABLE 0x04
+#define   ERR_BLOCK_TOO_BIG      0x05
+#define   ERR_SECTION_OVERFLOW   0x06
+#define   ERR_INVALID_CMD_LEN    0x07
+#define   ERR_INVALID_DATA_LEN   0x08
+#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
+#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
+#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
+#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
+#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
+#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
+#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
+#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
+#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
+#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
+#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
+#define	REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
+#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
+#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
+#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
+#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
+#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
+#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
+#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
+#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
+#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
+#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
+#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
+#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct picolcd_pending {
+	struct hid_report *out_report;
+	struct hid_report *in_report;
+	struct completion ready;
+	int raw_size;
+	u8 raw_data[64];
+};
+
+
+#define PICOLCD_KEYS 17
+
+/* Per device data structure */
+struct picolcd_data {
+	struct hid_device *hdev;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debug_reset;
+	struct dentry *debug_eeprom;
+	struct dentry *debug_flash;
+	struct mutex mutex_flash;
+	int addr_sz;
+#endif
+	u8 version[2];
+	unsigned short opmode_delay;
+	/* input stuff */
+	u8 pressed_keys[2];
+	struct input_dev *input_keys;
+#ifdef CONFIG_HID_PICOLCD_CIR
+	struct rc_dev *rc_dev;
+#endif
+	unsigned short keycode[PICOLCD_KEYS];
+
+#ifdef CONFIG_HID_PICOLCD_FB
+	/* Framebuffer stuff */
+	struct fb_info *fb_info;
+#endif /* CONFIG_HID_PICOLCD_FB */
+#ifdef CONFIG_HID_PICOLCD_LCD
+	struct lcd_device *lcd;
+	u8 lcd_contrast;
+#endif /* CONFIG_HID_PICOLCD_LCD */
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+	struct backlight_device *backlight;
+	u8 lcd_brightness;
+	u8 lcd_power;
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+#ifdef CONFIG_HID_PICOLCD_LEDS
+	/* LED stuff */
+	u8 led_state;
+	struct led_classdev *led[8];
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+	/* Housekeeping stuff */
+	spinlock_t lock;
+	struct mutex mutex;
+	struct picolcd_pending *pending;
+	int status;
+#define PICOLCD_BOOTLOADER 1
+#define PICOLCD_FAILED 2
+#define PICOLCD_CIR_SHUN 4
+};
+
+#ifdef CONFIG_HID_PICOLCD_FB
+struct picolcd_fb_data {
+	/* Framebuffer stuff */
+	spinlock_t lock;
+	struct picolcd_data *picolcd;
+	u8 update_rate;
+	u8 bpp;
+	u8 force;
+	u8 ready;
+	u8 *vbitmap;		/* local copy of what was sent to PicoLCD */
+	u8 *bitmap;		/* framebuffer */
+};
+#endif /* CONFIG_HID_PICOLCD_FB */
+
+/* Find a given report */
+#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
+#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
+
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
+
+#ifdef CONFIG_DEBUG_FS
+void picolcd_debug_out_report(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report);
+#define usbhid_submit_report(a, b, c) \
+	do { \
+		picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
+		usbhid_submit_report(a, b, c); \
+	} while (0)
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size);
+
+void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset);
+
+void picolcd_exit_devfs(struct picolcd_data *data);
+#else
+static inline void picolcd_debug_out_report(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report)
+{
+}
+static inline void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+}
+static inline void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset)
+{
+}
+static inline void picolcd_exit_devfs(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+
+#ifdef CONFIG_HID_PICOLCD_FB
+int picolcd_fb_reset(struct picolcd_data *data, int clear);
+
+int picolcd_init_framebuffer(struct picolcd_data *data);
+
+void picolcd_exit_framebuffer(struct picolcd_data *data);
+
+void picolcd_fb_refresh(struct picolcd_data *data);
+#define picolcd_fbinfo(d) ((d)->fb_info)
+#else
+static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+	return 0;
+}
+static inline int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+	return 0;
+}
+static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+}
+static inline void picolcd_fb_refresh(struct picolcd_data *data)
+{
+}
+#define picolcd_fbinfo(d) NULL
+#endif /* CONFIG_HID_PICOLCD_FB */
+
+
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+int picolcd_init_backlight(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_backlight(struct picolcd_data *data);
+
+int picolcd_resume_backlight(struct picolcd_data *data);
+
+void picolcd_suspend_backlight(struct picolcd_data *data);
+#else
+static inline int picolcd_init_backlight(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_backlight(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_backlight(struct picolcd_data *data)
+{
+	return 0;
+}
+static inline void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+}
+
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+
+
+#ifdef CONFIG_HID_PICOLCD_LCD
+int picolcd_init_lcd(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_lcd(struct picolcd_data *data);
+
+int picolcd_resume_lcd(struct picolcd_data *data);
+#else
+static inline int picolcd_init_lcd(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_lcd(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_lcd(struct picolcd_data *data)
+{
+	return 0;
+}
+#endif /* CONFIG_HID_PICOLCD_LCD */
+
+
+#ifdef CONFIG_HID_PICOLCD_LEDS
+int picolcd_init_leds(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_leds(struct picolcd_data *data);
+
+void picolcd_leds_set(struct picolcd_data *data);
+#else
+static inline int picolcd_init_leds(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_leds(struct picolcd_data *data)
+{
+}
+static inline void picolcd_leds_set(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+
+#ifdef CONFIG_HID_PICOLCD_CIR
+int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size);
+
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report);
+
+void picolcd_exit_cir(struct picolcd_data *data);
+#else
+static inline int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	return 1;
+}
+static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_cir(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LIRC */
+
+int picolcd_reset(struct hid_device *hdev);
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+			int report_id, const u8 *raw_data, int size);
diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c
new file mode 100644
index 0000000..b91f309
--- /dev/null
+++ b/drivers/hid/hid-picolcd_backlight.c
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include "hid-picolcd.h"
+
+static int picolcd_get_brightness(struct backlight_device *bdev)
+{
+	struct picolcd_data *data = bl_get_data(bdev);
+	return data->lcd_brightness;
+}
+
+static int picolcd_set_brightness(struct backlight_device *bdev)
+{
+	struct picolcd_data *data = bl_get_data(bdev);
+	struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
+	unsigned long flags;
+
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return -ENODEV;
+
+	data->lcd_brightness = bdev->props.brightness & 0x0ff;
+	data->lcd_power      = bdev->props.power;
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
+{
+	return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
+}
+
+static const struct backlight_ops picolcd_blops = {
+	.update_status  = picolcd_set_brightness,
+	.get_brightness = picolcd_get_brightness,
+	.check_fb       = picolcd_check_bl_fb,
+};
+
+int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct backlight_device *bdev;
+	struct backlight_properties props;
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported BRIGHTNESS report");
+		return -EINVAL;
+	}
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = 0xff;
+	bdev = backlight_device_register(dev_name(dev), dev, data,
+			&picolcd_blops, &props);
+	if (IS_ERR(bdev)) {
+		dev_err(dev, "failed to register backlight\n");
+		return PTR_ERR(bdev);
+	}
+	bdev->props.brightness     = 0xff;
+	data->lcd_brightness       = 0xff;
+	data->backlight            = bdev;
+	picolcd_set_brightness(bdev);
+	return 0;
+}
+
+void picolcd_exit_backlight(struct picolcd_data *data)
+{
+	struct backlight_device *bdev = data->backlight;
+
+	data->backlight = NULL;
+	if (bdev)
+		backlight_device_unregister(bdev);
+}
+
+int picolcd_resume_backlight(struct picolcd_data *data)
+{
+	if (!data->backlight)
+		return 0;
+	return picolcd_set_brightness(data->backlight);
+}
+
+#ifdef CONFIG_PM
+void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+	int bl_power = data->lcd_power;
+	if (!data->backlight)
+		return;
+
+	data->backlight->props.power = FB_BLANK_POWERDOWN;
+	picolcd_set_brightness(data->backlight);
+	data->lcd_power = data->backlight->props.power = bl_power;
+}
+#endif /* CONFIG_PM */
+
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
new file mode 100644
index 0000000..13ca919
--- /dev/null
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -0,0 +1,152 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <media/rc-core.h>
+
+#include "hid-picolcd.h"
+
+
+int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	unsigned long flags;
+	int i, w, sz;
+	DEFINE_IR_RAW_EVENT(rawir);
+
+	/* ignore if rc_dev is NULL or status is shunned */
+	spin_lock_irqsave(&data->lock, flags);
+	if (!data->rc_dev || (data->status & PICOLCD_CIR_SHUN)) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	/* PicoLCD USB packets contain 16-bit intervals in network order,
+	 * with value negated for pulse. Intervals are in microseconds.
+	 *
+	 * Note: some userspace LIRC code for PicoLCD says negated values
+	 * for space - is it a matter of IR chip? (pulse for my TSOP2236)
+	 *
+	 * In addition, the first interval seems to be around 15000 + base
+	 * interval for non-first report of IR data - thus the quirk below
+	 * to get RC_CODE to understand Sony and JVC remotes I have at hand
+	 */
+	sz = size > 0 ? min((int)raw_data[0], size-1) : 0;
+	for (i = 0; i+1 < sz; i += 2) {
+		init_ir_raw_event(&rawir);
+		w = (raw_data[i] << 8) | (raw_data[i+1]);
+		rawir.pulse = !!(w & 0x8000);
+		rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w);
+		/* Quirk!! - see above */
+		if (i == 0 && rawir.duration > 15000000)
+			rawir.duration -= 15000000;
+		ir_raw_event_store(data->rc_dev, &rawir);
+	}
+	ir_raw_event_handle(data->rc_dev);
+
+	return 1;
+}
+
+static int picolcd_cir_open(struct rc_dev *dev)
+{
+	struct picolcd_data *data = dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->status &= ~PICOLCD_CIR_SHUN;
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static void picolcd_cir_close(struct rc_dev *dev)
+{
+	struct picolcd_data *data = dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->status |= PICOLCD_CIR_SHUN;
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+/* initialize CIR input device */
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+	struct rc_dev *rdev;
+	int ret = 0;
+
+	rdev = rc_allocate_device();
+	if (!rdev)
+		return -ENOMEM;
+
+	rdev->priv             = data;
+	rdev->driver_type      = RC_DRIVER_IR_RAW;
+	rdev->allowed_protos   = RC_TYPE_ALL;
+	rdev->open             = picolcd_cir_open;
+	rdev->close            = picolcd_cir_close;
+	rdev->input_name       = data->hdev->name;
+	rdev->input_phys       = data->hdev->phys;
+	rdev->input_id.bustype = data->hdev->bus;
+	rdev->input_id.vendor  = data->hdev->vendor;
+	rdev->input_id.product = data->hdev->product;
+	rdev->input_id.version = data->hdev->version;
+	rdev->dev.parent       = &data->hdev->dev;
+	rdev->driver_name      = PICOLCD_NAME;
+	rdev->map_name         = RC_MAP_RC6_MCE;
+	rdev->timeout          = MS_TO_NS(100);
+	rdev->rx_resolution    = US_TO_NS(1);
+
+	ret = rc_register_device(rdev);
+	if (ret)
+		goto err;
+	data->rc_dev = rdev;
+	return 0;
+
+err:
+	rc_free_device(rdev);
+	return ret;
+}
+
+void picolcd_exit_cir(struct picolcd_data *data)
+{
+	struct rc_dev *rdev = data->rc_dev;
+
+	data->rc_dev = NULL;
+	rc_unregister_device(rdev);
+}
+
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
new file mode 100644
index 0000000..86df26e
--- /dev/null
+++ b/drivers/hid/hid-picolcd_core.c
@@ -0,0 +1,689 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+/* Input device
+ *
+ * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
+ * and header for 4x4 key matrix. The built-in keys are part of the matrix.
+ */
+static const unsigned short def_keymap[PICOLCD_KEYS] = {
+	KEY_RESERVED,	/* none */
+	KEY_BACK,	/* col 4 + row 1 */
+	KEY_HOMEPAGE,	/* col 3 + row 1 */
+	KEY_RESERVED,	/* col 2 + row 1 */
+	KEY_RESERVED,	/* col 1 + row 1 */
+	KEY_SCROLLUP,	/* col 4 + row 2 */
+	KEY_OK,		/* col 3 + row 2 */
+	KEY_SCROLLDOWN,	/* col 2 + row 2 */
+	KEY_RESERVED,	/* col 1 + row 2 */
+	KEY_RESERVED,	/* col 4 + row 3 */
+	KEY_RESERVED,	/* col 3 + row 3 */
+	KEY_RESERVED,	/* col 2 + row 3 */
+	KEY_RESERVED,	/* col 1 + row 3 */
+	KEY_RESERVED,	/* col 4 + row 4 */
+	KEY_RESERVED,	/* col 3 + row 4 */
+	KEY_RESERVED,	/* col 2 + row 4 */
+	KEY_RESERVED,	/* col 1 + row 4 */
+};
+
+
+/* Find a given report */
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
+{
+	struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
+	struct hid_report *report = NULL;
+
+	list_for_each_entry(report, feature_report_list, list) {
+		if (report->id == id)
+			return report;
+	}
+	hid_warn(hdev, "No report with id 0x%x found\n", id);
+	return NULL;
+}
+
+/* Submit a report and wait for a reply from device - if device fades away
+ * or does not respond in time, return NULL */
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+		int report_id, const u8 *raw_data, int size)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct picolcd_pending *work;
+	struct hid_report *report = picolcd_out_report(report_id, hdev);
+	unsigned long flags;
+	int i, j, k;
+
+	if (!report || !data)
+		return NULL;
+	if (data->status & PICOLCD_FAILED)
+		return NULL;
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return NULL;
+
+	init_completion(&work->ready);
+	work->out_report = report;
+	work->in_report  = NULL;
+	work->raw_size   = 0;
+
+	mutex_lock(&data->mutex);
+	spin_lock_irqsave(&data->lock, flags);
+	for (i = k = 0; i < report->maxfield; i++)
+		for (j = 0; j < report->field[i]->report_count; j++) {
+			hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
+			k++;
+		}
+	if (data->status & PICOLCD_FAILED) {
+		kfree(work);
+		work = NULL;
+	} else {
+		data->pending = work;
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+		spin_unlock_irqrestore(&data->lock, flags);
+		wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
+		spin_lock_irqsave(&data->lock, flags);
+		data->pending = NULL;
+	}
+	spin_unlock_irqrestore(&data->lock, flags);
+	mutex_unlock(&data->mutex);
+	return work;
+}
+
+/*
+ * input class device
+ */
+static int picolcd_raw_keypad(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	/*
+	 * Keypad event
+	 * First and second data bytes list currently pressed keys,
+	 * 0x00 means no key and at most 2 keys may be pressed at same time
+	 */
+	int i, j;
+
+	/* determine newly pressed keys */
+	for (i = 0; i < size; i++) {
+		unsigned int key_code;
+		if (raw_data[i] == 0)
+			continue;
+		for (j = 0; j < sizeof(data->pressed_keys); j++)
+			if (data->pressed_keys[j] == raw_data[i])
+				goto key_already_down;
+		for (j = 0; j < sizeof(data->pressed_keys); j++)
+			if (data->pressed_keys[j] == 0) {
+				data->pressed_keys[j] = raw_data[i];
+				break;
+			}
+		input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
+		if (raw_data[i] < PICOLCD_KEYS)
+			key_code = data->keycode[raw_data[i]];
+		else
+			key_code = KEY_UNKNOWN;
+		if (key_code != KEY_UNKNOWN) {
+			dbg_hid(PICOLCD_NAME " got key press for %u:%d",
+					raw_data[i], key_code);
+			input_report_key(data->input_keys, key_code, 1);
+		}
+		input_sync(data->input_keys);
+key_already_down:
+		continue;
+	}
+
+	/* determine newly released keys */
+	for (j = 0; j < sizeof(data->pressed_keys); j++) {
+		unsigned int key_code;
+		if (data->pressed_keys[j] == 0)
+			continue;
+		for (i = 0; i < size; i++)
+			if (data->pressed_keys[j] == raw_data[i])
+				goto key_still_down;
+		input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
+		if (data->pressed_keys[j] < PICOLCD_KEYS)
+			key_code = data->keycode[data->pressed_keys[j]];
+		else
+			key_code = KEY_UNKNOWN;
+		if (key_code != KEY_UNKNOWN) {
+			dbg_hid(PICOLCD_NAME " got key release for %u:%d",
+					data->pressed_keys[j], key_code);
+			input_report_key(data->input_keys, key_code, 0);
+		}
+		input_sync(data->input_keys);
+		data->pressed_keys[j] = 0;
+key_still_down:
+		continue;
+	}
+	return 1;
+}
+
+static int picolcd_check_version(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct picolcd_pending *verinfo;
+	int ret = 0;
+
+	if (!data)
+		return -ENODEV;
+
+	verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
+	if (!verinfo) {
+		hid_err(hdev, "no version response from PicoLCD\n");
+		return -ENODEV;
+	}
+
+	if (verinfo->raw_size == 2) {
+		data->version[0] = verinfo->raw_data[1];
+		data->version[1] = verinfo->raw_data[0];
+		if (data->status & PICOLCD_BOOTLOADER) {
+			hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+				 verinfo->raw_data[1], verinfo->raw_data[0]);
+		} else {
+			hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+				 verinfo->raw_data[1], verinfo->raw_data[0]);
+		}
+	} else {
+		hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
+		ret = -EINVAL;
+	}
+	kfree(verinfo);
+	return ret;
+}
+
+/*
+ * Reset our device and wait for answer to VERSION request
+ */
+int picolcd_reset(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
+	unsigned long flags;
+	int error;
+
+	if (!data || !report || report->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+		data->status |= PICOLCD_BOOTLOADER;
+
+	/* perform the reset */
+	hid_set_field(report->field[0], 0, 1);
+	if (data->status & PICOLCD_FAILED) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return -ENODEV;
+	}
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	error = picolcd_check_version(hdev);
+	if (error)
+		return error;
+
+	picolcd_resume_lcd(data);
+	picolcd_resume_backlight(data);
+	picolcd_fb_refresh(data);
+	picolcd_leds_set(data);
+	return 0;
+}
+
+/*
+ * The "operation_mode" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
+	else
+		return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
+}
+
+static ssize_t picolcd_operation_mode_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	struct hid_report *report = NULL;
+	size_t cnt = count;
+	int timeout = data->opmode_delay;
+	unsigned long flags;
+
+	if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
+		if (data->status & PICOLCD_BOOTLOADER)
+			report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
+		buf += 3;
+		cnt -= 3;
+	} else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
+		if (!(data->status & PICOLCD_BOOTLOADER))
+			report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
+		buf += 10;
+		cnt -= 10;
+	}
+	if (!report)
+		return -EINVAL;
+
+	while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
+		cnt--;
+	if (cnt != 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, timeout & 0xff);
+	hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
+	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return count;
+}
+
+static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
+		picolcd_operation_mode_store);
+
+/*
+ * The "operation_mode_delay" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
+}
+
+static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	unsigned u;
+	if (sscanf(buf, "%u", &u) != 1)
+		return -EINVAL;
+	if (u > 30000)
+		return -EINVAL;
+	else
+		data->opmode_delay = u;
+	return count;
+}
+
+static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
+		picolcd_operation_mode_delay_store);
+
+/*
+ * Handle raw report as sent by device
+ */
+static int picolcd_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+	int ret = 0;
+
+	if (!data)
+		return 1;
+
+	if (report->id == REPORT_KEY_STATE) {
+		if (data->input_keys)
+			ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
+	} else if (report->id == REPORT_IR_DATA) {
+		ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
+	} else {
+		spin_lock_irqsave(&data->lock, flags);
+		/*
+		 * We let the caller of picolcd_send_and_wait() check if the
+		 * report we got is one of the expected ones or not.
+		 */
+		if (data->pending) {
+			memcpy(data->pending->raw_data, raw_data+1, size-1);
+			data->pending->raw_size  = size-1;
+			data->pending->in_report = report;
+			complete(&data->pending->ready);
+		}
+		spin_unlock_irqrestore(&data->lock, flags);
+	}
+
+	picolcd_debug_raw_event(data, hdev, report, raw_data, size);
+	return 1;
+}
+
+#ifdef CONFIG_PM
+static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	if (PMSG_IS_AUTO(message))
+		return 0;
+
+	picolcd_suspend_backlight(hid_get_drvdata(hdev));
+	dbg_hid(PICOLCD_NAME " device ready for suspend\n");
+	return 0;
+}
+
+static int picolcd_resume(struct hid_device *hdev)
+{
+	int ret;
+	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+	return 0;
+}
+
+static int picolcd_reset_resume(struct hid_device *hdev)
+{
+	int ret;
+	ret = picolcd_reset(hdev);
+	if (ret)
+		dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
+	ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
+	ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
+	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+	picolcd_leds_set(hid_get_drvdata(hdev));
+	return 0;
+}
+#endif
+
+/* initialize keypad input device */
+static int picolcd_init_keys(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	struct hid_device *hdev = data->hdev;
+	struct input_dev *idev;
+	int error, i;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
+			report->field[0]->report_size != 8) {
+		hid_err(hdev, "unsupported KEY_STATE report\n");
+		return -EINVAL;
+	}
+
+	idev = input_allocate_device();
+	if (idev == NULL) {
+		hid_err(hdev, "failed to allocate input device\n");
+		return -ENOMEM;
+	}
+	input_set_drvdata(idev, hdev);
+	memcpy(data->keycode, def_keymap, sizeof(def_keymap));
+	idev->name = hdev->name;
+	idev->phys = hdev->phys;
+	idev->uniq = hdev->uniq;
+	idev->id.bustype = hdev->bus;
+	idev->id.vendor  = hdev->vendor;
+	idev->id.product = hdev->product;
+	idev->id.version = hdev->version;
+	idev->dev.parent = &hdev->dev;
+	idev->keycode     = &data->keycode;
+	idev->keycodemax  = PICOLCD_KEYS;
+	idev->keycodesize = sizeof(data->keycode[0]);
+	input_set_capability(idev, EV_MSC, MSC_SCAN);
+	set_bit(EV_REP, idev->evbit);
+	for (i = 0; i < PICOLCD_KEYS; i++)
+		input_set_capability(idev, EV_KEY, data->keycode[i]);
+	error = input_register_device(idev);
+	if (error) {
+		hid_err(hdev, "error registering the input device\n");
+		input_free_device(idev);
+		return error;
+	}
+	data->input_keys = idev;
+	return 0;
+}
+
+static void picolcd_exit_keys(struct picolcd_data *data)
+{
+	struct input_dev *idev = data->input_keys;
+
+	data->input_keys = NULL;
+	if (idev)
+		input_unregister_device(idev);
+}
+
+static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
+{
+	int error;
+
+	/* Setup keypad input device */
+	error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
+	if (error)
+		goto err;
+
+	/* Setup CIR input device */
+	error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
+	if (error)
+		goto err;
+
+	/* Set up the framebuffer device */
+	error = picolcd_init_framebuffer(data);
+	if (error)
+		goto err;
+
+	/* Setup lcd class device */
+	error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
+	if (error)
+		goto err;
+
+	/* Setup backlight class device */
+	error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
+	if (error)
+		goto err;
+
+	/* Setup the LED class devices */
+	error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
+	if (error)
+		goto err;
+
+	picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
+			picolcd_out_report(REPORT_EE_WRITE, hdev),
+			picolcd_out_report(REPORT_READ_MEMORY, hdev),
+			picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
+			picolcd_out_report(REPORT_RESET, hdev));
+	return 0;
+err:
+	picolcd_exit_leds(data);
+	picolcd_exit_backlight(data);
+	picolcd_exit_lcd(data);
+	picolcd_exit_framebuffer(data);
+	picolcd_exit_cir(data);
+	picolcd_exit_keys(data);
+	return error;
+}
+
+static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
+{
+	picolcd_init_devfs(data, NULL, NULL,
+			picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
+			picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
+	return 0;
+}
+
+static int picolcd_probe(struct hid_device *hdev,
+		     const struct hid_device_id *id)
+{
+	struct picolcd_data *data;
+	int error = -ENOMEM;
+
+	dbg_hid(PICOLCD_NAME " hardware probe...\n");
+
+	/*
+	 * Let's allocate the picolcd data structure, set some reasonable
+	 * defaults, and associate it with the device
+	 */
+	data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
+	if (data == NULL) {
+		hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
+		error = -ENOMEM;
+		goto err_no_cleanup;
+	}
+
+	spin_lock_init(&data->lock);
+	mutex_init(&data->mutex);
+	data->hdev = hdev;
+	data->opmode_delay = 5000;
+	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+		data->status |= PICOLCD_BOOTLOADER;
+	hid_set_drvdata(hdev, data);
+
+	/* Parse the device reports and start it up */
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "device report parse failed\n");
+		goto err_cleanup_data;
+	}
+
+	error = hid_hw_start(hdev, 0);
+	if (error) {
+		hid_err(hdev, "hardware start failed\n");
+		goto err_cleanup_data;
+	}
+
+	error = hid_hw_open(hdev);
+	if (error) {
+		hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
+		goto err_cleanup_hid_hw;
+	}
+
+	error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
+	if (error) {
+		hid_err(hdev, "failed to create sysfs attributes\n");
+		goto err_cleanup_hid_ll;
+	}
+
+	error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
+	if (error) {
+		hid_err(hdev, "failed to create sysfs attributes\n");
+		goto err_cleanup_sysfs1;
+	}
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		error = picolcd_probe_bootloader(hdev, data);
+	else
+		error = picolcd_probe_lcd(hdev, data);
+	if (error)
+		goto err_cleanup_sysfs2;
+
+	dbg_hid(PICOLCD_NAME " activated and initialized\n");
+	return 0;
+
+err_cleanup_sysfs2:
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+err_cleanup_sysfs1:
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+err_cleanup_hid_ll:
+	hid_hw_close(hdev);
+err_cleanup_hid_hw:
+	hid_hw_stop(hdev);
+err_cleanup_data:
+	kfree(data);
+err_no_cleanup:
+	hid_set_drvdata(hdev, NULL);
+
+	return error;
+}
+
+static void picolcd_remove(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+
+	dbg_hid(PICOLCD_NAME " hardware remove...\n");
+	spin_lock_irqsave(&data->lock, flags);
+	data->status |= PICOLCD_FAILED;
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	picolcd_exit_devfs(data);
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+
+	/* Shortcut potential pending reply that will never arrive */
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->pending)
+		complete(&data->pending->ready);
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	/* Cleanup LED */
+	picolcd_exit_leds(data);
+	/* Clean up the framebuffer */
+	picolcd_exit_backlight(data);
+	picolcd_exit_lcd(data);
+	picolcd_exit_framebuffer(data);
+	/* Cleanup input */
+	picolcd_exit_cir(data);
+	picolcd_exit_keys(data);
+
+	hid_set_drvdata(hdev, NULL);
+	mutex_destroy(&data->mutex);
+	/* Finally, clean up the picolcd data itself */
+	kfree(data);
+}
+
+static const struct hid_device_id picolcd_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, picolcd_devices);
+
+static struct hid_driver picolcd_driver = {
+	.name =          "hid-picolcd",
+	.id_table =      picolcd_devices,
+	.probe =         picolcd_probe,
+	.remove =        picolcd_remove,
+	.raw_event =     picolcd_raw_event,
+#ifdef CONFIG_PM
+	.suspend =       picolcd_suspend,
+	.resume =        picolcd_resume,
+	.reset_resume =  picolcd_reset_resume,
+#endif
+};
+
+static int __init picolcd_init(void)
+{
+	return hid_register_driver(&picolcd_driver);
+}
+
+static void __exit picolcd_exit(void)
+{
+	hid_unregister_driver(&picolcd_driver);
+}
+
+module_init(picolcd_init);
+module_exit(picolcd_exit);
+MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c
new file mode 100644
index 0000000..4809aa1
--- /dev/null
+++ b/drivers/hid/hid-picolcd_debugfs.c
@@ -0,0 +1,899 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "hid-picolcd.h"
+
+
+static int picolcd_debug_reset_show(struct seq_file *f, void *p)
+{
+	if (picolcd_fbinfo((struct picolcd_data *)f->private))
+		seq_printf(f, "all fb\n");
+	else
+		seq_printf(f, "all\n");
+	return 0;
+}
+
+static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, picolcd_debug_reset_show, inode->i_private);
+}
+
+static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
+	char buf[32];
+	size_t cnt = min(count, sizeof(buf)-1);
+	if (copy_from_user(buf, user_buf, cnt))
+		return -EFAULT;
+
+	while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
+		cnt--;
+	buf[cnt] = '\0';
+	if (strcmp(buf, "all") == 0) {
+		picolcd_reset(data->hdev);
+		picolcd_fb_reset(data, 1);
+	} else if (strcmp(buf, "fb") == 0) {
+		picolcd_fb_reset(data, 1);
+	} else {
+		return -EINVAL;
+	}
+	return count;
+}
+
+static const struct file_operations picolcd_debug_reset_fops = {
+	.owner    = THIS_MODULE,
+	.open     = picolcd_debug_reset_open,
+	.read     = seq_read,
+	.llseek   = seq_lseek,
+	.write    = picolcd_debug_reset_write,
+	.release  = single_release,
+};
+
+/*
+ * The "eeprom" file
+ */
+static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	struct picolcd_pending *resp;
+	u8 raw_data[3];
+	ssize_t ret = -EIO;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x0ff)
+		return 0;
+
+	/* prepare buffer with info about what we want to read (addr & len) */
+	raw_data[0] = *off & 0xff;
+	raw_data[1] = (*off >> 8) & 0xff;
+	raw_data[2] = s < 20 ? s : 20;
+	if (*off + raw_data[2] > 0xff)
+		raw_data[2] = 0x100 - *off;
+	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
+			sizeof(raw_data));
+	if (!resp)
+		return -EIO;
+
+	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+		/* successful read :) */
+		ret = resp->raw_data[2];
+		if (ret > s)
+			ret = s;
+		if (copy_to_user(u, resp->raw_data+3, ret))
+			ret = -EFAULT;
+		else
+			*off += ret;
+	} /* anything else is some kind of IO error */
+
+	kfree(resp);
+	return ret;
+}
+
+static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	struct picolcd_pending *resp;
+	ssize_t ret = -EIO;
+	u8 raw_data[23];
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x0ff)
+		return -ENOSPC;
+
+	memset(raw_data, 0, sizeof(raw_data));
+	raw_data[0] = *off & 0xff;
+	raw_data[1] = (*off >> 8) & 0xff;
+	raw_data[2] = min_t(size_t, 20, s);
+	if (*off + raw_data[2] > 0xff)
+		raw_data[2] = 0x100 - *off;
+
+	if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
+		return -EFAULT;
+	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
+			sizeof(raw_data));
+
+	if (!resp)
+		return -EIO;
+
+	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+		/* check if written data matches */
+		if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
+			*off += raw_data[2];
+			ret = raw_data[2];
+		}
+	}
+	kfree(resp);
+	return ret;
+}
+
+/*
+ * Notes:
+ * - read/write happens in chunks of at most 20 bytes, it's up to userspace
+ *   to loop in order to get more data.
+ * - on write errors on otherwise correct write request the bytes
+ *   that should have been written are in undefined state.
+ */
+static const struct file_operations picolcd_debug_eeprom_fops = {
+	.owner    = THIS_MODULE,
+	.open     = simple_open,
+	.read     = picolcd_debug_eeprom_read,
+	.write    = picolcd_debug_eeprom_write,
+	.llseek   = generic_file_llseek,
+};
+
+/*
+ * The "flash" file
+ */
+/* record a flash address to buf (bounds check to be done by caller) */
+static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
+{
+	buf[0] = off & 0xff;
+	buf[1] = (off >> 8) & 0xff;
+	if (data->addr_sz == 3)
+		buf[2] = (off >> 16) & 0xff;
+	return data->addr_sz == 2 ? 2 : 3;
+}
+
+/* read a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
+		char __user *u, size_t s, loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[4];
+	ssize_t ret = 0;
+	int len_off, err = -EIO;
+
+	while (s > 0) {
+		err = -EIO;
+		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+		raw_data[len_off] = s > 32 ? 32 : s;
+		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
+		if (!resp || !resp->in_report)
+			goto skip;
+		if (resp->in_report->id == REPORT_MEMORY ||
+			resp->in_report->id == REPORT_BL_READ_MEMORY) {
+			if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
+				goto skip;
+			if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
+				err = -EFAULT;
+				goto skip;
+			}
+			*off += raw_data[len_off];
+			s    -= raw_data[len_off];
+			ret  += raw_data[len_off];
+			err   = 0;
+		}
+skip:
+		kfree(resp);
+		if (err)
+			return ret > 0 ? ret : err;
+	}
+	return ret;
+}
+
+static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x05fff)
+		return 0;
+	if (*off + s > 0x05fff)
+		s = 0x06000 - *off;
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
+	else
+		return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
+}
+
+/* erase block aligned to 64bytes boundary */
+static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
+		loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[3];
+	int len_off;
+	ssize_t ret = -EIO;
+
+	if (*off & 0x3f)
+		return -EINVAL;
+
+	len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+	resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
+	if (!resp || !resp->in_report)
+		goto skip;
+	if (resp->in_report->id == REPORT_MEMORY ||
+		resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
+		if (memcmp(raw_data, resp->raw_data, len_off) != 0)
+			goto skip;
+		ret = 0;
+	}
+skip:
+	kfree(resp);
+	return ret;
+}
+
+/* write a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
+		const char __user *u, size_t s, loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[36];
+	ssize_t ret = 0;
+	int len_off, err = -EIO;
+
+	while (s > 0) {
+		err = -EIO;
+		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+		raw_data[len_off] = s > 32 ? 32 : s;
+		if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
+			err = -EFAULT;
+			break;
+		}
+		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
+				len_off+1+raw_data[len_off]);
+		if (!resp || !resp->in_report)
+			goto skip;
+		if (resp->in_report->id == REPORT_MEMORY ||
+			resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
+			if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
+				goto skip;
+			*off += raw_data[len_off];
+			s    -= raw_data[len_off];
+			ret  += raw_data[len_off];
+			err   = 0;
+		}
+skip:
+		kfree(resp);
+		if (err)
+			break;
+	}
+	return ret > 0 ? ret : err;
+}
+
+static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	ssize_t err, ret = 0;
+	int report_erase, report_write;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x5fff)
+		return -ENOSPC;
+	if (s & 0x3f)
+		return -EINVAL;
+	if (*off & 0x3f)
+		return -EINVAL;
+
+	if (data->status & PICOLCD_BOOTLOADER) {
+		report_erase = REPORT_BL_ERASE_MEMORY;
+		report_write = REPORT_BL_WRITE_MEMORY;
+	} else {
+		report_erase = REPORT_ERASE_MEMORY;
+		report_write = REPORT_WRITE_MEMORY;
+	}
+	mutex_lock(&data->mutex_flash);
+	while (s > 0) {
+		err = _picolcd_flash_erase64(data, report_erase, off);
+		if (err)
+			break;
+		err = _picolcd_flash_write(data, report_write, u, 64, off);
+		if (err < 0)
+			break;
+		ret += err;
+		*off += err;
+		s -= err;
+		if (err != 64)
+			break;
+	}
+	mutex_unlock(&data->mutex_flash);
+	return ret > 0 ? ret : err;
+}
+
+/*
+ * Notes:
+ * - concurrent writing is prevented by mutex and all writes must be
+ *   n*64 bytes and 64-byte aligned, each write being preceded by an
+ *   ERASE which erases a 64byte block.
+ *   If less than requested was written or an error is returned for an
+ *   otherwise correct write request the next 64-byte block which should
+ *   have been written is in undefined state (mostly: original, erased,
+ *   (half-)written with write error)
+ * - reading can happen without special restriction
+ */
+static const struct file_operations picolcd_debug_flash_fops = {
+	.owner    = THIS_MODULE,
+	.open     = simple_open,
+	.read     = picolcd_debug_flash_read,
+	.write    = picolcd_debug_flash_write,
+	.llseek   = generic_file_llseek,
+};
+
+
+/*
+ * Helper code for HID report level dumping/debugging
+ */
+static const char * const error_codes[] = {
+	"success", "parameter missing", "data_missing", "block readonly",
+	"block not erasable", "block too big", "section overflow",
+	"invalid command length", "invalid data length",
+};
+
+static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
+		const size_t data_len)
+{
+	int i, j;
+	for (i = j = 0; i < data_len && j + 4 < dst_sz; i++) {
+		dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
+		dst[j++] = hex_asc[data[i] & 0x0f];
+		dst[j++] = ' ';
+	}
+	dst[j]   = '\0';
+	if (j > 0)
+		dst[j-1] = '\n';
+	if (i < data_len && j > 2)
+		dst[j-2] = dst[j-3] = '.';
+}
+
+void picolcd_debug_out_report(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report)
+{
+	u8 raw_data[70];
+	int raw_size = (report->size >> 3) + 1;
+	char *buff;
+#define BUFF_SZ 256
+
+	/* Avoid unnecessary overhead if debugfs is disabled */
+	if (list_empty(&hdev->debug_list))
+		return;
+
+	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+	if (!buff)
+		return;
+
+	snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+			report->id, raw_size);
+	hid_debug_event(hdev, buff);
+	if (raw_size + 5 > sizeof(raw_data)) {
+		kfree(buff);
+		hid_debug_event(hdev, " TOO BIG\n");
+		return;
+	} else {
+		raw_data[0] = report->id;
+		hid_output_report(report, raw_data);
+		dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+		hid_debug_event(hdev, buff);
+	}
+
+	switch (report->id) {
+	case REPORT_LED_STATE:
+		/* 1 data byte with GPO state */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LED_STATE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_BRIGHTNESS:
+		/* 1 data byte with brightness */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_BRIGHTNESS", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_CONTRAST:
+		/* 1 data byte with contrast */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_CONTRAST", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_RESET:
+		/* 2 data bytes with reset duration in ms */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_RESET", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
+				raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_LCD_CMD:
+		/* 63 data bytes with LCD commands */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO: format decoding */
+		break;
+	case REPORT_LCD_DATA:
+		/* 63 data bytes with LCD data */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		/* TODO: format decoding */
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_LCD_CMD_DATA:
+		/* 63 data bytes with LCD commands and data */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		/* TODO: format decoding */
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EE_READ:
+		/* 3 data bytes with read area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EE_READ", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EE_WRITE:
+		/* 3+1..20 data bytes with write area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EE_WRITE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		if (raw_data[3] == 0) {
+			snprintf(buff, BUFF_SZ, "\tNo data\n");
+		} else if (raw_data[3] + 4 <= raw_size) {
+			snprintf(buff, BUFF_SZ, "\tData: ");
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_ERASE_MEMORY:
+	case REPORT_BL_ERASE_MEMORY:
+		/* 3 data bytes with pointer inside erase block */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_ERASE_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_READ_MEMORY:
+	case REPORT_BL_READ_MEMORY:
+		/* 4 data bytes with read area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_READ_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_WRITE_MEMORY:
+	case REPORT_BL_WRITE_MEMORY:
+		/* 4+1..32 data bytes with write adrea description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_WRITE_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[3] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[3] + 4 <= raw_size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[4] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[4] + 5 <= raw_size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_RESTART:
+		/* TODO */
+		break;
+	case REPORT_EXIT_KEYBOARD:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+				raw_data[1] | (raw_data[2] << 8),
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_VERSION:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_DEVID:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_DEVID", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_SIZE:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_SPLASH_SIZE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_HOOK_VERSION:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_HOOK_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EXIT_FLASHER:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+				raw_data[1] | (raw_data[2] << 8),
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	default:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"<unknown>", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	}
+	wake_up_interruptible(&hdev->debug_wait);
+	kfree(buff);
+}
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+	char *buff;
+
+#define BUFF_SZ 256
+	/* Avoid unnecessary overhead if debugfs is disabled */
+	if (list_empty(&hdev->debug_list))
+		return;
+
+	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+	if (!buff)
+		return;
+
+	switch (report->id) {
+	case REPORT_ERROR_CODE:
+		/* 2 data bytes with affected report and error code */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_ERROR_CODE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[2] < ARRAY_SIZE(error_codes))
+			snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
+					raw_data[2], error_codes[raw_data[2]], raw_data[1]);
+		else
+			snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
+					raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_KEY_STATE:
+		/* 2 data bytes with key state */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_KEY_STATE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[1] == 0)
+			snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
+		else if (raw_data[2] == 0)
+			snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
+					raw_data[1], raw_data[1]);
+		else
+			snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
+					raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_IR_DATA:
+		/* Up to 20 byes of IR scancode data */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_IR_DATA", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[1] == 0) {
+			snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
+			hid_debug_event(hdev, buff);
+		} else if (raw_data[1] + 1 <= size) {
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
+					raw_data[1]);
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]);
+			hid_debug_event(hdev, buff);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
+					raw_data[1]-1);
+			hid_debug_event(hdev, buff);
+		}
+		break;
+	case REPORT_EE_DATA:
+		/* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_EE_DATA", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		if (raw_data[3] == 0) {
+			snprintf(buff, BUFF_SZ, "\tNo data\n");
+			hid_debug_event(hdev, buff);
+		} else if (raw_data[3] + 4 <= size) {
+			snprintf(buff, BUFF_SZ, "\tData: ");
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			hid_debug_event(hdev, buff);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			hid_debug_event(hdev, buff);
+		}
+		break;
+	case REPORT_MEMORY:
+		/* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[3] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[3] + 4 <= size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[4] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[4] + 5 <= size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_VERSION:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_BL_ERASE_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_ERASE_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_BL_READ_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_READ_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_BL_WRITE_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_WRITE_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_DEVID:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_DEVID", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
+				raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
+				raw_data[5]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_SIZE:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_SPLASH_SIZE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
+				(raw_data[2] << 8) | raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
+				(raw_data[4] << 8) | raw_data[3]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_HOOK_VERSION:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_HOOK_VERSION", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+				raw_data[1], raw_data[2]);
+		hid_debug_event(hdev, buff);
+		break;
+	default:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"<unknown>", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	}
+	wake_up_interruptible(&hdev->debug_wait);
+	kfree(buff);
+}
+
+void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset)
+{
+	struct hid_device *hdev = data->hdev;
+
+	mutex_init(&data->mutex_flash);
+
+	/* reset */
+	if (reset)
+		data->debug_reset = debugfs_create_file("reset", 0600,
+				hdev->debug_dir, data, &picolcd_debug_reset_fops);
+
+	/* eeprom */
+	if (eeprom_r || eeprom_w)
+		data->debug_eeprom = debugfs_create_file("eeprom",
+			(eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
+			hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
+
+	/* flash */
+	if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
+		data->addr_sz = flash_r->field[0]->report_count - 1;
+	else
+		data->addr_sz = -1;
+	if (data->addr_sz == 2 || data->addr_sz == 3) {
+		data->debug_flash = debugfs_create_file("flash",
+			(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
+			hdev->debug_dir, data, &picolcd_debug_flash_fops);
+	} else if (flash_r || flash_w)
+		hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
+}
+
+void picolcd_exit_devfs(struct picolcd_data *data)
+{
+	struct dentry *dent;
+
+	dent = data->debug_reset;
+	data->debug_reset = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	dent = data->debug_eeprom;
+	data->debug_eeprom = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	dent = data->debug_flash;
+	data->debug_flash = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	mutex_destroy(&data->mutex_flash);
+}
+
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c
new file mode 100644
index 0000000..0008a51
--- /dev/null
+++ b/drivers/hid/hid-picolcd_fb.c
@@ -0,0 +1,615 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/vmalloc.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+/* Framebuffer
+ *
+ * The PicoLCD use a Topway LCD module of 256x64 pixel
+ * This display area is tiled over 4 controllers with 8 tiles
+ * each. Each tile has 8x64 pixel, each data byte representing
+ * a 1-bit wide vertical line of the tile.
+ *
+ * The display can be updated at a tile granularity.
+ *
+ *       Chip 1           Chip 2           Chip 3           Chip 4
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
+ * +----------------+----------------+----------------+----------------+
+ *                                  ...
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
+ * +----------------+----------------+----------------+----------------+
+ */
+#define PICOLCDFB_NAME "picolcdfb"
+#define PICOLCDFB_WIDTH (256)
+#define PICOLCDFB_HEIGHT (64)
+#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
+
+#define PICOLCDFB_UPDATE_RATE_LIMIT   10
+#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
+
+/* Framebuffer visual structures */
+static const struct fb_fix_screeninfo picolcdfb_fix = {
+	.id          = PICOLCDFB_NAME,
+	.type        = FB_TYPE_PACKED_PIXELS,
+	.visual      = FB_VISUAL_MONO01,
+	.xpanstep    = 0,
+	.ypanstep    = 0,
+	.ywrapstep   = 0,
+	.line_length = PICOLCDFB_WIDTH / 8,
+	.accel       = FB_ACCEL_NONE,
+};
+
+static const struct fb_var_screeninfo picolcdfb_var = {
+	.xres           = PICOLCDFB_WIDTH,
+	.yres           = PICOLCDFB_HEIGHT,
+	.xres_virtual   = PICOLCDFB_WIDTH,
+	.yres_virtual   = PICOLCDFB_HEIGHT,
+	.width          = 103,
+	.height         = 26,
+	.bits_per_pixel = 1,
+	.grayscale      = 1,
+	.red            = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.green          = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.blue           = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.transp         = {
+		.offset = 0,
+		.length = 0,
+		.msb_right = 0,
+	},
+};
+
+/* Send a given tile to PicoLCD */
+static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
+		int chip, int tile)
+{
+	struct hid_report *report1, *report2;
+	unsigned long flags;
+	u8 *tdata;
+	int i;
+
+	report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, data->hdev);
+	if (!report1 || report1->maxfield != 1)
+		return -ENODEV;
+	report2 = picolcd_out_report(REPORT_LCD_DATA, data->hdev);
+	if (!report2 || report2->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if ((data->status & PICOLCD_FAILED)) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return -ENODEV;
+	}
+	hid_set_field(report1->field[0],  0, chip << 2);
+	hid_set_field(report1->field[0],  1, 0x02);
+	hid_set_field(report1->field[0],  2, 0x00);
+	hid_set_field(report1->field[0],  3, 0x00);
+	hid_set_field(report1->field[0],  4, 0xb8 | tile);
+	hid_set_field(report1->field[0],  5, 0x00);
+	hid_set_field(report1->field[0],  6, 0x00);
+	hid_set_field(report1->field[0],  7, 0x40);
+	hid_set_field(report1->field[0],  8, 0x00);
+	hid_set_field(report1->field[0],  9, 0x00);
+	hid_set_field(report1->field[0], 10,   32);
+
+	hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
+	hid_set_field(report2->field[0],  1, 0x00);
+	hid_set_field(report2->field[0],  2, 0x00);
+	hid_set_field(report2->field[0],  3,   32);
+
+	tdata = vbitmap + (tile * 4 + chip) * 64;
+	for (i = 0; i < 64; i++)
+		if (i < 32)
+			hid_set_field(report1->field[0], 11 + i, tdata[i]);
+		else
+			hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
+
+	usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
+	usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+/* Translate a single tile*/
+static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
+		int chip, int tile)
+{
+	int i, b, changed = 0;
+	u8 tdata[64];
+	u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
+
+	if (bpp == 1) {
+		for (b = 7; b >= 0; b--) {
+			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
+			for (i = 0; i < 64; i++) {
+				tdata[i] <<= 1;
+				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
+			}
+		}
+	} else if (bpp == 8) {
+		for (b = 7; b >= 0; b--) {
+			const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
+			for (i = 0; i < 64; i++) {
+				tdata[i] <<= 1;
+				tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
+			}
+		}
+	} else {
+		/* Oops, we should never get here! */
+		WARN_ON(1);
+		return 0;
+	}
+
+	for (i = 0; i < 64; i++)
+		if (tdata[i] != vdata[i]) {
+			changed = 1;
+			vdata[i] = tdata[i];
+		}
+	return changed;
+}
+
+void picolcd_fb_refresh(struct picolcd_data *data)
+{
+	if (data->fb_info)
+		schedule_delayed_work(&data->fb_info->deferred_work, 0);
+}
+
+/* Reconfigure LCD display */
+int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
+	struct picolcd_fb_data *fbdata = data->fb_info->par;
+	int i, j;
+	unsigned long flags;
+	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
+
+	if (!report || report->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < report->field[0]->maxusage; j++)
+			if (j == 0)
+				hid_set_field(report->field[0], j, i << 2);
+			else if (j < sizeof(mapcmd))
+				hid_set_field(report->field[0], j, mapcmd[j]);
+			else
+				hid_set_field(report->field[0], j, 0);
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	}
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	if (clear) {
+		memset(fbdata->vbitmap, 0, PICOLCDFB_SIZE);
+		memset(fbdata->bitmap, 0, PICOLCDFB_SIZE*fbdata->bpp);
+	}
+	fbdata->force = 1;
+
+	/* schedule first output of framebuffer */
+	if (fbdata->ready)
+		schedule_delayed_work(&data->fb_info->deferred_work, 0);
+	else
+		fbdata->ready = 1;
+
+	return 0;
+}
+
+/* Update fb_vbitmap from the screen_base and send changed tiles to device */
+static void picolcd_fb_update(struct fb_info *info)
+{
+	int chip, tile, n;
+	unsigned long flags;
+	struct picolcd_fb_data *fbdata = info->par;
+	struct picolcd_data *data;
+
+	mutex_lock(&info->lock);
+
+	spin_lock_irqsave(&fbdata->lock, flags);
+	if (!fbdata->ready && fbdata->picolcd)
+		picolcd_fb_reset(fbdata->picolcd, 0);
+	spin_unlock_irqrestore(&fbdata->lock, flags);
+
+	/*
+	 * Translate the framebuffer into the format needed by the PicoLCD.
+	 * See display layout above.
+	 * Do this one tile after the other and push those tiles that changed.
+	 *
+	 * Wait for our IO to complete as otherwise we might flood the queue!
+	 */
+	n = 0;
+	for (chip = 0; chip < 4; chip++)
+		for (tile = 0; tile < 8; tile++) {
+			if (!fbdata->force && !picolcd_fb_update_tile(
+					fbdata->vbitmap, fbdata->bitmap,
+					fbdata->bpp, chip, tile))
+				continue;
+			n += 2;
+			if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
+				spin_lock_irqsave(&fbdata->lock, flags);
+				data = fbdata->picolcd;
+				spin_unlock_irqrestore(&fbdata->lock, flags);
+				mutex_unlock(&info->lock);
+				if (!data)
+					return;
+				usbhid_wait_io(data->hdev);
+				mutex_lock(&info->lock);
+				n = 0;
+			}
+			spin_lock_irqsave(&fbdata->lock, flags);
+			data = fbdata->picolcd;
+			spin_unlock_irqrestore(&fbdata->lock, flags);
+			if (!data || picolcd_fb_send_tile(data,
+					fbdata->vbitmap, chip, tile))
+				goto out;
+		}
+	fbdata->force = false;
+	if (n) {
+		spin_lock_irqsave(&fbdata->lock, flags);
+		data = fbdata->picolcd;
+		spin_unlock_irqrestore(&fbdata->lock, flags);
+		mutex_unlock(&info->lock);
+		if (data)
+			usbhid_wait_io(data->hdev);
+		return;
+	}
+out:
+	mutex_unlock(&info->lock);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_fillrect(struct fb_info *info,
+		const struct fb_fillrect *rect)
+{
+	if (!info->par)
+		return;
+	sys_fillrect(info, rect);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_copyarea(struct fb_info *info,
+		const struct fb_copyarea *area)
+{
+	if (!info->par)
+		return;
+	sys_copyarea(info, area);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	if (!info->par)
+		return;
+	sys_imageblit(info, image);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	if (!info->par)
+		return -ENODEV;
+	ret = fb_sys_write(info, buf, count, ppos);
+	if (ret >= 0)
+		schedule_delayed_work(&info->deferred_work, 0);
+	return ret;
+}
+
+static int picolcd_fb_blank(int blank, struct fb_info *info)
+{
+	/* We let fb notification do this for us via lcd/backlight device */
+	return 0;
+}
+
+static void picolcd_fb_destroy(struct fb_info *info)
+{
+	struct picolcd_fb_data *fbdata = info->par;
+
+	/* make sure no work is deferred */
+	fb_deferred_io_cleanup(info);
+
+	/* No thridparty should ever unregister our framebuffer! */
+	WARN_ON(fbdata->picolcd != NULL);
+
+	vfree((u8 *)info->fix.smem_start);
+	framebuffer_release(info);
+}
+
+static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	__u32 bpp      = var->bits_per_pixel;
+	__u32 activate = var->activate;
+
+	/* only allow 1/8 bit depth (8-bit is grayscale) */
+	*var = picolcdfb_var;
+	var->activate = activate;
+	if (bpp >= 8) {
+		var->bits_per_pixel = 8;
+		var->red.length     = 8;
+		var->green.length   = 8;
+		var->blue.length    = 8;
+	} else {
+		var->bits_per_pixel = 1;
+		var->red.length     = 1;
+		var->green.length   = 1;
+		var->blue.length    = 1;
+	}
+	return 0;
+}
+
+static int picolcd_set_par(struct fb_info *info)
+{
+	struct picolcd_fb_data *fbdata = info->par;
+	u8 *tmp_fb, *o_fb;
+	if (info->var.bits_per_pixel == fbdata->bpp)
+		return 0;
+	/* switch between 1/8 bit depths */
+	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
+		return -EINVAL;
+
+	o_fb   = fbdata->bitmap;
+	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
+	if (!tmp_fb)
+		return -ENOMEM;
+
+	/* translate FB content to new bits-per-pixel */
+	if (info->var.bits_per_pixel == 1) {
+		int i, b;
+		for (i = 0; i < PICOLCDFB_SIZE; i++) {
+			u8 p = 0;
+			for (b = 0; b < 8; b++) {
+				p <<= 1;
+				p |= o_fb[i*8+b] ? 0x01 : 0x00;
+			}
+			tmp_fb[i] = p;
+		}
+		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
+		info->fix.visual = FB_VISUAL_MONO01;
+		info->fix.line_length = PICOLCDFB_WIDTH / 8;
+	} else {
+		int i;
+		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
+		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
+			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+		info->fix.line_length = PICOLCDFB_WIDTH;
+	}
+
+	kfree(tmp_fb);
+	fbdata->bpp = info->var.bits_per_pixel;
+	return 0;
+}
+
+/* Note this can't be const because of struct fb_info definition */
+static struct fb_ops picolcdfb_ops = {
+	.owner        = THIS_MODULE,
+	.fb_destroy   = picolcd_fb_destroy,
+	.fb_read      = fb_sys_read,
+	.fb_write     = picolcd_fb_write,
+	.fb_blank     = picolcd_fb_blank,
+	.fb_fillrect  = picolcd_fb_fillrect,
+	.fb_copyarea  = picolcd_fb_copyarea,
+	.fb_imageblit = picolcd_fb_imageblit,
+	.fb_check_var = picolcd_fb_check_var,
+	.fb_set_par   = picolcd_set_par,
+};
+
+
+/* Callback from deferred IO workqueue */
+static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+	picolcd_fb_update(info);
+}
+
+static const struct fb_deferred_io picolcd_fb_defio = {
+	.delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
+	.deferred_io = picolcd_fb_deferred_io,
+};
+
+
+/*
+ * The "fb_update_rate" sysfs attribute
+ */
+static ssize_t picolcd_fb_update_rate_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	struct picolcd_fb_data *fbdata = data->fb_info->par;
+	unsigned i, fb_update_rate = fbdata->update_rate;
+	size_t ret = 0;
+
+	for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
+		if (ret >= PAGE_SIZE)
+			break;
+		else if (i == fb_update_rate)
+			ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
+		else
+			ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
+	if (ret > 0)
+		buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
+	return ret;
+}
+
+static ssize_t picolcd_fb_update_rate_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	struct picolcd_fb_data *fbdata = data->fb_info->par;
+	int i;
+	unsigned u;
+
+	if (count < 1 || count > 10)
+		return -EINVAL;
+
+	i = sscanf(buf, "%u", &u);
+	if (i != 1)
+		return -EINVAL;
+
+	if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
+		return -ERANGE;
+	else if (u == 0)
+		u = PICOLCDFB_UPDATE_RATE_DEFAULT;
+
+	fbdata->update_rate = u;
+	data->fb_info->fbdefio->delay = HZ / fbdata->update_rate;
+	return count;
+}
+
+static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
+		picolcd_fb_update_rate_store);
+
+/* initialize Framebuffer device */
+int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+	struct device *dev = &data->hdev->dev;
+	struct fb_info *info = NULL;
+	struct picolcd_fb_data *fbdata = NULL;
+	int i, error = -ENOMEM;
+	u32 *palette;
+
+	/* The extra memory is:
+	 * - 256*u32 for pseudo_palette
+	 * - struct fb_deferred_io
+	 */
+	info = framebuffer_alloc(256 * sizeof(u32) +
+			sizeof(struct fb_deferred_io) +
+			sizeof(struct picolcd_fb_data) +
+			PICOLCDFB_SIZE, dev);
+	if (info == NULL) {
+		dev_err(dev, "failed to allocate a framebuffer\n");
+		goto err_nomem;
+	}
+
+	info->fbdefio = info->par;
+	*info->fbdefio = picolcd_fb_defio;
+	info->par += sizeof(struct fb_deferred_io);
+	palette = info->par;
+	info->par += 256 * sizeof(u32);
+	for (i = 0; i < 256; i++)
+		palette[i] = i > 0 && i < 16 ? 0xff : 0;
+	info->pseudo_palette = palette;
+	info->fbops = &picolcdfb_ops;
+	info->var = picolcdfb_var;
+	info->fix = picolcdfb_fix;
+	info->fix.smem_len   = PICOLCDFB_SIZE*8;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	fbdata = info->par;
+	spin_lock_init(&fbdata->lock);
+	fbdata->picolcd = data;
+	fbdata->update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
+	fbdata->bpp     = picolcdfb_var.bits_per_pixel;
+	fbdata->force   = 1;
+	fbdata->vbitmap = info->par + sizeof(struct picolcd_fb_data);
+	fbdata->bitmap  = vmalloc(PICOLCDFB_SIZE*8);
+	if (fbdata->bitmap == NULL) {
+		dev_err(dev, "can't get a free page for framebuffer\n");
+		goto err_nomem;
+	}
+	info->screen_base = (char __force __iomem *)fbdata->bitmap;
+	info->fix.smem_start = (unsigned long)fbdata->bitmap;
+	memset(fbdata->vbitmap, 0xff, PICOLCDFB_SIZE);
+	data->fb_info = info;
+
+	error = picolcd_fb_reset(data, 1);
+	if (error) {
+		dev_err(dev, "failed to configure display\n");
+		goto err_cleanup;
+	}
+
+	error = device_create_file(dev, &dev_attr_fb_update_rate);
+	if (error) {
+		dev_err(dev, "failed to create sysfs attributes\n");
+		goto err_cleanup;
+	}
+
+	fb_deferred_io_init(info);
+	error = register_framebuffer(info);
+	if (error) {
+		dev_err(dev, "failed to register framebuffer\n");
+		goto err_sysfs;
+	}
+	return 0;
+
+err_sysfs:
+	device_remove_file(dev, &dev_attr_fb_update_rate);
+	fb_deferred_io_cleanup(info);
+err_cleanup:
+	data->fb_info    = NULL;
+
+err_nomem:
+	if (fbdata)
+		vfree(fbdata->bitmap);
+	framebuffer_release(info);
+	return error;
+}
+
+void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+	struct fb_info *info = data->fb_info;
+	struct picolcd_fb_data *fbdata = info->par;
+	unsigned long flags;
+
+	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
+
+	/* disconnect framebuffer from HID dev */
+	spin_lock_irqsave(&fbdata->lock, flags);
+	fbdata->picolcd = NULL;
+	spin_unlock_irqrestore(&fbdata->lock, flags);
+
+	/* make sure there is no running update - thus that fbdata->picolcd
+	 * once obtained under lock is guaranteed not to get free() under
+	 * the feet of the deferred work */
+	flush_delayed_work_sync(&info->deferred_work);
+
+	data->fb_info = NULL;
+	unregister_framebuffer(info);
+}
diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c
new file mode 100644
index 0000000..2d0ddc5
--- /dev/null
+++ b/drivers/hid/hid-picolcd_lcd.c
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/lcd.h>
+
+#include "hid-picolcd.h"
+
+/*
+ * lcd class device
+ */
+static int picolcd_get_contrast(struct lcd_device *ldev)
+{
+	struct picolcd_data *data = lcd_get_data(ldev);
+	return data->lcd_contrast;
+}
+
+static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
+{
+	struct picolcd_data *data = lcd_get_data(ldev);
+	struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
+	unsigned long flags;
+
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return -ENODEV;
+
+	data->lcd_contrast = contrast & 0x0ff;
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->lcd_contrast);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
+{
+	return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
+}
+
+static struct lcd_ops picolcd_lcdops = {
+	.get_contrast   = picolcd_get_contrast,
+	.set_contrast   = picolcd_set_contrast,
+	.check_fb       = picolcd_check_lcd_fb,
+};
+
+int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct lcd_device *ldev;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported CONTRAST report");
+		return -EINVAL;
+	}
+
+	ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
+	if (IS_ERR(ldev)) {
+		dev_err(dev, "failed to register LCD\n");
+		return PTR_ERR(ldev);
+	}
+	ldev->props.max_contrast = 0x0ff;
+	data->lcd_contrast = 0xe5;
+	data->lcd = ldev;
+	picolcd_set_contrast(ldev, 0xe5);
+	return 0;
+}
+
+void picolcd_exit_lcd(struct picolcd_data *data)
+{
+	struct lcd_device *ldev = data->lcd;
+
+	data->lcd = NULL;
+	if (ldev)
+		lcd_device_unregister(ldev);
+}
+
+int picolcd_resume_lcd(struct picolcd_data *data)
+{
+	if (!data->lcd)
+		return 0;
+	return picolcd_set_contrast(data->lcd, data->lcd_contrast);
+}
+
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
new file mode 100644
index 0000000..28cb6a4
--- /dev/null
+++ b/drivers/hid/hid-picolcd_leds.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   This program is free software: you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+void picolcd_leds_set(struct picolcd_data *data)
+{
+	struct hid_report *report;
+	unsigned long flags;
+
+	if (!data->led[0])
+		return;
+	report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->led_state);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct picolcd_data *data;
+	int i, state = 0;
+
+	dev  = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data = hid_get_drvdata(hdev);
+	if (!data)
+		return;
+	for (i = 0; i < 8; i++) {
+		if (led_cdev != data->led[i])
+			continue;
+		state = (data->led_state >> i) & 1;
+		if (value == LED_OFF && state) {
+			data->led_state &= ~(1 << i);
+			picolcd_leds_set(data);
+		} else if (value != LED_OFF && !state) {
+			data->led_state |= 1 << i;
+			picolcd_leds_set(data);
+		}
+		break;
+	}
+}
+
+static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct picolcd_data *data;
+	int i, value = 0;
+
+	dev  = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data = hid_get_drvdata(hdev);
+	for (i = 0; i < 8; i++)
+		if (led_cdev == data->led[i]) {
+			value = (data->led_state >> i) & 1;
+			break;
+		}
+	return value ? LED_FULL : LED_OFF;
+}
+
+int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct led_classdev *led;
+	size_t name_sz = strlen(dev_name(dev)) + 8;
+	char *name;
+	int i, ret = 0;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported LED_STATE report");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 8; i++) {
+		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+		if (!led) {
+			dev_err(dev, "can't allocate memory for LED %d\n", i);
+			ret = -ENOMEM;
+			goto err;
+		}
+		name = (void *)(&led[1]);
+		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
+		led->name = name;
+		led->brightness = 0;
+		led->max_brightness = 1;
+		led->brightness_get = picolcd_led_get_brightness;
+		led->brightness_set = picolcd_led_set_brightness;
+
+		data->led[i] = led;
+		ret = led_classdev_register(dev, data->led[i]);
+		if (ret) {
+			data->led[i] = NULL;
+			kfree(led);
+			dev_err(dev, "can't register LED %d\n", i);
+			goto err;
+		}
+	}
+	return 0;
+err:
+	for (i = 0; i < 8; i++)
+		if (data->led[i]) {
+			led = data->led[i];
+			data->led[i] = NULL;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+	return ret;
+}
+
+void picolcd_exit_leds(struct picolcd_data *data)
+{
+	struct led_classdev *led;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		led = data->led[i];
+		data->led[i] = NULL;
+		if (!led)
+			continue;
+		led_classdev_unregister(led);
+		kfree(led);
+	}
+}
+
+
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c
index 4d3c60d..c15adb0 100644
--- a/drivers/hid/hid-primax.c
+++ b/drivers/hid/hid-primax.c
@@ -64,29 +64,6 @@
 	return 0;
 }
 
-static int px_probe(struct hid_device *hid, const struct hid_device_id *id)
-{
-	int ret;
-
-	ret = hid_parse(hid);
-	if (ret) {
-		hid_err(hid, "parse failed\n");
-		goto fail;
-	}
-
-	ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
-	if (ret)
-		hid_err(hid, "hw start failed\n");
-
-fail:
-	return ret;
-}
-
-static void px_remove(struct hid_device *hid)
-{
-	hid_hw_stop(hid);
-}
-
 static const struct hid_device_id px_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
 	{ }
@@ -97,8 +74,6 @@
 	.name = "primax",
 	.id_table = px_devices,
 	.raw_event = px_raw_event,
-	.probe = px_probe,
-	.remove = px_remove,
 };
 
 static int __init px_init(void)
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index b71b77a..ec8ca33 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -105,7 +105,7 @@
 	struct device_attribute *attr, char *buf)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
 
@@ -118,7 +118,7 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	unsigned channel = 0;
 
@@ -142,7 +142,7 @@
  struct device_attribute *attr, char *buf)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
 
@@ -155,7 +155,7 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	unsigned sustain = 0;
 
@@ -181,7 +181,7 @@
 	struct device_attribute *attr, char *buf)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
 
@@ -194,7 +194,7 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 
 	int octave = 0;
 
@@ -759,7 +759,7 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 	struct pcmidi_snd *pm;
 
 	pm = pk->pm;
@@ -777,7 +777,7 @@
 static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,
 	u8 *data, int size)
 {
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 	int ret = 0;
 
 	if (1 == pk->pm->ifnum) {
@@ -858,7 +858,7 @@
 
 static void pk_remove(struct hid_device *hdev)
 {
-	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
+	struct pk_device *pk = hid_get_drvdata(hdev);
 	struct pcmidi_snd *pm;
 
 	pm = pk->pm;
diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c
new file mode 100644
index 0000000..03811e53
--- /dev/null
+++ b/drivers/hid/hid-ps3remote.c
@@ -0,0 +1,215 @@
+/*
+ * HID driver for Sony PS3 BD Remote Control
+ *
+ * Copyright (c) 2012 David Dillow <dave@thedillows.org>
+ * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
+ * and other kernel HID drivers.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
+ * a Bluetooth host, the key combination Start+Enter has to be kept pressed
+ * for about 7 seconds with the Bluetooth Host Controller in discovering mode.
+ *
+ * There will be no PIN request from the device.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 ps3remote_rdesc[] = {
+	0x05, 0x01,          /* GUsagePage Generic Desktop */
+	0x09, 0x05,          /* LUsage 0x05 [Game Pad] */
+	0xA1, 0x01,          /* MCollection Application (mouse, keyboard) */
+
+	 /* Use collection 1 for joypad buttons */
+	 0xA1, 0x02,         /* MCollection Logical (interrelated data) */
+
+	  /* Ignore the 1st byte, maybe it is used for a controller
+	   * number but it's not needed for correct operation */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+	  /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
+	   * buttons multiple keypresses are allowed */
+	  0x05, 0x09,        /* GUsagePage Button */
+	  0x19, 0x01,        /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
+	  0x29, 0x18,        /* LUsageMaximum 0x18 [Button 24] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x25, 0x01,        /* GLogicalMaximum 0x01 [1] */
+	  0x75, 0x01,        /* GReportSize 0x01 [1] */
+	  0x95, 0x18,        /* GReportCount 0x18 [24] */
+	  0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+	  0xC0,              /* MEndCollection */
+
+	 /* Use collection 2 for remote control buttons */
+	 0xA1, 0x02,         /* MCollection Logical (interrelated data) */
+
+	  /* 5th byte is used for remote control buttons */
+	  0x05, 0x09,        /* GUsagePage Button */
+	  0x18,              /* LUsageMinimum [No button pressed] */
+	  0x29, 0xFE,        /* LUsageMaximum 0xFE [Button 254] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x26, 0xFE, 0x00,  /* GLogicalMaximum 0x00FE [254] */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x80,              /* MInput  */
+
+	  /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
+	   * 0xff and 11th is for press indication */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x06,        /* GReportCount 0x06 [6] */
+	  0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+	  /* 12th byte is for battery strength */
+	  0x05, 0x06,        /* GUsagePage Generic Device Controls */
+	  0x09, 0x20,        /* LUsage 0x20 [Battery Strength] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x25, 0x05,        /* GLogicalMaximum 0x05 [5] */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+	  0xC0,              /* MEndCollection */
+
+	 0xC0                /* MEndCollection [Game Pad] */
+};
+
+static const unsigned int ps3remote_keymap_joypad_buttons[] = {
+	[0x01] = KEY_SELECT,
+	[0x02] = BTN_THUMBL,		/* L3 */
+	[0x03] = BTN_THUMBR,		/* R3 */
+	[0x04] = BTN_START,
+	[0x05] = KEY_UP,
+	[0x06] = KEY_RIGHT,
+	[0x07] = KEY_DOWN,
+	[0x08] = KEY_LEFT,
+	[0x09] = BTN_TL2,		/* L2 */
+	[0x0a] = BTN_TR2,		/* R2 */
+	[0x0b] = BTN_TL,		/* L1 */
+	[0x0c] = BTN_TR,		/* R1 */
+	[0x0d] = KEY_OPTION,		/* options/triangle */
+	[0x0e] = KEY_BACK,		/* back/circle */
+	[0x0f] = BTN_0,			/* cross */
+	[0x10] = KEY_SCREEN,		/* view/square */
+	[0x11] = KEY_HOMEPAGE,		/* PS button */
+	[0x14] = KEY_ENTER,
+};
+static const unsigned int ps3remote_keymap_remote_buttons[] = {
+	[0x00] = KEY_1,
+	[0x01] = KEY_2,
+	[0x02] = KEY_3,
+	[0x03] = KEY_4,
+	[0x04] = KEY_5,
+	[0x05] = KEY_6,
+	[0x06] = KEY_7,
+	[0x07] = KEY_8,
+	[0x08] = KEY_9,
+	[0x09] = KEY_0,
+	[0x0e] = KEY_ESC,		/* return */
+	[0x0f] = KEY_CLEAR,
+	[0x16] = KEY_EJECTCD,
+	[0x1a] = KEY_MENU,		/* top menu */
+	[0x28] = KEY_TIME,
+	[0x30] = KEY_PREVIOUS,
+	[0x31] = KEY_NEXT,
+	[0x32] = KEY_PLAY,
+	[0x33] = KEY_REWIND,		/* scan back */
+	[0x34] = KEY_FORWARD,		/* scan forward */
+	[0x38] = KEY_STOP,
+	[0x39] = KEY_PAUSE,
+	[0x40] = KEY_CONTEXT_MENU,	/* pop up/menu */
+	[0x60] = KEY_FRAMEBACK,		/* slow/step back */
+	[0x61] = KEY_FRAMEFORWARD,	/* slow/step forward */
+	[0x63] = KEY_SUBTITLE,
+	[0x64] = KEY_AUDIO,
+	[0x65] = KEY_ANGLE,
+	[0x70] = KEY_INFO,		/* display */
+	[0x80] = KEY_BLUE,
+	[0x81] = KEY_RED,
+	[0x82] = KEY_GREEN,
+	[0x83] = KEY_YELLOW,
+};
+
+static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
+			     unsigned int *rsize)
+{
+	*rsize = sizeof(ps3remote_rdesc);
+	return ps3remote_rdesc;
+}
+
+static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
+			     struct hid_field *field, struct hid_usage *usage,
+			     unsigned long **bit, int *max)
+{
+	unsigned int key = usage->hid & HID_USAGE;
+
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+		return -1;
+
+	switch (usage->collection_index) {
+	case 1:
+		if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons))
+			return -1;
+
+		key = ps3remote_keymap_joypad_buttons[key];
+		if (!key)
+			return -1;
+		break;
+	case 2:
+		if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
+			return -1;
+
+		key = ps3remote_keymap_remote_buttons[key];
+		if (!key)
+			return -1;
+		break;
+	default:
+		return -1;
+	}
+
+	hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
+	return 1;
+}
+
+static const struct hid_device_id ps3remote_devices[] = {
+	/* PS3 BD Remote Control */
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
+	/* Logitech Harmony Adapter for PS3 */
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ps3remote_devices);
+
+static struct hid_driver ps3remote_driver = {
+	.name          = "ps3_remote",
+	.id_table      = ps3remote_devices,
+	.report_fixup  = ps3remote_fixup,
+	.input_mapping = ps3remote_mapping,
+};
+
+static int __init ps3remote_init(void)
+{
+	return hid_register_driver(&ps3remote_driver);
+}
+
+static void __exit ps3remote_exit(void)
+{
+	hid_unregister_driver(&ps3remote_driver);
+}
+
+module_init(ps3remote_init);
+module_exit(ps3remote_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 3c1fd8a..a5821d3 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
  *
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
new file mode 100644
index 0000000..d9d73e9
--- /dev/null
+++ b/drivers/hid/hid-sensor-hub.c
@@ -0,0 +1,680 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/list.h>
+#include <linux/hid-sensor-ids.h>
+#include <linux/hid-sensor-hub.h>
+#include "hid-ids.h"
+
+/**
+ * struct sensor_hub_pending - Synchronous read pending information
+ * @status:		Pending status true/false.
+ * @ready:		Completion synchronization data.
+ * @usage_id:		Usage id for physical device, E.g. Gyro usage id.
+ * @attr_usage_id:	Usage Id of a field, E.g. X-AXIS for a gyro.
+ * @raw_size:		Response size for a read request.
+ * @raw_data:		Place holder for received response.
+ */
+struct sensor_hub_pending {
+	bool status;
+	struct completion ready;
+	u32 usage_id;
+	u32 attr_usage_id;
+	int raw_size;
+	u8  *raw_data;
+};
+
+/**
+ * struct sensor_hub_data - Hold a instance data for a HID hub device
+ * @hsdev:		Stored hid instance for current hub device.
+ * @mutex:		Mutex to serialize synchronous request.
+ * @lock:		Spin lock to protect pending request structure.
+ * @pending:		Holds information of pending sync read request.
+ * @dyn_callback_list:	Holds callback function
+ * @dyn_callback_lock:	spin lock to protect callback list
+ * @hid_sensor_hub_client_devs:	Stores all MFD cells for a hub instance.
+ * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached).
+ */
+struct sensor_hub_data {
+	struct hid_sensor_hub_device *hsdev;
+	struct mutex mutex;
+	spinlock_t lock;
+	struct sensor_hub_pending pending;
+	struct list_head dyn_callback_list;
+	spinlock_t dyn_callback_lock;
+	struct mfd_cell *hid_sensor_hub_client_devs;
+	int hid_sensor_client_cnt;
+};
+
+/**
+ * struct hid_sensor_hub_callbacks_list - Stores callback list
+ * @list:		list head.
+ * @usage_id:		usage id for a physical device.
+ * @usage_callback:	Stores registered callback functions.
+ * @priv:		Private data for a physical device.
+ */
+struct hid_sensor_hub_callbacks_list {
+	struct list_head list;
+	u32 usage_id;
+	struct hid_sensor_hub_callbacks *usage_callback;
+	void *priv;
+};
+
+static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
+{
+	int i;
+	int ret = -EINVAL;
+
+	for (i = 0; i < hdev->maxcollection; i++) {
+		struct hid_collection *col = &hdev->collection[i];
+		if (col->type == HID_COLLECTION_PHYSICAL &&
+		   (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
+						int dir)
+{
+	struct hid_report *report;
+
+	list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) {
+		if (report->id == id)
+			return report;
+	}
+	hid_warn(hdev, "No report with id 0x%x found\n", id);
+
+	return NULL;
+}
+
+static int sensor_hub_get_physical_device_count(
+				struct hid_report_enum *report_enum)
+{
+	struct hid_report *report;
+	struct hid_field *field;
+	int cnt = 0;
+
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		field = report->field[0];
+		if (report->maxfield && field &&
+					field->physical)
+			cnt++;
+	}
+
+	return cnt;
+}
+
+static void sensor_hub_fill_attr_info(
+		struct hid_sensor_hub_attribute_info *info,
+		s32 index, s32 report_id, s32 units, s32 unit_expo, s32 size)
+{
+	info->index = index;
+	info->report_id = report_id;
+	info->units = units;
+	info->unit_expo = unit_expo;
+	info->size = size/8;
+}
+
+static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
+					struct hid_device *hdev,
+					u32 usage_id, void **priv)
+{
+	struct hid_sensor_hub_callbacks_list *callback;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+
+	spin_lock(&pdata->dyn_callback_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			*priv = callback->priv;
+			spin_unlock(&pdata->dyn_callback_lock);
+			return callback->usage_callback;
+		}
+	spin_unlock(&pdata->dyn_callback_lock);
+
+	return NULL;
+}
+
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback)
+{
+	struct hid_sensor_hub_callbacks_list *callback;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_callback_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			spin_unlock(&pdata->dyn_callback_lock);
+			return -EINVAL;
+		}
+	callback = kzalloc(sizeof(*callback), GFP_ATOMIC);
+	if (!callback) {
+		spin_unlock(&pdata->dyn_callback_lock);
+		return -ENOMEM;
+	}
+	callback->usage_callback = usage_callback;
+	callback->usage_id = usage_id;
+	callback->priv = NULL;
+	list_add_tail(&callback->list, &pdata->dyn_callback_list);
+	spin_unlock(&pdata->dyn_callback_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
+
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+				u32 usage_id)
+{
+	struct hid_sensor_hub_callbacks_list *callback;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_callback_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			list_del(&callback->list);
+			kfree(callback);
+			break;
+		}
+	spin_unlock(&pdata->dyn_callback_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
+
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
+	if (!report || (field_index >=  report->maxfield)) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	hid_set_field(report->field[field_index], 0, value);
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
+	usbhid_wait_io(hsdev->hdev);
+
+done_proc:
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
+
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 *value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
+	if (!report || (field_index >=  report->maxfield)) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hsdev->hdev);
+	*value = report->field[field_index]->value[0];
+
+done_proc:
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
+
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					u32 attr_usage_id, u32 report_id)
+{
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	unsigned long flags;
+	struct hid_report *report;
+	int ret_val = 0;
+
+	mutex_lock(&data->mutex);
+	memset(&data->pending, 0, sizeof(data->pending));
+	init_completion(&data->pending.ready);
+	data->pending.usage_id = usage_id;
+	data->pending.attr_usage_id = attr_usage_id;
+	data->pending.raw_size = 0;
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->pending.status = true;
+	report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
+	if (!report) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		goto err_free;
+	}
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	spin_unlock_irqrestore(&data->lock, flags);
+	wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
+	switch (data->pending.raw_size) {
+	case 1:
+		ret_val = *(u8 *)data->pending.raw_data;
+		break;
+	case 2:
+		ret_val = *(u16 *)data->pending.raw_data;
+		break;
+	case 4:
+		ret_val = *(u32 *)data->pending.raw_data;
+		break;
+	default:
+		ret_val = 0;
+	}
+	kfree(data->pending.raw_data);
+
+err_free:
+	data->pending.status = false;
+	mutex_unlock(&data->mutex);
+
+	return ret_val;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
+
+int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
+				u8 type,
+				u32 usage_id,
+				u32 attr_usage_id,
+				struct hid_sensor_hub_attribute_info *info)
+{
+	int ret = -1;
+	int i, j;
+	int collection_index = -1;
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_report_enum *report_enum;
+	struct hid_device *hdev = hsdev->hdev;
+
+	/* Initialize with defaults */
+	info->usage_id = usage_id;
+	info->attrib_id =  attr_usage_id;
+	info->report_id = -1;
+	info->index = -1;
+	info->units = -1;
+	info->unit_expo = -1;
+
+	for (i = 0; i < hdev->maxcollection; ++i) {
+		struct hid_collection *collection = &hdev->collection[i];
+		if (usage_id == collection->usage) {
+			collection_index = i;
+			break;
+		}
+	}
+	if (collection_index == -1)
+		goto err_ret;
+
+	report_enum = &hdev->report_enum[type];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		for (i = 0; i < report->maxfield; ++i) {
+			field = report->field[i];
+			if (field->physical == usage_id &&
+				field->logical == attr_usage_id) {
+				sensor_hub_fill_attr_info(info, i, report->id,
+					field->unit, field->unit_exponent,
+					field->report_size);
+				ret = 0;
+			} else {
+				for (j = 0; j < field->maxusage; ++j) {
+					if (field->usage[j].hid ==
+					attr_usage_id &&
+					field->usage[j].collection_index ==
+					collection_index)  {
+						sensor_hub_fill_attr_info(info,
+							i, report->id,
+							field->unit,
+							field->unit_exponent,
+							field->report_size);
+						ret = 0;
+						break;
+					}
+				}
+			}
+			if (ret == 0)
+				break;
+		}
+	}
+
+err_ret:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
+
+#ifdef CONFIG_PM
+static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_suspend\n");
+	spin_lock(&pdata->dyn_callback_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->usage_callback->suspend)
+			callback->usage_callback->suspend(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_callback_lock);
+
+	return 0;
+}
+
+static int sensor_hub_resume(struct hid_device *hdev)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_resume\n");
+	spin_lock(&pdata->dyn_callback_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->usage_callback->resume)
+			callback->usage_callback->resume(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_callback_lock);
+
+	return 0;
+}
+
+static int sensor_hub_reset_resume(struct hid_device *hdev)
+{
+	return 0;
+}
+#endif
+/*
+ * Handle raw report as sent by device
+ */
+static int sensor_hub_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	int i;
+	u8 *ptr;
+	int sz;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+	unsigned long flags;
+	struct hid_sensor_hub_callbacks *callback = NULL;
+	struct hid_collection *collection = NULL;
+	void *priv = NULL;
+
+	hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
+			 report->id, size, report->type);
+	hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
+	if (report->type != HID_INPUT_REPORT)
+		return 1;
+
+	ptr = raw_data;
+	ptr++; /*Skip report id*/
+
+	if (!report)
+		goto err_report;
+
+	spin_lock_irqsave(&pdata->lock, flags);
+
+	for (i = 0; i < report->maxfield; ++i) {
+
+		hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
+				i, report->field[i]->usage->collection_index,
+				report->field[i]->usage->hid,
+				report->field[i]->report_size/8);
+
+		sz = report->field[i]->report_size/8;
+		if (pdata->pending.status && pdata->pending.attr_usage_id ==
+				report->field[i]->usage->hid) {
+			hid_dbg(hdev, "data was pending ...\n");
+			pdata->pending.raw_data = kmalloc(sz, GFP_ATOMIC);
+			if (pdata->pending.raw_data) {
+				memcpy(pdata->pending.raw_data, ptr, sz);
+				pdata->pending.raw_size  = sz;
+			} else
+				pdata->pending.raw_size = 0;
+			complete(&pdata->pending.ready);
+		}
+		collection = &hdev->collection[
+				report->field[i]->usage->collection_index];
+		hid_dbg(hdev, "collection->usage %x\n",
+					collection->usage);
+		callback = sensor_hub_get_callback(pdata->hsdev->hdev,
+						report->field[i]->physical,
+							&priv);
+		if (callback && callback->capture_sample) {
+			if (report->field[i]->logical)
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->logical, sz, ptr,
+					callback->pdev);
+			else
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->usage->hid, sz, ptr,
+					callback->pdev);
+		}
+		ptr += sz;
+	}
+	if (callback && collection && callback->send_event)
+		callback->send_event(pdata->hsdev, collection->usage,
+				callback->pdev);
+	spin_unlock_irqrestore(&pdata->lock, flags);
+
+err_report:
+	return 1;
+}
+
+static int sensor_hub_probe(struct hid_device *hdev,
+				const struct hid_device_id *id)
+{
+	int ret;
+	struct sensor_hub_data *sd;
+	int i;
+	char *name;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct hid_field *field;
+	int dev_cnt;
+
+	sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
+	if (!sd) {
+		hid_err(hdev, "cannot allocate Sensor data\n");
+		return -ENOMEM;
+	}
+	sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
+	if (!sd->hsdev) {
+		hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
+		ret = -ENOMEM;
+		goto err_free_hub;
+	}
+	hid_set_drvdata(hdev, sd);
+	sd->hsdev->hdev = hdev;
+	sd->hsdev->vendor_id = hdev->vendor;
+	sd->hsdev->product_id = hdev->product;
+	spin_lock_init(&sd->lock);
+	spin_lock_init(&sd->dyn_callback_lock);
+	mutex_init(&sd->mutex);
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+	if (sensor_hub_check_for_sensor_page(hdev) < 0) {
+		hid_err(hdev, "sensor page not found\n");
+		goto err_free;
+	}
+	INIT_LIST_HEAD(&hdev->inputs);
+
+	ret = hid_hw_start(hdev, 0);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+	ret = hid_hw_open(hdev);
+	if (ret) {
+		hid_err(hdev, "failed to open input interrupt pipe\n");
+		goto err_stop_hw;
+	}
+
+	INIT_LIST_HEAD(&sd->dyn_callback_list);
+	sd->hid_sensor_client_cnt = 0;
+	report_enum = &hdev->report_enum[HID_INPUT_REPORT];
+
+	dev_cnt = sensor_hub_get_physical_device_count(report_enum);
+	if (dev_cnt > HID_MAX_PHY_DEVICES) {
+		hid_err(hdev, "Invalid Physical device count\n");
+		ret = -EINVAL;
+		goto err_close;
+	}
+	sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
+						sizeof(struct mfd_cell),
+						GFP_KERNEL);
+	if (sd->hid_sensor_hub_client_devs == NULL) {
+		hid_err(hdev, "Failed to allocate memory for mfd cells\n");
+			ret = -ENOMEM;
+			goto err_close;
+	}
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		hid_dbg(hdev, "Report id:%x\n", report->id);
+		field = report->field[0];
+		if (report->maxfield && field &&
+					field->physical) {
+			name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
+						field->physical);
+			if (name  == NULL) {
+				hid_err(hdev, "Failed MFD device name\n");
+					ret = -ENOMEM;
+					goto err_free_names;
+			}
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].name = name;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].platform_data =
+						sd->hsdev;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].pdata_size =
+						sizeof(*sd->hsdev);
+			hid_dbg(hdev, "Adding %s:%p\n", name, sd);
+			sd->hid_sensor_client_cnt++;
+		}
+	}
+	ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
+		sd->hid_sensor_client_cnt, NULL, 0, NULL);
+	if (ret < 0)
+		goto err_free_names;
+
+	return ret;
+
+err_free_names:
+	for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
+		kfree(sd->hid_sensor_hub_client_devs[i].name);
+	kfree(sd->hid_sensor_hub_client_devs);
+err_close:
+	hid_hw_close(hdev);
+err_stop_hw:
+	hid_hw_stop(hdev);
+err_free:
+	kfree(sd->hsdev);
+err_free_hub:
+	kfree(sd);
+
+	return ret;
+}
+
+static void sensor_hub_remove(struct hid_device *hdev)
+{
+	struct sensor_hub_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+	int i;
+
+	hid_dbg(hdev, " hardware removed\n");
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->pending.status)
+		complete(&data->pending.ready);
+	spin_unlock_irqrestore(&data->lock, flags);
+	mfd_remove_devices(&hdev->dev);
+	for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
+		kfree(data->hid_sensor_hub_client_devs[i].name);
+	kfree(data->hid_sensor_hub_client_devs);
+	hid_set_drvdata(hdev, NULL);
+	mutex_destroy(&data->mutex);
+	kfree(data->hsdev);
+	kfree(data);
+}
+
+static const struct hid_device_id sensor_hub_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+			USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+			USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+			USB_DEVICE_ID_SENSOR_HUB_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+			USB_DEVICE_ID_SENSOR_HUB_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+			USB_DEVICE_ID_SENSOR_HUB_7014) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, sensor_hub_devices);
+
+static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
+	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
+};
+
+static struct hid_driver sensor_hub_driver = {
+	.name = "hid-sensor-hub",
+	.id_table = sensor_hub_devices,
+	.probe = sensor_hub_probe,
+	.remove = sensor_hub_remove,
+	.raw_event = sensor_hub_raw_event,
+#ifdef CONFIG_PM
+	.suspend = sensor_hub_suspend,
+	.resume =  sensor_hub_resume,
+	.reset_resume =  sensor_hub_reset_resume,
+#endif
+};
+
+static int __init sensor_hub_init(void)
+{
+	return hid_register_driver(&sensor_hub_driver);
+}
+
+static void __exit sensor_hub_exit(void)
+{
+	hid_unregister_driver(&sensor_hub_driver);
+}
+
+module_init(sensor_hub_init);
+module_exit(sensor_hub_exit);
+
+MODULE_DESCRIPTION("HID Sensor Hub driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 5cd25bd..7f33ebf 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -4,7 +4,6 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2006-2008 Jiri Kosina
  */
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index d484a00..45b4b06 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
  */
 
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 3aba02b..2e56a1f 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -466,6 +466,86 @@
 	0xC0                /*  End Collection                      */
 };
 
+/*
+ * See TWHA60 description, device and HID report descriptors at
+ * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
+ */
+
+/* Size of the original descriptors of TWHA60 tablet */
+#define TWHA60_RDESC_ORIG_SIZE0 254
+#define TWHA60_RDESC_ORIG_SIZE1 139
+
+/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
+static __u8 twha60_rdesc_fixed0[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x04,         /*          Report Count (4),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
+	0x27, 0x3F, 0x9C,
+		0x00, 0x00, /*          Logical Maximum (39999),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
+	0x26, 0xA7, 0x61,   /*          Logical Maximum (24999),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
+static __u8 twha60_rdesc_fixed1[] = {
+	0x05, 0x01, /*  Usage Page (Desktop),       */
+	0x09, 0x06, /*  Usage (Keyboard),           */
+	0xA1, 0x01, /*  Collection (Application),   */
+	0x85, 0x05, /*      Report ID (5),          */
+	0x05, 0x07, /*      Usage Page (Keyboard),  */
+	0x14,       /*      Logical Minimum (0),    */
+	0x25, 0x01, /*      Logical Maximum (1),    */
+	0x75, 0x01, /*      Report Size (1),        */
+	0x95, 0x08, /*      Report Count (8),       */
+	0x81, 0x01, /*      Input (Constant),       */
+	0x95, 0x0C, /*      Report Count (12),      */
+	0x19, 0x3A, /*      Usage Minimum (KB F1),  */
+	0x29, 0x45, /*      Usage Maximum (KB F12), */
+	0x81, 0x02, /*      Input (Variable),       */
+	0x95, 0x0C, /*      Report Count (12),      */
+	0x19, 0x68, /*      Usage Minimum (KB F13), */
+	0x29, 0x73, /*      Usage Maximum (KB F24), */
+	0x81, 0x02, /*      Input (Variable),       */
+	0x95, 0x08, /*      Report Count (8),       */
+	0x81, 0x01, /*      Input (Constant),       */
+	0xC0        /*  End Collection              */
+};
+
 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 					unsigned int *rsize)
 {
@@ -525,6 +605,22 @@
 			break;
 		}
 		break;
+	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
+		switch (iface_num) {
+		case 0:
+			if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
+				rdesc = twha60_rdesc_fixed0;
+				*rsize = sizeof(twha60_rdesc_fixed0);
+			}
+			break;
+		case 1:
+			if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
+				rdesc = twha60_rdesc_fixed1;
+				*rsize = sizeof(twha60_rdesc_fixed1);
+			}
+			break;
+		}
+		break;
 	}
 
 	return rdesc;
@@ -543,6 +639,8 @@
 				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index fe23a1e..2f60da9 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -5,7 +5,6 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
  *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
  *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
@@ -33,6 +32,8 @@
 #define PAD_DEVICE_ID	0x0F
 
 #define WAC_CMD_LED_CONTROL     0x20
+#define WAC_CMD_ICON_START_STOP     0x21
+#define WAC_CMD_ICON_TRANSFER       0x26
 
 struct wacom_data {
 	__u16 tool;
@@ -69,6 +70,91 @@
 	POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_scramble(__u8 *image)
+{
+	__u16 mask;
+	__u16 s1;
+	__u16 s2;
+	__u16 r1 ;
+	__u16 r2 ;
+	__u16 r;
+	__u8 buf[256];
+	int i, w, x, y, z;
+
+	for (x = 0; x < 32; x++) {
+		for (y = 0; y < 8; y++)
+			buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
+	}
+
+	/* Change 76543210 into GECA6420 as required by Intuos4 WL
+	 *        HGFEDCBA      HFDB7531
+	 */
+	for (x = 0; x < 4; x++) {
+		for (y = 0; y < 4; y++) {
+			for (z = 0; z < 8; z++) {
+				mask = 0x0001;
+				r1 = 0;
+				r2 = 0;
+				i = (x << 6) + (y << 4) + z;
+				s1 = buf[i];
+				s2 = buf[i+8];
+				for (w = 0; w < 8; w++) {
+					r1 |= (s1 & mask);
+					r2 |= (s2 & mask);
+					s1 <<= 1;
+					s2 <<= 1;
+					mask <<= 2;
+				}
+				r = r1 | (r2 << 1);
+				i = (x << 6) + (y << 4) + (z << 1);
+				image[i] = 0xFF & r;
+				image[i+1] = (0xFF00 & r) >> 8;
+			}
+		}
+	}
+}
+
+static void wacom_set_image(struct hid_device *hdev, const char *image,
+						__u8 icon_no)
+{
+	__u8 rep_data[68];
+	__u8 p[256];
+	int ret, i, j;
+
+	for (i = 0; i < 256; i++)
+		p[i] = image[i];
+
+	rep_data[0] = WAC_CMD_ICON_START_STOP;
+	rep_data[1] = 0;
+	ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+				HID_FEATURE_REPORT);
+	if (ret < 0)
+		goto err;
+
+	rep_data[0] = WAC_CMD_ICON_TRANSFER;
+	rep_data[1] = icon_no & 0x07;
+
+	wacom_scramble(p);
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 64; j++)
+			rep_data[j + 3] = p[(i << 6) + j];
+
+		rep_data[2] = i;
+		ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
+					HID_FEATURE_REPORT);
+	}
+
+	rep_data[0] = WAC_CMD_ICON_START_STOP;
+	rep_data[1] = 0;
+
+	ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+				HID_FEATURE_REPORT);
+
+err:
+	return;
+}
+
 static void wacom_leds_set_brightness(struct led_classdev *led_dev,
 						enum led_brightness value)
 {
@@ -91,7 +177,10 @@
 	if (buf) {
 		buf[0] = WAC_CMD_LED_CONTROL;
 		buf[1] = led;
-		buf[2] = value;
+		buf[2] = value >> 2;
+		buf[3] = value;
+		/* use fixed brightness for OLEDs */
+		buf[4] = 0x08;
 		hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
 		kfree(buf);
 	}
@@ -317,6 +406,34 @@
 static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
 		wacom_show_speed, wacom_store_speed);
 
+#define WACOM_STORE(OLED_ID)						\
+static ssize_t wacom_oled##OLED_ID##_store(struct device *dev,		\
+				struct device_attribute *attr,		\
+				const char *buf, size_t count)		\
+{									\
+	struct hid_device *hdev = container_of(dev, struct hid_device,	\
+				dev);					\
+									\
+	if (count != 256)						\
+		return -EINVAL;						\
+									\
+	wacom_set_image(hdev, buf, OLED_ID);				\
+									\
+	return count;							\
+}									\
+									\
+static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL,	\
+				wacom_oled##OLED_ID##_store)
+
+WACOM_STORE(0);
+WACOM_STORE(1);
+WACOM_STORE(2);
+WACOM_STORE(3);
+WACOM_STORE(4);
+WACOM_STORE(5);
+WACOM_STORE(6);
+WACOM_STORE(7);
+
 static int wacom_gr_parse_report(struct hid_device *hdev,
 			struct wacom_data *wdata,
 			struct input_dev *input, unsigned char *data)
@@ -717,17 +834,33 @@
 		hid_warn(hdev,
 			 "can't create sysfs speed attribute err: %d\n", ret);
 
+#define OLED_INIT(OLED_ID)						\
+	do {								\
+		ret = device_create_file(&hdev->dev,			\
+				&dev_attr_oled##OLED_ID##_img);		\
+		if (ret)						\
+			hid_warn(hdev,					\
+			 "can't create sysfs oled attribute, err: %d\n", ret);\
+	} while (0)
+
+OLED_INIT(0);
+OLED_INIT(1);
+OLED_INIT(2);
+OLED_INIT(3);
+OLED_INIT(4);
+OLED_INIT(5);
+OLED_INIT(6);
+OLED_INIT(7);
+
 	wdata->features = 0;
 	wacom_set_features(hdev, 1);
 
 	if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
 		sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
 		ret = wacom_initialize_leds(hdev);
-		if (ret) {
+		if (ret)
 			hid_warn(hdev,
 				 "can't create led attribute, err: %d\n", ret);
-			goto destroy_leds;
-		}
 	}
 
 	wdata->battery.properties = wacom_battery_props;
@@ -740,8 +873,8 @@
 
 	ret = power_supply_register(&hdev->dev, &wdata->battery);
 	if (ret) {
-		hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
-			 ret);
+		hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
+			ret);
 		goto err_battery;
 	}
 
@@ -756,8 +889,8 @@
 
 	ret = power_supply_register(&hdev->dev, &wdata->ac);
 	if (ret) {
-		hid_warn(hdev,
-			 "can't create ac battery attribute, err: %d\n", ret);
+		hid_err(hdev,
+			"can't create ac battery attribute, err: %d\n", ret);
 		goto err_ac;
 	}
 
@@ -767,10 +900,17 @@
 err_ac:
 	power_supply_unregister(&wdata->battery);
 err_battery:
+	wacom_destroy_leds(hdev);
+	device_remove_file(&hdev->dev, &dev_attr_oled0_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled1_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled2_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled3_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled4_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled5_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled6_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled7_img);
 	device_remove_file(&hdev->dev, &dev_attr_speed);
 	hid_hw_stop(hdev);
-destroy_leds:
-	wacom_destroy_leds(hdev);
 err_free:
 	kfree(wdata);
 	return ret;
@@ -781,6 +921,14 @@
 	struct wacom_data *wdata = hid_get_drvdata(hdev);
 
 	wacom_destroy_leds(hdev);
+	device_remove_file(&hdev->dev, &dev_attr_oled0_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled1_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled2_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled3_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled4_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled5_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled6_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled7_img);
 	device_remove_file(&hdev->dev, &dev_attr_speed);
 	hid_hw_stop(hdev);
 
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index 745e4e9..bb536ab 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -638,28 +638,6 @@
 	0xC0                /*  End Collection                      */
 };
 
-static int waltop_probe(struct hid_device *hdev,
-			const struct hid_device_id *id)
-{
-	int ret;
-
-	ret = hid_parse(hdev);
-	if (ret) {
-		hid_err(hdev, "parse failed\n");
-		goto err;
-	}
-
-	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-	if (ret) {
-		hid_err(hdev, "hw start failed\n");
-		goto err;
-	}
-
-	return 0;
-err:
-	return ret;
-}
-
 static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
@@ -776,11 +754,6 @@
 	return 0;
 }
 
-static void waltop_remove(struct hid_device *hdev)
-{
-	hid_hw_stop(hdev);
-}
-
 static const struct hid_device_id waltop_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
 				USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
@@ -803,10 +776,8 @@
 static struct hid_driver waltop_driver = {
 	.name = "waltop",
 	.id_table = waltop_devices,
-	.probe = waltop_probe,
 	.report_fixup = waltop_report_fixup,
 	.raw_event = waltop_raw_event,
-	.remove = waltop_remove,
 };
 
 static int __init waltop_init(void)
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
index 0a1805c..bc85bf2 100644
--- a/drivers/hid/hid-wiimote-ext.c
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -28,12 +28,14 @@
 	bool mp_plugged;
 	bool motionp;
 	__u8 ext_type;
+	__u16 calib[4][3];
 };
 
 enum wiiext_type {
 	WIIEXT_NONE,		/* placeholder */
 	WIIEXT_CLASSIC,		/* Nintendo classic controller */
 	WIIEXT_NUNCHUCK,	/* Nintendo nunchuck controller */
+	WIIEXT_BALANCE_BOARD,	/* Nintendo balance board controller */
 };
 
 enum wiiext_keys {
@@ -126,6 +128,7 @@
 static __u8 ext_read(struct wiimote_ext *ext)
 {
 	ssize_t ret;
+	__u8 buf[24], i, j, offs = 0;
 	__u8 rmem[2], wmem;
 	__u8 type = WIIEXT_NONE;
 
@@ -151,6 +154,28 @@
 			type = WIIEXT_NUNCHUCK;
 		else if (rmem[0] == 0x01 && rmem[1] == 0x01)
 			type = WIIEXT_CLASSIC;
+		else if (rmem[0] == 0x04 && rmem[1] == 0x02)
+			type = WIIEXT_BALANCE_BOARD;
+	}
+
+	/* get balance board calibration data */
+	if (type == WIIEXT_BALANCE_BOARD) {
+		ret = wiimote_cmd_read(ext->wdata, 0xa40024, buf, 12);
+		ret += wiimote_cmd_read(ext->wdata, 0xa40024 + 12,
+					buf + 12, 12);
+
+		if (ret != 24) {
+			type = WIIEXT_NONE;
+		} else {
+			for (i = 0; i < 3; i++) {
+				for (j = 0; j < 4; j++) {
+					ext->calib[j][i] = buf[offs];
+					ext->calib[j][i] <<= 8;
+					ext->calib[j][i] |= buf[offs + 1];
+					offs += 2;
+				}
+			}
+		}
 	}
 
 	wiimote_cmd_release(ext->wdata);
@@ -509,6 +534,71 @@
 	input_sync(ext->input);
 }
 
+static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload)
+{
+	__s32 val[4], tmp;
+	unsigned int i;
+
+	/*   Byte |  8  7  6  5  4  3  2  1  |
+	 *   -----+--------------------------+
+	 *    1   |    Top Right <15:8>      |
+	 *    2   |    Top Right  <7:0>      |
+	 *   -----+--------------------------+
+	 *    3   | Bottom Right <15:8>      |
+	 *    4   | Bottom Right  <7:0>      |
+	 *   -----+--------------------------+
+	 *    5   |     Top Left <15:8>      |
+	 *    6   |     Top Left  <7:0>      |
+	 *   -----+--------------------------+
+	 *    7   |  Bottom Left <15:8>      |
+	 *    8   |  Bottom Left  <7:0>      |
+	 *   -----+--------------------------+
+	 *
+	 * These values represent the weight-measurements of the Wii-balance
+	 * board with 16bit precision.
+	 *
+	 * The balance-board is never reported interleaved with motionp.
+	 */
+
+	val[0] = payload[0];
+	val[0] <<= 8;
+	val[0] |= payload[1];
+
+	val[1] = payload[2];
+	val[1] <<= 8;
+	val[1] |= payload[3];
+
+	val[2] = payload[4];
+	val[2] <<= 8;
+	val[2] |= payload[5];
+
+	val[3] = payload[6];
+	val[3] <<= 8;
+	val[3] |= payload[7];
+
+	/* apply calibration data */
+	for (i = 0; i < 4; i++) {
+		if (val[i] < ext->calib[i][1]) {
+			tmp = val[i] - ext->calib[i][0];
+			tmp *= 1700;
+			tmp /= ext->calib[i][1] - ext->calib[i][0];
+		} else {
+			tmp = val[i] - ext->calib[i][1];
+			tmp *= 1700;
+			tmp /= ext->calib[i][2] - ext->calib[i][1];
+			tmp += 1700;
+		}
+		val[i] = tmp;
+	}
+
+	input_report_abs(ext->input, ABS_HAT0X, val[0]);
+	input_report_abs(ext->input, ABS_HAT0Y, val[1]);
+	input_report_abs(ext->input, ABS_HAT1X, val[2]);
+	input_report_abs(ext->input, ABS_HAT1Y, val[3]);
+
+	input_sync(ext->input);
+}
+
 /* call this with state.lock spinlock held */
 void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
 {
@@ -523,6 +613,8 @@
 		handler_nunchuck(ext, payload);
 	} else if (ext->ext_type == WIIEXT_CLASSIC) {
 		handler_classic(ext, payload);
+	} else if (ext->ext_type == WIIEXT_BALANCE_BOARD) {
+		handler_balance_board(ext, payload);
 	}
 }
 
@@ -551,6 +643,11 @@
 			return sprintf(buf, "motionp+classic\n");
 		else
 			return sprintf(buf, "classic\n");
+	} else if (type == WIIEXT_BALANCE_BOARD) {
+		if (motionp)
+			return sprintf(buf, "motionp+balanceboard\n");
+		else
+			return sprintf(buf, "balanceboard\n");
 	} else {
 		if (motionp)
 			return sprintf(buf, "motionp\n");
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 3b6f7bf..17d15bb 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -42,6 +42,7 @@
 static struct class *hidraw_class;
 static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
 static DEFINE_MUTEX(minors_lock);
+static void drop_ref(struct hidraw *hid, int exists_bit);
 
 static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
@@ -113,7 +114,7 @@
 	__u8 *buf;
 	int ret = 0;
 
-	if (!hidraw_table[minor]) {
+	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
 		ret = -ENODEV;
 		goto out;
 	}
@@ -261,7 +262,7 @@
 	}
 
 	mutex_lock(&minors_lock);
-	if (!hidraw_table[minor]) {
+	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
 		err = -ENODEV;
 		goto out_unlock;
 	}
@@ -298,36 +299,12 @@
 static int hidraw_release(struct inode * inode, struct file * file)
 {
 	unsigned int minor = iminor(inode);
-	struct hidraw *dev;
 	struct hidraw_list *list = file->private_data;
-	int ret;
-	int i;
 
-	mutex_lock(&minors_lock);
-	if (!hidraw_table[minor]) {
-		ret = -ENODEV;
-		goto unlock;
-	}
-
+	drop_ref(hidraw_table[minor], 0);
 	list_del(&list->node);
-	dev = hidraw_table[minor];
-	if (!--dev->open) {
-		if (list->hidraw->exist) {
-			hid_hw_power(dev->hid, PM_HINT_NORMAL);
-			hid_hw_close(dev->hid);
-		} else {
-			kfree(list->hidraw);
-		}
-	}
-
-	for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
-		kfree(list->buffer[i].value);
 	kfree(list);
-	ret = 0;
-unlock:
-	mutex_unlock(&minors_lock);
-
-	return ret;
+	return 0;
 }
 
 static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -529,21 +506,7 @@
 void hidraw_disconnect(struct hid_device *hid)
 {
 	struct hidraw *hidraw = hid->hidraw;
-
-	mutex_lock(&minors_lock);
-	hidraw->exist = 0;
-
-	device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-
-	hidraw_table[hidraw->minor] = NULL;
-
-	if (hidraw->open) {
-		hid_hw_close(hid);
-		wake_up_interruptible(&hidraw->wait);
-	} else {
-		kfree(hidraw);
-	}
-	mutex_unlock(&minors_lock);
+	drop_ref(hidraw, 1);
 }
 EXPORT_SYMBOL_GPL(hidraw_disconnect);
 
@@ -559,21 +522,28 @@
 
 	if (result < 0) {
 		pr_warn("can't get major number\n");
-		result = 0;
 		goto out;
 	}
 
 	hidraw_class = class_create(THIS_MODULE, "hidraw");
 	if (IS_ERR(hidraw_class)) {
 		result = PTR_ERR(hidraw_class);
-		unregister_chrdev(hidraw_major, "hidraw");
-		goto out;
+		goto error_cdev;
 	}
 
         cdev_init(&hidraw_cdev, &hidraw_ops);
-        cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+	result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+	if (result < 0)
+		goto error_class;
+
 out:
 	return result;
+
+error_class:
+	class_destroy(hidraw_class);
+error_cdev:
+	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+	goto out;
 }
 
 void hidraw_exit(void)
@@ -585,3 +555,23 @@
 	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 
 }
+
+static void drop_ref(struct hidraw *hidraw, int exists_bit)
+{
+	mutex_lock(&minors_lock);
+	if (exists_bit) {
+		hid_hw_close(hidraw->hid);
+		hidraw->exist = 0;
+		if (hidraw->open)
+			wake_up_interruptible(&hidraw->wait);
+	} else {
+		--hidraw->open;
+	}
+
+	if (!hidraw->open && !hidraw->exist) {
+		device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+		hidraw_table[hidraw->minor] = NULL;
+		kfree(hidraw);
+	}
+	mutex_unlock(&minors_lock);
+}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index dedd8e4..8e0c4bf94 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1415,20 +1415,20 @@
 	 * configuration descriptors passed, we already know that
 	 * the size of the HID report descriptor has not changed.
 	 */
-	rdesc = kmalloc(hid->rsize, GFP_KERNEL);
+	rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
 	if (!rdesc) {
 		dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
 		return 1;
 	}
 	status = hid_get_class_descriptor(dev,
 				interface->desc.bInterfaceNumber,
-				HID_DT_REPORT, rdesc, hid->rsize);
+				HID_DT_REPORT, rdesc, hid->dev_rsize);
 	if (status < 0) {
 		dbg_hid("reading report descriptor failed (post_reset)\n");
 		kfree(rdesc);
 		return 1;
 	}
-	status = memcmp(rdesc, hid->rdesc, hid->rsize);
+	status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
 	kfree(rdesc);
 	if (status != 0) {
 		dbg_hid("report descriptor changed\n");
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 991e85c..11c7932 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -70,12 +70,13 @@
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
 	{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 86f8885..3648f8f 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/hyperv.h>
+#include <linux/version.h>
 #include <asm/hyperv.h>
 #include "hyperv_vmbus.h"
 
@@ -38,28 +39,6 @@
 };
 
 /*
- * query_hypervisor_presence
- * - Query the cpuid for presence of windows hypervisor
- */
-static int query_hypervisor_presence(void)
-{
-	unsigned int eax;
-	unsigned int ebx;
-	unsigned int ecx;
-	unsigned int edx;
-	unsigned int op;
-
-	eax = 0;
-	ebx = 0;
-	ecx = 0;
-	edx = 0;
-	op = HVCPUID_VERSION_FEATURES;
-	cpuid(op, &eax, &ebx, &ecx, &edx);
-
-	return ecx & HV_PRESENT_BIT;
-}
-
-/*
  * query_hypervisor_info - Get version info of the windows hypervisor
  */
 static int query_hypervisor_info(void)
@@ -159,14 +138,13 @@
 	memset(hv_context.synic_message_page, 0,
 	       sizeof(void *) * NR_CPUS);
 
-	if (!query_hypervisor_presence())
-		goto cleanup;
-
 	max_leaf = query_hypervisor_info();
 
-	/* Write our OS info */
-	wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
-	hv_context.guestid = HV_LINUX_GUEST_ID;
+	/*
+	 * Write our OS ID.
+	 */
+	hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+	wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
 
 	/* See if the hypercall page is already set */
 	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0012eed..ed50e9e 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -48,13 +48,24 @@
 	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
+/*
+ * Before we can accept KVP messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+
+/*
+ * This state maintains the version number registered by the daemon.
+ */
+static int dm_reg_value;
+
 static void kvp_send_key(struct work_struct *dummy);
 
-#define TIMEOUT_FIRED 1
 
-static void kvp_respond_to_host(char *key, char *value, int error);
+static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
 static void kvp_work_func(struct work_struct *dummy);
-static void kvp_register(void);
+static void kvp_register(int);
 
 static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
@@ -68,7 +79,7 @@
  */
 
 static void
-kvp_register(void)
+kvp_register(int reg_value)
 {
 
 	struct cn_msg *msg;
@@ -83,7 +94,7 @@
 		msg->id.idx =  CN_KVP_IDX;
 		msg->id.val = CN_KVP_VAL;
 
-		kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+		kvp_msg->kvp_hdr.operation = reg_value;
 		strcpy(version, HV_DRV_VERSION);
 		msg->len = sizeof(struct hv_kvp_msg);
 		cn_netlink_send(msg, 0, GFP_ATOMIC);
@@ -97,9 +108,43 @@
 	 * If the timer fires, the user-mode component has not responded;
 	 * process the pending transaction.
 	 */
-	kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
+	kvp_respond_to_host(NULL, HV_E_FAIL);
 }
 
+static int kvp_handle_handshake(struct hv_kvp_msg *msg)
+{
+	int ret = 1;
+
+	switch (msg->kvp_hdr.operation) {
+	case KVP_OP_REGISTER:
+		dm_reg_value = KVP_OP_REGISTER;
+		pr_info("KVP: IP injection functionality not available\n");
+		pr_info("KVP: Upgrade the KVP daemon\n");
+		break;
+	case KVP_OP_REGISTER1:
+		dm_reg_value = KVP_OP_REGISTER1;
+		break;
+	default:
+		pr_info("KVP: incompatible daemon\n");
+		pr_info("KVP: KVP version: %d, Daemon version: %d\n",
+			KVP_OP_REGISTER1, msg->kvp_hdr.operation);
+		ret = 0;
+	}
+
+	if (ret) {
+		/*
+		 * We have a compatible daemon; complete the handshake.
+		 */
+		pr_info("KVP: user-mode registering done.\n");
+		kvp_register(dm_reg_value);
+		kvp_transaction.active = false;
+		if (kvp_transaction.kvp_context)
+			hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+	}
+	return ret;
+}
+
+
 /*
  * Callback when data is received from user mode.
  */
@@ -109,29 +154,165 @@
 {
 	struct hv_kvp_msg *message;
 	struct hv_kvp_msg_enumerate *data;
+	int	error = 0;
 
 	message = (struct hv_kvp_msg *)msg->data;
-	switch (message->kvp_hdr.operation) {
+
+	/*
+	 * If we are negotiating the version information
+	 * with the daemon; handle that first.
+	 */
+
+	if (in_hand_shake) {
+		if (kvp_handle_handshake(message))
+			in_hand_shake = false;
+		return;
+	}
+
+	/*
+	 * Based on the version of the daemon, we propagate errors from the
+	 * daemon differently.
+	 */
+
+	data = &message->body.kvp_enum_data;
+
+	switch (dm_reg_value) {
 	case KVP_OP_REGISTER:
-		pr_info("KVP: user-mode registering done.\n");
-		kvp_register();
-		kvp_transaction.active = false;
-		hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+		/*
+		 * Null string is used to pass back error condition.
+		 */
+		if (data->data.key[0] == 0)
+			error = HV_S_CONT;
 		break;
 
-	default:
-		data = &message->body.kvp_enum_data;
+	case KVP_OP_REGISTER1:
 		/*
-		 * Complete the transaction by forwarding the key value
-		 * to the host. But first, cancel the timeout.
+		 * We use the message header information from
+		 * the user level daemon to transmit errors.
 		 */
-		if (cancel_delayed_work_sync(&kvp_work))
-			kvp_respond_to_host(data->data.key,
-					 data->data.value,
-					!strlen(data->data.key));
+		error = message->error;
+		break;
+	}
+
+	/*
+	 * Complete the transaction by forwarding the key value
+	 * to the host. But first, cancel the timeout.
+	 */
+	if (cancel_delayed_work_sync(&kvp_work))
+		kvp_respond_to_host(message, error);
+}
+
+
+static int process_ob_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_msg *in = in_msg;
+	struct hv_kvp_ip_msg *out = out_msg;
+	int len;
+
+	switch (op) {
+	case KVP_OP_GET_IP_INFO:
+		/*
+		 * Transform all parameters into utf16 encoding.
+		 */
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr,
+				strlen((char *)in->body.kvp_ip_val.ip_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net,
+				strlen((char *)in->body.kvp_ip_val.sub_net),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way,
+				strlen((char *)in->body.kvp_ip_val.gate_way),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr,
+				strlen((char *)in->body.kvp_ip_val.dns_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id,
+				strlen((char *)in->body.kvp_ip_val.adapter_id),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.adapter_id,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		out->kvp_ip_val.dhcp_enabled =
+			in->body.kvp_ip_val.dhcp_enabled;
+		out->kvp_ip_val.addr_family =
+			in->body.kvp_ip_val.addr_family;
+	}
+
+	return 0;
+}
+
+static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_ip_msg *in = in_msg;
+	struct hv_kvp_msg *out = out_msg;
+
+	switch (op) {
+	case KVP_OP_SET_IP_INFO:
+		/*
+		 * Transform all parameters into utf8 encoding.
+		 */
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+
+		out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
+
+	default:
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE);
+
+		out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family;
 	}
 }
 
+
+
+
 static void
 kvp_send_key(struct work_struct *dummy)
 {
@@ -167,6 +348,12 @@
 	 */
 
 	switch (message->kvp_hdr.operation) {
+	case KVP_OP_SET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
+		break;
+	case KVP_OP_GET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
+		break;
 	case KVP_OP_SET:
 		switch (in_msg->body.kvp_set.data.value_type) {
 		case REG_SZ:
@@ -243,17 +430,19 @@
  */
 
 static void
-kvp_respond_to_host(char *key, char *value, int error)
+kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error)
 {
 	struct hv_kvp_msg  *kvp_msg;
 	struct hv_kvp_exchg_msg_value  *kvp_data;
 	char	*key_name;
+	char	*value;
 	struct icmsg_hdr *icmsghdrp;
 	int	keylen = 0;
 	int	valuelen = 0;
 	u32	buf_len;
 	struct vmbus_channel *channel;
 	u64	req_id;
+	int ret;
 
 	/*
 	 * If a transaction is not active; log and return.
@@ -287,6 +476,7 @@
 		 */
 		return;
 
+	icmsghdrp->status = error;
 
 	/*
 	 * If the error parameter is set, terminate the host's enumeration
@@ -294,20 +484,27 @@
 	 */
 	if (error) {
 		/*
-		 * Something failed or the we have timedout;
-		 * terminate the current  host-side iteration.
+		 * Something failed or we have timedout;
+		 * terminate the current host-side iteration.
 		 */
-		icmsghdrp->status = HV_S_CONT;
 		goto response_done;
 	}
 
-	icmsghdrp->status = HV_S_OK;
-
 	kvp_msg = (struct hv_kvp_msg *)
 			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
 			sizeof(struct icmsg_hdr)];
 
 	switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
+	case KVP_OP_GET_IP_INFO:
+		ret = process_ob_ipinfo(msg_to_host,
+				 (struct hv_kvp_ip_msg *)kvp_msg,
+				 KVP_OP_GET_IP_INFO);
+		if (ret < 0)
+			icmsghdrp->status = HV_E_FAIL;
+
+		goto response_done;
+	case KVP_OP_SET_IP_INFO:
+		goto response_done;
 	case KVP_OP_GET:
 		kvp_data = &kvp_msg->body.kvp_get.data;
 		goto copy_value;
@@ -321,7 +518,7 @@
 	}
 
 	kvp_data = &kvp_msg->body.kvp_enum_data.data;
-	key_name = key;
+	key_name = msg_to_host->body.kvp_enum_data.data.key;
 
 	/*
 	 * The windows host expects the key/value pair to be encoded
@@ -335,6 +532,7 @@
 	kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
 
 copy_value:
+	value = msg_to_host->body.kvp_enum_data.data.value;
 	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
 				(wchar_t *) kvp_data->value,
 				(HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
@@ -387,7 +585,8 @@
 		return;
 	}
 
-	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
+	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+			 &requestid);
 
 	if (recvlen > 0) {
 		icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index d3ac6a4..a0667de 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -263,7 +263,7 @@
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {
@@ -274,7 +274,7 @@
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 0614ff3..d8d1fad 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -410,10 +410,49 @@
 
 #define HV_PRESENT_BIT			0x80000000
 
-#define HV_LINUX_GUEST_ID_LO		0x00000000
-#define HV_LINUX_GUEST_ID_HI		2976579765
-#define HV_LINUX_GUEST_ID		(((u64)HV_LINUX_GUEST_ID_HI << 32) | \
-					   HV_LINUX_GUEST_ID_LO)
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0  - Distro specific identification
+ *
+ *
+ */
+
+#define HV_LINUX_VENDOR_ID		0x8100
+
+/*
+ * Generate the guest ID based on the guideline described above.
+ */
+
+static inline  __u64 generate_guest_id(__u8 d_info1, __u32 kernel_version,
+					__u16 d_info2)
+{
+	__u64 guest_id = 0;
+
+	guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
+	guest_id |= (((__u64)(d_info1)) << 48);
+	guest_id |= (((__u64)(kernel_version)) << 16);
+	guest_id |= ((__u64)(d_info2));
+
+	return guest_id;
+}
+
 
 #define HV_CPU_POWER_MANAGEMENT		(1 << 0)
 #define HV_RECOMMENDATIONS_MAX		4
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 4748086..8e1a9ec 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -34,6 +34,7 @@
 #include <linux/completion.h>
 #include <linux/hyperv.h>
 #include <asm/hyperv.h>
+#include <asm/hypervisor.h>
 #include "hyperv_vmbus.h"
 
 
@@ -146,43 +147,9 @@
 	get_channel_info(hv_dev, device_info);
 
 	if (!strcmp(dev_attr->attr.name, "class_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_type.b[3],
-			       device_info->chn_type.b[2],
-			       device_info->chn_type.b[1],
-			       device_info->chn_type.b[0],
-			       device_info->chn_type.b[5],
-			       device_info->chn_type.b[4],
-			       device_info->chn_type.b[7],
-			       device_info->chn_type.b[6],
-			       device_info->chn_type.b[8],
-			       device_info->chn_type.b[9],
-			       device_info->chn_type.b[10],
-			       device_info->chn_type.b[11],
-			       device_info->chn_type.b[12],
-			       device_info->chn_type.b[13],
-			       device_info->chn_type.b[14],
-			       device_info->chn_type.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b);
 	} else if (!strcmp(dev_attr->attr.name, "device_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_instance.b[3],
-			       device_info->chn_instance.b[2],
-			       device_info->chn_instance.b[1],
-			       device_info->chn_instance.b[0],
-			       device_info->chn_instance.b[5],
-			       device_info->chn_instance.b[4],
-			       device_info->chn_instance.b[7],
-			       device_info->chn_instance.b[6],
-			       device_info->chn_instance.b[8],
-			       device_info->chn_instance.b[9],
-			       device_info->chn_instance.b[10],
-			       device_info->chn_instance.b[11],
-			       device_info->chn_instance.b[12],
-			       device_info->chn_instance.b[13],
-			       device_info->chn_instance.b[14],
-			       device_info->chn_instance.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b);
 	} else if (!strcmp(dev_attr->attr.name, "modalias")) {
 		print_alias_name(hv_dev, alias_name);
 		ret = sprintf(buf, "vmbus:%s\n", alias_name);
@@ -757,6 +724,9 @@
 {
 	int ret, t;
 
+	if (x86_hyper != &x86_hyper_ms_hyperv)
+		return -ENODEV;
+
 	init_completion(&probe_event);
 
 	/*
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b0a2e4c..c74e73b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -41,7 +41,7 @@
 
 config SENSORS_ABITUGURU
 	tristate "Abit uGuru (rev 1 & 2)"
-	depends on X86 && DMI && EXPERIMENTAL
+	depends on X86 && DMI
 	help
 	  If you say yes here you get support for the sensor part of the first
 	  and second revision of the Abit uGuru chip. The voltage and frequency
@@ -56,7 +56,7 @@
 
 config SENSORS_ABITUGURU3
 	tristate "Abit uGuru (rev 3)"
-	depends on X86 && DMI && EXPERIMENTAL
+	depends on X86 && DMI
 	help
 	  If you say yes here you get support for the sensor part of the
 	  third revision of the Abit uGuru chip. Only reading the sensors
@@ -70,7 +70,7 @@
 
 config SENSORS_AD7314
 	tristate "Analog Devices AD7314 and compatibles"
-	depends on SPI && EXPERIMENTAL
+	depends on SPI
 	help
 	  If you say yes here you get support for the Analog Devices
 	  AD7314, ADT7301 and ADT7302 temperature sensors.
@@ -80,7 +80,7 @@
 
 config SENSORS_AD7414
 	tristate "Analog Devices AD7414"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  AD7414 temperature monitoring chip.
@@ -90,7 +90,7 @@
 
 config SENSORS_AD7418
 	tristate "Analog Devices AD7416, AD7417 and AD7418"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  AD7416, AD7417 and AD7418 temperature monitoring chips.
@@ -100,7 +100,7 @@
 
 config SENSORS_ADCXX
 	tristate "National Semiconductor ADCxxxSxxx"
-	depends on SPI_MASTER && EXPERIMENTAL
+	depends on SPI_MASTER
 	help
 	  If you say yes here you get support for the National Semiconductor
 	  ADC<bb><c>S<sss> chip family, where
@@ -179,9 +179,19 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called adm9240.
 
+config SENSORS_ADT7410
+	tristate "Analog Devices ADT7410"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7410 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7410.
+
 config SENSORS_ADT7411
 	tristate "Analog Devices ADT7411"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  ADT7411 voltage and temperature monitoring chip.
@@ -191,7 +201,7 @@
 
 config SENSORS_ADT7462
 	tristate "Analog Devices ADT7462"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  ADT7462 temperature monitoring chips.
@@ -201,7 +211,7 @@
 
 config SENSORS_ADT7470
 	tristate "Analog Devices ADT7470"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  ADT7470 temperature monitoring chips.
@@ -236,7 +246,7 @@
 
 config SENSORS_K8TEMP
 	tristate "AMD Athlon64/FX or Opteron temperature sensor"
-	depends on X86 && PCI && EXPERIMENTAL
+	depends on X86 && PCI
 	help
 	  If you say yes here you get support for the temperature
 	  sensor(s) inside your CPU. Supported is whole AMD K8
@@ -271,7 +281,7 @@
 
 config SENSORS_ASB100
 	tristate "Asus ASB100 Bach"
-	depends on X86 && I2C && EXPERIMENTAL
+	depends on X86 && I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the ASB100 Bach sensor
@@ -282,7 +292,7 @@
 
 config SENSORS_ATXP1
 	tristate "Attansic ATXP1 VID controller"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Attansic ATXP1 VID
@@ -336,7 +346,7 @@
 
 config SENSORS_I5K_AMB
 	tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
-	depends on PCI && EXPERIMENTAL
+	depends on PCI
 	help
 	  If you say yes here you get support for FB-DIMM AMB temperature
 	  monitoring chips on systems with the Intel 5000 series chipset.
@@ -445,7 +455,7 @@
 
 config SENSORS_HIH6130
 	tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Honeywell Humidicon
 	  HIH-6130 and HIH-6131 Humidicon humidity sensors.
@@ -455,7 +465,7 @@
 
 config SENSORS_CORETEMP
 	tristate "Intel Core/Core2/Atom temperature sensor"
-	depends on X86 && PCI && EXPERIMENTAL
+	depends on X86 && PCI
 	help
 	  If you say yes here you get support for the temperature
 	  sensor inside your CPU. Most of the family 6 CPUs
@@ -495,8 +505,8 @@
 	select HWMON_VID
 	help
 	  If you say yes here you get support for ITE IT8705F, IT8712F,
-	  IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E
-	  sensor chips, and the SiS960 clone.
+	  IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
+	  IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
@@ -527,7 +537,7 @@
 
 config SENSORS_LINEAGE
 	tristate "Lineage Compact Power Line Power Entry Module"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Lineage Compact Power Line
 	  series of DC/DC and AC/DC converters such as CP1800, CP2000AC,
@@ -550,12 +560,12 @@
 	  will be called lm63.
 
 config SENSORS_LM70
-	tristate "National Semiconductor LM70 / Texas Instruments TMP121"
+	tristate "National Semiconductor LM70 and compatibles"
 	depends on SPI_MASTER
 	help
 	  If you say yes here you get support for the National Semiconductor
-	  LM70 and Texas Instruments TMP121/TMP123 digital temperature
-	  sensor chips.
+	  LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
+	  ture sensor chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm70.
@@ -709,7 +719,7 @@
 
 config SENSORS_LTC4215
 	tristate "Linear Technology LTC4215"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	default n
 	help
 	  If you say yes here you get support for Linear Technology LTC4215
@@ -720,7 +730,7 @@
 
 config SENSORS_LTC4245
 	tristate "Linear Technology LTC4245"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	default n
 	help
 	  If you say yes here you get support for Linear Technology LTC4245
@@ -731,7 +741,7 @@
 
 config SENSORS_LTC4261
 	tristate "Linear Technology LTC4261"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	default n
 	help
 	  If you say yes here you get support for Linear Technology LTC4261
@@ -752,7 +762,7 @@
 
 config SENSORS_LM95245
 	tristate "National Semiconductor LM95245 sensor chip"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for LM95245 sensor chip.
 
@@ -760,10 +770,11 @@
 	  will be called lm95245.
 
 config SENSORS_MAX1111
-	tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
+	tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
 	depends on SPI_MASTER
 	help
-	  Say y here to support Maxim's MAX1111 ADC chips.
+	  Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
+	  ADC chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called max1111.
@@ -795,7 +806,7 @@
 
 config SENSORS_MAX1668
 	tristate "Maxim MAX1668 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for MAX1668, MAX1989 and
 	  MAX1805 chips.
@@ -803,9 +814,18 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max1668.
 
+config SENSORS_MAX197
+	tristate "Maxim MAX197 and compatibles"
+	help
+	  Support for the Maxim MAX197 A/D converter.
+	  Support will include, but not be limited to, MAX197, and MAX199.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called max197.
+
 config SENSORS_MAX6639
 	tristate "Maxim MAX6639 sensor chip"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the MAX6639
 	  sensor chips.
@@ -815,7 +835,7 @@
 
 config SENSORS_MAX6642
 	tristate "Maxim MAX6642 sensor chip"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for MAX6642 sensor chip.
 	  MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
@@ -826,7 +846,7 @@
 
 config SENSORS_MAX6650
 	tristate "Maxim MAX6650 sensor chip"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the MAX6650 / MAX6651
 	  sensor chips.
@@ -835,18 +855,18 @@
 	  will be called max6650.
 
 config SENSORS_MCP3021
-	tristate "Microchip MCP3021"
-	depends on I2C && EXPERIMENTAL
+	tristate "Microchip MCP3021 and compatibles"
+	depends on I2C
 	help
-	  If you say yes here you get support for the MCP3021 chip
-	  that is a A/D converter (ADC) with 10-bit resolution.
+	  If you say yes here you get support for MCP3021 and MCP3221.
+	  The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
+	  with 12-bit resolution.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called mcp3021.
 
 config SENSORS_NTC_THERMISTOR
 	tristate "NTC thermistor support"
-	depends on EXPERIMENTAL
 	help
 	  This driver supports NTC thermistors sensor reading and its
 	  interpretation. The driver can also monitor the temperature and
@@ -951,7 +971,7 @@
 
 config SENSORS_SMM665
 	tristate "Summit Microelectronics SMM665"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	default n
 	help
 	  If you say yes here you get support for the hardware monitoring
@@ -966,7 +986,7 @@
 
 config SENSORS_DME1737
 	tristate "SMSC DME1737, SCH311x and compatibles"
-	depends on I2C && EXPERIMENTAL && !PPC
+	depends on I2C && !PPC
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the hardware monitoring
@@ -1042,7 +1062,7 @@
 
 config SENSORS_SMSC47B397
 	tristate "SMSC LPC47B397-NC"
-	depends on EXPERIMENTAL && !PPC
+	depends on !PPC
 	help
 	  If you say yes here you get support for the SMSC LPC47B397-NC
 	  sensor chip.
@@ -1116,7 +1136,7 @@
 
 config SENSORS_AMC6821
 	tristate "Texas Instruments AMC6821"
-	depends on I2C  && EXPERIMENTAL
+	depends on I2C 
 	help
 	  If you say yes here you get support for the Texas Instruments
 	  AMC6821 hardware monitoring chips.
@@ -1125,11 +1145,11 @@
 	  will be called amc6821.
 
 config SENSORS_INA2XX
-	tristate "Texas Instruments INA219, INA226"
-	depends on I2C && EXPERIMENTAL
+	tristate "Texas Instruments INA219 and compatibles"
+	depends on I2C
 	help
-	  If you say yes here you get support for INA219 and INA226 power
-	  monitor chips.
+	  If you say yes here you get support for INA219, INA220, INA226, and
+	  INA230 power monitor chips.
 
 	  The INA2xx driver is configured for the default configuration of
 	  the part as described in the datasheet.
@@ -1149,7 +1169,7 @@
 
 config SENSORS_TMP102
 	tristate "Texas Instruments TMP102"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Texas Instruments TMP102
 	  sensor chips.
@@ -1159,7 +1179,7 @@
 
 config SENSORS_TMP401
 	tristate "Texas Instruments TMP401 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Texas Instruments TMP401 and
 	  TMP411 temperature sensor chips.
@@ -1169,7 +1189,7 @@
 
 config SENSORS_TMP421
 	tristate "Texas Instruments TMP421 and compatible"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Texas Instruments TMP421,
 	  TMP422 and TMP423 temperature sensor chips.
@@ -1261,7 +1281,7 @@
 
 config SENSORS_W83793
 	tristate "Winbond W83793"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W83793
@@ -1273,7 +1293,7 @@
 
 config SENSORS_W83795
 	tristate "Winbond/Nuvoton W83795G/ADG"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Winbond W83795G and
 	  W83795ADG hardware monitoring chip, including manual fan speed
@@ -1284,7 +1304,7 @@
 
 config SENSORS_W83795_FANCTRL
 	boolean "Include automatic fan control support (DANGEROUS)"
-	depends on SENSORS_W83795 && EXPERIMENTAL
+	depends on SENSORS_W83795
 	default n
 	help
 	  If you say yes here, support for automatic fan speed control
@@ -1301,7 +1321,7 @@
 
 config SENSORS_W83L785TS
 	tristate "Winbond W83L785TS-S"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Winbond W83L785TS-S
 	  sensor chip, which is used on the Asus A7N8X, among other
@@ -1312,7 +1332,7 @@
 
 config SENSORS_W83L786NG
 	tristate "Winbond W83L786NG, W83L786NR"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Winbond W83L786NG
 	  and W83L786NR sensor chips.
@@ -1427,7 +1447,7 @@
 
 config SENSORS_ATK0110
 	tristate "ASUS ATK0110"
-	depends on X86 && EXPERIMENTAL
+	depends on X86
 	help
 	  If you say yes here you get support for the ACPI hardware
 	  monitoring interface found in many ASUS motherboards. This
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 7aa9811..a62ce17 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
+obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
 obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)	+= adt7470.o
@@ -94,6 +95,7 @@
 obj-$(CONFIG_SENSORS_MAX16065)	+= max16065.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_MAX1668)	+= max1668.o
+obj-$(CONFIG_SENSORS_MAX197)	+= max197.o
 obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index d4419b4..78b8179 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1278,7 +1278,8 @@
 		0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
 		0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
 
-	data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1430,8 +1431,6 @@
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return res;
 }
 
@@ -1446,8 +1445,6 @@
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 5d582ae..b174b8b 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -976,7 +976,8 @@
 	u8 buf[2];
 	u16 id;
 
-	data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1068,7 +1069,6 @@
 	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru3_sysfs_attr[i].dev_attr);
-	kfree(data);
 	return res;
 }
 
@@ -1084,8 +1084,6 @@
 	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru3_sysfs_attr[i].dev_attr);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index cfec802..37c01e7 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -87,10 +87,18 @@
 	}
 }
 
+static ssize_t ad7314_show_name(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
 			  ad7314_show_temperature, NULL, 0);
 
 static struct attribute *ad7314_attributes[] = {
+	&dev_attr_name.attr,
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	NULL,
 };
@@ -104,16 +112,16 @@
 	int ret;
 	struct ad7314_data *chip;
 
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
 	dev_set_drvdata(&spi_dev->dev, chip);
 
 	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 	if (ret < 0)
-		goto error_free_chip;
+		return ret;
+
 	chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
 	if (IS_ERR(chip->hwmon_dev)) {
 		ret = PTR_ERR(chip->hwmon_dev);
@@ -124,9 +132,6 @@
 	return 0;
 error_remove_group:
 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-error_free_chip:
-	kfree(chip);
-error_ret:
 	return ret;
 }
 
@@ -136,7 +141,6 @@
 
 	hwmon_device_unregister(chip->hwmon_dev);
 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-	kfree(chip);
 
 	return 0;
 }
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index 06d2d60..b420fb3 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -185,16 +185,13 @@
 	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-				     I2C_FUNC_SMBUS_READ_WORD_DATA)) {
-		err = -EOPNOTSUPP;
-		goto exit;
-	}
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EOPNOTSUPP;
 
-	data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ad7414_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -214,7 +211,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +223,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -238,7 +232,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index a50a6be..57d4a62 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -227,16 +227,13 @@
 	int err;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-					I2C_FUNC_SMBUS_WORD_DATA)) {
-		err = -EOPNOTSUPP;
-		goto exit;
-	}
+					I2C_FUNC_SMBUS_WORD_DATA))
+		return -EOPNOTSUPP;
 
-	data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ad7418_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 
@@ -268,7 +265,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +277,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -291,7 +285,6 @@
 	struct ad7418_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c
index a3d3183..f4c5867 100644
--- a/drivers/hwmon/adcxx.c
+++ b/drivers/hwmon/adcxx.c
@@ -141,10 +141,7 @@
 static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
 			      *devattr, char *buf)
 {
-	struct spi_device *spi = to_spi_device(dev);
-	struct adcxx *adc = spi_get_drvdata(spi);
-
-	return sprintf(buf, "adcxx%ds\n", adc->channels);
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
 }
 
 static struct sensor_device_attribute ad_input[] = {
@@ -171,7 +168,7 @@
 	int status;
 	int i;
 
-	adc = kzalloc(sizeof *adc, GFP_KERNEL);
+	adc = devm_kzalloc(&spi->dev, sizeof(*adc), GFP_KERNEL);
 	if (!adc)
 		return -ENOMEM;
 
@@ -208,7 +205,6 @@
 
 	spi_set_drvdata(spi, NULL);
 	mutex_unlock(&adc->lock);
-	kfree(adc);
 	return status;
 }
 
@@ -224,7 +220,6 @@
 
 	spi_set_drvdata(spi, NULL);
 	mutex_unlock(&adc->lock);
-	kfree(adc);
 
 	return 0;
 }
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 80cc465..97f4718 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -342,11 +342,10 @@
 	struct adm1029_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1029_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -355,15 +354,13 @@
 	 * Initialize the ADM1029 chip
 	 * Check config register
 	 */
-	if (adm1029_init_client(client) == 0) {
-		err = -ENODEV;
-		goto exit_free;
-	}
+	if (adm1029_init_client(client) == 0)
+		return -ENODEV;
 
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -375,9 +372,6 @@
 
  exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- exit_free:
-	kfree(data);
- exit:
 	return err;
 }
 
@@ -405,7 +399,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adm1029_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 5a78d10..8b24d1a 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -500,31 +500,6 @@
 }
 static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
 
-/* chassis_clear */
-static ssize_t chassis_clear_legacy(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	long val;
-	int err;
-
-	err = kstrtol(buf, 10, &val);
-	if (err)
-		return err;
-
-	dev_warn(dev, "Attribute chassis_clear is deprecated, "
-		 "use intrusion0_alarm instead\n");
-
-	if (val == 1) {
-		i2c_smbus_write_byte_data(client,
-				ADM9240_REG_CHASSIS_CLEAR, 0x80);
-		dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
-	}
-	return count;
-}
-static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear_legacy);
-
 static ssize_t chassis_clear(struct device *dev,
 		struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -586,7 +561,6 @@
 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
 	&dev_attr_alarms.attr,
 	&dev_attr_aout_output.attr,
-	&dev_attr_chassis_clear.attr,
 	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
 	&dev_attr_cpu0_vid.attr,
 	NULL
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 1958f03..2798246 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -156,7 +156,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-	kfree(data);
 	return 0;
 }
 
@@ -254,11 +253,10 @@
 	int err;
 	unsigned int k;
 
-	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -284,8 +282,6 @@
 exit_remove:
 	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-	kfree(data);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index bf3fdf4..1f9e8af 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -154,7 +154,6 @@
 	struct ads7828_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -217,11 +216,10 @@
 	struct ads7828_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ads7828_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -229,7 +227,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -241,9 +239,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
index e65c6e4..1b53aa4 100644
--- a/drivers/hwmon/ads7871.c
+++ b/drivers/hwmon/ads7871.c
@@ -139,6 +139,12 @@
 	}
 }
 
+static ssize_t ads7871_show_name(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
+}
+
 static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
 static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
 static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
@@ -148,6 +154,8 @@
 static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
 static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
 
+static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL);
+
 static struct attribute *ads7871_attributes[] = {
 	&sensor_dev_attr_in0_input.dev_attr.attr,
 	&sensor_dev_attr_in1_input.dev_attr.attr,
@@ -157,6 +165,7 @@
 	&sensor_dev_attr_in5_input.dev_attr.attr,
 	&sensor_dev_attr_in6_input.dev_attr.attr,
 	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -189,20 +198,17 @@
 	 * because there is no other error checking on an SPI bus
 	 * we need to make sure we really have a chip
 	 */
-	if (val != ret) {
-		err = -ENODEV;
-		goto exit;
-	}
+	if (val != ret)
+		return -ENODEV;
 
-	pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
-	if (!pdata) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data),
+			     GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
 
 	err = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
 	if (err < 0)
-		goto error_free;
+		return err;
 
 	spi_set_drvdata(spi, pdata);
 
@@ -216,9 +222,6 @@
 
 error_remove:
 	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-error_free:
-	kfree(pdata);
-exit:
 	return err;
 }
 
@@ -228,7 +231,6 @@
 
 	hwmon_device_unregister(pdata->hwmon_dev);
 	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-	kfree(pdata);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
new file mode 100644
index 0000000..030c8d7
--- /dev/null
+++ b/drivers/hwmon/adt7410.c
@@ -0,0 +1,464 @@
+/*
+ * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE		0
+#define ADT7410_STATUS			2
+#define ADT7410_CONFIG			3
+#define ADT7410_T_ALARM_HIGH		4
+#define ADT7410_T_ALARM_LOW		6
+#define ADT7410_T_CRIT			8
+#define ADT7410_T_HYST			0xA
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW		(1 << 4)
+#define ADT7410_STAT_T_HIGH		(1 << 5)
+#define ADT7410_STAT_T_CRIT		(1 << 6)
+#define ADT7410_STAT_NOT_RDY		(1 << 7)
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
+#define ADT7410_CT_POLARITY		(1 << 2)
+#define ADT7410_INT_POLARITY		(1 << 3)
+#define ADT7410_EVENT_MODE		(1 << 4)
+#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
+#define ADT7410_FULL			(0 << 5 | 0 << 6)
+#define ADT7410_PD			(1 << 5 | 1 << 6)
+#define ADT7410_RESOLUTION		(1 << 7)
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T13_VALUE_MASK			0xFFF8
+#define ADT7410_T_HYST_MASK			0xF
+
+/* straight from the datasheet */
+#define ADT7410_TEMP_MIN (-55000)
+#define ADT7410_TEMP_MAX 150000
+
+enum adt7410_type {		/* keep sorted in alphabetical order */
+	adt7410,
+};
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+					I2C_CLIENT_END };
+
+static const u8 ADT7410_REG_TEMP[4] = {
+	ADT7410_TEMPERATURE,		/* input */
+	ADT7410_T_ALARM_HIGH,		/* high */
+	ADT7410_T_ALARM_LOW,		/* low */
+	ADT7410_T_CRIT,			/* critical */
+};
+
+/* Each client has this additional data */
+struct adt7410_data {
+	struct device		*hwmon_dev;
+	struct mutex		update_lock;
+	u8			config;
+	u8			oldconfig;
+	bool			valid;		/* true if registers valid */
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[4];	/* Register values,
+						   0 = input
+						   1 = high
+						   2 = low
+						   3 = critical */
+	u8			hyst;		/* hysteresis offset */
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+static int adt7410_temp_ready(struct i2c_client *client)
+{
+	int i, status;
+
+	for (i = 0; i < 6; i++) {
+		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+		if (status < 0)
+			return status;
+		if (!(status & ADT7410_STAT_NOT_RDY))
+			return 0;
+		msleep(60);
+	}
+	return -ETIMEDOUT;
+}
+
+static struct adt7410_data *adt7410_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	struct adt7410_data *ret = data;
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int i, status;
+
+		dev_dbg(&client->dev, "Starting update\n");
+
+		status = adt7410_temp_ready(client); /* check for new value */
+		if (unlikely(status)) {
+			ret = ERR_PTR(status);
+			goto abort;
+		}
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			status = i2c_smbus_read_word_swapped(client,
+							ADT7410_REG_TEMP[i]);
+			if (unlikely(status < 0)) {
+				dev_dbg(dev,
+					"Failed to read value: reg %d, error %d\n",
+					ADT7410_REG_TEMP[i], status);
+				ret = ERR_PTR(status);
+				goto abort;
+			}
+			data->temp[i] = status;
+		}
+		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+		if (unlikely(status < 0)) {
+			dev_dbg(dev,
+				"Failed to read value: reg %d, error %d\n",
+				ADT7410_T_HYST, status);
+			ret = ERR_PTR(status);
+			goto abort;
+		}
+		data->hyst = status;
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static s16 ADT7410_TEMP_TO_REG(long temp)
+{
+	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
+					       ADT7410_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+{
+	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
+	if (!(data->config & ADT7410_RESOLUTION))
+		reg &= ADT7410_T13_VALUE_MASK;
+	/*
+	 * temperature is stored in twos complement format, in steps of
+	 * 1/128°C
+	 */
+	return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7410_show_temp(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data = adt7410_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
+		       data->temp[attr->index]));
+}
+
+static ssize_t adt7410_set_temp(struct device *dev,
+				struct device_attribute *da,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int nr = attr->index;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
+	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
+					   data->temp[nr]);
+	if (ret)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+				   struct device_attribute *da,
+				   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data;
+	int nr = attr->index;
+	int hyst;
+
+	data = adt7410_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
+
+	/*
+	 * hysteresis is stored as a 4 bit offset in the device, convert it
+	 * to an absolute value
+	 */
+	if (nr == 2)	/* min has positive offset, others have negative */
+		hyst = -hyst;
+	return sprintf(buf, "%d\n",
+		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7410_set_t_hyst(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int limit, ret;
+	long hyst;
+
+	ret = kstrtol(buf, 10, &hyst);
+	if (ret)
+		return ret;
+	/* convert absolute hysteresis value to a 4 bit delta value */
+	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
+	hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+	data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+				   0, ADT7410_T_HYST_MASK);
+	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t adt7410_show_alarm(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_CRIT);
+
+static struct attribute *adt7410_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adt7410_group = {
+	.attrs = adt7410_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int adt7410_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct adt7410_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* configure as specified */
+	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
+	if (ret < 0) {
+		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
+		return ret;
+	}
+	data->oldconfig = ret;
+	/*
+	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 */
+	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
+			ADT7410_EVENT_MODE;
+	if (data->config != data->oldconfig) {
+		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+						data->config);
+		if (ret)
+			return ret;
+	}
+	dev_dbg(&client->dev, "Config %02x\n", data->config);
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
+	if (ret)
+		goto exit_restore;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	dev_info(&client->dev, "sensor '%s'\n", client->name);
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+exit_restore:
+	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
+	return ret;
+}
+
+static int adt7410_remove(struct i2c_client *client)
+{
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+	if (data->oldconfig != data->config)
+		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+					  data->oldconfig);
+	return 0;
+}
+
+static const struct i2c_device_id adt7410_ids[] = {
+	{ "adt7410", adt7410, },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
+#ifdef CONFIG_PM
+static int adt7410_suspend(struct device *dev)
+{
+	int ret;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+					data->config | ADT7410_PD);
+	return ret;
+}
+
+static int adt7410_resume(struct device *dev)
+{
+	int ret;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
+	return ret;
+}
+
+static const struct dev_pm_ops adt7410_dev_pm_ops = {
+	.suspend	= adt7410_suspend,
+	.resume		= adt7410_resume,
+};
+#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
+#else
+#define ADT7410_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver adt7410_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7410",
+		.pm	= ADT7410_DEV_PM_OPS,
+	},
+	.probe		= adt7410_probe,
+	.remove		= adt7410_remove,
+	.id_table	= adt7410_ids,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adt7410_driver);
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index 71bacc5..fe72c69 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -283,7 +283,7 @@
 	struct adt7411_data *data;
 	int ret;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -294,14 +294,14 @@
 	ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
 				 ADT7411_CFG1_START_MONITOR, 1);
 	if (ret < 0)
-		goto exit_free;
+		return ret;
 
 	/* force update on first occasion */
 	data->next_update = jiffies;
 
 	ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
 	if (ret)
-		goto exit_free;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -315,8 +315,6 @@
 
  exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- exit_free:
-	kfree(data);
 	return ret;
 }
 
@@ -326,7 +324,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 339269f..baee482 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -1931,11 +1931,10 @@
 	struct adt7462_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adt7462_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7462_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -1946,7 +1945,7 @@
 	data->attrs.attrs = adt7462_attr;
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -1958,9 +1957,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1970,7 +1966,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 54ec890..39ecb1a 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -1256,11 +1256,10 @@
 	struct adt7470_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7470_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->num_temp_sensors = -1;
 	data->auto_update_interval = AUTO_UPDATE_INTERVAL;
@@ -1277,7 +1276,7 @@
 	data->attrs.attrs = adt7470_attr;
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -1299,9 +1298,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1313,7 +1309,6 @@
 	wait_for_completion(&data->auto_update_stop);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index f600fa1..ae482e3 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -862,12 +862,10 @@
 	struct amc6821_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&client->dev, "out of memory.\n");
+	data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
+			    GFP_KERNEL);
+	if (!data)
 		return -ENOMEM;
-	}
-
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -877,11 +875,11 @@
 	 */
 	err = amc6821_init_client(client);
 	if (err)
-		goto err_free;
+		return err;
 
 	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
 	if (err)
-		goto err_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (!IS_ERR(data->hwmon_dev))
@@ -890,8 +888,6 @@
 	err = PTR_ERR(data->hwmon_dev);
 	dev_err(&client->dev, "error registering hwmon device.\n");
 	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
-err_free:
-	kfree(data);
 	return err;
 }
 
@@ -902,8 +898,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 2827088..8f3f6f2 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -53,10 +53,10 @@
 
 #define APPLESMC_MAX_DATA_LENGTH 32
 
-/* wait up to 32 ms for a status change. */
+/* wait up to 128 ms for a status change. */
 #define APPLESMC_MIN_WAIT	0x0010
 #define APPLESMC_RETRY_WAIT	0x0100
-#define APPLESMC_MAX_WAIT	0x8000
+#define APPLESMC_MAX_WAIT	0x20000
 
 #define APPLESMC_READ_CMD	0x10
 #define APPLESMC_WRITE_CMD	0x11
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 4b8814d..a227be4 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -787,12 +787,10 @@
 	int err;
 	struct asb100_data *data;
 
-	data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
-	if (!data) {
-		pr_debug("probe failed, kzalloc failed!\n");
-		err = -ENOMEM;
-		goto ERROR0;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -801,7 +799,7 @@
 	/* Attach secondary lm75 clients */
 	err = asb100_detect_subclients(client);
 	if (err)
-		goto ERROR1;
+		return err;
 
 	/* Initialize the chip */
 	asb100_init_client(client);
@@ -829,9 +827,6 @@
 ERROR3:
 	i2c_unregister_device(data->lm75[1]);
 	i2c_unregister_device(data->lm75[0]);
-ERROR1:
-	kfree(data);
-ERROR0:
 	return err;
 }
 
@@ -845,8 +840,6 @@
 	i2c_unregister_device(data->lm75[1]);
 	i2c_unregister_device(data->lm75[0]);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 4ee5789..cccb0e9 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -962,7 +962,6 @@
 
 	return 1;
 out:
-	kfree(sensor->acpi_name);
 	kfree(sensor);
 	return err;
 }
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 0fa356f..984a3f1 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -815,17 +815,20 @@
 	if (err)
 		goto exit;
 
+	get_online_cpus();
 	for_each_online_cpu(i)
 		get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
+		put_online_cpus();
 		err = -ENODEV;
 		goto exit_driver_unreg;
 	}
 #endif
 
 	register_hotcpu_notifier(&coretemp_cpu_notifier);
+	put_online_cpus();
 	return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -840,6 +843,7 @@
 {
 	struct pdev_entry *p, *n;
 
+	get_online_cpus();
 	unregister_hotcpu_notifier(&coretemp_cpu_notifier);
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -848,6 +852,7 @@
 		kfree(p);
 	}
 	mutex_unlock(&pdev_list_mutex);
+	put_online_cpus();
 	platform_driver_unregister(&coretemp_driver);
 }
 
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index e7c6a19..fe0eeec 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -2475,11 +2475,9 @@
 	struct device *dev = &client->dev;
 	int err;
 
-	data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->type = id->driver_data;
@@ -2491,14 +2489,14 @@
 	err = dme1737_init_device(dev);
 	if (err) {
 		dev_err(dev, "Failed to initialize device.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Create sysfs files */
 	err = dme1737_create_files(dev);
 	if (err) {
 		dev_err(dev, "Failed to create sysfs files.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Register device */
@@ -2513,9 +2511,6 @@
 
 exit_remove:
 	dme1737_remove_files(dev);
-exit_kfree:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -2526,7 +2521,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&client->dev);
 
-	kfree(data);
 	return 0;
 }
 
@@ -2645,19 +2639,16 @@
 	int err;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+	if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
 		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
 			(unsigned short)res->start,
 			(unsigned short)res->start + DME1737_EXTENT - 1);
-		err = -EBUSY;
-		goto exit;
+		return -EBUSY;
 	}
 
-	data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release_region;
-	}
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->addr = res->start;
 	platform_set_drvdata(pdev, data);
@@ -2683,8 +2674,7 @@
 			   (device == SCH5127_DEVICE)) {
 			data->type = sch5127;
 		} else {
-			err = -ENODEV;
-			goto exit_kfree;
+			return -ENODEV;
 		}
 	}
 
@@ -2703,14 +2693,14 @@
 	err = dme1737_init_device(dev);
 	if (err) {
 		dev_err(dev, "Failed to initialize device.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Create sysfs files */
 	err = dme1737_create_files(dev);
 	if (err) {
 		dev_err(dev, "Failed to create sysfs files.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Register device */
@@ -2725,12 +2715,6 @@
 
 exit_remove_files:
 	dme1737_remove_files(dev);
-exit_kfree:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit_release_region:
-	release_region(res->start, DME1737_EXTENT);
-exit:
 	return err;
 }
 
@@ -2740,9 +2724,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&pdev->dev);
-	release_region(data->addr, DME1737_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index 50663ef..f1d6b42 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -232,11 +232,10 @@
 	struct ds620_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ds620_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -247,7 +246,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ds620_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -261,9 +260,6 @@
 
 exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &ds620_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -274,8 +270,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ds620_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 149dcb0..68ab94b 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -306,11 +306,10 @@
 	int res;
 	struct thermal_data *data;
 
-	data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
-	if (data == NULL) {
-		dev_warn(&client->dev, "out of memory");
+	data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
+			    GFP_KERNEL);
+	if (data == NULL)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->mutex);
@@ -319,21 +318,19 @@
 	res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
 	if (res) {
 		dev_warn(&client->dev, "create group failed\n");
-		goto thermal_error1;
+		return res;
 	}
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		res = PTR_ERR(data->hwmon_dev);
 		dev_warn(&client->dev, "register hwmon dev failed\n");
-		goto thermal_error2;
+		goto thermal_error;
 	}
 	dev_info(&client->dev, "EMC1403 Thermal chip found\n");
-	return res;
+	return 0;
 
-thermal_error2:
+thermal_error:
 	sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-thermal_error1:
-	kfree(data);
 	return res;
 }
 
@@ -343,7 +340,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 7bb8e88..77f434c 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -590,7 +590,8 @@
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct emc2103_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -608,7 +609,7 @@
 		if (status < 0) {
 			dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
 				status);
-			goto exit_free;
+			return status;
 		}
 
 		/* detect current state of hardware */
@@ -631,7 +632,7 @@
 	/* Register sysfs hooks */
 	status = sysfs_create_group(&client->dev.kobj, &emc2103_group);
 	if (status)
-		goto exit_free;
+		return status;
 
 	if (data->temp_count >= 3) {
 		status = sysfs_create_group(&client->dev.kobj,
@@ -666,8 +667,6 @@
 		sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &emc2103_group);
-exit_free:
-	kfree(data);
 	return status;
 }
 
@@ -685,7 +684,6 @@
 
 	sysfs_remove_group(&client->dev.kobj, &emc2103_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 6d12263..50e4ce2 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -2274,7 +2274,8 @@
 	int err, i;
 	u8 start_reg, reg;
 
-	data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -2288,13 +2289,11 @@
 	start_reg = f71882fg_read8(data, F71882FG_REG_START);
 	if (start_reg & 0x04) {
 		dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 	if (!(start_reg & 0x03)) {
 		dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	/* Register sysfs interface files */
@@ -2422,8 +2421,6 @@
 exit_unregister_sysfs:
 	f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
 	return err; /* f71882fg_remove() also frees our data */
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -2525,17 +2522,13 @@
 				ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
 		}
 	}
-
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
-static int __init f71882fg_find(int sioaddr, unsigned short *address,
-	struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
 {
 	u16 devid;
+	unsigned short address;
 	int err = superio_enter(sioaddr);
 	if (err)
 		return err;
@@ -2603,25 +2596,25 @@
 		goto exit;
 	}
 
-	*address = superio_inw(sioaddr, SIO_REG_ADDR);
-	if (*address == 0) {
+	address = superio_inw(sioaddr, SIO_REG_ADDR);
+	if (address == 0) {
 		pr_warn("Base address not set\n");
 		err = -ENODEV;
 		goto exit;
 	}
-	*address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+	address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
 
-	err = 0;
+	err = address;
 	pr_info("Found %s chip at %#x, revision %d\n",
-		f71882fg_names[sio_data->type],	(unsigned int)*address,
+		f71882fg_names[sio_data->type],	(unsigned int)address,
 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
 	superio_exit(sioaddr);
 	return err;
 }
 
-static int __init f71882fg_device_add(unsigned short address,
-	const struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_device_add(int address,
+				      const struct f71882fg_sio_data *sio_data)
 {
 	struct resource res = {
 		.start	= address,
@@ -2668,19 +2661,21 @@
 
 static int __init f71882fg_init(void)
 {
-	int err = -ENODEV;
-	unsigned short address;
+	int err;
+	int address;
 	struct f71882fg_sio_data sio_data;
 
 	memset(&sio_data, 0, sizeof(sio_data));
 
-	if (f71882fg_find(0x2e, &address, &sio_data) &&
-	    f71882fg_find(0x4e, &address, &sio_data))
-		goto exit;
+	address = f71882fg_find(0x2e, &sio_data);
+	if (address < 0)
+		address = f71882fg_find(0x4e, &sio_data);
+	if (address < 0)
+		return address;
 
 	err = platform_driver_register(&f71882fg_driver);
 	if (err)
-		goto exit;
+		return err;
 
 	err = f71882fg_device_add(address, &sio_data);
 	if (err)
@@ -2690,7 +2685,6 @@
 
 exit_driver:
 	platform_driver_unregister(&f71882fg_driver);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index ece4159..f7dba22 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -838,7 +838,8 @@
 	if (!i2c_check_functionality(client->adapter,
 				I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
-	data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -848,7 +849,7 @@
 
 	err = sysfs_create_group(&client->dev.kobj, &f75375_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->kind != f75373) {
 		err = sysfs_chmod_file(&client->dev.kobj,
@@ -875,8 +876,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &f75375_group);
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -885,7 +884,6 @@
 	struct f75375_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &f75375_group);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 2764b78..68ad7d2 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -129,12 +129,12 @@
  * counter saturations resulting in bogus power readings.
  * We correct this value ourselves to cope with older BIOSes.
  */
-static DEFINE_PCI_DEVICE_TABLE(affected_device) = {
+static const struct pci_device_id affected_device[] = {
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
 	{ 0 }
 };
 
-static void __devinit tweak_runavg_range(struct pci_dev *pdev)
+static void tweak_runavg_range(struct pci_dev *pdev)
 {
 	u32 val;
 
@@ -158,6 +158,16 @@
 		REG_TDP_RUNNING_AVERAGE, val);
 }
 
+#ifdef CONFIG_PM
+static int fam15h_power_resume(struct pci_dev *pdev)
+{
+	tweak_runavg_range(pdev);
+	return 0;
+}
+#else
+#define fam15h_power_resume NULL
+#endif
+
 static void __devinit fam15h_power_init_data(struct pci_dev *f4,
 					     struct fam15h_power_data *data)
 {
@@ -188,7 +198,7 @@
 					const struct pci_device_id *id)
 {
 	struct fam15h_power_data *data;
-	struct device *dev;
+	struct device *dev = &pdev->dev;
 	int err;
 
 	/*
@@ -198,23 +208,19 @@
 	 */
 	tweak_runavg_range(pdev);
 
-	if (!fam15h_power_is_internal_node0(pdev)) {
-		err = -ENODEV;
-		goto exit;
-	}
+	if (!fam15h_power_is_internal_node0(pdev))
+		return -ENODEV;
 
-	data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	fam15h_power_init_data(pdev, data);
-	dev = &pdev->dev;
 
 	dev_set_drvdata(dev, data);
 	err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
 	if (err)
-		goto exit_free_data;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +232,6 @@
 
 exit_remove_group:
 	sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-exit_free_data:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -241,8 +244,6 @@
 	data = dev_get_drvdata(dev);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-	dev_set_drvdata(dev, NULL);
-	kfree(data);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
@@ -256,6 +257,7 @@
 	.id_table = fam15h_power_id_table,
 	.probe = fam15h_power_probe,
 	.remove = __devexit_p(fam15h_power_remove),
+	.resume = fam15h_power_resume,
 };
 
 module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index ebcd269..8b2106f 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -207,7 +207,8 @@
 				     I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct g760a_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct g760a_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -223,7 +224,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &g760a_group);
 	if (err)
-		goto error_sysfs_create_group;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -235,9 +236,6 @@
 
 error_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &g760a_group);
-error_sysfs_create_group:
-	kfree(data);
-
 	return err;
 }
 
@@ -246,8 +244,6 @@
 	struct g760a_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &g760a_group);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 6021482..70717d4 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -5,10 +5,18 @@
  * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
  * Datasheet: http://www.ti.com/product/ina219
  *
+ * INA220:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina220
+ *
  * INA226:
  * Bi-Directional Current/Power Monitor with I2C Interface
  * Datasheet: http://www.ti.com/product/ina226
  *
+ * INA230:
+ * Bi-directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina230
+ *
  * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
  * Thanks to Jan Volkering
  *
@@ -57,18 +65,49 @@
 
 enum ina2xx_ids { ina219, ina226 };
 
+struct ina2xx_config {
+	u16 config_default;
+	int calibration_factor;
+	int registers;
+	int shunt_div;
+	int bus_voltage_shift;
+	int bus_voltage_lsb;	/* uV */
+	int power_lsb;		/* uW */
+};
+
 struct ina2xx_data {
 	struct device *hwmon_dev;
+	const struct ina2xx_config *config;
 
 	struct mutex update_lock;
 	bool valid;
 	unsigned long last_updated;
 
 	int kind;
-	int registers;
 	u16 regs[INA2XX_MAX_REGISTERS];
 };
 
+static const struct ina2xx_config ina2xx_config[] = {
+	[ina219] = {
+		.config_default = INA219_CONFIG_DEFAULT,
+		.calibration_factor = 40960000,
+		.registers = INA219_REGISTERS,
+		.shunt_div = 100,
+		.bus_voltage_shift = 3,
+		.bus_voltage_lsb = 4000,
+		.power_lsb = 20000,
+	},
+	[ina226] = {
+		.config_default = INA226_CONFIG_DEFAULT,
+		.calibration_factor = 5120000,
+		.registers = INA226_REGISTERS,
+		.shunt_div = 400,
+		.bus_voltage_shift = 0,
+		.bus_voltage_lsb = 1250,
+		.power_lsb = 25000,
+	},
+};
+
 static struct ina2xx_data *ina2xx_update_device(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -85,7 +124,7 @@
 		dev_dbg(&client->dev, "Starting ina2xx update\n");
 
 		/* Read all registers */
-		for (i = 0; i < data->registers; i++) {
+		for (i = 0; i < data->config->registers; i++) {
 			int rv = i2c_smbus_read_word_swapped(client, i);
 			if (rv < 0) {
 				ret = ERR_PTR(rv);
@@ -101,73 +140,26 @@
 	return ret;
 }
 
-static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
 {
-	/*
-	 * calculate exact value for the given register
-	 * we assume default power-on reset settings:
-	 * bus voltage range 32V
-	 * gain = /8
-	 * adc 1 & 2 -> conversion time 532uS
-	 * mode is continuous shunt and bus
-	 * calibration value is INA219_CALIBRATION_VALUE
-	 */
-	int val = data->regs[reg];
+	int val;
 
 	switch (reg) {
 	case INA2XX_SHUNT_VOLTAGE:
-		/* LSB=10uV. Convert to mV. */
-		val = DIV_ROUND_CLOSEST(val, 100);
+		val = DIV_ROUND_CLOSEST(data->regs[reg],
+					data->config->shunt_div);
 		break;
 	case INA2XX_BUS_VOLTAGE:
-		/* LSB=4mV. Register is not right aligned, convert to mV. */
-		val = (val >> 3) * 4;
+		val = (data->regs[reg] >> data->config->bus_voltage_shift)
+		  * data->config->bus_voltage_lsb;
+		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_POWER:
-		/* LSB=20mW. Convert to uW */
-		val = val * 20 * 1000;
+		val = data->regs[reg] * data->config->power_lsb;
 		break;
 	case INA2XX_CURRENT:
 		/* LSB=1mA (selected). Is in mA */
-		break;
-	default:
-		/* programmer goofed */
-		WARN_ON_ONCE(1);
-		val = 0;
-		break;
-	}
-
-	return val;
-}
-
-static int ina226_get_value(struct ina2xx_data *data, u8 reg)
-{
-	/*
-	 * calculate exact value for the given register
-	 * we assume default power-on reset settings:
-	 * bus voltage range 32V
-	 * gain = /8
-	 * adc 1 & 2 -> conversion time 532uS
-	 * mode is continuous shunt and bus
-	 * calibration value is INA226_CALIBRATION_VALUE
-	 */
-	int val = data->regs[reg];
-
-	switch (reg) {
-	case INA2XX_SHUNT_VOLTAGE:
-		/* LSB=2.5uV. Convert to mV. */
-		val = DIV_ROUND_CLOSEST(val, 400);
-		break;
-	case INA2XX_BUS_VOLTAGE:
-		/* LSB=1.25mV. Convert to mV. */
-		val = val + DIV_ROUND_CLOSEST(val, 4);
-		break;
-	case INA2XX_POWER:
-		/* LSB=25mW. Convert to uW */
-		val = val * 25 * 1000;
-		break;
-	case INA2XX_CURRENT:
-		/* LSB=1mA (selected). Is in mA */
+		val = data->regs[reg];
 		break;
 	default:
 		/* programmer goofed */
@@ -184,23 +176,12 @@
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct ina2xx_data *data = ina2xx_update_device(dev);
-	int value = 0;
 
 	if (IS_ERR(data))
 		return PTR_ERR(data);
 
-	switch (data->kind) {
-	case ina219:
-		value = ina219_get_value(data, attr->index);
-		break;
-	case ina226:
-		value = ina226_get_value(data, attr->index);
-		break;
-	default:
-		WARN_ON_ONCE(1);
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			ina2xx_get_value(data, attr->index));
 }
 
 /* shunt voltage */
@@ -238,7 +219,7 @@
 	struct i2c_adapter *adapter = client->adapter;
 	struct ina2xx_data *data;
 	struct ina2xx_platform_data *pdata;
-	int ret = 0;
+	int ret;
 	long shunt = 10000; /* default shunt value 10mOhms */
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
@@ -259,38 +240,15 @@
 
 	/* set the device type */
 	data->kind = id->driver_data;
+	data->config = &ina2xx_config[data->kind];
 
-	switch (data->kind) {
-	case ina219:
-		/* device configuration */
-		i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
-					     INA219_CONFIG_DEFAULT);
-
-		/* set current LSB to 1mA, shunt is in uOhms */
-		/* (equation 13 in datasheet) */
-		i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
-					     40960000 / shunt);
-		dev_info(&client->dev,
-			 "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
-		data->registers = INA219_REGISTERS;
-		break;
-	case ina226:
-		/* device configuration */
-		i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
-					     INA226_CONFIG_DEFAULT);
-
-		/* set current LSB to 1mA, shunt is in uOhms */
-		/* (equation 1 in datasheet)*/
-		i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
-					     5120000 / shunt);
-		dev_info(&client->dev,
-			 "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
-		data->registers = INA226_REGISTERS;
-		break;
-	default:
-		/* unknown device id */
-		return -ENODEV;
-	}
+	/* device configuration */
+	i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+				     data->config->config_default);
+	/* set current LSB to 1mA, shunt is in uOhms */
+	/* (equation 13 in datasheet) */
+	i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+				     data->config->calibration_factor / shunt);
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -305,6 +263,9 @@
 		goto out_err_hwmon;
 	}
 
+	dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n",
+		 id->name, shunt);
+
 	return 0;
 
 out_err_hwmon:
@@ -324,7 +285,9 @@
 
 static const struct i2c_device_id ina2xx_id[] = {
 	{ "ina219", ina219 },
+	{ "ina220", ina219 },
 	{ "ina226", ina226 },
+	{ "ina230", ina226 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ina2xx_id);
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
index 5253d23..dee9eec 100644
--- a/drivers/hwmon/jz4740-hwmon.c
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
 #include <linux/completion.h>
 #include <linux/mfd/core.h>
@@ -106,42 +107,37 @@
 	int ret;
 	struct jz4740_hwmon *hwmon;
 
-	hwmon = kmalloc(sizeof(*hwmon), GFP_KERNEL);
-	if (!hwmon) {
-		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
 		return -ENOMEM;
-	}
 
 	hwmon->cell = mfd_get_cell(pdev);
 
 	hwmon->irq = platform_get_irq(pdev, 0);
 	if (hwmon->irq < 0) {
-		ret = hwmon->irq;
-		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
-		goto err_free;
+		dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+			hwmon->irq);
+		return hwmon->irq;
 	}
 
 	hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!hwmon->mem) {
-		ret = -ENOENT;
 		dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
-		goto err_free;
+		return -ENOENT;
 	}
 
-	hwmon->mem = request_mem_region(hwmon->mem->start,
+	hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
 			resource_size(hwmon->mem), pdev->name);
 	if (!hwmon->mem) {
-		ret = -EBUSY;
 		dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-		goto err_free;
+		return -EBUSY;
 	}
 
-	hwmon->base = ioremap_nocache(hwmon->mem->start,
-			resource_size(hwmon->mem));
+	hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
+					   resource_size(hwmon->mem));
 	if (!hwmon->base) {
-		ret = -EBUSY;
 		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-		goto err_release_mem_region;
+		return -EBUSY;
 	}
 
 	init_completion(&hwmon->read_completion);
@@ -149,17 +145,18 @@
 
 	platform_set_drvdata(pdev, hwmon);
 
-	ret = request_irq(hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon);
+	ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
+			       pdev->name, hwmon);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-		goto err_iounmap;
+		return ret;
 	}
 	disable_irq(hwmon->irq);
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
-		goto err_free_irq;
+		return ret;
 	}
 
 	hwmon->hwmon = hwmon_device_register(&pdev->dev);
@@ -172,16 +169,6 @@
 
 err_remove_file:
 	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
-err_free_irq:
-	free_irq(hwmon->irq, hwmon);
-err_iounmap:
-	platform_set_drvdata(pdev, NULL);
-	iounmap(hwmon->base);
-err_release_mem_region:
-	release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-err_free:
-	kfree(hwmon);
-
 	return ret;
 }
 
@@ -192,14 +179,6 @@
 	hwmon_device_unregister(hwmon->hwmon);
 	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
 
-	free_irq(hwmon->irq, hwmon);
-
-	iounmap(hwmon->base);
-	release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-
-	platform_set_drvdata(pdev, NULL);
-	kfree(hwmon);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 472f795..2d1777a 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -43,6 +43,8 @@
 
 #define LM70_CHIP_LM70		0	/* original NS LM70 */
 #define LM70_CHIP_TMP121	1	/* TI TMP121/TMP123 */
+#define LM70_CHIP_LM71		2	/* NS LM71 */
+#define LM70_CHIP_LM74		3	/* NS LM74 */
 
 struct lm70 {
 	struct device *hwmon_dev;
@@ -88,9 +90,13 @@
 	 * Celsius.
 	 * So it's equivalent to multiplying by 0.25 * 1000 = 250.
 	 *
-	 * TMP121/TMP123:
+	 * LM74 and TMP121/TMP123:
 	 * 13 bits of 2's complement data, discard LSB 3 bits,
 	 * resolution 0.0625 degrees celsius.
+	 *
+	 * LM71:
+	 * 14 bits of 2's complement data, discard LSB 2 bits,
+	 * resolution 0.0312 degrees celsius.
 	 */
 	switch (p_lm70->chip) {
 	case LM70_CHIP_LM70:
@@ -98,8 +104,13 @@
 		break;
 
 	case LM70_CHIP_TMP121:
+	case LM70_CHIP_LM74:
 		val = ((int)raw / 8) * 625 / 10;
 		break;
+
+	case LM70_CHIP_LM71:
+		val = ((int)raw / 4) * 3125 / 100;
+		break;
 	}
 
 	status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
@@ -113,20 +124,7 @@
 static ssize_t lm70_show_name(struct device *dev, struct device_attribute
 			      *devattr, char *buf)
 {
-	struct lm70 *p_lm70 = dev_get_drvdata(dev);
-	int ret;
-
-	switch (p_lm70->chip) {
-	case LM70_CHIP_LM70:
-		ret = sprintf(buf, "lm70\n");
-		break;
-	case LM70_CHIP_TMP121:
-		ret = sprintf(buf, "tmp121\n");
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	return ret;
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
 }
 
 static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
@@ -139,17 +137,13 @@
 	struct lm70 *p_lm70;
 	int status;
 
-	/* signaling is SPI_MODE_0 for both LM70 and TMP121 */
+	/* signaling is SPI_MODE_0 */
 	if (spi->mode & (SPI_CPOL | SPI_CPHA))
 		return -EINVAL;
 
-	/* 3-wire link (shared SI/SO) for LM70 */
-	if (chip == LM70_CHIP_LM70 && !(spi->mode & SPI_3WIRE))
-		return -EINVAL;
-
 	/* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
 
-	p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
+	p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL);
 	if (!p_lm70)
 		return -ENOMEM;
 
@@ -181,7 +175,6 @@
 	device_remove_file(&spi->dev, &dev_attr_temp1_input);
 out_dev_create_temp_file_failed:
 	spi_set_drvdata(spi, NULL);
-	kfree(p_lm70);
 	return status;
 }
 
@@ -193,7 +186,6 @@
 	device_remove_file(&spi->dev, &dev_attr_temp1_input);
 	device_remove_file(&spi->dev, &dev_attr_name);
 	spi_set_drvdata(spi, NULL);
-	kfree(p_lm70);
 
 	return 0;
 }
@@ -202,6 +194,8 @@
 static const struct spi_device_id lm70_ids[] = {
 	{ "lm70",   LM70_CHIP_LM70 },
 	{ "tmp121", LM70_CHIP_TMP121 },
+	{ "lm71",   LM70_CHIP_LM71 },
+	{ "lm74",   LM70_CHIP_LM74 },
 	{ },
 };
 MODULE_DEVICE_TABLE(spi, lm70_ids);
@@ -219,5 +213,5 @@
 module_spi_driver(lm70_driver);
 
 MODULE_AUTHOR("Kaiwan N Billimoria");
-MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
+MODULE_DESCRIPTION("NS LM70 and compatibles Linux driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index bf94618..c3d4255 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -1830,7 +1830,7 @@
 
 	mutex_lock(&data->update_lock);
 	/* sanity test, ignore the write otherwise */
-	if (0 <= val && val <= 2) {
+	if (val <= 2) {
 		/* can't enable if pwm freq is 22.5KHz */
 		if (val) {
 			u8 ctl4 = lm93_read_byte(client,
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index bd8cdb7..4b68fb2 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -391,11 +391,10 @@
 	struct lm95241_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -406,7 +405,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -418,9 +417,6 @@
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -431,7 +427,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm95241_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 9a46c10..2915fd9 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -462,11 +462,10 @@
 	struct lm95245_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -477,7 +476,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -489,9 +488,6 @@
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -502,7 +498,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm95245_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
index 4d005b2..8496baa 100644
--- a/drivers/hwmon/ltc4151.c
+++ b/drivers/hwmon/ltc4151.c
@@ -181,11 +181,9 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -193,7 +191,7 @@
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &ltc4151_group);
 	if (ret)
-		goto out_sysfs_create_group;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -205,9 +203,6 @@
 
 out_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
-out_sysfs_create_group:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -218,8 +213,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 429c5b2..98b3d04f 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -253,11 +253,9 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -268,7 +266,7 @@
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
 	if (ret)
-		goto out_sysfs_create_group;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +278,6 @@
 
 out_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-out_sysfs_create_group:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -293,8 +288,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index b99b45b..52075914 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -519,11 +519,9 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -536,7 +534,7 @@
 	/* Register sysfs hooks */
 	ret = ltc4245_sysfs_create_groups(client);
 	if (ret)
-		goto out_sysfs_create_groups;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -548,9 +546,6 @@
 
 out_hwmon_device_register:
 	ltc4245_sysfs_remove_groups(client);
-out_sysfs_create_groups:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -560,7 +555,6 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	ltc4245_sysfs_remove_groups(client);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
index f3978a4..b4eb088 100644
--- a/drivers/hwmon/max1111.c
+++ b/drivers/hwmon/max1111.c
@@ -22,6 +22,8 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
+enum chips { max1110, max1111, max1112, max1113 };
+
 #define MAX1111_TX_BUF_SIZE	1
 #define MAX1111_RX_BUF_SIZE	2
 
@@ -30,6 +32,7 @@
 #define MAX1111_CTRL_PD1      (1u << 1)
 #define MAX1111_CTRL_SGL      (1u << 2)
 #define MAX1111_CTRL_UNI      (1u << 3)
+#define MAX1110_CTRL_SEL_SH   (4)
 #define MAX1111_CTRL_SEL_SH   (5)	/* NOTE: bit 4 is ignored */
 #define MAX1111_CTRL_STR      (1u << 7)
 
@@ -42,6 +45,8 @@
 	uint8_t rx_buf[MAX1111_RX_BUF_SIZE];
 	struct mutex		drvdata_lock;
 	/* protect msg, xfer and buffers from multiple access */
+	int			sel_sh;
+	int			lsb;
 };
 
 static int max1111_read(struct device *dev, int channel)
@@ -53,7 +58,7 @@
 	/* writing to drvdata struct is not thread safe, wait on mutex */
 	mutex_lock(&data->drvdata_lock);
 
-	data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) |
+	data->tx_buf[0] = (channel << data->sel_sh) |
 		MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 |
 		MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR;
 
@@ -93,12 +98,13 @@
 static ssize_t show_name(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "max1111\n");
+	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
 }
 
 static ssize_t show_adc(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
+	struct max1111_data *data = dev_get_drvdata(dev);
 	int channel = to_sensor_dev_attr(attr)->index;
 	int ret;
 
@@ -107,10 +113,10 @@
 		return ret;
 
 	/*
-	 * assume the reference voltage to be 2.048V, with an 8-bit sample,
-	 * the LSB weight is 8mV
+	 * Assume the reference voltage to be 2.048V or 4.096V, with an 8-bit
+	 * sample. The LSB weight is 8mV or 16mV depending on the chip type.
 	 */
-	return sprintf(buf, "%d\n", ret * 8);
+	return sprintf(buf, "%d\n", ret * data->lsb);
 }
 
 #define MAX1111_ADC_ATTR(_id)		\
@@ -121,6 +127,10 @@
 static MAX1111_ADC_ATTR(1);
 static MAX1111_ADC_ATTR(2);
 static MAX1111_ADC_ATTR(3);
+static MAX1111_ADC_ATTR(4);
+static MAX1111_ADC_ATTR(5);
+static MAX1111_ADC_ATTR(6);
+static MAX1111_ADC_ATTR(7);
 
 static struct attribute *max1111_attributes[] = {
 	&dev_attr_name.attr,
@@ -135,6 +145,18 @@
 	.attrs	= max1111_attributes,
 };
 
+static struct attribute *max1110_attributes[] = {
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group max1110_attr_group = {
+	.attrs	= max1110_attributes,
+};
+
 static int __devinit setup_transfer(struct max1111_data *data)
 {
 	struct spi_message *m;
@@ -159,6 +181,7 @@
 
 static int __devinit max1111_probe(struct spi_device *spi)
 {
+	enum chips chip = spi_get_device_id(spi)->driver_data;
 	struct max1111_data *data;
 	int err;
 
@@ -174,6 +197,24 @@
 		return -ENOMEM;
 	}
 
+	switch (chip) {
+	case max1110:
+		data->lsb = 8;
+		data->sel_sh = MAX1110_CTRL_SEL_SH;
+		break;
+	case max1111:
+		data->lsb = 8;
+		data->sel_sh = MAX1111_CTRL_SEL_SH;
+		break;
+	case max1112:
+		data->lsb = 16;
+		data->sel_sh = MAX1110_CTRL_SEL_SH;
+		break;
+	case max1113:
+		data->lsb = 16;
+		data->sel_sh = MAX1111_CTRL_SEL_SH;
+		break;
+	}
 	err = setup_transfer(data);
 	if (err)
 		return err;
@@ -188,6 +229,14 @@
 		dev_err(&spi->dev, "failed to create attribute group\n");
 		return err;
 	}
+	if (chip == max1110 || chip == max1112) {
+		err = sysfs_create_group(&spi->dev.kobj, &max1110_attr_group);
+		if (err) {
+			dev_err(&spi->dev,
+				"failed to create extended attribute group\n");
+			goto err_remove;
+		}
+	}
 
 	data->hwmon_dev = hwmon_device_register(&spi->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -202,6 +251,7 @@
 	return 0;
 
 err_remove:
+	sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
 	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
 	return err;
 }
@@ -211,16 +261,27 @@
 	struct max1111_data *data = spi_get_drvdata(spi);
 
 	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
 	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
 	mutex_destroy(&data->drvdata_lock);
 	return 0;
 }
 
+static const struct spi_device_id max1111_ids[] = {
+	{ "max1110", max1110 },
+	{ "max1111", max1111 },
+	{ "max1112", max1112 },
+	{ "max1113", max1113 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, max1111_ids);
+
 static struct spi_driver max1111_driver = {
 	.driver		= {
 		.name	= "max1111",
 		.owner	= THIS_MODULE,
 	},
+	.id_table	= max1111_ids,
 	.probe		= max1111_probe,
 	.remove		= __devexit_p(max1111_remove),
 };
@@ -228,6 +289,5 @@
 module_spi_driver(max1111_driver);
 
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
-MODULE_DESCRIPTION("MAX1111 ADC Driver");
+MODULE_DESCRIPTION("MAX1110/MAX1111/MAX1112/MAX1113 ADC Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:max1111");
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index 335b183..666d9f6 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -411,7 +411,8 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -422,7 +423,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
 	if (err)
-		goto error_free;
+		return err;
 
 	if (data->type == max1668 || data->type == max1989) {
 		err = sysfs_create_group(&client->dev.kobj,
@@ -444,8 +445,6 @@
 		sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
 error_sysrem0:
 	sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-error_free:
-	kfree(data);
 	return err;
 }
 
@@ -459,7 +458,6 @@
 
 	sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
new file mode 100644
index 0000000..6304f26
--- /dev/null
+++ b/drivers/hwmon/max197.c
@@ -0,0 +1,349 @@
+/*
+ * Maxim MAX197 A/D Converter driver
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/max197 file.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/max197.h>
+
+#define MAX199_LIMIT	4000		/* 4V */
+#define MAX197_LIMIT	10000		/* 10V */
+
+#define MAX197_NUM_CH	8		/* 8 Analog Input Channels */
+
+/* Control byte format */
+#define MAX197_BIP	(1 << 3)	/* Bipolarity */
+#define MAX197_RNG	(1 << 4)	/* Full range */
+
+#define MAX197_SCALE	12207		/* Scale coefficient for raw data */
+
+/* List of supported chips */
+enum max197_chips { max197, max199 };
+
+/**
+ * struct max197_data - device instance specific data
+ * @pdata:		Platform data.
+ * @hwmon_dev:		The hwmon device.
+ * @lock:		Read/Write mutex.
+ * @limit:		Max range value (10V for MAX197, 4V for MAX199).
+ * @scale:		Need to scale.
+ * @ctrl_bytes:		Channels control byte.
+ */
+struct max197_data {
+	struct max197_platform_data *pdata;
+	struct device *hwmon_dev;
+	struct mutex lock;
+	int limit;
+	bool scale;
+	u8 ctrl_bytes[MAX197_NUM_CH];
+};
+
+static inline void max197_set_unipolarity(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] &= ~MAX197_BIP;
+}
+
+static inline void max197_set_bipolarity(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] |= MAX197_BIP;
+}
+
+static inline void max197_set_half_range(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] &= ~MAX197_RNG;
+}
+
+static inline void max197_set_full_range(struct max197_data *data, int channel)
+{
+	data->ctrl_bytes[channel] |= MAX197_RNG;
+}
+
+static inline bool max197_is_bipolar(struct max197_data *data, int channel)
+{
+	return data->ctrl_bytes[channel] & MAX197_BIP;
+}
+
+static inline bool max197_is_full_range(struct max197_data *data, int channel)
+{
+	return data->ctrl_bytes[channel] & MAX197_RNG;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_show_range(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int channel = attr->index;
+	bool is_min = attr->nr;
+	int range;
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	range = max197_is_full_range(data, channel) ?
+		data->limit : data->limit / 2;
+	if (is_min) {
+		if (max197_is_bipolar(data, channel))
+			range = -range;
+		else
+			range = 0;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return sprintf(buf, "%d\n", range);
+}
+
+/* Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max} */
+static ssize_t max197_store_range(struct device *dev,
+				  struct device_attribute *devattr,
+				  const char *buf, size_t count)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int channel = attr->index;
+	bool is_min = attr->nr;
+	long value;
+	int half = data->limit / 2;
+	int full = data->limit;
+
+	if (kstrtol(buf, 10, &value))
+		return -EINVAL;
+
+	if (is_min) {
+		if (value <= -full)
+			value = -full;
+		else if (value < 0)
+			value = -half;
+		else
+			value = 0;
+	} else {
+		if (value >= full)
+			value = full;
+		else
+			value = half;
+	}
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	if (value == 0) {
+		/* We can deduce only the polarity */
+		max197_set_unipolarity(data, channel);
+	} else if (value == -half) {
+		max197_set_bipolarity(data, channel);
+		max197_set_half_range(data, channel);
+	} else if (value == -full) {
+		max197_set_bipolarity(data, channel);
+		max197_set_full_range(data, channel);
+	} else if (value == half) {
+		/* We can deduce only the range */
+		max197_set_half_range(data, channel);
+	} else if (value == full) {
+		/* We can deduce only the range */
+		max197_set_full_range(data, channel);
+	}
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+/* Function called on read access on in{0,1,2,3,4,5,6,7}_input */
+static ssize_t max197_show_input(struct device *dev,
+				 struct device_attribute *devattr,
+				 char *buf)
+{
+	struct max197_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int channel = attr->index;
+	s32 value;
+	int ret;
+
+	if (mutex_lock_interruptible(&data->lock))
+		return -ERESTARTSYS;
+
+	ret = data->pdata->convert(data->ctrl_bytes[channel]);
+	if (ret < 0) {
+		dev_err(dev, "conversion failed\n");
+		goto unlock;
+	}
+	value = ret;
+
+	/*
+	 * Coefficient to apply on raw value.
+	 * See Table 1. Full Scale and Zero Scale in the MAX197 datasheet.
+	 */
+	if (data->scale) {
+		value *= MAX197_SCALE;
+		if (max197_is_full_range(data, channel))
+			value *= 2;
+		value /= 10000;
+	}
+
+	ret = sprintf(buf, "%d\n", value);
+
+unlock:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+static ssize_t max197_show_name(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	return sprintf(buf, "%s\n", pdev->name);
+}
+
+#define MAX197_SENSOR_DEVICE_ATTR_CH(chan)				\
+	static SENSOR_DEVICE_ATTR(in##chan##_input, S_IRUGO,		\
+				  max197_show_input, NULL, chan);	\
+	static SENSOR_DEVICE_ATTR_2(in##chan##_min, S_IRUGO | S_IWUSR,	\
+				    max197_show_range,			\
+				    max197_store_range,			\
+				    true, chan);			\
+	static SENSOR_DEVICE_ATTR_2(in##chan##_max, S_IRUGO | S_IWUSR,	\
+				    max197_show_range,			\
+				    max197_store_range,			\
+				    false, chan)
+
+#define MAX197_SENSOR_DEV_ATTR_IN(chan)					\
+	&sensor_dev_attr_in##chan##_input.dev_attr.attr,		\
+	&sensor_dev_attr_in##chan##_max.dev_attr.attr,			\
+	&sensor_dev_attr_in##chan##_min.dev_attr.attr
+
+static DEVICE_ATTR(name, S_IRUGO, max197_show_name, NULL);
+
+MAX197_SENSOR_DEVICE_ATTR_CH(0);
+MAX197_SENSOR_DEVICE_ATTR_CH(1);
+MAX197_SENSOR_DEVICE_ATTR_CH(2);
+MAX197_SENSOR_DEVICE_ATTR_CH(3);
+MAX197_SENSOR_DEVICE_ATTR_CH(4);
+MAX197_SENSOR_DEVICE_ATTR_CH(5);
+MAX197_SENSOR_DEVICE_ATTR_CH(6);
+MAX197_SENSOR_DEVICE_ATTR_CH(7);
+
+static const struct attribute_group max197_sysfs_group = {
+	.attrs = (struct attribute *[]) {
+		&dev_attr_name.attr,
+		MAX197_SENSOR_DEV_ATTR_IN(0),
+		MAX197_SENSOR_DEV_ATTR_IN(1),
+		MAX197_SENSOR_DEV_ATTR_IN(2),
+		MAX197_SENSOR_DEV_ATTR_IN(3),
+		MAX197_SENSOR_DEV_ATTR_IN(4),
+		MAX197_SENSOR_DEV_ATTR_IN(5),
+		MAX197_SENSOR_DEV_ATTR_IN(6),
+		MAX197_SENSOR_DEV_ATTR_IN(7),
+		NULL
+	},
+};
+
+static int __devinit max197_probe(struct platform_device *pdev)
+{
+	int ch, ret;
+	struct max197_data *data;
+	struct max197_platform_data *pdata = pdev->dev.platform_data;
+	enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+
+	if (pdata->convert == NULL) {
+		dev_err(&pdev->dev, "no convert function supplied\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "devm_kzalloc failed\n");
+		return -ENOMEM;
+	}
+
+	data->pdata = pdata;
+	mutex_init(&data->lock);
+
+	if (chip == max197) {
+		data->limit = MAX197_LIMIT;
+		data->scale = true;
+	} else {
+		data->limit = MAX199_LIMIT;
+		data->scale = false;
+	}
+
+	for (ch = 0; ch < MAX197_NUM_CH; ch++)
+		data->ctrl_bytes[ch] = (u8) ch;
+
+	platform_set_drvdata(pdev, data);
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &max197_sysfs_group);
+	if (ret) {
+		dev_err(&pdev->dev, "sysfs create group failed\n");
+		return ret;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		dev_err(&pdev->dev, "hwmon device register failed\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+	return ret;
+}
+
+static int __devexit max197_remove(struct platform_device *pdev)
+{
+	struct max197_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
+
+	return 0;
+}
+
+static struct platform_device_id max197_device_ids[] = {
+	{ "max197", max197 },
+	{ "max199", max199 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max197_device_ids);
+
+static struct platform_driver max197_driver = {
+	.driver = {
+		.name = "max197",
+		.owner = THIS_MODULE,
+	},
+	.probe = max197_probe,
+	.remove = __devexit_p(max197_remove),
+	.id_table = max197_device_ids,
+};
+module_platform_driver(max197_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index d0afc0c..eedb322 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -1,8 +1,9 @@
 /*
- * mcp3021.c - driver for the Microchip MCP3021 chip
+ * mcp3021.c - driver for Microchip MCP3021 and MCP3221
  *
  * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
  * Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
  *
  * This driver export the value of analog input voltage to sysfs, the
  * voltage unit is mV. Through the sysfs interface, lm-sensors tool
@@ -34,16 +35,31 @@
 #define MCP3021_OUTPUT_RES	10	/* 10-bit resolution */
 #define MCP3021_OUTPUT_SCALE	4
 
+#define MCP3221_SAR_SHIFT	0
+#define MCP3221_SAR_MASK	0xfff
+#define MCP3221_OUTPUT_RES	12	/* 12-bit resolution */
+#define MCP3221_OUTPUT_SCALE	1
+
+enum chips {
+	mcp3021,
+	mcp3221
+};
+
 /*
  * Client data (each client gets its own)
  */
 struct mcp3021_data {
 	struct device *hwmon_dev;
 	u32 vdd;	/* device power supply */
+	u16 sar_shift;
+	u16 sar_mask;
+	u8 output_res;
+	u8 output_scale;
 };
 
 static int mcp3021_read16(struct i2c_client *client)
 {
+	struct mcp3021_data *data = i2c_get_clientdata(client);
 	int ret;
 	u16 reg;
 	__be16 buf;
@@ -61,20 +77,20 @@
 	 * The ten-bit output code is composed of the lower 4-bit of the
 	 * first byte and the upper 6-bit of the second byte.
 	 */
-	reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
+	reg = (reg >> data->sar_shift) & data->sar_mask;
 
 	return reg;
 }
 
-static inline u16 volts_from_reg(u16 vdd, u16 val)
+static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
 {
 	if (val == 0)
 		return 0;
 
-	val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
+	val = val * data->output_scale - data->output_scale / 2;
 
-	return val * DIV_ROUND_CLOSEST(vdd,
-			(1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
+	return val * DIV_ROUND_CLOSEST(data->vdd,
+			(1 << data->output_res) * data->output_scale);
 }
 
 static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
@@ -88,7 +104,8 @@
 	if (reg < 0)
 		return reg;
 
-	in_input = volts_from_reg(data->vdd, reg);
+	in_input = volts_from_reg(data, reg);
+
 	return sprintf(buf, "%d\n", in_input);
 }
 
@@ -103,25 +120,39 @@
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 
+	switch (id->driver_data) {
+	case mcp3021:
+		data->sar_shift = MCP3021_SAR_SHIFT;
+		data->sar_mask = MCP3021_SAR_MASK;
+		data->output_res = MCP3021_OUTPUT_RES;
+		data->output_scale = MCP3021_OUTPUT_SCALE;
+		break;
+
+	case mcp3221:
+		data->sar_shift = MCP3221_SAR_SHIFT;
+		data->sar_mask = MCP3221_SAR_MASK;
+		data->output_res = MCP3221_OUTPUT_RES;
+		data->output_scale = MCP3221_OUTPUT_SCALE;
+		break;
+	}
+
 	if (client->dev.platform_data) {
 		data->vdd = *(u32 *)client->dev.platform_data;
-		if (data->vdd > MCP3021_VDD_MAX ||
-				data->vdd < MCP3021_VDD_MIN) {
-			err = -EINVAL;
-			goto exit_free;
-		}
+		if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
+			return -EINVAL;
 	} else
 		data->vdd = MCP3021_VDD_REF;
 
 	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -133,8 +164,6 @@
 
 exit_remove:
 	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -144,13 +173,13 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-	kfree(data);
 
 	return 0;
 }
 
 static const struct i2c_device_id mcp3021_id[] = {
-	{ "mcp3021", 0 },
+	{ "mcp3021", mcp3021 },
+	{ "mcp3221", mcp3221 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mcp3021_id);
@@ -167,5 +196,5 @@
 module_i2c_driver(mcp3021_driver);
 
 MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
-MODULE_DESCRIPTION("Microchip MCP3021 driver");
+MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 8342275..49f6230 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -461,8 +461,6 @@
 		hwmon_device_unregister(data->hwmon_dev);
 
 	sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
@@ -472,7 +470,8 @@
 	struct sch5627_data *data;
 	int err, build_code, build_id, hwmon_rev, val;
 
-	data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
index 96a7e68..5171180 100644
--- a/drivers/hwmon/sch5636.c
+++ b/drivers/hwmon/sch5636.c
@@ -402,9 +402,6 @@
 		device_remove_file(&pdev->dev,
 				   &sch5636_fan_attr[i].dev_attr);
 
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
@@ -414,7 +411,8 @@
 	int i, err, val, revision[2];
 	char id[4];
 
-	data = kzalloc(sizeof(struct sch5636_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5636_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 4380f5d..d00b30a 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -503,10 +503,10 @@
  * platform dev find, add and remove functions
  */
 
-static int __init sch56xx_find(int sioaddr, unsigned short *address,
-			       const char **name)
+static int __init sch56xx_find(int sioaddr, const char **name)
 {
 	u8 devid;
+	unsigned short address;
 	int err;
 
 	err = superio_enter(sioaddr);
@@ -540,20 +540,21 @@
 	 * Warning the order of the low / high byte is the other way around
 	 * as on most other superio devices!!
 	 */
-	*address = superio_inb(sioaddr, SIO_REG_ADDR) |
+	address = superio_inb(sioaddr, SIO_REG_ADDR) |
 		   superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
-	if (*address == 0) {
+	if (address == 0) {
 		pr_warn("Base address not set\n");
 		err = -ENODEV;
 		goto exit;
 	}
+	err = address;
 
 exit:
 	superio_exit(sioaddr);
 	return err;
 }
 
-static int __init sch56xx_device_add(unsigned short address, const char *name)
+static int __init sch56xx_device_add(int address, const char *name)
 {
 	struct resource res = {
 		.start	= address,
@@ -593,15 +594,14 @@
 
 static int __init sch56xx_init(void)
 {
-	int err;
-	unsigned short address;
-	const char *name;
+	int address;
+	const char *name = NULL;
 
-	err = sch56xx_find(0x4e, &address, &name);
-	if (err)
-		err = sch56xx_find(0x2e, &address, &name);
-	if (err)
-		return err;
+	address = sch56xx_find(0x4e, &name);
+	if (address < 0)
+		address = sch56xx_find(0x2e, &name);
+	if (address < 0)
+		return address;
 
 	return sch56xx_device_add(address, name);
 }
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 8b011d0..07a0c1a 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1,7 +1,7 @@
 /*
  * sht15.c - support for the SHT15 Temperature and Humidity Sensor
  *
- * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ * Portions Copyright (c) 2010-2012 Savoir-faire Linux Inc.
  *          Jerome Oufella <jerome.oufella@savoirfairelinux.com>
  *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  *
@@ -24,12 +24,12 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/mutex.h>
+#include <linux/platform_data/sht15.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
 #include <linux/err.h>
-#include <linux/sht15.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/atomic.h>
@@ -53,6 +53,9 @@
 #define SHT15_STATUS_HEATER		0x04
 #define SHT15_STATUS_LOW_BATTERY	0x40
 
+/* List of supported chips */
+enum sht15_chips { sht10, sht11, sht15, sht71, sht75 };
+
 /* Actions the driver may be doing */
 enum sht15_state {
 	SHT15_READING_NOTHING,
@@ -884,14 +887,12 @@
 static int __devinit sht15_probe(struct platform_device *pdev)
 {
 	int ret;
-	struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+	struct sht15_data *data;
 	u8 status = 0;
 
-	if (!data) {
-		ret = -ENOMEM;
-		dev_err(&pdev->dev, "kzalloc failed\n");
-		goto error_ret;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	INIT_WORK(&data->read_work, sht15_bh_read_data);
 	INIT_WORK(&data->update_supply_work, sht15_update_voltage);
@@ -901,9 +902,8 @@
 	init_waitqueue_head(&data->wait_queue);
 
 	if (pdev->dev.platform_data == NULL) {
-		ret = -EINVAL;
 		dev_err(&pdev->dev, "no platform data supplied\n");
-		goto err_free_data;
+		return -EINVAL;
 	}
 	data->pdata = pdev->dev.platform_data;
 	data->supply_uV = data->pdata->supply_mv * 1000;
@@ -918,7 +918,7 @@
 	 * If a regulator is available,
 	 * query what the supply voltage actually is!
 	 */
-	data->reg = regulator_get(data->dev, "vcc");
+	data->reg = devm_regulator_get(data->dev, "vcc");
 	if (!IS_ERR(data->reg)) {
 		int voltage;
 
@@ -937,51 +937,51 @@
 			dev_err(&pdev->dev,
 				"regulator notifier request failed\n");
 			regulator_disable(data->reg);
-			regulator_put(data->reg);
-			goto err_free_data;
+			return ret;
 		}
 	}
 
 	/* Try requesting the GPIOs */
-	ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
+	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
 	if (ret) {
 		dev_err(&pdev->dev, "gpio request failed\n");
 		goto err_release_reg;
 	}
 	gpio_direction_output(data->pdata->gpio_sck, 0);
 
-	ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
+	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
+				"SHT15 data");
 	if (ret) {
 		dev_err(&pdev->dev, "gpio request failed\n");
-		goto err_release_gpio_sck;
+		goto err_release_reg;
 	}
 
-	ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
-			  sht15_interrupt_fired,
-			  IRQF_TRIGGER_FALLING,
-			  "sht15 data",
-			  data);
+	ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+			       sht15_interrupt_fired,
+			       IRQF_TRIGGER_FALLING,
+			       "sht15 data",
+			       data);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get irq for data line\n");
-		goto err_release_gpio_data;
+		goto err_release_reg;
 	}
 	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
 	sht15_connection_reset(data);
 	ret = sht15_soft_reset(data);
 	if (ret)
-		goto err_release_irq;
+		goto err_release_reg;
 
 	/* write status with platform data options */
 	if (status) {
 		ret = sht15_send_status(data, status);
 		if (ret)
-			goto err_release_irq;
+			goto err_release_reg;
 	}
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
 	if (ret) {
 		dev_err(&pdev->dev, "sysfs create failed\n");
-		goto err_release_irq;
+		goto err_release_reg;
 	}
 
 	data->hwmon_dev = hwmon_device_register(data->dev);
@@ -994,21 +994,11 @@
 
 err_release_sysfs_group:
 	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
-err_release_irq:
-	free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-err_release_gpio_data:
-	gpio_free(data->pdata->gpio_data);
-err_release_gpio_sck:
-	gpio_free(data->pdata->gpio_sck);
 err_release_reg:
 	if (!IS_ERR(data->reg)) {
 		regulator_unregister_notifier(data->reg, &data->nb);
 		regulator_disable(data->reg);
-		regulator_put(data->reg);
 	}
-err_free_data:
-	kfree(data);
-error_ret:
 	return ret;
 }
 
@@ -1030,89 +1020,33 @@
 	if (!IS_ERR(data->reg)) {
 		regulator_unregister_notifier(data->reg, &data->nb);
 		regulator_disable(data->reg);
-		regulator_put(data->reg);
 	}
 
-	free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-	gpio_free(data->pdata->gpio_data);
-	gpio_free(data->pdata->gpio_sck);
 	mutex_unlock(&data->read_lock);
-	kfree(data);
 
 	return 0;
 }
 
-/*
- * sht_drivers simultaneously refers to __devinit and __devexit function
- * which causes spurious section mismatch warning. So use __refdata to
- * get rid from this.
- */
-static struct platform_driver __refdata sht_drivers[] = {
-	{
-		.driver = {
-			.name = "sht10",
-			.owner = THIS_MODULE,
-		},
-		.probe = sht15_probe,
-		.remove = __devexit_p(sht15_remove),
-	}, {
-		.driver = {
-			.name = "sht11",
-			.owner = THIS_MODULE,
-		},
-		.probe = sht15_probe,
-		.remove = __devexit_p(sht15_remove),
-	}, {
-		.driver = {
-			.name = "sht15",
-			.owner = THIS_MODULE,
-		},
-		.probe = sht15_probe,
-		.remove = __devexit_p(sht15_remove),
-	}, {
-		.driver = {
-			.name = "sht71",
-			.owner = THIS_MODULE,
-		},
-		.probe = sht15_probe,
-		.remove = __devexit_p(sht15_remove),
-	}, {
-		.driver = {
-			.name = "sht75",
-			.owner = THIS_MODULE,
-		},
-		.probe = sht15_probe,
-		.remove = __devexit_p(sht15_remove),
-	},
+static struct platform_device_id sht15_device_ids[] = {
+	{ "sht10", sht10 },
+	{ "sht11", sht11 },
+	{ "sht15", sht15 },
+	{ "sht71", sht71 },
+	{ "sht75", sht75 },
+	{ }
 };
+MODULE_DEVICE_TABLE(platform, sht15_device_ids);
 
-static int __init sht15_init(void)
-{
-	int ret;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(sht_drivers); i++) {
-		ret = platform_driver_register(&sht_drivers[i]);
-		if (ret)
-			goto error_unreg;
-	}
-
-	return 0;
-
-error_unreg:
-	while (--i >= 0)
-		platform_driver_unregister(&sht_drivers[i]);
-
-	return ret;
-}
-module_init(sht15_init);
-
-static void __exit sht15_exit(void)
-{
-	int i;
-	for (i = ARRAY_SIZE(sht_drivers) - 1; i >= 0; i--)
-		platform_driver_unregister(&sht_drivers[i]);
-}
-module_exit(sht15_exit);
+static struct platform_driver sht15_driver = {
+	.driver = {
+		.name = "sht15",
+		.owner = THIS_MODULE,
+	},
+	.probe = sht15_probe,
+	.remove = __devexit_p(sht15_remove),
+	.id_table = sht15_device_ids,
+};
+module_platform_driver(sht15_driver);
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver");
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index 6c2dede..c2565d0 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -199,11 +199,10 @@
 		return -ENODEV;
 	}
 
-	sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
-	if (!sht21) {
-		dev_dbg(&client->dev, "kzalloc failed\n");
+	sht21 = devm_kzalloc(&client->dev, sizeof(*sht21), GFP_KERNEL);
+	if (!sht21)
 		return -ENOMEM;
-	}
+
 	i2c_set_clientdata(client, sht21);
 
 	mutex_init(&sht21->lock);
@@ -211,7 +210,7 @@
 	err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
 	if (err) {
 		dev_dbg(&client->dev, "could not create sysfs files\n");
-		goto fail_free;
+		return err;
 	}
 	sht21->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(sht21->hwmon_dev)) {
@@ -226,9 +225,6 @@
 
 fail_remove_sysfs:
 	sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-fail_free:
-	kfree(sht21);
-
 	return err;
 }
 
@@ -242,7 +238,6 @@
 
 	hwmon_device_unregister(sht21->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-	kfree(sht21);
 
 	return 0;
 }
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index ee4ebc1..4cddee0 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -128,12 +128,10 @@
 	int err;
 	u32 eax, edx;
 
-	data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		dev_err(&pdev->dev, "Out of memory\n");
-		goto exit;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->id = pdev->id;
 	data->name = "via_cputemp";
@@ -151,8 +149,7 @@
 		data->msr_temp = 0x1423;
 		break;
 	default:
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	/* test if we can access the TEMPERATURE MSR */
@@ -160,14 +157,14 @@
 	if (err) {
 		dev_err(&pdev->dev,
 			"Unable to access TEMPERATURE MSR, giving up\n");
-		goto exit_free;
+		return err;
 	}
 
 	platform_set_drvdata(pdev, data);
 
 	err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->msr_vid)
 		data->vrm = vid_which_vrm();
@@ -192,10 +189,6 @@
 	if (data->vrm)
 		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
 	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-exit_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -207,8 +200,6 @@
 	if (data->vrm)
 		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
 	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return 0;
 }
 
@@ -328,6 +319,7 @@
 	if (err)
 		goto exit;
 
+	get_online_cpus();
 	for_each_online_cpu(i) {
 		struct cpuinfo_x86 *c = &cpu_data(i);
 
@@ -347,12 +339,14 @@
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
+		put_online_cpus();
 		err = -ENODEV;
 		goto exit_driver_unreg;
 	}
 #endif
 
 	register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+	put_online_cpus();
 	return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -367,6 +361,7 @@
 {
 	struct pdev_entry *p, *n;
 
+	get_online_cpus();
 	unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -375,6 +370,7 @@
 		kfree(p);
 	}
 	mutex_unlock(&pdev_list_mutex);
+	put_online_cpus();
 	platform_driver_unregister(&via_cputemp_driver);
 }
 
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 386a845..84e3dc5 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -789,18 +789,16 @@
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, VT8231_EXTENT,
-			    vt8231_driver.driver.name)) {
+	if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT,
+				 vt8231_driver.driver.name)) {
 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
 			(unsigned long)res->start, (unsigned long)res->end);
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct vt8231_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	platform_set_drvdata(pdev, data);
 	data->addr = res->start;
@@ -812,7 +810,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Must update device information to find out the config field */
 	data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
@@ -850,13 +848,6 @@
 		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
 	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
-
-exit_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-exit_release:
-	release_region(res->start, VT8231_EXTENT);
 	return err;
 }
 
@@ -875,9 +866,6 @@
 
 	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-	release_region(data->addr, VT8231_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 9ade4d4..93ea81a 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -259,8 +259,7 @@
 					((val) + 500) / 1000)
 
 /* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
-#define TOL_TEMP_TO_REG(val)		((val) < 0 ? 0 : \
-					(val) >= 15000 ? 15 : \
+#define TOL_TEMP_TO_REG(val)		((val) >= 15000 ? 15 : \
 					((val) + 500) / 1000)
 
 #define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
@@ -848,10 +847,10 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct w83791d_data *data = i2c_get_clientdata(client);
 	int nr = sensor_attr->index;
-	unsigned long val;
+	long val;
 	u8 target_mask;
 
-	if (kstrtoul(buf, 10, &val))
+	if (kstrtol(buf, 10, &val))
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 0ba5a2b..06d6f56 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -296,7 +296,6 @@
 	u8 pwmenable[3];
 	u32 alarms;		/* realtime status register encoding,combined */
 	u8 chassis;		/* Chassis status */
-	u8 chassis_clear;	/* CLR_CHS, clear chassis intrusion detection */
 	u8 thermal_cruise[3];	/* Smart FanI: Fan1,2,3 target value */
 	u8 tolerance[3];	/* Fan1,2,3 tolerance(Smart Fan I/II) */
 	u8 sf2_points[3][4];	/* Smart FanII: Fan1,2,3 temperature points */
@@ -739,7 +738,7 @@
 }
 
 static ssize_t
-show_chassis(struct device *dev, struct device_attribute *attr,
+show_chassis_clear(struct device *dev, struct device_attribute *attr,
 			char *buf)
 {
 	struct w83792d_data *data = w83792d_update_device(dev);
@@ -747,52 +746,6 @@
 }
 
 static ssize_t
-show_regs_chassis(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	dev_warn(dev,
-		 "Attribute %s is deprecated, use intrusion0_alarm instead\n",
-		 "chassis");
-	return show_chassis(dev, attr, buf);
-}
-
-static ssize_t
-show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct w83792d_data *data = w83792d_update_device(dev);
-	return sprintf(buf, "%d\n", data->chassis_clear);
-}
-
-static ssize_t
-store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83792d_data *data = i2c_get_clientdata(client);
-	unsigned long val;
-	int err;
-	u8 temp1 = 0, temp2 = 0;
-
-	dev_warn(dev,
-		 "Attribute %s is deprecated, use intrusion0_alarm instead\n",
-		 "chassis_clear");
-
-	err = kstrtoul(buf, 10, &val);
-	if (err)
-		return err;
-
-	mutex_lock(&data->update_lock);
-	data->chassis_clear = SENSORS_LIMIT(val, 0, 1);
-	temp1 = ((data->chassis_clear) << 7) & 0x80;
-	temp2 = w83792d_read_value(client,
-		W83792D_REG_CHASSIS_CLR) & 0x7f;
-	w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
-	mutex_unlock(&data->update_lock);
-
-	return count;
-}
-
-static ssize_t
 store_chassis_clear(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
@@ -1116,11 +1069,8 @@
 static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
 static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
 static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
-static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
-static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
-			show_chassis_clear, store_chassis_clear_legacy);
 static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
-			show_chassis, store_chassis_clear);
+			show_chassis_clear, store_chassis_clear);
 static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
 static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
 static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
@@ -1320,8 +1270,6 @@
 	&sensor_dev_attr_pwm3_mode.dev_attr.attr,
 	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
 	&dev_attr_alarms.attr,
-	&dev_attr_chassis.attr,
-	&dev_attr_chassis_clear.attr,
 	&dev_attr_intrusion0_alarm.attr,
 	&sensor_dev_attr_tolerance1.dev_attr.attr,
 	&sensor_dev_attr_thermal_cruise1.dev_attr.attr,
@@ -1627,8 +1575,6 @@
 		/* Update CaseOpen status and it's CLR_CHS. */
 		data->chassis = (w83792d_read_value(client,
 			W83792D_REG_CHASSIS) >> 5) & 0x01;
-		data->chassis_clear = (w83792d_read_value(client,
-			W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
 
 		/* Update Thermal Cruise/Smart Fan I target value */
 		for (i = 0; i < 3; i++) {
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index d6b0bdd..4fc47e06 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -442,27 +442,6 @@
 	return count;
 }
 
-/* Write any value to clear chassis alarm */
-static ssize_t
-store_chassis_clear_legacy(struct device *dev,
-			   struct device_attribute *attr, const char *buf,
-			   size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83793_data *data = i2c_get_clientdata(client);
-	u8 val;
-
-	dev_warn(dev, "Attribute chassis is deprecated, "
-		 "use intrusion0_alarm instead\n");
-
-	mutex_lock(&data->update_lock);
-	val = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
-	val |= 0x80;
-	w83793_write_value(client, W83793_REG_CLR_CHASSIS, val);
-	mutex_unlock(&data->update_lock);
-	return count;
-}
-
 /* Write 0 to clear chassis alarm */
 static ssize_t
 store_chassis_clear(struct device *dev,
@@ -1189,8 +1168,6 @@
 static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
 
 static struct sensor_device_attribute_2 sda_single_files[] = {
-	SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
-		      store_chassis_clear_legacy, ALARM_STATUS, 30),
 	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
 		      store_chassis_clear, ALARM_STATUS, 30),
 	SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 5850b77..c99c8a0 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -668,11 +668,10 @@
 	int i, err = 0;
 	u8 reg_tmp;
 
-	data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -708,8 +707,6 @@
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -721,8 +718,6 @@
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 1201a15..db713c0 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -552,7 +552,7 @@
  */
 int hwspin_lock_free(struct hwspinlock *hwlock)
 {
-	struct device *dev = hwlock->bank->dev;
+	struct device *dev;
 	struct hwspinlock *tmp;
 	int ret;
 
@@ -561,6 +561,7 @@
 		return -EINVAL;
 	}
 
+	dev = hwlock->bank->dev;
 	mutex_lock(&hwspinlock_tree_lock);
 
 	/* make sure the hwspinlock is used */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 970a161..42d9fdd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -551,7 +551,7 @@
 
 config I2C_PNX
 	tristate "I2C bus support for Philips PNX and NXP LPC targets"
-	depends on ARCH_PNX4008 || ARCH_LPC32XX
+	depends on ARCH_LPC32XX
 	help
 	  This driver supports the Philips IP3204 I2C IP block master and/or
 	  slave controller
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 93f147a..2f99613 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -4,13 +4,13 @@
 /* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
  *                    <Peter dot Milne at D hyphen TACQ dot com>
  *
- * With acknowledgements to i2c-algo-ibm_ocp.c by 
+ * With acknowledgements to i2c-algo-ibm_ocp.c by
  * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
  *
  * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
  *
  * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
- *  
+ *
  * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
  * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
  *
@@ -39,14 +39,15 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 
 #include "i2c-iop3xx.h"
 
 /* global unit counter */
 static int i2c_id;
 
-static inline unsigned char 
-iic_cook_addr(struct i2c_msg *msg) 
+static inline unsigned char
+iic_cook_addr(struct i2c_msg *msg)
 {
 	unsigned char addr;
 
@@ -55,38 +56,38 @@
 	if (msg->flags & I2C_M_RD)
 		addr |= 1;
 
-	return addr;   
+	return addr;
 }
 
-static void 
+static void
 iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	/* Follows devman 9.3 */
 	__raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
 	__raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
 	__raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
-} 
+}
 
-static void 
+static void
 iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
 
-	/* 
+	/*
 	 * Every time unit enable is asserted, GPOD needs to be cleared
 	 * on IOP3XX to avoid data corruption on the bus.
 	 */
 #if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
 	if (iop3xx_adap->id == 0) {
-		gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
-		gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+		gpio_set_value(7, 0);
+		gpio_set_value(6, 0);
 	} else {
-		gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
-		gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+		gpio_set_value(5, 0);
+		gpio_set_value(4, 0);
 	}
 #endif
 	/* NB SR bits not same position as CR IE bits :-( */
-	iop3xx_adap->SR_enabled = 
+	iop3xx_adap->SR_enabled =
 		IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
 		IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
 
@@ -96,23 +97,23 @@
 	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-static void 
+static void
 iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
-	
-	cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | 
+
+	cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
 		IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
 
 	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-/* 
- * NB: the handler has to clear the source of the interrupt! 
+/*
+ * NB: the handler has to clear the source of the interrupt!
  * Then it passes the SR flags of interest to BH via adap data
  */
-static irqreturn_t 
-iop3xx_i2c_irq_handler(int this_irq, void *dev_id) 
+static irqreturn_t
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
 	u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
@@ -126,7 +127,7 @@
 }
 
 /* check all error conditions, clear them , report most important */
-static int 
+static int
 iop3xx_i2c_error(u32 sr)
 {
 	int rc = 0;
@@ -135,12 +136,12 @@
 		if ( !rc ) rc = -I2C_ERR_BERR;
 	}
 	if ((sr & IOP3XX_ISR_ALD)) {
-		if ( !rc ) rc = -I2C_ERR_ALD;		
+		if ( !rc ) rc = -I2C_ERR_ALD;
 	}
-	return rc;	
+	return rc;
 }
 
-static inline u32 
+static inline u32
 iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	unsigned long flags;
@@ -161,8 +162,8 @@
 typedef int (* compare_func)(unsigned test, unsigned mask);
 /* returns 1 on correct comparison */
 
-static int 
-iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
 			  unsigned flags, unsigned* status,
 			  compare_func compare)
 {
@@ -192,47 +193,47 @@
 }
 
 /*
- * Concrete compare_funcs 
+ * Concrete compare_funcs
  */
-static int 
+static int
 all_bits_clear(unsigned test, unsigned mask)
 {
 	return (test & mask) == 0;
 }
 
-static int 
+static int
 any_bits_set(unsigned test, unsigned mask)
 {
 	return (test & mask) != 0;
 }
 
-static int 
+static int
 iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
-		iop3xx_adap, 
+	return iop3xx_i2c_wait_event(
+		iop3xx_adap,
 	        IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
 		status, any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
-		iop3xx_adap, 
+	return iop3xx_i2c_wait_event(
+		iop3xx_adap,
 		IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
 		status,	any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
+	return iop3xx_i2c_wait_event(
 		iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
 }
 
-static int 
-iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
 				struct i2c_msg* msg)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -247,7 +248,7 @@
 	}
 
 	__raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
-	
+
 	cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
 	cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
 
@@ -257,8 +258,8 @@
 	return rc;
 }
 
-static int 
-iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, 
+static int
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
 				int stop)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -277,10 +278,10 @@
 	rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
 
 	return rc;
-} 
+}
 
-static int 
-iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, 
+static int
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
 				int stop)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -304,19 +305,19 @@
 	return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
 	int ii;
 	int rc = 0;
 
-	for (ii = 0; rc == 0 && ii != count; ++ii) 
+	for (ii = 0; rc == 0 && ii != count; ++ii)
 		rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
 	return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -325,7 +326,7 @@
 
 	for (ii = 0; rc == 0 && ii != count; ++ii)
 		rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
-	
+
 	return rc;
 }
 
@@ -336,8 +337,8 @@
  * Each transfer (i.e. a read or a write) is separated by a repeated start
  * condition.
  */
-static int 
-iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) 
+static int
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
 	int rc;
@@ -357,8 +358,8 @@
 /*
  * master_xfer() - main read/write entry
  */
-static int 
-iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 
+static int
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
 				int num)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -375,14 +376,14 @@
 	}
 
 	iop3xx_i2c_transaction_cleanup(iop3xx_adap);
-	
+
 	if(ret)
 		return ret;
 
-	return im;   
+	return im;
 }
 
-static u32 
+static u32
 iop3xx_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -393,11 +394,11 @@
 	.functionality	= iop3xx_i2c_func,
 };
 
-static int 
+static int
 iop3xx_i2c_remove(struct platform_device *pdev)
 {
 	struct i2c_adapter *padapter = platform_get_drvdata(pdev);
-	struct i2c_algo_iop3xx_data *adapter_data = 
+	struct i2c_algo_iop3xx_data *adapter_data =
 		(struct i2c_algo_iop3xx_data *)padapter->algo_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
@@ -419,7 +420,7 @@
 	return 0;
 }
 
-static int 
+static int
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
 	struct resource *res;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index b76731e..57f7703 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -647,7 +647,7 @@
 	}
 
 	if (match->data) {
-		struct mpc_i2c_data *data = match->data;
+		const struct mpc_i2c_data *data = match->data;
 		data->setup(op->dev.of_node, i2c, clock, data->prescaler);
 	} else {
 		/* Backwards compatibility */
@@ -730,24 +730,24 @@
 SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
 #endif
 
-static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
 	.setup = mpc_i2c_setup_512x,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
 	.setup = mpc_i2c_setup_52xx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 2,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 3,
 };
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 5d19a49..a0e49f6 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -944,7 +944,8 @@
 	struct omap_i2c_dev	*dev;
 	struct i2c_adapter	*adap;
 	struct resource		*mem, *irq, *ioarea;
-	struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+	const struct omap_i2c_bus_platform_data *pdata =
+		pdev->dev.platform_data;
 	struct device_node	*node = pdev->dev.of_node;
 	const struct of_device_id *match;
 	irq_handler_t isr;
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index d4984c8..6e3f143 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -1,5 +1,5 @@
 #
-# Industrial I/O subsytem configuration
+# Industrial I/O subsystem configuration
 #
 
 menuconfig IIO
@@ -54,10 +54,15 @@
 	This value controls the maximum number of consumers that a
 	given trigger may handle. Default is 2.
 
+source "drivers/iio/accel/Kconfig"
 source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/frequency/Kconfig"
 source "drivers/iio/dac/Kconfig"
+source "drivers/iio/common/Kconfig"
+source "drivers/iio/gyro/Kconfig"
+source "drivers/iio/light/Kconfig"
+source "drivers/iio/magnetometer/Kconfig"
 
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 34309ab..f7fa3c0 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -10,8 +10,13 @@
 obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
 
+obj-y += accel/
 obj-y += adc/
 obj-y += amplifiers/
 obj-y += light/
 obj-y += frequency/
 obj-y += dac/
+obj-y += common/
+obj-y += gyro/
+obj-y += light/
+obj-y += magnetometer/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
new file mode 100644
index 0000000..b2510c4
--- /dev/null
+++ b/drivers/iio/accel/Kconfig
@@ -0,0 +1,16 @@
+#
+# Accelerometer drivers
+#
+menu "Accelerometers"
+
+config HID_SENSOR_ACCEL_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Acelerometers 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  accelerometers 3D.
+
+endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
new file mode 100644
index 0000000..5bc6855
--- /dev/null
+++ b/drivers/iio/accel/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O accelerometer drivers
+#
+
+obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
new file mode 100644
index 0000000..314a405
--- /dev/null
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -0,0 +1,418 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-attributes.h"
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+/*Format: HID-SENSOR-usage_id_in_hex*/
+/*Usage ID from spec for Accelerometer-3D: 0x200073*/
+#define DRIVER_NAME "HID-SENSOR-200073"
+
+enum accel_3d_channel {
+	CHANNEL_SCAN_INDEX_X,
+	CHANNEL_SCAN_INDEX_Y,
+	CHANNEL_SCAN_INDEX_Z,
+	ACCEL_3D_CHANNEL_MAX,
+};
+
+struct accel_3d_state {
+	struct hid_sensor_hub_callbacks callbacks;
+	struct hid_sensor_iio_common common_attributes;
+	struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
+	u32 accel_val[ACCEL_3D_CHANNEL_MAX];
+};
+
+static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
+	HID_USAGE_SENSOR_ACCEL_X_AXIS,
+	HID_USAGE_SENSOR_ACCEL_Y_AXIS,
+	HID_USAGE_SENSOR_ACCEL_Z_AXIS
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec accel_3d_channels[] = {
+	{
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_X,
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Y,
+	}, {
+		.type = IIO_ACCEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Z,
+	}
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+						int channel, int size)
+{
+	channels[channel].scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channels[channel].scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is u32 */
+	channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int accel_3d_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct accel_3d_state *accel_state = iio_priv(indio_dev);
+	int report_id = -1;
+	u32 address;
+	int ret;
+	int ret_type;
+
+	*val = 0;
+	*val2 = 0;
+	switch (mask) {
+	case 0:
+		report_id = accel_state->accel[chan->scan_index].report_id;
+		address = accel_3d_addresses[chan->scan_index];
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				accel_state->common_attributes.hsdev,
+				HID_USAGE_SENSOR_ACCEL_3D, address,
+				report_id);
+		else {
+			*val = 0;
+			return -EINVAL;
+		}
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = accel_state->accel[CHANNEL_SCAN_INDEX_X].units;
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = hid_sensor_convert_exponent(
+			accel_state->accel[CHANNEL_SCAN_INDEX_X].unit_expo);
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_read_samp_freq_value(
+			&accel_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_read_raw_hyst_value(
+			&accel_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	default:
+		ret_type = -EINVAL;
+		break;
+	}
+
+	return ret_type;
+}
+
+/* Channel write_raw handler */
+static int accel_3d_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct accel_3d_state *accel_state = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_write_samp_freq_value(
+				&accel_state->common_attributes, val, val2);
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_write_raw_hyst_value(
+				&accel_state->common_attributes, val, val2);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int accel_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       long mask)
+{
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static const struct iio_info accel_3d_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &accel_3d_read_raw,
+	.write_raw = &accel_3d_write_raw,
+	.write_raw_get_fmt = &accel_3d_write_raw_get_fmt,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int datum_sz;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+	if (!buffer) {
+		dev_err(&indio_dev->dev, "Buffer == NULL\n");
+		return;
+	}
+	datum_sz = buffer->access->get_bytes_per_datum(buffer);
+	if (len > datum_sz) {
+		dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+				datum_sz);
+		return;
+	}
+	iio_push_to_buffer(buffer, (u8 *)data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct accel_3d_state *accel_state = iio_priv(indio_dev);
+
+	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n",
+				accel_state->common_attributes.data_ready);
+	if (accel_state->common_attributes.data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)accel_state->accel_val,
+				sizeof(accel_state->accel_val));
+
+	return 0;
+}
+
+/* Capture samples in local storage */
+static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				size_t raw_len, char *raw_data,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct accel_3d_state *accel_state = iio_priv(indio_dev);
+	int offset;
+	int ret = -EINVAL;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_ACCEL_X_AXIS:
+	case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
+	case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
+		offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
+		accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
+						*(u32 *)raw_data;
+		ret = 0;
+	break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int accel_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				struct iio_chan_spec *channels,
+				unsigned usage_id,
+				struct accel_3d_state *st)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
+		ret = sensor_hub_input_get_attribute_info(hsdev,
+				HID_INPUT_REPORT,
+				usage_id,
+				HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
+				&st->accel[CHANNEL_SCAN_INDEX_X + i]);
+		if (ret < 0)
+			break;
+		accel_3d_adjust_channel_bit_mask(channels,
+				CHANNEL_SCAN_INDEX_X + i,
+				st->accel[CHANNEL_SCAN_INDEX_X + i].size);
+	}
+	dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
+			st->accel[0].index,
+			st->accel[0].report_id,
+			st->accel[1].index, st->accel[1].report_id,
+			st->accel[2].index, st->accel[2].report_id);
+
+	return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int __devinit hid_accel_3d_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	static const char *name = "accel_3d";
+	struct iio_dev *indio_dev;
+	struct accel_3d_state *accel_state;
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_chan_spec *channels;
+
+	indio_dev = iio_device_alloc(sizeof(struct accel_3d_state));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	platform_set_drvdata(pdev, indio_dev);
+
+	accel_state = iio_priv(indio_dev);
+	accel_state->common_attributes.hsdev = hsdev;
+	accel_state->common_attributes.pdev = pdev;
+
+	ret = hid_sensor_parse_common_attributes(hsdev,
+					HID_USAGE_SENSOR_ACCEL_3D,
+					&accel_state->common_attributes);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup common attributes\n");
+		goto error_free_dev;
+	}
+
+	channels = kmemdup(accel_3d_channels,
+					sizeof(accel_3d_channels),
+					GFP_KERNEL);
+	if (!channels) {
+		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		goto error_free_dev;
+	}
+
+	ret = accel_3d_parse_report(pdev, hsdev, channels,
+					HID_USAGE_SENSOR_ACCEL_3D, accel_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev_mem;
+	}
+
+	indio_dev->channels = channels;
+	indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &accel_3d_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+		NULL, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+		goto error_free_dev_mem;
+	}
+	accel_state->common_attributes.data_ready = false;
+	ret = hid_sensor_setup_trigger(indio_dev, name,
+					&accel_state->common_attributes);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "trigger setup failed\n");
+		goto error_unreg_buffer_funcs;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "device register failed\n");
+		goto error_remove_trigger;
+	}
+
+	accel_state->callbacks.send_event = accel_3d_proc_event;
+	accel_state->callbacks.capture_sample = accel_3d_capture_sample;
+	accel_state->callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
+					&accel_state->callbacks);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "callback reg failed\n");
+		goto error_iio_unreg;
+	}
+
+	return ret;
+
+error_iio_unreg:
+	iio_device_unregister(indio_dev);
+error_remove_trigger:
+	hid_sensor_remove_trigger(indio_dev);
+error_unreg_buffer_funcs:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+	kfree(indio_dev->channels);
+error_free_dev:
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int __devinit hid_accel_3d_remove(struct platform_device *pdev)
+{
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+	iio_device_unregister(indio_dev);
+	hid_sensor_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	kfree(indio_dev->channels);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver hid_accel_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_accel_3d_probe,
+	.remove		= hid_accel_3d_remove,
+};
+module_platform_driver(hid_accel_3d_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Accel 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 8a78b4f..4927581 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -3,6 +3,11 @@
 #
 menu "Analog to digital converters"
 
+config AD_SIGMA_DELTA
+	tristate
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+
 config AD7266
 	tristate "Analog Devices AD7265/AD7266 ADC driver"
 	depends on SPI_MASTER
@@ -13,6 +18,33 @@
 	  Say yes here to build support for Analog Devices AD7265 and AD7266
 	  ADCs.
 
+config AD7791
+	tristate "Analog Devices AD7791 ADC driver"
+	depends on SPI
+	select AD_SIGMA_DELTA
+	help
+	  Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
+	  AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say
+	  N (but it is safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ad7791.
+
+config AD7476
+	tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
+	depends on SPI
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
+	  AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
+	  AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7476.
+
 config AT91_ADC
 	tristate "Atmel AT91 ADC"
 	depends on ARCH_AT91
@@ -22,4 +54,10 @@
 	help
 	  Say yes here to build support for Atmel AT91 ADC.
 
+config LP8788_ADC
+	bool "LP8788 ADC driver"
+	depends on MFD_LP8788
+	help
+	  Say yes here to build support for TI LP8788 ADC.
+
 endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 52eec25..900995d 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -2,5 +2,9 @@
 # Makefile for IIO ADC drivers
 #
 
+obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
 obj-$(CONFIG_AD7266) += ad7266.o
+obj-$(CONFIG_AD7476) += ad7476.o
+obj-$(CONFIG_AD7791) += ad7791.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index 5c3f1ba..b11f214 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -99,7 +99,7 @@
 	if (ret == 0) {
 		if (indio_dev->scan_timestamp)
 			((s64 *)st->data)[1] = pf->timestamp;
-		iio_push_to_buffer(buffer, (u8 *)st->data, pf->timestamp);
+		iio_push_to_buffer(buffer, (u8 *)st->data);
 	}
 
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
new file mode 100644
index 0000000..7f2f45a
--- /dev/null
+++ b/drivers/iio/adc/ad7476.c
@@ -0,0 +1,332 @@
+/*
+ * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define RES_MASK(bits)	((1 << (bits)) - 1)
+
+struct ad7476_state;
+
+struct ad7476_chip_info {
+	unsigned int			int_vref_uv;
+	struct iio_chan_spec		channel[2];
+	void (*reset)(struct ad7476_state *);
+};
+
+struct ad7476_state {
+	struct spi_device		*spi;
+	const struct ad7476_chip_info	*chip_info;
+	struct regulator		*reg;
+	struct spi_transfer		xfer;
+	struct spi_message		msg;
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 * Make the buffer large enough for one 16 bit sample and one 64 bit
+	 * aligned 64 bit timestamp.
+	 */
+	unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)]
+			____cacheline_aligned;
+};
+
+enum ad7476_supported_device_ids {
+	ID_AD7091R,
+	ID_AD7276,
+	ID_AD7277,
+	ID_AD7278,
+	ID_AD7466,
+	ID_AD7467,
+	ID_AD7468,
+	ID_AD7495,
+	ID_AD7940,
+};
+
+static irqreturn_t ad7476_trigger_handler(int irq, void  *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad7476_state *st = iio_priv(indio_dev);
+	s64 time_ns;
+	int b_sent;
+
+	b_sent = spi_sync(st->spi, &st->msg);
+	if (b_sent < 0)
+		goto done;
+
+	time_ns = iio_get_time_ns();
+
+	if (indio_dev->scan_timestamp)
+		((s64 *)st->data)[1] = time_ns;
+
+	iio_push_to_buffer(indio_dev->buffer, st->data);
+done:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static void ad7091_reset(struct ad7476_state *st)
+{
+	/* Any transfers with 8 scl cycles will reset the device */
+	spi_read(st->spi, st->data, 1);
+}
+
+static int ad7476_scan_direct(struct ad7476_state *st)
+{
+	int ret;
+
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret)
+		return ret;
+
+	return be16_to_cpup((__be16 *)st->data);
+}
+
+static int ad7476_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	int ret;
+	struct ad7476_state *st = iio_priv(indio_dev);
+	int scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&indio_dev->mlock);
+		if (iio_buffer_enabled(indio_dev))
+			ret = -EBUSY;
+		else
+			ret = ad7476_scan_direct(st);
+		mutex_unlock(&indio_dev->mlock);
+
+		if (ret < 0)
+			return ret;
+		*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
+			RES_MASK(st->chip_info->channel[0].scan_type.realbits);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (!st->chip_info->int_vref_uv) {
+			scale_uv = regulator_get_voltage(st->reg);
+			if (scale_uv < 0)
+				return scale_uv;
+		} else {
+			scale_uv = st->chip_info->int_vref_uv;
+		}
+		scale_uv >>= chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+	return -EINVAL;
+}
+
+#define _AD7476_CHAN(bits, _shift, _info_mask)			\
+	{							\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.info_mask = _info_mask |				\
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = (bits),				\
+		.storagebits = 16,				\
+		.shift = (_shift),				\
+		.endianness = IIO_BE,				\
+	},							\
+}
+
+#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
+		IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
+
+static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
+	[ID_AD7091R] = {
+		.channel[0] = AD7091R_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.reset = ad7091_reset,
+	},
+	[ID_AD7276] = {
+		.channel[0] = AD7940_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7277] = {
+		.channel[0] = AD7940_CHAN(10),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7278] = {
+		.channel[0] = AD7940_CHAN(8),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7466] = {
+		.channel[0] = AD7476_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7467] = {
+		.channel[0] = AD7476_CHAN(10),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7468] = {
+		.channel[0] = AD7476_CHAN(8),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+	[ID_AD7495] = {
+		.channel[0] = AD7476_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.int_vref_uv = 2500000,
+	},
+	[ID_AD7940] = {
+		.channel[0] = AD7940_CHAN(14),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+	},
+};
+
+static const struct iio_info ad7476_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &ad7476_read_raw,
+};
+
+static int __devinit ad7476_probe(struct spi_device *spi)
+{
+	struct ad7476_state *st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(indio_dev);
+	st->chip_info =
+		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (IS_ERR(st->reg)) {
+		ret = PTR_ERR(st->reg);
+		goto error_free_dev;
+	}
+
+	ret = regulator_enable(st->reg);
+	if (ret)
+		goto error_put_reg;
+
+	spi_set_drvdata(spi, indio_dev);
+
+	st->spi = spi;
+
+	/* Establish that the iio_dev is a child of the spi device */
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channel;
+	indio_dev->num_channels = 2;
+	indio_dev->info = &ad7476_info;
+	/* Setup default message */
+
+	st->xfer.rx_buf = &st->data;
+	st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
+
+	spi_message_init(&st->msg);
+	spi_message_add_tail(&st->xfer, &st->msg);
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+			&ad7476_trigger_handler, NULL);
+	if (ret)
+		goto error_disable_reg;
+
+	if (st->chip_info->reset)
+		st->chip_info->reset(st);
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_ring_unregister;
+	return 0;
+
+error_ring_unregister:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+	regulator_disable(st->reg);
+error_put_reg:
+	regulator_put(st->reg);
+error_free_dev:
+	iio_device_free(indio_dev);
+
+error_ret:
+	return ret;
+}
+
+static int __devexit ad7476_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad7476_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	regulator_disable(st->reg);
+	regulator_put(st->reg);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad7476_id[] = {
+	{"ad7091r", ID_AD7091R},
+	{"ad7273", ID_AD7277},
+	{"ad7274", ID_AD7276},
+	{"ad7276", ID_AD7276},
+	{"ad7277", ID_AD7277},
+	{"ad7278", ID_AD7278},
+	{"ad7466", ID_AD7466},
+	{"ad7467", ID_AD7467},
+	{"ad7468", ID_AD7468},
+	{"ad7475", ID_AD7466},
+	{"ad7476", ID_AD7466},
+	{"ad7476a", ID_AD7466},
+	{"ad7477", ID_AD7467},
+	{"ad7477a", ID_AD7467},
+	{"ad7478", ID_AD7468},
+	{"ad7478a", ID_AD7468},
+	{"ad7495", ID_AD7495},
+	{"ad7910", ID_AD7467},
+	{"ad7920", ID_AD7466},
+	{"ad7940", ID_AD7940},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad7476_id);
+
+static struct spi_driver ad7476_driver = {
+	.driver = {
+		.name	= "ad7476",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7476_probe,
+	.remove		= __devexit_p(ad7476_remove),
+	.id_table	= ad7476_id,
+};
+module_spi_driver(ad7476_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
new file mode 100644
index 0000000..e937408
--- /dev/null
+++ b/drivers/iio/adc/ad7791.c
@@ -0,0 +1,460 @@
+/*
+ * AD7787/AD7788/AD7789/AD7790/AD7791 SPI ADC driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
+
+#include <linux/platform_data/ad7791.h>
+
+#define AD7791_REG_COMM			0x0 /* For writes */
+#define AD7791_REG_STATUS		0x0 /* For reads */
+#define AD7791_REG_MODE			0x1
+#define AD7791_REG_FILTER		0x2
+#define AD7791_REG_DATA			0x3
+
+#define AD7791_MODE_CONTINUOUS		0x00
+#define AD7791_MODE_SINGLE		0x02
+#define AD7791_MODE_POWERDOWN		0x03
+
+#define AD7791_CH_AIN1P_AIN1N		0x00
+#define AD7791_CH_AIN2			0x01
+#define AD7791_CH_AIN1N_AIN1N		0x02
+#define AD7791_CH_AVDD_MONITOR		0x03
+
+#define AD7791_FILTER_CLK_DIV_1		(0x0 << 4)
+#define AD7791_FILTER_CLK_DIV_2		(0x1 << 4)
+#define AD7791_FILTER_CLK_DIV_4		(0x2 << 4)
+#define AD7791_FILTER_CLK_DIV_8		(0x3 << 4)
+#define AD7791_FILTER_CLK_MASK		(0x3 << 4)
+#define AD7791_FILTER_RATE_120		0x0
+#define AD7791_FILTER_RATE_100		0x1
+#define AD7791_FILTER_RATE_33_3		0x2
+#define AD7791_FILTER_RATE_20		0x3
+#define AD7791_FILTER_RATE_16_6		0x4
+#define AD7791_FILTER_RATE_16_7		0x5
+#define AD7791_FILTER_RATE_13_3		0x6
+#define AD7791_FILTER_RATE_9_5		0x7
+#define AD7791_FILTER_RATE_MASK		0x7
+
+#define AD7791_MODE_BUFFER		BIT(1)
+#define AD7791_MODE_UNIPOLAR		BIT(2)
+#define AD7791_MODE_BURNOUT		BIT(3)
+#define AD7791_MODE_SEL_MASK		(0x3 << 6)
+#define AD7791_MODE_SEL(x)		((x) << 6)
+
+#define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \
+const struct iio_chan_spec name[] = { \
+	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
+		(bits), (storagebits), 0), \
+	AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \
+	AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \
+		(bits), (storagebits), 0), \
+	AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR,  \
+		(bits), (storagebits), 0), \
+	IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
+#define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \
+const struct iio_chan_spec name[] = { \
+	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
+		(bits), (storagebits), 0), \
+	AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \
+		(bits), (storagebits), 0), \
+	AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \
+		(bits), (storagebits), 0), \
+	IIO_CHAN_SOFT_TIMESTAMP(3), \
+}
+
+static DECLARE_AD7787_CHANNELS(ad7787_channels, 24, 32);
+static DECLARE_AD7791_CHANNELS(ad7790_channels, 16, 16);
+static DECLARE_AD7791_CHANNELS(ad7791_channels, 24, 32);
+
+enum {
+	AD7787,
+	AD7788,
+	AD7789,
+	AD7790,
+	AD7791,
+};
+
+enum ad7791_chip_info_flags {
+	AD7791_FLAG_HAS_FILTER		= (1 << 0),
+	AD7791_FLAG_HAS_BUFFER		= (1 << 1),
+	AD7791_FLAG_HAS_UNIPOLAR	= (1 << 2),
+	AD7791_FLAG_HAS_BURNOUT		= (1 << 3),
+};
+
+struct ad7791_chip_info {
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
+	enum ad7791_chip_info_flags flags;
+};
+
+static const struct ad7791_chip_info ad7791_chip_infos[] = {
+	[AD7787] = {
+		.channels = ad7787_channels,
+		.num_channels = ARRAY_SIZE(ad7787_channels),
+		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
+			AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
+	},
+	[AD7788] = {
+		.channels = ad7790_channels,
+		.num_channels = ARRAY_SIZE(ad7790_channels),
+		.flags = AD7791_FLAG_HAS_UNIPOLAR,
+	},
+	[AD7789] = {
+		.channels = ad7791_channels,
+		.num_channels = ARRAY_SIZE(ad7791_channels),
+		.flags = AD7791_FLAG_HAS_UNIPOLAR,
+	},
+	[AD7790] = {
+		.channels = ad7790_channels,
+		.num_channels = ARRAY_SIZE(ad7790_channels),
+		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
+			AD7791_FLAG_HAS_BURNOUT,
+	},
+	[AD7791] = {
+		.channels = ad7791_channels,
+		.num_channels = ARRAY_SIZE(ad7791_channels),
+		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
+			AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
+	},
+};
+
+struct ad7791_state {
+	struct ad_sigma_delta sd;
+	uint8_t mode;
+	uint8_t filter;
+
+	struct regulator *reg;
+	const struct ad7791_chip_info *info;
+};
+
+static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd)
+{
+	return container_of(sd, struct ad7791_state, sd);
+}
+
+static int ad7791_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
+{
+	ad_sd_set_comm(sd, channel);
+
+	return 0;
+}
+
+static int ad7791_set_mode(struct ad_sigma_delta *sd,
+	enum ad_sigma_delta_mode mode)
+{
+	struct ad7791_state *st = ad_sigma_delta_to_ad7791(sd);
+
+	switch (mode) {
+	case AD_SD_MODE_CONTINUOUS:
+		mode = AD7791_MODE_CONTINUOUS;
+		break;
+	case AD_SD_MODE_SINGLE:
+		mode = AD7791_MODE_SINGLE;
+		break;
+	case AD_SD_MODE_IDLE:
+	case AD_SD_MODE_POWERDOWN:
+		mode = AD7791_MODE_POWERDOWN;
+		break;
+	}
+
+	st->mode &= ~AD7791_MODE_SEL_MASK;
+	st->mode |= AD7791_MODE_SEL(mode);
+
+	return ad_sd_write_reg(sd, AD7791_REG_MODE, sizeof(st->mode), st->mode);
+}
+
+static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
+	.set_channel = ad7791_set_channel,
+	.set_mode = ad7791_set_mode,
+	.has_registers = true,
+	.addr_shift = 4,
+	.read_mask = BIT(3),
+};
+
+static int ad7791_read_raw(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, int *val, int *val2, long info)
+{
+	struct ad7791_state *st = iio_priv(indio_dev);
+	bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR);
+	unsigned long long scale_pv;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		return ad_sigma_delta_single_conversion(indio_dev, chan, val);
+	case IIO_CHAN_INFO_OFFSET:
+		/**
+		 * Unipolar: 0 to VREF
+		 * Bipolar -VREF to VREF
+		 **/
+		if (unipolar)
+			*val = 0;
+		else
+			*val = -(1 << (chan->scan_type.realbits - 1));
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* The monitor channel uses an internal reference. */
+		if (chan->address == AD7791_CH_AVDD_MONITOR) {
+			scale_pv = 5850000000000ULL;
+		} else {
+			int voltage_uv;
+
+			voltage_uv = regulator_get_voltage(st->reg);
+			if (voltage_uv < 0)
+				return voltage_uv;
+			scale_pv = (unsigned long long)voltage_uv * 1000000;
+		}
+		if (unipolar)
+			scale_pv >>= chan->scan_type.realbits;
+		else
+			scale_pv >>= chan->scan_type.realbits - 1;
+		*val2 = do_div(scale_pv, 1000000000);
+		*val = scale_pv;
+
+		return IIO_VAL_INT_PLUS_NANO;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const ad7791_sample_freq_avail[] = {
+	[AD7791_FILTER_RATE_120] = "120",
+	[AD7791_FILTER_RATE_100] = "100",
+	[AD7791_FILTER_RATE_33_3] = "33.3",
+	[AD7791_FILTER_RATE_20] = "20",
+	[AD7791_FILTER_RATE_16_6] = "16.6",
+	[AD7791_FILTER_RATE_16_7] = "16.7",
+	[AD7791_FILTER_RATE_13_3] = "13.3",
+	[AD7791_FILTER_RATE_9_5] = "9.5",
+};
+
+static ssize_t ad7791_read_frequency(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad7791_state *st = iio_priv(indio_dev);
+	unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK;
+
+	return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]);
+}
+
+static ssize_t ad7791_write_frequency(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad7791_state *st = iio_priv(indio_dev);
+	int i, ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_enabled(indio_dev)) {
+		mutex_unlock(&indio_dev->mlock);
+		return -EBUSY;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	ret = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
+		if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) {
+
+			mutex_lock(&indio_dev->mlock);
+			st->filter &= ~AD7791_FILTER_RATE_MASK;
+			st->filter |= i;
+			ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
+					 sizeof(st->filter), st->filter);
+			mutex_unlock(&indio_dev->mlock);
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+		ad7791_read_frequency,
+		ad7791_write_frequency);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5");
+
+static struct attribute *ad7791_attributes[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group ad7791_attribute_group = {
+	.attrs = ad7791_attributes,
+};
+
+static const struct iio_info ad7791_info = {
+	.read_raw = &ad7791_read_raw,
+	.attrs = &ad7791_attribute_group,
+	.validate_trigger = ad_sd_validate_trigger,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_info ad7791_no_filter_info = {
+	.read_raw = &ad7791_read_raw,
+	.validate_trigger = ad_sd_validate_trigger,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad7791_setup(struct ad7791_state *st,
+	struct ad7791_platform_data *pdata)
+{
+	/* Set to poweron-reset default values */
+	st->mode = AD7791_MODE_BUFFER;
+	st->filter = AD7791_FILTER_RATE_16_6;
+
+	if (!pdata)
+		return 0;
+
+	if ((st->info->flags & AD7791_FLAG_HAS_BUFFER) && !pdata->buffered)
+		st->mode &= ~AD7791_MODE_BUFFER;
+
+	if ((st->info->flags & AD7791_FLAG_HAS_BURNOUT) &&
+		pdata->burnout_current)
+		st->mode |= AD7791_MODE_BURNOUT;
+
+	if ((st->info->flags & AD7791_FLAG_HAS_UNIPOLAR) && pdata->unipolar)
+		st->mode |= AD7791_MODE_UNIPOLAR;
+
+	return ad_sd_write_reg(&st->sd, AD7791_REG_MODE, sizeof(st->mode),
+		st->mode);
+}
+
+static int __devinit ad7791_probe(struct spi_device *spi)
+{
+	struct ad7791_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad7791_state *st;
+	int ret;
+
+	if (!spi->irq) {
+		dev_err(&spi->dev, "Missing IRQ.\n");
+		return -ENXIO;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "refin");
+	if (IS_ERR(st->reg)) {
+		ret = PTR_ERR(st->reg);
+		goto err_iio_free;
+	}
+
+	ret = regulator_enable(st->reg);
+	if (ret)
+		goto error_put_reg;
+
+	st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
+	ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
+
+	spi_set_drvdata(spi, indio_dev);
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->info->channels;
+	indio_dev->num_channels = st->info->num_channels;
+	if (st->info->flags & AD7791_FLAG_HAS_FILTER)
+		indio_dev->info = &ad7791_info;
+	else
+		indio_dev->info = &ad7791_no_filter_info;
+
+	ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ad7791_setup(st, pdata);
+	if (ret)
+		goto error_remove_trigger;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_remove_trigger;
+
+	return 0;
+
+error_remove_trigger:
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
+error_disable_reg:
+	regulator_disable(st->reg);
+error_put_reg:
+	regulator_put(st->reg);
+err_iio_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad7791_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad7791_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
+
+	regulator_disable(st->reg);
+	regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad7791_spi_ids[] = {
+	{ "ad7787", AD7787 },
+	{ "ad7788", AD7788 },
+	{ "ad7789", AD7789 },
+	{ "ad7790", AD7790 },
+	{ "ad7791", AD7791 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad7791_spi_ids);
+
+static struct spi_driver ad7791_driver = {
+	.driver = {
+		.name	= "ad7791",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7791_probe,
+	.remove		= __devexit_p(ad7791_remove),
+	.id_table	= ad7791_spi_ids,
+};
+module_spi_driver(ad7791_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
new file mode 100644
index 0000000..67baa13
--- /dev/null
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -0,0 +1,558 @@
+/*
+ * Support code for Analog Devices Sigma-Delta ADCs
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
+
+#include <asm/unaligned.h>
+
+
+#define AD_SD_COMM_CHAN_MASK	0x3
+
+#define AD_SD_REG_COMM		0x00
+#define AD_SD_REG_DATA		0x03
+
+/**
+ * ad_sd_set_comm() - Set communications register
+ *
+ * @sigma_delta: The sigma delta device
+ * @comm: New value for the communications register
+ */
+void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
+{
+	/* Some variants use the lower two bits of the communications register
+	 * to select the channel */
+	sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
+}
+EXPORT_SYMBOL_GPL(ad_sd_set_comm);
+
+/**
+ * ad_sd_write_reg() - Write a register
+ *
+ * @sigma_delta: The sigma delta device
+ * @reg: Address of the register
+ * @size: Size of the register (0-3)
+ * @val: Value to write to the register
+ *
+ * Returns 0 on success, an error code otherwise.
+ **/
+int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
+	unsigned int size, unsigned int val)
+{
+	uint8_t *data = sigma_delta->data;
+	struct spi_transfer t = {
+		.tx_buf		= data,
+		.len		= size + 1,
+		.cs_change	= sigma_delta->bus_locked,
+	};
+	struct spi_message m;
+	int ret;
+
+	data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm;
+
+	switch (size) {
+	case 3:
+		data[1] = val >> 16;
+		data[2] = val >> 8;
+		data[3] = val;
+		break;
+	case 2:
+		put_unaligned_be16(val, &data[1]);
+		break;
+	case 1:
+		data[1] = val;
+		break;
+	case 0:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	if (sigma_delta->bus_locked)
+		ret = spi_sync_locked(sigma_delta->spi, &m);
+	else
+		ret = spi_sync(sigma_delta->spi, &m);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ad_sd_write_reg);
+
+static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
+	unsigned int reg, unsigned int size, uint8_t *val)
+{
+	uint8_t *data = sigma_delta->data;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = data,
+			.len = 1,
+		}, {
+			.rx_buf = val,
+			.len = size,
+			.cs_change = sigma_delta->bus_locked,
+		},
+	};
+	struct spi_message m;
+
+	spi_message_init(&m);
+
+	if (sigma_delta->info->has_registers) {
+		data[0] = reg << sigma_delta->info->addr_shift;
+		data[0] |= sigma_delta->info->read_mask;
+		spi_message_add_tail(&t[0], &m);
+	}
+	spi_message_add_tail(&t[1], &m);
+
+	if (sigma_delta->bus_locked)
+		ret = spi_sync_locked(sigma_delta->spi, &m);
+	else
+		ret = spi_sync(sigma_delta->spi, &m);
+
+	return ret;
+}
+
+/**
+ * ad_sd_read_reg() - Read a register
+ *
+ * @sigma_delta: The sigma delta device
+ * @reg: Address of the register
+ * @size: Size of the register (1-4)
+ * @val: Read value
+ *
+ * Returns 0 on success, an error code otherwise.
+ **/
+int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
+	unsigned int reg, unsigned int size, unsigned int *val)
+{
+	int ret;
+
+	ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data);
+	if (ret < 0)
+		goto out;
+
+	switch (size) {
+	case 4:
+		*val = get_unaligned_be32(sigma_delta->data);
+		break;
+	case 3:
+		*val = (sigma_delta->data[0] << 16) |
+			(sigma_delta->data[1] << 8) |
+			sigma_delta->data[2];
+		break;
+	case 2:
+		*val = get_unaligned_be16(sigma_delta->data);
+		break;
+	case 1:
+		*val = sigma_delta->data[0];
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ad_sd_read_reg);
+
+static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
+	unsigned int mode, unsigned int channel)
+{
+	int ret;
+
+	ret = ad_sigma_delta_set_channel(sigma_delta, channel);
+	if (ret)
+		return ret;
+
+	spi_bus_lock(sigma_delta->spi->master);
+	sigma_delta->bus_locked = true;
+	INIT_COMPLETION(sigma_delta->completion);
+
+	ret = ad_sigma_delta_set_mode(sigma_delta, mode);
+	if (ret < 0)
+		goto out;
+
+	sigma_delta->irq_dis = false;
+	enable_irq(sigma_delta->spi->irq);
+	ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ);
+	if (ret == 0) {
+		sigma_delta->irq_dis = true;
+		disable_irq_nosync(sigma_delta->spi->irq);
+		ret = -EIO;
+	} else {
+		ret = 0;
+	}
+out:
+	sigma_delta->bus_locked = false;
+	spi_bus_unlock(sigma_delta->spi->master);
+	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+
+	return ret;
+}
+
+/**
+ * ad_sd_calibrate_all() - Performs channel calibration
+ * @sigma_delta: The sigma delta device
+ * @cb: Array of channels and calibration type to perform
+ * @n: Number of items in cb
+ *
+ * Returns 0 on success, an error code otherwise.
+ **/
+int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
+	const struct ad_sd_calib_data *cb, unsigned int n)
+{
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < n; i++) {
+		ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad_sd_calibrate_all);
+
+/**
+ * ad_sigma_delta_single_conversion() - Performs a single data conversion
+ * @indio_dev: The IIO device
+ * @chan: The conversion is done for this channel
+ * @val: Pointer to the location where to store the read value
+ *
+ * Returns: 0 on success, an error value otherwise.
+ */
+int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, int *val)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+	unsigned int sample, raw_sample;
+	int ret = 0;
+
+	if (iio_buffer_enabled(indio_dev))
+		return -EBUSY;
+
+	mutex_lock(&indio_dev->mlock);
+	ad_sigma_delta_set_channel(sigma_delta, chan->address);
+
+	spi_bus_lock(sigma_delta->spi->master);
+	sigma_delta->bus_locked = true;
+	INIT_COMPLETION(sigma_delta->completion);
+
+	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
+
+	sigma_delta->irq_dis = false;
+	enable_irq(sigma_delta->spi->irq);
+	ret = wait_for_completion_interruptible_timeout(
+			&sigma_delta->completion, HZ);
+
+	sigma_delta->bus_locked = false;
+	spi_bus_unlock(sigma_delta->spi->master);
+
+	if (ret == 0)
+		ret = -EIO;
+	if (ret < 0)
+		goto out;
+
+	ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
+		DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
+		&raw_sample);
+
+out:
+	if (!sigma_delta->irq_dis) {
+		disable_irq_nosync(sigma_delta->spi->irq);
+		sigma_delta->irq_dis = true;
+	}
+
+	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+	mutex_unlock(&indio_dev->mlock);
+
+	if (ret)
+		return ret;
+
+	sample = raw_sample >> chan->scan_type.shift;
+	sample &= (1 << chan->scan_type.realbits) - 1;
+	*val = sample;
+
+	ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample);
+	if (ret)
+		return ret;
+
+	return IIO_VAL_INT;
+}
+EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion);
+
+static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+	unsigned int channel;
+	int ret;
+
+	ret = iio_triggered_buffer_postenable(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	channel = find_first_bit(indio_dev->active_scan_mask,
+				 indio_dev->masklength);
+	ret = ad_sigma_delta_set_channel(sigma_delta,
+		indio_dev->channels[channel].address);
+	if (ret)
+		goto err_predisable;
+
+	spi_bus_lock(sigma_delta->spi->master);
+	sigma_delta->bus_locked = true;
+	ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
+	if (ret)
+		goto err_unlock;
+
+	sigma_delta->irq_dis = false;
+	enable_irq(sigma_delta->spi->irq);
+
+	return 0;
+
+err_unlock:
+	spi_bus_unlock(sigma_delta->spi->master);
+err_predisable:
+
+	return ret;
+}
+
+static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+
+	INIT_COMPLETION(sigma_delta->completion);
+	wait_for_completion_timeout(&sigma_delta->completion, HZ);
+
+	if (!sigma_delta->irq_dis) {
+		disable_irq_nosync(sigma_delta->spi->irq);
+		sigma_delta->irq_dis = true;
+	}
+
+	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+
+	sigma_delta->bus_locked = false;
+	return spi_bus_unlock(sigma_delta->spi->master);
+}
+
+static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+	unsigned int reg_size;
+	uint8_t data[16];
+	int ret;
+
+	memset(data, 0x00, 16);
+
+	/* Guaranteed to be aligned with 8 byte boundary */
+	if (indio_dev->scan_timestamp)
+		((s64 *)data)[1] = pf->timestamp;
+
+	reg_size = indio_dev->channels[0].scan_type.realbits +
+			indio_dev->channels[0].scan_type.shift;
+	reg_size = DIV_ROUND_UP(reg_size, 8);
+
+	switch (reg_size) {
+	case 4:
+	case 2:
+	case 1:
+		ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
+			reg_size, &data[0]);
+		break;
+	case 3:
+		/* We store 24 bit samples in a 32 bit word. Keep the upper
+		 * byte set to zero. */
+		ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
+			reg_size, &data[1]);
+		break;
+	}
+
+	iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data);
+
+	iio_trigger_notify_done(indio_dev->trig);
+	sigma_delta->irq_dis = false;
+	enable_irq(sigma_delta->spi->irq);
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
+	.preenable = &iio_sw_buffer_preenable,
+	.postenable = &ad_sd_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+	.postdisable = &ad_sd_buffer_postdisable,
+	.validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
+{
+	struct ad_sigma_delta *sigma_delta = private;
+
+	complete(&sigma_delta->completion);
+	disable_irq_nosync(irq);
+	sigma_delta->irq_dis = true;
+	iio_trigger_poll(sigma_delta->trig, iio_get_time_ns());
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices
+ * @indio_dev: The IIO device
+ * @trig: The new trigger
+ *
+ * Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta
+ * device, -EINVAL otherwise.
+ */
+int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+
+	if (sigma_delta->trig != trig)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
+
+static const struct iio_trigger_ops ad_sd_trigger_ops = {
+	.owner = THIS_MODULE,
+};
+
+static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+	int ret;
+
+	sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
+						indio_dev->id);
+	if (sigma_delta->trig == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	sigma_delta->trig->ops = &ad_sd_trigger_ops;
+	init_completion(&sigma_delta->completion);
+
+	ret = request_irq(sigma_delta->spi->irq,
+			  ad_sd_data_rdy_trig_poll,
+			  IRQF_TRIGGER_LOW,
+			  indio_dev->name,
+			  sigma_delta);
+	if (ret)
+		goto error_free_trig;
+
+	if (!sigma_delta->irq_dis) {
+		sigma_delta->irq_dis = true;
+		disable_irq_nosync(sigma_delta->spi->irq);
+	}
+	sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
+	sigma_delta->trig->private_data = sigma_delta;
+
+	ret = iio_trigger_register(sigma_delta->trig);
+	if (ret)
+		goto error_free_irq;
+
+	/* select default trigger */
+	indio_dev->trig = sigma_delta->trig;
+
+	return 0;
+
+error_free_irq:
+	free_irq(sigma_delta->spi->irq, sigma_delta);
+error_free_trig:
+	iio_trigger_free(sigma_delta->trig);
+error_ret:
+	return ret;
+}
+
+static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
+{
+	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+
+	iio_trigger_unregister(sigma_delta->trig);
+	free_irq(sigma_delta->spi->irq, sigma_delta);
+	iio_trigger_free(sigma_delta->trig);
+}
+
+/**
+ * ad_sd_setup_buffer_and_trigger() -
+ * @indio_dev: The IIO device
+ */
+int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
+{
+	int ret;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+			&ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
+	if (ret)
+		return ret;
+
+	ret = ad_sd_probe_trigger(indio_dev);
+	if (ret) {
+		iio_triggered_buffer_cleanup(indio_dev);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
+
+/**
+ * ad_sd_cleanup_buffer_and_trigger() -
+ * @indio_dev: The IIO device
+ */
+void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
+{
+	ad_sd_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+}
+EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
+
+/**
+ * ad_sd_init() - Initializes a ad_sigma_delta struct
+ * @sigma_delta: The ad_sigma_delta device
+ * @indio_dev: The IIO device which the Sigma Delta device is used for
+ * @spi: The SPI device for the ad_sigma_delta device
+ * @info: Device specific callbacks and options
+ *
+ * This function needs to be called before any other operations are performed on
+ * the ad_sigma_delta struct.
+ */
+int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
+	struct spi_device *spi, const struct ad_sigma_delta_info *info)
+{
+	sigma_delta->spi = spi;
+	sigma_delta->info = info;
+	iio_device_set_drvdata(indio_dev, sigma_delta);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad_sd_init);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 3bd5540..3ed94bf 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -82,7 +82,7 @@
 		*timestamp = pf->timestamp;
 	}
 
-	buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+	buffer->access->store_to(buffer, (u8 *)st->buffer);
 
 	iio_trigger_notify_done(idev->trig);
 	st->irq_enabled = true;
@@ -545,13 +545,6 @@
 		goto error_free_device;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "No resource defined\n");
-		ret = -ENXIO;
-		goto error_ret;
-	}
-
 	platform_set_drvdata(pdev, idev);
 
 	idev->dev.parent = &pdev->dev;
@@ -566,18 +559,12 @@
 		goto error_free_device;
 	}
 
-	if (!request_mem_region(res->start, resource_size(res),
-				"AT91 adc registers")) {
-		dev_err(&pdev->dev, "Resources are unavailable.\n");
-		ret = -EBUSY;
-		goto error_free_device;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-	st->reg_base = ioremap(res->start, resource_size(res));
+	st->reg_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!st->reg_base) {
-		dev_err(&pdev->dev, "Failed to map registers.\n");
 		ret = -ENOMEM;
-		goto error_release_mem;
+		goto error_free_device;
 	}
 
 	/*
@@ -592,45 +579,35 @@
 			  idev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
-		goto error_unmap_reg;
+		goto error_free_device;
 	}
 
-	st->clk = clk_get(&pdev->dev, "adc_clk");
+	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
 	if (IS_ERR(st->clk)) {
 		dev_err(&pdev->dev, "Failed to get the clock.\n");
 		ret = PTR_ERR(st->clk);
 		goto error_free_irq;
 	}
 
-	ret = clk_prepare(st->clk);
+	ret = clk_prepare_enable(st->clk);
 	if (ret) {
-		dev_err(&pdev->dev, "Could not prepare the clock.\n");
-		goto error_free_clk;
+		dev_err(&pdev->dev,
+			"Could not prepare or enable the clock.\n");
+		goto error_free_irq;
 	}
 
-	ret = clk_enable(st->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not enable the clock.\n");
-		goto error_unprepare_clk;
-	}
-
-	st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+	st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
 	if (IS_ERR(st->adc_clk)) {
 		dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
 		ret = PTR_ERR(st->adc_clk);
 		goto error_disable_clk;
 	}
 
-	ret = clk_prepare(st->adc_clk);
+	ret = clk_prepare_enable(st->adc_clk);
 	if (ret) {
-		dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
-		goto error_free_adc_clk;
-	}
-
-	ret = clk_enable(st->adc_clk);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
-		goto error_unprepare_adc_clk;
+		dev_err(&pdev->dev,
+			"Could not prepare or enable the ADC clock.\n");
+		goto error_disable_clk;
 	}
 
 	/*
@@ -694,23 +671,11 @@
 error_unregister_buffer:
 	at91_adc_buffer_remove(idev);
 error_disable_adc_clk:
-	clk_disable(st->adc_clk);
-error_unprepare_adc_clk:
-	clk_unprepare(st->adc_clk);
-error_free_adc_clk:
-	clk_put(st->adc_clk);
+	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
-	clk_disable(st->clk);
-error_unprepare_clk:
-	clk_unprepare(st->clk);
-error_free_clk:
-	clk_put(st->clk);
+	clk_disable_unprepare(st->clk);
 error_free_irq:
 	free_irq(st->irq, idev);
-error_unmap_reg:
-	iounmap(st->reg_base);
-error_release_mem:
-	release_mem_region(res->start, resource_size(res));
 error_free_device:
 	iio_device_free(idev);
 error_ret:
@@ -720,20 +685,14 @@
 static int __devexit at91_adc_remove(struct platform_device *pdev)
 {
 	struct iio_dev *idev = platform_get_drvdata(pdev);
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
 	at91_adc_trigger_remove(idev);
 	at91_adc_buffer_remove(idev);
 	clk_disable_unprepare(st->adc_clk);
-	clk_put(st->adc_clk);
-	clk_disable(st->clk);
-	clk_unprepare(st->clk);
-	clk_put(st->clk);
+	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
-	iounmap(st->reg_base);
-	release_mem_region(res->start, resource_size(res));
 	iio_device_free(idev);
 
 	return 0;
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
new file mode 100644
index 0000000..a93aaf0
--- /dev/null
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -0,0 +1,264 @@
+/*
+ * TI LP8788 MFD - ADC driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/machine.h>
+#include <linux/mfd/lp8788.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* register address */
+#define LP8788_ADC_CONF			0x60
+#define LP8788_ADC_RAW			0x61
+#define LP8788_ADC_DONE			0x63
+
+#define ADC_CONV_START			1
+
+struct lp8788_adc {
+	struct lp8788 *lp;
+	struct iio_map *map;
+	struct mutex lock;
+};
+
+static const int lp8788_scale[LPADC_MAX] = {
+	[LPADC_VBATT_5P5] = 1343101,
+	[LPADC_VIN_CHG]   = 3052503,
+	[LPADC_IBATT]     = 610500,
+	[LPADC_IC_TEMP]   = 61050,
+	[LPADC_VBATT_6P0] = 1465201,
+	[LPADC_VBATT_5P0] = 1221001,
+	[LPADC_ADC1]      = 610500,
+	[LPADC_ADC2]      = 610500,
+	[LPADC_VDD]       = 1025641,
+	[LPADC_VCOIN]     = 757020,
+	[LPADC_ADC3]      = 610500,
+	[LPADC_ADC4]      = 610500,
+};
+
+static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id,
+				int *val)
+{
+	unsigned int msb;
+	unsigned int lsb;
+	unsigned int result;
+	u8 data;
+	u8 rawdata[2];
+	int size = ARRAY_SIZE(rawdata);
+	int retry = 5;
+	int ret;
+
+	data = (id << 1) | ADC_CONV_START;
+	ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data);
+	if (ret)
+		goto err_io;
+
+	/* retry until adc conversion is done */
+	data = 0;
+	while (retry--) {
+		usleep_range(100, 200);
+
+		ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data);
+		if (ret)
+			goto err_io;
+
+		/* conversion done */
+		if (data)
+			break;
+	}
+
+	ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size);
+	if (ret)
+		goto err_io;
+
+	msb = (rawdata[0] << 4) & 0x00000ff0;
+	lsb = (rawdata[1] >> 4) & 0x0000000f;
+	result = msb | lsb;
+	*val = result;
+
+	return 0;
+
+err_io:
+	return ret;
+}
+
+static int lp8788_adc_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	struct lp8788_adc *adc = iio_priv(indio_dev);
+	enum lp8788_adc_id id = chan->channel;
+	int ret;
+
+	mutex_lock(&adc->lock);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = lp8788_scale[id] / 1000000;
+		*val2 = lp8788_scale[id] % 1000000;
+		ret = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&adc->lock);
+
+	return ret;
+}
+
+static const struct iio_info lp8788_adc_info = {
+	.read_raw = &lp8788_adc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define LP8788_CHAN(_id, _type) {				\
+		.type = _type,					\
+		.indexed = 1,					\
+		.channel = LPADC_##_id,				\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,	\
+		.datasheet_name = #_id,				\
+}
+
+static const struct iio_chan_spec lp8788_adc_channels[] = {
+	[LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE),
+	[LPADC_VIN_CHG]   = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE),
+	[LPADC_IBATT]     = LP8788_CHAN(IBATT, IIO_CURRENT),
+	[LPADC_IC_TEMP]   = LP8788_CHAN(IC_TEMP, IIO_TEMP),
+	[LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE),
+	[LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE),
+	[LPADC_ADC1]      = LP8788_CHAN(ADC1, IIO_VOLTAGE),
+	[LPADC_ADC2]      = LP8788_CHAN(ADC2, IIO_VOLTAGE),
+	[LPADC_VDD]       = LP8788_CHAN(VDD, IIO_VOLTAGE),
+	[LPADC_VCOIN]     = LP8788_CHAN(VCOIN, IIO_VOLTAGE),
+	[LPADC_ADC3]      = LP8788_CHAN(ADC3, IIO_VOLTAGE),
+	[LPADC_ADC4]      = LP8788_CHAN(ADC4, IIO_VOLTAGE),
+};
+
+/* default maps used by iio consumer (lp8788-charger driver) */
+static struct iio_map lp8788_default_iio_maps[] = {
+	{
+		.consumer_dev_name = "lp8788-charger",
+		.consumer_channel = "lp8788_vbatt_5p0",
+		.adc_channel_label = "VBATT_5P0",
+	},
+	{
+		.consumer_dev_name = "lp8788-charger",
+		.consumer_channel = "lp8788_adc1",
+		.adc_channel_label = "ADC1",
+	},
+	{ }
+};
+
+static int lp8788_iio_map_register(struct iio_dev *indio_dev,
+				struct lp8788_platform_data *pdata,
+				struct lp8788_adc *adc)
+{
+	struct iio_map *map;
+	int ret;
+
+	map = (!pdata || !pdata->adc_pdata) ?
+		lp8788_default_iio_maps : pdata->adc_pdata;
+
+	ret = iio_map_array_register(indio_dev, map);
+	if (ret) {
+		dev_err(adc->lp->dev, "iio map err: %d\n", ret);
+		return ret;
+	}
+
+	adc->map = map;
+	return 0;
+}
+
+static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
+				struct lp8788_adc *adc)
+{
+	iio_map_array_unregister(indio_dev, adc->map);
+}
+
+static int __devinit lp8788_adc_probe(struct platform_device *pdev)
+{
+	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+	struct iio_dev *indio_dev;
+	struct lp8788_adc *adc;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*adc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc = iio_priv(indio_dev);
+	adc->lp = lp;
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
+	if (ret)
+		goto err_iio_map;
+
+	mutex_init(&adc->lock);
+
+	indio_dev->dev.parent = lp->dev;
+	indio_dev->name = pdev->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &lp8788_adc_info;
+	indio_dev->channels = lp8788_adc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(lp->dev, "iio dev register err: %d\n", ret);
+		goto err_iio_device;
+	}
+
+	return 0;
+
+err_iio_device:
+	lp8788_iio_map_unregister(indio_dev, adc);
+err_iio_map:
+	iio_device_free(indio_dev);
+	return ret;
+}
+
+static int __devexit lp8788_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct lp8788_adc *adc = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	lp8788_iio_map_unregister(indio_dev, adc);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver lp8788_adc_driver = {
+	.probe = lp8788_adc_probe,
+	.remove = __devexit_p(lp8788_adc_remove),
+	.driver = {
+		.name = LP8788_DEV_ADC,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(lp8788_adc_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-adc");
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
new file mode 100644
index 0000000..ed45ee5
--- /dev/null
+++ b/drivers/iio/common/Kconfig
@@ -0,0 +1,5 @@
+#
+# IIO common modules
+#
+
+source "drivers/iio/common/hid-sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
new file mode 100644
index 0000000..8158400
--- /dev/null
+++ b/drivers/iio/common/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the IIO common modules.
+# Common modules contains modules, which can be shared among multiple
+# IIO modules. For example if the trigger processing is common for
+# multiple IIO modules then this can be moved to a common module
+# instead of duplicating in each module.
+#
+
+obj-y += hid-sensors/
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig
new file mode 100644
index 0000000..8e63d81
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/Kconfig
@@ -0,0 +1,26 @@
+#
+# Hid Sensor common modules
+#
+menu "Hid Sensor IIO Common"
+
+config HID_SENSOR_IIO_COMMON
+	tristate "Common modules for all HID Sensor IIO drivers"
+	depends on HID_SENSOR_HUB
+	select IIO_TRIGGER if IIO_BUFFER
+	help
+	  Say yes here to build support for HID sensor to use
+	  HID sensor common processing for attributes and IIO triggers.
+	  There are many attributes which can be shared among multiple
+	  HID sensor drivers, this module contains processing for those
+	  attributes.
+
+config HID_SENSOR_ENUM_BASE_QUIRKS
+	tristate "ENUM base quirks for HID Sensor IIO drivers"
+	depends on HID_SENSOR_IIO_COMMON
+	help
+	  Say yes here to build support for sensor hub FW using
+	  enumeration, which is using 1 as base instead of 0.
+	  Since logical minimum is still set 0 instead of 1,
+	  there is no easy way to differentiate.
+
+endmenu
diff --git a/drivers/iio/common/hid-sensors/Makefile b/drivers/iio/common/hid-sensors/Makefile
new file mode 100644
index 0000000..1f463e0
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Hid sensor common modules.
+#
+
+obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
+hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
new file mode 100644
index 0000000..7537495
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -0,0 +1,250 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "hid-sensor-attributes.h"
+
+static int pow_10(unsigned power)
+{
+	int i;
+	int ret = 1;
+	for (i = 0; i < power; ++i)
+		ret = ret * 10;
+
+	return ret;
+}
+
+static void simple_div(int dividend, int divisor, int *whole,
+				int *micro_frac)
+{
+	int rem;
+	int exp = 0;
+
+	*micro_frac = 0;
+	if (divisor == 0) {
+		*whole = 0;
+		return;
+	}
+	*whole = dividend/divisor;
+	rem = dividend % divisor;
+	if (rem) {
+		while (rem <= divisor) {
+			rem *= 10;
+			exp++;
+		}
+		*micro_frac = (rem / divisor) * pow_10(6-exp);
+	}
+}
+
+static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
+{
+	*val1 = no/pow_10(exp);
+	*val2 = no%pow_10(exp) * pow_10(6-exp);
+}
+
+/*
+VTF format uses exponent and variable size format.
+For example if the size is 2 bytes
+0x0067 with VTF16E14 format -> +1.03
+To convert just change to 0x67 to decimal and use two decimal as E14 stands
+for 10^-2.
+Negative numbers are 2's complement
+*/
+static void convert_from_vtf_format(u32 value, int size, int exp,
+					int *val1, int *val2)
+{
+	int sign = 1;
+
+	if (value & BIT(size*8 - 1)) {
+		value =  ((1LL << (size * 8)) - value);
+		sign = -1;
+	}
+	exp = hid_sensor_convert_exponent(exp);
+	if (exp >= 0) {
+		*val1 = sign * value * pow_10(exp);
+		*val2 = 0;
+	} else {
+		split_micro_fraction(value, -exp, val1, val2);
+		if (*val1)
+			*val1 = sign * (*val1);
+		else
+			*val2 = sign * (*val2);
+	}
+}
+
+static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
+{
+	u32 value;
+	int sign = 1;
+
+	if (val1 < 0 || val2 < 0)
+		sign = -1;
+	exp = hid_sensor_convert_exponent(exp);
+	if (exp < 0) {
+		value = abs(val1) * pow_10(-exp);
+		value += abs(val2) / pow_10(6+exp);
+	} else
+		value = abs(val1) / pow_10(exp);
+	if (sign < 0)
+		value =  ((1LL << (size * 8)) - value);
+
+	return value;
+}
+
+int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
+				int *val1, int *val2)
+{
+	s32 value;
+	int ret;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+		st->poll.report_id,
+		st->poll.index, &value);
+	if (ret < 0 || value < 0) {
+		*val1 = *val2 = 0;
+		return -EINVAL;
+	} else {
+		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+			simple_div(1000, value, val1, val2);
+		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+			simple_div(1, value, val1, val2);
+		else {
+			*val1 = *val2 = 0;
+			return -EINVAL;
+		}
+	}
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
+
+int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
+				int val1, int val2)
+{
+	s32 value;
+	int ret;
+
+	if (val1 < 0 || val2 < 0)
+		ret = -EINVAL;
+
+	value = val1 * pow_10(6) + val2;
+	if (value) {
+		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+			value = pow_10(9)/value;
+		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+			value = pow_10(6)/value;
+		else
+			value = 0;
+	}
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->poll.report_id,
+		st->poll.index, value);
+	if (ret < 0 || value < 0)
+		ret = -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
+
+int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
+				int *val1, int *val2)
+{
+	s32 value;
+	int ret;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index, &value);
+	if (ret < 0 || value < 0) {
+		*val1 = *val2 = 0;
+		return -EINVAL;
+	} else {
+		convert_from_vtf_format(value, st->sensitivity.size,
+					st->sensitivity.unit_expo,
+					val1, val2);
+	}
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
+
+int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
+					int val1, int val2)
+{
+	s32 value;
+	int ret;
+
+	value = convert_to_vtf_format(st->sensitivity.size,
+				st->sensitivity.unit_expo,
+				val1, val2);
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index, value);
+	if (ret < 0 || value < 0)
+		ret = -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_iio_common *st)
+{
+
+	sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
+					&st->poll);
+
+	sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_USAGE_SENSOR_PROP_REPORT_STATE,
+					&st->report_state);
+
+	sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_USAGE_SENSOR_PROY_POWER_STATE,
+					&st->power_state);
+
+	sensor_hub_input_get_attribute_info(hsdev,
+			HID_FEATURE_REPORT, usage_id,
+			HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
+			 &st->sensitivity);
+
+	hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
+			st->poll.index, st->poll.report_id,
+			st->report_state.index, st->report_state.report_id,
+			st->power_state.index, st->power_state.report_id,
+			st->sensitivity.index, st->sensitivity.report_id);
+
+	return 0;
+}
+EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_DESCRIPTION("HID Sensor common attribute processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h
new file mode 100644
index 0000000..a4676a0
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h
@@ -0,0 +1,57 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+#ifndef _HID_SENSORS_ATTRIBUTES_H
+#define _HID_SENSORS_ATTRIBUTES_H
+
+/* Common hid sensor iio structure */
+struct hid_sensor_iio_common {
+	struct hid_sensor_hub_device *hsdev;
+	struct platform_device *pdev;
+	unsigned usage_id;
+	bool data_ready;
+	struct hid_sensor_hub_attribute_info poll;
+	struct hid_sensor_hub_attribute_info report_state;
+	struct hid_sensor_hub_attribute_info power_state;
+	struct hid_sensor_hub_attribute_info sensitivity;
+};
+
+/*Convert from hid unit expo to regular exponent*/
+static inline int hid_sensor_convert_exponent(int unit_expo)
+{
+	if (unit_expo < 0x08)
+		return unit_expo;
+	else if (unit_expo <= 0x0f)
+		return -(0x0f-unit_expo+1);
+	else
+		return 0;
+}
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_iio_common *st);
+int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
+					int val1, int val2);
+int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
+					int *val1, int *val2);
+int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
+					int val1, int val2);
+int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
+					int *val1, int *val2);
+
+#endif
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
new file mode 100644
index 0000000..d4b790d
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -0,0 +1,103 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/sysfs.h>
+#include "hid-sensor-attributes.h"
+#include "hid-sensor-trigger.h"
+
+static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
+						bool state)
+{
+	struct hid_sensor_iio_common *st = trig->private_data;
+	int state_val;
+
+	state_val = state ? 1 : 0;
+#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
+	(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
+	++state_val;
+#endif
+	st->data_ready = state;
+	sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
+					st->power_state.index,
+					(s32)state_val);
+
+	sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
+					st->report_state.index,
+					(s32)state_val);
+
+	return 0;
+}
+
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
+{
+	iio_trigger_unregister(indio_dev->trig);
+	iio_trigger_free(indio_dev->trig);
+	indio_dev->trig = NULL;
+}
+EXPORT_SYMBOL(hid_sensor_remove_trigger);
+
+static const struct iio_trigger_ops hid_sensor_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
+};
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
+				struct hid_sensor_iio_common *attrb)
+{
+	int ret;
+	struct iio_trigger *trig;
+
+	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
+	if (trig == NULL) {
+		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	trig->dev.parent = indio_dev->dev.parent;
+	trig->private_data = attrb;
+	trig->ops = &hid_sensor_trigger_ops;
+	ret = iio_trigger_register(trig);
+
+	if (ret) {
+		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
+		goto error_free_trig;
+	}
+	indio_dev->trig = trig;
+
+	return ret;
+
+error_free_trig:
+	iio_trigger_free(trig);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(hid_sensor_setup_trigger);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_DESCRIPTION("HID Sensor trigger processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
new file mode 100644
index 0000000..fd98297
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -0,0 +1,26 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+#ifndef _HID_SENSOR_TRIGGER_H
+#define _HID_SENSOR_TRIGGER_H
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
+				struct hid_sensor_iio_common *attrb);
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
+
+#endif
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 1be15fa..b1c0ee5 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -57,11 +57,12 @@
 
 config AD5446
 	tristate "Analog Devices AD5446 and similar single channel DACs driver"
-	depends on SPI
+	depends on (SPI_MASTER || I2C)
 	help
-	  Say yes here to build support for Analog Devices AD5444, AD5446, AD5450,
-	  AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601,
-	  AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 DACs.
+	  Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
+	  AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
+	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
+	  AD5620, AD5621, AD5622, AD5640, AD5660, AD5662 DACs.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5446.
@@ -76,6 +77,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5504.
 
+config AD5755
+	tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
+	depends on SPI_MASTER
+	help
+	  Say yes here to build support for Analog Devices AD5755, AD5755-1,
+	  AD5757, AD5735, AD5737 quad channel Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5755.
+
 config AD5764
 	tristate "Analog Devices AD5764/64R/44/44R DAC driver"
 	depends on SPI_MASTER
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 9ea3cee..c0d333b 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_AD5064) += ad5064.o
 obj-$(CONFIG_AD5504) += ad5504.o
 obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_AD5755) += ad5755.o
 obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5791) += ad5791.o
 obj-$(CONFIG_AD5686) += ad5686.o
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index 2ca5059..3310cbb 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -14,6 +14,7 @@
 #include <linux/sysfs.h>
 #include <linux/list.h>
 #include <linux/spi/spi.h>
+#include <linux/i2c.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 #include <linux/module.h>
@@ -21,24 +22,40 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
-#include "ad5446.h"
+#define MODE_PWRDWN_1k		0x1
+#define MODE_PWRDWN_100k	0x2
+#define MODE_PWRDWN_TRISTATE	0x3
 
-static int ad5446_write(struct ad5446_state *st, unsigned val)
-{
-	__be16 data = cpu_to_be16(val);
-	return spi_write(st->spi, &data, sizeof(data));
-}
+/**
+ * struct ad5446_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ */
 
-static int ad5660_write(struct ad5446_state *st, unsigned val)
-{
-	uint8_t data[3];
+struct ad5446_state {
+	struct device		*dev;
+	const struct ad5446_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			cached_val;
+	unsigned			pwr_down_mode;
+	unsigned			pwr_down;
+};
 
-	data[0] = (val >> 16) & 0xFF;
-	data[1] = (val >> 8) & 0xFF;
-	data[2] = val & 0xFF;
+/**
+ * struct ad5446_chip_info - chip specific information
+ * @channel:		channel spec for the DAC
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ * @write:		chip specific helper function to write to the register
+ */
 
-	return spi_write(st->spi, data, sizeof(data));
-}
+struct ad5446_chip_info {
+	struct iio_chan_spec	channel;
+	u16			int_vref_mv;
+	int			(*write)(struct ad5446_state *st, unsigned val);
+};
 
 static const char * const ad5446_powerdown_modes[] = {
 	"1kohm_to_gnd", "100kohm_to_gnd", "three_state"
@@ -110,7 +127,7 @@
 	return ret ? ret : len;
 }
 
-static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
 	{
 		.name = "powerdown",
 		.read = ad5446_read_dac_powerdown,
@@ -136,9 +153,209 @@
 	_AD5446_CHANNEL(bits, storage, shift, NULL)
 
 #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
-	_AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+	_AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown)
 
-static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
+static int ad5446_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->cached_val;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5446_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		val <<= chan->scan_type.shift;
+		mutex_lock(&indio_dev->mlock);
+		st->cached_val = val;
+		if (!st->pwr_down)
+			ret = st->chip_info->write(st, val);
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5446_info = {
+	.read_raw = ad5446_read_raw,
+	.write_raw = ad5446_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5446_probe(struct device *dev, const char *name,
+	const struct ad5446_chip_info *chip_info)
+{
+	struct ad5446_state *st;
+	struct iio_dev *indio_dev;
+	struct regulator *reg;
+	int ret, voltage_uv = 0;
+
+	reg = regulator_get(dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(reg);
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_disable_reg;
+	}
+	st = iio_priv(indio_dev);
+	st->chip_info = chip_info;
+
+	dev_set_drvdata(dev, indio_dev);
+	st->reg = reg;
+	st->dev = dev;
+
+	/* Establish that the iio_dev is a child of the device */
+	indio_dev->dev.parent = dev;
+	indio_dev->name = name;
+	indio_dev->info = &ad5446_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = &st->chip_info->channel;
+	indio_dev->num_channels = 1;
+
+	st->pwr_down_mode = MODE_PWRDWN_1k;
+
+	if (st->chip_info->int_vref_mv)
+		st->vref_mv = st->chip_info->int_vref_mv;
+	else if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		dev_warn(dev, "reference voltage unspecified\n");
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_device;
+
+	return 0;
+
+error_free_device:
+	iio_device_free(indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	return ret;
+}
+
+static int ad5446_remove(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static int ad5446_write(struct ad5446_state *st, unsigned val)
+{
+	struct spi_device *spi = to_spi_device(st->dev);
+	__be16 data = cpu_to_be16(val);
+
+	return spi_write(spi, &data, sizeof(data));
+}
+
+static int ad5660_write(struct ad5446_state *st, unsigned val)
+{
+	struct spi_device *spi = to_spi_device(st->dev);
+	uint8_t data[3];
+
+	data[0] = (val >> 16) & 0xFF;
+	data[1] = (val >> 8) & 0xFF;
+	data[2] = val & 0xFF;
+
+	return spi_write(spi, data, sizeof(data));
+}
+
+/**
+ * ad5446_supported_spi_device_ids:
+ * The AD5620/40/60 parts are available in different fixed internal reference
+ * voltage options. The actual part numbers may look differently
+ * (and a bit cryptic), however this style is used to make clear which
+ * parts are supported here.
+ */
+enum ad5446_supported_spi_device_ids {
+	ID_AD5300,
+	ID_AD5310,
+	ID_AD5320,
+	ID_AD5444,
+	ID_AD5446,
+	ID_AD5450,
+	ID_AD5451,
+	ID_AD5541A,
+	ID_AD5512A,
+	ID_AD5553,
+	ID_AD5601,
+	ID_AD5611,
+	ID_AD5621,
+	ID_AD5620_2500,
+	ID_AD5620_1250,
+	ID_AD5640_2500,
+	ID_AD5640_1250,
+	ID_AD5660_2500,
+	ID_AD5660_1250,
+	ID_AD5662,
+};
+
+static const struct ad5446_chip_info ad5446_spi_chip_info[] = {
+	[ID_AD5300] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5310] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
+		.write = ad5446_write,
+	},
+	[ID_AD5320] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
+		.write = ad5446_write,
+	},
 	[ID_AD5444] = {
 		.channel = AD5446_CHANNEL(12, 16, 2),
 		.write = ad5446_write,
@@ -215,143 +432,10 @@
 	},
 };
 
-static int ad5446_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		*val = st->cached_val;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
-		*val =  scale_uv / 1000;
-		*val2 = (scale_uv % 1000) * 1000;
-		return IIO_VAL_INT_PLUS_MICRO;
-
-	}
-	return -EINVAL;
-}
-
-static int ad5446_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	int ret = 0;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		val <<= chan->scan_type.shift;
-		mutex_lock(&indio_dev->mlock);
-		st->cached_val = val;
-		if (!st->pwr_down)
-			ret = st->chip_info->write(st, val);
-		mutex_unlock(&indio_dev->mlock);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static const struct iio_info ad5446_info = {
-	.read_raw = ad5446_read_raw,
-	.write_raw = ad5446_write_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5446_probe(struct spi_device *spi)
-{
-	struct ad5446_state *st;
-	struct iio_dev *indio_dev;
-	struct regulator *reg;
-	int ret, voltage_uv = 0;
-
-	reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(reg)) {
-		ret = regulator_enable(reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(reg);
-	}
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_disable_reg;
-	}
-	st = iio_priv(indio_dev);
-	st->chip_info =
-		&ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
-
-	spi_set_drvdata(spi, indio_dev);
-	st->reg = reg;
-	st->spi = spi;
-
-	/* Establish that the iio_dev is a child of the spi device */
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5446_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = &st->chip_info->channel;
-	indio_dev->num_channels = 1;
-
-	st->pwr_down_mode = MODE_PWRDWN_1k;
-
-	if (st->chip_info->int_vref_mv)
-		st->vref_mv = st->chip_info->int_vref_mv;
-	else if (voltage_uv)
-		st->vref_mv = voltage_uv / 1000;
-	else
-		dev_warn(&spi->dev, "reference voltage unspecified\n");
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_device;
-
-	return 0;
-
-error_free_device:
-	iio_device_free(indio_dev);
-error_disable_reg:
-	if (!IS_ERR(reg))
-		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-
-	return ret;
-}
-
-static int ad5446_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5446_id[] = {
+static const struct spi_device_id ad5446_spi_ids[] = {
+	{"ad5300", ID_AD5300},
+	{"ad5310", ID_AD5310},
+	{"ad5320", ID_AD5320},
 	{"ad5444", ID_AD5444},
 	{"ad5446", ID_AD5446},
 	{"ad5450", ID_AD5450},
@@ -375,18 +459,160 @@
 	{"ad5662", ID_AD5662},
 	{}
 };
-MODULE_DEVICE_TABLE(spi, ad5446_id);
+MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
 
-static struct spi_driver ad5446_driver = {
+static int __devinit ad5446_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	return ad5446_probe(&spi->dev, id->name,
+		&ad5446_spi_chip_info[id->driver_data]);
+}
+
+static int __devexit ad5446_spi_remove(struct spi_device *spi)
+{
+	return ad5446_remove(&spi->dev);
+}
+
+static struct spi_driver ad5446_spi_driver = {
 	.driver = {
 		.name	= "ad5446",
 		.owner	= THIS_MODULE,
 	},
-	.probe		= ad5446_probe,
-	.remove		= __devexit_p(ad5446_remove),
-	.id_table	= ad5446_id,
+	.probe		= ad5446_spi_probe,
+	.remove		= __devexit_p(ad5446_spi_remove),
+	.id_table	= ad5446_spi_ids,
 };
-module_spi_driver(ad5446_driver);
+
+static int __init ad5446_spi_register_driver(void)
+{
+	return spi_register_driver(&ad5446_spi_driver);
+}
+
+static void ad5446_spi_unregister_driver(void)
+{
+	spi_unregister_driver(&ad5446_spi_driver);
+}
+
+#else
+
+static inline int ad5446_spi_register_driver(void) { return 0; }
+static inline void ad5446_spi_unregister_driver(void) { }
+
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+
+static int ad5622_write(struct ad5446_state *st, unsigned val)
+{
+	struct i2c_client *client = to_i2c_client(st->dev);
+	__be16 data = cpu_to_be16(val);
+
+	return i2c_master_send(client, (char *)&data, sizeof(data));
+}
+
+/**
+ * ad5446_supported_i2c_device_ids:
+ * The AD5620/40/60 parts are available in different fixed internal reference
+ * voltage options. The actual part numbers may look differently
+ * (and a bit cryptic), however this style is used to make clear which
+ * parts are supported here.
+ */
+enum ad5446_supported_i2c_device_ids {
+	ID_AD5602,
+	ID_AD5612,
+	ID_AD5622,
+};
+
+static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
+	[ID_AD5602] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
+		.write = ad5622_write,
+	},
+	[ID_AD5612] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
+		.write = ad5622_write,
+	},
+	[ID_AD5622] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
+		.write = ad5622_write,
+	},
+};
+
+static int __devinit ad5446_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	return ad5446_probe(&i2c->dev, id->name,
+		&ad5446_i2c_chip_info[id->driver_data]);
+}
+
+static int __devexit ad5446_i2c_remove(struct i2c_client *i2c)
+{
+	return ad5446_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5446_i2c_ids[] = {
+	{"ad5301", ID_AD5602},
+	{"ad5311", ID_AD5612},
+	{"ad5321", ID_AD5622},
+	{"ad5602", ID_AD5602},
+	{"ad5612", ID_AD5612},
+	{"ad5622", ID_AD5622},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
+
+static struct i2c_driver ad5446_i2c_driver = {
+	.driver = {
+		   .name = "ad5446",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5446_i2c_probe,
+	.remove = __devexit_p(ad5446_i2c_remove),
+	.id_table = ad5446_i2c_ids,
+};
+
+static int __init ad5446_i2c_register_driver(void)
+{
+	return i2c_add_driver(&ad5446_i2c_driver);
+}
+
+static void __exit ad5446_i2c_unregister_driver(void)
+{
+	i2c_del_driver(&ad5446_i2c_driver);
+}
+
+#else
+
+static inline int ad5446_i2c_register_driver(void) { return 0; }
+static inline void ad5446_i2c_unregister_driver(void) { }
+
+#endif
+
+static int __init ad5446_init(void)
+{
+	int ret;
+
+	ret = ad5446_spi_register_driver();
+	if (ret)
+		return ret;
+
+	ret = ad5446_i2c_register_driver();
+	if (ret) {
+		ad5446_spi_unregister_driver();
+		return ret;
+	}
+
+	return 0;
+}
+module_init(ad5446_init);
+
+static void __exit ad5446_exit(void)
+{
+	ad5446_i2c_unregister_driver();
+	ad5446_spi_unregister_driver();
+}
+module_exit(ad5446_exit);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
diff --git a/drivers/iio/dac/ad5446.h b/drivers/iio/dac/ad5446.h
deleted file mode 100644
index 2934269..0000000
--- a/drivers/iio/dac/ad5446.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * AD5446 SPI DAC driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-#ifndef IIO_DAC_AD5446_H_
-#define IIO_DAC_AD5446_H_
-
-/* DAC Control Bits */
-
-#define AD5446_LOAD		(0x0 << 14) /* Load and update */
-#define AD5446_SDO_DIS		(0x1 << 14) /* Disable SDO */
-#define AD5446_NOP		(0x2 << 14) /* No operation */
-#define AD5446_CLK_RISING	(0x3 << 14) /* Clock data on rising edge */
-
-#define AD5620_LOAD		(0x0 << 14) /* Load and update Norm Operation*/
-#define AD5620_PWRDWN_1k	(0x1 << 14) /* Power-down: 1kOhm to GND */
-#define AD5620_PWRDWN_100k	(0x2 << 14) /* Power-down: 100kOhm to GND */
-#define AD5620_PWRDWN_TRISTATE	(0x3 << 14) /* Power-down: Three-state */
-
-#define AD5660_LOAD		(0x0 << 16) /* Load and update Norm Operation*/
-#define AD5660_PWRDWN_1k	(0x1 << 16) /* Power-down: 1kOhm to GND */
-#define AD5660_PWRDWN_100k	(0x2 << 16) /* Power-down: 100kOhm to GND */
-#define AD5660_PWRDWN_TRISTATE	(0x3 << 16) /* Power-down: Three-state */
-
-#define MODE_PWRDWN_1k		0x1
-#define MODE_PWRDWN_100k	0x2
-#define MODE_PWRDWN_TRISTATE	0x3
-
-/**
- * struct ad5446_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @reg:		supply regulator
- * @vref_mv:		actual reference voltage used
- */
-
-struct ad5446_state {
-	struct spi_device		*spi;
-	const struct ad5446_chip_info	*chip_info;
-	struct regulator		*reg;
-	unsigned short			vref_mv;
-	unsigned			cached_val;
-	unsigned			pwr_down_mode;
-	unsigned			pwr_down;
-};
-
-/**
- * struct ad5446_chip_info - chip specific information
- * @channel:		channel spec for the DAC
- * @int_vref_mv:	AD5620/40/60: the internal reference voltage
- * @write:		chip specific helper function to write to the register
- */
-
-struct ad5446_chip_info {
-	struct iio_chan_spec	channel;
-	u16			int_vref_mv;
-	int			(*write)(struct ad5446_state *st, unsigned val);
-};
-
-/**
- * ad5446_supported_device_ids:
- * The AD5620/40/60 parts are available in different fixed internal reference
- * voltage options. The actual part numbers may look differently
- * (and a bit cryptic), however this style is used to make clear which
- * parts are supported here.
- */
-
-enum ad5446_supported_device_ids {
-	ID_AD5444,
-	ID_AD5446,
-	ID_AD5450,
-	ID_AD5451,
-	ID_AD5541A,
-	ID_AD5512A,
-	ID_AD5553,
-	ID_AD5601,
-	ID_AD5611,
-	ID_AD5621,
-	ID_AD5620_2500,
-	ID_AD5620_1250,
-	ID_AD5640_2500,
-	ID_AD5640_1250,
-	ID_AD5660_2500,
-	ID_AD5660_1250,
-	ID_AD5662,
-};
-
-#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
new file mode 100644
index 0000000..5db3506
--- /dev/null
+++ b/drivers/iio/dac/ad5755.c
@@ -0,0 +1,650 @@
+/*
+ * AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/platform_data/ad5755.h>
+
+#define AD5755_NUM_CHANNELS 4
+
+#define AD5755_ADDR(x)			((x) << 16)
+
+#define AD5755_WRITE_REG_DATA(chan)	(chan)
+#define AD5755_WRITE_REG_GAIN(chan)	(0x08 | (chan))
+#define AD5755_WRITE_REG_OFFSET(chan)	(0x10 | (chan))
+#define AD5755_WRITE_REG_CTRL(chan)	(0x1c | (chan))
+
+#define AD5755_READ_REG_DATA(chan)	(chan)
+#define AD5755_READ_REG_CTRL(chan)	(0x4 | (chan))
+#define AD5755_READ_REG_GAIN(chan)	(0x8 | (chan))
+#define AD5755_READ_REG_OFFSET(chan)	(0xc | (chan))
+#define AD5755_READ_REG_CLEAR(chan)	(0x10 | (chan))
+#define AD5755_READ_REG_SLEW(chan)	(0x14 | (chan))
+#define AD5755_READ_REG_STATUS		0x18
+#define AD5755_READ_REG_MAIN		0x19
+#define AD5755_READ_REG_DC_DC		0x1a
+
+#define AD5755_CTRL_REG_SLEW	0x0
+#define AD5755_CTRL_REG_MAIN	0x1
+#define AD5755_CTRL_REG_DAC	0x2
+#define AD5755_CTRL_REG_DC_DC	0x3
+#define AD5755_CTRL_REG_SW	0x4
+
+#define AD5755_READ_FLAG 0x800000
+
+#define AD5755_NOOP 0x1CE000
+
+#define AD5755_DAC_INT_EN			BIT(8)
+#define AD5755_DAC_CLR_EN			BIT(7)
+#define AD5755_DAC_OUT_EN			BIT(6)
+#define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR	BIT(5)
+#define AD5755_DAC_DC_DC_EN			BIT(4)
+#define AD5755_DAC_VOLTAGE_OVERRANGE_EN		BIT(3)
+
+#define AD5755_DC_DC_MAXV			0
+#define AD5755_DC_DC_FREQ_SHIFT			2
+#define AD5755_DC_DC_PHASE_SHIFT		4
+#define AD5755_EXT_DC_DC_COMP_RES		BIT(6)
+
+#define AD5755_SLEW_STEP_SIZE_SHIFT		0
+#define AD5755_SLEW_RATE_SHIFT			3
+#define AD5755_SLEW_ENABLE			BIT(12)
+
+/**
+ * struct ad5755_chip_info - chip specific information
+ * @channel_template:	channel specification
+ * @calib_shift:	shift for the calibration data registers
+ * @has_voltage_out:	whether the chip has voltage outputs
+ */
+struct ad5755_chip_info {
+	const struct iio_chan_spec channel_template;
+	unsigned int calib_shift;
+	bool has_voltage_out;
+};
+
+/**
+ * struct ad5755_state - driver instance specific data
+ * @spi:	spi device the driver is attached to
+ * @chip_info:	chip model specific constants, available modes etc
+ * @pwr_down:	bitmask which contains  hether a channel is powered down or not
+ * @ctrl:	software shadow of the channel ctrl registers
+ * @channels:	iio channel spec for the device
+ * @data:	spi transfer buffers
+ */
+struct ad5755_state {
+	struct spi_device		*spi;
+	const struct ad5755_chip_info	*chip_info;
+	unsigned int			pwr_down;
+	unsigned int			ctrl[AD5755_NUM_CHANNELS];
+	struct iio_chan_spec		channels[AD5755_NUM_CHANNELS];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+enum ad5755_type {
+	ID_AD5755,
+	ID_AD5757,
+	ID_AD5735,
+	ID_AD5737,
+};
+
+static int ad5755_write_unlocked(struct iio_dev *indio_dev,
+	unsigned int reg, unsigned int val)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+
+	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev,
+	unsigned int channel, unsigned int reg, unsigned int val)
+{
+	return ad5755_write_unlocked(indio_dev,
+		AD5755_WRITE_REG_CTRL(channel), (reg << 13) | val);
+}
+
+static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5755_write_unlocked(indio_dev, reg, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel,
+	unsigned int reg, unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.tx_buf = &st->data[1].d8[1],
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16));
+	st->data[1].d32 = cpu_to_be32(AD5755_NOOP);
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5755_update_dac_ctrl(struct iio_dev *indio_dev,
+	unsigned int channel, unsigned int set, unsigned int clr)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	int ret;
+
+	st->ctrl[channel] |= set;
+	st->ctrl[channel] &= ~clr;
+
+	ret = ad5755_write_ctrl_unlocked(indio_dev, channel,
+		AD5755_CTRL_REG_DAC, st->ctrl[channel]);
+
+	return ret;
+}
+
+static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev,
+	unsigned int channel, bool pwr_down)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	unsigned int mask = BIT(channel);
+
+	mutex_lock(&indio_dev->mlock);
+
+	if ((bool)(st->pwr_down & mask) == pwr_down)
+		goto out_unlock;
+
+	if (!pwr_down) {
+		st->pwr_down &= ~mask;
+		ad5755_update_dac_ctrl(indio_dev, channel,
+			AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN, 0);
+		udelay(200);
+		ad5755_update_dac_ctrl(indio_dev, channel,
+			AD5755_DAC_OUT_EN, 0);
+	} else {
+		st->pwr_down |= mask;
+		ad5755_update_dac_ctrl(indio_dev, channel,
+			0, AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN |
+				AD5755_DAC_DC_DC_EN);
+	}
+
+out_unlock:
+	mutex_unlock(&indio_dev->mlock);
+
+	return 0;
+}
+
+static const int ad5755_min_max_table[][2] = {
+	[AD5755_MODE_VOLTAGE_0V_5V] = { 0, 5000 },
+	[AD5755_MODE_VOLTAGE_0V_10V] = { 0, 10000 },
+	[AD5755_MODE_VOLTAGE_PLUSMINUS_5V] = { -5000, 5000 },
+	[AD5755_MODE_VOLTAGE_PLUSMINUS_10V] = { -10000, 10000 },
+	[AD5755_MODE_CURRENT_4mA_20mA] = { 4, 20 },
+	[AD5755_MODE_CURRENT_0mA_20mA] = { 0, 20 },
+	[AD5755_MODE_CURRENT_0mA_24mA] = { 0, 24 },
+};
+
+static void ad5755_get_min_max(struct ad5755_state *st,
+	struct iio_chan_spec const *chan, int *min, int *max)
+{
+	enum ad5755_mode mode = st->ctrl[chan->channel] & 7;
+	*min = ad5755_min_max_table[mode][0];
+	*max = ad5755_min_max_table[mode][1];
+}
+
+static inline int ad5755_get_offset(struct ad5755_state *st,
+	struct iio_chan_spec const *chan)
+{
+	int min, max;
+
+	ad5755_get_min_max(st, chan, &min, &max);
+	return (min * (1 << chan->scan_type.realbits)) / (max - min);
+}
+
+static inline int ad5755_get_scale(struct ad5755_state *st,
+	struct iio_chan_spec const *chan)
+{
+	int min, max;
+
+	ad5755_get_min_max(st, chan, &min, &max);
+	return ((max - min) * 1000000000ULL) >> chan->scan_type.realbits;
+}
+
+static int ad5755_chan_reg_info(struct ad5755_state *st,
+	struct iio_chan_spec const *chan, long info, bool write,
+	unsigned int *reg, unsigned int *shift, unsigned int *offset)
+{
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		if (write)
+			*reg = AD5755_WRITE_REG_DATA(chan->address);
+		else
+			*reg = AD5755_READ_REG_DATA(chan->address);
+		*shift = chan->scan_type.shift;
+		*offset = 0;
+		break;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (write)
+			*reg = AD5755_WRITE_REG_OFFSET(chan->address);
+		else
+			*reg = AD5755_READ_REG_OFFSET(chan->address);
+		*shift = st->chip_info->calib_shift;
+		*offset = 32768;
+		break;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (write)
+			*reg =  AD5755_WRITE_REG_GAIN(chan->address);
+		else
+			*reg =  AD5755_READ_REG_GAIN(chan->address);
+		*shift = st->chip_info->calib_shift;
+		*offset = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ad5755_read_raw(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, int *val, int *val2, long info)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	unsigned int reg, shift, offset;
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = ad5755_get_scale(st, chan);
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = ad5755_get_offset(st, chan);
+		return IIO_VAL_INT;
+	default:
+		ret = ad5755_chan_reg_info(st, chan, info, false,
+						&reg, &shift, &offset);
+		if (ret)
+			return ret;
+
+		ret = ad5755_read(indio_dev, reg);
+		if (ret < 0)
+			return ret;
+
+		*val = (ret - offset) >> shift;
+
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5755_write_raw(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, int val, int val2, long info)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	unsigned int shift, reg, offset;
+	int ret;
+
+	ret = ad5755_chan_reg_info(st, chan, info, true,
+					&reg, &shift, &offset);
+	if (ret)
+		return ret;
+
+	val <<= shift;
+	val += offset;
+
+	if (val < 0 || val > 0xffff)
+		return -EINVAL;
+
+	return ad5755_write(indio_dev, reg, val);
+}
+
+static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
+	const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n",
+		       (bool)(st->pwr_down & (1 << chan->channel)));
+}
+
+static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
+	struct iio_chan_spec const *chan, const char *buf, size_t len)
+{
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	ret = ad5755_set_channel_pwr_down(indio_dev, chan->channel, pwr_down);
+	return ret ? ret : len;
+}
+
+static const struct iio_info ad5755_info = {
+	.read_raw = ad5755_read_raw,
+	.write_raw = ad5755_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5755_read_powerdown,
+		.write = ad5755_write_powerdown,
+	},
+	{ },
+};
+
+#define AD5755_CHANNEL(_bits) {					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)),	\
+	.ext_info = ad5755_ext_info,				\
+}
+
+static const struct ad5755_chip_info ad5755_chip_info_tbl[] = {
+	[ID_AD5735] = {
+		.channel_template = AD5755_CHANNEL(14),
+		.has_voltage_out = true,
+		.calib_shift = 4,
+	},
+	[ID_AD5737] = {
+		.channel_template = AD5755_CHANNEL(14),
+		.has_voltage_out = false,
+		.calib_shift = 4,
+	},
+	[ID_AD5755] = {
+		.channel_template = AD5755_CHANNEL(16),
+		.has_voltage_out = true,
+		.calib_shift = 0,
+	},
+	[ID_AD5757] = {
+		.channel_template = AD5755_CHANNEL(16),
+		.has_voltage_out = false,
+		.calib_shift = 0,
+	},
+};
+
+static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode)
+{
+	switch (mode) {
+	case AD5755_MODE_VOLTAGE_0V_5V:
+	case AD5755_MODE_VOLTAGE_0V_10V:
+	case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
+	case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
+		return st->chip_info->has_voltage_out;
+	case AD5755_MODE_CURRENT_4mA_20mA:
+	case AD5755_MODE_CURRENT_0mA_20mA:
+	case AD5755_MODE_CURRENT_0mA_24mA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev,
+	const struct ad5755_platform_data *pdata)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	unsigned int val;
+	unsigned int i;
+	int ret;
+
+	if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE ||
+		pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ ||
+		pdata->dc_dc_maxv > AD5755_DC_DC_MAXV_29V5)
+		return -EINVAL;
+
+	val = pdata->dc_dc_maxv << AD5755_DC_DC_MAXV;
+	val |= pdata->dc_dc_freq << AD5755_DC_DC_FREQ_SHIFT;
+	val |= pdata->dc_dc_phase << AD5755_DC_DC_PHASE_SHIFT;
+	if (pdata->ext_dc_dc_compenstation_resistor)
+		val |= AD5755_EXT_DC_DC_COMP_RES;
+
+	ret = ad5755_write_ctrl(indio_dev, 0, AD5755_CTRL_REG_DC_DC, val);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
+		val = pdata->dac[i].slew.step_size <<
+			AD5755_SLEW_STEP_SIZE_SHIFT;
+		val |= pdata->dac[i].slew.rate <<
+			AD5755_SLEW_RATE_SHIFT;
+		if (pdata->dac[i].slew.enable)
+			val |= AD5755_SLEW_ENABLE;
+
+		ret = ad5755_write_ctrl(indio_dev, i,
+					AD5755_CTRL_REG_SLEW, val);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
+		if (!ad5755_is_valid_mode(st, pdata->dac[i].mode))
+			return -EINVAL;
+
+		val = 0;
+		if (!pdata->dac[i].ext_current_sense_resistor)
+			val |= AD5755_DAC_INT_CURRENT_SENSE_RESISTOR;
+		if (pdata->dac[i].enable_voltage_overrange)
+			val |= AD5755_DAC_VOLTAGE_OVERRANGE_EN;
+		val |= pdata->dac[i].mode;
+
+		ret = ad5755_update_dac_ctrl(indio_dev, i, val, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static bool __devinit ad5755_is_voltage_mode(enum ad5755_mode mode)
+{
+	switch (mode) {
+	case AD5755_MODE_VOLTAGE_0V_5V:
+	case AD5755_MODE_VOLTAGE_0V_10V:
+	case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
+	case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int __devinit ad5755_init_channels(struct iio_dev *indio_dev,
+	const struct ad5755_platform_data *pdata)
+{
+	struct ad5755_state *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels = st->channels;
+	unsigned int i;
+
+	for (i = 0; i < AD5755_NUM_CHANNELS; ++i) {
+		channels[i] = st->chip_info->channel_template;
+		channels[i].channel = i;
+		channels[i].address = i;
+		if (pdata && ad5755_is_voltage_mode(pdata->dac[i].mode))
+			channels[i].type = IIO_VOLTAGE;
+		else
+			channels[i].type = IIO_CURRENT;
+	}
+
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+#define AD5755_DEFAULT_DAC_PDATA { \
+		.mode = AD5755_MODE_CURRENT_4mA_20mA, \
+		.ext_current_sense_resistor = true, \
+		.enable_voltage_overrange = false, \
+		.slew = { \
+			.enable = false, \
+			.rate = AD5755_SLEW_RATE_64k, \
+			.step_size = AD5755_SLEW_STEP_SIZE_1, \
+		}, \
+	}
+
+static const struct ad5755_platform_data ad5755_default_pdata = {
+	.ext_dc_dc_compenstation_resistor = false,
+	.dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE,
+	.dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ,
+	.dc_dc_maxv = AD5755_DC_DC_MAXV_23V,
+	.dac = {
+		[0] = AD5755_DEFAULT_DAC_PDATA,
+		[1] = AD5755_DEFAULT_DAC_PDATA,
+		[2] = AD5755_DEFAULT_DAC_PDATA,
+		[3] = AD5755_DEFAULT_DAC_PDATA,
+	},
+};
+
+static int __devinit ad5755_probe(struct spi_device *spi)
+{
+	enum ad5755_type type = spi_get_device_id(spi)->driver_data;
+	const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev);
+	struct iio_dev *indio_dev;
+	struct ad5755_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return  -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->chip_info = &ad5755_chip_info_tbl[type];
+	st->spi = spi;
+	st->pwr_down = 0xf;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5755_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = AD5755_NUM_CHANNELS;
+
+	if (!pdata)
+		pdata = &ad5755_default_pdata;
+
+	ret = ad5755_init_channels(indio_dev, pdata);
+	if (ret)
+		goto error_free;
+
+	ret = ad5755_setup_pdata(indio_dev, pdata);
+	if (ret)
+		goto error_free;
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_free;
+	}
+
+	return 0;
+
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5755_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+	iio_device_unregister(indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5755_id[] = {
+	{ "ad5755", ID_AD5755 },
+	{ "ad5755-1", ID_AD5755 },
+	{ "ad5757", ID_AD5757 },
+	{ "ad5735", ID_AD5735 },
+	{ "ad5737", ID_AD5737 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5755_id);
+
+static struct spi_driver ad5755_driver = {
+	.driver = {
+		.name = "ad5755",
+		.owner = THIS_MODULE,
+	},
+	.probe = ad5755_probe,
+	.remove = __devexit_p(ad5755_remove),
+	.id_table = ad5755_id,
+};
+module_spi_driver(ad5755_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5755/55-1/57/35/37 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
new file mode 100644
index 0000000..21e27e2
--- /dev/null
+++ b/drivers/iio/gyro/Kconfig
@@ -0,0 +1,16 @@
+#
+# IIO Digital Gyroscope Sensor drivers configuration
+#
+menu "Digital gyroscope sensors"
+
+config HID_SENSOR_GYRO_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Gyroscope 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Gyroscope 3D.
+
+endmenu
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
new file mode 100644
index 0000000..8a895d9
--- /dev/null
+++ b/drivers/iio/gyro/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O gyroscope sensor drivers
+#
+
+obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
new file mode 100644
index 0000000..4c56ada
--- /dev/null
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -0,0 +1,418 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-attributes.h"
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+/*Format: HID-SENSOR-usage_id_in_hex*/
+/*Usage ID from spec for Gyro-3D: 0x200076*/
+#define DRIVER_NAME "HID-SENSOR-200076"
+
+enum gyro_3d_channel {
+	CHANNEL_SCAN_INDEX_X,
+	CHANNEL_SCAN_INDEX_Y,
+	CHANNEL_SCAN_INDEX_Z,
+	GYRO_3D_CHANNEL_MAX,
+};
+
+struct gyro_3d_state {
+	struct hid_sensor_hub_callbacks callbacks;
+	struct hid_sensor_iio_common common_attributes;
+	struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];
+	u32 gyro_val[GYRO_3D_CHANNEL_MAX];
+};
+
+static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
+	HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS,
+	HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS,
+	HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec gyro_3d_channels[] = {
+	{
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_X,
+	}, {
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Y,
+	}, {
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Z,
+	}
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+						int channel, int size)
+{
+	channels[channel].scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channels[channel].scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is u32 */
+	channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int gyro_3d_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
+	int report_id = -1;
+	u32 address;
+	int ret;
+	int ret_type;
+
+	*val = 0;
+	*val2 = 0;
+	switch (mask) {
+	case 0:
+		report_id = gyro_state->gyro[chan->scan_index].report_id;
+		address = gyro_3d_addresses[chan->scan_index];
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				gyro_state->common_attributes.hsdev,
+				HID_USAGE_SENSOR_GYRO_3D, address,
+				report_id);
+		else {
+			*val = 0;
+			return -EINVAL;
+		}
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = gyro_state->gyro[CHANNEL_SCAN_INDEX_X].units;
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = hid_sensor_convert_exponent(
+			gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo);
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_read_samp_freq_value(
+			&gyro_state->common_attributes, val, val2);
+			ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_read_raw_hyst_value(
+			&gyro_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	default:
+		ret_type = -EINVAL;
+		break;
+	}
+
+	return ret_type;
+}
+
+/* Channel write_raw handler */
+static int gyro_3d_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_write_samp_freq_value(
+				&gyro_state->common_attributes, val, val2);
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_write_raw_hyst_value(
+				&gyro_state->common_attributes, val, val2);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       long mask)
+{
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static const struct iio_info gyro_3d_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &gyro_3d_read_raw,
+	.write_raw = &gyro_3d_write_raw,
+	.write_raw_get_fmt = &gyro_3d_write_raw_get_fmt,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int datum_sz;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+	if (!buffer) {
+		dev_err(&indio_dev->dev, "Buffer == NULL\n");
+		return;
+	}
+	datum_sz = buffer->access->get_bytes_per_datum(buffer);
+	if (len > datum_sz) {
+		dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+				datum_sz);
+		return;
+	}
+	iio_push_to_buffer(buffer, (u8 *)data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
+
+	dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n",
+				gyro_state->common_attributes.data_ready);
+	if (gyro_state->common_attributes.data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)gyro_state->gyro_val,
+				sizeof(gyro_state->gyro_val));
+
+	return 0;
+}
+
+/* Capture samples in local storage */
+static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				size_t raw_len, char *raw_data,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
+	int offset;
+	int ret = -EINVAL;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS:
+	case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS:
+	case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS:
+		offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;
+		gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
+						*(u32 *)raw_data;
+		ret = 0;
+	break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int gyro_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				struct iio_chan_spec *channels,
+				unsigned usage_id,
+				struct gyro_3d_state *st)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
+		ret = sensor_hub_input_get_attribute_info(hsdev,
+				HID_INPUT_REPORT,
+				usage_id,
+				HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i,
+				&st->gyro[CHANNEL_SCAN_INDEX_X + i]);
+		if (ret < 0)
+			break;
+		gyro_3d_adjust_channel_bit_mask(channels,
+				CHANNEL_SCAN_INDEX_X + i,
+				st->gyro[CHANNEL_SCAN_INDEX_X + i].size);
+	}
+	dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
+			st->gyro[0].index,
+			st->gyro[0].report_id,
+			st->gyro[1].index, st->gyro[1].report_id,
+			st->gyro[2].index, st->gyro[2].report_id);
+
+	return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	static const char *name = "gyro_3d";
+	struct iio_dev *indio_dev;
+	struct gyro_3d_state *gyro_state;
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_chan_spec *channels;
+
+	indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	platform_set_drvdata(pdev, indio_dev);
+
+	gyro_state = iio_priv(indio_dev);
+	gyro_state->common_attributes.hsdev = hsdev;
+	gyro_state->common_attributes.pdev = pdev;
+
+	ret = hid_sensor_parse_common_attributes(hsdev,
+						HID_USAGE_SENSOR_GYRO_3D,
+						&gyro_state->common_attributes);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup common attributes\n");
+		goto error_free_dev;
+	}
+
+	channels = kmemdup(gyro_3d_channels,
+					sizeof(gyro_3d_channels),
+					GFP_KERNEL);
+	if (!channels) {
+		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		goto error_free_dev;
+	}
+
+	ret = gyro_3d_parse_report(pdev, hsdev, channels,
+					HID_USAGE_SENSOR_GYRO_3D, gyro_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev_mem;
+	}
+
+	indio_dev->channels = channels;
+	indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &gyro_3d_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+		NULL, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+		goto error_free_dev_mem;
+	}
+	gyro_state->common_attributes.data_ready = false;
+	ret = hid_sensor_setup_trigger(indio_dev, name,
+					&gyro_state->common_attributes);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "trigger setup failed\n");
+		goto error_unreg_buffer_funcs;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "device register failed\n");
+		goto error_remove_trigger;
+	}
+
+	gyro_state->callbacks.send_event = gyro_3d_proc_event;
+	gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;
+	gyro_state->callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
+					&gyro_state->callbacks);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "callback reg failed\n");
+		goto error_iio_unreg;
+	}
+
+	return ret;
+
+error_iio_unreg:
+	iio_device_unregister(indio_dev);
+error_remove_trigger:
+	hid_sensor_remove_trigger(indio_dev);
+error_unreg_buffer_funcs:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+	kfree(indio_dev->channels);
+error_free_dev:
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int __devinit hid_gyro_3d_remove(struct platform_device *pdev)
+{
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
+	iio_device_unregister(indio_dev);
+	hid_sensor_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	kfree(indio_dev->channels);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver hid_gyro_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_gyro_3d_probe,
+	.remove		= hid_gyro_3d_remove,
+};
+module_platform_driver(hid_gyro_3d_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Gyroscope 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 4add9bb..d4ad374 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -422,7 +422,7 @@
 			ret = indio_dev->setup_ops->preenable(indio_dev);
 			if (ret) {
 				printk(KERN_ERR
-				       "Buffer not started:"
+				       "Buffer not started: "
 				       "buffer preenable failed\n");
 				goto error_ret;
 			}
@@ -431,12 +431,12 @@
 			ret = buffer->access->request_update(buffer);
 			if (ret) {
 				printk(KERN_INFO
-				       "Buffer not started:"
+				       "Buffer not started: "
 				       "buffer parameter update failed\n");
 				goto error_ret;
 			}
 		}
-		/* Definitely possible for devices to support both of these.*/
+		/* Definitely possible for devices to support both of these. */
 		if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
 			if (!indio_dev->trig) {
 				printk(KERN_INFO
@@ -456,7 +456,7 @@
 			ret = indio_dev->setup_ops->postenable(indio_dev);
 			if (ret) {
 				printk(KERN_INFO
-				       "Buffer not started:"
+				       "Buffer not started: "
 				       "postenable failed\n");
 				indio_dev->currentmode = previous_mode;
 				if (indio_dev->setup_ops->postdisable)
@@ -657,7 +657,7 @@
 /**
  * struct iio_demux_table() - table describing demux memcpy ops
  * @from:	index to copy from
- * @to:	index to copy to
+ * @to:		index to copy to
  * @length:	how many bytes to copy
  * @l:		list head used for management
  */
@@ -682,12 +682,11 @@
 	return buffer->demux_bounce;
 }
 
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
-		       s64 timestamp)
+int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
 {
 	unsigned char *dataout = iio_demux(buffer, data);
 
-	return buffer->access->store_to(buffer, dataout, timestamp);
+	return buffer->access->store_to(buffer, dataout);
 }
 EXPORT_SYMBOL_GPL(iio_push_to_buffer);
 
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 2ec266e..6eb24db 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -29,7 +29,7 @@
 #include <linux/iio/sysfs.h>
 #include <linux/iio/events.h>
 
-/* IDA to assign each registered device a unique id*/
+/* IDA to assign each registered device a unique id */
 static DEFINE_IDA(iio_ida);
 
 static dev_t iio_devt;
@@ -99,6 +99,7 @@
 	[IIO_CHAN_INFO_FREQUENCY] = "frequency",
 	[IIO_CHAN_INFO_PHASE] = "phase",
 	[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
+	[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
 };
 
 const struct iio_chan_spec
@@ -365,6 +366,7 @@
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	unsigned long long tmp;
 	int val, val2;
 	bool scale_db = false;
 	int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
@@ -390,6 +392,11 @@
 			return sprintf(buf, "-%d.%09u\n", val, -val2);
 		else
 			return sprintf(buf, "%d.%09u\n", val, val2);
+	case IIO_VAL_FRACTIONAL:
+		tmp = div_s64((s64)val * 1000000000LL, val2);
+		val2 = do_div(tmp, 1000000000LL);
+		val = tmp;
+		return sprintf(buf, "%d.%09u\n", val, val2);
 	default:
 		return 0;
 	}
@@ -729,7 +736,7 @@
 	attrcount = attrcount_orig;
 	/*
 	 * New channel registration method - relies on the fact a group does
-	 * not need to be initialized if it is name is NULL.
+	 * not need to be initialized if its name is NULL.
 	 */
 	if (indio_dev->channels)
 		for (i = 0; i < indio_dev->num_channels; i++) {
@@ -980,6 +987,6 @@
 subsys_initcall(iio_init);
 module_exit(iio_exit);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("Industrial I/O core");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index b5afc2f..f2b78d4 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -111,6 +111,7 @@
 {
 	struct iio_map_internal *c_i = NULL, *c = NULL;
 	struct iio_channel *channel;
+	int err;
 
 	if (name == NULL && channel_name == NULL)
 		return ERR_PTR(-ENODEV);
@@ -130,18 +131,32 @@
 	if (c == NULL)
 		return ERR_PTR(-ENODEV);
 
-	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
-	if (channel == NULL)
-		return ERR_PTR(-ENOMEM);
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (channel == NULL) {
+		err = -ENOMEM;
+		goto error_no_mem;
+	}
 
 	channel->indio_dev = c->indio_dev;
 
-	if (c->map->adc_channel_label)
+	if (c->map->adc_channel_label) {
 		channel->channel =
 			iio_chan_spec_from_name(channel->indio_dev,
 						c->map->adc_channel_label);
 
+		if (channel->channel == NULL) {
+			err = -EINVAL;
+			goto error_no_chan;
+		}
+	}
+
 	return channel;
+
+error_no_chan:
+	kfree(channel);
+error_no_mem:
+	iio_device_put(c->indio_dev);
+	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iio_channel_get);
 
@@ -229,9 +244,21 @@
 }
 EXPORT_SYMBOL_GPL(iio_channel_release_all);
 
+static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
+	enum iio_chan_info_enum info)
+{
+	int unused;
+
+	if (val2 == NULL)
+		val2 = &unused;
+
+	return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
+						val, val2, info);
+}
+
 int iio_read_channel_raw(struct iio_channel *chan, int *val)
 {
-	int val2, ret;
+	int ret;
 
 	mutex_lock(&chan->indio_dev->info_exist_lock);
 	if (chan->indio_dev->info == NULL) {
@@ -239,8 +266,7 @@
 		goto err_unlock;
 	}
 
-	ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
-					      val, &val2, 0);
+	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
 err_unlock:
 	mutex_unlock(&chan->indio_dev->info_exist_lock);
 
@@ -248,6 +274,100 @@
 }
 EXPORT_SYMBOL_GPL(iio_read_channel_raw);
 
+static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
+	int raw, int *processed, unsigned int scale)
+{
+	int scale_type, scale_val, scale_val2, offset;
+	s64 raw64 = raw;
+	int ret;
+
+	ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE);
+	if (ret == 0)
+		raw64 += offset;
+
+	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
+					IIO_CHAN_INFO_SCALE);
+	if (scale_type < 0)
+		return scale_type;
+
+	switch (scale_type) {
+	case IIO_VAL_INT:
+		*processed = raw64 * scale_val;
+		break;
+	case IIO_VAL_INT_PLUS_MICRO:
+		if (scale_val2 < 0)
+			*processed = -raw64 * scale_val;
+		else
+			*processed = raw64 * scale_val;
+		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
+				      1000000LL);
+		break;
+	case IIO_VAL_INT_PLUS_NANO:
+		if (scale_val2 < 0)
+			*processed = -raw64 * scale_val;
+		else
+			*processed = raw64 * scale_val;
+		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
+				      1000000000LL);
+		break;
+	case IIO_VAL_FRACTIONAL:
+		*processed = div_s64(raw64 * (s64)scale_val * scale,
+				     scale_val2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
+	int *processed, unsigned int scale)
+{
+	int ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
+							scale);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
+
+int iio_read_channel_processed(struct iio_channel *chan, int *val)
+{
+	int ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
+		ret = iio_channel_read(chan, val, NULL,
+				       IIO_CHAN_INFO_PROCESSED);
+	} else {
+		ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
+		if (ret < 0)
+			goto err_unlock;
+		ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
+	}
+
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_processed);
+
 int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
 {
 	int ret;
@@ -258,10 +378,7 @@
 		goto err_unlock;
 	}
 
-	ret = chan->indio_dev->info->read_raw(chan->indio_dev,
-					      chan->channel,
-					      val, val2,
-					      IIO_CHAN_INFO_SCALE);
+	ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE);
 err_unlock:
 	mutex_unlock(&chan->indio_dev->info_exist_lock);
 
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 6bf9d05..5bc5c860 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -6,6 +6,7 @@
 #include <linux/kfifo.h>
 #include <linux/mutex.h>
 #include <linux/iio/kfifo_buf.h>
+#include <linux/sched.h>
 
 struct iio_kfifo {
 	struct iio_buffer buffer;
@@ -22,7 +23,8 @@
 		return -EINVAL;
 
 	__iio_update_buffer(&buf->buffer, bytes_per_datum, length);
-	return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL);
+	return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
+			     bytes_per_datum, GFP_KERNEL);
 }
 
 static int iio_request_update_kfifo(struct iio_buffer *r)
@@ -35,6 +37,7 @@
 	kfifo_free(&buf->kf);
 	ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
 				   buf->buffer.length);
+	r->stufftoread = false;
 error_ret:
 	return ret;
 }
@@ -81,6 +84,9 @@
 
 static int iio_set_length_kfifo(struct iio_buffer *r, int length)
 {
+	/* Avoid an invalid state */
+	if (length < 2)
+		length = 2;
 	if (r->length != length) {
 		r->length = length;
 		iio_mark_update_needed_kfifo(r);
@@ -89,14 +95,16 @@
 }
 
 static int iio_store_to_kfifo(struct iio_buffer *r,
-			      u8 *data,
-			      s64 timestamp)
+			      u8 *data)
 {
 	int ret;
 	struct iio_kfifo *kf = iio_to_kfifo(r);
-	ret = kfifo_in(&kf->kf, data, r->bytes_per_datum);
-	if (ret != r->bytes_per_datum)
+	ret = kfifo_in(&kf->kf, data, 1);
+	if (ret != 1)
 		return -EBUSY;
+	r->stufftoread = true;
+	wake_up_interruptible(&r->pollq);
+
 	return 0;
 }
 
@@ -106,11 +114,18 @@
 	int ret, copied;
 	struct iio_kfifo *kf = iio_to_kfifo(r);
 
-	if (n < r->bytes_per_datum)
+	if (n < r->bytes_per_datum || r->bytes_per_datum == 0)
 		return -EINVAL;
 
-	n = rounddown(n, r->bytes_per_datum);
 	ret = kfifo_to_user(&kf->kf, buf, n, &copied);
+	if (ret < 0)
+		return ret;
+
+	if (kfifo_is_empty(&kf->kf))
+		r->stufftoread = false;
+	/* verify it is still empty to avoid race */
+	if (!kfifo_is_empty(&kf->kf))
+		r->stufftoread = true;
 
 	return copied;
 }
@@ -136,7 +151,7 @@
 	iio_buffer_init(&kf->buffer);
 	kf->buffer.attrs = &iio_kfifo_attribute_group;
 	kf->buffer.access = &kfifo_access_funcs;
-
+	kf->buffer.length = 2;
 	return &kf->buffer;
 }
 EXPORT_SYMBOL(iio_kfifo_allocate);
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 91d15d2..1763c9b 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -42,4 +42,14 @@
 	 To compile this driver as a module, choose M here: the
 	 module will be called vcnl4000.
 
+config HID_SENSOR_ALS
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID ALS"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Ambient light sensor.
+
 endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 13f8a78..21a8f0d 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_ADJD_S311)		+= adjd_s311.o
 obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
 obj-$(CONFIG_VCNL4000)		+= vcnl4000.o
+obj-$(CONFIG_HID_SENSOR_ALS)	+= hid-sensor-als.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 9a99f43..164b62b 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -187,7 +187,7 @@
 	if (indio_dev->scan_timestamp)
 		*(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
 			= time_ns;
-	iio_push_to_buffer(buffer, (u8 *)data->buffer, time_ns);
+	iio_push_to_buffer(buffer, (u8 *)data->buffer);
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
new file mode 100644
index 0000000..96e3691
--- /dev/null
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -0,0 +1,385 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-attributes.h"
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+/*Format: HID-SENSOR-usage_id_in_hex*/
+/*Usage ID from spec for Accelerometer-3D: 0x200041*/
+#define DRIVER_NAME "HID-SENSOR-200041"
+
+#define CHANNEL_SCAN_INDEX_ILLUM 0
+
+struct als_state {
+	struct hid_sensor_hub_callbacks callbacks;
+	struct hid_sensor_iio_common common_attributes;
+	struct hid_sensor_hub_attribute_info als_illum;
+	u32 illum;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec als_channels[] = {
+	{
+		.type = IIO_INTENSITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_LIGHT_BOTH,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
+	}
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+					int channel, int size)
+{
+	channels[channel].scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channels[channel].scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is u32 */
+	channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int als_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct als_state *als_state = iio_priv(indio_dev);
+	int report_id = -1;
+	u32 address;
+	int ret;
+	int ret_type;
+
+	*val = 0;
+	*val2 = 0;
+	switch (mask) {
+	case 0:
+		switch (chan->scan_index) {
+		case  CHANNEL_SCAN_INDEX_ILLUM:
+			report_id = als_state->als_illum.report_id;
+			address =
+			HID_USAGE_SENSOR_LIGHT_ILLUM;
+			break;
+		default:
+			report_id = -1;
+			break;
+		}
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				als_state->common_attributes.hsdev,
+				HID_USAGE_SENSOR_ALS, address,
+				report_id);
+		else {
+			*val = 0;
+			return -EINVAL;
+		}
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = als_state->als_illum.units;
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = hid_sensor_convert_exponent(
+				als_state->als_illum.unit_expo);
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_read_samp_freq_value(
+				&als_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_read_raw_hyst_value(
+				&als_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	default:
+		ret_type = -EINVAL;
+		break;
+	}
+
+	return ret_type;
+}
+
+/* Channel write_raw handler */
+static int als_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct als_state *als_state = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_write_samp_freq_value(
+				&als_state->common_attributes, val, val2);
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_write_raw_hyst_value(
+				&als_state->common_attributes, val, val2);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int als_write_raw_get_fmt(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       long mask)
+{
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static const struct iio_info als_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &als_read_raw,
+	.write_raw = &als_write_raw,
+	.write_raw_get_fmt = &als_write_raw_get_fmt,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int datum_sz;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+	if (!buffer) {
+		dev_err(&indio_dev->dev, "Buffer == NULL\n");
+		return;
+	}
+	datum_sz = buffer->access->get_bytes_per_datum(buffer);
+	if (len > datum_sz) {
+		dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+				datum_sz);
+		return;
+	}
+	iio_push_to_buffer(buffer, (u8 *)data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int als_proc_event(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct als_state *als_state = iio_priv(indio_dev);
+
+	dev_dbg(&indio_dev->dev, "als_proc_event [%d]\n",
+				als_state->common_attributes.data_ready);
+	if (als_state->common_attributes.data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&als_state->illum,
+				sizeof(als_state->illum));
+
+	return 0;
+}
+
+/* Capture samples in local storage */
+static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				size_t raw_len, char *raw_data,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct als_state *als_state = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_LIGHT_ILLUM:
+		als_state->illum = *(u32 *)raw_data;
+		ret = 0;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int als_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				struct iio_chan_spec *channels,
+				unsigned usage_id,
+				struct als_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_LIGHT_ILLUM,
+			&st->als_illum);
+	if (ret < 0)
+		return ret;
+	als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
+					st->als_illum.size);
+
+	dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
+			st->als_illum.report_id);
+
+	return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int __devinit hid_als_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	static const char *name = "als";
+	struct iio_dev *indio_dev;
+	struct als_state *als_state;
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_chan_spec *channels;
+
+	indio_dev = iio_device_alloc(sizeof(struct als_state));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	platform_set_drvdata(pdev, indio_dev);
+
+	als_state = iio_priv(indio_dev);
+	als_state->common_attributes.hsdev = hsdev;
+	als_state->common_attributes.pdev = pdev;
+
+	ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
+					&als_state->common_attributes);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup common attributes\n");
+		goto error_free_dev;
+	}
+
+	channels = kmemdup(als_channels,
+					sizeof(als_channels),
+					GFP_KERNEL);
+	if (!channels) {
+		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		goto error_free_dev;
+	}
+
+	ret = als_parse_report(pdev, hsdev, channels,
+				HID_USAGE_SENSOR_ALS, als_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev_mem;
+	}
+
+	indio_dev->channels = channels;
+	indio_dev->num_channels =
+				ARRAY_SIZE(als_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &als_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+		NULL, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+		goto error_free_dev_mem;
+	}
+	als_state->common_attributes.data_ready = false;
+	ret = hid_sensor_setup_trigger(indio_dev, name,
+				&als_state->common_attributes);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "trigger setup failed\n");
+		goto error_unreg_buffer_funcs;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "device register failed\n");
+		goto error_remove_trigger;
+	}
+
+	als_state->callbacks.send_event = als_proc_event;
+	als_state->callbacks.capture_sample = als_capture_sample;
+	als_state->callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
+					&als_state->callbacks);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "callback reg failed\n");
+		goto error_iio_unreg;
+	}
+
+	return ret;
+
+error_iio_unreg:
+	iio_device_unregister(indio_dev);
+error_remove_trigger:
+	hid_sensor_remove_trigger(indio_dev);
+error_unreg_buffer_funcs:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+	kfree(indio_dev->channels);
+error_free_dev:
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int __devinit hid_als_remove(struct platform_device *pdev)
+{
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
+	iio_device_unregister(indio_dev);
+	hid_sensor_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	kfree(indio_dev->channels);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver hid_als_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_als_probe,
+	.remove		= hid_als_remove,
+};
+module_platform_driver(hid_als_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor ALS");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
new file mode 100644
index 0000000..c1f0cdd
--- /dev/null
+++ b/drivers/iio/magnetometer/Kconfig
@@ -0,0 +1,16 @@
+#
+# Magnetometer sensors
+#
+menu "Magnetometer sensors"
+
+config HID_SENSOR_MAGNETOMETER_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Magenetometer 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Magnetometer 3D.
+
+endmenu
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
new file mode 100644
index 0000000..60dc4f2
--- /dev/null
+++ b/drivers/iio/magnetometer/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O Magnetometer sensor drivers
+#
+
+obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
new file mode 100644
index 0000000..c4f0d27
--- /dev/null
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -0,0 +1,419 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-attributes.h"
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+/*Format: HID-SENSOR-usage_id_in_hex*/
+/*Usage ID from spec for Magnetometer-3D: 0x200083*/
+#define DRIVER_NAME "HID-SENSOR-200083"
+
+enum magn_3d_channel {
+	CHANNEL_SCAN_INDEX_X,
+	CHANNEL_SCAN_INDEX_Y,
+	CHANNEL_SCAN_INDEX_Z,
+	MAGN_3D_CHANNEL_MAX,
+};
+
+struct magn_3d_state {
+	struct hid_sensor_hub_callbacks callbacks;
+	struct hid_sensor_iio_common common_attributes;
+	struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
+	u32 magn_val[MAGN_3D_CHANNEL_MAX];
+};
+
+static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
+	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
+	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
+	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec magn_3d_channels[] = {
+	{
+		.type = IIO_MAGN,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_X,
+	}, {
+		.type = IIO_MAGN,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Y,
+	}, {
+		.type = IIO_MAGN,
+		.modified = 1,
+		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |
+		IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
+		IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Z,
+	}
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+						int channel, int size)
+{
+	channels[channel].scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channels[channel].scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is u32 */
+	channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int magn_3d_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct magn_3d_state *magn_state = iio_priv(indio_dev);
+	int report_id = -1;
+	u32 address;
+	int ret;
+	int ret_type;
+
+	*val = 0;
+	*val2 = 0;
+	switch (mask) {
+	case 0:
+		report_id =
+			magn_state->magn[chan->scan_index].report_id;
+		address = magn_3d_addresses[chan->scan_index];
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				magn_state->common_attributes.hsdev,
+				HID_USAGE_SENSOR_COMPASS_3D, address,
+				report_id);
+		else {
+			*val = 0;
+			return -EINVAL;
+		}
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = magn_state->magn[CHANNEL_SCAN_INDEX_X].units;
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = hid_sensor_convert_exponent(
+			magn_state->magn[CHANNEL_SCAN_INDEX_X].unit_expo);
+		ret_type = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_read_samp_freq_value(
+			&magn_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_read_raw_hyst_value(
+			&magn_state->common_attributes, val, val2);
+		ret_type = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	default:
+		ret_type = -EINVAL;
+		break;
+	}
+
+	return ret_type;
+}
+
+/* Channel write_raw handler */
+static int magn_3d_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct magn_3d_state *magn_state = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hid_sensor_write_samp_freq_value(
+				&magn_state->common_attributes, val, val2);
+		break;
+	case IIO_CHAN_INFO_HYSTERESIS:
+		ret = hid_sensor_write_raw_hyst_value(
+				&magn_state->common_attributes, val, val2);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int magn_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       long mask)
+{
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static const struct iio_info magn_3d_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &magn_3d_read_raw,
+	.write_raw = &magn_3d_write_raw,
+	.write_raw_get_fmt = &magn_3d_write_raw_get_fmt,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int datum_sz;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+	if (!buffer) {
+		dev_err(&indio_dev->dev, "Buffer == NULL\n");
+		return;
+	}
+	datum_sz = buffer->access->get_bytes_per_datum(buffer);
+	if (len > datum_sz) {
+		dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+				datum_sz);
+		return;
+	}
+	iio_push_to_buffer(buffer, (u8 *)data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct magn_3d_state *magn_state = iio_priv(indio_dev);
+
+	dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n",
+				magn_state->common_attributes.data_ready);
+	if (magn_state->common_attributes.data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)magn_state->magn_val,
+				sizeof(magn_state->magn_val));
+
+	return 0;
+}
+
+/* Capture samples in local storage */
+static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				size_t raw_len, char *raw_data,
+				void *priv)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(priv);
+	struct magn_3d_state *magn_state = iio_priv(indio_dev);
+	int offset;
+	int ret = -EINVAL;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
+		offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS;
+		magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] =
+						*(u32 *)raw_data;
+		ret = 0;
+	break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int magn_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				struct iio_chan_spec *channels,
+				unsigned usage_id,
+				struct magn_3d_state *st)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
+		ret = sensor_hub_input_get_attribute_info(hsdev,
+				HID_INPUT_REPORT,
+				usage_id,
+				HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i,
+				&st->magn[CHANNEL_SCAN_INDEX_X + i]);
+		if (ret < 0)
+			break;
+		magn_3d_adjust_channel_bit_mask(channels,
+				CHANNEL_SCAN_INDEX_X + i,
+				st->magn[CHANNEL_SCAN_INDEX_X + i].size);
+	}
+	dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
+			st->magn[0].index,
+			st->magn[0].report_id,
+			st->magn[1].index, st->magn[1].report_id,
+			st->magn[2].index, st->magn[2].report_id);
+
+	return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int __devinit hid_magn_3d_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	static char *name = "magn_3d";
+	struct iio_dev *indio_dev;
+	struct magn_3d_state *magn_state;
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_chan_spec *channels;
+
+	indio_dev = iio_device_alloc(sizeof(struct magn_3d_state));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	platform_set_drvdata(pdev, indio_dev);
+
+	magn_state = iio_priv(indio_dev);
+	magn_state->common_attributes.hsdev = hsdev;
+	magn_state->common_attributes.pdev = pdev;
+
+	ret = hid_sensor_parse_common_attributes(hsdev,
+				HID_USAGE_SENSOR_COMPASS_3D,
+				&magn_state->common_attributes);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup common attributes\n");
+		goto error_free_dev;
+	}
+
+	channels = kmemdup(magn_3d_channels,
+					sizeof(magn_3d_channels),
+					GFP_KERNEL);
+	if (!channels) {
+		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		goto error_free_dev;
+	}
+
+	ret = magn_3d_parse_report(pdev, hsdev, channels,
+				HID_USAGE_SENSOR_COMPASS_3D, magn_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev_mem;
+	}
+
+	indio_dev->channels = channels;
+	indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &magn_3d_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+		NULL, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+		goto error_free_dev_mem;
+	}
+	magn_state->common_attributes.data_ready = false;
+	ret = hid_sensor_setup_trigger(indio_dev, name,
+					&magn_state->common_attributes);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "trigger setup failed\n");
+		goto error_unreg_buffer_funcs;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "device register failed\n");
+		goto error_remove_trigger;
+	}
+
+	magn_state->callbacks.send_event = magn_3d_proc_event;
+	magn_state->callbacks.capture_sample = magn_3d_capture_sample;
+	magn_state->callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
+					&magn_state->callbacks);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "callback reg failed\n");
+		goto error_iio_unreg;
+	}
+
+	return ret;
+
+error_iio_unreg:
+	iio_device_unregister(indio_dev);
+error_remove_trigger:
+	hid_sensor_remove_trigger(indio_dev);
+error_unreg_buffer_funcs:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+	kfree(indio_dev->channels);
+error_free_dev:
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int __devinit hid_magn_3d_remove(struct platform_device *pdev)
+{
+	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
+	iio_device_unregister(indio_dev);
+	hid_sensor_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	kfree(indio_dev->channels);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver hid_magn_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_magn_3d_probe,
+	.remove		= hid_magn_3d_remove,
+};
+module_platform_driver(hid_magn_3d_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Magnetometer 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 51f4206..6cfd4d8 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1361,11 +1361,11 @@
 	struct tid_info *t = dev->rdev.lldi.tids;
 
 	ep = lookup_tid(t, tid);
-	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 	if (!ep) {
 		printk(KERN_WARNING MOD "Abort rpl to freed endpoint\n");
 		return 0;
 	}
+	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 	mutex_lock(&ep->com.mutex);
 	switch (ep->com.state) {
 	case ABORTING:
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 5358900..8615d7c 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -42,6 +42,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/smpboot.h>
 
 #include "ehca_classes.h"
 #include "ehca_irq.h"
@@ -652,7 +653,7 @@
 	ehca_process_eq((struct ehca_shca*)data, 1);
 }
 
-static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
+static int find_next_online_cpu(struct ehca_comp_pool *pool)
 {
 	int cpu;
 	unsigned long flags;
@@ -662,17 +663,20 @@
 		ehca_dmp(cpu_online_mask, cpumask_size(), "");
 
 	spin_lock_irqsave(&pool->last_cpu_lock, flags);
-	cpu = cpumask_next(pool->last_cpu, cpu_online_mask);
-	if (cpu >= nr_cpu_ids)
-		cpu = cpumask_first(cpu_online_mask);
-	pool->last_cpu = cpu;
+	do {
+		cpu = cpumask_next(pool->last_cpu, cpu_online_mask);
+		if (cpu >= nr_cpu_ids)
+			cpu = cpumask_first(cpu_online_mask);
+		pool->last_cpu = cpu;
+	} while (!per_cpu_ptr(pool->cpu_comp_tasks, cpu)->active);
 	spin_unlock_irqrestore(&pool->last_cpu_lock, flags);
 
 	return cpu;
 }
 
 static void __queue_comp_task(struct ehca_cq *__cq,
-			      struct ehca_cpu_comp_task *cct)
+			      struct ehca_cpu_comp_task *cct,
+			      struct task_struct *thread)
 {
 	unsigned long flags;
 
@@ -683,7 +687,7 @@
 		__cq->nr_callbacks++;
 		list_add_tail(&__cq->entry, &cct->cq_list);
 		cct->cq_jobs++;
-		wake_up(&cct->wait_queue);
+		wake_up_process(thread);
 	} else
 		__cq->nr_callbacks++;
 
@@ -695,6 +699,7 @@
 {
 	int cpu_id;
 	struct ehca_cpu_comp_task *cct;
+	struct task_struct *thread;
 	int cq_jobs;
 	unsigned long flags;
 
@@ -702,7 +707,8 @@
 	BUG_ON(!cpu_online(cpu_id));
 
 	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
-	BUG_ON(!cct);
+	thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
+	BUG_ON(!cct || !thread);
 
 	spin_lock_irqsave(&cct->task_lock, flags);
 	cq_jobs = cct->cq_jobs;
@@ -710,28 +716,25 @@
 	if (cq_jobs > 0) {
 		cpu_id = find_next_online_cpu(pool);
 		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
-		BUG_ON(!cct);
+		thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
+		BUG_ON(!cct || !thread);
 	}
-
-	__queue_comp_task(__cq, cct);
+	__queue_comp_task(__cq, cct, thread);
 }
 
 static void run_comp_task(struct ehca_cpu_comp_task *cct)
 {
 	struct ehca_cq *cq;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cct->task_lock, flags);
 
 	while (!list_empty(&cct->cq_list)) {
 		cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
-		spin_unlock_irqrestore(&cct->task_lock, flags);
+		spin_unlock_irq(&cct->task_lock);
 
 		comp_event_callback(cq);
 		if (atomic_dec_and_test(&cq->nr_events))
 			wake_up(&cq->wait_completion);
 
-		spin_lock_irqsave(&cct->task_lock, flags);
+		spin_lock_irq(&cct->task_lock);
 		spin_lock(&cq->task_lock);
 		cq->nr_callbacks--;
 		if (!cq->nr_callbacks) {
@@ -740,159 +743,76 @@
 		}
 		spin_unlock(&cq->task_lock);
 	}
-
-	spin_unlock_irqrestore(&cct->task_lock, flags);
 }
 
-static int comp_task(void *__cct)
-{
-	struct ehca_cpu_comp_task *cct = __cct;
-	int cql_empty;
-	DECLARE_WAITQUEUE(wait, current);
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (!kthread_should_stop()) {
-		add_wait_queue(&cct->wait_queue, &wait);
-
-		spin_lock_irq(&cct->task_lock);
-		cql_empty = list_empty(&cct->cq_list);
-		spin_unlock_irq(&cct->task_lock);
-		if (cql_empty)
-			schedule();
-		else
-			__set_current_state(TASK_RUNNING);
-
-		remove_wait_queue(&cct->wait_queue, &wait);
-
-		spin_lock_irq(&cct->task_lock);
-		cql_empty = list_empty(&cct->cq_list);
-		spin_unlock_irq(&cct->task_lock);
-		if (!cql_empty)
-			run_comp_task(__cct);
-
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-	__set_current_state(TASK_RUNNING);
-
-	return 0;
-}
-
-static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
-					    int cpu)
-{
-	struct ehca_cpu_comp_task *cct;
-
-	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-	spin_lock_init(&cct->task_lock);
-	INIT_LIST_HEAD(&cct->cq_list);
-	init_waitqueue_head(&cct->wait_queue);
-	cct->task = kthread_create_on_node(comp_task, cct, cpu_to_node(cpu),
-					   "ehca_comp/%d", cpu);
-
-	return cct->task;
-}
-
-static void destroy_comp_task(struct ehca_comp_pool *pool,
-			      int cpu)
-{
-	struct ehca_cpu_comp_task *cct;
-	struct task_struct *task;
-	unsigned long flags_cct;
-
-	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-
-	spin_lock_irqsave(&cct->task_lock, flags_cct);
-
-	task = cct->task;
-	cct->task = NULL;
-	cct->cq_jobs = 0;
-
-	spin_unlock_irqrestore(&cct->task_lock, flags_cct);
-
-	if (task)
-		kthread_stop(task);
-}
-
-static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
+static void comp_task_park(unsigned int cpu)
 {
 	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+	struct ehca_cpu_comp_task *target;
+	struct task_struct *thread;
+	struct ehca_cq *cq, *tmp;
 	LIST_HEAD(list);
-	struct ehca_cq *cq;
-	unsigned long flags_cct;
 
-	spin_lock_irqsave(&cct->task_lock, flags_cct);
-
+	spin_lock_irq(&cct->task_lock);
+	cct->cq_jobs = 0;
+	cct->active = 0;
 	list_splice_init(&cct->cq_list, &list);
+	spin_unlock_irq(&cct->task_lock);
 
-	while (!list_empty(&list)) {
-		cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
-
+	cpu = find_next_online_cpu(pool);
+	target = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+	thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu);
+	spin_lock_irq(&target->task_lock);
+	list_for_each_entry_safe(cq, tmp, &list, entry) {
 		list_del(&cq->entry);
-		__queue_comp_task(cq, this_cpu_ptr(pool->cpu_comp_tasks));
+		__queue_comp_task(cq, target, thread);
 	}
-
-	spin_unlock_irqrestore(&cct->task_lock, flags_cct);
-
+	spin_unlock_irq(&target->task_lock);
 }
 
-static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
-					unsigned long action,
-					void *hcpu)
+static void comp_task_stop(unsigned int cpu, bool online)
 {
-	unsigned int cpu = (unsigned long)hcpu;
-	struct ehca_cpu_comp_task *cct;
+	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
 
-	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
-		if (!create_comp_task(pool, cpu)) {
-			ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
-			return notifier_from_errno(-ENOMEM);
-		}
-		break;
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
-		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-		kthread_bind(cct->task, cpumask_any(cpu_online_mask));
-		destroy_comp_task(pool, cpu);
-		break;
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
-		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-		kthread_bind(cct->task, cpu);
-		wake_up_process(cct->task);
-		break;
-	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
-		break;
-	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
-		destroy_comp_task(pool, cpu);
-		take_over_work(pool, cpu);
-		break;
-	}
-
-	return NOTIFY_OK;
+	spin_lock_irq(&cct->task_lock);
+	cct->cq_jobs = 0;
+	cct->active = 0;
+	WARN_ON(!list_empty(&cct->cq_list));
+	spin_unlock_irq(&cct->task_lock);
 }
 
-static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
-	.notifier_call	= comp_pool_callback,
-	.priority	= 0,
+static int comp_task_should_run(unsigned int cpu)
+{
+	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+
+	return cct->cq_jobs;
+}
+
+static void comp_task(unsigned int cpu)
+{
+	struct ehca_cpu_comp_task *cct = this_cpu_ptr(pool->cpu_comp_tasks);
+	int cql_empty;
+
+	spin_lock_irq(&cct->task_lock);
+	cql_empty = list_empty(&cct->cq_list);
+	if (!cql_empty) {
+		__set_current_state(TASK_RUNNING);
+		run_comp_task(cct);
+	}
+	spin_unlock_irq(&cct->task_lock);
+}
+
+static struct smp_hotplug_thread comp_pool_threads = {
+	.thread_should_run	= comp_task_should_run,
+	.thread_fn		= comp_task,
+	.thread_comm		= "ehca_comp/%u",
+	.cleanup		= comp_task_stop,
+	.park			= comp_task_park,
 };
 
 int ehca_create_comp_pool(void)
 {
-	int cpu;
-	struct task_struct *task;
+	int cpu, ret = -ENOMEM;
 
 	if (!ehca_scaling_code)
 		return 0;
@@ -905,38 +825,46 @@
 	pool->last_cpu = cpumask_any(cpu_online_mask);
 
 	pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
-	if (pool->cpu_comp_tasks == NULL) {
-		kfree(pool);
-		return -EINVAL;
+	if (!pool->cpu_comp_tasks)
+		goto out_pool;
+
+	pool->cpu_comp_threads = alloc_percpu(struct task_struct *);
+	if (!pool->cpu_comp_threads)
+		goto out_tasks;
+
+	for_each_present_cpu(cpu) {
+		struct ehca_cpu_comp_task *cct;
+
+		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+		spin_lock_init(&cct->task_lock);
+		INIT_LIST_HEAD(&cct->cq_list);
 	}
 
-	for_each_online_cpu(cpu) {
-		task = create_comp_task(pool, cpu);
-		if (task) {
-			kthread_bind(task, cpu);
-			wake_up_process(task);
-		}
-	}
+	comp_pool_threads.store = pool->cpu_comp_threads;
+	ret = smpboot_register_percpu_thread(&comp_pool_threads);
+	if (ret)
+		goto out_threads;
 
-	register_hotcpu_notifier(&comp_pool_callback_nb);
+	pr_info("eHCA scaling code enabled\n");
+	return ret;
 
-	printk(KERN_INFO "eHCA scaling code enabled\n");
-
-	return 0;
+out_threads:
+	free_percpu(pool->cpu_comp_threads);
+out_tasks:
+	free_percpu(pool->cpu_comp_tasks);
+out_pool:
+	kfree(pool);
+	return ret;
 }
 
 void ehca_destroy_comp_pool(void)
 {
-	int i;
-
 	if (!ehca_scaling_code)
 		return;
 
-	unregister_hotcpu_notifier(&comp_pool_callback_nb);
+	smpboot_unregister_percpu_thread(&comp_pool_threads);
 
-	for_each_online_cpu(i)
-		destroy_comp_task(pool, i);
-
+	free_percpu(pool->cpu_comp_threads);
 	free_percpu(pool->cpu_comp_tasks);
 	kfree(pool);
 }
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
index 3346cb0..5370199 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.h
+++ b/drivers/infiniband/hw/ehca/ehca_irq.h
@@ -58,15 +58,15 @@
 void ehca_process_eq(struct ehca_shca *shca, int is_irq);
 
 struct ehca_cpu_comp_task {
-	wait_queue_head_t wait_queue;
 	struct list_head cq_list;
-	struct task_struct *task;
 	spinlock_t task_lock;
 	int cq_jobs;
+	int active;
 };
 
 struct ehca_comp_pool {
-	struct ehca_cpu_comp_task *cpu_comp_tasks;
+	struct ehca_cpu_comp_task __percpu *cpu_comp_tasks;
+	struct task_struct * __percpu *cpu_comp_threads;
 	int last_cpu;
 	spinlock_t last_cpu_lock;
 };
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c
index 4fa3534..74c6a94 100644
--- a/drivers/infiniband/hw/mthca/mthca_reset.c
+++ b/drivers/infiniband/hw/mthca/mthca_reset.c
@@ -241,16 +241,16 @@
 
 	if (hca_pcie_cap) {
 		devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4];
-		if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL,
-					   devctl)) {
+		if (pcie_capability_write_word(mdev->pdev, PCI_EXP_DEVCTL,
+					       devctl)) {
 			err = -ENODEV;
 			mthca_err(mdev, "Couldn't restore HCA PCI Express "
 				  "Device Control register, aborting.\n");
 			goto out;
 		}
 		linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4];
-		if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL,
-					   linkctl)) {
+		if (pcie_capability_write_word(mdev->pdev, PCI_EXP_LNKCTL,
+					       linkctl)) {
 			err = -ENODEV;
 			mthca_err(mdev, "Couldn't restore HCA PCI Express "
 				  "Link control register, aborting.\n");
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index cb5b7f7..b29a424 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -2219,7 +2219,6 @@
 	u32 wqe_idx;
 
 	if (!qp->wqe_wr_id_tbl[tail].signaled) {
-		expand = true;	/* CQE cannot be consumed yet */
 		*polled = false;    /* WC cannot be consumed yet */
 	} else {
 		ibwc->status = IB_WC_SUCCESS;
@@ -2227,10 +2226,11 @@
 		ibwc->qp = &qp->ibqp;
 		ocrdma_update_wc(qp, ibwc, tail);
 		*polled = true;
-		wqe_idx = le32_to_cpu(cqe->wq.wqeidx) &	OCRDMA_CQE_WQEIDX_MASK;
-		if (tail != wqe_idx)
-			expand = true; /* Coalesced CQE can't be consumed yet */
 	}
+	wqe_idx = le32_to_cpu(cqe->wq.wqeidx) &	OCRDMA_CQE_WQEIDX_MASK;
+	if (tail != wqe_idx)
+		expand = true; /* Coalesced CQE can't be consumed yet */
+
 	ocrdma_hwq_inc_tail(&qp->sq);
 	return expand;
 }
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 7b1b8669..4d11575 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -87,7 +87,7 @@
 };
 
 extern struct qlogic_ib_stats qib_stats;
-extern struct pci_error_handlers qib_pci_err_handler;
+extern const struct pci_error_handlers qib_pci_err_handler;
 extern struct pci_driver qib_driver;
 
 #define QIB_CHIP_SWVERSION QIB_CHIP_VERS_MAJ
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index 19f1e6c..ccb1191 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -471,9 +471,10 @@
 		if (port_num != port) {
 			ibp = to_iport(ibdev, port_num);
 			ret = check_mkey(ibp, smp, 0);
-			if (ret)
+			if (ret) {
 				ret = IB_MAD_RESULT_FAILURE;
 				goto bail;
+			}
 		}
 	}
 
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 062c301eb..c574ec7 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -273,10 +273,9 @@
 		    struct qib_msix_entry *entry)
 {
 	u16 linkstat, speed;
-	int pos = 0, pose, ret = 1;
+	int pos = 0, ret = 1;
 
-	pose = pci_pcie_cap(dd->pcidev);
-	if (!pose) {
+	if (!pci_is_pcie(dd->pcidev)) {
 		qib_dev_err(dd, "Can't find PCI Express capability!\n");
 		/* set up something... */
 		dd->lbus_width = 1;
@@ -298,7 +297,7 @@
 	if (!pos)
 		qib_enable_intx(dd->pcidev);
 
-	pci_read_config_word(dd->pcidev, pose + PCI_EXP_LNKSTA, &linkstat);
+	pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKSTA, &linkstat);
 	/*
 	 * speed is bits 0-3, linkwidth is bits 4-8
 	 * no defines for them in headers
@@ -516,7 +515,6 @@
 {
 	int r;
 	struct pci_dev *parent;
-	int ppos;
 	u16 devid;
 	u32 mask, bits, val;
 
@@ -529,8 +527,7 @@
 		qib_devinfo(dd->pcidev, "Parent not root\n");
 		return 1;
 	}
-	ppos = pci_pcie_cap(parent);
-	if (!ppos)
+	if (!pci_is_pcie(parent))
 		return 1;
 	if (parent->vendor != 0x8086)
 		return 1;
@@ -587,7 +584,6 @@
 {
 	int ret = 1; /* Assume the worst */
 	struct pci_dev *parent;
-	int ppos, epos;
 	u16 pcaps, pctl, ecaps, ectl;
 	int rc_sup, ep_sup;
 	int rc_cur, ep_cur;
@@ -598,19 +594,15 @@
 		qib_devinfo(dd->pcidev, "Parent not root\n");
 		goto bail;
 	}
-	ppos = pci_pcie_cap(parent);
-	if (ppos) {
-		pci_read_config_word(parent, ppos + PCI_EXP_DEVCAP, &pcaps);
-		pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
-	} else
+
+	if (!pci_is_pcie(parent) || !pci_is_pcie(dd->pcidev))
 		goto bail;
+	pcie_capability_read_word(parent, PCI_EXP_DEVCAP, &pcaps);
+	pcie_capability_read_word(parent, PCI_EXP_DEVCTL, &pctl);
 	/* Find out supported and configured values for endpoint (us) */
-	epos = pci_pcie_cap(dd->pcidev);
-	if (epos) {
-		pci_read_config_word(dd->pcidev, epos + PCI_EXP_DEVCAP, &ecaps);
-		pci_read_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, &ectl);
-	} else
-		goto bail;
+	pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCAP, &ecaps);
+	pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &ectl);
+
 	ret = 0;
 	/* Find max payload supported by root, endpoint */
 	rc_sup = fld2val(pcaps, PCI_EXP_DEVCAP_PAYLOAD);
@@ -629,14 +621,14 @@
 		rc_cur = rc_sup;
 		pctl = (pctl & ~PCI_EXP_DEVCTL_PAYLOAD) |
 			val2fld(rc_cur, PCI_EXP_DEVCTL_PAYLOAD);
-		pci_write_config_word(parent, ppos + PCI_EXP_DEVCTL, pctl);
+		pcie_capability_write_word(parent, PCI_EXP_DEVCTL, pctl);
 	}
 	/* If less than (allowed, supported), bump endpoint payload */
 	if (rc_sup > ep_cur) {
 		ep_cur = rc_sup;
 		ectl = (ectl & ~PCI_EXP_DEVCTL_PAYLOAD) |
 			val2fld(ep_cur, PCI_EXP_DEVCTL_PAYLOAD);
-		pci_write_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, ectl);
+		pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, ectl);
 	}
 
 	/*
@@ -654,13 +646,13 @@
 		rc_cur = rc_sup;
 		pctl = (pctl & ~PCI_EXP_DEVCTL_READRQ) |
 			val2fld(rc_cur, PCI_EXP_DEVCTL_READRQ);
-		pci_write_config_word(parent, ppos + PCI_EXP_DEVCTL, pctl);
+		pcie_capability_write_word(parent, PCI_EXP_DEVCTL, pctl);
 	}
 	if (rc_sup > ep_cur) {
 		ep_cur = rc_sup;
 		ectl = (ectl & ~PCI_EXP_DEVCTL_READRQ) |
 			val2fld(ep_cur, PCI_EXP_DEVCTL_READRQ);
-		pci_write_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, ectl);
+		pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, ectl);
 	}
 bail:
 	return ret;
@@ -753,7 +745,7 @@
 	qib_init(dd, 1); /* same as re-init after reset */
 }
 
-struct pci_error_handlers qib_pci_err_handler = {
+const struct pci_error_handlers qib_pci_err_handler = {
 	.error_detected = qib_pci_error_detected,
 	.mmio_enabled = qib_pci_mmio_enabled,
 	.link_reset = qib_pci_link_reset,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index ca43901..0af216d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -262,7 +262,10 @@
 	u16     max_coalesced_frames;
 };
 
+struct ipoib_neigh_table;
+
 struct ipoib_neigh_hash {
+	struct ipoib_neigh_table       *ntbl;
 	struct ipoib_neigh __rcu      **buckets;
 	struct rcu_head			rcu;
 	u32				mask;
@@ -271,9 +274,9 @@
 
 struct ipoib_neigh_table {
 	struct ipoib_neigh_hash __rcu  *htbl;
-	rwlock_t			rwlock;
 	atomic_t			entries;
 	struct completion		flushed;
+	struct completion		deleted;
 };
 
 /*
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 3e2085a..1e19b5a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -546,15 +546,15 @@
 	struct ipoib_neigh *neigh;
 	unsigned long flags;
 
+	spin_lock_irqsave(&priv->lock, flags);
 	neigh = ipoib_neigh_alloc(daddr, dev);
 	if (!neigh) {
+		spin_unlock_irqrestore(&priv->lock, flags);
 		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
 		return;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
-
 	path = __path_find(dev, daddr + 4);
 	if (!path) {
 		path = path_rec_create(dev, daddr + 4);
@@ -863,10 +863,10 @@
 	if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags))
 		return;
 
-	write_lock_bh(&ntbl->rwlock);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	htbl = rcu_dereference_protected(ntbl->htbl,
-					 lockdep_is_held(&ntbl->rwlock));
+					 lockdep_is_held(&priv->lock));
 
 	if (!htbl)
 		goto out_unlock;
@@ -883,16 +883,14 @@
 		struct ipoib_neigh __rcu **np = &htbl->buckets[i];
 
 		while ((neigh = rcu_dereference_protected(*np,
-							  lockdep_is_held(&ntbl->rwlock))) != NULL) {
+							  lockdep_is_held(&priv->lock))) != NULL) {
 			/* was the neigh idle for two GC periods */
 			if (time_after(neigh_obsolete, neigh->alive)) {
 				rcu_assign_pointer(*np,
 						   rcu_dereference_protected(neigh->hnext,
-									     lockdep_is_held(&ntbl->rwlock)));
+									     lockdep_is_held(&priv->lock)));
 				/* remove from path/mc list */
-				spin_lock_irqsave(&priv->lock, flags);
 				list_del(&neigh->list);
-				spin_unlock_irqrestore(&priv->lock, flags);
 				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 			} else {
 				np = &neigh->hnext;
@@ -902,7 +900,7 @@
 	}
 
 out_unlock:
-	write_unlock_bh(&ntbl->rwlock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static void ipoib_reap_neigh(struct work_struct *work)
@@ -947,10 +945,8 @@
 	struct ipoib_neigh *neigh;
 	u32 hash_val;
 
-	write_lock_bh(&ntbl->rwlock);
-
 	htbl = rcu_dereference_protected(ntbl->htbl,
-					 lockdep_is_held(&ntbl->rwlock));
+					 lockdep_is_held(&priv->lock));
 	if (!htbl) {
 		neigh = NULL;
 		goto out_unlock;
@@ -961,10 +957,10 @@
 	 */
 	hash_val = ipoib_addr_hash(htbl, daddr);
 	for (neigh = rcu_dereference_protected(htbl->buckets[hash_val],
-					       lockdep_is_held(&ntbl->rwlock));
+					       lockdep_is_held(&priv->lock));
 	     neigh != NULL;
 	     neigh = rcu_dereference_protected(neigh->hnext,
-					       lockdep_is_held(&ntbl->rwlock))) {
+					       lockdep_is_held(&priv->lock))) {
 		if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) {
 			/* found, take one ref on behalf of the caller */
 			if (!atomic_inc_not_zero(&neigh->refcnt)) {
@@ -987,12 +983,11 @@
 	/* put in hash */
 	rcu_assign_pointer(neigh->hnext,
 			   rcu_dereference_protected(htbl->buckets[hash_val],
-						     lockdep_is_held(&ntbl->rwlock)));
+						     lockdep_is_held(&priv->lock)));
 	rcu_assign_pointer(htbl->buckets[hash_val], neigh);
 	atomic_inc(&ntbl->entries);
 
 out_unlock:
-	write_unlock_bh(&ntbl->rwlock);
 
 	return neigh;
 }
@@ -1040,35 +1035,29 @@
 	struct ipoib_neigh *n;
 	u32 hash_val;
 
-	write_lock_bh(&ntbl->rwlock);
-
 	htbl = rcu_dereference_protected(ntbl->htbl,
-					lockdep_is_held(&ntbl->rwlock));
+					lockdep_is_held(&priv->lock));
 	if (!htbl)
-		goto out_unlock;
+		return;
 
 	hash_val = ipoib_addr_hash(htbl, neigh->daddr);
 	np = &htbl->buckets[hash_val];
 	for (n = rcu_dereference_protected(*np,
-					    lockdep_is_held(&ntbl->rwlock));
+					    lockdep_is_held(&priv->lock));
 	     n != NULL;
 	     n = rcu_dereference_protected(*np,
-					lockdep_is_held(&ntbl->rwlock))) {
+					lockdep_is_held(&priv->lock))) {
 		if (n == neigh) {
 			/* found */
 			rcu_assign_pointer(*np,
 					   rcu_dereference_protected(neigh->hnext,
-								     lockdep_is_held(&ntbl->rwlock)));
+								     lockdep_is_held(&priv->lock)));
 			call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
-			goto out_unlock;
+			return;
 		} else {
 			np = &n->hnext;
 		}
 	}
-
-out_unlock:
-	write_unlock_bh(&ntbl->rwlock);
-
 }
 
 static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)
@@ -1080,7 +1069,6 @@
 
 	clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);
 	ntbl->htbl = NULL;
-	rwlock_init(&ntbl->rwlock);
 	htbl = kzalloc(sizeof(*htbl), GFP_KERNEL);
 	if (!htbl)
 		return -ENOMEM;
@@ -1095,6 +1083,7 @@
 	htbl->mask = (size - 1);
 	htbl->buckets = buckets;
 	ntbl->htbl = htbl;
+	htbl->ntbl = ntbl;
 	atomic_set(&ntbl->entries, 0);
 
 	/* start garbage collection */
@@ -1111,9 +1100,11 @@
 						    struct ipoib_neigh_hash,
 						    rcu);
 	struct ipoib_neigh __rcu **buckets = htbl->buckets;
+	struct ipoib_neigh_table *ntbl = htbl->ntbl;
 
 	kfree(buckets);
 	kfree(htbl);
+	complete(&ntbl->deleted);
 }
 
 void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)
@@ -1125,10 +1116,10 @@
 	int i;
 
 	/* remove all neigh connected to a given path or mcast */
-	write_lock_bh(&ntbl->rwlock);
+	spin_lock_irqsave(&priv->lock, flags);
 
 	htbl = rcu_dereference_protected(ntbl->htbl,
-					 lockdep_is_held(&ntbl->rwlock));
+					 lockdep_is_held(&priv->lock));
 
 	if (!htbl)
 		goto out_unlock;
@@ -1138,16 +1129,14 @@
 		struct ipoib_neigh __rcu **np = &htbl->buckets[i];
 
 		while ((neigh = rcu_dereference_protected(*np,
-							  lockdep_is_held(&ntbl->rwlock))) != NULL) {
+							  lockdep_is_held(&priv->lock))) != NULL) {
 			/* delete neighs belong to this parent */
 			if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) {
 				rcu_assign_pointer(*np,
 						   rcu_dereference_protected(neigh->hnext,
-									     lockdep_is_held(&ntbl->rwlock)));
+									     lockdep_is_held(&priv->lock)));
 				/* remove from parent list */
-				spin_lock_irqsave(&priv->lock, flags);
 				list_del(&neigh->list);
-				spin_unlock_irqrestore(&priv->lock, flags);
 				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 			} else {
 				np = &neigh->hnext;
@@ -1156,7 +1145,7 @@
 		}
 	}
 out_unlock:
-	write_unlock_bh(&ntbl->rwlock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static void ipoib_flush_neighs(struct ipoib_dev_priv *priv)
@@ -1164,37 +1153,44 @@
 	struct ipoib_neigh_table *ntbl = &priv->ntbl;
 	struct ipoib_neigh_hash *htbl;
 	unsigned long flags;
-	int i;
+	int i, wait_flushed = 0;
 
-	write_lock_bh(&ntbl->rwlock);
+	init_completion(&priv->ntbl.flushed);
+
+	spin_lock_irqsave(&priv->lock, flags);
 
 	htbl = rcu_dereference_protected(ntbl->htbl,
-					lockdep_is_held(&ntbl->rwlock));
+					lockdep_is_held(&priv->lock));
 	if (!htbl)
 		goto out_unlock;
 
+	wait_flushed = atomic_read(&priv->ntbl.entries);
+	if (!wait_flushed)
+		goto free_htbl;
+
 	for (i = 0; i < htbl->size; i++) {
 		struct ipoib_neigh *neigh;
 		struct ipoib_neigh __rcu **np = &htbl->buckets[i];
 
 		while ((neigh = rcu_dereference_protected(*np,
-							  lockdep_is_held(&ntbl->rwlock))) != NULL) {
+				       lockdep_is_held(&priv->lock))) != NULL) {
 			rcu_assign_pointer(*np,
 					   rcu_dereference_protected(neigh->hnext,
-								     lockdep_is_held(&ntbl->rwlock)));
+								     lockdep_is_held(&priv->lock)));
 			/* remove from path/mc list */
-			spin_lock_irqsave(&priv->lock, flags);
 			list_del(&neigh->list);
-			spin_unlock_irqrestore(&priv->lock, flags);
 			call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
 		}
 	}
 
+free_htbl:
 	rcu_assign_pointer(ntbl->htbl, NULL);
 	call_rcu(&htbl->rcu, neigh_hash_free_rcu);
 
 out_unlock:
-	write_unlock_bh(&ntbl->rwlock);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	if (wait_flushed)
+		wait_for_completion(&priv->ntbl.flushed);
 }
 
 static void ipoib_neigh_hash_uninit(struct net_device *dev)
@@ -1203,7 +1199,7 @@
 	int stopped;
 
 	ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n");
-	init_completion(&priv->ntbl.flushed);
+	init_completion(&priv->ntbl.deleted);
 	set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);
 
 	/* Stop GC if called at init fail need to cancel work */
@@ -1211,10 +1207,9 @@
 	if (!stopped)
 		cancel_delayed_work(&priv->neigh_reap_task);
 
-	if (atomic_read(&priv->ntbl.entries)) {
-		ipoib_flush_neighs(priv);
-		wait_for_completion(&priv->ntbl.flushed);
-	}
+	ipoib_flush_neighs(priv);
+
+	wait_for_completion(&priv->ntbl.deleted);
 }
 
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 13f4aa7..7536724 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -707,9 +707,7 @@
 		neigh = ipoib_neigh_get(dev, daddr);
 		spin_lock_irqsave(&priv->lock, flags);
 		if (!neigh) {
-			spin_unlock_irqrestore(&priv->lock, flags);
 			neigh = ipoib_neigh_alloc(daddr, dev);
-			spin_lock_irqsave(&priv->lock, flags);
 			if (neigh) {
 				kref_get(&mcast->ah->ref);
 				neigh->ah	= mcast->ah;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 6c58bff..118d0300 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -54,16 +54,9 @@
 static struct evdev *evdev_table[EVDEV_MINORS];
 static DEFINE_MUTEX(evdev_table_mutex);
 
-static void evdev_pass_event(struct evdev_client *client,
-			     struct input_event *event,
-			     ktime_t mono, ktime_t real)
+static void __pass_event(struct evdev_client *client,
+			 const struct input_event *event)
 {
-	event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
-					mono : real);
-
-	/* Interrupts are disabled, just acquire the lock. */
-	spin_lock(&client->buffer_lock);
-
 	client->buffer[client->head++] = *event;
 	client->head &= client->bufsize - 1;
 
@@ -86,8 +79,63 @@
 		client->packet_head = client->head;
 		kill_fasync(&client->fasync, SIGIO, POLL_IN);
 	}
+}
+
+static void evdev_pass_values(struct evdev_client *client,
+			const struct input_value *vals, unsigned int count,
+			ktime_t mono, ktime_t real)
+{
+	struct evdev *evdev = client->evdev;
+	const struct input_value *v;
+	struct input_event event;
+	bool wakeup = false;
+
+	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
+				      mono : real);
+
+	/* Interrupts are disabled, just acquire the lock. */
+	spin_lock(&client->buffer_lock);
+
+	for (v = vals; v != vals + count; v++) {
+		event.type = v->type;
+		event.code = v->code;
+		event.value = v->value;
+		__pass_event(client, &event);
+		if (v->type == EV_SYN && v->code == SYN_REPORT)
+			wakeup = true;
+	}
 
 	spin_unlock(&client->buffer_lock);
+
+	if (wakeup)
+		wake_up_interruptible(&evdev->wait);
+}
+
+/*
+ * Pass incoming events to all connected clients.
+ */
+static void evdev_events(struct input_handle *handle,
+			 const struct input_value *vals, unsigned int count)
+{
+	struct evdev *evdev = handle->private;
+	struct evdev_client *client;
+	ktime_t time_mono, time_real;
+
+	time_mono = ktime_get();
+	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
+
+	rcu_read_lock();
+
+	client = rcu_dereference(evdev->grab);
+
+	if (client)
+		evdev_pass_values(client, vals, count, time_mono, time_real);
+	else
+		list_for_each_entry_rcu(client, &evdev->client_list, node)
+			evdev_pass_values(client, vals, count,
+					  time_mono, time_real);
+
+	rcu_read_unlock();
 }
 
 /*
@@ -96,32 +144,9 @@
 static void evdev_event(struct input_handle *handle,
 			unsigned int type, unsigned int code, int value)
 {
-	struct evdev *evdev = handle->private;
-	struct evdev_client *client;
-	struct input_event event;
-	ktime_t time_mono, time_real;
+	struct input_value vals[] = { { type, code, value } };
 
-	time_mono = ktime_get();
-	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
-
-	event.type = type;
-	event.code = code;
-	event.value = value;
-
-	rcu_read_lock();
-
-	client = rcu_dereference(evdev->grab);
-
-	if (client)
-		evdev_pass_event(client, &event, time_mono, time_real);
-	else
-		list_for_each_entry_rcu(client, &evdev->client_list, node)
-			evdev_pass_event(client, &event, time_mono, time_real);
-
-	rcu_read_unlock();
-
-	if (type == EV_SYN && code == SYN_REPORT)
-		wake_up_interruptible(&evdev->wait);
+	evdev_events(handle, vals, 1);
 }
 
 static int evdev_fasync(int fd, struct file *file, int on)
@@ -653,20 +678,22 @@
 				   unsigned int size,
 				   int __user *ip)
 {
-	const struct input_mt_slot *mt = dev->mt;
+	const struct input_mt *mt = dev->mt;
 	unsigned int code;
 	int max_slots;
 	int i;
 
 	if (get_user(code, &ip[0]))
 		return -EFAULT;
-	if (!input_is_mt_value(code))
+	if (!mt || !input_is_mt_value(code))
 		return -EINVAL;
 
 	max_slots = (size - sizeof(__u32)) / sizeof(__s32);
-	for (i = 0; i < dev->mtsize && i < max_slots; i++)
-		if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
+	for (i = 0; i < mt->num_slots && i < max_slots; i++) {
+		int value = input_mt_get_value(&mt->slots[i], code);
+		if (put_user(value, &ip[1 + i]))
 			return -EFAULT;
+	}
 
 	return 0;
 }
@@ -1048,6 +1075,7 @@
 
 static struct input_handler evdev_handler = {
 	.event		= evdev_event,
+	.events		= evdev_events,
 	.connect	= evdev_connect,
 	.disconnect	= evdev_disconnect,
 	.fops		= &evdev_fops,
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 70a16c7..c0ec7d4 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -14,6 +14,14 @@
 
 #define TRKID_SGN	((TRKID_MAX + 1) >> 1)
 
+static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
+{
+	if (dev->absinfo && test_bit(src, dev->absbit)) {
+		dev->absinfo[dst] = dev->absinfo[src];
+		dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
+	}
+}
+
 /**
  * input_mt_init_slots() - initialize MT input slots
  * @dev: input device supporting MT events and finger tracking
@@ -25,29 +33,63 @@
  * May be called repeatedly. Returns -EINVAL if attempting to
  * reinitialize with a different number of slots.
  */
-int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
+int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
+			unsigned int flags)
 {
+	struct input_mt *mt = dev->mt;
 	int i;
 
 	if (!num_slots)
 		return 0;
-	if (dev->mt)
-		return dev->mtsize != num_slots ? -EINVAL : 0;
+	if (mt)
+		return mt->num_slots != num_slots ? -EINVAL : 0;
 
-	dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
-	if (!dev->mt)
-		return -ENOMEM;
+	mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
+	if (!mt)
+		goto err_mem;
 
-	dev->mtsize = num_slots;
+	mt->num_slots = num_slots;
+	mt->flags = flags;
 	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
 	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
-	input_set_events_per_packet(dev, 6 * num_slots);
+
+	if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
+		__set_bit(EV_KEY, dev->evbit);
+		__set_bit(BTN_TOUCH, dev->keybit);
+
+		copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
+		copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
+		copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
+	}
+	if (flags & INPUT_MT_POINTER) {
+		__set_bit(BTN_TOOL_FINGER, dev->keybit);
+		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+		if (num_slots >= 3)
+			__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+		if (num_slots >= 4)
+			__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
+		if (num_slots >= 5)
+			__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
+		__set_bit(INPUT_PROP_POINTER, dev->propbit);
+	}
+	if (flags & INPUT_MT_DIRECT)
+		__set_bit(INPUT_PROP_DIRECT, dev->propbit);
+	if (flags & INPUT_MT_TRACK) {
+		unsigned int n2 = num_slots * num_slots;
+		mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
+		if (!mt->red)
+			goto err_mem;
+	}
 
 	/* Mark slots as 'unused' */
 	for (i = 0; i < num_slots; i++)
-		input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
+		input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
 
+	dev->mt = mt;
 	return 0;
+err_mem:
+	kfree(mt);
+	return -ENOMEM;
 }
 EXPORT_SYMBOL(input_mt_init_slots);
 
@@ -60,11 +102,11 @@
  */
 void input_mt_destroy_slots(struct input_dev *dev)
 {
-	kfree(dev->mt);
+	if (dev->mt) {
+		kfree(dev->mt->red);
+		kfree(dev->mt);
+	}
 	dev->mt = NULL;
-	dev->mtsize = 0;
-	dev->slot = 0;
-	dev->trkid = 0;
 }
 EXPORT_SYMBOL(input_mt_destroy_slots);
 
@@ -83,18 +125,24 @@
 void input_mt_report_slot_state(struct input_dev *dev,
 				unsigned int tool_type, bool active)
 {
-	struct input_mt_slot *mt;
+	struct input_mt *mt = dev->mt;
+	struct input_mt_slot *slot;
 	int id;
 
-	if (!dev->mt || !active) {
+	if (!mt)
+		return;
+
+	slot = &mt->slots[mt->slot];
+	slot->frame = mt->frame;
+
+	if (!active) {
 		input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
 		return;
 	}
 
-	mt = &dev->mt[dev->slot];
-	id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
-	if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
-		id = input_mt_new_trkid(dev);
+	id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
+	if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
+		id = input_mt_new_trkid(mt);
 
 	input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
 	input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
@@ -135,13 +183,19 @@
  */
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 {
-	struct input_mt_slot *oldest = NULL;
-	int oldid = dev->trkid;
-	int count = 0;
-	int i;
+	struct input_mt *mt = dev->mt;
+	struct input_mt_slot *oldest;
+	int oldid, count, i;
 
-	for (i = 0; i < dev->mtsize; ++i) {
-		struct input_mt_slot *ps = &dev->mt[i];
+	if (!mt)
+		return;
+
+	oldest = 0;
+	oldid = mt->trkid;
+	count = 0;
+
+	for (i = 0; i < mt->num_slots; ++i) {
+		struct input_mt_slot *ps = &mt->slots[i];
 		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
 
 		if (id < 0)
@@ -160,13 +214,208 @@
 	if (oldest) {
 		int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
 		int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
-		int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
 
 		input_event(dev, EV_ABS, ABS_X, x);
 		input_event(dev, EV_ABS, ABS_Y, y);
-		input_event(dev, EV_ABS, ABS_PRESSURE, p);
+
+		if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
+			int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
+			input_event(dev, EV_ABS, ABS_PRESSURE, p);
+		}
 	} else {
-		input_event(dev, EV_ABS, ABS_PRESSURE, 0);
+		if (test_bit(ABS_MT_PRESSURE, dev->absbit))
+			input_event(dev, EV_ABS, ABS_PRESSURE, 0);
 	}
 }
 EXPORT_SYMBOL(input_mt_report_pointer_emulation);
+
+/**
+ * input_mt_sync_frame() - synchronize mt frame
+ * @dev: input device with allocated MT slots
+ *
+ * Close the frame and prepare the internal state for a new one.
+ * Depending on the flags, marks unused slots as inactive and performs
+ * pointer emulation.
+ */
+void input_mt_sync_frame(struct input_dev *dev)
+{
+	struct input_mt *mt = dev->mt;
+	struct input_mt_slot *s;
+
+	if (!mt)
+		return;
+
+	if (mt->flags & INPUT_MT_DROP_UNUSED) {
+		for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+			if (s->frame == mt->frame)
+				continue;
+			input_mt_slot(dev, s - mt->slots);
+			input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+		}
+	}
+
+	input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER));
+
+	mt->frame++;
+}
+EXPORT_SYMBOL(input_mt_sync_frame);
+
+static int adjust_dual(int *begin, int step, int *end, int eq)
+{
+	int f, *p, s, c;
+
+	if (begin == end)
+		return 0;
+
+	f = *begin;
+	p = begin + step;
+	s = p == end ? f + 1 : *p;
+
+	for (; p != end; p += step)
+		if (*p < f)
+			s = f, f = *p;
+		else if (*p < s)
+			s = *p;
+
+	c = (f + s + 1) / 2;
+	if (c == 0 || (c > 0 && !eq))
+		return 0;
+	if (s < 0)
+		c *= 2;
+
+	for (p = begin; p != end; p += step)
+		*p -= c;
+
+	return (c < s && s <= 0) || (f >= 0 && f < c);
+}
+
+static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
+{
+	int i, k, sum;
+
+	for (k = 0; k < nrc; k++) {
+		for (i = 0; i < nr; i++)
+			adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
+		sum = 0;
+		for (i = 0; i < nrc; i += nr)
+			sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
+		if (!sum)
+			break;
+	}
+}
+
+static int input_mt_set_matrix(struct input_mt *mt,
+			       const struct input_mt_pos *pos, int num_pos)
+{
+	const struct input_mt_pos *p;
+	struct input_mt_slot *s;
+	int *w = mt->red;
+	int x, y;
+
+	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+		if (!input_mt_is_active(s))
+			continue;
+		x = input_mt_get_value(s, ABS_MT_POSITION_X);
+		y = input_mt_get_value(s, ABS_MT_POSITION_Y);
+		for (p = pos; p != pos + num_pos; p++) {
+			int dx = x - p->x, dy = y - p->y;
+			*w++ = dx * dx + dy * dy;
+		}
+	}
+
+	return w - mt->red;
+}
+
+static void input_mt_set_slots(struct input_mt *mt,
+			       int *slots, int num_pos)
+{
+	struct input_mt_slot *s;
+	int *w = mt->red, *p;
+
+	for (p = slots; p != slots + num_pos; p++)
+		*p = -1;
+
+	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+		if (!input_mt_is_active(s))
+			continue;
+		for (p = slots; p != slots + num_pos; p++)
+			if (*w++ < 0)
+				*p = s - mt->slots;
+	}
+
+	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+		if (input_mt_is_active(s))
+			continue;
+		for (p = slots; p != slots + num_pos; p++)
+			if (*p < 0) {
+				*p = s - mt->slots;
+				break;
+			}
+	}
+}
+
+/**
+ * input_mt_assign_slots() - perform a best-match assignment
+ * @dev: input device with allocated MT slots
+ * @slots: the slot assignment to be filled
+ * @pos: the position array to match
+ * @num_pos: number of positions
+ *
+ * Performs a best match against the current contacts and returns
+ * the slot assignment list. New contacts are assigned to unused
+ * slots.
+ *
+ * Returns zero on success, or negative error in case of failure.
+ */
+int input_mt_assign_slots(struct input_dev *dev, int *slots,
+			  const struct input_mt_pos *pos, int num_pos)
+{
+	struct input_mt *mt = dev->mt;
+	int nrc;
+
+	if (!mt || !mt->red)
+		return -ENXIO;
+	if (num_pos > mt->num_slots)
+		return -EINVAL;
+	if (num_pos < 1)
+		return 0;
+
+	nrc = input_mt_set_matrix(mt, pos, num_pos);
+	find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
+	input_mt_set_slots(mt, slots, num_pos);
+
+	return 0;
+}
+EXPORT_SYMBOL(input_mt_assign_slots);
+
+/**
+ * input_mt_get_slot_by_key() - return slot matching key
+ * @dev: input device with allocated MT slots
+ * @key: the key of the sought slot
+ *
+ * Returns the slot of the given key, if it exists, otherwise
+ * set the key on the first unused slot and return.
+ *
+ * If no available slot can be found, -1 is returned.
+ */
+int input_mt_get_slot_by_key(struct input_dev *dev, int key)
+{
+	struct input_mt *mt = dev->mt;
+	struct input_mt_slot *s;
+
+	if (!mt)
+		return -1;
+
+	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
+		if (input_mt_is_active(s) && s->key == key)
+			return s - mt->slots;
+
+	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
+		if (!input_mt_is_active(s)) {
+			s->key = key;
+			return s - mt->slots;
+		}
+
+	return -1;
+}
+EXPORT_SYMBOL(input_mt_get_slot_by_key);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 8921c61..5244f3d 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -47,6 +47,8 @@
 
 static struct input_handler *input_table[8];
 
+static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
+
 static inline int is_event_supported(unsigned int code,
 				     unsigned long *bm, unsigned int max)
 {
@@ -69,79 +71,6 @@
 	return value;
 }
 
-/*
- * Pass event first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
- */
-static void input_pass_event(struct input_dev *dev,
-			     unsigned int type, unsigned int code, int value)
-{
-	struct input_handler *handler;
-	struct input_handle *handle;
-
-	rcu_read_lock();
-
-	handle = rcu_dereference(dev->grab);
-	if (handle)
-		handle->handler->event(handle, type, code, value);
-	else {
-		bool filtered = false;
-
-		list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
-			if (!handle->open)
-				continue;
-
-			handler = handle->handler;
-			if (!handler->filter) {
-				if (filtered)
-					break;
-
-				handler->event(handle, type, code, value);
-
-			} else if (handler->filter(handle, type, code, value))
-				filtered = true;
-		}
-	}
-
-	rcu_read_unlock();
-}
-
-/*
- * Generate software autorepeat event. Note that we take
- * dev->event_lock here to avoid racing with input_event
- * which may cause keys get "stuck".
- */
-static void input_repeat_key(unsigned long data)
-{
-	struct input_dev *dev = (void *) data;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-
-	if (test_bit(dev->repeat_key, dev->key) &&
-	    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
-
-		input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
-
-		if (dev->sync) {
-			/*
-			 * Only send SYN_REPORT if we are not in a middle
-			 * of driver parsing a new hardware packet.
-			 * Otherwise assume that the driver will send
-			 * SYN_REPORT once it's done.
-			 */
-			input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-		}
-
-		if (dev->rep[REP_PERIOD])
-			mod_timer(&dev->timer, jiffies +
-					msecs_to_jiffies(dev->rep[REP_PERIOD]));
-	}
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
 static void input_start_autorepeat(struct input_dev *dev, int code)
 {
 	if (test_bit(EV_REP, dev->evbit) &&
@@ -158,14 +87,128 @@
 	del_timer(&dev->timer);
 }
 
+/*
+ * Pass event first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static unsigned int input_to_handler(struct input_handle *handle,
+			struct input_value *vals, unsigned int count)
+{
+	struct input_handler *handler = handle->handler;
+	struct input_value *end = vals;
+	struct input_value *v;
+
+	for (v = vals; v != vals + count; v++) {
+		if (handler->filter &&
+		    handler->filter(handle, v->type, v->code, v->value))
+			continue;
+		if (end != v)
+			*end = *v;
+		end++;
+	}
+
+	count = end - vals;
+	if (!count)
+		return 0;
+
+	if (handler->events)
+		handler->events(handle, vals, count);
+	else if (handler->event)
+		for (v = vals; v != end; v++)
+			handler->event(handle, v->type, v->code, v->value);
+
+	return count;
+}
+
+/*
+ * Pass values first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_values(struct input_dev *dev,
+			      struct input_value *vals, unsigned int count)
+{
+	struct input_handle *handle;
+	struct input_value *v;
+
+	if (!count)
+		return;
+
+	rcu_read_lock();
+
+	handle = rcu_dereference(dev->grab);
+	if (handle) {
+		count = input_to_handler(handle, vals, count);
+	} else {
+		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+			if (handle->open)
+				count = input_to_handler(handle, vals, count);
+	}
+
+	rcu_read_unlock();
+
+	add_input_randomness(vals->type, vals->code, vals->value);
+
+	/* trigger auto repeat for key events */
+	for (v = vals; v != vals + count; v++) {
+		if (v->type == EV_KEY && v->value != 2) {
+			if (v->value)
+				input_start_autorepeat(dev, v->code);
+			else
+				input_stop_autorepeat(dev);
+		}
+	}
+}
+
+static void input_pass_event(struct input_dev *dev,
+			     unsigned int type, unsigned int code, int value)
+{
+	struct input_value vals[] = { { type, code, value } };
+
+	input_pass_values(dev, vals, ARRAY_SIZE(vals));
+}
+
+/*
+ * Generate software autorepeat event. Note that we take
+ * dev->event_lock here to avoid racing with input_event
+ * which may cause keys get "stuck".
+ */
+static void input_repeat_key(unsigned long data)
+{
+	struct input_dev *dev = (void *) data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	if (test_bit(dev->repeat_key, dev->key) &&
+	    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+		struct input_value vals[] =  {
+			{ EV_KEY, dev->repeat_key, 2 },
+			input_value_sync
+		};
+
+		input_pass_values(dev, vals, ARRAY_SIZE(vals));
+
+		if (dev->rep[REP_PERIOD])
+			mod_timer(&dev->timer, jiffies +
+					msecs_to_jiffies(dev->rep[REP_PERIOD]));
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 #define INPUT_IGNORE_EVENT	0
 #define INPUT_PASS_TO_HANDLERS	1
 #define INPUT_PASS_TO_DEVICE	2
+#define INPUT_SLOT		4
+#define INPUT_FLUSH		8
 #define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
 				  unsigned int code, int *pval)
 {
+	struct input_mt *mt = dev->mt;
 	bool is_mt_event;
 	int *pold;
 
@@ -174,8 +217,8 @@
 		 * "Stage" the event; we'll flush it later, when we
 		 * get actual touch data.
 		 */
-		if (*pval >= 0 && *pval < dev->mtsize)
-			dev->slot = *pval;
+		if (mt && *pval >= 0 && *pval < mt->num_slots)
+			mt->slot = *pval;
 
 		return INPUT_IGNORE_EVENT;
 	}
@@ -184,9 +227,8 @@
 
 	if (!is_mt_event) {
 		pold = &dev->absinfo[code].value;
-	} else if (dev->mt) {
-		struct input_mt_slot *mtslot = &dev->mt[dev->slot];
-		pold = &mtslot->abs[code - ABS_MT_FIRST];
+	} else if (mt) {
+		pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
 	} else {
 		/*
 		 * Bypass filtering for multi-touch events when
@@ -205,16 +247,16 @@
 	}
 
 	/* Flush pending "slot" event */
-	if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
-		input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-		input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+	if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
+		input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
+		return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
 	}
 
 	return INPUT_PASS_TO_HANDLERS;
 }
 
-static void input_handle_event(struct input_dev *dev,
-			       unsigned int type, unsigned int code, int value)
+static int input_get_disposition(struct input_dev *dev,
+			  unsigned int type, unsigned int code, int value)
 {
 	int disposition = INPUT_IGNORE_EVENT;
 
@@ -227,37 +269,34 @@
 			break;
 
 		case SYN_REPORT:
-			if (!dev->sync) {
-				dev->sync = true;
-				disposition = INPUT_PASS_TO_HANDLERS;
-			}
+			disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
 			break;
 		case SYN_MT_REPORT:
-			dev->sync = false;
 			disposition = INPUT_PASS_TO_HANDLERS;
 			break;
 		}
 		break;
 
 	case EV_KEY:
-		if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-		    !!test_bit(code, dev->key) != value) {
+		if (is_event_supported(code, dev->keybit, KEY_MAX)) {
 
-			if (value != 2) {
-				__change_bit(code, dev->key);
-				if (value)
-					input_start_autorepeat(dev, code);
-				else
-					input_stop_autorepeat(dev);
+			/* auto-repeat bypasses state updates */
+			if (value == 2) {
+				disposition = INPUT_PASS_TO_HANDLERS;
+				break;
 			}
 
-			disposition = INPUT_PASS_TO_HANDLERS;
+			if (!!test_bit(code, dev->key) != !!value) {
+
+				__change_bit(code, dev->key);
+				disposition = INPUT_PASS_TO_HANDLERS;
+			}
 		}
 		break;
 
 	case EV_SW:
 		if (is_event_supported(code, dev->swbit, SW_MAX) &&
-		    !!test_bit(code, dev->sw) != value) {
+		    !!test_bit(code, dev->sw) != !!value) {
 
 			__change_bit(code, dev->sw);
 			disposition = INPUT_PASS_TO_HANDLERS;
@@ -284,7 +323,7 @@
 
 	case EV_LED:
 		if (is_event_supported(code, dev->ledbit, LED_MAX) &&
-		    !!test_bit(code, dev->led) != value) {
+		    !!test_bit(code, dev->led) != !!value) {
 
 			__change_bit(code, dev->led);
 			disposition = INPUT_PASS_TO_ALL;
@@ -317,14 +356,48 @@
 		break;
 	}
 
-	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-		dev->sync = false;
+	return disposition;
+}
+
+static void input_handle_event(struct input_dev *dev,
+			       unsigned int type, unsigned int code, int value)
+{
+	int disposition;
+
+	disposition = input_get_disposition(dev, type, code, value);
 
 	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
 		dev->event(dev, type, code, value);
 
-	if (disposition & INPUT_PASS_TO_HANDLERS)
-		input_pass_event(dev, type, code, value);
+	if (!dev->vals)
+		return;
+
+	if (disposition & INPUT_PASS_TO_HANDLERS) {
+		struct input_value *v;
+
+		if (disposition & INPUT_SLOT) {
+			v = &dev->vals[dev->num_vals++];
+			v->type = EV_ABS;
+			v->code = ABS_MT_SLOT;
+			v->value = dev->mt->slot;
+		}
+
+		v = &dev->vals[dev->num_vals++];
+		v->type = type;
+		v->code = code;
+		v->value = value;
+	}
+
+	if (disposition & INPUT_FLUSH) {
+		if (dev->num_vals >= 2)
+			input_pass_values(dev, dev->vals, dev->num_vals);
+		dev->num_vals = 0;
+	} else if (dev->num_vals >= dev->max_vals - 2) {
+		dev->vals[dev->num_vals++] = input_value_sync;
+		input_pass_values(dev, dev->vals, dev->num_vals);
+		dev->num_vals = 0;
+	}
+
 }
 
 /**
@@ -352,7 +425,6 @@
 	if (is_event_supported(type, dev->evbit, EV_MAX)) {
 
 		spin_lock_irqsave(&dev->event_lock, flags);
-		add_input_randomness(type, code, value);
 		input_handle_event(dev, type, code, value);
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 	}
@@ -831,10 +903,12 @@
 	if (test_bit(EV_KEY, dev->evbit) &&
 	    !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
 	    __test_and_clear_bit(old_keycode, dev->key)) {
+		struct input_value vals[] =  {
+			{ EV_KEY, old_keycode, 0 },
+			input_value_sync
+		};
 
-		input_pass_event(dev, EV_KEY, old_keycode, 0);
-		if (dev->sync)
-			input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+		input_pass_values(dev, vals, ARRAY_SIZE(vals));
 	}
 
  out:
@@ -1416,6 +1490,7 @@
 	input_ff_destroy(dev);
 	input_mt_destroy_slots(dev);
 	kfree(dev->absinfo);
+	kfree(dev->vals);
 	kfree(dev);
 
 	module_put(THIS_MODULE);
@@ -1751,8 +1826,8 @@
 	int i;
 	unsigned int events;
 
-	if (dev->mtsize) {
-		mt_slots = dev->mtsize;
+	if (dev->mt) {
+		mt_slots = dev->mt->num_slots;
 	} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
 		mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
 			   dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
@@ -1778,6 +1853,9 @@
 		if (test_bit(i, dev->relbit))
 			events++;
 
+	/* Make room for KEY and MSC events */
+	events += 7;
+
 	return events;
 }
 
@@ -1816,6 +1894,7 @@
 {
 	static atomic_t input_no = ATOMIC_INIT(0);
 	struct input_handler *handler;
+	unsigned int packet_size;
 	const char *path;
 	int error;
 
@@ -1828,9 +1907,14 @@
 	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
 	input_cleanse_bitmasks(dev);
 
-	if (!dev->hint_events_per_packet)
-		dev->hint_events_per_packet =
-				input_estimate_events_per_packet(dev);
+	packet_size = input_estimate_events_per_packet(dev);
+	if (dev->hint_events_per_packet < packet_size)
+		dev->hint_events_per_packet = packet_size;
+
+	dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
+	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+	if (!dev->vals)
+		return -ENOMEM;
 
 	/*
 	 * If delay and period are pre-set by the driver, then autorepeating
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index ce68e36..cdc2526 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -516,9 +516,9 @@
 	input_set_drvdata(input_dev, keypad);
 
 	/* Ensure that the keypad will stay dormant until opened */
-	clk_enable(keypad->clk);
+	clk_prepare_enable(keypad->clk);
 	imx_keypad_inhibit(keypad);
-	clk_disable(keypad->clk);
+	clk_disable_unprepare(keypad->clk);
 
 	error = request_irq(irq, imx_keypad_irq_handler, 0,
 			    pdev->name, keypad);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 2bda5f0b..6d6b1427 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -37,7 +37,7 @@
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/platform_data/gpio-omap.h>
-#include <plat/keypad.h>
+#include <linux/platform_data/keypad-omap.h>
 
 #undef NEW_BOARD_LEARNING_MODE
 
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 7360568..6b17975 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -405,7 +405,7 @@
 			goto exit;
 		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
 			int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
-			input_mt_init_slots(dev, nslot);
+			input_mt_init_slots(dev, nslot, 0);
 		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
 			input_set_events_per_packet(dev, 60);
 		}
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4a1347e..cf5af1f 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1620,7 +1620,7 @@
 	case ALPS_PROTO_V3:
 	case ALPS_PROTO_V4:
 		set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
-		input_mt_init_slots(dev1, 2);
+		input_mt_init_slots(dev1, 2, 0);
 		input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
 		input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
 
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index d528c23..3a78f23 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -40,6 +40,7 @@
 #include <linux/usb/input.h>
 #include <linux/hid.h>
 #include <linux/mutex.h>
+#include <linux/input/mt.h>
 
 #define USB_VENDOR_ID_APPLE		0x05ac
 
@@ -183,26 +184,26 @@
 	__le16 abs_y;		/* absolute y coodinate */
 	__le16 rel_x;		/* relative x coodinate */
 	__le16 rel_y;		/* relative y coodinate */
-	__le16 size_major;	/* finger size, major axis? */
-	__le16 size_minor;	/* finger size, minor axis? */
+	__le16 tool_major;	/* tool area, major axis */
+	__le16 tool_minor;	/* tool area, minor axis */
 	__le16 orientation;	/* 16384 when point, else 15 bit angle */
-	__le16 force_major;	/* trackpad force, major axis? */
-	__le16 force_minor;	/* trackpad force, minor axis? */
+	__le16 touch_major;	/* touch area, major axis */
+	__le16 touch_minor;	/* touch area, minor axis */
 	__le16 unused[3];	/* zeros */
 	__le16 multi;		/* one finger: varies, more fingers: constant */
 } __attribute__((packed,aligned(2)));
 
 /* trackpad finger data size, empirically at least ten fingers */
+#define MAX_FINGERS		16
 #define SIZEOF_FINGER		sizeof(struct tp_finger)
-#define SIZEOF_ALL_FINGERS	(16 * SIZEOF_FINGER)
+#define SIZEOF_ALL_FINGERS	(MAX_FINGERS * SIZEOF_FINGER)
 #define MAX_FINGER_ORIENTATION	16384
 
 /* device-specific parameters */
 struct bcm5974_param {
-	int dim;		/* logical dimension */
-	int fuzz;		/* logical noise value */
-	int devmin;		/* device minimum reading */
-	int devmax;		/* device maximum reading */
+	int snratio;		/* signal-to-noise ratio */
+	int min;		/* device minimum reading */
+	int max;		/* device maximum reading */
 };
 
 /* device-specific configuration */
@@ -219,6 +220,7 @@
 	struct bcm5974_param w;	/* finger width limits */
 	struct bcm5974_param x;	/* horizontal limits */
 	struct bcm5974_param y;	/* vertical limits */
+	struct bcm5974_param o;	/* orientation limits */
 };
 
 /* logical device structure */
@@ -234,23 +236,16 @@
 	struct bt_data *bt_data;	/* button transferred data */
 	struct urb *tp_urb;		/* trackpad usb request block */
 	u8 *tp_data;			/* trackpad transferred data */
-	int fingers;			/* number of fingers on trackpad */
+	const struct tp_finger *index[MAX_FINGERS];	/* finger index data */
+	struct input_mt_pos pos[MAX_FINGERS];		/* position array */
+	int slots[MAX_FINGERS];				/* slot assignments */
 };
 
-/* logical dimensions */
-#define DIM_PRESSURE	256		/* maximum finger pressure */
-#define DIM_WIDTH	16		/* maximum finger width */
-#define DIM_X		1280		/* maximum trackpad x value */
-#define DIM_Y		800		/* maximum trackpad y value */
-
 /* logical signal quality */
 #define SN_PRESSURE	45		/* pressure signal-to-noise ratio */
-#define SN_WIDTH	100		/* width signal-to-noise ratio */
+#define SN_WIDTH	25		/* width signal-to-noise ratio */
 #define SN_COORD	250		/* coordinate signal-to-noise ratio */
-
-/* pressure thresholds */
-#define PRESSURE_LOW	(2 * DIM_PRESSURE / SN_PRESSURE)
-#define PRESSURE_HIGH	(3 * PRESSURE_LOW)
+#define SN_ORIENT	10		/* orientation signal-to-noise ratio */
 
 /* device constants */
 static const struct bcm5974_config bcm5974_config_table[] = {
@@ -261,10 +256,11 @@
 		0,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4824, 5342 },
-		{ DIM_Y, DIM_Y / SN_COORD, -172, 5820 }
+		{ SN_PRESSURE, 0, 256 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4824, 5342 },
+		{ SN_COORD, -172, 5820 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
@@ -273,10 +269,11 @@
 		0,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4824, 4824 },
-		{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 }
+		{ SN_PRESSURE, 0, 256 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4824, 4824 },
+		{ SN_COORD, -172, 4290 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI,
@@ -285,10 +282,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4460, 5166 },
-		{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4460, 5166 },
+		{ SN_COORD, -75, 6700 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
@@ -297,10 +295,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-		{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4620, 5140 },
+		{ SN_COORD, -150, 6600 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
@@ -309,10 +308,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4616, 5112 },
-		{ DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4616, 5112 },
+		{ SN_COORD, -142, 5234 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
@@ -321,10 +321,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4415, 5050 },
-		{ DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4415, 5050 },
+		{ SN_COORD, -55, 6680 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
@@ -333,10 +334,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-		{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4620, 5140 },
+		{ SN_COORD, -150, 6600 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
@@ -345,10 +347,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4750, 5280 },
-		{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4750, 5280 },
+		{ SN_COORD, -150, 6730 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
@@ -357,10 +360,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-		{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4620, 5140 },
+		{ SN_COORD, -150, 6600 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{
 		USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
@@ -369,10 +373,11 @@
 		HAS_INTEGRATED_BUTTON,
 		0x84, sizeof(struct bt_data),
 		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-		{ DIM_X, DIM_X / SN_COORD, -4750, 5280 },
-		{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+		{ SN_PRESSURE, 0, 300 },
+		{ SN_WIDTH, 0, 2048 },
+		{ SN_COORD, -4750, 5280 },
+		{ SN_COORD, -150, 6730 },
+		{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
 	},
 	{}
 };
@@ -396,18 +401,11 @@
 	return (signed short)le16_to_cpu(x);
 }
 
-/* scale device data to logical dimensions (asserts devmin < devmax) */
-static inline int int2scale(const struct bcm5974_param *p, int x)
+static void set_abs(struct input_dev *input, unsigned int code,
+		    const struct bcm5974_param *p)
 {
-	return x * p->dim / (p->devmax - p->devmin);
-}
-
-/* all logical value ranges are [0,dim). */
-static inline int int2bound(const struct bcm5974_param *p, int x)
-{
-	int s = int2scale(p, x);
-
-	return clamp_val(s, 0, p->dim - 1);
+	int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0;
+	input_set_abs_params(input, code, p->min, p->max, fuzz, 0);
 }
 
 /* setup which logical events to report */
@@ -416,48 +414,30 @@
 {
 	__set_bit(EV_ABS, input_dev->evbit);
 
-	input_set_abs_params(input_dev, ABS_PRESSURE,
-				0, cfg->p.dim, cfg->p.fuzz, 0);
-	input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
-				0, cfg->w.dim, cfg->w.fuzz, 0);
-	input_set_abs_params(input_dev, ABS_X,
-				0, cfg->x.dim, cfg->x.fuzz, 0);
-	input_set_abs_params(input_dev, ABS_Y,
-				0, cfg->y.dim, cfg->y.fuzz, 0);
+	/* for synaptics only */
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0);
+	input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0);
 
 	/* finger touch area */
-	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
-			     cfg->w.devmin, cfg->w.devmax, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
-			     cfg->w.devmin, cfg->w.devmax, 0, 0);
+	set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
+	set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
 	/* finger approach area */
-	input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
-			     cfg->w.devmin, cfg->w.devmax, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
-			     cfg->w.devmin, cfg->w.devmax, 0, 0);
+	set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
+	set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
 	/* finger orientation */
-	input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
-			     -MAX_FINGER_ORIENTATION,
-			     MAX_FINGER_ORIENTATION, 0, 0);
+	set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
 	/* finger position */
-	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-			     cfg->x.devmin, cfg->x.devmax, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-			     cfg->y.devmin, cfg->y.devmax, 0, 0);
+	set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x);
+	set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y);
 
 	__set_bit(EV_KEY, input_dev->evbit);
-	__set_bit(BTN_TOUCH, input_dev->keybit);
-	__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-	__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-	__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 	__set_bit(BTN_LEFT, input_dev->keybit);
 
-	__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 	if (cfg->caps & HAS_INTEGRATED_BUTTON)
 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
-	input_set_events_per_packet(input_dev, 60);
+	input_mt_init_slots(input_dev, MAX_FINGERS,
+		INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
 }
 
 /* report button data as logical button state */
@@ -477,24 +457,44 @@
 	return 0;
 }
 
-static void report_finger_data(struct input_dev *input,
-			       const struct bcm5974_config *cfg,
+static void report_finger_data(struct input_dev *input, int slot,
+			       const struct input_mt_pos *pos,
 			       const struct tp_finger *f)
 {
+	input_mt_slot(input, slot);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
 	input_report_abs(input, ABS_MT_TOUCH_MAJOR,
-			 raw2int(f->force_major) << 1);
+			 raw2int(f->touch_major) << 1);
 	input_report_abs(input, ABS_MT_TOUCH_MINOR,
-			 raw2int(f->force_minor) << 1);
+			 raw2int(f->touch_minor) << 1);
 	input_report_abs(input, ABS_MT_WIDTH_MAJOR,
-			 raw2int(f->size_major) << 1);
+			 raw2int(f->tool_major) << 1);
 	input_report_abs(input, ABS_MT_WIDTH_MINOR,
-			 raw2int(f->size_minor) << 1);
+			 raw2int(f->tool_minor) << 1);
 	input_report_abs(input, ABS_MT_ORIENTATION,
 			 MAX_FINGER_ORIENTATION - raw2int(f->orientation));
-	input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x));
-	input_report_abs(input, ABS_MT_POSITION_Y,
-			 cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y));
-	input_mt_sync(input);
+	input_report_abs(input, ABS_MT_POSITION_X, pos->x);
+	input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
+}
+
+static void report_synaptics_data(struct input_dev *input,
+				  const struct bcm5974_config *cfg,
+				  const struct tp_finger *f, int raw_n)
+{
+	int abs_p = 0, abs_w = 0;
+
+	if (raw_n) {
+		int p = raw2int(f->touch_major);
+		int w = raw2int(f->tool_major);
+		if (p > 0 && raw2int(f->origin)) {
+			abs_p = clamp_val(256 * p / cfg->p.max, 0, 255);
+			abs_w = clamp_val(16 * w / cfg->w.max, 0, 15);
+		}
+	}
+
+	input_report_abs(input, ABS_PRESSURE, abs_p);
+	input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
 }
 
 /* report trackpad data as logical trackpad state */
@@ -503,9 +503,7 @@
 	const struct bcm5974_config *c = &dev->cfg;
 	const struct tp_finger *f;
 	struct input_dev *input = dev->input;
-	int raw_p, raw_w, raw_x, raw_y, raw_n, i;
-	int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
-	int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
+	int raw_n, i, n = 0;
 
 	if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
 		return -EIO;
@@ -514,76 +512,29 @@
 	f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
 	raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
 
-	/* always track the first finger; when detached, start over */
-	if (raw_n) {
-
-		/* report raw trackpad data */
-		for (i = 0; i < raw_n; i++)
-			report_finger_data(input, c, &f[i]);
-
-		raw_p = raw2int(f->force_major);
-		raw_w = raw2int(f->size_major);
-		raw_x = raw2int(f->abs_x);
-		raw_y = raw2int(f->abs_y);
-
-		dprintk(9,
-			"bcm5974: "
-			"raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
-			raw_p, raw_w, raw_x, raw_y, raw_n);
-
-		ptest = int2bound(&c->p, raw_p);
-		origin = raw2int(f->origin);
-
-		/* while tracking finger still valid, count all fingers */
-		if (ptest > PRESSURE_LOW && origin) {
-			abs_p = ptest;
-			abs_w = int2bound(&c->w, raw_w);
-			abs_x = int2bound(&c->x, raw_x - c->x.devmin);
-			abs_y = int2bound(&c->y, c->y.devmax - raw_y);
-			while (raw_n--) {
-				ptest = int2bound(&c->p,
-						  raw2int(f->force_major));
-				if (ptest > PRESSURE_LOW)
-					nmax++;
-				if (ptest > PRESSURE_HIGH)
-					nmin++;
-				f++;
-			}
-		}
+	for (i = 0; i < raw_n; i++) {
+		if (raw2int(f[i].touch_major) == 0)
+			continue;
+		dev->pos[n].x = raw2int(f[i].abs_x);
+		dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
+		dev->index[n++] = &f[i];
 	}
 
-	/* set the integrated button if applicable */
-	if (c->tp_type == TYPE2)
-		ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+	input_mt_assign_slots(input, dev->slots, dev->pos, n);
 
-	if (dev->fingers < nmin)
-		dev->fingers = nmin;
-	if (dev->fingers > nmax)
-		dev->fingers = nmax;
+	for (i = 0; i < n; i++)
+		report_finger_data(input, dev->slots[i],
+				   &dev->pos[i], dev->index[i]);
 
-	input_report_key(input, BTN_TOUCH, dev->fingers > 0);
-	input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
-	input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
-	input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3);
-	input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3);
+	input_mt_sync_frame(input);
 
-	input_report_abs(input, ABS_PRESSURE, abs_p);
-	input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
-
-	if (abs_p) {
-		input_report_abs(input, ABS_X, abs_x);
-		input_report_abs(input, ABS_Y, abs_y);
-
-		dprintk(8,
-			"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
-			"nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w,
-			abs_x, abs_y, nmin, nmax, dev->fingers, ibt);
-
-	}
+	report_synaptics_data(input, c, f, raw_n);
 
 	/* type 2 reports button events via ibt only */
-	if (c->tp_type == TYPE2)
+	if (c->tp_type == TYPE2) {
+		int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
 		input_report_key(input, BTN_LEFT, ibt);
+	}
 
 	input_sync(input);
 
@@ -742,9 +693,11 @@
 		goto err_out;
 	}
 
-	error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
-	if (error)
-		goto err_reset_mode;
+	if (dev->bt_urb) {
+		error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+		if (error)
+			goto err_reset_mode;
+	}
 
 	error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
 	if (error)
@@ -868,19 +821,23 @@
 	mutex_init(&dev->pm_mutex);
 
 	/* setup urbs */
-	dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!dev->bt_urb)
-		goto err_free_devs;
+	if (cfg->tp_type == TYPE1) {
+		dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!dev->bt_urb)
+			goto err_free_devs;
+	}
 
 	dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->tp_urb)
 		goto err_free_bt_urb;
 
-	dev->bt_data = usb_alloc_coherent(dev->udev,
+	if (dev->bt_urb) {
+		dev->bt_data = usb_alloc_coherent(dev->udev,
 					  dev->cfg.bt_datalen, GFP_KERNEL,
 					  &dev->bt_urb->transfer_dma);
-	if (!dev->bt_data)
-		goto err_free_urb;
+		if (!dev->bt_data)
+			goto err_free_urb;
+	}
 
 	dev->tp_data = usb_alloc_coherent(dev->udev,
 					  dev->cfg.tp_datalen, GFP_KERNEL,
@@ -888,10 +845,11 @@
 	if (!dev->tp_data)
 		goto err_free_bt_buffer;
 
-	usb_fill_int_urb(dev->bt_urb, udev,
-			 usb_rcvintpipe(udev, cfg->bt_ep),
-			 dev->bt_data, dev->cfg.bt_datalen,
-			 bcm5974_irq_button, dev, 1);
+	if (dev->bt_urb)
+		usb_fill_int_urb(dev->bt_urb, udev,
+				 usb_rcvintpipe(udev, cfg->bt_ep),
+				 dev->bt_data, dev->cfg.bt_datalen,
+				 bcm5974_irq_button, dev, 1);
 
 	usb_fill_int_urb(dev->tp_urb, udev,
 			 usb_rcvintpipe(udev, cfg->tp_ep),
@@ -929,8 +887,9 @@
 	usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
 		dev->tp_data, dev->tp_urb->transfer_dma);
 err_free_bt_buffer:
-	usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
-		dev->bt_data, dev->bt_urb->transfer_dma);
+	if (dev->bt_urb)
+		usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
+				  dev->bt_data, dev->bt_urb->transfer_dma);
 err_free_urb:
 	usb_free_urb(dev->tp_urb);
 err_free_bt_urb:
@@ -951,8 +910,9 @@
 	input_unregister_device(dev->input);
 	usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
 			  dev->tp_data, dev->tp_urb->transfer_dma);
-	usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
-			  dev->bt_data, dev->bt_urb->transfer_dma);
+	if (dev->bt_urb)
+		usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
+				  dev->bt_data, dev->bt_urb->transfer_dma);
 	usb_free_urb(dev->tp_urb);
 	usb_free_urb(dev->bt_urb);
 	kfree(dev);
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 4790110..1e8e42f 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1004,7 +1004,7 @@
 			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
 					     ETP_WMAX_V2, 0, 0);
 		}
-		input_mt_init_slots(dev, 2);
+		input_mt_init_slots(dev, 2, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
 		break;
@@ -1035,7 +1035,7 @@
 		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
 				     ETP_WMAX_V2, 0, 0);
 		/* Multitouch capable pad, up to 5 fingers. */
-		input_mt_init_slots(dev, ETP_MAX_FINGERS);
+		input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
 		input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 272dedd..21c60fe 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -42,7 +42,7 @@
 
 	x = (short) iomd_readl(IOMD_MOUSEX);
 	y = (short) iomd_readl(IOMD_MOUSEY);
-	b = (short) (__raw_readl(0xe0310000) ^ 0x70);
+	b = (short) (__raw_readl(IOMEM(0xe0310000)) ^ 0x70);
 
 	dx = x - rpcmouse_lastx;
 	dy = y - rpcmouse_lasty;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 3f5649f..e582922 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -721,6 +721,17 @@
 
 	switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
 	case FSP_PKT_TYPE_ABS:
+
+		if ((packet[0] == 0x48 || packet[0] == 0x49) &&
+		    packet[1] == 0 && packet[2] == 0) {
+			/*
+			 * Ignore coordinate noise when finger leaving the
+			 * surface, otherwise cursor may jump to upper-left
+			 * corner.
+			 */
+			packet[3] &= 0xf0;
+		}
+
 		abs_x = GET_ABS_X(packet);
 		abs_y = GET_ABS_Y(packet);
 
@@ -960,7 +971,7 @@
 
 		input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
 		input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
-		input_mt_init_slots(dev, 2);
+		input_mt_init_slots(dev, 2, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
 	}
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 14eaece..37033ad 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1232,7 +1232,7 @@
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
 	if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
-		input_mt_init_slots(dev, 2);
+		input_mt_init_slots(dev, 2, 0);
 		set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
 					ABS_MT_POSITION_Y);
 		/* Image sensors can report per-contact pressure */
@@ -1244,7 +1244,7 @@
 	} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
 		/* Non-image sensors with AGM use semi-mt */
 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
-		input_mt_init_slots(dev, 2);
+		input_mt_init_slots(dev, 2, 0);
 		set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
 					ABS_MT_POSITION_Y);
 	}
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 2ffd110..2e77246 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -72,7 +72,7 @@
 	unsigned int divisor;
 	int ret;
 
-	ret = clk_enable(kmi->clk);
+	ret = clk_prepare_enable(kmi->clk);
 	if (ret)
 		goto out;
 
@@ -92,7 +92,7 @@
 	return 0;
 
  clk_disable:
-	clk_disable(kmi->clk);
+	clk_disable_unprepare(kmi->clk);
  out:
 	return ret;
 }
@@ -104,7 +104,7 @@
 	writeb(0, KMICR);
 
 	free_irq(kmi->irq, kmi);
-	clk_disable(kmi->clk);
+	clk_disable_unprepare(kmi->clk);
 }
 
 static int __devinit amba_kmi_probe(struct amba_device *dev,
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index f5fbdf9..45887e3 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 
 #include <asm/mach-types.h>
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/ams-delta-fiq.h>
 
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 6918773..d6cc77a 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -335,6 +335,12 @@
 	},
 	{
 		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"),
+		},
+	},
+	{
+		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
 		},
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 532d067..2a81ce3 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1530,7 +1530,7 @@
 			__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 			__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 
-			input_mt_init_slots(input_dev, features->touch_max);
+			input_mt_init_slots(input_dev, features->touch_max, 0);
 
 			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			                     0, 255, 0, 0);
@@ -1575,7 +1575,7 @@
 
 	case TABLETPC2FG:
 		if (features->device_type == BTN_TOOL_FINGER) {
-			input_mt_init_slots(input_dev, features->touch_max);
+			input_mt_init_slots(input_dev, features->touch_max, 0);
 			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
 					0, MT_TOOL_MAX, 0, 0);
 			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1631,7 +1631,7 @@
 
 			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-			input_mt_init_slots(input_dev, features->touch_max);
+			input_mt_init_slots(input_dev, features->touch_max, 0);
 
 			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
 				__set_bit(BTN_TOOL_TRIPLETAP,
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 4623cc6..e92615d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1152,7 +1152,7 @@
 
 	/* For multi touch */
 	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
-	error = input_mt_init_slots(input_dev, num_mt_slots);
+	error = input_mt_init_slots(input_dev, num_mt_slots, 0);
 	if (error)
 		goto err_free_object;
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index f030d9e..8e60437 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -571,7 +571,7 @@
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			     0, CY_MAXZ, 0, 0);
 
-	input_mt_init_slots(input_dev, CY_MAX_ID);
+	input_mt_init_slots(input_dev, CY_MAX_ID, 0);
 
 	error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
 				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index b06a5e3..099d144a 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -566,9 +566,12 @@
 	}
 
 	read = min_t(size_t, count, tsdata->raw_bufsize - *off);
-	error = copy_to_user(buf, tsdata->raw_buffer + *off, read);
-	if (!error)
-		*off += read;
+	if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	*off += read;
 out:
 	mutex_unlock(&tsdata->mutex);
 	return error ?: read;
@@ -779,7 +782,7 @@
 			     0, tsdata->num_x * 64 - 1, 0, 0);
 	input_set_abs_params(input, ABS_MT_POSITION_Y,
 			     0, tsdata->num_y * 64 - 1, 0, 0);
-	error = input_mt_init_slots(input, MAX_SUPPORT_POINTS);
+	error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
 	if (error) {
 		dev_err(&client->dev, "Unable to init MT slots.\n");
 		goto err_free_mem;
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 70524dd..c1e3460 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -204,7 +204,7 @@
 			     ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
 	input_set_abs_params(input_dev,
 			     ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
-	input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
+	input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
 
 	input_set_drvdata(input_dev, ts);
 
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index c004417..4ac6976 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -252,7 +252,7 @@
 	input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
 
 	/* Multi touch */
-	input_mt_init_slots(input, MAX_TOUCHES);
+	input_mt_init_slots(input, MAX_TOUCHES, 0);
 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
 
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 49c44bb..560cf09 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -404,7 +404,7 @@
 	input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0);
 
 	/* For multi touch */
-	input_mt_init_slots(input_dev, MMS114_MAX_TOUCH);
+	input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0);
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			     0, MMS114_MAX_AREA, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 4ccde45..b49f0b8 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -264,7 +264,7 @@
 	input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
 
 	if (pm->maxcontacts > 1) {
-		input_mt_init_slots(pm->dev, pm->maxcontacts);
+		input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
 		input_set_abs_params(pm->dev,
 				     ABS_MT_POSITION_X, 0, max_x, 0, 0);
 		input_set_abs_params(pm->dev,
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index e32709e..721fdb3 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -304,6 +304,45 @@
 #define EGALAX_PKT_TYPE_REPT		0x80
 #define EGALAX_PKT_TYPE_DIAG		0x0A
 
+static int egalax_init(struct usbtouch_usb *usbtouch)
+{
+	int ret, i;
+	unsigned char *buf;
+	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+
+	/*
+	 * An eGalax diagnostic packet kicks the device into using the right
+	 * protocol.  We send a "check active" packet.  The response will be
+	 * read later and ignored.
+	 */
+
+	buf = kmalloc(3, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = EGALAX_PKT_TYPE_DIAG;
+	buf[1] = 1;	/* length */
+	buf[2] = 'A';	/* command - check active */
+
+	for (i = 0; i < 3; i++) {
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				      0,
+				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				      0, 0, buf, 3,
+				      USB_CTRL_SET_TIMEOUT);
+		if (ret >= 0) {
+			ret = 0;
+			break;
+		}
+		if (ret != -EPIPE)
+			break;
+	}
+
+	kfree(buf);
+
+	return ret;
+}
+
 static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
 	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
@@ -1056,6 +1095,7 @@
 		.process_pkt	= usbtouch_process_multi,
 		.get_pkt_len	= egalax_get_pkt_len,
 		.read_data	= egalax_read_data,
+		.init		= egalax_init,
 	},
 #endif
 
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 8f9ad2f..9a83be6 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -471,7 +471,7 @@
 		case 5:
 			w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
 
-			input_mt_init_slots(dev, 2);
+			input_mt_init_slots(dev, 2, 0);
 			input_set_abs_params(dev, ABS_MT_POSITION_X,
 						0, touch.x, 0, 0);
 			input_set_abs_params(dev, ABS_MT_POSITION_Y,
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index b64502d..e89daf1 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -266,7 +266,7 @@
 
 static int iommu_init_device(struct device *dev)
 {
-	struct pci_dev *dma_pdev, *pdev = to_pci_dev(dev);
+	struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev);
 	struct iommu_dev_data *dev_data;
 	struct iommu_group *group;
 	u16 alias;
@@ -293,7 +293,9 @@
 		dev_data->alias_data = alias_data;
 
 		dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
-	} else
+	}
+
+	if (dma_pdev == NULL)
 		dma_pdev = pci_dev_get(pdev);
 
 	/* Account for quirked devices */
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2297ec1..db820d7 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2351,7 +2351,7 @@
 			return 0;
 		if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
 			return 0;
-	} else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
+	} else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
 		return 0;
 
 	/* 
@@ -3546,10 +3546,10 @@
 		struct pci_dev *bridge = bus->self;
 
 		if (!bridge || !pci_is_pcie(bridge) ||
-		    bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
+		    pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
 			return 0;
 
-		if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
+		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
 			for (i = 0; i < atsru->devices_cnt; i++)
 				if (atsru->devices[i] == bridge)
 					return 1;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/drivers/irqchip/Kconfig
@@ -0,0 +1 @@
+# empty
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
new file mode 100644
index 0000000..054321d
--- /dev/null
+++ b/drivers/irqchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
new file mode 100644
index 0000000..dc670cc
--- /dev/null
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2010 Broadcom
+ * Copyright 2012 Simon Arlott, Chris Boot, Stephen Warren
+ *
+ * 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.
+ *
+ * Quirk 1: Shortcut interrupts don't set the bank 1/2 register pending bits
+ *
+ * If an interrupt fires on bank 1 that isn't in the shortcuts list, bit 8
+ * on bank 0 is set to signify that an interrupt in bank 1 has fired, and
+ * to look in the bank 1 status register for more information.
+ *
+ * If an interrupt fires on bank 1 that _is_ in the shortcuts list, its
+ * shortcut bit in bank 0 is set as well as its interrupt bit in the bank 1
+ * status register, but bank 0 bit 8 is _not_ set.
+ *
+ * Quirk 2: You can't mask the register 1/2 pending interrupts
+ *
+ * In a proper cascaded interrupt controller, the interrupt lines with
+ * cascaded interrupt controllers on them are just normal interrupt lines.
+ * You can mask the interrupts and get on with things. With this controller
+ * you can't do that.
+ *
+ * Quirk 3: The shortcut interrupts can't be (un)masked in bank 0
+ *
+ * Those interrupts that have shortcuts can only be masked/unmasked in
+ * their respective banks' enable/disable registers. Doing so in the bank 0
+ * enable/disable registers has no effect.
+ *
+ * The FIQ control register:
+ *  Bits 0-6: IRQ (index in order of interrupts from banks 1, 2, then 0)
+ *  Bit    7: Enable FIQ generation
+ *  Bits  8+: Unused
+ *
+ * An interrupt must be disabled before configuring it for FIQ generation
+ * otherwise both handlers will fire at the same time!
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/bcm2835.h>
+
+#include <asm/exception.h>
+
+/* Put the bank and irq (32 bits) into the hwirq */
+#define MAKE_HWIRQ(b, n)	((b << 5) | (n))
+#define HWIRQ_BANK(i)		(i >> 5)
+#define HWIRQ_BIT(i)		BIT(i & 0x1f)
+
+#define NR_IRQS_BANK0		8
+#define BANK0_HWIRQ_MASK	0xff
+/* Shortcuts can't be disabled so any unknown new ones need to be masked */
+#define SHORTCUT1_MASK		0x00007c00
+#define SHORTCUT2_MASK		0x001f8000
+#define SHORTCUT_SHIFT		10
+#define BANK1_HWIRQ		BIT(8)
+#define BANK2_HWIRQ		BIT(9)
+#define BANK0_VALID_MASK	(BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
+					| SHORTCUT1_MASK | SHORTCUT2_MASK)
+
+#define REG_FIQ_CONTROL		0x0c
+
+#define NR_BANKS		3
+#define IRQS_PER_BANK		32
+
+static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
+static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 };
+static int bank_irqs[] __initconst = { 8, 32, 32 };
+
+static const int shortcuts[] = {
+	7, 9, 10, 18, 19,		/* Bank 1 */
+	21, 22, 23, 24, 25, 30		/* Bank 2 */
+};
+
+struct armctrl_ic {
+	void __iomem *base;
+	void __iomem *pending[NR_BANKS];
+	void __iomem *enable[NR_BANKS];
+	void __iomem *disable[NR_BANKS];
+	struct irq_domain *domain;
+};
+
+static struct armctrl_ic intc __read_mostly;
+
+static void armctrl_mask_irq(struct irq_data *d)
+{
+	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
+}
+
+static void armctrl_unmask_irq(struct irq_data *d)
+{
+	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
+}
+
+static struct irq_chip armctrl_chip = {
+	.name = "ARMCTRL-level",
+	.irq_mask = armctrl_mask_irq,
+	.irq_unmask = armctrl_unmask_irq
+};
+
+static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
+	const u32 *intspec, unsigned int intsize,
+	unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (WARN_ON(intsize != 2))
+		return -EINVAL;
+
+	if (WARN_ON(intspec[0] >= NR_BANKS))
+		return -EINVAL;
+
+	if (WARN_ON(intspec[1] >= IRQS_PER_BANK))
+		return -EINVAL;
+
+	if (WARN_ON(intspec[0] == 0 && intspec[1] >= NR_IRQS_BANK0))
+		return -EINVAL;
+
+	*out_hwirq = MAKE_HWIRQ(intspec[0], intspec[1]);
+	*out_type = IRQ_TYPE_NONE;
+	return 0;
+}
+
+static struct irq_domain_ops armctrl_ops = {
+	.xlate = armctrl_xlate
+};
+
+static int __init armctrl_of_init(struct device_node *node,
+	struct device_node *parent)
+{
+	void __iomem *base;
+	int irq, b, i;
+
+	base = of_iomap(node, 0);
+	if (!base)
+		panic("%s: unable to map IC registers\n",
+			node->full_name);
+
+	intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
+			&armctrl_ops, NULL);
+	if (!intc.domain)
+		panic("%s: unable to create IRQ domain\n", node->full_name);
+
+	for (b = 0; b < NR_BANKS; b++) {
+		intc.pending[b] = base + reg_pending[b];
+		intc.enable[b] = base + reg_enable[b];
+		intc.disable[b] = base + reg_disable[b];
+
+		for (i = 0; i < bank_irqs[b]; i++) {
+			irq = irq_create_mapping(intc.domain, MAKE_HWIRQ(b, i));
+			BUG_ON(irq <= 0);
+			irq_set_chip_and_handler(irq, &armctrl_chip,
+				handle_level_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+	}
+	return 0;
+}
+
+static struct of_device_id irq_of_match[] __initconst = {
+	{ .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }
+};
+
+void __init bcm2835_init_irq(void)
+{
+	of_irq_init(irq_of_match);
+}
+
+/*
+ * Handle each interrupt across the entire interrupt controller.  This reads the
+ * status register before handling each interrupt, which is necessary given that
+ * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
+ */
+
+static void armctrl_handle_bank(int bank, struct pt_regs *regs)
+{
+	u32 stat, irq;
+
+	while ((stat = readl_relaxed(intc.pending[bank]))) {
+		irq = MAKE_HWIRQ(bank, ffs(stat) - 1);
+		handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
+	}
+}
+
+static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
+	u32 stat)
+{
+	u32 irq = MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]);
+	handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
+}
+
+asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+	struct pt_regs *regs)
+{
+	u32 stat, irq;
+
+	while ((stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK)) {
+		if (stat & BANK0_HWIRQ_MASK) {
+			irq = MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1);
+			handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
+		} else if (stat & SHORTCUT1_MASK) {
+			armctrl_handle_shortcut(1, regs, stat & SHORTCUT1_MASK);
+		} else if (stat & SHORTCUT2_MASK) {
+			armctrl_handle_shortcut(2, regs, stat & SHORTCUT2_MASK);
+		} else if (stat & BANK1_HWIRQ) {
+			armctrl_handle_bank(1, regs);
+		} else if (stat & BANK2_HWIRQ) {
+			armctrl_handle_bank(2, regs);
+		} else {
+			BUG();
+		}
+	}
+}
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 39809035..4af12e1 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -203,8 +203,8 @@
 	 * we set it now, so we can trap and pass that trap to the Guest if it
 	 * uses the FPU.
 	 */
-	if (cpu->ts)
-		unlazy_fpu(current);
+	if (cpu->ts && user_has_fpu())
+		stts();
 
 	/*
 	 * SYSENTER is an optimized way of doing system calls.  We can't allow
@@ -234,6 +234,10 @@
 	 if (boot_cpu_has(X86_FEATURE_SEP))
 		wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
 
+	/* Clear the host TS bit if it was set above. */
+	if (cpu->ts && user_has_fpu())
+		clts();
+
 	/*
 	 * If the Guest page faulted, then the cr2 register will tell us the
 	 * bad virtual address.  We have to grab this now, because once we
@@ -249,7 +253,7 @@
 	 * a different CPU. So all the critical stuff should be done
 	 * before this.
 	 */
-	else if (cpu->regs->trapnum == 7)
+	else if (cpu->regs->trapnum == 7 && !user_has_fpu())
 		math_state_restore();
 }
 
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 831d7517..3f8d032 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -63,7 +63,7 @@
 	int				value_count;
 	int				timer;
 	struct macio_dev		*mdev;
-	struct mb_ops*			ops;
+	const struct mb_ops*		ops;
 	int				index;
 	int				cached_gpio;
 	int				sleeping;
@@ -669,7 +669,7 @@
 
 /* Definitions of "ops" structures.
  */
-static struct mb_ops ohare_mb_ops = {
+static const struct mb_ops ohare_mb_ops = {
 	.name		= "Ohare",
 	.content	= ohare_mb_content,
 	.power		= ohare_mb_power,
@@ -678,7 +678,7 @@
 	.un_reset_ide	= ohare_mb_un_reset_ide,
 };
 
-static struct mb_ops heathrow_mb_ops = {
+static const struct mb_ops heathrow_mb_ops = {
 	.name		= "Heathrow",
 	.content	= heathrow_mb_content,
 	.power		= heathrow_mb_power,
@@ -687,7 +687,7 @@
 	.un_reset_ide	= heathrow_mb_un_reset_ide,
 };
 
-static struct mb_ops keylargo_mb_ops = {
+static const struct mb_ops keylargo_mb_ops = {
 	.name		= "KeyLargo",
 	.init		= keylargo_mb_init,
 	.content	= keylargo_mb_content,
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index d8abb90..034233e 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1555,6 +1555,7 @@
 			   unsigned long arg)
 {
 	struct multipath *m = ti->private;
+	struct pgpath *pgpath;
 	struct block_device *bdev;
 	fmode_t mode;
 	unsigned long flags;
@@ -1570,12 +1571,14 @@
 	if (!m->current_pgpath)
 		__choose_pgpath(m, 0);
 
-	if (m->current_pgpath) {
-		bdev = m->current_pgpath->path.dev->bdev;
-		mode = m->current_pgpath->path.dev->mode;
+	pgpath = m->current_pgpath;
+
+	if (pgpath) {
+		bdev = pgpath->path.dev->bdev;
+		mode = pgpath->path.dev->mode;
 	}
 
-	if (m->queue_io)
+	if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
 		r = -EAGAIN;
 	else if (!bdev)
 		r = -EIO;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index f900690..100368e 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1212,6 +1212,41 @@
 	return &t->targets[(KEYS_PER_NODE * n) + k];
 }
 
+static int count_device(struct dm_target *ti, struct dm_dev *dev,
+			sector_t start, sector_t len, void *data)
+{
+	unsigned *num_devices = data;
+
+	(*num_devices)++;
+
+	return 0;
+}
+
+/*
+ * Check whether a table has no data devices attached using each
+ * target's iterate_devices method.
+ * Returns false if the result is unknown because a target doesn't
+ * support iterate_devices.
+ */
+bool dm_table_has_no_data_devices(struct dm_table *table)
+{
+	struct dm_target *uninitialized_var(ti);
+	unsigned i = 0, num_devices = 0;
+
+	while (i < dm_table_get_num_targets(table)) {
+		ti = dm_table_get_target(table, i++);
+
+		if (!ti->type->iterate_devices)
+			return false;
+
+		ti->type->iterate_devices(ti, count_device, &num_devices);
+		if (num_devices)
+			return false;
+	}
+
+	return true;
+}
+
 /*
  * Establish the new table's queue_limits and validate them.
  */
@@ -1354,17 +1389,25 @@
 	return q && blk_queue_nonrot(q);
 }
 
-static bool dm_table_is_nonrot(struct dm_table *t)
+static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
+			     sector_t start, sector_t len, void *data)
+{
+	struct request_queue *q = bdev_get_queue(dev->bdev);
+
+	return q && !blk_queue_add_random(q);
+}
+
+static bool dm_table_all_devices_attribute(struct dm_table *t,
+					   iterate_devices_callout_fn func)
 {
 	struct dm_target *ti;
 	unsigned i = 0;
 
-	/* Ensure that all underlying device are non-rotational. */
 	while (i < dm_table_get_num_targets(t)) {
 		ti = dm_table_get_target(t, i++);
 
 		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, device_is_nonrot, NULL))
+		    !ti->type->iterate_devices(ti, func, NULL))
 			return 0;
 	}
 
@@ -1396,7 +1439,8 @@
 	if (!dm_table_discard_zeroes_data(t))
 		q->limits.discard_zeroes_data = 0;
 
-	if (dm_table_is_nonrot(t))
+	/* Ensure that all underlying devices are non-rotational. */
+	if (dm_table_all_devices_attribute(t, device_is_nonrot))
 		queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
 	else
 		queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
@@ -1404,6 +1448,15 @@
 	dm_table_set_integrity(t);
 
 	/*
+	 * Determine whether or not this queue's I/O timings contribute
+	 * to the entropy pool, Only request-based targets use this.
+	 * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not
+	 * have it set.
+	 */
+	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
+		queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
+
+	/*
 	 * QUEUE_FLAG_STACKABLE must be set after all queue settings are
 	 * visible to other CPUs because, once the flag is set, incoming bios
 	 * are processed by request-based dm, which refers to the queue
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index af1fc3b..c29410a 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -509,9 +509,9 @@
 struct pool_features {
 	enum pool_mode mode;
 
-	unsigned zero_new_blocks:1;
-	unsigned discard_enabled:1;
-	unsigned discard_passdown:1;
+	bool zero_new_blocks:1;
+	bool discard_enabled:1;
+	bool discard_passdown:1;
 };
 
 struct thin_c;
@@ -580,7 +580,8 @@
 	struct dm_target_callbacks callbacks;
 
 	dm_block_t low_water_blocks;
-	struct pool_features pf;
+	struct pool_features requested_pf; /* Features requested during table load */
+	struct pool_features adjusted_pf;  /* Features used after adjusting for constituent devices */
 };
 
 /*
@@ -1839,6 +1840,47 @@
 /*----------------------------------------------------------------
  * Binding of control targets to a pool object
  *--------------------------------------------------------------*/
+static bool data_dev_supports_discard(struct pool_c *pt)
+{
+	struct request_queue *q = bdev_get_queue(pt->data_dev->bdev);
+
+	return q && blk_queue_discard(q);
+}
+
+/*
+ * If discard_passdown was enabled verify that the data device
+ * supports discards.  Disable discard_passdown if not.
+ */
+static void disable_passdown_if_not_supported(struct pool_c *pt)
+{
+	struct pool *pool = pt->pool;
+	struct block_device *data_bdev = pt->data_dev->bdev;
+	struct queue_limits *data_limits = &bdev_get_queue(data_bdev)->limits;
+	sector_t block_size = pool->sectors_per_block << SECTOR_SHIFT;
+	const char *reason = NULL;
+	char buf[BDEVNAME_SIZE];
+
+	if (!pt->adjusted_pf.discard_passdown)
+		return;
+
+	if (!data_dev_supports_discard(pt))
+		reason = "discard unsupported";
+
+	else if (data_limits->max_discard_sectors < pool->sectors_per_block)
+		reason = "max discard sectors smaller than a block";
+
+	else if (data_limits->discard_granularity > block_size)
+		reason = "discard granularity larger than a block";
+
+	else if (block_size & (data_limits->discard_granularity - 1))
+		reason = "discard granularity not a factor of block size";
+
+	if (reason) {
+		DMWARN("Data device (%s) %s: Disabling discard passdown.", bdevname(data_bdev, buf), reason);
+		pt->adjusted_pf.discard_passdown = false;
+	}
+}
+
 static int bind_control_target(struct pool *pool, struct dm_target *ti)
 {
 	struct pool_c *pt = ti->private;
@@ -1847,31 +1889,16 @@
 	 * We want to make sure that degraded pools are never upgraded.
 	 */
 	enum pool_mode old_mode = pool->pf.mode;
-	enum pool_mode new_mode = pt->pf.mode;
+	enum pool_mode new_mode = pt->adjusted_pf.mode;
 
 	if (old_mode > new_mode)
 		new_mode = old_mode;
 
 	pool->ti = ti;
 	pool->low_water_blocks = pt->low_water_blocks;
-	pool->pf = pt->pf;
-	set_pool_mode(pool, new_mode);
+	pool->pf = pt->adjusted_pf;
 
-	/*
-	 * If discard_passdown was enabled verify that the data device
-	 * supports discards.  Disable discard_passdown if not; otherwise
-	 * -EOPNOTSUPP will be returned.
-	 */
-	/* FIXME: pull this out into a sep fn. */
-	if (pt->pf.discard_passdown) {
-		struct request_queue *q = bdev_get_queue(pt->data_dev->bdev);
-		if (!q || !blk_queue_discard(q)) {
-			char buf[BDEVNAME_SIZE];
-			DMWARN("Discard unsupported by data device (%s): Disabling discard passdown.",
-			       bdevname(pt->data_dev->bdev, buf));
-			pool->pf.discard_passdown = 0;
-		}
-	}
+	set_pool_mode(pool, new_mode);
 
 	return 0;
 }
@@ -1889,9 +1916,9 @@
 static void pool_features_init(struct pool_features *pf)
 {
 	pf->mode = PM_WRITE;
-	pf->zero_new_blocks = 1;
-	pf->discard_enabled = 1;
-	pf->discard_passdown = 1;
+	pf->zero_new_blocks = true;
+	pf->discard_enabled = true;
+	pf->discard_passdown = true;
 }
 
 static void __pool_destroy(struct pool *pool)
@@ -2119,13 +2146,13 @@
 		argc--;
 
 		if (!strcasecmp(arg_name, "skip_block_zeroing"))
-			pf->zero_new_blocks = 0;
+			pf->zero_new_blocks = false;
 
 		else if (!strcasecmp(arg_name, "ignore_discard"))
-			pf->discard_enabled = 0;
+			pf->discard_enabled = false;
 
 		else if (!strcasecmp(arg_name, "no_discard_passdown"))
-			pf->discard_passdown = 0;
+			pf->discard_passdown = false;
 
 		else if (!strcasecmp(arg_name, "read_only"))
 			pf->mode = PM_READ_ONLY;
@@ -2259,8 +2286,9 @@
 	pt->metadata_dev = metadata_dev;
 	pt->data_dev = data_dev;
 	pt->low_water_blocks = low_water_blocks;
-	pt->pf = pf;
+	pt->adjusted_pf = pt->requested_pf = pf;
 	ti->num_flush_requests = 1;
+
 	/*
 	 * Only need to enable discards if the pool should pass
 	 * them down to the data device.  The thin device's discard
@@ -2268,12 +2296,14 @@
 	 */
 	if (pf.discard_enabled && pf.discard_passdown) {
 		ti->num_discard_requests = 1;
+
 		/*
 		 * Setting 'discards_supported' circumvents the normal
 		 * stacking of discard limits (this keeps the pool and
 		 * thin devices' discard limits consistent).
 		 */
 		ti->discards_supported = true;
+		ti->discard_zeroes_data_unsupported = true;
 	}
 	ti->private = pt;
 
@@ -2703,7 +2733,7 @@
 		       format_dev_t(buf2, pt->data_dev->bdev->bd_dev),
 		       (unsigned long)pool->sectors_per_block,
 		       (unsigned long long)pt->low_water_blocks);
-		emit_flags(&pt->pf, result, sz, maxlen);
+		emit_flags(&pt->requested_pf, result, sz, maxlen);
 		break;
 	}
 
@@ -2732,20 +2762,21 @@
 	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
 
-static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
+static void set_discard_limits(struct pool_c *pt, struct queue_limits *limits)
 {
-	/*
-	 * FIXME: these limits may be incompatible with the pool's data device
-	 */
+	struct pool *pool = pt->pool;
+	struct queue_limits *data_limits;
+
 	limits->max_discard_sectors = pool->sectors_per_block;
 
 	/*
-	 * This is just a hint, and not enforced.  We have to cope with
-	 * bios that cover a block partially.  A discard that spans a block
-	 * boundary is not sent to this target.
+	 * discard_granularity is just a hint, and not enforced.
 	 */
-	limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
-	limits->discard_zeroes_data = pool->pf.zero_new_blocks;
+	if (pt->adjusted_pf.discard_passdown) {
+		data_limits = &bdev_get_queue(pt->data_dev->bdev)->limits;
+		limits->discard_granularity = data_limits->discard_granularity;
+	} else
+		limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
 }
 
 static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
@@ -2755,15 +2786,25 @@
 
 	blk_limits_io_min(limits, 0);
 	blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
-	if (pool->pf.discard_enabled)
-		set_discard_limits(pool, limits);
+
+	/*
+	 * pt->adjusted_pf is a staging area for the actual features to use.
+	 * They get transferred to the live pool in bind_control_target()
+	 * called from pool_preresume().
+	 */
+	if (!pt->adjusted_pf.discard_enabled)
+		return;
+
+	disable_passdown_if_not_supported(pt);
+
+	set_discard_limits(pt, limits);
 }
 
 static struct target_type pool_target = {
 	.name = "thin-pool",
 	.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
 		    DM_TARGET_IMMUTABLE,
-	.version = {1, 3, 0},
+	.version = {1, 4, 0},
 	.module = THIS_MODULE,
 	.ctr = pool_ctr,
 	.dtr = pool_dtr,
@@ -3042,19 +3083,19 @@
 	return 0;
 }
 
+/*
+ * A thin device always inherits its queue limits from its pool.
+ */
 static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
 	struct thin_c *tc = ti->private;
-	struct pool *pool = tc->pool;
 
-	blk_limits_io_min(limits, 0);
-	blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
-	set_discard_limits(pool, limits);
+	*limits = bdev_get_queue(tc->pool_dev->bdev)->limits;
 }
 
 static struct target_type thin_target = {
 	.name = "thin",
-	.version = {1, 3, 0},
+	.version = {1, 4, 0},
 	.module	= THIS_MODULE,
 	.ctr = thin_ctr,
 	.dtr = thin_dtr,
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
index 254d192..892ae276 100644
--- a/drivers/md/dm-verity.c
+++ b/drivers/md/dm-verity.c
@@ -718,8 +718,8 @@
 	v->hash_dev_block_bits = ffs(num) - 1;
 
 	if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
-	    num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) !=
-	    (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) {
+	    (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+	    >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
 		ti->error = "Invalid data blocks";
 		r = -EINVAL;
 		goto bad;
@@ -733,8 +733,8 @@
 	}
 
 	if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
-	    num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) !=
-	    (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) {
+	    (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
+	    >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
 		ti->error = "Invalid hash start";
 		r = -EINVAL;
 		goto bad;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 4e09b6f..67ffa39 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -865,10 +865,14 @@
 {
 	int r = error;
 	struct dm_rq_target_io *tio = clone->end_io_data;
-	dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io;
+	dm_request_endio_fn rq_end_io = NULL;
 
-	if (mapped && rq_end_io)
-		r = rq_end_io(tio->ti, clone, error, &tio->info);
+	if (tio->ti) {
+		rq_end_io = tio->ti->type->rq_end_io;
+
+		if (mapped && rq_end_io)
+			r = rq_end_io(tio->ti, clone, error, &tio->info);
+	}
 
 	if (r <= 0)
 		/* The target wants to complete the I/O */
@@ -1588,15 +1592,6 @@
 	int r, requeued = 0;
 	struct dm_rq_target_io *tio = clone->end_io_data;
 
-	/*
-	 * Hold the md reference here for the in-flight I/O.
-	 * We can't rely on the reference count by device opener,
-	 * because the device may be closed during the request completion
-	 * when all bios are completed.
-	 * See the comment in rq_completed() too.
-	 */
-	dm_get(md);
-
 	tio->ti = ti;
 	r = ti->type->map_rq(ti, clone, &tio->info);
 	switch (r) {
@@ -1628,6 +1623,26 @@
 	return requeued;
 }
 
+static struct request *dm_start_request(struct mapped_device *md, struct request *orig)
+{
+	struct request *clone;
+
+	blk_start_request(orig);
+	clone = orig->special;
+	atomic_inc(&md->pending[rq_data_dir(clone)]);
+
+	/*
+	 * Hold the md reference here for the in-flight I/O.
+	 * We can't rely on the reference count by device opener,
+	 * because the device may be closed during the request completion
+	 * when all bios are completed.
+	 * See the comment in rq_completed() too.
+	 */
+	dm_get(md);
+
+	return clone;
+}
+
 /*
  * q->request_fn for request-based dm.
  * Called with the queue lock held.
@@ -1657,14 +1672,21 @@
 			pos = blk_rq_pos(rq);
 
 		ti = dm_table_find_target(map, pos);
-		BUG_ON(!dm_target_is_valid(ti));
+		if (!dm_target_is_valid(ti)) {
+			/*
+			 * Must perform setup, that dm_done() requires,
+			 * before calling dm_kill_unmapped_request
+			 */
+			DMERR_LIMIT("request attempted access beyond the end of device");
+			clone = dm_start_request(md, rq);
+			dm_kill_unmapped_request(clone, -EIO);
+			continue;
+		}
 
 		if (ti->type->busy && ti->type->busy(ti))
 			goto delay_and_out;
 
-		blk_start_request(rq);
-		clone = rq->special;
-		atomic_inc(&md->pending[rq_data_dir(clone)]);
+		clone = dm_start_request(md, rq);
 
 		spin_unlock(q->queue_lock);
 		if (map_request(ti, clone, md))
@@ -1684,8 +1706,6 @@
 	blk_delay_queue(q, HZ / 10);
 out:
 	dm_table_put(map);
-
-	return;
 }
 
 int dm_underlying_device_busy(struct request_queue *q)
@@ -2409,7 +2429,7 @@
  */
 struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
 {
-	struct dm_table *map = ERR_PTR(-EINVAL);
+	struct dm_table *live_map, *map = ERR_PTR(-EINVAL);
 	struct queue_limits limits;
 	int r;
 
@@ -2419,6 +2439,19 @@
 	if (!dm_suspended_md(md))
 		goto out;
 
+	/*
+	 * If the new table has no data devices, retain the existing limits.
+	 * This helps multipath with queue_if_no_path if all paths disappear,
+	 * then new I/O is queued based on these limits, and then some paths
+	 * reappear.
+	 */
+	if (dm_table_has_no_data_devices(table)) {
+		live_map = dm_get_live_table(md);
+		if (live_map)
+			limits = md->queue->limits;
+		dm_table_put(live_map);
+	}
+
 	r = dm_calculate_queue_limits(table, &limits);
 	if (r) {
 		map = ERR_PTR(r);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 52eef49..6a99fef 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -54,6 +54,7 @@
 			     void (*fn)(void *), void *context);
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
+bool dm_table_has_no_data_devices(struct dm_table *table);
 int dm_calculate_queue_limits(struct dm_table *table,
 			      struct queue_limits *limits);
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3f6203a..308e87b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7619,6 +7619,8 @@
 			}
 		}
 	}
+	if (removed)
+		set_bit(MD_CHANGE_DEVS, &mddev->flags);
 	return spares;
 }
 
@@ -7632,9 +7634,11 @@
 	    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
 		/* success...*/
 		/* activate any spares */
-		if (mddev->pers->spare_active(mddev))
+		if (mddev->pers->spare_active(mddev)) {
 			sysfs_notify(&mddev->kobj, NULL,
 				     "degraded");
+			set_bit(MD_CHANGE_DEVS, &mddev->flags);
+		}
 	}
 	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
 	    mddev->pers->finish_reshape)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1c2eb38..0138a72 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1512,14 +1512,16 @@
 	do {
 		int n = conf->copies;
 		int cnt = 0;
+		int this = first;
 		while (n--) {
-			if (conf->mirrors[first].rdev &&
-			    first != ignore)
+			if (conf->mirrors[this].rdev &&
+			    this != ignore)
 				cnt++;
-			first = (first+1) % geo->raid_disks;
+			this = (this+1) % geo->raid_disks;
 		}
 		if (cnt == 0)
 			return 0;
+		first = (first + geo->near_copies) % geo->raid_disks;
 	} while (first != 0);
 	return 1;
 }
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index adda94d..0689173 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -393,6 +393,8 @@
 	degraded = 0;
 	for (i = 0; i < conf->previous_raid_disks; i++) {
 		struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && test_bit(Faulty, &rdev->flags))
+			rdev = rcu_dereference(conf->disks[i].replacement);
 		if (!rdev || test_bit(Faulty, &rdev->flags))
 			degraded++;
 		else if (test_bit(In_sync, &rdev->flags))
@@ -417,6 +419,8 @@
 	degraded2 = 0;
 	for (i = 0; i < conf->raid_disks; i++) {
 		struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && test_bit(Faulty, &rdev->flags))
+			rdev = rcu_dereference(conf->disks[i].replacement);
 		if (!rdev || test_bit(Faulty, &rdev->flags))
 			degraded2++;
 		else if (test_bit(In_sync, &rdev->flags))
@@ -1587,6 +1591,7 @@
 		#ifdef CONFIG_MULTICORE_RAID456
 		init_waitqueue_head(&nsh->ops.wait_for_ops);
 		#endif
+		spin_lock_init(&nsh->stripe_lock);
 
 		list_add(&nsh->lru, &newstripes);
 	}
@@ -4192,7 +4197,7 @@
 			finish_wait(&conf->wait_for_overlap, &w);
 			set_bit(STRIPE_HANDLE, &sh->state);
 			clear_bit(STRIPE_DELAYED, &sh->state);
-			if ((bi->bi_rw & REQ_NOIDLE) &&
+			if ((bi->bi_rw & REQ_SYNC) &&
 			    !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 				atomic_inc(&conf->preread_active_stripes);
 			release_stripe_plug(mddev, sh);
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
index 72ee8de..0a497be 100644
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -524,7 +524,7 @@
 	printk(KERN_INFO DEVICE_NAME ": resume\n");
 }
 
-static struct pci_error_handlers ngene_errors = {
+static const struct pci_error_handlers ngene_errors = {
 	.error_detected = ngene_error_detected,
 	.link_reset = ngene_link_reset,
 	.slot_reset = ngene_slot_reset,
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 42b3ce9..9cce5d7 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -2,6 +2,9 @@
 # Makefile for memory devices
 #
 
+ifeq ($(CONFIG_DDR),y)
+obj-$(CONFIG_OF)		+= of_memory.o
+endif
 obj-$(CONFIG_TI_EMIF)		+= emif.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
 obj-$(CONFIG_TEGRA30_MC)	+= tegra30-mc.o
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 33a4396b..06d31c9 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
@@ -25,6 +26,7 @@
 #include <linux/spinlock.h>
 #include <memory/jedec_ddr.h>
 #include "emif.h"
+#include "of_memory.h"
 
 /**
  * struct emif_data - Per device static data for driver's use
@@ -49,6 +51,7 @@
  *				frequency in effect at the moment)
  * @plat_data:			Pointer to saved platform data.
  * @debugfs_root:		dentry to the root folder for EMIF in debugfs
+ * @np_ddr:			Pointer to ddr device tree node
  */
 struct emif_data {
 	u8				duplicate;
@@ -63,6 +66,7 @@
 	struct emif_regs		*curr_regs;
 	struct emif_platform_data	*plat_data;
 	struct dentry			*debugfs_root;
+	struct device_node		*np_ddr;
 };
 
 static struct emif_data *emif1;
@@ -71,6 +75,7 @@
 static u32		t_ck; /* DDR clock period in ps */
 static LIST_HEAD(device_list);
 
+#ifdef CONFIG_DEBUG_FS
 static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
 	struct emif_regs *regs)
 {
@@ -162,23 +167,23 @@
 	int		ret;
 
 	dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
-	if (IS_ERR(dentry)) {
-		ret = PTR_ERR(dentry);
+	if (!dentry) {
+		ret = -ENOMEM;
 		goto err0;
 	}
 	emif->debugfs_root = dentry;
 
 	dentry = debugfs_create_file("regcache_dump", S_IRUGO,
 			emif->debugfs_root, emif, &emif_regdump_fops);
-	if (IS_ERR(dentry)) {
-		ret = PTR_ERR(dentry);
+	if (!dentry) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
 	dentry = debugfs_create_file("mr4", S_IRUGO,
 			emif->debugfs_root, emif, &emif_mr4_fops);
-	if (IS_ERR(dentry)) {
-		ret = PTR_ERR(dentry);
+	if (!dentry) {
+		ret = -ENOMEM;
 		goto err1;
 	}
 
@@ -194,6 +199,16 @@
 	debugfs_remove_recursive(emif->debugfs_root);
 	emif->debugfs_root = NULL;
 }
+#else
+static inline int __init_or_module emif_debugfs_init(struct emif_data *emif)
+{
+	return 0;
+}
+
+static inline void __exit emif_debugfs_exit(struct emif_data *emif)
+{
+}
+#endif
 
 /*
  * Calculate the period of DDR clock from frequency value
@@ -1148,6 +1163,168 @@
 	return valid;
 }
 
+#if defined(CONFIG_OF)
+static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
+		struct emif_data *emif)
+{
+	struct emif_custom_configs	*cust_cfgs = NULL;
+	int				len;
+	const int			*lpmode, *poll_intvl;
+
+	lpmode = of_get_property(np_emif, "low-power-mode", &len);
+	poll_intvl = of_get_property(np_emif, "temp-alert-poll-interval", &len);
+
+	if (lpmode || poll_intvl)
+		cust_cfgs = devm_kzalloc(emif->dev, sizeof(*cust_cfgs),
+			GFP_KERNEL);
+
+	if (!cust_cfgs)
+		return;
+
+	if (lpmode) {
+		cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_LPMODE;
+		cust_cfgs->lpmode = *lpmode;
+		of_property_read_u32(np_emif,
+				"low-power-mode-timeout-performance",
+				&cust_cfgs->lpmode_timeout_performance);
+		of_property_read_u32(np_emif,
+				"low-power-mode-timeout-power",
+				&cust_cfgs->lpmode_timeout_power);
+		of_property_read_u32(np_emif,
+				"low-power-mode-freq-threshold",
+				&cust_cfgs->lpmode_freq_threshold);
+	}
+
+	if (poll_intvl) {
+		cust_cfgs->mask |=
+				EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL;
+		cust_cfgs->temp_alert_poll_interval_ms = *poll_intvl;
+	}
+
+	if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
+		devm_kfree(emif->dev, cust_cfgs);
+		return;
+	}
+
+	emif->plat_data->custom_configs = cust_cfgs;
+}
+
+static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
+		struct device_node *np_ddr,
+		struct ddr_device_info *dev_info)
+{
+	u32 density = 0, io_width = 0;
+	int len;
+
+	if (of_find_property(np_emif, "cs1-used", &len))
+		dev_info->cs1_used = true;
+
+	if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
+		dev_info->cal_resistors_per_cs = true;
+
+	if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s4"))
+		dev_info->type = DDR_TYPE_LPDDR2_S4;
+	else if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s2"))
+		dev_info->type = DDR_TYPE_LPDDR2_S2;
+
+	of_property_read_u32(np_ddr, "density", &density);
+	of_property_read_u32(np_ddr, "io-width", &io_width);
+
+	/* Convert from density in Mb to the density encoding in jedc_ddr.h */
+	if (density & (density - 1))
+		dev_info->density = 0;
+	else
+		dev_info->density = __fls(density) - 5;
+
+	/* Convert from io_width in bits to io_width encoding in jedc_ddr.h */
+	if (io_width & (io_width - 1))
+		dev_info->io_width = 0;
+	else
+		dev_info->io_width = __fls(io_width) - 1;
+}
+
+static struct emif_data * __init_or_module of_get_memory_device_details(
+		struct device_node *np_emif, struct device *dev)
+{
+	struct emif_data		*emif = NULL;
+	struct ddr_device_info		*dev_info = NULL;
+	struct emif_platform_data	*pd = NULL;
+	struct device_node		*np_ddr;
+	int				len;
+
+	np_ddr = of_parse_phandle(np_emif, "device-handle", 0);
+	if (!np_ddr)
+		goto error;
+	emif	= devm_kzalloc(dev, sizeof(struct emif_data), GFP_KERNEL);
+	pd	= devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
+
+	if (!emif || !pd || !dev_info) {
+		dev_err(dev, "%s: Out of memory!!\n",
+			__func__);
+		goto error;
+	}
+
+	emif->plat_data		= pd;
+	pd->device_info		= dev_info;
+	emif->dev		= dev;
+	emif->np_ddr		= np_ddr;
+	emif->temperature_level	= SDRAM_TEMP_NOMINAL;
+
+	if (of_device_is_compatible(np_emif, "ti,emif-4d"))
+		emif->plat_data->ip_rev = EMIF_4D;
+	else if (of_device_is_compatible(np_emif, "ti,emif-4d5"))
+		emif->plat_data->ip_rev = EMIF_4D5;
+
+	of_property_read_u32(np_emif, "phy-type", &pd->phy_type);
+
+	if (of_find_property(np_emif, "hw-caps-ll-interface", &len))
+		pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE;
+
+	of_get_ddr_info(np_emif, np_ddr, dev_info);
+	if (!is_dev_data_valid(pd->device_info->type, pd->device_info->density,
+			pd->device_info->io_width, pd->phy_type, pd->ip_rev,
+			emif->dev)) {
+		dev_err(dev, "%s: invalid device data!!\n", __func__);
+		goto error;
+	}
+	/*
+	 * For EMIF instances other than EMIF1 see if the devices connected
+	 * are exactly same as on EMIF1(which is typically the case). If so,
+	 * mark it as a duplicate of EMIF1. This will save some memory and
+	 * computation.
+	 */
+	if (emif1 && emif1->np_ddr == np_ddr) {
+		emif->duplicate = true;
+		goto out;
+	} else if (emif1) {
+		dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
+			__func__);
+	}
+
+	of_get_custom_configs(np_emif, emif);
+	emif->plat_data->timings = of_get_ddr_timings(np_ddr, emif->dev,
+					emif->plat_data->device_info->type,
+					&emif->plat_data->timings_arr_size);
+
+	emif->plat_data->min_tck = of_get_min_tck(np_ddr, emif->dev);
+	goto out;
+
+error:
+	return NULL;
+out:
+	return emif;
+}
+
+#else
+
+static struct emif_data * __init_or_module of_get_memory_device_details(
+		struct device_node *np_emif, struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static struct emif_data *__init_or_module get_device_details(
 		struct platform_device *pdev)
 {
@@ -1267,7 +1444,11 @@
 	struct resource		*res;
 	int			irq;
 
-	emif = get_device_details(pdev);
+	if (pdev->dev.of_node)
+		emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev);
+	else
+		emif = get_device_details(pdev);
+
 	if (!emif) {
 		pr_err("%s: error getting device data\n", __func__);
 		goto error;
@@ -1644,11 +1825,21 @@
 	spin_unlock_irqrestore(&emif_lock, irq_state);
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id emif_of_match[] = {
+		{ .compatible = "ti,emif-4d" },
+		{ .compatible = "ti,emif-4d5" },
+		{},
+};
+MODULE_DEVICE_TABLE(of, emif_of_match);
+#endif
+
 static struct platform_driver emif_driver = {
 	.remove		= __exit_p(emif_remove),
 	.shutdown	= emif_shutdown,
 	.driver = {
 		.name = "emif",
+		.of_match_table = of_match_ptr(emif_of_match),
 	},
 };
 
diff --git a/drivers/memory/of_memory.c b/drivers/memory/of_memory.c
new file mode 100644
index 0000000..6007435
--- /dev/null
+++ b/drivers/memory/of_memory.c
@@ -0,0 +1,153 @@
+/*
+ * OpenFirmware helpers for memory drivers
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+#include <memory/jedec_ddr.h>
+#include <linux/export.h>
+
+/**
+ * of_get_min_tck() - extract min timing values for ddr
+ * @np: pointer to ddr device tree node
+ * @device: device requesting for min timing values
+ *
+ * Populates the lpddr2_min_tck structure by extracting data
+ * from device tree node. Returns a pointer to the populated
+ * structure. If any error in populating the structure, returns
+ * default min timings provided by JEDEC.
+ */
+const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
+		struct device *dev)
+{
+	int			ret = 0;
+	struct lpddr2_min_tck	*min;
+
+	min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
+	if (!min)
+		goto default_min_tck;
+
+	ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
+	ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
+	ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
+	ret |= of_property_read_u32(np, "tRASmin-min-tck", &min->tRASmin);
+	ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
+	ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
+	ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
+	ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
+	ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
+	ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
+	ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
+
+	if (ret) {
+		devm_kfree(dev, min);
+		goto default_min_tck;
+	}
+
+	return min;
+
+default_min_tck:
+	dev_warn(dev, "%s: using default min-tck values\n", __func__);
+	return &lpddr2_jedec_min_tck;
+}
+EXPORT_SYMBOL(of_get_min_tck);
+
+static int of_do_get_timings(struct device_node *np,
+		struct lpddr2_timings *tim)
+{
+	int ret;
+
+	ret = of_property_read_u32(np, "max-freq", &tim->max_freq);
+	ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
+	ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
+	ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
+	ret |= of_property_read_u32(np, "tWR", &tim->tWR);
+	ret |= of_property_read_u32(np, "tRAS-min", &tim->tRAS_min);
+	ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
+	ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
+	ret |= of_property_read_u32(np, "tXP", &tim->tXP);
+	ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
+	ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
+	ret |= of_property_read_u32(np, "tDQSCK-max", &tim->tDQSCK_max);
+	ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
+	ret |= of_property_read_u32(np, "tZQCS", &tim->tZQCS);
+	ret |= of_property_read_u32(np, "tZQCL", &tim->tZQCL);
+	ret |= of_property_read_u32(np, "tZQinit", &tim->tZQinit);
+	ret |= of_property_read_u32(np, "tRAS-max-ns", &tim->tRAS_max_ns);
+	ret |= of_property_read_u32(np, "tDQSCK-max-derated",
+		&tim->tDQSCK_max_derated);
+
+	return ret;
+}
+
+/**
+ * of_get_ddr_timings() - extracts the ddr timings and updates no of
+ * frequencies available.
+ * @np_ddr: Pointer to ddr device tree node
+ * @dev: Device requesting for ddr timings
+ * @device_type: Type of ddr(LPDDR2 S2/S4)
+ * @nr_frequencies: No of frequencies available for ddr
+ * (updated by this function)
+ *
+ * Populates lpddr2_timings structure by extracting data from device
+ * tree node. Returns pointer to populated structure. If any error
+ * while populating, returns default timings provided by JEDEC.
+ */
+const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
+		struct device *dev, u32 device_type, u32 *nr_frequencies)
+{
+	struct lpddr2_timings	*timings = NULL;
+	u32			arr_sz = 0, i = 0;
+	struct device_node	*np_tim;
+	char			*tim_compat;
+
+	switch (device_type) {
+	case DDR_TYPE_LPDDR2_S2:
+	case DDR_TYPE_LPDDR2_S4:
+		tim_compat = "jedec,lpddr2-timings";
+		break;
+	default:
+		dev_warn(dev, "%s: un-supported memory type\n", __func__);
+	}
+
+	for_each_child_of_node(np_ddr, np_tim)
+		if (of_device_is_compatible(np_tim, tim_compat))
+			arr_sz++;
+
+	if (arr_sz)
+		timings = devm_kzalloc(dev, sizeof(*timings) * arr_sz,
+			GFP_KERNEL);
+
+	if (!timings)
+		goto default_timings;
+
+	for_each_child_of_node(np_ddr, np_tim) {
+		if (of_device_is_compatible(np_tim, tim_compat)) {
+			if (of_do_get_timings(np_tim, &timings[i])) {
+				devm_kfree(dev, timings);
+				goto default_timings;
+			}
+			i++;
+		}
+	}
+
+	*nr_frequencies = arr_sz;
+
+	return timings;
+
+default_timings:
+	dev_warn(dev, "%s: using default timings\n", __func__);
+	*nr_frequencies = ARRAY_SIZE(lpddr2_jedec_timings);
+	return lpddr2_jedec_timings;
+}
+EXPORT_SYMBOL(of_get_ddr_timings);
diff --git a/drivers/memory/of_memory.h b/drivers/memory/of_memory.h
new file mode 100644
index 0000000..ef2514f
--- /dev/null
+++ b/drivers/memory/of_memory.h
@@ -0,0 +1,36 @@
+/*
+ * OpenFirmware helpers for memory drivers
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_MEMORY_OF_REG_H
+#define __LINUX_MEMORY_OF_REG_H
+
+#if defined(CONFIG_OF) && defined(CONFIG_DDR)
+extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
+		struct device *dev);
+extern const struct lpddr2_timings
+	*of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
+	u32 device_type, u32 *nr_frequencies);
+#else
+static inline const struct lpddr2_min_tck
+	*of_get_min_tck(struct device_node *np, struct device *dev)
+{
+	return NULL;
+}
+
+static inline const struct lpddr2_timings
+	*of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
+	u32 device_type, u32 *nr_frequencies)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF && CONFIG_DDR */
+
+#endif /* __LINUX_MEMORY_OF_REG_ */
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
index 3ed49c1..e6764bb 100644
--- a/drivers/memory/tegra20-mc.c
+++ b/drivers/memory/tegra20-mc.c
@@ -57,7 +57,7 @@
 
 	if (offs < 0x24)
 		val = readl(mc->regs[0] + offs);
-	if (offs < 0x400)
+	else if (offs < 0x400)
 		val = readl(mc->regs[1] + offs - 0x3c);
 
 	return val;
@@ -65,14 +65,10 @@
 
 static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs)
 {
-	if (offs < 0x24) {
+	if (offs < 0x24)
 		writel(val, mc->regs[0] + offs);
-		return;
-	}
-	if (offs < 0x400) {
+	else if (offs < 0x400)
 		writel(val, mc->regs[1] + offs - 0x3c);
-		return;
-	}
 }
 
 static const char * const tegra20_mc_client[] = {
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
index e56ff04..802b9ea 100644
--- a/drivers/memory/tegra30-mc.c
+++ b/drivers/memory/tegra30-mc.c
@@ -95,11 +95,11 @@
 
 	if (offs < 0x10)
 		val = readl(mc->regs[0] + offs);
-	if (offs < 0x1f0)
+	else if (offs < 0x1f0)
 		val = readl(mc->regs[1] + offs - 0x3c);
-	if (offs < 0x228)
+	else if (offs < 0x228)
 		val = readl(mc->regs[2] + offs - 0x200);
-	if (offs < 0x400)
+	else if (offs < 0x400)
 		val = readl(mc->regs[3] + offs - 0x284);
 
 	return val;
@@ -107,22 +107,14 @@
 
 static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
 {
-	if (offs < 0x10) {
+	if (offs < 0x10)
 		writel(val, mc->regs[0] + offs);
-		return;
-	}
-	if (offs < 0x1f0) {
+	else if (offs < 0x1f0)
 		writel(val, mc->regs[1] + offs - 0x3c);
-		return;
-	}
-	if (offs < 0x228) {
+	else if (offs < 0x228)
 		writel(val, mc->regs[2] + offs - 0x200);
-		return;
-	}
-	if (offs < 0x400) {
+	else if (offs < 0x400)
 		writel(val, mc->regs[3] + offs - 0x284);
-		return;
-	}
 }
 
 static const char * const tegra30_mc_client[] = {
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 866f959..29d72a2 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -342,7 +342,7 @@
 
 		 /*
 		  * Delay might be needed for ABB8500 cut 3.0, if not, remove
-		  * when hardware will be availible
+		  * when hardware will be available
 		  */
 			msleep(1);
 			break;
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 82c9d64..352c58b 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -46,7 +46,7 @@
 	return 0;
 }
 
-static struct i2c_device_id da9052_i2c_id[] = {
+static const struct i2c_device_id da9052_i2c_id[] = {
 	{"da9052", DA9052},
 	{"da9053-aa", DA9053_AA},
 	{"da9053-ba", DA9053_BA},
@@ -104,7 +104,7 @@
 		const struct of_device_id *deviceid;
 
 		deviceid = of_match_node(dialog_dt_ids, np);
-		id = (const struct i2c_device_id *)deviceid->data;
+		id = deviceid->data;
 	}
 #endif
 
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
index 3a8fa88..ff61efc 100644
--- a/drivers/mfd/rc5t583.c
+++ b/drivers/mfd/rc5t583.c
@@ -281,7 +281,7 @@
 
 	if (i2c->irq) {
 		ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
-		/* Still continue with waring if irq init fails */
+		/* Still continue with warning, if irq init fails */
 		if (ret)
 			dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
 		else
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c
index 0f70dce..fbabc3cb 100644
--- a/drivers/mfd/rdc321x-southbridge.c
+++ b/drivers/mfd/rdc321x-southbridge.c
@@ -1,5 +1,5 @@
 /*
- * RDC321x MFD southbrige driver
+ * RDC321x MFD southbridge driver
  *
  * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
  * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com>
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 5f58370..345960ca 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6586x.h>
@@ -346,6 +347,7 @@
 
 #ifdef CONFIG_OF
 static struct of_regulator_match tps6586x_matches[] = {
+	{ .name = "sys",     .driver_data = (void *)TPS6586X_ID_SYS     },
 	{ .name = "sm0",     .driver_data = (void *)TPS6586X_ID_SM_0    },
 	{ .name = "sm1",     .driver_data = (void *)TPS6586X_ID_SM_1    },
 	{ .name = "sm2",     .driver_data = (void *)TPS6586X_ID_SM_2    },
@@ -369,6 +371,7 @@
 	struct tps6586x_platform_data *pdata;
 	struct tps6586x_subdev_info *devs;
 	struct device_node *regs;
+	const char *sys_rail_name = NULL;
 	unsigned int count;
 	unsigned int i, j;
 	int err;
@@ -391,12 +394,22 @@
 		return NULL;
 
 	for (i = 0, j = 0; i < num && j < count; i++) {
+		struct regulator_init_data *reg_idata;
+
 		if (!tps6586x_matches[i].init_data)
 			continue;
 
+		reg_idata  = tps6586x_matches[i].init_data;
 		devs[j].name = "tps6586x-regulator";
 		devs[j].platform_data = tps6586x_matches[i].init_data;
 		devs[j].id = (int)tps6586x_matches[i].driver_data;
+		if (devs[j].id == TPS6586X_ID_SYS)
+			sys_rail_name = reg_idata->constraints.name;
+
+		if ((devs[j].id == TPS6586X_ID_LDO_5) ||
+			(devs[j].id == TPS6586X_ID_LDO_RTC))
+			reg_idata->supply_regulator = sys_rail_name;
+
 		devs[j].of_node = tps6586x_matches[i].of_node;
 		j++;
 	}
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index 5a62e6bf..0b6e361 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -136,7 +136,7 @@
 
 	ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot set COMP2 theshold\n");
+		dev_err(&pdev->dev, "cannot set COMP2 threshold\n");
 		return ret;
 	}
 
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index f462ff2..9d3a0bc 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -46,8 +46,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
-#include <plat/cpu.h>
-
 #include "twl-core.h"
 
 /*
@@ -1134,12 +1132,7 @@
 	u32 rate;
 	u8 ctrl = HFCLK_FREQ_26_MHZ;
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-	if (cpu_is_omap2430())
-		osc = clk_get(dev, "osc_ck");
-	else
-		osc = clk_get(dev, "osc_sys_ck");
-
+	osc = clk_get(dev, "fck");
 	if (IS_ERR(osc)) {
 		printk(KERN_WARNING "Skipping twl internal clock init and "
 				"using bootloader value (unknown osc rate)\n");
@@ -1149,18 +1142,6 @@
 	rate = clk_get_rate(osc);
 	clk_put(osc);
 
-#else
-	/* REVISIT for non-OMAP systems, pass the clock rate from
-	 * board init code, using platform_data.
-	 */
-	osc = ERR_PTR(-EIO);
-
-	printk(KERN_WARNING "Skipping twl internal clock init and "
-	       "using bootloader value (unknown osc rate)\n");
-
-	return;
-#endif
-
 	switch (rate) {
 	case 19200000:
 		ctrl = HFCLK_FREQ_19p2_MHZ;
@@ -1222,10 +1203,23 @@
 {
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	struct device_node		*node = client->dev.of_node;
+	struct platform_device		*pdev;
 	int				irq_base = 0;
 	int				status;
 	unsigned			i, num_slaves;
 
+	pdev = platform_device_alloc(DRIVER_NAME, -1);
+	if (!pdev) {
+		dev_err(&client->dev, "can't alloc pdev\n");
+		return -ENOMEM;
+	}
+
+	status = platform_device_add(pdev);
+	if (status) {
+		platform_device_put(pdev);
+		return status;
+	}
+
 	if (node && !pdata) {
 		/*
 		 * XXX: Temporary pdata until the information is correctly
@@ -1234,23 +1228,30 @@
 		pdata = devm_kzalloc(&client->dev,
 				     sizeof(struct twl4030_platform_data),
 				     GFP_KERNEL);
-		if (!pdata)
-			return -ENOMEM;
+		if (!pdata) {
+			status = -ENOMEM;
+			goto free;
+		}
 	}
 
 	if (!pdata) {
 		dev_dbg(&client->dev, "no platform data?\n");
-		return -EINVAL;
+		status = -EINVAL;
+		goto free;
 	}
 
+	platform_set_drvdata(pdev, pdata);
+
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
 		dev_dbg(&client->dev, "can't talk I2C?\n");
-		return -EIO;
+		status = -EIO;
+		goto free;
 	}
 
 	if (inuse) {
 		dev_dbg(&client->dev, "driver is already in use\n");
-		return -EBUSY;
+		status = -EBUSY;
+		goto free;
 	}
 
 	if ((id->driver_data) & TWL6030_CLASS) {
@@ -1285,7 +1286,7 @@
 	inuse = true;
 
 	/* setup clock framework */
-	clocks_init(&client->dev, pdata->clock);
+	clocks_init(&pdev->dev, pdata->clock);
 
 	/* read TWL IDCODE Register */
 	if (twl_id == TWL4030_CLASS_ID) {
@@ -1335,6 +1336,9 @@
 fail:
 	if (status < 0)
 		twl_remove(client);
+free:
+	if (status < 0)
+		platform_device_unregister(pdev);
 
 	return status;
 }
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index 0aac4af..a050e56 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -135,6 +135,7 @@
 	.status_base = WM8994_INTERRUPT_STATUS_1,
 	.mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
 	.ack_base = WM8994_INTERRUPT_STATUS_1,
+	.runtime_pm = true,
 };
 
 int wm8994_irq_init(struct wm8994 *wm8994)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 98a442d..99c7335 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -105,7 +105,7 @@
 
 config IBM_ASM
 	tristate "Device driver for IBM RSA service processor"
-	depends on X86 && PCI && INPUT && EXPERIMENTAL
+	depends on X86 && PCI && INPUT
 	---help---
 	  This option enables device driver support for in-band access to the
 	  IBM RSA (Condor) service processor in eServer xSeries systems.
@@ -162,8 +162,8 @@
 	  Otherwise say N.
 
 config TIFM_CORE
-	tristate "TI Flash Media interface support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PCI
+	tristate "TI Flash Media interface support"
+	depends on PCI
 	help
 	  If you want support for Texas Instruments(R) Flash Media adapters
 	  you should select this option and then also choose an appropriate
@@ -178,8 +178,8 @@
 	  be called tifm_core.
 
 config TIFM_7XX1
-	tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
-	depends on PCI && TIFM_CORE && EXPERIMENTAL
+	tristate "TI Flash Media PCI74xx/PCI76xx host adapter support"
+	depends on PCI && TIFM_CORE
 	default TIFM_CORE
 	help
 	  This option enables support for Texas Instruments(R) PCI74xx and
@@ -192,7 +192,7 @@
 
 config ICS932S401
 	tristate "Integrated Circuits ICS932S401"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Integrated Circuits
 	  ICS932S401 clock control chips.
@@ -398,7 +398,7 @@
 
 config DS1682
 	tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Dallas Semiconductor
 	  DS1682 Total Elapsed Time Recorder.
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c
index 9943971..a4f33c9 100644
--- a/drivers/misc/bmp085-i2c.c
+++ b/drivers/misc/bmp085-i2c.c
@@ -57,12 +57,6 @@
 	return bmp085_remove(&client->dev);
 }
 
-static const struct of_device_id bmp085_of_match[] = {
-	{ .compatible = "bosch,bmp085", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, bmp085_of_match);
-
 static const struct i2c_device_id bmp085_id[] = {
 	{ BMP085_NAME, 0 },
 	{ "bmp180", 0 },
@@ -74,7 +68,6 @@
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= BMP085_NAME,
-		.of_match_table = bmp085_of_match
 	},
 	.id_table	= bmp085_id,
 	.probe		= bmp085_i2c_probe,
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c
index 78aaff9..5e982af 100644
--- a/drivers/misc/bmp085-spi.c
+++ b/drivers/misc/bmp085-spi.c
@@ -73,19 +73,8 @@
 	.remove		= __devexit_p(bmp085_spi_remove)
 };
 
-static int __init bmp085_spi_init(void)
-{
-	return spi_register_driver(&bmp085_spi_driver);
-}
-
-static void __exit bmp085_spi_exit(void)
-{
-	spi_unregister_driver(&bmp085_spi_driver);
-}
+module_spi_driver(bmp085_spi_driver);
 
 MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
 MODULE_DESCRIPTION("BMP085 SPI bus driver");
 MODULE_LICENSE("GPL");
-
-module_init(bmp085_spi_init);
-module_exit(bmp085_spi_exit);
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
index 33ee834..0dd690e 100644
--- a/drivers/misc/c2port/Kconfig
+++ b/drivers/misc/c2port/Kconfig
@@ -3,8 +3,7 @@
 #
 
 menuconfig C2PORT
-	tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Silicon Labs C2 port support"
 	default n
 	help
 	  This option enables support for Silicon Labs C2 port used to
@@ -22,7 +21,7 @@
 if C2PORT
 
 config C2PORT_DURAMAR_2150
-	tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
+	tristate "C2 port support for Eurotech's Duramar 2150"
 	depends on X86
 	default n
 	help
diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c
index a2d25e4..eaddfe9 100644
--- a/drivers/misc/carma/carma-fpga-program.c
+++ b/drivers/misc/carma/carma-fpga-program.c
@@ -978,7 +978,6 @@
 	dev_set_drvdata(priv->dev, priv);
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_MEMCPY, mask);
-	dma_cap_set(DMA_INTERRUPT, mask);
 	dma_cap_set(DMA_SLAVE, mask);
 	dma_cap_set(DMA_SG, mask);
 
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
index 8c279da..0c43297 100644
--- a/drivers/misc/carma/carma-fpga.c
+++ b/drivers/misc/carma/carma-fpga.c
@@ -666,7 +666,7 @@
 	src = SYS_FPGA_BLOCK;
 	tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
 						  REG_BLOCK_SIZE,
-						  DMA_PREP_INTERRUPT);
+						  0);
 	if (!tx) {
 		dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
 		return -ENOMEM;
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 701edf6..c9e695e 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -50,7 +50,7 @@
 
 config EEPROM_MAX6875
 	tristate "Maxim MAX6874/5 power supply supervisor"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get read-only support for the user EEPROM of
 	  the Maxim MAX6874/5 EEPROM-programmable, quad power-supply
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 25003d6..4ed93dd 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -302,6 +302,61 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int at25_np_to_chip(struct device *dev,
+			   struct device_node *np,
+			   struct spi_eeprom *chip)
+{
+	u32 val;
+
+	memset(chip, 0, sizeof(*chip));
+	strncpy(chip->name, np->name, sizeof(chip->name));
+
+	if (of_property_read_u32(np, "size", &val) == 0 ||
+	    of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+		chip->byte_len = val;
+	} else {
+		dev_err(dev, "Error: missing \"size\" property\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(np, "pagesize", &val) == 0 ||
+	    of_property_read_u32(np, "at25,page-size", &val) == 0) {
+		chip->page_size = (u16)val;
+	} else {
+		dev_err(dev, "Error: missing \"pagesize\" property\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+		chip->flags = (u16)val;
+	} else {
+		if (of_property_read_u32(np, "address-width", &val)) {
+			dev_err(dev,
+				"Error: missing \"address-width\" property\n");
+			return -ENODEV;
+		}
+		switch (val) {
+		case 8:
+			chip->flags |= EE_ADDR1;
+			break;
+		case 16:
+			chip->flags |= EE_ADDR2;
+			break;
+		case 24:
+			chip->flags |= EE_ADDR3;
+			break;
+		default:
+			dev_err(dev,
+				"Error: bad \"address-width\" property: %u\n",
+				val);
+			return -ENODEV;
+		}
+		if (of_find_property(np, "read-only", NULL))
+			chip->flags |= EE_READONLY;
+	}
+	return 0;
+}
+
 static int at25_probe(struct spi_device *spi)
 {
 	struct at25_data	*at25 = NULL;
@@ -314,33 +369,11 @@
 	/* Chip description */
 	if (!spi->dev.platform_data) {
 		if (np) {
-			u32 val;
-
-			memset(&chip, 0, sizeof(chip));
-			strncpy(chip.name, np->name, 10);
-
-			err = of_property_read_u32(np, "at25,byte-len", &val);
-			if (err) {
-				dev_dbg(&spi->dev, "invalid chip dt description\n");
+			err = at25_np_to_chip(&spi->dev, np, &chip);
+			if (err)
 				goto fail;
-			}
-			chip.byte_len = val;
-
-			err = of_property_read_u32(np, "at25,addr-mode", &val);
-			if (err) {
-				dev_dbg(&spi->dev, "invalid chip dt description\n");
-				goto fail;
-			}
-			chip.flags = (u16)val;
-
-			err = of_property_read_u32(np, "at25,page-size", &val);
-			if (err) {
-				dev_dbg(&spi->dev, "invalid chip dt description\n");
-				goto fail;
-			}
-			chip.page_size = (u16)val;
 		} else {
-			dev_dbg(&spi->dev, "no chip description\n");
+			dev_err(&spi->dev, "Error: no chip description\n");
 			err = -ENODEV;
 			goto fail;
 		}
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 6df0da4..12ccdf9 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -736,7 +736,14 @@
 	free_irq(pdev->irq, ilo_hw);
 	ilo_unmap_device(pdev, ilo_hw);
 	pci_release_regions(pdev);
-	pci_disable_device(pdev);
+	/*
+	 * pci_disable_device(pdev) used to be here. But this PCI device has
+	 * two functions with interrupt lines connected to a single pin. The
+	 * other one is a USB host controller. So when we disable the PIN here
+	 * e.g. by rmmod hpilo, the controller stops working. It is because
+	 * the interrupt link is disabled in ACPI since it is not refcounted
+	 * yet. See acpi_pci_link_free_irq called from acpi_pci_irq_disable.
+	 */
 	kfree(ilo_hw);
 	ilo_hwdev[(minor / max_ccb)] = 0;
 }
@@ -826,7 +833,7 @@
 free_regions:
 	pci_release_regions(pdev);
 disable:
-	pci_disable_device(pdev);
+/*	pci_disable_device(pdev);  see comment in ilo_remove */
 free:
 	kfree(ilo_hw);
 out:
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index a981e2a..4a87e5c 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -39,6 +39,7 @@
 #include <linux/miscdevice.h>
 #include <linux/pm_runtime.h>
 #include <linux/atomic.h>
+#include <linux/of_device.h>
 #include "lis3lv02d.h"
 
 #define DRIVER_NAME     "lis3lv02d"
@@ -80,6 +81,15 @@
 #define LIS3_SENSITIVITY_12B		((LIS3_ACCURACY * 1000) / 1024)
 #define LIS3_SENSITIVITY_8B		(18 * LIS3_ACCURACY)
 
+/*
+ * LIS331DLH spec says 1LSBs corresponds 4G/4096 -> 1LSB is 1000/1024 mG.
+ * Below macros defines sensitivity values for +/-2G. Dataout bits for
+ * +/-2G range is 12 bits so 4 bits adjustment must be done to get 12bit
+ * data from 16bit value. Currently this driver supports only 2G range.
+ */
+#define LIS3DLH_SENSITIVITY_2G		((LIS3_ACCURACY * 1000) / 1024)
+#define SHIFT_ADJ_2G			4
+
 #define LIS3_DEFAULT_FUZZ_12B		3
 #define LIS3_DEFAULT_FLAT_12B		3
 #define LIS3_DEFAULT_FUZZ_8B		1
@@ -135,6 +145,19 @@
 	return (s16)((hi << 8) | lo);
 }
 
+/* 12bits for 2G range, 13 bits for 4G range and 14 bits for 8G range */
+static s16 lis331dlh_read_data(struct lis3lv02d *lis3, int reg)
+{
+	u8 lo, hi;
+	int v;
+
+	lis3->read(lis3, reg - 1, &lo);
+	lis3->read(lis3, reg, &hi);
+	v = (int) ((hi << 8) | lo);
+
+	return (s16) v >> lis3->shift_adj;
+}
+
 /**
  * lis3lv02d_get_axis - For the given axis, give the value converted
  * @axis:      1,2,3 - can also be negative
@@ -195,6 +218,7 @@
 static int lis3_12_rates[4] = {40, 160, 640, 2560};
 static int lis3_8_rates[2] = {100, 400};
 static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
+static int lis3_3dlh_rates[4] = {50, 100, 400, 1000};
 
 /* ODR is Output Data Rate */
 static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
@@ -267,7 +291,7 @@
 				(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
 	}
 
-	if (lis3->whoami == WAI_3DC) {
+	if ((lis3->whoami == WAI_3DC) || (lis3->whoami == WAI_3DLH)) {
 		ctlreg = CTRL_REG4;
 		selftest = CTRL4_ST0;
 	} else {
@@ -398,9 +422,17 @@
 		lis3->read(lis3, CTRL_REG2, &reg);
 		if (lis3->whoami ==  WAI_12B)
 			reg |= CTRL2_BDU | CTRL2_BOOT;
+		else if (lis3->whoami ==  WAI_3DLH)
+			reg |= CTRL2_BOOT_3DLH;
 		else
 			reg |= CTRL2_BOOT_8B;
 		lis3->write(lis3, CTRL_REG2, reg);
+
+		if (lis3->whoami ==  WAI_3DLH) {
+			lis3->read(lis3, CTRL_REG4, &reg);
+			reg |= CTRL4_BDU;
+			lis3->write(lis3, CTRL_REG4, reg);
+		}
 	}
 
 	err = lis3lv02d_get_pwron_wait(lis3);
@@ -912,6 +944,154 @@
 	}
 }
 
+#ifdef CONFIG_OF
+int lis3lv02d_init_dt(struct lis3lv02d *lis3)
+{
+	struct lis3lv02d_platform_data *pdata;
+	struct device_node *np = lis3->of_node;
+	u32 val;
+
+	if (!lis3->of_node)
+		return 0;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (of_get_property(np, "st,click-single-x", NULL))
+		pdata->click_flags |= LIS3_CLICK_SINGLE_X;
+	if (of_get_property(np, "st,click-double-x", NULL))
+		pdata->click_flags |= LIS3_CLICK_DOUBLE_X;
+
+	if (of_get_property(np, "st,click-single-y", NULL))
+		pdata->click_flags |= LIS3_CLICK_SINGLE_Y;
+	if (of_get_property(np, "st,click-double-y", NULL))
+		pdata->click_flags |= LIS3_CLICK_DOUBLE_Y;
+
+	if (of_get_property(np, "st,click-single-z", NULL))
+		pdata->click_flags |= LIS3_CLICK_SINGLE_Z;
+	if (of_get_property(np, "st,click-double-z", NULL))
+		pdata->click_flags |= LIS3_CLICK_DOUBLE_Z;
+
+	if (!of_property_read_u32(np, "st,click-threshold-x", &val))
+		pdata->click_thresh_x = val;
+	if (!of_property_read_u32(np, "st,click-threshold-y", &val))
+		pdata->click_thresh_y = val;
+	if (!of_property_read_u32(np, "st,click-threshold-z", &val))
+		pdata->click_thresh_z = val;
+
+	if (!of_property_read_u32(np, "st,click-time-limit", &val))
+		pdata->click_time_limit = val;
+	if (!of_property_read_u32(np, "st,click-latency", &val))
+		pdata->click_latency = val;
+	if (!of_property_read_u32(np, "st,click-window", &val))
+		pdata->click_window = val;
+
+	if (of_get_property(np, "st,irq1-disable", NULL))
+		pdata->irq_cfg |= LIS3_IRQ1_DISABLE;
+	if (of_get_property(np, "st,irq1-ff-wu-1", NULL))
+		pdata->irq_cfg |= LIS3_IRQ1_FF_WU_1;
+	if (of_get_property(np, "st,irq1-ff-wu-2", NULL))
+		pdata->irq_cfg |= LIS3_IRQ1_FF_WU_2;
+	if (of_get_property(np, "st,irq1-data-ready", NULL))
+		pdata->irq_cfg |= LIS3_IRQ1_DATA_READY;
+	if (of_get_property(np, "st,irq1-click", NULL))
+		pdata->irq_cfg |= LIS3_IRQ1_CLICK;
+
+	if (of_get_property(np, "st,irq2-disable", NULL))
+		pdata->irq_cfg |= LIS3_IRQ2_DISABLE;
+	if (of_get_property(np, "st,irq2-ff-wu-1", NULL))
+		pdata->irq_cfg |= LIS3_IRQ2_FF_WU_1;
+	if (of_get_property(np, "st,irq2-ff-wu-2", NULL))
+		pdata->irq_cfg |= LIS3_IRQ2_FF_WU_2;
+	if (of_get_property(np, "st,irq2-data-ready", NULL))
+		pdata->irq_cfg |= LIS3_IRQ2_DATA_READY;
+	if (of_get_property(np, "st,irq2-click", NULL))
+		pdata->irq_cfg |= LIS3_IRQ2_CLICK;
+
+	if (of_get_property(np, "st,irq-open-drain", NULL))
+		pdata->irq_cfg |= LIS3_IRQ_OPEN_DRAIN;
+	if (of_get_property(np, "st,irq-active-low", NULL))
+		pdata->irq_cfg |= LIS3_IRQ_ACTIVE_LOW;
+
+	if (!of_property_read_u32(np, "st,wu-duration-1", &val))
+		pdata->duration1 = val;
+	if (!of_property_read_u32(np, "st,wu-duration-2", &val))
+		pdata->duration2 = val;
+
+	if (of_get_property(np, "st,wakeup-x-lo", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_X_LO;
+	if (of_get_property(np, "st,wakeup-x-hi", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_X_HI;
+	if (of_get_property(np, "st,wakeup-y-lo", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_Y_LO;
+	if (of_get_property(np, "st,wakeup-y-hi", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_Y_HI;
+	if (of_get_property(np, "st,wakeup-z-lo", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_Z_LO;
+	if (of_get_property(np, "st,wakeup-z-hi", NULL))
+		pdata->wakeup_flags |= LIS3_WAKEUP_Z_HI;
+
+	if (!of_property_read_u32(np, "st,highpass-cutoff-hz", &val)) {
+		switch (val) {
+		case 1:
+			pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_1HZ;
+			break;
+		case 2:
+			pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_2HZ;
+			break;
+		case 4:
+			pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_4HZ;
+			break;
+		case 8:
+			pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_8HZ;
+			break;
+		}
+	}
+
+	if (of_get_property(np, "st,hipass1-disable", NULL))
+		pdata->hipass_ctrl |= LIS3_HIPASS1_DISABLE;
+	if (of_get_property(np, "st,hipass2-disable", NULL))
+		pdata->hipass_ctrl |= LIS3_HIPASS2_DISABLE;
+
+	if (of_get_property(np, "st,axis-x", &val))
+		pdata->axis_x = val;
+	if (of_get_property(np, "st,axis-y", &val))
+		pdata->axis_y = val;
+	if (of_get_property(np, "st,axis-z", &val))
+		pdata->axis_z = val;
+
+	if (of_get_property(np, "st,default-rate", NULL))
+		pdata->default_rate = val;
+
+	if (of_get_property(np, "st,min-limit-x", &val))
+		pdata->st_min_limits[0] = val;
+	if (of_get_property(np, "st,min-limit-y", &val))
+		pdata->st_min_limits[1] = val;
+	if (of_get_property(np, "st,min-limit-z", &val))
+		pdata->st_min_limits[2] = val;
+
+	if (of_get_property(np, "st,max-limit-x", &val))
+		pdata->st_max_limits[0] = val;
+	if (of_get_property(np, "st,max-limit-y", &val))
+		pdata->st_max_limits[1] = val;
+	if (of_get_property(np, "st,max-limit-z", &val))
+		pdata->st_max_limits[2] = val;
+
+
+	lis3->pdata = pdata;
+
+	return 0;
+}
+
+#else
+int lis3lv02d_init_dt(struct lis3lv02d *lis3)
+{
+	return 0;
+}
+#endif
+EXPORT_SYMBOL_GPL(lis3lv02d_init_dt);
+
 /*
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
@@ -956,6 +1136,16 @@
 		lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
 		lis3->scale = LIS3_SENSITIVITY_8B;
 		break;
+	case WAI_3DLH:
+		pr_info("16 bits lis331dlh sensor found\n");
+		lis3->read_data = lis331dlh_read_data;
+		lis3->mdps_max_val = 2048; /* 12 bits for 2G */
+		lis3->shift_adj = SHIFT_ADJ_2G;
+		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+		lis3->odrs = lis3_3dlh_rates;
+		lis3->odr_mask = CTRL1_DR0 | CTRL1_DR1;
+		lis3->scale = LIS3DLH_SENSITIVITY_2G;
+		break;
 	default:
 		pr_err("unknown sensor type 0x%X\n", lis3->whoami);
 		return -EINVAL;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
index 2b1482a..c439c82 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.h
+++ b/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -26,12 +26,12 @@
 /*
  * This driver tries to support the "digital" accelerometer chips from
  * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
- * LIS35DE, or LIS202DL. They are very similar in terms of programming, with
- * almost the same registers. In addition to differing on physical properties,
- * they differ on the number of axes (2/3), precision (8/12 bits), and special
- * features (freefall detection, click...). Unfortunately, not all the
- * differences can be probed via a register.
- * They can be connected either via I²C or SPI.
+ * LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of
+ * programming, with almost the same registers. In addition to differing
+ * on physical properties, they differ on the number of axes (2/3),
+ * precision (8/12 bits), and special features (freefall detection,
+ * click...). Unfortunately, not all the differences can be probed via
+ * a register. They can be connected either via I²C or SPI.
  */
 
 #include <linux/lis3lv02d.h>
@@ -96,12 +96,22 @@
 };
 
 enum lis3_who_am_i {
+	WAI_3DLH	= 0x32,	/* 16 bits: LIS331DLH */
 	WAI_3DC		= 0x33,	/* 8 bits: LIS3DC, HP3DC */
 	WAI_12B		= 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
 	WAI_8B		= 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
 	WAI_6B		= 0x52, /* 6 bits: LIS331DLF - not supported */
 };
 
+enum lis3_type {
+	LIS3LV02D,
+	LIS3DC,
+	HP3DC,
+	LIS2302D,
+	LIS331DLF,
+	LIS331DLH,
+};
+
 enum lis3lv02d_ctrl1_12b {
 	CTRL1_Xen	= 0x01,
 	CTRL1_Yen	= 0x02,
@@ -129,6 +139,27 @@
 	CTRL1_ODR3	= 0x80,
 };
 
+enum lis331dlh_ctrl1 {
+	CTRL1_DR0	= 0x08,
+	CTRL1_DR1	= 0x10,
+	CTRL1_PM0	= 0x20,
+	CTRL1_PM1	= 0x40,
+	CTRL1_PM2	= 0x80,
+};
+
+enum lis331dlh_ctrl2 {
+	CTRL2_HPEN1	= 0x04,
+	CTRL2_HPEN2	= 0x08,
+	CTRL2_FDS_3DLH	= 0x10,
+	CTRL2_BOOT_3DLH	= 0x80,
+};
+
+enum lis331dlh_ctrl4 {
+	CTRL4_STSIGN	= 0x08,
+	CTRL4_BLE	= 0x40,
+	CTRL4_BDU	= 0x80,
+};
+
 enum lis3lv02d_ctrl2 {
 	CTRL2_DAS	= 0x01,
 	CTRL2_SIM	= 0x02,
@@ -279,9 +310,14 @@
 	int                     data_ready_count[2];
 	atomic_t		wake_thread;
 	unsigned char           irq_cfg;
+	unsigned int		shift_adj;
 
 	struct lis3lv02d_platform_data *pdata;	/* for passing board config */
 	struct mutex		mutex;     /* Serialize poll and selftest */
+
+#ifdef CONFIG_OF
+	struct device_node	*of_node;
+#endif
 };
 
 int lis3lv02d_init_device(struct lis3lv02d *lis3);
@@ -290,5 +326,6 @@
 void lis3lv02d_poweroff(struct lis3lv02d *lis3);
 int lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
+int lis3lv02d_init_dt(struct lis3lv02d *lis3);
 
 extern struct lis3lv02d lis3_dev;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index e8c0019..60ec868 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -31,6 +31,10 @@
 #include <linux/i2c.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+
 #include "lis3lv02d.h"
 
 #define DRV_NAME	"lis3lv02d_i2c"
@@ -90,7 +94,11 @@
 	if (ret < 0)
 		return ret;
 
-	reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+	if (lis3->whoami == WAI_3DLH)
+		reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+	else
+		reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+
 	return lis3->write(lis3, CTRL_REG1, reg);
 }
 
@@ -98,12 +106,30 @@
 static union axis_conversion lis3lv02d_axis_map =
 	{ .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
 
+#ifdef CONFIG_OF
+static struct of_device_id lis3lv02d_i2c_dt_ids[] = {
+	{ .compatible = "st,lis3lv02d" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids);
+#endif
+
 static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
 	int ret = 0;
 	struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
 
+#ifdef CONFIG_OF
+	if (of_match_device(lis3lv02d_i2c_dt_ids, &client->dev)) {
+		lis3_dev.of_node = client->dev.of_node;
+		ret = lis3lv02d_init_dt(&lis3_dev);
+		if (ret)
+			return ret;
+		pdata = lis3_dev.pdata;
+	}
+#endif
+
 	if (pdata) {
 		if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
 			(i2c_check_functionality(client->adapter,
@@ -231,7 +257,8 @@
 #endif /* CONFIG_PM_RUNTIME */
 
 static const struct i2c_device_id lis3lv02d_id[] = {
-	{"lis3lv02d", 0 },
+	{"lis3lv02d", LIS3LV02D},
+	{"lis331dlh", LIS331DLH},
 	{}
 };
 
@@ -250,6 +277,7 @@
 		.name   = DRV_NAME,
 		.owner  = THIS_MODULE,
 		.pm     = &lis3_pm_ops,
+		.of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids),
 	},
 	.probe	= lis3lv02d_i2c_probe,
 	.remove	= __devexit_p(lis3lv02d_i2c_remove),
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index 80880e9..ccb6475f 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -17,6 +17,9 @@
 #include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
 
 #include "lis3lv02d.h"
 
@@ -58,6 +61,14 @@
 static union axis_conversion lis3lv02d_axis_normal =
 	{ .as_array = { 1, 2, 3 } };
 
+#ifdef CONFIG_OF
+static struct of_device_id lis302dl_spi_dt_ids[] = {
+	{ .compatible = "st,lis302dl-spi" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids);
+#endif
+
 static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 {
 	int ret;
@@ -75,6 +86,15 @@
 	lis3_dev.irq		= spi->irq;
 	lis3_dev.ac		= lis3lv02d_axis_normal;
 	lis3_dev.pdata		= spi->dev.platform_data;
+
+#ifdef CONFIG_OF
+	if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) {
+		lis3_dev.of_node = spi->dev.of_node;
+		ret = lis3lv02d_init_dt(&lis3_dev);
+		if (ret)
+			return ret;
+	}
+#endif
 	spi_set_drvdata(spi, &lis3_dev);
 
 	return lis3lv02d_init_device(&lis3_dev);
@@ -121,6 +141,7 @@
 		.name   = DRV_NAME,
 		.owner  = THIS_MODULE,
 		.pm	= &lis3lv02d_spi_pm,
+		.of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
 	},
 	.probe	= lis302dl_spi_probe,
 	.remove	= __devexit_p(lis302dl_spi_remove),
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 47d78a7..5a79ccd 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -1,6 +1,6 @@
 config INTEL_MEI
 	tristate "Intel Management Engine Interface (Intel MEI)"
-	depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
+	depends on X86 && PCI && WATCHDOG_CORE
 	help
 	  The Intel Management Engine (Intel ME) provides Manageability,
 	  Security and Media services for system containing Intel chipsets.
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 24c4c96..9700532 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -40,47 +40,48 @@
 /*
  * MEI device IDs
  */
-#define    MEI_DEV_ID_82946GZ	0x2974  /* 82946GZ/GL */
-#define    MEI_DEV_ID_82G35	0x2984  /* 82G35 Express */
-#define    MEI_DEV_ID_82Q965	0x2994  /* 82Q963/Q965 */
-#define    MEI_DEV_ID_82G965	0x29A4  /* 82P965/G965 */
+#define MEI_DEV_ID_82946GZ    0x2974  /* 82946GZ/GL */
+#define MEI_DEV_ID_82G35      0x2984  /* 82G35 Express */
+#define MEI_DEV_ID_82Q965     0x2994  /* 82Q963/Q965 */
+#define MEI_DEV_ID_82G965     0x29A4  /* 82P965/G965 */
 
-#define    MEI_DEV_ID_82GM965	0x2A04  /* Mobile PM965/GM965 */
-#define    MEI_DEV_ID_82GME965	0x2A14  /* Mobile GME965/GLE960 */
+#define MEI_DEV_ID_82GM965    0x2A04  /* Mobile PM965/GM965 */
+#define MEI_DEV_ID_82GME965   0x2A14  /* Mobile GME965/GLE960 */
 
-#define    MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
-#define    MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
-#define    MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
-#define    MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
-#define    MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
+#define MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
+#define MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
+#define MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
+#define MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
+#define MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
 
-#define    MEI_DEV_ID_ICH9_6	0x28B4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_7	0x28C4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_8	0x28D4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_9    0x28E4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_10	0x28F4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_6     0x28B4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_7     0x28C4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_8     0x28D4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_9     0x28E4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_10    0x28F4  /* Bearlake */
 
-#define    MEI_DEV_ID_ICH9M_1	0x2A44  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_2	0x2A54  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_3	0x2A64  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_4	0x2A74  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_1    0x2A44  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_2    0x2A54  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_3    0x2A64  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_4    0x2A74  /* Cantiga */
 
-#define    MEI_DEV_ID_ICH10_1	0x2E04  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_2	0x2E14  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_3	0x2E24  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_4	0x2E34  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_1    0x2E04  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_2    0x2E14  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_3    0x2E24  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_4    0x2E34  /* Eaglelake */
 
-#define    MEI_DEV_ID_IBXPK_1	0x3B64  /* Calpella */
-#define    MEI_DEV_ID_IBXPK_2	0x3B65  /* Calpella */
+#define MEI_DEV_ID_IBXPK_1    0x3B64  /* Calpella */
+#define MEI_DEV_ID_IBXPK_2    0x3B65  /* Calpella */
 
-#define    MEI_DEV_ID_CPT_1	0x1C3A    /* Cougerpoint */
-#define    MEI_DEV_ID_PBG_1	0x1D3A    /* PBG */
+#define MEI_DEV_ID_CPT_1      0x1C3A  /* Couger Point */
+#define MEI_DEV_ID_PBG_1      0x1D3A  /* C600/X79 Patsburg */
 
-#define    MEI_DEV_ID_PPT_1	0x1E3A    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_2	0x1CBA    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_3	0x1DBA    /* Pantherpoint PPT */
+#define MEI_DEV_ID_PPT_1      0x1E3A  /* Panther Point */
+#define MEI_DEV_ID_PPT_2      0x1CBA  /* Panther Point */
+#define MEI_DEV_ID_PPT_3      0x1DBA  /* Panther Point */
 
-
+#define MEI_DEV_ID_LPT        0x8C3A  /* Lynx Point */
+#define MEI_DEV_ID_LPT_LP     0x9C3A  /* Lynx Point LP */
 /*
  * MEI HW Section
  */
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index e77f86e..98f1430 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -24,6 +24,25 @@
 #include "interface.h"
 #include <linux/mei.h>
 
+const char *mei_dev_state_str(int state)
+{
+#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
+	switch (state) {
+	MEI_DEV_STATE(INITIALIZING);
+	MEI_DEV_STATE(INIT_CLIENTS);
+	MEI_DEV_STATE(ENABLED);
+	MEI_DEV_STATE(RESETING);
+	MEI_DEV_STATE(DISABLED);
+	MEI_DEV_STATE(RECOVERING_FROM_RESET);
+	MEI_DEV_STATE(POWER_DOWN);
+	MEI_DEV_STATE(POWER_UP);
+	default:
+		return "unkown";
+	}
+#undef MEI_DEV_STATE
+}
+
+
 const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
 						0xa8, 0x46, 0xe0, 0xff, 0x65,
 						0x81, 0x4c);
@@ -123,7 +142,7 @@
 	mutex_init(&dev->device_lock);
 	init_waitqueue_head(&dev->wait_recvd_msg);
 	init_waitqueue_head(&dev->wait_stop_wd);
-	dev->mei_state = MEI_INITIALIZING;
+	dev->dev_state = MEI_DEV_INITIALIZING;
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 	dev->wd_interface_reg = false;
 
@@ -182,7 +201,7 @@
 	}
 
 	if (err <= 0 && !dev->recvd_msg) {
-		dev->mei_state = MEI_DISABLED;
+		dev->dev_state = MEI_DEV_DISABLED;
 		dev_dbg(&dev->pdev->dev,
 			"wait_event_interruptible_timeout failed"
 			"on wait for ME to turn on ME_RDY.\n");
@@ -192,7 +211,7 @@
 
 	if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
 	      ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
-		dev->mei_state = MEI_DISABLED;
+		dev->dev_state = MEI_DEV_DISABLED;
 		dev_dbg(&dev->pdev->dev,
 			"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 			dev->host_hw_state, dev->me_hw_state);
@@ -258,15 +277,15 @@
 	struct mei_cl_cb *cb_next = NULL;
 	bool unexpected;
 
-	if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+	if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
 		dev->need_reset = true;
 		return;
 	}
 
-	unexpected = (dev->mei_state != MEI_INITIALIZING &&
-			dev->mei_state != MEI_DISABLED &&
-			dev->mei_state != MEI_POWER_DOWN &&
-			dev->mei_state != MEI_POWER_UP);
+	unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
+			dev->dev_state != MEI_DEV_DISABLED &&
+			dev->dev_state != MEI_DEV_POWER_DOWN &&
+			dev->dev_state != MEI_DEV_POWER_UP);
 
 	dev->host_hw_state = mei_hcsr_read(dev);
 
@@ -285,10 +304,10 @@
 
 	dev->need_reset = false;
 
-	if (dev->mei_state != MEI_INITIALIZING) {
-		if (dev->mei_state != MEI_DISABLED &&
-		    dev->mei_state != MEI_POWER_DOWN)
-			dev->mei_state = MEI_RESETING;
+	if (dev->dev_state != MEI_DEV_INITIALIZING) {
+		if (dev->dev_state != MEI_DEV_DISABLED &&
+		    dev->dev_state != MEI_DEV_POWER_DOWN)
+			dev->dev_state = MEI_DEV_RESETING;
 
 		list_for_each_entry_safe(cl_pos,
 				cl_next, &dev->file_list, link) {
@@ -311,7 +330,6 @@
 
 	dev->me_clients_num = 0;
 	dev->rd_msg_hdr = 0;
-	dev->stop = false;
 	dev->wd_pending = false;
 
 	/* update the state of the registers after reset */
@@ -322,7 +340,8 @@
 	    dev->host_hw_state, dev->me_hw_state);
 
 	if (unexpected)
-		dev_warn(&dev->pdev->dev, "unexpected reset.\n");
+		dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
+			 mei_dev_state_str(dev->dev_state));
 
 	/* Wake up all readings so they can be interrupted */
 	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
@@ -371,7 +390,7 @@
 	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
 				       mei_hdr->length)) {
 		dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
-		dev->mei_state = MEI_RESETING;
+		dev->dev_state = MEI_DEV_RESETING;
 		mei_reset(dev, 1);
 	}
 	dev->init_clients_state = MEI_START_MESSAGE;
@@ -403,7 +422,7 @@
 	host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
 	if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
 				mei_hdr->length)) {
-		dev->mei_state = MEI_RESETING;
+		dev->dev_state = MEI_DEV_RESETING;
 		dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
 		mei_reset(dev, 1);
 	}
@@ -444,7 +463,7 @@
 			sizeof(struct mei_me_client), GFP_KERNEL);
 	if (!clients) {
 		dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
-		dev->mei_state = MEI_RESETING;
+		dev->dev_state = MEI_DEV_RESETING;
 		mei_reset(dev, 1);
 		return ;
 	}
@@ -490,7 +509,7 @@
 		if (mei_write_message(dev, mei_header,
 				(unsigned char *)host_cli_req,
 				mei_header->length)) {
-			dev->mei_state = MEI_RESETING;
+			dev->dev_state = MEI_DEV_RESETING;
 			dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
 			mei_reset(dev, 1);
 			return -EIO;
@@ -522,12 +541,12 @@
 	priv->dev = dev;
 }
 
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid)
 {
-	int i, res = -1;
+	int i, res = -ENOENT;
 
 	for (i = 0; i < dev->me_clients_num; ++i)
-		if (uuid_le_cmp(cuuid,
+		if (uuid_le_cmp(*cuuid,
 				dev->me_clients[i].props.protocol_name) == 0) {
 			res = i;
 			break;
@@ -538,35 +557,35 @@
 
 
 /**
- * mei_find_me_client_update_filext - searches for ME client guid
+ * mei_me_cl_update_filext - searches for ME client guid
  *                       sets client_id in mei_file_private if found
  * @dev: the device structure
- * @priv: private file structure to set client_id in
- * @cguid: searched guid of ME client
+ * @cl: private file structure to set client_id in
+ * @cuuid: searched uuid of ME client
  * @client_id: id of host client to be set in file private structure
  *
  * returns ME client index
  */
-u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
-				const uuid_le *cguid, u8 client_id)
+int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
+				const uuid_le *cuuid, u8 host_cl_id)
 {
 	int i;
 
-	if (!dev || !priv || !cguid)
-		return 0;
+	if (!dev || !cl || !cuuid)
+		return -EINVAL;
 
 	/* check for valid client id */
-	i = mei_find_me_client_index(dev, *cguid);
+	i = mei_me_cl_by_uuid(dev, cuuid);
 	if (i >= 0) {
-		priv->me_client_id = dev->me_clients[i].client_id;
-		priv->state = MEI_FILE_CONNECTING;
-		priv->host_client_id = client_id;
+		cl->me_client_id = dev->me_clients[i].client_id;
+		cl->state = MEI_FILE_CONNECTING;
+		cl->host_client_id = host_cl_id;
 
-		list_add_tail(&priv->link, &dev->file_list);
+		list_add_tail(&cl->link, &dev->file_list);
 		return (u8)i;
 	}
 
-	return 0;
+	return -ENOENT;
 }
 
 /**
@@ -577,16 +596,16 @@
  */
 void mei_host_init_iamthif(struct mei_device *dev)
 {
-	u8 i;
+	int i;
 	unsigned char *msg_buf;
 
 	mei_cl_init(&dev->iamthif_cl, dev);
 	dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
 
 	/* find ME amthi client */
-	i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
+	i = mei_me_cl_update_filext(dev, &dev->iamthif_cl,
 			    &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
-	if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
+	if (i < 0) {
 		dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
 		return;
 	}
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
index fb5c7db..ec6c785 100644
--- a/drivers/misc/mei/interface.h
+++ b/drivers/misc/mei/interface.h
@@ -23,14 +23,6 @@
 #include "mei_dev.h"
 
 
-#define AMT_WD_DEFAULT_TIMEOUT 120	/* seconds */
-#define AMT_WD_MIN_TIMEOUT 120	/* seconds */
-#define AMT_WD_MAX_TIMEOUT 65535	/* seconds */
-
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-
 
 void mei_read_slots(struct mei_device *dev,
 		     unsigned char *buffer,
@@ -64,7 +56,7 @@
 
 
 int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev, bool preserve);
+int mei_wd_stop(struct mei_device *dev);
 int mei_wd_host_init(struct mei_device *dev);
 /*
  * mei_watchdog_register  - Registering watchdog interface
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index d78c05e..3533edd 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -221,17 +221,10 @@
 				cl->status = 0;
 				list_del(&cb_pos->cb_list);
 				dev_dbg(&dev->pdev->dev,
-					"completed read host client = %d,"
-					"ME client = %d, "
-					"data length = %lu\n",
+					"completed read H cl = %d, ME cl = %d, length = %lu\n",
 					cl->host_client_id,
 					cl->me_client_id,
 					cb_pos->information);
-
-				*(cb_pos->response_buffer.data +
-					cb_pos->information) = '\0';
-				dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
-					cb_pos->response_buffer.data);
 				list_add_tail(&cb_pos->cb_list,
 					&complete_list->mei_cb.cb_list);
 			}
@@ -633,7 +626,7 @@
 		if (version_res->host_version_supported) {
 			dev->version.major_version = HBM_MAJOR_VERSION;
 			dev->version.minor_version = HBM_MINOR_VERSION;
-			if (dev->mei_state == MEI_INIT_CLIENTS &&
+			if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
 			    dev->init_clients_state == MEI_START_MESSAGE) {
 				dev->init_clients_timer = 0;
 				mei_host_enum_clients_message(dev);
@@ -707,7 +700,7 @@
 			dev->me_clients[dev->me_client_presentation_num].props
 						= props_res->client_properties;
 
-			if (dev->mei_state == MEI_INIT_CLIENTS &&
+			if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
 			    dev->init_clients_state ==
 					MEI_CLIENT_PROPERTIES_MESSAGE) {
 				dev->me_client_index++;
@@ -734,7 +727,7 @@
 					 * Client ID 2 - Reserved for AMTHI
 					 */
 					bitmap_set(dev->host_clients_map, 0, 3);
-					dev->mei_state = MEI_ENABLED;
+					dev->dev_state = MEI_DEV_ENABLED;
 
 					/* if wd initialization fails, initialization the AMTHI client,
 					 * otherwise the AMTHI client will be initialized after the WD client connect response
@@ -759,7 +752,7 @@
 	case HOST_ENUM_RES_CMD:
 		enum_res = (struct hbm_host_enum_response *) mei_msg;
 		memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
-		if (dev->mei_state == MEI_INIT_CLIENTS &&
+		if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
 		    dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
 				dev->init_clients_timer = 0;
 				dev->me_client_presentation_num = 0;
@@ -776,7 +769,7 @@
 		break;
 
 	case HOST_STOP_RES_CMD:
-		dev->mei_state = MEI_DISABLED;
+		dev->dev_state = MEI_DEV_DISABLED;
 		dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
 		mei_reset(dev, 1);
 		break;
@@ -1224,10 +1217,9 @@
 		}
 	}
 
-	if (dev->stop && !dev->wd_pending) {
-		dev->wd_stopped = true;
+	if (dev->wd_state == MEI_WD_STOPPING) {
+		dev->wd_state = MEI_WD_IDLE;
 		wake_up_interruptible(&dev->wait_stop_wd);
-		return 0;
 	}
 
 	if (dev->extra_write_index) {
@@ -1240,7 +1232,7 @@
 		*slots -= dev->extra_write_index;
 		dev->extra_write_index = 0;
 	}
-	if (dev->mei_state == MEI_ENABLED) {
+	if (dev->dev_state == MEI_DEV_ENABLED) {
 		if (dev->wd_pending &&
 		    mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
 			if (mei_wd_send(dev))
@@ -1250,14 +1242,12 @@
 
 			dev->wd_pending = false;
 
-			if (dev->wd_timeout)
-				*slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
+			if (dev->wd_state == MEI_WD_RUNNING)
+				*slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
 			else
-				*slots -= mei_data2slots(MEI_WD_PARAMS_SIZE);
+				*slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
 		}
 	}
-	if (dev->stop)
-		return -ENODEV;
 
 	/* complete control write list CB */
 	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
@@ -1361,8 +1351,8 @@
 
 
 	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
-		if (dev->mei_state == MEI_INIT_CLIENTS) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
+		if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
 			if (dev->init_clients_timer) {
 				if (--dev->init_clients_timer == 0) {
 					dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
@@ -1484,8 +1474,8 @@
 
 	/* check if ME wants a reset */
 	if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
-	    dev->mei_state != MEI_RESETING &&
-	    dev->mei_state != MEI_INITIALIZING) {
+	    dev->dev_state != MEI_DEV_RESETING &&
+	    dev->dev_state != MEI_DEV_INITIALIZING) {
 		dev_dbg(&dev->pdev->dev, "FW not ready.\n");
 		mei_reset(dev, 1);
 		mutex_unlock(&dev->device_lock);
@@ -1498,7 +1488,7 @@
 			dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
 			dev->host_hw_state |= (H_IE | H_IG | H_RDY);
 			mei_hcsr_set(dev);
-			dev->mei_state = MEI_INIT_CLIENTS;
+			dev->dev_state = MEI_DEV_INIT_CLIENTS;
 			dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
 			/* link is established
 			 * start sending messages.
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c
index 50f52e2..fcba98e 100644
--- a/drivers/misc/mei/iorw.c
+++ b/drivers/misc/mei/iorw.c
@@ -38,7 +38,31 @@
 #include <linux/mei.h>
 #include "interface.h"
 
+/**
+ * mei_me_cl_by_id return index to me_clients for client_id
+ *
+ * @dev: the device structure
+ * @client_id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns index on success, -ENOENT on failure.
+ */
 
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
+{
+	int i;
+	for (i = 0; i < dev->me_clients_num; i++)
+		if (dev->me_clients[i].client_id == client_id)
+			break;
+	if (WARN_ON(dev->me_clients[i].client_id != client_id))
+		return -ENOENT;
+
+	if (i == dev->me_clients_num)
+		return -ENOENT;
+
+	return i;
+}
 
 /**
  * mei_ioctl_connect_client - the connect to fw client IOCTL function
@@ -84,7 +108,7 @@
 
 	cb->major_file_operations = MEI_IOCTL;
 
-	if (dev->mei_state != MEI_ENABLED) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
 		rets = -ENODEV;
 		goto end;
 	}
@@ -95,7 +119,7 @@
 	}
 
 	/* find ME client we're trying to connect to */
-	i = mei_find_me_client_index(dev, data->in_client_uuid);
+	i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
 	if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
 		cl->me_client_id = dev->me_clients[i].client_id;
 		cl->state = MEI_FILE_CONNECTING;
@@ -273,19 +297,12 @@
 		return -ETIMEDOUT;
 	}
 
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id ==
-		    dev->iamthif_cl.me_client_id)
-			break;
-	}
+	i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
 
-	if (i == dev->me_clients_num) {
+	if (i < 0) {
 		dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
 		return -ENODEV;
 	}
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
-		return -ENODEV;
-
 	dev_dbg(&dev->pdev->dev, "checking amthi data\n");
 	cb = find_amthi_read_list_entry(dev, file);
 
@@ -316,8 +333,7 @@
 	dev->iamthif_timer = 0;
 
 	if (cb) {
-		timeout = cb->read_time +
-					msecs_to_jiffies(IAMTHIF_READ_TIMER);
+		timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER);
 		dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
 				timeout);
 
@@ -386,7 +402,7 @@
 	if (cl->state != MEI_FILE_CONNECTED)
 		return -ENODEV;
 
-	if (dev->mei_state != MEI_ENABLED)
+	if (dev->dev_state != MEI_DEV_ENABLED)
 		return -ENODEV;
 
 	dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
@@ -401,19 +417,8 @@
 
 	dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
 		cl->host_client_id, cl->me_client_id);
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id == cl->me_client_id)
-			break;
-
-	}
-
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-		rets = -ENODEV;
-		goto unlock;
-	}
-
-	if (i == dev->me_clients_num) {
+	i = mei_me_cl_by_id(dev, cl->me_client_id);
+	if (i < 0) {
 		rets = -ENODEV;
 		goto unlock;
 	}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 7422c76..e8b0858 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -41,11 +41,8 @@
 #include <linux/mei.h>
 #include "interface.h"
 
-static const char mei_driver_name[] = "mei";
-
-/* The device pointer */
-/* Currently this driver works as long as there is only a single AMT device. */
-struct pci_dev *mei_device;
+/* AMT device is a singleton on the platform */
+static struct pci_dev *mei_pdev;
 
 /* mei_pci_tbl - PCI Device ID Table */
 static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
@@ -80,6 +77,8 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
 
 	/* required last entry */
 	{0, }
@@ -220,10 +219,10 @@
 	int err;
 
 	err = -ENODEV;
-	if (!mei_device)
+	if (!mei_pdev)
 		goto out;
 
-	dev = pci_get_drvdata(mei_device);
+	dev = pci_get_drvdata(mei_pdev);
 	if (!dev)
 		goto out;
 
@@ -234,18 +233,24 @@
 		goto out_unlock;
 
 	err = -ENODEV;
-	if (dev->mei_state != MEI_ENABLED) {
-		dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
-		    dev->mei_state);
+	if (dev->dev_state != MEI_DEV_ENABLED) {
+		dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
+		    mei_dev_state_str(dev->dev_state));
 		goto out_unlock;
 	}
 	err = -EMFILE;
-	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
+	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
+		dev_err(&dev->pdev->dev, "open_handle_count exceded %d",
+			MEI_MAX_OPEN_HANDLE_COUNT);
 		goto out_unlock;
+	}
 
 	cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
-	if (cl_id >= MEI_CLIENTS_MAX)
+	if (cl_id >= MEI_CLIENTS_MAX) {
+		dev_err(&dev->pdev->dev, "client_id exceded %d",
+				MEI_CLIENTS_MAX) ;
 		goto out_unlock;
+	}
 
 	cl->host_client_id  = cl_id;
 
@@ -386,17 +391,16 @@
 	dev = cl->dev;
 
 	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
 		rets = -ENODEV;
 		goto out;
 	}
 
 	if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
 		/* Do not allow to read watchdog client */
-		i = mei_find_me_client_index(dev, mei_wd_guid);
+		i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
 		if (i >= 0) {
 			struct mei_me_client *me_client = &dev->me_clients[i];
-
 			if (cl->me_client_id == me_client->client_id) {
 				rets = -EBADF;
 				goto out;
@@ -541,7 +545,7 @@
 
 	mutex_lock(&dev->device_lock);
 
-	if (dev->mei_state != MEI_ENABLED) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
 		mutex_unlock(&dev->device_lock);
 		return -ENODEV;
 	}
@@ -616,26 +620,16 @@
 			rets = -ENOMEM;
 			goto unlock_dev;
 		}
-		if (dev->mei_state != MEI_ENABLED) {
+		if (dev->dev_state != MEI_DEV_ENABLED) {
 			rets = -ENODEV;
 			goto unlock_dev;
 		}
-		for (i = 0; i < dev->me_clients_num; i++) {
-			if (dev->me_clients[i].client_id ==
-				dev->iamthif_cl.me_client_id)
-				break;
-		}
-
-		if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+		i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
+		if (i < 0) {
 			rets = -ENODEV;
 			goto unlock_dev;
 		}
-		if (i == dev->me_clients_num ||
-		    (dev->me_clients[i].client_id !=
-		      dev->iamthif_cl.me_client_id)) {
-			rets = -ENODEV;
-			goto unlock_dev;
-		} else if (length > dev->me_clients[i].props.max_msg_length ||
+		if (length > dev->me_clients[i].props.max_msg_length ||
 			   length <= 0) {
 			rets = -EMSGSIZE;
 			goto unlock_dev;
@@ -688,16 +682,8 @@
 		    cl->me_client_id);
 		goto unlock_dev;
 	}
-	for (i = 0; i < dev->me_clients_num; i++) {
-		if (dev->me_clients[i].client_id ==
-		    cl->me_client_id)
-			break;
-	}
-	if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-		rets = -ENODEV;
-		goto unlock_dev;
-	}
-	if (i == dev->me_clients_num) {
+	i = mei_me_cl_by_id(dev, cl->me_client_id);
+	if (i < 0) {
 		rets = -ENODEV;
 		goto unlock_dev;
 	}
@@ -790,7 +776,7 @@
 	dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
 
 	mutex_lock(&dev->device_lock);
-	if (dev->mei_state != MEI_ENABLED) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
 		rets = -ENODEV;
 		goto out;
 	}
@@ -869,7 +855,7 @@
 
 	mutex_lock(&dev->device_lock);
 
-	if (dev->mei_state != MEI_ENABLED)
+	if (dev->dev_state != MEI_DEV_ENABLED)
 		goto out;
 
 
@@ -966,7 +952,7 @@
 		goto end;
 	}
 
-	if (mei_device) {
+	if (mei_pdev) {
 		err = -EEXIST;
 		goto end;
 	}
@@ -979,7 +965,7 @@
 	/* set PCI host mastering  */
 	pci_set_master(pdev);
 	/* pci request regions for mei driver */
-	err = pci_request_regions(pdev, mei_driver_name);
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
 	if (err) {
 		dev_err(&pdev->dev, "failed to get pci regions.\n");
 		goto disable_device;
@@ -1004,12 +990,12 @@
 		err = request_threaded_irq(pdev->irq,
 			NULL,
 			mei_interrupt_thread_handler,
-			IRQF_ONESHOT, mei_driver_name, dev);
+			IRQF_ONESHOT, KBUILD_MODNAME, dev);
 	else
 		err = request_threaded_irq(pdev->irq,
 			mei_interrupt_quick_handler,
 			mei_interrupt_thread_handler,
-			IRQF_SHARED, mei_driver_name, dev);
+			IRQF_SHARED, KBUILD_MODNAME, dev);
 
 	if (err) {
 		dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
@@ -1027,7 +1013,7 @@
 	if (err)
 		goto release_irq;
 
-	mei_device = pdev;
+	mei_pdev = pdev;
 	pci_set_drvdata(pdev, dev);
 
 
@@ -1072,7 +1058,7 @@
 {
 	struct mei_device *dev;
 
-	if (mei_device != pdev)
+	if (mei_pdev != pdev)
 		return;
 
 	dev = pci_get_drvdata(pdev);
@@ -1081,9 +1067,11 @@
 
 	mutex_lock(&dev->device_lock);
 
-	mei_wd_stop(dev, false);
+	cancel_delayed_work(&dev->timer_work);
 
-	mei_device = NULL;
+	mei_wd_stop(dev);
+
+	mei_pdev = NULL;
 
 	if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
 		dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
@@ -1136,12 +1124,15 @@
 	if (!dev)
 		return -ENODEV;
 	mutex_lock(&dev->device_lock);
+
+	cancel_delayed_work(&dev->timer_work);
+
 	/* Stop watchdog if exists */
-	err = mei_wd_stop(dev, true);
+	err = mei_wd_stop(dev);
 	/* Set new mei state */
-	if (dev->mei_state == MEI_ENABLED ||
-	    dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-		dev->mei_state = MEI_POWER_DOWN;
+	if (dev->dev_state == MEI_DEV_ENABLED ||
+	    dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
+		dev->dev_state = MEI_DEV_POWER_DOWN;
 		mei_reset(dev, 0);
 	}
 	mutex_unlock(&dev->device_lock);
@@ -1169,12 +1160,12 @@
 		err = request_threaded_irq(pdev->irq,
 			NULL,
 			mei_interrupt_thread_handler,
-			IRQF_ONESHOT, mei_driver_name, dev);
+			IRQF_ONESHOT, KBUILD_MODNAME, dev);
 	else
 		err = request_threaded_irq(pdev->irq,
 			mei_interrupt_quick_handler,
 			mei_interrupt_thread_handler,
-			IRQF_SHARED, mei_driver_name, dev);
+			IRQF_SHARED, KBUILD_MODNAME, dev);
 
 	if (err) {
 		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
@@ -1183,7 +1174,7 @@
 	}
 
 	mutex_lock(&dev->device_lock);
-	dev->mei_state = MEI_POWER_UP;
+	dev->dev_state = MEI_DEV_POWER_UP;
 	mei_reset(dev, 1);
 	mutex_unlock(&dev->device_lock);
 
@@ -1201,7 +1192,7 @@
  *  PCI driver structure
  */
 static struct pci_driver mei_driver = {
-	.name = mei_driver_name,
+	.name = KBUILD_MODNAME,
 	.id_table = mei_pci_tbl,
 	.probe = mei_probe,
 	.remove = __devexit_p(mei_remove),
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d61c4dd..adb35fb 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -25,18 +25,20 @@
 /*
  * watch dog definition
  */
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
+#define MEI_WD_HDR_SIZE       4
+#define MEI_WD_STOP_MSG_SIZE  MEI_WD_HDR_SIZE
+#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16)
+
+#define MEI_WD_DEFAULT_TIMEOUT   120  /* seconds */
+#define MEI_WD_MIN_TIMEOUT       120  /* seconds */
+#define MEI_WD_MAX_TIMEOUT     65535  /* seconds */
+
+#define MEI_WD_STOP_TIMEOUT      10 /* msecs */
+
 #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
 
 #define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
 
-/*
- * MEI PCI Device object
- */
-extern struct pci_dev *mei_device;
-
 
 /*
  * AMTHI Client UUID
@@ -54,19 +56,21 @@
 extern const u8 mei_wd_state_independence_msg[3][4];
 
 /*
+ * Number of Maximum MEI Clients
+ */
+#define MEI_CLIENTS_MAX 256
+
+/*
  * Number of File descriptors/handles
  * that can be opened to the driver.
  *
- * Limit to 253: 255 Total Clients
+ * Limit to 253: 256 Total Clients
+ * minus internal client for MEI Bus Messags
  * minus internal client for AMTHI
  * minus internal client for Watchdog
  */
-#define  MEI_MAX_OPEN_HANDLE_COUNT	253
+#define  MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 3)
 
-/*
- * Number of Maximum MEI Clients
- */
-#define MEI_CLIENTS_MAX 255
 
 /* File state */
 enum file_state {
@@ -78,17 +82,19 @@
 };
 
 /* MEI device states */
-enum mei_states {
-	MEI_INITIALIZING = 0,
-	MEI_INIT_CLIENTS,
-	MEI_ENABLED,
-	MEI_RESETING,
-	MEI_DISABLED,
-	MEI_RECOVERING_FROM_RESET,
-	MEI_POWER_DOWN,
-	MEI_POWER_UP
+enum mei_dev_state {
+	MEI_DEV_INITIALIZING = 0,
+	MEI_DEV_INIT_CLIENTS,
+	MEI_DEV_ENABLED,
+	MEI_DEV_RESETING,
+	MEI_DEV_DISABLED,
+	MEI_DEV_RECOVERING_FROM_RESET,
+	MEI_DEV_POWER_DOWN,
+	MEI_DEV_POWER_UP
 };
 
+const char *mei_dev_state_str(int state);
+
 /* init clients states*/
 enum mei_init_clients_states {
 	MEI_START_MESSAGE = 0,
@@ -113,6 +119,12 @@
 	MEI_READ_COMPLETE
 };
 
+enum mei_wd_states {
+	MEI_WD_IDLE,
+	MEI_WD_RUNNING,
+	MEI_WD_STOPPING,
+};
+
 /* MEI CB */
 enum mei_cb_major_types {
 	MEI_READ = 0,
@@ -128,7 +140,7 @@
 struct mei_message_data {
 	u32 size;
 	unsigned char *data;
-} __packed;
+};
 
 
 struct mei_cl_cb {
@@ -218,10 +230,9 @@
 	/*
 	 * mei device  states
 	 */
-	enum mei_states mei_state;
+	enum mei_dev_state dev_state;
 	enum mei_init_clients_states init_clients_state;
 	u16 init_clients_timer;
-	bool stop;
 	bool need_reset;
 
 	u32 extra_write_index;
@@ -241,12 +252,11 @@
 	bool mei_host_buffer_is_empty;
 
 	struct mei_cl wd_cl;
+	enum mei_wd_states wd_state;
 	bool wd_interface_reg;
 	bool wd_pending;
-	bool wd_stopped;
-	bool wd_bypass;	/* if false, don't refresh watchdog ME client */
-	u16 wd_timeout;	/* seconds ((wd_data[1] << 8) + wd_data[0]) */
-	unsigned char wd_data[MEI_START_WD_DATA_SIZE];
+	u16 wd_timeout;
+	unsigned char wd_data[MEI_WD_START_MSG_SIZE];
 
 
 	struct file *iamthif_file_object;
@@ -279,9 +289,10 @@
 void mei_allocate_me_clients_storage(struct mei_device *dev);
 
 
-u8 mei_find_me_client_update_filext(struct mei_device *dev,
-				struct mei_cl *priv,
-				const uuid_le *cguid, u8 client_id);
+int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
+			const uuid_le *cguid, u8 host_client_id);
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
 
 /*
  * MEI IO List Functions
@@ -348,7 +359,6 @@
 
 void mei_free_cb_private(struct mei_cl_cb *priv_cb);
 
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
 
 /*
  * Register Access Function
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 5133fd7..d96c537 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -48,8 +48,8 @@
 static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
 {
 	dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
-	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
-	memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
+	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
+	memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
 }
 
 /**
@@ -66,10 +66,11 @@
 
 	/* look for WD client and connect to it */
 	dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-	dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
+	dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
+	dev->wd_state = MEI_WD_IDLE;
 
 	/* find ME WD client */
-	mei_find_me_client_update_filext(dev, &dev->wd_cl,
+	mei_me_cl_update_filext(dev, &dev->wd_cl,
 				&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
 
 	dev_dbg(&dev->pdev->dev, "wd: check client\n");
@@ -108,10 +109,10 @@
 	mei_hdr->msg_complete = 1;
 	mei_hdr->reserved = 0;
 
-	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
-		mei_hdr->length = MEI_START_WD_DATA_SIZE;
-	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
-		mei_hdr->length = MEI_WD_PARAMS_SIZE;
+	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
+		mei_hdr->length = MEI_WD_START_MSG_SIZE;
+	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
+		mei_hdr->length = MEI_WD_STOP_MSG_SIZE;
 	else
 		return -EINVAL;
 
@@ -128,18 +129,17 @@
  *	-EIO when message send fails
  *	-EINVAL when invalid message is to be sent
  */
-int mei_wd_stop(struct mei_device *dev, bool preserve)
+int mei_wd_stop(struct mei_device *dev)
 {
 	int ret;
-	u16 wd_timeout = dev->wd_timeout;
 
-	cancel_delayed_work(&dev->timer_work);
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
+	if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
+	    dev->wd_state != MEI_WD_RUNNING)
 		return 0;
 
-	dev->wd_timeout = 0;
-	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
-	dev->stop = true;
+	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
+
+	dev->wd_state = MEI_WD_STOPPING;
 
 	ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
 	if (ret < 0)
@@ -161,13 +161,14 @@
 	} else {
 		dev->wd_pending = true;
 	}
-	dev->wd_stopped = false;
+
 	mutex_unlock(&dev->device_lock);
 
 	ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-					dev->wd_stopped, 10 * HZ);
+					dev->wd_state == MEI_WD_IDLE,
+					msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
 	mutex_lock(&dev->device_lock);
-	if (dev->wd_stopped) {
+	if (dev->wd_state == MEI_WD_IDLE) {
 		dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
 		ret = 0;
 	} else {
@@ -177,9 +178,6 @@
 			"wd: stop failed to complete ret=%d.\n", ret);
 	}
 
-	if (preserve)
-		dev->wd_timeout = wd_timeout;
-
 out:
 	return ret;
 }
@@ -196,16 +194,16 @@
 	int err = -ENODEV;
 	struct mei_device *dev;
 
-	dev = pci_get_drvdata(mei_device);
+	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
 		return -ENODEV;
 
 	mutex_lock(&dev->device_lock);
 
-	if (dev->mei_state != MEI_ENABLED) {
+	if (dev->dev_state != MEI_DEV_ENABLED) {
 		dev_dbg(&dev->pdev->dev,
-			"wd: mei_state != MEI_ENABLED  mei_state = %d\n",
-			dev->mei_state);
+			"wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
+			mei_dev_state_str(dev->dev_state));
 		goto end_unlock;
 	}
 
@@ -233,13 +231,13 @@
 static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
 {
 	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
 
+	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
 		return -ENODEV;
 
 	mutex_lock(&dev->device_lock);
-	mei_wd_stop(dev, false);
+	mei_wd_stop(dev);
 	mutex_unlock(&dev->device_lock);
 
 	return 0;
@@ -256,8 +254,8 @@
 {
 	int ret = 0;
 	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
 
+	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
 		return -ENODEV;
 
@@ -269,6 +267,8 @@
 		goto end;
 	}
 
+	dev->wd_state = MEI_WD_RUNNING;
+
 	/* Check if we can send the ping to HW*/
 	if (dev->mei_host_buffer_is_empty &&
 		mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
@@ -309,13 +309,13 @@
 static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
 {
 	struct mei_device *dev;
-	dev = pci_get_drvdata(mei_device);
 
+	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
 		return -ENODEV;
 
 	/* Check Timeout value */
-	if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
+	if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
 		return -EINVAL;
 
 	mutex_lock(&dev->device_lock);
@@ -341,37 +341,42 @@
 };
 static const struct watchdog_info wd_info = {
 		.identity = INTEL_AMT_WATCHDOG_ID,
-		.options = WDIOF_KEEPALIVEPING | WDIOF_ALARMONLY,
+		.options = WDIOF_KEEPALIVEPING |
+			   WDIOF_SETTIMEOUT |
+			   WDIOF_ALARMONLY,
 };
 
 static struct watchdog_device amt_wd_dev = {
 		.info = &wd_info,
 		.ops = &wd_ops,
-		.timeout = AMT_WD_DEFAULT_TIMEOUT,
-		.min_timeout = AMT_WD_MIN_TIMEOUT,
-		.max_timeout = AMT_WD_MAX_TIMEOUT,
+		.timeout = MEI_WD_DEFAULT_TIMEOUT,
+		.min_timeout = MEI_WD_MIN_TIMEOUT,
+		.max_timeout = MEI_WD_MAX_TIMEOUT,
 };
 
 
-void  mei_watchdog_register(struct mei_device *dev)
+void mei_watchdog_register(struct mei_device *dev)
 {
-	dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
-
 	if (watchdog_register_device(&amt_wd_dev)) {
 		dev_err(&dev->pdev->dev,
 			"wd: unable to register watchdog device.\n");
 		dev->wd_interface_reg = false;
-	} else {
-		dev_dbg(&dev->pdev->dev,
-			"wd: successfully register watchdog interface.\n");
-		dev->wd_interface_reg = true;
+		return;
 	}
+
+	dev_dbg(&dev->pdev->dev,
+		"wd: successfully register watchdog interface.\n");
+	dev->wd_interface_reg = true;
+	watchdog_set_drvdata(&amt_wd_dev, dev);
 }
 
 void mei_watchdog_unregister(struct mei_device *dev)
 {
-	if (dev->wd_interface_reg)
-		watchdog_unregister_device(&amt_wd_dev);
+	if (!dev->wd_interface_reg)
+		return;
+
+	watchdog_set_drvdata(&amt_wd_dev, NULL);
+	watchdog_unregister_device(&amt_wd_dev);
 	dev->wd_interface_reg = false;
 }
 
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 9fbcacd..c9f20da 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -699,7 +699,7 @@
 	chip->pch_phub_base_address = pci_iomap(pdev, 1, 0);
 
 
-	if (chip->pch_phub_base_address == 0) {
+	if (chip->pch_phub_base_address == NULL) {
 		dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
 		ret = -ENOMEM;
 		goto err_pci_iomap;
@@ -893,18 +893,7 @@
 	.resume = pch_phub_resume
 };
 
-static int __init pch_phub_pci_init(void)
-{
-	return pci_register_driver(&pch_phub_driver);
-}
-
-static void __exit pch_phub_pci_exit(void)
-{
-	pci_unregister_driver(&pch_phub_driver);
-}
-
-module_init(pch_phub_pci_init);
-module_exit(pch_phub_pci_exit);
+module_pci_driver(pch_phub_driver);
 
 MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB");
 MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index acfaeeb..46937b1 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -30,11 +30,13 @@
 
 #include <linux/ti_wilink_st.h>
 
+extern void st_kim_recv(void *, const unsigned char *, long);
+void st_int_recv(void *, const unsigned char *, long);
 /* function pointer pointing to either,
  * st_kim_recv during registration to receive fw download responses
  * st_int_recv after registration to receive proto stack responses
  */
-void (*st_recv) (void*, const unsigned char*, long);
+static void (*st_recv) (void *, const unsigned char *, long);
 
 /********************************************************************/
 static void add_channel_to_table(struct st_data_s *st_gdata,
@@ -100,7 +102,7 @@
  * push the skb received to relevant
  * protocol stacks
  */
-void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
+static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
 {
 	pr_debug(" %s(prot:%d) ", __func__, chnl_id);
 
@@ -140,7 +142,7 @@
  * This function is being called with spin lock held, protocol drivers are
  * only expected to complete their waits and do nothing more than that.
  */
-void st_reg_complete(struct st_data_s *st_gdata, char err)
+static void st_reg_complete(struct st_data_s *st_gdata, char err)
 {
 	unsigned char i = 0;
 	pr_info(" %s ", __func__);
@@ -379,7 +381,7 @@
  *	completely, return that skb which has the pending data.
  *	In normal cases, return top of txq.
  */
-struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
+static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
 {
 	struct sk_buff *returning_skb;
 
@@ -401,7 +403,7 @@
  *	txq and waitq needs protection since the other contexts
  *	may be sending data, waking up chip.
  */
-void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
+static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
 {
 	unsigned long flags = 0;
 
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 7c14f8f..04a8199 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -63,10 +63,27 @@
  *	in case of error don't complete so that waiting for proper
  *	response times out
  */
-void validate_firmware_response(struct kim_data_s *kim_gdata)
+static void validate_firmware_response(struct kim_data_s *kim_gdata)
 {
 	struct sk_buff *skb = kim_gdata->rx_skb;
-	if (unlikely(skb->data[5] != 0)) {
+	if (!skb)
+		return;
+
+	/* these magic numbers are the position in the response buffer which
+	 * allows us to distinguish whether the response is for the read
+	 * version info. command
+	 */
+	if (skb->data[2] == 0x01 && skb->data[3] == 0x01 &&
+			skb->data[4] == 0x10 && skb->data[5] == 0x00) {
+		/* fw version response */
+		memcpy(kim_gdata->resp_buffer,
+				kim_gdata->rx_skb->data,
+				kim_gdata->rx_skb->len);
+		complete_all(&kim_gdata->kim_rcvd);
+		kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+		kim_gdata->rx_skb = NULL;
+		kim_gdata->rx_count = 0;
+	} else if (unlikely(skb->data[5] != 0)) {
 		pr_err("no proper response during fw download");
 		pr_err("data6 %x", skb->data[5]);
 		kfree_skb(skb);
@@ -119,7 +136,7 @@
  *	have been observed to come in bursts of different
  *	tty_receive and hence the logic
  */
-void kim_int_recv(struct kim_data_s *kim_gdata,
+static void kim_int_recv(struct kim_data_s *kim_gdata,
 	const unsigned char *data, long count)
 {
 	const unsigned char *ptr;
@@ -207,16 +224,19 @@
 		return -EIO;
 	}
 
-	if (!wait_for_completion_timeout
-	    (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
+	if (!wait_for_completion_interruptible_timeout(
+		&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
 		pr_err(" waiting for ver info- timed out ");
 		return -ETIMEDOUT;
 	}
 	INIT_COMPLETION(kim_gdata->kim_rcvd);
+	/* the positions 12 & 13 in the response buffer provide with the
+	 * chip, major & minor numbers
+	 */
 
 	version =
-		MAKEWORD(kim_gdata->resp_buffer[13],
-				kim_gdata->resp_buffer[14]);
+		MAKEWORD(kim_gdata->resp_buffer[12],
+				kim_gdata->resp_buffer[13]);
 	chip = (version & 0x7C00) >> 10;
 	min_ver = (version & 0x007F);
 	maj_ver = (version & 0x0380) >> 7;
@@ -236,7 +256,7 @@
 	return 0;
 }
 
-void skip_change_remote_baud(unsigned char **ptr, long *len)
+static void skip_change_remote_baud(unsigned char **ptr, long *len)
 {
 	unsigned char *nxt_action, *cur_action;
 	cur_action = *ptr;
@@ -370,9 +390,9 @@
 			break;
 		case ACTION_WAIT_EVENT:  /* wait */
 			pr_debug("W");
-			if (!wait_for_completion_timeout
-					(&kim_gdata->kim_rcvd,
-					 msecs_to_jiffies(CMD_RESP_TIME))) {
+			if (!wait_for_completion_interruptible_timeout(
+					&kim_gdata->kim_rcvd,
+					msecs_to_jiffies(CMD_RESP_TIME))) {
 				pr_err("response timeout during fw download ");
 				/* timed out */
 				release_firmware(kim_gdata->fw_entry);
@@ -410,16 +430,10 @@
 	struct st_data_s	*st_gdata = (struct st_data_s *)disc_data;
 	struct kim_data_s	*kim_gdata = st_gdata->kim_data;
 
-	/* copy to local buffer */
-	if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
-		/* must be the read_ver_cmd */
-		memcpy(kim_gdata->resp_buffer, data, count);
-		complete_all(&kim_gdata->kim_rcvd);
-		return;
-	} else {
-		kim_int_recv(kim_gdata, data, count);
-		/* either completes or times out */
-	}
+	/* proceed to gather all data and distinguish read fw version response
+	 * from other fw responses when data gathering is complete
+	 */
+	kim_int_recv(kim_gdata, data, count);
 	return;
 }
 
@@ -454,11 +468,6 @@
 		if (pdata->chip_enable)
 			pdata->chip_enable(kim_gdata);
 
-		/* Configure BT nShutdown to HIGH state */
-		gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
-		mdelay(5);	/* FIXME: a proper toggle */
-		gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
-		mdelay(100);
 		/* re-initialize the completion */
 		INIT_COMPLETION(kim_gdata->ldisc_installed);
 		/* send notification to UIM */
@@ -467,8 +476,8 @@
 		sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
 				NULL, "install");
 		/* wait for ldisc to be installed */
-		err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
-				msecs_to_jiffies(LDISC_TIME));
+		err = wait_for_completion_interruptible_timeout(
+			&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
 		if (!err) {
 			/* ldisc installation timeout,
 			 * flush uart, power cycle BT_EN */
@@ -500,8 +509,7 @@
  *	(b) upon failure to either install ldisc or download firmware.
  *	The function is responsible to (a) notify UIM about un-installation,
  *	(b) flush UART if the ldisc was installed.
- *	(c) reset BT_EN - pull down nshutdown at the end.
- *	(d) invoke platform's chip disabling routine.
+ *	(c) invoke platform's chip disabling routine.
  */
 long st_kim_stop(void *kim_data)
 {
@@ -526,20 +534,13 @@
 	sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
 
 	/* wait for ldisc to be un-installed */
-	err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
-			msecs_to_jiffies(LDISC_TIME));
+	err = wait_for_completion_interruptible_timeout(
+		&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
 	if (!err) {		/* timeout */
 		pr_err(" timed out waiting for ldisc to be un-installed");
-		return -ETIMEDOUT;
+		err = -ETIMEDOUT;
 	}
 
-	/* By default configure BT nShutdown to LOW state */
-	gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
-	mdelay(1);
-	gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
-	mdelay(1);
-	gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
-
 	/* platform specific disable */
 	if (pdata->chip_disable)
 		pdata->chip_disable(kim_gdata);
@@ -701,7 +702,7 @@
  * board-*.c file
  */
 
-struct dentry *kim_debugfs_dir;
+static struct dentry *kim_debugfs_dir;
 static int kim_probe(struct platform_device *pdev)
 {
 	long status;
@@ -731,20 +732,6 @@
 	/* refer to itself */
 	kim_gdata->core_data->kim_data = kim_gdata;
 
-	/* Claim the chip enable nShutdown gpio from the system */
-	kim_gdata->nshutdown = pdata->nshutdown_gpio;
-	status = gpio_request(kim_gdata->nshutdown, "kim");
-	if (unlikely(status)) {
-		pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
-		return status;
-	}
-
-	/* Configure nShutdown GPIO as output=0 */
-	status = gpio_direction_output(kim_gdata->nshutdown, 0);
-	if (unlikely(status)) {
-		pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
-		return status;
-	}
 	/* get reference of pdev for request_firmware
 	 */
 	kim_gdata->kim_pdev = pdev;
@@ -780,18 +767,10 @@
 
 static int kim_remove(struct platform_device *pdev)
 {
-	/* free the GPIOs requested */
-	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
 	struct kim_data_s	*kim_gdata;
 
 	kim_gdata = dev_get_drvdata(&pdev->dev);
 
-	/* Free the Bluetooth/FM/GPIO
-	 * nShutdown gpio from the system
-	 */
-	gpio_free(pdata->nshutdown_gpio);
-	pr_info("nshutdown GPIO Freed");
-
 	debugfs_remove_recursive(kim_debugfs_dir);
 	sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
 	pr_info("sysfs entries removed");
@@ -804,7 +783,7 @@
 	return 0;
 }
 
-int kim_suspend(struct platform_device *pdev, pm_message_t state)
+static int kim_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
 
@@ -814,7 +793,7 @@
 	return -EOPNOTSUPP;
 }
 
-int kim_resume(struct platform_device *pdev)
+static int kim_resume(struct platform_device *pdev)
 {
 	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
 
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index ba24790..f8d66543 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -434,21 +434,9 @@
 	.resume = tifm_7xx1_resume,
 };
 
-static int __init tifm_7xx1_init(void)
-{
-	return pci_register_driver(&tifm_7xx1_driver);
-}
-
-static void __exit tifm_7xx1_exit(void)
-{
-	pci_unregister_driver(&tifm_7xx1_driver);
-}
-
+module_pci_driver(tifm_7xx1_driver);
 MODULE_AUTHOR("Alex Dubov");
 MODULE_DESCRIPTION("TI FlashMedia host driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
 MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tifm_7xx1_init);
-module_exit(tifm_7xx1_exit);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index d4619e2..2273ce6 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -641,7 +641,7 @@
 	/*
 	 * If the host and card support UHS-I mode request the card
 	 * to switch to 1.8V signaling level.  No 1.8v signalling if
-	 * UHS mode is not enabled to maintain compatibilty and some
+	 * UHS mode is not enabled to maintain compatibility and some
 	 * systems that claim 1.8v signalling in fact do not support
 	 * it.
 	 */
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index efdb81d..74bed0f 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -356,7 +356,7 @@
 }
 
 /*
- * Update bytes tranfered count during a write operation
+ * Update bytes transfered count during a write operation
  */
 static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
 {
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index a53c7c4..852d5fb 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1022,7 +1022,7 @@
 }
 
 /*
- * Stop data transfer because error(s) occured.
+ * Stop data transfer because error(s) occurred.
  */
 static void atmci_stop_transfer_pdc(struct atmel_mci *host)
 {
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 87c0293..c6259a8 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -36,7 +36,6 @@
 #include <plat/mmc.h>
 #include <asm/gpio.h>
 #include <plat/dma.h>
-#include <plat/mux.h>
 #include <plat/fpga.h>
 
 #define	OMAP_MMC_REG_CMD	0x00
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f871b31..38adc33 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -446,7 +446,7 @@
 	OMAP_HSMMC_WRITE(host->base, SYSCTL,
 		OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
 	if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
-		dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
+		dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n");
 }
 
 static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
@@ -1781,7 +1781,7 @@
 	if (match) {
 		pdata = of_get_hsmmc_pdata(&pdev->dev);
 		if (match->data) {
-			u16 *offsetp = match->data;
+			const u16 *offsetp = match->data;
 			pdata->reg_offset = *offsetp;
 		}
 	}
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index e23f813..32f4a07 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -315,7 +315,7 @@
 		new_val = val & (SDHCI_CTRL_LED | \
 				SDHCI_CTRL_4BITBUS | \
 				SDHCI_CTRL_D3CD);
-		/* ensure the endianess */
+		/* ensure the endianness */
 		new_val |= ESDHC_HOST_CONTROL_LE;
 		/* bits 8&9 are reserved on mx25 */
 		if (!is_imx25_esdhc(imx_data)) {
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 0810ccc..5393c64 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -27,7 +27,6 @@
 
 #include <asm/gpio.h>
 
-#include <mach/gpio-tegra.h>
 #include <mach/sdhci.h>
 
 #include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 3135a1a..58eab9a 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -806,7 +806,7 @@
 		 * we suspect a buggy USB host controller
 		 */
 	} else if (!vub300->data) {
-		/* this means that the command (typically CMD52) suceeded */
+		/* this means that the command (typically CMD52) succeeded */
 	} else if (vub300->resp.common.header_type != 0x02) {
 		/*
 		 * this is an error response from the VUB300 chip
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index f2f482b..a6e7451 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1123,6 +1123,33 @@
 }
 #endif
 
+static inline unsigned long get_vm_size(struct vm_area_struct *vma)
+{
+	return vma->vm_end - vma->vm_start;
+}
+
+static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
+{
+	return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
+}
+
+/*
+ * Set a new vm offset.
+ *
+ * Verify that the incoming offset really works as a page offset,
+ * and that the offset and size fit in a resource_size_t.
+ */
+static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
+{
+	pgoff_t pgoff = off >> PAGE_SHIFT;
+	if (off != (resource_size_t) pgoff << PAGE_SHIFT)
+		return -EINVAL;
+	if (off + get_vm_size(vma) - 1 < off)
+		return -EINVAL;
+	vma->vm_pgoff = pgoff;
+	return 0;
+}
+
 /*
  * set up a mapping for shared memory segments
  */
@@ -1132,20 +1159,29 @@
 	struct mtd_file_info *mfi = file->private_data;
 	struct mtd_info *mtd = mfi->mtd;
 	struct map_info *map = mtd->priv;
-	unsigned long start;
-	unsigned long off;
-	u32 len;
+	resource_size_t start, off;
+	unsigned long len, vma_len;
 
 	if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
-		off = vma->vm_pgoff << PAGE_SHIFT;
+		off = get_vm_offset(vma);
 		start = map->phys;
 		len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
 		start &= PAGE_MASK;
-		if ((vma->vm_end - vma->vm_start + off) > len)
+		vma_len = get_vm_size(vma);
+
+		/* Overflow in off+len? */
+		if (vma_len + off < off)
+			return -EINVAL;
+		/* Does it fit in the mapping? */
+		if (vma_len + off > len)
 			return -EINVAL;
 
 		off += start;
-		vma->vm_pgoff = off >> PAGE_SHIFT;
+		/* Did that overflow? */
+		if (off < start)
+			return -EINVAL;
+		if (set_vm_offset(vma, off) < 0)
+			return -EINVAL;
 		vma->vm_flags |= VM_IO | VM_RESERVED;
 
 #ifdef pgprot_noncached
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 78a524b..a7040af 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -29,7 +29,7 @@
 #include <asm/io.h>
 #include <asm/sizes.h>
 
-#include <plat/board-ams-delta.h>
+#include <mach/board-ams-delta.h>
 
 #include <mach/hardware.h>
 
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
index c855e7c..d0d1bd4 100644
--- a/drivers/mtd/nand/bcm_umi_nand.c
+++ b/drivers/mtd/nand/bcm_umi_nand.c
@@ -249,20 +249,20 @@
 int bcm_umi_nand_inithw(void)
 {
 	/* Configure nand timing parameters */
-	REG_UMI_NAND_TCR &= ~0x7ffff;
-	REG_UMI_NAND_TCR |= HW_CFG_NAND_TCR;
+	writel(readl(&REG_UMI_NAND_TCR) & ~0x7ffff, &REG_UMI_NAND_TCR);
+	writel(readl(&REG_UMI_NAND_TCR) | HW_CFG_NAND_TCR, &REG_UMI_NAND_TCR);
 
 #if !defined(CONFIG_MTD_NAND_BCM_UMI_HWCS)
 	/* enable software control of CS */
-	REG_UMI_NAND_TCR |= REG_UMI_NAND_TCR_CS_SWCTRL;
+	writel(readl(&REG_UMI_NAND_TCR) | REG_UMI_NAND_TCR_CS_SWCTRL, &REG_UMI_NAND_TCR);
 #endif
 
 	/* keep NAND chip select asserted */
-	REG_UMI_NAND_RCSR |= REG_UMI_NAND_RCSR_CS_ASSERTED;
+	writel(readl(&REG_UMI_NAND_RCSR) | REG_UMI_NAND_RCSR_CS_ASSERTED, &REG_UMI_NAND_RCSR);
 
-	REG_UMI_NAND_TCR &= ~REG_UMI_NAND_TCR_WORD16;
+	writel(readl(&REG_UMI_NAND_TCR) & ~REG_UMI_NAND_TCR_WORD16, &REG_UMI_NAND_TCR);
 	/* enable writes to flash */
-	REG_UMI_MMD_ICR |= REG_UMI_MMD_ICR_FLASH_WP;
+	writel(readl(&REG_UMI_MMD_ICR) | REG_UMI_MMD_ICR_FLASH_WP, &REG_UMI_MMD_ICR);
 
 	writel(NAND_CMD_RESET, bcm_umi_io_base + REG_NAND_CMD_OFFSET);
 	nand_bcm_umi_wait_till_ready();
diff --git a/drivers/mtd/nand/nand_bcm_umi.h b/drivers/mtd/nand/nand_bcm_umi.h
index 198b304..d901866 100644
--- a/drivers/mtd/nand/nand_bcm_umi.h
+++ b/drivers/mtd/nand/nand_bcm_umi.h
@@ -17,7 +17,7 @@
 /* ---- Include Files ---------------------------------------------------- */
 #include <mach/reg_umi.h>
 #include <mach/reg_nand.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
 #if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
@@ -48,7 +48,7 @@
 /* Check in device is ready */
 static inline int nand_bcm_umi_dev_ready(void)
 {
-	return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
+	return readl(&REG_UMI_NAND_RCSR) & REG_UMI_NAND_RCSR_RDY;
 }
 
 /* Wait until device is ready */
@@ -62,10 +62,11 @@
 static inline void nand_bcm_umi_hamming_enable_hwecc(void)
 {
 	/* disable and reset ECC, 512 byte page */
-	REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
-		REG_UMI_NAND_ECC_CSR_256BYTE);
+	writel(readl(&REG_UMI_NAND_ECC_CSR) & ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
+		REG_UMI_NAND_ECC_CSR_256BYTE), &REG_UMI_NAND_ECC_CSR);
 	/* enable ECC */
-	REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
+	writel(readl(&REG_UMI_NAND_ECC_CSR) | REG_UMI_NAND_ECC_CSR_ECC_ENABLE,
+		&REG_UMI_NAND_ECC_CSR);
 }
 
 #if NAND_ECC_BCH
@@ -76,18 +77,18 @@
 static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
 {
 	/* disable and reset ECC */
-	REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+	writel(REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
 	/* Turn on ECC */
-	REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+	writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Enable BCH Write ECC */
 static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
 {
 	/* disable and reset ECC */
-	REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
+	writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
 	/* Turn on ECC */
-	REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
+	writel(REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Config number of BCH ECC bytes */
@@ -99,9 +100,9 @@
 	uint32_t numBits = numEccBytes * 8;
 
 	/* disable and reset ECC */
-	REG_UMI_BCH_CTRL_STATUS =
-	    REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
-	    REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+	writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
+	       REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID,
+	       &REG_UMI_BCH_CTRL_STATUS);
 
 	/* Every correctible bit requires 13 ECC bits */
 	tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
@@ -113,23 +114,21 @@
 	kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
 
 	/* Write the settings */
-	REG_UMI_BCH_N = nValue;
-	REG_UMI_BCH_T = tValue;
-	REG_UMI_BCH_K = kValue;
+	writel(nValue, &REG_UMI_BCH_N);
+	writel(tValue, &REG_UMI_BCH_T);
+	writel(kValue, &REG_UMI_BCH_K);
 }
 
 /* Pause during ECC read calculation to skip bytes in OOB */
 static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
 {
-	REG_UMI_BCH_CTRL_STATUS =
-	    REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
-	    REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
+	writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Resume during ECC read calculation after skipping bytes in OOB */
 static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
 {
-	REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+	writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Poll read ECC calc to check when hardware completes */
@@ -139,7 +138,7 @@
 
 	do {
 		/* wait for ECC to be valid */
-		regVal = REG_UMI_BCH_CTRL_STATUS;
+		regVal = readl(&REG_UMI_BCH_CTRL_STATUS);
 	} while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
 
 	return regVal;
@@ -149,7 +148,7 @@
 static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
 {
 	/* wait for ECC to be valid */
-	while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
+	while ((readl(&REG_UMI_BCH_CTRL_STATUS) & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
 	       == 0)
 		;
 }
@@ -170,9 +169,9 @@
 	if (pageSize != NAND_DATA_ACCESS_SIZE) {
 		/* skip BI */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-		*oobp++ = REG_NAND_DATA8;
+		*oobp++ = readb(&REG_NAND_DATA8);
 #else
-		REG_NAND_DATA8;
+		readb(&REG_NAND_DATA8);
 #endif
 		numToRead--;
 	}
@@ -180,9 +179,9 @@
 	while (numToRead > numEccBytes) {
 		/* skip free oob region */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-		*oobp++ = REG_NAND_DATA8;
+		*oobp++ = readb(&REG_NAND_DATA8);
 #else
-		REG_NAND_DATA8;
+		readb(&REG_NAND_DATA8);
 #endif
 		numToRead--;
 	}
@@ -193,11 +192,11 @@
 
 		while (numToRead > 11) {
 #if defined(__KERNEL__) && !defined(STANDALONE)
-			*oobp = REG_NAND_DATA8;
+			*oobp = readb(&REG_NAND_DATA8);
 			eccCalc[eccPos++] = *oobp;
 			oobp++;
 #else
-			eccCalc[eccPos++] = REG_NAND_DATA8;
+			eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
 #endif
 			numToRead--;
 		}
@@ -207,9 +206,9 @@
 		if (numToRead == 11) {
 			/* read BI */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-			*oobp++ = REG_NAND_DATA8;
+			*oobp++ = readb(&REG_NAND_DATA8);
 #else
-			REG_NAND_DATA8;
+			readb(&REG_NAND_DATA8);
 #endif
 			numToRead--;
 		}
@@ -219,11 +218,11 @@
 	nand_bcm_umi_bch_resume_read_ecc_calc();
 	while (numToRead) {
 #if defined(__KERNEL__) && !defined(STANDALONE)
-		*oobp = REG_NAND_DATA8;
+		*oobp = readb(&REG_NAND_DATA8);
 		eccCalc[eccPos++] = *oobp;
 		oobp++;
 #else
-		eccCalc[eccPos++] = REG_NAND_DATA8;
+		eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
 #endif
 		numToRead--;
 	}
@@ -255,7 +254,7 @@
 	if (pageSize == NAND_DATA_ACCESS_SIZE) {
 		/* Now fill in the ECC bytes */
 		if (numEccBytes >= 13)
-			eccVal = REG_UMI_BCH_WR_ECC_3;
+			eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
 
 		/* Usually we skip CM in oob[0,1] */
 		NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
@@ -268,7 +267,7 @@
 			eccVal & 0xff);	/* ECC 12 */
 
 		if (numEccBytes >= 9)
-			eccVal = REG_UMI_BCH_WR_ECC_2;
+			eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
 
 		NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
 			(eccVal >> 24) & 0xff);	/* ECC11 */
@@ -281,7 +280,7 @@
 
 		/* Now fill in the ECC bytes */
 		if (numEccBytes >= 13)
-			eccVal = REG_UMI_BCH_WR_ECC_3;
+			eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
 
 		/* Usually skip CM in oob[1,2] */
 		NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
@@ -294,7 +293,7 @@
 			eccVal & 0xff);	/* ECC12 */
 
 		if (numEccBytes >= 9)
-			eccVal = REG_UMI_BCH_WR_ECC_2;
+			eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
 
 		NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
 			(eccVal >> 24) & 0xff);	/* ECC11 */
@@ -309,7 +308,7 @@
 		eccVal & 0xff);	/* ECC8 */
 
 	if (numEccBytes >= 5)
-		eccVal = REG_UMI_BCH_WR_ECC_1;
+		eccVal = readl(&REG_UMI_BCH_WR_ECC_1);
 
 	NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
 		(eccVal >> 24) & 0xff);	/* ECC7 */
@@ -321,7 +320,7 @@
 		eccVal & 0xff);	/* ECC4 */
 
 	if (numEccBytes >= 1)
-		eccVal = REG_UMI_BCH_WR_ECC_0;
+		eccVal = readl(&REG_UMI_BCH_WR_ECC_0);
 
 	NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
 		(eccVal >> 24) & 0xff);	/* ECC3 */
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 27293e3..fc81112 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -29,7 +29,7 @@
 
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/nand.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
 
 #define	DRIVER_NAME	"omap2-nand"
 #define	OMAP_NAND_TIMEOUT_MS	5000
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 9d49b1f..1961be9 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -39,7 +39,7 @@
 
 #include <asm/mach/flash.h>
 #include <plat/gpmc.h>
-#include <plat/onenand.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
 #include <asm/gpio.h>
 
 #include <plat/dma.h>
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 98ee438..7edadee 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1391,7 +1391,6 @@
  */
 static int ican3_reset_module(struct ican3_dev *mod)
 {
-	u8 val = 1 << mod->num;
 	unsigned long start;
 	u8 runold, runnew;
 
@@ -1405,8 +1404,7 @@
 	runold = ioread8(mod->dpm + TARGET_RUNNING);
 
 	/* reset the module */
-	iowrite8(val, &mod->ctrl->reset_assert);
-	iowrite8(val, &mod->ctrl->reset_deassert);
+	iowrite8(0x00, &mod->dpmctrl->hwreset);
 
 	/* wait until the module has finished resetting and is running */
 	start = jiffies;
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 06adf88..8a8df82 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -380,12 +380,12 @@
 }
 #endif
 
-static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
+static const struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
 	.type = MSCAN_TYPE_MPC5200,
 	.get_clock = mpc52xx_can_get_clock,
 };
 
-static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
+static const struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
 	.type = MSCAN_TYPE_MPC5121,
 	.get_clock = mpc512x_can_get_clock,
 };
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 527dbcf..9ded21e 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -984,12 +984,12 @@
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct ti_hecc_priv *priv = netdev_priv(ndev);
 
+	unregister_candev(ndev);
 	clk_disable(priv->clk);
 	clk_put(priv->clk);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	iounmap(priv->base);
 	release_mem_region(res->start, resource_size(res));
-	unregister_candev(ndev);
 	free_candev(ndev);
 	platform_set_drvdata(pdev, NULL);
 
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index b153666..bb9670f 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -364,7 +364,7 @@
 static inline void
 typhoon_inc_tx_index(u32 *index, const int count)
 {
-	/* if we start using the Hi Tx ring, this needs updateing */
+	/* if we start using the Hi Tx ring, this needs updating */
 	typhoon_inc_index(index, count, TXLO_ENTRIES);
 }
 
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 1bf5bbfe..55a2e37 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -149,7 +149,7 @@
 	data &= ~(PCI_ERR_UNC_DLP | PCI_ERR_UNC_FCP);
 	pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, data);
 	/* clear error status */
-	pci_write_config_word(pdev, pci_pcie_cap(pdev) + PCI_EXP_DEVSTA,
+	pcie_capability_write_word(pdev, PCI_EXP_DEVSTA,
 			PCI_EXP_DEVSTA_NFED |
 			PCI_EXP_DEVSTA_FED |
 			PCI_EXP_DEVSTA_CED |
@@ -2685,7 +2685,7 @@
 	netif_device_attach(netdev);
 }
 
-static struct pci_error_handlers atl1c_err_handler = {
+static const struct pci_error_handlers atl1c_err_handler = {
 	.error_detected = atl1c_io_error_detected,
 	.slot_reset = atl1c_io_slot_reset,
 	.resume = atl1c_io_resume,
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index a98acc8..e213da2 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -2489,7 +2489,7 @@
 	netif_device_attach(netdev);
 }
 
-static struct pci_error_handlers atl1e_err_handler = {
+static const struct pci_error_handlers atl1e_err_handler = {
 	.error_detected = atl1e_io_error_detected,
 	.slot_reset = atl1e_io_slot_reset,
 	.resume = atl1e_io_resume,
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 79cebd8..d431070 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -8564,7 +8564,7 @@
 	return 0;
 
 error:
-	iounmap(bp->regview);
+	pci_iounmap(pdev, bp->regview);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
@@ -8742,7 +8742,7 @@
 	rtnl_unlock();
 }
 
-static struct pci_error_handlers bnx2_err_handler = {
+static const struct pci_error_handlers bnx2_err_handler = {
 	.error_detected	= bnx2_io_error_detected,
 	.slot_reset	= bnx2_io_slot_reset,
 	.resume		= bnx2_io_resume,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 6d1a24a..eac2523 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1458,7 +1458,7 @@
 	int				fw_stats_req_sz;
 
 	/*
-	 * FW statistics data shortcut (points at the begining of
+	 * FW statistics data shortcut (points at the beginning of
 	 * fw_stats buffer + fw_stats_req_sz).
 	 */
 	struct bnx2x_fw_stats_data	*fw_stats_data;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index af20c6e..e8e97a7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -662,14 +662,16 @@
 				 struct bnx2x_fastpath *fp,
 				 struct bnx2x_eth_q_stats *qstats)
 {
-	/* Do nothing if no IP/L4 csum validation was done */
-
+	/* Do nothing if no L4 csum validation was done.
+	 * We do not check whether IP csum was validated. For IPv4 we assume
+	 * that if the card got as far as validating the L4 csum, it also
+	 * validated the IP csum. IPv6 has no IP csum.
+	 */
 	if (cqe->fast_path_cqe.status_flags &
-	    (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG |
-	     ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG))
+	    ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)
 		return;
 
-	/* If both IP/L4 validation were done, check if an error was found. */
+	/* If L4 validation was done, check if an error was found. */
 
 	if (cqe->fast_path_cqe.type_error_flags &
 	    (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 211753e..e11485c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -1162,14 +1162,9 @@
 
 static u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
 {
-	int pos;
 	u16 status;
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return false;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
+	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
 	return status & PCI_EXP_DEVSTA_TRPND;
 }
 
@@ -6135,8 +6130,7 @@
 	u16 devctl;
 	int r_order, w_order;
 
-	pci_read_config_word(bp->pdev,
-			     pci_pcie_cap(bp->pdev) + PCI_EXP_DEVCTL, &devctl);
+	pcie_capability_read_word(bp->pdev, PCI_EXP_DEVCTL, &devctl);
 	DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl);
 	w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
 	if (bp->mrrs == -1)
@@ -9380,7 +9374,7 @@
 
 static int __devinit bnx2x_do_flr(struct bnx2x *bp)
 {
-	int i, pos;
+	int i;
 	u16 status;
 	struct pci_dev *dev = bp->pdev;
 
@@ -9397,16 +9391,12 @@
 		return -EINVAL;
 	}
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return -ENOTTY;
-
 	/* Wait for Transaction Pending bit clean */
 	for (i = 0; i < 4; i++) {
 		if (i)
 			msleep((1 << (i - 1)) * 100);
 
-		pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
+		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
 		if (!(status & PCI_EXP_DEVSTA_TRPND))
 			goto clear;
 	}
@@ -9831,12 +9821,13 @@
 	}
 
 #ifdef CONFIG_PCI_MSI
-	/*
-	 * It's expected that number of CAM entries for this functions is equal
-	 * to the number evaluated based on the MSI-X table size. We want a
-	 * harsh warning if these values are different!
+	/* Due to new PF resource allocation by MFW T7.4 and above, it's
+	 * optional that number of CAM entries will not be equal to the value
+	 * advertised in PCI.
+	 * Driver should use the minimal value of both as the actual status
+	 * block count
 	 */
-	WARN_ON(bp->igu_sb_cnt != igu_sb_cnt);
+	bp->igu_sb_cnt = min_t(int, bp->igu_sb_cnt, igu_sb_cnt);
 #endif
 
 	if (igu_sb_cnt == 0)
@@ -12166,7 +12157,7 @@
 	rtnl_unlock();
 }
 
-static struct pci_error_handlers bnx2x_err_handler = {
+static const struct pci_error_handlers bnx2x_err_handler = {
 	.error_detected = bnx2x_io_error_detected,
 	.slot_reset     = bnx2x_io_slot_reset,
 	.resume         = bnx2x_io_resume,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index f83e033..acf2fe4c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -1321,7 +1321,7 @@
  * the current command will be enqueued to the tail of the
  * pending commands list.
  *
- * Return: 0 is operation was sucessfull and there are no pending completions,
+ * Return: 0 is operation was successfull and there are no pending completions,
  *         negative if there were errors, positive if there are pending
  *         completions.
  */
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index bf906c5..388d322 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3653,17 +3653,9 @@
 	tg3_enable_register_access(tp);
 
 	/* Restore the CLKREQ setting. */
-	if (tg3_flag(tp, CLKREQ_BUG)) {
-		u16 lnkctl;
-
-		pci_read_config_word(tp->pdev,
-				     pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
-				     &lnkctl);
-		lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
-		pci_write_config_word(tp->pdev,
-				      pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
-				      lnkctl);
-	}
+	if (tg3_flag(tp, CLKREQ_BUG))
+		pcie_capability_set_word(tp->pdev, PCI_EXP_LNKCTL,
+					 PCI_EXP_LNKCTL_CLKREQ_EN);
 
 	misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
 	tw32(TG3PCI_MISC_HOST_CTRL,
@@ -4434,20 +4426,13 @@
 
 	/* Prevent send BD corruption. */
 	if (tg3_flag(tp, CLKREQ_BUG)) {
-		u16 oldlnkctl, newlnkctl;
-
-		pci_read_config_word(tp->pdev,
-				     pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
-				     &oldlnkctl);
 		if (tp->link_config.active_speed == SPEED_100 ||
 		    tp->link_config.active_speed == SPEED_10)
-			newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN;
+			pcie_capability_clear_word(tp->pdev, PCI_EXP_LNKCTL,
+						   PCI_EXP_LNKCTL_CLKREQ_EN);
 		else
-			newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN;
-		if (newlnkctl != oldlnkctl)
-			pci_write_config_word(tp->pdev,
-					      pci_pcie_cap(tp->pdev) +
-					      PCI_EXP_LNKCTL, newlnkctl);
+			pcie_capability_set_word(tp->pdev, PCI_EXP_LNKCTL,
+						 PCI_EXP_LNKCTL_CLKREQ_EN);
 	}
 
 	if (current_link_up != netif_carrier_ok(tp->dev)) {
@@ -8054,7 +8039,7 @@
 
 	udelay(120);
 
-	if (tg3_flag(tp, PCI_EXPRESS) && pci_pcie_cap(tp->pdev)) {
+	if (tg3_flag(tp, PCI_EXPRESS) && pci_is_pcie(tp->pdev)) {
 		u16 val16;
 
 		if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
@@ -8071,24 +8056,17 @@
 		}
 
 		/* Clear the "no snoop" and "relaxed ordering" bits. */
-		pci_read_config_word(tp->pdev,
-				     pci_pcie_cap(tp->pdev) + PCI_EXP_DEVCTL,
-				     &val16);
-		val16 &= ~(PCI_EXP_DEVCTL_RELAX_EN |
-			   PCI_EXP_DEVCTL_NOSNOOP_EN);
+		val16 = PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN;
 		/*
 		 * Older PCIe devices only support the 128 byte
 		 * MPS setting.  Enforce the restriction.
 		 */
 		if (!tg3_flag(tp, CPMU_PRESENT))
-			val16 &= ~PCI_EXP_DEVCTL_PAYLOAD;
-		pci_write_config_word(tp->pdev,
-				      pci_pcie_cap(tp->pdev) + PCI_EXP_DEVCTL,
-				      val16);
+			val16 |= PCI_EXP_DEVCTL_PAYLOAD;
+		pcie_capability_clear_word(tp->pdev, PCI_EXP_DEVCTL, val16);
 
 		/* Clear error status */
-		pci_write_config_word(tp->pdev,
-				      pci_pcie_cap(tp->pdev) + PCI_EXP_DEVSTA,
+		pcie_capability_write_word(tp->pdev, PCI_EXP_DEVSTA,
 				      PCI_EXP_DEVSTA_CED |
 				      PCI_EXP_DEVSTA_NFED |
 				      PCI_EXP_DEVSTA_FED |
@@ -14565,9 +14543,7 @@
 
 		tg3_flag_set(tp, PCI_EXPRESS);
 
-		pci_read_config_word(tp->pdev,
-				     pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
-				     &lnkctl);
+		pcie_capability_read_word(tp->pdev, PCI_EXP_LNKCTL, &lnkctl);
 		if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
 			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
 			    ASIC_REV_5906) {
@@ -16397,7 +16373,7 @@
 	rtnl_unlock();
 }
 
-static struct pci_error_handlers tg3_err_handler = {
+static const struct pci_error_handlers tg3_err_handler = {
 	.error_detected	= tg3_io_error_detected,
 	.slot_reset	= tg3_io_slot_reset,
 	.resume		= tg3_io_resume
diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
index 7788419..4e980a78 100644
--- a/drivers/net/ethernet/cadence/at91_ether.c
+++ b/drivers/net/ethernet/cadence/at91_ether.c
@@ -1086,7 +1086,7 @@
 	/* Clock */
 	lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
 	if (IS_ERR(lp->ether_clk)) {
-		res = -ENODEV;
+		res = PTR_ERR(lp->ether_clk);
 		goto err_ioumap;
 	}
 	clk_enable(lp->ether_clk);
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 6505070..875bbb9 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -3036,7 +3036,7 @@
 	t3_resume_ports(adapter);
 }
 
-static struct pci_error_handlers t3_err_handler = {
+static const struct pci_error_handlers t3_err_handler = {
 	.error_detected = t3_io_error_detected,
 	.slot_reset = t3_io_slot_reset,
 	.resume = t3_io_resume,
diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index bff8a3c..aef45d3 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -3289,22 +3289,18 @@
 	unsigned int log2_width, pldsize;
 	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
 
-	pci_read_config_word(adap->pdev,
-			     adap->pdev->pcie_cap + PCI_EXP_DEVCTL,
-			     &val);
+	pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL, &val);
 	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
 
 	pci_read_config_word(adap->pdev, 0x2, &devid);
 	if (devid == 0x37) {
-		pci_write_config_word(adap->pdev,
-				      adap->pdev->pcie_cap + PCI_EXP_DEVCTL,
-				      val & ~PCI_EXP_DEVCTL_READRQ &
-				      ~PCI_EXP_DEVCTL_PAYLOAD);
+		pcie_capability_write_word(adap->pdev, PCI_EXP_DEVCTL,
+					   val & ~PCI_EXP_DEVCTL_READRQ &
+					   ~PCI_EXP_DEVCTL_PAYLOAD);
 		pldsize = 0;
 	}
 
-	pci_read_config_word(adap->pdev, adap->pdev->pcie_cap + PCI_EXP_LNKCTL,
-			     &val);
+	pcie_capability_read_word(adap->pdev, PCI_EXP_LNKCTL, &val);
 
 	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
 	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
@@ -3425,15 +3421,13 @@
 static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
 {
 	static unsigned short speed_map[] = { 33, 66, 100, 133 };
-	u32 pci_mode, pcie_cap;
+	u32 pci_mode;
 
-	pcie_cap = pci_pcie_cap(adapter->pdev);
-	if (pcie_cap) {
+	if (pci_is_pcie(adapter->pdev)) {
 		u16 val;
 
 		p->variant = PCI_VARIANT_PCIE;
-		pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
-					&val);
+		pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
 		p->width = (val >> 4) & 0x3f;
 		return;
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 5ed49af..9339854 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3453,7 +3453,7 @@
 	rtnl_unlock();
 }
 
-static struct pci_error_handlers cxgb4_eeh = {
+static const struct pci_error_handlers cxgb4_eeh = {
 	.error_detected = eeh_err_detected,
 	.slot_reset     = eeh_slot_reset,
 	.resume         = eeh_resume,
@@ -3694,15 +3694,7 @@
 
 static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev)
 {
-	u16 v;
-	int pos;
-
-	pos = pci_pcie_cap(dev);
-	if (pos > 0) {
-		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &v);
-		v |= PCI_EXP_DEVCTL_RELAX_EN;
-		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, v);
-	}
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
 }
 
 /*
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index fa947df..af16013 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -2741,11 +2741,9 @@
 				   struct pci_params *p)
 {
 	u16 val;
-	u32 pcie_cap = pci_pcie_cap(adapter->pdev);
 
-	if (pcie_cap) {
-		pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
-				     &val);
+	if (pci_is_pcie(adapter->pdev)) {
+		pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
 		p->speed = val & PCI_EXP_LNKSTA_CLS;
 		p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
 	}
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 78b8aa8..95d1047 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4106,7 +4106,7 @@
 	dev_err(&adapter->pdev->dev, "EEH resume failed\n");
 }
 
-static struct pci_error_handlers be_eeh_handlers = {
+static const struct pci_error_handlers be_eeh_handlers = {
 	.error_detected = be_eeh_err_detected,
 	.slot_reset = be_eeh_reset,
 	.resume = be_eeh_resume,
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 8971921..ab6762c 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -1773,6 +1773,7 @@
 }
 
 int gfar_phc_index = -1;
+EXPORT_SYMBOL(gfar_phc_index);
 
 static int gfar_get_ts_info(struct net_device *dev,
 			    struct ethtool_ts_info *info)
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index c08e5d4..0daa66b 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -515,7 +515,7 @@
 		err = PTR_ERR(etsects->clock);
 		goto no_clock;
 	}
-	gfar_phc_clock = ptp_clock_index(etsects->clock);
+	gfar_phc_index = ptp_clock_index(etsects->clock);
 
 	dev_set_drvdata(&dev->dev, etsects);
 
@@ -539,7 +539,7 @@
 	gfar_write(&etsects->regs->tmr_temask, 0);
 	gfar_write(&etsects->regs->tmr_ctrl,   0);
 
-	gfar_phc_clock = -1;
+	gfar_phc_index = -1;
 	ptp_clock_unregister(etsects->clock);
 	iounmap(etsects->regs);
 	release_resource(etsects->rsrc);
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index 535f94f..29ce9bd 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -3157,7 +3157,7 @@
 	}
 }
 
-static struct pci_error_handlers e100_err_handler = {
+static const struct pci_error_handlers e100_err_handler = {
 	.error_detected = e100_io_error_detected,
 	.slot_reset = e100_io_slot_reset,
 	.resume = e100_io_resume,
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 3bfbb8d..f3f9aeb 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -192,7 +192,7 @@
 static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
 static void e1000_io_resume(struct pci_dev *pdev);
 
-static struct pci_error_handlers e1000_err_handler = {
+static const struct pci_error_handlers e1000_err_handler = {
 	.error_detected = e1000_io_error_detected,
 	.slot_reset = e1000_io_slot_reset,
 	.resume = e1000_io_resume,
@@ -3149,6 +3149,17 @@
 		return NETDEV_TX_OK;
 	}
 
+	/* On PCI/PCI-X HW, if packet size is less than ETH_ZLEN,
+	 * packets may get corrupted during padding by HW.
+	 * To WA this issue, pad all small packets manually.
+	 */
+	if (skb->len < ETH_ZLEN) {
+		if (skb_pad(skb, ETH_ZLEN - skb->len))
+			return NETDEV_TX_OK;
+		skb->len = ETH_ZLEN;
+		skb_set_tail_pointer(skb, ETH_ZLEN);
+	}
+
 	mss = skb_shinfo(skb)->gso_size;
 	/* The controller does a simple calculation to
 	 * make sure there is enough room in the FIFO before
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index d01a099..3f0223a 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5584,16 +5584,15 @@
 	 */
 	if (adapter->flags & FLAG_IS_QUAD_PORT) {
 		struct pci_dev *us_dev = pdev->bus->self;
-		int pos = pci_pcie_cap(us_dev);
 		u16 devctl;
 
-		pci_read_config_word(us_dev, pos + PCI_EXP_DEVCTL, &devctl);
-		pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL,
-		                      (devctl & ~PCI_EXP_DEVCTL_CERE));
+		pcie_capability_read_word(us_dev, PCI_EXP_DEVCTL, &devctl);
+		pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL,
+					   (devctl & ~PCI_EXP_DEVCTL_CERE));
 
 		e1000_power_off(pdev, sleep, wake);
 
-		pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, devctl);
+		pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL, devctl);
 	} else {
 		e1000_power_off(pdev, sleep, wake);
 	}
@@ -5607,25 +5606,15 @@
 #else
 static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 {
-	int pos;
-	u16 reg16;
-
 	/*
 	 * Both device and parent should have the same ASPM setting.
 	 * Disable ASPM in downstream component first and then upstream.
 	 */
-	pos = pci_pcie_cap(pdev);
-	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
-	reg16 &= ~state;
-	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
+	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, state);
 
-	if (!pdev->bus->self)
-		return;
-
-	pos = pci_pcie_cap(pdev->bus->self);
-	pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, &reg16);
-	reg16 &= ~state;
-	pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16);
+	if (pdev->bus->self)
+		pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
+					   state);
 }
 #endif
 static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
@@ -6486,7 +6475,7 @@
 }
 
 /* PCI Error Recovery (ERS) */
-static struct pci_error_handlers e1000_err_handler = {
+static const struct pci_error_handlers e1000_err_handler = {
 	.error_detected = e1000_io_error_detected,
 	.slot_reset = e1000_io_slot_reset,
 	.resume = e1000_io_resume,
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 48cc4fb..f88c822 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -217,7 +217,7 @@
 static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
 static void igb_io_resume(struct pci_dev *);
 
-static struct pci_error_handlers igb_err_handler = {
+static const struct pci_error_handlers igb_err_handler = {
 	.error_detected = igb_io_error_detected,
 	.slot_reset = igb_io_slot_reset,
 	.resume = igb_io_resume,
@@ -6538,28 +6538,20 @@
 s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
 {
 	struct igb_adapter *adapter = hw->back;
-	u16 cap_offset;
 
-	cap_offset = adapter->pdev->pcie_cap;
-	if (!cap_offset)
+	if (pcie_capability_read_word(adapter->pdev, reg, value))
 		return -E1000_ERR_CONFIG;
 
-	pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
 	return 0;
 }
 
 s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
 {
 	struct igb_adapter *adapter = hw->back;
-	u16 cap_offset;
 
-	cap_offset = adapter->pdev->pcie_cap;
-	if (!cap_offset)
+	if (pcie_capability_write_word(adapter->pdev, reg, *value))
 		return -E1000_ERR_CONFIG;
 
-	pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
-
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 0696abf..0ac11f5 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -2833,7 +2833,7 @@
 }
 
 /* PCI Error Recovery (ERS) */
-static struct pci_error_handlers igbvf_err_handler = {
+static const struct pci_error_handlers igbvf_err_handler = {
 	.error_detected = igbvf_io_error_detected,
 	.slot_reset = igbvf_io_slot_reset,
 	.resume = igbvf_io_resume,
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index d05fc95..d99a2d5 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -115,7 +115,7 @@
 static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
 static void ixgb_io_resume (struct pci_dev *pdev);
 
-static struct pci_error_handlers ixgb_err_handler = {
+static const struct pci_error_handlers ixgb_err_handler = {
 	.error_detected = ixgb_io_error_detected,
 	.slot_reset = ixgb_io_slot_reset,
 	.resume = ixgb_io_resume,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 4326f74..ee61819 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7527,7 +7527,7 @@
 		goto skip_bad_vf_detection;
 
 	bdev = pdev->bus->self;
-	while (bdev && (bdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+	while (bdev && (pci_pcie_type(bdev) != PCI_EXP_TYPE_ROOT_PORT))
 		bdev = bdev->bus->self;
 
 	if (!bdev)
@@ -7677,7 +7677,7 @@
 	netif_device_attach(netdev);
 }
 
-static struct pci_error_handlers ixgbe_err_handler = {
+static const struct pci_error_handlers ixgbe_err_handler = {
 	.error_detected = ixgbe_io_error_detected,
 	.slot_reset = ixgbe_io_slot_reset,
 	.resume = ixgbe_io_resume,
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 60ef645..6647383 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -3256,7 +3256,7 @@
 }
 
 /* PCI Error Recovery (ERS) */
-static struct pci_error_handlers ixgbevf_err_handler = {
+static const struct pci_error_handlers ixgbevf_err_handler = {
 	.error_detected = ixgbevf_io_error_detected,
 	.slot_reset = ixgbevf_io_slot_reset,
 	.resume = ixgbevf_io_resume,
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index daf4179..31d0264 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -227,9 +227,10 @@
 			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
 }
 
-int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj)
 {
-	int i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+	u32 i = (obj & (table->num_obj - 1)) /
+			(MLX4_TABLE_CHUNK_SIZE / table->obj_size);
 	int ret = 0;
 
 	mutex_lock(&table->mutex);
@@ -262,16 +263,18 @@
 	return ret;
 }
 
-void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
+void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj)
 {
-	int i;
+	u32 i;
+	u64 offset;
 
 	i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
 
 	mutex_lock(&table->mutex);
 
 	if (--table->icm[i]->refcount == 0) {
-		mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
+		offset = (u64) i * MLX4_TABLE_CHUNK_SIZE;
+		mlx4_UNMAP_ICM(dev, table->virt + offset,
 			       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
 		mlx4_free_icm(dev, table->icm[i], table->coherent);
 		table->icm[i] = NULL;
@@ -280,9 +283,11 @@
 	mutex_unlock(&table->mutex);
 }
 
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle)
+void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj,
+			dma_addr_t *dma_handle)
 {
-	int idx, offset, dma_offset, i;
+	int offset, dma_offset, i;
+	u64 idx;
 	struct mlx4_icm_chunk *chunk;
 	struct mlx4_icm *icm;
 	struct page *page = NULL;
@@ -292,7 +297,7 @@
 
 	mutex_lock(&table->mutex);
 
-	idx = (obj & (table->num_obj - 1)) * table->obj_size;
+	idx = (u64) (obj & (table->num_obj - 1)) * table->obj_size;
 	icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE];
 	dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE;
 
@@ -326,10 +331,11 @@
 }
 
 int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-			 int start, int end)
+			 u32 start, u32 end)
 {
 	int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size;
-	int i, err;
+	int err;
+	u32 i;
 
 	for (i = start; i <= end; i += inc) {
 		err = mlx4_table_get(dev, table, i);
@@ -349,9 +355,9 @@
 }
 
 void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-			  int start, int end)
+			  u32 start, u32 end)
 {
-	int i;
+	u32 i;
 
 	for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size)
 		mlx4_table_put(dev, table, i);
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.h b/drivers/net/ethernet/mellanox/mlx4/icm.h
index a67744f..dee67fa 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.h
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.h
@@ -71,17 +71,17 @@
 				gfp_t gfp_mask, int coherent);
 void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
 
-int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
-void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj);
+void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj);
 int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-			 int start, int end);
+			 u32 start, u32 end);
 void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-			  int start, int end);
+			  u32 start, u32 end);
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 			u64 virt, int obj_size,	u32 nobj, int reserved,
 			int use_lowmem, int use_coherent);
 void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
+void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, dma_addr_t *dma_handle);
 
 static inline void mlx4_icm_first(struct mlx4_icm *icm,
 				  struct mlx4_icm_iter *iter)
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 2f816c6..dd6ea94 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -2300,7 +2300,7 @@
 	return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
 
-static struct pci_error_handlers mlx4_err_handler = {
+static const struct pci_error_handlers mlx4_err_handler = {
 	.error_detected = mlx4_pci_err_detected,
 	.slot_reset     = mlx4_pci_slot_reset,
 };
diff --git a/drivers/net/ethernet/mellanox/mlx4/reset.c b/drivers/net/ethernet/mellanox/mlx4/reset.c
index 11e7c1c..dd1b509 100644
--- a/drivers/net/ethernet/mellanox/mlx4/reset.c
+++ b/drivers/net/ethernet/mellanox/mlx4/reset.c
@@ -141,16 +141,16 @@
 	/* Now restore the PCI headers */
 	if (pcie_cap) {
 		devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];
-		if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL,
-					   devctl)) {
+		if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL,
+					       devctl)) {
 			err = -ENODEV;
 			mlx4_err(dev, "Couldn't restore HCA PCI Express "
 				 "Device Control register, aborting.\n");
 			goto out;
 		}
 		linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];
-		if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL,
-					   linkctl)) {
+		if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL,
+					       linkctl)) {
 			err = -ENODEV;
 			mlx4_err(dev, "Couldn't restore HCA PCI Express "
 				 "Link control register, aborting.\n");
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index fa85cf1..83516e3 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -1078,22 +1078,16 @@
 #ifdef CONFIG_MYRI10GE_DCA
 static int myri10ge_toggle_relaxed(struct pci_dev *pdev, int on)
 {
-	int ret, cap, err;
+	int ret;
 	u16 ctl;
 
-	cap = pci_pcie_cap(pdev);
-	if (!cap)
-		return 0;
-
-	err = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
-	if (err)
-		return 0;
+	pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &ctl);
 
 	ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4;
 	if (ret != on) {
 		ctl &= ~PCI_EXP_DEVCTL_RELAX_EN;
 		ctl |= (on << 4);
-		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+		pcie_capability_write_word(pdev, PCI_EXP_DEVCTL, ctl);
 	}
 	return ret;
 }
@@ -3192,18 +3186,13 @@
 	struct device *dev = &mgp->pdev->dev;
 	int cap;
 	unsigned err_cap;
-	u16 val;
-	u8 ext_type;
 	int ret;
 
 	if (!myri10ge_ecrc_enable || !bridge)
 		return;
 
 	/* check that the bridge is a root port */
-	cap = pci_pcie_cap(bridge);
-	pci_read_config_word(bridge, cap + PCI_CAP_FLAGS, &val);
-	ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
-	if (ext_type != PCI_EXP_TYPE_ROOT_PORT) {
+	if (pci_pcie_type(bridge) != PCI_EXP_TYPE_ROOT_PORT) {
 		if (myri10ge_ecrc_enable > 1) {
 			struct pci_dev *prev_bridge, *old_bridge = bridge;
 
@@ -3218,11 +3207,8 @@
 						" to force ECRC\n");
 					return;
 				}
-				cap = pci_pcie_cap(bridge);
-				pci_read_config_word(bridge,
-						     cap + PCI_CAP_FLAGS, &val);
-				ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
-			} while (ext_type != PCI_EXP_TYPE_ROOT_PORT);
+			} while (pci_pcie_type(bridge) !=
+				 PCI_EXP_TYPE_ROOT_PORT);
 
 			dev_info(dev,
 				 "Forcing ECRC on non-root port %s"
@@ -3335,11 +3321,10 @@
 	int overridden = 0;
 
 	if (myri10ge_force_firmware == 0) {
-		int link_width, exp_cap;
+		int link_width;
 		u16 lnk;
 
-		exp_cap = pci_pcie_cap(mgp->pdev);
-		pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
+		pcie_capability_read_word(mgp->pdev, PCI_EXP_LNKSTA, &lnk);
 		link_width = (lnk >> 4) & 0x3f;
 
 		/* Check to see if Link is less than 8 or if the
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index d958c22..de50547 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -484,7 +484,7 @@
 
 MODULE_DEVICE_TABLE(pci, s2io_tbl);
 
-static struct pci_error_handlers s2io_err_handler = {
+static const struct pci_error_handlers s2io_err_handler = {
 	.error_detected = s2io_io_error_detected,
 	.slot_reset = s2io_io_slot_reset,
 	.resume = s2io_io_resume,
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 32d0682..c2e420a 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -757,7 +757,7 @@
 	u16 lnk;
 
 	/* Get the negotiated link width and speed from PCI config space */
-	pci_read_config_word(dev, dev->pcie_cap + PCI_EXP_LNKSTA, &lnk);
+	pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnk);
 
 	if ((lnk & PCI_EXP_LNKSTA_CLS) != 1)
 		return VXGE_HW_ERR_INVALID_PCI_INFO;
@@ -1982,7 +1982,7 @@
 	struct pci_dev *dev = hldev->pdev;
 	u16 lnk;
 
-	pci_read_config_word(dev, dev->pcie_cap + PCI_EXP_LNKSTA, &lnk);
+	pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnk);
 	return (lnk & VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4;
 }
 
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index de21904..cfa71a3 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -4799,7 +4799,7 @@
 			     __LINE__);
 }
 
-static struct pci_error_handlers vxge_err_handler = {
+static const struct pci_error_handlers vxge_err_handler = {
 	.error_detected = vxge_io_error_detected,
 	.slot_reset = vxge_io_slot_reset,
 	.resume = vxge_io_resume,
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index c42bbb1..a688a2d 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -722,10 +722,8 @@
 				   octeon_mgmt_adjust_link, 0,
 				   PHY_INTERFACE_MODE_MII);
 
-	if (IS_ERR(p->phydev)) {
-		p->phydev = NULL;
+	if (!p->phydev)
 		return -1;
-	}
 
 	phy_start_aneg(p->phydev);
 
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index feb85d5..b2a94d0 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -2795,7 +2795,7 @@
 };
 #endif
 
-static struct pci_error_handlers pch_gbe_err_handler = {
+static const struct pci_error_handlers pch_gbe_err_handler = {
 	.error_detected = pch_gbe_io_error_detected,
 	.slot_reset = pch_gbe_io_slot_reset,
 	.resume = pch_gbe_io_resume
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c
index e559dfa..6fa74d5 100644
--- a/drivers/net/ethernet/pasemi/pasemi_mac.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -1101,9 +1101,9 @@
 	phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0,
 				PHY_INTERFACE_MODE_SGMII);
 
-	if (IS_ERR(phydev)) {
+	if (!phydev) {
 		printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
-		return PTR_ERR(phydev);
+		return -ENODEV;
 	}
 
 	mac->phydev = phydev;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 342b3a7..df45061 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -1378,11 +1378,15 @@
 	struct pci_dev *root = pdev->bus->self;
 	u32 aer_pos;
 
+	/* root bus? */
+	if (!root)
+		return;
+
 	if (adapter->ahw.board_type != NETXEN_BRDTYPE_P3_4_GB_MM &&
 		adapter->ahw.board_type != NETXEN_BRDTYPE_P3_10G_TP)
 		return;
 
-	if (root->pcie_type != PCI_EXP_TYPE_ROOT_PORT)
+	if (pci_pcie_type(root) != PCI_EXP_TYPE_ROOT_PORT)
 		return;
 
 	aer_pos = pci_find_ext_capability(root, PCI_EXT_CAP_ID_ERR);
@@ -3336,7 +3340,7 @@
 { }
 #endif
 
-static struct pci_error_handlers netxen_err_handler = {
+static const struct pci_error_handlers netxen_err_handler = {
 	.error_detected = netxen_io_error_detected,
 	.slot_reset = netxen_io_slot_reset,
 	.resume = netxen_io_resume,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index b8ead69..2a179d0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -15,7 +15,7 @@
 
 	do {
 		/* give atleast 1ms for firmware to respond */
-		msleep(1);
+		mdelay(1);
 
 		if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
 			return QLCNIC_CDRP_RSP_TIMEOUT;
@@ -601,7 +601,7 @@
 		qlcnic_fw_cmd_destroy_tx_ctx(adapter);
 
 		/* Allow dma queues to drain after context reset */
-		msleep(20);
+		mdelay(20);
 	}
 }
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 212c121..473ce13 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -4522,7 +4522,7 @@
 qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
-static struct pci_error_handlers qlcnic_err_handler = {
+static const struct pci_error_handlers qlcnic_err_handler = {
 	.error_detected = qlcnic_io_error_detected,
 	.slot_reset = qlcnic_io_slot_reset,
 	.resume = qlcnic_io_resume,
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index b53a3b6..b262d615 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -4847,7 +4847,7 @@
 	netif_device_attach(ndev);
 }
 
-static struct pci_error_handlers qlge_err_handler = {
+static const struct pci_error_handlers qlge_err_handler = {
 	.error_detected = qlge_io_error_detected,
 	.slot_reset = qlge_io_slot_reset,
 	.resume = qlge_io_resume,
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index b47d5b3..a7cc560 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -833,15 +833,8 @@
 
 static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
 {
-	int cap = pci_pcie_cap(pdev);
-
-	if (cap) {
-		u16 ctl;
-
-		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
-		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
-		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
-	}
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+					   PCI_EXP_DEVCTL_READRQ, force);
 }
 
 struct rtl_cond {
@@ -4739,28 +4732,14 @@
 
 static void rtl_disable_clock_request(struct pci_dev *pdev)
 {
-	int cap = pci_pcie_cap(pdev);
-
-	if (cap) {
-		u16 ctl;
-
-		pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
-		ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
-		pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
-	}
+	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
+				   PCI_EXP_LNKCTL_CLKREQ_EN);
 }
 
 static void rtl_enable_clock_request(struct pci_dev *pdev)
 {
-	int cap = pci_pcie_cap(pdev);
-
-	if (cap) {
-		u16 ctl;
-
-		pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
-		ctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
-		pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
-	}
+	pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
+				 PCI_EXP_LNKCTL_CLKREQ_EN);
 }
 
 #define R8168_CPCMD_QUIRK_MASK (\
@@ -5405,14 +5384,9 @@
 		tp->event_slow &= ~RxFIFOOver;
 
 	if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
-	    tp->mac_version == RTL_GIGA_MAC_VER_16) {
-		int cap = pci_pcie_cap(pdev);
-
-		if (cap) {
-			pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
-					      PCI_EXP_DEVCTL_NOSNOOP_EN);
-		}
-	}
+	    tp->mac_version == RTL_GIGA_MAC_VER_16)
+		pcie_capability_set_word(pdev, PCI_EXP_DEVCTL,
+					 PCI_EXP_DEVCTL_NOSNOOP_EN);
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
 
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index df808ac..6a40dd0 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -99,13 +99,13 @@
  * The SEEQ8005 doesn't like us writing to its registers
  * too quickly.
  */
-static inline void ether3_outb(int v, const void __iomem *r)
+static inline void ether3_outb(int v, void __iomem *r)
 {
 	writeb(v, r);
 	udelay(1);
 }
 
-static inline void ether3_outw(int v, const void __iomem *r)
+static inline void ether3_outw(int v, void __iomem *r)
 {
 	writew(v, r);
 	udelay(1);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c136162..3be8833 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1066,7 +1066,7 @@
 	} else
 		priv->tm->enable = 1;
 #endif
-	clk_enable(priv->stmmac_clk);
+	clk_prepare_enable(priv->stmmac_clk);
 
 	stmmac_check_ether_addr(priv);
 
@@ -1188,7 +1188,7 @@
 	if (priv->phydev)
 		phy_disconnect(priv->phydev);
 
-	clk_disable(priv->stmmac_clk);
+	clk_disable_unprepare(priv->stmmac_clk);
 
 	return ret;
 }
@@ -1246,7 +1246,7 @@
 #ifdef CONFIG_STMMAC_DEBUG_FS
 	stmmac_exit_fs();
 #endif
-	clk_disable(priv->stmmac_clk);
+	clk_disable_unprepare(priv->stmmac_clk);
 
 	return 0;
 }
@@ -2178,7 +2178,7 @@
 	else {
 		stmmac_set_mac(priv->ioaddr, false);
 		/* Disable clock in case of PWM is off */
-		clk_disable(priv->stmmac_clk);
+		clk_disable_unprepare(priv->stmmac_clk);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	return 0;
@@ -2203,7 +2203,7 @@
 		priv->hw->mac->pmt(priv->ioaddr, 0);
 	else
 		/* enable the clk prevously disabled */
-		clk_enable(priv->stmmac_clk);
+		clk_prepare_enable(priv->stmmac_clk);
 
 	netif_device_attach(ndev);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
index 2a0e1ab..4ccd4e2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
@@ -97,19 +97,19 @@
 static void stmmac_tmu_start(unsigned int new_freq)
 {
 	clk_set_rate(timer_clock, new_freq);
-	clk_enable(timer_clock);
+	clk_prepare_enable(timer_clock);
 }
 
 static void stmmac_tmu_stop(void)
 {
-	clk_disable(timer_clock);
+	clk_disable_unprepare(timer_clock);
 }
 
 int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
 {
 	timer_clock = clk_get(NULL, TMU_CHANNEL);
 
-	if (timer_clock == NULL)
+	if (IS_ERR(timer_clock))
 		return -1;
 
 	if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) {
@@ -126,7 +126,7 @@
 
 int stmmac_close_ext_timer(void)
 {
-	clk_disable(timer_clock);
+	clk_disable_unprepare(timer_clock);
 	tmu2_unregister_user();
 	clk_put(timer_clock);
 	return 0;
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index c2a0fe3..3208dca 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -9762,9 +9762,8 @@
 	union niu_parent_id parent_id;
 	struct net_device *dev;
 	struct niu *np;
-	int err, pos;
+	int err;
 	u64 dma_mask;
-	u16 val16;
 
 	niu_driver_version();
 
@@ -9787,8 +9786,7 @@
 		goto err_out_disable_pdev;
 	}
 
-	pos = pci_pcie_cap(pdev);
-	if (pos <= 0) {
+	if (!pci_is_pcie(pdev)) {
 		dev_err(&pdev->dev, "Cannot find PCI Express capability, aborting\n");
 		goto err_out_free_res;
 	}
@@ -9813,14 +9811,11 @@
 		goto err_out_free_dev;
 	}
 
-	pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
-	val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
-	val16 |= (PCI_EXP_DEVCTL_CERE |
-		  PCI_EXP_DEVCTL_NFERE |
-		  PCI_EXP_DEVCTL_FERE |
-		  PCI_EXP_DEVCTL_URRE |
-		  PCI_EXP_DEVCTL_RELAX_EN);
-	pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+		PCI_EXP_DEVCTL_NOSNOOP_EN,
+		PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+		PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE |
+		PCI_EXP_DEVCTL_RELAX_EN);
 
 	dma_mask = DMA_BIT_MASK(44);
 	err = pci_set_dma_mask(pdev, dma_mask);
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 256eddf..7951094 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -280,7 +280,7 @@
 	}
 
 	clk = clk_get(NULL, "irda_clk");
-	if (!clk) {
+	if (IS_ERR(clk)) {
 		dev_err(dev, "can not get irda_clk\n");
 		return -EIO;
 	}
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index 2346b38..7997895 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -229,3 +229,5 @@
 		ARRAY_SIZE(bcm87xx_driver));
 }
 module_exit(bcm87xx_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index cf287e0..2165d5f 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -21,6 +21,12 @@
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
 
+/* Operation Mode Strap Override */
+#define MII_KSZPHY_OMSO				0x16
+#define KSZPHY_OMSO_B_CAST_OFF			(1 << 9)
+#define KSZPHY_OMSO_RMII_OVERRIDE		(1 << 1)
+#define KSZPHY_OMSO_MII_OVERRIDE		(1 << 0)
+
 /* general Interrupt control/status reg in vendor specific block. */
 #define MII_KSZPHY_INTCS			0x1B
 #define	KSZPHY_INTCS_JABBER			(1 << 15)
@@ -101,6 +107,13 @@
 	return 0;
 }
 
+static int ksz8021_config_init(struct phy_device *phydev)
+{
+	const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
+	phy_write(phydev, MII_KSZPHY_OMSO, val);
+	return 0;
+}
+
 static int ks8051_config_init(struct phy_device *phydev)
 {
 	int regval;
@@ -128,9 +141,22 @@
 	.config_intr	= ks8737_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 }, {
-	.phy_id		= PHY_ID_KS8041,
+	.phy_id		= PHY_ID_KSZ8021,
+	.phy_id_mask	= 0x00ffffff,
+	.name		= "Micrel KSZ8021",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+			   SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= ksz8021_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+}, {
+	.phy_id		= PHY_ID_KSZ8041,
 	.phy_id_mask	= 0x00fffff0,
-	.name		= "Micrel KS8041",
+	.name		= "Micrel KSZ8041",
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
 				| SUPPORTED_Asym_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -141,9 +167,9 @@
 	.config_intr	= kszphy_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 }, {
-	.phy_id		= PHY_ID_KS8051,
+	.phy_id		= PHY_ID_KSZ8051,
 	.phy_id_mask	= 0x00fffff0,
-	.name		= "Micrel KS8051",
+	.name		= "Micrel KSZ8051",
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
 				| SUPPORTED_Asym_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -154,8 +180,8 @@
 	.config_intr	= kszphy_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 }, {
-	.phy_id		= PHY_ID_KS8001,
-	.name		= "Micrel KS8001 or KS8721",
+	.phy_id		= PHY_ID_KSZ8001,
+	.name		= "Micrel KSZ8001 or KS8721",
 	.phy_id_mask	= 0x00ffffff,
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -201,10 +227,11 @@
 
 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
 	{ PHY_ID_KSZ9021, 0x000ffffe },
-	{ PHY_ID_KS8001, 0x00ffffff },
+	{ PHY_ID_KSZ8001, 0x00ffffff },
 	{ PHY_ID_KS8737, 0x00fffff0 },
-	{ PHY_ID_KS8041, 0x00fffff0 },
-	{ PHY_ID_KS8051, 0x00fffff0 },
+	{ PHY_ID_KSZ8021, 0x00ffffff },
+	{ PHY_ID_KSZ8041, 0x00fffff0 },
+	{ PHY_ID_KSZ8051, 0x00fffff0 },
 	{ }
 };
 
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 6d61923..88e3991 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -56,6 +56,32 @@
 	return smsc_phy_ack_interrupt (phydev);
 }
 
+static int lan87xx_config_init(struct phy_device *phydev)
+{
+	/*
+	 * Make sure the EDPWRDOWN bit is NOT set. Setting this bit on
+	 * LAN8710/LAN8720 PHY causes the PHY to misbehave, likely due
+	 * to a bug on the chip.
+	 *
+	 * When the system is powered on with the network cable being
+	 * disconnected all the way until after ifconfig ethX up is
+	 * issued for the LAN port with this PHY, connecting the cable
+	 * afterwards does not cause LINK change detection, while the
+	 * expected behavior is the Link UP being detected.
+	 */
+	int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+	if (rc < 0)
+		return rc;
+
+	rc &= ~MII_LAN83C185_EDPWRDOWN;
+
+	rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, rc);
+	if (rc < 0)
+		return rc;
+
+	return smsc_phy_ack_interrupt(phydev);
+}
+
 static int lan911x_config_init(struct phy_device *phydev)
 {
 	return smsc_phy_ack_interrupt(phydev);
@@ -162,7 +188,7 @@
 	/* basic functions */
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.config_init	= smsc_phy_config_init,
+	.config_init	= lan87xx_config_init,
 
 	/* IRQ related */
 	.ack_interrupt	= smsc_phy_ack_interrupt,
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index cbf7047..20f31d0 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -570,7 +570,7 @@
 
 	po = pppox_sk(sk);
 
-	if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+	if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) {
 		dev_put(po->pppoe_dev);
 		po->pppoe_dev = NULL;
 	}
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 341b65d..f8cd61f 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -848,7 +848,7 @@
 }
 #endif
 
-static void __team_port_change_check(struct team_port *port, bool linkup);
+static void __team_port_change_port_added(struct team_port *port, bool linkup);
 
 static int team_port_add(struct team *team, struct net_device *port_dev)
 {
@@ -948,7 +948,7 @@
 	team_port_enable(team, port);
 	list_add_tail_rcu(&port->list, &team->port_list);
 	__team_compute_features(team);
-	__team_port_change_check(port, !!netif_carrier_ok(port_dev));
+	__team_port_change_port_added(port, !!netif_carrier_ok(port_dev));
 	__team_options_change_check(team);
 
 	netdev_info(dev, "Port device %s added\n", portname);
@@ -983,6 +983,8 @@
 	return err;
 }
 
+static void __team_port_change_port_removed(struct team_port *port);
+
 static int team_port_del(struct team *team, struct net_device *port_dev)
 {
 	struct net_device *dev = team->dev;
@@ -999,8 +1001,7 @@
 	__team_option_inst_mark_removed_port(team, port);
 	__team_options_change_check(team);
 	__team_option_inst_del_port(team, port);
-	port->removed = true;
-	__team_port_change_check(port, false);
+	__team_port_change_port_removed(port);
 	team_port_disable(team, port);
 	list_del_rcu(&port->list);
 	netdev_rx_handler_unregister(port_dev);
@@ -1652,8 +1653,8 @@
 
 	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
 			  &team_nl_family, 0, TEAM_CMD_NOOP);
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -EMSGSIZE;
 		goto err_msg_put;
 	}
 
@@ -1847,8 +1848,8 @@
 
 	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags | NLM_F_MULTI,
 			  TEAM_CMD_OPTIONS_GET);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
 		goto nla_put_failure;
@@ -2067,8 +2068,8 @@
 
 	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
 			  TEAM_CMD_PORT_LIST_GET);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
 		goto nla_put_failure;
@@ -2251,13 +2252,11 @@
 }
 
 /* rtnl lock is held */
-static void __team_port_change_check(struct team_port *port, bool linkup)
+
+static void __team_port_change_send(struct team_port *port, bool linkup)
 {
 	int err;
 
-	if (!port->removed && port->state.linkup == linkup)
-		return;
-
 	port->changed = true;
 	port->state.linkup = linkup;
 	team_refresh_port_linkup(port);
@@ -2282,6 +2281,23 @@
 
 }
 
+static void __team_port_change_check(struct team_port *port, bool linkup)
+{
+	if (port->state.linkup != linkup)
+		__team_port_change_send(port, linkup);
+}
+
+static void __team_port_change_port_added(struct team_port *port, bool linkup)
+{
+	__team_port_change_send(port, linkup);
+}
+
+static void __team_port_change_port_removed(struct team_port *port)
+{
+	port->removed = true;
+	__team_port_change_send(port, false);
+}
+
 static void team_port_change_check(struct team_port *port, bool linkup)
 {
 	struct team *team = port->team;
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 4fd48df..32e31c5 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -962,6 +962,10 @@
 	USB_DEVICE (0x2001, 0x3c05),
 	.driver_info = (unsigned long) &ax88772_info,
 }, {
+       // DLink DUB-E100 H/W Ver C1
+       USB_DEVICE (0x2001, 0x1a02),
+       .driver_info = (unsigned long) &ax88772_info,
+}, {
 	// Linksys USB1000
 	USB_DEVICE (0x1737, 0x0039),
 	.driver_info = (unsigned long) &ax88178_info,
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index b1ba68f1..3543c9e 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -366,16 +366,20 @@
 	},
 
 	/* 2. Combined interface devices matching on class+protocol */
+	{	/* Huawei E367 and possibly others in "Windows mode" */
+		USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 7),
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
 	{	/* Huawei E392, E398 and possibly others in "Windows mode" */
 		USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
 		.driver_info        = (unsigned long)&qmi_wwan_shared,
 	},
-	{	/* Pantech UML290 */
-		USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
+	{	/* Pantech UML290, P4200 and more */
+		USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
 		.driver_info        = (unsigned long)&qmi_wwan_shared,
 	},
 	{	/* Pantech UML290 - newer firmware */
-		USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
+		USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
 		.driver_info        = (unsigned long)&qmi_wwan_shared,
 	},
 
@@ -383,6 +387,7 @@
 	{QMI_FIXED_INTF(0x19d2, 0x0055, 1)},	/* ZTE (Vodafone) K3520-Z */
 	{QMI_FIXED_INTF(0x19d2, 0x0063, 4)},	/* ZTE (Vodafone) K3565-Z */
 	{QMI_FIXED_INTF(0x19d2, 0x0104, 4)},	/* ZTE (Vodafone) K4505-Z */
+	{QMI_FIXED_INTF(0x19d2, 0x0157, 5)},	/* ZTE MF683 */
 	{QMI_FIXED_INTF(0x19d2, 0x0167, 4)},	/* ZTE MF820D */
 	{QMI_FIXED_INTF(0x19d2, 0x0326, 4)},	/* ZTE MF821D */
 	{QMI_FIXED_INTF(0x19d2, 0x1008, 4)},	/* ZTE (Vodafone) K3570-Z */
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index f5ab6e6..376143e 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1253,6 +1253,7 @@
 	.probe		= usbnet_probe,
 	.suspend	= usbnet_suspend,
 	.resume		= usbnet_resume,
+	.reset_resume	= usbnet_resume,
 	.disconnect	= usbnet_disconnect,
 	.disable_hub_initiated_lpm = 1,
 };
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 2588848..d066f25 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -2982,6 +2982,10 @@
 	case EEP_RX_MASK:
 		return pBase->txrxMask & 0xf;
 	case EEP_PAPRD:
+		if (AR_SREV_9462(ah))
+			return false;
+		if (!ah->config.enable_paprd);
+			return false;
 		return !!(pBase->featureEnable & BIT(5));
 	case EEP_CHAIN_MASK_REDUCE:
 		return (pBase->miscConfiguration >> 0x3) & 0x1;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 68b643c..c8ef301 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1577,6 +1577,8 @@
 			    sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
 	debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
 			    sc->debug.debugfs_phy, sc, &fops_disable_ani);
+	debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    &sc->sc_ah->config.enable_paprd);
 	debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
 			    sc, &fops_regidx);
 	debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 48af401..4faf0a3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2497,10 +2497,6 @@
 		pCap->rx_status_len = sizeof(struct ar9003_rxs);
 		pCap->tx_desc_len = sizeof(struct ar9003_txc);
 		pCap->txs_len = sizeof(struct ar9003_txs);
-		if (!ah->config.paprd_disable &&
-		    ah->eep_ops->get_eeprom(ah, EEP_PAPRD) &&
-		    !AR_SREV_9462(ah))
-			pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
 	} else {
 		pCap->tx_desc_len = sizeof(struct ath_desc);
 		if (AR_SREV_9280_20(ah))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 6599a75..de6968f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -236,7 +236,6 @@
 	ATH9K_HW_CAP_LDPC			= BIT(6),
 	ATH9K_HW_CAP_FASTCLOCK			= BIT(7),
 	ATH9K_HW_CAP_SGI_20			= BIT(8),
-	ATH9K_HW_CAP_PAPRD			= BIT(9),
 	ATH9K_HW_CAP_ANT_DIV_COMB		= BIT(10),
 	ATH9K_HW_CAP_2GHZ			= BIT(11),
 	ATH9K_HW_CAP_5GHZ			= BIT(12),
@@ -287,12 +286,12 @@
 	u8 pcie_clock_req;
 	u32 pcie_waen;
 	u8 analog_shiftreg;
-	u8 paprd_disable;
 	u32 ofdm_trig_low;
 	u32 ofdm_trig_high;
 	u32 cck_trig_high;
 	u32 cck_trig_low;
 	u32 enable_ani;
+	u32 enable_paprd;
 	int serialize_regmode;
 	bool rx_intr_mitigation;
 	bool tx_intr_mitigation;
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 825a29c..7b88b9c 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -423,7 +423,7 @@
 		cal_interval = min(cal_interval, (u32)short_cal_interval);
 
 	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+	if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) {
 		if (!ah->caldata->paprd_done)
 			ieee80211_queue_work(sc->hw, &sc->paprd_work);
 		else if (!ah->paprd_table_write_done)
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index a978984..ef11dc6 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -113,41 +113,32 @@
 	struct ath_hw *ah = sc->sc_ah;
 	struct pci_dev *pdev = to_pci_dev(sc->dev);
 	struct pci_dev *parent;
-	int pos;
-	u8 aspm;
+	u16 aspm;
 
 	if (!ah->is_pciexpress)
 		return;
 
-	pos = pci_pcie_cap(pdev);
-	if (!pos)
-		return;
-
 	parent = pdev->bus->self;
 	if (!parent)
 		return;
 
 	if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
 		/* Bluetooth coexistance requires disabling ASPM. */
-		pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
-		aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
-		pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
+		pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
+			PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 		/*
 		 * Both upstream and downstream PCIe components should
 		 * have the same ASPM settings.
 		 */
-		pos = pci_pcie_cap(parent);
-		pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
-		aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
-		pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
+		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
+			PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 		ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
 		return;
 	}
 
-	pos = pci_pcie_cap(parent);
-	pci_read_config_byte(parent, pos +  PCI_EXP_LNKCTL, &aspm);
+	pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm);
 	if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
 		ah->aspm_enabled = true;
 		/* Initialize PCIe PM and SERDES registers. */
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 3876c7e..7a28d21 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -34,8 +34,8 @@
 config B43_BCMA_EXTRA
 	bool "Hardware support that overlaps with the brcmsmac driver"
 	depends on B43_BCMA
-	default n if BRCMSMAC || BRCMSMAC_MODULE
-	default	y
+	default n if BRCMSMAC
+	default y
 
 config B43_SSB
 	bool
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index 49765d3..7c4ee72 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -638,6 +638,8 @@
 
 		oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq),
 				       GFP_KERNEL);
+		if (!oobirq_entry)
+			return -ENOMEM;
 		oobirq_entry->irq = res->start;
 		oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK;
 		list_add_tail(&oobirq_entry->list, &oobirq_lh);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index 2621dd3..6f70953 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -764,8 +764,11 @@
 {
 	char iovbuf[32];
 	int retcode;
+	__le32 arp_mode_le;
 
-	brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+	arp_mode_le = cpu_to_le32(arp_mode);
+	brcmf_c_mkiovar("arp_ol", (char *)&arp_mode_le, 4, iovbuf,
+			sizeof(iovbuf));
 	retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
 				   iovbuf, sizeof(iovbuf));
 	retcode = retcode >= 0 ? 0 : retcode;
@@ -781,8 +784,11 @@
 {
 	char iovbuf[32];
 	int retcode;
+	__le32 arp_enable_le;
 
-	brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4,
+	arp_enable_le = cpu_to_le32(arp_enable);
+
+	brcmf_c_mkiovar("arpoe", (char *)&arp_enable_le, 4,
 			iovbuf, sizeof(iovbuf));
 	retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
 				   iovbuf, sizeof(iovbuf));
@@ -800,10 +806,10 @@
 	char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];	/*  Room for
 				 "event_msgs" + '\0' + bitvec  */
 	char buf[128], *ptr;
-	u32 roaming = 1;
-	uint bcn_timeout = 3;
-	int scan_assoc_time = 40;
-	int scan_unassoc_time = 40;
+	__le32 roaming_le = cpu_to_le32(1);
+	__le32 bcn_timeout_le = cpu_to_le32(3);
+	__le32 scan_assoc_time_le = cpu_to_le32(40);
+	__le32 scan_unassoc_time_le = cpu_to_le32(40);
 	int i;
 	struct brcmf_bus_dcmd *cmdlst;
 	struct list_head *cur, *q;
@@ -829,14 +835,14 @@
 
 	/* Setup timeout if Beacons are lost and roam is off to report
 		 link down */
-	brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
+	brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout_le, 4, iovbuf,
 		    sizeof(iovbuf));
 	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
 				  sizeof(iovbuf));
 
 	/* Enable/Disable build-in roaming to allowed ext supplicant to take
 		 of romaing */
-	brcmf_c_mkiovar("roam_off", (char *)&roaming, 4,
+	brcmf_c_mkiovar("roam_off", (char *)&roaming_le, 4,
 		      iovbuf, sizeof(iovbuf));
 	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
 				  sizeof(iovbuf));
@@ -848,9 +854,9 @@
 				  sizeof(iovbuf));
 
 	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
-			 (char *)&scan_assoc_time, sizeof(scan_assoc_time));
+		 (char *)&scan_assoc_time_le, sizeof(scan_assoc_time_le));
 	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
-			 (char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
+		 (char *)&scan_unassoc_time_le, sizeof(scan_unassoc_time_le));
 
 	/* Set and enable ARP offload feature */
 	brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index c36e923..50b5553 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -500,8 +500,10 @@
 	params_le->active_time = cpu_to_le32(-1);
 	params_le->passive_time = cpu_to_le32(-1);
 	params_le->home_time = cpu_to_le32(-1);
-	if (ssid && ssid->SSID_len)
-		memcpy(&params_le->ssid_le, ssid, sizeof(struct brcmf_ssid));
+	if (ssid && ssid->SSID_len) {
+		params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len);
+		memcpy(&params_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len);
+	}
 }
 
 static s32
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 7ed7d75..64a48f0 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -77,7 +77,7 @@
 					 NL80211_RRF_NO_IBSS)
 
 static const struct ieee80211_regdomain brcms_regdom_x2 = {
-	.n_reg_rules = 7,
+	.n_reg_rules = 6,
 	.alpha2 = "X2",
 	.reg_rules = {
 		BRCM_2GHZ_2412_2462,
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index 5f50177..7246826 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1832,10 +1832,8 @@
 static inline u16
 il_pcie_link_ctl(struct il_priv *il)
 {
-	int pos;
 	u16 pci_lnk_ctl;
-	pos = pci_pcie_cap(il->pci_dev);
-	pci_read_config_word(il->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+	pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &pci_lnk_ctl);
 	return pci_lnk_ctl;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 1e86ea2..063ecaf 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -675,13 +675,10 @@
 static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	int pos;
 	u16 pci_lnk_ctl;
 
-	struct pci_dev *pci_dev = trans_pcie->pci_dev;
-
-	pos = pci_pcie_cap(pci_dev);
-	pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+	pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL,
+				  &pci_lnk_ctl);
 	return pci_lnk_ctl;
 }
 
@@ -1442,6 +1439,7 @@
 	return err;
 
 err_free_irq:
+	trans_pcie->irq_requested = false;
 	free_irq(trans_pcie->irq, trans);
 error:
 	iwl_free_isr_ict(trans);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 80f75d3..5983631a 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -372,13 +372,11 @@
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 
 	u8 tmp;
-	int pos;
-	u8 linkctrl_reg;
+	u16 linkctrl_reg;
 
 	/*Link Control Register */
-	pos = pci_pcie_cap(pdev);
-	pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
-	pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;
+	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &linkctrl_reg);
+	pcipriv->ndis_adapter.linkctrl_reg = (u8)linkctrl_reg;
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n",
 		 pcipriv->ndis_adapter.linkctrl_reg);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 44febfd..8a7b864 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -315,7 +315,7 @@
 	u16 box_reg = 0, box_extreg = 0;
 	u8 u1b_tmp;
 	bool isfw_read = false;
-	bool bwrite_sucess = false;
+	bool bwrite_success = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[2];
@@ -354,7 +354,7 @@
 		}
 	}
 
-	while (!bwrite_sucess) {
+	while (!bwrite_success) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -491,7 +491,7 @@
 			break;
 		}
 
-		bwrite_sucess = true;
+		bwrite_success = true;
 
 		rtlhal->last_hmeboxnum = boxnum + 1;
 		if (rtlhal->last_hmeboxnum == 4)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 04c3aef..2925094 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -117,6 +117,7 @@
 
 #define CHIP_VER_B			BIT(4)
 #define CHIP_92C_BITMASK		BIT(0)
+#define CHIP_UNKNOWN			BIT(7)
 #define CHIP_92C_1T2R			0x03
 #define CHIP_92C			0x01
 #define CHIP_88C			0x00
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index bd0da7e..dd4bb09 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -994,8 +994,16 @@
 		version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C :
 			   VERSION_A_CHIP_88C;
 	} else {
-		version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C :
-			   VERSION_B_CHIP_88C;
+		version = (enum version_8192c) (CHIP_VER_B |
+				((value32 & TYPE_ID) ? CHIP_92C_BITMASK : 0) |
+				((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+		if ((!IS_CHIP_VENDOR_UMC(version)) && (value32 &
+		     CHIP_VER_RTL_MASK)) {
+			version = (enum version_8192c)(version |
+				   ((((value32 & CHIP_VER_RTL_MASK) == BIT(12))
+				   ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) |
+				   CHIP_VENDOR_UMC));
+		}
 	}
 
 	switch (version) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 3aa927f..7d8f964 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -162,10 +162,12 @@
 
 	/* request fw */
 	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
-	    !IS_92C_SERIAL(rtlhal->version))
+	    !IS_92C_SERIAL(rtlhal->version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
-	else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+		pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n");
+	}
 
 	rtlpriv->max_fw_size = 0x4000;
 	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
index 895ae6c..eb22dcc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
@@ -365,7 +365,7 @@
 	u8 u1b_tmp;
 	bool isfw_read = false;
 	u8 buf_index = 0;
-	bool bwrite_sucess = false;
+	bool bwrite_success = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[2];
@@ -408,7 +408,7 @@
 			break;
 		}
 	}
-	while (!bwrite_sucess) {
+	while (!bwrite_success) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -515,7 +515,7 @@
 				 "switch case not processed\n");
 			break;
 		}
-		bwrite_sucess = true;
+		bwrite_success = true;
 		rtlhal->last_hmeboxnum = boxnum + 1;
 		if (rtlhal->last_hmeboxnum == 4)
 			rtlhal->last_hmeboxnum = 0;
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index b8ef8dd..8aa73fa 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -451,14 +451,9 @@
 {
 	struct oprofile_cpu_buffer *b =
 		container_of(work, struct oprofile_cpu_buffer, work.work);
-	if (b->cpu != smp_processor_id()) {
-		printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
-		       smp_processor_id(), b->cpu);
-
-		if (!cpu_online(b->cpu)) {
-			cancel_delayed_work(&b->work);
-			return;
-		}
+	if (b->cpu != smp_processor_id() && !cpu_online(b->cpu)) {
+		cancel_delayed_work(&b->work);
+		return;
 	}
 	sync_buffer(b->cpu);
 
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index ffddc4f..fb6a1fe 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -477,14 +477,12 @@
 	if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB,
 				F_EXTEND(0xf0000000UL) | _8MB,
 				F_EXTEND(0xffffffffUL) &~ _8MB, _8MB) < 0) {
-		struct list_head *ln, *tmp_ln;
+		struct pci_dev *dev, *tmp;
 
 		printk(KERN_ERR "Dino: cannot attach bus %s\n",
 		       dev_name(bus->bridge));
 		/* kill the bus, we can't do anything with it */
-		list_for_each_safe(ln, tmp_ln, &bus->devices) {
-			struct pci_dev *dev = pci_dev_b(ln);
-
+		list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
 			list_del(&dev->bus_list);
 		}
 			
@@ -549,7 +547,6 @@
 static void __init
 dino_fixup_bus(struct pci_bus *bus)
 {
-	struct list_head *ln;
         struct pci_dev *dev;
         struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
 
@@ -596,8 +593,7 @@
 	}
 
 
-	list_for_each(ln, &bus->devices) {
-		dev = pci_dev_b(ln);
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		if (is_card_dino(&dino_dev->hba.dev->id))
 			dino_card_fixup(dev);
 
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 4f9cf24..fdd63a6 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -629,7 +629,7 @@
 static void
 lba_fixup_bus(struct pci_bus *bus)
 {
-	struct list_head *ln;
+	struct pci_dev *dev;
 #ifdef FBB_SUPPORT
 	u16 status;
 #endif
@@ -710,9 +710,8 @@
 
 	}
 
-	list_for_each(ln, &bus->devices) {
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		int i;
-		struct pci_dev *dev = pci_dev_b(ln);
 
 		DBG("lba_fixup_bus() %s\n", pci_name(dev));
 
@@ -770,7 +769,7 @@
 	}
 
 	/* Lastly enable FBB/PERR/SERR on all devices too */
-	list_for_each(ln, &bus->devices) {
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		(void) pci_read_config_word(dev, PCI_COMMAND, &status);
 		status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable;
 		(void) pci_write_config_word(dev, PCI_COMMAND, status);
diff --git a/drivers/pci/.gitignore b/drivers/pci/.gitignore
deleted file mode 100644
index f297ca8..0000000
--- a/drivers/pci/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-classlist.h
-devlist.h
-gen-devlist
-
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 848bfb8..6d51aa6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -3,7 +3,6 @@
 #
 config ARCH_SUPPORTS_MSI
 	bool
-	default n
 
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index ba91a7e..3af0478 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -469,3 +469,205 @@
 	raw_spin_unlock_irqrestore(&pci_lock, flags);
 }
 EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
+
+static inline int pcie_cap_version(const struct pci_dev *dev)
+{
+	return dev->pcie_flags_reg & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
+{
+	return true;
+}
+
+static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+
+	return pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       type == PCI_EXP_TYPE_ENDPOINT ||
+	       type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+
+	return pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       (type == PCI_EXP_TYPE_DOWNSTREAM &&
+		dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+
+	return pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       type == PCI_EXP_TYPE_RC_EC;
+}
+
+static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+	if (!pci_is_pcie(dev))
+		return false;
+
+	switch (pos) {
+	case PCI_EXP_FLAGS_TYPE:
+		return true;
+	case PCI_EXP_DEVCAP:
+	case PCI_EXP_DEVCTL:
+	case PCI_EXP_DEVSTA:
+		return pcie_cap_has_devctl(dev);
+	case PCI_EXP_LNKCAP:
+	case PCI_EXP_LNKCTL:
+	case PCI_EXP_LNKSTA:
+		return pcie_cap_has_lnkctl(dev);
+	case PCI_EXP_SLTCAP:
+	case PCI_EXP_SLTCTL:
+	case PCI_EXP_SLTSTA:
+		return pcie_cap_has_sltctl(dev);
+	case PCI_EXP_RTCTL:
+	case PCI_EXP_RTCAP:
+	case PCI_EXP_RTSTA:
+		return pcie_cap_has_rtctl(dev);
+	case PCI_EXP_DEVCAP2:
+	case PCI_EXP_DEVCTL2:
+	case PCI_EXP_LNKCAP2:
+	case PCI_EXP_LNKCTL2:
+	case PCI_EXP_LNKSTA2:
+		return pcie_cap_version(dev) > 1;
+	default:
+		return false;
+	}
+}
+
+/*
+ * Note that these accessor functions are only for the "PCI Express
+ * Capability" (see PCIe spec r3.0, sec 7.8).  They do not apply to the
+ * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
+ */
+int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
+{
+	int ret;
+
+	*val = 0;
+	if (pos & 1)
+		return -EINVAL;
+
+	if (pcie_capability_reg_implemented(dev, pos)) {
+		ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
+		/*
+		 * Reset *val to 0 if pci_read_config_word() fails, it may
+		 * have been written as 0xFFFF if hardware error happens
+		 * during pci_read_config_word().
+		 */
+		if (ret)
+			*val = 0;
+		return ret;
+	}
+
+	/*
+	 * For Functions that do not implement the Slot Capabilities,
+	 * Slot Status, and Slot Control registers, these spaces must
+	 * be hardwired to 0b, with the exception of the Presence Detect
+	 * State bit in the Slot Status register of Downstream Ports,
+	 * which must be hardwired to 1b.  (PCIe Base Spec 3.0, sec 7.8)
+	 */
+	if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
+		 pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+		*val = PCI_EXP_SLTSTA_PDS;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pcie_capability_read_word);
+
+int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
+{
+	int ret;
+
+	*val = 0;
+	if (pos & 3)
+		return -EINVAL;
+
+	if (pcie_capability_reg_implemented(dev, pos)) {
+		ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+		/*
+		 * Reset *val to 0 if pci_read_config_dword() fails, it may
+		 * have been written as 0xFFFFFFFF if hardware error happens
+		 * during pci_read_config_dword().
+		 */
+		if (ret)
+			*val = 0;
+		return ret;
+	}
+
+	if (pci_is_pcie(dev) && pos == PCI_EXP_SLTCTL &&
+		 pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+		*val = PCI_EXP_SLTSTA_PDS;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pcie_capability_read_dword);
+
+int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
+{
+	if (pos & 1)
+		return -EINVAL;
+
+	if (!pcie_capability_reg_implemented(dev, pos))
+		return 0;
+
+	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
+}
+EXPORT_SYMBOL(pcie_capability_write_word);
+
+int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
+{
+	if (pos & 3)
+		return -EINVAL;
+
+	if (!pcie_capability_reg_implemented(dev, pos))
+		return 0;
+
+	return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+}
+EXPORT_SYMBOL(pcie_capability_write_dword);
+
+int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+				       u16 clear, u16 set)
+{
+	int ret;
+	u16 val;
+
+	ret = pcie_capability_read_word(dev, pos, &val);
+	if (!ret) {
+		val &= ~clear;
+		val |= set;
+		ret = pcie_capability_write_word(dev, pos, val);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(pcie_capability_clear_and_set_word);
+
+int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
+					u32 clear, u32 set)
+{
+	int ret;
+	u32 val;
+
+	ret = pcie_capability_read_dword(dev, pos, &val);
+	if (!ret) {
+		val &= ~clear;
+		val |= set;
+		ret = pcie_capability_write_dword(dev, pos, val);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 4b0970b..6241fd0 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -87,11 +87,15 @@
 void pci_bus_remove_resources(struct pci_bus *bus)
 {
 	int i;
+	struct pci_bus_resource *bus_res, *tmp;
 
 	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
 		bus->resource[i] = NULL;
 
-	pci_free_resource_list(&bus->resources);
+	list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
+		list_del(&bus_res->list);
+		kfree(bus_res);
+	}
 }
 
 /**
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 66f29bc..b0e46de 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -17,28 +17,6 @@
 
 if HOTPLUG_PCI
 
-config HOTPLUG_PCI_FAKE
-	tristate "Fake PCI Hotplug driver"
-	help
-	  Say Y here if you want to use the fake PCI hotplug driver. It can
-	  be used to simulate PCI hotplug events if even if your system is
-	  not PCI hotplug capable.
-
-	  This driver will "emulate" removing PCI devices from the system.
-	  If the "power" file is written to with "0" then the specified PCI
-	  device will be completely removed from the kernel.
-
-	  WARNING, this does NOT turn off the power to the PCI device.
-	  This is a "logical" removal, not a physical or electrical
-	  removal.
-
-	  Use this module at your own risk.  You have been warned!
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called fakephp.
-
-	  When in doubt, say N.
-
 config HOTPLUG_PCI_COMPAQ
 	tristate "Compaq PCI Hotplug driver"
 	depends on X86 && PCI_BIOS
@@ -143,7 +121,7 @@
 
 config HOTPLUG_PCI_RPA
 	tristate "RPA PCI Hotplug driver"
-	depends on PPC_PSERIES && EEH && !HOTPLUG_PCI_FAKE
+	depends on PPC_PSERIES && EEH
 	help
 	  Say Y here if you have a RPA system that supports PCI Hotplug.
 
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 6cd9f3c..c459cd4 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -23,9 +23,6 @@
 
 obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM)	+= acpiphp_ibm.o
 
-# Link this last so it doesn't claim devices that have a real hotplug driver
-obj-$(CONFIG_HOTPLUG_PCI_FAKE)		+= fakephp.o
-
 pci_hotplug-objs	:=	pci_hotplug_core.o pcihp_slot.o
 
 ifdef CONFIG_HOTPLUG_PCI_CPCI
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index ad6fd66..3d6d4fd 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -115,6 +115,35 @@
 	.handler = handle_hotplug_event_func,
 };
 
+/* Check whether the PCI device is managed by native PCIe hotplug driver */
+static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
+{
+	u32 reg32;
+	acpi_handle tmp;
+	struct acpi_pci_root *root;
+
+	/* Check whether the PCIe port supports native PCIe hotplug */
+	if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &reg32))
+		return false;
+	if (!(reg32 & PCI_EXP_SLTCAP_HPC))
+		return false;
+
+	/*
+	 * Check whether native PCIe hotplug has been enabled for
+	 * this PCIe hierarchy.
+	 */
+	tmp = acpi_find_root_bridge_handle(pdev);
+	if (!tmp)
+		return false;
+	root = acpi_pci_find_root(tmp);
+	if (!root)
+		return false;
+	if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
+		return false;
+
+	return true;
+}
+
 /* callback routine to register each ACPI PCI slot object */
 static acpi_status
 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -142,16 +171,8 @@
 	function = adr & 0xffff;
 
 	pdev = pbus->self;
-	if (pdev && pci_is_pcie(pdev)) {
-		tmp = acpi_find_root_bridge_handle(pdev);
-		if (tmp) {
-			struct acpi_pci_root *root = acpi_pci_find_root(tmp);
-
-			if (root && (root->osc_control_set &
-					OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
-				return AE_OK;
-		}
-	}
+	if (pdev && device_is_managed_by_native_pciehp(pdev))
+		return AE_OK;
 
 	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
 	if (!newfunc)
@@ -382,10 +403,10 @@
 
 
 /* allocate and initialize host bridge data structure */
-static void add_host_bridge(acpi_handle *handle)
+static void add_host_bridge(struct acpi_pci_root *root)
 {
 	struct acpiphp_bridge *bridge;
-	struct acpi_pci_root *root = acpi_pci_find_root(handle);
+	acpi_handle handle = root->device->handle;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
 	if (bridge == NULL)
@@ -468,11 +489,12 @@
 
 
 /* find hot-pluggable slots, and then find P2P bridge */
-static int add_bridge(acpi_handle handle)
+static int add_bridge(struct acpi_pci_root *root)
 {
 	acpi_status status;
 	unsigned long long tmp;
 	acpi_handle dummy_handle;
+	acpi_handle handle = root->device->handle;
 
 	/* if the bridge doesn't have _STA, we assume it is always there */
 	status = acpi_get_handle(handle, "_STA", &dummy_handle);
@@ -490,7 +512,7 @@
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
 		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
-		add_host_bridge(handle);
+		add_host_bridge(root);
 	}
 
 	/* search P2P bridges under this host bridge */
@@ -588,9 +610,10 @@
 	return AE_OK;
 }
 
-static void remove_bridge(acpi_handle handle)
+static void remove_bridge(struct acpi_pci_root *root)
 {
 	struct acpiphp_bridge *bridge;
+	acpi_handle handle = root->device->handle;
 
 	/* cleanup p2p bridges under this host bridge
 	   in a depth-first manner */
@@ -869,17 +892,6 @@
 	return retval;
 }
 
-static void disable_bridges(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		if (dev->subordinate) {
-			disable_bridges(dev->subordinate);
-			pci_disable_device(dev);
-		}
-	}
-}
-
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
@@ -931,12 +943,7 @@
 	 * here.
 	 */
 	while ((pdev = dev_in_slot(slot))) {
-		pci_stop_bus_device(pdev);
-		if (pdev->subordinate) {
-			disable_bridges(pdev->subordinate);
-			pci_disable_device(pdev);
-		}
-		__pci_remove_bus_device(pdev);
+		pci_stop_and_remove_bus_device(pdev);
 		pci_dev_put(pdev);
 	}
 
@@ -1477,34 +1484,6 @@
 }
 
 
-#if 0
-/**
- * acpiphp_for_each_slot - call function for each slot
- * @fn: callback function
- * @data: context to be passed to callback function
- */
-static int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
-{
-	struct list_head *node;
-	struct acpiphp_bridge *bridge;
-	struct acpiphp_slot *slot;
-	int retval = 0;
-
-	list_for_each (node, &bridge_list) {
-		bridge = (struct acpiphp_bridge *)node;
-		for (slot = bridge->slots; slot; slot = slot->next) {
-			retval = fn(slot, data);
-			if (!retval)
-				goto err_exit;
-		}
-	}
-
- err_exit:
-	return retval;
-}
-#endif
-
-
 /**
  * acpiphp_enable_slot - power on slot
  * @slot: ACPI PHP slot
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index 81af764..a6a71c4 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -154,12 +154,8 @@
 	if(!r)
 		return -EBUSY;
 
-	bus = pci_find_bus(0, bridge_busnr);
-	if (!bus) {
-		err("Invalid bus number %d", bridge_busnr);
-		return -EINVAL;
-	}
-	dev = pci_get_slot(bus, PCI_DEVFN(bridge_slot, 0));
+	dev = pci_get_domain_bus_and_slot(0, bridge_busnr,
+					  PCI_DEVFN(bridge_slot, 0));
 	if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
 		err("Invalid bridge device %s", bridge);
 		pci_dev_put(dev);
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index e43908d..36112fe 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -2890,27 +2890,8 @@
 						func->mem_head = mem_node;
 					} else
 						return -ENOMEM;
-				} else if ((temp_register & 0x0BL) == 0x04) {
-					/* Map memory */
-					base = temp_register & 0xFFFFFFF0;
-					base = ~base + 1;
-
-					dbg("CND:      length = 0x%x\n", base);
-					mem_node = get_resource(&(resources->mem_head), base);
-
-					/* allocate the resource to the board */
-					if (mem_node) {
-						base = mem_node->base;
-
-						mem_node->next = func->mem_head;
-						func->mem_head = mem_node;
-					} else
-						return -ENOMEM;
-				} else if ((temp_register & 0x0BL) == 0x06) {
-					/* Those bits are reserved, we can't handle this */
-					return 1;
 				} else {
-					/* Requesting space below 1M */
+					/* Reserved bits or requesting space below 1M */
 					return NOT_ENOUGH_RESOURCES;
 				}
 
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
deleted file mode 100644
index a019c9a..0000000
--- a/drivers/pci/hotplug/fakephp.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Works like the fakephp driver used to, except a little better.
- *
- * - It's possible to remove devices with subordinate busses.
- * - New PCI devices that appear via any method, not just a fakephp triggered
- *   rescan, will be noticed.
- * - Devices that are removed via any method, not just a fakephp triggered
- *   removal, will also be noticed.
- *
- * Uses nothing from the pci-hotplug subsystem.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include "../pci.h"
-
-struct legacy_slot {
-	struct kobject		kobj;
-	struct pci_dev		*dev;
-	struct list_head	list;
-};
-
-static LIST_HEAD(legacy_list);
-
-static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr,
-			   char *buf)
-{
-	struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
-	strcpy(buf, "1\n");
-	return 2;
-}
-
-static void remove_callback(void *data)
-{
-	pci_stop_and_remove_bus_device((struct pci_dev *)data);
-}
-
-static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
-			    const char *buf, size_t len)
-{
-	struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
-	unsigned long val;
-
-	if (strict_strtoul(buf, 0, &val) < 0)
-		return -EINVAL;
-
-	if (val)
-		pci_rescan_bus(slot->dev->bus);
-	else
-		sysfs_schedule_callback(&slot->dev->dev.kobj, remove_callback,
-					slot->dev, THIS_MODULE);
-	return len;
-}
-
-static struct attribute *legacy_attrs[] = {
-	&(struct attribute){ .name = "power", .mode = 0644 },
-	NULL,
-};
-
-static void legacy_release(struct kobject *kobj)
-{
-	struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
-
-	pci_dev_put(slot->dev);
-	kfree(slot);
-}
-
-static struct kobj_type legacy_ktype = {
-	.sysfs_ops = &(const struct sysfs_ops){
-		.store = legacy_store, .show = legacy_show
-	},
-	.release = &legacy_release,
-	.default_attrs = legacy_attrs,
-};
-
-static int legacy_add_slot(struct pci_dev *pdev)
-{
-	struct legacy_slot *slot = kzalloc(sizeof(*slot), GFP_KERNEL);
-
-	if (!slot)
-		return -ENOMEM;
-
-	if (kobject_init_and_add(&slot->kobj, &legacy_ktype,
-				 &pci_slots_kset->kobj, "%s",
-				 dev_name(&pdev->dev))) {
-		dev_warn(&pdev->dev, "Failed to created legacy fake slot\n");
-		return -EINVAL;
-	}
-	slot->dev = pci_dev_get(pdev);
-
-	list_add(&slot->list, &legacy_list);
-
-	return 0;
-}
-
-static int legacy_notify(struct notifier_block *nb,
-			 unsigned long action, void *data)
-{
-	struct pci_dev *pdev = to_pci_dev(data);
-
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		legacy_add_slot(pdev);
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		struct legacy_slot *slot;
-
-		list_for_each_entry(slot, &legacy_list, list)
-			if (slot->dev == pdev)
-				goto found;
-
-		dev_warn(&pdev->dev, "Missing legacy fake slot?");
-		return -ENODEV;
-found:
-		kobject_del(&slot->kobj);
-		list_del(&slot->list);
-		kobject_put(&slot->kobj);
-	}
-
-	return 0;
-}
-
-static struct notifier_block legacy_notifier = {
-	.notifier_call = legacy_notify
-};
-
-static int __init init_legacy(void)
-{
-	struct pci_dev *pdev = NULL;
-
-	/* Add existing devices */
-	for_each_pci_dev(pdev)
-		legacy_add_slot(pdev);
-
-	/* Be alerted of any new ones */
-	bus_register_notifier(&pci_bus_type, &legacy_notifier);
-	return 0;
-}
-module_init(init_legacy);
-
-static void __exit remove_legacy(void)
-{
-	struct legacy_slot *slot, *tmp;
-
-	bus_unregister_notifier(&pci_bus_type, &legacy_notifier);
-
-	list_for_each_entry_safe(slot, tmp, &legacy_list, list) {
-		list_del(&slot->list);
-		kobject_del(&slot->kobj);
-		kobject_put(&slot->kobj);
-	}
-}
-module_exit(remove_legacy);
-
-
-MODULE_AUTHOR("Trent Piepho <xyzzy@speakeasy.org>");
-MODULE_DESCRIPTION("Legacy version of the fakephp interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index 376d70d..24d709b 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -81,16 +81,12 @@
 /* Dummy driver for dumplicate name detection */
 static int __init dummy_probe(struct pcie_device *dev)
 {
-	int pos;
 	u32 slot_cap;
 	acpi_handle handle;
 	struct dummy_slot *slot, *tmp;
 	struct pci_dev *pdev = dev->port;
 
-	pos = pci_pcie_cap(pdev);
-	if (!pos)
-		return -ENODEV;
-	pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
+	pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
 	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 	if (!slot)
 		return -ENOMEM;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 365c6b9..916bf4f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -300,24 +300,24 @@
 
 static int pciehp_resume (struct pcie_device *dev)
 {
+	struct controller *ctrl;
+	struct slot *slot;
+	u8 status;
+
 	dev_info(&dev->device, "%s ENTRY\n", __func__);
-	if (pciehp_force) {
-		struct controller *ctrl = get_service_data(dev);
-		struct slot *slot;
-		u8 status;
+	ctrl = get_service_data(dev);
 
-		/* reinitialize the chipset's event detection logic */
-		pcie_enable_notification(ctrl);
+	/* reinitialize the chipset's event detection logic */
+	pcie_enable_notification(ctrl);
 
-		slot = ctrl->slot;
+	slot = ctrl->slot;
 
-		/* Check if slot is occupied */
-		pciehp_get_adapter_status(slot, &status);
-		if (status)
-			pciehp_enable_slot(slot);
-		else
-			pciehp_disable_slot(slot);
-	}
+	/* Check if slot is occupied */
+	pciehp_get_adapter_status(slot, &status);
+	if (status)
+		pciehp_enable_slot(slot);
+	else
+		pciehp_disable_slot(slot);
 	return 0;
 }
 #endif /* PM */
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 302451e..13b2eaf 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -44,25 +44,25 @@
 static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
 {
 	struct pci_dev *dev = ctrl->pcie->port;
-	return pci_read_config_word(dev, pci_pcie_cap(dev) + reg, value);
+	return pcie_capability_read_word(dev, reg, value);
 }
 
 static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
 {
 	struct pci_dev *dev = ctrl->pcie->port;
-	return pci_read_config_dword(dev, pci_pcie_cap(dev) + reg, value);
+	return pcie_capability_read_dword(dev, reg, value);
 }
 
 static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
 {
 	struct pci_dev *dev = ctrl->pcie->port;
-	return pci_write_config_word(dev, pci_pcie_cap(dev) + reg, value);
+	return pcie_capability_write_word(dev, reg, value);
 }
 
 static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
 {
 	struct pci_dev *dev = ctrl->pcie->port;
-	return pci_write_config_dword(dev, pci_pcie_cap(dev) + reg, value);
+	return pcie_capability_write_dword(dev, reg, value);
 }
 
 /* Power Control Command */
@@ -855,10 +855,6 @@
 		goto abort;
 	}
 	ctrl->pcie = dev;
-	if (!pci_pcie_cap(pdev)) {
-		ctrl_err(ctrl, "Cannot find PCI Express capability\n");
-		goto abort_ctrl;
-	}
 	if (pciehp_readl(ctrl, PCI_EXP_SLTCAP, &slot_cap)) {
 		ctrl_err(ctrl, "Cannot read SLOTCAP register\n");
 		goto abort_ctrl;
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index 8c05a18..fec2d5b 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -96,17 +96,11 @@
 static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
 {
 	int pos;
-	u16 reg16;
 	u32 reg32;
 
 	if (!hpp)
 		return;
 
-	/* Find PCI Express capability */
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return;
-
 	if (hpp->revision > 1) {
 		dev_warn(&dev->dev, "PCIe settings rev %d not supported\n",
 			 hpp->revision);
@@ -114,17 +108,13 @@
 	}
 
 	/* Initialize Device Control Register */
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
-	reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
+	pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+			~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
 
 	/* Initialize Link Control Register */
-	if (dev->subordinate) {
-		pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &reg16);
-		reg16 = (reg16 & hpp->pci_exp_lnkctl_and)
-			| hpp->pci_exp_lnkctl_or;
-		pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16);
-	}
+	if (dev->subordinate)
+		pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
+			~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
 
 	/* Find Advanced Error Reporting Enhanced Capability */
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 74bbaf8..aeccc91 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -433,8 +433,8 @@
 	struct resource *res;
 	struct pci_dev *pdev;
 
-	if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
-	    dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
+	if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END &&
+	    pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT)
 		return -ENODEV;
 
 	pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
@@ -503,7 +503,7 @@
 	iov->self = dev;
 	pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
 	pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
-	if (dev->pcie_type == PCI_EXP_TYPE_RC_END)
+	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
 		iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
 
 	if (pdev)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d6fd6b6..9e1d295 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -139,7 +139,6 @@
 		return retval;
 	return count;
 }
-static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 /**
  * store_remove_id - remove a PCI device ID from this driver
@@ -185,38 +184,16 @@
 		return retval;
 	return count;
 }
-static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
-static int
-pci_create_newid_files(struct pci_driver *drv)
-{
-	int error = 0;
+static struct driver_attribute pci_drv_attrs[] = {
+	__ATTR(new_id, S_IWUSR, NULL, store_new_id),
+	__ATTR(remove_id, S_IWUSR, NULL, store_remove_id),
+	__ATTR_NULL,
+};
 
-	if (drv->probe != NULL) {
-		error = driver_create_file(&drv->driver, &driver_attr_new_id);
-		if (error == 0) {
-			error = driver_create_file(&drv->driver,
-					&driver_attr_remove_id);
-			if (error)
-				driver_remove_file(&drv->driver,
-						&driver_attr_new_id);
-		}
-	}
-	return error;
-}
-
-static void pci_remove_newid_files(struct pci_driver *drv)
-{
-	driver_remove_file(&drv->driver, &driver_attr_remove_id);
-	driver_remove_file(&drv->driver, &driver_attr_new_id);
-}
-#else /* !CONFIG_HOTPLUG */
-static inline int pci_create_newid_files(struct pci_driver *drv)
-{
-	return 0;
-}
-static inline void pci_remove_newid_files(struct pci_driver *drv) {}
-#endif
+#else
+#define pci_drv_attrs	NULL
+#endif /* CONFIG_HOTPLUG */
 
 /**
  * pci_match_id - See if a pci device matches a given pci_id table
@@ -1162,8 +1139,6 @@
 int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 			  const char *mod_name)
 {
-	int error;
-
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &pci_bus_type;
@@ -1174,19 +1149,7 @@
 	INIT_LIST_HEAD(&drv->dynids.list);
 
 	/* register with core */
-	error = driver_register(&drv->driver);
-	if (error)
-		goto out;
-
-	error = pci_create_newid_files(drv);
-	if (error)
-		goto out_newid;
-out:
-	return error;
-
-out_newid:
-	driver_unregister(&drv->driver);
-	goto out;
+	return driver_register(&drv->driver);
 }
 
 /**
@@ -1202,7 +1165,6 @@
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
-	pci_remove_newid_files(drv);
 	driver_unregister(&drv->driver);
 	pci_free_dynids(drv);
 }
@@ -1302,6 +1264,7 @@
 	.shutdown	= pci_device_shutdown,
 	.dev_attrs	= pci_dev_attrs,
 	.bus_attrs	= pci_bus_attrs,
+	.drv_attrs	= pci_drv_attrs,
 	.pm		= PCI_PM_OPS_PTR,
 };
 
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ab4bf5a..5485883 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -254,36 +254,56 @@
 }
 
 /**
- * pci_pcie_cap2 - query for devices' PCI_CAP_ID_EXP v2 capability structure
- * @dev: PCI device to check
+ * pci_find_next_ext_capability - Find an extended capability
+ * @dev: PCI device to query
+ * @start: address at which to start looking (0 to start at beginning of list)
+ * @cap: capability code
  *
- * Like pci_pcie_cap() but also checks that the PCIe capability version is
- * >= 2.  Note that v1 capability structures could be sparse in that not
- * all register fields were required.  v2 requires the entire structure to
- * be present size wise, while still allowing for non-implemented registers
- * to exist but they must be hardwired to 0.
- *
- * Due to the differences in the versions of capability structures, one
- * must be careful not to try and access non-existant registers that may
- * exist in early versions - v1 - of Express devices.
- *
- * Returns the offset of the PCIe capability structure as long as the
- * capability version is >= 2; otherwise 0 is returned.
+ * Returns the address of the next matching extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it.  Some capabilities can occur several times, e.g., the
+ * vendor-specific capability, and this provides a way to find them all.
  */
-static int pci_pcie_cap2(struct pci_dev *dev)
+int pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap)
 {
-	u16 flags;
-	int pos;
+	u32 header;
+	int ttl;
+	int pos = PCI_CFG_SPACE_SIZE;
 
-	pos = pci_pcie_cap(dev);
-	if (pos) {
-		pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
-		if ((flags & PCI_EXP_FLAGS_VERS) < 2)
-			pos = 0;
+	/* minimum 8 bytes per capability */
+	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+	if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
+		return 0;
+
+	if (start)
+		pos = start;
+
+	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+		return 0;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+
+		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+			break;
 	}
 
-	return pos;
+	return 0;
 }
+EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
 
 /**
  * pci_find_ext_capability - Find an extended capability
@@ -301,39 +321,7 @@
  */
 int pci_find_ext_capability(struct pci_dev *dev, int cap)
 {
-	u32 header;
-	int ttl;
-	int pos = PCI_CFG_SPACE_SIZE;
-
-	/* minimum 8 bytes per capability */
-	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
-
-	if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
-		return 0;
-
-	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
-		return 0;
-
-	/*
-	 * If we have no capabilities, this is indicated by cap ID,
-	 * cap version and next pointer all being 0.
-	 */
-	if (header == 0)
-		return 0;
-
-	while (ttl-- > 0) {
-		if (PCI_EXT_CAP_ID(header) == cap)
-			return pos;
-
-		pos = PCI_EXT_CAP_NEXT(header);
-		if (pos < PCI_CFG_SPACE_SIZE)
-			break;
-
-		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
-			break;
-	}
-
-	return 0;
+	return pci_find_next_ext_capability(dev, 0, cap);
 }
 EXPORT_SYMBOL_GPL(pci_find_ext_capability);
 
@@ -854,21 +842,6 @@
 
 #define PCI_EXP_SAVE_REGS	7
 
-#define pcie_cap_has_devctl(type, flags)	1
-#define pcie_cap_has_lnkctl(type, flags)		\
-		((flags & PCI_EXP_FLAGS_VERS) > 1 ||	\
-		 (type == PCI_EXP_TYPE_ROOT_PORT ||	\
-		  type == PCI_EXP_TYPE_ENDPOINT ||	\
-		  type == PCI_EXP_TYPE_LEG_END))
-#define pcie_cap_has_sltctl(type, flags)		\
-		((flags & PCI_EXP_FLAGS_VERS) > 1 ||	\
-		 ((type == PCI_EXP_TYPE_ROOT_PORT) ||	\
-		  (type == PCI_EXP_TYPE_DOWNSTREAM &&	\
-		   (flags & PCI_EXP_FLAGS_SLOT))))
-#define pcie_cap_has_rtctl(type, flags)			\
-		((flags & PCI_EXP_FLAGS_VERS) > 1 ||	\
-		 (type == PCI_EXP_TYPE_ROOT_PORT ||	\
-		  type == PCI_EXP_TYPE_RC_EC))
 
 static struct pci_cap_saved_state *pci_find_saved_cap(
 	struct pci_dev *pci_dev, char cap)
@@ -885,13 +858,11 @@
 
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
-	int pos, i = 0;
+	int i = 0;
 	struct pci_cap_saved_state *save_state;
 	u16 *cap;
-	u16 flags;
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
+	if (!pci_is_pcie(dev))
 		return 0;
 
 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
@@ -899,60 +870,37 @@
 		dev_err(&dev->dev, "buffer not found in %s\n", __func__);
 		return -ENOMEM;
 	}
+
 	cap = (u16 *)&save_state->cap.data[0];
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_SLTCTL, &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_RTCTL,  &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
 
-	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
-
-	if (pcie_cap_has_devctl(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
-	if (pcie_cap_has_lnkctl(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
-	if (pcie_cap_has_sltctl(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
-	if (pcie_cap_has_rtctl(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
-
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return 0;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
-	pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
-	pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
 	return 0;
 }
 
 static void pci_restore_pcie_state(struct pci_dev *dev)
 {
-	int i = 0, pos;
+	int i = 0;
 	struct pci_cap_saved_state *save_state;
 	u16 *cap;
-	u16 flags;
 
 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (!save_state || pos <= 0)
+	if (!save_state)
 		return;
+
 	cap = (u16 *)&save_state->cap.data[0];
-
-	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
-
-	if (pcie_cap_has_devctl(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
-	if (pcie_cap_has_lnkctl(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
-	if (pcie_cap_has_sltctl(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
-	if (pcie_cap_has_rtctl(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
-
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return;
-
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
-	pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
-	pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_LNKCTL, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_SLTCTL, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_RTCTL, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, cap[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
 }
 
 
@@ -1543,7 +1491,7 @@
 
 /**
  * pci_wakeup - Wake up a PCI device
- * @dev: Device to handle.
+ * @pci_dev: Device to handle.
  * @ign: ignored parameter
  */
 static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
@@ -2067,35 +2015,24 @@
  */
 void pci_enable_ari(struct pci_dev *dev)
 {
-	int pos;
 	u32 cap;
-	u16 ctrl;
 	struct pci_dev *bridge;
 
 	if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
 		return;
 
-	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
-	if (!pos)
+	if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
 		return;
 
 	bridge = dev->bus->self;
 	if (!bridge)
 		return;
 
-	/* ARI is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(bridge);
-	if (!pos)
-		return;
-
-	pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
+	pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
 	if (!(cap & PCI_EXP_DEVCAP2_ARI))
 		return;
 
-	pci_read_config_word(bridge, pos + PCI_EXP_DEVCTL2, &ctrl);
-	ctrl |= PCI_EXP_DEVCTL2_ARI;
-	pci_write_config_word(bridge, pos + PCI_EXP_DEVCTL2, ctrl);
-
+	pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
 	bridge->ari_enabled = 1;
 }
 
@@ -2110,20 +2047,14 @@
  */
 void pci_enable_ido(struct pci_dev *dev, unsigned long type)
 {
-	int pos;
-	u16 ctrl;
+	u16 ctrl = 0;
 
-	/* ID-based Ordering is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
 	if (type & PCI_EXP_IDO_REQUEST)
 		ctrl |= PCI_EXP_IDO_REQ_EN;
 	if (type & PCI_EXP_IDO_COMPLETION)
 		ctrl |= PCI_EXP_IDO_CMP_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+	if (ctrl)
+		pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, ctrl);
 }
 EXPORT_SYMBOL(pci_enable_ido);
 
@@ -2134,20 +2065,14 @@
  */
 void pci_disable_ido(struct pci_dev *dev, unsigned long type)
 {
-	int pos;
-	u16 ctrl;
+	u16 ctrl = 0;
 
-	/* ID-based Ordering is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
 	if (type & PCI_EXP_IDO_REQUEST)
-		ctrl &= ~PCI_EXP_IDO_REQ_EN;
+		ctrl |= PCI_EXP_IDO_REQ_EN;
 	if (type & PCI_EXP_IDO_COMPLETION)
-		ctrl &= ~PCI_EXP_IDO_CMP_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+		ctrl |= PCI_EXP_IDO_CMP_EN;
+	if (ctrl)
+		pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, ctrl);
 }
 EXPORT_SYMBOL(pci_disable_ido);
 
@@ -2172,17 +2097,11 @@
  */
 int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
 {
-	int pos;
 	u32 cap;
 	u16 ctrl;
 	int ret;
 
-	/* OBFF is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return -ENOTSUPP;
-
-	pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
+	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
 	if (!(cap & PCI_EXP_OBFF_MASK))
 		return -ENOTSUPP; /* no OBFF support at all */
 
@@ -2193,7 +2112,7 @@
 			return ret;
 	}
 
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctrl);
 	if (cap & PCI_EXP_OBFF_WAKE)
 		ctrl |= PCI_EXP_OBFF_WAKE_EN;
 	else {
@@ -2211,7 +2130,7 @@
 			return -ENOTSUPP;
 		}
 	}
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+	pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, ctrl);
 
 	return 0;
 }
@@ -2225,17 +2144,7 @@
  */
 void pci_disable_obff(struct pci_dev *dev)
 {
-	int pos;
-	u16 ctrl;
-
-	/* OBFF is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
-	ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_OBFF_WAKE_EN);
 }
 EXPORT_SYMBOL(pci_disable_obff);
 
@@ -2248,15 +2157,9 @@
  */
 static bool pci_ltr_supported(struct pci_dev *dev)
 {
-	int pos;
 	u32 cap;
 
-	/* LTR is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return false;
-
-	pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
+	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
 
 	return cap & PCI_EXP_DEVCAP2_LTR;
 }
@@ -2273,22 +2176,15 @@
  */
 int pci_enable_ltr(struct pci_dev *dev)
 {
-	int pos;
-	u16 ctrl;
 	int ret;
 
-	if (!pci_ltr_supported(dev))
-		return -ENOTSUPP;
-
-	/* LTR is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return -ENOTSUPP;
-
 	/* Only primary function can enable/disable LTR */
 	if (PCI_FUNC(dev->devfn) != 0)
 		return -EINVAL;
 
+	if (!pci_ltr_supported(dev))
+		return -ENOTSUPP;
+
 	/* Enable upstream ports first */
 	if (dev->bus->self) {
 		ret = pci_enable_ltr(dev->bus->self);
@@ -2296,11 +2192,7 @@
 			return ret;
 	}
 
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
-	ctrl |= PCI_EXP_LTR_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
-
-	return 0;
+	return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
 }
 EXPORT_SYMBOL(pci_enable_ltr);
 
@@ -2310,24 +2202,14 @@
  */
 void pci_disable_ltr(struct pci_dev *dev)
 {
-	int pos;
-	u16 ctrl;
-
-	if (!pci_ltr_supported(dev))
-		return;
-
-	/* LTR is a PCIe cap v2 feature */
-	pos = pci_pcie_cap2(dev);
-	if (!pos)
-		return;
-
 	/* Only primary function can enable/disable LTR */
 	if (PCI_FUNC(dev->devfn) != 0)
 		return;
 
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
-	ctrl &= ~PCI_EXP_LTR_EN;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+	if (!pci_ltr_supported(dev))
+		return;
+
+	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
 }
 EXPORT_SYMBOL(pci_disable_ltr);
 
@@ -2410,9 +2292,6 @@
 	if (!pci_acs_enable)
 		return;
 
-	if (!pci_is_pcie(dev))
-		return;
-
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
 	if (!pos)
 		return;
@@ -2460,8 +2339,8 @@
 		acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
 			      PCI_ACS_EC | PCI_ACS_DT);
 
-	if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
-	    pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM ||
+	    pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
 	    pdev->multifunction) {
 		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
 		if (!pos)
@@ -3177,15 +3056,10 @@
 static int pcie_flr(struct pci_dev *dev, int probe)
 {
 	int i;
-	int pos;
 	u32 cap;
-	u16 status, control;
+	u16 status;
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return -ENOTTY;
-
-	pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
+	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
 	if (!(cap & PCI_EXP_DEVCAP_FLR))
 		return -ENOTTY;
 
@@ -3197,7 +3071,7 @@
 		if (i)
 			msleep((1 << (i - 1)) * 100);
 
-		pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
+		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
 		if (!(status & PCI_EXP_DEVSTA_TRPND))
 			goto clear;
 	}
@@ -3206,9 +3080,7 @@
 			"proceeding with reset anyway\n");
 
 clear:
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &control);
-	control |= PCI_EXP_DEVCTL_BCR_FLR;
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, control);
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
 	msleep(100);
 
@@ -3576,18 +3448,11 @@
  */
 int pcie_get_readrq(struct pci_dev *dev)
 {
-	int ret, cap;
 	u16 ctl;
 
-	cap = pci_pcie_cap(dev);
-	if (!cap)
-		return -EINVAL;
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
 
-	ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
-	if (!ret)
-		ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
-
-	return ret;
+	return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
 }
 EXPORT_SYMBOL(pcie_get_readrq);
 
@@ -3601,19 +3466,11 @@
  */
 int pcie_set_readrq(struct pci_dev *dev, int rq)
 {
-	int cap, err = -EINVAL;
-	u16 ctl, v;
+	u16 v;
 
 	if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
-		goto out;
+		return -EINVAL;
 
-	cap = pci_pcie_cap(dev);
-	if (!cap)
-		goto out;
-
-	err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
-	if (err)
-		goto out;
 	/*
 	 * If using the "performance" PCIe config, we clamp the
 	 * read rq size to the max packet size to prevent the
@@ -3631,14 +3488,8 @@
 
 	v = (ffs(rq) - 8) << 12;
 
-	if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
-		ctl &= ~PCI_EXP_DEVCTL_READRQ;
-		ctl |= v;
-		err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
-	}
-
-out:
-	return err;
+	return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+						  PCI_EXP_DEVCTL_READRQ, v);
 }
 EXPORT_SYMBOL(pcie_set_readrq);
 
@@ -3651,18 +3502,11 @@
  */
 int pcie_get_mps(struct pci_dev *dev)
 {
-	int ret, cap;
 	u16 ctl;
 
-	cap = pci_pcie_cap(dev);
-	if (!cap)
-		return -EINVAL;
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
 
-	ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
-	if (!ret)
-		ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
-
-	return ret;
+	return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
 }
 
 /**
@@ -3675,32 +3519,18 @@
  */
 int pcie_set_mps(struct pci_dev *dev, int mps)
 {
-	int cap, err = -EINVAL;
-	u16 ctl, v;
+	u16 v;
 
 	if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
-		goto out;
+		return -EINVAL;
 
 	v = ffs(mps) - 8;
 	if (v > dev->pcie_mpss) 
-		goto out;
+		return -EINVAL;
 	v <<= 5;
 
-	cap = pci_pcie_cap(dev);
-	if (!cap)
-		goto out;
-
-	err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
-	if (err)
-		goto out;
-
-	if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) {
-		ctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
-		ctl |= v;
-		err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
-	}
-out:
-	return err;
+	return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+						  PCI_EXP_DEVCTL_PAYLOAD, v);
 }
 
 /**
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 5222986..4e24cb8 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -288,7 +288,7 @@
 	while (1) {
 		if (!pci_is_pcie(dev))
 			break;
-		if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+		if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
 			return dev;
 		if (!dev->bus->self)
 			break;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 58ad791..030cf12 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -48,7 +48,7 @@
 static void aer_error_resume(struct pci_dev *dev);
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
 
-static struct pci_error_handlers aer_error_handlers = {
+static const struct pci_error_handlers aer_error_handlers = {
 	.error_detected = aer_error_detected,
 	.resume		= aer_error_resume,
 };
@@ -81,10 +81,11 @@
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);
+	int type = pci_pcie_type(dev);
 
-	if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
-	    (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
-	    (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) {
+	if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
+	    (type == PCI_EXP_TYPE_UPSTREAM) ||
+	    (type == PCI_EXP_TYPE_DOWNSTREAM)) {
 		if (enable)
 			pci_enable_pcie_error_reporting(dev);
 		else
@@ -121,19 +122,17 @@
 static void aer_enable_rootport(struct aer_rpc *rpc)
 {
 	struct pci_dev *pdev = rpc->rpd->port;
-	int pos, aer_pos;
+	int aer_pos;
 	u16 reg16;
 	u32 reg32;
 
-	pos = pci_pcie_cap(pdev);
 	/* Clear PCIe Capability's Device Status */
-	pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
-	pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
+	pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &reg16);
+	pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16);
 
 	/* Disable system error generation in response to error messages */
-	pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
-	reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
-	pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
+	pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
+				   SYSTEM_ERROR_INTR_ON_MESG_MASK);
 
 	aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
 	/* Clear error status */
@@ -395,9 +394,8 @@
 	u16 reg16;
 
 	/* Clean up Root device status */
-	pos = pci_pcie_cap(dev);
-	pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
-	pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
+	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &reg16);
+	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16);
 
 	/* Clean AER Root Error Status */
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 124f20f..5194a7d 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -60,7 +60,7 @@
 	p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
 	if (p->flags & ACPI_HEST_GLOBAL) {
 		if ((pci_is_pcie(info->pci_dev) &&
-		     info->pci_dev->pcie_type == pcie_type) || bridge)
+		     pci_pcie_type(info->pci_dev) == pcie_type) || bridge)
 			ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
 	} else
 		if (hest_match_pci(p, info->pci_dev))
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 0ca0535..06bad96 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -32,53 +32,28 @@
 module_param(forceload, bool, 0);
 module_param(nosourceid, bool, 0);
 
+#define	PCI_EXP_AER_FLAGS	(PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
+				 PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
+
 int pci_enable_pcie_error_reporting(struct pci_dev *dev)
 {
-	u16 reg16 = 0;
-	int pos;
-
 	if (pcie_aer_get_firmware_first(dev))
 		return -EIO;
 
-	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-	if (!pos)
+	if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
 		return -EIO;
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return -EIO;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
-	reg16 |= (PCI_EXP_DEVCTL_CERE |
-		PCI_EXP_DEVCTL_NFERE |
-		PCI_EXP_DEVCTL_FERE |
-		PCI_EXP_DEVCTL_URRE);
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
-
-	return 0;
+	return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
 }
 EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
 
 int pci_disable_pcie_error_reporting(struct pci_dev *dev)
 {
-	u16 reg16 = 0;
-	int pos;
-
 	if (pcie_aer_get_firmware_first(dev))
 		return -EIO;
 
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return -EIO;
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
-	reg16 &= ~(PCI_EXP_DEVCTL_CERE |
-		PCI_EXP_DEVCTL_NFERE |
-		PCI_EXP_DEVCTL_FERE |
-		PCI_EXP_DEVCTL_URRE);
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
-
-	return 0;
+	return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
+					  PCI_EXP_AER_FLAGS);
 }
 EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
 
@@ -151,18 +126,12 @@
 	 */
 	if (atomic_read(&dev->enable_cnt) == 0)
 		return false;
-	pos = pci_pcie_cap(dev);
-	if (!pos)
-		return false;
 
 	/* Check if AER is enabled */
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
-	if (!(reg16 & (
-		PCI_EXP_DEVCTL_CERE |
-		PCI_EXP_DEVCTL_NFERE |
-		PCI_EXP_DEVCTL_FERE |
-		PCI_EXP_DEVCTL_URRE)))
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &reg16);
+	if (!(reg16 & PCI_EXP_AER_FLAGS))
 		return false;
+
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 	if (!pos)
 		return false;
@@ -240,7 +209,7 @@
 static int report_error_detected(struct pci_dev *dev, void *data)
 {
 	pci_ers_result_t vote;
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
@@ -274,7 +243,7 @@
 static int report_mmio_enabled(struct pci_dev *dev, void *data)
 {
 	pci_ers_result_t vote;
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
@@ -292,7 +261,7 @@
 static int report_slot_reset(struct pci_dev *dev, void *data)
 {
 	pci_ers_result_t vote;
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
@@ -309,7 +278,7 @@
 
 static int report_resume(struct pci_dev *dev, void *data)
 {
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 
 	dev->error_state = pci_channel_io_normal;
 
@@ -465,7 +434,7 @@
 
 	if (driver && driver->reset_link) {
 		status = driver->reset_link(udev);
-	} else if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
+	} else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM) {
 		status = default_downstream_reset_link(udev);
 	} else {
 		dev_printk(KERN_DEBUG, &dev->dev,
@@ -540,14 +509,12 @@
 				"resume",
 				report_resume);
 
-	dev_printk(KERN_DEBUG, &dev->dev,
-		"AER driver successfully recovered\n");
+	dev_info(&dev->dev, "AER: Device recovery successful\n");
 	return;
 
 failed:
 	/* TODO: Should kernel panic here? */
-	dev_printk(KERN_DEBUG, &dev->dev,
-		"AER driver didn't recover\n");
+	dev_info(&dev->dev, "AER: Device recovery failed\n");
 }
 
 /**
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index b500840..213753b 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -125,21 +125,16 @@
 
 static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 {
-	int pos;
-	u16 reg16;
 	struct pci_dev *child;
 	struct pci_bus *linkbus = link->pdev->subordinate;
 
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		pos = pci_pcie_cap(child);
-		if (!pos)
-			return;
-		pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16);
 		if (enable)
-			reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN;
+			pcie_capability_set_word(child, PCI_EXP_LNKCTL,
+						 PCI_EXP_LNKCTL_CLKREQ_EN);
 		else
-			reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
-		pci_write_config_word(child, pos + PCI_EXP_LNKCTL, reg16);
+			pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
+						   PCI_EXP_LNKCTL_CLKREQ_EN);
 	}
 	link->clkpm_enabled = !!enable;
 }
@@ -157,7 +152,7 @@
 
 static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
 {
-	int pos, capable = 1, enabled = 1;
+	int capable = 1, enabled = 1;
 	u32 reg32;
 	u16 reg16;
 	struct pci_dev *child;
@@ -165,16 +160,13 @@
 
 	/* All functions should have the same cap and state, take the worst */
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		pos = pci_pcie_cap(child);
-		if (!pos)
-			return;
-		pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, &reg32);
+		pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &reg32);
 		if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
 			capable = 0;
 			enabled = 0;
 			break;
 		}
-		pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16);
+		pcie_capability_read_word(child, PCI_EXP_LNKCTL, &reg16);
 		if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
 			enabled = 0;
 	}
@@ -190,7 +182,7 @@
  */
 static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
 {
-	int ppos, cpos, same_clock = 1;
+	int same_clock = 1;
 	u16 reg16, parent_reg, child_reg[8];
 	unsigned long start_jiffies;
 	struct pci_dev *child, *parent = link->pdev;
@@ -203,46 +195,43 @@
 	BUG_ON(!pci_is_pcie(child));
 
 	/* Check downstream component if bit Slot Clock Configuration is 1 */
-	cpos = pci_pcie_cap(child);
-	pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, &reg16);
+	pcie_capability_read_word(child, PCI_EXP_LNKSTA, &reg16);
 	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
 		same_clock = 0;
 
 	/* Check upstream component if bit Slot Clock Configuration is 1 */
-	ppos = pci_pcie_cap(parent);
-	pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16);
+	pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &reg16);
 	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
 		same_clock = 0;
 
 	/* Configure downstream component, all functions */
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		cpos = pci_pcie_cap(child);
-		pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, &reg16);
+		pcie_capability_read_word(child, PCI_EXP_LNKCTL, &reg16);
 		child_reg[PCI_FUNC(child->devfn)] = reg16;
 		if (same_clock)
 			reg16 |= PCI_EXP_LNKCTL_CCC;
 		else
 			reg16 &= ~PCI_EXP_LNKCTL_CCC;
-		pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, reg16);
+		pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16);
 	}
 
 	/* Configure upstream component */
-	pci_read_config_word(parent, ppos + PCI_EXP_LNKCTL, &reg16);
+	pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
 	parent_reg = reg16;
 	if (same_clock)
 		reg16 |= PCI_EXP_LNKCTL_CCC;
 	else
 		reg16 &= ~PCI_EXP_LNKCTL_CCC;
-	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16);
+	pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
 
 	/* Retrain link */
 	reg16 |= PCI_EXP_LNKCTL_RL;
-	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16);
+	pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
 
 	/* Wait for link training end. Break out after waiting for timeout */
 	start_jiffies = jiffies;
 	for (;;) {
-		pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16);
+		pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &reg16);
 		if (!(reg16 & PCI_EXP_LNKSTA_LT))
 			break;
 		if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
@@ -255,12 +244,10 @@
 	/* Training failed. Restore common clock configurations */
 	dev_printk(KERN_ERR, &parent->dev,
 		   "ASPM: Could not configure common clock\n");
-	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		cpos = pci_pcie_cap(child);
-		pci_write_config_word(child, cpos + PCI_EXP_LNKCTL,
-				      child_reg[PCI_FUNC(child->devfn)]);
-	}
-	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg);
+	list_for_each_entry(child, &linkbus->devices, bus_list)
+		pcie_capability_write_word(child, PCI_EXP_LNKCTL,
+					   child_reg[PCI_FUNC(child->devfn)]);
+	pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
 }
 
 /* Convert L0s latency encoding to ns */
@@ -305,16 +292,14 @@
 static void pcie_get_aspm_reg(struct pci_dev *pdev,
 			      struct aspm_register_info *info)
 {
-	int pos;
 	u16 reg16;
 	u32 reg32;
 
-	pos = pci_pcie_cap(pdev);
-	pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32);
+	pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &reg32);
 	info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
 	info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
 	info->latency_encoding_l1  = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
-	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
+	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
 	info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
 }
 
@@ -412,7 +397,7 @@
 	 * do ASPM for now.
 	 */
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
+		if (pci_pcie_type(child) == PCI_EXP_TYPE_PCI_BRIDGE) {
 			link->aspm_disable = ASPM_STATE_ALL;
 			break;
 		}
@@ -420,17 +405,15 @@
 
 	/* Get and check endpoint acceptable latencies */
 	list_for_each_entry(child, &linkbus->devices, bus_list) {
-		int pos;
 		u32 reg32, encoding;
 		struct aspm_latency *acceptable =
 			&link->acceptable[PCI_FUNC(child->devfn)];
 
-		if (child->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
-		    child->pcie_type != PCI_EXP_TYPE_LEG_END)
+		if (pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT &&
+		    pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END)
 			continue;
 
-		pos = pci_pcie_cap(child);
-		pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
+		pcie_capability_read_dword(child, PCI_EXP_DEVCAP, &reg32);
 		/* Calculate endpoint L0s acceptable latency */
 		encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
 		acceptable->l0s = calc_l0s_acceptable(encoding);
@@ -444,13 +427,7 @@
 
 static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
 {
-	u16 reg16;
-	int pos = pci_pcie_cap(pdev);
-
-	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
-	reg16 &= ~0x3;
-	reg16 |= val;
-	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, 0x3, val);
 }
 
 static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
@@ -505,7 +482,6 @@
 static int pcie_aspm_sanity_check(struct pci_dev *pdev)
 {
 	struct pci_dev *child;
-	int pos;
 	u32 reg32;
 
 	/*
@@ -513,8 +489,7 @@
 	 * very strange. Disable ASPM for the whole slot
 	 */
 	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
-		pos = pci_pcie_cap(child);
-		if (!pos)
+		if (!pci_is_pcie(child))
 			return -EINVAL;
 
 		/*
@@ -530,7 +505,7 @@
 		 * Disable ASPM for pre-1.1 PCIe device, we follow MS to use
 		 * RBER bit to determine if a function is 1.1 version device
 		 */
-		pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
+		pcie_capability_read_dword(child, PCI_EXP_DEVCAP, &reg32);
 		if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
 			dev_printk(KERN_INFO, &child->dev, "disabling ASPM"
 				" on pre-1.1 PCIe device.  You can enable it"
@@ -552,7 +527,7 @@
 	INIT_LIST_HEAD(&link->children);
 	INIT_LIST_HEAD(&link->link);
 	link->pdev = pdev;
-	if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) {
 		struct pcie_link_state *parent;
 		parent = pdev->bus->parent->self->link_state;
 		if (!parent) {
@@ -585,12 +560,12 @@
 
 	if (!pci_is_pcie(pdev) || pdev->link_state)
 		return;
-	if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
-	    pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
+	if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
+	    pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)
 		return;
 
 	/* VIA has a strange chipset, root port is under a bridge */
-	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT &&
 	    pdev->bus->self)
 		return;
 
@@ -647,8 +622,8 @@
 		if (link->root != root)
 			continue;
 		list_for_each_entry(child, &linkbus->devices, bus_list) {
-			if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT) &&
-			    (child->pcie_type != PCI_EXP_TYPE_LEG_END))
+			if ((pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT) &&
+			    (pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END))
 				continue;
 			pcie_aspm_check_latency(child);
 		}
@@ -663,8 +638,8 @@
 
 	if (!pci_is_pcie(pdev) || !parent || !parent->link_state)
 		return;
-	if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
-	    (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+	if ((pci_pcie_type(parent) != PCI_EXP_TYPE_ROOT_PORT) &&
+	    (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM))
 		return;
 
 	down_read(&pci_bus_sem);
@@ -704,8 +679,8 @@
 
 	if (aspm_disabled || !pci_is_pcie(pdev) || !link)
 		return;
-	if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
-	    (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
 		return;
 	/*
 	 * Devices changed PM state, we should recheck if latency
@@ -729,8 +704,8 @@
 	if (aspm_policy != POLICY_POWERSAVE)
 		return;
 
-	if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
-	    (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
 		return;
 
 	down_read(&pci_bus_sem);
@@ -757,8 +732,8 @@
 	if (!pci_is_pcie(pdev))
 		return;
 
-	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
-	    pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
+	    pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)
 		parent = pdev;
 	if (!parent || !parent->link_state)
 		return;
@@ -933,8 +908,8 @@
 	struct pcie_link_state *link_state = pdev->link_state;
 
 	if (!pci_is_pcie(pdev) ||
-	    (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
-	     pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
+	     pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
 		return;
 
 	if (link_state->aspm_support)
@@ -950,8 +925,8 @@
 	struct pcie_link_state *link_state = pdev->link_state;
 
 	if (!pci_is_pcie(pdev) ||
-	    (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
-	     pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
+	     pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
 		return;
 
 	if (link_state->aspm_support)
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 001f1b7..9ca0dc9 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -57,17 +57,12 @@
  */
 void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
 {
-	int rtctl_pos;
-	u16 rtctl;
-
-	rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL;
-
-	pci_read_config_word(dev, rtctl_pos, &rtctl);
 	if (enable)
-		rtctl |= PCI_EXP_RTCTL_PMEIE;
+		pcie_capability_set_word(dev, PCI_EXP_RTCTL,
+					 PCI_EXP_RTCTL_PMEIE);
 	else
-		rtctl &= ~PCI_EXP_RTCTL_PMEIE;
-	pci_write_config_word(dev, rtctl_pos, rtctl);
+		pcie_capability_clear_word(dev, PCI_EXP_RTCTL,
+					   PCI_EXP_RTCTL_PMEIE);
 }
 
 /**
@@ -120,7 +115,7 @@
 	if (!dev)
 		return false;
 
-	if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
+	if (pci_is_pcie(dev) && pci_pcie_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) {
 		down_read(&pci_bus_sem);
 		if (pcie_pme_walk_bus(bus))
 			found = true;
@@ -226,18 +221,15 @@
 	struct pcie_pme_service_data *data =
 			container_of(work, struct pcie_pme_service_data, work);
 	struct pci_dev *port = data->srv->port;
-	int rtsta_pos;
 	u32 rtsta;
 
-	rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA;
-
 	spin_lock_irq(&data->lock);
 
 	for (;;) {
 		if (data->noirq)
 			break;
 
-		pci_read_config_dword(port, rtsta_pos, &rtsta);
+		pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
 		if (rtsta & PCI_EXP_RTSTA_PME) {
 			/*
 			 * Clear PME status of the port.  If there are other
@@ -276,17 +268,14 @@
 {
 	struct pci_dev *port;
 	struct pcie_pme_service_data *data;
-	int rtsta_pos;
 	u32 rtsta;
 	unsigned long flags;
 
 	port = ((struct pcie_device *)context)->port;
 	data = get_service_data((struct pcie_device *)context);
 
-	rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA;
-
 	spin_lock_irqsave(&data->lock, flags);
-	pci_read_config_dword(port, rtsta_pos, &rtsta);
+	pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
 
 	if (!(rtsta & PCI_EXP_RTSTA_PME)) {
 		spin_unlock_irqrestore(&data->lock, flags);
@@ -335,13 +324,13 @@
 		struct pci_dev *dev;
 
 		/* Check if this is a root port event collector. */
-		if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus)
+		if (pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC || !bus)
 			return;
 
 		down_read(&pci_bus_sem);
 		list_for_each_entry(dev, &bus->devices, bus_list)
 			if (pci_is_pcie(dev)
-			    && dev->pcie_type == PCI_EXP_TYPE_RC_END)
+			    && pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
 				pcie_pme_set_native(dev, NULL);
 		up_read(&pci_bus_sem);
 	}
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
index 18bf90f..67be55a 100644
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -38,7 +38,7 @@
 		return 0;
 
 	if ((driver->port_type != PCIE_ANY_PORT) &&
-	    (driver->port_type != pciedev->port->pcie_type))
+	    (driver->port_type != pci_pcie_type(pciedev->port)))
 		return 0;
 
 	return 1;
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 75915b3..d03a7a3 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -200,10 +200,13 @@
 {
 	int i, irq = -1;
 
-	/* We have to use INTx if MSI cannot be used for PCIe PME or pciehp. */
+	/*
+	 * If MSI cannot be used for PCIe PME or hotplug, we have to use
+	 * INTx or other interrupts, e.g. system shared interrupt.
+	 */
 	if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) ||
 	    ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) {
-		if (dev->pin)
+		if (dev->irq)
 			irq = dev->irq;
 		goto no_msi;
 	}
@@ -212,8 +215,12 @@
 	if (!pcie_port_enable_msix(dev, irqs, mask))
 		return 0;
 
-	/* We're not going to use MSI-X, so try MSI and fall back to INTx */
-	if (!pci_enable_msi(dev) || dev->pin)
+	/*
+	 * We're not going to use MSI-X, so try MSI and fall back to INTx.
+	 * If neither MSI/MSI-X nor INTx available, try other interrupt.  On
+	 * some platforms, root port doesn't support MSI/MSI-X/INTx in RC mode.
+	 */
+	if (!pci_enable_msi(dev) || dev->irq)
 		irq = dev->irq;
 
  no_msi:
@@ -246,8 +253,7 @@
  */
 static int get_port_device_capability(struct pci_dev *dev)
 {
-	int services = 0, pos;
-	u16 reg16;
+	int services = 0;
 	u32 reg32;
 	int cap_mask = 0;
 	int err;
@@ -265,11 +271,9 @@
 			return 0;
 	}
 
-	pos = pci_pcie_cap(dev);
-	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
 	/* Hot-Plug Capable */
-	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
-		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
+	if (cap_mask & PCIE_PORT_SERVICE_HP) {
+		pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &reg32);
 		if (reg32 & PCI_EXP_SLTCAP_HPC) {
 			services |= PCIE_PORT_SERVICE_HP;
 			/*
@@ -277,10 +281,8 @@
 			 * enabled by the BIOS and the hot-plug service driver
 			 * is not loaded.
 			 */
-			pos += PCI_EXP_SLTCTL;
-			pci_read_config_word(dev, pos, &reg16);
-			reg16 &= ~(PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE);
-			pci_write_config_word(dev, pos, reg16);
+			pcie_capability_clear_word(dev, PCI_EXP_SLTCTL,
+				PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE);
 		}
 	}
 	/* AER capable */
@@ -298,7 +300,7 @@
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
 	if ((cap_mask & PCIE_PORT_SERVICE_PME)
-	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
+	    && pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
 		services |= PCIE_PORT_SERVICE_PME;
 		/*
 		 * Disable PME interrupt on this port in case it's been enabled
@@ -336,7 +338,7 @@
 	device->release = release_pcie_device;	/* callback to free pcie dev */
 	dev_set_name(device, "%s:pcie%02x",
 		     pci_name(pdev),
-		     get_descriptor_id(pdev->pcie_type, service));
+		     get_descriptor_id(pci_pcie_type(pdev), service));
 	device->parent = &pdev->dev;
 	device_enable_async_suspend(device);
 
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index e76b447..0761d90 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -64,14 +64,7 @@
  */
 void pcie_clear_root_pme_status(struct pci_dev *dev)
 {
-	int rtsta_pos;
-	u32 rtsta;
-
-	rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
-
-	pci_read_config_dword(dev, rtsta_pos, &rtsta);
-	rtsta |= PCI_EXP_RTSTA_PME;
-	pci_write_config_dword(dev, rtsta_pos, rtsta);
+	pcie_capability_set_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME);
 }
 
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
@@ -95,7 +88,7 @@
 	 * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
 	 * bits now just in case (shouldn't hurt).
 	 */
-	if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
 		pcie_clear_root_pme_status(pdev);
 	return 0;
 }
@@ -195,9 +188,9 @@
 	int status;
 
 	if (!pci_is_pcie(dev) ||
-	    ((dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
-	     (dev->pcie_type != PCI_EXP_TYPE_UPSTREAM) &&
-	     (dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)))
+	    ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
+	     (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
+	     (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
 		return -ENODEV;
 
 	if (!dev->irq && dev->pin) {
@@ -385,11 +378,11 @@
 };
 MODULE_DEVICE_TABLE(pci, port_pci_ids);
 
-static struct pci_error_handlers pcie_portdrv_err_handler = {
-		.error_detected = pcie_portdrv_error_detected,
-		.mmio_enabled = pcie_portdrv_mmio_enabled,
-		.slot_reset = pcie_portdrv_slot_reset,
-		.resume = pcie_portdrv_err_resume,
+static const struct pci_error_handlers pcie_portdrv_err_handler = {
+	.error_detected = pcie_portdrv_error_detected,
+	.mmio_enabled = pcie_portdrv_mmio_enabled,
+	.slot_reset = pcie_portdrv_slot_reset,
+	.resume = pcie_portdrv_err_resume,
 };
 
 static struct pci_driver pcie_portdriver = {
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 9f8a6b7..ec909af 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -606,10 +606,10 @@
 		u32 linkcap;
 		u16 linksta;
 
-		pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap);
+		pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap);
 		bus->max_bus_speed = pcie_link_speed[linkcap & 0xf];
 
-		pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta);
+		pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta);
 		pcie_update_link_speed(bus, linksta);
 	}
 }
@@ -729,8 +729,10 @@
 
 	/* Check if setup is sensible at all */
 	if (!pass &&
-	    (primary != bus->number || secondary <= bus->number)) {
-		dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+	    (primary != bus->number || secondary <= bus->number ||
+	     secondary > subordinate)) {
+		dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
+			 secondary, subordinate);
 		broken = 1;
 	}
 
@@ -932,24 +934,16 @@
 	pdev->is_pcie = 1;
 	pdev->pcie_cap = pos;
 	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
-	pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+	pdev->pcie_flags_reg = reg16;
 	pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
 	pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 }
 
 void set_pcie_hotplug_bridge(struct pci_dev *pdev)
 {
-	int pos;
-	u16 reg16;
 	u32 reg32;
 
-	pos = pci_pcie_cap(pdev);
-	if (!pos)
-		return;
-	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
-	if (!(reg16 & PCI_EXP_FLAGS_SLOT))
-		return;
-	pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &reg32);
+	pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &reg32);
 	if (reg32 & PCI_EXP_SLTCAP_HPC)
 		pdev->is_hotplug_bridge = 1;
 }
@@ -1163,8 +1157,7 @@
 	if (class == PCI_CLASS_BRIDGE_HOST)
 		return pci_cfg_space_size_ext(dev);
 
-	pos = pci_pcie_cap(dev);
-	if (!pos) {
+	if (!pci_is_pcie(dev)) {
 		pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
 		if (!pos)
 			goto fail;
@@ -1386,9 +1379,9 @@
 
 	if (!parent || !pci_is_pcie(parent))
 		return 0;
-	if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if (pci_pcie_type(parent) == PCI_EXP_TYPE_ROOT_PORT)
 		return 1;
-	if (parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM &&
+	if (pci_pcie_type(parent) == PCI_EXP_TYPE_DOWNSTREAM &&
 	    !pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
 		return 1;
 	return 0;
@@ -1465,7 +1458,7 @@
 	 */
 	if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
 	     (dev->bus->self &&
-	      dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT)))
+	      pci_pcie_type(dev->bus->self) != PCI_EXP_TYPE_ROOT_PORT)))
 		*smpss = 0;
 
 	if (*smpss > dev->pcie_mpss)
@@ -1481,7 +1474,8 @@
 	if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
 		mps = 128 << dev->pcie_mpss;
 
-		if (dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && dev->bus->self)
+		if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT &&
+		    dev->bus->self)
 			/* For "Performance", the assumption is made that
 			 * downstream communication will never be larger than
 			 * the MRRS.  So, the MPS only needs to be configured
@@ -1756,11 +1750,6 @@
 			   "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n",
 			    res, pci_is_root_bus(b) ? "domain " : "",
 			    parent_res, conflict->name, conflict);
-	else
-		dev_printk(KERN_DEBUG, &b->dev,
-			   "busn_res: %pR is inserted under %s%pR\n",
-			   res, pci_is_root_bus(b) ? "domain " : "",
-			   parent_res);
 
 	return conflict == NULL;
 }
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 27911b5..eb907a8f 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -434,25 +434,6 @@
 	return 0;
 }
 
-#if 0
-int pci_proc_attach_bus(struct pci_bus* bus)
-{
-	struct proc_dir_entry *de = bus->procdir;
-
-	if (!proc_initialized)
-		return -EACCES;
-
-	if (!de) {
-		char name[16];
-		sprintf(name, "%02x", bus->number);
-		de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
-		if (!de)
-			return -ENOMEM;
-	}
-	return 0;
-}
-#endif  /*  0  */
-
 int pci_proc_detach_bus(struct pci_bus* bus)
 {
 	struct proc_dir_entry *de = bus->procdir;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5155317..7a451ff 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3081,17 +3081,36 @@
 
 static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
 {
-	int pos;
+	int i;
+	u16 status;
 
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (!pos)
-		return -ENOTTY;
+	/*
+	 * http://www.intel.com/content/dam/doc/datasheet/82599-10-gbe-controller-datasheet.pdf
+	 *
+	 * The 82599 supports FLR on VFs, but FLR support is reported only
+	 * in the PF DEVCAP (sec 9.3.10.4), not in the VF DEVCAP (sec 9.5).
+	 * Therefore, we can't use pcie_flr(), which checks the VF DEVCAP.
+	 */
 
 	if (probe)
 		return 0;
 
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
-				PCI_EXP_DEVCTL_BCR_FLR);
+	/* Wait for Transaction Pending bit clean */
+	for (i = 0; i < 4; i++) {
+		if (i)
+			msleep((1 << (i - 1)) * 100);
+
+		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
+		if (!(status & PCI_EXP_DEVSTA_TRPND))
+			goto clear;
+	}
+
+	dev_err(&dev->dev, "transaction is not cleared; "
+			"proceeding with reset anyway\n");
+
+clear:
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
+
 	msleep(100);
 
 	return 0;
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 04a4861..513972f 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -32,53 +32,67 @@
 
 static void pci_destroy_dev(struct pci_dev *dev)
 {
-	/* Remove the device from the device lists, and prevent any further
-	 * list accesses from this device */
 	down_write(&pci_bus_sem);
 	list_del(&dev->bus_list);
-	dev->bus_list.next = dev->bus_list.prev = NULL;
 	up_write(&pci_bus_sem);
 
 	pci_free_resources(dev);
 	pci_dev_put(dev);
 }
 
-/**
- * pci_remove_device_safe - remove an unused hotplug device
- * @dev: the device to remove
- *
- * Delete the device structure from the device lists and 
- * notify userspace (/sbin/hotplug), but only if the device
- * in question is not being used by a driver.
- * Returns 0 on success.
- */
-#if 0
-int pci_remove_device_safe(struct pci_dev *dev)
+void pci_remove_bus(struct pci_bus *bus)
 {
-	if (pci_dev_driver(dev))
-		return -EBUSY;
-	pci_destroy_dev(dev);
-	return 0;
-}
-#endif  /*  0  */
-
-void pci_remove_bus(struct pci_bus *pci_bus)
-{
-	pci_proc_detach_bus(pci_bus);
+	pci_proc_detach_bus(bus);
 
 	down_write(&pci_bus_sem);
-	list_del(&pci_bus->node);
-	pci_bus_release_busn_res(pci_bus);
+	list_del(&bus->node);
+	pci_bus_release_busn_res(bus);
 	up_write(&pci_bus_sem);
-	if (!pci_bus->is_added)
+	if (!bus->is_added)
 		return;
 
-	pci_remove_legacy_files(pci_bus);
-	device_unregister(&pci_bus->dev);
+	pci_remove_legacy_files(bus);
+	device_unregister(&bus->dev);
 }
 EXPORT_SYMBOL(pci_remove_bus);
 
-static void __pci_remove_behind_bridge(struct pci_dev *dev);
+static void pci_stop_bus_device(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->subordinate;
+	struct pci_dev *child, *tmp;
+
+	/*
+	 * Stopping an SR-IOV PF device removes all the associated VFs,
+	 * which will update the bus->devices list and confuse the
+	 * iterator.  Therefore, iterate in reverse so we remove the VFs
+	 * first, then the PF.
+	 */
+	if (bus) {
+		list_for_each_entry_safe_reverse(child, tmp,
+						 &bus->devices, bus_list)
+			pci_stop_bus_device(child);
+	}
+
+	pci_stop_dev(dev);
+}
+
+static void pci_remove_bus_device(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->subordinate;
+	struct pci_dev *child, *tmp;
+
+	if (bus) {
+		list_for_each_entry_safe(child, tmp,
+					 &bus->devices, bus_list)
+			pci_remove_bus_device(child);
+
+		pci_remove_bus(bus);
+		dev->subordinate = NULL;
+	}
+
+	pci_destroy_dev(dev);
+}
+
 /**
  * pci_stop_and_remove_bus_device - remove a PCI device and any children
  * @dev: the device to remove
@@ -91,93 +105,9 @@
  * device lists, remove the /proc entry, and notify userspace
  * (/sbin/hotplug).
  */
-void __pci_remove_bus_device(struct pci_dev *dev)
-{
-	if (dev->subordinate) {
-		struct pci_bus *b = dev->subordinate;
-
-		__pci_remove_behind_bridge(dev);
-		pci_remove_bus(b);
-		dev->subordinate = NULL;
-	}
-
-	pci_destroy_dev(dev);
-}
-EXPORT_SYMBOL(__pci_remove_bus_device);
-
 void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 {
 	pci_stop_bus_device(dev);
-	__pci_remove_bus_device(dev);
+	pci_remove_bus_device(dev);
 }
-
-static void __pci_remove_behind_bridge(struct pci_dev *dev)
-{
-	struct list_head *l, *n;
-
-	if (dev->subordinate)
-		list_for_each_safe(l, n, &dev->subordinate->devices)
-			__pci_remove_bus_device(pci_dev_b(l));
-}
-
-static void pci_stop_behind_bridge(struct pci_dev *dev)
-{
-	struct list_head *l, *n;
-
-	if (dev->subordinate)
-		list_for_each_safe(l, n, &dev->subordinate->devices)
-			pci_stop_bus_device(pci_dev_b(l));
-}
-
-/**
- * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
- *					 a PCI bridge
- * @dev: PCI bridge device
- *
- * Remove all devices on the bus, except for the parent bridge.
- * This also removes any child buses, and any devices they may
- * contain in a depth-first manner.
- */
-void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
-{
-	pci_stop_behind_bridge(dev);
-	__pci_remove_behind_bridge(dev);
-}
-
-static void pci_stop_bus_devices(struct pci_bus *bus)
-{
-	struct list_head *l, *n;
-
-	/*
-	 * VFs could be removed by pci_stop_and_remove_bus_device() in the
-	 *  pci_stop_bus_devices() code path for PF.
-	 *  aka, bus->devices get updated in the process.
-	 * but VFs are inserted after PFs when SRIOV is enabled for PF,
-	 * We can iterate the list backwards to get prev valid PF instead
-	 *  of removed VF.
-	 */
-	list_for_each_prev_safe(l, n, &bus->devices) {
-		struct pci_dev *dev = pci_dev_b(l);
-		pci_stop_bus_device(dev);
-	}
-}
-
-/**
- * pci_stop_bus_device - stop a PCI device and any children
- * @dev: the device to stop
- *
- * Stop a PCI device (detach the driver, remove from the global list
- * and so on). This also stop any subordinate buses and children in a
- * depth-first manner.
- */
-void pci_stop_bus_device(struct pci_dev *dev)
-{
-	if (dev->subordinate)
-		pci_stop_bus_devices(dev->subordinate);
-
-	pci_stop_dev(dev);
-}
-
 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
-EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);
-EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 48ebdb2..0b3037a 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -167,44 +167,6 @@
 	return rom;
 }
 
-#if 0
-/**
- * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
- * @pdev: pointer to pci device struct
- * @size: pointer to receive size of pci window over ROM
- *
- * Return: kernel virtual pointer to image of ROM
- *
- * Map a PCI ROM into kernel space. If ROM is boot video ROM,
- * the shadow BIOS copy will be returned instead of the
- * actual ROM.
- */
-void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
-{
-	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
-	void __iomem *rom;
-
-	rom = pci_map_rom(pdev, size);
-	if (!rom)
-		return NULL;
-
-	if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW |
-			  IORESOURCE_ROM_BIOS_COPY))
-		return rom;
-
-	res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
-	if (!res->start)
-		return rom;
-
-	res->end = res->start + *size;
-	memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
-	pci_unmap_rom(pdev, rom);
-	res->flags |= IORESOURCE_ROM_COPY;
-
-	return (void __iomem *)(unsigned long)res->start;
-}
-#endif  /*  0  */
-
 /**
  * pci_unmap_rom - unmap the ROM from kernel space
  * @pdev: pointer to pci device struct
@@ -226,27 +188,6 @@
 		pci_disable_rom(pdev);
 }
 
-#if 0
-/**
- * pci_remove_rom - disable the ROM and remove its sysfs attribute
- * @pdev: pointer to pci device struct
- *
- * Remove the rom file in sysfs and disable ROM decoding.
- */
-void pci_remove_rom(struct pci_dev *pdev)
-{
-	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
-
-	if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
-		sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
-	if (!(res->flags & (IORESOURCE_ROM_ENABLE |
-			    IORESOURCE_ROM_SHADOW |
-			    IORESOURCE_ROM_BIOS_COPY |
-			    IORESOURCE_ROM_COPY)))
-		pci_disable_rom(pdev);
-}
-#endif  /*  0  */
-
 /**
  * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy
  * @pdev: pointer to pci device struct
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 993d4a0a..bf969ba 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -41,7 +41,7 @@
 			continue;
 		}
 		/* PCI device should connect to a PCIe bridge */
-		if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
+		if (pci_pcie_type(pdev) != PCI_EXP_TYPE_PCI_BRIDGE) {
 			/* Busted hardware? */
 			WARN_ON_ONCE(1);
 			return NULL;
@@ -130,16 +130,14 @@
  * decrement the reference count by calling pci_dev_put().
  * If no device is found, %NULL is returned.
  */
-struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
+struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
 {
-	struct list_head *tmp;
 	struct pci_dev *dev;
 
 	WARN_ON(in_interrupt());
 	down_read(&pci_bus_sem);
 
-	list_for_each(tmp, &bus->devices) {
-		dev = pci_dev_b(tmp);
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		if (dev->devfn == devfn)
 			goto out;
 	}
@@ -245,30 +243,14 @@
 			       unsigned int ss_vendor, unsigned int ss_device,
 			       struct pci_dev *from)
 {
-	struct pci_dev *pdev;
-	struct pci_device_id *id;
+	struct pci_device_id id = {
+		.vendor = vendor,
+		.device = device,
+		.subvendor = ss_vendor,
+		.subdevice = ss_device,
+	};
 
-	/*
-	 * pci_find_subsys() can be called on the ide_setup() path,
-	 * super-early in boot.  But the down_read() will enable local
-	 * interrupts, which can cause some machines to crash.  So here we
-	 * detect and flag that situation and bail out early.
-	 */
-	if (unlikely(no_pci_devices()))
-		return NULL;
-
-	id = kzalloc(sizeof(*id), GFP_KERNEL);
-	if (!id)
-		return NULL;
-	id->vendor = vendor;
-	id->device = device;
-	id->subvendor = ss_vendor;
-	id->subdevice = ss_device;
-
-	pdev = pci_get_dev_by_id(id, from);
-	kfree(id);
-
-	return pdev;
+	return pci_get_dev_by_id(&id, from);
 }
 
 /**
@@ -307,19 +289,16 @@
  */
 struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
 {
-	struct pci_dev *dev;
-	struct pci_device_id *id;
+	struct pci_device_id id = {
+		.vendor = PCI_ANY_ID,
+		.device = PCI_ANY_ID,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.class_mask = PCI_ANY_ID,
+		.class = class,
+	};
 
-	id = kzalloc(sizeof(*id), GFP_KERNEL);
-	if (!id)
-		return NULL;
-	id->vendor = id->device = id->subvendor = id->subdevice = PCI_ANY_ID;
-	id->class_mask = PCI_ANY_ID;
-	id->class = class;
-
-	dev = pci_get_dev_by_id(id, from);
-	kfree(id);
-	return dev;
+	return pci_get_dev_by_id(&id, from);
 }
 
 /**
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index fb50613..1e808ca 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -697,6 +697,38 @@
 	return size;
 }
 
+resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
+						unsigned long type)
+{
+	return 1;
+}
+
+#define PCI_P2P_DEFAULT_MEM_ALIGN	0x100000	/* 1MiB */
+#define PCI_P2P_DEFAULT_IO_ALIGN	0x1000		/* 4KiB */
+#define PCI_P2P_DEFAULT_IO_ALIGN_1K	0x400		/* 1KiB */
+
+static resource_size_t window_alignment(struct pci_bus *bus,
+					unsigned long type)
+{
+	resource_size_t align = 1, arch_align;
+
+	if (type & IORESOURCE_MEM)
+		align = PCI_P2P_DEFAULT_MEM_ALIGN;
+	else if (type & IORESOURCE_IO) {
+		/*
+		 * Per spec, I/O windows are 4K-aligned, but some
+		 * bridges have an extension to support 1K alignment.
+		 */
+		if (bus->self->io_window_1k)
+			align = PCI_P2P_DEFAULT_IO_ALIGN_1K;
+		else
+			align = PCI_P2P_DEFAULT_IO_ALIGN;
+	}
+
+	arch_align = pcibios_window_alignment(bus, type);
+	return max(align, arch_align);
+}
+
 /**
  * pbus_size_io() - size the io window of a given bus
  *
@@ -717,17 +749,12 @@
 	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
 	unsigned long size = 0, size0 = 0, size1 = 0;
 	resource_size_t children_add_size = 0;
-	resource_size_t min_align = 4096, align;
+	resource_size_t min_align, io_align, align;
 
 	if (!b_res)
  		return;
 
-	/*
-	 * Per spec, I/O windows are 4K-aligned, but some bridges have an
-	 * extension to support 1K alignment.
-	 */
-	if (bus->self->io_window_1k)
-		min_align = 1024;
+	io_align = min_align = window_alignment(bus, IORESOURCE_IO);
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		int i;
 
@@ -754,8 +781,8 @@
 		}
 	}
 
-	if (min_align > 4096)
-		min_align = 4096;
+	if (min_align > io_align)
+		min_align = io_align;
 
 	size0 = calculate_iosize(size, min_size, size1,
 			resource_size(b_res), min_align);
@@ -785,6 +812,28 @@
 	}
 }
 
+static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
+						  int max_order)
+{
+	resource_size_t align = 0;
+	resource_size_t min_align = 0;
+	int order;
+
+	for (order = 0; order <= max_order; order++) {
+		resource_size_t align1 = 1;
+
+		align1 <<= (order + 20);
+
+		if (!align)
+			min_align = align1;
+		else if (ALIGN(align + min_align, min_align) < align1)
+			min_align = align1 >> 1;
+		align += aligns[order];
+	}
+
+	return min_align;
+}
+
 /**
  * pbus_size_mem() - size the memory window of a given bus
  *
@@ -864,19 +913,9 @@
 				children_add_size += get_res_add_size(realloc_head, r);
 		}
 	}
-	align = 0;
-	min_align = 0;
-	for (order = 0; order <= max_order; order++) {
-		resource_size_t align1 = 1;
 
-		align1 <<= (order + 20);
-
-		if (!align)
-			min_align = align1;
-		else if (ALIGN(align + min_align, min_align) < align1)
-			min_align = align1 >> 1;
-		align += aligns[order];
-	}
+	min_align = calculate_mem_align(aligns, max_order);
+	min_align = max(min_align, window_alignment(bus, b_res->flags & mask));
 	size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
 	if (children_add_size > add_size)
 		add_size = children_add_size;
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index eb219a1..9bd6864 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -17,8 +17,13 @@
 #include <linux/ioport.h>
 #include <linux/cache.h>
 
+void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	dev_dbg(&dev->dev, "assigning IRQ %02d\n", irq);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
 
-static void __init
+static void
 pdev_fixup_irq(struct pci_dev *dev,
 	       u8 (*swizzle)(struct pci_dev *, u8 *),
 	       int (*map_irq)(const struct pci_dev *, u8, u8))
@@ -54,7 +59,7 @@
 	pcibios_update_irq(dev, irq);
 }
 
-void __init
+void
 pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
 	       int (*map_irq)(const struct pci_dev *, u8, u8))
 {
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index d6cc62c..def8d0b 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -982,7 +982,6 @@
 	int err = 0;
 	int i, num_devs;
 	unsigned int domain, bus, slot, func;
-	struct pci_bus *pci_bus;
 	struct pci_dev *pci_dev;
 	char str[64];
 
@@ -1032,13 +1031,8 @@
 			goto out;
 		}
 
-		pci_bus = pci_find_bus(domain, bus);
-		if (!pci_bus) {
-			dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n",
-				domain, bus);
-			continue;
-		}
-		pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func));
+		pci_dev = pci_get_domain_bus_and_slot(domain, bus,
+				PCI_DEVFN(slot, func));
 		if (!pci_dev) {
 			dev_dbg(&pdev->xdev->dev,
 				"Cannot get PCI device %04x:%02x:%02x.%d\n",
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 24caeaf..9d3ac99 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -105,8 +105,17 @@
  */
 void cb_free(struct pcmcia_socket *s)
 {
-	struct pci_dev *bridge = s->cb_dev;
+	struct pci_dev *bridge, *dev, *tmp;
+	struct pci_bus *bus;
 
-	if (bridge)
-		pci_stop_and_remove_behind_bridge(bridge);
+	bridge = s->cb_dev;
+	if (!bridge)
+		return;
+
+	bus = bridge->subordinate;
+	if (!bus)
+		return;
+
+	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list)
+		pci_stop_and_remove_bus_device(dev);
 }
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 0ad06a3b..fa74efe 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -24,7 +24,7 @@
 #include <asm/io.h>
 #include <asm/sizes.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/tc.h>
 
 
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 490bb82..cfec9dd 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -297,7 +297,7 @@
 	}
 
 	clk = clk_get(&dev->dev, NULL);
-	if (!clk)
+	if (IS_ERR(clk))
 		return -ENODEV;
 
 	pxa2xx_drv_pcmcia_ops(ops);
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index cc0f00d..b446c96 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -1,11 +1,8 @@
 /*
  * U300 GPIO module.
  *
- * Copyright (C) 2007-2011 ST-Ericsson AB
+ * Copyright (C) 2007-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
- * This can driver either of the two basic GPIO cores
- * available in the U300 platforms:
- * COH 901 335   - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0)
  * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0)
  * Author: Linus Walleij <linus.walleij@linaro.org>
  * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
@@ -24,19 +21,22 @@
 #include <linux/slab.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinconf-generic.h>
-#include <mach/gpio-u300.h>
+#include <linux/platform_data/pinctrl-coh901.h>
 #include "pinctrl-coh901.h"
 
+#define U300_GPIO_PORT_STRIDE				(0x30)
 /*
- * Register definitions for COH 901 335 variant
+ * Control Register 32bit (R/W)
+ * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
+ * gives the number of GPIO pins.
+ * bit 8-2  (mask 0x000001FC) contains the core version ID.
  */
-#define U300_335_PORT_STRIDE				(0x1C)
-/* Port X Pin Data Register 32bit, this is both input and output (R/W) */
-#define U300_335_PXPDIR					(0x00)
-#define U300_335_PXPDOR					(0x00)
-/* Port X Pin Config Register 32bit (R/W) */
-#define U300_335_PXPCR					(0x04)
-/* This register layout is the same in both blocks */
+#define U300_GPIO_CR					(0x00)
+#define U300_GPIO_CR_SYNC_SEL_ENABLE			(0x00000002UL)
+#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE			(0x00000001UL)
+#define U300_GPIO_PXPDIR				(0x04)
+#define U300_GPIO_PXPDOR				(0x08)
+#define U300_GPIO_PXPCR					(0x0C)
 #define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK		(0x0000FFFFUL)
 #define U300_GPIO_PXPCR_PIN_MODE_MASK			(0x00000003UL)
 #define U300_GPIO_PXPCR_PIN_MODE_SHIFT			(0x00000002UL)
@@ -44,53 +44,17 @@
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL	(0x00000001UL)
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN	(0x00000002UL)
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE	(0x00000003UL)
-/* Port X Interrupt Event Register 32bit (R/W) */
-#define U300_335_PXIEV					(0x08)
-/* Port X Interrupt Enable Register 32bit (R/W) */
-#define U300_335_PXIEN					(0x0C)
-/* Port X Interrupt Force Register 32bit (R/W) */
-#define U300_335_PXIFR					(0x10)
-/* Port X Interrupt Config Register 32bit (R/W) */
-#define U300_335_PXICR					(0x14)
-/* This register layout is the same in both blocks */
+#define U300_GPIO_PXPER					(0x10)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK	(0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE			(0x00000001UL)
+#define U300_GPIO_PXIEV					(0x14)
+#define U300_GPIO_PXIEN					(0x18)
+#define U300_GPIO_PXIFR					(0x1C)
+#define U300_GPIO_PXICR					(0x20)
 #define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK		(0x000000FFUL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_MASK			(0x00000001UL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE		(0x00000000UL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE		(0x00000001UL)
-/* Port X Pull-up Enable Register 32bit (R/W) */
-#define U300_335_PXPER					(0x18)
-/* This register layout is the same in both blocks */
-#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK	(0x000000FFUL)
-#define U300_GPIO_PXPER_PULL_UP_DISABLE			(0x00000001UL)
-/* Control Register 32bit (R/W) */
-#define U300_335_CR					(0x54)
-#define U300_335_CR_BLOCK_CLOCK_ENABLE			(0x00000001UL)
-
-/*
- * Register definitions for COH 901 571 / 3 variant
- */
-#define U300_571_PORT_STRIDE				(0x30)
-/*
- * Control Register 32bit (R/W)
- * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
- * gives the number of GPIO pins.
- * bit 8-2  (mask 0x000001FC) contains the core version ID.
- */
-#define U300_571_CR					(0x00)
-#define U300_571_CR_SYNC_SEL_ENABLE			(0x00000002UL)
-#define U300_571_CR_BLOCK_CLKRQ_ENABLE			(0x00000001UL)
-/*
- * These registers have the same layout and function as the corresponding
- * COH 901 335 registers, just at different offset.
- */
-#define U300_571_PXPDIR					(0x04)
-#define U300_571_PXPDOR					(0x08)
-#define U300_571_PXPCR					(0x0C)
-#define U300_571_PXPER					(0x10)
-#define U300_571_PXIEV					(0x14)
-#define U300_571_PXIEN					(0x18)
-#define U300_571_PXIFR					(0x1C)
-#define U300_571_PXICR					(0x20)
 
 /* 8 bits per port, no version has more than 7 ports */
 #define U300_GPIO_PINS_PER_PORT 8
@@ -149,8 +113,6 @@
 
 /* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */
 #define BS335_GPIO_NUM_PORTS 7
-/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */
-#define BS365_GPIO_NUM_PORTS 5
 
 #define U300_FLOATING_INPUT { \
 	.bias_mode = PIN_CONFIG_BIAS_HIGH_IMPEDANCE, \
@@ -172,7 +134,6 @@
 	.outval = 1, \
 }
 
-
 /* Initial configuration */
 static const struct __initconst u300_gpio_confdata
 bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
@@ -255,66 +216,6 @@
 	}
 };
 
-static const struct __initconst u300_gpio_confdata
-bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
-	/* Port 0, pins 0-7 */
-	{
-		U300_FLOATING_INPUT,
-		U300_OUTPUT_LOW,
-		U300_FLOATING_INPUT,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-		U300_PULL_UP_INPUT,
-		U300_FLOATING_INPUT,
-	},
-	/* Port 1, pins 0-7 */
-	{
-		U300_OUTPUT_LOW,
-		U300_FLOATING_INPUT,
-		U300_OUTPUT_LOW,
-		U300_FLOATING_INPUT,
-		U300_FLOATING_INPUT,
-		U300_OUTPUT_HIGH,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-	},
-	/* Port 2, pins 0-7 */
-	{
-		U300_FLOATING_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-	},
-	/* Port 3, pins 0-7 */
-	{
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-	},
-	/* Port 4, pins 0-7 */
-	{
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		U300_PULL_UP_INPUT,
-		/* These 4 pins doesn't exist on DB3210 */
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-		U300_OUTPUT_LOW,
-	}
-};
-
 /**
  * to_u300_gpio() - get the pointer to u300_gpio
  * @chip: the gpio chip member of the structure u300_gpio
@@ -716,13 +617,7 @@
 			const struct u300_gpio_confdata *conf;
 			int offset = (i*8) + j;
 
-			if (plat->variant == U300_GPIO_COH901571_3_BS335)
-				conf = &bs335_gpio_config[i][j];
-			else if (plat->variant == U300_GPIO_COH901571_3_BS365)
-				conf = &bs365_gpio_config[i][j];
-			else
-				break;
-
+			conf = &bs335_gpio_config[i][j];
 			u300_gpio_init_pin(gpio, offset, conf);
 		}
 	}
@@ -796,50 +691,27 @@
 		goto err_no_ioremap;
 	}
 
-	if (plat->variant == U300_GPIO_COH901335) {
-		dev_info(gpio->dev,
-			 "initializing GPIO Controller COH 901 335\n");
-		gpio->stride = U300_335_PORT_STRIDE;
-		gpio->pcr = U300_335_PXPCR;
-		gpio->dor = U300_335_PXPDOR;
-		gpio->dir = U300_335_PXPDIR;
-		gpio->per = U300_335_PXPER;
-		gpio->icr = U300_335_PXICR;
-		gpio->ien = U300_335_PXIEN;
-		gpio->iev = U300_335_PXIEV;
-		ifr = U300_335_PXIFR;
+	dev_info(gpio->dev,
+		 "initializing GPIO Controller COH 901 571/3\n");
+	gpio->stride = U300_GPIO_PORT_STRIDE;
+	gpio->pcr = U300_GPIO_PXPCR;
+	gpio->dor = U300_GPIO_PXPDOR;
+	gpio->dir = U300_GPIO_PXPDIR;
+	gpio->per = U300_GPIO_PXPER;
+	gpio->icr = U300_GPIO_PXICR;
+	gpio->ien = U300_GPIO_PXIEN;
+	gpio->iev = U300_GPIO_PXIEV;
+	ifr = U300_GPIO_PXIFR;
 
-		/* Turn on the GPIO block */
-		writel(U300_335_CR_BLOCK_CLOCK_ENABLE,
-		       gpio->base + U300_335_CR);
-	} else if (plat->variant == U300_GPIO_COH901571_3_BS335 ||
-		   plat->variant == U300_GPIO_COH901571_3_BS365) {
-		dev_info(gpio->dev,
-			 "initializing GPIO Controller COH 901 571/3\n");
-		gpio->stride = U300_571_PORT_STRIDE;
-		gpio->pcr = U300_571_PXPCR;
-		gpio->dor = U300_571_PXPDOR;
-		gpio->dir = U300_571_PXPDIR;
-		gpio->per = U300_571_PXPER;
-		gpio->icr = U300_571_PXICR;
-		gpio->ien = U300_571_PXIEN;
-		gpio->iev = U300_571_PXIEV;
-		ifr = U300_571_PXIFR;
-
-		val = readl(gpio->base + U300_571_CR);
-		dev_info(gpio->dev, "COH901571/3 block version: %d, " \
-			 "number of cores: %d totalling %d pins\n",
-			 ((val & 0x000001FC) >> 2),
-			 ((val & 0x0000FE00) >> 9),
-			 ((val & 0x0000FE00) >> 9) * 8);
-		writel(U300_571_CR_BLOCK_CLKRQ_ENABLE,
-		       gpio->base + U300_571_CR);
-		u300_gpio_init_coh901571(gpio, plat);
-	} else {
-		dev_err(gpio->dev, "unknown block variant\n");
-		err = -ENODEV;
-		goto err_unknown_variant;
-	}
+	val = readl(gpio->base + U300_GPIO_CR);
+	dev_info(gpio->dev, "COH901571/3 block version: %d, " \
+		 "number of cores: %d totalling %d pins\n",
+		 ((val & 0x000001FC) >> 2),
+		 ((val & 0x0000FE00) >> 9),
+		 ((val & 0x0000FE00) >> 9) * 8);
+	writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE,
+	       gpio->base + U300_GPIO_CR);
+	u300_gpio_init_coh901571(gpio, plat);
 
 	/* Add each port with its IRQ separately */
 	INIT_LIST_HEAD(&gpio->port_list);
@@ -906,7 +778,6 @@
 err_no_chip:
 err_no_port:
 	u300_gpio_free_ports(gpio);
-err_unknown_variant:
 	iounmap(gpio->base);
 err_no_ioremap:
 	release_mem_region(gpio->memres->start, resource_size(gpio->memres));
@@ -923,16 +794,11 @@
 
 static int __exit u300_gpio_remove(struct platform_device *pdev)
 {
-	struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
 	struct u300_gpio *gpio = platform_get_drvdata(pdev);
 	int err;
 
 	/* Turn off the GPIO block */
-	if (plat->variant == U300_GPIO_COH901335)
-		writel(0x00000000U, gpio->base + U300_335_CR);
-	if (plat->variant == U300_GPIO_COH901571_3_BS335 ||
-	    plat->variant == U300_GPIO_COH901571_3_BS365)
-		writel(0x00000000U, gpio->base + U300_571_CR);
+	writel(0x00000000U, gpio->base + U300_GPIO_CR);
 
 	err = gpiochip_remove(&gpio->chip);
 	if (err < 0) {
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index c1892f3..8097819 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -29,6 +29,13 @@
 	  Say Y here to enable support APM status emulation using
 	  battery class devices.
 
+config GENERIC_ADC_BATTERY
+	tristate "Generic battery support using IIO"
+	depends on IIO
+	help
+	  Say Y here to enable support for the generic battery driver
+	  which uses IIO framework to read adc.
+
 config MAX8925_POWER
 	tristate "MAX8925 battery charger support"
 	depends on MFD_MAX8925
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee58afb..e0b4d42 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -5,6 +5,7 @@
 power_supply-$(CONFIG_LEDS_TRIGGERS)	+= power_supply_leds.o
 
 obj-$(CONFIG_POWER_SUPPLY)	+= power_supply.o
+obj-$(CONFIG_GENERIC_ADC_BATTERY)	+= generic-adc-battery.o
 
 obj-$(CONFIG_PDA_POWER)		+= pda_power.o
 obj-$(CONFIG_APM_POWER)		+= apm_power.o
diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c
new file mode 100644
index 0000000..9bdf444
--- /dev/null
+++ b/drivers/power/generic-adc-battery.c
@@ -0,0 +1,422 @@
+/*
+ * Generic battery driver code using IIO
+ * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com>
+ * based on jz4740-battery.c
+ * based on s3c_adc_battery.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
+#include <linux/power/generic-adc-battery.h>
+
+#define JITTER_DEFAULT 10 /* hope 10ms is enough */
+
+enum gab_chan_type {
+	GAB_VOLTAGE = 0,
+	GAB_CURRENT,
+	GAB_POWER,
+	GAB_MAX_CHAN_TYPE
+};
+
+/*
+ * gab_chan_name suggests the standard channel names for commonly used
+ * channel types.
+ */
+static const char *const gab_chan_name[] = {
+	[GAB_VOLTAGE]	= "voltage",
+	[GAB_CURRENT]	= "current",
+	[GAB_POWER]		= "power",
+};
+
+struct gab {
+	struct power_supply	psy;
+	struct iio_channel	*channel[GAB_MAX_CHAN_TYPE];
+	struct gab_platform_data	*pdata;
+	struct delayed_work bat_work;
+	int	level;
+	int	status;
+	bool cable_plugged;
+};
+
+static struct gab *to_generic_bat(struct power_supply *psy)
+{
+	return container_of(psy, struct gab, psy);
+}
+
+static void gab_ext_power_changed(struct power_supply *psy)
+{
+	struct gab *adc_bat = to_generic_bat(psy);
+
+	schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0));
+}
+
+static const enum power_supply_property gab_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+};
+
+/*
+ * This properties are set based on the received platform data and this
+ * should correspond one-to-one with enum chan_type.
+ */
+static const enum power_supply_property gab_dyn_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_POWER_NOW,
+};
+
+static bool gab_charge_finished(struct gab *adc_bat)
+{
+	struct gab_platform_data *pdata = adc_bat->pdata;
+	bool ret = gpio_get_value(pdata->gpio_charge_finished);
+	bool inv = pdata->gpio_inverted;
+
+	if (!gpio_is_valid(pdata->gpio_charge_finished))
+		return false;
+	return ret ^ inv;
+}
+
+static int gab_get_status(struct gab *adc_bat)
+{
+	struct gab_platform_data *pdata = adc_bat->pdata;
+	struct power_supply_info *bat_info;
+
+	bat_info = &pdata->battery_info;
+	if (adc_bat->level == bat_info->charge_full_design)
+		return POWER_SUPPLY_STATUS_FULL;
+	return adc_bat->status;
+}
+
+static enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_POWER_NOW:
+		return GAB_POWER;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		return GAB_VOLTAGE;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		return GAB_CURRENT;
+	default:
+		WARN_ON(1);
+		break;
+	}
+	return GAB_POWER;
+}
+
+static int read_channel(struct gab *adc_bat, enum power_supply_property psp,
+		int *result)
+{
+	int ret;
+	int chan_index;
+
+	chan_index = gab_prop_to_chan(psp);
+	ret = iio_read_channel_processed(adc_bat->channel[chan_index],
+			result);
+	if (ret < 0)
+		pr_err("read channel error\n");
+	return ret;
+}
+
+static int gab_get_property(struct power_supply *psy,
+		enum power_supply_property psp, union power_supply_propval *val)
+{
+	struct gab *adc_bat;
+	struct gab_platform_data *pdata;
+	struct power_supply_info *bat_info;
+	int result = 0;
+	int ret = 0;
+
+	adc_bat = to_generic_bat(psy);
+	if (!adc_bat) {
+		dev_err(psy->dev, "no battery infos ?!\n");
+		return -EINVAL;
+	}
+	pdata = adc_bat->pdata;
+	bat_info = &pdata->battery_info;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		gab_get_status(adc_bat);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
+		val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = pdata->cal_charge(result);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+	case POWER_SUPPLY_PROP_POWER_NOW:
+		ret = read_channel(adc_bat, psp, &result);
+		if (ret < 0)
+			goto err;
+		val->intval = result;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = bat_info->technology;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		val->intval = bat_info->voltage_min_design;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = bat_info->voltage_max_design;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = bat_info->charge_full_design;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = bat_info->name;
+		break;
+	default:
+		return -EINVAL;
+	}
+err:
+	return ret;
+}
+
+static void gab_work(struct work_struct *work)
+{
+	struct gab *adc_bat;
+	struct gab_platform_data *pdata;
+	struct delayed_work *delayed_work;
+	bool is_plugged;
+	int status;
+
+	delayed_work = container_of(work, struct delayed_work, work);
+	adc_bat = container_of(delayed_work, struct gab, bat_work);
+	pdata = adc_bat->pdata;
+	status = adc_bat->status;
+
+	is_plugged = power_supply_am_i_supplied(&adc_bat->psy);
+	adc_bat->cable_plugged = is_plugged;
+
+	if (!is_plugged)
+		adc_bat->status =  POWER_SUPPLY_STATUS_DISCHARGING;
+	else if (gab_charge_finished(adc_bat))
+		adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+	else
+		adc_bat->status = POWER_SUPPLY_STATUS_CHARGING;
+
+	if (status != adc_bat->status)
+		power_supply_changed(&adc_bat->psy);
+}
+
+static irqreturn_t gab_charged(int irq, void *dev_id)
+{
+	struct gab *adc_bat = dev_id;
+	struct gab_platform_data *pdata = adc_bat->pdata;
+	int delay;
+
+	delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT;
+	schedule_delayed_work(&adc_bat->bat_work,
+			msecs_to_jiffies(delay));
+	return IRQ_HANDLED;
+}
+
+static int __devinit gab_probe(struct platform_device *pdev)
+{
+	struct gab *adc_bat;
+	struct power_supply *psy;
+	struct gab_platform_data *pdata = pdev->dev.platform_data;
+	enum power_supply_property *properties;
+	int ret = 0;
+	int chan;
+	int index = 0;
+
+	adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL);
+	if (!adc_bat) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	psy = &adc_bat->psy;
+	psy->name = pdata->battery_info.name;
+
+	/* bootup default values for the battery */
+	adc_bat->cable_plugged = false;
+	adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
+	psy->type = POWER_SUPPLY_TYPE_BATTERY;
+	psy->get_property = gab_get_property;
+	psy->external_power_changed = gab_ext_power_changed;
+	adc_bat->pdata = pdata;
+
+	/* calculate the total number of channels */
+	chan = ARRAY_SIZE(gab_chan_name);
+
+	/*
+	 * copying the static properties and allocating extra memory for holding
+	 * the extra configurable properties received from platform data.
+	 */
+	psy->properties = kcalloc(ARRAY_SIZE(gab_props) +
+					ARRAY_SIZE(gab_chan_name),
+					sizeof(*psy->properties), GFP_KERNEL);
+	if (!psy->properties) {
+		ret = -ENOMEM;
+		goto first_mem_fail;
+	}
+
+	memcpy(psy->properties, gab_props, sizeof(gab_props));
+	properties = psy->properties + sizeof(gab_props);
+
+	/*
+	 * getting channel from iio and copying the battery properties
+	 * based on the channel supported by consumer device.
+	 */
+	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
+		adc_bat->channel[chan] = iio_channel_get(dev_name(&pdev->dev),
+						gab_chan_name[chan]);
+		if (IS_ERR(adc_bat->channel[chan])) {
+			ret = PTR_ERR(adc_bat->channel[chan]);
+		} else {
+			/* copying properties for supported channels only */
+			memcpy(properties + sizeof(*(psy->properties)) * index,
+					&gab_dyn_props[chan],
+					sizeof(gab_dyn_props[chan]));
+			index++;
+		}
+	}
+
+	/* none of the channels are supported so let's bail out */
+	if (index == ARRAY_SIZE(gab_chan_name))
+		goto second_mem_fail;
+
+	/*
+	 * Total number of properties is equal to static properties
+	 * plus the dynamic properties.Some properties may not be set
+	 * as come channels may be not be supported by the device.So
+	 * we need to take care of that.
+	 */
+	psy->num_properties = ARRAY_SIZE(gab_props) + index;
+
+	ret = power_supply_register(&pdev->dev, psy);
+	if (ret)
+		goto err_reg_fail;
+
+	INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work);
+
+	if (gpio_is_valid(pdata->gpio_charge_finished)) {
+		int irq;
+		ret = gpio_request(pdata->gpio_charge_finished, "charged");
+		if (ret)
+			goto gpio_req_fail;
+
+		irq = gpio_to_irq(pdata->gpio_charge_finished);
+		ret = request_any_context_irq(irq, gab_charged,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"battery charged", adc_bat);
+		if (ret)
+			goto err_gpio;
+	}
+
+	platform_set_drvdata(pdev, adc_bat);
+
+	/* Schedule timer to check current status */
+	schedule_delayed_work(&adc_bat->bat_work,
+			msecs_to_jiffies(0));
+	return 0;
+
+err_gpio:
+	gpio_free(pdata->gpio_charge_finished);
+gpio_req_fail:
+	power_supply_unregister(psy);
+err_reg_fail:
+	for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
+		iio_channel_release(adc_bat->channel[chan]);
+second_mem_fail:
+	kfree(psy->properties);
+first_mem_fail:
+	return ret;
+}
+
+static int __devexit gab_remove(struct platform_device *pdev)
+{
+	int chan;
+	struct gab *adc_bat = platform_get_drvdata(pdev);
+	struct gab_platform_data *pdata = adc_bat->pdata;
+
+	power_supply_unregister(&adc_bat->psy);
+
+	if (gpio_is_valid(pdata->gpio_charge_finished)) {
+		free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat);
+		gpio_free(pdata->gpio_charge_finished);
+	}
+
+	for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
+		iio_channel_release(adc_bat->channel[chan]);
+
+	kfree(adc_bat->psy.properties);
+	cancel_delayed_work(&adc_bat->bat_work);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gab_suspend(struct device *dev)
+{
+	struct gab *adc_bat = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&adc_bat->bat_work);
+	adc_bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
+	return 0;
+}
+
+static int gab_resume(struct device *dev)
+{
+	struct gab *adc_bat = dev_get_drvdata(dev);
+	struct gab_platform_data *pdata = adc_bat->pdata;
+	int delay;
+
+	delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT;
+
+	/* Schedule timer to check current status */
+	schedule_delayed_work(&adc_bat->bat_work,
+			msecs_to_jiffies(delay));
+	return 0;
+}
+
+static const struct dev_pm_ops gab_pm_ops = {
+	.suspend        = gab_suspend,
+	.resume         = gab_resume,
+};
+
+#define GAB_PM_OPS       (&gab_pm_ops)
+#else
+#define GAB_PM_OPS       (NULL)
+#endif
+
+static struct platform_driver gab_driver = {
+	.driver		= {
+		.name	= "generic-adc-battery",
+		.owner	= THIS_MODULE,
+		.pm	= GAB_PM_OPS
+	},
+	.probe		= gab_probe,
+	.remove		= __devexit_p(gab_remove),
+};
+module_platform_driver(gab_driver);
+
+MODULE_AUTHOR("anish kumar <anish198519851985@gmail.com>");
+MODULE_DESCRIPTION("generic battery driver using IIO");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 5d44252..d5e1625 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -2219,9 +2219,7 @@
 				  const struct pci_device_id *id)
 {
 	struct tsi721_device *priv;
-	int cap;
 	int err;
-	u32 regval;
 
 	priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL);
 	if (priv == NULL) {
@@ -2330,20 +2328,16 @@
 			dev_info(&pdev->dev, "Unable to set consistent DMA mask\n");
 	}
 
-	cap = pci_pcie_cap(pdev);
-	BUG_ON(cap == 0);
+	BUG_ON(!pci_is_pcie(pdev));
 
 	/* Clear "no snoop" and "relaxed ordering" bits, use default MRRS. */
-	pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, &regval);
-	regval &= ~(PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_RELAX_EN |
-		    PCI_EXP_DEVCTL_NOSNOOP_EN);
-	regval |= 0x2 << MAX_READ_REQUEST_SZ_SHIFT;
-	pci_write_config_dword(pdev, cap + PCI_EXP_DEVCTL, regval);
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+		PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_RELAX_EN |
+		PCI_EXP_DEVCTL_NOSNOOP_EN,
+		0x2 << MAX_READ_REQUEST_SZ_SHIFT);
 
 	/* Adjust PCIe completion timeout. */
-	pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL2, &regval);
-	regval &= ~(0x0f);
-	pci_write_config_dword(pdev, cap + PCI_EXP_DEVCTL2, regval | 0x2);
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2);
 
 	/*
 	 * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc..e98a5e7 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -33,9 +33,8 @@
 	help
 	  If this option is enabled then when a regulator lookup fails
 	  and the board has not specified that it has provided full
-	  constraints then the regulator core will provide an always
-	  enabled dummy regulator will be provided, allowing consumer
-	  drivers to continue.
+	  constraints the regulator core will provide an always
+	  enabled dummy regulator, allowing consumer drivers to continue.
 
 	  A warning will be generated when this substitution is done.
 
@@ -50,11 +49,11 @@
 	tristate "Virtual regulator consumer support"
 	help
 	  This driver provides a virtual consumer for the voltage and
-          current regulator API which provides sysfs controls for
-          configuring the supplies requested.  This is mainly useful
-          for test purposes.
+	  current regulator API which provides sysfs controls for
+	  configuring the supplies requested.  This is mainly useful
+	  for test purposes.
 
-          If unsure, say no.
+	  If unsure, say no.
 
 config REGULATOR_USERSPACE_CONSUMER
 	tristate "Userspace regulator consumer support"
@@ -63,7 +62,7 @@
 	  from user space. Userspace consumer driver provides ability to
 	  control power supplies for such devices.
 
-          If unsure, say no.
+	  If unsure, say no.
 
 config REGULATOR_GPIO
 	tristate "GPIO regulator support"
@@ -110,6 +109,17 @@
 	  This driver supports the voltage regulators of DA9052-BC and
 	  DA9053-AA/Bx PMIC.
 
+config REGULATOR_FAN53555
+	tristate "Fairchild FAN53555 Regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports Fairchild FAN53555 Digitally Programmable
+	  TinyBuck Regulator. The FAN53555 is a step-down switching voltage
+	  regulator that delivers a digitally programmable output from an
+	  input voltage supply of 2.5V to 5.5V. The output voltage is
+	  programmed through an I2C interface.
+
 config REGULATOR_ANATOP
 	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
 	depends on MFD_ANATOP
@@ -172,6 +182,14 @@
 	  This driver controls a Maxim 8660/8661 voltage output
 	  regulator via I2C bus.
 
+config REGULATOR_MAX8907
+	tristate "Maxim 8907 voltage regulator"
+	depends on MFD_MAX8907
+	help
+	  This driver controls a Maxim 8907 voltage output regulator
+	  via I2C bus. The provided regulator is suitable for Tegra
+	  chip to control Step-Down DC-DC and LDOs.
+
 config REGULATOR_MAX8925
 	tristate "Maxim MAX8925 Power Management IC"
 	depends on MFD_MAX8925
@@ -247,7 +265,7 @@
 
 config REGULATOR_PCF50633
 	tristate "NXP PCF50633 regulator driver"
-        depends on MFD_PCF50633
+	depends on MFD_PCF50633
 	help
 	 Say Y here to support the voltage regulators and convertors
 	 on PCF50633
@@ -416,7 +434,7 @@
 	depends on MFD_WM8350
 	help
 	  This driver provides support for the voltage and current regulators
-          of the WM8350 AudioPlus PMIC.
+	  of the WM8350 AudioPlus PMIC.
 
 config REGULATOR_WM8400
 	tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3342615..e431eed 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
@@ -30,6 +31,7 @@
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
 obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index 6f45bfd..167c93f 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -162,7 +162,7 @@
 static int aat2870_regulator_probe(struct platform_device *pdev)
 {
 	struct aat2870_regulator *ri;
-	struct regulator_config config = { 0 };
+	struct regulator_config config = { };
 	struct regulator_dev *rdev;
 
 	ri = aat2870_get_regulator(pdev->id);
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index c151fd5..65ad2b3 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -347,17 +347,11 @@
 	return abreg->plfdata->external_voltage;
 }
 
-static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg)
-{
-	return reg->desc->min_uV;
-}
-
 static struct regulator_ops regulator_ops_fixed = {
 	.list_voltage = regulator_list_voltage_linear,
 	.enable      = ab3100_enable_regulator,
 	.disable     = ab3100_disable_regulator,
 	.is_enabled  = ab3100_is_enabled_regulator,
-	.get_voltage = ab3100_get_fixed_voltage_regulator,
 };
 
 static struct regulator_ops regulator_ops_variable = {
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 10f2f4d..e3d1d06 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -37,6 +37,7 @@
  * @voltage_bank: bank to control regulator voltage
  * @voltage_reg: register to control regulator voltage
  * @voltage_mask: mask to control regulator voltage
+ * @voltage_shift: shift to control regulator voltage
  * @delay: startup/set voltage delay in us
  */
 struct ab8500_regulator_info {
@@ -50,6 +51,7 @@
 	u8 voltage_bank;
 	u8 voltage_reg;
 	u8 voltage_mask;
+	u8 voltage_shift;
 	unsigned int delay;
 };
 
@@ -195,17 +197,14 @@
 	}
 
 	dev_vdbg(rdev_get_dev(rdev),
-		"%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
-		" 0x%x\n",
-		info->desc.name, info->voltage_bank, info->voltage_reg,
-		info->voltage_mask, regval);
+		"%s-get_voltage (bank, reg, mask, shift, value): "
+		"0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+		info->desc.name, info->voltage_bank,
+		info->voltage_reg, info->voltage_mask,
+		info->voltage_shift, regval);
 
-	/* vintcore has a different layout */
 	val = regval & info->voltage_mask;
-	if (info->desc.id == AB8500_LDO_INTCORE)
-		return val >> 0x3;
-	else
-		return val;
+	return val >> info->voltage_shift;
 }
 
 static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
@@ -221,7 +220,7 @@
 	}
 
 	/* set the registers for the request */
-	regval = (u8)selector;
+	regval = (u8)selector << info->voltage_shift;
 	ret = abx500_mask_and_set_register_interruptible(info->dev,
 			info->voltage_bank, info->voltage_reg,
 			info->voltage_mask, regval);
@@ -238,13 +237,6 @@
 	return ret;
 }
 
-static int ab8500_regulator_enable_time(struct regulator_dev *rdev)
-{
-	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-	return info->delay;
-}
-
 static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 					     unsigned int old_sel,
 					     unsigned int new_sel)
@@ -261,22 +253,14 @@
 	.get_voltage_sel = ab8500_regulator_get_voltage_sel,
 	.set_voltage_sel = ab8500_regulator_set_voltage_sel,
 	.list_voltage	= regulator_list_voltage_table,
-	.enable_time	= ab8500_regulator_enable_time,
 	.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
-static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
-{
-	return rdev->desc->min_uV;
-}
-
 static struct regulator_ops ab8500_regulator_fixed_ops = {
 	.enable		= ab8500_regulator_enable,
 	.disable	= ab8500_regulator_disable,
 	.is_enabled	= ab8500_regulator_is_enabled,
-	.get_voltage	= ab8500_fixed_get_voltage,
 	.list_voltage	= regulator_list_voltage_linear,
-	.enable_time	= ab8500_regulator_enable_time,
 };
 
 static struct ab8500_regulator_info
@@ -358,6 +342,7 @@
 		.voltage_bank		= 0x03,
 		.voltage_reg		= 0x80,
 		.voltage_mask		= 0x38,
+		.voltage_shift		= 3,
 	},
 
 	/*
@@ -374,6 +359,7 @@
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
 			.min_uV		= 2000000,
+			.enable_time	= 10000,
 		},
 		.delay			= 10000,
 		.update_bank		= 0x03,
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index c8f95c0..d184aa3 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -39,6 +39,8 @@
 	.map_voltage = regulator_map_voltage_linear,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 };
 
 static const struct regulator_desc arizona_ldo1 = {
@@ -49,9 +51,11 @@
 
 	.vsel_reg = ARIZONA_LDO1_CONTROL_1,
 	.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
+	.bypass_reg = ARIZONA_LDO1_CONTROL_1,
+	.bypass_mask = ARIZONA_LDO1_BYPASS,
 	.min_uV = 900000,
 	.uV_step = 50000,
-	.n_voltages = 7,
+	.n_voltages = 6,
 
 	.owner = THIS_MODULE,
 };
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 450a069..d9b1f82 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -82,6 +82,9 @@
 
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 };
 
 static const struct regulator_desc arizona_micsupp = {
@@ -95,6 +98,8 @@
 	.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
 	.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
 	.enable_mask = ARIZONA_CPMIC_ENA,
+	.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
+	.bypass_mask = ARIZONA_CPMIC_BYPASS,
 
 	.owner = THIS_MODULE,
 };
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 4838531..2e0352d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -77,6 +77,7 @@
 	struct device *dev;
 	struct list_head list;
 	unsigned int always_on:1;
+	unsigned int bypass:1;
 	int uA_load;
 	int min_uV;
 	int max_uV;
@@ -394,6 +395,9 @@
 	case REGULATOR_STATUS_STANDBY:
 		label = "standby";
 		break;
+	case REGULATOR_STATUS_BYPASS:
+		label = "bypass";
+		break;
 	case REGULATOR_STATUS_UNDEFINED:
 		label = "undefined";
 		break;
@@ -585,6 +589,27 @@
 static DEVICE_ATTR(suspend_standby_state, 0444,
 		regulator_suspend_standby_state_show, NULL);
 
+static ssize_t regulator_bypass_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	const char *report;
+	bool bypass;
+	int ret;
+
+	ret = rdev->desc->ops->get_bypass(rdev, &bypass);
+
+	if (ret != 0)
+		report = "unknown";
+	else if (bypass)
+		report = "enabled";
+	else
+		report = "disabled";
+
+	return sprintf(buf, "%s\n", report);
+}
+static DEVICE_ATTR(bypass, 0444,
+		   regulator_bypass_show, NULL);
 
 /*
  * These are the only attributes are present for all regulators.
@@ -778,6 +803,9 @@
 	if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
 		count += sprintf(buf + count, "standby");
 
+	if (!count)
+		sprintf(buf, "no parameters");
+
 	rdev_info(rdev, "%s\n", buf);
 
 	if ((constraints->min_uV != constraints->max_uV) &&
@@ -974,6 +1002,7 @@
 		err = -ENOMEM;
 		return err;
 	}
+	supply_rdev->open_count++;
 
 	return 0;
 }
@@ -1720,6 +1749,9 @@
 	if (regulator->always_on)
 		return 0;
 
+	if (!ms)
+		return regulator_disable(regulator);
+
 	mutex_lock(&rdev->mutex);
 	rdev->deferred_disables++;
 	mutex_unlock(&rdev->mutex);
@@ -2178,9 +2210,12 @@
 		}
 	}
 
-	if (ret == 0 && best_val >= 0)
+	if (ret == 0 && best_val >= 0) {
+		unsigned long data = best_val;
+
 		_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
-				     (void *)best_val);
+				     (void *)data);
+	}
 
 	trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
@@ -2291,8 +2326,8 @@
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
 
 /**
- *regulator_set_voltage_time_sel - get raise/fall time
- * @regulator: regulator source
+ * regulator_set_voltage_time_sel - get raise/fall time
+ * @rdev: regulator source device
  * @old_selector: selector for starting voltage
  * @new_selector: selector for target voltage
  *
@@ -2388,6 +2423,8 @@
 		ret = rdev->desc->ops->list_voltage(rdev, sel);
 	} else if (rdev->desc->ops->get_voltage) {
 		ret = rdev->desc->ops->get_voltage(rdev);
+	} else if (rdev->desc->ops->list_voltage) {
+		ret = rdev->desc->ops->list_voltage(rdev, 0);
 	} else {
 		return -EINVAL;
 	}
@@ -2674,6 +2711,100 @@
 EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
 
 /**
+ * regulator_set_bypass_regmap - Default set_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: state to set.
+ */
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
+{
+	unsigned int val;
+
+	if (enable)
+		val = rdev->desc->bypass_mask;
+	else
+		val = 0;
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
+				  rdev->desc->bypass_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
+
+/**
+ * regulator_get_bypass_regmap - Default get_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: current state.
+ */
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	*enable = val & rdev->desc->bypass_mask;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
+
+/**
+ * regulator_allow_bypass - allow the regulator to go into bypass mode
+ *
+ * @regulator: Regulator to configure
+ * @allow: enable or disable bypass mode
+ *
+ * Allow the regulator to go into bypass mode if all other consumers
+ * for the regulator also enable bypass mode and the machine
+ * constraints allow this.  Bypass mode means that the regulator is
+ * simply passing the input directly to the output with no regulation.
+ */
+int regulator_allow_bypass(struct regulator *regulator, bool enable)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret = 0;
+
+	if (!rdev->desc->ops->set_bypass)
+		return 0;
+
+	if (rdev->constraints &&
+	    !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
+		return 0;
+
+	mutex_lock(&rdev->mutex);
+
+	if (enable && !regulator->bypass) {
+		rdev->bypass_count++;
+
+		if (rdev->bypass_count == rdev->open_count) {
+			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			if (ret != 0)
+				rdev->bypass_count--;
+		}
+
+	} else if (!enable && regulator->bypass) {
+		rdev->bypass_count--;
+
+		if (rdev->bypass_count != rdev->open_count) {
+			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			if (ret != 0)
+				rdev->bypass_count++;
+		}
+	}
+
+	if (ret == 0)
+		regulator->bypass = enable;
+
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_allow_bypass);
+
+/**
  * regulator_register_notifier - register regulator event notifier
  * @regulator: regulator source
  * @nb: notifier block
@@ -3011,7 +3142,8 @@
 
 	/* some attributes need specific methods to be displayed */
 	if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
-	    (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) {
+	    (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
+	    (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) {
 		status = device_create_file(dev, &dev_attr_microvolts);
 		if (status < 0)
 			return status;
@@ -3036,6 +3168,11 @@
 		if (status < 0)
 			return status;
 	}
+	if (ops->get_bypass) {
+		status = device_create_file(dev, &dev_attr_bypass);
+		if (status < 0)
+			return status;
+	}
 
 	/* some attributes are type-specific */
 	if (rdev->desc->type == REGULATOR_CURRENT) {
@@ -3124,6 +3261,8 @@
 			   &rdev->use_count);
 	debugfs_create_u32("open_count", 0444, rdev->debugfs,
 			   &rdev->open_count);
+	debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
+			   &rdev->bypass_count);
 }
 
 /**
@@ -3189,8 +3328,10 @@
 	rdev->desc = regulator_desc;
 	if (config->regmap)
 		rdev->regmap = config->regmap;
-	else
+	else if (dev_get_regmap(dev, NULL))
 		rdev->regmap = dev_get_regmap(dev, NULL);
+	else if (dev->parent)
+		rdev->regmap = dev_get_regmap(dev->parent, NULL);
 	INIT_LIST_HEAD(&rdev->consumer_list);
 	INIT_LIST_HEAD(&rdev->list);
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 903299c..27355b1 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -133,8 +133,8 @@
 	    max_uA < da9052_current_limits[row][DA9052_MIN_UA])
 		return -EINVAL;
 
-	for (i = 0; i < DA9052_CURRENT_RANGE; i++) {
-		if (min_uA <= da9052_current_limits[row][i]) {
+	for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {
+		if (da9052_current_limits[row][i] <= max_uA) {
 			reg_val = i;
 			break;
 		}
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index 86f655c..03a1d7c 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -30,7 +30,7 @@
 static struct regulator_ops dummy_ops;
 
 static struct regulator_desc dummy_desc = {
-	.name = "dummy",
+	.name = "regulator-dummy",
 	.id = -1,
 	.type = REGULATOR_VOLTAGE,
 	.owner = THIS_MODULE,
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
new file mode 100644
index 0000000..339f4d7
--- /dev/null
+++ b/drivers/regulator/fan53555.c
@@ -0,0 +1,322 @@
+/*
+ * FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver.
+ *
+ * Supported Part Numbers:
+ * FAN53555UC00X/01X/03X/04X/05X
+ *
+ * Copyright (c) 2012 Marvell Technology Ltd.
+ * Yunfan Zhang <yfzhang@marvell.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/regulator/fan53555.h>
+
+/* Voltage setting */
+#define FAN53555_VSEL0		0x00
+#define FAN53555_VSEL1		0x01
+/* Control register */
+#define FAN53555_CONTROL	0x02
+/* IC Type */
+#define FAN53555_ID1		0x03
+/* IC mask version */
+#define FAN53555_ID2		0x04
+/* Monitor register */
+#define FAN53555_MONITOR	0x05
+
+/* VSEL bit definitions */
+#define VSEL_BUCK_EN	(1 << 7)
+#define VSEL_MODE		(1 << 6)
+#define VSEL_NSEL_MASK	0x3F
+/* Chip ID and Verison */
+#define DIE_ID		0x0F	/* ID1 */
+#define DIE_REV		0x0F	/* ID2 */
+/* Control bit definitions */
+#define CTL_OUTPUT_DISCHG	(1 << 7)
+#define CTL_SLEW_MASK		(0x7 << 4)
+#define CTL_SLEW_SHIFT		4
+#define CTL_RESET			(1 << 2)
+
+#define FAN53555_NVOLTAGES	64	/* Numbers of voltages */
+
+/* IC Type */
+enum {
+	FAN53555_CHIP_ID_00 = 0,
+	FAN53555_CHIP_ID_01,
+	FAN53555_CHIP_ID_02,
+	FAN53555_CHIP_ID_03,
+	FAN53555_CHIP_ID_04,
+	FAN53555_CHIP_ID_05,
+};
+
+struct fan53555_device_info {
+	struct regmap *regmap;
+	struct device *dev;
+	struct regulator_desc desc;
+	struct regulator_dev *rdev;
+	struct regulator_init_data *regulator;
+	/* IC Type and Rev */
+	int chip_id;
+	int chip_rev;
+	/* Voltage setting register */
+	unsigned int vol_reg;
+	unsigned int sleep_reg;
+	/* Voltage range and step(linear) */
+	unsigned int vsel_min;
+	unsigned int vsel_step;
+	/* Voltage slew rate limiting */
+	unsigned int slew_rate;
+	/* Sleep voltage cache */
+	unsigned int sleep_vol_cache;
+};
+
+static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int ret;
+
+	if (di->sleep_vol_cache == uV)
+		return 0;
+	ret = regulator_map_voltage_linear(rdev, uV, uV);
+	if (ret < 0)
+		return -EINVAL;
+	ret = regmap_update_bits(di->regmap, di->sleep_reg,
+					VSEL_NSEL_MASK, ret);
+	if (ret < 0)
+		return -EINVAL;
+	/* Cache the sleep voltage setting.
+	 * Might not be the real voltage which is rounded */
+	di->sleep_vol_cache = uV;
+
+	return 0;
+}
+
+static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		regmap_update_bits(di->regmap, di->vol_reg,
+				VSEL_MODE, VSEL_MODE);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret = 0;
+
+	ret = regmap_read(di->regmap, di->vol_reg, &val);
+	if (ret < 0)
+		return ret;
+	if (val & VSEL_MODE)
+		return REGULATOR_MODE_FAST;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops fan53555_regulator_ops = {
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.map_voltage = regulator_map_voltage_linear,
+	.list_voltage = regulator_list_voltage_linear,
+	.set_suspend_voltage = fan53555_set_suspend_voltage,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = fan53555_set_mode,
+	.get_mode = fan53555_get_mode,
+};
+
+/* For 00,01,03,05 options:
+ * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
+ * For 04 option:
+ * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
+ * */
+static int fan53555_device_setup(struct fan53555_device_info *di,
+				struct fan53555_platform_data *pdata)
+{
+	unsigned int reg, data, mask;
+
+	/* Setup voltage control register */
+	switch (pdata->sleep_vsel_id) {
+	case FAN53555_VSEL_ID_0:
+		di->sleep_reg = FAN53555_VSEL0;
+		di->vol_reg = FAN53555_VSEL1;
+		break;
+	case FAN53555_VSEL_ID_1:
+		di->sleep_reg = FAN53555_VSEL1;
+		di->vol_reg = FAN53555_VSEL0;
+		break;
+	default:
+		dev_err(di->dev, "Invalid VSEL ID!\n");
+		return -EINVAL;
+	}
+	/* Init voltage range and step */
+	switch (di->chip_id) {
+	case FAN53555_CHIP_ID_00:
+	case FAN53555_CHIP_ID_01:
+	case FAN53555_CHIP_ID_03:
+	case FAN53555_CHIP_ID_05:
+		di->vsel_min = 600000;
+		di->vsel_step = 10000;
+		break;
+	case FAN53555_CHIP_ID_04:
+		di->vsel_min = 603000;
+		di->vsel_step = 12826;
+		break;
+	default:
+		dev_err(di->dev,
+			"Chip ID[%d]\n not supported!\n", di->chip_id);
+		return -EINVAL;
+	}
+	/* Init slew rate */
+	if (pdata->slew_rate & 0x7)
+		di->slew_rate = pdata->slew_rate;
+	else
+		di->slew_rate = FAN53555_SLEW_RATE_64MV;
+	reg = FAN53555_CONTROL;
+	data = di->slew_rate << CTL_SLEW_SHIFT;
+	mask = CTL_SLEW_MASK;
+	return regmap_update_bits(di->regmap, reg, mask, data);
+}
+
+static int fan53555_regulator_register(struct fan53555_device_info *di,
+			struct regulator_config *config)
+{
+	struct regulator_desc *rdesc = &di->desc;
+
+	rdesc->name = "fan53555-reg";
+	rdesc->ops = &fan53555_regulator_ops;
+	rdesc->type = REGULATOR_VOLTAGE;
+	rdesc->n_voltages = FAN53555_NVOLTAGES;
+	rdesc->enable_reg = di->vol_reg;
+	rdesc->enable_mask = VSEL_BUCK_EN;
+	rdesc->min_uV = di->vsel_min;
+	rdesc->uV_step = di->vsel_step;
+	rdesc->vsel_reg = di->vol_reg;
+	rdesc->vsel_mask = VSEL_NSEL_MASK;
+	rdesc->owner = THIS_MODULE;
+
+	di->rdev = regulator_register(&di->desc, config);
+	if (IS_ERR(di->rdev))
+		return PTR_ERR(di->rdev);
+	return 0;
+
+}
+
+static struct regmap_config fan53555_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit fan53555_regulator_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct fan53555_device_info *di;
+	struct fan53555_platform_data *pdata;
+	struct regulator_config config = { };
+	unsigned int val;
+	int ret;
+
+	pdata = client->dev.platform_data;
+	if (!pdata || !pdata->regulator) {
+		dev_err(&client->dev, "Platform data not found!\n");
+		return -ENODEV;
+	}
+
+	di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
+					GFP_KERNEL);
+	if (!di) {
+		dev_err(&client->dev, "Failed to allocate device info data!\n");
+		return -ENOMEM;
+	}
+	di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
+	if (IS_ERR(di->regmap)) {
+		dev_err(&client->dev, "Failed to allocate regmap!\n");
+		return PTR_ERR(di->regmap);
+	}
+	di->dev = &client->dev;
+	di->regulator = pdata->regulator;
+	i2c_set_clientdata(client, di);
+	/* Get chip ID */
+	ret = regmap_read(di->regmap, FAN53555_ID1, &val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to get chip ID!\n");
+		return -ENODEV;
+	}
+	di->chip_id = val & DIE_ID;
+	/* Get chip revision */
+	ret = regmap_read(di->regmap, FAN53555_ID2, &val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to get chip Rev!\n");
+		return -ENODEV;
+	}
+	di->chip_rev = val & DIE_REV;
+	dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
+				di->chip_id, di->chip_rev);
+	/* Device init */
+	ret = fan53555_device_setup(di, pdata);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to setup device!\n");
+		return ret;
+	}
+	/* Register regulator */
+	config.dev = di->dev;
+	config.init_data = di->regulator;
+	config.regmap = di->regmap;
+	config.driver_data = di;
+	ret = fan53555_regulator_register(di, &config);
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to register regulator!\n");
+	return ret;
+
+}
+
+static int __devexit fan53555_regulator_remove(struct i2c_client *client)
+{
+	struct fan53555_device_info *di = i2c_get_clientdata(client);
+
+	regulator_unregister(di->rdev);
+	return 0;
+}
+
+static const struct i2c_device_id fan53555_id[] = {
+	{"fan53555", -1},
+	{ },
+};
+
+static struct i2c_driver fan53555_regulator_driver = {
+	.driver = {
+		.name = "fan53555-regulator",
+	},
+	.probe = fan53555_regulator_probe,
+	.remove = __devexit_p(fan53555_regulator_remove),
+	.id_table = fan53555_id,
+};
+
+module_i2c_driver(fan53555_regulator_driver);
+
+MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>");
+MODULE_DESCRIPTION("FAN53555 regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index 1d145a0..d8ecf49a 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -73,13 +73,7 @@
 	.map_voltage	= regulator_map_voltage_linear,
 };
 
-static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
-{
-	return dev->desc->min_uV;
-}
-
 static struct regulator_ops isl_fixed_ops = {
-	.get_voltage	= isl6271a_get_fixed_voltage,
 	.list_voltage	= regulator_list_voltage_linear,
 };
 
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 212c38e..708f4b6 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -86,6 +86,10 @@
 #define EXTERN_DVS_USED			0
 #define MAX_DELAY			6
 
+/* Default DVS Mode */
+#define LP8720_DEFAULT_DVS		0
+#define LP8725_DEFAULT_DVS		BIT(2)
+
 /* dump registers in regmap-debugfs */
 #define MAX_REGISTERS			0x0F
 
@@ -269,9 +273,9 @@
 	return val > MAX_DELAY ? 0 : val * time_step_us;
 }
 
-static void lp872x_set_dvs(struct lp872x *lp, int gpio)
+static void lp872x_set_dvs(struct lp872x *lp, enum lp872x_dvs_sel dvs_sel,
+			int gpio)
 {
-	enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel;
 	enum lp872x_dvs_state state;
 
 	state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW;
@@ -339,10 +343,10 @@
 	struct lp872x *lp = rdev_get_drvdata(rdev);
 	enum lp872x_regulator_id buck = rdev_get_id(rdev);
 	u8 addr, mask = LP872X_VOUT_M;
-	struct lp872x_dvs *dvs = lp->pdata->dvs;
+	struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL;
 
 	if (dvs && gpio_is_valid(dvs->gpio))
-		lp872x_set_dvs(lp, dvs->gpio);
+		lp872x_set_dvs(lp, dvs->vsel, dvs->gpio);
 
 	addr = lp872x_select_buck_vout_addr(lp, buck);
 	if (!lp872x_is_valid_buck_addr(addr))
@@ -374,8 +378,8 @@
 {
 	struct lp872x *lp = rdev_get_drvdata(rdev);
 	enum lp872x_regulator_id buck = rdev_get_id(rdev);
-	int i, max = ARRAY_SIZE(lp8725_buck_uA);
-	u8 addr, val;
+	int i;
+	u8 addr;
 
 	switch (buck) {
 	case LP8725_ID_BUCK1:
@@ -388,17 +392,15 @@
 		return -EINVAL;
 	}
 
-	for (i = 0 ; i < max ; i++)
+	for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) {
 		if (lp8725_buck_uA[i] >= min_uA &&
 			lp8725_buck_uA[i] <= max_uA)
-			break;
+			return lp872x_update_bits(lp, addr,
+						  LP8725_BUCK_CL_M,
+						  i << LP8725_BUCK_CL_S);
+	}
 
-	if (i == max)
-		return -EINVAL;
-
-	val = i << LP8725_BUCK_CL_S;
-
-	return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val);
+	return -EINVAL;
 }
 
 static int lp8725_buck_get_current_limit(struct regulator_dev *rdev)
@@ -727,39 +729,16 @@
 	},
 };
 
-static int lp872x_check_dvs_validity(struct lp872x *lp)
-{
-	struct lp872x_dvs *dvs = lp->pdata->dvs;
-	u8 val = 0;
-	int ret;
-
-	ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
-	if (ret)
-		return ret;
-
-	ret = 0;
-	if (lp->chipid == LP8720) {
-		if (val & LP8720_EXT_DVS_M)
-			ret = dvs ? 0 : -EINVAL;
-	} else {
-		if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED)
-			ret = dvs ? 0 : -EINVAL;
-	}
-
-	return ret;
-}
-
 static int lp872x_init_dvs(struct lp872x *lp)
 {
 	int ret, gpio;
-	struct lp872x_dvs *dvs = lp->pdata->dvs;
+	struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL;
 	enum lp872x_dvs_state pinstate;
+	u8 mask[] = { LP8720_EXT_DVS_M, LP8725_DVS1_M | LP8725_DVS2_M };
+	u8 default_dvs_mode[] = { LP8720_DEFAULT_DVS, LP8725_DEFAULT_DVS };
 
-	ret = lp872x_check_dvs_validity(lp);
-	if (ret) {
-		dev_warn(lp->dev, "invalid dvs data: %d\n", ret);
-		return ret;
-	}
+	if (!dvs)
+		goto set_default_dvs_mode;
 
 	gpio = dvs->gpio;
 	if (!gpio_is_valid(gpio)) {
@@ -778,6 +757,10 @@
 	lp->dvs_gpio = gpio;
 
 	return 0;
+
+set_default_dvs_mode:
+	return lp872x_update_bits(lp, LP872X_GENERAL_CFG, mask[lp->chipid],
+				default_dvs_mode[lp->chipid]);
 }
 
 static int lp872x_config(struct lp872x *lp)
@@ -785,24 +768,29 @@
 	struct lp872x_platform_data *pdata = lp->pdata;
 	int ret;
 
-	if (!pdata->update_config)
-		return 0;
+	if (!pdata || !pdata->update_config)
+		goto init_dvs;
 
 	ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config);
 	if (ret)
 		return ret;
 
+init_dvs:
 	return lp872x_init_dvs(lp);
 }
 
 static struct regulator_init_data
 *lp872x_find_regulator_init_data(int id, struct lp872x *lp)
 {
+	struct lp872x_platform_data *pdata = lp->pdata;
 	int i;
 
+	if (!pdata)
+		return NULL;
+
 	for (i = 0; i < lp->num_regulators; i++) {
-		if (lp->pdata->regulator_data[i].id == id)
-			return lp->pdata->regulator_data[i].init_data;
+		if (pdata->regulator_data[i].id == id)
+			return pdata->regulator_data[i].init_data;
 	}
 
 	return NULL;
@@ -863,18 +851,12 @@
 static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
 	struct lp872x *lp;
-	struct lp872x_platform_data *pdata = cl->dev.platform_data;
 	int ret, size, num_regulators;
 	const int lp872x_num_regulators[] = {
 		[LP8720] = LP8720_NUM_REGULATORS,
 		[LP8725] = LP8725_NUM_REGULATORS,
 	};
 
-	if (!pdata) {
-		dev_err(&cl->dev, "no platform data\n");
-		return -EINVAL;
-	}
-
 	lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
 	if (!lp)
 		goto err_mem;
@@ -894,7 +876,7 @@
 	}
 
 	lp->dev = &cl->dev;
-	lp->pdata = pdata;
+	lp->pdata = cl->dev.platform_data;
 	lp->chipid = id->driver_data;
 	lp->num_regulators = num_regulators;
 	i2c_set_clientdata(cl, lp);
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index 6356e82..ba3e0aa 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -69,6 +69,9 @@
 #define PIN_HIGH			1
 #define ENABLE_TIME_USEC		32
 
+#define BUCK_FPWM_MASK(x)		(1 << (x))
+#define BUCK_FPWM_SHIFT(x)		(x)
+
 enum lp8788_dvs_state {
 	DVS_LOW  = GPIOF_OUT_INIT_LOW,
 	DVS_HIGH = GPIOF_OUT_INIT_HIGH,
@@ -86,15 +89,9 @@
 	BUCK4,
 };
 
-struct lp8788_pwm_map {
-	u8 mask;
-	u8 shift;
-};
-
 struct lp8788_buck {
 	struct lp8788 *lp;
 	struct regulator_dev *regulator;
-	struct lp8788_pwm_map *pmap;
 	void *dvs;
 };
 
@@ -106,29 +103,6 @@
 	1950000, 2000000,
 };
 
-/* buck pwm mode selection : used for set/get_mode in regulator ops
- * @forced pwm : fast mode
- * @auto pwm   : normal mode
- */
-static struct lp8788_pwm_map buck_pmap[] = {
-	[BUCK1] = {
-		.mask = LP8788_FPWM_BUCK1_M,
-		.shift = LP8788_FPWM_BUCK1_S,
-	},
-	[BUCK2] = {
-		.mask = LP8788_FPWM_BUCK2_M,
-		.shift = LP8788_FPWM_BUCK2_S,
-	},
-	[BUCK3] = {
-		.mask = LP8788_FPWM_BUCK3_M,
-		.shift = LP8788_FPWM_BUCK3_S,
-	},
-	[BUCK4] = {
-		.mask = LP8788_FPWM_BUCK4_M,
-		.shift = LP8788_FPWM_BUCK4_S,
-	},
-};
-
 static const u8 buck1_vout_addr[] = {
 	LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
 	LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
@@ -347,41 +321,37 @@
 static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
-	struct lp8788_pwm_map *pmap = buck->pmap;
-	u8 val;
+	enum lp8788_buck_id id = rdev_get_id(rdev);
+	u8 mask, val;
 
-	if (!pmap)
-		return -EINVAL;
-
+	mask = BUCK_FPWM_MASK(id);
 	switch (mode) {
 	case REGULATOR_MODE_FAST:
-		val = LP8788_FORCE_PWM << pmap->shift;
+		val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);
 		break;
 	case REGULATOR_MODE_NORMAL:
-		val = LP8788_AUTO_PWM << pmap->shift;
+		val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val);
+	return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);
 }
 
 static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
 {
 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
-	struct lp8788_pwm_map *pmap = buck->pmap;
+	enum lp8788_buck_id id = rdev_get_id(rdev);
 	u8 val;
 	int ret;
 
-	if (!pmap)
-		return -EINVAL;
-
 	ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
 	if (ret)
 		return ret;
 
-	return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+	return val & BUCK_FPWM_MASK(id) ?
+				REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 }
 
 static struct regulator_ops lp8788_buck12_ops = {
@@ -459,27 +429,6 @@
 	},
 };
 
-static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp,
-					enum lp8788_buck_id id)
-{
-	u8 mask, val;
-
-	switch (id) {
-	case BUCK1:
-		mask = LP8788_BUCK1_DVS_SEL_M;
-		val  = LP8788_BUCK1_DVS_I2C;
-		break;
-	case BUCK2:
-		mask = LP8788_BUCK2_DVS_SEL_M;
-		val  = LP8788_BUCK2_DVS_I2C;
-		break;
-	default:
-		return 0;
-	}
-
-	return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val);
-}
-
 static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name)
 {
 	struct device *dev = buck->lp->dev;
@@ -530,6 +479,7 @@
 	struct lp8788_platform_data *pdata = buck->lp->pdata;
 	u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
 	u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
+	u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 
 	/* no dvs for buck3, 4 */
 	if (id == BUCK3 || id == BUCK4)
@@ -550,7 +500,8 @@
 				val[id]);
 
 set_default_dvs_mode:
-	return lp8788_set_default_dvs_ctrl_mode(buck->lp, id);
+	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
+				  default_dvs_mode[id]);
 }
 
 static __devinit int lp8788_buck_probe(struct platform_device *pdev)
@@ -567,7 +518,6 @@
 		return -ENOMEM;
 
 	buck->lp = lp;
-	buck->pmap = &buck_pmap[id];
 
 	ret = lp8788_init_dvs(buck, id);
 	if (ret)
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index d2122e4..6796eeb 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -496,6 +496,7 @@
 		.name = "dldo12",
 		.id = DLDO12,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_B,
@@ -521,6 +522,7 @@
 		.name = "aldo2",
 		.id = ALDO2,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_B,
@@ -530,6 +532,7 @@
 		.name = "aldo3",
 		.id = ALDO3,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_B,
@@ -539,6 +542,7 @@
 		.name = "aldo4",
 		.id = ALDO4,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_B,
@@ -548,6 +552,7 @@
 		.name = "aldo5",
 		.id = ALDO5,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_C,
@@ -583,6 +588,7 @@
 		.name = "aldo8",
 		.id = ALDO8,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_C,
@@ -592,6 +598,7 @@
 		.name = "aldo9",
 		.id = ALDO9,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_C,
@@ -601,6 +608,7 @@
 		.name = "aldo10",
 		.id = ALDO10,
 		.ops = &lp8788_ldo_voltage_fixed_ops,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 		.enable_reg = LP8788_EN_LDO_C,
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index c564af6..2a67d08 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -66,7 +66,7 @@
 };
 
 struct max77686_data {
-	struct regulator_dev **rdev;
+	struct regulator_dev *rdev[MAX77686_REGULATORS];
 };
 
 static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
@@ -265,6 +265,7 @@
 		rmatch.of_node = NULL;
 		of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
 		rdata[i].initdata = rmatch.init_data;
+		rdata[i].of_node = rmatch.of_node;
 	}
 
 	pdata->regulators = rdata;
@@ -283,10 +284,8 @@
 {
 	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 	struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
-	struct regulator_dev **rdev;
 	struct max77686_data *max77686;
-	int i,  size;
-	int ret = 0;
+	int i, ret = 0;
 	struct regulator_config config = { };
 
 	dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -313,45 +312,38 @@
 	if (!max77686)
 		return -ENOMEM;
 
-	size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS;
-	max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-	if (!max77686->rdev)
-		return -ENOMEM;
-
-	rdev = max77686->rdev;
 	config.dev = &pdev->dev;
 	config.regmap = iodev->regmap;
 	platform_set_drvdata(pdev, max77686);
 
 	for (i = 0; i < MAX77686_REGULATORS; i++) {
 		config.init_data = pdata->regulators[i].initdata;
+		config.of_node = pdata->regulators[i].of_node;
 
-		rdev[i] = regulator_register(&regulators[i], &config);
-		if (IS_ERR(rdev[i])) {
-			ret = PTR_ERR(rdev[i]);
+		max77686->rdev[i] = regulator_register(&regulators[i], &config);
+		if (IS_ERR(max77686->rdev[i])) {
+			ret = PTR_ERR(max77686->rdev[i]);
 			dev_err(&pdev->dev,
 				"regulator init failed for %d\n", i);
-				rdev[i] = NULL;
-				goto err;
+			max77686->rdev[i] = NULL;
+			goto err;
 		}
 	}
 
 	return 0;
 err:
 	while (--i >= 0)
-		regulator_unregister(rdev[i]);
+		regulator_unregister(max77686->rdev[i]);
 	return ret;
 }
 
 static int __devexit max77686_pmic_remove(struct platform_device *pdev)
 {
 	struct max77686_data *max77686 = platform_get_drvdata(pdev);
-	struct regulator_dev **rdev = max77686->rdev;
 	int i;
 
 	for (i = 0; i < MAX77686_REGULATORS; i++)
-		if (rdev[i])
-			regulator_unregister(rdev[i]);
+		regulator_unregister(max77686->rdev[i]);
 
 	return 0;
 }
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
new file mode 100644
index 0000000..af76075
--- /dev/null
+++ b/drivers/regulator/max8907-regulator.c
@@ -0,0 +1,408 @@
+/*
+ * max8907-regulator.c -- support regulators in max8907
+ *
+ * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
+ * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Portions based on drivers/regulator/tps65910-regulator.c,
+ *     Copyright 2010 Texas Instruments Inc.
+ *     Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *     Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8907.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define MAX8907_II2RR_VERSION_MASK	0xF0
+#define MAX8907_II2RR_VERSION_REV_A	0x00
+#define MAX8907_II2RR_VERSION_REV_B	0x10
+#define MAX8907_II2RR_VERSION_REV_C	0x30
+
+struct max8907_regulator {
+	struct regulator_desc desc[MAX8907_NUM_REGULATORS];
+	struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
+};
+
+#define REG_MBATT() \
+	[MAX8907_MBATT] = { \
+		.name = "MBATT", \
+		.supply_name = "mbatt", \
+		.id = MAX8907_MBATT, \
+		.ops = &max8907_mbatt_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+	}
+
+#define REG_LDO(ids, supply, base, min, max, step) \
+	[MAX8907_##ids] = { \
+		.name = #ids, \
+		.supply_name = supply, \
+		.id = MAX8907_##ids, \
+		.n_voltages = ((max) - (min)) / (step) + 1, \
+		.ops = &max8907_ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		.min_uV = (min), \
+		.uV_step = (step), \
+		.vsel_reg = (base) + MAX8907_VOUT, \
+		.vsel_mask = 0x3f, \
+		.enable_reg = (base) + MAX8907_CTL, \
+		.enable_mask = MAX8907_MASK_LDO_EN, \
+	}
+
+#define REG_FIXED(ids, supply, voltage) \
+	[MAX8907_##ids] = { \
+		.name = #ids, \
+		.supply_name = supply, \
+		.id = MAX8907_##ids, \
+		.n_voltages = 1, \
+		.ops = &max8907_fixed_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		.min_uV = (voltage), \
+	}
+
+#define REG_OUT5V(ids, supply, base, voltage) \
+	[MAX8907_##ids] = { \
+		.name = #ids, \
+		.supply_name = supply, \
+		.id = MAX8907_##ids, \
+		.n_voltages = 1, \
+		.ops = &max8907_out5v_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		.min_uV = (voltage), \
+		.enable_reg = (base), \
+		.enable_mask = MAX8907_MASK_OUT5V_EN, \
+	}
+
+#define REG_BBAT(ids, supply, base, min, max, step) \
+	[MAX8907_##ids] = { \
+		.name = #ids, \
+		.supply_name = supply, \
+		.id = MAX8907_##ids, \
+		.n_voltages = ((max) - (min)) / (step) + 1, \
+		.ops = &max8907_bbat_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		.min_uV = (min), \
+		.uV_step = (step), \
+		.vsel_reg = (base), \
+		.vsel_mask = MAX8907_MASK_VBBATTCV, \
+	}
+
+#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
+			750000, 3900000, 50000)
+#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
+			650000, 2225000, 25000)
+
+static struct regulator_ops max8907_mbatt_ops = {
+};
+
+static struct regulator_ops max8907_ldo_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops max8907_ldo_hwctl_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops max8907_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops max8907_out5v_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops max8907_out5v_hwctl_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops max8907_bbat_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_desc max8907_regulators[] = {
+	REG_MBATT(),
+	REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
+	REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
+	REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
+	LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
+	LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
+	LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
+	LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
+	LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
+	LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
+	LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
+	LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
+	LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
+	LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
+	LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
+	LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
+	LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
+	LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
+	LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
+	LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
+	LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
+	LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
+	LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
+	LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
+	REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
+	REG_OUT5V(OUT33V, "mbatt",  MAX8907_REG_OUT33VEN, 3300000),
+	REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
+						2400000, 3000000, 200000),
+	REG_FIXED(SDBY, "MBATT", 1200000),
+	REG_FIXED(VRTC, "MBATT", 3300000),
+};
+
+#ifdef CONFIG_OF
+
+#define MATCH(_name, _id) \
+	[MAX8907_##_id] = { \
+		.name = #_name, \
+		.driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
+	}
+
+static struct of_regulator_match max8907_matches[] = {
+	MATCH(mbatt, MBATT),
+	MATCH(sd1, SD1),
+	MATCH(sd2, SD2),
+	MATCH(sd3, SD3),
+	MATCH(ldo1, LDO1),
+	MATCH(ldo2, LDO2),
+	MATCH(ldo3, LDO3),
+	MATCH(ldo4, LDO4),
+	MATCH(ldo5, LDO5),
+	MATCH(ldo6, LDO6),
+	MATCH(ldo7, LDO7),
+	MATCH(ldo8, LDO8),
+	MATCH(ldo9, LDO9),
+	MATCH(ldo10, LDO10),
+	MATCH(ldo11, LDO11),
+	MATCH(ldo12, LDO12),
+	MATCH(ldo13, LDO13),
+	MATCH(ldo14, LDO14),
+	MATCH(ldo15, LDO15),
+	MATCH(ldo16, LDO16),
+	MATCH(ldo17, LDO17),
+	MATCH(ldo18, LDO18),
+	MATCH(ldo19, LDO19),
+	MATCH(ldo20, LDO20),
+	MATCH(out5v, OUT5V),
+	MATCH(out33v, OUT33V),
+	MATCH(bbat, BBAT),
+	MATCH(sdby, SDBY),
+	MATCH(vrtc, VRTC),
+};
+
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.parent->of_node;
+	struct device_node *regulators;
+	int ret;
+
+	if (!pdev->dev.parent->of_node)
+		return 0;
+
+	regulators = of_find_node_by_name(np, "regulators");
+	if (!regulators) {
+		dev_err(&pdev->dev, "regulators node not found\n");
+		return -EINVAL;
+	}
+
+	ret = of_regulator_match(pdev->dev.parent, regulators,
+				 max8907_matches,
+				 ARRAY_SIZE(max8907_matches));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+	return max8907_matches[index].init_data;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+	return max8907_matches[index].of_node;
+}
+#else
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+	return NULL;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+	return NULL;
+}
+#endif
+
+static __devinit int max8907_regulator_probe(struct platform_device *pdev)
+{
+	struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
+	struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
+	int ret;
+	struct max8907_regulator *pmic;
+	unsigned int val;
+	int i;
+	struct regulator_config config = {};
+	struct regulator_init_data *idata;
+	const char *mbatt_rail_name = NULL;
+
+	ret = max8907_regulator_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic) {
+		dev_err(&pdev->dev, "Failed to alloc pmic\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, pmic);
+
+	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
+
+	/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
+	regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+	if ((val & MAX8907_II2RR_VERSION_MASK) ==
+	    MAX8907_II2RR_VERSION_REV_B) {
+		pmic->desc[MAX8907_SD1].min_uV = 637500;
+		pmic->desc[MAX8907_SD1].uV_step = 12500;
+		pmic->desc[MAX8907_SD1].n_voltages =
+						(1425000 - 637500) / 12500 + 1;
+	}
+
+	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+		config.dev = pdev->dev.parent;
+		if (pdata)
+			idata = pdata->init_data[i];
+		else
+			idata = match_init_data(i);
+		config.init_data = idata;
+		config.driver_data = pmic;
+		config.regmap = max8907->regmap_gen;
+		config.of_node = match_of_node(i);
+
+		switch (pmic->desc[i].id) {
+		case MAX8907_MBATT:
+			if (idata && idata->constraints.name)
+				mbatt_rail_name = idata->constraints.name;
+			else
+				mbatt_rail_name = pmic->desc[i].name;
+			break;
+		case MAX8907_BBAT:
+		case MAX8907_SDBY:
+		case MAX8907_VRTC:
+			idata->supply_regulator = mbatt_rail_name;
+			break;
+		}
+
+		if (pmic->desc[i].ops == &max8907_ldo_ops) {
+			regmap_read(config.regmap, pmic->desc[i].enable_reg,
+				    &val);
+			if ((val & MAX8907_MASK_LDO_SEQ) !=
+			    MAX8907_MASK_LDO_SEQ)
+				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
+		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
+			regmap_read(config.regmap, pmic->desc[i].enable_reg,
+				    &val);
+			if ((val & (MAX8907_MASK_OUT5V_VINEN |
+						MAX8907_MASK_OUT5V_ENSRC)) !=
+			    MAX8907_MASK_OUT5V_ENSRC)
+				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
+		}
+
+		pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
+		if (IS_ERR(pmic->rdev[i])) {
+			dev_err(&pdev->dev,
+				"failed to register %s regulator\n",
+				pmic->desc[i].name);
+			ret = PTR_ERR(pmic->rdev[i]);
+			goto err_unregister_regulator;
+		}
+	}
+
+	return 0;
+
+err_unregister_regulator:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+	return ret;
+}
+
+static __devexit int max8907_regulator_remove(struct platform_device *pdev)
+{
+	struct max8907_regulator *pmic = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
+		regulator_unregister(pmic->rdev[i]);
+
+	return 0;
+}
+
+static struct platform_driver max8907_regulator_driver = {
+	.driver = {
+		   .name = "max8907-regulator",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = max8907_regulator_probe,
+	.remove = __devexit_p(max8907_regulator_remove),
+};
+
+static int __init max8907_regulator_init(void)
+{
+	return platform_driver_register(&max8907_regulator_driver);
+}
+
+subsys_initcall(max8907_regulator_init);
+
+static void __exit max8907_reg_exit(void)
+{
+	platform_driver_unregister(&max8907_regulator_driver);
+}
+
+module_exit(max8907_reg_exit);
+
+MODULE_DESCRIPTION("MAX8907 regulator driver");
+MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max8907-regulator");
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 4932e34..0801a6d 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -21,6 +21,30 @@
 #include <linux/module.h>
 #include "mc13xxx.h"
 
+#define MC13783_REG_SWITCHERS0			24
+/* Enable does not exist for SW1A */
+#define MC13783_REG_SWITCHERS0_SW1AEN			0
+#define MC13783_REG_SWITCHERS0_SW1AVSEL			0
+#define MC13783_REG_SWITCHERS0_SW1AVSEL_M		(63 << 0)
+
+#define MC13783_REG_SWITCHERS1			25
+/* Enable does not exist for SW1B */
+#define MC13783_REG_SWITCHERS1_SW1BEN			0
+#define MC13783_REG_SWITCHERS1_SW1BVSEL			0
+#define MC13783_REG_SWITCHERS1_SW1BVSEL_M		(63 << 0)
+
+#define MC13783_REG_SWITCHERS2			26
+/* Enable does not exist for SW2A */
+#define MC13783_REG_SWITCHERS2_SW2AEN			0
+#define MC13783_REG_SWITCHERS2_SW2AVSEL			0
+#define MC13783_REG_SWITCHERS2_SW2AVSEL_M		(63 << 0)
+
+#define MC13783_REG_SWITCHERS3			27
+/* Enable does not exist for SW2B */
+#define MC13783_REG_SWITCHERS3_SW2BEN			0
+#define MC13783_REG_SWITCHERS3_SW2BVSEL			0
+#define MC13783_REG_SWITCHERS3_SW2BVSEL_M		(63 << 0)
+
 #define MC13783_REG_SWITCHERS5			29
 #define MC13783_REG_SWITCHERS5_SW3EN			(1 << 20)
 #define MC13783_REG_SWITCHERS5_SW3VSEL			18
@@ -93,6 +117,44 @@
 
 
 /* Voltage Values */
+static const int mc13783_sw1x_val[] = {
+	900000, 925000, 950000, 975000,
+	1000000, 1025000, 1050000, 1075000,
+	1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000,
+	1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000,
+	1600000, 1625000, 1650000, 1675000,
+	1700000, 1700000, 1700000, 1700000,
+	1800000, 1800000, 1800000, 1800000,
+	1850000, 1850000, 1850000, 1850000,
+	2000000, 2000000, 2000000, 2000000,
+	2100000, 2100000, 2100000, 2100000,
+	2200000, 2200000, 2200000, 2200000,
+	2200000, 2200000, 2200000, 2200000,
+	2200000, 2200000, 2200000, 2200000,
+};
+
+static const int mc13783_sw2x_val[] = {
+	900000, 925000, 950000, 975000,
+	1000000, 1025000, 1050000, 1075000,
+	1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000,
+	1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000,
+	1600000, 1625000, 1650000, 1675000,
+	1700000, 1700000, 1700000, 1700000,
+	1800000, 1800000, 1800000, 1800000,
+	1900000, 1900000, 1900000, 1900000,
+	2000000, 2000000, 2000000, 2000000,
+	2100000, 2100000, 2100000, 2100000,
+	2200000, 2200000, 2200000, 2200000,
+	2200000, 2200000, 2200000, 2200000,
+	2200000, 2200000, 2200000, 2200000,
+};
+
 static const unsigned int mc13783_sw3_val[] = {
 	5000000, 5000000, 5000000, 5500000,
 };
@@ -188,6 +250,10 @@
 	MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages)
 
 static struct mc13xxx_regulator mc13783_regulators[] = {
+	MC13783_DEFINE_SW(SW1A, SWITCHERS0, SWITCHERS0, mc13783_sw1x_val),
+	MC13783_DEFINE_SW(SW1B, SWITCHERS1, SWITCHERS1, mc13783_sw1x_val),
+	MC13783_DEFINE_SW(SW2A, SWITCHERS2, SWITCHERS2, mc13783_sw2x_val),
+	MC13783_DEFINE_SW(SW2B, SWITCHERS3, SWITCHERS3, mc13783_sw2x_val),
 	MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val),
 
 	MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
@@ -238,9 +304,10 @@
 
 	BUG_ON(val & ~mask);
 
+	mc13xxx_lock(priv->mc13xxx);
 	ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
 	if (ret)
-		return ret;
+		goto out;
 
 	/* Update the stored state for Power Gates. */
 	priv->powermisc_pwgt_state =
@@ -253,7 +320,10 @@
 	valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
 						priv->powermisc_pwgt_state;
 
-	return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+	ret = mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+	return ret;
 }
 
 static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
@@ -261,7 +331,6 @@
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
 	int id = rdev_get_id(rdev);
-	int ret;
 	u32 en_val = mc13xxx_regulators[id].enable_bit;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -271,12 +340,8 @@
 	    id == MC13783_REG_PWGT2SPI)
 		en_val = 0;
 
-	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+	return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
 					en_val);
-	mc13xxx_unlock(priv->mc13xxx);
-
-	return ret;
 }
 
 static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
@@ -284,7 +349,6 @@
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
 	int id = rdev_get_id(rdev);
-	int ret;
 	u32 dis_val = 0;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -294,12 +358,8 @@
 	    id == MC13783_REG_PWGT2SPI)
 		dis_val = mc13xxx_regulators[id].enable_bit;
 
-	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+	return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
 					dis_val);
-	mc13xxx_unlock(priv->mc13xxx);
-
-	return ret;
 }
 
 static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
@@ -330,7 +390,6 @@
 	.is_enabled = mc13783_gpo_regulator_is_enabled,
 	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
-	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 
 static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index b388b74..1fa6381 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -305,9 +305,10 @@
 
 	BUG_ON(val & ~mask);
 
+	mc13xxx_lock(priv->mc13xxx);
 	ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
 	if (ret)
-		return ret;
+		goto out;
 
 	/* Update the stored state for Power Gates. */
 	priv->powermisc_pwgt_state =
@@ -320,14 +321,16 @@
 	valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
 		priv->powermisc_pwgt_state;
 
-	return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+	ret = mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+	return ret;
 }
 
 static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
 {
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	int id = rdev_get_id(rdev);
-	int ret;
 	u32 en_val = mc13892_regulators[id].enable_bit;
 	u32 mask = mc13892_regulators[id].enable_bit;
 
@@ -340,18 +343,13 @@
 	if (id == MC13892_GPO4)
 		mask |= MC13892_POWERMISC_GPO4ADINEN;
 
-	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13892_powermisc_rmw(priv, mask, en_val);
-	mc13xxx_unlock(priv->mc13xxx);
-
-	return ret;
+	return mc13892_powermisc_rmw(priv, mask, en_val);
 }
 
 static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
 {
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	int id = rdev_get_id(rdev);
-	int ret;
 	u32 dis_val = 0;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -360,12 +358,8 @@
 	if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
 		dis_val = mc13892_regulators[id].enable_bit;
 
-	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
+	return mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
 		dis_val);
-	mc13xxx_unlock(priv->mc13xxx);
-
-	return ret;
 }
 
 static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
@@ -396,14 +390,13 @@
 	.is_enabled = mc13892_gpo_regulator_is_enabled,
 	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
-	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 
-static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
+static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	int ret, id = rdev_get_id(rdev);
-	unsigned int val, hi;
+	unsigned int val;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
@@ -414,17 +407,11 @@
 	if (ret)
 		return ret;
 
-	hi  = val & MC13892_SWITCHERS0_SWxHI;
 	val = (val & mc13892_regulators[id].vsel_mask)
 		>> mc13892_regulators[id].vsel_shift;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
 
-	if (hi)
-		val = (25000 * val) + 1100000;
-	else
-		val = (25000 * val) + 600000;
-
 	return val;
 }
 
@@ -432,37 +419,25 @@
 						unsigned selector)
 {
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-	int hi, value, mask, id = rdev_get_id(rdev);
-	u32 valread;
+	int volt, mask, id = rdev_get_id(rdev);
+	u32 reg_value;
 	int ret;
 
-	value = rdev->desc->volt_table[selector];
+	volt = rdev->desc->volt_table[selector];
+	mask = mc13892_regulators[id].vsel_mask;
+	reg_value = selector << mc13892_regulators[id].vsel_shift;
+
+	if (volt > 1375000) {
+		mask |= MC13892_SWITCHERS0_SWxHI;
+		reg_value |= MC13892_SWITCHERS0_SWxHI;
+	} else if (volt < 1100000) {
+		mask |= MC13892_SWITCHERS0_SWxHI;
+		reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+	}
 
 	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13xxx_reg_read(priv->mc13xxx,
-		mc13892_regulators[id].vsel_reg, &valread);
-	if (ret)
-		goto err;
-
-	if (value > 1375000)
-		hi = 1;
-	else if (value < 1100000)
-		hi = 0;
-	else
-		hi = valread & MC13892_SWITCHERS0_SWxHI;
-
-	if (hi) {
-		value = (value - 1100000) / 25000;
-		value |= MC13892_SWITCHERS0_SWxHI;
-	} else
-		value = (value - 600000) / 25000;
-
-	mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
-	valread = (valread & ~mask) |
-			(value << mc13892_regulators[id].vsel_shift);
-	ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
-			valread);
-err:
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
+			      reg_value);
 	mc13xxx_unlock(priv->mc13xxx);
 
 	return ret;
@@ -471,7 +446,7 @@
 static struct regulator_ops mc13892_sw_regulator_ops = {
 	.list_voltage = regulator_list_voltage_table,
 	.set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
-	.get_voltage = mc13892_sw_regulator_get_voltage,
+	.get_voltage_sel = mc13892_sw_regulator_get_voltage_sel,
 };
 
 static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index d6eda28..88cbb83 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -143,30 +143,21 @@
 		__func__, id, min_uV, max_uV);
 
 	if (min_uV <= rdev->desc->volt_table[0] &&
-	    rdev->desc->volt_table[0] <= max_uV)
+	    rdev->desc->volt_table[0] <= max_uV) {
+		*selector = 0;
 		return 0;
-	else
+	} else {
 		return -EINVAL;
+	}
 }
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
 
-int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
-{
-	int id = rdev_get_id(rdev);
-
-	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
-	return rdev->desc->volt_table[0];
-}
-EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
-
 struct regulator_ops mc13xxx_fixed_regulator_ops = {
 	.enable = mc13xxx_regulator_enable,
 	.disable = mc13xxx_regulator_disable,
 	.is_enabled = mc13xxx_regulator_is_enabled,
 	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
-	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
 
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index eaff551..06c8903 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -34,7 +34,6 @@
 
 extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
 		int min_uV, int max_uV, unsigned *selector);
-extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
 
 #ifdef CONFIG_OF
 extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 3e4106f..6f68491 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -92,16 +92,18 @@
 EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
 
 /**
- * of_regulator_match - extract regulator init data when node
- * property "regulator-compatible" matches with the regulator name.
+ * of_regulator_match - extract multiple regulator init data from device tree.
  * @dev: device requesting the data
  * @node: parent device node of the regulators
  * @matches: match table for the regulators
  * @num_matches: number of entries in match table
  *
- * This function uses a match table specified by the regulator driver and
- * looks up the corresponding init data in the device tree  if
- * regulator-compatible matches. Note that the match table is modified
+ * This function uses a match table specified by the regulator driver to
+ * parse regulator init data from the device tree. @node is expected to
+ * contain a set of child nodes, each providing the init data for one
+ * regulator. The data parsed from a child node will be matched to a regulator
+ * based on either the deprecated property regulator-compatible if present,
+ * or otherwise the child node's name. Note that the match table is modified
  * in place.
  *
  * Returns the number of matches found or a negative error code on failure.
@@ -112,26 +114,23 @@
 {
 	unsigned int count = 0;
 	unsigned int i;
-	const char *regulator_comp;
+	const char *name;
 	struct device_node *child;
 
 	if (!dev || !node)
 		return -EINVAL;
 
 	for_each_child_of_node(node, child) {
-		regulator_comp = of_get_property(child,
+		name = of_get_property(child,
 					"regulator-compatible", NULL);
-		if (!regulator_comp) {
-			dev_err(dev, "regulator-compatible is missing for node %s\n",
-				child->name);
-			continue;
-		}
+		if (!name)
+			name = child->name;
 		for (i = 0; i < num_matches; i++) {
 			struct of_regulator_match *match = &matches[i];
 			if (match->of_node)
 				continue;
 
-			if (strcmp(match->name, regulator_comp))
+			if (strcmp(match->name, name))
 				continue;
 
 			match->init_data =
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 46c7e88..2ba7502 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -443,44 +443,6 @@
 	return  850000 + (selector * 50000);
 }
 
-static int palmas_get_voltage_ldo_sel(struct regulator_dev *dev)
-{
-	struct palmas_pmic *pmic = rdev_get_drvdata(dev);
-	int id = rdev_get_id(dev);
-	int selector;
-	unsigned int reg;
-	unsigned int addr;
-
-	addr = palmas_regs_info[id].vsel_addr;
-
-	palmas_ldo_read(pmic->palmas, addr, &reg);
-
-	selector = reg & PALMAS_LDO1_VOLTAGE_VSEL_MASK;
-
-	/* Adjust selector to match list_voltage ranges */
-	if (selector > 49)
-		selector = 49;
-
-	return selector;
-}
-
-static int palmas_set_voltage_ldo_sel(struct regulator_dev *dev,
-		unsigned selector)
-{
-	struct palmas_pmic *pmic = rdev_get_drvdata(dev);
-	int id = rdev_get_id(dev);
-	unsigned int reg = 0;
-	unsigned int addr;
-
-	addr = palmas_regs_info[id].vsel_addr;
-
-	reg = selector;
-
-	palmas_ldo_write(pmic->palmas, addr, reg);
-
-	return 0;
-}
-
 static int palmas_map_voltage_ldo(struct regulator_dev *rdev,
 		int min_uV, int max_uV)
 {
@@ -505,8 +467,8 @@
 	.is_enabled		= palmas_is_enabled_ldo,
 	.enable			= regulator_enable_regmap,
 	.disable		= regulator_disable_regmap,
-	.get_voltage_sel	= palmas_get_voltage_ldo_sel,
-	.set_voltage_sel	= palmas_set_voltage_ldo_sel,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
 	.list_voltage		= palmas_list_voltage_ldo,
 	.map_voltage		= palmas_map_voltage_ldo,
 };
@@ -757,6 +719,9 @@
 
 		pmic->desc[id].type = REGULATOR_VOLTAGE;
 		pmic->desc[id].owner = THIS_MODULE;
+		pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+						palmas_regs_info[id].vsel_addr);
+		pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
 		pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
 						palmas_regs_info[id].ctrl_addr);
 		pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 4669dc9..926f9c8 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -24,7 +24,7 @@
 #include <linux/mfd/samsung/s2mps11.h>
 
 struct s2mps11_info {
-	struct regulator_dev **rdev;
+	struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
 
 	int ramp_delay2;
 	int ramp_delay34;
@@ -236,9 +236,8 @@
 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
 	struct regulator_config config = { };
-	struct regulator_dev **rdev;
 	struct s2mps11_info *s2mps11;
-	int i, ret, size;
+	int i, ret;
 	unsigned char ramp_enable, ramp_reg = 0;
 
 	if (!pdata) {
@@ -251,13 +250,6 @@
 	if (!s2mps11)
 		return -ENOMEM;
 
-	size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX;
-	s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-	if (!s2mps11->rdev) {
-		return -ENOMEM;
-	}
-
-	rdev = s2mps11->rdev;
 	platform_set_drvdata(pdev, s2mps11);
 
 	s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
@@ -297,12 +289,12 @@
 		config.init_data = pdata->regulators[i].initdata;
 		config.driver_data = s2mps11;
 
-		rdev[i] = regulator_register(&regulators[i], &config);
-		if (IS_ERR(rdev[i])) {
-			ret = PTR_ERR(rdev[i]);
+		s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
+		if (IS_ERR(s2mps11->rdev[i])) {
+			ret = PTR_ERR(s2mps11->rdev[i]);
 			dev_err(&pdev->dev, "regulator init failed for %d\n",
 				i);
-			rdev[i] = NULL;
+			s2mps11->rdev[i] = NULL;
 			goto err;
 		}
 	}
@@ -310,8 +302,7 @@
 	return 0;
 err:
 	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
-		if (rdev[i])
-			regulator_unregister(rdev[i]);
+		regulator_unregister(s2mps11->rdev[i]);
 
 	return ret;
 }
@@ -319,12 +310,10 @@
 static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
 {
 	struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
-	struct regulator_dev **rdev = s2mps11->rdev;
 	int i;
 
 	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
-		if (rdev[i])
-			regulator_unregister(rdev[i]);
+		regulator_unregister(s2mps11->rdev[i]);
 
 	return 0;
 }
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 947ece9..058d2f2 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -502,15 +502,13 @@
 	if (info->n_ilimsels == 1)
 		return -EINVAL;
 
-	for (i = 0; i < info->n_ilimsels; i++)
+	for (i = info->n_ilimsels - 1; i >= 0; i--) {
 		if (min_uA <= info->ilimsels[i] &&
 		    max_uA >= info->ilimsels[i])
-			break;
+			return write_field(hw, &info->ilimsel, i);
+	}
 
-	if (i >= info->n_ilimsels)
-		return -EINVAL;
-
-	return write_field(hw, &info->ilimsel, i);
+	return -EINVAL;
 }
 
 static int get_current_limit(struct regulator_dev *rdev)
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 19241fc..ce1e7cb 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -57,9 +57,6 @@
 struct tps6586x_regulator {
 	struct regulator_desc desc;
 
-	int volt_reg;
-	int volt_shift;
-	int volt_nbits;
 	int enable_bit[2];
 	int enable_reg[2];
 
@@ -81,10 +78,10 @@
 	int ret, val, rid = rdev_get_id(rdev);
 	uint8_t mask;
 
-	val = selector << ri->volt_shift;
-	mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+	val = selector << (ffs(rdev->desc->vsel_mask) - 1);
+	mask = rdev->desc->vsel_mask;
 
-	ret = tps6586x_update(parent, ri->volt_reg, val, mask);
+	ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
 	if (ret)
 		return ret;
 
@@ -100,66 +97,17 @@
 	return ret;
 }
 
-static int tps6586x_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-	struct device *parent = to_tps6586x_dev(rdev);
-	uint8_t val, mask;
-	int ret;
-
-	ret = tps6586x_read(parent, ri->volt_reg, &val);
-	if (ret)
-		return ret;
-
-	mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
-	val = (val & mask) >> ri->volt_shift;
-
-	if (val >= ri->desc.n_voltages)
-		BUG();
-
-	return val;
-}
-
-static int tps6586x_regulator_enable(struct regulator_dev *rdev)
-{
-	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-	struct device *parent = to_tps6586x_dev(rdev);
-
-	return tps6586x_set_bits(parent, ri->enable_reg[0],
-				 1 << ri->enable_bit[0]);
-}
-
-static int tps6586x_regulator_disable(struct regulator_dev *rdev)
-{
-	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-	struct device *parent = to_tps6586x_dev(rdev);
-
-	return tps6586x_clr_bits(parent, ri->enable_reg[0],
-				 1 << ri->enable_bit[0]);
-}
-
-static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
-{
-	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-	struct device *parent = to_tps6586x_dev(rdev);
-	uint8_t reg_val;
-	int ret;
-
-	ret = tps6586x_read(parent, ri->enable_reg[0], &reg_val);
-	if (ret)
-		return ret;
-
-	return !!(reg_val & (1 << ri->enable_bit[0]));
-}
-
 static struct regulator_ops tps6586x_regulator_ops = {
 	.list_voltage = regulator_list_voltage_table,
-	.get_voltage_sel = tps6586x_get_voltage_sel,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = tps6586x_set_voltage_sel,
 
-	.is_enabled = tps6586x_regulator_is_enabled,
-	.enable = tps6586x_regulator_enable,
-	.disable = tps6586x_regulator_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+};
+
+static struct regulator_ops tps6586x_sys_regulator_ops = {
 };
 
 static const unsigned int tps6586x_ldo0_voltages[] = {
@@ -202,10 +150,11 @@
 		.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),	\
 		.volt_table = tps6586x_##vdata##_voltages,		\
 		.owner	= THIS_MODULE,					\
+		.enable_reg = TPS6586X_SUPPLY##ereg0,			\
+		.enable_mask = 1 << (ebit0),				\
+		.vsel_reg = TPS6586X_##vreg,				\
+		.vsel_mask = ((1 << (nbits)) - 1) << (shift),		\
 	},								\
-	.volt_reg	= TPS6586X_##vreg,				\
-	.volt_shift	= (shift),					\
-	.volt_nbits	= (nbits),					\
 	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
 	.enable_bit[0]	= (ebit0),					\
 	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
@@ -230,15 +179,28 @@
 	TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
 }
 
+#define TPS6586X_SYS_REGULATOR()					\
+{									\
+	.desc	= {							\
+		.supply_name = "sys",					\
+		.name	= "REG-SYS",					\
+		.ops	= &tps6586x_sys_regulator_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= TPS6586X_ID_SYS,				\
+		.owner	= THIS_MODULE,					\
+	},								\
+}
+
 static struct tps6586x_regulator tps6586x_regulator[] = {
+	TPS6586X_SYS_REGULATOR(),
 	TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0),
 	TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
-	TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+	TPS6586X_LDO(LDO_5, "REG-SYS", ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
 	TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
 	TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
 	TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
 	TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
-	TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
+	TPS6586X_LDO(LDO_RTC, "REG-SYS", ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
 	TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
 	TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
 
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 77a71a5..7eb986a 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -10,6 +10,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -624,18 +626,9 @@
 	return info->min_mV * 1000;
 }
 
-static int twlfixed_get_voltage(struct regulator_dev *rdev)
-{
-	struct twlreg_info	*info = rdev_get_drvdata(rdev);
-
-	return info->min_mV * 1000;
-}
-
 static struct regulator_ops twl4030fixed_ops = {
 	.list_voltage	= twlfixed_list_voltage,
 
-	.get_voltage	= twlfixed_get_voltage,
-
 	.enable		= twl4030reg_enable,
 	.disable	= twl4030reg_disable,
 	.is_enabled	= twl4030reg_is_enabled,
@@ -648,8 +641,6 @@
 static struct regulator_ops twl6030fixed_ops = {
 	.list_voltage	= twlfixed_list_voltage,
 
-	.get_voltage	= twlfixed_get_voltage,
-
 	.enable		= twl6030reg_enable,
 	.disable	= twl6030reg_disable,
 	.is_enabled	= twl6030reg_is_enabled,
@@ -659,13 +650,6 @@
 	.get_status	= twl6030reg_get_status,
 };
 
-static struct regulator_ops twl6030_fixed_resource = {
-	.enable		= twl6030reg_enable,
-	.disable	= twl6030reg_disable,
-	.is_enabled	= twl6030reg_is_enabled,
-	.get_status	= twl6030reg_get_status,
-};
-
 /*
  * SMPS status and control
  */
@@ -757,37 +741,32 @@
 	return voltage;
 }
 
-static int
-twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
-			unsigned int *selector)
+static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV)
 {
-	struct twlreg_info	*info = rdev_get_drvdata(rdev);
-	int	vsel = 0;
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
+	int vsel = 0;
 
 	switch (info->flags) {
 	case 0:
 		if (min_uV == 0)
 			vsel = 0;
 		else if ((min_uV >= 600000) && (min_uV <= 1300000)) {
-			int calc_uV;
 			vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
 			vsel++;
-			calc_uV = twl6030smps_list_voltage(rdev, vsel);
-			if (calc_uV > max_uV)
-				return -EINVAL;
 		}
 		/* Values 1..57 for vsel are linear and can be calculated
 		 * values 58..62 are non linear.
 		 */
-		else if ((min_uV > 1900000) && (max_uV >= 2100000))
+		else if ((min_uV > 1900000) && (min_uV <= 2100000))
 			vsel = 62;
-		else if ((min_uV > 1800000) && (max_uV >= 1900000))
+		else if ((min_uV > 1800000) && (min_uV <= 1900000))
 			vsel = 61;
-		else if ((min_uV > 1500000) && (max_uV >= 1800000))
+		else if ((min_uV > 1500000) && (min_uV <= 1800000))
 			vsel = 60;
-		else if ((min_uV > 1350000) && (max_uV >= 1500000))
+		else if ((min_uV > 1350000) && (min_uV <= 1500000))
 			vsel = 59;
-		else if ((min_uV > 1300000) && (max_uV >= 1350000))
+		else if ((min_uV > 1300000) && (min_uV <= 1350000))
 			vsel = 58;
 		else
 			return -EINVAL;
@@ -796,25 +775,21 @@
 		if (min_uV == 0)
 			vsel = 0;
 		else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
-			int calc_uV;
 			vsel = DIV_ROUND_UP(min_uV - 700000, 12500);
 			vsel++;
-			calc_uV = twl6030smps_list_voltage(rdev, vsel);
-			if (calc_uV > max_uV)
-				return -EINVAL;
 		}
 		/* Values 1..57 for vsel are linear and can be calculated
 		 * values 58..62 are non linear.
 		 */
-		else if ((min_uV > 1900000) && (max_uV >= 2100000))
+		else if ((min_uV > 1900000) && (min_uV <= 2100000))
 			vsel = 62;
-		else if ((min_uV > 1800000) && (max_uV >= 1900000))
+		else if ((min_uV > 1800000) && (min_uV <= 1900000))
 			vsel = 61;
-		else if ((min_uV > 1350000) && (max_uV >= 1800000))
+		else if ((min_uV > 1350000) && (min_uV <= 1800000))
 			vsel = 60;
-		else if ((min_uV > 1350000) && (max_uV >= 1500000))
+		else if ((min_uV > 1350000) && (min_uV <= 1500000))
 			vsel = 59;
-		else if ((min_uV > 1300000) && (max_uV >= 1350000))
+		else if ((min_uV > 1300000) && (min_uV <= 1350000))
 			vsel = 58;
 		else
 			return -EINVAL;
@@ -830,17 +805,23 @@
 	case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
 		if (min_uV == 0) {
 			vsel = 0;
-		} else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+		} else if ((min_uV >= 2161000) && (min_uV <= 4321000)) {
 			vsel = DIV_ROUND_UP(min_uV - 2161000, 38600);
 			vsel++;
 		}
 		break;
 	}
 
-	*selector = vsel;
+	return vsel;
+}
+
+static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev,
+				       unsigned int selector)
+{
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
 
 	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
-							vsel);
+			    selector);
 }
 
 static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
@@ -852,8 +833,9 @@
 
 static struct regulator_ops twlsmps_ops = {
 	.list_voltage		= twl6030smps_list_voltage,
+	.map_voltage		= twl6030smps_map_voltage,
 
-	.set_voltage		= twl6030smps_set_voltage,
+	.set_voltage_sel	= twl6030smps_set_voltage_sel,
 	.get_voltage_sel	= twl6030smps_get_voltage_sel,
 
 	.enable			= twl6030reg_enable,
@@ -876,7 +858,7 @@
 			0x0, TWL6030, twl6030fixed_ops)
 
 #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
-static struct twlreg_info TWL4030_INFO_##label = { \
+static const struct twlreg_info TWL4030_INFO_##label = { \
 	.base = offset, \
 	.id = num, \
 	.table_len = ARRAY_SIZE(label##_VSEL_table), \
@@ -894,7 +876,7 @@
 	}
 
 #define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
-static struct twlreg_info TWL4030_INFO_##label = { \
+static const struct twlreg_info TWL4030_INFO_##label = { \
 	.base = offset, \
 	.id = num, \
 	.remap = remap_conf, \
@@ -909,7 +891,7 @@
 	}
 
 #define TWL6030_ADJUSTABLE_SMPS(label) \
-static struct twlreg_info TWL6030_INFO_##label = { \
+static const struct twlreg_info TWL6030_INFO_##label = { \
 	.desc = { \
 		.name = #label, \
 		.id = TWL6030_REG_##label, \
@@ -920,7 +902,7 @@
 	}
 
 #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
-static struct twlreg_info TWL6030_INFO_##label = { \
+static const struct twlreg_info TWL6030_INFO_##label = { \
 	.base = offset, \
 	.min_mV = min_mVolts, \
 	.max_mV = max_mVolts, \
@@ -935,7 +917,7 @@
 	}
 
 #define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
-static struct twlreg_info TWL6025_INFO_##label = { \
+static const struct twlreg_info TWL6025_INFO_##label = { \
 	.base = offset, \
 	.min_mV = min_mVolts, \
 	.max_mV = max_mVolts, \
@@ -951,7 +933,7 @@
 
 #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
 		family, operations) \
-static struct twlreg_info TWLFIXED_INFO_##label = { \
+static const struct twlreg_info TWLFIXED_INFO_##label = { \
 	.base = offset, \
 	.id = num, \
 	.min_mV = mVolts, \
@@ -981,7 +963,7 @@
 	}
 
 #define TWL6025_ADJUSTABLE_SMPS(label, offset) \
-static struct twlreg_info TWLSMPS_INFO_##label = { \
+static const struct twlreg_info TWLSMPS_INFO_##label = { \
 	.base = offset, \
 	.min_mV = 600, \
 	.max_mV = 2100, \
@@ -1138,6 +1120,7 @@
 {
 	int				i, id;
 	struct twlreg_info		*info;
+	const struct twlreg_info	*template;
 	struct regulator_init_data	*initdata;
 	struct regulation_constraints	*c;
 	struct regulator_dev		*rdev;
@@ -1147,17 +1130,17 @@
 
 	match = of_match_device(twl_of_match, &pdev->dev);
 	if (match) {
-		info = match->data;
-		id = info->desc.id;
+		template = match->data;
+		id = template->desc.id;
 		initdata = of_get_regulator_init_data(&pdev->dev,
 						      pdev->dev.of_node);
 		drvdata = NULL;
 	} else {
 		id = pdev->id;
 		initdata = pdev->dev.platform_data;
-		for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
-			info = twl_of_match[i].data;
-			if (info && info->desc.id == id)
+		for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
+			template = twl_of_match[i].data;
+			if (template && template->desc.id == id)
 				break;
 		}
 		if (i == ARRAY_SIZE(twl_of_match))
@@ -1168,12 +1151,16 @@
 			return -EINVAL;
 	}
 
-	if (!info)
+	if (!template)
 		return -ENODEV;
 
 	if (!initdata)
 		return -EINVAL;
 
+	info = kmemdup(template, sizeof (*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
 	if (drvdata) {
 		/* copy the driver data into regulator data */
 		info->features = drvdata->features;
@@ -1234,6 +1221,7 @@
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "can't register %s, %ld\n",
 				info->desc.name, PTR_ERR(rdev));
+		kfree(info);
 		return PTR_ERR(rdev);
 	}
 	platform_set_drvdata(pdev, rdev);
@@ -1255,7 +1243,11 @@
 
 static int __devexit twlreg_remove(struct platform_device *pdev)
 {
-	regulator_unregister(platform_get_drvdata(pdev));
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct twlreg_info *info = rdev->reg_data;
+
+	regulator_unregister(rdev);
+	kfree(info);
 	return 0;
 }
 
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 7413885..90cbcc6 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -339,16 +339,15 @@
 	u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) {
+	for (i = ARRAY_SIZE(wm831x_dcdc_ilim) - 1; i >= 0; i--) {
 		if ((min_uA <= wm831x_dcdc_ilim[i]) &&
 		    (wm831x_dcdc_ilim[i] <= max_uA))
-			break;
+			return wm831x_set_bits(wm831x, reg,
+					       WM831X_DC1_HC_THR_MASK,
+						i << WM831X_DC1_HC_THR_SHIFT);
 	}
-	if (i == ARRAY_SIZE(wm831x_dcdc_ilim))
-		return -EINVAL;
 
-	return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK,
-			       i << WM831X_DC1_HC_THR_SHIFT);
+	return -EINVAL;
 }
 
 static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 5cb70ca..9af5126 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -205,6 +205,8 @@
 
 	/* Is it reporting under voltage? */
 	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+	if (ret < 0)
+		return ret;
 	if (ret & mask)
 		return REGULATOR_STATUS_ERROR;
 
@@ -237,6 +239,8 @@
 	.set_mode = wm831x_gp_ldo_set_mode,
 	.get_status = wm831x_gp_ldo_get_status,
 	.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
@@ -293,6 +297,8 @@
 	ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
 	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
 	ldo->desc.enable_mask = 1 << id;
+	ldo->desc.bypass_reg = ldo->base;
+	ldo->desc.bypass_mask = WM831X_LDO1_SWI;
 
 	config.dev = pdev->dev.parent;
 	if (pdata)
@@ -469,6 +475,8 @@
 
 	/* Is it reporting under voltage? */
 	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+	if (ret < 0)
+		return ret;
 	if (ret & mask)
 		return REGULATOR_STATUS_ERROR;
 
@@ -488,6 +496,8 @@
 	.get_mode = wm831x_aldo_get_mode,
 	.set_mode = wm831x_aldo_set_mode,
 	.get_status = wm831x_aldo_get_status,
+	.set_bypass = regulator_set_bypass_regmap,
+	.get_bypass = regulator_get_bypass_regmap,
 
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
@@ -544,6 +554,8 @@
 	ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
 	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
 	ldo->desc.enable_mask = 1 << id;
+	ldo->desc.bypass_reg = ldo->base;
+	ldo->desc.bypass_mask = WM831X_LDO7_SWI;
 
 	config.dev = pdev->dev.parent;
 	if (pdata)
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 9035dd0..27c746e 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -120,13 +120,8 @@
 
 	case REGULATOR_MODE_IDLE:
 		/* Datasheet: standby */
-		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
-				      WM8400_DC1_ACTIVE, 0);
-		if (ret != 0)
-			return ret;
 		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
-				       WM8400_DC1_SLEEP, 0);
-
+				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP, 0);
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index a1f7ac1..b54504e 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -29,7 +29,7 @@
 #include <linux/remoteproc.h>
 
 #include <plat/mailbox.h>
-#include <plat/remoteproc.h>
+#include <linux/platform_data/remoteproc-omap.h>
 
 #include "omap_remoteproc.h"
 #include "remoteproc_internal.h"
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 590cfaf..1859f71 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -1008,8 +1008,8 @@
 	return 0;
 
 free_coherent:
-	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, bufs_va,
-					vrp->bufs_dma);
+	dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE,
+					bufs_va, vrp->bufs_dma);
 vqs_del:
 	vdev->config->del_vqs(vrp->vdev);
 free_vrp:
@@ -1043,7 +1043,7 @@
 
 	vdev->config->del_vqs(vrp->vdev);
 
-	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+	dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE,
 					vrp->rbufs, vrp->bufs_dma);
 
 	kfree(vrp);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index c5d06fe..9277d94 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -495,6 +495,11 @@
 	if (ret < 0)
 		goto out1;
 
+	/* ensure interrupts are disabled, bootloaders can be strange */
+	ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG);
+	if (ret < 0)
+		dev_warn(&pdev->dev, "unable to disable interrupt\n");
+
 	/* init cached IRQ enable bits */
 	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
 	if (ret < 0)
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 8e477bb..4a3b623 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -70,3 +70,21 @@
 	  This driver provides a character device interface to the
 	  DASD extended error reporting. This is only needed if you want to
 	  use applications written for the EER facility.
+
+config SCM_BLOCK
+	def_tristate m
+	prompt "Support for Storage Class Memory"
+	depends on S390 && BLOCK && EADM_SCH && SCM_BUS
+	help
+	  Block device driver for Storage Class Memory (SCM). This driver
+	  provides a block device interface for each available SCM increment.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called scm_block.
+
+config SCM_BLOCK_CLUSTER_WRITE
+	def_bool y
+	prompt "SCM force cluster writes"
+	depends on SCM_BLOCK
+	help
+	  Force writes to Storage Class Memory (SCM) to be in done in clusters.
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index 0a89e08..c2f4e67 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -17,3 +17,9 @@
 obj-$(CONFIG_DASD_FBA)  += dasd_fba_mod.o
 obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
 obj-$(CONFIG_DCSSBLK) += dcssblk.o
+
+scm_block-objs := scm_drv.o scm_blk.o
+ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
+scm_block-objs += scm_blk_cluster.o
+endif
+obj-$(CONFIG_SCM_BLOCK) += scm_block.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 15370a2..0595c76 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -534,11 +534,11 @@
 	if (rc)
 		device->target = device->state;
 
-	if (device->state == device->target)
-		wake_up(&dasd_init_waitq);
-
 	/* let user-space know that the device status changed */
 	kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE);
+
+	if (device->state == device->target)
+		wake_up(&dasd_init_waitq);
 }
 
 /*
@@ -2157,6 +2157,7 @@
 		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
 		    (!dasd_eer_enabled(device))) {
 			cqr->status = DASD_CQR_FAILED;
+			cqr->intrc = -EAGAIN;
 			continue;
 		}
 		/* Don't try to start requests if device is stopped */
@@ -3270,6 +3271,16 @@
 			dasd_schedule_device_bh(device);
 		}
 		if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
+			if (!(device->path_data.opm & eventlpm) &&
+			    !(device->path_data.tbvpm & eventlpm)) {
+				/*
+				 * we can not establish a pathgroup on an
+				 * unavailable path, so trigger a path
+				 * verification first
+				 */
+				device->path_data.tbvpm |= eventlpm;
+				dasd_schedule_device_bh(device);
+			}
 			DBF_DEV_EVENT(DBF_WARNING, device, "%s",
 				      "Pathgroup re-established\n");
 			if (device->discipline->kick_validate)
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 157defe..6b55699 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -384,6 +384,29 @@
 		group->next = NULL;
 };
 
+static int
+suborder_not_supported(struct dasd_ccw_req *cqr)
+{
+	char *sense;
+	char reason;
+	char msg_format;
+	char msg_no;
+
+	sense = dasd_get_sense(&cqr->irb);
+	if (!sense)
+		return 0;
+
+	reason = sense[0];
+	msg_format = (sense[7] & 0xF0);
+	msg_no = (sense[7] & 0x0F);
+
+	/* command reject, Format 0 MSG 4 - invalid parameter */
+	if ((reason == 0x80) && (msg_format == 0x00) && (msg_no == 0x04))
+		return 1;
+
+	return 0;
+}
+
 static int read_unit_address_configuration(struct dasd_device *device,
 					   struct alias_lcu *lcu)
 {
@@ -435,6 +458,8 @@
 
 	do {
 		rc = dasd_sleep_on(cqr);
+		if (rc && suborder_not_supported(cqr))
+			return -EOPNOTSUPP;
 	} while (rc && (cqr->retries > 0));
 	if (rc) {
 		spin_lock_irqsave(&lcu->lock, flags);
@@ -521,7 +546,7 @@
 	 * processing the data
 	 */
 	spin_lock_irqsave(&lcu->lock, flags);
-	if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
+	if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {
 		DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
 			    " alias data in lcu (rc = %d), retry later", rc);
 		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 2fb2b9e..108332b 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -20,6 +20,7 @@
 #include <linux/compat.h>
 #include <linux/init.h>
 
+#include <asm/css_chars.h>
 #include <asm/debug.h>
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
@@ -31,8 +32,6 @@
 
 #include "dasd_int.h"
 #include "dasd_eckd.h"
-#include "../cio/chsc.h"
-
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -140,6 +139,10 @@
 static const int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
 
+/* head and record addresses of count_area read in analysis ccw */
+static const int count_area_head[] = { 0, 0, 0, 0, 2 };
+static const int count_area_rec[] = { 1, 2, 3, 4, 1 };
+
 static inline unsigned int
 round_up_multiple(unsigned int no, unsigned int mult)
 {
@@ -212,7 +215,7 @@
 
 	rc = get_sync_clock(&data->ep_sys_time);
 	/* Ignore return code if sync clock is switched off. */
-	if (rc == -ENOSYS || rc == -EACCES)
+	if (rc == -EOPNOTSUPP || rc == -EACCES)
 		rc = 0;
 
 	de_ccw->count = sizeof(struct DE_eckd_data);
@@ -323,7 +326,7 @@
 
 	rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time);
 	/* Ignore return code if sync clock is switched off. */
-	if (rc == -ENOSYS || rc == -EACCES)
+	if (rc == -EOPNOTSUPP || rc == -EACCES)
 		rc = 0;
 	return rc;
 }
@@ -1507,7 +1510,8 @@
  * call might change behaviour of DASD devices.
  */
 static int
-dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav)
+dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav,
+		  unsigned long flags)
 {
 	struct dasd_ccw_req *cqr;
 	int rc;
@@ -1516,10 +1520,19 @@
 	if (IS_ERR(cqr))
 		return PTR_ERR(cqr);
 
+	/*
+	 * set flags e.g. turn on failfast, to prevent blocking
+	 * the calling function should handle failed requests
+	 */
+	cqr->flags |= flags;
+
 	rc = dasd_sleep_on(cqr);
 	if (!rc)
 		/* trigger CIO to reprobe devices */
 		css_schedule_reprobe();
+	else if (cqr->intrc == -EAGAIN)
+		rc = -EAGAIN;
+
 	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
@@ -1527,7 +1540,8 @@
 /*
  * Valide storage server of current device.
  */
-static void dasd_eckd_validate_server(struct dasd_device *device)
+static int dasd_eckd_validate_server(struct dasd_device *device,
+				     unsigned long flags)
 {
 	int rc;
 	struct dasd_eckd_private *private;
@@ -1536,17 +1550,18 @@
 	private = (struct dasd_eckd_private *) device->private;
 	if (private->uid.type == UA_BASE_PAV_ALIAS ||
 	    private->uid.type == UA_HYPER_PAV_ALIAS)
-		return;
+		return 0;
 	if (dasd_nopav || MACHINE_IS_VM)
 		enable_pav = 0;
 	else
 		enable_pav = 1;
-	rc = dasd_eckd_psf_ssc(device, enable_pav);
+	rc = dasd_eckd_psf_ssc(device, enable_pav, flags);
 
 	/* may be requested feature is not available on server,
 	 * therefore just report error and go ahead */
 	DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
 			"returned rc=%d", private->uid.ssid, rc);
+	return rc;
 }
 
 /*
@@ -1556,7 +1571,13 @@
 {
 	struct dasd_device *device = container_of(work, struct dasd_device,
 						  kick_validate);
-	dasd_eckd_validate_server(device);
+	if (dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST)
+	    == -EAGAIN) {
+		/* schedule worker again if failed */
+		schedule_work(&device->kick_validate);
+		return;
+	}
+
 	dasd_put_device(device);
 }
 
@@ -1685,7 +1706,7 @@
 	if (rc)
 		goto out_err2;
 
-	dasd_eckd_validate_server(device);
+	dasd_eckd_validate_server(device, 0);
 
 	/* device may report different configuration data after LCU setup */
 	rc = dasd_eckd_read_conf(device);
@@ -1922,7 +1943,10 @@
 	count_area = NULL;
 	for (i = 0; i < 3; i++) {
 		if (private->count_area[i].kl != 4 ||
-		    private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4) {
+		    private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4 ||
+		    private->count_area[i].cyl != 0 ||
+		    private->count_area[i].head != count_area_head[i] ||
+		    private->count_area[i].record != count_area_rec[i]) {
 			private->uses_cdl = 0;
 			break;
 		}
@@ -1934,7 +1958,10 @@
 		for (i = 0; i < 5; i++) {
 			if ((private->count_area[i].kl != 0) ||
 			    (private->count_area[i].dl !=
-			     private->count_area[0].dl))
+			     private->count_area[0].dl) ||
+			    private->count_area[i].cyl !=  0 ||
+			    private->count_area[i].head != count_area_head[i] ||
+			    private->count_area[i].record != count_area_rec[i])
 				break;
 		}
 		if (i == 5)
@@ -4153,7 +4180,7 @@
 	rc = dasd_alias_make_device_known_to_lcu(device);
 	if (rc)
 		return rc;
-	dasd_eckd_validate_server(device);
+	dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST);
 
 	/* RE-Read Configuration Data */
 	rc = dasd_eckd_read_conf(device);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 654c692..8252f37 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -292,12 +292,12 @@
 #else
 static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
-	return -ENOSYS;
+	return -ENOTTY;
 }
 
 static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
-	return -ENOSYS;
+	return -ENOTTY;
 }
 #endif
 
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
new file mode 100644
index 0000000..9978ad4
--- /dev/null
+++ b/drivers/s390/block/scm_blk.c
@@ -0,0 +1,445 @@
+/*
+ * Block driver for s390 storage class memory.
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#define KMSG_COMPONENT "scm_block"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <asm/eadm.h>
+#include "scm_blk.h"
+
+debug_info_t *scm_debug;
+static int scm_major;
+static DEFINE_SPINLOCK(list_lock);
+static LIST_HEAD(inactive_requests);
+static unsigned int nr_requests = 64;
+static atomic_t nr_devices = ATOMIC_INIT(0);
+module_param(nr_requests, uint, S_IRUGO);
+MODULE_PARM_DESC(nr_requests, "Number of parallel requests.");
+
+MODULE_DESCRIPTION("Block driver for s390 storage class memory.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("scm:scmdev*");
+
+static void __scm_free_rq(struct scm_request *scmrq)
+{
+	struct aob_rq_header *aobrq = to_aobrq(scmrq);
+
+	free_page((unsigned long) scmrq->aob);
+	free_page((unsigned long) scmrq->aidaw);
+	__scm_free_rq_cluster(scmrq);
+	kfree(aobrq);
+}
+
+static void scm_free_rqs(void)
+{
+	struct list_head *iter, *safe;
+	struct scm_request *scmrq;
+
+	spin_lock_irq(&list_lock);
+	list_for_each_safe(iter, safe, &inactive_requests) {
+		scmrq = list_entry(iter, struct scm_request, list);
+		list_del(&scmrq->list);
+		__scm_free_rq(scmrq);
+	}
+	spin_unlock_irq(&list_lock);
+}
+
+static int __scm_alloc_rq(void)
+{
+	struct aob_rq_header *aobrq;
+	struct scm_request *scmrq;
+
+	aobrq = kzalloc(sizeof(*aobrq) + sizeof(*scmrq), GFP_KERNEL);
+	if (!aobrq)
+		return -ENOMEM;
+
+	scmrq = (void *) aobrq->data;
+	scmrq->aidaw = (void *) get_zeroed_page(GFP_DMA);
+	scmrq->aob = (void *) get_zeroed_page(GFP_DMA);
+	if (!scmrq->aob || !scmrq->aidaw) {
+		__scm_free_rq(scmrq);
+		return -ENOMEM;
+	}
+
+	if (__scm_alloc_rq_cluster(scmrq)) {
+		__scm_free_rq(scmrq);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&scmrq->list);
+	spin_lock_irq(&list_lock);
+	list_add(&scmrq->list, &inactive_requests);
+	spin_unlock_irq(&list_lock);
+
+	return 0;
+}
+
+static int scm_alloc_rqs(unsigned int nrqs)
+{
+	int ret = 0;
+
+	while (nrqs-- && !ret)
+		ret = __scm_alloc_rq();
+
+	return ret;
+}
+
+static struct scm_request *scm_request_fetch(void)
+{
+	struct scm_request *scmrq = NULL;
+
+	spin_lock(&list_lock);
+	if (list_empty(&inactive_requests))
+		goto out;
+	scmrq = list_first_entry(&inactive_requests, struct scm_request, list);
+	list_del(&scmrq->list);
+out:
+	spin_unlock(&list_lock);
+	return scmrq;
+}
+
+static void scm_request_done(struct scm_request *scmrq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&list_lock, flags);
+	list_add(&scmrq->list, &inactive_requests);
+	spin_unlock_irqrestore(&list_lock, flags);
+}
+
+static int scm_open(struct block_device *blkdev, fmode_t mode)
+{
+	return scm_get_ref();
+}
+
+static int scm_release(struct gendisk *gendisk, fmode_t mode)
+{
+	scm_put_ref();
+	return 0;
+}
+
+static const struct block_device_operations scm_blk_devops = {
+	.owner = THIS_MODULE,
+	.open = scm_open,
+	.release = scm_release,
+};
+
+static void scm_request_prepare(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+	struct scm_device *scmdev = bdev->gendisk->private_data;
+	struct aidaw *aidaw = scmrq->aidaw;
+	struct msb *msb = &scmrq->aob->msb[0];
+	struct req_iterator iter;
+	struct bio_vec *bv;
+
+	msb->bs = MSB_BS_4K;
+	scmrq->aob->request.msb_count = 1;
+	msb->scm_addr = scmdev->address +
+		((u64) blk_rq_pos(scmrq->request) << 9);
+	msb->oc = (rq_data_dir(scmrq->request) == READ) ?
+		MSB_OC_READ : MSB_OC_WRITE;
+	msb->flags |= MSB_FLAG_IDA;
+	msb->data_addr = (u64) aidaw;
+
+	rq_for_each_segment(bv, scmrq->request, iter) {
+		WARN_ON(bv->bv_offset);
+		msb->blk_count += bv->bv_len >> 12;
+		aidaw->data_addr = (u64) page_address(bv->bv_page);
+		aidaw++;
+	}
+}
+
+static inline void scm_request_init(struct scm_blk_dev *bdev,
+				    struct scm_request *scmrq,
+				    struct request *req)
+{
+	struct aob_rq_header *aobrq = to_aobrq(scmrq);
+	struct aob *aob = scmrq->aob;
+
+	memset(aob, 0, sizeof(*aob));
+	memset(scmrq->aidaw, 0, PAGE_SIZE);
+	aobrq->scmdev = bdev->scmdev;
+	aob->request.cmd_code = ARQB_CMD_MOVE;
+	aob->request.data = (u64) aobrq;
+	scmrq->request = req;
+	scmrq->bdev = bdev;
+	scmrq->retries = 4;
+	scmrq->error = 0;
+	scm_request_cluster_init(scmrq);
+}
+
+static void scm_ensure_queue_restart(struct scm_blk_dev *bdev)
+{
+	if (atomic_read(&bdev->queued_reqs)) {
+		/* Queue restart is triggered by the next interrupt. */
+		return;
+	}
+	blk_delay_queue(bdev->rq, SCM_QUEUE_DELAY);
+}
+
+void scm_request_requeue(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+
+	scm_release_cluster(scmrq);
+	blk_requeue_request(bdev->rq, scmrq->request);
+	scm_request_done(scmrq);
+	scm_ensure_queue_restart(bdev);
+}
+
+void scm_request_finish(struct scm_request *scmrq)
+{
+	scm_release_cluster(scmrq);
+	blk_end_request_all(scmrq->request, scmrq->error);
+	scm_request_done(scmrq);
+}
+
+static void scm_blk_request(struct request_queue *rq)
+{
+	struct scm_device *scmdev = rq->queuedata;
+	struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
+	struct scm_request *scmrq;
+	struct request *req;
+	int ret;
+
+	while ((req = blk_peek_request(rq))) {
+		if (req->cmd_type != REQ_TYPE_FS)
+			continue;
+
+		scmrq = scm_request_fetch();
+		if (!scmrq) {
+			SCM_LOG(5, "no request");
+			scm_ensure_queue_restart(bdev);
+			return;
+		}
+		scm_request_init(bdev, scmrq, req);
+		if (!scm_reserve_cluster(scmrq)) {
+			SCM_LOG(5, "cluster busy");
+			scm_request_done(scmrq);
+			return;
+		}
+		if (scm_need_cluster_request(scmrq)) {
+			blk_start_request(req);
+			scm_initiate_cluster_request(scmrq);
+			return;
+		}
+		scm_request_prepare(scmrq);
+		blk_start_request(req);
+
+		ret = scm_start_aob(scmrq->aob);
+		if (ret) {
+			SCM_LOG(5, "no subchannel");
+			scm_request_requeue(scmrq);
+			return;
+		}
+		atomic_inc(&bdev->queued_reqs);
+	}
+}
+
+static void __scmrq_log_error(struct scm_request *scmrq)
+{
+	struct aob *aob = scmrq->aob;
+
+	if (scmrq->error == -ETIMEDOUT)
+		SCM_LOG(1, "Request timeout");
+	else {
+		SCM_LOG(1, "Request error");
+		SCM_LOG_HEX(1, &aob->response, sizeof(aob->response));
+	}
+	if (scmrq->retries)
+		SCM_LOG(1, "Retry request");
+	else
+		pr_err("An I/O operation to SCM failed with rc=%d\n",
+		       scmrq->error);
+}
+
+void scm_blk_irq(struct scm_device *scmdev, void *data, int error)
+{
+	struct scm_request *scmrq = data;
+	struct scm_blk_dev *bdev = scmrq->bdev;
+
+	scmrq->error = error;
+	if (error)
+		__scmrq_log_error(scmrq);
+
+	spin_lock(&bdev->lock);
+	list_add_tail(&scmrq->list, &bdev->finished_requests);
+	spin_unlock(&bdev->lock);
+	tasklet_hi_schedule(&bdev->tasklet);
+}
+
+static void scm_blk_tasklet(struct scm_blk_dev *bdev)
+{
+	struct scm_request *scmrq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bdev->lock, flags);
+	while (!list_empty(&bdev->finished_requests)) {
+		scmrq = list_first_entry(&bdev->finished_requests,
+					 struct scm_request, list);
+		list_del(&scmrq->list);
+		spin_unlock_irqrestore(&bdev->lock, flags);
+
+		if (scmrq->error && scmrq->retries-- > 0) {
+			if (scm_start_aob(scmrq->aob)) {
+				spin_lock_irqsave(&bdev->rq_lock, flags);
+				scm_request_requeue(scmrq);
+				spin_unlock_irqrestore(&bdev->rq_lock, flags);
+			}
+			/* Request restarted or requeued, handle next. */
+			spin_lock_irqsave(&bdev->lock, flags);
+			continue;
+		}
+
+		if (scm_test_cluster_request(scmrq)) {
+			scm_cluster_request_irq(scmrq);
+			spin_lock_irqsave(&bdev->lock, flags);
+			continue;
+		}
+
+		scm_request_finish(scmrq);
+		atomic_dec(&bdev->queued_reqs);
+		spin_lock_irqsave(&bdev->lock, flags);
+	}
+	spin_unlock_irqrestore(&bdev->lock, flags);
+	/* Look out for more requests. */
+	blk_run_queue(bdev->rq);
+}
+
+int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
+{
+	struct request_queue *rq;
+	int len, ret = -ENOMEM;
+	unsigned int devindex, nr_max_blk;
+
+	devindex = atomic_inc_return(&nr_devices) - 1;
+	/* scma..scmz + scmaa..scmzz */
+	if (devindex > 701) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	bdev->scmdev = scmdev;
+	spin_lock_init(&bdev->rq_lock);
+	spin_lock_init(&bdev->lock);
+	INIT_LIST_HEAD(&bdev->finished_requests);
+	atomic_set(&bdev->queued_reqs, 0);
+	tasklet_init(&bdev->tasklet,
+		     (void (*)(unsigned long)) scm_blk_tasklet,
+		     (unsigned long) bdev);
+
+	rq = blk_init_queue(scm_blk_request, &bdev->rq_lock);
+	if (!rq)
+		goto out;
+
+	bdev->rq = rq;
+	nr_max_blk = min(scmdev->nr_max_block,
+			 (unsigned int) (PAGE_SIZE / sizeof(struct aidaw)));
+
+	blk_queue_logical_block_size(rq, 1 << 12);
+	blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */
+	blk_queue_max_segments(rq, nr_max_blk);
+	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rq);
+	scm_blk_dev_cluster_setup(bdev);
+
+	bdev->gendisk = alloc_disk(SCM_NR_PARTS);
+	if (!bdev->gendisk)
+		goto out_queue;
+
+	rq->queuedata = scmdev;
+	bdev->gendisk->driverfs_dev = &scmdev->dev;
+	bdev->gendisk->private_data = scmdev;
+	bdev->gendisk->fops = &scm_blk_devops;
+	bdev->gendisk->queue = rq;
+	bdev->gendisk->major = scm_major;
+	bdev->gendisk->first_minor = devindex * SCM_NR_PARTS;
+
+	len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm");
+	if (devindex > 25) {
+		len += snprintf(bdev->gendisk->disk_name + len,
+				DISK_NAME_LEN - len, "%c",
+				'a' + (devindex / 26) - 1);
+		devindex = devindex % 26;
+	}
+	snprintf(bdev->gendisk->disk_name + len, DISK_NAME_LEN - len, "%c",
+		 'a' + devindex);
+
+	/* 512 byte sectors */
+	set_capacity(bdev->gendisk, scmdev->size >> 9);
+	add_disk(bdev->gendisk);
+	return 0;
+
+out_queue:
+	blk_cleanup_queue(rq);
+out:
+	atomic_dec(&nr_devices);
+	return ret;
+}
+
+void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
+{
+	tasklet_kill(&bdev->tasklet);
+	del_gendisk(bdev->gendisk);
+	blk_cleanup_queue(bdev->gendisk->queue);
+	put_disk(bdev->gendisk);
+}
+
+static int __init scm_blk_init(void)
+{
+	int ret = -EINVAL;
+
+	if (!scm_cluster_size_valid())
+		goto out;
+
+	ret = register_blkdev(0, "scm");
+	if (ret < 0)
+		goto out;
+
+	scm_major = ret;
+	if (scm_alloc_rqs(nr_requests))
+		goto out_unreg;
+
+	scm_debug = debug_register("scm_log", 16, 1, 16);
+	if (!scm_debug)
+		goto out_free;
+
+	debug_register_view(scm_debug, &debug_hex_ascii_view);
+	debug_set_level(scm_debug, 2);
+
+	ret = scm_drv_init();
+	if (ret)
+		goto out_dbf;
+
+	return ret;
+
+out_dbf:
+	debug_unregister(scm_debug);
+out_free:
+	scm_free_rqs();
+out_unreg:
+	unregister_blkdev(scm_major, "scm");
+out:
+	return ret;
+}
+module_init(scm_blk_init);
+
+static void __exit scm_blk_cleanup(void)
+{
+	scm_drv_cleanup();
+	debug_unregister(scm_debug);
+	scm_free_rqs();
+	unregister_blkdev(scm_major, "scm");
+}
+module_exit(scm_blk_cleanup);
diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h
new file mode 100644
index 0000000..7ac6bad
--- /dev/null
+++ b/drivers/s390/block/scm_blk.h
@@ -0,0 +1,117 @@
+#ifndef SCM_BLK_H
+#define SCM_BLK_H
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <linux/list.h>
+
+#include <asm/debug.h>
+#include <asm/eadm.h>
+
+#define SCM_NR_PARTS 8
+#define SCM_QUEUE_DELAY 5
+
+struct scm_blk_dev {
+	struct tasklet_struct tasklet;
+	struct request_queue *rq;
+	struct gendisk *gendisk;
+	struct scm_device *scmdev;
+	spinlock_t rq_lock;	/* guard the request queue */
+	spinlock_t lock;	/* guard the rest of the blockdev */
+	atomic_t queued_reqs;
+	struct list_head finished_requests;
+#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
+	struct list_head cluster_list;
+#endif
+};
+
+struct scm_request {
+	struct scm_blk_dev *bdev;
+	struct request *request;
+	struct aidaw *aidaw;
+	struct aob *aob;
+	struct list_head list;
+	u8 retries;
+	int error;
+#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
+	struct {
+		enum {CLUSTER_NONE, CLUSTER_READ, CLUSTER_WRITE} state;
+		struct list_head list;
+		void **buf;
+	} cluster;
+#endif
+};
+
+#define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data)
+
+int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *);
+void scm_blk_dev_cleanup(struct scm_blk_dev *);
+void scm_blk_irq(struct scm_device *, void *, int);
+
+void scm_request_finish(struct scm_request *);
+void scm_request_requeue(struct scm_request *);
+
+int scm_drv_init(void);
+void scm_drv_cleanup(void);
+
+#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
+void __scm_free_rq_cluster(struct scm_request *);
+int __scm_alloc_rq_cluster(struct scm_request *);
+void scm_request_cluster_init(struct scm_request *);
+bool scm_reserve_cluster(struct scm_request *);
+void scm_release_cluster(struct scm_request *);
+void scm_blk_dev_cluster_setup(struct scm_blk_dev *);
+bool scm_need_cluster_request(struct scm_request *);
+void scm_initiate_cluster_request(struct scm_request *);
+void scm_cluster_request_irq(struct scm_request *);
+bool scm_test_cluster_request(struct scm_request *);
+bool scm_cluster_size_valid(void);
+#else
+#define __scm_free_rq_cluster(scmrq) {}
+#define __scm_alloc_rq_cluster(scmrq) 0
+#define scm_request_cluster_init(scmrq) {}
+#define scm_reserve_cluster(scmrq) true
+#define scm_release_cluster(scmrq) {}
+#define scm_blk_dev_cluster_setup(bdev) {}
+#define scm_need_cluster_request(scmrq) false
+#define scm_initiate_cluster_request(scmrq) {}
+#define scm_cluster_request_irq(scmrq) {}
+#define scm_test_cluster_request(scmrq) false
+#define scm_cluster_size_valid() true
+#endif
+
+extern debug_info_t *scm_debug;
+
+#define SCM_LOG(imp, txt) do {					\
+		debug_text_event(scm_debug, imp, txt);		\
+	} while (0)
+
+static inline void SCM_LOG_HEX(int level, void *data, int length)
+{
+	if (level > scm_debug->level)
+		return;
+	while (length > 0) {
+		debug_event(scm_debug, level, data, length);
+		length -= scm_debug->buf_size;
+		data += scm_debug->buf_size;
+	}
+}
+
+static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev)
+{
+	struct {
+		u64 address;
+		u8 oper_state;
+		u8 rank;
+	} __packed data = {
+		.address = scmdev->address,
+		.oper_state = scmdev->attrs.oper_state,
+		.rank = scmdev->attrs.rank,
+	};
+
+	SCM_LOG_HEX(level, &data, sizeof(data));
+}
+
+#endif /* SCM_BLK_H */
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c
new file mode 100644
index 0000000..f4bb61b
--- /dev/null
+++ b/drivers/s390/block/scm_blk_cluster.c
@@ -0,0 +1,228 @@
+/*
+ * Block driver for s390 storage class memory.
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <asm/eadm.h>
+#include "scm_blk.h"
+
+static unsigned int write_cluster_size = 64;
+module_param(write_cluster_size, uint, S_IRUGO);
+MODULE_PARM_DESC(write_cluster_size,
+		 "Number of pages used for contiguous writes.");
+
+#define CLUSTER_SIZE (write_cluster_size * PAGE_SIZE)
+
+void __scm_free_rq_cluster(struct scm_request *scmrq)
+{
+	int i;
+
+	if (!scmrq->cluster.buf)
+		return;
+
+	for (i = 0; i < 2 * write_cluster_size; i++)
+		free_page((unsigned long) scmrq->cluster.buf[i]);
+
+	kfree(scmrq->cluster.buf);
+}
+
+int __scm_alloc_rq_cluster(struct scm_request *scmrq)
+{
+	int i;
+
+	scmrq->cluster.buf = kzalloc(sizeof(void *) * 2 * write_cluster_size,
+				 GFP_KERNEL);
+	if (!scmrq->cluster.buf)
+		return -ENOMEM;
+
+	for (i = 0; i < 2 * write_cluster_size; i++) {
+		scmrq->cluster.buf[i] = (void *) get_zeroed_page(GFP_DMA);
+		if (!scmrq->cluster.buf[i])
+			return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&scmrq->cluster.list);
+	return 0;
+}
+
+void scm_request_cluster_init(struct scm_request *scmrq)
+{
+	scmrq->cluster.state = CLUSTER_NONE;
+}
+
+static bool clusters_intersect(struct scm_request *A, struct scm_request *B)
+{
+	unsigned long firstA, lastA, firstB, lastB;
+
+	firstA = ((u64) blk_rq_pos(A->request) << 9) / CLUSTER_SIZE;
+	lastA = (((u64) blk_rq_pos(A->request) << 9) +
+		    blk_rq_bytes(A->request) - 1) / CLUSTER_SIZE;
+
+	firstB = ((u64) blk_rq_pos(B->request) << 9) / CLUSTER_SIZE;
+	lastB = (((u64) blk_rq_pos(B->request) << 9) +
+		    blk_rq_bytes(B->request) - 1) / CLUSTER_SIZE;
+
+	return (firstB <= lastA && firstA <= lastB);
+}
+
+bool scm_reserve_cluster(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+	struct scm_request *iter;
+
+	if (write_cluster_size == 0)
+		return true;
+
+	spin_lock(&bdev->lock);
+	list_for_each_entry(iter, &bdev->cluster_list, cluster.list) {
+		if (clusters_intersect(scmrq, iter) &&
+		    (rq_data_dir(scmrq->request) == WRITE ||
+		     rq_data_dir(iter->request) == WRITE)) {
+			spin_unlock(&bdev->lock);
+			return false;
+		}
+	}
+	list_add(&scmrq->cluster.list, &bdev->cluster_list);
+	spin_unlock(&bdev->lock);
+
+	return true;
+}
+
+void scm_release_cluster(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+	unsigned long flags;
+
+	if (write_cluster_size == 0)
+		return;
+
+	spin_lock_irqsave(&bdev->lock, flags);
+	list_del(&scmrq->cluster.list);
+	spin_unlock_irqrestore(&bdev->lock, flags);
+}
+
+void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev)
+{
+	INIT_LIST_HEAD(&bdev->cluster_list);
+	blk_queue_io_opt(bdev->rq, CLUSTER_SIZE);
+}
+
+static void scm_prepare_cluster_request(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+	struct scm_device *scmdev = bdev->gendisk->private_data;
+	struct request *req = scmrq->request;
+	struct aidaw *aidaw = scmrq->aidaw;
+	struct msb *msb = &scmrq->aob->msb[0];
+	struct req_iterator iter;
+	struct bio_vec *bv;
+	int i = 0;
+	u64 addr;
+
+	switch (scmrq->cluster.state) {
+	case CLUSTER_NONE:
+		scmrq->cluster.state = CLUSTER_READ;
+		/* fall through */
+	case CLUSTER_READ:
+		scmrq->aob->request.msb_count = 1;
+		msb->bs = MSB_BS_4K;
+		msb->oc = MSB_OC_READ;
+		msb->flags = MSB_FLAG_IDA;
+		msb->data_addr = (u64) aidaw;
+		msb->blk_count = write_cluster_size;
+
+		addr = scmdev->address + ((u64) blk_rq_pos(req) << 9);
+		msb->scm_addr = round_down(addr, CLUSTER_SIZE);
+
+		if (msb->scm_addr !=
+		    round_down(addr + (u64) blk_rq_bytes(req) - 1,
+			       CLUSTER_SIZE))
+			msb->blk_count = 2 * write_cluster_size;
+
+		for (i = 0; i < msb->blk_count; i++) {
+			aidaw->data_addr = (u64) scmrq->cluster.buf[i];
+			aidaw++;
+		}
+
+		break;
+	case CLUSTER_WRITE:
+		msb->oc = MSB_OC_WRITE;
+
+		for (addr = msb->scm_addr;
+		     addr < scmdev->address + ((u64) blk_rq_pos(req) << 9);
+		     addr += PAGE_SIZE) {
+			aidaw->data_addr = (u64) scmrq->cluster.buf[i];
+			aidaw++;
+			i++;
+		}
+		rq_for_each_segment(bv, req, iter) {
+			aidaw->data_addr = (u64) page_address(bv->bv_page);
+			aidaw++;
+			i++;
+		}
+		for (; i < msb->blk_count; i++) {
+			aidaw->data_addr = (u64) scmrq->cluster.buf[i];
+			aidaw++;
+		}
+		break;
+	}
+}
+
+bool scm_need_cluster_request(struct scm_request *scmrq)
+{
+	if (rq_data_dir(scmrq->request) == READ)
+		return false;
+
+	return blk_rq_bytes(scmrq->request) < CLUSTER_SIZE;
+}
+
+/* Called with queue lock held. */
+void scm_initiate_cluster_request(struct scm_request *scmrq)
+{
+	scm_prepare_cluster_request(scmrq);
+	if (scm_start_aob(scmrq->aob))
+		scm_request_requeue(scmrq);
+}
+
+bool scm_test_cluster_request(struct scm_request *scmrq)
+{
+	return scmrq->cluster.state != CLUSTER_NONE;
+}
+
+void scm_cluster_request_irq(struct scm_request *scmrq)
+{
+	struct scm_blk_dev *bdev = scmrq->bdev;
+	unsigned long flags;
+
+	switch (scmrq->cluster.state) {
+	case CLUSTER_NONE:
+		BUG();
+		break;
+	case CLUSTER_READ:
+		if (scmrq->error) {
+			scm_request_finish(scmrq);
+			break;
+		}
+		scmrq->cluster.state = CLUSTER_WRITE;
+		spin_lock_irqsave(&bdev->rq_lock, flags);
+		scm_initiate_cluster_request(scmrq);
+		spin_unlock_irqrestore(&bdev->rq_lock, flags);
+		break;
+	case CLUSTER_WRITE:
+		scm_request_finish(scmrq);
+		break;
+	}
+}
+
+bool scm_cluster_size_valid(void)
+{
+	return write_cluster_size == 0 || write_cluster_size == 32 ||
+		write_cluster_size == 64 || write_cluster_size == 128;
+}
diff --git a/drivers/s390/block/scm_drv.c b/drivers/s390/block/scm_drv.c
new file mode 100644
index 0000000..9fa0a90
--- /dev/null
+++ b/drivers/s390/block/scm_drv.c
@@ -0,0 +1,81 @@
+/*
+ * Device driver for s390 storage class memory.
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#define KMSG_COMPONENT "scm_block"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/eadm.h>
+#include "scm_blk.h"
+
+static void notify(struct scm_device *scmdev)
+{
+	pr_info("%lu: The capabilities of the SCM increment changed\n",
+		(unsigned long) scmdev->address);
+	SCM_LOG(2, "State changed");
+	SCM_LOG_STATE(2, scmdev);
+}
+
+static int scm_probe(struct scm_device *scmdev)
+{
+	struct scm_blk_dev *bdev;
+	int ret;
+
+	SCM_LOG(2, "probe");
+	SCM_LOG_STATE(2, scmdev);
+
+	if (scmdev->attrs.oper_state != OP_STATE_GOOD)
+		return -EINVAL;
+
+	bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
+	if (!bdev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&scmdev->dev, bdev);
+	ret = scm_blk_dev_setup(bdev, scmdev);
+	if (ret) {
+		dev_set_drvdata(&scmdev->dev, NULL);
+		kfree(bdev);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static int scm_remove(struct scm_device *scmdev)
+{
+	struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
+
+	scm_blk_dev_cleanup(bdev);
+	dev_set_drvdata(&scmdev->dev, NULL);
+	kfree(bdev);
+
+	return 0;
+}
+
+static struct scm_driver scm_drv = {
+	.drv = {
+		.name = "scm_block",
+		.owner = THIS_MODULE,
+	},
+	.notify = notify,
+	.probe = scm_probe,
+	.remove = scm_remove,
+	.handler = scm_blk_irq,
+};
+
+int __init scm_drv_init(void)
+{
+	return scm_driver_register(&scm_drv);
+}
+
+void scm_drv_cleanup(void)
+{
+	scm_driver_unregister(&scm_drv);
+}
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index bb07577..699fd3e 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -35,7 +35,6 @@
  */
 struct con3270 {
 	struct raw3270_view view;
-	spinlock_t lock;
 	struct list_head freemem;	/* list of free memory for strings. */
 
 	/* Output stuff. */
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 5b8b859..f4ff515 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -571,8 +571,11 @@
 	if (rc)
 		goto out_iucv;
 	monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
-	if (!monreader_device)
+	if (!monreader_device) {
+		rc = -ENOMEM;
 		goto out_driver;
+	}
+
 	dev_set_name(monreader_device, "monreader-dev");
 	monreader_device->bus = &iucv_bus;
 	monreader_device->parent = iucv_root;
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 3fcc000..4fa21f7 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -334,7 +334,7 @@
 			reg->receiver_fn(evbuf);
 			spin_lock_irqsave(&sclp_lock, flags);
 		} else if (reg == NULL)
-			rc = -ENOSYS;
+			rc = -EOPNOTSUPP;
 	}
 	spin_unlock_irqrestore(&sclp_lock, flags);
 	return rc;
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 4be63be..3b13d58 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -463,7 +463,7 @@
 		/* Use write priority message */
 		sccb->msg_buf.header.type = EVTYP_PMSGCMD;
 	else
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
 	buffer->request.status = SCLP_REQ_FILLED;
 	buffer->request.callback = sclp_writedata_callback;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index c06be6c..ea664dd 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -15,7 +15,6 @@
 #include <asm/ccwdev.h>
 #include <asm/debug.h>
 #include <asm/idals.h>
-#include <linux/blkdev.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtio.h>
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h
index c5816ad..8c760c0 100644
--- a/drivers/s390/char/tape_std.h
+++ b/drivers/s390/char/tape_std.h
@@ -100,11 +100,7 @@
 void tape_std_read_backward(struct tape_device *device,
 			    struct tape_request *request);
 struct tape_request *tape_std_write_block(struct tape_device *, size_t);
-struct tape_request *tape_std_bread(struct tape_device *, struct request *);
-void tape_std_free_bread(struct tape_request *);
 void tape_std_check_locate(struct tape_device *, struct tape_request *);
-struct tape_request *tape_std_bwrite(struct request *,
-				     struct tape_device *, int);
 
 /* Some non-mtop commands. */
 int tape_std_assign(struct tape_device *);
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c131bc4..9b3a24e 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -321,7 +321,7 @@
 	 * only allow for blocking reads to be open
 	 */
 	if (filp->f_flags & O_NONBLOCK)
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
 	/* Besure this device hasn't already been opened */
 	spin_lock_bh(&logptr->priv_lock);
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index e1b700a..8c4a386 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -8,6 +8,8 @@
 ccw_device-objs += device_id.o device_pgid.o device_status.o
 obj-y += ccw_device.o cmf.o
 obj-$(CONFIG_CHSC_SCH) += chsc_sch.o
+obj-$(CONFIG_EADM_SCH) += eadm_sch.o
+obj-$(CONFIG_SCM_BUS) += scm.o
 obj-$(CONFIG_CCWGROUP) += ccwgroup.o
 
 qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index cfe0c08..4d51a7c 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -52,6 +52,11 @@
 		return -EINVAL;
 	case 0x0004:
 		return -EOPNOTSUPP;
+	case 0x000b:
+		return -EBUSY;
+	case 0x0100:
+	case 0x0102:
+		return -ENOMEM;
 	default:
 		return -EIO;
 	}
@@ -393,6 +398,20 @@
 	}
 }
 
+static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area)
+{
+	int ret;
+
+	CIO_CRW_EVENT(4, "chsc: scm change notification\n");
+	if (sei_area->rs != 7)
+		return;
+
+	ret = scm_update_information();
+	if (ret)
+		CIO_CRW_EVENT(0, "chsc: updating change notification"
+			      " failed (rc=%d).\n", ret);
+}
+
 static void chsc_process_sei(struct chsc_sei_area *sei_area)
 {
 	/* Check if we might have lost some information. */
@@ -414,6 +433,9 @@
 	case 8: /* channel-path-configuration notification */
 		chsc_process_sei_chp_config(sei_area);
 		break;
+	case 12: /* scm change notification */
+		chsc_process_sei_scm_change(sei_area);
+		break;
 	default: /* other stuff */
 		CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
 			      sei_area->cc);
@@ -1047,3 +1069,33 @@
 	return rc;
 }
 EXPORT_SYMBOL_GPL(chsc_siosl);
+
+/**
+ * chsc_scm_info() - store SCM information (SSI)
+ * @scm_area: request and response block for SSI
+ * @token: continuation token
+ *
+ * Returns 0 on success.
+ */
+int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token)
+{
+	int ccode, ret;
+
+	memset(scm_area, 0, sizeof(*scm_area));
+	scm_area->request.length = 0x0020;
+	scm_area->request.code = 0x004C;
+	scm_area->reqtok = token;
+
+	ccode = chsc(scm_area);
+	if (ccode > 0) {
+		ret = (ccode == 3) ? -ENODEV : -EBUSY;
+		goto out;
+	}
+	ret = chsc_error_from_response(scm_area->response.code);
+	if (ret != 0)
+		CIO_MSG_EVENT(2, "chsc: scm info failed (rc=%04x)\n",
+			      scm_area->response.code);
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(chsc_scm_info);
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 3f15b2a..662dab4 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
+#include <asm/css_chars.h>
 #include <asm/chpid.h>
 #include <asm/chsc.h>
 #include <asm/schid.h>
@@ -118,4 +119,46 @@
 
 int chsc_siosl(struct subchannel_id schid);
 
+/* Functions and definitions to query storage-class memory. */
+struct sale {
+	u64 sa;
+	u32 p:4;
+	u32 op_state:4;
+	u32 data_state:4;
+	u32 rank:4;
+	u32 r:1;
+	u32:7;
+	u32 rid:8;
+	u32:32;
+} __packed;
+
+struct chsc_scm_info {
+	struct chsc_header request;
+	u32:32;
+	u64 reqtok;
+	u32 reserved1[4];
+	struct chsc_header response;
+	u64:56;
+	u8 rq;
+	u32 mbc;
+	u64 msa;
+	u16 is;
+	u16 mmc;
+	u32 mci;
+	u64 nr_scm_ini;
+	u64 nr_scm_unini;
+	u32 reserved2[10];
+	u64 restok;
+	struct sale scmal[248];
+} __packed;
+
+int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
+
+#ifdef CONFIG_SCM_BUS
+int scm_update_information(void);
+#else /* CONFIG_SCM_BUS */
+#define scm_update_information() 0
+#endif /* CONFIG_SCM_BUS */
+
+
 #endif
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 33d1ef7..8e927b9 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1029,7 +1029,7 @@
 /* Make sure all subchannels are quiet before we re-ipl an lpar. */
 void reipl_ccw_dev(struct ccw_dev_id *devid)
 {
-	struct subchannel_id schid;
+	struct subchannel_id uninitialized_var(schid);
 
 	s390_reset_system(NULL, NULL);
 	if (reipl_find_schid(devid, &schid) != 0)
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 21908e6..b4d572f 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -445,6 +445,7 @@
 		put_device(&sch->dev);
 	}
 }
+EXPORT_SYMBOL_GPL(css_sched_sch_todo);
 
 static void css_sch_todo(struct work_struct *work)
 {
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index ed25c87..fc916f5 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1426,6 +1426,8 @@
 		return IO_SCH_REPROBE;
 	if (cdev->online)
 		return IO_SCH_VERIFY;
+	if (cdev->private->state == DEV_STATE_NOT_OPER)
+		return IO_SCH_UNREG_ATTACH;
 	return IO_SCH_NOP;
 }
 
@@ -1519,11 +1521,14 @@
 			goto out;
 		break;
 	case IO_SCH_UNREG_ATTACH:
+		spin_lock_irqsave(sch->lock, flags);
 		if (cdev->private->flags.resuming) {
 			/* Device will be handled later. */
 			rc = 0;
-			goto out;
+			goto out_unlock;
 		}
+		sch_set_cdev(sch, NULL);
+		spin_unlock_irqrestore(sch->lock, flags);
 		/* Unregister ccw device. */
 		ccw_device_unregister(cdev);
 		break;
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c
new file mode 100644
index 0000000..6c96734
--- /dev/null
+++ b/drivers/s390/cio/eadm_sch.c
@@ -0,0 +1,401 @@
+/*
+ * Driver for s390 eadm subchannels
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <asm/css_chars.h>
+#include <asm/debug.h>
+#include <asm/isc.h>
+#include <asm/cio.h>
+#include <asm/scsw.h>
+#include <asm/eadm.h>
+
+#include "eadm_sch.h"
+#include "ioasm.h"
+#include "cio.h"
+#include "css.h"
+#include "orb.h"
+
+MODULE_DESCRIPTION("driver for s390 eadm subchannels");
+MODULE_LICENSE("GPL");
+
+#define EADM_TIMEOUT (5 * HZ)
+static DEFINE_SPINLOCK(list_lock);
+static LIST_HEAD(eadm_list);
+
+static debug_info_t *eadm_debug;
+
+#define EADM_LOG(imp, txt) do {					\
+		debug_text_event(eadm_debug, imp, txt);		\
+	} while (0)
+
+static void EADM_LOG_HEX(int level, void *data, int length)
+{
+	if (level > eadm_debug->level)
+		return;
+	while (length > 0) {
+		debug_event(eadm_debug, level, data, length);
+		length -= eadm_debug->buf_size;
+		data += eadm_debug->buf_size;
+	}
+}
+
+static void orb_init(union orb *orb)
+{
+	memset(orb, 0, sizeof(union orb));
+	orb->eadm.compat1 = 1;
+	orb->eadm.compat2 = 1;
+	orb->eadm.fmt = 1;
+	orb->eadm.x = 1;
+}
+
+static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
+{
+	union orb *orb = &get_eadm_private(sch)->orb;
+	int cc;
+
+	orb_init(orb);
+	orb->eadm.aob = (u32)__pa(aob);
+	orb->eadm.intparm = (u32)(addr_t)sch;
+	orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
+
+	EADM_LOG(6, "start");
+	EADM_LOG_HEX(6, &sch->schid, sizeof(sch->schid));
+
+	cc = ssch(sch->schid, orb);
+	switch (cc) {
+	case 0:
+		sch->schib.scsw.eadm.actl |= SCSW_ACTL_START_PEND;
+		break;
+	case 1:		/* status pending */
+	case 2:		/* busy */
+		return -EBUSY;
+	case 3:		/* not operational */
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int eadm_subchannel_clear(struct subchannel *sch)
+{
+	int cc;
+
+	cc = csch(sch->schid);
+	if (cc)
+		return -ENODEV;
+
+	sch->schib.scsw.eadm.actl |= SCSW_ACTL_CLEAR_PEND;
+	return 0;
+}
+
+static void eadm_subchannel_timeout(unsigned long data)
+{
+	struct subchannel *sch = (struct subchannel *) data;
+
+	spin_lock_irq(sch->lock);
+	EADM_LOG(1, "timeout");
+	EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid));
+	if (eadm_subchannel_clear(sch))
+		EADM_LOG(0, "clear failed");
+	spin_unlock_irq(sch->lock);
+}
+
+static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires)
+{
+	struct eadm_private *private = get_eadm_private(sch);
+
+	if (expires == 0) {
+		del_timer(&private->timer);
+		return;
+	}
+	if (timer_pending(&private->timer)) {
+		if (mod_timer(&private->timer, jiffies + expires))
+			return;
+	}
+	private->timer.function = eadm_subchannel_timeout;
+	private->timer.data = (unsigned long) sch;
+	private->timer.expires = jiffies + expires;
+	add_timer(&private->timer);
+}
+
+static void eadm_subchannel_irq(struct subchannel *sch)
+{
+	struct eadm_private *private = get_eadm_private(sch);
+	struct eadm_scsw *scsw = &sch->schib.scsw.eadm;
+	struct irb *irb = (struct irb *)&S390_lowcore.irb;
+	int error = 0;
+
+	EADM_LOG(6, "irq");
+	EADM_LOG_HEX(6, irb, sizeof(*irb));
+
+	kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++;
+
+	if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
+	    && scsw->eswf == 1 && irb->esw.eadm.erw.r)
+		error = -EIO;
+
+	if (scsw->fctl & SCSW_FCTL_CLEAR_FUNC)
+		error = -ETIMEDOUT;
+
+	eadm_subchannel_set_timeout(sch, 0);
+
+	if (private->state != EADM_BUSY) {
+		EADM_LOG(1, "irq unsol");
+		EADM_LOG_HEX(1, irb, sizeof(*irb));
+		private->state = EADM_NOT_OPER;
+		css_sched_sch_todo(sch, SCH_TODO_EVAL);
+		return;
+	}
+	scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
+	private->state = EADM_IDLE;
+}
+
+static struct subchannel *eadm_get_idle_sch(void)
+{
+	struct eadm_private *private;
+	struct subchannel *sch;
+	unsigned long flags;
+
+	spin_lock_irqsave(&list_lock, flags);
+	list_for_each_entry(private, &eadm_list, head) {
+		sch = private->sch;
+		spin_lock(sch->lock);
+		if (private->state == EADM_IDLE) {
+			private->state = EADM_BUSY;
+			list_move_tail(&private->head, &eadm_list);
+			spin_unlock(sch->lock);
+			spin_unlock_irqrestore(&list_lock, flags);
+
+			return sch;
+		}
+		spin_unlock(sch->lock);
+	}
+	spin_unlock_irqrestore(&list_lock, flags);
+
+	return NULL;
+}
+
+static int eadm_start_aob(struct aob *aob)
+{
+	struct eadm_private *private;
+	struct subchannel *sch;
+	unsigned long flags;
+	int ret;
+
+	sch = eadm_get_idle_sch();
+	if (!sch)
+		return -EBUSY;
+
+	spin_lock_irqsave(sch->lock, flags);
+	eadm_subchannel_set_timeout(sch, EADM_TIMEOUT);
+	ret = eadm_subchannel_start(sch, aob);
+	if (!ret)
+		goto out_unlock;
+
+	/* Handle start subchannel failure. */
+	eadm_subchannel_set_timeout(sch, 0);
+	private = get_eadm_private(sch);
+	private->state = EADM_NOT_OPER;
+	css_sched_sch_todo(sch, SCH_TODO_EVAL);
+
+out_unlock:
+	spin_unlock_irqrestore(sch->lock, flags);
+
+	return ret;
+}
+
+static int eadm_subchannel_probe(struct subchannel *sch)
+{
+	struct eadm_private *private;
+	int ret;
+
+	private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+	if (!private)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&private->head);
+	init_timer(&private->timer);
+
+	spin_lock_irq(sch->lock);
+	set_eadm_private(sch, private);
+	private->state = EADM_IDLE;
+	private->sch = sch;
+	sch->isc = EADM_SCH_ISC;
+	ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+	if (ret) {
+		set_eadm_private(sch, NULL);
+		spin_unlock_irq(sch->lock);
+		kfree(private);
+		goto out;
+	}
+	spin_unlock_irq(sch->lock);
+
+	spin_lock_irq(&list_lock);
+	list_add(&private->head, &eadm_list);
+	spin_unlock_irq(&list_lock);
+
+	if (dev_get_uevent_suppress(&sch->dev)) {
+		dev_set_uevent_suppress(&sch->dev, 0);
+		kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+	}
+out:
+	return ret;
+}
+
+static void eadm_quiesce(struct subchannel *sch)
+{
+	int ret;
+
+	do {
+		spin_lock_irq(sch->lock);
+		ret = cio_disable_subchannel(sch);
+		spin_unlock_irq(sch->lock);
+	} while (ret == -EBUSY);
+}
+
+static int eadm_subchannel_remove(struct subchannel *sch)
+{
+	struct eadm_private *private = get_eadm_private(sch);
+
+	spin_lock_irq(&list_lock);
+	list_del(&private->head);
+	spin_unlock_irq(&list_lock);
+
+	eadm_quiesce(sch);
+
+	spin_lock_irq(sch->lock);
+	set_eadm_private(sch, NULL);
+	spin_unlock_irq(sch->lock);
+
+	kfree(private);
+
+	return 0;
+}
+
+static void eadm_subchannel_shutdown(struct subchannel *sch)
+{
+	eadm_quiesce(sch);
+}
+
+static int eadm_subchannel_freeze(struct subchannel *sch)
+{
+	return cio_disable_subchannel(sch);
+}
+
+static int eadm_subchannel_restore(struct subchannel *sch)
+{
+	return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+}
+
+/**
+ * eadm_subchannel_sch_event - process subchannel event
+ * @sch: subchannel
+ * @process: non-zero if function is called in process context
+ *
+ * An unspecified event occurred for this subchannel. Adjust data according
+ * to the current operational state of the subchannel. Return zero when the
+ * event has been handled sufficiently or -EAGAIN when this function should
+ * be called again in process context.
+ */
+static int eadm_subchannel_sch_event(struct subchannel *sch, int process)
+{
+	struct eadm_private *private;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(sch->lock, flags);
+	if (!device_is_registered(&sch->dev))
+		goto out_unlock;
+
+	if (work_pending(&sch->todo_work))
+		goto out_unlock;
+
+	if (cio_update_schib(sch)) {
+		css_sched_sch_todo(sch, SCH_TODO_UNREG);
+		goto out_unlock;
+	}
+	private = get_eadm_private(sch);
+	if (private->state == EADM_NOT_OPER)
+		private->state = EADM_IDLE;
+
+out_unlock:
+	spin_unlock_irqrestore(sch->lock, flags);
+
+	return ret;
+}
+
+static struct css_device_id eadm_subchannel_ids[] = {
+	{ .match_flags = 0x1, .type = SUBCHANNEL_TYPE_ADM, },
+	{ /* end of list */ },
+};
+MODULE_DEVICE_TABLE(css, eadm_subchannel_ids);
+
+static struct css_driver eadm_subchannel_driver = {
+	.drv = {
+		.name = "eadm_subchannel",
+		.owner = THIS_MODULE,
+	},
+	.subchannel_type = eadm_subchannel_ids,
+	.irq = eadm_subchannel_irq,
+	.probe = eadm_subchannel_probe,
+	.remove = eadm_subchannel_remove,
+	.shutdown = eadm_subchannel_shutdown,
+	.sch_event = eadm_subchannel_sch_event,
+	.freeze = eadm_subchannel_freeze,
+	.thaw = eadm_subchannel_restore,
+	.restore = eadm_subchannel_restore,
+};
+
+static struct eadm_ops eadm_ops = {
+	.eadm_start = eadm_start_aob,
+	.owner = THIS_MODULE,
+};
+
+static int __init eadm_sch_init(void)
+{
+	int ret;
+
+	if (!css_general_characteristics.eadm)
+		return -ENXIO;
+
+	eadm_debug = debug_register("eadm_log", 16, 1, 16);
+	if (!eadm_debug)
+		return -ENOMEM;
+
+	debug_register_view(eadm_debug, &debug_hex_ascii_view);
+	debug_set_level(eadm_debug, 2);
+
+	isc_register(EADM_SCH_ISC);
+	ret = css_driver_register(&eadm_subchannel_driver);
+	if (ret)
+		goto cleanup;
+
+	register_eadm_ops(&eadm_ops);
+	return ret;
+
+cleanup:
+	isc_unregister(EADM_SCH_ISC);
+	debug_unregister(eadm_debug);
+	return ret;
+}
+
+static void __exit eadm_sch_exit(void)
+{
+	unregister_eadm_ops(&eadm_ops);
+	css_driver_unregister(&eadm_subchannel_driver);
+	isc_unregister(EADM_SCH_ISC);
+	debug_unregister(eadm_debug);
+}
+module_init(eadm_sch_init);
+module_exit(eadm_sch_exit);
diff --git a/drivers/s390/cio/eadm_sch.h b/drivers/s390/cio/eadm_sch.h
new file mode 100644
index 0000000..2779be0
--- /dev/null
+++ b/drivers/s390/cio/eadm_sch.h
@@ -0,0 +1,20 @@
+#ifndef EADM_SCH_H
+#define EADM_SCH_H
+
+#include <linux/device.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include "orb.h"
+
+struct eadm_private {
+	union orb orb;
+	enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state;
+	struct timer_list timer;
+	struct list_head head;
+	struct subchannel *sch;
+} __aligned(8);
+
+#define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev))
+#define set_eadm_private(n, p) (dev_set_drvdata(&n->dev, p))
+
+#endif
diff --git a/drivers/s390/cio/orb.h b/drivers/s390/cio/orb.h
index 45a9865..7a64053 100644
--- a/drivers/s390/cio/orb.h
+++ b/drivers/s390/cio/orb.h
@@ -59,9 +59,33 @@
 	u32:32;
 }  __packed __aligned(4);
 
+/*
+ * eadm operation request block
+ */
+struct eadm_orb {
+	u32 intparm;
+	u32 key:4;
+	u32:4;
+	u32 compat1:1;
+	u32 compat2:1;
+	u32:21;
+	u32 x:1;
+	u32 aob;
+	u32 css_prio:8;
+	u32:8;
+	u32 scm_prio:8;
+	u32:8;
+	u32:29;
+	u32 fmt:3;
+	u32:32;
+	u32:32;
+	u32:32;
+}  __packed __aligned(4);
+
 union orb {
 	struct cmd_orb cmd;
 	struct tm_orb tm;
+	struct eadm_orb eadm;
 }  __packed __aligned(4);
 
 #endif /* S390_ORB_H */
diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h
index e1f6468..7f8b973 100644
--- a/drivers/s390/cio/qdio_debug.h
+++ b/drivers/s390/cio/qdio_debug.h
@@ -37,10 +37,14 @@
 		debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \
 	} while (0)
 
-#define DBF_HEX(addr, len) \
-	do { \
-		debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \
-	} while (0)
+static inline void DBF_HEX(void *addr, int len)
+{
+	while (len > 0) {
+		debug_event(qdio_dbf_setup, DBF_ERR, addr, len);
+		len -= qdio_dbf_setup->buf_size;
+		addr += qdio_dbf_setup->buf_size;
+	}
+}
 
 #define DBF_ERROR(text...) \
 	do { \
@@ -49,11 +53,14 @@
 		debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \
 	} while (0)
 
-#define DBF_ERROR_HEX(addr, len) \
-	do { \
-		debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \
-	} while (0)
-
+static inline void DBF_ERROR_HEX(void *addr, int len)
+{
+	while (len > 0) {
+		debug_event(qdio_dbf_error, DBF_ERR, addr, len);
+		len -= qdio_dbf_error->buf_size;
+		addr += qdio_dbf_error->buf_size;
+	}
+}
 
 #define DBF_DEV_EVENT(level, device, text...) \
 	do { \
@@ -64,10 +71,15 @@
 		} \
 	} while (0)
 
-#define DBF_DEV_HEX(level, device, addr, len) \
-	do { \
-		debug_event(device->debug_area, level, (void*)(addr), len); \
-	} while (0)
+static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr,
+			       int len, int level)
+{
+	while (len > 0) {
+		debug_event(dev->debug_area, level, addr, len);
+		len -= dev->debug_area->buf_size;
+		addr += dev->debug_area->buf_size;
+	}
+}
 
 void qdio_allocate_dbf(struct qdio_initialize *init_data,
 		       struct qdio_irq *irq_ptr);
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c
new file mode 100644
index 0000000..bcf20f3
--- /dev/null
+++ b/drivers/s390/cio/scm.c
@@ -0,0 +1,317 @@
+/*
+ * Recognize and maintain s390 storage class memory.
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <asm/eadm.h>
+#include "chsc.h"
+
+static struct device *scm_root;
+static struct eadm_ops *eadm_ops;
+static DEFINE_MUTEX(eadm_ops_mutex);
+
+#define to_scm_dev(n) container_of(n, struct scm_device, dev)
+#define	to_scm_drv(d) container_of(d, struct scm_driver, drv)
+
+static int scmdev_probe(struct device *dev)
+{
+	struct scm_device *scmdev = to_scm_dev(dev);
+	struct scm_driver *scmdrv = to_scm_drv(dev->driver);
+
+	return scmdrv->probe ? scmdrv->probe(scmdev) : -ENODEV;
+}
+
+static int scmdev_remove(struct device *dev)
+{
+	struct scm_device *scmdev = to_scm_dev(dev);
+	struct scm_driver *scmdrv = to_scm_drv(dev->driver);
+
+	return scmdrv->remove ? scmdrv->remove(scmdev) : -ENODEV;
+}
+
+static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	return add_uevent_var(env, "MODALIAS=scm:scmdev");
+}
+
+static struct bus_type scm_bus_type = {
+	.name  = "scm",
+	.probe = scmdev_probe,
+	.remove = scmdev_remove,
+	.uevent = scmdev_uevent,
+};
+
+/**
+ * scm_driver_register() - register a scm driver
+ * @scmdrv: driver to be registered
+ */
+int scm_driver_register(struct scm_driver *scmdrv)
+{
+	struct device_driver *drv = &scmdrv->drv;
+
+	drv->bus = &scm_bus_type;
+
+	return driver_register(drv);
+}
+EXPORT_SYMBOL_GPL(scm_driver_register);
+
+/**
+ * scm_driver_unregister() - deregister a scm driver
+ * @scmdrv: driver to be deregistered
+ */
+void scm_driver_unregister(struct scm_driver *scmdrv)
+{
+	driver_unregister(&scmdrv->drv);
+}
+EXPORT_SYMBOL_GPL(scm_driver_unregister);
+
+int scm_get_ref(void)
+{
+	int ret = 0;
+
+	mutex_lock(&eadm_ops_mutex);
+	if (!eadm_ops || !try_module_get(eadm_ops->owner))
+		ret = -ENOENT;
+	mutex_unlock(&eadm_ops_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(scm_get_ref);
+
+void scm_put_ref(void)
+{
+	mutex_lock(&eadm_ops_mutex);
+	module_put(eadm_ops->owner);
+	mutex_unlock(&eadm_ops_mutex);
+}
+EXPORT_SYMBOL_GPL(scm_put_ref);
+
+void register_eadm_ops(struct eadm_ops *ops)
+{
+	mutex_lock(&eadm_ops_mutex);
+	eadm_ops = ops;
+	mutex_unlock(&eadm_ops_mutex);
+}
+EXPORT_SYMBOL_GPL(register_eadm_ops);
+
+void unregister_eadm_ops(struct eadm_ops *ops)
+{
+	mutex_lock(&eadm_ops_mutex);
+	eadm_ops = NULL;
+	mutex_unlock(&eadm_ops_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_eadm_ops);
+
+int scm_start_aob(struct aob *aob)
+{
+	return eadm_ops->eadm_start(aob);
+}
+EXPORT_SYMBOL_GPL(scm_start_aob);
+
+void scm_irq_handler(struct aob *aob, int error)
+{
+	struct aob_rq_header *aobrq = (void *) aob->request.data;
+	struct scm_device *scmdev = aobrq->scmdev;
+	struct scm_driver *scmdrv = to_scm_drv(scmdev->dev.driver);
+
+	scmdrv->handler(scmdev, aobrq->data, error);
+}
+EXPORT_SYMBOL_GPL(scm_irq_handler);
+
+#define scm_attr(name)							\
+static ssize_t show_##name(struct device *dev,				\
+	       struct device_attribute *attr, char *buf)		\
+{									\
+	struct scm_device *scmdev = to_scm_dev(dev);			\
+	int ret;							\
+									\
+	device_lock(dev);						\
+	ret = sprintf(buf, "%u\n", scmdev->attrs.name);			\
+	device_unlock(dev);						\
+									\
+	return ret;							\
+}									\
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+scm_attr(persistence);
+scm_attr(oper_state);
+scm_attr(data_state);
+scm_attr(rank);
+scm_attr(release);
+scm_attr(res_id);
+
+static struct attribute *scmdev_attrs[] = {
+	&dev_attr_persistence.attr,
+	&dev_attr_oper_state.attr,
+	&dev_attr_data_state.attr,
+	&dev_attr_rank.attr,
+	&dev_attr_release.attr,
+	&dev_attr_res_id.attr,
+	NULL,
+};
+
+static struct attribute_group scmdev_attr_group = {
+	.attrs = scmdev_attrs,
+};
+
+static const struct attribute_group *scmdev_attr_groups[] = {
+	&scmdev_attr_group,
+	NULL,
+};
+
+static void scmdev_release(struct device *dev)
+{
+	struct scm_device *scmdev = to_scm_dev(dev);
+
+	kfree(scmdev);
+}
+
+static void scmdev_setup(struct scm_device *scmdev, struct sale *sale,
+			 unsigned int size, unsigned int max_blk_count)
+{
+	dev_set_name(&scmdev->dev, "%016llx", (unsigned long long) sale->sa);
+	scmdev->nr_max_block = max_blk_count;
+	scmdev->address = sale->sa;
+	scmdev->size = 1UL << size;
+	scmdev->attrs.rank = sale->rank;
+	scmdev->attrs.persistence = sale->p;
+	scmdev->attrs.oper_state = sale->op_state;
+	scmdev->attrs.data_state = sale->data_state;
+	scmdev->attrs.rank = sale->rank;
+	scmdev->attrs.release = sale->r;
+	scmdev->attrs.res_id = sale->rid;
+	scmdev->dev.parent = scm_root;
+	scmdev->dev.bus = &scm_bus_type;
+	scmdev->dev.release = scmdev_release;
+	scmdev->dev.groups = scmdev_attr_groups;
+}
+
+/*
+ * Check for state-changes, notify the driver and userspace.
+ */
+static void scmdev_update(struct scm_device *scmdev, struct sale *sale)
+{
+	struct scm_driver *scmdrv;
+	bool changed;
+
+	device_lock(&scmdev->dev);
+	changed = scmdev->attrs.rank != sale->rank ||
+		  scmdev->attrs.oper_state != sale->op_state;
+	scmdev->attrs.rank = sale->rank;
+	scmdev->attrs.oper_state = sale->op_state;
+	if (!scmdev->dev.driver)
+		goto out;
+	scmdrv = to_scm_drv(scmdev->dev.driver);
+	if (changed && scmdrv->notify)
+		scmdrv->notify(scmdev);
+out:
+	device_unlock(&scmdev->dev);
+	if (changed)
+		kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static int check_address(struct device *dev, void *data)
+{
+	struct scm_device *scmdev = to_scm_dev(dev);
+	struct sale *sale = data;
+
+	return scmdev->address == sale->sa;
+}
+
+static struct scm_device *scmdev_find(struct sale *sale)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&scm_bus_type, NULL, sale, check_address);
+
+	return dev ? to_scm_dev(dev) : NULL;
+}
+
+static int scm_add(struct chsc_scm_info *scm_info, size_t num)
+{
+	struct sale *sale, *scmal = scm_info->scmal;
+	struct scm_device *scmdev;
+	int ret;
+
+	for (sale = scmal; sale < scmal + num; sale++) {
+		scmdev = scmdev_find(sale);
+		if (scmdev) {
+			scmdev_update(scmdev, sale);
+			/* Release reference from scm_find(). */
+			put_device(&scmdev->dev);
+			continue;
+		}
+		scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL);
+		if (!scmdev)
+			return -ENODEV;
+		scmdev_setup(scmdev, sale, scm_info->is, scm_info->mbc);
+		ret = device_register(&scmdev->dev);
+		if (ret) {
+			/* Release reference from device_initialize(). */
+			put_device(&scmdev->dev);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int scm_update_information(void)
+{
+	struct chsc_scm_info *scm_info;
+	u64 token = 0;
+	size_t num;
+	int ret;
+
+	scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+	if (!scm_info)
+		return -ENOMEM;
+
+	do {
+		ret = chsc_scm_info(scm_info, token);
+		if (ret)
+			break;
+
+		num = (scm_info->response.length -
+		       (offsetof(struct chsc_scm_info, scmal) -
+			offsetof(struct chsc_scm_info, response))
+		      ) / sizeof(struct sale);
+
+		ret = scm_add(scm_info, num);
+		if (ret)
+			break;
+
+		token = scm_info->restok;
+	} while (token);
+
+	free_page((unsigned long)scm_info);
+
+	return ret;
+}
+
+static int __init scm_init(void)
+{
+	int ret;
+
+	ret = bus_register(&scm_bus_type);
+	if (ret)
+		return ret;
+
+	scm_root = root_device_register("scm");
+	if (IS_ERR(scm_root)) {
+		bus_unregister(&scm_bus_type);
+		return PTR_ERR(scm_root);
+	}
+
+	scm_update_information();
+	return 0;
+}
+subsys_initcall_sync(scm_init);
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index af3c7f1..771faf70 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -4,4 +4,5 @@
 
 ap-objs := ap_bus.o
 obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o
-obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o zcrypt_cex4.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index ae258a4..7b865a7 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corp. 2006
+ * Copyright IBM Corp. 2006, 2012
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
  *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -62,13 +62,14 @@
 static void ap_reset(struct ap_device *ap_dev);
 static void ap_config_timeout(unsigned long ptr);
 static int ap_select_domain(void);
+static void ap_query_configuration(void);
 
 /*
  * Module description.
  */
 MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("Adjunct Processor Bus driver, "
-		   "Copyright IBM Corp. 2006");
+MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \
+		   "Copyright IBM Corp. 2006, 2012");
 MODULE_LICENSE("GPL");
 
 /*
@@ -84,6 +85,7 @@
 MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
 
 static struct device *ap_root_device = NULL;
+static struct ap_config_info *ap_configuration;
 static DEFINE_SPINLOCK(ap_device_list_lock);
 static LIST_HEAD(ap_device_list);
 
@@ -158,6 +160,19 @@
 }
 
 /**
+ * ap_configuration_available(): Test if AP configuration
+ * information is available.
+ *
+ * Returns 1 if AP configuration information is available.
+ */
+#ifdef CONFIG_64BIT
+static int ap_configuration_available(void)
+{
+	return test_facility(2) && test_facility(12);
+}
+#endif
+
+/**
  * ap_test_queue(): Test adjunct processor queue.
  * @qid: The AP queue number
  * @queue_depth: Pointer to queue depth value
@@ -242,6 +257,26 @@
 }
 #endif
 
+#ifdef CONFIG_64BIT
+static inline int __ap_query_configuration(struct ap_config_info *config)
+{
+	register unsigned long reg0 asm ("0") = 0x04000000UL;
+	register unsigned long reg1 asm ("1") = -EINVAL;
+	register unsigned char *reg2 asm ("2") = (unsigned char *)config;
+
+	asm volatile(
+		".long 0xb2af0000\n"		/* PQAP(QCI) */
+		"0: la    %1,0\n"
+		"1:\n"
+		EX_TABLE(0b, 1b)
+		: "+d" (reg0), "+d" (reg1), "+d" (reg2)
+		:
+		: "cc");
+
+	return reg1;
+}
+#endif
+
 /**
  * ap_query_functions(): Query supported functions.
  * @qid: The AP queue number
@@ -292,25 +327,6 @@
 }
 
 /**
- * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA
- * support.
- * @qid: The AP queue number
- *
- * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not.
- */
-int ap_4096_commands_available(ap_qid_t qid)
-{
-	unsigned int functions;
-
-	if (ap_query_functions(qid, &functions))
-		return 0;
-
-	return test_ap_facility(functions, 1) &&
-	       test_ap_facility(functions, 2);
-}
-EXPORT_SYMBOL(ap_4096_commands_available);
-
-/**
  * ap_queue_enable_interruption(): Enable interruption on an AP.
  * @qid: The AP queue number
  * @ind: the notification indicator byte
@@ -657,6 +673,34 @@
 
 static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
 
+static ssize_t ap_requestq_count_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	int rc;
+
+	spin_lock_bh(&ap_dev->lock);
+	rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count);
+	spin_unlock_bh(&ap_dev->lock);
+	return rc;
+}
+
+static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
+
+static ssize_t ap_pendingq_count_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	int rc;
+
+	spin_lock_bh(&ap_dev->lock);
+	rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count);
+	spin_unlock_bh(&ap_dev->lock);
+	return rc;
+}
+
+static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
+
 static ssize_t ap_modalias_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -665,11 +709,23 @@
 
 static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
 
+static ssize_t ap_functions_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions);
+}
+
+static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
+
 static struct attribute *ap_dev_attrs[] = {
 	&dev_attr_hwtype.attr,
 	&dev_attr_depth.attr,
 	&dev_attr_request_count.attr,
+	&dev_attr_requestq_count.attr,
+	&dev_attr_pendingq_count.attr,
 	&dev_attr_modalias.attr,
+	&dev_attr_ap_functions.attr,
 	NULL
 };
 static struct attribute_group ap_dev_attr_group = {
@@ -772,6 +828,7 @@
 		ap_suspend_flag = 0;
 		if (!ap_interrupts_available())
 			ap_interrupt_indicator = NULL;
+		ap_query_configuration();
 		if (!user_set_domain) {
 			ap_domain_index = -1;
 			ap_select_domain();
@@ -895,6 +952,20 @@
 }
 EXPORT_SYMBOL(ap_driver_unregister);
 
+void ap_bus_force_rescan(void)
+{
+	/* Delete the AP bus rescan timer. */
+	del_timer(&ap_config_timer);
+
+	/* processing a synchonuous bus rescan */
+	ap_scan_bus(NULL);
+
+	/* Setup the AP bus rescan timer again. */
+	ap_config_timer.expires = jiffies + ap_config_time * HZ;
+	add_timer(&ap_config_timer);
+}
+EXPORT_SYMBOL(ap_bus_force_rescan);
+
 /*
  * AP bus attributes.
  */
@@ -997,6 +1068,65 @@
 	NULL,
 };
 
+static inline int ap_test_config(unsigned int *field, unsigned int nr)
+{
+	if (nr > 0xFFu)
+		return 0;
+	return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
+}
+
+/*
+ * ap_test_config_card_id(): Test, whether an AP card ID is configured.
+ * @id AP card ID
+ *
+ * Returns 0 if the card is not configured
+ *	   1 if the card is configured or
+ *	     if the configuration information is not available
+ */
+static inline int ap_test_config_card_id(unsigned int id)
+{
+	if (!ap_configuration)
+		return 1;
+	return ap_test_config(ap_configuration->apm, id);
+}
+
+/*
+ * ap_test_config_domain(): Test, whether an AP usage domain is configured.
+ * @domain AP usage domain ID
+ *
+ * Returns 0 if the usage domain is not configured
+ *	   1 if the usage domain is configured or
+ *	     if the configuration information is not available
+ */
+static inline int ap_test_config_domain(unsigned int domain)
+{
+	if (!ap_configuration)
+		return 1;
+	return ap_test_config(ap_configuration->aqm, domain);
+}
+
+/**
+ * ap_query_configuration(): Query AP configuration information.
+ *
+ * Query information of installed cards and configured domains from AP.
+ */
+static void ap_query_configuration(void)
+{
+#ifdef CONFIG_64BIT
+	if (ap_configuration_available()) {
+		if (!ap_configuration)
+			ap_configuration =
+				kzalloc(sizeof(struct ap_config_info),
+					GFP_KERNEL);
+		if (ap_configuration)
+			__ap_query_configuration(ap_configuration);
+	} else
+		ap_configuration = NULL;
+#else
+	ap_configuration = NULL;
+#endif
+}
+
 /**
  * ap_select_domain(): Select an AP domain.
  *
@@ -1005,6 +1135,7 @@
 static int ap_select_domain(void)
 {
 	int queue_depth, device_type, count, max_count, best_domain;
+	ap_qid_t qid;
 	int rc, i, j;
 
 	/*
@@ -1018,9 +1149,13 @@
 	best_domain = -1;
 	max_count = 0;
 	for (i = 0; i < AP_DOMAINS; i++) {
+		if (!ap_test_config_domain(i))
+			continue;
 		count = 0;
 		for (j = 0; j < AP_DEVICES; j++) {
-			ap_qid_t qid = AP_MKQID(j, i);
+			if (!ap_test_config_card_id(j))
+				continue;
+			qid = AP_MKQID(j, i);
 			rc = ap_query_queue(qid, &queue_depth, &device_type);
 			if (rc)
 				continue;
@@ -1169,6 +1304,7 @@
 	unsigned int device_functions;
 	int rc, i;
 
+	ap_query_configuration();
 	if (ap_select_domain() != 0)
 		return;
 	for (i = 0; i < AP_DEVICES; i++) {
@@ -1176,7 +1312,10 @@
 		dev = bus_find_device(&ap_bus_type, NULL,
 				      (void *)(unsigned long)qid,
 				      __ap_scan_bus);
-		rc = ap_query_queue(qid, &queue_depth, &device_type);
+		if (ap_test_config_card_id(i))
+			rc = ap_query_queue(qid, &queue_depth, &device_type);
+		else
+			rc = -ENODEV;
 		if (dev) {
 			if (rc == -EBUSY) {
 				set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1217,29 +1356,22 @@
 			    (unsigned long) ap_dev);
 		switch (device_type) {
 		case 0:
+			/* device type probing for old cards */
 			if (ap_probe_device_type(ap_dev)) {
 				kfree(ap_dev);
 				continue;
 			}
 			break;
-		case 10:
-			if (ap_query_functions(qid, &device_functions)) {
-				kfree(ap_dev);
-				continue;
-			}
-			if (test_ap_facility(device_functions, 3))
-				ap_dev->device_type = AP_DEVICE_TYPE_CEX3C;
-			else if (test_ap_facility(device_functions, 4))
-				ap_dev->device_type = AP_DEVICE_TYPE_CEX3A;
-			else {
-				kfree(ap_dev);
-				continue;
-			}
-			break;
 		default:
 			ap_dev->device_type = device_type;
 		}
 
+		rc = ap_query_functions(qid, &device_functions);
+		if (!rc)
+			ap_dev->functions = device_functions;
+		else
+			ap_dev->functions = 0u;
+
 		ap_dev->device.bus = &ap_bus_type;
 		ap_dev->device.parent = ap_root_device;
 		if (dev_set_name(&ap_dev->device, "card%02x",
@@ -1785,6 +1917,7 @@
 		goto out_root;
 	}
 
+	ap_query_configuration();
 	if (ap_select_domain() == 0)
 		ap_scan_bus(NULL);
 
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 52d6199..685f6cc0 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corp. 2006
+ * Copyright IBM Corp. 2006, 2012
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
  *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -83,13 +83,12 @@
 	return !(memcmp(status, &invalid, sizeof(struct ap_queue_status)));
 }
 
-#define MAX_AP_FACILITY 31
-
-static inline int test_ap_facility(unsigned int function, unsigned int nr)
+#define AP_MAX_BITS 31
+static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
 {
-	if (nr > MAX_AP_FACILITY)
+	if (nr > AP_MAX_BITS)
 		return 0;
-	return function & (unsigned int)(0x80000000 >> nr);
+	return (*ptr & (0x80000000u >> nr)) != 0;
 }
 
 #define AP_RESPONSE_NORMAL		0x00
@@ -117,6 +116,15 @@
 #define AP_DEVICE_TYPE_CEX2C	7
 #define AP_DEVICE_TYPE_CEX3A	8
 #define AP_DEVICE_TYPE_CEX3C	9
+#define AP_DEVICE_TYPE_CEX4	10
+
+/*
+ * Known function facilities
+ */
+#define AP_FUNC_MEX4K 1
+#define AP_FUNC_CRT4K 2
+#define AP_FUNC_COPRO 3
+#define AP_FUNC_ACCEL 4
 
 /*
  * AP reset flag states
@@ -151,6 +159,7 @@
 	ap_qid_t qid;			/* AP queue id. */
 	int queue_depth;		/* AP queue depth.*/
 	int device_type;		/* AP device type. */
+	unsigned int functions;		/* AP device function bitfield. */
 	int unregistered;		/* marks AP device as unregistered */
 	struct timer_list timeout;	/* Timer for request timeouts. */
 	int reset;			/* Reset required after req. timeout. */
@@ -183,6 +192,17 @@
 			struct ap_message *);
 };
 
+struct ap_config_info {
+	unsigned int special_command:1;
+	unsigned int ap_extended:1;
+	unsigned char reserved1:6;
+	unsigned char reserved2[15];
+	unsigned int apm[8];		/* AP ID mask */
+	unsigned int aqm[8];		/* AP queue mask */
+	unsigned int adm[8];		/* AP domain mask */
+	unsigned char reserved4[16];
+} __packed;
+
 #define AP_DEVICE(dt)					\
 	.dev_type=(dt),					\
 	.match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
@@ -211,10 +231,9 @@
 void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
 void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
 void ap_flush_queue(struct ap_device *ap_dev);
+void ap_bus_force_rescan(void);
 
 int ap_module_init(void);
 void ap_module_exit(void);
 
-int ap_4096_commands_available(ap_qid_t qid);
-
 #endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 2f94132..31cfaa55 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1,7 +1,7 @@
 /*
  *  zcrypt 2.1.0
  *
- *  Copyright IBM Corp. 2001, 2006
+ *  Copyright IBM Corp. 2001, 2012
  *  Author(s): Robert Burroughs
  *	       Eric Rossman (edrossma@us.ibm.com)
  *	       Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -9,6 +9,7 @@
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
  *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,25 +38,39 @@
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
 #include <linux/hw_random.h>
+#include <linux/debugfs.h>
+#include <asm/debug.h>
 
+#include "zcrypt_debug.h"
 #include "zcrypt_api.h"
 
 /*
  * Module description.
  */
 MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("Cryptographic Coprocessor interface, "
-		   "Copyright IBM Corp. 2001, 2006");
+MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
+		   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
 static DEFINE_SPINLOCK(zcrypt_device_lock);
 static LIST_HEAD(zcrypt_device_list);
 static int zcrypt_device_count = 0;
 static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
+static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
+
+atomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
+EXPORT_SYMBOL(zcrypt_rescan_req);
 
 static int zcrypt_rng_device_add(void);
 static void zcrypt_rng_device_remove(void);
 
+static DEFINE_SPINLOCK(zcrypt_ops_list_lock);
+static LIST_HEAD(zcrypt_ops_list);
+
+static debug_info_t *zcrypt_dbf_common;
+static debug_info_t *zcrypt_dbf_devices;
+static struct dentry *debugfs_root;
+
 /*
  * Device attributes common for all crypto devices.
  */
@@ -85,6 +100,8 @@
 	if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
 		return -EINVAL;
 	zdev->online = online;
+	ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid,
+		       zdev->online);
 	if (!online)
 		ap_flush_queue(zdev->ap_dev);
 	return count;
@@ -103,6 +120,24 @@
 };
 
 /**
+ * Process a rescan of the transport layer.
+ *
+ * Returns 1, if the rescan has been processed, otherwise 0.
+ */
+static inline int zcrypt_process_rescan(void)
+{
+	if (atomic_read(&zcrypt_rescan_req)) {
+		atomic_set(&zcrypt_rescan_req, 0);
+		atomic_inc(&zcrypt_rescan_count);
+		ap_bus_force_rescan();
+		ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d",
+				  atomic_inc_return(&zcrypt_rescan_count));
+		return 1;
+	}
+	return 0;
+}
+
+/**
  * __zcrypt_increase_preference(): Increase preference of a crypto device.
  * @zdev: Pointer the crypto device
  *
@@ -190,6 +225,7 @@
 	zdev->reply.length = max_response_size;
 	spin_lock_init(&zdev->lock);
 	INIT_LIST_HEAD(&zdev->list);
+	zdev->dbf_area = zcrypt_dbf_devices;
 	return zdev;
 
 out_free:
@@ -215,6 +251,8 @@
 {
 	int rc;
 
+	if (!zdev->ops)
+		return -ENODEV;
 	rc = sysfs_create_group(&zdev->ap_dev->device.kobj,
 				&zcrypt_device_attr_group);
 	if (rc)
@@ -223,6 +261,8 @@
 	kref_init(&zdev->refcount);
 	spin_lock_bh(&zcrypt_device_lock);
 	zdev->online = 1;	/* New devices are online by default. */
+	ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
+		       zdev->online);
 	list_add_tail(&zdev->list, &zcrypt_device_list);
 	__zcrypt_increase_preference(zdev);
 	zcrypt_device_count++;
@@ -269,6 +309,67 @@
 }
 EXPORT_SYMBOL(zcrypt_device_unregister);
 
+void zcrypt_msgtype_register(struct zcrypt_ops *zops)
+{
+	if (zops->owner) {
+		spin_lock_bh(&zcrypt_ops_list_lock);
+		list_add_tail(&zops->list, &zcrypt_ops_list);
+		spin_unlock_bh(&zcrypt_ops_list_lock);
+	}
+}
+EXPORT_SYMBOL(zcrypt_msgtype_register);
+
+void zcrypt_msgtype_unregister(struct zcrypt_ops *zops)
+{
+	spin_lock_bh(&zcrypt_ops_list_lock);
+	list_del_init(&zops->list);
+	spin_unlock_bh(&zcrypt_ops_list_lock);
+}
+EXPORT_SYMBOL(zcrypt_msgtype_unregister);
+
+static inline
+struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant)
+{
+	struct zcrypt_ops *zops;
+	int found = 0;
+
+	spin_lock_bh(&zcrypt_ops_list_lock);
+	list_for_each_entry(zops, &zcrypt_ops_list, list) {
+		if ((zops->variant == variant) &&
+		    (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_bh(&zcrypt_ops_list_lock);
+
+	if (!found)
+		return NULL;
+	return zops;
+}
+
+struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant)
+{
+	struct zcrypt_ops *zops = NULL;
+
+	zops = __ops_lookup(name, variant);
+	if (!zops) {
+		request_module(name);
+		zops = __ops_lookup(name, variant);
+	}
+	if ((!zops) || (!try_module_get(zops->owner)))
+		return NULL;
+	return zops;
+}
+EXPORT_SYMBOL(zcrypt_msgtype_request);
+
+void zcrypt_msgtype_release(struct zcrypt_ops *zops)
+{
+	if (zops)
+		module_put(zops->owner);
+}
+EXPORT_SYMBOL(zcrypt_msgtype_release);
+
 /**
  * zcrypt_read (): Not supported beyond zcrypt 1.3.1.
  *
@@ -640,6 +741,11 @@
 		do {
 			rc = zcrypt_rsa_modexpo(&mex);
 		} while (rc == -EAGAIN);
+		/* on failure: retry once again after a requested rescan */
+		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+			do {
+				rc = zcrypt_rsa_modexpo(&mex);
+			} while (rc == -EAGAIN);
 		if (rc)
 			return rc;
 		return put_user(mex.outputdatalength, &umex->outputdatalength);
@@ -652,6 +758,11 @@
 		do {
 			rc = zcrypt_rsa_crt(&crt);
 		} while (rc == -EAGAIN);
+		/* on failure: retry once again after a requested rescan */
+		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+			do {
+				rc = zcrypt_rsa_crt(&crt);
+			} while (rc == -EAGAIN);
 		if (rc)
 			return rc;
 		return put_user(crt.outputdatalength, &ucrt->outputdatalength);
@@ -664,6 +775,11 @@
 		do {
 			rc = zcrypt_send_cprb(&xcRB);
 		} while (rc == -EAGAIN);
+		/* on failure: retry once again after a requested rescan */
+		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+			do {
+				rc = zcrypt_send_cprb(&xcRB);
+			} while (rc == -EAGAIN);
 		if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
 			return -EFAULT;
 		return rc;
@@ -770,10 +886,15 @@
 	do {
 		rc = zcrypt_rsa_modexpo(&mex64);
 	} while (rc == -EAGAIN);
-	if (!rc)
-		rc = put_user(mex64.outputdatalength,
-			      &umex32->outputdatalength);
-	return rc;
+	/* on failure: retry once again after a requested rescan */
+	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+		do {
+			rc = zcrypt_rsa_modexpo(&mex64);
+		} while (rc == -EAGAIN);
+	if (rc)
+		return rc;
+	return put_user(mex64.outputdatalength,
+			&umex32->outputdatalength);
 }
 
 struct compat_ica_rsa_modexpo_crt {
@@ -810,10 +931,15 @@
 	do {
 		rc = zcrypt_rsa_crt(&crt64);
 	} while (rc == -EAGAIN);
-	if (!rc)
-		rc = put_user(crt64.outputdatalength,
-			      &ucrt32->outputdatalength);
-	return rc;
+	/* on failure: retry once again after a requested rescan */
+	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+		do {
+			rc = zcrypt_rsa_crt(&crt64);
+		} while (rc == -EAGAIN);
+	if (rc)
+		return rc;
+	return put_user(crt64.outputdatalength,
+			&ucrt32->outputdatalength);
 }
 
 struct compat_ica_xcRB {
@@ -869,6 +995,11 @@
 	do {
 		rc = zcrypt_send_cprb(&xcRB64);
 	} while (rc == -EAGAIN);
+	/* on failure: retry once again after a requested rescan */
+	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+		do {
+			rc = zcrypt_send_cprb(&xcRB64);
+		} while (rc == -EAGAIN);
 	xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
 	xcRB32.reply_data_length = xcRB64.reply_data_length;
 	xcRB32.status = xcRB64.status;
@@ -1126,6 +1257,9 @@
 	 */
 	if (zcrypt_rng_buffer_index == 0) {
 		rc = zcrypt_rng((char *) zcrypt_rng_buffer);
+		/* on failure: retry once again after a requested rescan */
+		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+			rc = zcrypt_rng((char *) zcrypt_rng_buffer);
 		if (rc < 0)
 			return -EIO;
 		zcrypt_rng_buffer_index = rc / sizeof *data;
@@ -1178,6 +1312,30 @@
 	mutex_unlock(&zcrypt_rng_mutex);
 }
 
+int __init zcrypt_debug_init(void)
+{
+	debugfs_root = debugfs_create_dir("zcrypt", NULL);
+
+	zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16);
+	debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view);
+	debug_set_level(zcrypt_dbf_common, DBF_ERR);
+
+	zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16);
+	debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view);
+	debug_set_level(zcrypt_dbf_devices, DBF_ERR);
+
+	return 0;
+}
+
+void zcrypt_debug_exit(void)
+{
+	debugfs_remove(debugfs_root);
+	if (zcrypt_dbf_common)
+		debug_unregister(zcrypt_dbf_common);
+	if (zcrypt_dbf_devices)
+		debug_unregister(zcrypt_dbf_devices);
+}
+
 /**
  * zcrypt_api_init(): Module initialization.
  *
@@ -1187,6 +1345,12 @@
 {
 	int rc;
 
+	rc = zcrypt_debug_init();
+	if (rc)
+		goto out;
+
+	atomic_set(&zcrypt_rescan_req, 0);
+
 	/* Register the request sprayer. */
 	rc = misc_register(&zcrypt_misc_device);
 	if (rc < 0)
@@ -1216,6 +1380,7 @@
 {
 	remove_proc_entry("driver/z90crypt", NULL);
 	misc_deregister(&zcrypt_misc_device);
+	zcrypt_debug_exit();
 }
 
 module_init(zcrypt_api_init);
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 7a32c4b..8963291 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -1,7 +1,7 @@
 /*
  *  zcrypt 2.1.0
  *
- *  Copyright IBM Corp. 2001, 2006
+ *  Copyright IBM Corp. 2001, 2012
  *  Author(s): Robert Burroughs
  *	       Eric Rossman (edrossma@us.ibm.com)
  *	       Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -9,6 +9,7 @@
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
  *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,8 +29,10 @@
 #ifndef _ZCRYPT_API_H_
 #define _ZCRYPT_API_H_
 
-#include "ap_bus.h"
+#include <linux/atomic.h>
+#include <asm/debug.h>
 #include <asm/zcrypt.h>
+#include "ap_bus.h"
 
 /* deprecated status calls */
 #define ICAZ90STATUS		_IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
@@ -87,6 +90,9 @@
 				struct ica_rsa_modexpo_crt *);
 	long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
 	long (*rng)(struct zcrypt_device *, char *);
+	struct list_head list;		/* zcrypt ops list. */
+	struct module *owner;
+	int variant;
 };
 
 struct zcrypt_device {
@@ -108,14 +114,23 @@
 
 	struct ap_message reply;	/* Per-device reply structure. */
 	int max_exp_bit_length;
+
+	debug_info_t *dbf_area;		/* debugging */
 };
 
+/* transport layer rescanning */
+extern atomic_t zcrypt_rescan_req;
+
 struct zcrypt_device *zcrypt_device_alloc(size_t);
 void zcrypt_device_free(struct zcrypt_device *);
 void zcrypt_device_get(struct zcrypt_device *);
 int zcrypt_device_put(struct zcrypt_device *);
 int zcrypt_device_register(struct zcrypt_device *);
 void zcrypt_device_unregister(struct zcrypt_device *);
+void zcrypt_msgtype_register(struct zcrypt_ops *);
+void zcrypt_msgtype_unregister(struct zcrypt_ops *);
+struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *, int);
+void zcrypt_msgtype_release(struct zcrypt_ops *);
 int zcrypt_api_init(void);
 void zcrypt_api_exit(void);
 
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 744c668..1e849d6 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -1,13 +1,14 @@
 /*
  *  zcrypt 2.1.0
  *
- *  Copyright IBM Corp. 2001, 2006
+ *  Copyright IBM Corp. 2001, 2012
  *  Author(s): Robert Burroughs
  *	       Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
  *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +36,7 @@
 #include "zcrypt_api.h"
 #include "zcrypt_error.h"
 #include "zcrypt_cex2a.h"
+#include "zcrypt_msgtype50.h"
 
 #define CEX2A_MIN_MOD_SIZE	  1	/*    8 bits	*/
 #define CEX2A_MAX_MOD_SIZE	256	/* 2048 bits	*/
@@ -63,14 +65,12 @@
 
 MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
 MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, "
-		   "Copyright IBM Corp. 2001, 2006");
+MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
+		   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
 static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
 static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
-static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
-				 struct ap_message *);
 
 static struct ap_driver zcrypt_cex2a_driver = {
 	.probe = zcrypt_cex2a_probe,
@@ -80,344 +80,6 @@
 };
 
 /**
- * Convert a ICAMEX message to a type50 MEX message.
- *
- * @zdev: crypto device pointer
- * @zreq: crypto request pointer
- * @mex: pointer to user input data
- *
- * Returns 0 on success or -EFAULT.
- */
-static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
-				       struct ap_message *ap_msg,
-				       struct ica_rsa_modexpo *mex)
-{
-	unsigned char *mod, *exp, *inp;
-	int mod_len;
-
-	mod_len = mex->inputdatalength;
-
-	if (mod_len <= 128) {
-		struct type50_meb1_msg *meb1 = ap_msg->message;
-		memset(meb1, 0, sizeof(*meb1));
-		ap_msg->length = sizeof(*meb1);
-		meb1->header.msg_type_code = TYPE50_TYPE_CODE;
-		meb1->header.msg_len = sizeof(*meb1);
-		meb1->keyblock_type = TYPE50_MEB1_FMT;
-		mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
-		exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
-		inp = meb1->message + sizeof(meb1->message) - mod_len;
-	} else if (mod_len <= 256) {
-		struct type50_meb2_msg *meb2 = ap_msg->message;
-		memset(meb2, 0, sizeof(*meb2));
-		ap_msg->length = sizeof(*meb2);
-		meb2->header.msg_type_code = TYPE50_TYPE_CODE;
-		meb2->header.msg_len = sizeof(*meb2);
-		meb2->keyblock_type = TYPE50_MEB2_FMT;
-		mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
-		exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
-		inp = meb2->message + sizeof(meb2->message) - mod_len;
-	} else {
-		/* mod_len > 256 = 4096 bit RSA Key */
-		struct type50_meb3_msg *meb3 = ap_msg->message;
-		memset(meb3, 0, sizeof(*meb3));
-		ap_msg->length = sizeof(*meb3);
-		meb3->header.msg_type_code = TYPE50_TYPE_CODE;
-		meb3->header.msg_len = sizeof(*meb3);
-		meb3->keyblock_type = TYPE50_MEB3_FMT;
-		mod = meb3->modulus + sizeof(meb3->modulus) - mod_len;
-		exp = meb3->exponent + sizeof(meb3->exponent) - mod_len;
-		inp = meb3->message + sizeof(meb3->message) - mod_len;
-	}
-
-	if (copy_from_user(mod, mex->n_modulus, mod_len) ||
-	    copy_from_user(exp, mex->b_key, mod_len) ||
-	    copy_from_user(inp, mex->inputdata, mod_len))
-		return -EFAULT;
-	return 0;
-}
-
-/**
- * Convert a ICACRT message to a type50 CRT message.
- *
- * @zdev: crypto device pointer
- * @zreq: crypto request pointer
- * @crt: pointer to user input data
- *
- * Returns 0 on success or -EFAULT.
- */
-static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
-				       struct ap_message *ap_msg,
-				       struct ica_rsa_modexpo_crt *crt)
-{
-	int mod_len, short_len, long_len, long_offset, limit;
-	unsigned char *p, *q, *dp, *dq, *u, *inp;
-
-	mod_len = crt->inputdatalength;
-	short_len = mod_len / 2;
-	long_len = mod_len / 2 + 8;
-
-	/*
-	 * CEX2A cannot handle p, dp, or U > 128 bytes.
-	 * If we have one of these, we need to do extra checking.
-	 * For CEX3A the limit is 256 bytes.
-	 */
-	if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)
-		limit = 256;
-	else
-		limit = 128;
-
-	if (long_len > limit) {
-		/*
-		 * zcrypt_rsa_crt already checked for the leading
-		 * zeroes of np_prime, bp_key and u_mult_inc.
-		 */
-		long_offset = long_len - limit;
-		long_len = limit;
-	} else
-		long_offset = 0;
-
-	/*
-	 * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use
-	 * the larger message structure.
-	 */
-	if (long_len <= 64) {
-		struct type50_crb1_msg *crb1 = ap_msg->message;
-		memset(crb1, 0, sizeof(*crb1));
-		ap_msg->length = sizeof(*crb1);
-		crb1->header.msg_type_code = TYPE50_TYPE_CODE;
-		crb1->header.msg_len = sizeof(*crb1);
-		crb1->keyblock_type = TYPE50_CRB1_FMT;
-		p = crb1->p + sizeof(crb1->p) - long_len;
-		q = crb1->q + sizeof(crb1->q) - short_len;
-		dp = crb1->dp + sizeof(crb1->dp) - long_len;
-		dq = crb1->dq + sizeof(crb1->dq) - short_len;
-		u = crb1->u + sizeof(crb1->u) - long_len;
-		inp = crb1->message + sizeof(crb1->message) - mod_len;
-	} else if (long_len <= 128) {
-		struct type50_crb2_msg *crb2 = ap_msg->message;
-		memset(crb2, 0, sizeof(*crb2));
-		ap_msg->length = sizeof(*crb2);
-		crb2->header.msg_type_code = TYPE50_TYPE_CODE;
-		crb2->header.msg_len = sizeof(*crb2);
-		crb2->keyblock_type = TYPE50_CRB2_FMT;
-		p = crb2->p + sizeof(crb2->p) - long_len;
-		q = crb2->q + sizeof(crb2->q) - short_len;
-		dp = crb2->dp + sizeof(crb2->dp) - long_len;
-		dq = crb2->dq + sizeof(crb2->dq) - short_len;
-		u = crb2->u + sizeof(crb2->u) - long_len;
-		inp = crb2->message + sizeof(crb2->message) - mod_len;
-	} else {
-		/* long_len >= 256 */
-		struct type50_crb3_msg *crb3 = ap_msg->message;
-		memset(crb3, 0, sizeof(*crb3));
-		ap_msg->length = sizeof(*crb3);
-		crb3->header.msg_type_code = TYPE50_TYPE_CODE;
-		crb3->header.msg_len = sizeof(*crb3);
-		crb3->keyblock_type = TYPE50_CRB3_FMT;
-		p = crb3->p + sizeof(crb3->p) - long_len;
-		q = crb3->q + sizeof(crb3->q) - short_len;
-		dp = crb3->dp + sizeof(crb3->dp) - long_len;
-		dq = crb3->dq + sizeof(crb3->dq) - short_len;
-		u = crb3->u + sizeof(crb3->u) - long_len;
-		inp = crb3->message + sizeof(crb3->message) - mod_len;
-	}
-
-	if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
-	    copy_from_user(q, crt->nq_prime, short_len) ||
-	    copy_from_user(dp, crt->bp_key + long_offset, long_len) ||
-	    copy_from_user(dq, crt->bq_key, short_len) ||
-	    copy_from_user(u, crt->u_mult_inv + long_offset, long_len) ||
-	    copy_from_user(inp, crt->inputdata, mod_len))
-		return -EFAULT;
-
-	return 0;
-}
-
-/**
- * Copy results from a type 80 reply message back to user space.
- *
- * @zdev: crypto device pointer
- * @reply: reply AP message.
- * @data: pointer to user output data
- * @length: size of user output data
- *
- * Returns 0 on success or -EFAULT.
- */
-static int convert_type80(struct zcrypt_device *zdev,
-			  struct ap_message *reply,
-			  char __user *outputdata,
-			  unsigned int outputdatalength)
-{
-	struct type80_hdr *t80h = reply->message;
-	unsigned char *data;
-
-	if (t80h->len < sizeof(*t80h) + outputdatalength) {
-		/* The result is too short, the CEX2A card may not do that.. */
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-	if (zdev->user_space_type == ZCRYPT_CEX2A)
-		BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
-	else
-		BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
-	data = reply->message + t80h->len - outputdatalength;
-	if (copy_to_user(outputdata, data, outputdatalength))
-		return -EFAULT;
-	return 0;
-}
-
-static int convert_response(struct zcrypt_device *zdev,
-			    struct ap_message *reply,
-			    char __user *outputdata,
-			    unsigned int outputdatalength)
-{
-	/* Response type byte is the second byte in the response. */
-	switch (((unsigned char *) reply->message)[1]) {
-	case TYPE82_RSP_CODE:
-	case TYPE88_RSP_CODE:
-		return convert_error(zdev, reply);
-	case TYPE80_RSP_CODE:
-		return convert_type80(zdev, reply,
-				      outputdata, outputdatalength);
-	default: /* Unknown response type, this should NEVER EVER happen */
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-}
-
-/**
- * This function is called from the AP bus code after a crypto request
- * "msg" has finished with the reply message "reply".
- * It is called from tasklet context.
- * @ap_dev: pointer to the AP device
- * @msg: pointer to the AP message
- * @reply: pointer to the AP reply message
- */
-static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
-				 struct ap_message *msg,
-				 struct ap_message *reply)
-{
-	static struct error_hdr error_reply = {
-		.type = TYPE82_RSP_CODE,
-		.reply_code = REP82_ERROR_MACHINE_FAILURE,
-	};
-	struct type80_hdr *t80h;
-	int length;
-
-	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply)) {
-		memcpy(msg->message, &error_reply, sizeof(error_reply));
-		goto out;
-	}
-	t80h = reply->message;
-	if (t80h->type == TYPE80_RSP_CODE) {
-		if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A)
-			length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
-		else
-			length = min(CEX3A_MAX_RESPONSE_SIZE, (int) t80h->len);
-		memcpy(msg->message, reply->message, length);
-	} else
-		memcpy(msg->message, reply->message, sizeof error_reply);
-out:
-	complete((struct completion *) msg->private);
-}
-
-static atomic_t zcrypt_step = ATOMIC_INIT(0);
-
-/**
- * The request distributor calls this function if it picked the CEX2A
- * device to handle a modexpo request.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  CEX2A device to the request distributor
- * @mex: pointer to the modexpo request buffer
- */
-static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
-				 struct ica_rsa_modexpo *mex)
-{
-	struct ap_message ap_msg;
-	struct completion work;
-	int rc;
-
-	ap_init_message(&ap_msg);
-	if (zdev->user_space_type == ZCRYPT_CEX2A)
-		ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
-	else
-		ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_cex2a_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &work;
-	rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
-	if (rc)
-		goto out_free;
-	init_completion(&work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&work);
-	if (rc == 0)
-		rc = convert_response(zdev, &ap_msg, mex->outputdata,
-				      mex->outputdatalength);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
-	kfree(ap_msg.message);
-	return rc;
-}
-
-/**
- * The request distributor calls this function if it picked the CEX2A
- * device to handle a modexpo_crt request.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  CEX2A device to the request distributor
- * @crt: pointer to the modexpoc_crt request buffer
- */
-static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
-				     struct ica_rsa_modexpo_crt *crt)
-{
-	struct ap_message ap_msg;
-	struct completion work;
-	int rc;
-
-	ap_init_message(&ap_msg);
-	if (zdev->user_space_type == ZCRYPT_CEX2A)
-		ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
-	else
-		ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_cex2a_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &work;
-	rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
-	if (rc)
-		goto out_free;
-	init_completion(&work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&work);
-	if (rc == 0)
-		rc = convert_response(zdev, &ap_msg, crt->outputdata,
-				      crt->outputdatalength);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
-	kfree(ap_msg.message);
-	return rc;
-}
-
-/**
- * The crypto operations for a CEX2A card.
- */
-static struct zcrypt_ops zcrypt_cex2a_ops = {
-	.rsa_modexpo = zcrypt_cex2a_modexpo,
-	.rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
-};
-
-/**
  * Probe function for CEX2A cards. It always accepts the AP device
  * since the bus_match already checked the hardware type.
  * @ap_dev: pointer to the AP device.
@@ -449,7 +111,8 @@
 		zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
 		zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
 		zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
-		if (ap_4096_commands_available(ap_dev->qid)) {
+		if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
+		    ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
 			zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
 			zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
 		}
@@ -457,16 +120,18 @@
 		zdev->speed_rating = CEX3A_SPEED_RATING;
 		break;
 	}
-	if (zdev != NULL) {
-		zdev->ap_dev = ap_dev;
-		zdev->ops = &zcrypt_cex2a_ops;
-		zdev->online = 1;
-		ap_dev->reply = &zdev->reply;
-		ap_dev->private = zdev;
-		rc = zcrypt_device_register(zdev);
-	}
+	if (!zdev)
+		return -ENODEV;
+	zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
+					   MSGTYPE50_VARIANT_DEFAULT);
+	zdev->ap_dev = ap_dev;
+	zdev->online = 1;
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
 	if (rc) {
 		ap_dev->private = NULL;
+		zcrypt_msgtype_release(zdev->ops);
 		zcrypt_device_free(zdev);
 	}
 	return rc;
@@ -479,8 +144,10 @@
 static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
 {
 	struct zcrypt_device *zdev = ap_dev->private;
+	struct zcrypt_ops *zops = zdev->ops;
 
 	zcrypt_device_unregister(zdev);
+	zcrypt_msgtype_release(zops);
 }
 
 int __init zcrypt_cex2a_init(void)
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
new file mode 100644
index 0000000..ce12263
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -0,0 +1,149 @@
+/*
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Holger Dengler <hd@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_msgtype6.h"
+#include "zcrypt_msgtype50.h"
+#include "zcrypt_error.h"
+#include "zcrypt_cex4.h"
+
+#define CEX4A_MIN_MOD_SIZE	  1	/*    8 bits	*/
+#define CEX4A_MAX_MOD_SIZE_2K	256	/* 2048 bits	*/
+#define CEX4A_MAX_MOD_SIZE_4K	512	/* 4096 bits	*/
+
+#define CEX4C_MIN_MOD_SIZE	 16	/*  256 bits	*/
+#define CEX4C_MAX_MOD_SIZE	512	/* 4096 bits	*/
+
+#define CEX4A_SPEED_RATING	900	 /* TODO new card, new speed rating */
+#define CEX4C_SPEED_RATING	6500	 /* TODO new card, new speed rating */
+
+#define CEX4A_MAX_MESSAGE_SIZE	MSGTYPE50_CRB3_MAX_MSG_SIZE
+#define CEX4C_MAX_MESSAGE_SIZE	MSGTYPE06_MAX_MSG_SIZE
+
+#define CEX4_CLEANUP_TIME	(15*HZ)
+
+static struct ap_device_id zcrypt_cex4_ids[] = {
+	{ AP_DEVICE(AP_DEVICE_TYPE_CEX4)  },
+	{ /* end of list */ },
+};
+
+MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
+		   "Copyright IBM Corp. 2012");
+MODULE_LICENSE("GPL");
+
+static int zcrypt_cex4_probe(struct ap_device *ap_dev);
+static void zcrypt_cex4_remove(struct ap_device *ap_dev);
+
+static struct ap_driver zcrypt_cex4_driver = {
+	.probe = zcrypt_cex4_probe,
+	.remove = zcrypt_cex4_remove,
+	.ids = zcrypt_cex4_ids,
+	.request_timeout = CEX4_CLEANUP_TIME,
+};
+
+/**
+ * Probe function for CEX4 cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_cex4_probe(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = NULL;
+	int rc = 0;
+
+	switch (ap_dev->device_type) {
+	case AP_DEVICE_TYPE_CEX4:
+		if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
+			zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
+			if (!zdev)
+				return -ENOMEM;
+			zdev->type_string = "CEX4A";
+			zdev->user_space_type = ZCRYPT_CEX3A;
+			zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
+			if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
+			    ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
+				zdev->max_mod_size =
+					CEX4A_MAX_MOD_SIZE_4K;
+				zdev->max_exp_bit_length =
+					CEX4A_MAX_MOD_SIZE_4K;
+			} else {
+				zdev->max_mod_size =
+					CEX4A_MAX_MOD_SIZE_2K;
+				zdev->max_exp_bit_length =
+					CEX4A_MAX_MOD_SIZE_2K;
+			}
+			zdev->short_crt = 1;
+			zdev->speed_rating = CEX4A_SPEED_RATING;
+			zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
+							   MSGTYPE50_VARIANT_DEFAULT);
+		} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
+			zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
+			if (!zdev)
+				return -ENOMEM;
+			zdev->type_string = "CEX4C";
+			zdev->user_space_type = ZCRYPT_CEX3C;
+			zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
+			zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
+			zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
+			zdev->short_crt = 0;
+			zdev->speed_rating = CEX4C_SPEED_RATING;
+			zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
+							   MSGTYPE06_VARIANT_DEFAULT);
+		}
+		break;
+	}
+	if (!zdev)
+		return -ENODEV;
+	zdev->ap_dev = ap_dev;
+	zdev->online = 1;
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
+	if (rc) {
+		zcrypt_msgtype_release(zdev->ops);
+		ap_dev->private = NULL;
+		zcrypt_device_free(zdev);
+	}
+	return rc;
+}
+
+/**
+ * This is called to remove the extended CEX4 driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_cex4_remove(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = ap_dev->private;
+	struct zcrypt_ops *zops;
+
+	if (zdev) {
+		zops = zdev->ops;
+		zcrypt_device_unregister(zdev);
+		zcrypt_msgtype_release(zops);
+	}
+}
+
+int __init zcrypt_cex4_init(void)
+{
+	return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4");
+}
+
+void __exit zcrypt_cex4_exit(void)
+{
+	ap_driver_unregister(&zcrypt_cex4_driver);
+}
+
+module_init(zcrypt_cex4_init);
+module_exit(zcrypt_cex4_exit);
diff --git a/drivers/s390/crypto/zcrypt_cex4.h b/drivers/s390/crypto/zcrypt_cex4.h
new file mode 100644
index 0000000..7195713
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_cex4.h
@@ -0,0 +1,12 @@
+/*
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Holger Dengler <hd@linux.vnet.ibm.com>
+ */
+
+#ifndef _ZCRYPT_CEX4_H_
+#define _ZCRYPT_CEX4_H_
+
+int zcrypt_cex4_init(void);
+void zcrypt_cex4_exit(void);
+
+#endif /* _ZCRYPT_CEX4_H_ */
diff --git a/drivers/s390/crypto/zcrypt_debug.h b/drivers/s390/crypto/zcrypt_debug.h
new file mode 100644
index 0000000..841ea72
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_debug.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Holger Dengler (hd@linux.vnet.ibm.com)
+ */
+#ifndef ZCRYPT_DEBUG_H
+#define ZCRYPT_DEBUG_H
+
+#include <asm/debug.h>
+#include "zcrypt_api.h"
+
+/* that gives us 15 characters in the text event views */
+#define ZCRYPT_DBF_LEN	16
+
+/* sort out low debug levels early to avoid wasted sprints */
+static inline int zcrypt_dbf_passes(debug_info_t *dbf_grp, int level)
+{
+	return (level <= dbf_grp->level);
+}
+
+#define DBF_ERR		3	/* error conditions	*/
+#define DBF_WARN	4	/* warning conditions	*/
+#define DBF_INFO	6	/* informational	*/
+
+#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
+
+#define ZCRYPT_DBF_COMMON(level, text...) \
+	do { \
+		if (zcrypt_dbf_passes(zcrypt_dbf_common, level)) { \
+			char debug_buffer[ZCRYPT_DBF_LEN]; \
+			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+			debug_text_event(zcrypt_dbf_common, level, \
+					 debug_buffer); \
+		} \
+	} while (0)
+
+#define ZCRYPT_DBF_DEVICES(level, text...) \
+	do { \
+		if (zcrypt_dbf_passes(zcrypt_dbf_devices, level)) { \
+			char debug_buffer[ZCRYPT_DBF_LEN]; \
+			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+			debug_text_event(zcrypt_dbf_devices, level, \
+					 debug_buffer); \
+		} \
+	} while (0)
+
+#define ZCRYPT_DBF_DEV(level, device, text...) \
+	do { \
+		if (zcrypt_dbf_passes(device->dbf_area, level)) { \
+			char debug_buffer[ZCRYPT_DBF_LEN]; \
+			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+			debug_text_event(device->dbf_area, level, \
+					 debug_buffer); \
+		} \
+	} while (0)
+
+int zcrypt_debug_init(void);
+void zcrypt_debug_exit(void);
+
+#endif /* ZCRYPT_DEBUG_H */
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h
index 0965e26..0079b66 100644
--- a/drivers/s390/crypto/zcrypt_error.h
+++ b/drivers/s390/crypto/zcrypt_error.h
@@ -26,6 +26,8 @@
 #ifndef _ZCRYPT_ERROR_H_
 #define _ZCRYPT_ERROR_H_
 
+#include <linux/atomic.h>
+#include "zcrypt_debug.h"
 #include "zcrypt_api.h"
 
 /**
@@ -108,16 +110,27 @@
 		 * and then repeat the request.
 		 */
 		WARN_ON(1);
+		atomic_set(&zcrypt_rescan_req, 1);
 		zdev->online = 0;
+		ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
+			       zdev->ap_dev->qid,
+			       zdev->online, ehdr->reply_code);
 		return -EAGAIN;
 	case REP82_ERROR_TRANSPORT_FAIL:
 	case REP82_ERROR_MACHINE_FAILURE:
 	//   REP88_ERROR_MODULE_FAILURE		// '10' CEX2A
 		/* If a card fails disable it and repeat the request. */
+		atomic_set(&zcrypt_rescan_req, 1);
 		zdev->online = 0;
+		ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
+			       zdev->ap_dev->qid,
+			       zdev->online, ehdr->reply_code);
 		return -EAGAIN;
 	default:
 		zdev->online = 0;
+		ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
+			       zdev->ap_dev->qid,
+			       zdev->online, ehdr->reply_code);
 		return -EAGAIN;	/* repeat the request on a different device. */
 	}
 }
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
new file mode 100644
index 0000000..035b6dc
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -0,0 +1,531 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_msgtype50.h"
+
+#define CEX3A_MAX_MOD_SIZE	512	/* 4096 bits	*/
+
+#define CEX2A_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
+
+#define CEX3A_MAX_RESPONSE_SIZE	0x210	/* 512 bit modulus
+					 * (max outputdatalength) +
+					 * type80_hdr*/
+
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
+		   "Copyright IBM Corp. 2001, 2012");
+MODULE_LICENSE("GPL");
+
+static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+/**
+ * The type 50 message family is associated with a CEX2A card.
+ *
+ * The four members of the family are described below.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type50_hdr {
+	unsigned char	reserved1;
+	unsigned char	msg_type_code;	/* 0x50 */
+	unsigned short	msg_len;
+	unsigned char	reserved2;
+	unsigned char	ignored;
+	unsigned short	reserved3;
+} __packed;
+
+#define TYPE50_TYPE_CODE	0x50
+
+#define TYPE50_MEB1_FMT		0x0001
+#define TYPE50_MEB2_FMT		0x0002
+#define TYPE50_MEB3_FMT		0x0003
+#define TYPE50_CRB1_FMT		0x0011
+#define TYPE50_CRB2_FMT		0x0012
+#define TYPE50_CRB3_FMT		0x0013
+
+/* Mod-Exp, with a small modulus */
+struct type50_meb1_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0001 */
+	unsigned char	reserved[6];
+	unsigned char	exponent[128];
+	unsigned char	modulus[128];
+	unsigned char	message[128];
+} __packed;
+
+/* Mod-Exp, with a large modulus */
+struct type50_meb2_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0002 */
+	unsigned char	reserved[6];
+	unsigned char	exponent[256];
+	unsigned char	modulus[256];
+	unsigned char	message[256];
+} __packed;
+
+/* Mod-Exp, with a larger modulus */
+struct type50_meb3_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0003 */
+	unsigned char	reserved[6];
+	unsigned char	exponent[512];
+	unsigned char	modulus[512];
+	unsigned char	message[512];
+} __packed;
+
+/* CRT, with a small modulus */
+struct type50_crb1_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0011 */
+	unsigned char	reserved[6];
+	unsigned char	p[64];
+	unsigned char	q[64];
+	unsigned char	dp[64];
+	unsigned char	dq[64];
+	unsigned char	u[64];
+	unsigned char	message[128];
+} __packed;
+
+/* CRT, with a large modulus */
+struct type50_crb2_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0012 */
+	unsigned char	reserved[6];
+	unsigned char	p[128];
+	unsigned char	q[128];
+	unsigned char	dp[128];
+	unsigned char	dq[128];
+	unsigned char	u[128];
+	unsigned char	message[256];
+} __packed;
+
+/* CRT, with a larger modulus */
+struct type50_crb3_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0013 */
+	unsigned char	reserved[6];
+	unsigned char	p[256];
+	unsigned char	q[256];
+	unsigned char	dp[256];
+	unsigned char	dq[256];
+	unsigned char	u[256];
+	unsigned char	message[512];
+} __packed;
+
+/**
+ * The type 80 response family is associated with a CEX2A card.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+
+#define TYPE80_RSP_CODE 0x80
+
+struct type80_hdr {
+	unsigned char	reserved1;
+	unsigned char	type;		/* 0x80 */
+	unsigned short	len;
+	unsigned char	code;		/* 0x00 */
+	unsigned char	reserved2[3];
+	unsigned char	reserved3[8];
+} __packed;
+
+/**
+ * Convert a ICAMEX message to a type50 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo *mex)
+{
+	unsigned char *mod, *exp, *inp;
+	int mod_len;
+
+	mod_len = mex->inputdatalength;
+
+	if (mod_len <= 128) {
+		struct type50_meb1_msg *meb1 = ap_msg->message;
+		memset(meb1, 0, sizeof(*meb1));
+		ap_msg->length = sizeof(*meb1);
+		meb1->header.msg_type_code = TYPE50_TYPE_CODE;
+		meb1->header.msg_len = sizeof(*meb1);
+		meb1->keyblock_type = TYPE50_MEB1_FMT;
+		mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
+		exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
+		inp = meb1->message + sizeof(meb1->message) - mod_len;
+	} else if (mod_len <= 256) {
+		struct type50_meb2_msg *meb2 = ap_msg->message;
+		memset(meb2, 0, sizeof(*meb2));
+		ap_msg->length = sizeof(*meb2);
+		meb2->header.msg_type_code = TYPE50_TYPE_CODE;
+		meb2->header.msg_len = sizeof(*meb2);
+		meb2->keyblock_type = TYPE50_MEB2_FMT;
+		mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
+		exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
+		inp = meb2->message + sizeof(meb2->message) - mod_len;
+	} else {
+		/* mod_len > 256 = 4096 bit RSA Key */
+		struct type50_meb3_msg *meb3 = ap_msg->message;
+		memset(meb3, 0, sizeof(*meb3));
+		ap_msg->length = sizeof(*meb3);
+		meb3->header.msg_type_code = TYPE50_TYPE_CODE;
+		meb3->header.msg_len = sizeof(*meb3);
+		meb3->keyblock_type = TYPE50_MEB3_FMT;
+		mod = meb3->modulus + sizeof(meb3->modulus) - mod_len;
+		exp = meb3->exponent + sizeof(meb3->exponent) - mod_len;
+		inp = meb3->message + sizeof(meb3->message) - mod_len;
+	}
+
+	if (copy_from_user(mod, mex->n_modulus, mod_len) ||
+	    copy_from_user(exp, mex->b_key, mod_len) ||
+	    copy_from_user(inp, mex->inputdata, mod_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type50 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo_crt *crt)
+{
+	int mod_len, short_len, long_len, long_offset, limit;
+	unsigned char *p, *q, *dp, *dq, *u, *inp;
+
+	mod_len = crt->inputdatalength;
+	short_len = mod_len / 2;
+	long_len = mod_len / 2 + 8;
+
+	/*
+	 * CEX2A cannot handle p, dp, or U > 128 bytes.
+	 * If we have one of these, we need to do extra checking.
+	 * For CEX3A the limit is 256 bytes.
+	 */
+	if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)
+		limit = 256;
+	else
+		limit = 128;
+
+	if (long_len > limit) {
+		/*
+		 * zcrypt_rsa_crt already checked for the leading
+		 * zeroes of np_prime, bp_key and u_mult_inc.
+		 */
+		long_offset = long_len - limit;
+		long_len = limit;
+	} else
+		long_offset = 0;
+
+	/*
+	 * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use
+	 * the larger message structure.
+	 */
+	if (long_len <= 64) {
+		struct type50_crb1_msg *crb1 = ap_msg->message;
+		memset(crb1, 0, sizeof(*crb1));
+		ap_msg->length = sizeof(*crb1);
+		crb1->header.msg_type_code = TYPE50_TYPE_CODE;
+		crb1->header.msg_len = sizeof(*crb1);
+		crb1->keyblock_type = TYPE50_CRB1_FMT;
+		p = crb1->p + sizeof(crb1->p) - long_len;
+		q = crb1->q + sizeof(crb1->q) - short_len;
+		dp = crb1->dp + sizeof(crb1->dp) - long_len;
+		dq = crb1->dq + sizeof(crb1->dq) - short_len;
+		u = crb1->u + sizeof(crb1->u) - long_len;
+		inp = crb1->message + sizeof(crb1->message) - mod_len;
+	} else if (long_len <= 128) {
+		struct type50_crb2_msg *crb2 = ap_msg->message;
+		memset(crb2, 0, sizeof(*crb2));
+		ap_msg->length = sizeof(*crb2);
+		crb2->header.msg_type_code = TYPE50_TYPE_CODE;
+		crb2->header.msg_len = sizeof(*crb2);
+		crb2->keyblock_type = TYPE50_CRB2_FMT;
+		p = crb2->p + sizeof(crb2->p) - long_len;
+		q = crb2->q + sizeof(crb2->q) - short_len;
+		dp = crb2->dp + sizeof(crb2->dp) - long_len;
+		dq = crb2->dq + sizeof(crb2->dq) - short_len;
+		u = crb2->u + sizeof(crb2->u) - long_len;
+		inp = crb2->message + sizeof(crb2->message) - mod_len;
+	} else {
+		/* long_len >= 256 */
+		struct type50_crb3_msg *crb3 = ap_msg->message;
+		memset(crb3, 0, sizeof(*crb3));
+		ap_msg->length = sizeof(*crb3);
+		crb3->header.msg_type_code = TYPE50_TYPE_CODE;
+		crb3->header.msg_len = sizeof(*crb3);
+		crb3->keyblock_type = TYPE50_CRB3_FMT;
+		p = crb3->p + sizeof(crb3->p) - long_len;
+		q = crb3->q + sizeof(crb3->q) - short_len;
+		dp = crb3->dp + sizeof(crb3->dp) - long_len;
+		dq = crb3->dq + sizeof(crb3->dq) - short_len;
+		u = crb3->u + sizeof(crb3->u) - long_len;
+		inp = crb3->message + sizeof(crb3->message) - mod_len;
+	}
+
+	if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
+	    copy_from_user(q, crt->nq_prime, short_len) ||
+	    copy_from_user(dp, crt->bp_key + long_offset, long_len) ||
+	    copy_from_user(dq, crt->bq_key, short_len) ||
+	    copy_from_user(u, crt->u_mult_inv + long_offset, long_len) ||
+	    copy_from_user(inp, crt->inputdata, mod_len))
+		return -EFAULT;
+
+	return 0;
+}
+
+/**
+ * Copy results from a type 80 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int convert_type80(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
+{
+	struct type80_hdr *t80h = reply->message;
+	unsigned char *data;
+
+	if (t80h->len < sizeof(*t80h) + outputdatalength) {
+		/* The result is too short, the CEX2A card may not do that.. */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	if (zdev->user_space_type == ZCRYPT_CEX2A)
+		BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
+	else
+		BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
+	data = reply->message + t80h->len - outputdatalength;
+	if (copy_to_user(outputdata, data, outputdatalength))
+		return -EFAULT;
+	return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE80_RSP_CODE:
+		return convert_type80(zdev, reply,
+				      outputdata, outputdatalength);
+	default: /* Unknown response type, this should NEVER EVER happen */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
+				 struct ap_message *msg,
+				 struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct type80_hdr *t80h;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply)) {
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+		goto out;
+	}
+	t80h = reply->message;
+	if (t80h->type == TYPE80_RSP_CODE) {
+		if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A)
+			length = min_t(int,
+				       CEX2A_MAX_RESPONSE_SIZE, t80h->len);
+		else
+			length = min_t(int,
+				       CEX3A_MAX_RESPONSE_SIZE, t80h->len);
+		memcpy(msg->message, reply->message, length);
+	} else
+		memcpy(msg->message, reply->message, sizeof(error_reply));
+out:
+	complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  CEX2A device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
+				 struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_init_message(&ap_msg);
+	if (zdev->user_space_type == ZCRYPT_CEX2A)
+		ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
+					 GFP_KERNEL);
+	else
+		ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE,
+					 GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_cex2a_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&work);
+	if (rc == 0)
+		rc = convert_response(zdev, &ap_msg, mex->outputdata,
+				      mex->outputdatalength);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  CEX2A device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
+				     struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_init_message(&ap_msg);
+	if (zdev->user_space_type == ZCRYPT_CEX2A)
+		ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
+					 GFP_KERNEL);
+	else
+		ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE,
+					 GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_cex2a_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&work);
+	if (rc == 0)
+		rc = convert_response(zdev, &ap_msg, crt->outputdata,
+				      crt->outputdatalength);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for message type 50.
+ */
+static struct zcrypt_ops zcrypt_msgtype50_ops = {
+	.rsa_modexpo = zcrypt_cex2a_modexpo,
+	.rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
+	.owner = THIS_MODULE,
+	.variant = MSGTYPE50_VARIANT_DEFAULT,
+};
+
+int __init zcrypt_msgtype50_init(void)
+{
+	zcrypt_msgtype_register(&zcrypt_msgtype50_ops);
+	return 0;
+}
+
+void __exit zcrypt_msgtype50_exit(void)
+{
+	zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops);
+}
+
+module_init(zcrypt_msgtype50_init);
+module_exit(zcrypt_msgtype50_exit);
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h
new file mode 100644
index 0000000..e56dc72
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_msgtype50.h
@@ -0,0 +1,39 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZCRYPT_MSGTYPE50_H_
+#define _ZCRYPT_MSGTYPE50_H_
+
+#define MSGTYPE50_NAME			"zcrypt_msgtype50"
+#define MSGTYPE50_VARIANT_DEFAULT	0
+
+#define MSGTYPE50_CRB2_MAX_MSG_SIZE	0x390 /*sizeof(struct type50_crb2_msg)*/
+#define MSGTYPE50_CRB3_MAX_MSG_SIZE	0x710 /*sizeof(struct type50_crb3_msg)*/
+
+int zcrypt_msgtype50_init(void);
+void zcrypt_msgtype50_exit(void);
+
+#endif /* _ZCRYPT_MSGTYPE50_H_ */
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
new file mode 100644
index 0000000..7d97fa5
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -0,0 +1,856 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_msgtype6.h"
+#include "zcrypt_cca_key.h"
+
+#define PCIXCC_MIN_MOD_SIZE_OLD	 64	/*  512 bits	*/
+#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply	    */
+
+#define CEIL4(x) ((((x)+3)/4)*4)
+
+struct response_type {
+	struct completion work;
+	int type;
+};
+#define PCIXCC_RESPONSE_TYPE_ICA  0
+#define PCIXCC_RESPONSE_TYPE_XCRB 1
+
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
+		   "Copyright IBM Corp. 2001, 2012");
+MODULE_LICENSE("GPL");
+
+static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+/**
+ * CPRB
+ *	  Note that all shorts, ints and longs are little-endian.
+ *	  All pointer fields are 32-bits long, and mean nothing
+ *
+ *	  A request CPRB is followed by a request_parameter_block.
+ *
+ *	  The request (or reply) parameter block is organized thus:
+ *	    function code
+ *	    VUD block
+ *	    key block
+ */
+struct CPRB {
+	unsigned short cprb_len;	/* CPRB length			 */
+	unsigned char cprb_ver_id;	/* CPRB version id.		 */
+	unsigned char pad_000;		/* Alignment pad byte.		 */
+	unsigned char srpi_rtcode[4];	/* SRPI return code LELONG	 */
+	unsigned char srpi_verb;	/* SRPI verb type		 */
+	unsigned char flags;		/* flags			 */
+	unsigned char func_id[2];	/* function id			 */
+	unsigned char checkpoint_flag;	/*				 */
+	unsigned char resv2;		/* reserved			 */
+	unsigned short req_parml;	/* request parameter buffer	 */
+					/* length 16-bit little endian	 */
+	unsigned char req_parmp[4];	/* request parameter buffer	 *
+					 * pointer (means nothing: the	 *
+					 * parameter buffer follows	 *
+					 * the CPRB).			 */
+	unsigned char req_datal[4];	/* request data buffer		 */
+					/* length	  ULELONG	 */
+	unsigned char req_datap[4];	/* request data buffer		 */
+					/* pointer			 */
+	unsigned short rpl_parml;	/* reply  parameter buffer	 */
+					/* length 16-bit little endian	 */
+	unsigned char pad_001[2];	/* Alignment pad bytes. ULESHORT */
+	unsigned char rpl_parmp[4];	/* reply parameter buffer	 *
+					 * pointer (means nothing: the	 *
+					 * parameter buffer follows	 *
+					 * the CPRB).			 */
+	unsigned char rpl_datal[4];	/* reply data buffer len ULELONG */
+	unsigned char rpl_datap[4];	/* reply data buffer		 */
+					/* pointer			 */
+	unsigned short ccp_rscode;	/* server reason code	ULESHORT */
+	unsigned short ccp_rtcode;	/* server return code	ULESHORT */
+	unsigned char repd_parml[2];	/* replied parameter len ULESHORT*/
+	unsigned char mac_data_len[2];	/* Mac Data Length	ULESHORT */
+	unsigned char repd_datal[4];	/* replied data length	ULELONG	 */
+	unsigned char req_pc[2];	/* PC identifier		 */
+	unsigned char res_origin[8];	/* resource origin		 */
+	unsigned char mac_value[8];	/* Mac Value			 */
+	unsigned char logon_id[8];	/* Logon Identifier		 */
+	unsigned char usage_domain[2];	/* cdx				 */
+	unsigned char resv3[18];	/* reserved for requestor	 */
+	unsigned short svr_namel;	/* server name length  ULESHORT	 */
+	unsigned char svr_name[8];	/* server name			 */
+} __packed;
+
+struct function_and_rules_block {
+	unsigned char function_code[2];
+	unsigned short ulen;
+	unsigned char only_rule[8];
+} __packed;
+
+/**
+ * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
+ * card in a type6 message. The 3 fields that must be filled in at execution
+ * time are  req_parml, rpl_parml and usage_domain.
+ * Everything about this interface is ascii/big-endian, since the
+ * device does *not* have 'Intel inside'.
+ *
+ * The CPRBX is followed immediately by the parm block.
+ * The parm block contains:
+ * - function code ('PD' 0x5044 or 'PK' 0x504B)
+ * - rule block (one of:)
+ *   + 0x000A 'PKCS-1.2' (MCL2 'PD')
+ *   + 0x000A 'ZERO-PAD' (MCL2 'PK')
+ *   + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
+ *   + 0x000A 'MRP     ' (MCL3 'PK' or CEX2C 'PK')
+ * - VUD block
+ */
+static struct CPRBX static_cprbx = {
+	.cprb_len	=  0x00DC,
+	.cprb_ver_id	=  0x02,
+	.func_id	= {0x54, 0x32},
+};
+
+/**
+ * Convert a ICAMEX message to a type6 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo *mex)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {'C', 'A',},
+		.function_code	= {'P', 'K'},
+	};
+	static struct function_and_rules_block static_pke_fnr = {
+		.function_code	= {'P', 'K'},
+		.ulen		= 10,
+		.only_rule	= {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '}
+	};
+	static struct function_and_rules_block static_pke_fnr_MCL2 = {
+		.function_code	= {'P', 'K'},
+		.ulen		= 10,
+		.only_rule	= {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __packed * msg = ap_msg->message;
+	int size;
+
+	/* VUD.ciphertext */
+	msg->length = mex->inputdatalength + 2;
+	if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
+		return -EFAULT;
+
+	/* Set up key which is located after the variable length text. */
+	size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
+	if (size < 0)
+		return size;
+	size += sizeof(*msg) + mex->inputdatalength;
+
+	/* message header, cprbx and f&r */
+	msg->hdr = static_type6_hdrX;
+	msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
+	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprbx = static_cprbx;
+	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
+
+	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+		static_pke_fnr_MCL2 : static_pke_fnr;
+
+	msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+	ap_msg->length = size;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type6 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo_crt *crt)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {'C', 'A',},
+		.function_code	= {'P', 'D'},
+	};
+	static struct function_and_rules_block static_pkd_fnr = {
+		.function_code	= {'P', 'D'},
+		.ulen		= 10,
+		.only_rule	= {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
+	};
+
+	static struct function_and_rules_block static_pkd_fnr_MCL2 = {
+		.function_code	= {'P', 'D'},
+		.ulen		= 10,
+		.only_rule	= {'P', 'K', 'C', 'S', '-', '1', '.', '2'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __packed * msg = ap_msg->message;
+	int size;
+
+	/* VUD.ciphertext */
+	msg->length = crt->inputdatalength + 2;
+	if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
+		return -EFAULT;
+
+	/* Set up key which is located after the variable length text. */
+	size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
+	if (size < 0)
+		return size;
+	size += sizeof(*msg) + crt->inputdatalength;	/* total size of msg */
+
+	/* message header, cprbx and f&r */
+	msg->hdr = static_type6_hdrX;
+	msg->hdr.ToCardLen1 = size -  sizeof(msg->hdr);
+	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprbx = static_cprbx;
+	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
+		size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+		static_pkd_fnr_MCL2 : static_pkd_fnr;
+
+	ap_msg->length = size;
+	return 0;
+}
+
+/**
+ * Convert a XCRB message to a type6 CPRB message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @xcRB: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT, -EINVAL.
+ */
+struct type86_fmt2_msg {
+	struct type86_hdr hdr;
+	struct type86_fmt2_ext fmt2;
+} __packed;
+
+static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_xcRB *xcRB)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+	} __packed * msg = ap_msg->message;
+
+	int rcblen = CEIL4(xcRB->request_control_blk_length);
+	int replylen;
+	char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
+	char *function_code;
+
+	/* length checks */
+	ap_msg->length = sizeof(struct type6_hdr) +
+		CEIL4(xcRB->request_control_blk_length) +
+		xcRB->request_data_length;
+	if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
+		return -EINVAL;
+	replylen = sizeof(struct type86_fmt2_msg) +
+		CEIL4(xcRB->reply_control_blk_length) +
+		xcRB->reply_data_length;
+	if (replylen > MSGTYPE06_MAX_MSG_SIZE)
+		return -EINVAL;
+
+	/* prepare type6 header */
+	msg->hdr = static_type6_hdrX;
+	memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
+	msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
+	if (xcRB->request_data_length) {
+		msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
+		msg->hdr.ToCardLen2 = xcRB->request_data_length;
+	}
+	msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
+	msg->hdr.FromCardLen2 = xcRB->reply_data_length;
+
+	/* prepare CPRB */
+	if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
+		    xcRB->request_control_blk_length))
+		return -EFAULT;
+	if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
+	    xcRB->request_control_blk_length)
+		return -EINVAL;
+	function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
+	memcpy(msg->hdr.function_code, function_code,
+	       sizeof(msg->hdr.function_code));
+
+	if (memcmp(function_code, "US", 2) == 0)
+		ap_msg->special = 1;
+	else
+		ap_msg->special = 0;
+
+	/* copy data block */
+	if (xcRB->request_data_length &&
+	    copy_from_user(req_data, xcRB->request_data_address,
+		xcRB->request_data_length))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Copy results from a type 86 ICA reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+struct type86x_reply {
+	struct type86_hdr hdr;
+	struct type86_fmt2_ext fmt2;
+	struct CPRBX cprbx;
+	unsigned char pad[4];	/* 4 byte function code/rules block ? */
+	unsigned short length;
+	char text[0];
+} __packed;
+
+static int convert_type86_ica(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
+{
+	static unsigned char static_pad[] = {
+		0x00, 0x02,
+		0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD,
+		0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57,
+		0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B,
+		0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39,
+		0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5,
+		0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D,
+		0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB,
+		0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F,
+		0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9,
+		0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45,
+		0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9,
+		0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F,
+		0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD,
+		0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D,
+		0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD,
+		0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9,
+		0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B,
+		0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B,
+		0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B,
+		0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD,
+		0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7,
+		0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1,
+		0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3,
+		0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23,
+		0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55,
+		0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43,
+		0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F,
+		0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F,
+		0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5,
+		0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD,
+		0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41,
+		0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09
+	};
+	struct type86x_reply *msg = reply->message;
+	unsigned short service_rc, service_rs;
+	unsigned int reply_len, pad_len;
+	char *data;
+
+	service_rc = msg->cprbx.ccp_rtcode;
+	if (unlikely(service_rc != 0)) {
+		service_rs = msg->cprbx.ccp_rscode;
+		if (service_rc == 8 && service_rs == 66)
+			return -EINVAL;
+		if (service_rc == 8 && service_rs == 65)
+			return -EINVAL;
+		if (service_rc == 8 && service_rs == 770)
+			return -EINVAL;
+		if (service_rc == 8 && service_rs == 783) {
+			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+			return -EAGAIN;
+		}
+		if (service_rc == 12 && service_rs == 769)
+			return -EINVAL;
+		if (service_rc == 8 && service_rs == 72)
+			return -EINVAL;
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	data = msg->text;
+	reply_len = msg->length - 2;
+	if (reply_len > outputdatalength)
+		return -EINVAL;
+	/*
+	 * For all encipher requests, the length of the ciphertext (reply_len)
+	 * will always equal the modulus length. For MEX decipher requests
+	 * the output needs to get padded. Minimum pad size is 10.
+	 *
+	 * Currently, the cases where padding will be added is for:
+	 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
+	 *   ZERO-PAD and CRT is only supported for PKD requests)
+	 * - PCICC, always
+	 */
+	pad_len = outputdatalength - reply_len;
+	if (pad_len > 0) {
+		if (pad_len < 10)
+			return -EINVAL;
+		/* 'restore' padding left in the PCICC/PCIXCC card. */
+		if (copy_to_user(outputdata, static_pad, pad_len - 1))
+			return -EFAULT;
+		if (put_user(0, outputdata + pad_len - 1))
+			return -EFAULT;
+	}
+	/* Copy the crypto response to user space. */
+	if (copy_to_user(outputdata + pad_len, data, reply_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Copy results from a type 86 XCRB reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @xcRB: pointer to XCRB
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+static int convert_type86_xcrb(struct zcrypt_device *zdev,
+			       struct ap_message *reply,
+			       struct ica_xcRB *xcRB)
+{
+	struct type86_fmt2_msg *msg = reply->message;
+	char *data = reply->message;
+
+	/* Copy CPRB to user */
+	if (copy_to_user(xcRB->reply_control_blk_addr,
+		data + msg->fmt2.offset1, msg->fmt2.count1))
+		return -EFAULT;
+	xcRB->reply_control_blk_length = msg->fmt2.count1;
+
+	/* Copy data buffer to user */
+	if (msg->fmt2.count2)
+		if (copy_to_user(xcRB->reply_data_addr,
+			data + msg->fmt2.offset2, msg->fmt2.count2))
+			return -EFAULT;
+	xcRB->reply_data_length = msg->fmt2.count2;
+	return 0;
+}
+
+static int convert_type86_rng(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char *buffer)
+{
+	struct {
+		struct type86_hdr hdr;
+		struct type86_fmt2_ext fmt2;
+		struct CPRBX cprbx;
+	} __packed * msg = reply->message;
+	char *data = reply->message;
+
+	if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
+		return -EINVAL;
+	memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
+	return msg->fmt2.count2;
+}
+
+static int convert_response_ica(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	struct type86x_reply *msg = reply->message;
+
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE86_RSP_CODE:
+		if (msg->cprbx.ccp_rtcode &&
+		   (msg->cprbx.ccp_rscode == 0x14f) &&
+		   (outputdatalength > 256)) {
+			if (zdev->max_exp_bit_length <= 17) {
+				zdev->max_exp_bit_length = 17;
+				return -EAGAIN;
+			} else
+				return -EINVAL;
+		}
+		if (msg->hdr.reply_code)
+			return convert_error(zdev, reply);
+		if (msg->cprbx.cprb_ver_id == 0x02)
+			return convert_type86_ica(zdev, reply,
+						  outputdata, outputdatalength);
+		/* Fall through, no break, incorrect cprb version is an unknown
+		 * response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+static int convert_response_xcrb(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    struct ica_xcRB *xcRB)
+{
+	struct type86x_reply *msg = reply->message;
+
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+		return convert_error(zdev, reply);
+	case TYPE86_RSP_CODE:
+		if (msg->hdr.reply_code) {
+			memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
+			return convert_error(zdev, reply);
+		}
+		if (msg->cprbx.cprb_ver_id == 0x02)
+			return convert_type86_xcrb(zdev, reply, xcRB);
+		/* Fall through, no break, incorrect cprb version is an unknown
+		 * response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+static int convert_response_rng(struct zcrypt_device *zdev,
+				 struct ap_message *reply,
+				 char *data)
+{
+	struct type86x_reply *msg = reply->message;
+
+	switch (msg->hdr.type) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return -EINVAL;
+	case TYPE86_RSP_CODE:
+		if (msg->hdr.reply_code)
+			return -EINVAL;
+		if (msg->cprbx.cprb_ver_id == 0x02)
+			return convert_type86_rng(zdev, reply, data);
+		/* Fall through, no break, incorrect cprb version is an unknown
+		 * response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_msgtype6_receive(struct ap_device *ap_dev,
+				  struct ap_message *msg,
+				  struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct response_type *resp_type =
+		(struct response_type *) msg->private;
+	struct type86x_reply *t86r;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply)) {
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+		goto out;
+	}
+	t86r = reply->message;
+	if (t86r->hdr.type == TYPE86_RSP_CODE &&
+		 t86r->cprbx.cprb_ver_id == 0x02) {
+		switch (resp_type->type) {
+		case PCIXCC_RESPONSE_TYPE_ICA:
+			length = sizeof(struct type86x_reply)
+				+ t86r->length - 2;
+			length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
+			memcpy(msg->message, reply->message, length);
+			break;
+		case PCIXCC_RESPONSE_TYPE_XCRB:
+			length = t86r->fmt2.offset2 + t86r->fmt2.count2;
+			length = min(MSGTYPE06_MAX_MSG_SIZE, length);
+			memcpy(msg->message, reply->message, length);
+			break;
+		default:
+			memcpy(msg->message, &error_reply,
+			       sizeof(error_reply));
+		}
+	} else
+		memcpy(msg->message, reply->message, sizeof(error_reply));
+out:
+	complete(&(resp_type->work));
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
+				  struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_ICA,
+	};
+	int rc;
+
+	ap_init_message(&ap_msg);
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_msgtype6_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&resp_type.work);
+	if (rc == 0)
+		rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
+					  mex->outputdatalength);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
+				      struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_ICA,
+	};
+	int rc;
+
+	ap_init_message(&ap_msg);
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_msgtype6_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&resp_type.work);
+	if (rc == 0)
+		rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
+					  crt->outputdatalength);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a send_cprb request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @xcRB: pointer to the send_cprb request buffer
+ */
+static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
+				    struct ica_xcRB *xcRB)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_XCRB,
+	};
+	int rc;
+
+	ap_init_message(&ap_msg);
+	ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_msgtype6_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&resp_type.work);
+	if (rc == 0)
+		rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+out_free:
+	kzfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to generate random data.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @buffer: pointer to a memory page to return random data
+ */
+
+static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
+				    char *buffer)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_XCRB,
+	};
+	int rc;
+
+	ap_init_message(&ap_msg);
+	ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.receive = zcrypt_msgtype6_receive;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible(&resp_type.work);
+	if (rc == 0)
+		rc = convert_response_rng(zdev, &ap_msg, buffer);
+	else
+		/* Signal pending. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for a PCIXCC/CEX2C card.
+ */
+static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
+	.owner = THIS_MODULE,
+	.variant = MSGTYPE06_VARIANT_NORNG,
+	.rsa_modexpo = zcrypt_msgtype6_modexpo,
+	.rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
+	.send_cprb = zcrypt_msgtype6_send_cprb,
+};
+
+static struct zcrypt_ops zcrypt_msgtype6_ops = {
+	.owner = THIS_MODULE,
+	.variant = MSGTYPE06_VARIANT_DEFAULT,
+	.rsa_modexpo = zcrypt_msgtype6_modexpo,
+	.rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
+	.send_cprb = zcrypt_msgtype6_send_cprb,
+	.rng = zcrypt_msgtype6_rng,
+};
+
+int __init zcrypt_msgtype6_init(void)
+{
+	zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops);
+	zcrypt_msgtype_register(&zcrypt_msgtype6_ops);
+	return 0;
+}
+
+void __exit zcrypt_msgtype6_exit(void)
+{
+	zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops);
+	zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops);
+}
+
+module_init(zcrypt_msgtype6_init);
+module_exit(zcrypt_msgtype6_exit);
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
new file mode 100644
index 0000000..1e500d3
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -0,0 +1,169 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZCRYPT_MSGTYPE6_H_
+#define _ZCRYPT_MSGTYPE6_H_
+
+#include <asm/zcrypt.h>
+
+#define MSGTYPE06_NAME			"zcrypt_msgtype6"
+#define MSGTYPE06_VARIANT_DEFAULT	0
+#define MSGTYPE06_VARIANT_NORNG		1
+
+#define MSGTYPE06_MAX_MSG_SIZE		(12*1024)
+
+/**
+ * The type 6 message family is associated with PCICC or PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB, both of which
+ * are described below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type6_hdr {
+	unsigned char reserved1;	/* 0x00				*/
+	unsigned char type;		/* 0x06				*/
+	unsigned char reserved2[2];	/* 0x0000			*/
+	unsigned char right[4];		/* 0x00000000			*/
+	unsigned char reserved3[2];	/* 0x0000			*/
+	unsigned char reserved4[2];	/* 0x0000			*/
+	unsigned char apfs[4];		/* 0x00000000			*/
+	unsigned int  offset1;		/* 0x00000058 (offset to CPRB)	*/
+	unsigned int  offset2;		/* 0x00000000			*/
+	unsigned int  offset3;		/* 0x00000000			*/
+	unsigned int  offset4;		/* 0x00000000			*/
+	unsigned char agent_id[16];	/* PCICC:			*/
+					/*    0x0100			*/
+					/*    0x4343412d4150504c202020	*/
+					/*    0x010101			*/
+					/* PCIXCC:			*/
+					/*    0x4341000000000000	*/
+					/*    0x0000000000000000	*/
+	unsigned char rqid[2];		/* rqid.  internal to 603	*/
+	unsigned char reserved5[2];	/* 0x0000			*/
+	unsigned char function_code[2];	/* for PKD, 0x5044 (ascii 'PD')	*/
+	unsigned char reserved6[2];	/* 0x0000			*/
+	unsigned int  ToCardLen1;	/* (request CPRB len + 3) & -4	*/
+	unsigned int  ToCardLen2;	/* db len 0x00000000 for PKD	*/
+	unsigned int  ToCardLen3;	/* 0x00000000			*/
+	unsigned int  ToCardLen4;	/* 0x00000000			*/
+	unsigned int  FromCardLen1;	/* response buffer length	*/
+	unsigned int  FromCardLen2;	/* db len 0x00000000 for PKD	*/
+	unsigned int  FromCardLen3;	/* 0x00000000			*/
+	unsigned int  FromCardLen4;	/* 0x00000000			*/
+} __packed;
+
+/**
+ * The type 86 message family is associated with PCICC and PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB.  The CPRB is
+ * the same as the request CPRB, which is described above.
+ *
+ * If format is 1, an error condition exists and no data beyond
+ * the 8-byte message header is of interest.
+ *
+ * The non-error message is shown below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type86_hdr {
+	unsigned char reserved1;	/* 0x00				*/
+	unsigned char type;		/* 0x86				*/
+	unsigned char format;		/* 0x01 (error) or 0x02 (ok)	*/
+	unsigned char reserved2;	/* 0x00				*/
+	unsigned char reply_code;	/* reply code (see above)	*/
+	unsigned char reserved3[3];	/* 0x000000			*/
+} __packed;
+
+#define TYPE86_RSP_CODE 0x86
+#define TYPE86_FMT2	0x02
+
+struct type86_fmt2_ext {
+	unsigned char	  reserved[4];	/* 0x00000000			*/
+	unsigned char	  apfs[4];	/* final status			*/
+	unsigned int	  count1;	/* length of CPRB + parameters	*/
+	unsigned int	  offset1;	/* offset to CPRB		*/
+	unsigned int	  count2;	/* 0x00000000			*/
+	unsigned int	  offset2;	/* db offset 0x00000000 for PKD	*/
+	unsigned int	  count3;	/* 0x00000000			*/
+	unsigned int	  offset3;	/* 0x00000000			*/
+	unsigned int	  count4;	/* 0x00000000			*/
+	unsigned int	  offset4;	/* 0x00000000			*/
+} __packed;
+
+/**
+ * Prepare a type6 CPRB message for random number generation
+ *
+ * @ap_dev: AP device pointer
+ * @ap_msg: pointer to AP message
+ */
+static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev,
+			       struct ap_message *ap_msg,
+			       unsigned random_number_length)
+{
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+		char function_code[2];
+		short int rule_length;
+		char rule[8];
+		short int verb_length;
+		short int key_length;
+	} __packed * msg = ap_msg->message;
+	static struct type6_hdr static_type6_hdrX = {
+		.type		= 0x06,
+		.offset1	= 0x00000058,
+		.agent_id	= {'C', 'A'},
+		.function_code	= {'R', 'L'},
+		.ToCardLen1	= sizeof(*msg) - sizeof(msg->hdr),
+		.FromCardLen1	= sizeof(*msg) - sizeof(msg->hdr),
+	};
+	static struct CPRBX local_cprbx = {
+		.cprb_len	= 0x00dc,
+		.cprb_ver_id	= 0x02,
+		.func_id	= {0x54, 0x32},
+		.req_parml	= sizeof(*msg) - sizeof(msg->hdr) -
+				  sizeof(msg->cprbx),
+		.rpl_msgbl	= sizeof(*msg) - sizeof(msg->hdr),
+	};
+
+	msg->hdr = static_type6_hdrX;
+	msg->hdr.FromCardLen2 = random_number_length,
+	msg->cprbx = local_cprbx;
+	msg->cprbx.rpl_datal = random_number_length,
+	msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
+	memcpy(msg->function_code, msg->hdr.function_code, 0x02);
+	msg->rule_length = 0x0a;
+	memcpy(msg->rule, "RANDOM  ", 8);
+	msg->verb_length = 0x02;
+	msg->key_length = 0x02;
+	ap_msg->length = sizeof(*msg);
+}
+
+int zcrypt_msgtype6_init(void);
+void zcrypt_msgtype6_exit(void);
+
+#endif /* _ZCRYPT_MSGTYPE6_H_ */
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index ccb4f8b6..c7275e3 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -1,13 +1,14 @@
 /*
  *  zcrypt 2.1.0
  *
- *  Copyright IBM Corp. 2001, 2006
+ *  Copyright IBM Corp. 2001, 2012
  *  Author(s): Robert Burroughs
  *	       Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
  *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,9 +36,10 @@
 #include "ap_bus.h"
 #include "zcrypt_api.h"
 #include "zcrypt_error.h"
-#include "zcrypt_pcicc.h"
+#include "zcrypt_msgtype6.h"
 #include "zcrypt_pcixcc.h"
 #include "zcrypt_cca_key.h"
+#include "zcrypt_msgtype6.h"
 
 #define PCIXCC_MIN_MOD_SIZE	 16	/*  128 bits	*/
 #define PCIXCC_MIN_MOD_SIZE_OLD	 64	/*  512 bits	*/
@@ -75,14 +77,12 @@
 
 MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
 MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
-		   "Copyright IBM Corp. 2001, 2006");
+MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
+		   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
 static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
 static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
-static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
-				 struct ap_message *);
 
 static struct ap_driver zcrypt_pcixcc_driver = {
 	.probe = zcrypt_pcixcc_probe,
@@ -92,766 +92,6 @@
 };
 
 /**
- * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
- * card in a type6 message. The 3 fields that must be filled in at execution
- * time are  req_parml, rpl_parml and usage_domain.
- * Everything about this interface is ascii/big-endian, since the
- * device does *not* have 'Intel inside'.
- *
- * The CPRBX is followed immediately by the parm block.
- * The parm block contains:
- * - function code ('PD' 0x5044 or 'PK' 0x504B)
- * - rule block (one of:)
- *   + 0x000A 'PKCS-1.2' (MCL2 'PD')
- *   + 0x000A 'ZERO-PAD' (MCL2 'PK')
- *   + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
- *   + 0x000A 'MRP     ' (MCL3 'PK' or CEX2C 'PK')
- * - VUD block
- */
-static struct CPRBX static_cprbx = {
-	.cprb_len	=  0x00DC,
-	.cprb_ver_id	=  0x02,
-	.func_id	= {0x54,0x32},
-};
-
-/**
- * Convert a ICAMEX message to a type6 MEX message.
- *
- * @zdev: crypto device pointer
- * @ap_msg: pointer to AP message
- * @mex: pointer to user input data
- *
- * Returns 0 on success or -EFAULT.
- */
-static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
-				       struct ap_message *ap_msg,
-				       struct ica_rsa_modexpo *mex)
-{
-	static struct type6_hdr static_type6_hdrX = {
-		.type		=  0x06,
-		.offset1	=  0x00000058,
-		.agent_id	= {'C','A',},
-		.function_code	= {'P','K'},
-	};
-	static struct function_and_rules_block static_pke_fnr = {
-		.function_code	= {'P','K'},
-		.ulen		= 10,
-		.only_rule	= {'M','R','P',' ',' ',' ',' ',' '}
-	};
-	static struct function_and_rules_block static_pke_fnr_MCL2 = {
-		.function_code	= {'P','K'},
-		.ulen		= 10,
-		.only_rule	= {'Z','E','R','O','-','P','A','D'}
-	};
-	struct {
-		struct type6_hdr hdr;
-		struct CPRBX cprbx;
-		struct function_and_rules_block fr;
-		unsigned short length;
-		char text[0];
-	} __attribute__((packed)) *msg = ap_msg->message;
-	int size;
-
-	/* VUD.ciphertext */
-	msg->length = mex->inputdatalength + 2;
-	if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
-		return -EFAULT;
-
-	/* Set up key which is located after the variable length text. */
-	size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
-	if (size < 0)
-		return size;
-	size += sizeof(*msg) + mex->inputdatalength;
-
-	/* message header, cprbx and f&r */
-	msg->hdr = static_type6_hdrX;
-	msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
-	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
-
-	msg->cprbx = static_cprbx;
-	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
-	msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
-
-	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
-		static_pke_fnr_MCL2 : static_pke_fnr;
-
-	msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
-
-	ap_msg->length = size;
-	return 0;
-}
-
-/**
- * Convert a ICACRT message to a type6 CRT message.
- *
- * @zdev: crypto device pointer
- * @ap_msg: pointer to AP message
- * @crt: pointer to user input data
- *
- * Returns 0 on success or -EFAULT.
- */
-static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
-				       struct ap_message *ap_msg,
-				       struct ica_rsa_modexpo_crt *crt)
-{
-	static struct type6_hdr static_type6_hdrX = {
-		.type		=  0x06,
-		.offset1	=  0x00000058,
-		.agent_id	= {'C','A',},
-		.function_code	= {'P','D'},
-	};
-	static struct function_and_rules_block static_pkd_fnr = {
-		.function_code	= {'P','D'},
-		.ulen		= 10,
-		.only_rule	= {'Z','E','R','O','-','P','A','D'}
-	};
-
-	static struct function_and_rules_block static_pkd_fnr_MCL2 = {
-		.function_code	= {'P','D'},
-		.ulen		= 10,
-		.only_rule	= {'P','K','C','S','-','1','.','2'}
-	};
-	struct {
-		struct type6_hdr hdr;
-		struct CPRBX cprbx;
-		struct function_and_rules_block fr;
-		unsigned short length;
-		char text[0];
-	} __attribute__((packed)) *msg = ap_msg->message;
-	int size;
-
-	/* VUD.ciphertext */
-	msg->length = crt->inputdatalength + 2;
-	if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
-		return -EFAULT;
-
-	/* Set up key which is located after the variable length text. */
-	size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
-	if (size < 0)
-		return size;
-	size += sizeof(*msg) + crt->inputdatalength;	/* total size of msg */
-
-	/* message header, cprbx and f&r */
-	msg->hdr = static_type6_hdrX;
-	msg->hdr.ToCardLen1 = size -  sizeof(msg->hdr);
-	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
-
-	msg->cprbx = static_cprbx;
-	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
-	msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
-		size - sizeof(msg->hdr) - sizeof(msg->cprbx);
-
-	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
-		static_pkd_fnr_MCL2 : static_pkd_fnr;
-
-	ap_msg->length = size;
-	return 0;
-}
-
-/**
- * Convert a XCRB message to a type6 CPRB message.
- *
- * @zdev: crypto device pointer
- * @ap_msg: pointer to AP message
- * @xcRB: pointer to user input data
- *
- * Returns 0 on success or -EFAULT, -EINVAL.
- */
-struct type86_fmt2_msg {
-	struct type86_hdr hdr;
-	struct type86_fmt2_ext fmt2;
-} __attribute__((packed));
-
-static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
-				       struct ap_message *ap_msg,
-				       struct ica_xcRB *xcRB)
-{
-	static struct type6_hdr static_type6_hdrX = {
-		.type		=  0x06,
-		.offset1	=  0x00000058,
-	};
-	struct {
-		struct type6_hdr hdr;
-		struct CPRBX cprbx;
-	} __attribute__((packed)) *msg = ap_msg->message;
-
-	int rcblen = CEIL4(xcRB->request_control_blk_length);
-	int replylen;
-	char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
-	char *function_code;
-
-	/* length checks */
-	ap_msg->length = sizeof(struct type6_hdr) +
-		CEIL4(xcRB->request_control_blk_length) +
-		xcRB->request_data_length;
-	if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
-		return -EINVAL;
-	replylen = sizeof(struct type86_fmt2_msg) +
-		CEIL4(xcRB->reply_control_blk_length) +
-		xcRB->reply_data_length;
-	if (replylen > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
-		return -EINVAL;
-
-	/* prepare type6 header */
-	msg->hdr = static_type6_hdrX;
-	memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
-	msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
-	if (xcRB->request_data_length) {
-		msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
-		msg->hdr.ToCardLen2 = xcRB->request_data_length;
-	}
-	msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
-	msg->hdr.FromCardLen2 = xcRB->reply_data_length;
-
-	/* prepare CPRB */
-	if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
-		    xcRB->request_control_blk_length))
-		return -EFAULT;
-	if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
-	    xcRB->request_control_blk_length)
-		return -EINVAL;
-	function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
-	memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
-
-	if (memcmp(function_code, "US", 2) == 0)
-		ap_msg->special = 1;
-	else
-		ap_msg->special = 0;
-
-	/* copy data block */
-	if (xcRB->request_data_length &&
-	    copy_from_user(req_data, xcRB->request_data_address,
-		xcRB->request_data_length))
-		return -EFAULT;
-	return 0;
-}
-
-/**
- * Prepare a type6 CPRB message for random number generation
- *
- * @ap_dev: AP device pointer
- * @ap_msg: pointer to AP message
- */
-static void rng_type6CPRB_msgX(struct ap_device *ap_dev,
-			       struct ap_message *ap_msg,
-			       unsigned random_number_length)
-{
-	struct {
-		struct type6_hdr hdr;
-		struct CPRBX cprbx;
-		char function_code[2];
-		short int rule_length;
-		char rule[8];
-		short int verb_length;
-		short int key_length;
-	} __attribute__((packed)) *msg = ap_msg->message;
-	static struct type6_hdr static_type6_hdrX = {
-		.type		= 0x06,
-		.offset1	= 0x00000058,
-		.agent_id	= {'C', 'A'},
-		.function_code	= {'R', 'L'},
-		.ToCardLen1	= sizeof *msg - sizeof(msg->hdr),
-		.FromCardLen1	= sizeof *msg - sizeof(msg->hdr),
-	};
-	static struct CPRBX local_cprbx = {
-		.cprb_len	= 0x00dc,
-		.cprb_ver_id	= 0x02,
-		.func_id	= {0x54, 0x32},
-		.req_parml	= sizeof *msg - sizeof(msg->hdr) -
-				  sizeof(msg->cprbx),
-		.rpl_msgbl	= sizeof *msg - sizeof(msg->hdr),
-	};
-
-	msg->hdr = static_type6_hdrX;
-	msg->hdr.FromCardLen2 = random_number_length,
-	msg->cprbx = local_cprbx;
-	msg->cprbx.rpl_datal = random_number_length,
-	msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
-	memcpy(msg->function_code, msg->hdr.function_code, 0x02);
-	msg->rule_length = 0x0a;
-	memcpy(msg->rule, "RANDOM  ", 8);
-	msg->verb_length = 0x02;
-	msg->key_length = 0x02;
-	ap_msg->length = sizeof *msg;
-}
-
-/**
- * Copy results from a type 86 ICA reply message back to user space.
- *
- * @zdev: crypto device pointer
- * @reply: reply AP message.
- * @data: pointer to user output data
- * @length: size of user output data
- *
- * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
- */
-struct type86x_reply {
-	struct type86_hdr hdr;
-	struct type86_fmt2_ext fmt2;
-	struct CPRBX cprbx;
-	unsigned char pad[4];	/* 4 byte function code/rules block ? */
-	unsigned short length;
-	char text[0];
-} __attribute__((packed));
-
-static int convert_type86_ica(struct zcrypt_device *zdev,
-			  struct ap_message *reply,
-			  char __user *outputdata,
-			  unsigned int outputdatalength)
-{
-	static unsigned char static_pad[] = {
-		0x00,0x02,
-		0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
-		0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
-		0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
-		0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
-		0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
-		0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
-		0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
-		0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
-		0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
-		0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
-		0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
-		0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
-		0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
-		0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
-		0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
-		0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
-		0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
-		0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
-		0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
-		0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
-		0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
-		0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
-		0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
-		0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
-		0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
-		0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
-		0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
-		0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
-		0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
-		0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
-		0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
-		0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
-	};
-	struct type86x_reply *msg = reply->message;
-	unsigned short service_rc, service_rs;
-	unsigned int reply_len, pad_len;
-	char *data;
-
-	service_rc = msg->cprbx.ccp_rtcode;
-	if (unlikely(service_rc != 0)) {
-		service_rs = msg->cprbx.ccp_rscode;
-		if (service_rc == 8 && service_rs == 66)
-			return -EINVAL;
-		if (service_rc == 8 && service_rs == 65)
-			return -EINVAL;
-		if (service_rc == 8 && service_rs == 770)
-			return -EINVAL;
-		if (service_rc == 8 && service_rs == 783) {
-			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
-			return -EAGAIN;
-		}
-		if (service_rc == 12 && service_rs == 769)
-			return -EINVAL;
-		if (service_rc == 8 && service_rs == 72)
-			return -EINVAL;
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-	data = msg->text;
-	reply_len = msg->length - 2;
-	if (reply_len > outputdatalength)
-		return -EINVAL;
-	/*
-	 * For all encipher requests, the length of the ciphertext (reply_len)
-	 * will always equal the modulus length. For MEX decipher requests
-	 * the output needs to get padded. Minimum pad size is 10.
-	 *
-	 * Currently, the cases where padding will be added is for:
-	 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
-	 *   ZERO-PAD and CRT is only supported for PKD requests)
-	 * - PCICC, always
-	 */
-	pad_len = outputdatalength - reply_len;
-	if (pad_len > 0) {
-		if (pad_len < 10)
-			return -EINVAL;
-		/* 'restore' padding left in the PCICC/PCIXCC card. */
-		if (copy_to_user(outputdata, static_pad, pad_len - 1))
-			return -EFAULT;
-		if (put_user(0, outputdata + pad_len - 1))
-			return -EFAULT;
-	}
-	/* Copy the crypto response to user space. */
-	if (copy_to_user(outputdata + pad_len, data, reply_len))
-		return -EFAULT;
-	return 0;
-}
-
-/**
- * Copy results from a type 86 XCRB reply message back to user space.
- *
- * @zdev: crypto device pointer
- * @reply: reply AP message.
- * @xcRB: pointer to XCRB
- *
- * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
- */
-static int convert_type86_xcrb(struct zcrypt_device *zdev,
-			       struct ap_message *reply,
-			       struct ica_xcRB *xcRB)
-{
-	struct type86_fmt2_msg *msg = reply->message;
-	char *data = reply->message;
-
-	/* Copy CPRB to user */
-	if (copy_to_user(xcRB->reply_control_blk_addr,
-		data + msg->fmt2.offset1, msg->fmt2.count1))
-		return -EFAULT;
-	xcRB->reply_control_blk_length = msg->fmt2.count1;
-
-	/* Copy data buffer to user */
-	if (msg->fmt2.count2)
-		if (copy_to_user(xcRB->reply_data_addr,
-			data + msg->fmt2.offset2, msg->fmt2.count2))
-			return -EFAULT;
-	xcRB->reply_data_length = msg->fmt2.count2;
-	return 0;
-}
-
-static int convert_type86_rng(struct zcrypt_device *zdev,
-			  struct ap_message *reply,
-			  char *buffer)
-{
-	struct {
-		struct type86_hdr hdr;
-		struct type86_fmt2_ext fmt2;
-		struct CPRBX cprbx;
-	} __attribute__((packed)) *msg = reply->message;
-	char *data = reply->message;
-
-	if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
-		return -EINVAL;
-	memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
-	return msg->fmt2.count2;
-}
-
-static int convert_response_ica(struct zcrypt_device *zdev,
-			    struct ap_message *reply,
-			    char __user *outputdata,
-			    unsigned int outputdatalength)
-{
-	struct type86x_reply *msg = reply->message;
-
-	/* Response type byte is the second byte in the response. */
-	switch (((unsigned char *) reply->message)[1]) {
-	case TYPE82_RSP_CODE:
-	case TYPE88_RSP_CODE:
-		return convert_error(zdev, reply);
-	case TYPE86_RSP_CODE:
-		if (msg->cprbx.ccp_rtcode &&
-		   (msg->cprbx.ccp_rscode == 0x14f) &&
-		   (outputdatalength > 256)) {
-			if (zdev->max_exp_bit_length <= 17) {
-				zdev->max_exp_bit_length = 17;
-				return -EAGAIN;
-			} else
-				return -EINVAL;
-		}
-		if (msg->hdr.reply_code)
-			return convert_error(zdev, reply);
-		if (msg->cprbx.cprb_ver_id == 0x02)
-			return convert_type86_ica(zdev, reply,
-						  outputdata, outputdatalength);
-		/* Fall through, no break, incorrect cprb version is an unknown
-		 * response */
-	default: /* Unknown response type, this should NEVER EVER happen */
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-}
-
-static int convert_response_xcrb(struct zcrypt_device *zdev,
-			    struct ap_message *reply,
-			    struct ica_xcRB *xcRB)
-{
-	struct type86x_reply *msg = reply->message;
-
-	/* Response type byte is the second byte in the response. */
-	switch (((unsigned char *) reply->message)[1]) {
-	case TYPE82_RSP_CODE:
-	case TYPE88_RSP_CODE:
-		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
-		return convert_error(zdev, reply);
-	case TYPE86_RSP_CODE:
-		if (msg->hdr.reply_code) {
-			memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
-			return convert_error(zdev, reply);
-		}
-		if (msg->cprbx.cprb_ver_id == 0x02)
-			return convert_type86_xcrb(zdev, reply, xcRB);
-		/* Fall through, no break, incorrect cprb version is an unknown
-		 * response */
-	default: /* Unknown response type, this should NEVER EVER happen */
-		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-}
-
-static int convert_response_rng(struct zcrypt_device *zdev,
-				 struct ap_message *reply,
-				 char *data)
-{
-	struct type86x_reply *msg = reply->message;
-
-	switch (msg->hdr.type) {
-	case TYPE82_RSP_CODE:
-	case TYPE88_RSP_CODE:
-		return -EINVAL;
-	case TYPE86_RSP_CODE:
-		if (msg->hdr.reply_code)
-			return -EINVAL;
-		if (msg->cprbx.cprb_ver_id == 0x02)
-			return convert_type86_rng(zdev, reply, data);
-		/* Fall through, no break, incorrect cprb version is an unknown
-		 * response */
-	default: /* Unknown response type, this should NEVER EVER happen */
-		zdev->online = 0;
-		return -EAGAIN;	/* repeat the request on a different device. */
-	}
-}
-
-/**
- * This function is called from the AP bus code after a crypto request
- * "msg" has finished with the reply message "reply".
- * It is called from tasklet context.
- * @ap_dev: pointer to the AP device
- * @msg: pointer to the AP message
- * @reply: pointer to the AP reply message
- */
-static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
-				  struct ap_message *msg,
-				  struct ap_message *reply)
-{
-	static struct error_hdr error_reply = {
-		.type = TYPE82_RSP_CODE,
-		.reply_code = REP82_ERROR_MACHINE_FAILURE,
-	};
-	struct response_type *resp_type =
-		(struct response_type *) msg->private;
-	struct type86x_reply *t86r;
-	int length;
-
-	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply)) {
-		memcpy(msg->message, &error_reply, sizeof(error_reply));
-		goto out;
-	}
-	t86r = reply->message;
-	if (t86r->hdr.type == TYPE86_RSP_CODE &&
-		 t86r->cprbx.cprb_ver_id == 0x02) {
-		switch (resp_type->type) {
-		case PCIXCC_RESPONSE_TYPE_ICA:
-			length = sizeof(struct type86x_reply)
-				+ t86r->length - 2;
-			length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
-			memcpy(msg->message, reply->message, length);
-			break;
-		case PCIXCC_RESPONSE_TYPE_XCRB:
-			length = t86r->fmt2.offset2 + t86r->fmt2.count2;
-			length = min(PCIXCC_MAX_XCRB_MESSAGE_SIZE, length);
-			memcpy(msg->message, reply->message, length);
-			break;
-		default:
-			memcpy(msg->message, &error_reply, sizeof error_reply);
-		}
-	} else
-		memcpy(msg->message, reply->message, sizeof error_reply);
-out:
-	complete(&(resp_type->work));
-}
-
-static atomic_t zcrypt_step = ATOMIC_INIT(0);
-
-/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
- * device to handle a modexpo request.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  PCIXCC/CEX2C device to the request distributor
- * @mex: pointer to the modexpo request buffer
- */
-static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
-				  struct ica_rsa_modexpo *mex)
-{
-	struct ap_message ap_msg;
-	struct response_type resp_type = {
-		.type = PCIXCC_RESPONSE_TYPE_ICA,
-	};
-	int rc;
-
-	ap_init_message(&ap_msg);
-	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_pcixcc_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &resp_type;
-	rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
-	if (rc)
-		goto out_free;
-	init_completion(&resp_type.work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&resp_type.work);
-	if (rc == 0)
-		rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
-					  mex->outputdatalength);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
-	free_page((unsigned long) ap_msg.message);
-	return rc;
-}
-
-/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
- * device to handle a modexpo_crt request.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  PCIXCC/CEX2C device to the request distributor
- * @crt: pointer to the modexpoc_crt request buffer
- */
-static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
-				      struct ica_rsa_modexpo_crt *crt)
-{
-	struct ap_message ap_msg;
-	struct response_type resp_type = {
-		.type = PCIXCC_RESPONSE_TYPE_ICA,
-	};
-	int rc;
-
-	ap_init_message(&ap_msg);
-	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_pcixcc_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &resp_type;
-	rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
-	if (rc)
-		goto out_free;
-	init_completion(&resp_type.work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&resp_type.work);
-	if (rc == 0)
-		rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
-					  crt->outputdatalength);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
-	free_page((unsigned long) ap_msg.message);
-	return rc;
-}
-
-/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
- * device to handle a send_cprb request.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  PCIXCC/CEX2C device to the request distributor
- * @xcRB: pointer to the send_cprb request buffer
- */
-static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
-				    struct ica_xcRB *xcRB)
-{
-	struct ap_message ap_msg;
-	struct response_type resp_type = {
-		.type = PCIXCC_RESPONSE_TYPE_XCRB,
-	};
-	int rc;
-
-	ap_init_message(&ap_msg);
-	ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_pcixcc_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &resp_type;
-	rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
-	if (rc)
-		goto out_free;
-	init_completion(&resp_type.work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&resp_type.work);
-	if (rc == 0)
-		rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
-	kzfree(ap_msg.message);
-	return rc;
-}
-
-/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
- * device to generate random data.
- * @zdev: pointer to zcrypt_device structure that identifies the
- *	  PCIXCC/CEX2C device to the request distributor
- * @buffer: pointer to a memory page to return random data
- */
-
-static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev,
-				    char *buffer)
-{
-	struct ap_message ap_msg;
-	struct response_type resp_type = {
-		.type = PCIXCC_RESPONSE_TYPE_XCRB,
-	};
-	int rc;
-
-	ap_init_message(&ap_msg);
-	ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
-	if (!ap_msg.message)
-		return -ENOMEM;
-	ap_msg.receive = zcrypt_pcixcc_receive;
-	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
-				atomic_inc_return(&zcrypt_step);
-	ap_msg.private = &resp_type;
-	rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
-	init_completion(&resp_type.work);
-	ap_queue_message(zdev->ap_dev, &ap_msg);
-	rc = wait_for_completion_interruptible(&resp_type.work);
-	if (rc == 0)
-		rc = convert_response_rng(zdev, &ap_msg, buffer);
-	else
-		/* Signal pending. */
-		ap_cancel_message(zdev->ap_dev, &ap_msg);
-	kfree(ap_msg.message);
-	return rc;
-}
-
-/**
- * The crypto operations for a PCIXCC/CEX2C card.
- */
-static struct zcrypt_ops zcrypt_pcixcc_ops = {
-	.rsa_modexpo = zcrypt_pcixcc_modexpo,
-	.rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
-	.send_cprb = zcrypt_pcixcc_send_cprb,
-};
-
-static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = {
-	.rsa_modexpo = zcrypt_pcixcc_modexpo,
-	.rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
-	.send_cprb = zcrypt_pcixcc_send_cprb,
-	.rng = zcrypt_pcixcc_rng,
-};
-
-/**
  * Micro-code detection function. Its sends a message to a pcixcc card
  * to find out the microcode level.
  * @ap_dev: pointer to the AP device.
@@ -1083,9 +323,11 @@
 		return rc;
 	}
 	if (rc)
-		zdev->ops = &zcrypt_pcixcc_with_rng_ops;
+		zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
+						   MSGTYPE06_VARIANT_DEFAULT);
 	else
-		zdev->ops = &zcrypt_pcixcc_ops;
+		zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
+						   MSGTYPE06_VARIANT_NORNG);
 	ap_dev->reply = &zdev->reply;
 	ap_dev->private = zdev;
 	rc = zcrypt_device_register(zdev);
@@ -1095,6 +337,7 @@
 
  out_free:
 	ap_dev->private = NULL;
+	zcrypt_msgtype_release(zdev->ops);
 	zcrypt_device_free(zdev);
 	return rc;
 }
@@ -1106,8 +349,10 @@
 static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
 {
 	struct zcrypt_device *zdev = ap_dev->private;
+	struct zcrypt_ops *zops = zdev->ops;
 
 	zcrypt_device_unregister(zdev);
+	zcrypt_msgtype_release(zops);
 }
 
 int __init zcrypt_pcixcc_init(void)
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index c7cdf59..eacafc8 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -1,12 +1,13 @@
 /*
  *  zcrypt 2.1.0
  *
- *  Copyright IBM Corp. 2001, 2006
+ *  Copyright IBM Corp. 2001, 2012
  *  Author(s): Robert Burroughs
  *	       Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 7a8b096..cf6da7fa 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2993,7 +2993,7 @@
 	struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
 	struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info;
 	struct ccw_dev_id ccwid;
-	int level, rc;
+	int level;
 
 	tid->chpid = card->info.chpid;
 	ccw_device_get_id(CARD_RDEV(card), &ccwid);
@@ -3001,17 +3001,10 @@
 	tid->devno = ccwid.devno;
 	if (!info)
 		return;
-
-	rc = stsi(NULL, 0, 0, 0);
-	if (rc == -ENOSYS)
-		level = rc;
-	else
-		level = (((unsigned int) rc) >> 28);
-
-	if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS))
+	level = stsi(NULL, 0, 0, 0);
+	if ((level >= 2) && (stsi(info222, 2, 2, 2) == 0))
 		tid->lparnr = info222->lpar_number;
-
-	if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) {
+	if ((level >= 3) && (stsi(info322, 3, 2, 2) == 0)) {
 		EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name));
 		memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname));
 	}
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 25417d0..0bcacf7 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -2888,7 +2888,7 @@
 		ahd_outb(ahd, CLRINT, CLRSCSIINT);
 		ahd_unpause(ahd);
 	} else {
-		printk("Reseting Channel for LQI Phase error\n");
+		printk("Resetting Channel for LQI Phase error\n");
 		ahd_dump_card_state(ahd);
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 	}
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index edfd12b..968d083 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -273,7 +273,7 @@
 {
 	const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
 	const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
-	const void __iomem *reg_dmadata = base + EESOX_DMADATA;
+	void __iomem *reg_dmadata = base + EESOX_DMADATA;
 
 	do {
 		unsigned int status;
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 8cdb79c..21ad290 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -5587,7 +5587,7 @@
 static void bfa_dconf_init_cb(void *arg, bfa_status_t status);
 
 /*
- * Begining state of dconf module. Waiting for an event to start.
+ * Beginning state of dconf module. Waiting for an event to start.
  */
 static void
 bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 1a99d4b..7b916e0 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -530,7 +530,7 @@
 
 struct bfa_diag_qtest_result_s {
 	u32	status;
-	u16	count;	/* sucessful queue test count */
+	u16	count;	/* successful queue test count */
 	u8	queue;
 	u8	rsvd;	/* 64-bit align */
 };
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index ae1cb76..e055865 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -908,7 +908,7 @@
 		return;
 
 	default:
-		printk(KERN_ERR PFX "Unkonwn netevent %ld", event);
+		printk(KERN_ERR PFX "Unknown netevent %ld", event);
 		return;
 	}
 
@@ -1738,7 +1738,7 @@
 /**
  * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance
  *
- * @handle:	transport handle pointing to adapter struture
+ * @handle:	transport handle pointing to adapter structure
  *
  * This function maps adapter structure to pcidev structure and initiates
  *	firmware handshake to enable/initialize on-chip FCoE components.
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 33d6630..91eec60 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1264,6 +1264,9 @@
 	int rc = 0;
 	u64 mask64;
 
+	memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1));
+	memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2));
+
 	bnx2i_adjust_qp_size(hba);
 
 	iscsi_init.flags =
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index d3e4d7c..fbf6f0f4 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -49,15 +49,6 @@
 /* GDT_ISA */
 #define GDT2_ID         0x0120941c              /* GDT2000/2020 */
 
-/* vendor ID, device IDs (PCI) */
-/* these defines should already exist in <linux/pci.h> */
-#ifndef PCI_VENDOR_ID_VORTEX
-#define PCI_VENDOR_ID_VORTEX            0x1119  /* PCI controller vendor ID */
-#endif
-#ifndef PCI_VENDOR_ID_INTEL
-#define PCI_VENDOR_ID_INTEL             0x8086  
-#endif
-
 #ifndef PCI_DEVICE_ID_VORTEX_GDT60x0
 /* GDT_PCI */
 #define PCI_DEVICE_ID_VORTEX_GDT60x0    0       /* GDT6000/6020/6050 */
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 796482b..2b4261c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1315,8 +1315,9 @@
 	}
 		break;
 	case CMD_PROTOCOL_ERR:
+		cmd->result = DID_ERROR << 16;
 		dev_warn(&h->pdev->dev, "cp %p has "
-			"protocol error \n", cp);
+			"protocol error\n", cp);
 		break;
 	case CMD_HARDWARE_ERR:
 		cmd->result = DID_ERROR << 16;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 467dc38..0a2c5a8 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -192,7 +192,7 @@
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
 };
 
-static int ipr_max_bus_speeds [] = {
+static int ipr_max_bus_speeds[] = {
 	IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE
 };
 
@@ -562,7 +562,7 @@
 	trace_entry->u.add_data = add_data;
 }
 #else
-#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
+#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while (0)
 #endif
 
 /**
@@ -1002,7 +1002,7 @@
  **/
 static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto)
 {
-	switch(proto) {
+	switch (proto) {
 	case IPR_PROTO_SATA:
 	case IPR_PROTO_SAS_STP:
 		res->ata_class = ATA_DEV_ATA;
@@ -3043,7 +3043,7 @@
 }
 
 #else
-#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0)
+#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while (0)
 #endif
 
 /**
@@ -3055,7 +3055,7 @@
  **/
 static void ipr_release_dump(struct kref *kref)
 {
-	struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref);
+	struct ipr_dump *dump = container_of(kref, struct ipr_dump, kref);
 	struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg;
 	unsigned long lock_flags = 0;
 	int i;
@@ -3142,7 +3142,7 @@
 				break;
 			}
 		}
-	} while(did_work);
+	} while (did_work);
 
 	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
 		if (res->add_to_ml) {
@@ -3268,7 +3268,7 @@
  * 	number of bytes printed to buffer
  **/
 static ssize_t ipr_store_log_level(struct device *dev,
-			           struct device_attribute *attr,
+				   struct device_attribute *attr,
 				   const char *buf, size_t count)
 {
 	struct Scsi_Host *shost = class_to_shost(dev);
@@ -3315,7 +3315,7 @@
 		return -EACCES;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -3682,7 +3682,7 @@
 	unsigned long lock_flags;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -3746,7 +3746,7 @@
 	len = snprintf(fname, 99, "%s", buf);
 	fname[len-1] = '\0';
 
-	if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
+	if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
 		dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
 		return -EIO;
 	}
@@ -4612,7 +4612,7 @@
  * Return value:
  * 	SUCCESS / FAILED
  **/
-static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd)
+static int __ipr_eh_host_reset(struct scsi_cmnd *scsi_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg;
 	int rc;
@@ -4634,7 +4634,7 @@
 	return rc;
 }
 
-static int ipr_eh_host_reset(struct scsi_cmnd * cmd)
+static int ipr_eh_host_reset(struct scsi_cmnd *cmd)
 {
 	int rc;
 
@@ -4701,7 +4701,7 @@
 	}
 
 	LEAVE;
-	return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
+	return IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0;
 }
 
 /**
@@ -4725,7 +4725,7 @@
 
 	ENTER;
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -4753,7 +4753,7 @@
  * Return value:
  *	SUCCESS / FAILED
  **/
-static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
+static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
 {
 	struct ipr_cmnd *ipr_cmd;
 	struct ipr_ioa_cfg *ioa_cfg;
@@ -4811,10 +4811,10 @@
 	res->resetting_device = 0;
 
 	LEAVE;
-	return (rc ? FAILED : SUCCESS);
+	return rc ? FAILED : SUCCESS;
 }
 
-static int ipr_eh_dev_reset(struct scsi_cmnd * cmd)
+static int ipr_eh_dev_reset(struct scsi_cmnd *cmd)
 {
 	int rc;
 
@@ -4910,7 +4910,7 @@
  * Return value:
  *	SUCCESS / FAILED
  **/
-static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
+static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd)
 {
 	struct ipr_cmnd *ipr_cmd;
 	struct ipr_ioa_cfg *ioa_cfg;
@@ -4979,7 +4979,7 @@
 		res->needs_sync_complete = 1;
 
 	LEAVE;
-	return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
+	return IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS;
 }
 
 /**
@@ -4989,7 +4989,7 @@
  * Return value:
  * 	SUCCESS / FAILED
  **/
-static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd)
+static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd)
 {
 	unsigned long flags;
 	int rc;
@@ -5907,7 +5907,7 @@
  * Return value:
  * 	pointer to buffer with description string
  **/
-static const char * ipr_ioa_info(struct Scsi_Host *host)
+static const char *ipr_ioa_info(struct Scsi_Host *host)
 {
 	static char buffer[512];
 	struct ipr_ioa_cfg *ioa_cfg;
@@ -5965,7 +5965,7 @@
 
 	ENTER;
 	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
@@ -6005,7 +6005,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
@@ -6330,7 +6330,7 @@
 	int i;
 
 	if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) {
-		for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){
+		for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++) {
 			if (__is_processor(ipr_blocked_processors[i]))
 				return 1;
 		}
@@ -6608,7 +6608,7 @@
  * 	none
  **/
 static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg,
-					  	struct ipr_mode_pages *mode_pages)
+					  struct ipr_mode_pages *mode_pages)
 {
 	int i, entry_length;
 	struct ipr_dev_bus_entry *bus;
@@ -8022,7 +8022,7 @@
 		ipr_reinit_ipr_cmnd(ipr_cmd);
 		ipr_cmd->job_step_failed = ipr_reset_cmd_failed;
 		rc = ipr_cmd->job_step(ipr_cmd);
-	} while(rc == IPR_RC_JOB_CONTINUE);
+	} while (rc == IPR_RC_JOB_CONTINUE);
 }
 
 /**
@@ -8283,7 +8283,7 @@
 	}
 
 	if (ioa_cfg->ipr_cmd_pool)
-		pci_pool_destroy (ioa_cfg->ipr_cmd_pool);
+		pci_pool_destroy(ioa_cfg->ipr_cmd_pool);
 
 	kfree(ioa_cfg->ipr_cmnd_list);
 	kfree(ioa_cfg->ipr_cmnd_list_dma);
@@ -8363,8 +8363,8 @@
 	dma_addr_t dma_addr;
 	int i;
 
-	ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev,
-						 sizeof(struct ipr_cmnd), 512, 0);
+	ioa_cfg->ipr_cmd_pool = pci_pool_create(IPR_NAME, ioa_cfg->pdev,
+						sizeof(struct ipr_cmnd), 512, 0);
 
 	if (!ioa_cfg->ipr_cmd_pool)
 		return -ENOMEM;
@@ -8378,7 +8378,7 @@
 	}
 
 	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
-		ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
+		ipr_cmd = pci_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
 
 		if (!ipr_cmd) {
 			ipr_free_cmd_blks(ioa_cfg);
@@ -8964,7 +8964,7 @@
 	int target, lun;
 
 	for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++)
-		for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ )
+		for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++)
 			scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun);
 }
 
@@ -9010,7 +9010,7 @@
 	ENTER;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
@@ -9139,7 +9139,7 @@
 	unsigned long lock_flags = 0;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	while(ioa_cfg->in_reset_reload) {
+	while (ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -9228,7 +9228,7 @@
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
 
-static struct pci_error_handlers ipr_err_handler = {
+static const struct pci_error_handlers ipr_err_handler = {
 	.error_detected = ipr_pci_error_detected,
 	.slot_reset = ipr_pci_slot_reset,
 };
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 45385f5..b334fdc 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -492,7 +492,7 @@
 	u32 event_cycle;
 
 	dev_dbg(&ihost->pdev->dev,
-		"%s: completion queue begining get:0x%08x\n",
+		"%s: completion queue beginning get:0x%08x\n",
 		__func__,
 		ihost->completion_queue_get);
 
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 92c1d86..9be45a2 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -222,7 +222,7 @@
  * @isci_host: This parameter specifies the lldd specific wrapper for the
  *    libsas sas_ha struct.
  *
- * This method returns an error code indicating sucess or failure. The user
+ * This method returns an error code indicating success or failure. The user
  * should check for possible memory allocation error return otherwise, a zero
  * indicates success.
  */
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 2fb85bf..13098b0 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -212,7 +212,7 @@
 		memcpy(iphy->sas_phy.attached_sas_addr,
 		       iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE);
 	} else {
-		dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__);
+		dev_err(&isci_host->pdev->dev, "%s: unknown target\n", __func__);
 		success = false;
 	}
 
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 7a0431c..c1bafc3 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2240,7 +2240,7 @@
 			status = ireq->sci_status;
 			sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR);
 		} else {
-			/* If receiving any non-sucess TC status, no UF
+			/* If receiving any non-success TC status, no UF
 			 * received yet, then an UF for the status fis
 			 * is coming after (XXX: suspect this is
 			 * actually a protocol error or a bug like the
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 6bc74eb..b6f19a1 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -532,7 +532,7 @@
 		/* The request has already completed and there
 		* is nothing to do here other than to set the task
 		* done bit, and indicate that the task abort function
-		* was sucessful.
+		* was successful.
 		*/
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		task->task_state_flags |= SAS_TASK_STATE_DONE;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 45c1520..628a703 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -6607,7 +6607,7 @@
  * we just use some constant number as place holder.
  *
  * Return codes
- *      0 - sucessful
+ *      0 - successful
  *      -ENOMEM - No availble memory
  *      -EIO - The mailbox failed to complete successfully.
  **/
@@ -10425,7 +10425,7 @@
 
 MODULE_DEVICE_TABLE(pci, lpfc_id_table);
 
-static struct pci_error_handlers lpfc_err_handler = {
+static const struct pci_error_handlers lpfc_err_handler = {
 	.error_detected = lpfc_io_error_detected,
 	.slot_reset = lpfc_io_slot_reset,
 	.resume = lpfc_io_resume,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 9cbd20b..0e7e144 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4739,7 +4739,7 @@
  * is attached to.
  *
  * Return codes
- *      0 - sucessful
+ *      0 - successful
  *      otherwise - failed to retrieve physical port name
  **/
 static int
@@ -15209,7 +15209,7 @@
 	/*
 	 * if next_fcf_pri was not set above and the list is not empty then
 	 * we have failed flogis on all of them. So reset flogi failed
-	 * and start at the begining.
+	 * and start at the beginning.
 	 */
 	if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) {
 		list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 97825f1..76ad72d 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -305,12 +305,11 @@
 
 	adapter->host->sg_tablesize = adapter->sglen;
 
-
 	/* use HP firmware and bios version encoding
 	   Note: fw_version[0|1] and bios_version[0|1] were originally shifted
 	   right 8 bits making them zero. This 0 value was hardcoded to fix
 	   sparse warnings. */
-	if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
+	if (adapter->product_info.subsysvid == PCI_VENDOR_ID_HP) {
 		sprintf (adapter->fw_version, "%c%d%d.%d%d",
 			 adapter->product_info.fw_version[2],
 			 0,
@@ -4716,7 +4715,7 @@
 	 * support, since this firmware cannot handle 64 bit
 	 * addressing
 	 */
-	if ((subsysvid == HP_SUBSYS_VID) &&
+	if ((subsysvid == PCI_VENDOR_ID_HP) &&
 	    ((subsysid == 0x60E7) || (subsysid == 0x60E8))) {
 		/*
 		 * which firmware
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 9a7897f..4fb2adf 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -45,45 +45,10 @@
 
 #define MAX_DEV_TYPE	32
 
-#ifndef PCI_VENDOR_ID_LSI_LOGIC
-#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
-#endif
-
-#ifndef PCI_VENDOR_ID_AMI
-#define PCI_VENDOR_ID_AMI		0x101E
-#endif
-
-#ifndef PCI_VENDOR_ID_DELL
-#define PCI_VENDOR_ID_DELL		0x1028
-#endif
-
-#ifndef PCI_VENDOR_ID_INTEL
-#define PCI_VENDOR_ID_INTEL		0x8086
-#endif
-
-#ifndef PCI_DEVICE_ID_AMI_MEGARAID
-#define PCI_DEVICE_ID_AMI_MEGARAID	0x9010
-#endif
-
-#ifndef PCI_DEVICE_ID_AMI_MEGARAID2
-#define PCI_DEVICE_ID_AMI_MEGARAID2	0x9060
-#endif
-
-#ifndef PCI_DEVICE_ID_AMI_MEGARAID3
-#define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
-#endif
-
 #define PCI_DEVICE_ID_DISCOVERY		0x000E
 #define PCI_DEVICE_ID_PERC4_DI		0x000F
 #define PCI_DEVICE_ID_PERC4_QC_VERDE	0x0407
 
-/* Sub-System Vendor IDs */
-#define	AMI_SUBSYS_VID			0x101E
-#define DELL_SUBSYS_VID			0x1028
-#define	HP_SUBSYS_VID			0x103C
-#define LSI_SUBSYS_VID			0x1000
-#define INTEL_SUBSYS_VID		0x8086
-
 #define HBA_SIGNATURE	      		0x3344
 #define HBA_SIGNATURE_471	  	0xCCCC
 #define HBA_SIGNATURE_64BIT		0x0299
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index b25757d..9d5a56c 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -1209,6 +1209,13 @@
 	u16 message_control;
 
 
+	/* Check whether controller SAS2008 B0 controller,
+	   if it is SAS2008 B0 controller use IO-APIC instead of MSIX */
+	if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
+	    ioc->pdev->revision == 0x01) {
+		return -EINVAL;
+	}
+
 	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
 	if (!base) {
 		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index b1ebd6f..1ccae45 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -8306,7 +8306,7 @@
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 
-static struct pci_error_handlers _scsih_err_handler = {
+static const struct pci_error_handlers _scsih_err_handler = {
 	.error_detected = _scsih_pci_error_detected,
 	.mmio_enabled = _scsih_pci_mmio_enabled,
 	.slot_reset =	_scsih_pci_slot_reset,
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 88cf1db..783edc7 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -122,7 +122,7 @@
 
 	if (!res) {
 		dev_err(&mhba->pdev->dev,
-			"Failed to allocate memory for resouce manager.\n");
+			"Failed to allocate memory for resource manager.\n");
 		return NULL;
 	}
 
@@ -1007,13 +1007,13 @@
 		tmp |= INT_MAP_COMAOUT | INT_MAP_COMAERR;
 		iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG);
 		iowrite32(mhba->list_num_io, mhba->ib_shadow);
-		/* Set InBound List Avaliable count shadow */
+		/* Set InBound List Available count shadow */
 		iowrite32(lower_32_bits(mhba->ib_shadow_phys),
 					regs + CLA_INB_AVAL_COUNT_BASEL);
 		iowrite32(upper_32_bits(mhba->ib_shadow_phys),
 					regs + CLA_INB_AVAL_COUNT_BASEH);
 
-		/* Set OutBound List Avaliable count shadow */
+		/* Set OutBound List Available count shadow */
 		iowrite32((mhba->list_num_io-1) | CL_POINTER_TOGGLE,
 						mhba->ob_shadow);
 		iowrite32(lower_32_bits(mhba->ob_shadow_phys), regs + 0x5B0);
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 9ce3a8f..7cfdf2b 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1615,13 +1615,11 @@
 char *
 qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
 {
-	int pcie_reg;
 	struct qla_hw_data *ha = vha->hw;
 	char lwstr[6];
 	uint16_t lnk;
 
-	pcie_reg = pci_pcie_cap(ha->pdev);
-	pci_read_config_word(ha->pdev, pcie_reg + PCI_EXP_LNKSTA, &lnk);
+	pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
 	ha->link_width = (lnk >> 4) & 0x3f;
 
 	strcpy(str, "PCIe (");
@@ -2497,7 +2495,6 @@
 int
 qla82xx_start_firmware(scsi_qla_host_t *vha)
 {
-	int           pcie_cap;
 	uint16_t      lnk;
 	struct qla_hw_data *ha = vha->hw;
 
@@ -2528,8 +2525,7 @@
 	}
 
 	/* Negotiated Link width */
-	pcie_cap = pci_pcie_cap(ha->pdev);
-	pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk);
+	pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
 	ha->link_width = (lnk >> 4) & 0x3f;
 
 	/* Synchronize with Receive peg */
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index fb8cd38..d305262 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4471,7 +4471,7 @@
 	ha->flags.eeh_busy = 0;
 }
 
-static struct pci_error_handlers qla2xxx_err_handler = {
+static const struct pci_error_handlers qla2xxx_err_handler = {
 	.error_detected = qla2xxx_pci_error_detected,
 	.mmio_enabled = qla2xxx_pci_mmio_enabled,
 	.slot_reset = qla2xxx_pci_slot_reset,
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 939d726..807bf76 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1566,7 +1566,6 @@
 static int
 qla4_8xxx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start)
 {
-	int pcie_cap;
 	uint16_t lnk;
 
 	/* scrub dma mask expansion register */
@@ -1590,8 +1589,7 @@
 	}
 
 	/* Negotiated Link width */
-	pcie_cap = pci_pcie_cap(ha->pdev);
-	pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk);
+	pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
 	ha->link_width = (lnk >> 4) & 0x3f;
 
 	/* Synchronize with Receive peg */
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 9da4266..79243b7 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -803,7 +803,7 @@
 				     iscsi_stats_dma);
 	if (ret != QLA_SUCCESS) {
 		ql4_printk(KERN_ERR, ha,
-			   "Unable to retreive iscsi stats\n");
+			   "Unable to retrieve iscsi stats\n");
 		goto free_stats;
 	}
 
@@ -4338,7 +4338,7 @@
 		return QLA_ERROR;
 
 	/* For multi sessions, driver generates the ISID, so do not compare
-	 * ISID in reset path since it would be a comparision between the
+	 * ISID in reset path since it would be a comparison between the
 	 * driver generated ISID and firmware generated ISID. This could
 	 * lead to adding duplicated DDBs in the list as driver generated
 	 * ISID would not match firmware generated ISID.
@@ -5326,7 +5326,7 @@
 	}
 }
 /**
- * qla4xxx_remove_adapter - calback function to remove adapter.
+ * qla4xxx_remove_adapter - callback function to remove adapter.
  * @pci_dev: PCI device pointer
  **/
 static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
@@ -6148,7 +6148,7 @@
 	clear_bit(AF_EEH_BUSY, &ha->flags);
 }
 
-static struct pci_error_handlers qla4xxx_err_handler = {
+static const struct pci_error_handlers qla4xxx_err_handler = {
 	.error_detected = qla4xxx_pci_error_detected,
 	.mmio_enabled = qla4xxx_pci_mmio_enabled,
 	.slot_reset = qla4xxx_pci_slot_reset,
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 36d1ed7..e2b8e68 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -2117,7 +2117,7 @@
 
 MODULE_DEVICE_TABLE(pci, sym2_id_table);
 
-static struct pci_error_handlers sym2_err_handler = {
+static const struct pci_error_handlers sym2_err_handler = {
 	.error_detected	= sym2_io_error_detected,
 	.mmio_enabled	= sym2_io_slot_dump,
 	.slot_reset	= sym2_io_slot_reset,
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index c7030fb..3e79a2f 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -331,7 +331,7 @@
 	int i;
 
 	for_each_sg(table->sgl, sg_elem, table->nents, i)
-		sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length);
+		sg[idx++] = *sg_elem;
 
 	*p_idx = idx;
 }
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 4411d42..20b3a48 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -295,7 +295,7 @@
 
 static void ll_bus_reset(const struct pvscsi_adapter *adapter)
 {
-	dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter);
+	dev_dbg(pvscsi_dev(adapter), "Resetting bus on %p\n", adapter);
 
 	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0);
 }
@@ -304,7 +304,7 @@
 {
 	struct PVSCSICmdDescResetDevice cmd = { 0 };
 
-	dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target);
+	dev_dbg(pvscsi_dev(adapter), "Resetting device: target=%u\n", target);
 
 	cmd.target = target;
 
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 32c26d7..8f32a13 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -355,7 +355,7 @@
 			if (unlikely(res)) {
 				if (res == -EEXIST) {
 					res = irq_domain_associate(d->domain,
-								   irq, irq);
+								   irq2, irq2);
 					if (unlikely(res)) {
 						pr_err("domain association "
 						       "failure\n");
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c
index 2804eaa..0646bf6 100644
--- a/drivers/sh/pfc/pinctrl.c
+++ b/drivers/sh/pfc/pinctrl.c
@@ -208,10 +208,13 @@
 
 		break;
 	case PINMUX_TYPE_GPIO:
+	case PINMUX_TYPE_INPUT:
+	case PINMUX_TYPE_OUTPUT:
 		break;
 	default:
 		pr_err("Unsupported mux type (%d), bailing...\n", pinmux_type);
-		return -ENOTSUPP;
+		ret = -ENOTSUPP;
+		goto err;
 	}
 
 	ret = 0;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5f84b55..2d198a01 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -366,7 +366,7 @@
 
 config SPI_TEGRA
 	tristate "Nvidia Tegra SPI controller"
-	depends on ARCH_TEGRA && (TEGRA_SYSTEM_DMA || TEGRA20_APB_DMA)
+	depends on ARCH_TEGRA && TEGRA20_APB_DMA
 	help
 	  SPI driver for NVidia Tegra SoCs
 
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 5784c87..4de66d1 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -475,7 +475,7 @@
 		/*
 		 * due to an spi error we consider transfer as done,
 		 * so mask all events until before next transfer start
-		 * and stop the possibly running dma immediatelly
+		 * and stop the possibly running dma immediately
 		 */
 		au1550_spi_mask_ack_all(hw);
 		au1xxx_dbdma_stop(hw->dma_rx_ch);
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 1fe5119..6555ecd 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -467,7 +467,7 @@
 		dev_dbg(drv_data->dev, "IO write error!\n");
 		drv_data->state = ERROR_STATE;
 	} else {
-		/* Update total byte transfered */
+		/* Update total byte transferred */
 		message->actual_length += transfer->len;
 		/* Move to next transfer of this msg */
 		drv_data->state = bfin_sport_spi_next_transfer(drv_data);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index e834ff8..3bd9c69 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -97,7 +97,7 @@
 	const void *tx_buf;
 	unsigned int txfifo; /* number of words pushed in tx FIFO */
 
-	struct spi_imx_devtype_data *devtype_data;
+	const struct spi_imx_devtype_data *devtype_data;
 	int chipselect[0];
 };
 
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 698018f..9d9071b 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -129,7 +129,7 @@
 	unsigned int i;
 
 	if (hw->irq >= 0) {
-		/* use intrrupt driven data transfer */
+		/* use interrupt driven data transfer */
 		hw->len = t->len;
 		hw->txp = t->tx_buf;
 		hw->rxp = t->rx_buf;
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index a3996a1..0a94d9d 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -52,7 +52,7 @@
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #include <mach/omap7xx.h>	/* OMAP7XX_IO_CONF registers */
 
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index b2fb141..5d59a69 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -42,7 +42,7 @@
 #include <linux/spi/spi.h>
 
 #include <plat/clock.h>
-#include <plat/mcspi.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #define OMAP2_MCSPI_MAX_FREQ		48000000
 #define SPI_AUTOSUSPEND_TIMEOUT		2000
@@ -1116,7 +1116,7 @@
 static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
 {
 	struct spi_master	*master;
-	struct omap2_mcspi_platform_config *pdata;
+	const struct omap2_mcspi_platform_config *pdata;
 	struct omap2_mcspi	*mcspi;
 	struct resource		*r;
 	int			status = 0, i;
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 75ac9d4..7a85f22 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -101,7 +101,7 @@
 	u8 dummy;
 	/*
 	 * Clock divisor modulus register
-	 * This uses the follwing formula:
+	 * This uses the following formula:
 	 *    SCPClkOut = OPBCLK/(4(CDM + 1))
 	 * or
 	 *    CDM = (OPBCLK/4*SCPClkOut) - 1
@@ -201,7 +201,7 @@
 		return -EINVAL;
 	}
 
-	/* Write new configration */
+	/* Write new configuration */
 	out_8(&hw->regs->mode, cs->mode);
 
 	/* Set the clock */
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index ef52c1c..488d9b6 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -164,23 +164,15 @@
 	 * for the generic case.
 	 */
 	int			dma_req_len;
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	struct tegra_dma_req	rx_dma_req;
-	struct tegra_dma_channel *rx_dma;
-#else
 	struct dma_chan		*rx_dma;
 	struct dma_slave_config	sconfig;
 	struct dma_async_tx_descriptor	*rx_dma_desc;
 	dma_cookie_t		rx_cookie;
-#endif
 	u32			*rx_bb;
 	dma_addr_t		rx_bb_phys;
 };
 
-#if !defined(CONFIG_TEGRA_SYSTEM_DMA)
 static void tegra_spi_rx_dma_complete(void *args);
-#endif
-
 static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
 					    unsigned long reg)
 {
@@ -204,10 +196,6 @@
 	val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN;
 	val |= SLINK_DMA_BLOCK_SIZE(tspi->dma_req_len / 4 - 1);
 	spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	tspi->rx_dma_req.size = tspi->dma_req_len;
-	tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
-#else
 	tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma,
 				tspi->rx_bb_phys, tspi->dma_req_len,
 				DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
@@ -219,7 +207,6 @@
 	tspi->rx_dma_desc->callback_param = tspi;
 	tspi->rx_cookie = dmaengine_submit(tspi->rx_dma_desc);
 	dma_async_issue_pending(tspi->rx_dma);
-#endif
 
 	val |= SLINK_DMA_EN;
 	spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
@@ -405,19 +392,12 @@
 
 	spin_unlock_irqrestore(&tspi->lock, flags);
 }
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req)
-{
-	struct spi_tegra_data *tspi = req->dev;
-	handle_spi_rx_dma_complete(tspi);
-}
-#else
+
 static void tegra_spi_rx_dma_complete(void *args)
 {
 	struct spi_tegra_data *tspi = args;
 	handle_spi_rx_dma_complete(tspi);
 }
-#endif
 
 static int spi_tegra_setup(struct spi_device *spi)
 {
@@ -509,9 +489,7 @@
 	struct spi_tegra_data	*tspi;
 	struct resource		*r;
 	int ret;
-#if !defined(CONFIG_TEGRA_SYSTEM_DMA)
 	dma_cap_mask_t mask;
-#endif
 
 	master = spi_alloc_master(&pdev->dev, sizeof *tspi);
 	if (master == NULL) {
@@ -563,14 +541,6 @@
 
 	INIT_LIST_HEAD(&tspi->queue);
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
-	if (!tspi->rx_dma) {
-		dev_err(&pdev->dev, "can not allocate rx dma channel\n");
-		ret = -ENODEV;
-		goto err3;
-	}
-#else
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
 	tspi->rx_dma = dma_request_channel(mask, NULL, NULL);
@@ -580,8 +550,6 @@
 		goto err3;
 	}
 
-#endif
-
 	tspi->rx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
 					 &tspi->rx_bb_phys, GFP_KERNEL);
 	if (!tspi->rx_bb) {
@@ -590,17 +558,6 @@
 		goto err4;
 	}
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
-	tspi->rx_dma_req.to_memory = 1;
-	tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys;
-	tspi->rx_dma_req.dest_bus_width = 32;
-	tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
-	tspi->rx_dma_req.source_bus_width = 32;
-	tspi->rx_dma_req.source_wrap = 4;
-	tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
-	tspi->rx_dma_req.dev = tspi;
-#else
 	/* Dmaengine Dma slave config */
 	tspi->sconfig.src_addr = tspi->phys + SLINK_RX_FIFO;
 	tspi->sconfig.dst_addr = tspi->phys + SLINK_RX_FIFO;
@@ -616,7 +573,6 @@
 			ret);
 		goto err4;
 	}
-#endif
 
 	master->dev.of_node = pdev->dev.of_node;
 	ret = spi_register_master(master);
@@ -630,11 +586,7 @@
 	dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
 			  tspi->rx_bb, tspi->rx_bb_phys);
 err4:
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	tegra_dma_free_channel(tspi->rx_dma);
-#else
 	dma_release_channel(tspi->rx_dma);
-#endif
 err3:
 	clk_put(tspi->clk);
 err2:
@@ -656,12 +608,7 @@
 	tspi = spi_master_get_devdata(master);
 
 	spi_unregister_master(master);
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-	tegra_dma_free_channel(tspi->rx_dma);
-#else
 	dma_release_channel(tspi->rx_dma);
-#endif
-
 	dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
 			  tspi->rx_bb, tspi->rx_bb_phys);
 
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index cd56dcf..1284c9b 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -505,7 +505,7 @@
 	}
 
 	if (unlikely(pspi->max_speed_hz == 0)) {
-		dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n",
+		dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
 			__func__, pspi->max_speed_hz);
 		retval = -EINVAL;
 		goto err_out;
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e3402d5..d805eef 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -122,8 +122,6 @@
 
 source "drivers/staging/telephony/Kconfig"
 
-source "drivers/staging/ramster/Kconfig"
-
 source "drivers/staging/ozwpan/Kconfig"
 
 source "drivers/staging/ccg/Kconfig"
@@ -136,4 +134,14 @@
 
 source "drivers/staging/omap-thermal/Kconfig"
 
+source "drivers/staging/ramster/Kconfig"
+
+source "drivers/staging/silicom/Kconfig"
+
+source "drivers/staging/ced1401/Kconfig"
+
+source "drivers/staging/imx-drm/Kconfig"
+
+source "drivers/staging/dgrp/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 3be59d0..76e2ebd 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -54,9 +54,13 @@
 obj-$(CONFIG_DRM_OMAP)		+= omapdrm/
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_PHONE)		+= telephony/
-obj-$(CONFIG_RAMSTER)		+= ramster/
 obj-$(CONFIG_USB_WPAN_HCD)	+= ozwpan/
 obj-$(CONFIG_USB_G_CCG)		+= ccg/
 obj-$(CONFIG_WIMAX_GDM72XX)	+= gdm72xx/
 obj-$(CONFIG_CSR_WIFI)		+= csr/
 obj-$(CONFIG_OMAP_BANDGAP)	+= omap-thermal/
+obj-$(CONFIG_ZCACHE2)		+= ramster/
+obj-$(CONFIG_NET_VENDOR_SILICOM)	+= silicom/
+obj-$(CONFIG_CED1401)		+= ced1401/
+obj-$(CONFIG_DRM_IMX)		+= imx-drm/
+obj-$(CONFIG_DGRP)		+= dgrp/
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index 5b70640..a9b293f 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -67,10 +67,8 @@
 
 static int is_wakeup(enum android_alarm_type type)
 {
-	if (type == ANDROID_ALARM_RTC_WAKEUP ||
-			type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
-		return 1;
-	return 0;
+	return (type == ANDROID_ALARM_RTC_WAKEUP ||
+		type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP);
 }
 
 
@@ -85,12 +83,9 @@
 
 static int devalarm_try_to_cancel(struct devalarm *alrm)
 {
-	int ret;
 	if (is_wakeup(alrm->type))
-		ret = alarm_try_to_cancel(&alrm->u.alrm);
-	else
-		ret = hrtimer_try_to_cancel(&alrm->u.hrt);
-	return ret;
+		return alarm_try_to_cancel(&alrm->u.alrm);
+	return hrtimer_try_to_cancel(&alrm->u.hrt);
 }
 
 static void devalarm_cancel(struct devalarm *alrm)
@@ -223,10 +218,12 @@
 		case ANDROID_ALARM_ELAPSED_REALTIME:
 			get_monotonic_boottime(&tmp_time);
 			break;
-		case ANDROID_ALARM_TYPE_COUNT:
 		case ANDROID_ALARM_SYSTEMTIME:
 			ktime_get_ts(&tmp_time);
 			break;
+		default:
+			rv = -EINVAL;
+			goto err1;
 		}
 		if (copy_to_user((void __user *)arg, &tmp_time,
 		    sizeof(tmp_time))) {
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 69cf2db..94a740d 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -1,20 +1,20 @@
 /* mm/ashmem.c
-**
-** Anonymous Shared Memory Subsystem, ashmem
-**
-** Copyright (C) 2008 Google, Inc.
-**
-** Robert Love <rlove@google.com>
-**
-** This software is licensed under the terms of the GNU General Public
-** License version 2, as published by the Free Software Foundation, and
-** may be copied, distributed, and modified under those terms.
-**
-** 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.
-*/
+ *
+ * Anonymous Shared Memory Subsystem, ashmem
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
 
 #define pr_fmt(fmt) "ashmem: " fmt
 
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 574e992..a807129 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -365,7 +365,7 @@
 /*
  * copied from get_unused_fd_flags
  */
-int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
+static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
 {
 	struct files_struct *files = proc->files;
 	int fd, error;
@@ -415,13 +415,13 @@
 	else
 		__clear_close_on_exec(fd, fdt);
 	files->next_fd = fd + 1;
-#if 1
+
 	/* Sanity check */
 	if (fdt->fd[fd] != NULL) {
 		pr_warn("get_unused_fd: slot %d not NULL!\n", fd);
 		fdt->fd[fd] = NULL;
 	}
-#endif
+
 	error = fd;
 
 out:
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index f7b8237..1d5ed47 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -32,38 +32,50 @@
 
 #include <asm/ioctls.h>
 
-/*
+/**
  * struct logger_log - represents a specific log, such as 'main' or 'radio'
+ * @buffer:	The actual ring buffer
+ * @misc:	The "misc" device representing the log
+ * @wq:		The wait queue for @readers
+ * @readers:	This log's readers
+ * @mutex:	The mutex that protects the @buffer
+ * @w_off:	The current write head offset
+ * @head:	The head, or location that readers start reading at.
+ * @size:	The size of the log
+ * @logs:	The list of log channels
  *
  * This structure lives from module insertion until module removal, so it does
  * not need additional reference counting. The structure is protected by the
  * mutex 'mutex'.
  */
 struct logger_log {
-	unsigned char		*buffer;/* the ring buffer itself */
-	struct miscdevice	misc;	/* misc device representing the log */
-	wait_queue_head_t	wq;	/* wait queue for readers */
-	struct list_head	readers; /* this log's readers */
-	struct mutex		mutex;	/* mutex protecting buffer */
-	size_t			w_off;	/* current write head offset */
-	size_t			head;	/* new readers start here */
-	size_t			size;	/* size of the log */
-	struct list_head	logs;	/* list of log channels (myself)*/
+	unsigned char		*buffer;
+	struct miscdevice	misc;
+	wait_queue_head_t	wq;
+	struct list_head	readers;
+	struct mutex		mutex;
+	size_t			w_off;
+	size_t			head;
+	size_t			size;
+	struct list_head	logs;
 };
 
 static LIST_HEAD(log_list);
 
 
-/*
+/**
  * struct logger_reader - a logging device open for reading
+ * @log:	The associated log
+ * @list:	The associated entry in @logger_log's list
+ * @r_off:	The current read head offset.
  *
  * This object lives from open to release, so we don't need additional
  * reference counting. The structure is protected by log->mutex.
  */
 struct logger_reader {
-	struct logger_log	*log;	/* associated log */
-	struct list_head	list;	/* entry in logger_log's list */
-	size_t			r_off;	/* current read head offset */
+	struct logger_log	*log;
+	struct list_head	list;
+	size_t			r_off;
 };
 
 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
index 2cb06e9..9b929a8 100644
--- a/drivers/staging/android/logger.h
+++ b/drivers/staging/android/logger.h
@@ -20,14 +20,24 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
+/**
+ * struct logger_entry - defines a single entry that is given to a logger
+ * @len:	The length of the payload
+ * @__pad:	Two bytes of padding that appear to be required
+ * @pid:	The generating process' process ID
+ * @tid:	The generating process' thread ID
+ * @sec:	The number of seconds that have elapsed since the Epoch
+ * @nsec:	The number of nanoseconds that have elapsed since @sec
+ * @msg:	The message that is to be logged
+ */
 struct logger_entry {
-	__u16		len;	/* length of the payload */
-	__u16		__pad;	/* no matter what, we get 2 bytes of padding */
-	__s32		pid;	/* generating process's pid */
-	__s32		tid;	/* generating process's tid */
-	__s32		sec;	/* seconds since Epoch */
-	__s32		nsec;	/* nanoseconds */
-	char		msg[0];	/* the entry's payload */
+	__u16		len;
+	__u16		__pad;
+	__s32		pid;
+	__s32		tid;
+	__s32		sec;
+	__s32		nsec;
+	char		msg[0];
 };
 
 #define LOGGER_LOG_RADIO	"log_radio"	/* radio-related messages */
diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c
index 45c522c..e814514 100644
--- a/drivers/staging/android/timed_gpio.c
+++ b/drivers/staging/android/timed_gpio.c
@@ -161,18 +161,7 @@
 	},
 };
 
-static int __init timed_gpio_init(void)
-{
-	return platform_driver_register(&timed_gpio_driver);
-}
-
-static void __exit timed_gpio_exit(void)
-{
-	platform_driver_unregister(&timed_gpio_driver);
-}
-
-module_init(timed_gpio_init);
-module_exit(timed_gpio_exit);
+module_platform_driver(timed_gpio_driver);
 
 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
 MODULE_DESCRIPTION("timed gpio driver");
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index f63c1d3..0018547 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -42,8 +42,6 @@
 #define ASUS_OLED_NAME			"asus-oled"
 #define ASUS_OLED_UNDERSCORE_NAME	"asus_oled"
 
-#define ASUS_OLED_ERROR			"Asus OLED Display Error: "
-
 #define ASUS_OLED_STATIC		's'
 #define ASUS_OLED_ROLL			'r'
 #define ASUS_OLED_FLASH			'f'
@@ -57,8 +55,9 @@
 #define USB_DEVICE_ID_ASUS_LCM2     0x175b
 
 MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
-MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
+MODULE_DESCRIPTION("Asus OLED Driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ASUS_OLED_VERSION);
 
 static struct class *oled_class;
 static int oled_num;
@@ -138,6 +137,7 @@
 	size_t			buf_size;
 	char			*buf;
 	uint8_t			enabled;
+	uint8_t			enabled_post_resume;
 	struct device		*dev;
 };
 
@@ -383,13 +383,13 @@
 
 		default:
 			i = 0;
-			printk(ASUS_OLED_ERROR "Unknown OLED Pack Mode: %d!\n",
+			dev_err(odev->dev, "Unknown OLED Pack Mode: %d!\n",
 			       odev->pack_mode);
 			break;
 		}
 
 		if (i >= odev->buf_size) {
-			printk(ASUS_OLED_ERROR "Buffer overflow! Report a bug:"
+			dev_err(odev->dev, "Buffer overflow! Report a bug:"
 			       "offs: %d >= %d i: %d (x: %d y: %d)\n",
 			       (int) odev->buf_offs, (int) odev->buf_size,
 			       (int) i, (int) x, (int) y);
@@ -435,7 +435,7 @@
 		odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
 		if (odev->buf == NULL) {
 			odev->buf_size = 0;
-			printk(ASUS_OLED_ERROR "Out of memory!\n");
+			dev_err(odev->dev, "Out of memory!\n");
 			return -ENOMEM;
 		}
 
@@ -473,7 +473,7 @@
 			odev->pic_mode = buf[1];
 			break;
 		default:
-			printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n",
+			dev_err(odev->dev, "Wrong picture mode: '%c'.\n",
 			       buf[1]);
 			return -EIO;
 			break;
@@ -533,7 +533,7 @@
 
 		if (odev->buf == NULL) {
 			odev->buf_size = 0;
-			printk(ASUS_OLED_ERROR "Out of memory!\n");
+			dev_err(odev->dev, "Out of memory!\n");
 			return -ENOMEM;
 		}
 
@@ -593,15 +593,15 @@
 	return count;
 
 error_width:
-	printk(ASUS_OLED_ERROR "Wrong picture width specified.\n");
+	dev_err(odev->dev, "Wrong picture width specified.\n");
 	return -EIO;
 
 error_height:
-	printk(ASUS_OLED_ERROR "Wrong picture height specified.\n");
+	dev_err(odev->dev, "Wrong picture height specified.\n");
 	return -EIO;
 
 error_header:
-	printk(ASUS_OLED_ERROR "Wrong picture header.\n");
+	dev_err(odev->dev, "Wrong picture header.\n");
 	return -EIO;
 }
 
@@ -766,11 +766,45 @@
 	dev_info(&interface->dev, "Disconnected Asus OLED device\n");
 }
 
+#ifdef CONFIG_PM
+static int asus_oled_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct asus_oled_dev *odev;
+
+	odev = usb_get_intfdata(intf);
+	if (!odev)
+		return -ENODEV;
+
+	odev->enabled_post_resume = odev->enabled;
+	enable_oled(odev, 0);
+
+	return 0;
+}
+
+static int asus_oled_resume(struct usb_interface *intf)
+{
+	struct asus_oled_dev *odev;
+
+	odev = usb_get_intfdata(intf);
+	if (!odev)
+		return -ENODEV;
+
+	enable_oled(odev, odev->enabled_post_resume);
+
+	return 0;
+}
+#else
+#define asus_oled_suspend NULL
+#define asus_oled_resume NULL
+#endif
+
 static struct usb_driver oled_driver = {
 	.name =		ASUS_OLED_NAME,
 	.probe =	asus_oled_probe,
 	.disconnect =	asus_oled_disconnect,
 	.id_table =	id_table,
+	.suspend =	asus_oled_suspend,
+	.resume =	asus_oled_resume,
 };
 
 static CLASS_ATTR_STRING(version, S_IRUGO,
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index cf411d1..3d02c2eb 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -820,6 +820,7 @@
 
 		if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
 			up(&Adapter->fw_download_sema);
+			kfree(psFwInfo);
 			return -EFAULT;
 		}
 
@@ -829,6 +830,7 @@
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n",
 					psFwInfo->u32FirmwareLength);
 			up(&Adapter->fw_download_sema);
+			kfree(psFwInfo);
 			Status = -EINVAL;
 			return Status;
 		}
diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c
index b54ec97..325b592 100644
--- a/drivers/staging/bcm/CmHost.c
+++ b/drivers/staging/bcm/CmHost.c
@@ -235,7 +235,7 @@
  * @ingroup ctrl_pkt_functions
  * copy classifier rule into the specified SF index
  */
-static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, stConvergenceSLTypes  *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex)
+static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, struct bcm_convergence_types *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex)
 {
 	struct bcm_classifier_rule *pstClassifierEntry = NULL;
 	/* VOID *pvPhsContext = NULL; */
@@ -428,7 +428,7 @@
  * @ingroup ctrl_pkt_functions
  */
 static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */
-			register pstServiceFlowParamSI psfLocalSet, /* <Pointer to the ServiceFlowParamSI structure */
+			register struct bcm_connect_mgr_params *psfLocalSet, /* Pointer to the connection manager parameters structure */
 			register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */
 			register UCHAR ucDsxType,
 			stLocalSFAddIndicationAlt *pstAddIndication) {
@@ -439,7 +439,7 @@
 	enum E_CLASSIFIER_ACTION eClassifierAction = eInvalidClassifierAction;
 	B_UINT16 u16PacketClassificationRuleIndex = 0;
 	int i;
-	stConvergenceSLTypes *psfCSType = NULL;
+	struct bcm_convergence_types *psfCSType = NULL;
 	S_PHS_RULE sPhsRule;
 	USHORT uVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value;
 	UINT UGIValue = 0;
@@ -915,7 +915,7 @@
 	if (!pstAddIndication->sfAuthorizedSet.bValid)
 		pstAddIndication->sfAuthorizedSet.bValid = 1;
 	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) {
-		stConvergenceSLTypes *psfCSType = NULL;
+		struct bcm_convergence_types *psfCSType = NULL;
 		psfCSType =  &pstAddIndication->sfAuthorizedSet.cConvergenceSLTypes[nIndex];
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "psfCSType = %p", psfCSType);
@@ -999,13 +999,10 @@
 #ifdef VERSION_D5
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
 				psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ",
+				6, psfCSType->cCPacketClassificationRule.
+					      u8IPv6FlowLable);
 #endif
 	}
 
@@ -1015,13 +1012,9 @@
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfAdmittedSet.u16CID);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X",
 			pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength);
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[0],
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[1],
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[2],
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[3],
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[4],
-			pstAddIndication->sfAdmittedSet.u8ServiceClassName[5]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,
+			"u8ServiceClassName: 0x%*ph",
+			6, pstAddIndication->sfAdmittedSet.u8ServiceClassName);
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfAdmittedSet.u8MBSService);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfAdmittedSet.u8QosParamSet);
@@ -1066,7 +1059,7 @@
 		nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF;
 
 	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) {
-		stConvergenceSLTypes *psfCSType = NULL;
+		struct bcm_convergence_types *psfCSType = NULL;
 
 		psfCSType =  &pstAddIndication->sfAdmittedSet.cConvergenceSLTypes[nIndex];
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>");
@@ -1074,10 +1067,10 @@
 				psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%02X",
 				psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%02X %02X %02X",
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
-				psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%*ph",
+				3, psfCSType->cCPacketClassificationRule.
+					      u8IPTypeOfService);
 		for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++)
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol);
 
@@ -1098,20 +1091,20 @@
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength: 0x%02X ",
 				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
 
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x %02X %02X %02X %02X ",
-				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
-				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
-				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
-				psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: "
+				"0x%*ph ", 4, psfCSType->
+						cCPacketClassificationRule.
+						u8ProtocolSourcePortRange);
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ",
 				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
 
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x %02X %02X %02X %02X ",
-				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
-				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
-				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
-				psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: "
+				"0x%*ph ", 4, psfCSType->
+						cCPacketClassificationRule.
+						u8ProtocolDestPortRange);
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ",
 				psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
@@ -1130,10 +1123,10 @@
 						u8EthernetSourceMACAddress);
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X %02X %02X",
-				psfCSType->cCPacketClassificationRule.u8Ethertype[0],
-				psfCSType->cCPacketClassificationRule.u8Ethertype[1],
-				psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8Ethertype[3]: 0x%*ph",
+				3, psfCSType->cCPacketClassificationRule.
+					      u8Ethertype);
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID);
@@ -1147,13 +1140,10 @@
 #ifdef VERSION_D5
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
 				psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-				psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+				DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ",
+				6, psfCSType->cCPacketClassificationRule.
+					      u8IPv6FlowLable);
 #endif
 	}
 
@@ -1162,13 +1152,9 @@
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfActiveSet.u32SFID);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfActiveSet.u16CID);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfActiveSet.u8ServiceClassNameLength);
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
-			pstAddIndication->sfActiveSet.u8ServiceClassName[0],
-			pstAddIndication->sfActiveSet.u8ServiceClassName[1],
-			pstAddIndication->sfActiveSet.u8ServiceClassName[2],
-			pstAddIndication->sfActiveSet.u8ServiceClassName[3],
-			pstAddIndication->sfActiveSet.u8ServiceClassName[4],
-			pstAddIndication->sfActiveSet.u8ServiceClassName[5]);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,
+			"u8ServiceClassName: 0x%*ph",
+			6, pstAddIndication->sfActiveSet.u8ServiceClassName);
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfActiveSet.u8MBSService);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfActiveSet.u8QosParamSet);
@@ -1212,7 +1198,7 @@
 		nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF;
 
 	for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++)	{
-		stConvergenceSLTypes *psfCSType = NULL;
+		struct bcm_convergence_types *psfCSType = NULL;
 
 		psfCSType =  &pstAddIndication->sfActiveSet.cConvergenceSLTypes[nIndex];
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>");
@@ -1314,7 +1300,7 @@
 
 static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter, ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer)
 {
-	UINT  nBytesToRead = sizeof(stServiceFlowParamSI);
+	UINT  nBytesToRead = sizeof(struct bcm_connect_mgr_params);
 
 	if (ulAddrSFParamSet == 0 || NULL == pucDestBuffer) {
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Got Param address as 0!!");
@@ -1331,7 +1317,7 @@
 
 static ULONG StoreSFParam(struct bcm_mini_adapter *Adapter, PUCHAR pucSrcBuffer, ULONG ulAddrSFParamSet)
 {
-	UINT nBytesToWrite = sizeof(stServiceFlowParamSI);
+	UINT nBytesToWrite = sizeof(struct bcm_connect_mgr_params);
 	int ret = 0;
 
 	if (ulAddrSFParamSet == 0 || NULL == pucSrcBuffer)
@@ -1348,8 +1334,8 @@
 ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBuffer, UINT *puBufferLength)
 {
 	stLocalSFAddIndicationAlt *pstAddIndicationAlt = NULL;
-	stLocalSFAddIndication *pstAddIndication = NULL;
-	stLocalSFDeleteRequest *pstDeletionRequest;
+	struct bcm_add_indication *pstAddIndication = NULL;
+	struct bcm_del_request *pstDeletionRequest;
 	UINT uiSearchRuleIndex;
 	ULONG ulSFID;
 
@@ -1360,7 +1346,7 @@
 	 * we can stop the further classifying the pkt for this SF.
 	 */
 	if (pstAddIndicationAlt->u8Type == DSD_REQ) {
-		pstDeletionRequest = (stLocalSFDeleteRequest *)pvBuffer;
+		pstDeletionRequest = (struct bcm_del_request *)pvBuffer;
 
 		ulSFID = ntohl(pstDeletionRequest->u32SFID);
 		uiSearchRuleIndex = SearchSfid(Adapter, ulSFID);
@@ -1379,12 +1365,12 @@
 	}
 	/* For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver! */
 
-	pstAddIndication = kmalloc(sizeof(*pstAddIndication), GFP_KERNEL);
+	pstAddIndication = kmalloc(sizeof(struct bcm_add_indication), GFP_KERNEL);
 	if (pstAddIndication == NULL)
 		return 0;
 
 	/* AUTHORIZED SET */
-	pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *)
+	pstAddIndication->psfAuthorizedSet = (struct bcm_connect_mgr_params *)
 			GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
 	if (!pstAddIndication->psfAuthorizedSet) {
 		kfree(pstAddIndication);
@@ -1398,10 +1384,10 @@
 	}
 
 	/* this can't possibly be right */
-	pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAuthorizedSet);
+	pstAddIndication->psfAuthorizedSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfAuthorizedSet);
 
 	if (pstAddIndicationAlt->u8Type == DSA_REQ) {
-		stLocalSFAddRequest AddRequest;
+		struct bcm_add_request AddRequest;
 
 		AddRequest.u8Type = pstAddIndicationAlt->u8Type;
 		AddRequest.eConnectionDir = pstAddIndicationAlt->u8Direction;
@@ -1409,8 +1395,8 @@
 		AddRequest.u16CID = pstAddIndicationAlt->u16CID;
 		AddRequest.u16VCID = pstAddIndicationAlt->u16VCID;
 		AddRequest.psfParameterSet = pstAddIndication->psfAuthorizedSet;
-		(*puBufferLength) = sizeof(stLocalSFAddRequest);
-		memcpy(pvBuffer, &AddRequest, sizeof(stLocalSFAddRequest));
+		(*puBufferLength) = sizeof(struct bcm_add_request);
+		memcpy(pvBuffer, &AddRequest, sizeof(struct bcm_add_request));
 		kfree(pstAddIndication);
 		return 1;
 	}
@@ -1426,7 +1412,7 @@
 	pstAddIndication->u8CC = pstAddIndicationAlt->u8CC;
 
 	/* ADMITTED SET */
-	pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *)
+	pstAddIndication->psfAdmittedSet = (struct bcm_connect_mgr_params *)
 		GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
 	if (!pstAddIndication->psfAdmittedSet) {
 		kfree(pstAddIndication);
@@ -1437,10 +1423,10 @@
 		return 0;
 	}
 
-	pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAdmittedSet);
+	pstAddIndication->psfAdmittedSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfAdmittedSet);
 
 	/* ACTIVE SET */
-	pstAddIndication->psfActiveSet = (stServiceFlowParamSI *)
+	pstAddIndication->psfActiveSet = (struct bcm_connect_mgr_params *)
 		GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID);
 	if (!pstAddIndication->psfActiveSet) {
 		kfree(pstAddIndication);
@@ -1451,10 +1437,10 @@
 		return 0;
 	}
 
-	pstAddIndication->psfActiveSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfActiveSet);
+	pstAddIndication->psfActiveSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfActiveSet);
 
-	(*puBufferLength) = sizeof(stLocalSFAddIndication);
-	*(stLocalSFAddIndication *)pvBuffer = *pstAddIndication;
+	(*puBufferLength) = sizeof(struct bcm_add_indication);
+	*(struct bcm_add_indication *)pvBuffer = *pstAddIndication;
 	kfree(pstAddIndication);
 	return 1;
 }
@@ -1463,10 +1449,10 @@
 *RestoreCmControlResponseMessage(register struct bcm_mini_adapter *Adapter, register PVOID pvBuffer)
 {
 	ULONG ulStatus = 0;
-	stLocalSFAddIndication *pstAddIndication = NULL;
+	struct bcm_add_indication *pstAddIndication = NULL;
 	stLocalSFAddIndicationAlt *pstAddIndicationDest = NULL;
 
-	pstAddIndication = (stLocalSFAddIndication *)(pvBuffer);
+	pstAddIndication = (struct bcm_add_indication *)(pvBuffer);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "=====>");
 	if ((pstAddIndication->u8Type == DSD_REQ) ||
 		(pstAddIndication->u8Type == DSD_RSP) ||
@@ -1553,7 +1539,7 @@
 	if (Adapter->astTargetDsxBuffer[0].ulTargetDsxBuffer)
 		return 1;
 
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of ServiceFlowParamSI): %zx ", sizeof(stServiceFlowParamSI));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of connection manager parameters): %zx ", sizeof(struct bcm_connect_mgr_params));
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Reading DSX buffer From Target location %x ", DSX_MESSAGE_EXCHANGE_BUFFER);
 
 	Status = rdmalt(Adapter, DSX_MESSAGE_EXCHANGE_BUFFER, (PUINT)&ulTargetDsxBuffersBase, sizeof(UINT));
@@ -1564,7 +1550,7 @@
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Base Address Of DSX  Target Buffer : 0x%lx", ulTargetDsxBuffersBase);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "Tgt Buffer is Now %lx :", ulTargetDsxBuffersBase);
-	ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / sizeof(stServiceFlowParamSI);
+	ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / sizeof(struct bcm_connect_mgr_params);
 
 	Adapter->ulTotalTargetBuffersAvailable =
 		ulCntTargetBuffers > MAX_TARGET_DSX_BUFFERS ?
@@ -1576,7 +1562,7 @@
 		Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer = ulTargetDsxBuffersBase;
 		Adapter->astTargetDsxBuffer[i].valid = 1;
 		Adapter->astTargetDsxBuffer[i].tid = 0;
-		ulTargetDsxBuffersBase += sizeof(stServiceFlowParamSI);
+		ulTargetDsxBuffersBase += sizeof(struct bcm_connect_mgr_params);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "  Target DSX Buffer %lx setup at 0x%lx",
 				i, Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer);
 	}
@@ -1647,7 +1633,7 @@
 BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter,  /* <Pointer to the Adapter structure */
 				PVOID pvBuffer /* Starting Address of the Buffer, that contains the AddIndication Data */)
 {
-	stServiceFlowParamSI *psfLocalSet = NULL;
+	struct bcm_connect_mgr_params *psfLocalSet = NULL;
 	stLocalSFAddIndicationAlt *pstAddIndication = NULL;
 	stLocalSFChangeIndicationAlt *pstChangeIndication = NULL;
 	struct bcm_leader *pLeader = NULL;
@@ -1658,7 +1644,7 @@
 	 */
 	pstAddIndication = RestoreCmControlResponseMessage(Adapter, pvBuffer);
 	if (pstAddIndication == NULL) {
-		ClearTargetDSXBuffer(Adapter, ((stLocalSFAddIndication *)pvBuffer)->u16TID, FALSE);
+		ClearTargetDSXBuffer(Adapter, ((struct bcm_add_indication *)pvBuffer)->u16TID, FALSE);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Error in restoring Service Flow param structure from DSx message");
 		return FALSE;
 	}
@@ -1870,10 +1856,10 @@
 		UINT uiSearchRuleIndex;
 		ULONG ulSFID;
 
-		pLeader->PLength = sizeof(stLocalSFDeleteIndication);
-		*((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((stLocalSFDeleteIndication *)pstAddIndication);
+		pLeader->PLength = sizeof(struct bcm_del_indication);
+		*((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((struct bcm_del_indication *)pstAddIndication);
 
-		ulSFID = ntohl(((stLocalSFDeleteIndication *)pstAddIndication)->u32SFID);
+		ulSFID = ntohl(((struct bcm_del_indication *)pstAddIndication)->u32SFID);
 		uiSearchRuleIndex = SearchSfid(Adapter, ulSFID);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD - Removing connection %x", uiSearchRuleIndex);
 
@@ -1884,7 +1870,7 @@
 		}
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC");
-		((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP;
+		((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP;
 		CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
 	}
 	case DSD_RSP:
@@ -1927,7 +1913,7 @@
 VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, PUINT puiBuffer)
 {
 	B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1));
-	stIM_SFHostNotify *pHostInfo = NULL;
+	struct bcm_stim_sfhostnotify *pHostInfo = NULL;
 	UINT uiSearchRuleIndex = 0;
 	ULONG ulSFID = 0;
 
@@ -1936,7 +1922,7 @@
 
 	while (u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES) {
 		u32NumofSFsinMsg--;
-		pHostInfo = (stIM_SFHostNotify *)puiBuffer;
+		pHostInfo = (struct bcm_stim_sfhostnotify *)puiBuffer;
 		puiBuffer = (PUINT)(pHostInfo + 1);
 
 		ulSFID = ntohl(pHostInfo->SFID);
diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h
index 4cc6f93..1c5a07c 100644
--- a/drivers/staging/bcm/CmHost.h
+++ b/drivers/staging/bcm/CmHost.h
@@ -35,8 +35,7 @@
     B_UINT16                        u16VCID;
 
 
-	/// \brief structure ParameterSet
-    stServiceFlowParamSI              sfParameterSet;
+	struct bcm_connect_mgr_params sfParameterSet;
 
     //USE_MEMORY_MANAGER();
 }stLocalSFAddRequestAlt;
@@ -50,12 +49,9 @@
     B_UINT16                        u16CID;
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;
-	/// \brief structure AuthorizedSet
-    stServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              sfAdmittedSet;
-	/// \brief structure ActiveSet
-    stServiceFlowParamSI              sfActiveSet;
+	struct bcm_connect_mgr_params sfAuthorizedSet;
+	struct bcm_connect_mgr_params sfAdmittedSet;
+	struct bcm_connect_mgr_params sfActiveSet;
 
 	B_UINT8 						u8CC;	/**<  Confirmation Code*/
 	B_UINT8 						u8Padd; 	/**<  8-bit Padding */
@@ -72,12 +68,9 @@
     B_UINT16                        u16CID;
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;
-    /// \brief structure AuthorizedSet
-    stServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              sfAdmittedSet;
-    /// \brief structure ActiveSet
-    stServiceFlowParamSI              sfActiveSet;
+	struct bcm_connect_mgr_params sfAuthorizedSet;
+	struct bcm_connect_mgr_params sfAdmittedSet;
+	struct bcm_connect_mgr_params sfActiveSet;
 }stLocalSFAddConfirmationAlt;
 
 
@@ -91,16 +84,13 @@
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;
 	/*
-	//Pointer location at which following Service Flow param Structure can be read
-	//from the target. We get only the address location and we need to read out the
-	//entire SF param structure at the given location on target
+	//Pointer location at which following connection manager param Structure can be read
+	//from the target. We only get the address location and we need to read out the
+	//entire connection manager param structure at the given location on target
 	*/
-    /// \brief structure AuthorizedSet
-    stServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              sfAdmittedSet;
-    /// \brief structure ParameterSet
-    stServiceFlowParamSI              sfActiveSet;
+	struct bcm_connect_mgr_params sfAuthorizedSet;
+	struct bcm_connect_mgr_params sfAdmittedSet;
+	struct bcm_connect_mgr_params sfActiveSet;
 
 	B_UINT8 						u8CC;	/**<  Confirmation Code*/
 	B_UINT8 						u8Padd; 	/**<  8-bit Padding */
@@ -117,12 +107,9 @@
     B_UINT16                        u16CID;
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;
-    /// \brief structure AuthorizedSet
-    stServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              sfAdmittedSet;
-    /// \brief structure ActiveSet
-    stServiceFlowParamSI              sfActiveSet;
+	struct bcm_connect_mgr_params sfAuthorizedSet;
+	struct bcm_connect_mgr_params sfAdmittedSet;
+	struct bcm_connect_mgr_params sfActiveSet;
 
 }stLocalSFChangeConfirmationAlt;
 
@@ -135,12 +122,9 @@
     B_UINT16                        u16CID;
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;
-    /// \brief structure AuthorizedSet
-    stServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              sfAdmittedSet;
-    /// \brief structure ActiveSet
-    stServiceFlowParamSI              sfActiveSet;
+	struct bcm_connect_mgr_params sfAuthorizedSet;
+	struct bcm_connect_mgr_params sfAdmittedSet;
+	struct bcm_connect_mgr_params sfActiveSet;
 
 	B_UINT8 						u8CC;	/**<  Confirmation Code*/
 	B_UINT8 						u8Padd; 	/**<  8-bit Padding */
diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c
index 8f85de6..b05f5f7 100644
--- a/drivers/staging/bcm/InterfaceInit.c
+++ b/drivers/staging/bcm/InterfaceInit.c
@@ -8,6 +8,7 @@
 	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
 	{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
 	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
+	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
@@ -669,16 +670,24 @@
 
 static __init int bcm_init(void)
 {
-	printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
-	printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
+	int retval;
+
+	pr_info("%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
+	pr_info("%s\n", DRV_COPYRIGHT);
 
 	bcm_class = class_create(THIS_MODULE, DRV_NAME);
 	if (IS_ERR(bcm_class)) {
-		printk(KERN_ERR DRV_NAME ": could not create class\n");
+		pr_err(DRV_NAME ": could not create class\n");
 		return PTR_ERR(bcm_class);
 	}
 
-	return usb_register(&usbbcm_driver);
+	retval = usb_register(&usbbcm_driver);
+	if (retval < 0) {
+		pr_err(DRV_NAME ": could not register usb driver\n");
+		class_destroy(bcm_class);
+		return retval;
+	}
+	return 0;
 }
 
 static __exit void bcm_exit(void)
diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h
index 058315a..866924e 100644
--- a/drivers/staging/bcm/InterfaceInit.h
+++ b/drivers/staging/bcm/InterfaceInit.h
@@ -1,27 +1,26 @@
 #ifndef _INTERFACE_INIT_H
 #define _INTERFACE_INIT_H
 
-#define BCM_USB_VENDOR_ID_T3 	0x198f
-#define BCM_USB_VENDOR_ID_FOXCONN       0x0489
-#define BCM_USB_VENDOR_ID_ZTE   0x19d2
+#define BCM_USB_VENDOR_ID_T3	0x198f
+#define BCM_USB_VENDOR_ID_FOXCONN	0x0489
+#define BCM_USB_VENDOR_ID_ZTE	0x19d2
 
-#define BCM_USB_PRODUCT_ID_T3 	0x0300
-#define BCM_USB_PRODUCT_ID_T3B 	0x0210
-#define BCM_USB_PRODUCT_ID_T3L 	0x0220
-#define BCM_USB_PRODUCT_ID_SM250 	0xbccd
-#define BCM_USB_PRODUCT_ID_SYM  0x15E
-#define BCM_USB_PRODUCT_ID_1901 0xe017
-#define BCM_USB_PRODUCT_ID_226  0x0132
-#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007
+#define BCM_USB_PRODUCT_ID_T3	0x0300
+#define BCM_USB_PRODUCT_ID_T3B	0x0210
+#define BCM_USB_PRODUCT_ID_T3L	0x0220
+#define BCM_USB_PRODUCT_ID_SM250	0xbccd
+#define BCM_USB_PRODUCT_ID_SYM	0x15E
+#define BCM_USB_PRODUCT_ID_1901	0xe017
+#define BCM_USB_PRODUCT_ID_226	0x0132 /* not sure if this is valid */
+#define BCM_USB_PRODUCT_ID_ZTE_226 0x172
+#define BCM_USB_PRODUCT_ID_ZTE_TU25	0x0007
 
-#define BCM_USB_MINOR_BASE 		192
+#define BCM_USB_MINOR_BASE	192
 
+int InterfaceInitialize(void);
 
-INT InterfaceInitialize(void);
+int InterfaceExit(void);
 
-INT InterfaceExit(void);
-
-INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter);
+int usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter);
 
 #endif
-
diff --git a/drivers/staging/bcm/Kconfig b/drivers/staging/bcm/Kconfig
index 96adb10..83c9752 100644
--- a/drivers/staging/bcm/Kconfig
+++ b/drivers/staging/bcm/Kconfig
@@ -1,6 +1,6 @@
 config BCM_WIMAX
        tristate "Beceem BCS200/BCS220-3 and BCSM250 wimax support"
-       depends on USB && NET && EXPERIMENTAL
+       depends on USB && NET
        default N
        help
          This is an experimental driver for the Beceem WIMAX chipset used
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index f545716..f13a958 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -752,7 +752,10 @@
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "AuthzSet: %x\n", Adapter->PackInfo[uiLoopIndex].bAuthorizedSet);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ClassifyPrority: %x\n", Adapter->PackInfo[uiLoopIndex].bClassifierPriority);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxLatency: %x\n", Adapter->PackInfo[uiLoopIndex].uiMaxLatency);
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ServiceClassName: %x %x %x %x\n", Adapter->PackInfo[uiLoopIndex].ucServiceClassName[0], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[1], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[2], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[3]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO,
+				DBG_LVL_ALL, "ServiceClassName: %*ph\n",
+				4, Adapter->PackInfo[uiLoopIndex].
+					    ucServiceClassName);
 /* BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bHeaderSuppressionEnabled :%X\n", Adapter->PackInfo[uiLoopIndex].bHeaderSuppressionEnabled);
  * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalTxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalTxBytes);
  * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalRxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalRxBytes);
diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c
index 4795742..6dc0bbc 100644
--- a/drivers/staging/bcm/PHSModule.c
+++ b/drivers/staging/bcm/PHSModule.c
@@ -66,7 +66,7 @@
 						BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF.
 
 Return:					STATUS_SUCCESS - If the send was successful.
-						Other          - If an error occured.
+						Other  - If an error occurred.
 */
 
 int PHSTransmit(struct bcm_mini_adapter *Adapter,
@@ -346,7 +346,7 @@
 
 
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successfull");
+	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful");
 	return STATUS_SUCCESS;
 }
 
diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h
index 3c8cc5b..3ec8f80 100644
--- a/drivers/staging/bcm/Prototypes.h
+++ b/drivers/staging/bcm/Prototypes.h
@@ -95,7 +95,7 @@
 int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo);
 
 void CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter,
-		CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex);
+		struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex);
 
 VOID ResetCounters(struct bcm_mini_adapter *Adapter);
 
diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c
index 5e603ce..27e8c89 100644
--- a/drivers/staging/bcm/Transmit.c
+++ b/drivers/staging/bcm/Transmit.c
@@ -1,162 +1,149 @@
 /**
-@file Transmit.c
-@defgroup tx_functions Transmission
-@section Queueing
-@dot
-digraph transmit1 {
-node[shape=box]
-edge[weight=5;color=red]
-
-bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
-GetPacketQueueIndex->IpVersion4[label="IPV4"]
-GetPacketQueueIndex->IpVersion6[label="IPV6"]
-}
-
-@enddot
-
-@section De-Queueing
-@dot
-digraph transmit2 {
-node[shape=box]
-edge[weight=5;color=red]
-interrupt_service_thread->transmit_packets
-tx_pkt_hdler->transmit_packets
-transmit_packets->CheckAndSendPacketFromIndex
-transmit_packets->UpdateTokenCount
-CheckAndSendPacketFromIndex->PruneQueue
-CheckAndSendPacketFromIndex->IsPacketAllowedForFlow
-CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"]
-SendControlPacket->bcm_cmd53
-CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"]
-SendPacketFromQueue->SetupNextSend->bcm_cmd53
-}
-@enddot
-*/
+ * @file Transmit.c
+ * @defgroup tx_functions Transmission
+ * @section Queueing
+ * @dot
+ * digraph transmit1 {
+ * node[shape=box]
+ * edge[weight=5;color=red]
+ *
+ * bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
+ * GetPacketQueueIndex->IpVersion4[label="IPV4"]
+ * GetPacketQueueIndex->IpVersion6[label="IPV6"]
+ * }
+ *
+ * @enddot
+ *
+ * @section De-Queueing
+ * @dot
+ * digraph transmit2 {
+ * node[shape=box]
+ * edge[weight=5;color=red]
+ * interrupt_service_thread->transmit_packets
+ * tx_pkt_hdler->transmit_packets
+ * transmit_packets->CheckAndSendPacketFromIndex
+ * transmit_packets->UpdateTokenCount
+ * CheckAndSendPacketFromIndex->PruneQueue
+ * CheckAndSendPacketFromIndex->IsPacketAllowedForFlow
+ * CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"]
+ * SendControlPacket->bcm_cmd53
+ * CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"]
+ * SendPacketFromQueue->SetupNextSend->bcm_cmd53
+ * }
+ * @enddot
+ */
 
 #include "headers.h"
 
-
 /**
-@ingroup ctrl_pkt_functions
-This function dispatches control packet to the h/w interface
-@return zero(success) or -ve value(failure)
-*/
-INT SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
+ * @ingroup ctrl_pkt_functions
+ * This function dispatches control packet to the h/w interface
+ * @return zero(success) or -ve value(failure)
+ */
+int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
 {
 	struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
-	if(!pControlPacket || !Adapter)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
+	if (!pControlPacket || !Adapter) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
 		return STATUS_FAILURE;
 	}
-	if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
-		((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
-    {
-    	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
-        return STATUS_FAILURE;
-    }
+	if ((atomic_read(&Adapter->CurrNumFreeTxDesc) <
+			((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))	{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
+		return STATUS_FAILURE;
+	}
 
 	/* Update the netdevice statistics */
 	/* Dump Packet  */
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
-	if(Adapter->device_removed)
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x", PLeader->Vcid);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x", PLeader->PLength);
+	if (Adapter->device_removed)
 		return 0;
 
 	if (netif_msg_pktdata(Adapter))
 		print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE,
-			       16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
+			16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
 
 	Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
-					pControlPacket, (PLeader->PLength + LEADER_SIZE));
+				pControlPacket, (PLeader->PLength + LEADER_SIZE));
 
 	atomic_dec(&Adapter->CurrNumFreeTxDesc);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
 	return STATUS_SUCCESS;
 }
 
 /**
-@ingroup tx_functions
-This function despatches the IP packets with the given vcid
-to the target via the host h/w interface.
-@return  zero(success) or -ve value(failure)
-*/
-INT SetupNextSend(struct bcm_mini_adapter *Adapter,  struct sk_buff *Packet, USHORT Vcid)
+ * @ingroup tx_functions
+ * This function despatches the IP packets with the given vcid
+ * to the target via the host h/w interface.
+ * @return  zero(success) or -ve value(failure)
+ */
+int SetupNextSend(struct bcm_mini_adapter *Adapter,  struct sk_buff *Packet, USHORT Vcid)
 {
-	int		status=0;
-	BOOLEAN bHeaderSupressionEnabled = FALSE;
-	B_UINT16            uiClassifierRuleID;
+	int	status = 0;
+	BOOLEAN	bHeaderSupressionEnabled = FALSE;
+	B_UINT16 uiClassifierRuleID;
 	u16	QueueIndex = skb_get_queue_mapping(Packet);
-	struct bcm_leader Leader={0};
+	struct bcm_leader Leader = {0};
 
-	if(Packet->len > MAX_DEVICE_DESC_SIZE)
-	{
+	if (Packet->len > MAX_DEVICE_DESC_SIZE) {
 		status = STATUS_FAILURE;
 		goto errExit;
 	}
 
 	/* Get the Classifier Rule ID */
-	uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
+	uiClassifierRuleID = *((UINT32 *) (Packet->cb) + SKB_CB_CLASSIFICATION_OFFSET);
 
 	bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
 		& Adapter->bPHSEnabled;
 
-	if(Adapter->device_removed)
-		{
+	if (Adapter->device_removed) {
 		status = STATUS_FAILURE;
 		goto errExit;
-		}
-
-	status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
-							(UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
-
-	if(status != STATUS_SUCCESS)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
-		goto errExit;
 	}
 
-	Leader.Vcid	= Vcid;
+	status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
+			(UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
 
-	if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
+	if (status != STATUS_SUCCESS) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
+		goto errExit;
+	}
+
+	Leader.Vcid = Vcid;
+
+	if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET))
 		Leader.Status = LEADER_STATUS_TCP_ACK;
 	else
 		Leader.Status = LEADER_STATUS;
 
-	if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
-	{
+	if (Adapter->PackInfo[QueueIndex].bEthCSSupport) {
 		Leader.PLength = Packet->len;
-		if(skb_headroom(Packet) < LEADER_SIZE)
-        {
-			if((status = skb_cow(Packet,LEADER_SIZE)))
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
+		if (skb_headroom(Packet) < LEADER_SIZE) {
+			status = skb_cow(Packet, LEADER_SIZE);
+			if (status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit : Failed To Increase headRoom\n");
 				goto errExit;
 			}
 		}
 		skb_push(Packet, LEADER_SIZE);
 		memcpy(Packet->data, &Leader, LEADER_SIZE);
-	}
-	else
-	{
+	} else {
 		Leader.PLength = Packet->len - ETH_HLEN;
 		memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
 	}
 
 	status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
-			Packet->data, (Leader.PLength + LEADER_SIZE));
-	if(status)
-	{
+					Packet->data, (Leader.PLength + LEADER_SIZE));
+	if (status) {
 		++Adapter->dev->stats.tx_errors;
 		if (netif_msg_tx_err(Adapter))
 			pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name,
 				status);
-	}
-	else
-	{
+	} else {
 		struct net_device_stats *netstats = &Adapter->dev->stats;
 		Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
 
@@ -175,7 +162,6 @@
 	atomic_dec(&Adapter->CurrNumFreeTxDesc);
 
 errExit:
-
 	dev_kfree_skb(Packet);
 	return status;
 }
@@ -188,73 +174,65 @@
 }
 
 /**
-@ingroup tx_functions
-Transmit thread
-*/
-int tx_pkt_handler(struct bcm_mini_adapter *Adapter  /**< pointer to adapter object*/
-				)
+ * @ingroup tx_functions
+ * Transmit thread
+ */
+int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/)
 {
 	int status = 0;
 
-	while(! kthread_should_stop()) {
+	while (!kthread_should_stop()) {
 		/* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
-		if(Adapter->LinkUpStatus)
+		if (Adapter->LinkUpStatus)
 			wait_event_timeout(Adapter->tx_packet_wait_queue,
-					   tx_pending(Adapter), msecs_to_jiffies(10));
+					tx_pending(Adapter), msecs_to_jiffies(10));
 		else
 			wait_event_interruptible(Adapter->tx_packet_wait_queue,
-						 tx_pending(Adapter));
+						tx_pending(Adapter));
 
 		if (Adapter->device_removed)
 			break;
 
-		if(Adapter->downloadDDR == 1)
-		{
-			Adapter->downloadDDR +=1;
+		if (Adapter->downloadDDR == 1) {
+			Adapter->downloadDDR += 1;
 			status = download_ddr_settings(Adapter);
-			if(status)
+			if (status)
 				pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
 			continue;
 		}
 
-		//Check end point for halt/stall.
-		if(Adapter->bEndPointHalted == TRUE)
-		{
+		/* Check end point for halt/stall. */
+		if (Adapter->bEndPointHalted == TRUE) {
 			Bcm_clear_halt_of_endpoints(Adapter);
 			Adapter->bEndPointHalted = FALSE;
 			StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
 		}
 
-		if(Adapter->LinkUpStatus && !Adapter->IdleMode)
-		{
-			if(atomic_read(&Adapter->TotalPacketCount))
-			{
+		if (Adapter->LinkUpStatus && !Adapter->IdleMode) {
+			if (atomic_read(&Adapter->TotalPacketCount))
 				update_per_sf_desc_cnts(Adapter);
-			}
 		}
 
-		if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
+		if (atomic_read(&Adapter->CurrNumFreeTxDesc) &&
 			Adapter->LinkStatus == SYNC_UP_REQUEST &&
-			!Adapter->bSyncUpRequestSent)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
+			!Adapter->bSyncUpRequestSent) {
+
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
 			LinkMessage(Adapter);
 		}
 
-		if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
-		{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
-    			Adapter->usIdleModePattern = ABORT_IDLE_MODE;
-				Adapter->bWakeUpDevice = TRUE;
-				wake_up(&Adapter->process_rx_cntrlpkt);
+		if ((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount)) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
+			Adapter->usIdleModePattern = ABORT_IDLE_MODE;
+			Adapter->bWakeUpDevice = TRUE;
+			wake_up(&Adapter->process_rx_cntrlpkt);
 		}
 
 		transmit_packets(Adapter);
-
 		atomic_set(&Adapter->TxPktAvail, 0);
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
 	Adapter->transmit_packet_thread = NULL;
 	return 0;
 }
diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h
index 7619e4b..990e809 100644
--- a/drivers/staging/bcm/cntrl_SignalingInterface.h
+++ b/drivers/staging/bcm/cntrl_SignalingInterface.h
@@ -1,423 +1,311 @@
 #ifndef CNTRL_SIGNALING_INTERFACE_
 #define CNTRL_SIGNALING_INTERFACE_
 
+#define DSA_REQ			11
+#define DSA_RSP			12
+#define DSA_ACK			13
+#define DSC_REQ			14
+#define DSC_RSP			15
+#define DSC_ACK			16
+#define DSD_REQ			17
+#define DSD_RSP			18
+#define DSD_ACK			19
+#define MAX_CLASSIFIERS_IN_SF	4
 
+#define MAX_STRING_LEN			20
+#define MAX_PHS_LENGTHS			255
+#define VENDOR_PHS_PARAM_LENGTH		10
+#define MAX_NUM_ACTIVE_BS		10
+#define AUTH_TOKEN_LENGTH		10
+#define NUM_HARQ_CHANNELS		16 /* Changed from 10 to 16 to accommodate all HARQ channels */
+#define VENDOR_CLASSIFIER_PARAM_LENGTH	1  /* Changed the size to 1 byte since we dnt use it */
+#define  VENDOR_SPECIF_QOS_PARAM	1
+#define VENDOR_PHS_PARAM_LENGTH		10
+#define MBS_CONTENTS_ID_LENGTH		10
+#define GLOBAL_SF_CLASSNAME_LENGTH	6
 
+#define TYPE_OF_SERVICE_LENGTH		3
+#define IP_MASKED_SRC_ADDRESS_LENGTH	32
+#define IP_MASKED_DEST_ADDRESS_LENGTH	32
+#define PROTOCOL_SRC_PORT_RANGE_LENGTH	4
+#define PROTOCOL_DEST_PORT_RANGE_LENGTH	4
+#define ETHERNET_DEST_MAC_ADDR_LENGTH	12
+#define ETHERNET_SRC_MAC_ADDR_LENGTH	12
+#define NUM_ETHERTYPE_BYTES		3
+#define NUM_IPV6_FLOWLABLE_BYTES	3
 
-#define DSA_REQ 11
-#define DSA_RSP 12
-#define DSA_ACK 13
-#define DSC_REQ 14
-#define DSC_RSP 15
-#define DSC_ACK 16
-#define DSD_REQ 17
-#define DSD_RSP 18
-#define DSD_ACK 19
-#define MAX_CLASSIFIERS_IN_SF  4
-
-
-#define MAX_STRING_LEN 20
-#define MAX_PHS_LENGTHS 255
-#define VENDOR_PHS_PARAM_LENGTH 10
-#define MAX_NUM_ACTIVE_BS 10
-#define AUTH_TOKEN_LENGTH	10
-#define NUM_HARQ_CHANNELS	16	//Changed from 10 to 16 to accommodate all HARQ channels
-#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 //Changed the size to 1 byte since we dnt use it
-#define  VENDOR_SPECIF_QOS_PARAM 1
-#define VENDOR_PHS_PARAM_LENGTH	10
-#define MBS_CONTENTS_ID_LENGTH	10
-#define GLOBAL_SF_CLASSNAME_LENGTH 6
-
-#define TYPE_OF_SERVICE_LENGTH				3
-#define IP_MASKED_SRC_ADDRESS_LENGTH			32
-#define IP_MASKED_DEST_ADDRESS_LENGTH		32
-#define PROTOCOL_SRC_PORT_RANGE_LENGTH		4
-#define PROTOCOL_DEST_PORT_RANGE_LENGTH		4
-#define ETHERNET_DEST_MAC_ADDR_LENGTH		12
-#define ETHERNET_SRC_MAC_ADDR_LENGTH		12
-#define NUM_ETHERTYPE_BYTES  3
-#define NUM_IPV6_FLOWLABLE_BYTES 3
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////structure Definitions///////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-/// \brief class cCPacketClassificationRule
-struct _stCPacketClassificationRuleSI{
-
-	/**  16bit UserPriority Of The Service Flow*/
-    B_UINT16                        u16UserPriority;
-	/**  16bit VLANID Of The Service Flow*/
-    B_UINT16                        u16VLANID;
-	/**  16bit Packet Classification RuleIndex Of The Service Flow*/
-    B_UINT16                        u16PacketClassificationRuleIndex;
-	/**  8bit Classifier Rule Priority Of The Service Flow*/
-    B_UINT8                         u8ClassifierRulePriority;
-	/**  Length of IP TypeOfService field*/
-	B_UINT8                         u8IPTypeOfServiceLength;
-	/**  3bytes IP TypeOfService */
-    B_UINT8                         u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH];
-	/** Protocol used in classification of Service Flow*/
-    B_UINT8                         u8Protocol;
-	/**  Length of IP Masked Source Address */
-    B_UINT8                         u8IPMaskedSourceAddressLength;
-	/**  IP Masked Source Address used in classification for the Service Flow*/
-    B_UINT8                         u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH];
-	/**  Length of IP Destination Address */
-    B_UINT8                         u8IPDestinationAddressLength;
-	/**  IP Destination Address used in classification for the Service Flow*/
-    B_UINT8                         u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH];
-	/** Length of Protocol Source Port Range */
-    B_UINT8                         u8ProtocolSourcePortRangeLength;
-	/**  Protocol Source Port Range used in the Service Flow*/
-    B_UINT8                         u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH];
-	/** Length of Protocol Dest Port Range */
-    B_UINT8                         u8ProtocolDestPortRangeLength;
-	/**  Protocol Dest Port Range used in the Service Flow*/
-    B_UINT8                         u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH];
-	/** Length of Ethernet Destination MAC Address  */
-    B_UINT8                         u8EthernetDestMacAddressLength;
-	/**  Ethernet Destination MAC Address  used in classification of the Service Flow*/
-    B_UINT8                         u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH];
-	/** Length of Ethernet Source MAC Address  */
-    B_UINT8                         u8EthernetSourceMACAddressLength;
-	/**  Ethernet Source MAC Address  used in classification of the Service Flow*/
-    B_UINT8                         u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH];
-	/**  Length of Ethertype */
-	B_UINT8                         u8EthertypeLength;
-	/**  3bytes Ethertype Of The Service Flow*/
-    B_UINT8                         u8Ethertype[NUM_ETHERTYPE_BYTES];
-	/**  8bit Associated PHSI Of The Service Flow*/
-    B_UINT8                         u8AssociatedPHSI;
-	/** Length of Vendor Specific Classifier Param length Of The Service Flow*/
-    B_UINT8                         u8VendorSpecificClassifierParamLength;
-	/**  Vendor Specific Classifier Param Of The Service Flow*/
-    B_UINT8                         u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH];
-    /** Length Of IPv6 Flow Lable of the Service Flow*/
-    B_UINT8                         u8IPv6FlowLableLength;
-	/**  IPv6 Flow Lable Of The Service Flow*/
-    B_UINT8                         u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES];
-	/**  Action associated with the classifier rule*/
-    B_UINT8							u8ClassifierActionRule;
-    B_UINT16							u16ValidityBitMap;
+struct bcm_packet_class_rules {
+	/* 16bit UserPriority Of The Service Flow */
+	B_UINT16 u16UserPriority;
+	/* 16bit VLANID Of The Service Flow */
+	B_UINT16 u16VLANID;
+	/* 16bit Packet Classification RuleIndex Of The Service Flow */
+	B_UINT16 u16PacketClassificationRuleIndex;
+	/* 8bit Classifier Rule Priority Of The Service Flow */
+	B_UINT8 u8ClassifierRulePriority;
+	/* Length of IP TypeOfService field */
+	B_UINT8 u8IPTypeOfServiceLength;
+	/* 3bytes IP TypeOfService */
+	B_UINT8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH];
+	/* Protocol used in classification of Service Flow */
+	B_UINT8 u8Protocol;
+	/* Length of IP Masked Source Address */
+	B_UINT8 u8IPMaskedSourceAddressLength;
+	/* IP Masked Source Address used in classification for the Service Flow */
+	B_UINT8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH];
+	/* Length of IP Destination Address */
+	B_UINT8 u8IPDestinationAddressLength;
+	/* IP Destination Address used in classification for the Service Flow */
+	B_UINT8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH];
+	/* Length of Protocol Source Port Range */
+	B_UINT8 u8ProtocolSourcePortRangeLength;
+	/* Protocol Source Port Range used in the Service Flow */
+	B_UINT8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH];
+	/* Length of Protocol Dest Port Range */
+	B_UINT8 u8ProtocolDestPortRangeLength;
+	/* Protocol Dest Port Range used in the Service Flow */
+	B_UINT8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH];
+	/* Length of Ethernet Destination MAC Address */
+	B_UINT8 u8EthernetDestMacAddressLength;
+	/* Ethernet Destination MAC Address  used in classification of the Service Flow */
+	B_UINT8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH];
+	/* Length of Ethernet Source MAC Address */
+	B_UINT8 u8EthernetSourceMACAddressLength;
+	/* Ethernet Source MAC Address  used in classification of the Service Flow */
+	B_UINT8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH];
+	/* Length of Ethertype */
+	B_UINT8 u8EthertypeLength;
+	/* 3bytes Ethertype Of The Service Flow */
+	B_UINT8 u8Ethertype[NUM_ETHERTYPE_BYTES];
+	/* 8bit Associated PHSI Of The Service Flow */
+	B_UINT8 u8AssociatedPHSI;
+	/* Length of Vendor Specific Classifier Param length Of The Service Flow */
+	B_UINT8 u8VendorSpecificClassifierParamLength;
+	/* Vendor Specific Classifier Param Of The Service Flow */
+	B_UINT8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH];
+	/* Length Of IPv6 Flow Lable of the Service Flow */
+	B_UINT8 u8IPv6FlowLableLength;
+	/* IPv6 Flow Lable Of The Service Flow */
+	B_UINT8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES];
+	/* Action associated with the classifier rule */
+	B_UINT8 u8ClassifierActionRule;
+	B_UINT16 u16ValidityBitMap;
 };
-typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI;
 
-/// \brief class CPhsRuleSI
-typedef struct _stPhsRuleSI {
-	/**  8bit PHS Index Of The Service Flow*/
-    B_UINT8                         u8PHSI;
-	/**  PHSF Length Of The Service Flow*/
-    B_UINT8                         u8PHSFLength;
-    /** String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS*/
-    B_UINT8                         u8PHSF[MAX_PHS_LENGTHS];
-	/**  PHSM Length Of The Service Flow*/
-    B_UINT8                         u8PHSMLength;
-	/**  PHS Mask for the SF*/
-    B_UINT8                         u8PHSM[MAX_PHS_LENGTHS];
-	/**  8bit Total number of bytes to be suppressed for the Service Flow*/
-    B_UINT8                         u8PHSS;
-	/**  8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */
-    B_UINT8                         u8PHSV;
-	/**  Vendor Specific PHS param Length Of The Service Flow*/
-    B_UINT8                         u8VendorSpecificPHSParamsLength;
-	/**  Vendor Specific PHS param Of The Service Flow*/
-    B_UINT8                         u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
-
-	B_UINT8                         u8Padding[2];
-}stPhsRuleSI,*pstPhsRuleSI;
-typedef stPhsRuleSI CPhsRuleSI;
-
-/// \brief structure cConvergenceSLTypes
-struct _stConvergenceSLTypes{
-	/**  8bit Phs Classfier Action Of The Service Flow*/
-    B_UINT8                         u8ClassfierDSCAction;
-	/**  8bit Phs DSC Action Of The Service Flow*/
-    B_UINT8                         u8PhsDSCAction;
-	/**   16bit Padding */
-    B_UINT8                         u8Padding[2];
-    /// \brief class cCPacketClassificationRule
-    stCPacketClassificationRuleSI     cCPacketClassificationRule;
-    /// \brief class CPhsRuleSI
-     struct _stPhsRuleSI		cPhsRule;
+struct bcm_phs_rules {
+	/* 8bit PHS Index Of The Service Flow */
+	B_UINT8 u8PHSI;
+	/* PHSF Length Of The Service Flow */
+	B_UINT8 u8PHSFLength;
+	/* String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS */
+	B_UINT8 u8PHSF[MAX_PHS_LENGTHS];
+	/* PHSM Length Of The Service Flow */
+	B_UINT8 u8PHSMLength;
+	/* PHS Mask for the SF */
+	B_UINT8 u8PHSM[MAX_PHS_LENGTHS];
+	/* 8bit Total number of bytes to be suppressed for the Service Flow */
+	B_UINT8 u8PHSS;
+	/* 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */
+	B_UINT8 u8PHSV;
+	/* Vendor Specific PHS param Length Of The Service Flow */
+	B_UINT8 u8VendorSpecificPHSParamsLength;
+	/* Vendor Specific PHS param Of The Service Flow */
+	B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
+	B_UINT8 u8Padding[2];
 };
-typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes;
 
+struct bcm_convergence_types {
+	/* 8bit Phs Classfier Action Of The Service Flow */
+	B_UINT8 u8ClassfierDSCAction;
+	/* 8bit Phs DSC Action Of The Service Flow */
+	B_UINT8 u8PhsDSCAction;
+	/* 16bit Padding */
+	B_UINT8 u8Padding[2];
+	/* Packet classification rules structure */
+	struct bcm_packet_class_rules cCPacketClassificationRule;
+	/* Payload header suppression rules structure */
+	struct bcm_phs_rules cPhsRule;
+};
 
-/// \brief structure CServiceFlowParamSI
-typedef struct _stServiceFlowParamSI{
+struct bcm_connect_mgr_params {
+	/* 32bitSFID Of The Service Flow */
+	B_UINT32 u32SFID;
+	/* 32bit Maximum Sustained Traffic Rate of the Service Flow */
+	B_UINT32 u32MaxSustainedTrafficRate;
+	/* 32bit Maximum Traffic Burst allowed for the Service Flow */
+	B_UINT32 u32MaxTrafficBurst;
+	/* 32bit Minimum Reserved Traffic Rate of the Service Flow */
+	B_UINT32 u32MinReservedTrafficRate;
+	/* 32bit Tolerated Jitter of the Service Flow */
+	B_UINT32 u32ToleratedJitter;
+	/* 32bit Maximum Latency of the Service Flow */
+	B_UINT32 u32MaximumLatency;
+	/* 16bitCID Of The Service Flow */
+	B_UINT16 u16CID;
+	/* 16bit SAID on which the service flow being set up shall be mapped */
+	B_UINT16 u16TargetSAID;
+	/* 16bit  ARQ window size negotiated */
+	B_UINT16 u16ARQWindowSize;
+	/* 16bit Total Tx delay incl sending, receiving & processing delays */
+	B_UINT16 u16ARQRetryTxTimeOut;
+	/* 16bit Total Rx delay incl sending, receiving & processing delays */
+	B_UINT16 u16ARQRetryRxTimeOut;
+	/* 16bit ARQ block lifetime */
+	B_UINT16 u16ARQBlockLifeTime;
+	/* 16bit ARQ Sync loss timeout */
+	B_UINT16 u16ARQSyncLossTimeOut;
+	/* 16bit ARQ Purge timeout */
+	B_UINT16 u16ARQRxPurgeTimeOut;
+	/* TODO::Remove this once we move to a new CORR2 driver
+	 * brief Size of an ARQ block
+	 */
+	B_UINT16 u16ARQBlockSize;
+	/* #endif */
+	/* 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP */
+	B_UINT16 u16SDUInterArrivalTime;
+	/* 16bit Specifies the time base for rate measurement */
+	B_UINT16 u16TimeBase;
+	/* 16bit Interval b/w Successive Grant oppurtunities */
+	B_UINT16 u16UnsolicitedGrantInterval;
+	/* 16bit Interval b/w Successive Polling grant oppurtunities */
+	B_UINT16 u16UnsolicitedPollingInterval;
+	/* internal var to get the overhead */
+	B_UINT16 u16MacOverhead;
+	/* MBS contents Identifier */
+	B_UINT16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH];
+	/* MBS contents Identifier length */
+	B_UINT8 u8MBSContentsIDLength;
+	/* ServiceClassName Length Of The Service Flow */
+	B_UINT8 u8ServiceClassNameLength;
+	/* 32bytes ServiceClassName Of The Service Flow */
+	B_UINT8 u8ServiceClassName[32];
+	/* 8bit Indicates whether or not MBS service is requested for this Serivce Flow */
+	B_UINT8 u8MBSService;
+	/* 8bit QOS Parameter Set specifies proper application of QoS parameters to Provisioned, Admitted and Active sets */
+	B_UINT8 u8QosParamSet;
+	/* 8bit Traffic Priority Of the Service Flow */
+	B_UINT8 u8TrafficPriority;
+	/* 8bit Uplink Grant Scheduling Type of The Service Flow */
+	B_UINT8 u8ServiceFlowSchedulingType;
+	/* 8bit Request transmission Policy of the Service Flow */
+	B_UINT8 u8RequesttransmissionPolicy;
+	/* 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */
+	B_UINT8 u8FixedLengthVSVariableLengthSDUIndicator;
+	/* 8bit Length of the SDU for a fixed length SDU service flow */
+	B_UINT8 u8SDUSize;
+	/* 8bit Indicates whether or not ARQ is requested for this connection */
+	B_UINT8 u8ARQEnable;
+	/* < 8bit Indicates whether or not data has tobe delivered in order to higher layer */
+	B_UINT8 u8ARQDeliverInOrder;
+	/* 8bit Receiver ARQ ACK processing time */
+	B_UINT8 u8RxARQAckProcessingTime;
+	/* 8bit Convergence Sublayer Specification Of The Service Flow */
+	B_UINT8 u8CSSpecification;
+	/* 8 bit Type of data delivery service */
+	B_UINT8 u8TypeOfDataDeliveryService;
+	/* 8bit Specifies whether a service flow may generate Paging */
+	B_UINT8 u8PagingPreference;
+	/* 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */
+	B_UINT8 u8MBSZoneIdentifierassignment;
+	/* 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode */
+	B_UINT8 u8TrafficIndicationPreference;
+	/* 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */
+	B_UINT8 u8GlobalServicesClassNameLength;
+	/* 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */
+	B_UINT8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH];
+	/* 8bit Indicates whether or not SN feedback is enabled for the conn */
+	B_UINT8 u8SNFeedbackEnabled;
+	/* Indicates the size of the Fragment Sequence Number for the connection */
+	B_UINT8 u8FSNSize;
+	/* 8bit Number of CIDs in active BS list */
+	B_UINT8 u8CIDAllocation4activeBSsLength;
+	/* CIDs of BS in the active list */
+	B_UINT8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS];
+	/* Specifies if PDU extended subheader should be applied on every PDU on this conn */
+	B_UINT8 u8PDUSNExtendedSubheader4HarqReordering;
+	/* 8bit Specifies whether the connection uses HARQ or not */
+	B_UINT8 u8HARQServiceFlows;
+	/* Specifies the length of Authorization token */
+	B_UINT8 u8AuthTokenLength;
+	/* Specifies the Authorization token */
+	B_UINT8 u8AuthToken[AUTH_TOKEN_LENGTH];
+	/* specifes Number of HARQ channels used to carry data length */
+	B_UINT8 u8HarqChannelMappingLength;
+	/* specifes HARQ channels used to carry data */
+	B_UINT8 u8HARQChannelMapping[NUM_HARQ_CHANNELS];
+	/* 8bit Length of Vendor Specific QoS Params */
+	B_UINT8 u8VendorSpecificQoSParamLength;
+	/* 1byte  Vendor Specific QoS Param Of The Service Flow */
+	B_UINT8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM];
+	/* indicates total classifiers in the SF */
+	B_UINT8 u8TotalClassifiers;  /* < Total number of valid classifiers */
+	B_UINT8 bValid;	/* < Validity flag */
+	B_UINT8 u8Padding;	 /* < Padding byte */
+	/*
+	 * Structure for Convergence SubLayer Types with a maximum of 4 classifiers
+	 */
+	struct bcm_convergence_types cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
+};
 
-     /**  32bitSFID Of The Service Flow*/
-    B_UINT32                        u32SFID;
+struct bcm_add_request {
+	B_UINT8 u8Type;	/* < Type */
+	B_UINT8 eConnectionDir; /* < Connection direction */
+	/* brief 16 bit TID */
+	B_UINT16 u16TID; /* < 16bit TID */
+	/* brief 16bitCID */
+	B_UINT16 u16CID; /* < 16bit CID */
+	/* brief 16bitVCID */
+	B_UINT16 u16VCID; /* < 16bit VCID */
+	struct bcm_connect_mgr_params *psfParameterSet; /* < connection manager parameters */
+};
 
-     /**  32bit Maximum Sustained Traffic Rate of the Service Flow*/
-    B_UINT32                        u32MaxSustainedTrafficRate;
+struct bcm_add_indication {
+	B_UINT8 u8Type;	/* < Type */
+	B_UINT8 eConnectionDir;	/* < Connection Direction */
+	/* brief 16 bit TID */
+	B_UINT16 u16TID; /* < TID */
+	/* brief 16bitCID */
+	B_UINT16 u16CID; /* < 16bitCID */
+	/* brief 16bitVCID */
+	B_UINT16 u16VCID; /* < 16bitVCID */
+	struct bcm_connect_mgr_params *psfAuthorizedSet; /* Authorized set of connection manager parameters */
+	struct bcm_connect_mgr_params *psfAdmittedSet; /* Admitted set of connection manager parameters */
+	struct bcm_connect_mgr_params *psfActiveSet; /* Activeset of connection manager parameters */
+	B_UINT8 u8CC; /* <Confirmation Code */
+	B_UINT8 u8Padd; /* < 8-bit Padding */
+	B_UINT16 u16Padd; /* < 16 bit Padding */
+};
 
-     /**  32bit Maximum Traffic Burst allowed for the Service Flow*/
-    B_UINT32                        u32MaxTrafficBurst;
+struct bcm_del_request {
+	B_UINT8 u8Type; /* < Type */
+	B_UINT8 u8Padding; /* < Padding byte */
+	B_UINT16 u16TID; /* < TID */
+	/* brief 32bitSFID */
+	B_UINT32 u32SFID; /* < SFID */
+};
 
-    /**  32bit Minimum Reserved Traffic Rate of the Service Flow*/
-    B_UINT32                        u32MinReservedTrafficRate;
+struct bcm_del_indication {
+	B_UINT8 u8Type;	/* < Type */
+	B_UINT8 u8Padding; /* < Padding */
+	B_UINT16 u16TID; /* < TID */
+	/* brief 16bitCID */
+	B_UINT16 u16CID; /* < CID */
+	/* brief 16bitVCID */
+	B_UINT16 u16VCID; /* < VCID */
+	/* brief 32bitSFID */
+	B_UINT32 u32SFID; /* < SFID */
+	/* brief 8bit Confirmation code */
+	B_UINT8 u8ConfirmationCode; /* < Confirmation code */
+	B_UINT8 u8Padding1[3]; /* < 3 byte Padding */
+};
 
-	/**  32bit Tolerated Jitter of the Service Flow*/
-    	B_UINT32                        u32ToleratedJitter;
-
-   /**  32bit Maximum Latency of the Service Flow*/
-    B_UINT32                        u32MaximumLatency;
-
-	/**  16bitCID Of The Service Flow*/
-    B_UINT16                        u16CID;
-
-     /**  16bit SAID on which the service flow being set up shall be mapped*/
-    B_UINT16                        u16TargetSAID;
-
-	/** 16bit  ARQ window size negotiated*/
-    B_UINT16                        u16ARQWindowSize;
-
-     /**  16bit Total Tx delay incl sending, receiving & processing delays 	*/
-    B_UINT16                        u16ARQRetryTxTimeOut;
-
-	/**  16bit Total Rx delay incl sending, receiving & processing delays 	*/
-    B_UINT16                        u16ARQRetryRxTimeOut;
-
-	/**  16bit ARQ block lifetime	*/
-    B_UINT16                        u16ARQBlockLifeTime;
-
-	/**  16bit ARQ Sync loss timeout*/
-    B_UINT16                        u16ARQSyncLossTimeOut;
-
-	 /**  16bit ARQ Purge timeout */
-    B_UINT16                        u16ARQRxPurgeTimeOut;
-//TODO::Remove this once we move to a new CORR2 driver
-    /// \brief Size of an ARQ block
-    B_UINT16                        u16ARQBlockSize;
-
-//#endif
-	/**  16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP*/
-	B_UINT16                        u16SDUInterArrivalTime;
-
-	/**  16bit Specifies the time base for rate measurement 	*/
-	B_UINT16                        u16TimeBase;
-
-	 /** 16bit Interval b/w Successive Grant oppurtunities*/
-	B_UINT16                        u16UnsolicitedGrantInterval;
-
-	/** 16bit Interval b/w Successive Polling grant oppurtunities*/
-	B_UINT16						u16UnsolicitedPollingInterval;
-
-	 /**   internal var to get the overhead */
-	B_UINT16						u16MacOverhead;
-
-	 /**  MBS contents Identifier*/
-	B_UINT16						u16MBSContentsID[MBS_CONTENTS_ID_LENGTH];
-
-	/**  MBS contents Identifier length*/
-	B_UINT8							u8MBSContentsIDLength;
-
-	/**	 ServiceClassName Length Of The Service Flow*/
-    B_UINT8                         u8ServiceClassNameLength;
-
-	/**  32bytes ServiceClassName Of The Service Flow*/
-    B_UINT8                         u8ServiceClassName[32];
-
-	/**  8bit Indicates whether or not MBS service is requested for this Serivce Flow*/
-	B_UINT8							u8MBSService;
-
-    /**  8bit QOS Parameter Set specifies proper application of QoS paramters to Provisioned, Admitted and Active sets*/
-    B_UINT8                         u8QosParamSet;
-
-   /**  8bit Traffic Priority Of the Service Flow */
-    B_UINT8                         u8TrafficPriority;
-
-   /**  8bit Uplink Grant Scheduling Type of The Service Flow */
-    B_UINT8                         u8ServiceFlowSchedulingType;
-
-  /**  8bit Request transmission Policy of the Service Flow*/
-    B_UINT8							u8RequesttransmissionPolicy;
-
-	/**  8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */
-    B_UINT8                         u8FixedLengthVSVariableLengthSDUIndicator;
-
-	/**  8bit Length of the SDU for a fixed length SDU service flow*/
-	B_UINT8                         u8SDUSize;
-
-	 /** 8bit Indicates whether or not ARQ is requested for this connection*/
-       B_UINT8                         u8ARQEnable;
-
-	/**<  8bit Indicates whether or not data has tobe delivered in order to higher layer*/
-       B_UINT8                         u8ARQDeliverInOrder;
-
-	/**  8bit Receiver ARQ ACK processing time */
-	B_UINT8                         u8RxARQAckProcessingTime;
-
-	/**  8bit Convergence Sublayer Specification Of The Service Flow*/
-       B_UINT8                         u8CSSpecification;
-
-	 /**  8 bit Type of data delivery service*/
-	B_UINT8                         u8TypeOfDataDeliveryService;
-
-	/** 8bit Specifies whether a service flow may generate Paging	*/
-	B_UINT8                         u8PagingPreference;
-
-	/**  8bit Indicates the MBS Zone through which the connection or virtual connection is valid	*/
-       B_UINT8                         u8MBSZoneIdentifierassignment;
-
-       /**  8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode*/
-	B_UINT8                         u8TrafficIndicationPreference;
-
-	/** 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF	*/
-	B_UINT8                         u8GlobalServicesClassNameLength;
-
-	 /**  6 byte Speciifes the predefined Global QoS parameter set encoding for this SF	*/
-	B_UINT8                         u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH];
-
-	 /**  8bit Indicates whether or not SN feedback is enabled for the conn	*/
-	B_UINT8                         u8SNFeedbackEnabled;
-
-	 /**  Indicates the size of the Fragment Sequence Number for the connection	*/
-	B_UINT8                         u8FSNSize;
-
-	/** 8bit Number of CIDs in active BS list 	*/
-	B_UINT8							u8CIDAllocation4activeBSsLength;
-
-	/**  CIDs of BS in the active list	*/
-	B_UINT8							u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS];
-
-	 /**  Specifies if PDU extended subheader should be applied on every PDU on this conn*/
-	B_UINT8                         u8PDUSNExtendedSubheader4HarqReordering;
-
-	 /**  8bit Specifies whether the connection uses HARQ or not	*/
-	B_UINT8                         u8HARQServiceFlows;
-
-	/**  Specifies the length of Authorization token*/
-	B_UINT8							u8AuthTokenLength;
-
-	/**  Specifies the Authorization token*/
-	B_UINT8							u8AuthToken[AUTH_TOKEN_LENGTH];
-
-	/**  specifes Number of HARQ channels used to carry data length*/
-	B_UINT8							u8HarqChannelMappingLength;
-
-	 /**  specifes HARQ channels used to carry data*/
-	B_UINT8							u8HARQChannelMapping[NUM_HARQ_CHANNELS];
-
-	/**  8bit Length of Vendor Specific QoS Params */
-    B_UINT8                         u8VendorSpecificQoSParamLength;
-
-	/** 1byte  Vendor Specific QoS Param Of The Service Flow*/
-    B_UINT8                          u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM];
-
-	// indicates total classifiers in the SF
-	B_UINT8                         u8TotalClassifiers;  /**< Total number of valid classifiers*/
-	B_UINT8							bValid;	/**<  Validity flag */
-	B_UINT8				u8Padding;	 /**<  Padding byte*/
-
-/**
-Structure for Convergence SubLayer Types with a maximum of 4 classifiers
-*/
-	stConvergenceSLTypes		cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
-
-} stServiceFlowParamSI, *pstServiceFlowParamSI;
-typedef stServiceFlowParamSI CServiceFlowParamSI;
-
-/**
-structure stLocalSFAddRequest
-*/
-typedef struct _stLocalSFAddRequest{
-
-	B_UINT8                         u8Type;	/**<  Type*/
-	B_UINT8      eConnectionDir;		/**<  Connection direction*/
-	/// \brief 16 bit TID
-	B_UINT16                        u16TID;	/**<  16bit TID*/
-	/// \brief 16bitCID
-    	B_UINT16                        u16CID;	/**<  16bit CID*/
-	/// \brief 16bitVCID
-	B_UINT16                        u16VCID;	/**<  16bit VCID*/
-    /// \brief structure ParameterSet
-
-	stServiceFlowParamSI	*psfParameterSet;	/**<  structure ParameterSet*/
-
-}stLocalSFAddRequest, *pstLocalSFAddRequest;
-
-
-/**
-structure stLocalSFAddIndication
-*/
-typedef struct _stLocalSFAddIndication{
-
-	B_UINT8                         u8Type;	/**<  Type*/
-	B_UINT8      eConnectionDir;	/**<  Connection Direction*/
-	/// \brief 16 bit TID
-	B_UINT16                         u16TID;	/**<  TID*/
-    /// \brief 16bitCID
-    B_UINT16                        u16CID;		/**<  16bitCID*/
-    /// \brief 16bitVCID
-    B_UINT16                        u16VCID;	 /**<  16bitVCID*/
-
-
-    /// \brief structure AuthorizedSet
-    /// \brief structure AuthorizedSet
-    stServiceFlowParamSI              *psfAuthorizedSet;	/**<  AuthorizedSet of type stServiceFlowParamSI*/
-    /// \brief structure AdmittedSet
-    stServiceFlowParamSI              *psfAdmittedSet;	/**<  AdmittedSet of type stServiceFlowParamSI*/
-    /// \brief structure ActiveSet
-    stServiceFlowParamSI              *psfActiveSet;	/**<  sfActiveSet of type stServiceFlowParamSI*/
-	B_UINT8				   u8CC;	/**<  Confirmation Code*/
-	B_UINT8				   u8Padd;		/**<  8-bit Padding */
-
-    B_UINT16               u16Padd;	/**< 16 bit Padding */
-
-}stLocalSFAddIndication;
-
-
-typedef struct _stLocalSFAddIndication *pstLocalSFAddIndication;
-/**
-structure stLocalSFChangeRequest is same as structure stLocalSFAddIndication
-*/
-typedef struct _stLocalSFAddIndication stLocalSFChangeRequest, *pstLocalSFChangeRequest;
-/**
-structure stLocalSFChangeIndication is same as structure stLocalSFAddIndication
-*/
-typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFChangeIndication;
-
-/**
-structure stLocalSFDeleteRequest
-*/
-typedef struct _stLocalSFDeleteRequest{
-	B_UINT8                         u8Type;	 /**< Type*/
-	B_UINT8                         u8Padding;	 /**<  Padding byte*/
-	B_UINT16			u16TID;		 /**<  TID*/
-    /// \brief 32bitSFID
-    B_UINT32                        u32SFID;	 /**<  SFID*/
-}stLocalSFDeleteRequest, *pstLocalSFDeleteRequest;
-
-/**
-structure stLocalSFDeleteIndication
-*/
-typedef struct stLocalSFDeleteIndication{
-	B_UINT8                         u8Type;	/**< Type */
-	B_UINT8                         u8Padding;	/**< Padding  */
-	B_UINT16			u16TID;			/**< TID */
-       /// \brief 16bitCID
-    B_UINT16                        u16CID;			/**< CID */
-    /// \brief 16bitVCID
-    B_UINT16                        u16VCID;		/**< VCID */
-    /// \brief 32bitSFID
-    B_UINT32                        u32SFID; 		/**< SFID */
-	/// \brief 8bit Confirmation code
-	B_UINT8                         u8ConfirmationCode;	/**< Confirmation code */
-	B_UINT8                         u8Padding1[3];		/**< 3 byte Padding  */
-}stLocalSFDeleteIndication;
-
-typedef struct _stIM_SFHostNotify
-{
-	B_UINT32 	SFID;      //SFID of the service flow
-	B_UINT16 	newCID;   //the new/changed CID
-	B_UINT16 	VCID;             //Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid
-	B_UINT8  	RetainSF;        //Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete
-	B_UINT8 	QoSParamSet; //QoS paramset of the retained SF
-	B_UINT16 	u16reserved;  //For byte alignment
-
-} stIM_SFHostNotify;
+struct bcm_stim_sfhostnotify {
+	B_UINT32 SFID; /* SFID of the service flow */
+	B_UINT16 newCID; /* the new/changed CID */
+	B_UINT16 VCID; /* Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid */
+	B_UINT8 RetainSF; /* Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete */
+	B_UINT8 QoSParamSet; /* QoS paramset of the retained SF */
+	B_UINT16 u16reserved; /* For byte alignment */
+};
 
 #endif
diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c
index 08d13a4..10361bb 100644
--- a/drivers/staging/bcm/hostmibs.c
+++ b/drivers/staging/bcm/hostmibs.c
@@ -101,7 +101,7 @@
 	       sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
 }
 
-VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex)
+VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex)
 {
 	S_MIBS_EXTSERVICEFLOW_PARAMETERS *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable;
 
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index b179dba..b034eb5 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -577,7 +577,7 @@
 			 * the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms
 			 * won't hamper performance in any case.
 			 */
-			udelay(10000);
+			mdelay(10);
 		} while ((uiStatus & 0x1) && (iRetries < 400));
 
 		if (uiStatus & 0x1) {
@@ -3932,7 +3932,7 @@
 				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART3);
 		}
 
-		/* since this uiSectEndoffset is the size of iso Image. hence for calculating the vitual endoffset
+		/* since this uiSectEndoffset is the size of iso Image. hence for calculating the virtual endoffset
 		 * it should be added in startoffset. so that check done in last of this function can be valued.
 		 */
 		uiSectEndOffset = uiSectStartOffset + uiSectEndOffset;
diff --git a/drivers/staging/bcm/target_params.h b/drivers/staging/bcm/target_params.h
index 1487638..ad7ec00 100644
--- a/drivers/staging/bcm/target_params.h
+++ b/drivers/staging/bcm/target_params.h
@@ -32,7 +32,7 @@
       B_UINT32 m_u32PowerSavingModesEnable; //bit 1: 1 Idlemode enable; bit2: 1 Sleepmode Enable
 	  /* PowerSaving Mode Options:
 	     bit 0 = 1: CPE mode - to keep pcmcia if alive;
-	     bit 1 = 1: CINR reporing in Idlemode Msg
+	     bit 1 = 1: CINR reporting in Idlemode Msg
 	     bit 2 = 1: Default PSC Enable in sleepmode*/
       B_UINT32 m_u32PowerSavingModeOptions;
 
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
index 1f00d70..8997a8c 100644
--- a/drivers/staging/ccg/Kconfig
+++ b/drivers/staging/ccg/Kconfig
@@ -2,7 +2,7 @@
 
 config USB_G_CCG
 	tristate "Configurable Composite Gadget (STAGING)"
-	depends on STAGING && BLOCK && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
+	depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
 	help
 	  The Configurable Composite Gadget supports multiple USB
 	  functions: acm, mass storage, rndis and FunctionFS.
@@ -17,4 +17,9 @@
 	  Configurable Composite Gadget can be compiled "M" only
 	  or not at all.
 
+	  BIG FAT NOTE: DON'T RELY ON THIS USERINTERFACE HERE! AS PART
+	  OF THE REWORK DONE HERE WILL BE A NEW USER INTERFACE WITHOUT ANY
+	  COMPATIBILITY TO THIS SYSFS INTERFACE HERE. BE AWARE OF THIS
+	  BEFORE SELECTING THIS.
+
 endif # USB_GADGET
diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile
index 693da63..814fa9d 100644
--- a/drivers/staging/ccg/Makefile
+++ b/drivers/staging/ccg/Makefile
@@ -1,4 +1,2 @@
 g_ccg-y				:= ccg.o
-ccflags-y			+= -Idrivers/usb/gadget
-
 obj-$(CONFIG_USB_G_CCG)		+= g_ccg.o
diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c
index 6a7aab8..93e1e2f 100644
--- a/drivers/staging/ccg/ccg.c
+++ b/drivers/staging/ccg/ccg.c
@@ -32,7 +32,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
+#include "composite.h"
 #include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
@@ -44,19 +44,19 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "../../usb/gadget/usbstring.c"
-#include "../../usb/gadget/config.c"
-#include "../../usb/gadget/epautoconf.c"
-#include "../../usb/gadget/composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "composite.c"
 
-#include "../../usb/gadget/f_mass_storage.c"
-#include "../../usb/gadget/u_serial.c"
-#include "../../usb/gadget/f_acm.c"
+#include "f_mass_storage.c"
+#include "u_serial.c"
+#include "f_acm.c"
 #define USB_ETH_RNDIS y
-#include "../../usb/gadget/f_rndis.c"
-#include "../../usb/gadget/rndis.c"
-#include "../../usb/gadget/u_ether.c"
-#include "../../usb/gadget/f_fs.c"
+#include "f_rndis.c"
+#include "rndis.c"
+#include "u_ether.c"
+#include "f_fs.c"
 
 MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
 MODULE_DESCRIPTION("Configurable Composite USB Gadget");
@@ -728,7 +728,7 @@
 	struct fsg_common *common;
 	int err;
 
-	memset(&fsg, 0, sizeof fsg);
+	memset(&fsg, 0, sizeof(fsg));
 	fsg.nluns = 1;
 	fsg.luns[0].removable = 1;
 	fsg.vendor_name = iManufacturer;
@@ -1101,13 +1101,7 @@
 static int ccg_bind_config(struct usb_configuration *c)
 {
 	struct ccg_dev *dev = _ccg_dev;
-	int ret = 0;
-
-	ret = ccg_bind_enabled_functions(dev, c);
-	if (ret)
-		return ret;
-
-	return 0;
+	return ccg_bind_enabled_functions(dev, c);
 }
 
 static void ccg_unbind_config(struct usb_configuration *c)
@@ -1162,6 +1156,7 @@
 static struct usb_composite_driver ccg_usb_driver = {
 	.name		= "configurable_usb",
 	.dev		= &device_desc,
+	.bind		= ccg_bind,
 	.unbind		= ccg_usb_unbind,
 	.needs_serial	= true,
 	.iManufacturer	= "Linux Foundation",
@@ -1254,8 +1249,10 @@
 		return PTR_ERR(ccg_class);
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
+	if (!dev) {
+		class_destroy(ccg_class);
 		return -ENOMEM;
+	}
 
 	dev->functions = supported_functions;
 	INIT_LIST_HEAD(&dev->enabled_functions);
@@ -1275,7 +1272,7 @@
 	composite_driver.setup = ccg_setup;
 	composite_driver.disconnect = ccg_disconnect;
 
-	err = usb_composite_probe(&ccg_usb_driver, ccg_bind);
+	err = usb_composite_probe(&ccg_usb_driver);
 	if (err) {
 		class_destroy(ccg_class);
 		kfree(dev);
diff --git a/drivers/staging/ccg/composite.c b/drivers/staging/ccg/composite.c
new file mode 100644
index 0000000..228b457
--- /dev/null
+++ b/drivers/staging/ccg/composite.c
@@ -0,0 +1,1688 @@
+/*
+ * composite.c - infrastructure for Composite USB Gadgets
+ *
+ * Copyright (C) 2006-2008 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/utsname.h>
+
+#include <linux/usb/composite.h>
+#include <asm/unaligned.h>
+
+/*
+ * The code in this file is utility code, used to build a gadget driver
+ * from one or more "function" drivers, one or more "configuration"
+ * objects, and a "usb_composite_driver" by gluing them together along
+ * with the relevant device-wide data.
+ */
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ	1024
+
+static struct usb_composite_driver *composite;
+
+/* Some systems will need runtime overrides for the  product identifiers
+ * published in the device descriptor, either numbers or strings or both.
+ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort idVendor;
+module_param(idVendor, ushort, 0644);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort idProduct;
+module_param(idProduct, ushort, 0644);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort bcdDevice;
+module_param(bcdDevice, ushort, 0644);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *iManufacturer;
+module_param(iManufacturer, charp, 0644);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *iProduct;
+module_param(iProduct, charp, 0644);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, 0644);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
+
+static char composite_manufacturer[50];
+
+/*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+	for (; *t; t++) {
+		if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+			return t;
+	}
+	return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *		descriptors list
+ * @start:	pointer within descriptor array.
+ * @ep_desc:	endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+	for (ep_desc = next_ep_desc(start); \
+	      ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+			struct usb_function *f,
+			struct usb_ep *_ep)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(g);
+	struct usb_endpoint_descriptor *chosen_desc = NULL;
+	struct usb_descriptor_header **speed_desc = NULL;
+
+	struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+	int want_comp_desc = 0;
+
+	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+	if (!g || !f || !_ep)
+		return -EIO;
+
+	/* select desired speed */
+	switch (g->speed) {
+	case USB_SPEED_SUPER:
+		if (gadget_is_superspeed(g)) {
+			speed_desc = f->ss_descriptors;
+			want_comp_desc = 1;
+			break;
+		}
+		/* else: Fall trough */
+	case USB_SPEED_HIGH:
+		if (gadget_is_dualspeed(g)) {
+			speed_desc = f->hs_descriptors;
+			break;
+		}
+		/* else: fall through */
+	default:
+		speed_desc = f->descriptors;
+	}
+	/* find descriptors */
+	for_each_ep_desc(speed_desc, d_spd) {
+		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+		if (chosen_desc->bEndpointAddress == _ep->address)
+			goto ep_found;
+	}
+	return -EIO;
+
+ep_found:
+	/* commit results */
+	_ep->maxpacket = usb_endpoint_maxp(chosen_desc);
+	_ep->desc = chosen_desc;
+	_ep->comp_desc = NULL;
+	_ep->maxburst = 0;
+	_ep->mult = 0;
+	if (!want_comp_desc)
+		return 0;
+
+	/*
+	 * Companion descriptor should follow EP descriptor
+	 * USB 3.0 spec, #9.6.7
+	 */
+	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+	if (!comp_desc ||
+	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+		return -EIO;
+	_ep->comp_desc = comp_desc;
+	if (g->speed == USB_SPEED_SUPER) {
+		switch (usb_endpoint_type(_ep->desc)) {
+		case USB_ENDPOINT_XFER_ISOC:
+			/* mult: bits 1:0 of bmAttributes */
+			_ep->mult = comp_desc->bmAttributes & 0x3;
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			_ep->maxburst = comp_desc->bMaxBurst + 1;
+			break;
+		default:
+			if (comp_desc->bMaxBurst != 0)
+				ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+			_ep->maxburst = 1;
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * usb_add_function() - add a function to a configuration
+ * @config: the configuration
+ * @function: the function being added
+ * Context: single threaded during gadget setup
+ *
+ * After initialization, each configuration must have one or more
+ * functions added to it.  Adding a function involves calling its @bind()
+ * method to allocate resources such as interface and string identifiers
+ * and endpoints.
+ *
+ * This function returns the value of the function's bind(), which is
+ * zero for success else a negative errno value.
+ */
+int usb_add_function(struct usb_configuration *config,
+		struct usb_function *function)
+{
+	int	value = -EINVAL;
+
+	DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
+			function->name, function,
+			config->label, config);
+
+	if (!function->set_alt || !function->disable)
+		goto done;
+
+	function->config = config;
+	list_add_tail(&function->list, &config->functions);
+
+	/* REVISIT *require* function->bind? */
+	if (function->bind) {
+		value = function->bind(config, function);
+		if (value < 0) {
+			list_del(&function->list);
+			function->config = NULL;
+		}
+	} else
+		value = 0;
+
+	/* We allow configurations that don't work at both speeds.
+	 * If we run into a lowspeed Linux system, treat it the same
+	 * as full speed ... it's the function drivers that will need
+	 * to avoid bulk and ISO transfers.
+	 */
+	if (!config->fullspeed && function->descriptors)
+		config->fullspeed = true;
+	if (!config->highspeed && function->hs_descriptors)
+		config->highspeed = true;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = true;
+
+done:
+	if (value)
+		DBG(config->cdev, "adding '%s'/%p --> %d\n",
+				function->name, function, value);
+	return value;
+}
+
+/**
+ * usb_function_deactivate - prevent function and gadget enumeration
+ * @function: the function that isn't yet ready to respond
+ *
+ * Blocks response of the gadget driver to host enumeration by
+ * preventing the data line pullup from being activated.  This is
+ * normally called during @bind() processing to change from the
+ * initial "ready to respond" state, or when a required resource
+ * becomes available.
+ *
+ * For example, drivers that serve as a passthrough to a userspace
+ * daemon can block enumeration unless that daemon (such as an OBEX,
+ * MTP, or print server) is ready to handle host requests.
+ *
+ * Not all systems support software control of their USB peripheral
+ * data pullups.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_deactivate(struct usb_function *function)
+{
+	struct usb_composite_dev	*cdev = function->config->cdev;
+	unsigned long			flags;
+	int				status = 0;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+
+	if (cdev->deactivations == 0)
+		status = usb_gadget_disconnect(cdev->gadget);
+	if (status == 0)
+		cdev->deactivations++;
+
+	spin_unlock_irqrestore(&cdev->lock, flags);
+	return status;
+}
+
+/**
+ * usb_function_activate - allow function and gadget enumeration
+ * @function: function on which usb_function_activate() was called
+ *
+ * Reverses effect of usb_function_deactivate().  If no more functions
+ * are delaying their activation, the gadget driver will respond to
+ * host enumeration procedures.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_activate(struct usb_function *function)
+{
+	struct usb_composite_dev	*cdev = function->config->cdev;
+	unsigned long			flags;
+	int				status = 0;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+
+	if (WARN_ON(cdev->deactivations == 0))
+		status = -EINVAL;
+	else {
+		cdev->deactivations--;
+		if (cdev->deactivations == 0)
+			status = usb_gadget_connect(cdev->gadget);
+	}
+
+	spin_unlock_irqrestore(&cdev->lock, flags);
+	return status;
+}
+
+/**
+ * usb_interface_id() - allocate an unused interface ID
+ * @config: configuration associated with the interface
+ * @function: function handling the interface
+ * Context: single threaded during gadget setup
+ *
+ * usb_interface_id() is called from usb_function.bind() callbacks to
+ * allocate new interface IDs.  The function driver will then store that
+ * ID in interface, association, CDC union, and other descriptors.  It
+ * will also handle any control requests targeted at that interface,
+ * particularly changing its altsetting via set_alt().  There may
+ * also be class-specific or vendor-specific requests to handle.
+ *
+ * All interface identifier should be allocated using this routine, to
+ * ensure that for example different functions don't wrongly assign
+ * different meanings to the same identifier.  Note that since interface
+ * identifiers are configuration-specific, functions used in more than
+ * one configuration (or more than once in a given configuration) need
+ * multiple versions of the relevant descriptors.
+ *
+ * Returns the interface ID which was allocated; or -ENODEV if no
+ * more interface IDs can be allocated.
+ */
+int usb_interface_id(struct usb_configuration *config,
+		struct usb_function *function)
+{
+	unsigned id = config->next_interface_id;
+
+	if (id < MAX_CONFIG_INTERFACES) {
+		config->interface[id] = function;
+		config->next_interface_id = id + 1;
+		return id;
+	}
+	return -ENODEV;
+}
+
+static int config_buf(struct usb_configuration *config,
+		enum usb_device_speed speed, void *buf, u8 type)
+{
+	struct usb_config_descriptor	*c = buf;
+	void				*next = buf + USB_DT_CONFIG_SIZE;
+	int				len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
+	struct usb_function		*f;
+	int				status;
+
+	/* write the config descriptor */
+	c = buf;
+	c->bLength = USB_DT_CONFIG_SIZE;
+	c->bDescriptorType = type;
+	/* wTotalLength is written later */
+	c->bNumInterfaces = config->next_interface_id;
+	c->bConfigurationValue = config->bConfigurationValue;
+	c->iConfiguration = config->iConfiguration;
+	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
+	c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+
+	/* There may be e.g. OTG descriptors */
+	if (config->descriptors) {
+		status = usb_descriptor_fillbuf(next, len,
+				config->descriptors);
+		if (status < 0)
+			return status;
+		len -= status;
+		next += status;
+	}
+
+	/* add each function's descriptors */
+	list_for_each_entry(f, &config->functions, list) {
+		struct usb_descriptor_header **descriptors;
+
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
+			descriptors = f->hs_descriptors;
+			break;
+		default:
+			descriptors = f->descriptors;
+		}
+
+		if (!descriptors)
+			continue;
+		status = usb_descriptor_fillbuf(next, len,
+			(const struct usb_descriptor_header **) descriptors);
+		if (status < 0)
+			return status;
+		len -= status;
+		next += status;
+	}
+
+	len = next - buf;
+	c->wTotalLength = cpu_to_le16(len);
+	return len;
+}
+
+static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
+{
+	struct usb_gadget		*gadget = cdev->gadget;
+	struct usb_configuration	*c;
+	u8				type = w_value >> 8;
+	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
+
+	if (gadget->speed == USB_SPEED_SUPER)
+		speed = gadget->speed;
+	else if (gadget_is_dualspeed(gadget)) {
+		int	hs = 0;
+		if (gadget->speed == USB_SPEED_HIGH)
+			hs = 1;
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+		if (hs)
+			speed = USB_SPEED_HIGH;
+
+	}
+
+	/* This is a lookup by config *INDEX* */
+	w_value &= 0xff;
+	list_for_each_entry(c, &cdev->configs, list) {
+		/* ignore configs that won't work at this speed */
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			if (!c->superspeed)
+				continue;
+			break;
+		case USB_SPEED_HIGH:
+			if (!c->highspeed)
+				continue;
+			break;
+		default:
+			if (!c->fullspeed)
+				continue;
+		}
+
+		if (w_value == 0)
+			return config_buf(c, speed, cdev->req->buf, type);
+		w_value--;
+	}
+	return -EINVAL;
+}
+
+static int count_configs(struct usb_composite_dev *cdev, unsigned type)
+{
+	struct usb_gadget		*gadget = cdev->gadget;
+	struct usb_configuration	*c;
+	unsigned			count = 0;
+	int				hs = 0;
+	int				ss = 0;
+
+	if (gadget_is_dualspeed(gadget)) {
+		if (gadget->speed == USB_SPEED_HIGH)
+			hs = 1;
+		if (gadget->speed == USB_SPEED_SUPER)
+			ss = 1;
+		if (type == USB_DT_DEVICE_QUALIFIER)
+			hs = !hs;
+	}
+	list_for_each_entry(c, &cdev->configs, list) {
+		/* ignore configs that won't work at this speed */
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
+			if (!c->highspeed)
+				continue;
+		} else {
+			if (!c->fullspeed)
+				continue;
+		}
+		count++;
+	}
+	return count;
+}
+
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *	descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor	*usb_ext;
+	struct usb_ss_cap_descriptor	*ss_cap;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor	*bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented by all
+	 * SuperSpeed devices.
+	 */
+	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				USB_FULL_SPEED_OPERATION |
+				USB_HIGH_SPEED_OPERATION |
+				USB_5GBPS_OPERATION);
+	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+	/* Get Controller configuration */
+	if (cdev->gadget->ops->get_config_params)
+		cdev->gadget->ops->get_config_params(&dcd_config_params);
+	else {
+		dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
+		dcd_config_params.bU2DevExitLat =
+			cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+	}
+	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+	return le16_to_cpu(bos->wTotalLength);
+}
+
+static void device_qual(struct usb_composite_dev *cdev)
+{
+	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
+
+	qual->bLength = sizeof(*qual);
+	qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+	/* POLICY: same bcdUSB and device type info at both speeds */
+	qual->bcdUSB = cdev->desc.bcdUSB;
+	qual->bDeviceClass = cdev->desc.bDeviceClass;
+	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
+	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
+	/* ASSUME same EP0 fifo size at both speeds */
+	qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
+	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
+	qual->bRESERVED = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void reset_config(struct usb_composite_dev *cdev)
+{
+	struct usb_function		*f;
+
+	DBG(cdev, "reset config\n");
+
+	list_for_each_entry(f, &cdev->config->functions, list) {
+		if (f->disable)
+			f->disable(f);
+
+		bitmap_zero(f->endpoints, 32);
+	}
+	cdev->config = NULL;
+}
+
+static int set_config(struct usb_composite_dev *cdev,
+		const struct usb_ctrlrequest *ctrl, unsigned number)
+{
+	struct usb_gadget	*gadget = cdev->gadget;
+	struct usb_configuration *c = NULL;
+	int			result = -EINVAL;
+	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
+	int			tmp;
+
+	if (number) {
+		list_for_each_entry(c, &cdev->configs, list) {
+			if (c->bConfigurationValue == number) {
+				/*
+				 * We disable the FDs of the previous
+				 * configuration only if the new configuration
+				 * is a valid one
+				 */
+				if (cdev->config)
+					reset_config(cdev);
+				result = 0;
+				break;
+			}
+		}
+		if (result < 0)
+			goto done;
+	} else { /* Zero configuration value - need to reset the config */
+		if (cdev->config)
+			reset_config(cdev);
+		result = 0;
+	}
+
+	INFO(cdev, "%s config #%d: %s\n",
+	     usb_speed_string(gadget->speed),
+	     number, c ? c->label : "unconfigured");
+
+	if (!c)
+		goto done;
+
+	cdev->config = c;
+
+	/* Initialize all interfaces by setting them to altsetting zero. */
+	for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
+		struct usb_function	*f = c->interface[tmp];
+		struct usb_descriptor_header **descriptors;
+
+		if (!f)
+			break;
+
+		/*
+		 * Record which endpoints are used by the function. This is used
+		 * to dispatch control requests targeted at that endpoint to the
+		 * function's setup callback instead of the current
+		 * configuration's setup callback.
+		 */
+		switch (gadget->speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
+			descriptors = f->hs_descriptors;
+			break;
+		default:
+			descriptors = f->descriptors;
+		}
+
+		for (; *descriptors; ++descriptors) {
+			struct usb_endpoint_descriptor *ep;
+			int addr;
+
+			if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
+				continue;
+
+			ep = (struct usb_endpoint_descriptor *)*descriptors;
+			addr = ((ep->bEndpointAddress & 0x80) >> 3)
+			     |  (ep->bEndpointAddress & 0x0f);
+			set_bit(addr, f->endpoints);
+		}
+
+		result = f->set_alt(f, tmp, 0);
+		if (result < 0) {
+			DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
+					tmp, f->name, f, result);
+
+			reset_config(cdev);
+			goto done;
+		}
+
+		if (result == USB_GADGET_DELAYED_STATUS) {
+			DBG(cdev,
+			 "%s: interface %d (%s) requested delayed status\n",
+					__func__, tmp, f->name);
+			cdev->delayed_status++;
+			DBG(cdev, "delayed_status count %d\n",
+					cdev->delayed_status);
+		}
+	}
+
+	/* when we return, be sure our power usage is valid */
+	power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+done:
+	usb_gadget_vbus_draw(gadget, power);
+	if (result >= 0 && cdev->delayed_status)
+		result = USB_GADGET_DELAYED_STATUS;
+	return result;
+}
+
+/**
+ * usb_add_config() - add a configuration to a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration, with bConfigurationValue assigned
+ * @bind: the configuration's bind function
+ * Context: single threaded during gadget setup
+ *
+ * One of the main tasks of a composite @bind() routine is to
+ * add each of the configurations it supports, using this routine.
+ *
+ * This function returns the value of the configuration's @bind(), which
+ * is zero for success else a negative errno value.  Binding configurations
+ * assigns global resources including string IDs, and per-configuration
+ * resources such as interface IDs and endpoints.
+ */
+int usb_add_config(struct usb_composite_dev *cdev,
+		struct usb_configuration *config,
+		int (*bind)(struct usb_configuration *))
+{
+	int				status = -EINVAL;
+	struct usb_configuration	*c;
+
+	DBG(cdev, "adding config #%u '%s'/%p\n",
+			config->bConfigurationValue,
+			config->label, config);
+
+	if (!config->bConfigurationValue || !bind)
+		goto done;
+
+	/* Prevent duplicate configuration identifiers */
+	list_for_each_entry(c, &cdev->configs, list) {
+		if (c->bConfigurationValue == config->bConfigurationValue) {
+			status = -EBUSY;
+			goto done;
+		}
+	}
+
+	config->cdev = cdev;
+	list_add_tail(&config->list, &cdev->configs);
+
+	INIT_LIST_HEAD(&config->functions);
+	config->next_interface_id = 0;
+	memset(config->interface, 0, sizeof(config->interface));
+
+	status = bind(config);
+	if (status < 0) {
+		while (!list_empty(&config->functions)) {
+			struct usb_function		*f;
+
+			f = list_first_entry(&config->functions,
+					struct usb_function, list);
+			list_del(&f->list);
+			if (f->unbind) {
+				DBG(cdev, "unbind function '%s'/%p\n",
+					f->name, f);
+				f->unbind(config, f);
+				/* may free memory for "f" */
+			}
+		}
+		list_del(&config->list);
+		config->cdev = NULL;
+	} else {
+		unsigned	i;
+
+		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
+			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
+			config->highspeed ? " high" : "",
+			config->fullspeed
+				? (gadget_is_dualspeed(cdev->gadget)
+					? " full"
+					: " full/low")
+				: "");
+
+		for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
+			struct usb_function	*f = config->interface[i];
+
+			if (!f)
+				continue;
+			DBG(cdev, "  interface %d = %s/%p\n",
+				i, f->name, f);
+		}
+	}
+
+	/* set_alt(), or next bind(), sets up
+	 * ep->driver_data as needed.
+	 */
+	usb_ep_autoconfig_reset(cdev->gadget);
+
+done:
+	if (status)
+		DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
+				config->bConfigurationValue, status);
+	return status;
+}
+
+static void remove_config(struct usb_composite_dev *cdev,
+			      struct usb_configuration *config)
+{
+	while (!list_empty(&config->functions)) {
+		struct usb_function		*f;
+
+		f = list_first_entry(&config->functions,
+				struct usb_function, list);
+		list_del(&f->list);
+		if (f->unbind) {
+			DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+			f->unbind(config, f);
+			/* may free memory for "f" */
+		}
+	}
+	list_del(&config->list);
+	if (config->unbind) {
+		DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+		config->unbind(config);
+			/* may free memory for "c" */
+	}
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void usb_remove_config(struct usb_composite_dev *cdev,
+		      struct usb_configuration *config)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cdev->lock, flags);
+
+	if (cdev->config == config)
+		reset_config(cdev);
+
+	spin_unlock_irqrestore(&cdev->lock, flags);
+
+	remove_config(cdev, config);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* We support strings in multiple languages ... string descriptor zero
+ * says which languages are supported.  The typical case will be that
+ * only one language (probably English) is used, with I18N handled on
+ * the host side.
+ */
+
+static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
+{
+	const struct usb_gadget_strings	*s;
+	__le16				language;
+	__le16				*tmp;
+
+	while (*sp) {
+		s = *sp;
+		language = cpu_to_le16(s->language);
+		for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) {
+			if (*tmp == language)
+				goto repeat;
+		}
+		*tmp++ = language;
+repeat:
+		sp++;
+	}
+}
+
+static int lookup_string(
+	struct usb_gadget_strings	**sp,
+	void				*buf,
+	u16				language,
+	int				id
+)
+{
+	struct usb_gadget_strings	*s;
+	int				value;
+
+	while (*sp) {
+		s = *sp++;
+		if (s->language != language)
+			continue;
+		value = usb_gadget_get_string(s, id, buf);
+		if (value > 0)
+			return value;
+	}
+	return -EINVAL;
+}
+
+static int get_string(struct usb_composite_dev *cdev,
+		void *buf, u16 language, int id)
+{
+	struct usb_configuration	*c;
+	struct usb_function		*f;
+	int				len;
+	const char			*str;
+
+	/* Yes, not only is USB's I18N support probably more than most
+	 * folk will ever care about ... also, it's all supported here.
+	 * (Except for UTF8 support for Unicode's "Astral Planes".)
+	 */
+
+	/* 0 == report all available language codes */
+	if (id == 0) {
+		struct usb_string_descriptor	*s = buf;
+		struct usb_gadget_strings	**sp;
+
+		memset(s, 0, 256);
+		s->bDescriptorType = USB_DT_STRING;
+
+		sp = composite->strings;
+		if (sp)
+			collect_langs(sp, s->wData);
+
+		list_for_each_entry(c, &cdev->configs, list) {
+			sp = c->strings;
+			if (sp)
+				collect_langs(sp, s->wData);
+
+			list_for_each_entry(f, &c->functions, list) {
+				sp = f->strings;
+				if (sp)
+					collect_langs(sp, s->wData);
+			}
+		}
+
+		for (len = 0; len <= 126 && s->wData[len]; len++)
+			continue;
+		if (!len)
+			return -EINVAL;
+
+		s->bLength = 2 * (len + 1);
+		return s->bLength;
+	}
+
+	/* Otherwise, look up and return a specified string.  First
+	 * check if the string has not been overridden.
+	 */
+	if (cdev->manufacturer_override == id)
+		str = iManufacturer ?: composite->iManufacturer ?:
+			composite_manufacturer;
+	else if (cdev->product_override == id)
+		str = iProduct ?: composite->iProduct;
+	else if (cdev->serial_override == id)
+		str = iSerialNumber ?: composite->iSerialNumber;
+	else
+		str = NULL;
+	if (str) {
+		struct usb_gadget_strings strings = {
+			.language = language,
+			.strings  = &(struct usb_string) { 0xff, str }
+		};
+		return usb_gadget_get_string(&strings, 0xff, buf);
+	}
+
+	/* String IDs are device-scoped, so we look up each string
+	 * table we're told about.  These lookups are infrequent;
+	 * simpler-is-better here.
+	 */
+	if (composite->strings) {
+		len = lookup_string(composite->strings, buf, language, id);
+		if (len > 0)
+			return len;
+	}
+	list_for_each_entry(c, &cdev->configs, list) {
+		if (c->strings) {
+			len = lookup_string(c->strings, buf, language, id);
+			if (len > 0)
+				return len;
+		}
+		list_for_each_entry(f, &c->functions, list) {
+			if (!f->strings)
+				continue;
+			len = lookup_string(f->strings, buf, language, id);
+			if (len > 0)
+				return len;
+		}
+	}
+	return -EINVAL;
+}
+
+/**
+ * usb_string_id() - allocate an unused string ID
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_id() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
+ * that for example different functions don't wrongly assign different
+ * meanings to the same identifier.
+ */
+int usb_string_id(struct usb_composite_dev *cdev)
+{
+	if (cdev->next_string_id < 254) {
+		/* string id 0 is reserved by USB spec for list of
+		 * supported languages */
+		/* 255 reserved as well? -- mina86 */
+		cdev->next_string_id++;
+		return cdev->next_string_id;
+	}
+	return -ENODEV;
+}
+
+/**
+ * usb_string_ids() - allocate unused string IDs in batch
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * @str: an array of usb_string objects to assign numbers to
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_ids() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then copy IDs from the string table to the appropriate descriptors
+ * and string table for other languages.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
+{
+	int next = cdev->next_string_id;
+
+	for (; str->s; ++str) {
+		if (unlikely(next >= 254))
+			return -ENODEV;
+		str->id = ++next;
+	}
+
+	cdev->next_string_id = next;
+
+	return 0;
+}
+
+/**
+ * usb_string_ids_n() - allocate unused string IDs in batch
+ * @c: the device whose string descriptor IDs are being allocated
+ * @n: number of string IDs to allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns the first requested ID.  This ID and next @n-1 IDs are now
+ * valid IDs.  At least provided that @n is non-zero because if it
+ * is, returns last requested ID which is now very useful information.
+ *
+ * @usb_string_ids_n() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
+{
+	unsigned next = c->next_string_id;
+	if (unlikely(n > 254 || (unsigned)next + n > 254))
+		return -ENODEV;
+	c->next_string_id += n;
+	return next + 1;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		DBG((struct usb_composite_dev *) ep->driver_data,
+				"setup complete --> %d, %d/%d\n",
+				req->status, req->actual, req->length);
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver(like
+ * device and endpoint feature flags, and their status).  It's all
+ * housekeeping for the gadget function we're implementing.  Most of
+ * the work is in config and function specific setup.
+ */
+static int
+composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_request		*req = cdev->req;
+	int				value = -EOPNOTSUPP;
+	int				status = 0;
+	u16				w_index = le16_to_cpu(ctrl->wIndex);
+	u8				intf = w_index & 0xFF;
+	u16				w_value = le16_to_cpu(ctrl->wValue);
+	u16				w_length = le16_to_cpu(ctrl->wLength);
+	struct usb_function		*f = NULL;
+	u8				endp;
+
+	/* partial re-init of the response message; the function or the
+	 * gadget might need to intercept e.g. a control-OUT completion
+	 * when we delegate to it.
+	 */
+	req->zero = 0;
+	req->complete = composite_setup_complete;
+	req->length = 0;
+	gadget->ep0->driver_data = cdev;
+
+	switch (ctrl->bRequest) {
+
+	/* we handle all standard USB descriptors */
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			goto unknown;
+		switch (w_value >> 8) {
+
+		case USB_DT_DEVICE:
+			cdev->desc.bNumConfigurations =
+				count_configs(cdev, USB_DT_DEVICE);
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget_is_superspeed(gadget)) {
+				if (gadget->speed >= USB_SPEED_SUPER) {
+					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+					cdev->desc.bMaxPacketSize0 = 9;
+				} else {
+					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+				}
+			}
+
+			value = min(w_length, (u16) sizeof cdev->desc);
+			memcpy(req->buf, &cdev->desc, value);
+			break;
+		case USB_DT_DEVICE_QUALIFIER:
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
+				break;
+			device_qual(cdev);
+			value = min_t(int, w_length,
+				sizeof(struct usb_qualifier_descriptor));
+			break;
+		case USB_DT_OTHER_SPEED_CONFIG:
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
+				break;
+			/* FALLTHROUGH */
+		case USB_DT_CONFIG:
+			value = config_desc(cdev, w_value);
+			if (value >= 0)
+				value = min(w_length, (u16) value);
+			break;
+		case USB_DT_STRING:
+			value = get_string(cdev, req->buf,
+					w_index, w_value & 0xff);
+			if (value >= 0)
+				value = min(w_length, (u16) value);
+			break;
+		case USB_DT_BOS:
+			if (gadget_is_superspeed(gadget)) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16) value);
+			}
+			break;
+		}
+		break;
+
+	/* any number of configs can work */
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != 0)
+			goto unknown;
+		if (gadget_is_otg(gadget)) {
+			if (gadget->a_hnp_support)
+				DBG(cdev, "HNP available\n");
+			else if (gadget->a_alt_hnp_support)
+				DBG(cdev, "HNP on another port\n");
+			else
+				VDBG(cdev, "HNP inactive\n");
+		}
+		spin_lock(&cdev->lock);
+		value = set_config(cdev, ctrl, w_value);
+		spin_unlock(&cdev->lock);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			goto unknown;
+		if (cdev->config)
+			*(u8 *)req->buf = cdev->config->bConfigurationValue;
+		else
+			*(u8 *)req->buf = 0;
+		value = min(w_length, (u16) 1);
+		break;
+
+	/* function drivers must handle get/set altsetting; if there's
+	 * no get() method, we know only altsetting zero works.
+	 */
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+			goto unknown;
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		if (w_value && !f->set_alt)
+			break;
+		value = f->set_alt(f, w_index, w_value);
+		if (value == USB_GADGET_DELAYED_STATUS) {
+			DBG(cdev,
+			 "%s: interface %d (%s) requested delayed status\n",
+					__func__, intf, f->name);
+			cdev->delayed_status++;
+			DBG(cdev, "delayed_status count %d\n",
+					cdev->delayed_status);
+		}
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+			goto unknown;
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		/* lots of interfaces only need altsetting zero... */
+		value = f->get_alt ? f->get_alt(f, w_index) : 0;
+		if (value < 0)
+			break;
+		*((u8 *)req->buf) = value;
+		value = min(w_length, (u16) 1);
+		break;
+
+	/*
+	 * USB 3.0 additions:
+	 * Function driver should handle get_status request. If such cb
+	 * wasn't supplied we respond with default value = 0
+	 * Note: function driver should supply such cb only for the first
+	 * interface of the function
+	 */
+	case USB_REQ_GET_STATUS:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+			goto unknown;
+		value = 2;	/* This is the length of the get_status reply */
+		put_unaligned_le16(0, req->buf);
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		status = f->get_status ? f->get_status(f) : 0;
+		if (status < 0)
+			break;
+		put_unaligned_le16(status & 0x0000ffff, req->buf);
+		break;
+	/*
+	 * Function drivers should handle SetFeature/ClearFeature
+	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+	 * only for the first interface of the function
+	 */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+			goto unknown;
+		switch (w_value) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			if (!f)
+				break;
+			value = 0;
+			if (f->func_suspend)
+				value = f->func_suspend(f, w_index >> 8);
+			if (value < 0) {
+				ERROR(cdev,
+				      "func_suspend() returned error %d\n",
+				      value);
+				value = 0;
+			}
+			break;
+		}
+		break;
+	default:
+unknown:
+		VDBG(cdev,
+			"non-core control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+
+		/* functions always handle their interfaces and endpoints...
+		 * punt other recipients (other, WUSB, ...) to the current
+		 * configuration code.
+		 *
+		 * REVISIT it could make sense to let the composite device
+		 * take such requests too, if that's ever needed:  to work
+		 * in config 0, etc.
+		 */
+		switch (ctrl->bRequestType & USB_RECIP_MASK) {
+		case USB_RECIP_INTERFACE:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			break;
+
+		case USB_RECIP_ENDPOINT:
+			endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
+			list_for_each_entry(f, &cdev->config->functions, list) {
+				if (test_bit(endp, f->endpoints))
+					break;
+			}
+			if (&f->list == &cdev->config->functions)
+				f = NULL;
+			break;
+		}
+
+		if (f && f->setup)
+			value = f->setup(f, ctrl);
+		else {
+			struct usb_configuration	*c;
+
+			c = cdev->config;
+			if (c && c->setup)
+				value = c->setup(c, ctrl);
+		}
+
+		goto done;
+	}
+
+	/* respond with data transfer before status phase? */
+	if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
+		req->length = value;
+		req->zero = value < w_length;
+		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			DBG(cdev, "ep_queue --> %d\n", value);
+			req->status = 0;
+			composite_setup_complete(gadget->ep0, req);
+		}
+	} else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
+		WARN(cdev,
+			"%s: Delayed status not supported for w_length != 0",
+			__func__);
+	}
+
+done:
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+static void composite_disconnect(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	unsigned long			flags;
+
+	/* REVISIT:  should we have config and device level
+	 * disconnect callbacks?
+	 */
+	spin_lock_irqsave(&cdev->lock, flags);
+	if (cdev->config)
+		reset_config(cdev);
+	if (composite->disconnect)
+		composite->disconnect(cdev);
+	spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t composite_show_suspended(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+	struct usb_composite_dev *cdev = get_gadget_data(gadget);
+
+	return sprintf(buf, "%d\n", cdev->suspended);
+}
+
+static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
+
+static void
+composite_unbind(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+
+	/* composite_disconnect() must already have been called
+	 * by the underlying peripheral controller driver!
+	 * so there's no i/o concurrency that could affect the
+	 * state protected by cdev->lock.
+	 */
+	WARN_ON(cdev->config);
+
+	while (!list_empty(&cdev->configs)) {
+		struct usb_configuration	*c;
+		c = list_first_entry(&cdev->configs,
+				struct usb_configuration, list);
+		remove_config(cdev, c);
+	}
+	if (composite->unbind)
+		composite->unbind(cdev);
+
+	if (cdev->req) {
+		kfree(cdev->req->buf);
+		usb_ep_free_request(gadget->ep0, cdev->req);
+	}
+	device_remove_file(&gadget->dev, &dev_attr_suspended);
+	kfree(cdev);
+	set_gadget_data(gadget, NULL);
+	composite = NULL;
+}
+
+static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
+{
+	if (!*desc) {
+		int ret = usb_string_id(cdev);
+		if (unlikely(ret < 0))
+			WARNING(cdev, "failed to override string ID\n");
+		else
+			*desc = ret;
+	}
+
+	return *desc;
+}
+
+static int composite_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct usb_composite_dev	*cdev;
+	int				status = -ENOMEM;
+
+	cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
+	if (!cdev)
+		return status;
+
+	spin_lock_init(&cdev->lock);
+	cdev->gadget = gadget;
+	set_gadget_data(gadget, cdev);
+	INIT_LIST_HEAD(&cdev->configs);
+
+	/* preallocate control response and buffer */
+	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+	if (!cdev->req)
+		goto fail;
+	cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+	if (!cdev->req->buf)
+		goto fail;
+	cdev->req->complete = composite_setup_complete;
+	gadget->ep0->driver_data = cdev;
+
+	cdev->bufsiz = USB_BUFSIZ;
+	cdev->driver = composite;
+
+	/*
+	 * As per USB compliance update, a device that is actively drawing
+	 * more than 100mA from USB must report itself as bus-powered in
+	 * the GetStatus(DEVICE) call.
+	 */
+	if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
+		usb_gadget_set_selfpowered(gadget);
+
+	/* interface and string IDs start at zero via kzalloc.
+	 * we force endpoints to start unassigned; few controller
+	 * drivers will zero ep->driver_data.
+	 */
+	usb_ep_autoconfig_reset(cdev->gadget);
+
+	/* composite gadget needs to assign strings for whole device (like
+	 * serial number), register function drivers, potentially update
+	 * power state and consumption, etc
+	 */
+	status = composite->bind(cdev);
+	if (status < 0)
+		goto fail;
+
+	cdev->desc = *composite->dev;
+
+	/* standardized runtime overrides for device ID data */
+	if (idVendor)
+		cdev->desc.idVendor = cpu_to_le16(idVendor);
+	else
+		idVendor = le16_to_cpu(cdev->desc.idVendor);
+	if (idProduct)
+		cdev->desc.idProduct = cpu_to_le16(idProduct);
+	else
+		idProduct = le16_to_cpu(cdev->desc.idProduct);
+	if (bcdDevice)
+		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+	else
+		bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
+
+	/* string overrides */
+	if (iManufacturer || !cdev->desc.iManufacturer) {
+		if (!iManufacturer && !composite->iManufacturer &&
+		    !*composite_manufacturer)
+			snprintf(composite_manufacturer,
+				 sizeof composite_manufacturer,
+				 "%s %s with %s",
+				 init_utsname()->sysname,
+				 init_utsname()->release,
+				 gadget->name);
+
+		cdev->manufacturer_override =
+			override_id(cdev, &cdev->desc.iManufacturer);
+	}
+
+	if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
+		cdev->product_override =
+			override_id(cdev, &cdev->desc.iProduct);
+
+	if (iSerialNumber ||
+	    (!cdev->desc.iSerialNumber && composite->iSerialNumber))
+		cdev->serial_override =
+			override_id(cdev, &cdev->desc.iSerialNumber);
+
+	/* has userspace failed to provide a serial number? */
+	if (composite->needs_serial && !cdev->desc.iSerialNumber)
+		WARNING(cdev, "userspace failed to provide iSerialNumber\n");
+
+	/* finish up */
+	status = device_create_file(&gadget->dev, &dev_attr_suspended);
+	if (status)
+		goto fail;
+
+	INFO(cdev, "%s ready\n", composite->name);
+	return 0;
+
+fail:
+	composite_unbind(gadget);
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+composite_suspend(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_function		*f;
+
+	/* REVISIT:  should we have config level
+	 * suspend/resume callbacks?
+	 */
+	DBG(cdev, "suspend\n");
+	if (cdev->config) {
+		list_for_each_entry(f, &cdev->config->functions, list) {
+			if (f->suspend)
+				f->suspend(f);
+		}
+	}
+	if (composite->suspend)
+		composite->suspend(cdev);
+
+	cdev->suspended = 1;
+
+	usb_gadget_vbus_draw(gadget, 2);
+}
+
+static void
+composite_resume(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_function		*f;
+	u8				maxpower;
+
+	/* REVISIT:  should we have config level
+	 * suspend/resume callbacks?
+	 */
+	DBG(cdev, "resume\n");
+	if (composite->resume)
+		composite->resume(cdev);
+	if (cdev->config) {
+		list_for_each_entry(f, &cdev->config->functions, list) {
+			if (f->resume)
+				f->resume(f);
+		}
+
+		maxpower = cdev->config->bMaxPower;
+
+		usb_gadget_vbus_draw(gadget, maxpower ?
+			(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
+	}
+
+	cdev->suspended = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver composite_driver = {
+	.bind		= composite_bind,
+	.unbind		= composite_unbind,
+
+	.setup		= composite_setup,
+	.disconnect	= composite_disconnect,
+
+	.suspend	= composite_suspend,
+	.resume		= composite_resume,
+
+	.driver	= {
+		.owner		= THIS_MODULE,
+	},
+};
+
+/**
+ * usb_composite_probe() - register a composite driver
+ * @driver: the driver to register
+ * @bind: the callback used to allocate resources that are shared across the
+ *	whole device, such as string IDs, and add its configurations using
+ *	@usb_add_config().  This may fail by returning a negative errno
+ *	value; it should return zero on successful initialization.
+ * Context: single threaded during gadget setup
+ *
+ * This function is used to register drivers using the composite driver
+ * framework.  The return value is zero, or a negative errno value.
+ * Those values normally come from the driver's @bind method, which does
+ * all the work of setting up the driver to match the hardware.
+ *
+ * On successful return, the gadget is ready to respond to requests from
+ * the host, unless one of its components invokes usb_gadget_disconnect()
+ * while it was binding.  That would usually be done in order to wait for
+ * some userspace participation.
+ */
+int usb_composite_probe(struct usb_composite_driver *driver)
+{
+	if (!driver || !driver->dev || composite || !driver->bind)
+		return -EINVAL;
+
+	if (!driver->name)
+		driver->name = "composite";
+	if (!driver->iProduct)
+		driver->iProduct = driver->name;
+	composite_driver.function =  (char *) driver->name;
+	composite_driver.driver.name = driver->name;
+	composite_driver.max_speed = driver->max_speed;
+	composite = driver;
+
+	return usb_gadget_probe_driver(&composite_driver);
+}
+
+/**
+ * usb_composite_unregister() - unregister a composite driver
+ * @driver: the driver to unregister
+ *
+ * This function is used to unregister drivers using the composite
+ * driver framework.
+ */
+void usb_composite_unregister(struct usb_composite_driver *driver)
+{
+	if (composite != driver)
+		return;
+	usb_gadget_unregister_driver(&composite_driver);
+}
+
+/**
+ * usb_composite_setup_continue() - Continue with the control transfer
+ * @cdev: the composite device who's control transfer was kept waiting
+ *
+ * This function must be called by the USB function driver to continue
+ * with the control transfer's data/status stage in case it had requested to
+ * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
+ * can request the composite framework to delay the setup request's data/status
+ * stages by returning USB_GADGET_DELAYED_STATUS.
+ */
+void usb_composite_setup_continue(struct usb_composite_dev *cdev)
+{
+	int			value;
+	struct usb_request	*req = cdev->req;
+	unsigned long		flags;
+
+	DBG(cdev, "%s\n", __func__);
+	spin_lock_irqsave(&cdev->lock, flags);
+
+	if (cdev->delayed_status == 0) {
+		WARN(cdev, "%s: Unexpected call\n", __func__);
+
+	} else if (--cdev->delayed_status == 0) {
+		DBG(cdev, "%s: Completing delayed status\n", __func__);
+		req->length = 0;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			DBG(cdev, "ep_queue --> %d\n", value);
+			req->status = 0;
+			composite_setup_complete(cdev->gadget->ep0, req);
+		}
+	}
+
+	spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
diff --git a/drivers/staging/ccg/composite.h b/drivers/staging/ccg/composite.h
new file mode 100644
index 0000000..19a5adf
--- /dev/null
+++ b/drivers/staging/ccg/composite.h
@@ -0,0 +1,395 @@
+/*
+ * composite.h -- framework for usb gadgets which are composite devices
+ *
+ * Copyright (C) 2006-2008 David Brownell
+ *
+ * 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
+ */
+
+#ifndef	__LINUX_USB_COMPOSITE_H
+#define	__LINUX_USB_COMPOSITE_H
+
+/*
+ * This framework is an optional layer on top of the USB Gadget interface,
+ * making it easier to build (a) Composite devices, supporting multiple
+ * functions within any single configuration, and (b) Multi-configuration
+ * devices, also supporting multiple functions but without necessarily
+ * having more than one function per configuration.
+ *
+ * Example:  a device with a single configuration supporting both network
+ * link and mass storage functions is a composite device.  Those functions
+ * might alternatively be packaged in individual configurations, but in
+ * the composite model the host can use both functions at the same time.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/*
+ * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
+ * wish to delay the data/status stages of the control transfer till they
+ * are ready. The control transfer will then be kept from completing till
+ * all the function drivers that requested for USB_GADGET_DELAYED_STAUS
+ * invoke usb_composite_setup_continue().
+ */
+#define USB_GADGET_DELAYED_STATUS       0x7fff	/* Impossibly large value */
+
+struct usb_configuration;
+
+/**
+ * struct usb_function - describes one function of a configuration
+ * @name: For diagnostics, identifies the function.
+ * @strings: tables of strings, keyed by identifiers assigned during bind()
+ *	and by language IDs provided in control requests
+ * @descriptors: Table of full (or low) speed descriptors, using interface and
+ *	string identifiers assigned during @bind().  If this pointer is null,
+ *	the function will not be available at full speed (or at low speed).
+ * @hs_descriptors: Table of high speed descriptors, using interface and
+ *	string identifiers assigned during @bind().  If this pointer is null,
+ *	the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors, using interface and
+ *	string identifiers assigned during @bind(). If this
+ *	pointer is null after initiation, the function will not
+ *	be available at super speed.
+ * @config: assigned when @usb_add_function() is called; this is the
+ *	configuration with which this function is associated.
+ * @bind: Before the gadget can register, all of its functions bind() to the
+ *	available resources including string and interface identifiers used
+ *	in interface or class descriptors; endpoints; I/O buffers; and so on.
+ * @unbind: Reverses @bind; called as a side effect of unregistering the
+ *	driver which added this function.
+ * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
+ *	initialize usb_ep.driver data at this time (when it is used).
+ *	Note that setting an interface to its current altsetting resets
+ *	interface state, and that all interfaces have a disabled state.
+ * @get_alt: Returns the active altsetting.  If this is not provided,
+ *	then only altsetting zero is supported.
+ * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
+ *	include host resetting or reconfiguring the gadget, and disconnection.
+ * @setup: Used for interface-specific control requests.
+ * @suspend: Notifies functions when the host stops sending USB traffic.
+ * @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ *	GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ *	SetFeature(FUNCTION_SUSPEND) is reseived
+ *
+ * A single USB function uses one or more interfaces, and should in most
+ * cases support operation at both full and high speeds.  Each function is
+ * associated by @usb_add_function() with a one configuration; that function
+ * causes @bind() to be called so resources can be allocated as part of
+ * setting up a gadget driver.  Those resources include endpoints, which
+ * should be allocated using @usb_ep_autoconfig().
+ *
+ * To support dual speed operation, a function driver provides descriptors
+ * for both high and full speed operation.  Except in rare cases that don't
+ * involve bulk endpoints, each speed needs different endpoint descriptors.
+ *
+ * Function drivers choose their own strategies for managing instance data.
+ * The simplest strategy just declares it "static', which means the function
+ * can only be activated once.  If the function needs to be exposed in more
+ * than one configuration at a given speed, it needs to support multiple
+ * usb_function structures (one for each configuration).
+ *
+ * A more complex strategy might encapsulate a @usb_function structure inside
+ * a driver-specific instance structure to allows multiple activations.  An
+ * example of multiple activations might be a CDC ACM function that supports
+ * two or more distinct instances within the same configuration, providing
+ * several independent logical data links to a USB host.
+ */
+struct usb_function {
+	const char			*name;
+	struct usb_gadget_strings	**strings;
+	struct usb_descriptor_header	**descriptors;
+	struct usb_descriptor_header	**hs_descriptors;
+	struct usb_descriptor_header	**ss_descriptors;
+
+	struct usb_configuration	*config;
+
+	/* REVISIT:  bind() functions can be marked __init, which
+	 * makes trouble for section mismatch analysis.  See if
+	 * we can't restructure things to avoid mismatching.
+	 * Related:  unbind() may kfree() but bind() won't...
+	 */
+
+	/* configuration management:  bind/unbind */
+	int			(*bind)(struct usb_configuration *,
+					struct usb_function *);
+	void			(*unbind)(struct usb_configuration *,
+					struct usb_function *);
+
+	/* runtime state management */
+	int			(*set_alt)(struct usb_function *,
+					unsigned interface, unsigned alt);
+	int			(*get_alt)(struct usb_function *,
+					unsigned interface);
+	void			(*disable)(struct usb_function *);
+	int			(*setup)(struct usb_function *,
+					const struct usb_ctrlrequest *);
+	void			(*suspend)(struct usb_function *);
+	void			(*resume)(struct usb_function *);
+
+	/* USB 3.0 additions */
+	int			(*get_status)(struct usb_function *);
+	int			(*func_suspend)(struct usb_function *,
+						u8 suspend_opt);
+	/* private: */
+	/* internals */
+	struct list_head		list;
+	DECLARE_BITMAP(endpoints, 32);
+};
+
+int usb_add_function(struct usb_configuration *, struct usb_function *);
+
+int usb_function_deactivate(struct usb_function *);
+int usb_function_activate(struct usb_function *);
+
+int usb_interface_id(struct usb_configuration *, struct usb_function *);
+
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+			struct usb_ep *_ep);
+
+#define	MAX_CONFIG_INTERFACES		16	/* arbitrary; max 255 */
+
+/**
+ * struct usb_configuration - represents one gadget configuration
+ * @label: For diagnostics, describes the configuration.
+ * @strings: Tables of strings, keyed by identifiers assigned during @bind()
+ *	and by language IDs provided in control requests.
+ * @descriptors: Table of descriptors preceding all function descriptors.
+ *	Examples include OTG and vendor-specific descriptors.
+ * @unbind: Reverses @bind; called as a side effect of unregistering the
+ *	driver which added this configuration.
+ * @setup: Used to delegate control requests that aren't handled by standard
+ *	device infrastructure or directed at a specific interface.
+ * @bConfigurationValue: Copied into configuration descriptor.
+ * @iConfiguration: Copied into configuration descriptor.
+ * @bmAttributes: Copied into configuration descriptor.
+ * @bMaxPower: Copied into configuration descriptor.
+ * @cdev: assigned by @usb_add_config() before calling @bind(); this is
+ *	the device associated with this configuration.
+ *
+ * Configurations are building blocks for gadget drivers structured around
+ * function drivers.  Simple USB gadgets require only one function and one
+ * configuration, and handle dual-speed hardware by always providing the same
+ * functionality.  Slightly more complex gadgets may have more than one
+ * single-function configuration at a given speed; or have configurations
+ * that only work at one speed.
+ *
+ * Composite devices are, by definition, ones with configurations which
+ * include more than one function.
+ *
+ * The lifecycle of a usb_configuration includes allocation, initialization
+ * of the fields described above, and calling @usb_add_config() to set up
+ * internal data and bind it to a specific device.  The configuration's
+ * @bind() method is then used to initialize all the functions and then
+ * call @usb_add_function() for them.
+ *
+ * Those functions would normally be independent of each other, but that's
+ * not mandatory.  CDC WMC devices are an example where functions often
+ * depend on other functions, with some functions subsidiary to others.
+ * Such interdependency may be managed in any way, so long as all of the
+ * descriptors complete by the time the composite driver returns from
+ * its bind() routine.
+ */
+struct usb_configuration {
+	const char			*label;
+	struct usb_gadget_strings	**strings;
+	const struct usb_descriptor_header **descriptors;
+
+	/* REVISIT:  bind() functions can be marked __init, which
+	 * makes trouble for section mismatch analysis.  See if
+	 * we can't restructure things to avoid mismatching...
+	 */
+
+	/* configuration management: unbind/setup */
+	void			(*unbind)(struct usb_configuration *);
+	int			(*setup)(struct usb_configuration *,
+					const struct usb_ctrlrequest *);
+
+	/* fields in the config descriptor */
+	u8			bConfigurationValue;
+	u8			iConfiguration;
+	u8			bmAttributes;
+	u8			bMaxPower;
+
+	struct usb_composite_dev	*cdev;
+
+	/* private: */
+	/* internals */
+	struct list_head	list;
+	struct list_head	functions;
+	u8			next_interface_id;
+	unsigned		superspeed:1;
+	unsigned		highspeed:1;
+	unsigned		fullspeed:1;
+	struct usb_function	*interface[MAX_CONFIG_INTERFACES];
+};
+
+int usb_add_config(struct usb_composite_dev *,
+		struct usb_configuration *,
+		int (*)(struct usb_configuration *));
+
+void usb_remove_config(struct usb_composite_dev *,
+		struct usb_configuration *);
+
+/**
+ * struct usb_composite_driver - groups configurations into a gadget
+ * @name: For diagnostics, identifies the driver.
+ * @iProduct: Used as iProduct override if @dev->iProduct is not set.
+ *	If NULL value of @name is taken.
+ * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
+ *	not set. If NULL a default "<system> <release> with <udc>" value
+ *	will be used.
+ * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
+ *	not set.
+ * @dev: Template descriptor for the device, including default device
+ *	identifiers.
+ * @strings: tables of strings, keyed by identifiers assigned during @bind
+ *	and language IDs provided in control requests
+ * @max_speed: Highest speed the driver supports.
+ * @needs_serial: set to 1 if the gadget needs userspace to provide
+ * 	a serial number.  If one is not provided, warning will be printed.
+ * @bind: (REQUIRED) Used to allocate resources that are shared across the
+ *	whole device, such as string IDs, and add its configurations using
+ *	@usb_add_config(). This may fail by returning a negative errno
+ *	value; it should return zero on successful initialization.
+ * @unbind: Reverses @bind; called as a side effect of unregistering
+ *	this driver.
+ * @disconnect: optional driver disconnect method
+ * @suspend: Notifies when the host stops sending USB traffic,
+ *	after function notifications
+ * @resume: Notifies configuration when the host restarts USB traffic,
+ *	before function notifications
+ *
+ * Devices default to reporting self powered operation.  Devices which rely
+ * on bus powered operation should report this in their @bind method.
+ *
+ * Before returning from @bind, various fields in the template descriptor
+ * may be overridden.  These include the idVendor/idProduct/bcdDevice values
+ * normally to bind the appropriate host side driver, and the three strings
+ * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
+ * meaningful device identifiers.  (The strings will not be defined unless
+ * they are defined in @dev and @strings.)  The correct ep0 maxpacket size
+ * is also reported, as defined by the underlying controller driver.
+ */
+struct usb_composite_driver {
+	const char				*name;
+	const char				*iProduct;
+	const char				*iManufacturer;
+	const char				*iSerialNumber;
+	const struct usb_device_descriptor	*dev;
+	struct usb_gadget_strings		**strings;
+	enum usb_device_speed			max_speed;
+	unsigned		needs_serial:1;
+
+	int			(*bind)(struct usb_composite_dev *cdev);
+	int			(*unbind)(struct usb_composite_dev *);
+
+	void			(*disconnect)(struct usb_composite_dev *);
+
+	/* global suspend hooks */
+	void			(*suspend)(struct usb_composite_dev *);
+	void			(*resume)(struct usb_composite_dev *);
+};
+
+extern int usb_composite_probe(struct usb_composite_driver *driver);
+extern void usb_composite_unregister(struct usb_composite_driver *driver);
+extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
+
+
+/**
+ * struct usb_composite_device - represents one composite usb gadget
+ * @gadget: read-only, abstracts the gadget's usb peripheral controller
+ * @req: used for control responses; buffer is pre-allocated
+ * @bufsiz: size of buffer pre-allocated in @req
+ * @config: the currently active configuration
+ *
+ * One of these devices is allocated and initialized before the
+ * associated device driver's bind() is called.
+ *
+ * OPEN ISSUE:  it appears that some WUSB devices will need to be
+ * built by combining a normal (wired) gadget with a wireless one.
+ * This revision of the gadget framework should probably try to make
+ * sure doing that won't hurt too much.
+ *
+ * One notion for how to handle Wireless USB devices involves:
+ * (a) a second gadget here, discovery mechanism TBD, but likely
+ *     needing separate "register/unregister WUSB gadget" calls;
+ * (b) updates to usb_gadget to include flags "is it wireless",
+ *     "is it wired", plus (presumably in a wrapper structure)
+ *     bandgroup and PHY info;
+ * (c) presumably a wireless_ep wrapping a usb_ep, and reporting
+ *     wireless-specific parameters like maxburst and maxsequence;
+ * (d) configurations that are specific to wireless links;
+ * (e) function drivers that understand wireless configs and will
+ *     support wireless for (additional) function instances;
+ * (f) a function to support association setup (like CBAF), not
+ *     necessarily requiring a wireless adapter;
+ * (g) composite device setup that can create one or more wireless
+ *     configs, including appropriate association setup support;
+ * (h) more, TBD.
+ */
+struct usb_composite_dev {
+	struct usb_gadget		*gadget;
+	struct usb_request		*req;
+	unsigned			bufsiz;
+
+	struct usb_configuration	*config;
+
+	/* private: */
+	/* internals */
+	unsigned int			suspended:1;
+	struct usb_device_descriptor	desc;
+	struct list_head		configs;
+	struct usb_composite_driver	*driver;
+	u8				next_string_id;
+	u8				manufacturer_override;
+	u8				product_override;
+	u8				serial_override;
+
+	/* the gadget driver won't enable the data pullup
+	 * while the deactivation count is nonzero.
+	 */
+	unsigned			deactivations;
+
+	/* the composite driver won't complete the control transfer's
+	 * data/status stages till delayed_status is zero.
+	 */
+	int				delayed_status;
+
+	/* protects deactivations and delayed_status counts*/
+	spinlock_t			lock;
+};
+
+extern int usb_string_id(struct usb_composite_dev *c);
+extern int usb_string_ids_tab(struct usb_composite_dev *c,
+			      struct usb_string *str);
+extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
+
+
+/* messaging utils */
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
+
+#endif	/* __LINUX_USB_COMPOSITE_H */
diff --git a/drivers/staging/ccg/config.c b/drivers/staging/ccg/config.c
new file mode 100644
index 0000000..7542a72c
--- /dev/null
+++ b/drivers/staging/ccg/config.c
@@ -0,0 +1,158 @@
+/*
+ * usb/gadget/config.c -- simplify building config descriptors
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * 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/errno.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * usb_descriptor_fillbuf - fill buffer with descriptors
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ *
+ * Copies descriptors into the buffer, returning the length or a
+ * negative error code if they can't all be copied.  Useful when
+ * assembling descriptors for an associated set of interfaces used
+ * as part of configuring a composite device; or in other cases where
+ * sets of descriptors need to be marshaled.
+ */
+int
+usb_descriptor_fillbuf(void *buf, unsigned buflen,
+		const struct usb_descriptor_header **src)
+{
+	u8	*dest = buf;
+
+	if (!src)
+		return -EINVAL;
+
+	/* fill buffer from src[] until null descriptor ptr */
+	for (; NULL != *src; src++) {
+		unsigned		len = (*src)->bLength;
+
+		if (len > buflen)
+			return -EINVAL;
+		memcpy(dest, *src, len);
+		buflen -= len;
+		dest += len;
+	}
+	return dest - (u8 *)buf;
+}
+
+
+/**
+ * usb_gadget_config_buf - builts a complete configuration descriptor
+ * @config: Header for the descriptor, including characteristics such
+ *	as power requirements and number of interfaces.
+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
+ *	endpoint, etc) defining all functions in this device configuration.
+ * @buf: Buffer for the resulting configuration descriptor.
+ * @length: Length of buffer.  If this is not big enough to hold the
+ *	entire configuration descriptor, an error code will be returned.
+ *
+ * This copies descriptors into the response buffer, building a descriptor
+ * for that configuration.  It returns the buffer length or a negative
+ * status code.  The config.wTotalLength field is set to match the length
+ * of the result, but other descriptor fields (including power usage and
+ * interface count) must be set by the caller.
+ *
+ * Gadget drivers could use this when constructing a config descriptor
+ * in response to USB_REQ_GET_DESCRIPTOR.  They will need to patch the
+ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
+ */
+int usb_gadget_config_buf(
+	const struct usb_config_descriptor	*config,
+	void					*buf,
+	unsigned				length,
+	const struct usb_descriptor_header	**desc
+)
+{
+	struct usb_config_descriptor		*cp = buf;
+	int					len;
+
+	/* config descriptor first */
+	if (length < USB_DT_CONFIG_SIZE || !desc)
+		return -EINVAL;
+	*cp = *config;
+
+	/* then interface/endpoint/class/vendor/... */
+	len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+			length - USB_DT_CONFIG_SIZE, desc);
+	if (len < 0)
+		return len;
+	len += USB_DT_CONFIG_SIZE;
+	if (len > 0xffff)
+		return -EINVAL;
+
+	/* patch up the config descriptor */
+	cp->bLength = USB_DT_CONFIG_SIZE;
+	cp->bDescriptorType = USB_DT_CONFIG;
+	cp->wTotalLength = cpu_to_le16(len);
+	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+	return len;
+}
+
+/**
+ * usb_copy_descriptors - copy a vector of USB descriptors
+ * @src: null-terminated vector to copy
+ * Context: initialization code, which may sleep
+ *
+ * This makes a copy of a vector of USB descriptors.  Its primary use
+ * is to support usb_function objects which can have multiple copies,
+ * each needing different descriptors.  Functions may have static
+ * tables of descriptors, which are used as templates and customized
+ * with identifiers (for interfaces, strings, endpoints, and more)
+ * as needed by a given function instance.
+ */
+struct usb_descriptor_header **
+usb_copy_descriptors(struct usb_descriptor_header **src)
+{
+	struct usb_descriptor_header **tmp;
+	unsigned bytes;
+	unsigned n_desc;
+	void *mem;
+	struct usb_descriptor_header **ret;
+
+	/* count descriptors and their sizes; then add vector size */
+	for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
+		bytes += (*tmp)->bLength;
+	bytes += (n_desc + 1) * sizeof(*tmp);
+
+	mem = kmalloc(bytes, GFP_KERNEL);
+	if (!mem)
+		return NULL;
+
+	/* fill in pointers starting at "tmp",
+	 * to descriptors copied starting at "mem";
+	 * and return "ret"
+	 */
+	tmp = mem;
+	ret = mem;
+	mem += (n_desc + 1) * sizeof(*tmp);
+	while (*src) {
+		memcpy(mem, *src, (*src)->bLength);
+		*tmp = mem;
+		tmp++;
+		mem += (*src)->bLength;
+		src++;
+	}
+	*tmp = NULL;
+
+	return ret;
+}
+
diff --git a/drivers/staging/ccg/epautoconf.c b/drivers/staging/ccg/epautoconf.c
new file mode 100644
index 0000000..51f3d42
--- /dev/null
+++ b/drivers/staging/ccg/epautoconf.c
@@ -0,0 +1,393 @@
+/*
+ * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
+ *
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "gadget_chips.h"
+
+
+/* we must assign addresses for configurable endpoints (like net2280) */
+static unsigned epnum;
+
+// #define MANY_ENDPOINTS
+#ifdef MANY_ENDPOINTS
+/* more than 15 configurable endpoints */
+static unsigned in_epnum;
+#endif
+
+
+/*
+ * This should work with endpoints from controller drivers sharing the
+ * same endpoint naming convention.  By example:
+ *
+ *	- ep1, ep2, ... address is fixed, not direction or type
+ *	- ep1in, ep2out, ... address and direction are fixed, not type
+ *	- ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ *	- ep1in-bulk, ep2out-iso, ... all three are fixed
+ *	- ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
+ * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE:  each endpoint is unidirectional, as specified by its USB
+ * descriptor; and isn't specific to a configuration or altsetting.
+ */
+static int
+ep_matches (
+	struct usb_gadget		*gadget,
+	struct usb_ep			*ep,
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+	u8		type;
+	const char	*tmp;
+	u16		max;
+
+	int		num_req_streams = 0;
+
+	/* endpoint already claimed? */
+	if (NULL != ep->driver_data)
+		return 0;
+
+	/* only support ep0 for portable CONTROL traffic */
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	if (USB_ENDPOINT_XFER_CONTROL == type)
+		return 0;
+
+	/* some other naming convention */
+	if ('e' != ep->name[0])
+		return 0;
+
+	/* type-restriction:  "-iso", "-bulk", or "-int".
+	 * direction-restriction:  "in", "out".
+	 */
+	if ('-' != ep->name[2]) {
+		tmp = strrchr (ep->name, '-');
+		if (tmp) {
+			switch (type) {
+			case USB_ENDPOINT_XFER_INT:
+				/* bulk endpoints handle interrupt transfers,
+				 * except the toggle-quirky iso-synch kind
+				 */
+				if ('s' == tmp[2])	// == "-iso"
+					return 0;
+				/* for now, avoid PXA "interrupt-in";
+				 * it's documented as never using DATA1.
+				 */
+				if (gadget_is_pxa (gadget)
+						&& 'i' == tmp [1])
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_BULK:
+				if ('b' != tmp[1])	// != "-bulk"
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				if ('s' != tmp[2])	// != "-iso"
+					return 0;
+			}
+		} else {
+			tmp = ep->name + strlen (ep->name);
+		}
+
+		/* direction-restriction:  "..in-..", "out-.." */
+		tmp--;
+		if (!isdigit (*tmp)) {
+			if (desc->bEndpointAddress & USB_DIR_IN) {
+				if ('n' != *tmp)
+					return 0;
+			} else {
+				if ('t' != *tmp)
+					return 0;
+			}
+		}
+	}
+
+	/*
+	 * Get the number of required streams from the EP companion
+	 * descriptor and see if the EP matches it
+	 */
+	if (usb_endpoint_xfer_bulk(desc)) {
+		if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
+			num_req_streams = ep_comp->bmAttributes & 0x1f;
+			if (num_req_streams > ep->max_streams)
+				return 0;
+		}
+
+	}
+
+	/*
+	 * If the protocol driver hasn't yet decided on wMaxPacketSize
+	 * and wants to know the maximum possible, provide the info.
+	 */
+	if (desc->wMaxPacketSize == 0)
+		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);
+
+	/* endpoint maxpacket size is an input parameter, except for bulk
+	 * where it's an output parameter representing the full speed limit.
+	 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+	 */
+	max = 0x7ff & usb_endpoint_maxp(desc);
+	switch (type) {
+	case USB_ENDPOINT_XFER_INT:
+		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
+		if (!gadget_is_dualspeed(gadget) && max > 64)
+			return 0;
+		/* FALLTHROUGH */
+
+	case USB_ENDPOINT_XFER_ISOC:
+		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
+		if (ep->maxpacket < max)
+			return 0;
+		if (!gadget_is_dualspeed(gadget) && max > 1023)
+			return 0;
+
+		/* BOTH:  "high bandwidth" works only at high speed */
+		if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
+			if (!gadget_is_dualspeed(gadget))
+				return 0;
+			/* configure your hardware with enough buffering!! */
+		}
+		break;
+	}
+
+	/* MATCH!! */
+
+	/* report address */
+	desc->bEndpointAddress &= USB_DIR_IN;
+	if (isdigit (ep->name [2])) {
+		u8	num = simple_strtoul (&ep->name [2], NULL, 10);
+		desc->bEndpointAddress |= num;
+#ifdef	MANY_ENDPOINTS
+	} else if (desc->bEndpointAddress & USB_DIR_IN) {
+		if (++in_epnum > 15)
+			return 0;
+		desc->bEndpointAddress = USB_DIR_IN | in_epnum;
+#endif
+	} else {
+		if (++epnum > 15)
+			return 0;
+		desc->bEndpointAddress |= epnum;
+	}
+
+	/* report (variable) full speed bulk maxpacket */
+	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
+		int size = ep->maxpacket;
+
+		/* min() doesn't work on bitfields with gcc-3.5 */
+		if (size > 64)
+			size = 64;
+		desc->wMaxPacketSize = cpu_to_le16(size);
+	}
+	ep->address = desc->bEndpointAddress;
+	return 1;
+}
+
+static struct usb_ep *
+find_ep (struct usb_gadget *gadget, const char *name)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		if (0 == strcmp (ep->name, name))
+			return ep;
+	}
+	return NULL;
+}
+
+/**
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
+ *
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig_ss(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+	struct usb_ep	*ep;
+	u8		type;
+
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	/* First, apply chip-specific "best usage" knowledge.
+	 * This might make a good usb_gadget_ops hook ...
+	 */
+	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
+		/* ep-e, ep-f are PIO with only 64 byte fifos */
+		ep = find_ep (gadget, "ep-e");
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			goto found_ep;
+		ep = find_ep (gadget, "ep-f");
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			goto found_ep;
+
+	} else if (gadget_is_goku (gadget)) {
+		if (USB_ENDPOINT_XFER_INT == type) {
+			/* single buffering is enough */
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc, ep_comp))
+				goto found_ep;
+		} else if (USB_ENDPOINT_XFER_BULK == type
+				&& (USB_DIR_IN & desc->bEndpointAddress)) {
+			/* DMA may be available */
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc,
+					      ep_comp))
+				goto found_ep;
+		}
+
+#ifdef CONFIG_BLACKFIN
+	} else if (gadget_is_musbhdrc(gadget)) {
+		if ((USB_ENDPOINT_XFER_BULK == type) ||
+		    (USB_ENDPOINT_XFER_ISOC == type)) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep (gadget, "ep5in");
+			else
+				ep = find_ep (gadget, "ep6out");
+		} else if (USB_ENDPOINT_XFER_INT == type) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep(gadget, "ep1in");
+			else
+				ep = find_ep(gadget, "ep2out");
+		} else
+			ep = NULL;
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			goto found_ep;
+#endif
+	}
+
+	/* Second, look at endpoints until an unclaimed one looks usable */
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		if (ep_matches(gadget, ep, desc, ep_comp))
+			goto found_ep;
+	}
+
+	/* Fail */
+	return NULL;
+found_ep:
+	ep->desc = NULL;
+	ep->comp_desc = NULL;
+	return ep;
+}
+
+/**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+
+
+/**
+ * usb_ep_autoconfig_reset - reset endpoint autoconfig state
+ * @gadget: device for which autoconfig state will be reset
+ *
+ * Use this for devices where one configuration may need to assign
+ * endpoint resources very differently from the next one.  It clears
+ * state such as ep->driver_data and the record of assigned endpoints
+ * used by usb_ep_autoconfig().
+ */
+void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		ep->driver_data = NULL;
+	}
+#ifdef	MANY_ENDPOINTS
+	in_epnum = 0;
+#endif
+	epnum = 0;
+}
+
diff --git a/drivers/staging/ccg/f_acm.c b/drivers/staging/ccg/f_acm.c
new file mode 100644
index 0000000..d672250a
--- /dev/null
+++ b/drivers/staging/ccg/f_acm.c
@@ -0,0 +1,814 @@
+/*
+ * f_acm.c -- USB CDC serial (ACM) function driver
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ * Copyright (C) 2009 by Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * either version 2 of that License or (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "gadget_chips.h"
+
+
+/*
+ * This CDC ACM function support just wraps control functions and
+ * notifications around the generic serial-over-usb code.
+ *
+ * Because CDC ACM is standardized by the USB-IF, many host operating
+ * systems have drivers for it.  Accordingly, ACM is the preferred
+ * interop solution for serial-port type connections.  The control
+ * models are often not necessary, and in any case don't do much in
+ * this bare-bones implementation.
+ *
+ * Note that even MS-Windows has some support for ACM.  However, that
+ * support is somewhat broken because when you use ACM in a composite
+ * device, having multiple interfaces confuses the poor OS.  It doesn't
+ * seem to understand CDC Union descriptors.  The new "association"
+ * descriptors (roughly equivalent to CDC Unions) may sometimes help.
+ */
+
+struct f_acm {
+	struct gserial			port;
+	u8				ctrl_id, data_id;
+	u8				port_num;
+
+	u8				pending;
+
+	/* lock is mostly for pending and notify_req ... they get accessed
+	 * by callbacks both from tty (open/close/break) under its spinlock,
+	 * and notify_req.complete() which can't use that lock.
+	 */
+	spinlock_t			lock;
+
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+
+	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
+
+	/* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
+	u16				port_handshake_bits;
+#define ACM_CTRL_RTS	(1 << 1)	/* unused with full duplex */
+#define ACM_CTRL_DTR	(1 << 0)	/* host is ready for data r/w */
+
+	/* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
+	u16				serial_state;
+#define ACM_CTRL_OVERRUN	(1 << 6)
+#define ACM_CTRL_PARITY		(1 << 5)
+#define ACM_CTRL_FRAMING	(1 << 4)
+#define ACM_CTRL_RI		(1 << 3)
+#define ACM_CTRL_BRK		(1 << 2)
+#define ACM_CTRL_DSR		(1 << 1)
+#define ACM_CTRL_DCD		(1 << 0)
+};
+
+static inline struct f_acm *func_to_acm(struct usb_function *f)
+{
+	return container_of(f, struct f_acm, port.func);
+}
+
+static inline struct f_acm *port_to_acm(struct gserial *p)
+{
+	return container_of(p, struct f_acm, port);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* notification endpoint uses smallish and infrequent fixed-size messages */
+
+#define GS_LOG2_NOTIFY_INTERVAL		5	/* 1 << 5 == 32 msec */
+#define GS_NOTIFY_MAXPACKET		10	/* notification + 2 bytes */
+
+/* interface and class descriptors: */
+
+static struct usb_interface_assoc_descriptor
+acm_iad_descriptor = {
+	.bLength =		sizeof acm_iad_descriptor,
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+
+	/* .bFirstInterface =	DYNAMIC, */
+	.bInterfaceCount = 	2,	// control + data
+	.bFunctionClass =	USB_CLASS_COMM,
+	.bFunctionSubClass =	USB_CDC_SUBCLASS_ACM,
+	.bFunctionProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
+	/* .iFunction =		DYNAMIC */
+};
+
+
+static struct usb_interface_descriptor acm_control_interface_desc = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
+	.bDescriptorType =	USB_DT_INTERFACE,
+	/* .bInterfaceNumber = DYNAMIC */
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ACM,
+	.bInterfaceProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_interface_descriptor acm_data_interface_desc = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
+	.bDescriptorType =	USB_DT_INTERFACE,
+	/* .bInterfaceNumber = DYNAMIC */
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc acm_header_desc = {
+	.bLength =		sizeof(acm_header_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor
+acm_call_mgmt_descriptor = {
+	.bLength =		sizeof(acm_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	/* .bDataInterface = DYNAMIC */
+};
+
+static struct usb_cdc_acm_descriptor acm_descriptor = {
+	.bLength =		sizeof(acm_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	USB_CDC_CAP_LINE,
+};
+
+static struct usb_cdc_union_desc acm_union_desc = {
+	.bLength =		sizeof(acm_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor acm_fs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
+};
+
+static struct usb_endpoint_descriptor acm_fs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor acm_fs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *acm_fs_function[] = {
+	(struct usb_descriptor_header *) &acm_iad_descriptor,
+	(struct usb_descriptor_header *) &acm_control_interface_desc,
+	(struct usb_descriptor_header *) &acm_header_desc,
+	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &acm_union_desc,
+	(struct usb_descriptor_header *) &acm_fs_notify_desc,
+	(struct usb_descriptor_header *) &acm_data_interface_desc,
+	(struct usb_descriptor_header *) &acm_fs_in_desc,
+	(struct usb_descriptor_header *) &acm_fs_out_desc,
+	NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor acm_hs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_endpoint_descriptor acm_hs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor acm_hs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *acm_hs_function[] = {
+	(struct usb_descriptor_header *) &acm_iad_descriptor,
+	(struct usb_descriptor_header *) &acm_control_interface_desc,
+	(struct usb_descriptor_header *) &acm_header_desc,
+	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &acm_union_desc,
+	(struct usb_descriptor_header *) &acm_hs_notify_desc,
+	(struct usb_descriptor_header *) &acm_data_interface_desc,
+	(struct usb_descriptor_header *) &acm_hs_in_desc,
+	(struct usb_descriptor_header *) &acm_hs_out_desc,
+	NULL,
+};
+
+static struct usb_endpoint_descriptor acm_ss_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor acm_ss_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
+	.bLength =              sizeof acm_ss_bulk_comp_desc,
+	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *acm_ss_function[] = {
+	(struct usb_descriptor_header *) &acm_iad_descriptor,
+	(struct usb_descriptor_header *) &acm_control_interface_desc,
+	(struct usb_descriptor_header *) &acm_header_desc,
+	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &acm_union_desc,
+	(struct usb_descriptor_header *) &acm_hs_notify_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &acm_data_interface_desc,
+	(struct usb_descriptor_header *) &acm_ss_in_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &acm_ss_out_desc,
+	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+	NULL,
+};
+
+/* string descriptors: */
+
+#define ACM_CTRL_IDX	0
+#define ACM_DATA_IDX	1
+#define ACM_IAD_IDX	2
+
+/* static strings, in UTF-8 */
+static struct usb_string acm_string_defs[] = {
+	[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
+	[ACM_DATA_IDX].s = "CDC ACM Data",
+	[ACM_IAD_IDX ].s = "CDC Serial",
+	{  /* ZEROES END LIST */ },
+};
+
+static struct usb_gadget_strings acm_string_table = {
+	.language =		0x0409,	/* en-us */
+	.strings =		acm_string_defs,
+};
+
+static struct usb_gadget_strings *acm_strings[] = {
+	&acm_string_table,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* ACM control ... data handling is delegated to tty library code.
+ * The main task of this function is to activate and deactivate
+ * that code based on device state; track parameters like line
+ * speed, handshake state, and so on; and issue notifications.
+ */
+
+static void acm_complete_set_line_coding(struct usb_ep *ep,
+		struct usb_request *req)
+{
+	struct f_acm	*acm = ep->driver_data;
+	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
+
+	if (req->status != 0) {
+		DBG(cdev, "acm ttyGS%d completion, err %d\n",
+				acm->port_num, req->status);
+		return;
+	}
+
+	/* normal completion */
+	if (req->actual != sizeof(acm->port_line_coding)) {
+		DBG(cdev, "acm ttyGS%d short resp, len %d\n",
+				acm->port_num, req->actual);
+		usb_ep_set_halt(ep);
+	} else {
+		struct usb_cdc_line_coding	*value = req->buf;
+
+		/* REVISIT:  we currently just remember this data.
+		 * If we change that, (a) validate it first, then
+		 * (b) update whatever hardware needs updating,
+		 * (c) worry about locking.  This is information on
+		 * the order of 9600-8-N-1 ... most of which means
+		 * nothing unless we control a real RS232 line.
+		 */
+		acm->port_line_coding = *value;
+	}
+}
+
+static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_acm		*acm = func_to_acm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request	*req = cdev->req;
+	int			value = -EOPNOTSUPP;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
+
+	/* composite driver infrastructure handles everything except
+	 * CDC class messages; interface activation uses set_alt().
+	 *
+	 * Note CDC spec table 4 lists the ACM request profile.  It requires
+	 * encapsulated command support ... we don't handle any, and respond
+	 * to them by stalling.  Options include get/set/clear comm features
+	 * (not that useful) and SEND_BREAK.
+	 */
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+	/* SET_LINE_CODING ... just read and save what the host sends */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_LINE_CODING:
+		if (w_length != sizeof(struct usb_cdc_line_coding)
+				|| w_index != acm->ctrl_id)
+			goto invalid;
+
+		value = w_length;
+		cdev->gadget->ep0->driver_data = acm;
+		req->complete = acm_complete_set_line_coding;
+		break;
+
+	/* GET_LINE_CODING ... return what host sent, or initial value */
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_GET_LINE_CODING:
+		if (w_index != acm->ctrl_id)
+			goto invalid;
+
+		value = min_t(unsigned, w_length,
+				sizeof(struct usb_cdc_line_coding));
+		memcpy(req->buf, &acm->port_line_coding, value);
+		break;
+
+	/* SET_CONTROL_LINE_STATE ... save what the host sent */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+		if (w_index != acm->ctrl_id)
+			goto invalid;
+
+		value = 0;
+
+		/* FIXME we should not allow data to flow until the
+		 * host sets the ACM_CTRL_DTR bit; and when it clears
+		 * that bit, we should return to that no-flow state.
+		 */
+		acm->port_handshake_bits = w_value;
+		break;
+
+	default:
+invalid:
+		VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* respond with data transfer or status phase? */
+	if (value >= 0) {
+		DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
+			acm->port_num, ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = 0;
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0)
+			ERROR(cdev, "acm response on ttyGS%d, err %d\n",
+					acm->port_num, value);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_acm		*acm = func_to_acm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	/* we know alt == 0, so this is an activation or a reset */
+
+	if (intf == acm->ctrl_id) {
+		if (acm->notify->driver_data) {
+			VDBG(cdev, "reset acm control interface %d\n", intf);
+			usb_ep_disable(acm->notify);
+		} else {
+			VDBG(cdev, "init acm ctrl interface %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+				return -EINVAL;
+		}
+		usb_ep_enable(acm->notify);
+		acm->notify->driver_data = acm;
+
+	} else if (intf == acm->data_id) {
+		if (acm->port.in->driver_data) {
+			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
+			gserial_disconnect(&acm->port);
+		}
+		if (!acm->port.in->desc || !acm->port.out->desc) {
+			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       acm->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       acm->port.out)) {
+				acm->port.in->desc = NULL;
+				acm->port.out->desc = NULL;
+				return -EINVAL;
+			}
+		}
+		gserial_connect(&acm->port, acm->port_num);
+
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void acm_disable(struct usb_function *f)
+{
+	struct f_acm	*acm = func_to_acm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
+	gserial_disconnect(&acm->port);
+	usb_ep_disable(acm->notify);
+	acm->notify->driver_data = NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * acm_cdc_notify - issue CDC notification to host
+ * @acm: wraps host to be notified
+ * @type: notification type
+ * @value: Refer to cdc specs, wValue field.
+ * @data: data to be sent
+ * @length: size of data
+ * Context: irqs blocked, acm->lock held, acm_notify_req non-null
+ *
+ * Returns zero on success or a negative errno.
+ *
+ * See section 6.3.5 of the CDC 1.1 specification for information
+ * about the only notification we issue:  SerialState change.
+ */
+static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
+		void *data, unsigned length)
+{
+	struct usb_ep			*ep = acm->notify;
+	struct usb_request		*req;
+	struct usb_cdc_notification	*notify;
+	const unsigned			len = sizeof(*notify) + length;
+	void				*buf;
+	int				status;
+
+	req = acm->notify_req;
+	acm->notify_req = NULL;
+	acm->pending = false;
+
+	req->length = len;
+	notify = req->buf;
+	buf = notify + 1;
+
+	notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+			| USB_RECIP_INTERFACE;
+	notify->bNotificationType = type;
+	notify->wValue = cpu_to_le16(value);
+	notify->wIndex = cpu_to_le16(acm->ctrl_id);
+	notify->wLength = cpu_to_le16(length);
+	memcpy(buf, data, length);
+
+	/* ep_queue() can complete immediately if it fills the fifo... */
+	spin_unlock(&acm->lock);
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	spin_lock(&acm->lock);
+
+	if (status < 0) {
+		ERROR(acm->port.func.config->cdev,
+				"acm ttyGS%d can't notify serial state, %d\n",
+				acm->port_num, status);
+		acm->notify_req = req;
+	}
+
+	return status;
+}
+
+static int acm_notify_serial_state(struct f_acm *acm)
+{
+	struct usb_composite_dev *cdev = acm->port.func.config->cdev;
+	int			status;
+
+	spin_lock(&acm->lock);
+	if (acm->notify_req) {
+		DBG(cdev, "acm ttyGS%d serial state %04x\n",
+				acm->port_num, acm->serial_state);
+		status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
+				0, &acm->serial_state, sizeof(acm->serial_state));
+	} else {
+		acm->pending = true;
+		status = 0;
+	}
+	spin_unlock(&acm->lock);
+	return status;
+}
+
+static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_acm		*acm = req->context;
+	u8			doit = false;
+
+	/* on this call path we do NOT hold the port spinlock,
+	 * which is why ACM needs its own spinlock
+	 */
+	spin_lock(&acm->lock);
+	if (req->status != -ESHUTDOWN)
+		doit = acm->pending;
+	acm->notify_req = req;
+	spin_unlock(&acm->lock);
+
+	if (doit)
+		acm_notify_serial_state(acm);
+}
+
+/* connect == the TTY link is open */
+
+static void acm_connect(struct gserial *port)
+{
+	struct f_acm		*acm = port_to_acm(port);
+
+	acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
+	acm_notify_serial_state(acm);
+}
+
+static void acm_disconnect(struct gserial *port)
+{
+	struct f_acm		*acm = port_to_acm(port);
+
+	acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
+	acm_notify_serial_state(acm);
+}
+
+static int acm_send_break(struct gserial *port, int duration)
+{
+	struct f_acm		*acm = port_to_acm(port);
+	u16			state;
+
+	state = acm->serial_state;
+	state &= ~ACM_CTRL_BRK;
+	if (duration)
+		state |= ACM_CTRL_BRK;
+
+	acm->serial_state = state;
+	return acm_notify_serial_state(acm);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ACM function driver setup/binding */
+static int
+acm_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_acm		*acm = func_to_acm(f);
+	int			status;
+	struct usb_ep		*ep;
+
+	/* allocate instance-specific interface IDs, and patch descriptors */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	acm->ctrl_id = status;
+	acm_iad_descriptor.bFirstInterface = status;
+
+	acm_control_interface_desc.bInterfaceNumber = status;
+	acm_union_desc .bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	acm->data_id = status;
+
+	acm_data_interface_desc.bInterfaceNumber = status;
+	acm_union_desc.bSlaveInterface0 = status;
+	acm_call_mgmt_descriptor.bDataInterface = status;
+
+	status = -ENODEV;
+
+	/* allocate instance-specific endpoints */
+	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
+	if (!ep)
+		goto fail;
+	acm->port.in = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
+	if (!ep)
+		goto fail;
+	acm->port.out = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
+	if (!ep)
+		goto fail;
+	acm->notify = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	/* allocate notification */
+	acm->notify_req = gs_alloc_req(ep,
+			sizeof(struct usb_cdc_notification) + 2,
+			GFP_KERNEL);
+	if (!acm->notify_req)
+		goto fail;
+
+	acm->notify_req->complete = acm_cdc_notify_complete;
+	acm->notify_req->context = acm;
+
+	/* copy descriptors */
+	f->descriptors = usb_copy_descriptors(acm_fs_function);
+	if (!f->descriptors)
+		goto fail;
+
+	/* support all relevant hardware speeds... we expect that when
+	 * hardware is dual speed, all bulk-capable endpoints work at
+	 * both speeds
+	 */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		acm_hs_in_desc.bEndpointAddress =
+				acm_fs_in_desc.bEndpointAddress;
+		acm_hs_out_desc.bEndpointAddress =
+				acm_fs_out_desc.bEndpointAddress;
+		acm_hs_notify_desc.bEndpointAddress =
+				acm_fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors */
+		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
+	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		acm_ss_in_desc.bEndpointAddress =
+			acm_fs_in_desc.bEndpointAddress;
+		acm_ss_out_desc.bEndpointAddress =
+			acm_fs_out_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
+	}
+
+	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			acm->port_num,
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
+			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+			acm->port.in->name, acm->port.out->name,
+			acm->notify->name);
+	return 0;
+
+fail:
+	if (acm->notify_req)
+		gs_free_req(acm->notify, acm->notify_req);
+
+	/* we might as well release our claims on endpoints */
+	if (acm->notify)
+		acm->notify->driver_data = NULL;
+	if (acm->port.out)
+		acm->port.out->driver_data = NULL;
+	if (acm->port.in)
+		acm->port.in->driver_data = NULL;
+
+	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
+
+	return status;
+}
+
+static void
+acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_acm		*acm = func_to_acm(f);
+
+	if (gadget_is_dualspeed(c->cdev->gadget))
+		usb_free_descriptors(f->hs_descriptors);
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
+	usb_free_descriptors(f->descriptors);
+	gs_free_req(acm->notify, acm->notify_req);
+	kfree(acm);
+}
+
+/* Some controllers can't support CDC ACM ... */
+static inline bool can_support_cdc(struct usb_configuration *c)
+{
+	/* everything else is *probably* fine ... */
+	return true;
+}
+
+/**
+ * acm_bind_config - add a CDC ACM function to a configuration
+ * @c: the configuration to support the CDC ACM instance
+ * @port_num: /dev/ttyGS* port this interface will use
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gserial_setup() with enough ports to
+ * handle all the ones it binds.  Caller is also responsible
+ * for calling @gserial_cleanup() before module unload.
+ */
+int acm_bind_config(struct usb_configuration *c, u8 port_num)
+{
+	struct f_acm	*acm;
+	int		status;
+
+	if (!can_support_cdc(c))
+		return -EINVAL;
+
+	/* REVISIT might want instance-specific strings to help
+	 * distinguish instances ...
+	 */
+
+	/* maybe allocate device-global string IDs, and patch descriptors */
+	if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		acm_string_defs[ACM_CTRL_IDX].id = status;
+
+		acm_control_interface_desc.iInterface = status;
+
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		acm_string_defs[ACM_DATA_IDX].id = status;
+
+		acm_data_interface_desc.iInterface = status;
+
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		acm_string_defs[ACM_IAD_IDX].id = status;
+
+		acm_iad_descriptor.iFunction = status;
+	}
+
+	/* allocate and initialize one new instance */
+	acm = kzalloc(sizeof *acm, GFP_KERNEL);
+	if (!acm)
+		return -ENOMEM;
+
+	spin_lock_init(&acm->lock);
+
+	acm->port_num = port_num;
+
+	acm->port.connect = acm_connect;
+	acm->port.disconnect = acm_disconnect;
+	acm->port.send_break = acm_send_break;
+
+	acm->port.func.name = "acm";
+	acm->port.func.strings = acm_strings;
+	/* descriptors are per-instance copies */
+	acm->port.func.bind = acm_bind;
+	acm->port.func.unbind = acm_unbind;
+	acm->port.func.set_alt = acm_set_alt;
+	acm->port.func.setup = acm_setup;
+	acm->port.func.disable = acm_disable;
+
+	status = usb_add_function(c, &acm->port.func);
+	if (status)
+		kfree(acm);
+	return status;
+}
diff --git a/drivers/staging/ccg/f_fs.c b/drivers/staging/ccg/f_fs.c
new file mode 100644
index 0000000..8adc79d
--- /dev/null
+++ b/drivers/staging/ccg/f_fs.c
@@ -0,0 +1,2455 @@
+/*
+ * f_fs.c -- user mode file system API for USB composite function controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz <mina86@mina86.com>
+ *
+ * Based on inode.c (GadgetFS) which was:
+ * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003 Agilent Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/blkdev.h>
+#include <linux/pagemap.h>
+#include <linux/export.h>
+#include <linux/hid.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/functionfs.h>
+
+
+#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */
+
+
+/* Debugging ****************************************************************/
+
+#ifdef VERBOSE_DEBUG
+#  define pr_vdebug pr_debug
+#  define ffs_dump_mem(prefix, ptr, len) \
+	print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
+#else
+#  define pr_vdebug(...)                 do { } while (0)
+#  define ffs_dump_mem(prefix, ptr, len) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define ENTER()    pr_vdebug("%s()\n", __func__)
+
+
+/* The data structure and setup file ****************************************/
+
+enum ffs_state {
+	/*
+	 * Waiting for descriptors and strings.
+	 *
+	 * In this state no open(2), read(2) or write(2) on epfiles
+	 * may succeed (which should not be the problem as there
+	 * should be no such files opened in the first place).
+	 */
+	FFS_READ_DESCRIPTORS,
+	FFS_READ_STRINGS,
+
+	/*
+	 * We've got descriptors and strings.  We are or have called
+	 * functionfs_ready_callback().  functionfs_bind() may have
+	 * been called but we don't know.
+	 *
+	 * This is the only state in which operations on epfiles may
+	 * succeed.
+	 */
+	FFS_ACTIVE,
+
+	/*
+	 * All endpoints have been closed.  This state is also set if
+	 * we encounter an unrecoverable error.  The only
+	 * unrecoverable error is situation when after reading strings
+	 * from user space we fail to initialise epfiles or
+	 * functionfs_ready_callback() returns with error (<0).
+	 *
+	 * In this state no open(2), read(2) or write(2) (both on ep0
+	 * as well as epfile) may succeed (at this point epfiles are
+	 * unlinked and all closed so this is not a problem; ep0 is
+	 * also closed but ep0 file exists and so open(2) on ep0 must
+	 * fail).
+	 */
+	FFS_CLOSING
+};
+
+
+enum ffs_setup_state {
+	/* There is no setup request pending. */
+	FFS_NO_SETUP,
+	/*
+	 * User has read events and there was a setup request event
+	 * there.  The next read/write on ep0 will handle the
+	 * request.
+	 */
+	FFS_SETUP_PENDING,
+	/*
+	 * There was event pending but before user space handled it
+	 * some other event was introduced which canceled existing
+	 * setup.  If this state is set read/write on ep0 return
+	 * -EIDRM.  This state is only set when adding event.
+	 */
+	FFS_SETUP_CANCELED
+};
+
+
+
+struct ffs_epfile;
+struct ffs_function;
+
+struct ffs_data {
+	struct usb_gadget		*gadget;
+
+	/*
+	 * Protect access read/write operations, only one read/write
+	 * at a time.  As a consequence protects ep0req and company.
+	 * While setup request is being processed (queued) this is
+	 * held.
+	 */
+	struct mutex			mutex;
+
+	/*
+	 * Protect access to endpoint related structures (basically
+	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
+	 * endpoint zero.
+	 */
+	spinlock_t			eps_lock;
+
+	/*
+	 * XXX REVISIT do we need our own request? Since we are not
+	 * handling setup requests immediately user space may be so
+	 * slow that another setup will be sent to the gadget but this
+	 * time not to us but another function and then there could be
+	 * a race.  Is that the case? Or maybe we can use cdev->req
+	 * after all, maybe we just need some spinlock for that?
+	 */
+	struct usb_request		*ep0req;		/* P: mutex */
+	struct completion		ep0req_completion;	/* P: mutex */
+	int				ep0req_status;		/* P: mutex */
+
+	/* reference counter */
+	atomic_t			ref;
+	/* how many files are opened (EP0 and others) */
+	atomic_t			opened;
+
+	/* EP0 state */
+	enum ffs_state			state;
+
+	/*
+	 * Possible transitions:
+	 * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock
+	 *               happens only in ep0 read which is P: mutex
+	 * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock
+	 *               happens only in ep0 i/o  which is P: mutex
+	 * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
+	 * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg
+	 */
+	enum ffs_setup_state		setup_state;
+
+#define FFS_SETUP_STATE(ffs)					\
+	((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,	\
+				       FFS_SETUP_CANCELED, FFS_NO_SETUP))
+
+	/* Events & such. */
+	struct {
+		u8				types[4];
+		unsigned short			count;
+		/* XXX REVISIT need to update it in some places, or do we? */
+		unsigned short			can_stall;
+		struct usb_ctrlrequest		setup;
+
+		wait_queue_head_t		waitq;
+	} ev; /* the whole structure, P: ev.waitq.lock */
+
+	/* Flags */
+	unsigned long			flags;
+#define FFS_FL_CALL_CLOSED_CALLBACK 0
+#define FFS_FL_BOUND                1
+
+	/* Active function */
+	struct ffs_function		*func;
+
+	/*
+	 * Device name, write once when file system is mounted.
+	 * Intended for user to read if she wants.
+	 */
+	const char			*dev_name;
+	/* Private data for our user (ie. gadget).  Managed by user. */
+	void				*private_data;
+
+	/* filled by __ffs_data_got_descs() */
+	/*
+	 * Real descriptors are 16 bytes after raw_descs (so you need
+	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
+	 * first full speed descriptor).  raw_descs_length and
+	 * raw_fs_descs_length do not have those 16 bytes added.
+	 */
+	const void			*raw_descs;
+	unsigned			raw_descs_length;
+	unsigned			raw_fs_descs_length;
+	unsigned			fs_descs_count;
+	unsigned			hs_descs_count;
+
+	unsigned short			strings_count;
+	unsigned short			interfaces_count;
+	unsigned short			eps_count;
+	unsigned short			_pad1;
+
+	/* filled by __ffs_data_got_strings() */
+	/* ids in stringtabs are set in functionfs_bind() */
+	const void			*raw_strings;
+	struct usb_gadget_strings	**stringtabs;
+
+	/*
+	 * File system's super block, write once when file system is
+	 * mounted.
+	 */
+	struct super_block		*sb;
+
+	/* File permissions, written once when fs is mounted */
+	struct ffs_file_perms {
+		umode_t				mode;
+		uid_t				uid;
+		gid_t				gid;
+	}				file_perms;
+
+	/*
+	 * The endpoint files, filled by ffs_epfiles_create(),
+	 * destroyed by ffs_epfiles_destroy().
+	 */
+	struct ffs_epfile		*epfiles;
+};
+
+/* Reference counter handling */
+static void ffs_data_get(struct ffs_data *ffs);
+static void ffs_data_put(struct ffs_data *ffs);
+/* Creates new ffs_data object. */
+static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
+
+/* Opened counter handling. */
+static void ffs_data_opened(struct ffs_data *ffs);
+static void ffs_data_closed(struct ffs_data *ffs);
+
+/* Called with ffs->mutex held; take over ownership of data. */
+static int __must_check
+__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
+static int __must_check
+__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
+
+
+/* The function structure ***************************************************/
+
+struct ffs_ep;
+
+struct ffs_function {
+	struct usb_configuration	*conf;
+	struct usb_gadget		*gadget;
+	struct ffs_data			*ffs;
+
+	struct ffs_ep			*eps;
+	u8				eps_revmap[16];
+	short				*interfaces_nums;
+
+	struct usb_function		function;
+};
+
+
+static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
+{
+	return container_of(f, struct ffs_function, function);
+}
+
+static void ffs_func_free(struct ffs_function *func);
+
+static void ffs_func_eps_disable(struct ffs_function *func);
+static int __must_check ffs_func_eps_enable(struct ffs_function *func);
+
+static int ffs_func_bind(struct usb_configuration *,
+			 struct usb_function *);
+static void ffs_func_unbind(struct usb_configuration *,
+			    struct usb_function *);
+static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
+static void ffs_func_disable(struct usb_function *);
+static int ffs_func_setup(struct usb_function *,
+			  const struct usb_ctrlrequest *);
+static void ffs_func_suspend(struct usb_function *);
+static void ffs_func_resume(struct usb_function *);
+
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
+
+
+/* The endpoints structures *************************************************/
+
+struct ffs_ep {
+	struct usb_ep			*ep;	/* P: ffs->eps_lock */
+	struct usb_request		*req;	/* P: epfile->mutex */
+
+	/* [0]: full speed, [1]: high speed */
+	struct usb_endpoint_descriptor	*descs[2];
+
+	u8				num;
+
+	int				status;	/* P: epfile->mutex */
+};
+
+struct ffs_epfile {
+	/* Protects ep->ep and ep->req. */
+	struct mutex			mutex;
+	wait_queue_head_t		wait;
+
+	struct ffs_data			*ffs;
+	struct ffs_ep			*ep;	/* P: ffs->eps_lock */
+
+	struct dentry			*dentry;
+
+	char				name[5];
+
+	unsigned char			in;	/* P: ffs->eps_lock */
+	unsigned char			isoc;	/* P: ffs->eps_lock */
+
+	unsigned char			_pad;
+};
+
+static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+
+static struct inode *__must_check
+ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
+		   const struct file_operations *fops,
+		   struct dentry **dentry_p);
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+	__attribute__((warn_unused_result, nonnull));
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+	__attribute__((warn_unused_result, nonnull));
+
+
+/* Control file aka ep0 *****************************************************/
+
+static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ffs_data *ffs = req->context;
+
+	complete_all(&ffs->ep0req_completion);
+}
+
+static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
+{
+	struct usb_request *req = ffs->ep0req;
+	int ret;
+
+	req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+
+	req->buf      = data;
+	req->length   = len;
+
+	/*
+	 * UDC layer requires to provide a buffer even for ZLP, but should
+	 * not use it at all. Let's provide some poisoned pointer to catch
+	 * possible bug in the driver.
+	 */
+	if (req->buf == NULL)
+		req->buf = (void *)0xDEADBABE;
+
+	INIT_COMPLETION(ffs->ep0req_completion);
+
+	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
+	if (unlikely(ret)) {
+		usb_ep_dequeue(ffs->gadget->ep0, req);
+		return -EINTR;
+	}
+
+	ffs->setup_state = FFS_NO_SETUP;
+	return ffs->ep0req_status;
+}
+
+static int __ffs_ep0_stall(struct ffs_data *ffs)
+{
+	if (ffs->ev.can_stall) {
+		pr_vdebug("ep0 stall\n");
+		usb_ep_set_halt(ffs->gadget->ep0);
+		ffs->setup_state = FFS_NO_SETUP;
+		return -EL2HLT;
+	} else {
+		pr_debug("bogus ep0 stall!\n");
+		return -ESRCH;
+	}
+}
+
+static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
+			     size_t len, loff_t *ptr)
+{
+	struct ffs_data *ffs = file->private_data;
+	ssize_t ret;
+	char *data;
+
+	ENTER();
+
+	/* Fast check if setup was canceled */
+	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+		return -EIDRM;
+
+	/* Acquire mutex */
+	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+	if (unlikely(ret < 0))
+		return ret;
+
+	/* Check state */
+	switch (ffs->state) {
+	case FFS_READ_DESCRIPTORS:
+	case FFS_READ_STRINGS:
+		/* Copy data */
+		if (unlikely(len < 16)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		data = ffs_prepare_buffer(buf, len);
+		if (IS_ERR(data)) {
+			ret = PTR_ERR(data);
+			break;
+		}
+
+		/* Handle data */
+		if (ffs->state == FFS_READ_DESCRIPTORS) {
+			pr_info("read descriptors\n");
+			ret = __ffs_data_got_descs(ffs, data, len);
+			if (unlikely(ret < 0))
+				break;
+
+			ffs->state = FFS_READ_STRINGS;
+			ret = len;
+		} else {
+			pr_info("read strings\n");
+			ret = __ffs_data_got_strings(ffs, data, len);
+			if (unlikely(ret < 0))
+				break;
+
+			ret = ffs_epfiles_create(ffs);
+			if (unlikely(ret)) {
+				ffs->state = FFS_CLOSING;
+				break;
+			}
+
+			ffs->state = FFS_ACTIVE;
+			mutex_unlock(&ffs->mutex);
+
+			ret = functionfs_ready_callback(ffs);
+			if (unlikely(ret < 0)) {
+				ffs->state = FFS_CLOSING;
+				return ret;
+			}
+
+			set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
+			return len;
+		}
+		break;
+
+	case FFS_ACTIVE:
+		data = NULL;
+		/*
+		 * We're called from user space, we can use _irq
+		 * rather then _irqsave
+		 */
+		spin_lock_irq(&ffs->ev.waitq.lock);
+		switch (FFS_SETUP_STATE(ffs)) {
+		case FFS_SETUP_CANCELED:
+			ret = -EIDRM;
+			goto done_spin;
+
+		case FFS_NO_SETUP:
+			ret = -ESRCH;
+			goto done_spin;
+
+		case FFS_SETUP_PENDING:
+			break;
+		}
+
+		/* FFS_SETUP_PENDING */
+		if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+			ret = __ffs_ep0_stall(ffs);
+			break;
+		}
+
+		/* FFS_SETUP_PENDING and not stall */
+		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+		spin_unlock_irq(&ffs->ev.waitq.lock);
+
+		data = ffs_prepare_buffer(buf, len);
+		if (IS_ERR(data)) {
+			ret = PTR_ERR(data);
+			break;
+		}
+
+		spin_lock_irq(&ffs->ev.waitq.lock);
+
+		/*
+		 * We are guaranteed to be still in FFS_ACTIVE state
+		 * but the state of setup could have changed from
+		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
+		 * to check for that.  If that happened we copied data
+		 * from user space in vain but it's unlikely.
+		 *
+		 * For sure we are not in FFS_NO_SETUP since this is
+		 * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
+		 * transition can be performed and it's protected by
+		 * mutex.
+		 */
+		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+			ret = -EIDRM;
+done_spin:
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+		} else {
+			/* unlocks spinlock */
+			ret = __ffs_ep0_queue_wait(ffs, data, len);
+		}
+		kfree(data);
+		break;
+
+	default:
+		ret = -EBADFD;
+		break;
+	}
+
+	mutex_unlock(&ffs->mutex);
+	return ret;
+}
+
+static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
+				     size_t n)
+{
+	/*
+	 * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
+	 * to release them.
+	 */
+	struct usb_functionfs_event events[n];
+	unsigned i = 0;
+
+	memset(events, 0, sizeof events);
+
+	do {
+		events[i].type = ffs->ev.types[i];
+		if (events[i].type == FUNCTIONFS_SETUP) {
+			events[i].u.setup = ffs->ev.setup;
+			ffs->setup_state = FFS_SETUP_PENDING;
+		}
+	} while (++i < n);
+
+	if (n < ffs->ev.count) {
+		ffs->ev.count -= n;
+		memmove(ffs->ev.types, ffs->ev.types + n,
+			ffs->ev.count * sizeof *ffs->ev.types);
+	} else {
+		ffs->ev.count = 0;
+	}
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+	mutex_unlock(&ffs->mutex);
+
+	return unlikely(__copy_to_user(buf, events, sizeof events))
+		? -EFAULT : sizeof events;
+}
+
+static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
+			    size_t len, loff_t *ptr)
+{
+	struct ffs_data *ffs = file->private_data;
+	char *data = NULL;
+	size_t n;
+	int ret;
+
+	ENTER();
+
+	/* Fast check if setup was canceled */
+	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+		return -EIDRM;
+
+	/* Acquire mutex */
+	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+	if (unlikely(ret < 0))
+		return ret;
+
+	/* Check state */
+	if (ffs->state != FFS_ACTIVE) {
+		ret = -EBADFD;
+		goto done_mutex;
+	}
+
+	/*
+	 * We're called from user space, we can use _irq rather then
+	 * _irqsave
+	 */
+	spin_lock_irq(&ffs->ev.waitq.lock);
+
+	switch (FFS_SETUP_STATE(ffs)) {
+	case FFS_SETUP_CANCELED:
+		ret = -EIDRM;
+		break;
+
+	case FFS_NO_SETUP:
+		n = len / sizeof(struct usb_functionfs_event);
+		if (unlikely(!n)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
+			ret = -EAGAIN;
+			break;
+		}
+
+		if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
+							ffs->ev.count)) {
+			ret = -EINTR;
+			break;
+		}
+
+		return __ffs_ep0_read_events(ffs, buf,
+					     min(n, (size_t)ffs->ev.count));
+
+	case FFS_SETUP_PENDING:
+		if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+			ret = __ffs_ep0_stall(ffs);
+			goto done_mutex;
+		}
+
+		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+		spin_unlock_irq(&ffs->ev.waitq.lock);
+
+		if (likely(len)) {
+			data = kmalloc(len, GFP_KERNEL);
+			if (unlikely(!data)) {
+				ret = -ENOMEM;
+				goto done_mutex;
+			}
+		}
+
+		spin_lock_irq(&ffs->ev.waitq.lock);
+
+		/* See ffs_ep0_write() */
+		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+			ret = -EIDRM;
+			break;
+		}
+
+		/* unlocks spinlock */
+		ret = __ffs_ep0_queue_wait(ffs, data, len);
+		if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
+			ret = -EFAULT;
+		goto done_mutex;
+
+	default:
+		ret = -EBADFD;
+		break;
+	}
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+done_mutex:
+	mutex_unlock(&ffs->mutex);
+	kfree(data);
+	return ret;
+}
+
+static int ffs_ep0_open(struct inode *inode, struct file *file)
+{
+	struct ffs_data *ffs = inode->i_private;
+
+	ENTER();
+
+	if (unlikely(ffs->state == FFS_CLOSING))
+		return -EBUSY;
+
+	file->private_data = ffs;
+	ffs_data_opened(ffs);
+
+	return 0;
+}
+
+static int ffs_ep0_release(struct inode *inode, struct file *file)
+{
+	struct ffs_data *ffs = file->private_data;
+
+	ENTER();
+
+	ffs_data_closed(ffs);
+
+	return 0;
+}
+
+static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
+{
+	struct ffs_data *ffs = file->private_data;
+	struct usb_gadget *gadget = ffs->gadget;
+	long ret;
+
+	ENTER();
+
+	if (code == FUNCTIONFS_INTERFACE_REVMAP) {
+		struct ffs_function *func = ffs->func;
+		ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
+	} else if (gadget && gadget->ops->ioctl) {
+		ret = gadget->ops->ioctl(gadget, code, value);
+	} else {
+		ret = -ENOTTY;
+	}
+
+	return ret;
+}
+
+static const struct file_operations ffs_ep0_operations = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+
+	.open =		ffs_ep0_open,
+	.write =	ffs_ep0_write,
+	.read =		ffs_ep0_read,
+	.release =	ffs_ep0_release,
+	.unlocked_ioctl =	ffs_ep0_ioctl,
+};
+
+
+/* "Normal" endpoints operations ********************************************/
+
+static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+	ENTER();
+	if (likely(req->context)) {
+		struct ffs_ep *ep = _ep->driver_data;
+		ep->status = req->status ? req->status : req->actual;
+		complete(req->context);
+	}
+}
+
+static ssize_t ffs_epfile_io(struct file *file,
+			     char __user *buf, size_t len, int read)
+{
+	struct ffs_epfile *epfile = file->private_data;
+	struct ffs_ep *ep;
+	char *data = NULL;
+	ssize_t ret;
+	int halt;
+
+	goto first_try;
+	do {
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+		mutex_unlock(&epfile->mutex);
+
+first_try:
+		/* Are we still active? */
+		if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
+			ret = -ENODEV;
+			goto error;
+		}
+
+		/* Wait for endpoint to be enabled */
+		ep = epfile->ep;
+		if (!ep) {
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				goto error;
+			}
+
+			if (wait_event_interruptible(epfile->wait,
+						     (ep = epfile->ep))) {
+				ret = -EINTR;
+				goto error;
+			}
+		}
+
+		/* Do we halt? */
+		halt = !read == !epfile->in;
+		if (halt && epfile->isoc) {
+			ret = -EINVAL;
+			goto error;
+		}
+
+		/* Allocate & copy */
+		if (!halt && !data) {
+			data = kzalloc(len, GFP_KERNEL);
+			if (unlikely(!data))
+				return -ENOMEM;
+
+			if (!read &&
+			    unlikely(__copy_from_user(data, buf, len))) {
+				ret = -EFAULT;
+				goto error;
+			}
+		}
+
+		/* We will be using request */
+		ret = ffs_mutex_lock(&epfile->mutex,
+				     file->f_flags & O_NONBLOCK);
+		if (unlikely(ret))
+			goto error;
+
+		/*
+		 * We're called from user space, we can use _irq rather then
+		 * _irqsave
+		 */
+		spin_lock_irq(&epfile->ffs->eps_lock);
+
+		/*
+		 * While we were acquiring mutex endpoint got disabled
+		 * or changed?
+		 */
+	} while (unlikely(epfile->ep != ep));
+
+	/* Halt */
+	if (unlikely(halt)) {
+		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
+			usb_ep_set_halt(ep->ep);
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+		ret = -EBADMSG;
+	} else {
+		/* Fire the request */
+		DECLARE_COMPLETION_ONSTACK(done);
+
+		struct usb_request *req = ep->req;
+		req->context  = &done;
+		req->complete = ffs_epfile_io_complete;
+		req->buf      = data;
+		req->length   = len;
+
+		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+
+		if (unlikely(ret < 0)) {
+			/* nop */
+		} else if (unlikely(wait_for_completion_interruptible(&done))) {
+			ret = -EINTR;
+			usb_ep_dequeue(ep->ep, req);
+		} else {
+			ret = ep->status;
+			if (read && ret > 0 &&
+			    unlikely(copy_to_user(buf, data, ret)))
+				ret = -EFAULT;
+		}
+	}
+
+	mutex_unlock(&epfile->mutex);
+error:
+	kfree(data);
+	return ret;
+}
+
+static ssize_t
+ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
+		 loff_t *ptr)
+{
+	ENTER();
+
+	return ffs_epfile_io(file, (char __user *)buf, len, 0);
+}
+
+static ssize_t
+ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
+{
+	ENTER();
+
+	return ffs_epfile_io(file, buf, len, 1);
+}
+
+static int
+ffs_epfile_open(struct inode *inode, struct file *file)
+{
+	struct ffs_epfile *epfile = inode->i_private;
+
+	ENTER();
+
+	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+		return -ENODEV;
+
+	file->private_data = epfile;
+	ffs_data_opened(epfile->ffs);
+
+	return 0;
+}
+
+static int
+ffs_epfile_release(struct inode *inode, struct file *file)
+{
+	struct ffs_epfile *epfile = inode->i_private;
+
+	ENTER();
+
+	ffs_data_closed(epfile->ffs);
+
+	return 0;
+}
+
+static long ffs_epfile_ioctl(struct file *file, unsigned code,
+			     unsigned long value)
+{
+	struct ffs_epfile *epfile = file->private_data;
+	int ret;
+
+	ENTER();
+
+	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+		return -ENODEV;
+
+	spin_lock_irq(&epfile->ffs->eps_lock);
+	if (likely(epfile->ep)) {
+		switch (code) {
+		case FUNCTIONFS_FIFO_STATUS:
+			ret = usb_ep_fifo_status(epfile->ep->ep);
+			break;
+		case FUNCTIONFS_FIFO_FLUSH:
+			usb_ep_fifo_flush(epfile->ep->ep);
+			ret = 0;
+			break;
+		case FUNCTIONFS_CLEAR_HALT:
+			ret = usb_ep_clear_halt(epfile->ep->ep);
+			break;
+		case FUNCTIONFS_ENDPOINT_REVMAP:
+			ret = epfile->ep->num;
+			break;
+		default:
+			ret = -ENOTTY;
+		}
+	} else {
+		ret = -ENODEV;
+	}
+	spin_unlock_irq(&epfile->ffs->eps_lock);
+
+	return ret;
+}
+
+static const struct file_operations ffs_epfile_operations = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+
+	.open =		ffs_epfile_open,
+	.write =	ffs_epfile_write,
+	.read =		ffs_epfile_read,
+	.release =	ffs_epfile_release,
+	.unlocked_ioctl =	ffs_epfile_ioctl,
+};
+
+
+/* File system and super block operations ***********************************/
+
+/*
+ * Mounting the file system creates a controller file, used first for
+ * function configuration then later for event monitoring.
+ */
+
+static struct inode *__must_check
+ffs_sb_make_inode(struct super_block *sb, void *data,
+		  const struct file_operations *fops,
+		  const struct inode_operations *iops,
+		  struct ffs_file_perms *perms)
+{
+	struct inode *inode;
+
+	ENTER();
+
+	inode = new_inode(sb);
+
+	if (likely(inode)) {
+		struct timespec current_time = CURRENT_TIME;
+
+		inode->i_ino	 = get_next_ino();
+		inode->i_mode    = perms->mode;
+		inode->i_uid     = perms->uid;
+		inode->i_gid     = perms->gid;
+		inode->i_atime   = current_time;
+		inode->i_mtime   = current_time;
+		inode->i_ctime   = current_time;
+		inode->i_private = data;
+		if (fops)
+			inode->i_fop = fops;
+		if (iops)
+			inode->i_op  = iops;
+	}
+
+	return inode;
+}
+
+/* Create "regular" file */
+static struct inode *ffs_sb_create_file(struct super_block *sb,
+					const char *name, void *data,
+					const struct file_operations *fops,
+					struct dentry **dentry_p)
+{
+	struct ffs_data	*ffs = sb->s_fs_info;
+	struct dentry	*dentry;
+	struct inode	*inode;
+
+	ENTER();
+
+	dentry = d_alloc_name(sb->s_root, name);
+	if (unlikely(!dentry))
+		return NULL;
+
+	inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
+	if (unlikely(!inode)) {
+		dput(dentry);
+		return NULL;
+	}
+
+	d_add(dentry, inode);
+	if (dentry_p)
+		*dentry_p = dentry;
+
+	return inode;
+}
+
+/* Super block */
+static const struct super_operations ffs_sb_operations = {
+	.statfs =	simple_statfs,
+	.drop_inode =	generic_delete_inode,
+};
+
+struct ffs_sb_fill_data {
+	struct ffs_file_perms perms;
+	umode_t root_mode;
+	const char *dev_name;
+	union {
+		/* set by ffs_fs_mount(), read by ffs_sb_fill() */
+		void *private_data;
+		/* set by ffs_sb_fill(), read by ffs_fs_mount */
+		struct ffs_data *ffs_data;
+	};
+};
+
+static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
+{
+	struct ffs_sb_fill_data *data = _data;
+	struct inode	*inode;
+	struct ffs_data	*ffs;
+
+	ENTER();
+
+	/* Initialise data */
+	ffs = ffs_data_new();
+	if (unlikely(!ffs))
+		goto Enomem;
+
+	ffs->sb              = sb;
+	ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL);
+	if (unlikely(!ffs->dev_name))
+		goto Enomem;
+	ffs->file_perms      = data->perms;
+	ffs->private_data    = data->private_data;
+
+	/* used by the caller of this function */
+	data->ffs_data       = ffs;
+
+	sb->s_fs_info        = ffs;
+	sb->s_blocksize      = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic          = FUNCTIONFS_MAGIC;
+	sb->s_op             = &ffs_sb_operations;
+	sb->s_time_gran      = 1;
+
+	/* Root inode */
+	data->perms.mode = data->root_mode;
+	inode = ffs_sb_make_inode(sb, NULL,
+				  &simple_dir_operations,
+				  &simple_dir_inode_operations,
+				  &data->perms);
+	sb->s_root = d_make_root(inode);
+	if (unlikely(!sb->s_root))
+		goto Enomem;
+
+	/* EP0 file */
+	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
+					 &ffs_ep0_operations, NULL)))
+		goto Enomem;
+
+	return 0;
+
+Enomem:
+	return -ENOMEM;
+}
+
+static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
+{
+	ENTER();
+
+	if (!opts || !*opts)
+		return 0;
+
+	for (;;) {
+		char *end, *eq, *comma;
+		unsigned long value;
+
+		/* Option limit */
+		comma = strchr(opts, ',');
+		if (comma)
+			*comma = 0;
+
+		/* Value limit */
+		eq = strchr(opts, '=');
+		if (unlikely(!eq)) {
+			pr_err("'=' missing in %s\n", opts);
+			return -EINVAL;
+		}
+		*eq = 0;
+
+		/* Parse value */
+		value = simple_strtoul(eq + 1, &end, 0);
+		if (unlikely(*end != ',' && *end != 0)) {
+			pr_err("%s: invalid value: %s\n", opts, eq + 1);
+			return -EINVAL;
+		}
+
+		/* Interpret option */
+		switch (eq - opts) {
+		case 5:
+			if (!memcmp(opts, "rmode", 5))
+				data->root_mode  = (value & 0555) | S_IFDIR;
+			else if (!memcmp(opts, "fmode", 5))
+				data->perms.mode = (value & 0666) | S_IFREG;
+			else
+				goto invalid;
+			break;
+
+		case 4:
+			if (!memcmp(opts, "mode", 4)) {
+				data->root_mode  = (value & 0555) | S_IFDIR;
+				data->perms.mode = (value & 0666) | S_IFREG;
+			} else {
+				goto invalid;
+			}
+			break;
+
+		case 3:
+			if (!memcmp(opts, "uid", 3))
+				data->perms.uid = value;
+			else if (!memcmp(opts, "gid", 3))
+				data->perms.gid = value;
+			else
+				goto invalid;
+			break;
+
+		default:
+invalid:
+			pr_err("%s: invalid option\n", opts);
+			return -EINVAL;
+		}
+
+		/* Next iteration */
+		if (!comma)
+			break;
+		opts = comma + 1;
+	}
+
+	return 0;
+}
+
+/* "mount -t functionfs dev_name /dev/function" ends up here */
+
+static struct dentry *
+ffs_fs_mount(struct file_system_type *t, int flags,
+	      const char *dev_name, void *opts)
+{
+	struct ffs_sb_fill_data data = {
+		.perms = {
+			.mode = S_IFREG | 0600,
+			.uid = 0,
+			.gid = 0
+		},
+		.root_mode = S_IFDIR | 0500,
+	};
+	struct dentry *rv;
+	int ret;
+	void *ffs_dev;
+
+	ENTER();
+
+	ret = ffs_fs_parse_opts(&data, opts);
+	if (unlikely(ret < 0))
+		return ERR_PTR(ret);
+
+	ffs_dev = functionfs_acquire_dev_callback(dev_name);
+	if (IS_ERR(ffs_dev))
+		return ffs_dev;
+
+	data.dev_name = dev_name;
+	data.private_data = ffs_dev;
+	rv = mount_nodev(t, flags, &data, ffs_sb_fill);
+
+	/* data.ffs_data is set by ffs_sb_fill */
+	if (IS_ERR(rv))
+		functionfs_release_dev_callback(data.ffs_data);
+
+	return rv;
+}
+
+static void
+ffs_fs_kill_sb(struct super_block *sb)
+{
+	ENTER();
+
+	kill_litter_super(sb);
+	if (sb->s_fs_info) {
+		functionfs_release_dev_callback(sb->s_fs_info);
+		ffs_data_put(sb->s_fs_info);
+	}
+}
+
+static struct file_system_type ffs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "functionfs",
+	.mount		= ffs_fs_mount,
+	.kill_sb	= ffs_fs_kill_sb,
+};
+
+
+/* Driver's main init/cleanup functions *************************************/
+
+static int functionfs_init(void)
+{
+	int ret;
+
+	ENTER();
+
+	ret = register_filesystem(&ffs_fs_type);
+	if (likely(!ret))
+		pr_info("file system registered\n");
+	else
+		pr_err("failed registering file system (%d)\n", ret);
+
+	return ret;
+}
+
+static void functionfs_cleanup(void)
+{
+	ENTER();
+
+	pr_info("unloading\n");
+	unregister_filesystem(&ffs_fs_type);
+}
+
+
+/* ffs_data and ffs_function construction and destruction code **************/
+
+static void ffs_data_clear(struct ffs_data *ffs);
+static void ffs_data_reset(struct ffs_data *ffs);
+
+static void ffs_data_get(struct ffs_data *ffs)
+{
+	ENTER();
+
+	atomic_inc(&ffs->ref);
+}
+
+static void ffs_data_opened(struct ffs_data *ffs)
+{
+	ENTER();
+
+	atomic_inc(&ffs->ref);
+	atomic_inc(&ffs->opened);
+}
+
+static void ffs_data_put(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (unlikely(atomic_dec_and_test(&ffs->ref))) {
+		pr_info("%s(): freeing\n", __func__);
+		ffs_data_clear(ffs);
+		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
+		       waitqueue_active(&ffs->ep0req_completion.wait));
+		kfree(ffs->dev_name);
+		kfree(ffs);
+	}
+}
+
+static void ffs_data_closed(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (atomic_dec_and_test(&ffs->opened)) {
+		ffs->state = FFS_CLOSING;
+		ffs_data_reset(ffs);
+	}
+
+	ffs_data_put(ffs);
+}
+
+static struct ffs_data *ffs_data_new(void)
+{
+	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
+	if (unlikely(!ffs))
+		return 0;
+
+	ENTER();
+
+	atomic_set(&ffs->ref, 1);
+	atomic_set(&ffs->opened, 0);
+	ffs->state = FFS_READ_DESCRIPTORS;
+	mutex_init(&ffs->mutex);
+	spin_lock_init(&ffs->eps_lock);
+	init_waitqueue_head(&ffs->ev.waitq);
+	init_completion(&ffs->ep0req_completion);
+
+	/* XXX REVISIT need to update it in some places, or do we? */
+	ffs->ev.can_stall = 1;
+
+	return ffs;
+}
+
+static void ffs_data_clear(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
+		functionfs_closed_callback(ffs);
+
+	BUG_ON(ffs->gadget);
+
+	if (ffs->epfiles)
+		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+
+	kfree(ffs->raw_descs);
+	kfree(ffs->raw_strings);
+	kfree(ffs->stringtabs);
+}
+
+static void ffs_data_reset(struct ffs_data *ffs)
+{
+	ENTER();
+
+	ffs_data_clear(ffs);
+
+	ffs->epfiles = NULL;
+	ffs->raw_descs = NULL;
+	ffs->raw_strings = NULL;
+	ffs->stringtabs = NULL;
+
+	ffs->raw_descs_length = 0;
+	ffs->raw_fs_descs_length = 0;
+	ffs->fs_descs_count = 0;
+	ffs->hs_descs_count = 0;
+
+	ffs->strings_count = 0;
+	ffs->interfaces_count = 0;
+	ffs->eps_count = 0;
+
+	ffs->ev.count = 0;
+
+	ffs->state = FFS_READ_DESCRIPTORS;
+	ffs->setup_state = FFS_NO_SETUP;
+	ffs->flags = 0;
+}
+
+
+static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
+{
+	struct usb_gadget_strings **lang;
+	int first_id;
+
+	ENTER();
+
+	if (WARN_ON(ffs->state != FFS_ACTIVE
+		 || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
+		return -EBADFD;
+
+	first_id = usb_string_ids_n(cdev, ffs->strings_count);
+	if (unlikely(first_id < 0))
+		return first_id;
+
+	ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+	if (unlikely(!ffs->ep0req))
+		return -ENOMEM;
+	ffs->ep0req->complete = ffs_ep0_complete;
+	ffs->ep0req->context = ffs;
+
+	lang = ffs->stringtabs;
+	for (lang = ffs->stringtabs; *lang; ++lang) {
+		struct usb_string *str = (*lang)->strings;
+		int id = first_id;
+		for (; str->s; ++id, ++str)
+			str->id = id;
+	}
+
+	ffs->gadget = cdev->gadget;
+	ffs_data_get(ffs);
+	return 0;
+}
+
+static void functionfs_unbind(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (!WARN_ON(!ffs->gadget)) {
+		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
+		ffs->ep0req = NULL;
+		ffs->gadget = NULL;
+		ffs_data_put(ffs);
+		clear_bit(FFS_FL_BOUND, &ffs->flags);
+	}
+}
+
+static int ffs_epfiles_create(struct ffs_data *ffs)
+{
+	struct ffs_epfile *epfile, *epfiles;
+	unsigned i, count;
+
+	ENTER();
+
+	count = ffs->eps_count;
+	epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
+	if (!epfiles)
+		return -ENOMEM;
+
+	epfile = epfiles;
+	for (i = 1; i <= count; ++i, ++epfile) {
+		epfile->ffs = ffs;
+		mutex_init(&epfile->mutex);
+		init_waitqueue_head(&epfile->wait);
+		sprintf(epfiles->name, "ep%u",  i);
+		if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile,
+						 &ffs_epfile_operations,
+						 &epfile->dentry))) {
+			ffs_epfiles_destroy(epfiles, i - 1);
+			return -ENOMEM;
+		}
+	}
+
+	ffs->epfiles = epfiles;
+	return 0;
+}
+
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+{
+	struct ffs_epfile *epfile = epfiles;
+
+	ENTER();
+
+	for (; count; --count, ++epfile) {
+		BUG_ON(mutex_is_locked(&epfile->mutex) ||
+		       waitqueue_active(&epfile->wait));
+		if (epfile->dentry) {
+			d_delete(epfile->dentry);
+			dput(epfile->dentry);
+			epfile->dentry = NULL;
+		}
+	}
+
+	kfree(epfiles);
+}
+
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+				  struct usb_configuration *c,
+				  struct ffs_data *ffs)
+{
+	struct ffs_function *func;
+	int ret;
+
+	ENTER();
+
+	func = kzalloc(sizeof *func, GFP_KERNEL);
+	if (unlikely(!func))
+		return -ENOMEM;
+
+	func->function.name    = "Function FS Gadget";
+	func->function.strings = ffs->stringtabs;
+
+	func->function.bind    = ffs_func_bind;
+	func->function.unbind  = ffs_func_unbind;
+	func->function.set_alt = ffs_func_set_alt;
+	func->function.disable = ffs_func_disable;
+	func->function.setup   = ffs_func_setup;
+	func->function.suspend = ffs_func_suspend;
+	func->function.resume  = ffs_func_resume;
+
+	func->conf   = c;
+	func->gadget = cdev->gadget;
+	func->ffs = ffs;
+	ffs_data_get(ffs);
+
+	ret = usb_add_function(c, &func->function);
+	if (unlikely(ret))
+		ffs_func_free(func);
+
+	return ret;
+}
+
+static void ffs_func_free(struct ffs_function *func)
+{
+	struct ffs_ep *ep         = func->eps;
+	unsigned count            = func->ffs->eps_count;
+	unsigned long flags;
+
+	ENTER();
+
+	/* cleanup after autoconfig */
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		if (ep->ep && ep->req)
+			usb_ep_free_request(ep->ep, ep->req);
+		ep->req = NULL;
+		++ep;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+	ffs_data_put(func->ffs);
+
+	kfree(func->eps);
+	/*
+	 * eps and interfaces_nums are allocated in the same chunk so
+	 * only one free is required.  Descriptors are also allocated
+	 * in the same chunk.
+	 */
+
+	kfree(func);
+}
+
+static void ffs_func_eps_disable(struct ffs_function *func)
+{
+	struct ffs_ep *ep         = func->eps;
+	struct ffs_epfile *epfile = func->ffs->epfiles;
+	unsigned count            = func->ffs->eps_count;
+	unsigned long flags;
+
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		/* pending requests get nuked */
+		if (likely(ep->ep))
+			usb_ep_disable(ep->ep);
+		epfile->ep = NULL;
+
+		++ep;
+		++epfile;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+}
+
+static int ffs_func_eps_enable(struct ffs_function *func)
+{
+	struct ffs_data *ffs      = func->ffs;
+	struct ffs_ep *ep         = func->eps;
+	struct ffs_epfile *epfile = ffs->epfiles;
+	unsigned count            = ffs->eps_count;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		struct usb_endpoint_descriptor *ds;
+		ds = ep->descs[ep->descs[1] ? 1 : 0];
+
+		ep->ep->driver_data = ep;
+		ep->ep->desc = ds;
+		ret = usb_ep_enable(ep->ep);
+		if (likely(!ret)) {
+			epfile->ep = ep;
+			epfile->in = usb_endpoint_dir_in(ds);
+			epfile->isoc = usb_endpoint_xfer_isoc(ds);
+		} else {
+			break;
+		}
+
+		wake_up(&epfile->wait);
+
+		++ep;
+		++epfile;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+	return ret;
+}
+
+
+/* Parsing and building descriptors and strings *****************************/
+
+/*
+ * This validates if data pointed by data is a valid USB descriptor as
+ * well as record how many interfaces, endpoints and strings are
+ * required by given configuration.  Returns address after the
+ * descriptor or NULL if data is invalid.
+ */
+
+enum ffs_entity_type {
+	FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
+};
+
+typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
+				   u8 *valuep,
+				   struct usb_descriptor_header *desc,
+				   void *priv);
+
+static int __must_check ffs_do_desc(char *data, unsigned len,
+				    ffs_entity_callback entity, void *priv)
+{
+	struct usb_descriptor_header *_ds = (void *)data;
+	u8 length;
+	int ret;
+
+	ENTER();
+
+	/* At least two bytes are required: length and type */
+	if (len < 2) {
+		pr_vdebug("descriptor too short\n");
+		return -EINVAL;
+	}
+
+	/* If we have at least as many bytes as the descriptor takes? */
+	length = _ds->bLength;
+	if (len < length) {
+		pr_vdebug("descriptor longer then available data\n");
+		return -EINVAL;
+	}
+
+#define __entity_check_INTERFACE(val)  1
+#define __entity_check_STRING(val)     (val)
+#define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
+#define __entity(type, val) do {					\
+		pr_vdebug("entity " #type "(%02x)\n", (val));		\
+		if (unlikely(!__entity_check_ ##type(val))) {		\
+			pr_vdebug("invalid entity's value\n");		\
+			return -EINVAL;					\
+		}							\
+		ret = entity(FFS_ ##type, &val, _ds, priv);		\
+		if (unlikely(ret < 0)) {				\
+			pr_debug("entity " #type "(%02x); ret = %d\n",	\
+				 (val), ret);				\
+			return ret;					\
+		}							\
+	} while (0)
+
+	/* Parse descriptor depending on type. */
+	switch (_ds->bDescriptorType) {
+	case USB_DT_DEVICE:
+	case USB_DT_CONFIG:
+	case USB_DT_STRING:
+	case USB_DT_DEVICE_QUALIFIER:
+		/* function can't have any of those */
+		pr_vdebug("descriptor reserved for gadget: %d\n",
+		      _ds->bDescriptorType);
+		return -EINVAL;
+
+	case USB_DT_INTERFACE: {
+		struct usb_interface_descriptor *ds = (void *)_ds;
+		pr_vdebug("interface descriptor\n");
+		if (length != sizeof *ds)
+			goto inv_length;
+
+		__entity(INTERFACE, ds->bInterfaceNumber);
+		if (ds->iInterface)
+			__entity(STRING, ds->iInterface);
+	}
+		break;
+
+	case USB_DT_ENDPOINT: {
+		struct usb_endpoint_descriptor *ds = (void *)_ds;
+		pr_vdebug("endpoint descriptor\n");
+		if (length != USB_DT_ENDPOINT_SIZE &&
+		    length != USB_DT_ENDPOINT_AUDIO_SIZE)
+			goto inv_length;
+		__entity(ENDPOINT, ds->bEndpointAddress);
+	}
+		break;
+
+	case HID_DT_HID:
+		pr_vdebug("hid descriptor\n");
+		if (length != sizeof(struct hid_descriptor))
+			goto inv_length;
+		break;
+
+	case USB_DT_OTG:
+		if (length != sizeof(struct usb_otg_descriptor))
+			goto inv_length;
+		break;
+
+	case USB_DT_INTERFACE_ASSOCIATION: {
+		struct usb_interface_assoc_descriptor *ds = (void *)_ds;
+		pr_vdebug("interface association descriptor\n");
+		if (length != sizeof *ds)
+			goto inv_length;
+		if (ds->iFunction)
+			__entity(STRING, ds->iFunction);
+	}
+		break;
+
+	case USB_DT_OTHER_SPEED_CONFIG:
+	case USB_DT_INTERFACE_POWER:
+	case USB_DT_DEBUG:
+	case USB_DT_SECURITY:
+	case USB_DT_CS_RADIO_CONTROL:
+		/* TODO */
+		pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
+		return -EINVAL;
+
+	default:
+		/* We should never be here */
+		pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
+		return -EINVAL;
+
+inv_length:
+		pr_vdebug("invalid length: %d (descriptor %d)\n",
+			  _ds->bLength, _ds->bDescriptorType);
+		return -EINVAL;
+	}
+
+#undef __entity
+#undef __entity_check_DESCRIPTOR
+#undef __entity_check_INTERFACE
+#undef __entity_check_STRING
+#undef __entity_check_ENDPOINT
+
+	return length;
+}
+
+static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
+				     ffs_entity_callback entity, void *priv)
+{
+	const unsigned _len = len;
+	unsigned long num = 0;
+
+	ENTER();
+
+	for (;;) {
+		int ret;
+
+		if (num == count)
+			data = NULL;
+
+		/* Record "descriptor" entity */
+		ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
+		if (unlikely(ret < 0)) {
+			pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
+				 num, ret);
+			return ret;
+		}
+
+		if (!data)
+			return _len - len;
+
+		ret = ffs_do_desc(data, len, entity, priv);
+		if (unlikely(ret < 0)) {
+			pr_debug("%s returns %d\n", __func__, ret);
+			return ret;
+		}
+
+		len -= ret;
+		data += ret;
+		++num;
+	}
+}
+
+static int __ffs_data_do_entity(enum ffs_entity_type type,
+				u8 *valuep, struct usb_descriptor_header *desc,
+				void *priv)
+{
+	struct ffs_data *ffs = priv;
+
+	ENTER();
+
+	switch (type) {
+	case FFS_DESCRIPTOR:
+		break;
+
+	case FFS_INTERFACE:
+		/*
+		 * Interfaces are indexed from zero so if we
+		 * encountered interface "n" then there are at least
+		 * "n+1" interfaces.
+		 */
+		if (*valuep >= ffs->interfaces_count)
+			ffs->interfaces_count = *valuep + 1;
+		break;
+
+	case FFS_STRING:
+		/*
+		 * Strings are indexed from 1 (0 is magic ;) reserved
+		 * for languages list or some such)
+		 */
+		if (*valuep > ffs->strings_count)
+			ffs->strings_count = *valuep;
+		break;
+
+	case FFS_ENDPOINT:
+		/* Endpoints are indexed from 1 as well. */
+		if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
+			ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
+		break;
+	}
+
+	return 0;
+}
+
+static int __ffs_data_got_descs(struct ffs_data *ffs,
+				char *const _data, size_t len)
+{
+	unsigned fs_count, hs_count;
+	int fs_len, ret = -EINVAL;
+	char *data = _data;
+
+	ENTER();
+
+	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
+		     get_unaligned_le32(data + 4) != len))
+		goto error;
+	fs_count = get_unaligned_le32(data +  8);
+	hs_count = get_unaligned_le32(data + 12);
+
+	if (!fs_count && !hs_count)
+		goto einval;
+
+	data += 16;
+	len  -= 16;
+
+	if (likely(fs_count)) {
+		fs_len = ffs_do_descs(fs_count, data, len,
+				      __ffs_data_do_entity, ffs);
+		if (unlikely(fs_len < 0)) {
+			ret = fs_len;
+			goto error;
+		}
+
+		data += fs_len;
+		len  -= fs_len;
+	} else {
+		fs_len = 0;
+	}
+
+	if (likely(hs_count)) {
+		ret = ffs_do_descs(hs_count, data, len,
+				   __ffs_data_do_entity, ffs);
+		if (unlikely(ret < 0))
+			goto error;
+	} else {
+		ret = 0;
+	}
+
+	if (unlikely(len != ret))
+		goto einval;
+
+	ffs->raw_fs_descs_length = fs_len;
+	ffs->raw_descs_length    = fs_len + ret;
+	ffs->raw_descs           = _data;
+	ffs->fs_descs_count      = fs_count;
+	ffs->hs_descs_count      = hs_count;
+
+	return 0;
+
+einval:
+	ret = -EINVAL;
+error:
+	kfree(_data);
+	return ret;
+}
+
+static int __ffs_data_got_strings(struct ffs_data *ffs,
+				  char *const _data, size_t len)
+{
+	u32 str_count, needed_count, lang_count;
+	struct usb_gadget_strings **stringtabs, *t;
+	struct usb_string *strings, *s;
+	const char *data = _data;
+
+	ENTER();
+
+	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+		     get_unaligned_le32(data + 4) != len))
+		goto error;
+	str_count  = get_unaligned_le32(data + 8);
+	lang_count = get_unaligned_le32(data + 12);
+
+	/* if one is zero the other must be zero */
+	if (unlikely(!str_count != !lang_count))
+		goto error;
+
+	/* Do we have at least as many strings as descriptors need? */
+	needed_count = ffs->strings_count;
+	if (unlikely(str_count < needed_count))
+		goto error;
+
+	/*
+	 * If we don't need any strings just return and free all
+	 * memory.
+	 */
+	if (!needed_count) {
+		kfree(_data);
+		return 0;
+	}
+
+	/* Allocate everything in one chunk so there's less maintenance. */
+	{
+		struct {
+			struct usb_gadget_strings *stringtabs[lang_count + 1];
+			struct usb_gadget_strings stringtab[lang_count];
+			struct usb_string strings[lang_count*(needed_count+1)];
+		} *d;
+		unsigned i = 0;
+
+		d = kmalloc(sizeof *d, GFP_KERNEL);
+		if (unlikely(!d)) {
+			kfree(_data);
+			return -ENOMEM;
+		}
+
+		stringtabs = d->stringtabs;
+		t = d->stringtab;
+		i = lang_count;
+		do {
+			*stringtabs++ = t++;
+		} while (--i);
+		*stringtabs = NULL;
+
+		stringtabs = d->stringtabs;
+		t = d->stringtab;
+		s = d->strings;
+		strings = s;
+	}
+
+	/* For each language */
+	data += 16;
+	len -= 16;
+
+	do { /* lang_count > 0 so we can use do-while */
+		unsigned needed = needed_count;
+
+		if (unlikely(len < 3))
+			goto error_free;
+		t->language = get_unaligned_le16(data);
+		t->strings  = s;
+		++t;
+
+		data += 2;
+		len -= 2;
+
+		/* For each string */
+		do { /* str_count > 0 so we can use do-while */
+			size_t length = strnlen(data, len);
+
+			if (unlikely(length == len))
+				goto error_free;
+
+			/*
+			 * User may provide more strings then we need,
+			 * if that's the case we simply ignore the
+			 * rest
+			 */
+			if (likely(needed)) {
+				/*
+				 * s->id will be set while adding
+				 * function to configuration so for
+				 * now just leave garbage here.
+				 */
+				s->s = data;
+				--needed;
+				++s;
+			}
+
+			data += length + 1;
+			len -= length + 1;
+		} while (--str_count);
+
+		s->id = 0;   /* terminator */
+		s->s = NULL;
+		++s;
+
+	} while (--lang_count);
+
+	/* Some garbage left? */
+	if (unlikely(len))
+		goto error_free;
+
+	/* Done! */
+	ffs->stringtabs = stringtabs;
+	ffs->raw_strings = _data;
+
+	return 0;
+
+error_free:
+	kfree(stringtabs);
+error:
+	kfree(_data);
+	return -EINVAL;
+}
+
+
+/* Events handling and management *******************************************/
+
+static void __ffs_event_add(struct ffs_data *ffs,
+			    enum usb_functionfs_event_type type)
+{
+	enum usb_functionfs_event_type rem_type1, rem_type2 = type;
+	int neg = 0;
+
+	/*
+	 * Abort any unhandled setup
+	 *
+	 * We do not need to worry about some cmpxchg() changing value
+	 * of ffs->setup_state without holding the lock because when
+	 * state is FFS_SETUP_PENDING cmpxchg() in several places in
+	 * the source does nothing.
+	 */
+	if (ffs->setup_state == FFS_SETUP_PENDING)
+		ffs->setup_state = FFS_SETUP_CANCELED;
+
+	switch (type) {
+	case FUNCTIONFS_RESUME:
+		rem_type2 = FUNCTIONFS_SUSPEND;
+		/* FALL THROUGH */
+	case FUNCTIONFS_SUSPEND:
+	case FUNCTIONFS_SETUP:
+		rem_type1 = type;
+		/* Discard all similar events */
+		break;
+
+	case FUNCTIONFS_BIND:
+	case FUNCTIONFS_UNBIND:
+	case FUNCTIONFS_DISABLE:
+	case FUNCTIONFS_ENABLE:
+		/* Discard everything other then power management. */
+		rem_type1 = FUNCTIONFS_SUSPEND;
+		rem_type2 = FUNCTIONFS_RESUME;
+		neg = 1;
+		break;
+
+	default:
+		BUG();
+	}
+
+	{
+		u8 *ev  = ffs->ev.types, *out = ev;
+		unsigned n = ffs->ev.count;
+		for (; n; --n, ++ev)
+			if ((*ev == rem_type1 || *ev == rem_type2) == neg)
+				*out++ = *ev;
+			else
+				pr_vdebug("purging event %d\n", *ev);
+		ffs->ev.count = out - ffs->ev.types;
+	}
+
+	pr_vdebug("adding event %d\n", type);
+	ffs->ev.types[ffs->ev.count++] = type;
+	wake_up_locked(&ffs->ev.waitq);
+}
+
+static void ffs_event_add(struct ffs_data *ffs,
+			  enum usb_functionfs_event_type type)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+	__ffs_event_add(ffs, type);
+	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+}
+
+
+/* Bind/unbind USB function hooks *******************************************/
+
+static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
+				    struct usb_descriptor_header *desc,
+				    void *priv)
+{
+	struct usb_endpoint_descriptor *ds = (void *)desc;
+	struct ffs_function *func = priv;
+	struct ffs_ep *ffs_ep;
+
+	/*
+	 * If hs_descriptors is not NULL then we are reading hs
+	 * descriptors now
+	 */
+	const int isHS = func->function.hs_descriptors != NULL;
+	unsigned idx;
+
+	if (type != FFS_DESCRIPTOR)
+		return 0;
+
+	if (isHS)
+		func->function.hs_descriptors[(long)valuep] = desc;
+	else
+		func->function.descriptors[(long)valuep]    = desc;
+
+	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+		return 0;
+
+	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
+	ffs_ep = func->eps + idx;
+
+	if (unlikely(ffs_ep->descs[isHS])) {
+		pr_vdebug("two %sspeed descriptors for EP %d\n",
+			  isHS ? "high" : "full",
+			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+		return -EINVAL;
+	}
+	ffs_ep->descs[isHS] = ds;
+
+	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
+	if (ffs_ep->ep) {
+		ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
+		if (!ds->wMaxPacketSize)
+			ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
+	} else {
+		struct usb_request *req;
+		struct usb_ep *ep;
+
+		pr_vdebug("autoconfig\n");
+		ep = usb_ep_autoconfig(func->gadget, ds);
+		if (unlikely(!ep))
+			return -ENOTSUPP;
+		ep->driver_data = func->eps + idx;
+
+		req = usb_ep_alloc_request(ep, GFP_KERNEL);
+		if (unlikely(!req))
+			return -ENOMEM;
+
+		ffs_ep->ep  = ep;
+		ffs_ep->req = req;
+		func->eps_revmap[ds->bEndpointAddress &
+				 USB_ENDPOINT_NUMBER_MASK] = idx + 1;
+	}
+	ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
+
+	return 0;
+}
+
+static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
+				   struct usb_descriptor_header *desc,
+				   void *priv)
+{
+	struct ffs_function *func = priv;
+	unsigned idx;
+	u8 newValue;
+
+	switch (type) {
+	default:
+	case FFS_DESCRIPTOR:
+		/* Handled in previous pass by __ffs_func_bind_do_descs() */
+		return 0;
+
+	case FFS_INTERFACE:
+		idx = *valuep;
+		if (func->interfaces_nums[idx] < 0) {
+			int id = usb_interface_id(func->conf, &func->function);
+			if (unlikely(id < 0))
+				return id;
+			func->interfaces_nums[idx] = id;
+		}
+		newValue = func->interfaces_nums[idx];
+		break;
+
+	case FFS_STRING:
+		/* String' IDs are allocated when fsf_data is bound to cdev */
+		newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
+		break;
+
+	case FFS_ENDPOINT:
+		/*
+		 * USB_DT_ENDPOINT are handled in
+		 * __ffs_func_bind_do_descs().
+		 */
+		if (desc->bDescriptorType == USB_DT_ENDPOINT)
+			return 0;
+
+		idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
+		if (unlikely(!func->eps[idx].ep))
+			return -EINVAL;
+
+		{
+			struct usb_endpoint_descriptor **descs;
+			descs = func->eps[idx].descs;
+			newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
+		}
+		break;
+	}
+
+	pr_vdebug("%02x -> %02x\n", *valuep, newValue);
+	*valuep = newValue;
+	return 0;
+}
+
+static int ffs_func_bind(struct usb_configuration *c,
+			 struct usb_function *f)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+
+	const int full = !!func->ffs->fs_descs_count;
+	const int high = gadget_is_dualspeed(func->gadget) &&
+		func->ffs->hs_descs_count;
+
+	int ret;
+
+	/* Make it a single chunk, less management later on */
+	struct {
+		struct ffs_ep eps[ffs->eps_count];
+		struct usb_descriptor_header
+			*fs_descs[full ? ffs->fs_descs_count + 1 : 0];
+		struct usb_descriptor_header
+			*hs_descs[high ? ffs->hs_descs_count + 1 : 0];
+		short inums[ffs->interfaces_count];
+		char raw_descs[high ? ffs->raw_descs_length
+				    : ffs->raw_fs_descs_length];
+	} *data;
+
+	ENTER();
+
+	/* Only high speed but not supported by gadget? */
+	if (unlikely(!(full | high)))
+		return -ENOTSUPP;
+
+	/* Allocate */
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (unlikely(!data))
+		return -ENOMEM;
+
+	/* Zero */
+	memset(data->eps, 0, sizeof data->eps);
+	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
+	memset(data->inums, 0xff, sizeof data->inums);
+	for (ret = ffs->eps_count; ret; --ret)
+		data->eps[ret].num = -1;
+
+	/* Save pointers */
+	func->eps             = data->eps;
+	func->interfaces_nums = data->inums;
+
+	/*
+	 * Go through all the endpoint descriptors and allocate
+	 * endpoints first, so that later we can rewrite the endpoint
+	 * numbers without worrying that it may be described later on.
+	 */
+	if (likely(full)) {
+		func->function.descriptors = data->fs_descs;
+		ret = ffs_do_descs(ffs->fs_descs_count,
+				   data->raw_descs,
+				   sizeof data->raw_descs,
+				   __ffs_func_bind_do_descs, func);
+		if (unlikely(ret < 0))
+			goto error;
+	} else {
+		ret = 0;
+	}
+
+	if (likely(high)) {
+		func->function.hs_descriptors = data->hs_descs;
+		ret = ffs_do_descs(ffs->hs_descs_count,
+				   data->raw_descs + ret,
+				   (sizeof data->raw_descs) - ret,
+				   __ffs_func_bind_do_descs, func);
+	}
+
+	/*
+	 * Now handle interface numbers allocation and interface and
+	 * endpoint numbers rewriting.  We can do that in one go
+	 * now.
+	 */
+	ret = ffs_do_descs(ffs->fs_descs_count +
+			   (high ? ffs->hs_descs_count : 0),
+			   data->raw_descs, sizeof data->raw_descs,
+			   __ffs_func_bind_do_nums, func);
+	if (unlikely(ret < 0))
+		goto error;
+
+	/* And we're done */
+	ffs_event_add(ffs, FUNCTIONFS_BIND);
+	return 0;
+
+error:
+	/* XXX Do we need to release all claimed endpoints here? */
+	return ret;
+}
+
+
+/* Other USB function hooks *************************************************/
+
+static void ffs_func_unbind(struct usb_configuration *c,
+			    struct usb_function *f)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+
+	ENTER();
+
+	if (ffs->func == func) {
+		ffs_func_eps_disable(func);
+		ffs->func = NULL;
+	}
+
+	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
+
+	ffs_func_free(func);
+}
+
+static int ffs_func_set_alt(struct usb_function *f,
+			    unsigned interface, unsigned alt)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+	int ret = 0, intf;
+
+	if (alt != (unsigned)-1) {
+		intf = ffs_func_revmap_intf(func, interface);
+		if (unlikely(intf < 0))
+			return intf;
+	}
+
+	if (ffs->func)
+		ffs_func_eps_disable(ffs->func);
+
+	if (ffs->state != FFS_ACTIVE)
+		return -ENODEV;
+
+	if (alt == (unsigned)-1) {
+		ffs->func = NULL;
+		ffs_event_add(ffs, FUNCTIONFS_DISABLE);
+		return 0;
+	}
+
+	ffs->func = func;
+	ret = ffs_func_eps_enable(func);
+	if (likely(ret >= 0))
+		ffs_event_add(ffs, FUNCTIONFS_ENABLE);
+	return ret;
+}
+
+static void ffs_func_disable(struct usb_function *f)
+{
+	ffs_func_set_alt(f, 0, (unsigned)-1);
+}
+
+static int ffs_func_setup(struct usb_function *f,
+			  const struct usb_ctrlrequest *creq)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+	unsigned long flags;
+	int ret;
+
+	ENTER();
+
+	pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
+	pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest);
+	pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue));
+	pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex));
+	pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength));
+
+	/*
+	 * Most requests directed to interface go through here
+	 * (notable exceptions are set/get interface) so we need to
+	 * handle them.  All other either handled by composite or
+	 * passed to usb_configuration->setup() (if one is set).  No
+	 * matter, we will handle requests directed to endpoint here
+	 * as well (as it's straightforward) but what to do with any
+	 * other request?
+	 */
+	if (ffs->state != FFS_ACTIVE)
+		return -ENODEV;
+
+	switch (creq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
+		if (unlikely(ret < 0))
+			return ret;
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
+		if (unlikely(ret < 0))
+			return ret;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+	ffs->ev.setup = *creq;
+	ffs->ev.setup.wIndex = cpu_to_le16(ret);
+	__ffs_event_add(ffs, FUNCTIONFS_SETUP);
+	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+
+	return 0;
+}
+
+static void ffs_func_suspend(struct usb_function *f)
+{
+	ENTER();
+	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
+}
+
+static void ffs_func_resume(struct usb_function *f)
+{
+	ENTER();
+	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
+}
+
+
+/* Endpoint and interface numbers reverse mapping ***************************/
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
+{
+	num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
+	return num ? num : -EDOM;
+}
+
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
+{
+	short *nums = func->interfaces_nums;
+	unsigned count = func->ffs->interfaces_count;
+
+	for (; count; --count, ++nums) {
+		if (*nums >= 0 && *nums == intf)
+			return nums - func->interfaces_nums;
+	}
+
+	return -EDOM;
+}
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+{
+	return nonblock
+		? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
+		: mutex_lock_interruptible(mutex);
+}
+
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+{
+	char *data;
+
+	if (unlikely(!len))
+		return NULL;
+
+	data = kmalloc(len, GFP_KERNEL);
+	if (unlikely(!data))
+		return ERR_PTR(-ENOMEM);
+
+	if (unlikely(__copy_from_user(data, buf, len))) {
+		kfree(data);
+		return ERR_PTR(-EFAULT);
+	}
+
+	pr_vdebug("Buffer from user space:\n");
+	ffs_dump_mem("", data, len);
+
+	return data;
+}
diff --git a/drivers/staging/ccg/f_mass_storage.c b/drivers/staging/ccg/f_mass_storage.c
new file mode 100644
index 0000000..4f1142e
--- /dev/null
+++ b/drivers/staging/ccg/f_mass_storage.c
@@ -0,0 +1,3135 @@
+/*
+ * f_mass_storage.c -- Mass Storage USB Composite Function
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz <mina86@mina86.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The Mass Storage Function acts as a USB Mass Storage device,
+ * appearing to the host as a disk drive or as a CD-ROM drive.  In
+ * addition to providing an example of a genuinely useful composite
+ * function for a USB device, it also illustrates a technique of
+ * double-buffering for increased throughput.
+ *
+ * For more information about MSF and in particular its module
+ * parameters and sysfs interface read the
+ * <Documentation/usb/mass-storage.txt> file.
+ */
+
+/*
+ * MSF is configured by specifying a fsg_config structure.  It has the
+ * following fields:
+ *
+ *	nluns		Number of LUNs function have (anywhere from 1
+ *				to FSG_MAX_LUNS which is 8).
+ *	luns		An array of LUN configuration values.  This
+ *				should be filled for each LUN that
+ *				function will include (ie. for "nluns"
+ *				LUNs).  Each element of the array has
+ *				the following fields:
+ *	->filename	The path to the backing file for the LUN.
+ *				Required if LUN is not marked as
+ *				removable.
+ *	->ro		Flag specifying access to the LUN shall be
+ *				read-only.  This is implied if CD-ROM
+ *				emulation is enabled as well as when
+ *				it was impossible to open "filename"
+ *				in R/W mode.
+ *	->removable	Flag specifying that LUN shall be indicated as
+ *				being removable.
+ *	->cdrom		Flag specifying that LUN shall be reported as
+ *				being a CD-ROM.
+ *	->nofua		Flag specifying that FUA flag in SCSI WRITE(10,12)
+ *				commands for this LUN shall be ignored.
+ *
+ *	vendor_name
+ *	product_name
+ *	release		Information used as a reply to INQUIRY
+ *				request.  To use default set to NULL,
+ *				NULL, 0xffff respectively.  The first
+ *				field should be 8 and the second 16
+ *				characters or less.
+ *
+ *	can_stall	Set to permit function to halt bulk endpoints.
+ *				Disabled on some USB devices known not
+ *				to work correctly.  You should set it
+ *				to true.
+ *
+ * If "removable" is not set for a LUN then a backing file must be
+ * specified.  If it is set, then NULL filename means the LUN's medium
+ * is not loaded (an empty string as "filename" in the fsg_config
+ * structure causes error).  The CD-ROM emulation includes a single
+ * data track and no audio tracks; hence there need be only one
+ * backing file per LUN.
+ *
+ * This function is heavily based on "File-backed Storage Gadget" by
+ * Alan Stern which in turn is heavily based on "Gadget Zero" by David
+ * Brownell.  The driver's SCSI command interface was based on the
+ * "Information technology - Small Computer System Interface - 2"
+ * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93,
+ * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
+ * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which
+ * was based on the "Universal Serial Bus Mass Storage Class UFI
+ * Command Specification" document, Revision 1.0, December 14, 1998,
+ * available at
+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
+ */
+
+/*
+ *				Driver Design
+ *
+ * The MSF is fairly straightforward.  There is a main kernel
+ * thread that handles most of the work.  Interrupt routines field
+ * callbacks from the controller driver: bulk- and interrupt-request
+ * completion notifications, endpoint-0 events, and disconnect events.
+ * Completion events are passed to the main thread by wakeup calls.  Many
+ * ep0 requests are handled at interrupt time, but SetInterface,
+ * SetConfiguration, and device reset requests are forwarded to the
+ * thread in the form of "exceptions" using SIGUSR1 signals (since they
+ * should interrupt any ongoing file I/O operations).
+ *
+ * The thread's main routine implements the standard command/data/status
+ * parts of a SCSI interaction.  It and its subroutines are full of tests
+ * for pending signals/exceptions -- all this polling is necessary since
+ * the kernel has no setjmp/longjmp equivalents.  (Maybe this is an
+ * indication that the driver really wants to be running in userspace.)
+ * An important point is that so long as the thread is alive it keeps an
+ * open reference to the backing file.  This will prevent unmounting
+ * the backing file's underlying filesystem and could cause problems
+ * during system shutdown, for example.  To prevent such problems, the
+ * thread catches INT, TERM, and KILL signals and converts them into
+ * an EXIT exception.
+ *
+ * In normal operation the main thread is started during the gadget's
+ * fsg_bind() callback and stopped during fsg_unbind().  But it can
+ * also exit when it receives a signal, and there's no point leaving
+ * the gadget running when the thread is dead.  As of this moment, MSF
+ * provides no way to deregister the gadget when thread dies -- maybe
+ * a callback functions is needed.
+ *
+ * To provide maximum throughput, the driver uses a circular pipeline of
+ * buffer heads (struct fsg_buffhd).  In principle the pipeline can be
+ * arbitrarily long; in practice the benefits don't justify having more
+ * than 2 stages (i.e., double buffering).  But it helps to think of the
+ * pipeline as being a long one.  Each buffer head contains a bulk-in and
+ * a bulk-out request pointer (since the buffer can be used for both
+ * output and input -- directions always are given from the host's
+ * point of view) as well as a pointer to the buffer and various state
+ * variables.
+ *
+ * Use of the pipeline follows a simple protocol.  There is a variable
+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
+ * At any time that buffer head may still be in use from an earlier
+ * request, so each buffer head has a state variable indicating whether
+ * it is EMPTY, FULL, or BUSY.  Typical use involves waiting for the
+ * buffer head to be EMPTY, filling the buffer either by file I/O or by
+ * USB I/O (during which the buffer head is BUSY), and marking the buffer
+ * head FULL when the I/O is complete.  Then the buffer will be emptied
+ * (again possibly by USB I/O, during which it is marked BUSY) and
+ * finally marked EMPTY again (possibly by a completion routine).
+ *
+ * A module parameter tells the driver to avoid stalling the bulk
+ * endpoints wherever the transport specification allows.  This is
+ * necessary for some UDCs like the SuperH, which cannot reliably clear a
+ * halt on a bulk endpoint.  However, under certain circumstances the
+ * Bulk-only specification requires a stall.  In such cases the driver
+ * will halt the endpoint and set a flag indicating that it should clear
+ * the halt in software during the next device reset.  Hopefully this
+ * will permit everything to work correctly.  Furthermore, although the
+ * specification allows the bulk-out endpoint to halt when the host sends
+ * too much data, implementing this would cause an unavoidable race.
+ * The driver will always use the "no-stall" approach for OUT transfers.
+ *
+ * One subtle point concerns sending status-stage responses for ep0
+ * requests.  Some of these requests, such as device reset, can involve
+ * interrupting an ongoing file I/O operation, which might take an
+ * arbitrarily long time.  During that delay the host might give up on
+ * the original ep0 request and issue a new one.  When that happens the
+ * driver should not notify the host about completion of the original
+ * request, as the host will no longer be waiting for it.  So the driver
+ * assigns to each ep0 request a unique tag, and it keeps track of the
+ * tag value of the request associated with a long-running exception
+ * (device-reset, interface-change, or configuration-change).  When the
+ * exception handler is finished, the status-stage response is submitted
+ * only if the current ep0 request tag is equal to the exception request
+ * tag.  Thus only the most recently received ep0 request will get a
+ * status-stage response.
+ *
+ * Warning: This driver source file is too long.  It ought to be split up
+ * into a header file plus about 3 separate .c files, to handle the details
+ * of the Gadget, USB Mass Storage, and SCSI protocols.
+ */
+
+
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
+
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/dcache.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kref.h>
+#include <linux/kthread.h>
+#include <linux/limits.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/freezer.h>
+#include <linux/utsname.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include "gadget_chips.h"
+
+
+/*------------------------------------------------------------------------*/
+
+#define FSG_DRIVER_DESC		"Mass Storage Function"
+#define FSG_DRIVER_VERSION	"2009/09/11"
+
+static const char fsg_string_interface[] = "Mass Storage";
+
+#define FSG_NO_DEVICE_STRINGS    1
+#define FSG_NO_OTG               1
+#define FSG_NO_INTR_EP           1
+
+#include "storage_common.c"
+
+
+/*-------------------------------------------------------------------------*/
+
+struct fsg_dev;
+struct fsg_common;
+
+/* FSF callback functions */
+struct fsg_operations {
+	/*
+	 * Callback function to call when thread exits.  If no
+	 * callback is set or it returns value lower then zero MSF
+	 * will force eject all LUNs it operates on (including those
+	 * marked as non-removable or with prevent_medium_removal flag
+	 * set).
+	 */
+	int (*thread_exits)(struct fsg_common *common);
+
+	/*
+	 * Called prior to ejection.  Negative return means error,
+	 * zero means to continue with ejection, positive means not to
+	 * eject.
+	 */
+	int (*pre_eject)(struct fsg_common *common,
+			 struct fsg_lun *lun, int num);
+	/*
+	 * Called after ejection.  Negative return means error, zero
+	 * or positive is just a success.
+	 */
+	int (*post_eject)(struct fsg_common *common,
+			  struct fsg_lun *lun, int num);
+};
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+	struct usb_gadget	*gadget;
+	struct usb_composite_dev *cdev;
+	struct fsg_dev		*fsg, *new_fsg;
+	wait_queue_head_t	fsg_wait;
+
+	/* filesem protects: backing files in use */
+	struct rw_semaphore	filesem;
+
+	/* lock protects: state, all the req_busy's */
+	spinlock_t		lock;
+
+	struct usb_ep		*ep0;		/* Copy of gadget->ep0 */
+	struct usb_request	*ep0req;	/* Copy of cdev->req */
+	unsigned int		ep0_req_tag;
+
+	struct fsg_buffhd	*next_buffhd_to_fill;
+	struct fsg_buffhd	*next_buffhd_to_drain;
+	struct fsg_buffhd	*buffhds;
+
+	int			cmnd_size;
+	u8			cmnd[MAX_COMMAND_SIZE];
+
+	unsigned int		nluns;
+	unsigned int		lun;
+	struct fsg_lun		*luns;
+	struct fsg_lun		*curlun;
+
+	unsigned int		bulk_out_maxpacket;
+	enum fsg_state		state;		/* For exception handling */
+	unsigned int		exception_req_tag;
+
+	enum data_direction	data_dir;
+	u32			data_size;
+	u32			data_size_from_cmnd;
+	u32			tag;
+	u32			residue;
+	u32			usb_amount_left;
+
+	unsigned int		can_stall:1;
+	unsigned int		free_storage_on_release:1;
+	unsigned int		phase_error:1;
+	unsigned int		short_packet_received:1;
+	unsigned int		bad_lun_okay:1;
+	unsigned int		running:1;
+
+	int			thread_wakeup_needed;
+	struct completion	thread_notifier;
+	struct task_struct	*thread_task;
+
+	/* Callback functions. */
+	const struct fsg_operations	*ops;
+	/* Gadget's private data. */
+	void			*private_data;
+
+	/*
+	 * Vendor (8 chars), product (16 chars), release (4
+	 * hexadecimal digits) and NUL byte
+	 */
+	char inquiry_string[8 + 16 + 4 + 1];
+
+	struct kref		ref;
+};
+
+struct fsg_config {
+	unsigned nluns;
+	struct fsg_lun_config {
+		const char *filename;
+		char ro;
+		char removable;
+		char cdrom;
+		char nofua;
+	} luns[FSG_MAX_LUNS];
+
+	/* Callback functions. */
+	const struct fsg_operations	*ops;
+	/* Gadget's private data. */
+	void			*private_data;
+
+	const char *vendor_name;		/*  8 characters or less */
+	const char *product_name;		/* 16 characters or less */
+	u16 release;
+
+	char			can_stall;
+};
+
+struct fsg_dev {
+	struct usb_function	function;
+	struct usb_gadget	*gadget;	/* Copy of cdev->gadget */
+	struct fsg_common	*common;
+
+	u16			interface_number;
+
+	unsigned int		bulk_in_enabled:1;
+	unsigned int		bulk_out_enabled:1;
+
+	unsigned long		atomic_bitflags;
+#define IGNORE_BULK_OUT		0
+
+	struct usb_ep		*bulk_in;
+	struct usb_ep		*bulk_out;
+};
+
+static inline int __fsg_is_set(struct fsg_common *common,
+			       const char *func, unsigned line)
+{
+	if (common->fsg)
+		return 1;
+	ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
+	WARN_ON(1);
+	return 0;
+}
+
+#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
+
+static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
+{
+	return container_of(f, struct fsg_dev, function);
+}
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int exception_in_progress(struct fsg_common *common)
+{
+	return common->state > FSG_STATE_IDLE;
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void set_bulk_out_req_length(struct fsg_common *common,
+				    struct fsg_buffhd *bh, unsigned int length)
+{
+	unsigned int	rem;
+
+	bh->bulk_out_intended_length = length;
+	rem = length % common->bulk_out_maxpacket;
+	if (rem > 0)
+		length += common->bulk_out_maxpacket - rem;
+	bh->outreq->length = length;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
+{
+	const char	*name;
+
+	if (ep == fsg->bulk_in)
+		name = "bulk-in";
+	else if (ep == fsg->bulk_out)
+		name = "bulk-out";
+	else
+		name = ep->name;
+	DBG(fsg, "%s set halt\n", name);
+	return usb_ep_set_halt(ep);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+/* Caller must hold fsg->lock */
+static void wakeup_thread(struct fsg_common *common)
+{
+	/* Tell the main thread that something has happened */
+	common->thread_wakeup_needed = 1;
+	if (common->thread_task)
+		wake_up_process(common->thread_task);
+}
+
+static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
+{
+	unsigned long		flags;
+
+	/*
+	 * Do nothing if a higher-priority exception is already in progress.
+	 * If a lower-or-equal priority exception is in progress, preempt it
+	 * and notify the main thread by sending it a signal.
+	 */
+	spin_lock_irqsave(&common->lock, flags);
+	if (common->state <= new_state) {
+		common->exception_req_tag = common->ep0_req_tag;
+		common->state = new_state;
+		if (common->thread_task)
+			send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+				      common->thread_task);
+	}
+	spin_unlock_irqrestore(&common->lock, flags);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ep0_queue(struct fsg_common *common)
+{
+	int	rc;
+
+	rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
+	common->ep0->driver_data = common;
+	if (rc != 0 && rc != -ESHUTDOWN) {
+		/* We can't do much more than wait for a reset */
+		WARNING(common, "error in submission: %s --> %d\n",
+			common->ep0->name, rc);
+	}
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Completion handlers. These always run in_irq. */
+
+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_common	*common = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
+
+	if (req->status || req->actual != req->length)
+		DBG(common, "%s --> %d, %u/%u\n", __func__,
+		    req->status, req->actual, req->length);
+	if (req->status == -ECONNRESET)		/* Request was cancelled */
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	smp_wmb();
+	spin_lock(&common->lock);
+	bh->inreq_busy = 0;
+	bh->state = BUF_STATE_EMPTY;
+	wakeup_thread(common);
+	spin_unlock(&common->lock);
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_common	*common = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
+
+	dump_msg(common, "bulk-out", req->buf, req->actual);
+	if (req->status || req->actual != bh->bulk_out_intended_length)
+		DBG(common, "%s --> %d, %u/%u\n", __func__,
+		    req->status, req->actual, bh->bulk_out_intended_length);
+	if (req->status == -ECONNRESET)		/* Request was cancelled */
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	smp_wmb();
+	spin_lock(&common->lock);
+	bh->outreq_busy = 0;
+	bh->state = BUF_STATE_FULL;
+	wakeup_thread(common);
+	spin_unlock(&common->lock);
+}
+
+static int fsg_setup(struct usb_function *f,
+		     const struct usb_ctrlrequest *ctrl)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+	struct usb_request	*req = fsg->common->ep0req;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
+
+	if (!fsg_is_set(fsg->common))
+		return -EOPNOTSUPP;
+
+	++fsg->common->ep0_req_tag;	/* Record arrival of a new request */
+	req->context = NULL;
+	req->length = 0;
+	dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+
+	switch (ctrl->bRequest) {
+
+	case US_BULK_RESET_REQUEST:
+		if (ctrl->bRequestType !=
+		    (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+			break;
+		if (w_index != fsg->interface_number || w_value != 0 ||
+				w_length != 0)
+			return -EDOM;
+
+		/*
+		 * Raise an exception to stop the current operation
+		 * and reinitialize our state.
+		 */
+		DBG(fsg, "bulk reset request\n");
+		raise_exception(fsg->common, FSG_STATE_RESET);
+		return DELAYED_STATUS;
+
+	case US_BULK_GET_MAX_LUN:
+		if (ctrl->bRequestType !=
+		    (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+			break;
+		if (w_index != fsg->interface_number || w_value != 0 ||
+				w_length != 1)
+			return -EDOM;
+		VDBG(fsg, "get max LUN\n");
+		*(u8 *)req->buf = fsg->common->nluns - 1;
+
+		/* Respond with data/status */
+		req->length = min((u16)1, w_length);
+		return ep0_queue(fsg->common);
+	}
+
+	VDBG(fsg,
+	     "unknown class-specific control req %02x.%02x v%04x i%04x l%u\n",
+	     ctrl->bRequestType, ctrl->bRequest,
+	     le16_to_cpu(ctrl->wValue), w_index, w_length);
+	return -EOPNOTSUPP;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* All the following routines run in process context */
+
+/* Use this for bulk or interrupt transfers, not ep0 */
+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
+			   struct usb_request *req, int *pbusy,
+			   enum fsg_buffer_state *state)
+{
+	int	rc;
+
+	if (ep == fsg->bulk_in)
+		dump_msg(fsg, "bulk-in", req->buf, req->length);
+
+	spin_lock_irq(&fsg->common->lock);
+	*pbusy = 1;
+	*state = BUF_STATE_BUSY;
+	spin_unlock_irq(&fsg->common->lock);
+	rc = usb_ep_queue(ep, req, GFP_KERNEL);
+	if (rc != 0) {
+		*pbusy = 0;
+		*state = BUF_STATE_EMPTY;
+
+		/* We can't do much more than wait for a reset */
+
+		/*
+		 * Note: currently the net2280 driver fails zero-length
+		 * submissions if DMA is enabled.
+		 */
+		if (rc != -ESHUTDOWN &&
+		    !(rc == -EOPNOTSUPP && req->length == 0))
+			WARNING(fsg, "error in submission: %s --> %d\n",
+				ep->name, rc);
+	}
+}
+
+static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	if (!fsg_is_set(common))
+		return false;
+	start_transfer(common->fsg, common->fsg->bulk_in,
+		       bh->inreq, &bh->inreq_busy, &bh->state);
+	return true;
+}
+
+static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	if (!fsg_is_set(common))
+		return false;
+	start_transfer(common->fsg, common->fsg->bulk_out,
+		       bh->outreq, &bh->outreq_busy, &bh->state);
+	return true;
+}
+
+static int sleep_thread(struct fsg_common *common)
+{
+	int	rc = 0;
+
+	/* Wait until a signal arrives or we are woken up */
+	for (;;) {
+		try_to_freeze();
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+		if (common->thread_wakeup_needed)
+			break;
+		schedule();
+	}
+	__set_current_state(TASK_RUNNING);
+	common->thread_wakeup_needed = 0;
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_read(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = common->curlun;
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			rc;
+	u32			amount_left;
+	loff_t			file_offset, file_offset_tmp;
+	unsigned int		amount;
+	ssize_t			nread;
+
+	/*
+	 * Get the starting Logical Block Address and check that it's
+	 * not too big.
+	 */
+	if (common->cmnd[0] == READ_6)
+		lba = get_unaligned_be24(&common->cmnd[1]);
+	else {
+		lba = get_unaligned_be32(&common->cmnd[2]);
+
+		/*
+		 * We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = don't read from the
+		 * cache), but we don't implement them.
+		 */
+		if ((common->cmnd[1] & ~0x18) != 0) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+	file_offset = ((loff_t) lba) << curlun->blkbits;
+
+	/* Carry out the file reads */
+	amount_left = common->data_size_from_cmnd;
+	if (unlikely(amount_left == 0))
+		return -EIO;		/* No default reply */
+
+	for (;;) {
+		/*
+		 * Figure out how much we need to read:
+		 * Try to read the remaining amount.
+		 * But don't read more than the buffer size.
+		 * And don't try to read past the end of the file.
+		 */
+		amount = min(amount_left, FSG_BUFLEN);
+		amount = min((loff_t)amount,
+			     curlun->file_length - file_offset);
+
+		/* Wait for the next buffer to become available */
+		bh = common->next_buffhd_to_fill;
+		while (bh->state != BUF_STATE_EMPTY) {
+			rc = sleep_thread(common);
+			if (rc)
+				return rc;
+		}
+
+		/*
+		 * If we were asked to read past the end of file,
+		 * end with an empty buffer.
+		 */
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
+			curlun->info_valid = 1;
+			bh->inreq->length = 0;
+			bh->state = BUF_STATE_FULL;
+			break;
+		}
+
+		/* Perform the read */
+		file_offset_tmp = file_offset;
+		nread = vfs_read(curlun->filp,
+				 (char __user *)bh->buf,
+				 amount, &file_offset_tmp);
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+		      (unsigned long long)file_offset, (int)nread);
+		if (signal_pending(current))
+			return -EINTR;
+
+		if (nread < 0) {
+			LDBG(curlun, "error in file read: %d\n", (int)nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file read: %d/%u\n",
+			     (int)nread, amount);
+			nread = round_down(nread, curlun->blksize);
+		}
+		file_offset  += nread;
+		amount_left  -= nread;
+		common->residue -= nread;
+
+		/*
+		 * Except at the end of the transfer, nread will be
+		 * equal to the buffer size, which is divisible by the
+		 * bulk-in maxpacket size.
+		 */
+		bh->inreq->length = nread;
+		bh->state = BUF_STATE_FULL;
+
+		/* If an error occurred, report it and its position */
+		if (nread < amount) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
+			curlun->info_valid = 1;
+			break;
+		}
+
+		if (amount_left == 0)
+			break;		/* No more left to read */
+
+		/* Send this buffer and go read some more */
+		bh->inreq->zero = 0;
+		if (!start_in_transfer(common, bh))
+			/* Don't know what to do if common->fsg is NULL */
+			return -EIO;
+		common->next_buffhd_to_fill = bh->next;
+	}
+
+	return -EIO;		/* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_write(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = common->curlun;
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			get_some_more;
+	u32			amount_left_to_req, amount_left_to_write;
+	loff_t			usb_offset, file_offset, file_offset_tmp;
+	unsigned int		amount;
+	ssize_t			nwritten;
+	int			rc;
+
+	if (curlun->ro) {
+		curlun->sense_data = SS_WRITE_PROTECTED;
+		return -EINVAL;
+	}
+	spin_lock(&curlun->filp->f_lock);
+	curlun->filp->f_flags &= ~O_SYNC;	/* Default is not to wait */
+	spin_unlock(&curlun->filp->f_lock);
+
+	/*
+	 * Get the starting Logical Block Address and check that it's
+	 * not too big
+	 */
+	if (common->cmnd[0] == WRITE_6)
+		lba = get_unaligned_be24(&common->cmnd[1]);
+	else {
+		lba = get_unaligned_be32(&common->cmnd[2]);
+
+		/*
+		 * We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = write directly to the
+		 * medium).  We don't implement DPO; we implement FUA by
+		 * performing synchronous output.
+		 */
+		if (common->cmnd[1] & ~0x18) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+		if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
+			spin_lock(&curlun->filp->f_lock);
+			curlun->filp->f_flags |= O_SYNC;
+			spin_unlock(&curlun->filp->f_lock);
+		}
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/* Carry out the file writes */
+	get_some_more = 1;
+	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
+	amount_left_to_req = common->data_size_from_cmnd;
+	amount_left_to_write = common->data_size_from_cmnd;
+
+	while (amount_left_to_write > 0) {
+
+		/* Queue a request for more data from the host */
+		bh = common->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+			/*
+			 * Figure out how much we want to get:
+			 * Try to get the remaining amount,
+			 * but not more than the buffer size.
+			 */
+			amount = min(amount_left_to_req, FSG_BUFLEN);
+
+			/* Beyond the end of the backing file? */
+			if (usb_offset >= curlun->file_length) {
+				get_some_more = 0;
+				curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+				curlun->sense_data_info =
+					usb_offset >> curlun->blkbits;
+				curlun->info_valid = 1;
+				continue;
+			}
+
+			/* Get the next buffer */
+			usb_offset += amount;
+			common->usb_amount_left -= amount;
+			amount_left_to_req -= amount;
+			if (amount_left_to_req == 0)
+				get_some_more = 0;
+
+			/*
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(common, bh, amount);
+			if (!start_out_transfer(common, bh))
+				/* Dunno what to do if common->fsg is NULL */
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			continue;
+		}
+
+		/* Write the received data to the backing file */
+		bh = common->next_buffhd_to_drain;
+		if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+			break;			/* We stopped early */
+		if (bh->state == BUF_STATE_FULL) {
+			smp_rmb();
+			common->next_buffhd_to_drain = bh->next;
+			bh->state = BUF_STATE_EMPTY;
+
+			/* Did something go wrong with the transfer? */
+			if (bh->outreq->status != 0) {
+				curlun->sense_data = SS_COMMUNICATION_FAILURE;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
+				curlun->info_valid = 1;
+				break;
+			}
+
+			amount = bh->outreq->actual;
+			if (curlun->file_length - file_offset < amount) {
+				LERROR(curlun,
+				       "write %u @ %llu beyond end %llu\n",
+				       amount, (unsigned long long)file_offset,
+				       (unsigned long long)curlun->file_length);
+				amount = curlun->file_length - file_offset;
+			}
+
+			/* Don't accept excess data.  The spec doesn't say
+			 * what to do in this case.  We'll ignore the error.
+			 */
+			amount = min(amount, bh->bulk_out_intended_length);
+
+			/* Don't write a partial block */
+			amount = round_down(amount, curlun->blksize);
+			if (amount == 0)
+				goto empty_write;
+
+			/* Perform the write */
+			file_offset_tmp = file_offset;
+			nwritten = vfs_write(curlun->filp,
+					     (char __user *)bh->buf,
+					     amount, &file_offset_tmp);
+			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
+			      (unsigned long long)file_offset, (int)nwritten);
+			if (signal_pending(current))
+				return -EINTR;		/* Interrupted! */
+
+			if (nwritten < 0) {
+				LDBG(curlun, "error in file write: %d\n",
+				     (int)nwritten);
+				nwritten = 0;
+			} else if (nwritten < amount) {
+				LDBG(curlun, "partial file write: %d/%u\n",
+				     (int)nwritten, amount);
+				nwritten = round_down(nwritten, curlun->blksize);
+			}
+			file_offset += nwritten;
+			amount_left_to_write -= nwritten;
+			common->residue -= nwritten;
+
+			/* If an error occurred, report it and its position */
+			if (nwritten < amount) {
+				curlun->sense_data = SS_WRITE_ERROR;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
+				curlun->info_valid = 1;
+				break;
+			}
+
+ empty_write:
+			/* Did the host decide to stop early? */
+			if (bh->outreq->actual < bh->bulk_out_intended_length) {
+				common->short_packet_received = 1;
+				break;
+			}
+			continue;
+		}
+
+		/* Wait for something to happen */
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	return -EIO;		/* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_synchronize_cache(struct fsg_common *common)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		rc;
+
+	/* We ignore the requested LBA and write out all file's
+	 * dirty data buffers. */
+	rc = fsg_lun_fsync_sub(curlun);
+	if (rc)
+		curlun->sense_data = SS_WRITE_ERROR;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void invalidate_sub(struct fsg_lun *curlun)
+{
+	struct file	*filp = curlun->filp;
+	struct inode	*inode = filp->f_path.dentry->d_inode;
+	unsigned long	rc;
+
+	rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
+	VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
+}
+
+static int do_verify(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = common->curlun;
+	u32			lba;
+	u32			verification_length;
+	struct fsg_buffhd	*bh = common->next_buffhd_to_fill;
+	loff_t			file_offset, file_offset_tmp;
+	u32			amount_left;
+	unsigned int		amount;
+	ssize_t			nread;
+
+	/*
+	 * Get the starting Logical Block Address and check that it's
+	 * not too big.
+	 */
+	lba = get_unaligned_be32(&common->cmnd[2]);
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/*
+	 * We allow DPO (Disable Page Out = don't save data in the
+	 * cache) but we don't implement it.
+	 */
+	if (common->cmnd[1] & ~0x10) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	verification_length = get_unaligned_be16(&common->cmnd[7]);
+	if (unlikely(verification_length == 0))
+		return -EIO;		/* No default reply */
+
+	/* Prepare to carry out the file verify */
+	amount_left = verification_length << curlun->blkbits;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
+
+	/* Write out all the dirty buffers before invalidating them */
+	fsg_lun_fsync_sub(curlun);
+	if (signal_pending(current))
+		return -EINTR;
+
+	invalidate_sub(curlun);
+	if (signal_pending(current))
+		return -EINTR;
+
+	/* Just try to read the requested blocks */
+	while (amount_left > 0) {
+		/*
+		 * Figure out how much we need to read:
+		 * Try to read the remaining amount, but not more than
+		 * the buffer size.
+		 * And don't try to read past the end of the file.
+		 */
+		amount = min(amount_left, FSG_BUFLEN);
+		amount = min((loff_t)amount,
+			     curlun->file_length - file_offset);
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
+			curlun->info_valid = 1;
+			break;
+		}
+
+		/* Perform the read */
+		file_offset_tmp = file_offset;
+		nread = vfs_read(curlun->filp,
+				(char __user *) bh->buf,
+				amount, &file_offset_tmp);
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+				(unsigned long long) file_offset,
+				(int) nread);
+		if (signal_pending(current))
+			return -EINTR;
+
+		if (nread < 0) {
+			LDBG(curlun, "error in file verify: %d\n", (int)nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file verify: %d/%u\n",
+			     (int)nread, amount);
+			nread = round_down(nread, curlun->blksize);
+		}
+		if (nread == 0) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
+			curlun->info_valid = 1;
+			break;
+		}
+		file_offset += nread;
+		amount_left -= nread;
+	}
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun *curlun = common->curlun;
+	u8	*buf = (u8 *) bh->buf;
+
+	if (!curlun) {		/* Unsupported LUNs are okay */
+		common->bad_lun_okay = 1;
+		memset(buf, 0, 36);
+		buf[0] = 0x7f;		/* Unsupported, no device-type */
+		buf[4] = 31;		/* Additional length */
+		return 36;
+	}
+
+	buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK;
+	buf[1] = curlun->removable ? 0x80 : 0;
+	buf[2] = 2;		/* ANSI SCSI level 2 */
+	buf[3] = 2;		/* SCSI-2 INQUIRY data format */
+	buf[4] = 31;		/* Additional length */
+	buf[5] = 0;		/* No special options */
+	buf[6] = 0;
+	buf[7] = 0;
+	memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
+	return 36;
+}
+
+static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	u8		*buf = (u8 *) bh->buf;
+	u32		sd, sdinfo;
+	int		valid;
+
+	/*
+	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):
+	 *
+	 * If a REQUEST SENSE command is received from an initiator
+	 * with a pending unit attention condition (before the target
+	 * generates the contingent allegiance condition), then the
+	 * target shall either:
+	 *   a) report any pending sense data and preserve the unit
+	 *	attention condition on the logical unit, or,
+	 *   b) report the unit attention condition, may discard any
+	 *	pending sense data, and clear the unit attention
+	 *	condition on the logical unit for that initiator.
+	 *
+	 * FSG normally uses option a); enable this code to use option b).
+	 */
+#if 0
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+	}
+#endif
+
+	if (!curlun) {		/* Unsupported LUNs are okay */
+		common->bad_lun_okay = 1;
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+		sdinfo = 0;
+		valid = 0;
+	} else {
+		sd = curlun->sense_data;
+		sdinfo = curlun->sense_data_info;
+		valid = curlun->info_valid << 7;
+		curlun->sense_data = SS_NO_SENSE;
+		curlun->sense_data_info = 0;
+		curlun->info_valid = 0;
+	}
+
+	memset(buf, 0, 18);
+	buf[0] = valid | 0x70;			/* Valid, current error */
+	buf[2] = SK(sd);
+	put_unaligned_be32(sdinfo, &buf[3]);	/* Sense information */
+	buf[7] = 18 - 8;			/* Additional sense length */
+	buf[12] = ASC(sd);
+	buf[13] = ASCQ(sd);
+	return 18;
+}
+
+static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	u32		lba = get_unaligned_be32(&common->cmnd[2]);
+	int		pmi = common->cmnd[8];
+	u8		*buf = (u8 *)bh->buf;
+
+	/* Check the PMI and LBA fields */
+	if (pmi > 1 || (pmi == 0 && lba != 0)) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
+						/* Max logical block */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
+	return 8;
+}
+
+static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		msf = common->cmnd[1] & 0x02;
+	u32		lba = get_unaligned_be32(&common->cmnd[2]);
+	u8		*buf = (u8 *)bh->buf;
+
+	if (common->cmnd[1] & ~0x02) {		/* Mask away MSF */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	memset(buf, 0, 8);
+	buf[0] = 0x01;		/* 2048 bytes of user data, rest is EC */
+	store_cdrom_address(&buf[4], msf, lba);
+	return 8;
+}
+
+static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		msf = common->cmnd[1] & 0x02;
+	int		start_track = common->cmnd[6];
+	u8		*buf = (u8 *)bh->buf;
+
+	if ((common->cmnd[1] & ~0x02) != 0 ||	/* Mask away MSF */
+			start_track > 1) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	memset(buf, 0, 20);
+	buf[1] = (20-2);		/* TOC data length */
+	buf[2] = 1;			/* First track number */
+	buf[3] = 1;			/* Last track number */
+	buf[5] = 0x16;			/* Data track, copying allowed */
+	buf[6] = 0x01;			/* Only track is number 1 */
+	store_cdrom_address(&buf[8], msf, 0);
+
+	buf[13] = 0x16;			/* Lead-out track is data */
+	buf[14] = 0xAA;			/* Lead-out track number */
+	store_cdrom_address(&buf[16], msf, curlun->num_sectors);
+	return 20;
+}
+
+static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		mscmnd = common->cmnd[0];
+	u8		*buf = (u8 *) bh->buf;
+	u8		*buf0 = buf;
+	int		pc, page_code;
+	int		changeable_values, all_pages;
+	int		valid_page = 0;
+	int		len, limit;
+
+	if ((common->cmnd[1] & ~0x08) != 0) {	/* Mask away DBD */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+	pc = common->cmnd[2] >> 6;
+	page_code = common->cmnd[2] & 0x3f;
+	if (pc == 3) {
+		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
+		return -EINVAL;
+	}
+	changeable_values = (pc == 1);
+	all_pages = (page_code == 0x3f);
+
+	/*
+	 * Write the mode parameter header.  Fixed values are: default
+	 * medium type, no cache control (DPOFUA), and no block descriptors.
+	 * The only variable value is the WriteProtect bit.  We will fill in
+	 * the mode data length later.
+	 */
+	memset(buf, 0, 8);
+	if (mscmnd == MODE_SENSE) {
+		buf[2] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf += 4;
+		limit = 255;
+	} else {			/* MODE_SENSE_10 */
+		buf[3] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf += 8;
+		limit = 65535;		/* Should really be FSG_BUFLEN */
+	}
+
+	/* No block descriptors */
+
+	/*
+	 * The mode pages, in numerical order.  The only page we support
+	 * is the Caching page.
+	 */
+	if (page_code == 0x08 || all_pages) {
+		valid_page = 1;
+		buf[0] = 0x08;		/* Page code */
+		buf[1] = 10;		/* Page length */
+		memset(buf+2, 0, 10);	/* None of the fields are changeable */
+
+		if (!changeable_values) {
+			buf[2] = 0x04;	/* Write cache enable, */
+					/* Read cache not disabled */
+					/* No cache retention priorities */
+			put_unaligned_be16(0xffff, &buf[4]);
+					/* Don't disable prefetch */
+					/* Minimum prefetch = 0 */
+			put_unaligned_be16(0xffff, &buf[8]);
+					/* Maximum prefetch */
+			put_unaligned_be16(0xffff, &buf[10]);
+					/* Maximum prefetch ceiling */
+		}
+		buf += 12;
+	}
+
+	/*
+	 * Check that a valid page was requested and the mode data length
+	 * isn't too long.
+	 */
+	len = buf - buf0;
+	if (!valid_page || len > limit) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	/*  Store the mode data length */
+	if (mscmnd == MODE_SENSE)
+		buf0[0] = len - 1;
+	else
+		put_unaligned_be16(len - 2, buf0);
+	return len;
+}
+
+static int do_start_stop(struct fsg_common *common)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		loej, start;
+
+	if (!curlun) {
+		return -EINVAL;
+	} else if (!curlun->removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	} else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
+		   (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	loej  = common->cmnd[4] & 0x02;
+	start = common->cmnd[4] & 0x01;
+
+	/*
+	 * Our emulation doesn't support mounting; the medium is
+	 * available for use as soon as it is loaded.
+	 */
+	if (start) {
+		if (!fsg_lun_is_open(curlun)) {
+			curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	/* Are we allowed to unload the media? */
+	if (curlun->prevent_medium_removal) {
+		LDBG(curlun, "unload attempt prevented\n");
+		curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
+		return -EINVAL;
+	}
+
+	if (!loej)
+		return 0;
+
+	/* Simulate an unload/eject */
+	if (common->ops && common->ops->pre_eject) {
+		int r = common->ops->pre_eject(common, curlun,
+					       curlun - common->luns);
+		if (unlikely(r < 0))
+			return r;
+		else if (r)
+			return 0;
+	}
+
+	up_read(&common->filesem);
+	down_write(&common->filesem);
+	fsg_lun_close(curlun);
+	up_write(&common->filesem);
+	down_read(&common->filesem);
+
+	return common->ops && common->ops->post_eject
+		? min(0, common->ops->post_eject(common, curlun,
+						 curlun - common->luns))
+		: 0;
+}
+
+static int do_prevent_allow(struct fsg_common *common)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	int		prevent;
+
+	if (!common->curlun) {
+		return -EINVAL;
+	} else if (!common->curlun->removable) {
+		common->curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	}
+
+	prevent = common->cmnd[4] & 0x01;
+	if ((common->cmnd[4] & ~0x01) != 0) {	/* Mask away Prevent */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	if (curlun->prevent_medium_removal && !prevent)
+		fsg_lun_fsync_sub(curlun);
+	curlun->prevent_medium_removal = prevent;
+	return 0;
+}
+
+static int do_read_format_capacities(struct fsg_common *common,
+			struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	u8		*buf = (u8 *) bh->buf;
+
+	buf[0] = buf[1] = buf[2] = 0;
+	buf[3] = 8;	/* Only the Current/Maximum Capacity Descriptor */
+	buf += 4;
+
+	put_unaligned_be32(curlun->num_sectors, &buf[0]);
+						/* Number of blocks */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
+	buf[4] = 0x02;				/* Current capacity */
+	return 12;
+}
+
+static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+
+	/* We don't support MODE SELECT */
+	if (curlun)
+		curlun->sense_data = SS_INVALID_COMMAND;
+	return -EINVAL;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	rc = fsg_set_halt(fsg, fsg->bulk_in);
+	if (rc == -EAGAIN)
+		VDBG(fsg, "delayed bulk-in endpoint halt\n");
+	while (rc != 0) {
+		if (rc != -EAGAIN) {
+			WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
+			rc = 0;
+			break;
+		}
+
+		/* Wait for a short time and then try again */
+		if (msleep_interruptible(100) != 0)
+			return -EINTR;
+		rc = usb_ep_set_halt(fsg->bulk_in);
+	}
+	return rc;
+}
+
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	DBG(fsg, "bulk-in set wedge\n");
+	rc = usb_ep_set_wedge(fsg->bulk_in);
+	if (rc == -EAGAIN)
+		VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+	while (rc != 0) {
+		if (rc != -EAGAIN) {
+			WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
+			rc = 0;
+			break;
+		}
+
+		/* Wait for a short time and then try again */
+		if (msleep_interruptible(100) != 0)
+			return -EINTR;
+		rc = usb_ep_set_wedge(fsg->bulk_in);
+	}
+	return rc;
+}
+
+static int throw_away_data(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	u32			amount;
+	int			rc;
+
+	for (bh = common->next_buffhd_to_drain;
+	     bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
+	     bh = common->next_buffhd_to_drain) {
+
+		/* Throw away the data in a filled buffer */
+		if (bh->state == BUF_STATE_FULL) {
+			smp_rmb();
+			bh->state = BUF_STATE_EMPTY;
+			common->next_buffhd_to_drain = bh->next;
+
+			/* A short packet or an error ends everything */
+			if (bh->outreq->actual < bh->bulk_out_intended_length ||
+			    bh->outreq->status != 0) {
+				raise_exception(common,
+						FSG_STATE_ABORT_BULK_OUT);
+				return -EINTR;
+			}
+			continue;
+		}
+
+		/* Try to submit another request if we need one */
+		bh = common->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY
+		 && common->usb_amount_left > 0) {
+			amount = min(common->usb_amount_left, FSG_BUFLEN);
+
+			/*
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(common, bh, amount);
+			if (!start_out_transfer(common, bh))
+				/* Dunno what to do if common->fsg is NULL */
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			common->usb_amount_left -= amount;
+			continue;
+		}
+
+		/* Otherwise wait for something to happen */
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
+static int finish_reply(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh = common->next_buffhd_to_fill;
+	int			rc = 0;
+
+	switch (common->data_dir) {
+	case DATA_DIR_NONE:
+		break;			/* Nothing to send */
+
+	/*
+	 * If we don't know whether the host wants to read or write,
+	 * this must be CB or CBI with an unknown command.  We mustn't
+	 * try to send or receive any data.  So stall both bulk pipes
+	 * if we can and wait for a reset.
+	 */
+	case DATA_DIR_UNKNOWN:
+		if (!common->can_stall) {
+			/* Nothing */
+		} else if (fsg_is_set(common)) {
+			fsg_set_halt(common->fsg, common->fsg->bulk_out);
+			rc = halt_bulk_in_endpoint(common->fsg);
+		} else {
+			/* Don't know what to do if common->fsg is NULL */
+			rc = -EIO;
+		}
+		break;
+
+	/* All but the last buffer of data must have already been sent */
+	case DATA_DIR_TO_HOST:
+		if (common->data_size == 0) {
+			/* Nothing to send */
+
+		/* Don't know what to do if common->fsg is NULL */
+		} else if (!fsg_is_set(common)) {
+			rc = -EIO;
+
+		/* If there's no residue, simply send the last buffer */
+		} else if (common->residue == 0) {
+			bh->inreq->zero = 0;
+			if (!start_in_transfer(common, bh))
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+
+		/*
+		 * For Bulk-only, mark the end of the data with a short
+		 * packet.  If we are allowed to stall, halt the bulk-in
+		 * endpoint.  (Note: This violates the Bulk-Only Transport
+		 * specification, which requires us to pad the data if we
+		 * don't halt the endpoint.  Presumably nobody will mind.)
+		 */
+		} else {
+			bh->inreq->zero = 1;
+			if (!start_in_transfer(common, bh))
+				rc = -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			if (common->can_stall)
+				rc = halt_bulk_in_endpoint(common->fsg);
+		}
+		break;
+
+	/*
+	 * We have processed all we want from the data the host has sent.
+	 * There may still be outstanding bulk-out requests.
+	 */
+	case DATA_DIR_FROM_HOST:
+		if (common->residue == 0) {
+			/* Nothing to receive */
+
+		/* Did the host stop sending unexpectedly early? */
+		} else if (common->short_packet_received) {
+			raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+
+		/*
+		 * We haven't processed all the incoming data.  Even though
+		 * we may be allowed to stall, doing so would cause a race.
+		 * The controller may already have ACK'ed all the remaining
+		 * bulk-out packets, in which case the host wouldn't see a
+		 * STALL.  Not realizing the endpoint was halted, it wouldn't
+		 * clear the halt -- leading to problems later on.
+		 */
+#if 0
+		} else if (common->can_stall) {
+			if (fsg_is_set(common))
+				fsg_set_halt(common->fsg,
+					     common->fsg->bulk_out);
+			raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+#endif
+
+		/*
+		 * We can't stall.  Read in the excess data and throw it
+		 * all away.
+		 */
+		} else {
+			rc = throw_away_data(common);
+		}
+		break;
+	}
+	return rc;
+}
+
+static int send_status(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = common->curlun;
+	struct fsg_buffhd	*bh;
+	struct bulk_cs_wrap	*csw;
+	int			rc;
+	u8			status = US_BULK_STAT_OK;
+	u32			sd, sdinfo = 0;
+
+	/* Wait for the next buffer to become available */
+	bh = common->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	if (curlun) {
+		sd = curlun->sense_data;
+		sdinfo = curlun->sense_data_info;
+	} else if (common->bad_lun_okay)
+		sd = SS_NO_SENSE;
+	else
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+	if (common->phase_error) {
+		DBG(common, "sending phase-error status\n");
+		status = US_BULK_STAT_PHASE;
+		sd = SS_INVALID_COMMAND;
+	} else if (sd != SS_NO_SENSE) {
+		DBG(common, "sending command-failure status\n");
+		status = US_BULK_STAT_FAIL;
+		VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+				"  info x%x\n",
+				SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+	}
+
+	/* Store and send the Bulk-only CSW */
+	csw = (void *)bh->buf;
+
+	csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
+	csw->Tag = common->tag;
+	csw->Residue = cpu_to_le32(common->residue);
+	csw->Status = status;
+
+	bh->inreq->length = US_BULK_CS_WRAP_LEN;
+	bh->inreq->zero = 0;
+	if (!start_in_transfer(common, bh))
+		/* Don't know what to do if common->fsg is NULL */
+		return -EIO;
+
+	common->next_buffhd_to_fill = bh->next;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have.
+ */
+static int check_command(struct fsg_common *common, int cmnd_size,
+			 enum data_direction data_dir, unsigned int mask,
+			 int needs_medium, const char *name)
+{
+	int			i;
+	int			lun = common->cmnd[1] >> 5;
+	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
+	char			hdlen[20];
+	struct fsg_lun		*curlun;
+
+	hdlen[0] = 0;
+	if (common->data_dir != DATA_DIR_UNKNOWN)
+		sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
+			common->data_size);
+	VDBG(common, "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
+	     name, cmnd_size, dirletter[(int) data_dir],
+	     common->data_size_from_cmnd, common->cmnd_size, hdlen);
+
+	/*
+	 * We can't reply at all until we know the correct data direction
+	 * and size.
+	 */
+	if (common->data_size_from_cmnd == 0)
+		data_dir = DATA_DIR_NONE;
+	if (common->data_size < common->data_size_from_cmnd) {
+		/*
+		 * Host data size < Device data size is a phase error.
+		 * Carry out the command, but only transfer as much as
+		 * we are allowed.
+		 */
+		common->data_size_from_cmnd = common->data_size;
+		common->phase_error = 1;
+	}
+	common->residue = common->data_size;
+	common->usb_amount_left = common->data_size;
+
+	/* Conflicting data directions is a phase error */
+	if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) {
+		common->phase_error = 1;
+		return -EINVAL;
+	}
+
+	/* Verify the length of the command itself */
+	if (cmnd_size != common->cmnd_size) {
+
+		/*
+		 * Special case workaround: There are plenty of buggy SCSI
+		 * implementations. Many have issues with cbw->Length
+		 * field passing a wrong command size. For those cases we
+		 * always try to work around the problem by using the length
+		 * sent by the host side provided it is at least as large
+		 * as the correct command length.
+		 * Examples of such cases would be MS-Windows, which issues
+		 * REQUEST SENSE with cbw->Length == 12 where it should
+		 * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
+		 * REQUEST SENSE with cbw->Length == 10 where it should
+		 * be 6 as well.
+		 */
+		if (cmnd_size <= common->cmnd_size) {
+			DBG(common, "%s is buggy! Expected length %d "
+			    "but we got %d\n", name,
+			    cmnd_size, common->cmnd_size);
+			cmnd_size = common->cmnd_size;
+		} else {
+			common->phase_error = 1;
+			return -EINVAL;
+		}
+	}
+
+	/* Check that the LUN values are consistent */
+	if (common->lun != lun)
+		DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
+		    common->lun, lun);
+
+	/* Check the LUN */
+	curlun = common->curlun;
+	if (curlun) {
+		if (common->cmnd[0] != REQUEST_SENSE) {
+			curlun->sense_data = SS_NO_SENSE;
+			curlun->sense_data_info = 0;
+			curlun->info_valid = 0;
+		}
+	} else {
+		common->bad_lun_okay = 0;
+
+		/*
+		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
+		 * to use unsupported LUNs; all others may not.
+		 */
+		if (common->cmnd[0] != INQUIRY &&
+		    common->cmnd[0] != REQUEST_SENSE) {
+			DBG(common, "unsupported LUN %d\n", common->lun);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * If a unit attention condition exists, only INQUIRY and
+	 * REQUEST SENSE commands are allowed; anything else must fail.
+	 */
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+	    common->cmnd[0] != INQUIRY &&
+	    common->cmnd[0] != REQUEST_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+		return -EINVAL;
+	}
+
+	/* Check that only command bytes listed in the mask are non-zero */
+	common->cmnd[1] &= 0x1f;			/* Mask away the LUN */
+	for (i = 1; i < cmnd_size; ++i) {
+		if (common->cmnd[i] && !(mask & (1 << i))) {
+			if (curlun)
+				curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+
+	/* If the medium isn't mounted and the command needs to access
+	 * it, return an error. */
+	if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
+		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_common *common,
+		int cmnd_size, enum data_direction data_dir,
+		unsigned int mask, int needs_medium, const char *name)
+{
+	if (common->curlun)
+		common->data_size_from_cmnd <<= common->curlun->blkbits;
+	return check_command(common, cmnd_size, data_dir,
+			mask, needs_medium, name);
+}
+
+static int do_scsi_command(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	int			rc;
+	int			reply = -EINVAL;
+	int			i;
+	static char		unknown[16];
+
+	dump_cdb(common);
+
+	/* Wait for the next buffer to become available for data or status */
+	bh = common->next_buffhd_to_fill;
+	common->next_buffhd_to_drain = bh;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+	common->phase_error = 0;
+	common->short_packet_received = 0;
+
+	down_read(&common->filesem);	/* We're using the backing file */
+	switch (common->cmnd[0]) {
+
+	case INQUIRY:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<4), 0,
+				      "INQUIRY");
+		if (reply == 0)
+			reply = do_inquiry(common, bh);
+		break;
+
+	case MODE_SELECT:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+				      (1<<1) | (1<<4), 0,
+				      "MODE SELECT(6)");
+		if (reply == 0)
+			reply = do_mode_select(common, bh);
+		break;
+
+	case MODE_SELECT_10:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+				      (1<<1) | (3<<7), 0,
+				      "MODE SELECT(10)");
+		if (reply == 0)
+			reply = do_mode_select(common, bh);
+		break;
+
+	case MODE_SENSE:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<1) | (1<<2) | (1<<4), 0,
+				      "MODE SENSE(6)");
+		if (reply == 0)
+			reply = do_mode_sense(common, bh);
+		break;
+
+	case MODE_SENSE_10:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (1<<1) | (1<<2) | (3<<7), 0,
+				      "MODE SENSE(10)");
+		if (reply == 0)
+			reply = do_mode_sense(common, bh);
+		break;
+
+	case ALLOW_MEDIUM_REMOVAL:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				      (1<<4), 0,
+				      "PREVENT-ALLOW MEDIUM REMOVAL");
+		if (reply == 0)
+			reply = do_prevent_allow(common);
+		break;
+
+	case READ_6:
+		i = common->cmnd[4];
+		common->data_size_from_cmnd = (i == 0) ? 256 : i;
+		reply = check_command_size_in_blocks(common, 6,
+				      DATA_DIR_TO_HOST,
+				      (7<<1) | (1<<4), 1,
+				      "READ(6)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case READ_10:
+		common->data_size_from_cmnd =
+				get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command_size_in_blocks(common, 10,
+				      DATA_DIR_TO_HOST,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "READ(10)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case READ_12:
+		common->data_size_from_cmnd =
+				get_unaligned_be32(&common->cmnd[6]);
+		reply = check_command_size_in_blocks(common, 12,
+				      DATA_DIR_TO_HOST,
+				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
+				      "READ(12)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case READ_CAPACITY:
+		common->data_size_from_cmnd = 8;
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (0xf<<2) | (1<<8), 1,
+				      "READ CAPACITY");
+		if (reply == 0)
+			reply = do_read_capacity(common, bh);
+		break;
+
+	case READ_HEADER:
+		if (!common->curlun || !common->curlun->cdrom)
+			goto unknown_cmnd;
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (3<<7) | (0x1f<<1), 1,
+				      "READ HEADER");
+		if (reply == 0)
+			reply = do_read_header(common, bh);
+		break;
+
+	case READ_TOC:
+		if (!common->curlun || !common->curlun->cdrom)
+			goto unknown_cmnd;
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (7<<6) | (1<<1), 1,
+				      "READ TOC");
+		if (reply == 0)
+			reply = do_read_toc(common, bh);
+		break;
+
+	case READ_FORMAT_CAPACITIES:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (3<<7), 1,
+				      "READ FORMAT CAPACITIES");
+		if (reply == 0)
+			reply = do_read_format_capacities(common, bh);
+		break;
+
+	case REQUEST_SENSE:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<4), 0,
+				      "REQUEST SENSE");
+		if (reply == 0)
+			reply = do_request_sense(common, bh);
+		break;
+
+	case START_STOP:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				      (1<<1) | (1<<4), 0,
+				      "START-STOP UNIT");
+		if (reply == 0)
+			reply = do_start_stop(common);
+		break;
+
+	case SYNCHRONIZE_CACHE:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 10, DATA_DIR_NONE,
+				      (0xf<<2) | (3<<7), 1,
+				      "SYNCHRONIZE CACHE");
+		if (reply == 0)
+			reply = do_synchronize_cache(common);
+		break;
+
+	case TEST_UNIT_READY:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				0, 1,
+				"TEST UNIT READY");
+		break;
+
+	/*
+	 * Although optional, this command is used by MS-Windows.  We
+	 * support a minimal version: BytChk must be 0.
+	 */
+	case VERIFY:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 10, DATA_DIR_NONE,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "VERIFY");
+		if (reply == 0)
+			reply = do_verify(common);
+		break;
+
+	case WRITE_6:
+		i = common->cmnd[4];
+		common->data_size_from_cmnd = (i == 0) ? 256 : i;
+		reply = check_command_size_in_blocks(common, 6,
+				      DATA_DIR_FROM_HOST,
+				      (7<<1) | (1<<4), 1,
+				      "WRITE(6)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	case WRITE_10:
+		common->data_size_from_cmnd =
+				get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command_size_in_blocks(common, 10,
+				      DATA_DIR_FROM_HOST,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "WRITE(10)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	case WRITE_12:
+		common->data_size_from_cmnd =
+				get_unaligned_be32(&common->cmnd[6]);
+		reply = check_command_size_in_blocks(common, 12,
+				      DATA_DIR_FROM_HOST,
+				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
+				      "WRITE(12)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	/*
+	 * Some mandatory commands that we recognize but don't implement.
+	 * They don't mean much in this setting.  It's left as an exercise
+	 * for anyone interested to implement RESERVE and RELEASE in terms
+	 * of Posix locks.
+	 */
+	case FORMAT_UNIT:
+	case RELEASE:
+	case RESERVE:
+	case SEND_DIAGNOSTIC:
+		/* Fall through */
+
+	default:
+unknown_cmnd:
+		common->data_size_from_cmnd = 0;
+		sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
+		reply = check_command(common, common->cmnd_size,
+				      DATA_DIR_UNKNOWN, ~0, 0, unknown);
+		if (reply == 0) {
+			common->curlun->sense_data = SS_INVALID_COMMAND;
+			reply = -EINVAL;
+		}
+		break;
+	}
+	up_read(&common->filesem);
+
+	if (reply == -EINTR || signal_pending(current))
+		return -EINTR;
+
+	/* Set up the single reply buffer for finish_reply() */
+	if (reply == -EINVAL)
+		reply = 0;		/* Error reply length */
+	if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
+		reply = min((u32)reply, common->data_size_from_cmnd);
+		bh->inreq->length = reply;
+		bh->state = BUF_STATE_FULL;
+		common->residue -= reply;
+	}				/* Otherwise it's already set */
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct usb_request	*req = bh->outreq;
+	struct bulk_cb_wrap	*cbw = req->buf;
+	struct fsg_common	*common = fsg->common;
+
+	/* Was this a real packet?  Should it be ignored? */
+	if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+		return -EINVAL;
+
+	/* Is the CBW valid? */
+	if (req->actual != US_BULK_CB_WRAP_LEN ||
+			cbw->Signature != cpu_to_le32(
+				US_BULK_CB_SIGN)) {
+		DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
+				req->actual,
+				le32_to_cpu(cbw->Signature));
+
+		/*
+		 * The Bulk-only spec says we MUST stall the IN endpoint
+		 * (6.6.1), so it's unavoidable.  It also says we must
+		 * retain this state until the next reset, but there's
+		 * no way to tell the controller driver it should ignore
+		 * Clear-Feature(HALT) requests.
+		 *
+		 * We aren't required to halt the OUT endpoint; instead
+		 * we can simply accept and discard any data received
+		 * until the next reset.
+		 */
+		wedge_bulk_in_endpoint(fsg);
+		set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+		return -EINVAL;
+	}
+
+	/* Is the CBW meaningful? */
+	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
+			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
+		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
+				"cmdlen %u\n",
+				cbw->Lun, cbw->Flags, cbw->Length);
+
+		/*
+		 * We can do anything we want here, so let's stall the
+		 * bulk pipes if we are allowed to.
+		 */
+		if (common->can_stall) {
+			fsg_set_halt(fsg, fsg->bulk_out);
+			halt_bulk_in_endpoint(fsg);
+		}
+		return -EINVAL;
+	}
+
+	/* Save the command for later */
+	common->cmnd_size = cbw->Length;
+	memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
+	if (cbw->Flags & US_BULK_FLAG_IN)
+		common->data_dir = DATA_DIR_TO_HOST;
+	else
+		common->data_dir = DATA_DIR_FROM_HOST;
+	common->data_size = le32_to_cpu(cbw->DataTransferLength);
+	if (common->data_size == 0)
+		common->data_dir = DATA_DIR_NONE;
+	common->lun = cbw->Lun;
+	if (common->lun >= 0 && common->lun < common->nluns)
+		common->curlun = &common->luns[common->lun];
+	else
+		common->curlun = NULL;
+	common->tag = cbw->Tag;
+	return 0;
+}
+
+static int get_next_command(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	int			rc = 0;
+
+	/* Wait for the next buffer to become available */
+	bh = common->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	/* Queue a request to read a Bulk-only CBW */
+	set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
+	if (!start_out_transfer(common, bh))
+		/* Don't know what to do if common->fsg is NULL */
+		return -EIO;
+
+	/*
+	 * We will drain the buffer in software, which means we
+	 * can reuse it for the next filling.  No need to advance
+	 * next_buffhd_to_fill.
+	 */
+
+	/* Wait for the CBW to arrive */
+	while (bh->state != BUF_STATE_FULL) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+	smp_rmb();
+	rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+	bh->state = BUF_STATE_EMPTY;
+
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
+		struct usb_request **preq)
+{
+	*preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (*preq)
+		return 0;
+	ERROR(common, "can't allocate request for %s\n", ep->name);
+	return -ENOMEM;
+}
+
+/* Reset interface setting and re-init endpoint state (toggle etc). */
+static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
+{
+	struct fsg_dev *fsg;
+	int i, rc = 0;
+
+	if (common->running)
+		DBG(common, "reset interface\n");
+
+reset:
+	/* Deallocate the requests */
+	if (common->fsg) {
+		fsg = common->fsg;
+
+		for (i = 0; i < fsg_num_buffers; ++i) {
+			struct fsg_buffhd *bh = &common->buffhds[i];
+
+			if (bh->inreq) {
+				usb_ep_free_request(fsg->bulk_in, bh->inreq);
+				bh->inreq = NULL;
+			}
+			if (bh->outreq) {
+				usb_ep_free_request(fsg->bulk_out, bh->outreq);
+				bh->outreq = NULL;
+			}
+		}
+
+		/* Disable the endpoints */
+		if (fsg->bulk_in_enabled) {
+			usb_ep_disable(fsg->bulk_in);
+			fsg->bulk_in_enabled = 0;
+		}
+		if (fsg->bulk_out_enabled) {
+			usb_ep_disable(fsg->bulk_out);
+			fsg->bulk_out_enabled = 0;
+		}
+
+		common->fsg = NULL;
+		wake_up(&common->fsg_wait);
+	}
+
+	common->running = 0;
+	if (!new_fsg || rc)
+		return rc;
+
+	common->fsg = new_fsg;
+	fsg = common->fsg;
+
+	/* Enable the endpoints */
+	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_in);
+	if (rc)
+		goto reset;
+	fsg->bulk_in->driver_data = common;
+	fsg->bulk_in_enabled = 1;
+
+	rc = config_ep_by_speed(common->gadget, &(fsg->function),
+				fsg->bulk_out);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_out);
+	if (rc)
+		goto reset;
+	fsg->bulk_out->driver_data = common;
+	fsg->bulk_out_enabled = 1;
+	common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
+	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+	/* Allocate the requests */
+	for (i = 0; i < fsg_num_buffers; ++i) {
+		struct fsg_buffhd	*bh = &common->buffhds[i];
+
+		rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
+		if (rc)
+			goto reset;
+		rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
+		if (rc)
+			goto reset;
+		bh->inreq->buf = bh->outreq->buf = bh->buf;
+		bh->inreq->context = bh->outreq->context = bh;
+		bh->inreq->complete = bulk_in_complete;
+		bh->outreq->complete = bulk_out_complete;
+	}
+
+	common->running = 1;
+	for (i = 0; i < common->nluns; ++i)
+		common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+	return rc;
+}
+
+
+/****************************** ALT CONFIGS ******************************/
+
+static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct fsg_dev *fsg = fsg_from_func(f);
+	fsg->common->new_fsg = fsg;
+	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+	return USB_GADGET_DELAYED_STATUS;
+}
+
+static void fsg_disable(struct usb_function *f)
+{
+	struct fsg_dev *fsg = fsg_from_func(f);
+	fsg->common->new_fsg = NULL;
+	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_common *common)
+{
+	siginfo_t		info;
+	int			i;
+	struct fsg_buffhd	*bh;
+	enum fsg_state		old_state;
+	struct fsg_lun		*curlun;
+	unsigned int		exception_req_tag;
+
+	/*
+	 * Clear the existing signals.  Anything but SIGUSR1 is converted
+	 * into a high-priority EXIT exception.
+	 */
+	for (;;) {
+		int sig =
+			dequeue_signal_lock(current, &current->blocked, &info);
+		if (!sig)
+			break;
+		if (sig != SIGUSR1) {
+			if (common->state < FSG_STATE_EXIT)
+				DBG(common, "Main thread exiting on signal\n");
+			raise_exception(common, FSG_STATE_EXIT);
+		}
+	}
+
+	/* Cancel all the pending transfers */
+	if (likely(common->fsg)) {
+		for (i = 0; i < fsg_num_buffers; ++i) {
+			bh = &common->buffhds[i];
+			if (bh->inreq_busy)
+				usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
+			if (bh->outreq_busy)
+				usb_ep_dequeue(common->fsg->bulk_out,
+					       bh->outreq);
+		}
+
+		/* Wait until everything is idle */
+		for (;;) {
+			int num_active = 0;
+			for (i = 0; i < fsg_num_buffers; ++i) {
+				bh = &common->buffhds[i];
+				num_active += bh->inreq_busy + bh->outreq_busy;
+			}
+			if (num_active == 0)
+				break;
+			if (sleep_thread(common))
+				return;
+		}
+
+		/* Clear out the controller's fifos */
+		if (common->fsg->bulk_in_enabled)
+			usb_ep_fifo_flush(common->fsg->bulk_in);
+		if (common->fsg->bulk_out_enabled)
+			usb_ep_fifo_flush(common->fsg->bulk_out);
+	}
+
+	/*
+	 * Reset the I/O buffer states and pointers, the SCSI
+	 * state, and the exception.  Then invoke the handler.
+	 */
+	spin_lock_irq(&common->lock);
+
+	for (i = 0; i < fsg_num_buffers; ++i) {
+		bh = &common->buffhds[i];
+		bh->state = BUF_STATE_EMPTY;
+	}
+	common->next_buffhd_to_fill = &common->buffhds[0];
+	common->next_buffhd_to_drain = &common->buffhds[0];
+	exception_req_tag = common->exception_req_tag;
+	old_state = common->state;
+
+	if (old_state == FSG_STATE_ABORT_BULK_OUT)
+		common->state = FSG_STATE_STATUS_PHASE;
+	else {
+		for (i = 0; i < common->nluns; ++i) {
+			curlun = &common->luns[i];
+			curlun->prevent_medium_removal = 0;
+			curlun->sense_data = SS_NO_SENSE;
+			curlun->unit_attention_data = SS_NO_SENSE;
+			curlun->sense_data_info = 0;
+			curlun->info_valid = 0;
+		}
+		common->state = FSG_STATE_IDLE;
+	}
+	spin_unlock_irq(&common->lock);
+
+	/* Carry out any extra actions required for the exception */
+	switch (old_state) {
+	case FSG_STATE_ABORT_BULK_OUT:
+		send_status(common);
+		spin_lock_irq(&common->lock);
+		if (common->state == FSG_STATE_STATUS_PHASE)
+			common->state = FSG_STATE_IDLE;
+		spin_unlock_irq(&common->lock);
+		break;
+
+	case FSG_STATE_RESET:
+		/*
+		 * In case we were forced against our will to halt a
+		 * bulk endpoint, clear the halt now.  (The SuperH UDC
+		 * requires this.)
+		 */
+		if (!fsg_is_set(common))
+			break;
+		if (test_and_clear_bit(IGNORE_BULK_OUT,
+				       &common->fsg->atomic_bitflags))
+			usb_ep_clear_halt(common->fsg->bulk_in);
+
+		if (common->ep0_req_tag == exception_req_tag)
+			ep0_queue(common);	/* Complete the status stage */
+
+		/*
+		 * Technically this should go here, but it would only be
+		 * a waste of time.  Ditto for the INTERFACE_CHANGE and
+		 * CONFIG_CHANGE cases.
+		 */
+		/* for (i = 0; i < common->nluns; ++i) */
+		/*	common->luns[i].unit_attention_data = */
+		/*		SS_RESET_OCCURRED;  */
+		break;
+
+	case FSG_STATE_CONFIG_CHANGE:
+		do_set_interface(common, common->new_fsg);
+		if (common->new_fsg)
+			usb_composite_setup_continue(common->cdev);
+		break;
+
+	case FSG_STATE_EXIT:
+	case FSG_STATE_TERMINATED:
+		do_set_interface(common, NULL);		/* Free resources */
+		spin_lock_irq(&common->lock);
+		common->state = FSG_STATE_TERMINATED;	/* Stop the thread */
+		spin_unlock_irq(&common->lock);
+		break;
+
+	case FSG_STATE_INTERFACE_CHANGE:
+	case FSG_STATE_DISCONNECT:
+	case FSG_STATE_COMMAND_PHASE:
+	case FSG_STATE_DATA_PHASE:
+	case FSG_STATE_STATUS_PHASE:
+	case FSG_STATE_IDLE:
+		break;
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_main_thread(void *common_)
+{
+	struct fsg_common	*common = common_;
+
+	/*
+	 * Allow the thread to be killed by a signal, but set the signal mask
+	 * to block everything but INT, TERM, KILL, and USR1.
+	 */
+	allow_signal(SIGINT);
+	allow_signal(SIGTERM);
+	allow_signal(SIGKILL);
+	allow_signal(SIGUSR1);
+
+	/* Allow the thread to be frozen */
+	set_freezable();
+
+	/*
+	 * Arrange for userspace references to be interpreted as kernel
+	 * pointers.  That way we can pass a kernel pointer to a routine
+	 * that expects a __user pointer and it will work okay.
+	 */
+	set_fs(get_ds());
+
+	/* The main loop */
+	while (common->state != FSG_STATE_TERMINATED) {
+		if (exception_in_progress(common) || signal_pending(current)) {
+			handle_exception(common);
+			continue;
+		}
+
+		if (!common->running) {
+			sleep_thread(common);
+			continue;
+		}
+
+		if (get_next_command(common))
+			continue;
+
+		spin_lock_irq(&common->lock);
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_DATA_PHASE;
+		spin_unlock_irq(&common->lock);
+
+		if (do_scsi_command(common) || finish_reply(common))
+			continue;
+
+		spin_lock_irq(&common->lock);
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_STATUS_PHASE;
+		spin_unlock_irq(&common->lock);
+
+		if (send_status(common))
+			continue;
+
+		spin_lock_irq(&common->lock);
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_IDLE;
+		spin_unlock_irq(&common->lock);
+	}
+
+	spin_lock_irq(&common->lock);
+	common->thread_task = NULL;
+	spin_unlock_irq(&common->lock);
+
+	if (!common->ops || !common->ops->thread_exits
+	 || common->ops->thread_exits(common) < 0) {
+		struct fsg_lun *curlun = common->luns;
+		unsigned i = common->nluns;
+
+		down_write(&common->filesem);
+		for (; i--; ++curlun) {
+			if (!fsg_lun_is_open(curlun))
+				continue;
+
+			fsg_lun_close(curlun);
+			curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+		}
+		up_write(&common->filesem);
+	}
+
+	/* Let fsg_unbind() know the thread has exited */
+	complete_and_exit(&common->thread_notifier, 0);
+}
+
+
+/*************************** DEVICE ATTRIBUTES ***************************/
+
+static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
+static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
+static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+
+static struct device_attribute dev_attr_ro_cdrom =
+	__ATTR(ro, 0444, fsg_show_ro, NULL);
+static struct device_attribute dev_attr_file_nonremovable =
+	__ATTR(file, 0444, fsg_show_file, NULL);
+
+
+/****************************** FSG COMMON ******************************/
+
+static void fsg_common_release(struct kref *ref);
+
+static void fsg_lun_release(struct device *dev)
+{
+	/* Nothing needs to be done */
+}
+
+static inline void fsg_common_get(struct fsg_common *common)
+{
+	kref_get(&common->ref);
+}
+
+static inline void fsg_common_put(struct fsg_common *common)
+{
+	kref_put(&common->ref, fsg_common_release);
+}
+
+static struct fsg_common *fsg_common_init(struct fsg_common *common,
+					  struct usb_composite_dev *cdev,
+					  struct fsg_config *cfg)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	struct fsg_buffhd *bh;
+	struct fsg_lun *curlun;
+	struct fsg_lun_config *lcfg;
+	int nluns, i, rc;
+	char *pathbuf;
+
+	rc = fsg_num_buffers_validate();
+	if (rc != 0)
+		return ERR_PTR(rc);
+
+	/* Find out how many LUNs there should be */
+	nluns = cfg->nluns;
+	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Allocate? */
+	if (!common) {
+		common = kzalloc(sizeof *common, GFP_KERNEL);
+		if (!common)
+			return ERR_PTR(-ENOMEM);
+		common->free_storage_on_release = 1;
+	} else {
+		memset(common, 0, sizeof *common);
+		common->free_storage_on_release = 0;
+	}
+
+	common->buffhds = kcalloc(fsg_num_buffers,
+				  sizeof *(common->buffhds), GFP_KERNEL);
+	if (!common->buffhds) {
+		if (common->free_storage_on_release)
+			kfree(common);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	common->ops = cfg->ops;
+	common->private_data = cfg->private_data;
+
+	common->gadget = gadget;
+	common->ep0 = gadget->ep0;
+	common->ep0req = cdev->req;
+	common->cdev = cdev;
+
+	/* Maybe allocate device-global string IDs, and patch descriptors */
+	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+		rc = usb_string_id(cdev);
+		if (unlikely(rc < 0))
+			goto error_release;
+		fsg_strings[FSG_STRING_INTERFACE].id = rc;
+		fsg_intf_desc.iInterface = rc;
+	}
+
+	/*
+	 * Create the LUNs, open their backing files, and register the
+	 * LUN devices in sysfs.
+	 */
+	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+	if (unlikely(!curlun)) {
+		rc = -ENOMEM;
+		goto error_release;
+	}
+	common->luns = curlun;
+
+	init_rwsem(&common->filesem);
+
+	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
+		curlun->cdrom = !!lcfg->cdrom;
+		curlun->ro = lcfg->cdrom || lcfg->ro;
+		curlun->initially_ro = curlun->ro;
+		curlun->removable = lcfg->removable;
+		curlun->dev.release = fsg_lun_release;
+		curlun->dev.parent = &gadget->dev;
+		/* curlun->dev.driver = &fsg_driver.driver; XXX */
+		dev_set_drvdata(&curlun->dev, &common->filesem);
+		dev_set_name(&curlun->dev, "lun%d", i);
+
+		rc = device_register(&curlun->dev);
+		if (rc) {
+			INFO(common, "failed to register LUN%d: %d\n", i, rc);
+			common->nluns = i;
+			put_device(&curlun->dev);
+			goto error_release;
+		}
+
+		rc = device_create_file(&curlun->dev,
+					curlun->cdrom
+				      ? &dev_attr_ro_cdrom
+				      : &dev_attr_ro);
+		if (rc)
+			goto error_luns;
+		rc = device_create_file(&curlun->dev,
+					curlun->removable
+				      ? &dev_attr_file
+				      : &dev_attr_file_nonremovable);
+		if (rc)
+			goto error_luns;
+		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
+		if (rc)
+			goto error_luns;
+
+		if (lcfg->filename) {
+			rc = fsg_lun_open(curlun, lcfg->filename);
+			if (rc)
+				goto error_luns;
+		} else if (!curlun->removable) {
+			ERROR(common, "no file given for LUN%d\n", i);
+			rc = -EINVAL;
+			goto error_luns;
+		}
+	}
+	common->nluns = nluns;
+
+	/* Data buffers cyclic list */
+	bh = common->buffhds;
+	i = fsg_num_buffers;
+	goto buffhds_first_it;
+	do {
+		bh->next = bh + 1;
+		++bh;
+buffhds_first_it:
+		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+		if (unlikely(!bh->buf)) {
+			rc = -ENOMEM;
+			goto error_release;
+		}
+	} while (--i);
+	bh->next = common->buffhds;
+
+	/* Prepare inquiryString */
+	if (cfg->release != 0xffff) {
+		i = cfg->release;
+	} else {
+		i = usb_gadget_controller_number(gadget);
+		if (i >= 0) {
+			i = 0x0300 + i;
+		} else {
+			WARNING(common, "controller '%s' not recognized\n",
+				gadget->name);
+			i = 0x0399;
+		}
+	}
+	snprintf(common->inquiry_string, sizeof common->inquiry_string,
+		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
+		 /* Assume product name dependent on the first LUN */
+		 cfg->product_name ?: (common->luns->cdrom
+				     ? "File-Stor Gadget"
+				     : "File-CD Gadget"),
+		 i);
+
+	/*
+	 * Some peripheral controllers are known not to be able to
+	 * halt bulk endpoints correctly.  If one of them is present,
+	 * disable stalls.
+	 */
+	common->can_stall = cfg->can_stall &&
+		!(gadget_is_at91(common->gadget));
+
+	spin_lock_init(&common->lock);
+	kref_init(&common->ref);
+
+	/* Tell the thread to start working */
+	common->thread_task =
+		kthread_create(fsg_main_thread, common, "file-storage");
+	if (IS_ERR(common->thread_task)) {
+		rc = PTR_ERR(common->thread_task);
+		goto error_release;
+	}
+	init_completion(&common->thread_notifier);
+	init_waitqueue_head(&common->fsg_wait);
+
+	/* Information */
+	INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+	INFO(common, "Number of LUNs=%d\n", common->nluns);
+
+	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+	for (i = 0, nluns = common->nluns, curlun = common->luns;
+	     i < nluns;
+	     ++curlun, ++i) {
+		char *p = "(no medium)";
+		if (fsg_lun_is_open(curlun)) {
+			p = "(error)";
+			if (pathbuf) {
+				p = d_path(&curlun->filp->f_path,
+					   pathbuf, PATH_MAX);
+				if (IS_ERR(p))
+					p = "(error)";
+			}
+		}
+		LINFO(curlun, "LUN: %s%s%sfile: %s\n",
+		      curlun->removable ? "removable " : "",
+		      curlun->ro ? "read only " : "",
+		      curlun->cdrom ? "CD-ROM " : "",
+		      p);
+	}
+	kfree(pathbuf);
+
+	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+
+	wake_up_process(common->thread_task);
+
+	return common;
+
+error_luns:
+	common->nluns = i + 1;
+error_release:
+	common->state = FSG_STATE_TERMINATED;	/* The thread is dead */
+	/* Call fsg_common_release() directly, ref might be not initialised. */
+	fsg_common_release(&common->ref);
+	return ERR_PTR(rc);
+}
+
+static void fsg_common_release(struct kref *ref)
+{
+	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+
+	/* If the thread isn't already dead, tell it to exit now */
+	if (common->state != FSG_STATE_TERMINATED) {
+		raise_exception(common, FSG_STATE_EXIT);
+		wait_for_completion(&common->thread_notifier);
+	}
+
+	if (likely(common->luns)) {
+		struct fsg_lun *lun = common->luns;
+		unsigned i = common->nluns;
+
+		/* In error recovery common->nluns may be zero. */
+		for (; i; --i, ++lun) {
+			device_remove_file(&lun->dev, &dev_attr_nofua);
+			device_remove_file(&lun->dev,
+					   lun->cdrom
+					 ? &dev_attr_ro_cdrom
+					 : &dev_attr_ro);
+			device_remove_file(&lun->dev,
+					   lun->removable
+					 ? &dev_attr_file
+					 : &dev_attr_file_nonremovable);
+			fsg_lun_close(lun);
+			device_unregister(&lun->dev);
+		}
+
+		kfree(common->luns);
+	}
+
+	{
+		struct fsg_buffhd *bh = common->buffhds;
+		unsigned i = fsg_num_buffers;
+		do {
+			kfree(bh->buf);
+		} while (++bh, --i);
+	}
+
+	kfree(common->buffhds);
+	if (common->free_storage_on_release)
+		kfree(common);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+	struct fsg_common	*common = fsg->common;
+
+	DBG(fsg, "unbind\n");
+	if (fsg->common->fsg == fsg) {
+		fsg->common->new_fsg = NULL;
+		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+		/* FIXME: make interruptible or killable somehow? */
+		wait_event(common->fsg_wait, common->fsg != fsg);
+	}
+
+	fsg_common_put(common);
+	usb_free_descriptors(fsg->function.descriptors);
+	usb_free_descriptors(fsg->function.hs_descriptors);
+	usb_free_descriptors(fsg->function.ss_descriptors);
+	kfree(fsg);
+}
+
+static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+	struct usb_gadget	*gadget = c->cdev->gadget;
+	int			i;
+	struct usb_ep		*ep;
+
+	fsg->gadget = gadget;
+
+	/* New interface */
+	i = usb_interface_id(c, f);
+	if (i < 0)
+		return i;
+	fsg_intf_desc.bInterfaceNumber = i;
+	fsg->interface_number = i;
+
+	/* Find all the endpoints we will use */
+	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+	if (!ep)
+		goto autoconf_fail;
+	ep->driver_data = fsg->common;	/* claim the endpoint */
+	fsg->bulk_in = ep;
+
+	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
+	if (!ep)
+		goto autoconf_fail;
+	ep->driver_data = fsg->common;	/* claim the endpoint */
+	fsg->bulk_out = ep;
+
+	/* Copy descriptors */
+	f->descriptors = usb_copy_descriptors(fsg_fs_function);
+	if (unlikely(!f->descriptors))
+		return -ENOMEM;
+
+	if (gadget_is_dualspeed(gadget)) {
+		/* Assume endpoint addresses are the same for both speeds */
+		fsg_hs_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_hs_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
+		if (unlikely(!f->hs_descriptors)) {
+			usb_free_descriptors(f->descriptors);
+			return -ENOMEM;
+		}
+	}
+
+	if (gadget_is_superspeed(gadget)) {
+		unsigned	max_burst;
+
+		/* Calculate bMaxBurst, we know packet size is 1024 */
+		max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+		fsg_ss_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+		fsg_ss_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+		f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+		if (unlikely(!f->ss_descriptors)) {
+			usb_free_descriptors(f->hs_descriptors);
+			usb_free_descriptors(f->descriptors);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+
+autoconf_fail:
+	ERROR(fsg, "unable to autoconfigure all endpoints\n");
+	return -ENOTSUPP;
+}
+
+
+/****************************** ADD FUNCTION ******************************/
+
+static struct usb_gadget_strings *fsg_strings_array[] = {
+	&fsg_stringtab,
+	NULL,
+};
+
+static int fsg_bind_config(struct usb_composite_dev *cdev,
+			   struct usb_configuration *c,
+			   struct fsg_common *common)
+{
+	struct fsg_dev *fsg;
+	int rc;
+
+	fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+	if (unlikely(!fsg))
+		return -ENOMEM;
+
+	fsg->function.name        = FSG_DRIVER_DESC;
+	fsg->function.strings     = fsg_strings_array;
+	fsg->function.bind        = fsg_bind;
+	fsg->function.unbind      = fsg_unbind;
+	fsg->function.setup       = fsg_setup;
+	fsg->function.set_alt     = fsg_set_alt;
+	fsg->function.disable     = fsg_disable;
+
+	fsg->common               = common;
+	/*
+	 * Our caller holds a reference to common structure so we
+	 * don't have to be worry about it being freed until we return
+	 * from this function.  So instead of incrementing counter now
+	 * and decrement in error recovery we increment it only when
+	 * call to usb_add_function() was successful.
+	 */
+
+	rc = usb_add_function(c, &fsg->function);
+	if (unlikely(rc))
+		kfree(fsg);
+	else
+		fsg_common_get(fsg->common);
+	return rc;
+}
+
+
+/************************* Module parameters *************************/
+
+struct fsg_module_parameters {
+	char		*file[FSG_MAX_LUNS];
+	bool		ro[FSG_MAX_LUNS];
+	bool		removable[FSG_MAX_LUNS];
+	bool		cdrom[FSG_MAX_LUNS];
+	bool		nofua[FSG_MAX_LUNS];
+
+	unsigned int	file_count, ro_count, removable_count, cdrom_count;
+	unsigned int	nofua_count;
+	unsigned int	luns;	/* nluns */
+	bool		stall;	/* can_stall */
+};
+
+#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\
+	module_param_array_named(prefix ## name, params.name, type,	\
+				 &prefix ## params.name ## _count,	\
+				 S_IRUGO);				\
+	MODULE_PARM_DESC(prefix ## name, desc)
+
+#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\
+	module_param_named(prefix ## name, params.name, type,		\
+			   S_IRUGO);					\
+	MODULE_PARM_DESC(prefix ## name, desc)
+
+#define FSG_MODULE_PARAMETERS(prefix, params)				\
+	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\
+				"names of backing files or devices");	\
+	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\
+				"true to force read-only");		\
+	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\
+				"true to simulate removable media");	\
+	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\
+				"true to simulate CD-ROM instead of disk"); \
+	_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,		\
+				"true to ignore SCSI WRITE(10,12) FUA bit"); \
+	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\
+			  "number of LUNs");				\
+	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\
+			  "false to prevent bulk stalls")
+
+static void
+fsg_config_from_params(struct fsg_config *cfg,
+		       const struct fsg_module_parameters *params)
+{
+	struct fsg_lun_config *lun;
+	unsigned i;
+
+	/* Configure LUNs */
+	cfg->nluns =
+		min(params->luns ?: (params->file_count ?: 1u),
+		    (unsigned)FSG_MAX_LUNS);
+	for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
+		lun->ro = !!params->ro[i];
+		lun->cdrom = !!params->cdrom[i];
+		lun->removable = !!params->removable[i];
+		lun->filename =
+			params->file_count > i && params->file[i][0]
+			? params->file[i]
+			: 0;
+	}
+
+	/* Let MSF use defaults */
+	cfg->vendor_name = 0;
+	cfg->product_name = 0;
+	cfg->release = 0xffff;
+
+	cfg->ops = NULL;
+	cfg->private_data = NULL;
+
+	/* Finalise */
+	cfg->can_stall = params->stall;
+}
+
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+		       struct usb_composite_dev *cdev,
+		       const struct fsg_module_parameters *params)
+	__attribute__((unused));
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+		       struct usb_composite_dev *cdev,
+		       const struct fsg_module_parameters *params)
+{
+	struct fsg_config cfg;
+	fsg_config_from_params(&cfg, params);
+	return fsg_common_init(common, cdev, &cfg);
+}
diff --git a/drivers/staging/ccg/f_rndis.c b/drivers/staging/ccg/f_rndis.c
new file mode 100644
index 0000000..b1681e4
--- /dev/null
+++ b/drivers/staging/ccg/f_rndis.c
@@ -0,0 +1,918 @@
+/*
+ * f_rndis.c -- RNDIS link function driver
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz (mina86@mina86.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.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+
+#include <linux/atomic.h>
+
+#include "u_ether.h"
+#include "rndis.h"
+
+
+/*
+ * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
+ * been promoted instead of the standard CDC Ethernet.  The published RNDIS
+ * spec is ambiguous, incomplete, and needlessly complex.  Variants such as
+ * ActiveSync have even worse status in terms of specification.
+ *
+ * In short:  it's a protocol controlled by (and for) Microsoft, not for an
+ * Open ecosystem or markets.  Linux supports it *only* because Microsoft
+ * doesn't support the CDC Ethernet standard.
+ *
+ * The RNDIS data transfer model is complex, with multiple Ethernet packets
+ * per USB message, and out of band data.  The control model is built around
+ * what's essentially an "RNDIS RPC" protocol.  It's all wrapped in a CDC ACM
+ * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
+ * useless (they're ignored).  RNDIS expects to be the only function in its
+ * configuration, so it's no real help if you need composite devices; and
+ * it expects to be the first configuration too.
+ *
+ * There is a single technical advantage of RNDIS over CDC Ethernet, if you
+ * discount the fluff that its RPC can be made to deliver: it doesn't need
+ * a NOP altsetting for the data interface.  That lets it work on some of the
+ * "so smart it's stupid" hardware which takes over configuration changes
+ * from the software, and adds restrictions like "no altsettings".
+ *
+ * Unfortunately MSFT's RNDIS drivers are buggy.  They hang or oops, and
+ * have all sorts of contrary-to-specification oddities that can prevent
+ * them from working sanely.  Since bugfixes (or accurate specs, letting
+ * Linux work around those bugs) are unlikely to ever come from MSFT, you
+ * may want to avoid using RNDIS on purely operational grounds.
+ *
+ * Omissions from the RNDIS 1.0 specification include:
+ *
+ *   - Power management ... references data that's scattered around lots
+ *     of other documentation, which is incorrect/incomplete there too.
+ *
+ *   - There are various undocumented protocol requirements, like the need
+ *     to send garbage in some control-OUT messages.
+ *
+ *   - MS-Windows drivers sometimes emit undocumented requests.
+ */
+
+struct f_rndis {
+	struct gether			port;
+	u8				ctrl_id, data_id;
+	u8				ethaddr[ETH_ALEN];
+	u32				vendorID;
+	const char			*manufacturer;
+	int				config;
+
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+	atomic_t			notify_count;
+};
+
+static inline struct f_rndis *func_to_rndis(struct usb_function *f)
+{
+	return container_of(f, struct f_rndis, port.func);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static unsigned int bitrate(struct usb_gadget *g)
+{
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return 13 * 1024 * 8 * 1000 * 8;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return 13 * 512 * 8 * 1000 * 8;
+	else
+		return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
+#define STATUS_BYTECOUNT		8	/* 8 bytes data */
+
+
+/* interface descriptor: */
+
+static struct usb_interface_descriptor rndis_control_intf = {
+	.bLength =		sizeof rndis_control_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	/* status endpoint is optional; this could be patched later */
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+	.bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc header_desc = {
+	.bLength =		sizeof header_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
+	.bLength =		sizeof call_mgmt_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+
+	.bmCapabilities =	0x00,
+	.bDataInterface =	0x01,
+};
+
+static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
+	.bLength =		sizeof rndis_acm_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+
+	.bmCapabilities =	0x00,
+};
+
+static struct usb_cdc_union_desc rndis_union_desc = {
+	.bLength =		sizeof(rndis_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
+/* the data interface has two bulk endpoints */
+
+static struct usb_interface_descriptor rndis_data_intf = {
+	.bLength =		sizeof rndis_data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	/* .iInterface = DYNAMIC */
+};
+
+
+static struct usb_interface_assoc_descriptor
+rndis_iad_descriptor = {
+	.bLength =		sizeof rndis_iad_descriptor,
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+
+	.bFirstInterface =	0, /* XXX, hardcoded */
+	.bInterfaceCount = 	2,	// control + data
+	.bFunctionClass =	USB_CLASS_COMM,
+	.bFunctionSubClass =	USB_CDC_SUBCLASS_ETHERNET,
+	.bFunctionProtocol =	USB_CDC_PROTO_NONE,
+	/* .iFunction = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor fs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor fs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *eth_fs_function[] = {
+	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_union_desc,
+	(struct usb_descriptor_header *) &fs_notify_desc,
+
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &fs_in_desc,
+	(struct usb_descriptor_header *) &fs_out_desc,
+	NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor hs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_endpoint_descriptor hs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *eth_hs_function[] = {
+	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_union_desc,
+	(struct usb_descriptor_header *) &hs_notify_desc,
+
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &hs_in_desc,
+	(struct usb_descriptor_header *) &hs_out_desc,
+	NULL,
+};
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
+	.bLength =		sizeof ss_intr_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+	.bLength =		sizeof ss_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *eth_ss_function[] = {
+	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_union_desc,
+	(struct usb_descriptor_header *) &ss_notify_desc,
+	(struct usb_descriptor_header *) &ss_intr_comp_desc,
+
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &ss_in_desc,
+	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &ss_out_desc,
+	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
+	NULL,
+};
+
+/* string descriptors: */
+
+static struct usb_string rndis_string_defs[] = {
+	[0].s = "RNDIS Communications Control",
+	[1].s = "RNDIS Ethernet Data",
+	[2].s = "RNDIS",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings rndis_string_table = {
+	.language =		0x0409,	/* en-us */
+	.strings =		rndis_string_defs,
+};
+
+static struct usb_gadget_strings *rndis_strings[] = {
+	&rndis_string_table,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct sk_buff *rndis_add_header(struct gether *port,
+					struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+
+	skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
+	if (skb2)
+		rndis_add_hdr(skb2);
+
+	dev_kfree_skb_any(skb);
+	return skb2;
+}
+
+static void rndis_response_available(void *_rndis)
+{
+	struct f_rndis			*rndis = _rndis;
+	struct usb_request		*req = rndis->notify_req;
+	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
+	__le32				*data = req->buf;
+	int				status;
+
+	if (atomic_inc_return(&rndis->notify_count) != 1)
+		return;
+
+	/* Send RNDIS RESPONSE_AVAILABLE notification; a
+	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
+	 *
+	 * This is the only notification defined by RNDIS.
+	 */
+	data[0] = cpu_to_le32(1);
+	data[1] = cpu_to_le32(0);
+
+	status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+	if (status) {
+		atomic_dec(&rndis->notify_count);
+		DBG(cdev, "notify/0 --> %d\n", status);
+	}
+}
+
+static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_rndis			*rndis = req->context;
+	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
+	int				status = req->status;
+
+	/* after TX:
+	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
+	 *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
+	 */
+	switch (status) {
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		atomic_set(&rndis->notify_count, 0);
+		break;
+	default:
+		DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
+			ep->name, status,
+			req->actual, req->length);
+		/* FALLTHROUGH */
+	case 0:
+		if (ep != rndis->notify)
+			break;
+
+		/* handle multiple pending RNDIS_RESPONSE_AVAILABLE
+		 * notifications by resending until we're done
+		 */
+		if (atomic_dec_and_test(&rndis->notify_count))
+			break;
+		status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+		if (status) {
+			atomic_dec(&rndis->notify_count);
+			DBG(cdev, "notify/1 --> %d\n", status);
+		}
+		break;
+	}
+}
+
+static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_rndis			*rndis = req->context;
+	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
+	int				status;
+
+	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+//	spin_lock(&dev->lock);
+	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
+	if (status < 0)
+		ERROR(cdev, "RNDIS command error %d, %d/%d\n",
+			status, req->actual, req->length);
+//	spin_unlock(&dev->lock);
+}
+
+static int
+rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_rndis		*rndis = func_to_rndis(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request	*req = cdev->req;
+	int			value = -EOPNOTSUPP;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
+
+	/* composite driver infrastructure handles everything except
+	 * CDC class messages; interface activation uses set_alt().
+	 */
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+	/* RNDIS uses the CDC command encapsulation mechanism to implement
+	 * an RPC scheme, with much getting/setting of attributes by OID.
+	 */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
+		if (w_value || w_index != rndis->ctrl_id)
+			goto invalid;
+		/* read the request; process it later */
+		value = w_length;
+		req->complete = rndis_command_complete;
+		req->context = rndis;
+		/* later, rndis_response_available() sends a notification */
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_GET_ENCAPSULATED_RESPONSE:
+		if (w_value || w_index != rndis->ctrl_id)
+			goto invalid;
+		else {
+			u8 *buf;
+			u32 n;
+
+			/* return the result */
+			buf = rndis_get_next_response(rndis->config, &n);
+			if (buf) {
+				memcpy(req->buf, buf, n);
+				req->complete = rndis_response_complete;
+				req->context = rndis;
+				rndis_free_response(rndis->config, buf);
+				value = n;
+			}
+			/* else stalls ... spec says to avoid that */
+		}
+		break;
+
+	default:
+invalid:
+		VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* respond with data transfer or status phase? */
+	if (value >= 0) {
+		DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = (value < w_length);
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0)
+			ERROR(cdev, "rndis response on err %d\n", value);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+
+static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_rndis		*rndis = func_to_rndis(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	/* we know alt == 0 */
+
+	if (intf == rndis->ctrl_id) {
+		if (rndis->notify->driver_data) {
+			VDBG(cdev, "reset rndis control %d\n", intf);
+			usb_ep_disable(rndis->notify);
+		}
+		if (!rndis->notify->desc) {
+			VDBG(cdev, "init rndis ctrl %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
+		}
+		usb_ep_enable(rndis->notify);
+		rndis->notify->driver_data = rndis;
+
+	} else if (intf == rndis->data_id) {
+		struct net_device	*net;
+
+		if (rndis->port.in_ep->driver_data) {
+			DBG(cdev, "reset rndis\n");
+			gether_disconnect(&rndis->port);
+		}
+
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
+			DBG(cdev, "init rndis\n");
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
+		}
+
+		/* Avoid ZLPs; they can be troublesome. */
+		rndis->port.is_zlp_ok = false;
+
+		/* RNDIS should be in the "RNDIS uninitialized" state,
+		 * either never activated or after rndis_uninit().
+		 *
+		 * We don't want data to flow here until a nonzero packet
+		 * filter is set, at which point it enters "RNDIS data
+		 * initialized" state ... but we do want the endpoints
+		 * to be activated.  It's a strange little state.
+		 *
+		 * REVISIT the RNDIS gadget code has done this wrong for a
+		 * very long time.  We need another call to the link layer
+		 * code -- gether_updown(...bool) maybe -- to do it right.
+		 */
+		rndis->port.cdc_filter = 0;
+
+		DBG(cdev, "RNDIS RX/TX early activation ... \n");
+		net = gether_connect(&rndis->port);
+		if (IS_ERR(net))
+			return PTR_ERR(net);
+
+		rndis_set_param_dev(rndis->config, net,
+				&rndis->port.cdc_filter);
+	} else
+		goto fail;
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static void rndis_disable(struct usb_function *f)
+{
+	struct f_rndis		*rndis = func_to_rndis(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	if (!rndis->notify->driver_data)
+		return;
+
+	DBG(cdev, "rndis deactivated\n");
+
+	rndis_uninit(rndis->config);
+	gether_disconnect(&rndis->port);
+
+	usb_ep_disable(rndis->notify);
+	rndis->notify->driver_data = NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This isn't quite the same mechanism as CDC Ethernet, since the
+ * notification scheme passes less data, but the same set of link
+ * states must be tested.  A key difference is that altsettings are
+ * not used to tell whether the link should send packets or not.
+ */
+
+static void rndis_open(struct gether *geth)
+{
+	struct f_rndis		*rndis = func_to_rndis(&geth->func);
+	struct usb_composite_dev *cdev = geth->func.config->cdev;
+
+	DBG(cdev, "%s\n", __func__);
+
+	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
+				bitrate(cdev->gadget) / 100);
+	rndis_signal_connect(rndis->config);
+}
+
+static void rndis_close(struct gether *geth)
+{
+	struct f_rndis		*rndis = func_to_rndis(&geth->func);
+
+	DBG(geth->func.config->cdev, "%s\n", __func__);
+
+	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
+	rndis_signal_disconnect(rndis->config);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethernet function driver setup/binding */
+
+static int
+rndis_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_rndis		*rndis = func_to_rndis(f);
+	int			status;
+	struct usb_ep		*ep;
+
+	/* allocate instance-specific interface IDs */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	rndis->ctrl_id = status;
+	rndis_iad_descriptor.bFirstInterface = status;
+
+	rndis_control_intf.bInterfaceNumber = status;
+	rndis_union_desc.bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	rndis->data_id = status;
+
+	rndis_data_intf.bInterfaceNumber = status;
+	rndis_union_desc.bSlaveInterface0 = status;
+
+	status = -ENODEV;
+
+	/* allocate instance-specific endpoints */
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
+	if (!ep)
+		goto fail;
+	rndis->port.in_ep = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
+	if (!ep)
+		goto fail;
+	rndis->port.out_ep = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	/* NOTE:  a status/notification endpoint is, strictly speaking,
+	 * optional.  We don't treat it that way though!  It's simpler,
+	 * and some newer profiles don't treat it as optional.
+	 */
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
+	if (!ep)
+		goto fail;
+	rndis->notify = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	status = -ENOMEM;
+
+	/* allocate notification request and buffer */
+	rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
+	if (!rndis->notify_req)
+		goto fail;
+	rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
+	if (!rndis->notify_req->buf)
+		goto fail;
+	rndis->notify_req->length = STATUS_BYTECOUNT;
+	rndis->notify_req->context = rndis;
+	rndis->notify_req->complete = rndis_response_complete;
+
+	/* copy descriptors, and track endpoint copies */
+	f->descriptors = usb_copy_descriptors(eth_fs_function);
+	if (!f->descriptors)
+		goto fail;
+
+	/* support all relevant hardware speeds... we expect that when
+	 * hardware is dual speed, all bulk-capable endpoints work at
+	 * both speeds
+	 */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		hs_in_desc.bEndpointAddress =
+				fs_in_desc.bEndpointAddress;
+		hs_out_desc.bEndpointAddress =
+				fs_out_desc.bEndpointAddress;
+		hs_notify_desc.bEndpointAddress =
+				fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
+		if (!f->hs_descriptors)
+			goto fail;
+	}
+
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_in_desc.bEndpointAddress =
+				fs_in_desc.bEndpointAddress;
+		ss_out_desc.bEndpointAddress =
+				fs_out_desc.bEndpointAddress;
+		ss_notify_desc.bEndpointAddress =
+				fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
+	}
+
+	rndis->port.open = rndis_open;
+	rndis->port.close = rndis_close;
+
+	status = rndis_register(rndis_response_available, rndis);
+	if (status < 0)
+		goto fail;
+	rndis->config = status;
+
+	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
+	rndis_set_host_mac(rndis->config, rndis->ethaddr);
+
+	if (rndis->manufacturer && rndis->vendorID &&
+			rndis_set_param_vendor(rndis->config, rndis->vendorID,
+					       rndis->manufacturer))
+		goto fail;
+
+	/* NOTE:  all that is done without knowing or caring about
+	 * the network link ... which is unavailable to this code
+	 * until we're activated via set_alt().
+	 */
+
+	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
+			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+			rndis->port.in_ep->name, rndis->port.out_ep->name,
+			rndis->notify->name);
+	return 0;
+
+fail:
+	if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+	if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+	if (f->descriptors)
+		usb_free_descriptors(f->descriptors);
+
+	if (rndis->notify_req) {
+		kfree(rndis->notify_req->buf);
+		usb_ep_free_request(rndis->notify, rndis->notify_req);
+	}
+
+	/* we might as well release our claims on endpoints */
+	if (rndis->notify)
+		rndis->notify->driver_data = NULL;
+	if (rndis->port.out_ep->desc)
+		rndis->port.out_ep->driver_data = NULL;
+	if (rndis->port.in_ep->desc)
+		rndis->port.in_ep->driver_data = NULL;
+
+	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+
+	return status;
+}
+
+static void
+rndis_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_rndis		*rndis = func_to_rndis(f);
+
+	rndis_deregister(rndis->config);
+	rndis_exit();
+	rndis_string_defs[0].id = 0;
+
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
+	if (gadget_is_dualspeed(c->cdev->gadget))
+		usb_free_descriptors(f->hs_descriptors);
+	usb_free_descriptors(f->descriptors);
+
+	kfree(rndis->notify_req->buf);
+	usb_ep_free_request(rndis->notify, rndis->notify_req);
+
+	kfree(rndis);
+}
+
+/* Some controllers can't support RNDIS ... */
+static inline bool can_support_rndis(struct usb_configuration *c)
+{
+	/* everything else is *presumably* fine */
+	return true;
+}
+
+int
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer)
+{
+	struct f_rndis	*rndis;
+	int		status;
+
+	if (!can_support_rndis(c) || !ethaddr)
+		return -EINVAL;
+
+	/* maybe allocate device-global string IDs */
+	if (rndis_string_defs[0].id == 0) {
+
+		/* ... and setup RNDIS itself */
+		status = rndis_init();
+		if (status < 0)
+			return status;
+
+		/* control interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_string_defs[0].id = status;
+		rndis_control_intf.iInterface = status;
+
+		/* data interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_string_defs[1].id = status;
+		rndis_data_intf.iInterface = status;
+
+		/* IAD iFunction label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_string_defs[2].id = status;
+		rndis_iad_descriptor.iFunction = status;
+	}
+
+	/* allocate and initialize one new instance */
+	status = -ENOMEM;
+	rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
+	if (!rndis)
+		goto fail;
+
+	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+	rndis->vendorID = vendorID;
+	rndis->manufacturer = manufacturer;
+
+	/* RNDIS activates when the host changes this filter */
+	rndis->port.cdc_filter = 0;
+
+	/* RNDIS has special (and complex) framing */
+	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
+	rndis->port.wrap = rndis_add_header;
+	rndis->port.unwrap = rndis_rm_hdr;
+
+	rndis->port.func.name = "rndis";
+	rndis->port.func.strings = rndis_strings;
+	/* descriptors are per-instance copies */
+	rndis->port.func.bind = rndis_bind;
+	rndis->port.func.unbind = rndis_unbind;
+	rndis->port.func.set_alt = rndis_set_alt;
+	rndis->port.func.setup = rndis_setup;
+	rndis->port.func.disable = rndis_disable;
+
+	status = usb_add_function(c, &rndis->port.func);
+	if (status) {
+		kfree(rndis);
+fail:
+		rndis_exit();
+	}
+	return status;
+}
diff --git a/drivers/staging/ccg/gadget_chips.h b/drivers/staging/ccg/gadget_chips.h
new file mode 100644
index 0000000..0ccca58
--- /dev/null
+++ b/drivers/staging/ccg/gadget_chips.h
@@ -0,0 +1,150 @@
+/*
+ * USB device controllers have lots of quirks.  Use these macros in
+ * gadget drivers or other code that needs to deal with them, and which
+ * autoconfigures instead of using early binding to the hardware.
+ *
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
+ * some config file that gets updated as new hardware is supported.
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
+ *
+ * NOTE:  some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
+ */
+
+#ifndef __GADGET_CHIPS_H
+#define __GADGET_CHIPS_H
+
+/*
+ * NOTICE: the entries below are alphabetical and should be kept
+ * that way.
+ *
+ * Always be sure to add new entries to the correct position or
+ * accept the bashing later.
+ *
+ * If you have forgotten the alphabetical order let VIM/EMACS
+ * do that for you.
+ */
+#define gadget_is_amd5536udc(g)		(!strcmp("amd5536udc", (g)->name))
+#define gadget_is_at91(g)		(!strcmp("at91_udc", (g)->name))
+#define gadget_is_atmel_usba(g)		(!strcmp("atmel_usba_udc", (g)->name))
+#define gadget_is_bcm63xx(g)		(!strcmp("bcm63xx_udc", (g)->name))
+#define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
+#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
+#define gadget_is_dummy(g)		(!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g)		(!strcmp("dwc3-gadget", (g)->name))
+#define gadget_is_fsl_qe(g)		(!strcmp("fsl_qe_udc", (g)->name))
+#define gadget_is_fsl_usb2(g)		(!strcmp("fsl-usb2-udc", (g)->name))
+#define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name))
+#define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name))
+#define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name))
+#define gadget_is_lpc32xx(g)		(!strcmp("lpc32xx_udc", (g)->name))
+#define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name))
+#define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name))
+#define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name))
+#define gadget_is_net2280(g)		(!strcmp("net2280", (g)->name))
+#define gadget_is_omap(g)		(!strcmp("omap_udc", (g)->name))
+#define gadget_is_pch(g)		(!strcmp("pch_udc", (g)->name))
+#define gadget_is_pxa(g)		(!strcmp("pxa25x_udc", (g)->name))
+#define gadget_is_pxa27x(g)		(!strcmp("pxa27x_udc", (g)->name))
+#define gadget_is_r8a66597(g)		(!strcmp("r8a66597_udc", (g)->name))
+#define gadget_is_renesas_usbhs(g)	(!strcmp("renesas_usbhs_udc", (g)->name))
+#define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name))
+#define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name))
+#define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))
+
+/**
+ * usb_gadget_controller_number - support bcdDevice id convention
+ * @gadget: the controller being driven
+ *
+ * Return a 2-digit BCD value associated with the peripheral controller,
+ * suitable for use as part of a bcdDevice value, or a negative error code.
+ *
+ * NOTE:  this convention is purely optional, and has no meaning in terms of
+ * any USB specification.  If you want to use a different convention in your
+ * gadget driver firmware -- maybe a more formal revision ID -- feel free.
+ *
+ * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
+ * to change their behavior accordingly.  For example it might help avoiding
+ * some chip bug.
+ */
+static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+{
+	if (gadget_is_net2280(gadget))
+		return 0x01;
+	else if (gadget_is_dummy(gadget))
+		return 0x02;
+	else if (gadget_is_pxa(gadget))
+		return 0x03;
+	else if (gadget_is_goku(gadget))
+		return 0x06;
+	else if (gadget_is_omap(gadget))
+		return 0x08;
+	else if (gadget_is_pxa27x(gadget))
+		return 0x11;
+	else if (gadget_is_s3c2410(gadget))
+		return 0x12;
+	else if (gadget_is_at91(gadget))
+		return 0x13;
+	else if (gadget_is_imx(gadget))
+		return 0x14;
+	else if (gadget_is_musbhdrc(gadget))
+		return 0x16;
+	else if (gadget_is_atmel_usba(gadget))
+		return 0x18;
+	else if (gadget_is_fsl_usb2(gadget))
+		return 0x19;
+	else if (gadget_is_amd5536udc(gadget))
+		return 0x20;
+	else if (gadget_is_m66592(gadget))
+		return 0x21;
+	else if (gadget_is_fsl_qe(gadget))
+		return 0x22;
+	else if (gadget_is_ci13xxx_pci(gadget))
+		return 0x23;
+	else if (gadget_is_langwell(gadget))
+		return 0x24;
+	else if (gadget_is_r8a66597(gadget))
+		return 0x25;
+	else if (gadget_is_s3c_hsotg(gadget))
+		return 0x26;
+	else if (gadget_is_pch(gadget))
+		return 0x27;
+	else if (gadget_is_ci13xxx_msm(gadget))
+		return 0x28;
+	else if (gadget_is_renesas_usbhs(gadget))
+		return 0x29;
+	else if (gadget_is_s3c_hsudc(gadget))
+		return 0x30;
+	else if (gadget_is_net2272(gadget))
+		return 0x31;
+	else if (gadget_is_dwc3(gadget))
+		return 0x32;
+	else if (gadget_is_lpc32xx(gadget))
+		return 0x33;
+	else if (gadget_is_bcm63xx(gadget))
+		return 0x34;
+
+	return -ENOENT;
+}
+
+
+/**
+ * gadget_supports_altsettings - return true if altsettings work
+ * @gadget: the gadget in question
+ */
+static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
+{
+	/* PXA 21x/25x/26x has no altsettings at all */
+	if (gadget_is_pxa(gadget))
+		return false;
+
+	/* PXA 27x and 3xx have *broken* altsetting support */
+	if (gadget_is_pxa27x(gadget))
+		return false;
+
+	/* Everything else is *presumably* fine ... */
+	return true;
+}
+
+#endif /* __GADGET_CHIPS_H */
diff --git a/drivers/staging/ccg/ndis.h b/drivers/staging/ccg/ndis.h
new file mode 100644
index 0000000..a19f72d
--- /dev/null
+++ b/drivers/staging/ccg/ndis.h
@@ -0,0 +1,47 @@
+/*
+ * ndis.h
+ *
+ * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+ *
+ * Thanks to the cygwin development team,
+ * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ */
+
+#ifndef _LINUX_NDIS_H
+#define _LINUX_NDIS_H
+
+enum NDIS_DEVICE_POWER_STATE {
+	NdisDeviceStateUnspecified = 0,
+	NdisDeviceStateD0,
+	NdisDeviceStateD1,
+	NdisDeviceStateD2,
+	NdisDeviceStateD3,
+	NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+	enum NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
+};
+
+struct NDIS_PNP_CAPABILITIES {
+	__le32					Flags;
+	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
+};
+
+#endif /* _LINUX_NDIS_H */
diff --git a/drivers/staging/ccg/rndis.c b/drivers/staging/ccg/rndis.c
new file mode 100644
index 0000000..e4192b8
--- /dev/null
+++ b/drivers/staging/ccg/rndis.c
@@ -0,0 +1,1175 @@
+/*
+ * RNDIS MSG parser
+ *
+ * Authors:	Benedikt Spranger, Pengutronix
+ *		Robert Schwebel, Pengutronix
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              version 2, as published by the Free Software Foundation.
+ *
+ *		This software was originally developed in conformance with
+ *		Microsoft's Remote NDIS Specification License Agreement.
+ *
+ * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *		Fixed message length bug in init_response
+ *
+ * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *		Fixed rndis_rm_hdr length bug.
+ *
+ * Copyright (C) 2004 by David Brownell
+ *		updates to merge with Linux 2.6, better match RNDIS spec
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/netdevice.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+
+#undef	VERBOSE_DEBUG
+
+#include "rndis.h"
+
+
+/* The driver for your USB chip needs to support ep0 OUT to work with
+ * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
+ *
+ * Windows hosts need an INF file like Documentation/usb/linux.inf
+ * and will be happier if you provide the host_addr module parameter.
+ */
+
+#if 0
+static int rndis_debug = 0;
+module_param (rndis_debug, int, 0);
+MODULE_PARM_DESC (rndis_debug, "enable debugging");
+#else
+#define rndis_debug		0
+#endif
+
+#define RNDIS_MAX_CONFIGS	1
+
+
+static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+
+/* Driver Version */
+static const __le32 rndis_driver_version = cpu_to_le32(1);
+
+/* Function Prototypes */
+static rndis_resp_t *rndis_add_response(int configNr, u32 length);
+
+
+/* supported OIDs */
+static const u32 oid_supported_list[] =
+{
+	/* the general stuff */
+	RNDIS_OID_GEN_SUPPORTED_LIST,
+	RNDIS_OID_GEN_HARDWARE_STATUS,
+	RNDIS_OID_GEN_MEDIA_SUPPORTED,
+	RNDIS_OID_GEN_MEDIA_IN_USE,
+	RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
+	RNDIS_OID_GEN_LINK_SPEED,
+	RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
+	RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
+	RNDIS_OID_GEN_VENDOR_ID,
+	RNDIS_OID_GEN_VENDOR_DESCRIPTION,
+	RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
+	RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+	RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
+	RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+	RNDIS_OID_GEN_PHYSICAL_MEDIUM,
+
+	/* the statistical stuff */
+	RNDIS_OID_GEN_XMIT_OK,
+	RNDIS_OID_GEN_RCV_OK,
+	RNDIS_OID_GEN_XMIT_ERROR,
+	RNDIS_OID_GEN_RCV_ERROR,
+	RNDIS_OID_GEN_RCV_NO_BUFFER,
+#ifdef	RNDIS_OPTIONAL_STATS
+	RNDIS_OID_GEN_DIRECTED_BYTES_XMIT,
+	RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT,
+	RNDIS_OID_GEN_MULTICAST_BYTES_XMIT,
+	RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT,
+	RNDIS_OID_GEN_BROADCAST_BYTES_XMIT,
+	RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT,
+	RNDIS_OID_GEN_DIRECTED_BYTES_RCV,
+	RNDIS_OID_GEN_DIRECTED_FRAMES_RCV,
+	RNDIS_OID_GEN_MULTICAST_BYTES_RCV,
+	RNDIS_OID_GEN_MULTICAST_FRAMES_RCV,
+	RNDIS_OID_GEN_BROADCAST_BYTES_RCV,
+	RNDIS_OID_GEN_BROADCAST_FRAMES_RCV,
+	RNDIS_OID_GEN_RCV_CRC_ERROR,
+	RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+	/* mandatory 802.3 */
+	/* the general stuff */
+	RNDIS_OID_802_3_PERMANENT_ADDRESS,
+	RNDIS_OID_802_3_CURRENT_ADDRESS,
+	RNDIS_OID_802_3_MULTICAST_LIST,
+	RNDIS_OID_802_3_MAC_OPTIONS,
+	RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
+
+	/* the statistical stuff */
+	RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
+	RNDIS_OID_802_3_XMIT_ONE_COLLISION,
+	RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef	RNDIS_OPTIONAL_STATS
+	RNDIS_OID_802_3_XMIT_DEFERRED,
+	RNDIS_OID_802_3_XMIT_MAX_COLLISIONS,
+	RNDIS_OID_802_3_RCV_OVERRUN,
+	RNDIS_OID_802_3_XMIT_UNDERRUN,
+	RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE,
+	RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST,
+	RNDIS_OID_802_3_XMIT_LATE_COLLISIONS,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* PM and wakeup are "mandatory" for USB, but the RNDIS specs
+	 * don't say what they mean ... and the NDIS specs are often
+	 * confusing and/or ambiguous in this context.  (That is, more
+	 * so than their specs for the other OIDs.)
+	 *
+	 * FIXME someone who knows what these should do, please
+	 * implement them!
+	 */
+
+	/* power management */
+	OID_PNP_CAPABILITIES,
+	OID_PNP_QUERY_POWER,
+	OID_PNP_SET_POWER,
+
+#ifdef	RNDIS_WAKEUP
+	/* wake up host */
+	OID_PNP_ENABLE_WAKE_UP,
+	OID_PNP_ADD_WAKE_UP_PATTERN,
+	OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif	/* RNDIS_WAKEUP */
+#endif	/* RNDIS_PM */
+};
+
+
+/* NDIS Functions */
+static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
+			       unsigned buf_len, rndis_resp_t *r)
+{
+	int retval = -ENOTSUPP;
+	u32 length = 4;	/* usually */
+	__le32 *outbuf;
+	int i, count;
+	rndis_query_cmplt_type *resp;
+	struct net_device *net;
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *stats;
+
+	if (!r) return -ENOMEM;
+	resp = (rndis_query_cmplt_type *)r->buf;
+
+	if (!resp) return -ENOMEM;
+
+	if (buf_len && rndis_debug > 1) {
+		pr_debug("query OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			pr_debug("%03d: %08x %08x %08x %08x\n", i,
+				get_unaligned_le32(&buf[i]),
+				get_unaligned_le32(&buf[i + 4]),
+				get_unaligned_le32(&buf[i + 8]),
+				get_unaligned_le32(&buf[i + 12]));
+		}
+	}
+
+	/* response goes here, right after the header */
+	outbuf = (__le32 *)&resp[1];
+	resp->InformationBufferOffset = cpu_to_le32(16);
+
+	net = rndis_per_dev_params[configNr].dev;
+	stats = dev_get_stats(net, &temp);
+
+	switch (OID) {
+
+	/* general oids (table 4-1) */
+
+	/* mandatory */
+	case RNDIS_OID_GEN_SUPPORTED_LIST:
+		pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
+		length = sizeof(oid_supported_list);
+		count  = length / sizeof(u32);
+		for (i = 0; i < count; i++)
+			outbuf[i] = cpu_to_le32(oid_supported_list[i]);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_HARDWARE_STATUS:
+		pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__);
+		/* Bogus question!
+		 * Hardware must be ready to receive high level protocols.
+		 * BTW:
+		 * reddite ergo quae sunt Caesaris Caesari
+		 * et quae sunt Dei Deo!
+		 */
+		*outbuf = cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_MEDIA_SUPPORTED:
+		pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
+		*outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_MEDIA_IN_USE:
+		pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
+		/* one medium, one transport... (maybe you do it better) */
+		*outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
+		pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
+		if (rndis_per_dev_params[configNr].dev) {
+			*outbuf = cpu_to_le32(
+				rndis_per_dev_params[configNr].dev->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_LINK_SPEED:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
+		if (rndis_per_dev_params[configNr].media_state
+				== RNDIS_MEDIA_STATE_DISCONNECTED)
+			*outbuf = cpu_to_le32(0);
+		else
+			*outbuf = cpu_to_le32(
+				rndis_per_dev_params[configNr].speed);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
+		pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
+		if (rndis_per_dev_params[configNr].dev) {
+			*outbuf = cpu_to_le32(
+				rndis_per_dev_params[configNr].dev->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
+		pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
+		if (rndis_per_dev_params[configNr].dev) {
+			*outbuf = cpu_to_le32(
+				rndis_per_dev_params[configNr].dev->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_VENDOR_ID:
+		pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
+		*outbuf = cpu_to_le32(
+			rndis_per_dev_params[configNr].vendorID);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
+		pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
+		if (rndis_per_dev_params[configNr].vendorDescr) {
+			length = strlen(rndis_per_dev_params[configNr].
+					vendorDescr);
+			memcpy(outbuf,
+				rndis_per_dev_params[configNr].vendorDescr,
+				length);
+		} else {
+			outbuf[0] = 0;
+		}
+		retval = 0;
+		break;
+
+	case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
+		pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
+		/* Created as LE */
+		*outbuf = rndis_driver_version;
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
+		pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
+		*outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE:
+		pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
+		*outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
+		*outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
+						.media_state);
+		retval = 0;
+		break;
+
+	case RNDIS_OID_GEN_PHYSICAL_MEDIUM:
+		pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__);
+		*outbuf = cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* The RNDIS specification is incomplete/wrong.   Some versions
+	 * of MS-Windows expect OIDs that aren't specified there.  Other
+	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
+	 */
+	case RNDIS_OID_GEN_MAC_OPTIONS:		/* from WinME */
+		pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__);
+		*outbuf = cpu_to_le32(
+			  RNDIS_MAC_OPTION_RECEIVE_SERIALIZED
+			| RNDIS_MAC_OPTION_FULL_DUPLEX);
+		retval = 0;
+		break;
+
+	/* statistics OIDs (table 4-2) */
+
+	/* mandatory */
+	case RNDIS_OID_GEN_XMIT_OK:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->tx_packets
+				- stats->tx_errors - stats->tx_dropped);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_RCV_OK:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->rx_packets
+				- stats->rx_errors - stats->rx_dropped);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_XMIT_ERROR:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->tx_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_RCV_ERROR:
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->rx_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_GEN_RCV_NO_BUFFER:
+		pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->rx_dropped);
+			retval = 0;
+		}
+		break;
+
+	/* ieee802.3 OIDs (table 4-3) */
+
+	/* mandatory */
+	case RNDIS_OID_802_3_PERMANENT_ADDRESS:
+		pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
+		if (rndis_per_dev_params[configNr].dev) {
+			length = ETH_ALEN;
+			memcpy(outbuf,
+				rndis_per_dev_params[configNr].host_mac,
+				length);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_802_3_CURRENT_ADDRESS:
+		pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
+		if (rndis_per_dev_params[configNr].dev) {
+			length = ETH_ALEN;
+			memcpy(outbuf,
+				rndis_per_dev_params [configNr].host_mac,
+				length);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_802_3_MULTICAST_LIST:
+		pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
+		/* Multicast base address only */
+		*outbuf = cpu_to_le32(0xE0000000);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE:
+		pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
+		/* Multicast base address only */
+		*outbuf = cpu_to_le32(1);
+		retval = 0;
+		break;
+
+	case RNDIS_OID_802_3_MAC_OPTIONS:
+		pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__);
+		*outbuf = cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* ieee802.3 statistics OIDs (table 4-4) */
+
+	/* mandatory */
+	case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
+		pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
+		if (stats) {
+			*outbuf = cpu_to_le32(stats->rx_frame_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_802_3_XMIT_ONE_COLLISION:
+		pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__);
+		*outbuf = cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS:
+		pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
+		*outbuf = cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	default:
+		pr_warning("%s: query unknown OID 0x%08X\n",
+			 __func__, OID);
+	}
+	if (retval < 0)
+		length = 0;
+
+	resp->InformationBufferLength = cpu_to_le32(length);
+	r->length = length + sizeof(*resp);
+	resp->MessageLength = cpu_to_le32(r->length);
+	return retval;
+}
+
+static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
+			     rndis_resp_t *r)
+{
+	rndis_set_cmplt_type *resp;
+	int i, retval = -ENOTSUPP;
+	struct rndis_params *params;
+
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_set_cmplt_type *)r->buf;
+	if (!resp)
+		return -ENOMEM;
+
+	if (buf_len && rndis_debug > 1) {
+		pr_debug("set OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			pr_debug("%03d: %08x %08x %08x %08x\n", i,
+				get_unaligned_le32(&buf[i]),
+				get_unaligned_le32(&buf[i + 4]),
+				get_unaligned_le32(&buf[i + 8]),
+				get_unaligned_le32(&buf[i + 12]));
+		}
+	}
+
+	params = &rndis_per_dev_params[configNr];
+	switch (OID) {
+	case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
+
+		/* these NDIS_PACKET_TYPE_* bitflags are shared with
+		 * cdc_filter; it's not RNDIS-specific
+		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
+		 *	PROMISCUOUS, DIRECTED,
+		 *	MULTICAST, ALL_MULTICAST, BROADCAST
+		 */
+		*params->filter = (u16)get_unaligned_le32(buf);
+		pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+			__func__, *params->filter);
+
+		/* this call has a significant side effect:  it's
+		 * what makes the packet flow start and stop, like
+		 * activating the CDC Ethernet altsetting.
+		 */
+		retval = 0;
+		if (*params->filter) {
+			params->state = RNDIS_DATA_INITIALIZED;
+			netif_carrier_on(params->dev);
+			if (netif_running(params->dev))
+				netif_wake_queue(params->dev);
+		} else {
+			params->state = RNDIS_INITIALIZED;
+			netif_carrier_off(params->dev);
+			netif_stop_queue(params->dev);
+		}
+		break;
+
+	case RNDIS_OID_802_3_MULTICAST_LIST:
+		/* I think we can ignore this */
+		pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
+		retval = 0;
+		break;
+
+	default:
+		pr_warning("%s: set unknown OID 0x%08X, size %d\n",
+			 __func__, OID, buf_len);
+	}
+
+	return retval;
+}
+
+/*
+ * Response Functions
+ */
+
+static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
+{
+	rndis_init_cmplt_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	if (!params->dev)
+		return -ENOTSUPP;
+
+	r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_init_cmplt_type *)r->buf;
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C);
+	resp->MessageLength = cpu_to_le32(52);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+	resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
+	resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
+	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
+	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
+	resp->MaxPacketsPerTransfer = cpu_to_le32(1);
+	resp->MaxTransferSize = cpu_to_le32(
+		  params->dev->mtu
+		+ sizeof(struct ethhdr)
+		+ sizeof(struct rndis_packet_msg_type)
+		+ 22);
+	resp->PacketAlignmentFactor = cpu_to_le32(0);
+	resp->AFListOffset = cpu_to_le32(0);
+	resp->AFListSize = cpu_to_le32(0);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
+{
+	rndis_query_cmplt_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
+	if (!params->dev)
+		return -ENOTSUPP;
+
+	/*
+	 * we need more memory:
+	 * gen_ndis_query_resp expects enough space for
+	 * rndis_query_cmplt_type followed by data.
+	 * oid_supported_list is the largest data reply
+	 */
+	r = rndis_add_response(configNr,
+		sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_query_cmplt_type *)r->buf;
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+
+	if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID),
+			le32_to_cpu(buf->InformationBufferOffset)
+					+ 8 + (u8 *)buf,
+			le32_to_cpu(buf->InformationBufferLength),
+			r)) {
+		/* OID not supported */
+		resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+		resp->MessageLength = cpu_to_le32(sizeof *resp);
+		resp->InformationBufferLength = cpu_to_le32(0);
+		resp->InformationBufferOffset = cpu_to_le32(0);
+	} else
+		resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
+{
+	u32 BufLength, BufOffset;
+	rndis_set_cmplt_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_set_cmplt_type *)r->buf;
+
+	BufLength = le32_to_cpu(buf->InformationBufferLength);
+	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+
+#ifdef	VERBOSE_DEBUG
+	pr_debug("%s: Length: %d\n", __func__, BufLength);
+	pr_debug("%s: Offset: %d\n", __func__, BufOffset);
+	pr_debug("%s: InfoBuffer: ", __func__);
+
+	for (i = 0; i < BufLength; i++) {
+		pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+	}
+
+	pr_debug("\n");
+#endif
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
+	resp->MessageLength = cpu_to_le32(16);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID),
+			((u8 *)buf) + 8 + BufOffset, BufLength, r))
+		resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+	else
+		resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
+{
+	rndis_reset_cmplt_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_reset_cmplt_type *)r->buf;
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C);
+	resp->MessageLength = cpu_to_le32(16);
+	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+	/* resent information */
+	resp->AddressingReset = cpu_to_le32(1);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+static int rndis_keepalive_response(int configNr,
+				    rndis_keepalive_msg_type *buf)
+{
+	rndis_keepalive_cmplt_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	/* host "should" check only in RNDIS_DATA_INITIALIZED state */
+
+	r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_keepalive_cmplt_type *)r->buf;
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
+	resp->MessageLength = cpu_to_le32(16);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+
+/*
+ * Device to Host Comunication
+ */
+static int rndis_indicate_status_msg(int configNr, u32 status)
+{
+	rndis_indicate_status_msg_type *resp;
+	rndis_resp_t *r;
+	struct rndis_params *params = rndis_per_dev_params + configNr;
+
+	if (params->state == RNDIS_UNINITIALIZED)
+		return -ENOTSUPP;
+
+	r = rndis_add_response(configNr,
+				sizeof(rndis_indicate_status_msg_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_indicate_status_msg_type *)r->buf;
+
+	resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE);
+	resp->MessageLength = cpu_to_le32(20);
+	resp->Status = cpu_to_le32(status);
+	resp->StatusBufferLength = cpu_to_le32(0);
+	resp->StatusBufferOffset = cpu_to_le32(0);
+
+	params->resp_avail(params->v);
+	return 0;
+}
+
+int rndis_signal_connect(int configNr)
+{
+	rndis_per_dev_params[configNr].media_state
+			= RNDIS_MEDIA_STATE_CONNECTED;
+	return rndis_indicate_status_msg(configNr,
+					  RNDIS_STATUS_MEDIA_CONNECT);
+}
+
+int rndis_signal_disconnect(int configNr)
+{
+	rndis_per_dev_params[configNr].media_state
+			= RNDIS_MEDIA_STATE_DISCONNECTED;
+	return rndis_indicate_status_msg(configNr,
+					  RNDIS_STATUS_MEDIA_DISCONNECT);
+}
+
+void rndis_uninit(int configNr)
+{
+	u8 *buf;
+	u32 length;
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return;
+	rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
+
+	/* drain the response queue */
+	while ((buf = rndis_get_next_response(configNr, &length)))
+		rndis_free_response(configNr, buf);
+}
+
+void rndis_set_host_mac(int configNr, const u8 *addr)
+{
+	rndis_per_dev_params[configNr].host_mac = addr;
+}
+
+/*
+ * Message Parser
+ */
+int rndis_msg_parser(u8 configNr, u8 *buf)
+{
+	u32 MsgType, MsgLength;
+	__le32 *tmp;
+	struct rndis_params *params;
+
+	if (!buf)
+		return -ENOMEM;
+
+	tmp = (__le32 *)buf;
+	MsgType   = get_unaligned_le32(tmp++);
+	MsgLength = get_unaligned_le32(tmp++);
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return -ENOTSUPP;
+	params = &rndis_per_dev_params[configNr];
+
+	/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+	 * and normal HC level polling to see if there's any IN traffic.
+	 */
+
+	/* For USB: responses may take up to 10 seconds */
+	switch (MsgType) {
+	case RNDIS_MSG_INIT:
+		pr_debug("%s: RNDIS_MSG_INIT\n",
+			__func__);
+		params->state = RNDIS_INITIALIZED;
+		return rndis_init_response(configNr,
+					(rndis_init_msg_type *)buf);
+
+	case RNDIS_MSG_HALT:
+		pr_debug("%s: RNDIS_MSG_HALT\n",
+			__func__);
+		params->state = RNDIS_UNINITIALIZED;
+		if (params->dev) {
+			netif_carrier_off(params->dev);
+			netif_stop_queue(params->dev);
+		}
+		return 0;
+
+	case RNDIS_MSG_QUERY:
+		return rndis_query_response(configNr,
+					(rndis_query_msg_type *)buf);
+
+	case RNDIS_MSG_SET:
+		return rndis_set_response(configNr,
+					(rndis_set_msg_type *)buf);
+
+	case RNDIS_MSG_RESET:
+		pr_debug("%s: RNDIS_MSG_RESET\n",
+			__func__);
+		return rndis_reset_response(configNr,
+					(rndis_reset_msg_type *)buf);
+
+	case RNDIS_MSG_KEEPALIVE:
+		/* For USB: host does this every 5 seconds */
+		if (rndis_debug > 1)
+			pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
+				__func__);
+		return rndis_keepalive_response(configNr,
+						 (rndis_keepalive_msg_type *)
+						 buf);
+
+	default:
+		/* At least Windows XP emits some undefined RNDIS messages.
+		 * In one case those messages seemed to relate to the host
+		 * suspending itself.
+		 */
+		pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
+			__func__, MsgType, MsgLength);
+		print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
+				     buf, MsgLength);
+		break;
+	}
+
+	return -ENOTSUPP;
+}
+
+int rndis_register(void (*resp_avail)(void *v), void *v)
+{
+	u8 i;
+
+	if (!resp_avail)
+		return -EINVAL;
+
+	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+		if (!rndis_per_dev_params[i].used) {
+			rndis_per_dev_params[i].used = 1;
+			rndis_per_dev_params[i].resp_avail = resp_avail;
+			rndis_per_dev_params[i].v = v;
+			pr_debug("%s: configNr = %d\n", __func__, i);
+			return i;
+		}
+	}
+	pr_debug("failed\n");
+
+	return -ENODEV;
+}
+
+void rndis_deregister(int configNr)
+{
+	pr_debug("%s:\n", __func__);
+
+	if (configNr >= RNDIS_MAX_CONFIGS) return;
+	rndis_per_dev_params[configNr].used = 0;
+}
+
+int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
+{
+	pr_debug("%s:\n", __func__);
+	if (!dev)
+		return -EINVAL;
+	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+	rndis_per_dev_params[configNr].dev = dev;
+	rndis_per_dev_params[configNr].filter = cdc_filter;
+
+	return 0;
+}
+
+int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
+{
+	pr_debug("%s:\n", __func__);
+	if (!vendorDescr) return -1;
+	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+	rndis_per_dev_params[configNr].vendorID = vendorID;
+	rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
+
+	return 0;
+}
+
+int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
+{
+	pr_debug("%s: %u %u\n", __func__, medium, speed);
+	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+	rndis_per_dev_params[configNr].medium = medium;
+	rndis_per_dev_params[configNr].speed = speed;
+
+	return 0;
+}
+
+void rndis_add_hdr(struct sk_buff *skb)
+{
+	struct rndis_packet_msg_type *header;
+
+	if (!skb)
+		return;
+	header = (void *)skb_push(skb, sizeof(*header));
+	memset(header, 0, sizeof *header);
+	header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
+	header->MessageLength = cpu_to_le32(skb->len);
+	header->DataOffset = cpu_to_le32(36);
+	header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
+}
+
+void rndis_free_response(int configNr, u8 *buf)
+{
+	rndis_resp_t *r;
+	struct list_head *act, *tmp;
+
+	list_for_each_safe(act, tmp,
+			&(rndis_per_dev_params[configNr].resp_queue))
+	{
+		r = list_entry(act, rndis_resp_t, list);
+		if (r && r->buf == buf) {
+			list_del(&r->list);
+			kfree(r);
+		}
+	}
+}
+
+u8 *rndis_get_next_response(int configNr, u32 *length)
+{
+	rndis_resp_t *r;
+	struct list_head *act, *tmp;
+
+	if (!length) return NULL;
+
+	list_for_each_safe(act, tmp,
+			&(rndis_per_dev_params[configNr].resp_queue))
+	{
+		r = list_entry(act, rndis_resp_t, list);
+		if (!r->send) {
+			r->send = 1;
+			*length = r->length;
+			return r->buf;
+		}
+	}
+
+	return NULL;
+}
+
+static rndis_resp_t *rndis_add_response(int configNr, u32 length)
+{
+	rndis_resp_t *r;
+
+	/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
+	r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
+	if (!r) return NULL;
+
+	r->buf = (u8 *)(r + 1);
+	r->length = length;
+	r->send = 0;
+
+	list_add_tail(&r->list,
+		&(rndis_per_dev_params[configNr].resp_queue));
+	return r;
+}
+
+int rndis_rm_hdr(struct gether *port,
+			struct sk_buff *skb,
+			struct sk_buff_head *list)
+{
+	/* tmp points to a struct rndis_packet_msg_type */
+	__le32 *tmp = (void *)skb->data;
+
+	/* MessageType, MessageLength */
+	if (cpu_to_le32(RNDIS_MSG_PACKET)
+			!= get_unaligned(tmp++)) {
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
+	tmp++;
+
+	/* DataOffset, DataLength */
+	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
+		dev_kfree_skb_any(skb);
+		return -EOVERFLOW;
+	}
+	skb_trim(skb, get_unaligned_le32(tmp++));
+
+	skb_queue_tail(list, skb);
+	return 0;
+}
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static int rndis_proc_show(struct seq_file *m, void *v)
+{
+	rndis_params *param = m->private;
+
+	seq_printf(m,
+			 "Config Nr. %d\n"
+			 "used      : %s\n"
+			 "state     : %s\n"
+			 "medium    : 0x%08X\n"
+			 "speed     : %d\n"
+			 "cable     : %s\n"
+			 "vendor ID : 0x%08X\n"
+			 "vendor    : %s\n",
+			 param->confignr, (param->used) ? "y" : "n",
+			 ({ char *s = "?";
+			 switch (param->state) {
+			 case RNDIS_UNINITIALIZED:
+				s = "RNDIS_UNINITIALIZED"; break;
+			 case RNDIS_INITIALIZED:
+				s = "RNDIS_INITIALIZED"; break;
+			 case RNDIS_DATA_INITIALIZED:
+				s = "RNDIS_DATA_INITIALIZED"; break;
+			}; s; }),
+			 param->medium,
+			 (param->media_state) ? 0 : param->speed*100,
+			 (param->media_state) ? "disconnected" : "connected",
+			 param->vendorID, param->vendorDescr);
+	return 0;
+}
+
+static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	rndis_params *p = PDE(file->f_path.dentry->d_inode)->data;
+	u32 speed = 0;
+	int i, fl_speed = 0;
+
+	for (i = 0; i < count; i++) {
+		char c;
+		if (get_user(c, buffer))
+			return -EFAULT;
+		switch (c) {
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			fl_speed = 1;
+			speed = speed * 10 + c - '0';
+			break;
+		case 'C':
+		case 'c':
+			rndis_signal_connect(p->confignr);
+			break;
+		case 'D':
+		case 'd':
+			rndis_signal_disconnect(p->confignr);
+			break;
+		default:
+			if (fl_speed) p->speed = speed;
+			else pr_debug("%c is not valid\n", c);
+			break;
+		}
+
+		buffer++;
+	}
+
+	return count;
+}
+
+static int rndis_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rndis_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations rndis_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rndis_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.write		= rndis_proc_write,
+};
+
+#define	NAME_TEMPLATE "driver/rndis-%03d"
+
+static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+
+int rndis_init(void)
+{
+	u8 i;
+
+	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
+		char name [20];
+
+		sprintf(name, NAME_TEMPLATE, i);
+		rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
+					&rndis_proc_fops,
+					(void *)(rndis_per_dev_params + i));
+		if (!rndis_connect_state[i]) {
+			pr_debug("%s: remove entries", __func__);
+			while (i) {
+				sprintf(name, NAME_TEMPLATE, --i);
+				remove_proc_entry(name, NULL);
+			}
+			pr_debug("\n");
+			return -EIO;
+		}
+#endif
+		rndis_per_dev_params[i].confignr = i;
+		rndis_per_dev_params[i].used = 0;
+		rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
+		rndis_per_dev_params[i].media_state
+				= RNDIS_MEDIA_STATE_DISCONNECTED;
+		INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
+	}
+
+	return 0;
+}
+
+void rndis_exit(void)
+{
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	u8 i;
+	char name[20];
+
+	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+		sprintf(name, NAME_TEMPLATE, i);
+		remove_proc_entry(name, NULL);
+	}
+#endif
+}
diff --git a/drivers/staging/ccg/rndis.h b/drivers/staging/ccg/rndis.h
new file mode 100644
index 0000000..0647f2f
--- /dev/null
+++ b/drivers/staging/ccg/rndis.h
@@ -0,0 +1,222 @@
+/*
+ * RNDIS	Definitions for Remote NDIS
+ *
+ * Authors:	Benedikt Spranger, Pengutronix
+ *		Robert Schwebel, Pengutronix
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		version 2, as published by the Free Software Foundation.
+ *
+ *		This software was originally developed in conformance with
+ *		Microsoft's Remote NDIS Specification License Agreement.
+ */
+
+#ifndef _LINUX_RNDIS_H
+#define _LINUX_RNDIS_H
+
+#include <linux/rndis.h>
+#include "ndis.h"
+
+#define RNDIS_MAXIMUM_FRAME_SIZE	1518
+#define RNDIS_MAX_TOTAL_SIZE		1558
+
+typedef struct rndis_init_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	MaxTransferSize;
+} rndis_init_msg_type;
+
+typedef struct rndis_init_cmplt_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	DeviceFlags;
+	__le32	Medium;
+	__le32	MaxPacketsPerTransfer;
+	__le32	MaxTransferSize;
+	__le32	PacketAlignmentFactor;
+	__le32	AFListOffset;
+	__le32	AFListSize;
+} rndis_init_cmplt_type;
+
+typedef struct rndis_halt_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+} rndis_halt_msg_type;
+
+typedef struct rndis_query_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
+} rndis_query_msg_type;
+
+typedef struct rndis_query_cmplt_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+} rndis_query_cmplt_type;
+
+typedef struct rndis_set_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
+} rndis_set_msg_type;
+
+typedef struct rndis_set_cmplt_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+} rndis_set_cmplt_type;
+
+typedef struct rndis_reset_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Reserved;
+} rndis_reset_msg_type;
+
+typedef struct rndis_reset_cmplt_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	AddressingReset;
+} rndis_reset_cmplt_type;
+
+typedef struct rndis_indicate_status_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	StatusBufferLength;
+	__le32	StatusBufferOffset;
+} rndis_indicate_status_msg_type;
+
+typedef struct rndis_keepalive_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+} rndis_keepalive_msg_type;
+
+typedef struct rndis_keepalive_cmplt_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+} rndis_keepalive_cmplt_type;
+
+struct rndis_packet_msg_type
+{
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	DataOffset;
+	__le32	DataLength;
+	__le32	OOBDataOffset;
+	__le32	OOBDataLength;
+	__le32	NumOOBDataElements;
+	__le32	PerPacketInfoOffset;
+	__le32	PerPacketInfoLength;
+	__le32	VcHandle;
+	__le32	Reserved;
+} __attribute__ ((packed));
+
+struct rndis_config_parameter
+{
+	__le32	ParameterNameOffset;
+	__le32	ParameterNameLength;
+	__le32	ParameterType;
+	__le32	ParameterValueOffset;
+	__le32	ParameterValueLength;
+};
+
+/* implementation specific */
+enum rndis_state
+{
+	RNDIS_UNINITIALIZED,
+	RNDIS_INITIALIZED,
+	RNDIS_DATA_INITIALIZED,
+};
+
+typedef struct rndis_resp_t
+{
+	struct list_head	list;
+	u8			*buf;
+	u32			length;
+	int			send;
+} rndis_resp_t;
+
+typedef struct rndis_params
+{
+	u8			confignr;
+	u8			used;
+	u16			saved_filter;
+	enum rndis_state	state;
+	u32			medium;
+	u32			speed;
+	u32			media_state;
+
+	const u8		*host_mac;
+	u16			*filter;
+	struct net_device	*dev;
+
+	u32			vendorID;
+	const char		*vendorDescr;
+	void			(*resp_avail)(void *v);
+	void			*v;
+	struct list_head	resp_queue;
+} rndis_params;
+
+/* RNDIS Message parser and other useless functions */
+int  rndis_msg_parser (u8 configNr, u8 *buf);
+int  rndis_register(void (*resp_avail)(void *v), void *v);
+void rndis_deregister (int configNr);
+int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
+			 u16 *cdc_filter);
+int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
+			    const char *vendorDescr);
+int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
+void rndis_add_hdr (struct sk_buff *skb);
+int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
+			struct sk_buff_head *list);
+u8   *rndis_get_next_response (int configNr, u32 *length);
+void rndis_free_response (int configNr, u8 *buf);
+
+void rndis_uninit (int configNr);
+int  rndis_signal_connect (int configNr);
+int  rndis_signal_disconnect (int configNr);
+int  rndis_state (int configNr);
+extern void rndis_set_host_mac (int configNr, const u8 *addr);
+
+int rndis_init(void);
+void rndis_exit (void);
+
+#endif  /* _LINUX_RNDIS_H */
diff --git a/drivers/staging/ccg/storage_common.c b/drivers/staging/ccg/storage_common.c
new file mode 100644
index 0000000..8d9bcd8
--- /dev/null
+++ b/drivers/staging/ccg/storage_common.c
@@ -0,0 +1,893 @@
+/*
+ * storage_common.c -- Common definitions for mass storage functionality
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyeight (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+/*
+ * This file requires the following identifiers used in USB strings to
+ * be defined (each of type pointer to char):
+ *  - fsg_string_manufacturer -- name of the manufacturer
+ *  - fsg_string_product      -- name of the product
+ *  - fsg_string_config       -- name of the configuration
+ *  - fsg_string_interface    -- name of the interface
+ * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
+ * macro is defined prior to including this file.
+ */
+
+/*
+ * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
+ * fsg_hs_intr_in_desc objects as well as
+ * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
+ * macros are not defined.
+ *
+ * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
+ * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
+ * defined (as well as corresponding entries in string tables are
+ * missing) and FSG_STRING_INTERFACE has value of zero.
+ *
+ * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
+ */
+
+/*
+ * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
+ * sets the number of pipeline buffers (length of the fsg_buffhd array).
+ * The valid range of num_buffers is: num >= 2 && num <= 4.
+ */
+
+
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <asm/unaligned.h>
+
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID	0x0525	/* NetChip */
+#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
+
+
+/*-------------------------------------------------------------------------*/
+
+
+#ifndef DEBUG
+#undef VERBOSE_DEBUG
+#undef DUMP_MSGS
+#endif /* !DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VLDBG	LDBG
+#else
+#define VLDBG(lun, fmt, args...) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args)
+#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
+#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
+#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
+
+/*
+ * Keep those macros in sync with those in
+ * include/linux/usb/composite.h or else GCC will complain.  If they
+ * are identical (the same names of arguments, white spaces in the
+ * same places) GCC will allow redefinition otherwise (even if some
+ * white space is removed or added) warning will be issued.
+ *
+ * Those macros are needed here because File Storage Gadget does not
+ * include the composite.h header.  For composite gadgets those macros
+ * are redundant since composite.h is included any way.
+ *
+ * One could check whether those macros are already defined (which
+ * would indicate composite.h had been included) or not (which would
+ * indicate we were in FSG) but this is not done because a warning is
+ * desired if definitions here differ from the ones in composite.h.
+ *
+ * We want the definitions to match and be the same in File Storage
+ * Gadget as well as Mass Storage Function (and so composite gadgets
+ * using MSF).  If someone changes them in composite.h it will produce
+ * a warning in this file when building MSF.
+ */
+#define DBG(d, fmt, args...)     dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...)    dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...)   dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...)    dev_info(&(d)->gadget->dev , fmt , ## args)
+
+
+
+#ifdef DUMP_MSGS
+
+#  define dump_msg(fsg, /* const char * */ label,			\
+		   /* const u8 * */ buf, /* unsigned */ length) do {	\
+	if (length < 512) {						\
+		DBG(fsg, "%s, length %u:\n", label, length);		\
+		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\
+			       16, 1, buf, length, 0);			\
+	}								\
+} while (0)
+
+#  define dump_cdb(fsg) do { } while (0)
+
+#else
+
+#  define dump_msg(fsg, /* const char * */ label, \
+		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
+
+#  ifdef VERBOSE_DEBUG
+
+#    define dump_cdb(fsg)						\
+	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\
+		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\
+
+#  else
+
+#    define dump_cdb(fsg) do { } while (0)
+
+#  endif /* VERBOSE_DEBUG */
+
+#endif /* DUMP_MSGS */
+
+/*-------------------------------------------------------------------------*/
+
+/* CBI Interrupt data structure */
+struct interrupt_data {
+	u8	bType;
+	u8	bValue;
+};
+
+#define CBI_INTERRUPT_DATA_LEN		2
+
+/* CBI Accept Device-Specific Command request */
+#define USB_CBI_ADSC_REQUEST		0x00
+
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE	16
+
+/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
+#define SS_NO_SENSE				0
+#define SS_COMMUNICATION_FAILURE		0x040800
+#define SS_INVALID_COMMAND			0x052000
+#define SS_INVALID_FIELD_IN_CDB			0x052400
+#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100
+#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500
+#define SS_MEDIUM_NOT_PRESENT			0x023a00
+#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302
+#define SS_NOT_READY_TO_READY_TRANSITION	0x062800
+#define SS_RESET_OCCURRED			0x062900
+#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900
+#define SS_UNRECOVERED_READ_ERROR		0x031100
+#define SS_WRITE_ERROR				0x030c02
+#define SS_WRITE_PROTECTED			0x072700
+
+#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */
+#define ASC(x)		((u8) ((x) >> 8))
+#define ASCQ(x)		((u8) (x))
+
+
+/*-------------------------------------------------------------------------*/
+
+
+struct fsg_lun {
+	struct file	*filp;
+	loff_t		file_length;
+	loff_t		num_sectors;
+
+	unsigned int	initially_ro:1;
+	unsigned int	ro:1;
+	unsigned int	removable:1;
+	unsigned int	cdrom:1;
+	unsigned int	prevent_medium_removal:1;
+	unsigned int	registered:1;
+	unsigned int	info_valid:1;
+	unsigned int	nofua:1;
+
+	u32		sense_data;
+	u32		sense_data_info;
+	u32		unit_attention_data;
+
+	unsigned int	blkbits;	/* Bits of logical block size of bound block device */
+	unsigned int	blksize;	/* logical block size of bound block device */
+	struct device	dev;
+};
+
+#define fsg_lun_is_open(curlun)	((curlun)->filp != NULL)
+
+static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+{
+	return container_of(dev, struct fsg_lun, dev);
+}
+
+
+/* Big enough to hold our biggest descriptor */
+#define EP0_BUFSIZE	256
+#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);
+MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_DEBUG */
+
+/* check if fsg_num_buffers is within a valid range */
+static inline int fsg_num_buffers_validate(void)
+{
+	if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
+		return 0;
+	pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
+	       fsg_num_buffers, 2 ,4);
+	return -EINVAL;
+}
+
+/* Default size of buffer length. */
+#define FSG_BUFLEN	((u32)16384)
+
+/* Maximal number of LUNs supported in mass storage function */
+#define FSG_MAX_LUNS	8
+
+enum fsg_buffer_state {
+	BUF_STATE_EMPTY = 0,
+	BUF_STATE_FULL,
+	BUF_STATE_BUSY
+};
+
+struct fsg_buffhd {
+	void				*buf;
+	enum fsg_buffer_state		state;
+	struct fsg_buffhd		*next;
+
+	/*
+	 * The NetChip 2280 is faster, and handles some protocol faults
+	 * better, if we don't submit any short bulk-out read requests.
+	 * So we will record the intended request length here.
+	 */
+	unsigned int			bulk_out_intended_length;
+
+	struct usb_request		*inreq;
+	int				inreq_busy;
+	struct usb_request		*outreq;
+	int				outreq_busy;
+};
+
+enum fsg_state {
+	/* This one isn't used anywhere */
+	FSG_STATE_COMMAND_PHASE = -10,
+	FSG_STATE_DATA_PHASE,
+	FSG_STATE_STATUS_PHASE,
+
+	FSG_STATE_IDLE = 0,
+	FSG_STATE_ABORT_BULK_OUT,
+	FSG_STATE_RESET,
+	FSG_STATE_INTERFACE_CHANGE,
+	FSG_STATE_CONFIG_CHANGE,
+	FSG_STATE_DISCONNECT,
+	FSG_STATE_EXIT,
+	FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+	DATA_DIR_UNKNOWN = 0,
+	DATA_DIR_FROM_HOST,
+	DATA_DIR_TO_HOST,
+	DATA_DIR_NONE
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static inline u32 get_unaligned_be24(u8 *buf)
+{
+	return 0xffffff & (u32) get_unaligned_be32(buf - 1);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+enum {
+#ifndef FSG_NO_DEVICE_STRINGS
+	FSG_STRING_MANUFACTURER	= 1,
+	FSG_STRING_PRODUCT,
+	FSG_STRING_SERIAL,
+	FSG_STRING_CONFIG,
+#endif
+	FSG_STRING_INTERFACE
+};
+
+
+#ifndef FSG_NO_OTG
+static struct usb_otg_descriptor
+fsg_otg_desc = {
+	.bLength =		sizeof fsg_otg_desc,
+	.bDescriptorType =	USB_DT_OTG,
+
+	.bmAttributes =		USB_OTG_SRP,
+};
+#endif
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor
+fsg_intf_desc = {
+	.bLength =		sizeof fsg_intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
+	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
+	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
+	.iInterface =		FSG_STRING_INTERFACE,
+};
+
+/*
+ * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
+ * interrupt-in.
+ */
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	/* wMaxPacketSize set by autoconfiguration */
+};
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	/* wMaxPacketSize set by autoconfiguration */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_fs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		32,	/* frames -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_fs_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
+#endif
+	NULL,
+};
+
+
+/*
+ * USB 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * That means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the configuration descriptor.
+ */
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+	.bInterval =		1,	/* NAK every 1 uframe */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_hs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_hs_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
+#endif
+	NULL,
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/*.bMaxBurst =		DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/*.bMaxBurst =		DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	.wBytesPerInterval =	cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+	.bLength =		USB_DT_USB_EXT_CAP_SIZE,
+	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
+	.bDevCapabilityType =	USB_CAP_TYPE_EXT,
+
+	.bmAttributes =		cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+	.bLength =		USB_DT_USB_SS_CAP_SIZE,
+	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
+	.bDevCapabilityType =	USB_SS_CAP_TYPE,
+
+	/* .bmAttributes = LTM is not supported yet */
+
+	.wSpeedSupported =	cpu_to_le16(USB_LOW_SPEED_OPERATION
+		| USB_FULL_SPEED_OPERATION
+		| USB_HIGH_SPEED_OPERATION
+		| USB_5GBPS_OPERATION),
+	.bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+	.bU1devExitLat =	USB_DEFAULT_U1_DEV_EXIT_LAT,
+	.bU2DevExitLat =	cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT),
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+	.bLength =		USB_DT_BOS_SIZE,
+	.bDescriptorType =	USB_DT_BOS,
+
+	.wTotalLength =		cpu_to_le16(USB_DT_BOS_SIZE
+				+ USB_DT_USB_EXT_CAP_SIZE
+				+ USB_DT_USB_SS_CAP_SIZE),
+
+	.bNumDeviceCaps =	2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+	(struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+	NULL,
+};
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+static __maybe_unused struct usb_endpoint_descriptor *
+fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *ss)
+{
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return ss;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+
+/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
+static struct usb_string		fsg_strings[] = {
+#ifndef FSG_NO_DEVICE_STRINGS
+	{FSG_STRING_MANUFACTURER,	fsg_string_manufacturer},
+	{FSG_STRING_PRODUCT,		fsg_string_product},
+	{FSG_STRING_SERIAL,		""},
+	{FSG_STRING_CONFIG,		fsg_string_config},
+#endif
+	{FSG_STRING_INTERFACE,		fsg_string_interface},
+	{}
+};
+
+static struct usb_gadget_strings	fsg_stringtab = {
+	.language	= 0x0409,		/* en-us */
+	.strings	= fsg_strings,
+};
+
+
+ /*-------------------------------------------------------------------------*/
+
+/*
+ * If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing.
+ */
+
+static void fsg_lun_close(struct fsg_lun *curlun)
+{
+	if (curlun->filp) {
+		LDBG(curlun, "close backing file\n");
+		fput(curlun->filp);
+		curlun->filp = NULL;
+	}
+}
+
+
+static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
+{
+	int				ro;
+	struct file			*filp = NULL;
+	int				rc = -EINVAL;
+	struct inode			*inode = NULL;
+	loff_t				size;
+	loff_t				num_sectors;
+	loff_t				min_sectors;
+	unsigned int			blkbits;
+	unsigned int			blksize;
+
+	/* R/W if we can, R/O if we must */
+	ro = curlun->initially_ro;
+	if (!ro) {
+		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
+		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
+			ro = 1;
+	}
+	if (ro)
+		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		LINFO(curlun, "unable to open backing file: %s\n", filename);
+		return PTR_ERR(filp);
+	}
+
+	if (!(filp->f_mode & FMODE_WRITE))
+		ro = 1;
+
+	inode = filp->f_path.dentry->d_inode;
+	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
+		LINFO(curlun, "invalid file type: %s\n", filename);
+		goto out;
+	}
+
+	/*
+	 * If we can't read the file, it's no good.
+	 * If we can't write the file, use it read-only.
+	 */
+	if (!(filp->f_op->read || filp->f_op->aio_read)) {
+		LINFO(curlun, "file not readable: %s\n", filename);
+		goto out;
+	}
+	if (!(filp->f_op->write || filp->f_op->aio_write))
+		ro = 1;
+
+	size = i_size_read(inode->i_mapping->host);
+	if (size < 0) {
+		LINFO(curlun, "unable to find file size: %s\n", filename);
+		rc = (int) size;
+		goto out;
+	}
+
+	if (curlun->cdrom) {
+		blksize = 2048;
+		blkbits = 11;
+	} else if (inode->i_bdev) {
+		blksize = bdev_logical_block_size(inode->i_bdev);
+		blkbits = blksize_bits(blksize);
+	} else {
+		blksize = 512;
+		blkbits = 9;
+	}
+
+	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
+	min_sectors = 1;
+	if (curlun->cdrom) {
+		min_sectors = 300;	/* Smallest track is 300 frames */
+		if (num_sectors >= 256*60*75) {
+			num_sectors = 256*60*75 - 1;
+			LINFO(curlun, "file too big: %s\n", filename);
+			LINFO(curlun, "using only first %d blocks\n",
+					(int) num_sectors);
+		}
+	}
+	if (num_sectors < min_sectors) {
+		LINFO(curlun, "file too small: %s\n", filename);
+		rc = -ETOOSMALL;
+		goto out;
+	}
+
+	if (fsg_lun_is_open(curlun))
+		fsg_lun_close(curlun);
+
+	curlun->blksize = blksize;
+	curlun->blkbits = blkbits;
+	curlun->ro = ro;
+	curlun->filp = filp;
+	curlun->file_length = size;
+	curlun->num_sectors = num_sectors;
+	LDBG(curlun, "open backing file: %s\n", filename);
+	return 0;
+
+out:
+	fput(filp);
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sync the file data, don't bother with the metadata.
+ * This code was copied from fs/buffer.c:sys_fdatasync().
+ */
+static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
+{
+	struct file	*filp = curlun->filp;
+
+	if (curlun->ro || !filp)
+		return 0;
+	return vfs_fsync(filp, 1);
+}
+
+static void store_cdrom_address(u8 *dest, int msf, u32 addr)
+{
+	if (msf) {
+		/* Convert to Minutes-Seconds-Frames */
+		addr >>= 2;		/* Convert to 2048-byte frames */
+		addr += 2*75;		/* Lead-in occupies 2 seconds */
+		dest[3] = addr % 75;	/* Frames */
+		addr /= 75;
+		dest[2] = addr % 60;	/* Seconds */
+		addr /= 60;
+		dest[1] = addr;		/* Minutes */
+		dest[0] = 0;		/* Reserved */
+	} else {
+		/* Absolute sector */
+		put_unaligned_be32(addr, dest);
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+
+	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
+				  ? curlun->ro
+				  : curlun->initially_ro);
+}
+
+static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+
+	return sprintf(buf, "%u\n", curlun->nofua);
+}
+
+static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	char		*p;
+	ssize_t		rc;
+
+	down_read(filesem);
+	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
+		p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
+		if (IS_ERR(p))
+			rc = PTR_ERR(p);
+		else {
+			rc = strlen(p);
+			memmove(buf, p, rc);
+			buf[rc] = '\n';		/* Add a newline */
+			buf[++rc] = 0;
+		}
+	} else {				/* No file, return 0 bytes */
+		*buf = 0;
+		rc = 0;
+	}
+	up_read(filesem);
+	return rc;
+}
+
+
+static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	ssize_t		rc;
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	unsigned	ro;
+
+	rc = kstrtouint(buf, 2, &ro);
+	if (rc)
+		return rc;
+
+	/*
+	 * Allow the write-enable status to change only while the
+	 * backing file is closed.
+	 */
+	down_read(filesem);
+	if (fsg_lun_is_open(curlun)) {
+		LDBG(curlun, "read-only status change prevented\n");
+		rc = -EBUSY;
+	} else {
+		curlun->ro = ro;
+		curlun->initially_ro = ro;
+		LDBG(curlun, "read-only status set to %d\n", curlun->ro);
+		rc = count;
+	}
+	up_read(filesem);
+	return rc;
+}
+
+static ssize_t fsg_store_nofua(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+	unsigned	nofua;
+	int		ret;
+
+	ret = kstrtouint(buf, 2, &nofua);
+	if (ret)
+		return ret;
+
+	/* Sync data when switching from async mode to sync */
+	if (!nofua && curlun->nofua)
+		fsg_lun_fsync_sub(curlun);
+
+	curlun->nofua = nofua;
+
+	return count;
+}
+
+static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
+	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	int		rc = 0;
+
+	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
+		LDBG(curlun, "eject attempt prevented\n");
+		return -EBUSY;				/* "Door is locked" */
+	}
+
+	/* Remove a trailing newline */
+	if (count > 0 && buf[count-1] == '\n')
+		((char *) buf)[count-1] = 0;		/* Ugh! */
+
+	/* Load new medium */
+	down_write(filesem);
+	if (count > 0 && buf[0]) {
+		/* fsg_lun_open() will close existing file if any. */
+		rc = fsg_lun_open(curlun, buf);
+		if (rc == 0)
+			curlun->unit_attention_data =
+					SS_NOT_READY_TO_READY_TRANSITION;
+	} else if (fsg_lun_is_open(curlun)) {
+		fsg_lun_close(curlun);
+		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+	}
+	up_write(filesem);
+	return (rc < 0 ? rc : count);
+}
diff --git a/drivers/staging/ccg/u_ether.c b/drivers/staging/ccg/u_ether.c
new file mode 100644
index 0000000..1154a99
--- /dev/null
+++ b/drivers/staging/ccg/u_ether.c
@@ -0,0 +1,986 @@
+/*
+ * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+#include "u_ether.h"
+
+
+/*
+ * This component encapsulates the Ethernet link glue needed to provide
+ * one (!) network link through the USB gadget stack, normally "usb0".
+ *
+ * The control and data models are handled by the function driver which
+ * connects to this code; such as CDC Ethernet (ECM or EEM),
+ * "CDC Subset", or RNDIS.  That includes all descriptor and endpoint
+ * management.
+ *
+ * Link level addressing is handled by this component using module
+ * parameters; if no such parameters are provided, random link level
+ * addresses are used.  Each end of the link uses one address.  The
+ * host end address is exported in various ways, and is often recorded
+ * in configuration databases.
+ *
+ * The driver which assembles each configuration using such a link is
+ * responsible for ensuring that each configuration includes at most one
+ * instance of is network link.  (The network layer provides ways for
+ * this single "physical" link to be used by multiple virtual links.)
+ */
+
+#define UETH__VERSION	"29-May-2008"
+
+struct eth_dev {
+	/* lock is held while accessing port_usb
+	 * or updating its backlink port_usb->ioport
+	 */
+	spinlock_t		lock;
+	struct gether		*port_usb;
+
+	struct net_device	*net;
+	struct usb_gadget	*gadget;
+
+	spinlock_t		req_lock;	/* guard {rx,tx}_reqs */
+	struct list_head	tx_reqs, rx_reqs;
+	atomic_t		tx_qlen;
+
+	struct sk_buff_head	rx_frames;
+
+	unsigned		header_len;
+	struct sk_buff		*(*wrap)(struct gether *, struct sk_buff *skb);
+	int			(*unwrap)(struct gether *,
+						struct sk_buff *skb,
+						struct sk_buff_head *list);
+
+	struct work_struct	work;
+
+	unsigned long		todo;
+#define	WORK_RX_MEMORY		0
+
+	bool			zlp;
+	u8			host_mac[ETH_ALEN];
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define RX_EXTRA	20	/* bytes guarding against rx overflows */
+
+#define DEFAULT_QLEN	2	/* double buffering by default */
+
+static unsigned qmult = 5;
+module_param(qmult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
+
+/* for dual-speed hardware, use deeper queues at high/super speed */
+static inline int qlen(struct usb_gadget *gadget)
+{
+	if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
+					    gadget->speed == USB_SPEED_SUPER))
+		return qmult * DEFAULT_QLEN;
+	else
+		return DEFAULT_QLEN;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* REVISIT there must be a better way than having two sets
+ * of debug calls ...
+ */
+
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define xprintk(d, level, fmt, args...) \
+	printk(level "%s: " fmt , (d)->net->name , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DBG(dev, fmt, args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev, fmt, args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VDBG	DBG
+#else
+#define VDBG(dev, fmt, args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev, fmt, args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define INFO(dev, fmt, args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
+
+static int ueth_change_mtu(struct net_device *net, int new_mtu)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	unsigned long	flags;
+	int		status = 0;
+
+	/* don't change MTU on "live" link (peer won't know) */
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->port_usb)
+		status = -EBUSY;
+	else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
+		status = -ERANGE;
+	else
+		net->mtu = new_mtu;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return status;
+}
+
+static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+
+	strlcpy(p->driver, "g_ether", sizeof p->driver);
+	strlcpy(p->version, UETH__VERSION, sizeof p->version);
+	strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
+	strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+}
+
+/* REVISIT can also support:
+ *   - WOL (by tracking suspends and issuing remote wakeup)
+ *   - msglevel (implies updated messaging)
+ *   - ... probably more ethtool ops
+ */
+
+static const struct ethtool_ops ops = {
+	.get_drvinfo = eth_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
+
+static void defer_kevent(struct eth_dev *dev, int flag)
+{
+	if (test_and_set_bit(flag, &dev->todo))
+		return;
+	if (!schedule_work(&dev->work))
+		ERROR(dev, "kevent %d may have been dropped\n", flag);
+	else
+		DBG(dev, "kevent %d scheduled\n", flag);
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+
+static int
+rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
+{
+	struct sk_buff	*skb;
+	int		retval = -ENOMEM;
+	size_t		size = 0;
+	struct usb_ep	*out;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->port_usb)
+		out = dev->port_usb->out_ep;
+	else
+		out = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (!out)
+		return -ENOTCONN;
+
+
+	/* Padding up to RX_EXTRA handles minor disagreements with host.
+	 * Normally we use the USB "terminate on short read" convention;
+	 * so allow up to (N*maxpacket), since that memory is normally
+	 * already allocated.  Some hardware doesn't deal well with short
+	 * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+	 * byte off the end (to force hardware errors on overflow).
+	 *
+	 * RNDIS uses internal framing, and explicitly allows senders to
+	 * pad to end-of-packet.  That's potentially nice for speed, but
+	 * means receivers can't recover lost synch on their own (because
+	 * new packets don't only start after a short RX).
+	 */
+	size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
+	size += dev->port_usb->header_len;
+	size += out->maxpacket - 1;
+	size -= size % out->maxpacket;
+
+	if (dev->port_usb->is_fixed)
+		size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+
+	skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+	if (skb == NULL) {
+		DBG(dev, "no rx skb\n");
+		goto enomem;
+	}
+
+	/* Some platforms perform better when IP packets are aligned,
+	 * but on at least one, checksumming fails otherwise.  Note:
+	 * RNDIS headers involve variable numbers of LE32 values.
+	 */
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	req->buf = skb->data;
+	req->length = size;
+	req->complete = rx_complete;
+	req->context = skb;
+
+	retval = usb_ep_queue(out, req, gfp_flags);
+	if (retval == -ENOMEM)
+enomem:
+		defer_kevent(dev, WORK_RX_MEMORY);
+	if (retval) {
+		DBG(dev, "rx submit --> %d\n", retval);
+		if (skb)
+			dev_kfree_skb_any(skb);
+		spin_lock_irqsave(&dev->req_lock, flags);
+		list_add(&req->list, &dev->rx_reqs);
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+	}
+	return retval;
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct sk_buff	*skb = req->context, *skb2;
+	struct eth_dev	*dev = ep->driver_data;
+	int		status = req->status;
+
+	switch (status) {
+
+	/* normal completion */
+	case 0:
+		skb_put(skb, req->actual);
+
+		if (dev->unwrap) {
+			unsigned long	flags;
+
+			spin_lock_irqsave(&dev->lock, flags);
+			if (dev->port_usb) {
+				status = dev->unwrap(dev->port_usb,
+							skb,
+							&dev->rx_frames);
+			} else {
+				dev_kfree_skb_any(skb);
+				status = -ENOTCONN;
+			}
+			spin_unlock_irqrestore(&dev->lock, flags);
+		} else {
+			skb_queue_tail(&dev->rx_frames, skb);
+		}
+		skb = NULL;
+
+		skb2 = skb_dequeue(&dev->rx_frames);
+		while (skb2) {
+			if (status < 0
+					|| ETH_HLEN > skb2->len
+					|| skb2->len > ETH_FRAME_LEN) {
+				dev->net->stats.rx_errors++;
+				dev->net->stats.rx_length_errors++;
+				DBG(dev, "rx length %d\n", skb2->len);
+				dev_kfree_skb_any(skb2);
+				goto next_frame;
+			}
+			skb2->protocol = eth_type_trans(skb2, dev->net);
+			dev->net->stats.rx_packets++;
+			dev->net->stats.rx_bytes += skb2->len;
+
+			/* no buffer copies needed, unless hardware can't
+			 * use skb buffers.
+			 */
+			status = netif_rx(skb2);
+next_frame:
+			skb2 = skb_dequeue(&dev->rx_frames);
+		}
+		break;
+
+	/* software-driven interface shutdown */
+	case -ECONNRESET:		/* unlink */
+	case -ESHUTDOWN:		/* disconnect etc */
+		VDBG(dev, "rx shutdown, code %d\n", status);
+		goto quiesce;
+
+	/* for hardware automagic (such as pxa) */
+	case -ECONNABORTED:		/* endpoint reset */
+		DBG(dev, "rx %s reset\n", ep->name);
+		defer_kevent(dev, WORK_RX_MEMORY);
+quiesce:
+		dev_kfree_skb_any(skb);
+		goto clean;
+
+	/* data overrun */
+	case -EOVERFLOW:
+		dev->net->stats.rx_over_errors++;
+		/* FALLTHROUGH */
+
+	default:
+		dev->net->stats.rx_errors++;
+		DBG(dev, "rx status %d\n", status);
+		break;
+	}
+
+	if (skb)
+		dev_kfree_skb_any(skb);
+	if (!netif_running(dev->net)) {
+clean:
+		spin_lock(&dev->req_lock);
+		list_add(&req->list, &dev->rx_reqs);
+		spin_unlock(&dev->req_lock);
+		req = NULL;
+	}
+	if (req)
+		rx_submit(dev, req, GFP_ATOMIC);
+}
+
+static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
+{
+	unsigned		i;
+	struct usb_request	*req;
+
+	if (!n)
+		return -ENOMEM;
+
+	/* queue/recycle up to N requests */
+	i = n;
+	list_for_each_entry(req, list, list) {
+		if (i-- == 0)
+			goto extra;
+	}
+	while (i--) {
+		req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+		if (!req)
+			return list_empty(list) ? -ENOMEM : 0;
+		list_add(&req->list, list);
+	}
+	return 0;
+
+extra:
+	/* free extras */
+	for (;;) {
+		struct list_head	*next;
+
+		next = req->list.next;
+		list_del(&req->list);
+		usb_ep_free_request(ep, req);
+
+		if (next == list)
+			break;
+
+		req = container_of(next, struct usb_request, list);
+	}
+	return 0;
+}
+
+static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
+{
+	int	status;
+
+	spin_lock(&dev->req_lock);
+	status = prealloc(&dev->tx_reqs, link->in_ep, n);
+	if (status < 0)
+		goto fail;
+	status = prealloc(&dev->rx_reqs, link->out_ep, n);
+	if (status < 0)
+		goto fail;
+	goto done;
+fail:
+	DBG(dev, "can't alloc requests\n");
+done:
+	spin_unlock(&dev->req_lock);
+	return status;
+}
+
+static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
+{
+	struct usb_request	*req;
+	unsigned long		flags;
+
+	/* fill unused rxq slots with some skb */
+	spin_lock_irqsave(&dev->req_lock, flags);
+	while (!list_empty(&dev->rx_reqs)) {
+		req = container_of(dev->rx_reqs.next,
+				struct usb_request, list);
+		list_del_init(&req->list);
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+
+		if (rx_submit(dev, req, gfp_flags) < 0) {
+			defer_kevent(dev, WORK_RX_MEMORY);
+			return;
+		}
+
+		spin_lock_irqsave(&dev->req_lock, flags);
+	}
+	spin_unlock_irqrestore(&dev->req_lock, flags);
+}
+
+static void eth_work(struct work_struct *work)
+{
+	struct eth_dev	*dev = container_of(work, struct eth_dev, work);
+
+	if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) {
+		if (netif_running(dev->net))
+			rx_fill(dev, GFP_KERNEL);
+	}
+
+	if (dev->todo)
+		DBG(dev, "work done, flags = 0x%lx\n", dev->todo);
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct sk_buff	*skb = req->context;
+	struct eth_dev	*dev = ep->driver_data;
+
+	switch (req->status) {
+	default:
+		dev->net->stats.tx_errors++;
+		VDBG(dev, "tx err %d\n", req->status);
+		/* FALLTHROUGH */
+	case -ECONNRESET:		/* unlink */
+	case -ESHUTDOWN:		/* disconnect etc */
+		break;
+	case 0:
+		dev->net->stats.tx_bytes += skb->len;
+	}
+	dev->net->stats.tx_packets++;
+
+	spin_lock(&dev->req_lock);
+	list_add(&req->list, &dev->tx_reqs);
+	spin_unlock(&dev->req_lock);
+	dev_kfree_skb_any(skb);
+
+	atomic_dec(&dev->tx_qlen);
+	if (netif_carrier_ok(dev->net))
+		netif_wake_queue(dev->net);
+}
+
+static inline int is_promisc(u16 cdc_filter)
+{
+	return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+}
+
+static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
+					struct net_device *net)
+{
+	struct eth_dev		*dev = netdev_priv(net);
+	int			length = skb->len;
+	int			retval;
+	struct usb_request	*req = NULL;
+	unsigned long		flags;
+	struct usb_ep		*in;
+	u16			cdc_filter;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->port_usb) {
+		in = dev->port_usb->in_ep;
+		cdc_filter = dev->port_usb->cdc_filter;
+	} else {
+		in = NULL;
+		cdc_filter = 0;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (!in) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* apply outgoing CDC or RNDIS filters */
+	if (!is_promisc(cdc_filter)) {
+		u8		*dest = skb->data;
+
+		if (is_multicast_ether_addr(dest)) {
+			u16	type;
+
+			/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+			 * SET_ETHERNET_MULTICAST_FILTERS requests
+			 */
+			if (is_broadcast_ether_addr(dest))
+				type = USB_CDC_PACKET_TYPE_BROADCAST;
+			else
+				type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+			if (!(cdc_filter & type)) {
+				dev_kfree_skb_any(skb);
+				return NETDEV_TX_OK;
+			}
+		}
+		/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+	}
+
+	spin_lock_irqsave(&dev->req_lock, flags);
+	/*
+	 * this freelist can be empty if an interrupt triggered disconnect()
+	 * and reconfigured the gadget (shutting down this queue) after the
+	 * network stack decided to xmit but before we got the spinlock.
+	 */
+	if (list_empty(&dev->tx_reqs)) {
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	req = container_of(dev->tx_reqs.next, struct usb_request, list);
+	list_del(&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
+	if (list_empty(&dev->tx_reqs))
+		netif_stop_queue(net);
+	spin_unlock_irqrestore(&dev->req_lock, flags);
+
+	/* no buffer copies needed, unless the network stack did it
+	 * or the hardware can't use skb buffers.
+	 * or there's not enough space for extra headers we need
+	 */
+	if (dev->wrap) {
+		unsigned long	flags;
+
+		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->port_usb)
+			skb = dev->wrap(dev->port_usb, skb);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		if (!skb)
+			goto drop;
+
+		length = skb->len;
+	}
+	req->buf = skb->data;
+	req->context = skb;
+	req->complete = tx_complete;
+
+	/* NCM requires no zlp if transfer is dwNtbInMaxSize */
+	if (dev->port_usb->is_fixed &&
+	    length == dev->port_usb->fixed_in_len &&
+	    (length % in->maxpacket) == 0)
+		req->zero = 0;
+	else
+		req->zero = 1;
+
+	/* use zlp framing on tx for strict CDC-Ether conformance,
+	 * though any robust network rx path ignores extra padding.
+	 * and some hardware doesn't like to write zlps.
+	 */
+	if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
+		length++;
+
+	req->length = length;
+
+	/* throttle high/super speed IRQ rate back slightly */
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
+				     dev->gadget->speed == USB_SPEED_SUPER)
+			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+			: 0;
+
+	retval = usb_ep_queue(in, req, GFP_ATOMIC);
+	switch (retval) {
+	default:
+		DBG(dev, "tx queue err %d\n", retval);
+		break;
+	case 0:
+		net->trans_start = jiffies;
+		atomic_inc(&dev->tx_qlen);
+	}
+
+	if (retval) {
+		dev_kfree_skb_any(skb);
+drop:
+		dev->net->stats.tx_dropped++;
+		spin_lock_irqsave(&dev->req_lock, flags);
+		if (list_empty(&dev->tx_reqs))
+			netif_start_queue(net);
+		list_add(&req->list, &dev->tx_reqs);
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+	}
+	return NETDEV_TX_OK;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
+{
+	DBG(dev, "%s\n", __func__);
+
+	/* fill the rx queue */
+	rx_fill(dev, gfp_flags);
+
+	/* and open the tx floodgates */
+	atomic_set(&dev->tx_qlen, 0);
+	netif_wake_queue(dev->net);
+}
+
+static int eth_open(struct net_device *net)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	struct gether	*link;
+
+	DBG(dev, "%s\n", __func__);
+	if (netif_carrier_ok(dev->net))
+		eth_start(dev, GFP_KERNEL);
+
+	spin_lock_irq(&dev->lock);
+	link = dev->port_usb;
+	if (link && link->open)
+		link->open(link);
+	spin_unlock_irq(&dev->lock);
+
+	return 0;
+}
+
+static int eth_stop(struct net_device *net)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	unsigned long	flags;
+
+	VDBG(dev, "%s\n", __func__);
+	netif_stop_queue(net);
+
+	DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+		dev->net->stats.rx_packets, dev->net->stats.tx_packets,
+		dev->net->stats.rx_errors, dev->net->stats.tx_errors
+		);
+
+	/* ensure there are no more active requests */
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->port_usb) {
+		struct gether	*link = dev->port_usb;
+
+		if (link->close)
+			link->close(link);
+
+		/* NOTE:  we have no abort-queue primitive we could use
+		 * to cancel all pending I/O.  Instead, we disable then
+		 * reenable the endpoints ... this idiom may leave toggle
+		 * wrong, but that's a self-correcting error.
+		 *
+		 * REVISIT:  we *COULD* just let the transfers complete at
+		 * their own pace; the network stack can handle old packets.
+		 * For the moment we leave this here, since it works.
+		 */
+		usb_ep_disable(link->in_ep);
+		usb_ep_disable(link->out_ep);
+		if (netif_carrier_ok(net)) {
+			DBG(dev, "host still using in/out endpoints\n");
+			usb_ep_enable(link->in_ep);
+			usb_ep_enable(link->out_ep);
+		}
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
+static char *dev_addr;
+module_param(dev_addr, charp, S_IRUGO);
+MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
+
+/* this address is invisible to ifconfig */
+static char *host_addr;
+module_param(host_addr, charp, S_IRUGO);
+MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
+
+static int get_ether_addr(const char *str, u8 *dev_addr)
+{
+	if (str) {
+		unsigned	i;
+
+		for (i = 0; i < 6; i++) {
+			unsigned char num;
+
+			if ((*str == '.') || (*str == ':'))
+				str++;
+			num = hex_to_bin(*str++) << 4;
+			num |= hex_to_bin(*str++);
+			dev_addr [i] = num;
+		}
+		if (is_valid_ether_addr(dev_addr))
+			return 0;
+	}
+	eth_random_addr(dev_addr);
+	return 1;
+}
+
+static struct eth_dev *the_dev;
+
+static const struct net_device_ops eth_netdev_ops = {
+	.ndo_open		= eth_open,
+	.ndo_stop		= eth_stop,
+	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_change_mtu		= ueth_change_mtu,
+	.ndo_set_mac_address 	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static struct device_type gadget_type = {
+	.name	= "gadget",
+};
+
+/**
+ * gether_setup_name - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ *	host side of the link is recorded
+ * @netname: name for network device (for example, "usb")
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework.  The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+		const char *netname)
+{
+	struct eth_dev		*dev;
+	struct net_device	*net;
+	int			status;
+
+	if (the_dev)
+		return -EBUSY;
+
+	net = alloc_etherdev(sizeof *dev);
+	if (!net)
+		return -ENOMEM;
+
+	dev = netdev_priv(net);
+	spin_lock_init(&dev->lock);
+	spin_lock_init(&dev->req_lock);
+	INIT_WORK(&dev->work, eth_work);
+	INIT_LIST_HEAD(&dev->tx_reqs);
+	INIT_LIST_HEAD(&dev->rx_reqs);
+
+	skb_queue_head_init(&dev->rx_frames);
+
+	/* network device setup */
+	dev->net = net;
+	snprintf(net->name, sizeof(net->name), "%s%%d", netname);
+
+	if (get_ether_addr(dev_addr, net->dev_addr))
+		dev_warn(&g->dev,
+			"using random %s ethernet address\n", "self");
+	if (get_ether_addr(host_addr, dev->host_mac))
+		dev_warn(&g->dev,
+			"using random %s ethernet address\n", "host");
+
+	if (ethaddr)
+		memcpy(ethaddr, dev->host_mac, ETH_ALEN);
+
+	net->netdev_ops = &eth_netdev_ops;
+
+	SET_ETHTOOL_OPS(net, &ops);
+
+	dev->gadget = g;
+	SET_NETDEV_DEV(net, &g->dev);
+	SET_NETDEV_DEVTYPE(net, &gadget_type);
+
+	status = register_netdev(net);
+	if (status < 0) {
+		dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
+		free_netdev(net);
+	} else {
+		INFO(dev, "MAC %pM\n", net->dev_addr);
+		INFO(dev, "HOST MAC %pM\n", dev->host_mac);
+
+		the_dev = dev;
+
+		/* two kinds of host-initiated state changes:
+		 *  - iff DATA transfer is active, carrier is "on"
+		 *  - tx queueing enabled if open *and* carrier is "on"
+		 */
+		netif_carrier_off(net);
+	}
+
+	return status;
+}
+
+/**
+ * gether_cleanup - remove Ethernet-over-USB device
+ * Context: may sleep
+ *
+ * This is called to free all resources allocated by @gether_setup().
+ */
+void gether_cleanup(void)
+{
+	if (!the_dev)
+		return;
+
+	unregister_netdev(the_dev->net);
+	flush_work_sync(&the_dev->work);
+	free_netdev(the_dev->net);
+
+	the_dev = NULL;
+}
+
+
+/**
+ * gether_connect - notify network layer that USB link is active
+ * @link: the USB link, set up with endpoints, descriptors matching
+ *	current device speed, and any framing wrapper(s) set up.
+ * Context: irqs blocked
+ *
+ * This is called to activate endpoints and let the network layer know
+ * the connection is active ("carrier detect").  It may cause the I/O
+ * queues to open and start letting network packets flow, but will in
+ * any case activate the endpoints so that they respond properly to the
+ * USB host.
+ *
+ * Verify net_device pointer returned using IS_ERR().  If it doesn't
+ * indicate some error code (negative errno), ep->driver_data values
+ * have been overwritten.
+ */
+struct net_device *gether_connect(struct gether *link)
+{
+	struct eth_dev		*dev = the_dev;
+	int			result = 0;
+
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	link->in_ep->driver_data = dev;
+	result = usb_ep_enable(link->in_ep);
+	if (result != 0) {
+		DBG(dev, "enable %s --> %d\n",
+			link->in_ep->name, result);
+		goto fail0;
+	}
+
+	link->out_ep->driver_data = dev;
+	result = usb_ep_enable(link->out_ep);
+	if (result != 0) {
+		DBG(dev, "enable %s --> %d\n",
+			link->out_ep->name, result);
+		goto fail1;
+	}
+
+	if (result == 0)
+		result = alloc_requests(dev, link, qlen(dev->gadget));
+
+	if (result == 0) {
+		dev->zlp = link->is_zlp_ok;
+		DBG(dev, "qlen %d\n", qlen(dev->gadget));
+
+		dev->header_len = link->header_len;
+		dev->unwrap = link->unwrap;
+		dev->wrap = link->wrap;
+
+		spin_lock(&dev->lock);
+		dev->port_usb = link;
+		link->ioport = dev;
+		if (netif_running(dev->net)) {
+			if (link->open)
+				link->open(link);
+		} else {
+			if (link->close)
+				link->close(link);
+		}
+		spin_unlock(&dev->lock);
+
+		netif_carrier_on(dev->net);
+		if (netif_running(dev->net))
+			eth_start(dev, GFP_ATOMIC);
+
+	/* on error, disable any endpoints  */
+	} else {
+		(void) usb_ep_disable(link->out_ep);
+fail1:
+		(void) usb_ep_disable(link->in_ep);
+	}
+fail0:
+	/* caller is responsible for cleanup on error */
+	if (result < 0)
+		return ERR_PTR(result);
+	return dev->net;
+}
+
+/**
+ * gether_disconnect - notify network layer that USB link is inactive
+ * @link: the USB link, on which gether_connect() was called
+ * Context: irqs blocked
+ *
+ * This is called to deactivate endpoints and let the network layer know
+ * the connection went inactive ("no carrier").
+ *
+ * On return, the state is as if gether_connect() had never been called.
+ * The endpoints are inactive, and accordingly without active USB I/O.
+ * Pointers to endpoint descriptors and endpoint private data are nulled.
+ */
+void gether_disconnect(struct gether *link)
+{
+	struct eth_dev		*dev = link->ioport;
+	struct usb_request	*req;
+
+	WARN_ON(!dev);
+	if (!dev)
+		return;
+
+	DBG(dev, "%s\n", __func__);
+
+	netif_stop_queue(dev->net);
+	netif_carrier_off(dev->net);
+
+	/* disable endpoints, forcing (synchronous) completion
+	 * of all pending i/o.  then free the request objects
+	 * and forget about the endpoints.
+	 */
+	usb_ep_disable(link->in_ep);
+	spin_lock(&dev->req_lock);
+	while (!list_empty(&dev->tx_reqs)) {
+		req = container_of(dev->tx_reqs.next,
+					struct usb_request, list);
+		list_del(&req->list);
+
+		spin_unlock(&dev->req_lock);
+		usb_ep_free_request(link->in_ep, req);
+		spin_lock(&dev->req_lock);
+	}
+	spin_unlock(&dev->req_lock);
+	link->in_ep->driver_data = NULL;
+	link->in_ep->desc = NULL;
+
+	usb_ep_disable(link->out_ep);
+	spin_lock(&dev->req_lock);
+	while (!list_empty(&dev->rx_reqs)) {
+		req = container_of(dev->rx_reqs.next,
+					struct usb_request, list);
+		list_del(&req->list);
+
+		spin_unlock(&dev->req_lock);
+		usb_ep_free_request(link->out_ep, req);
+		spin_lock(&dev->req_lock);
+	}
+	spin_unlock(&dev->req_lock);
+	link->out_ep->driver_data = NULL;
+	link->out_ep->desc = NULL;
+
+	/* finish forgetting about this USB link episode */
+	dev->header_len = 0;
+	dev->unwrap = NULL;
+	dev->wrap = NULL;
+
+	spin_lock(&dev->lock);
+	dev->port_usb = NULL;
+	link->ioport = NULL;
+	spin_unlock(&dev->lock);
+}
diff --git a/drivers/staging/ccg/u_ether.h b/drivers/staging/ccg/u_ether.h
new file mode 100644
index 0000000..6f4a1623
--- /dev/null
+++ b/drivers/staging/ccg/u_ether.h
@@ -0,0 +1,154 @@
+/*
+ * u_ether.h -- interface to USB gadget "ethernet link" utilities
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __U_ETHER_H
+#define __U_ETHER_H
+
+#include <linux/err.h>
+#include <linux/if_ether.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+
+#include "gadget_chips.h"
+
+
+/*
+ * This represents the USB side of an "ethernet" link, managed by a USB
+ * function which provides control and (maybe) framing.  Two functions
+ * in different configurations could share the same ethernet link/netdev,
+ * using different host interaction models.
+ *
+ * There is a current limitation that only one instance of this link may
+ * be present in any given configuration.  When that's a problem, network
+ * layer facilities can be used to package multiple logical links on this
+ * single "physical" one.
+ */
+struct gether {
+	struct usb_function		func;
+
+	/* updated by gether_{connect,disconnect} */
+	struct eth_dev			*ioport;
+
+	/* endpoints handle full and/or high speeds */
+	struct usb_ep			*in_ep;
+	struct usb_ep			*out_ep;
+
+	bool				is_zlp_ok;
+
+	u16				cdc_filter;
+
+	/* hooks for added framing, as needed for RNDIS and EEM. */
+	u32				header_len;
+	/* NCM requires fixed size bundles */
+	bool				is_fixed;
+	u32				fixed_out_len;
+	u32				fixed_in_len;
+	struct sk_buff			*(*wrap)(struct gether *port,
+						struct sk_buff *skb);
+	int				(*unwrap)(struct gether *port,
+						struct sk_buff *skb,
+						struct sk_buff_head *list);
+
+	/* called on network open/close */
+	void				(*open)(struct gether *);
+	void				(*close)(struct gether *);
+};
+
+#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
+			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
+			|USB_CDC_PACKET_TYPE_DIRECTED)
+
+/* variant of gether_setup that allows customizing network device name */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+		const char *netname);
+
+/* netdev setup/teardown as directed by the gadget driver */
+/* gether_setup - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ *	host side of the link is recorded
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework.  The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+{
+	return gether_setup_name(g, ethaddr, "usb");
+}
+
+void gether_cleanup(void);
+
+/* connect/disconnect is handled by individual functions */
+struct net_device *gether_connect(struct gether *);
+void gether_disconnect(struct gether *);
+
+/* Some controllers can't support CDC Ethernet (ECM) ... */
+static inline bool can_support_ecm(struct usb_gadget *gadget)
+{
+	if (!gadget_supports_altsettings(gadget))
+		return false;
+
+	/* Everything else is *presumably* fine ... but this is a bit
+	 * chancy, so be **CERTAIN** there are no hardware issues with
+	 * your controller.  Add it above if it can't handle CDC.
+	 */
+	return true;
+}
+
+/* each configuration may bind one instance of an ethernet link */
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int eem_bind_config(struct usb_configuration *c);
+
+#ifdef USB_ETH_RNDIS
+
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer);
+
+#else
+
+static inline int
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+				u32 vendorID, const char *manufacturer)
+{
+	return 0;
+}
+
+#endif
+
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ *	side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup().  Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+				    u8 ethaddr[ETH_ALEN])
+{
+	return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
+#endif /* __U_ETHER_H */
diff --git a/drivers/staging/ccg/u_serial.c b/drivers/staging/ccg/u_serial.c
new file mode 100644
index 0000000..5b3f5ff
--- /dev/null
+++ b/drivers/staging/ccg/u_serial.c
@@ -0,0 +1,1341 @@
+/*
+ * u_serial.c - utilities for USB gadget "serial port"/TTY support
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This code also borrows from usbserial.c, which is
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
+ * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com)
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * either version 2 of that License or (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "u_serial.h"
+
+
+/*
+ * This component encapsulates the TTY layer glue needed to provide basic
+ * "serial port" functionality through the USB gadget stack.  Each such
+ * port is exposed through a /dev/ttyGS* node.
+ *
+ * After initialization (gserial_setup), these TTY port devices stay
+ * available until they are removed (gserial_cleanup).  Each one may be
+ * connected to a USB function (gserial_connect), or disconnected (with
+ * gserial_disconnect) when the USB host issues a config change event.
+ * Data can only flow when the port is connected to the host.
+ *
+ * A given TTY port can be made available in multiple configurations.
+ * For example, each one might expose a ttyGS0 node which provides a
+ * login application.  In one case that might use CDC ACM interface 0,
+ * while another configuration might use interface 3 for that.  The
+ * work to handle that (including descriptor management) is not part
+ * of this component.
+ *
+ * Configurations may expose more than one TTY port.  For example, if
+ * ttyGS0 provides login service, then ttyGS1 might provide dialer access
+ * for a telephone or fax link.  And ttyGS2 might be something that just
+ * needs a simple byte stream interface for some messaging protocol that
+ * is managed in userspace ... OBEX, PTP, and MTP have been mentioned.
+ */
+
+#define PREFIX	"ttyGS"
+
+/*
+ * gserial is the lifecycle interface, used by USB functions
+ * gs_port is the I/O nexus, used by the tty driver
+ * tty_struct links to the tty/filesystem framework
+ *
+ * gserial <---> gs_port ... links will be null when the USB link is
+ * inactive; managed by gserial_{connect,disconnect}().  each gserial
+ * instance can wrap its own USB control protocol.
+ *	gserial->ioport == usb_ep->driver_data ... gs_port
+ *	gs_port->port_usb ... gserial
+ *
+ * gs_port <---> tty_struct ... links will be null when the TTY file
+ * isn't opened; managed by gs_open()/gs_close()
+ *	gserial->port_tty ... tty_struct
+ *	tty_struct->driver_data ... gserial
+ */
+
+/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the
+ * next layer of buffering.  For TX that's a circular buffer; for RX
+ * consider it a NOP.  A third layer is provided by the TTY code.
+ */
+#define QUEUE_SIZE		16
+#define WRITE_BUF_SIZE		8192		/* TX only */
+
+/* circular buffer */
+struct gs_buf {
+	unsigned		buf_size;
+	char			*buf_buf;
+	char			*buf_get;
+	char			*buf_put;
+};
+
+/*
+ * The port structure holds info for each port, one for each minor number
+ * (and thus for each /dev/ node).
+ */
+struct gs_port {
+	struct tty_port		port;
+	spinlock_t		port_lock;	/* guard port_* access */
+
+	struct gserial		*port_usb;
+
+	bool			openclose;	/* open/close in progress */
+	u8			port_num;
+
+	struct list_head	read_pool;
+	int read_started;
+	int read_allocated;
+	struct list_head	read_queue;
+	unsigned		n_read;
+	struct tasklet_struct	push;
+
+	struct list_head	write_pool;
+	int write_started;
+	int write_allocated;
+	struct gs_buf		port_write_buf;
+	wait_queue_head_t	drain_wait;	/* wait while writes drain */
+
+	/* REVISIT this state ... */
+	struct usb_cdc_line_coding port_line_coding;	/* 8-N-1 etc */
+};
+
+/* increase N_PORTS if you need more */
+#define N_PORTS		4
+static struct portmaster {
+	struct mutex	lock;			/* protect open/close */
+	struct gs_port	*port;
+} ports[N_PORTS];
+static unsigned	n_ports;
+
+#define GS_CLOSE_TIMEOUT		15		/* seconds */
+
+
+
+#ifdef VERBOSE_DEBUG
+#define pr_vdebug(fmt, arg...) \
+	pr_debug(fmt, ##arg)
+#else
+#define pr_vdebug(fmt, arg...) \
+	({ if (0) pr_debug(fmt, ##arg); })
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* Circular Buffer */
+
+/*
+ * gs_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
+{
+	gb->buf_buf = kmalloc(size, GFP_KERNEL);
+	if (gb->buf_buf == NULL)
+		return -ENOMEM;
+
+	gb->buf_size = size;
+	gb->buf_put = gb->buf_buf;
+	gb->buf_get = gb->buf_buf;
+
+	return 0;
+}
+
+/*
+ * gs_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void gs_buf_free(struct gs_buf *gb)
+{
+	kfree(gb->buf_buf);
+	gb->buf_buf = NULL;
+}
+
+/*
+ * gs_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void gs_buf_clear(struct gs_buf *gb)
+{
+	gb->buf_get = gb->buf_put;
+	/* equivalent to a get of all data available */
+}
+
+/*
+ * gs_buf_data_avail
+ *
+ * Return the number of bytes of data written into the circular
+ * buffer.
+ */
+static unsigned gs_buf_data_avail(struct gs_buf *gb)
+{
+	return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
+}
+
+/*
+ * gs_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+static unsigned gs_buf_space_avail(struct gs_buf *gb)
+{
+	return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
+}
+
+/*
+ * gs_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
+{
+	unsigned len;
+
+	len  = gs_buf_space_avail(gb);
+	if (count > len)
+		count = len;
+
+	if (count == 0)
+		return 0;
+
+	len = gb->buf_buf + gb->buf_size - gb->buf_put;
+	if (count > len) {
+		memcpy(gb->buf_put, buf, len);
+		memcpy(gb->buf_buf, buf+len, count - len);
+		gb->buf_put = gb->buf_buf + count - len;
+	} else {
+		memcpy(gb->buf_put, buf, count);
+		if (count < len)
+			gb->buf_put += count;
+		else /* count == len */
+			gb->buf_put = gb->buf_buf;
+	}
+
+	return count;
+}
+
+/*
+ * gs_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
+{
+	unsigned len;
+
+	len = gs_buf_data_avail(gb);
+	if (count > len)
+		count = len;
+
+	if (count == 0)
+		return 0;
+
+	len = gb->buf_buf + gb->buf_size - gb->buf_get;
+	if (count > len) {
+		memcpy(buf, gb->buf_get, len);
+		memcpy(buf+len, gb->buf_buf, count - len);
+		gb->buf_get = gb->buf_buf + count - len;
+	} else {
+		memcpy(buf, gb->buf_get, count);
+		if (count < len)
+			gb->buf_get += count;
+		else /* count == len */
+			gb->buf_get = gb->buf_buf;
+	}
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* I/O glue between TTY (upper) and USB function (lower) driver layers */
+
+/*
+ * gs_alloc_req
+ *
+ * Allocate a usb_request and its buffer.  Returns a pointer to the
+ * usb_request or NULL if there is an error.
+ */
+struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, kmalloc_flags);
+
+	if (req != NULL) {
+		req->length = len;
+		req->buf = kmalloc(len, kmalloc_flags);
+		if (req->buf == NULL) {
+			usb_ep_free_request(ep, req);
+			return NULL;
+		}
+	}
+
+	return req;
+}
+
+/*
+ * gs_free_req
+ *
+ * Free a usb_request and its buffer.
+ */
+void gs_free_req(struct usb_ep *ep, struct usb_request *req)
+{
+	kfree(req->buf);
+	usb_ep_free_request(ep, req);
+}
+
+/*
+ * gs_send_packet
+ *
+ * If there is data to send, a packet is built in the given
+ * buffer and the size is returned.  If there is no data to
+ * send, 0 is returned.
+ *
+ * Called with port_lock held.
+ */
+static unsigned
+gs_send_packet(struct gs_port *port, char *packet, unsigned size)
+{
+	unsigned len;
+
+	len = gs_buf_data_avail(&port->port_write_buf);
+	if (len < size)
+		size = len;
+	if (size != 0)
+		size = gs_buf_get(&port->port_write_buf, packet, size);
+	return size;
+}
+
+/*
+ * gs_start_tx
+ *
+ * This function finds available write requests, calls
+ * gs_send_packet to fill these packets with data, and
+ * continues until either there are no more write requests
+ * available or no more data to send.  This function is
+ * run whenever data arrives or write requests are available.
+ *
+ * Context: caller owns port_lock; port_usb is non-null.
+ */
+static int gs_start_tx(struct gs_port *port)
+/*
+__releases(&port->port_lock)
+__acquires(&port->port_lock)
+*/
+{
+	struct list_head	*pool = &port->write_pool;
+	struct usb_ep		*in = port->port_usb->in;
+	int			status = 0;
+	bool			do_tty_wake = false;
+
+	while (!list_empty(pool)) {
+		struct usb_request	*req;
+		int			len;
+
+		if (port->write_started >= QUEUE_SIZE)
+			break;
+
+		req = list_entry(pool->next, struct usb_request, list);
+		len = gs_send_packet(port, req->buf, in->maxpacket);
+		if (len == 0) {
+			wake_up_interruptible(&port->drain_wait);
+			break;
+		}
+		do_tty_wake = true;
+
+		req->length = len;
+		list_del(&req->list);
+		req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
+
+		pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
+				port->port_num, len, *((u8 *)req->buf),
+				*((u8 *)req->buf+1), *((u8 *)req->buf+2));
+
+		/* Drop lock while we call out of driver; completions
+		 * could be issued while we do so.  Disconnection may
+		 * happen too; maybe immediately before we queue this!
+		 *
+		 * NOTE that we may keep sending data for a while after
+		 * the TTY closed (dev->ioport->port_tty is NULL).
+		 */
+		spin_unlock(&port->port_lock);
+		status = usb_ep_queue(in, req, GFP_ATOMIC);
+		spin_lock(&port->port_lock);
+
+		if (status) {
+			pr_debug("%s: %s %s err %d\n",
+					__func__, "queue", in->name, status);
+			list_add(&req->list, pool);
+			break;
+		}
+
+		port->write_started++;
+
+		/* abort immediately after disconnect */
+		if (!port->port_usb)
+			break;
+	}
+
+	if (do_tty_wake && port->port.tty)
+		tty_wakeup(port->port.tty);
+	return status;
+}
+
+/*
+ * Context: caller owns port_lock, and port_usb is set
+ */
+static unsigned gs_start_rx(struct gs_port *port)
+/*
+__releases(&port->port_lock)
+__acquires(&port->port_lock)
+*/
+{
+	struct list_head	*pool = &port->read_pool;
+	struct usb_ep		*out = port->port_usb->out;
+
+	while (!list_empty(pool)) {
+		struct usb_request	*req;
+		int			status;
+		struct tty_struct	*tty;
+
+		/* no more rx if closed */
+		tty = port->port.tty;
+		if (!tty)
+			break;
+
+		if (port->read_started >= QUEUE_SIZE)
+			break;
+
+		req = list_entry(pool->next, struct usb_request, list);
+		list_del(&req->list);
+		req->length = out->maxpacket;
+
+		/* drop lock while we call out; the controller driver
+		 * may need to call us back (e.g. for disconnect)
+		 */
+		spin_unlock(&port->port_lock);
+		status = usb_ep_queue(out, req, GFP_ATOMIC);
+		spin_lock(&port->port_lock);
+
+		if (status) {
+			pr_debug("%s: %s %s err %d\n",
+					__func__, "queue", out->name, status);
+			list_add(&req->list, pool);
+			break;
+		}
+		port->read_started++;
+
+		/* abort immediately after disconnect */
+		if (!port->port_usb)
+			break;
+	}
+	return port->read_started;
+}
+
+/*
+ * RX tasklet takes data out of the RX queue and hands it up to the TTY
+ * layer until it refuses to take any more data (or is throttled back).
+ * Then it issues reads for any further data.
+ *
+ * If the RX queue becomes full enough that no usb_request is queued,
+ * the OUT endpoint may begin NAKing as soon as its FIFO fills up.
+ * So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
+ * can be buffered before the TTY layer's buffers (currently 64 KB).
+ */
+static void gs_rx_push(unsigned long _port)
+{
+	struct gs_port		*port = (void *)_port;
+	struct tty_struct	*tty;
+	struct list_head	*queue = &port->read_queue;
+	bool			disconnect = false;
+	bool			do_push = false;
+
+	/* hand any queued data to the tty */
+	spin_lock_irq(&port->port_lock);
+	tty = port->port.tty;
+	while (!list_empty(queue)) {
+		struct usb_request	*req;
+
+		req = list_first_entry(queue, struct usb_request, list);
+
+		/* discard data if tty was closed */
+		if (!tty)
+			goto recycle;
+
+		/* leave data queued if tty was rx throttled */
+		if (test_bit(TTY_THROTTLED, &tty->flags))
+			break;
+
+		switch (req->status) {
+		case -ESHUTDOWN:
+			disconnect = true;
+			pr_vdebug(PREFIX "%d: shutdown\n", port->port_num);
+			break;
+
+		default:
+			/* presumably a transient fault */
+			pr_warning(PREFIX "%d: unexpected RX status %d\n",
+					port->port_num, req->status);
+			/* FALLTHROUGH */
+		case 0:
+			/* normal completion */
+			break;
+		}
+
+		/* push data to (open) tty */
+		if (req->actual) {
+			char		*packet = req->buf;
+			unsigned	size = req->actual;
+			unsigned	n;
+			int		count;
+
+			/* we may have pushed part of this packet already... */
+			n = port->n_read;
+			if (n) {
+				packet += n;
+				size -= n;
+			}
+
+			count = tty_insert_flip_string(tty, packet, size);
+			if (count)
+				do_push = true;
+			if (count != size) {
+				/* stop pushing; TTY layer can't handle more */
+				port->n_read += count;
+				pr_vdebug(PREFIX "%d: rx block %d/%d\n",
+						port->port_num,
+						count, req->actual);
+				break;
+			}
+			port->n_read = 0;
+		}
+recycle:
+		list_move(&req->list, &port->read_pool);
+		port->read_started--;
+	}
+
+	/* Push from tty to ldisc; without low_latency set this is handled by
+	 * a workqueue, so we won't get callbacks and can hold port_lock
+	 */
+	if (tty && do_push)
+		tty_flip_buffer_push(tty);
+
+
+	/* We want our data queue to become empty ASAP, keeping data
+	 * in the tty and ldisc (not here).  If we couldn't push any
+	 * this time around, there may be trouble unless there's an
+	 * implicit tty_unthrottle() call on its way...
+	 *
+	 * REVISIT we should probably add a timer to keep the tasklet
+	 * from starving ... but it's not clear that case ever happens.
+	 */
+	if (!list_empty(queue) && tty) {
+		if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+			if (do_push)
+				tasklet_schedule(&port->push);
+			else
+				pr_warning(PREFIX "%d: RX not scheduled?\n",
+					port->port_num);
+		}
+	}
+
+	/* If we're still connected, refill the USB RX queue. */
+	if (!disconnect && port->port_usb)
+		gs_start_rx(port);
+
+	spin_unlock_irq(&port->port_lock);
+}
+
+static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gs_port	*port = ep->driver_data;
+
+	/* Queue all received data until the tty layer is ready for it. */
+	spin_lock(&port->port_lock);
+	list_add_tail(&req->list, &port->read_queue);
+	tasklet_schedule(&port->push);
+	spin_unlock(&port->port_lock);
+}
+
+static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gs_port	*port = ep->driver_data;
+
+	spin_lock(&port->port_lock);
+	list_add(&req->list, &port->write_pool);
+	port->write_started--;
+
+	switch (req->status) {
+	default:
+		/* presumably a transient fault */
+		pr_warning("%s: unexpected %s status %d\n",
+				__func__, ep->name, req->status);
+		/* FALL THROUGH */
+	case 0:
+		/* normal completion */
+		gs_start_tx(port);
+		break;
+
+	case -ESHUTDOWN:
+		/* disconnect */
+		pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
+		break;
+	}
+
+	spin_unlock(&port->port_lock);
+}
+
+static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
+							 int *allocated)
+{
+	struct usb_request	*req;
+
+	while (!list_empty(head)) {
+		req = list_entry(head->next, struct usb_request, list);
+		list_del(&req->list);
+		gs_free_req(ep, req);
+		if (allocated)
+			(*allocated)--;
+	}
+}
+
+static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
+		void (*fn)(struct usb_ep *, struct usb_request *),
+		int *allocated)
+{
+	int			i;
+	struct usb_request	*req;
+	int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE;
+
+	/* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
+	 * do quite that many this time, don't fail ... we just won't
+	 * be as speedy as we might otherwise be.
+	 */
+	for (i = 0; i < n; i++) {
+		req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+		if (!req)
+			return list_empty(head) ? -ENOMEM : 0;
+		req->complete = fn;
+		list_add_tail(&req->list, head);
+		if (allocated)
+			(*allocated)++;
+	}
+	return 0;
+}
+
+/**
+ * gs_start_io - start USB I/O streams
+ * @dev: encapsulates endpoints to use
+ * Context: holding port_lock; port_tty and port_usb are non-null
+ *
+ * We only start I/O when something is connected to both sides of
+ * this port.  If nothing is listening on the host side, we may
+ * be pointlessly filling up our TX buffers and FIFO.
+ */
+static int gs_start_io(struct gs_port *port)
+{
+	struct list_head	*head = &port->read_pool;
+	struct usb_ep		*ep = port->port_usb->out;
+	int			status;
+	unsigned		started;
+
+	/* Allocate RX and TX I/O buffers.  We can't easily do this much
+	 * earlier (with GFP_KERNEL) because the requests are coupled to
+	 * endpoints, as are the packet sizes we'll be using.  Different
+	 * configurations may use different endpoints with a given port;
+	 * and high speed vs full speed changes packet sizes too.
+	 */
+	status = gs_alloc_requests(ep, head, gs_read_complete,
+		&port->read_allocated);
+	if (status)
+		return status;
+
+	status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
+			gs_write_complete, &port->write_allocated);
+	if (status) {
+		gs_free_requests(ep, head, &port->read_allocated);
+		return status;
+	}
+
+	/* queue read requests */
+	port->n_read = 0;
+	started = gs_start_rx(port);
+
+	/* unblock any pending writes into our circular buffer */
+	if (started) {
+		tty_wakeup(port->port.tty);
+	} else {
+		gs_free_requests(ep, head, &port->read_allocated);
+		gs_free_requests(port->port_usb->in, &port->write_pool,
+			&port->write_allocated);
+		status = -EIO;
+	}
+
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* TTY Driver */
+
+/*
+ * gs_open sets up the link between a gs_port and its associated TTY.
+ * That link is broken *only* by TTY close(), and all driver methods
+ * know that.
+ */
+static int gs_open(struct tty_struct *tty, struct file *file)
+{
+	int		port_num = tty->index;
+	struct gs_port	*port;
+	int		status;
+
+	do {
+		mutex_lock(&ports[port_num].lock);
+		port = ports[port_num].port;
+		if (!port)
+			status = -ENODEV;
+		else {
+			spin_lock_irq(&port->port_lock);
+
+			/* already open?  Great. */
+			if (port->port.count) {
+				status = 0;
+				port->port.count++;
+
+			/* currently opening/closing? wait ... */
+			} else if (port->openclose) {
+				status = -EBUSY;
+
+			/* ... else we do the work */
+			} else {
+				status = -EAGAIN;
+				port->openclose = true;
+			}
+			spin_unlock_irq(&port->port_lock);
+		}
+		mutex_unlock(&ports[port_num].lock);
+
+		switch (status) {
+		default:
+			/* fully handled */
+			return status;
+		case -EAGAIN:
+			/* must do the work */
+			break;
+		case -EBUSY:
+			/* wait for EAGAIN task to finish */
+			msleep(1);
+			/* REVISIT could have a waitchannel here, if
+			 * concurrent open performance is important
+			 */
+			break;
+		}
+	} while (status != -EAGAIN);
+
+	/* Do the "real open" */
+	spin_lock_irq(&port->port_lock);
+
+	/* allocate circular buffer on first open */
+	if (port->port_write_buf.buf_buf == NULL) {
+
+		spin_unlock_irq(&port->port_lock);
+		status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
+		spin_lock_irq(&port->port_lock);
+
+		if (status) {
+			pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n",
+				port->port_num, tty, file);
+			port->openclose = false;
+			goto exit_unlock_port;
+		}
+	}
+
+	/* REVISIT if REMOVED (ports[].port NULL), abort the open
+	 * to let rmmod work faster (but this way isn't wrong).
+	 */
+
+	/* REVISIT maybe wait for "carrier detect" */
+
+	tty->driver_data = port;
+	port->port.tty = tty;
+
+	port->port.count = 1;
+	port->openclose = false;
+
+	/* if connected, start the I/O stream */
+	if (port->port_usb) {
+		struct gserial	*gser = port->port_usb;
+
+		pr_debug("gs_open: start ttyGS%d\n", port->port_num);
+		gs_start_io(port);
+
+		if (gser->connect)
+			gser->connect(gser);
+	}
+
+	pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
+
+	status = 0;
+
+exit_unlock_port:
+	spin_unlock_irq(&port->port_lock);
+	return status;
+}
+
+static int gs_writes_finished(struct gs_port *p)
+{
+	int cond;
+
+	/* return true on disconnect or empty buffer */
+	spin_lock_irq(&p->port_lock);
+	cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf);
+	spin_unlock_irq(&p->port_lock);
+
+	return cond;
+}
+
+static void gs_close(struct tty_struct *tty, struct file *file)
+{
+	struct gs_port *port = tty->driver_data;
+	struct gserial	*gser;
+
+	spin_lock_irq(&port->port_lock);
+
+	if (port->port.count != 1) {
+		if (port->port.count == 0)
+			WARN_ON(1);
+		else
+			--port->port.count;
+		goto exit;
+	}
+
+	pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
+
+	/* mark port as closing but in use; we can drop port lock
+	 * and sleep if necessary
+	 */
+	port->openclose = true;
+	port->port.count = 0;
+
+	gser = port->port_usb;
+	if (gser && gser->disconnect)
+		gser->disconnect(gser);
+
+	/* wait for circular write buffer to drain, disconnect, or at
+	 * most GS_CLOSE_TIMEOUT seconds; then discard the rest
+	 */
+	if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
+		spin_unlock_irq(&port->port_lock);
+		wait_event_interruptible_timeout(port->drain_wait,
+					gs_writes_finished(port),
+					GS_CLOSE_TIMEOUT * HZ);
+		spin_lock_irq(&port->port_lock);
+		gser = port->port_usb;
+	}
+
+	/* Iff we're disconnected, there can be no I/O in flight so it's
+	 * ok to free the circular buffer; else just scrub it.  And don't
+	 * let the push tasklet fire again until we're re-opened.
+	 */
+	if (gser == NULL)
+		gs_buf_free(&port->port_write_buf);
+	else
+		gs_buf_clear(&port->port_write_buf);
+
+	tty->driver_data = NULL;
+	port->port.tty = NULL;
+
+	port->openclose = false;
+
+	pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
+			port->port_num, tty, file);
+
+	wake_up_interruptible(&port->port.close_wait);
+exit:
+	spin_unlock_irq(&port->port_lock);
+}
+
+static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	struct gs_port	*port = tty->driver_data;
+	unsigned long	flags;
+	int		status;
+
+	pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
+			port->port_num, tty, count);
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (count)
+		count = gs_buf_put(&port->port_write_buf, buf, count);
+	/* treat count == 0 as flush_chars() */
+	if (port->port_usb)
+		status = gs_start_tx(port);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	return count;
+}
+
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct gs_port	*port = tty->driver_data;
+	unsigned long	flags;
+	int		status;
+
+	pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
+		port->port_num, tty, ch, __builtin_return_address(0));
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	status = gs_buf_put(&port->port_write_buf, &ch, 1);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	return status;
+}
+
+static void gs_flush_chars(struct tty_struct *tty)
+{
+	struct gs_port	*port = tty->driver_data;
+	unsigned long	flags;
+
+	pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port_usb)
+		gs_start_tx(port);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int gs_write_room(struct tty_struct *tty)
+{
+	struct gs_port	*port = tty->driver_data;
+	unsigned long	flags;
+	int		room = 0;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port_usb)
+		room = gs_buf_space_avail(&port->port_write_buf);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
+		port->port_num, tty, room);
+
+	return room;
+}
+
+static int gs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct gs_port	*port = tty->driver_data;
+	unsigned long	flags;
+	int		chars = 0;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	chars = gs_buf_data_avail(&port->port_write_buf);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
+		port->port_num, tty, chars);
+
+	return chars;
+}
+
+/* undo side effects of setting TTY_THROTTLED */
+static void gs_unthrottle(struct tty_struct *tty)
+{
+	struct gs_port		*port = tty->driver_data;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port_usb) {
+		/* Kickstart read queue processing.  We don't do xon/xoff,
+		 * rts/cts, or other handshaking with the host, but if the
+		 * read queue backs up enough we'll be NAKing OUT packets.
+		 */
+		tasklet_schedule(&port->push);
+		pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num);
+	}
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int gs_break_ctl(struct tty_struct *tty, int duration)
+{
+	struct gs_port	*port = tty->driver_data;
+	int		status = 0;
+	struct gserial	*gser;
+
+	pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n",
+			port->port_num, duration);
+
+	spin_lock_irq(&port->port_lock);
+	gser = port->port_usb;
+	if (gser && gser->send_break)
+		status = gser->send_break(gser, duration);
+	spin_unlock_irq(&port->port_lock);
+
+	return status;
+}
+
+static const struct tty_operations gs_tty_ops = {
+	.open =			gs_open,
+	.close =		gs_close,
+	.write =		gs_write,
+	.put_char =		gs_put_char,
+	.flush_chars =		gs_flush_chars,
+	.write_room =		gs_write_room,
+	.chars_in_buffer =	gs_chars_in_buffer,
+	.unthrottle =		gs_unthrottle,
+	.break_ctl =		gs_break_ctl,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct tty_driver *gs_tty_driver;
+
+static int
+gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
+{
+	struct gs_port	*port;
+
+	port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
+	if (port == NULL)
+		return -ENOMEM;
+
+	tty_port_init(&port->port);
+	spin_lock_init(&port->port_lock);
+	init_waitqueue_head(&port->drain_wait);
+
+	tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
+
+	INIT_LIST_HEAD(&port->read_pool);
+	INIT_LIST_HEAD(&port->read_queue);
+	INIT_LIST_HEAD(&port->write_pool);
+
+	port->port_num = port_num;
+	port->port_line_coding = *coding;
+
+	ports[port_num].port = port;
+
+	return 0;
+}
+
+/**
+ * gserial_setup - initialize TTY driver for one or more ports
+ * @g: gadget to associate with these ports
+ * @count: how many ports to support
+ * Context: may sleep
+ *
+ * The TTY stack needs to know in advance how many devices it should
+ * plan to manage.  Use this call to set up the ports you will be
+ * exporting through USB.  Later, connect them to functions based
+ * on what configuration is activated by the USB host; and disconnect
+ * them as appropriate.
+ *
+ * An example would be a two-configuration device in which both
+ * configurations expose port 0, but through different functions.
+ * One configuration could even expose port 1 while the other
+ * one doesn't.
+ *
+ * Returns negative errno or zero.
+ */
+int gserial_setup(struct usb_gadget *g, unsigned count)
+{
+	unsigned			i;
+	struct usb_cdc_line_coding	coding;
+	int				status;
+
+	if (count == 0 || count > N_PORTS)
+		return -EINVAL;
+
+	gs_tty_driver = alloc_tty_driver(count);
+	if (!gs_tty_driver)
+		return -ENOMEM;
+
+	gs_tty_driver->driver_name = "g_serial";
+	gs_tty_driver->name = PREFIX;
+	/* uses dynamically assigned dev_t values */
+
+	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	gs_tty_driver->init_termios = tty_std_termios;
+
+	/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
+	 * MS-Windows.  Otherwise, most of these flags shouldn't affect
+	 * anything unless we were to actually hook up to a serial line.
+	 */
+	gs_tty_driver->init_termios.c_cflag =
+			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	gs_tty_driver->init_termios.c_ispeed = 9600;
+	gs_tty_driver->init_termios.c_ospeed = 9600;
+
+	coding.dwDTERate = cpu_to_le32(9600);
+	coding.bCharFormat = 8;
+	coding.bParityType = USB_CDC_NO_PARITY;
+	coding.bDataBits = USB_CDC_1_STOP_BITS;
+
+	tty_set_operations(gs_tty_driver, &gs_tty_ops);
+
+	/* make devices be openable */
+	for (i = 0; i < count; i++) {
+		mutex_init(&ports[i].lock);
+		status = gs_port_alloc(i, &coding);
+		if (status) {
+			count = i;
+			goto fail;
+		}
+	}
+	n_ports = count;
+
+	/* export the driver ... */
+	status = tty_register_driver(gs_tty_driver);
+	if (status) {
+		pr_err("%s: cannot register, err %d\n",
+				__func__, status);
+		goto fail;
+	}
+
+	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
+	for (i = 0; i < count; i++) {
+		struct device	*tty_dev;
+
+		tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+		if (IS_ERR(tty_dev))
+			pr_warning("%s: no classdev for port %d, err %ld\n",
+				__func__, i, PTR_ERR(tty_dev));
+	}
+
+	pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
+			count, (count == 1) ? "" : "s");
+
+	return status;
+fail:
+	while (count--)
+		kfree(ports[count].port);
+	put_tty_driver(gs_tty_driver);
+	gs_tty_driver = NULL;
+	return status;
+}
+
+static int gs_closed(struct gs_port *port)
+{
+	int cond;
+
+	spin_lock_irq(&port->port_lock);
+	cond = (port->port.count == 0) && !port->openclose;
+	spin_unlock_irq(&port->port_lock);
+	return cond;
+}
+
+/**
+ * gserial_cleanup - remove TTY-over-USB driver and devices
+ * Context: may sleep
+ *
+ * This is called to free all resources allocated by @gserial_setup().
+ * Accordingly, it may need to wait until some open /dev/ files have
+ * closed.
+ *
+ * The caller must have issued @gserial_disconnect() for any ports
+ * that had previously been connected, so that there is never any
+ * I/O pending when it's called.
+ */
+void gserial_cleanup(void)
+{
+	unsigned	i;
+	struct gs_port	*port;
+
+	if (!gs_tty_driver)
+		return;
+
+	/* start sysfs and /dev/ttyGS* node removal */
+	for (i = 0; i < n_ports; i++)
+		tty_unregister_device(gs_tty_driver, i);
+
+	for (i = 0; i < n_ports; i++) {
+		/* prevent new opens */
+		mutex_lock(&ports[i].lock);
+		port = ports[i].port;
+		ports[i].port = NULL;
+		mutex_unlock(&ports[i].lock);
+
+		tasklet_kill(&port->push);
+
+		/* wait for old opens to finish */
+		wait_event(port->port.close_wait, gs_closed(port));
+
+		WARN_ON(port->port_usb != NULL);
+
+		kfree(port);
+	}
+	n_ports = 0;
+
+	tty_unregister_driver(gs_tty_driver);
+	put_tty_driver(gs_tty_driver);
+	gs_tty_driver = NULL;
+
+	pr_debug("%s: cleaned up ttyGS* support\n", __func__);
+}
+
+/**
+ * gserial_connect - notify TTY I/O glue that USB link is active
+ * @gser: the function, set up with endpoints and descriptors
+ * @port_num: which port is active
+ * Context: any (usually from irq)
+ *
+ * This is called activate endpoints and let the TTY layer know that
+ * the connection is active ... not unlike "carrier detect".  It won't
+ * necessarily start I/O queues; unless the TTY is held open by any
+ * task, there would be no point.  However, the endpoints will be
+ * activated so the USB host can perform I/O, subject to basic USB
+ * hardware flow control.
+ *
+ * Caller needs to have set up the endpoints and USB function in @dev
+ * before calling this, as well as the appropriate (speed-specific)
+ * endpoint descriptors, and also have set up the TTY driver by calling
+ * @gserial_setup().
+ *
+ * Returns negative errno or zero.
+ * On success, ep->driver_data will be overwritten.
+ */
+int gserial_connect(struct gserial *gser, u8 port_num)
+{
+	struct gs_port	*port;
+	unsigned long	flags;
+	int		status;
+
+	if (!gs_tty_driver || port_num >= n_ports)
+		return -ENXIO;
+
+	/* we "know" gserial_cleanup() hasn't been called */
+	port = ports[port_num].port;
+
+	/* activate the endpoints */
+	status = usb_ep_enable(gser->in);
+	if (status < 0)
+		return status;
+	gser->in->driver_data = port;
+
+	status = usb_ep_enable(gser->out);
+	if (status < 0)
+		goto fail_out;
+	gser->out->driver_data = port;
+
+	/* then tell the tty glue that I/O can work */
+	spin_lock_irqsave(&port->port_lock, flags);
+	gser->ioport = port;
+	port->port_usb = gser;
+
+	/* REVISIT unclear how best to handle this state...
+	 * we don't really couple it with the Linux TTY.
+	 */
+	gser->port_line_coding = port->port_line_coding;
+
+	/* REVISIT if waiting on "carrier detect", signal. */
+
+	/* if it's already open, start I/O ... and notify the serial
+	 * protocol about open/close status (connect/disconnect).
+	 */
+	if (port->port.count) {
+		pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
+		gs_start_io(port);
+		if (gser->connect)
+			gser->connect(gser);
+	} else {
+		if (gser->disconnect)
+			gser->disconnect(gser);
+	}
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	return status;
+
+fail_out:
+	usb_ep_disable(gser->in);
+	gser->in->driver_data = NULL;
+	return status;
+}
+
+/**
+ * gserial_disconnect - notify TTY I/O glue that USB link is inactive
+ * @gser: the function, on which gserial_connect() was called
+ * Context: any (usually from irq)
+ *
+ * This is called to deactivate endpoints and let the TTY layer know
+ * that the connection went inactive ... not unlike "hangup".
+ *
+ * On return, the state is as if gserial_connect() had never been called;
+ * there is no active USB I/O on these endpoints.
+ */
+void gserial_disconnect(struct gserial *gser)
+{
+	struct gs_port	*port = gser->ioport;
+	unsigned long	flags;
+
+	if (!port)
+		return;
+
+	/* tell the TTY glue not to do I/O here any more */
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	/* REVISIT as above: how best to track this? */
+	port->port_line_coding = gser->port_line_coding;
+
+	port->port_usb = NULL;
+	gser->ioport = NULL;
+	if (port->port.count > 0 || port->openclose) {
+		wake_up_interruptible(&port->drain_wait);
+		if (port->port.tty)
+			tty_hangup(port->port.tty);
+	}
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	/* disable endpoints, aborting down any active I/O */
+	usb_ep_disable(gser->out);
+	gser->out->driver_data = NULL;
+
+	usb_ep_disable(gser->in);
+	gser->in->driver_data = NULL;
+
+	/* finally, free any unused/unusable I/O buffers */
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port.count == 0 && !port->openclose)
+		gs_buf_free(&port->port_write_buf);
+	gs_free_requests(gser->out, &port->read_pool, NULL);
+	gs_free_requests(gser->out, &port->read_queue, NULL);
+	gs_free_requests(gser->in, &port->write_pool, NULL);
+
+	port->read_allocated = port->read_started =
+		port->write_allocated = port->write_started = 0;
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
diff --git a/drivers/staging/ccg/u_serial.h b/drivers/staging/ccg/u_serial.h
new file mode 100644
index 0000000..9b0fe64
--- /dev/null
+++ b/drivers/staging/ccg/u_serial.h
@@ -0,0 +1,65 @@
+/*
+ * u_serial.h - interface to USB gadget "serial port"/TTY utilities
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * either version 2 of that License or (at your option) any later version.
+ */
+
+#ifndef __U_SERIAL_H
+#define __U_SERIAL_H
+
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+
+/*
+ * One non-multiplexed "serial" I/O port ... there can be several of these
+ * on any given USB peripheral device, if it provides enough endpoints.
+ *
+ * The "u_serial" utility component exists to do one thing:  manage TTY
+ * style I/O using the USB peripheral endpoints listed here, including
+ * hookups to sysfs and /dev for each logical "tty" device.
+ *
+ * REVISIT at least ACM could support tiocmget() if needed.
+ *
+ * REVISIT someday, allow multiplexing several TTYs over these endpoints.
+ */
+struct gserial {
+	struct usb_function		func;
+
+	/* port is managed by gserial_{connect,disconnect} */
+	struct gs_port			*ioport;
+
+	struct usb_ep			*in;
+	struct usb_ep			*out;
+
+	/* REVISIT avoid this CDC-ACM support harder ... */
+	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
+
+	/* notification callbacks */
+	void (*connect)(struct gserial *p);
+	void (*disconnect)(struct gserial *p);
+	int (*send_break)(struct gserial *p, int duration);
+};
+
+/* utilities to allocate/free request and buffer */
+struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
+void gs_free_req(struct usb_ep *, struct usb_request *req);
+
+/* port setup/teardown is handled by gadget driver */
+int gserial_setup(struct usb_gadget *g, unsigned n_ports);
+void gserial_cleanup(void);
+
+/* connect/disconnect is handled by individual functions */
+int gserial_connect(struct gserial *, u8 port_num);
+void gserial_disconnect(struct gserial *);
+
+/* functions are bound to configurations by a config or gadget driver */
+int acm_bind_config(struct usb_configuration *c, u8 port_num);
+int gser_bind_config(struct usb_configuration *c, u8 port_num);
+int obex_bind_config(struct usb_configuration *c, u8 port_num);
+
+#endif /* __U_SERIAL_H */
diff --git a/drivers/staging/ccg/usbstring.c b/drivers/staging/ccg/usbstring.c
new file mode 100644
index 0000000..4d25b90
--- /dev/null
+++ b/drivers/staging/ccg/usbstring.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/nls.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * usb_gadget_get_string - fill out a string descriptor 
+ * @table: of c strings encoded using UTF-8
+ * @id: string id, from low byte of wValue in get string descriptor
+ * @buf: at least 256 bytes, must be 16-bit aligned
+ *
+ * Finds the UTF-8 string matching the ID, and converts it into a
+ * string descriptor in utf16-le.
+ * Returns length of descriptor (always even) or negative errno
+ *
+ * If your driver needs stings in multiple languages, you'll probably
+ * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
+ * using this routine after choosing which set of UTF-8 strings to use.
+ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
+ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
+ * characters (which are also widely used in C strings).
+ */
+int
+usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
+{
+	struct usb_string	*s;
+	int			len;
+
+	/* descriptor 0 has the language id */
+	if (id == 0) {
+		buf [0] = 4;
+		buf [1] = USB_DT_STRING;
+		buf [2] = (u8) table->language;
+		buf [3] = (u8) (table->language >> 8);
+		return 4;
+	}
+	for (s = table->strings; s && s->s; s++)
+		if (s->id == id)
+			break;
+
+	/* unrecognized: stall. */
+	if (!s || !s->s)
+		return -EINVAL;
+
+	/* string descriptors have length, tag, then UTF16-LE text */
+	len = min ((size_t) 126, strlen (s->s));
+	len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
+			(wchar_t *) &buf[2], 126);
+	if (len < 0)
+		return -EINVAL;
+	buf [0] = (len + 1) * 2;
+	buf [1] = USB_DT_STRING;
+	return buf [0];
+}
+
diff --git a/drivers/staging/ced1401/Kconfig b/drivers/staging/ced1401/Kconfig
new file mode 100644
index 0000000..ae36d1b
--- /dev/null
+++ b/drivers/staging/ced1401/Kconfig
@@ -0,0 +1,6 @@
+config CED1401
+	tristate "Cambridge Electronic Design 1401 USB support"
+	depends on USB
+	help
+	  This driver supports the Cambridge Electronic Design 1401 USB device
+	  (whatever that is.)
diff --git a/drivers/staging/ced1401/Makefile b/drivers/staging/ced1401/Makefile
new file mode 100644
index 0000000..f0c114b
--- /dev/null
+++ b/drivers/staging/ced1401/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_CED1401)	:= cedusb.o
+cedusb-objs	:= usb1401.o ced_ioc.o
diff --git a/drivers/staging/ced1401/TODO b/drivers/staging/ced1401/TODO
new file mode 100644
index 0000000..9fd5630
--- /dev/null
+++ b/drivers/staging/ced1401/TODO
@@ -0,0 +1,10 @@
+TODO:
+	- coding syle fixes
+	- build warning fixups
+	- ioctl auditing
+	- usb api auditing
+	- proper USB minor number (it's stomping on an existing one right now.)
+
+Please send patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and Cc:
+Alois Schlögl <alois.schloegl@ist.ac.at>
+
diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c
new file mode 100644
index 0000000..c9492ed
--- /dev/null
+++ b/drivers/staging/ced1401/ced_ioc.c
@@ -0,0 +1,1515 @@
+/* ced_ioc.c
+ ioctl part of the 1401 usb device driver for linux.
+ Copyright (C) 2010 Cambridge Electronic Design Ltd
+ Author Greg P Smith (greg@ced.co.uk)
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/page-flags.h>
+#include <linux/pagemap.h>
+#include <linux/jiffies.h>
+
+#include "usb1401.h"
+
+/****************************************************************************
+** FlushOutBuff
+**
+** Empties the Output buffer and sets int lines. Used from user level only
+****************************************************************************/
+void FlushOutBuff(DEVICE_EXTENSION * pdx)
+{
+	dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__,
+		pdx->sCurrentState);
+	if (pdx->sCurrentState == U14ERR_TIME)	/* Do nothing if hardware in trouble */
+		return;
+//    CharSend_Cancel(pdx);                   /* Kill off any pending I/O */
+	spin_lock_irq(&pdx->charOutLock);
+	pdx->dwNumOutput = 0;
+	pdx->dwOutBuffGet = 0;
+	pdx->dwOutBuffPut = 0;
+	spin_unlock_irq(&pdx->charOutLock);
+}
+
+/****************************************************************************
+**
+** FlushInBuff
+**
+** Empties the input buffer and sets int lines
+****************************************************************************/
+void FlushInBuff(DEVICE_EXTENSION * pdx)
+{
+	dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__,
+		pdx->sCurrentState);
+	if (pdx->sCurrentState == U14ERR_TIME)	/* Do nothing if hardware in trouble */
+		return;
+//    CharRead_Cancel(pDevObject);            /* Kill off any pending I/O */
+	spin_lock_irq(&pdx->charInLock);
+	pdx->dwNumInput = 0;
+	pdx->dwInBuffGet = 0;
+	pdx->dwInBuffPut = 0;
+	spin_unlock_irq(&pdx->charInLock);
+}
+
+/****************************************************************************
+** PutChars
+**
+** Utility routine to copy chars into the output buffer and fire them off.
+** called from user mode, holds charOutLock.
+****************************************************************************/
+static int PutChars(DEVICE_EXTENSION * pdx, const char *pCh,
+		    unsigned int uCount)
+{
+	int iReturn;
+	spin_lock_irq(&pdx->charOutLock);	// get the output spin lock
+	if ((OUTBUF_SZ - pdx->dwNumOutput) >= uCount) {
+		unsigned int u;
+		for (u = 0; u < uCount; u++) {
+			pdx->outputBuffer[pdx->dwOutBuffPut++] = pCh[u];
+			if (pdx->dwOutBuffPut >= OUTBUF_SZ)
+				pdx->dwOutBuffPut = 0;
+		}
+		pdx->dwNumOutput += uCount;
+		spin_unlock_irq(&pdx->charOutLock);
+		iReturn = SendChars(pdx);	// ...give a chance to transmit data
+	} else {
+		iReturn = U14ERR_NOOUT;	// no room at the out (ha-ha)
+		spin_unlock_irq(&pdx->charOutLock);
+	}
+	return iReturn;
+}
+
+/*****************************************************************************
+** Add the data in pData (local pointer) of length n to the output buffer, and
+** trigger an output transfer if this is appropriate. User mode.
+** Holds the io_mutex
+*****************************************************************************/
+int SendString(DEVICE_EXTENSION * pdx, const char __user * pData,
+	       unsigned int n)
+{
+	int iReturn = U14ERR_NOERROR;	// assume all will be well
+	char buffer[OUTBUF_SZ + 1];	// space in our address space for characters
+	if (n > OUTBUF_SZ)	// check space in local buffer...
+		return U14ERR_NOOUT;	// ...too many characters
+	if (copy_from_user(buffer, pData, n))
+		return -EFAULT;
+	buffer[n] = 0;		// terminate for debug purposes
+
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	if (n > 0)		// do nothing if nowt to do!
+	{
+		dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, n,
+			buffer);
+		iReturn = PutChars(pdx, buffer, n);
+	}
+
+	Allowi(pdx, false);	// make sure we have input int
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** SendChar
+**
+** Sends a single character to the 1401. User mode, holds io_mutex.
+****************************************************************************/
+int SendChar(DEVICE_EXTENSION * pdx, char c)
+{
+	int iReturn;
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	iReturn = PutChars(pdx, &c, 1);
+	dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)", c, c);
+	Allowi(pdx, false);	// Make sure char reads are running
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/***************************************************************************
+**
+** Get1401State
+**
+**  Retrieves state information from the 1401, adjusts the 1401 state held
+**  in the device extension to indicate the current 1401 type.
+**
+**  *state is updated with information about the 1401 state as returned by the
+**         1401. The low byte is a code for what 1401 is doing:
+**
+**  0       normal 1401 operation
+**  1       sending chars to host
+**  2       sending block data to host
+**  3       reading block data from host
+**  4       sending an escape sequence to the host
+**  0x80    1401 is executing self-test, in which case the upper word
+**          is the last error code seen (or zero for no new error).
+**
+** *error is updated with error information if a self-test error code
+**          is returned in the upper word of state.
+**
+**  both state and error are set to -1 if there are comms problems, and
+**  to zero if there is a simple failure.
+**
+** return error code (U14ERR_NOERROR for OK)
+*/
+int Get1401State(DEVICE_EXTENSION * pdx, __u32 * state, __u32 * error)
+{
+	int nGot;
+	dev_dbg(&pdx->interface->dev, "Get1401State() entry");
+
+	*state = 0xFFFFFFFF;	// Start off with invalid state
+	nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0),
+			       GET_STATUS, (D_TO_H | VENDOR | DEVREQ), 0, 0,
+			       pdx->statBuf, sizeof(pdx->statBuf), HZ);
+	if (nGot != sizeof(pdx->statBuf)) {
+		dev_err(&pdx->interface->dev,
+			"Get1401State() FAILED, return code %d", nGot);
+		pdx->sCurrentState = U14ERR_TIME;	// Indicate that things are very wrong indeed
+		*state = 0;	// Force status values to a known state
+		*error = 0;
+	} else {
+		int nDevice;
+		dev_dbg(&pdx->interface->dev,
+			"Get1401State() Success, state: 0x%x, 0x%x",
+			pdx->statBuf[0], pdx->statBuf[1]);
+
+		*state = pdx->statBuf[0];	// Return the state values to the calling code
+		*error = pdx->statBuf[1];
+
+		nDevice = pdx->udev->descriptor.bcdDevice >> 8;	// 1401 type code value
+		switch (nDevice)	// so we can clean up current state
+		{
+		case 0:
+			pdx->sCurrentState = U14ERR_U1401;
+			break;
+
+		default:	// allow lots of device codes for future 1401s
+			if ((nDevice >= 1) && (nDevice <= 23))
+				pdx->sCurrentState = (short)(nDevice + 6);
+			else
+				pdx->sCurrentState = U14ERR_ILL;
+			break;
+		}
+	}
+
+	return pdx->sCurrentState >= 0 ? U14ERR_NOERROR : pdx->sCurrentState;
+}
+
+/****************************************************************************
+** ReadWrite_Cancel
+**
+** Kills off staged read\write request from the USB if one is pending.
+****************************************************************************/
+int ReadWrite_Cancel(DEVICE_EXTENSION * pdx)
+{
+	dev_dbg(&pdx->interface->dev, "ReadWrite_Cancel entry %d",
+		pdx->bStagedUrbPending);
+#ifdef NOT_WRITTEN_YET
+	int ntStatus = STATUS_SUCCESS;
+	bool bResult = false;
+	unsigned int i;
+	// We can fill this in when we know how we will implement the staged transfer stuff
+	spin_lock_irq(&pdx->stagedLock);
+
+	if (pdx->bStagedUrbPending)	// anything to be cancelled? May need more...
+	{
+		dev_info(&pdx->interface - dev,
+			 "ReadWrite_Cancel about to cancel Urb");
+
+		//       KeClearEvent(&pdx->StagingDoneEvent);   // Clear the staging done flag
+		USB_ASSERT(pdx->pStagedIrp != NULL);
+
+		// Release the spinlock first otherwise the completion routine may hang
+		//  on the spinlock while this function hands waiting for the event.
+		spin_unlock_irq(&pdx->stagedLock);
+		bResult = IoCancelIrp(pdx->pStagedIrp);	// Actually do the cancel
+		if (bResult) {
+			LARGE_INTEGER timeout;
+			timeout.QuadPart = -10000000;	// Use a timeout of 1 second
+			dev_info(&pdx->interface - dev,
+				 "ReadWrite_Cancel about to wait till done");
+			ntStatus =
+			    KeWaitForSingleObject(&pdx->StagingDoneEvent,
+						  Executive, KernelMode, FALSE,
+						  &timeout);
+		} else {
+			dev_info(&pdx->interface - dev,
+				 "ReadWrite_Cancel, cancellation failed");
+			ntStatus = U14ERR_FAIL;
+		}
+		USB_KdPrint(DBGLVL_DEFAULT,
+			    ("ReadWrite_Cancel ntStatus = 0x%x decimal %d\n",
+			     ntStatus, ntStatus));
+	} else
+		spin_unlock_irq(&pdx->stagedLock);
+
+	dev_info(&pdx->interface - dev, "ReadWrite_Cancel  done");
+	return ntStatus;
+#else
+	return U14ERR_NOERROR;
+#endif
+
+}
+
+/***************************************************************************
+** InSelfTest - utility to check in self test. Return 1 for ST, 0 for not or
+** a -ve error code if we failed for some reason.
+***************************************************************************/
+static int InSelfTest(DEVICE_EXTENSION * pdx, unsigned int *pState)
+{
+	unsigned int state, error;
+	int iReturn = Get1401State(pdx, &state, &error);	// see if in self-test
+	if (iReturn == U14ERR_NOERROR)	// if all still OK
+		iReturn = (state == (unsigned int)-1) ||	// TX problem or...
+		    ((state & 0xff) == 0x80);	// ...self test
+	*pState = state;	// return actual state
+	return iReturn;
+}
+
+/***************************************************************************
+** Is1401 - ALWAYS CALLED HOLDING THE io_mutex
+**
+** Tests for the current state of the 1401. Sets sCurrentState:
+**
+**  U14ERR_NOIF  1401  i/f card not installed (not done here)
+**  U14ERR_OFF   1401  apparently not switched on
+**  U14ERR_NC    1401  appears to be not connected
+**  U14ERR_ILL   1401  if it is there its not very well at all
+**  U14ERR_TIME  1401  appears OK, but doesn't communicate - very bad
+**  U14ERR_STD   1401  OK and ready for use
+**  U14ERR_PLUS  1401+ OK and ready for use
+**  U14ERR_U1401 Micro1401 OK and ready for use
+**  U14ERR_POWER Power1401 OK and ready for use
+**  U14ERR_U14012 Micro1401 mkII OK and ready for use
+**
+**  Returns TRUE if a 1401 detected and OK, else FALSE
+****************************************************************************/
+bool Is1401(DEVICE_EXTENSION * pdx)
+{
+	int iReturn;
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	ced_draw_down(pdx);	// wait for, then kill outstanding Urbs
+	FlushInBuff(pdx);	// Clear out input buffer & pipe
+	FlushOutBuff(pdx);	// Clear output buffer & pipe
+
+	// The next call returns 0 if OK, but has returned 1 in the past, meaning that
+	// usb_unlock_device() is needed... now it always is
+	iReturn = usb_lock_device_for_reset(pdx->udev, pdx->interface);
+
+	// release the io_mutex because if we don't, we will deadlock due to system
+	// calls back into the driver.
+	mutex_unlock(&pdx->io_mutex);	// locked, so we will not get system calls
+	if (iReturn >= 0)	// if we failed
+	{
+		iReturn = usb_reset_device(pdx->udev);	// try to do the reset
+		usb_unlock_device(pdx->udev);	// undo the lock
+	}
+
+	mutex_lock(&pdx->io_mutex);	// hold stuff off while we wait
+	pdx->dwDMAFlag = MODE_CHAR;	// Clear DMA mode flag regardless!
+	if (iReturn == 0)	// if all is OK still
+	{
+		unsigned int state;
+		iReturn = InSelfTest(pdx, &state);	// see if likely in self test
+		if (iReturn > 0)	// do we need to wait for self-test?
+		{
+			unsigned long ulTimeOut = jiffies + 30 * HZ;	// when to give up
+			while ((iReturn > 0) && time_before(jiffies, ulTimeOut)) {
+				schedule();	// let other stuff run
+				iReturn = InSelfTest(pdx, &state);	// see if done yet
+			}
+		}
+
+		if (iReturn == 0)	// if all is OK...
+			iReturn = state == 0;	// then sucess is that the state is 0
+	} else
+		iReturn = 0;	// we failed
+	pdx->bForceReset = false;	// Clear forced reset flag now
+
+	return iReturn > 0;
+}
+
+/****************************************************************************
+** QuickCheck  - ALWAYS CALLED HOLDING THE io_mutex
+** This is used to test for a 1401. It will try to do a quick check if all is
+**  OK, that is the 1401 was OK the last time it was asked, and there is no DMA
+**  in progress, and if the bTestBuff flag is set, the character buffers must be
+**  empty too. If the quick check shows that the state is still the same, then
+**  all is OK.
+**
+** If any of the above conditions are not met, or if the state or type of the
+**  1401 has changed since the previous test, the full Is1401 test is done, but
+**  only if bCanReset is also TRUE.
+**
+** The return value is TRUE if a useable 1401 is found, FALSE if not
+*/
+bool QuickCheck(DEVICE_EXTENSION * pdx, bool bTestBuff, bool bCanReset)
+{
+	bool bRet = false;	// assume it will fail and we will reset
+	bool bShortTest;
+
+	bShortTest = ((pdx->dwDMAFlag == MODE_CHAR) &&	// no DMA running
+		      (!pdx->bForceReset) &&	// Not had a real reset forced
+		      (pdx->sCurrentState >= U14ERR_STD));	// No 1401 errors stored
+
+	dev_dbg(&pdx->interface->dev,
+		"%s DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d",
+		__func__, pdx->dwDMAFlag, pdx->sCurrentState, pdx->bForceReset,
+		bTestBuff, bShortTest);
+
+	if ((bTestBuff) &&	// Buffer check requested, and...
+	    (pdx->dwNumInput || pdx->dwNumOutput))	// ...characters were in the buffer?
+	{
+		bShortTest = false;	// Then do the full test
+		dev_dbg(&pdx->interface->dev,
+			"%s will reset as buffers not empty", __func__);
+	}
+
+	if (bShortTest || !bCanReset)	// Still OK to try the short test?
+	{			// Always test if no reset - we want state update
+		unsigned int state, error;
+		dev_dbg(&pdx->interface->dev, "%s->Get1401State", __func__);
+		if (Get1401State(pdx, &state, &error) == U14ERR_NOERROR)	// Check on the 1401 state
+		{
+			if ((state & 0xFF) == 0)	// If call worked, check the status value
+				bRet = true;	// If that was zero, all is OK, no reset needed
+		}
+	}
+
+	if (!bRet && bCanReset)	// If all not OK, then
+	{
+		dev_info(&pdx->interface->dev, "%s->Is1401 %d %d %d %d",
+			 __func__, bShortTest, pdx->sCurrentState, bTestBuff,
+			 pdx->bForceReset);
+		bRet = Is1401(pdx);	//  do full test
+	}
+
+	return bRet;
+}
+
+/****************************************************************************
+** Reset1401
+**
+** Resets the 1401 and empties the i/o buffers
+*****************************************************************************/
+int Reset1401(DEVICE_EXTENSION * pdx)
+{
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	dev_dbg(&pdx->interface->dev, "ABout to call QuickCheck");
+	QuickCheck(pdx, true, true);	// Check 1401, reset if not OK
+	mutex_unlock(&pdx->io_mutex);
+	return U14ERR_NOERROR;
+}
+
+/****************************************************************************
+** GetChar
+**
+** Gets a single character from the 1401
+****************************************************************************/
+int GetChar(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = U14ERR_NOIN;	// assume we will get  nothing
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+
+	dev_dbg(&pdx->interface->dev, "GetChar");
+
+	Allowi(pdx, false);	// Make sure char reads are running
+	SendChars(pdx);		// and send any buffered chars
+
+	spin_lock_irq(&pdx->charInLock);
+	if (pdx->dwNumInput > 0)	// worth looking
+	{
+		iReturn = pdx->inputBuffer[pdx->dwInBuffGet++];
+		if (pdx->dwInBuffGet >= INBUF_SZ)
+			pdx->dwInBuffGet = 0;
+		pdx->dwNumInput--;
+	} else
+		iReturn = U14ERR_NOIN;	// no input data to read
+	spin_unlock_irq(&pdx->charInLock);
+
+	Allowi(pdx, false);	// Make sure char reads are running
+
+	mutex_unlock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	return iReturn;
+}
+
+/****************************************************************************
+** GetString
+**
+** Gets a string from the 1401. Returns chars up to the next CR or when
+** there are no more to read or nowhere to put them. CR is translated to
+** 0 and counted as a character. If the string does not end in a 0, we will
+** add one, if there is room, but it is not counted as a character.
+**
+** returns the count of characters (including the terminator, or 0 if none
+** or a negative error code.
+****************************************************************************/
+int GetString(DEVICE_EXTENSION * pdx, char __user * pUser, int n)
+{
+	int nAvailable;		// character in the buffer
+	int iReturn = U14ERR_NOIN;
+	if (n <= 0)
+		return -ENOMEM;
+
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	Allowi(pdx, false);	// Make sure char reads are running
+	SendChars(pdx);		// and send any buffered chars
+
+	spin_lock_irq(&pdx->charInLock);
+	nAvailable = pdx->dwNumInput;	// characters available now
+	if (nAvailable > n)	// read max of space in pUser...
+		nAvailable = n;	// ...or input characters
+
+	if (nAvailable > 0)	// worth looking?
+	{
+		char buffer[INBUF_SZ + 1];	// space for a linear copy of data
+		int nGot = 0;
+		int nCopyToUser;	// number to copy to user
+		char cData;
+		do {
+			cData = pdx->inputBuffer[pdx->dwInBuffGet++];
+			if (cData == CR_CHAR)	// replace CR with zero
+				cData = (char)0;
+
+			if (pdx->dwInBuffGet >= INBUF_SZ)
+				pdx->dwInBuffGet = 0;	// wrap buffer pointer
+
+			buffer[nGot++] = cData;	// save the output
+		}
+		while ((nGot < nAvailable) && cData);
+
+		nCopyToUser = nGot;	// what to copy...
+		if (cData)	// do we need null
+		{
+			buffer[nGot] = (char)0;	// make it tidy
+			if (nGot < n)	// if space in user buffer...
+				++nCopyToUser;	// ...copy the 0 as well.
+		}
+
+		pdx->dwNumInput -= nGot;
+		spin_unlock_irq(&pdx->charInLock);
+
+		dev_dbg(&pdx->interface->dev,
+			"GetString read %d characters >%s<", nGot, buffer);
+		if (copy_to_user(pUser, buffer, nCopyToUser))
+			iReturn = -EFAULT;
+		else
+			iReturn = nGot;		// report characters read
+	} else
+		spin_unlock_irq(&pdx->charInLock);
+
+	Allowi(pdx, false);	// Make sure char reads are running
+	mutex_unlock(&pdx->io_mutex);	// Protect disconnect from new i/o
+
+	return iReturn;
+}
+
+/*******************************************************************************
+** Get count of characters in the inout buffer.
+*******************************************************************************/
+int Stat1401(DEVICE_EXTENSION * pdx)
+{
+	int iReturn;
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	Allowi(pdx, false);	// make sure we allow pending chars
+	SendChars(pdx);		// in both directions
+	iReturn = pdx->dwNumInput;	// no lock as single read
+	mutex_unlock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	return iReturn;
+}
+
+/****************************************************************************
+** LineCount
+**
+** Returns the number of newline chars in the buffer. There is no need for
+** any fancy interlocks as we only read the interrupt routine data, and the
+** system is arranged so nothing can be destroyed.
+****************************************************************************/
+int LineCount(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = 0;	// will be count of line ends
+
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	Allowi(pdx, false);	// Make sure char reads are running
+	SendChars(pdx);		// and send any buffered chars
+	spin_lock_irq(&pdx->charInLock);	// Get protection
+
+	if (pdx->dwNumInput > 0)	// worth looking?
+	{
+		unsigned int dwIndex = pdx->dwInBuffGet;	// start at first available
+		unsigned int dwEnd = pdx->dwInBuffPut;	// Position for search end
+		do {
+			if (pdx->inputBuffer[dwIndex++] == CR_CHAR)
+				++iReturn;	// inc count if CR
+
+			if (dwIndex >= INBUF_SZ)	// see if we fall off buff
+				dwIndex = 0;
+		}
+		while (dwIndex != dwEnd);	// go to last avaliable
+	}
+
+	spin_unlock_irq(&pdx->charInLock);
+	dev_dbg(&pdx->interface->dev, "LineCount returned %d", iReturn);
+	mutex_unlock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	return iReturn;
+}
+
+/****************************************************************************
+** GetOutBufSpace
+**
+** Gets the space in the output buffer. Called from user code.
+*****************************************************************************/
+int GetOutBufSpace(DEVICE_EXTENSION * pdx)
+{
+	int iReturn;
+	mutex_lock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	SendChars(pdx);		// send any buffered chars
+	iReturn = (int)(OUTBUF_SZ - pdx->dwNumOutput);	// no lock needed for single read
+	dev_dbg(&pdx->interface->dev, "OutBufSpace %d", iReturn);
+	mutex_unlock(&pdx->io_mutex);	// Protect disconnect from new i/o
+	return iReturn;
+}
+
+/****************************************************************************
+**
+** ClearArea
+**
+** Clears up a transfer area. This is always called in the context of a user
+** request, never from a call-back.
+****************************************************************************/
+int ClearArea(DEVICE_EXTENSION * pdx, int nArea)
+{
+	int iReturn = U14ERR_NOERROR;
+
+	if ((nArea < 0) || (nArea >= MAX_TRANSAREAS)) {
+		iReturn = U14ERR_BADAREA;
+		dev_err(&pdx->interface->dev, "%s Attempt to clear area %d",
+			__func__, nArea);
+	} else {
+		TRANSAREA *pTA = &pdx->rTransDef[nArea];	// to save typing
+		if (!pTA->bUsed)	// if not used...
+			iReturn = U14ERR_NOTSET;	// ...nothing to be done
+		else {
+			// We must save the memory we return as we shouldn't mess with memory while
+			// holding a spin lock.
+			struct page **pPages = 0;	// save page address list
+			int nPages = 0;	// and number of pages
+			int np;
+
+			dev_dbg(&pdx->interface->dev, "%s area %d", __func__,
+				nArea);
+			spin_lock_irq(&pdx->stagedLock);
+			if ((pdx->StagedId == nArea)
+			    && (pdx->dwDMAFlag > MODE_CHAR)) {
+				iReturn = U14ERR_UNLOCKFAIL;	// cannot delete as in use
+				dev_err(&pdx->interface->dev,
+					"%s call on area %d while active",
+					__func__, nArea);
+			} else {
+				pPages = pTA->pPages;	// save page address list
+				nPages = pTA->nPages;	// and page count
+				if (pTA->dwEventSz)	// if events flagging in use
+					wake_up_interruptible(&pTA->wqEvent);	// release anything that was waiting
+
+				if (pdx->bXFerWaiting
+				    && (pdx->rDMAInfo.wIdent == nArea))
+					pdx->bXFerWaiting = false;	// Cannot have pending xfer if area cleared
+
+				// Clean out the TRANSAREA except for the wait queue, which is at the end
+				// This sets bUsed to false and dwEventSz to 0 to say area not used and no events.
+				memset(pTA, 0,
+				       sizeof(TRANSAREA) -
+				       sizeof(wait_queue_head_t));
+			}
+			spin_unlock_irq(&pdx->stagedLock);
+
+			if (pPages)	// if we decided to release the memory
+			{
+				// Now we must undo the pinning down of the pages. We will assume the worst and mark
+				// all the pages as dirty. Don't be tempted to move this up above as you must not be
+				// holding a spin lock to do this stuff as it is not atomic.
+				dev_dbg(&pdx->interface->dev, "%s nPages=%d",
+					__func__, nPages);
+
+				for (np = 0; np < nPages; ++np) {
+					if (pPages[np]) {
+						SetPageDirty(pPages[np]);
+						page_cache_release(pPages[np]);
+					}
+				}
+
+				kfree(pPages);
+				dev_dbg(&pdx->interface->dev,
+					"%s kfree(pPages) done", __func__);
+			}
+		}
+	}
+
+	return iReturn;
+}
+
+/****************************************************************************
+** SetArea
+**
+** Sets up a transfer area - the functional part. Called by both
+** SetTransfer and SetCircular.
+****************************************************************************/
+static int SetArea(DEVICE_EXTENSION * pdx, int nArea, char __user * puBuf,
+		   unsigned int dwLength, bool bCircular, bool bCircToHost)
+{
+	// Start by working out the page aligned start of the area and the size
+	// of the area in pages, allowing for the start not being aligned and the
+	// end needing to be rounded up to a page boundary.
+	unsigned long ulStart = ((unsigned long)puBuf) & PAGE_MASK;
+	unsigned int ulOffset = ((unsigned long)puBuf) & (PAGE_SIZE - 1);
+	int len = (dwLength + ulOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	TRANSAREA *pTA = &pdx->rTransDef[nArea];	// to save typing
+	struct page **pPages = 0;	// space for page tables
+	int nPages = 0;		// and number of pages
+
+	int iReturn = ClearArea(pdx, nArea);	// see if OK to use this area
+	if ((iReturn != U14ERR_NOTSET) &&	// if not area unused and...
+	    (iReturn != U14ERR_NOERROR))	// ...not all OK, then...
+		return iReturn;	// ...we cannot use this area
+
+	if (!access_ok(VERIFY_WRITE, puBuf, dwLength))	// if we cannot access the memory...
+		return -EFAULT;	// ...then we are done
+
+	// Now allocate space to hold the page pointer and virtual address pointer tables
+	pPages =
+	    (struct page **)kmalloc(len * sizeof(struct page *), GFP_KERNEL);
+	if (!pPages) {
+		iReturn = U14ERR_NOMEMORY;
+		goto error;
+	}
+	dev_dbg(&pdx->interface->dev, "%s %p, length=%06x, circular %d",
+		__func__, puBuf, dwLength, bCircular);
+
+	// To pin down user pages we must first acquire the mapping semaphore.
+	down_read(&current->mm->mmap_sem);	// get memory map semaphore
+	nPages =
+	    get_user_pages(current, current->mm, ulStart, len, 1, 0, pPages, 0);
+	up_read(&current->mm->mmap_sem);	// release the semaphore
+	dev_dbg(&pdx->interface->dev, "%s nPages = %d", __func__, nPages);
+
+	if (nPages > 0)		// if we succeeded
+	{
+		// If you are tempted to use page_address (form LDD3), forget it. You MUST use
+		// kmap() or kmap_atomic() to get a virtual address. page_address will give you
+		// (null) or at least it does in this context with an x86 machine.
+		spin_lock_irq(&pdx->stagedLock);
+		pTA->lpvBuff = puBuf;	// keep start of region (user address)
+		pTA->dwBaseOffset = ulOffset;	// save offset in first page to start of xfer
+		pTA->dwLength = dwLength;	// Size if the region in bytes
+		pTA->pPages = pPages;	// list of pages that are used by buffer
+		pTA->nPages = nPages;	// number of pages
+
+		pTA->bCircular = bCircular;
+		pTA->bCircToHost = bCircToHost;
+
+		pTA->aBlocks[0].dwOffset = 0;
+		pTA->aBlocks[0].dwSize = 0;
+		pTA->aBlocks[1].dwOffset = 0;
+		pTA->aBlocks[1].dwSize = 0;
+		pTA->bUsed = true;	// This is now a used block
+
+		spin_unlock_irq(&pdx->stagedLock);
+		iReturn = U14ERR_NOERROR;	// say all was well
+	} else {
+		iReturn = U14ERR_LOCKFAIL;
+		goto error;
+	}
+
+	return iReturn;
+
+error:
+	kfree(pPages);
+	return iReturn;
+}
+
+/****************************************************************************
+** SetTransfer
+**
+** Sets up a transfer area record. If the area is already set, we attempt to
+** unset it. Unsetting will fail if the area is booked, and a transfer to that
+** area is in progress. Otherwise, we will release the area and re-assign it.
+****************************************************************************/
+int SetTransfer(DEVICE_EXTENSION * pdx, TRANSFERDESC __user * pTD)
+{
+	int iReturn;
+	TRANSFERDESC td;
+
+	if (copy_from_user(&td, pTD, sizeof(td)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__,
+		td.wAreaNum, td.dwLength);
+	// The strange cast is done so that we don't get warnings in 32-bit linux about the size of the
+	// pointer. The pointer is always passed as a 64-bit object so that we don't have problems using
+	// a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system.
+	iReturn =
+	    SetArea(pdx, td.wAreaNum,
+		    (char __user *)((unsigned long)td.lpvBuff), td.dwLength,
+		    false, false);
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/****************************************************************************
+** UnSetTransfer
+** Erases a transfer area record
+****************************************************************************/
+int UnsetTransfer(DEVICE_EXTENSION * pdx, int nArea)
+{
+	int iReturn;
+	mutex_lock(&pdx->io_mutex);
+	iReturn = ClearArea(pdx, nArea);
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/****************************************************************************
+** SetEvent
+** Creates an event that we can test for based on a transfer to/from an area.
+** The area must be setup for a transfer. We attempt to simulate the Windows
+** driver behavior for events (as we don't actually use them), which is to
+** pretend that whatever the user asked for was achieved, so we return 1 if
+** try to create one, and 0 if they ask to remove (assuming all else was OK).
+****************************************************************************/
+int SetEvent(DEVICE_EXTENSION * pdx, TRANSFEREVENT __user * pTE)
+{
+	int iReturn = U14ERR_NOERROR;
+	TRANSFEREVENT te;
+
+	// get a local copy of the data
+	if (copy_from_user(&te, pTE, sizeof(te)))
+		return -EFAULT;
+
+	if (te.wAreaNum >= MAX_TRANSAREAS)	// the area must exist
+		return U14ERR_BADAREA;
+	else {
+		TRANSAREA *pTA = &pdx->rTransDef[te.wAreaNum];
+		mutex_lock(&pdx->io_mutex);	// make sure we have no competitor
+		spin_lock_irq(&pdx->stagedLock);
+		if (pTA->bUsed)	// area must be in use
+		{
+			pTA->dwEventSt = te.dwStart;	// set area regions
+			pTA->dwEventSz = te.dwLength;	// set size (0 cancels it)
+			pTA->bEventToHost = te.wFlags & 1;	// set the direction
+			pTA->iWakeUp = 0;	// zero the wake up count
+		} else
+			iReturn = U14ERR_NOTSET;
+		spin_unlock_irq(&pdx->stagedLock);
+		mutex_unlock(&pdx->io_mutex);
+	}
+	return iReturn ==
+	    U14ERR_NOERROR ? (te.iSetEvent ? 1 : U14ERR_NOERROR) : iReturn;
+}
+
+/****************************************************************************
+** WaitEvent
+** Sleep the process with a timeout waiting for an event. Returns the number
+** of times that a block met the event condition since we last cleared it or
+** 0 if timed out, or -ve error (bad area or not set, or signal).
+****************************************************************************/
+int WaitEvent(DEVICE_EXTENSION * pdx, int nArea, int msTimeOut)
+{
+	int iReturn;
+	if ((unsigned)nArea >= MAX_TRANSAREAS)
+		return U14ERR_BADAREA;
+	else {
+		int iWait;
+		TRANSAREA *pTA = &pdx->rTransDef[nArea];
+		msTimeOut = (msTimeOut * HZ + 999) / 1000;	// convert timeout to jiffies
+
+		// We cannot wait holding the mutex, but we check the flags while holding
+		// it. This may well be pointless as another thread could get in between
+		// releasing it and the wait call. However, this would have to clear the
+		// iWakeUp flag. However, the !pTA-bUsed may help us in this case.
+		mutex_lock(&pdx->io_mutex);	// make sure we have no competitor
+		if (!pTA->bUsed || !pTA->dwEventSz)	// check something to wait for...
+			return U14ERR_NOTSET;	// ...else we do nothing
+		mutex_unlock(&pdx->io_mutex);
+
+		if (msTimeOut)
+			iWait =
+			    wait_event_interruptible_timeout(pTA->wqEvent,
+							     pTA->iWakeUp
+							     || !pTA->bUsed,
+							     msTimeOut);
+		else
+			iWait =
+			    wait_event_interruptible(pTA->wqEvent, pTA->iWakeUp
+						     || !pTA->bUsed);
+		if (iWait)
+			iReturn = -ERESTARTSYS;	// oops - we have had a SIGNAL
+		else
+			iReturn = pTA->iWakeUp;	// else the wakeup count
+
+		spin_lock_irq(&pdx->stagedLock);
+		pTA->iWakeUp = 0;	// clear the flag
+		spin_unlock_irq(&pdx->stagedLock);
+	}
+	return iReturn;
+}
+
+/****************************************************************************
+** TestEvent
+** Test the event to see if a WaitEvent would return immediately. Returns the
+** number of times a block completed since the last call, or 0 if none or a
+** negative error.
+****************************************************************************/
+int TestEvent(DEVICE_EXTENSION * pdx, int nArea)
+{
+	int iReturn;
+	if ((unsigned)nArea >= MAX_TRANSAREAS)
+		iReturn = U14ERR_BADAREA;
+	else {
+		TRANSAREA *pTA = &pdx->rTransDef[nArea];
+		mutex_lock(&pdx->io_mutex);	// make sure we have no competitor
+		spin_lock_irq(&pdx->stagedLock);
+		iReturn = pTA->iWakeUp;	// get wakeup count since last call
+		pTA->iWakeUp = 0;	// clear the count
+		spin_unlock_irq(&pdx->stagedLock);
+		mutex_unlock(&pdx->io_mutex);
+	}
+	return iReturn;
+}
+
+/****************************************************************************
+** GetTransferInfo
+** Puts the current state of the 1401 in a TGET_TX_BLOCK.
+*****************************************************************************/
+int GetTransfer(DEVICE_EXTENSION * pdx, TGET_TX_BLOCK __user * pTX)
+{
+	int iReturn = U14ERR_NOERROR;
+	unsigned int dwIdent;
+
+	mutex_lock(&pdx->io_mutex);
+	dwIdent = pdx->StagedId;	// area ident for last xfer
+	if (dwIdent >= MAX_TRANSAREAS)
+		iReturn = U14ERR_BADAREA;
+	else {
+		// Return the best information we have - we don't have physical addresses
+		TGET_TX_BLOCK tx;
+		memset(&tx, 0, sizeof(tx));	// clean out local work structure
+		tx.size = pdx->rTransDef[dwIdent].dwLength;
+		tx.linear = (long long)((long)pdx->rTransDef[dwIdent].lpvBuff);
+		tx.avail = GET_TX_MAXENTRIES;	// how many blocks we could return
+		tx.used = 1;	// number we actually return
+		tx.entries[0].physical =
+		    (long long)(tx.linear + pdx->StagedOffset);
+		tx.entries[0].size = tx.size;
+
+		if (copy_to_user(pTX, &tx, sizeof(tx)))
+			iReturn = -EFAULT;
+	}
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/****************************************************************************
+** KillIO1401
+**
+** Empties the host i/o buffers
+****************************************************************************/
+int KillIO1401(DEVICE_EXTENSION * pdx)
+{
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+	mutex_lock(&pdx->io_mutex);
+	FlushOutBuff(pdx);
+	FlushInBuff(pdx);
+	mutex_unlock(&pdx->io_mutex);
+	return U14ERR_NOERROR;
+}
+
+/****************************************************************************
+** BlkTransState
+** Returns a 0 or a 1 for whether DMA is happening. No point holding a mutex
+** for this as it only does one read.
+*****************************************************************************/
+int BlkTransState(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = pdx->dwDMAFlag != MODE_CHAR;
+	dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn);
+	return iReturn;
+}
+
+/****************************************************************************
+** StateOf1401
+**
+** Puts the current state of the 1401 in the Irp return buffer.
+*****************************************************************************/
+int StateOf1401(DEVICE_EXTENSION * pdx)
+{
+	int iReturn;
+	mutex_lock(&pdx->io_mutex);
+
+	QuickCheck(pdx, false, false);	// get state up to date, no reset
+	iReturn = pdx->sCurrentState;
+
+	mutex_unlock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** StartSelfTest
+**
+** Initiates a self-test cycle. The assumption is that we have no interrupts
+** active, so we should make sure that this is the case.
+*****************************************************************************/
+int StartSelfTest(DEVICE_EXTENSION * pdx)
+{
+	int nGot;
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	ced_draw_down(pdx);	// wait for, then kill outstanding Urbs
+	FlushInBuff(pdx);	// Clear out input buffer & pipe
+	FlushOutBuff(pdx);	// Clear output buffer & pipe
+//    ReadWrite_Cancel(pDeviceObject);        /* so things stay tidy */
+	pdx->dwDMAFlag = MODE_CHAR;	/* Clear DMA mode flags here */
+
+	nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), DB_SELFTEST, (H_TO_D | VENDOR | DEVREQ), 0, 0, 0, 0, HZ);	// allow 1 second timeout
+	pdx->ulSelfTestTime = jiffies + HZ * 30;	// 30 seconds into the future
+
+	mutex_unlock(&pdx->io_mutex);
+	if (nGot < 0)
+		dev_err(&pdx->interface->dev, "%s err=%d", __func__, nGot);
+	return nGot < 0 ? U14ERR_FAIL : U14ERR_NOERROR;
+}
+
+/****************************************************************************
+** CheckSelfTest
+**
+** Check progress of a self-test cycle
+****************************************************************************/
+int CheckSelfTest(DEVICE_EXTENSION * pdx, TGET_SELFTEST __user * pGST)
+{
+	unsigned int state, error;
+	int iReturn;
+	TGET_SELFTEST gst;	// local work space
+	memset(&gst, 0, sizeof(gst));	// clear out the space (sets code 0)
+
+	mutex_lock(&pdx->io_mutex);
+
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+	iReturn = Get1401State(pdx, &state, &error);
+	if (iReturn == U14ERR_NOERROR)	// Only accept zero if it happens twice
+		iReturn = Get1401State(pdx, &state, &error);
+
+	if (iReturn != U14ERR_NOERROR)	// Self-test can cause comms errors
+	{			// so we assume still testing
+		dev_err(&pdx->interface->dev,
+			"%s Get1401State=%d, assuming still testing", __func__,
+			iReturn);
+		state = 0x80;	// Force still-testing, no error
+		error = 0;
+		iReturn = U14ERR_NOERROR;
+	}
+
+	if ((state == -1) && (error == -1))	// If Get1401State had problems
+	{
+		dev_err(&pdx->interface->dev,
+			"%s Get1401State failed, assuming still testing",
+			__func__);
+		state = 0x80;	// Force still-testing, no error
+		error = 0;
+	}
+
+	if ((state & 0xFF) == 0x80)	// If we are still in self-test
+	{
+		if (state & 0x00FF0000)	// Have we got an error?
+		{
+			gst.code = (state & 0x00FF0000) >> 16;	// read the error code
+			gst.x = error & 0x0000FFFF;	// Error data X
+			gst.y = (error & 0xFFFF0000) >> 16;	// and data Y
+			dev_dbg(&pdx->interface->dev, "Self-test error code %d",
+				gst.code);
+		} else		// No error, check for timeout
+		{
+			unsigned long ulNow = jiffies;	// get current time
+			if (time_after(ulNow, pdx->ulSelfTestTime)) {
+				gst.code = -2;	// Flag the timeout
+				dev_dbg(&pdx->interface->dev,
+					"Self-test timed-out");
+			} else
+				dev_dbg(&pdx->interface->dev,
+					"Self-test on-going");
+		}
+	} else {
+		gst.code = -1;	// Flag the test is done
+		dev_dbg(&pdx->interface->dev, "Self-test done");
+	}
+
+	if (gst.code < 0)	// If we have a problem or finished
+	{			// If using the 2890 we should reset properly
+		if ((pdx->nPipes == 4) && (pdx->s1401Type <= TYPEPOWER))
+			Is1401(pdx);	// Get 1401 reset and OK
+		else
+			QuickCheck(pdx, true, true);	// Otherwise check without reset unless problems
+	}
+	mutex_unlock(&pdx->io_mutex);
+
+	if (copy_to_user(pGST, &gst, sizeof(gst)))
+		return -EFAULT;
+
+	return iReturn;
+}
+
+/****************************************************************************
+** TypeOf1401
+**
+** Returns code for standard, plus, micro1401, power1401 or none
+****************************************************************************/
+int TypeOf1401(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = TYPEUNKNOWN;
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	switch (pdx->s1401Type) {
+	case TYPE1401:
+		iReturn = U14ERR_STD;
+		break;		// Handle these types directly
+	case TYPEPLUS:
+		iReturn = U14ERR_PLUS;
+		break;
+	case TYPEU1401:
+		iReturn = U14ERR_U1401;
+		break;
+	default:
+		if ((pdx->s1401Type >= TYPEPOWER) && (pdx->s1401Type <= 25))
+			iReturn = pdx->s1401Type + 4;	// We can calculate types
+		else		//  for up-coming 1401 designs
+			iReturn = TYPEUNKNOWN;	// Don't know or not there
+	}
+	dev_dbg(&pdx->interface->dev, "%s %d", __func__, iReturn);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** TransferFlags
+**
+** Returns flags on block transfer abilities
+****************************************************************************/
+int TransferFlags(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = U14TF_MULTIA | U14TF_DIAG |	// we always have multiple DMA area
+	    U14TF_NOTIFY | U14TF_CIRCTH;	// diagnostics, notify and circular
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+	mutex_lock(&pdx->io_mutex);
+	if (pdx->bIsUSB2)	// Set flag for USB2 if appropriate
+		iReturn |= U14TF_USB2;
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/***************************************************************************
+** DbgCmd1401
+** Issues a debug\diagnostic command to the 1401 along with a 32-bit datum
+** This is a utility command used for dbg operations.
+*/
+static int DbgCmd1401(DEVICE_EXTENSION * pdx, unsigned char cmd,
+		      unsigned int data)
+{
+	int iReturn;
+	dev_dbg(&pdx->interface->dev, "%s entry", __func__);
+	iReturn = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), cmd, (H_TO_D | VENDOR | DEVREQ), (unsigned short)data, (unsigned short)(data >> 16), 0, 0, HZ);	// allow 1 second timeout
+	if (iReturn < 0)
+		dev_err(&pdx->interface->dev, "%s fail code=%d", __func__,
+			iReturn);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgPeek
+**
+** Execute the diagnostic peek operation. Uses address, width and repeats.
+****************************************************************************/
+int DbgPeek(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB)
+{
+	int iReturn;
+	TDBGBLOCK db;
+
+	if (copy_from_user(&db, pDB, sizeof(db)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+
+	iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_PEEK, 0);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgPoke
+**
+** Execute the diagnostic poke operation. Parameters are in the CSBLOCK struct
+** in order address, size, repeats and value to poke.
+****************************************************************************/
+int DbgPoke(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB)
+{
+	int iReturn;
+	TDBGBLOCK db;
+
+	if (copy_from_user(&db, pDB, sizeof(db)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+
+	iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_POKE, db.iData);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgRampData
+**
+** Execute the diagnostic ramp data operation. Parameters are in the CSBLOCK struct
+** in order address, default, enable mask, size and repeats.
+****************************************************************************/
+int DbgRampData(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB)
+{
+	int iReturn;
+	TDBGBLOCK db;
+
+	if (copy_from_user(&db, pDB, sizeof(db)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+
+	iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_SETMASK, db.iMask);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_RAMPD, 0);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgRampAddr
+**
+** Execute the diagnostic ramp address operation
+****************************************************************************/
+int DbgRampAddr(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB)
+{
+	int iReturn;
+	TDBGBLOCK db;
+
+	if (copy_from_user(&db, pDB, sizeof(db)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_SETMASK, db.iMask);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats);
+	if (iReturn == U14ERR_NOERROR)
+		iReturn = DbgCmd1401(pdx, DB_RAMPA, 0);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgGetData
+**
+** Retrieve the data resulting from the last debug Peek operation
+****************************************************************************/
+int DbgGetData(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB)
+{
+	int iReturn;
+	TDBGBLOCK db;
+	memset(&db, 0, sizeof(db));	// fill returned block with 0s
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	// Read back the last peeked value from the 1401.
+	iReturn = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0),
+				  DB_DATA, (D_TO_H | VENDOR | DEVREQ), 0, 0,
+				  &db.iData, sizeof(db.iData), HZ);
+	if (iReturn == sizeof(db.iData)) {
+		if (copy_to_user(pDB, &db, sizeof(db)))
+			iReturn = -EFAULT;
+		else
+			iReturn = U14ERR_NOERROR;
+	} else
+		dev_err(&pdx->interface->dev, "%s failed, code %d", __func__,
+			iReturn);
+
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** DbgStopLoop
+**
+** Stop any never-ending debug loop, we just call Get1401State for USB
+**
+****************************************************************************/
+int DbgStopLoop(DEVICE_EXTENSION * pdx)
+{
+	int iReturn;
+	unsigned int uState, uErr;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+	iReturn = Get1401State(pdx, &uState, &uErr);
+	mutex_unlock(&pdx->io_mutex);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** SetCircular
+**
+** Sets up a transfer area record for circular transfers. If the area is
+** already set, we attempt to unset it. Unsetting will fail if the area is
+** booked and a transfer to that area is in progress. Otherwise, we will
+** release the area and re-assign it.
+****************************************************************************/
+int SetCircular(DEVICE_EXTENSION * pdx, TRANSFERDESC __user * pTD)
+{
+	int iReturn;
+	bool bToHost;
+	TRANSFERDESC td;
+
+	if (copy_from_user(&td, pTD, sizeof(td)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__,
+		td.wAreaNum, td.dwLength);
+	bToHost = td.eSize != 0;	// this is used as the tohost flag
+
+	// The strange cast is done so that we don't get warnings in 32-bit linux about the size of the
+	// pointer. The pointer is always passed as a 64-bit object so that we don't have problems using
+	// a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system.
+	iReturn =
+	    SetArea(pdx, td.wAreaNum,
+		    (char __user *)((unsigned long)td.lpvBuff), td.dwLength,
+		    true, bToHost);
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/****************************************************************************
+** GetCircBlock
+**
+** Return the next available block of circularly-transferred data.
+****************************************************************************/
+int GetCircBlock(DEVICE_EXTENSION * pdx, TCIRCBLOCK __user * pCB)
+{
+	int iReturn = U14ERR_NOERROR;
+	unsigned int nArea;
+	TCIRCBLOCK cb;
+
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	if (copy_from_user(&cb, pCB, sizeof(cb)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+
+	nArea = cb.nArea;	// Retrieve parameters first
+	cb.dwOffset = 0;	// set default result (nothing)
+	cb.dwSize = 0;
+
+	if (nArea < MAX_TRANSAREAS)	// The area number must be OK
+	{
+		TRANSAREA *pArea = &pdx->rTransDef[nArea];	// Pointer to relevant info
+		spin_lock_irq(&pdx->stagedLock);	// Lock others out
+
+		if ((pArea->bUsed) && (pArea->bCircular) &&	// Must be circular area
+		    (pArea->bCircToHost))	// For now at least must be to host
+		{
+			if (pArea->aBlocks[0].dwSize > 0)	// Got anything?
+			{
+				cb.dwOffset = pArea->aBlocks[0].dwOffset;
+				cb.dwSize = pArea->aBlocks[0].dwSize;
+				dev_dbg(&pdx->interface->dev,
+					"%s return block 0: %d bytes at %d",
+					__func__, cb.dwSize, cb.dwOffset);
+			}
+		} else
+			iReturn = U14ERR_NOTSET;
+
+		spin_unlock_irq(&pdx->stagedLock);
+	} else
+		iReturn = U14ERR_BADAREA;
+
+	if (copy_to_user(pCB, &cb, sizeof(cb)))
+		iReturn = -EFAULT;
+
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
+
+/****************************************************************************
+** FreeCircBlock
+**
+** Frees a block of circularly-transferred data and returns the next one.
+****************************************************************************/
+int FreeCircBlock(DEVICE_EXTENSION * pdx, TCIRCBLOCK __user * pCB)
+{
+	int iReturn = U14ERR_NOERROR;
+	unsigned int nArea, uStart, uSize;
+	TCIRCBLOCK cb;
+
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	if (copy_from_user(&cb, pCB, sizeof(cb)))
+		return -EFAULT;
+
+	mutex_lock(&pdx->io_mutex);
+
+	nArea = cb.nArea;	// Retrieve parameters first
+	uStart = cb.dwOffset;
+	uSize = cb.dwSize;
+	cb.dwOffset = 0;	// then set default result (nothing)
+	cb.dwSize = 0;
+
+	if (nArea < MAX_TRANSAREAS)	// The area number must be OK
+	{
+		TRANSAREA *pArea = &pdx->rTransDef[nArea];	// Pointer to relevant info
+		spin_lock_irq(&pdx->stagedLock);	// Lock others out
+
+		if ((pArea->bUsed) && (pArea->bCircular) &&	// Must be circular area
+		    (pArea->bCircToHost))	// For now at least must be to host
+		{
+			bool bWaiting = false;
+
+			if ((pArea->aBlocks[0].dwSize >= uSize) &&	// Got anything?
+			    (pArea->aBlocks[0].dwOffset == uStart))	// Must be legal data
+			{
+				pArea->aBlocks[0].dwSize -= uSize;
+				pArea->aBlocks[0].dwOffset += uSize;
+				if (pArea->aBlocks[0].dwSize == 0)	// Have we emptied this block?
+				{
+					if (pArea->aBlocks[1].dwSize)	// Is there a second block?
+					{
+						pArea->aBlocks[0] = pArea->aBlocks[1];	// Copy down block 2 data
+						pArea->aBlocks[1].dwSize = 0;	// and mark the second block as unused
+						pArea->aBlocks[1].dwOffset = 0;
+					} else
+						pArea->aBlocks[0].dwOffset = 0;
+				}
+
+				dev_dbg(&pdx->interface->dev,
+					"%s free %d bytes at %d, return %d bytes at %d, wait=%d",
+					__func__, uSize, uStart,
+					pArea->aBlocks[0].dwSize,
+					pArea->aBlocks[0].dwOffset,
+					pdx->bXFerWaiting);
+
+				// Return the next available block of memory as well
+				if (pArea->aBlocks[0].dwSize > 0)	// Got anything?
+				{
+					cb.dwOffset =
+					    pArea->aBlocks[0].dwOffset;
+					cb.dwSize = pArea->aBlocks[0].dwSize;
+				}
+
+				bWaiting = pdx->bXFerWaiting;
+				if (bWaiting && pdx->bStagedUrbPending) {
+					dev_err(&pdx->interface->dev,
+						"%s ERROR: waiting xfer and staged Urb pending!",
+						__func__);
+					bWaiting = false;
+				}
+			} else {
+				dev_err(&pdx->interface->dev,
+					"%s ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d",
+					__func__, uSize, uStart,
+					pArea->aBlocks[0].dwSize,
+					pArea->aBlocks[0].dwOffset);
+				iReturn = U14ERR_NOMEMORY;
+			}
+
+			// If we have one, kick off pending transfer
+			if (bWaiting)	// Got a block xfer waiting?
+			{
+				int RWMStat =
+				    ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard,
+						 pdx->rDMAInfo.wIdent,
+						 pdx->rDMAInfo.dwOffset,
+						 pdx->rDMAInfo.dwSize);
+				if (RWMStat != U14ERR_NOERROR)
+					dev_err(&pdx->interface->dev,
+						"%s rw setup failed %d",
+						__func__, RWMStat);
+			}
+		} else
+			iReturn = U14ERR_NOTSET;
+
+		spin_unlock_irq(&pdx->stagedLock);
+	} else
+		iReturn = U14ERR_BADAREA;
+
+	if (copy_to_user(pCB, &cb, sizeof(cb)))
+		return -EFAULT;
+
+	mutex_unlock(&pdx->io_mutex);
+	return iReturn;
+}
diff --git a/drivers/staging/ced1401/ced_ioctl.h b/drivers/staging/ced1401/ced_ioctl.h
new file mode 100644
index 0000000..0895c941
--- /dev/null
+++ b/drivers/staging/ced1401/ced_ioctl.h
@@ -0,0 +1,345 @@
+/*
+ * IOCTL calls for the CED1401 driver
+ * Copyright (C) 2010 Cambridge Electronic Design Ltd
+ * Author Greg P Smith (greg@ced.co.uk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 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.
+ */
+#ifndef __CED_IOCTL_H__
+#define __CED_IOCTL_H__
+
+#include <linux/ioctl.h>
+
+/* dma modes, only MODE_CHAR and MODE_LINEAR are used in this driver */
+#define MODE_CHAR		0
+#define MODE_LINEAR		1
+
+/****************************************************************************
+** TypeDefs
+*****************************************************************************/
+
+typedef unsigned short TBLOCKENTRY;	/* index the blk transfer table 0-7 */
+
+typedef struct TransferDesc {
+	long long lpvBuff;	/* address of transfer area (for 64 or 32 bit) */
+	unsigned int dwLength;	/* length of the area */
+	TBLOCKENTRY wAreaNum;	/* number of transfer area to set up */
+	short eSize;		/* element size - is tohost flag for circular */
+} TRANSFERDESC;
+
+typedef TRANSFERDESC * LPTRANSFERDESC;
+
+typedef struct TransferEvent {
+	unsigned int dwStart;		/* offset into the area */
+	unsigned int dwLength;		/* length of the region */
+	unsigned short wAreaNum;	/* the area number */
+	unsigned short wFlags;		/* bit 0 set for toHost */
+	int iSetEvent;			/* could be dummy in LINUX */
+} TRANSFEREVENT;
+
+#define MAX_TRANSFER_SIZE	0x4000		/* Maximum data bytes per IRP */
+#define MAX_AREA_LENGTH		0x100000	/* Maximum size of transfer area */
+#define MAX_TRANSAREAS		8		/* definitions for dma set up  */
+
+typedef struct TGetSelfTest {
+	int code;			/* self-test error code */
+	int x, y;			/* additional information */
+} TGET_SELFTEST;
+
+/* Debug block used for several commands. Not all fields are used for all commands. */
+typedef struct TDbgBlock {
+	int iAddr;			/* the address in the 1401 */
+	int iRepeats;			/* number of repeats */
+	int iWidth;			/* width in bytes 1, 2, 4 */
+	int iDefault;			/* default value */
+	int iMask;			/* mask to apply */
+	int iData;			/* data for poke, result for peek */
+} TDBGBLOCK;
+
+/* Used to collect information about a circular block from the device driver */
+typedef struct TCircBlock {
+	unsigned int nArea;		/* the area to collect information from */
+	unsigned int dwOffset;		/* offset into the area to the available block */
+	unsigned int dwSize;		/* size of the area */
+} TCIRCBLOCK;
+
+/* Used to clollect the 1401 status */
+typedef struct TCSBlock {
+	unsigned int uiState;
+	unsigned int uiError;
+} TCSBLOCK;
+
+/*
+ * As seen by the user, an ioctl call looks like: int ioctl(int fd, unsigned
+ * long cmd, char* argp); We will then have all sorts of variants on this that
+ * can be used to pass stuff to our driver. We will generate macros for each
+ * type of call so as to provide some sort of type safety in the calling:
+ */
+#define CED_MAGIC_IOC 0xce
+
+/* NBNB: READ and WRITE are from the point of view of the device, not user. */
+typedef struct ced_ioc_string {
+	int nChars;
+	char buffer[256];
+} CED_IOC_STRING;
+
+#define IOCTL_CED_SENDSTRING(n)		_IOC(_IOC_WRITE, CED_MAGIC_IOC, 2, n)
+
+#define IOCTL_CED_RESET1401		_IO(CED_MAGIC_IOC, 3)
+#define IOCTL_CED_GETCHAR		_IO(CED_MAGIC_IOC, 4)
+#define IOCTL_CED_SENDCHAR		_IO(CED_MAGIC_IOC, 5)
+#define IOCTL_CED_STAT1401		_IO(CED_MAGIC_IOC, 6)
+#define IOCTL_CED_LINECOUNT		_IO(CED_MAGIC_IOC, 7)
+#define IOCTL_CED_GETSTRING(nMax)	_IOC(_IOC_READ, CED_MAGIC_IOC, 8, nMax)
+
+#define IOCTL_CED_SETTRANSFER		_IOW(CED_MAGIC_IOC, 11, TRANSFERDESC)
+#define IOCTL_CED_UNSETTRANSFER		_IO(CED_MAGIC_IOC, 12)
+#define IOCTL_CED_SETEVENT		_IOW(CED_MAGIC_IOC, 13, TRANSFEREVENT)
+#define IOCTL_CED_GETOUTBUFSPACE	_IO(CED_MAGIC_IOC, 14)
+#define IOCTL_CED_GETBASEADDRESS	_IO(CED_MAGIC_IOC, 15)
+#define IOCTL_CED_GETDRIVERREVISION	_IO(CED_MAGIC_IOC, 16)
+
+#define IOCTL_CED_GETTRANSFER		_IOR(CED_MAGIC_IOC, 17, TGET_TX_BLOCK)
+#define IOCTL_CED_KILLIO1401		_IO(CED_MAGIC_IOC, 18)
+#define IOCTL_CED_BLKTRANSSTATE		_IO(CED_MAGIC_IOC, 19)
+
+#define IOCTL_CED_STATEOF1401		_IO(CED_MAGIC_IOC, 23)
+#define IOCTL_CED_GRAB1401		_IO(CED_MAGIC_IOC, 25)
+#define IOCTL_CED_FREE1401		_IO(CED_MAGIC_IOC, 26)
+#define IOCTL_CED_STARTSELFTEST		_IO(CED_MAGIC_IOC, 31)
+#define IOCTL_CED_CHECKSELFTEST		_IOR(CED_MAGIC_IOC, 32, TGET_SELFTEST)
+#define IOCTL_CED_TYPEOF1401		_IO(CED_MAGIC_IOC, 33)
+#define IOCTL_CED_TRANSFERFLAGS		_IO(CED_MAGIC_IOC, 34)
+
+#define IOCTL_CED_DBGPEEK		_IOW(CED_MAGIC_IOC, 35, TDBGBLOCK)
+#define IOCTL_CED_DBGPOKE		_IOW(CED_MAGIC_IOC, 36, TDBGBLOCK)
+#define IOCTL_CED_DBGRAMPDATA		_IOW(CED_MAGIC_IOC, 37, TDBGBLOCK)
+#define IOCTL_CED_DBGRAMPADDR		_IOW(CED_MAGIC_IOC, 38, TDBGBLOCK)
+#define IOCTL_CED_DBGGETDATA		_IOR(CED_MAGIC_IOC, 39, TDBGBLOCK)
+#define IOCTL_CED_DBGSTOPLOOP		_IO(CED_MAGIC_IOC, 40)
+#define IOCTL_CED_FULLRESET		_IO(CED_MAGIC_IOC, 41)
+#define IOCTL_CED_SETCIRCULAR		_IOW(CED_MAGIC_IOC, 42, TRANSFERDESC)
+#define IOCTL_CED_GETCIRCBLOCK		_IOWR(CED_MAGIC_IOC, 43, TCIRCBLOCK)
+#define IOCTL_CED_FREECIRCBLOCK		_IOWR(CED_MAGIC_IOC, 44, TCIRCBLOCK)
+#define IOCTL_CED_WAITEVENT		_IO(CED_MAGIC_IOC, 45)
+#define IOCTL_CED_TESTEVENT		_IO(CED_MAGIC_IOC, 46)
+
+#ifndef __KERNEL__
+/*
+ * If nothing said about return value, it is a U14ERR_... error code
+ * (U14ERR_NOERROR for none)
+ */
+inline int CED_SendString(int fh, const char *szText, int n)
+{
+	return ioctl(fh, IOCTL_CED_SENDSTRING(n), szText);
+}
+
+inline int CED_Reset1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_RESET1401);
+}
+
+/* Return the singe character or a -ve error code. */
+inline int CED_GetChar(int fh)
+{
+	return ioctl(fh, IOCTL_CED_GETCHAR);
+}
+
+/* Return character count in input buffer */
+inline int CED_Stat1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_STAT1401);
+}
+
+inline int CED_SendChar(int fh, char c)
+{
+	return ioctl(fh, IOCTL_CED_SENDCHAR, c);
+}
+
+inline int CED_LineCount(int fh)
+{
+	return ioctl(fh, IOCTL_CED_LINECOUNT);
+}
+
+/*
+ * return the count of characters returned. If the string was terminated by CR
+ * or 0, then the 0 is part of the count. Otherwise, we will add a zero if
+ * there is room, but it is not included in the count.  The return value is 0
+ * if there was nothing to read.
+ */
+inline int CED_GetString(int fh, char *szText, int nMax)
+{
+	return ioctl(fh, IOCTL_CED_GETSTRING(nMax), szText);
+}
+
+/* returns space in the output buffer. */
+inline int CED_GetOutBufSpace(int fh)
+{
+	return ioctl(fh, IOCTL_CED_GETOUTBUFSPACE);
+}
+
+/* This always returns -1 as not implemented. */
+inline int CED_GetBaseAddress(int fh)
+{
+	return ioctl(fh, IOCTL_CED_GETBASEADDRESS);
+}
+
+/* returns the major revision <<16 | minor revision. */
+inline int CED_GetDriverRevision(int fh)
+{
+	return ioctl(fh, IOCTL_CED_GETDRIVERREVISION);
+}
+
+inline int CED_SetTransfer(int fh, TRANSFERDESC *pTD)
+{
+	return ioctl(fh, IOCTL_CED_SETTRANSFER, pTD);
+}
+
+inline int CED_UnsetTransfer(int fh, int nArea)
+{
+	return ioctl(fh, IOCTL_CED_UNSETTRANSFER, nArea);
+}
+
+inline int CED_SetEvent(int fh, TRANSFEREVENT *pTE)
+{
+	return ioctl(fh, IOCTL_CED_SETEVENT, pTE);
+}
+
+inline int CED_GetTransfer(int fh, TGET_TX_BLOCK *pTX)
+{
+	return ioctl(fh, IOCTL_CED_GETTRANSFER, pTX);
+}
+
+inline int CED_KillIO1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_KILLIO1401);
+}
+
+/* returns 0 if no active DMA, 1 if active */
+inline int CED_BlkTransState(int fh)
+{
+	return ioctl(fh, IOCTL_CED_BLKTRANSSTATE);
+}
+
+inline int CED_StateOf1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_STATEOF1401);
+}
+
+inline int CED_Grab1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_GRAB1401);
+}
+
+inline int CED_Free1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_FREE1401);
+}
+
+inline int CED_StartSelfTest(int fh)
+{
+	return ioctl(fh, IOCTL_CED_STARTSELFTEST);
+}
+
+inline int CED_CheckSelfTest(int fh, TGET_SELFTEST *pGST)
+{
+	return ioctl(fh, IOCTL_CED_CHECKSELFTEST, pGST);
+}
+
+inline int CED_TypeOf1401(int fh)
+{
+	return ioctl(fh, IOCTL_CED_TYPEOF1401);
+}
+
+inline int CED_TransferFlags(int fh)
+{
+	return ioctl(fh, IOCTL_CED_TRANSFERFLAGS);
+}
+
+inline int CED_DbgPeek(int fh, TDBGBLOCK *pDB)
+{
+	return ioctl(fh, IOCTL_CED_DBGPEEK, pDB);
+}
+
+inline int CED_DbgPoke(int fh, TDBGBLOCK *pDB)
+{
+	return ioctl(fh, IOCTL_CED_DBGPOKE, pDB);
+}
+
+inline int CED_DbgRampData(int fh, TDBGBLOCK *pDB)
+{
+	return ioctl(fh, IOCTL_CED_DBGRAMPDATA, pDB);
+}
+
+inline int CED_DbgRampAddr(int fh, TDBGBLOCK *pDB)
+{
+	return ioctl(fh, IOCTL_CED_DBGRAMPADDR, pDB);
+}
+
+inline int CED_DbgGetData(int fh, TDBGBLOCK *pDB)
+{
+	return ioctl(fh, IOCTL_CED_DBGGETDATA, pDB);
+}
+
+inline int CED_DbgStopLoop(int fh)
+{
+	return ioctl(fh, IOCTL_CED_DBGSTOPLOOP);
+}
+
+inline int CED_FullReset(int fh)
+{
+	return ioctl(fh, IOCTL_CED_FULLRESET);
+}
+
+inline int CED_SetCircular(int fh, TRANSFERDESC *pTD)
+{
+	return ioctl(fh, IOCTL_CED_SETCIRCULAR, pTD);
+}
+
+inline int CED_GetCircBlock(int fh, TCIRCBLOCK *pCB)
+{
+	return ioctl(fh, IOCTL_CED_GETCIRCBLOCK, pCB);
+}
+
+inline int CED_FreeCircBlock(int fh, TCIRCBLOCK *pCB)
+{
+	return ioctl(fh, IOCTL_CED_FREECIRCBLOCK, pCB);
+}
+
+inline int CED_WaitEvent(int fh, int nArea, int msTimeOut)
+{
+	return ioctl(fh, IOCTL_CED_WAITEVENT, (nArea & 0xff)|(msTimeOut << 8));
+}
+
+inline int CED_TestEvent(int fh, int nArea)
+{
+	return ioctl(fh, IOCTL_CED_TESTEVENT, nArea);
+}
+#endif
+
+#ifdef NOTWANTEDYET
+#define IOCTL_CED_REGCALLBACK		_IO(CED_MAGIC_IOC, 9)	/* Not used */
+#define IOCTL_CED_GETMONITORBUF		_IO(CED_MAGIC_IOC, 10)	/* Not used */
+
+#define IOCTL_CED_BYTECOUNT		_IO(CED_MAGIC_IOC, 20)	/* Not used */
+#define IOCTL_CED_ZEROBLOCKCOUNT	_IO(CED_MAGIC_IOC, 21)	/* Not used */
+#define IOCTL_CED_STOPCIRCULAR		_IO(CED_MAGIC_IOC, 22)	/* Not used */
+
+#define IOCTL_CED_REGISTERS1401		_IO(CED_MAGIC_IOC, 24)	/* Not used */
+#define IOCTL_CED_STEP1401		_IO(CED_MAGIC_IOC, 27)	/* Not used */
+#define IOCTL_CED_SET1401REGISTERS	_IO(CED_MAGIC_IOC, 28)	/* Not used */
+#define IOCTL_CED_STEPTILL1401		_IO(CED_MAGIC_IOC, 29)	/* Not used */
+#define IOCTL_CED_SETORIN		_IO(CED_MAGIC_IOC, 30)	/* Not used */
+
+#endif
+
+/* __CED_IOCTL_H__ */
+#endif
diff --git a/drivers/staging/ced1401/machine.h b/drivers/staging/ced1401/machine.h
new file mode 100644
index 0000000..af07379
--- /dev/null
+++ b/drivers/staging/ced1401/machine.h
@@ -0,0 +1,127 @@
+/*****************************************************************************
+**
+** machine.h
+**
+** Copyright (c) Cambridge Electronic Design Limited 1991,1992,2010
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License
+** as published by the Free Software Foundation; either version 2
+** of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+**
+** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road
+**              Cambridge, CB6 0FE.
+**              www.ced.co.uk
+**              greg@ced.co.uk
+**
+** This file is included at the start of 'C' or 'C++' source file to define
+** things for cross-platform/compiler interoperability. This used to deal with
+** MSDOS/16-bit stuff, but this was all removed in Decemeber 2010. There are
+** three things to consider: Windows, LINUX, mac OSX (BSD Unix) and 32 vs 64
+** bit. At the time of writing (DEC 2010) there is a consensus on the following
+** and their unsigned equivalents:
+**
+** type       bits
+** char         8
+** short       16
+** int         32
+** long long   64
+**
+** long is a problem as it is always 64 bits on linux/unix and is always 32 bits
+** on windows.
+** On windows, we define _IS_WINDOWS_ and one of WIN32 or WIN64.
+** On linux we define LINUX
+** On Max OSX we define MACOSX
+**
+*/
+
+#ifndef __MACHINE_H__
+#define __MACHINE_H__
+#ifndef __KERNEL__
+#include <float.h>
+#include <limits.h>
+#endif
+
+/*
+** The initial section is to identify the operating system
+*/
+#if (defined(__linux__) || defined(_linux) || defined(__linux)) && !defined(LINUX)
+#define LINUX 1
+#endif
+
+#if (defined(__WIN32__) || defined(_WIN32)) && !defined(WIN32)
+#define WIN32 1
+#endif
+
+#if defined(__APPLE__)
+#define MACOSX
+#endif
+
+#if defined(_WIN64)
+#undef WIN32
+#undef WIN64
+#define WIN64 1
+#endif
+
+#if defined(WIN32) || defined(WIN64)
+#define _IS_WINDOWS_ 1
+#endif
+
+#if defined(LINUX) || defined(MAXOSX)
+    #define FAR
+
+    typedef int BOOL;       // To match Windows
+    typedef char * LPSTR;
+    typedef const char * LPCSTR;
+    typedef unsigned short WORD;
+    typedef unsigned int  DWORD;
+    typedef unsigned char  BYTE;
+    typedef BYTE  BOOLEAN;
+    typedef unsigned char UCHAR;
+    #define __packed __attribute__((packed))
+    typedef BYTE * LPBYTE;
+    #define HIWORD(x) (WORD)(((x)>>16) & 0xffff)
+    #define LOWORD(x) (WORD)((x) & 0xffff)
+#endif
+
+#ifdef _IS_WINDOWS_
+#include <windows.h>
+#define __packed
+#endif
+
+/*
+** Sort out the DllExport and DllImport macros. The GCC compiler has its own
+** syntax for this, though it also supports the MS specific __declspec() as
+** a synonym.
+*/
+#ifdef GNUC
+    #define DllExport __attribute__((dllexport))
+    #define DllImport __attribute__((dllimport))
+#endif
+
+#ifndef DllExport
+#ifdef _IS_WINDOWS_
+    #define DllExport __declspec(dllexport)
+    #define DllImport __declspec(dllimport)
+#else
+    #define DllExport
+    #define DllImport
+#endif
+#endif /* _IS_WINDOWS_ */
+
+    
+#ifndef TRUE
+   #define TRUE 1
+   #define FALSE 0
+#endif
+
+#endif
diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c
new file mode 100644
index 0000000..6ba0ef6
--- /dev/null
+++ b/drivers/staging/ced1401/usb1401.c
@@ -0,0 +1,1637 @@
+/***********************************************************************************
+ CED1401 usb driver. This basic loading is based on the usb-skeleton.c code that is:
+ Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ Copyright (C) 2012 Alois Schloegl <alois.schloegl@ist.ac.at>
+ There is not a great deal of the skeleton left.
+
+ All the remainder dealing specifically with the CED1401 is based on drivers written
+ by CED for other systems (mainly Windows) and is:
+ Copyright (C) 2010 Cambridge Electronic Design Ltd
+ Author Greg P Smith (greg@ced.co.uk)
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Endpoints
+*********
+There are 4 endpoints plus the control endpoint in the standard interface
+provided by most 1401s. The control endpoint is used for standard USB requests,
+plus various CED-specific transactions such as start self test, debug and get
+the 1401 status. The other endpoints are:
+
+ 1 Characters to the 1401
+ 2 Characters from the 1401
+ 3 Block data to the 1401
+ 4 Block data to the host.
+
+inside the driver these are indexed as an array from 0 to 3, transactions
+over the control endpoint are carried out using a separate mechanism. The
+use of the endpoints is mostly straightforward, with the driver issuing
+IO request packets (IRPs) as required to transfer data to and from the 1401.
+The handling of endpoint 2 is different because it is used for characters
+from the 1401, which can appear spontaneously and without any other driver
+activity - for example to repeatedly request DMA transfers in Spike2. The
+desired effect is achieved by using an interrupt endpoint which can be
+polled to see if it has data available, and writing the driver so that it
+always maintains a pending read IRP from that endpoint which will read the
+character data and terminate as soon as the 1401 makes data available. This
+works very well, some care is taken with when you kick off this character
+read IRP to avoid it being active when it is not wanted but generally it
+is running all the time.
+
+In the 2270, there are only three endpoints plus the control endpoint. In
+addition to the transactions mentioned above, the control endpoint is used
+to transfer character data to the 1401. The other endpoints are used as:
+
+ 1 Characters from the 1401
+ 2 Block data to the 1401
+ 3 Block data to the host.
+
+The type of interface available is specified by the interface subclass field
+in the interface descriptor provided by the 1401. See the USB_INT_ constants
+for the values that this field can hold.
+
+****************************************************************************
+Linux implementation
+
+Although Linux Device Drivers (3rd Edition) was a major source of information,
+it is very out of date. A lot of information was gleaned from the latest
+usb_skeleton.c code (you need to download the kernel sources to get this).
+
+To match the Windows version, everything is done using ioctl calls. All the
+device state is held in the DEVICE_EXTENSION (named to match Windows use).
+Block transfers are done by using get_user_pages() to pin down a list of
+pages that we hold a pointer to in the device driver. We also allocate a
+coherent transfer buffer of size STAGED_SZ (this must be a multiple of the
+bulk endpoint size so that the 1401 does not realise that we break large
+transfers down into smaller pieces). We use kmap_atomic() to get a kernel
+va for each page, as it is required, for copying; see CopyUserSpace().
+
+All character and data transfers are done using asynchronous IO. All Urbs are
+tracked by anchoring them. Status and debug ioctls are implemented with the
+synchronous non-Urb based transfers.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/version.h>
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) )
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#endif
+
+#include "usb1401.h"
+
+/* Define these values to match your devices */
+#define USB_CED_VENDOR_ID	0x0525
+#define USB_CED_PRODUCT_ID	0xa0f0
+
+/* table of devices that work with this driver */
+static const struct usb_device_id ced_table[] = {
+	{USB_DEVICE(USB_CED_VENDOR_ID, USB_CED_PRODUCT_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ced_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_CED_MINOR_BASE	192
+
+/* our private defines. if this grows any larger, use your own .h file */
+#define MAX_TRANSFER		(PAGE_SIZE - 512)
+/* MAX_TRANSFER is chosen so that the VM is not stressed by
+   allocations > PAGE_SIZE and the number of packets in a page
+   is an integer 512 is the largest possible packet on EHCI */
+#define WRITES_IN_FLIGHT	8
+/* arbitrarily chosen */
+
+/* 
+The cause for these errors is that the driver makes use of the functions usb_buffer_alloc() and usb_buffer_free() which got renamed in kernel 2.6.35. This is stated in the Changelog:   USB: rename usb_buffer_alloc() and usb_buffer_free() users
+    For more clearance what the functions actually do,
+      usb_buffer_alloc() is renamed to usb_alloc_coherent()
+      usb_buffer_free()  is renamed to usb_free_coherent()
+   This is needed on Debian 2.6.32-5-amd64
+*/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) )
+#define usb_alloc_coherent usb_buffer_alloc
+#define usb_free_coherent  usb_buffer_free
+#define noop_llseek NULL
+#endif
+
+static struct usb_driver ced_driver;
+
+static void ced_delete(struct kref *kref)
+{
+	DEVICE_EXTENSION *pdx = to_DEVICE_EXTENSION(kref);
+
+	// Free up the output buffer, then free the output urb. Note that the interface member
+	// of pdx will probably be NULL, so cannot be used to get to dev.
+	usb_free_coherent(pdx->udev, OUTBUF_SZ, pdx->pCoherCharOut,
+			  pdx->pUrbCharOut->transfer_dma);
+	usb_free_urb(pdx->pUrbCharOut);
+
+	// Do the same for chan input
+	usb_free_coherent(pdx->udev, INBUF_SZ, pdx->pCoherCharIn,
+			  pdx->pUrbCharIn->transfer_dma);
+	usb_free_urb(pdx->pUrbCharIn);
+
+	// Do the same for the block transfers
+	usb_free_coherent(pdx->udev, STAGED_SZ, pdx->pCoherStagedIO,
+			  pdx->pStagedUrb->transfer_dma);
+	usb_free_urb(pdx->pStagedUrb);
+
+	usb_put_dev(pdx->udev);
+	kfree(pdx);
+}
+
+// This is the driver end of the open() call from user space.
+static int ced_open(struct inode *inode, struct file *file)
+{
+	DEVICE_EXTENSION *pdx;
+	int retval = 0;
+	int subminor = iminor(inode);
+	struct usb_interface *interface =
+	    usb_find_interface(&ced_driver, subminor);
+	if (!interface) {
+		pr_err("%s - error, can't find device for minor %d", __func__,
+		       subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	pdx = usb_get_intfdata(interface);
+	if (!pdx) {
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	dev_dbg(&interface->dev, "%s got pdx", __func__);
+
+	/* increment our usage count for the device */
+	kref_get(&pdx->kref);
+
+	/* lock the device to allow correctly handling errors
+	 * in resumption */
+	mutex_lock(&pdx->io_mutex);
+
+	if (!pdx->open_count++) {
+		retval = usb_autopm_get_interface(interface);
+		if (retval) {
+			pdx->open_count--;
+			mutex_unlock(&pdx->io_mutex);
+			kref_put(&pdx->kref, ced_delete);
+			goto exit;
+		}
+	} else {		//uncomment this block if you want exclusive open
+		dev_err(&interface->dev, "%s fail: already open", __func__);
+		retval = -EBUSY;
+		pdx->open_count--;
+		mutex_unlock(&pdx->io_mutex);
+		kref_put(&pdx->kref, ced_delete);
+		goto exit;
+	}
+	/* prevent the device from being autosuspended */
+
+	/* save our object in the file's private structure */
+	file->private_data = pdx;
+	mutex_unlock(&pdx->io_mutex);
+
+exit:
+	return retval;
+}
+
+static int ced_release(struct inode *inode, struct file *file)
+{
+	DEVICE_EXTENSION *pdx = file->private_data;
+	if (pdx == NULL)
+		return -ENODEV;
+
+	dev_dbg(&pdx->interface->dev, "%s called", __func__);
+	mutex_lock(&pdx->io_mutex);
+	if (!--pdx->open_count && pdx->interface)	// Allow autosuspend
+		usb_autopm_put_interface(pdx->interface);
+	mutex_unlock(&pdx->io_mutex);
+
+	kref_put(&pdx->kref, ced_delete);	// decrement the count on our device
+	return 0;
+}
+
+static int ced_flush(struct file *file, fl_owner_t id)
+{
+	int res;
+	DEVICE_EXTENSION *pdx = file->private_data;
+	if (pdx == NULL)
+		return -ENODEV;
+
+	dev_dbg(&pdx->interface->dev, "%s char in pend=%d", __func__,
+		pdx->bReadCharsPending);
+
+	/* wait for io to stop */
+	mutex_lock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s got io_mutex", __func__);
+	ced_draw_down(pdx);
+
+	/* read out errors, leave subsequent opens a clean slate */
+	spin_lock_irq(&pdx->err_lock);
+	res = pdx->errors ? (pdx->errors == -EPIPE ? -EPIPE : -EIO) : 0;
+	pdx->errors = 0;
+	spin_unlock_irq(&pdx->err_lock);
+
+	mutex_unlock(&pdx->io_mutex);
+	dev_dbg(&pdx->interface->dev, "%s exit reached", __func__);
+
+	return res;
+}
+
+/***************************************************************************
+** CanAcceptIoRequests
+** If the device is removed, interface is set NULL. We also clear our pointer
+** from the interface, so we should make sure that pdx is not NULL. This will
+** not help with a device extension held by a file.
+** return true if can accept new io requests, else false
+*/
+static bool CanAcceptIoRequests(DEVICE_EXTENSION * pdx)
+{
+	return pdx && pdx->interface;	// Can we accept IO requests
+}
+
+/****************************************************************************
+** Callback routine to complete writes. This may need to fire off another
+** urb to complete the transfer.
+****************************************************************************/
+static void ced_writechar_callback(struct urb *pUrb)
+{
+	DEVICE_EXTENSION *pdx = pUrb->context;
+	int nGot = pUrb->actual_length;	// what we transferred
+
+	if (pUrb->status) {	// sync/async unlink faults aren't errors
+		if (!
+		    (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
+		     || pUrb->status == -ESHUTDOWN)) {
+			dev_err(&pdx->interface->dev,
+				"%s - nonzero write bulk status received: %d",
+				__func__, pUrb->status);
+		}
+
+		spin_lock(&pdx->err_lock);
+		pdx->errors = pUrb->status;
+		spin_unlock(&pdx->err_lock);
+		nGot = 0;	//  and tidy up again if so
+
+		spin_lock(&pdx->charOutLock);	// already at irq level
+		pdx->dwOutBuffGet = 0;	// Reset the output buffer
+		pdx->dwOutBuffPut = 0;
+		pdx->dwNumOutput = 0;	// Clear the char count
+		pdx->bPipeError[0] = 1;	// Flag an error for later
+		pdx->bSendCharsPending = false;	// Allow other threads again
+		spin_unlock(&pdx->charOutLock);	// already at irq level
+		dev_dbg(&pdx->interface->dev,
+			"%s - char out done, 0 chars sent", __func__);
+	} else {
+		dev_dbg(&pdx->interface->dev,
+			"%s - char out done, %d chars sent", __func__, nGot);
+		spin_lock(&pdx->charOutLock);	// already at irq level
+		pdx->dwNumOutput -= nGot;	// Now adjust the char send buffer
+		pdx->dwOutBuffGet += nGot;	// to match what we did
+		if (pdx->dwOutBuffGet >= OUTBUF_SZ)	// Can't do this any earlier as data could be overwritten
+			pdx->dwOutBuffGet = 0;
+
+		if (pdx->dwNumOutput > 0)	// if more to be done...
+		{
+			int nPipe = 0;	// The pipe number to use
+			int iReturn;
+			char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet];
+			unsigned int dwCount = pdx->dwNumOutput;	// maximum to send
+			if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ)	// does it cross buffer end?
+				dwCount = OUTBUF_SZ - pdx->dwOutBuffGet;
+			spin_unlock(&pdx->charOutLock);	// we are done with stuff that changes
+			memcpy(pdx->pCoherCharOut, pDat, dwCount);	// copy output data to the buffer
+			usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev,
+					  usb_sndbulkpipe(pdx->udev,
+							  pdx->epAddr[0]),
+					  pdx->pCoherCharOut, dwCount,
+					  ced_writechar_callback, pdx);
+			pdx->pUrbCharOut->transfer_flags |=
+			    URB_NO_TRANSFER_DMA_MAP;
+			usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted);	// in case we need to kill it
+			iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC);
+			dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__,
+				dwCount, pDat);
+			spin_lock(&pdx->charOutLock);	// grab lock for errors
+			if (iReturn) {
+				pdx->bPipeError[nPipe] = 1;	// Flag an error to be handled later
+				pdx->bSendCharsPending = false;	// Allow other threads again
+				usb_unanchor_urb(pdx->pUrbCharOut);
+				dev_err(&pdx->interface->dev,
+					"%s usb_submit_urb() returned %d",
+					__func__, iReturn);
+			}
+		} else
+			pdx->bSendCharsPending = false;	// Allow other threads again
+		spin_unlock(&pdx->charOutLock);	// already at irq level
+	}
+}
+
+/****************************************************************************
+** SendChars
+** Transmit the characters in the output buffer to the 1401. This may need
+** breaking down into multiple transfers.
+****************************************************************************/
+int SendChars(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = U14ERR_NOERROR;
+
+	spin_lock_irq(&pdx->charOutLock);	// Protect ourselves
+
+	if ((!pdx->bSendCharsPending) &&	// Not currently sending
+	    (pdx->dwNumOutput > 0) &&	//  has characters to output
+	    (CanAcceptIoRequests(pdx)))	//  and current activity is OK
+	{
+		unsigned int dwCount = pdx->dwNumOutput;	// Get a copy of the character count
+		pdx->bSendCharsPending = true;	// Set flag to lock out other threads
+
+		dev_dbg(&pdx->interface->dev,
+			"Send %d chars to 1401, EP0 flag %d\n", dwCount,
+			pdx->nPipes == 3);
+		// If we have only 3 end points we must send the characters to the 1401 using EP0.
+		if (pdx->nPipes == 3) {
+			// For EP0 character transmissions to the 1401, we have to hang about until they
+			// are gone, as otherwise without more character IO activity they will never go.
+			unsigned int count = dwCount;	// Local char counter
+			unsigned int index = 0;	// The index into the char buffer
+
+			spin_unlock_irq(&pdx->charOutLock);	// Free spinlock as we call USBD
+
+			while ((count > 0) && (iReturn == U14ERR_NOERROR)) {
+				// We have to break the transfer up into 64-byte chunks because of a 2270 problem
+				int n = count > 64 ? 64 : count;	// Chars for this xfer, max of 64
+				int nSent = usb_control_msg(pdx->udev,
+							    usb_sndctrlpipe(pdx->udev, 0),	// use end point 0
+							    DB_CHARS,	// bRequest
+							    (H_TO_D | VENDOR | DEVREQ),	// to the device, vendor request to the device
+							    0, 0,	// value and index are both 0
+							    &pdx->outputBuffer[index],	// where to send from
+							    n,	// how much to send
+							    1000);	// timeout in jiffies
+				if (nSent <= 0) {
+					iReturn = nSent ? nSent : -ETIMEDOUT;	// if 0 chars says we timed out
+					dev_err(&pdx->interface->dev,
+						"Send %d chars by EP0 failed: %d",
+						n, iReturn);
+				} else {
+					dev_dbg(&pdx->interface->dev,
+						"Sent %d chars by EP0", n);
+					count -= nSent;
+					index += nSent;
+				}
+			}
+
+			spin_lock_irq(&pdx->charOutLock);	// Protect pdx changes, released by general code
+			pdx->dwOutBuffGet = 0;	// so reset the output buffer
+			pdx->dwOutBuffPut = 0;
+			pdx->dwNumOutput = 0;	// and clear the buffer count
+			pdx->bSendCharsPending = false;	// Allow other threads again
+		} else {	// Here for sending chars normally - we hold the spin lock
+			int nPipe = 0;	// The pipe number to use
+			char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet];
+
+			if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ)	// does it cross buffer end?
+				dwCount = OUTBUF_SZ - pdx->dwOutBuffGet;
+			spin_unlock_irq(&pdx->charOutLock);	// we are done with stuff that changes
+			memcpy(pdx->pCoherCharOut, pDat, dwCount);	// copy output data to the buffer
+			usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev,
+					  usb_sndbulkpipe(pdx->udev,
+							  pdx->epAddr[0]),
+					  pdx->pCoherCharOut, dwCount,
+					  ced_writechar_callback, pdx);
+			pdx->pUrbCharOut->transfer_flags |=
+			    URB_NO_TRANSFER_DMA_MAP;
+			usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted);
+			iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_KERNEL);
+			spin_lock_irq(&pdx->charOutLock);	// grab lock for errors
+			if (iReturn) {
+				pdx->bPipeError[nPipe] = 1;	// Flag an error to be handled later
+				pdx->bSendCharsPending = false;	// Allow other threads again
+				usb_unanchor_urb(pdx->pUrbCharOut);	// remove from list of active urbs
+			}
+		}
+	} else if (pdx->bSendCharsPending && (pdx->dwNumOutput > 0))
+		dev_dbg(&pdx->interface->dev,
+			"SendChars bSendCharsPending:true");
+
+	dev_dbg(&pdx->interface->dev, "SendChars exit code: %d", iReturn);
+	spin_unlock_irq(&pdx->charOutLock);	// Now let go of the spinlock
+	return iReturn;
+}
+
+/***************************************************************************
+** CopyUserSpace
+** This moves memory between pinned down user space and the pCoherStagedIO
+** memory buffer we use for transfers. Copy n bytes in the directions that
+** is defined by pdx->StagedRead. The user space is determined by the area
+** in pdx->StagedId and the offset in pdx->StagedDone. The user
+** area may well not start on a page boundary, so allow for that.
+**
+** We have a table of physical pages that describe the area, so we can use
+** this to get a virtual address that the kernel can use.
+**
+** pdx  Is our device extension which holds all we know about the transfer.
+** n    The number of bytes to move one way or the other.
+***************************************************************************/
+static void CopyUserSpace(DEVICE_EXTENSION * pdx, int n)
+{
+	unsigned int nArea = pdx->StagedId;
+	if (nArea < MAX_TRANSAREAS) {
+		TRANSAREA *pArea = &pdx->rTransDef[nArea];	// area to be used
+		unsigned int dwOffset =
+		    pdx->StagedDone + pdx->StagedOffset + pArea->dwBaseOffset;
+		char *pCoherBuf = pdx->pCoherStagedIO;	// coherent buffer
+		if (!pArea->bUsed) {
+			dev_err(&pdx->interface->dev, "%s area %d unused",
+				__func__, nArea);
+			return;
+		}
+
+		while (n) {
+			int nPage = dwOffset >> PAGE_SHIFT;	// page number in table
+			if (nPage < pArea->nPages) {
+				char *pvAddress =
+				    (char *)kmap_atomic(pArea->pPages[nPage]);
+				if (pvAddress) {
+					unsigned int uiPageOff = dwOffset & (PAGE_SIZE - 1);	// offset into the page
+					size_t uiXfer = PAGE_SIZE - uiPageOff;	// max to transfer on this page
+					if (uiXfer > n)	// limit byte count if too much
+						uiXfer = n;	// for the page
+					if (pdx->StagedRead)
+						memcpy(pvAddress + uiPageOff,
+						       pCoherBuf, uiXfer);
+					else
+						memcpy(pCoherBuf,
+						       pvAddress + uiPageOff,
+						       uiXfer);
+					kunmap_atomic(pvAddress);
+					dwOffset += uiXfer;
+					pCoherBuf += uiXfer;
+					n -= uiXfer;
+				} else {
+					dev_err(&pdx->interface->dev,
+						"%s did not map page %d",
+						__func__, nPage);
+					return;
+				}
+
+			} else {
+				dev_err(&pdx->interface->dev,
+					"%s exceeded pages %d", __func__,
+					nPage);
+				return;
+			}
+		}
+	} else
+		dev_err(&pdx->interface->dev, "%s bad area %d", __func__,
+			nArea);
+}
+
+// Forward declarations for stuff used circularly
+static int StageChunk(DEVICE_EXTENSION * pdx);
+/***************************************************************************
+** ReadWrite_Complete
+**
+**  Completion routine for our staged read/write Irps
+*/
+static void staged_callback(struct urb *pUrb)
+{
+	DEVICE_EXTENSION *pdx = pUrb->context;
+	unsigned int nGot = pUrb->actual_length;	// what we transferred
+	bool bCancel = false;
+	bool bRestartCharInput;	// used at the end
+
+	spin_lock(&pdx->stagedLock);	// stop ReadWriteMem() action while this routine is running
+	pdx->bStagedUrbPending = false;	// clear the flag for staged IRP pending
+
+	if (pUrb->status) {	// sync/async unlink faults aren't errors
+		if (!
+		    (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
+		     || pUrb->status == -ESHUTDOWN)) {
+			dev_err(&pdx->interface->dev,
+				"%s - nonzero write bulk status received: %d",
+				__func__, pUrb->status);
+		} else
+			dev_info(&pdx->interface->dev,
+				 "%s - staged xfer cancelled", __func__);
+
+		spin_lock(&pdx->err_lock);
+		pdx->errors = pUrb->status;
+		spin_unlock(&pdx->err_lock);
+		nGot = 0;	//  and tidy up again if so
+		bCancel = true;
+	} else {
+		dev_dbg(&pdx->interface->dev, "%s %d chars xferred", __func__,
+			nGot);
+		if (pdx->StagedRead)	// if reading, save to user space
+			CopyUserSpace(pdx, nGot);	// copy from buffer to user
+		if (nGot == 0)
+			dev_dbg(&pdx->interface->dev, "%s ZLP", __func__);
+	}
+
+	// Update the transfer length based on the TransferBufferLength value in the URB
+	pdx->StagedDone += nGot;
+
+	dev_dbg(&pdx->interface->dev, "%s, done %d bytes of %d", __func__,
+		pdx->StagedDone, pdx->StagedLength);
+
+	if ((pdx->StagedDone == pdx->StagedLength) ||	// If no more to do
+	    (bCancel))		// or this IRP was cancelled
+	{
+		TRANSAREA *pArea = &pdx->rTransDef[pdx->StagedId];	// Transfer area info
+		dev_dbg(&pdx->interface->dev,
+			"%s transfer done, bytes %d, cancel %d", __func__,
+			pdx->StagedDone, bCancel);
+
+		// Here is where we sort out what to do with this transfer if using a circular buffer. We have
+		//  a completed transfer that can be assumed to fit into the transfer area. We should be able to
+		//  add this to the end of a growing block or to use it to start a new block unless the code
+		//  that calculates the offset to use (in ReadWriteMem) is totally duff.
+		if ((pArea->bCircular) && (pArea->bCircToHost) && (!bCancel) &&	// Time to sort out circular buffer info?
+		    (pdx->StagedRead))	// Only for tohost transfers for now
+		{
+			if (pArea->aBlocks[1].dwSize > 0)	// If block 1 is in use we must append to it
+			{
+				if (pdx->StagedOffset ==
+				    (pArea->aBlocks[1].dwOffset +
+				     pArea->aBlocks[1].dwSize)) {
+					pArea->aBlocks[1].dwSize +=
+					    pdx->StagedLength;
+					dev_dbg(&pdx->interface->dev,
+						"RWM_Complete, circ block 1 now %d bytes at %d",
+						pArea->aBlocks[1].dwSize,
+						pArea->aBlocks[1].dwOffset);
+				} else {
+					// Here things have gone very, very, wrong, but I cannot see how this can actually be achieved
+					pArea->aBlocks[1].dwOffset =
+					    pdx->StagedOffset;
+					pArea->aBlocks[1].dwSize =
+					    pdx->StagedLength;
+					dev_err(&pdx->interface->dev,
+						"%s ERROR, circ block 1 re-started %d bytes at %d",
+						__func__,
+						pArea->aBlocks[1].dwSize,
+						pArea->aBlocks[1].dwOffset);
+				}
+			} else	// If block 1 is not used, we try to add to block 0
+			{
+				if (pArea->aBlocks[0].dwSize > 0)	// Got stored block 0 information?
+				{	// Must append onto the existing block 0
+					if (pdx->StagedOffset ==
+					    (pArea->aBlocks[0].dwOffset +
+					     pArea->aBlocks[0].dwSize)) {
+						pArea->aBlocks[0].dwSize += pdx->StagedLength;	// Just add this transfer in
+						dev_dbg(&pdx->interface->dev,
+							"RWM_Complete, circ block 0 now %d bytes at %d",
+							pArea->aBlocks[0].
+							dwSize,
+							pArea->aBlocks[0].
+							dwOffset);
+					} else	// If it doesn't append, put into new block 1
+					{
+						pArea->aBlocks[1].dwOffset =
+						    pdx->StagedOffset;
+						pArea->aBlocks[1].dwSize =
+						    pdx->StagedLength;
+						dev_dbg(&pdx->interface->dev,
+							"RWM_Complete, circ block 1 started %d bytes at %d",
+							pArea->aBlocks[1].
+							dwSize,
+							pArea->aBlocks[1].
+							dwOffset);
+					}
+				} else	// No info stored yet, just save in block 0
+				{
+					pArea->aBlocks[0].dwOffset =
+					    pdx->StagedOffset;
+					pArea->aBlocks[0].dwSize =
+					    pdx->StagedLength;
+					dev_dbg(&pdx->interface->dev,
+						"RWM_Complete, circ block 0 started %d bytes at %d",
+						pArea->aBlocks[0].dwSize,
+						pArea->aBlocks[0].dwOffset);
+				}
+			}
+		}
+
+		if (!bCancel)	// Don't generate an event if cancelled
+		{
+			dev_dbg(&pdx->interface->dev,
+				"RWM_Complete,  bCircular %d, bToHost %d, eStart %d, eSize %d",
+				pArea->bCircular, pArea->bEventToHost,
+				pArea->dwEventSt, pArea->dwEventSz);
+			if ((pArea->dwEventSz) &&	// Set a user-mode event...
+			    (pdx->StagedRead == pArea->bEventToHost))	// ...on transfers in this direction?
+			{
+				int iWakeUp = 0;	// assume
+				// If we have completed the right sort of DMA transfer then set the event to notify
+				//   the user code to wake up anyone that is waiting.
+				if ((pArea->bCircular) &&	// Circular areas use a simpler test
+				    (pArea->bCircToHost))	// only in supported direction
+				{	// Is total data waiting up to size limit?
+					unsigned int dwTotal =
+					    pArea->aBlocks[0].dwSize +
+					    pArea->aBlocks[1].dwSize;
+					iWakeUp = (dwTotal >= pArea->dwEventSz);
+				} else {
+					unsigned int transEnd =
+					    pdx->StagedOffset +
+					    pdx->StagedLength;
+					unsigned int eventEnd =
+					    pArea->dwEventSt + pArea->dwEventSz;
+					iWakeUp = (pdx->StagedOffset < eventEnd)
+					    && (transEnd > pArea->dwEventSt);
+				}
+
+				if (iWakeUp) {
+					dev_dbg(&pdx->interface->dev,
+						"About to set event to notify app");
+					wake_up_interruptible(&pArea->wqEvent);	// wake up waiting processes
+					++pArea->iWakeUp;	// increment wakeup count
+				}
+			}
+		}
+
+		pdx->dwDMAFlag = MODE_CHAR;	// Switch back to char mode before ReadWriteMem call
+
+		if (!bCancel)	// Don't look for waiting transfer if cancelled
+		{
+			// If we have a transfer waiting, kick it off
+			if (pdx->bXFerWaiting)	// Got a block xfer waiting?
+			{
+				int iReturn;
+				dev_info(&pdx->interface->dev,
+					 "*** RWM_Complete *** pending transfer will now be set up!!!");
+				iReturn =
+				    ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard,
+						 pdx->rDMAInfo.wIdent,
+						 pdx->rDMAInfo.dwOffset,
+						 pdx->rDMAInfo.dwSize);
+
+				if (iReturn)
+					dev_err(&pdx->interface->dev,
+						"RWM_Complete rw setup failed %d",
+						iReturn);
+			}
+		}
+
+	} else			// Here for more to do
+		StageChunk(pdx);	// fire off the next bit
+
+	// While we hold the stagedLock, see if we should reallow character input ints
+	// Don't allow if cancelled, or if a new block has started or if there is a waiting block.
+	// This feels wrong as we should ask which spin lock protects dwDMAFlag.
+	bRestartCharInput = !bCancel && (pdx->dwDMAFlag == MODE_CHAR)
+	    && !pdx->bXFerWaiting;
+
+	spin_unlock(&pdx->stagedLock);	// Finally release the lock again
+
+	// This is not correct as dwDMAFlag is protected by the staged lock, but it is treated
+	// in Allowi as if it were protected by the char lock. In any case, most systems will
+	// not be upset by char input during DMA... sigh. Needs sorting out.
+	if (bRestartCharInput)	// may be out of date, but...
+		Allowi(pdx, true);	// ...Allowi tests a lock too.
+	dev_dbg(&pdx->interface->dev, "%s done", __func__);
+}
+
+/****************************************************************************
+** StageChunk
+**
+** Generates the next chunk of data making up a staged transfer.
+**
+** The calling code must have acquired the staging spinlock before calling
+**  this function, and is responsible for releasing it. We are at callback level.
+****************************************************************************/
+static int StageChunk(DEVICE_EXTENSION * pdx)
+{
+	int iReturn = U14ERR_NOERROR;
+	unsigned int ChunkSize;
+	int nPipe = pdx->StagedRead ? 3 : 2;	// The pipe number to use for reads or writes
+	if (pdx->nPipes == 3)
+		nPipe--;	// Adjust for the 3-pipe case
+	if (nPipe < 0)		// and trap case that should never happen
+		return U14ERR_FAIL;
+
+	if (!CanAcceptIoRequests(pdx))	// got sudden remove?
+	{
+		dev_info(&pdx->interface->dev, "%s sudden remove, giving up",
+			 __func__);
+		return U14ERR_FAIL;	// could do with a better error
+	}
+
+	ChunkSize = (pdx->StagedLength - pdx->StagedDone);	// transfer length remaining
+	if (ChunkSize > STAGED_SZ)	// make sure to keep legal
+		ChunkSize = STAGED_SZ;	//  limit to max allowed
+
+	if (!pdx->StagedRead)	// if writing...
+		CopyUserSpace(pdx, ChunkSize);	// ...copy data into the buffer
+
+	usb_fill_bulk_urb(pdx->pStagedUrb, pdx->udev,
+			  pdx->StagedRead ? usb_rcvbulkpipe(pdx->udev,
+							    pdx->
+							    epAddr[nPipe]) :
+			  usb_sndbulkpipe(pdx->udev, pdx->epAddr[nPipe]),
+			  pdx->pCoherStagedIO, ChunkSize, staged_callback, pdx);
+	pdx->pStagedUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	usb_anchor_urb(pdx->pStagedUrb, &pdx->submitted);	// in case we need to kill it
+	iReturn = usb_submit_urb(pdx->pStagedUrb, GFP_ATOMIC);
+	if (iReturn) {
+		usb_unanchor_urb(pdx->pStagedUrb);	// kill it
+		pdx->bPipeError[nPipe] = 1;	// Flag an error to be handled later
+		dev_err(&pdx->interface->dev, "%s submit urb failed, code %d",
+			__func__, iReturn);
+	} else
+		pdx->bStagedUrbPending = true;	// Set the flag for staged URB pending
+	dev_dbg(&pdx->interface->dev, "%s done so far:%d, this size:%d",
+		__func__, pdx->StagedDone, ChunkSize);
+
+	return iReturn;
+}
+
+/***************************************************************************
+** ReadWriteMem
+**
+** This routine is used generally for block read and write operations.
+** Breaks up a read or write in to specified sized chunks, as specified by pipe
+** information on maximum transfer size.
+**
+** Any code that calls this must be holding the stagedLock
+**
+** Arguments:
+**    DeviceObject - pointer to our FDO (Functional Device Object)
+**    Read - TRUE for read, FALSE for write. This is from POV of the driver
+**    wIdent - the transfer area number - defines memory area and more.
+**    dwOffs - the start offset within the transfer area of the start of this
+**             transfer.
+**    dwLen - the number of bytes to transfer.
+*/
+int ReadWriteMem(DEVICE_EXTENSION * pdx, bool Read, unsigned short wIdent,
+		 unsigned int dwOffs, unsigned int dwLen)
+{
+	TRANSAREA *pArea = &pdx->rTransDef[wIdent];	// Transfer area info
+
+	if (!CanAcceptIoRequests(pdx))	// Are we in a state to accept new requests?
+	{
+		dev_err(&pdx->interface->dev, "%s can't accept requests",
+			__func__);
+		return U14ERR_FAIL;
+	}
+
+	dev_dbg(&pdx->interface->dev,
+		"%s xfer %d bytes to %s, offset %d, area %d", __func__, dwLen,
+		Read ? "host" : "1401", dwOffs, wIdent);
+
+	// Amazingly, we can get an escape sequence back before the current staged Urb is done, so we
+	//  have to check for this situation and, if so, wait until all is OK.
+	if (pdx->bStagedUrbPending) {
+		pdx->bXFerWaiting = true;	// Flag we are waiting
+		dev_info(&pdx->interface->dev,
+			 "%s xfer is waiting, as previous staged pending",
+			 __func__);
+		return U14ERR_NOERROR;
+	}
+
+	if (dwLen == 0)		// allow 0-len read or write; just return success
+	{
+		dev_dbg(&pdx->interface->dev,
+			"%s OK; zero-len read/write request", __func__);
+		return U14ERR_NOERROR;
+	}
+
+	if ((pArea->bCircular) &&	// Circular transfer?
+	    (pArea->bCircToHost) && (Read))	// In a supported direction
+	{			// If so, we sort out offset ourself
+		bool bWait = false;	// Flag for transfer having to wait
+
+		dev_dbg(&pdx->interface->dev,
+			"Circular buffers are %d at %d and %d at %d",
+			pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset,
+			pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset);
+		if (pArea->aBlocks[1].dwSize > 0)	// Using the second block already?
+		{
+			dwOffs = pArea->aBlocks[1].dwOffset + pArea->aBlocks[1].dwSize;	// take offset from that
+			bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset;	// Wait if will overwrite block 0?
+			bWait |= (dwOffs + dwLen) > pArea->dwLength;	// or if it overflows the buffer
+		} else		// Area 1 not in use, try to use area 0
+		{
+			if (pArea->aBlocks[0].dwSize == 0)	// Reset block 0 if not in use
+				pArea->aBlocks[0].dwOffset = 0;
+			dwOffs =
+			    pArea->aBlocks[0].dwOffset +
+			    pArea->aBlocks[0].dwSize;
+			if ((dwOffs + dwLen) > pArea->dwLength)	// Off the end of the buffer?
+			{
+				pArea->aBlocks[1].dwOffset = 0;	// Set up to use second block
+				dwOffs = 0;
+				bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset;	// Wait if will overwrite block 0?
+				bWait |= (dwOffs + dwLen) > pArea->dwLength;	// or if it overflows the buffer
+			}
+		}
+
+		if (bWait)	// This transfer will have to wait?
+		{
+			pdx->bXFerWaiting = true;	// Flag we are waiting
+			dev_dbg(&pdx->interface->dev,
+				"%s xfer waiting for circular buffer space",
+				__func__);
+			return U14ERR_NOERROR;
+		}
+
+		dev_dbg(&pdx->interface->dev,
+			"%s circular xfer, %d bytes starting at %d", __func__,
+			dwLen, dwOffs);
+	}
+	// Save the parameters for the read\write transfer
+	pdx->StagedRead = Read;	// Save the parameters for this read
+	pdx->StagedId = wIdent;	// ID allows us to get transfer area info
+	pdx->StagedOffset = dwOffs;	// The area within the transfer area
+	pdx->StagedLength = dwLen;
+	pdx->StagedDone = 0;	// Initialise the byte count
+	pdx->dwDMAFlag = MODE_LINEAR;	// Set DMA mode flag at this point
+	pdx->bXFerWaiting = false;	// Clearly not a transfer waiting now
+
+//    KeClearEvent(&pdx->StagingDoneEvent);           // Clear the transfer done event
+	StageChunk(pdx);	// fire off the first chunk
+
+	return U14ERR_NOERROR;
+}
+
+/****************************************************************************
+**
+** ReadChar
+**
+** Reads a character a buffer. If there is no more
+**  data we return FALSE. Used as part of decoding a DMA request.
+**
+****************************************************************************/
+static bool ReadChar(unsigned char *pChar, char *pBuf, unsigned int *pdDone,
+		     unsigned int dGot)
+{
+	bool bRead = false;
+	unsigned int dDone = *pdDone;
+
+	if (dDone < dGot)	// If there is more data
+	{
+		*pChar = (unsigned char)pBuf[dDone];	// Extract the next char
+		dDone++;	// Increment the done count
+		*pdDone = dDone;
+		bRead = true;	// and flag success
+	}
+
+	return bRead;
+}
+
+#ifdef NOTUSED
+/****************************************************************************
+**
+** ReadWord
+**
+** Reads a word from the 1401, just uses ReadChar twice; passes on any error
+**
+*****************************************************************************/
+static bool ReadWord(unsigned short *pWord, char *pBuf, unsigned int *pdDone,
+		     unsigned int dGot)
+{
+	if (ReadChar((unsigned char *)pWord, pBuf, pdDone, dGot))
+		return ReadChar(((unsigned char *)pWord) + 1, pBuf, pdDone,
+				dGot);
+	else
+		return false;
+}
+#endif
+
+/****************************************************************************
+** ReadHuff
+**
+** Reads a coded number in and returns it, Code is:
+** If data is in range 0..127 we recieve 1 byte. If data in range 128-16383
+** we recieve two bytes, top bit of first indicates another on its way. If
+** data in range 16383-4194303 we get three bytes, top two bits of first set
+** to indicate three byte total.
+**
+*****************************************************************************/
+static bool ReadHuff(volatile unsigned int *pDWord, char *pBuf,
+		     unsigned int *pdDone, unsigned int dGot)
+{
+	unsigned char ucData;	/* for each read to ReadChar */
+	bool bReturn = true;	/* assume we will succeed */
+	unsigned int dwData = 0;	/* Accumulator for the data */
+
+	if (ReadChar(&ucData, pBuf, pdDone, dGot)) {
+		dwData = ucData;	/* copy the data */
+		if ((dwData & 0x00000080) != 0) {	/* Bit set for more data ? */
+			dwData &= 0x0000007F;	/* Clear the relevant bit */
+			if (ReadChar(&ucData, pBuf, pdDone, dGot)) {
+				dwData = (dwData << 8) | ucData;
+				if ((dwData & 0x00004000) != 0) {	/* three byte sequence ? */
+					dwData &= 0x00003FFF;	/* Clear the relevant bit */
+					if (ReadChar
+					    (&ucData, pBuf, pdDone, dGot))
+						dwData = (dwData << 8) | ucData;
+					else
+						bReturn = false;
+				}
+			} else
+				bReturn = false;	/* couldn't read data */
+		}
+	} else
+		bReturn = false;
+
+	*pDWord = dwData;	/* return the data */
+	return bReturn;
+}
+
+/***************************************************************************
+**
+** ReadDMAInfo
+**
+** Tries to read info about the dma request from the 1401 and decode it into
+** the dma descriptor block. We have at this point had the escape character
+** from the 1401 and now we must read in the rest of the information about
+** the transfer request. Returns FALSE if 1401 fails to respond or obselete
+** code from 1401 or bad parameters.
+**
+** The pBuf char pointer does not include the initial escape character, so
+**  we start handling the data at offset zero.
+**
+*****************************************************************************/
+static bool ReadDMAInfo(volatile DMADESC * pDmaDesc, DEVICE_EXTENSION * pdx,
+			char *pBuf, unsigned int dwCount)
+{
+	bool bResult = false;	// assume we won't succeed
+	unsigned char ucData;
+	unsigned int dDone = 0;	// We haven't parsed anything so far
+
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	if (ReadChar(&ucData, pBuf, &dDone, dwCount)) {
+		unsigned char ucTransCode = (ucData & 0x0F);	// get code for transfer type
+		unsigned short wIdent = ((ucData >> 4) & 0x07);	// and area identifier
+
+		// fill in the structure we were given
+		pDmaDesc->wTransType = ucTransCode;	// type of transfer
+		pDmaDesc->wIdent = wIdent;	// area to use
+		pDmaDesc->dwSize = 0;	// initialise other bits
+		pDmaDesc->dwOffset = 0;
+
+		dev_dbg(&pdx->interface->dev, "%s type: %d ident: %d", __func__,
+			pDmaDesc->wTransType, pDmaDesc->wIdent);
+
+		pDmaDesc->bOutWard = (ucTransCode != TM_EXTTOHOST);	// set transfer direction
+
+		switch (ucTransCode) {
+		case TM_EXTTOHOST:	// Extended linear transfer modes (the only ones!)
+		case TM_EXTTO1401:
+			{
+				bResult =
+				    ReadHuff(&(pDmaDesc->dwOffset), pBuf,
+					     &dDone, dwCount)
+				    && ReadHuff(&(pDmaDesc->dwSize), pBuf,
+						&dDone, dwCount);
+				if (bResult) {
+					dev_dbg(&pdx->interface->dev,
+						"%s xfer offset & size %d %d",
+						__func__, pDmaDesc->dwOffset,
+						pDmaDesc->dwSize);
+
+					if ((wIdent >= MAX_TRANSAREAS) ||	// Illegal area number, or...
+					    (!pdx->rTransDef[wIdent].bUsed) ||	// area not set up, or...
+					    (pDmaDesc->dwOffset > pdx->rTransDef[wIdent].dwLength) ||	// range/size
+					    ((pDmaDesc->dwOffset +
+					      pDmaDesc->dwSize) >
+					     (pdx->rTransDef[wIdent].
+					      dwLength))) {
+						bResult = false;	// bad parameter(s)
+						dev_dbg(&pdx->interface->dev,
+							"%s bad param - id %d, bUsed %d, offset %d, size %d, area length %d",
+							__func__, wIdent,
+							pdx->rTransDef[wIdent].
+							bUsed,
+							pDmaDesc->dwOffset,
+							pDmaDesc->dwSize,
+							pdx->rTransDef[wIdent].
+							dwLength);
+					}
+				}
+				break;
+			}
+		default:
+			break;
+		}
+	} else
+		bResult = false;
+
+	if (!bResult)		// now check parameters for validity
+		dev_err(&pdx->interface->dev, "%s error reading Esc sequence",
+			__func__);
+
+	return bResult;
+}
+
+/****************************************************************************
+**
+** Handle1401Esc
+**
+** Deals with an escape sequence coming from the 1401. This can either be
+**  a DMA transfer request of various types or a response to an escape sequence
+**  sent to the 1401. This is called from a callback.
+**
+** Parameters are
+**
+** dwCount - the number of characters in the device extension char in buffer,
+**           this is known to be at least 2 or we will not be called.
+**
+****************************************************************************/
+static int Handle1401Esc(DEVICE_EXTENSION * pdx, char *pCh,
+			 unsigned int dwCount)
+{
+	int iReturn = U14ERR_FAIL;
+
+	// I have no idea what this next test is about. '?' is 0x3f, which is area 3, code
+	// 15. At the moment, this is not used, so it does no harm, but unless someone can
+	// tell me what this is for, it should be removed from this and the Windows driver.
+	if (pCh[0] == '?')	// Is this an information response
+	{			// Parse and save the information
+	} else {
+		spin_lock(&pdx->stagedLock);	// Lock others out
+
+		if (ReadDMAInfo(&pdx->rDMAInfo, pdx, pCh, dwCount))	// Get DMA parameters
+		{
+			unsigned short wTransType = pdx->rDMAInfo.wTransType;	// check transfer type
+
+			dev_dbg(&pdx->interface->dev,
+				"%s xfer to %s, offset %d, length %d", __func__,
+				pdx->rDMAInfo.bOutWard ? "1401" : "host",
+				pdx->rDMAInfo.dwOffset, pdx->rDMAInfo.dwSize);
+
+			if (pdx->bXFerWaiting)	// Check here for badly out of kilter...
+			{	// This can never happen, really
+				dev_err(&pdx->interface->dev,
+					"ERROR: DMA setup while transfer still waiting");
+				spin_unlock(&pdx->stagedLock);
+			} else {
+				if ((wTransType == TM_EXTTOHOST)
+				    || (wTransType == TM_EXTTO1401)) {
+					iReturn =
+					    ReadWriteMem(pdx,
+							 !pdx->rDMAInfo.
+							 bOutWard,
+							 pdx->rDMAInfo.wIdent,
+							 pdx->rDMAInfo.dwOffset,
+							 pdx->rDMAInfo.dwSize);
+					if (iReturn != U14ERR_NOERROR)
+						dev_err(&pdx->interface->dev,
+							"%s ReadWriteMem() failed %d",
+							__func__, iReturn);
+				} else	// This covers non-linear transfer setup
+					dev_err(&pdx->interface->dev,
+						"%s Unknown block xfer type %d",
+						__func__, wTransType);
+			}
+		} else		// Failed to read parameters
+			dev_err(&pdx->interface->dev, "%s ReadDMAInfo() fail",
+				__func__);
+
+		spin_unlock(&pdx->stagedLock);	// OK here
+	}
+
+	dev_dbg(&pdx->interface->dev, "%s returns %d", __func__, iReturn);
+
+	return iReturn;
+}
+
+/****************************************************************************
+** Callback for the character read complete or error
+****************************************************************************/
+static void ced_readchar_callback(struct urb *pUrb)
+{
+	DEVICE_EXTENSION *pdx = pUrb->context;
+	int nGot = pUrb->actual_length;	// what we transferred
+
+	if (pUrb->status)	// Do we have a problem to handle?
+	{
+		int nPipe = pdx->nPipes == 4 ? 1 : 0;	// The pipe number to use for error
+		// sync/async unlink faults aren't errors... just saying device removed or stopped
+		if (!
+		    (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
+		     || pUrb->status == -ESHUTDOWN)) {
+			dev_err(&pdx->interface->dev,
+				"%s - nonzero write bulk status received: %d",
+				__func__, pUrb->status);
+		} else
+			dev_dbg(&pdx->interface->dev,
+				"%s - 0 chars pUrb->status=%d (shutdown?)",
+				__func__, pUrb->status);
+
+		spin_lock(&pdx->err_lock);
+		pdx->errors = pUrb->status;
+		spin_unlock(&pdx->err_lock);
+		nGot = 0;	//  and tidy up again if so
+
+		spin_lock(&pdx->charInLock);	// already at irq level
+		pdx->bPipeError[nPipe] = 1;	// Flag an error for later
+	} else {
+		if ((nGot > 1) && ((pdx->pCoherCharIn[0] & 0x7f) == 0x1b))	// Esc sequence?
+		{
+			Handle1401Esc(pdx, &pdx->pCoherCharIn[1], nGot - 1);	// handle it
+			spin_lock(&pdx->charInLock);	// already at irq level
+		} else {
+			spin_lock(&pdx->charInLock);	// already at irq level
+			if (nGot > 0) {
+				unsigned int i;
+				if (nGot < INBUF_SZ) {
+					pdx->pCoherCharIn[nGot] = 0;	// tidy the string
+					dev_dbg(&pdx->interface->dev,
+						"%s got %d chars >%s<",
+						__func__, nGot,
+						pdx->pCoherCharIn);
+				}
+				// We know that whatever we read must fit in the input buffer
+				for (i = 0; i < nGot; i++) {
+					pdx->inputBuffer[pdx->dwInBuffPut++] =
+					    pdx->pCoherCharIn[i] & 0x7F;
+					if (pdx->dwInBuffPut >= INBUF_SZ)
+						pdx->dwInBuffPut = 0;
+				}
+
+				if ((pdx->dwNumInput + nGot) <= INBUF_SZ)
+					pdx->dwNumInput += nGot;	// Adjust the buffer count accordingly
+			} else
+				dev_dbg(&pdx->interface->dev, "%s read ZLP",
+					__func__);
+		}
+	}
+
+	pdx->bReadCharsPending = false;	// No longer have a pending read
+	spin_unlock(&pdx->charInLock);	// already at irq level
+
+	Allowi(pdx, true);	// see if we can do the next one
+}
+
+/****************************************************************************
+** Allowi
+**
+** This is used to make sure that there is always a pending input transfer so
+** we can pick up any inward transfers. This can be called in multiple contexts
+** so we use the irqsave version of the spinlock.
+****************************************************************************/
+int Allowi(DEVICE_EXTENSION * pdx, bool bInCallback)
+{
+	int iReturn = U14ERR_NOERROR;
+	unsigned long flags;
+	spin_lock_irqsave(&pdx->charInLock, flags);	// can be called in multiple contexts
+
+	// We don't want char input running while DMA is in progress as we know that this
+	//  can cause sequencing problems for the 2270. So don't. It will also allow the
+	//  ERR response to get back to the host code too early on some PCs, even if there
+	//  is no actual driver failure, so we don't allow this at all.
+	if (!pdx->bInDrawDown &&	// stop input if
+	    !pdx->bReadCharsPending &&	// If no read request outstanding
+	    (pdx->dwNumInput < (INBUF_SZ / 2)) &&	//  and there is some space
+	    (pdx->dwDMAFlag == MODE_CHAR) &&	//  not doing any DMA
+	    (!pdx->bXFerWaiting) &&	//  no xfer waiting to start
+	    (CanAcceptIoRequests(pdx)))	//  and activity is generally OK
+	{			//  then off we go
+		unsigned int nMax = INBUF_SZ - pdx->dwNumInput;	// max we could read
+		int nPipe = pdx->nPipes == 4 ? 1 : 0;	// The pipe number to use
+
+		dev_dbg(&pdx->interface->dev, "%s %d chars in input buffer",
+			__func__, pdx->dwNumInput);
+
+		usb_fill_int_urb(pdx->pUrbCharIn, pdx->udev,
+				 usb_rcvintpipe(pdx->udev, pdx->epAddr[nPipe]),
+				 pdx->pCoherCharIn, nMax, ced_readchar_callback,
+				 pdx, pdx->bInterval);
+		pdx->pUrbCharIn->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;	// short xfers are OK by default
+		usb_anchor_urb(pdx->pUrbCharIn, &pdx->submitted);	// in case we need to kill it
+		iReturn =
+		    usb_submit_urb(pdx->pUrbCharIn,
+				   bInCallback ? GFP_ATOMIC : GFP_KERNEL);
+		if (iReturn) {
+			usb_unanchor_urb(pdx->pUrbCharIn);	// remove from list of active Urbs
+			pdx->bPipeError[nPipe] = 1;	// Flag an error to be handled later
+			dev_err(&pdx->interface->dev,
+				"%s submit urb failed: %d", __func__, iReturn);
+		} else
+			pdx->bReadCharsPending = true;	// Flag that we are active here
+	}
+
+	spin_unlock_irqrestore(&pdx->charInLock, flags);
+
+	return iReturn;
+
+}
+
+/*****************************************************************************
+** The ioctl entry point to the driver that is used by us to talk to it.
+** inode    The device node (no longer in 3.0.0 kernels)
+** file     The file that is open, which holds our pdx pointer
+** ulArg    The argument passed in. Note that long is 64-bits in 64-bit system, i.e. it is big
+**          enough for a 64-bit pointer.
+*****************************************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg)
+#else
+static int ced_ioctl(struct inode *node, struct file *file, unsigned int cmd,
+		     unsigned long ulArg)
+#endif
+{
+	int err = 0;
+	DEVICE_EXTENSION *pdx = file->private_data;
+	if (!CanAcceptIoRequests(pdx))	// check we still exist
+		return -ENODEV;
+
+	// Check that access is allowed, where is is needed. Anything that would have an indeterminate
+	// size will be checked by the specific command.
+	if (_IOC_DIR(cmd) & _IOC_READ)	// read from point of view of user...
+		err = !access_ok(VERIFY_WRITE, (void __user *)ulArg, _IOC_SIZE(cmd));	// is kernel write
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)	// and write from point of view of user...
+		err = !access_ok(VERIFY_READ, (void __user *)ulArg, _IOC_SIZE(cmd));	// is kernel read
+	if (err)
+		return -EFAULT;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(IOCTL_CED_SENDSTRING(0)):
+		return SendString(pdx, (const char __user *)ulArg,
+				  _IOC_SIZE(cmd));
+
+	case _IOC_NR(IOCTL_CED_RESET1401):
+		return Reset1401(pdx);
+
+	case _IOC_NR(IOCTL_CED_GETCHAR):
+		return GetChar(pdx);
+
+	case _IOC_NR(IOCTL_CED_SENDCHAR):
+		return SendChar(pdx, (char)ulArg);
+
+	case _IOC_NR(IOCTL_CED_STAT1401):
+		return Stat1401(pdx);
+
+	case _IOC_NR(IOCTL_CED_LINECOUNT):
+		return LineCount(pdx);
+
+	case _IOC_NR(IOCTL_CED_GETSTRING(0)):
+		return GetString(pdx, (char __user *)ulArg, _IOC_SIZE(cmd));
+
+	case _IOC_NR(IOCTL_CED_SETTRANSFER):
+		return SetTransfer(pdx, (TRANSFERDESC __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_UNSETTRANSFER):
+		return UnsetTransfer(pdx, (int)ulArg);
+
+	case _IOC_NR(IOCTL_CED_SETEVENT):
+		return SetEvent(pdx, (TRANSFEREVENT __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE):
+		return GetOutBufSpace(pdx);
+
+	case _IOC_NR(IOCTL_CED_GETBASEADDRESS):
+		return -1;
+
+	case _IOC_NR(IOCTL_CED_GETDRIVERREVISION):
+		return (2 << 24) | (DRIVERMAJREV << 16) | DRIVERMINREV;	// USB | MAJOR | MINOR
+
+	case _IOC_NR(IOCTL_CED_GETTRANSFER):
+		return GetTransfer(pdx, (TGET_TX_BLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_KILLIO1401):
+		return KillIO1401(pdx);
+
+	case _IOC_NR(IOCTL_CED_STATEOF1401):
+		return StateOf1401(pdx);
+
+	case _IOC_NR(IOCTL_CED_GRAB1401):
+	case _IOC_NR(IOCTL_CED_FREE1401):
+		return U14ERR_NOERROR;
+
+	case _IOC_NR(IOCTL_CED_STARTSELFTEST):
+		return StartSelfTest(pdx);
+
+	case _IOC_NR(IOCTL_CED_CHECKSELFTEST):
+		return CheckSelfTest(pdx, (TGET_SELFTEST __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_TYPEOF1401):
+		return TypeOf1401(pdx);
+
+	case _IOC_NR(IOCTL_CED_TRANSFERFLAGS):
+		return TransferFlags(pdx);
+
+	case _IOC_NR(IOCTL_CED_DBGPEEK):
+		return DbgPeek(pdx, (TDBGBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_DBGPOKE):
+		return DbgPoke(pdx, (TDBGBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_DBGRAMPDATA):
+		return DbgRampData(pdx, (TDBGBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_DBGRAMPADDR):
+		return DbgRampAddr(pdx, (TDBGBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_DBGGETDATA):
+		return DbgGetData(pdx, (TDBGBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_DBGSTOPLOOP):
+		return DbgStopLoop(pdx);
+
+	case _IOC_NR(IOCTL_CED_FULLRESET):
+		pdx->bForceReset = true;	// Set a flag for a full reset
+		break;
+
+	case _IOC_NR(IOCTL_CED_SETCIRCULAR):
+		return SetCircular(pdx, (TRANSFERDESC __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_GETCIRCBLOCK):
+		return GetCircBlock(pdx, (TCIRCBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_FREECIRCBLOCK):
+		return FreeCircBlock(pdx, (TCIRCBLOCK __user *) ulArg);
+
+	case _IOC_NR(IOCTL_CED_WAITEVENT):
+		return WaitEvent(pdx, (int)(ulArg & 0xff), (int)(ulArg >> 8));
+
+	case _IOC_NR(IOCTL_CED_TESTEVENT):
+		return TestEvent(pdx, (int)ulArg);
+
+	default:
+		return U14ERR_NO_SUCH_FN;
+	}
+	return U14ERR_NOERROR;
+}
+
+static const struct file_operations ced_fops = {
+	.owner = THIS_MODULE,
+	.open = ced_open,
+	.release = ced_release,
+	.flush = ced_flush,
+	.llseek = noop_llseek,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+	.unlocked_ioctl = ced_ioctl,
+#else
+	.ioctl = ced_ioctl,
+#endif
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
+static struct usb_class_driver ced_class = {
+	.name = "cedusb%d",
+	.fops = &ced_fops,
+	.minor_base = USB_CED_MINOR_BASE,
+};
+
+// Check that the device that matches a 1401 vendor and product ID is OK to use and
+// initialise our DEVICE_EXTENSION.
+static int ced_probe(struct usb_interface *interface,
+		     const struct usb_device_id *id)
+{
+	DEVICE_EXTENSION *pdx;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int i, bcdDevice;
+	int retval = -ENOMEM;
+
+	// allocate memory for our device extension and initialize it
+	pdx = kzalloc(sizeof(*pdx), GFP_KERNEL);
+	if (!pdx) {
+		dev_err(&interface->dev, "Out of memory\n");
+		goto error;
+	}
+
+	for (i = 0; i < MAX_TRANSAREAS; ++i)	// Initialise the wait queues
+	{
+		init_waitqueue_head(&pdx->rTransDef[i].wqEvent);
+	}
+
+	// Put initialises for our stuff here. Note that all of *pdx is zero, so
+	// no need to explicitly zero it.
+	spin_lock_init(&pdx->charOutLock);
+	spin_lock_init(&pdx->charInLock);
+	spin_lock_init(&pdx->stagedLock);
+
+	// Initialises from the skeleton stuff
+	kref_init(&pdx->kref);
+	mutex_init(&pdx->io_mutex);
+	spin_lock_init(&pdx->err_lock);
+	init_usb_anchor(&pdx->submitted);
+
+	pdx->udev = usb_get_dev(interface_to_usbdev(interface));
+	pdx->interface = interface;
+
+	// Attempt to identify the device
+	bcdDevice = pdx->udev->descriptor.bcdDevice;
+	i = (bcdDevice >> 8);
+	if (i == 0)
+		pdx->s1401Type = TYPEU1401;
+	else if ((i >= 1) && (i <= 23))
+		pdx->s1401Type = i + 2;
+	else {
+		dev_err(&interface->dev, "%s Unknown device. bcdDevice = %d",
+			__func__, bcdDevice);
+		goto error;
+	}
+	// set up the endpoint information. We only care about the number of EP as
+	// we know that we are dealing with a 1401 device.
+	iface_desc = interface->cur_altsetting;
+	pdx->nPipes = iface_desc->desc.bNumEndpoints;
+	dev_info(&interface->dev, "1401Type=%d with %d End Points",
+		 pdx->s1401Type, pdx->nPipes);
+	if ((pdx->nPipes < 3) || (pdx->nPipes > 4))
+		goto error;
+
+	// Allocate the URBs we hold for performing transfers
+	pdx->pUrbCharOut = usb_alloc_urb(0, GFP_KERNEL);	// character output URB
+	pdx->pUrbCharIn = usb_alloc_urb(0, GFP_KERNEL);	// character input URB
+	pdx->pStagedUrb = usb_alloc_urb(0, GFP_KERNEL);	// block transfer URB
+	if (!pdx->pUrbCharOut || !pdx->pUrbCharIn || !pdx->pStagedUrb) {
+		dev_err(&interface->dev, "%s URB alloc failed", __func__);
+		goto error;
+	}
+
+	pdx->pCoherStagedIO =
+	    usb_alloc_coherent(pdx->udev, STAGED_SZ, GFP_KERNEL,
+			       &pdx->pStagedUrb->transfer_dma);
+	pdx->pCoherCharOut =
+	    usb_alloc_coherent(pdx->udev, OUTBUF_SZ, GFP_KERNEL,
+			       &pdx->pUrbCharOut->transfer_dma);
+	pdx->pCoherCharIn =
+	    usb_alloc_coherent(pdx->udev, INBUF_SZ, GFP_KERNEL,
+			       &pdx->pUrbCharIn->transfer_dma);
+	if (!pdx->pCoherCharOut || !pdx->pCoherCharIn || !pdx->pCoherStagedIO) {
+		dev_err(&interface->dev, "%s Coherent buffer alloc failed",
+			__func__);
+		goto error;
+	}
+
+	for (i = 0; i < pdx->nPipes; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		pdx->epAddr[i] = endpoint->bEndpointAddress;
+		dev_info(&interface->dev, "Pipe %d, ep address %02x", i,
+			 pdx->epAddr[i]);
+		if (((pdx->nPipes == 3) && (i == 0)) ||	// if char input end point
+		    ((pdx->nPipes == 4) && (i == 1))) {
+			pdx->bInterval = endpoint->bInterval;	// save the endpoint interrupt interval
+			dev_info(&interface->dev, "Pipe %d, bInterval = %d", i,
+				 pdx->bInterval);
+		}
+		// Detect USB2 by checking last ep size (64 if USB1)
+		if (i == pdx->nPipes - 1)	// if this is the last ep (bulk)
+		{
+			pdx->bIsUSB2 =
+			    le16_to_cpu(endpoint->wMaxPacketSize) > 64;
+			dev_info(&pdx->interface->dev, "USB%d",
+				 pdx->bIsUSB2 + 1);
+		}
+	}
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, pdx);
+
+	/* we can register the device now, as it is ready */
+	retval = usb_register_dev(interface, &ced_class);
+	if (retval) {
+		/* something prevented us from registering this driver */
+		dev_err(&interface->dev,
+			"Not able to get a minor for this device.\n");
+		usb_set_intfdata(interface, NULL);
+		goto error;
+	}
+
+	/* let the user know what node this device is now attached to */
+	dev_info(&interface->dev,
+		 "USB CEDUSB device now attached to cedusb #%d",
+		 interface->minor);
+	return 0;
+
+error:
+	if (pdx)
+		kref_put(&pdx->kref, ced_delete);	// frees allocated memory
+	return retval;
+}
+
+static void ced_disconnect(struct usb_interface *interface)
+{
+	DEVICE_EXTENSION *pdx = usb_get_intfdata(interface);
+	int minor = interface->minor;	// save for message at the end
+	int i;
+
+	usb_set_intfdata(interface, NULL);	// remove the pdx from the interface
+	usb_deregister_dev(interface, &ced_class);	// give back our minor device number
+
+	mutex_lock(&pdx->io_mutex);	// stop more I/O starting while...
+	ced_draw_down(pdx);	// ...wait for then kill any io
+	for (i = 0; i < MAX_TRANSAREAS; ++i) {
+		int iErr = ClearArea(pdx, i);	// ...release any used memory
+		if (iErr == U14ERR_UNLOCKFAIL)
+			dev_err(&pdx->interface->dev, "%s Area %d was in used",
+				__func__, i);
+	}
+	pdx->interface = NULL;	// ...we kill off link to interface
+	mutex_unlock(&pdx->io_mutex);
+
+	usb_kill_anchored_urbs(&pdx->submitted);
+
+	kref_put(&pdx->kref, ced_delete);	// decrement our usage count
+
+	dev_info(&interface->dev, "USB cedusb #%d now disconnected", minor);
+}
+
+// Wait for all the urbs we know of to be done with, then kill off any that
+// are left. NBNB we will need to have a mechanism to stop circular xfers
+// from trying to fire off more urbs. We will wait up to 3 seconds for Urbs
+// to be done.
+void ced_draw_down(DEVICE_EXTENSION * pdx)
+{
+	int time;
+	dev_dbg(&pdx->interface->dev, "%s called", __func__);
+
+	pdx->bInDrawDown = true;
+	time = usb_wait_anchor_empty_timeout(&pdx->submitted, 3000);
+	if (!time)		// if we timed out we kill the urbs
+	{
+		usb_kill_anchored_urbs(&pdx->submitted);
+		dev_err(&pdx->interface->dev, "%s timed out", __func__);
+	}
+	pdx->bInDrawDown = false;
+}
+
+static int ced_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
+	if (!pdx)
+		return 0;
+	ced_draw_down(pdx);
+
+	dev_dbg(&pdx->interface->dev, "%s called", __func__);
+	return 0;
+}
+
+static int ced_resume(struct usb_interface *intf)
+{
+	DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
+	if (!pdx)
+		return 0;
+	dev_dbg(&pdx->interface->dev, "%s called", __func__);
+	return 0;
+}
+
+static int ced_pre_reset(struct usb_interface *intf)
+{
+	DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+	mutex_lock(&pdx->io_mutex);
+	ced_draw_down(pdx);
+	return 0;
+}
+
+static int ced_post_reset(struct usb_interface *intf)
+{
+	DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
+	dev_dbg(&pdx->interface->dev, "%s", __func__);
+
+	/* we are sure no URBs are active - no locking needed */
+	pdx->errors = -EPIPE;
+	mutex_unlock(&pdx->io_mutex);
+
+	return 0;
+}
+
+static struct usb_driver ced_driver = {
+	.name = "cedusb",
+	.probe = ced_probe,
+	.disconnect = ced_disconnect,
+	.suspend = ced_suspend,
+	.resume = ced_resume,
+	.pre_reset = ced_pre_reset,
+	.post_reset = ced_post_reset,
+	.id_table = ced_table,
+	.supports_autosuspend = 1,
+};
+
+module_usb_driver(ced_driver);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ced1401/usb1401.h b/drivers/staging/ced1401/usb1401.h
new file mode 100644
index 0000000..331ca98
--- /dev/null
+++ b/drivers/staging/ced1401/usb1401.h
@@ -0,0 +1,249 @@
+/* usb1401.h
+ Header file for the CED 1401 USB device driver for Linux
+ Copyright (C) 2010 Cambridge Electronic Design Ltd
+ Author Greg P Smith (greg@ced.co.uk)
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+#ifndef __USB1401_H__
+#define __USB1401_H__
+#include "use1401.h"
+#include "ced_ioctl.h"
+
+#ifndef UINT
+#define UINT unsigned int
+#endif
+
+/// Device type codes, but these don't need to be extended - a succession is assumed
+/// These are set for usb from the bcdDevice field (suitably mangled). Future devices
+/// will be added in order of device creation to the list, so the names here are just
+/// to help use remember which device is which. The U14ERR_... values follow the same
+/// pattern for modern devices.
+#define TYPEUNKNOWN        -1             // dont know
+#define TYPE1401           0              // standard 1401
+#define TYPEPLUS           1              // 1401 plus
+#define TYPEU1401          2              // u1401
+#define TYPEPOWER          3              // Power1401
+#define TYPEU14012         4              // u1401 mkII
+#define TYPEPOWER2         5              // Power1401 mk II
+#define TYPEMICRO3         6              // Micro1401-3
+#define TYPEPOWER3         7              // Power1401-3
+
+/// Some useful defines of constants. DONT FORGET to change the version in the
+/// resources whenever you change it here!.
+#define DRIVERMAJREV      2             // driver revision level major (match windows)
+#define DRIVERMINREV      0             // driver revision level minor
+
+/// Definitions of the various block transfer command codes
+#define TM_EXTTOHOST    8               // extended tohost
+#define TM_EXTTO1401    9               // extended to1401
+
+/// Definitions of values in usbReqtype. Used in sorting out setup actions
+#define H_TO_D 0x00
+#define D_TO_H 0x80
+#define VENDOR 0x40
+#define DEVREQ 0x00
+#define INTREQ 0x01
+#define ENDREQ 0x02
+
+/// Definition of values in usbRequest, again used to sort out setup
+#define GET_STATUS      0x00
+#define CLEAR_FEATURE   0x01
+#define SET_FEATURE     0x03
+#define SET_ADDRESS     0x05
+#define GET_DESC        0x06
+#define SET_DESC        0x07
+#define GET_CONF        0x08
+#define SET_CONF        0x09
+#define GET_INTERFACE   0x0a
+#define SET_INTERFACE   0x0b
+#define SYNCH_FRAME     0x0c
+
+/// Definitions of the various debug command codes understood by the 1401. These
+/// are used in various vendor-specific commands to achieve the desired effect
+#define DB_GRAB         0x50            /* Grab is a NOP for USB */
+#define DB_FREE         0x51            /* Free is a NOP for the USB */
+#define DB_SETADD       0x52            /* Set debug address (double) */
+#define DB_SELFTEST     0x53            /* Start self test */
+#define DB_SETMASK      0x54            /* Set enable mask (double) */
+#define DB_SETDEF       0x55            /* Set default mask (double) */
+#define DB_PEEK         0x56            /* Peek address, save result */
+#define DB_POKE         0x57            /* Poke address with data (double) */
+#define DB_RAMPD        0x58            /* Ramp data at debug address */
+#define DB_RAMPA        0x59            /* Ramp address bus */
+#define DB_REPEATS      0x5A            /* Set repeats for operations (double) */
+#define DB_WIDTH        0x5B            /* Set width for operations (byte) */
+#define DB_DATA         0x5C            /* Get 4-byte data read by PEEK */
+#define DB_CHARS        0x5D            /* Send chars via EP0 control write */
+
+#define CR_CHAR          0x0D           /* The carriage return character */
+#define CR_CHAR_80       0x8d           /*  and with bit 7 set */
+
+/// A structure holding information about a block of memory for use in circular transfers
+typedef struct circBlk
+{
+    volatile UINT dwOffset;             /* Offset within area of block start */
+    volatile UINT dwSize;               /* Size of the block, in bytes (0 = unused) */
+} CIRCBLK;
+
+/// A structure holding all of the information about a transfer area - an area of
+///  memory set up for use either as a source or destination in DMA transfers.
+typedef struct transarea
+{
+    void*       lpvBuff;                // User address of xfer area saved for completeness
+    UINT        dwBaseOffset;           // offset to start of xfer area in first page
+    UINT        dwLength;               // Length of xfer area, in bytes
+    struct page **pPages;               // Points at array of locked down pages
+    int         nPages;                 // number of pages that are locked down
+    bool        bUsed;                  // Is this structure in use?
+    bool        bCircular;              // Is this area for circular transfers?
+    bool        bCircToHost;            // Flag for direction of circular transfer
+    bool        bEventToHost;           // Set event on transfer to host?
+    int         iWakeUp;                // Set 1 on event, cleared by TestEvent()
+    UINT        dwEventSt;              // Defines section within xfer area for...
+    UINT        dwEventSz;              // ...notification by the event SZ is 0 if unset
+    CIRCBLK     aBlocks[2];             // Info on a pair of circular blocks
+    wait_queue_head_t wqEvent;          // The wait queue for events in this area MUST BE LAST
+} TRANSAREA;
+
+/// The DMADESC structure is used to hold information on the transfer in progress. It
+/// is set up by ReadDMAInfo, using information sent by the 1401 in an escape sequence.
+typedef struct dmadesc
+{
+    unsigned short wTransType;          /* transfer type as TM_xxx above        */
+    unsigned short wIdent;              /* identifier word                      */
+    unsigned int   dwSize;              /* bytes to transfer                    */
+    unsigned int   dwOffset;            /* offset into transfer area for trans  */
+    bool           bOutWard;            /* true when data is going TO 1401      */
+} DMADESC;
+
+#define INBUF_SZ         256            /* input buffer size */
+#define OUTBUF_SZ        256            /* output buffer size */
+#define STAGED_SZ 0x10000               // size of coherent buffer for staged transfers
+
+/// Structure to hold all of our device specific stuff. We are making this as similar as we
+/// can to the Windows driver to help in our understanding of what is going on.
+typedef struct _DEVICE_EXTENSION
+{
+    char inputBuffer[INBUF_SZ];         /* The two buffers */
+    char outputBuffer[OUTBUF_SZ];       /* accessed by the host functions */
+    volatile unsigned int dwNumInput;   /* num of chars in input buffer   */
+    volatile unsigned int dwInBuffGet;  /* where to get from input buffer */
+    volatile unsigned int dwInBuffPut;  /* where to put into input buffer */
+    volatile unsigned int dwNumOutput;  /* num of chars in output buffer  */
+    volatile unsigned int dwOutBuffGet; /* where to get from output buffer*/
+    volatile unsigned int dwOutBuffPut; /* where to put into output buffer*/
+
+    volatile bool bSendCharsPending;    /* Flag to indicate sendchar active */
+    volatile bool bReadCharsPending;    /* Flag to indicate a read is primed */
+    char* pCoherCharOut;                /* special aligned buffer for chars to 1401 */
+    struct urb* pUrbCharOut;            /* urb used for chars to 1401 */
+    char* pCoherCharIn;                 /* special aligned buffer for chars to host */
+    struct urb* pUrbCharIn;             /* urb used for chars to host */
+
+    spinlock_t charOutLock;             /* to protect the outputBuffer and outputting */
+    spinlock_t charInLock;              /* to protect the inputBuffer and char reads */
+    __u8 bInterval;                     /* Interrupt end point interval */
+
+    volatile unsigned int dwDMAFlag;    /* state of DMA */
+    TRANSAREA rTransDef[MAX_TRANSAREAS];/* transfer area info */
+    volatile DMADESC rDMAInfo;          // info on current DMA transfer
+    volatile bool bXFerWaiting;         // Flag set if DMA transfer stalled
+    volatile bool bInDrawDown;          // Flag that we want to halt transfers
+
+    // Parameters relating to a block read\write that is in progress. Some of these values
+    //  are equivalent to values in rDMAInfo. The values here are those in use, while those
+    //  in rDMAInfo are those recieved from the 1401 via an escape sequence. If another
+    //  escape sequence arrives before the previous xfer ends, rDMAInfo values are updated while these
+    //  are used to finish off the current transfer.
+    volatile short StagedId;            // The transfer area id for this transfer
+    volatile bool StagedRead;           // Flag TRUE for read from 1401, FALSE for write
+    volatile unsigned int StagedLength; // Total length of this transfer
+    volatile unsigned int StagedOffset; // Offset within memory area for transfer start
+    volatile unsigned int StagedDone;   // Bytes transferred so far
+    volatile bool bStagedUrbPending;    // Flag to indicate active
+    char* pCoherStagedIO;               // buffer used for block transfers
+    struct urb* pStagedUrb;             // The URB to use
+    spinlock_t stagedLock;              // protects ReadWriteMem() and circular buffer stuff
+
+    short s1401Type;                    // type of 1401 attached
+    short sCurrentState;                // current error state
+    bool bIsUSB2;                       // type of the interface we connect to
+    bool bForceReset;                   // Flag to make sure we get a real reset
+    __u32 statBuf[2];                   // buffer for 1401 state info
+
+    unsigned long ulSelfTestTime;       // used to timeout self test
+
+    int nPipes;                         // Should be 3 or 4 depending on 1401 usb chip
+    int bPipeError[4];                  // set non-zero if an error on one of the pipe
+    __u8 epAddr[4];                     // addresses of the 3/4 end points
+
+    struct usb_device *udev;            // the usb device for this device
+    struct usb_interface *interface;    // the interface for this device, NULL if removed
+    struct usb_anchor submitted;        // in case we need to retract our submissions
+    struct mutex io_mutex;              // synchronize I/O with disconnect, one user-mode caller at a time
+
+    int    errors;                      // the last request tanked
+    int    open_count;                  // count the number of openers
+    spinlock_t err_lock;                // lock for errors
+    struct kref kref;
+}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+#define to_DEVICE_EXTENSION(d) container_of(d, DEVICE_EXTENSION, kref)
+
+/// Definitions of routimes used between compilation object files
+// in usb1401.c
+extern int Allowi(DEVICE_EXTENSION* pdx, bool bInCallback);
+extern int SendChars(DEVICE_EXTENSION* pdx);
+extern void ced_draw_down(DEVICE_EXTENSION *pdx);
+extern int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
+                      unsigned int dwOffs, unsigned int dwLen);
+
+// in ced_ioc.c
+extern int ClearArea(DEVICE_EXTENSION *pdx, int nArea);
+extern int SendString(DEVICE_EXTENSION* pdx, const char __user* pData, unsigned int n);
+extern int SendChar(DEVICE_EXTENSION *pdx, char c);
+extern int Get1401State(DEVICE_EXTENSION* pdx, __u32* state, __u32* error);
+extern int ReadWrite_Cancel(DEVICE_EXTENSION *pdx);
+extern bool Is1401(DEVICE_EXTENSION* pdx);
+extern bool QuickCheck(DEVICE_EXTENSION* pdx, bool bTestBuff, bool bCanReset);
+extern int Reset1401(DEVICE_EXTENSION *pdx);
+extern int GetChar(DEVICE_EXTENSION *pdx);
+extern int GetString(DEVICE_EXTENSION *pdx, char __user* pUser, int n);
+extern int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
+extern int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea);
+extern int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user*pTE);
+extern int Stat1401(DEVICE_EXTENSION *pdx);
+extern int LineCount(DEVICE_EXTENSION *pdx);
+extern int GetOutBufSpace(DEVICE_EXTENSION *pdx);
+extern int GetTransfer(DEVICE_EXTENSION *pdx, TGET_TX_BLOCK __user *pGTB);
+extern int KillIO1401(DEVICE_EXTENSION *pdx);
+extern int BlkTransState(DEVICE_EXTENSION *pdx);
+extern int StateOf1401(DEVICE_EXTENSION *pdx);
+extern int StartSelfTest(DEVICE_EXTENSION *pdx);
+extern int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST);
+extern int TypeOf1401(DEVICE_EXTENSION *pdx);
+extern int TransferFlags(DEVICE_EXTENSION *pdx);
+extern int DbgPeek(DEVICE_EXTENSION *pdx, TDBGBLOCK __user* pDB);
+extern int DbgPoke(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
+extern int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
+extern int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
+extern int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
+extern int DbgStopLoop(DEVICE_EXTENSION *pdx);
+extern int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
+extern int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB);
+extern int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB);
+extern int WaitEvent(DEVICE_EXTENSION *pdx, int nArea, int msTimeOut);
+extern int TestEvent(DEVICE_EXTENSION *pdx, int nArea);
+#endif
diff --git a/drivers/staging/ced1401/use1401.h b/drivers/staging/ced1401/use1401.h
new file mode 100644
index 0000000..86294e2
--- /dev/null
+++ b/drivers/staging/ced1401/use1401.h
@@ -0,0 +1,287 @@
+/****************************************************************************
+** use1401.h
+** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010
+** Authors: Paul Cox, Tim Bergel, Greg Smith
+** See CVS for revisions.
+**
+** Because the size of a long is different between 32-bit and 64-bit on some
+** systems, we avoid this in this interface.
+****************************************************************************/
+#ifndef __USE1401_H__
+#define __USE1401_H__
+#include "machine.h"
+
+// Some definitions to make things compatible. If you want to use Use1401 directly
+//  from a Windows program you should define U14_NOT_DLL, in which case you also
+//  MUST make sure that your application startup code calls U14InitLib().
+// DLL_USE1401 is defined when you are building the Use1401 dll, not otherwise.
+#ifdef _IS_WINDOWS_
+#ifndef U14_NOT_DLL
+#ifdef DLL_USE1401
+#define U14API(retType) retType DllExport __stdcall
+#else
+#define U14API(retType) retType DllImport __stdcall
+#endif
+#endif
+
+#define U14ERRBASE -500
+#define U14LONG long
+#endif
+
+#ifdef LINUX
+#define U14ERRBASE -1000
+#define U14LONG int
+#endif
+
+#ifdef _QT
+#ifndef U14_NOT_DLL
+#undef U14API
+#define U14API(retType) retType __declspec(dllimport) __stdcall
+#endif
+#undef U14LONG
+#define U14LONG int
+#endif
+
+#ifndef U14API
+#define U14API(retType) retType
+#endif
+
+#ifndef U14LONG
+#define U14LONG long
+#endif
+
+/// Error codes: We need them here as user space can see them.
+#define U14ERR_NOERROR        0             // no problems
+
+/// Device error codes, but these don't need to be extended - a succession is assumed
+#define U14ERR_STD            4              // standard 1401 connected
+#define U14ERR_U1401          5              // u1401 connected
+#define U14ERR_PLUS           6              // 1401 plus connected
+#define U14ERR_POWER          7              // Power1401 connected
+#define U14ERR_U14012         8              // u1401 mkII connected
+#define U14ERR_POWER2         9
+#define U14ERR_U14013        10
+#define U14ERR_POWER3        11
+
+/// NBNB Error numbers need shifting as some linux error codes start at 512
+#define U14ERR(n)             (n+U14ERRBASE)
+#define U14ERR_OFF            U14ERR(0)      /* 1401 there but switched off    */
+#define U14ERR_NC             U14ERR(-1)     /* 1401 not connected             */
+#define U14ERR_ILL            U14ERR(-2)     /* if present it is ill           */
+#define U14ERR_NOIF           U14ERR(-3)     /* I/F card missing               */
+#define U14ERR_TIME           U14ERR(-4)     /* 1401 failed to come ready      */
+#define U14ERR_BADSW          U14ERR(-5)     /* I/F card bad switches          */
+#define U14ERR_PTIME          U14ERR(-6)     /* 1401plus failed to come ready  */
+#define U14ERR_NOINT          U14ERR(-7)     /* couldn't grab the int vector   */
+#define U14ERR_INUSE          U14ERR(-8)     /* 1401 is already in use         */
+#define U14ERR_NODMA          U14ERR(-9)     /* couldn't get DMA channel       */
+#define U14ERR_BADHAND        U14ERR(-10)    /* handle provided was bad        */
+#define U14ERR_BAD1401NUM     U14ERR(-11)    /* 1401 number provided was bad   */
+
+#define U14ERR_NO_SUCH_FN     U14ERR(-20)    /* no such function               */
+#define U14ERR_NO_SUCH_SUBFN  U14ERR(-21)    /* no such sub function           */
+#define U14ERR_NOOUT          U14ERR(-22)    /* no room in output buffer       */
+#define U14ERR_NOIN           U14ERR(-23)    /* no input in buffer             */
+#define U14ERR_STRLEN         U14ERR(-24)    /* string longer than buffer      */
+#define U14ERR_ERR_STRLEN     U14ERR(-24)    /* string longer than buffer      */
+#define U14ERR_LOCKFAIL       U14ERR(-25)    /* failed to lock memory          */
+#define U14ERR_UNLOCKFAIL     U14ERR(-26)    /* failed to unlock memory        */
+#define U14ERR_ALREADYSET     U14ERR(-27)    /* area already set up            */
+#define U14ERR_NOTSET         U14ERR(-28)    /* area not set up                */
+#define U14ERR_BADAREA        U14ERR(-29)    /* illegal area number            */
+#define U14ERR_FAIL           U14ERR(-30)    /* we failed for some other reason*/
+
+#define U14ERR_NOFILE         U14ERR(-40)    /* command file not found         */
+#define U14ERR_READERR        U14ERR(-41)    /* error reading command file     */
+#define U14ERR_UNKNOWN        U14ERR(-42)    /* unknown command                */
+#define U14ERR_HOSTSPACE      U14ERR(-43)    /* not enough host space to load  */
+#define U14ERR_LOCKERR        U14ERR(-44)    /* could not lock resource/command*/
+#define U14ERR_CLOADERR       U14ERR(-45)    /* CLOAD command failed           */
+
+#define U14ERR_TOXXXERR       U14ERR(-60)    /* tohost/1401 failed             */
+#define U14ERR_NO386ENH       U14ERR(-80)    /* not 386 enhanced mode          */
+#define U14ERR_NO1401DRIV     U14ERR(-81)    /* no device driver               */
+#define U14ERR_DRIVTOOOLD     U14ERR(-82)    /* device driver too old          */
+
+#define U14ERR_TIMEOUT        U14ERR(-90)    /* timeout occurred               */
+
+#define U14ERR_BUFF_SMALL     U14ERR(-100)   /* buffer for getstring too small */
+#define U14ERR_CBALREADY      U14ERR(-101)   /* there is already a callback    */
+#define U14ERR_BADDEREG       U14ERR(-102)   /* bad parameter to deregcallback */
+#define U14ERR_NOMEMORY       U14ERR(-103)   /* no memory for allocation       */
+
+#define U14ERR_DRIVCOMMS      U14ERR(-110)   /* failed talking to driver       */
+#define U14ERR_OUTOFMEMORY    U14ERR(-111)   /* needed memory and couldnt get it*/
+
+/// 1401 type codes.
+#define U14TYPE1401           0           /* standard 1401                  */
+#define U14TYPEPLUS           1           /* 1401 plus                      */
+#define U14TYPEU1401          2           /* u1401                          */
+#define U14TYPEPOWER          3           /* power1401                      */
+#define U14TYPEU14012         4           /* u1401 mk II                    */
+#define U14TYPEPOWER2         5           /* power1401 mk II                */
+#define U14TYPEU14013         6           /* u1401-3                        */
+#define U14TYPEPOWER3         7           /* power1401-3                    */
+#define U14TYPEUNKNOWN        -1          /* dont know                      */
+
+/// Transfer flags to allow driver capabilities to be interrogated
+
+/// Constants for transfer flags
+#define U14TF_USEDMA          1           /* Transfer flag for use DMA      */
+#define U14TF_MULTIA          2           /* Transfer flag for multi areas  */
+#define U14TF_FIFO            4           /* for FIFO interface card        */
+#define U14TF_USB2            8           /* for USB2 interface and 1401    */
+#define U14TF_NOTIFY          16          /* for event notifications        */
+#define U14TF_SHORT           32          /* for PCI can short cycle        */
+#define U14TF_PCI2            64          /* for new PCI card 1401-70       */
+#define U14TF_CIRCTH          128         /* Circular-mode to host          */
+#define U14TF_DIAG            256         /* Diagnostics/debug functions    */
+#define U14TF_CIRC14          512         /* Circular-mode to 1401          */
+
+/// Definitions of element sizes for DMA transfers - to allow byte-swapping
+#define ESZBYTES              0           /* BYTE element size value        */
+#define ESZWORDS              1           /* WORD element size value        */
+#define ESZLONGS              2           /* long element size value        */
+#define ESZUNKNOWN            0           /* unknown element size value     */
+
+/// These define required access types for the debug/diagnostics function
+#define BYTE_SIZE             1           /* 8-bit access                   */
+#define WORD_SIZE             2           /* 16-bit access                  */
+#define LONG_SIZE             3           /* 32-bit access                  */
+
+/// Stuff used by U14_GetTransfer
+#define GET_TX_MAXENTRIES  257          /* (max length / page size + 1) */
+
+#ifdef _IS_WINDOWS_
+#pragma pack(1)
+
+typedef struct                          /* used for U14_GetTransfer results */
+{                                          /* Info on a single mapped block */
+   U14LONG physical;
+   U14LONG size;
+} TXENTRY;
+
+typedef struct TGetTxBlock              /* used for U14_GetTransfer results */
+{                                               /* matches structure in VXD */
+   U14LONG size;
+   U14LONG linear;
+   short   seg;
+   short   reserved;
+   short   avail;                      /* number of available entries */
+   short   used;                       /* number of used entries */
+   TXENTRY entries[GET_TX_MAXENTRIES];       /* Array of mapped block info */
+} TGET_TX_BLOCK;
+
+typedef TGET_TX_BLOCK *LPGET_TX_BLOCK;
+
+#pragma pack()
+#endif
+
+#ifdef LINUX
+typedef struct                          /* used for U14_GetTransfer results */
+{                                       /* Info on a single mapped block */
+   long long physical;
+   long     size;
+} TXENTRY;
+
+typedef struct TGetTxBlock              /* used for U14_GetTransfer results */
+{                                       /* matches structure in VXD */
+   long long linear;                    /* linear address */
+   long     size;                       /* total size of the mapped area, holds id when called */
+   short    seg;                        /* segment of the address for Win16 */
+   short    reserved;
+   short    avail;                      /* number of available entries */
+   short    used;                       /* number of used entries */
+   TXENTRY  entries[GET_TX_MAXENTRIES]; /* Array of mapped block info */
+} TGET_TX_BLOCK;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+U14API(int)   U14WhenToTimeOut(short hand);         // when to timeout in ms
+U14API(short) U14PassedTime(int iTime);             // non-zero if iTime passed
+
+U14API(short) U14LastErrCode(short hand);
+
+U14API(short) U14Open1401(short n1401);
+U14API(short) U14Close1401(short hand);
+U14API(short) U14Reset1401(short hand);
+U14API(short) U14ForceReset(short hand);
+U14API(short) U14TypeOf1401(short hand);
+U14API(short) U14NameOf1401(short hand, char* pBuf, WORD wMax);
+
+U14API(short) U14Stat1401(short hand);
+U14API(short) U14CharCount(short hand);
+U14API(short) U14LineCount(short hand);
+
+U14API(short) U14SendString(short hand, const char* pString);
+U14API(short) U14GetString(short hand, char* pBuffer, WORD wMaxLen);
+U14API(short) U14SendChar(short hand, char cChar);
+U14API(short) U14GetChar(short hand, char* pcChar);
+
+U14API(short) U14LdCmd(short hand, const char* command);
+U14API(DWORD) U14Ld(short hand, const char* vl, const char* str);
+
+U14API(short) U14SetTransArea(short hand, WORD wArea, void *pvBuff,
+                                            DWORD dwLength, short eSz);
+U14API(short) U14UnSetTransfer(short hand, WORD wArea);
+U14API(short) U14SetTransferEvent(short hand, WORD wArea, BOOL bEvent,
+                                  BOOL bToHost, DWORD dwStart, DWORD dwLength);
+U14API(int)   U14TestTransferEvent(short hand, WORD wArea);
+U14API(int)   U14WaitTransferEvent(short hand, WORD wArea, int msTimeOut);
+U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock);
+
+U14API(short) U14ToHost(short hand, char* pAddrHost,DWORD dwSize,DWORD dw1401,
+                                                            short eSz);
+U14API(short) U14To1401(short hand, const char* pAddrHost,DWORD dwSize,DWORD dw1401,
+                                                            short eSz);
+
+U14API(short) U14SetCircular(short hand, WORD wArea, BOOL bToHost, void *pvBuff,
+                                         DWORD dwLength);
+
+U14API(int)   U14GetCircBlk(short hand, WORD wArea, DWORD *pdwOffs);
+U14API(int)   U14FreeCircBlk(short hand, WORD wArea, DWORD dwOffs, DWORD dwSize,
+                                         DWORD *pdwOffs);
+
+U14API(short) U14StrToLongs(const char* pszBuff, U14LONG *palNums, short sMaxLongs);
+U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs);
+
+U14API(void)  U14SetTimeout(short hand, int lTimeout);
+U14API(int)   U14GetTimeout(short hand);
+U14API(short) U14OutBufSpace(short hand);
+U14API(int)   U14BaseAddr1401(short hand);
+U14API(int)   U14DriverVersion(short hand);
+U14API(int)   U14DriverType(short hand);
+U14API(short) U14DriverName(short hand, char* pBuf, WORD wMax);
+U14API(short) U14GetUserMemorySize(short hand, DWORD *pMemorySize);
+U14API(short) U14KillIO1401(short hand);
+
+U14API(short) U14BlkTransState(short hand);
+U14API(short) U14StateOf1401(short hand);
+
+U14API(short) U14Grab1401(short hand);
+U14API(short) U14Free1401(short hand);
+U14API(short) U14Peek1401(short hand, DWORD dwAddr, int nSize, int nRepeats);
+U14API(short) U14Poke1401(short hand, DWORD dwAddr, DWORD dwValue, int nSize, int nRepeats);
+U14API(short) U14Ramp1401(short hand, DWORD dwAddr, DWORD dwDef, DWORD dwEnable, int nSize, int nRepeats);
+U14API(short) U14RampAddr(short hand, DWORD dwDef, DWORD dwEnable, int nSize, int nRepeats);
+U14API(short) U14StopDebugLoop(short hand);
+U14API(short) U14GetDebugData(short hand, U14LONG *plValue);
+
+U14API(short) U14StartSelfTest(short hand);
+U14API(short) U14CheckSelfTest(short hand, U14LONG *pData);
+U14API(short) U14TransferFlags(short hand);
+U14API(void)  U14GetErrorString(short nErr, char* pStr, WORD wMax);
+U14API(int)   U14MonitorRev(short hand);
+U14API(void)  U14CloseAll(void);
+
+U14API(short) U14WorkingSet(DWORD dwMinKb, DWORD dwMaxKb);
+U14API(int)   U14InitLib(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* End of ifndef __USE1401_H__ */
diff --git a/drivers/staging/ced1401/use14_ioc.h b/drivers/staging/ced1401/use14_ioc.h
new file mode 100644
index 0000000..15ca638
--- /dev/null
+++ b/drivers/staging/ced1401/use14_ioc.h
@@ -0,0 +1,301 @@
+/* use14_ioc.h
+** definitions of use1401 module stuff that is shared between use1401 and the driver.
+** Copyright (C) Cambridge Electronic Design Limited 2010
+** Author Greg P Smith
+************************************************************************************/
+#ifndef __USE14_IOC_H__
+#define __USE14_IOC_H__
+
+#define  MAX_TRANSAREAS   8   /* The number of transfer areas supported by driver */
+
+#define i386
+#include "winioctl.h"                   /* needed so we can access driver   */
+
+/*
+** Defines for IOCTL functions to ask driver to perform. These must be matched
+** in both use1401 and in the driver. The IOCTL code contains a command
+** identifier, plus other information about the device, the type of access
+** with which the file must have been opened, and the type of buffering.
+** The IOCTL function codes from 0x80 to 0xFF are for developer use.
+*/
+#define  FILE_DEVICE_CED1401    0x8001
+#define  FNNUMBASE              0x800
+
+#define  U14_OPEN1401            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE,               \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_CLOSE1401           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+1,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SENDSTRING          CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+2,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_RESET1401           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+3,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETCHAR             CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+4,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SENDCHAR            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+5,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STAT1401            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+6,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_LINECOUNT           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+7,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETSTRING           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+8,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_REGCALLBACK         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+9,             \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETMONITORBUF       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+10,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SETTRANSFER         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+11,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_UNSETTRANSFER       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+12,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SETTRANSEVENT       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+13,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETOUTBUFSPACE      CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+14,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETBASEADDRESS      CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+15,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETDRIVERREVISION   CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+16,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETTRANSFER         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+17,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_KILLIO1401          CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+18,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_BLKTRANSSTATE       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+19,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_BYTECOUNT           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+20,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_ZEROBLOCKCOUNT      CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+21,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STOPCIRCULAR        CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+22,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STATEOF1401         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+23,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_REGISTERS1401       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+24,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GRAB1401            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+25,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_FREE1401            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+26,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STEP1401            CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+27,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SET1401REGISTERS    CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+28,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STEPTILL1401        CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+29,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SETORIN             CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+30,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_STARTSELFTEST       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+31,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_CHECKSELFTEST       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+32,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_TYPEOF1401          CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+33,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_TRANSFERFLAGS       CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+34,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGPEEK             CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+35,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGPOKE             CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+36,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGRAMPDATA         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+37,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGRAMPADDR         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+38,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGGETDATA          CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+39,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_DBGSTOPLOOP         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+40,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_FULLRESET           CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+41,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_SETCIRCULAR         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+42,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_GETCIRCBLK          CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+43,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+#define  U14_FREECIRCBLK         CTL_CODE( FILE_DEVICE_CED1401,     \
+                                           FNNUMBASE+44,            \
+                                           METHOD_BUFFERED,         \
+                                           FILE_ANY_ACCESS)
+
+//--------------- Structures that are shared with the driver -------------
+#pragma pack(1)
+
+typedef struct                  /* used for get/set standard 1401 registers */
+{
+   short   sPC;
+   char    A;
+   char    X;
+   char    Y;
+   char    stat;
+   char    rubbish;
+} T1401REGISTERS;
+
+typedef union     /* to communicate with 1401 driver status & control funcs */
+{
+   char           chrs[22];
+   short          ints[11];
+   long           longs[5];
+   T1401REGISTERS registers;
+} TCSBLOCK;
+
+typedef TCSBLOCK*  LPTCSBLOCK;
+
+typedef struct paramBlk
+{
+    short       sState;
+    TCSBLOCK    csBlock;
+} PARAMBLK;
+
+typedef PARAMBLK*   PPARAMBLK;
+
+typedef struct TransferDesc          /* Structure and type for SetTransArea */
+{
+   WORD        wArea;            /* number of transfer area to set up       */
+   void FAR *  lpvBuff;          /* address of transfer area                */
+   DWORD       dwLength;         /* length of area to set up                */
+   short       eSize;            /* size to move (for swapping on MAC)      */
+} TRANSFERDESC;
+
+typedef TRANSFERDESC FAR *    LPTRANSFERDESC;
+
+/* This is the structure used to set up a transfer area */
+typedef struct VXTransferDesc    /* use1401.c and use1432x.x use only       */
+{
+   WORD        wArea;            /* number of transfer area to set up       */
+   WORD        wAddrSel;         /* 16 bit selector for area                */
+   DWORD       dwAddrOfs;        /* 32 bit offset for area start            */
+   DWORD       dwLength;         /* length of area to set up                */
+} VXTRANSFERDESC;
+
+#pragma pack()
+
+#endif
\ No newline at end of file
diff --git a/drivers/staging/ced1401/userspace/use1401.c b/drivers/staging/ced1401/userspace/use1401.c
new file mode 100644
index 0000000..d4c6316
--- /dev/null
+++ b/drivers/staging/ced1401/userspace/use1401.c
@@ -0,0 +1,3035 @@
+/****************************************************************************
+** use1401.c
+** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License
+** as published by the Free Software Foundation; either version 2
+** of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+**
+** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road
+**              Cambridge, CB6 0FE.
+**              www.ced.co.uk
+**              greg@ced.co.uk
+**
+**  Title:      USE1401.C
+**  Version:    4.00
+**  Author:     Paul Cox, Tim Bergel, Greg Smith
+**
+** The code was vigorously pruned in DEC 2010 to remove the macintosh options
+** and to get rid of the 16-bit support. It has also been aligned with the
+** Linux version. See CVS for revisions. This will work for Win 9x onwards.
+****************************************************************************
+**
+** Notes on Windows interface to driver
+** ************************************
+**
+** Under Windows 9x and NT, Use1401 uses DeviceIoControl to get access to
+** the 1401 driver. This has parameters for the device handle, the function
+** code, an input pointer and byte count, an output pointer and byte count
+** and a pointer to a DWORD to hold the output byte count. Note that input
+** and output are from the point-of-view of the driver, so the output stuff
+** is used to read values from the 1401, not send to the 1401. The use of
+** these parameters varies with the function in use and the operating
+** system; there are five separate DIOC calls SendString, GetString and
+** SetTransferArea all have their own specialised calls, the rest use the
+** Status1401 or Control1401 functions.
+**
+** There are two basic styles of DIOC call used, one for Win9x VxD drivers
+** and one for NT Kernel-mode and WDM drivers (see below for tables showing
+** the different parameters used. The array bUseNTDIOC[] selects between
+** these two calling styles.
+**
+** Function codes
+** In Win3.x, simple function codes from 0 to 40 were used, shifted left 8
+** bits with a sub-function code in the lower 8 bits. These were also used
+** in the Windows 95 driver, though we had to add 1 to the code value to
+** avoid problems (Open from CreateFile is zero), and the sub-function code
+** is now unused. We found that this gave some problems with Windows 98
+** as the function code values are reserved by microsoft, so we switched to
+** using the NT function codes instead. The NT codes are generated using the
+** CTL_CODE macro, essentially this gives 0x80012000 | (func << 2), where
+** func is the original 0 to 34 value. The driver will handle both types of
+** code and Use1432 only uses the NT codes if it knows the driver is new
+** enough. The array bUseNTCodes[] holds flags on the type of codes required.
+** GPS/TDB Dec 2010: we removed the bUseNTCodes array as this is always true
+** as we no longer support ancient versions.
+**
+** The CreateFile and CloseFile function calls are also handled
+** by DIOC, using the special function codes 0 and -1 respectively.
+**
+** Input pointer and buffer size
+** These are intended for data sent to the device driver. In nearly all cases
+** they are unused in calls to the Win95 driver, the NT driver uses them
+** for all information sent to the driver. The table below shows the pointer
+** and byte count used for the various calls:
+**
+**                      Win 95                  Win NT
+** SendString           NULL, 0                 pStr, nStr
+** GetString            NULL, 0                 NULL, 0
+** SetTransferArea      pBuf, nBuf (unused?)    pDesc, nDesc
+** GetTransfer          NULL, 0                 NULL, 0
+** Status1401           NULL, 0                 NULL, 0
+** Control1401          NULL, 0                 pBlk, nBlk
+**
+** pStr and nStr are pointers to a char buffer and the buffer length for
+** string I/O, note that these are temporary buffers owned by the DLL, not
+** application memory, pBuf and nBuf are the transfer area buffer (I think
+** these are unused), pDesc and nDesc are the TRANSFERDESC structure, pBlk
+** and nBlk are the TCSBLOCK structure.
+**
+**
+** Output pointer and buffer size
+** These are intended for data read from the device driver. These are used
+** for almost all information sent to the Win95 driver, the NT driver uses
+** them for information read from the driver, chiefly the error code. The
+** table below shows the pointer and byte count used for the various calls:
+**
+**                      Win 95                  Win NT
+** SendString           pStr, nStr              pPar, nPar
+** GetString            pStr, nStr+2            pStr, nStr+2
+** SetTransferArea      pDesc, nDesc            pPar, nPar
+** GetTransfer          pGet, nGet              pGet, nGet
+** Status1401           pBlk, nBlk              pPar, nPar
+** Control1401          pBlk, nBlk              pPar, nPar
+**
+** pStr and nStr are pointers to a char buffer and the buffer length for
+** string I/O, the +2 for GetString refers to two spare bytes at the start
+** used to hold the string length and returning an error code for NT. Note
+** again that these are (and must be) DLL-owned temporary buffers. pPar
+** and nPar are a PARAM structure used in NT (it holds an error code and a 
+** TCSBLOCK structure). pDesc and nDesc are the VXTRANSFERDESC structure,
+** pBlk and nBlk are the TCSBLOCK structure. pGet and nGet indicate the
+** TGET_TX_BLOCK structure used for GetTransfer.
+**
+**
+** The output byte count
+** Both drivers return the output buffer size here, regardless of the actual
+** bytes output. This is used to check that we did get through to the driver.
+**
+** Multiple 1401s
+** **************
+**
+** We have code that tries to support the use of multiple 1401s, but there
+** are problems: The lDriverVersion and lDriverType variables are global, not
+** per-1401 (a particular problem as the U14 functions that use them don't
+** have a hand parameter). In addition, the mechansim for finding a free
+** 1401 depends upon the 1401 device driver open operation failing if it's
+** already in use, which doesn't always happen, particularly with the VxDs.
+** The code in TryToOpen tries to fix this by relying on TYPEOF1401 to detect
+** the 1401-in-use state - the VxDs contain special code to help this. This is
+** working OK but multiple 1401 support works better with the Win2000 drivers.
+**
+** USB driver
+** **********
+**
+** The USB driver, which runs on both Win98 and NT2000, uses the NT-style
+** calling convention, both for the DIOC codes and the DIOC parameters. The
+** TryToOpen function has been altered to look for an NT driver first in
+** the appropriate circumstances, and to set the driver DIOC flags up in
+** the correct state.
+**
+** Adding a new 1401 type - now almost nothing to do
+** *************************************************
+**
+** The 1401 types are defined by a set of U14TYPExxxx codes in USE1401.H.
+** You should add a new one of these to keep things tidy for applications.
+**
+** DRIVERET_MAX (below) specifies the maximum allowed type code from the
+** 1401 driver; I have set this high to accomodate as yet undesigned 1401
+** types. Similarly, as long as the command file names follow the ARM,
+** ARN, ARO sequence, these are calculated by the ExtForType function, so
+** you don't need to do anything here either.
+**
+** Version number
+** **************
+** The new U14InitLib() function returns 0 if the OS is incapable of use,
+** otherwise is returns the version of the USE1401 library. This is done
+** in three parts: Major(31-24).Minor(23-16).Revision.(15-0) (brackets are
+** the bits used). The Major number starts at 2 for the first revision with
+** the U14InitLib() function. Changes to the Major version means that we
+** have broken backwards compatibility. Minor number changes mean that we
+** have added new functionality that does not break backwards compatibility.
+** we starts at 0. Revision changes mean we have fixed something. Each index
+** returns to 0 when a higer one changes.
+*/
+#define U14LIB_MAJOR 4
+#define U14LIB_MINOR 0
+#define U14LIB_REVISION 0
+#define U14LIB_VERSION ((U14LIB_MAJOR<<24) | (U14LIB_MINOR<<16) | U14LIB_REVISION)
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "USE1401.H"
+
+#ifdef _IS_WINDOWS_
+#include <io.h>
+#include <windows.h>
+#pragma warning(disable: 4100) /* Disable "Unused formal parameter" warning */
+#include <assert.h>
+#include "process.h"
+
+
+#define sprintf wsprintf
+#define PATHSEP '\\'
+#define PATHSEPSTR "\\"
+#define DEFCMDPATH "\\1401\\"   // default command path if all else fails
+#define MINDRIVERMAJREV 1       // minimum driver revision level we need
+#define __packed                // does nothing in Windows
+
+#include "use14_ioc.h"          // links to device driver stuff
+#endif
+
+#ifdef LINUX
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <libgen.h>
+#define PATHSEP '/'
+#define PATHSEPSTR "/"
+#define DEFCMDPATH "/var/1401/" // default command path if all else fails
+#define MINDRIVERMAJREV 2       // minimum driver revision level we need
+
+#include "ced_ioctl.h"          // links to device driver stuff
+#endif
+
+#define MAX1401         8       // The number of 1401s that can be supported
+
+/*
+** These are the 1401 type codes returned by the driver, they are a slightly
+** odd sequence & start for reasons of compatability with the DOS driver.
+** The maximum code value is the upper limit of 1401 device types.
+*/
+#define DRIVRET_STD     4       // Codes for 1401 types matching driver values
+#define DRIVRET_U1401   5       // This table does not need extending, as
+#define DRIVRET_PLUS    6       // we can calculate values now.
+#define DRIVRET_POWER   7       // but we need all of these values still
+#define DRIVRET_MAX     26      // Maximum tolerated code - future designs
+
+/*
+** These variables store data that will be used to generate the last
+** error string. For now, a string will hold the 1401 command file name.
+*/
+static char szLastName[20];     // additional text information
+
+/*
+** Information stored per handle. NBNB, driverType and DriverVersion used to be
+** only stored once for all handles... i.e. nonsensical. This change means that
+** three U14...() calls now include handles that were previously void. We have
+** set a constructor and a destructor call for the library (see the end) to
+** initialise important structures, or call use1401_load().
+*/
+static short asDriverType[MAX1401] = {0};
+static int lLastDriverVersion = U14ERR_NO1401DRIV;
+static int lLastDriverType = U14TYPEUNKNOWN;
+static int alDriverVersion[MAX1401];            // version/type of each driver
+static int alTimeOutPeriod[MAX1401];            // timeout time in milliseconds
+static short asLastRetCode[MAX1401];            // last code from a fn call
+static short asType1401[MAX1401] = {0};         // The type of the 1401
+static BOOL abGrabbed[MAX1401] = {0};           // Flag for grabbed, set true by grab1401
+static int iAttached = 0;                       // counts process attaches so can let go
+
+#ifdef _IS_WINDOWS_
+/****************************************************************************
+** Windows NT Specific Variables and internal types
+****************************************************************************/
+static HANDLE aHand1401[MAX1401] = {0};         // handles for 1401s
+static HANDLE aXferEvent[MAX1401] = {0};        // transfer events for the 1401s
+static LPVOID apAreas[MAX1401][MAX_TRANSAREAS]; // Locked areas
+static DWORD  auAreas[MAX1401][MAX_TRANSAREAS]; // Size of locked areas
+static BOOL   bWindows9x = FALSE;               // if we are Windows 95 or better
+#ifdef _WIN64
+#define USE_NT_DIOC(ind) TRUE
+#else
+static BOOL   abUseNTDIOC[MAX1401];             // Use NT-style DIOC parameters */
+#define USE_NT_DIOC(ind) abUseNTDIOC[ind]
+#endif
+
+#endif
+
+#ifdef LINUX
+static int aHand1401[MAX1401] = {0};    // handles for 1401s
+#define INVALID_HANDLE_VALUE 0          // to avoid code differences
+#endif
+
+
+/*
+** The CmdHead relates to backwards compatibility with ancient Microsoft (and Sperry!)
+** versions of BASIC, where this header was needed so we could load a command into
+** memory.
+*/
+#pragma pack(1)                 // pack our structure
+typedef struct CmdHead          // defines header block on command
+{                               // for PC commands
+   char   acBasic[5];           // BASIC information - needed to align things
+   WORD   wBasicSz;             // size as seen by BASIC
+   WORD   wCmdSize;             // size of the following info
+} __packed CMDHEAD;
+#pragma pack()                  // back to normal
+
+/*
+** The rest of the header looks like this...
+**  int    iRelPnt;             relocation pointer... actual start
+**  char   acName[8];           string holding the command name
+**  BYTE   bMonRev;             monitor revision level
+**  BYTE   bCmdRev;             command revision level
+*/
+
+typedef CMDHEAD *LPCMDHEAD;     // pointer to a command header
+
+#define  MAXSTRLEN   255        // maximum string length we use
+#define  TOHOST      FALSE
+#define  TO1401      TRUE
+
+static short CheckHandle(short h)
+{
+    if ((h < 0) || (h >= MAX1401))  // must be legal range...
+        return U14ERR_BADHAND;
+    if (aHand1401[h] <= 0)          // must be open
+        return U14ERR_BADHAND;
+    return U14ERR_NOERROR;
+}
+
+#ifdef _IS_WINDOWS_
+/****************************************************************************
+** U14Status1401    Used for functions which do not pass any data in but
+**                  get data back
+****************************************************************************/
+static short U14Status1401(short sHand, LONG lCode, TCSBLOCK* pBlk)
+{
+    DWORD dwBytes = 0;
+
+    if ((sHand < 0) || (sHand >= MAX1401))  /* Check parameters */
+        return U14ERR_BADHAND;
+#ifndef _WIN64
+    if (!USE_NT_DIOC(sHand)) 
+    {   /* Windows 9x DIOC methods? */
+        if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk,sizeof(TCSBLOCK),&dwBytes,NULL))
+            return (short)((dwBytes>=sizeof(TCSBLOCK)) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS);
+        else
+            return (short)GetLastError();
+    }
+    else
+#endif
+    {                                       /* Windows NT or USB driver */
+        PARAMBLK rWork;
+        rWork.sState = U14ERR_DRIVCOMMS;
+        if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, &rWork,sizeof(PARAMBLK),&dwBytes,NULL) &&
+            (dwBytes >= sizeof(PARAMBLK)))
+        {
+            *pBlk = rWork.csBlock;
+            return rWork.sState;
+        }
+    }
+
+    return U14ERR_DRIVCOMMS;
+}
+
+/****************************************************************************
+** U14Control1401   Used for functions which pass data in and only expect
+**                  an error code back
+****************************************************************************/
+static short U14Control1401(short sHand, LONG lCode, TCSBLOCK* pBlk)
+{
+    DWORD dwBytes = 0;
+
+    if ((sHand < 0) || (sHand >= MAX1401))              /* Check parameters */
+        return U14ERR_BADHAND;
+
+#ifndef _WIN64
+    if (!USE_NT_DIOC(sHand))                    
+    {                            /* Windows 9x DIOC methods */
+        if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk, sizeof(TCSBLOCK), &dwBytes, NULL))
+            return (short)(dwBytes >= sizeof(TCSBLOCK) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS);
+        else
+            return (short)GetLastError();
+    }
+    else
+#endif
+    {                            /* Windows NT or later */
+        PARAMBLK rWork;
+        rWork.sState = U14ERR_DRIVCOMMS;
+        if (DeviceIoControl(aHand1401[sHand], lCode, pBlk, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
+            (dwBytes >= sizeof(PARAMBLK)))
+            return rWork.sState;
+    }
+
+    return U14ERR_DRIVCOMMS;
+}
+#endif
+
+/****************************************************************************
+** SafeTickCount
+** Gets time in approximately units of a millisecond.
+*****************************************************************************/
+static long SafeTickCount()
+{
+#ifdef _IS_WINDOWS_
+    return GetTickCount();
+#endif
+#ifdef LINUX
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (tv.tv_sec*1000 + tv.tv_usec/1000);
+#endif
+}
+
+/****************************************************************************
+** A utility routine to get the command file extension for a given type
+** of 1401. We assume the type code is vaguely legal.
+****************************************************************************/
+static int ExtForType(short sType, char* szExt)
+{
+    szExt[0] = 0;                       /* Default return is a blank string */
+    switch (sType)
+    {
+    case U14TYPE1401: strcpy(szExt, ".CMD");  break;    // Standard 1401
+    case U14TYPEPLUS: strcpy(szExt, ".GXC");  break;    // 1401 plus
+    default:               // All others are in a predictable sequence
+        strcpy(szExt, ".ARM");
+            szExt[3] = (char)('M' + sType - U14TYPEU1401);
+        if (szExt[3] > 'Z')             // Wrap round to ARA after ARZ
+                szExt[3] = (char)(szExt[3] - 26);
+    }
+    return 0;
+}
+
+/****************************************************************************
+**   U14WhenToTimeOut
+**       Returns the time to time out in time units suitable for the machine
+** we are running on  ie millsecs for pc/linux, or Mac/
+****************************************************************************/
+U14API(int) U14WhenToTimeOut(short hand)
+{
+    int iNow = SafeTickCount();
+    if ((hand >= 0) && (hand < MAX1401))
+        iNow += alTimeOutPeriod[hand];
+    return iNow;
+}
+
+/****************************************************************************
+** U14PassedTime
+** Returns non zero if the timed passed in has been passed 0 if not
+****************************************************************************/
+U14API(short) U14PassedTime(int lCheckTime)
+{
+    return (short)((SafeTickCount()-lCheckTime) > 0);
+}
+
+/****************************************************************************
+** TranslateString
+** Tidies up string that U14GetString returns. Converts all the commas in a
+** string to spaces. Removes terminating CR character. May do more in future.
+****************************************************************************/
+static void TranslateString(char* pStr)
+{
+    int i = 0;
+    while (pStr[i])
+    {
+        if (pStr[i] == ',')
+            pStr[i] = ' ';              /* convert comma to space */
+        ++i;
+    }
+
+    if ((i > 0) && (pStr[i-1] == '\n'))  /* kill terminating LF */
+        pStr[i-1] = (char)0;
+}
+
+/****************************************************************************
+** U14StrToLongs
+** Converts a string to an array of longs and returns the number of values
+****************************************************************************/
+U14API(short) U14StrToLongs(const char* pszBuff, U14LONG *palNums, short sMaxLongs)
+{
+    WORD wChInd = 0;                // index into source
+    short sLgInd = 0;               // index into result longs
+
+    while (pszBuff[wChInd] &&       // until we get to end of string...
+           (sLgInd < sMaxLongs))    // ...or filled the buffer
+    {
+        // Why not use a C Library converter?
+        switch (pszBuff[wChInd])
+        {
+        case '-':
+        case '0': case '1':   case '2': case '3':   case '4':
+        case '5': case '6':   case '7': case '8':   case '9':
+            {
+                BOOL bDone = FALSE; // true at end of number
+                int iSign = 1;      // sign of number
+                long lValue = 0;
+
+                while ((!bDone) && pszBuff[wChInd])
+                {
+                    switch (pszBuff[wChInd])
+                    {
+                    case '-':
+                        iSign = -1; // swap sign
+                        break;
+
+                    case '0': case '1':   case '2': case '3':   case '4':
+                    case '5': case '6':   case '7': case '8':   case '9':
+                        lValue *= 10;   // move to next digit base 10
+                        lValue += ((int)pszBuff[wChInd]-(int)'0');
+                        break;
+
+                    default:        // end of number
+                        bDone = TRUE;
+                        break;
+                    }
+                    wChInd++;       // move onto next character
+                }
+                palNums[sLgInd] = lValue * iSign;
+                sLgInd++;
+            }
+            break;
+
+        default:
+            wChInd++;               // look at next char
+            break;
+        }
+    }
+    return (sLgInd);
+}
+
+
+/****************************************************************************
+** U14LongsFrom1401
+** Gets the next waiting line from the 1401 and converts it longs
+** Returns the number of numbers read or an error.
+****************************************************************************/
+U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs)
+{
+    char szWork[MAXSTRLEN];
+    short sResult = U14GetString(hand, szWork, MAXSTRLEN);/* get reply from 1401   */
+    if (sResult == U14ERR_NOERROR)                  /* if no error convert   */
+        sResult = U14StrToLongs(szWork, palBuff, sMaxLongs);
+    return sResult;
+}
+
+/****************************************************************************
+**   U14CheckErr
+**   Sends the ERR command to the 1401 and gets the result. Returns 0, a
+**   negative error code, or the first error value.
+****************************************************************************/
+U14API(short) U14CheckErr(short hand)
+{
+    short sResult = U14SendString(hand, ";ERR;");
+    if (sResult == U14ERR_NOERROR)
+    {
+        U14LONG er[3];
+        sResult = U14LongsFrom1401(hand, er, 3);
+        if (sResult > 0)
+        {
+            sResult = (short)er[0];        /* Either zero or an error value */
+#ifdef _DEBUG
+            if (er[0] != 0)
+            {
+                char szMsg[50];
+                sprintf(szMsg, "U14CheckErr returned %d,%d\n", er[0], er[1]);
+                OutputDebugString(szMsg);
+            }
+#endif
+        }
+        else
+        {
+            if (sResult == 0)
+                sResult = U14ERR_TIMEOUT;      /* No numbers equals timeout */
+        }
+    }
+
+    return sResult;
+}
+
+/****************************************************************************
+** U14LastErrCode
+** Returns the last code from the driver. This is for Windows where all calls
+** go through the Control and Status routines, so we can save any error.
+****************************************************************************/
+U14API(short) U14LastErrCode(short hand)
+{
+    if ((hand < 0) || (hand >= MAX1401))
+        return U14ERR_BADHAND;
+    return asLastRetCode[hand];
+}
+
+/****************************************************************************
+** U14SetTimeout
+** Set the timeout period for 1401 comms in milliseconds
+****************************************************************************/
+U14API(void) U14SetTimeout(short hand, int lTimeOut)
+{
+    if ((hand < 0) || (hand >= MAX1401))
+        return;
+    alTimeOutPeriod[hand] = lTimeOut;
+}
+
+/****************************************************************************
+** U14GetTimeout
+** Get the timeout period for 1401 comms in milliseconds
+****************************************************************************/
+U14API(int) U14GetTimeout(short hand)
+{
+    if ((hand < 0) || (hand >= MAX1401))
+        return U14ERR_BADHAND;
+    return alTimeOutPeriod[hand];
+}
+
+/****************************************************************************
+** U14OutBufSpace
+** Return the space in the output buffer, or an error.
+****************************************************************************/
+U14API(short) U14OutBufSpace(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_GETOUTBUFSPACE,&csBlock);
+    if (sErr == U14ERR_NOERROR)
+        sErr = csBlock.ints[0];
+    return sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_GetOutBufSpace(aHand1401[hand]) : sErr;
+#endif
+}
+
+
+/****************************************************************************
+** U14BaseAddr1401
+** Returns the 1401 base address or an error code. Meaningless nowadays
+****************************************************************************/
+U14API(int) U14BaseAddr1401(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    int iError = U14Status1401(hand, U14_GETBASEADDRESS,&csBlock);
+    if (iError == U14ERR_NOERROR)
+        iError = csBlock.longs[0];
+    return iError;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_GetBaseAddress(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14StateOf1401
+** Return error state, either NOERROR or a negative code.
+****************************************************************************/
+U14API(short) U14StateOf1401(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_STATEOF1401, &csBlock);
+    if (sErr == U14ERR_NOERROR)
+    {
+        sErr = csBlock.ints[0];      // returned 1401 state
+        if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX))
+            sErr = U14ERR_NOERROR;
+    }
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        sErr = (short)CED_StateOf1401(aHand1401[hand]);
+        if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX))
+            sErr = U14ERR_NOERROR;
+    }
+#endif
+    return sErr;
+}
+
+/****************************************************************************
+** U14DriverVersion
+** Returns the driver version. Hi word is major revision, low word is minor.
+** If you pass in a silly handle (like -1), we return the version of the last
+** driver we know of (to cope with PCI and no 1401 attached).
+****************************************************************************/
+U14API(int) U14DriverVersion(short hand)
+{
+    return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverVersion : alDriverVersion[hand];
+}
+
+/****************************************************************************
+** U14DriverType
+** Returns the driver type. The type, 0=ISA/NU-Bus, 1=PCI, 2=USB, 3=HSS
+** If you pass in a silly handle (like -1), we return the type of the last
+** driver we know of (to cope with PCI and no 1401 attached).
+****************************************************************************/
+U14API(int) U14DriverType(short hand)
+{
+    return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverType : asDriverType[hand];
+}
+
+/****************************************************************************
+** U14DriverName
+** Returns the driver type as 3 character (ISA, PCI, USB or HSS))
+****************************************************************************/
+U14API(short) U14DriverName(short hand, char* pBuf, WORD wMax)
+{
+    char* pName;
+    *pBuf = 0;                             // Start off with a blank string
+    switch (U14DriverType(hand))           // Results according to type
+    {
+    case 0:  pName = "ISA"; break;
+    case 1:  pName = "PCI"; break;
+    case 2:  pName = "USB"; break;
+    case 3:  pName = "HSS"; break;
+    default: pName = "???"; break;
+    }
+    strncpy(pBuf, pName, wMax);            // Copy the correct name to return
+
+    return U14ERR_NOERROR;
+}
+
+/****************************************************************************
+** U14BlkTransState
+** Returns 0 no transfer in progress, 1 transfer in progress or an error code
+****************************************************************************/
+U14API(short) U14BlkTransState(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_BLKTRANSSTATE, &csBlock);
+    if (sErr == U14ERR_NOERROR)
+        sErr = csBlock.ints[0];
+    return sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_BlkTransState(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14Grab1401
+** Take control of the 1401 for diagnostics purposes. USB does nothing.
+****************************************************************************/
+U14API(short) U14Grab1401(short hand)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+#ifdef _IS_WINDOWS_
+        if (abGrabbed[hand])            // 1401 should not have been grabbed
+            sErr = U14ERR_ALREADYSET;   // Error code defined for this
+        else
+        {
+            TCSBLOCK csBlock;
+            sErr = U14Control1401(hand, U14_GRAB1401, &csBlock);
+        }
+#endif
+#ifdef LINUX
+        // 1401 should not have been grabbed
+        sErr = abGrabbed[hand] ? U14ERR_ALREADYSET : CED_Grab1401(aHand1401[hand]);
+#endif
+        if (sErr == U14ERR_NOERROR)
+            abGrabbed[hand] = TRUE;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14Free1401
+****************************************************************************/
+U14API(short)  U14Free1401(short hand)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+#ifdef _IS_WINDOWS_
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+            TCSBLOCK csBlock;
+            sErr = U14Control1401(hand, U14_FREE1401, &csBlock);
+        }
+        else
+            sErr = U14ERR_NOTSET;
+#endif
+#ifdef LINUX
+        // 1401 should not have been grabbed
+        sErr = abGrabbed[hand] ? CED_Free1401(aHand1401[hand]) : U14ERR_NOTSET;
+#endif
+        if (sErr == U14ERR_NOERROR)
+            abGrabbed[hand] = FALSE;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14Peek1401
+** DESCRIPTION  Cause the 1401 to do one or more peek operations.
+** If lRepeats is zero, the loop will continue until U14StopDebugLoop
+** is called. After the peek is done, use U14GetDebugData to retrieve
+** the results of the peek.
+****************************************************************************/
+U14API(short) U14Peek1401(short hand, DWORD dwAddr, int nSize, int nRepeats)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+#ifdef _IS_WINDOWS_
+            TCSBLOCK csBlock;
+            csBlock.longs[0] = (long)dwAddr;
+            csBlock.longs[1] = nSize;
+            csBlock.longs[2] = nRepeats;
+            sErr = U14Control1401(hand, U14_DBGPEEK, &csBlock);
+#endif
+#ifdef LINUX
+            TDBGBLOCK dbb;
+            dbb.iAddr = (int)dwAddr;
+            dbb.iWidth = nSize;
+            dbb.iRepeats = nRepeats;
+            sErr = CED_DbgPeek(aHand1401[hand], &dbb);
+#endif
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14Poke1401
+** DESCRIPTION  Cause the 1401 to do one or more poke operations.
+** If lRepeats is zero, the loop will continue until U14StopDebugLoop
+** is called.
+****************************************************************************/
+U14API(short) U14Poke1401(short hand, DWORD dwAddr, DWORD dwValue,
+                                      int nSize, int nRepeats)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+#ifdef _IS_WINDOWS_
+            TCSBLOCK csBlock;
+            csBlock.longs[0] = (long)dwAddr;
+            csBlock.longs[1] = nSize;
+            csBlock.longs[2] = nRepeats;
+            csBlock.longs[3] = (long)dwValue;
+            sErr = U14Control1401(hand, U14_DBGPOKE, &csBlock);
+#endif
+#ifdef LINUX
+            TDBGBLOCK dbb;
+            dbb.iAddr = (int)dwAddr;
+            dbb.iWidth = nSize;
+            dbb.iRepeats= nRepeats;
+            dbb.iData = (int)dwValue;
+            sErr = CED_DbgPoke(aHand1401[hand], &dbb);
+#endif
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14Ramp1401
+** DESCRIPTION  Cause the 1401 to loop, writing a ramp to a location.
+** If lRepeats is zero, the loop will continue until U14StopDebugLoop.
+****************************************************************************/
+U14API(short) U14Ramp1401(short hand, DWORD dwAddr, DWORD dwDef, DWORD dwEnable,
+                                      int nSize, int nRepeats)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+#ifdef _IS_WINDOWS_
+            TCSBLOCK csBlock;
+            csBlock.longs[0] = (long)dwAddr;
+            csBlock.longs[1] = (long)dwDef;
+            csBlock.longs[2] = (long)dwEnable;
+            csBlock.longs[3] = nSize;
+            csBlock.longs[4] = nRepeats;
+            sErr = U14Control1401(hand, U14_DBGRAMPDATA, &csBlock);
+#endif
+#ifdef LINUX
+            TDBGBLOCK dbb;
+            dbb.iAddr = (int)dwAddr;
+            dbb.iDefault = (int)dwDef;
+            dbb.iMask = (int)dwEnable;
+            dbb.iWidth = nSize;
+            dbb.iRepeats = nRepeats;
+            sErr = CED_DbgRampAddr(aHand1401[hand], &dbb);
+#endif
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14RampAddr
+** DESCRIPTION  Cause the 1401 to loop, reading from a ramping location.
+** If lRepeats is zero, the loop will continue until U14StopDebugLoop
+****************************************************************************/
+U14API(short) U14RampAddr(short hand, DWORD dwDef, DWORD dwEnable,
+                                      int nSize, int nRepeats)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+#ifdef _IS_WINDOWS_
+            TCSBLOCK csBlock;
+            csBlock.longs[0] = (long)dwDef;
+            csBlock.longs[1] = (long)dwEnable;
+            csBlock.longs[2] = nSize;
+            csBlock.longs[3] = nRepeats;
+            sErr = U14Control1401(hand, U14_DBGRAMPADDR, &csBlock);
+#endif
+#ifdef LINUX
+            TDBGBLOCK dbb;
+            dbb.iDefault = (int)dwDef;
+            dbb.iMask = (int)dwEnable;
+            dbb.iWidth = nSize;
+            dbb.iRepeats = nRepeats;
+            sErr = CED_DbgRampAddr(aHand1401[hand], &dbb);
+#endif
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+**    U14StopDebugLoop
+**    DESCRIPTION Stops a peek\poke\ramp that, with repeats set to zero,
+**    will otherwise continue forever.
+****************************************************************************/
+U14API(short) U14StopDebugLoop(short hand)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+#ifdef _IS_WINDOWS_
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+            TCSBLOCK csBlock;
+            sErr = U14Control1401(hand, U14_DBGSTOPLOOP, &csBlock);
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+#endif
+#ifdef LINUX
+        sErr = abGrabbed[hand] ? CED_DbgStopLoop(aHand1401[hand]) : U14ERR_NOTSET;
+#endif
+    return sErr;
+}
+
+/****************************************************************************
+** U14GetDebugData
+** DESCRIPTION Returns the result from a previous peek operation.
+****************************************************************************/
+U14API(short) U14GetDebugData(short hand, U14LONG* plValue)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        if (abGrabbed[hand])    // 1401 should have been grabbed
+        {
+#ifdef _IS_WINDOWS_
+            TCSBLOCK csBlock;
+            sErr = U14Status1401(hand, U14_DBGGETDATA, &csBlock);
+            if (sErr == U14ERR_NOERROR)
+                *plValue = csBlock.longs[0];    // Return the data
+#endif
+#ifdef LINUX
+            TDBGBLOCK dbb;
+            sErr = CED_DbgGetData(aHand1401[hand], &dbb);
+            if (sErr == U14ERR_NOERROR)
+                *plValue = dbb.iData;                     /* Return the data */
+#endif
+        }
+        else
+            sErr = U14ERR_NOTSET;
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14StartSelfTest
+****************************************************************************/
+U14API(short) U14StartSelfTest(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    return U14Control1401(hand, U14_STARTSELFTEST, &csBlock);
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_StartSelfTest(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14CheckSelfTest
+****************************************************************************/
+U14API(short) U14CheckSelfTest(short hand, U14LONG *pData)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_CHECKSELFTEST, &csBlock);
+    if (sErr == U14ERR_NOERROR)
+    {
+        pData[0] = csBlock.longs[0];        /* Return the results to user */
+        pData[1] = csBlock.longs[1];
+        pData[2] = csBlock.longs[2];
+    }
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)                /* Check parameters */
+    {
+        TGET_SELFTEST gst;
+        sErr = CED_CheckSelfTest(aHand1401[hand], &gst);
+        if (sErr == U14ERR_NOERROR)
+        {
+            pData[0] = gst.code;        /* Return the results to user */
+            pData[1] = gst.x;
+            pData[2] = gst.y;
+        }
+    }
+#endif
+    return sErr;
+}
+
+/****************************************************************************
+** U14GetUserMemorySize
+****************************************************************************/
+U14API(short) U14GetUserMemorySize(short hand, DWORD *pMemorySize)
+{
+    // The original 1401 used a different command for getting the size
+    short sErr = U14SendString(hand, (asType1401[hand] == U14TYPE1401) ? "MEMTOP;" : "MEMTOP,?;");
+    *pMemorySize = 0;         /* if we get error then leave size set at 0  */
+    if (sErr == U14ERR_NOERROR)
+    {
+        U14LONG alLimits[4];
+        sErr = U14LongsFrom1401(hand, alLimits, 4);
+        if (sErr > 0)              /* +ve sErr is the number of values read */
+        {
+            sErr = U14ERR_NOERROR;                  /* All OK, flag success */
+            if (asType1401[hand] == U14TYPE1401)    /* result for standard  */
+                *pMemorySize = alLimits[0] - alLimits[1]; /* memtop-membot */
+            else
+                *pMemorySize = alLimits[0];   /* result for plus or u1401  */
+        }
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14TypeOf1401
+** Returns the type of the 1401, maybe unknown
+****************************************************************************/
+U14API(short) U14TypeOf1401(short hand)
+{
+    if ((hand < 0) || (hand >= MAX1401))                /* Check parameters */
+        return U14ERR_BADHAND;
+    else
+        return asType1401[hand];
+}
+
+/****************************************************************************
+** U14NameOf1401
+** Returns the type of the 1401 as a string, blank if unknown
+****************************************************************************/
+U14API(short) U14NameOf1401(short hand, char* pBuf, WORD wMax)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+    char* pName;
+    switch (asType1401[hand])               // Results according to type
+    {
+    case U14TYPE1401:  pName = "Std 1401"; break;
+    case U14TYPEPLUS:  pName = "1401plus"; break;
+    case U14TYPEU1401: pName = "micro1401"; break;
+    case U14TYPEPOWER: pName = "Power1401"; break;
+    case U14TYPEU14012:pName = "Micro1401 mk II"; break;
+    case U14TYPEPOWER2:pName = "Power1401 mk II"; break;
+    case U14TYPEU14013:pName = "Micro1401-3"; break;
+    case U14TYPEPOWER3:pName = "Power1401-3"; break;
+    default:           pName = "Unknown";
+    }
+        strncpy(pBuf, pName, wMax);
+    }
+    return sErr;
+}
+
+/****************************************************************************
+** U14TransferFlags
+**  Returns the driver block transfer flags.
+**  Bits can be set - see U14TF_ constants in use1401.h
+*****************************************************************************/
+U14API(short) U14TransferFlags(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_TRANSFERFLAGS, &csBlock);
+    return (sErr == U14ERR_NOERROR) ? (short)csBlock.ints[0] : sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_TransferFlags(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** GetDriverVersion
+** Actually reads driver version from the device driver.
+** Hi word is major revision, low word is minor revision.
+** Assumes that hand has been checked. Also codes driver type in bits 24 up.
+*****************************************************************************/
+static int GetDriverVersion(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    int iErr = U14Status1401(hand, U14_GETDRIVERREVISION, &csBlock);
+    if (iErr == U14ERR_NOERROR)
+        iErr = csBlock.longs[0];
+    return iErr;
+#endif
+#ifdef LINUX
+    return CED_GetDriverRevision(aHand1401[hand]);
+#endif
+}
+
+/****************************************************************************
+** U14MonitorRev
+** Returns the 1401 monitor revision number.
+** The number returned is the minor revision - the part after the
+** decimal point - plus the major revision times 1000.
+*****************************************************************************/
+U14API(int) U14MonitorRev(short hand)
+{
+    int iRev = 0;
+    int iErr = CheckHandle(hand);
+    if (iErr != U14ERR_NOERROR)                 // Check open and in use
+        return iErr;
+
+    if (asType1401[hand] >= U14TYPEPOWER2)      // The Power2 onwards can give us the monitor
+    {                                           //  revision directly for all versions
+        iErr = U14SendString(hand, "INFO,S,28;");
+        if (iErr == U14ERR_NOERROR)
+        {
+            U14LONG lVals[2];                   // Read a single number being the revision
+            iErr = U14LongsFrom1401(hand, lVals, 1);
+            if (iErr > 0)
+            {
+                iErr = U14ERR_NOERROR;
+                iRev = lVals[0];                // This is the minor part of the revision
+                iRev += asType1401[hand] * 10000;
+            }
+        }
+    }
+    else
+    {                                           /* Do it the hard way for older hardware */
+        iErr = U14SendString(hand, ";CLIST;");     /* ask for command levels */
+        if (iErr == U14ERR_NOERROR)
+        {     
+            while (iErr == U14ERR_NOERROR)
+            {
+                char wstr[50];
+                iErr = U14GetString(hand, wstr, 45);
+                if (iErr == U14ERR_NOERROR)
+                {
+                    char *pstr = strstr(wstr,"RESET");  /* Is this the RESET command? */
+                    if ((pstr == wstr) && (wstr[5] == ' '))
+                    {
+                        char *pstr2;
+                        size_t l;
+                        pstr += 6;       /* Move past RESET and followinmg char */
+                        l = strlen(pstr);       /* The length of text remaining */
+                        while (((pstr[l-1] == ' ') || (pstr[l-1] == 13)) && (l > 0))
+                        {
+                            pstr[l-1] = 0;         /* Tidy up string at the end */
+                            l--;                  /* by removing spaces and CRs */
+                        }
+                        pstr2 = strchr(pstr, '.');    /* Find the decimal point */
+                        if (pstr2 != NULL)                /* If we found the DP */
+                        {
+                            *pstr2 = 0;                /* End pstr string at DP */
+                            pstr2++;              /* Now past the decimal point */
+                            iRev = atoi(pstr2);   /* Get the number after point */
+                        }
+                        iRev += (atoi(pstr) * 1000);    /* Add first bit * 1000 */
+                    }
+                    if ((strlen(wstr) < 3) && (wstr[0] == ' '))
+                        break;              /* Spot the last line of results */
+                }
+            }
+        }
+    }
+    if (iErr == U14ERR_NOERROR)            /* Return revision if no error */
+        iErr = iRev;
+
+    return iErr;
+}
+
+/****************************************************************************
+** U14TryToOpen     Tries to open the 1401 number passed
+**  Note : This will succeed with NT driver even if no I/F card or
+**         1401 switched off, so we check state and close the driver
+**         if the state is unsatisfactory in U14Open1401.
+****************************************************************************/
+#ifdef _IS_WINDOWS_
+#define U14NAMEOLD "\\\\.\\CED_140%d"
+#define U14NAMENEW "\\\\.\\CED%d"
+static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle)
+{
+    short sErr = U14ERR_NOERROR;
+    HANDLE hDevice = INVALID_HANDLE_VALUE;
+    DWORD dwErr = 0;
+    int nFirst, nLast, nDev = 0;        /* Used for the search for a 1401 */
+    BOOL bOldName = FALSE;               /* start by looking for a modern driver */
+
+    if (n1401 == 0)                             /* If we need to look for a 1401 */
+    {
+        nFirst = 1;                             /* Set the search range */
+        nLast = MAX1401;                        /* through all the possible 1401s */
+    }
+    else
+        nFirst = nLast = n1401;                 /* Otherwise just one 1401 */
+
+    while (hDevice == INVALID_HANDLE_VALUE)     /* Loop to try for a 1401 */
+    {
+        for (nDev = nFirst; nDev <= nLast; nDev++)
+        {
+            char szDevName[40];                 /* name of the device to open */
+            sprintf(szDevName, bOldName ? U14NAMEOLD : U14NAMENEW, nDev);
+            hDevice = CreateFile(szDevName, GENERIC_WRITE | GENERIC_READ,
+                                 0, 0,          /* Unshared mode does nothing as this is a device */
+                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+            if (hDevice != INVALID_HANDLE_VALUE)/* Check 1401 if opened */
+            {
+                TCSBLOCK csBlock;
+                assert(aHand1401[nDev-1] == INVALID_HANDLE_VALUE);  // assert if already open
+                aHand1401[nDev-1] = hDevice;    /* Save handle for now */
+
+#ifndef _WIN64
+                // Use DIOC method if not windows 9x or if using new device name
+                abUseNTDIOC[nDev-1] = (BOOL)(!bWindows9x || !bOldName);
+#endif
+                sErr = U14Status1401((short)(nDev-1), U14_TYPEOF1401, &csBlock);
+                if (sErr == U14ERR_NOERROR)
+                {
+                    *plRetVal = csBlock.ints[0];
+                    if (csBlock.ints[0] == U14ERR_INUSE)/* Prevent multi opens */
+                    {
+                        CloseHandle(hDevice);   /* treat as open failure */
+                        hDevice = INVALID_HANDLE_VALUE;
+                        aHand1401[nDev-1] = INVALID_HANDLE_VALUE;
+                        sErr = U14ERR_INUSE;
+                    }
+                    else
+                        break;                  /* Exit from for loop on success */
+                }
+                else
+                {
+                    CloseHandle(hDevice);       /* Give up if func fails */
+                    hDevice = INVALID_HANDLE_VALUE;
+                    aHand1401[nDev-1] = INVALID_HANDLE_VALUE;
+                }
+            }
+            else
+            {
+                DWORD dwe = GetLastError();     /* Get error code otherwise */
+                if ((dwe != ERROR_FILE_NOT_FOUND) || (dwErr == 0))
+                    dwErr = dwe;                /* Ignore repeats of 'not found' */
+            }
+        }
+
+        if ((hDevice == INVALID_HANDLE_VALUE) &&/* No device found, and... */
+            (bWindows9x) &&                     /* ...old names are allowed, and... */
+            (bOldName == FALSE))                /* ...not tried old names yet */
+            bOldName = TRUE;                    /* Set flag and go round again */
+        else
+            break;                              /* otherwise that's all folks */
+    }
+
+    if (hDevice != INVALID_HANDLE_VALUE)        /* If we got our device open */
+        *psHandle = (short)(nDev-1);            /* return 1401 number opened */
+    else
+    {
+        if (dwErr == ERROR_FILE_NOT_FOUND)      /* Sort out the error codes */
+            sErr = U14ERR_NO1401DRIV;           /* if file not found */
+        else if (dwErr == ERROR_NOT_SUPPORTED)
+            sErr = U14ERR_DRIVTOOOLD;           /* if DIOC not supported */
+        else if (dwErr == ERROR_ACCESS_DENIED)
+            sErr = U14ERR_INUSE;
+        else
+            sErr = U14ERR_DRIVCOMMS;            /* otherwise assume comms problem */
+    }
+    return sErr;
+}
+#endif
+#ifdef LINUX
+static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle)
+{
+    short sErr = U14ERR_NOERROR;
+    int fh = 0;                             // will be 1401 handle
+    int iErr = 0;
+    int nFirst, nLast, nDev = 0;            // Used for the search for a 1401
+
+    if (n1401 == 0)                         // If we need to look for a 1401
+    {
+        nFirst = 1;                             /* Set the search range */
+        nLast = MAX1401;                        /* through all the possible 1401s */
+    }
+    else
+        nFirst = nLast = n1401;                 /* Otherwise just one 1401 */
+
+    for (nDev = nFirst; nDev <= nLast; nDev++)
+    {
+        char szDevName[40];                 // name of the device to open
+        sprintf(szDevName,"/dev/cedusb/%d", nDev-1);
+        fh = open(szDevName, O_RDWR);       // can only be opened once at a time
+        if (fh > 0)                         // Check 1401 if opened
+        {
+            int iType1401 = CED_TypeOf1401(fh); // get 1401 type
+            aHand1401[nDev-1] = fh;         // Save handle for now
+            if (iType1401 >= 0)
+            {
+                *plRetVal = iType1401;
+                 break;                     // Exit from for loop on success
+            }
+            else
+            {
+                close(fh);                  // Give up if func fails
+                fh = 0;
+                aHand1401[nDev-1] = 0;
+            }
+        }
+        else
+        {
+            if (((errno != ENODEV) && (errno != ENOENT)) || (iErr == 0))
+                iErr = errno;                // Ignore repeats of 'not found'
+        }
+    }
+
+
+    if (fh)                                 // If we got our device open
+        *psHandle = (short)(nDev-1);        // return 1401 number opened
+    else
+    {
+        if ((iErr == ENODEV) || (iErr == ENOENT)) // Sort out the error codes
+            sErr = U14ERR_NO1401DRIV;       // if file not found
+        else if (iErr == EBUSY)
+            sErr = U14ERR_INUSE;
+        else
+            sErr = U14ERR_DRIVCOMMS;        // otherwise assume comms problem
+    }
+
+    return sErr;
+}
+#endif
+/****************************************************************************
+** U14Open1401
+** Tries to get the 1401 for use by this application
+*****************************************************************************/
+U14API(short) U14Open1401(short n1401)
+{
+    long     lRetVal = -1;
+    short    sErr;
+    short    hand = 0;
+    
+    if ((n1401 < 0) || (n1401 > MAX1401))       // must check the 1401 number
+        return U14ERR_BAD1401NUM;
+
+    szLastName[0] = 0;          /* initialise the error info string */
+
+    sErr = U14TryToOpen(n1401, &lRetVal, &hand);
+    if (sErr == U14ERR_NOERROR)
+    {
+        long lDriverVersion = GetDriverVersion(hand);   /* get driver revision */
+        long lDriverRev = -1;
+		if (lDriverVersion >= 0)                    /* can use it if all OK */
+        {
+            lLastDriverType = (lDriverVersion >> 24) & 0x000000FF;
+            asDriverType[hand] = (short)lLastDriverType;    /* Drv type */
+            lLastDriverVersion = lDriverVersion & 0x00FFFFFF;
+            alDriverVersion[hand] = lLastDriverVersion;     /* Actual version */
+            lDriverRev = ((lDriverVersion>>16) & 0x00FF);    /* use hi word */
+        }
+        else
+        {
+            U14Close1401(hand);    /* If there is a problem we should close */
+            return (short)lDriverVersion;      /* and return the error code */
+        }
+    
+        if (lDriverRev < MINDRIVERMAJREV)       /* late enough version?     */
+        {
+            U14Close1401(hand);    /* If there is a problem we should close */
+            return U14ERR_DRIVTOOOLD;           /* too old                  */
+        }
+    
+        asLastRetCode[hand] = U14ERR_NOERROR; /* Initialise this 1401s info */
+        abGrabbed[hand] = FALSE;          /* we are not in single step mode */
+        U14SetTimeout(hand, 3000);      /* set 3 seconds as default timeout */
+
+        switch (lRetVal)
+        {
+        case DRIVRET_STD:  asType1401[hand] = U14TYPE1401; break;      /* Some we do by hand */
+        case DRIVRET_U1401:asType1401[hand] = U14TYPEU1401; break;
+        case DRIVRET_PLUS: asType1401[hand] = U14TYPEPLUS; break;
+        default:  // For the power upwards, we can calculate the codes
+                if ((lRetVal >= DRIVRET_POWER) && (lRetVal <= DRIVRET_MAX))
+                    asType1401[hand] = (short)(lRetVal - (DRIVRET_POWER - U14TYPEPOWER));
+                else
+                    asType1401[hand] = U14TYPEUNKNOWN;
+                break;
+            }
+        U14KillIO1401(hand);                     /* resets the 1401 buffers */
+
+        if (asType1401[hand] != U14TYPEUNKNOWN)   /* If all seems OK so far */
+        {
+            sErr = U14CheckErr(hand);        /* we can check 1401 comms now */
+            if (sErr != 0)                       /* If this failed to go OK */
+                U14Reset1401(hand); /* Reset the 1401 to try to sort it out */
+        }
+
+        sErr = U14StateOf1401(hand);/* Get the state of the 1401 for return */
+        if (sErr == U14ERR_NOERROR)
+            sErr = hand;                 /* return the handle if no problem */
+        else
+            U14Close1401(hand);    /* If there is a problem we should close */
+    }
+
+    return sErr;
+}
+
+
+/****************************************************************************
+** U14Close1401
+** Closes the 1401 so someone else can use it.
+****************************************************************************/
+U14API(short) U14Close1401(short hand)
+{
+    int j;
+    int iAreaMask = 0;                          // Mask for active areas
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)                 // Check open and in use
+        return sErr;
+
+    for (j = 0; j<MAX_TRANSAREAS; ++j)
+    {
+        TGET_TX_BLOCK gtb;
+        int iReturn = U14GetTransfer(hand, &gtb);   // get area information
+        if (iReturn == U14ERR_NOERROR)          // ignore if any problem
+            if (gtb.used)
+                iAreaMask |= (1 << j);          // set a bit for each used area
+    }
+
+    if (iAreaMask)                              // if any areas are in use
+    {
+        U14Reset1401(hand);                     // in case an active transfer running
+        for (j = 0; j < MAX_TRANSAREAS; ++j)    // Locate locked areas
+            if (iAreaMask & (1 << j))           // And kill off any transfers
+                U14UnSetTransfer(hand, (WORD)j);
+    }
+
+#ifdef _IS_WINDOWS_
+    if (aXferEvent[hand])                       // if this 1401 has an open event handle
+    {
+        CloseHandle(aXferEvent[hand]);          // close down the handle
+        aXferEvent[hand] = NULL;                // and mark it as gone
+    }
+
+    if (CloseHandle(aHand1401[hand]))
+#endif
+#ifdef LINUX
+    if (close(aHand1401[hand]) == 0)            // make sure that close works
+#endif
+    {
+        aHand1401[hand] = INVALID_HANDLE_VALUE;
+        asType1401[hand] = U14TYPEUNKNOWN;
+        return U14ERR_NOERROR;
+    }
+    else
+        return U14ERR_BADHAND;     /* BUGBUG GetLastError() ? */
+}
+
+/**************************************************************************
+**
+** Look for open 1401s and attempt to close them down. 32-bit windows only.
+**************************************************************************/
+U14API(void) U14CloseAll(void)
+{
+    int i;
+    for (i = 0; i < MAX1401; i++)       // Tidy up and make safe
+        if (aHand1401[i] != INVALID_HANDLE_VALUE)
+            U14Close1401((short)i);     // Last ditch close 1401
+}
+
+/****************************************************************************
+** U14Reset1401
+** Resets the 1401
+****************************************************************************/
+U14API(short) U14Reset1401(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    return U14Control1401(hand, U14_RESET1401, &csBlock);
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_Reset1401(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14ForceReset
+**    Sets the 1401 full reset flag, so that next call to Reset1401 will
+**     always cause a genuine reset.
+*****************************************************************************/
+U14API(short) U14ForceReset(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    return U14Control1401(hand, U14_FULLRESET, &csBlock);
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_FullReset(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14KillIO1401
+**    Removes any pending IO from the buffers.
+*****************************************************************************/
+U14API(short) U14KillIO1401(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    return U14Control1401(hand, U14_KILLIO1401, &csBlock);
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_KillIO1401(aHand1401[hand]) : sErr;
+#endif
+}
+
+
+/****************************************************************************
+** U14SendString
+** Send characters to the 1401
+*****************************************************************************/
+U14API(short) U14SendString(short hand, const char* pString)
+{
+    int nChars;                     // length we are sending
+    long lTimeOutTicks;             // when to time out
+    BOOL bSpaceToSend;              // space to send yet
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+
+    nChars = (int)strlen(pString);  // get string length we want to send
+    if (nChars > MAXSTRLEN)
+        return U14ERR_STRLEN;       // String too long
+
+#ifdef _IS_WINDOWS_
+    // To get here we must wait for the buffer to have some space
+    lTimeOutTicks = U14WhenToTimeOut(hand);
+    do
+    {
+        bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
+    }
+    while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks));
+
+    if (!bSpaceToSend)             /* Last-ditch attempt to avoid timeout */
+    {           /* This can happen with anti-virus or network activity! */
+        int i;
+        for (i = 0; (i < 4) && (!bSpaceToSend); ++i)
+        {
+            Sleep(25);       /* Give other threads a chance for a while */
+            bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
+        }
+    }
+
+    if (asLastRetCode[hand] == U14ERR_NOERROR)      /* no errors? */
+    {
+        if (bSpaceToSend)
+        {
+            PARAMBLK    rData;
+            DWORD       dwBytes;
+            char        tstr[MAXSTRLEN+5];          /* Buffer for chars */
+
+            if ((hand < 0) || (hand >= MAX1401))
+                sErr = U14ERR_BADHAND;
+            else
+            {
+                strcpy(tstr, pString);              /* Into local buf */
+#ifndef _WIN64
+                if (!USE_NT_DIOC(hand))             /* Using WIN 95 driver access? */
+                {
+                    int iOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_SENDSTRING,
+                                    NULL, 0, tstr, nChars,
+                                    &dwBytes, NULL);
+                    if (iOK)
+                        sErr = (dwBytes >= (DWORD)nChars) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS;
+                    else
+                        sErr = (short)GetLastError();
+                }
+                else
+#endif
+                {
+                    int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_SENDSTRING,
+                                    tstr, nChars,
+                                    &rData,sizeof(PARAMBLK),&dwBytes,NULL);
+                    if (iOK && (dwBytes >= sizeof(PARAMBLK)))
+                        sErr = rData.sState;
+                    else
+                        sErr = U14ERR_DRIVCOMMS;
+                }
+
+                if (sErr != U14ERR_NOERROR) // If we have had a comms error
+                    U14ForceReset(hand);    //  make sure we get real reset
+            }
+
+            return sErr;
+
+        }
+        else
+        {
+            U14ForceReset(hand);                //  make sure we get real reset
+            return U14ERR_TIMEOUT;
+        }
+    }
+    else
+        return asLastRetCode[hand];
+#endif
+#ifdef LINUX
+    // Just try to send it and see what happens!
+    sErr = CED_SendString(aHand1401[hand], pString, nChars);
+    if (sErr != U14ERR_NOOUT)       // if any result except "no room in output"...
+    {
+        if (sErr != U14ERR_NOERROR) // if a problem...
+             U14ForceReset(hand);   // ...make sure we get real reset next time
+        return sErr;                // ... we are done as nothing we can do
+    }
+
+    // To get here we must wait for the buffer to have some space
+    lTimeOutTicks = U14WhenToTimeOut(hand);
+    do
+    {
+        bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
+        if (!bSpaceToSend)
+            sched_yield();          // let others have fun while we wait
+    }
+    while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks));
+
+    if (asLastRetCode[hand] == U14ERR_NOERROR)                /* no errors? */
+    {
+        if (bSpaceToSend)
+        {
+            sErr = CED_SendString(aHand1401[hand], pString, nChars);
+            if (sErr != U14ERR_NOERROR) // If we have had a comms error
+                U14ForceReset(hand);    //  make sure we get real reset
+            return sErr;
+        }
+        else
+        {
+            U14ForceReset(hand);                //  make sure we get real reset
+            return U14ERR_TIMEOUT;
+        }
+    }
+    else
+        return asLastRetCode[hand];
+#endif
+}
+
+/****************************************************************************
+** U14SendChar
+** Send character to the 1401
+*****************************************************************************/
+U14API(short) U14SendChar(short hand, char cChar)
+{
+#ifdef _IS_WINDOWS_
+    char sz[2]=" ";                         // convert to a string and send
+    sz[0] = cChar;
+    sz[1] = 0;
+    return(U14SendString(hand, sz));        // String routines are better
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_SendChar(aHand1401[hand], cChar) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14GetString
+** Get a string from the 1401. Returns a null terminated string.
+** The string is all the characters up to the next CR in the buffer
+** or the end of the buffer if that comes first. This only returns text
+** if there is a CR in the buffer. The terminating CR character is removed.
+** wMaxLen  Is the size of the buffer and must be at least 2 or an error.
+** Returns  U14ERR_NOERR if OK with the result in the string or a negative
+**          error code. Any error from the device causes us to set up for
+**          a full reset.
+****************************************************************************/
+U14API(short) U14GetString(short hand, char* pBuffer, WORD wMaxLen)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)             // If an error...
+        return sErr;                        // ...bail out!
+
+#ifdef _IS_WINDOWS_
+    if (wMaxLen>1)                          // we need space for terminating 0
+    {
+        BOOL bLineToGet;                    // true when a line to get
+        long lTimeOutTicks = U14WhenToTimeOut(hand);
+        do
+            bLineToGet = (BOOL)(U14LineCount(hand) != 0);
+        while (!bLineToGet && !U14PassedTime(lTimeOutTicks));
+
+        if (!bLineToGet)             /* Last-ditch attempt to avoid timeout */
+        {           /* This can happen with anti-virus or network activity! */
+            int i;
+            for (i = 0; (i < 4) && (!bLineToGet); ++i)
+            {
+                Sleep(25);       /* Give other threads a chance for a while */
+                bLineToGet = (BOOL)(U14LineCount(hand) != 0);
+            }
+        }
+
+        if (bLineToGet)
+        {
+            if (asLastRetCode[hand] == U14ERR_NOERROR)     /* all ok so far */
+            {
+                DWORD       dwBytes = 0;
+                *((WORD *)pBuffer) = wMaxLen;       /* set up length */
+#ifndef _WIN64
+                if (!USE_NT_DIOC(hand))             /* Win 95 DIOC here ? */
+                {
+                    char tstr[MAXSTRLEN+5];         /* Buffer for Win95 chars */
+                    int iOK;
+
+                    if (wMaxLen > MAXSTRLEN)        /* Truncate length */
+                        wMaxLen = MAXSTRLEN;    
+
+                    *((WORD *)tstr) = wMaxLen;      /* set len */
+
+                    iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING,
+                                    NULL, 0, tstr, wMaxLen+sizeof(short),
+                                    &dwBytes, NULL);
+                    if (iOK)                        /* Device IO control OK ? */
+                    {
+                        if (dwBytes >= 0)           /* If driver OK */
+                        {
+                            strcpy(pBuffer, tstr);
+                            sErr = U14ERR_NOERROR;
+                        }
+                        else
+                            sErr = U14ERR_DRIVCOMMS;
+                    }
+                    else
+                    {
+                        sErr = (short)GetLastError();
+                        if (sErr > 0)               /* Errors are -ve */
+                            sErr = (short)-sErr;
+                    }
+                }
+                else
+#endif
+                {       /* Here for NT, the DLL must own the buffer */
+                    HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE,wMaxLen+sizeof(short));
+                    if (hMem)
+                    {
+                        char* pMem = (char*)GlobalLock(hMem);
+                        if (pMem)
+                        {
+                            int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING,
+                                            NULL, 0, pMem, wMaxLen+sizeof(short),
+                                            &dwBytes, NULL);
+                            if (iOK)                /* Device IO control OK ? */
+                            {
+                                if (dwBytes >= wMaxLen)
+                                {
+                                    strcpy(pBuffer, pMem+sizeof(short));
+                                    sErr = *((SHORT*)pMem);
+                                }
+                                else
+                                    sErr = U14ERR_DRIVCOMMS;
+                            }
+                            else
+                                sErr = U14ERR_DRIVCOMMS;
+
+                            GlobalUnlock(hMem);
+                        }
+                        else
+                            sErr = U14ERR_OUTOFMEMORY;
+
+                        GlobalFree(hMem);
+                    }
+                    else
+                        sErr = U14ERR_OUTOFMEMORY;
+                }
+
+                if (sErr == U14ERR_NOERROR)     // If all OK...
+                    TranslateString(pBuffer);   // ...convert any commas to spaces
+                else                            // If we have had a comms error...
+                    U14ForceReset(hand);        // ...make sure we get real reset
+
+            }
+            else
+                sErr = asLastRetCode[hand];
+        }
+        else
+        {
+            sErr = U14ERR_TIMEOUT;
+            U14ForceReset(hand);            //  make sure we get real reset
+        }
+    }
+    else
+        sErr = U14ERR_BUFF_SMALL;
+    return sErr;
+#endif
+#ifdef LINUX
+    if (wMaxLen>1)                          // we need space for terminating 0
+    {
+        BOOL bLineToGet;                    // true when a line to get
+        long lTimeOutTicks = U14WhenToTimeOut(hand);
+        do
+        {
+            bLineToGet = (BOOL)(U14LineCount(hand) != 0);
+            if (!bLineToGet)
+                sched_yield();
+
+        }
+        while (!bLineToGet && !U14PassedTime(lTimeOutTicks));
+
+        if (bLineToGet)
+        {
+            sErr = CED_GetString(aHand1401[hand], pBuffer, wMaxLen-1);   // space for terminator
+            if (sErr >=0)                    // if we were OK...
+            {
+                if (sErr >= wMaxLen)         // this should NOT happen unless
+                    sErr = U14ERR_DRIVCOMMS; // ...driver Comms are very bad
+                else
+                {
+                    pBuffer[sErr] = 0;      // OK, so terminate the string...
+                    TranslateString(pBuffer);  // ...and convert commas to spaces.
+                }
+            }
+
+            if (sErr < U14ERR_NOERROR)       // If we have had a comms error
+                U14ForceReset(hand);            //  make sure we get real reset
+        }
+        else
+        {
+            sErr = U14ERR_TIMEOUT;
+            U14ForceReset(hand);            //  make sure we get real reset
+        }
+    }
+    else
+        sErr = U14ERR_BUFF_SMALL;
+
+    return sErr >= U14ERR_NOERROR ? U14ERR_NOERROR : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14GetChar
+** Get a character from the 1401. CR returned as CR.
+*****************************************************************************/
+U14API(short) U14GetChar(short hand, char* pcChar)
+{
+#ifdef _IS_WINDOWS_
+    char sz[2];                             // read a very short string
+    short sErr = U14GetString(hand, sz, 2); // read one char and nul terminate it
+    *pcChar = sz[0];    // copy to result, NB char translate done by GetString
+    if (sErr == U14ERR_NOERROR)
+    {                                       // undo translate of CR to zero
+        if (*pcChar == '\0')                // by converting back
+            *pcChar = '\n';                 // What a nasty thing to have to do
+    }
+    return sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)             // Check parameters
+        return sErr;
+    sErr = CED_GetChar(aHand1401[hand]);    // get one char, if available
+    if (sErr >= 0)
+    {
+        *pcChar = (char)sErr;              // return if it we have one
+        return U14ERR_NOERROR;              // say all OK
+    }
+    else
+        return sErr;
+#endif
+}
+
+/****************************************************************************
+** U14Stat1401
+** Returns 0 for no lines or error or non zero for something waiting
+****************************************************************************/
+U14API(short) U14Stat1401(short hand)
+{
+    return ((short)(U14LineCount(hand) > 0));
+}
+
+/****************************************************************************
+** U14CharCount
+** Returns the number of characters in the input buffer
+*****************************************************************************/
+U14API(short) U14CharCount(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_STAT1401, &csBlock);
+    if (sErr == U14ERR_NOERROR)
+        sErr = csBlock.ints[0];
+    return sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_Stat1401(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14LineCount
+** Returns the number of CR characters in the input buffer
+*****************************************************************************/
+U14API(short) U14LineCount(short hand)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14Status1401(hand, U14_LINECOUNT, &csBlock);
+    if (sErr == U14ERR_NOERROR)
+        sErr = csBlock.ints[0];
+    return sErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_LineCount(aHand1401[hand]) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14GetErrorString
+** Converts error code supplied to a decent descriptive string.
+** NOTE: This function may use some extra information stored
+**       internally in the DLL. This information is stored on a
+**       per-process basis, but it might be altered if you call
+**       other functions after getting an error and before using
+**       this function.
+****************************************************************************/
+U14API(void)  U14GetErrorString(short nErr, char* pStr, WORD wMax)
+{
+    char    wstr[150];
+
+    switch (nErr)              /* Basically, we do this with a switch block */
+    {
+    case U14ERR_OFF:
+        sprintf(wstr, "The 1401 is apparently switched off (code %d)", nErr);
+        break;
+
+    case U14ERR_NC:
+        sprintf(wstr, "The 1401 is not connected to the interface card (code %d)", nErr);
+        break;
+
+    case U14ERR_ILL:
+        sprintf(wstr, "The 1401 is not working correctly (code %d)", nErr);
+        break;
+
+    case U14ERR_NOIF:
+        sprintf(wstr, "The 1401 interface card was not detected (code %d)", nErr);
+        break;
+
+    case U14ERR_TIME:
+        sprintf(wstr, "The 1401 fails to become ready for use (code %d)", nErr);
+        break;
+
+    case U14ERR_BADSW:
+        sprintf(wstr, "The 1401 interface card jumpers are incorrect (code %d)", nErr);
+        break;
+
+    case U14ERR_NOINT:
+        sprintf(wstr, "The 1401 interrupt is not available for use (code %d)", nErr);
+        break;
+
+    case U14ERR_INUSE:
+        sprintf(wstr, "The 1401 is already in use by another program (code %d)", nErr);
+        break;
+
+    case U14ERR_NODMA:
+        sprintf(wstr, "The 1401 DMA channel is not available for use (code %d)", nErr);
+        break;
+
+    case U14ERR_BADHAND:
+        sprintf(wstr, "The application supplied an incorrect 1401 handle (code %d)", nErr);
+        break;
+
+    case U14ERR_BAD1401NUM:
+        sprintf(wstr, "The application used an incorrect 1401 number (code %d)", nErr);
+        break;
+
+    case U14ERR_NO_SUCH_FN:
+        sprintf(wstr, "The code passed to the 1401 driver is invalid (code %d)", nErr);
+        break;
+
+    case U14ERR_NO_SUCH_SUBFN:
+        sprintf(wstr, "The sub-code passed to the 1401 driver is invalid (code %d)", nErr);
+        break;
+
+    case U14ERR_NOOUT:
+        sprintf(wstr, "No room in buffer for characters for the 1401 (code %d)", nErr);
+        break;
+
+    case U14ERR_NOIN:
+        sprintf(wstr, "No characters from the 1401 are available (code %d)", nErr);
+        break;
+
+    case U14ERR_STRLEN:
+        sprintf(wstr, "A string sent to or read from the 1401 was too long (code %d)", nErr);
+        break;
+
+    case U14ERR_LOCKFAIL:
+        sprintf(wstr, "Failed to lock host memory for data transfer (code %d)", nErr);
+        break;
+
+    case U14ERR_UNLOCKFAIL:
+        sprintf(wstr, "Failed to unlock host memory after data transfer (code %d)", nErr);
+        break;
+
+    case U14ERR_ALREADYSET:
+        sprintf(wstr, "The transfer area used is already set up (code %d)", nErr);
+        break;
+
+    case U14ERR_NOTSET:
+        sprintf(wstr, "The transfer area used has not been set up (code %d)", nErr);
+        break;
+
+    case U14ERR_BADAREA:
+        sprintf(wstr, "The transfer area number is incorrect (code %d)", nErr);
+        break;
+
+    case U14ERR_NOFILE:
+        sprintf(wstr, "The command file %s could not be opened (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_READERR:
+        sprintf(wstr, "The command file %s could not be read (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_UNKNOWN:
+        sprintf(wstr, "The %s command resource could not be found (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_HOSTSPACE:
+        sprintf(wstr, "Unable to allocate memory for loading command %s (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_LOCKERR:
+        sprintf(wstr, "Unable to lock memory for loading command %s (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_CLOADERR:
+        sprintf(wstr, "Error in loading command %s, bad command format (code %d)", szLastName, nErr);
+        break;
+
+    case U14ERR_TOXXXERR:
+        sprintf(wstr, "Error detected after data transfer to or from the 1401 (code %d)", nErr);
+        break;
+
+    case U14ERR_NO386ENH:
+        sprintf(wstr, "Windows 3.1 is not running in 386 enhanced mode (code %d)", nErr);
+        break;
+
+    case U14ERR_NO1401DRIV:
+        sprintf(wstr, "The 1401 device driver cannot be found (code %d)\nUSB:   check plugged in and powered\nOther: not installed?", nErr);
+        break;
+
+    case U14ERR_DRIVTOOOLD:
+        sprintf(wstr, "The 1401 device driver is too old for use (code %d)", nErr);
+        break;
+
+    case U14ERR_TIMEOUT:
+        sprintf(wstr, "Character transmissions to the 1401 timed-out (code %d)", nErr);
+        break;
+
+    case U14ERR_BUFF_SMALL:
+        sprintf(wstr, "Buffer for text from the 1401 was too small (code %d)", nErr);
+        break;
+
+    case U14ERR_CBALREADY:
+        sprintf(wstr, "1401 monitor callback already set up (code %d)", nErr);
+        break;
+
+    case U14ERR_BADDEREG:
+        sprintf(wstr, "1401 monitor callback deregister invalid (code %d)", nErr);
+        break;
+
+    case U14ERR_DRIVCOMMS:
+        sprintf(wstr, "1401 device driver communications failed (code %d)", nErr);
+        break;
+
+    case U14ERR_OUTOFMEMORY:
+        sprintf(wstr, "Failed to allocate or lock memory for text from the 1401 (code %d)", nErr);
+        break;
+
+    default:
+        sprintf(wstr, "1401 error code %d returned; this code is unknown", nErr);
+        break;
+
+    }
+    if ((WORD)strlen(wstr) >= wMax-1)  /* Check for string being too long */
+        wstr[wMax-1] = 0;                          /* and truncate it if so */
+    strcpy(pStr, wstr);                       /* Return the error string */
+}
+
+/***************************************************************************
+** U14GetTransfer
+** Get a TGET_TX_BLOCK describing a transfer area (held in the block)
+***************************************************************************/
+U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock)
+{
+    short sErr = CheckHandle(hand);
+#ifdef _IS_WINDOWS_
+    if (sErr == U14ERR_NOERROR)
+    { 
+        DWORD dwBytes = 0;
+        BOOL bOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_GETTRANSFER, NULL, 0, pTransBlock,
+                              sizeof(TGET_TX_BLOCK), &dwBytes, NULL);
+    
+        if (bOK && (dwBytes >= sizeof(TGET_TX_BLOCK)))
+            sErr = U14ERR_NOERROR;
+        else
+            sErr = U14ERR_DRIVCOMMS;
+    }
+    return sErr;
+#endif
+#ifdef LINUX
+    return (sErr == U14ERR_NOERROR) ? CED_GetTransfer(aHand1401[hand], pTransBlock) : sErr;
+#endif
+}
+/////////////////////////////////////////////////////////////////////////////
+// U14WorkingSet
+// For Win32 only, adjusts process working set so that minimum is at least
+//  dwMinKb and maximum is at least dwMaxKb.
+// Return value is zero if all went OK, or a code from 1 to 3 indicating the
+//  cause of the failure:
+//
+//     1 unable to access process (insufficient rights?)
+//     2 unable to read process working set
+//     3 unable to set process working set - bad parameters?
+U14API(short) U14WorkingSet(DWORD dwMinKb, DWORD dwMaxKb)
+{
+#ifdef _IS_WINDOWS_
+    short sRetVal = 0;                      // 0 means all is OK
+    HANDLE hProcess;
+    DWORD dwVer = GetVersion();
+	if (dwVer & 0x80000000)                 // is this not NT?
+        return 0;                           // then give up right now
+
+    // Now attempt to get information on working set size
+    hProcess = OpenProcess(STANDARD_RIGHTS_REQUIRED |
+                                  PROCESS_QUERY_INFORMATION |
+                                  PROCESS_SET_QUOTA,
+                                  FALSE, _getpid());
+    if (hProcess)
+    {
+        SIZE_T dwMinSize,dwMaxSize;
+        if (GetProcessWorkingSetSize(hProcess, &dwMinSize, &dwMaxSize))
+        {
+            DWORD dwMin = dwMinKb << 10;    // convert from kb to bytes
+            DWORD dwMax = dwMaxKb << 10;
+
+            // if we get here, we have managed to read the current size
+            if (dwMin > dwMinSize)          // need to change sizes?
+                dwMinSize = dwMin;
+
+            if (dwMax > dwMaxSize)
+                dwMaxSize = dwMax;
+
+            if (!SetProcessWorkingSetSize(hProcess, dwMinSize, dwMaxSize))
+                sRetVal = 3;                // failed to change size
+        }
+        else
+            sRetVal = 2;                    // failed to read original size
+
+        CloseHandle(hProcess);
+    }
+    else
+        sRetVal = 1;            // failed to get handle
+
+    return sRetVal;
+#endif
+#ifdef LINUX
+    if (dwMinKb | dwMaxKb)
+    {
+        // to stop compiler moaning
+    }
+    return U14ERR_NOERROR;
+#endif
+}
+
+/****************************************************************************
+** U14UnSetTransfer  Cancels a transfer area
+** wArea    The index of a block previously used in by SetTransfer
+*****************************************************************************/
+U14API(short) U14UnSetTransfer(short hand, WORD wArea)
+{
+    short sErr = CheckHandle(hand);
+#ifdef _IS_WINDOWS_
+    if (sErr == U14ERR_NOERROR)
+    {
+       TCSBLOCK csBlock;
+       csBlock.ints[0] = (short)wArea;       /* Area number into control block */
+       sErr = U14Control1401(hand, U14_UNSETTRANSFER, &csBlock);  /* Free area */
+   
+       VirtualUnlock(apAreas[hand][wArea], auAreas[hand][wArea]);/* Unlock */
+       apAreas[hand][wArea] = NULL;                         /* Clear locations */
+       auAreas[hand][wArea] = 0;
+    }
+    return sErr;
+#endif
+#ifdef LINUX
+    return (sErr == U14ERR_NOERROR) ? CED_UnsetTransfer(aHand1401[hand], wArea) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14SetTransArea      Sets an area up to be used for transfers
+** WORD  wArea     The area number to set up
+** void *pvBuff    The address of the buffer for the data.
+** DWORD dwLength  The length of the buffer for the data
+** short eSz       The element size (used for byte swapping on the Mac)
+****************************************************************************/
+U14API(short) U14SetTransArea(short hand, WORD wArea, void *pvBuff,
+                                          DWORD dwLength, short eSz)
+{
+    TRANSFERDESC td;
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+    if (wArea >= MAX_TRANSAREAS)                    // Is this a valid area number
+        return U14ERR_BADAREA;
+
+#ifdef _IS_WINDOWS_
+    assert(apAreas[hand][wArea] == NULL);
+    assert(auAreas[hand][wArea] == 0);
+
+    apAreas[hand][wArea] = pvBuff;                  /* Save data for later */
+    auAreas[hand][wArea] = dwLength;
+
+    if (!VirtualLock(pvBuff, dwLength))             /* Lock using WIN32 calls */
+    {
+        apAreas[hand][wArea] = NULL;                /* Clear locations */
+        auAreas[hand][wArea] = 0;
+        return U14ERR_LOCKERR;                      /* VirtualLock failed */
+    }
+#ifndef _WIN64
+    if (!USE_NT_DIOC(hand))                         /* Use Win 9x DIOC? */
+    {
+        DWORD dwBytes;
+        VXTRANSFERDESC vxDesc;                      /* Structure to pass to VXD */
+        vxDesc.wArea = wArea;                       /* Copy across simple params */
+        vxDesc.dwLength = dwLength;
+
+        // Check we are not asking an old driver for more than area 0
+        if ((wArea != 0) && (U14DriverVersion(hand) < 0x00010002L))
+            sErr = U14ERR_DRIVTOOOLD;
+        else
+        {
+            vxDesc.dwAddrOfs = (DWORD)pvBuff;       /* 32 bit offset */
+            vxDesc.wAddrSel  = 0;
+
+            if (DeviceIoControl(aHand1401[hand], (DWORD)U14_SETTRANSFER,
+                                pvBuff,dwLength,    /* Will translate pointer */
+                                &vxDesc,sizeof(VXTRANSFERDESC),
+                                &dwBytes,NULL))
+            {
+                if (dwBytes >= sizeof(VXTRANSFERDESC)) /* Driver OK ? */
+                    sErr = U14ERR_NOERROR;
+                else
+                    sErr = U14ERR_DRIVCOMMS;        /* Else never got there */
+            }
+            else
+                sErr = (short)GetLastError();
+        }
+    }
+    else
+#endif
+    {
+        PARAMBLK rWork;
+        DWORD dwBytes;
+        td.wArea = wArea;     /* Pure NT - put data into struct */
+        td.lpvBuff = pvBuff;
+        td.dwLength = dwLength;
+        td.eSize = 0;                // Dummy element size
+
+        if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETTRANSFER,
+                            &td,sizeof(TRANSFERDESC),
+                            &rWork,sizeof(PARAMBLK),&dwBytes,NULL))
+        {
+            if (dwBytes >= sizeof(PARAMBLK))    // maybe error from driver?
+                sErr = rWork.sState;            // will report any error
+            else
+                sErr = U14ERR_DRIVCOMMS;        // Else never got there
+        }
+        else
+            sErr = U14ERR_DRIVCOMMS;
+    }
+
+    if (sErr != U14ERR_NOERROR)
+    {
+        if (sErr != U14ERR_LOCKERR)             // unless lock failed...
+            VirtualUnlock(pvBuff, dwLength);    // ...release the lock
+        apAreas[hand][wArea] = NULL;            // Clear locations
+        auAreas[hand][wArea] = 0;
+    }
+
+    return sErr;
+#endif
+#ifdef LINUX
+    // The strange cast is so that it works in 64 and 32-bit linux as long is 64-bits
+    // in the 64 bit version.
+    td.lpvBuff = (long long)((unsigned long)pvBuff);
+    td.wAreaNum = wArea;
+    td.dwLength = dwLength;
+    td.eSize = eSz;                // Dummy element size
+    return CED_SetTransfer(aHand1401[hand], &td);
+#endif
+}
+
+/****************************************************************************
+** U14SetTransferEvent  Sets an event for notification of application
+** wArea       The tranfer area index, from 0 to MAXAREAS-1
+**    bEvent      True to create an event, false to remove it
+**    bToHost     Set 0 for notification on to1401 tranfers, 1 for
+**                notification of transfers to the host PC
+**    dwStart     The offset of the sub-area of interest
+**    dwLength    The size of the sub-area of interest
+**
+** The device driver will set the event supplied to the signalled state
+** whenever a DMA transfer to/from the specified area is completed. The
+** transfer has to be in the direction specified by bToHost, and overlap
+** that part of the whole transfer area specified by dwStart and dwLength.
+** It is important that this function is called with bEvent false to release
+** the event once 1401 activity is finished.
+**
+** Returns 1 if an event handle exists, 0 if all OK and no event handle or
+** a negative code for an error.
+****************************************************************************/
+U14API(short) U14SetTransferEvent(short hand, WORD wArea, BOOL bEvent,
+                                  BOOL bToHost, DWORD dwStart, DWORD dwLength)
+{
+#ifdef _IS_WINDOWS_
+    TCSBLOCK csBlock;
+    short sErr = U14TransferFlags(hand);        // see if we can handle events
+    if (sErr >= U14ERR_NOERROR)                 // check handle is OK
+    {
+        bEvent = bEvent && ((sErr & U14TF_NOTIFY) != 0); // remove request if we cannot do events
+        if (wArea >= MAX_TRANSAREAS)            // Check a valid area...
+            return U14ERR_BADAREA;              // ...and bail of not
+
+        // We can hold an event for each area, so see if we need to change the
+        // state of the event.
+        if ((bEvent != 0) != (aXferEvent[hand] != 0))    // change of event state?
+        {
+            if (bEvent)                         // want one and none present
+                aXferEvent[hand] = CreateEvent(NULL, FALSE, FALSE, NULL);
+            else
+            {
+                CloseHandle(aXferEvent[hand]);  // clear the existing event
+                aXferEvent[hand] = NULL;        // and clear handle
+            }
+        }
+
+        // We have to store the parameters differently for 64-bit operations
+        //  because a handle is 64 bits long. The drivers know of this and
+        //  handle the information appropriately.
+#ifdef _WIN64
+        csBlock.longs[0] = wArea;               // Pass paramaters into the driver...
+        if (bToHost != 0)                       // The direction flag is held in the
+            csBlock.longs[0] |= 0x10000;        //  upper word of the transfer area value
+        *((HANDLE*)&csBlock.longs[1]) = aXferEvent[hand];  // The event handle is 64-bits
+        csBlock.longs[3] = dwStart;             // Thankfully these two remain
+        csBlock.longs[4] = dwLength;            //  as unsigned 32-bit values
+#else
+        csBlock.longs[0] = wArea;               // pass paramaters into the driver...
+        csBlock.longs[1] = (long)aXferEvent[hand];    // ...especially the event handle
+        csBlock.longs[2] = bToHost;
+        csBlock.longs[3] = dwStart;
+        csBlock.longs[4] = dwLength;
+#endif
+        sErr = U14Control1401(hand, U14_SETTRANSEVENT, &csBlock);
+        if (sErr == U14ERR_NOERROR)
+            sErr = (short)(aXferEvent[hand] != NULL);    // report if we have a flag
+    }
+
+    return sErr;
+#endif
+#ifdef LINUX
+    TRANSFEREVENT te;
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+
+    if (wArea >= MAX_TRANSAREAS)            // Is this a valid area number
+        return U14ERR_BADAREA;
+
+    te.wAreaNum = wArea;                    // copy parameters to the control block
+    te.wFlags = bToHost ? 1 : 0;            // bit 0 sets the direction
+    te.dwStart = dwStart;                   // start offset of the event area
+    te.dwLength = dwLength;                 // size of the event area
+    te.iSetEvent = bEvent;                  // in Windows, this creates/destroys the event
+    return CED_SetEvent(aHand1401[hand], &te);
+#endif
+}
+
+/****************************************************************************
+** U14TestTransferEvent
+** Would a U14WaitTransferEvent() call return immediately? return 1 if so,
+** 0 if not or a negative code if a problem.
+****************************************************************************/
+U14API(int) U14TestTransferEvent(short hand, WORD wArea)
+{
+#ifdef _IS_WINDOWS_
+    int iErr = CheckHandle(hand);
+    if (iErr == U14ERR_NOERROR)
+    {
+        if (aXferEvent[hand])           // if a handle is set...
+            iErr = WaitForSingleObject(aXferEvent[hand], 0) == WAIT_OBJECT_0;
+    }
+    return iErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_TestEvent(aHand1401[hand], wArea) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14WaitTransferEvent
+** Wait for a transfer event with a timeout.
+** msTimeOut is 0 for an infinite wait, else it is the maximum time to wait
+**           in milliseconds in range 0-0x00ffffff.
+** Returns   If no event handle then return immediately. Else return 1 if
+**           timed out or 0=event, and a negative code if a problem.
+****************************************************************************/
+U14API(int) U14WaitTransferEvent(short hand, WORD wArea, int msTimeOut)
+{
+#ifdef _IS_WINDOWS_
+    int iErr = CheckHandle(hand);
+    if (iErr == U14ERR_NOERROR)
+    {
+        if (aXferEvent[hand])
+        {
+            if (msTimeOut == 0)
+                msTimeOut = INFINITE;
+            iErr = WaitForSingleObject(aXferEvent[hand], msTimeOut) != WAIT_OBJECT_0;
+        }
+        else
+            iErr = TRUE;                // say we timed out if no event
+    }
+    return iErr;
+#endif
+#ifdef LINUX
+    short sErr = CheckHandle(hand);
+    return (sErr == U14ERR_NOERROR) ? CED_WaitEvent(aHand1401[hand], wArea, msTimeOut) : sErr;
+#endif
+}
+
+/****************************************************************************
+** U14SetCircular    Sets an area up for circular DMA transfers
+** WORD  wArea          The area number to set up
+** BOOL  bToHost        Sets the direction of data transfer
+** void *pvBuff        The address of the buffer for the data
+** DWORD dwLength       The length of the buffer for the data
+****************************************************************************/
+U14API(short) U14SetCircular(short hand, WORD wArea, BOOL bToHost,
+									void *pvBuff, DWORD dwLength)
+{
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+
+    if (wArea >= MAX_TRANSAREAS)         /* Is this a valid area number */
+        return U14ERR_BADAREA;
+
+	if (!bToHost)             /* For now, support tohost transfers only */
+        return U14ERR_BADAREA;            /* best error code I can find */
+#ifdef _IS_WINDOWS_
+    assert(apAreas[hand][wArea] == NULL);
+    assert(auAreas[hand][wArea] == 0);
+
+    apAreas[hand][wArea] = pvBuff;              /* Save data for later */
+    auAreas[hand][wArea] = dwLength;
+
+    if (!VirtualLock(pvBuff, dwLength))      /* Lock using WIN32 calls */
+        sErr = U14ERR_LOCKERR;                    /* VirtualLock failed */
+    else
+    {
+        PARAMBLK rWork;
+        DWORD dwBytes;
+        TRANSFERDESC txDesc;
+        txDesc.wArea = wArea;             /* Pure NT - put data into struct */
+        txDesc.lpvBuff = pvBuff;
+        txDesc.dwLength = dwLength;
+        txDesc.eSize = (short)bToHost;       /* Use this for direction flag */
+   
+        if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETCIRCULAR,
+                           &txDesc, sizeof(TRANSFERDESC),
+                           &rWork, sizeof(PARAMBLK),&dwBytes,NULL))
+        {
+           if (dwBytes >= sizeof(PARAMBLK))          /* error from driver? */
+               sErr = rWork.sState;         /* No, just return driver data */
+           else
+               sErr = U14ERR_DRIVCOMMS;            /* Else never got there */
+        }
+        else
+            sErr = U14ERR_DRIVCOMMS;
+    }
+
+    if (sErr != U14ERR_NOERROR)
+    {
+        if (sErr != U14ERR_LOCKERR)
+            VirtualUnlock(pvBuff, dwLength);         /* Release NT lock */
+        apAreas[hand][wArea] = NULL;                 /* Clear locations */
+        auAreas[hand][wArea] = 0;
+    }
+
+    return sErr;
+#endif
+#ifdef LINUX
+    else
+    {
+        TRANSFERDESC td;
+        td.lpvBuff = (long long)((unsigned long)pvBuff);
+        td.wAreaNum = wArea;
+        td.dwLength = dwLength;
+        td.eSize = (short)bToHost;       /* Use this for direction flag */
+        return CED_SetCircular(aHand1401[hand], &td);
+    }
+#endif
+}
+
+/****************************************************************************
+** Function  GetCircBlk returns the size (& start offset) of the next
+**           available block of circular data.
+****************************************************************************/
+U14API(int) U14GetCircBlk(short hand, WORD wArea, DWORD *pdwOffs)
+{
+    int lErr = CheckHandle(hand);
+    if (lErr != U14ERR_NOERROR)
+        return lErr;
+
+    if (wArea >= MAX_TRANSAREAS)            // Is this a valid area number?
+        return U14ERR_BADAREA;
+    else
+    {
+#ifdef _IS_WINDOWS_
+        PARAMBLK rWork;
+        TCSBLOCK csBlock;
+        DWORD dwBytes;
+        csBlock.longs[0] = wArea;               // Area number into control block
+        rWork.sState = U14ERR_DRIVCOMMS;
+        if (DeviceIoControl(aHand1401[hand], (DWORD)U14_GETCIRCBLK, &csBlock, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
+           (dwBytes >= sizeof(PARAMBLK)))
+            lErr = rWork.sState;
+        else
+            lErr = U14ERR_DRIVCOMMS;
+   
+        if (lErr == U14ERR_NOERROR)             // Did everything go OK?
+        {                                       // Yes, we can pass the results back
+            lErr = rWork.csBlock.longs[1];      // Return the block information
+            *pdwOffs = rWork.csBlock.longs[0];  // Offset is first in array
+        }
+#endif
+#ifdef LINUX
+        TCIRCBLOCK cb;
+        cb.nArea = wArea;                       // Area number into control block
+        cb.dwOffset = 0;
+        cb.dwSize = 0;
+        lErr = CED_GetCircBlock(aHand1401[hand], &cb);
+        if (lErr == U14ERR_NOERROR)             // Did everything go OK?
+        {                                       // Yes, we can pass the results back
+            lErr = cb.dwSize;                   // return the size
+            *pdwOffs = cb.dwOffset;             // and the offset
+        }
+#endif
+    }
+    return lErr;
+}
+
+/****************************************************************************
+** Function  FreeCircBlk marks the specified area of memory as free for
+**           resuse for circular transfers and returns the size (& start
+**           offset) of the next available block of circular data.
+****************************************************************************/
+U14API(int) U14FreeCircBlk(short hand, WORD wArea, DWORD dwOffs, DWORD dwSize,
+                                        DWORD *pdwOffs)
+{
+    int lErr = CheckHandle(hand);
+    if (lErr != U14ERR_NOERROR)
+        return lErr;
+
+    if (wArea < MAX_TRANSAREAS)                 // Is this a valid area number
+    {
+#ifdef _IS_WINDOWS_
+        PARAMBLK rWork;
+        TCSBLOCK csBlock;
+        DWORD dwBytes;
+        csBlock.longs[0] = wArea;               // Area number into control block
+        csBlock.longs[1] = dwOffs;
+        csBlock.longs[2] = dwSize;
+        rWork.sState = U14ERR_DRIVCOMMS;
+        if (DeviceIoControl(aHand1401[hand], (DWORD)U14_FREECIRCBLK, &csBlock, sizeof(TCSBLOCK),
+                           &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
+           (dwBytes >= sizeof(PARAMBLK)))
+           lErr = rWork.sState;
+        else
+           lErr = U14ERR_DRIVCOMMS;
+       if (lErr == U14ERR_NOERROR)             // Did everything work OK?
+       {                                       // Yes, we can pass the results back
+           lErr = rWork.csBlock.longs[1];      // Return the block information
+           *pdwOffs = rWork.csBlock.longs[0];  // Offset is first in array
+       }
+#endif
+#ifdef LINUX
+        TCIRCBLOCK cb;
+        cb.nArea = wArea;                       // Area number into control block
+        cb.dwOffset = dwOffs;
+        cb.dwSize = dwSize;
+    
+        lErr = CED_FreeCircBlock(aHand1401[hand], &cb);
+        if (lErr == U14ERR_NOERROR)             // Did everything work OK?
+        {                                       // Yes, we can pass the results back
+            lErr = cb.dwSize;                   // Return the block information
+            *pdwOffs = cb.dwOffset;             // Offset is first in array
+        }
+#endif
+    }
+    else
+        lErr = U14ERR_BADAREA;
+
+    return lErr;
+}
+
+/****************************************************************************
+** Transfer
+** Transfer moves data to 1401 or to host
+** Assumes memory is allocated and locked,
+** which it should be to get a pointer
+*****************************************************************************/
+static short Transfer(short hand, BOOL bTo1401, char* pData,
+                       DWORD dwSize, DWORD dw1401, short eSz)
+{
+    char strcopy[MAXSTRLEN+1];          // to hold copy of work string
+    short sResult = U14SetTransArea(hand, 0, (void *)pData, dwSize, eSz);
+    if (sResult == U14ERR_NOERROR)      // no error
+    {
+        sprintf(strcopy,                // data offset is always 0
+                "TO%s,$%X,$%X,0;", bTo1401 ? "1401" : "HOST", dw1401, dwSize);
+
+        U14SendString(hand, strcopy);   // send transfer string
+
+        sResult = U14CheckErr(hand);    // Use ERR command to check for done
+        if (sResult > 0)
+            sResult = U14ERR_TOXXXERR;  // If a 1401 error, use this code
+
+        U14UnSetTransfer(hand, 0);
+    }
+    return sResult;
+}
+
+/****************************************************************************
+** Function  ToHost transfers data into the host from the 1401
+****************************************************************************/
+U14API(short) U14ToHost(short hand, char* pAddrHost, DWORD dwSize,
+                                            DWORD dw1401, short eSz)
+{
+    short sErr = CheckHandle(hand);
+    if ((sErr == U14ERR_NOERROR) && dwSize) // TOHOST is a constant
+        sErr = Transfer(hand, TOHOST, pAddrHost, dwSize, dw1401, eSz);
+    return sErr;
+}
+
+/****************************************************************************
+** Function  To1401 transfers data into the 1401 from the host
+****************************************************************************/
+U14API(short) U14To1401(short hand, const char* pAddrHost,DWORD dwSize,
+                                    DWORD dw1401, short eSz)
+{
+    short sErr = CheckHandle(hand);
+    if ((sErr == U14ERR_NOERROR) && dwSize) // TO1401 is a constant
+        sErr = Transfer(hand, TO1401, (char*)pAddrHost, dwSize, dw1401, eSz);
+    return sErr;
+}
+
+/****************************************************************************
+** Function  LdCmd    Loads a command from a full path or just a file
+*****************************************************************************/
+#ifdef _IS_WINDOWS_
+#define file_exist(name) (_access(name, 0) != -1)
+#define file_open(name) _lopen(name, OF_READ)
+#define file_close(h)   _lclose(h)
+#define file_seek(h, pos) _llseek(h, pos, FILE_BEGIN) 
+#define file_read(h, buffer, size) (_lread(h, buffer, size) == size)
+#endif
+#ifdef LINUX
+#define file_exist(name) (access(name, F_OK) != -1)
+#define file_open(name) open(name, O_RDONLY)
+#define file_close(h)   close(h)
+#define file_seek(h, pos) lseek(h, pos, SEEK_SET) 
+#define file_read(h, buffer, size) (read(h, buffer, size) == (ssize_t)size)
+static DWORD GetModuleFileName(void* dummy, char* buffer, int max)
+{
+    // The following works for Linux systems with a /proc file system.
+    char szProcPath[32];
+    sprintf(szProcPath, "/proc/%d/exe", getpid());  // attempt to read link
+    if (readlink(szProcPath, buffer, max) != -1)
+    {
+        dirname (buffer);
+        strcat  (buffer, "/");
+        return strlen(buffer);
+    }
+    return 0;
+}
+#endif
+
+U14API(short) U14LdCmd(short hand, const char* command)
+{
+    char strcopy[MAXSTRLEN+1];      // to hold copy of work string
+    BOOL bGotIt = FALSE;            // have we found the command file?
+    int iFHandle;                   // file handle of command
+#define FNSZ 260
+    char filnam[FNSZ];              // space to build name in
+    char szCmd[25];                 // just the command name with extension
+
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+
+    if (strchr(command, '.') != NULL)       // see if we have full name
+    {
+        if (file_exist(command))            // If the file exists
+        {
+            strcpy(filnam, command);        // use name as is
+            bGotIt = TRUE;                  // Flag no more searching
+        }
+        else                                // not found, get file name for search
+        {
+            char* pStr = strrchr(command, PATHSEP);  // Point to last separator
+            if (pStr != NULL)               // Check we got it
+            {
+                pStr++;                     // move past the backslash
+                strcpy(szCmd, pStr);        // copy file name as is
+            }
+            else
+                strcpy(szCmd, command);     // use as is
+        }
+    }
+    else    // File extension not supplied, so build the command file name
+    {
+        char szExt[8];
+        strcpy(szCmd, command);             // Build command file name
+        ExtForType(asType1401[hand], szExt);// File extension string
+        strcat(szCmd, szExt);               // add it to the end
+    }
+
+    // Next place to look is in the 1401 folder in the same place as the
+    // application was run from.
+    if (!bGotIt)                            // Still not got it?
+    {
+        DWORD dwLen = GetModuleFileName(NULL, filnam, FNSZ); // Get app path
+        if (dwLen > 0)                      // and use it as path if found
+        {
+            char* pStr = strrchr(filnam, PATHSEP);    // Point to last separator
+            if (pStr != NULL)
+            {
+                *(++pStr) = 0;                  // Terminate string there
+                if (strlen(filnam) < FNSZ-6)    // make sure we have space
+                {
+                    strcat(filnam, "1401" PATHSEPSTR);  // add in 1401 subdir
+                    strcat(filnam,szCmd);
+                    bGotIt = (BOOL)file_exist(filnam);  // See if file exists
+                }
+            }
+        }
+    }
+
+    // Next place to look is in whatever path is set by the 1401DIR environment
+    // variable, if it exists.
+    if (!bGotIt)                            // Need to do more searches?/
+    {
+        char* pStr = getenv("1401DIR");     // Try to find environment var
+        if (pStr != NULL)                   // and use it as path if found
+        {
+            strcpy(filnam, pStr);                   // Use path in environment
+            if (filnam[strlen(filnam)-1] != PATHSEP)// We need separator
+                strcat(filnam, PATHSEPSTR);
+            strcat(filnam, szCmd);
+            bGotIt = (BOOL)file_exist(filnam); // Got this one?
+        }
+    }
+
+    // Last place to look is the default location.
+    if (!bGotIt)                        // Need to do more searches?
+    {
+        strcpy(filnam, DEFCMDPATH);     // Use default path
+        strcat(filnam, szCmd);
+        bGotIt = file_exist(filnam);    // Got this one?
+    }
+
+    iFHandle = file_open(filnam);
+    if (iFHandle == -1)
+        sErr = U14ERR_NOFILE;
+    else
+    {                                   // first read in the header block
+        CMDHEAD rCmdHead;               // to hold the command header
+        if (file_read(iFHandle, &rCmdHead, sizeof(CMDHEAD)))
+        {
+            size_t nComSize = rCmdHead.wCmdSize;
+            char* pMem = malloc(nComSize);
+            if (pMem != NULL)
+            {
+                file_seek(iFHandle, sizeof(CMDHEAD));
+                if (file_read(iFHandle, pMem, (UINT)nComSize))
+                {
+                    sErr = U14SetTransArea(hand, 0, (void *)pMem, (DWORD)nComSize, ESZBYTES);
+                    if (sErr == U14ERR_NOERROR)
+                    {
+                        sprintf(strcopy, "CLOAD,0,$%X;", (int)nComSize);
+                        sErr = U14SendString(hand, strcopy);
+                        if (sErr == U14ERR_NOERROR)
+                        {
+                            sErr = U14CheckErr(hand);     // Use ERR to check for done
+                            if (sErr > 0)
+                                sErr = U14ERR_CLOADERR;   // If an error, this code
+                        }
+                        U14UnSetTransfer(hand, 0);  // release transfer area
+                    }
+                }
+                else
+                    sErr = U14ERR_READERR;
+                free(pMem);
+            }
+            else
+                sErr = U14ERR_HOSTSPACE;    // memory allocate failed
+        }
+        else
+            sErr = U14ERR_READERR;
+
+        file_close(iFHandle);               // close the file
+    }
+
+    return sErr;
+}
+
+
+/****************************************************************************
+** Ld
+** Loads a command into the 1401
+** Returns NOERROR code or a long with error in lo word and index of
+** command that failed in high word
+****************************************************************************/
+U14API(DWORD) U14Ld(short hand, const char* vl, const char* str)
+{
+    DWORD dwIndex = 0;              // index to current command
+    long lErr = U14ERR_NOERROR;     // what the error was that went wrong
+    char strcopy[MAXSTRLEN+1];      // stores unmodified str parameter
+    char szFExt[8];                 // The command file extension
+    short sErr = CheckHandle(hand);
+    if (sErr != U14ERR_NOERROR)
+        return sErr;
+
+    ExtForType(asType1401[hand], szFExt);   // File extension string
+    strcpy(strcopy, str);               // to avoid changing original
+
+    // now break out one command at a time and see if loaded
+    if (*str)                           // if anything there
+    {
+        BOOL bDone = FALSE;             // true when finished all commands
+        int iLoop1 = 0;                 // Point at start of string for command name
+        int iLoop2 = 0;                 // and at start of str parameter
+        do                              // repeat until end of str
+        {
+            char filnam[MAXSTRLEN+1];   // filename to use
+            char szFName[MAXSTRLEN+1];  // filename work string
+
+            if (!strcopy[iLoop1])       // at the end of the string?
+                bDone = TRUE;           // set the finish flag
+
+            if (bDone || (strcopy[iLoop1] == ','))  // end of cmd?
+            {
+                U14LONG er[5];                  // Used to read back error results
+                ++dwIndex;                      // Keep count of command number, first is 1
+                szFName[iLoop2]=(char)0;        // null terminate name of command
+
+                strncpy(szLastName, szFName, sizeof(szLastName));    // Save for error info
+                szLastName[sizeof(szLastName)-1] = 0;
+                strncat(szLastName, szFExt, sizeof(szLastName));     // with extension included
+                szLastName[sizeof(szLastName)-1] = 0;
+
+                U14SendString(hand, szFName);   // ask if loaded
+                U14SendString(hand, ";ERR;");   // add err return
+
+                lErr = U14LongsFrom1401(hand, er, 5);
+                if (lErr > 0)
+                {
+                    lErr = U14ERR_NOERROR;
+                    if (er[0] == 255)           // if command not loaded at all
+                    {
+                        if (vl && *vl)          // if we have a path name
+                        {
+                            strcpy(filnam, vl);
+                            if (strchr("\\/:", filnam[strlen(filnam)-1]) == NULL)
+                                strcat(filnam, PATHSEPSTR); // add separator if none found
+                            strcat(filnam, szFName);    // add the file name
+                            strcat(filnam, szFExt);     // and extension
+                        }
+                        else
+                            strcpy(filnam, szFName);    // simple name
+
+                        lErr = U14LdCmd(hand, filnam);  // load cmd
+                        if (lErr != U14ERR_NOERROR)     // spot any errors
+                            bDone = TRUE;               // give up if an error
+                    }
+                }
+                else
+                    bDone = TRUE;       // give up if an error
+
+                iLoop2 = 0;             // Reset pointer to command name string
+                ++iLoop1;               // and move on through str parameter
+            }
+            else
+                szFName[iLoop2++] = strcopy[iLoop1++];  // no command end, so copy 1 char
+        }
+        while (!bDone);
+    }
+
+    if (lErr == U14ERR_NOERROR)
+    {
+        szLastName[0] = 0;      // No error, so clean out command name here
+        return lErr;
+    }
+    else
+        return ((dwIndex<<16) | ((DWORD)lErr & 0x0000FFFF));
+}
+
+// Initialise the library (if not initialised) and return the library version
+U14API(int) U14InitLib(void)
+{
+    int iRetVal = U14LIB_VERSION;
+    if (iAttached == 0)         // only do this the first time please
+    {
+        int i;
+#ifdef _IS_WINDOWS_
+        int j;
+        DWORD   dwVersion = GetVersion();
+        bWindows9x = FALSE;                  // Assume not Win9x
+
+        if (dwVersion & 0x80000000)                 // if not windows NT
+        {
+            if ((LOBYTE(LOWORD(dwVersion)) < 4) &&  // if Win32s or...
+                 (HIBYTE(LOWORD(dwVersion)) < 95))  // ...below Windows 95
+            iRetVal = 0;                            // We do not support this
+        else
+            bWindows9x = TRUE;                      // Flag we have Win9x
+        }
+#endif
+        
+        for (i = 0; i < MAX1401; i++)               // initialise the device area
+        {
+            aHand1401[i] = INVALID_HANDLE_VALUE;    // Clear handle values
+            asType1401[i] = U14TYPEUNKNOWN;         // and 1401 type codes
+            alTimeOutPeriod[i] = 3000;              // 3 second timeouts
+#ifdef _IS_WINDOWS_
+#ifndef _WIN64
+            abUseNTDIOC[i] = (BOOL)!bWindows9x;
+#endif
+            aXferEvent[i] = NULL;                   // there are no Xfer events
+            for (j = 0; j < MAX_TRANSAREAS; j++)    // Clear out locked area info
+            {
+                apAreas[i][j] = NULL;
+                auAreas[i][j] = 0;
+            }
+#endif
+        }
+    }
+    return iRetVal;
+}
+
+///--------------------------------------------------------------------------------
+/// Functions called when the library is loaded and unloaded to give us a chance to
+/// setup the library.
+
+
+#ifdef _IS_WINDOWS_
+#ifndef U14_NOT_DLL
+/****************************************************************************
+** FUNCTION: DllMain(HANDLE, DWORD, LPVOID)
+** LibMain is called by Windows when the DLL is initialized, Thread Attached,
+** and other times. Refer to SDK documentation, as to the different ways this
+** may be called.
+****************************************************************************/
+INT APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved)
+{
+    int iRetVal = 1;
+
+    switch (ul_reason_being_called)
+    {
+    case DLL_PROCESS_ATTACH:
+        iRetVal = U14InitLib() > 0;         // does nothing if iAttached != 0
+        ++iAttached;                        // count times attached
+        break;
+
+    case DLL_PROCESS_DETACH:
+        if (--iAttached == 0)               // last man out?
+            U14CloseAll();                  // release all open handles
+        break;
+    }
+    return iRetVal;
+
+    UNREFERENCED_PARAMETER(lpReserved);
+}
+#endif
+#endif
+#ifdef LINUX
+void __attribute__((constructor)) use1401_load(void)
+{
+    U14InitLib();
+    ++iAttached;
+}
+
+void __attribute__((destructor)) use1401_unload(void)
+{
+        if (--iAttached == 0)               // last man out?
+            U14CloseAll();                  // release all open handles
+}
+#endif
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 6cee785..2093403 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -549,6 +549,23 @@
 
 if COMEDI_PCI_DRIVERS
 
+config COMEDI_8255_PCI
+	tristate "Generic PCI based 8255 digital i/o board support"
+	select COMEDI_8255
+	---help---
+	  Enable support for PCI based 8255 digital i/o boards. This driver
+	  provides a PCI wrapper around the generic 8255 driver.
+
+	  Supported boards:
+	    ADlink - PCI-7224, PCI-7248, and PCI-7296
+	    Measurement Computing - PCI-DIO24, PCI-DIO24H, PCI-DIO48H and
+	                            PCI-DIO96H
+	    National Instruments - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503,
+	                           PCI-6503B, PCI-6503X, and PXI-6503
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called 8255_pci.
+
 config COMEDI_ADDI_APCI_035
 	tristate "ADDI-DATA APCI_035 support"
 	depends on VIRT_TO_BUS
@@ -676,30 +693,16 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called adl_pci6208.
 
-config COMEDI_ADL_PCI7230
-	tristate "ADLink PCI-7230 digital io board support"
+config COMEDI_ADL_PCI7X3X
+	tristate "ADLink PCI-723X/743X isolated digital i/o board support"
 	---help---
-	  Enable support for ADlink PCI-7230 digital io board support
+	  Enable support for ADlink PCI-723X/743X isolated digital i/o boards.
+	  Supported boards include the 32-channel PCI-7230 (16 in/16 out),
+	  PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel
+	  PCI-7432 (32 in/32 out), PCI-7433 (64 in), and PCI-7434 (64 out).
 
 	  To compile this driver as a module, choose M here: the module will be
-	  called adl_pci7230.
-
-config COMEDI_ADL_PCI7296
-	tristate "ADLink PCI-7296 96 ch. digital io board support"
-	select COMEDI_8255
-	---help---
-	  Enable support for ADlink PCI-7296 96 ch. digital io board support
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called adl_pci7296.
-
-config COMEDI_ADL_PCI7432
-	tristate "ADLink PCI-7432 64 ch. isolated digital io board support"
-	---help---
-	  Enable support for ADlink PCI-7432 64 ch. isolated digital io board
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called adl_pci7432.
+	  called adl_pci7x3x.
 
 config COMEDI_ADL_PCI8164
 	tristate "ADLink PCI-8164 4 Axes Motion Control board support"
@@ -935,16 +938,6 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called cb_pcidda.
 
-config COMEDI_CB_PCIDIO
-	tristate "MeasurementComputing PCI-DIO series support"
-	select COMEDI_8255
-	---help---
-	  Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
-	  PCI-DIO24, PCI-DIO24H and PCI-DIO48H
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called cb_pcidio.
-
 config COMEDI_CB_PCIMDAS
 	tristate "MeasurementComputing PCIM-DAS1602/16 support"
 	select COMEDI_8255
@@ -1039,15 +1032,12 @@
 	  called ni_labpc.
 
 config COMEDI_NI_PCIDIO
-	tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
+	tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support"
 	select COMEDI_MITE
 	select COMEDI_8255
 	---help---
 	  Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
-	  PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
-	  PXI-6503, PCI-6533 and PCI-6534
-	  The DIO-96 appears as four 8255 subdevices. See the 8255
-	  driver notes for details.
+	  PCI-6533 and PCI-6534
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called ni_pcidio.
@@ -1262,8 +1252,8 @@
 	  that has an 8255 chip. For multifunction boards, the main driver will
 	  configure the 8255 subdevice automatically.
 
-	  Note that most PCI 8255 boards do NOT work with this driver, and
-	  need a separate driver as a wrapper.
+	  Note that most PCI based 8255 boards use the 8255_pci driver as a
+	  wrapper around this driver.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called 8255.
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 8ea55ae..133f013 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -208,92 +208,92 @@
 
 /* subdevice types */
 
-	enum comedi_subdevice_type {
-		COMEDI_SUBD_UNUSED,	/* unused by driver */
-		COMEDI_SUBD_AI,	/* analog input */
-		COMEDI_SUBD_AO,	/* analog output */
-		COMEDI_SUBD_DI,	/* digital input */
-		COMEDI_SUBD_DO,	/* digital output */
-		COMEDI_SUBD_DIO,	/* digital input/output */
-		COMEDI_SUBD_COUNTER,	/* counter */
-		COMEDI_SUBD_TIMER,	/* timer */
-		COMEDI_SUBD_MEMORY,	/* memory, EEPROM, DPRAM */
-		COMEDI_SUBD_CALIB,	/* calibration DACs */
-		COMEDI_SUBD_PROC,	/* processor, DSP */
-		COMEDI_SUBD_SERIAL,	/* serial IO */
-		COMEDI_SUBD_PWM	/* PWM */
-	};
+enum comedi_subdevice_type {
+	COMEDI_SUBD_UNUSED,	/* unused by driver */
+	COMEDI_SUBD_AI,		/* analog input */
+	COMEDI_SUBD_AO,		/* analog output */
+	COMEDI_SUBD_DI,		/* digital input */
+	COMEDI_SUBD_DO,		/* digital output */
+	COMEDI_SUBD_DIO,	/* digital input/output */
+	COMEDI_SUBD_COUNTER,	/* counter */
+	COMEDI_SUBD_TIMER,	/* timer */
+	COMEDI_SUBD_MEMORY,	/* memory, EEPROM, DPRAM */
+	COMEDI_SUBD_CALIB,	/* calibration DACs */
+	COMEDI_SUBD_PROC,	/* processor, DSP */
+	COMEDI_SUBD_SERIAL,	/* serial IO */
+	COMEDI_SUBD_PWM		/* PWM */
+};
 
 /* configuration instructions */
 
-	enum configuration_ids {
-		INSN_CONFIG_DIO_INPUT = 0,
-		INSN_CONFIG_DIO_OUTPUT = 1,
-		INSN_CONFIG_DIO_OPENDRAIN = 2,
-		INSN_CONFIG_ANALOG_TRIG = 16,
+enum configuration_ids {
+	INSN_CONFIG_DIO_INPUT = 0,
+	INSN_CONFIG_DIO_OUTPUT = 1,
+	INSN_CONFIG_DIO_OPENDRAIN = 2,
+	INSN_CONFIG_ANALOG_TRIG = 16,
 /*	INSN_CONFIG_WAVEFORM = 17, */
 /*	INSN_CONFIG_TRIG = 18, */
 /*	INSN_CONFIG_COUNTER = 19, */
-		INSN_CONFIG_ALT_SOURCE = 20,
-		INSN_CONFIG_DIGITAL_TRIG = 21,
-		INSN_CONFIG_BLOCK_SIZE = 22,
-		INSN_CONFIG_TIMER_1 = 23,
-		INSN_CONFIG_FILTER = 24,
-		INSN_CONFIG_CHANGE_NOTIFY = 25,
+	INSN_CONFIG_ALT_SOURCE = 20,
+	INSN_CONFIG_DIGITAL_TRIG = 21,
+	INSN_CONFIG_BLOCK_SIZE = 22,
+	INSN_CONFIG_TIMER_1 = 23,
+	INSN_CONFIG_FILTER = 24,
+	INSN_CONFIG_CHANGE_NOTIFY = 25,
 
-		 /*ALPHA*/ INSN_CONFIG_SERIAL_CLOCK = 26,
-		INSN_CONFIG_BIDIRECTIONAL_DATA = 27,
-		INSN_CONFIG_DIO_QUERY = 28,
-		INSN_CONFIG_PWM_OUTPUT = 29,
-		INSN_CONFIG_GET_PWM_OUTPUT = 30,
-		INSN_CONFIG_ARM = 31,
-		INSN_CONFIG_DISARM = 32,
-		INSN_CONFIG_GET_COUNTER_STATUS = 33,
-		INSN_CONFIG_RESET = 34,
-		/* Use CTR as single pulsegenerator */
-		INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001,
-		/* Use CTR as pulsetraingenerator */
-		INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002,
-		/* Use the counter as encoder */
-		INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003,
-		INSN_CONFIG_SET_GATE_SRC = 2001,	/* Set gate source */
-		INSN_CONFIG_GET_GATE_SRC = 2002,	/* Get gate source */
-		/* Set master clock source */
-		INSN_CONFIG_SET_CLOCK_SRC = 2003,
-		INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */
-		INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */
-		/* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */
-		/* Get size in bytes of subdevice's on-board fifos used during
-		 * streaming input/output */
-		INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,
-		INSN_CONFIG_SET_COUNTER_MODE = 4097,
-		/* INSN_CONFIG_8254_SET_MODE is deprecated */
-		INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,
-		INSN_CONFIG_8254_READ_STATUS = 4098,
-		INSN_CONFIG_SET_ROUTING = 4099,
-		INSN_CONFIG_GET_ROUTING = 4109,
-/* PWM */
-		INSN_CONFIG_PWM_SET_PERIOD = 5000,	/* sets frequency */
-		INSN_CONFIG_PWM_GET_PERIOD = 5001,	/* gets frequency */
-		INSN_CONFIG_GET_PWM_STATUS = 5002,	/* is it running? */
-		/* sets H bridge: duty cycle and sign bit for a relay at the
-		 * same time */
-		INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
-		/* gets H bridge data: duty cycle and the sign bit */
-		INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
-	};
+	INSN_CONFIG_SERIAL_CLOCK = 26,	/*ALPHA*/
+	INSN_CONFIG_BIDIRECTIONAL_DATA = 27,
+	INSN_CONFIG_DIO_QUERY = 28,
+	INSN_CONFIG_PWM_OUTPUT = 29,
+	INSN_CONFIG_GET_PWM_OUTPUT = 30,
+	INSN_CONFIG_ARM = 31,
+	INSN_CONFIG_DISARM = 32,
+	INSN_CONFIG_GET_COUNTER_STATUS = 33,
+	INSN_CONFIG_RESET = 34,
+	/* Use CTR as single pulsegenerator */
+	INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001,
+	/* Use CTR as pulsetraingenerator */
+	INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002,
+	/* Use the counter as encoder */
+	INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003,
+	INSN_CONFIG_SET_GATE_SRC = 2001,	/* Set gate source */
+	INSN_CONFIG_GET_GATE_SRC = 2002,	/* Get gate source */
+	/* Set master clock source */
+	INSN_CONFIG_SET_CLOCK_SRC = 2003,
+	INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */
+	INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */
+	/* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */
+	/* Get size in bytes of subdevice's on-board fifos used during
+	 * streaming input/output */
+	INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,
+	INSN_CONFIG_SET_COUNTER_MODE = 4097,
+	/* INSN_CONFIG_8254_SET_MODE is deprecated */
+	INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,
+	INSN_CONFIG_8254_READ_STATUS = 4098,
+	INSN_CONFIG_SET_ROUTING = 4099,
+	INSN_CONFIG_GET_ROUTING = 4109,
+	/* PWM */
+	INSN_CONFIG_PWM_SET_PERIOD = 5000,	/* sets frequency */
+	INSN_CONFIG_PWM_GET_PERIOD = 5001,	/* gets frequency */
+	INSN_CONFIG_GET_PWM_STATUS = 5002,	/* is it running? */
+	/* sets H bridge: duty cycle and sign bit for a relay at the
+	 * same time */
+	INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
+	/* gets H bridge data: duty cycle and the sign bit */
+	INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
+};
 
-	enum comedi_io_direction {
-		COMEDI_INPUT = 0,
-		COMEDI_OUTPUT = 1,
-		COMEDI_OPENDRAIN = 2
-	};
+enum comedi_io_direction {
+	COMEDI_INPUT = 0,
+	COMEDI_OUTPUT = 1,
+	COMEDI_OPENDRAIN = 2
+};
 
-	enum comedi_support_level {
-		COMEDI_UNKNOWN_SUPPORT = 0,
-		COMEDI_SUPPORTED,
-		COMEDI_UNSUPPORTED
-	};
+enum comedi_support_level {
+	COMEDI_UNKNOWN_SUPPORT = 0,
+	COMEDI_SUPPORTED,
+	COMEDI_UNSUPPORTED
+};
 
 /* ioctls */
 
@@ -317,133 +317,133 @@
 
 /* structures */
 
-	struct comedi_trig {
-		unsigned int subdev;	/* subdevice */
-		unsigned int mode;	/* mode */
-		unsigned int flags;
-		unsigned int n_chan;	/* number of channels */
-		unsigned int *chanlist;	/* channel/range list */
-		short *data;	/* data list, size depends on subd flags */
-		unsigned int n;	/* number of scans */
-		unsigned int trigsrc;
-		unsigned int trigvar;
-		unsigned int trigvar1;
-		unsigned int data_len;
-		unsigned int unused[3];
-	};
+struct comedi_trig {
+	unsigned int subdev;	/* subdevice */
+	unsigned int mode;	/* mode */
+	unsigned int flags;
+	unsigned int n_chan;	/* number of channels */
+	unsigned int *chanlist;	/* channel/range list */
+	short *data;		/* data list, size depends on subd flags */
+	unsigned int n;		/* number of scans */
+	unsigned int trigsrc;
+	unsigned int trigvar;
+	unsigned int trigvar1;
+	unsigned int data_len;
+	unsigned int unused[3];
+};
 
-	struct comedi_insn {
-		unsigned int insn;
-		unsigned int n;
-		unsigned int __user *data;
-		unsigned int subdev;
-		unsigned int chanspec;
-		unsigned int unused[3];
-	};
+struct comedi_insn {
+	unsigned int insn;
+	unsigned int n;
+	unsigned int __user *data;
+	unsigned int subdev;
+	unsigned int chanspec;
+	unsigned int unused[3];
+};
 
-	struct comedi_insnlist {
-		unsigned int n_insns;
-		struct comedi_insn __user *insns;
-	};
+struct comedi_insnlist {
+	unsigned int n_insns;
+	struct comedi_insn __user *insns;
+};
 
-	struct comedi_cmd {
-		unsigned int subdev;
-		unsigned int flags;
+struct comedi_cmd {
+	unsigned int subdev;
+	unsigned int flags;
 
-		unsigned int start_src;
-		unsigned int start_arg;
+	unsigned int start_src;
+	unsigned int start_arg;
 
-		unsigned int scan_begin_src;
-		unsigned int scan_begin_arg;
+	unsigned int scan_begin_src;
+	unsigned int scan_begin_arg;
 
-		unsigned int convert_src;
-		unsigned int convert_arg;
+	unsigned int convert_src;
+	unsigned int convert_arg;
 
-		unsigned int scan_end_src;
-		unsigned int scan_end_arg;
+	unsigned int scan_end_src;
+	unsigned int scan_end_arg;
 
-		unsigned int stop_src;
-		unsigned int stop_arg;
+	unsigned int stop_src;
+	unsigned int stop_arg;
 
-		unsigned int __user *chanlist;	/* channel/range list */
-		unsigned int chanlist_len;
+	unsigned int *chanlist;	/* channel/range list */
+	unsigned int chanlist_len;
 
-		short __user *data; /* data list, size depends on subd flags */
-		unsigned int data_len;
-	};
+	short __user *data; /* data list, size depends on subd flags */
+	unsigned int data_len;
+};
 
-	struct comedi_chaninfo {
-		unsigned int subdev;
-		unsigned int __user *maxdata_list;
-		unsigned int __user *flaglist;
-		unsigned int __user *rangelist;
-		unsigned int unused[4];
-	};
+struct comedi_chaninfo {
+	unsigned int subdev;
+	unsigned int __user *maxdata_list;
+	unsigned int __user *flaglist;
+	unsigned int __user *rangelist;
+	unsigned int unused[4];
+};
 
-	struct comedi_rangeinfo {
-		unsigned int range_type;
-		void __user *range_ptr;
-	};
+struct comedi_rangeinfo {
+	unsigned int range_type;
+	void __user *range_ptr;
+};
 
-	struct comedi_krange {
-		int min;	/* fixed point, multiply by 1e-6 */
-		int max;	/* fixed point, multiply by 1e-6 */
-		unsigned int flags;
-	};
+struct comedi_krange {
+	int min;	/* fixed point, multiply by 1e-6 */
+	int max;	/* fixed point, multiply by 1e-6 */
+	unsigned int flags;
+};
 
-	struct comedi_subdinfo {
-		unsigned int type;
-		unsigned int n_chan;
-		unsigned int subd_flags;
-		unsigned int timer_type;
-		unsigned int len_chanlist;
-		unsigned int maxdata;
-		unsigned int flags;	/* channel flags */
-		unsigned int range_type;	/* lookup in kernel */
-		unsigned int settling_time_0;
-		/* see support_level enum for values */
-		unsigned insn_bits_support;
-		unsigned int unused[8];
-	};
+struct comedi_subdinfo {
+	unsigned int type;
+	unsigned int n_chan;
+	unsigned int subd_flags;
+	unsigned int timer_type;
+	unsigned int len_chanlist;
+	unsigned int maxdata;
+	unsigned int flags;		/* channel flags */
+	unsigned int range_type;	/* lookup in kernel */
+	unsigned int settling_time_0;
+	/* see support_level enum for values */
+	unsigned insn_bits_support;
+	unsigned int unused[8];
+};
 
-	struct comedi_devinfo {
-		unsigned int version_code;
-		unsigned int n_subdevs;
-		char driver_name[COMEDI_NAMELEN];
-		char board_name[COMEDI_NAMELEN];
-		int read_subdevice;
-		int write_subdevice;
-		int unused[30];
-	};
+struct comedi_devinfo {
+	unsigned int version_code;
+	unsigned int n_subdevs;
+	char driver_name[COMEDI_NAMELEN];
+	char board_name[COMEDI_NAMELEN];
+	int read_subdevice;
+	int write_subdevice;
+	int unused[30];
+};
 
-	struct comedi_devconfig {
-		char board_name[COMEDI_NAMELEN];
-		int options[COMEDI_NDEVCONFOPTS];
-	};
+struct comedi_devconfig {
+	char board_name[COMEDI_NAMELEN];
+	int options[COMEDI_NDEVCONFOPTS];
+};
 
-	struct comedi_bufconfig {
-		unsigned int subdevice;
-		unsigned int flags;
+struct comedi_bufconfig {
+	unsigned int subdevice;
+	unsigned int flags;
 
-		unsigned int maximum_size;
-		unsigned int size;
+	unsigned int maximum_size;
+	unsigned int size;
 
-		unsigned int unused[4];
-	};
+	unsigned int unused[4];
+};
 
-	struct comedi_bufinfo {
-		unsigned int subdevice;
-		unsigned int bytes_read;
+struct comedi_bufinfo {
+	unsigned int subdevice;
+	unsigned int bytes_read;
 
-		unsigned int buf_write_ptr;
-		unsigned int buf_read_ptr;
-		unsigned int buf_write_count;
-		unsigned int buf_read_count;
+	unsigned int buf_write_ptr;
+	unsigned int buf_read_ptr;
+	unsigned int buf_write_count;
+	unsigned int buf_read_count;
 
-		unsigned int bytes_written;
+	unsigned int bytes_written;
 
-		unsigned int unused[4];
-	};
+	unsigned int unused[4];
+};
 
 /* range stuff */
 
@@ -495,306 +495,306 @@
 
 */
 
-	enum i8254_mode {
-		I8254_MODE0 = (0 << 1),	/* Interrupt on terminal count */
-		I8254_MODE1 = (1 << 1),	/* Hardware retriggerable one-shot */
-		I8254_MODE2 = (2 << 1),	/* Rate generator */
-		I8254_MODE3 = (3 << 1),	/* Square wave mode */
-		I8254_MODE4 = (4 << 1),	/* Software triggered strobe */
-		I8254_MODE5 = (5 << 1),	/* Hardware triggered strobe
-					 * (retriggerable) */
-		I8254_BCD = 1,	/* use binary-coded decimal instead of binary
+enum i8254_mode {
+	I8254_MODE0 = (0 << 1),	/* Interrupt on terminal count */
+	I8254_MODE1 = (1 << 1),	/* Hardware retriggerable one-shot */
+	I8254_MODE2 = (2 << 1),	/* Rate generator */
+	I8254_MODE3 = (3 << 1),	/* Square wave mode */
+	I8254_MODE4 = (4 << 1),	/* Software triggered strobe */
+	I8254_MODE5 = (5 << 1),	/* Hardware triggered strobe
+				 * (retriggerable) */
+	I8254_BCD = 1,		/* use binary-coded decimal instead of binary
 				 * (pretty useless) */
-		I8254_BINARY = 0
-	};
+	I8254_BINARY = 0
+};
 
-	static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel)
-	{
-		if (pfi_channel < 10)
-			return 0x1 + pfi_channel;
-		else
-			return 0xb + pfi_channel;
-	}
+static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel)
+{
+	if (pfi_channel < 10)
+		return 0x1 + pfi_channel;
+	else
+		return 0xb + pfi_channel;
+}
 
-	static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel)
-	{
-		if (rtsi_channel < 7)
-			return 0xb + rtsi_channel;
-		else
-			return 0x1b;
-	}
+static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel)
+{
+	if (rtsi_channel < 7)
+		return 0xb + rtsi_channel;
+	else
+		return 0x1b;
+}
 
 /* mode bits for NI general-purpose counters, set with
  * INSN_CONFIG_SET_COUNTER_MODE */
 #define NI_GPCT_COUNTING_MODE_SHIFT 16
 #define NI_GPCT_INDEX_PHASE_BITSHIFT 20
 #define NI_GPCT_COUNTING_DIRECTION_SHIFT 24
-	enum ni_gpct_mode_bits {
-		NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4,
-		NI_GPCT_EDGE_GATE_MODE_MASK = 0x18,
-		NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0,
-		NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8,
-		NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10,
-		NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18,
-		NI_GPCT_STOP_MODE_MASK = 0x60,
-		NI_GPCT_STOP_ON_GATE_BITS = 0x00,
-		NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20,
-		NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40,
-		NI_GPCT_LOAD_B_SELECT_BIT = 0x80,
-		NI_GPCT_OUTPUT_MODE_MASK = 0x300,
-		NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100,
-		NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200,
-		NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300,
-		NI_GPCT_HARDWARE_DISARM_MASK = 0xc00,
-		NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000,
-		NI_GPCT_DISARM_AT_TC_BITS = 0x400,
-		NI_GPCT_DISARM_AT_GATE_BITS = 0x800,
-		NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00,
-		NI_GPCT_LOADING_ON_TC_BIT = 0x1000,
-		NI_GPCT_LOADING_ON_GATE_BIT = 0x4000,
-		NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_NORMAL_BITS =
-		    0x0 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS =
-		    0x1 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS =
-		    0x2 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS =
-		    0x3 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS =
-		    0x4 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS =
-		    0x6 << NI_GPCT_COUNTING_MODE_SHIFT,
-		NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
-		NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS =
-		    0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT,
-		NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS =
-		    0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT,
-		NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS =
-		    0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT,
-		NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS =
-		    0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
-		NI_GPCT_INDEX_ENABLE_BIT = 0x400000,
-		NI_GPCT_COUNTING_DIRECTION_MASK =
-		    0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
-		NI_GPCT_COUNTING_DIRECTION_DOWN_BITS =
-		    0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
-		NI_GPCT_COUNTING_DIRECTION_UP_BITS =
-		    0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
-		NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS =
-		    0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
-		NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS =
-		    0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
-		NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000,
-		NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0,
-		NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000,
-		NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000,
-		NI_GPCT_OR_GATE_BIT = 0x10000000,
-		NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000
-	};
+enum ni_gpct_mode_bits {
+	NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4,
+	NI_GPCT_EDGE_GATE_MODE_MASK = 0x18,
+	NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0,
+	NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8,
+	NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10,
+	NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18,
+	NI_GPCT_STOP_MODE_MASK = 0x60,
+	NI_GPCT_STOP_ON_GATE_BITS = 0x00,
+	NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20,
+	NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40,
+	NI_GPCT_LOAD_B_SELECT_BIT = 0x80,
+	NI_GPCT_OUTPUT_MODE_MASK = 0x300,
+	NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100,
+	NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200,
+	NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300,
+	NI_GPCT_HARDWARE_DISARM_MASK = 0xc00,
+	NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000,
+	NI_GPCT_DISARM_AT_TC_BITS = 0x400,
+	NI_GPCT_DISARM_AT_GATE_BITS = 0x800,
+	NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00,
+	NI_GPCT_LOADING_ON_TC_BIT = 0x1000,
+	NI_GPCT_LOADING_ON_GATE_BIT = 0x4000,
+	NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_NORMAL_BITS =
+		0x0 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS =
+		0x1 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS =
+		0x2 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS =
+		0x3 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS =
+		0x4 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS =
+		0x6 << NI_GPCT_COUNTING_MODE_SHIFT,
+	NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+	NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS =
+		0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+	NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS =
+		0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+	NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS =
+		0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+	NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS =
+		0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+	NI_GPCT_INDEX_ENABLE_BIT = 0x400000,
+	NI_GPCT_COUNTING_DIRECTION_MASK =
+		0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+	NI_GPCT_COUNTING_DIRECTION_DOWN_BITS =
+		0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+	NI_GPCT_COUNTING_DIRECTION_UP_BITS =
+		0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+	NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS =
+		0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+	NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS =
+		0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+	NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000,
+	NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0,
+	NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000,
+	NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000,
+	NI_GPCT_OR_GATE_BIT = 0x10000000,
+	NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000
+};
 
 /* Bits for setting a clock source with
  * INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters. */
-	enum ni_gpct_clock_source_bits {
-		NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f,
-		NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0,
-		NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1,
-		NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2,
-		NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3,
-		NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4,
-		NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5,
-		/* NI 660x-specific */
-		NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6,
-		NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7,
-		NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8,
-		NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9,
-		NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000,
-		NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0,
-		/* divide source by 2 */
-		NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000,
-		/* divide source by 8 */
-		NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000,
-		NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000
-	};
-	static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n)
-	{
-		/* NI 660x-specific */
-		return 0x10 + n;
-	}
-	static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n)
-	{
-		return 0x18 + n;
-	}
-	static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n)
-	{
-		/* no pfi on NI 660x */
-		return 0x20 + n;
-	}
+enum ni_gpct_clock_source_bits {
+	NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f,
+	NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0,
+	NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1,
+	NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2,
+	NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3,
+	NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4,
+	NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5,
+	/* NI 660x-specific */
+	NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6,
+	NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7,
+	NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8,
+	NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9,
+	NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000,
+	NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0,
+	/* divide source by 2 */
+	NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000,
+	/* divide source by 8 */
+	NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000,
+	NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000
+};
+static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n)
+{
+	/* NI 660x-specific */
+	return 0x10 + n;
+}
+static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n)
+{
+	return 0x18 + n;
+}
+static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n)
+{
+	/* no pfi on NI 660x */
+	return 0x20 + n;
+}
 
 /* Possibilities for setting a gate source with
 INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters.
 May be bitwise-or'd with CR_EDGE or CR_INVERT. */
-	enum ni_gpct_gate_select {
-		/* m-series gates */
-		NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0,
-		NI_GPCT_AI_START2_GATE_SELECT = 0x12,
-		NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13,
-		NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14,
-		NI_GPCT_AI_START1_GATE_SELECT = 0x1c,
-		NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d,
-		NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e,
-		NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f,
-		/* more gates for 660x */
-		NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100,
-		NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101,
-		/* more gates for 660x "second gate" */
-		NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201,
-		NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e,
-		/* m-series "second gate" sources are unknown,
-		 * we should add them here with an offset of 0x300 when
-		 * known. */
-		NI_GPCT_DISABLED_GATE_SELECT = 0x8000,
-	};
-	static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n)
-	{
-		return 0x102 + n;
-	}
-	static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n)
-	{
-		return NI_USUAL_RTSI_SELECT(n);
-	}
-	static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n)
-	{
-		return NI_USUAL_PFI_SELECT(n);
-	}
-	static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n)
-	{
-		return 0x202 + n;
-	}
+enum ni_gpct_gate_select {
+	/* m-series gates */
+	NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0,
+	NI_GPCT_AI_START2_GATE_SELECT = 0x12,
+	NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13,
+	NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14,
+	NI_GPCT_AI_START1_GATE_SELECT = 0x1c,
+	NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d,
+	NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e,
+	NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f,
+	/* more gates for 660x */
+	NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100,
+	NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101,
+	/* more gates for 660x "second gate" */
+	NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201,
+	NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e,
+	/* m-series "second gate" sources are unknown,
+	 * we should add them here with an offset of 0x300 when
+	 * known. */
+	NI_GPCT_DISABLED_GATE_SELECT = 0x8000,
+};
+static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n)
+{
+	return 0x102 + n;
+}
+static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n)
+{
+	return NI_USUAL_RTSI_SELECT(n);
+}
+static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n)
+{
+	return NI_USUAL_PFI_SELECT(n);
+}
+static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n)
+{
+	return 0x202 + n;
+}
 
 /* Possibilities for setting a source with
 INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */
-	enum ni_gpct_other_index {
-		NI_GPCT_SOURCE_ENCODER_A,
-		NI_GPCT_SOURCE_ENCODER_B,
-		NI_GPCT_SOURCE_ENCODER_Z
-	};
-	enum ni_gpct_other_select {
-		/* m-series gates */
-		/* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */
-		NI_GPCT_DISABLED_OTHER_SELECT = 0x8000,
-	};
-	static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n)
-	{
-		return NI_USUAL_PFI_SELECT(n);
-	}
+enum ni_gpct_other_index {
+	NI_GPCT_SOURCE_ENCODER_A,
+	NI_GPCT_SOURCE_ENCODER_B,
+	NI_GPCT_SOURCE_ENCODER_Z
+};
+enum ni_gpct_other_select {
+	/* m-series gates */
+	/* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */
+	NI_GPCT_DISABLED_OTHER_SELECT = 0x8000,
+};
+static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n)
+{
+	return NI_USUAL_PFI_SELECT(n);
+}
 
 /* start sources for ni general-purpose counters for use with
 INSN_CONFIG_ARM */
-	enum ni_gpct_arm_source {
-		NI_GPCT_ARM_IMMEDIATE = 0x0,
-		NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter
-						     * and the adjacent paired
-						     * counter simultaneously */
-		/* NI doesn't document bits for selecting hardware arm triggers.
-		 * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least
-		 * significant bits (3 bits for 660x or 5 bits for m-series)
-		 * through to the hardware.  This will at least allow someone to
-		 * figure out what the bits do later. */
-		NI_GPCT_ARM_UNKNOWN = 0x1000,
-	};
+enum ni_gpct_arm_source {
+	NI_GPCT_ARM_IMMEDIATE = 0x0,
+	NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter
+					     * and the adjacent paired
+					     * counter simultaneously */
+	/* NI doesn't document bits for selecting hardware arm triggers.
+	 * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least
+	 * significant bits (3 bits for 660x or 5 bits for m-series)
+	 * through to the hardware.  This will at least allow someone to
+	 * figure out what the bits do later. */
+	NI_GPCT_ARM_UNKNOWN = 0x1000,
+};
 
 /* digital filtering options for ni 660x for use with INSN_CONFIG_FILTER. */
-	enum ni_gpct_filter_select {
-		NI_GPCT_FILTER_OFF = 0x0,
-		NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1,
-		NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2,
-		NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3,
-		NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4,
-		NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5,
-		NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6
-	};
+enum ni_gpct_filter_select {
+	NI_GPCT_FILTER_OFF = 0x0,
+	NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1,
+	NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2,
+	NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3,
+	NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4,
+	NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5,
+	NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6
+};
 
 /* PFI digital filtering options for ni m-series for use with
  * INSN_CONFIG_FILTER. */
-	enum ni_pfi_filter_select {
-		NI_PFI_FILTER_OFF = 0x0,
-		NI_PFI_FILTER_125ns = 0x1,
-		NI_PFI_FILTER_6425ns = 0x2,
-		NI_PFI_FILTER_2550us = 0x3
-	};
+enum ni_pfi_filter_select {
+	NI_PFI_FILTER_OFF = 0x0,
+	NI_PFI_FILTER_125ns = 0x1,
+	NI_PFI_FILTER_6425ns = 0x2,
+	NI_PFI_FILTER_2550us = 0x3
+};
 
 /* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */
-	enum ni_mio_clock_source {
-		NI_MIO_INTERNAL_CLOCK = 0,
-		NI_MIO_RTSI_CLOCK = 1,	/* doesn't work for m-series, use
-					   NI_MIO_PLL_RTSI_CLOCK() */
-		/* the NI_MIO_PLL_* sources are m-series only */
-		NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
-		NI_MIO_PLL_PXI10_CLOCK = 3,
-		NI_MIO_PLL_RTSI0_CLOCK = 4
-	};
-	static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel)
-	{
-		return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel;
-	}
+enum ni_mio_clock_source {
+	NI_MIO_INTERNAL_CLOCK = 0,
+	NI_MIO_RTSI_CLOCK = 1,	/* doesn't work for m-series, use
+				   NI_MIO_PLL_RTSI_CLOCK() */
+	/* the NI_MIO_PLL_* sources are m-series only */
+	NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
+	NI_MIO_PLL_PXI10_CLOCK = 3,
+	NI_MIO_PLL_RTSI0_CLOCK = 4
+};
+static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel)
+{
+	return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel;
+}
 
 /* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING.
  The numbers assigned are not arbitrary, they correspond to the bits required
  to program the board. */
-	enum ni_rtsi_routing {
-		NI_RTSI_OUTPUT_ADR_START1 = 0,
-		NI_RTSI_OUTPUT_ADR_START2 = 1,
-		NI_RTSI_OUTPUT_SCLKG = 2,
-		NI_RTSI_OUTPUT_DACUPDN = 3,
-		NI_RTSI_OUTPUT_DA_START1 = 4,
-		NI_RTSI_OUTPUT_G_SRC0 = 5,
-		NI_RTSI_OUTPUT_G_GATE0 = 6,
-		NI_RTSI_OUTPUT_RGOUT0 = 7,
-		NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
-		NI_RTSI_OUTPUT_RTSI_OSC = 12	/* pre-m-series always have RTSI
-						 * clock on line 7 */
-	};
-	static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)
-	{
-		return NI_RTSI_OUTPUT_RTSI_BRD_0 + n;
-	}
+enum ni_rtsi_routing {
+	NI_RTSI_OUTPUT_ADR_START1 = 0,
+	NI_RTSI_OUTPUT_ADR_START2 = 1,
+	NI_RTSI_OUTPUT_SCLKG = 2,
+	NI_RTSI_OUTPUT_DACUPDN = 3,
+	NI_RTSI_OUTPUT_DA_START1 = 4,
+	NI_RTSI_OUTPUT_G_SRC0 = 5,
+	NI_RTSI_OUTPUT_G_GATE0 = 6,
+	NI_RTSI_OUTPUT_RGOUT0 = 7,
+	NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
+	NI_RTSI_OUTPUT_RTSI_OSC = 12	/* pre-m-series always have RTSI
+					 * clock on line 7 */
+};
+static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)
+{
+	return NI_RTSI_OUTPUT_RTSI_BRD_0 + n;
+}
 
 /* Signals which can be routed to an NI PFI pin on an m-series board with
  * INSN_CONFIG_SET_ROUTING.  These numbers are also returned by
  * INSN_CONFIG_GET_ROUTING on pre-m-series boards, even though their routing
  * cannot be changed.  The numbers assigned are not arbitrary, they correspond
  * to the bits required to program the board. */
-	enum ni_pfi_routing {
-		NI_PFI_OUTPUT_PFI_DEFAULT = 0,
-		NI_PFI_OUTPUT_AI_START1 = 1,
-		NI_PFI_OUTPUT_AI_START2 = 2,
-		NI_PFI_OUTPUT_AI_CONVERT = 3,
-		NI_PFI_OUTPUT_G_SRC1 = 4,
-		NI_PFI_OUTPUT_G_GATE1 = 5,
-		NI_PFI_OUTPUT_AO_UPDATE_N = 6,
-		NI_PFI_OUTPUT_AO_START1 = 7,
-		NI_PFI_OUTPUT_AI_START_PULSE = 8,
-		NI_PFI_OUTPUT_G_SRC0 = 9,
-		NI_PFI_OUTPUT_G_GATE0 = 10,
-		NI_PFI_OUTPUT_EXT_STROBE = 11,
-		NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12,
-		NI_PFI_OUTPUT_GOUT0 = 13,
-		NI_PFI_OUTPUT_GOUT1 = 14,
-		NI_PFI_OUTPUT_FREQ_OUT = 15,
-		NI_PFI_OUTPUT_PFI_DO = 16,
-		NI_PFI_OUTPUT_I_ATRIG = 17,
-		NI_PFI_OUTPUT_RTSI0 = 18,
-		NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26,
-		NI_PFI_OUTPUT_SCXI_TRIG1 = 27,
-		NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28,
-		NI_PFI_OUTPUT_CDI_SAMPLE = 29,
-		NI_PFI_OUTPUT_CDO_UPDATE = 30
-	};
-	static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel)
-	{
-		return NI_PFI_OUTPUT_RTSI0 + rtsi_channel;
-	}
+enum ni_pfi_routing {
+	NI_PFI_OUTPUT_PFI_DEFAULT = 0,
+	NI_PFI_OUTPUT_AI_START1 = 1,
+	NI_PFI_OUTPUT_AI_START2 = 2,
+	NI_PFI_OUTPUT_AI_CONVERT = 3,
+	NI_PFI_OUTPUT_G_SRC1 = 4,
+	NI_PFI_OUTPUT_G_GATE1 = 5,
+	NI_PFI_OUTPUT_AO_UPDATE_N = 6,
+	NI_PFI_OUTPUT_AO_START1 = 7,
+	NI_PFI_OUTPUT_AI_START_PULSE = 8,
+	NI_PFI_OUTPUT_G_SRC0 = 9,
+	NI_PFI_OUTPUT_G_GATE0 = 10,
+	NI_PFI_OUTPUT_EXT_STROBE = 11,
+	NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12,
+	NI_PFI_OUTPUT_GOUT0 = 13,
+	NI_PFI_OUTPUT_GOUT1 = 14,
+	NI_PFI_OUTPUT_FREQ_OUT = 15,
+	NI_PFI_OUTPUT_PFI_DO = 16,
+	NI_PFI_OUTPUT_I_ATRIG = 17,
+	NI_PFI_OUTPUT_RTSI0 = 18,
+	NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26,
+	NI_PFI_OUTPUT_SCXI_TRIG1 = 27,
+	NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28,
+	NI_PFI_OUTPUT_CDI_SAMPLE = 29,
+	NI_PFI_OUTPUT_CDO_UPDATE = 30
+};
+static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel)
+{
+	return NI_PFI_OUTPUT_RTSI0 + rtsi_channel;
+}
 
 /* Signals which can be routed to output on a NI PFI pin on a 660x board
  with INSN_CONFIG_SET_ROUTING.  The numbers assigned are
@@ -802,113 +802,112 @@
  to program the board.  Lines 0 to 7 can only be set to
  NI_660X_PFI_OUTPUT_DIO.  Lines 32 to 39 can only be set to
  NI_660X_PFI_OUTPUT_COUNTER. */
-	enum ni_660x_pfi_routing {
-		NI_660X_PFI_OUTPUT_COUNTER = 1,	/* counter */
-		NI_660X_PFI_OUTPUT_DIO = 2,	/* static digital output */
-	};
+enum ni_660x_pfi_routing {
+	NI_660X_PFI_OUTPUT_COUNTER = 1,	/* counter */
+	NI_660X_PFI_OUTPUT_DIO = 2,	/* static digital output */
+};
 
 /* NI External Trigger lines.  These values are not arbitrary, but are related
  * to the bits required to program the board (offset by 1 for historical
  * reasons). */
-	static inline unsigned NI_EXT_PFI(unsigned pfi_channel)
-	{
-		return NI_USUAL_PFI_SELECT(pfi_channel) - 1;
-	}
-	static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel)
-	{
-		return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1;
-	}
+static inline unsigned NI_EXT_PFI(unsigned pfi_channel)
+{
+	return NI_USUAL_PFI_SELECT(pfi_channel) - 1;
+}
+static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel)
+{
+	return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1;
+}
 
 /* status bits for INSN_CONFIG_GET_COUNTER_STATUS */
-	enum comedi_counter_status_flags {
-		COMEDI_COUNTER_ARMED = 0x1,
-		COMEDI_COUNTER_COUNTING = 0x2,
-		COMEDI_COUNTER_TERMINAL_COUNT = 0x4,
-	};
+enum comedi_counter_status_flags {
+	COMEDI_COUNTER_ARMED = 0x1,
+	COMEDI_COUNTER_COUNTING = 0x2,
+	COMEDI_COUNTER_TERMINAL_COUNT = 0x4,
+};
 
 /* Clock sources for CDIO subdevice on NI m-series boards.  Used as the
  * scan_begin_arg for a comedi_command. These sources may also be bitwise-or'd
  * with CR_INVERT to change polarity. */
-	enum ni_m_series_cdio_scan_begin_src {
-		NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0,
-		NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18,
-		NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19,
-		NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20,
-		NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28,
-		NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29,
-		NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30,
-		NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31,
-		NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32,
-		NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33
-	};
-	static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
-	{
-		return NI_USUAL_PFI_SELECT(pfi_channel);
-	}
-	static inline unsigned
-		NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
-	{
-		return NI_USUAL_RTSI_SELECT(rtsi_channel);
-	}
+enum ni_m_series_cdio_scan_begin_src {
+	NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0,
+	NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18,
+	NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19,
+	NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20,
+	NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28,
+	NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29,
+	NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30,
+	NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31,
+	NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32,
+	NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33
+};
+static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
+{
+	return NI_USUAL_PFI_SELECT(pfi_channel);
+}
+static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
+{
+	return NI_USUAL_RTSI_SELECT(rtsi_channel);
+}
 
 /* scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI
  * boards.  These scan begin sources can also be bitwise-or'd with CR_INVERT to
  * change polarity. */
-	static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
-	{
-		return NI_USUAL_PFI_SELECT(pfi_channel);
-	}
-	static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
-	{
-		return NI_USUAL_RTSI_SELECT(rtsi_channel);
-	}
+static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
+{
+	return NI_USUAL_PFI_SELECT(pfi_channel);
+}
+static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
+{
+	return NI_USUAL_RTSI_SELECT(rtsi_channel);
+}
 
 /* Bits for setting a clock source with
  * INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice. */
-	enum ni_freq_out_clock_source_bits {
-		NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC,	/* 10 MHz */
-		NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC	/* 100 KHz */
-	};
+enum ni_freq_out_clock_source_bits {
+	NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC,	/* 10 MHz */
+	NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC	/* 100 KHz */
+};
 
 /* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
  * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
-	enum amplc_dio_clock_source {
-		AMPLC_DIO_CLK_CLKN,	/* per channel external clock
-					   input/output pin (pin is only an
-					   input when clock source set to this
-					   value, otherwise it is an output) */
-		AMPLC_DIO_CLK_10MHZ,	/* 10 MHz internal clock */
-		AMPLC_DIO_CLK_1MHZ,	/* 1 MHz internal clock */
-		AMPLC_DIO_CLK_100KHZ,	/* 100 kHz internal clock */
-		AMPLC_DIO_CLK_10KHZ,	/* 10 kHz internal clock */
-		AMPLC_DIO_CLK_1KHZ,	/* 1 kHz internal clock */
-		AMPLC_DIO_CLK_OUTNM1,	/* output of preceding counter channel
-					   (for channel 0, preceding counter
-					   channel is channel 2 on preceding
-					   counter subdevice, for first counter
-					   subdevice, preceding counter
-					   subdevice is the last counter
-					   subdevice) */
-		AMPLC_DIO_CLK_EXT	/* per chip external input pin */
-	};
+enum amplc_dio_clock_source {
+	AMPLC_DIO_CLK_CLKN,	/* per channel external clock
+				   input/output pin (pin is only an
+				   input when clock source set to this
+				   value, otherwise it is an output) */
+	AMPLC_DIO_CLK_10MHZ,	/* 10 MHz internal clock */
+	AMPLC_DIO_CLK_1MHZ,	/* 1 MHz internal clock */
+	AMPLC_DIO_CLK_100KHZ,	/* 100 kHz internal clock */
+	AMPLC_DIO_CLK_10KHZ,	/* 10 kHz internal clock */
+	AMPLC_DIO_CLK_1KHZ,	/* 1 kHz internal clock */
+	AMPLC_DIO_CLK_OUTNM1,	/* output of preceding counter channel
+				   (for channel 0, preceding counter
+				   channel is channel 2 on preceding
+				   counter subdevice, for first counter
+				   subdevice, preceding counter
+				   subdevice is the last counter
+				   subdevice) */
+	AMPLC_DIO_CLK_EXT	/* per chip external input pin */
+};
 
 /* Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for
  * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
-	enum amplc_dio_gate_source {
-		AMPLC_DIO_GAT_VCC,	/* internal high logic level */
-		AMPLC_DIO_GAT_GND,	/* internal low logic level */
-		AMPLC_DIO_GAT_GATN,	/* per channel external gate input */
-		AMPLC_DIO_GAT_NOUTNM2,	/* negated output of counter channel
-					   minus 2 (for channels 0 or 1,
-					   channel minus 2 is channel 1 or 2 on
-					   the preceding counter subdevice, for
-					   the first counter subdevice the
-					   preceding counter subdevice is the
-					   last counter subdevice) */
-		AMPLC_DIO_GAT_RESERVED4,
-		AMPLC_DIO_GAT_RESERVED5,
-		AMPLC_DIO_GAT_RESERVED6,
-		AMPLC_DIO_GAT_RESERVED7
-	};
+enum amplc_dio_gate_source {
+	AMPLC_DIO_GAT_VCC,	/* internal high logic level */
+	AMPLC_DIO_GAT_GND,	/* internal low logic level */
+	AMPLC_DIO_GAT_GATN,	/* per channel external gate input */
+	AMPLC_DIO_GAT_NOUTNM2,	/* negated output of counter channel
+				   minus 2 (for channels 0 or 1,
+				   channel minus 2 is channel 1 or 2 on
+				   the preceding counter subdevice, for
+				   the first counter subdevice the
+				   preceding counter subdevice is the
+				   last counter subdevice) */
+	AMPLC_DIO_GAT_RESERVED4,
+	AMPLC_DIO_GAT_RESERVED5,
+	AMPLC_DIO_GAT_RESERVED6,
+	AMPLC_DIO_GAT_RESERVED7
+};
 
 #endif /* _COMEDI_H */
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index e821264..c2a32cf 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -370,7 +370,8 @@
 			return -ENOMEM;
 
 		if (copy_from_user(aux_data,
-				   comedi_aux_data(it.options, 0), aux_len)) {
+				   (unsigned char __user *
+				    )comedi_aux_data(it.options, 0), aux_len)) {
 			vfree(aux_data);
 			return -EFAULT;
 		}
@@ -426,7 +427,7 @@
 	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
 		return -EINVAL;
 
-	s = dev->subdevices + bc.subdevice;
+	s = &dev->subdevices[bc.subdevice];
 	async = s->async;
 
 	if (!async) {
@@ -539,7 +540,7 @@
 
 	/* fill subdinfo structs */
 	for (i = 0; i < dev->n_subdevices; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		us = tmp + i;
 
 		us->type = s->type;
@@ -617,7 +618,7 @@
 
 	if (it.subdev >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + it.subdev;
+	s = &dev->subdevices[it.subdev];
 
 	if (it.maxdata_list) {
 		if (s->maxdata || !s->maxdata_list)
@@ -685,7 +686,7 @@
 	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
 		return -EINVAL;
 
-	s = dev->subdevices + bi.subdevice;
+	s = &dev->subdevices[bi.subdevice];
 
 	if (s->lock && s->lock != file)
 		return -EACCES;
@@ -882,14 +883,12 @@
 		/* by default we allow the insn since we don't have checks for
 		 * all possible cases yet */
 	default:
-		printk(KERN_WARNING
-		       "comedi: no check for data length of config insn id "
-		       "%i is implemented.\n"
-		       " Add a check to %s in %s.\n"
-		       " Assuming n=%i is correct.\n", data[0], __func__,
-		       __FILE__, insn->n);
+		pr_warn("comedi: No check for data length of config insn id %i is implemented.\n",
+			data[0]);
+		pr_warn("comedi: Add a check to %s in %s.\n",
+			__func__, __FILE__);
+		pr_warn("comedi: Assuming n=%i is correct.\n", insn->n);
 		return 0;
-		break;
 	}
 	return -EINVAL;
 }
@@ -940,7 +939,7 @@
 				ret = -EINVAL;
 				break;
 			}
-			s = dev->subdevices + insn->subdev;
+			s = &dev->subdevices[insn->subdev];
 			if (!s->async) {
 				DPRINTK("no async\n");
 				ret = -EINVAL;
@@ -951,7 +950,7 @@
 				ret = -EAGAIN;
 				break;
 			}
-			ret = s->async->inttrig(dev, s, insn->data[0]);
+			ret = s->async->inttrig(dev, s, data[0]);
 			if (ret >= 0)
 				ret = 1;
 			break;
@@ -969,7 +968,7 @@
 			ret = -EINVAL;
 			goto out;
 		}
-		s = dev->subdevices + insn->subdev;
+		s = &dev->subdevices[insn->subdev];
 
 		if (s->type == COMEDI_SUBD_UNUSED) {
 			DPRINTK("%d not usable subdevice\n", insn->subdev);
@@ -1133,37 +1132,37 @@
 }
 
 static int do_cmd_ioctl(struct comedi_device *dev,
-			struct comedi_cmd __user *cmd, void *file)
+			struct comedi_cmd __user *arg, void *file)
 {
-	struct comedi_cmd user_cmd;
+	struct comedi_cmd cmd;
 	struct comedi_subdevice *s;
 	struct comedi_async *async;
 	int ret = 0;
-	unsigned int __user *chanlist_saver = NULL;
+	unsigned int __user *user_chanlist;
 
-	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
+	if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 	}
 	/* save user's chanlist pointer so it can be restored later */
-	chanlist_saver = user_cmd.chanlist;
+	user_chanlist = (unsigned int __user *)cmd.chanlist;
 
-	if (user_cmd.subdev >= dev->n_subdevices) {
-		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+	if (cmd.subdev >= dev->n_subdevices) {
+		DPRINTK("%d no such subdevice\n", cmd.subdev);
 		return -ENODEV;
 	}
 
-	s = dev->subdevices + user_cmd.subdev;
+	s = &dev->subdevices[cmd.subdev];
 	async = s->async;
 
 	if (s->type == COMEDI_SUBD_UNUSED) {
-		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+		DPRINTK("%d not valid subdevice\n", cmd.subdev);
 		return -EIO;
 	}
 
 	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
 		DPRINTK("subdevice %i does not support commands\n",
-			user_cmd.subdev);
+			cmd.subdev);
 		return -EIO;
 	}
 
@@ -1181,23 +1180,22 @@
 	s->busy = file;
 
 	/* make sure channel/gain list isn't too long */
-	if (user_cmd.chanlist_len > s->len_chanlist) {
+	if (cmd.chanlist_len > s->len_chanlist) {
 		DPRINTK("channel/gain list too long %u > %d\n",
-			user_cmd.chanlist_len, s->len_chanlist);
+			cmd.chanlist_len, s->len_chanlist);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
 	/* make sure channel/gain list isn't too short */
-	if (user_cmd.chanlist_len < 1) {
+	if (cmd.chanlist_len < 1) {
 		DPRINTK("channel/gain list too short %u < 1\n",
-			user_cmd.chanlist_len);
+			cmd.chanlist_len);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
-	kfree(async->cmd.chanlist);
-	async->cmd = user_cmd;
+	async->cmd = cmd;
 	async->cmd.data = NULL;
 	/* load channel/gain list */
 	async->cmd.chanlist =
@@ -1208,7 +1206,7 @@
 		goto cleanup;
 	}
 
-	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
+	if (copy_from_user(async->cmd.chanlist, user_chanlist,
 			   async->cmd.chanlist_len * sizeof(int))) {
 		DPRINTK("fault reading chanlist\n");
 		ret = -EFAULT;
@@ -1228,11 +1226,11 @@
 
 	if (async->cmd.flags & TRIG_BOGUS || ret) {
 		DPRINTK("test returned %d\n", ret);
-		user_cmd = async->cmd;
+		cmd = async->cmd;
 		/* restore chanlist pointer before copying back */
-		user_cmd.chanlist = chanlist_saver;
-		user_cmd.data = NULL;
-		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
+		cmd.chanlist = (unsigned int __force *)user_chanlist;
+		cmd.data = NULL;
+		if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
 			DPRINTK("fault writing cmd\n");
 			ret = -EFAULT;
 			goto cleanup;
@@ -1285,77 +1283,77 @@
 static int do_cmdtest_ioctl(struct comedi_device *dev,
 			    struct comedi_cmd __user *arg, void *file)
 {
-	struct comedi_cmd user_cmd;
+	struct comedi_cmd cmd;
 	struct comedi_subdevice *s;
 	int ret = 0;
 	unsigned int *chanlist = NULL;
-	unsigned int __user *chanlist_saver = NULL;
+	unsigned int __user *user_chanlist;
 
-	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
+	if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 	}
 	/* save user's chanlist pointer so it can be restored later */
-	chanlist_saver = user_cmd.chanlist;
+	user_chanlist = (unsigned int __user *)cmd.chanlist;
 
-	if (user_cmd.subdev >= dev->n_subdevices) {
-		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+	if (cmd.subdev >= dev->n_subdevices) {
+		DPRINTK("%d no such subdevice\n", cmd.subdev);
 		return -ENODEV;
 	}
 
-	s = dev->subdevices + user_cmd.subdev;
+	s = &dev->subdevices[cmd.subdev];
 	if (s->type == COMEDI_SUBD_UNUSED) {
-		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+		DPRINTK("%d not valid subdevice\n", cmd.subdev);
 		return -EIO;
 	}
 
 	if (!s->do_cmd || !s->do_cmdtest) {
 		DPRINTK("subdevice %i does not support commands\n",
-			user_cmd.subdev);
+			cmd.subdev);
 		return -EIO;
 	}
 
 	/* make sure channel/gain list isn't too long */
-	if (user_cmd.chanlist_len > s->len_chanlist) {
+	if (cmd.chanlist_len > s->len_chanlist) {
 		DPRINTK("channel/gain list too long %d > %d\n",
-			user_cmd.chanlist_len, s->len_chanlist);
+			cmd.chanlist_len, s->len_chanlist);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
 	/* load channel/gain list */
-	if (user_cmd.chanlist) {
+	if (cmd.chanlist) {
 		chanlist =
-		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
+		    kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL);
 		if (!chanlist) {
 			DPRINTK("allocation failed\n");
 			ret = -ENOMEM;
 			goto cleanup;
 		}
 
-		if (copy_from_user(chanlist, user_cmd.chanlist,
-				   user_cmd.chanlist_len * sizeof(int))) {
+		if (copy_from_user(chanlist, user_chanlist,
+				   cmd.chanlist_len * sizeof(int))) {
 			DPRINTK("fault reading chanlist\n");
 			ret = -EFAULT;
 			goto cleanup;
 		}
 
 		/* make sure each element in channel/gain list is valid */
-		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
+		ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
 		if (ret < 0) {
 			DPRINTK("bad chanlist\n");
 			goto cleanup;
 		}
 
-		user_cmd.chanlist = chanlist;
+		cmd.chanlist = chanlist;
 	}
 
-	ret = s->do_cmdtest(dev, s, &user_cmd);
+	ret = s->do_cmdtest(dev, s, &cmd);
 
 	/* restore chanlist pointer before copying back */
-	user_cmd.chanlist = chanlist_saver;
+	cmd.chanlist = (unsigned int __force *)user_chanlist;
 
-	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
+	if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		ret = -EFAULT;
 		goto cleanup;
@@ -1390,7 +1388,7 @@
 
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + arg;
+	s = &dev->subdevices[arg];
 
 	spin_lock_irqsave(&s->spin_lock, flags);
 	if (s->busy || s->lock)
@@ -1433,7 +1431,7 @@
 
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + arg;
+	s = &dev->subdevices[arg];
 
 	if (s->busy)
 		return -EBUSY;
@@ -1474,7 +1472,7 @@
 
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + arg;
+	s = &dev->subdevices[arg];
 	if (s->async == NULL)
 		return -EINVAL;
 
@@ -1511,7 +1509,7 @@
 
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + arg;
+	s = &dev->subdevices[arg];
 
 	if (s->lock && s->lock != file)
 		return -EACCES;
@@ -2025,7 +2023,8 @@
 /*
    This function restores a subdevice to an idle state.
  */
-void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
+static void do_become_nonbusy(struct comedi_device *dev,
+			      struct comedi_subdevice *s)
 {
 	struct comedi_async *async = s->async;
 
@@ -2033,9 +2032,11 @@
 	if (async) {
 		comedi_reset_async_buf(async);
 		async->inttrig = NULL;
+		kfree(async->cmd.chanlist);
+		async->cmd.chanlist = NULL;
 	} else {
-		printk(KERN_ERR
-		       "BUG: (?) do_become_nonbusy called with async=0\n");
+		dev_err(dev->class_dev,
+			"BUG: (?) do_become_nonbusy called with async=NULL\n");
 	}
 
 	s->busy = NULL;
@@ -2140,7 +2141,7 @@
 
 	if (dev->subdevices) {
 		for (i = 0; i < dev->n_subdevices; i++) {
-			s = dev->subdevices + i;
+			s = &dev->subdevices[i];
 
 			if (s->busy == file)
 				do_cancel(dev, s);
@@ -2211,14 +2212,12 @@
 	int i;
 	int retval;
 
-	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
-	       " - http://www.comedi.org\n");
+	pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
 
 	if (comedi_num_legacy_minors < 0 ||
 	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
-		printk(KERN_ERR "comedi: error: invalid value for module "
-		       "parameter \"comedi_num_legacy_minors\".  Valid values "
-		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
+		pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\".  Valid values are 0 through %i.\n",
+		       COMEDI_NUM_BOARD_MINORS);
 		return -EINVAL;
 	}
 
@@ -2247,7 +2246,7 @@
 	}
 	comedi_class = class_create(THIS_MODULE, "comedi");
 	if (IS_ERR(comedi_class)) {
-		printk(KERN_ERR "comedi: failed to create class");
+		pr_err("comedi: failed to create class\n");
 		cdev_del(&comedi_cdev);
 		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
 					 COMEDI_NUM_MINORS);
@@ -2295,8 +2294,7 @@
 
 void comedi_error(const struct comedi_device *dev, const char *s)
 {
-	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
-	       dev->driver->driver_name, s);
+	dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
 }
 EXPORT_SYMBOL(comedi_error);
 
@@ -2364,7 +2362,7 @@
 		return 0;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		if (s->busy)
 			return 1;
 		if (s->async && s->async->mmap_count)
@@ -2420,9 +2418,7 @@
 		comedi_device_cleanup(info->device);
 		kfree(info->device);
 		kfree(info);
-		printk(KERN_ERR
-		       "comedi: error: "
-		       "ran out of minor numbers for board device files.\n");
+		pr_err("comedi: error: ran out of minor numbers for board device files.\n");
 		return -EBUSY;
 	}
 	info->device->minor = i;
@@ -2499,9 +2495,7 @@
 	spin_unlock(&comedi_file_info_table_lock);
 	if (i == COMEDI_NUM_MINORS) {
 		kfree(info);
-		printk(KERN_ERR
-		       "comedi: error: "
-		       "ran out of minor numbers for board device files.\n");
+		pr_err("comedi: error: ran out of minor numbers for board device files.\n");
 		return -EBUSY;
 	}
 	s->minor = i;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index f713783..cb67a5c 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -46,7 +46,7 @@
 
 #define DPRINTK(format, args...)	do {		\
 	if (comedi_debug)				\
-		printk(KERN_DEBUG "comedi: " format , ## args);	\
+		pr_debug("comedi: " format, ## args);	\
 } while (0)
 
 #define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 2359151..1db6bfd 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -71,7 +71,7 @@
 	dev->n_subdevices = num_subdevices;
 
 	for (i = 0; i < num_subdevices; ++i) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		s->device = dev;
 		s->async_dma_dir = DMA_NONE;
 		spin_lock_init(&s->spin_lock);
@@ -88,7 +88,7 @@
 
 	if (dev->subdevices) {
 		for (i = 0; i < dev->n_subdevices; i++) {
-			s = dev->subdevices + i;
+			s = &dev->subdevices[i];
 			comedi_free_subdevice_minor(s);
 			if (s->async) {
 				comedi_buf_alloc(dev, s, 0);
@@ -119,8 +119,8 @@
 	if (dev->driver)
 		dev->driver->detach(dev);
 	else
-		printk(KERN_WARNING
-		       "BUG: dev->driver=NULL in comedi_device_detach()\n");
+		dev_warn(dev->class_dev,
+			 "BUG: dev->driver=NULL in comedi_device_detach()\n");
 	cleanup_device(dev);
 }
 
@@ -142,8 +142,7 @@
 		return ret;
 	}
 	if (!dev->board_name) {
-		printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
-		       dev->board_name);
+		dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n");
 		dev->board_name = "BUG";
 	}
 	smp_wmb();
@@ -160,10 +159,8 @@
 		return -EBUSY;
 
 	for (driv = comedi_drivers; driv; driv = driv->next) {
-		if (!try_module_get(driv->module)) {
-			printk(KERN_INFO "comedi: failed to increment module count, skipping\n");
+		if (!try_module_get(driv->module))
 			continue;
-		}
 		if (driv->num_names) {
 			dev->board_ptr = comedi_recognize(driv, it->board_name);
 			if (dev->board_ptr)
@@ -176,16 +173,21 @@
 		/*  recognize has failed if we get here */
 		/*  report valid board names before returning error */
 		for (driv = comedi_drivers; driv; driv = driv->next) {
-			if (!try_module_get(driv->module)) {
-				printk(KERN_INFO
-				       "comedi: failed to increment module count\n");
+			if (!try_module_get(driv->module))
 				continue;
-			}
 			comedi_report_boards(driv);
 			module_put(driv->module);
 		}
 		return -EIO;
 	}
+	if (driv->attach == NULL) {
+		/* driver does not support manual configuration */
+		dev_warn(dev->class_dev,
+			 "driver '%s' does not support attach using comedi_config\n",
+			 driv->driver_name);
+		module_put(driv->module);
+		return -ENOSYS;
+	}
 	/* initialize dev->driver here so
 	 * comedi_error() can be called from attach */
 	dev->driver = driv;
@@ -225,8 +227,9 @@
 		mutex_lock(&dev->mutex);
 		if (dev->attached && dev->driver == driver) {
 			if (dev->use_count)
-				printk(KERN_WARNING "BUG! detaching device with use_count=%d\n",
-						dev->use_count);
+				dev_warn(dev->class_dev,
+					 "BUG! detaching device with use_count=%d\n",
+					 dev->use_count);
 			comedi_device_detach(dev);
 		}
 		mutex_unlock(&dev->mutex);
@@ -255,7 +258,7 @@
 	int ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 
 		if (s->type == COMEDI_SUBD_UNUSED)
 			continue;
@@ -273,8 +276,8 @@
 			async =
 			    kzalloc(sizeof(struct comedi_async), GFP_KERNEL);
 			if (async == NULL) {
-				printk(KERN_INFO
-				       "failed to allocate async struct\n");
+				dev_warn(dev->class_dev,
+					 "failed to allocate async struct\n");
 				return -ENOMEM;
 			}
 			init_waitqueue_head(&async->wait_head);
@@ -290,7 +293,8 @@
 			async->prealloc_buf = NULL;
 			async->prealloc_bufsz = 0;
 			if (comedi_buf_alloc(dev, s, buf_size) < 0) {
-				printk(KERN_INFO "Buffer allocation failed\n");
+				dev_warn(dev->class_dev,
+					 "Buffer allocation failed\n");
 				return -ENOMEM;
 			}
 			if (s->buf_change) {
@@ -370,17 +374,17 @@
 	unsigned int i;
 	const char *const *name_ptr;
 
-	printk(KERN_INFO "comedi: valid board names for %s driver are:\n",
-	       driv->driver_name);
+	pr_info("comedi: valid board names for %s driver are:\n",
+		driv->driver_name);
 
 	name_ptr = driv->board_name;
 	for (i = 0; i < driv->num_names; i++) {
-		printk(KERN_INFO " %s\n", *name_ptr);
+		pr_info(" %s\n", *name_ptr);
 		name_ptr = (const char **)((char *)name_ptr + driv->offset);
 	}
 
 	if (driv->num_names == 0)
-		printk(KERN_INFO " %s\n", driv->driver_name);
+		pr_info(" %s\n", driv->driver_name);
 }
 
 static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -411,7 +415,6 @@
 	new_insn.insn = INSN_BITS;
 	new_insn.chanspec = base_bitfield_channel;
 	new_insn.n = 2;
-	new_insn.data = new_data;
 	new_insn.subdev = insn->subdev;
 
 	if (insn->insn == INSN_WRITE) {
@@ -584,9 +587,9 @@
 
 		block_size = num_bytes - count;
 		if (block_size < 0) {
-			printk(KERN_WARNING
-			       "%s: %s: bug! block_size is negative\n",
-			       __FILE__, __func__);
+			dev_warn(s->device->class_dev,
+				 "%s: %s: bug! block_size is negative\n",
+				 __FILE__, __func__);
 			break;
 		}
 		if ((int)(async->munge_ptr + block_size -
@@ -667,7 +670,8 @@
 {
 	if ((int)(async->buf_write_count + nbytes -
 		  async->buf_write_alloc_count) > 0) {
-		printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n");
+		dev_info(async->subdevice->device->class_dev,
+			 "attempted to write-free more bytes than have been write-allocated.\n");
 		nbytes = async->buf_write_alloc_count - async->buf_write_count;
 	}
 	async->buf_write_count += nbytes;
@@ -703,8 +707,8 @@
 	smp_mb();
 	if ((int)(async->buf_read_count + nbytes -
 		  async->buf_read_alloc_count) > 0) {
-		printk(KERN_INFO
-		       "comedi: attempted to read-free more bytes than have been read-allocated.\n");
+		dev_info(async->subdevice->device->class_dev,
+			 "attempted to read-free more bytes than have been read-allocated.\n");
 		nbytes = async->buf_read_alloc_count - async->buf_read_count;
 	}
 	async->buf_read_count += nbytes;
@@ -853,10 +857,9 @@
 	mutex_lock(&comedi_dev->mutex);
 	if (comedi_dev->attached)
 		ret = -EBUSY;
-	else if (!try_module_get(driver->module)) {
-		printk(KERN_INFO "comedi: failed to increment module count\n");
+	else if (!try_module_get(driver->module))
 		ret = -EIO;
-	} else {
+	else {
 		/* set comedi_dev->driver here for attach wrapper */
 		comedi_dev->driver = driver;
 		ret = (*attach_wrapper)(comedi_dev, context);
@@ -884,14 +887,19 @@
 		 * has already been copied to it->board_name */
 		dev->board_ptr = comedi_recognize(driv, it->board_name);
 		if (dev->board_ptr == NULL) {
-			printk(KERN_WARNING
-			       "comedi: auto config failed to find board entry"
-			       " '%s' for driver '%s'\n", it->board_name,
-			       driv->driver_name);
+			dev_warn(dev->class_dev,
+				 "auto config failed to find board entry '%s' for driver '%s'\n",
+				 it->board_name, driv->driver_name);
 			comedi_report_boards(driv);
 			return -EINVAL;
 		}
 	}
+	if (!driv->attach) {
+		dev_warn(dev->class_dev,
+			 "BUG! driver '%s' using old-style auto config but has no attach handler\n",
+			 driv->driver_name);
+		return -EINVAL;
+	}
 	return driv->attach(dev, it);
 }
 
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h
index 3eb45d4..429e0d6 100644
--- a/drivers/staging/comedi/drivers/8253.h
+++ b/drivers/staging/comedi/drivers/8253.h
@@ -262,8 +262,10 @@
 	return 0;
 }
 
-static inline int i8254_mm_load(void *base_address, unsigned int regshift,
-				unsigned int counter_number, unsigned int count,
+static inline int i8254_mm_load(void __iomem *base_address,
+				unsigned int regshift,
+				unsigned int counter_number,
+				unsigned int count,
 				unsigned int mode)
 {
 	unsigned int byte;
@@ -311,7 +313,8 @@
 	return ret;
 }
 
-static inline int i8254_mm_read(void *base_address, unsigned int regshift,
+static inline int i8254_mm_read(void __iomem *base_address,
+				unsigned int regshift,
 				unsigned int counter_number)
 {
 	unsigned int byte;
@@ -348,7 +351,7 @@
 	outb(byte, base_address + (counter_number << regshift));
 }
 
-static inline void i8254_mm_write(void *base_address,
+static inline void i8254_mm_write(void __iomem *base_address,
 				  unsigned int regshift,
 				  unsigned int counter_number,
 				  unsigned int count)
@@ -390,7 +393,7 @@
 	return 0;
 }
 
-static inline int i8254_mm_set_mode(void *base_address,
+static inline int i8254_mm_set_mode(void __iomem *base_address,
 				    unsigned int regshift,
 				    unsigned int counter_number,
 				    unsigned int mode)
@@ -419,7 +422,7 @@
 	return inb(base_address + (counter_number << regshift));
 }
 
-static inline int i8254_mm_status(void *base_address,
+static inline int i8254_mm_status(void __iomem *base_address,
 				  unsigned int regshift,
 				  unsigned int counter_number)
 {
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 4c9977b..a256622 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -82,6 +82,8 @@
 
 #include <linux/ioport.h>
 #include <linux/slab.h>
+
+#include "comedi_fc.h"
 #include "8255.h"
 
 #define _8255_SIZE	4
@@ -229,39 +231,20 @@
 			       struct comedi_cmd *cmd)
 {
 	int err = 0;
-	unsigned int tmp;
 
-	/* step 1 */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2 */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -403,7 +386,7 @@
 		return ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		iobase = it->options[i];
 
 		if (!request_region(iobase, _8255_SIZE, "8255")) {
@@ -429,7 +412,7 @@
 	int i;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		if (s->type != COMEDI_SUBD_UNUSED) {
 			spriv = s->private;
 			release_region(spriv->iobase, _8255_SIZE);
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
new file mode 100644
index 0000000..7dff3c0
--- /dev/null
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -0,0 +1,353 @@
+/*
+ * COMEDI driver for generic PCI based 8255 digital i/o boards
+ * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the tested adl_pci7296 driver written by:
+ *	Jon Grierson <jd@renko.co.uk>
+ * and the experimental cb_pcidio driver written by:
+ *	Yoshiya Matsuzaka
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+Driver: 8255_pci
+Description: Generic PCI based 8255 Digital I/O boards
+Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels
+	 (ADLink) PCI-7248 [adl_pci-7248] - 48 channels
+	 (ADLink) PCI-7296 [adl_pci-7296] - 96 channels
+	 (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels
+	 (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels
+	 (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels
+	 (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels
+	 (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels
+	 (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels
+	 (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels
+	 (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels
+	 (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels
+	 (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels
+	 (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels
+Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+Updated: Wed, 12 Sep 2012 11:52:01 -0700
+Status: untested
+
+Some of these boards also have an 8254 programmable timer/counter
+chip. This chip is not currently supported by this driver.
+
+Interrupt support for these boards is also not currently supported.
+
+Configuration Options: not applicable, uses PCI auto config
+*/
+
+#include "../comedidev.h"
+
+#include "8255.h"
+
+/*
+ * PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_ADLINK_PCI7224	0x7224
+#define PCI_DEVICE_ID_ADLINK_PCI7248	0x7248
+#define PCI_DEVICE_ID_ADLINK_PCI7296	0x7296
+
+/* ComputerBoards is now known as Measurement Computing */
+#define PCI_VENDOR_ID_CB		0x1307
+
+#define PCI_DEVICE_ID_CB_PCIDIO48H	0x000b
+#define PCI_DEVICE_ID_CB_PCIDIO24H	0x0014
+#define PCI_DEVICE_ID_CB_PCIDIO96H	0x0017
+#define PCI_DEVICE_ID_CB_PCIDIO24	0x0028
+
+#define PCI_DEVICE_ID_NI_PCIDIO96	0x0160
+#define PCI_DEVICE_ID_NI_PCI6503	0x0400
+#define PCI_DEVICE_ID_NI_PCI6503B	0x1250
+#define PCI_DEVICE_ID_NI_PXI6508	0x13c0
+#define PCI_DEVICE_ID_NI_PCIDIO96B	0x1630
+#define PCI_DEVICE_ID_NI_PCI6503X	0x17d0
+#define PCI_DEVICE_ID_NI_PXI_6503	0x1800
+
+struct pci_8255_boardinfo {
+	const char *name;
+	unsigned short vendor;
+	unsigned short device;
+	int dio_badr;
+	int is_mmio;
+	int n_8255;
+};
+
+static const struct pci_8255_boardinfo pci_8255_boards[] = {
+	{
+		.name		= "adl_pci-7224",
+		.vendor		= PCI_VENDOR_ID_ADLINK,
+		.device		= PCI_DEVICE_ID_ADLINK_PCI7224,
+		.dio_badr	= 2,
+		.n_8255		= 1,
+	}, {
+		.name		= "adl_pci-7248",
+		.vendor		= PCI_VENDOR_ID_ADLINK,
+		.device		= PCI_DEVICE_ID_ADLINK_PCI7248,
+		.dio_badr	= 2,
+		.n_8255		= 2,
+	}, {
+		.name		= "adl_pci-7296",
+		.vendor		= PCI_VENDOR_ID_ADLINK,
+		.device		= PCI_DEVICE_ID_ADLINK_PCI7296,
+		.dio_badr	= 2,
+		.n_8255		= 4,
+	}, {
+		.name		= "cb_pci-dio24",
+		.vendor		= PCI_VENDOR_ID_CB,
+		.device		= PCI_DEVICE_ID_CB_PCIDIO24,
+		.dio_badr	= 2,
+		.n_8255		= 1,
+	}, {
+		.name		= "cb_pci-dio24h",
+		.vendor		= PCI_VENDOR_ID_CB,
+		.device		= PCI_DEVICE_ID_CB_PCIDIO24H,
+		.dio_badr	= 2,
+		.n_8255		= 1,
+	}, {
+		.name		= "cb_pci-dio48h",
+		.vendor		= PCI_VENDOR_ID_CB,
+		.device		= PCI_DEVICE_ID_CB_PCIDIO48H,
+		.dio_badr	= 1,
+		.n_8255		= 2,
+	}, {
+		.name		= "cb_pci-dio96h",
+		.vendor		= PCI_VENDOR_ID_CB,
+		.device		= PCI_DEVICE_ID_CB_PCIDIO96H,
+		.dio_badr	= 2,
+		.n_8255		= 4,
+	}, {
+		.name		= "ni_pci-dio-96",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PCIDIO96,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 4,
+	}, {
+		.name		= "ni_pci-dio-96b",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PCIDIO96B,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 4,
+	}, {
+		.name		= "ni_pxi-6508",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PXI6508,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 4,
+	}, {
+		.name		= "ni_pci-6503",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PCI6503,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 1,
+	}, {
+		.name		= "ni_pci-6503b",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PCI6503B,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 1,
+	}, {
+		.name		= "ni_pci-6503x",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PCI6503X,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 1,
+	}, {
+		.name		= "ni_pxi-6503",
+		.vendor		= PCI_VENDOR_ID_NI,
+		.device		= PCI_DEVICE_ID_NI_PXI_6503,
+		.dio_badr	= 1,
+		.is_mmio	= 1,
+		.n_8255		= 1,
+	},
+};
+
+struct pci_8255_private {
+	void __iomem *mmio_base;
+};
+
+static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase)
+{
+	void __iomem *mmio_base = (void __iomem *)iobase;
+
+	if (dir) {
+		writeb(data, mmio_base + port);
+		return 0;
+	} else {
+		return readb(mmio_base  + port);
+	}
+}
+
+static const void *pci_8255_find_boardinfo(struct comedi_device *dev,
+					      struct pci_dev *pcidev)
+{
+	const struct pci_8255_boardinfo *board;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pci_8255_boards); i++) {
+		board = &pci_8255_boards[i];
+		if (pcidev->vendor == board->vendor &&
+		    pcidev->device == board->device)
+			return board;
+	}
+	return NULL;
+}
+
+static int pci_8255_attach_pci(struct comedi_device *dev,
+			       struct pci_dev *pcidev)
+{
+	const struct pci_8255_boardinfo *board;
+	struct pci_8255_private *devpriv;
+	struct comedi_subdevice *s;
+	resource_size_t iobase;
+	unsigned long len;
+	int ret;
+	int i;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	board = pci_8255_find_boardinfo(dev, pcidev);
+	if (!board)
+		return -ENODEV;
+	dev->board_ptr = board;
+	dev->board_name = board->name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	iobase = pci_resource_start(pcidev, board->dio_badr);
+	len = pci_resource_len(pcidev, board->dio_badr);
+
+	if (board->is_mmio) {
+		devpriv->mmio_base = ioremap(iobase, len);
+		if (!devpriv->mmio_base)
+			return -ENOMEM;
+	}
+	dev->iobase = iobase;
+
+	/*
+	 * One, two, or four subdevices are setup by this driver depending
+	 * on the number of channels provided by the board. Each subdevice
+	 * has 24 channels supported by the 8255 module.
+	 */
+	ret = comedi_alloc_subdevices(dev, board->n_8255);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < board->n_8255; i++) {
+		s = &dev->subdevices[i];
+		if (board->is_mmio) {
+			iobase = (unsigned long)(devpriv->mmio_base + (i * 4));
+			ret = subdev_8255_init(dev, s, pci_8255_mmio, iobase);
+		} else {
+			iobase = dev->iobase + (i * 4);
+			ret = subdev_8255_init(dev, s, NULL, iobase);
+		}
+		if (ret)
+			return ret;
+	}
+
+	dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n",
+		dev->board_name, board->n_8255 * 24);
+
+	return 0;
+}
+
+static void pci_8255_detach(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	const struct pci_8255_boardinfo *board = comedi_board(dev);
+	struct pci_8255_private *devpriv = dev->private;
+	struct comedi_subdevice *s;
+	int i;
+
+	if (dev->subdevices) {
+		for (i = 0; i < board->n_8255; i++) {
+			s = &dev->subdevices[i];
+			subdev_8255_cleanup(dev, s);
+		}
+	}
+	if (pcidev) {
+		if (devpriv->mmio_base)
+			iounmap(devpriv->mmio_base);
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
+	}
+}
+
+static struct comedi_driver pci_8255_driver = {
+	.driver_name	= "8255_pci",
+	.module		= THIS_MODULE,
+	.attach_pci	= pci_8255_attach_pci,
+	.detach		= pci_8255_detach,
+};
+
+static int __devinit pci_8255_pci_probe(struct pci_dev *dev,
+					const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &pci_8255_driver);
+}
+
+static void __devexit pci_8255_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7224) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7248) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7296) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24H) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO48H) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO96H) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96B) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI6508) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503B) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503X) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI_6503) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci_8255_pci_table);
+
+static struct pci_driver pci_8255_pci_driver = {
+	.name		= "8255_pci",
+	.id_table	= pci_8255_pci_table,
+	.probe		= pci_8255_pci_probe,
+	.remove		= __devexit_p(pci_8255_pci_remove),
+};
+module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver);
+
+MODULE_DESCRIPTION("COMEDI - Generic PCI based 8255 Digital I/O boards");
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 57b19e4..a2787c0 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -55,6 +55,7 @@
 obj-$(CONFIG_COMEDI_POC)		+= poc.o
 
 # Comedi PCI drivers
+obj-$(CONFIG_COMEDI_8255_PCI)		+= 8255_pci.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_035)	+= addi_apci_035.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_1032)	+= addi_apci_1032.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_1500)	+= addi_apci_1500.o
@@ -69,9 +70,7 @@
 obj-$(CONFIG_COMEDI_ADDI_APCI_3501)	+= addi_apci_3501.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_3XXX)	+= addi_apci_3xxx.o
 obj-$(CONFIG_COMEDI_ADL_PCI6208)	+= adl_pci6208.o
-obj-$(CONFIG_COMEDI_ADL_PCI7230)	+= adl_pci7230.o
-obj-$(CONFIG_COMEDI_ADL_PCI7296)	+= adl_pci7296.o
-obj-$(CONFIG_COMEDI_ADL_PCI7432)	+= adl_pci7432.o
+obj-$(CONFIG_COMEDI_ADL_PCI7X3X)	+= adl_pci7x3x.o
 obj-$(CONFIG_COMEDI_ADL_PCI8164)	+= adl_pci8164.o
 obj-$(CONFIG_COMEDI_ADL_PCI9111)	+= adl_pci9111.o
 obj-$(CONFIG_COMEDI_ADL_PCI9118)	+= adl_pci9118.o
@@ -96,7 +95,6 @@
 obj-$(CONFIG_COMEDI_CB_PCIDAS64)	+= cb_pcidas64.o
 obj-$(CONFIG_COMEDI_CB_PCIDAS)		+= cb_pcidas.o
 obj-$(CONFIG_COMEDI_CB_PCIDDA)		+= cb_pcidda.o
-obj-$(CONFIG_COMEDI_CB_PCIDIO)		+= cb_pcidio.o
 obj-$(CONFIG_COMEDI_CB_PCIMDAS)		+= cb_pcimdas.o
 obj-$(CONFIG_COMEDI_CB_PCIMDDA)		+= cb_pcimdda.o
 obj-$(CONFIG_COMEDI_ME4000)		+= me4000.o
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index ddba5db..28c7fd3 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -81,7 +81,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* Relays outputs */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -91,7 +91,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)ACL7225_RIO_LO;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* Relays status */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -101,7 +101,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)ACL7225_RIO_LO;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* Isolated digital inputs */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
deleted file mode 100644
index b973095..0000000
--- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-You should also find the complete GPL in the COPYING file accompanying this source code.
-
-@endverbatim
-*/
-/*
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-------------------------------+---------------------------------------+
-  | Project : ADDI HEADER READ WRITER |     Compiler   : Visual C++       |
-  | Module name : S5920.cpp           |     Version    : 6.0              |
-  +-------------------------------+---------------------------------------+
-  | Author : E. LIBS                      Date : 02/05/2002               |
-  +-----------------------------------------------------------------------+
-  | Description   : DLL with the S5920 PCI Controller functions           |
-  +-----------------------------------------------------------------------+
-  |                             UPDATE'S                                  |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  | 28/08/02 | LIBS Eric | Add return codes each time a function of the   |
-  |          |           | Addi Library is called                         |
-  +-----------------------------------------------------------------------+
-  | 31/07/03 | KRAUTH J. | Changes for the MSX-Box                        |
-  +-----------------------------------------------------------------------+
-*/
-
-#include "addi_amcc_S5920.h"
-
-/*+----------------------------------------------------------------------------+*/
-/*| Function   Name   : int i_AddiHeaderRW_ReadEeprom                          |*/
-/*|                               (int    i_NbOfWordsToRead,                   |*/
-/*|                                unsigned int dw_PCIBoardEepromAddress,             |*/
-/*|                                unsigned short   w_EepromStartAddress,                |*/
-/*|                                unsigned short * pw_DataRead)                          |*/
-/*+----------------------------------------------------------------------------+*/
-/*| Task              : Read word from the 5920 eeprom.                        |*/
-/*+----------------------------------------------------------------------------+*/
-/*| Input Parameters  : int    i_NbOfWordsToRead : Nbr. of word to read        |*/
-/*|                     unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/
-/*|                     unsigned short   w_EepromStartAddress : Eeprom start address     |*/
-/*+----------------------------------------------------------------------------+*/
-/*| Output Parameters : unsigned short * pw_DataRead : Read data                          |*/
-/*+----------------------------------------------------------------------------+*/
-/*| Return Value      : -                                                      |*/
-/*+----------------------------------------------------------------------------+*/
-
-int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead,
-	unsigned int dw_PCIBoardEepromAddress,
-	unsigned short w_EepromStartAddress, unsigned short *pw_DataRead)
-{
-	unsigned int dw_eeprom_busy = 0;
-	int i_Counter = 0;
-	int i_WordCounter;
-	int i;
-	unsigned char pb_ReadByte[1];
-	unsigned char b_ReadLowByte = 0;
-	unsigned char b_ReadHighByte = 0;
-	unsigned char b_SelectedAddressLow = 0;
-	unsigned char b_SelectedAddressHigh = 0;
-	unsigned short w_ReadWord = 0;
-
-	for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead;
-		i_WordCounter++) {
-		do {
-			dw_eeprom_busy =
-				inl(dw_PCIBoardEepromAddress +
-				AMCC_OP_REG_MCSR);
-			dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-		} while (dw_eeprom_busy == EEPROM_BUSY);
-
-		for (i_Counter = 0; i_Counter < 2; i_Counter++) {
-			b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256;	/* Read the low 8 bit part */
-			b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256;	/* Read the high 8 bit part */
-
-			/* Select the load low address mode */
-			outb(NVCMD_LOAD_LOW,
-				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
-				3);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Load the low address */
-			outb(b_SelectedAddressLow,
-				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
-				2);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Select the load high address mode */
-			outb(NVCMD_LOAD_HIGH,
-				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
-				3);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Load the high address */
-			outb(b_SelectedAddressHigh,
-				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
-				2);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Select the READ mode */
-			outb(NVCMD_BEGIN_READ,
-				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
-				3);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Read data into the EEPROM */
-			*pb_ReadByte =
-				inb(dw_PCIBoardEepromAddress +
-				AMCC_OP_REG_MCSR + 2);
-
-			/* Wait on busy */
-			do {
-				dw_eeprom_busy =
-					inl(dw_PCIBoardEepromAddress +
-					AMCC_OP_REG_MCSR);
-				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
-			} while (dw_eeprom_busy == EEPROM_BUSY);
-
-			/* Select the upper address part */
-			if (i_Counter == 0)
-				b_ReadLowByte = pb_ReadByte[0];
-			else
-				b_ReadHighByte = pb_ReadByte[0];
-
-			/* Sleep */
-			msleep(1);
-
-		}
-		w_ReadWord =
-			(b_ReadLowByte | (((unsigned short)b_ReadHighByte) *
-				256));
-
-		pw_DataRead[i_WordCounter] = w_ReadWord;
-
-		w_EepromStartAddress += 2;	/*  to read the next word */
-
-	}			/*  for (...) i_NbOfWordsToRead */
-	return 0;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h
deleted file mode 100644
index 9afdb13..0000000
--- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
- *
- *	ADDI-DATA GmbH
- *	Dieselstrasse 3
- *	D-77833 Ottersweier
- *	Tel: +19(0)7223/9493-0
- *	Fax: +49(0)7223/9493-92
- *	http://www.addi-data.com
- *	info@addi-data.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.
- */
-
-#define AMCC_OP_REG_MCSR	0x3c
-#define EEPROM_BUSY		0x80000000
-#define NVCMD_LOAD_LOW		(0x4 << 5)	/* nvRam load low command */
-#define NVCMD_LOAD_HIGH		(0x5 << 5)	/* nvRam load high command */
-#define NVCMD_BEGIN_READ	(0x7 << 5)	/* nvRam begin read command */
-#define NVCMD_BEGIN_WRITE	(0x6 << 5)	/* EEPROM begin write command */
-
-int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead,
-			      unsigned int dw_PCIBoardEepromAddress,
-			      unsigned short w_EepromStartAddress, unsigned short *pw_DataRead);
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index a3d4ed2..99a96bd 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -1669,7 +1669,7 @@
 			return ret;
 
 		/*  Allocate and Initialise AI Subdevice Structures */
-		s = dev->subdevices + 0;
+		s = &dev->subdevices[0];
 		if ((devpriv->s_EeParameters.i_NbrAiChannel)
 			|| (this_board->i_NbrAiChannelDiff)) {
 			dev->read_subdev = s;
@@ -1705,7 +1705,7 @@
 		}
 
 		/*  Allocate and Initialise AO Subdevice Structures */
-		s = dev->subdevices + 1;
+		s = &dev->subdevices[1];
 		if (devpriv->s_EeParameters.i_NbrAoChannel) {
 			s->type = COMEDI_SUBD_AO;
 			s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
@@ -1720,7 +1720,7 @@
 			s->type = COMEDI_SUBD_UNUSED;
 		}
 		/*  Allocate and Initialise DI Subdevice Structures */
-		s = dev->subdevices + 2;
+		s = &dev->subdevices[2];
 		if (devpriv->s_EeParameters.i_NbrDiChannel) {
 			s->type = COMEDI_SUBD_DI;
 			s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -1738,7 +1738,7 @@
 			s->type = COMEDI_SUBD_UNUSED;
 		}
 		/*  Allocate and Initialise DO Subdevice Structures */
-		s = dev->subdevices + 3;
+		s = &dev->subdevices[3];
 		if (devpriv->s_EeParameters.i_NbrDoChannel) {
 			s->type = COMEDI_SUBD_DO;
 			s->subdev_flags =
@@ -1760,7 +1760,7 @@
 		}
 
 		/*  Allocate and Initialise Timer Subdevice Structures */
-		s = dev->subdevices + 4;
+		s = &dev->subdevices[4];
 		if (devpriv->s_EeParameters.i_Timer) {
 			s->type = COMEDI_SUBD_TIMER;
 			s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
@@ -1778,7 +1778,7 @@
 		}
 
 		/*  Allocate and Initialise TTL */
-		s = dev->subdevices + 5;
+		s = &dev->subdevices[5];
 		if (this_board->i_NbrTTLChannel) {
 			s->type = COMEDI_SUBD_TTLIO;
 			s->subdev_flags =
@@ -1797,7 +1797,7 @@
 		}
 
 		/* EEPROM */
-		s = dev->subdevices + 6;
+		s = &dev->subdevices[6];
 		if (this_board->i_PCIEeprom) {
 			s->type = COMEDI_SUBD_MEMORY;
 			s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
diff --git a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
deleted file mode 100644
index c26c28c..0000000
--- a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
-	Modified by umesh on 16th may 2001
-	Modified by sarath on 22nd may 2001
-*/
-
-/*
-    comedi/drivers/amcc_s5933_v_58.h
-
-    Stuff for AMCC S5933 PCI Controller
-
-    Author: Michal Dobes <majkl@tesnet.cz>
-
-    Inspirated from general-purpose AMCC S5933 PCI Matchmaker driver
-    made by Andrea Cisternino  <acister@pcape1.pi.infn.it>
-    and as result of espionage from MITE code made by David A. Schleef.
-    Thanks to AMCC for their on-line documentation and bus master DMA
-    example.
-*/
-
-#ifndef _AMCC_S5933_H_
-#define _AMCC_S5933_H_
-
-#include <linux/pci.h>
-#include "../../comedidev.h"
-
-/***********Added by sarath for compatibility with APCI3120
-
-*************************/
-
-#define FIFO_ADVANCE_ON_BYTE_2     0x20000000	/*  written on base0 */
-
-#define AMWEN_ENABLE                     0x02	/*  added for step 6 dma written on base2 */
-#define A2P_FIFO_WRITE_ENABLE            0x01
-
-#define AGCSTS_TC_ENABLE		   0x10000000	/*  Added for transfer count enable bit */
-
-/* ADDON RELATED ADDITIONS */
-/* Constant */
-#define     APCI3120_ENABLE_TRANSFER_ADD_ON_LOW       0x00
-#define     APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH      0x1200
-#define     APCI3120_A2P_FIFO_MANAGEMENT              0x04000400L
-#define     APCI3120_AMWEN_ENABLE                     0x02
-#define     APCI3120_A2P_FIFO_WRITE_ENABLE            0x01
-#define     APCI3120_FIFO_ADVANCE_ON_BYTE_2           0x20000000L
-#define     APCI3120_ENABLE_WRITE_TC_INT              0x00004000L
-#define     APCI3120_CLEAR_WRITE_TC_INT               0x00040000L
-#define     APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0
-#define     APCI3120_DISABLE_BUS_MASTER_ADD_ON        0x0
-#define     APCI3120_DISABLE_BUS_MASTER_PCI           0x0
-
- /*  ADD_ON ::: this needed since apci supports 16 bit interface to add on */
-#define     APCI3120_ADD_ON_AGCSTS_LOW       0x3C
-#define     APCI3120_ADD_ON_AGCSTS_HIGH      APCI3120_ADD_ON_AGCSTS_LOW + 2
-#define     APCI3120_ADD_ON_MWAR_LOW         0x24
-#define     APCI3120_ADD_ON_MWAR_HIGH        APCI3120_ADD_ON_MWAR_LOW + 2
-#define     APCI3120_ADD_ON_MWTC_LOW         0x058
-#define     APCI3120_ADD_ON_MWTC_HIGH        APCI3120_ADD_ON_MWTC_LOW + 2
-
-/* AMCC */
-#define     APCI3120_AMCC_OP_MCSR            0x3C
-#define     APCI3120_AMCC_OP_REG_INTCSR      0x38
-
-/*******from here all upward definitions are added by sarath */
-
-/****************************************************************************/
-/* AMCC Operation Register Offsets - PCI                                    */
-/****************************************************************************/
-
-#define AMCC_OP_REG_OMB1         0x00
-#define AMCC_OP_REG_OMB2         0x04
-#define AMCC_OP_REG_OMB3         0x08
-#define AMCC_OP_REG_OMB4         0x0c
-#define AMCC_OP_REG_IMB1         0x10
-#define AMCC_OP_REG_IMB2         0x14
-#define AMCC_OP_REG_IMB3         0x18
-#define AMCC_OP_REG_IMB4         0x1c
-#define AMCC_OP_REG_FIFO         0x20
-#define AMCC_OP_REG_MWAR         0x24
-#define AMCC_OP_REG_MWTC         0x28
-#define AMCC_OP_REG_MRAR         0x2c
-#define AMCC_OP_REG_MRTC         0x30
-#define AMCC_OP_REG_MBEF         0x34
-#define AMCC_OP_REG_INTCSR       0x38
-#define  AMCC_OP_REG_INTCSR_SRC  (AMCC_OP_REG_INTCSR + 2)	/* int source */
-#define  AMCC_OP_REG_INTCSR_FEC  (AMCC_OP_REG_INTCSR + 3)	/* FIFO ctrl */
-#define AMCC_OP_REG_MCSR         0x3c
-#define  AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2)	/* Data in byte 2 */
-#define  AMCC_OP_REG_MCSR_NVCMD  (AMCC_OP_REG_MCSR + 3)	/* Command in byte 3 */
-
-#define AMCC_FIFO_DEPTH_DWORD	8
-#define AMCC_FIFO_DEPTH_BYTES	(8 * sizeof (u32))
-
-/****************************************************************************/
-/* AMCC Operation Registers Size - PCI                                      */
-/****************************************************************************/
-
-#define AMCC_OP_REG_SIZE	 64	/* in bytes */
-
-/****************************************************************************/
-/* AMCC Operation Register Offsets - Add-on                                 */
-/****************************************************************************/
-
-#define AMCC_OP_REG_AIMB1         0x00
-#define AMCC_OP_REG_AIMB2         0x04
-#define AMCC_OP_REG_AIMB3         0x08
-#define AMCC_OP_REG_AIMB4         0x0c
-#define AMCC_OP_REG_AOMB1         0x10
-#define AMCC_OP_REG_AOMB2         0x14
-#define AMCC_OP_REG_AOMB3         0x18
-#define AMCC_OP_REG_AOMB4         0x1c
-#define AMCC_OP_REG_AFIFO         0x20
-#define AMCC_OP_REG_AMWAR         0x24
-#define AMCC_OP_REG_APTA          0x28
-#define AMCC_OP_REG_APTD          0x2c
-#define AMCC_OP_REG_AMRAR         0x30
-#define AMCC_OP_REG_AMBEF         0x34
-#define AMCC_OP_REG_AINT          0x38
-#define AMCC_OP_REG_AGCSTS        0x3c
-#define AMCC_OP_REG_AMWTC         0x58
-#define AMCC_OP_REG_AMRTC         0x5c
-
-/****************************************************************************/
-/* AMCC - Add-on General Control/Status Register                            */
-/****************************************************************************/
-
-#define AGCSTS_CONTROL_MASK	0xfffff000
-#define  AGCSTS_NV_ACC_MASK	0xe0000000
-#define  AGCSTS_RESET_MASK	0x0e000000
-#define  AGCSTS_NV_DA_MASK	0x00ff0000
-#define  AGCSTS_BIST_MASK	0x0000f000
-#define AGCSTS_STATUS_MASK	0x000000ff
-#define  AGCSTS_TCZERO_MASK	0x000000c0
-#define  AGCSTS_FIFO_ST_MASK	0x0000003f
-
-#define AGCSTS_RESET_MBFLAGS	0x08000000
-#define AGCSTS_RESET_P2A_FIFO	0x04000000
-#define AGCSTS_RESET_A2P_FIFO	0x02000000
-#define AGCSTS_RESET_FIFOS	(AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO)
-
-#define AGCSTS_A2P_TCOUNT	0x00000080
-#define AGCSTS_P2A_TCOUNT	0x00000040
-
-#define AGCSTS_FS_P2A_EMPTY	0x00000020
-#define AGCSTS_FS_P2A_HALF	0x00000010
-#define AGCSTS_FS_P2A_FULL	0x00000008
-
-#define AGCSTS_FS_A2P_EMPTY	0x00000004
-#define AGCSTS_FS_A2P_HALF	0x00000002
-#define AGCSTS_FS_A2P_FULL	0x00000001
-
-/****************************************************************************/
-/* AMCC - Add-on Interrupt Control/Status Register                            */
-/****************************************************************************/
-
-#define AINT_INT_MASK		0x00ff0000
-#define AINT_SEL_MASK		0x0000ffff
-#define  AINT_IS_ENSEL_MASK	0x00001f1f
-
-#define AINT_INT_ASSERTED	0x00800000
-#define AINT_BM_ERROR		0x00200000
-#define AINT_BIST_INT		0x00100000
-
-#define AINT_RT_COMPLETE	0x00080000
-#define AINT_WT_COMPLETE	0x00040000
-
-#define AINT_OUT_MB_INT		0x00020000
-#define AINT_IN_MB_INT		0x00010000
-
-#define AINT_READ_COMPL		0x00008000
-#define AINT_WRITE_COMPL	0x00004000
-
-#define AINT_OMB_ENABLE 	0x00001000
-#define AINT_OMB_SELECT 	0x00000c00
-#define AINT_OMB_BYTE		0x00000300
-
-#define AINT_IMB_ENABLE 	0x00000010
-#define AINT_IMB_SELECT 	0x0000000c
-#define AINT_IMB_BYTE		0x00000003
-
-/* Enable Bus Mastering */
-#define EN_A2P_TRANSFERS	0x00000400
-/* FIFO Flag Reset */
-#define RESET_A2P_FLAGS		0x04000000L
-/* FIFO Relative Priority */
-#define A2P_HI_PRIORITY		0x00000100L
-/* Identify Interrupt Sources */
-#define ANY_S593X_INT		0x00800000L
-#define READ_TC_INT		0x00080000L
-#define WRITE_TC_INT		0x00040000L
-#define IN_MB_INT		0x00020000L
-#define MASTER_ABORT_INT	0x00100000L
-#define TARGET_ABORT_INT	0x00200000L
-#define BUS_MASTER_INT		0x00200000L
-
-/****************************************************************************/
-
-struct pcilst_struct {
-	struct pcilst_struct *next;
-	int used;
-	struct pci_dev *pcidev;
-	unsigned short vendor;
-	unsigned short device;
-	unsigned int master;
-	unsigned char pci_bus;
-	unsigned char pci_slot;
-	unsigned char pci_func;
-	unsigned int io_addr[5];
-	unsigned int irq;
-};
-
-struct pcilst_struct *amcc_devices;	/*  ptr to root list of all amcc devices */
-
-/****************************************************************************/
-
-void v_pci_card_list_init(unsigned short pci_vendor, char display);
-void v_pci_card_list_cleanup(unsigned short pci_vendor);
-struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
-						       unsigned short
-						       device_id);
-int i_find_free_pci_card_by_position(unsigned short vendor_id,
-				     unsigned short device_id,
-				     unsigned short pci_bus,
-				     unsigned short pci_slot,
-				     struct pcilst_struct **card);
-struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
-						    unsigned short device_id,
-						    unsigned short pci_bus,
-						    unsigned short pci_slot);
-
-int i_pci_card_alloc(struct pcilst_struct *amcc);
-int i_pci_card_free(struct pcilst_struct *amcc);
-void v_pci_card_list_display(void);
-int i_pci_card_data(struct pcilst_struct *amcc,
-		    unsigned char *pci_bus, unsigned char *pci_slot,
-		    unsigned char *pci_func, unsigned short *io_addr,
-		    unsigned short *irq, unsigned short *master);
-
-/****************************************************************************/
-
-/* build list of amcc cards in this system */
-void v_pci_card_list_init(unsigned short pci_vendor, char display)
-{
-	struct pci_dev *pcidev;
-	struct pcilst_struct *amcc, *last;
-	int i;
-
-	amcc_devices = NULL;
-	last = NULL;
-
-	pci_for_each_dev(pcidev) {
-		if (pcidev->vendor == pci_vendor) {
-			amcc = kzalloc(sizeof(*amcc), GFP_KERNEL);
-			if (amcc == NULL)
-				continue;
-
-			amcc->pcidev = pcidev;
-			if (last) {
-				last->next = amcc;
-			} else {
-				amcc_devices = amcc;
-			}
-			last = amcc;
-
-			amcc->vendor = pcidev->vendor;
-			amcc->device = pcidev->device;
-#if 0
-			amcc->master = pcidev->master;	/*  how get this information under 2.4 kernels? */
-#endif
-			amcc->pci_bus = pcidev->bus->number;
-			amcc->pci_slot = PCI_SLOT(pcidev->devfn);
-			amcc->pci_func = PCI_FUNC(pcidev->devfn);
-			for (i = 0; i < 5; i++)
-				amcc->io_addr[i] =
-				    pcidev->resource[i].start & ~3UL;
-			amcc->irq = pcidev->irq;
-		}
-	}
-
-	if (display)
-		v_pci_card_list_display();
-}
-
-/****************************************************************************/
-/* free up list of amcc cards in this system */
-void v_pci_card_list_cleanup(unsigned short pci_vendor)
-{
-	struct pcilst_struct *amcc, *next;
-
-	for (amcc = amcc_devices; amcc; amcc = next) {
-		next = amcc->next;
-		kfree(amcc);
-	}
-
-	amcc_devices = NULL;
-}
-
-/****************************************************************************/
-/* find first unused card with this device_id */
-struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
-						       unsigned short device_id)
-{
-	struct pcilst_struct *amcc, *next;
-
-	for (amcc = amcc_devices; amcc; amcc = next) {
-		next = amcc->next;
-		if ((!amcc->used) && (amcc->device == device_id)
-		    && (amcc->vendor == vendor_id))
-			return amcc;
-
-	}
-
-	return NULL;
-}
-
-/****************************************************************************/
-/* find card on requested position */
-int i_find_free_pci_card_by_position(unsigned short vendor_id,
-				     unsigned short device_id,
-				     unsigned short pci_bus,
-				     unsigned short pci_slot,
-				     struct pcilst_struct **card)
-{
-	struct pcilst_struct *amcc, *next;
-
-	*card = NULL;
-	for (amcc = amcc_devices; amcc; amcc = next) {
-		next = amcc->next;
-		if ((amcc->vendor == vendor_id) && (amcc->device == device_id)
-		    && (amcc->pci_bus == pci_bus)
-		    && (amcc->pci_slot == pci_slot)) {
-			if (!(amcc->used)) {
-				*card = amcc;
-				return 0;	/*  ok, card is found */
-			} else {
-				printk
-				    (" - \nCard on requested position is used b:s %d:%d!\n",
-				     pci_bus, pci_slot);
-				return 2;	/*  card exist but is used */
-			}
-		}
-	}
-
-	return 1;		/*  no card found */
-}
-
-/****************************************************************************/
-/* mark card as used */
-int i_pci_card_alloc(struct pcilst_struct *amcc)
-{
-	if (!amcc)
-		return -1;
-
-	if (amcc->used)
-		return 1;
-	amcc->used = 1;
-	return 0;
-}
-
-/****************************************************************************/
-/* mark card as free */
-int i_pci_card_free(struct pcilst_struct *amcc)
-{
-	if (!amcc)
-		return -1;
-
-	if (!amcc->used)
-		return 1;
-	amcc->used = 0;
-	return 0;
-}
-
-/****************************************************************************/
-/* display list of found cards */
-void v_pci_card_list_display(void)
-{
-	struct pcilst_struct *amcc, *next;
-
-	printk("List of pci cards\n");
-	printk("bus:slot:func vendor device master io_amcc io_daq irq used\n");
-
-	for (amcc = amcc_devices; amcc; amcc = next) {
-		next = amcc->next;
-		printk
-		    ("%2d   %2d   %2d  0x%4x 0x%4x   %3s   0x%4x 0x%4x  %2d  %2d\n",
-		     amcc->pci_bus, amcc->pci_slot, amcc->pci_func,
-		     amcc->vendor, amcc->device, amcc->master ? "yes" : "no",
-		     amcc->io_addr[0], amcc->io_addr[2], amcc->irq, amcc->used);
-
-	}
-}
-
-/****************************************************************************/
-/* return all card information for driver */
-int i_pci_card_data(struct pcilst_struct *amcc,
-		    unsigned char *pci_bus, unsigned char *pci_slot,
-		    unsigned char *pci_func, unsigned short *io_addr,
-		    unsigned short *irq, unsigned short *master)
-{
-	int i;
-
-	if (!amcc)
-		return -1;
-	*pci_bus = amcc->pci_bus;
-	*pci_slot = amcc->pci_slot;
-	*pci_func = amcc->pci_func;
-	for (i = 0; i < 5; i++)
-		io_addr[i] = amcc->io_addr[i];
-	*irq = amcc->irq;
-	*master = amcc->master;
-	return 0;
-}
-
-/****************************************************************************/
-/* select and alloc card */
-struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
-						    unsigned short device_id,
-						    unsigned short pci_bus,
-						    unsigned short pci_slot)
-{
-	struct pcilst_struct *card;
-
-	if ((pci_bus < 1) & (pci_slot < 1)) {	/*  use autodetection */
-		card = ptr_find_free_pci_card_by_device(vendor_id, device_id);
-		if (card == NULL) {
-			printk(" - Unused card not found in system!\n");
-			return NULL;
-		}
-	} else {
-		switch (i_find_free_pci_card_by_position(vendor_id, device_id,
-							 pci_bus, pci_slot,
-							 &card)) {
-		case 1:
-			printk
-			    (" - Card not found on requested position b:s %d:%d!\n",
-			     pci_bus, pci_slot);
-			return NULL;
-		case 2:
-			printk
-			    (" - Card on requested position is used b:s %d:%d!\n",
-			     pci_bus, pci_slot);
-			return NULL;
-		}
-	}
-
-	if (i_pci_card_alloc(card) != 0) {
-		printk(" - Can't allocate card!\n");
-		return NULL;
-	}
-
-	return card;
-}
-
-#endif
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
index 595238f..f9a8937 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
@@ -67,7 +67,7 @@
 		return;
 
 	/*  Allocate and Initialise Timer Subdevice Structures */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 
 	s->type = COMEDI_SUBD_TIMER;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
@@ -81,7 +81,7 @@
 	s->insn_bits = i_APCI1710_InsnBitsTimer;
 
 	/*  Allocate and Initialise DIO Subdevice Structures */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags =
@@ -96,7 +96,7 @@
 	s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff;
 
 	/*  Allocate and Initialise Chrono Subdevice Structures */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 
 	s->type = COMEDI_SUBD_CHRONO;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
@@ -110,7 +110,7 @@
 	s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO;
 
 	/*  Allocate and Initialise PWM Subdevice Structures */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_PWM;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -125,7 +125,7 @@
 	s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt;
 
 	/*  Allocate and Initialise TTLIO Subdevice Structures */
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	s->type = COMEDI_SUBD_TTLIO;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -139,7 +139,7 @@
 	s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue;
 
 	/*  Allocate and Initialise TOR Subdevice Structures */
-	s = dev->subdevices + 5;
+	s = &dev->subdevices[5];
 	s->type = COMEDI_SUBD_TOR;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -154,7 +154,7 @@
 	s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue;
 
 	/*  Allocate and Initialise SSI Subdevice Structures */
-	s = dev->subdevices + 6;
+	s = &dev->subdevices[6];
 	s->type = COMEDI_SUBD_SSI;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -167,7 +167,7 @@
 	s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO;
 
 	/*  Allocate and Initialise PULSEENCODER Subdevice Structures */
-	s = dev->subdevices + 7;
+	s = &dev->subdevices[7];
 	s->type = COMEDI_SUBD_PULSEENCODER;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
@@ -181,7 +181,7 @@
 	s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder;
 
 	/*  Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */
-	s = dev->subdevices + 8;
+	s = &dev->subdevices[8];
 	s->type = COMEDI_SUBD_INCREMENTALCOUNTER;
 	s->subdev_flags =
 		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index ffe390c..f406dfb 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -479,57 +479,26 @@
 	struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;		/*  divisor1,divisor2; */
 
-	/*  step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-		cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-
-	if (cmd->convert_src != TRIG_TIMER)
-		err++;
-
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1451,7 +1420,7 @@
 	unsigned short us_TmpValue;
 	unsigned char b_DummyRead;
 
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	ui_Check = 1;
 
 	int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;	/*  get IRQ reasons */
@@ -1656,7 +1625,7 @@
 int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
 {
 	int n_chan, i;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int err = 1;
 
 	n_chan = devpriv->ui_AiNbrofChannels;
@@ -1698,7 +1667,7 @@
 void v_APCI3120_InterruptDma(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	unsigned int next_dma_buf, samplesinbuf;
 	unsigned long low_word, high_word, var;
 
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
index f9545b0..38ab499 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
@@ -57,11 +57,8 @@
   +----------------------------------------------------------------------------+
 */
 #include "hwdrv_apci3200.h"
-/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */
-#include "addi_amcc_S5920.h"
-/* #define PRINT_INFO */
 
-/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */
+/* #define PRINT_INFO */
 
 /* BEGIN JK 06.07.04: Management of sevrals boards */
 /*
@@ -90,7 +87,12 @@
 struct str_BoardInfos s_BoardInfos[100];	/*  100 will be the max number of boards to be used */
 /* END JK 06.07.04: Management of sevrals boards */
 
-/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */
+#define AMCC_OP_REG_MCSR	0x3c
+#define EEPROM_BUSY		0x80000000
+#define NVCMD_LOAD_LOW		(0x4 << 5)	/* nvRam load low command */
+#define NVCMD_LOAD_HIGH		(0x5 << 5)	/* nvRam load high command */
+#define NVCMD_BEGIN_READ	(0x7 << 5)	/* nvRam begin read command */
+#define NVCMD_BEGIN_WRITE	(0x6 << 5)	/* EEPROM begin write command */
 
 /*+----------------------------------------------------------------------------+*/
 /*| Function   Name   : int i_AddiHeaderRW_ReadEeprom                          |*/
@@ -2558,7 +2560,6 @@
 {
 
 	int err = 0;
-	int tmp;		/*  divisor1,divisor2; */
 	unsigned int ui_ConvertTime = 0;
 	unsigned int ui_ConvertTimeBase = 0;
 	unsigned int ui_DelayTime = 0;
@@ -2569,41 +2570,32 @@
 	int i_Cpt = 0;
 	double d_ConversionTimeForAllChannels = 0.0;
 	double d_SCANTimeNewUnit = 0.0;
-	/*  step 1: make sure trigger sources are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
-	/* if(i_InterruptFlag==0) */
-	if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) {
-		err++;
-		/*           printk("\nThe interrupt should be enabled\n"); */
-	}
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == 0)
+		err |= -EINVAL;
+
 	if (err) {
 		i_APCI3200_Reset(dev);
 		return 1;
 	}
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
-		err++;
-	}
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(&cmd->start_src);
+	err |= cfc_check_trigger_is_unique(&cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(&cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->start_src == TRIG_EXT) {
 		i_TriggerEdge = cmd->start_arg & 0xFFFF;
 		i_Triggermode = cmd->start_arg >> 16;
@@ -2617,21 +2609,6 @@
 		}
 	}
 
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-		cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-
-	if (cmd->convert_src != TRIG_TIMER)
-		err++;
-
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
-
 	if (err) {
 		i_APCI3200_Reset(dev);
 		return 2;
@@ -3495,7 +3472,7 @@
 int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
 {
 	unsigned int ui_StatusRegister = 0;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 
 	/* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
 	/* comedi_async *async = s->async; */
diff --git a/drivers/staging/comedi/drivers/addi_apci_all.c b/drivers/staging/comedi/drivers/addi_apci_all.c
deleted file mode 100644
index aeb1b26..0000000
--- a/drivers/staging/comedi/drivers/addi_apci_all.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#define CONFIG_APCI_035  1
-#define CONFIG_APCI_1032 1
-#define CONFIG_APCI_1500 1
-#define CONFIG_APCI_1516 1
-#define CONFIG_APCI_1564 1
-#define CONFIG_APCI_16XX 1
-#define CONFIG_APCI_1710 1
-#define CONFIG_APCI_2016 1
-#define CONFIG_APCI_2032 1
-#define CONFIG_APCI_2200 1
-#define CONFIG_APCI_3001 1
-#define CONFIG_APCI_3120 1
-#define CONFIG_APCI_3200 1
-#define CONFIG_APCI_3300 1
-#define CONFIG_APCI_3501 1
-#define CONFIG_APCI_3XXX 1
-
-#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 3bec0f6..3492ce1 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -27,14 +27,14 @@
 */
 /*
 Driver: adl_pci6208
-Description: ADLink PCI-6208A
-Devices: [ADLink] PCI-6208A (adl_pci6208)
+Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
+Devices: (ADLink) PCI-6208 [adl_pci6208]
+	 (ADLink) PCI-6216 [adl_pci6216]
 Author: nsyeow <nsyeow@pd.jaring.my>
 Updated: Fri, 30 Jan 2004 14:44:27 +0800
 Status: untested
 
-Configuration Options:
-  none
+Configuration Options: not applicable, uses PCI auto config
 
 References:
 	- ni_660x.c
@@ -45,6 +45,12 @@
 #include "../comedidev.h"
 
 /*
+ * ADLINK PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_PCI6208		0x6208
+#define PCI_DEVICE_ID_PCI6216		0x6216
+
+/*
  * PCI-6208/6216-GL register map
  */
 #define PCI6208_AO_CONTROL(x)		(0x00 + (2 * (x)))
@@ -56,7 +62,7 @@
 #define PCI6208_DIO_DI_MASK		(0xf0)
 #define PCI6208_DIO_DI_SHIFT		(4)
 
-#define PCI6208_MAX_AO_CHANNELS		8
+#define PCI6208_MAX_AO_CHANNELS		16
 
 struct pci6208_board {
 	const char *name;
@@ -66,9 +72,13 @@
 
 static const struct pci6208_board pci6208_boards[] = {
 	{
-		.name		= "pci6208a",
-		.dev_id		= 0x6208,
+		.name		= "adl_pci6208",
+		.dev_id		= PCI_DEVICE_ID_PCI6208,
 		.ao_chans	= 8,
+	}, {
+		.name		= "adl_pci6216",
+		.dev_id		= PCI_DEVICE_ID_PCI6216,
+		.ao_chans	= 16,
 	},
 };
 
@@ -115,141 +125,122 @@
 	return insn->n;
 }
 
-static int pci6208_dio_insn_bits(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn,
-				 unsigned int *data)
+static int pci6208_di_insn_bits(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	unsigned int mask = data[0] & PCI6208_DIO_DO_MASK;
+	unsigned int val;
+
+	val = inw(dev->iobase + PCI6208_DIO);
+	val = (val & PCI6208_DIO_DI_MASK) >> PCI6208_DIO_DI_SHIFT;
+
+	data[1] = val;
+
+	return insn->n;
+}
+
+static int pci6208_do_insn_bits(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
+{
+	unsigned int mask = data[0];
 	unsigned int bits = data[1];
 
 	if (mask) {
 		s->state &= ~mask;
-		s->state |= bits & mask;
+		s->state |= (bits & mask);
 
 		outw(s->state, dev->iobase + PCI6208_DIO);
 	}
 
-	s->state = inw(dev->iobase + PCI6208_DIO);
 	data[1] = s->state;
 
 	return insn->n;
 }
 
-static int pci6208_dio_insn_config(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn,
-				   unsigned int *data)
+static const void *pci6208_find_boardinfo(struct comedi_device *dev,
+					  struct pci_dev *pcidev)
 {
-	int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask = 1 << chan;
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return insn->n;
-}
-
-static struct pci_dev *pci6208_find_device(struct comedi_device *dev,
-					   struct comedi_devconfig *it)
-{
-	const struct pci6208_board *thisboard;
-	struct pci_dev *pci_dev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
+	const struct pci6208_board *boardinfo;
 	int i;
 
-	for_each_pci_dev(pci_dev) {
-		if (pci_dev->vendor != PCI_VENDOR_ID_ADLINK)
-			continue;
-		for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
-			thisboard = &pci6208_boards[i];
-			if (thisboard->dev_id != pci_dev->device)
-				continue;
-			/* was a particular bus/slot requested? */
-			if (bus || slot) {
-				/* are we on the wrong bus/slot? */
-				if (pci_dev->bus->number != bus ||
-				    PCI_SLOT(pci_dev->devfn) != slot)
-					continue;
-			}
-			dev_dbg(dev->class_dev,
-				"Found %s on bus %d, slot, %d, irq=%d\n",
-				thisboard->name,
-				pci_dev->bus->number,
-				PCI_SLOT(pci_dev->devfn),
-				pci_dev->irq);
-			dev->board_ptr = thisboard;
-			return pci_dev;
-		}
+	for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
+		boardinfo = &pci6208_boards[i];
+		if (boardinfo->dev_id == pcidev->device)
+			return boardinfo;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int pci6208_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static int pci6208_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev)
 {
-	const struct pci6208_board *thisboard;
+	const struct pci6208_board *boardinfo;
 	struct pci6208_private *devpriv;
-	struct pci_dev *pcidev;
 	struct comedi_subdevice *s;
+	unsigned int val;
 	int ret;
 
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	boardinfo = pci6208_find_boardinfo(dev, pcidev);
+	if (!boardinfo)
+		return -ENODEV;
+	dev->board_ptr = boardinfo;
+	dev->board_name = boardinfo->name;
+
 	ret = alloc_private(dev, sizeof(*devpriv));
 	if (ret < 0)
 		return ret;
 	devpriv = dev->private;
 
-	pcidev = pci6208_find_device(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-	thisboard = comedi_board(dev);
-
-	dev->board_name = thisboard->name;
-
-	ret = comedi_pci_enable(pcidev, dev->driver->driver_name);
-	if (ret) {
-		dev_err(dev->class_dev,
-			"Failed to enable PCI device and request regions\n");
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
 		return ret;
-	}
 	dev->iobase = pci_resource_start(pcidev, 2);
 
-	ret = comedi_alloc_subdevices(dev, 2);
+	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog output subdevice */
 	s->type		= COMEDI_SUBD_AO;
 	s->subdev_flags	= SDF_WRITABLE;
-	s->n_chan	= thisboard->ao_chans;
+	s->n_chan	= boardinfo->ao_chans;
 	s->maxdata	= 0xffff;
 	s->range_table	= &range_bipolar10;
 	s->insn_write	= pci6208_ao_winsn;
 	s->insn_read	= pci6208_ao_rinsn;
 
-	s = dev->subdevices + 1;
-	/* digital i/o subdevice */
-	s->type		= COMEDI_SUBD_DIO;
-	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
-	s->n_chan	= 8;
+	s = &dev->subdevices[1];
+	/* digital input subdevice */
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 4;
 	s->maxdata	= 1;
 	s->range_table	= &range_digital;
-	s->insn_bits	= pci6208_dio_insn_bits;
-	s->insn_config	= pci6208_dio_insn_config;
+	s->insn_bits	= pci6208_di_insn_bits;
 
+	s = &dev->subdevices[2];
+	/* digital output subdevice */
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 4;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= pci6208_do_insn_bits;
+
+	/*
+	 * Get the read back signals from the digital outputs
+	 * and save it as the initial state for the subdevice.
+	 */
+	val = inw(dev->iobase + PCI6208_DIO);
+	val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT;
+	s->state	= val;
 	s->io_bits	= 0x0f;
-	s->state	= inw(dev->iobase + PCI6208_DIO);
 
 	dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx\n",
 		dev->driver->driver_name, dev->board_name, dev->iobase);
@@ -264,14 +255,13 @@
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver adl_pci6208_driver = {
 	.driver_name	= "adl_pci6208",
 	.module		= THIS_MODULE,
-	.attach		= pci6208_attach,
+	.attach_pci	= pci6208_attach_pci,
 	.detach		= pci6208_detach,
 };
 
@@ -287,7 +277,8 @@
 }
 
 static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6208) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6216) },
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
deleted file mode 100644
index 7df4c96..0000000
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-    comedi/drivers/adl_pci7230.c
-
-    Hardware comedi driver fot PCI7230 Adlink card
-    Copyright (C) 2010 David Fernandez <dfcastelao@gmail.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: adl_pci7230
-Description: Driver for the Adlink PCI-7230 32 ch. isolated digital io board
-Devices: [ADLink] PCI-7230 (adl_pci7230)
-Author: David Fernandez <dfcastelao@gmail.com>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:08:14 +0100
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
-*/
-
-#include "../comedidev.h"
-#include <linux/kernel.h>
-
-#define PCI7230_DI      0x00
-#define PCI7230_DO	    0x00
-
-#define PCI_DEVICE_ID_PCI7230 0x7230
-
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
-	struct comedi_subdevice *s,
-	struct comedi_insn *insn,
-	unsigned int *data)
-{
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= (data[0] & data[1]);
-
-		outl((s->state  << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
-	}
-
-	return insn->n;
-}
-
-static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
-	struct comedi_subdevice *s,
-	struct comedi_insn *insn,
-	unsigned int *data)
-{
-	data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
-
-	return insn->n;
-}
-
-static struct pci_dev *adl_pci7230_find_pci(struct comedi_device *dev,
-	struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-		    pcidev->device != PCI_DEVICE_ID_PCI7230)
-			continue;
-		if (bus || slot) {
-			/* requested particular bus/slot */
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		return pcidev;
-	}
-	printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-		dev->minor, bus, slot);
-	return NULL;
-}
-
-static int adl_pci7230_attach(struct comedi_device *dev,
-	struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	struct pci_dev *pcidev;
-	int ret;
-
-	printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor);
-
-	dev->board_name = "pci7230";
-
-	ret = comedi_alloc_subdevices(dev, 2);
-	if (ret)
-		return ret;
-
-	pcidev = adl_pci7230_find_pci(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) {
-		printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-			dev->minor);
-		return -EIO;
-	}
-	dev->iobase = pci_resource_start(pcidev, 2);
-	printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase);
-
-	s = dev->subdevices + 0;
-	/* Isolated do */
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = adl_pci7230_do_insn_bits;
-
-	s = dev->subdevices + 1;
-	/* Isolated di */
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = adl_pci7230_di_insn_bits;
-
-	printk(KERN_DEBUG "comedi: attached\n");
-
-	return 1;
-}
-
-static void adl_pci7230_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-}
-
-static struct comedi_driver adl_pci7230_driver = {
-	.driver_name	= "adl_pci7230",
-	.module		= THIS_MODULE,
-	.attach		= adl_pci7230_attach,
-	.detach		= adl_pci7230_detach,
-};
-
-static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev,
-					   const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, &adl_pci7230_driver);
-}
-
-static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-
-static struct pci_driver adl_pci7230_pci_driver = {
-	.name		= "adl_pci7230",
-	.id_table	= adl_pci7230_pci_table,
-	.probe		= adl_pci7230_pci_probe,
-	.remove		= __devexit_p(adl_pci7230_pci_remove),
-};
-module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
deleted file mode 100644
index 19b47af..0000000
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-    comedi/drivers/adl_pci7296.c
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: adl_pci7296
-Description: Driver for the Adlink PCI-7296 96 ch. digital io board
-Devices: [ADLink] PCI-7296 (adl_pci7296)
-Author: Jon Grierson <jd@renko.co.uk>
-Updated: Mon, 14 Apr 2008 15:05:56 +0100
-Status: testing
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
-*/
-
-#include "../comedidev.h"
-#include <linux/kernel.h>
-
-#include "8255.h"
-/* #include "8253.h" */
-
-#define PORT1A 0
-#define PORT2A 4
-#define PORT3A 8
-#define PORT4A 12
-
-#define PCI_DEVICE_ID_PCI7296 0x7296
-
-static struct pci_dev *adl_pci7296_find_pci(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-		    pcidev->device != PCI_DEVICE_ID_PCI7296)
-			continue;
-		if (bus || slot) {
-			/* requested particular bus/slot */
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		return pcidev;
-	}
-	printk(KERN_ERR
-		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-	       dev->minor, bus, slot);
-	return NULL;
-}
-
-static int adl_pci7296_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *s;
-	int ret;
-
-	printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
-
-	dev->board_name = "pci7432";
-
-	ret = comedi_alloc_subdevices(dev, 4);
-	if (ret)
-		return ret;
-
-	pcidev = adl_pci7296_find_pci(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) {
-		printk(KERN_ERR
-			"comedi%d: Failed to enable PCI device and request regions\n",
-			dev->minor);
-		return -EIO;
-	}
-
-	dev->iobase = pci_resource_start(pcidev, 2);
-	printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
-
-	/*  four 8255 digital io subdevices */
-	s = dev->subdevices + 0;
-	subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase));
-
-	s = dev->subdevices + 1;
-	ret = subdev_8255_init(dev, s, NULL,
-				(unsigned long)(dev->iobase + PORT2A));
-	if (ret < 0)
-		return ret;
-
-	s = dev->subdevices + 2;
-	ret = subdev_8255_init(dev, s, NULL,
-				(unsigned long)(dev->iobase + PORT3A));
-	if (ret < 0)
-		return ret;
-
-	s = dev->subdevices + 3;
-	ret = subdev_8255_init(dev, s, NULL,
-				(unsigned long)(dev->iobase + PORT4A));
-	if (ret < 0)
-		return ret;
-
-	printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
-
-	return 0;
-}
-
-static void adl_pci7296_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-	if (dev->subdevices) {
-		subdev_8255_cleanup(dev, dev->subdevices + 0);
-		subdev_8255_cleanup(dev, dev->subdevices + 1);
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
-		subdev_8255_cleanup(dev, dev->subdevices + 3);
-	}
-}
-
-static struct comedi_driver adl_pci7296_driver = {
-	.driver_name	= "adl_pci7296",
-	.module		= THIS_MODULE,
-	.attach		= adl_pci7296_attach,
-	.detach		= adl_pci7296_detach,
-};
-
-static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev,
-					   const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, &adl_pci7296_driver);
-}
-
-static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-
-static struct pci_driver adl_pci7296_pci_driver = {
-	.name		= "adl_pci7296",
-	.id_table	= adl_pci7296_pci_table,
-	.probe		= adl_pci7296_pci_probe,
-	.remove		= __devexit_p(adl_pci7296_pci_remove),
-};
-module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
deleted file mode 100644
index 6b8d940..0000000
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-    comedi/drivers/adl_pci7432.c
-
-    Hardware comedi driver fot PCI7432 Adlink card
-    Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: adl_pci7432
-Description: Driver for the Adlink PCI-7432 64 ch. isolated digital io board
-Devices: [ADLink] PCI-7432 (adl_pci7432)
-Author: Michel Lachaine <mike@mikelachaine.ca>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:08:14 +0100
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
-*/
-
-#include "../comedidev.h"
-#include <linux/kernel.h>
-
-#define PCI7432_DI      0x00
-#define PCI7432_DO	    0x00
-
-#define PCI_DEVICE_ID_PCI7432 0x7432
-
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
-	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= (data[0] & data[1]);
-
-		printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
-		       dev->iobase + PCI7432_DO);
-		outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
-	}
-	return insn->n;
-}
-
-static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
-	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-	data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
-	printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-
-	return insn->n;
-}
-
-static struct pci_dev *adl_pci7432_find_pci(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-		    pcidev->device != PCI_DEVICE_ID_PCI7432)
-			continue;
-		if (bus || slot) {
-			/* requested particular bus/slot */
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		return pcidev;
-	}
-	printk(KERN_ERR
-		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-	       dev->minor, bus, slot);
-	return NULL;
-}
-
-static int adl_pci7432_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *s;
-	int ret;
-
-	printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
-
-	dev->board_name = "pci7432";
-
-	ret = comedi_alloc_subdevices(dev, 2);
-	if (ret)
-		return ret;
-
-	pcidev = adl_pci7432_find_pci(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) {
-		printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-			dev->minor);
-		return -EIO;
-	}
-	dev->iobase = pci_resource_start(pcidev, 2);
-	printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
-
-	s = dev->subdevices + 0;
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 32;
-	s->maxdata = 1;
-	s->len_chanlist = 32;
-	s->io_bits = 0x00000000;
-	s->range_table = &range_digital;
-	s->insn_bits = adl_pci7432_di_insn_bits;
-
-	s = dev->subdevices + 1;
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 32;
-	s->maxdata = 1;
-	s->len_chanlist = 32;
-	s->io_bits = 0xffffffff;
-	s->range_table = &range_digital;
-	s->insn_bits = adl_pci7432_do_insn_bits;
-
-	printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
-	return 0;
-}
-
-static void adl_pci7432_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-}
-
-static struct comedi_driver adl_pci7432_driver = {
-	.driver_name	= "adl_pci7432",
-	.module		= THIS_MODULE,
-	.attach		= adl_pci7432_attach,
-	.detach		= adl_pci7432_detach,
-};
-
-static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev,
-					   const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, &adl_pci7432_driver);
-}
-
-static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-
-static struct pci_driver adl_pci7432_pci_driver = {
-	.name		= "adl_pci7432",
-	.id_table	= adl_pci7432_pci_table,
-	.probe		= adl_pci7432_pci_probe,
-	.remove		= __devexit_p(adl_pci7432_pci_remove),
-};
-module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
new file mode 100644
index 0000000..599714e
--- /dev/null
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -0,0 +1,332 @@
+/*
+ * COMEDI driver for the ADLINK PCI-723x/743x series boards.
+ * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the adl_pci7230 driver written by:
+ *	David Fernandez <dfcastelao@gmail.com>
+ * and the adl_pci7432 driver written by:
+ *	Michel Lachaine <mike@mikelachaine.ca>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+Driver: adl_pci7x3x
+Description: 32/64-Channel Isolated Digital I/O Boards
+Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output
+	 (ADLink) PCI-7233 [adl_pci7233] - 32 input
+	 (ADLink) PCI-7234 [adl_pci7234] - 32 output
+	 (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output
+	 (ADLink) PCI-7433 [adl_pci7433] - 64 input
+	 (ADLink) PCI-7434 [adl_pci7434] - 64 output
+Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+Updated: Thu, 02 Aug 2012 14:27:46 -0700
+Status: untested
+
+This driver only attaches using the PCI PnP auto config support
+in the comedi core. The module parameter 'comedi_autoconfig'
+must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG
+ioctl, used by the comedi_config utility, is not supported by
+this driver.
+
+The PCI-7230, PCI-7432 and PCI-7433 boards also support external
+interrupt signals on digital input channels 0 and 1. The PCI-7233
+has dual-interrupt sources for change-of-state (COS) on any 16
+digital input channels of LSB and for COS on any 16 digital input
+lines of MSB. Interrupts are not currently supported by this
+driver.
+
+Configuration Options: not applicable
+*/
+
+#include "../comedidev.h"
+
+/*
+ * PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_PCI7230	0x7230
+#define PCI_DEVICE_ID_PCI7233	0x7233
+#define PCI_DEVICE_ID_PCI7234	0x7234
+#define PCI_DEVICE_ID_PCI7432	0x7432
+#define PCI_DEVICE_ID_PCI7433	0x7433
+#define PCI_DEVICE_ID_PCI7434	0x7434
+
+/*
+ * Register I/O map (32-bit access only)
+ */
+#define PCI7X3X_DIO_REG		0x00
+#define PCI743X_DIO_REG		0x04
+
+struct adl_pci7x3x_boardinfo {
+	const char *name;
+	unsigned short device;
+	int nsubdevs;
+	int di_nchan;
+	int do_nchan;
+};
+
+static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
+	{
+		.name		= "adl_pci7230",
+		.device		= PCI_DEVICE_ID_PCI7230,
+		.nsubdevs	= 2,
+		.di_nchan	= 16,
+		.do_nchan	= 16,
+	}, {
+		.name		= "adl_pci7233",
+		.device		= PCI_DEVICE_ID_PCI7233,
+		.nsubdevs	= 1,
+		.di_nchan	= 32,
+	}, {
+		.name		= "adl_pci7234",
+		.device		= PCI_DEVICE_ID_PCI7234,
+		.nsubdevs	= 1,
+		.do_nchan	= 32,
+	}, {
+		.name		= "adl_pci7432",
+		.device		= PCI_DEVICE_ID_PCI7432,
+		.nsubdevs	= 2,
+		.di_nchan	= 32,
+		.do_nchan	= 32,
+	}, {
+		.name		= "adl_pci7433",
+		.device		= PCI_DEVICE_ID_PCI7433,
+		.nsubdevs	= 2,
+		.di_nchan	= 64,
+	}, {
+		.name		= "adl_pci7434",
+		.device		= PCI_DEVICE_ID_PCI7434,
+		.nsubdevs	= 2,
+		.do_nchan	= 64,
+	}
+};
+
+static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	unsigned long reg = (unsigned long)s->private;
+	unsigned int mask = data[0];
+	unsigned int bits = data[1];
+
+	if (mask) {
+		s->state &= ~mask;
+		s->state |= (bits & mask);
+
+		outl(s->state, dev->iobase + reg);
+	}
+
+	/*
+	 * NOTE: The output register is not readable.
+	 * This returned state will not be correct until all the
+	 * outputs have been updated.
+	 */
+	data[1] = s->state;
+
+	return insn->n;
+}
+
+static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	unsigned long reg = (unsigned long)s->private;
+
+	data[1] = inl(dev->iobase + reg);
+
+	return insn->n;
+}
+
+static const void *adl_pci7x3x_find_boardinfo(struct comedi_device *dev,
+					      struct pci_dev *pcidev)
+{
+	const struct adl_pci7x3x_boardinfo *board;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adl_pci7x3x_boards); i++) {
+		board = &adl_pci7x3x_boards[i];
+		if (pcidev->device == board->device)
+			return board;
+	}
+	return NULL;
+}
+
+static int adl_pci7x3x_attach_pci(struct comedi_device *dev,
+				  struct pci_dev *pcidev)
+{
+	const struct adl_pci7x3x_boardinfo *board;
+	struct comedi_subdevice *s;
+	int subdev;
+	int nchan;
+	int ret;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	board = adl_pci7x3x_find_boardinfo(dev, pcidev);
+	if (!board)
+		return -ENODEV;
+	dev->board_ptr = board;
+	dev->board_name = board->name;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, 2);
+
+	/*
+	 * One or two subdevices are setup by this driver depending on
+	 * the number of digital inputs and/or outputs provided by the
+	 * board. Each subdevice has a maximum of 32 channels.
+	 *
+	 *	PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
+	 *	PCI-7233 - 1 subdevice: 0 - 32 input
+	 *	PCI-7234 - 1 subdevice: 0 - 32 output
+	 *	PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
+	 *	PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
+	 *	PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
+	 */
+	ret = comedi_alloc_subdevices(dev, board->nsubdevs);
+	if (ret)
+		return ret;
+
+	subdev = 0;
+
+	if (board->di_nchan) {
+		nchan = min(board->di_nchan, 32);
+
+		s = &dev->subdevices[subdev];
+		/* Isolated digital inputs 0 to 15/31 */
+		s->type		= COMEDI_SUBD_DI;
+		s->subdev_flags	= SDF_READABLE;
+		s->n_chan	= nchan;
+		s->maxdata	= 1;
+		s->insn_bits	= adl_pci7x3x_di_insn_bits;
+		s->range_table	= &range_digital;
+
+		s->private	= (void *)PCI7X3X_DIO_REG;
+
+		subdev++;
+
+		nchan = board->di_nchan - nchan;
+		if (nchan) {
+			s = &dev->subdevices[subdev];
+			/* Isolated digital inputs 32 to 63 */
+			s->type		= COMEDI_SUBD_DI;
+			s->subdev_flags	= SDF_READABLE;
+			s->n_chan	= nchan;
+			s->maxdata	= 1;
+			s->insn_bits	= adl_pci7x3x_di_insn_bits;
+			s->range_table	= &range_digital;
+
+			s->private	= (void *)PCI743X_DIO_REG;
+
+			subdev++;
+		}
+	}
+
+	if (board->do_nchan) {
+		nchan = min(board->do_nchan, 32);
+
+		s = &dev->subdevices[subdev];
+		/* Isolated digital outputs 0 to 15/31 */
+		s->type		= COMEDI_SUBD_DO;
+		s->subdev_flags	= SDF_WRITABLE;
+		s->n_chan	= nchan;
+		s->maxdata	= 1;
+		s->insn_bits	= adl_pci7x3x_do_insn_bits;
+		s->range_table	= &range_digital;
+
+		s->private	= (void *)PCI7X3X_DIO_REG;
+
+		subdev++;
+
+		nchan = board->do_nchan - nchan;
+		if (nchan) {
+			s = &dev->subdevices[subdev];
+			/* Isolated digital outputs 32 to 63 */
+			s->type		= COMEDI_SUBD_DO;
+			s->subdev_flags	= SDF_WRITABLE;
+			s->n_chan	= nchan;
+			s->maxdata	= 1;
+			s->insn_bits	= adl_pci7x3x_do_insn_bits;
+			s->range_table	= &range_digital;
+
+			s->private	= (void *)PCI743X_DIO_REG;
+
+			subdev++;
+		}
+	}
+
+	dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n",
+		dev->board_name, board->di_nchan, board->do_nchan);
+
+	return 0;
+}
+
+static void adl_pci7x3x_detach(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
+	}
+}
+
+static struct comedi_driver adl_pci7x3x_driver = {
+	.driver_name	= "adl_pci7x3x",
+	.module		= THIS_MODULE,
+	.attach_pci	= adl_pci7x3x_attach_pci,
+	.detach		= adl_pci7x3x_detach,
+};
+
+static int __devinit adl_pci7x3x_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &adl_pci7x3x_driver);
+}
+
+static void __devexit adl_pci7x3x_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7233) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7234) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7433) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7434) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
+
+static struct pci_driver adl_pci7x3x_pci_driver = {
+	.name		= "adl_pci7x3x",
+	.id_table	= adl_pci7x3x_pci_table,
+	.probe		= adl_pci7x3x_pci_probe,
+	.remove		= __devexit_p(adl_pci7x3x_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver);
+
+MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 247ef00a..05e06e7 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -27,11 +27,7 @@
 Status: experimental
 Updated: Mon, 14 Apr 2008 15:10:32 +0100
 
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration Options: not applicable, uses PCI auto config
 */
 
 #include "../comedidev.h"
@@ -216,61 +212,26 @@
 	return 2;
 }
 
-static struct pci_dev *adl_pci8164_find_pci(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
+static int adl_pci8164_attach_pci(struct comedi_device *dev,
+				  struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-		    pcidev->device != PCI_DEVICE_ID_PCI8164)
-			continue;
-		if (bus || slot) {
-			/* requested particular bus/slot */
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		return pcidev;
-	}
-	printk(KERN_ERR
-		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-		dev->minor, bus, slot);
-	return NULL;
-}
-
-static int adl_pci8164_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
 	struct comedi_subdevice *s;
 	int ret;
 
-	printk(KERN_INFO "comedi: attempt to attach...\n");
-	printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
+	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	dev->board_name = "pci8164";
+	dev->board_name = dev->driver->driver_name;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, 2);
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
-	pcidev = adl_pci8164_find_pci(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
-		printk(KERN_ERR "comedi%d: Failed to enable "
-		"PCI device and request regions\n", dev->minor);
-		return -EIO;
-	}
-	dev->iobase = pci_resource_start(pcidev, 2);
-	printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase);
-
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_PROC;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 4;
@@ -280,7 +241,7 @@
 	s->insn_read = adl_pci8164_insn_read_msts;
 	s->insn_write = adl_pci8164_insn_write_cmd;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_PROC;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 4;
@@ -290,7 +251,7 @@
 	s->insn_read = adl_pci8164_insn_read_ssts;
 	s->insn_write = adl_pci8164_insn_write_otp;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_PROC;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 4;
@@ -300,7 +261,7 @@
 	s->insn_read = adl_pci8164_insn_read_buf0;
 	s->insn_write = adl_pci8164_insn_write_buf0;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_PROC;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 4;
@@ -310,7 +271,8 @@
 	s->insn_read = adl_pci8164_insn_read_buf1;
 	s->insn_write = adl_pci8164_insn_write_buf1;
 
-	printk(KERN_INFO "comedi: attached\n");
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+
 	return 0;
 }
 
@@ -321,14 +283,13 @@
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver adl_pci8164_driver = {
 	.driver_name	= "adl_pci8164",
 	.module		= THIS_MODULE,
-	.attach		= adl_pci8164_attach,
+	.attach_pci	= adl_pci8164_attach_pci,
 	.detach		= adl_pci8164_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index a31dae6..a87192a 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -47,14 +47,7 @@
 The scanned channels must be consecutive and start from 0. They must
 all have the same range and aref.
 
-Configuration options:
-
-	[0] - PCI bus number (optional)
-	[1] - PCI slot number (optional)
-
-If bus/slot is not specified, the first available PCI
-device will be used.
-
+Configuration options: not applicable, uses PCI auto config
 */
 
 /*
@@ -86,29 +79,9 @@
 #define PCI9111_DRIVER_NAME	"adl_pci9111"
 #define PCI9111_HR_DEVICE_ID	0x9111
 
-/*  TODO: Add other pci9111 board id */
-
-#define PCI9111_IO_RANGE	0x0100
-
 #define PCI9111_FIFO_HALF_SIZE	512
 
-#define PCI9111_AI_CHANNEL_NBR			16
-
-#define PCI9111_AI_RESOLUTION			12
-#define PCI9111_AI_RESOLUTION_MASK		0x0FFF
-#define PCI9111_AI_RESOLUTION_2_CMP_BIT		0x0800
-
-#define PCI9111_HR_AI_RESOLUTION		16
-#define PCI9111_HR_AI_RESOLUTION_MASK		0xFFFF
-#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT	0x8000
-
 #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS	10000
-#define PCI9111_AO_CHANNEL_NBR			1
-#define	PCI9111_AO_RESOLUTION			12
-#define PCI9111_AO_RESOLUTION_MASK		0x0FFF
-#define PCI9111_DI_CHANNEL_NBR			16
-#define	PCI9111_DO_CHANNEL_NBR			16
-#define PCI9111_DO_MASK				0xFFFF
 
 #define PCI9111_RANGE_SETTING_DELAY		10
 #define PCI9111_AI_INSTANT_READ_UDELAY_US	2
@@ -116,233 +89,49 @@
 
 #define PCI9111_8254_CLOCK_PERIOD_NS		500
 
-#define PCI9111_8254_COUNTER_0			0x00
-#define PCI9111_8254_COUNTER_1			0x40
-#define PCI9111_8254_COUNTER_2			0x80
-#define PCI9111_8254_COUNTER_LATCH		0x00
-#define PCI9111_8254_READ_LOAD_LSB_ONLY		0x10
-#define PCI9111_8254_READ_LOAD_MSB_ONLY		0x20
-#define PCI9111_8254_READ_LOAD_LSB_MSB		0x30
-#define PCI9111_8254_MODE_0			0x00
-#define PCI9111_8254_MODE_1			0x02
-#define PCI9111_8254_MODE_2			0x04
-#define PCI9111_8254_MODE_3			0x06
-#define PCI9111_8254_MODE_4			0x08
-#define PCI9111_8254_MODE_5			0x0A
-#define PCI9111_8254_BINARY_COUNTER		0x00
-#define PCI9111_8254_BCD_COUNTER		0x01
-
-/* IO address map */
-
-#define PCI9111_REGISTER_AD_FIFO_VALUE			0x00 /* AD Data stored
-								in FIFO */
-#define PCI9111_REGISTER_DA_OUTPUT			0x00
-#define PCI9111_REGISTER_DIGITAL_IO			0x02
-#define PCI9111_REGISTER_EXTENDED_IO_PORTS		0x04
-#define PCI9111_REGISTER_AD_CHANNEL_CONTROL		0x06 /* Channel
-								selection */
-#define PCI9111_REGISTER_AD_CHANNEL_READBACK		0x06
-#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE		0x08
-#define PCI9111_REGISTER_RANGE_STATUS_READBACK		0x08
-#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL		0x0A
-#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK	0x0A
-#define PCI9111_REGISTER_SOFTWARE_TRIGGER		0x0E
-#define PCI9111_REGISTER_INTERRUPT_CONTROL		0x0C
-#define PCI9111_REGISTER_8254_COUNTER_0			0x40
-#define PCI9111_REGISTER_8254_COUNTER_1			0x42
-#define PCI9111_REGISTER_8254_COUNTER_2			0X44
-#define PCI9111_REGISTER_8254_CONTROL			0x46
-#define PCI9111_REGISTER_INTERRUPT_CLEAR		0x48
-
-#define PCI9111_TRIGGER_MASK				0x0F
-#define PCI9111_PTRG_OFF				(0 << 3)
-#define PCI9111_PTRG_ON					(1 << 3)
-#define PCI9111_EITS_EXTERNAL				(1 << 2)
-#define PCI9111_EITS_INTERNAL				(0 << 2)
-#define PCI9111_TPST_SOFTWARE_TRIGGER			(0 << 1)
-#define PCI9111_TPST_TIMER_PACER			(1 << 1)
-#define PCI9111_ASCAN_ON				(1 << 0)
-#define PCI9111_ASCAN_OFF				(0 << 0)
-
-#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
-#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL		(1 << 0)
-#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK		(0 << 1)
-#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG			(1 << 1)
-#define PCI9111_FFEN_SET_FIFO_ENABLE			(0 << 2)
-#define PCI9111_FFEN_SET_FIFO_DISABLE			(1 << 2)
-
-#define PCI9111_CHANNEL_MASK				0x0F
-
-#define PCI9111_RANGE_MASK				0x07
-#define PCI9111_FIFO_EMPTY_MASK				0x10
-#define PCI9111_FIFO_HALF_FULL_MASK			0x20
-#define PCI9111_FIFO_FULL_MASK				0x40
-#define PCI9111_AD_BUSY_MASK				0x80
-
-#define PCI9111_IO_BASE (dev->iobase)
-
 /*
- * Define inlined function
+ * IO address map and bit defines
  */
+#define PCI9111_AI_FIFO_REG		0x00
+#define PCI9111_AO_REG			0x00
+#define PCI9111_DIO_REG			0x02
+#define PCI9111_EDIO_REG		0x04
+#define PCI9111_AI_CHANNEL_REG		0x06
+#define PCI9111_AI_RANGE_STAT_REG	0x08
+#define PCI9111_AI_STAT_AD_BUSY		(1 << 7)
+#define PCI9111_AI_STAT_FF_FF		(1 << 6)
+#define PCI9111_AI_STAT_FF_HF		(1 << 5)
+#define PCI9111_AI_STAT_FF_EF		(1 << 4)
+#define PCI9111_AI_RANGE_MASK		(7 << 0)
+#define PCI9111_AI_TRIG_CTRL_REG	0x0a
+#define PCI9111_AI_TRIG_CTRL_TRGEVENT	(1 << 5)
+#define PCI9111_AI_TRIG_CTRL_POTRG	(1 << 4)
+#define PCI9111_AI_TRIG_CTRL_PTRG	(1 << 3)
+#define PCI9111_AI_TRIG_CTRL_ETIS	(1 << 2)
+#define PCI9111_AI_TRIG_CTRL_TPST	(1 << 1)
+#define PCI9111_AI_TRIG_CTRL_ASCAN	(1 << 0)
+#define PCI9111_INT_CTRL_REG		0x0c
+#define PCI9111_INT_CTRL_ISC2		(1 << 3)
+#define PCI9111_INT_CTRL_FFEN		(1 << 2)
+#define PCI9111_INT_CTRL_ISC1		(1 << 1)
+#define PCI9111_INT_CTRL_ISC0		(1 << 0)
+#define PCI9111_SOFT_TRIG_REG		0x0e
+#define PCI9111_8254_BASE_REG		0x40
+#define PCI9111_INT_CLR_REG		0x48
 
-#define pci9111_trigger_and_autoscan_get() \
-	(inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
-
-#define pci9111_trigger_and_autoscan_set(flags) \
-	outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
-
-#define pci9111_interrupt_and_fifo_get() \
-	((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \
-		>> 4) & 0x03)
-
-#define pci9111_interrupt_and_fifo_set(flags) \
-	outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
-
-#define pci9111_interrupt_clear() \
-	outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR)
-
-#define pci9111_software_trigger() \
-	outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
-
-#define pci9111_fifo_reset() do { \
-	outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
-	outb(PCI9111_FFEN_SET_FIFO_DISABLE, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
-	outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
-	} while (0)
-
-#define pci9111_is_fifo_full() \
-	((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
-		PCI9111_FIFO_FULL_MASK) == 0)
-
-#define pci9111_is_fifo_half_full() \
-	((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
-		PCI9111_FIFO_HALF_FULL_MASK) == 0)
-
-#define pci9111_is_fifo_empty() \
-	((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
-		PCI9111_FIFO_EMPTY_MASK) == 0)
-
-#define pci9111_ai_channel_set(channel) \
-	outb((channel)&PCI9111_CHANNEL_MASK, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
-
-#define pci9111_ai_channel_get() \
-	(inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK) \
-		&PCI9111_CHANNEL_MASK)
-
-#define pci9111_ai_range_set(range) \
-	outb((range)&PCI9111_RANGE_MASK, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
-
-#define pci9111_ai_range_get() \
-	(inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK) \
-		&PCI9111_RANGE_MASK)
-
-#define pci9111_ai_get_data() \
-	(((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \
-		&PCI9111_AI_RESOLUTION_MASK) \
-			^ PCI9111_AI_RESOLUTION_2_CMP_BIT)
-
-#define pci9111_hr_ai_get_data() \
-	((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) \
-		&PCI9111_HR_AI_RESOLUTION_MASK) \
-			^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT)
-
-#define pci9111_ao_set_data(data) \
-	outw(data&PCI9111_AO_RESOLUTION_MASK, \
-		PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
-
-#define pci9111_di_get_bits() \
-	inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
-
-#define pci9111_do_set_bits(bits) \
-	outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
-
-#define pci9111_8254_control_set(flags) \
-	outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)
-
-#define pci9111_8254_counter_0_set(data) \
-	do { \
-		outb(data & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
-		outb((data >> 8) & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
-	} while (0)
-
-#define pci9111_8254_counter_1_set(data) \
-	do { \
-		outb(data & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
-		outb((data >> 8) & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
-	} while (0)
-
-#define pci9111_8254_counter_2_set(data) \
-	do { \
-		outb(data & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
-		outb((data >> 8) & 0xFF, \
-			PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
-	} while (0)
-
-static const struct comedi_lrange pci9111_hr_ai_range = {
+static const struct comedi_lrange pci9111_ai_range = {
 	5,
 	{
-	 BIP_RANGE(10),
-	 BIP_RANGE(5),
-	 BIP_RANGE(2.5),
-	 BIP_RANGE(1.25),
-	 BIP_RANGE(0.625)
-	 }
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
+		BIP_RANGE(0.625)
+	}
 };
 
-/*  */
-/*  Board specification structure */
-/*  */
-
-struct pci9111_board {
-	const char *name;	/*  driver name */
-	int device_id;
-	int ai_channel_nbr;	/*  num of A/D chans */
-	int ao_channel_nbr;	/*  num of D/A chans */
-	int ai_resolution;	/*  resolution of A/D */
-	int ai_resolution_mask;
-	int ao_resolution;	/*  resolution of D/A */
-	int ao_resolution_mask;
-	const struct comedi_lrange *ai_range_list;	/*  rangelist for A/D */
-	const struct comedi_lrange *ao_range_list;	/*  rangelist for D/A */
-	unsigned int ai_acquisition_period_min_ns;
-};
-
-static const struct pci9111_board pci9111_boards[] = {
-	{
-	 .name = "pci9111_hr",
-	 .device_id = PCI9111_HR_DEVICE_ID,
-	 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
-	 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
-	 .ai_resolution = PCI9111_HR_AI_RESOLUTION,
-	 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
-	 .ao_resolution = PCI9111_AO_RESOLUTION,
-	 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
-	 .ai_range_list = &pci9111_hr_ai_range,
-	 .ao_range_list = &range_bipolar10,
-	 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
-};
-
-#define pci9111_board_nbr \
-	(sizeof(pci9111_boards)/sizeof(struct pci9111_board))
-
-/*  Private data structure */
-
 struct pci9111_private_data {
-	unsigned long io_range;	/*  PCI6503 io range */
-
-	unsigned long lcr_io_base; /* Local configuration register base
-				    * address */
-	unsigned long lcr_io_range;
+	unsigned long lcr_io_base;
 
 	int stop_counter;
 	int stop_is_none;
@@ -352,23 +141,14 @@
 	unsigned int chunk_counter;
 	unsigned int chunk_num_samples;
 
-	int ao_readback;	/*  Last written analog output data */
+	int ao_readback;
 
-	unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
-				       * pacer */
-	unsigned int timer_divisor_2;
-
-	int is_valid;		/*  Is device valid */
+	unsigned int div1;
+	unsigned int div2;
 
 	short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
 };
 
-#define dev_private	((struct pci9111_private_data *)dev->private)
-
-/*  ------------------------------------------------------------------ */
-/*  PLX9050 SECTION */
-/*  ------------------------------------------------------------------ */
-
 #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
 
 #define PLX9050_LINTI1_ENABLE		(1 << 0)
@@ -404,33 +184,19 @@
 	outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
 }
 
-/*  ------------------------------------------------------------------ */
-/*  MISCELLANEOUS SECTION */
-/*  ------------------------------------------------------------------ */
-
-/*  8254 timer */
-
 static void pci9111_timer_set(struct comedi_device *dev)
 {
-	pci9111_8254_control_set(PCI9111_8254_COUNTER_0 |
-				 PCI9111_8254_READ_LOAD_LSB_MSB |
-				 PCI9111_8254_MODE_0 |
-				 PCI9111_8254_BINARY_COUNTER);
+	struct pci9111_private_data *dev_private = dev->private;
+	unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
 
-	pci9111_8254_control_set(PCI9111_8254_COUNTER_1 |
-				 PCI9111_8254_READ_LOAD_LSB_MSB |
-				 PCI9111_8254_MODE_2 |
-				 PCI9111_8254_BINARY_COUNTER);
-
-	pci9111_8254_control_set(PCI9111_8254_COUNTER_2 |
-				 PCI9111_8254_READ_LOAD_LSB_MSB |
-				 PCI9111_8254_MODE_2 |
-				 PCI9111_8254_BINARY_COUNTER);
+	i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
+	i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
+	i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
 
 	udelay(1);
 
-	pci9111_8254_counter_2_set(dev_private->timer_divisor_2);
-	pci9111_8254_counter_1_set(dev_private->timer_divisor_1);
+	i8254_write(timer_base, 1, 2, dev_private->div2);
+	i8254_write(timer_base, 1, 1, dev_private->div1);
 }
 
 enum pci9111_trigger_sources {
@@ -444,47 +210,55 @@
 {
 	int flags;
 
-	flags = pci9111_trigger_and_autoscan_get() & 0x09;
+	/* Read the current trigger mode control bits */
+	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
+	/* Mask off the EITS and TPST bits */
+	flags &= 0x9;
 
 	switch (source) {
 	case software:
-		flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
 		break;
 
 	case timer_pacer:
-		flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
+		flags |= PCI9111_AI_TRIG_CTRL_TPST;
 		break;
 
 	case external:
-		flags |= PCI9111_EITS_EXTERNAL;
+		flags |= PCI9111_AI_TRIG_CTRL_ETIS;
 		break;
 	}
 
-	pci9111_trigger_and_autoscan_set(flags);
+	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
 }
 
 static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
 {
 	int flags;
 
-	flags = pci9111_trigger_and_autoscan_get() & 0x07;
+	/* Read the current trigger mode control bits */
+	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
+	/* Mask off the PTRG bit */
+	flags &= 0x7;
 
 	if (pretrigger)
-		flags |= PCI9111_PTRG_ON;
+		flags |= PCI9111_AI_TRIG_CTRL_PTRG;
 
-	pci9111_trigger_and_autoscan_set(flags);
+	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
 }
 
 static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
 {
 	int flags;
 
-	flags = pci9111_trigger_and_autoscan_get() & 0x0e;
+	/* Read the current trigger mode control bits */
+	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
+	/* Mask off the ASCAN bit */
+	flags &= 0xe;
 
 	if (autoscan)
-		flags |= PCI9111_ASCAN_ON;
+		flags |= PCI9111_AI_TRIG_CTRL_ASCAN;
 
-	pci9111_trigger_and_autoscan_set(flags);
+	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
 }
 
 enum pci9111_ISC0_sources {
@@ -503,30 +277,39 @@
 {
 	int flags;
 
-	flags = pci9111_interrupt_and_fifo_get() & 0x04;
+	/* Read the current interrupt control bits */
+	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
+	/* Shift the bits so they are compatible with the write register */
+	flags >>= 4;
+	/* Mask off the ISCx bits */
+	flags &= 0xc0;
 
+	/* Now set the new ISCx bits */
 	if (irq_0_source == irq_on_fifo_half_full)
-		flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
+		flags |= PCI9111_INT_CTRL_ISC0;
 
 	if (irq_1_source == irq_on_external_trigger)
-		flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
+		flags |= PCI9111_INT_CTRL_ISC1;
 
-	pci9111_interrupt_and_fifo_set(flags);
+	outb(flags, dev->iobase + PCI9111_INT_CTRL_REG);
 }
 
-/*  ------------------------------------------------------------------ */
-/*  HARDWARE TRIGGERED ANALOG INPUT SECTION */
-/*  ------------------------------------------------------------------ */
+static void pci9111_fifo_reset(struct comedi_device *dev)
+{
+	unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG;
 
-/*  Cancel analog input autoscan */
-
-#undef AI_DO_CMD_DEBUG
+	/* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
+	outb(0, int_ctrl_reg);
+	outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg);
+	outb(0, int_ctrl_reg);
+}
 
 static int pci9111_ai_cancel(struct comedi_device *dev,
 			     struct comedi_subdevice *s)
 {
-	/*  Disable interrupts */
+	struct pci9111_private_data *dev_private = dev->private;
 
+	/*  Disable interrupts */
 	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
 				  true, false);
 
@@ -534,97 +317,65 @@
 
 	pci9111_autoscan_set(dev, false);
 
-	pci9111_fifo_reset();
-
-#ifdef AI_DO_CMD_DEBUG
-	printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
-#endif
+	pci9111_fifo_reset(dev);
 
 	return 0;
 }
 
-/*  Test analog input command */
-
-#define pci9111_check_trigger_src(src, flags)	do {			\
-		tmp = src;						\
-		src &= flags;						\
-		if (!src || tmp != src)					\
-			error++;					\
-	} while (false);
-
-static int
-pci9111_ai_do_cmd_test(struct comedi_device *dev,
-		       struct comedi_subdevice *s, struct comedi_cmd *cmd)
+static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
+				  struct comedi_subdevice *s,
+				  struct comedi_cmd *cmd)
 {
+	struct pci9111_private_data *dev_private = dev->private;
 	int tmp;
 	int error = 0;
 	int range, reference;
 	int i;
-	struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
 
-	/*  Step 1 : check if trigger are trivialy valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
-	pci9111_check_trigger_src(cmd->scan_begin_src,
-				  TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
-	pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
-	pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
-	pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+	error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	error |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
+	error |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_EXT);
+	error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	error |= cfc_check_trigger_src(&cmd->stop_src,
+					TRIG_COUNT | TRIG_NONE);
 
 	if (error)
 		return 1;
 
-	/*  step 2 : make sure trigger sources are unique and mutually
-	 *  compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW)
-		error++;
+	error |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	error |= cfc_check_trigger_is_unique(cmd->convert_src);
+	error |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if ((cmd->scan_begin_src != TRIG_TIMER) &&
-	    (cmd->scan_begin_src != TRIG_FOLLOW) &&
-	    (cmd->scan_begin_src != TRIG_EXT))
-		error++;
+	/* Step 2b : and mutually compatible */
 
-	if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
-		error++;
 	if ((cmd->convert_src == TRIG_TIMER) &&
 	    !((cmd->scan_begin_src == TRIG_TIMER) ||
 	      (cmd->scan_begin_src == TRIG_FOLLOW)))
-		error++;
+		error |= -EINVAL;
 	if ((cmd->convert_src == TRIG_EXT) &&
 	    !((cmd->scan_begin_src == TRIG_EXT) ||
 	      (cmd->scan_begin_src == TRIG_FOLLOW)))
-		error++;
-
-
-	if (cmd->scan_end_src != TRIG_COUNT)
-		error++;
-	if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
-		error++;
+		error |= -EINVAL;
 
 	if (error)
 		return 2;
 
 	/*  Step 3 : make sure arguments are trivialy compatible */
 
-	if (cmd->chanlist_len < 1) {
-		cmd->chanlist_len = 1;
-		error++;
-	}
-
-	if (cmd->chanlist_len > board->ai_channel_nbr) {
-		cmd->chanlist_len = board->ai_channel_nbr;
-		error++;
-	}
-
 	if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
 		cmd->start_arg = 0;
 		error++;
 	}
 
 	if ((cmd->convert_src == TRIG_TIMER) &&
-	    (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
-		cmd->convert_arg = board->ai_acquisition_period_min_ns;
+	    (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
+		cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
 		error++;
 	}
 	if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
@@ -633,8 +384,8 @@
 	}
 
 	if ((cmd->scan_begin_src == TRIG_TIMER) &&
-	    (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
-		cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
+	    (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
+		cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
 		error++;
 	}
 	if ((cmd->scan_begin_src == TRIG_FOLLOW)
@@ -670,9 +421,9 @@
 	if (cmd->convert_src == TRIG_TIMER) {
 		tmp = cmd->convert_arg;
 		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
-					       &(dev_private->timer_divisor_1),
-					       &(dev_private->timer_divisor_2),
-					       &(cmd->convert_arg),
+					       &dev_private->div1,
+					       &dev_private->div2,
+					       &cmd->convert_arg,
 					       cmd->flags & TRIG_ROUND_MASK);
 		if (tmp != cmd->convert_arg)
 			error++;
@@ -733,14 +484,6 @@
 					error++;
 				}
 			}
-		} else {
-			if ((CR_CHAN(cmd->chanlist[0]) >
-			     (board->ai_channel_nbr - 1))
-			    || (CR_CHAN(cmd->chanlist[0]) < 0)) {
-				comedi_error(dev,
-					     "channel number is out of limits\n");
-				error++;
-			}
 		}
 	}
 
@@ -751,12 +494,11 @@
 
 }
 
-/*  Analog input command */
-
 static int pci9111_ai_do_cmd(struct comedi_device *dev,
-			     struct comedi_subdevice *subdevice)
+			     struct comedi_subdevice *s)
 {
-	struct comedi_cmd *async_cmd = &subdevice->async->cmd;
+	struct pci9111_private_data *dev_private = dev->private;
+	struct comedi_cmd *async_cmd = &s->async->cmd;
 
 	if (!dev->irq) {
 		comedi_error(dev,
@@ -768,17 +510,20 @@
 	/*  TODO: handle the case of an external multiplexer */
 
 	if (async_cmd->chanlist_len > 1) {
-		pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
+		outb(async_cmd->chanlist_len - 1,
+			dev->iobase + PCI9111_AI_CHANNEL_REG);
 		pci9111_autoscan_set(dev, true);
 	} else {
-		pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
+		outb(CR_CHAN(async_cmd->chanlist[0]),
+			dev->iobase + PCI9111_AI_CHANNEL_REG);
 		pci9111_autoscan_set(dev, false);
 	}
 
 	/*  Set gain */
 	/*  This is the same gain on every channel */
 
-	pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
+	outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
+		dev->iobase + PCI9111_AI_RANGE_STAT_REG);
 
 	/* Set counter */
 
@@ -804,21 +549,9 @@
 	dev_private->scan_delay = 0;
 	switch (async_cmd->convert_src) {
 	case TRIG_TIMER:
-		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
-					       &(dev_private->timer_divisor_1),
-					       &(dev_private->timer_divisor_2),
-					       &(async_cmd->convert_arg),
-					       async_cmd->
-					       flags & TRIG_ROUND_MASK);
-#ifdef AI_DO_CMD_DEBUG
-		printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
-		       dev_private->timer_divisor_1,
-		       dev_private->timer_divisor_2);
-#endif
-
 		pci9111_trigger_source_set(dev, software);
 		pci9111_timer_set(dev);
-		pci9111_fifo_reset();
+		pci9111_fifo_reset(dev);
 		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
 					     irq_on_timer_tick);
 		pci9111_trigger_source_set(dev, timer_pacer);
@@ -837,7 +570,7 @@
 	case TRIG_EXT:
 
 		pci9111_trigger_source_set(dev, external);
-		pci9111_fifo_reset();
+		pci9111_fifo_reset(dev);
 		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
 					     irq_on_timer_tick);
 		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
@@ -856,23 +589,6 @@
 	dev_private->chunk_num_samples =
 	    dev_private->chanlist_len * (1 + dev_private->scan_delay);
 
-#ifdef AI_DO_CMD_DEBUG
-	printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
-	printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
-	       pci9111_trigger_and_autoscan_get());
-	printk(PCI9111_DRIVER_NAME ": irq source     = %2x\n",
-	       pci9111_interrupt_and_fifo_get());
-	printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
-	printk(PCI9111_DRIVER_NAME ": stop counter   = %d\n",
-	       dev_private->stop_counter);
-	printk(PCI9111_DRIVER_NAME ": scan delay     = %d\n",
-	       dev_private->scan_delay);
-	printk(PCI9111_DRIVER_NAME ": chanlist_len   = %d\n",
-	       dev_private->chanlist_len);
-	printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
-	       dev_private->chunk_num_samples);
-#endif
-
 	return 0;
 }
 
@@ -881,34 +597,24 @@
 			     unsigned int num_bytes,
 			     unsigned int start_chan_index)
 {
-	unsigned int i, num_samples = num_bytes / sizeof(short);
 	short *array = data;
-	int resolution =
-	    ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
+	unsigned int maxdata = s->maxdata;
+	unsigned int invert = (maxdata + 1) >> 1;
+	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
+	unsigned int num_samples = num_bytes / sizeof(short);
+	unsigned int i;
 
-	for (i = 0; i < num_samples; i++) {
-		if (resolution == PCI9111_HR_AI_RESOLUTION)
-			array[i] =
-			    (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
-			    PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
-		else
-			array[i] =
-			    ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
-			    PCI9111_AI_RESOLUTION_2_CMP_BIT;
-	}
+	for (i = 0; i < num_samples; i++)
+		array[i] = ((array[i] >> shift) & maxdata) ^ invert;
 }
 
-/*  ------------------------------------------------------------------ */
-/*  INTERRUPT SECTION */
-/*  ------------------------------------------------------------------ */
-
-#undef INTERRUPT_DEBUG
-
 static irqreturn_t pci9111_interrupt(int irq, void *p_device)
 {
 	struct comedi_device *dev = p_device;
-	struct comedi_subdevice *subdevice = dev->read_subdev;
+	struct pci9111_private_data *dev_private = dev->private;
+	struct comedi_subdevice *s = dev->read_subdev;
 	struct comedi_async *async;
+	unsigned int status;
 	unsigned long irq_flags;
 	unsigned char intcsr;
 
@@ -918,7 +624,7 @@
 		return IRQ_NONE;
 	}
 
-	async = subdevice->async;
+	async = s->async;
 
 	spin_lock_irqsave(&dev->spinlock, irq_flags);
 
@@ -940,37 +646,37 @@
 	    (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
 		/*  Interrupt comes from fifo_half-full signal */
 
-		if (pci9111_is_fifo_full()) {
+		status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+
+		/* '0' means FIFO is full, data may have been lost */
+		if (!(status & PCI9111_AI_STAT_FF_FF)) {
 			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 			comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
-			pci9111_interrupt_clear();
-			pci9111_ai_cancel(dev, subdevice);
+			outb(0, dev->iobase + PCI9111_INT_CLR_REG);
+			pci9111_ai_cancel(dev, s);
 			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
-			comedi_event(dev, subdevice);
+			comedi_event(dev, s);
 
 			return IRQ_HANDLED;
 		}
 
-		if (pci9111_is_fifo_half_full()) {
+		/* '0' means FIFO is half-full */
+		if (!(status & PCI9111_AI_STAT_FF_HF)) {
 			unsigned int num_samples;
 			unsigned int bytes_written = 0;
 
-#ifdef INTERRUPT_DEBUG
-			printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
-#endif
-
 			num_samples =
 			    PCI9111_FIFO_HALF_SIZE >
 			    dev_private->stop_counter
 			    && !dev_private->
 			    stop_is_none ? dev_private->stop_counter :
 			    PCI9111_FIFO_HALF_SIZE;
-			insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE,
+			insw(dev->iobase + PCI9111_AI_FIFO_REG,
 			     dev_private->ai_bounce_buffer, num_samples);
 
 			if (dev_private->scan_delay < 1) {
 				bytes_written =
-				    cfc_write_array_to_buffer(subdevice,
+				    cfc_write_array_to_buffer(s,
 							      dev_private->
 							      ai_bounce_buffer,
 							      num_samples *
@@ -994,7 +700,7 @@
 
 						bytes_written +=
 						    cfc_write_array_to_buffer
-						    (subdevice,
+						    (s,
 						     dev_private->ai_bounce_buffer
 						     + position,
 						     to_read * sizeof(short));
@@ -1029,168 +735,135 @@
 
 	if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
 		async->events |= COMEDI_CB_EOA;
-		pci9111_ai_cancel(dev, subdevice);
+		pci9111_ai_cancel(dev, s);
 	}
 
-	/* Very important, otherwise another interrupt request will be inserted
-	 * and will cause driver hangs on processing interrupt event. */
-
-	pci9111_interrupt_clear();
+	outb(0, dev->iobase + PCI9111_INT_CLR_REG);
 
 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 
-	comedi_event(dev, subdevice);
+	comedi_event(dev, s);
 
 	return IRQ_HANDLED;
 }
 
-/*  ------------------------------------------------------------------ */
-/*  INSTANT ANALOG INPUT OUTPUT SECTION */
-/*  ------------------------------------------------------------------ */
-
-/*  analog instant input */
-
-#undef AI_INSN_DEBUG
-
 static int pci9111_ai_insn_read(struct comedi_device *dev,
-				struct comedi_subdevice *subdevice,
+				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	int resolution =
-	    ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int maxdata = s->maxdata;
+	unsigned int invert = (maxdata + 1) >> 1;
+	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
+	unsigned int status;
+	int timeout;
+	int i;
 
-	int timeout, i;
+	outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
 
-#ifdef AI_INSN_DEBUG
-	printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
-	       CR_CHAN((&insn->chanspec)[0]),
-	       CR_RANGE((&insn->chanspec)[0]), insn->n);
-#endif
+	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+	if ((status & PCI9111_AI_RANGE_MASK) != range) {
+		outb(range & PCI9111_AI_RANGE_MASK,
+			dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+	}
 
-	pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
-
-	if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0]))
-		pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
-
-	pci9111_fifo_reset();
+	pci9111_fifo_reset(dev);
 
 	for (i = 0; i < insn->n; i++) {
-		pci9111_software_trigger();
+		/* Generate a software trigger */
+		outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
 
 		timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
 
 		while (timeout--) {
-			if (!pci9111_is_fifo_empty())
+			status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+			/* '1' means FIFO is not empty */
+			if (status & PCI9111_AI_STAT_FF_EF)
 				goto conversion_done;
 		}
 
 		comedi_error(dev, "A/D read timeout");
 		data[i] = 0;
-		pci9111_fifo_reset();
+		pci9111_fifo_reset(dev);
 		return -ETIME;
 
 conversion_done:
 
-		if (resolution == PCI9111_HR_AI_RESOLUTION)
-			data[i] = pci9111_hr_ai_get_data();
-		else
-			data[i] = pci9111_ai_get_data();
+		data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
+		data[i] = ((data[i] >> shift) & maxdata) ^ invert;
 	}
 
-#ifdef AI_INSN_DEBUG
-	printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
-	       pci9111_ai_channel_get(),
-	       pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
-#endif
-
 	return i;
 }
 
-/*  Analog instant output */
-
-static int
-pci9111_ao_insn_write(struct comedi_device *dev,
-		      struct comedi_subdevice *s, struct comedi_insn *insn,
-		      unsigned int *data)
+static int pci9111_ao_insn_write(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
+	struct pci9111_private_data *dev_private = dev->private;
+	unsigned int val = 0;
 	int i;
 
 	for (i = 0; i < insn->n; i++) {
-		pci9111_ao_set_data(data[i]);
-		dev_private->ao_readback = data[i];
+		val = data[i];
+		outw(val, dev->iobase + PCI9111_AO_REG);
 	}
+	dev_private->ao_readback = val;
 
-	return i;
+	return insn->n;
 }
 
-/*  Analog output readback */
-
 static int pci9111_ao_insn_read(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
+	struct pci9111_private_data *dev_private = dev->private;
 	int i;
 
 	for (i = 0; i < insn->n; i++)
-		data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
+		data[i] = dev_private->ao_readback;
 
-	return i;
+	return insn->n;
 }
 
-/*  ------------------------------------------------------------------ */
-/*  DIGITAL INPUT OUTPUT SECTION */
-/*  ------------------------------------------------------------------ */
-
-/*  Digital inputs */
-
 static int pci9111_di_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *subdevice,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	unsigned int bits;
-
-	bits = pci9111_di_get_bits();
-	data[1] = bits;
+	data[1] = inw(dev->iobase + PCI9111_DIO_REG);
 
 	return insn->n;
 }
 
-/*  Digital outputs */
-
 static int pci9111_do_insn_bits(struct comedi_device *dev,
-				struct comedi_subdevice *subdevice,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	unsigned int bits;
+	unsigned int mask = data[0];
+	unsigned int bits = data[1];
 
-	/*  Only set bits that have been masked */
-	/*  data[0] = mask */
-	/*  data[1] = bit state */
+	if (mask) {
+		s->state &= ~mask;
+		s->state |= (bits & mask);
 
-	data[0] &= PCI9111_DO_MASK;
+		outw(s->state, dev->iobase + PCI9111_DIO_REG);
+	}
 
-	bits = subdevice->state;
-	bits &= ~data[0];
-	bits |= data[0] & data[1];
-	subdevice->state = bits;
-
-	pci9111_do_set_bits(bits);
-
-	data[1] = bits;
+	data[1] = s->state;
 
 	return insn->n;
 }
 
-/*  ------------------------------------------------------------------ */
-/*  INITIALISATION SECTION */
-/*  ------------------------------------------------------------------ */
-
-/*  Reset device */
-
 static int pci9111_reset(struct comedi_device *dev)
 {
-	/*  Set trigger source to software */
+	struct pci9111_private_data *dev_private = dev->private;
 
+	/*  Set trigger source to software */
 	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
 				  true, false);
 
@@ -1198,177 +871,90 @@
 	pci9111_pretrigger_set(dev, false);
 	pci9111_autoscan_set(dev, false);
 
-	/*  Reset 8254 chip */
-
-	dev_private->timer_divisor_1 = 0;
-	dev_private->timer_divisor_2 = 0;
-
+	/* Reset 8254 chip */
+	dev_private->div1 = 0;
+	dev_private->div2 = 0;
 	pci9111_timer_set(dev);
 
 	return 0;
 }
 
-static struct pci_dev *pci9111_find_pci(struct comedi_device *dev,
-					struct comedi_devconfig *it)
+static int pci9111_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
+	struct pci9111_private_data *dev_private;
+	struct comedi_subdevice *s;
+	int ret;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK)
-			continue;
-		for (i = 0; i < pci9111_board_nbr; i++) {
-			if (pcidev->device != pci9111_boards[i].device_id)
-				continue;
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus ||
-				    PCI_SLOT(pcidev->devfn) != slot)
-					continue;
-			}
-			dev->board_ptr = pci9111_boards + i;
-			printk(KERN_ERR
-				"comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n",
-				dev->minor, pci9111_boards[i].name,
-				pcidev->bus->number, PCI_SLOT(pcidev->devfn),
-				PCI_FUNC(pcidev->devfn), pcidev->irq);
-			return pcidev;
-		}
-	}
-	printk(KERN_ERR
-		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-		dev->minor, bus, slot);
-	return NULL;
-}
-
-static int pci9111_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *subdevice;
-	unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
-	int error;
-	const struct pci9111_board *board;
-
-	if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0)
-		return -ENOMEM;
-	/*  Probe the device to determine what device in the series it is. */
-
-	printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n",
-								dev->minor);
-
-	pcidev = pci9111_find_pci(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
-	board = (struct pci9111_board *)dev->board_ptr;
+	dev->board_name = dev->driver->driver_name;
 
-	/*  TODO: Warn about non-tested boards. */
+	ret = alloc_private(dev, sizeof(*dev_private));
+	if (ret)
+		return ret;
+	dev_private = dev->private;
 
-	/*  Read local configuration register base address
-	 *  [PCI_BASE_ADDRESS #1]. */
-
-	lcr_io_base = pci_resource_start(pcidev, 1);
-	lcr_io_range = pci_resource_len(pcidev, 1);
-
-	printk
-	    ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
-	     dev->minor, lcr_io_base, lcr_io_range);
-
-	/*  Enable PCI device and request regions */
-	if (comedi_pci_enable(pcidev, PCI9111_DRIVER_NAME) < 0) {
-		printk
-		    ("comedi%d: Failed to enable PCI device and request regions\n",
-		     dev->minor);
-		return -EIO;
-	}
-	/*  Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
-
-	io_base = pci_resource_start(pcidev, 2);
-	io_range = pci_resource_len(pcidev, 2);
-
-	printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
-	       dev->minor, io_base, io_range);
-
-	dev->iobase = io_base;
-	dev->board_name = board->name;
-	dev_private->io_range = io_range;
-	dev_private->is_valid = 0;
-	dev_private->lcr_io_base = lcr_io_base;
-	dev_private->lcr_io_range = lcr_io_range;
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
+	dev->iobase = pci_resource_start(pcidev, 2);
 
 	pci9111_reset(dev);
 
-	/*  Irq setup */
-
-	dev->irq = 0;
 	if (pcidev->irq > 0) {
+		ret = request_irq(dev->irq, pci9111_interrupt,
+				  IRQF_SHARED, dev->board_name, dev);
+		if (ret)
+			return ret;
 		dev->irq = pcidev->irq;
-
-		if (request_irq(dev->irq, pci9111_interrupt,
-				IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
-			printk(KERN_ERR
-				"comedi%d: unable to allocate irq  %u\n",
-					dev->minor, dev->irq);
-			return -EINVAL;
-		}
 	}
 
-	/*  TODO: Add external multiplexer setup (according to option[2]). */
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
-	error = comedi_alloc_subdevices(dev, 4);
-	if (error)
-		return error;
+	s = &dev->subdevices[0];
+	dev->read_subdev = s;
+	s->type		= COMEDI_SUBD_AI;
+	s->subdev_flags	= SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
+	s->n_chan	= 16;
+	s->maxdata	= 0xffff;
+	s->len_chanlist	= 16;
+	s->range_table	= &pci9111_ai_range;
+	s->cancel	= pci9111_ai_cancel;
+	s->insn_read	= pci9111_ai_insn_read;
+	s->do_cmdtest	= pci9111_ai_do_cmd_test;
+	s->do_cmd	= pci9111_ai_do_cmd;
+	s->munge	= pci9111_ai_munge;
 
-	subdevice = dev->subdevices + 0;
-	dev->read_subdev = subdevice;
+	s = &dev->subdevices[1];
+	s->type		= COMEDI_SUBD_AO;
+	s->subdev_flags	= SDF_WRITABLE | SDF_COMMON;
+	s->n_chan	= 1;
+	s->maxdata	= 0x0fff;
+	s->len_chanlist	= 1;
+	s->range_table	= &range_bipolar10;
+	s->insn_write	= pci9111_ao_insn_write;
+	s->insn_read	= pci9111_ao_insn_read;
 
-	subdevice->type = COMEDI_SUBD_AI;
-	subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
+	s = &dev->subdevices[2];
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= pci9111_di_insn_bits;
 
-	/*  TODO: Add external multiplexer data */
-	/*     if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; } */
-	/*     else { subdevice->n_chan = this_board->n_aichan; } */
+	s = &dev->subdevices[3];
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= pci9111_do_insn_bits;
 
-	subdevice->n_chan = board->ai_channel_nbr;
-	subdevice->maxdata = board->ai_resolution_mask;
-	subdevice->len_chanlist = board->ai_channel_nbr;
-	subdevice->range_table = board->ai_range_list;
-	subdevice->cancel = pci9111_ai_cancel;
-	subdevice->insn_read = pci9111_ai_insn_read;
-	subdevice->do_cmdtest = pci9111_ai_do_cmd_test;
-	subdevice->do_cmd = pci9111_ai_do_cmd;
-	subdevice->munge = pci9111_ai_munge;
-
-	subdevice = dev->subdevices + 1;
-	subdevice->type = COMEDI_SUBD_AO;
-	subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON;
-	subdevice->n_chan = board->ao_channel_nbr;
-	subdevice->maxdata = board->ao_resolution_mask;
-	subdevice->len_chanlist = board->ao_channel_nbr;
-	subdevice->range_table = board->ao_range_list;
-	subdevice->insn_write = pci9111_ao_insn_write;
-	subdevice->insn_read = pci9111_ao_insn_read;
-
-	subdevice = dev->subdevices + 2;
-	subdevice->type = COMEDI_SUBD_DI;
-	subdevice->subdev_flags = SDF_READABLE;
-	subdevice->n_chan = PCI9111_DI_CHANNEL_NBR;
-	subdevice->maxdata = 1;
-	subdevice->range_table = &range_digital;
-	subdevice->insn_bits = pci9111_di_insn_bits;
-
-	subdevice = dev->subdevices + 3;
-	subdevice->type = COMEDI_SUBD_DO;
-	subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	subdevice->n_chan = PCI9111_DO_CHANNEL_NBR;
-	subdevice->maxdata = 1;
-	subdevice->range_table = &range_digital;
-	subdevice->insn_bits = pci9111_do_insn_bits;
-
-	dev_private->is_valid = 1;
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
 	return 0;
 }
@@ -1377,23 +963,20 @@
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
-	if (dev->private != NULL) {
-		if (dev_private->is_valid)
-			pci9111_reset(dev);
-	}
+	if (dev->iobase)
+		pci9111_reset(dev);
 	if (dev->irq != 0)
 		free_irq(dev->irq, dev);
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver adl_pci9111_driver = {
 	.driver_name	= "adl_pci9111",
 	.module		= THIS_MODULE,
-	.attach		= pci9111_attach,
+	.attach_pci	= pci9111_attach_pci,
 	.detach		= pci9111_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index a1f74c2..06ff65c 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -81,18 +81,6 @@
 				 * correct channel number on every 12 bit sample
 				 */
 
-#undef PCI9118_EXTDEBUG		/*
-				 * if defined then driver prints
-				 * a lot of messages
-				 */
-
-#undef DPRINTK
-#ifdef PCI9118_EXTDEBUG
-#define DPRINTK(fmt, args...) printk(fmt, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 #define IORANGE_9118 	64	/* I hope */
 #define PCI9118_CHANLEN	255	/*
 				 * len of chanlist, some source say 256,
@@ -356,43 +344,170 @@
 	unsigned int ai_inttrig_start;	/* TRIG_INT for start */
 };
 
-#define devpriv ((struct pci9118_private *)dev->private)
-#define this_board ((struct boardtype *)dev->board_ptr)
-
-/*
-==============================================================================
-*/
-
 static int check_channel_list(struct comedi_device *dev,
 			      struct comedi_subdevice *s, int n_chan,
-			      unsigned int *chanlist, int frontadd,
-			      int backadd);
+			      unsigned int *chanlist, int frontadd, int backadd)
+{
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci9118_private *devpriv = dev->private;
+	unsigned int i, differencial = 0, bipolar = 0;
+
+	/* correct channel and range number check itself comedi/range.c */
+	if (n_chan < 1) {
+		comedi_error(dev, "range/channel list is empty!");
+		return 0;
+	}
+	if ((frontadd + n_chan + backadd) > s->len_chanlist) {
+		printk
+		    ("comedi%d: range/channel list is too long for "
+						"actual configuration (%d>%d)!",
+		     dev->minor, n_chan, s->len_chanlist - frontadd - backadd);
+		return 0;
+	}
+
+	if (CR_AREF(chanlist[0]) == AREF_DIFF)
+		differencial = 1;	/* all input must be diff */
+	if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
+		bipolar = 1;	/* all input must be bipolar */
+	if (n_chan > 1)
+		for (i = 1; i < n_chan; i++) {	/* check S.E/diff */
+			if ((CR_AREF(chanlist[i]) == AREF_DIFF) !=
+			    (differencial)) {
+				comedi_error(dev,
+					     "Differencial and single ended "
+						"inputs can't be mixtured!");
+				return 0;
+			}
+			if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) !=
+			    (bipolar)) {
+				comedi_error(dev,
+					     "Bipolar and unipolar ranges "
+							"can't be mixtured!");
+				return 0;
+			}
+			if (!devpriv->usemux && differencial &&
+			    (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) {
+				comedi_error(dev,
+					     "If AREF_DIFF is used then is "
+					"available only first 8 channels!");
+				return 0;
+			}
+		}
+
+	return 1;
+}
+
 static int setup_channel_list(struct comedi_device *dev,
 			      struct comedi_subdevice *s, int n_chan,
 			      unsigned int *chanlist, int rot, int frontadd,
-			      int backadd, int usedma, char eoshandle);
-static void start_pacer(struct comedi_device *dev, int mode,
-			unsigned int divisor1, unsigned int divisor2);
-static int pci9118_reset(struct comedi_device *dev);
-static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source);
-static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source);
-static int pci9118_ai_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  unsigned int *tim1, unsigned int *tim2,
-				  unsigned int flags, int chans,
-				  unsigned int *div1, unsigned int *div2,
-				  char usessh, unsigned int chnsshfront);
+			      int backadd, int usedma, char useeos)
+{
+	struct pci9118_private *devpriv = dev->private;
+	unsigned int i, differencial = 0, bipolar = 0;
+	unsigned int scanquad, gain, ssh = 0x00;
 
-/*
-==============================================================================
-*/
+	if (usedma == 1) {
+		rot = 8;
+		usedma = 0;
+	}
+
+	if (CR_AREF(chanlist[0]) == AREF_DIFF)
+		differencial = 1;	/* all input must be diff */
+	if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
+		bipolar = 1;	/* all input must be bipolar */
+
+	/* All is ok, so we can setup channel/range list */
+
+	if (!bipolar) {
+		devpriv->AdControlReg |= AdControl_UniP;
+							/* set unibipolar */
+	} else {
+		devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff);
+							/* enable bipolar */
+	}
+
+	if (differencial) {
+		devpriv->AdControlReg |= AdControl_Diff;
+							/* enable diff inputs */
+	} else {
+		devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff);
+						/* set single ended inputs */
+	}
+
+	outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
+								/* setup mode */
+
+	outl(2, dev->iobase + PCI9118_SCANMOD);
+					/* gods know why this sequence! */
+	outl(0, dev->iobase + PCI9118_SCANMOD);
+	outl(1, dev->iobase + PCI9118_SCANMOD);
+
+#ifdef PCI9118_PARANOIDCHECK
+	devpriv->chanlistlen = n_chan;
+	for (i = 0; i < (PCI9118_CHANLEN + 1); i++)
+		devpriv->chanlist[i] = 0x55aa;
+#endif
+
+	if (frontadd) {		/* insert channels for S&H */
+		ssh = devpriv->softsshsample;
+		for (i = 0; i < frontadd; i++) {
+						/* store range list to card */
+			scanquad = CR_CHAN(chanlist[0]);
+						/* get channel number; */
+			gain = CR_RANGE(chanlist[0]);
+						/* get gain number */
+			scanquad |= ((gain & 0x03) << 8);
+			outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
+			ssh = devpriv->softsshhold;
+		}
+	}
+
+	for (i = 0; i < n_chan; i++) {	/* store range list to card */
+		scanquad = CR_CHAN(chanlist[i]);	/* get channel number */
+#ifdef PCI9118_PARANOIDCHECK
+		devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot;
+#endif
+		gain = CR_RANGE(chanlist[i]);		/* get gain number */
+		scanquad |= ((gain & 0x03) << 8);
+		outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
+	}
+
+	if (backadd) {		/* insert channels for fit onto 32bit DMA */
+		for (i = 0; i < backadd; i++) {	/* store range list to card */
+			scanquad = CR_CHAN(chanlist[0]);
+							/* get channel number */
+			gain = CR_RANGE(chanlist[0]);	/* get gain number */
+			scanquad |= ((gain & 0x03) << 8);
+			outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
+		}
+	}
+#ifdef PCI9118_PARANOIDCHECK
+	devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma];
+						/* for 32bit operations */
+	if (useeos) {
+		for (i = 1; i < n_chan; i++) {	/* store range list to card */
+			devpriv->chanlist[(n_chan + i) ^ usedma] =
+			    (CR_CHAN(chanlist[i]) & 0xf) << rot;
+		}
+		devpriv->chanlist[(2 * n_chan) ^ usedma] =
+						devpriv->chanlist[0 ^ usedma];
+						/* for 32bit operations */
+		useeos = 2;
+	} else {
+		useeos = 1;
+	}
+#endif
+	outl(0, dev->iobase + PCI9118_SCANMOD);	/* close scan queue */
+	/* udelay(100); important delay, or first sample will be crippled */
+
+	return 1;		/* we can serve this with scan logic */
+}
+
 static int pci9118_insn_read_ai(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-
+	struct pci9118_private *devpriv = dev->private;
 	int n, timeout;
 
 	devpriv->AdControlReg = AdControl_Int & 0xff;
@@ -442,13 +557,11 @@
 
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_insn_write_ao(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci9118_private *devpriv = dev->private;
 	int n, chanreg, ch;
 
 	ch = CR_CHAN(insn->chanspec);
@@ -466,13 +579,11 @@
 	return n;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_insn_read_ao(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci9118_private *devpriv = dev->private;
 	int n, chan;
 
 	chan = CR_CHAN(insn->chanspec);
@@ -482,9 +593,6 @@
 	return n;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_insn_bits_di(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
@@ -494,9 +602,6 @@
 	return insn->n;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_insn_bits_do(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
@@ -511,11 +616,10 @@
 	return insn->n;
 }
 
-/*
-==============================================================================
-*/
 static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev)
 {
+	struct pci9118_private *devpriv = dev->private;
+
 	devpriv->AdFunctionReg =
 	    AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM;
 	outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
@@ -533,6 +637,7 @@
 					  short *dma_buffer,
 					  unsigned int num_samples)
 {
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int i = 0, j = 0;
 	unsigned int start_pos = devpriv->ai_add_front,
 	    stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan;
@@ -551,14 +656,12 @@
 	return j;
 }
 
-/*
-==============================================================================
-*/
 static int move_block_from_dma(struct comedi_device *dev,
 					struct comedi_subdevice *s,
 					short *dma_buffer,
 					unsigned int num_samples)
 {
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int num_bytes;
 
 	num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples);
@@ -574,13 +677,153 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
+static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source)
+{
+	struct pci9118_private *devpriv = dev->private;
+
+	if (source > 3)
+		return -1;				/* incorrect source */
+	devpriv->exttrg_users |= (1 << source);
+	devpriv->IntControlReg |= Int_DTrg;
+	outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
+	outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
+					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+							/* allow INT in AMCC */
+	return 0;
+}
+
+static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source)
+{
+	struct pci9118_private *devpriv = dev->private;
+
+	if (source > 3)
+		return -1;			/* incorrect source */
+	devpriv->exttrg_users &= ~(1 << source);
+	if (!devpriv->exttrg_users) {	/* shutdown ext trg intterrupts */
+		devpriv->IntControlReg &= ~Int_DTrg;
+		if (!devpriv->IntControlReg)	/* all IRQ disabled */
+			outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) &
+					(~0x00001f00),
+					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+						/* disable int in AMCC */
+		outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
+	}
+	return 0;
+}
+
+static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
+				  struct comedi_subdevice *s,
+				  unsigned int *tim1, unsigned int *tim2,
+				  unsigned int flags, int chans,
+				  unsigned int *div1, unsigned int *div2,
+				  char usessh, unsigned int chnsshfront)
+{
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci9118_private *devpriv = dev->private;
+
+	switch (mode) {
+	case 1:
+	case 4:
+		if (*tim2 < this_board->ai_ns_min)
+			*tim2 = this_board->ai_ns_min;
+		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2,
+					  tim2, flags & TRIG_ROUND_NEAREST);
+		break;
+	case 2:
+		if (*tim2 < this_board->ai_ns_min)
+			*tim2 = this_board->ai_ns_min;
+		*div1 = *tim2 / devpriv->i8254_osc_base;
+						/* convert timer (burst) */
+		if (*div1 < this_board->ai_pacer_min)
+			*div1 = this_board->ai_pacer_min;
+		*div2 = *tim1 / devpriv->i8254_osc_base;	/* scan timer */
+		*div2 = *div2 / *div1;		/* major timer is c1*c2 */
+		if (*div2 < chans)
+			*div2 = chans;
+
+		*tim2 = *div1 * devpriv->i8254_osc_base;
+							/* real convert timer */
+
+		if (usessh & (chnsshfront == 0))	/* use BSSH signal */
+			if (*div2 < (chans + 2))
+				*div2 = chans + 2;
+
+		*tim1 = *div1 * *div2 * devpriv->i8254_osc_base;
+		break;
+	}
+}
+
+static void start_pacer(struct comedi_device *dev, int mode,
+			unsigned int divisor1, unsigned int divisor2)
+{
+	outl(0x74, dev->iobase + PCI9118_CNTCTRL);
+	outl(0xb4, dev->iobase + PCI9118_CNTCTRL);
+/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */
+	udelay(1);
+
+	if ((mode == 1) || (mode == 2) || (mode == 4)) {
+		outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2);
+		outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2);
+		outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1);
+		outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1);
+	}
+}
+
+static int pci9118_ai_cancel(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	struct pci9118_private *devpriv = dev->private;
+
+	if (devpriv->usedma)
+		outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) &
+			(~EN_A2P_TRANSFERS),
+			devpriv->iobase_a + AMCC_OP_REG_MCSR);	/* stop DMA */
+	pci9118_exttrg_del(dev, EXTTRG_AI);
+	start_pacer(dev, 0, 0, 0);	/* stop 8254 counters */
+	devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
+	outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+					/*
+					 * positive triggers, no S&H, no burst,
+					 * burst stop, no post trigger,
+					 * no about trigger, trigger stop
+					 */
+	devpriv->AdControlReg = 0x00;
+	outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
+					/*
+					 * bipolar, S.E., use 8254, stop 8354,
+					 * internal trigger, soft trigger,
+					 * disable INT and DMA
+					 */
+	outl(0, dev->iobase + PCI9118_BURST);
+	outl(1, dev->iobase + PCI9118_SCANMOD);
+	outl(2, dev->iobase + PCI9118_SCANMOD);	/* reset scan queue */
+	outl(0, dev->iobase + PCI9118_DELFIFO);	/* flush FIFO */
+
+	devpriv->ai_do = 0;
+	devpriv->usedma = 0;
+
+	devpriv->ai_act_scan = 0;
+	devpriv->ai_act_dmapos = 0;
+	s->async->cur_chan = 0;
+	s->async->inttrig = NULL;
+	devpriv->ai_buf_ptr = 0;
+	devpriv->ai_neverending = 0;
+	devpriv->dma_actbuf = 0;
+
+	if (!devpriv->IntControlReg)
+		outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
+					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+							/* allow INT in AMCC */
+
+	return 0;
+}
+
 static char pci9118_decode_error_status(struct comedi_device *dev,
 					struct comedi_subdevice *s,
 					unsigned char m)
 {
+	struct pci9118_private *devpriv = dev->private;
+
 	if (m & 0x100) {
 		comedi_error(dev, "A/D FIFO Full status (Fatal Error!)");
 		devpriv->ai_maskerr &= ~0x100L;
@@ -613,6 +856,7 @@
 			     unsigned int num_bytes,
 			     unsigned int start_chan_index)
 {
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int i, num_samples = num_bytes / sizeof(short);
 	short *array = data;
 
@@ -627,15 +871,13 @@
 	}
 }
 
-/*
-==============================================================================
-*/
 static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
 					   struct comedi_subdevice *s,
 					   unsigned short int_adstat,
 					   unsigned int int_amcc,
 					   unsigned short int_daq)
 {
+	struct pci9118_private *devpriv = dev->private;
 	register short sampl;
 
 	s->async->events = 0;
@@ -680,15 +922,13 @@
 		comedi_event(dev, s);
 }
 
-/*
-==============================================================================
-*/
 static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
 				     struct comedi_subdevice *s,
 				     unsigned short int_adstat,
 				     unsigned int int_amcc,
 				     unsigned short int_daq)
 {
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int next_dma_buf, samplesinbuf, sampls, m;
 
 	if (int_amcc & MASTER_ABORT_INT) {
@@ -713,7 +953,6 @@
 
 	samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1;
 					/* number of received real samples */
-/* DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); */
 
 	if (devpriv->dma_doublebuf) {	/*
 					 * switch DMA buffers if is used
@@ -735,17 +974,12 @@
 						 * how many samples is to
 						 * end of buffer
 						 */
-/*
- * DPRINTK("samps=%d m=%d %d %d\n",
- * samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr);
- */
 		sampls = m;
 		move_block_from_dma(dev, s,
 				    devpriv->dmabuf_virt[devpriv->dma_actbuf],
 				    samplesinbuf);
 		m = m - sampls;		/* m= how many samples was transferred */
 	}
-/* DPRINTK("YYY\n"); */
 
 	if (!devpriv->ai_neverending)
 		if (devpriv->ai_act_scan >= devpriv->ai_scans) {
@@ -768,12 +1002,10 @@
 	comedi_event(dev, s);
 }
 
-/*
-==============================================================================
-*/
 static irqreturn_t interrupt_pci9118(int irq, void *d)
 {
 	struct comedi_device *dev = d;
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int int_daq = 0, int_amcc, int_adstat;
 
 	if (!dev->attached)
@@ -784,14 +1016,6 @@
 	int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
 					/* get INT register from AMCC chip */
 
-/*
- * DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x
- * MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n",
- * int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR),
- * inl(devpriv->iobase_a+AMCC_OP_REG_MWTC),
- * inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do);
- */
-
 	if ((!int_daq) && (!(int_amcc & ANY_S593X_INT)))
 		return IRQ_NONE;	/* interrupt from other source */
 
@@ -837,19 +1061,18 @@
 				}
 			}
 
-		(devpriv->int_ai_func) (dev, dev->subdevices + 0, int_adstat,
+		(devpriv->int_ai_func) (dev, &dev->subdevices[0], int_adstat,
 					int_amcc, int_daq);
 
 	}
 	return IRQ_HANDLED;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_ai_inttrig(struct comedi_device *dev,
 			      struct comedi_subdevice *s, unsigned int trignum)
 {
+	struct pci9118_private *devpriv = dev->private;
+
 	if (trignum != devpriv->ai_inttrig_start)
 		return -EINVAL;
 
@@ -868,119 +1091,64 @@
 	return 1;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_ai_cmdtest(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_cmd *cmd)
 {
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci9118_private *devpriv = dev->private;
 	int err = 0;
+	unsigned int flags;
 	int tmp;
 	unsigned int divisor1 = 0, divisor2 = 0;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src,
+					TRIG_NOW | TRIG_EXT | TRIG_INT);
 
-	tmp = cmd->scan_begin_src;
+	flags = TRIG_FOLLOW;
 	if (devpriv->master)
-		cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW;
-	else
-		cmd->scan_begin_src &= TRIG_FOLLOW;
+		flags |= TRIG_TIMER | TRIG_EXT;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
 
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
+	flags = TRIG_TIMER | TRIG_EXT;
 	if (devpriv->master)
-		cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW;
-	else
-		cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
+		flags |= TRIG_NOW;
+	err |= cfc_check_trigger_src(&cmd->convert_src, flags);
 
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE | TRIG_EXT;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src,
+					TRIG_COUNT | TRIG_NONE | TRIG_EXT);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2:
-	 * make sure trigger sources are
-	 * unique and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW &&
-	    cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_INT &&
-	    cmd->scan_begin_src != TRIG_FOLLOW) {
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
+	/* Step 2b : and mutually compatible */
 
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) {
-		cmd->convert_src = TRIG_TIMER;
-		err++;
-	}
+	if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+		err |= -EINVAL;
 
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
-	if (cmd->stop_src != TRIG_NONE &&
-	    cmd->stop_src != TRIG_COUNT &&
-	    cmd->stop_src != TRIG_INT && cmd->stop_src != TRIG_EXT) {
-		cmd->stop_src = TRIG_COUNT;
-		err++;
-	}
-
-	if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
-
-	if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
+	if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
+		err |= -EINVAL;
 
 	if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
-	    (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) {
-		cmd->convert_src = TRIG_TIMER;
-		err++;
-	}
+	    (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
+		err |= -EINVAL;
 
 	if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
-	    (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) {
-		cmd->convert_src = TRIG_TIMER;
-		err++;
-	}
+	    (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
+		err |= -EINVAL;
 
-	if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) {
-		cmd->stop_src = TRIG_COUNT;
-		err++;
-	}
+	if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -1074,11 +1242,9 @@
 
 	if (cmd->scan_begin_src == TRIG_TIMER) {
 		tmp = cmd->scan_begin_arg;
-/* printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */
 		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
 					  &divisor2, &cmd->scan_begin_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
-/* printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */
 		if (cmd->scan_begin_arg < this_board->ai_ns_min)
 			cmd->scan_begin_arg = this_board->ai_ns_min;
 		if (tmp != cmd->scan_begin_arg)
@@ -1090,7 +1256,6 @@
 		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
 					  &divisor2, &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
-/* printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */
 		if (cmd->convert_arg < this_board->ai_ns_min)
 			cmd->convert_arg = this_board->ai_ns_min;
 		if (tmp != cmd->convert_arg)
@@ -1104,7 +1269,6 @@
 					cmd->scan_begin_arg =
 					    this_board->ai_ns_min *
 					    (cmd->scan_end_arg + 2);
-/* printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */
 					err++;
 				}
 			} else {
@@ -1113,7 +1277,6 @@
 					cmd->scan_begin_arg =
 					    cmd->convert_arg *
 					    cmd->chanlist_len;
-/* printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */
 					err++;
 				}
 			}
@@ -1131,18 +1294,13 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int Compute_and_setup_dma(struct comedi_device *dev)
 {
+	struct pci9118_private *devpriv = dev->private;
 	unsigned int dmalen0, dmalen1, i;
 
-	DPRINTK("adl_pci9118 EDBG: BGN: Compute_and_setup_dma()\n");
 	dmalen0 = devpriv->dmabuf_size[0];
 	dmalen1 = devpriv->dmabuf_size[1];
-	DPRINTK("1 dmalen0=%d dmalen1=%d ai_data_len=%d\n", dmalen0, dmalen1,
-		devpriv->ai_data_len);
 	/* isn't output buff smaller that our DMA buff? */
 	if (dmalen0 > (devpriv->ai_data_len)) {
 		dmalen0 = devpriv->ai_data_len & ~3L;	/*
@@ -1154,7 +1312,6 @@
 							 * align to 32bit down
 							 */
 	}
-	DPRINTK("2 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1);
 
 	/* we want wake up every scan? */
 	if (devpriv->ai_flags & TRIG_WAKE_EOS) {
@@ -1169,11 +1326,6 @@
 		} else {
 			/* short first DMA buffer to one scan */
 			dmalen0 = devpriv->ai_n_realscanlen << 1;
-			DPRINTK
-				("21 dmalen0=%d ai_n_realscanlen=%d "
-							"useeoshandle=%d\n",
-				dmalen0, devpriv->ai_n_realscanlen,
-				devpriv->useeoshandle);
 			if (devpriv->useeoshandle)
 				dmalen0 += 2;
 			if (dmalen0 < 4) {
@@ -1197,11 +1349,6 @@
 		} else {
 			/* short second DMA buffer to one scan */
 			dmalen1 = devpriv->ai_n_realscanlen << 1;
-			DPRINTK
-			    ("22 dmalen1=%d ai_n_realscanlen=%d "
-							"useeoshandle=%d\n",
-			     dmalen1, devpriv->ai_n_realscanlen,
-			     devpriv->useeoshandle);
 			if (devpriv->useeoshandle)
 				dmalen1 -= 2;
 			if (dmalen1 < 4) {
@@ -1214,7 +1361,6 @@
 		}
 	}
 
-	DPRINTK("3 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1);
 	/* transfer without TRIG_WAKE_EOS */
 	if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) {
 		/* if it's possible then align DMA buffers to length of scan */
@@ -1241,15 +1387,9 @@
 			if (dmalen0 >
 			    ((devpriv->ai_n_realscanlen << 1) *
 			     devpriv->ai_scans)) {
-				DPRINTK
-				    ("3.0 ai_n_realscanlen=%d ai_scans=%d\n",
-				     devpriv->ai_n_realscanlen,
-				     devpriv->ai_scans);
 				dmalen0 =
 				    (devpriv->ai_n_realscanlen << 1) *
 				    devpriv->ai_scans;
-				DPRINTK("3.1 dmalen0=%d dmalen1=%d\n", dmalen0,
-					dmalen1);
 				dmalen0 &= ~3L;
 			} else {	/*
 					 * fits whole measure into
@@ -1261,21 +1401,16 @@
 					dmalen1 =
 					    (devpriv->ai_n_realscanlen << 1) *
 					    devpriv->ai_scans - dmalen0;
-				DPRINTK("3.2 dmalen0=%d dmalen1=%d\n", dmalen0,
-					dmalen1);
 				dmalen1 &= ~3L;
 			}
 		}
 	}
 
-	DPRINTK("4 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1);
-
 	/* these DMA buffer size will be used */
 	devpriv->dma_actbuf = 0;
 	devpriv->dmabuf_use_size[0] = dmalen0;
 	devpriv->dmabuf_use_size[1] = dmalen1;
 
-	DPRINTK("5 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1);
 #if 0
 	if (devpriv->ai_n_scanlen < this_board->half_fifo_size) {
 		devpriv->dmabuf_panic_size[0] =
@@ -1308,18 +1443,14 @@
 			devpriv->iobase_a + AMCC_OP_REG_INTCSR);
 						/* allow bus mastering */
 
-	DPRINTK("adl_pci9118 EDBG: END: Compute_and_setup_dma()\n");
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_ai_docmd_sampl(struct comedi_device *dev,
 				  struct comedi_subdevice *s)
 {
-	DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_sampl(%d,) [%d]\n",
-		dev->minor, devpriv->ai_do);
+	struct pci9118_private *devpriv = dev->private;
+
 	switch (devpriv->ai_do) {
 	case 1:
 		devpriv->AdControlReg |= AdControl_TmrTr;
@@ -1366,18 +1497,14 @@
 		outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
 	}
 
-	DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_docmd_sampl()\n");
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_ai_docmd_dma(struct comedi_device *dev,
 				struct comedi_subdevice *s)
 {
-	DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma(%d,) [%d,%d]\n",
-		dev->minor, devpriv->ai_do, devpriv->usedma);
+	struct pci9118_private *devpriv = dev->private;
+
 	Compute_and_setup_dma(dev);
 
 	switch (devpriv->ai_do) {
@@ -1440,20 +1567,17 @@
 		outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
 	}
 
-	DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma()\n");
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci9118_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int addchans = 0;
 	int ret = 0;
 
-	DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_cmd(%d,)\n", dev->minor);
 	devpriv->ai12_startstop = 0;
 	devpriv->ai_flags = cmd->flags;
 	devpriv->ai_n_chan = cmd->chanlist_len;
@@ -1502,10 +1626,6 @@
 		devpriv->usessh = 0;
 				/*  no */
 
-	DPRINTK("1 neverending=%d scans=%u usessh=%d ai_startstop=0x%2x\n",
-		devpriv->ai_neverending, devpriv->ai_scans, devpriv->usessh,
-		devpriv->ai12_startstop);
-
 	/*
 	 * use additional sample at end of every scan
 	 * to satisty DMA 32 bit transfer?
@@ -1586,12 +1706,6 @@
 	     devpriv->ai_add_back) * (devpriv->ai_n_scanlen /
 				      devpriv->ai_n_chan);
 
-	DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n",
-		devpriv->usedma,
-		devpriv->ai_n_realscanlen, devpriv->ai_add_front,
-		devpriv->ai_n_chan, devpriv->ai_add_back,
-		devpriv->ai_n_scanlen);
-
 	/* check and setup channel list */
 	if (!check_channel_list(dev, s, devpriv->ai_n_chan,
 				devpriv->ai_chanlist, devpriv->ai_add_front,
@@ -1688,371 +1802,13 @@
 	else
 		ret = pci9118_ai_docmd_sampl(dev, s);
 
-	DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n");
 	return ret;
 }
 
-/*
-==============================================================================
-*/
-static int check_channel_list(struct comedi_device *dev,
-			      struct comedi_subdevice *s, int n_chan,
-			      unsigned int *chanlist, int frontadd, int backadd)
-{
-	unsigned int i, differencial = 0, bipolar = 0;
-
-	/* correct channel and range number check itself comedi/range.c */
-	if (n_chan < 1) {
-		comedi_error(dev, "range/channel list is empty!");
-		return 0;
-	}
-	if ((frontadd + n_chan + backadd) > s->len_chanlist) {
-		printk
-		    ("comedi%d: range/channel list is too long for "
-						"actual configuration (%d>%d)!",
-		     dev->minor, n_chan, s->len_chanlist - frontadd - backadd);
-		return 0;
-	}
-
-	if (CR_AREF(chanlist[0]) == AREF_DIFF)
-		differencial = 1;	/* all input must be diff */
-	if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
-		bipolar = 1;	/* all input must be bipolar */
-	if (n_chan > 1)
-		for (i = 1; i < n_chan; i++) {	/* check S.E/diff */
-			if ((CR_AREF(chanlist[i]) == AREF_DIFF) !=
-			    (differencial)) {
-				comedi_error(dev,
-					     "Differencial and single ended "
-						"inputs can't be mixtured!");
-				return 0;
-			}
-			if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) !=
-			    (bipolar)) {
-				comedi_error(dev,
-					     "Bipolar and unipolar ranges "
-							"can't be mixtured!");
-				return 0;
-			}
-			if (!devpriv->usemux && differencial &&
-			    (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) {
-				comedi_error(dev,
-					     "If AREF_DIFF is used then is "
-					"available only first 8 channels!");
-				return 0;
-			}
-		}
-
-	return 1;
-}
-
-/*
-==============================================================================
-*/
-static int setup_channel_list(struct comedi_device *dev,
-			      struct comedi_subdevice *s, int n_chan,
-			      unsigned int *chanlist, int rot, int frontadd,
-			      int backadd, int usedma, char useeos)
-{
-	unsigned int i, differencial = 0, bipolar = 0;
-	unsigned int scanquad, gain, ssh = 0x00;
-
-	DPRINTK
-	    ("adl_pci9118 EDBG: BGN: setup_channel_list"
-						"(%d,.,%d,.,%d,%d,%d,%d)\n",
-	     dev->minor, n_chan, rot, frontadd, backadd, usedma);
-
-	if (usedma == 1) {
-		rot = 8;
-		usedma = 0;
-	}
-
-	if (CR_AREF(chanlist[0]) == AREF_DIFF)
-		differencial = 1;	/* all input must be diff */
-	if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
-		bipolar = 1;	/* all input must be bipolar */
-
-	/* All is ok, so we can setup channel/range list */
-
-	if (!bipolar) {
-		devpriv->AdControlReg |= AdControl_UniP;
-							/* set unibipolar */
-	} else {
-		devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff);
-							/* enable bipolar */
-	}
-
-	if (differencial) {
-		devpriv->AdControlReg |= AdControl_Diff;
-							/* enable diff inputs */
-	} else {
-		devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff);
-						/* set single ended inputs */
-	}
-
-	outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
-								/* setup mode */
-
-	outl(2, dev->iobase + PCI9118_SCANMOD);
-					/* gods know why this sequence! */
-	outl(0, dev->iobase + PCI9118_SCANMOD);
-	outl(1, dev->iobase + PCI9118_SCANMOD);
-
-#ifdef PCI9118_PARANOIDCHECK
-	devpriv->chanlistlen = n_chan;
-	for (i = 0; i < (PCI9118_CHANLEN + 1); i++)
-		devpriv->chanlist[i] = 0x55aa;
-#endif
-
-	if (frontadd) {		/* insert channels for S&H */
-		ssh = devpriv->softsshsample;
-		DPRINTK("FA: %04x: ", ssh);
-		for (i = 0; i < frontadd; i++) {
-						/* store range list to card */
-			scanquad = CR_CHAN(chanlist[0]);
-						/* get channel number; */
-			gain = CR_RANGE(chanlist[0]);
-						/* get gain number */
-			scanquad |= ((gain & 0x03) << 8);
-			outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
-			DPRINTK("%02x ", scanquad | ssh);
-			ssh = devpriv->softsshhold;
-		}
-		DPRINTK("\n ");
-	}
-
-	DPRINTK("SL: ", ssh);
-	for (i = 0; i < n_chan; i++) {	/* store range list to card */
-		scanquad = CR_CHAN(chanlist[i]);	/* get channel number */
-#ifdef PCI9118_PARANOIDCHECK
-		devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot;
-#endif
-		gain = CR_RANGE(chanlist[i]);		/* get gain number */
-		scanquad |= ((gain & 0x03) << 8);
-		outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
-		DPRINTK("%02x ", scanquad | ssh);
-	}
-	DPRINTK("\n ");
-
-	if (backadd) {		/* insert channels for fit onto 32bit DMA */
-		DPRINTK("BA: %04x: ", ssh);
-		for (i = 0; i < backadd; i++) {	/* store range list to card */
-			scanquad = CR_CHAN(chanlist[0]);
-							/* get channel number */
-			gain = CR_RANGE(chanlist[0]);	/* get gain number */
-			scanquad |= ((gain & 0x03) << 8);
-			outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
-			DPRINTK("%02x ", scanquad | ssh);
-		}
-		DPRINTK("\n ");
-	}
-#ifdef PCI9118_PARANOIDCHECK
-	devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma];
-						/* for 32bit operations */
-	if (useeos) {
-		for (i = 1; i < n_chan; i++) {	/* store range list to card */
-			devpriv->chanlist[(n_chan + i) ^ usedma] =
-			    (CR_CHAN(chanlist[i]) & 0xf) << rot;
-		}
-		devpriv->chanlist[(2 * n_chan) ^ usedma] =
-						devpriv->chanlist[0 ^ usedma];
-						/* for 32bit operations */
-		useeos = 2;
-	} else {
-		useeos = 1;
-	}
-#ifdef PCI9118_EXTDEBUG
-	DPRINTK("CHL: ");
-	for (i = 0; i <= (useeos * n_chan); i++)
-		DPRINTK("%04x ", devpriv->chanlist[i]);
-
-	DPRINTK("\n ");
-#endif
-#endif
-	outl(0, dev->iobase + PCI9118_SCANMOD);	/* close scan queue */
-	/* udelay(100); important delay, or first sample will be crippled */
-
-	DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n");
-	return 1;		/* we can serve this with scan logic */
-}
-
-/*
-==============================================================================
-  calculate 8254 divisors if they are used for dual timing
-*/
-static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  unsigned int *tim1, unsigned int *tim2,
-				  unsigned int flags, int chans,
-				  unsigned int *div1, unsigned int *div2,
-				  char usessh, unsigned int chnsshfront)
-{
-	DPRINTK
-	    ("adl_pci9118 EDBG: BGN: pci9118_calc_divisors"
-					"(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n",
-	     mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront);
-	switch (mode) {
-	case 1:
-	case 4:
-		if (*tim2 < this_board->ai_ns_min)
-			*tim2 = this_board->ai_ns_min;
-		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2,
-					  tim2, flags & TRIG_ROUND_NEAREST);
-		DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n",
-			devpriv->i8254_osc_base, *div1, *div2, *tim1);
-		break;
-	case 2:
-		if (*tim2 < this_board->ai_ns_min)
-			*tim2 = this_board->ai_ns_min;
-		DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		*div1 = *tim2 / devpriv->i8254_osc_base;
-						/* convert timer (burst) */
-		DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		if (*div1 < this_board->ai_pacer_min)
-			*div1 = this_board->ai_pacer_min;
-		DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		*div2 = *tim1 / devpriv->i8254_osc_base;	/* scan timer */
-		DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		*div2 = *div2 / *div1;		/* major timer is c1*c2 */
-		DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		if (*div2 < chans)
-			*div2 = chans;
-		DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-
-		*tim2 = *div1 * devpriv->i8254_osc_base;
-							/* real convert timer */
-
-		if (usessh & (chnsshfront == 0))	/* use BSSH signal */
-			if (*div2 < (chans + 2))
-				*div2 = chans + 2;
-
-		DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2,
-			*tim1, *tim2);
-		*tim1 = *div1 * *div2 * devpriv->i8254_osc_base;
-		DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n",
-			devpriv->i8254_osc_base, *div1, *div2, *tim1, *tim2);
-		break;
-	}
-	DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n",
-		*div1, *div2);
-}
-
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
-			unsigned int divisor1, unsigned int divisor2)
-{
-	outl(0x74, dev->iobase + PCI9118_CNTCTRL);
-	outl(0xb4, dev->iobase + PCI9118_CNTCTRL);
-/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */
-	udelay(1);
-
-	if ((mode == 1) || (mode == 2) || (mode == 4)) {
-		outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2);
-		outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2);
-		outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1);
-		outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1);
-	}
-}
-
-/*
-==============================================================================
-*/
-static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source)
-{
-	if (source > 3)
-		return -1;				/* incorrect source */
-	devpriv->exttrg_users |= (1 << source);
-	devpriv->IntControlReg |= Int_DTrg;
-	outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
-	outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
-					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
-							/* allow INT in AMCC */
-	return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source)
-{
-	if (source > 3)
-		return -1;			/* incorrect source */
-	devpriv->exttrg_users &= ~(1 << source);
-	if (!devpriv->exttrg_users) {	/* shutdown ext trg intterrupts */
-		devpriv->IntControlReg &= ~Int_DTrg;
-		if (!devpriv->IntControlReg)	/* all IRQ disabled */
-			outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) &
-					(~0x00001f00),
-					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
-						/* disable int in AMCC */
-		outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
-	}
-	return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci9118_ai_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	if (devpriv->usedma)
-		outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) &
-			(~EN_A2P_TRANSFERS),
-			devpriv->iobase_a + AMCC_OP_REG_MCSR);	/* stop DMA */
-	pci9118_exttrg_del(dev, EXTTRG_AI);
-	start_pacer(dev, 0, 0, 0);	/* stop 8254 counters */
-	devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
-	outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
-					/*
-					 * positive triggers, no S&H, no burst,
-					 * burst stop, no post trigger,
-					 * no about trigger, trigger stop
-					 */
-	devpriv->AdControlReg = 0x00;
-	outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
-					/*
-					 * bipolar, S.E., use 8254, stop 8354,
-					 * internal trigger, soft trigger,
-					 * disable INT and DMA
-					 */
-	outl(0, dev->iobase + PCI9118_BURST);
-	outl(1, dev->iobase + PCI9118_SCANMOD);
-	outl(2, dev->iobase + PCI9118_SCANMOD);	/* reset scan queue */
-	outl(0, dev->iobase + PCI9118_DELFIFO);	/* flush FIFO */
-
-	devpriv->ai_do = 0;
-	devpriv->usedma = 0;
-
-	devpriv->ai_act_scan = 0;
-	devpriv->ai_act_dmapos = 0;
-	s->async->cur_chan = 0;
-	s->async->inttrig = NULL;
-	devpriv->ai_buf_ptr = 0;
-	devpriv->ai_neverending = 0;
-	devpriv->dma_actbuf = 0;
-
-	if (!devpriv->IntControlReg)
-		outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
-					devpriv->iobase_a + AMCC_OP_REG_INTCSR);
-							/* allow INT in AMCC */
-
-	return 0;
-}
-
-/*
-==============================================================================
-*/
 static int pci9118_reset(struct comedi_device *dev)
 {
+	struct pci9118_private *devpriv = dev->private;
+
 	devpriv->IntControlReg = 0;
 	devpriv->exttrg_users = 0;
 	inl(dev->iobase + PCI9118_INTCTRL);
@@ -2112,6 +1868,7 @@
 static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
 					struct comedi_devconfig *it)
 {
+	const struct boardtype *this_board = comedi_board(dev);
 	struct pci_dev *pcidev = NULL;
 	int bus = it->options[0];
 	int slot = it->options[1];
@@ -2150,6 +1907,8 @@
 static int pci9118_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci9118_private *devpriv;
 	struct pci_dev *pcidev;
 	struct comedi_subdevice *s;
 	int ret, pages, i;
@@ -2164,11 +1923,12 @@
 	else
 		master = 1;
 
-	ret = alloc_private(dev, sizeof(struct pci9118_private));
+	ret = alloc_private(dev, sizeof(*devpriv));
 	if (ret < 0) {
 		printk(" - Allocation failed!\n");
 		return -ENOMEM;
 	}
+	devpriv = dev->private;
 
 	pcidev = pci9118_find_pci(dev, it);
 	if (!pcidev)
@@ -2273,7 +2033,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
@@ -2294,7 +2054,7 @@
 		s->munge = pci9118_ai_munge;
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 	s->n_chan = this_board->n_aochan;
@@ -2304,7 +2064,7 @@
 	s->insn_write = pci9118_insn_write_ao;
 	s->insn_read = pci9118_insn_read_ao;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
 	s->n_chan = 4;
@@ -2314,7 +2074,7 @@
 	s->io_bits = 0;		/* all bits input */
 	s->insn_bits = pci9118_insn_bits_di;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 	s->n_chan = 4;
@@ -2345,8 +2105,9 @@
 static void pci9118_detach(struct comedi_device *dev)
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	struct pci9118_private *devpriv = dev->private;
 
-	if (dev->private) {
+	if (devpriv) {
 		if (devpriv->valid)
 			pci9118_reset(dev);
 		if (dev->irq)
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 6df51c8..3a2aa56 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -133,8 +133,6 @@
 	unsigned int digital_state;
 };
 
-#define devpriv ((struct adq12b_private *)dev->private)
-
 /*
  * "instructions" read/write data in "one-shot" or "software-triggered"
  * mode.
@@ -144,6 +142,7 @@
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
 {
+	struct adq12b_private *devpriv = dev->private;
 	int n, i;
 	int range, channel;
 	unsigned char hi, lo, status;
@@ -200,6 +199,7 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct adq12b_private *devpriv = dev->private;
 	int channel;
 
 	for (channel = 0; channel < 8; channel++)
@@ -221,6 +221,7 @@
 static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct adq12b_board *board = comedi_board(dev);
+	struct adq12b_private *devpriv;
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	int unipolar, differential;
@@ -252,19 +253,18 @@
 
 	dev->board_name = board->name;
 
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct adq12b_private)) < 0)
-		return -ENOMEM;
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
 
-/* fill in devpriv structure */
 	devpriv->unipolar = unipolar;
 	devpriv->differential = differential;
 	devpriv->digital_state = 0;
-/* initialize channel and range to -1 so we make sure we always write
-   at least once to the CTREG in the instruction */
+	/*
+	 * initialize channel and range to -1 so we make sure we
+	 * always write at least once to the CTREG in the instruction
+	 */
 	devpriv->last_channel = -1;
 	devpriv->last_range = -1;
 
@@ -272,7 +272,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
 	if (differential) {
@@ -294,7 +294,7 @@
 				   the board can handle */
 	s->insn_read = adq12b_ai_rinsn;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* digital input subdevice */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -303,7 +303,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = adq12b_di_insn_bits;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital output subdevice */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -321,7 +321,6 @@
 {
 	if (dev->iobase)
 		release_region(dev->iobase, ADQ12B_SIZE);
-	kfree(devpriv);
 }
 
 static const struct adq12b_board adq12b_boards[] = {
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 6b4d0d68..def37bc 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -45,6 +45,7 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "8253.h"
 #include "amcc_s5933.h"
 
@@ -52,17 +53,6 @@
 				 * correct channel number on every 12 bit
 				 * sample */
 
-#undef PCI171X_EXTDEBUG
-
-#define DRV_NAME "adv_pci1710"
-
-#undef DPRINTK
-#ifdef PCI171X_EXTDEBUG
-#define DPRINTK(fmt, args...) printk(fmt, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe
 
 /* hardware types of the cards */
@@ -211,44 +201,101 @@
 };
 
 static const struct boardtype boardtypes[] = {
-	{"pci1710", 0x1710,
-	 IORANGE_171x, 1, TYPE_PCI171X,
-	 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
-	 &range_pci1710_3, range_codes_pci1710_3,
-	 &range_pci171x_da,
-	 10000, 2048},
-	{"pci1710hg", 0x1710,
-	 IORANGE_171x, 1, TYPE_PCI171X,
-	 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
-	 &range_pci1710hg, range_codes_pci1710hg,
-	 &range_pci171x_da,
-	 10000, 2048},
-	{"pci1711", 0x1711,
-	 IORANGE_171x, 1, TYPE_PCI171X,
-	 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
-	 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
-	 10000, 512},
-	{"pci1713", 0x1713,
-	 IORANGE_171x, 1, TYPE_PCI1713,
-	 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
-	 &range_pci1710_3, range_codes_pci1710_3, NULL,
-	 10000, 2048},
-	{"pci1720", 0x1720,
-	 IORANGE_1720, 0, TYPE_PCI1720,
-	 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
-	 NULL, NULL, &range_pci1720,
-	 0, 0},
-	{"pci1731", 0x1731,
-	 IORANGE_171x, 1, TYPE_PCI171X,
-	 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
-	 &range_pci17x1, range_codes_pci17x1, NULL,
-	 10000, 512},
-	/*  dummy entry corresponding to driver name */
-	{.name = DRV_NAME},
+	{
+		.name		= "pci1710",
+		.device_id	= 0x1710,
+		.iorange	= IORANGE_171x,
+		.have_irq	= 1,
+		.cardtype	= TYPE_PCI171X,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.n_aochan	= 2,
+		.n_dichan	= 16,
+		.n_dochan	= 16,
+		.n_counter	= 1,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci1710_3,
+		.rangecode_ai	= range_codes_pci1710_3,
+		.rangelist_ao	= &range_pci171x_da,
+		.ai_ns_min	= 10000,
+		.fifo_half_size	= 2048,
+	}, {
+		.name		= "pci1710hg",
+		.device_id	= 0x1710,
+		.iorange	= IORANGE_171x,
+		.have_irq	= 1,
+		.cardtype	= TYPE_PCI171X,
+		.n_aichan	= 16,
+		.n_aichand	= 8,
+		.n_aochan	= 2,
+		.n_dichan	= 16,
+		.n_dochan	= 16,
+		.n_counter	= 1,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci1710hg,
+		.rangecode_ai	= range_codes_pci1710hg,
+		.rangelist_ao	= &range_pci171x_da,
+		.ai_ns_min	= 10000,
+		.fifo_half_size	= 2048,
+	}, {
+		.name		= "pci1711",
+		.device_id	= 0x1711,
+		.iorange	= IORANGE_171x,
+		.have_irq	= 1,
+		.cardtype	= TYPE_PCI171X,
+		.n_aichan	= 16,
+		.n_aochan	= 2,
+		.n_dichan	= 16,
+		.n_dochan	= 16,
+		.n_counter	= 1,
+		.ai_maxdata	= 0x0fff,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci17x1,
+		.rangecode_ai	= range_codes_pci17x1,
+		.rangelist_ao	= &range_pci171x_da,
+		.ai_ns_min	= 10000,
+		.fifo_half_size	= 512,
+	}, {
+		.name		= "pci1713",
+		.device_id	= 0x1713,
+		.iorange	= IORANGE_171x,
+		.have_irq	= 1,
+		.cardtype	= TYPE_PCI1713,
+		.n_aichan	= 32,
+		.n_aichand	= 16,
+		.ai_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci1710_3,
+		.rangecode_ai	= range_codes_pci1710_3,
+		.ai_ns_min	= 10000,
+		.fifo_half_size	= 2048,
+	}, {
+		.name		= "pci1720",
+		.device_id	= 0x1720,
+		.iorange	= IORANGE_1720,
+		.cardtype	= TYPE_PCI1720,
+		.n_aochan	= 4,
+		.ao_maxdata	= 0x0fff,
+		.rangelist_ao	= &range_pci1720,
+	}, {
+		.name		= "pci1731",
+		.device_id	= 0x1731,
+		.iorange	= IORANGE_171x,
+		.have_irq	= 1,
+		.cardtype	= TYPE_PCI171X,
+		.n_aichan	= 16,
+		.n_dichan	= 16,
+		.n_dochan	= 16,
+		.ai_maxdata	= 0x0fff,
+		.rangelist_ai	= &range_pci17x1,
+		.rangecode_ai	= range_codes_pci17x1,
+		.ai_ns_min	= 10000,
+		.fifo_half_size	= 512,
+	},
 };
 
 struct pci1710_private {
-	char valid;		/*  card is usable */
 	char neverending_ai;	/*  we do unlimited AI */
 	unsigned int CntrlReg;	/*  Control register */
 	unsigned int i8254_osc_base;	/*  frequence of onboard oscilator */
@@ -278,26 +325,6 @@
 					 * internal state */
 };
 
-#define devpriv ((struct pci1710_private *)dev->private)
-#define this_board ((const struct boardtype *)dev->board_ptr)
-
-/*
-==============================================================================
-*/
-
-static int check_channel_list(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      unsigned int *chanlist, unsigned int n_chan);
-static void setup_channel_list(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       unsigned int *chanlist, unsigned int n_chan,
-			       unsigned int seglen);
-static void start_pacer(struct comedi_device *dev, int mode,
-			unsigned int divisor1, unsigned int divisor2);
-static int pci1710_reset(struct comedi_device *dev);
-static int pci171x_ai_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-
 /*  used for gain list programming */
 static const unsigned int muxonechan[] = {
 	0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
@@ -308,17 +335,113 @@
 
 /*
 ==============================================================================
+ Check if channel list from user is builded correctly
+ If it's ok, then program scan/gain logic.
+ This works for all cards.
+*/
+static int check_channel_list(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      unsigned int *chanlist, unsigned int n_chan)
+{
+	unsigned int chansegment[32];
+	unsigned int i, nowmustbechan, seglen, segpos;
+
+	/* correct channel and range number check itself comedi/range.c */
+	if (n_chan < 1) {
+		comedi_error(dev, "range/channel list is empty!");
+		return 0;
+	}
+
+	if (n_chan == 1)
+		return 1; /* seglen=1 */
+
+	chansegment[0] = chanlist[0]; /*  first channel is every time ok */
+	for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
+		if (chanlist[0] == chanlist[i])
+			break;	/*  we detected a loop, stop */
+		if ((CR_CHAN(chanlist[i]) & 1) &&
+		    (CR_AREF(chanlist[i]) == AREF_DIFF)) {
+			comedi_error(dev, "Odd channel cannot be differential input!\n");
+			return 0;
+		}
+		nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
+		if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
+			nowmustbechan = (nowmustbechan + 1) % s->n_chan;
+		if (nowmustbechan != CR_CHAN(chanlist[i])) {
+			printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+			       i, CR_CHAN(chanlist[i]), nowmustbechan,
+			       CR_CHAN(chanlist[0]));
+			return 0;
+		}
+		chansegment[i] = chanlist[i]; /* next correct channel in list */
+	}
+
+	for (i = 0, segpos = 0; i < n_chan; i++) {
+		if (chanlist[i] != chansegment[i % seglen]) {
+			printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+			       i, CR_CHAN(chansegment[i]),
+			       CR_RANGE(chansegment[i]),
+			       CR_AREF(chansegment[i]),
+			       CR_CHAN(chanlist[i % seglen]),
+			       CR_RANGE(chanlist[i % seglen]),
+			       CR_AREF(chansegment[i % seglen]));
+			return 0;
+		}
+	}
+	return seglen;
+}
+
+static void setup_channel_list(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       unsigned int *chanlist, unsigned int n_chan,
+			       unsigned int seglen)
+{
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
+	unsigned int i, range, chanprog;
+
+	devpriv->act_chanlist_len = seglen;
+	devpriv->act_chanlist_pos = 0;
+
+	for (i = 0; i < seglen; i++) {	/*  store range list to card */
+		chanprog = muxonechan[CR_CHAN(chanlist[i])];
+		outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
+		range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
+		if (CR_AREF(chanlist[i]) == AREF_DIFF)
+			range |= 0x0020;
+		outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
+#ifdef PCI171x_PARANOIDCHECK
+		devpriv->act_chanlist[i] =
+			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
+#endif
+	}
+#ifdef PCI171x_PARANOIDCHECK
+	for ( ; i < n_chan; i++) { /* store remainder of channel list */
+		devpriv->act_chanlist[i] =
+			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
+	}
+#endif
+
+	devpriv->ai_et_MuxVal =
+		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
+	/* select channel interval to scan */
+	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
+}
+
+/*
+==============================================================================
 */
 static int pci171x_insn_read_ai(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1710_private *devpriv = dev->private;
 	int n, timeout;
 #ifdef PCI171x_PARANOIDCHECK
+	const struct boardtype *this_board = comedi_board(dev);
 	unsigned int idata;
 #endif
 
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
 	devpriv->CntrlReg &= Control_CNT0;
 	devpriv->CntrlReg |= Control_SW;	/*  set software trigger */
 	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
@@ -327,32 +450,18 @@
 
 	setup_channel_list(dev, s, &insn->chanspec, 1, 1);
 
-	DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
-		inw(dev->iobase + PCI171x_STATUS),
-		dev->iobase + PCI171x_STATUS);
 	for (n = 0; n < insn->n; n++) {
 		outw(0, dev->iobase + PCI171x_SOFTTRG);	/* start conversion */
-		DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
-			inw(dev->iobase + PCI171x_STATUS));
 		/* udelay(1); */
-		DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
-			inw(dev->iobase + PCI171x_STATUS));
 		timeout = 100;
 		while (timeout--) {
 			if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
 				goto conv_finish;
-			if (!(timeout % 10))
-				DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
-					timeout,
-					inw(dev->iobase + PCI171x_STATUS));
 		}
 		comedi_error(dev, "A/D insn timeout");
 		outb(0, dev->iobase + PCI171x_CLRFIFO);
 		outb(0, dev->iobase + PCI171x_CLRINT);
 		data[n] = 0;
-		DPRINTK
-		    ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
-		     n);
 		return -ETIME;
 
 conv_finish:
@@ -373,7 +482,6 @@
 	outb(0, dev->iobase + PCI171x_CLRFIFO);
 	outb(0, dev->iobase + PCI171x_CLRINT);
 
-	DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
 	return n;
 }
 
@@ -384,6 +492,7 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1710_private *devpriv = dev->private;
 	int n, chan, range, ofs;
 
 	chan = CR_CHAN(insn->chanspec);
@@ -416,6 +525,7 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1710_private *devpriv = dev->private;
 	int n, chan;
 
 	chan = CR_CHAN(insn->chanspec);
@@ -457,6 +567,23 @@
 /*
 ==============================================================================
 */
+static void start_pacer(struct comedi_device *dev, int mode,
+			unsigned int divisor1, unsigned int divisor2)
+{
+	outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
+	outw(0x74, dev->iobase + PCI171x_CNTCTRL);
+
+	if (mode == 1) {
+		outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
+		outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
+		outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
+		outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
+	}
+}
+
+/*
+==============================================================================
+*/
 static int pci171x_insn_counter_read(struct comedi_device *dev,
 				     struct comedi_subdevice *s,
 				     struct comedi_insn *insn,
@@ -486,6 +613,7 @@
 				      struct comedi_insn *insn,
 				      unsigned int *data)
 {
+	struct pci1710_private *devpriv = dev->private;
 	uint msb, lsb, ccntrl, status;
 
 	lsb = data[0] & 0x00FF;
@@ -517,6 +645,7 @@
 {
 #ifdef unused
 	/* This doesn't work like a normal Comedi counter config */
+	struct pci1710_private *devpriv = dev->private;
 	uint ccntrl = 0;
 
 	devpriv->cnt0_write_wait = data[0] & 0x20;
@@ -552,6 +681,7 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1710_private *devpriv = dev->private;
 	int n, rangereg, chan;
 
 	chan = CR_CHAN(insn->chanspec);
@@ -575,16 +705,47 @@
 /*
 ==============================================================================
 */
+static int pci171x_ai_cancel(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
+
+	switch (this_board->cardtype) {
+	default:
+		devpriv->CntrlReg &= Control_CNT0;
+		devpriv->CntrlReg |= Control_SW;
+
+		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);	/*  reset any operations */
+		start_pacer(dev, -1, 0, 0);
+		outb(0, dev->iobase + PCI171x_CLRFIFO);
+		outb(0, dev->iobase + PCI171x_CLRINT);
+		break;
+	}
+
+	devpriv->ai_do = 0;
+	devpriv->ai_act_scan = 0;
+	s->async->cur_chan = 0;
+	devpriv->ai_buf_ptr = 0;
+	devpriv->neverending_ai = 0;
+
+	return 0;
+}
+
+/*
+==============================================================================
+*/
 static void interrupt_pci1710_every_sample(void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct pci1710_private *devpriv = dev->private;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int m;
 #ifdef PCI171x_PARANOIDCHECK
+	const struct boardtype *this_board = comedi_board(dev);
 	short sampl;
 #endif
 
-	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
 	m = inw(dev->iobase + PCI171x_STATUS);
 	if (m & Status_FE) {
 		printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
@@ -605,11 +766,9 @@
 
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
 
-	DPRINTK("FOR ");
 	for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
 #ifdef PCI171x_PARANOIDCHECK
 		sampl = inw(dev->iobase + PCI171x_AD_DATA);
-		DPRINTK("%04x:", sampl);
 		if (this_board->cardtype != TYPE_PCI1713)
 			if ((sampl & 0xf000) !=
 			    devpriv->act_chanlist[s->async->cur_chan]) {
@@ -626,8 +785,6 @@
 				comedi_event(dev, s);
 				return;
 			}
-		DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
-			s->async->cur_chan, s->async->buf_int_count);
 		comedi_buf_put(s->async, sampl & 0x0fff);
 #else
 		comedi_buf_put(s->async,
@@ -641,11 +798,6 @@
 
 		if (s->async->cur_chan == 0) {	/*  one scan done */
 			devpriv->ai_act_scan++;
-			DPRINTK
-			    ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
-			     s->async->buf_int_count, s->async->buf_int_ptr,
-			     s->async->buf_user_count, s->async->buf_user_ptr);
-			DPRINTK("adv_pci1710 EDBG: EOS2\n");
 			if ((!devpriv->neverending_ai) &&
 			    (devpriv->ai_act_scan >= devpriv->ai_scans)) {
 				/*  all data sampled */
@@ -658,7 +810,6 @@
 	}
 
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
-	DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
 
 	comedi_event(dev, s);
 }
@@ -669,12 +820,13 @@
 static int move_block_from_fifo(struct comedi_device *dev,
 				struct comedi_subdevice *s, int n, int turn)
 {
+	struct pci1710_private *devpriv = dev->private;
 	int i, j;
 #ifdef PCI171x_PARANOIDCHECK
+	const struct boardtype *this_board = comedi_board(dev);
 	int sampl;
 #endif
-	DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
-		turn);
+
 	j = s->async->cur_chan;
 	for (i = 0; i < n; i++) {
 #ifdef PCI171x_PARANOIDCHECK
@@ -705,7 +857,6 @@
 		}
 	}
 	s->async->cur_chan = j;
-	DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
 	return 0;
 }
 
@@ -715,10 +866,11 @@
 static void interrupt_pci1710_half_fifo(void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int m, samplesinbuf;
 
-	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
 	m = inw(dev->iobase + PCI171x_STATUS);
 	if (!(m & Status_FH)) {
 		printk("comedi%d: A/D FIFO not half full! (%4x)\n",
@@ -760,7 +912,6 @@
 			return;
 		}
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
-	DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
 
 	comedi_event(dev, s);
 }
@@ -771,18 +922,14 @@
 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
 {
 	struct comedi_device *dev = d;
+	struct pci1710_private *devpriv = dev->private;
 
-	DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
-		irq);
 	if (!dev->attached)	/*  is device attached? */
 		return IRQ_NONE;	/*  no, exit */
 	/*  is this interrupt from our board? */
 	if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
 		return IRQ_NONE;	/*  no, exit */
 
-	DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
-		inw(dev->iobase + PCI171x_STATUS));
-
 	if (devpriv->ai_et) {	/*  Switch from initial TRIG_EXT to TRIG_xxx. */
 		devpriv->ai_et = 0;
 		devpriv->CntrlReg &= Control_CNT0;
@@ -802,7 +949,6 @@
 	} else {
 		interrupt_pci1710_half_fifo(d);
 	}
-	DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
 	return IRQ_HANDLED;
 }
 
@@ -812,11 +958,11 @@
 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
 				     struct comedi_subdevice *s)
 {
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
 	unsigned int divisor1 = 0, divisor2 = 0;
 	unsigned int seglen;
 
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
-		mode);
 	start_pacer(dev, -1, 0, 0);	/*  stop pacer */
 
 	seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
@@ -869,10 +1015,6 @@
 		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
 					  &divisor2, &devpriv->ai_timer1,
 					  devpriv->ai_flags & TRIG_ROUND_MASK);
-		DPRINTK
-		    ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
-		     devpriv->i8254_osc_base, divisor1, divisor2,
-		     devpriv->ai_timer1);
 		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 		if (mode != 2) {
 			/*  start pacer */
@@ -888,27 +1030,9 @@
 		break;
 	}
 
-	DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
 	return 0;
 }
 
-#ifdef PCI171X_EXTDEBUG
-/*
-==============================================================================
-*/
-static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
-{
-	printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
-	       cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
-	printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
-	       cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
-	printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
-	       cmd->scan_end_src);
-	printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
-	       e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
-}
-#endif
-
 /*
 ==============================================================================
 */
@@ -916,83 +1040,33 @@
 			      struct comedi_subdevice *s,
 			      struct comedi_cmd *cmd)
 {
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
 	int err = 0;
 	int tmp;
 	unsigned int divisor1 = 0, divisor2 = 0;
 
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
-#ifdef PCI171X_EXTDEBUG
-	pci171x_cmdtest_out(-1, cmd);
-#endif
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
-
-	if (err) {
-#ifdef PCI171X_EXTDEBUG
-		pci171x_cmdtest_out(1, cmd);
-#endif
-		DPRINTK(
-		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
-		err);
+	if (err)
 		return 1;
-	}
 
-	/* step2: make sure trigger srcs are unique and mutually compatible */
+	/* step 2a: make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if (cmd->scan_begin_src != TRIG_FOLLOW) {
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
+	/* step 2b: and mutually compatible */
 
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
-
-	if (err) {
-#ifdef PCI171X_EXTDEBUG
-		pci171x_cmdtest_out(2, cmd);
-#endif
-		DPRINTK(
-		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
-		err);
+	if (err)
 		return 2;
-	}
 
 	/* step 3: make sure arguments are trivially compatible */
 
@@ -1034,15 +1108,8 @@
 		}
 	}
 
-	if (err) {
-#ifdef PCI171X_EXTDEBUG
-		pci171x_cmdtest_out(3, cmd);
-#endif
-		DPRINTK(
-		"adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
-		err);
+	if (err)
 		return 3;
-	}
 
 	/* step 4: fix up any arguments */
 
@@ -1057,12 +1124,8 @@
 			err++;
 	}
 
-	if (err) {
-		DPRINTK
-		    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
-		     err);
+	if (err)
 		return 4;
-	}
 
 	/* step 5: complain about special chanlist considerations */
 
@@ -1072,7 +1135,6 @@
 			return 5;	/*  incorrect channels list */
 	}
 
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
 	return 0;
 }
 
@@ -1081,9 +1143,9 @@
 */
 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct pci1710_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
 	devpriv->ai_n_chan = cmd->chanlist_len;
 	devpriv->ai_chanlist = cmd->chanlist;
 	devpriv->ai_flags = cmd->flags;
@@ -1115,162 +1177,12 @@
 
 /*
 ==============================================================================
- Check if channel list from user is builded correctly
- If it's ok, then program scan/gain logic.
- This works for all cards.
-*/
-static int check_channel_list(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      unsigned int *chanlist, unsigned int n_chan)
-{
-	unsigned int chansegment[32];
-	unsigned int i, nowmustbechan, seglen, segpos;
-
-	DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
-	/* correct channel and range number check itself comedi/range.c */
-	if (n_chan < 1) {
-		comedi_error(dev, "range/channel list is empty!");
-		return 0;
-	}
-
-	if (n_chan == 1)
-		return 1; /* seglen=1 */
-
-	chansegment[0] = chanlist[0]; /*  first channel is every time ok */
-	for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
-		if (chanlist[0] == chanlist[i])
-			break;	/*  we detected a loop, stop */
-		if ((CR_CHAN(chanlist[i]) & 1) &&
-		    (CR_AREF(chanlist[i]) == AREF_DIFF)) {
-			comedi_error(dev, "Odd channel cannot be differential input!\n");
-			return 0;
-		}
-		nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
-		if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
-			nowmustbechan = (nowmustbechan + 1) % s->n_chan;
-		if (nowmustbechan != CR_CHAN(chanlist[i])) {
-			printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
-			       i, CR_CHAN(chanlist[i]), nowmustbechan,
-			       CR_CHAN(chanlist[0]));
-			return 0;
-		}
-		chansegment[i] = chanlist[i]; /* next correct channel in list */
-	}
-
-	for (i = 0, segpos = 0; i < n_chan; i++) {
-		if (chanlist[i] != chansegment[i % seglen]) {
-			printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
-			       i, CR_CHAN(chansegment[i]),
-			       CR_RANGE(chansegment[i]),
-			       CR_AREF(chansegment[i]),
-			       CR_CHAN(chanlist[i % seglen]),
-			       CR_RANGE(chanlist[i % seglen]),
-			       CR_AREF(chansegment[i % seglen]));
-			return 0;
-		}
-	}
-	return seglen;
-}
-
-static void setup_channel_list(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       unsigned int *chanlist, unsigned int n_chan,
-			       unsigned int seglen)
-{
-	unsigned int i, range, chanprog;
-
-	DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
-		seglen);
-	devpriv->act_chanlist_len = seglen;
-	devpriv->act_chanlist_pos = 0;
-
-	DPRINTK("SegLen: %d\n", seglen);
-	for (i = 0; i < seglen; i++) {	/*  store range list to card */
-		chanprog = muxonechan[CR_CHAN(chanlist[i])];
-		outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
-		range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
-		if (CR_AREF(chanlist[i]) == AREF_DIFF)
-			range |= 0x0020;
-		outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
-#ifdef PCI171x_PARANOIDCHECK
-		devpriv->act_chanlist[i] =
-			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
-#endif
-		DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
-			devpriv->act_chanlist[i]);
-	}
-#ifdef PCI171x_PARANOIDCHECK
-	for ( ; i < n_chan; i++) { /* store remainder of channel list */
-		devpriv->act_chanlist[i] =
-			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
-	}
-#endif
-
-	devpriv->ai_et_MuxVal =
-		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
-	/* select channel interval to scan */
-	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
-	DPRINTK("MUX: %4x L%4x.H%4x\n",
-		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
-		CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
-}
-
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
-			unsigned int divisor1, unsigned int divisor2)
-{
-	DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
-		divisor1, divisor2);
-	outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
-	outw(0x74, dev->iobase + PCI171x_CNTCTRL);
-
-	if (mode == 1) {
-		outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
-		outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
-		outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
-		outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
-	}
-	DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
-}
-
-/*
-==============================================================================
-*/
-static int pci171x_ai_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
-
-	switch (this_board->cardtype) {
-	default:
-		devpriv->CntrlReg &= Control_CNT0;
-		devpriv->CntrlReg |= Control_SW;
-
-		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);	/*  reset any operations */
-		start_pacer(dev, -1, 0, 0);
-		outb(0, dev->iobase + PCI171x_CLRFIFO);
-		outb(0, dev->iobase + PCI171x_CLRINT);
-		break;
-	}
-
-	devpriv->ai_do = 0;
-	devpriv->ai_act_scan = 0;
-	s->async->cur_chan = 0;
-	devpriv->ai_buf_ptr = 0;
-	devpriv->neverending_ai = 0;
-
-	DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
-	return 0;
-}
-
-/*
-==============================================================================
 */
 static int pci171x_reset(struct comedi_device *dev)
 {
-	DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
+	const struct boardtype *this_board = comedi_board(dev);
+	struct pci1710_private *devpriv = dev->private;
+
 	outw(0x30, dev->iobase + PCI171x_CNTCTRL);
 	devpriv->CntrlReg = Control_SW | Control_CNT0;	/*  Software trigger, CNT0=external */
 	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);	/*  reset any operations */
@@ -1291,7 +1203,6 @@
 	outb(0, dev->iobase + PCI171x_CLRFIFO);	/*  clear FIFO */
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear INT request */
 
-	DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
 	return 0;
 }
 
@@ -1300,7 +1211,8 @@
 */
 static int pci1720_reset(struct comedi_device *dev)
 {
-	DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
+	struct pci1710_private *devpriv = dev->private;
+
 	outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);	/*  set synchronous output mode */
 	devpriv->da_ranges = 0xAA;
 	outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);	/*  set all ranges to +/-5V */
@@ -1313,7 +1225,6 @@
 	devpriv->ao_data[1] = 0x0800;
 	devpriv->ao_data[2] = 0x0800;
 	devpriv->ao_data[3] = 0x0800;
-	DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
 	return 0;
 }
 
@@ -1322,82 +1233,55 @@
 */
 static int pci1710_reset(struct comedi_device *dev)
 {
-	DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
+	const struct boardtype *this_board = comedi_board(dev);
+
 	switch (this_board->cardtype) {
 	case TYPE_PCI1720:
 		return pci1720_reset(dev);
 	default:
 		return pci171x_reset(dev);
 	}
-	DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
 }
 
-static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
+static const void *pci1710_find_boardinfo(struct comedi_device *dev,
+					  struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int board_index = this_board - boardtypes;
+	const struct boardtype *this_board;
 	int i;
 
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
-			continue;
-		if (strcmp(this_board->name, DRV_NAME) == 0) {
-			for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
-				if (pcidev->device == boardtypes[i].device_id) {
-					board_index = i;
-					break;
-				}
-			}
-			if (i == ARRAY_SIZE(boardtypes))
-				continue;
-		} else {
-			if (pcidev->device != boardtypes[board_index].device_id)
-				continue;
-		}
-		dev->board_ptr = &boardtypes[board_index];
-		return pcidev;
+	for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
+		this_board = &boardtypes[i];
+		if (pcidev->device == this_board->device_id)
+			return this_board;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int pci1710_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static int pci1710_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev;
+	const struct boardtype *this_board;
+	struct pci1710_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret, subdev, n_subdevices;
-	unsigned int irq;
 
-	dev_info(dev->class_dev, DRV_NAME ": attach\n");
-
-	ret = alloc_private(dev, sizeof(struct pci1710_private));
-	if (ret < 0)
-		return -ENOMEM;
-
-	pcidev = pci1710_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	ret = comedi_pci_enable(pcidev, DRV_NAME);
+	this_board = pci1710_find_boardinfo(dev, pcidev);
+	if (!this_board)
+		return -ENODEV;
+	dev->board_ptr = this_board;
+	dev->board_name = this_board->name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
 	if (ret)
 		return ret;
-
 	dev->iobase = pci_resource_start(pcidev, 2);
-	irq = pcidev->irq;
-
-	dev->board_name = this_board->name;
 
 	n_subdevices = 0;
 	if (this_board->n_aichan)
@@ -1417,30 +1301,17 @@
 
 	pci1710_reset(dev);
 
-	if (this_board->have_irq) {
-		if (irq) {
-			if (request_irq(irq, interrupt_service_pci1710,
-					IRQF_SHARED, "Advantech PCI-1710",
-					dev)) {
-				dev_dbg(dev->class_dev,
-					"unable to allocate IRQ %d, DISABLING IT",
-					irq);
-				irq = 0;	/* Can't use IRQ */
-			} else {
-				dev_dbg(dev->class_dev, "irq=%u", irq);
-			}
-		} else {
-			dev_dbg(dev->class_dev, "IRQ disabled");
-		}
-	} else {
-		irq = 0;
+	if (this_board->have_irq && pcidev->irq) {
+		ret = request_irq(pcidev->irq, interrupt_service_pci1710,
+				  IRQF_SHARED, dev->board_name, dev);
+		if (ret == 0)
+			dev->irq = pcidev->irq;
 	}
 
-	dev->irq = irq;
 	subdev = 0;
 
 	if (this_board->n_aichan) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		dev->read_subdev = s;
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
@@ -1452,7 +1323,7 @@
 		s->range_table = this_board->rangelist_ai;
 		s->cancel = pci171x_ai_cancel;
 		s->insn_read = pci171x_insn_read_ai;
-		if (irq) {
+		if (dev->irq) {
 			s->subdev_flags |= SDF_CMD_READ;
 			s->do_cmdtest = pci171x_ai_cmdtest;
 			s->do_cmd = pci171x_ai_cmd;
@@ -1462,7 +1333,7 @@
 	}
 
 	if (this_board->n_aochan) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 		s->n_chan = this_board->n_aochan;
@@ -1482,7 +1353,7 @@
 	}
 
 	if (this_board->n_dichan) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
 		s->n_chan = this_board->n_dichan;
@@ -1495,7 +1366,7 @@
 	}
 
 	if (this_board->n_dochan) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 		s->n_chan = this_board->n_dochan;
@@ -1510,7 +1381,7 @@
 	}
 
 	if (this_board->n_counter) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_COUNTER;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 		s->n_chan = this_board->n_counter;
@@ -1523,7 +1394,8 @@
 		subdev++;
 	}
 
-	devpriv->valid = 1;
+	dev_info(dev->class_dev, "%s attached, irq %sabled\n",
+		dev->board_name, dev->irq ? "en" : "dis");
 
 	return 0;
 }
@@ -1532,27 +1404,21 @@
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
-	if (dev->private) {
-		if (devpriv->valid)
-			pci1710_reset(dev);
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-	}
+	if (dev->iobase)
+		pci1710_reset(dev);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver adv_pci1710_driver = {
 	.driver_name	= "adv_pci1710",
 	.module		= THIS_MODULE,
-	.attach		= pci1710_attach,
+	.attach_pci	= pci1710_attach_pci,
 	.detach		= pci1710_detach,
-	.num_names	= ARRAY_SIZE(boardtypes),
-	.board_name	= &boardtypes[0].name,
-	.offset		= sizeof(struct boardtype),
 };
 
 static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index dfde0f6..df4efc0 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -52,11 +52,6 @@
 
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe	/* Advantech PCI vendor ID */
 
-/* hardware types of the cards */
-#define TYPE_PCI1723 0
-
-#define IORANGE_1723  0x2A
-
 /* all the registers for the pci1723 board */
 #define PCI1723_DA(N)   ((N)<<1)	/* W: D/A register N (0 to 7) */
 
@@ -112,63 +107,18 @@
 
 #define PCI1723_SELECT_CALIBRATION 0x28	/* Select the calibration Ref_V */
 
-/* static unsigned short pci_list_builded=0;      =1 list of card is know */
-
-static const struct comedi_lrange range_pci1723 = { 1, {
-							BIP_RANGE(10)
-							}
-};
-
-/*
- * Board descriptions for pci1723 boards.
- */
-struct pci1723_board {
-	const char *name;
-	int vendor_id;		/* PCI vendor a device ID of card */
-	int device_id;
-	int iorange;
-	char cardtype;
-	int n_aochan;		/* num of D/A chans */
-	int n_diochan;		/* num of DIO chans */
-	int ao_maxdata;		/* resolution of D/A */
-	const struct comedi_lrange *rangelist_ao;	/* rangelist for D/A */
-};
-
-static const struct pci1723_board boardtypes[] = {
-	{
-	 .name = "pci1723",
-	 .vendor_id = PCI_VENDOR_ID_ADVANTECH,
-	 .device_id = 0x1723,
-	 .iorange = IORANGE_1723,
-	 .cardtype = TYPE_PCI1723,
-	 .n_aochan = 8,
-	 .n_diochan = 16,
-	 .ao_maxdata = 0xffff,
-	 .rangelist_ao = &range_pci1723,
-	 },
-};
-
-/* This structure is for data unique to this hardware driver. */
 struct pci1723_private {
-	int valid;		/* card is usable; */
-
 	unsigned char da_range[8];	/* D/A output range for each channel */
-
 	short ao_data[8];	/* data output buffer */
 };
 
-/* The following macro to make it easy to access the private structure. */
-#define devpriv ((struct pci1723_private *)dev->private)
-
-#define this_board boardtypes
-
 /*
  * The pci1723 card reset;
  */
 static int pci1723_reset(struct comedi_device *dev)
 {
+	struct pci1723_private *devpriv = dev->private;
 	int i;
-	DPRINTK("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n");
 
 	outw(0x01, dev->iobase + PCI1723_SYN_SET);
 					       /* set synchronous output mode */
@@ -190,7 +140,6 @@
 	/* set asynchronous output mode */
 	outw(0, dev->iobase + PCI1723_SYN_SET);
 
-	DPRINTK("adv_pci1723 EDBG: END: pci1723_reset(...)\n");
 	return 0;
 }
 
@@ -198,10 +147,10 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1723_private *devpriv = dev->private;
 	int n, chan;
 
 	chan = CR_CHAN(insn->chanspec);
-	DPRINTK(" adv_PCI1723 DEBUG: pci1723_insn_read_ao() -----\n");
 	for (n = 0; n < insn->n; n++)
 		data[n] = devpriv->ao_data[chan];
 
@@ -215,11 +164,10 @@
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci1723_private *devpriv = dev->private;
 	int n, chan;
 	chan = CR_CHAN(insn->chanspec);
 
-	DPRINTK("PCI1723: the pci1723_ao_write_winsn() ------\n");
-
 	for (n = 0; n < insn->n; n++) {
 
 		devpriv->ao_data[chan] = data[n];
@@ -286,124 +234,73 @@
 	return insn->n;
 }
 
-static struct pci_dev *pci1723_find_pci_dev(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
+static int pci1723_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
-			continue;
-		return pcidev;
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-static int pci1723_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
+	struct pci1723_private *devpriv;
 	struct comedi_subdevice *s;
-	int ret, subdev, n_subdevices;
+	int ret;
 
-	printk(KERN_ERR "comedi%d: adv_pci1723: board=%s",
-						dev->minor, this_board->name);
-
-	ret = alloc_private(dev, sizeof(struct pci1723_private));
-	if (ret < 0) {
-		printk(" - Allocation failed!\n");
-		return -ENOMEM;
-	}
-
-	pcidev = pci1723_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
+	dev->board_name = dev->driver->driver_name;
 
-	ret = comedi_pci_enable(pcidev, "adv_pci1723");
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
 	if (ret)
 		return ret;
-
 	dev->iobase = pci_resource_start(pcidev, 2);
 
-	dev->board_name = this_board->name;
-
-	n_subdevices = 0;
-
-	if (this_board->n_aochan)
-		n_subdevices++;
-	if (this_board->n_diochan)
-		n_subdevices++;
-
-	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
 
-	pci1723_reset(dev);
-	subdev = 0;
-	if (this_board->n_aochan) {
-		s = dev->subdevices + subdev;
-		dev->write_subdev = s;
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
-		s->n_chan = this_board->n_aochan;
-		s->maxdata = this_board->ao_maxdata;
-		s->len_chanlist = this_board->n_aochan;
-		s->range_table = this_board->rangelist_ao;
+	s = &dev->subdevices[0];
+	dev->write_subdev = s;
+	s->type		= COMEDI_SUBD_AO;
+	s->subdev_flags	= SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
+	s->n_chan	= 8;
+	s->maxdata	= 0xffff;
+	s->len_chanlist	= 8;
+	s->range_table	= &range_bipolar10;
+	s->insn_write	= pci1723_ao_write_winsn;
+	s->insn_read	= pci1723_insn_read_ao;
 
-		s->insn_write = pci1723_ao_write_winsn;
-		s->insn_read = pci1723_insn_read_ao;
+	s = &dev->subdevices[1];
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->len_chanlist	= 16;
+	s->range_table	= &range_digital;
+	s->insn_config	= pci1723_dio_insn_config;
+	s->insn_bits	= pci1723_dio_insn_bits;
 
-		/* read DIO config */
-		switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE)
-								       & 0x03) {
-		case 0x00:	/* low byte output, high byte output */
-			s->io_bits = 0xFFFF;
-			break;
-		case 0x01:	/* low byte input, high byte output */
-			s->io_bits = 0xFF00;
-			break;
-		case 0x02:	/* low byte output, high byte input */
-			s->io_bits = 0x00FF;
-			break;
-		case 0x03:	/* low byte input, high byte input */
-			s->io_bits = 0x0000;
-			break;
-		}
-		/* read DIO port state */
-		s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
-
-		subdev++;
+	/* read DIO config */
+	switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) {
+	case 0x00:	/* low byte output, high byte output */
+		s->io_bits = 0xFFFF;
+		break;
+	case 0x01:	/* low byte input, high byte output */
+		s->io_bits = 0xFF00;
+		break;
+	case 0x02:	/* low byte output, high byte input */
+		s->io_bits = 0x00FF;
+		break;
+	case 0x03:	/* low byte input, high byte input */
+		s->io_bits = 0x0000;
+		break;
 	}
-
-	if (this_board->n_diochan) {
-		s = dev->subdevices + subdev;
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags =
-		    SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-		s->n_chan = this_board->n_diochan;
-		s->maxdata = 1;
-		s->len_chanlist = this_board->n_diochan;
-		s->range_table = &range_digital;
-		s->insn_config = pci1723_dio_insn_config;
-		s->insn_bits = pci1723_dio_insn_bits;
-		subdev++;
-	}
-
-	devpriv->valid = 1;
+	/* read DIO port state */
+	s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
 
 	pci1723_reset(dev);
 
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+
 	return 0;
 }
 
@@ -411,21 +308,18 @@
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
-	if (dev->private) {
-		if (devpriv->valid)
-			pci1723_reset(dev);
-	}
 	if (pcidev) {
-		if (dev->iobase)
+		if (dev->iobase) {
+			pci1723_reset(dev);
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
+		}
 	}
 }
 
 static struct comedi_driver adv_pci1723_driver = {
 	.driver_name	= "adv_pci1723",
 	.module		= THIS_MODULE,
-	.attach		= pci1723_attach,
+	.attach_pci	= pci1723_attach_pci,
 	.detach		= pci1723_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 2d4cb7f..a3c2241 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -36,15 +36,6 @@
 #include "8255.h"
 #include "8253.h"
 
-#undef PCI_DIO_EXTDEBUG		/* if defined, enable extensive debug logging */
-
-#undef DPRINTK
-#ifdef PCI_DIO_EXTDEBUG
-#define DPRINTK(fmt, args...) printk(fmt, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe
 
 /* hardware types of the cards */
@@ -250,6 +241,7 @@
 	int device_id;
 	int main_pci_region;	/*  main I/O PCI region */
 	enum hw_cards_id cardtype;
+	int nsubdevs;
 	struct diosubd_data sdi[MAX_DI_SUBDEVS];	/*  DI chans */
 	struct diosubd_data sdo[MAX_DO_SUBDEVS];	/*  DO chans */
 	struct diosubd_data sdio[MAX_DIO_SUBDEVG];	/*  DIO 8255 chans */
@@ -259,126 +251,164 @@
 };
 
 static const struct dio_boardtype boardtypes[] = {
-	{"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
-	 TYPE_PCI1730,
-	 { {16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0} },
-	 { {16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
-	 TYPE_PCI1733,
-	 { {0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
-	 TYPE_PCI1734,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
-	 TYPE_PCI1735,
-	 { {32, PCI1735_DI, 4, 0}, {0, 0, 0, 0} },
-	 { {32, PCI1735_DO, 4, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
-	 { {3, PCI1735_C8254, 1, 0} },
-	 IO_8b},
-	{"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
-	 TYPE_PCI1736,
-	 { {0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0} },
-	 { {0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1739", PCI_VENDOR_ID_ADVANTECH, 0x1739, PCIDIO_MAINREG,
-	 TYPE_PCI1739,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {48, PCI1739_DIO, 2, 0}, {0, 0, 0, 0} },
-	 {0, 0, 0, 0},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
-	 TYPE_PCI1750,
-	 { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} },
-	 { {0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {0, 0, 0, 0},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
-	 TYPE_PCI1751,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0} },
-	 {0, 0, 0, 0},
-	 { {3, PCI1751_CNT, 1, 0} },
-	 IO_8b},
-	{"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
-	 TYPE_PCI1752,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_16b},
-	{"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
-	 TYPE_PCI1753,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0} },
-	 {0, 0, 0, 0},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
-	 TYPE_PCI1753E,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0} },
-	 {0, 0, 0, 0},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
-	 TYPE_PCI1754,
-	 { {32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_16b},
-	{"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
-	 TYPE_PCI1756,
-	 { {0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0} },
-	 { {0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_16b},
-	{"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
-	 TYPE_PCI1760,
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} }, /* This card have own setup work */
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {0, 0, 0, 0},
-	 { {0, 0, 0, 0} },
-	 IO_8b},
-	{"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
-	 TYPE_PCI1762,
-	 { {0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0} },
-	 { {0, 0, 0, 0}, {16, PCI1762_RO, 1, 0} },
-	 { {0, 0, 0, 0}, {0, 0, 0, 0} },
-	 {4, PCI1762_BOARDID, 1, SDF_INTERNAL},
-	 { {0, 0, 0, 0} },
-	 IO_16b}
+	{
+		.name		= "pci1730",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1730,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1730,
+		.nsubdevs	= 5,
+		.sdi[0]		= { 16, PCI1730_DI, 2, 0, },
+		.sdi[1]		= { 16, PCI1730_IDI, 2, 0, },
+		.sdo[0]		= { 16, PCI1730_DO, 2, 0, },
+		.sdo[1]		= { 16, PCI1730_IDO, 2, 0, },
+		.boardid	= { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1733",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1733,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1733,
+		.nsubdevs	= 2,
+		.sdi[1]		= { 32, PCI1733_IDI, 4, 0, },
+		.boardid	= { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1734",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1734,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1734,
+		.nsubdevs	= 2,
+		.sdo[1]		= { 32, PCI1734_IDO, 4, 0, },
+		.boardid	= { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1735",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1735,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1735,
+		.nsubdevs	= 4,
+		.sdi[0]		= { 32, PCI1735_DI, 4, 0, },
+		.sdo[0]		= { 32, PCI1735_DO, 4, 0, },
+		.boardid	= { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, },
+		.s8254[0]	= { 3, PCI1735_C8254, 1, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1736",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1736,
+		.main_pci_region = PCI1736_MAINREG,
+		.cardtype	= TYPE_PCI1736,
+		.nsubdevs	= 3,
+		.sdi[1]		= { 16, PCI1736_IDI, 2, 0, },
+		.sdo[1]		= { 16, PCI1736_IDO, 2, 0, },
+		.boardid	= { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1739",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1739,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1739,
+		.nsubdevs	= 2,
+		.sdio[0]	= { 48, PCI1739_DIO, 2, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1750",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1750,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1750,
+		.nsubdevs	= 2,
+		.sdi[1]		= { 16, PCI1750_IDI, 2, 0, },
+		.sdo[1]		= { 16, PCI1750_IDO, 2, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1751",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1751,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1751,
+		.nsubdevs	= 3,
+		.sdio[0]	= { 48, PCI1751_DIO, 2, 0, },
+		.s8254[0]	= { 3, PCI1751_CNT, 1, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1752",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1752,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1752,
+		.nsubdevs	= 3,
+		.sdo[0]		= { 32, PCI1752_IDO, 2, 0, },
+		.sdo[1]		= { 32, PCI1752_IDO2, 2, 0, },
+		.boardid	= { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_16b,
+	}, {
+		.name		= "pci1753",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1753,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1753,
+		.nsubdevs	= 4,
+		.sdio[0]	= { 96, PCI1753_DIO, 4, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1753e",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1753,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1753E,
+		.nsubdevs	= 8,
+		.sdio[0]	= { 96, PCI1753_DIO, 4, 0, },
+		.sdio[1]	= { 96, PCI1753E_DIO, 4, 0, },
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1754",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1754,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1754,
+		.nsubdevs	= 3,
+		.sdi[0]		= { 32, PCI1754_IDI, 2, 0, },
+		.sdi[1]		= { 32, PCI1754_IDI2, 2, 0, },
+		.boardid	= { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_16b,
+	}, {
+		.name		= "pci1756",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1756,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1756,
+		.nsubdevs	= 3,
+		.sdi[1]		= { 32, PCI1756_IDI, 2, 0, },
+		.sdo[1]		= { 32, PCI1756_IDO, 2, 0, },
+		.boardid	= { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_16b,
+	}, {
+		/* This card has its own 'attach' */
+		.name		= "pci1760",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1760,
+		.main_pci_region = 0,
+		.cardtype	= TYPE_PCI1760,
+		.nsubdevs	= 4,
+		.io_access	= IO_8b,
+	}, {
+		.name		= "pci1762",
+		.vendor_id	= PCI_VENDOR_ID_ADVANTECH,
+		.device_id	= 0x1762,
+		.main_pci_region = PCIDIO_MAINREG,
+		.cardtype	= TYPE_PCI1762,
+		.nsubdevs	= 3,
+		.sdi[1]		= { 16, PCI1762_IDI, 1, 0, },
+		.sdo[1]		= { 16, PCI1762_RO, 1, 0, },
+		.boardid	= { 4, PCI1762_BOARDID, 1, SDF_INTERNAL, },
+		.io_access	= IO_16b,
+	},
 };
 
 struct pci_dio_private {
@@ -401,9 +431,6 @@
 	unsigned short IDIFiltrHigh[8];	/*  IDI's filter value high signal */
 };
 
-#define devpriv ((struct pci_dio_private *)dev->private)
-#define this_board ((const struct dio_boardtype *)dev->board_ptr)
-
 /*
 ==============================================================================
 */
@@ -694,6 +721,7 @@
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci_dio_private *devpriv = dev->private;
 	int ret;
 	unsigned char chan = CR_CHAN(insn->chanspec) & 0x07;
 	unsigned char bitmask = 1 << chan;
@@ -736,6 +764,7 @@
 */
 static int pci1760_reset(struct comedi_device *dev)
 {
+	struct pci_dio_private *devpriv = dev->private;
 	int i;
 	unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 };
 	unsigned char imb[4];
@@ -816,7 +845,7 @@
 */
 static int pci_dio_reset(struct comedi_device *dev)
 {
-	DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n");
+	const struct dio_boardtype *this_board = comedi_board(dev);
 
 	switch (this_board->cardtype) {
 	case TYPE_PCI1730:
@@ -917,21 +946,17 @@
 		break;
 	}
 
-	DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n");
-
 	return 0;
 }
 
 /*
 ==============================================================================
 */
-static int pci1760_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static int pci1760_attach(struct comedi_device *dev)
 {
 	struct comedi_subdevice *s;
-	int subdev = 0;
 
-	s = dev->subdevices + subdev;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
 	s->n_chan = 8;
@@ -939,9 +964,8 @@
 	s->len_chanlist = 8;
 	s->range_table = &range_digital;
 	s->insn_bits = pci1760_insn_bits_di;
-	subdev++;
 
-	s = dev->subdevices + subdev;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 	s->n_chan = 8;
@@ -950,18 +974,16 @@
 	s->range_table = &range_digital;
 	s->state = 0;
 	s->insn_bits = pci1760_insn_bits_do;
-	subdev++;
 
-	s = dev->subdevices + subdev;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_TIMER;
 	s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL;
 	s->n_chan = 2;
 	s->maxdata = 0xffffffff;
 	s->len_chanlist = 2;
 /*       s->insn_config=pci1760_insn_pwm_cfg; */
-	subdev++;
 
-	s = dev->subdevices + subdev;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 8;
@@ -970,7 +992,6 @@
 	s->insn_read = pci1760_insn_cnt_read;
 	s->insn_write = pci1760_insn_cnt_write;
 /*       s->insn_config=pci1760_insn_cnt_cfg; */
-	subdev++;
 
 	return 0;
 }
@@ -978,9 +999,12 @@
 /*
 ==============================================================================
 */
-static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s,
-			  const struct diosubd_data *d, int subdev)
+static int pci_dio_add_di(struct comedi_device *dev,
+			  struct comedi_subdevice *s,
+			  const struct diosubd_data *d)
 {
+	const struct dio_boardtype *this_board = comedi_board(dev);
+
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags;
 	if (d->chans > 16)
@@ -1005,9 +1029,12 @@
 /*
 ==============================================================================
 */
-static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
-			  const struct diosubd_data *d, int subdev)
+static int pci_dio_add_do(struct comedi_device *dev,
+			  struct comedi_subdevice *s,
+			  const struct diosubd_data *d)
 {
+	const struct dio_boardtype *this_board = comedi_board(dev);
+
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 	if (d->chans > 16)
@@ -1035,7 +1062,7 @@
 */
 static int pci_dio_add_8254(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
-			    const struct diosubd_data *d, int subdev)
+			    const struct diosubd_data *d)
 {
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
@@ -1050,101 +1077,69 @@
 	return 0;
 }
 
-static struct pci_dev *pci_dio_find_pci_dev(struct comedi_device *dev,
-					    struct comedi_devconfig *it)
+static const void *pci_dio_find_boardinfo(struct comedi_device *dev,
+					  struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
+	const struct dio_boardtype *this_board;
 	int i;
 
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
-			if (boardtypes[i].vendor_id != pcidev->vendor)
-				continue;
-			if (boardtypes[i].device_id != pcidev->device)
-				continue;
-			dev->board_ptr = boardtypes + i;
-			return pcidev;
-		}
+	for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
+		this_board = &boardtypes[i];
+		if (this_board->vendor_id == pcidev->vendor &&
+		    this_board->device_id == pcidev->device)
+			return this_board;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int pci_dio_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static int pci_dio_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev;
+	const struct dio_boardtype *this_board;
+	struct pci_dio_private *devpriv;
 	struct comedi_subdevice *s;
-	int ret, subdev, n_subdevices, i, j;
+	int ret, subdev, i, j;
 
-	ret = alloc_private(dev, sizeof(struct pci_dio_private));
-	if (ret < 0)
-		return -ENOMEM;
-
-	pcidev = pci_dio_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
-		dev_err(dev->class_dev,
-			"Error: Can't enable PCI device and request regions!\n");
-		return -EIO;
-	}
-
-	dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region);
+	this_board = pci_dio_find_boardinfo(dev, pcidev);
+	if (!this_board)
+		return -ENODEV;
+	dev->board_ptr = this_board;
 	dev->board_name = this_board->name;
 
-	if (this_board->cardtype == TYPE_PCI1760) {
-		n_subdevices = 4;	/*  8 IDI, 8 IDO, 2 PWM, 8 CNT */
-	} else {
-		n_subdevices = 0;
-		for (i = 0; i < MAX_DI_SUBDEVS; i++)
-			if (this_board->sdi[i].chans)
-				n_subdevices++;
-		for (i = 0; i < MAX_DO_SUBDEVS; i++)
-			if (this_board->sdo[i].chans)
-				n_subdevices++;
-		for (i = 0; i < MAX_DIO_SUBDEVG; i++)
-			n_subdevices += this_board->sdio[i].regs;
-		if (this_board->boardid.chans)
-			n_subdevices++;
-		for (i = 0; i < MAX_8254_SUBDEVS; i++)
-			if (this_board->s8254[i].chans)
-				n_subdevices++;
-	}
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
 
-	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region);
+
+	ret = comedi_alloc_subdevices(dev, this_board->nsubdevs);
 	if (ret)
 		return ret;
 
 	subdev = 0;
 	for (i = 0; i < MAX_DI_SUBDEVS; i++)
 		if (this_board->sdi[i].chans) {
-			s = dev->subdevices + subdev;
-			pci_dio_add_di(dev, s, &this_board->sdi[i], subdev);
+			s = &dev->subdevices[subdev];
+			pci_dio_add_di(dev, s, &this_board->sdi[i]);
 			subdev++;
 		}
 
 	for (i = 0; i < MAX_DO_SUBDEVS; i++)
 		if (this_board->sdo[i].chans) {
-			s = dev->subdevices + subdev;
-			pci_dio_add_do(dev, s, &this_board->sdo[i], subdev);
+			s = &dev->subdevices[subdev];
+			pci_dio_add_do(dev, s, &this_board->sdo[i]);
 			subdev++;
 		}
 
 	for (i = 0; i < MAX_DIO_SUBDEVG; i++)
 		for (j = 0; j < this_board->sdio[i].regs; j++) {
-			s = dev->subdevices + subdev;
+			s = &dev->subdevices[subdev];
 			subdev_8255_init(dev, s, NULL,
 					 dev->iobase +
 					 this_board->sdio[i].addr +
@@ -1153,21 +1148,21 @@
 		}
 
 	if (this_board->boardid.chans) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_DI;
-		pci_dio_add_di(dev, s, &this_board->boardid, subdev);
+		pci_dio_add_di(dev, s, &this_board->boardid);
 		subdev++;
 	}
 
 	for (i = 0; i < MAX_8254_SUBDEVS; i++)
 		if (this_board->s8254[i].chans) {
-			s = dev->subdevices + subdev;
-			pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev);
+			s = &dev->subdevices[subdev];
+			pci_dio_add_8254(dev, s, &this_board->s8254[i]);
 			subdev++;
 		}
 
 	if (this_board->cardtype == TYPE_PCI1760)
-		pci1760_attach(dev, it);
+		pci1760_attach(dev);
 
 	devpriv->valid = 1;
 
@@ -1178,52 +1173,34 @@
 
 static void pci_dio_detach(struct comedi_device *dev)
 {
+	struct pci_dio_private *devpriv = dev->private;
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-	int i, j;
 	struct comedi_subdevice *s;
-	int subdev;
+	int i;
 
-	if (dev->private) {
+	if (devpriv) {
 		if (devpriv->valid)
 			pci_dio_reset(dev);
-		subdev = 0;
-		for (i = 0; i < MAX_DI_SUBDEVS; i++) {
-			if (this_board->sdi[i].chans)
-				subdev++;
-		}
-		for (i = 0; i < MAX_DO_SUBDEVS; i++) {
-			if (this_board->sdo[i].chans)
-				subdev++;
-		}
-		for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
-			for (j = 0; j < this_board->sdio[i].regs; j++) {
-				s = dev->subdevices + subdev;
-				subdev_8255_cleanup(dev, s);
-				subdev++;
-			}
-		}
-		if (this_board->boardid.chans)
-			subdev++;
-		for (i = 0; i < MAX_8254_SUBDEVS; i++)
-			if (this_board->s8254[i].chans)
-				subdev++;
+	}
+	if (dev->subdevices) {
 		for (i = 0; i < dev->n_subdevices; i++) {
-			s = dev->subdevices + i;
+			s = &dev->subdevices[i];
+			if (s->type == COMEDI_SUBD_DIO)
+				subdev_8255_cleanup(dev, s);
 			s->private = NULL;
 		}
 	}
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver adv_pci_dio_driver = {
 	.driver_name	= "adv_pci_dio",
 	.module		= THIS_MODULE,
-	.attach		= pci_dio_attach,
-	.detach		= pci_dio_detach
+	.attach_pci	= pci_dio_attach_pci,
+	.detach		= pci_dio_detach,
 };
 
 static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index f7d453f..8acf60d 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -25,8 +25,9 @@
 Driver: aio_aio12_8
 Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board
 Author: Pablo Mejia <pablo.mejia@cctechnol.com>
-Devices:
- [Access I/O] PC-104 AIO12-8
+Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8)
+	 [Access I/O] PC-104 AI12-8 (aio_ai12_8)
+	 [Access I/O] PC-104 AO12-8 (aio_ao12_8)
 Status: experimental
 
 Configuration Options:
@@ -42,91 +43,118 @@
 #include <linux/ioport.h>
 #include "8255.h"
 
-#define AIO12_8_STATUS			0x00
-#define AIO12_8_INTERRUPT		0x01
-#define AIO12_8_ADC			0x02
-#define AIO12_8_DAC_0			0x04
-#define AIO12_8_DAC_1			0x06
-#define AIO12_8_DAC_2			0x08
-#define AIO12_8_DAC_3			0x0A
-#define AIO12_8_COUNTER_0		0x0C
-#define AIO12_8_COUNTER_1		0x0D
-#define AIO12_8_COUNTER_2		0x0E
-#define AIO12_8_COUNTER_CONTROL		0x0F
-#define AIO12_8_DIO_0			0x10
-#define AIO12_8_DIO_1			0x11
-#define AIO12_8_DIO_2			0x12
-#define AIO12_8_DIO_STATUS		0x13
-#define AIO12_8_DIO_CONTROL		0x14
-#define AIO12_8_ADC_TRIGGER_CONTROL	0x15
-#define AIO12_8_TRIGGER			0x16
-#define AIO12_8_POWER			0x17
-
-#define STATUS_ADC_EOC			0x80
-
-#define ADC_MODE_NORMAL			0x00
-#define ADC_MODE_INTERNAL_CLOCK		0x40
-#define ADC_MODE_STANDBY		0x80
-#define ADC_MODE_POWERDOWN		0xC0
-
-#define DAC_ENABLE			0x18
+/*
+ * Register map
+ */
+#define AIO12_8_STATUS_REG		0x00
+#define AIO12_8_STATUS_ADC_EOC		(1 << 7)
+#define AIO12_8_STATUS_PORT_C_COS	(1 << 6)
+#define AIO12_8_STATUS_IRQ_ENA		(1 << 2)
+#define AIO12_8_INTERRUPT_REG		0x01
+#define AIO12_8_INTERRUPT_ADC		(1 << 7)
+#define AIO12_8_INTERRUPT_COS		(1 << 6)
+#define AIO12_8_INTERRUPT_COUNTER1	(1 << 5)
+#define AIO12_8_INTERRUPT_PORT_C3	(1 << 4)
+#define AIO12_8_INTERRUPT_PORT_C0	(1 << 3)
+#define AIO12_8_INTERRUPT_ENA		(1 << 2)
+#define AIO12_8_ADC_REG			0x02
+#define AIO12_8_ADC_MODE_NORMAL		(0 << 6)
+#define AIO12_8_ADC_MODE_INT_CLK	(1 << 6)
+#define AIO12_8_ADC_MODE_STANDBY	(2 << 6)
+#define AIO12_8_ADC_MODE_POWERDOWN	(3 << 6)
+#define AIO12_8_ADC_ACQ_3USEC		(0 << 5)
+#define AIO12_8_ADC_ACQ_PROGRAM		(1 << 5)
+#define AIO12_8_ADC_RANGE(x)		((x) << 3)
+#define AIO12_8_ADC_CHAN(x)		((x) << 0)
+#define AIO12_8_DAC_REG(x)		(0x04 + (x) * 2)
+#define AIO12_8_8254_BASE_REG		0x0c
+#define AIO12_8_8255_BASE_REG		0x10
+#define AIO12_8_DIO_CONTROL_REG		0x14
+#define AIO12_8_DIO_CONTROL_TST		(1 << 0)
+#define AIO12_8_ADC_TRIGGER_REG		0x15
+#define AIO12_8_ADC_TRIGGER_RANGE(x)	((x) << 3)
+#define AIO12_8_ADC_TRIGGER_CHAN(x)	((x) << 0)
+#define AIO12_8_TRIGGER_REG		0x16
+#define AIO12_8_TRIGGER_ADTRIG		(1 << 1)
+#define AIO12_8_TRIGGER_DACTRIG		(1 << 0)
+#define AIO12_8_COS_REG			0x17
+#define AIO12_8_DAC_ENABLE_REG		0x18
+#define AIO12_8_DAC_ENABLE_REF_ENA	(1 << 0)
 
 struct aio12_8_boardtype {
 	const char *name;
+	int ai_nchan;
+	int ao_nchan;
 };
 
 static const struct aio12_8_boardtype board_types[] = {
 	{
-	 .name = "aio_aio12_8"},
+		.name		= "aio_aio12_8",
+		.ai_nchan	= 8,
+		.ao_nchan	= 4,
+	}, {
+		.name		= "aio_ai12_8",
+		.ai_nchan	= 8,
+	}, {
+		.name		= "aio_ao12_8",
+		.ao_nchan	= 4,
+	},
 };
 
 struct aio12_8_private {
 	unsigned int ao_readback[4];
 };
 
-#define devpriv	((struct aio12_8_private *) dev->private)
-
 static int aio_aio12_8_ai_read(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int val;
+	unsigned char control;
 	int n;
-	unsigned char control =
-	    ADC_MODE_NORMAL |
-	    (CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec);
 
-	/* read status to clear EOC latch */
-	inb(dev->iobase + AIO12_8_STATUS);
+	/*
+	 * Setup the control byte for internal 2MHz clock, 3uS conversion,
+	 * at the desired range of the requested channel.
+	 */
+	control = AIO12_8_ADC_MODE_NORMAL | AIO12_8_ADC_ACQ_3USEC |
+		  AIO12_8_ADC_RANGE(range) | AIO12_8_ADC_CHAN(chan);
+
+	/* Read status to clear EOC latch */
+	inb(dev->iobase + AIO12_8_STATUS_REG);
 
 	for (n = 0; n < insn->n; n++) {
 		int timeout = 5;
 
 		/*  Setup and start conversion */
-		outb(control, dev->iobase + AIO12_8_ADC);
+		outb(control, dev->iobase + AIO12_8_ADC_REG);
 
 		/*  Wait for conversion to complete */
-		while (timeout &&
-		       !(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) {
+		do {
+			val = inb(dev->iobase + AIO12_8_STATUS_REG);
 			timeout--;
-			printk(KERN_ERR "timeout %d\n", timeout);
-			udelay(1);
-		}
-		if (timeout == 0) {
-			comedi_error(dev, "ADC timeout");
-			return -EIO;
-		}
+			if (timeout == 0) {
+				dev_err(dev->class_dev, "ADC timeout\n");
+				return -ETIMEDOUT;
+			}
+		} while (!(val & AIO12_8_STATUS_ADC_EOC));
 
-		data[n] = inw(dev->iobase + AIO12_8_ADC) & 0x0FFF;
+		data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
 	}
-	return n;
+
+	return insn->n;
 }
 
 static int aio_aio12_8_ao_read(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct aio12_8_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int val = devpriv->ao_readback[chan];
 	int i;
-	int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
 
 	for (i = 0; i < insn->n; i++)
 		data[i] = val;
@@ -137,18 +165,22 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct aio12_8_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned long port = dev->iobase + AIO12_8_DAC_REG(chan);
+	unsigned int val = 0;
 	int i;
-	int chan = CR_CHAN(insn->chanspec);
-	unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan);
 
 	/* enable DACs */
-	outb(0x01, dev->iobase + DAC_ENABLE);
+	outb(AIO12_8_DAC_ENABLE_REF_ENA, dev->iobase + AIO12_8_DAC_ENABLE_REG);
 
 	for (i = 0; i < insn->n; i++) {
-		outb(data[i] & 0xFF, port);	/*  LSB */
-		outb((data[i] >> 8) & 0x0F, port + 1);	/*  MSB */
-		devpriv->ao_readback[chan] = data[i];
+		val = data[i];
+		outw(val, port);
 	}
+
+	devpriv->ao_readback[chan] = val;
+
 	return insn->n;
 }
 
@@ -166,53 +198,77 @@
 			      struct comedi_devconfig *it)
 {
 	const struct aio12_8_boardtype *board = comedi_board(dev);
-	int iobase;
+	struct aio12_8_private *devpriv;
 	struct comedi_subdevice *s;
+	int iobase;
 	int ret;
 
-	iobase = it->options[0];
-	if (!request_region(iobase, 24, "aio_aio12_8")) {
-		printk(KERN_ERR "I/O port conflict");
-		return -EIO;
-	}
-
 	dev->board_name = board->name;
 
+	iobase = it->options[0];
+	if (!request_region(iobase, 32, dev->board_name)) {
+		printk(KERN_ERR "I/O port conflict");
+		return -EIO;
+	}
 	dev->iobase = iobase;
 
-	if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0)
-		return -ENOMEM;
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
 
-	ret = comedi_alloc_subdevices(dev, 3);
+	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
 	s = &dev->subdevices[0];
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-	s->n_chan = 8;
-	s->maxdata = (1 << 12) - 1;
-	s->range_table = &range_aio_aio12_8;
-	s->insn_read = aio_aio12_8_ai_read;
+	if (board->ai_nchan) {
+		/* Analog input subdevice */
+		s->type		= COMEDI_SUBD_AI;
+		s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_DIFF;
+		s->n_chan	= board->ai_nchan;
+		s->maxdata	= 0x0fff;
+		s->range_table	= &range_aio_aio12_8;
+		s->insn_read	= aio_aio12_8_ai_read;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
 
 	s = &dev->subdevices[1];
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF;
-	s->n_chan = 4;
-	s->maxdata = (1 << 12) - 1;
-	s->range_table = &range_aio_aio12_8;
-	s->insn_read = aio_aio12_8_ao_read;
-	s->insn_write = aio_aio12_8_ao_write;
+	if (board->ao_nchan) {
+		/* Analog output subdevice */
+		s->type		= COMEDI_SUBD_AO;
+		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_DIFF;
+		s->n_chan	= 4;
+		s->maxdata	= 0x0fff;
+		s->range_table	= &range_aio_aio12_8;
+		s->insn_read	= aio_aio12_8_ao_read;
+		s->insn_write	= aio_aio12_8_ao_write;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
 
 	s = &dev->subdevices[2];
-	subdev_8255_init(dev, s, NULL, dev->iobase + AIO12_8_DIO_0);
+	/* 8255 Digital i/o subdevice */
+	iobase = dev->iobase + AIO12_8_8255_BASE_REG;
+	ret = subdev_8255_init(dev, s, NULL, iobase);
+	if (ret)
+		return ret;
+
+	s = &dev->subdevices[3];
+	/* 8254 counter/timer subdevice */
+	s->type		= COMEDI_SUBD_UNUSED;
+
+	dev_info(dev->class_dev, "%s: %s attached\n",
+		dev->driver->driver_name, dev->board_name);
 
 	return 0;
 }
 
 static void aio_aio12_8_detach(struct comedi_device *dev)
 {
-	subdev_8255_cleanup(dev, &dev->subdevices[2]);
+	if (dev->subdevices)
+		subdev_8255_cleanup(dev, &dev->subdevices[2]);
 	if (dev->iobase)
 		release_region(dev->iobase, 24);
 }
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index ba1e3bb..b2cb8b0 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -112,7 +112,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->n_chan = 16;
@@ -120,7 +120,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = aio_iiro_16_dio_insn_bits_write;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 16;
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index cc8931f..08f3052 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -210,11 +210,15 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "8255.h"
 #include "8253.h"
 
 #define DIO200_DRIVER_NAME	"amplc_dio200"
 
+#define DO_ISA	IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#define DO_PCI	IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+
 /* PCI IDs */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -272,12 +276,12 @@
 };
 
 enum dio200_layout {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
 	pc212_layout,
 	pc214_layout,
 #endif
 	pc215_layout,
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
 	pc218_layout,
 #endif
 	pc272_layout
@@ -292,7 +296,7 @@
 };
 
 static const struct dio200_board dio200_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
 	{
 	 .name = "pc212e",
 	 .bustype = isa_bustype,
@@ -324,7 +328,7 @@
 	 .layout = pc272_layout,
 	 },
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+#if DO_PCI
 	{
 	 .name = "pci215",
 	 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
@@ -367,7 +371,7 @@
 };
 
 static const struct dio200_layout_struct dio200_layouts[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
 	[pc212_layout] = {
 			  .n_subdevs = 6,
 			  .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -396,7 +400,7 @@
 			  .has_int_sce = 1,
 			  .has_clk_gat_sce = 1,
 			  },
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
 	[pc218_layout] = {
 			  .n_subdevs = 7,
 			  .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -449,6 +453,16 @@
 	int continuous;
 };
 
+static inline bool is_pci_board(const struct dio200_board *board)
+{
+	return DO_PCI && board->bustype == pci_bustype;
+}
+
+static inline bool is_isa_board(const struct dio200_board *board)
+{
+	return DO_ISA && board->bustype == isa_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -458,7 +472,7 @@
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(dio200_boards); i++)
-		if (dio200_boards[i].bustype == pci_bustype &&
+		if (is_pci_board(&dio200_boards[i]) &&
 		    pci_dev->device == dio200_boards[i].devid)
 			return &dio200_boards[i];
 	return NULL;
@@ -758,52 +772,24 @@
 			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
 	int err = 0;
-	unsigned int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= (TRIG_NOW | TRIG_INT);
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-		   compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* these tests are true if more than one _src bit is set */
-	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
-		err++;
-	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
-		err++;
-	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -965,15 +951,15 @@
 {
 	struct comedi_device *dev = d;
 	struct dio200_private *devpriv = dev->private;
+	struct comedi_subdevice *s;
 	int handled;
 
 	if (!dev->attached)
 		return IRQ_NONE;
 
 	if (devpriv->intr_sd >= 0) {
-		handled = dio200_handle_read_intr(dev,
-						  dev->subdevices +
-						  devpriv->intr_sd);
+		s = &dev->subdevices[devpriv->intr_sd];
+		handled = dio200_handle_read_intr(dev, s);
 	} else {
 		handled = 0;
 	}
@@ -1228,12 +1214,10 @@
 	char tmpbuf[60];
 	int tmplen;
 
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
-	    thisboard->bustype == isa_bustype)
+	if (is_isa_board(thisboard))
 		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
 				   "(base %#lx) ", dev->iobase);
-	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
-		 thisboard->bustype == pci_bustype)
+	else if (is_pci_board(thisboard))
 		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
 				   "(pci %s) ", pci_name(pcidev));
 	else
@@ -1361,8 +1345,7 @@
 	}
 
 	/* Process options and reserve resources according to bus type. */
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
-	    thisboard->bustype == isa_bustype) {
+	if (is_isa_board(thisboard)) {
 		unsigned long iobase;
 		unsigned int irq;
 
@@ -1372,8 +1355,7 @@
 		if (ret < 0)
 			return ret;
 		return dio200_common_attach(dev, iobase, irq, 0);
-	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
-		   thisboard->bustype == pci_bustype) {
+	} else if (is_pci_board(thisboard)) {
 		struct pci_dev *pci_dev;
 
 		pci_dev = dio200_find_pci_dev(dev, it);
@@ -1397,7 +1379,7 @@
 {
 	int ret;
 
-	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI))
+	if (!DO_PCI)
 		return -EINVAL;
 
 	dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n",
@@ -1425,7 +1407,6 @@
 static void dio200_detach(struct comedi_device *dev)
 {
 	const struct dio200_board *thisboard = comedi_board(dev);
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 	const struct dio200_layout_struct *layout;
 	unsigned n;
 
@@ -1450,13 +1431,16 @@
 			}
 		}
 	}
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	} else {
+	if (is_isa_board(thisboard)) {
 		if (dev->iobase)
 			release_region(dev->iobase, DIO200_IO_SIZE);
+	} else if (is_pci_board(thisboard)) {
+		struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+		if (pcidev) {
+			if (dev->iobase)
+				comedi_pci_disable(pcidev);
+			pci_dev_put(pcidev);
+		}
 	}
 }
 
@@ -1477,7 +1461,7 @@
 	.num_names = ARRAY_SIZE(dio200_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index f502879..eacb5e4 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -56,11 +56,15 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "8255.h"
 #include "plx9052.h"
 
 #define PC236_DRIVER_NAME	"amplc_pc236"
 
+#define DO_ISA	IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)
+#define DO_PCI	IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+
 /* PCI236 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -103,14 +107,14 @@
 	enum pc236_model model;
 };
 static const struct pc236_board pc236_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)
+#if DO_ISA
 	{
 		.name = "pc36at",
 		.bustype = isa_bustype,
 		.model = pc36at_model,
 	},
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+#if DO_PCI
 	{
 		.name = "pci236",
 		.devid = PCI_DEVICE_ID_AMPLICON_PCI236,
@@ -135,6 +139,18 @@
 	int enable_irq;
 };
 
+/* test if ISA supported and this is an ISA board */
+static inline bool is_isa_board(const struct pc236_board *board)
+{
+	return DO_ISA && board->bustype == isa_bustype;
+}
+
+/* test if PCI supported and this is a PCI board */
+static inline bool is_pci_board(const struct pc236_board *board)
+{
+	return DO_PCI && board->bustype == pci_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -143,7 +159,7 @@
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(pc236_boards); i++)
-		if (pc236_boards[i].bustype == pci_bustype &&
+		if (is_pci_board(&pc236_boards[i]) &&
 		    pci_dev->device == pc236_boards[i].devid)
 			return &pc236_boards[i];
 	return NULL;
@@ -214,12 +230,13 @@
  */
 static void pc236_intr_disable(struct comedi_device *dev)
 {
+	const struct pc236_board *thisboard = comedi_board(dev);
 	struct pc236_private *devpriv = dev->private;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 0;
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
+	if (is_pci_board(thisboard))
 		outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
@@ -231,12 +248,13 @@
  */
 static void pc236_intr_enable(struct comedi_device *dev)
 {
+	const struct pc236_board *thisboard = comedi_board(dev);
 	struct pc236_private *devpriv = dev->private;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 1;
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
+	if (is_pci_board(thisboard))
 		outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
@@ -250,6 +268,7 @@
  */
 static int pc236_intr_check(struct comedi_device *dev)
 {
+	const struct pc236_board *thisboard = comedi_board(dev);
 	struct pc236_private *devpriv = dev->private;
 	int retval = 0;
 	unsigned long flags;
@@ -257,8 +276,7 @@
 	spin_lock_irqsave(&dev->spinlock, flags);
 	if (devpriv->enable_irq) {
 		retval = 1;
-		if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-		    devpriv->lcr_iobase) {
+		if (is_pci_board(thisboard)) {
 			if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
 			     & PLX9052_INTCSR_LI1STAT_MASK)
 			    == PLX9052_INTCSR_LI1STAT_INACTIVE) {
@@ -296,39 +314,20 @@
 			      struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 
-	/* step 1 */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: ignored */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -395,7 +394,7 @@
 static irqreturn_t pc236_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 1;
+	struct comedi_subdevice *s = &dev->subdevices[1];
 	int handled;
 
 	handled = pc236_intr_check(dev);
@@ -414,15 +413,13 @@
 	char tmpbuf[60];
 	int tmplen;
 
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
-	    thisboard->bustype == isa_bustype)
+	if (is_isa_board(thisboard))
 		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
 				   "(base %#lx) ", dev->iobase);
-	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-		 thisboard->bustype == pci_bustype) {
+	else if (is_pci_board(thisboard))
 		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
 				   "(pci %s) ", pci_name(pcidev));
-	} else
+	else
 		tmplen = 0;
 	if (irq)
 		tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
@@ -449,14 +446,14 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* digital i/o subdevice (8255) */
 	ret = subdev_8255_init(dev, s, NULL, iobase);
 	if (ret < 0) {
 		dev_err(dev->class_dev, "error! out of memory!\n");
 		return ret;
 	}
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_UNUSED;
 	pc236_intr_disable(dev);
@@ -517,16 +514,14 @@
 		return ret;
 	}
 	/* Process options according to bus type. */
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
-	    thisboard->bustype == isa_bustype) {
+	if (is_isa_board(thisboard)) {
 		unsigned long iobase = it->options[0];
 		unsigned int irq = it->options[1];
 		ret = pc236_request_region(dev, iobase, PC236_IO_SIZE);
 		if (ret < 0)
 			return ret;
 		return pc236_common_attach(dev, iobase, irq, 0);
-	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-		   thisboard->bustype == pci_bustype) {
+	} else if (is_pci_board(thisboard)) {
 		struct pci_dev *pci_dev;
 
 		pci_dev = pc236_find_pci_dev(dev, it);
@@ -550,7 +545,7 @@
 {
 	int ret;
 
-	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI))
+	if (!DO_PCI)
 		return -EINVAL;
 
 	dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n",
@@ -577,22 +572,25 @@
 
 static void pc236_detach(struct comedi_device *dev)
 {
+	const struct pc236_board *thisboard = comedi_board(dev);
 	struct pc236_private *devpriv = dev->private;
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
 	if (devpriv)
 		pc236_intr_disable(dev);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 0);
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	} else {
+		subdev_8255_cleanup(dev, &dev->subdevices[0]);
+	if (is_isa_board(thisboard)) {
 		if (dev->iobase)
 			release_region(dev->iobase, PC236_IO_SIZE);
+	} else if (is_pci_board(thisboard)) {
+		struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+		if (pcidev) {
+			if (dev->iobase)
+				comedi_pci_disable(pcidev);
+			pci_dev_put(pcidev);
+		}
 	}
 }
 
@@ -613,7 +611,7 @@
 	.num_names = ARRAY_SIZE(pc236_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
 	{0}
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 8191c4e..60830cc 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -48,6 +48,9 @@
 
 #define PC263_DRIVER_NAME	"amplc_pc263"
 
+#define DO_ISA	IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
+#define DO_PCI	IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+
 /* PCI263 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -70,14 +73,14 @@
 	enum pc263_model model;
 };
 static const struct pc263_board pc263_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
+#if DO_ISA
 	{
 		.name = "pc263",
 		.bustype = isa_bustype,
 		.model = pc263_model,
 	},
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+#if DO_PCI
 	{
 		.name = "pci263",
 		.devid = PCI_DEVICE_ID_AMPLICON_PCI263,
@@ -93,6 +96,18 @@
 #endif
 };
 
+/* test if ISA supported and this is an ISA board */
+static inline bool is_isa_board(const struct pc263_board *board)
+{
+	return DO_ISA && board->bustype == isa_bustype;
+}
+
+/* test if PCI supported and this is a PCI board */
+static inline bool is_pci_board(const struct pc263_board *board)
+{
+	return DO_PCI && board->bustype == pci_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -101,7 +116,7 @@
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(pc263_boards); i++)
-		if (pc263_boards[i].bustype == pci_bustype &&
+		if (is_pci_board(&pc263_boards[i]) &&
 		    pci_dev->device == pc263_boards[i].devid)
 			return &pc263_boards[i];
 	return NULL;
@@ -187,11 +202,9 @@
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 	char tmpbuf[40];
 
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
-	    thisboard->bustype == isa_bustype)
+	if (is_isa_board(thisboard))
 		snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase);
-	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
-		 thisboard->bustype == pci_bustype)
+	else if (is_pci_board(thisboard))
 		snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ",
 			 pci_name(pcidev));
 	else
@@ -212,7 +225,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* digital output subdevice */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -259,15 +272,13 @@
 	dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n");
 
 	/* Process options and reserve resources according to bus type. */
-	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
-	    thisboard->bustype == isa_bustype) {
+	if (is_isa_board(thisboard)) {
 		unsigned long iobase = it->options[0];
 		ret = pc263_request_region(dev, iobase, PC263_IO_SIZE);
 		if (ret < 0)
 			return ret;
 		return pc263_common_attach(dev, iobase);
-	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
-		   thisboard->bustype == pci_bustype) {
+	} else if (is_pci_board(thisboard)) {
 		struct pci_dev *pci_dev;
 
 		pci_dev = pc263_find_pci_dev(dev, it);
@@ -288,7 +299,7 @@
 static int __devinit pc263_attach_pci(struct comedi_device *dev,
 				      struct pci_dev *pci_dev)
 {
-	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI))
+	if (!DO_PCI)
 		return -EINVAL;
 
 	dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n",
@@ -310,15 +321,18 @@
 
 static void pc263_detach(struct comedi_device *dev)
 {
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	const struct pc263_board *thisboard = comedi_board(dev);
 
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	} else {
+	if (is_isa_board(thisboard)) {
 		if (dev->iobase)
 			release_region(dev->iobase, PC263_IO_SIZE);
+	} else if (is_pci_board(thisboard)) {
+		struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+		if (pcidev) {
+			if (dev->iobase)
+				comedi_pci_disable(pcidev);
+			pci_dev_put(pcidev);
+		}
 	}
 }
 
@@ -339,7 +353,7 @@
 	.num_names = ARRAY_SIZE(pc263_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
 	{0}
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index 8bf109e..1f65ec4 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -720,53 +720,31 @@
 	int err = 0;
 	unsigned int tmp;
 
-	/* Step 1: make sure trigger sources are trivially valid. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT | TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_EXT | TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src,
+					TRIG_COUNT | TRIG_EXT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* Step 2: make sure trigger sources are unique and mutually
-	 * compatible. */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* these tests are true if more than one _src bit is set */
-	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
-		err++;
-	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
-		err++;
-	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	/* There's only one external trigger signal (which makes these
-	 * tests easier).  Only one thing can use it. */
+	/* Step 2b : and mutually compatible */
+
+	/*
+	 * There's only one external trigger signal (which makes these
+	 * tests easier).  Only one thing can use it.
+	 */
 	tmp = 0;
 	if (cmd->start_src & TRIG_EXT)
 		tmp++;
@@ -775,7 +753,7 @@
 	if (cmd->stop_src & TRIG_EXT)
 		tmp++;
 	if (tmp > 1)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -1375,7 +1353,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* Analog output subdevice. */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
@@ -1523,7 +1501,7 @@
 	if (dev->subdevices) {
 		struct comedi_subdevice *s;
 
-		s = dev->subdevices + 0;
+		s = &dev->subdevices[0];
 		/* AO subdevice */
 		kfree(s->range_table_list);
 	}
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 66e74bd..bd8fb87 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -193,6 +193,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 #include "8255.h"
 
@@ -958,23 +959,11 @@
 	int err = 0;
 	unsigned int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.
-	 * Using the cmdtest ioctl, a user can create a valid cmd
-	 * and then have it executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
-	 * the command passes. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* Step 1: make sure trigger sources are trivially valid.
-	 * "invalid source" returned by comedilib to user mode process
-	 * if this fails. */
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
+	tmp = TRIG_TIMER | TRIG_INT;
 	if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) {
 		/*
 		 * For PCI230+ hardware version 2 onwards, allow external
@@ -990,46 +979,23 @@
 		 * scan_begin_src==TRIG_EXT support to be a bonus rather than a
 		 * guarantee!
 		 */
-		cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
-	} else {
-		cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT;
+		tmp |= TRIG_EXT;
 	}
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp);
 
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* Step 2: make sure trigger sources are unique and mutually compatible
-	 * "source conflict" returned by comedilib to user mode process
-	 * if this fails. */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* these tests are true if more than one _src bit is set */
-	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
-		err++;
-	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
-		err++;
-	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1610,75 +1576,45 @@
 	int err = 0;
 	unsigned int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.
-	 * Using the cmdtest ioctl, a user can create a valid cmd
-	 * and then have it executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4,5 or 0, depending on which tests
-	 * the command passes. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* Step 1: make sure trigger sources are trivially valid.
-	 * "invalid source" returned by comedilib to user mode process
-	 * if this fails. */
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	/* Unfortunately, we cannot trigger a scan off an external source
-	 * on the PCI260 board, since it uses the PPIC0 (DIO) input, which
-	 * isn't present on the PCI260.  For PCI260+ we can use the
-	 * EXTTRIG/EXTCONVCLK input on pin 17 instead. */
+	tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
 	if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) {
-		cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT
-		    | TRIG_EXT;
-	} else {
-		cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
+		/*
+		 * Unfortunately, we cannot trigger a scan off an external
+		 * source on the PCI260 board, since it uses the PPIC0 (DIO)
+		 * input, which isn't present on the PCI260.  For PCI260+
+		 * we can use the EXTTRIG/EXTCONVCLK input on pin 17 instead.
+		 */
+		tmp |= TRIG_EXT;
 	}
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* Step 2: make sure trigger sources are unique and mutually compatible
-	 * "source conflict" returned by comedilib to user mode process
-	 * if this fails. */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* these tests are true if more than one _src bit is set */
-	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
-		err++;
-	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
-		err++;
-	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	/* If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
-	 * set up to generate a fixed number of timed conversion pulses. */
+	/* Step 2b : and mutually compatible */
+
+	/*
+	 * If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
+	 * set up to generate a fixed number of timed conversion pulses.
+	 */
 	if ((cmd->scan_begin_src != TRIG_FOLLOW)
 	    && (cmd->convert_src != TRIG_TIMER))
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -2838,7 +2774,7 @@
 	if (rc)
 		return rc;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
@@ -2855,7 +2791,7 @@
 		s->do_cmdtest = &pci230_ai_cmdtest;
 		s->cancel = pci230_ai_cancel;
 	}
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* analog output subdevice */
 	if (thisboard->ao_chans > 0) {
 		s->type = COMEDI_SUBD_AO;
@@ -2878,7 +2814,7 @@
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital i/o subdevice */
 	if (thisboard->have_dio) {
 		rc = subdev_8255_init(dev, s, NULL,
@@ -2941,7 +2877,7 @@
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
 	if (dev->subdevices && thisboard->have_dio)
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
+		subdev_8255_cleanup(dev, &dev->subdevices[2]);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (pcidev) {
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 41ed857..070037c 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -447,7 +447,7 @@
 	else if (irq == 0)
 		printk(KERN_DEBUG "comedi%d: no irq\n", dev->minor);
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* pwm output subdevice */
 	s->type = COMEDI_SUBD_AO;	/*  Not sure what to put here */
 	s->subdev_flags = SDF_WRITEABLE;
@@ -458,7 +458,7 @@
 	s->maxdata = 500;
 	s->range_table = &range_bipolar10;	/*  A suitable lie */
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* encoder (counter) subdevice */
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
@@ -468,7 +468,7 @@
 	s->maxdata = 0xffffff;
 	s->range_table = &range_unknown;
 
-	/*	s = dev->subdevices + 2; */
+	/*	s = &dev->subdevices[2]; */
 	/* pwm output subdevice */
 	/*	s->type = COMEDI_SUBD_COUNTER;  // Not sure what to put here */
 	/*	s->subdev_flags = SDF_WRITEABLE; */
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 58d4529..6d81d8b 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -46,6 +46,7 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 
 #define DAS16CS_SIZE			18
@@ -169,47 +170,26 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and
-	 * mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -478,7 +458,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* analog input subdevice */
 	s->type		= COMEDI_SUBD_AI;
@@ -491,7 +471,7 @@
 	s->do_cmd	= das16cs_ai_cmd;
 	s->do_cmdtest	= das16cs_ai_cmdtest;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* analog output subdevice */
 	if (thisboard->n_ao_chans) {
 		s->type		= COMEDI_SUBD_AO;
@@ -505,7 +485,7 @@
 		s->type		= COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital i/o subdevice */
 	s->type		= COMEDI_SUBD_DIO;
 	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 2b6a637c..de21a26 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -45,11 +45,7 @@
   The boards may be autocalibrated using the comedi_calibrate
   utility.
 
-Configuration options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration options: not applicable, uses PCI auto config
 
 For commands, the scanned channels must be consecutive
 (i.e. 4-5-6-7, 2-3-4,...), and must all have the same
@@ -807,58 +803,35 @@
 	int tmp;
 	int i, gain, start_chan;
 
-	/* step 1: trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_NOW | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	/*  make sure trigger sources are compatible with each other */
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
-		err++;
+		err |= -EINVAL;
 	if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
-		err++;
+		err |= -EINVAL;
 	if (cmd->start_src == TRIG_EXT &&
 	    (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -1083,43 +1056,24 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1501,69 +1455,45 @@
 	return IRQ_HANDLED;
 }
 
-static struct pci_dev *cb_pcidas_find_pci_device(struct comedi_device *dev,
-						 struct comedi_devconfig *it)
+static const void *cb_pcidas_find_boardinfo(struct comedi_device *dev,
+					    struct pci_dev *pcidev)
 {
 	const struct cb_pcidas_board *thisboard;
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
 	int i;
 
-	for_each_pci_dev(pcidev) {
-		/*  is it not a computer boards card? */
-		if (pcidev->vendor != PCI_VENDOR_ID_CB)
-			continue;
-		/*  loop through cards supported by this driver */
-		for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) {
-			thisboard = &cb_pcidas_boards[i];
-			if (thisboard->device_id != pcidev->device)
-				continue;
-			/*  was a particular bus/slot requested? */
-			if (bus || slot) {
-				/*  are we on the wrong bus/slot? */
-				if (pcidev->bus->number != bus ||
-				    PCI_SLOT(pcidev->devfn) != slot) {
-					continue;
-				}
-			}
-			dev_dbg(dev->class_dev,
-				"Found %s on bus %i, slot %i\n",
-				thisboard->name,
-				pcidev->bus->number, PCI_SLOT(pcidev->devfn));
-			dev->board_ptr = thisboard;
-			return pcidev;
-		}
+	for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) {
+		thisboard = &cb_pcidas_boards[i];
+		if (thisboard->device_id == pcidev->device)
+			return thisboard;
 	}
-	dev_err(dev->class_dev, "No supported card found\n");
 	return NULL;
 }
 
-static int cb_pcidas_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it)
+static int cb_pcidas_attach_pci(struct comedi_device *dev,
+				struct pci_dev *pcidev)
 {
 	const struct cb_pcidas_board *thisboard;
 	struct cb_pcidas_private *devpriv;
-	struct pci_dev *pcidev;
 	struct comedi_subdevice *s;
 	int i;
 	int ret;
 
-	if (alloc_private(dev, sizeof(struct cb_pcidas_private)) < 0)
-		return -ENOMEM;
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	thisboard = cb_pcidas_find_boardinfo(dev, pcidev);
+	if (!thisboard)
+		return -ENODEV;
+	dev->board_ptr  = thisboard;
+	dev->board_name = thisboard->name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
 	devpriv = dev->private;
 
-	pcidev = cb_pcidas_find_pci_device(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-	thisboard = comedi_board(dev);
-
-	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
-		dev_err(dev->class_dev,
-			"Failed to enable PCI device and request regions\n");
-		return -EIO;
-	}
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
 
 	devpriv->s5933_config = pci_resource_start(pcidev, 0);
 	devpriv->control_status = pci_resource_start(pcidev, 1);
@@ -1584,13 +1514,11 @@
 	}
 	dev->irq = pcidev->irq;
 
-	dev->board_name = thisboard->name;
-
 	ret = comedi_alloc_subdevices(dev, 7);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog input subdevice */
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
@@ -1607,7 +1535,7 @@
 	s->cancel = cb_pcidas_cancel;
 
 	/* analog output subdevice */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (thisboard->ao_nchan) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
@@ -1634,14 +1562,14 @@
 	}
 
 	/* 8255 */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	ret = subdev_8255_init(dev, s, NULL,
 			       devpriv->pacer_counter_dio + DIO_8255);
 	if (ret)
 		return ret;
 
 	/*  serial EEPROM, */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_MEMORY;
 	s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
 	s->n_chan = 256;
@@ -1649,7 +1577,7 @@
 	s->insn_read = eeprom_read_insn;
 
 	/*  8800 caldac */
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	s->type = COMEDI_SUBD_CALIB;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	s->n_chan = NUM_CHANNELS_8800;
@@ -1660,7 +1588,7 @@
 		caldac_8800_write(dev, i, s->maxdata / 2);
 
 	/*  trim potentiometer */
-	s = dev->subdevices + 5;
+	s = &dev->subdevices[5];
 	s->type = COMEDI_SUBD_CALIB;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	if (thisboard->trimpot == AD7376) {
@@ -1676,7 +1604,7 @@
 		cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
 
 	/*  dac08 caldac */
-	s = dev->subdevices + 6;
+	s = &dev->subdevices[6];
 	if (thisboard->has_dac08) {
 		s->type = COMEDI_SUBD_CALIB;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
@@ -1698,7 +1626,10 @@
 	outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
 	     devpriv->s5933_config + AMCC_OP_REG_INTCSR);
 
-	return 1;
+	dev_info(dev->class_dev, "%s: %s attached\n",
+		dev->driver->driver_name, dev->board_name);
+
+	return 0;
 }
 
 static void cb_pcidas_detach(struct comedi_device *dev)
@@ -1715,18 +1646,17 @@
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
+		subdev_8255_cleanup(dev, &dev->subdevices[2]);
 	if (pcidev) {
 		if (devpriv->s5933_config)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver cb_pcidas_driver = {
 	.driver_name	= "cb_pcidas",
 	.module		= THIS_MODULE,
-	.attach		= cb_pcidas_attach,
+	.attach_pci	= cb_pcidas_attach_pci,
 	.detach		= cb_pcidas_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 65cbaab..0472a90 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1348,7 +1348,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog input subdevice */
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
@@ -1379,7 +1379,7 @@
 	}
 
 	/* analog output subdevice */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (board(dev)->ao_nchan) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags =
@@ -1401,7 +1401,7 @@
 	}
 
 	/*  digital input */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	if (board(dev)->layout == LAYOUT_64XX) {
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
@@ -1414,7 +1414,7 @@
 
 	/*  digital output */
 	if (board(dev)->layout == LAYOUT_64XX) {
-		s = dev->subdevices + 3;
+		s = &dev->subdevices[3];
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 		s->n_chan = 4;
@@ -1425,7 +1425,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/* 8255 */
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	if (board(dev)->has_8255) {
 		if (board(dev)->layout == LAYOUT_4020) {
 			dio_8255_iobase =
@@ -1442,7 +1442,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/*  8 channel dio for 60xx */
-	s = dev->subdevices + 5;
+	s = &dev->subdevices[5];
 	if (board(dev)->layout == LAYOUT_60XX) {
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
@@ -1455,7 +1455,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/*  caldac */
-	s = dev->subdevices + 6;
+	s = &dev->subdevices[6];
 	s->type = COMEDI_SUBD_CALIB;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	s->n_chan = 8;
@@ -1469,7 +1469,7 @@
 		caldac_write(dev, i, s->maxdata / 2);
 
 	/*  2 channel ad8402 potentiometer */
-	s = dev->subdevices + 7;
+	s = &dev->subdevices[7];
 	if (board(dev)->layout == LAYOUT_64XX) {
 		s->type = COMEDI_SUBD_CALIB;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
@@ -1483,7 +1483,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/* serial EEPROM, if present */
-	s = dev->subdevices + 8;
+	s = &dev->subdevices[8];
 	if (readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) {
 		s->type = COMEDI_SUBD_MEMORY;
 		s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
@@ -1494,7 +1494,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/*  user counter subd XXX */
-	s = dev->subdevices + 9;
+	s = &dev->subdevices[9];
 	s->type = COMEDI_SUBD_UNUSED;
 
 	return 0;
@@ -1847,7 +1847,7 @@
 		}
 	}
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 4);
+		subdev_8255_cleanup(dev, &dev->subdevices[4]);
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
@@ -2108,74 +2108,50 @@
 		      struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 	unsigned int tmp_arg, tmp_arg2;
 	int i;
 	int aref;
 	unsigned int triggers;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
 
-	tmp = cmd->scan_begin_src;
 	triggers = TRIG_TIMER;
 	if (board(dev)->layout == LAYOUT_4020)
 		triggers |= TRIG_OTHER;
 	else
 		triggers |= TRIG_FOLLOW;
-	cmd->scan_begin_src &= triggers;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, triggers);
 
-	tmp = cmd->convert_src;
 	triggers = TRIG_TIMER;
 	if (board(dev)->layout == LAYOUT_4020)
 		triggers |= TRIG_NOW;
 	else
 		triggers |= TRIG_EXT;
-	cmd->convert_src &= triggers;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, triggers);
 
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src,
+					TRIG_COUNT | TRIG_EXT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/*  uniqueness check */
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_OTHER &&
-	    cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT &&
-	    cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	/*  compatibility check */
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER)
-		err++;
+		err |= -EINVAL;
 	if (cmd->stop_src != TRIG_COUNT &&
 	    cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -3466,55 +3442,33 @@
 		      struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 	unsigned int tmp_arg;
 	int i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/*  uniqueness check */
-	if (cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
 
-	/*  compatibility check */
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER)
-		err++;
+		err |= -EINVAL;
 	if (cmd->stop_src != TRIG_COUNT &&
 	    cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 12660a3..aef946d 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -48,6 +48,7 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "8255.h"
 
 /* PCI vendor number of ComputerBoards */
@@ -56,14 +57,6 @@
 /* maximum number of ao channels for supported boards */
 #define MAX_AO_CHANNELS 8
 
-/* PCI-DDA base addresses */
-#define DIGITALIO_BADRINDEX	2
-	/*  DIGITAL I/O is pci_dev->resource[2] */
-#define DIGITALIO_SIZE 8
-	/*  DIGITAL I/O uses 8 I/O port addresses */
-#define DAC_BADRINDEX	3
-	/*  DAC is pci_dev->resource[3] */
-
 /* Digital I/O registers */
 #define PORT1A 0		/*  PORT 1A DATA */
 
@@ -203,11 +196,6 @@
 };
 
 /*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr)
-
-/*
  * this structure is for data unique to this hardware driver.  If
  * several hardware drivers keep similar information in this structure,
  * feel free to suggest moving the variable to the struct comedi_device
@@ -230,164 +218,6 @@
 };
 
 /*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct cb_pcidda_private *)dev->private)
-
-/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
-static int cb_pcidda_ao_winsn(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-
-/* static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct *comedi_subdevice *s);*/
-/* static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); */
-/* static int cb_pcidda_ns_to_timer(unsigned int *ns,int *round); */
-
-static unsigned int cb_pcidda_serial_in(struct comedi_device *dev);
-static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
-				 unsigned int num_bits);
-static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
-					  unsigned int address);
-static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
-				unsigned int range);
-
-static struct pci_dev *cb_pcidda_find_pci_dev(struct comedi_device *dev,
-					      struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_CB)
-			continue;
-
-		for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) {
-			if (cb_pcidda_boards[i].device_id != pcidev->device)
-				continue;
-			dev->board_ptr = cb_pcidda_boards + i;
-			return pcidev;
-		}
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.
- */
-static int cb_pcidda_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *s;
-	int index;
-	int ret;
-
-/*
- * Allocate the private structure area.
- */
-	if (alloc_private(dev, sizeof(struct cb_pcidda_private)) < 0)
-		return -ENOMEM;
-
-	pcidev = cb_pcidda_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	/*
-	 * Enable PCI device and request regions.
-	 */
-	if (comedi_pci_enable(pcidev, thisboard->name)) {
-		dev_err(dev->class_dev,
-			"cb_pcidda: failed to enable PCI device and request regions\n");
-		return -EIO;
-	}
-
-/*
- * Allocate the I/O ports.
- */
-	devpriv->digitalio = pci_resource_start(pcidev, DIGITALIO_BADRINDEX);
-	devpriv->dac = pci_resource_start(pcidev, DAC_BADRINDEX);
-	dev->iobase = devpriv->dac;
-
-/*
- * Warn about the status of the driver.
- */
-	if (thisboard->status == 2)
-		printk
-		    ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. "
-		     "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. "
-		     "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");
-
-/*
- * Initialize dev->board_name.
- */
-	dev->board_name = thisboard->name;
-
-	ret = comedi_alloc_subdevices(dev, 3);
-	if (ret)
-		return ret;
-
-	s = dev->subdevices + 0;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->ao_chans;
-	s->maxdata = (1 << thisboard->ao_bits) - 1;
-	s->range_table = thisboard->ranges;
-	s->insn_write = cb_pcidda_ao_winsn;
-
-	/* s->subdev_flags |= SDF_CMD_READ; */
-	/* s->do_cmd = cb_pcidda_ai_cmd; */
-	/* s->do_cmdtest = cb_pcidda_ai_cmdtest; */
-
-	/*  two 8255 digital io subdevices */
-	s = dev->subdevices + 1;
-	subdev_8255_init(dev, s, NULL, devpriv->digitalio);
-	s = dev->subdevices + 2;
-	subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A);
-
-	dev_dbg(dev->class_dev, "eeprom:\n");
-	for (index = 0; index < EEPROM_SIZE; index++) {
-		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
-		dev_dbg(dev->class_dev, "%i:0x%x\n", index,
-			devpriv->eeprom_data[index]);
-	}
-
-	/*  set calibrations dacs */
-	for (index = 0; index < thisboard->ao_chans; index++)
-		cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);
-
-	return 1;
-}
-
-static void cb_pcidda_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-	if (dev->subdevices) {
-		subdev_8255_cleanup(dev, dev->subdevices + 1);
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
-	}
-}
-
-/*
  * I will program this later... ;-)
  */
 #if 0
@@ -418,56 +248,26 @@
 	int err = 0;
 	int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.
-	 * Using the cmdtest ioctl, a user can create a valid cmd
-	 * and then have it executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
-	 * the command passes. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* step 1: make sure trigger sources are trivially valid */
-
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually
-	 * compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER
-	    && cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -581,59 +381,10 @@
 }
 #endif
 
-static int cb_pcidda_ao_winsn(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data)
-{
-	unsigned int command;
-	unsigned int channel, range;
-
-	channel = CR_CHAN(insn->chanspec);
-	range = CR_RANGE(insn->chanspec);
-
-	/*  adjust calibration dacs if range has changed */
-	if (range != devpriv->ao_range[channel])
-		cb_pcidda_calibrate(dev, channel, range);
-
-	/* output channel configuration */
-	command = NOSU | ENABLEDAC;
-
-	/* output channel range */
-	switch (range) {
-	case 0:
-		command |= BIP | RANGE10V;
-		break;
-	case 1:
-		command |= BIP | RANGE5V;
-		break;
-	case 2:
-		command |= BIP | RANGE2V5;
-		break;
-	case 3:
-		command |= UNIP | RANGE10V;
-		break;
-	case 4:
-		command |= UNIP | RANGE5V;
-		break;
-	case 5:
-		command |= UNIP | RANGE2V5;
-		break;
-	}
-
-	/* output channel specification */
-	command |= channel << 2;
-	outw(command, devpriv->dac + DACONTROL);
-
-	/* write data */
-	outw(data[0], devpriv->dac + DADATA + channel * 2);
-
-	/* return the number of samples read/written */
-	return 1;
-}
-
 /* lowlevel read from eeprom */
 static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
 {
+	struct cb_pcidda_private *devpriv = dev->private;
 	unsigned int value = 0;
 	int i;
 	const int value_width = 16;	/*  number of bits wide values are */
@@ -651,6 +402,7 @@
 static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
 				 unsigned int num_bits)
 {
+	struct cb_pcidda_private *devpriv = dev->private;
 	int i;
 
 	for (i = 1; i <= num_bits; i++) {
@@ -667,6 +419,7 @@
 static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
 					  unsigned int address)
 {
+	struct cb_pcidda_private *devpriv = dev->private;
 	unsigned int i;
 	unsigned int cal2_bits;
 	unsigned int value;
@@ -703,6 +456,7 @@
 				   unsigned int caldac, unsigned int channel,
 				   unsigned int value)
 {
+	struct cb_pcidda_private *devpriv = dev->private;
 	unsigned int cal2_bits;
 	unsigned int i;
 	/* caldacs use 3 bit channel specification */
@@ -797,6 +551,7 @@
 static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
 				unsigned int range)
 {
+	struct cb_pcidda_private *devpriv = dev->private;
 	unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
 
 	/* remember range so we can tell when we need to readjust calibration */
@@ -827,10 +582,164 @@
 			       fine_gain_channel(channel), fine_gain);
 }
 
+static int cb_pcidda_ao_winsn(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data)
+{
+	struct cb_pcidda_private *devpriv = dev->private;
+	unsigned int command;
+	unsigned int channel, range;
+
+	channel = CR_CHAN(insn->chanspec);
+	range = CR_RANGE(insn->chanspec);
+
+	/*  adjust calibration dacs if range has changed */
+	if (range != devpriv->ao_range[channel])
+		cb_pcidda_calibrate(dev, channel, range);
+
+	/* output channel configuration */
+	command = NOSU | ENABLEDAC;
+
+	/* output channel range */
+	switch (range) {
+	case 0:
+		command |= BIP | RANGE10V;
+		break;
+	case 1:
+		command |= BIP | RANGE5V;
+		break;
+	case 2:
+		command |= BIP | RANGE2V5;
+		break;
+	case 3:
+		command |= UNIP | RANGE10V;
+		break;
+	case 4:
+		command |= UNIP | RANGE5V;
+		break;
+	case 5:
+		command |= UNIP | RANGE2V5;
+		break;
+	}
+
+	/* output channel specification */
+	command |= channel << 2;
+	outw(command, devpriv->dac + DACONTROL);
+
+	/* write data */
+	outw(data[0], devpriv->dac + DADATA + channel * 2);
+
+	/* return the number of samples read/written */
+	return 1;
+}
+
+static const void *cb_pcidda_find_boardinfo(struct comedi_device *dev,
+					    struct pci_dev *pcidev)
+{
+	const struct cb_pcidda_board *thisboard;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) {
+		thisboard = &cb_pcidda_boards[i];
+		if (thisboard->device_id != pcidev->device)
+			return thisboard;
+	}
+	return NULL;
+}
+
+static int cb_pcidda_attach_pci(struct comedi_device *dev,
+				struct pci_dev *pcidev)
+{
+	const struct cb_pcidda_board *thisboard;
+	struct cb_pcidda_private *devpriv;
+	struct comedi_subdevice *s;
+	int index;
+	int ret;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	thisboard = cb_pcidda_find_boardinfo(dev, pcidev);
+	if (!pcidev)
+		return -ENODEV;
+	dev->board_ptr = thisboard;
+	dev->board_name = thisboard->name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+
+	devpriv->digitalio = pci_resource_start(pcidev, 2);
+	devpriv->dac = pci_resource_start(pcidev, 3);
+	dev->iobase = devpriv->dac;
+
+	if (thisboard->status == 2)
+		printk
+		    ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. "
+		     "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. "
+		     "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");
+
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
+
+	s = &dev->subdevices[0];
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = thisboard->ao_chans;
+	s->maxdata = (1 << thisboard->ao_bits) - 1;
+	s->range_table = thisboard->ranges;
+	s->insn_write = cb_pcidda_ao_winsn;
+
+	/* s->subdev_flags |= SDF_CMD_READ; */
+	/* s->do_cmd = cb_pcidda_ai_cmd; */
+	/* s->do_cmdtest = cb_pcidda_ai_cmdtest; */
+
+	/*  two 8255 digital io subdevices */
+	s = &dev->subdevices[1];
+	subdev_8255_init(dev, s, NULL, devpriv->digitalio);
+	s = &dev->subdevices[2];
+	subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A);
+
+	dev_dbg(dev->class_dev, "eeprom:\n");
+	for (index = 0; index < EEPROM_SIZE; index++) {
+		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
+		dev_dbg(dev->class_dev, "%i:0x%x\n", index,
+			devpriv->eeprom_data[index]);
+	}
+
+	/*  set calibrations dacs */
+	for (index = 0; index < thisboard->ao_chans; index++)
+		cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);
+
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+
+	return 0;
+}
+
+static void cb_pcidda_detach(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+	if (dev->subdevices) {
+		subdev_8255_cleanup(dev, &dev->subdevices[1]);
+		subdev_8255_cleanup(dev, &dev->subdevices[2]);
+	}
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
+	}
+}
+
 static struct comedi_driver cb_pcidda_driver = {
 	.driver_name	= "cb_pcidda",
 	.module		= THIS_MODULE,
-	.attach		= cb_pcidda_attach,
+	.attach_pci	= cb_pcidda_attach_pci,
 	.detach		= cb_pcidda_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
deleted file mode 100644
index e370d0d..0000000
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
-    comedi/drivers/cb_pcidio.c
-    A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing)
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: cb_pcidio
-Description: ComputerBoards' DIO boards with PCI interface
-Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H
-Author: Yoshiya Matsuzaka
-Updated: Mon, 29 Oct 2007 15:40:47 +0000
-Status: experimental
-
-This driver has been modified from skel.c of comedi-0.7.70.
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first available PCI device will
-  be used.
-
-Passing a zero for an option is the same as leaving it unspecified.
-*/
-
-/*------------------------------ HEADER FILES ---------------------------------*/
-#include "../comedidev.h"
-#include "8255.h"
-
-/*-------------------------- MACROS and DATATYPES -----------------------------*/
-#define PCI_VENDOR_ID_CB	0x1307
-
-/*
- * Board descriptions for two imaginary boards.  Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
-struct pcidio_board {
-	const char *name;	/*  name of the board */
-	int dev_id;
-	int n_8255;		/*  number of 8255 chips on board */
-
-	/*  indices of base address regions */
-	int pcicontroler_badrindex;
-	int dioregs_badrindex;
-};
-
-static const struct pcidio_board pcidio_boards[] = {
-	{
-	 .name = "pci-dio24",
-	 .dev_id = 0x0028,
-	 .n_8255 = 1,
-	 .pcicontroler_badrindex = 1,
-	 .dioregs_badrindex = 2,
-	 },
-	{
-	 .name = "pci-dio24h",
-	 .dev_id = 0x0014,
-	 .n_8255 = 1,
-	 .pcicontroler_badrindex = 1,
-	 .dioregs_badrindex = 2,
-	 },
-	{
-	 .name = "pci-dio48h",
-	 .dev_id = 0x000b,
-	 .n_8255 = 2,
-	 .pcicontroler_badrindex = 0,
-	 .dioregs_badrindex = 1,
-	 },
-};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pcidio_board *)dev->board_ptr)
-
-static struct pci_dev *pcidio_find_pci_dev(struct comedi_device *dev,
-					   struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-				slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_CB)
-			continue;
-		for (i = 0; i < ARRAY_SIZE(pcidio_boards); i++) {
-			if (pcidio_boards[i].dev_id != pcidev->device)
-				continue;
-
-			dev->board_ptr = pcidio_boards + i;
-			return pcidev;
-		}
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	int i;
-	int ret;
-
-	pcidev = pcidio_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
-
-	if (comedi_pci_enable(pcidev, thisboard->name))
-		return -EIO;
-
-	dev->iobase = pci_resource_start(pcidev, thisboard->dioregs_badrindex);
-
-	ret = comedi_alloc_subdevices(dev, thisboard->n_8255);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < thisboard->n_8255; i++) {
-		subdev_8255_init(dev, dev->subdevices + i,
-				 NULL, dev->iobase + i * 4);
-		dev_dbg(dev->class_dev, "subdev %d: base = 0x%lx\n", i,
-			dev->iobase + i * 4);
-	}
-
-	return 1;
-}
-
-static void pcidio_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-	if (dev->subdevices) {
-		int i;
-		for (i = 0; i < thisboard->n_8255; i++)
-			subdev_8255_cleanup(dev, dev->subdevices + i);
-	}
-}
-
-static struct comedi_driver cb_pcidio_driver = {
-	.driver_name	= "cb_pcidio",
-	.module		= THIS_MODULE,
-	.attach		= pcidio_attach,
-	.detach		= pcidio_detach,
-};
-
-static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev,
-						const struct pci_device_id *ent)
-{
-	return comedi_pci_auto_config(dev, &cb_pcidio_driver);
-}
-
-static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table);
-
-static struct pci_driver cb_pcidio_pci_driver = {
-	.name		= "cb_pcidio",
-	.id_table	= cb_pcidio_pci_table,
-	.probe		= cb_pcidio_pci_probe,
-	.remove		= __devexit_p(cb_pcidio_pci_remove),
-};
-module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index c632a89..9515b69 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -119,11 +119,6 @@
 };
 
 /*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
-
-/*
  * this structure is for data unique to this hardware driver.  If
  * several hardware drivers keep similar information in this structure,
  * feel free to suggest moving the variable to the struct comedi_device
@@ -138,160 +133,6 @@
 };
 
 /*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct cb_pcimdas_private *)dev->private)
-
-static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
-static struct pci_dev *cb_pcimdas_find_pci_dev(struct comedi_device *dev,
-					       struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-				slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
-			continue;
-
-		for (i = 0; i < ARRAY_SIZE(cb_pcimdas_boards); i++) {
-			if (cb_pcimdas_boards[i].device_id != pcidev->device)
-				continue;
-
-			dev->board_ptr = cb_pcimdas_boards + i;
-			return pcidev;
-		}
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int cb_pcimdas_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *s;
-	unsigned long iobase_8255;
-	int ret;
-
-/*
- * Allocate the private structure area.
- */
-	if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0)
-		return -ENOMEM;
-
-	pcidev = cb_pcimdas_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
-
-	/*  Warn about non-tested features */
-	switch (thisboard->device_id) {
-	case 0x56:
-		break;
-	default:
-		dev_dbg(dev->class_dev, "THIS CARD IS UNSUPPORTED.\n");
-		dev_dbg(dev->class_dev,
-			"PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
-	}
-
-	if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
-		dev_err(dev->class_dev,
-			"Failed to enable PCI device and request regions\n");
-		return -EIO;
-	}
-
-	dev->iobase = pci_resource_start(pcidev, 2);
-	devpriv->BADR3 = pci_resource_start(pcidev, 3);
-	iobase_8255 = pci_resource_start(pcidev, 4);
-
-/* Dont support IRQ yet */
-/*  get irq */
-/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */
-/* { */
-/* printk(" unable to allocate irq %u\n", pcidev->irq); */
-/* return -EINVAL; */
-/* } */
-/* dev->irq = pcidev->irq; */
-
-	/* Initialize dev->board_name */
-	dev->board_name = thisboard->name;
-
-	ret = comedi_alloc_subdevices(dev, 3);
-	if (ret)
-		return ret;
-
-	s = dev->subdevices + 0;
-	/* dev->read_subdev=s; */
-	/*  analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND;
-	s->n_chan = thisboard->ai_se_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = &range_unknown;
-	s->len_chanlist = 1;	/*  This is the maximum chanlist length that */
-	/*  the board can handle */
-	s->insn_read = cb_pcimdas_ai_rinsn;
-
-	s = dev->subdevices + 1;
-	/*  analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->ao_nchan;
-	s->maxdata = 1 << thisboard->ao_bits;
-	/* ranges are hardware settable, but not software readable. */
-	s->range_table = &range_unknown;
-	s->insn_write = &cb_pcimdas_ao_winsn;
-	s->insn_read = &cb_pcimdas_ao_rinsn;
-
-	s = dev->subdevices + 2;
-	/* digital i/o subdevice */
-	if (thisboard->has_dio)
-		subdev_8255_init(dev, s, NULL, iobase_8255);
-	else
-		s->type = COMEDI_SUBD_UNUSED;
-
-	return 1;
-}
-
-static void cb_pcimdas_detach(struct comedi_device *dev)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (pcidev) {
-		if (dev->iobase)
-			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
-	}
-}
-
-/*
  * "instructions" read/write data in "one-shot" or "software-triggered"
  * mode.
  */
@@ -299,6 +140,8 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	const struct cb_pcimdas_board *thisboard = comedi_board(dev);
+	struct cb_pcimdas_private *devpriv = dev->private;
 	int n, i;
 	unsigned int d;
 	unsigned int busy;
@@ -368,6 +211,7 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct cb_pcimdas_private *devpriv = dev->private;
 	int i;
 	int chan = CR_CHAN(insn->chanspec);
 
@@ -397,6 +241,7 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct cb_pcimdas_private *devpriv = dev->private;
 	int i;
 	int chan = CR_CHAN(insn->chanspec);
 
@@ -406,10 +251,124 @@
 	return i;
 }
 
+static const void *cb_pcimdas_find_boardinfo(struct comedi_device *dev,
+					     struct pci_dev *pcidev)
+{
+	const struct cb_pcimdas_board *thisboard;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cb_pcimdas_boards); i++) {
+		thisboard = &cb_pcimdas_boards[i];
+		if (thisboard->device_id == pcidev->device)
+			return thisboard;
+	}
+	return NULL;
+}
+
+static int cb_pcimdas_attach_pci(struct comedi_device *dev,
+				 struct pci_dev *pcidev)
+{
+	const struct cb_pcimdas_board *thisboard;
+	struct cb_pcimdas_private *devpriv;
+	struct comedi_subdevice *s;
+	unsigned long iobase_8255;
+	int ret;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	thisboard = cb_pcimdas_find_boardinfo(dev, pcidev);
+	if (!thisboard)
+		return -ENODEV;
+	dev->board_ptr = thisboard;
+	dev->board_name = thisboard->name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
+
+	/*  Warn about non-tested features */
+	switch (thisboard->device_id) {
+	case 0x56:
+		break;
+	default:
+		dev_dbg(dev->class_dev, "THIS CARD IS UNSUPPORTED.\n");
+		dev_dbg(dev->class_dev,
+			"PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
+	}
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+
+	dev->iobase = pci_resource_start(pcidev, 2);
+	devpriv->BADR3 = pci_resource_start(pcidev, 3);
+	iobase_8255 = pci_resource_start(pcidev, 4);
+
+/* Dont support IRQ yet */
+/*  get irq */
+/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */
+/* { */
+/* printk(" unable to allocate irq %u\n", pcidev->irq); */
+/* return -EINVAL; */
+/* } */
+/* dev->irq = pcidev->irq; */
+
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
+
+	s = &dev->subdevices[0];
+	/* dev->read_subdev=s; */
+	/*  analog input subdevice */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND;
+	s->n_chan = thisboard->ai_se_chans;
+	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->range_table = &range_unknown;
+	s->len_chanlist = 1;	/*  This is the maximum chanlist length that */
+	/*  the board can handle */
+	s->insn_read = cb_pcimdas_ai_rinsn;
+
+	s = &dev->subdevices[1];
+	/*  analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = thisboard->ao_nchan;
+	s->maxdata = 1 << thisboard->ao_bits;
+	/* ranges are hardware settable, but not software readable. */
+	s->range_table = &range_unknown;
+	s->insn_write = &cb_pcimdas_ao_winsn;
+	s->insn_read = &cb_pcimdas_ao_rinsn;
+
+	s = &dev->subdevices[2];
+	/* digital i/o subdevice */
+	if (thisboard->has_dio)
+		subdev_8255_init(dev, s, NULL, iobase_8255);
+	else
+		s->type = COMEDI_SUBD_UNUSED;
+
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+
+	return 0;
+}
+
+static void cb_pcimdas_detach(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
+	}
+}
+
 static struct comedi_driver cb_pcimdas_driver = {
 	.driver_name	= "cb_pcimdas",
 	.module		= THIS_MODULE,
-	.attach		= cb_pcimdas_attach,
+	.attach_pci	= cb_pcimdas_attach_pci,
 	.detach		= cb_pcimdas_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index a801461..ba9f059 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -57,12 +57,7 @@
     then issue one comedi_data_read() on any channel on the AO subdevice
     to initiate the simultaneous XFER.
 
-Configuration Options:
-  [0] PCI bus (optional)
-  [1] PCI slot (optional)
-  [2] analog output range jumper setting
-      0 == +/- 5 V
-      1 == +/- 10 V
+Configuration Options: not applicable, uses PCI auto config
 */
 
 /*
@@ -93,337 +88,133 @@
 #define PCI_ID_PCIM_DDA06_16		0x0053
 
 /*
- * This is straight from skel.c -- I did this in case this source file
- * will someday support more than 1 board...
+ * Register map, 8-bit access only
  */
-struct board_struct {
-	const char *name;
-	unsigned short device_id;
-	int ao_chans;
-	int ao_bits;
-	int dio_chans;
-	int dio_method;
-	/* how many bytes into the BADR are the DIO ports */
-	int dio_offset;
-	int regs_badrindex;	/* IO Region for the control, analog output,
-				   and DIO registers */
-	int reg_sz;		/* number of bytes of registers in io region */
-};
+#define PCIMDDA_DA_CHAN(x)		(0x00 + (x) * 2)
+#define PCIMDDA_8255_BASE_REG		0x0c
 
-enum DIO_METHODS {
-	DIO_NONE = 0,
-	DIO_8255,
-	DIO_INTERNAL		/* unimplemented */
-};
+#define MAX_AO_READBACK_CHANNELS	6
 
-static const struct board_struct boards[] = {
-	{
-	 .name = "cb_pcimdda06-16",
-	 .device_id = PCI_ID_PCIM_DDA06_16,
-	 .ao_chans = 6,
-	 .ao_bits = 16,
-	 .dio_chans = 24,
-	 .dio_method = DIO_8255,
-	 .dio_offset = 12,
-	 .regs_badrindex = 3,
-	 .reg_sz = 16,
-	 }
-};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard    ((const struct board_struct *)dev->board_ptr)
-
-#define REG_SZ (thisboard->reg_sz)
-#define REGS_BADRINDEX (thisboard->regs_badrindex)
-
-/*
- * this structure is for data unique to this hardware driver.  If
- * several hardware drivers keep similar information in this structure,
- * feel free to suggest moving the variable to the struct comedi_device
- * struct.
- */
-struct board_private_struct {
-	unsigned long registers;	/* set by probe */
-	unsigned long dio_registers;
-	char attached_to_8255;	/* boolean */
-	/* would be useful for a PCI device */
-	struct pci_dev *pci_dev;
-
-#define MAX_AO_READBACK_CHANNELS 6
-	/* Used for AO readback */
+struct cb_pcimdda_private {
 	unsigned int ao_readback[MAX_AO_READBACK_CHANNELS];
-
 };
 
-/*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct board_private_struct *)dev->private)
-
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data);
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data);
-
-/*---------------------------------------------------------------------------
-  HELPER FUNCTION DECLARATIONS
------------------------------------------------------------------------------*/
-
-/* returns a maxdata value for a given n_bits */
-static inline unsigned int figure_out_maxdata(int bits)
+static int cb_pcimdda_ao_winsn(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
-	return ((unsigned int)1 << bits) - 1;
-}
+	struct cb_pcimdda_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
+	unsigned int val = 0;
+	int i;
 
-/*
- *  Probes for a supported device.
- *
- *  Prerequisite: private be allocated already inside dev
- *
- *  If the device is found, it returns 0 and has the following side effects:
- *
- *  o  assigns a struct pci_dev * to dev->private->pci_dev
- *  o  assigns a struct board * to dev->board_ptr
- *  o  sets dev->private->registers
- *  o  sets dev->private->dio_registers
- *
- *  Otherwise, returns a -errno on error
- */
-static int probe(struct comedi_device *dev, const struct comedi_devconfig *it);
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
 
-/*---------------------------------------------------------------------------
-  FUNCTION DEFINITIONS
------------------------------------------------------------------------------*/
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	int err;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- * if this function fails (returns negative) then the private area is
- * kfree'd by comedi
- */
-	if (alloc_private(dev, sizeof(struct board_private_struct)) < 0)
-		return -ENOMEM;
-
-/*
- * If you can probe the device to determine what device in a series
- * it is, this is the place to do it.  Otherwise, dev->board_ptr
- * should already be initialized.
- */
-	err = probe(dev, it);
-	if (err)
-		return err;
-
-/* Output some info */
-	printk("comedi%d: %s: ", dev->minor, thisboard->name);
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
-
-	err = comedi_alloc_subdevices(dev, 2);
-	if (err)
-		return err;
-
-	s = dev->subdevices + 0;
-
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = thisboard->ao_chans;
-	s->maxdata = figure_out_maxdata(thisboard->ao_bits);
-	/* this is hard-coded here */
-	if (it->options[2])
-		s->range_table = &range_bipolar10;
-	else
-		s->range_table = &range_bipolar5;
-	s->insn_write = &ao_winsn;
-	s->insn_read = &ao_rinsn;
-
-	s = dev->subdevices + 1;
-	/* digital i/o subdevice */
-	if (thisboard->dio_chans) {
-		switch (thisboard->dio_method) {
-		case DIO_8255:
-			/*
-			 * this is a straight 8255, so register us with
-			 * the 8255 driver
-			 */
-			subdev_8255_init(dev, s, NULL, devpriv->dio_registers);
-			devpriv->attached_to_8255 = 1;
-			break;
-		case DIO_INTERNAL:
-		default:
-			printk("DIO_INTERNAL not implemented yet!\n");
-			return -ENXIO;
-			break;
-		}
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
+		/*
+		 * Write the LSB then MSB.
+		 *
+		 * If the simultaneous xfer mode is selected by the
+		 * jumper on the card, a read instruction is needed
+		 * in order to initiate the simultaneous transfer.
+		 * Otherwise, the DAC will be updated when the MSB
+		 * is written.
+		 */
+		outb(val & 0x00ff, offset);
+		outb((val >> 8) & 0x00ff, offset + 1);
 	}
 
-	printk("attached\n");
+	/* Cache the last value for readback */
+	devpriv->ao_readback[chan] = val;
+
+	return insn->n;
+}
+
+static int cb_pcimdda_ao_rinsn(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn,
+			       unsigned int *data)
+{
+	struct cb_pcimdda_private *devpriv = dev->private;
+	int chan = CR_CHAN(insn->chanspec);
+	unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
+	int i;
+
+	for (i = 0; i < insn->n; i++) {
+		/* Initiate the simultaneous transfer */
+		inw(offset);
+
+		data[i] = devpriv->ao_readback[chan];
+	}
+
+	return insn->n;
+}
+
+static int cb_pcimdda_attach_pci(struct comedi_device *dev,
+				 struct pci_dev *pcidev)
+{
+	struct cb_pcimdda_private *devpriv;
+	struct comedi_subdevice *s;
+	int ret;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+	dev->board_name = dev->driver->driver_name;
+
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, 3);
+
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
+
+	s = &dev->subdevices[0];
+	/* analog output subdevice */
+	s->type		= COMEDI_SUBD_AO;
+	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
+	s->n_chan	= 6;
+	s->maxdata	= 0xffff;
+	s->range_table	= &range_bipolar5;
+	s->insn_write	= cb_pcimdda_ao_winsn;
+	s->insn_read	= cb_pcimdda_ao_rinsn;
+
+	s = &dev->subdevices[1];
+	/* digital i/o subdevice */
+	ret = subdev_8255_init(dev, s, NULL,
+			dev->iobase + PCIMDDA_8255_BASE_REG);
+	if (ret)
+		return ret;
+
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
 	return 1;
 }
 
-static void detach(struct comedi_device *dev)
+static void cb_pcimdda_detach(struct comedi_device *dev)
 {
-	if (devpriv) {
-		if (dev->subdevices && devpriv->attached_to_8255) {
-			subdev_8255_cleanup(dev, dev->subdevices + 2);
-			devpriv->attached_to_8255 = 0;
-		}
-		if (devpriv->pci_dev) {
-			if (devpriv->registers)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		}
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+	if (dev->subdevices)
+		subdev_8255_cleanup(dev, &dev->subdevices[1]);
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
 	}
 }
 
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data)
-{
-	int i;
-	int chan = CR_CHAN(insn->chanspec);
-	unsigned long offset = devpriv->registers + chan * 2;
-
-	/* Writing a list of values to an AO channel is probably not
-	 * very useful, but that's how the interface is defined. */
-	for (i = 0; i < insn->n; i++) {
-		/*  first, load the low byte */
-		outb((char)(data[i] & 0x00ff), offset);
-		/*  next, write the high byte -- only after this is written is
-		   the channel voltage updated in the DAC, unless
-		   we're in simultaneous xfer mode (jumper on card)
-		   then a rinsn is necessary to actually update the DAC --
-		   see ao_rinsn() below... */
-		outb((char)(data[i] >> 8 & 0x00ff), offset + 1);
-
-		/* for testing only.. the actual rinsn SHOULD do an inw!
-		   (see the stuff about simultaneous XFER mode on this board) */
-		devpriv->ao_readback[chan] = data[i];
-	}
-
-	/* return the number of samples read/written */
-	return i;
-}
-
-/* AO subdevices should have a read insn as well as a write insn.
-
-   Usually this means copying a value stored in devpriv->ao_readback.
-   However, since this board has this jumper setting called "Simultaneous
-   Xfer mode" (off by default), we will support it.  Simultaneaous xfer
-   mode is accomplished by loading ALL the values you want for AO in all the
-   channels, then READing off one of the AO registers to initiate the
-   instantaneous simultaneous update of all DAC outputs, which makes
-   all AO channels update simultaneously.  This is useful for some control
-   applications, I would imagine.
-*/
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data)
-{
-	int i;
-	int chan = CR_CHAN(insn->chanspec);
-
-	for (i = 0; i < insn->n; i++) {
-		inw(devpriv->registers + chan * 2);
-		/*
-		 * should I set data[i] to the result of the actual read
-		 * on the register or the cached unsigned int in
-		 * devpriv->ao_readback[]?
-		 */
-		data[i] = devpriv->ao_readback[chan];
-	}
-
-	return i;
-}
-
-/*---------------------------------------------------------------------------
-  HELPER FUNCTION DEFINITIONS
------------------------------------------------------------------------------*/
-
-/*
- *  Probes for a supported device.
- *
- *  Prerequisite: private be allocated already inside dev
- *
- *  If the device is found, it returns 0 and has the following side effects:
- *
- *  o  assigns a struct pci_dev * to dev->private->pci_dev
- *  o  assigns a struct board * to dev->board_ptr
- *  o  sets dev->private->registers
- *  o  sets dev->private->dio_registers
- *
- *  Otherwise, returns a -errno on error
- */
-static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev = NULL;
-	int index;
-	unsigned long registers;
-
-	for_each_pci_dev(pcidev) {
-		/*  is it not a computer boards card? */
-		if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
-			continue;
-		/*  loop through cards supported by this driver */
-		for (index = 0; index < ARRAY_SIZE(boards); index++) {
-			if (boards[index].device_id != pcidev->device)
-				continue;
-			/*  was a particular bus/slot requested? */
-			if (it->options[0] || it->options[1]) {
-				/*  are we on the wrong bus/slot? */
-				if (pcidev->bus->number != it->options[0] ||
-				    PCI_SLOT(pcidev->devfn) != it->options[1]) {
-					continue;
-				}
-			}
-			/* found ! */
-
-			devpriv->pci_dev = pcidev;
-			dev->board_ptr = boards + index;
-			if (comedi_pci_enable(pcidev, thisboard->name)) {
-				printk
-				    ("cb_pcimdda: Failed to enable PCI device and request regions\n");
-				return -EIO;
-			}
-			registers =
-			    pci_resource_start(devpriv->pci_dev,
-					       REGS_BADRINDEX);
-			devpriv->registers = registers;
-			devpriv->dio_registers
-			    = devpriv->registers + thisboard->dio_offset;
-			return 0;
-		}
-	}
-
-	printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing "
-	       "card found at the requested position\n");
-	return -ENODEV;
-}
-
 static struct comedi_driver cb_pcimdda_driver = {
 	.driver_name	= "cb_pcimdda",
 	.module		= THIS_MODULE,
-	.attach		= attach,
-	.detach		= detach,
+	.attach_pci	= cb_pcimdda_attach_pci,
+	.detach		= cb_pcimdda_detach,
 };
 
 static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 5ed324c..5c768bc 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -59,40 +59,6 @@
 /* The maxiumum number of channels per subdevice. */
 #define MAX_CHANS 256
 
-#define MODULE_NAME "comedi_bond"
-#ifndef STR
-#  define STR1(x) #x
-#  define STR(x) STR1(x)
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
-		 "only to developers.");
-
-#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
-#define DEBUG(x...)							\
-	do {								\
-		if (debug)						\
-			printk(KERN_DEBUG MODULE_NAME": DEBUG: "x);	\
-	} while (0)
-#define WARNING(x...)  printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
-#define ERROR(x...)  printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
-
-/*
- * Board descriptions for two imaginary boards.  Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
-struct BondingBoard {
-	const char *name;
-};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct BondingBoard *)dev->board_ptr)
-
 struct BondedDevice {
 	struct comedi_device *dev;
 	unsigned minor;
@@ -107,7 +73,7 @@
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.  */
-struct Private {
+struct comedi_bond_private {
 # define MAX_BOARD_NAME 256
 	char name[MAX_BOARD_NAME];
 	struct BondedDevice **devs;
@@ -116,12 +82,6 @@
 	unsigned nchans;
 };
 
-/*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct Private *)dev->private)
-
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
  * useful to applications if you implement the insn_bits interface.
@@ -131,6 +91,7 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct comedi_bond_private *devpriv = dev->private;
 #define LSAMPL_BITS (sizeof(unsigned int)*8)
 	unsigned nchans = LSAMPL_BITS, num_done = 0, i;
 
@@ -177,6 +138,7 @@
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
 {
+	struct comedi_bond_private *devpriv = dev->private;
 	int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
 	unsigned int io;
 	struct BondedDevice *bdev;
@@ -230,6 +192,7 @@
 
 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	struct comedi_bond_private *devpriv = dev->private;
 	int i;
 	struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
 
@@ -245,15 +208,18 @@
 		struct BondedDevice *bdev = NULL;
 
 		if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
-			ERROR("Minor %d is invalid!\n", minor);
+			dev_err(dev->class_dev,
+				"Minor %d is invalid!\n", minor);
 			return 0;
 		}
 		if (minor == dev->minor) {
-			ERROR("Cannot bond this driver to itself!\n");
+			dev_err(dev->class_dev,
+				"Cannot bond this driver to itself!\n");
 			return 0;
 		}
 		if (devs_opened[minor]) {
-			ERROR("Minor %d specified more than once!\n", minor);
+			dev_err(dev->class_dev,
+				"Minor %d specified more than once!\n", minor);
 			return 0;
 		}
 
@@ -263,7 +229,8 @@
 		d = devs_opened[minor] = comedi_open(file);
 
 		if (!d) {
-			ERROR("Minor %u could not be opened\n", minor);
+			dev_err(dev->class_dev,
+				"Minor %u could not be opened\n", minor);
 			return 0;
 		}
 
@@ -272,14 +239,14 @@
 							     sdev + 1)) > -1) {
 			nchans = comedi_get_n_channels(d, sdev);
 			if (nchans <= 0) {
-				ERROR("comedi_get_n_channels() returned %d "
-				      "on minor %u subdev %d!\n",
-				      nchans, minor, sdev);
+				dev_err(dev->class_dev,
+					"comedi_get_n_channels() returned %d on minor %u subdev %d!\n",
+					nchans, minor, sdev);
 				return 0;
 			}
 			bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
 			if (!bdev) {
-				ERROR("Out of memory.\n");
+				dev_err(dev->class_dev, "Out of memory\n");
 				return 0;
 			}
 			bdev->dev = d;
@@ -302,8 +269,8 @@
 			    Realloc(devpriv->devs,
 				    ++devpriv->ndevs * sizeof(bdev), tmp);
 			if (!devpriv->devs) {
-				ERROR("Could not allocate memory. "
-				      "Out of memory?");
+				dev_err(dev->class_dev,
+					"Could not allocate memory. Out of memory?\n");
 				return 0;
 			}
 
@@ -323,7 +290,7 @@
 	}
 
 	if (!devpriv->nchans) {
-		ERROR("No channels found!\n");
+		dev_err(dev->class_dev, "No channels found!\n");
 		return 0;
 	}
 
@@ -333,35 +300,28 @@
 static int bonding_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	struct comedi_bond_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret;
 
-	LOG_MSG("comedi%d\n", dev->minor);
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
 
 	/*
-	 * Allocate the private structure area.  alloc_private() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_private(dev, sizeof(struct Private)) < 0)
-		return -ENOMEM;
-
-	/*
-	 * Setup our bonding from config params.. sets up our Private struct..
+	 * Setup our bonding from config params.. sets up our private struct..
 	 */
 	if (!doDevConfig(dev, it))
 		return -EINVAL;
 
-	/*
-	 * Initialize dev->board_name.  Note that we can use the "thisboard"
-	 * macro now, since we just initialized it in the last line.
-	 */
 	dev->board_name = devpriv->name;
 
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = devpriv->nchans;
@@ -370,9 +330,9 @@
 	s->insn_bits = bonding_dio_insn_bits;
 	s->insn_config = bonding_dio_insn_config;
 
-	LOG_MSG("attached with %u DIO channels coming from %u different "
-		"subdevices all bonded together.  "
-		"John Lennon would be proud!\n",
+	dev_info(dev->class_dev,
+		"%s: %s attached, %u channels from %u devices\n",
+		dev->driver->driver_name, dev->board_name,
 		devpriv->nchans, devpriv->ndevs);
 
 	return 1;
@@ -380,6 +340,7 @@
 
 static void bonding_detach(struct comedi_device *dev)
 {
+	struct comedi_bond_private *devpriv = dev->private;
 	unsigned long devs_closed = 0;
 
 	if (devpriv) {
@@ -402,25 +363,16 @@
 	}
 }
 
-static const struct BondingBoard bondingBoards[] = {
-	{
-		.name		= "comedi_bond",
-	},
-};
-
 static struct comedi_driver bonding_driver = {
 	.driver_name	= "comedi_bond",
 	.module		= THIS_MODULE,
 	.attach		= bonding_attach,
 	.detach		= bonding_detach,
-	.board_name	= &bondingBoards[0].name,
-	.offset		= sizeof(struct BondingBoard),
-	.num_names	= ARRAY_SIZE(bondingBoards),
 };
 module_comedi_driver(bonding_driver);
 
 MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
+MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI "
 		   "devices together as one.  In the words of John Lennon: "
 		   "'And the world will live as one...'");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h
index 4b2cfd3..94481c6 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.h
+++ b/drivers/staging/comedi/drivers/comedi_fc.h
@@ -73,4 +73,36 @@
 	return num_samples * bytes_per_sample(subd);
 }
 
+/**
+ * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source
+ * @src: pointer to the trigger source to validate
+ * @flags: bitmask of valid TRIG_* for the trigger
+ *
+ * This is used in "step 1" of the do_cmdtest functions of comedi drivers
+ * to vaildate the comedi_cmd triggers. The mask of the @src against the
+ * @flags allows the userspace comedilib to pass all the comedi_cmd
+ * triggers as TRIG_ANY and get back a bitmask of the valid trigger sources.
+ */
+static inline int cfc_check_trigger_src(unsigned int *src, unsigned int flags)
+{
+	unsigned int orig_src = *src;
+
+	*src = orig_src & flags;
+	if (*src == TRIG_INVALID || *src != orig_src)
+		return -EINVAL;
+	return 0;
+}
+
+/**
+ * cfc_check_trigger_is_unique() - make sure a trigger source is unique
+ * @src: the trigger source to check
+ */
+static inline int cfc_check_trigger_is_unique(unsigned int src)
+{
+	/* this test is true if more than one _src bit is set */
+	if ((src & (src - 1)) != 0)
+		return -EINVAL;
+	return 0;
+}
+
 #endif /* _COMEDI_FC_H */
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 9a63cac..22ef942 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -85,6 +85,8 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 
+#include "comedi_fc.h"
+
 #define PARPORT_SIZE 3
 
 #define PARPORT_A 0
@@ -96,11 +98,12 @@
 	unsigned int c_data;
 	int enable_irq;
 };
-#define devpriv ((struct parport_private *)(dev->private))
 
 static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	struct parport_private *devpriv = dev->private;
+
 	if (data[0]) {
 		devpriv->a_data &= ~data[0];
 		devpriv->a_data |= (data[0] & data[1]);
@@ -117,6 +120,8 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct parport_private *devpriv = dev->private;
+
 	if (data[0]) {
 		s->io_bits = 0xff;
 		devpriv->c_data &= ~(1 << 5);
@@ -145,6 +150,8 @@
 static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	struct parport_private *devpriv = dev->private;
+
 	data[0] &= 0x0f;
 	if (data[0]) {
 		devpriv->c_data &= ~data[0];
@@ -171,39 +178,20 @@
 				struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 
-	/* step 1 */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: ignored */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -245,6 +233,8 @@
 static int parport_intr_cmd(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
+	struct parport_private *devpriv = dev->private;
+
 	devpriv->c_data |= 0x10;
 	outb(devpriv->c_data, dev->iobase + PARPORT_C);
 
@@ -256,7 +246,7 @@
 static int parport_intr_cancel(struct comedi_device *dev,
 			       struct comedi_subdevice *s)
 {
-	printk(KERN_DEBUG "parport_intr_cancel()\n");
+	struct parport_private *devpriv = dev->private;
 
 	devpriv->c_data &= ~0x10;
 	outb(devpriv->c_data, dev->iobase + PARPORT_C);
@@ -269,12 +259,11 @@
 static irqreturn_t parport_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 3;
+	struct parport_private *devpriv = dev->private;
+	struct comedi_subdevice *s = &dev->subdevices[3];
 
-	if (!devpriv->enable_irq) {
-		printk(KERN_ERR "comedi_parport: bogus irq, ignored\n");
+	if (!devpriv->enable_irq)
 		return IRQ_NONE;
-	}
 
 	comedi_buf_put(s->async, 0);
 	s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
@@ -286,41 +275,42 @@
 static int parport_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	struct parport_private *devpriv;
 	int ret;
 	unsigned int irq;
 	unsigned long iobase;
 	struct comedi_subdevice *s;
 
+	dev->board_name = dev->driver->driver_name;
+
 	iobase = it->options[0];
-	printk(KERN_INFO "comedi%d: parport: 0x%04lx ", dev->minor, iobase);
-	if (!request_region(iobase, PARPORT_SIZE, "parport (comedi)")) {
-		printk(KERN_ERR "I/O port conflict\n");
+	if (!request_region(iobase, PARPORT_SIZE, dev->board_name)) {
+		dev_err(dev->class_dev, "I/O port conflict\n");
 		return -EIO;
 	}
 	dev->iobase = iobase;
 
 	irq = it->options[1];
 	if (irq) {
-		printk(KERN_INFO " irq=%u", irq);
-		ret = request_irq(irq, parport_interrupt, 0, "comedi_parport",
+		ret = request_irq(irq, parport_interrupt, 0, dev->board_name,
 				  dev);
 		if (ret < 0) {
-			printk(KERN_ERR " irq not available\n");
+			dev_err(dev->class_dev, "irq not available\n");
 			return -EINVAL;
 		}
 		dev->irq = irq;
 	}
-	dev->board_name = "parport";
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
-	ret = alloc_private(dev, sizeof(struct parport_private));
+	ret = alloc_private(dev, sizeof(*devpriv));
 	if (ret < 0)
 		return ret;
+	devpriv = dev->private;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 8;
@@ -329,7 +319,7 @@
 	s->insn_bits = parport_insn_a;
 	s->insn_config = parport_insn_config_a;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 5;
@@ -337,7 +327,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = parport_insn_b;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->n_chan = 4;
@@ -345,7 +335,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = parport_insn_c;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	if (irq) {
 		dev->read_subdev = s;
 		s->type = COMEDI_SUBD_DI;
@@ -366,8 +356,10 @@
 	devpriv->c_data = 0;
 	outb(devpriv->c_data, dev->iobase + PARPORT_C);
 
-	printk(KERN_INFO "\n");
-	return 1;
+	dev_info(dev->class_dev, "%s: iobase=0x%04lx, irq %sabled",
+		dev->board_name, dev->iobase, dev->irq ? "en" : "dis");
+
+	return 0;
 }
 
 static void parport_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 523a809..7817def 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -57,14 +57,6 @@
 #include "comedi_fc.h"
 #include <linux/timer.h>
 
-/* Board descriptions */
-struct waveform_board {
-	const char *name;
-	int ai_chans;
-	int ai_bits;
-	int have_dio;
-};
-
 #define N_CHANS 8
 
 /* Data unique to this driver */
@@ -81,7 +73,6 @@
 	unsigned timer_running:1;
 	unsigned int ao_loopbacks[N_CHANS];
 };
-#define devpriv ((struct waveform_private *)dev->private)
 
 /* 1000 nanosec in a microsec */
 static const int nano_per_micro = 1000;
@@ -98,6 +89,7 @@
 static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
 			   unsigned long current_time)
 {
+	struct waveform_private *devpriv = dev->private;
 	struct comedi_subdevice *s = dev->read_subdev;
 	unsigned int offset = s->maxdata / 2;
 	u64 value;
@@ -122,6 +114,7 @@
 			     unsigned int range_index,
 			     unsigned long current_time)
 {
+	struct waveform_private *devpriv = dev->private;
 	struct comedi_subdevice *s = dev->read_subdev;
 	unsigned int offset = s->maxdata / 2;
 	u64 value;
@@ -175,6 +168,7 @@
 static void waveform_ai_interrupt(unsigned long arg)
 {
 	struct comedi_device *dev = (struct comedi_device *)arg;
+	struct waveform_private *devpriv = dev->private;
 	struct comedi_async *async = dev->read_subdev->async;
 	struct comedi_cmd *cmd = &async->cmd;
 	unsigned int i, j;
@@ -237,44 +231,23 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW | TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW | TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -362,6 +335,7 @@
 static int waveform_ai_cmd(struct comedi_device *dev,
 			   struct comedi_subdevice *s)
 {
+	struct waveform_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
 	if (cmd->flags & TRIG_RT) {
@@ -395,6 +369,8 @@
 static int waveform_ai_cancel(struct comedi_device *dev,
 			      struct comedi_subdevice *s)
 {
+	struct waveform_private *devpriv = dev->private;
+
 	devpriv->timer_running = 0;
 	del_timer(&devpriv->timer);
 	return 0;
@@ -404,6 +380,7 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct waveform_private *devpriv = dev->private;
 	int i, chan = CR_CHAN(insn->chanspec);
 
 	for (i = 0; i < insn->n; i++)
@@ -416,6 +393,7 @@
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct waveform_private *devpriv = dev->private;
 	int i, chan = CR_CHAN(insn->chanspec);
 
 	for (i = 0; i < insn->n; i++)
@@ -427,17 +405,19 @@
 static int waveform_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
-	const struct waveform_board *board = comedi_board(dev);
+	struct waveform_private *devpriv;
 	struct comedi_subdevice *s;
 	int amplitude = it->options[0];
 	int period = it->options[1];
 	int i;
 	int ret;
 
-	dev->board_name = board->name;
+	dev->board_name = dev->driver->driver_name;
 
-	if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
-		return -ENOMEM;
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
 
 	/* set default amplitude and period */
 	if (amplitude <= 0)
@@ -452,13 +432,13 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	s->n_chan = board->ai_chans;
-	s->maxdata = (1 << board->ai_bits) - 1;
+	s->n_chan = N_CHANS;
+	s->maxdata = 0xffff;
 	s->range_table = &waveform_ai_ranges;
 	s->len_chanlist = s->n_chan * 2;
 	s->insn_read = waveform_ai_insn_read;
@@ -466,13 +446,13 @@
 	s->do_cmdtest = waveform_ai_cmdtest;
 	s->cancel = waveform_ai_cancel;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	dev->write_subdev = s;
 	/* analog output subdevice (loopback) */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
-	s->n_chan = board->ai_chans;
-	s->maxdata = (1 << board->ai_bits) - 1;
+	s->n_chan = N_CHANS;
+	s->maxdata = 0xffff;
 	s->range_table = &waveform_ai_ranges;
 	s->len_chanlist = s->n_chan * 2;
 	s->insn_write = waveform_ao_insn_write;
@@ -488,35 +468,27 @@
 	devpriv->timer.function = waveform_ai_interrupt;
 	devpriv->timer.data = (unsigned long)dev;
 
-	printk(KERN_INFO "comedi%d: comedi_test: "
-	       "%i microvolt, %li microsecond waveform attached\n", dev->minor,
-	       devpriv->uvolt_amplitude, devpriv->usec_period);
-	return 1;
+	dev_info(dev->class_dev,
+		"%s: %i microvolt, %li microsecond waveform attached\n",
+		dev->board_name,
+		devpriv->uvolt_amplitude, devpriv->usec_period);
+
+	return 0;
 }
 
 static void waveform_detach(struct comedi_device *dev)
 {
-	if (dev->private)
+	struct waveform_private *devpriv = dev->private;
+
+	if (devpriv)
 		waveform_ai_cancel(dev, dev->read_subdev);
 }
 
-static const struct waveform_board waveform_boards[] = {
-	{
-		.name		= "comedi_test",
-		.ai_chans	= N_CHANS,
-		.ai_bits	= 16,
-		.have_dio	= 0,
-	},
-};
-
 static struct comedi_driver waveform_driver = {
 	.driver_name	= "comedi_test",
 	.module		= THIS_MODULE,
 	.attach		= waveform_attach,
 	.detach		= waveform_detach,
-	.board_name	= &waveform_boards[0].name,
-	.offset		= sizeof(struct waveform_board),
-	.num_names	= ARRAY_SIZE(waveform_boards),
 };
 module_comedi_driver(waveform_driver);
 
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 944cfee..178a6a4 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -27,51 +27,35 @@
 Updated: Wed, 27 Jun 2007 13:00:06 +0100
 Status: works
 
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration Options: not applicable, uses comedi PCI auto config
 */
 
 #include "../comedidev.h"
 
-enum contec_model {
-	PIO1616L = 0,
-};
-
-struct contec_board {
-	const char *name;
-	int model;
-	int in_ports;
-	int out_ports;
-	int in_offs;
-	int out_offs;
-	int out_boffs;
-};
-static const struct contec_board contec_boards[] = {
-	{"PIO1616L", PIO1616L, 16, 16, 0, 2, 10},
-};
-
 #define PCI_DEVICE_ID_PIO1616L 0x8172
 
-#define thisboard ((const struct contec_board *)dev->board_ptr)
+/*
+ * Register map
+ */
+#define PIO1616L_DI_REG		0x00
+#define PIO1616L_DO_REG		0x02
 
 static int contec_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	unsigned int mask = data[0];
+	unsigned int bits = data[1];
 
-	dev_dbg(dev->class_dev, "contec_do_insn_bits called\n");
-	dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
+	if (mask) {
+		s->state &= ~mask;
+		s->state |= (bits & mask);
 
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= data[0] & data[1];
-		dev_dbg(dev->class_dev, "out: %d on %lx\n", s->state,
-			dev->iobase + thisboard->out_offs);
-		outw(s->state, dev->iobase + thisboard->out_offs);
+		outw(s->state, dev->iobase + PIO1616L_DO_REG);
 	}
+
+	data[1] = s->state;
+
 	return insn->n;
 }
 
@@ -79,87 +63,49 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-
-	dev_dbg(dev->class_dev, "contec_di_insn_bits called\n");
-	dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
-
-	data[1] = inw(dev->iobase + thisboard->in_offs);
+	data[1] = inw(dev->iobase + PIO1616L_DI_REG);
 
 	return insn->n;
 }
 
-static struct pci_dev *contec_find_pci_dev(struct comedi_device *dev,
-					   struct comedi_devconfig *it)
+static int contec_attach_pci(struct comedi_device *dev,
+			     struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-				slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_CONTEC ||
-		    pcidev->device != PCI_DEVICE_ID_PIO1616L)
-			continue;
-
-		dev->board_ptr = contec_boards + 0;
-		return pcidev;
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
 	struct comedi_subdevice *s;
 	int ret;
 
-	printk("comedi%d: contec: ", dev->minor);
+	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	dev->board_name = thisboard->name;
+	dev->board_name = dev->driver->driver_name;
+
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, 0);
 
 	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
 
-	pcidev = contec_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pcidev->dev);
+	s = &dev->subdevices[0];
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= contec_di_insn_bits;
 
-	if (comedi_pci_enable(pcidev, "contec_pci_dio")) {
-		printk("error enabling PCI device and request regions!\n");
-		return -EIO;
-	}
-	dev->iobase = pci_resource_start(pcidev, 0);
-	printk(" base addr %lx ", dev->iobase);
+	s = &dev->subdevices[1];
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= contec_do_insn_bits;
 
-	s = dev->subdevices + 0;
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = contec_di_insn_bits;
-
-	s = dev->subdevices + 1;
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = contec_do_insn_bits;
-
-	printk("attached\n");
-
-	return 1;
+	return 0;
 }
 
 static void contec_detach(struct comedi_device *dev)
@@ -169,14 +115,13 @@
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver contec_pci_dio_driver = {
 	.driver_name	= "contec_pci_dio",
 	.module		= THIS_MODULE,
-	.attach		= contec_attach,
+	.attach_pci	= contec_attach_pci,
 	.detach		= contec_detach,
 };
 
@@ -192,8 +137,7 @@
 }
 
 static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
-		.driver_data = PIO1616L },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) },
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index cad559a..d13c8c5 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -31,16 +31,10 @@
 Much of the functionality of this driver was determined from reading
 the source code for the Windows driver.
 
-The FPGA on the board requires initialization code, which can
-be loaded by comedi_config using the -i
-option.  The initialization code is available from http://www.comedi.org
-in the comedi_nonfree_firmware tarball.
+The FPGA on the board requires fimware, which is available from
+http://www.comedi.org in the comedi_nonfree_firmware tarball.
 
-Configuration options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration options: not applicable, uses PCI auto config
 */
 /*
    This card was obviously never intended to leave the Windows world,
@@ -117,17 +111,17 @@
 
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/firmware.h>
 
 #include "8255.h"
 
+#define DAQBOARD2000_FIRMWARE		"daqboard2000_firmware.bin"
+
 #define PCI_VENDOR_ID_IOTECH		0x1616
 
 #define DAQBOARD2000_SUBSYSTEM_IDS2 	0x0002	/* Daqboard/2000 - 2 Dacs */
 #define DAQBOARD2000_SUBSYSTEM_IDS4 	0x0004	/* Daqboard/2000 - 4 Dacs */
 
-#define DAQBOARD2000_DAQ_SIZE 		0x1002
-#define DAQBOARD2000_PLX_SIZE 		0x100
-
 /* Initialization bits for the Serial EEPROM Control Register */
 #define DAQBOARD2000_SECRProgPinHi      0x8001767e
 #define DAQBOARD2000_SECRProgPinLo      0x8000767e
@@ -143,85 +137,56 @@
 #define DAQBOARD2000_CPLD_INIT 		0x0002
 #define DAQBOARD2000_CPLD_DONE 		0x0004
 
-/* Available ranges */
-static const struct comedi_lrange range_daqboard2000_ai = { 13, {
-								 RANGE(-10, 10),
-								 RANGE(-5, 5),
-								 RANGE(-2.5,
-								       2.5),
-								 RANGE(-1.25,
-								       1.25),
-								 RANGE(-0.625,
-								       0.625),
-								 RANGE(-0.3125,
-								       0.3125),
-								 RANGE(-0.156,
-								       0.156),
-								 RANGE(0, 10),
-								 RANGE(0, 5),
-								 RANGE(0, 2.5),
-								 RANGE(0, 1.25),
-								 RANGE(0,
-								       0.625),
-								 RANGE(0,
-								       0.3125)
-								 }
+static const struct comedi_lrange range_daqboard2000_ai = {
+	13, {
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
+		BIP_RANGE(0.625),
+		BIP_RANGE(0.3125),
+		BIP_RANGE(0.156),
+		UNI_RANGE(10),
+		UNI_RANGE(5),
+		UNI_RANGE(2.5),
+		UNI_RANGE(1.25),
+		UNI_RANGE(0.625),
+		UNI_RANGE(0.3125)
+	}
 };
 
-static const struct comedi_lrange range_daqboard2000_ao = { 1, {
-								RANGE(-10, 10)
-								}
-};
-
-struct daqboard2000_hw {
-	volatile u16 acqControl;	/*  0x00 */
-	volatile u16 acqScanListFIFO;	/*  0x02 */
-	volatile u32 acqPacerClockDivLow;	/*  0x04 */
-
-	volatile u16 acqScanCounter;	/*  0x08 */
-	volatile u16 acqPacerClockDivHigh;	/*  0x0a */
-	volatile u16 acqTriggerCount;	/*  0x0c */
-	volatile u16 fill2;	/*  0x0e */
-	volatile u16 acqResultsFIFO;	/*  0x10 */
-	volatile u16 fill3;	/*  0x12 */
-	volatile u16 acqResultsShadow;	/*  0x14 */
-	volatile u16 fill4;	/*  0x16 */
-	volatile u16 acqAdcResult;	/*  0x18 */
-	volatile u16 fill5;	/*  0x1a */
-	volatile u16 dacScanCounter;	/*  0x1c */
-	volatile u16 fill6;	/*  0x1e */
-
-	volatile u16 dacControl;	/*  0x20 */
-	volatile u16 fill7;	/*  0x22 */
-	volatile s16 dacFIFO;	/*  0x24 */
-	volatile u16 fill8[2];	/*  0x26 */
-	volatile u16 dacPacerClockDiv;	/*  0x2a */
-	volatile u16 refDacs;	/*  0x2c */
-	volatile u16 fill9;	/*  0x2e */
-
-	volatile u16 dioControl;	/*  0x30 */
-	volatile s16 dioP3hsioData;	/*  0x32 */
-	volatile u16 dioP3Control;	/*  0x34 */
-	volatile u16 calEepromControl;	/*  0x36 */
-	volatile s16 dacSetting[4];	/*  0x38 */
-	volatile s16 dioP2ExpansionIO8Bit[32];	/*  0x40 */
-
-	volatile u16 ctrTmrControl;	/*  0x80 */
-	volatile u16 fill10[3];	/*  0x82 */
-	volatile s16 ctrInput[4];	/*  0x88 */
-	volatile u16 fill11[8];	/*  0x90 */
-	volatile u16 timerDivisor[2];	/*  0xa0 */
-	volatile u16 fill12[6];	/*  0xa4 */
-
-	volatile u16 dmaControl;	/*  0xb0 */
-	volatile u16 trigControl;	/*  0xb2 */
-	volatile u16 fill13[2];	/*  0xb4 */
-	volatile u16 calEeprom;	/*  0xb8 */
-	volatile u16 acqDigitalMark;	/*  0xba */
-	volatile u16 trigDacs;	/*  0xbc */
-	volatile u16 fill14;	/*  0xbe */
-	volatile s16 dioP2ExpansionIO16Bit[32];	/*  0xc0 */
-};
+/*
+ * Register Memory Map
+ */
+#define acqControl			0x00		/* u16 */
+#define acqScanListFIFO			0x02		/* u16 */
+#define acqPacerClockDivLow		0x04		/* u32 */
+#define acqScanCounter			0x08		/* u16 */
+#define acqPacerClockDivHigh		0x0a		/* u16 */
+#define acqTriggerCount			0x0c		/* u16 */
+#define acqResultsFIFO			0x10		/* u16 */
+#define acqResultsShadow		0x14		/* u16 */
+#define acqAdcResult			0x18		/* u16 */
+#define dacScanCounter			0x1c		/* u16 */
+#define dacControl			0x20		/* u16 */
+#define dacFIFO				0x24		/* s16 */
+#define dacPacerClockDiv		0x2a		/* u16 */
+#define refDacs				0x2c		/* u16 */
+#define dioControl			0x30		/* u16 */
+#define dioP3hsioData			0x32		/* s16 */
+#define dioP3Control			0x34		/* u16 */
+#define calEepromControl		0x36		/* u16 */
+#define dacSetting(x)			(0x38 + (x)*2)	/* s16 */
+#define dioP2ExpansionIO8Bit		0x40		/* s16 */
+#define ctrTmrControl			0x80		/* u16 */
+#define ctrInput(x)			(0x88 + (x)*2)	/* s16 */
+#define timerDivisor(x)			(0xa0 + (x)*2)	/* u16 */
+#define dmaControl			0xb0		/* u16 */
+#define trigControl			0xb2		/* u16 */
+#define calEeprom			0xb8		/* u16 */
+#define acqDigitalMark			0xba		/* u16 */
+#define trigDacs			0xbc		/* u16 */
+#define dioP2ExpansionIO16Bit(x)	(0xc0 + (x)*2)	/* s16 */
 
 /* Scan Sequencer programming */
 #define DAQBOARD2000_SeqStartScanList            0x0011
@@ -311,27 +276,23 @@
 	{"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
 };
 
-#define this_board ((const struct daq200_boardtype *)dev->board_ptr)
-
 struct daqboard2000_private {
 	enum {
 		card_daqboard_2000
 	} card;
-	void *daq;
+	void __iomem *daq;
 	void __iomem *plx;
 	unsigned int ao_readback[2];
 };
 
-#define devpriv ((struct daqboard2000_private *)dev->private)
-
 static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry)
 {
-	struct daqboard2000_hw *fpga = devpriv->daq;
+	struct daqboard2000_private *devpriv = dev->private;
 
-/* udelay(4); */
-	fpga->acqScanListFIFO = entry & 0x00ff;
-/* udelay(4); */
-	fpga->acqScanListFIFO = (entry >> 8) & 0x00ff;
+	/* udelay(4); */
+	writew(entry & 0x00ff, devpriv->daq + acqScanListFIFO);
+	/* udelay(4); */
+	writew((entry >> 8) & 0x00ff, devpriv->daq + acqScanListFIFO);
 }
 
 static void setup_sampling(struct comedi_device *dev, int chan, int gain)
@@ -372,7 +333,6 @@
 	/* These should be read from EEPROM */
 	word2 |= 0x0800;
 	word3 |= 0xc000;
-/*  printk("%d %4.4x %4.4x %4.4x %4.4x\n", chan, word0, word1, word2, word3);*/
 	writeAcqScanListEntry(dev, word0);
 	writeAcqScanListEntry(dev, word1);
 	writeAcqScanListEntry(dev, word2);
@@ -384,21 +344,22 @@
 				     struct comedi_insn *insn,
 				     unsigned int *data)
 {
-	int i;
-	struct daqboard2000_hw *fpga = devpriv->daq;
+	struct daqboard2000_private *devpriv = dev->private;
+	unsigned int val;
 	int gain, chan, timeout;
+	int i;
 
-	fpga->acqControl =
-	    DAQBOARD2000_AcqResetScanListFifo |
-	    DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
+	writew(DAQBOARD2000_AcqResetScanListFifo |
+	       DAQBOARD2000_AcqResetResultsFifo |
+	       DAQBOARD2000_AcqResetConfigPipe, devpriv->daq + acqControl);
 
 	/*
 	 * If pacer clock is not set to some high value (> 10 us), we
 	 * risk multiple samples to be put into the result FIFO.
 	 */
 	/* 1 second, should be long enough */
-	fpga->acqPacerClockDivLow = 1000000;
-	fpga->acqPacerClockDivHigh = 0;
+	writel(1000000, devpriv->daq + acqPacerClockDivLow);
+	writew(0, devpriv->daq + acqPacerClockDivHigh);
 
 	gain = CR_RANGE(insn->chanspec);
 	chan = CR_CHAN(insn->chanspec);
@@ -410,28 +371,30 @@
 	for (i = 0; i < insn->n; i++) {
 		setup_sampling(dev, chan, gain);
 		/* Enable reading from the scanlist FIFO */
-		fpga->acqControl = DAQBOARD2000_SeqStartScanList;
+		writew(DAQBOARD2000_SeqStartScanList,
+		       devpriv->daq + acqControl);
 		for (timeout = 0; timeout < 20; timeout++) {
-			if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull)
+			val = readw(devpriv->daq + acqControl);
+			if (val & DAQBOARD2000_AcqConfigPipeFull)
 				break;
 			/* udelay(2); */
 		}
-		fpga->acqControl = DAQBOARD2000_AdcPacerEnable;
+		writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl);
 		for (timeout = 0; timeout < 20; timeout++) {
-			if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning)
+			val = readw(devpriv->daq + acqControl);
+			if (val & DAQBOARD2000_AcqLogicScanning)
 				break;
 			/* udelay(2); */
 		}
 		for (timeout = 0; timeout < 20; timeout++) {
-			if (fpga->acqControl &
-			    DAQBOARD2000_AcqResultsFIFOHasValidData) {
+			val = readw(devpriv->daq + acqControl);
+			if (val & DAQBOARD2000_AcqResultsFIFOHasValidData)
 				break;
-			}
 			/* udelay(2); */
 		}
-		data[i] = fpga->acqResultsFIFO;
-		fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
-		fpga->acqControl = DAQBOARD2000_SeqStopScanList;
+		data[i] = readw(devpriv->daq + acqResultsFIFO);
+		writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
+		writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
 	}
 
 	return i;
@@ -442,8 +405,9 @@
 				     struct comedi_insn *insn,
 				     unsigned int *data)
 {
-	int i;
+	struct daqboard2000_private *devpriv = dev->private;
 	int chan = CR_CHAN(insn->chanspec);
+	int i;
 
 	for (i = 0; i < insn->n; i++)
 		data[i] = devpriv->ao_readback[chan];
@@ -456,28 +420,39 @@
 				      struct comedi_insn *insn,
 				      unsigned int *data)
 {
-	int i;
+	struct daqboard2000_private *devpriv = dev->private;
 	int chan = CR_CHAN(insn->chanspec);
-	struct daqboard2000_hw *fpga = devpriv->daq;
+	unsigned int val;
 	int timeout;
+	int i;
 
 	for (i = 0; i < insn->n; i++) {
+#if 0
 		/*
-		 * OK, since it works OK without enabling the DAC's, let's keep
-		 * it as simple as possible...
+		 * OK, since it works OK without enabling the DAC's,
+		 * let's keep it as simple as possible...
 		 */
-		/* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */
-		fpga->dacSetting[chan] = data[i];
+		writew((chan + 2) * 0x0010 | 0x0001,
+		       devpriv->daq + dacControl);
+		udelay(1000);
+#endif
+		writew(data[i], devpriv->daq + dacSetting(chan));
 		for (timeout = 0; timeout < 20; timeout++) {
-			if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0)
+			val = readw(devpriv->daq + dacControl);
+			if ((val & ((chan + 1) * 0x0010)) == 0)
 				break;
 			/* udelay(2); */
 		}
 		devpriv->ao_readback[chan] = data[i];
+#if 0
 		/*
-		 * Since we never enabled the DAC's, we don't need to disable it...
-		 * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; udelay(1000);
+		 * Since we never enabled the DAC's, we don't need
+		 * to disable it...
 		 */
+		writew((chan + 2) * 0x0010 | 0x0000,
+		       devpriv->daq + dacControl);
+		udelay(1000);
+#endif
 	}
 
 	return i;
@@ -485,7 +460,8 @@
 
 static void daqboard2000_resetLocalBus(struct comedi_device *dev)
 {
-	dev_dbg(dev->class_dev, "daqboard2000_resetLocalBus\n");
+	struct daqboard2000_private *devpriv = dev->private;
+
 	writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
@@ -494,7 +470,8 @@
 
 static void daqboard2000_reloadPLX(struct comedi_device *dev)
 {
-	dev_dbg(dev->class_dev, "daqboard2000_reloadPLX\n");
+	struct daqboard2000_private *devpriv = dev->private;
+
 	writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
@@ -505,7 +482,8 @@
 
 static void daqboard2000_pulseProgPin(struct comedi_device *dev)
 {
-	dev_dbg(dev->class_dev, "daqboard2000_pulseProgPin 1\n");
+	struct daqboard2000_private *devpriv = dev->private;
+
 	writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
@@ -514,6 +492,7 @@
 
 static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask)
 {
+	struct daqboard2000_private *devpriv = dev->private;
 	int result = 0;
 	int i;
 	int cpld;
@@ -533,6 +512,7 @@
 
 static int daqboard2000_writeCPLD(struct comedi_device *dev, int data)
 {
+	struct daqboard2000_private *devpriv = dev->private;
 	int result = 0;
 
 	udelay(10);
@@ -545,41 +525,29 @@
 }
 
 static int initialize_daqboard2000(struct comedi_device *dev,
-				   unsigned char *cpld_array, int len)
+				   const u8 *cpld_array, size_t len)
 {
+	struct daqboard2000_private *devpriv = dev->private;
 	int result = -EIO;
 	/* Read the serial EEPROM control register */
 	int secr;
 	int retry;
-	int i;
+	size_t i;
 
 	/* Check to make sure the serial eeprom is present on the board */
 	secr = readl(devpriv->plx + 0x6c);
-	if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) {
-#ifdef DEBUG_EEPROM
-		dev_dbg(dev->class_dev, "no serial eeprom\n");
-#endif
+	if (!(secr & DAQBOARD2000_EEPROM_PRESENT))
 		return -EIO;
-	}
 
 	for (retry = 0; retry < 3; retry++) {
-#ifdef DEBUG_EEPROM
-		dev_dbg(dev->class_dev, "Programming EEPROM try %x\n", retry);
-#endif
-
 		daqboard2000_resetLocalBus(dev);
 		daqboard2000_reloadPLX(dev);
 		daqboard2000_pulseProgPin(dev);
 		if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) {
 			for (i = 0; i < len; i++) {
-				if (cpld_array[i] == 0xff
-				    && cpld_array[i + 1] == 0x20) {
-#ifdef DEBUG_EEPROM
-					dev_dbg(dev->class_dev,
-						"Preamble found at %d\n", i);
-#endif
+				if (cpld_array[i] == 0xff &&
+				    cpld_array[i + 1] == 0x20)
 					break;
-				}
 			}
 			for (; i < len; i += 2) {
 				int data =
@@ -588,9 +556,6 @@
 					break;
 			}
 			if (i >= len) {
-#ifdef DEBUG_EEPROM
-				dev_dbg(dev->class_dev, "Programmed\n");
-#endif
 				daqboard2000_resetLocalBus(dev);
 				daqboard2000_reloadPLX(dev);
 				result = 0;
@@ -601,28 +566,45 @@
 	return result;
 }
 
+static int daqboard2000_upload_firmware(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	const struct firmware *fw;
+	int ret;
+
+	ret = request_firmware(&fw, DAQBOARD2000_FIRMWARE, &pcidev->dev);
+	if (ret)
+		return ret;
+
+	ret = initialize_daqboard2000(dev, fw->data, fw->size);
+	release_firmware(fw);
+
+	return ret;
+}
+
 static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev)
 {
-/*  printk("Implement: daqboard2000_adcStopDmaTransfer\n");*/
 }
 
 static void daqboard2000_adcDisarm(struct comedi_device *dev)
 {
-	struct daqboard2000_hw *fpga = devpriv->daq;
+	struct daqboard2000_private *devpriv = dev->private;
 
 	/* Disable hardware triggers */
 	udelay(2);
-	fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable;
+	writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable,
+	       devpriv->daq + trigControl);
 	udelay(2);
-	fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable;
+	writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable,
+	       devpriv->daq + trigControl);
 
 	/* Stop the scan list FIFO from loading the configuration pipe */
 	udelay(2);
-	fpga->acqControl = DAQBOARD2000_SeqStopScanList;
+	writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
 
 	/* Stop the pacer clock */
 	udelay(2);
-	fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
+	writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
 
 	/* Stop the input dma (abort channel 1) */
 	daqboard2000_adcStopDmaTransfer(dev);
@@ -630,41 +612,39 @@
 
 static void daqboard2000_activateReferenceDacs(struct comedi_device *dev)
 {
-	struct daqboard2000_hw *fpga = devpriv->daq;
+	struct daqboard2000_private *devpriv = dev->private;
+	unsigned int val;
 	int timeout;
 
 	/*  Set the + reference dac value in the FPGA */
-	fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect;
+	writew(0x80 | DAQBOARD2000_PosRefDacSelect, devpriv->daq + refDacs);
 	for (timeout = 0; timeout < 20; timeout++) {
-		if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0)
+		val = readw(devpriv->daq + dacControl);
+		if ((val & DAQBOARD2000_RefBusy) == 0)
 			break;
 		udelay(2);
 	}
-/*  printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/
 
 	/*  Set the - reference dac value in the FPGA */
-	fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect;
+	writew(0x80 | DAQBOARD2000_NegRefDacSelect, devpriv->daq + refDacs);
 	for (timeout = 0; timeout < 20; timeout++) {
-		if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0)
+		val = readw(devpriv->daq + dacControl);
+		if ((val & DAQBOARD2000_RefBusy) == 0)
 			break;
 		udelay(2);
 	}
-/*  printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/
 }
 
 static void daqboard2000_initializeCtrs(struct comedi_device *dev)
 {
-/*  printk("Implement: daqboard2000_initializeCtrs\n");*/
 }
 
 static void daqboard2000_initializeTmrs(struct comedi_device *dev)
 {
-/*  printk("Implement: daqboard2000_initializeTmrs\n");*/
 }
 
 static void daqboard2000_dacDisarm(struct comedi_device *dev)
 {
-/*  printk("Implement: daqboard2000_dacDisarm\n");*/
 }
 
 static void daqboard2000_initializeAdc(struct comedi_device *dev)
@@ -680,92 +660,66 @@
 	daqboard2000_dacDisarm(dev);
 }
 
-/*
-The test command, REMOVE!!:
-
-rmmod daqboard2000 ; rmmod comedi; make install ; modprobe daqboard2000; /usr/sbin/comedi_config /dev/comedi0 daqboard/2000 ; tail -40 /var/log/messages
-*/
-
 static int daqboard2000_8255_cb(int dir, int port, int data,
 				unsigned long ioaddr)
 {
-	int result = 0;
+	void __iomem *mmio_base = (void __iomem *)ioaddr;
+
 	if (dir) {
-		writew(data, ((void *)ioaddr) + port * 2);
-		result = 0;
+		writew(data, mmio_base + port * 2);
+		return 0;
 	} else {
-		result = readw(((void *)ioaddr) + port * 2);
+		return readw(mmio_base + port * 2);
 	}
-/*
-  printk("daqboard2000_8255_cb %x %d %d %2.2x -> %2.2x\n",
-        arg, dir, port, data, result);
-*/
-	return result;
 }
 
-static struct pci_dev *daqboard2000_find_pci_dev(struct comedi_device *dev,
-						 struct comedi_devconfig *it)
+static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
+					       struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
+	const struct daq200_boardtype *board;
 	int i;
 
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_IOTECH ||
-		    pcidev->device != 0x0409 ||
-		    pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
-			continue;
+	if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
+		return NULL;
 
-		for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
-			if (boardtypes[i].id != pcidev->subsystem_device)
-				continue;
-			dev->board_ptr = boardtypes + i;
-			return pcidev;
-		}
+	for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
+		board = &boardtypes[i];
+		if (pcidev->subsystem_device == board->id)
+			return board;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int daqboard2000_attach(struct comedi_device *dev,
-			       struct comedi_devconfig *it)
+static int daqboard2000_attach_pci(struct comedi_device *dev,
+				   struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev;
+	const struct daq200_boardtype *board;
+	struct daqboard2000_private *devpriv;
 	struct comedi_subdevice *s;
-	resource_size_t pci_base;
-	void *aux_data;
-	unsigned int aux_len;
 	int result;
 
-	result = alloc_private(dev, sizeof(struct daqboard2000_private));
-	if (result < 0)
-		return -ENOMEM;
-
-	pcidev = daqboard2000_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	result = comedi_pci_enable(pcidev, "daqboard2000");
-	if (result < 0) {
-		dev_err(dev->class_dev,
-			"failed to enable PCI device and request regions\n");
-		return -EIO;
-	}
+	board = daqboard2000_find_boardinfo(dev, pcidev);
+	if (!board)
+		return -ENODEV;
+	dev->board_ptr = board;
+	dev->board_name = board->name;
+
+	result = alloc_private(dev, sizeof(*devpriv));
+	if (result < 0)
+		return -ENOMEM;
+	devpriv = dev->private;
+
+	result = comedi_pci_enable(pcidev, dev->driver->driver_name);
+	if (result < 0)
+		return result;
 	dev->iobase = 1;	/* the "detach" needs this */
 
-	pci_base = pci_resource_start(pcidev, 0);
-	devpriv->plx = ioremap(pci_base, DAQBOARD2000_PLX_SIZE);
-	pci_base = pci_resource_start(pcidev, 2);
-	devpriv->daq = ioremap(pci_base, DAQBOARD2000_DAQ_SIZE);
+	devpriv->plx = ioremap(pci_resource_start(pcidev, 0),
+			       pci_resource_len(pcidev, 0));
+	devpriv->daq = ioremap(pci_resource_start(pcidev, 2),
+			       pci_resource_len(pcidev, 2));
 	if (!devpriv->plx || !devpriv->daq)
 		return -ENOMEM;
 
@@ -775,36 +729,14 @@
 
 	readl(devpriv->plx + 0x6c);
 
-	/*
-	   u8 interrupt;
-	   Windows code does restore interrupts, but since we don't use them...
-	   pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt);
-	   printk("Interrupt before is: %x\n", interrupt);
-	 */
-
-	aux_data = comedi_aux_data(it->options, 0);
-	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-
-	if (aux_data && aux_len) {
-		result = initialize_daqboard2000(dev, aux_data, aux_len);
-	} else {
-		dev_dbg(dev->class_dev,
-			"no FPGA initialization code, aborting\n");
-		result = -EIO;
-	}
+	result = daqboard2000_upload_firmware(dev);
 	if (result < 0)
-		goto out;
+		return result;
+
 	daqboard2000_initializeAdc(dev);
 	daqboard2000_initializeDac(dev);
-	/*
-	   Windows code does restore interrupts, but since we don't use them...
-	   pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt);
-	   printk("Interrupt after is: %x\n", interrupt);
-	 */
 
-	dev->board_name = this_board->name;
-
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ai subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -813,7 +745,7 @@
 	s->insn_read = daqboard2000_ai_insn_read;
 	s->range_table = &range_daqboard2000_ai;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -821,22 +753,27 @@
 	s->maxdata = 0xffff;
 	s->insn_read = daqboard2000_ao_insn_read;
 	s->insn_write = daqboard2000_ao_insn_write;
-	s->range_table = &range_daqboard2000_ao;
+	s->range_table = &range_bipolar10;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
-				  (unsigned long)(devpriv->daq + 0x40));
+			(unsigned long)(devpriv->daq + dioP2ExpansionIO8Bit));
+	if (result)
+		return result;
 
-out:
-	return result;
+	dev_info(dev->class_dev, "%s: %s attached\n",
+		dev->driver->driver_name, dev->board_name);
+
+	return 0;
 }
 
 static void daqboard2000_detach(struct comedi_device *dev)
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	struct daqboard2000_private *devpriv = dev->private;
 
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
+		subdev_8255_cleanup(dev, &dev->subdevices[2]);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (devpriv) {
@@ -855,7 +792,7 @@
 static struct comedi_driver daqboard2000_driver = {
 	.driver_name	= "daqboard2000",
 	.module		= THIS_MODULE,
-	.attach		= daqboard2000_attach,
+	.attach_pci	= daqboard2000_attach_pci,
 	.detach		= daqboard2000_detach,
 };
 
@@ -887,3 +824,4 @@
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE);
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 67a914a..5fd21fa 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -32,8 +32,9 @@
  *   [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
  *   DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
  *   DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
- *   DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08 or das08),
+ *   DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08),
  *   PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16)
+ * Updated: Fri, 31 Aug 2012 19:19:06 +0100
  * Status: works
  *
  * This is a rewrite of the das08 and das08jr drivers.
@@ -41,9 +42,8 @@
  * Options (for ISA cards):
  *		[0] - base io address
  *
- * Options (for pci-das08):
- *		[0] - bus  (optional)
- *		[1] = slot (optional)
+ * Manual configuration of PCI cards is not supported; they are
+ * configured automatically.
  *
  * The das08 driver doesn't support asynchronous commands, since
  * the cheap das08 hardware doesn't really support them.  The
@@ -61,9 +61,9 @@
 
 #define DRV_NAME "das08"
 
-#define DO_COMEDI_DRIVER_REGISTER \
-	(IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) || \
-	 IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
+#define DO_ISA IS_ENABLED(CONFIG_COMEDI_DAS08_ISA)
+#define DO_PCI IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+#define DO_COMEDI_DRIVER_REGISTER (DO_ISA || DO_PCI)
 
 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
 #define PCI_DEVICE_ID_PCIDAS08 0x29
@@ -236,6 +236,16 @@
 	das08_pgm_gainlist,
 };
 
+static inline bool is_isa_board(const struct das08_board_struct *board)
+{
+	return DO_ISA && board->bustype == isa;
+}
+
+static inline bool is_pci_board(const struct das08_board_struct *board)
+{
+	return DO_PCI && board->bustype == pci;
+}
+
 #define TIMEOUT 100000
 
 static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -342,9 +352,9 @@
 	return insn->n;
 }
 
-static int __maybe_unused
-das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
-		 struct comedi_insn *insn, unsigned int *data)
+static int das08jr_di_rbits(struct comedi_device *dev,
+			    struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data)
 {
 	data[0] = 0;
 	data[1] = inb(dev->iobase + DAS08JR_DIO);
@@ -352,9 +362,9 @@
 	return insn->n;
 }
 
-static int __maybe_unused
-das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-		 struct comedi_insn *insn, unsigned int *data)
+static int das08jr_do_wbits(struct comedi_device *dev,
+			    struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data)
 {
 	struct das08_private_struct *devpriv = dev->private;
 
@@ -369,88 +379,92 @@
 	return insn->n;
 }
 
-static int __maybe_unused
-das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		 struct comedi_insn *insn, unsigned int *data)
+static void das08_ao_set_data(struct comedi_device *dev,
+			      unsigned int chan, unsigned int data)
+{
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct das08_private_struct *devpriv = dev->private;
+	unsigned char lsb;
+	unsigned char msb;
+
+	lsb = data & 0xff;
+	msb = (data >> 8) & 0xff;
+	if (thisboard->is_jr) {
+		outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan));
+		outb(msb, dev->iobase + DAS08JR_AO_MSB(chan));
+		/* load DACs */
+		inb(dev->iobase + DAS08JR_DIO);
+	} else {
+		outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan));
+		outb(msb, dev->iobase + DAS08AO_AO_MSB(chan));
+		/* load DACs */
+		inb(dev->iobase + DAS08AO_AO_UPDATE);
+	}
+	devpriv->ao_readback[chan] = data;
+}
+
+static void das08_ao_initialize(struct comedi_device *dev,
+				struct comedi_subdevice *s)
 {
 	int n;
-	int lsb, msb;
-	int chan;
+	unsigned int data;
 
-	lsb = data[0] & 0xff;
-	msb = (data[0] >> 8) & 0xff;
+	data = s->maxdata / 2;	/* should be about 0 volts */
+	for (n = 0; n < s->n_chan; n++)
+		das08_ao_set_data(dev, n, data);
+}
+
+static int das08_ao_winsn(struct comedi_device *dev,
+			  struct comedi_subdevice *s,
+			  struct comedi_insn *insn, unsigned int *data)
+{
+	unsigned int n;
+	unsigned int chan;
 
 	chan = CR_CHAN(insn->chanspec);
 
-	for (n = 0; n < insn->n; n++) {
-#if 0
-		outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]);
-		outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]);
-#else
-		outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan));
-		outb(msb, dev->iobase + DAS08JR_AO_MSB(chan));
-#endif
-
-		/* load DACs */
-		inb(dev->iobase + DAS08JR_DIO);
-	}
+	for (n = 0; n < insn->n; n++)
+		das08_ao_set_data(dev, chan, *data);
 
 	return n;
 }
 
-/*
- *
- * The -aox boards have the DACs at a different offset and use
- * a different method to force an update.
- *
- */
-static int __maybe_unused
-das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		 struct comedi_insn *insn, unsigned int *data)
+static int das08_ao_rinsn(struct comedi_device *dev,
+			  struct comedi_subdevice *s,
+			  struct comedi_insn *insn, unsigned int *data)
 {
-	int n;
-	int lsb, msb;
-	int chan;
-
-	lsb = data[0] & 0xff;
-	msb = (data[0] >> 8) & 0xf;
+	struct das08_private_struct *devpriv = dev->private;
+	unsigned int n;
+	unsigned int chan;
 
 	chan = CR_CHAN(insn->chanspec);
 
-	for (n = 0; n < insn->n; n++) {
-#if 0
-		outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]);
-		outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]);
-#else
-		outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan));
-		outb(msb, dev->iobase + DAS08AO_AO_MSB(chan));
-#endif
-
-		/* load DACs */
-		inb(dev->iobase + DAS08AO_AO_UPDATE);
-	}
+	for (n = 0; n < insn->n; n++)
+		data[n] = devpriv->ao_readback[chan];
 
 	return n;
 }
 
 static void i8254_initialize(struct comedi_device *dev)
 {
-	struct das08_private_struct *devpriv = dev->private;
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
 	unsigned int mode = I8254_MODE0 | I8254_BINARY;
 	int i;
 
 	for (i = 0; i < 3; ++i)
-		i8254_set_mode(devpriv->i8254_iobase, 0, i, mode);
+		i8254_set_mode(i8254_iobase, 0, i, mode);
 }
 
 static int das08_counter_read(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	struct das08_private_struct *devpriv = dev->private;
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
 	int chan = insn->chanspec;
 
-	data[0] = i8254_read(devpriv->i8254_iobase, 0, chan);
+	data[0] = i8254_read(i8254_iobase, 0, chan);
 	return 1;
 }
 
@@ -458,10 +472,11 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	struct das08_private_struct *devpriv = dev->private;
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
 	int chan = insn->chanspec;
 
-	i8254_write(devpriv->i8254_iobase, 0, chan, data[0]);
+	i8254_write(i8254_iobase, 0, chan, data[0]);
 	return 1;
 }
 
@@ -469,18 +484,16 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	struct das08_private_struct *devpriv = dev->private;
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
 	int chan = insn->chanspec;
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	switch (data[0]) {
 	case INSN_CONFIG_SET_COUNTER_MODE:
-		i8254_set_mode(devpriv->i8254_iobase, 0, chan, data[1]);
+		i8254_set_mode(i8254_iobase, 0, chan, data[1]);
 		break;
 	case INSN_CONFIG_8254_READ_STATUS:
-		data[1] = i8254_status(devpriv->i8254_iobase, 0, chan);
+		data[1] = i8254_status(i8254_iobase, 0, chan);
 		break;
 	default:
 		return -EINVAL;
@@ -491,18 +504,14 @@
 
 #if DO_COMEDI_DRIVER_REGISTER
 static const struct das08_board_struct das08_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_DAS08_ISA)
+#if DO_ISA
 	{
 		.name = "isa-das08",	/*  cio-das08.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pg_none,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.ao_nbits = 12,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
 		.i8255_offset = 8,
 		.i8254_offset = 4,
@@ -511,13 +520,10 @@
 	{
 		.name = "das08-pgm",	/*  cio-das08pgx.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgm,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
 		.i8255_offset = 0,
 		.i8254_offset = 0x04,
@@ -526,44 +532,33 @@
 	{
 		.name = "das08-pgh",	/*  cio-das08pgx.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgh,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
-		.i8255_offset = 0,
 		.i8254_offset = 0x04,
 		.iosize = 16,		/*  unchecked */
 	},
 	{
 		.name = "das08-pgl",	/*  cio-das08pgx.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgl,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
-		.i8255_offset = 0,
 		.i8254_offset = 0x04,
 		.iosize = 16,		/*  unchecked */
 	},
 	{
 		.name = "das08-aoh",	/*  cio-das08_aox.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgh,
 		.ai_encoding = das08_encode12,
-		.ao = das08ao_ao_winsn,	/*  8 */
 		.ao_nbits = 12,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
 		.i8255_offset = 0x0c,
 		.i8254_offset = 0x04,
@@ -572,14 +567,11 @@
 	{
 		.name = "das08-aol",	/*  cio-das08_aox.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgl,
 		.ai_encoding = das08_encode12,
-		.ao = das08ao_ao_winsn,	/*  8 */
 		.ao_nbits = 12,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
 		.i8255_offset = 0x0c,
 		.i8254_offset = 0x04,
@@ -588,14 +580,11 @@
 	{
 		.name = "das08-aom",	/*  cio-das08_aox.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_pgm,
 		.ai_encoding = das08_encode12,
-		.ao = das08ao_ao_winsn,	/*  8 */
 		.ao_nbits = 12,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
 		.i8255_offset = 0x0c,
 		.i8254_offset = 0x04,
@@ -604,152 +593,68 @@
 	{
 		.name = "das08/jr-ao",	/*  cio-das08-jr-ao.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
+		.is_jr = true,
 		.ai_nbits = 12,
 		.ai_pg = das08_pg_none,
 		.ai_encoding = das08_encode12,
-		.ao = das08jr_ao_winsn,
 		.ao_nbits = 12,
-		.di = das08jr_di_rbits,
-		.do_ = das08jr_do_wbits,
+		.di_nchan = 8,
 		.do_nchan = 8,
-		.i8255_offset = 0,
-		.i8254_offset = 0,
 		.iosize = 16,		/*  unchecked */
 	},
 	{
 		.name = "das08jr-16-ao",	/*  cio-das08jr-16-ao.pdf */
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
+		.is_jr = true,
 		.ai_nbits = 16,
 		.ai_pg = das08_pg_none,
 		.ai_encoding = das08_encode16,
-		.ao = das08jr_ao_winsn,
 		.ao_nbits = 16,
-		.di = das08jr_di_rbits,
-		.do_ = das08jr_do_wbits,
+		.di_nchan = 8,
 		.do_nchan = 8,
-		.i8255_offset = 0,
 		.i8254_offset = 0x04,
 		.iosize = 16,		/*  unchecked */
 	},
 	{
 		.name = "pc104-das08",
-		.bustype = pc104,
-		.ai = das08_ai_rinsn,
+		.bustype = isa,
 		.ai_nbits = 12,
 		.ai_pg = das08_pg_none,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.ao_nbits = 0,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
-		.i8255_offset = 0,
 		.i8254_offset = 4,
 		.iosize = 16,		/*  unchecked */
 	},
-#if 0
-	{
-		.name = "das08/f",
-	},
-	{
-		.name = "das08jr",
-	},
-#endif
 	{
 		.name = "das08jr/16",
 		.bustype = isa,
-		.ai = das08_ai_rinsn,
+		.is_jr = true,
 		.ai_nbits = 16,
 		.ai_pg = das08_pg_none,
 		.ai_encoding = das08_encode16,
-		.ao = NULL,
-		.ao_nbits = 0,
-		.di = das08jr_di_rbits,
-		.do_ = das08jr_do_wbits,
+		.di_nchan = 8,
 		.do_nchan = 8,
-		.i8255_offset = 0,
-		.i8254_offset = 0,
 		.iosize = 16,		/*  unchecked */
 	},
-#if 0
-	{
-		.name = "das48-pga",	/*  cio-das48-pga.pdf */
-	},
-	{
-		.name = "das08-pga-g2",	/*  a KM board */
-	},
-#endif
-#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) */
-#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+#endif /* DO_ISA */
+#if DO_PCI
 	{
 		.name = "pci-das08",	/*  pci-das08 */
 		.id = PCI_DEVICE_ID_PCIDAS08,
 		.bustype = pci,
-		.ai = das08_ai_rinsn,
 		.ai_nbits = 12,
 		.ai_pg = das08_bipolar5,
 		.ai_encoding = das08_encode12,
-		.ao = NULL,
-		.ao_nbits = 0,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
+		.di_nchan = 3,
 		.do_nchan = 4,
-		.i8255_offset = 0,
 		.i8254_offset = 4,
 		.iosize = 8,
 	},
-	{ /* wildcard entry matches any supported PCI device */
-		.name = DRV_NAME,
-		.id = PCI_ANY_ID,
-		.bustype = pci,
-	},
-#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) */
+#endif /* DO_PCI */
 };
 #endif /* DO_COMEDI_DRIVER_REGISTER */
 
-#if IS_ENABLED(CONFIG_COMEDI_DAS08_CS)
-struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
-	{
-		.name = "pcm-das08",
-		.id = 0x0,		/*  XXX */
-		.bustype = pcmcia,
-		.ai = das08_ai_rinsn,
-		.ai_nbits = 12,
-		.ai_pg = das08_bipolar5,
-		.ai_encoding = das08_pcm_encode12,
-		.ao = NULL,
-		.ao_nbits = 0,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
-		.do_nchan = 3,
-		.i8255_offset = 0,
-		.i8254_offset = 0,
-		.iosize = 16,
-	},
-	/*  duplicate so driver name can be used also */
-	{
-		.name = "das08_cs",
-		.id = 0x0,		/*  XXX */
-		.bustype = pcmcia,
-		.ai = das08_ai_rinsn,
-		.ai_nbits = 12,
-		.ai_pg = das08_bipolar5,
-		.ai_encoding = das08_pcm_encode12,
-		.ao = NULL,
-		.ao_nbits = 0,
-		.di = das08_di_rbits,
-		.do_ = das08_do_wbits,
-		.do_nchan = 3,
-		.i8255_offset = 0,
-		.i8254_offset = 0,
-		.iosize = 16,
-	},
-};
-EXPORT_SYMBOL_GPL(das08_cs_boards);
-#endif
-
 int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
 {
 	const struct das08_board_struct *thisboard = comedi_board(dev);
@@ -765,9 +670,9 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ai */
-	if (thisboard->ai) {
+	if (thisboard->ai_nbits) {
 		s->type = COMEDI_SUBD_AI;
 		/* XXX some boards actually have differential
 		 * inputs instead of single ended.
@@ -778,53 +683,56 @@
 		s->n_chan = 8;
 		s->maxdata = (1 << thisboard->ai_nbits) - 1;
 		s->range_table = das08_ai_lranges[thisboard->ai_pg];
-		s->insn_read = thisboard->ai;
+		s->insn_read = das08_ai_rinsn;
 		devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg];
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* ao */
-	if (thisboard->ao) {
+	if (thisboard->ao_nbits) {
 		s->type = COMEDI_SUBD_AO;
-/* XXX lacks read-back insn */
 		s->subdev_flags = SDF_WRITABLE;
 		s->n_chan = 2;
 		s->maxdata = (1 << thisboard->ao_nbits) - 1;
 		s->range_table = &range_bipolar5;
-		s->insn_write = thisboard->ao;
+		s->insn_write = das08_ao_winsn;
+		s->insn_read = das08_ao_rinsn;
+		das08_ao_initialize(dev, s);
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* di */
-	if (thisboard->di) {
+	if (thisboard->di_nchan) {
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
-		s->n_chan = (thisboard->di == das08_di_rbits) ? 3 : 8;
+		s->n_chan = thisboard->di_nchan;
 		s->maxdata = 1;
 		s->range_table = &range_digital;
-		s->insn_bits = thisboard->di;
+		s->insn_bits =
+			thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits;
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* do */
-	if (thisboard->do_) {
+	if (thisboard->do_nchan) {
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 		s->n_chan = thisboard->do_nchan;
 		s->maxdata = 1;
 		s->range_table = &range_digital;
-		s->insn_bits = thisboard->do_;
+		s->insn_bits =
+			thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits;
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	/* 8255 */
 	if (thisboard->i8255_offset != 0) {
 		subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase +
@@ -834,7 +742,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 5;
+	s = &dev->subdevices[5];
 	/* 8254 */
 	if (thisboard->i8254_offset != 0) {
 		s->type = COMEDI_SUBD_COUNTER;
@@ -844,8 +752,6 @@
 		s->insn_read = das08_counter_read;
 		s->insn_write = das08_counter_write;
 		s->insn_config = das08_counter_config;
-
-		devpriv->i8254_iobase = iobase + thisboard->i8254_offset;
 		i8254_initialize(dev);
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
@@ -855,50 +761,13 @@
 }
 EXPORT_SYMBOL_GPL(das08_common_attach);
 
-static int das08_pci_attach_common(struct comedi_device *dev,
-				   struct pci_dev *pdev)
-{
-	unsigned long iobase;
-	unsigned long pci_iobase;
-	struct das08_private_struct *devpriv = dev->private;
-
-	if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
-		return -EINVAL;
-
-	devpriv->pdev = pdev;
-	/*  enable PCI device and reserve I/O spaces */
-	if (comedi_pci_enable(pdev, dev->driver->driver_name)) {
-		dev_err(dev->class_dev,
-			"Error enabling PCI device and requesting regions\n");
-		return -EIO;
-	}
-	/*  read base addresses */
-	pci_iobase = pci_resource_start(pdev, 1);
-	iobase = pci_resource_start(pdev, 2);
-	dev_info(dev->class_dev, "pcibase 0x%lx  iobase 0x%lx\n",
-		 pci_iobase, iobase);
-	devpriv->pci_iobase = pci_iobase;
-#if 0
-	/* We could enable pci-das08's interrupt here to make it possible
-	* to do timed input in this driver, but there is little point since
-	* conversions would have to be started by the interrupt handler
-	* so you might as well use comedi_rt_timer to emulate commands
-	*/
-	/* set source of interrupt trigger to counter2 output */
-	outb(CNTRL_INTR | CNTRL_DIR, pci_iobase + CNTRL);
-	/* Enable local interrupt 1 and pci interrupt */
-	outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
-#endif
-	return das08_common_attach(dev, iobase);
-}
-
 static const struct das08_board_struct *
 das08_find_pci_board(struct pci_dev *pdev)
 {
 #if DO_COMEDI_DRIVER_REGISTER
 	unsigned int i;
 	for (i = 0; i < ARRAY_SIZE(das08_boards); i++)
-		if (das08_boards[i].bustype == pci &&
+		if (is_pci_board(&das08_boards[i]) &&
 		    pdev->device == das08_boards[i].id)
 			return &das08_boards[i];
 #endif
@@ -909,9 +778,10 @@
 static int __devinit __maybe_unused
 das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev)
 {
+	unsigned long iobase;
 	int ret;
 
-	if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
+	if (!DO_PCI)
 		return -EINVAL;
 	ret = alloc_private(dev, sizeof(struct das08_private_struct));
 	if (ret < 0)
@@ -922,65 +792,16 @@
 		dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
 		return -EINVAL;
 	}
-	/*
-	 * Need to 'get' the PCI device to match the 'put' in das08_detach().
-	 * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
-	 * support for manual attachment of PCI devices via das08_attach()
-	 * has been removed.
-	 */
-	pci_dev_get(pdev);
-	return das08_pci_attach_common(dev, pdev);
-}
-
-static struct pci_dev *das08_find_pci(struct comedi_device *dev,
-				      int bus, int slot)
-{
-	const struct das08_board_struct *thisboard = comedi_board(dev);
-	struct pci_dev *pdev;
-	unsigned int matchid;
-
-	if (bus || slot)
-		dev_dbg(dev->class_dev, "Looking for %s at PCI %02X:%02X\n",
-			thisboard->name, bus, slot);
-	else
-		dev_dbg(dev->class_dev, "Looking for %s on PCI buses\n",
-			thisboard->name);
-
-	matchid = thisboard->id;
-	pdev = NULL;
-	for_each_pci_dev(pdev) {
-		if ((bus || slot) &&
-		    (bus != pdev->bus->number || slot != PCI_SLOT(pdev->devfn)))
-			continue;
-		if (pdev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
-			continue;
-		if (matchid == PCI_ANY_ID) {
-			/* wildcard board matches any supported PCI board */
-			const struct das08_board_struct *foundboard;
-			foundboard = das08_find_pci_board(pdev);
-			if (foundboard == NULL)
-				continue;
-			/* replace wildcard board_ptr */
-			dev->board_ptr = thisboard = foundboard;
-		} else {
-			/* match specific PCI board */
-			if (pdev->device != matchid)
-				continue;
-		}
-		/* found a match */
-		dev_info(dev->class_dev, "Found %s at PCI %s\n",
-			 thisboard->name, pci_name(pdev));
-		return pdev;
-	}
-	/* no match found */
-	if (bus || slot)
+	comedi_set_hw_dev(dev, &pdev->dev);
+	/*  enable PCI device and reserve I/O spaces */
+	if (comedi_pci_enable(pdev, dev->driver->driver_name)) {
 		dev_err(dev->class_dev,
-			"No %s cards found at PCI %02X:%02X\n",
-			thisboard->name, bus, slot);
-	else
-		dev_err(dev->class_dev, "No %s cards found on PCI buses\n",
-			thisboard->name);
-	return NULL;
+			"Error enabling PCI device and requesting regions\n");
+		return -EIO;
+	}
+	/*  read base addresses */
+	iobase = pci_resource_start(pdev, 2);
+	return das08_common_attach(dev, iobase);
 }
 
 static int __maybe_unused
@@ -997,14 +818,12 @@
 	devpriv = dev->private;
 
 	dev_info(dev->class_dev, "attach\n");
-	if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) && thisboard->bustype == pci) {
-		struct pci_dev *pdev;
-		pdev = das08_find_pci(dev, it->options[0], it->options[1]);
-		if (pdev == NULL)
-			return -EIO;
-		return das08_pci_attach_common(dev, pdev);
-	} else if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) &&
-		   (thisboard->bustype == isa || thisboard->bustype == pc104)) {
+	if (is_pci_board(thisboard)) {
+		dev_err(dev->class_dev,
+			"Manual configuration of PCI board '%s' is not supported\n",
+			thisboard->name);
+		return -EIO;
+	} else if (is_isa_board(thisboard)) {
 		iobase = it->options[0];
 		dev_info(dev->class_dev, "iobase 0x%lx\n", iobase);
 		if (!request_region(iobase, thisboard->iosize, DRV_NAME)) {
@@ -1019,26 +838,23 @@
 void das08_common_detach(struct comedi_device *dev)
 {
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 4);
+		subdev_8255_cleanup(dev, &dev->subdevices[4]);
 }
 EXPORT_SYMBOL_GPL(das08_common_detach);
 
 static void __maybe_unused das08_detach(struct comedi_device *dev)
 {
 	const struct das08_board_struct *thisboard = comedi_board(dev);
-	struct das08_private_struct *devpriv = dev->private;
 
 	das08_common_detach(dev);
-	if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) &&
-	    (thisboard->bustype == isa || thisboard->bustype == pc104)) {
+	if (is_isa_board(thisboard)) {
 		if (dev->iobase)
 			release_region(dev->iobase, thisboard->iosize);
-	} else if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) &&
-		   thisboard->bustype == pci) {
-		if (devpriv && devpriv->pdev) {
-			if (devpriv->pci_iobase)
-				comedi_pci_disable(devpriv->pdev);
-			pci_dev_put(devpriv->pdev);
+	} else if (is_pci_board(thisboard)) {
+		struct pci_dev *pdev = comedi_to_pci_dev(dev);
+		if (pdev) {
+			if (dev->iobase)
+				comedi_pci_disable(pdev);
 		}
 	}
 }
@@ -1056,7 +872,7 @@
 };
 #endif
 
-#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
 	{0}
@@ -1081,10 +897,10 @@
 	.probe = &das08_pci_probe,
 	.remove = __devexit_p(&das08_pci_remove)
 };
-#endif /* CONFIG_COMEDI_DAS08_PCI */
+#endif /* DO_PCI */
 
 #if DO_COMEDI_DRIVER_REGISTER
-#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+#if DO_PCI
 module_comedi_pci_driver(das08_driver, das08_pci_driver);
 #else
 module_comedi_driver(das08_driver);
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 27b6d4e..0314bae 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -24,7 +24,7 @@
 #ifndef _DAS08_H
 #define _DAS08_H
 
-enum das08_bustype { isa, pci, pcmcia, pc104 };
+enum das08_bustype { isa, pci, pcmcia };
 /* different ways ai data is encoded in first two registers */
 enum das08_ai_encoding { das08_encode12, das08_encode16, das08_pcm_encode12 };
 enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl,
@@ -35,14 +35,12 @@
 	const char *name;
 	unsigned int id;	/*  id for pci/pcmcia boards */
 	enum das08_bustype bustype;
-	void *ai;
+	bool is_jr;		/* true for 'JR' boards */
 	unsigned int ai_nbits;
 	enum das08_lrange ai_pg;
 	enum das08_ai_encoding ai_encoding;
-	void *ao;
 	unsigned int ao_nbits;
-	void *di;
-	void *do_;
+	unsigned int di_nchan;
 	unsigned int do_nchan;
 	unsigned int i8255_offset;
 	unsigned int i8254_offset;
@@ -53,14 +51,9 @@
 	unsigned int do_mux_bits;	/*  bits for do/mux register on boards without separate do register */
 	unsigned int do_bits;	/*  bits for do register on boards with register dedicated to digital out only */
 	const unsigned int *pg_gainlist;
-	struct pci_dev *pdev;	/*  struct for pci-das08 */
-	unsigned int pci_iobase;	/*  additional base address for pci-das08 */
-	unsigned int i8254_iobase;
+	unsigned int ao_readback[2];	/* assume 2 AO channels */
 };
 
-#define NUM_DAS08_CS_BOARDS 2
-extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS];
-
 int das08_common_attach(struct comedi_device *dev, unsigned long iobase);
 void das08_common_detach(struct comedi_device *dev);
 
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index f5700de..e4c91e6 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -58,6 +58,32 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
+static const struct das08_board_struct das08_cs_boards[] = {
+	{
+		.name = "pcm-das08",
+		.id = 0x0,		/*  XXX */
+		.bustype = pcmcia,
+		.ai_nbits = 12,
+		.ai_pg = das08_bipolar5,
+		.ai_encoding = das08_pcm_encode12,
+		.di_nchan = 3,
+		.do_nchan = 3,
+		.iosize = 16,
+	},
+	/*  duplicate so driver name can be used also */
+	{
+		.name = "das08_cs",
+		.id = 0x0,		/*  XXX */
+		.bustype = pcmcia,
+		.ai_nbits = 12,
+		.ai_pg = das08_bipolar5,
+		.ai_encoding = das08_pcm_encode12,
+		.di_nchan = 3,
+		.do_nchan = 3,
+		.iosize = 16,
+	},
+};
+
 static struct pcmcia_device *cur_dev;
 
 static int das08_cs_attach(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 895cc77..fcb8a32 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -402,62 +402,42 @@
 	int gain, start_chan, i;
 	int mask;
 
-	/* make sure triggers are valid */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->scan_begin_src;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+
 	mask = TRIG_FOLLOW;
 	/*  if board supports burst mode */
 	if (board->size > 0x400)
 		mask |= TRIG_TIMER | TRIG_EXT;
-	cmd->scan_begin_src &= mask;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
 
 	tmp = cmd->convert_src;
 	mask = TRIG_TIMER | TRIG_EXT;
 	/*  if board supports burst mode */
 	if (board->size > 0x400)
 		mask |= TRIG_NOW;
-	cmd->convert_src &= mask;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, mask);
 
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/**
-	 * step 2: make sure trigger sources are unique and
-	 * mutually compatible
-	 */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	/*  make sure scan_begin_src and convert_src dont conflict */
 	if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
-		err++;
+		err |= -EINVAL;
 	if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -558,7 +538,7 @@
 
 /* utility function that suggests a dma transfer size in bytes */
 static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
-						struct comedi_cmd cmd)
+						const struct comedi_cmd *cmd)
 {
 	unsigned int size;
 	unsigned int freq;
@@ -571,16 +551,16 @@
 
 	/* otherwise, we are relying on dma terminal count interrupt,
 	 * so pick a reasonable size */
-	if (cmd.convert_src == TRIG_TIMER)
-		freq = 1000000000 / cmd.convert_arg;
-	else if (cmd.scan_begin_src == TRIG_TIMER)
-		freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
+	if (cmd->convert_src == TRIG_TIMER)
+		freq = 1000000000 / cmd->convert_arg;
+	else if (cmd->scan_begin_src == TRIG_TIMER)
+		freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len;
 	/*  return some default value */
 	else
 		freq = 0xffffffff;
 
-	if (cmd.flags & TRIG_WAKE_EOS) {
-		size = sample_size * cmd.chanlist_len;
+	if (cmd->flags & TRIG_WAKE_EOS) {
+		size = sample_size * cmd->chanlist_len;
 	} else {
 		/*  make buffer fill in no more than 1/3 second */
 		size = (freq / 3) * sample_size;
@@ -592,7 +572,7 @@
 	else if (size < sample_size)
 		size = sample_size;
 
-	if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
+	if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
 		size = devpriv->adc_byte_count;
 
 	return size;
@@ -685,7 +665,7 @@
 	set_dma_addr(devpriv->dma_chan,
 		     devpriv->dma_buffer_addr[devpriv->current_buffer]);
 	/*  set appropriate size of transfer */
-	devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd);
+	devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd);
 	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
 	enable_dma(devpriv->dma_chan);
 	release_dma_lock(flags);
@@ -1268,7 +1248,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* ai */
 	if (board->ai) {
@@ -1300,7 +1280,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* ao */
 	if (board->ao) {
 		s->type = COMEDI_SUBD_AO;
@@ -1318,7 +1298,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* di */
 	if (board->di) {
 		s->type = COMEDI_SUBD_DI;
@@ -1331,7 +1311,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* do */
 	if (board->do_) {
 		s->type = COMEDI_SUBD_DO;
@@ -1346,7 +1326,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	/* 8255 */
 	if (board->i8255_offset != 0) {
 		subdev_8255_init(dev, s, NULL, (dev->iobase +
@@ -1376,7 +1356,7 @@
 
 	das16_reset(dev);
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 4);
+		subdev_8255_cleanup(dev, &dev->subdevices[4]);
 	if (devpriv) {
 		int i;
 		for (i = 0; i < 2; i++) {
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 2009263..3f87d75 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -170,42 +170,24 @@
 	const struct das16m1_board *board = comedi_board(dev);
 	unsigned int err = 0, tmp, i;
 
-	/* make sure triggers are valid */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -650,7 +632,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* ai */
 	s->type = COMEDI_SUBD_AI;
@@ -666,7 +648,7 @@
 	s->cancel = das16m1_cancel;
 	s->poll = das16m1_poll;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* di */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -675,7 +657,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = das16m1_di_rbits;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* do */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
@@ -684,7 +666,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = das16m1_do_wbits;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* 8255 */
 	subdev_8255_init(dev, s, NULL, dev->iobase + DAS16M1_82C55);
 
@@ -707,7 +689,7 @@
 static void das16m1_detach(struct comedi_device *dev)
 {
 	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 3);
+		subdev_8255_cleanup(dev, &dev->subdevices[3]);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase) {
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 25e7e56..2555f32 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -656,7 +656,7 @@
 /* the guts of the interrupt handler, that is shared with das1800_ai_poll */
 static void das1800_ai_handler(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + 0;	/* analog input subdevice */
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
 	unsigned int status = inb(dev->iobase + DAS1800_STATUS);
@@ -784,59 +784,35 @@
 				 struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 	unsigned int tmp_arg;
 	int i;
 	int unipolar;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src,
+					TRIG_COUNT | TRIG_EXT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/*  uniqueness check */
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT &&
-	    cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
-		err++;
-	/* compatibility check */
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->scan_begin_src != TRIG_FOLLOW &&
 	    cmd->convert_src != TRIG_TIMER)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -958,14 +934,14 @@
 }
 
 /* returns appropriate bits for control register a, depending on command */
-static int control_a_bits(struct comedi_cmd cmd)
+static int control_a_bits(const struct comedi_cmd *cmd)
 {
 	int control_a;
 
 	control_a = FFEN;	/* enable fifo */
-	if (cmd.stop_src == TRIG_EXT)
+	if (cmd->stop_src == TRIG_EXT)
 		control_a |= ATEN;
-	switch (cmd.start_src) {
+	switch (cmd->start_src) {
 	case TRIG_EXT:
 		control_a |= TGEN | CGSL;
 		break;
@@ -980,7 +956,7 @@
 }
 
 /* returns appropriate bits for control register c, depending on command */
-static int control_c_bits(struct comedi_cmd cmd)
+static int control_c_bits(const struct comedi_cmd *cmd)
 {
 	int control_c;
 	int aref;
@@ -988,18 +964,18 @@
 	/* set clock source to internal or external, select analog reference,
 	 * select unipolar / bipolar
 	 */
-	aref = CR_AREF(cmd.chanlist[0]);
+	aref = CR_AREF(cmd->chanlist[0]);
 	control_c = UQEN;	/* enable upper qram addresses */
 	if (aref != AREF_DIFF)
 		control_c |= SD;
 	if (aref == AREF_COMMON)
 		control_c |= CMEN;
 	/* if a unipolar range was selected */
-	if (CR_RANGE(cmd.chanlist[0]) & UNIPOLAR)
+	if (CR_RANGE(cmd->chanlist[0]) & UNIPOLAR)
 		control_c |= UB;
-	switch (cmd.scan_begin_src) {
+	switch (cmd->scan_begin_src) {
 	case TRIG_FOLLOW:	/*  not in burst mode */
-		switch (cmd.convert_src) {
+		switch (cmd->convert_src) {
 		case TRIG_TIMER:
 			/* trig on cascaded counters */
 			control_c |= IPCLK;
@@ -1047,29 +1023,33 @@
 }
 
 /* sets up counters */
-static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd)
+static int setup_counters(struct comedi_device *dev,
+			  const struct comedi_cmd *cmd)
 {
+	unsigned int period;
+
 	/*  setup cascaded counters for conversion/scan frequency */
-	switch (cmd.scan_begin_src) {
+	switch (cmd->scan_begin_src) {
 	case TRIG_FOLLOW:	/*  not in burst mode */
-		if (cmd.convert_src == TRIG_TIMER) {
+		if (cmd->convert_src == TRIG_TIMER) {
 			/* set conversion frequency */
+			period = cmd->convert_arg;
 			i8253_cascade_ns_to_timer_2div(TIMER_BASE,
-						       &(devpriv->divisor1),
-						       &(devpriv->divisor2),
-						       &(cmd.convert_arg),
-						       cmd.
-						       flags & TRIG_ROUND_MASK);
+						       &devpriv->divisor1,
+						       &devpriv->divisor2,
+						       &period,
+						       cmd->flags &
+							TRIG_ROUND_MASK);
 			if (das1800_set_frequency(dev) < 0)
 				return -1;
 		}
 		break;
 	case TRIG_TIMER:	/*  in burst mode */
 		/* set scan frequency */
-		i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
-					       &(devpriv->divisor2),
-					       &(cmd.scan_begin_arg),
-					       cmd.flags & TRIG_ROUND_MASK);
+		period = cmd->scan_begin_arg;
+		i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1,
+					       &devpriv->divisor2, &period,
+					       cmd->flags & TRIG_ROUND_MASK);
 		if (das1800_set_frequency(dev) < 0)
 			return -1;
 		break;
@@ -1078,7 +1058,7 @@
 	}
 
 	/*  setup counter 0 for 'about triggering' */
-	if (cmd.stop_src == TRIG_EXT) {
+	if (cmd->stop_src == TRIG_EXT) {
 		/*  load counter 0 in mode 0 */
 		i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0);
 	}
@@ -1087,7 +1067,7 @@
 }
 
 /* utility function that suggests a dma transfer size based on the conversion period 'ns' */
-static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
+static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd)
 {
 	unsigned int size = DMA_BUF_SIZE;
 	static const int sample_size = 2;	/*  size in bytes of one sample from board */
@@ -1125,7 +1105,7 @@
 }
 
 /* sets up dma */
-static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd)
+static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
 {
 	unsigned long lock_flags;
 	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
@@ -1134,7 +1114,7 @@
 		return;
 
 	/* determine a reasonable dma transfer size */
-	devpriv->dma_transfer_size = suggest_transfer_size(&cmd);
+	devpriv->dma_transfer_size = suggest_transfer_size(cmd);
 	lock_flags = claim_dma_lock();
 	disable_dma(devpriv->dma0);
 	/* clear flip-flop to make sure 2-byte registers for
@@ -1163,14 +1143,15 @@
 }
 
 /* programs channel/gain list into card */
-static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd)
+static void program_chanlist(struct comedi_device *dev,
+			     const struct comedi_cmd *cmd)
 {
 	int i, n, chan_range;
 	unsigned long irq_flags;
 	const int range_mask = 0x3;	/* masks unipolar/bipolar bit off range */
 	const int range_bitshift = 8;
 
-	n = cmd.chanlist_len;
+	n = cmd->chanlist_len;
 	/*  spinlock protects indirect addressing */
 	spin_lock_irqsave(&dev->spinlock, irq_flags);
 	outb(QRAM, dev->iobase + DAS1800_SELECT);	/* select QRAM for baseAddress + 0x0 */
@@ -1178,9 +1159,9 @@
 	/* make channel / gain list */
 	for (i = 0; i < n; i++) {
 		chan_range =
-		    CR_CHAN(cmd.
-			    chanlist[i]) | ((CR_RANGE(cmd.chanlist[i]) &
-					     range_mask) << range_bitshift);
+		    CR_CHAN(cmd->chanlist[i]) |
+		    ((CR_RANGE(cmd->chanlist[i]) & range_mask) <<
+		     range_bitshift);
 		outw(chan_range, dev->iobase + DAS1800_QRAM);
 	}
 	outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS);	/*finish write to QRAM */
@@ -1196,7 +1177,7 @@
 	int ret;
 	int control_a, control_c;
 	struct comedi_async *async = s->async;
-	struct comedi_cmd cmd = async->cmd;
+	const struct comedi_cmd *cmd = &async->cmd;
 
 	if (!dev->irq) {
 		comedi_error(dev,
@@ -1206,12 +1187,12 @@
 
 	/* disable dma on TRIG_WAKE_EOS, or TRIG_RT
 	 * (because dma in handler is unsafe at hard real-time priority) */
-	if (cmd.flags & (TRIG_WAKE_EOS | TRIG_RT))
+	if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT))
 		devpriv->irq_dma_bits &= ~DMA_ENABLED;
 	else
 		devpriv->irq_dma_bits |= devpriv->dma_bits;
 	/*  interrupt on end of conversion for TRIG_WAKE_EOS */
-	if (cmd.flags & TRIG_WAKE_EOS) {
+	if (cmd->flags & TRIG_WAKE_EOS) {
 		/*  interrupt fifo not empty */
 		devpriv->irq_dma_bits &= ~FIMD;
 	} else {
@@ -1219,8 +1200,8 @@
 		devpriv->irq_dma_bits |= FIMD;
 	}
 	/*  determine how many conversions we need */
-	if (cmd.stop_src == TRIG_COUNT)
-		devpriv->count = cmd.stop_arg * cmd.chanlist_len;
+	if (cmd->stop_src == TRIG_COUNT)
+		devpriv->count = cmd->stop_arg * cmd->chanlist_len;
 
 	das1800_cancel(dev, s);
 
@@ -1240,9 +1221,9 @@
 	/*  set conversion rate and length for burst mode */
 	if (control_c & BMDE) {
 		/*  program conversion period with number of microseconds minus 1 */
-		outb(cmd.convert_arg / 1000 - 1,
+		outb(cmd->convert_arg / 1000 - 1,
 		     dev->iobase + DAS1800_BURST_RATE);
-		outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);
+		outb(cmd->chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);
 	}
 	outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B);	/*  enable irq/dma */
 	outb(control_a, dev->iobase + DAS1800_CONTROL_A);	/* enable fifo and triggering */
@@ -1653,7 +1634,7 @@
 		return retval;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ;
@@ -1670,7 +1651,7 @@
 	s->cancel = das1800_cancel;
 
 	/* analog out */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (thisboard->ao_ability == 1) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE;
@@ -1683,7 +1664,7 @@
 	}
 
 	/* di */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 4;
@@ -1692,7 +1673,7 @@
 	s->insn_bits = das1800_di_rbits;
 
 	/* do */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 	s->n_chan = thisboard->do_n_chan;
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index e3afcfa..e134c46 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -152,7 +152,7 @@
 static irqreturn_t intr_handler(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 
 	if (!dev->attached || devpriv->das6402_ignoreirq) {
 		dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
@@ -312,7 +312,7 @@
 		return ret;
 
 	/* ai subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = 8;
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index a0959a5..215deac 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -435,7 +435,7 @@
 	if (fifo_overflow) {
 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 		comedi_error(dev, "DAS800 FIFO overflow");
-		das800_cancel(dev, dev->subdevices + 0);
+		das800_cancel(dev, s);
 		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 		comedi_event(dev, s);
 		async->events = 0;
@@ -517,7 +517,7 @@
 		return ret;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
@@ -531,7 +531,7 @@
 	s->cancel = das800_cancel;
 
 	/* di */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 3;
@@ -540,7 +540,7 @@
 	s->insn_bits = das800_di_rbits;
 
 	/* do */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 	s->n_chan = 4;
@@ -609,44 +609,24 @@
 	int gain, startChan;
 	int i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 7107f59..4d5c33c 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -41,6 +41,8 @@
 #include "../comedidev.h"
 #include <linux/ioport.h>
 
+#include "comedi_fc.h"
+
 /* Board register addresses */
 
 #define DMM32AT_MEMSIZE 0x10
@@ -258,47 +260,26 @@
 	int tmp;
 	int start_chan, gain, i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER /*| TRIG_EXT */);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER /*| TRIG_EXT */);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-	 * compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -825,7 +806,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
@@ -841,7 +822,7 @@
 	s->do_cmdtest = dmm32at_ai_cmdtest;
 	s->cancel = dmm32at_ai_cancel;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -851,7 +832,7 @@
 	s->insn_write = dmm32at_ao_winsn;
 	s->insn_read = dmm32at_ao_rinsn;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital i/o subdevice */
 
 	/* get access to the DIO regs */
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index d332269..c59a652 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -532,7 +532,7 @@
 {
 	int which = 0;
 
-	if (s == dev->subdevices + 4)
+	if (s == &dev->subdevices[3])
 		which = 1;
 
 	if (data[0]) {
@@ -555,7 +555,7 @@
 {
 	int which = 0;
 
-	if (s == dev->subdevices + 4)
+	if (s == &dev->subdevices[3])
 		which = 1;
 
 	/* configure */
@@ -636,7 +636,7 @@
 
 	dev->board_name = boardtype.name;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ai subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -652,7 +652,7 @@
 	s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
 	s->insn_read = dt2801_ai_insn_read;
 
-	s++;
+	s = &dev->subdevices[1];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -664,7 +664,7 @@
 	s->insn_read = dt2801_ao_insn_read;
 	s->insn_write = dt2801_ao_insn_write;
 
-	s++;
+	s = &dev->subdevices[2];
 	/* 1st digital subdevice */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -674,7 +674,7 @@
 	s->insn_bits = dt2801_dio_insn_bits;
 	s->insn_config = dt2801_dio_insn_config;
 
-	s++;
+	s = &dev->subdevices[3];
 	/* 2nd digital subdevice */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 290b933..d3a8c1a 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -510,7 +510,7 @@
 		break;
 	}
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* initialize the ADC subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -530,7 +530,7 @@
 		break;
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -542,7 +542,7 @@
 	devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
 	devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* di subdevice */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -551,7 +551,7 @@
 	s->maxdata = 1;
 	s->range_table = &range_digital;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* do subdevice */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 2e39ebe..064a8f2 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -45,6 +45,8 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 
+#include "comedi_fc.h"
+
 #define DT2814_SIZE 2
 
 #define DT2814_CSR 0
@@ -129,42 +131,22 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are
-	 * unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -247,7 +229,7 @@
 		return IRQ_HANDLED;
 	}
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 
 	hi = inb(dev->iobase + DT2814_DATA);
 	lo = inb(dev->iobase + DT2814_DATA);
@@ -346,7 +328,7 @@
 	if (ret < 0)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 45b20be..b9692ef 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -185,7 +185,7 @@
 	if (alloc_private(dev, sizeof(struct dt2815_private)) < 0)
 		return -ENOMEM;
 
-	s = dev->subdevices;
+	s = &dev->subdevices[0];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index beba044..502e42e 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -141,7 +141,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 
 	s->n_chan = 32;
 	s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 1f0b40e..78d3407 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -312,7 +312,7 @@
 	void *ptr;
 	int size;
 	int i;
-	struct comedi_subdevice *s = dev->subdevices + 1;
+	struct comedi_subdevice *s = &dev->subdevices[1];
 
 	outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
 
@@ -345,7 +345,7 @@
 	int size;
 	int i;
 	int ret;
-	struct comedi_subdevice *s = dev->subdevices;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 
 	outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
 
@@ -457,8 +457,8 @@
 		return IRQ_HANDLED;
 	}
 
-	s = dev->subdevices + 0;
-	s_ao = dev->subdevices + 1;
+	s = &dev->subdevices[0];
+	s_ao = &dev->subdevices[1];
 	adcsr = inw(dev->iobase + DT2821_ADCSR);
 	dacsr = inw(dev->iobase + DT2821_DACSR);
 	supcsr = inw(dev->iobase + DT2821_SUPCSR);
@@ -582,47 +582,24 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique
-	 * and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -862,44 +839,22 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique
-	 * and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1275,7 +1230,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 
 	dev->read_subdev = s;
 	/* ai subdevice */
@@ -1294,7 +1249,7 @@
 	    opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
 	devpriv->ad_2scomp = it->options[opt_ai_twos];
 
-	s++;
+	s = &dev->subdevices[1];
 
 	s->n_chan = boardtype.dachan;
 	if (s->n_chan) {
@@ -1320,7 +1275,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s++;
+	s = &dev->subdevices[2];
 	/* dio subsystem */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 3476cda..43d05ef 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -63,6 +63,8 @@
 #include "../comedidev.h"
 #include <linux/delay.h>
 
+#include "comedi_fc.h"
+
 #define PCI_VENDOR_ID_DT	0x1116
 
 static const struct comedi_lrange range_dt3000_ai = { 4, {
@@ -330,7 +332,7 @@
 	if (!dev->attached)
 		return IRQ_NONE;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	status = readw(devpriv->io_addr + DPR_Intr_Flag);
 #ifdef DEBUG
 	debug_intr_flags(status);
@@ -408,37 +410,19 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -842,7 +826,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 
 	/* ai subdevice */
@@ -857,7 +841,7 @@
 	s->do_cmdtest = dt3k_ai_cmdtest;
 	s->cancel = dt3k_ai_cancel;
 
-	s++;
+	s = &dev->subdevices[1];
 	/* ao subsystem */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -868,7 +852,7 @@
 	s->len_chanlist = 1;
 	s->range_table = &range_bipolar10;
 
-	s++;
+	s = &dev->subdevices[2];
 	/* dio subsystem */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -879,7 +863,7 @@
 	s->len_chanlist = 8;
 	s->range_table = &range_digital;
 
-	s++;
+	s = &dev->subdevices[3];
 	/* mem subsystem */
 	s->type = COMEDI_SUBD_MEMORY;
 	s->subdev_flags = SDF_READABLE;
@@ -890,7 +874,7 @@
 	s->range_table = &range_unknown;
 
 #if 0
-	s++;
+	s = &dev->subdevices[4];
 	/* proc subsystem */
 	s->type = COMEDI_SUBD_PROC;
 #endif
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 40821c7..bc6f409 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -1041,7 +1041,7 @@
 		return ret;
 
 	/* digital input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 0;
@@ -1050,7 +1050,7 @@
 	s->insn_read = &dt9812_di_rinsn;
 
 	/* digital output subdevice */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITEABLE;
 	s->n_chan = 0;
@@ -1059,7 +1059,7 @@
 	s->insn_write = &dt9812_do_winsn;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = 0;
@@ -1068,7 +1068,7 @@
 	s->insn_read = &dt9812_ai_rinsn;
 
 	/* analog output subdevice */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITEABLE;
 	s->n_chan = 0;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index 064be9a..6f612be 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -41,7 +41,6 @@
 #include <linux/mutex.h>
 
 #define PCI_VENDOR_ID_DYNALOG		0x10b5
-#define DRV_NAME			"dyna_pci10xx"
 
 #define READ_TIMEOUT 50
 
@@ -54,59 +53,11 @@
 
 static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 };
 
-static const struct comedi_lrange range_pci1050_ao = { 1, {
-							  UNI_RANGE(10)
-							  }
-};
-
-static const char range_codes_pci1050_ao[] = { 0x00 };
-
-struct boardtype {
-	const char *name;
-	int device_id;
-	int ai_chans;
-	int ai_bits;
-	int ao_chans;
-	int ao_bits;
-	int di_chans;
-	int di_bits;
-	int do_chans;
-	int do_bits;
-	const struct comedi_lrange *range_ai;
-	const char *range_codes_ai;
-	const struct comedi_lrange *range_ao;
-	const char *range_codes_ao;
-};
-
-static const struct boardtype boardtypes[] = {
-	{
-	.name = "dyna_pci1050",
-	.device_id = 0x1050,
-	.ai_chans = 16,
-	.ai_bits = 12,
-	.ao_chans = 16,
-	.ao_bits = 12,
-	.di_chans = 16,
-	.di_bits = 16,
-	.do_chans = 16,
-	.do_bits = 16,
-	.range_ai = &range_pci1050_ai,
-	.range_codes_ai = range_codes_pci1050_ai,
-	.range_ao = &range_pci1050_ao,
-	.range_codes_ao = range_codes_pci1050_ao,
-	},
-	/*  dummy entry corresponding to driver name */
-	{.name = DRV_NAME},
-};
-
 struct dyna_pci10xx_private {
 	struct mutex mutex;
 	unsigned long BADR3;
 };
 
-#define thisboard ((const struct boardtype *)dev->board_ptr)
-#define devpriv ((struct dyna_pci10xx_private *)dev->private)
-
 /******************************************************************************/
 /************************** READ WRITE FUNCTIONS ******************************/
 /******************************************************************************/
@@ -116,13 +67,14 @@
 			struct comedi_subdevice *s,
 			struct comedi_insn *insn, unsigned int *data)
 {
+	struct dyna_pci10xx_private *devpriv = dev->private;
 	int n, counter;
 	u16 d = 0;
 	unsigned int chan, range;
 
 	/* get the channel number and range */
 	chan = CR_CHAN(insn->chanspec);
-	range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
+	range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))];
 
 	mutex_lock(&devpriv->mutex);
 	/* convert n samples */
@@ -159,11 +111,12 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
+	struct dyna_pci10xx_private *devpriv = dev->private;
 	int n;
 	unsigned int chan, range;
 
 	chan = CR_CHAN(insn->chanspec);
-	range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
+	range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))];
 
 	mutex_lock(&devpriv->mutex);
 	for (n = 0; n < insn->n; n++) {
@@ -181,6 +134,7 @@
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
+	struct dyna_pci10xx_private *devpriv = dev->private;
 	u16 d = 0;
 
 	mutex_lock(&devpriv->mutex);
@@ -200,6 +154,8 @@
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
+	struct dyna_pci10xx_private *devpriv = dev->private;
+
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit.
 	 * s->state contains the previous write data
@@ -223,143 +179,98 @@
 	return insn->n;
 }
 
-static struct pci_dev *dyna_pci10xx_find_pci_dev(struct comedi_device *dev,
-						 struct comedi_devconfig *it)
+static int dyna_pci10xx_attach_pci(struct comedi_device *dev,
+				   struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
-
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (bus != pcidev->bus->number ||
-			    slot != PCI_SLOT(pcidev->devfn))
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_DYNALOG)
-			continue;
-
-		for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
-			if (pcidev->device != boardtypes[i].device_id)
-				continue;
-
-			dev->board_ptr = &boardtypes[i];
-			return pcidev;
-		}
-	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
-	return NULL;
-}
-
-static int dyna_pci10xx_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct pci_dev *pcidev;
+	struct dyna_pci10xx_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret;
 
-	if (alloc_private(dev, sizeof(struct dyna_pci10xx_private)) < 0) {
-		printk(KERN_ERR "comedi: dyna_pci10xx: "
-			"failed to allocate memory!\n");
-		return -ENOMEM;
-	}
-
-	pcidev = dyna_pci10xx_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
 
-	dev->board_name = thisboard->name;
-	dev->irq = 0;
+	dev->board_name = dev->driver->driver_name;
 
-	if (comedi_pci_enable(pcidev, DRV_NAME)) {
-		printk(KERN_ERR "comedi: dyna_pci10xx: "
-			"failed to enable PCI device and request regions!");
-		return -EIO;
-	}
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
 
-	mutex_init(&devpriv->mutex);
-
-	printk(KERN_INFO "comedi: dyna_pci10xx: device found!\n");
-
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
 	dev->iobase = pci_resource_start(pcidev, 2);
 	devpriv->BADR3 = pci_resource_start(pcidev, 3);
 
+	mutex_init(&devpriv->mutex);
+
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
 	/* analog input */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-	s->n_chan = thisboard->ai_chans;
+	s->n_chan = 16;
 	s->maxdata = 0x0FFF;
-	s->range_table = thisboard->range_ai;
+	s->range_table = &range_pci1050_ai;
 	s->len_chanlist = 16;
 	s->insn_read = dyna_pci10xx_insn_read_ai;
 
 	/* analog output */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->ao_chans;
+	s->n_chan = 16;
 	s->maxdata = 0x0FFF;
-	s->range_table = thisboard->range_ao;
+	s->range_table = &range_unipolar10;
 	s->len_chanlist = 16;
 	s->insn_write = dyna_pci10xx_insn_write_ao;
 
 	/* digital input */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
-	s->n_chan = thisboard->di_chans;
+	s->n_chan = 16;
 	s->maxdata = 1;
 	s->range_table = &range_digital;
-	s->len_chanlist = thisboard->di_chans;
+	s->len_chanlist = 16;
 	s->insn_bits = dyna_pci10xx_di_insn_bits;
 
 	/* digital output */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-	s->n_chan = thisboard->do_chans;
+	s->n_chan = 16;
 	s->maxdata = 1;
 	s->range_table = &range_digital;
-	s->len_chanlist = thisboard->do_chans;
+	s->len_chanlist = 16;
 	s->state = 0;
 	s->insn_bits = dyna_pci10xx_do_insn_bits;
 
-	printk(KERN_INFO "comedi: dyna_pci10xx: %s - device setup completed!\n",
-		thisboard->name);
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
-	return 1;
+	return 0;
 }
 
 static void dyna_pci10xx_detach(struct comedi_device *dev)
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	struct dyna_pci10xx_private *devpriv = dev->private;
 
 	if (devpriv)
 		mutex_destroy(&devpriv->mutex);
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver dyna_pci10xx_driver = {
 	.driver_name	= "dyna_pci10xx",
 	.module		= THIS_MODULE,
-	.attach		= dyna_pci10xx_attach,
+	.attach_pci	= dyna_pci10xx_attach_pci,
 	.detach		= dyna_pci10xx_detach,
-	.board_name	= &boardtypes[0].name,
-	.offset		= sizeof(struct boardtype),
-	.num_names	= ARRAY_SIZE(boardtypes),
 };
 
 static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index d1da809..ae8e8f4 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -140,7 +140,7 @@
 	 * this if the definitions of the supdevices, 2 have been defined
 	 */
 	/* Analog indput */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* define subdevice as Analog In */
 	s->type = COMEDI_SUBD_AI;
 	/* you can read it from userspace */
@@ -156,7 +156,7 @@
 	printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n");
 
 	/* Analog output */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* define subdevice as Analog OUT */
 	s->type = COMEDI_SUBD_AO;
 	/* you can write it from userspace */
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 79f5808..abff660 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -436,7 +436,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog input subdevice */
 	dev->read_subdev = s;
 /*	dev->write_subdev = s; */
@@ -723,45 +723,24 @@
 		       struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 	int i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-	 * compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/*  uniqueness check */
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index b10ebdb..d696d4d 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -44,10 +44,7 @@
 
 4 x 16-bit counters
 
-Options:
- [0] - PCI bus number - if bus number and slot number are 0,
-			then driver search for first unused card
- [1] - PCI slot number
+Configuration options: not applicable, uses PCI auto config
 */
 
 #include <linux/interrupt.h>
@@ -56,16 +53,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 
-#include "icp_multi.h"
-
-#define DEVICE_ID	0x8000	/* Device ID */
-
-#define ICP_MULTI_EXTDEBUG
-
-/*  Hardware types of the cards */
-#define TYPE_ICP_MULTI	0
-
-#define IORANGE_ICP_MULTI 	32
+#define PCI_DEVICE_ID_ICP_MULTI	0x8000
 
 #define ICP_MULTI_ADC_CSR	0	/* R/W: ADC command/status register */
 #define ICP_MULTI_AI		2	/* R:   Analogue input data */
@@ -124,32 +112,10 @@
 	Data & Structure declarations
 ==============================================================================
 */
-static unsigned short pci_list_builded;	/*>0 list of card is known */
-
-struct boardtype {
-	const char *name;	/*  driver name */
-	int device_id;
-	int iorange;		/*  I/O range len */
-	char have_irq;		/*  1=card support IRQ */
-	char cardtype;		/*  0=ICP Multi */
-	int n_aichan;		/*  num of A/D chans */
-	int n_aichand;		/*  num of A/D chans in diff mode */
-	int n_aochan;		/*  num of D/A chans */
-	int n_dichan;		/*  num of DI chans */
-	int n_dochan;		/*  num of DO chans */
-	int n_ctrs;		/*  num of counters */
-	int ai_maxdata;		/*  resolution of A/D */
-	int ao_maxdata;		/*  resolution of D/A */
-	const struct comedi_lrange *rangelist_ai;	/*  rangelist for A/D */
-	const char *rangecode;	/*  range codes for programming */
-	const struct comedi_lrange *rangelist_ao;	/*  rangelist for D/A */
-};
 
 struct icp_multi_private {
-	struct pcilst_struct *card;	/*  pointer to card */
 	char valid;		/*  card is usable */
 	void __iomem *io_addr;		/*  Pointer to mapped io address */
-	resource_size_t phys_iobase;	/*  Physical io address */
 	unsigned int AdcCmdStatus;	/*  ADC Command/Status register */
 	unsigned int DacCmdStatus;	/*  DAC Command/Status register */
 	unsigned int IntEnable;	/*  Interrupt Enable register */
@@ -164,40 +130,14 @@
 	unsigned int do_data;	/*  Remember digital output data */
 };
 
-#define devpriv ((struct icp_multi_private *)dev->private)
-#define this_board ((const struct boardtype *)dev->board_ptr)
-
-/*
-==============================================================================
-
-Name:	setup_channel_list
-
-Description:
-	This function sets the appropriate channel selection,
-	differential input mode and range bits in the ADC Command/
-	Status register.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current service structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	unsigned int *chanlist	Pointer to packed channel list
-	unsigned int n_chan	Number of channels to scan
-
-Returns:Void
-
-==============================================================================
-*/
 static void setup_channel_list(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       unsigned int *chanlist, unsigned int n_chan)
 {
+	struct icp_multi_private *devpriv = dev->private;
 	unsigned int i, range, chanprog;
 	unsigned int diff;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG:  setup_channel_list(...,%d)\n", n_chan);
-#endif
 	devpriv->act_chanlist_len = n_chan;
 	devpriv->act_chanlist_pos = 0;
 
@@ -228,50 +168,23 @@
 			devpriv->AdcCmdStatus |= (chanprog << 8);
 
 		/*  Get range for current channel */
-		range = this_board->rangecode[CR_RANGE(chanlist[i])];
+		range = range_codes_analog[CR_RANGE(chanlist[i])];
 		/*  Set range. bits 4-5 */
 		devpriv->AdcCmdStatus |= range;
 
 		/* Output channel, range, mode to ICP Multi */
 		writew(devpriv->AdcCmdStatus,
 		       devpriv->io_addr + ICP_MULTI_ADC_CSR);
-
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG
-		       "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
-		       devpriv->act_chanlist[i]);
-#endif
 	}
-
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_read_ai
-
-Description:
-	This function reads a single analogue input.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to analogue input data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_read_ai(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct icp_multi_private *devpriv = dev->private;
 	int n, timeout;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n");
-#endif
 	/*  Disable A/D conversion ready interrupt */
 	devpriv->IntEnable &= ~ADC_READY;
 	writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
@@ -283,12 +196,6 @@
 	/*  Set up appropriate channel, mode and range data, for specified ch */
 	setup_channel_list(dev, s, &insn->chanspec, 1);
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG "icp_multi A ST=%4x IO=%p\n",
-	       readw(devpriv->io_addr + ICP_MULTI_ADC_CSR),
-	       devpriv->io_addr + ICP_MULTI_ADC_CSR);
-#endif
-
 	for (n = 0; n < insn->n; n++) {
 		/*  Set start ADC bit */
 		devpriv->AdcCmdStatus |= ADC_ST;
@@ -296,18 +203,8 @@
 		       devpriv->io_addr + ICP_MULTI_ADC_CSR);
 		devpriv->AdcCmdStatus &= ~ADC_ST;
 
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG "icp multi B n=%d ST=%4x\n", n,
-		       readw(devpriv->io_addr + ICP_MULTI_ADC_CSR));
-#endif
-
 		udelay(1);
 
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG "icp multi C n=%d ST=%4x\n", n,
-		       readw(devpriv->io_addr + ICP_MULTI_ADC_CSR));
-#endif
-
 		/*  Wait for conversion to complete, or get fed up waiting */
 		timeout = 100;
 		while (timeout--) {
@@ -315,15 +212,6 @@
 				    ICP_MULTI_ADC_CSR) & ADC_BSY))
 				goto conv_finish;
 
-#ifdef ICP_MULTI_EXTDEBUG
-			if (!(timeout % 10))
-				printk(KERN_DEBUG
-				       "icp multi D n=%d tm=%d ST=%4x\n", n,
-				       timeout,
-				       readw(devpriv->io_addr +
-					     ICP_MULTI_ADC_CSR));
-#endif
-
 			udelay(1);
 		}
 
@@ -342,11 +230,6 @@
 		/*  Clear data received */
 		data[n] = 0;
 
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG
-		      "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n",
-		      n);
-#endif
 		return -ETIME;
 
 conv_finish:
@@ -362,41 +245,16 @@
 	devpriv->IntStatus |= ADC_READY;
 	writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", n);
-#endif
 	return n;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_write_ao
-
-Description:
-	This function writes a single analogue output.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to analogue output data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_write_ao(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
 {
+	struct icp_multi_private *devpriv = dev->private;
 	int n, chan, range, timeout;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n");
-#endif
 	/*  Disable D/A conversion ready interrupt */
 	devpriv->IntEnable &= ~DAC_READY;
 	writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
@@ -415,7 +273,7 @@
 	/*  Bit 5 = 1 : 10V */
 	/*  Bits 8-9 : Channel number */
 	devpriv->DacCmdStatus &= 0xfccf;
-	devpriv->DacCmdStatus |= this_board->rangecode[range];
+	devpriv->DacCmdStatus |= range_codes_analog[range];
 	devpriv->DacCmdStatus |= (chan << 8);
 
 	writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR);
@@ -429,15 +287,6 @@
 				    ICP_MULTI_DAC_CSR) & DAC_BSY))
 				goto dac_ready;
 
-#ifdef ICP_MULTI_EXTDEBUG
-			if (!(timeout % 10))
-				printk(KERN_DEBUG
-				       "icp multi A n=%d tm=%d ST=%4x\n", n,
-				       timeout,
-				       readw(devpriv->io_addr +
-					     ICP_MULTI_DAC_CSR));
-#endif
-
 			udelay(1);
 		}
 
@@ -456,11 +305,6 @@
 		/*  Clear data received */
 		devpriv->ao_data[chan] = 0;
 
-#ifdef ICP_MULTI_EXTDEBUG
-		printk(KERN_DEBUG
-		     "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n",
-		     n);
-#endif
 		return -ETIME;
 
 dac_ready:
@@ -477,35 +321,14 @@
 		devpriv->ao_data[chan] = data[n];
 	}
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", n);
-#endif
 	return n;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_read_ao
-
-Description:
-	This function reads a single analogue output.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to analogue output data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_read_ao(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct icp_multi_private *devpriv = dev->private;
 	int n, chan;
 
 	/*  Get channel number */
@@ -518,58 +341,22 @@
 	return n;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_bits_di
-
-Description:
-	This function reads the digital inputs.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to analogue output data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_bits_di(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	struct icp_multi_private *devpriv = dev->private;
+
 	data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
 
 	return insn->n;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_bits_do
-
-Description:
-	This function writes the appropriate digital outputs.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to analogue output data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_bits_do(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n");
-#endif
+	struct icp_multi_private *devpriv = dev->private;
 
 	if (data[0]) {
 		s->state &= ~data[0];
@@ -582,30 +369,9 @@
 
 	data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_insn_bits_do(...)\n");
-#endif
 	return insn->n;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_read_ctr
-
-Description:
-	This function reads the specified counter.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to counter data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_read_ctr(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
@@ -613,24 +379,6 @@
 	return 0;
 }
 
-/*
-==============================================================================
-
-Name:	icp_multi_insn_write_ctr
-
-Description:
-	This function write to the specified counter.
-
-Parameters:
-	struct comedi_device *dev	Pointer to current device structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	struct comedi_insn *insn	Pointer to current comedi instruction
-	unsigned int *data		Pointer to counter data
-
-Returns:int			Nmuber of instructions executed
-
-==============================================================================
-*/
 static int icp_multi_insn_write_ctr(struct comedi_device *dev,
 				    struct comedi_subdevice *s,
 				    struct comedi_insn *insn,
@@ -639,44 +387,18 @@
 	return 0;
 }
 
-/*
-==============================================================================
-
-Name:	interrupt_service_icp_multi
-
-Description:
-	This function is the interrupt service routine for all
-	interrupts generated by the icp multi board.
-
-Parameters:
-	int irq
-	void *d			Pointer to current device
-
-==============================================================================
-*/
 static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
 {
 	struct comedi_device *dev = d;
+	struct icp_multi_private *devpriv = dev->private;
 	int int_no;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n",
-	       irq);
-#endif
-
 	/*  Is this interrupt from our board? */
 	int_no = readw(devpriv->io_addr + ICP_MULTI_INT_STAT) & Status_IRQ;
 	if (!int_no)
 		/*  No, exit */
 		return IRQ_NONE;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n",
-	       readw(devpriv->io_addr + ICP_MULTI_INT_STAT));
-#endif
-
 	/*  Determine which interrupt is active & handle it */
 	switch (int_no) {
 	case ADC_READY:
@@ -700,44 +422,16 @@
 
 	}
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: END: interrupt_service_icp_multi(...)\n");
-#endif
 	return IRQ_HANDLED;
 }
 
 #if 0
-/*
-==============================================================================
-
-Name:	check_channel_list
-
-Description:
-	This function checks if the channel list, provided by user
-	is built correctly
-
-Parameters:
-	struct comedi_device *dev	Pointer to current service structure
-	struct comedi_subdevice *s	Pointer to current subdevice structure
-	unsigned int *chanlist	Pointer to packed channel list
-	unsigned int n_chan	Number of channels to scan
-
-Returns:int 0 = failure
-	    1 = success
-
-==============================================================================
-*/
 static int check_channel_list(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      unsigned int *chanlist, unsigned int n_chan)
 {
 	unsigned int i;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG:  check_channel_list(...,%d)\n", n_chan);
-#endif
 	/*  Check that we at least have one channel to check */
 	if (n_chan < 1) {
 		comedi_error(dev, "range/channel list is empty!");
@@ -747,13 +441,13 @@
 	for (i = 0; i < n_chan; i++) {
 		/*  Check that channel number is < maximum */
 		if (CR_AREF(chanlist[i]) == AREF_DIFF) {
-			if (CR_CHAN(chanlist[i]) > this_board->n_aichand) {
+			if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) {
 				comedi_error(dev,
 					     "Incorrect differential ai ch-nr");
 				return 0;
 			}
 		} else {
-			if (CR_CHAN(chanlist[i]) > this_board->n_aichan) {
+			if (CR_CHAN(chanlist[i]) > s->n_chan) {
 				comedi_error(dev,
 					     "Incorrect ai channel number");
 				return 0;
@@ -764,295 +458,189 @@
 }
 #endif
 
-/*
-==============================================================================
-
-Name:	icp_multi_reset
-
-Description:
-	This function resets the icp multi device to a 'safe' state
-
-Parameters:
-	struct comedi_device *dev	Pointer to current service structure
-
-Returns:int	0 = success
-
-==============================================================================
-*/
 static int icp_multi_reset(struct comedi_device *dev)
 {
+	struct icp_multi_private *devpriv = dev->private;
 	unsigned int i;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp_multi EDBG: BGN: icp_multi_reset(...)\n");
-#endif
 	/*  Clear INT enables and requests */
 	writew(0, devpriv->io_addr + ICP_MULTI_INT_EN);
 	writew(0x00ff, devpriv->io_addr + ICP_MULTI_INT_STAT);
 
-	if (this_board->n_aochan)
-		/*  Set DACs to 0..5V range and 0V output */
-		for (i = 0; i < this_board->n_aochan; i++) {
-			devpriv->DacCmdStatus &= 0xfcce;
+	/* Set DACs to 0..5V range and 0V output */
+	for (i = 0; i < 4; i++) {
+		devpriv->DacCmdStatus &= 0xfcce;
 
-			/*  Set channel number */
-			devpriv->DacCmdStatus |= (i << 8);
+		/*  Set channel number */
+		devpriv->DacCmdStatus |= (i << 8);
 
-			/*  Output 0V */
-			writew(0, devpriv->io_addr + ICP_MULTI_AO);
+		/*  Output 0V */
+		writew(0, devpriv->io_addr + ICP_MULTI_AO);
 
-			/*  Set start conversion bit */
-			devpriv->DacCmdStatus |= DAC_ST;
+		/*  Set start conversion bit */
+		devpriv->DacCmdStatus |= DAC_ST;
 
-			/*  Output to command / status register */
-			writew(devpriv->DacCmdStatus,
-			       devpriv->io_addr + ICP_MULTI_DAC_CSR);
+		/*  Output to command / status register */
+		writew(devpriv->DacCmdStatus,
+			devpriv->io_addr + ICP_MULTI_DAC_CSR);
 
-			/*  Delay to allow DAC time to recover */
-			udelay(1);
-		}
-	/*  Digital outputs to 0 */
+		/*  Delay to allow DAC time to recover */
+		udelay(1);
+	}
+
+	/* Digital outputs to 0 */
 	writew(0, devpriv->io_addr + ICP_MULTI_DO);
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "icp multi EDBG: END: icp_multi_reset(...)\n");
-#endif
 	return 0;
 }
 
-static int icp_multi_attach(struct comedi_device *dev,
-			    struct comedi_devconfig *it)
+static int icp_multi_attach_pci(struct comedi_device *dev,
+				struct pci_dev *pcidev)
 {
+	struct icp_multi_private *devpriv;
 	struct comedi_subdevice *s;
-	int ret, subdev, n_subdevices;
-	unsigned int irq;
-	struct pcilst_struct *card = NULL;
-	resource_size_t io_addr[5], iobase;
-	unsigned char pci_bus, pci_slot, pci_func;
+	resource_size_t iobase;
+	int ret;
 
-	printk(KERN_WARNING
-	       "icp_multi EDBG: BGN: icp_multi_attach(...)\n");
+	comedi_set_hw_dev(dev, &pcidev->dev);
+	dev->board_name = dev->driver->driver_name;
 
-	/*  Allocate private data storage space */
-	ret = alloc_private(dev, sizeof(struct icp_multi_private));
+	ret = alloc_private(dev, sizeof(*devpriv));
 	if (ret < 0)
 		return ret;
+	devpriv = dev->private;
 
-	/*  Initialise list of PCI cards in system, if not already done so */
-	if (pci_list_builded++ == 0) {
-		pci_card_list_init(PCI_VENDOR_ID_ICP,
-#ifdef ICP_MULTI_EXTDEBUG
-				   1
-#else
-				   0
-#endif
-		    );
-	}
-
-	printk(KERN_WARNING
-	       "Anne's comedi%d: icp_multi: board=%s", dev->minor,
-	       this_board->name);
-
-	card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP,
-					 this_board->device_id, it->options[0],
-					 it->options[1]);
-
-	if (card == NULL)
-		return -EIO;
-
-	devpriv->card = card;
-
-	if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0],
-			   &irq)) < 0) {
-		printk(KERN_WARNING " - Can't get configuration data!\n");
-		return -EIO;
-	}
-
-	iobase = io_addr[2];
-	devpriv->phys_iobase = iobase;
-
-	printk(KERN_WARNING
-	       ", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func,
-	       (unsigned long long)iobase);
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	iobase = pci_resource_start(pcidev, 2);
+	dev->iobase = iobase;
 
 	devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE);
-
-	if (devpriv->io_addr == NULL) {
-		printk(KERN_WARNING "ioremap failed.\n");
+	if (!devpriv->io_addr)
 		return -ENOMEM;
-	}
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG
-	       "0x%08llx mapped to %p, ", (unsigned long long)iobase,
-	       devpriv->io_addr);
-#endif
 
-	dev->board_name = this_board->name;
-
-	n_subdevices = 0;
-	if (this_board->n_aichan)
-		n_subdevices++;
-	if (this_board->n_aochan)
-		n_subdevices++;
-	if (this_board->n_dichan)
-		n_subdevices++;
-	if (this_board->n_dochan)
-		n_subdevices++;
-	if (this_board->n_ctrs)
-		n_subdevices++;
-
-	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	ret = comedi_alloc_subdevices(dev, 5);
 	if (ret)
 		return ret;
 
 	icp_multi_reset(dev);
 
-	if (this_board->have_irq) {
-		if (irq) {
-			if (request_irq(irq, interrupt_service_icp_multi,
-					IRQF_SHARED, "Inova Icp Multi", dev)) {
-				printk(KERN_WARNING
-				    "unable to allocate IRQ %u, DISABLING IT",
-				     irq);
-				irq = 0;	/* Can't use IRQ */
-			} else
-				printk(KERN_WARNING ", irq=%u", irq);
-		} else
-			printk(KERN_WARNING ", IRQ disabled");
-	} else
-		irq = 0;
-
-	dev->irq = irq;
-
-	printk(KERN_WARNING ".\n");
-
-	subdev = 0;
-
-	if (this_board->n_aichan) {
-		s = dev->subdevices + subdev;
-		dev->read_subdev = s;
-		s->type = COMEDI_SUBD_AI;
-		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
-		if (this_board->n_aichand)
-			s->subdev_flags |= SDF_DIFF;
-		s->n_chan = this_board->n_aichan;
-		s->maxdata = this_board->ai_maxdata;
-		s->len_chanlist = this_board->n_aichan;
-		s->range_table = this_board->rangelist_ai;
-		s->insn_read = icp_multi_insn_read_ai;
-		subdev++;
+	if (pcidev->irq) {
+		ret = request_irq(pcidev->irq, interrupt_service_icp_multi,
+				  IRQF_SHARED, dev->board_name, dev);
+		if (ret == 0)
+			dev->irq = pcidev->irq;
 	}
 
-	if (this_board->n_aochan) {
-		s = dev->subdevices + subdev;
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-		s->n_chan = this_board->n_aochan;
-		s->maxdata = this_board->ao_maxdata;
-		s->len_chanlist = this_board->n_aochan;
-		s->range_table = this_board->rangelist_ao;
-		s->insn_write = icp_multi_insn_write_ao;
-		s->insn_read = icp_multi_insn_read_ao;
-		subdev++;
-	}
+	s = &dev->subdevices[0];
+	dev->read_subdev = s;
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+	s->n_chan = 16;
+	s->maxdata = 0x0fff;
+	s->len_chanlist = 16;
+	s->range_table = &range_analog;
+	s->insn_read = icp_multi_insn_read_ai;
 
-	if (this_board->n_dichan) {
-		s = dev->subdevices + subdev;
-		s->type = COMEDI_SUBD_DI;
-		s->subdev_flags = SDF_READABLE;
-		s->n_chan = this_board->n_dichan;
-		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dichan;
-		s->range_table = &range_digital;
-		s->io_bits = 0;
-		s->insn_bits = icp_multi_insn_bits_di;
-		subdev++;
-	}
+	s = &dev->subdevices[1];
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 4;
+	s->maxdata = 0x0fff;
+	s->len_chanlist = 4;
+	s->range_table = &range_analog;
+	s->insn_write = icp_multi_insn_write_ao;
+	s->insn_read = icp_multi_insn_read_ao;
 
-	if (this_board->n_dochan) {
-		s = dev->subdevices + subdev;
-		s->type = COMEDI_SUBD_DO;
-		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-		s->n_chan = this_board->n_dochan;
-		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dochan;
-		s->range_table = &range_digital;
-		s->io_bits = (1 << this_board->n_dochan) - 1;
-		s->state = 0;
-		s->insn_bits = icp_multi_insn_bits_do;
-		subdev++;
-	}
+	s = &dev->subdevices[2];
+	s->type = COMEDI_SUBD_DI;
+	s->subdev_flags = SDF_READABLE;
+	s->n_chan = 16;
+	s->maxdata = 1;
+	s->len_chanlist = 16;
+	s->range_table = &range_digital;
+	s->io_bits = 0;
+	s->insn_bits = icp_multi_insn_bits_di;
 
-	if (this_board->n_ctrs) {
-		s = dev->subdevices + subdev;
-		s->type = COMEDI_SUBD_COUNTER;
-		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-		s->n_chan = this_board->n_ctrs;
-		s->maxdata = 0xffff;
-		s->len_chanlist = this_board->n_ctrs;
-		s->state = 0;
-		s->insn_read = icp_multi_insn_read_ctr;
-		s->insn_write = icp_multi_insn_write_ctr;
-		subdev++;
-	}
+	s = &dev->subdevices[3];
+	s->type = COMEDI_SUBD_DO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->len_chanlist = 8;
+	s->range_table = &range_digital;
+	s->io_bits = 0xff;
+	s->state = 0;
+	s->insn_bits = icp_multi_insn_bits_do;
+
+	s = &dev->subdevices[4];
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->len_chanlist = 4;
+	s->state = 0;
+	s->insn_read = icp_multi_insn_read_ctr;
+	s->insn_write = icp_multi_insn_write_ctr;
 
 	devpriv->valid = 1;
 
-#ifdef ICP_MULTI_EXTDEBUG
-	printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_attach(...)\n");
-#endif
+	dev_info(dev->class_dev, "%s attached, irq %sabled\n",
+		dev->board_name, dev->irq ? "en" : "dis");
 
 	return 0;
 }
 
 static void icp_multi_detach(struct comedi_device *dev)
 {
-	if (dev->private)
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	struct icp_multi_private *devpriv = dev->private;
+
+	if (devpriv)
 		if (devpriv->valid)
 			icp_multi_reset(dev);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-	if (dev->private && devpriv->io_addr)
+	if (devpriv && devpriv->io_addr)
 		iounmap(devpriv->io_addr);
-	if (dev->private && devpriv->card)
-		pci_card_free(devpriv->card);
-	if (--pci_list_builded == 0)
-		pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
+	}
 }
 
-static const struct boardtype boardtypes[] = {
-	{
-		.name		= "icp_multi",
-		.device_id	= DEVICE_ID,
-		.iorange	= IORANGE_ICP_MULTI,
-		.have_irq	= 1,
-		.cardtype	= TYPE_ICP_MULTI,
-		.n_aichan	= 16,
-		.n_aichand	= 8,
-		.n_aochan	= 4,
-		.n_dichan	= 16,
-		.n_dochan	= 8,
-		.n_ctrs		= 4,
-		.ai_maxdata	= 0x0fff,
-		.ao_maxdata	= 0x0fff,
-		.rangelist_ai	= &range_analog,
-		.rangecode	= range_codes_analog,
-		.rangelist_ao	= &range_analog,
-	},
-};
-
 static struct comedi_driver icp_multi_driver = {
 	.driver_name	= "icp_multi",
 	.module		= THIS_MODULE,
-	.attach		= icp_multi_attach,
+	.attach_pci	= icp_multi_attach_pci,
 	.detach		= icp_multi_detach,
-	.num_names	= ARRAY_SIZE(boardtypes),
-	.board_name	= &boardtypes[0].name,
-	.offset		= sizeof(struct boardtype),
 };
-module_comedi_driver(icp_multi_driver);
+
+static int __devinit icp_multi_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &icp_multi_driver);
+}
+
+static void __devexit icp_multi_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, icp_multi_pci_table);
+
+static struct pci_driver icp_multi_pci_driver = {
+	.name		= "icp_multi",
+	.id_table	= icp_multi_pci_table,
+	.probe		= icp_multi_pci_probe,
+	.remove		= __devexit_p(icp_multi_pci_remove),
+};
+module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h
deleted file mode 100644
index dbf9908..0000000
--- a/drivers/staging/comedi/drivers/icp_multi.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
-    comedi/drivers/icp_multi.h
-
-    Stuff for ICP Multi
-
-    Author: Anne Smorthit <anne.smorthit@sfwte.ch>
-
-*/
-
-#ifndef _ICP_MULTI_H_
-#define _ICP_MULTI_H_
-
-#include "../comedidev.h"
-
-/****************************************************************************/
-
-struct pcilst_struct {
-	struct pcilst_struct *next;
-	int used;
-	struct pci_dev *pcidev;
-	unsigned short vendor;
-	unsigned short device;
-	unsigned char pci_bus;
-	unsigned char pci_slot;
-	unsigned char pci_func;
-	resource_size_t io_addr[5];
-	unsigned int irq;
-};
-
-struct pcilst_struct *inova_devices;
-/* ptr to root list of all Inova devices */
-
-/****************************************************************************/
-
-static void pci_card_list_init(unsigned short pci_vendor, char display);
-static void pci_card_list_cleanup(unsigned short pci_vendor);
-static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
-							  vendor_id,
-							  unsigned short
-							  device_id);
-static int find_free_pci_card_by_position(unsigned short vendor_id,
-					  unsigned short device_id,
-					  unsigned short pci_bus,
-					  unsigned short pci_slot,
-					  struct pcilst_struct **card);
-static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
-						       unsigned short device_id,
-						       unsigned short pci_bus,
-						       unsigned short pci_slot);
-
-static int pci_card_alloc(struct pcilst_struct *amcc);
-static int pci_card_free(struct pcilst_struct *amcc);
-static void pci_card_list_display(void);
-static int pci_card_data(struct pcilst_struct *amcc,
-			 unsigned char *pci_bus, unsigned char *pci_slot,
-			 unsigned char *pci_func, resource_size_t * io_addr,
-			 unsigned int *irq);
-
-/****************************************************************************/
-
-/* build list of Inova cards in this system */
-static void pci_card_list_init(unsigned short pci_vendor, char display)
-{
-	struct pci_dev *pcidev = NULL;
-	struct pcilst_struct *inova, *last;
-	int i;
-
-	inova_devices = NULL;
-	last = NULL;
-
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == pci_vendor) {
-			inova = kzalloc(sizeof(*inova), GFP_KERNEL);
-			if (!inova) {
-				printk
-				    ("icp_multi: pci_card_list_init: allocation failed\n");
-				pci_dev_put(pcidev);
-				break;
-			}
-
-			inova->pcidev = pci_dev_get(pcidev);
-			if (last) {
-				last->next = inova;
-			} else {
-				inova_devices = inova;
-			}
-			last = inova;
-
-			inova->vendor = pcidev->vendor;
-			inova->device = pcidev->device;
-			inova->pci_bus = pcidev->bus->number;
-			inova->pci_slot = PCI_SLOT(pcidev->devfn);
-			inova->pci_func = PCI_FUNC(pcidev->devfn);
-			/* Note: resources may be invalid if PCI device
-			 * not enabled, but they are corrected in
-			 * pci_card_alloc. */
-			for (i = 0; i < 5; i++)
-				inova->io_addr[i] =
-				    pci_resource_start(pcidev, i);
-			inova->irq = pcidev->irq;
-		}
-	}
-
-	if (display)
-		pci_card_list_display();
-}
-
-/****************************************************************************/
-/* free up list of amcc cards in this system */
-static void pci_card_list_cleanup(unsigned short pci_vendor)
-{
-	struct pcilst_struct *inova, *next;
-
-	for (inova = inova_devices; inova; inova = next) {
-		next = inova->next;
-		pci_dev_put(inova->pcidev);
-		kfree(inova);
-	}
-
-	inova_devices = NULL;
-}
-
-/****************************************************************************/
-/* find first unused card with this device_id */
-static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
-							  vendor_id,
-							  unsigned short
-							  device_id)
-{
-	struct pcilst_struct *inova, *next;
-
-	for (inova = inova_devices; inova; inova = next) {
-		next = inova->next;
-		if ((!inova->used) && (inova->device == device_id)
-		    && (inova->vendor == vendor_id))
-			return inova;
-
-	}
-
-	return NULL;
-}
-
-/****************************************************************************/
-/* find card on requested position */
-static int find_free_pci_card_by_position(unsigned short vendor_id,
-					  unsigned short device_id,
-					  unsigned short pci_bus,
-					  unsigned short pci_slot,
-					  struct pcilst_struct **card)
-{
-	struct pcilst_struct *inova, *next;
-
-	*card = NULL;
-	for (inova = inova_devices; inova; inova = next) {
-		next = inova->next;
-		if ((inova->vendor == vendor_id) && (inova->device == device_id)
-		    && (inova->pci_bus == pci_bus)
-		    && (inova->pci_slot == pci_slot)) {
-			if (!(inova->used)) {
-				*card = inova;
-				return 0;	/* ok, card is found */
-			} else {
-				return 2;	/* card exist but is used */
-			}
-		}
-	}
-
-	return 1;		/* no card found */
-}
-
-/****************************************************************************/
-/* mark card as used */
-static int pci_card_alloc(struct pcilst_struct *inova)
-{
-	int i;
-
-	if (!inova) {
-		printk(" - BUG!! inova is NULL!\n");
-		return -1;
-	}
-
-	if (inova->used)
-		return 1;
-	if (comedi_pci_enable(inova->pcidev, "icp_multi")) {
-		printk(" - Can't enable PCI device and request regions!\n");
-		return -1;
-	}
-	/* Resources will be accurate now. */
-	for (i = 0; i < 5; i++)
-		inova->io_addr[i] = pci_resource_start(inova->pcidev, i);
-	inova->irq = inova->pcidev->irq;
-	inova->used = 1;
-	return 0;
-}
-
-/****************************************************************************/
-/* mark card as free */
-static int pci_card_free(struct pcilst_struct *inova)
-{
-	if (!inova)
-		return -1;
-
-	if (!inova->used)
-		return 1;
-	inova->used = 0;
-	comedi_pci_disable(inova->pcidev);
-	return 0;
-}
-
-/****************************************************************************/
-/* display list of found cards */
-static void pci_card_list_display(void)
-{
-	struct pcilst_struct *inova, *next;
-
-	printk("Anne's List of pci cards\n");
-	printk("bus:slot:func vendor device io_inova io_daq irq used\n");
-
-	for (inova = inova_devices; inova; inova = next) {
-		next = inova->next;
-		printk
-		    ("%2d   %2d   %2d  0x%4x 0x%4x   0x%8llx 0x%8llx  %2u  %2d\n",
-		     inova->pci_bus, inova->pci_slot, inova->pci_func,
-		     inova->vendor, inova->device,
-		     (unsigned long long)inova->io_addr[0],
-		     (unsigned long long)inova->io_addr[2], inova->irq,
-		     inova->used);
-
-	}
-}
-
-/****************************************************************************/
-/* return all card information for driver */
-static int pci_card_data(struct pcilst_struct *inova,
-			 unsigned char *pci_bus, unsigned char *pci_slot,
-			 unsigned char *pci_func, resource_size_t * io_addr,
-			 unsigned int *irq)
-{
-	int i;
-
-	if (!inova)
-		return -1;
-	*pci_bus = inova->pci_bus;
-	*pci_slot = inova->pci_slot;
-	*pci_func = inova->pci_func;
-	for (i = 0; i < 5; i++)
-		io_addr[i] = inova->io_addr[i];
-	*irq = inova->irq;
-	return 0;
-}
-
-/****************************************************************************/
-/* select and alloc card */
-static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
-						       unsigned short device_id,
-						       unsigned short pci_bus,
-						       unsigned short pci_slot)
-{
-	struct pcilst_struct *card;
-	int err;
-
-	if ((pci_bus < 1) & (pci_slot < 1)) {	/* use autodetection */
-
-		card = find_free_pci_card_by_device(vendor_id, device_id);
-		if (card == NULL) {
-			printk(" - Unused card not found in system!\n");
-			return NULL;
-		}
-	} else {
-		switch (find_free_pci_card_by_position(vendor_id, device_id,
-						       pci_bus, pci_slot,
-						       &card)) {
-		case 1:
-			printk
-			    (" - Card not found on requested position b:s %d:%d!\n",
-			     pci_bus, pci_slot);
-			return NULL;
-		case 2:
-			printk
-			    (" - Card on requested position is used b:s %d:%d!\n",
-			     pci_bus, pci_slot);
-			return NULL;
-		}
-	}
-
-	err = pci_card_alloc(card);
-	if (err != 0) {
-		if (err > 0)
-			printk(" - Can't allocate card!\n");
-		/* else: error already printed. */
-		return NULL;
-	}
-
-	return card;
-}
-
-#endif
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 0f9cfe6..65ff1c9 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -224,7 +224,7 @@
 	       dev->minor, devpriv->ioaddr);
 
 	for (i = 0; i < PCI20000_MODULES; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET);
 		s->private = devpriv->subdev_private + i;
 		sdp = s->private;
@@ -259,7 +259,7 @@
 	}
 
 	/* initialize struct pci20xxx_private */
-	pci20xxx_dio_init(dev, dev->subdevices + PCI20000_MODULES);
+	pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]);
 
 	return 1;
 }
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 93f94cd..4a108ea 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -362,10 +362,11 @@
 	return 0;
 }
 
-int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val)
+static int read_idm_word(const u8 *data, size_t size, int *pos,
+			 unsigned int *val)
 {
 	int result = 0;
-	if (pos != 0 && val != 0) {
+	if (pos && val) {
 		/*  Skip over non hex */
 		for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) {
 		}
@@ -875,7 +876,7 @@
 			p->maxdata_list[56] = 0xffff;
 			p->maxdata_list[57] = 0xffff;
 			/*  Channel specific range and maxdata */
-			dev->subdevices[i].range_table = 0;
+			dev->subdevices[i].range_table = NULL;
 			dev->subdevices[i].range_table_list =
 			    p->range_table_list;
 			dev->subdevices[i].maxdata = 0;
@@ -884,7 +885,7 @@
 	}
 
 	/*  Reset DSP card */
-	devpriv->iobase->channel[0].reset = 0;
+	writel(0, &devpriv->iobase->channel[0].reset);
 
 	result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware);
 	dev_dbg(dev->class_dev, "Firmare load %d\n", result);
diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h
index a146961..9c42653 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.h
+++ b/drivers/staging/comedi/drivers/jr3_pci.h
@@ -97,7 +97,7 @@
 	mz = 0x0020,
 	changeV2 = 0x0040,
 	changeV1 = 0x0080
-} vect_bits_t;
+};
 
 /* WARNING_BITS */
 /* The warning_bits structure shows the bit pattern for the warning
@@ -116,7 +116,7 @@
 	mx_near_sat = 0x0008,
 	my_near_sat = 0x0010,
 	mz_near_sat = 0x0020
-} warning_bits_t;
+};
 
 /*  ERROR_BITS */
 /*  XX_SAT */
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index d4e9292..e867b72 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -28,11 +28,7 @@
 Updated: Mon, 14 Apr 2008 15:42:42 +0100
 Status: tested
 
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration Options: not applicable, uses PCI auto config
 
 This driver is a simple driver to read the counter values from
 Kolter Electronic PCI Counter Card.
@@ -111,82 +107,53 @@
 	return 1;
 }
 
-static struct pci_dev *cnt_find_pci_dev(struct comedi_device *dev,
-					struct comedi_devconfig *it)
+static const void *cnt_find_boardinfo(struct comedi_device *dev,
+				      struct pci_dev *pcidev)
 {
 	const struct cnt_board_struct *board;
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
 	int i;
 
-	/* Probe the device to determine what device in the series it is. */
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_KOLTER)
-			continue;
-
-		for (i = 0; i < ARRAY_SIZE(cnt_boards); i++) {
-			board = &cnt_boards[i];
-			if (board->device_id != pcidev->device)
-				continue;
-
-			dev->board_ptr = board;
-			return pcidev;
-		}
+	for (i = 0; i < ARRAY_SIZE(cnt_boards); i++) {
+		board = &cnt_boards[i];
+		if (board->device_id == pcidev->device)
+			return board;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int cnt_attach_pci(struct comedi_device *dev,
+			  struct pci_dev *pcidev)
 {
 	const struct cnt_board_struct *board;
-	struct pci_dev *pcidev;
-	struct comedi_subdevice *subdevice;
-	unsigned long io_base;
-	int error;
+	struct comedi_subdevice *s;
+	int ret;
 
-	pcidev = cnt_find_pci_dev(dev, it);
-	if (!pcidev)
-		return -EIO;
 	comedi_set_hw_dev(dev, &pcidev->dev);
-	board = comedi_board(dev);
 
+	board = cnt_find_boardinfo(dev, pcidev);
+	if (!board)
+		return -ENODEV;
+	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	/* enable PCI device and request regions */
-	error = comedi_pci_enable(pcidev, CNT_DRIVER_NAME);
-	if (error < 0) {
-		printk(KERN_WARNING "comedi%d: "
-		       "failed to enable PCI device and request regions!\n",
-		       dev->minor);
-		return error;
-	}
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = pci_resource_start(pcidev, 0);
 
-	/* read register base address [PCI_BASE_ADDRESS #0] */
-	io_base = pci_resource_start(pcidev, 0);
-	dev->iobase = io_base;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
-	error = comedi_alloc_subdevices(dev, 1);
-	if (error)
-		return error;
+	s = &dev->subdevices[0];
+	dev->read_subdev = s;
 
-	subdevice = dev->subdevices + 0;
-	dev->read_subdev = subdevice;
-
-	subdevice->type = COMEDI_SUBD_COUNTER;
-	subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
-	subdevice->n_chan = board->cnt_channel_nbr;
-	subdevice->maxdata = (1 << board->cnt_bits) - 1;
-	subdevice->insn_read = cnt_rinsn;
-	subdevice->insn_write = cnt_winsn;
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
+	s->n_chan = board->cnt_channel_nbr;
+	s->maxdata = (1 << board->cnt_bits) - 1;
+	s->insn_read = cnt_rinsn;
+	s->insn_write = cnt_winsn;
 
 	/*  select 20MHz clock */
 	outb(3, dev->iobase + 248);
@@ -196,8 +163,9 @@
 	outb(0, dev->iobase + 0x20);
 	outb(0, dev->iobase + 0x40);
 
-	printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n",
-	       dev->minor);
+	dev_info(dev->class_dev, "%s: %s attached\n",
+		dev->driver->driver_name, dev->board_name);
+
 	return 0;
 }
 
@@ -208,14 +176,13 @@
 	if (pcidev) {
 		if (dev->iobase)
 			comedi_pci_disable(pcidev);
-		pci_dev_put(pcidev);
 	}
 }
 
 static struct comedi_driver ke_counter_driver = {
 	.driver_name	= "ke_counter",
 	.module		= THIS_MODULE,
-	.attach		= cnt_attach,
+	.attach_pci	= cnt_attach_pci,
 	.detach		= cnt_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 9a8258e..22db35d 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -35,13 +35,7 @@
     - Digital I/O
     - Counter
 
-Configuration Options:
-
-    [0] - PCI bus number (optional)
-    [1] - PCI slot number (optional)
-
-    If bus/slot is not specified, the first available PCI
-    device will be used.
+Configuration Options: not applicable, uses PCI auto config
 
 The firmware required by these boards is available in the
 comedi_nonfree_firmware tarball available from
@@ -58,51 +52,306 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
-#include "me4000.h"
+#include "comedi_fc.h"
+#include "8253.h"
+
 #if 0
 /* file removed due to GPL incompatibility */
 #include "me4000_fw.h"
 #endif
 
-static const struct me4000_board me4000_boards[] = {
-	{"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} },
+#define PCI_VENDOR_ID_MEILHAUS		0x1402
 
-	{"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3} },
-	{"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3} },
-	{"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3} },
-	{"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3} },
+#define PCI_DEVICE_ID_MEILHAUS_ME4650	0x4650
+#define PCI_DEVICE_ID_MEILHAUS_ME4660	0x4660
+#define PCI_DEVICE_ID_MEILHAUS_ME4660I	0x4661
+#define PCI_DEVICE_ID_MEILHAUS_ME4660S	0x4662
+#define PCI_DEVICE_ID_MEILHAUS_ME4660IS	0x4663
+#define PCI_DEVICE_ID_MEILHAUS_ME4670	0x4670
+#define PCI_DEVICE_ID_MEILHAUS_ME4670I	0x4671
+#define PCI_DEVICE_ID_MEILHAUS_ME4670S	0x4672
+#define PCI_DEVICE_ID_MEILHAUS_ME4670IS	0x4673
+#define PCI_DEVICE_ID_MEILHAUS_ME4680	0x4680
+#define PCI_DEVICE_ID_MEILHAUS_ME4680I	0x4681
+#define PCI_DEVICE_ID_MEILHAUS_ME4680S	0x4682
+#define PCI_DEVICE_ID_MEILHAUS_ME4680IS	0x4683
 
-	{"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3} },
-	{"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3} },
-	{"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3} },
-	{"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3} },
+/*
+ * ME4000 Register map and bit defines
+ */
+#define ME4000_AO_CHAN(x)			((x) * 0x18)
 
-	{"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3} },
-	{"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3} },
-	{"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3} },
-	{"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3} },
+#define ME4000_AO_CTRL_REG(x)			(0x00 + ME4000_AO_CHAN(x))
+#define ME4000_AO_CTRL_BIT_MODE_0		(1 << 0)
+#define ME4000_AO_CTRL_BIT_MODE_1		(1 << 1)
+#define ME4000_AO_CTRL_MASK_MODE		(3 << 0)
+#define ME4000_AO_CTRL_BIT_STOP			(1 << 2)
+#define ME4000_AO_CTRL_BIT_ENABLE_FIFO		(1 << 3)
+#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG	(1 << 4)
+#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE		(1 << 5)
+#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP	(1 << 7)
+#define ME4000_AO_CTRL_BIT_ENABLE_DO		(1 << 8)
+#define ME4000_AO_CTRL_BIT_ENABLE_IRQ		(1 << 9)
+#define ME4000_AO_CTRL_BIT_RESET_IRQ		(1 << 10)
+#define ME4000_AO_STATUS_REG(x)			(0x04 + ME4000_AO_CHAN(x))
+#define ME4000_AO_STATUS_BIT_FSM		(1 << 0)
+#define ME4000_AO_STATUS_BIT_FF			(1 << 1)
+#define ME4000_AO_STATUS_BIT_HF			(1 << 2)
+#define ME4000_AO_STATUS_BIT_EF			(1 << 3)
+#define ME4000_AO_FIFO_REG(x)			(0x08 + ME4000_AO_CHAN(x))
+#define ME4000_AO_SINGLE_REG(x)			(0x0c + ME4000_AO_CHAN(x))
+#define ME4000_AO_TIMER_REG(x)			(0x10 + ME4000_AO_CHAN(x))
+#define ME4000_AI_CTRL_REG			0x74
+#define ME4000_AI_STATUS_REG			0x74
+#define ME4000_AI_CTRL_BIT_MODE_0		(1 << 0)
+#define ME4000_AI_CTRL_BIT_MODE_1		(1 << 1)
+#define ME4000_AI_CTRL_BIT_MODE_2		(1 << 2)
+#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD		(1 << 3)
+#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP	(1 << 4)
+#define ME4000_AI_CTRL_BIT_STOP			(1 << 5)
+#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO		(1 << 6)
+#define ME4000_AI_CTRL_BIT_DATA_FIFO		(1 << 7)
+#define ME4000_AI_CTRL_BIT_FULLSCALE		(1 << 8)
+#define ME4000_AI_CTRL_BIT_OFFSET		(1 << 9)
+#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG	(1 << 10)
+#define ME4000_AI_CTRL_BIT_EX_TRIG		(1 << 11)
+#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING	(1 << 12)
+#define ME4000_AI_CTRL_BIT_EX_IRQ		(1 << 13)
+#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET		(1 << 14)
+#define ME4000_AI_CTRL_BIT_LE_IRQ		(1 << 15)
+#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET		(1 << 16)
+#define ME4000_AI_CTRL_BIT_HF_IRQ		(1 << 17)
+#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET		(1 << 18)
+#define ME4000_AI_CTRL_BIT_SC_IRQ		(1 << 19)
+#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET		(1 << 20)
+#define ME4000_AI_CTRL_BIT_SC_RELOAD		(1 << 21)
+#define ME4000_AI_STATUS_BIT_EF_CHANNEL		(1 << 22)
+#define ME4000_AI_STATUS_BIT_HF_CHANNEL		(1 << 23)
+#define ME4000_AI_STATUS_BIT_FF_CHANNEL		(1 << 24)
+#define ME4000_AI_STATUS_BIT_EF_DATA		(1 << 25)
+#define ME4000_AI_STATUS_BIT_HF_DATA		(1 << 26)
+#define ME4000_AI_STATUS_BIT_FF_DATA		(1 << 27)
+#define ME4000_AI_STATUS_BIT_LE			(1 << 28)
+#define ME4000_AI_STATUS_BIT_FSM		(1 << 29)
+#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH		(1 << 31)
+#define ME4000_AI_CHANNEL_LIST_REG		0x78
+#define ME4000_AI_LIST_INPUT_SINGLE_ENDED	(0 << 5)
+#define ME4000_AI_LIST_INPUT_DIFFERENTIAL	(1 << 5)
+#define ME4000_AI_LIST_RANGE_BIPOLAR_10		(0 << 6)
+#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5	(1 << 6)
+#define ME4000_AI_LIST_RANGE_UNIPOLAR_10	(2 << 6)
+#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5	(3 << 6)
+#define ME4000_AI_LIST_LAST_ENTRY		(1 << 8)
+#define ME4000_AI_DATA_REG			0x7c
+#define ME4000_AI_CHAN_TIMER_REG		0x80
+#define ME4000_AI_CHAN_PRE_TIMER_REG		0x84
+#define ME4000_AI_SCAN_TIMER_LOW_REG		0x88
+#define ME4000_AI_SCAN_TIMER_HIGH_REG		0x8c
+#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG	0x90
+#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG	0x94
+#define ME4000_AI_START_REG			0x98
+#define ME4000_IRQ_STATUS_REG			0x9c
+#define ME4000_IRQ_STATUS_BIT_EX		(1 << 0)
+#define ME4000_IRQ_STATUS_BIT_LE		(1 << 1)
+#define ME4000_IRQ_STATUS_BIT_AI_HF		(1 << 2)
+#define ME4000_IRQ_STATUS_BIT_AO_0_HF		(1 << 3)
+#define ME4000_IRQ_STATUS_BIT_AO_1_HF		(1 << 4)
+#define ME4000_IRQ_STATUS_BIT_AO_2_HF		(1 << 5)
+#define ME4000_IRQ_STATUS_BIT_AO_3_HF		(1 << 6)
+#define ME4000_IRQ_STATUS_BIT_SC		(1 << 7)
+#define ME4000_DIO_PORT_0_REG			0xa0
+#define ME4000_DIO_PORT_1_REG			0xa4
+#define ME4000_DIO_PORT_2_REG			0xa8
+#define ME4000_DIO_PORT_3_REG			0xac
+#define ME4000_DIO_DIR_REG			0xb0
+#define ME4000_AO_LOADSETREG_XX			0xb4
+#define ME4000_DIO_CTRL_REG			0xb8
+#define ME4000_DIO_CTRL_BIT_MODE_0		(1 << 0)
+#define ME4000_DIO_CTRL_BIT_MODE_1		(1 << 1)
+#define ME4000_DIO_CTRL_BIT_MODE_2		(1 << 2)
+#define ME4000_DIO_CTRL_BIT_MODE_3		(1 << 3)
+#define ME4000_DIO_CTRL_BIT_MODE_4		(1 << 4)
+#define ME4000_DIO_CTRL_BIT_MODE_5		(1 << 5)
+#define ME4000_DIO_CTRL_BIT_MODE_6		(1 << 6)
+#define ME4000_DIO_CTRL_BIT_MODE_7		(1 << 7)
+#define ME4000_DIO_CTRL_BIT_FUNCTION_0		(1 << 8)
+#define ME4000_DIO_CTRL_BIT_FUNCTION_1		(1 << 9)
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0		(1 << 10)
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1		(1 << 11)
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2		(1 << 12)
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3		(1 << 13)
+#define ME4000_AO_DEMUX_ADJUST_REG		0xbc
+#define ME4000_AO_DEMUX_ADJUST_VALUE		0x4c
+#define ME4000_AI_SAMPLE_COUNTER_REG		0xc0
 
-	{0},
+/*
+ * PLX Register map and bit defines
+ */
+#define PLX_INTCSR				0x4c
+#define PLX_INTCSR_LOCAL_INT1_EN		(1 << 0)
+#define PLX_INTCSR_LOCAL_INT1_POL		(1 << 1)
+#define PLX_INTCSR_LOCAL_INT1_STATE		(1 << 2)
+#define PLX_INTCSR_LOCAL_INT2_EN		(1 << 3)
+#define PLX_INTCSR_LOCAL_INT2_POL		(1 << 4)
+#define PLX_INTCSR_LOCAL_INT2_STATE		(1 << 5)
+#define PLX_INTCSR_PCI_INT_EN			(1 << 6)
+#define PLX_INTCSR_SOFT_INT			(1 << 7)
+#define PLX_ICR					0x50
+#define PLX_ICR_BIT_EEPROM_CLOCK_SET		(1 << 24)
+#define PLX_ICR_BIT_EEPROM_CHIP_SELECT		(1 << 25)
+#define PLX_ICR_BIT_EEPROM_WRITE		(1 << 26)
+#define PLX_ICR_BIT_EEPROM_READ			(1 << 27)
+#define PLX_ICR_BIT_EEPROM_VALID		(1 << 28)
+#define PLX_ICR_MASK_EEPROM			(0x1f << 24)
+
+#define EEPROM_DELAY				1
+
+#define ME4000_AI_FIFO_COUNT			2048
+
+#define ME4000_AI_MIN_TICKS			66
+#define ME4000_AI_MIN_SAMPLE_TIME		2000
+#define ME4000_AI_BASE_FREQUENCY		(unsigned int) 33E6
+
+#define ME4000_AI_CHANNEL_LIST_COUNT		1024
+
+struct me4000_info {
+	unsigned long plx_regbase;
+	unsigned long timer_regbase;
+
+	unsigned int ao_readback[4];
 };
 
-#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1)
+struct me4000_board {
+	const char *name;
+	unsigned short device_id;
+	int ao_nchan;
+	int ao_fifo;
+	int ai_nchan;
+	int ai_diff_nchan;
+	int ai_sh_nchan;
+	int ex_trig_analog;
+	int dio_nchan;
+	int has_counter;
+};
 
-/*-----------------------------------------------------------------------------
-  Meilhaus function prototypes
-  ---------------------------------------------------------------------------*/
-static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p);
-static int init_board_info(struct comedi_device *dev,
-			   struct pci_dev *pci_dev_p);
-static int init_ao_context(struct comedi_device *dev);
-static int init_ai_context(struct comedi_device *dev);
-static int init_dio_context(struct comedi_device *dev);
-static int init_cnt_context(struct comedi_device *dev);
-static int xilinx_download(struct comedi_device *dev);
-static int reset_board(struct comedi_device *dev);
-
-static int ai_write_chanlist(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_cmd *cmd);
+static const struct me4000_board me4000_boards[] = {
+	{
+		.name		= "ME-4650",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4650,
+		.ai_nchan	= 16,
+		.dio_nchan	= 32,
+	}, {
+		.name		= "ME-4660",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4660,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4660i",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4660I,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4660s",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4660S,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4660is",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4660IS,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4670",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4670,
+		.ao_nchan	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4670i",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4670I,
+		.ao_nchan	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4670s",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4670S,
+		.ao_nchan	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4670is",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4670IS,
+		.ao_nchan	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4680",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4680,
+		.ao_nchan	= 4,
+		.ao_fifo	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4680i",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4680I,
+		.ao_nchan	= 4,
+		.ao_fifo	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4680s",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4680S,
+		.ao_nchan	= 4,
+		.ao_fifo	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	}, {
+		.name		= "ME-4680is",
+		.device_id	= PCI_DEVICE_ID_MEILHAUS_ME4680IS,
+		.ao_nchan	= 4,
+		.ao_fifo	= 4,
+		.ai_nchan	= 32,
+		.ai_diff_nchan	= 16,
+		.ai_sh_nchan	= 8,
+		.ex_trig_analog	= 1,
+		.dio_nchan	= 32,
+		.has_counter	= 1,
+	},
+};
 
 static const struct comedi_lrange me4000_ai_range = {
 	4,
@@ -114,380 +363,6 @@
 	 }
 };
 
-static const struct comedi_lrange me4000_ao_range = {
-	1,
-	{
-	 BIP_RANGE(10),
-	 }
-};
-
-static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct pci_dev *pci_device = NULL;
-	int result, i;
-	struct me4000_board *board;
-
-	/* Allocate private memory */
-	if (alloc_private(dev, sizeof(struct me4000_info)) < 0)
-		return -ENOMEM;
-
-	/*
-	 * Probe the device to determine what device in the series it is.
-	 */
-	for_each_pci_dev(pci_device) {
-		if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
-			for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
-				if (me4000_boards[i].device_id ==
-				    pci_device->device) {
-					/*
-					 * Was a particular
-					 * bus/slot requested?
-					 */
-					if ((it->options[0] != 0)
-					    || (it->options[1] != 0)) {
-						/*
-						 * Are we on the wrong
-						 * bus/slot?
-						 */
-						if (pci_device->bus->number !=
-						    it->options[0]
-						    ||
-						    PCI_SLOT(pci_device->devfn)
-						    != it->options[1]) {
-							continue;
-						}
-					}
-					dev->board_ptr = me4000_boards + i;
-					board =
-					    (struct me4000_board *)
-					    dev->board_ptr;
-					info->pci_dev_p = pci_device;
-					goto found;
-				}
-			}
-		}
-	}
-
-	printk(KERN_ERR
-	       "comedi%d: me4000: me4000_probe(): "
-	       "No supported board found (req. bus/slot : %d/%d)\n",
-	       dev->minor, it->options[0], it->options[1]);
-	return -ENODEV;
-
-found:
-
-	printk(KERN_INFO
-	       "comedi%d: me4000: me4000_probe(): "
-	       "Found %s at PCI bus %d, slot %d\n",
-	       dev->minor, me4000_boards[i].name, pci_device->bus->number,
-	       PCI_SLOT(pci_device->devfn));
-
-	/* Set data in device structure */
-	dev->board_name = board->name;
-
-	/* Enable PCI device and request regions */
-	result = comedi_pci_enable(pci_device, dev->board_name);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): Cannot enable PCI "
-		       "device and request I/O regions\n", dev->minor);
-		return result;
-	}
-
-	/* Get the PCI base registers */
-	result = get_registers(dev, pci_device);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot get registers\n", dev->minor);
-		return result;
-	}
-	/* Initialize board info */
-	result = init_board_info(dev, pci_device);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot init baord info\n", dev->minor);
-		return result;
-	}
-
-	/* Init analog output context */
-	result = init_ao_context(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot init ao context\n", dev->minor);
-		return result;
-	}
-
-	/* Init analog input context */
-	result = init_ai_context(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot init ai context\n", dev->minor);
-		return result;
-	}
-
-	/* Init digital I/O context */
-	result = init_dio_context(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot init dio context\n", dev->minor);
-		return result;
-	}
-
-	/* Init counter context */
-	result = init_cnt_context(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Cannot init cnt context\n", dev->minor);
-		return result;
-	}
-
-	/* Download the xilinx firmware */
-	result = xilinx_download(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): "
-		       "Can't download firmware\n", dev->minor);
-		return result;
-	}
-
-	/* Make a hardware reset */
-	result = reset_board(dev);
-	if (result) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_probe(): Can't reset board\n",
-		       dev->minor);
-		return result;
-	}
-
-	return 0;
-}
-
-static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p)
-{
-    /*--------------------------- plx regbase -------------------------------*/
-
-	info->plx_regbase = pci_resource_start(pci_dev_p, 1);
-	if (info->plx_regbase == 0) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: get_registers(): "
-		       "PCI base address 1 is not available\n", dev->minor);
-		return -ENODEV;
-	}
-	info->plx_regbase_size = pci_resource_len(pci_dev_p, 1);
-
-    /*--------------------------- me4000 regbase ----------------------------*/
-
-	info->me4000_regbase = pci_resource_start(pci_dev_p, 2);
-	if (info->me4000_regbase == 0) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: get_registers(): "
-		       "PCI base address 2 is not available\n", dev->minor);
-		return -ENODEV;
-	}
-	info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2);
-
-    /*--------------------------- timer regbase ------------------------------*/
-
-	info->timer_regbase = pci_resource_start(pci_dev_p, 3);
-	if (info->timer_regbase == 0) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: get_registers(): "
-		       "PCI base address 3 is not available\n", dev->minor);
-		return -ENODEV;
-	}
-	info->timer_regbase_size = pci_resource_len(pci_dev_p, 3);
-
-    /*--------------------------- program regbase ----------------------------*/
-
-	info->program_regbase = pci_resource_start(pci_dev_p, 5);
-	if (info->program_regbase == 0) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: get_registers(): "
-		       "PCI base address 5 is not available\n", dev->minor);
-		return -ENODEV;
-	}
-	info->program_regbase_size = pci_resource_len(pci_dev_p, 5);
-
-	return 0;
-}
-
-static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p)
-{
-	int result;
-
-	/* Init spin locks */
-	/* spin_lock_init(&info->preload_lock); */
-	/* spin_lock_init(&info->ai_ctrl_lock); */
-
-	/* Get the serial number */
-	result = pci_read_config_dword(pci_dev_p, 0x2C, &info->serial_no);
-	if (result != PCIBIOS_SUCCESSFUL)
-		return result;
-
-	/* Get the hardware revision */
-	result = pci_read_config_byte(pci_dev_p, 0x08, &info->hw_revision);
-	if (result != PCIBIOS_SUCCESSFUL)
-		return result;
-
-	/* Get the vendor id */
-	info->vendor_id = pci_dev_p->vendor;
-
-	/* Get the device id */
-	info->device_id = pci_dev_p->device;
-
-	/* Get the irq assigned to the board */
-	info->irq = pci_dev_p->irq;
-
-	return 0;
-}
-
-static int init_ao_context(struct comedi_device *dev)
-{
-	int i;
-
-	for (i = 0; i < thisboard->ao.count; i++) {
-		/* spin_lock_init(&info->ao_context[i].use_lock); */
-		info->ao_context[i].irq = info->irq;
-
-		switch (i) {
-		case 0:
-			info->ao_context[i].ctrl_reg =
-			    info->me4000_regbase + ME4000_AO_00_CTRL_REG;
-			info->ao_context[i].status_reg =
-			    info->me4000_regbase + ME4000_AO_00_STATUS_REG;
-			info->ao_context[i].fifo_reg =
-			    info->me4000_regbase + ME4000_AO_00_FIFO_REG;
-			info->ao_context[i].single_reg =
-			    info->me4000_regbase + ME4000_AO_00_SINGLE_REG;
-			info->ao_context[i].timer_reg =
-			    info->me4000_regbase + ME4000_AO_00_TIMER_REG;
-			info->ao_context[i].irq_status_reg =
-			    info->me4000_regbase + ME4000_IRQ_STATUS_REG;
-			info->ao_context[i].preload_reg =
-			    info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
-			break;
-		case 1:
-			info->ao_context[i].ctrl_reg =
-			    info->me4000_regbase + ME4000_AO_01_CTRL_REG;
-			info->ao_context[i].status_reg =
-			    info->me4000_regbase + ME4000_AO_01_STATUS_REG;
-			info->ao_context[i].fifo_reg =
-			    info->me4000_regbase + ME4000_AO_01_FIFO_REG;
-			info->ao_context[i].single_reg =
-			    info->me4000_regbase + ME4000_AO_01_SINGLE_REG;
-			info->ao_context[i].timer_reg =
-			    info->me4000_regbase + ME4000_AO_01_TIMER_REG;
-			info->ao_context[i].irq_status_reg =
-			    info->me4000_regbase + ME4000_IRQ_STATUS_REG;
-			info->ao_context[i].preload_reg =
-			    info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
-			break;
-		case 2:
-			info->ao_context[i].ctrl_reg =
-			    info->me4000_regbase + ME4000_AO_02_CTRL_REG;
-			info->ao_context[i].status_reg =
-			    info->me4000_regbase + ME4000_AO_02_STATUS_REG;
-			info->ao_context[i].fifo_reg =
-			    info->me4000_regbase + ME4000_AO_02_FIFO_REG;
-			info->ao_context[i].single_reg =
-			    info->me4000_regbase + ME4000_AO_02_SINGLE_REG;
-			info->ao_context[i].timer_reg =
-			    info->me4000_regbase + ME4000_AO_02_TIMER_REG;
-			info->ao_context[i].irq_status_reg =
-			    info->me4000_regbase + ME4000_IRQ_STATUS_REG;
-			info->ao_context[i].preload_reg =
-			    info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
-			break;
-		case 3:
-			info->ao_context[i].ctrl_reg =
-			    info->me4000_regbase + ME4000_AO_03_CTRL_REG;
-			info->ao_context[i].status_reg =
-			    info->me4000_regbase + ME4000_AO_03_STATUS_REG;
-			info->ao_context[i].fifo_reg =
-			    info->me4000_regbase + ME4000_AO_03_FIFO_REG;
-			info->ao_context[i].single_reg =
-			    info->me4000_regbase + ME4000_AO_03_SINGLE_REG;
-			info->ao_context[i].timer_reg =
-			    info->me4000_regbase + ME4000_AO_03_TIMER_REG;
-			info->ao_context[i].irq_status_reg =
-			    info->me4000_regbase + ME4000_IRQ_STATUS_REG;
-			info->ao_context[i].preload_reg =
-			    info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
-			break;
-		default:
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int init_ai_context(struct comedi_device *dev)
-{
-	info->ai_context.irq = info->irq;
-
-	info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG;
-	info->ai_context.status_reg =
-	    info->me4000_regbase + ME4000_AI_STATUS_REG;
-	info->ai_context.channel_list_reg =
-	    info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG;
-	info->ai_context.data_reg = info->me4000_regbase + ME4000_AI_DATA_REG;
-	info->ai_context.chan_timer_reg =
-	    info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG;
-	info->ai_context.chan_pre_timer_reg =
-	    info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG;
-	info->ai_context.scan_timer_low_reg =
-	    info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG;
-	info->ai_context.scan_timer_high_reg =
-	    info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG;
-	info->ai_context.scan_pre_timer_low_reg =
-	    info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG;
-	info->ai_context.scan_pre_timer_high_reg =
-	    info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG;
-	info->ai_context.start_reg = info->me4000_regbase + ME4000_AI_START_REG;
-	info->ai_context.irq_status_reg =
-	    info->me4000_regbase + ME4000_IRQ_STATUS_REG;
-	info->ai_context.sample_counter_reg =
-	    info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG;
-
-	return 0;
-}
-
-static int init_dio_context(struct comedi_device *dev)
-{
-	info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG;
-	info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG;
-	info->dio_context.port_0_reg =
-	    info->me4000_regbase + ME4000_DIO_PORT_0_REG;
-	info->dio_context.port_1_reg =
-	    info->me4000_regbase + ME4000_DIO_PORT_1_REG;
-	info->dio_context.port_2_reg =
-	    info->me4000_regbase + ME4000_DIO_PORT_2_REG;
-	info->dio_context.port_3_reg =
-	    info->me4000_regbase + ME4000_DIO_PORT_3_REG;
-
-	return 0;
-}
-
-static int init_cnt_context(struct comedi_device *dev)
-{
-	info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG;
-	info->cnt_context.counter_0_reg =
-	    info->timer_regbase + ME4000_CNT_COUNTER_0_REG;
-	info->cnt_context.counter_1_reg =
-	    info->timer_regbase + ME4000_CNT_COUNTER_1_REG;
-	info->cnt_context.counter_2_reg =
-	    info->timer_regbase + ME4000_CNT_COUNTER_2_REG;
-
-	return 0;
-}
-
 #define FIRMWARE_NOT_AVAILABLE 1
 #if FIRMWARE_NOT_AVAILABLE
 extern unsigned char *xilinx_firm;
@@ -495,11 +370,17 @@
 
 static int xilinx_download(struct comedi_device *dev)
 {
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	struct me4000_info *info = dev->private;
+	unsigned long xilinx_iobase = pci_resource_start(pcidev, 5);
 	u32 value = 0;
 	wait_queue_head_t queue;
 	int idx = 0;
 	int size = 0;
 
+	if (!xilinx_iobase)
+		return -ENODEV;
+
 	init_waitqueue_head(&queue);
 
 	/*
@@ -514,14 +395,12 @@
 	outl(value, info->plx_regbase + PLX_ICR);
 
 	/* Init Xilinx with CS1 */
-	inb(info->program_regbase + 0xC8);
+	inb(xilinx_iobase + 0xC8);
 
 	/* Wait until /INIT pin is set */
 	udelay(20);
 	if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: xilinx_download(): "
-		       "Can't init Xilinx\n", dev->minor);
+		dev_err(dev->class_dev, "Can't init Xilinx\n");
 		return -EIO;
 	}
 
@@ -530,8 +409,8 @@
 	value &= ~0x100;
 	outl(value, info->plx_regbase + PLX_ICR);
 	if (FIRMWARE_NOT_AVAILABLE) {
-		comedi_error(dev, "xilinx firmware unavailable "
-			     "due to licensing, aborting");
+		dev_err(dev->class_dev,
+			"xilinx firmware unavailable due to licensing, aborting");
 		return -EIO;
 	} else {
 		/* Download Xilinx firmware */
@@ -540,15 +419,14 @@
 		udelay(10);
 
 		for (idx = 0; idx < size; idx++) {
-			outb(xilinx_firm[16 + idx], info->program_regbase);
+			outb(xilinx_firm[16 + idx], xilinx_iobase);
 			udelay(10);
 
 			/* Check if BUSY flag is low */
 			if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
-				printk(KERN_ERR
-				       "comedi%d: me4000: xilinx_download(): "
-				       "Xilinx is still busy (idx = %d)\n",
-				       dev->minor, idx);
+				dev_err(dev->class_dev,
+					"Xilinx is still busy (idx = %d)\n",
+					idx);
 				return -EIO;
 			}
 		}
@@ -557,12 +435,8 @@
 	/* If done flag is high download was successful */
 	if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
 	} else {
-		printk(KERN_ERR
-		       "comedi%d: me4000: xilinx_download(): "
-		       "DONE flag is not set\n", dev->minor);
-		printk(KERN_ERR
-		       "comedi%d: me4000: xilinx_download(): "
-		       "Download not successful\n", dev->minor);
+		dev_err(dev->class_dev, "DONE flag is not set\n");
+		dev_err(dev->class_dev, "Download not successful\n");
 		return -EIO;
 	}
 
@@ -574,52 +448,45 @@
 	return 0;
 }
 
-static int reset_board(struct comedi_device *dev)
+static void me4000_reset(struct comedi_device *dev)
 {
-	unsigned long icr;
+	struct me4000_info *info = dev->private;
+	unsigned long val;
+	int chan;
 
 	/* Make a hardware reset */
-	icr = inl(info->plx_regbase + PLX_ICR);
-	icr |= 0x40000000;
-	outl(icr, info->plx_regbase + PLX_ICR);
-	icr &= ~0x40000000;
-	outl(icr, info->plx_regbase + PLX_ICR);
+	val = inl(info->plx_regbase + PLX_ICR);
+	val |= 0x40000000;
+	outl(val, info->plx_regbase + PLX_ICR);
+	val &= ~0x40000000;
+	outl(val , info->plx_regbase + PLX_ICR);
 
 	/* 0x8000 to the DACs means an output voltage of 0V */
-	outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
-	outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
-	outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
-	outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
+	for (chan = 0; chan < 4; chan++)
+		outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan));
 
 	/* Set both stop bits in the analog input control register */
 	outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
-		info->me4000_regbase + ME4000_AI_CTRL_REG);
+		dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Set both stop bits in the analog output control register */
-	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		info->me4000_regbase + ME4000_AO_00_CTRL_REG);
-	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		info->me4000_regbase + ME4000_AO_01_CTRL_REG);
-	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		info->me4000_regbase + ME4000_AO_02_CTRL_REG);
-	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		info->me4000_regbase + ME4000_AO_03_CTRL_REG);
+	val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP;
+	for (chan = 0; chan < 4; chan++)
+		outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
 
 	/* Enable interrupts on the PLX */
 	outl(0x43, info->plx_regbase + PLX_INTCSR);
 
 	/* Set the adustment register for AO demux */
 	outl(ME4000_AO_DEMUX_ADJUST_VALUE,
-		    info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
+		    dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
 
 	/*
 	 * Set digital I/O direction for port 0
 	 * to output on isolated versions
 	 */
-	if (!(inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1))
-		outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG);
-
-	return 0;
+	if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
+		outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG);
 }
 
 /*=============================================================================
@@ -630,7 +497,7 @@
 			       struct comedi_subdevice *subdevice,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-
+	const struct me4000_board *thisboard = comedi_board(dev);
 	int chan = CR_CHAN(insn->chanspec);
 	int rang = CR_RANGE(insn->chanspec);
 	int aref = CR_AREF(insn->chanspec);
@@ -642,9 +509,8 @@
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_insn_read(): "
-		       "Invalid instruction length %d\n", dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid instruction length %d\n",
+			insn->n);
 		return -EINVAL;
 	}
 
@@ -662,19 +528,16 @@
 		entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
 		break;
 	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_insn_read(): "
-		       "Invalid range specified\n", dev->minor);
+		dev_err(dev->class_dev, "Invalid range specified\n");
 		return -EINVAL;
 	}
 
 	switch (aref) {
 	case AREF_GROUND:
 	case AREF_COMMON:
-		if (chan >= thisboard->ai.count) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_insn_read(): "
-			       "Analog input is not available\n", dev->minor);
+		if (chan >= thisboard->ai_nchan) {
+			dev_err(dev->class_dev,
+				"Analog input is not available\n");
 			return -EINVAL;
 		}
 		entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan;
@@ -682,68 +545,61 @@
 
 	case AREF_DIFF:
 		if (rang == 0 || rang == 1) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_insn_read(): "
-			       "Range must be bipolar when aref = diff\n",
-			       dev->minor);
+			dev_err(dev->class_dev,
+				"Range must be bipolar when aref = diff\n");
 			return -EINVAL;
 		}
 
-		if (chan >= thisboard->ai.diff_count) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_insn_read(): "
-			       "Analog input is not available\n", dev->minor);
+		if (chan >= thisboard->ai_diff_nchan) {
+			dev_err(dev->class_dev,
+				"Analog input is not available\n");
 			return -EINVAL;
 		}
 		entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan;
 		break;
 	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_insn_read(): "
-		       "Invalid aref specified\n", dev->minor);
+		dev_err(dev->class_dev, "Invalid aref specified\n");
 		return -EINVAL;
 	}
 
 	entry |= ME4000_AI_LIST_LAST_ENTRY;
 
 	/* Clear channel list, data fifo and both stop bits */
-	tmp = inl(info->ai_context.ctrl_reg);
+	tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
 	tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
 		 ME4000_AI_CTRL_BIT_DATA_FIFO |
 		 ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Set the acquisition mode to single */
 	tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 |
 		 ME4000_AI_CTRL_BIT_MODE_2);
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Enable channel list and data fifo */
 	tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Generate channel list entry */
-	outl(entry, info->ai_context.channel_list_reg);
+	outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
 
 	/* Set the timer to maximum sample rate */
-	outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg);
-	outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_pre_timer_reg);
+	outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
+	outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
 
 	/* Start conversion by dummy read */
-	inl(info->ai_context.start_reg);
+	inl(dev->iobase + ME4000_AI_START_REG);
 
 	/* Wait until ready */
 	udelay(10);
-	if (!(inl(info->ai_context.status_reg) &
+	if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) &
 	     ME4000_AI_STATUS_BIT_EF_DATA)) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_insn_read(): "
-		       "Value not available after wait\n", dev->minor);
+		dev_err(dev->class_dev, "Value not available after wait\n");
 		return -EIO;
 	}
 
 	/* Read value from data fifo */
-	lval = inl(info->ai_context.data_reg) & 0xFFFF;
+	lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
 	data[0] = lval ^ 0x8000;
 
 	return 1;
@@ -755,12 +611,12 @@
 	unsigned long tmp;
 
 	/* Stop any running conversion */
-	tmp = inl(info->ai_context.ctrl_reg);
+	tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
 	tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Clear the control register */
-	outl(0x0, info->ai_context.ctrl_reg);
+	outl(0x0, dev->iobase + ME4000_AI_CTRL_REG);
 
 	return 0;
 }
@@ -768,30 +624,25 @@
 static int ai_check_chanlist(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct me4000_board *thisboard = comedi_board(dev);
 	int aref;
 	int i;
 
 	/* Check whether a channel list is available */
 	if (!cmd->chanlist_len) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: ai_check_chanlist(): "
-		       "No channel list available\n", dev->minor);
+		dev_err(dev->class_dev, "No channel list available\n");
 		return -EINVAL;
 	}
 
 	/* Check the channel list size */
 	if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: ai_check_chanlist(): "
-		       "Channel list is to large\n", dev->minor);
+		dev_err(dev->class_dev, "Channel list is to large\n");
 		return -EINVAL;
 	}
 
 	/* Check the pointer */
 	if (!cmd->chanlist) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: ai_check_chanlist(): "
-		       "NULL pointer to channel list\n", dev->minor);
+		dev_err(dev->class_dev, "NULL pointer to channel list\n");
 		return -EFAULT;
 	}
 
@@ -799,10 +650,8 @@
 	aref = CR_AREF(cmd->chanlist[0]);
 	for (i = 0; i < cmd->chanlist_len; i++) {
 		if (CR_AREF(cmd->chanlist[i]) != aref) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: ai_check_chanlist(): "
-			       "Mode is not equal for all entries\n",
-			       dev->minor);
+			dev_err(dev->class_dev,
+				"Mode is not equal for all entries\n");
 			return -EINVAL;
 		}
 	}
@@ -811,19 +660,17 @@
 	if (aref == SDF_DIFF) {
 		for (i = 0; i < cmd->chanlist_len; i++) {
 			if (CR_CHAN(cmd->chanlist[i]) >=
-			    thisboard->ai.diff_count) {
-				printk(KERN_ERR
-				       "comedi%d: me4000: ai_check_chanlist():"
-				       " Channel number to high\n", dev->minor);
+			    thisboard->ai_diff_nchan) {
+				dev_err(dev->class_dev,
+					"Channel number to high\n");
 				return -EINVAL;
 			}
 		}
 	} else {
 		for (i = 0; i < cmd->chanlist_len; i++) {
-			if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) {
-				printk(KERN_ERR
-				       "comedi%d: me4000: ai_check_chanlist(): "
-				       "Channel number to high\n", dev->minor);
+			if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) {
+				dev_err(dev->class_dev,
+					"Channel number to high\n");
 				return -EINVAL;
 			}
 		}
@@ -834,11 +681,8 @@
 		for (i = 0; i < cmd->chanlist_len; i++) {
 			if (CR_RANGE(cmd->chanlist[i]) != 1 &&
 			    CR_RANGE(cmd->chanlist[i]) != 2) {
-				printk(KERN_ERR
-				       "comedi%d: me4000: ai_check_chanlist(): "
-				       "Bipolar is not selected in "
-				       "differential mode\n",
-				       dev->minor);
+				dev_err(dev->class_dev,
+				       "Bipolar is not selected in differential mode\n");
 				return -EINVAL;
 			}
 		}
@@ -906,16 +750,52 @@
 			   unsigned int init_ticks,
 			   unsigned int scan_ticks, unsigned int chan_ticks)
 {
-	outl(init_ticks - 1, info->ai_context.scan_pre_timer_low_reg);
-	outl(0x0, info->ai_context.scan_pre_timer_high_reg);
+	outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
+	outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
 
 	if (scan_ticks) {
-		outl(scan_ticks - 1, info->ai_context.scan_timer_low_reg);
-		outl(0x0, info->ai_context.scan_timer_high_reg);
+		outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
+		outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
 	}
 
-	outl(chan_ticks - 1, info->ai_context.chan_pre_timer_reg);
-	outl(chan_ticks - 1, info->ai_context.chan_timer_reg);
+	outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
+	outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
+}
+
+static int ai_write_chanlist(struct comedi_device *dev,
+			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
+{
+	unsigned int entry;
+	unsigned int chan;
+	unsigned int rang;
+	unsigned int aref;
+	int i;
+
+	for (i = 0; i < cmd->chanlist_len; i++) {
+		chan = CR_CHAN(cmd->chanlist[i]);
+		rang = CR_RANGE(cmd->chanlist[i]);
+		aref = CR_AREF(cmd->chanlist[i]);
+
+		entry = chan;
+
+		if (rang == 0)
+			entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
+		else if (rang == 1)
+			entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
+		else if (rang == 2)
+			entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
+		else
+			entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
+
+		if (aref == SDF_DIFF)
+			entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
+		else
+			entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
+
+		outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
+	}
+
+	return 0;
 }
 
 static int ai_prepare(struct comedi_device *dev,
@@ -931,7 +811,7 @@
 	ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks);
 
 	/* Reset control register */
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Start sources */
 	if ((cmd->start_src == TRIG_EXT &&
@@ -965,19 +845,19 @@
 	/* Stop triggers */
 	if (cmd->stop_src == TRIG_COUNT) {
 		outl(cmd->chanlist_len * cmd->stop_arg,
-			    info->ai_context.sample_counter_reg);
+			    dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
 	} else if (cmd->stop_src == TRIG_NONE &&
 		   cmd->scan_end_src == TRIG_COUNT) {
 		outl(cmd->scan_end_arg,
-			    info->ai_context.sample_counter_reg);
+			    dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
 	} else {
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
 	}
 
 	/* Write the setup to the control register */
-	outl(tmp, info->ai_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 	/* Write the channel list */
 	ai_write_chanlist(dev, s, cmd);
@@ -985,42 +865,6 @@
 	return 0;
 }
 
-static int ai_write_chanlist(struct comedi_device *dev,
-			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
-{
-	unsigned int entry;
-	unsigned int chan;
-	unsigned int rang;
-	unsigned int aref;
-	int i;
-
-	for (i = 0; i < cmd->chanlist_len; i++) {
-		chan = CR_CHAN(cmd->chanlist[i]);
-		rang = CR_RANGE(cmd->chanlist[i]);
-		aref = CR_AREF(cmd->chanlist[i]);
-
-		entry = chan;
-
-		if (rang == 0)
-			entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
-		else if (rang == 1)
-			entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
-		else if (rang == 2)
-			entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
-		else
-			entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
-
-		if (aref == SDF_DIFF)
-			entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
-		else
-			entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
-
-		outl(entry, info->ai_context.channel_list_reg);
-	}
-
-	return 0;
-}
-
 static int me4000_ai_do_cmd(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
@@ -1047,23 +891,11 @@
 		return err;
 
 	/* Start acquistion by dummy read */
-	inl(info->ai_context.start_reg);
+	inl(dev->iobase + ME4000_AI_START_REG);
 
 	return 0;
 }
 
-/*
- * me4000_ai_do_cmd_test():
- *
- * The demo cmd.c in ./comedilib/demo specifies 6 return values:
- * - success
- * - invalid source
- * - source conflict
- * - invalid argument
- * - argument conflict
- * - invalid chanlist
- * So I tried to adopt this scheme.
- */
 static int me4000_ai_do_cmd_test(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_cmd *cmd)
@@ -1080,91 +912,29 @@
 	/* Round the timer arguments */
 	ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
 
-	/*
-	 * Stage 1. Check if the trigger sources are generally valid.
-	 */
-	switch (cmd->start_src) {
-	case TRIG_NOW:
-	case TRIG_EXT:
-		break;
-	case TRIG_ANY:
-		cmd->start_src &= TRIG_NOW | TRIG_EXT;
-		err++;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid start source\n", dev->minor);
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
-	switch (cmd->scan_begin_src) {
-	case TRIG_FOLLOW:
-	case TRIG_TIMER:
-	case TRIG_EXT:
-		break;
-	case TRIG_ANY:
-		cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
-		err++;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid scan begin source\n", dev->minor);
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
-	switch (cmd->convert_src) {
-	case TRIG_TIMER:
-	case TRIG_EXT:
-		break;
-	case TRIG_ANY:
-		cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-		err++;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid convert source\n", dev->minor);
-		cmd->convert_src = TRIG_TIMER;
-		err++;
-	}
-	switch (cmd->scan_end_src) {
-	case TRIG_NONE:
-	case TRIG_COUNT:
-		break;
-	case TRIG_ANY:
-		cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT;
-		err++;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid scan end source\n", dev->minor);
-		cmd->scan_end_src = TRIG_NONE;
-		err++;
-	}
-	switch (cmd->stop_src) {
-	case TRIG_NONE:
-	case TRIG_COUNT:
-		break;
-	case TRIG_ANY:
-		cmd->stop_src &= TRIG_NONE | TRIG_COUNT;
-		err++;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid stop source\n", dev->minor);
-		cmd->stop_src = TRIG_NONE;
-		err++;
-	}
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src,
+					TRIG_NONE | TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT);
+
 	if (err)
 		return 1;
 
-	/*
-	 * Stage 2. Check for trigger source conflicts.
-	 */
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_end_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->start_src == TRIG_NOW &&
 	    cmd->scan_begin_src == TRIG_TIMER &&
 	    cmd->convert_src == TRIG_TIMER) {
@@ -1184,13 +954,7 @@
 		   cmd->scan_begin_src == TRIG_EXT &&
 		   cmd->convert_src == TRIG_EXT) {
 	} else {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid start trigger combination\n", dev->minor);
-		cmd->start_src = TRIG_NOW;
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		cmd->convert_src = TRIG_TIMER;
-		err++;
+		err |= -EINVAL;
 	}
 
 	if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) {
@@ -1201,13 +965,9 @@
 	} else if (cmd->stop_src == TRIG_COUNT &&
 		   cmd->scan_end_src == TRIG_COUNT) {
 	} else {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Invalid stop trigger combination\n", dev->minor);
-		cmd->stop_src = TRIG_NONE;
-		cmd->scan_end_src = TRIG_NONE;
-		err++;
+		err |= -EINVAL;
 	}
+
 	if (err)
 		return 2;
 
@@ -1215,30 +975,22 @@
 	 * Stage 3. Check if arguments are generally valid.
 	 */
 	if (cmd->chanlist_len < 1) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "No channel list\n", dev->minor);
+		dev_err(dev->class_dev, "No channel list\n");
 		cmd->chanlist_len = 1;
 		err++;
 	}
 	if (init_ticks < 66) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Start arg to low\n", dev->minor);
+		dev_err(dev->class_dev, "Start arg to low\n");
 		cmd->start_arg = 2000;
 		err++;
 	}
 	if (scan_ticks && scan_ticks < 67) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Scan begin arg to low\n", dev->minor);
+		dev_err(dev->class_dev, "Scan begin arg to low\n");
 		cmd->scan_begin_arg = 2031;
 		err++;
 	}
 	if (chan_ticks < 66) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-		       "Convert arg to low\n", dev->minor);
+		dev_err(dev->class_dev, "Convert arg to low\n");
 		cmd->convert_arg = 2000;
 		err++;
 	}
@@ -1255,23 +1007,17 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (chan_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid convert arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid convert arg\n");
 			cmd->convert_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid scan end arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid scan end arg\n");
 
 			/*  At least one tick more */
 			cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
@@ -1283,16 +1029,12 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (chan_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid convert arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid convert arg\n");
 			cmd->convert_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
@@ -1302,23 +1044,17 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (chan_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid convert arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid convert arg\n");
 			cmd->convert_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid scan end arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid scan end arg\n");
 
 			/*  At least one tick more */
 			cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
@@ -1330,16 +1066,12 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (chan_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid convert arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid convert arg\n");
 			cmd->convert_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
@@ -1349,16 +1081,12 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 		if (chan_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid convert arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid convert arg\n");
 			cmd->convert_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
@@ -1368,27 +1096,21 @@
 
 		/* Check timer arguments */
 		if (init_ticks < ME4000_AI_MIN_TICKS) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid start arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid start arg\n");
 			cmd->start_arg = 2000;	/*  66 ticks at least */
 			err++;
 		}
 	}
 	if (cmd->stop_src == TRIG_COUNT) {
 		if (cmd->stop_arg == 0) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid stop arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid stop arg\n");
 			cmd->stop_arg = 1;
 			err++;
 		}
 	}
 	if (cmd->scan_end_src == TRIG_COUNT) {
 		if (cmd->scan_end_arg == 0) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_do_cmd_test(): "
-			       "Invalid scan end arg\n", dev->minor);
+			dev_err(dev->class_dev, "Invalid scan end arg\n");
 			cmd->scan_end_arg = 1;
 			err++;
 		}
@@ -1410,8 +1132,7 @@
 {
 	unsigned int tmp;
 	struct comedi_device *dev = dev_id;
-	struct comedi_subdevice *s = dev->subdevices;
-	struct me4000_ai_context *ai_context = &info->ai_context;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int i;
 	int c = 0;
 	long lval;
@@ -1423,17 +1144,15 @@
 	s->async->events = 0;
 
 	/* Check if irq number is right */
-	if (irq != ai_context->irq) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ai_isr(): "
-		       "Incorrect interrupt num: %d\n", dev->minor, irq);
+	if (irq != dev->irq) {
+		dev_err(dev->class_dev, "Incorrect interrupt num: %d\n", irq);
 		return IRQ_HANDLED;
 	}
 
-	if (inl(ai_context->irq_status_reg) &
+	if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
 	    ME4000_IRQ_STATUS_BIT_AI_HF) {
 		/* Read status register to find out what happened */
-		tmp = inl(ai_context->ctrl_reg);
+		tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
 
 		if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
 		    !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) &&
@@ -1447,13 +1166,11 @@
 			tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 			tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
-			outl(tmp, ai_context->ctrl_reg);
+			outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_isr(): "
-			       "FIFO overflow\n", dev->minor);
+			dev_err(dev->class_dev, "FIFO overflow\n");
 		} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
 			   && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
 			   && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
@@ -1461,9 +1178,8 @@
 
 			c = ME4000_AI_FIFO_COUNT / 2;
 		} else {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_isr(): "
-			       "Can't determine state of fifo\n", dev->minor);
+			dev_err(dev->class_dev,
+				"Can't determine state of fifo\n");
 			c = 0;
 
 			/*
@@ -1473,18 +1189,16 @@
 			tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 			tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
-			outl(tmp, ai_context->ctrl_reg);
+			outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_ai_isr(): "
-			       "Undefined FIFO state\n", dev->minor);
+			dev_err(dev->class_dev, "Undefined FIFO state\n");
 		}
 
 		for (i = 0; i < c; i++) {
 			/* Read value from data fifo */
-			lval = inl(ai_context->data_reg) & 0xFFFF;
+			lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
 			lval ^= 0x8000;
 
 			if (!comedi_buf_put(s->async, lval)) {
@@ -1495,13 +1209,11 @@
 				tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 				tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 					 ME4000_AI_CTRL_BIT_SC_IRQ);
-				outl(tmp, ai_context->ctrl_reg);
+				outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 				s->async->events |= COMEDI_CB_OVERFLOW;
 
-				printk(KERN_ERR
-				       "comedi%d: me4000: me4000_ai_isr(): "
-				       "Buffer overflow\n", dev->minor);
+				dev_err(dev->class_dev, "Buffer overflow\n");
 
 				break;
 			}
@@ -1509,33 +1221,33 @@
 
 		/* Work is done, so reset the interrupt */
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
-		outl(tmp, ai_context->ctrl_reg);
+		outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 		tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
-		outl(tmp, ai_context->ctrl_reg);
+		outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 	}
 
-	if (inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) {
+	if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
+	    ME4000_IRQ_STATUS_BIT_SC) {
 		s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA;
 
 		/*
 		 * Acquisition is complete, so stop
 		 * conversion and disable all interrupts
 		 */
-		tmp = inl(ai_context->ctrl_reg);
+		tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
 		tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 		tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
-		outl(tmp, ai_context->ctrl_reg);
+		outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
 		/* Poll data until fifo empty */
-		while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) {
+		while (inl(dev->iobase + ME4000_AI_CTRL_REG) &
+		       ME4000_AI_STATUS_BIT_EF_DATA) {
 			/* Read value from data fifo */
-			lval = inl(ai_context->data_reg) & 0xFFFF;
+			lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
 			lval ^= 0x8000;
 
 			if (!comedi_buf_put(s->async, lval)) {
-				printk(KERN_ERR
-				       "comedi%d: me4000: me4000_ai_isr(): "
-				       "Buffer overflow\n", dev->minor);
+				dev_err(dev->class_dev, "Buffer overflow\n");
 				s->async->events |= COMEDI_CB_OVERFLOW;
 				break;
 			}
@@ -1543,9 +1255,9 @@
 
 		/* Work is done, so reset the interrupt */
 		tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
-		outl(tmp, ai_context->ctrl_reg);
+		outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 		tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
-		outl(tmp, ai_context->ctrl_reg);
+		outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 	}
 
 	if (s->async->events)
@@ -1562,7 +1274,8 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-
+	const struct me4000_board *thisboard = comedi_board(dev);
+	struct me4000_info *info = dev->private;
 	int chan = CR_CHAN(insn->chanspec);
 	int rang = CR_RANGE(insn->chanspec);
 	int aref = CR_AREF(insn->chanspec);
@@ -1571,46 +1284,39 @@
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ao_insn_write(): "
-		       "Invalid instruction length %d\n", dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid instruction length %d\n",
+			insn->n);
 		return -EINVAL;
 	}
 
-	if (chan >= thisboard->ao.count) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ao_insn_write(): "
-		       "Invalid channel %d\n", dev->minor, insn->n);
+	if (chan >= thisboard->ao_nchan) {
+		dev_err(dev->class_dev, "Invalid channel %d\n", insn->n);
 		return -EINVAL;
 	}
 
 	if (rang != 0) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ao_insn_write(): "
-		       "Invalid range %d\n", dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid range %d\n", insn->n);
 		return -EINVAL;
 	}
 
 	if (aref != AREF_GROUND && aref != AREF_COMMON) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_ao_insn_write(): "
-		       "Invalid aref %d\n", dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid aref %d\n", insn->n);
 		return -EINVAL;
 	}
 
 	/* Stop any running conversion */
-	tmp = inl(info->ao_context[chan].ctrl_reg);
+	tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
 	tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
-	outl(tmp, info->ao_context[chan].ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan));
 
 	/* Clear control register and set to single mode */
-	outl(0x0, info->ao_context[chan].ctrl_reg);
+	outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan));
 
 	/* Write data value */
-	outl(data[0], info->ao_context[chan].single_reg);
+	outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
 
 	/* Store in the mirror */
-	info->ao_context[chan].mirror = data[0];
+	info->ao_readback[chan] = data[0];
 
 	return 1;
 }
@@ -1619,18 +1325,17 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct me4000_info *info = dev->private;
 	int chan = CR_CHAN(insn->chanspec);
 
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
-		printk
-		    ("comedi%d: me4000: me4000_ao_insn_read(): "
-		     "Invalid instruction length\n", dev->minor);
+		dev_err(dev->class_dev, "Invalid instruction length\n");
 		return -EINVAL;
 	}
 
-	data[0] = info->ao_context[chan].mirror;
+	data[0] = info->ao_readback[chan];
 
 	return 1;
 }
@@ -1659,21 +1364,21 @@
 
 		/* Write out the new digital output lines */
 		outl((s->state >> 0) & 0xFF,
-			    info->dio_context.port_0_reg);
+			    dev->iobase + ME4000_DIO_PORT_0_REG);
 		outl((s->state >> 8) & 0xFF,
-			    info->dio_context.port_1_reg);
+			    dev->iobase + ME4000_DIO_PORT_1_REG);
 		outl((s->state >> 16) & 0xFF,
-			    info->dio_context.port_2_reg);
+			    dev->iobase + ME4000_DIO_PORT_2_REG);
 		outl((s->state >> 24) & 0xFF,
-			    info->dio_context.port_3_reg);
+			    dev->iobase + ME4000_DIO_PORT_3_REG);
 	}
 
 	/* On return, data[1] contains the value of
 	   the digital input and output lines. */
-	data[1] = ((inl(info->dio_context.port_0_reg) & 0xFF) << 0) |
-		  ((inl(info->dio_context.port_1_reg) & 0xFF) << 8) |
-		  ((inl(info->dio_context.port_2_reg) & 0xFF) << 16) |
-		  ((inl(info->dio_context.port_3_reg) & 0xFF) << 24);
+	data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
+		  ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
+		  ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
+		  ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
 
 	return insn->n;
 }
@@ -1705,7 +1410,7 @@
 	 * On the ME-4000 it is only possible to switch port wise (8 bit)
 	 */
 
-	tmp = inl(info->dio_context.ctrl_reg);
+	tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
 
 	if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
 		if (chan < 8) {
@@ -1719,7 +1424,7 @@
 			 * If one the first port is a fixed output
 			 * port and the second is a fixed input port.
 			 */
-			if (!inl(info->dio_context.dir_reg))
+			if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
 				return -ENODEV;
 
 			s->io_bits |= 0xFF00;
@@ -1746,7 +1451,7 @@
 			 * If one the first port is a fixed output
 			 * port and the second is a fixed input port.
 			 */
-			if (!inl(info->dio_context.dir_reg))
+			if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
 				return -ENODEV;
 
 			s->io_bits &= ~0xFF;
@@ -1769,7 +1474,7 @@
 		}
 	}
 
-	outl(tmp, info->dio_context.ctrl_reg);
+	outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
 
 	return 1;
 }
@@ -1778,177 +1483,56 @@
   Counter section
   ===========================================================================*/
 
-static int cnt_reset(struct comedi_device *dev, unsigned int channel)
-{
-	switch (channel) {
-	case 0:
-		outb(0x30, info->cnt_context.ctrl_reg);
-		outb(0x00, info->cnt_context.counter_0_reg);
-		outb(0x00, info->cnt_context.counter_0_reg);
-		break;
-	case 1:
-		outb(0x70, info->cnt_context.ctrl_reg);
-		outb(0x00, info->cnt_context.counter_1_reg);
-		outb(0x00, info->cnt_context.counter_1_reg);
-		break;
-	case 2:
-		outb(0xB0, info->cnt_context.ctrl_reg);
-		outb(0x00, info->cnt_context.counter_2_reg);
-		outb(0x00, info->cnt_context.counter_2_reg);
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: cnt_reset(): Invalid channel\n",
-		       dev->minor);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int cnt_config(struct comedi_device *dev, unsigned int channel,
-		      unsigned int mode)
-{
-	int tmp = 0;
-
-	switch (channel) {
-	case 0:
-		tmp |= ME4000_CNT_COUNTER_0;
-		break;
-	case 1:
-		tmp |= ME4000_CNT_COUNTER_1;
-		break;
-	case 2:
-		tmp |= ME4000_CNT_COUNTER_2;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: cnt_config(): Invalid channel\n",
-		       dev->minor);
-		return -EINVAL;
-	}
-
-	switch (mode) {
-	case 0:
-		tmp |= ME4000_CNT_MODE_0;
-		break;
-	case 1:
-		tmp |= ME4000_CNT_MODE_1;
-		break;
-	case 2:
-		tmp |= ME4000_CNT_MODE_2;
-		break;
-	case 3:
-		tmp |= ME4000_CNT_MODE_3;
-		break;
-	case 4:
-		tmp |= ME4000_CNT_MODE_4;
-		break;
-	case 5:
-		tmp |= ME4000_CNT_MODE_5;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: cnt_config(): Invalid counter mode\n",
-		       dev->minor);
-		return -EINVAL;
-	}
-
-	/* Write the control word */
-	tmp |= 0x30;
-	outb(tmp, info->cnt_context.ctrl_reg);
-
-	return 0;
-}
-
 static int me4000_cnt_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-
+	struct me4000_info *info = dev->private;
 	int err;
 
 	switch (data[0]) {
 	case GPCT_RESET:
-		if (insn->n != 1) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_cnt_insn_config(): "
-			       "Invalid instruction length%d\n",
-			       dev->minor, insn->n);
+		if (insn->n != 1)
 			return -EINVAL;
-		}
 
-		err = cnt_reset(dev, insn->chanspec);
+		err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0,
+				I8254_MODE0 | I8254_BINARY);
 		if (err)
 			return err;
 		break;
 	case GPCT_SET_OPERATION:
-		if (insn->n != 2) {
-			printk(KERN_ERR
-			       "comedi%d: me4000: me4000_cnt_insn_config(): "
-			       "Invalid instruction length%d\n",
-			       dev->minor, insn->n);
+		if (insn->n != 2)
 			return -EINVAL;
-		}
 
-		err = cnt_config(dev, insn->chanspec, data[1]);
+		err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec,
+				(data[1] << 1) | I8254_BINARY);
 		if (err)
 			return err;
 		break;
 	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_cnt_insn_config(): "
-		       "Invalid instruction\n", dev->minor);
 		return -EINVAL;
 	}
 
-	return 2;
+	return insn->n;
 }
 
 static int me4000_cnt_insn_read(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-
-	unsigned short tmp;
+	struct me4000_info *info = dev->private;
 
 	if (insn->n == 0)
 		return 0;
 
 	if (insn->n > 1) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_cnt_insn_read(): "
-		       "Invalid instruction length %d\n",
-		       dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid instruction length %d\n",
+			insn->n);
 		return -EINVAL;
 	}
 
-	switch (insn->chanspec) {
-	case 0:
-		tmp = inb(info->cnt_context.counter_0_reg);
-		data[0] = tmp;
-		tmp = inb(info->cnt_context.counter_0_reg);
-		data[0] |= tmp << 8;
-		break;
-	case 1:
-		tmp = inb(info->cnt_context.counter_1_reg);
-		data[0] = tmp;
-		tmp = inb(info->cnt_context.counter_1_reg);
-		data[0] |= tmp << 8;
-		break;
-	case 2:
-		tmp = inb(info->cnt_context.counter_2_reg);
-		data[0] = tmp;
-		tmp = inb(info->cnt_context.counter_2_reg);
-		data[0] |= tmp << 8;
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_cnt_insn_read(): "
-		       "Invalid channel %d\n",
-		       dev->minor, insn->chanspec);
-		return -EINVAL;
-	}
+	data[0] = i8254_read(info->timer_regbase, 0, insn->chanspec);
 
 	return 1;
 }
@@ -1957,57 +1541,71 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
-
-	unsigned short tmp;
+	struct me4000_info *info = dev->private;
 
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_cnt_insn_write(): "
-		       "Invalid instruction length %d\n",
-		       dev->minor, insn->n);
+		dev_err(dev->class_dev, "Invalid instruction length %d\n",
+			insn->n);
 		return -EINVAL;
 	}
 
-	switch (insn->chanspec) {
-	case 0:
-		tmp = data[0] & 0xFF;
-		outb(tmp, info->cnt_context.counter_0_reg);
-		tmp = (data[0] >> 8) & 0xFF;
-		outb(tmp, info->cnt_context.counter_0_reg);
-		break;
-	case 1:
-		tmp = data[0] & 0xFF;
-		outb(tmp, info->cnt_context.counter_1_reg);
-		tmp = (data[0] >> 8) & 0xFF;
-		outb(tmp, info->cnt_context.counter_1_reg);
-		break;
-	case 2:
-		tmp = data[0] & 0xFF;
-		outb(tmp, info->cnt_context.counter_2_reg);
-		tmp = (data[0] >> 8) & 0xFF;
-		outb(tmp, info->cnt_context.counter_2_reg);
-		break;
-	default:
-		printk(KERN_ERR
-		       "comedi%d: me4000: me4000_cnt_insn_write(): "
-		       "Invalid channel %d\n",
-		       dev->minor, insn->chanspec);
-		return -EINVAL;
-	}
+	i8254_write(info->timer_regbase, 0, insn->chanspec, data[0]);
 
 	return 1;
 }
 
-static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static const void *me4000_find_boardinfo(struct comedi_device *dev,
+					 struct pci_dev *pcidev)
 {
+	const struct me4000_board *thisboard;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) {
+		thisboard = &me4000_boards[i];
+		if (thisboard->device_id == pcidev->device)
+			return thisboard;
+	}
+	return NULL;
+}
+
+static int me4000_attach_pci(struct comedi_device *dev,
+			     struct pci_dev *pcidev)
+{
+	const struct me4000_board *thisboard;
+	struct me4000_info *info;
 	struct comedi_subdevice *s;
 	int result;
 
-	result = me4000_probe(dev, it);
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	thisboard = me4000_find_boardinfo(dev, pcidev);
+	if (!thisboard)
+		return -ENODEV;
+	dev->board_ptr = thisboard;
+	dev->board_name = thisboard->name;
+
+	result = alloc_private(dev, sizeof(*info));
 	if (result)
 		return result;
+	info = dev->private;
+
+	result = comedi_pci_enable(pcidev, dev->board_name);
+	if (result)
+		return result;
+
+	info->plx_regbase = pci_resource_start(pcidev, 1);
+	dev->iobase = pci_resource_start(pcidev, 2);
+	info->timer_regbase = pci_resource_start(pcidev, 3);
+	if (!info->plx_regbase || !dev->iobase || !info->timer_regbase)
+		return -ENODEV;
+
+	result = xilinx_download(dev);
+	if (result)
+		return result;
+
+	me4000_reset(dev);
 
 	result = comedi_alloc_subdevices(dev, 4);
 	if (result)
@@ -2017,35 +1615,34 @@
       Analog input subdevice
       ========================================================================*/
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 
-	if (thisboard->ai.count) {
+	if (thisboard->ai_nchan) {
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags =
 		    SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
-		s->n_chan = thisboard->ai.count;
+		s->n_chan = thisboard->ai_nchan;
 		s->maxdata = 0xFFFF;	/*  16 bit ADC */
 		s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
 		s->range_table = &me4000_ai_range;
 		s->insn_read = me4000_ai_insn_read;
 
-		if (info->irq > 0) {
-			if (request_irq(info->irq, me4000_ai_isr,
-					IRQF_SHARED, "ME-4000", dev)) {
-				printk
-				    ("comedi%d: me4000: me4000_attach(): "
-				     "Unable to allocate irq\n", dev->minor);
+		if (pcidev->irq > 0) {
+			if (request_irq(pcidev->irq, me4000_ai_isr,
+					IRQF_SHARED, dev->board_name, dev)) {
+				dev_warn(dev->class_dev,
+					"request_irq failed\n");
 			} else {
 				dev->read_subdev = s;
 				s->subdev_flags |= SDF_CMD_READ;
 				s->cancel = me4000_ai_cancel;
 				s->do_cmdtest = me4000_ai_do_cmd_test;
 				s->do_cmd = me4000_ai_do_cmd;
+
+				dev->irq = pcidev->irq;
 			}
 		} else {
-			printk(KERN_WARNING
-			       "comedi%d: me4000: me4000_attach(): "
-			       "No interrupt available\n", dev->minor);
+			dev_warn(dev->class_dev, "No interrupt available\n");
 		}
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
@@ -2055,14 +1652,14 @@
       Analog output subdevice
       ========================================================================*/
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 
-	if (thisboard->ao.count) {
+	if (thisboard->ao_nchan) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
-		s->n_chan = thisboard->ao.count;
+		s->n_chan = thisboard->ao_nchan;
 		s->maxdata = 0xFFFF;	/*  16 bit DAC */
-		s->range_table = &me4000_ao_range;
+		s->range_table = &range_bipolar10;
 		s->insn_write = me4000_ao_insn_write;
 		s->insn_read = me4000_ao_insn_read;
 	} else {
@@ -2073,12 +1670,12 @@
       Digital I/O subdevice
       ========================================================================*/
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 
-	if (thisboard->dio.count) {
+	if (thisboard->dio_nchan) {
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = thisboard->dio.count * 8;
+		s->n_chan = thisboard->dio_nchan;
 		s->maxdata = 1;
 		s->range_table = &range_digital;
 		s->insn_bits = me4000_dio_insn_bits;
@@ -2091,21 +1688,22 @@
 	 * Check for optoisolated ME-4000 version. If one the first
 	 * port is a fixed output port and the second is a fixed input port.
 	 */
-	if (!inl(info->dio_context.dir_reg)) {
+	if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) {
 		s->io_bits |= 0xFF;
-		outl(ME4000_DIO_CTRL_BIT_MODE_0, info->dio_context.dir_reg);
+		outl(ME4000_DIO_CTRL_BIT_MODE_0,
+			dev->iobase + ME4000_DIO_DIR_REG);
 	}
 
     /*=========================================================================
       Counter subdevice
       ========================================================================*/
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 
-	if (thisboard->cnt.count) {
+	if (thisboard->has_counter) {
 		s->type = COMEDI_SUBD_COUNTER;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = thisboard->cnt.count;
+		s->n_chan = 3;
 		s->maxdata = 0xFFFF;	/*  16 bit counters */
 		s->insn_read = me4000_cnt_insn_read;
 		s->insn_write = me4000_cnt_insn_write;
@@ -2119,12 +1717,14 @@
 
 static void me4000_detach(struct comedi_device *dev)
 {
-	if (info) {
-		if (info->pci_dev_p) {
-			reset_board(dev);
-			if (info->plx_regbase)
-				comedi_pci_disable(info->pci_dev_p);
-			pci_dev_put(info->pci_dev_p);
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (pcidev) {
+		if (dev->iobase) {
+			me4000_reset(dev);
+			comedi_pci_disable(pcidev);
 		}
 	}
 }
@@ -2132,7 +1732,7 @@
 static struct comedi_driver me4000_driver = {
 	.driver_name	= "me4000",
 	.module		= THIS_MODULE,
-	.attach		= me4000_attach,
+	.attach_pci	= me4000_attach_pci,
 	.detach		= me4000_detach,
 };
 
@@ -2148,20 +1748,20 @@
 }
 
 static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
-	{ 0 }
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)},
+	{PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)},
+	{0}
 };
 MODULE_DEVICE_TABLE(pci, me4000_pci_table);
 
diff --git a/drivers/staging/comedi/drivers/me4000.h b/drivers/staging/comedi/drivers/me4000.h
deleted file mode 100644
index 5a4df4e..0000000
--- a/drivers/staging/comedi/drivers/me4000.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
-    me4000.h
-    Register descriptions and defines for the ME-4000 board family
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1998-9 David A. Schleef <ds@schleef.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef _ME4000_H_
-#define _ME4000_H_
-
-/*=============================================================================
-  PCI vendor and device IDs
-  ===========================================================================*/
-
-#define PCI_VENDOR_ID_MEILHAUS 0x1402
-
-#define PCI_DEVICE_ID_MEILHAUS_ME4650	0x4650	/*  Low Cost version */
-
-#define PCI_DEVICE_ID_MEILHAUS_ME4660	0x4660	/*  Standard version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4660I	0x4661	/*  Isolated version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4660S	0x4662	/*  Standard version with Sample and Hold */
-#define PCI_DEVICE_ID_MEILHAUS_ME4660IS	0x4663	/*  Isolated version with Sample and Hold */
-
-#define PCI_DEVICE_ID_MEILHAUS_ME4670	0x4670	/*  Standard version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4670I	0x4671	/*  Isolated version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4670S	0x4672	/*  Standard version with Sample and Hold */
-#define PCI_DEVICE_ID_MEILHAUS_ME4670IS	0x4673	/*  Isolated version with Sample and Hold */
-
-#define PCI_DEVICE_ID_MEILHAUS_ME4680	0x4680	/*  Standard version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4680I	0x4681	/*  Isolated version */
-#define PCI_DEVICE_ID_MEILHAUS_ME4680S	0x4682	/*  Standard version with Sample and Hold */
-#define PCI_DEVICE_ID_MEILHAUS_ME4680IS	0x4683	/*  Isolated version with Sample and Hold */
-
-/*=============================================================================
-  ME-4000 base register offsets
-  ===========================================================================*/
-
-#define ME4000_AO_00_CTRL_REG			0x00	/*  R/W */
-#define ME4000_AO_00_STATUS_REG			0x04	/*  R/_ */
-#define ME4000_AO_00_FIFO_REG			0x08	/*  _/W */
-#define ME4000_AO_00_SINGLE_REG			0x0C	/*  R/W */
-#define ME4000_AO_00_TIMER_REG			0x10	/*  _/W */
-
-#define ME4000_AO_01_CTRL_REG			0x18	/*  R/W */
-#define ME4000_AO_01_STATUS_REG			0x1C	/*  R/_ */
-#define ME4000_AO_01_FIFO_REG			0x20	/*  _/W */
-#define ME4000_AO_01_SINGLE_REG			0x24	/*  R/W */
-#define ME4000_AO_01_TIMER_REG			0x28	/*  _/W */
-
-#define ME4000_AO_02_CTRL_REG			0x30	/*  R/W */
-#define ME4000_AO_02_STATUS_REG			0x34	/*  R/_ */
-#define ME4000_AO_02_FIFO_REG			0x38	/*  _/W */
-#define ME4000_AO_02_SINGLE_REG			0x3C	/*  R/W */
-#define ME4000_AO_02_TIMER_REG			0x40	/*  _/W */
-
-#define ME4000_AO_03_CTRL_REG			0x48	/*  R/W */
-#define ME4000_AO_03_STATUS_REG			0x4C	/*  R/_ */
-#define ME4000_AO_03_FIFO_REG			0x50	/*  _/W */
-#define ME4000_AO_03_SINGLE_REG			0x54	/*  R/W */
-#define ME4000_AO_03_TIMER_REG			0x58	/*  _/W */
-
-#define ME4000_AI_CTRL_REG			0x74	/*  _/W */
-#define ME4000_AI_STATUS_REG			0x74	/*  R/_ */
-#define ME4000_AI_CHANNEL_LIST_REG		0x78	/*  _/W */
-#define ME4000_AI_DATA_REG			0x7C	/*  R/_ */
-#define ME4000_AI_CHAN_TIMER_REG		0x80	/*  _/W */
-#define ME4000_AI_CHAN_PRE_TIMER_REG		0x84	/*  _/W */
-#define ME4000_AI_SCAN_TIMER_LOW_REG		0x88	/*  _/W */
-#define ME4000_AI_SCAN_TIMER_HIGH_REG		0x8C	/*  _/W */
-#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG	0x90	/*  _/W */
-#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG	0x94	/*  _/W */
-#define ME4000_AI_START_REG			0x98	/*  R/_ */
-
-#define ME4000_IRQ_STATUS_REG			0x9C	/*  R/_ */
-
-#define ME4000_DIO_PORT_0_REG			0xA0	/*  R/W */
-#define ME4000_DIO_PORT_1_REG			0xA4	/*  R/W */
-#define ME4000_DIO_PORT_2_REG			0xA8	/*  R/W */
-#define ME4000_DIO_PORT_3_REG			0xAC	/*  R/W */
-#define ME4000_DIO_DIR_REG			0xB0	/*  R/W */
-
-#define ME4000_AO_LOADSETREG_XX			0xB4	/*  R/W */
-
-#define ME4000_DIO_CTRL_REG			0xB8	/*  R/W */
-
-#define ME4000_AO_DEMUX_ADJUST_REG		0xBC	/*  -/W */
-
-#define ME4000_AI_SAMPLE_COUNTER_REG		0xC0	/*  _/W */
-
-/*=============================================================================
-  Value to adjust Demux
-  ===========================================================================*/
-
-#define ME4000_AO_DEMUX_ADJUST_VALUE            0x4C
-
-/*=============================================================================
-  Counter base register offsets
-  ===========================================================================*/
-
-#define ME4000_CNT_COUNTER_0_REG		0x00
-#define ME4000_CNT_COUNTER_1_REG		0x01
-#define ME4000_CNT_COUNTER_2_REG		0x02
-#define ME4000_CNT_CTRL_REG			0x03
-
-/*=============================================================================
-  PLX base register offsets
-  ===========================================================================*/
-
-#define PLX_INTCSR	0x4C	/*  Interrupt control and status register */
-#define PLX_ICR		0x50	/*  Initialization control register */
-
-/*=============================================================================
-  Bits for the PLX_ICSR register
-  ===========================================================================*/
-
-#define PLX_INTCSR_LOCAL_INT1_EN             0x01	/*  If set, local interrupt 1 is enabled (r/w) */
-#define PLX_INTCSR_LOCAL_INT1_POL            0x02	/*  If set, local interrupt 1 polarity is active high (r/w) */
-#define PLX_INTCSR_LOCAL_INT1_STATE          0x04	/*  If set, local interrupt 1 is active (r/_) */
-#define PLX_INTCSR_LOCAL_INT2_EN             0x08	/*  If set, local interrupt 2 is enabled (r/w) */
-#define PLX_INTCSR_LOCAL_INT2_POL            0x10	/*  If set, local interrupt 2 polarity is active high (r/w) */
-#define PLX_INTCSR_LOCAL_INT2_STATE          0x20	/*  If set, local interrupt 2 is active  (r/_) */
-#define PLX_INTCSR_PCI_INT_EN                0x40	/*  If set, PCI interrupt is enabled (r/w) */
-#define PLX_INTCSR_SOFT_INT                  0x80	/*  If set, a software interrupt is generated (r/w) */
-
-/*=============================================================================
-  Bits for the PLX_ICR register
-  ===========================================================================*/
-
-#define PLX_ICR_BIT_EEPROM_CLOCK_SET		0x01000000
-#define PLX_ICR_BIT_EEPROM_CHIP_SELECT		0x02000000
-#define PLX_ICR_BIT_EEPROM_WRITE		0x04000000
-#define PLX_ICR_BIT_EEPROM_READ			0x08000000
-#define PLX_ICR_BIT_EEPROM_VALID		0x10000000
-
-#define PLX_ICR_MASK_EEPROM			0x1F000000
-
-#define EEPROM_DELAY				1
-
-/*=============================================================================
-  Bits for the ME4000_AO_CTRL_REG register
-  ===========================================================================*/
-
-#define ME4000_AO_CTRL_BIT_MODE_0		0x001
-#define ME4000_AO_CTRL_BIT_MODE_1		0x002
-#define ME4000_AO_CTRL_MASK_MODE		0x003
-#define ME4000_AO_CTRL_BIT_STOP			0x004
-#define ME4000_AO_CTRL_BIT_ENABLE_FIFO		0x008
-#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG	0x010
-#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE		0x020
-#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP	0x080
-#define ME4000_AO_CTRL_BIT_ENABLE_DO		0x100
-#define ME4000_AO_CTRL_BIT_ENABLE_IRQ		0x200
-#define ME4000_AO_CTRL_BIT_RESET_IRQ		0x400
-
-/*=============================================================================
-  Bits for the ME4000_AO_STATUS_REG register
-  ===========================================================================*/
-
-#define ME4000_AO_STATUS_BIT_FSM		0x01
-#define ME4000_AO_STATUS_BIT_FF			0x02
-#define ME4000_AO_STATUS_BIT_HF			0x04
-#define ME4000_AO_STATUS_BIT_EF			0x08
-
-/*=============================================================================
-  Bits for the ME4000_AI_CTRL_REG register
-  ===========================================================================*/
-
-#define ME4000_AI_CTRL_BIT_MODE_0		0x00000001
-#define ME4000_AI_CTRL_BIT_MODE_1		0x00000002
-#define ME4000_AI_CTRL_BIT_MODE_2		0x00000004
-#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD		0x00000008
-#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP	0x00000010
-#define ME4000_AI_CTRL_BIT_STOP			0x00000020
-#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO		0x00000040
-#define ME4000_AI_CTRL_BIT_DATA_FIFO		0x00000080
-#define ME4000_AI_CTRL_BIT_FULLSCALE		0x00000100
-#define ME4000_AI_CTRL_BIT_OFFSET		0x00000200
-#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG	0x00000400
-#define ME4000_AI_CTRL_BIT_EX_TRIG		0x00000800
-#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING	0x00001000
-#define ME4000_AI_CTRL_BIT_EX_IRQ		0x00002000
-#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET		0x00004000
-#define ME4000_AI_CTRL_BIT_LE_IRQ		0x00008000
-#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET		0x00010000
-#define ME4000_AI_CTRL_BIT_HF_IRQ		0x00020000
-#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET		0x00040000
-#define ME4000_AI_CTRL_BIT_SC_IRQ		0x00080000
-#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET		0x00100000
-#define ME4000_AI_CTRL_BIT_SC_RELOAD		0x00200000
-#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH		0x80000000
-
-/*=============================================================================
-  Bits for the ME4000_AI_STATUS_REG register
-  ===========================================================================*/
-
-#define ME4000_AI_STATUS_BIT_EF_CHANNEL		0x00400000
-#define ME4000_AI_STATUS_BIT_HF_CHANNEL		0x00800000
-#define ME4000_AI_STATUS_BIT_FF_CHANNEL		0x01000000
-#define ME4000_AI_STATUS_BIT_EF_DATA		0x02000000
-#define ME4000_AI_STATUS_BIT_HF_DATA		0x04000000
-#define ME4000_AI_STATUS_BIT_FF_DATA		0x08000000
-#define ME4000_AI_STATUS_BIT_LE			0x10000000
-#define ME4000_AI_STATUS_BIT_FSM		0x20000000
-
-/*=============================================================================
-  Bits for the ME4000_IRQ_STATUS_REG register
-  ===========================================================================*/
-
-#define ME4000_IRQ_STATUS_BIT_EX		0x01
-#define ME4000_IRQ_STATUS_BIT_LE		0x02
-#define ME4000_IRQ_STATUS_BIT_AI_HF		0x04
-#define ME4000_IRQ_STATUS_BIT_AO_0_HF		0x08
-#define ME4000_IRQ_STATUS_BIT_AO_1_HF		0x10
-#define ME4000_IRQ_STATUS_BIT_AO_2_HF		0x20
-#define ME4000_IRQ_STATUS_BIT_AO_3_HF		0x40
-#define ME4000_IRQ_STATUS_BIT_SC		0x80
-
-/*=============================================================================
-  Bits for the ME4000_DIO_CTRL_REG register
-  ===========================================================================*/
-
-#define ME4000_DIO_CTRL_BIT_MODE_0		0x0001
-#define ME4000_DIO_CTRL_BIT_MODE_1		0x0002
-#define ME4000_DIO_CTRL_BIT_MODE_2		0x0004
-#define ME4000_DIO_CTRL_BIT_MODE_3		0x0008
-#define ME4000_DIO_CTRL_BIT_MODE_4		0x0010
-#define ME4000_DIO_CTRL_BIT_MODE_5		0x0020
-#define ME4000_DIO_CTRL_BIT_MODE_6		0x0040
-#define ME4000_DIO_CTRL_BIT_MODE_7		0x0080
-
-#define ME4000_DIO_CTRL_BIT_FUNCTION_0		0x0100
-#define ME4000_DIO_CTRL_BIT_FUNCTION_1		0x0200
-
-#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0		0x0400
-#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1		0x0800
-#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2		0x1000
-#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3		0x2000
-
-/*=============================================================================
-  Information about the hardware capabilities
-  ===========================================================================*/
-
-struct me4000_ao_info {
-	int count;
-	int fifo_count;
-};
-
-struct me4000_ai_info {
-	int count;
-	int sh_count;
-	int diff_count;
-	int ex_trig_analog;
-};
-
-struct me4000_dio_info {
-	int count;
-};
-
-struct me4000_cnt_info {
-	int count;
-};
-
-struct me4000_board {
-	const char *name;
-	unsigned short device_id;
-	struct me4000_ao_info ao;
-	struct me4000_ai_info ai;
-	struct me4000_dio_info dio;
-	struct me4000_cnt_info cnt;
-};
-
-#define thisboard ((const struct me4000_board *)dev->board_ptr)
-
-/*=============================================================================
-  Global board and subdevice information structures
-  ===========================================================================*/
-
-struct me4000_ao_context {
-	int irq;
-
-	unsigned long mirror;	/*  Store the last written value */
-
-	unsigned long ctrl_reg;
-	unsigned long status_reg;
-	unsigned long fifo_reg;
-	unsigned long single_reg;
-	unsigned long timer_reg;
-	unsigned long irq_status_reg;
-	unsigned long preload_reg;
-};
-
-struct me4000_ai_context {
-	int irq;
-
-	unsigned long ctrl_reg;
-	unsigned long status_reg;
-	unsigned long channel_list_reg;
-	unsigned long data_reg;
-	unsigned long chan_timer_reg;
-	unsigned long chan_pre_timer_reg;
-	unsigned long scan_timer_low_reg;
-	unsigned long scan_timer_high_reg;
-	unsigned long scan_pre_timer_low_reg;
-	unsigned long scan_pre_timer_high_reg;
-	unsigned long start_reg;
-	unsigned long irq_status_reg;
-	unsigned long sample_counter_reg;
-};
-
-struct me4000_dio_context {
-	unsigned long dir_reg;
-	unsigned long ctrl_reg;
-	unsigned long port_0_reg;
-	unsigned long port_1_reg;
-	unsigned long port_2_reg;
-	unsigned long port_3_reg;
-};
-
-struct me4000_cnt_context {
-	unsigned long ctrl_reg;
-	unsigned long counter_0_reg;
-	unsigned long counter_1_reg;
-	unsigned long counter_2_reg;
-};
-
-struct me4000_info {
-	unsigned long plx_regbase;	/*  PLX configuration space base address */
-	unsigned long me4000_regbase;	/*  Base address of the ME4000 */
-	unsigned long timer_regbase;	/*  Base address of the timer circuit */
-	unsigned long program_regbase;	/*  Base address to set the program pin for the xilinx */
-
-	unsigned long plx_regbase_size;	/*  PLX register set space */
-	unsigned long me4000_regbase_size;	/*  ME4000 register set space */
-	unsigned long timer_regbase_size;	/*  Timer circuit register set space */
-	unsigned long program_regbase_size;	/*  Size of program base address of the ME4000 */
-
-	unsigned int serial_no;	/*  Serial number of the board */
-	unsigned char hw_revision;	/*  Hardware revision of the board */
-	unsigned short vendor_id;	/*  Meilhaus vendor id */
-	unsigned short device_id;	/*  Device id */
-
-	struct pci_dev *pci_dev_p;	/*  General PCI information */
-
-	unsigned int irq;	/*  IRQ assigned from the PCI BIOS */
-
-	struct me4000_ai_context ai_context;	/*  Analog input  specific context */
-	struct me4000_ao_context ao_context[4];	/*  Vector with analog output specific context */
-	struct me4000_dio_context dio_context;	/*  Digital I/O specific context */
-	struct me4000_cnt_context cnt_context;	/*  Counter specific context */
-};
-
-#define info	((struct me4000_info *)dev->private)
-
-/*-----------------------------------------------------------------------------
-  Defines for analog input
- ----------------------------------------------------------------------------*/
-
-/* General stuff */
-#define ME4000_AI_FIFO_COUNT			2048
-
-#define ME4000_AI_MIN_TICKS			66
-#define ME4000_AI_MIN_SAMPLE_TIME		2000	/*  Minimum sample time [ns] */
-#define ME4000_AI_BASE_FREQUENCY		(unsigned int) 33E6
-
-/* Channel list defines and masks */
-#define ME4000_AI_CHANNEL_LIST_COUNT		1024
-
-#define ME4000_AI_LIST_INPUT_SINGLE_ENDED	0x000
-#define ME4000_AI_LIST_INPUT_DIFFERENTIAL	0x020
-
-#define ME4000_AI_LIST_RANGE_BIPOLAR_10		0x000
-#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5	0x040
-#define ME4000_AI_LIST_RANGE_UNIPOLAR_10	0x080
-#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5	0x0C0
-
-#define ME4000_AI_LIST_LAST_ENTRY		0x100
-
-/*-----------------------------------------------------------------------------
-  Defines for counters
- ----------------------------------------------------------------------------*/
-
-#define ME4000_CNT_COUNTER_0  0x00
-#define ME4000_CNT_COUNTER_1  0x40
-#define ME4000_CNT_COUNTER_2  0x80
-
-#define ME4000_CNT_MODE_0     0x00	/*  Change state if zero crossing */
-#define ME4000_CNT_MODE_1     0x02	/*  Retriggerable One-Shot */
-#define ME4000_CNT_MODE_2     0x04	/*  Asymmetrical divider */
-#define ME4000_CNT_MODE_3     0x06	/*  Symmetrical divider */
-#define ME4000_CNT_MODE_4     0x08	/*  Counter start by software trigger */
-#define ME4000_CNT_MODE_5     0x0A	/*  Counter start by hardware trigger */
-
-#endif
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 8c6f8b9..2ce0b14 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -41,22 +41,14 @@
 
     If bus/slot is not specified, the first available PCI
     device will be used.
-
-The 2600 requires a firmware upload, which can be accomplished
-using the -i or --init-data option of comedi_config.
-The firmware can be
-found in the comedi_nonfree_firmware tarball available
-from http://www.comedi.org
-
 */
 
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/firmware.h>
 #include "../comedidev.h"
 
-/*#include "me2600_fw.h" */
-
-#define ME_DRIVER_NAME		"me_daq"
+#define ME2600_FIRMWARE		"me2600_firmware.bin"
 
 #define PCI_VENDOR_ID_MEILHAUS	0x1402
 #define ME2000_DEVICE_ID	0x2000
@@ -198,8 +190,7 @@
 
 static const struct me_board me_boards[] = {
 	{
-	 /* -- ME-2600i -- */
-	 .name = ME_DRIVER_NAME,
+	 .name = "me-2600i",
 	 .device_id = ME2600_DEVICE_ID,
 	 /* Analog Output */
 	 .ao_channel_nbr = 4,
@@ -214,8 +205,7 @@
 	 .dio_channel_nbr = 32,
 	 },
 	{
-	 /* -- ME-2000i -- */
-	 .name = ME_DRIVER_NAME,
+	 .name = "me-2000i",
 	 .device_id = ME2000_DEVICE_ID,
 	 /* Analog Output */
 	 .ao_channel_nbr = 0,
@@ -341,7 +331,7 @@
 
 /* Analog instant input */
 static int me_ai_insn_read(struct comedi_device *dev,
-			   struct comedi_subdevice *subdevice,
+			   struct comedi_subdevice *s,
 			   struct comedi_insn *insn, unsigned int *data)
 {
 	unsigned short value;
@@ -435,7 +425,7 @@
 
 /* Analog input command */
 static int me_ai_do_cmd(struct comedi_device *dev,
-			struct comedi_subdevice *subdevice)
+			struct comedi_subdevice *s)
 {
 	return 0;
 }
@@ -524,8 +514,7 @@
 
 /* Xilinx firmware download for card: ME-2600i */
 static int me2600_xilinx_download(struct comedi_device *dev,
-				  unsigned char *me2600_firmware,
-				  unsigned int length)
+				  const u8 *data, size_t size)
 {
 	unsigned int value;
 	unsigned int file_length;
@@ -552,19 +541,20 @@
 	 * Byte 8-11:  date
 	 * Byte 12-15: reserved
 	 */
-	if (length < 16)
+	if (size < 16)
 		return -EINVAL;
-	file_length = (((unsigned int)me2600_firmware[0] & 0xff) << 24) +
-	    (((unsigned int)me2600_firmware[1] & 0xff) << 16) +
-	    (((unsigned int)me2600_firmware[2] & 0xff) << 8) +
-	    ((unsigned int)me2600_firmware[3] & 0xff);
+
+	file_length = (((unsigned int)data[0] & 0xff) << 24) +
+	    (((unsigned int)data[1] & 0xff) << 16) +
+	    (((unsigned int)data[2] & 0xff) << 8) +
+	    ((unsigned int)data[3] & 0xff);
 
 	/*
 	 * Loop for writing firmware byte by byte to xilinx
 	 * Firmware data start at offfset 16
 	 */
 	for (i = 0; i < file_length; i++)
-		writeb((me2600_firmware[16 + i] & 0xff),
+		writeb((data[16 + i] & 0xff),
 		       dev_private->me_regbase + 0x0);
 
 	/* Write 5 dummy values to xilinx */
@@ -590,6 +580,22 @@
 	return 0;
 }
 
+static int me2600_upload_firmware(struct comedi_device *dev)
+{
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	const struct firmware *fw;
+	int ret;
+
+	ret = request_firmware(&fw, ME2600_FIRMWARE, &pcidev->dev);
+	if (ret)
+		return ret;
+
+	ret = me2600_xilinx_download(dev, fw->data, fw->size);
+	release_firmware(fw);
+
+	return ret;
+}
+
 /* Reset device */
 static int me_reset(struct comedi_device *dev)
 {
@@ -607,44 +613,24 @@
 	return 0;
 }
 
-static struct pci_dev *me_find_pci_dev(struct comedi_device *dev,
-				       struct comedi_devconfig *it)
+static const void *me_find_boardinfo(struct comedi_device *dev,
+				     struct pci_dev *pcidev)
 {
 	const struct me_board *board;
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
 	int i;
 
-	for_each_pci_dev(pcidev) {
-		if (bus || slot) {
-			if (pcidev->bus->number != bus ||
-			    PCI_SLOT(pcidev->devfn) != slot)
-				continue;
-		}
-		if (pcidev->vendor != PCI_VENDOR_ID_MEILHAUS)
-			continue;
-
-		for (i = 0; i < ARRAY_SIZE(me_boards); i++) {
-			board = &me_boards[i];
-			if (board->device_id != pcidev->device)
-				continue;
-
-			dev->board_ptr = board;
-			return pcidev;
-		}
+	for (i = 0; i < ARRAY_SIZE(me_boards); i++) {
+		board = &me_boards[i];
+		if (board->device_id == pcidev->device)
+			return board;
 	}
-	dev_err(dev->class_dev,
-		"No supported board found! (req. bus %d, slot %d)\n",
-		bus, slot);
 	return NULL;
 }
 
-static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int me_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev)
 {
-	struct pci_dev *pci_device;
-	struct comedi_subdevice *subdevice;
-	struct me_board *board;
+	const struct me_board *board;
+	struct comedi_subdevice *s;
 	resource_size_t plx_regbase_tmp;
 	unsigned long plx_regbase_size_tmp;
 	resource_size_t me_regbase_tmp;
@@ -654,29 +640,28 @@
 	resource_size_t regbase_tmp;
 	int result, error;
 
+	comedi_set_hw_dev(dev, &pcidev->dev);
+
+	board = me_find_boardinfo(dev, pcidev);
+	if (!board)
+		return -ENODEV;
+	dev->board_ptr = board;
+	dev->board_name = board->name;
+
 	/* Allocate private memory */
 	if (alloc_private(dev, sizeof(struct me_private_data)) < 0)
 		return -ENOMEM;
 
-	pci_device = me_find_pci_dev(dev, it);
-	if (!pci_device)
-		return -EIO;
-	comedi_set_hw_dev(dev, &pci_device->dev);
-	board = (struct me_board *)dev->board_ptr;
-
 	/* Enable PCI device and request PCI regions */
-	if (comedi_pci_enable(pci_device, ME_DRIVER_NAME) < 0) {
+	if (comedi_pci_enable(pcidev, dev->board_name) < 0) {
 		printk(KERN_ERR "comedi%d: Failed to enable PCI device and "
 		       "request regions\n", dev->minor);
 		return -EIO;
 	}
 
-	/* Set data in device structure */
-	dev->board_name = board->name;
-
 	/* Read PLX register base address [PCI_BASE_ADDRESS #0]. */
-	plx_regbase_tmp = pci_resource_start(pci_device, 0);
-	plx_regbase_size_tmp = pci_resource_len(pci_device, 0);
+	plx_regbase_tmp = pci_resource_start(pcidev, 0);
+	plx_regbase_size_tmp = pci_resource_len(pcidev, 0);
 	dev_private->plx_regbase =
 	    ioremap(plx_regbase_tmp, plx_regbase_size_tmp);
 	dev_private->plx_regbase_size = plx_regbase_size_tmp;
@@ -687,8 +672,8 @@
 
 	/* Read Swap base address [PCI_BASE_ADDRESS #5]. */
 
-	swap_regbase_tmp = pci_resource_start(pci_device, 5);
-	swap_regbase_size_tmp = pci_resource_len(pci_device, 5);
+	swap_regbase_tmp = pci_resource_start(pcidev, 5);
+	swap_regbase_size_tmp = pci_resource_len(pcidev, 5);
 
 	if (!swap_regbase_tmp)
 		printk(KERN_ERR "comedi%d: Swap not present\n", dev->minor);
@@ -702,20 +687,20 @@
 			plx_regbase_tmp = swap_regbase_tmp;
 			swap_regbase_tmp = regbase_tmp;
 
-			result = pci_write_config_dword(pci_device,
+			result = pci_write_config_dword(pcidev,
 							PCI_BASE_ADDRESS_0,
 							plx_regbase_tmp);
 			if (result != PCIBIOS_SUCCESSFUL)
 				return -EIO;
 
-			result = pci_write_config_dword(pci_device,
+			result = pci_write_config_dword(pcidev,
 							PCI_BASE_ADDRESS_5,
 							swap_regbase_tmp);
 			if (result != PCIBIOS_SUCCESSFUL)
 				return -EIO;
 		} else {
 			plx_regbase_tmp -= 0x80;
-			result = pci_write_config_dword(pci_device,
+			result = pci_write_config_dword(pcidev,
 							PCI_BASE_ADDRESS_0,
 							plx_regbase_tmp);
 			if (result != PCIBIOS_SUCCESSFUL)
@@ -726,8 +711,8 @@
 
 	/* Read Meilhaus register base address [PCI_BASE_ADDRESS #2]. */
 
-	me_regbase_tmp = pci_resource_start(pci_device, 2);
-	me_regbase_size_tmp = pci_resource_len(pci_device, 2);
+	me_regbase_tmp = pci_resource_start(pcidev, 2);
+	me_regbase_size_tmp = pci_resource_len(pcidev, 2);
 	dev_private->me_regbase_size = me_regbase_size_tmp;
 	dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp);
 	if (!dev_private->me_regbase) {
@@ -735,64 +720,55 @@
 		       dev->minor);
 		return -ENOMEM;
 	}
+
 	/* Download firmware and reset card */
 	if (board->device_id == ME2600_DEVICE_ID) {
-		unsigned char *aux_data;
-		int aux_len;
-
-		aux_data = comedi_aux_data(it->options, 0);
-		aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-
-		if (!aux_data || aux_len < 1) {
-			comedi_error(dev, "You must provide me2600 firmware "
-				     "using the --init-data option of "
-				     "comedi_config");
-			return -EINVAL;
-		}
-		me2600_xilinx_download(dev, aux_data, aux_len);
+		result = me2600_upload_firmware(dev);
+		if (result < 0)
+			return result;
 	}
-
 	me_reset(dev);
 
 	error = comedi_alloc_subdevices(dev, 3);
 	if (error)
 		return error;
 
-	subdevice = dev->subdevices + 0;
-	subdevice->type = COMEDI_SUBD_AI;
-	subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
-	subdevice->n_chan = board->ai_channel_nbr;
-	subdevice->maxdata = board->ai_resolution_mask;
-	subdevice->len_chanlist = board->ai_channel_nbr;
-	subdevice->range_table = board->ai_range_list;
-	subdevice->cancel = me_ai_cancel;
-	subdevice->insn_read = me_ai_insn_read;
-	subdevice->do_cmdtest = me_ai_do_cmd_test;
-	subdevice->do_cmd = me_ai_do_cmd;
+	s = &dev->subdevices[0];
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
+	s->n_chan = board->ai_channel_nbr;
+	s->maxdata = board->ai_resolution_mask;
+	s->len_chanlist = board->ai_channel_nbr;
+	s->range_table = board->ai_range_list;
+	s->cancel = me_ai_cancel;
+	s->insn_read = me_ai_insn_read;
+	s->do_cmdtest = me_ai_do_cmd_test;
+	s->do_cmd = me_ai_do_cmd;
 
-	subdevice = dev->subdevices + 1;
-	subdevice->type = COMEDI_SUBD_AO;
-	subdevice->subdev_flags = SDF_WRITEABLE | SDF_COMMON;
-	subdevice->n_chan = board->ao_channel_nbr;
-	subdevice->maxdata = board->ao_resolution_mask;
-	subdevice->len_chanlist = board->ao_channel_nbr;
-	subdevice->range_table = board->ao_range_list;
-	subdevice->insn_read = me_ao_insn_read;
-	subdevice->insn_write = me_ao_insn_write;
+	s = &dev->subdevices[1];
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITEABLE | SDF_COMMON;
+	s->n_chan = board->ao_channel_nbr;
+	s->maxdata = board->ao_resolution_mask;
+	s->len_chanlist = board->ao_channel_nbr;
+	s->range_table = board->ao_range_list;
+	s->insn_read = me_ao_insn_read;
+	s->insn_write = me_ao_insn_write;
 
-	subdevice = dev->subdevices + 2;
-	subdevice->type = COMEDI_SUBD_DIO;
-	subdevice->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
-	subdevice->n_chan = board->dio_channel_nbr;
-	subdevice->maxdata = 1;
-	subdevice->len_chanlist = board->dio_channel_nbr;
-	subdevice->range_table = &range_digital;
-	subdevice->insn_bits = me_dio_insn_bits;
-	subdevice->insn_config = me_dio_insn_config;
-	subdevice->io_bits = 0;
+	s = &dev->subdevices[2];
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
+	s->n_chan = board->dio_channel_nbr;
+	s->maxdata = 1;
+	s->len_chanlist = board->dio_channel_nbr;
+	s->range_table = &range_digital;
+	s->insn_bits = me_dio_insn_bits;
+	s->insn_config = me_dio_insn_config;
+	s->io_bits = 0;
 
-	printk(KERN_INFO "comedi%d: " ME_DRIVER_NAME " attached.\n",
-	       dev->minor);
+	dev_info(dev->class_dev, "%s: %s attached\n",
+		dev->driver->driver_name, dev->board_name);
+
 	return 0;
 }
 
@@ -818,7 +794,7 @@
 static struct comedi_driver me_daq_driver = {
 	.driver_name	= "me_daq",
 	.module		= THIS_MODULE,
-	.attach		= me_attach,
+	.attach_pci	= me_attach_pci,
 	.detach		= me_detach,
 };
 
@@ -851,3 +827,4 @@
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(ME2600_FIRMWARE);
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index a93166d..e27850f 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -49,6 +49,8 @@
 
 /* #define USE_KMALLOC */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "mite.h"
 
 #include "comedi_fc.h"
@@ -59,52 +61,38 @@
 #define PCI_DAQ_SIZE		4096
 #define PCI_DAQ_SIZE_660X       8192
 
-struct mite_struct *mite_devices;
-EXPORT_SYMBOL(mite_devices);
-
 #define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK)))
 
-void mite_init(void)
+struct mite_struct *mite_alloc(struct pci_dev *pcidev)
 {
-	struct pci_dev *pcidev = NULL;
 	struct mite_struct *mite;
+	unsigned int i;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_NI) {
-			unsigned i;
-
-			mite = kzalloc(sizeof(*mite), GFP_KERNEL);
-			if (!mite) {
-				printk(KERN_ERR "mite: allocation failed\n");
-				pci_dev_put(pcidev);
-				return;
-			}
-			spin_lock_init(&mite->lock);
-			mite->pcidev = pci_dev_get(pcidev);
-			for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) {
-				mite->channels[i].mite = mite;
-				mite->channels[i].channel = i;
-				mite->channels[i].done = 1;
-			}
-			mite->next = mite_devices;
-			mite_devices = mite;
+	mite = kzalloc(sizeof(*mite), GFP_KERNEL);
+	if (mite) {
+		spin_lock_init(&mite->lock);
+		mite->pcidev = pcidev;
+		for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) {
+			mite->channels[i].mite = mite;
+			mite->channels[i].channel = i;
+			mite->channels[i].done = 1;
 		}
 	}
+	return mite;
 }
+EXPORT_SYMBOL(mite_alloc);
 
 static void dump_chip_signature(u32 csigr_bits)
 {
-	printk(KERN_INFO "mite: version = %i, type = %i, mite mode = %i,"
-	       "interface mode = %i\n",
-	       mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits),
-	       mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits));
-	printk(KERN_INFO "mite: num channels = %i, write post fifo depth = %i,"
-	       "wins = %i, iowins = %i\n",
-	       mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits),
-	       mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits));
+	pr_info("version = %i, type = %i, mite mode = %i, interface mode = %i\n",
+		mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits),
+		mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits));
+	pr_info("num channels = %i, write post fifo depth = %i, wins = %i, iowins = %i\n",
+		mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits),
+		mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits));
 }
 
-unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel)
+static unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel)
 {
 	unsigned fcr_bits = readl(mite->mite_io_addr + MITE_FCR(channel));
 	unsigned empty_count = (fcr_bits >> 16) & 0xff;
@@ -121,7 +109,8 @@
 	unsigned unknown_dma_burst_bits;
 
 	if (comedi_pci_enable(mite->pcidev, "mite")) {
-		printk(KERN_ERR "error enabling mite and requesting io regions\n");
+		dev_err(&mite->pcidev->dev,
+			"error enabling mite and requesting io regions\n");
 		return -EIO;
 	}
 	pci_set_master(mite->pcidev);
@@ -130,11 +119,10 @@
 	mite->mite_phys_addr = addr;
 	mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE);
 	if (!mite->mite_io_addr) {
-		printk(KERN_ERR "Failed to remap mite io memory address\n");
+		dev_err(&mite->pcidev->dev,
+			"Failed to remap mite io memory address\n");
 		return -ENOMEM;
 	}
-	printk(KERN_INFO "MITE:0x%08llx mapped to %p ",
-	       (unsigned long long)mite->mite_phys_addr, mite->mite_io_addr);
 
 	addr = pci_resource_start(mite->pcidev, 1);
 	mite->daq_phys_addr = addr;
@@ -145,15 +133,15 @@
 	 */
 	mite->daq_io_addr = ioremap(mite->daq_phys_addr, length);
 	if (!mite->daq_io_addr) {
-		printk(KERN_ERR "Failed to remap daq io memory address\n");
+		dev_err(&mite->pcidev->dev,
+			"Failed to remap daq io memory address\n");
 		return -ENOMEM;
 	}
-	printk(KERN_INFO "DAQ:0x%08llx mapped to %p\n",
-	       (unsigned long long)mite->daq_phys_addr, mite->daq_io_addr);
 
 	if (use_iodwbsr_1) {
 		writel(0, mite->mite_io_addr + MITE_IODWBSR);
-		printk(KERN_INFO "mite: using I/O Window Base Size register 1\n");
+		dev_info(&mite->pcidev->dev,
+			 "using I/O Window Base Size register 1\n");
 		writel(mite->daq_phys_addr | WENAB |
 		       MITE_IODWBSR_1_WSIZE_bits(length),
 		       mite->mite_io_addr + MITE_IODWBSR_1);
@@ -178,9 +166,9 @@
 	csigr_bits = readl(mite->mite_io_addr + MITE_CSIGR);
 	mite->num_channels = mite_csigr_dmac(csigr_bits);
 	if (mite->num_channels > MAX_MITE_DMA_CHANNELS) {
-		printk(KERN_WARNING "mite: bug? chip claims to have %i dma "
-		       "channels. Setting to %i.\n",
-		       mite->num_channels, MAX_MITE_DMA_CHANNELS);
+		dev_warn(&mite->pcidev->dev,
+			 "mite: bug? chip claims to have %i dma channels. Setting to %i.\n",
+			 mite->num_channels, MAX_MITE_DMA_CHANNELS);
 		mite->num_channels = MAX_MITE_DMA_CHANNELS;
 	}
 	dump_chip_signature(csigr_bits);
@@ -193,9 +181,7 @@
 		       mite->mite_io_addr + MITE_CHCR(i));
 	}
 	mite->fifo_size = mite_fifo_size(mite, 0);
-	printk(KERN_INFO "mite: fifo size is %i.\n", mite->fifo_size);
-	mite->used = 1;
-
+	dev_info(&mite->pcidev->dev, "fifo size is %i.\n", mite->fifo_size);
 	return 0;
 }
 EXPORT_SYMBOL(mite_setup2);
@@ -206,17 +192,6 @@
 }
 EXPORT_SYMBOL(mite_setup);
 
-void mite_cleanup(void)
-{
-	struct mite_struct *mite, *next;
-
-	for (mite = mite_devices; mite; mite = next) {
-		pci_dev_put(mite->pcidev);
-		next = mite->next;
-		kfree(mite);
-	}
-}
-
 void mite_unsetup(struct mite_struct *mite)
 {
 	/* unsigned long offset, start, length; */
@@ -236,26 +211,43 @@
 		comedi_pci_disable(mite->pcidev);
 		mite->mite_phys_addr = 0;
 	}
-
-	mite->used = 0;
 }
 EXPORT_SYMBOL(mite_unsetup);
 
-void mite_list_devices(void)
+struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite)
 {
-	struct mite_struct *mite, *next;
+	struct mite_dma_descriptor_ring *ring =
+	    kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL);
 
-	printk(KERN_INFO "Available NI device IDs:");
-	if (mite_devices)
-		for (mite = mite_devices; mite; mite = next) {
-			next = mite->next;
-			printk(KERN_INFO " 0x%04x", mite_device_id(mite));
-			if (mite->used)
-				printk(KERN_INFO "(used)");
+	if (ring == NULL)
+		return ring;
+	ring->hw_dev = get_device(&mite->pcidev->dev);
+	if (ring->hw_dev == NULL) {
+		kfree(ring);
+		return NULL;
+	}
+	ring->n_links = 0;
+	ring->descriptors = NULL;
+	ring->descriptors_dma_addr = 0;
+	return ring;
+};
+EXPORT_SYMBOL(mite_alloc_ring);
+
+void mite_free_ring(struct mite_dma_descriptor_ring *ring)
+{
+	if (ring) {
+		if (ring->descriptors) {
+			dma_free_coherent(ring->hw_dev,
+					  ring->n_links *
+					  sizeof(struct mite_dma_descriptor),
+					  ring->descriptors,
+					  ring->descriptors_dma_addr);
 		}
-	printk(KERN_INFO "\n");
-}
-EXPORT_SYMBOL(mite_list_devices);
+		put_device(ring->hw_dev);
+		kfree(ring);
+	}
+};
+EXPORT_SYMBOL(mite_free_ring);
 
 struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
 						   struct
@@ -317,7 +309,7 @@
 	int chor;
 	unsigned long flags;
 
-	MDPRINTK("mite_dma_arm ch%i\n", channel);
+	MDPRINTK("mite_dma_arm ch%i\n", mite_chan->channel);
 	/*
 	 * memory barrier is intended to insure any twiddling with the buffer
 	 * is done before writing to the mite to arm dma transfer
@@ -365,7 +357,8 @@
 			       n_links * sizeof(struct mite_dma_descriptor),
 			       &ring->descriptors_dma_addr, GFP_KERNEL);
 	if (!ring->descriptors) {
-		printk(KERN_ERR "mite: ring buffer allocation failed\n");
+		dev_err(async->subdevice->device->class_dev,
+			"mite: ring buffer allocation failed\n");
 		return -ENOMEM;
 	}
 	ring->n_links = n_links;
@@ -442,8 +435,7 @@
 		mcr |= CR_PSIZE32;
 		break;
 	default:
-		printk(KERN_WARNING "mite: bug! invalid mem bit width for dma "
-		       "transfer\n");
+		pr_warn("bug! invalid mem bit width for dma transfer\n");
 		break;
 	}
 	writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel));
@@ -462,8 +454,7 @@
 		dcr |= CR_PSIZE32;
 		break;
 	default:
-		printk(KERN_WARNING "mite: bug! invalid dev bit width for dma "
-		       "transfer\n");
+		pr_warn("bug! invalid dev bit width for dma transfer\n");
 		break;
 	}
 	writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel));
@@ -483,7 +474,7 @@
 }
 EXPORT_SYMBOL(mite_prep_dma);
 
-u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
+static u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
 {
 	struct mite_struct *mite = mite_chan->mite;
 	return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel));
@@ -577,7 +568,8 @@
 	nbytes = mite_bytes_written_to_memory_lb(mite_chan);
 	if ((int)(mite_bytes_written_to_memory_ub(mite_chan) -
 		  old_alloc_count) > 0) {
-		printk("mite: DMA overwrite of free area\n");
+		dev_warn(async->subdevice->device->class_dev,
+			 "mite: DMA overwrite of free area\n");
 		async->events |= COMEDI_CB_OVERFLOW;
 		return -1;
 	}
@@ -621,7 +613,8 @@
 	    (int)(nbytes_ub - stop_count) > 0)
 		nbytes_ub = stop_count;
 	if ((int)(nbytes_ub - old_alloc_count) > 0) {
-		printk(KERN_ERR "mite: DMA underrun\n");
+		dev_warn(async->subdevice->device->class_dev,
+			 "mite: DMA underrun\n");
 		async->events |= COMEDI_CB_OVERFLOW;
 		return -1;
 	}
@@ -672,8 +665,6 @@
 
 #ifdef DEBUG_MITE
 
-static void mite_decode(char **bit_str, unsigned int bits);
-
 /* names of bits in mite registers */
 
 static const char *const mite_CHOR_strings[] = {
@@ -743,86 +734,80 @@
 	"28", "lpauses", "30", "int",
 };
 
-void mite_dump_regs(struct mite_channel *mite_chan)
-{
-	unsigned long mite_io_addr =
-	    (unsigned long)mite_chan->mite->mite_io_addr;
-	unsigned long addr = 0;
-	unsigned long temp = 0;
-
-	printk(KERN_DEBUG "mite_dump_regs ch%i\n", mite_chan->channel);
-	printk(KERN_DEBUG "mite address is  =0x%08lx\n", mite_io_addr);
-
-	addr = mite_io_addr + MITE_CHOR(channel);
-	printk(KERN_DEBUG "mite status[CHOR]at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_CHOR_strings, temp);
-	addr = mite_io_addr + MITE_CHCR(channel);
-	printk(KERN_DEBUG "mite status[CHCR]at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_CHCR_strings, temp);
-	addr = mite_io_addr + MITE_TCR(channel);
-	printk(KERN_DEBUG "mite status[TCR] at 0x%08lx =0x%08x\n", addr,
-	       readl(addr));
-	addr = mite_io_addr + MITE_MCR(channel);
-	printk(KERN_DEBUG "mite status[MCR] at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_MCR_strings, temp);
-
-	addr = mite_io_addr + MITE_MAR(channel);
-	printk(KERN_DEBUG "mite status[MAR] at 0x%08lx =0x%08x\n", addr,
-	       readl(addr));
-	addr = mite_io_addr + MITE_DCR(channel);
-	printk(KERN_DEBUG "mite status[DCR] at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_DCR_strings, temp);
-	addr = mite_io_addr + MITE_DAR(channel);
-	printk(KERN_DEBUG "mite status[DAR] at 0x%08lx =0x%08x\n", addr,
-	       readl(addr));
-	addr = mite_io_addr + MITE_LKCR(channel);
-	printk(KERN_DEBUG "mite status[LKCR]at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_LKCR_strings, temp);
-	addr = mite_io_addr + MITE_LKAR(channel);
-	printk(KERN_DEBUG "mite status[LKAR]at 0x%08lx =0x%08x\n", addr,
-	       readl(addr));
-	addr = mite_io_addr + MITE_CHSR(channel);
-	printk(KERN_DEBUG "mite status[CHSR]at 0x%08lx =0x%08lx\n", addr,
-	       temp = readl(addr));
-	mite_decode(mite_CHSR_strings, temp);
-	addr = mite_io_addr + MITE_FCR(channel);
-	printk(KERN_DEBUG "mite status[FCR] at 0x%08lx =0x%08x\n\n", addr,
-	       readl(addr));
-}
-EXPORT_SYMBOL(mite_dump_regs);
-
-static void mite_decode(char **bit_str, unsigned int bits)
+static void mite_decode(const char *const *bit_str, unsigned int bits)
 {
 	int i;
 
 	for (i = 31; i >= 0; i--) {
 		if (bits & (1 << i))
-			printk(KERN_DEBUG " %s", bit_str[i]);
+			pr_debug(" %s\n", bit_str[i]);
 	}
-	printk(KERN_DEBUG "\n");
 }
-EXPORT_SYMBOL(mite_decode);
+
+void mite_dump_regs(struct mite_channel *mite_chan)
+{
+	void __iomem *mite_io_addr = mite_chan->mite->mite_io_addr;
+	unsigned int offset;
+	unsigned int value;
+	int channel = mite_chan->channel;
+
+	pr_debug("mite_dump_regs ch%i\n", channel);
+	pr_debug("mite address is  =%p\n", mite_io_addr);
+
+	offset = MITE_CHOR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[CHOR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_CHOR_strings, value);
+	offset = MITE_CHCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[CHCR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_CHCR_strings, value);
+	offset = MITE_TCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[TCR] at 0x%08x =0x%08x\n", offset, value);
+	offset = MITE_MCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[MCR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_MCR_strings, value);
+	offset = MITE_MAR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[MAR] at 0x%08x =0x%08x\n", offset, value);
+	offset = MITE_DCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[DCR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_DCR_strings, value);
+	offset = MITE_DAR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[DAR] at 0x%08x =0x%08x\n", offset, value);
+	offset = MITE_LKCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[LKCR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_LKCR_strings, value);
+	offset = MITE_LKAR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[LKAR] at 0x%08x =0x%08x\n", offset, value);
+	offset = MITE_CHSR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[CHSR] at 0x%08x =0x%08x\n", offset, value);
+	mite_decode(mite_CHSR_strings, value);
+	offset = MITE_FCR(channel);
+	value = readl(mite_io_addr + offset);
+	pr_debug("mite status[FCR] at 0x%08x =0x%08x\n", offset, value);
+}
+EXPORT_SYMBOL(mite_dump_regs);
 #endif
 
-#ifdef MODULE
-int __init init_module(void)
+static int __init mite_module_init(void)
 {
-	mite_init();
-	mite_list_devices();
-
 	return 0;
 }
 
-void __exit cleanup_module(void)
+static void __exit mite_module_exit(void)
 {
-	mite_cleanup();
 }
-#endif
+
+module_init(mite_module_init);
+module_exit(mite_module_exit);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index 83f1b27..255b8ba 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -25,15 +25,16 @@
 #define _MITE_H_
 
 #include <linux/pci.h>
+#include <linux/log2.h>
 #include "../comedidev.h"
 
 /*  #define DEBUG_MITE */
 #define PCIMIO_COMPAT
 
 #ifdef DEBUG_MITE
-#define MDPRINTK(format, args...)	printk(format , ## args)
+#define MDPRINTK(format, args...)	pr_debug(format , ## args)
 #else
-#define MDPRINTK(format, args...)
+#define MDPRINTK(format, args...)	do { } while (0)
 #endif
 
 #define MAX_MITE_DMA_CHANNELS 8
@@ -61,15 +62,11 @@
 };
 
 struct mite_struct {
-	struct mite_struct *next;
-	int used;
-
 	struct pci_dev *pcidev;
 	resource_size_t mite_phys_addr;
 	void __iomem *mite_io_addr;
 	resource_size_t daq_phys_addr;
 	void __iomem *daq_io_addr;
-
 	struct mite_channel channels[MAX_MITE_DMA_CHANNELS];
 	short channel_allocated[MAX_MITE_DMA_CHANNELS];
 	int num_channels;
@@ -77,41 +74,12 @@
 	spinlock_t lock;
 };
 
-static inline struct mite_dma_descriptor_ring *mite_alloc_ring(struct
-							       mite_struct
-							       *mite)
-{
-	struct mite_dma_descriptor_ring *ring =
-	    kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL);
-	if (ring == NULL)
-		return ring;
-	ring->hw_dev = get_device(&mite->pcidev->dev);
-	if (ring->hw_dev == NULL) {
-		kfree(ring);
-		return NULL;
-	}
-	ring->n_links = 0;
-	ring->descriptors = NULL;
-	ring->descriptors_dma_addr = 0;
-	return ring;
-};
+struct mite_struct *mite_alloc(struct pci_dev *pcidev);
 
-static inline void mite_free_ring(struct mite_dma_descriptor_ring *ring)
+static inline void mite_free(struct mite_struct *mite)
 {
-	if (ring) {
-		if (ring->descriptors) {
-			dma_free_coherent(ring->hw_dev,
-					  ring->n_links *
-					  sizeof(struct mite_dma_descriptor),
-					  ring->descriptors,
-					  ring->descriptors_dma_addr);
-		}
-		put_device(ring->hw_dev);
-		kfree(ring);
-	}
-};
-
-extern struct mite_struct *mite_devices;
+	kfree(mite);
+}
 
 static inline unsigned int mite_irq(struct mite_struct *mite)
 {
@@ -123,12 +91,11 @@
 	return mite->pcidev->device;
 };
 
-void mite_init(void);
-void mite_cleanup(void);
 int mite_setup(struct mite_struct *mite);
 int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1);
 void mite_unsetup(struct mite_struct *mite);
-void mite_list_devices(void);
+struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite);
+void mite_free_ring(struct mite_dma_descriptor_ring *ring);
 struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
 						   struct
 						   mite_dma_descriptor_ring
@@ -279,8 +246,9 @@
 static inline unsigned MITE_IODWBSR_1_WSIZE_bits(unsigned size)
 {
 	unsigned order = 0;
-	while (size >>= 1)
-		++order;
+
+	BUG_ON(size == 0);
+	order = ilog2(size);
 	BUG_ON(order < 1);
 	return (order - 1) & 0x1f;
 }
@@ -427,12 +395,10 @@
 {
 	int value = 0;
 
-	while (retry_limit) {
-		retry_limit >>= 1;
-		value++;
-	}
+	if (retry_limit)
+		value = 1 + ilog2(retry_limit);
 	if (value > 0x7)
-		printk("comedi: bug! retry_limit too large\n");
+		value = 0x7;
 	return (value & 0x7) << 21;
 }
 
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index b928b67..f8b7fae 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -353,7 +353,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_DIFF;
 	s->n_chan = 8;
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index a7fda8f..c0c3329 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -137,7 +137,7 @@
 		return ret;
 
 	for (i = 0; i < 4; i++) {
-		s = dev->subdevices + i;
+		s = &dev->subdevices[i];
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 		s->n_chan = 32;
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index eccbe1f..4625cb4 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -204,8 +204,10 @@
 
 static void encoder_reset(struct comedi_device *dev)
 {
+	struct comedi_subdevice *s = &dev->subdevices[4];
 	int chan;
-	for (chan = 0; chan < dev->subdevices[4].n_chan; chan++) {
+
+	for (chan = 0; chan < s->n_chan; chan++) {
 		int control =
 		    MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3);
 		outw(control, dev->iobase + MULTIQ3_CONTROL);
@@ -258,7 +260,7 @@
 	if (result < 0)
 		return result;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ai subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -267,7 +269,7 @@
 	s->maxdata = 0x1fff;
 	s->range_table = &range_bipolar5;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -277,7 +279,7 @@
 	s->maxdata = 0xfff;
 	s->range_table = &range_bipolar5;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* di subdevice */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -286,7 +288,7 @@
 	s->maxdata = 1;
 	s->range_table = &range_digital;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* do subdevice */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -296,7 +298,7 @@
 	s->range_table = &range_digital;
 	s->state = 0;
 
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	/* encoder (counter) subdevice */
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index a80c52f..51295f3 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -44,8 +44,11 @@
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "mite.h"
 
+#define DRIVER_NAME "ni_6527"
+
 #define NI6527_DIO_SIZE 4096
 #define NI6527_MITE_SIZE 4096
 
@@ -76,16 +79,6 @@
 #define Rising_Edge_Detection_Enable(x)		(0x018+(x))
 #define Falling_Edge_Detection_Enable(x)	(0x020+(x))
 
-static int ni6527_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static void ni6527_detach(struct comedi_device *dev);
-static struct comedi_driver driver_ni6527 = {
-	.driver_name = "ni6527",
-	.module = THIS_MODULE,
-	.attach = ni6527_attach,
-	.detach = ni6527_detach,
-};
-
 struct ni6527_board {
 
 	int dev_id;
@@ -103,7 +96,6 @@
 	 },
 };
 
-#define n_ni6527_boards ARRAY_SIZE(ni6527_boards)
 #define this_board ((const struct ni6527_board *)dev->board_ptr)
 
 static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
@@ -122,8 +114,6 @@
 
 #define devpriv ((struct ni6527_private *)dev->private)
 
-static int ni6527_find_device(struct comedi_device *dev, int bus, int slot);
-
 static int ni6527_di_insn_config(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
@@ -212,7 +202,7 @@
 static irqreturn_t ni6527_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 2;
+	struct comedi_subdevice *s = &dev->subdevices[2];
 	unsigned int status;
 
 	status = readb(devpriv->mite->daq_io_addr + Change_Status);
@@ -235,40 +225,20 @@
 			       struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_OTHER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and */
-	/*         are mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -364,36 +334,53 @@
 	return 2;
 }
 
-static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static const struct ni6527_board *
+ni6527_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int dev_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(ni6527_boards); n++) {
+		const struct ni6527_board *board = &ni6527_boards[n];
+		if (board->dev_id == dev_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit ni6527_attach_pci(struct comedi_device *dev,
+				       struct pci_dev *pcidev)
 {
 	struct comedi_subdevice *s;
 	int ret;
 
-	printk(KERN_INFO "comedi%d: ni6527\n", dev->minor);
-
 	ret = alloc_private(dev, sizeof(struct ni6527_private));
 	if (ret < 0)
 		return ret;
 
-	ret = ni6527_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = ni6527_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+
+	devpriv->mite = mite_alloc(pcidev);
+	if (!devpriv->mite)
+		return -ENOMEM;
 
 	ret = mite_setup(devpriv->mite);
 	if (ret < 0) {
-		printk(KERN_ERR "comedi: error setting up mite\n");
+		dev_err(dev->class_dev, "error setting up mite\n");
 		return ret;
 	}
 
 	dev->board_name = this_board->name;
-	printk(KERN_INFO "comedi board: %s, ID=0x%02x\n", dev->board_name,
-		readb(devpriv->mite->daq_io_addr + ID_Register));
+	dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name,
+		 readb(devpriv->mite->daq_io_addr + ID_Register));
 
 	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 24;
@@ -402,7 +389,7 @@
 	s->insn_config = ni6527_di_insn_config;
 	s->insn_bits = ni6527_di_insn_bits;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 24;
@@ -410,7 +397,7 @@
 	s->maxdata = 1;
 	s->insn_bits = ni6527_do_insn_bits;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
@@ -432,9 +419,9 @@
 	writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
 
 	ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt,
-			  IRQF_SHARED, "ni6527", dev);
+			  IRQF_SHARED, DRIVER_NAME, dev);
 	if (ret < 0)
-		printk(KERN_WARNING "comedi i6527 irq not available\n");
+		dev_warn(dev->class_dev, "irq not available\n");
 	else
 		dev->irq = mite_irq(devpriv->mite);
 
@@ -448,73 +435,37 @@
 		       devpriv->mite->daq_io_addr + Master_Interrupt_Control);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
-	if (devpriv && devpriv->mite)
+	if (devpriv && devpriv->mite) {
 		mite_unsetup(devpriv->mite);
-}
-
-static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-		for (i = 0; i < n_ni6527_boards; i++) {
-			if (mite_device_id(mite) == ni6527_boards[i].dev_id) {
-				dev->board_ptr = ni6527_boards + i;
-				devpriv->mite = mite;
-				return 0;
-			}
-		}
+		mite_free(devpriv->mite);
 	}
-	printk(KERN_ERR "comedi 6527: no device found\n");
-	mite_list_devices();
-	return -EIO;
 }
 
-static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev,
-					     const struct pci_device_id *ent)
+static struct comedi_driver ni6527_driver = {
+	.driver_name = DRIVER_NAME,
+	.module = THIS_MODULE,
+	.attach_pci = ni6527_attach_pci,
+	.detach = ni6527_detach,
+};
+
+static int __devinit ni6527_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_ni6527);
+	return comedi_pci_auto_config(dev, &ni6527_driver);
 }
 
-static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev)
+static void __devexit ni6527_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_ni6527_pci_driver = {
+static struct pci_driver ni6527_pci_driver = {
+	.name = DRIVER_NAME,
 	.id_table = ni6527_pci_table,
-	.probe = &driver_ni6527_pci_probe,
-	.remove = __devexit_p(&driver_ni6527_pci_remove)
+	.probe = ni6527_pci_probe,
+	.remove = __devexit_p(ni6527_pci_remove)
 };
-
-static int __init driver_ni6527_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_ni6527);
-	if (retval < 0)
-		return retval;
-
-	driver_ni6527_pci_driver.name = (char *)driver_ni6527.driver_name;
-	return pci_register_driver(&driver_ni6527_pci_driver);
-}
-
-static void __exit driver_ni6527_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_ni6527_pci_driver);
-	comedi_driver_unregister(&driver_ni6527);
-}
-
-module_init(driver_ni6527_init_module);
-module_exit(driver_ni6527_cleanup_module);
+module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index bce39f1..2a73ff5 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -55,6 +55,7 @@
 #include <linux/slab.h>
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "mite.h"
 
 #define NI6514_DIO_SIZE 4096
@@ -109,18 +110,7 @@
 #define OverflowIntEnable		0x02
 #define EdgeIntEnable			0x01
 
-static int ni_65xx_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static void ni_65xx_detach(struct comedi_device *dev);
-static struct comedi_driver driver_ni_65xx = {
-	.driver_name = "ni_65xx",
-	.module = THIS_MODULE,
-	.attach = ni_65xx_attach,
-	.detach = ni_65xx_detach,
-};
-
 struct ni_65xx_board {
-
 	int dev_id;
 	const char *name;
 	unsigned num_dio_ports;
@@ -325,8 +315,6 @@
 	return subdev_private;
 }
 
-static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot);
-
 static int ni_65xx_config_filter(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
@@ -453,11 +441,9 @@
 			writeb(bits,
 			       private(dev)->mite->daq_io_addr +
 			       Port_Data(port));
-/* printk("wrote 0x%x to port %i\n", bits, port); */
 		}
 		port_read_bits =
 		    readb(private(dev)->mite->daq_io_addr + Port_Data(port));
-/* printk("read 0x%x from port %i\n", port_read_bits, port); */
 		if (s->type == COMEDI_SUBD_DO && board(dev)->invert_outputs) {
 			/* Outputs inverted, so invert value read back from
 			 * DO subdevice.  (Does not apply to boards with DIO
@@ -478,7 +464,7 @@
 static irqreturn_t ni_65xx_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 2;
+	struct comedi_subdevice *s = &dev->subdevices[2];
 	unsigned int status;
 
 	status = readb(private(dev)->mite->daq_io_addr + Change_Status);
@@ -501,40 +487,20 @@
 				struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_OTHER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-	compatible */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -644,41 +610,55 @@
 	return 2;
 }
 
-static int ni_65xx_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static const struct ni_65xx_board *
+ni_65xx_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int dev_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(ni_65xx_boards); n++) {
+		const struct ni_65xx_board *board = &ni_65xx_boards[n];
+		if (board->dev_id == dev_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit ni_65xx_attach_pci(struct comedi_device *dev,
+					struct pci_dev *pcidev)
 {
 	struct comedi_subdevice *s;
 	unsigned i;
 	int ret;
 
-	printk(KERN_INFO "comedi%d: ni_65xx:", dev->minor);
-
 	ret = alloc_private(dev, sizeof(struct ni_65xx_private));
 	if (ret < 0)
 		return ret;
 
-	ret = ni_65xx_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = ni_65xx_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+
+	private(dev)->mite = mite_alloc(pcidev);
+	if (!private(dev)->mite)
+		return -ENOMEM;
 
 	ret = mite_setup(private(dev)->mite);
 	if (ret < 0) {
-		printk(KERN_WARNING "error setting up mite\n");
+		dev_warn(dev->class_dev, "error setting up mite\n");
 		return ret;
 	}
 
 	dev->board_name = board(dev)->name;
 	dev->irq = mite_irq(private(dev)->mite);
-	printk(KERN_INFO " %s", dev->board_name);
-
-	printk(KERN_INFO " ID=0x%02x",
+	dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name,
 	       readb(private(dev)->mite->daq_io_addr + ID_Register));
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	if (board(dev)->num_di_ports) {
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
@@ -696,7 +676,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (board(dev)->num_do_ports) {
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -713,7 +693,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	if (board(dev)->num_dio_ports) {
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -737,7 +717,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
@@ -772,11 +752,9 @@
 			  "ni_65xx", dev);
 	if (ret < 0) {
 		dev->irq = 0;
-		printk(KERN_WARNING " irq not available");
+		dev_warn(dev->class_dev, "irq not available\n");
 	}
 
-	printk("\n");
-
 	return 0;
 }
 
@@ -791,79 +769,46 @@
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (private(dev)) {
+		struct comedi_subdevice *s;
 		unsigned i;
+
 		for (i = 0; i < dev->n_subdevices; ++i) {
-			kfree(dev->subdevices[i].private);
-			dev->subdevices[i].private = NULL;
+			s = &dev->subdevices[i];
+			kfree(s->private);
+			s->private = NULL;
 		}
-		if (private(dev)->mite)
+		if (private(dev)->mite) {
 			mite_unsetup(private(dev)->mite);
-	}
-}
-
-static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-		for (i = 0; i < n_ni_65xx_boards; i++) {
-			if (mite_device_id(mite) == ni_65xx_boards[i].dev_id) {
-				dev->board_ptr = ni_65xx_boards + i;
-				private(dev)->mite = mite;
-				return 0;
-			}
+			mite_free(private(dev)->mite);
 		}
 	}
-	printk(KERN_WARNING "no device found\n");
-	mite_list_devices();
-	return -EIO;
 }
 
-static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static struct comedi_driver ni_65xx_driver = {
+	.driver_name = "ni_65xx",
+	.module = THIS_MODULE,
+	.attach_pci = ni_65xx_attach_pci,
+	.detach = ni_65xx_detach,
+};
+
+static int __devinit ni_65xx_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_ni_65xx);
+	return comedi_pci_auto_config(dev, &ni_65xx_driver);
 }
 
-static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev)
+static void __devexit ni_65xx_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_ni_65xx_pci_driver = {
+static struct pci_driver ni_65xx_pci_driver = {
+	.name = "ni_65xx",
 	.id_table = ni_65xx_pci_table,
-	.probe = &driver_ni_65xx_pci_probe,
-	.remove = __devexit_p(&driver_ni_65xx_pci_remove)
+	.probe = ni_65xx_pci_probe,
+	.remove = __devexit_p(ni_65xx_pci_remove)
 };
-
-static int __init driver_ni_65xx_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_ni_65xx);
-	if (retval < 0)
-		return retval;
-
-	driver_ni_65xx_pci_driver.name = (char *)driver_ni_65xx.driver_name;
-	return pci_register_driver(&driver_ni_65xx_pci_driver);
-}
-
-static void __exit driver_ni_65xx_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_ni_65xx_pci_driver);
-	comedi_driver_unregister(&driver_ni_65xx);
-}
-
-module_init(driver_ni_65xx_init_module);
-module_exit(driver_ni_65xx_cleanup_module);
+module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 5e863ff..df2f3b0 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -448,68 +448,46 @@
 	return dev->private;
 }
 
-/* initialized in ni_660x_find_device() */
+/* initialized in ni_660x_attach_pci() */
 static inline const struct ni_660x_board *board(struct comedi_device *dev)
 {
 	return dev->board_ptr;
 }
 
-#define n_ni_660x_boards ARRAY_SIZE(ni_660x_boards)
-
-static int ni_660x_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
+static int ni_660x_attach_pci(struct comedi_device *dev,
+			      struct pci_dev *pcidev);
 static void ni_660x_detach(struct comedi_device *dev);
 static void init_tio_chip(struct comedi_device *dev, int chipset);
 static void ni_660x_select_pfi_output(struct comedi_device *dev,
 				      unsigned pfi_channel,
 				      unsigned output_select);
 
-static struct comedi_driver driver_ni_660x = {
+static struct comedi_driver ni_660x_driver = {
 	.driver_name = "ni_660x",
 	.module = THIS_MODULE,
-	.attach = ni_660x_attach,
+	.attach_pci = ni_660x_attach_pci,
 	.detach = ni_660x_detach,
 };
 
-static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev,
-					      const struct pci_device_id *ent)
+static int __devinit ni_660x_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_ni_660x);
+	return comedi_pci_auto_config(dev, &ni_660x_driver);
 }
 
-static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev)
+static void __devexit ni_660x_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_ni_660x_pci_driver = {
+static struct pci_driver ni_660x_pci_driver = {
+	.name = "ni_660x",
 	.id_table = ni_660x_pci_table,
-	.probe = &driver_ni_660x_pci_probe,
-	.remove = __devexit_p(&driver_ni_660x_pci_remove)
+	.probe = ni_660x_pci_probe,
+	.remove = __devexit_p(ni_660x_pci_remove)
 };
+module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver);
 
-static int __init driver_ni_660x_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_ni_660x);
-	if (retval < 0)
-		return retval;
-
-	driver_ni_660x_pci_driver.name = (char *)driver_ni_660x.driver_name;
-	return pci_register_driver(&driver_ni_660x_pci_driver);
-}
-
-static void __exit driver_ni_660x_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_ni_660x_pci_driver);
-	comedi_driver_unregister(&driver_ni_660x);
-}
-
-module_init(driver_ni_660x_init_module);
-module_exit(driver_ni_660x_cleanup_module);
-
-static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot);
 static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan,
 				   unsigned source);
 
@@ -748,8 +726,6 @@
 		ni_660x_register = G3InterruptEnable;
 		break;
 	default:
-		printk(KERN_WARNING "%s: unhandled register 0x%x in switch.\n",
-		       __func__, reg);
 		BUG();
 		return 0;
 		break;
@@ -773,8 +749,6 @@
 		writel(bits, write_address);
 		break;
 	default:
-		printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
-		       __FILE__, __func__, reg);
 		BUG();
 		break;
 	}
@@ -796,8 +770,6 @@
 		return readl(read_address);
 		break;
 	default:
-		printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
-		       __FILE__, __func__, reg);
 		BUG();
 		break;
 	}
@@ -893,8 +865,8 @@
 	return 0;
 }
 
-void ni_660x_release_mite_channel(struct comedi_device *dev,
-				  struct ni_gpct *counter)
+static void ni_660x_release_mite_channel(struct comedi_device *dev,
+					 struct ni_gpct *counter)
 {
 	unsigned long flags;
 
@@ -985,7 +957,7 @@
 	spin_lock_irqsave(&private(dev)->interrupt_lock, flags);
 	smp_mb();
 	for (i = 0; i < ni_660x_num_counters(dev); ++i) {
-		s = dev->subdevices + NI_660X_GPCT_SUBDEV(i);
+		s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)];
 		ni_660x_handle_gpct_interrupt(dev, s);
 	}
 	spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags);
@@ -1062,28 +1034,43 @@
 	}
 }
 
-static int ni_660x_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static const struct ni_660x_board *
+ni_660x_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int dev_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(ni_660x_boards); n++) {
+		const struct ni_660x_board *board = &ni_660x_boards[n];
+		if (board->dev_id == dev_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit ni_660x_attach_pci(struct comedi_device *dev,
+					struct pci_dev *pcidev)
 {
 	struct comedi_subdevice *s;
 	int ret;
 	unsigned i;
 	unsigned global_interrupt_config_bits;
 
-	printk(KERN_INFO "comedi%d: ni_660x: ", dev->minor);
-
 	ret = ni_660x_allocate_private(dev);
 	if (ret < 0)
 		return ret;
-	ret = ni_660x_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = ni_660x_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+	private(dev)->mite = mite_alloc(pcidev);
+	if (!private(dev)->mite)
+		return -ENOMEM;
 
 	dev->board_name = board(dev)->name;
 
 	ret = mite_setup2(private(dev)->mite, 1);
 	if (ret < 0) {
-		printk(KERN_WARNING "error setting up mite\n");
+		dev_warn(dev->class_dev, "error setting up mite\n");
 		return ret;
 	}
 	comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev);
@@ -1091,17 +1078,15 @@
 	if (ret < 0)
 		return ret;
 
-	printk(KERN_INFO " %s ", dev->board_name);
-
 	ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */
 	s->type = COMEDI_SUBD_UNUSED;
 
-	s = dev->subdevices + NI_660X_DIO_SUBDEV;
+	s = &dev->subdevices[NI_660X_DIO_SUBDEV];
 	/* DIGITAL I/O SUBDEVICE */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -1124,7 +1109,7 @@
 	if (private(dev)->counter_dev == NULL)
 		return -ENOMEM;
 	for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) {
-		s = dev->subdevices + NI_660X_GPCT_SUBDEV(i);
+		s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)];
 		if (i < ni_660x_num_counters(dev)) {
 			s->type = COMEDI_SUBD_COUNTER;
 			s->subdev_flags =
@@ -1174,7 +1159,7 @@
 	ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt,
 			  IRQF_SHARED, "ni_660x", dev);
 	if (ret < 0) {
-		printk(KERN_WARNING " irq not available\n");
+		dev_warn(dev->class_dev, " irq not available\n");
 		return ret;
 	}
 	dev->irq = mite_irq(private(dev)->mite);
@@ -1183,7 +1168,7 @@
 		global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
 	ni_660x_write_register(dev, 0, global_interrupt_config_bits,
 			       GlobalInterruptConfigRegister);
-	printk(KERN_INFO "attached\n");
+	dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
 	return 0;
 }
 
@@ -1197,6 +1182,7 @@
 		if (private(dev)->mite) {
 			ni_660x_free_mite_rings(dev);
 			mite_unsetup(private(dev)->mite);
+			mite_free(private(dev)->mite);
 		}
 	}
 }
@@ -1240,33 +1226,6 @@
 	return ni_tio_winsn(subdev_to_counter(s), insn, data);
 }
 
-static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-
-		for (i = 0; i < n_ni_660x_boards; i++) {
-			if (mite_device_id(mite) == ni_660x_boards[i].dev_id) {
-				dev->board_ptr = ni_660x_boards + i;
-				private(dev)->mite = mite;
-				return 0;
-			}
-		}
-	}
-	printk(KERN_WARNING "no device found\n");
-	mite_list_devices();
-	return -EIO;
-}
-
 static int ni_660x_dio_insn_bits(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 9c57618..eac6dc0 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -187,37 +187,22 @@
 	return insn->n;
 }
 
-static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot)
+static const struct ni_670x_board *
+ni_670x_find_boardinfo(struct pci_dev *pcidev)
 {
-	struct ni_670x_private *devpriv = dev->private;
-	struct mite_struct *mite;
-	int i;
+	unsigned int dev_id = pcidev->device;
+	unsigned int n;
 
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number
-			    || slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-
-		for (i = 0; i < ARRAY_SIZE(ni_670x_boards); i++) {
-			if (mite_device_id(mite) == ni_670x_boards[i].dev_id) {
-				dev->board_ptr = ni_670x_boards + i;
-				devpriv->mite = mite;
-
-				return 0;
-			}
-		}
+	for (n = 0; n < ARRAY_SIZE(ni_670x_boards); n++) {
+		const struct ni_670x_board *board = &ni_670x_boards[n];
+		if (board->dev_id == dev_id)
+			return board;
 	}
-	dev_warn(dev->class_dev, "no device found\n");
-	mite_list_devices();
-	return -EIO;
+	return NULL;
 }
 
-static int ni_670x_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static int __devinit ni_670x_attach_pci(struct comedi_device *dev,
+					struct pci_dev *pcidev)
 {
 	const struct ni_670x_board *thisboard;
 	struct ni_670x_private *devpriv;
@@ -229,10 +214,12 @@
 	if (ret < 0)
 		return ret;
 	devpriv = dev->private;
-
-	ret = ni_670x_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = ni_670x_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+	devpriv->mite = mite_alloc(pcidev);
+	if (!devpriv->mite)
+		return -ENOMEM;
 	thisboard = comedi_board(dev);
 
 	ret = mite_setup(devpriv->mite);
@@ -241,13 +228,12 @@
 		return ret;
 	}
 	dev->board_name = thisboard->name;
-	dev->irq = mite_irq(devpriv->mite);
 
 	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -271,7 +257,7 @@
 	s->insn_write = &ni_670x_ao_winsn;
 	s->insn_read = &ni_670x_ao_rinsn;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* digital i/o subdevice */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -298,20 +284,20 @@
 	struct comedi_subdevice *s;
 
 	if (dev->n_subdevices) {
-		s = dev->subdevices + 0;
+		s = &dev->subdevices[0];
 		if (s)
 			kfree(s->range_table_list);
 	}
-	if (devpriv && devpriv->mite)
+	if (devpriv && devpriv->mite) {
 		mite_unsetup(devpriv->mite);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
+		mite_free(devpriv->mite);
+	}
 }
 
 static struct comedi_driver ni_670x_driver = {
 	.driver_name	= "ni_670x",
 	.module		= THIS_MODULE,
-	.attach		= ni_670x_attach,
+	.attach_pci	= ni_670x_attach_pci,
 	.detach		= ni_670x_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index b53a428..8395080 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -321,45 +321,23 @@
 	int startChan;
 	int i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually
-	 * compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -832,7 +810,7 @@
 		return ret;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 62c8c44..93938ce 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -358,7 +358,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -371,7 +371,7 @@
 	s->insn_write = &atao_ao_winsn;
 	s->insn_read = &atao_ao_rinsn;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* digital i/o subdevice */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -381,7 +381,7 @@
 	s->insn_bits = atao_dio_insn_bits;
 	s->insn_config = atao_dio_insn_config;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* caldac subdevice */
 	s->type = COMEDI_SUBD_CALIB;
 	s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
@@ -390,7 +390,7 @@
 	s->insn_read = atao_calib_insn_read;
 	s->insn_write = atao_calib_insn_write;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* eeprom subdevice */
 	/* s->type=COMEDI_SUBD_EEPROM; */
 	s->type = COMEDI_SUBD_UNUSED;
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 6448373..cac2557 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -489,7 +489,7 @@
 
 	/* generic E series stuff in ni_mio_common.c */
 
-	ret = ni_E_init(dev, it);
+	ret = ni_E_init(dev);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 2c78d3d..e91a620 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -40,6 +40,7 @@
 
 #include <linux/ioport.h>
 
+#include "comedi_fc.h"
 #include "8255.h"
 
 /* Configuration and Status Registers */
@@ -234,7 +235,7 @@
 static irqreturn_t atmio16d_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 
 	comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG));
 
@@ -246,45 +247,26 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_cmd *cmd)
 {
-	int err = 0, tmp;
+	int err = 0;
 
-	/* make sure triggers are valid */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique & mutually compatible */
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -724,7 +706,7 @@
 	devpriv->dac1_coding = it->options[12];
 
 	/* setup sub-devices */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* ai subdevice */
 	s->type = COMEDI_SUBD_AI;
@@ -749,7 +731,7 @@
 	}
 
 	/* ao subdevice */
-	s++;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->n_chan = 2;
@@ -775,7 +757,7 @@
 	}
 
 	/* Digital I/O */
-	s++;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 	s->n_chan = 8;
@@ -785,7 +767,7 @@
 	s->range_table = &range_digital;
 
 	/* 8255 subdevice */
-	s++;
+	s = &dev->subdevices[3];
 	if (board->has_8255)
 		subdev_8255_init(dev, s, NULL, dev->iobase);
 	else
@@ -793,7 +775,7 @@
 
 /* don't yet know how to deal with counter/timers */
 #if 0
-	s++;
+	s = &dev->subdevices[4];
 	/* do */
 	s->type = COMEDI_SUBD_TIMER;
 	s->n_chan = 0;
@@ -807,9 +789,12 @@
 static void atmio16d_detach(struct comedi_device *dev)
 {
 	const struct atmio16_board_t *board = comedi_board(dev);
+	struct comedi_subdevice *s;
 
-	if (dev->subdevices && board->has_8255)
-		subdev_8255_cleanup(dev, dev->subdevices + 3);
+	if (dev->subdevices && board->has_8255) {
+		s = &dev->subdevices[3];
+		subdev_8255_cleanup(dev, s);
+	}
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	reset_atmio16d(dev);
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 83016b4..2ba0ade4 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -1,6 +1,6 @@
 /*
  *     comedi/drivers/ni_daq_700.c
- *     Driver for DAQCard-700 DIO only
+ *     Driver for DAQCard-700 DIO/AI
  *     copied from 8255
  *
  *     COMEDI - Linux Control and Measurement Device Interface
@@ -29,14 +29,25 @@
   based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es>
 Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
 Status: works
-Updated: Thu, 21 Feb 2008 12:07:20 +0000
+Updated: Wed, 19 Sep 2012 12:07:20 +0000
 
-The daqcard-700 appears in Comedi as a single digital I/O subdevice with
-16 channels.  The channel 0 corresponds to the daqcard-700's output
+The daqcard-700 appears in Comedi as a  digital I/O subdevice (0) with
+16 channels and a analog input subdevice (1) with 16 single-ended channels.
+
+Digital:  The channel 0 corresponds to the daqcard-700's output
 port, bit 0; channel 8 corresponds to the input port, bit 0.
 
-Direction configuration: channels 0-7 output, 8-15 input (8225 device
+Digital direction configuration: channels 0-7 output, 8-15 input (8225 device
 emu as port A output, port B input, port C N/A).
+
+Analog: The input  range is 0 to 4095 for -10 to +10 volts 
+IRQ is assigned but not used.
+
+Version 0.1	Original DIO only driver
+Version 0.2	DIO and basic AI analog input support on 16 se channels
+
+Manuals:	Register level:	http://www.ni.com/pdf/manuals/340698.pdf
+		User Manual:	http://www.ni.com/pdf/manuals/320676d.pdf
 */
 
 #include <linux/interrupt.h>
@@ -51,16 +62,29 @@
 
 static struct pcmcia_device *pcmcia_cur_dev;
 
-struct dio700_board {
+struct daq700_board {
 	const char *name;
 };
 
-#define DIO_W		0x04
-#define DIO_R		0x05
+/* daqcard700 registers */
+#define DIO_W		0x04	/* WO 8bit */
+#define DIO_R		0x05	/* RO 8bit */
+#define CMD_R1		0x00	/* WO 8bit */
+#define CMD_R2		0x07	/* RW 8bit */
+#define CMD_R3		0x05	/* W0 8bit */
+#define STA_R1		0x00	/* RO 8bit */
+#define STA_R2		0x01	/* RO 8bit */
+#define ADFIFO_R	0x02	/* RO 16bit */
+#define ADCLEAR_R	0x01	/* WO 8bit */
+#define CDA_R0		0x08	/* RW 8bit */
+#define CDA_R1		0x09	/* RW 8bit */
+#define CDA_R2		0x0A	/* RW 8bit */
+#define CMO_R		0x0B	/* RO 8bit */
+#define TIC_R		0x06	/* WO 8bit */
 
-static int subdev_700_insn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data)
+static int daq700_dio_insn_bits(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data)
 {
 	if (data[0]) {
 		s->state &= ~data[0];
@@ -76,7 +100,7 @@
 	return insn->n;
 }
 
-static int subdev_700_insn_config(struct comedi_device *dev,
+static int daq700_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
@@ -97,9 +121,90 @@
 	return insn->n;
 }
 
-static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int daq700_ai_rinsn(struct comedi_device *dev,
+			   struct comedi_subdevice *s,
+			   struct comedi_insn *insn, unsigned int *data)
 {
-	const struct dio700_board *thisboard = comedi_board(dev);
+	int n, i, chan;
+	int d;
+	unsigned int status;
+	enum { TIMEOUT = 100 };
+
+	chan = CR_CHAN(insn->chanspec);
+	/* write channel to multiplexer */
+	/* set mask scan bit high to disable scanning */
+	outb(chan | 0x80, dev->iobase + CMD_R1);
+
+	/* convert n samples */
+	for (n = 0; n < insn->n; n++) {
+		/* trigger conversion with out0 L to H */
+		outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
+		outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
+		/* mode 1 out0 H, L to H, start conversion */
+		outb(0x32, dev->iobase + CMO_R);
+		/* wait for conversion to end */
+		for (i = 0; i < TIMEOUT; i++) {
+			status = inb(dev->iobase + STA_R2);
+			if ((status & 0x03) != 0) {
+				dev_info(dev->class_dev,
+					 "Overflow/run Error\n");
+				return -EOVERFLOW;
+			}
+			status = inb(dev->iobase + STA_R1);
+			if ((status & 0x02) != 0) {
+				dev_info(dev->class_dev, "Data Error\n");
+				return -ENODATA;
+			}
+			if ((status & 0x11) == 0x01) {
+				/* ADC conversion complete */
+				break;
+			}
+			udelay(1);
+		}
+		if (i == TIMEOUT) {
+			dev_info(dev->class_dev,
+				 "timeout during ADC conversion\n");
+			return -ETIMEDOUT;
+		}
+		/* read data */
+		d = inw(dev->iobase + ADFIFO_R);
+		/* mangle the data as necessary */
+		/* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
+		d &= 0x0fff;
+		d ^= 0x0800;
+		data[n] = d;
+	}
+	return n;
+}
+
+/*
+ * Data acquisition is enabled.
+ * The counter 0 output is high.
+ * The I/O connector pin CLK1 drives counter 1 source.
+ * Multiple-channel scanning is disabled.
+ * All interrupts are disabled.
+ * The analog input range is set to +-10 V
+ * The analog input mode is single-ended.
+ * The analog input circuitry is initialized to channel 0.
+ * The A/D FIFO is cleared.
+ */
+static void daq700_ai_config(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{			
+	unsigned long iobase = dev->iobase;
+
+	outb(0x80, iobase + CMD_R1);	/* disable scanning, ADC to chan 0 */
+	outb(0x00, iobase + CMD_R2);	/* clear all bits */
+	outb(0x00, iobase + CMD_R3);	/* set +-10 range */
+	outb(0x32, iobase + CMO_R);	/* config counter mode1, out0 to H */
+	outb(0x00, iobase + TIC_R);	/* clear counter interrupt */
+	outb(0x00, iobase + ADCLEAR_R);	/* clear the ADC FIFO */
+	inw(iobase + ADFIFO_R);		/* read 16bit junk from FIFO to clear */
+}
+
+static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	const struct daq700_board *thisboard = comedi_board(dev);
 	struct comedi_subdevice *s;
 	struct pcmcia_device *link;
 	int ret;
@@ -116,23 +221,33 @@
 
 	dev->board_name = thisboard->name;
 
-	ret = comedi_alloc_subdevices(dev, 1);
+	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
 
 	/* DAQCard-700 dio */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type		= COMEDI_SUBD_DIO;
 	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
 	s->n_chan	= 16;
 	s->range_table	= &range_digital;
 	s->maxdata	= 1;
-	s->insn_bits	= subdev_700_insn;
-	s->insn_config	= subdev_700_insn_config;
-
+	s->insn_bits	= daq700_dio_insn_bits;
+	s->insn_config	= daq700_dio_insn_config;
 	s->state	= 0;
 	s->io_bits	= 0x00ff;
 
+	/* DAQCard-700 ai */
+	s = &dev->subdevices[1];
+	s->type = COMEDI_SUBD_AI;
+	/* we support single-ended (ground)  */
+	s->subdev_flags = SDF_READABLE | SDF_GROUND;
+	s->n_chan = 16;
+	s->maxdata = (1 << 12) - 1;
+	s->range_table = &range_bipolar10;
+	s->insn_read = daq700_ai_rinsn;
+	daq700_ai_config(dev, s);
+
 	dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
 		dev->driver->driver_name,
 		dev->board_name,
@@ -141,12 +256,12 @@
 	return 0;
 }
 
-static void dio700_detach(struct comedi_device *dev)
+static void daq700_detach(struct comedi_device *dev)
 {
 	/* nothing to cleanup */
 }
 
-static const struct dio700_board dio700_boards[] = {
+static const struct daq700_board daq700_boards[] = {
 	{
 		.name		= "daqcard-700",
 	}, {
@@ -154,17 +269,17 @@
 	},
 };
 
-static struct comedi_driver driver_dio700 = {
+static struct comedi_driver daq700_driver = {
 	.driver_name	= "ni_daq_700",
 	.module		= THIS_MODULE,
-	.attach		= dio700_attach,
-	.detach		= dio700_detach,
-	.board_name	= &dio700_boards[0].name,
-	.num_names	= ARRAY_SIZE(dio700_boards),
-	.offset		= sizeof(struct dio700_board),
+	.attach		= daq700_attach,
+	.detach		= daq700_detach,
+	.board_name	= &daq700_boards[0].name,
+	.num_names	= ARRAY_SIZE(daq700_boards),
+	.offset		= sizeof(struct daq700_board),
 };
 
-static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
+static int daq700_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
 {
 	if (p_dev->config_index == 0)
@@ -173,14 +288,14 @@
 	return pcmcia_request_io(p_dev);
 }
 
-static int dio700_cs_attach(struct pcmcia_device *link)
+static int daq700_cs_attach(struct pcmcia_device *link)
 {
 	int ret;
 
 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
 		CONF_AUTO_SET_IO;
 
-	ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL);
+	ret = pcmcia_loop_config(link, daq700_pcmcia_config_loop, NULL);
 	if (ret)
 		goto failed;
 
@@ -199,52 +314,53 @@
 	return ret;
 }
 
-static void dio700_cs_detach(struct pcmcia_device *link)
+static void daq700_cs_detach(struct pcmcia_device *link)
 {
 	pcmcia_disable_device(link);
 	pcmcia_cur_dev = NULL;
 }
 
-static const struct pcmcia_device_id dio700_cs_ids[] = {
+static const struct pcmcia_device_id daq700_cs_ids[] = {
 	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
 	PCMCIA_DEVICE_NULL
 };
-MODULE_DEVICE_TABLE(pcmcia, dio700_cs_ids);
+MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
 
-static struct pcmcia_driver dio700_cs_driver = {
+static struct pcmcia_driver daq700_cs_driver = {
 	.name		= "ni_daq_700",
 	.owner		= THIS_MODULE,
-	.probe		= dio700_cs_attach,
-	.remove		= dio700_cs_detach,
-	.id_table	= dio700_cs_ids,
+	.probe		= daq700_cs_attach,
+	.remove		= daq700_cs_detach,
+	.id_table	= daq700_cs_ids,
 };
 
-static int __init dio700_cs_init(void)
+static int __init daq700_cs_init(void)
 {
 	int ret;
 
-	ret = comedi_driver_register(&driver_dio700);
+	ret = comedi_driver_register(&daq700_driver);
 	if (ret < 0)
 		return ret;
 
-	ret = pcmcia_register_driver(&dio700_cs_driver);
+	ret = pcmcia_register_driver(&daq700_cs_driver);
 	if (ret < 0) {
-		comedi_driver_unregister(&driver_dio700);
+		comedi_driver_unregister(&daq700_driver);
 		return ret;
 	}
 
 	return 0;
 }
-module_init(dio700_cs_init);
+module_init(daq700_cs_init);
 
-static void __exit dio700_cs_exit(void)
+static void __exit daq700_cs_exit(void)
 {
-	pcmcia_unregister_driver(&dio700_cs_driver);
-	comedi_driver_unregister(&driver_dio700);
+	pcmcia_unregister_driver(&daq700_cs_driver);
+	comedi_driver_unregister(&daq700_driver);
 }
-module_exit(dio700_cs_exit);
+module_exit(daq700_cs_exit);
 
 MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
 MODULE_DESCRIPTION(
-	"Comedi driver for National Instruments PCMCIA DAQCard-700 DIO");
+	"Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
+MODULE_VERSION("0.2.00");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index e27cae0..0ca222b 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -164,7 +164,7 @@
 		return ret;
 
 	/* 8255 dio */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	subdev_8255_init(dev, s, NULL, dev->iobase);
 
 	return 0;
@@ -172,8 +172,12 @@
 
 static void dio24_detach(struct comedi_device *dev)
 {
-	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 0);
+	struct comedi_subdevice *s;
+
+	if (dev->subdevices) {
+		s = &dev->subdevices[0];
+		subdev_8255_cleanup(dev, s);
+	}
 	if (thisboard->bustype != pcmcia_bustype && dev->iobase)
 		release_region(dev->iobase, DIO24_SIZE);
 	if (dev->irq)
@@ -304,7 +308,7 @@
 		   "PCMCIA DAQ-Card DIO-24");
 MODULE_LICENSE("GPL");
 
-struct pcmcia_driver dio24_cs_driver = {
+static struct pcmcia_driver dio24_cs_driver = {
 	.probe = dio24_cs_attach,
 	.remove = dio24_cs_detach,
 	.suspend = dio24_cs_suspend,
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index ab8b787..28b91a6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -73,9 +73,6 @@
 
 */
 
-#undef LABPC_DEBUG
-/* #define LABPC_DEBUG    enable debugging messages */
-
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -209,7 +206,13 @@
 #define   INIT_A1_BITS	0x70
 #define COUNTER_B_BASE_REG	0x18
 
-static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
+enum scan_mode {
+	MODE_SINGLE_CHAN,
+	MODE_SINGLE_CHAN_INTERVAL,
+	MODE_MULT_CHAN_UP,
+	MODE_MULT_CHAN_DOWN,
+};
+
 static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 static irqreturn_t labpc_interrupt(int irq, void *d);
 static int labpc_drain_fifo(struct comedi_device *dev);
@@ -240,12 +243,10 @@
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn,
 				   unsigned int *data);
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+			     enum scan_mode scan_mode);
 #ifdef CONFIG_ISA_DMA_API
-static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd);
-#endif
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-static int labpc_find_device(struct comedi_device *dev, int bus, int slot);
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd);
 #endif
 static int labpc_dio_mem_callback(int dir, int port, int data,
 				  unsigned long arg);
@@ -261,13 +262,6 @@
 static void write_caldac(struct comedi_device *dev, unsigned int channel,
 			 unsigned int value);
 
-enum scan_mode {
-	MODE_SINGLE_CHAN,
-	MODE_SINGLE_CHAN_INTERVAL,
-	MODE_MULT_CHAN_UP,
-	MODE_MULT_CHAN_DOWN,
-};
-
 /* analog input ranges */
 #define NUM_LABPC_PLUS_AI_RANGES 16
 /* indicates unipolar ranges */
@@ -416,12 +410,12 @@
 
 static inline unsigned int labpc_readb(unsigned long address)
 {
-	return readb((void *)address);
+	return readb((void __iomem *)address);
 }
 
 static inline void labpc_writeb(unsigned int byte, unsigned long address)
 {
-	writeb(byte, (void *)address);
+	writeb(byte, (void __iomem *)address);
 }
 
 static const struct labpc_board_struct labpc_boards[] = {
@@ -495,33 +489,14 @@
 
 #define devpriv ((struct labpc_private *)dev->private)
 
-static struct comedi_driver driver_labpc = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = labpc_attach,
-	.detach = labpc_common_detach,
-	.num_names = ARRAY_SIZE(labpc_boards),
-	.board_name = &labpc_boards[0].name,
-	.offset = sizeof(struct labpc_board_struct),
-};
-
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, labpc_pci_table);
-#endif /* CONFIG_COMEDI_PCI_DRIVERS */
-
 static inline int labpc_counter_load(struct comedi_device *dev,
 				     unsigned long base_address,
 				     unsigned int counter_number,
 				     unsigned int count, unsigned int mode)
 {
 	if (thisboard->memory_mapped_io)
-		return i8254_mm_load((void *)base_address, 0, counter_number,
-				     count, mode);
+		return i8254_mm_load((void __iomem *)base_address, 0,
+				     counter_number, count, mode);
 	else
 		return i8254_load(base_address, 0, counter_number, count, mode);
 }
@@ -538,25 +513,16 @@
 	short lsb, msb;
 	int ret;
 
-	printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor,
-								thisboard->name,
-	       iobase);
-	if (irq)
-		printk(", irq %u", irq);
-	if (dma_chan)
-		printk(", dma %u", dma_chan);
-	printk("\n");
-
+	dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name);
 	if (iobase == 0) {
-		printk(KERN_ERR "io base address is zero!\n");
+		dev_err(dev->class_dev, "io base address is zero!\n");
 		return -EINVAL;
 	}
 	/*  request io regions for isa boards */
 	if (thisboard->bustype == isa_bustype) {
 		/* check if io addresses are available */
-		if (!request_region(iobase, LABPC_SIZE,
-				    driver_labpc.driver_name)) {
-			printk(KERN_ERR "I/O port conflict\n");
+		if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) {
+			dev_err(dev->class_dev, "I/O port conflict\n");
 			return -EIO;
 		}
 	}
@@ -588,8 +554,9 @@
 		    || thisboard->bustype == pcmcia_bustype)
 			isr_flags |= IRQF_SHARED;
 		if (request_irq(irq, labpc_interrupt, isr_flags,
-				driver_labpc.driver_name, dev)) {
-			printk(KERN_ERR "unable to allocate irq %u\n", irq);
+				DRV_NAME, dev)) {
+			dev_err(dev->class_dev, "unable to allocate irq %u\n",
+				irq);
 			return -EINVAL;
 		}
 	}
@@ -598,19 +565,21 @@
 #ifdef CONFIG_ISA_DMA_API
 	/* grab dma channel */
 	if (dma_chan > 3) {
-		printk(KERN_ERR " invalid dma channel %u\n", dma_chan);
+		dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan);
 		return -EINVAL;
 	} else if (dma_chan) {
 		/* allocate dma buffer */
 		devpriv->dma_buffer =
 		    kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
 		if (devpriv->dma_buffer == NULL) {
-			printk(KERN_ERR " failed to allocate dma buffer\n");
+			dev_err(dev->class_dev,
+				"failed to allocate dma buffer\n");
 			return -ENOMEM;
 		}
-		if (request_dma(dma_chan, driver_labpc.driver_name)) {
-			printk(KERN_ERR " failed to allocate dma channel %u\n",
-			       dma_chan);
+		if (request_dma(dma_chan, DRV_NAME)) {
+			dev_err(dev->class_dev,
+				"failed to allocate dma channel %u\n",
+				dma_chan);
 			return -EINVAL;
 		}
 		devpriv->dma_chan = dma_chan;
@@ -628,7 +597,7 @@
 		return ret;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags =
@@ -643,7 +612,7 @@
 	s->cancel = labpc_cancel;
 
 	/* analog output */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (thisboard->has_ao) {
 		/*
 		 * Could provide command support, except it only has a
@@ -670,7 +639,7 @@
 	}
 
 	/* 8255 dio */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/*  if board uses io memory we have to give a custom callback
 	 * function to the 8255 driver */
 	if (thisboard->memory_mapped_io)
@@ -680,7 +649,7 @@
 		subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
 
 	/*  calibration subdevices for boards that have one */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	if (thisboard->register_layout == labpc_1200_layout) {
 		s->type = COMEDI_SUBD_CALIB;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
@@ -695,7 +664,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 
 	/* EEPROM */
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	if (thisboard->register_layout == labpc_1200_layout) {
 		s->type = COMEDI_SUBD_MEMORY;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
@@ -706,12 +675,6 @@
 
 		for (i = 0; i < EEPROM_SIZE; i++)
 			devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
-#ifdef LABPC_DEBUG
-		printk(KERN_ERR " eeprom:");
-		for (i = 0; i < EEPROM_SIZE; i++)
-			printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);
-		printk("\n");
-#endif
 	} else
 		s->type = COMEDI_SUBD_UNUSED;
 
@@ -719,14 +682,52 @@
 }
 EXPORT_SYMBOL_GPL(labpc_common_attach);
 
+static const struct labpc_board_struct *
+labpc_pci_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int device_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) {
+		const struct labpc_board_struct *board = &labpc_boards[n];
+		if (board->bustype == pci_bustype &&
+		    board->device_id == device_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit labpc_attach_pci(struct comedi_device *dev,
+				      struct pci_dev *pcidev)
+{
+	unsigned long iobase;
+	unsigned int irq;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
+		return -ENODEV;
+	ret = alloc_private(dev, sizeof(struct labpc_private));
+	if (ret < 0)
+		return ret;
+	dev->board_ptr = labpc_pci_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+	devpriv->mite = mite_alloc(pcidev);
+	if (!devpriv->mite)
+		return -ENOMEM;
+	ret = mite_setup(devpriv->mite);
+	if (ret < 0)
+		return ret;
+	iobase = (unsigned long)devpriv->mite->daq_io_addr;
+	irq = mite_irq(devpriv->mite);
+	return labpc_common_attach(dev, iobase, irq, 0);
+}
+
 static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	unsigned long iobase = 0;
 	unsigned int irq = 0;
 	unsigned int dma_chan = 0;
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-	int retval;
-#endif
 
 	/* allocate and initialize dev->private */
 	if (alloc_private(dev, sizeof(struct labpc_private)) < 0)
@@ -740,34 +741,26 @@
 		irq = it->options[1];
 		dma_chan = it->options[2];
 #else
-		printk(KERN_ERR " this driver has not been built with ISA DMA "
-								"support.\n");
+		dev_err(dev->class_dev,
+			"ni_labpc driver has not been built with ISA DMA support.\n");
 		return -EINVAL;
 #endif
 		break;
 	case pci_bustype:
 #ifdef CONFIG_COMEDI_PCI_DRIVERS
-		retval = labpc_find_device(dev, it->options[0], it->options[1]);
-		if (retval < 0)
-			return retval;
-		retval = mite_setup(devpriv->mite);
-		if (retval < 0)
-			return retval;
-		iobase = (unsigned long)devpriv->mite->daq_io_addr;
-		irq = mite_irq(devpriv->mite);
+		dev_err(dev->class_dev,
+			"manual configuration of PCI board '%s' is not supported\n",
+			thisboard->name);
+		return -EINVAL;
 #else
-		printk(KERN_ERR " this driver has not been built with PCI "
-								"support.\n");
+		dev_err(dev->class_dev,
+			"ni_labpc driver has not been built with PCI support.\n");
 		return -EINVAL;
 #endif
 		break;
-	case pcmcia_bustype:
-		printk
-		    (" this driver does not support pcmcia cards, use ni_labpc_cs.o\n");
-		return -EINVAL;
-		break;
 	default:
-		printk(KERN_ERR "bug! couldn't determine board type\n");
+		dev_err(dev->class_dev,
+			"ni_labpc: bug! couldn't determine board type\n");
 		return -EINVAL;
 		break;
 	}
@@ -775,42 +768,14 @@
 	return labpc_common_attach(dev, iobase, irq, dma_chan);
 }
 
-/* adapted from ni_pcimio for finding mite based boards (pc-1200) */
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-/* if bus/slot are specified then make sure we have the right bus/slot */
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number
-			    || slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-		for (i = 0; i < driver_labpc.num_names; i++) {
-			if (labpc_boards[i].bustype != pci_bustype)
-				continue;
-			if (mite_device_id(mite) == labpc_boards[i].device_id) {
-				devpriv->mite = mite;
-/* fixup board pointer, in case we were using the dummy "ni_labpc" entry */
-				dev->board_ptr = &labpc_boards[i];
-				return 0;
-			}
-		}
-	}
-	printk(KERN_ERR "no device found\n");
-	mite_list_devices();
-	return -EIO;
-}
-#endif
-
 void labpc_common_detach(struct comedi_device *dev)
 {
-	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
+	struct comedi_subdevice *s;
+
+	if (dev->subdevices) {
+		s = &dev->subdevices[2];
+		subdev_8255_cleanup(dev, s);
+	}
 #ifdef CONFIG_ISA_DMA_API
 	/* only free stuff if it has been allocated by _attach */
 	kfree(devpriv->dma_buffer);
@@ -822,8 +787,10 @@
 	if (thisboard->bustype == isa_bustype && dev->iobase)
 		release_region(dev->iobase, LABPC_SIZE);
 #ifdef CONFIG_COMEDI_PCI_DRIVERS
-	if (devpriv->mite)
+	if (devpriv->mite) {
 		mite_unsetup(devpriv->mite);
+		mite_free(devpriv->mite);
+	}
 #endif
 };
 EXPORT_SYMBOL_GPL(labpc_common_detach);
@@ -868,21 +835,19 @@
 	if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1]))
 		return MODE_MULT_CHAN_DOWN;
 
-	printk(KERN_ERR "ni_labpc: bug! this should never happen\n");
-
+	pr_err("ni_labpc: bug! cannot determine AI scan mode\n");
 	return 0;
 }
 
 static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
-				     const struct comedi_cmd *cmd)
+				     const struct comedi_cmd *cmd,
+				     enum scan_mode mode)
 {
-	int mode, channel, range, aref, i;
+	int channel, range, aref, i;
 
 	if (cmd->chanlist == NULL)
 		return 0;
 
-	mode = labpc_ai_scan_mode(cmd);
-
 	if (mode == MODE_SINGLE_CHAN)
 		return 0;
 
@@ -924,7 +889,8 @@
 			}
 			break;
 		default:
-			printk(KERN_ERR "ni_labpc: bug! in chanlist check\n");
+			dev_err(dev->class_dev,
+				"ni_labpc: bug! in chanlist check\n");
 			return 1;
 			break;
 		}
@@ -945,9 +911,10 @@
 	return 0;
 }
 
-static int labpc_use_continuous_mode(const struct comedi_cmd *cmd)
+static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+				     enum scan_mode mode)
 {
-	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN)
+	if (mode == MODE_SINGLE_CHAN)
 		return 1;
 
 	if (cmd->scan_begin_src == TRIG_FOLLOW)
@@ -956,24 +923,25 @@
 	return 0;
 }
 
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd)
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+					    enum scan_mode mode)
 {
 	if (cmd->convert_src != TRIG_TIMER)
 		return 0;
 
-	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
-	    cmd->scan_begin_src == TRIG_TIMER)
+	if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
 		return cmd->scan_begin_arg;
 
 	return cmd->convert_arg;
 }
 
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns)
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+					enum scan_mode mode, unsigned int ns)
 {
 	if (cmd->convert_src != TRIG_TIMER)
 		return;
 
-	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
+	if (mode == MODE_SINGLE_CHAN &&
 	    cmd->scan_begin_src == TRIG_TIMER) {
 		cmd->scan_begin_arg = ns;
 		if (cmd->convert_arg > cmd->scan_begin_arg)
@@ -982,25 +950,25 @@
 		cmd->convert_arg = ns;
 }
 
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd)
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+					enum scan_mode mode)
 {
 	if (cmd->scan_begin_src != TRIG_TIMER)
 		return 0;
 
-	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
-	    cmd->convert_src == TRIG_TIMER)
+	if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
 		return 0;
 
 	return cmd->scan_begin_arg;
 }
 
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, unsigned int ns)
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+				     enum scan_mode mode, unsigned int ns)
 {
 	if (cmd->scan_begin_src != TRIG_TIMER)
 		return;
 
-	if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
-	    cmd->convert_src == TRIG_TIMER)
+	if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
 		return;
 
 	cmd->scan_begin_arg = ns;
@@ -1011,54 +979,33 @@
 {
 	int err = 0;
 	int tmp, tmp2;
-	int stop_mask;
+	unsigned int stop_mask;
+	enum scan_mode mode;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
 	stop_mask = TRIG_COUNT | TRIG_NONE;
 	if (thisboard->register_layout == labpc_1200_layout)
 		stop_mask |= TRIG_EXT;
-	cmd->stop_src &= stop_mask;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT &&
-	    cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	/* can't have external stop and start triggers at once */
 	if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
@@ -1133,14 +1080,15 @@
 
 	tmp = cmd->convert_arg;
 	tmp2 = cmd->scan_begin_arg;
-	labpc_adc_timing(dev, cmd);
+	mode = labpc_ai_scan_mode(cmd);
+	labpc_adc_timing(dev, cmd, mode);
 	if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg)
 		err++;
 
 	if (err)
 		return 4;
 
-	if (labpc_ai_chanlist_invalid(dev, cmd))
+	if (labpc_ai_chanlist_invalid(dev, cmd, mode))
 		return 5;
 
 	return 0;
@@ -1156,6 +1104,7 @@
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
 	enum transfer_type xfer;
+	enum scan_mode mode;
 	unsigned long flags;
 
 	if (!dev->irq) {
@@ -1221,6 +1170,7 @@
 	} else
 		xfer = fifo_not_empty_transfer;
 	devpriv->current_transfer = xfer;
+	mode = labpc_ai_scan_mode(cmd);
 
 	/*  setup command6 register for 1200 boards */
 	if (thisboard->register_layout == labpc_1200_layout) {
@@ -1245,7 +1195,7 @@
 		else
 			devpriv->command6_bits &= ~A1_INTR_EN_BIT;
 		/*  are we scanning up or down through channels? */
-		if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
+		if (mode == MODE_MULT_CHAN_UP)
 			devpriv->command6_bits |= ADC_SCAN_UP_BIT;
 		else
 			devpriv->command6_bits &= ~ADC_SCAN_UP_BIT;
@@ -1256,19 +1206,18 @@
 
 	/* setup channel list, etc (command1 register) */
 	devpriv->command1_bits = 0;
-	if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
+	if (mode == MODE_MULT_CHAN_UP)
 		channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
 	else
 		channel = CR_CHAN(cmd->chanlist[0]);
 	/* munge channel bits for differential / scan disabled mode */
-	if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF)
+	if (mode != MODE_SINGLE_CHAN && aref == AREF_DIFF)
 		channel *= 2;
 	devpriv->command1_bits |= ADC_CHAN_BITS(channel);
 	devpriv->command1_bits |= thisboard->ai_range_code[range];
 	devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
 	/* manual says to set scan enable bit on second pass */
-	if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP ||
-	    labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) {
+	if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
 		devpriv->command1_bits |= ADC_SCAN_EN_BIT;
 		/* need a brief delay before enabling scan, or scan
 		 * list will get screwed when you switch
@@ -1283,7 +1232,7 @@
 		devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
 	/* XXX should discard first scan when using interval scanning
 	 * since manual says it is not synced with scan clock */
-	if (labpc_use_continuous_mode(cmd) == 0) {
+	if (labpc_use_continuous_mode(cmd, mode) == 0) {
 		devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT;
 		if (cmd->scan_begin_src == TRIG_EXT)
 			devpriv->command4_bits |= EXT_SCAN_EN_BIT;
@@ -1301,7 +1250,7 @@
 
 	if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) {
 		/*  set up pacing */
-		labpc_adc_timing(dev, cmd);
+		labpc_adc_timing(dev, cmd, mode);
 		/*  load counter b0 in mode 3 */
 		ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
 					 0, devpriv->divisor_b0, 3);
@@ -1311,7 +1260,7 @@
 		}
 	}
 	/*  set up conversion pacing */
-	if (labpc_ai_convert_period(cmd)) {
+	if (labpc_ai_convert_period(cmd, mode)) {
 		/*  load counter a0 in mode 2 */
 		ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
 					 0, devpriv->divisor_a0, 2);
@@ -1324,7 +1273,7 @@
 				    dev->iobase + COUNTER_A_CONTROL_REG);
 
 	/*  set up scan pacing */
-	if (labpc_ai_scan_period(cmd)) {
+	if (labpc_ai_scan_period(cmd, mode)) {
 		/*  load counter b1 in mode 2 */
 		ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
 					 1, devpriv->divisor_b1, 2);
@@ -1347,7 +1296,7 @@
 		set_dma_addr(devpriv->dma_chan,
 			     virt_to_bus(devpriv->dma_buffer));
 		/*  set appropriate size of transfer */
-		devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd);
+		devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
 		if (cmd->stop_src == TRIG_COUNT &&
 		    devpriv->count * sample_size < devpriv->dma_transfer_size) {
 			devpriv->dma_transfer_size =
@@ -1786,8 +1735,8 @@
 
 	/*  only allow writes to user area of eeprom */
 	if (channel < 16 || channel > 127) {
-		printk
-		    ("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)");
+		dev_dbg(dev->class_dev,
+			"eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n");
 		return -EINVAL;
 	}
 
@@ -1800,13 +1749,13 @@
 
 #ifdef CONFIG_ISA_DMA_API
 /* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd)
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
 {
 	unsigned int size;
 	unsigned int freq;
 
-	if (cmd.convert_src == TRIG_TIMER)
-		freq = 1000000000 / cmd.convert_arg;
+	if (cmd->convert_src == TRIG_TIMER)
+		freq = 1000000000 / cmd->convert_arg;
 	/* return some default value */
 	else
 		freq = 0xffffffff;
@@ -1825,24 +1774,29 @@
 #endif
 
 /* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+			     enum scan_mode mode)
 {
 	/* max value for 16 bit counter in mode 2 */
 	const int max_counter_value = 0x10000;
 	/* min value for 16 bit counter in mode 2 */
 	const int min_counter_value = 2;
 	unsigned int base_period;
+	unsigned int scan_period;
+	unsigned int convert_period;
 
 	/*
 	 * if both convert and scan triggers are TRIG_TIMER, then they
 	 * both rely on counter b0
 	 */
-	if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) {
+	convert_period = labpc_ai_convert_period(cmd, mode);
+	scan_period = labpc_ai_scan_period(cmd, mode);
+	if (convert_period && scan_period) {
 		/*
 		 * pick the lowest b0 divisor value we can (for maximum input
 		 * clock speed on convert and scan counters)
 		 */
-		devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) /
+		devpriv->divisor_b0 = (scan_period - 1) /
 		    (LABPC_TIMER_BASE * max_counter_value) + 1;
 		if (devpriv->divisor_b0 < min_counter_value)
 			devpriv->divisor_b0 = min_counter_value;
@@ -1856,25 +1810,19 @@
 		default:
 		case TRIG_ROUND_NEAREST:
 			devpriv->divisor_a0 =
-			    (labpc_ai_convert_period(cmd) +
-			     (base_period / 2)) / base_period;
+			    (convert_period + (base_period / 2)) / base_period;
 			devpriv->divisor_b1 =
-			    (labpc_ai_scan_period(cmd) +
-			     (base_period / 2)) / base_period;
+			    (scan_period + (base_period / 2)) / base_period;
 			break;
 		case TRIG_ROUND_UP:
 			devpriv->divisor_a0 =
-			    (labpc_ai_convert_period(cmd) + (base_period -
-							     1)) / base_period;
+			    (convert_period + (base_period - 1)) / base_period;
 			devpriv->divisor_b1 =
-			    (labpc_ai_scan_period(cmd) + (base_period -
-							  1)) / base_period;
+			    (scan_period + (base_period - 1)) / base_period;
 			break;
 		case TRIG_ROUND_DOWN:
-			devpriv->divisor_a0 =
-			    labpc_ai_convert_period(cmd) / base_period;
-			devpriv->divisor_b1 =
-			    labpc_ai_scan_period(cmd) / base_period;
+			devpriv->divisor_a0 = convert_period / base_period;
+			devpriv->divisor_b1 = scan_period / base_period;
 			break;
 		}
 		/*  make sure a0 and b1 values are acceptable */
@@ -1887,18 +1835,15 @@
 		if (devpriv->divisor_b1 > max_counter_value)
 			devpriv->divisor_b1 = max_counter_value;
 		/*  write corrected timings to command */
-		labpc_set_ai_convert_period(cmd,
+		labpc_set_ai_convert_period(cmd, mode,
 					    base_period * devpriv->divisor_a0);
-		labpc_set_ai_scan_period(cmd,
+		labpc_set_ai_scan_period(cmd, mode,
 					 base_period * devpriv->divisor_b1);
 		/*
 		 * if only one TRIG_TIMER is used, we can employ the generic
 		 * cascaded timing functions
 		 */
-	} else if (labpc_ai_scan_period(cmd)) {
-		unsigned int scan_period;
-
-		scan_period = labpc_ai_scan_period(cmd);
+	} else if (scan_period) {
 		/*
 		 * calculate cascaded counter values
 		 * that give desired scan timing
@@ -1908,11 +1853,8 @@
 					       &(devpriv->divisor_b0),
 					       &scan_period,
 					       cmd->flags & TRIG_ROUND_MASK);
-		labpc_set_ai_scan_period(cmd, scan_period);
-	} else if (labpc_ai_convert_period(cmd)) {
-		unsigned int convert_period;
-
-		convert_period = labpc_ai_convert_period(cmd);
+		labpc_set_ai_scan_period(cmd, mode, scan_period);
+	} else if (convert_period) {
 		/*
 		 * calculate cascaded counter values
 		 * that give desired conversion timing
@@ -1922,7 +1864,7 @@
 					       &(devpriv->divisor_b0),
 					       &convert_period,
 					       cmd->flags & TRIG_ROUND_MASK);
-		labpc_set_ai_convert_period(cmd, convert_period);
+		labpc_set_ai_convert_period(cmd, mode, convert_period);
 	}
 }
 
@@ -1930,10 +1872,10 @@
 				  unsigned long iobase)
 {
 	if (dir) {
-		writeb(data, (void *)(iobase + port));
+		writeb(data, (void __iomem *)(iobase + port));
 		return 0;
 	} else {
-		return readb((void *)(iobase + port));
+		return readb((void __iomem *)(iobase + port));
 	}
 }
 
@@ -2136,57 +2078,44 @@
 	devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
 }
 
+static struct comedi_driver labpc_driver = {
+	.driver_name = DRV_NAME,
+	.module = THIS_MODULE,
+	.attach = labpc_attach,
+	.attach_pci = labpc_attach_pci,
+	.detach = labpc_common_detach,
+	.num_names = ARRAY_SIZE(labpc_boards),
+	.board_name = &labpc_boards[0].name,
+	.offset = sizeof(struct labpc_board_struct),
+};
+
 #ifdef CONFIG_COMEDI_PCI_DRIVERS
-static int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
-					    const struct pci_device_id *ent)
+static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, labpc_pci_table);
+
+static int __devinit labpc_pci_probe(struct pci_dev *dev,
+				     const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_labpc);
+	return comedi_pci_auto_config(dev, &labpc_driver);
 }
 
-static void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
+static void __devexit labpc_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_labpc_pci_driver = {
+static struct pci_driver labpc_pci_driver = {
+	.name = DRV_NAME,
 	.id_table = labpc_pci_table,
-	.probe = &driver_labpc_pci_probe,
-	.remove = __devexit_p(&driver_labpc_pci_remove)
+	.probe = labpc_pci_probe,
+	.remove = __devexit_p(labpc_pci_remove)
 };
-
-static int __init driver_labpc_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_labpc);
-	if (retval < 0)
-		return retval;
-
-	driver_labpc_pci_driver.name = (char *)driver_labpc.driver_name;
-	return pci_register_driver(&driver_labpc_pci_driver);
-}
-
-static void __exit driver_labpc_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_labpc_pci_driver);
-	comedi_driver_unregister(&driver_labpc);
-}
-
-module_init(driver_labpc_init_module);
-module_exit(driver_labpc_cleanup_module);
+module_comedi_pci_driver(labpc_driver, labpc_pci_driver);
 #else
-static int __init driver_labpc_init_module(void)
-{
-	return comedi_driver_register(&driver_labpc);
-}
-
-static void __exit driver_labpc_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_labpc);
-}
-
-module_init(driver_labpc_init_module);
-module_exit(driver_labpc_cleanup_module);
+module_comedi_driver(labpc_driver);
 #endif
 
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index dbb61b6..eb0417e 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -270,7 +270,7 @@
 MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC");
 MODULE_LICENSE("GPL");
 
-struct pcmcia_driver labpc_cs_driver = {
+static struct pcmcia_driver labpc_cs_driver = {
 	.probe = labpc_cs_attach,
 	.remove = labpc_cs_detach,
 	.suspend = labpc_cs_suspend,
@@ -291,7 +291,7 @@
 	pcmcia_unregister_driver(&labpc_cs_driver);
 }
 
-int __init labpc_init_module(void)
+static int __init labpc_init_module(void)
 {
 	int ret;
 
@@ -302,7 +302,7 @@
 	return comedi_driver_register(&driver_labpc_cs);
 }
 
-void __exit labpc_exit_module(void)
+static void __exit labpc_exit_module(void)
 {
 	exit_labpc_cs();
 	comedi_driver_unregister(&driver_labpc_cs);
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index cf0e0d14..3e5fdae 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -644,10 +644,10 @@
 #endif /*  PCIDMA */
 }
 
-void ni_release_gpct_mite_channel(struct comedi_device *dev,
-				  unsigned gpct_index)
-{
 #ifdef PCIDMA
+static void ni_release_gpct_mite_channel(struct comedi_device *dev,
+					 unsigned gpct_index)
+{
 	unsigned long flags;
 
 	BUG_ON(gpct_index >= NUM_GPCT);
@@ -663,8 +663,8 @@
 		mite_release_channel(mite_chan);
 	}
 	spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
-#endif /*  PCIDMA */
 }
+#endif /*  PCIDMA */
 
 static void ni_release_cdo_mite_channel(struct comedi_device *dev)
 {
@@ -872,7 +872,7 @@
 #ifdef PCIDMA
 static void ni_sync_ai_dma(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 	unsigned long flags;
 
 	spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
@@ -884,7 +884,7 @@
 static void mite_handle_b_linkc(struct mite_struct *mite,
 				struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV];
 	unsigned long flags;
 
 	spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
@@ -942,7 +942,7 @@
 
 static void shutdown_ai_command(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 
 #ifdef PCIDMA
 	ni_ai_drain_dma(dev);
@@ -984,8 +984,9 @@
 				  unsigned short counter_index)
 {
 #ifdef PCIDMA
-	struct comedi_subdevice *s =
-	    dev->subdevices + NI_GPCT_SUBDEV(counter_index);
+	struct comedi_subdevice *s;
+
+	s = &dev->subdevices[NI_GPCT_SUBDEV(counter_index)];
 
 	ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index],
 				s);
@@ -1018,7 +1019,7 @@
 static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
 			       unsigned ai_mite_status)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 
 	/* 67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt */
 	if (s->type == COMEDI_SUBD_UNUSED)
@@ -1150,7 +1151,7 @@
 static void handle_b_interrupt(struct comedi_device *dev,
 			       unsigned short b_status, unsigned ao_mite_status)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV];
 	/* unsigned short ack=0; */
 #ifdef DEBUG_INTERRUPT
 	printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
@@ -1422,7 +1423,7 @@
 static void ni_handle_fifo_half_full(struct comedi_device *dev)
 {
 	int n;
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 
 	n = boardtype.ai_fifo_depth / 2;
 
@@ -1470,7 +1471,7 @@
 */
 static void ni_handle_fifo_dregs(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 	short data[2];
 	u32 dl;
 	short fifo_empty;
@@ -1534,7 +1535,7 @@
 
 static void get_last_sample_611x(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 	short data;
 	u32 dl;
 
@@ -1551,7 +1552,7 @@
 
 static void get_last_sample_6143(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 	short data;
 	u32 dl;
 
@@ -1598,7 +1599,7 @@
 
 static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
 	int retval;
 	unsigned long flags;
 
@@ -1637,7 +1638,7 @@
 
 static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
 {
-	struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV];
 	int retval;
 	unsigned long flags;
 
@@ -1765,20 +1766,18 @@
 
 static int ni_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 	int count;
 
 	/*  lock to avoid race with interrupt handler */
-	if (in_interrupt() == 0)
-		spin_lock_irqsave(&dev->spinlock, flags);
+	spin_lock_irqsave(&dev->spinlock, flags);
 #ifndef PCIDMA
 	ni_handle_fifo_dregs(dev);
 #else
 	ni_sync_ai_dma(dev);
 #endif
 	count = s->async->buf_write_count - s->async->buf_read_count;
-	if (in_interrupt() == 0)
-		spin_unlock_irqrestore(&dev->spinlock, flags);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
 
 	return count;
 }
@@ -1880,7 +1879,7 @@
 	return insn->n;
 }
 
-void ni_prime_channelgain_list(struct comedi_device *dev)
+static void ni_prime_channelgain_list(struct comedi_device *dev)
 {
 	int i;
 	devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
@@ -2165,61 +2164,38 @@
 {
 	int err = 0;
 	int tmp;
-	int sources;
+	unsigned int sources;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	if ((cmd->flags & CMDF_WRITE)) {
+	if ((cmd->flags & CMDF_WRITE))
 		cmd->flags &= ~CMDF_WRITE;
-	}
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src,
+					TRIG_NOW | TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
 	sources = TRIG_TIMER | TRIG_EXT;
-	if ((boardtype.reg_type == ni_reg_611x)
-	    || (boardtype.reg_type == ni_reg_6143))
+	if (boardtype.reg_type == ni_reg_611x ||
+	    boardtype.reg_type == ni_reg_6143)
 		sources |= TRIG_NOW;
-	cmd->convert_src &= sources;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, sources);
 
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->start_src != TRIG_NOW &&
-	    cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_OTHER)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -3357,44 +3333,28 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	if ((cmd->flags & CMDF_WRITE) == 0) {
+	if ((cmd->flags & CMDF_WRITE) == 0)
 		cmd->flags |= CMDF_WRITE;
-	}
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_INT | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -3644,51 +3604,21 @@
 {
 	int err = 0;
 	int tmp;
-	int sources;
 	unsigned i;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	sources = TRIG_INT;
-	cmd->start_src &= sources;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique... */
-
-	if (cmd->start_src != TRIG_INT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_NONE)
-		err++;
-	/* ... and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -3852,7 +3782,7 @@
 static void handle_cdio_interrupt(struct comedi_device *dev)
 {
 	unsigned cdio_status;
-	struct comedi_subdevice *s = dev->subdevices + NI_DIO_SUBDEV;
+	struct comedi_subdevice *s = &dev->subdevices[NI_DIO_SUBDEV];
 #ifdef PCIDMA
 	unsigned long flags;
 #endif
@@ -4101,13 +4031,17 @@
 
 static void mio_common_detach(struct comedi_device *dev)
 {
+	struct comedi_subdevice *s;
+
 	if (dev->private) {
 		if (devpriv->counter_dev) {
 			ni_gpct_device_destroy(devpriv->counter_dev);
 		}
 	}
-	if (dev->subdevices && boardtype.has_8255)
-		subdev_8255_cleanup(dev, dev->subdevices + NI_8255_DIO_SUBDEV);
+	if (dev->subdevices && boardtype.has_8255) {
+		s = &dev->subdevices[NI_8255_DIO_SUBDEV];
+		subdev_8255_cleanup(dev, s);
+	}
 }
 
 static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -4399,7 +4333,7 @@
 	return 0;
 };
 
-static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it)
+static int ni_E_init(struct comedi_device *dev)
 {
 	struct comedi_subdevice *s;
 	unsigned j;
@@ -4417,7 +4351,7 @@
 
 	/* analog input subdevice */
 
-	s = dev->subdevices + NI_AI_SUBDEV;
+	s = &dev->subdevices[NI_AI_SUBDEV];
 	dev->read_subdev = s;
 	if (boardtype.n_adchan) {
 		s->type = COMEDI_SUBD_AI;
@@ -4449,7 +4383,7 @@
 
 	/* analog output subdevice */
 
-	s = dev->subdevices + NI_AO_SUBDEV;
+	s = &dev->subdevices[NI_AO_SUBDEV];
 	if (boardtype.n_aochan) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
@@ -4488,7 +4422,7 @@
 
 	/* digital i/o subdevice */
 
-	s = dev->subdevices + NI_DIO_SUBDEV;
+	s = &dev->subdevices[NI_DIO_SUBDEV];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 	s->maxdata = 1;
@@ -4516,7 +4450,7 @@
 	}
 
 	/* 8255 device */
-	s = dev->subdevices + NI_8255_DIO_SUBDEV;
+	s = &dev->subdevices[NI_8255_DIO_SUBDEV];
 	if (boardtype.has_8255) {
 		subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev);
 	} else {
@@ -4524,11 +4458,11 @@
 	}
 
 	/* formerly general purpose counter/timer device, but no longer used */
-	s = dev->subdevices + NI_UNUSED_SUBDEV;
+	s = &dev->subdevices[NI_UNUSED_SUBDEV];
 	s->type = COMEDI_SUBD_UNUSED;
 
 	/* calibration subdevice -- ai and ao */
-	s = dev->subdevices + NI_CALIBRATION_SUBDEV;
+	s = &dev->subdevices[NI_CALIBRATION_SUBDEV];
 	s->type = COMEDI_SUBD_CALIB;
 	if (boardtype.reg_type & ni_reg_m_series_mask) {
 		/*  internal PWM analog output used for AI nonlinearity calibration */
@@ -4551,7 +4485,7 @@
 	}
 
 	/* EEPROM */
-	s = dev->subdevices + NI_EEPROM_SUBDEV;
+	s = &dev->subdevices[NI_EEPROM_SUBDEV];
 	s->type = COMEDI_SUBD_MEMORY;
 	s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
 	s->maxdata = 0xff;
@@ -4564,7 +4498,7 @@
 	}
 
 	/* PFI */
-	s = dev->subdevices + NI_PFI_DIO_SUBDEV;
+	s = &dev->subdevices[NI_PFI_DIO_SUBDEV];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	if (boardtype.reg_type & ni_reg_m_series_mask) {
@@ -4586,7 +4520,7 @@
 	ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0);
 
 	/* cs5529 calibration adc */
-	s = dev->subdevices + NI_CS5529_CALIBRATION_SUBDEV;
+	s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV];
 	if (boardtype.reg_type & ni_reg_67xx_mask) {
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL;
@@ -4602,7 +4536,7 @@
 	}
 
 	/* Serial */
-	s = dev->subdevices + NI_SERIAL_SUBDEV;
+	s = &dev->subdevices[NI_SERIAL_SUBDEV];
 	s->type = COMEDI_SUBD_SERIAL;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	s->n_chan = 1;
@@ -4612,7 +4546,7 @@
 	devpriv->serial_hw_mode = 0;
 
 	/* RTSI */
-	s = dev->subdevices + NI_RTSI_SUBDEV;
+	s = &dev->subdevices[NI_RTSI_SUBDEV];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 	s->n_chan = 8;
@@ -4633,7 +4567,7 @@
 							NUM_GPCT);
 	/* General purpose counters */
 	for (j = 0; j < NUM_GPCT; ++j) {
-		s = dev->subdevices + NI_GPCT_SUBDEV(j);
+		s = &dev->subdevices[NI_GPCT_SUBDEV(j)];
 		s->type = COMEDI_SUBD_COUNTER;
 		s->subdev_flags =
 		    SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ
@@ -4659,7 +4593,7 @@
 	}
 
 	/* Frequency output */
-	s = dev->subdevices + NI_FREQ_OUT_SUBDEV;
+	s = &dev->subdevices[NI_FREQ_OUT_SUBDEV];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 1;
@@ -4669,7 +4603,8 @@
 	s->insn_config = &ni_freq_out_insn_config;
 
 	/* ai configuration */
-	ni_ai_reset(dev, dev->subdevices + NI_AI_SUBDEV);
+	s = &dev->subdevices[NI_AI_SUBDEV];
+	ni_ai_reset(dev, s);
 	if ((boardtype.reg_type & ni_reg_6xxx_mask) == 0) {
 		/*  BEAM is this needed for PCI-6143 ?? */
 		devpriv->clock_and_fout =
@@ -4688,7 +4623,8 @@
 			    Clock_and_FOUT_Register);
 
 	/* analog output configuration */
-	ni_ao_reset(dev, dev->subdevices + NI_AO_SUBDEV);
+	s = &dev->subdevices[NI_AO_SUBDEV];
+	ni_ao_reset(dev, s);
 
 	if (dev->irq) {
 		devpriv->stc_writew(dev,
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index b85765d..ca4f8e0 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -382,7 +382,7 @@
 	devpriv->stc_writel = &win_out2;
 	devpriv->stc_readl = &win_in2;
 
-	ret = ni_E_init(dev, it);
+	ret = ni_E_init(dev);
 
 	if (ret < 0)
 		return ret;
@@ -421,7 +421,7 @@
 MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series");
 MODULE_LICENSE("GPL");
 
-struct pcmcia_driver ni_mio_cs_driver = {
+static struct pcmcia_driver ni_mio_cs_driver = {
 	.probe = &cs_attach,
 	.remove = &cs_detach,
 	.suspend = &mio_cs_suspend,
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 0a55de9..bc9313e 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -1,8 +1,6 @@
 /*
     comedi/drivers/ni_pcidio.c
-    driver for National Instruments PCI-DIO-96/PCI-6508
-		National Instruments PCI-DIO-32HS
-		National Instruments PCI-6503
+    driver for National Instruments PCI-DIO-32HS
 
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 1999,2002 David A. Schleef <ds@schleef.org>
@@ -24,17 +22,14 @@
 */
 /*
 Driver: ni_pcidio
-Description: National Instruments PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503
+Description: National Instruments PCI-DIO32HS, PCI-6533
 Author: ds
 Status: works
-Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533,
-  PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
-  PXI-6503, PCI-6533, PCI-6534
+Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio)
+	 [National Instruments] PXI-6533, PCI-6533 (pxi-6533)
+	 [National Instruments] PCI-6534 (pci-6534)
 Updated: Mon, 09 Jan 2012 14:27:23 +0000
 
-The DIO-96 appears as four 8255 subdevices.  See the 8255
-driver notes for details.
-
 The DIO32HS board appears as one subdevice, with 32 channels.
 Each channel is individually I/O configurable.  The channel order
 is 0=A0, 1=A1, 2=A2, ... 8=B0, 16=C0, 24=D0.  The driver only
@@ -56,49 +51,28 @@
 comedi_nonfree_firmware tarball available from http://www.comedi.org
 */
 
-/*
-   This driver is for both the NI PCI-DIO-32HS and the PCI-DIO-96,
-   which have very different architectures.  But, since the '96 is
-   so simple, it is included here.
-
-   Manuals (available from ftp://ftp.natinst.com/support/manuals)
-
-	320938c.pdf	PCI-DIO-96/PXI-6508/PCI-6503 User Manual
-	321464b.pdf	AT/PCI-DIO-32HS User Manual
-	341329A.pdf	PCI-6533 Register-Level Programmer Manual
-	341330A.pdf	DAQ-DIO Technical Reference Manual
-
- */
-
 #define USE_DMA
 /* #define DEBUG 1 */
 /* #define DEBUG_FLAGS */
 
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/firmware.h>
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
 #include "mite.h"
-#include "8255.h"
 
 #undef DPRINTK
 #ifdef DEBUG
-#define DPRINTK(format, args...)	printk(format, ## args)
+#define DPRINTK(format, args...) pr_debug(format, ## args)
 #else
-#define DPRINTK(format, args...)
+#define DPRINTK(format, args...) do { } while (0)
 #endif
 
 #define PCI_DIO_SIZE 4096
 #define PCI_MITE_SIZE 4096
 
-/* defines for the PCI-DIO-96 */
-
-#define NIDIO_8255_BASE(x)	((x)*4)
-#define NIDIO_A 0
-#define NIDIO_B 4
-#define NIDIO_C 8
-#define NIDIO_D 12
-
 /* defines for the PCI-DIO-32HS */
 
 #define Window_Address			4	/* W */
@@ -258,6 +232,14 @@
 #define Protocol_Register_8		88	/* 32 bit */
 #define StartDelay			Protocol_Register_8
 
+/* Firmware files for PCI-6524 */
+#define FW_PCI_6534_MAIN		"ni6534a.bin"
+#define FW_PCI_6534_SCARAB_DI		"niscrb01.bin"
+#define FW_PCI_6534_SCARAB_DO		"niscrb02.bin"
+MODULE_FIRMWARE(FW_PCI_6534_MAIN);
+MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DI);
+MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DO);
+
 enum pci_6534_firmware_registers {	/* 16 bit */
 	Firmware_Control_Register = 0x100,
 	Firmware_Status_Register = 0x104,
@@ -297,76 +279,23 @@
 			    struct comedi_subdevice *s);
 
 struct nidio_board {
-
 	int dev_id;
 	const char *name;
-	int n_8255;
-	unsigned int is_diodaq:1;
 	unsigned int uses_firmware:1;
 };
 
 static const struct nidio_board nidio_boards[] = {
 	{
-	 .dev_id = 0x1150,
-	 .name = "pci-dio-32hs",
-	 .n_8255 = 0,
-	 .is_diodaq = 1,
-	 },
-	{
-	 .dev_id = 0x1320,
-	 .name = "pxi-6533",
-	 .n_8255 = 0,
-	 .is_diodaq = 1,
-	 },
-	{
-	 .dev_id = 0x12b0,
-	 .name = "pci-6534",
-	 .n_8255 = 0,
-	 .is_diodaq = 1,
-	 .uses_firmware = 1,
-	 },
-	{
-	 .dev_id = 0x0160,
-	 .name = "pci-dio-96",
-	 .n_8255 = 4,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x1630,
-	 .name = "pci-dio-96b",
-	 .n_8255 = 4,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x13c0,
-	 .name = "pxi-6508",
-	 .n_8255 = 4,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x0400,
-	 .name = "pci-6503",
-	 .n_8255 = 1,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x1250,
-	 .name = "pci-6503b",
-	 .n_8255 = 1,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x17d0,
-	 .name = "pci-6503x",
-	 .n_8255 = 1,
-	 .is_diodaq = 0,
-	 },
-	{
-	 .dev_id = 0x1800,
-	 .name = "pxi-6503",
-	 .n_8255 = 1,
-	 .is_diodaq = 0,
-	 },
+		.dev_id		= 0x1150,
+		.name		= "pci-dio-32hs",
+	}, {
+		.dev_id		= 0x1320,
+		.name		= "pxi-6533",
+	}, {
+		.dev_id		= 0x12b0,
+		.name		= "pci-6534",
+		.uses_firmware	= 1,
+	},
 };
 
 #define n_nidio_boards ARRAY_SIZE(nidio_boards)
@@ -442,17 +371,8 @@
 	spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 }
 
-static int nidio96_8255_cb(int dir, int port, int data, unsigned long iobase)
-{
-	if (dir) {
-		writeb(data, (void *)(iobase + port));
-		return 0;
-	} else {
-		return readb((void *)(iobase + port));
-	}
-}
-
-void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s)
+static void ni_pcidio_event(struct comedi_device *dev,
+			    struct comedi_subdevice *s)
 {
 	if (s->
 	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
@@ -480,7 +400,7 @@
 static irqreturn_t nidio_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	struct comedi_async *async = s->async;
 	struct mite_struct *mite = devpriv->mite;
 
@@ -511,18 +431,12 @@
 	ni_pcidio_print_flags(flags);
 	ni_pcidio_print_status(status);
 
-	/* printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); */
-	/* printk("buf[4096]=%08x\n",
-	       *(unsigned int *)(async->prealloc_buf+4096)); */
-
 	spin_lock(&devpriv->mite_channel_lock);
 	if (devpriv->di_mite_chan)
 		m_status = mite_get_status(devpriv->di_mite_chan);
 #ifdef MITE_DEBUG
 	mite_print_chsr(m_status);
 #endif
-	/* printk("mite_bytes_transferred: %d\n",
-	       mite_bytes_transferred(mite,DI_DMA_CHAN)); */
 
 	/* mite_dump_regs(mite); */
 	if (m_status & CHSR_INT) {
@@ -617,7 +531,7 @@
 		}
 #if 0
 		else {
-			printk("ni_pcidio: unknown interrupt\n");
+			DPRINTK("ni_pcidio: unknown interrupt\n");
 			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 			writeb(0x00,
 			       devpriv->mite->daq_io_addr +
@@ -648,38 +562,47 @@
 }
 
 #ifdef DEBUG_FLAGS
+static const char *bit_set_string(unsigned int bits, unsigned int bit,
+				  const char *const strings[])
+{
+	return (bits & (1U << bit)) ? strings[bit] : "";
+}
+
 static const char *const flags_strings[] = {
-	"TransferReady", "CountExpired", "2", "3",
-	"4", "Waited", "PrimaryTC", "SecondaryTC",
+	" TransferReady", " CountExpired", " 2", " 3",
+	" 4", " Waited", " PrimaryTC", " SecondaryTC",
 };
 
+
 static void ni_pcidio_print_flags(unsigned int flags)
 {
-	int i;
-
-	printk(KERN_INFO "group_1_flags:");
-	for (i = 7; i >= 0; i--) {
-		if (flags & (1 << i))
-			printk(" %s", flags_strings[i]);
-	}
-	printk("\n");
+	pr_debug("group_1_flags:%s%s%s%s%s%s%s%s\n",
+		 bit_set_string(flags, 7, flags_strings),
+		 bit_set_string(flags, 6, flags_strings),
+		 bit_set_string(flags, 5, flags_strings),
+		 bit_set_string(flags, 4, flags_strings),
+		 bit_set_string(flags, 3, flags_strings),
+		 bit_set_string(flags, 2, flags_strings),
+		 bit_set_string(flags, 1, flags_strings),
+		 bit_set_string(flags, 0, flags_strings));
 }
 
-static char *status_strings[] = {
-	"DataLeft1", "Reserved1", "Req1", "StopTrig1",
-	"DataLeft2", "Reserved2", "Req2", "StopTrig2",
+static const char *const status_strings[] = {
+	" DataLeft1", " Reserved1", " Req1", " StopTrig1",
+	" DataLeft2", " Reserved2", " Req2", " StopTrig2",
 };
 
 static void ni_pcidio_print_status(unsigned int flags)
 {
-	int i;
-
-	printk(KERN_INFO "group_status:");
-	for (i = 7; i >= 0; i--) {
-		if (flags & (1 << i))
-			printk(" %s", status_strings[i]);
-	}
-	printk("\n");
+	pr_debug("group_status:%s%s%s%s%s%s%s%s\n",
+		 bit_set_string(flags, 7, status_strings),
+		 bit_set_string(flags, 6, status_strings),
+		 bit_set_string(flags, 5, status_strings),
+		 bit_set_string(flags, 4, status_strings),
+		 bit_set_string(flags, 3, status_strings),
+		 bit_set_string(flags, 2, status_strings),
+		 bit_set_string(flags, 1, status_strings),
+		 bit_set_string(flags, 0, status_strings));
 }
 #endif
 
@@ -761,45 +684,25 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-	compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1065,10 +968,12 @@
 }
 
 static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index,
-			      u8 *data, int data_len)
+			      const u8 *data, size_t data_len)
 {
 	static const int timeout = 1000;
-	int i, j;
+	int i;
+	size_t j;
+
 	writew(0x80 | fpga_index,
 	       devpriv->mite->daq_io_addr + Firmware_Control_Register);
 	writew(0xc0 | fpga_index,
@@ -1079,8 +984,9 @@
 		udelay(1);
 	}
 	if (i == timeout) {
-		printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, "
-		       "waiting for status 0x2\n", fpga_index);
+		dev_warn(dev->class_dev,
+			 "ni_pcidio: failed to load fpga %i, waiting for status 0x2\n",
+			 fpga_index);
 		return -EIO;
 	}
 	writew(0x80 | fpga_index,
@@ -1091,8 +997,9 @@
 		udelay(1);
 	}
 	if (i == timeout) {
-		printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, "
-		       "waiting for status 0x3\n", fpga_index);
+		dev_warn(dev->class_dev,
+			 "ni_pcidio: failed to load fpga %i, waiting for status 0x3\n",
+			 fpga_index);
 		return -EIO;
 	}
 	for (j = 0; j + 1 < data_len;) {
@@ -1107,8 +1014,9 @@
 			udelay(1);
 		}
 		if (i == timeout) {
-			printk("ni_pcidio: failed to load word into fpga %i\n",
-			       fpga_index);
+			dev_warn(dev->class_dev,
+				 "ni_pcidio: failed to load word into fpga %i\n",
+				 fpga_index);
 			return -EIO;
 		}
 		if (need_resched())
@@ -1147,85 +1055,72 @@
 	writel(0, devpriv->mite->daq_io_addr + FPGA_SCBMS_Counter_Register);
 }
 
-static int pci_6534_upload_firmware(struct comedi_device *dev, int options[])
+static int pci_6534_upload_firmware(struct comedi_device *dev)
 {
 	int ret;
-	void *main_fpga_data, *scarab_a_data, *scarab_b_data;
-	int main_fpga_data_len, scarab_a_data_len, scarab_b_data_len;
+	const struct firmware *fw;
+	static const char *const fw_file[3] = {
+		FW_PCI_6534_SCARAB_DI,	/* loaded into scarab A for DI */
+		FW_PCI_6534_SCARAB_DO,	/* loaded into scarab B for DO */
+		FW_PCI_6534_MAIN,	/* loaded into main FPGA */
+	};
+	int n;
 
-	if (options[COMEDI_DEVCONF_AUX_DATA_LENGTH] == 0)
-		return 0;
 	ret = pci_6534_reset_fpgas(dev);
 	if (ret < 0)
 		return ret;
-	main_fpga_data = comedi_aux_data(options, 0);
-	main_fpga_data_len = options[COMEDI_DEVCONF_AUX_DATA0_LENGTH];
-	ret = pci_6534_load_fpga(dev, 2, main_fpga_data, main_fpga_data_len);
-	if (ret < 0)
-		return ret;
-	pci_6534_init_main_fpga(dev);
-	scarab_a_data = comedi_aux_data(options, 1);
-	scarab_a_data_len = options[COMEDI_DEVCONF_AUX_DATA1_LENGTH];
-	ret = pci_6534_load_fpga(dev, 0, scarab_a_data, scarab_a_data_len);
-	if (ret < 0)
-		return ret;
-	scarab_b_data = comedi_aux_data(options, 2);
-	scarab_b_data_len = options[COMEDI_DEVCONF_AUX_DATA2_LENGTH];
-	ret = pci_6534_load_fpga(dev, 1, scarab_b_data, scarab_b_data_len);
-	if (ret < 0)
-		return ret;
-	return 0;
-}
-
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
+	/* load main FPGA first, then the two scarabs */
+	for (n = 2; n >= 0; n--) {
+		ret = request_firmware(&fw, fw_file[n],
+				       &devpriv->mite->pcidev->dev);
+		if (ret == 0) {
+			ret = pci_6534_load_fpga(dev, n, fw->data, fw->size);
+			if (ret == 0 && n == 2)
+				pci_6534_init_main_fpga(dev);
+			release_firmware(fw);
 		}
-		for (i = 0; i < n_nidio_boards; i++) {
-			if (mite_device_id(mite) == nidio_boards[i].dev_id) {
-				dev->board_ptr = nidio_boards + i;
-				devpriv->mite = mite;
-
-				return 0;
-			}
-		}
+		if (ret < 0)
+			break;
 	}
-	printk(KERN_WARNING "no device found\n");
-	mite_list_devices();
-	return -EIO;
+	return ret;
 }
 
-static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static const struct nidio_board *
+nidio_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int dev_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(nidio_boards); n++) {
+		const struct nidio_board *board = &nidio_boards[n];
+		if (board->dev_id == dev_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit nidio_attach_pci(struct comedi_device *dev,
+				      struct pci_dev *pcidev)
 {
 	struct comedi_subdevice *s;
-	int i;
 	int ret;
-	int n_subdevices;
 	unsigned int irq;
 
-	printk(KERN_INFO "comedi%d: nidio:", dev->minor);
-
 	ret = alloc_private(dev, sizeof(struct nidio96_private));
 	if (ret < 0)
 		return ret;
 	spin_lock_init(&devpriv->mite_channel_lock);
 
-	ret = nidio_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = nidio_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+	devpriv->mite = mite_alloc(pcidev);
+	if (!devpriv->mite)
+		return -ENOMEM;
 
 	ret = mite_setup(devpriv->mite);
 	if (ret < 0) {
-		printk(KERN_WARNING "error setting up mite\n");
+		dev_warn(dev->class_dev, "error setting up mite\n");
 		return ret;
 	}
 	comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev);
@@ -1235,84 +1130,60 @@
 
 	dev->board_name = this_board->name;
 	irq = mite_irq(devpriv->mite);
-	printk(KERN_INFO " %s", dev->board_name);
 	if (this_board->uses_firmware) {
-		ret = pci_6534_upload_firmware(dev, it->options);
+		ret = pci_6534_upload_firmware(dev);
 		if (ret < 0)
 			return ret;
 	}
-	if (!this_board->is_diodaq)
-		n_subdevices = this_board->n_8255;
-	else
-		n_subdevices = 1;
 
-	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
 		return ret;
 
-	if (!this_board->is_diodaq) {
-		for (i = 0; i < this_board->n_8255; i++) {
-			subdev_8255_init(dev, dev->subdevices + i,
-					 nidio96_8255_cb,
-					 (unsigned long)(devpriv->mite->
-							 daq_io_addr +
-							 NIDIO_8255_BASE(i)));
-		}
-	} else {
+	dev_info(dev->class_dev, "%s rev=%d\n", dev->board_name,
+		 readb(devpriv->mite->daq_io_addr + Chip_Version));
 
-		printk(KERN_INFO " rev=%d",
-		       readb(devpriv->mite->daq_io_addr + Chip_Version));
+	s = &dev->subdevices[0];
 
-		s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags =
+		SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED |
+		SDF_CMD_READ;
+	s->n_chan = 32;
+	s->range_table = &range_digital;
+	s->maxdata = 1;
+	s->insn_config = &ni_pcidio_insn_config;
+	s->insn_bits = &ni_pcidio_insn_bits;
+	s->do_cmd = &ni_pcidio_cmd;
+	s->do_cmdtest = &ni_pcidio_cmdtest;
+	s->cancel = &ni_pcidio_cancel;
+	s->len_chanlist = 32;	/* XXX */
+	s->buf_change = &ni_pcidio_change;
+	s->async_dma_dir = DMA_BIDIRECTIONAL;
+	s->poll = &ni_pcidio_poll;
 
-		dev->read_subdev = s;
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags =
-		    SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED |
-		    SDF_CMD_READ;
-		s->n_chan = 32;
-		s->range_table = &range_digital;
-		s->maxdata = 1;
-		s->insn_config = &ni_pcidio_insn_config;
-		s->insn_bits = &ni_pcidio_insn_bits;
-		s->do_cmd = &ni_pcidio_cmd;
-		s->do_cmdtest = &ni_pcidio_cmdtest;
-		s->cancel = &ni_pcidio_cancel;
-		s->len_chanlist = 32;	/* XXX */
-		s->buf_change = &ni_pcidio_change;
-		s->async_dma_dir = DMA_BIDIRECTIONAL;
-		s->poll = &ni_pcidio_poll;
+	writel(0, devpriv->mite->daq_io_addr + Port_IO(0));
+	writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
+	writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0));
 
-		writel(0, devpriv->mite->daq_io_addr + Port_IO(0));
-		writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
-		writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0));
+	/* disable interrupts on board */
+	writeb(0x00,
+		devpriv->mite->daq_io_addr +
+		Master_DMA_And_Interrupt_Control);
 
-		/* disable interrupts on board */
-		writeb(0x00,
-		       devpriv->mite->daq_io_addr +
-		       Master_DMA_And_Interrupt_Control);
+	ret = request_irq(irq, nidio_interrupt, IRQF_SHARED,
+				"ni_pcidio", dev);
+	if (ret < 0)
+		dev_warn(dev->class_dev, "irq not available\n");
 
-		ret = request_irq(irq, nidio_interrupt, IRQF_SHARED,
-				  "ni_pcidio", dev);
-		if (ret < 0)
-			printk(KERN_WARNING " irq not available");
-
-		dev->irq = irq;
-	}
-
-	printk("\n");
+	dev->irq = irq;
 
 	return 0;
 }
 
 static void nidio_detach(struct comedi_device *dev)
 {
-	int i;
-
-	if (this_board && !this_board->is_diodaq) {
-		for (i = 0; i < this_board->n_8255; i++)
-			subdev_8255_cleanup(dev, dev->subdevices + i);
-	}
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (devpriv) {
@@ -1320,15 +1191,17 @@
 			mite_free_ring(devpriv->di_mite_ring);
 			devpriv->di_mite_ring = NULL;
 		}
-		if (devpriv->mite)
+		if (devpriv->mite) {
 			mite_unsetup(devpriv->mite);
+			mite_free(devpriv->mite);
+		}
 	}
 }
 
 static struct comedi_driver ni_pcidio_driver = {
 	.driver_name	= "ni_pcidio",
 	.module		= THIS_MODULE,
-	.attach		= nidio_attach,
+	.attach_pci	= nidio_attach_pci,
 	.detach		= nidio_detach,
 };
 
@@ -1347,13 +1220,6 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) },
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 89f4d43..f284a90 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1188,8 +1188,6 @@
 	 },
 };
 
-#define n_pcimio_boards ARRAY_SIZE(ni_boards)
-
 struct ni_private {
 NI_PRIVATE_COMMON};
 #define devpriv ((struct ni_private *)dev->private)
@@ -1502,7 +1500,6 @@
 
 #include "ni_mio_common.c"
 
-static int pcimio_find_device(struct comedi_device *dev, int bus, int slot);
 static int pcimio_ai_change(struct comedi_device *dev,
 			    struct comedi_subdevice *s, unsigned long new_size);
 static int pcimio_ao_change(struct comedi_device *dev,
@@ -1584,24 +1581,45 @@
 		mite_free_ring(devpriv->cdo_mite_ring);
 		mite_free_ring(devpriv->gpct_mite_ring[0]);
 		mite_free_ring(devpriv->gpct_mite_ring[1]);
-		if (devpriv->mite)
+		if (devpriv->mite) {
 			mite_unsetup(devpriv->mite);
+			mite_free(devpriv->mite);
+		}
 	}
 }
 
-static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static const struct ni_board_struct *
+pcimio_find_boardinfo(struct pci_dev *pcidev)
+{
+	unsigned int device_id = pcidev->device;
+	unsigned int n;
+
+	for (n = 0; n < ARRAY_SIZE(ni_boards); n++) {
+		const struct ni_board_struct *board = &ni_boards[n];
+		if (board->device_id == device_id)
+			return board;
+	}
+	return NULL;
+}
+
+static int __devinit pcimio_attach_pci(struct comedi_device *dev,
+				       struct pci_dev *pcidev)
 {
 	int ret;
 
-	dev_info(dev->class_dev, "ni_pcimio: attach\n");
+	dev_info(dev->class_dev, "ni_pcimio: attach %s\n", pci_name(pcidev));
 
 	ret = ni_alloc_private(dev);
 	if (ret < 0)
 		return ret;
 
-	ret = pcimio_find_device(dev, it->options[0], it->options[1]);
-	if (ret < 0)
-		return ret;
+	dev->board_ptr = pcimio_find_boardinfo(pcidev);
+	if (!dev->board_ptr)
+		return -ENODEV;
+
+	devpriv->mite = mite_alloc(pcidev);
+	if (!devpriv->mite)
+		return -ENOMEM;
 
 	dev_dbg(dev->class_dev, "%s\n", boardtype.name);
 	dev->board_name = boardtype.name;
@@ -1659,7 +1677,7 @@
 		}
 	}
 
-	ret = ni_E_init(dev, it);
+	ret = ni_E_init(dev);
 	if (ret < 0)
 		return ret;
 
@@ -1672,34 +1690,6 @@
 	return ret;
 }
 
-static int pcimio_find_device(struct comedi_device *dev, int bus, int slot)
-{
-	struct mite_struct *mite;
-	int i;
-
-	for (mite = mite_devices; mite; mite = mite->next) {
-		if (mite->used)
-			continue;
-		if (bus || slot) {
-			if (bus != mite->pcidev->bus->number ||
-			    slot != PCI_SLOT(mite->pcidev->devfn))
-				continue;
-		}
-
-		for (i = 0; i < n_pcimio_boards; i++) {
-			if (mite_device_id(mite) == ni_boards[i].device_id) {
-				dev->board_ptr = ni_boards + i;
-				devpriv->mite = mite;
-
-				return 0;
-			}
-		}
-	}
-	pr_warn("no device found\n");
-	mite_list_devices();
-	return -EIO;
-}
-
 static int pcimio_ai_change(struct comedi_device *dev,
 			    struct comedi_subdevice *s, unsigned long new_size)
 {
@@ -1765,7 +1755,7 @@
 static struct comedi_driver ni_pcimio_driver = {
 	.driver_name	= "ni_pcimio",
 	.module		= THIS_MODULE,
-	.attach		= pcimio_attach,
+	.attach_pci	= pcimio_attach_pci,
 	.detach		= pcimio_detach,
 };
 
@@ -1844,7 +1834,7 @@
 	.probe		= ni_pcimio_pci_probe,
 	.remove		= __devexit_p(ni_pcimio_pci_remove)
 };
-module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver)
+module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index a961158..8ee93d3 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -48,6 +48,7 @@
 	Support use of both banks X and Y
 */
 
+#include "comedi_fc.h"
 #include "ni_tio_internal.h"
 #include "mite.h"
 
@@ -237,61 +238,35 @@
 int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd)
 {
 	int err = 0;
-	int tmp;
-	int sources;
+	unsigned int sources;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
 	sources = TRIG_NOW | TRIG_INT | TRIG_OTHER;
 	if (ni_tio_counting_mode_registers_present(counter->counter_dev))
 		sources |= TRIG_EXT;
-	cmd->start_src &= sources;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, sources);
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER;
-	cmd->convert_src &= sources;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_NOW | TRIG_EXT | TRIG_OTHER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique... */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW &&
-	    cmd->start_src != TRIG_INT &&
-	    cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER)
-		err++;
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_OTHER)
-		err++;
-	if (cmd->convert_src != TRIG_OTHER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_NONE)
-		err++;
-	/* ... and mutually compatible */
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+
+	/* Step 2b : and mutually compatible */
+
 	if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index bb72d0b..89305a1 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -64,6 +64,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 
 #define PCL711_SIZE 16
@@ -168,7 +169,7 @@
 	int data;
 	struct comedi_device *dev = d;
 	const struct pcl711_board *board = comedi_board(dev);
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 
 	if (!dev->attached) {
 		comedi_error(dev, "spurious interrupt");
@@ -266,42 +267,24 @@
 	int tmp;
 	int err = 0;
 
-	/* step 1 */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -520,7 +503,7 @@
 	if (ret < 0)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* AI subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -536,7 +519,7 @@
 		s->do_cmd = pcl711_ai_cmd;
 	}
 
-	s++;
+	s = &dev->subdevices[1];
 	/* AO subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -547,7 +530,7 @@
 	s->insn_write = pcl711_ao_insn;
 	s->insn_read = pcl711_ao_insn_read;
 
-	s++;
+	s = &dev->subdevices[2];
 	/* 16-bit digital input */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -557,7 +540,7 @@
 	s->range_table = &range_digital;
 	s->insn_bits = pcl711_di_insn_bits;
 
-	s++;
+	s = &dev->subdevices[3];
 	/* 16-bit digital out */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index c8fe23c..7b3c429 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -99,6 +99,7 @@
 static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct pcl724_board *board = comedi_board(dev);
+	struct comedi_subdevice *s;
 	unsigned long iobase;
 	unsigned int iorange;
 	int ret, i, n_subdevices;
@@ -161,14 +162,13 @@
 		return ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
+		s = &dev->subdevices[i];
 		if (board->is_pet48) {
-			subdev_8255_init(dev, dev->subdevices + i,
-					 subdev_8255mapped_cb,
+			subdev_8255_init(dev, s, subdev_8255mapped_cb,
 					 (unsigned long)(dev->iobase +
 							 i * 0x1000));
 		} else
-			subdev_8255_init(dev, dev->subdevices + i,
-					 subdev_8255_cb,
+			subdev_8255_init(dev, s, subdev_8255_cb,
 					 (unsigned long)(dev->iobase +
 							 SIZE_8255 * i));
 	}
@@ -179,10 +179,13 @@
 static void pcl724_detach(struct comedi_device *dev)
 {
 	const struct pcl724_board *board = comedi_board(dev);
+	struct comedi_subdevice *s;
 	int i;
 
-	for (i = 0; i < dev->n_subdevices; i++)
-		subdev_8255_cleanup(dev, dev->subdevices + i);
+	for (i = 0; i < dev->n_subdevices; i++) {
+		s = &dev->subdevices[i];
+		subdev_8255_cleanup(dev, s);
+	}
 #ifdef PCL724_IRQ
 	if (dev->irq)
 		free_irq(dev->irq, dev);
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index d5b60cf..21fbc1a 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -62,7 +62,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* do */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -71,7 +71,7 @@
 	s->insn_bits = pcl725_do_insn;
 	s->range_table = &range_digital;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* di */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 2b10f1d..07e72de 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -290,7 +290,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ao */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
@@ -316,7 +316,7 @@
 			devpriv->bipolar[i] = 1;	/* bipolar range */
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* di */
 	if (!board->have_dio) {
 		s->type = COMEDI_SUBD_UNUSED;
@@ -330,7 +330,7 @@
 		s->range_table = &range_digital;
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* do */
 	if (!board->have_dio) {
 		s->type = COMEDI_SUBD_UNUSED;
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index 4675ec5..e3de499 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -84,7 +84,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* Isolated do */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -94,7 +94,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCL730_IDIO_LO;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* Isolated di */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -104,7 +104,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCL730_IDIO_LO;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* TTL do */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -114,7 +114,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCL730_DIO_LO;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* TTL di */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 578fd89..3cf55ff 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -117,6 +117,7 @@
 #include <linux/io.h>
 #include <asm/dma.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 
 /* hardware types of the cards */
@@ -533,49 +534,31 @@
 {
 	const struct pcl812_board *board = comedi_board(dev);
 	int err = 0;
+	unsigned int flags;
 	int tmp, divisor1, divisor2;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
 	if (devpriv->use_ext_trg)
-		cmd->convert_src &= TRIG_EXT;
+		flags = TRIG_EXT;
 	else
-		cmd->convert_src &= TRIG_TIMER;
+		flags = TRIG_TIMER;
+	err |= cfc_check_trigger_src(&cmd->convert_src, flags);
 
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are
-	 * unique and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -806,7 +789,7 @@
 	char err = 1;
 	unsigned int mask, timeout;
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	unsigned int next_chan;
 
 	s->async->events = 0;
@@ -909,7 +892,7 @@
 static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	unsigned long dma_flags;
 	int len, bufptr;
 	short *ptr;
@@ -1267,7 +1250,7 @@
 
 	/* analog input */
 	if (board->n_aichan > 0) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags = SDF_READABLE;
 		switch (board->board_type) {
@@ -1409,7 +1392,7 @@
 
 	/* analog output */
 	if (board->n_aochan > 0) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
 		s->n_chan = board->n_aochan;
@@ -1438,7 +1421,7 @@
 
 	/* digital input */
 	if (board->n_dichan > 0) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
 		s->n_chan = board->n_dichan;
@@ -1451,7 +1434,7 @@
 
 	/* digital output */
 	if (board->n_dochan > 0) {
-		s = dev->subdevices + subdev;
+		s = &dev->subdevices[subdev];
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE;
 		s->n_chan = board->n_dochan;
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index ba6911f..0822de0 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -41,6 +41,7 @@
 #include <linux/io.h>
 #include <asm/dma.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 
 #define DEBUG(x) x
@@ -258,7 +259,7 @@
 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int low, hi;
 	int timeout = 50;	/* wait max 50us */
 
@@ -349,7 +350,7 @@
 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int len, bufptr, this_dma_buf;
 	unsigned long dma_flags;
 	short *ptr;
@@ -458,48 +459,23 @@
 	      pcl816_cmdtest_out(-1, cmd);
 	     );
 
-	/* step 1: make sure trigger sources are trivially valid */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_EXT | TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
+	/* Step 2a : make sure trigger sources are unique */
 
-	/*
-	 * step 2: make sure trigger sources
-	 * are unique and mutually compatible
-	 */
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
-		cmd->convert_src = TRIG_TIMER;
-		err++;
-	}
-
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1183,7 +1159,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	if (board->n_aichan > 0) {
 		s->type = COMEDI_SUBD_AI;
 		devpriv->sub_ai = s;
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 34169c1..d4b0859 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -107,6 +107,7 @@
 #include <linux/io.h>
 #include <asm/dma.h>
 
+#include "comedi_fc.h"
 #include "8253.h"
 
 /* #define PCL818_MODE13_AO 1 */
@@ -477,7 +478,7 @@
 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int low;
 	int timeout = 50;	/* wait max 50us */
 
@@ -536,7 +537,7 @@
 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int i, len, bufptr;
 	unsigned long flags;
 	short *ptr;
@@ -615,7 +616,7 @@
 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	unsigned long tmp;
 	unsigned int top1, top2, i, bufptr;
 	long ofs_dats;
@@ -720,7 +721,7 @@
 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
 {
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	int i, len, lo;
 
 	outb(0, dev->iobase + PCL818_FI_INTCLR);	/*  clear fifo int request */
@@ -811,7 +812,7 @@
 			   being reprogrammed while a DMA transfer is in
 			   progress.
 			 */
-			struct comedi_subdevice *s = dev->subdevices + 0;
+			struct comedi_subdevice *s = &dev->subdevices[0];
 			devpriv->ai_act_scan = 0;
 			devpriv->neverending_ai = 0;
 			pcl818_ai_cancel(dev, s);
@@ -1261,43 +1262,23 @@
 	int err = 0;
 	int tmp, divisor1 = 0, divisor2 = 0;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
 
-	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
-		err++;
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1763,7 +1744,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	if (!board->n_aichan_se) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
@@ -1829,7 +1810,7 @@
 		}
 	}
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	if (!board->n_aochan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
@@ -1862,7 +1843,7 @@
 		}
 	}
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	if (!board->n_dichan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
@@ -1875,7 +1856,7 @@
 		s->insn_bits = pcl818_di_insn_bits;
 	}
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	if (!board->n_dochan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 62c22cc..4102547 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -119,6 +119,8 @@
 static void do_3724_config(struct comedi_device *dev,
 			   struct comedi_subdevice *s, int chanspec)
 {
+	struct comedi_subdevice *s_dio1 = &dev->subdevices[0];
+	struct comedi_subdevice *s_dio2 = &dev->subdevices[1];
 	int config;
 	int buffer_config;
 	unsigned long port_8255_cfg;
@@ -136,10 +138,10 @@
 	if (!(s->io_bits & 0xff0000))
 		config |= CR_C_IO;
 
-	buffer_config = compute_buffer(0, 0, dev->subdevices);
-	buffer_config = compute_buffer(buffer_config, 1, (dev->subdevices) + 1);
+	buffer_config = compute_buffer(0, 0, s_dio1);
+	buffer_config = compute_buffer(buffer_config, 1, s_dio2);
 
-	if (s == dev->subdevices)
+	if (s == s_dio1)
 		port_8255_cfg = dev->iobase + _8255_CR;
 	else
 		port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR;
@@ -154,6 +156,7 @@
 static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
 			int chanspec)
 {
+	struct comedi_subdevice *s_dio1 = &dev->subdevices[0];
 	unsigned int mask;
 	int gatecfg;
 	struct priv_pcm3724 *priv;
@@ -162,9 +165,9 @@
 	priv = dev->private;
 
 	mask = 1 << CR_CHAN(chanspec);
-	if (s == dev->subdevices)	/*  subdev 0 */
+	if (s == s_dio1)
 		priv->dio_1 |= mask;
-	else		/* subdev 1 */
+	else
 		priv->dio_2 |= mask;
 
 	if (priv->dio_1 & 0xff0000)
@@ -231,6 +234,7 @@
 			  struct comedi_devconfig *it)
 {
 	const struct pcm3724_board *board = comedi_board(dev);
+	struct comedi_subdevice *s;
 	unsigned long iobase;
 	unsigned int iorange;
 	int ret, i, n_subdevices;
@@ -263,9 +267,10 @@
 		return ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		subdev_8255_init(dev, dev->subdevices + i, subdev_8255_cb,
+		s = &dev->subdevices[i];
+		subdev_8255_init(dev, s, subdev_8255_cb,
 				 (unsigned long)(dev->iobase + SIZE_8255 * i));
-		((dev->subdevices) + i)->insn_config = subdev_3724_insn_config;
+		s->insn_config = subdev_3724_insn_config;
 	}
 	return 0;
 }
@@ -273,11 +278,14 @@
 static void pcm3724_detach(struct comedi_device *dev)
 {
 	const struct pcm3724_board *board = comedi_board(dev);
+	struct comedi_subdevice *s;
 	int i;
 
 	if (dev->subdevices) {
-		for (i = 0; i < dev->n_subdevices; i++)
-			subdev_8255_cleanup(dev, dev->subdevices + i);
+		for (i = 0; i < dev->n_subdevices; i++) {
+			s = &dev->subdevices[i];
+			subdev_8255_cleanup(dev, s);
+		}
 	}
 	if (dev->iobase)
 		release_region(dev->iobase, board->io_range);
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index d65e0bd..067f14d 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -72,7 +72,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->maxdata = 1;
@@ -81,7 +81,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCM3730_DOA;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->maxdata = 1;
@@ -90,7 +90,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCM3730_DOB;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
 	s->maxdata = 1;
@@ -99,7 +99,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCM3730_DOC;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->maxdata = 1;
@@ -108,7 +108,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCM3730_DIA;
 
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->maxdata = 1;
@@ -117,7 +117,7 @@
 	s->range_table = &range_digital;
 	s->private = (void *)PCM3730_DIB;
 
-	s = dev->subdevices + 5;
+	s = &dev->subdevices[5];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->maxdata = 1;
diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c
index 474af7b..85ee05e 100644
--- a/drivers/staging/comedi/drivers/pcm_common.c
+++ b/drivers/staging/comedi/drivers/pcm_common.c
@@ -1,60 +1,30 @@
 #include "../comedidev.h"
+
+#include "comedi_fc.h"
 #include "pcm_common.h"
 
-/*
- * 'do_cmdtest' function for an 'INTERRUPT' subdevice.  This is for
- * the PCM drivers.
- */
 int comedi_pcm_cmdtest(struct comedi_device *dev,
 		       struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
 	int err = 0;
-	unsigned int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= (TRIG_NOW | TRIG_INT);
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and
-	 * mutually compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* these tests are true if more than one _src bit is set */
-	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
-		err++;
-	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
-		err++;
-	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
-		err++;
-	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 54d19c9..5efeb92 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -127,7 +127,7 @@
 
 	dev->board_name = board->name;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | AREF_GROUND;
 	s->n_chan = 16;		/* XXX */
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 291ce7c..28af8f6 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -195,7 +195,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices;
+	s = &dev->subdevices[0];
 	s->private = NULL;
 	s->maxdata = (0x1 << BITS) - 1;
 	s->range_table = &pcmda12_ranges;
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 3d2e6f0..a10bf0a 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -526,6 +526,7 @@
 {
 	int asic, got1 = 0;
 	struct comedi_device *dev = (struct comedi_device *)d;
+	int i;
 
 	for (asic = 0; asic < MAX_ASICS; ++asic) {
 		if (irq == devpriv->asics[asic].irq) {
@@ -583,9 +584,8 @@
 				printk
 				    (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
 				     irq, asic, triggered);
-				for (s = dev->subdevices + 2;
-				     s < dev->subdevices + dev->n_subdevices;
-				     ++s) {
+				for (i = 2; i < dev->n_subdevices; i++) {
+					s = &dev->subdevices[i];
 					/*
 					 * this is an interrupt subdev,
 					 * and it matches this asic!
@@ -1076,9 +1076,8 @@
 		return ret;
 
 	/* First, AI */
-	sdev_no = 0;
-	s = dev->subdevices + sdev_no;
-	s->private = devpriv->sprivs + sdev_no;
+	s = &dev->subdevices[0];
+	s->private = &devpriv->sprivs[0];
 	s->maxdata = (1 << board->ai_bits) - 1;
 	s->range_table = board->ai_range_table;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
@@ -1092,9 +1091,8 @@
 	outb(0, subpriv->iobase + 4 + 3);
 
 	/* Next, AO */
-	++sdev_no;
-	s = dev->subdevices + sdev_no;
-	s->private = devpriv->sprivs + sdev_no;
+	s = &dev->subdevices[1];
+	s->private = &devpriv->sprivs[1];
 	s->maxdata = (1 << board->ao_bits) - 1;
 	s->range_table = board->ao_range_table;
 	s->subdev_flags = SDF_READABLE;
@@ -1108,14 +1106,13 @@
 	outb(0, subpriv->iobase + 3);
 	outb(0, subpriv->iobase + 4 + 3);
 
-	++sdev_no;
 	port = 0;
 	asic = 0;
-	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+	for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
 		int byte_no;
 
-		s = dev->subdevices + sdev_no;
-		s->private = devpriv->sprivs + sdev_no;
+		s = &dev->subdevices[sdev_no];
+		s->private = &devpriv->sprivs[sdev_no];
 		s->maxdata = 1;
 		s->range_table = &range_digital;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -1200,15 +1197,6 @@
 				 * multiple irqs..
 				 */
 
-	if (irq[0]) {
-		printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
-		if (board->dio_num_asics == 2 && irq[1])
-			printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
-					dev->minor, irq[1]);
-	} else {
-		printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
-	}
-
 	printk(KERN_INFO "comedi%d: attached\n", dev->minor);
 
 	return 1;
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index feef3d0..0e32119 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -442,7 +442,7 @@
 
 	subpriv->intr.enabled_mask = 0;
 	subpriv->intr.active = 0;
-	s->async->inttrig = 0;
+	s->async->inttrig = NULL;
 	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
 	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
 	switch_page(dev, asic, PAGE_ENAB);
@@ -456,6 +456,7 @@
 {
 	int asic, got1 = 0;
 	struct comedi_device *dev = (struct comedi_device *)d;
+	int i;
 
 	for (asic = 0; asic < MAX_ASICS; ++asic) {
 		if (irq == devpriv->asics[asic].irq) {
@@ -507,9 +508,8 @@
 				printk
 				    ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
 				     irq, asic, triggered);
-				for (s = dev->subdevices;
-				     s < dev->subdevices + dev->n_subdevices;
-				     ++s) {
+				for (i = 0; i < dev->n_subdevices; i++) {
+					s = &dev->subdevices[i];
 					if (subpriv->intr.asic == asic) {	/* this is an interrupt subdev, and it matches this asic! */
 						unsigned long flags;
 						unsigned oldevents;
@@ -683,7 +683,7 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
-	s->async->inttrig = 0;
+	s->async->inttrig = NULL;
 	if (subpriv->intr.active)
 		event = pcmuio_start_intr(dev, s);
 
@@ -811,8 +811,8 @@
 	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
 		int byte_no;
 
-		s = dev->subdevices + sdev_no;
-		s->private = devpriv->sprivs + sdev_no;
+		s = &dev->subdevices[sdev_no];
+		s->private = &devpriv->sprivs[sdev_no];
 		s->maxdata = 1;
 		s->range_table = &range_digital;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index c253bb9..78dfe16 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -164,7 +164,7 @@
 		return -ENOMEM;
 
 	/* analog output subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = board->type;
 	s->n_chan = board->n_chan;
 	s->maxdata = (1 << board->n_bits) - 1;
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index a029147..3e276f7 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -56,6 +56,8 @@
 
 #include <linux/completion.h>
 
+#include "comedi_fc.h"
+
 /* Maximum number of separate DAQP devices we'll allow */
 #define MAX_DEV         4
 
@@ -456,51 +458,26 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources
-	 * are unique and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-	if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER)
-		err++;
-	if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -878,7 +855,7 @@
 	printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n",
 	       dev->minor, it->options[0], dev->iobase);
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	s->private = local;
 	s->type = COMEDI_SUBD_AI;
@@ -892,7 +869,7 @@
 	s->do_cmd = daqp_ai_cmd;
 	s->cancel = daqp_ai_cancel;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	dev->write_subdev = s;
 	s->private = local;
 	s->type = COMEDI_SUBD_AO;
@@ -903,7 +880,7 @@
 	s->range_table = &range_daqp_ao;
 	s->insn_write = daqp_ao_insn_write;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->private = local;
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -911,7 +888,7 @@
 	s->len_chanlist = 1;
 	s->insn_read = daqp_di_insn_read;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->private = local;
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITEABLE;
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 5aa8be1..41d24b0 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -106,6 +106,8 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
+
 #define DRV_NAME "rtd520"
 
 /*======================================================================
@@ -783,7 +785,7 @@
 				 void *d)
 {				/* our data *//* cpu context (ignored) */
 	struct comedi_device *dev = d;
-	struct comedi_subdevice *s = dev->subdevices + 0;	/* analog in subdevice */
+	struct comedi_subdevice *s = &dev->subdevices[0];
 	struct rtdPrivate *devpriv = dev->private;
 	u32 overrun;
 	u16 status;
@@ -964,7 +966,7 @@
 /*
   cmdtest tests a particular command to see if it is valid.
   Using the cmdtest ioctl, a user can create a valid cmd
-  and then have it executed by the cmd ioctl (asyncronously).
+  and then have it executed by the cmd ioctl (asynchronously).
 
   cmdtest returns 1,2,3,4 or 0, depending on which tests
   the command passes.
@@ -976,52 +978,25 @@
 	int err = 0;
 	int tmp;
 
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
-
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique
-	   and mutually compatible */
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT) {
-		err++;
-	}
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1706,7 +1681,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	dev->read_subdev = s;
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
@@ -1726,7 +1701,7 @@
 	s->cancel = rtd_ai_cancel;
 	/* s->poll = rtd_ai_poll; *//* not ready yet */
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -1736,7 +1711,7 @@
 	s->insn_write = rtd_ao_winsn;
 	s->insn_read = rtd_ao_rinsn;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital i/o subdevice */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -1748,7 +1723,7 @@
 	s->insn_config = rtd_dio_insn_config;
 
 	/* timer/counter subdevices (not currently supported) */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 3;
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index f7fa940..137885b 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -360,7 +360,7 @@
 	devpriv->dac1_coding = it->options[8];
 	devpriv->muxgain_bits = -1;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* ai subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
@@ -379,7 +379,7 @@
 		break;
 	}
 
-	s++;
+	s = &dev->subdevices[1];
 	if (board->has_ao) {
 		/* ao subdevice (only on rti815) */
 		s->type = COMEDI_SUBD_AO;
@@ -409,7 +409,7 @@
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
-	s++;
+	s = &dev->subdevices[2];
 	/* di */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
@@ -418,7 +418,7 @@
 	s->maxdata = 1;
 	s->range_table = &range_digital;
 
-	s++;
+	s = &dev->subdevices[3];
 	/* do */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -429,7 +429,7 @@
 
 /* don't yet know how to deal with counter/timers */
 #if 0
-	s++;
+	s = &dev->subdevices[4];
 	/* do */
 	s->type = COMEDI_SUBD_TIMER;
 #endif
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index fc16508..3f9d027 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -111,7 +111,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices;
+	s = &dev->subdevices[0];
 	/* ao subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 737a194..a1e2562 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -83,36 +83,6 @@
 #define REG_EED 0x32
 #define REG_EEC 0x34
 
-static const int s526_ports[] = {
-	REG_TCR,
-	REG_WDC,
-	REG_DAC,
-	REG_ADC,
-	REG_ADD,
-	REG_DIO,
-	REG_IER,
-	REG_ISR,
-	REG_MSC,
-	REG_C0L,
-	REG_C0H,
-	REG_C0M,
-	REG_C0C,
-	REG_C1L,
-	REG_C1H,
-	REG_C1M,
-	REG_C1C,
-	REG_C2L,
-	REG_C2H,
-	REG_C2M,
-	REG_C2C,
-	REG_C3L,
-	REG_C3H,
-	REG_C3M,
-	REG_C3C,
-	REG_EED,
-	REG_EEC
-};
-
 struct counter_mode_register_t {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned short coutSource:1;
@@ -148,122 +118,48 @@
 	unsigned short value;
 };
 
-#define MAX_GPCT_CONFIG_DATA 6
-
-/* Different Application Classes for GPCT Subdevices */
-/* The list is not exhaustive and needs discussion! */
-enum S526_GPCT_APP_CLASS {
-	CountingAndTimeMeasurement,
-	SinglePulseGeneration,
-	PulseTrainGeneration,
-	PositionMeasurement,
-	Miscellaneous
-};
-
-/* Config struct for different GPCT subdevice Application Classes and
-   their options
-*/
-struct s526GPCTConfig {
-	enum S526_GPCT_APP_CLASS app;
-	int data[MAX_GPCT_CONFIG_DATA];
-};
-
-/*
- * Board descriptions for two imaginary boards.  Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
-struct s526_board {
-	const char *name;
-	int gpct_chans;
-	int gpct_bits;
-	int ad_chans;
-	int ad_bits;
-	int da_chans;
-	int da_bits;
-	int have_dio;
-};
-
-static const struct s526_board s526_boards[] = {
-	{
-	 .name = "s526",
-	 .gpct_chans = 4,
-	 .gpct_bits = 24,
-	 .ad_chans = 8,
-	 .ad_bits = 16,
-	 .da_chans = 4,
-	 .da_bits = 16,
-	 .have_dio = 1,
-	 }
-};
-
-#define ADDR_REG(reg) (dev->iobase + (reg))
-#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
-
-/* this structure is for data unique to this hardware driver.  If
-   several hardware drivers keep similar information in this structure,
-   feel free to suggest moving the variable to the struct comedi_device
-   struct.
-*/
 struct s526_private {
 	unsigned int ao_readback[2];
-	struct s526GPCTConfig s526_gpct_config[4];
-	unsigned short s526_ai_config;
+	unsigned int gpct_config[4];
+	unsigned short ai_config;
 };
 
-/*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct s526_private *)dev->private)
-
 static int s526_gpct_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
+			   struct comedi_subdevice *s,
+			   struct comedi_insn *insn,
 			   unsigned int *data)
 {
-	int i;			/*  counts the Data */
-	int counter_channel = CR_CHAN(insn->chanspec);
-	unsigned short datalow;
-	unsigned short datahigh;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned long chan_iobase = dev->iobase + chan * 8;
+	unsigned int lo;
+	unsigned int hi;
+	int i;
 
-	/*  Check if (n > 0) */
-	if (insn->n <= 0) {
-		printk(KERN_ERR "s526: INSN_READ: n should be > 0\n");
-		return -EINVAL;
-	}
-	/*  Read the low word first */
 	for (i = 0; i < insn->n; i++) {
-		datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
-		datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
-		data[i] = (int)(datahigh & 0x00FF);
-		data[i] = (data[i] << 16) | (datalow & 0xFFFF);
-		/* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n",
-		   counter_channel, data[i], datahigh, datalow); */
+		/* Read the low word first */
+		lo = inw(chan_iobase + REG_C0L) & 0xffff;
+		hi = inw(chan_iobase + REG_C0H) & 0xff;
+
+		data[i] = (hi << 16) | lo;
 	}
-	return i;
+
+	return insn->n;
 }
 
 static int s526_gpct_insn_config(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
-	int subdev_channel = CR_CHAN(insn->chanspec);	/*  Unpack chanspec */
-	int i;
-	short value;
+	struct s526_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned long chan_iobase = dev->iobase + chan * 8;
+	unsigned int val;
 	union cmReg cmReg;
 
-	/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n",
-						subdev_channel); */
-
-	for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
-		devpriv->s526_gpct_config[subdev_channel].data[i] =
-		    insn->data[i];
-/* printk("data[%d]=%x\n", i, insn->data[i]); */
-	}
-
 	/*  Check what type of Counter the user requested, data[0] contains */
 	/*  the Application type */
-	switch (insn->data[0]) {
+	switch (data[0]) {
 	case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
 		/*
 		   data[0]: Application Type
@@ -271,9 +167,7 @@
 		   data[2]: Pre-load Register Value
 		   data[3]: Conter Control Register
 		 */
-		printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
-		devpriv->s526_gpct_config[subdev_channel].app =
-		    PositionMeasurement;
+		devpriv->gpct_config[chan] = data[0];
 
 #if 0
 		/*  Example of Counter Application */
@@ -290,34 +184,32 @@
 		cmReg.reg.preloadRegSel = 0;	/*  PR0 */
 		cmReg.reg.reserved = 0;
 
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
-		outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
-		outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		outw(0x0001, chan_iobase + REG_C0H);
+		outw(0x3C68, chan_iobase + REG_C0L);
 
 		/*  Reset the counter */
-		outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		outw(0x8000, chan_iobase + REG_C0C);
 		/*  Load the counter from PR0 */
-		outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		outw(0x4000, chan_iobase + REG_C0C);
 
 		/*  Reset RCAP (fires one-shot) */
-		outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		outw(0x0008, chan_iobase + REG_C0C);
 
 #endif
 
 #if 1
 		/*  Set Counter Mode Register */
-		cmReg.value = insn->data[1] & 0xFFFF;
-
-/* printk("s526: Counter Mode register=%x\n", cmReg.value); */
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		cmReg.value = data[1] & 0xffff;
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Reset the counter if it is software preload */
 		if (cmReg.reg.autoLoadResetRcap == 0) {
 			/*  Reset the counter */
-			outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+			outw(0x8000, chan_iobase + REG_C0C);
 			/* Load the counter from PR0
-			 * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+			 * outw(0x4000, chan_iobase + REG_C0C);
 			 */
 		}
 #else
@@ -325,47 +217,47 @@
 		cmReg.reg.countDirCtrl = 0;
 
 		/*  data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */
-		if (insn->data[1] == GPCT_X2)
+		if (data[1] == GPCT_X2)
 			cmReg.reg.clockSource = 1;
-		else if (insn->data[1] == GPCT_X4)
+		else if (data[1] == GPCT_X4)
 			cmReg.reg.clockSource = 2;
 		else
 			cmReg.reg.clockSource = 0;
 
 		/*  When to take into account the indexpulse: */
-		/*if (insn->data[2] == GPCT_IndexPhaseLowLow) {
-		} else if (insn->data[2] == GPCT_IndexPhaseLowHigh) {
-		} else if (insn->data[2] == GPCT_IndexPhaseHighLow) {
-		} else if (insn->data[2] == GPCT_IndexPhaseHighHigh) {
+		/*if (data[2] == GPCT_IndexPhaseLowLow) {
+		} else if (data[2] == GPCT_IndexPhaseLowHigh) {
+		} else if (data[2] == GPCT_IndexPhaseHighLow) {
+		} else if (data[2] == GPCT_IndexPhaseHighHigh) {
 		}*/
 		/*  Take into account the index pulse? */
-		if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
+		if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
 			/*  Auto load with INDEX^ */
 			cmReg.reg.autoLoadResetRcap = 4;
 
 		/*  Set Counter Mode Register */
-		cmReg.value = (short)(insn->data[1] & 0xFFFF);
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		cmReg.value = data[1] & 0xffff;
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Load the pre-load register high word */
-		value = (short)((insn->data[2] >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+		val = (data[2] >> 16) & 0xffff;
+		outw(val, chan_iobase + REG_C0H);
 
 		/*  Load the pre-load register low word */
-		value = (short)(insn->data[2] & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		val = data[2] & 0xffff;
+		outw(val, chan_iobase + REG_C0L);
 
 		/*  Write the Counter Control Register */
-		if (insn->data[3] != 0) {
-			value = (short)(insn->data[3] & 0xFFFF);
-			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		if (data[3]) {
+			val = data[3] & 0xffff;
+			outw(val, chan_iobase + REG_C0C);
 		}
 		/*  Reset the counter if it is software preload */
 		if (cmReg.reg.autoLoadResetRcap == 0) {
 			/*  Reset the counter */
-			outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+			outw(0x8000, chan_iobase + REG_C0C);
 			/*  Load the counter from PR0 */
-			outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+			outw(0x4000, chan_iobase + REG_C0C);
 		}
 #endif
 		break;
@@ -378,40 +270,38 @@
 		   data[3]: Pre-load Register 1 Value
 		   data[4]: Conter Control Register
 		 */
-		printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n");
-		devpriv->s526_gpct_config[subdev_channel].app =
-		    SinglePulseGeneration;
+		devpriv->gpct_config[chan] = data[0];
 
 		/*  Set Counter Mode Register */
-		cmReg.value = (short)(insn->data[1] & 0xFFFF);
+		cmReg.value = data[1] & 0xffff;
 		cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Load the pre-load register 0 high word */
-		value = (short)((insn->data[2] >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+		val = (data[2] >> 16) & 0xffff;
+		outw(val, chan_iobase + REG_C0H);
 
 		/*  Load the pre-load register 0 low word */
-		value = (short)(insn->data[2] & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		val = data[2] & 0xffff;
+		outw(val, chan_iobase + REG_C0L);
 
 		/*  Set Counter Mode Register */
-		cmReg.value = (short)(insn->data[1] & 0xFFFF);
+		cmReg.value = data[1] & 0xffff;
 		cmReg.reg.preloadRegSel = 1;	/*  PR1 */
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Load the pre-load register 1 high word */
-		value = (short)((insn->data[3] >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+		val = (data[3] >> 16) & 0xffff;
+		outw(val, chan_iobase + REG_C0H);
 
 		/*  Load the pre-load register 1 low word */
-		value = (short)(insn->data[3] & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		val = data[3] & 0xffff;
+		outw(val, chan_iobase + REG_C0L);
 
 		/*  Write the Counter Control Register */
-		if (insn->data[4] != 0) {
-			value = (short)(insn->data[4] & 0xFFFF);
-			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		if (data[4]) {
+			val = data[4] & 0xffff;
+			outw(val, chan_iobase + REG_C0C);
 		}
 		break;
 
@@ -423,45 +313,42 @@
 		   data[3]: Pre-load Register 1 Value
 		   data[4]: Conter Control Register
 		 */
-		printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n");
-		devpriv->s526_gpct_config[subdev_channel].app =
-		    PulseTrainGeneration;
+		devpriv->gpct_config[chan] = data[0];
 
 		/*  Set Counter Mode Register */
-		cmReg.value = (short)(insn->data[1] & 0xFFFF);
+		cmReg.value = data[1] & 0xffff;
 		cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Load the pre-load register 0 high word */
-		value = (short)((insn->data[2] >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+		val = (data[2] >> 16) & 0xffff;
+		outw(val, chan_iobase + REG_C0H);
 
 		/*  Load the pre-load register 0 low word */
-		value = (short)(insn->data[2] & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		val = data[2] & 0xffff;
+		outw(val, chan_iobase + REG_C0L);
 
 		/*  Set Counter Mode Register */
-		cmReg.value = (short)(insn->data[1] & 0xFFFF);
+		cmReg.value = data[1] & 0xffff;
 		cmReg.reg.preloadRegSel = 1;	/*  PR1 */
-		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+		outw(cmReg.value, chan_iobase + REG_C0M);
 
 		/*  Load the pre-load register 1 high word */
-		value = (short)((insn->data[3] >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+		val = (data[3] >> 16) & 0xffff;
+		outw(val, chan_iobase + REG_C0H);
 
 		/*  Load the pre-load register 1 low word */
-		value = (short)(insn->data[3] & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		val = data[3] & 0xffff;
+		outw(val, chan_iobase + REG_C0L);
 
 		/*  Write the Counter Control Register */
-		if (insn->data[4] != 0) {
-			value = (short)(insn->data[4] & 0xFFFF);
-			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+		if (data[4]) {
+			val = data[4] & 0xffff;
+			outw(val, chan_iobase + REG_C0C);
 		}
 		break;
 
 	default:
-		printk(KERN_ERR "s526: unsupported GPCT_insn_config\n");
 		return -EINVAL;
 		break;
 	}
@@ -470,65 +357,40 @@
 }
 
 static int s526_gpct_winsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
+			   struct comedi_subdevice *s,
+			   struct comedi_insn *insn,
 			   unsigned int *data)
 {
-	int subdev_channel = CR_CHAN(insn->chanspec);	/*  Unpack chanspec */
-	short value;
-	union cmReg cmReg;
+	struct s526_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned long chan_iobase = dev->iobase + chan * 8;
 
-	printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n",
-					subdev_channel);
-	cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
-	printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value);
+	inw(chan_iobase + REG_C0M);	/* Is this read required? */
+
 	/*  Check what Application of Counter this channel is configured for */
-	switch (devpriv->s526_gpct_config[subdev_channel].app) {
-	case PositionMeasurement:
-		printk(KERN_INFO "S526: INSN_WRITE: PM\n");
-		outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
-							     subdev_channel));
-		outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
-		break;
-
-	case SinglePulseGeneration:
-		printk(KERN_INFO "S526: INSN_WRITE: SPG\n");
-		outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
-							     subdev_channel));
-		outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
-		break;
-
-	case PulseTrainGeneration:
+	switch (devpriv->gpct_config[chan]) {
+	case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
 		/* data[0] contains the PULSE_WIDTH
 		   data[1] contains the PULSE_PERIOD
 		   @pre PULSE_PERIOD > PULSE_WIDTH > 0
 		   The above periods must be expressed as a multiple of the
 		   pulse frequency on the selected source
 		 */
-		printk(KERN_INFO "S526: INSN_WRITE: PTG\n");
-		if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
-			(devpriv->s526_gpct_config[subdev_channel]).data[0] =
-			    insn->data[0];
-			(devpriv->s526_gpct_config[subdev_channel]).data[1] =
-			    insn->data[1];
-		} else {
-			printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
-				insn->data[0], insn->data[1]);
+		if ((data[1] <= data[0]) || !data[0])
 			return -EINVAL;
-		}
 
-		value = (short)((*data >> 16) & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
-		value = (short)(*data & 0xFFFF);
-		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+		/* Fall thru to write the PULSE_WIDTH */
+
+	case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
+	case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
+		outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H);
+		outw(data[0] & 0xffff, chan_iobase + REG_C0L);
 		break;
-	default:		/*  Impossible */
-		printk
-		    ("s526: INSN_WRITE: Functionality %d not implemented yet\n",
-		     devpriv->s526_gpct_config[subdev_channel].app);
+
+	default:
 		return -EINVAL;
-		break;
 	}
-	/*  return the number of samples written */
+
 	return insn->n;
 }
 
@@ -537,6 +399,7 @@
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct s526_private *devpriv = dev->private;
 	int result = -EINVAL;
 
 	if (insn->n < 1)
@@ -552,62 +415,50 @@
 	 * INSN_READ handler. */
 
 	/*  Enable ADC interrupt */
-	outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
-/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */
-	devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
+	outw(ISR_ADC_DONE, dev->iobase + REG_IER);
+	devpriv->ai_config = (data[0] & 0x3ff) << 5;
 	if (data[1] > 0)
-		devpriv->s526_ai_config |= 0x8000;	/* set the delay */
+		devpriv->ai_config |= 0x8000;	/* set the delay */
 
-	devpriv->s526_ai_config |= 0x0001;	/*  ADC start bit. */
+	devpriv->ai_config |= 0x0001;		/* ADC start bit */
 
 	return result;
 }
 
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
 static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
+	struct s526_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	int n, i;
-	int chan = CR_CHAN(insn->chanspec);
 	unsigned short value;
 	unsigned int d;
 	unsigned int status;
 
 	/* Set configured delay, enable channel for this channel only,
 	 * select "ADC read" channel, set "ADC start" bit. */
-	value = (devpriv->s526_ai_config & 0x8000) |
-	    ((1 << 5) << chan) | (chan << 1) | 0x0001;
+	value = (devpriv->ai_config & 0x8000) |
+		((1 << 5) << chan) | (chan << 1) | 0x0001;
 
 	/* convert n samples */
 	for (n = 0; n < insn->n; n++) {
 		/* trigger conversion */
-		outw(value, ADDR_REG(REG_ADC));
-/* printk("s526: Wrote 0x%04x to ADC\n", value); */
-/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */
+		outw(value, dev->iobase + REG_ADC);
 
 #define TIMEOUT 100
 		/* wait for conversion to end */
 		for (i = 0; i < TIMEOUT; i++) {
-			status = inw(ADDR_REG(REG_ISR));
+			status = inw(dev->iobase + REG_ISR);
 			if (status & ISR_ADC_DONE) {
-				outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
+				outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
 				break;
 			}
 		}
-		if (i == TIMEOUT) {
-			/* printk() should be used instead of printk()
-			 * whenever the code can be called from real-time. */
-			printk(KERN_ERR "s526: ADC(0x%04x) timeout\n",
-			       inw(ADDR_REG(REG_ISR)));
+		if (i == TIMEOUT)
 			return -ETIMEDOUT;
-		}
 
 		/* read data */
-		d = inw(ADDR_REG(REG_ADD));
-/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */
+		d = inw(dev->iobase + REG_ADD);
 
 		/* munge data */
 		data[n] = d ^ 0x8000;
@@ -620,40 +471,30 @@
 static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
-	int i;
-	int chan = CR_CHAN(insn->chanspec);
+	struct s526_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned short val;
+	int i;
 
-/* printk("s526_ao_winsn\n"); */
 	val = chan << 1;
-/* outw(val, dev->iobase + REG_DAC); */
-	outw(val, ADDR_REG(REG_DAC));
+	outw(val, dev->iobase + REG_DAC);
 
-	/* Writing a list of values to an AO channel is probably not
-	 * very useful, but that's how the interface is defined. */
 	for (i = 0; i < insn->n; i++) {
-		/* a typical programming sequence */
-		/* write the data to preload register
-		 * outw(data[i], dev->iobase + REG_ADD);
-		 */
-		/* write the data to preload register */
-		outw(data[i], ADDR_REG(REG_ADD));
+		outw(data[i], dev->iobase + REG_ADD);
 		devpriv->ao_readback[chan] = data[i];
-/* outw(val + 1, dev->iobase + REG_DAC);  starts the D/A conversion. */
-		outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/
+		/* starts the D/A conversion */
+		outw(val + 1, dev->iobase + REG_DAC);
 	}
 
-	/* return the number of samples read/written */
 	return i;
 }
 
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
 static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
+	struct s526_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	int i;
-	int chan = CR_CHAN(insn->chanspec);
 
 	for (i = 0; i < insn->n; i++)
 		data[i] = devpriv->ao_readback[chan];
@@ -661,30 +502,18 @@
 	return i;
 }
 
-/* DIO devices are slightly special.  Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels.  The
- * comedi core can convert between insn_bits and insn_read/write */
 static int s526_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	/* The insn data is a mask in data[0] and the new data
-	 * in data[1], each channel cooresponding to a bit. */
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
-		/* Write out the new digital output lines */
-		outw(s->state, ADDR_REG(REG_DIO));
+
+		outw(s->state, dev->iobase + REG_DIO);
 	}
 
-	/* on return, data[1] contains the value of the digital
-	 * input and output lines. */
-	data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */
-	/* or we could just return the software copy of the output values if
-	 * it was a purely digital output subdevice */
-	/* data[1]=s->state & 0xFF; */
+	data[1] = inw(dev->iobase + REG_DIO) & 0xff;
 
 	return insn->n;
 }
@@ -693,16 +522,9 @@
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	int chan = CR_CHAN(insn->chanspec);
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	int group, mask;
 
-	printk(KERN_INFO "S526 DIO insn_config\n");
-
-	/* The input or output configuration of each digital line is
-	 * configured by a special insn_config instruction.  chanspec
-	 * contains the channel to be changed, and data[0] contains the
-	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
-
 	group = chan >> 2;
 	mask = 0xF << (group << 2);
 	switch (data[0]) {
@@ -721,88 +543,60 @@
 	default:
 		return -EINVAL;
 	}
-	outw(s->state, ADDR_REG(REG_DIO));
+	outw(s->state, dev->iobase + REG_DIO);
 
 	return 1;
 }
 
 static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	const struct s526_board *board = comedi_board(dev);
+	struct s526_private *devpriv;
 	struct comedi_subdevice *s;
 	int iobase;
-	int i, n;
 	int ret;
-/* short value; */
-/* int subdev_channel = 0; */
-	union cmReg cmReg;
 
-	printk(KERN_INFO "comedi%d: s526: ", dev->minor);
+	dev->board_name = dev->driver->driver_name;
 
 	iobase = it->options[0];
-	if (!iobase || !request_region(iobase, S526_IOSIZE, board->name)) {
+	if (!iobase || !request_region(iobase, S526_IOSIZE, dev->board_name)) {
 		comedi_error(dev, "I/O port conflict");
 		return -EIO;
 	}
 	dev->iobase = iobase;
 
-	printk("iobase=0x%lx\n", dev->iobase);
-
-	/*** make it a little quieter, exw, 8/29/06
-	for (i = 0; i < S526_NUM_PORTS; i++) {
-		printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
-				inw(ADDR_REG(s526_ports[i])));
-	}
-	***/
-
-	dev->board_name = board->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_private(dev, sizeof(struct s526_private)) < 0)
-		return -ENOMEM;
+	ret = alloc_private(dev, sizeof(*devpriv));
+	if (ret)
+		return ret;
+	devpriv = dev->private;
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
-	/* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
-	s->n_chan = board->gpct_chans;
+	s->n_chan = 4;
 	s->maxdata = 0x00ffffff;	/* 24 bit counter */
 	s->insn_read = s526_gpct_rinsn;
 	s->insn_config = s526_gpct_insn_config;
 	s->insn_write = s526_gpct_winsn;
 
-	/* Command are not implemented yet, however they are necessary to
-	   allocate the necessary memory for the comedi_async struct (used
-	   to trigger the GPCT in case of pulsegenerator function */
-	/* s->do_cmd = s526_gpct_cmd; */
-	/* s->do_cmdtest = s526_gpct_cmdtest; */
-	/* s->cancel = s526_gpct_cancel; */
-
-	s = dev->subdevices + 1;
-	/* dev->read_subdev=s; */
+	s = &dev->subdevices[1];
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
-	/* we support differential */
 	s->subdev_flags = SDF_READABLE | SDF_DIFF;
 	/* channels 0 to 7 are the regular differential inputs */
 	/* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
 	s->n_chan = 10;
 	s->maxdata = 0xffff;
 	s->range_table = &range_bipolar10;
-	s->len_chanlist = 16;	/* This is the maximum chanlist length that
-				   the board can handle */
+	s->len_chanlist = 16;
 	s->insn_read = s526_ai_rinsn;
 	s->insn_config = s526_ai_insn_config;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -812,106 +606,19 @@
 	s->insn_write = s526_ao_winsn;
 	s->insn_read = s526_ao_rinsn;
 
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	/* digital i/o subdevice */
-	if (board->have_dio) {
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = 8;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = s526_dio_insn_bits;
-		s->insn_config = s526_dio_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = s526_dio_insn_bits;
+	s->insn_config = s526_dio_insn_config;
 
-	printk(KERN_INFO "attached\n");
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
 	return 1;
-
-#if 0
-	/*  Example of Counter Application */
-	/* One-shot (software trigger) */
-	cmReg.reg.coutSource = 0;	/*  out RCAP */
-	cmReg.reg.coutPolarity = 1;	/*  Polarity inverted */
-	cmReg.reg.autoLoadResetRcap = 1;/*  Auto load 0:disabled, 1:enabled */
-	cmReg.reg.hwCtEnableSource = 3;	/*  NOT RCAP */
-	cmReg.reg.ctEnableCtrl = 2;	/*  Hardware */
-	cmReg.reg.clockSource = 2;	/*  Internal */
-	cmReg.reg.countDir = 1;	/*  Down */
-	cmReg.reg.countDirCtrl = 1;	/*  Software */
-	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
-	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-	cmReg.reg.reserved = 0;
-
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
-
-	outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
-	outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
-
-	/*  Reset the counter */
-	outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-	/*  Load the counter from PR0 */
-	outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-	/*  Reset RCAP (fires one-shot) */
-	outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-
-#else
-
-	/*  Set Counter Mode Register */
-	cmReg.reg.coutSource = 0;	/*  out RCAP */
-	cmReg.reg.coutPolarity = 0;	/*  Polarity inverted */
-	cmReg.reg.autoLoadResetRcap = 0;	/*  Auto load disabled */
-	cmReg.reg.hwCtEnableSource = 2;	/*  NOT RCAP */
-	cmReg.reg.ctEnableCtrl = 1;	/*  1: Software,  >1 : Hardware */
-	cmReg.reg.clockSource = 3;	/*  x4 */
-	cmReg.reg.countDir = 0;	/*  up */
-	cmReg.reg.countDirCtrl = 0;	/*  quadrature */
-	cmReg.reg.outputRegLatchCtrl = 0;	/*  latch on read */
-	cmReg.reg.preloadRegSel = 0;	/*  PR0 */
-	cmReg.reg.reserved = 0;
-
-	n = 0;
-	printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
-		cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	udelay(1000);
-	printk(KERN_INFO "Read back mode reg=0x%04x\n",
-		inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-	/*  Load the pre-load register high word */
-/* value = (short) (0x55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
-
-	/*  Load the pre-load register low word */
-/* value = (short)(0xaa55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
-
-	/*  Write the Counter Control Register */
-/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
-
-	/*  Reset the counter if it is software preload */
-	if (cmReg.reg.autoLoadResetRcap == 0) {
-		/*  Reset the counter */
-		outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
-		/*  Load the counter from PR0 */
-		outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
-	}
-
-	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
-	udelay(1000);
-	printk(KERN_INFO "Read back mode reg=0x%04x\n",
-			inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-#endif
-	printk(KERN_INFO "Current registres:\n");
-
-	for (i = 0; i < S526_NUM_PORTS; i++) {
-		printk(KERN_INFO "0x%02lx: 0x%04x\n",
-			ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
-	}
-	return 1;
 }
 
 static void s526_detach(struct comedi_device *dev)
@@ -925,9 +632,6 @@
 	.module		= THIS_MODULE,
 	.attach		= s526_attach,
 	.detach		= s526_detach,
-	.board_name	= &s526_boards[0].name,
-	.offset		= sizeof(struct s526_board),
-	.num_names	= ARRAY_SIZE(s526_boards),
 };
 module_comedi_driver(s526_driver);
 
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index f90578e..551d68b 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -32,11 +32,7 @@
 Updated: Fri, 15 Feb 2008 10:28:42 +0000
 Status: experimental
 
-Configuration options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration options: not applicable, uses PCI auto config
 
 INSN_CONFIG instructions:
   analog input:
@@ -82,45 +78,8 @@
 #define PCI_SUBVENDOR_ID_S626 0x6000
 #define PCI_SUBDEVICE_ID_S626 0x0272
 
-struct s626_board {
-	const char *name;
-	int vendor_id;
-	int device_id;
-	int subvendor_id;
-	int subdevice_id;
-	int ai_chans;
-	int ai_bits;
-	int ao_chans;
-	int ao_bits;
-	int dio_chans;
-	int dio_banks;
-	int enc_chans;
-};
-
-static const struct s626_board s626_boards[] = {
-	{
-	 .name = "s626",
-	 .vendor_id = PCI_VENDOR_ID_S626,
-	 .device_id = PCI_DEVICE_ID_S626,
-	 .subvendor_id = PCI_SUBVENDOR_ID_S626,
-	 .subdevice_id = PCI_SUBDEVICE_ID_S626,
-	 .ai_chans = S626_ADC_CHANNELS,
-	 .ai_bits = 14,
-	 .ao_chans = S626_DAC_CHANNELS,
-	 .ao_bits = 13,
-	 .dio_chans = S626_DIO_CHANNELS,
-	 .dio_banks = S626_DIO_BANKS,
-	 .enc_chans = S626_ENCODER_CHANNELS,
-	 }
-};
-
-#define thisboard ((const struct s626_board *)dev->board_ptr)
-
 struct s626_private {
-	struct pci_dev *pdev;
 	void __iomem *base_addr;
-	int got_regions;
-	short allocatedBuf;
 	uint8_t ai_cmd_running;	/*  ai_cmd is running */
 	uint8_t ai_continous;	/*  continous acquisition */
 	int ai_sample_count;	/*  number of samples to acquire */
@@ -139,9 +98,7 @@
 	/* Pointer to logical adrs of DMA buffer used to hold DAC  data. */
 	uint16_t Dacpol;	/* Image of DAC polarity register. */
 	uint8_t TrimSetpoint[12];	/* Images of TrimDAC setpoints */
-	uint16_t ChargeEnabled;	/* Image of MISC2 Battery */
 	/* Charge Enabled (0 or WRMISC2_CHARGE_ENABLE). */
-	uint16_t WDInterval;	/* Image of MISC2 watchdog interval control bits. */
 	uint32_t I2CAdrs;
 	/* I2C device address for onboard EEPROM (board rev dependent). */
 	/*   short         I2Cards; */
@@ -1548,56 +1505,28 @@
 	int err = 0;
 	int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.  Using
-	 * the cmdtest ioctl, a user can create a valid cmd and then have it
-	 * executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4 or 0, depending on which tests the
-	 * command passes. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* step 1: make sure trigger sources are trivially valid */
-
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src,
+					TRIG_NOW | TRIG_INT | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->convert_src,
+					TRIG_TIMER | TRIG_EXT | TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually
-	   compatible */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT
-	    && cmd->scan_begin_src != TRIG_FOLLOW)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER &&
-	    cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1847,6 +1776,9 @@
 /* Now this function initializes the value of the counter (data[0])
    and set the subdevice. To complete with trigger and interrupt
    configuration */
+/* FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating
+ * what is being configured, but this function appears to be using data[0]
+ * as a variable. */
 static int s626_enc_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
@@ -1868,7 +1800,7 @@
 	/*   (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */
 
 	k->SetMode(dev, k, Setup, TRUE);
-	Preload(dev, k, *(insn->data));
+	Preload(dev, k, data[0]);
 	k->PulseIndex(dev, k);
 	SetLatchSource(dev, k, valueSrclatch);
 	k->SetEnable(dev, k, (uint16_t) (enab != 0));
@@ -1920,6 +1852,7 @@
 static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
 		      size_t bsize)
 {
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 	void *vbptr;
 	dma_addr_t vpptr;
 
@@ -1930,7 +1863,7 @@
 	vbptr = pdma->LogicalBase;
 	vpptr = pdma->PhysicalBase;
 	if (vbptr) {
-		pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr);
+		pci_free_consistent(pcidev, bsize, vbptr, vpptr);
 		pdma->LogicalBase = NULL;
 		pdma->PhysicalBase = 0;
 	}
@@ -2476,146 +2409,317 @@
 	}
 }
 
-static struct pci_dev *s626_find_pci(struct comedi_device *dev,
-				     struct comedi_devconfig *it)
+static int s626_allocate_dma_buffers(struct comedi_device *dev)
 {
-	struct pci_dev *pcidev = NULL;
-	int bus = it->options[0];
-	int slot = it->options[1];
-	int i;
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+	void *addr;
+	dma_addr_t appdma;
 
-	for (i = 0; i < ARRAY_SIZE(s626_boards) && !pcidev; i++) {
-		do {
-			pcidev = pci_get_subsys(s626_boards[i].vendor_id,
-						s626_boards[i].device_id,
-						s626_boards[i].subvendor_id,
-						s626_boards[i].subdevice_id,
-						pcidev);
+	addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma);
+	if (!addr)
+		return -ENOMEM;
+	devpriv->ANABuf.LogicalBase = addr;
+	devpriv->ANABuf.PhysicalBase = appdma;
 
-			if ((bus || slot) && pcidev) {
-				/* matches requested bus/slot */
-				if (pcidev->bus->number == bus &&
-				    PCI_SLOT(pcidev->devfn) == slot)
-					break;
-			} else {
-				break;
-			}
-		} while (1);
-	}
-	return pcidev;
+	addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma);
+	if (!addr)
+		return -ENOMEM;
+	devpriv->RPSBuf.LogicalBase = addr;
+	devpriv->RPSBuf.PhysicalBase = appdma;
+
+	return 0;
 }
 
-static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static void s626_initialize(struct comedi_device *dev)
 {
-/*   uint8_t	PollList; */
-/*   uint16_t	AdcData; */
-/*   uint16_t	StartVal; */
-/*   uint16_t	index; */
-/*   unsigned int data[16]; */
-	int result;
+	dma_addr_t pPhysBuf;
+	uint16_t chan;
 	int i;
-	int ret;
-	resource_size_t resourceStart;
-	dma_addr_t appdma;
+
+	/* Enable DEBI and audio pins, enable I2C interface */
+	MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
+
+	/*
+	 *  Configure DEBI operating mode
+	 *
+	 *   Local bus is 16 bits wide
+	 *   Declare DEBI transfer timeout interval
+	 *   Set up byte lane steering
+	 *   Intel-compatible local bus (DEBI never times out)
+	 */
+	WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 |
+			  (DEBI_TOUT << DEBI_CFG_TOUT_BIT) |
+			  DEBI_SWAP | DEBI_CFG_INTEL);
+
+	/* Disable MMU paging */
+	WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);
+
+	/* Init GPIO so that ADC Start* is negated */
+	WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
+
+	/* I2C device address for onboard eeprom (revb) */
+	devpriv->I2CAdrs = 0xA0;
+
+	/*
+	 * Issue an I2C ABORT command to halt any I2C
+	 * operation in progress and reset BUSY flag.
+	 */
+	WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);
+	MC_ENABLE(P_MC2, MC2_UPLD_IIC);
+	while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
+		;
+
+	/*
+	 * Per SAA7146 data sheet, write to STATUS
+	 * reg twice to reset all  I2C error flags.
+	 */
+	for (i = 0; i < 2; i++) {
+		WR7146(P_I2CSTAT, I2C_CLKSEL);
+		MC_ENABLE(P_MC2, MC2_UPLD_IIC);
+		while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+			;
+	}
+
+	/*
+	 * Init audio interface functional attributes: set DAC/ADC
+	 * serial clock rates, invert DAC serial clock so that
+	 * DAC data setup times are satisfied, enable DAC serial
+	 * clock out.
+	 */
+	WR7146(P_ACON2, ACON2_INIT);
+
+	/*
+	 * Set up TSL1 slot list, which is used to control the
+	 * accumulation of ADC data: RSD1 = shift data in on SD1.
+	 * SIB_A1  = store data uint8_t at next available location
+	 * in FB BUFFER1 register.
+	 */
+	WR7146(P_TSL1, RSD1 | SIB_A1);
+	WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);
+
+	/* Enable TSL1 slot list so that it executes all the time */
+	WR7146(P_ACON1, ACON1_ADCSTART);
+
+	/*
+	 * Initialize RPS registers used for ADC
+	 */
+
+	/* Physical start of RPS program */
+	WR7146(P_RPSADDR1, (uint32_t)devpriv->RPSBuf.PhysicalBase);
+	/* RPS program performs no explicit mem writes */
+	WR7146(P_RPSPAGE1, 0);
+	/* Disable RPS timeouts */
+	WR7146(P_RPS1_TOUT, 0);
+
+#if 0
+	/*
+	 * SAA7146 BUG WORKAROUND
+	 *
+	 * Initialize SAA7146 ADC interface to a known state by
+	 * invoking ADCs until FB BUFFER 1 register shows that it
+	 * is correctly receiving ADC data. This is necessary
+	 * because the SAA7146 ADC interface does not start up in
+	 * a defined state after a PCI reset.
+	 */
+
+	{
+	uint8_t PollList;
+	uint16_t AdcData;
+	uint16_t StartVal;
+	uint16_t index;
+	unsigned int data[16];
+
+	/* Create a simple polling list for analog input channel 0 */
+	PollList = EOPL;
+	ResetADC(dev, &PollList);
+
+	/* Get initial ADC value */
+	s626_ai_rinsn(dev, dev->subdevices, NULL, data);
+	StartVal = data[0];
+
+	/*
+	 * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION.
+	 *
+	 * Invoke ADCs until the new ADC value differs from the initial
+	 * value or a timeout occurs.  The timeout protects against the
+	 * possibility that the driver is restarting and the ADC data is a
+	 * fixed value resulting from the applied ADC analog input being
+	 * unusually quiet or at the rail.
+	 */
+	for (index = 0; index < 500; index++) {
+		s626_ai_rinsn(dev, dev->subdevices, NULL, data);
+		AdcData = data[0];
+		if (AdcData != StartVal)
+			break;
+	}
+
+	}
+#endif	/* SAA7146 BUG WORKAROUND */
+
+	/*
+	 * Initialize the DAC interface
+	 */
+
+	/*
+	 * Init Audio2's output DMAC attributes:
+	 *   burst length = 1 DWORD
+	 *   threshold = 1 DWORD.
+	 */
+	WR7146(P_PCI_BT_A, 0);
+
+	/*
+	 * Init Audio2's output DMA physical addresses.  The protection
+	 * address is set to 1 DWORD past the base address so that a
+	 * single DWORD will be transferred each time a DMA transfer is
+	 * enabled.
+	 */
+	pPhysBuf = devpriv->ANABuf.PhysicalBase +
+		   (DAC_WDMABUF_OS * sizeof(uint32_t));
+	WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);
+	WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t)));
+
+	/*
+	 * Cache Audio2's output DMA buffer logical address.  This is
+	 * where DAC data is buffered for A2 output DMA transfers.
+	 */
+	devpriv->pDacWBuf = (uint32_t *)devpriv->ANABuf.LogicalBase +
+			    DAC_WDMABUF_OS;
+
+	/*
+	 * Audio2's output channels does not use paging.  The
+	 * protection violation handling bit is set so that the
+	 * DMAC will automatically halt and its PCI address pointer
+	 * will be reset when the protection address is reached.
+	 */
+	WR7146(P_PAGEA2_OUT, 8);
+
+	/*
+	 * Initialize time slot list 2 (TSL2), which is used to control
+	 * the clock generation for and serialization of data to be sent
+	 * to the DAC devices.  Slot 0 is a NOP that is used to trap TSL
+	 * execution; this permits other slots to be safely modified
+	 * without first turning off the TSL sequencer (which is
+	 * apparently impossible to do).  Also, SD3 (which is driven by a
+	 * pull-up resistor) is shifted in and stored to the MSB of
+	 * FB_BUFFER2 to be used as evidence that the slot sequence has
+	 * not yet finished executing.
+	 */
+
+	/* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */
+	SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS);
+
+	/*
+	 * Initialize slot 1, which is constant.  Slot 1 causes a
+	 * DWORD to be transferred from audio channel 2's output FIFO
+	 * to the FIFO's output buffer so that it can be serialized
+	 * and sent to the DAC during subsequent slots.  All remaining
+	 * slots are dynamically populated as required by the target
+	 * DAC device.
+	 */
+
+	/* Slot 1: Fetch DWORD from Audio2's output FIFO */
+	SETVECT(1, LF_A2);
+
+	/* Start DAC's audio interface (TSL2) running */
+	WR7146(P_ACON1, ACON1_DACSTART);
+
+	/*
+	 * Init Trim DACs to calibrated values.  Do it twice because the
+	 * SAA7146 audio channel does not always reset properly and
+	 * sometimes causes the first few TrimDAC writes to malfunction.
+	 */
+	LoadTrimDACs(dev);
+	LoadTrimDACs(dev);
+
+	/*
+	 * Manually init all gate array hardware in case this is a soft
+	 * reset (we have no way of determining whether this is a warm
+	 * or cold start).  This is necessary because the gate array will
+	 * reset only in response to a PCI hard reset; there is no soft
+	 * reset function.
+	 */
+
+	/*
+	 * Init all DAC outputs to 0V and init all DAC setpoint and
+	 * polarity images.
+	 */
+	for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
+		SetDAC(dev, chan, 0);
+
+	/* Init counters */
+	CountersInit(dev);
+
+	/*
+	 * Without modifying the state of the Battery Backup enab, disable
+	 * the watchdog timer, set DIO channels 0-5 to operate in the
+	 * standard DIO (vs. counter overflow) mode, disable the battery
+	 * charger, and reset the watchdog interval selector to zero.
+	 */
+	WriteMISC2(dev, (uint16_t)(DEBIread(dev, LP_RDMISC2) &
+				   MISC2_BATT_ENABLE));
+
+	/* Initialize the digital I/O subsystem */
+	s626_dio_init(dev);
+
+	/* enable interrupt test */
+	/* writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER); */
+}
+
+static int s626_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev)
+{
 	struct comedi_subdevice *s;
+	int ret;
+
+	comedi_set_hw_dev(dev, &pcidev->dev);
+	dev->board_name = dev->driver->driver_name;
 
 	if (alloc_private(dev, sizeof(struct s626_private)) < 0)
 		return -ENOMEM;
 
-	devpriv->pdev = s626_find_pci(dev, it);
-	if (!devpriv->pdev) {
-		printk(KERN_ERR "s626_attach: Board not present!!!\n");
-		return -ENODEV;
+	ret = comedi_pci_enable(pcidev, dev->board_name);
+	if (ret)
+		return ret;
+	dev->iobase = 1;	/* detach needs this */
+
+	devpriv->base_addr = ioremap(pci_resource_start(pcidev, 0),
+				     pci_resource_len(pcidev, 0));
+	if (!devpriv->base_addr)
+		return -ENOMEM;
+
+	/* disable master interrupt */
+	writel(0, devpriv->base_addr + P_IER);
+
+	/* soft reset */
+	writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
+
+	/* DMA FIXME DMA// */
+
+	ret = s626_allocate_dma_buffers(dev);
+	if (ret)
+		return ret;
+
+	if (pcidev->irq) {
+		ret = request_irq(pcidev->irq, s626_irq_handler, IRQF_SHARED,
+				  dev->board_name, dev);
+
+		if (ret == 0)
+			dev->irq = pcidev->irq;
 	}
 
-	result = comedi_pci_enable(devpriv->pdev, "s626");
-	if (result < 0) {
-		printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n");
-		return -ENODEV;
-	}
-	devpriv->got_regions = 1;
-
-	resourceStart = pci_resource_start(devpriv->pdev, 0);
-
-	devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE);
-	if (devpriv->base_addr == NULL) {
-		printk(KERN_ERR "s626_attach: IOREMAP failed\n");
-		return -ENODEV;
-	}
-
-	if (devpriv->base_addr) {
-		/* disable master interrupt */
-		writel(0, devpriv->base_addr + P_IER);
-
-		/* soft reset */
-		writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
-
-		/* DMA FIXME DMA// */
-
-		/* adc buffer allocation */
-		devpriv->allocatedBuf = 0;
-
-		devpriv->ANABuf.LogicalBase =
-		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
-
-		if (devpriv->ANABuf.LogicalBase == NULL) {
-			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
-			return -ENOMEM;
-		}
-
-		devpriv->ANABuf.PhysicalBase = appdma;
-
-		devpriv->allocatedBuf++;
-
-		devpriv->RPSBuf.LogicalBase =
-		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
-
-		if (devpriv->RPSBuf.LogicalBase == NULL) {
-			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
-			return -ENOMEM;
-		}
-
-		devpriv->RPSBuf.PhysicalBase = appdma;
-
-		devpriv->allocatedBuf++;
-
-	}
-
-	dev->board_ptr = s626_boards;
-	dev->board_name = thisboard->name;
-
 	ret = comedi_alloc_subdevices(dev, 6);
 	if (ret)
 		return ret;
 
-	dev->iobase = (unsigned long)devpriv->base_addr;
-	dev->irq = devpriv->pdev->irq;
-
-	/* set up interrupt handler */
-	if (dev->irq == 0) {
-		printk(KERN_ERR " unknown irq (bad)\n");
-	} else {
-		ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED,
-				  "s626", dev);
-
-		if (ret < 0) {
-			printk(KERN_ERR " irq not available\n");
-			dev->irq = 0;
-		}
-	}
-
 	s = dev->subdevices + 0;
 	/* analog input subdevice */
 	dev->read_subdev = s;
 	/* we support single-ended (ground) and differential */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
-	s->n_chan = thisboard->ai_chans;
+	s->n_chan = S626_ADC_CHANNELS;
 	s->maxdata = (0xffff >> 2);
 	s->range_table = &s626_range_table;
-	s->len_chanlist = thisboard->ai_chans;	/* This is the maximum chanlist
-						   length that the board can
-						   handle */
+	s->len_chanlist = S626_ADC_CHANNELS;
 	s->insn_config = s626_ai_insn_config;
 	s->insn_read = s626_ai_insn_read;
 	s->do_cmd = s626_ai_cmd;
@@ -2626,7 +2730,7 @@
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = thisboard->ao_chans;
+	s->n_chan = S626_DAC_CHANNELS;
 	s->maxdata = (0x3fff);
 	s->range_table = &range_bipolar10;
 	s->insn_write = s626_ao_winsn;
@@ -2672,7 +2776,7 @@
 	/* encoder (counter) subdevice */
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
-	s->n_chan = thisboard->enc_chans;
+	s->n_chan = S626_ENCODER_CHANNELS;
 	s->private = enc_private_data;
 	s->insn_config = s626_enc_insn_config;
 	s->insn_read = s626_enc_insn_read;
@@ -2680,269 +2784,17 @@
 	s->maxdata = 0xffffff;
 	s->range_table = &range_unknown;
 
-	/* stop ai_command */
-	devpriv->ai_cmd_running = 0;
+	s626_initialize(dev);
 
-	if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) {
-		dma_addr_t pPhysBuf;
-		uint16_t chan;
+	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
-		/*  enab DEBI and audio pins, enable I2C interface. */
-		MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
-		/*  Configure DEBI operating mode. */
-		WR7146(P_DEBICFG, DEBI_CFG_SLAVE16	/*  Local bus is 16 */
-		       /*  bits wide. */
-		       | (DEBI_TOUT << DEBI_CFG_TOUT_BIT)
-
-		       /*  Declare DEBI */
-		       /*  transfer timeout */
-		       /*  interval. */
-		       |DEBI_SWAP	/*  Set up byte lane */
-		       /*  steering. */
-		       | DEBI_CFG_INTEL);	/*  Intel-compatible */
-		/*  local bus (DEBI */
-		/*  never times out). */
-
-		/* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */
-		/* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */
-
-		/*  Paging is disabled. */
-		WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);	/*  Disable MMU paging. */
-
-		/*  Init GPIO so that ADC Start* is negated. */
-		WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
-
-		/* IsBoardRevA is a boolean that indicates whether the board is RevA.
-		 *
-		 * VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC
-		 * EEPROM ADDRESS SELECTION.  Initialize the I2C interface, which
-		 * is used to access the onboard serial EEPROM.  The EEPROM's I2C
-		 * DeviceAddress is hardwired to a value that is dependent on the
-		 * 626 board revision.  On all board revisions, the EEPROM stores
-		 * TrimDAC calibration constants for analog I/O.  On RevB and
-		 * higher boards, the DeviceAddress is hardwired to 0 to enable
-		 * the EEPROM to also store the PCI SubVendorID and SubDeviceID;
-		 * this is the address at which the SAA7146 expects a
-		 * configuration EEPROM to reside.  On RevA boards, the EEPROM
-		 * device address, which is hardwired to 4, prevents the SAA7146
-		 * from retrieving PCI sub-IDs, so the SAA7146 uses its built-in
-		 * default values, instead.
-		 */
-
-		/*     devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */
-		/*  DeviceType (0xA0) */
-		/*  and DeviceAddress<<1. */
-
-		devpriv->I2CAdrs = 0xA0;	/*  I2C device address for onboard */
-		/*  eeprom(revb) */
-
-		/*  Issue an I2C ABORT command to halt any I2C operation in */
-		/* progress and reset BUSY flag. */
-		WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);
-		/*  Write I2C control: abort any I2C activity. */
-		MC_ENABLE(P_MC2, MC2_UPLD_IIC);
-		/*  Invoke command  upload */
-		while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
-			;
-		/*  and wait for upload to complete. */
-
-		/* Per SAA7146 data sheet, write to STATUS reg twice to
-		 * reset all  I2C error flags. */
-		for (i = 0; i < 2; i++) {
-			WR7146(P_I2CSTAT, I2C_CLKSEL);
-			/*  Write I2C control: reset  error flags. */
-			MC_ENABLE(P_MC2, MC2_UPLD_IIC);	/*  Invoke command upload */
-			while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
-				;
-			/* and wait for upload to complete. */
-		}
-
-		/* Init audio interface functional attributes: set DAC/ADC
-		 * serial clock rates, invert DAC serial clock so that
-		 * DAC data setup times are satisfied, enable DAC serial
-		 * clock out.
-		 */
-
-		WR7146(P_ACON2, ACON2_INIT);
-
-		/* Set up TSL1 slot list, which is used to control the
-		 * accumulation of ADC data: RSD1 = shift data in on SD1.
-		 * SIB_A1  = store data uint8_t at next available location in
-		 * FB BUFFER1  register. */
-		WR7146(P_TSL1, RSD1 | SIB_A1);
-		/*  Fetch ADC high data uint8_t. */
-		WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);
-		/*  Fetch ADC low data uint8_t; end of TSL1. */
-
-		/*  enab TSL1 slot list so that it executes all the time. */
-		WR7146(P_ACON1, ACON1_ADCSTART);
-
-		/*  Initialize RPS registers used for ADC. */
-
-		/* Physical start of RPS program. */
-		WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
-
-		WR7146(P_RPSPAGE1, 0);
-		/*  RPS program performs no explicit mem writes. */
-		WR7146(P_RPS1_TOUT, 0);	/*  Disable RPS timeouts. */
-
-		/* SAA7146 BUG WORKAROUND.  Initialize SAA7146 ADC interface
-		 * to a known state by invoking ADCs until FB BUFFER 1
-		 * register shows that it is correctly receiving ADC data.
-		 * This is necessary because the SAA7146 ADC interface does
-		 * not start up in a defined state after a PCI reset.
-		 */
-
-/*     PollList = EOPL;		// Create a simple polling */
-/*				// list for analog input */
-/*				// channel 0. */
-/*     ResetADC( dev, &PollList ); */
-
-/*     s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */
-/*							//Get initial ADC */
-/*							//value. */
-
-/*     StartVal = data[0]; */
-
-/*     // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */
-/*     // Invoke ADCs until the new ADC value differs from the initial */
-/*     // value or a timeout occurs.  The timeout protects against the */
-/*     // possibility that the driver is restarting and the ADC data is a */
-/*     // fixed value resulting from the applied ADC analog input being */
-/*     // unusually quiet or at the rail. */
-
-/*     for ( index = 0; index < 500; index++ ) */
-/*       { */
-/*	s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
-/*	AdcData = data[0];	//ReadADC(  &AdcData ); */
-/*	if ( AdcData != StartVal ) */
-/*		break; */
-/*       } */
-
-		/*  end initADC */
-
-		/*  init the DAC interface */
-
-		/* Init Audio2's output DMAC attributes: burst length = 1
-		 * DWORD,  threshold = 1 DWORD.
-		 */
-		WR7146(P_PCI_BT_A, 0);
-
-		/* Init Audio2's output DMA physical addresses.  The protection
-		 * address is set to 1 DWORD past the base address so that a
-		 * single DWORD will be transferred each time a DMA transfer is
-		 * enabled. */
-
-		pPhysBuf =
-		    devpriv->ANABuf.PhysicalBase +
-		    (DAC_WDMABUF_OS * sizeof(uint32_t));
-
-		WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);	/*  Buffer base adrs. */
-		WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t)));	/*  Protection address. */
-
-		/* Cache Audio2's output DMA buffer logical address.  This is
-		 * where DAC data is buffered for A2 output DMA transfers. */
-		devpriv->pDacWBuf =
-		    (uint32_t *) devpriv->ANABuf.LogicalBase + DAC_WDMABUF_OS;
-
-		/* Audio2's output channels does not use paging.  The protection
-		 * violation handling bit is set so that the DMAC will
-		 * automatically halt and its PCI address pointer will be reset
-		 * when the protection address is reached. */
-
-		WR7146(P_PAGEA2_OUT, 8);
-
-		/* Initialize time slot list 2 (TSL2), which is used to control
-		 * the clock generation for and serialization of data to be sent
-		 * to the DAC devices.  Slot 0 is a NOP that is used to trap TSL
-		 * execution; this permits other slots to be safely modified
-		 * without first turning off the TSL sequencer (which is
-		 * apparently impossible to do).  Also, SD3 (which is driven by a
-		 * pull-up resistor) is shifted in and stored to the MSB of
-		 * FB_BUFFER2 to be used as evidence that the slot sequence has
-		 * not yet finished executing.
-		 */
-
-		SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS);
-		/*  Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */
-
-		/* Initialize slot 1, which is constant.  Slot 1 causes a
-		 * DWORD to be transferred from audio channel 2's output FIFO
-		 * to the FIFO's output buffer so that it can be serialized
-		 * and sent to the DAC during subsequent slots.  All remaining
-		 * slots are dynamically populated as required by the target
-		 * DAC device.
-		 */
-		SETVECT(1, LF_A2);
-		/*  Slot 1: Fetch DWORD from Audio2's output FIFO. */
-
-		/*  Start DAC's audio interface (TSL2) running. */
-		WR7146(P_ACON1, ACON1_DACSTART);
-
-		/* end init DAC interface */
-
-		/* Init Trim DACs to calibrated values.  Do it twice because the
-		 * SAA7146 audio channel does not always reset properly and
-		 * sometimes causes the first few TrimDAC writes to malfunction.
-		 */
-
-		LoadTrimDACs(dev);
-		LoadTrimDACs(dev);	/*  Insurance. */
-
-		/* Manually init all gate array hardware in case this is a soft
-		 * reset (we have no way of determining whether this is a warm
-		 * or cold start).  This is necessary because the gate array will
-		 * reset only in response to a PCI hard reset; there is no soft
-		 * reset function. */
-
-		/* Init all DAC outputs to 0V and init all DAC setpoint and
-		 * polarity images.
-		 */
-		for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
-			SetDAC(dev, chan, 0);
-
-		/* Init image of WRMISC2 Battery Charger Enabled control bit.
-		 * This image is used when the state of the charger control bit,
-		 * which has no direct hardware readback mechanism, is queried.
-		 */
-		devpriv->ChargeEnabled = 0;
-
-		/* Init image of watchdog timer interval in WRMISC2.  This image
-		 * maintains the value of the control bits of MISC2 are
-		 * continuously reset to zero as long as the WD timer is disabled.
-		 */
-		devpriv->WDInterval = 0;
-
-		/* Init Counter Interrupt enab mask for RDMISC2.  This mask is
-		 * applied against MISC2 when testing to determine which timer
-		 * events are requesting interrupt service.
-		 */
-		devpriv->CounterIntEnabs = 0;
-
-		/*  Init counters. */
-		CountersInit(dev);
-
-		/* Without modifying the state of the Battery Backup enab, disable
-		 * the watchdog timer, set DIO channels 0-5 to operate in the
-		 * standard DIO (vs. counter overflow) mode, disable the battery
-		 * charger, and reset the watchdog interval selector to zero.
-		 */
-		WriteMISC2(dev, (uint16_t) (DEBIread(dev,
-						     LP_RDMISC2) &
-					    MISC2_BATT_ENABLE));
-
-		/*  Initialize the digital I/O subsystem. */
-		s626_dio_init(dev);
-
-		/* enable interrupt test */
-		/*  writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */
-	}
-
-	return 1;
+	return 0;
 }
 
 static void s626_detach(struct comedi_device *dev)
 {
+	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
 	if (devpriv) {
 		/* stop ai_command */
 		devpriv->ai_cmd_running = 0;
@@ -2967,18 +2819,17 @@
 			free_irq(dev->irq, dev);
 		if (devpriv->base_addr)
 			iounmap(devpriv->base_addr);
-		if (devpriv->pdev) {
-			if (devpriv->got_regions)
-				comedi_pci_disable(devpriv->pdev);
-			pci_dev_put(devpriv->pdev);
-		}
+	}
+	if (pcidev) {
+		if (dev->iobase)
+			comedi_pci_disable(pcidev);
 	}
 }
 
 static struct comedi_driver s626_driver = {
 	.driver_name	= "s626",
 	.module		= THIS_MODULE,
-	.attach		= s626_attach,
+	.attach_pci	= s626_attach_pci,
 	.detach		= s626_detach,
 };
 
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index 8a8f196..ff4b3a5 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -73,7 +73,6 @@
 #include <linux/slab.h>
 
 #define S626_SIZE 0x0200
-#define SIZEOF_ADDRESS_SPACE		0x0200
 #define DMABUF_SIZE			4096	/*  4k pages */
 
 #define S626_ADC_CHANNELS       16
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index c18314b..5bf84cf 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -588,7 +588,9 @@
 				kfree(s->range_table_list);
 				s->range_table = NULL;
 				s->range_table_list = NULL;
-				if (range) {
+				if (kind == 1 || kind == 2) {
+					s->range_table = &range_digital;
+				} else if (range) {
 					s->range_table_list = range_table_list =
 					    kmalloc(sizeof
 						    (struct
@@ -798,7 +800,7 @@
 		return ret;
 
 	/* digital input subdevice */
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = 0;
@@ -807,7 +809,7 @@
 	s->insn_read = &serial2002_di_rinsn;
 
 	/* digital output subdevice */
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITEABLE;
 	s->n_chan = 0;
@@ -816,7 +818,7 @@
 	s->insn_write = &serial2002_do_winsn;
 
 	/* analog input subdevice */
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = 0;
@@ -825,7 +827,7 @@
 	s->insn_read = &serial2002_ai_rinsn;
 
 	/* analog output subdevice */
-	s = dev->subdevices + 3;
+	s = &dev->subdevices[3];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITEABLE;
 	s->n_chan = 0;
@@ -835,7 +837,7 @@
 	s->insn_read = &serial2002_ao_rinsn;
 
 	/* encoder input subdevice */
-	s = dev->subdevices + 4;
+	s = &dev->subdevices[4];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
 	s->n_chan = 0;
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 9a68eeb..b70cdf3 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -76,6 +76,8 @@
 
 #include <linux/pci.h>		/* for PCI devices */
 
+#include "comedi_fc.h"
+
 /* Imaginary registers for the imaginary board */
 
 #define SKEL_SIZE 0
@@ -238,7 +240,7 @@
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* dev->read_subdev=s; */
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
@@ -256,7 +258,7 @@
 */
 	s->do_cmdtest = skel_ai_cmdtest;
 
-	s = dev->subdevices + 1;
+	s = &dev->subdevices[1];
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
@@ -266,7 +268,7 @@
 	s->insn_write = skel_ao_winsn;
 	s->insn_read = skel_ao_rinsn;
 
-	s = dev->subdevices + 2;
+	s = &dev->subdevices[2];
 	/* digital i/o subdevice */
 	if (thisboard->have_dio) {
 		s->type = COMEDI_SUBD_DIO;
@@ -349,60 +351,40 @@
 	return n;
 }
 
+/*
+ * cmdtest tests a particular command to see if it is valid.
+ * Using the cmdtest ioctl, a user can create a valid cmd
+ * and then have it executes by the cmd ioctl.
+ *
+ * cmdtest returns 1,2,3,4 or 0, depending on which tests
+ * the command passes.
+ */
 static int skel_ai_cmdtest(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
+			   struct comedi_subdevice *s,
+			   struct comedi_cmd *cmd)
 {
 	int err = 0;
 	int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.
-	 * Using the cmdtest ioctl, a user can create a valid cmd
-	 * and then have it executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
-	 * the command passes. */
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* step 1: make sure trigger sources are trivially valid */
-
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/* step 2: make sure trigger sources are unique and mutually compatible
-     */
+	/* Step 2a : make sure trigger sources are unique */
 
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 84b9f2a4..ae3aa1c 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -177,15 +177,13 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
-
 	dev->board_name = board->name;
 
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
 		return ret;
 
-	s = dev->subdevices + 0;
+	s = &dev->subdevices[0];
 	/* digital i/o subdevice                                             */
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -195,8 +193,6 @@
 	s->insn_bits = dnp_dio_insn_bits;
 	s->insn_config = dnp_dio_insn_config;
 
-	printk("attached\n");
-
 	/* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
 	 * allocated for the primary 8259, so we don't need to allocate them
 	 * ourselves. */
@@ -209,6 +205,7 @@
 	outb(PCMR, CSCIR);
 	outb((inb(CSCDR) & 0xAA), CSCDR);
 
+	dev_info(dev->class_dev, "%s: attached\n", dev->board_name);
 	return 1;
 }
 
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 11ee836..b536bba 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -98,6 +98,8 @@
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
+
 /* timeout for the USB-transfer in ms*/
 #define BULK_TIMEOUT 1000
 
@@ -404,7 +406,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 	/* subdevice which is the AD converter */
-	s = this_comedidev->subdevices + SUBDEV_AD;
+	s = &this_comedidev->subdevices[SUBDEV_AD];
 
 	/* first we test if something unusual has just happened */
 	switch (urb->status) {
@@ -604,7 +606,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 
-	s = this_comedidev->subdevices + SUBDEV_DA;
+	s = &this_comedidev->subdevices[SUBDEV_DA];
 
 	switch (urb->status) {
 	case 0:
@@ -929,9 +931,9 @@
 static int usbdux_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
-	int err = 0, tmp, i;
-	unsigned int tmpTimer;
 	struct usbduxsub *this_usbduxsub = dev->private;
+	int err = 0, i;
+	unsigned int tmpTimer;
 
 	if (!(this_usbduxsub->probed))
 		return -ENODEV;
@@ -939,51 +941,23 @@
 	dev_dbg(&this_usbduxsub->interface->dev,
 		"comedi%d: usbdux_ai_cmdtest\n", dev->minor);
 
-	/* make sure triggers are valid */
-	/* Only immediate triggers are allowed */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* trigger should happen timed */
-	tmp = cmd->scan_begin_src;
-	/* start a new _scan_ with a timer */
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	/* scanning is continuous */
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	/* issue a trigger when scan is finished and start a new scan */
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	/* trigger at the end of count events or not, stop condition or not */
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually compatible
-	 * note that mutual compatibility is not an issue here
-	 */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1488,8 +1462,9 @@
 static int usbdux_ao_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
-	int err = 0, tmp;
 	struct usbduxsub *this_usbduxsub = dev->private;
+	int err = 0;
+	unsigned int flags;
 
 	if (!this_usbduxsub)
 		return -EFAULT;
@@ -1500,69 +1475,46 @@
 	dev_dbg(&this_usbduxsub->interface->dev,
 		"comedi%d: usbdux_ao_cmdtest\n", dev->minor);
 
-	/* make sure triggers are valid */
-	/* Only immediate triggers are allowed */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* trigger should happen timed */
-	tmp = cmd->scan_begin_src;
-	/* just now we scan also in the high speed mode every frame */
-	/* this is due to ehci driver limitations */
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+
 	if (0) {		/* (this_usbduxsub->high_speed) */
-		/* start immediately a new scan */
 		/* the sampling rate is set by the coversion rate */
-		cmd->scan_begin_src &= TRIG_FOLLOW;
+		flags = TRIG_FOLLOW;
 	} else {
 		/* start a new scan (output at once) with a timer */
-		cmd->scan_begin_src &= TRIG_TIMER;
+		flags = TRIG_TIMER;
 	}
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
 
-	/* scanning is continuous */
-	tmp = cmd->convert_src;
-	/* we always output at 1kHz just now all channels at once */
 	if (0) {		/* (this_usbduxsub->high_speed) */
 		/*
-		 * in usb-2.0 only one conversion it transmitted but with 8kHz/n
+		 * in usb-2.0 only one conversion it transmitted
+		 * but with 8kHz/n
 		 */
-		cmd->convert_src &= TRIG_TIMER;
+		flags = TRIG_TIMER;
 	} else {
-		/* all conversion events happen simultaneously with a rate of
-		 * 1kHz/n */
-		cmd->convert_src &= TRIG_NOW;
+		/*
+		 * all conversion events happen simultaneously with
+		 * a rate of 1kHz/n
+		 */
+		flags = TRIG_NOW;
 	}
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, flags);
 
-	/* issue a trigger when scan is finished and start a new scan */
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	/* trigger at the end of count events or not, stop condition or not */
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually compatible
-	 * note that mutual compatibility is not an issue here
-	 */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1947,7 +1899,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 
-	s = this_comedidev->subdevices + SUBDEV_DA;
+	s = &this_comedidev->subdevices[SUBDEV_DA];
 
 	switch (urb->status) {
 	case 0:
@@ -2293,10 +2245,8 @@
 	usbduxsub_tmp->pwm_cmd_running = 0;
 }
 
-/* common part of attach and attach_usb */
 static int usbdux_attach_common(struct comedi_device *dev,
-				struct usbduxsub *udev,
-				void *aux_data, int aux_len)
+				struct usbduxsub *udev)
 {
 	int ret;
 	struct comedi_subdevice *s = NULL;
@@ -2306,10 +2256,6 @@
 	/* pointer back to the corresponding comedi device */
 	udev->comedidev = dev;
 
-	/* trying to upload the firmware into the chip */
-	if (aux_data)
-		firmwareUpload(udev, aux_data, aux_len);
-
 	dev->board_name = "usbdux";
 
 	/* set number of subdevices */
@@ -2331,7 +2277,7 @@
 	dev->private = udev;
 
 	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
+	s = &dev->subdevices[SUBDEV_AD];
 	/* the URBs get the comedi subdevice */
 	/* which is responsible for reading */
 	/* this is the subdevice which reads data */
@@ -2358,7 +2304,7 @@
 	s->range_table = (&range_usbdux_ai_range);
 
 	/* analog out */
-	s = dev->subdevices + SUBDEV_DA;
+	s = &dev->subdevices[SUBDEV_DA];
 	/* analog out */
 	s->type = COMEDI_SUBD_AO;
 	/* backward pointer */
@@ -2384,7 +2330,7 @@
 	s->insn_write = usbdux_ao_insn_write;
 
 	/* digital I/O */
-	s = dev->subdevices + SUBDEV_DIO;
+	s = &dev->subdevices[SUBDEV_DIO];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 8;
@@ -2396,7 +2342,7 @@
 	s->private = NULL;
 
 	/* counter */
-	s = dev->subdevices + SUBDEV_COUNTER;
+	s = &dev->subdevices[SUBDEV_COUNTER];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 	s->n_chan = 4;
@@ -2407,7 +2353,7 @@
 
 	if (udev->high_speed) {
 		/* timer / pwm */
-		s = dev->subdevices + SUBDEV_PWM;
+		s = &dev->subdevices[SUBDEV_PWM];
 		s->type = COMEDI_SUBD_PWM;
 		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
 		s->n_chan = 8;
@@ -2429,48 +2375,6 @@
 	return 0;
 }
 
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	void *aux_data;
-	int aux_len;
-
-	dev->private = NULL;
-
-	aux_data = comedi_aux_data(it->options, 0);
-	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-	if (aux_data == NULL)
-		aux_len = 0;
-	else if (aux_len == 0)
-		aux_data = NULL;
-
-	down(&start_stop_sem);
-	/* find a valid device which has been detected by the probe function of
-	 * the usb */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
-			index = i;
-			break;
-		}
-	}
-
-	if (index < 0) {
-		printk(KERN_ERR
-		       "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
-		       dev->minor);
-		ret = -ENODEV;
-	} else
-		ret = usbdux_attach_common(dev, &usbduxsub[index],
-					   aux_data, aux_len);
-	up(&start_stop_sem);
-	return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
 static int usbdux_attach_usb(struct comedi_device *dev,
 			     struct usb_interface *uinterf)
 {
@@ -2492,7 +2396,7 @@
 		       dev->minor);
 		ret = -ENODEV;
 	} else
-		ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+		ret = usbdux_attach_common(dev, this_usbduxsub);
 	up(&start_stop_sem);
 	return ret;
 }
@@ -2513,9 +2417,8 @@
 static struct comedi_driver usbdux_driver = {
 	.driver_name	= "usbdux",
 	.module		= THIS_MODULE,
-	.attach		= usbdux_attach,
-	.detach		= usbdux_detach,
 	.attach_usb	= usbdux_attach_usb,
+	.detach		= usbdux_detach,
 };
 
 static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 8eb41257..1154a7e2 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -346,7 +346,7 @@
 		return;
 	}
 	/* subdevice which is the AD converter */
-	s = this_comedidev->subdevices + SUBDEV_AD;
+	s = &this_comedidev->subdevices[SUBDEV_AD];
 
 	/* first we test if something unusual has just happened */
 	switch (urb->status) {
@@ -549,10 +549,10 @@
 				 struct comedi_subdevice *s,
 				 struct comedi_cmd *cmd)
 {
-	int err = 0, stop_mask = 0;
+	struct usbduxfastsub_s *udfs = dev->private;
+	int err = 0;
 	long int steps, tmp;
 	int minSamplPer;
-	struct usbduxfastsub_s *udfs = dev->private;
 
 	if (!udfs->probed)
 		return -ENODEV;
@@ -563,57 +563,31 @@
 	       "scan_begin_arg=%u\n",
 	       dev->minor, cmd->convert_arg, cmd->scan_begin_arg);
 #endif
-	/* step 1: make sure trigger sources are trivially valid */
+	/* Step 1 : check if triggers are trivially valid */
 
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	stop_mask = TRIG_COUNT | TRIG_NONE;
-	cmd->stop_src &= stop_mask;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src,
+					TRIG_NOW | TRIG_EXT | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+					TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually compatible
-	 */
+	/* Step 2a : make sure trigger sources are unique */
 
-	if (cmd->start_src != TRIG_NOW &&
-	    cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT)
-		err++;
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT)
-		err++;
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT &&
-	    cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
-		err++;
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+	err |= cfc_check_trigger_is_unique(cmd->convert_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	/* can't have external stop and start triggers at once */
 	if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
-		err++;
+		err |= -EINVAL;
 
 	if (err)
 		return 2;
@@ -1430,10 +1404,8 @@
 	udfs->ai_cmd_running = 0;
 }
 
-/* common part of attach and attach_usb */
 static int usbduxfast_attach_common(struct comedi_device *dev,
-				    struct usbduxfastsub_s *udfs,
-				    void *aux_data, int aux_len)
+				    struct usbduxfastsub_s *udfs)
 {
 	int ret;
 	struct comedi_subdevice *s;
@@ -1441,9 +1413,6 @@
 	down(&udfs->sem);
 	/* pointer back to the corresponding comedi device */
 	udfs->comedidev = dev;
-	/* trying to upload the firmware into the chip */
-	if (aux_data)
-		firmwareUpload(udfs, aux_data, aux_len);
 	dev->board_name = "usbduxfast";
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret) {
@@ -1453,7 +1422,7 @@
 	/* private structure is also simply the usb-structure */
 	dev->private = udfs;
 	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
+	s = &dev->subdevices[SUBDEV_AD];
 	/*
 	 * the URBs get the comedi subdevice which is responsible for reading
 	 * this is the subdevice which reads data
@@ -1485,48 +1454,6 @@
 	return 0;
 }
 
-/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
-static int usbduxfast_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	void *aux_data;
-	int aux_len;
-
-	dev->private = NULL;
-
-	aux_data = comedi_aux_data(it->options, 0);
-	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-	if (aux_data == NULL)
-		aux_len = 0;
-	else if (aux_len == 0)
-		aux_data = NULL;
-	down(&start_stop_sem);
-	/*
-	 * find a valid device which has been detected by the
-	 * probe function of the usb
-	 */
-	index = -1;
-	for (i = 0; i < NUMUSBDUXFAST; i++) {
-		if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
-			index = i;
-			break;
-		}
-	}
-	if (index < 0) {
-		dev_err(dev->class_dev,
-			"usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n");
-		ret = -ENODEV;
-	} else
-		ret = usbduxfast_attach_common(dev, &usbduxfastsub[index],
-					       aux_data, aux_len);
-	up(&start_stop_sem);
-	return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
 static int usbduxfast_attach_usb(struct comedi_device *dev,
 				 struct usb_interface *uinterf)
 {
@@ -1545,7 +1472,7 @@
 		       "usbduxfast: error: attach_usb failed, already attached\n");
 		ret = -ENODEV;
 	} else
-		ret = usbduxfast_attach_common(dev, udfs, NULL, 0);
+		ret = usbduxfast_attach_common(dev, udfs);
 	up(&start_stop_sem);
 	return ret;
 }
@@ -1568,9 +1495,8 @@
 static struct comedi_driver usbduxfast_driver = {
 	.driver_name	= "usbduxfast",
 	.module		= THIS_MODULE,
-	.attach		= usbduxfast_attach,
-	.detach		= usbduxfast_detach,
 	.attach_usb	= usbduxfast_attach_usb,
+	.detach		= usbduxfast_detach,
 };
 
 static void usbduxfast_firmware_request_complete_handler(const struct firmware
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index f54ab8c..b169412 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -356,7 +356,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 	/* subdevice which is the AD converter */
-	s = this_comedidev->subdevices + SUBDEV_AD;
+	s = &this_comedidev->subdevices[SUBDEV_AD];
 
 	/* first we test if something unusual has just happened */
 	switch (urb->status) {
@@ -558,7 +558,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 
-	s = this_comedidev->subdevices + SUBDEV_DA;
+	s = &this_comedidev->subdevices[SUBDEV_DA];
 
 	switch (urb->status) {
 	case 0:
@@ -897,9 +897,9 @@
 			     struct comedi_subdevice *s,
 			     struct comedi_cmd *cmd)
 {
-	int err = 0, tmp, i;
-	unsigned int tmpTimer;
 	struct usbduxsub *this_usbduxsub = dev->private;
+	int err = 0, i;
+	unsigned int tmpTimer;
 
 	if (!(this_usbduxsub->probed))
 		return -ENODEV;
@@ -907,51 +907,23 @@
 	dev_dbg(&this_usbduxsub->interface->dev,
 		"comedi%d: usbdux_ai_cmdtest\n", dev->minor);
 
-	/* make sure triggers are valid */
-	/* Only immediate triggers are allowed */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* trigger should happen timed */
-	tmp = cmd->scan_begin_src;
-	/* start a new _scan_ with a timer */
-	cmd->scan_begin_src &= TRIG_TIMER;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	/* scanning is continuous */
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_NOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	/* issue a trigger when scan is finished and start a new scan */
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	/* trigger at the end of count events or not, stop condition or not */
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources are unique and mutually compatible
-	 * note that mutual compatibility is not an issue here
-	 */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1558,8 +1530,9 @@
 			     struct comedi_subdevice *s,
 			     struct comedi_cmd *cmd)
 {
-	int err = 0, tmp;
 	struct usbduxsub *this_usbduxsub = dev->private;
+	int err = 0;
+	unsigned int flags;
 
 	if (!this_usbduxsub)
 		return -EFAULT;
@@ -1570,63 +1543,35 @@
 	dev_dbg(&this_usbduxsub->interface->dev,
 		"comedi%d: usbdux_ao_cmdtest\n", dev->minor);
 
-	/* make sure triggers are valid */
-	/* Only immediate triggers are allowed */
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW | TRIG_INT;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
+	/* Step 1 : check if triggers are trivially valid */
 
-	/* trigger should happen timed */
-	tmp = cmd->scan_begin_src;
-	/* just now we scan also in the high speed mode every frame */
-	/* this is due to ehci driver limitations */
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+
 	if (0) {		/* (this_usbduxsub->high_speed) */
-		/* start immediately a new scan */
-		/* the sampling rate is set by the coversion rate */
-		cmd->scan_begin_src &= TRIG_FOLLOW;
+		/*
+		 * start immediately a new scan
+		 * the sampling rate is set by the coversion rate
+		 */
+		flags = TRIG_FOLLOW;
 	} else {
 		/* start a new scan (output at once) with a timer */
-		cmd->scan_begin_src &= TRIG_TIMER;
+		flags = TRIG_TIMER;
 	}
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
 
-	/* scanning is continuous */
-	tmp = cmd->convert_src;
-
-	/* all conversion events happen simultaneously */
-	cmd->convert_src &= TRIG_NOW;
-
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	/* issue a trigger when scan is finished and start a new scan */
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	/* trigger at the end of count events or not, stop condition or not */
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 
 	if (err)
 		return 1;
 
-	/*
-	 * step 2: make sure trigger sources
-	 * are unique and mutually compatible
-	 * note that mutual compatibility is not an issue here
-	 */
-	if (cmd->scan_begin_src != TRIG_FOLLOW &&
-	    cmd->scan_begin_src != TRIG_EXT &&
-	    cmd->scan_begin_src != TRIG_TIMER)
-		err++;
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+	/* Step 2a : make sure trigger sources are unique */
+
+	err |= cfc_check_trigger_is_unique(cmd->start_src);
+	err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+	/* Step 2b : and mutually compatible */
 
 	if (err)
 		return 2;
@@ -1950,7 +1895,7 @@
 	/* the private structure of the subdevice is struct usbduxsub */
 	this_usbduxsub = this_comedidev->private;
 
-	s = this_comedidev->subdevices + SUBDEV_DA;
+	s = &this_comedidev->subdevices[SUBDEV_DA];
 
 	switch (urb->status) {
 	case 0:
@@ -2301,10 +2246,8 @@
 	usbduxsub_tmp->pwm_cmd_running = 0;
 }
 
-/* common part of attach and attach_usb */
 static int usbduxsigma_attach_common(struct comedi_device *dev,
-				     struct usbduxsub *uds,
-				     void *aux_data, int aux_len)
+				     struct usbduxsub *uds)
 {
 	int ret;
 	struct comedi_subdevice *s;
@@ -2314,9 +2257,6 @@
 	down(&uds->sem);
 	/* pointer back to the corresponding comedi device */
 	uds->comedidev = dev;
-	/* trying to upload the firmware into the FX2 */
-	if (aux_data)
-		firmwareUpload(uds, aux_data, aux_len);
 	dev->board_name = "usbduxsigma";
 	/* set number of subdevices */
 	if (uds->high_speed)
@@ -2331,7 +2271,7 @@
 	/* private structure is also simply the usb-structure */
 	dev->private = uds;
 	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
+	s = &dev->subdevices[SUBDEV_AD];
 	/* the URBs get the comedi subdevice */
 	/* which is responsible for reading */
 	/* this is the subdevice which reads data */
@@ -2358,7 +2298,7 @@
 	/* range table to convert to physical units */
 	s->range_table = (&range_usbdux_ai_range);
 	/* analog output subdevice */
-	s = dev->subdevices + SUBDEV_DA;
+	s = &dev->subdevices[SUBDEV_DA];
 	/* analog out */
 	s->type = COMEDI_SUBD_AO;
 	/* backward pointer */
@@ -2383,7 +2323,7 @@
 	s->insn_read = usbdux_ao_insn_read;
 	s->insn_write = usbdux_ao_insn_write;
 	/* digital I/O subdevice */
-	s = dev->subdevices + SUBDEV_DIO;
+	s = &dev->subdevices[SUBDEV_DIO];
 	s->type = COMEDI_SUBD_DIO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	/* 8 external and 16 internal channels */
@@ -2396,7 +2336,7 @@
 	s->private = NULL;
 	if (uds->high_speed) {
 		/* timer / pwm subdevice */
-		s = dev->subdevices + SUBDEV_PWM;
+		s = &dev->subdevices[SUBDEV_PWM];
 		s->type = COMEDI_SUBD_PWM;
 		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
 		s->n_chan = 8;
@@ -2419,47 +2359,6 @@
 	return 0;
 }
 
-/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
-static int usbduxsigma_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	void *aux_data;
-	int aux_len;
-
-	dev->private = NULL;
-
-	aux_data = comedi_aux_data(it->options, 0);
-	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-	if (aux_data == NULL)
-		aux_len = 0;
-	else if (aux_len == 0)
-		aux_data = NULL;
-
-	down(&start_stop_sem);
-	/* find a valid device which has been detected by the probe function of
-	 * the usb */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
-			index = i;
-			break;
-		}
-	}
-	if (index < 0) {
-		dev_err(dev->class_dev,
-			"usbduxsigma: error: attach failed, dev not connected to the usb bus.\n");
-		ret = -ENODEV;
-	} else
-		ret = usbduxsigma_attach_common(dev, &usbduxsub[index],
-						aux_data, aux_len);
-	up(&start_stop_sem);
-	return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
 static int usbduxsigma_attach_usb(struct comedi_device *dev,
 				  struct usb_interface *uinterf)
 {
@@ -2478,7 +2377,7 @@
 		       "usbduxsigma: error: attach_usb failed, already attached\n");
 		ret = -ENODEV;
 	} else
-		ret = usbduxsigma_attach_common(dev, uds, NULL, 0);
+		ret = usbduxsigma_attach_common(dev, uds);
 	up(&start_stop_sem);
 	return ret;
 }
@@ -2499,9 +2398,8 @@
 static struct comedi_driver usbduxsigma_driver = {
 	.driver_name	= "usbduxsigma",
 	.module		= THIS_MODULE,
-	.attach		= usbduxsigma_attach,
-	.detach		= usbduxsigma_detach,
 	.attach_usb	= usbduxsigma_attach_usb,
+	.detach		= usbduxsigma_detach,
 };
 
 static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 94010fc..df277aa 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -546,6 +546,7 @@
 			reg[0] = VMK8055_AI2_REG;
 		break;
 	case VMK8061_MODEL:
+	default:
 		reg[0] = VMK8061_AI_REG1;
 		reg[1] = VMK8061_AI_REG2;
 		dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
@@ -904,6 +905,7 @@
 			reg[0] = VMK8055_CNT2_REG;
 		break;
 	case VMK8061_MODEL:
+	default:
 		reg[0] = VMK8061_CNT_REG;
 		reg[1] = VMK8061_CNT_REG;
 		dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
@@ -1119,7 +1121,7 @@
 		return ret;
 	}
 	/* Analog input subdevice */
-	s = cdev->subdevices + VMK80XX_SUBD_AI;
+	s = &cdev->subdevices[VMK80XX_SUBD_AI];
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = dev->board.ai_chans;
@@ -1127,7 +1129,7 @@
 	s->range_table = dev->board.range;
 	s->insn_read = vmk80xx_ai_rinsn;
 	/* Analog output subdevice */
-	s = cdev->subdevices + VMK80XX_SUBD_AO;
+	s = &cdev->subdevices[VMK80XX_SUBD_AO];
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
 	s->n_chan = dev->board.ao_chans;
@@ -1139,7 +1141,7 @@
 		s->insn_read = vmk80xx_ao_rinsn;
 	}
 	/* Digital input subdevice */
-	s = cdev->subdevices + VMK80XX_SUBD_DI;
+	s = &cdev->subdevices[VMK80XX_SUBD_DI];
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = dev->board.di_chans;
@@ -1147,7 +1149,7 @@
 	s->insn_read = vmk80xx_di_rinsn;
 	s->insn_bits = vmk80xx_di_bits;
 	/* Digital output subdevice */
-	s = cdev->subdevices + VMK80XX_SUBD_DO;
+	s = &cdev->subdevices[VMK80XX_SUBD_DO];
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
 	s->n_chan = dev->board.do_chans;
@@ -1159,7 +1161,7 @@
 		s->insn_read = vmk80xx_do_rinsn;
 	}
 	/* Counter subdevice */
-	s = cdev->subdevices + VMK80XX_SUBD_CNT;
+	s = &cdev->subdevices[VMK80XX_SUBD_CNT];
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE;
 	s->n_chan = dev->board.cnt_chans;
@@ -1172,7 +1174,7 @@
 	}
 	/* PWM subdevice */
 	if (dev->board.model == VMK8061_MODEL) {
-		s = cdev->subdevices + VMK80XX_SUBD_PWM;
+		s = &cdev->subdevices[VMK80XX_SUBD_PWM];
 		s->type = COMEDI_SUBD_PWM;
 		s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
 		s->n_chan = dev->board.pwm_chans;
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 0252b44..3f20ea5 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -80,7 +80,9 @@
 }
 EXPORT_SYMBOL(comedi_close);
 
-static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
+static int comedi_do_insn(struct comedi_device *dev,
+			  struct comedi_insn *insn,
+			  unsigned int *data)
 {
 	struct comedi_subdevice *s;
 	int ret = 0;
@@ -90,7 +92,7 @@
 		ret = -EINVAL;
 		goto error;
 	}
-	s = dev->subdevices + insn->subdev;
+	s = &dev->subdevices[insn->subdev];
 
 	if (s->type == COMEDI_SUBD_UNUSED) {
 		printk(KERN_ERR "%d not useable subdevice\n", insn->subdev);
@@ -115,11 +117,11 @@
 
 	switch (insn->insn) {
 	case INSN_BITS:
-		ret = s->insn_bits(dev, s, insn, insn->data);
+		ret = s->insn_bits(dev, s, insn, data);
 		break;
 	case INSN_CONFIG:
 		/* XXX should check instruction length */
-		ret = s->insn_config(dev, s, insn, insn->data);
+		ret = s->insn_config(dev, s, insn, data);
 		break;
 	default:
 		ret = -EINVAL;
@@ -140,11 +142,10 @@
 	memset(&insn, 0, sizeof(insn));
 	insn.insn = INSN_CONFIG;
 	insn.n = 1;
-	insn.data = &io;
 	insn.subdev = subdev;
 	insn.chanspec = CR_PACK(chan, 0, 0);
 
-	return comedi_do_insn(dev, &insn);
+	return comedi_do_insn(dev, &insn, &io);
 }
 EXPORT_SYMBOL(comedi_dio_config);
 
@@ -158,13 +159,12 @@
 	memset(&insn, 0, sizeof(insn));
 	insn.insn = INSN_BITS;
 	insn.n = 2;
-	insn.data = data;
 	insn.subdev = subdev;
 
 	data[0] = mask;
 	data[1] = *bits;
 
-	ret = comedi_do_insn(dev, &insn);
+	ret = comedi_do_insn(dev, &insn, data);
 
 	*bits = data[1];
 
@@ -175,11 +175,14 @@
 int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
 				  unsigned int subd)
 {
+	struct comedi_subdevice *s;
+
 	if (subd > dev->n_subdevices)
 		return -ENODEV;
 
 	for (; subd < dev->n_subdevices; subd++) {
-		if (dev->subdevices[subd].type == type)
+		s = &dev->subdevices[subd];
+		if (s->type == type)
 			return subd;
 	}
 	return -1;
@@ -188,7 +191,7 @@
 
 int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
 {
-	struct comedi_subdevice *s = dev->subdevices + subdevice;
+	struct comedi_subdevice *s = &dev->subdevices[subdevice];
 
 	return s->n_chan;
 }
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 41f9523..59ff0cf 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -68,7 +68,7 @@
 		return -EINVAL;
 	if (subd >= dev->n_subdevices)
 		return -EINVAL;
-	s = dev->subdevices + subd;
+	s = &dev->subdevices[subd];
 	if (s->range_table) {
 		lr = s->range_table;
 	} else if (s->range_table_list) {
@@ -131,6 +131,7 @@
 int comedi_check_chanlist(struct comedi_subdevice *s, int n,
 			  unsigned int *chanlist)
 {
+	struct comedi_device *dev = s->device;
 	int i;
 	int chan;
 
@@ -139,10 +140,10 @@
 			if (CR_CHAN(chanlist[i]) >= s->n_chan ||
 			    CR_RANGE(chanlist[i]) >= s->range_table->length
 			    || aref_invalid(s, chanlist[i])) {
-				printk(KERN_ERR "bad chanlist[%d]=0x%08x "
-				       "in_chan=%d range length=%d\n", i,
-				       chanlist[i], s->n_chan,
-				       s->range_table->length);
+				dev_warn(dev->class_dev,
+					 "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n",
+					 i, chanlist[i], s->n_chan,
+					 s->range_table->length);
 				return -EINVAL;
 			}
 	} else if (s->range_table_list) {
@@ -152,13 +153,14 @@
 			    CR_RANGE(chanlist[i]) >=
 			    s->range_table_list[chan]->length
 			    || aref_invalid(s, chanlist[i])) {
-				printk(KERN_ERR "bad chanlist[%d]=0x%08x\n",
-				       i, chanlist[i]);
+				dev_warn(dev->class_dev,
+					 "bad chanlist[%d]=0x%08x\n",
+					 i, chanlist[i]);
 				return -EINVAL;
 			}
 		}
 	} else {
-		printk(KERN_ERR "comedi: (bug) no range type list!\n");
+		dev_err(dev->class_dev, "(bug) no range type list!\n");
 		return -EINVAL;
 	}
 	return 0;
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
index 0d924d3..a49b0da 100644
--- a/drivers/staging/cptm1217/clearpad_tm1217.c
+++ b/drivers/staging/cptm1217/clearpad_tm1217.c
@@ -658,18 +658,7 @@
 	.resume     = cp_tm1217_resume,
 };
 
-static int __init clearpad_tm1217_init(void)
-{
-	return i2c_add_driver(&cp_tm1217_driver);
-}
-
-static void __exit clearpad_tm1217_exit(void)
-{
-	i2c_del_driver(&cp_tm1217_driver);
-}
-
-module_init(clearpad_tm1217_init);
-module_exit(clearpad_tm1217_exit);
+module_i2c_driver(cp_tm1217_driver);
 
 MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
 MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index d9e3d61..166203a 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -373,13 +373,15 @@
 	/* register crystalhd class */
 	crystalhd_class = class_create(THIS_MODULE, "crystalhd");
 	if (IS_ERR(crystalhd_class)) {
+		rc = PTR_ERR(crystalhd_class);
 		BCMLOG_ERR("failed to create class\n");
-		goto fail;
+		goto class_create_fail;
 	}
 
 	dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0),
 			    NULL, "crystalhd");
 	if (IS_ERR(dev)) {
+		rc = PTR_ERR(dev);
 		BCMLOG_ERR("failed to create device\n");
 		goto device_create_fail;
 	}
@@ -410,6 +412,8 @@
 	device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 device_create_fail:
 	class_destroy(crystalhd_class);
+class_create_fail:
+	unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
 fail:
 	return rc;
 }
diff --git a/drivers/staging/csr/Makefile b/drivers/staging/csr/Makefile
index afda44b..ab626ed 100644
--- a/drivers/staging/csr/Makefile
+++ b/drivers/staging/csr/Makefile
@@ -25,7 +25,6 @@
 		unifi_event.o			\
 		unifi_pdu_processing.o		\
 		unifi_sme.o			\
-		csr_formatted_io.o		\
 		csr_wifi_hip_card_sdio.o	\
 		csr_wifi_hip_card_sdio_intr.o	\
 		csr_wifi_hip_card_sdio_mem.o	\
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c
index b089c28..addee05 100644
--- a/drivers/staging/csr/bh.c
+++ b/drivers/staging/csr/bh.c
@@ -32,45 +32,49 @@
  *      0 on success or else a Linux error code.
  * ---------------------------------------------------------------------------
  */
-int
-uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *))
+int uf_start_thread(unifi_priv_t *priv,
+		    struct uf_thread *thread, int (*func)(void *))
 {
-    if (thread->thread_task != NULL) {
-        unifi_error(priv, "%s thread already started\n", thread->name);
-        return 0;
-    }
+	if (thread->thread_task != NULL) {
+		unifi_error(priv, "%s thread already started\n", thread->name);
+		return 0;
+	}
 
-    /* Start the kernel thread that handles all h/w accesses. */
-    thread->thread_task = kthread_run(func, priv, "%s", thread->name);
-    if (IS_ERR(thread->thread_task)) {
-        return PTR_ERR(thread->thread_task);
-    }
+	/* Start the kernel thread that handles all h/w accesses. */
+	thread->thread_task = kthread_run(func, priv, "%s", thread->name);
+	if (IS_ERR(thread->thread_task))
+		return PTR_ERR(thread->thread_task);
 
-    /* Module parameter overides the thread priority */
-    if (bh_priority != -1) {
-        if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
-            struct sched_param param;
-            priv->bh_thread.prio = bh_priority;
-            unifi_trace(priv, UDBG1, "%s thread (RT) priority = %d\n",
-                        thread->name, bh_priority);
-            param.sched_priority = bh_priority;
-            sched_setscheduler(thread->thread_task, SCHED_FIFO, &param);
-        } else if (bh_priority > MAX_RT_PRIO && bh_priority <= MAX_PRIO) {
-            priv->bh_thread.prio = bh_priority;
-            unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
-                        thread->name, PRIO_TO_NICE(bh_priority));
-            set_user_nice(thread->thread_task, PRIO_TO_NICE(bh_priority));
-        } else {
-            priv->bh_thread.prio = DEFAULT_PRIO;
-            unifi_warning(priv, "%s thread unsupported (%d) priority\n",
-                          thread->name, bh_priority);
-        }
-    } else {
-        priv->bh_thread.prio = DEFAULT_PRIO;
-    }
-    unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
+	/* Module parameter overides the thread priority */
+	if (bh_priority != -1) {
+		if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
+			struct sched_param param;
+			priv->bh_thread.prio = bh_priority;
+			unifi_trace(priv, UDBG1,
+				"%s thread (RT) priority = %d\n",
+				thread->name, bh_priority);
+			param.sched_priority = bh_priority;
+			sched_setscheduler(thread->thread_task,
+					   SCHED_FIFO, &param);
+		} else if (bh_priority > MAX_RT_PRIO &&
+			   bh_priority <= MAX_PRIO) {
+			priv->bh_thread.prio = bh_priority;
+			unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
+					thread->name,
+					PRIO_TO_NICE(bh_priority));
+			set_user_nice(thread->thread_task,
+				      PRIO_TO_NICE(bh_priority));
+		} else {
+			priv->bh_thread.prio = DEFAULT_PRIO;
+			unifi_warning(priv,
+				      "%s thread unsupported (%d) priority\n",
+				      thread->name, bh_priority);
+		}
+	} else
+		priv->bh_thread.prio = DEFAULT_PRIO;
+	unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
 
-    return 0;
+	return 0;
 } /* uf_start_thread() */
 
 
@@ -88,18 +92,18 @@
  *
  * ---------------------------------------------------------------------------
  */
-    void
-uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
+void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
 {
-    if (!thread->thread_task) {
-        unifi_notice(priv, "%s thread is already stopped\n", thread->name);
-        return;
-    }
+	if (!thread->thread_task) {
+		unifi_notice(priv, "%s thread is already stopped\n",
+							thread->name);
+		return;
+	}
 
-    unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
+	unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
 
-    kthread_stop(thread->thread_task);
-    thread->thread_task = NULL;
+	kthread_stop(thread->thread_task);
+	thread->thread_task = NULL;
 
 } /* uf_stop_thread() */
 
@@ -118,23 +122,24 @@
  *
  * ---------------------------------------------------------------------------
  */
-    void
+void
 uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
 {
-    /*
-     * kthread_stop() cannot handle the thread exiting while
-     * kthread_should_stop() is false, so sleep until kthread_stop()
-     * wakes us up.
-     */
-    unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n", thread->name);
-    set_current_state(TASK_INTERRUPTIBLE);
-    if (!kthread_should_stop()) {
-        unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
-        schedule();
-    }
+	/*
+	 * kthread_stop() cannot handle the thread exiting while
+	 * kthread_should_stop() is false, so sleep until kthread_stop()
+	 * wakes us up
+	 */
+	unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n",
+							thread->name);
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (!kthread_should_stop()) {
+		unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
+		schedule();
+	}
 
-    thread->thread_task = NULL;
-    unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
+	thread->thread_task = NULL;
+	unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
 } /* uf_wait_for_thread_to_stop() */
 
 
@@ -155,39 +160,41 @@
  *      None.
  * ---------------------------------------------------------------------------
  */
-    static void
+static void
 handle_bh_error(unifi_priv_t *priv)
 {
-    u8 conf_param = CONFIG_IND_ERROR;
-    u8 interfaceTag = 0; /* used as a loop counter */
+	netInterface_priv_t *interfacePriv;
+	u8 conf_param = CONFIG_IND_ERROR;
+	u8 interfaceTag;
 
 
-    /* Block unifi_run_bh() until the error has been handled. */
-    priv->bh_thread.block_thread = 1;
+	/* Block unifi_run_bh() until the error has been handled. */
+	priv->bh_thread.block_thread = 1;
 
-    /* Consider UniFi to be uninitialised */
-    priv->init_progress = UNIFI_INIT_NONE;
+	/* Consider UniFi to be uninitialised */
+	priv->init_progress = UNIFI_INIT_NONE;
 
-    /* Stop the network traffic */
-    for( interfaceTag =0; interfaceTag <CSR_WIFI_NUM_INTERFACES;interfaceTag ++) {
-        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
-        if (interfacePriv->netdev_registered == 1) {
-            netif_carrier_off(priv->netdev[interfaceTag]);
-        }
-    }
+	/* Stop the network traffic */
+	for (interfaceTag = 0;
+	     interfaceTag < CSR_WIFI_NUM_INTERFACES; interfaceTag++) {
+		interfacePriv = priv->interfacePriv[interfaceTag];
+		if (interfacePriv->netdev_registered)
+			netif_carrier_off(priv->netdev[interfaceTag]);
+	}
 
 #ifdef CSR_NATIVE_LINUX
-    /* Force any client waiting on an mlme_wait_for_reply() to abort. */
-    uf_abort_mlme(priv);
+	/* Force any client waiting on an mlme_wait_for_reply() to abort. */
+	uf_abort_mlme(priv);
 
-    /* Cancel any pending workqueue tasks */
-    flush_workqueue(priv->unifi_workqueue);
+	/* Cancel any pending workqueue tasks */
+	flush_workqueue(priv->unifi_workqueue);
 
 #endif /* CSR_NATIVE_LINUX */
 
-    unifi_error(priv, "handle_bh_error: fatal error is reported to the SME.\n");
-    /* Notify the clients (SME or unifi_manager) for the error. */
-    ul_log_config_ind(priv, &conf_param, sizeof(u8));
+	unifi_error(priv,
+		"handle_bh_error: fatal error is reported to the SME.\n");
+	/* Notify the clients (SME or unifi_manager) for the error. */
+	ul_log_config_ind(priv, &conf_param, sizeof(u8));
 
 } /* handle_bh_error() */
 
diff --git a/drivers/staging/csr/csr_formatted_io.c b/drivers/staging/csr/csr_formatted_io.c
deleted file mode 100644
index 7213cc8..0000000
--- a/drivers/staging/csr/csr_formatted_io.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*****************************************************************************
-
-            (c) Cambridge Silicon Radio Limited 2010
-            All rights reserved and confidential information of CSR
-
-            Refer to LICENSE.txt included with this source for details
-            on the license terms.
-
-*****************************************************************************/
-#include <linux/kernel.h>
-#include "csr_formatted_io.h"
-
-s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...)
-{
-    s32 r;
-    va_list args;
-    va_start(args, fmt);
-    r = vsnprintf(dest, n, fmt, args);
-    va_end(args);
-
-    if (dest && (n > 0))
-    {
-        dest[n - 1] = '\0';
-    }
-
-    return r;
-}
diff --git a/drivers/staging/csr/csr_formatted_io.h b/drivers/staging/csr/csr_formatted_io.h
deleted file mode 100644
index 2e238cb..0000000
--- a/drivers/staging/csr/csr_formatted_io.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef CSR_FORMATTED_IO_H__
-#define CSR_FORMATTED_IO_H__
-/*****************************************************************************
-
-            (c) Cambridge Silicon Radio Limited 2010
-            All rights reserved and confidential information of CSR
-
-            Refer to LICENSE.txt included with this source for details
-            on the license terms.
-
-*****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <linux/types.h>
-
-s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/staging/csr/csr_framework_ext.c b/drivers/staging/csr/csr_framework_ext.c
index 12e7ddf..f91a4bf 100644
--- a/drivers/staging/csr/csr_framework_ext.c
+++ b/drivers/staging/csr/csr_framework_ext.c
@@ -12,20 +12,9 @@
 #include <linux/version.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
-#include <linux/slab.h>
-#endif
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
 #include <linux/freezer.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
-#include <asm/semaphore.h>
-#else
 #include <linux/semaphore.h>
-#endif
-
+#include <linux/slab.h>
 #include <linux/bitops.h>
 
 #include "csr_framework_ext.h"
diff --git a/drivers/staging/csr/csr_panic.c b/drivers/staging/csr/csr_panic.c
index 353a829..095f7fa 100644
--- a/drivers/staging/csr/csr_panic.c
+++ b/drivers/staging/csr/csr_panic.c
@@ -9,7 +9,6 @@
 *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include "csr_panic.h"
diff --git a/drivers/staging/csr/csr_time.c b/drivers/staging/csr/csr_time.c
index 83586ca..7b597f7 100644
--- a/drivers/staging/csr/csr_time.c
+++ b/drivers/staging/csr/csr_time.c
@@ -10,13 +10,6 @@
 
 #include <linux/kernel.h>
 #include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
-#include <linux/autoconf.h>
-#include <linux/config.h>
-#endif
-
 #include <linux/time.h>
 #include <linux/module.h>
 
@@ -24,20 +17,18 @@
 
 CsrTime CsrTimeGet(CsrTime *high)
 {
-    struct timespec ts;
-    u64 time;
-    CsrTime low;
+	struct timespec ts;
+	u64 time;
+	CsrTime low;
 
-    ts = current_kernel_time();
-    time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+	ts = current_kernel_time();
+	time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
 
-    if (high != NULL)
-    {
-        *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
-    }
+	if (high != NULL)
+		*high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
 
-    low = (CsrTime) (time & 0xFFFFFFFF);
+	low = (CsrTime) (time & 0xFFFFFFFF);
 
-    return low;
+	return low;
 }
 EXPORT_SYMBOL_GPL(CsrTimeGet);
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio.c b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
index 44ab00c..cf148a0 100644
--- a/drivers/staging/csr/csr_wifi_hip_card_sdio.c
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
@@ -1612,13 +1612,13 @@
     /* Reset any state carried forward from a previous life */
     card->fh_command_queue.q_rd_ptr = 0;
     card->fh_command_queue.q_wr_ptr = 0;
-    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+    (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
                       "fh_cmd_q");
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
         card->fh_traffic_queue[i].q_rd_ptr = 0;
         card->fh_traffic_queue[i].q_wr_ptr = 0;
-        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+        (void)scnprintf(card->fh_traffic_queue[i].name,
                           UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
     }
 #ifndef CSR_WIFI_HIP_TA_DISABLE
@@ -1826,13 +1826,13 @@
     /* Reset any state carried forward from a previous life */
     card->fh_command_queue.q_rd_ptr = 0;
     card->fh_command_queue.q_wr_ptr = 0;
-    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+    (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
                       "fh_cmd_q");
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
         card->fh_traffic_queue[i].q_rd_ptr = 0;
         card->fh_traffic_queue[i].q_wr_ptr = 0;
-        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+        (void)scnprintf(card->fh_traffic_queue[i].name,
                           UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
     }
 #ifndef CSR_WIFI_HIP_TA_DISABLE
diff --git a/drivers/staging/csr/csr_wifi_hip_download.c b/drivers/staging/csr/csr_wifi_hip_download.c
index 8e4a460..6db672c 100644
--- a/drivers/staging/csr/csr_wifi_hip_download.c
+++ b/drivers/staging/csr/csr_wifi_hip_download.c
@@ -250,6 +250,7 @@
         if (r != CSR_RESULT_SUCCESS)
         {
             unifi_error(card->ospriv, "Failed to find BOOT_LOADER_CONTROL\n");
+            kfree(pfw);
             return CSR_RESULT_FAILURE;
         }
 
@@ -265,6 +266,7 @@
         desc = unifi_fw_open_buffer(card->ospriv, pfw, psize);
         if (!desc)
         {
+            kfree(pfw);
             return CSR_WIFI_HIP_RESULT_NO_MEMORY;
         }
 
diff --git a/drivers/staging/csr/csr_wifi_hip_send.c b/drivers/staging/csr/csr_wifi_hip_send.c
index 684d304..86aa23c 100644
--- a/drivers/staging/csr/csr_wifi_hip_send.c
+++ b/drivers/staging/csr/csr_wifi_hip_send.c
@@ -172,13 +172,8 @@
     {
         const u8 *sig = sigptr;
 
-        unifi_error(card->ospriv, "Signal(%d): %02x %02x %02x %02x %02x %02x %02x %02x"
-                    " %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                    siglen,
-                    sig[0], sig[1], sig[2], sig[3],
-                    sig[4], sig[5], sig[6], sig[7],
-                    sig[8], sig[9], sig[10], sig[11],
-                    sig[12], sig[13], sig[14], sig[15]);
+		unifi_error(card->ospriv, "Signal(%d): %*ph\n", siglen,
+					  16, sig);
         unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n",
                     bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL,
                     bulkdata != NULL?bulkdata->d[0].data_length : 0,
diff --git a/drivers/staging/csr/csr_wifi_hip_udi.c b/drivers/staging/csr/csr_wifi_hip_udi.c
index 07cfd36..a65b822 100644
--- a/drivers/staging/csr/csr_wifi_hip_udi.c
+++ b/drivers/staging/csr/csr_wifi_hip_udi.c
@@ -64,104 +64,104 @@
     }
 
     i = n = 0;
-    written = CsrSnprintf(p, remaining, "Chip ID %u\n",
+    written = scnprintf(p, remaining, "Chip ID %u\n",
                           (u16)card->chip_id);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Chip Version %04X\n",
+    written = scnprintf(p, remaining, "Chip Version %04X\n",
                           card->chip_version);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "HIP v%u.%u\n",
+    written = scnprintf(p, remaining, "HIP v%u.%u\n",
                           (card->config_data.version >> 8) & 0xFF,
                           card->config_data.version & 0xFF);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Build %lu: %s\n",
+    written = scnprintf(p, remaining, "Build %u: %s\n",
                           card->build_id, card->build_id_string);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     cfg = &card->config_data;
 
-    written = CsrSnprintf(p, remaining, "sdio ctrl offset          %u\n",
+    written = scnprintf(p, remaining, "sdio ctrl offset          %u\n",
                           cfg->sdio_ctrl_offset);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "fromhost sigbuf handle    %u\n",
+    written = scnprintf(p, remaining, "fromhost sigbuf handle    %u\n",
                           cfg->fromhost_sigbuf_handle);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "tohost_sigbuf_handle      %u\n",
+    written = scnprintf(p, remaining, "tohost_sigbuf_handle      %u\n",
                           cfg->tohost_sigbuf_handle);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_fromhost_sig_frags    %u\n",
+    written = scnprintf(p, remaining, "num_fromhost_sig_frags    %u\n",
                           cfg->num_fromhost_sig_frags);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_tohost_sig_frags      %u\n",
+    written = scnprintf(p, remaining, "num_tohost_sig_frags      %u\n",
                           cfg->num_tohost_sig_frags);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_fromhost_data_slots   %u\n",
+    written = scnprintf(p, remaining, "num_fromhost_data_slots   %u\n",
                           cfg->num_fromhost_data_slots);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_tohost_data_slots     %u\n",
+    written = scnprintf(p, remaining, "num_tohost_data_slots     %u\n",
                           cfg->num_tohost_data_slots);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "data_slot_size            %u\n",
+    written = scnprintf(p, remaining, "data_slot_size            %u\n",
                           cfg->data_slot_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0001 */
-    written = CsrSnprintf(p, remaining, "overlay_size              %u\n",
+    written = scnprintf(p, remaining, "overlay_size              %u\n",
                           (u16)cfg->overlay_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0300 */
-    written = CsrSnprintf(p, remaining, "data_slot_round           %u\n",
+    written = scnprintf(p, remaining, "data_slot_round           %u\n",
                           cfg->data_slot_round);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "sig_frag_size             %u\n",
+    written = scnprintf(p, remaining, "sig_frag_size             %u\n",
                           cfg->sig_frag_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0300 */
-    written = CsrSnprintf(p, remaining, "tohost_sig_pad            %u\n",
+    written = scnprintf(p, remaining, "tohost_sig_pad            %u\n",
                           cfg->tohost_signal_padding);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "\nInternal state:\n");
+    written = scnprintf(p, remaining, "\nInternal state:\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n",
+    written = scnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n",
                           card->last_phy_panic_code, card->last_phy_panic_arg);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n",
+    written = scnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n",
                           card->last_mac_panic_code, card->last_mac_panic_arg);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "fhsr: %u\n",
+    written = scnprintf(p, remaining, "fhsr: %u\n",
                           (u16)card->from_host_signals_r);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "fhsw: %u\n",
+    written = scnprintf(p, remaining, "fhsw: %u\n",
                           (u16)card->from_host_signals_w);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "thsr: %u\n",
+    written = scnprintf(p, remaining, "thsr: %u\n",
                           (u16)card->to_host_signals_r);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "thsw: %u\n",
+    written = scnprintf(p, remaining, "thsw: %u\n",
                           (u16)card->to_host_signals_w);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining,
-                          "fh buffer contains: %u signals, %u bytes\n",
+    written = scnprintf(p, remaining,
+                          "fh buffer contains: %d signals, %td bytes\n",
                           card->fh_buffer.count,
                           card->fh_buffer.ptr - card->fh_buffer.buf);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "paused: ");
+    written = scnprintf(p, remaining, "paused: ");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++)
     {
-        written = CsrSnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0");
+        written = scnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0");
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining,
+    written = scnprintf(p, remaining,
                           "fh command q: %u waiting, %u free of %u:\n",
                           CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_command_queue),
                           CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_command_queue),
@@ -169,7 +169,7 @@
     UNIFI_SNPRINTF_RET(p, remaining, written);
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
-        written = CsrSnprintf(p, remaining,
+        written = scnprintf(p, remaining,
                               "fh traffic q[%u]: %u waiting, %u free of %u:\n",
                               i,
                               CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_traffic_queue[i]),
@@ -178,58 +178,58 @@
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 
-    written = CsrSnprintf(p, remaining, "fh data slots free: %u\n",
+    written = scnprintf(p, remaining, "fh data slots free: %u\n",
                           card->from_host_data?CardGetFreeFromHostDataSlots(card) : 0);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
 
-    written = CsrSnprintf(p, remaining, "From host data slots:");
+    written = scnprintf(p, remaining, "From host data slots:");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     n = card->config_data.num_fromhost_data_slots;
     for (i = 0; i < n && card->from_host_data; i++)
     {
-        written = CsrSnprintf(p, remaining, " %u",
+        written = scnprintf(p, remaining, " %u",
                               (u16)card->from_host_data[i].bd.data_length);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "To host data slots:");
+    written = scnprintf(p, remaining, "To host data slots:");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     n = card->config_data.num_tohost_data_slots;
     for (i = 0; i < n && card->to_host_data; i++)
     {
-        written = CsrSnprintf(p, remaining, " %u",
+        written = scnprintf(p, remaining, " %u",
                               (u16)card->to_host_data[i].data_length);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
 #ifdef CSR_UNSAFE_SDIO_ACCESS
-    written = CsrSnprintf(p, remaining, "Host State: %s\n", states[card->host_state]);
+    written = scnprintf(p, remaining, "Host State: %s\n", states[card->host_state]);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     r = unifi_check_io_status(card, &iostate);
     if (iostate == 1)
     {
-        written = CsrSnprintf(p, remaining, "I/O Check: F1 disabled\n");
+        written = scnprintf(p, remaining, "I/O Check: F1 disabled\n");
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
     else
     {
         if (iostate == 1)
         {
-            written = CsrSnprintf(p, remaining, "I/O Check: pending interrupt\n");
+            written = scnprintf(p, remaining, "I/O Check: pending interrupt\n");
             UNIFI_SNPRINTF_RET(p, remaining, written);
         }
 
-        written = CsrSnprintf(p, remaining, "BH reason interrupt = %d\n",
+        written = scnprintf(p, remaining, "BH reason interrupt = %d\n",
                               card->bh_reason_unifi);
         UNIFI_SNPRINTF_RET(p, remaining, written);
-        written = CsrSnprintf(p, remaining, "BH reason host      = %d\n",
+        written = scnprintf(p, remaining, "BH reason host      = %d\n",
                               card->bh_reason_host);
         UNIFI_SNPRINTF_RET(p, remaining, written);
 
@@ -238,26 +238,26 @@
             r = unifi_read_8_or_16(card, card->sdio_ctrl_addr + 2, &b);
             if ((r == CSR_RESULT_SUCCESS) && (!(b & 0x80)))
             {
-                written = CsrSnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n",
+                written = scnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n",
                                       b, card->from_host_signals_r);
                 UNIFI_SNPRINTF_RET(p, remaining, written);
                 break;
             }
         }
         iostate = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4);
-        written = CsrSnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n",
+        written = scnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n",
                               iostate, card->to_host_signals_w);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 #endif
 
-    written = CsrSnprintf(p, remaining, "\nStats:\n");
+    written = scnprintf(p, remaining, "\nStats:\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Total SDIO bytes: R=%lu W=%lu\n",
+    written = scnprintf(p, remaining, "Total SDIO bytes: R=%u W=%u\n",
                           card->sdio_bytes_read, card->sdio_bytes_written);
 
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Interrupts generated on card: %lu\n",
+    written = scnprintf(p, remaining, "Interrupts generated on card: %u\n",
                           card->unifi_interrupt_seq);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
diff --git a/drivers/staging/csr/csr_wifi_hip_unifi.h b/drivers/staging/csr/csr_wifi_hip_unifi.h
index dc3c60b..2923e2ef 100644
--- a/drivers/staging/csr/csr_wifi_hip_unifi.h
+++ b/drivers/staging/csr/csr_wifi_hip_unifi.h
@@ -98,7 +98,6 @@
 #include "csr_framework_ext.h"  /* from the synergy porting folder */
 #include "csr_sdio.h"           /* from the synergy porting folder */
 #include "csr_macro.h"          /* from the synergy porting folder */
-#include "csr_formatted_io.h"   /* from the synergy gsp folder */
 #include "csr_wifi_result.h"
 
 /* Utility MACROS. Note that UNIFI_MAC_ADDRESS_CMP returns TRUE on success */
diff --git a/drivers/staging/csr/drv.c b/drivers/staging/csr/drv.c
index b2c27f4..2497580 100644
--- a/drivers/staging/csr/drv.c
+++ b/drivers/staging/csr/drv.c
@@ -15,8 +15,6 @@
  * ---------------------------------------------------------------------------
  */
 
-
-
 /*
  * Porting Notes:
  * Part of this file contains an example for how to glue the OS layer
@@ -37,6 +35,7 @@
 #include <linux/poll.h>
 #include <asm/uaccess.h>
 #include <linux/jiffies.h>
+#include <linux/version.h>
 
 #include "csr_wifi_hip_unifiversion.h"
 #include "unifi_priv.h"
@@ -124,11 +123,7 @@
 
 
 /* Mutex to protect access to  priv->sme_cli */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
 DEFINE_SEMAPHORE(udi_mutex);
-#else
-DECLARE_MUTEX(udi_mutex);
-#endif
 
 s32 CsrHipResultToStatus(CsrResult csrResult)
 {
@@ -1980,18 +1975,6 @@
 } /* uf_sme_queue_message() */
 #endif
 
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create(_class, _parent, _devno, _priv, _fmt, _args)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args)
-#else
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create(_class, _parent, _devno, _fmt, _args)
-#endif
-
 /*
  ****************************************************************************
  *
@@ -2009,17 +1992,6 @@
     .poll       = unifi_poll,
 };
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create(_class, _parent, _devno, _priv, _fmt, _args)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args)
-#else
-#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
-    device_create(_class, _parent, _devno, _fmt, _args)
-#endif
-
 static dev_t unifi_first_devno;
 static struct class *unifi_class;
 
@@ -2042,11 +2014,11 @@
     }
 
 #ifdef SDIO_EXPORTS_STRUCT_DEVICE
-    if (!UF_DEVICE_CREATE(unifi_class, priv->unifi_device,
-                          devno, priv, "unifi%d", bus_id)) {
+    if (!device_create(unifi_class, priv->unifi_device,
+                       devno, priv, "unifi%d", bus_id)) {
 #else
-    priv->unifi_device = UF_DEVICE_CREATE(unifi_class, NULL,
-                                          devno, priv, "unifi%d", bus_id);
+    priv->unifi_device = device_create(unifi_class, NULL,
+                                       devno, priv, "unifi%d", bus_id);
     if (priv->unifi_device == NULL) {
 #endif /* SDIO_EXPORTS_STRUCT_DEVICE */
 
@@ -2068,13 +2040,13 @@
         return r;
     }
 
-    if (!UF_DEVICE_CREATE(unifi_class,
+    if (!device_create(unifi_class,
 #ifdef SDIO_EXPORTS_STRUCT_DEVICE
-                          priv->unifi_device,
+                       priv->unifi_device,
 #else
-                          NULL,
+                       NULL,
 #endif /* SDIO_EXPORTS_STRUCT_DEVICE */
-                          devno, priv, "unifiudi%d", bus_id)) {
+                       devno, priv, "unifiudi%d", bus_id)) {
         device_destroy(unifi_class, priv->unifi_cdev.dev);
         cdev_del(&priv->unifiudi_cdev);
         cdev_del(&priv->unifi_cdev);
diff --git a/drivers/staging/csr/firmware.c b/drivers/staging/csr/firmware.c
index d14e118..b6d8a6e 100644
--- a/drivers/staging/csr/firmware.c
+++ b/drivers/staging/csr/firmware.c
@@ -286,7 +286,7 @@
 
     unifi_trace(priv, UDBG2, "running %s %s %s\n", argv[0], argv[1], argv[2]);
 
-    r = call_usermodehelper(argv[0], argv, envp, 0);
+    r = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
 
     return r;
 #else
@@ -402,9 +402,7 @@
 int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free)
 {
     if (to_free != NULL) {
-        if (to_free->fw_desc != NULL) {
-            release_firmware((const struct firmware *)to_free->fw_desc);
-        }
+        release_firmware((const struct firmware *)to_free->fw_desc);
         to_free->fw_desc = NULL;
         to_free->dl_data = NULL;
         to_free->dl_len = 0;
diff --git a/drivers/staging/csr/io.c b/drivers/staging/csr/io.c
index e6503d96..caf48e3 100644
--- a/drivers/staging/csr/io.c
+++ b/drivers/staging/csr/io.c
@@ -31,6 +31,7 @@
  * ---------------------------------------------------------------------------
  */
 #include <linux/proc_fs.h>
+#include <linux/version.h>
 
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_unifiversion.h"
@@ -38,7 +39,6 @@
 #include "unifiio.h"
 #include "unifi_priv.h"
 
-
 /*
  * Array of pointers to context structs for unifi devices that are present.
  * The index in the array corresponds to the wlan interface number
@@ -70,11 +70,7 @@
  * Mutex to prevent UDI clients to open the character device before the priv
  * is created and initialised.
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
 DEFINE_SEMAPHORE(Unifi_instance_mutex);
-#else
-DECLARE_MUTEX(Unifi_instance_mutex);
-#endif
 /*
  * When the device is removed, unregister waits on Unifi_cleanup_wq
  * until all the UDI clients release the character device.
@@ -177,21 +173,6 @@
     /* The device is registed */
     interfacePriv->netdev_registered = 1;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-#ifdef CONFIG_NET_SCHED
-    /*
-     * IMPORTANT:
-     * uf_install_qdisc() holds the network device lock, we can not
-     * install the qdisk before the network device is registered.
-     */
-    r = uf_install_qdisc(priv->netdev[interfaceTag]);
-    if (r) {
-        unifi_error(priv, "Failed to install qdisc\n");
-        return r;
-    }
-#endif /* CONFIG_NET_SCHED */
-#endif /* LINUX_VERSION_CODE */
-
 #ifdef CSR_SUPPORT_SME
     /*
      * Register the inet handler; it notifies us for changes in the IP address.
@@ -347,7 +328,7 @@
     /*
      * We use the slot number as unifi device index.
      */
-    snprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
+    scnprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
     /*
      * The following complex casting is in place in order to eliminate 64-bit compilation warning
      * "cast to/from pointer from/to integer of different size"
@@ -669,7 +650,7 @@
         if(interfacePriv->netdev_registered)
         {
             netif_carrier_off(priv->netdev[interfaceTag]);
-            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]);
+            netif_tx_stop_all_queues(priv->netdev[interfaceTag]);
         }
     }
 
@@ -904,54 +885,54 @@
 
     orig_p = p;
 
-    written = CsrSnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n",
+    written = scnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n",
             CSR_WIFI_VERSION, __DATE__, __TIME__);
     UNIFI_SNPRINTF_RET(p, remain, written);
 #ifdef CSR_SME_USERSPACE
-    written = CsrSnprintf(p, remain, "SME: CSR userspace ");
+    written = scnprintf(p, remain, "SME: CSR userspace ");
     UNIFI_SNPRINTF_RET(p, remain, written);
 #ifdef CSR_SUPPORT_WEXT
-    written = CsrSnprintf(p, remain, "with WEXT support\n");
+    written = scnprintf(p, remain, "with WEXT support\n");
 #else
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
 #endif /* CSR_SUPPORT_WEXT */
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif /* CSR_SME_USERSPACE */
 #ifdef CSR_NATIVE_LINUX
-    written = CsrSnprintf(p, remain, "SME: native\n");
+    written = scnprintf(p, remain, "SME: native\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif
 
 #ifdef CSR_SUPPORT_SME
-    written = CsrSnprintf(p, remain,
-            "Firmware (ROM) build:%lu, Patch:%lu\n",
+    written = scnprintf(p, remain,
+            "Firmware (ROM) build:%u, Patch:%u\n",
             priv->card_info.fw_build,
             priv->sme_versions.firmwarePatch);
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif
     p += unifi_print_status(priv->card, p, &remain);
 
-    written = CsrSnprintf(p, remain, "Last dbg str: %s\n",
+    written = scnprintf(p, remain, "Last dbg str: %s\n",
             priv->last_debug_string);
     UNIFI_SNPRINTF_RET(p, remain, written);
 
-    written = CsrSnprintf(p, remain, "Last dbg16:");
+    written = scnprintf(p, remain, "Last dbg16:");
     UNIFI_SNPRINTF_RET(p, remain, written);
     for (i = 0; i < 8; i++) {
-        written = CsrSnprintf(p, remain, " %04X",
+        written = scnprintf(p, remain, " %04X",
                 priv->last_debug_word16[i]);
         UNIFI_SNPRINTF_RET(p, remain, written);
     }
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
-    written = CsrSnprintf(p, remain, "           ");
+    written = scnprintf(p, remain, "           ");
     UNIFI_SNPRINTF_RET(p, remain, written);
     for (; i < 16; i++) {
-        written = CsrSnprintf(p, remain, " %04X",
+        written = scnprintf(p, remain, " %04X",
                 priv->last_debug_word16[i]);
         UNIFI_SNPRINTF_RET(p, remain, written);
     }
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
     *start = page;
 
diff --git a/drivers/staging/csr/monitor.c b/drivers/staging/csr/monitor.c
index 628782a..7c524a1 100644
--- a/drivers/staging/csr/monitor.c
+++ b/drivers/staging/csr/monitor.c
@@ -10,6 +10,7 @@
  * ---------------------------------------------------------------------------
  */
 
+#include <linux/version.h>
 #include "unifi_priv.h"
 
 #ifdef UNIFI_SNIFF_ARPHRD
@@ -23,8 +24,6 @@
 #define ETH_P_80211_RAW ETH_P_ALL
 #endif
 
-
-
 /*
  * ---------------------------------------------------------------------------
  *  uf_start_sniff
@@ -192,11 +191,7 @@
 
 
     skb->dev = dev;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
     skb->mac_header = skb->data;
-#else
-    skb->mac.raw = skb->data;
-#endif
     skb->pkt_type = PACKET_OTHERHOST;
     skb->protocol = __constant_htons(ETH_P_80211_RAW);
     memset(skb->cb, 0, sizeof(skb->cb));
diff --git a/drivers/staging/csr/netdev.c b/drivers/staging/csr/netdev.c
index 1e6e111..9a52ab4 100644
--- a/drivers/staging/csr/netdev.c
+++ b/drivers/staging/csr/netdev.c
@@ -15,7 +15,6 @@
  * ---------------------------------------------------------------------------
  */
 
-
 /*
  * Porting Notes:
  * This file implements the data plane of the UniFi linux driver.
@@ -48,59 +47,14 @@
 #include <linux/etherdevice.h>
 #include <linux/mutex.h>
 #include <linux/semaphore.h>
-
+#include <linux/version.h>
 #include <linux/vmalloc.h>
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
 #include "unifi_priv.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-#include <net/iw_handler.h>
-#endif
 #include <net/pkt_sched.h>
 
 
-/* ALLOW_Q_PAUSE: Pre 2.6.28 kernels do not support multiple driver queues (required for QoS).
- * In order to support QoS in these kernels, multiple queues are implemented in the driver. But since
- * there is only a single queue in the kernel (leading to multiple queues in the driver) there is no possibility
- * of stopping a particular queue in the kernel. Stopping the single kernel queue leads to undesirable starvation
- * of driver queues. One of the proposals is to not stop the kernel queue but to prevent dequeuing from the
- * 'stopped' driver queue. Allow q pause is an experimental implementation of this scheme for pre 2.6.28 kernels.
- * When NOT defined, queues are paused locally in the driver and packets are dequeued for transmission only from the
- * unpaused queues. When Allow q pause is defined the kernel queue is stopped whenever any driver queue is paused.
- */
-#define ALLOW_Q_PAUSE
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
-#ifdef UNIFI_NET_NAME
-#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
-    do {                                                                \
-        static char name[8];                                           \
-        sprintf(name, "%s%s", UNIFI_NET_NAME, _name);                   \
-        _dev = alloc_netdev_mq(_size, name, _setup, _num_of_queues);    \
-    } while (0);
-#else
-#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
-    do {                                                                \
-        _dev = alloc_etherdev_mq(_size, _num_of_queues);                \
-    } while (0);
-#endif /* UNIFI_NET_NAME */
-#else
-#ifdef UNIFI_NET_NAME
-#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
-    do {                                                                \
-        static char name[8];                                           \
-        sprintf(name, "%s%s", UNIFI_NET_NAME, _name);                   \
-        _dev = alloc_netdev(_size, name, _setup);                       \
-    } while (0);
-#else
-#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
-    do {                                                                \
-        _dev = alloc_etherdev(_size);                                   \
-    } while (0);
-#endif /* UNIFI_NET_NAME */
-#endif /* LINUX_VERSION_CODE */
-
-
 /* Wext handler is suported only if CSR_SUPPORT_WEXT is defined */
 #ifdef CSR_SUPPORT_WEXT
 extern struct iw_handler_def unifi_iw_handler_def;
@@ -119,20 +73,8 @@
 static int uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int uf_net_stop(struct net_device *dev);
 static struct net_device_stats *uf_net_get_stats(struct net_device *dev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
 static u16 uf_net_select_queue(struct net_device *dev, struct sk_buff *skb);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 static netdev_tx_t uf_net_xmit(struct sk_buff *skb, struct net_device *dev);
-#else
-static int uf_net_xmit(struct sk_buff *skb, struct net_device *dev);
-#ifndef NETDEV_TX_OK
-#define NETDEV_TX_OK        0
-#endif
-#ifndef NETDEV_TX_BUSY
-#define NETDEV_TX_BUSY      1
-#endif
-#endif
 static void uf_set_multicast_list(struct net_device *dev);
 
 
@@ -182,62 +124,8 @@
     unsigned long host_tag;
 };
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd);
-static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd);
-static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd);
-static void uf_qdiscop_reset(struct Qdisc* qd);
-static void uf_qdiscop_destroy(struct Qdisc* qd);
-static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
-static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt);
-static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt);
-#else
-static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt);
-static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt);
-#endif
-#endif
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-/* queueing discipline operations */
-static struct Qdisc_ops uf_qdisc_ops =
-{
-    .next = NULL,
-    .cl_ops = NULL,
-    .id = "UniFi Qdisc",
-    .priv_size = sizeof(struct uf_sched_data),
-
-    .enqueue = uf_qdiscop_enqueue,
-    .dequeue = uf_qdiscop_dequeue,
-    .requeue = uf_qdiscop_requeue,
-    .drop = NULL, /* drop not needed since we are always the root qdisc */
-
-    .init = uf_qdiscop_init,
-    .reset = uf_qdiscop_reset,
-    .destroy = uf_qdiscop_destroy,
-    .change = uf_qdiscop_tune,
-
-    .dump = uf_qdiscop_dump,
-};
-#endif /* LINUX_VERSION_CODE */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
-#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
-    qdisc_create_dflt(dev, netdev_get_tx_queue(_dev, 0), _ops, _root)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
-    qdisc_create_dflt(dev, _ops, _root)
-#else
-#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
-    qdisc_create_dflt(dev, _ops)
-#endif /* LINUX_VERSION_CODE */
-
 #endif /* CONFIG_NET_SCHED */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
 static const struct net_device_ops uf_netdev_ops =
 {
     .ndo_open = uf_net_open,
@@ -248,7 +136,6 @@
     .ndo_set_rx_mode = uf_set_multicast_list,
     .ndo_select_queue = uf_net_select_queue,
 };
-#endif
 
 static u8 oui_rfc1042[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
 static u8 oui_8021h[P80211_OUI_LEN]   = { 0x00, 0x00, 0xf8 };
@@ -310,7 +197,7 @@
      * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices,
      * so use "eth*" (like other wireless extns drivers).
      */
-    UF_ALLOC_NETDEV(dev, sizeof(unifi_priv_t)+sizeof(netInterface_priv_t), "%d", ether_setup, UNIFI_TRAFFIC_Q_MAX);
+    dev = alloc_etherdev_mq(sizeof(unifi_priv_t) + sizeof(netInterface_priv_t), UNIFI_TRAFFIC_Q_MAX);
 
     if (dev == NULL) {
         return NULL;
@@ -332,22 +219,7 @@
     priv->interfacePriv[0] = interfacePriv;
 
     /* Setup / override net_device fields */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
     dev->netdev_ops = &uf_netdev_ops;
-#else
-    dev->open             = uf_net_open;
-    dev->stop             = uf_net_stop;
-    dev->hard_start_xmit  = uf_net_xmit;
-    dev->do_ioctl         = uf_net_ioctl;
-
-    /* called by /proc/net/dev */
-    dev->get_stats = uf_net_get_stats;
-
-    dev->set_multicast_list = uf_set_multicast_list;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
-    dev->select_queue       = uf_net_select_queue;
-#endif
-#endif
 
 #ifdef CSR_SUPPORT_WEXT
     dev->wireless_handlers = &unifi_iw_handler_def;
@@ -440,21 +312,13 @@
     interfacePriv->connected = UnifiConnectedUnknown;  /* -1 unknown, 0 no, 1 yes */
 
 #ifdef USE_DRIVER_LOCK
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
     sema_init(&priv->lock, 1);
-#else
-    init_MUTEX(&priv->lock);
-#endif
 #endif /* USE_DRIVER_LOCK */
 
     spin_lock_init(&priv->send_signal_lock);
 
     spin_lock_init(&priv->m4_lock);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
     sema_init(&priv->ba_mutex, 1);
-#else
-    init_MUTEX(&priv->ba_mutex);
-#endif
 
 #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
     spin_lock_init(&priv->wapi_lock);
@@ -487,16 +351,8 @@
 #endif
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-#ifdef CONFIG_NET_SCHED
-    /* Register the qdisc operations */
-    register_qdisc(&uf_qdisc_ops);
-#endif /* CONFIG_NET_SCHED */
-#endif /* LINUX_VERSION_CODE */
-
     priv->ref_count = 1;
 
-
     priv->amp_client = NULL;
     priv->coredump_mode = 0;
     priv->ptest_mode = 0;
@@ -566,7 +422,7 @@
      * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices,
      * so use "eth*" (like other wireless extns drivers).
      */
-    UF_ALLOC_NETDEV(dev, sizeof(netInterface_priv_t), "%d", ether_setup, 1);
+    dev = alloc_etherdev_mq(sizeof(netInterface_priv_t), 1);
     if (dev == NULL) {
         return FALSE;
     }
@@ -589,19 +445,7 @@
     INIT_LIST_HEAD(&interfacePriv->rx_controlled_list);
 
     /* Setup / override net_device fields */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
     dev->netdev_ops = &uf_netdev_ops;
-#else
-    dev->open             = uf_net_open;
-    dev->stop             = uf_net_stop;
-    dev->hard_start_xmit  = uf_net_xmit;
-    dev->do_ioctl         = uf_net_ioctl;
-
-    /* called by /proc/net/dev */
-    dev->get_stats = uf_net_get_stats;
-
-    dev->set_multicast_list = uf_set_multicast_list;
-#endif
 
 #ifdef CSR_SUPPORT_WEXT
     dev->wireless_handlers = &unifi_iw_handler_def;
@@ -686,13 +530,6 @@
     spin_unlock_irqrestore(&priv->wapi_lock, flags);
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-#ifdef CONFIG_NET_SCHED
-    /* Unregister the qdisc operations */
-    unregister_qdisc(&uf_qdisc_ops);
-#endif /* CONFIG_NET_SCHED */
-#endif /* LINUX_VERSION_CODE */
-
 #ifdef CSR_SUPPORT_WEXT
     /* Unregister callback for netdevice state changes */
     unregister_netdevice_notifier(&uf_netdev_notifier);
@@ -700,10 +537,8 @@
 
 #ifdef CSR_SUPPORT_SME
     /* Cancel work items and destroy the workqueue */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
     cancel_work_sync(&priv->multicast_list_task);
 #endif
-#endif
 /* Destroy the workqueues. */
     flush_workqueue(priv->unifi_workqueue);
     destroy_workqueue(priv->unifi_workqueue);
@@ -778,7 +613,7 @@
     }
 #endif
 
-    UF_NETIF_TX_START_ALL_QUEUES(dev);
+    netif_tx_start_all_queues(dev);
 
     func_exit();
     return 0;
@@ -808,7 +643,7 @@
     func_enter();
 #endif
 
-    UF_NETIF_TX_STOP_ALL_QUEUES(dev);
+    netif_tx_stop_all_queues(dev);
 
     func_exit();
     return 0;
@@ -957,7 +792,6 @@
     return priority;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
 /*
  * ---------------------------------------------------------------------------
  *  uf_net_select_queue
@@ -1005,7 +839,6 @@
     func_exit();
     return (u16)queue;
 } /* uf_net_select_queue() */
-#endif
 
 int
 skb_add_llc_snap(struct net_device *dev, struct sk_buff *skb, int proto)
@@ -1915,11 +1748,7 @@
  *      The controlled port is handled in the qdisc dequeue handler.
  * ---------------------------------------------------------------------------
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 static netdev_tx_t
-#else
-static int
-#endif
 uf_net_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
@@ -1929,9 +1758,7 @@
     int result;
     static tx_signal_handler tx_handler;
     CSR_PRIORITY priority;
-#if !defined (CONFIG_NET_SCHED) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
     CsrWifiRouterCtrlPortAction port_action;
-#endif /* CONFIG_NET_SCHED */
 
     func_enter();
 
@@ -1956,11 +1783,6 @@
         port = UF_UNCONTROLLED_PORT_Q;
     }
 
-#if defined (CONFIG_NET_SCHED) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28))
-    /* Remove the ethernet header */
-    skb_pull(skb, ETH_HLEN);
-    result = tx_handler(priv, skb, &ehdr, priority);
-#else
     /* Uncontrolled port rules apply */
     port_action = verify_port(priv
         , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode)||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI== interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest)
@@ -1986,7 +1808,6 @@
         func_exit();
         return NETDEV_TX_OK;
     }
-#endif /* CONFIG_NET_SCHED */
 
     if (result == NETDEV_TX_OK) {
 #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
@@ -2059,7 +1880,6 @@
     func_enter();
     unifi_trace(priv, UDBG2, "Stopping queue %d\n", queue);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
     for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
     {
         if (netif_running(priv->netdev[i]))
@@ -2067,24 +1887,6 @@
             netif_stop_subqueue(priv->netdev[i], (u16)queue);
         }
     }
-#else
-#ifdef ALLOW_Q_PAUSE
-    unifi_trace(priv, UDBG2, "Stopping netif\n");
-    /* stop the traffic from all the interfaces. */
-    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
-    {
-        if (netif_running(priv->netdev[i])) {
-            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]);
-        }
-    }
-#else
-    if (net_is_tx_q_paused(priv, queue)) {
-        unifi_trace(priv, UDBG2, "Queue already stopped\n");
-        return;
-    }
-    net_tx_q_pause(priv, queue);
-#endif
-#endif
 
 #ifdef CSR_SUPPORT_SME
     if(queue<=3) {
@@ -2108,7 +1910,6 @@
     func_enter();
     unifi_trace(priv, UDBG2, "Waking queue %d\n", queue);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
     for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
     {
         if (netif_running(priv->netdev[i]))
@@ -2116,25 +1917,6 @@
             netif_wake_subqueue(priv->netdev[i], (u16)queue);
         }
     }
-#else
-#ifdef ALLOW_Q_PAUSE
-    /* Need to supply queue number depending on Kernel support */
-    /* Resume the traffic from all the interfaces */
-    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
-    {
-        if (netif_running(priv->netdev[i])) {
-            UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[i]);
-        }
-    }
-#else
-    if (!(net_is_tx_q_paused(priv, queue))) {
-        unifi_trace(priv, UDBG2, "Queue already running\n");
-        func_exit();
-        return;
-    }
-    net_tx_q_unpause(priv, queue);
-#endif
-#endif
 
 #ifdef CSR_SUPPORT_SME
     if(queue <=3) {
@@ -2349,13 +2131,7 @@
     {
 #ifdef CONFIG_NET_SCHED
         if (netif_running(priv->netdev[interfaceTag])) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
             netif_tx_schedule_all(priv->netdev[interfaceTag]);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-            netif_schedule_queue(netdev_get_tx_queue(priv->netdev[interfaceTag], 0));
-#else
-            netif_schedule(priv->netdev[interfaceTag]);
-#endif /* LINUX_VERSION_CODE */
         }
 #endif
         uf_process_rx_pending_queue(priv, queue, peer_address, 1,interfaceTag);
@@ -2998,19 +2774,13 @@
 #else
 
     u8 *mc_list = interfacePriv->mc_list;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
     struct netdev_hw_addr *mc_addr;
     int mc_addr_count;
-#else
-    struct dev_mc_list *p;      /* Pointer to the addresses structure. */
-    int i;
-#endif
 
     if (priv->init_progress != UNIFI_INIT_COMPLETED) {
         return;
     }
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
     mc_addr_count = netdev_mc_count(dev);
 
     unifi_trace(priv, UDBG3,
@@ -3029,25 +2799,6 @@
         mc_list += ETH_ALEN;
     }
 
-#else
-    unifi_trace(priv, UDBG3,
-            "uf_set_multicast_list (count=%d)\n", dev->mc_count);
-
-    /* Not enough space? */
-    if (dev->mc_count > UNIFI_MAX_MULTICAST_ADDRESSES) {
-        return;
-    }
-
-    /* Store the list to be processed by the work item. */
-    interfacePriv->mc_list_count = dev->mc_count;
-    p = dev->mc_list;
-    for (i = 0; i < dev->mc_count; i++) {
-        memcpy(mc_list, p->dmi_addr, ETH_ALEN);
-        p = p->next;
-        mc_list += ETH_ALEN;
-    }
-#endif
-
     /* Send a message to the workqueue */
     queue_work(priv->unifi_workqueue, &priv->multicast_list_task);
 #endif
@@ -3181,375 +2932,6 @@
 
 } /* uf_net_get_name */
 
-
-
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-#ifdef CONFIG_NET_SCHED
-
-/*
- * ---------------------------------------------------------------------------
- *  uf_install_qdisc
- *
- *      Creates a root qdisc, registers our qdisc handlers and
- *      overrides the device's qdisc_sleeping to prevent the system
- *      from creating a new one for our network device.
- *
- *  Arguments:
- *      dev             Pointer to the network device.
- *
- *  Returns:
- *      0 on success, Linux error code otherwise.
- *
- *  Notes:
- *      This function holds the qdisk lock so it needs to be called
- *      after registering the network device in uf_register_netdev().
- *      Also, the qdisc_create_dflt() API has changed in 2.6.20 to
- *      include the parentid.
- * ---------------------------------------------------------------------------
- */
-int uf_install_qdisc(struct net_device *dev)
-{
-    struct Qdisc *qdisc;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    struct netdev_queue *queue0;
-#endif /* LINUX_VERSION_CODE */
-
-
-    func_enter();
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-    /*
-     * check that there is no qdisc currently attached to device
-     * this ensures that we will be the root qdisc. (I can't find a better
-     * way to test this explicitly)
-     */
-    if (dev->qdisc_sleeping != &noop_qdisc) {
-        func_exit_r(-EFAULT);
-        return -EINVAL;
-    }
-#endif /* LINUX_VERSION_CODE */
-
-    qdisc = UF_QDISC_CREATE_DFLT(dev, &uf_qdisc_ops, TC_H_ROOT);
-    if (!qdisc) {
-        unifi_error(NULL, "%s: qdisc installation failed\n", dev->name);
-        func_exit_r(-EFAULT);
-        return -EFAULT;
-    }
-    unifi_trace(NULL, UDBG5, "%s: parent qdisc=0x%p\n",
-            dev->name, qdisc);
-
-    qdisc->handle = 0x80020000;
-    qdisc->flags = 0x0;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    queue0 = netdev_get_tx_queue(dev, 0);
-    if (queue0 == NULL) {
-        unifi_error(NULL, "%s: netdev_get_tx_queue returned no queue\n",
-                dev->name);
-        func_exit_r(-EFAULT);
-        return -EFAULT;
-    }
-    queue0->qdisc = qdisc;
-    queue0->qdisc_sleeping = qdisc;
-#else
-    qdisc_lock_tree(dev);
-    list_add_tail(&qdisc->list, &dev->qdisc_list);
-    dev->qdisc_sleeping = qdisc;
-    qdisc_unlock_tree(dev);
-#endif /* LINUX_VERSION_CODE */
-
-    func_exit_r(0);
-    return 0;
-
-} /* uf_install_qdisc() */
-
-static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev);
-#else
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev);
-#endif /* LINUX_VERSION_CODE */
-    unifi_priv_t *priv = interfacePriv->privPtr;
-    struct uf_sched_data *q = qdisc_priv(qd);
-    struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb;
-    struct ethhdr ehdr;
-    struct Qdisc *qdisc;
-    int r, proto;
-
-    func_enter();
-
-    memcpy(&ehdr, skb->data, ETH_HLEN);
-    proto = ntohs(ehdr.h_proto);
-
-    /* 802.1x - apply controlled/uncontrolled port rules */
-    if ((proto != ETH_P_PAE)
-#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
-            && (proto != ETH_P_WAI)
-#endif
-       ) {
-        /* queues 0 - 3 */
-        pkt_data->priority = get_packet_priority(priv, skb, &ehdr, interfacePriv);
-        pkt_data->queue = unifi_frame_priority_to_queue(pkt_data->priority);
-    } else {
-        pkt_data->queue = UNIFI_TRAFFIC_Q_EAPOL;
-    }
-
-    qdisc = q->queues[pkt_data->queue];
-    r = qdisc->enqueue(skb, qdisc);
-    if (r == NET_XMIT_SUCCESS) {
-        qd->q.qlen++;
-        qd->bstats.bytes += skb->len;
-        qd->bstats.packets++;
-        func_exit_r(NET_XMIT_SUCCESS);
-        return NET_XMIT_SUCCESS;
-    }
-
-    unifi_error(priv, "uf_qdiscop_enqueue: dropped\n");
-    qd->qstats.drops++;
-
-    func_exit_r(r);
-    return r;
-
-} /* uf_qdiscop_enqueue() */
-
-
-static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev_queue->dev);
-#else
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev);
-#endif /* LINUX_VERSION_CODE */
-    unifi_priv_t *priv = interfacePriv->privPtr;
-    struct uf_sched_data *q = qdisc_priv(qd);
-    struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb;
-    struct Qdisc *qdisc;
-    int r;
-
-    func_enter();
-
-    unifi_trace(priv, UDBG5, "uf_qdiscop_requeue: (q=%d), tag=%u\n",
-            pkt_data->queue, pkt_data->host_tag);
-
-    /* we recorded which queue to use earlier! */
-    qdisc = q->queues[pkt_data->queue];
-
-    if ((r = qdisc->ops->requeue(skb, qdisc)) == 0) {
-        qd->q.qlen++;
-        func_exit_r(0);
-        return 0;
-    }
-
-    unifi_error(priv, "uf_qdiscop_requeue: dropped\n");
-    qd->qstats.drops++;
-
-    func_exit_r(r);
-    return r;
-} /* uf_qdiscop_requeue() */
-
-static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev);
-#else
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev);
-#endif /* LINUX_VERSION_CODE */
-    unifi_priv_t *priv = interfacePriv->privPtr;
-    struct uf_sched_data *q = qdisc_priv(qd);
-    struct sk_buff *skb;
-    struct Qdisc *qdisc;
-    int queue, i;
-    struct ethhdr ehdr;
-    struct uf_tx_packet_data *pkt_data;
-    CsrWifiRouterCtrlPortAction port_action;
-
-    func_enter();
-
-    /* check all the queues */
-    for (i = UNIFI_TRAFFIC_Q_MAX - 1; i >= 0; i--) {
-
-        if (i != UNIFI_TRAFFIC_Q_EAPOL) {
-            queue = priv->prev_queue;
-            if (++priv->prev_queue >= UNIFI_TRAFFIC_Q_EAPOL) {
-                priv->prev_queue = 0;
-            }
-        } else {
-            queue = i;
-        }
-
-#ifndef ALLOW_Q_PAUSE
-        /* If queue is paused, do not dequeue */
-        if (net_is_tx_q_paused(priv, queue)) {
-            unifi_trace(priv, UDBG5,
-                    "uf_qdiscop_dequeue: tx queue paused (q=%d)\n", queue);
-            continue;
-        }
-#endif
-
-        qdisc = q->queues[queue];
-        skb = qdisc->dequeue(qdisc);
-        if (skb) {
-            /* A packet has been dequeued, decrease the queued packets count */
-            qd->q.qlen--;
-
-            pkt_data = (struct uf_tx_packet_data *) skb->cb;
-
-            /* Check the (un)controlled port status */
-            memcpy(&ehdr, skb->data, ETH_HLEN);
-
-            port_action = verify_port(priv
-                            , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) ||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI == interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest)
-                            , (UNIFI_TRAFFIC_Q_EAPOL == queue? UF_UNCONTROLLED_PORT_Q: UF_CONTROLLED_PORT_Q)
-                            , interfacePriv->InterfaceTag);
-
-            /* Dequeue packet if port is open */
-            if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
-                unifi_trace(priv, UDBG5,
-                        "uf_qdiscop_dequeue: new (q=%d), tag=%u\n",
-                        queue, pkt_data->host_tag);
-
-                func_exit();
-                return skb;
-            }
-
-            /* Discard or block the packet if necessary */
-            if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) {
-                unifi_trace(priv, UDBG5,
-                        "uf_qdiscop_dequeue: drop (q=%d), tag=%u\n",
-                        queue, pkt_data->host_tag);
-                kfree_skb(skb);
-                break;
-            }
-
-            /* We can not send the packet now, put it back to the queue */
-            if (qdisc->ops->requeue(skb, qdisc) != 0) {
-                unifi_error(priv,
-                        "uf_qdiscop_dequeue: requeue (q=%d) failed, tag=%u, drop it\n",
-                        queue, pkt_data->host_tag);
-
-                /* Requeue failed, drop the packet */
-                kfree_skb(skb);
-                break;
-            }
-            /* We requeued the packet, increase the queued packets count */
-            qd->q.qlen++;
-
-            unifi_trace(priv, UDBG5,
-                    "uf_qdiscop_dequeue: skip (q=%d), tag=%u\n",
-                    queue, pkt_data->host_tag);
-        }
-    }
-
-    func_exit();
-    return NULL;
-} /* uf_qdiscop_dequeue() */
-
-
-static void uf_qdiscop_reset(struct Qdisc* qd)
-{
-    struct uf_sched_data *q = qdisc_priv(qd);
-    int queue;
-    func_enter();
-
-    for (queue = 0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) {
-        qdisc_reset(q->queues[queue]);
-    }
-    qd->q.qlen = 0;
-
-    func_exit();
-} /* uf_qdiscop_reset() */
-
-
-static void uf_qdiscop_destroy(struct Qdisc* qd)
-{
-    struct uf_sched_data *q = qdisc_priv(qd);
-    int queue;
-
-    func_enter();
-
-    for (queue=0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) {
-        qdisc_destroy(q->queues[queue]);
-        q->queues[queue] = &noop_qdisc;
-    }
-
-    func_exit();
-} /* uf_qdiscop_destroy() */
-
-
-/* called whenever parameters are updated on existing qdisc */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
-static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt)
-#else
-static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt)
-#endif
-{
-    func_enter();
-    func_exit();
-    return 0;
-} /* uf_qdiscop_tune() */
-
-
-/* called during initial creation of qdisc on device */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
-static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
-#else
-static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
-#endif
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-    struct net_device *dev = qd->dev_queue->dev;
-#else
-    struct net_device *dev = qd->dev;
-#endif /* LINUX_VERSION_CODE */
-    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
-    unifi_priv_t *priv = interfacePriv->privPtr;
-    struct uf_sched_data *q = qdisc_priv(qd);
-    int err = 0, i;
-
-    func_enter();
-
-    /* make sure we do not mess with the ingress qdisc */
-    if (qd->flags & TCQ_F_INGRESS) {
-        func_exit();
-        return -EINVAL;
-    }
-
-    /* if options were passed in, set them */
-    if (opt) {
-        err = uf_qdiscop_tune(qd, opt);
-    }
-
-    /* create child queues */
-    for (i = 0; i < UNIFI_TRAFFIC_Q_MAX; i++) {
-        q->queues[i] = UF_QDISC_CREATE_DFLT(dev, &pfifo_qdisc_ops,
-                qd->handle);
-        if (!q->queues[i]) {
-            q->queues[i] = &noop_qdisc;
-            unifi_error(priv, "%s child qdisc %i creation failed\n");
-        }
-
-        unifi_trace(priv, UDBG5, "%s: child qdisc=0x%p\n",
-                dev->name, q->queues[i]);
-    }
-
-    func_exit_r(err);
-    return err;
-} /* uf_qdiscop_init() */
-
-
-static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
-{
-    func_enter();
-    func_exit_r(skb->len);
-    return skb->len;
-} /* uf_qdiscop_dump() */
-
-#endif /* CONFIG_NET_SCHED */
-#endif /* LINUX_VERSION_CODE */
-
 #ifdef CSR_SUPPORT_WEXT
 
 /*
@@ -3595,7 +2977,7 @@
                     interfacePriv->wait_netdev_change ? "" : "not");
 
         if (interfacePriv->wait_netdev_change) {
-            UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[interfacePriv->InterfaceTag]);
+            netif_tx_wake_all_queues(priv->netdev[interfacePriv->InterfaceTag]);
             interfacePriv->connected = UnifiConnected;
             interfacePriv->wait_netdev_change = FALSE;
             /* Note: passing the broadcast address here will allow anyone to attempt to join our adhoc network */
diff --git a/drivers/staging/csr/sdio_events.c b/drivers/staging/csr/sdio_events.c
index 6892c2e..2a80b9e 100644
--- a/drivers/staging/csr/sdio_events.c
+++ b/drivers/staging/csr/sdio_events.c
@@ -66,7 +66,7 @@
                 unifi_trace(priv, UDBG1, "unifi_suspend: netif_carrier_off");
                 netif_carrier_off(priv->netdev[interfaceTag]);
             }
-            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]);
+            netif_tx_stop_all_queues(priv->netdev[interfaceTag]);
         }
     }
 
@@ -119,7 +119,7 @@
             if (interfacePriv->netdev_registered == 1)
             {
                 netif_carrier_on(priv->netdev[interfaceTag]);
-                UF_NETIF_TX_START_ALL_QUEUES(priv->netdev[interfaceTag]);
+                netif_tx_start_all_queues(priv->netdev[interfaceTag]);
             }
         }
 
diff --git a/drivers/staging/csr/sdio_mmc.c b/drivers/staging/csr/sdio_mmc.c
index d3fd57c..af3e40b 100644
--- a/drivers/staging/csr/sdio_mmc.c
+++ b/drivers/staging/csr/sdio_mmc.c
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/mutex.h>
 #include <linux/gfp.h>
-
+#include <linux/version.h>
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -31,7 +31,6 @@
 
 static CsrSdioFunctionDriver *sdio_func_drv;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
 static int uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long event, void *ptr);
 #endif
@@ -45,7 +44,6 @@
  * returning immediately (at least on x86).
  */
 static int card_is_powered = 1;
-#endif /* 2.6.32 */
 
 /* MMC uses ENOMEDIUM to indicate card gone away */
 
@@ -637,7 +635,6 @@
 CsrResult
 CsrSdioPowerOn(CsrSdioFunction *function)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
     struct sdio_func *func = (struct sdio_func *)function->priv;
     struct mmc_host *host = func->card->host;
 
@@ -649,7 +646,6 @@
         printk(KERN_INFO "SDIO: Skip power on; card is already powered.\n");
     }
     _sdio_release_host(func);
-#endif /* 2.6.32 */
 
     return CSR_RESULT_SUCCESS;
 } /* CsrSdioPowerOn() */
@@ -667,7 +663,6 @@
 void
 CsrSdioPowerOff(CsrSdioFunction *function)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
     struct sdio_func *func = (struct sdio_func *)function->priv;
     struct mmc_host *host = func->card->host;
 
@@ -679,7 +674,6 @@
         printk(KERN_INFO "SDIO: Skip power off; card is already powered off.\n");
     }
     _sdio_release_host(func);
-#endif /* 2.6.32 */
 } /* CsrSdioPowerOff() */
 
 
@@ -845,19 +839,18 @@
  *      Status of the removal.
  * ---------------------------------------------------------------------------
  */
-int
-csr_sdio_linux_remove_irq(CsrSdioFunction *function)
+int csr_sdio_linux_remove_irq(CsrSdioFunction *function)
 {
-    struct sdio_func *func = (struct sdio_func *)function->priv;
-    int r;
+	struct sdio_func *func = (struct sdio_func *)function->priv;
+	int r;
 
-    unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n");
+	unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n");
 
-    sdio_claim_host(func);
-    r = sdio_release_irq(func);
-    sdio_release_host(func);
+	sdio_claim_host(func);
+	r = sdio_release_irq(func);
+	sdio_release_host(func);
 
-    return r;
+	return r;
 
 } /* csr_sdio_linux_remove_irq() */
 
@@ -876,28 +869,25 @@
  *      Status of the removal.
  * ---------------------------------------------------------------------------
  */
-int
-csr_sdio_linux_install_irq(CsrSdioFunction *function)
+int csr_sdio_linux_install_irq(CsrSdioFunction *function)
 {
-    struct sdio_func *func = (struct sdio_func *)function->priv;
-    int r;
+	struct sdio_func *func = (struct sdio_func *)function->priv;
+	int r;
 
-    unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n");
+	unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n");
 
-    /* Register our interrupt handle */
-    sdio_claim_host(func);
-    r = sdio_claim_irq(func, uf_glue_sdio_int_handler);
-    sdio_release_host(func);
+	/* Register our interrupt handle */
+	sdio_claim_host(func);
+	r = sdio_claim_irq(func, uf_glue_sdio_int_handler);
+	sdio_release_host(func);
 
-    /* If the interrupt was installed earlier, is fine */
-    if (r == -EBUSY) {
-        r = 0;
-    }
+	/* If the interrupt was installed earlier, is fine */
+	if (r == -EBUSY)
+		r = 0;
 
-    return r;
+	return r;
 } /* csr_sdio_linux_install_irq() */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
 
 /*
@@ -1023,7 +1013,6 @@
 }
 
 #endif /* CONFIG_PM */
-#endif /* 2.6.32 */
 
 /*
  * ---------------------------------------------------------------------------
@@ -1050,10 +1039,8 @@
     /* First of all claim the SDIO driver */
     sdio_claim_host(func);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
     /* Assume that the card is already powered */
     card_is_powered = 1;
-#endif
 
     /* Assumes one card per host, which is true for SDIO */
     instance = func->card->host->index;
@@ -1093,14 +1080,12 @@
     /* Pass context to the SDIO driver */
     sdio_set_drvdata(func, sdio_ctx);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
     /* Register to get PM events */
     if (uf_sdio_mmc_register_pm_notifier(sdio_ctx) == NULL) {
         unifi_error(NULL, "%s: Failed to register for PM events\n", __FUNCTION__);
     }
 #endif
-#endif
 
     /* Register this device with the SDIO function driver */
     /* Call the main UniFi driver inserted handler */
@@ -1156,12 +1141,10 @@
         sdio_func_drv->removed(sdio_ctx);
     }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
     /* Unregister for PM events */
     uf_sdio_mmc_unregister_pm_notifier(sdio_ctx);
 #endif
-#endif
 
     kfree(sdio_ctx);
 
@@ -1182,7 +1165,6 @@
 
 MODULE_DEVICE_TABLE(sdio, unifi_ids);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
 
 /*
@@ -1252,16 +1234,13 @@
 #define UNIFI_PM_OPS  NULL
 
 #endif /* CONFIG_PM */
-#endif /* 2.6.32 */
 
 static struct sdio_driver unifi_driver = {
     .probe      = uf_glue_sdio_probe,
     .remove     = uf_glue_sdio_remove,
     .name       = "unifi",
     .id_table	= unifi_ids,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
     .drv.pm     = UNIFI_PM_OPS,
-#endif /* 2.6.32 */
 };
 
 
@@ -1305,12 +1284,10 @@
      */
     sdio_func_drv = sdio_drv;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 #ifdef CONFIG_PM
     /* Initialise PM notifier list */
     INIT_LIST_HEAD(&uf_sdio_mmc_pm_notifiers.list);
 #endif
-#endif
 
     /* Register ourself with mmc_core */
     r = sdio_register_driver(&unifi_driver);
diff --git a/drivers/staging/csr/sme_blocking.c b/drivers/staging/csr/sme_blocking.c
index acf0f0f..543e8f2 100644
--- a/drivers/staging/csr/sme_blocking.c
+++ b/drivers/staging/csr/sme_blocking.c
@@ -18,10 +18,10 @@
 
 
 /*
- * This file also contains the implementation of the asyncronous
+ * This file also contains the implementation of the asynchronous
  * requests to the SME.
  *
- * Before calling an asyncronous SME function, we call sme_init_request()
+ * Before calling an asynchronous SME function, we call sme_init_request()
  * which gets hold of the SME semaphore and updates the request status.
  * The semaphore makes sure that there is only one pending request to
  * the SME at a time.
diff --git a/drivers/staging/csr/sme_native.c b/drivers/staging/csr/sme_native.c
index 229268f..d7a5125 100644
--- a/drivers/staging/csr/sme_native.c
+++ b/drivers/staging/csr/sme_native.c
@@ -12,7 +12,7 @@
  */
 
 #include <linux/netdevice.h>
-
+#include <linux/version.h>
 #include "unifi_priv.h"
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
@@ -24,11 +24,7 @@
 {
     func_enter();
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
     sema_init(&priv->mlme_blocking_mutex, 1);
-#else
-    init_MUTEX(&priv->mlme_blocking_mutex);
-#endif
 
 #ifdef CSR_SUPPORT_WEXT
     {
diff --git a/drivers/staging/csr/sme_sys.c b/drivers/staging/csr/sme_sys.c
index 99de27e..5b26c41 100644
--- a/drivers/staging/csr/sme_sys.c
+++ b/drivers/staging/csr/sme_sys.c
@@ -14,6 +14,7 @@
  * ---------------------------------------------------------------------------
  */
 
+#include <linux/version.h>
 #include "csr_wifi_hip_unifiversion.h"
 #include "unifi_priv.h"
 #include "csr_wifi_hip_conversions.h"
@@ -21,7 +22,6 @@
 #include "csr_wifi_sme_sef.h"
 #endif
 
-
 /*
  * This file implements the SME SYS API and contains the following functions:
  * CsrWifiRouterCtrlMediaStatusReqHandler()
@@ -192,7 +192,7 @@
 #endif
                     unifi_trace(priv, UDBG1,
                                 "CsrWifiRouterCtrlMediaStatusReqHandler: AP/P2PGO setting netif_carrier_on\n");
-                    UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]);
+                    netif_tx_wake_all_queues(priv->netdev[req->interfaceTag]);
                     break;
 
                 default:
@@ -226,7 +226,7 @@
                     unifi_trace(priv, UDBG1,
                                 "CsrWifiRouterMediaStatusReqHandler: UnifiConnected && netif_carrier_on\n");
                     netif_carrier_on(priv->netdev[req->interfaceTag]);
-                    UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]);
+                    netif_tx_wake_all_queues(priv->netdev[req->interfaceTag]);
                     uf_process_rx_pending_queue(priv, UF_UNCONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag);
                     uf_process_rx_pending_queue(priv, UF_CONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag);
                 }
@@ -869,7 +869,6 @@
     unifi_trace(priv, UDBG1, "wifi_off\n");
 
     /* Destroy the Traffic Analysis Module */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
     cancel_work_sync(&priv->ta_ind_work.task);
     cancel_work_sync(&priv->ta_sample_ind_work.task);
 #ifdef CSR_SUPPORT_WEXT
@@ -884,7 +883,6 @@
             cancel_work_sync(&netpriv->send_m4_ready_task);
         }
     }
-#endif
     flush_workqueue(priv->unifi_workqueue);
 
     /* fw_init parameter can prevent power off UniFi, for debugging */
@@ -955,7 +953,7 @@
         netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
         if (interfacePriv->netdev_registered == 1) {
             netif_carrier_off(priv->netdev[i]);
-            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]);
+            netif_tx_stop_all_queues(priv->netdev[i]);
             interfacePriv->connected = UnifiConnectedUnknown;
         }
         interfacePriv->interfaceMode = 0;
@@ -2123,7 +2121,7 @@
             /* Allocate for the new station record , to avoid race condition would happen between ADD_PEER &
              * DEL_PEER the allocation made atomic memory rather than kernel memory
              */
-            newRecord = (CsrWifiRouterCtrlStaInfo_t *) kmalloc(sizeof(CsrWifiRouterCtrlStaInfo_t), GFP_ATOMIC);
+            newRecord = kmalloc(sizeof(CsrWifiRouterCtrlStaInfo_t), GFP_ATOMIC);
             if (!newRecord) {
                 unifi_error(priv, "failed to allocate the %d bytes of mem for station record\n",
                             sizeof(CsrWifiRouterCtrlStaInfo_t));
@@ -2815,12 +2813,11 @@
         }
 
         /* create and populate the new BA session structure */
-        ba_session_tx = kmalloc(sizeof(ba_session_tx_struct), GFP_KERNEL);
+        ba_session_tx = kzalloc(sizeof(ba_session_tx_struct), GFP_KERNEL);
         if (!ba_session_tx) {
             unifi_error(priv, "%s: kmalloc failed for ba_session_tx\n", __FUNCTION__);
             return FALSE;
         }
-        memset(ba_session_tx, 0, sizeof(ba_session_tx_struct));
 
         ba_session_tx->interfacePriv = interfacePriv;
         ba_session_tx->tID = tID;
@@ -2905,26 +2902,23 @@
             return FALSE;
         }
 
-        ba_session_rx = kmalloc(sizeof(ba_session_rx_struct), GFP_KERNEL);
+        ba_session_rx = kzalloc(sizeof(ba_session_rx_struct), GFP_KERNEL);
         if (!ba_session_rx) {
             unifi_error(priv, "%s: kmalloc failed for ba_session_rx\n", __FUNCTION__);
             return FALSE;
         }
-        memset(ba_session_rx, 0, sizeof(ba_session_rx_struct));
 
         ba_session_rx->wind_size = wind_size;
         ba_session_rx->start_sn = ba_session_rx->expected_sn = start_sn;
         ba_session_rx->trigger_ba_after_ssn = FALSE;
 
-        ba_session_rx->buffer = kmalloc(ba_session_rx->wind_size*sizeof(frame_desc_struct), GFP_KERNEL);
+        ba_session_rx->buffer = kzalloc(ba_session_rx->wind_size*sizeof(frame_desc_struct), GFP_KERNEL);
         if (!ba_session_rx->buffer) {
             kfree(ba_session_rx);
             unifi_error(priv, "%s: kmalloc failed for buffer\n", __FUNCTION__);
             return FALSE;
         }
 
-        memset(ba_session_rx->buffer, 0, ba_session_rx->wind_size*sizeof(frame_desc_struct));
-
         INIT_WORK(&ba_session_rx->send_ba_err_task, uf_send_ba_err_wq);
         if (timeout) {
             ba_session_rx->timeout = timeout;
diff --git a/drivers/staging/csr/sme_wext.c b/drivers/staging/csr/sme_wext.c
index 7e85907..b58c0c6 100644
--- a/drivers/staging/csr/sme_wext.c
+++ b/drivers/staging/csr/sme_wext.c
@@ -1191,8 +1191,6 @@
     netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
     unifi_priv_t *priv = interfacePriv->privPtr;
     int err = 0;
-    const unsigned char zero_bssid[ETH_ALEN] = {0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00};
 
     func_enter();
 
@@ -1213,7 +1211,7 @@
 	unifi_trace(priv, UDBG1, "unifi_siwap: asked for %pM\n",
 		wrqu->ap_addr.sa_data);
 
-    if (!memcmp(wrqu->ap_addr.sa_data, zero_bssid, ETH_ALEN)) {
+    if (is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
         priv->ignore_bssid_join = FALSE;
         err = sme_mgt_disconnect(priv);
         if (err) {
@@ -3043,8 +3041,8 @@
     memcpy(sme_key.address.a, ext->addr.sa_data, ETH_ALEN);
     if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
 
-        unifi_trace(priv, UDBG5, "RSC first 6 bytes = %02X:%02X:%02X:%02X:%02X:%02X\n",
-                    ext->rx_seq[0], ext->rx_seq[1], ext->rx_seq[2], ext->rx_seq[3], ext->rx_seq[4], ext->rx_seq[5]);
+		unifi_trace(priv, UDBG5, "RSC first 6 bytes = %*phC\n",
+					 6, ext->rx_seq);
 
         /* memcpy((u8*)(&sme_key.keyRsc), ext->rx_seq, 8); */
         sme_key.keyRsc[0] = ext->rx_seq[1] << 8 | ext->rx_seq[0];
diff --git a/drivers/staging/csr/ul_int.c b/drivers/staging/csr/ul_int.c
index 46d3507..4013d02 100644
--- a/drivers/staging/csr/ul_int.c
+++ b/drivers/staging/csr/ul_int.c
@@ -12,6 +12,7 @@
  *
  * ***************************************************************************
  */
+#include <linux/version.h>
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
 #include "unifi_priv.h"
@@ -44,11 +45,7 @@
     int id;
     ul_client_t *ul_clients;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
     sema_init(&priv->udi_logging_mutex, 1);
-#else
-    init_MUTEX(&priv->udi_logging_mutex);
-#endif
     priv->logging_client = NULL;
 
     ul_clients = priv->ul_clients;
diff --git a/drivers/staging/csr/unifi_pdu_processing.c b/drivers/staging/csr/unifi_pdu_processing.c
index 7c7e8d4..ae7c8fc 100644
--- a/drivers/staging/csr/unifi_pdu_processing.c
+++ b/drivers/staging/csr/unifi_pdu_processing.c
@@ -14,7 +14,7 @@
  * ---------------------------------------------------------------------------
  */
 
-
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
@@ -23,9 +23,6 @@
 #include "csr_wifi_hip_conversions.h"
 #include "csr_time.h"
 #include "unifi_priv.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-#include <net/iw_handler.h>
-#endif
 #include <net/pkt_sched.h>
 
 #ifdef CSR_SUPPORT_SME
diff --git a/drivers/staging/csr/unifi_priv.h b/drivers/staging/csr/unifi_priv.h
index 6d6b461..aec8e28 100644
--- a/drivers/staging/csr/unifi_priv.h
+++ b/drivers/staging/csr/unifi_priv.h
@@ -29,9 +29,7 @@
 #include <linux/wireless.h>
 #include <linux/cdev.h>
 #include <linux/kthread.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
 #include <linux/freezer.h>
-#endif
 
 #ifdef CSR_WIFI_SUPPORT_MMC_DRIVER
 #include <linux/mmc/core.h>
@@ -73,33 +71,6 @@
 
 #include "unifi_clients.h"
 
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-#include <linux/workqueue.h>
-
-#undef INIT_WORK
-#define INIT_WORK(_work, _func)                                         \
-    do {                                                                \
-        INIT_LIST_HEAD(&(_work)->entry);                                \
-        (_work)->pending = 0;                                           \
-        PREPARE_WORK((_work), (_func), (_work));                        \
-        init_timer(&(_work)->timer);                                    \
-    } while(0)
-
-#endif  /* Linux kernel < 2.6.20 */
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev)    netif_tx_wake_all_queues(_netdev)
-#define UF_NETIF_TX_START_ALL_QUEUES(_netdev)   netif_tx_start_all_queues(_netdev)
-#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev)    netif_tx_stop_all_queues(_netdev)
-#else
-#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev)    netif_wake_queue(_netdev)
-#define UF_NETIF_TX_START_ALL_QUEUES(_netdev)   netif_start_queue(_netdev)
-#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev)    netif_stop_queue(_netdev)
-#endif  /* Linux kernel >= 2.6.27 */
-
-
 #ifdef CSR_NATIVE_LINUX
 #include "sme_native/unifi_native.h"
 #else
@@ -634,12 +605,10 @@
     spinlock_t wapi_lock;
 #endif
 
-#ifndef ALLOW_Q_PAUSE
     /* Array to indicate if a particular Tx queue is paused, this may not be
      * required in a multiqueue implementation since we can directly stop kernel
      * queues */
     u8 tx_q_paused_flag[UNIFI_TRAFFIC_Q_MAX];
-#endif
 
 #ifdef CSR_WIFI_RX_PATH_SPLIT
     struct workqueue_struct *rx_workqueue;
@@ -798,12 +767,6 @@
     u8 bcTimSetReqQueued;
 } netInterface_priv_t;
 
-#ifndef ALLOW_Q_PAUSE
-#define net_is_tx_q_paused(priv, q)   (priv->tx_q_paused_flag[q])
-#define net_tx_q_unpause(priv, q)   (priv->tx_q_paused_flag[q] = 0)
-#define net_tx_q_pause(priv, q)   (priv->tx_q_paused_flag[q] = 1)
-#endif
-
 #ifdef CSR_SUPPORT_SME
 #define routerStartBuffering(priv,queue) priv->routerBufferEnable[(queue)] = TRUE;
 #define routerStopBuffering(priv,queue) priv->routerBufferEnable[(queue)]  = FALSE;
@@ -1088,9 +1051,6 @@
 void uf_update_sta_activity(unifi_priv_t *priv, u16 interfaceTag, const u8 *peerMacAddress);
 void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,u16 interfaceTag, const CSR_MA_PACKET_CONFIRM *pkt_cfm);
 #endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-int uf_install_qdisc(struct net_device *dev);
-#endif
 
 void uf_resume_data_plane(unifi_priv_t *priv, int queue,
                           CsrWifiMacAddress peer_address,
diff --git a/drivers/staging/csr/unifi_wext.h b/drivers/staging/csr/unifi_wext.h
index 6d7a995..6834c43 100644
--- a/drivers/staging/csr/unifi_wext.h
+++ b/drivers/staging/csr/unifi_wext.h
@@ -16,6 +16,7 @@
 #define __LINUX_UNIFI_WEXT_H__ 1
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <net/iw_handler.h>
 #include "csr_wifi_sme_prim.h"
 
@@ -70,15 +71,9 @@
 {
     char *new_start;
 
-    new_start = iwe_stream_add_point(
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined (IW_REQUEST_FLAG_COMPAT)
-                                     info,
-#endif
-                                     start, stop, piwe, extra);
+    new_start = iwe_stream_add_point(info, start, stop, piwe, extra);
     if (unlikely(new_start == start))
-    {
         return -E2BIG;
-    }
 
     return (new_start - start);
 }
@@ -90,14 +85,9 @@
 {
     char *new_start;
 
-    new_start = iwe_stream_add_event(
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT)
-                                     info,
-#endif
-                                     start, stop, piwe, len);
-    if (unlikely(new_start == start)) {
+    new_start = iwe_stream_add_event(info, start, stop, piwe, len);
+    if (unlikely(new_start == start))
         return -E2BIG;
-    }
 
     return (new_start - start);
 }
@@ -108,14 +98,9 @@
 {
     char *new_start;
 
-    new_start = iwe_stream_add_value(
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT)
-                                     info,
-#endif
-                                     stream, start, stop, piwe, len);
-    if (unlikely(new_start == start)) {
+    new_start = iwe_stream_add_value(info, stream, start, stop, piwe, len);
+    if (unlikely(new_start == start))
         return -E2BIG;
-    }
 
     return (new_start - start);
 }
diff --git a/drivers/staging/csr/wext_events.c b/drivers/staging/csr/wext_events.c
index d356887..9860ea3 100644
--- a/drivers/staging/csr/wext_events.c
+++ b/drivers/staging/csr/wext_events.c
@@ -194,11 +194,9 @@
     union iwreq_data wrqu;
     char buf[128];
 
-    sprintf(buf,
-            "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%02x:%02x:%02x:%02x:%02x:%02x)",
-            key_idx, (key_type == CSR_GROUP) ? "broad" : "uni",
-            macaddr[0], macaddr[1], macaddr[2],
-            macaddr[3], macaddr[4], macaddr[5]);
+	sprintf(buf,
+		"MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%pM)",
+		key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", macaddr);
     memset(&wrqu, 0, sizeof(wrqu));
     wrqu.data.length = strlen(buf);
     wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index 911c0e4..0ff2865 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -405,7 +405,7 @@
     priv = hdlc->priv;
 
     rval = musycc_start_xmit (priv->ci, priv->channum, skb);
-    return -rval;
+    return rval;
 }
 
 static const struct net_device_ops chan_ops = {
@@ -1169,11 +1169,11 @@
 STATIC void __exit
 c4_mod_remove (void)
 {
-    cleanup_hdlc ();            /* delete any missed channels */
-    cleanup_devs ();
-    c4_cleanup ();
-    cleanup_ioremap ();
-    pr_info("SBE - driver removed.\n");
+	cleanup_hdlc();            /* delete any missed channels */
+	cleanup_devs();
+	c4_cleanup();
+	cleanup_ioremap();
+	pr_info("SBE - driver removed.\n");
 }
 
 module_init (c4_mod_init);
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index 90c0f1e..ba721c6 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -1761,15 +1761,15 @@
     u_int32_t   len;
 
     if (!(ch = sd_find_chan (ci, channum)))
-        return ENOENT;
+        return -ENOENT;
 
     if (ci->state != C_RUNNING)     /* full interrupt processing available */
-        return EINVAL;
+        return -EINVAL;
     if (ch->state != UP)
-        return EINVAL;
+        return -EINVAL;
 
     if (!(ch->status & TX_ENABLED))
-        return EROFS;               /* how else to flag unwritable state ? */
+        return -EROFS;               /* how else to flag unwritable state ? */
 
 #ifdef RLD_TRANS_DEBUGx
     if (1 || cxt1e1_log_level >= LOG_MONITOR2)
@@ -1836,7 +1836,7 @@
 #if 0
         spin_unlock_irqrestore (&ch->ch_txlock, flags);
 #endif
-        return EBUSY;               /* tell user to try again later */
+        return -EBUSY;               /* tell user to try again later */
     }
     /**************************************************/
     /** Put the user data into MUSYCC data buffer(s) **/
diff --git a/drivers/staging/dgrp/Kconfig b/drivers/staging/dgrp/Kconfig
new file mode 100644
index 0000000..39f4bb6
--- /dev/null
+++ b/drivers/staging/dgrp/Kconfig
@@ -0,0 +1,9 @@
+config DGRP
+       tristate "Digi Realport driver"
+       default n
+       depends on SYSFS
+       ---help---
+       Support for Digi Realport devices.  These devices allow you to
+       access remote serial ports as if they are local tty devices.  This
+       will build the kernel driver, you will still need the userspace
+       component to make your Realport device work.
diff --git a/drivers/staging/dgrp/Makefile b/drivers/staging/dgrp/Makefile
new file mode 100644
index 0000000..d9c3b88
--- /dev/null
+++ b/drivers/staging/dgrp/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_DGRP) += dgrp.o
+
+dgrp-y := 			\
+	dgrp_common.o 		\
+	dgrp_dpa_ops.o 		\
+	dgrp_driver.o 		\
+	dgrp_mon_ops.o 	 	\
+	dgrp_net_ops.o 		\
+	dgrp_ports_ops.o 	\
+	dgrp_specproc.o 	\
+	dgrp_tty.o 		\
+	dgrp_sysfs.o
diff --git a/drivers/staging/dgrp/README b/drivers/staging/dgrp/README
new file mode 100644
index 0000000..1d8aaee
--- /dev/null
+++ b/drivers/staging/dgrp/README
@@ -0,0 +1,2 @@
+The user space code to work with this driver is located at
+https://github.com/wfp5p/dgrp-utils
diff --git a/drivers/staging/dgrp/TODO b/drivers/staging/dgrp/TODO
new file mode 100644
index 0000000..3ef2611
--- /dev/null
+++ b/drivers/staging/dgrp/TODO
@@ -0,0 +1,13 @@
+- Use configfs for config stuff.  This will require changes to the
+  user space code.
+
+- dgrp_send() and dgrp_receive() could use some refactoring
+
+- Don't automatically create CHAN_MAX (64) channel array entries for
+  every device as many devices are going to have much less than 64
+  channels.
+
+- The locking needs to be checked.  It seems haphazardly done in most
+  places.
+
+- Check Kconfig dependencies
diff --git a/drivers/staging/dgrp/dgrp_common.c b/drivers/staging/dgrp/dgrp_common.c
new file mode 100644
index 0000000..fce74e7
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_common.c
@@ -0,0 +1,200 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_common.c
+ *
+ *  Description:
+ *
+ *     Definitions of global variables and functions which are either
+ *     shared by the tty, mon, and net drivers; or which cross them
+ *     functionally (like the poller).
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+
+#include "dgrp_common.h"
+
+/**
+ * dgrp_carrier -- check for carrier change state and act
+ * @ch: struct ch_struct *
+ */
+void dgrp_carrier(struct ch_struct *ch)
+{
+	struct nd_struct *nd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+
+	/* fix case when the tty has already closed. */
+
+	if (!ch)
+		return;
+	nd  = ch->ch_nd;
+	if (!nd)
+		return;
+
+	/*
+	 *  If we are currently waiting to determine the status of the port,
+	 *  we don't yet know the state of the modem lines.  As a result,
+	 *  we ignore state changes when we are waiting for the modem lines
+	 *  to be established.  We know, as a result of code in dgrp_net_ops,
+	 *  that we will be called again immediately following the reception
+	 *  of the status message with the true modem status flags in it.
+	 */
+	if (ch->ch_expect & RR_STATUS)
+		return;
+
+	/*
+	 * If CH_HANGUP is set, we gotta keep trying to get all the processes
+	 * that have the port open to close the port.
+	 * So lets just keep sending a hangup every time we get here.
+	 */
+	if ((ch->ch_flag & CH_HANGUP) &&
+	    (ch->ch_tun.un_open_count > 0))
+		tty_hangup(ch->ch_tun.un_tty);
+
+	/*
+	 *  Compute the effective state of both the physical and virtual
+	 *  senses of carrier.
+	 */
+
+	if (ch->ch_s_mlast & DM_CD)
+		phys_carrier = 1;
+
+	if ((ch->ch_s_mlast & DM_CD) ||
+	    (ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+	    (ch->ch_flag & CH_CLOCAL))
+		virt_carrier = 1;
+
+	/*
+	 *  Test for a VIRTUAL carrier transition to HIGH.
+	 *
+	 *  The CH_HANGUP condition is intended to prevent any action
+	 *  except for close.  As a result, we ignore positive carrier
+	 *  transitions during CH_HANGUP.
+	 */
+	if (((ch->ch_flag & CH_HANGUP)  == 0) &&
+	    ((ch->ch_flag & CH_VIRT_CD) == 0) &&
+	    (virt_carrier == 1)) {
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+		nd->nd_tx_work = 1;
+
+		if (waitqueue_active(&ch->ch_flag_wait))
+			wake_up_interruptible(&ch->ch_flag_wait);
+	}
+
+	/*
+	 *  Test for a PHYSICAL transition to low, so long as we aren't
+	 *  currently ignoring physical transitions (which is what "virtual
+	 *  carrier" indicates).
+	 *
+	 *  The transition of the virtual carrier to low really doesn't
+	 *  matter... it really only means "ignore carrier state", not
+	 *  "make pretend that carrier is there".
+	 */
+	if ((virt_carrier == 0) &&
+	    ((ch->ch_flag & CH_PHYS_CD) != 0) &&
+	    (phys_carrier == 0)) {
+		/*
+		 * When carrier drops:
+		 *
+		 *   Do a Hard Hangup if that is called for.
+		 *
+		 *   Drop carrier on all open units.
+		 *
+		 *   Flush queues, waking up any task waiting in the
+		 *   line discipline.
+		 *
+		 *   Send a hangup to the control terminal.
+		 *
+		 *   Enable all select calls.
+		 */
+
+		nd->nd_tx_work = 1;
+
+		ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT);
+
+		if (waitqueue_active(&ch->ch_flag_wait))
+			wake_up_interruptible(&ch->ch_flag_wait);
+
+		if (ch->ch_tun.un_open_count > 0)
+			tty_hangup(ch->ch_tun.un_tty);
+
+		if (ch->ch_pun.un_open_count > 0)
+			tty_hangup(ch->ch_pun.un_tty);
+	}
+
+	/*
+	 *  Make sure that our cached values reflect the current reality.
+	 */
+	if (virt_carrier == 1)
+		ch->ch_flag |= CH_VIRT_CD;
+	else
+		ch->ch_flag &= ~CH_VIRT_CD;
+
+	if (phys_carrier == 1)
+		ch->ch_flag |= CH_PHYS_CD;
+	else
+		ch->ch_flag &= ~CH_PHYS_CD;
+
+}
+
+/**
+ * dgrp_chk_perm() -- check permissions for net device
+ * @inode: pointer to inode structure for the net communication device
+ * @op: operation to be tested
+ *
+ * The file permissions and ownerships are tested to determine whether
+ * the operation "op" is permitted on the file pointed to by the inode.
+ * Returns 0 if the operation is permitted, -EACCESS otherwise
+ */
+int dgrp_chk_perm(int mode, int op)
+{
+	if (!current_euid())
+		mode >>= 6;
+	else if (in_egroup_p(0))
+		mode >>= 3;
+
+	if ((mode & op & 0007) == op)
+		return 0;
+
+	if (capable(CAP_SYS_ADMIN))
+		return 0;
+
+	return -EACCES;
+}
+
+/* dgrp_chk_perm wrapper for permission call in struct inode_operations */
+int dgrp_inode_permission(struct inode *inode, int op)
+{
+	return dgrp_chk_perm(inode->i_mode, op);
+}
diff --git a/drivers/staging/dgrp/dgrp_common.h b/drivers/staging/dgrp/dgrp_common.h
new file mode 100644
index 0000000..05ff338
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_common.h
@@ -0,0 +1,208 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DGRP_COMMON_H
+#define __DGRP_COMMON_H
+
+#define DIGI_VERSION "1.9-29"
+
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include "drp.h"
+
+#define DGRP_TTIME 100
+#define DGRP_RTIME 100
+
+/************************************************************************
+ * All global storage allocation.
+ ************************************************************************/
+
+extern int dgrp_rawreadok;  /* Allow raw writing of input */
+extern int dgrp_register_cudevices; /* enable legacy cu devices */
+extern int dgrp_register_prdevices; /* enable transparent print devices */
+extern int dgrp_poll_tick;          /* Poll interval - in ms */
+
+extern struct list_head nd_struct_list;
+
+struct dgrp_poll_data {
+	spinlock_t poll_lock;
+	struct timer_list timer;
+	int poll_tick;
+	ulong poll_round;	/* Timer rouding factor */
+	long node_active_count;
+};
+
+extern struct dgrp_poll_data dgrp_poll_data;
+extern void dgrp_poll_handler(unsigned long arg);
+
+/* from dgrp_mon_ops.c */
+extern void dgrp_register_mon_hook(struct proc_dir_entry *de);
+
+/* from dgrp_tty.c */
+extern int dgrp_tty_init(struct nd_struct *nd);
+extern void dgrp_tty_uninit(struct nd_struct *nd);
+
+/* from dgrp_ports_ops.c */
+extern void dgrp_register_ports_hook(struct proc_dir_entry *de);
+
+/* from dgrp_net_ops.c */
+extern void dgrp_register_net_hook(struct proc_dir_entry *de);
+
+/* from dgrp_dpa_ops.c */
+extern void dgrp_register_dpa_hook(struct proc_dir_entry *de);
+extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int);
+
+/* from dgrp_sysfs.c */
+extern void dgrp_create_class_sysfs_files(void);
+extern void dgrp_remove_class_sysfs_files(void);
+
+extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd);
+extern void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd);
+
+extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c);
+extern void dgrp_remove_tty_sysfs(struct device *c);
+
+/* from dgrp_specproc.c */
+/*
+ *  The list of DGRP entries with r/w capabilities.  These
+ *  magic numbers are used for identification purposes.
+ */
+enum {
+	DGRP_CONFIG = 1,	/* Configure portservers */
+	DGRP_NETDIR = 2,	/* Directory for "net" devices */
+	DGRP_MONDIR = 3,	/* Directory for "mon" devices */
+	DGRP_PORTSDIR = 4,	/* Directory for "ports" devices */
+	DGRP_INFO = 5,		/* Get info. about the running module */
+	DGRP_NODEINFO = 6,	/* Get info. about the configured nodes */
+	DGRP_DPADIR = 7,	/* Directory for the "dpa" devices */
+};
+
+/*
+ *  Directions for proc handlers
+ */
+enum {
+	INBOUND = 1,		/* Data being written to kernel */
+	OUTBOUND = 2,		/* Data being read from the kernel */
+};
+
+/**
+ * dgrp_proc_entry: structure for dgrp proc dirs
+ * @id: ID number associated with this particular entry.  Should be
+ *    unique across all of DGRP.
+ * @name: text name associated with the /proc entry
+ * @mode: file access permisssions for the /proc entry
+ * @child: pointer to table describing a subdirectory for this entry
+ * @de: pointer to directory entry for this object once registered.  Used
+ *    to grab the handle of the object for unregistration
+ * @excl_sem: semaphore to provide exclusive to struct
+ * @excl_cnt: counter of current accesses
+ *
+ *  Each entry in a DGRP proc directory is described with a
+ *  dgrp_proc_entry structure.  A collection of these
+ *  entries (in an array) represents the members associated
+ *  with a particular /proc directory, and is referred to
+ *  as a table.  All tables are terminated by an entry with
+ *  zeros for every member.
+ */
+struct dgrp_proc_entry {
+	int                  id;          /* Integer identifier */
+	const char        *name;          /* ASCII identifier */
+	mode_t             mode;          /* File access permissions */
+	struct dgrp_proc_entry *child;    /* Child pointer */
+
+	/* file ops to use, pass NULL to use default */
+	struct file_operations *proc_file_ops;
+
+	struct proc_dir_entry *de;        /* proc entry pointer */
+	struct semaphore   excl_sem;      /* Protects exclusive access var */
+	int                excl_cnt;      /* Counts number of curr accesses */
+};
+
+extern void dgrp_unregister_proc(void);
+extern void dgrp_register_proc(void);
+
+/*-----------------------------------------------------------------------*
+ *
+ *  Declarations for common operations:
+ *
+ *      (either used by more than one of net, mon, or tty,
+ *       or in interrupt context (i.e. the poller))
+ *
+ *-----------------------------------------------------------------------*/
+
+void dgrp_carrier(struct ch_struct *ch);
+extern int dgrp_inode_permission(struct inode *inode, int op);
+extern int dgrp_chk_perm(int mode, int op);
+
+
+/*
+ *  ID manipulation macros (where c1 & c2 are characters, i is
+ *  a long integer, and s is a character array of at least three members
+ */
+
+static inline void ID_TO_CHAR(long i, char *s)
+{
+	s[0] = ((i & 0xff00)>>8);
+	s[1] = (i & 0xff);
+	s[2] = 0;
+}
+
+static inline long CHAR_TO_ID(char *s)
+{
+	return ((s[0] & 0xff) << 8) | (s[1] & 0xff);
+}
+
+static inline struct nd_struct *nd_struct_get(long major)
+{
+	struct nd_struct *nd;
+
+	list_for_each_entry(nd, &nd_struct_list, list) {
+		if (major == nd->nd_major)
+			return nd;
+	}
+
+	return NULL;
+}
+
+static inline int nd_struct_add(struct nd_struct *entry)
+{
+	struct nd_struct *ptr;
+
+	ptr = nd_struct_get(entry->nd_major);
+
+	if (ptr)
+		return -EBUSY;
+
+	list_add_tail(&entry->list, &nd_struct_list);
+
+	return 0;
+}
+
+static inline int nd_struct_del(struct nd_struct *entry)
+{
+	struct nd_struct *nd;
+
+	nd = nd_struct_get(entry->nd_major);
+
+	if (!nd)
+		return -ENODEV;
+
+	list_del(&nd->list);
+	return 0;
+}
+
+#endif /* __DGRP_COMMON_H */
diff --git a/drivers/staging/dgrp/dgrp_dpa_ops.c b/drivers/staging/dgrp/dgrp_dpa_ops.c
new file mode 100644
index 0000000..49e6709
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_dpa_ops.c
@@ -0,0 +1,556 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_dpa_ops.c
+ *
+ *  Description:
+ *
+ *     Handle the file operations required for the "dpa" devices.
+ *     Includes those functions required to register the "dpa" devices
+ *     in "/proc".
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/poll.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_dpa_open(struct inode *, struct file *);
+static int dgrp_dpa_release(struct inode *, struct file *);
+static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *);
+static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg);
+static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *);
+
+static const struct file_operations dpa_ops = {
+	.owner   =  THIS_MODULE,
+	.read    =  dgrp_dpa_read,
+	.poll    =  dgrp_dpa_select,
+	.unlocked_ioctl =  dgrp_dpa_ioctl,
+	.open    =  dgrp_dpa_open,
+	.release =  dgrp_dpa_release,
+};
+
+static struct inode_operations dpa_inode_ops = {
+	.permission = dgrp_inode_permission
+};
+
+
+
+struct digi_node {
+	uint	nd_state;		/* Node state: 1 = up, 0 = down. */
+	uint	nd_chan_count;		/* Number of channels found */
+	uint	nd_tx_byte;		/* Tx data count */
+	uint	nd_rx_byte;		/* RX data count */
+	u8	nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */
+};
+
+#define DIGI_GETNODE      (('d'<<8) | 249)	/* get board info */
+
+
+struct digi_chan {
+	uint	ch_port;	/* Port number to get info on */
+	uint	ch_open;	/* 1 if open, 0 if not */
+	uint	ch_txcount;	/* TX data count  */
+	uint	ch_rxcount;	/* RX data count  */
+	uint	ch_s_brate;	/* Realport BRATE */
+	uint	ch_s_estat;	/* Realport ELAST */
+	uint	ch_s_cflag;	/* Realport CFLAG */
+	uint	ch_s_iflag;	/* Realport IFLAG */
+	uint	ch_s_oflag;	/* Realport OFLAG */
+	uint	ch_s_xflag;	/* Realport XFLAG */
+	uint	ch_s_mstat;	/* Realport MLAST */
+};
+
+#define DIGI_GETCHAN      (('d'<<8) | 248)	/* get channel info */
+
+
+struct digi_vpd {
+	int vpd_len;
+	char vpd_data[VPDSIZE];
+};
+
+#define DIGI_GETVPD       (('d'<<8) | 246)	/* get VPD info */
+
+
+struct digi_debug {
+	int onoff;
+	int port;
+};
+
+#define DIGI_SETDEBUG      (('d'<<8) | 247)	/* set debug info */
+
+
+void dgrp_register_dpa_hook(struct proc_dir_entry *de)
+{
+	struct nd_struct *node = de->data;
+
+	de->proc_iops = &dpa_inode_ops;
+	de->proc_fops = &dpa_ops;
+
+	node->nd_dpa_de = de;
+	spin_lock_init(&node->nd_dpa_lock);
+}
+
+/*
+ * dgrp_dpa_open -- open the DPA device for a particular PortServer
+ */
+static int dgrp_dpa_open(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+	int rtn = 0;
+
+	struct proc_dir_entry *de;
+
+	rtn = try_module_get(THIS_MODULE);
+	if (!rtn)
+		return -ENXIO;
+
+	rtn = 0;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		rtn = -EPERM;
+		goto done;
+	}
+
+	/*
+	 *  Make sure that the "private_data" field hasn't already been used.
+	 */
+	if (file->private_data) {
+		rtn = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 *  Get the node pointer, and fail if it doesn't exist.
+	 */
+	de = PDE(inode);
+	if (!de) {
+		rtn = -ENXIO;
+		goto done;
+	}
+	nd = (struct nd_struct *)de->data;
+	if (!nd) {
+		rtn = -ENXIO;
+		goto done;
+	}
+
+	file->private_data = (void *) nd;
+
+	/*
+	 * Allocate the DPA buffer.
+	 */
+
+	if (nd->nd_dpa_buf) {
+		rtn = -EBUSY;
+	} else {
+		nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL);
+
+		if (!nd->nd_dpa_buf) {
+			rtn = -ENOMEM;
+		} else {
+			nd->nd_dpa_out = 0;
+			nd->nd_dpa_in = 0;
+			nd->nd_dpa_lbolt = jiffies;
+		}
+	}
+
+done:
+
+	if (rtn)
+		module_put(THIS_MODULE);
+	return rtn;
+}
+
+/*
+ * dgrp_dpa_release -- close the DPA device for a particular PortServer
+ */
+static int dgrp_dpa_release(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+	u8 *buf;
+	unsigned long lock_flags;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		goto done;
+
+	/*
+	 *  Free the dpa buffer.
+	 */
+
+	spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+	buf = nd->nd_dpa_buf;
+
+	nd->nd_dpa_buf = NULL;
+	nd->nd_dpa_out = nd->nd_dpa_in;
+
+	/*
+	 *  Wakeup any thread waiting for buffer space.
+	 */
+
+	if (nd->nd_dpa_flag & DPA_WAIT_SPACE) {
+		nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
+		wake_up_interruptible(&nd->nd_dpa_wqueue);
+	}
+
+	spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+
+	kfree(buf);
+
+done:
+	module_put(THIS_MODULE);
+	file->private_data = NULL;
+	return 0;
+}
+
+/*
+ * dgrp_dpa_read
+ *
+ * Copy data from the monitoring buffer to the user, freeing space
+ * in the monitoring buffer for more messages
+ */
+static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct nd_struct *nd;
+	int n;
+	int r;
+	int offset = 0;
+	int res = 0;
+	ssize_t rtn;
+	unsigned long lock_flags;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		return -ENXIO;
+
+	/*
+	 *  Wait for some data to appear in the buffer.
+	 */
+
+	spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+	for (;;) {
+		n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
+
+		if (n != 0)
+			break;
+
+		nd->nd_dpa_flag |= DPA_WAIT_DATA;
+
+		spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+
+		/*
+		 * Go to sleep waiting until the condition becomes true.
+		 */
+		rtn = wait_event_interruptible(nd->nd_dpa_wqueue,
+			((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0));
+
+		if (rtn)
+			return rtn;
+
+		spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+	}
+
+	/*
+	 *  Read whatever is there.
+	 */
+
+	if (n > count)
+		n = count;
+
+	res = n;
+
+	r = DPA_MAX - nd->nd_dpa_out;
+
+	if (r <= n) {
+
+		spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+		rtn = copy_to_user((void __user *)buf,
+				   nd->nd_dpa_buf + nd->nd_dpa_out, r);
+		spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+		if (rtn) {
+			rtn = -EFAULT;
+			goto done;
+		}
+
+		nd->nd_dpa_out = 0;
+		n -= r;
+		offset = r;
+	}
+
+	spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+	rtn = copy_to_user((void __user *)buf + offset,
+			   nd->nd_dpa_buf + nd->nd_dpa_out, n);
+	spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+	if (rtn) {
+		rtn = -EFAULT;
+		goto done;
+	}
+
+	nd->nd_dpa_out += n;
+
+	*ppos += res;
+
+	rtn = res;
+
+	/*
+	 *  Wakeup any thread waiting for buffer space.
+	 */
+
+	n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
+
+	if (nd->nd_dpa_flag & DPA_WAIT_SPACE &&
+	    (DPA_MAX - n) > DPA_HIGH_WATER) {
+		nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
+		wake_up_interruptible(&nd->nd_dpa_wqueue);
+	}
+
+ done:
+	spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+	return rtn;
+}
+
+static unsigned int dgrp_dpa_select(struct file *file,
+				    struct poll_table_struct *table)
+{
+	unsigned int retval = 0;
+	struct nd_struct *nd = file->private_data;
+
+	if (nd->nd_dpa_out != nd->nd_dpa_in)
+		retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
+
+	retval |= POLLOUT | POLLWRNORM;        /* Always writeable */
+
+	return retval;
+}
+
+static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+
+	struct nd_struct  *nd;
+	struct digi_chan getchan;
+	struct digi_node getnode;
+	struct ch_struct *ch;
+	struct digi_debug setdebug;
+	struct digi_vpd vpd;
+	unsigned int port;
+	void __user *uarg = (void __user *) arg;
+
+	nd = file->private_data;
+
+	switch (cmd) {
+	case DIGI_GETCHAN:
+		if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan)))
+			return -EFAULT;
+
+		port = getchan.ch_port;
+
+		if (port < 0 || port > nd->nd_chan_count)
+			return -EINVAL;
+
+		ch = nd->nd_chan + port;
+
+		getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0;
+		getchan.ch_txcount = ch->ch_txcount;
+		getchan.ch_rxcount = ch->ch_rxcount;
+		getchan.ch_s_brate = ch->ch_s_brate;
+		getchan.ch_s_estat = ch->ch_s_elast;
+		getchan.ch_s_cflag = ch->ch_s_cflag;
+		getchan.ch_s_iflag = ch->ch_s_iflag;
+		getchan.ch_s_oflag = ch->ch_s_oflag;
+		getchan.ch_s_xflag = ch->ch_s_xflag;
+		getchan.ch_s_mstat = ch->ch_s_mlast;
+
+		if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan)))
+			return -EFAULT;
+		break;
+
+
+	case DIGI_GETNODE:
+		getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0;
+		getnode.nd_chan_count = nd->nd_chan_count;
+		getnode.nd_tx_byte = nd->nd_tx_byte;
+		getnode.nd_rx_byte = nd->nd_rx_byte;
+
+		memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN);
+		strncpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN);
+
+		if (copy_to_user(uarg, &getnode, sizeof(struct digi_node)))
+			return -EFAULT;
+		break;
+
+
+	case DIGI_SETDEBUG:
+		if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug)))
+			return -EFAULT;
+
+		nd->nd_dpa_debug = setdebug.onoff;
+		nd->nd_dpa_port = setdebug.port;
+		break;
+
+
+	case DIGI_GETVPD:
+		if (nd->nd_vpd_len > 0) {
+			vpd.vpd_len = nd->nd_vpd_len;
+			memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len);
+		} else {
+			vpd.vpd_len = 0;
+		}
+
+		if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd)))
+			return -EFAULT;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * dgrp_dpa() -- send data to the device monitor queue
+ * @nd: pointer to a node structure
+ * @buf: buffer of data to copy to the monitoring buffer
+ * @len: number of bytes to transfer to the buffer
+ *
+ * Called by the net device routines to send data to the device
+ * monitor queue.  If the device monitor buffer is too full to
+ * accept the data, it waits until the buffer is ready.
+ */
+static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf)
+{
+	int n;
+	int r;
+	unsigned long lock_flags;
+
+	/*
+	 *  Grab DPA lock.
+	 */
+	spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+	/*
+	 *  Loop while data remains.
+	 */
+	while (nbuf > 0 && nd->nd_dpa_buf != NULL) {
+
+		n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK;
+
+		/*
+		 * Enforce flow control on the DPA device.
+		 */
+		if (n < (DPA_MAX - DPA_HIGH_WATER))
+			nd->nd_dpa_flag |= DPA_WAIT_SPACE;
+
+		/*
+		 * This should never happen, as the flow control above
+		 * should have stopped things before they got to this point.
+		 */
+		if (n == 0) {
+			spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+			return;
+		}
+
+		/*
+		 * Copy as much data as will fit.
+		 */
+
+		if (n > nbuf)
+			n = nbuf;
+
+		r = DPA_MAX - nd->nd_dpa_in;
+
+		if (r <= n) {
+			memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r);
+
+			n -= r;
+
+			nd->nd_dpa_in = 0;
+
+			buf += r;
+			nbuf -= r;
+		}
+
+		memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n);
+
+		nd->nd_dpa_in += n;
+
+		buf += n;
+		nbuf -= n;
+
+		if (nd->nd_dpa_in >= DPA_MAX)
+			pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n",
+					    __func__, nd->nd_dpa_in);
+
+		/*
+		 *  Wakeup any thread waiting for data
+		 */
+		if (nd->nd_dpa_flag & DPA_WAIT_DATA) {
+			nd->nd_dpa_flag &= ~DPA_WAIT_DATA;
+			wake_up_interruptible(&nd->nd_dpa_wqueue);
+		}
+	}
+
+	/*
+	 *  Release the DPA lock.
+	 */
+	spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+}
+
+/**
+ * dgrp_monitor_data() -- builds a DPA data packet
+ * @nd: pointer to a node structure
+ * @type: type of message to be logged in the DPA buffer
+ * @buf: buffer of data to be logged in the DPA buffer
+ * @size -- number of bytes in the "buf" buffer
+ */
+void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size)
+{
+	u8 header[5];
+
+	header[0] = type;
+
+	put_unaligned_be32(size, header + 1);
+
+	dgrp_dpa(nd, header, sizeof(header));
+	dgrp_dpa(nd, buf, size);
+}
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c
new file mode 100644
index 0000000..6e4a0eb
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_driver.c
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 1999-2003 Digi International (www.digi.com)
+ *     Jeff Randall
+ *     James Puzzo  <jamesp at digi dot com>
+ *     Scott Kilau  <Scott_Kilau at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *	Driver specific includes
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ *  PortServer includes
+ */
+#include "dgrp_common.h"
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("RealPort driver for Digi's ethernet-based serial connectivity product line");
+MODULE_VERSION(DIGI_VERSION);
+
+struct list_head nd_struct_list;
+struct dgrp_poll_data dgrp_poll_data;
+
+int dgrp_rawreadok = 1;		/* Bypass flipbuf on input */
+int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */
+int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */
+int dgrp_poll_tick = 20;	/* Poll interval - in ms */
+
+module_param_named(rawreadok, dgrp_rawreadok, int, 0644);
+MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input");
+
+module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644);
+MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices");
+
+module_param_named(register_prdevices, dgrp_register_prdevices, int, 0644);
+MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print devices");
+
+module_param_named(pollrate, dgrp_poll_tick, int, 0644);
+MODULE_PARM_DESC(pollrate, "Poll interval in ms");
+
+/* Driver load/unload functions */
+static int dgrp_init_module(void);
+static void dgrp_cleanup_module(void);
+
+module_init(dgrp_init_module);
+module_exit(dgrp_cleanup_module);
+
+/*
+ * init_module()
+ *
+ * Module load.  This is where it all starts.
+ */
+static int dgrp_init_module(void)
+{
+	INIT_LIST_HEAD(&nd_struct_list);
+
+	spin_lock_init(&dgrp_poll_data.poll_lock);
+	init_timer(&dgrp_poll_data.timer);
+	dgrp_poll_data.poll_tick = dgrp_poll_tick;
+	dgrp_poll_data.timer.function = dgrp_poll_handler;
+	dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data;
+
+	dgrp_create_class_sysfs_files();
+
+	dgrp_register_proc();
+
+	return 0;
+}
+
+
+/*
+ *	Module unload.  This is where it all ends.
+ */
+static void dgrp_cleanup_module(void)
+{
+	struct nd_struct *nd, *next;
+
+	/*
+	 *	Attempting to free resources in backwards
+	 *	order of allocation, in case that helps
+	 *	memory pool fragmentation.
+	 */
+	dgrp_unregister_proc();
+
+	dgrp_remove_class_sysfs_files();
+
+
+	list_for_each_entry_safe(nd, next, &nd_struct_list, list) {
+		dgrp_tty_uninit(nd);
+		kfree(nd);
+	}
+}
diff --git a/drivers/staging/dgrp/dgrp_mon_ops.c b/drivers/staging/dgrp/dgrp_mon_ops.c
new file mode 100644
index 0000000..268dcb9
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_mon_ops.c
@@ -0,0 +1,346 @@
+/*****************************************************************************
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_mon_ops.c
+ *
+ *  Description:
+ *
+ *     Handle the file operations required for the "monitor" devices.
+ *     Includes those functions required to register the "mon" devices
+ *     in "/proc".
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <asm/unaligned.h>
+#include <linux/proc_fs.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_mon_open(struct inode *, struct file *);
+static int dgrp_mon_release(struct inode *, struct file *);
+static ssize_t dgrp_mon_read(struct file *, char __user *, size_t, loff_t *);
+static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg);
+
+static const struct file_operations mon_ops = {
+	.owner   = THIS_MODULE,
+	.read    = dgrp_mon_read,
+	.unlocked_ioctl = dgrp_mon_ioctl,
+	.open    = dgrp_mon_open,
+	.release = dgrp_mon_release,
+};
+
+static struct inode_operations mon_inode_ops = {
+	.permission = dgrp_inode_permission
+};
+
+void dgrp_register_mon_hook(struct proc_dir_entry *de)
+{
+	struct nd_struct *node = de->data;
+
+	de->proc_iops = &mon_inode_ops;
+	de->proc_fops = &mon_ops;
+	node->nd_mon_de = de;
+	sema_init(&node->nd_mon_semaphore, 1);
+}
+
+/**
+ * dgrp_mon_open() -- open /proc/dgrp/ports device for a PortServer
+ * @inode: struct inode *
+ * @file: struct file *
+ *
+ * Open function to open the /proc/dgrp/ports device for a PortServer.
+ */
+static int dgrp_mon_open(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+	struct proc_dir_entry *de;
+	struct timeval tv;
+	uint32_t time;
+	u8 *buf;
+	int rtn;
+
+	rtn = try_module_get(THIS_MODULE);
+	if (!rtn)
+		return -ENXIO;
+
+	rtn = 0;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		rtn = -EPERM;
+		goto done;
+	}
+
+	/*
+	 *  Make sure that the "private_data" field hasn't already been used.
+	 */
+	if (file->private_data) {
+		rtn = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 *  Get the node pointer, and fail if it doesn't exist.
+	 */
+	de = PDE(inode);
+	if (!de) {
+		rtn = -ENXIO;
+		goto done;
+	}
+
+	nd = (struct nd_struct *)de->data;
+	if (!nd) {
+		rtn = -ENXIO;
+		goto done;
+	}
+
+	file->private_data = (void *) nd;
+
+	/*
+	 * Allocate the monitor buffer.
+	 */
+
+	/*
+	 *  Grab the MON lock.
+	 */
+	down(&nd->nd_mon_semaphore);
+
+	if (nd->nd_mon_buf) {
+		rtn = -EBUSY;
+		goto done_up;
+	}
+
+	nd->nd_mon_buf = kmalloc(MON_MAX, GFP_KERNEL);
+
+	if (!nd->nd_mon_buf) {
+		rtn = -ENOMEM;
+		goto done_up;
+	}
+
+	/*
+	 *  Enter an RPDUMP file header into the buffer.
+	 */
+
+	buf = nd->nd_mon_buf;
+
+	strcpy(buf, RPDUMP_MAGIC);
+	buf += strlen(buf) + 1;
+
+	do_gettimeofday(&tv);
+
+	/*
+	 *  tv.tv_sec might be a 64 bit quantity.  Pare
+	 *  it down to 32 bits before attempting to encode
+	 *  it.
+	 */
+	time = (uint32_t) (tv.tv_sec & 0xffffffff);
+
+	put_unaligned_be32(time, buf);
+	put_unaligned_be16(0, buf + 4);
+	buf += 6;
+
+	if (nd->nd_tx_module) {
+		buf[0] = RPDUMP_CLIENT;
+		put_unaligned_be32(0, buf + 1);
+		put_unaligned_be16(1, buf + 5);
+		buf[7] = 0xf0 + nd->nd_tx_module;
+		buf += 8;
+	}
+
+	if (nd->nd_rx_module) {
+		buf[0] = RPDUMP_SERVER;
+		put_unaligned_be32(0, buf + 1);
+		put_unaligned_be16(1, buf + 5);
+		buf[7] = 0xf0 + nd->nd_rx_module;
+		buf += 8;
+	}
+
+	nd->nd_mon_out = 0;
+	nd->nd_mon_in  = buf - nd->nd_mon_buf;
+	nd->nd_mon_lbolt = jiffies;
+
+done_up:
+	up(&nd->nd_mon_semaphore);
+
+done:
+	if (rtn)
+		module_put(THIS_MODULE);
+	return rtn;
+}
+
+
+/**
+ * dgrp_mon_release() - Close the MON device for a particular PortServer
+ * @inode: struct inode *
+ * @file: struct file *
+ */
+static int dgrp_mon_release(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		goto done;
+
+	/*
+	 *  Free the monitor buffer.
+	 */
+
+	down(&nd->nd_mon_semaphore);
+
+	kfree(nd->nd_mon_buf);
+	nd->nd_mon_buf = NULL;
+	nd->nd_mon_out = nd->nd_mon_in;
+
+	/*
+	 *  Wakeup any thread waiting for buffer space.
+	 */
+
+	if (nd->nd_mon_flag & MON_WAIT_SPACE) {
+		nd->nd_mon_flag &= ~MON_WAIT_SPACE;
+		wake_up_interruptible(&nd->nd_mon_wqueue);
+	}
+
+	up(&nd->nd_mon_semaphore);
+
+	/*
+	 *  Make sure there is no thread in the middle of writing a packet.
+	 */
+	down(&nd->nd_net_semaphore);
+	up(&nd->nd_net_semaphore);
+
+done:
+	module_put(THIS_MODULE);
+	file->private_data = NULL;
+	return 0;
+}
+
+/**
+ * dgrp_mon_read() -- Copy data from the monitoring buffer to the user
+ */
+static ssize_t dgrp_mon_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct nd_struct *nd;
+	int r;
+	int offset = 0;
+	int res = 0;
+	ssize_t rtn;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		return -ENXIO;
+
+	/*
+	 *  Wait for some data to appear in the buffer.
+	 */
+
+	down(&nd->nd_mon_semaphore);
+
+	for (;;) {
+		res = (nd->nd_mon_in - nd->nd_mon_out) & MON_MASK;
+
+		if (res)
+			break;
+
+		nd->nd_mon_flag |= MON_WAIT_DATA;
+
+		up(&nd->nd_mon_semaphore);
+
+		/*
+		 * Go to sleep waiting until the condition becomes true.
+		 */
+		rtn = wait_event_interruptible(nd->nd_mon_wqueue,
+					       ((nd->nd_mon_flag & MON_WAIT_DATA) == 0));
+
+		if (rtn)
+			return rtn;
+
+		down(&nd->nd_mon_semaphore);
+	}
+
+	/*
+	 *  Read whatever is there.
+	 */
+
+	if (res > count)
+		res = count;
+
+	r = MON_MAX - nd->nd_mon_out;
+
+	if (r <= res) {
+		rtn = copy_to_user((void __user *)buf,
+				   nd->nd_mon_buf + nd->nd_mon_out, r);
+		if (rtn) {
+			up(&nd->nd_mon_semaphore);
+			return -EFAULT;
+		}
+
+		nd->nd_mon_out = 0;
+		res -= r;
+		offset = r;
+	}
+
+	rtn = copy_to_user((void __user *) buf + offset,
+			   nd->nd_mon_buf + nd->nd_mon_out, res);
+	if (rtn) {
+		up(&nd->nd_mon_semaphore);
+		return -EFAULT;
+	}
+
+	nd->nd_mon_out += res;
+
+	*ppos += res;
+
+	up(&nd->nd_mon_semaphore);
+
+	/*
+	 *  Wakeup any thread waiting for buffer space.
+	 */
+
+	if (nd->nd_mon_flag & MON_WAIT_SPACE) {
+		nd->nd_mon_flag &= ~MON_WAIT_SPACE;
+		wake_up_interruptible(&nd->nd_mon_wqueue);
+	}
+
+	return res;
+}
+
+/*  ioctl is not valid on monitor device */
+static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	return -EINVAL;
+}
diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c
new file mode 100644
index 0000000..ab839ea
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_net_ops.c
@@ -0,0 +1,3737 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo  <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_net_ops.c
+ *
+ *  Description:
+ *
+ *     Handle the file operations required for the "network" devices.
+ *     Includes those functions required to register the "net" devices
+ *     in "/proc".
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+
+#define MYFLIPLEN	TBUF_MAX
+
+#include "dgrp_common.h"
+
+#define TTY_FLIPBUF_SIZE 512
+#define DEVICE_NAME_SIZE 50
+
+/*
+ *  Generic helper function declarations
+ */
+static void   parity_scan(struct ch_struct *ch, unsigned char *cbuf,
+				unsigned char *fbuf, int *len);
+
+/*
+ *  File operation declarations
+ */
+static int dgrp_net_open(struct inode *, struct file *);
+static int dgrp_net_release(struct inode *, struct file *);
+static ssize_t dgrp_net_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t dgrp_net_write(struct file *, const char __user *, size_t,
+			      loff_t *);
+static long dgrp_net_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg);
+static unsigned int dgrp_net_select(struct file *file,
+				    struct poll_table_struct *table);
+
+static const struct file_operations net_ops = {
+	.owner   =  THIS_MODULE,
+	.read    =  dgrp_net_read,
+	.write   =  dgrp_net_write,
+	.poll    =  dgrp_net_select,
+	.unlocked_ioctl =  dgrp_net_ioctl,
+	.open    =  dgrp_net_open,
+	.release =  dgrp_net_release,
+};
+
+static struct inode_operations net_inode_ops = {
+	.permission = dgrp_inode_permission
+};
+
+void dgrp_register_net_hook(struct proc_dir_entry *de)
+{
+	struct nd_struct *node = de->data;
+
+	de->proc_iops = &net_inode_ops;
+	de->proc_fops = &net_ops;
+	node->nd_net_de = de;
+	sema_init(&node->nd_net_semaphore, 1);
+	node->nd_state = NS_CLOSED;
+	dgrp_create_node_class_sysfs_files(node);
+}
+
+
+/**
+ * dgrp_dump() -- prints memory for debugging purposes.
+ * @mem: Memory location which should be printed to the console
+ * @len: Number of bytes to be dumped
+ */
+static void dgrp_dump(u8 *mem, int len)
+{
+	int i;
+
+	pr_debug("dgrp dump length = %d, data = ", len);
+	for (i = 0; i < len; ++i)
+		pr_debug("%.2x ", mem[i]);
+	pr_debug("\n");
+}
+
+/**
+ * dgrp_read_data_block() -- Read a data block
+ * @ch: struct ch_struct *
+ * @flipbuf: u8 *
+ * @flipbuf_size: size of flipbuf
+ */
+static void dgrp_read_data_block(struct ch_struct *ch, u8 *flipbuf,
+				 int flipbuf_size)
+{
+	int t;
+	int n;
+
+	if (flipbuf_size <= 0)
+		return;
+
+	t = RBUF_MAX - ch->ch_rout;
+	n = flipbuf_size;
+
+	if (n >= t) {
+		memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, t);
+		flipbuf += t;
+		n -= t;
+		ch->ch_rout = 0;
+	}
+
+	memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, n);
+	flipbuf += n;
+	ch->ch_rout += n;
+}
+
+
+/**
+ * dgrp_input() -- send data to the line disipline
+ * @ch: pointer to channel struct
+ *
+ * Copys the rbuf to the flipbuf and sends to line discipline.
+ * Sends input buffer data to the line discipline.
+ *
+ * There are several modes to consider here:
+ *    rawreadok, tty->real_raw, and IF_PARMRK
+ */
+static void dgrp_input(struct ch_struct *ch)
+{
+	struct nd_struct *nd;
+	struct tty_struct *tty;
+	int remain;
+	int data_len;
+	int len;
+	int flip_len;
+	int tty_count;
+	ulong lock_flags;
+	struct tty_ldisc *ld;
+	u8  *myflipbuf;
+	u8  *myflipflagbuf;
+
+	if (!ch)
+		return;
+
+	nd = ch->ch_nd;
+
+	if (!nd)
+		return;
+
+	spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+	myflipbuf = nd->nd_inputbuf;
+	myflipflagbuf = nd->nd_inputflagbuf;
+
+	if (!ch->ch_open_count) {
+		ch->ch_rout = ch->ch_rin;
+		goto out;
+	}
+
+	if (ch->ch_tun.un_flag & UN_CLOSING) {
+		ch->ch_rout = ch->ch_rin;
+		goto out;
+	}
+
+	tty = (ch->ch_tun).un_tty;
+
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		ch->ch_rout = ch->ch_rin;
+		goto out;
+	}
+
+	tty_count = tty->count;
+	if (!tty_count) {
+		ch->ch_rout = ch->ch_rin;
+		goto out;
+	}
+
+	if (tty->closing || test_bit(TTY_CLOSING, &tty->flags)) {
+		ch->ch_rout = ch->ch_rin;
+		goto out;
+	}
+
+	spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+	/* Decide how much data we can send into the tty layer */
+	if (dgrp_rawreadok && tty->real_raw)
+		flip_len = MYFLIPLEN;
+	else
+		flip_len = TTY_FLIPBUF_SIZE;
+
+	/* data_len should be the number of chars that we read in */
+	data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK;
+	remain = data_len;
+
+	/* len is the amount of data we are going to transfer here */
+	len = min(data_len, flip_len);
+
+	/* take into consideration length of ldisc */
+	len = min(len, (N_TTY_BUF_SIZE - 1) - tty->read_cnt);
+
+	ld = tty_ldisc_ref(tty);
+
+	/*
+	 * If we were unable to get a reference to the ld,
+	 * don't flush our buffer, and act like the ld doesn't
+	 * have any space to put the data right now.
+	 */
+	if (!ld) {
+		len = 0;
+	} else if (!ld->ops->receive_buf) {
+		spin_lock_irqsave(&nd->nd_lock, lock_flags);
+		ch->ch_rout = ch->ch_rin;
+		spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+		len = 0;
+	}
+
+	/* Check DPA flow control */
+	if ((nd->nd_dpa_debug) &&
+	    (nd->nd_dpa_flag & DPA_WAIT_SPACE) &&
+	    (nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))))
+		len = 0;
+
+	if ((len) && !(ch->ch_flag & CH_RXSTOP)) {
+
+		dgrp_read_data_block(ch, myflipbuf, len);
+
+		/*
+		 * In high performance mode, we don't have to update
+		 * flag_buf or any of the counts or pointers into flip buf.
+		 */
+		if (!dgrp_rawreadok || !tty->real_raw) {
+			if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty))
+				parity_scan(ch, myflipbuf, myflipflagbuf, &len);
+			else
+				memset(myflipflagbuf, TTY_NORMAL, len);
+		}
+
+		if ((nd->nd_dpa_debug) &&
+		    (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty)))))
+			dgrp_dpa_data(nd, 1, myflipbuf, len);
+
+		/*
+		 * If we're doing raw reads, jam it right into the
+		 * line disc bypassing the flip buffers.
+		 */
+		if (dgrp_rawreadok && tty->real_raw)
+			ld->ops->receive_buf(tty, myflipbuf, NULL, len);
+		else {
+			len = tty_buffer_request_room(tty, len);
+			tty_insert_flip_string_flags(tty, myflipbuf,
+						     myflipflagbuf, len);
+
+			/* Tell the tty layer its okay to "eat" the data now */
+			tty_flip_buffer_push(tty);
+		}
+
+		ch->ch_rxcount += len;
+	}
+
+	if (ld)
+		tty_ldisc_deref(ld);
+
+	/*
+	 * Wake up any sleepers (maybe dgrp close) that might be waiting
+	 * for a channel flag state change.
+	 */
+	wake_up_interruptible(&ch->ch_flag_wait);
+	return;
+
+out:
+	spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+}
+
+
+/*
+ *  parity_scan
+ *
+ *  Loop to inspect each single character or 0xFF escape.
+ *
+ *  if PARMRK & ~DOSMODE:
+ *     0xFF  0xFF           Normal 0xFF character, escaped
+ *                          to eliminate confusion.
+ *     0xFF  0x00  0x00     Break
+ *     0xFF  0x00  CC       Error character CC.
+ *     CC                   Normal character CC.
+ *
+ *  if PARMRK & DOSMODE:
+ *     0xFF  0x18  0x00     Break
+ *     0xFF  0x08  0x00     Framing Error
+ *     0xFF  0x04  0x00     Parity error
+ *     0xFF  0x0C  0x00     Both Framing and Parity error
+ *
+ *  TODO:  do we need to do the XMODEM, XOFF, XON, XANY processing??
+ *         as per protocol
+ */
+static void parity_scan(struct ch_struct *ch, unsigned char *cbuf,
+			unsigned char *fbuf, int *len)
+{
+	int l = *len;
+	int count = 0;
+	int DOS = ((ch->ch_iflag & IF_DOSMODE) == 0 ? 0 : 1);
+	unsigned char *cout; /* character buffer */
+	unsigned char *fout; /* flag buffer */
+	unsigned char *in;
+	unsigned char c;
+
+	in = cbuf;
+	cout = cbuf;
+	fout = fbuf;
+
+	while (l--) {
+		c = *in;
+		in++;
+
+		switch (ch->ch_pscan_state) {
+		default:
+			/* reset to sanity and fall through */
+			ch->ch_pscan_state = 0 ;
+
+		case 0:
+			/* No FF seen yet */
+			if (c == 0xff) /* delete this character from stream */
+				ch->ch_pscan_state = 1;
+			else {
+				*cout++ = c;
+				*fout++ = TTY_NORMAL;
+				count += 1;
+			}
+			break;
+
+		case 1:
+			/* first FF seen */
+			if (c == 0xff) {
+				/* doubled ff, transform to single ff */
+				*cout++ = c;
+				*fout++ = TTY_NORMAL;
+				count += 1;
+				ch->ch_pscan_state = 0;
+			} else {
+				/* save value examination in next state */
+				ch->ch_pscan_savechar = c;
+				ch->ch_pscan_state = 2;
+			}
+			break;
+
+		case 2:
+			/* third character of ff sequence */
+			*cout++ = c;
+			if (DOS) {
+				if (ch->ch_pscan_savechar & 0x10)
+					*fout++ = TTY_BREAK;
+				else if (ch->ch_pscan_savechar & 0x08)
+					*fout++ = TTY_FRAME;
+				else
+					/*
+					 * either marked as a parity error,
+					 * indeterminate, or not in DOSMODE
+					 * call it a parity error
+					 */
+					*fout++ = TTY_PARITY;
+			} else {
+				/* case FF XX ?? where XX is not 00 */
+				if (ch->ch_pscan_savechar & 0xff) {
+					/* this should not happen */
+					pr_info("%s: parity_scan: error unexpected byte\n",
+						__func__);
+					*fout++ = TTY_PARITY;
+				}
+				/* case FF 00 XX where XX is not 00 */
+				else if (c == 0xff)
+					*fout++ = TTY_PARITY;
+				/* case FF 00 00 */
+				else
+					*fout++ = TTY_BREAK;
+
+			}
+			count += 1;
+			ch->ch_pscan_state = 0;
+		}
+	}
+	*len = count;
+}
+
+
+/**
+ * dgrp_net_idle() -- Idle the network connection
+ * @nd: pointer to node structure to idle
+ */
+static void dgrp_net_idle(struct nd_struct *nd)
+{
+	struct ch_struct *ch;
+	int i;
+
+	nd->nd_tx_work = 1;
+
+	nd->nd_state = NS_IDLE;
+	nd->nd_flag = 0;
+
+	for (i = nd->nd_seq_out; ; i = (i + 1) & SEQ_MASK) {
+		if (!nd->nd_seq_wait[i]) {
+			nd->nd_seq_wait[i] = 0;
+			wake_up_interruptible(&nd->nd_seq_wque[i]);
+		}
+
+		if (i == nd->nd_seq_in)
+			break;
+	}
+
+	nd->nd_seq_out = nd->nd_seq_in;
+
+	nd->nd_unack = 0;
+	nd->nd_remain = 0;
+
+	nd->nd_tx_module = 0x10;
+	nd->nd_rx_module = 0x00;
+
+	for (i = 0, ch = nd->nd_chan; i < CHAN_MAX; i++, ch++) {
+		ch->ch_state = CS_IDLE;
+
+		ch->ch_otype = 0;
+		ch->ch_otype_waiting = 0;
+	}
+}
+
+/*
+ *  Increase the number of channels, waking up any
+ *  threads that might be waiting for the channels
+ *  to appear.
+ */
+static void increase_channel_count(struct nd_struct *nd, int n)
+{
+	struct ch_struct *ch;
+	struct device *classp;
+	char name[DEVICE_NAME_SIZE];
+	int ret;
+	u8 *buf;
+	int i;
+
+	for (i = nd->nd_chan_count; i < n; ++i) {
+		ch = nd->nd_chan + i;
+
+		/* FIXME: return a useful error instead! */
+		buf = kmalloc(TBUF_MAX, GFP_KERNEL);
+		if (!buf)
+			return;
+
+		if (ch->ch_tbuf)
+			pr_info_ratelimited("%s - ch_tbuf was not NULL\n",
+					    __func__);
+
+		ch->ch_tbuf = buf;
+
+		buf = kmalloc(RBUF_MAX, GFP_KERNEL);
+		if (!buf)
+			return;
+
+		if (ch->ch_rbuf)
+			pr_info("%s - ch_rbuf was not NULL\n",
+				__func__);
+		ch->ch_rbuf = buf;
+
+		classp = tty_port_register_device(&ch->port,
+						  nd->nd_serial_ttdriver, i,
+						  NULL);
+
+		ch->ch_tun.un_sysfs = classp;
+		snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i);
+
+		dgrp_create_tty_sysfs(&ch->ch_tun, classp);
+		ret = sysfs_create_link(&nd->nd_class_dev->kobj,
+					&classp->kobj, name);
+
+		/* NOTE: We don't support "cu" devices anymore,
+		 * so you will notice we don't register them
+		 * here anymore. */
+		if (dgrp_register_prdevices) {
+			classp = tty_register_device(nd->nd_xprint_ttdriver,
+						     i, NULL);
+			ch->ch_pun.un_sysfs = classp;
+			snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i);
+
+			dgrp_create_tty_sysfs(&ch->ch_pun, classp);
+			ret = sysfs_create_link(&nd->nd_class_dev->kobj,
+						&classp->kobj, name);
+		}
+
+		nd->nd_chan_count = i + 1;
+		wake_up_interruptible(&ch->ch_flag_wait);
+	}
+}
+
+/*
+ * Decrease the number of channels, and wake up any threads that might
+ * be waiting on the channels that vanished.
+ */
+static void decrease_channel_count(struct nd_struct *nd, int n)
+{
+	struct ch_struct *ch;
+	char name[DEVICE_NAME_SIZE];
+	int i;
+
+	for (i = nd->nd_chan_count - 1; i >= n; --i) {
+		ch = nd->nd_chan + i;
+
+		/*
+		 *  Make any open ports inoperative.
+		 */
+		ch->ch_state = CS_IDLE;
+
+		ch->ch_otype = 0;
+		ch->ch_otype_waiting = 0;
+
+		/*
+		 *  Only "HANGUP" if we care about carrier
+		 *  transitions and we are already open.
+		 */
+		if (ch->ch_open_count != 0) {
+			ch->ch_flag |= CH_HANGUP;
+			dgrp_carrier(ch);
+		}
+
+		/*
+		 * Unlike the CH_HANGUP flag above, use another
+		 * flag to indicate to the RealPort state machine
+		 * that this port has disappeared.
+		 */
+		if (ch->ch_open_count != 0)
+			ch->ch_flag |= CH_PORT_GONE;
+
+		wake_up_interruptible(&ch->ch_flag_wait);
+
+		nd->nd_chan_count = i;
+
+		kfree(ch->ch_tbuf);
+		ch->ch_tbuf = NULL;
+
+		kfree(ch->ch_rbuf);
+		ch->ch_rbuf = NULL;
+
+		nd->nd_chan_count = i;
+
+		dgrp_remove_tty_sysfs(ch->ch_tun.un_sysfs);
+		snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i);
+		sysfs_remove_link(&nd->nd_class_dev->kobj, name);
+		tty_unregister_device(nd->nd_serial_ttdriver, i);
+
+		/*
+		 * NOTE: We don't support "cu" devices anymore, so don't
+		 * unregister them here anymore.
+		 */
+
+		if (dgrp_register_prdevices) {
+			dgrp_remove_tty_sysfs(ch->ch_pun.un_sysfs);
+			snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i);
+			sysfs_remove_link(&nd->nd_class_dev->kobj, name);
+			tty_unregister_device(nd->nd_xprint_ttdriver, i);
+		}
+	}
+}
+
+/**
+ * dgrp_chan_count() -- Adjust the node channel count.
+ * @nd: pointer to a node structure
+ * @n: new value for channel count
+ *
+ * Adjusts the node channel count.  If new ports have appeared, it tries
+ * to signal those processes that might have been waiting for ports to
+ * appear.  If ports have disappeared it tries to signal those processes
+ * that might be hung waiting for a response for the now non-existant port.
+ */
+static void dgrp_chan_count(struct nd_struct *nd, int n)
+{
+	if (n == nd->nd_chan_count)
+		return;
+
+	if (n > nd->nd_chan_count)
+		increase_channel_count(nd, n);
+
+	if (n < nd->nd_chan_count)
+		decrease_channel_count(nd, n);
+}
+
+/**
+ * dgrp_monitor() -- send data to the device monitor queue
+ * @nd: pointer to a node structure
+ * @buf: data to copy to the monitoring buffer
+ * @len: number of bytes to transfer to the buffer
+ *
+ * Called by the net device routines to send data to the device
+ * monitor queue.  If the device monitor buffer is too full to
+ * accept the data, it waits until the buffer is ready.
+ */
+static void dgrp_monitor(struct nd_struct *nd, u8 *buf, int len)
+{
+	int n;
+	int r;
+	int rtn;
+
+	/*
+	 *  Grab monitor lock.
+	 */
+	down(&nd->nd_mon_semaphore);
+
+	/*
+	 *  Loop while data remains.
+	 */
+	while ((len > 0) && (nd->nd_mon_buf)) {
+		/*
+		 *  Determine the amount of available space left in the
+		 *  buffer.  If there's none, wait until some appears.
+		 */
+
+		n = (nd->nd_mon_out - nd->nd_mon_in - 1) & MON_MASK;
+
+		if (!n) {
+			nd->nd_mon_flag |= MON_WAIT_SPACE;
+
+			up(&nd->nd_mon_semaphore);
+
+			/*
+			 * Go to sleep waiting until the condition becomes true.
+			 */
+			rtn = wait_event_interruptible(nd->nd_mon_wqueue,
+						       ((nd->nd_mon_flag & MON_WAIT_SPACE) == 0));
+
+/* FIXME: really ignore rtn? */
+
+			/*
+			 *  We can't exit here if we receive a signal, since
+			 *  to do so would trash the debug stream.
+			 */
+
+			down(&nd->nd_mon_semaphore);
+
+			continue;
+		}
+
+		/*
+		 * Copy as much data as will fit.
+		 */
+
+		if (n > len)
+			n = len;
+
+		r = MON_MAX - nd->nd_mon_in;
+
+		if (r <= n) {
+			memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, r);
+
+			n -= r;
+
+			nd->nd_mon_in = 0;
+
+			buf += r;
+			len -= r;
+		}
+
+		memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, n);
+
+		nd->nd_mon_in += n;
+
+		buf += n;
+		len -= n;
+
+		if (nd->nd_mon_in >= MON_MAX)
+			pr_info_ratelimited("%s - nd_mon_in (%i) >= MON_MAX\n",
+					    __func__, nd->nd_mon_in);
+
+		/*
+		 *  Wakeup any thread waiting for data
+		 */
+
+		if (nd->nd_mon_flag & MON_WAIT_DATA) {
+			nd->nd_mon_flag &= ~MON_WAIT_DATA;
+			wake_up_interruptible(&nd->nd_mon_wqueue);
+		}
+	}
+
+	/*
+	 *  Release the monitor lock.
+	 */
+	up(&nd->nd_mon_semaphore);
+}
+
+/**
+ * dgrp_encode_time() -- Encodes rpdump time into a 4-byte quantity.
+ * @nd: pointer to a node structure
+ * @buf: destination buffer
+ *
+ * Encodes "rpdump" time into a 4-byte quantity.  Time is measured since
+ * open.
+ */
+static void dgrp_encode_time(struct nd_struct *nd, u8 *buf)
+{
+	ulong t;
+
+	/*
+	 *  Convert time in HZ since open to time in milliseconds
+	 *  since open.
+	 */
+	t = jiffies - nd->nd_mon_lbolt;
+	t = 1000 * (t / HZ) + 1000 * (t % HZ) / HZ;
+
+	put_unaligned_be32((uint)(t & 0xffffffff), buf);
+}
+
+
+
+/**
+ * dgrp_monitor_message() -- Builds a rpdump style message.
+ * @nd: pointer to a node structure
+ * @message: destination buffer
+ */
+static void dgrp_monitor_message(struct nd_struct *nd, char *message)
+{
+	u8 header[7];
+	int n;
+
+	header[0] = RPDUMP_MESSAGE;
+
+	dgrp_encode_time(nd, header + 1);
+
+	n = strlen(message);
+
+	put_unaligned_be16(n, header + 5);
+
+	dgrp_monitor(nd, header, sizeof(header));
+	dgrp_monitor(nd, (u8 *) message, n);
+}
+
+
+
+/**
+ * dgrp_monitor_reset() -- Note a reset in the monitoring buffer.
+ * @nd: pointer to a node structure
+ */
+static void dgrp_monitor_reset(struct nd_struct *nd)
+{
+	u8 header[5];
+
+	header[0] = RPDUMP_RESET;
+
+	dgrp_encode_time(nd, header + 1);
+
+	dgrp_monitor(nd, header, sizeof(header));
+}
+
+/**
+ * dgrp_monitor_data() -- builds a monitor data packet
+ * @nd: pointer to a node structure
+ * @type: type of message to be logged
+ * @buf: data to be logged
+ * @size: number of bytes in the buffer
+ */
+static void dgrp_monitor_data(struct nd_struct *nd, u8 type, u8 *buf, int size)
+{
+	u8 header[7];
+
+	header[0] = type;
+
+	dgrp_encode_time(nd, header + 1);
+
+	put_unaligned_be16(size, header + 5);
+
+	dgrp_monitor(nd, header, sizeof(header));
+	dgrp_monitor(nd, buf, size);
+}
+
+static int alloc_nd_buffers(struct nd_struct *nd)
+{
+
+	nd->nd_iobuf = NULL;
+	nd->nd_writebuf = NULL;
+	nd->nd_inputbuf = NULL;
+	nd->nd_inputflagbuf = NULL;
+
+	/*
+	 *  Allocate the network read/write buffer.
+	 */
+	nd->nd_iobuf = kzalloc(UIO_MAX + 10, GFP_KERNEL);
+	if (!nd->nd_iobuf)
+		goto out_err;
+
+	/*
+	 * Allocate a buffer for doing the copy from user space to
+	 * kernel space in the write routines.
+	 */
+	nd->nd_writebuf = kzalloc(WRITEBUFLEN, GFP_KERNEL);
+	if (!nd->nd_writebuf)
+		goto out_err;
+
+	/*
+	 * Allocate a buffer for doing the copy from kernel space to
+	 * tty buffer space in the read routines.
+	 */
+	nd->nd_inputbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+	if (!nd->nd_inputbuf)
+		goto out_err;
+
+	/*
+	 * Allocate a buffer for doing the copy from kernel space to
+	 * tty buffer space in the read routines.
+	 */
+	nd->nd_inputflagbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+	if (!nd->nd_inputflagbuf)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	kfree(nd->nd_iobuf);
+	kfree(nd->nd_writebuf);
+	kfree(nd->nd_inputbuf);
+	kfree(nd->nd_inputflagbuf);
+	return -ENOMEM;
+}
+
+/*
+ * dgrp_net_open() -- Open the NET device for a particular PortServer
+ */
+static int dgrp_net_open(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+	struct proc_dir_entry *de;
+	ulong  lock_flags;
+	int rtn;
+
+	rtn = try_module_get(THIS_MODULE);
+	if (!rtn)
+		return -EAGAIN;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		rtn = -EPERM;
+		goto done;
+	}
+
+	/*
+	 *  Make sure that the "private_data" field hasn't already been used.
+	 */
+	if (file->private_data) {
+		rtn = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 *  Get the node pointer, and fail if it doesn't exist.
+	 */
+	de = PDE(inode);
+	if (!de) {
+		rtn = -ENXIO;
+		goto done;
+	}
+
+	nd = (struct nd_struct *) de->data;
+	if (!nd) {
+		rtn = -ENXIO;
+		goto done;
+	}
+
+	file->private_data = (void *) nd;
+
+	/*
+	 *  Grab the NET lock.
+	 */
+	down(&nd->nd_net_semaphore);
+
+	if (nd->nd_state != NS_CLOSED) {
+		rtn = -EBUSY;
+		goto unlock;
+	}
+
+	/*
+	 *  Initialize the link speed parameters.
+	 */
+
+	nd->nd_link.lk_fast_rate = UIO_MAX;
+	nd->nd_link.lk_slow_rate = UIO_MAX;
+
+	nd->nd_link.lk_fast_delay = 1000;
+	nd->nd_link.lk_slow_delay = 1000;
+
+	nd->nd_link.lk_header_size = 46;
+
+
+	rtn = alloc_nd_buffers(nd);
+	if (rtn)
+		goto unlock;
+
+	/*
+	 *  The port is now open, so move it to the IDLE state
+	 */
+	dgrp_net_idle(nd);
+
+	nd->nd_tx_time = jiffies;
+
+	/*
+	 *  If the polling routing is not running, start it running here
+	 */
+	spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+	if (!dgrp_poll_data.node_active_count) {
+		dgrp_poll_data.node_active_count = 2;
+		dgrp_poll_data.timer.expires = jiffies +
+			dgrp_poll_tick * HZ / 1000;
+		add_timer(&dgrp_poll_data.timer);
+	}
+
+	spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+	dgrp_monitor_message(nd, "Net Open");
+
+unlock:
+	/*
+	 *  Release the NET lock.
+	 */
+	up(&nd->nd_net_semaphore);
+
+done:
+	if (rtn)
+		module_put(THIS_MODULE);
+
+	return rtn;
+}
+
+/* dgrp_net_release() -- close the NET device for a particular PortServer */
+static int dgrp_net_release(struct inode *inode, struct file *file)
+{
+	struct nd_struct *nd;
+	ulong  lock_flags;
+
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		goto done;
+
+/* TODO : historical locking placeholder */
+/*
+ *  In the HPUX version of the RealPort driver (which served as a basis
+ *  for this driver) this locking code was used.  Saved if ever we need
+ *  to review the locking under Linux.
+ */
+/*	spinlock(&nd->nd_lock); */
+
+
+	/*
+	 *  Grab the NET lock.
+	 */
+	down(&nd->nd_net_semaphore);
+
+	/*
+	 *  Before "closing" the internal connection, make sure all
+	 *  ports are "idle".
+	 */
+	dgrp_net_idle(nd);
+
+	nd->nd_state = NS_CLOSED;
+	nd->nd_flag = 0;
+
+	/*
+	 *  TODO ... must the wait queue be reset on close?
+	 *  should any pending waiters be reset?
+	 *  Let's decide to assert that the waitq is empty... and see
+	 *  how soon we break.
+	 */
+	if (waitqueue_active(&nd->nd_tx_waitq))
+		pr_info("%s - expected waitqueue_active to be false\n",
+			__func__);
+
+	nd->nd_send = 0;
+
+	kfree(nd->nd_iobuf);
+	nd->nd_iobuf = NULL;
+
+/* TODO : historical locking placeholder */
+/*
+ *  In the HPUX version of the RealPort driver (which served as a basis
+ *  for this driver) this locking code was used.  Saved if ever we need
+ *  to review the locking under Linux.
+ */
+/*	spinunlock( &nd->nd_lock ); */
+
+
+	kfree(nd->nd_writebuf);
+	nd->nd_writebuf = NULL;
+
+	kfree(nd->nd_inputbuf);
+	nd->nd_inputbuf = NULL;
+
+	kfree(nd->nd_inputflagbuf);
+	nd->nd_inputflagbuf = NULL;
+
+/* TODO : historical locking placeholder */
+/*
+ *  In the HPUX version of the RealPort driver (which served as a basis
+ *  for this driver) this locking code was used.  Saved if ever we need
+ *  to review the locking under Linux.
+ */
+/*	spinlock(&nd->nd_lock); */
+
+	/*
+	 *  Set the active port count to zero.
+	 */
+	dgrp_chan_count(nd, 0);
+
+/* TODO : historical locking placeholder */
+/*
+ *  In the HPUX version of the RealPort driver (which served as a basis
+ *  for this driver) this locking code was used.  Saved if ever we need
+ *  to review the locking under Linux.
+ */
+/*	spinunlock(&nd->nd_lock); */
+
+	/*
+	 *  Release the NET lock.
+	 */
+	up(&nd->nd_net_semaphore);
+
+	/*
+	 *  Cause the poller to stop scheduling itself if this is
+	 *  the last active node.
+	 */
+	spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+	if (dgrp_poll_data.node_active_count == 2) {
+		del_timer(&dgrp_poll_data.timer);
+		dgrp_poll_data.node_active_count = 0;
+	}
+
+	spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+done:
+	down(&nd->nd_net_semaphore);
+
+	dgrp_monitor_message(nd, "Net Close");
+
+	up(&nd->nd_net_semaphore);
+
+	module_put(THIS_MODULE);
+	file->private_data = NULL;
+	return 0;
+}
+
+/* used in dgrp_send to setup command header */
+static inline u8 *set_cmd_header(u8 *b, u8 port, u8 cmd)
+{
+	*b++ = 0xb0 + (port & 0x0f);
+	*b++ = cmd;
+	return b;
+}
+
+/**
+ * dgrp_send() -- build a packet for transmission to the server
+ * @nd: pointer to a node structure
+ * @tmax: maximum bytes to transmit
+ *
+ * returns number of bytes sent
+ */
+static int dgrp_send(struct nd_struct *nd, long tmax)
+{
+	struct ch_struct *ch = nd->nd_chan;
+	u8 *b;
+	u8 *buf;
+	u8 *mbuf;
+	u8 port;
+	int mod;
+	long send;
+	int maxport;
+	long lastport = -1;
+	ushort rwin;
+	long in;
+	ushort n;
+	long t;
+	long ttotal;
+	long tchan;
+	long tsend;
+	ushort tsafe;
+	long work;
+	long send_sync;
+	long wanted_sync_port = -1;
+	ushort tdata[CHAN_MAX];
+	long used_buffer;
+
+	mbuf = nd->nd_iobuf + UIO_BASE;
+	buf = b = mbuf;
+
+	send_sync = nd->nd_link.lk_slow_rate < UIO_MAX;
+
+	ttotal = 0;
+	tchan = 0;
+
+	memset(tdata, 0, sizeof(tdata));
+
+
+	/*
+	 * If there are any outstanding requests to be serviced,
+	 * service them here.
+	 */
+	if (nd->nd_send & NR_PASSWORD) {
+
+		/*
+		 *  Send Password response.
+		 */
+
+		b[0] = 0xfc;
+		b[1] = 0x20;
+		put_unaligned_be16(strlen(nd->password), b + 2);
+		b += 4;
+		b += strlen(nd->password);
+		nd->nd_send &= ~(NR_PASSWORD);
+	}
+
+
+	/*
+	 *  Loop over all modules to generate commands, and determine
+	 *  the amount of data queued for transmit.
+	 */
+
+	for (mod = 0, port = 0; port < nd->nd_chan_count; mod++) {
+		/*
+		 *  If this is not the current module, enter a module select
+		 *  code in the buffer.
+		 */
+
+		if (mod != nd->nd_tx_module)
+			mbuf = ++b;
+
+		/*
+		 *  Loop to process one module.
+		 */
+
+		maxport = port + 16;
+
+		if (maxport > nd->nd_chan_count)
+			maxport = nd->nd_chan_count;
+
+		for (; port < maxport; port++, ch++) {
+			/*
+			 *  Switch based on channel state.
+			 */
+
+			switch (ch->ch_state) {
+			/*
+			 *  Send requests when the port is closed, and there
+			 *  are no Open, Close or Cancel requests expected.
+			 */
+
+			case CS_IDLE:
+				/*
+				 * Wait until any open error code
+				 * has been delivered to all
+				 * associated ports.
+				 */
+
+				if (ch->ch_open_error) {
+					if (ch->ch_wait_count[ch->ch_otype]) {
+						work = 1;
+						break;
+					}
+
+					ch->ch_open_error = 0;
+				}
+
+				/*
+				 *  Wait until the channel HANGUP flag is reset
+				 *  before sending the first open.  We can only
+				 *  get to this state after a server disconnect.
+				 */
+
+				if ((ch->ch_flag & CH_HANGUP) != 0)
+					break;
+
+				/*
+				 *  If recovering from a TCP disconnect, or if
+				 *  there is an immediate open pending, send an
+				 *  Immediate Open request.
+				 */
+				if ((ch->ch_flag & CH_PORT_GONE) ||
+				    ch->ch_wait_count[OTYPE_IMMEDIATE] != 0) {
+					b = set_cmd_header(b, port, 10);
+					*b++ = 0;
+
+					ch->ch_state = CS_WAIT_OPEN;
+					ch->ch_otype = OTYPE_IMMEDIATE;
+					break;
+				}
+
+	/*
+	 *  If there is no Persistent or Incoming Open on the wait
+	 *  list in the server, and a thread is waiting for a
+	 *  Persistent or Incoming Open, send a Persistent or Incoming
+	 *  Open Request.
+	 */
+				if (ch->ch_otype_waiting == 0) {
+					if (ch->ch_wait_count[OTYPE_PERSISTENT] != 0) {
+						b = set_cmd_header(b, port, 10);
+						*b++ = 1;
+
+						ch->ch_state = CS_WAIT_OPEN;
+						ch->ch_otype = OTYPE_PERSISTENT;
+					} else if (ch->ch_wait_count[OTYPE_INCOMING] != 0) {
+						b = set_cmd_header(b, port, 10);
+						*b++ = 2;
+
+						ch->ch_state = CS_WAIT_OPEN;
+						ch->ch_otype = OTYPE_INCOMING;
+					}
+					break;
+				}
+
+				/*
+				 *  If a Persistent or Incoming Open is pending in
+				 *  the server, but there is no longer an open
+				 *  thread waiting for it, cancel the request.
+				 */
+
+				if (ch->ch_wait_count[ch->ch_otype_waiting] == 0) {
+					b = set_cmd_header(b, port, 10);
+					*b++ = 4;
+
+					ch->ch_state = CS_WAIT_CANCEL;
+					ch->ch_otype = ch->ch_otype_waiting;
+				}
+				break;
+
+				/*
+				 *  Send port parameter queries.
+				 */
+			case CS_SEND_QUERY:
+				/*
+				 *  Clear out all FEP state that might remain
+				 *  from the last connection.
+				 */
+
+				ch->ch_flag |= CH_PARAM;
+
+				ch->ch_flag &= ~CH_RX_FLUSH;
+
+				ch->ch_expect = 0;
+
+				ch->ch_s_tin   = 0;
+				ch->ch_s_tpos  = 0;
+				ch->ch_s_tsize = 0;
+				ch->ch_s_treq  = 0;
+				ch->ch_s_elast = 0;
+
+				ch->ch_s_rin   = 0;
+				ch->ch_s_rwin  = 0;
+				ch->ch_s_rsize = 0;
+
+				ch->ch_s_tmax  = 0;
+				ch->ch_s_ttime = 0;
+				ch->ch_s_rmax  = 0;
+				ch->ch_s_rtime = 0;
+				ch->ch_s_rlow  = 0;
+				ch->ch_s_rhigh = 0;
+
+				ch->ch_s_brate = 0;
+				ch->ch_s_iflag = 0;
+				ch->ch_s_cflag = 0;
+				ch->ch_s_oflag = 0;
+				ch->ch_s_xflag = 0;
+
+				ch->ch_s_mout  = 0;
+				ch->ch_s_mflow = 0;
+				ch->ch_s_mctrl = 0;
+				ch->ch_s_xon   = 0;
+				ch->ch_s_xoff  = 0;
+				ch->ch_s_lnext = 0;
+				ch->ch_s_xxon  = 0;
+				ch->ch_s_xxoff = 0;
+
+				/* Send Sequence Request */
+				b = set_cmd_header(b, port, 14);
+
+				/* Configure Event Conditions Packet */
+				b = set_cmd_header(b, port, 42);
+				put_unaligned_be16(0x02c0, b);
+				b += 2;
+				*b++ = (DM_DTR | DM_RTS | DM_CTS |
+					DM_DSR | DM_RI | DM_CD);
+
+				/* Send Status Request */
+				b = set_cmd_header(b, port, 16);
+
+				/* Send Buffer Request  */
+				b = set_cmd_header(b, port, 20);
+
+				/* Send Port Capability Request */
+				b = set_cmd_header(b, port, 22);
+
+				ch->ch_expect = (RR_SEQUENCE |
+						 RR_STATUS  |
+						 RR_BUFFER |
+						 RR_CAPABILITY);
+
+				ch->ch_state = CS_WAIT_QUERY;
+
+				/* Raise modem signals */
+				b = set_cmd_header(b, port, 44);
+
+				if (ch->ch_flag & CH_PORT_GONE)
+					ch->ch_s_mout = ch->ch_mout;
+				else
+					ch->ch_s_mout = ch->ch_mout = DM_DTR | DM_RTS;
+
+				*b++ = ch->ch_mout;
+				*b++ = ch->ch_s_mflow = 0;
+				*b++ = ch->ch_s_mctrl = ch->ch_mctrl = 0;
+
+				if (ch->ch_flag & CH_PORT_GONE)
+					ch->ch_flag &= ~CH_PORT_GONE;
+
+				break;
+
+			/*
+			 *  Handle normal open and ready mode.
+			 */
+
+			case CS_READY:
+
+				/*
+				 *  If the port is not open, and there are no
+				 *  no longer any ports requesting an open,
+				 *  then close the port.
+				 */
+
+				if (ch->ch_open_count == 0 &&
+				    ch->ch_wait_count[ch->ch_otype] == 0) {
+					goto send_close;
+				}
+
+	/*
+	 *  Process waiting input.
+	 *
+	 *  If there is no one to read it, discard the data.
+	 *
+	 *  Otherwise if we are not in fastcook mode, or if there is a
+	 *  fastcook thread waiting for data, send the data to the
+	 *  line discipline.
+	 */
+				if (ch->ch_rin != ch->ch_rout) {
+					if (ch->ch_tun.un_open_count == 0 ||
+					     (ch->ch_tun.un_flag & UN_CLOSING) ||
+					    (ch->ch_cflag & CF_CREAD) == 0) {
+						ch->ch_rout = ch->ch_rin;
+					} else if ((ch->ch_flag & CH_FAST_READ) == 0 ||
+							ch->ch_inwait != 0) {
+						dgrp_input(ch);
+
+						if (ch->ch_rin != ch->ch_rout)
+							work = 1;
+					}
+				}
+
+				/*
+				 *  Handle receive flush, and changes to
+				 *  server port parameters.
+				 */
+
+				if (ch->ch_flag & (CH_RX_FLUSH | CH_PARAM)) {
+				/*
+				 *  If we are in receive flush mode,
+				 *  and enough data has gone by, reset
+				 *  receive flush mode.
+				 */
+					if (ch->ch_flag & CH_RX_FLUSH) {
+						if (((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >
+						    ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK))
+							ch->ch_flag &= ~CH_RX_FLUSH;
+						else
+							work = 1;
+					}
+
+					/*
+					 *  Send TMAX, TTIME.
+					 */
+
+					if (ch->ch_s_tmax  != ch->ch_tmax ||
+					    ch->ch_s_ttime != ch->ch_ttime) {
+						b = set_cmd_header(b, port, 48);
+
+						ch->ch_s_tmax = ch->ch_tmax;
+						ch->ch_s_ttime = ch->ch_ttime;
+
+						put_unaligned_be16(ch->ch_s_tmax,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_ttime,
+								   b);
+						b += 2;
+					}
+
+					/*
+					 *  Send RLOW, RHIGH.
+					 */
+
+					if (ch->ch_s_rlow  != ch->ch_rlow ||
+					    ch->ch_s_rhigh != ch->ch_rhigh) {
+						b = set_cmd_header(b, port, 45);
+
+						ch->ch_s_rlow  = ch->ch_rlow;
+						ch->ch_s_rhigh = ch->ch_rhigh;
+
+						put_unaligned_be16(ch->ch_s_rlow,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_rhigh,
+								   b);
+						b += 2;
+					}
+
+					/*
+					 *  Send BRATE, CFLAG, IFLAG,
+					 *  OFLAG, XFLAG.
+					 */
+
+					if (ch->ch_s_brate != ch->ch_brate ||
+					    ch->ch_s_cflag != ch->ch_cflag ||
+					    ch->ch_s_iflag != ch->ch_iflag ||
+					    ch->ch_s_oflag != ch->ch_oflag ||
+					    ch->ch_s_xflag != ch->ch_xflag) {
+						b = set_cmd_header(b, port, 40);
+
+						ch->ch_s_brate = ch->ch_brate;
+						ch->ch_s_cflag = ch->ch_cflag;
+						ch->ch_s_iflag = ch->ch_iflag;
+						ch->ch_s_oflag = ch->ch_oflag;
+						ch->ch_s_xflag = ch->ch_xflag;
+
+						put_unaligned_be16(ch->ch_s_brate,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_cflag,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_iflag,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_oflag,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_xflag,
+								   b);
+						b += 2;
+					}
+
+					/*
+					 *  Send MOUT, MFLOW, MCTRL.
+					 */
+
+					if (ch->ch_s_mout  != ch->ch_mout  ||
+					    ch->ch_s_mflow != ch->ch_mflow ||
+					    ch->ch_s_mctrl != ch->ch_mctrl) {
+						b = set_cmd_header(b, port, 44);
+
+						*b++ = ch->ch_s_mout  = ch->ch_mout;
+						*b++ = ch->ch_s_mflow = ch->ch_mflow;
+						*b++ = ch->ch_s_mctrl = ch->ch_mctrl;
+					}
+
+					/*
+					 *  Send Flow control characters.
+					 */
+
+					if (ch->ch_s_xon   != ch->ch_xon   ||
+					    ch->ch_s_xoff  != ch->ch_xoff  ||
+					    ch->ch_s_lnext != ch->ch_lnext ||
+					    ch->ch_s_xxon  != ch->ch_xxon  ||
+					    ch->ch_s_xxoff != ch->ch_xxoff) {
+						b = set_cmd_header(b, port, 46);
+
+						*b++ = ch->ch_s_xon   = ch->ch_xon;
+						*b++ = ch->ch_s_xoff  = ch->ch_xoff;
+						*b++ = ch->ch_s_lnext = ch->ch_lnext;
+						*b++ = ch->ch_s_xxon  = ch->ch_xxon;
+						*b++ = ch->ch_s_xxoff = ch->ch_xxoff;
+					}
+
+					/*
+					 *  Send RMAX, RTIME.
+					 */
+
+					if (ch->ch_s_rmax != ch->ch_rmax ||
+					    ch->ch_s_rtime != ch->ch_rtime) {
+						b = set_cmd_header(b, port, 47);
+
+						ch->ch_s_rmax  = ch->ch_rmax;
+						ch->ch_s_rtime = ch->ch_rtime;
+
+						put_unaligned_be16(ch->ch_s_rmax,
+								   b);
+						b += 2;
+
+						put_unaligned_be16(ch->ch_s_rtime,
+								   b);
+						b += 2;
+					}
+
+					ch->ch_flag &= ~CH_PARAM;
+					wake_up_interruptible(&ch->ch_flag_wait);
+				}
+
+
+				/*
+				 *  Handle action commands.
+				 */
+
+				if (ch->ch_send != 0) {
+					/* int send = ch->ch_send & ~ch->ch_expect; */
+					send = ch->ch_send & ~ch->ch_expect;
+
+					/* Send character immediate */
+					if ((send & RR_TX_ICHAR) != 0) {
+						b = set_cmd_header(b, port, 60);
+
+						*b++ = ch->ch_xon;
+						ch->ch_expect |= RR_TX_ICHAR;
+					}
+
+					/* BREAK request */
+					if ((send & RR_TX_BREAK) != 0) {
+						if (ch->ch_break_time != 0) {
+							b = set_cmd_header(b, port, 61);
+							put_unaligned_be16(ch->ch_break_time,
+									   b);
+							b += 2;
+
+							ch->ch_expect |= RR_TX_BREAK;
+							ch->ch_break_time = 0;
+						} else {
+							ch->ch_send &= ~RR_TX_BREAK;
+							ch->ch_flag &= ~CH_TX_BREAK;
+							wake_up_interruptible(&ch->ch_flag_wait);
+						}
+					}
+
+					/*
+					 *  Flush input/output buffers.
+					 */
+
+					if ((send & (RR_RX_FLUSH | RR_TX_FLUSH)) != 0) {
+						b = set_cmd_header(b, port, 62);
+
+						*b++ = ((send & RR_TX_FLUSH) == 0 ? 1 :
+							(send & RR_RX_FLUSH) == 0 ? 2 : 3);
+
+						if (send & RR_RX_FLUSH) {
+							ch->ch_flush_seq = nd->nd_seq_in;
+							ch->ch_flag |= CH_RX_FLUSH;
+							work = 1;
+							send_sync = 1;
+							wanted_sync_port = port;
+						}
+
+						ch->ch_send &= ~(RR_RX_FLUSH | RR_TX_FLUSH);
+					}
+
+					/*  Pause input/output */
+					if ((send & (RR_RX_STOP | RR_TX_STOP)) != 0) {
+						b = set_cmd_header(b, port, 63);
+						*b = 0;
+
+						if ((send & RR_TX_STOP) != 0)
+							*b |= EV_OPU;
+
+						if ((send & RR_RX_STOP) != 0)
+							*b |= EV_IPU;
+
+						b++;
+
+						ch->ch_send &= ~(RR_RX_STOP | RR_TX_STOP);
+					}
+
+					/* Start input/output */
+					if ((send & (RR_RX_START | RR_TX_START)) != 0) {
+						b = set_cmd_header(b, port, 64);
+						*b = 0;
+
+						if ((send & RR_TX_START) != 0)
+							*b |= EV_OPU | EV_OPS | EV_OPX;
+
+						if ((send & RR_RX_START) != 0)
+							*b |= EV_IPU | EV_IPS;
+
+						b++;
+
+						ch->ch_send &= ~(RR_RX_START | RR_TX_START);
+					}
+				}
+
+
+				/*
+				 *  Send a window sequence to acknowledge received data.
+				 */
+
+				rwin = (ch->ch_s_rin +
+					((ch->ch_rout - ch->ch_rin - 1) & RBUF_MASK));
+
+				n = (rwin - ch->ch_s_rwin) & 0xffff;
+
+				if (n >= RBUF_MAX / 4) {
+					b[0] = 0xa0 + (port & 0xf);
+					ch->ch_s_rwin = rwin;
+					put_unaligned_be16(rwin, b + 1);
+					b += 3;
+				}
+
+				/*
+				 *  If the terminal is waiting on LOW
+				 *  water or EMPTY, and the condition
+				 *  is now satisfied, call the line
+				 *  discipline to put more data in the
+				 *  buffer.
+				 */
+
+				n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+				if ((ch->ch_tun.un_flag & (UN_EMPTY|UN_LOW)) != 0) {
+					if ((ch->ch_tun.un_flag & UN_LOW) != 0 ?
+					    (n <= TBUF_LOW) :
+					    (n == 0 && ch->ch_s_tpos == ch->ch_s_tin)) {
+						ch->ch_tun.un_flag &= ~(UN_EMPTY|UN_LOW);
+
+						if (waitqueue_active(&((ch->ch_tun.un_tty)->write_wait)))
+							wake_up_interruptible(&((ch->ch_tun.un_tty)->write_wait));
+						tty_wakeup(ch->ch_tun.un_tty);
+						n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+					}
+				}
+
+				/*
+				 * If the printer is waiting on LOW
+				 * water, TIME, EMPTY or PWAIT, and is
+				 * now ready to put more data in the
+				 * buffer, call the line discipline to
+				 * do the job.
+				 */
+
+				if (ch->ch_pun.un_open_count &&
+				    (ch->ch_pun.un_flag &
+				    (UN_EMPTY|UN_TIME|UN_LOW|UN_PWAIT)) != 0) {
+
+					if ((ch->ch_pun.un_flag & UN_LOW) != 0 ?
+					    (n <= TBUF_LOW) :
+					    (ch->ch_pun.un_flag & UN_TIME) != 0 ?
+					    ((jiffies - ch->ch_waketime) >= 0) :
+					    (n == 0 && ch->ch_s_tpos == ch->ch_s_tin) &&
+					    ((ch->ch_pun.un_flag & UN_EMPTY) != 0 ||
+					    ((ch->ch_tun.un_open_count &&
+					      ch->ch_tun.un_tty->ops->chars_in_buffer) ?
+					     (ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) == 0
+					     : 1
+					    )
+					    )) {
+						ch->ch_pun.un_flag &= ~(UN_EMPTY | UN_TIME | UN_LOW | UN_PWAIT);
+
+						if (waitqueue_active(&((ch->ch_pun.un_tty)->write_wait)))
+							wake_up_interruptible(&((ch->ch_pun.un_tty)->write_wait));
+						tty_wakeup(ch->ch_pun.un_tty);
+						n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+					} else if ((ch->ch_pun.un_flag & UN_TIME) != 0) {
+						work = 1;
+					}
+				}
+
+
+				/*
+				 *  Determine the max number of bytes
+				 *  this port can send, including
+				 *  packet header overhead.
+				 */
+
+				t = ((ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff);
+
+				if (n > t)
+					n = t;
+
+				if (n != 0) {
+					n += (n <= 8 ? 1 : n <= 255 ? 2 : 3);
+
+					tdata[tchan++] = n;
+					ttotal += n;
+				}
+				break;
+
+			/*
+			 *  Close the port.
+			 */
+
+send_close:
+			case CS_SEND_CLOSE:
+				b = set_cmd_header(b, port, 10);
+				if (ch->ch_otype == OTYPE_IMMEDIATE)
+					*b++ = 3;
+				else
+					*b++ = 4;
+
+				ch->ch_state = CS_WAIT_CLOSE;
+				break;
+
+			/*
+			 *  Wait for a previous server request.
+			 */
+
+			case CS_WAIT_OPEN:
+			case CS_WAIT_CANCEL:
+			case CS_WAIT_FAIL:
+			case CS_WAIT_QUERY:
+			case CS_WAIT_CLOSE:
+				break;
+
+			default:
+				pr_info("%s - unexpected channel state (%i)\n",
+					__func__, ch->ch_state);
+			}
+		}
+
+		/*
+		 *  If a module select code is needed, drop one in.  If space
+		 *  was reserved for one, but none is needed, recover the space.
+		 */
+
+		if (mod != nd->nd_tx_module) {
+			if (b != mbuf) {
+				mbuf[-1] = 0xf0 | mod;
+				nd->nd_tx_module = mod;
+			} else {
+				b--;
+			}
+		}
+	}
+
+	/*
+	 *  Adjust "tmax" so that under worst case conditions we do
+	 *  not overflow either the daemon buffer or the internal
+	 *  buffer in the loop that follows.   Leave a safe area
+	 *  of 64 bytes so we start getting asserts before we start
+	 *  losing data or clobbering memory.
+	 */
+
+	n = UIO_MAX - UIO_BASE;
+
+	if (tmax > n)
+		tmax = n;
+
+	tmax -= 64;
+
+	tsafe = tmax;
+
+	/*
+	 *  Allocate space for 5 Module Selects, 1 Sequence Request,
+	 *  and 1 Set TREQ for each active channel.
+	 */
+
+	tmax -= 5 + 3 + 4 * nd->nd_chan_count;
+
+	/*
+	 *  Further reduce "tmax" to the available transmit credit.
+	 *  Note that this is a soft constraint;  The transmit credit
+	 *  can go negative for a time and then recover.
+	 */
+
+	n = nd->nd_tx_deposit - nd->nd_tx_charge - nd->nd_link.lk_header_size;
+
+	if (tmax > n)
+		tmax = n;
+
+	/*
+	 *  Finally reduce tmax by the number of bytes already in
+	 *  the buffer.
+	 */
+
+	tmax -= b - buf;
+
+	/*
+	 *  Suspend data transmit unless every ready channel can send
+	 *  at least 1 character.
+	 */
+	if (tmax < 2 * nd->nd_chan_count) {
+		tsend = 1;
+
+	} else if (tchan > 1 && ttotal > tmax) {
+
+		/*
+		 *  If transmit is limited by the credit budget, find the
+		 *  largest number of characters we can send without driving
+		 *  the credit negative.
+		 */
+
+		long tm = tmax;
+		int tc = tchan;
+		int try;
+
+		tsend = tm / tc;
+
+		for (try = 0; try < 3; try++) {
+			int i;
+			int c = 0;
+
+			for (i = 0; i < tc; i++) {
+				if (tsend < tdata[i])
+					tdata[c++] = tdata[i];
+				else
+					tm -= tdata[i];
+			}
+
+			if (c == tc)
+				break;
+
+			tsend = tm / c;
+
+			if (c == 1)
+				break;
+
+			tc = c;
+		}
+
+		tsend = tm / nd->nd_chan_count;
+
+		if (tsend < 2)
+			tsend = 1;
+
+	} else {
+		/*
+		 *  If no budgetary constraints, or only one channel ready
+		 *  to send, set the character limit to the remaining
+		 *  buffer size.
+		 */
+
+		tsend = tmax;
+	}
+
+	tsend -= (tsend <= 9) ? 1 : (tsend <= 257) ? 2 : 3;
+
+	/*
+	 *  Loop over all channels, sending queued data.
+	 */
+
+	port = 0;
+	ch = nd->nd_chan;
+	used_buffer = tmax;
+
+	for (mod = 0; port < nd->nd_chan_count; mod++) {
+		/*
+		 *  If this is not the current module, enter a module select
+		 *  code in the buffer.
+		 */
+
+		if (mod != nd->nd_tx_module)
+			mbuf = ++b;
+
+		/*
+		 *  Loop to process one module.
+		 */
+
+		maxport = port + 16;
+
+		if (maxport > nd->nd_chan_count)
+			maxport = nd->nd_chan_count;
+
+		for (; port < maxport; port++, ch++) {
+			if (ch->ch_state != CS_READY)
+				continue;
+
+			lastport = port;
+
+			n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+			/*
+			 *  If there is data that can be sent, send it.
+			 */
+
+			if (n != 0 && used_buffer > 0) {
+				t = (ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff;
+
+				if (n > t)
+					n = t;
+
+				if (n > tsend) {
+					work = 1;
+					n = tsend;
+				}
+
+				if (n > used_buffer) {
+					work = 1;
+					n = used_buffer;
+				}
+
+				if (n <= 0)
+					continue;
+
+				/*
+				 *  Create the correct size transmit header,
+				 *  depending on the amount of data to transmit.
+				 */
+
+				if (n <= 8) {
+
+					b[0] = ((n - 1) << 4) + (port & 0xf);
+					b += 1;
+
+				} else if (n <= 255) {
+
+					b[0] = 0x80 + (port & 0xf);
+					b[1] = n;
+					b += 2;
+
+				} else {
+
+					b[0] = 0x90 + (port & 0xf);
+					put_unaligned_be16(n, b + 1);
+					b += 3;
+				}
+
+				ch->ch_s_tin = (ch->ch_s_tin + n) & 0xffff;
+
+				/*
+				 *  Copy transmit data to the packet.
+				 */
+
+				t = TBUF_MAX - ch->ch_tout;
+
+				if (n >= t) {
+					memcpy(b, ch->ch_tbuf + ch->ch_tout, t);
+					b += t;
+					n -= t;
+					used_buffer -= t;
+					ch->ch_tout = 0;
+				}
+
+				memcpy(b, ch->ch_tbuf + ch->ch_tout, n);
+				b += n;
+				used_buffer -= n;
+				ch->ch_tout += n;
+				n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+			}
+
+			/*
+			 *  Wake any terminal unit process waiting in the
+			 *  dgrp_write routine for low water.
+			 */
+
+			if (n > TBUF_LOW)
+				continue;
+
+			if ((ch->ch_flag & CH_LOW) != 0) {
+				ch->ch_flag &= ~CH_LOW;
+				wake_up_interruptible(&ch->ch_flag_wait);
+			}
+
+			/* selwakeup tty_sel */
+			if (ch->ch_tun.un_open_count) {
+				struct tty_struct *tty = (ch->ch_tun.un_tty);
+
+				if (waitqueue_active(&tty->write_wait))
+					wake_up_interruptible(&tty->write_wait);
+
+				tty_wakeup(tty);
+			}
+
+			if (ch->ch_pun.un_open_count) {
+				struct tty_struct *tty = (ch->ch_pun.un_tty);
+
+				if (waitqueue_active(&tty->write_wait))
+					wake_up_interruptible(&tty->write_wait);
+
+				tty_wakeup(tty);
+			}
+
+			/*
+			 *  Do EMPTY processing.
+			 */
+
+			if (n != 0)
+				continue;
+
+			if ((ch->ch_flag & (CH_EMPTY | CH_DRAIN)) != 0 ||
+			    (ch->ch_pun.un_flag & UN_EMPTY) != 0) {
+				/*
+				 *  If there is still data in the server, ask the server
+				 *  to notify us when its all gone.
+				 */
+
+				if (ch->ch_s_treq != ch->ch_s_tin) {
+					b = set_cmd_header(b, port, 43);
+
+					ch->ch_s_treq = ch->ch_s_tin;
+					put_unaligned_be16(ch->ch_s_treq,
+							   b);
+					b += 2;
+				}
+
+				/*
+				 *  If there is a thread waiting for buffer empty,
+				 *  and we are truly empty, wake the thread.
+				 */
+
+				else if ((ch->ch_flag & CH_EMPTY) != 0 &&
+					(ch->ch_send & RR_TX_BREAK) == 0) {
+					ch->ch_flag &= ~CH_EMPTY;
+
+					wake_up_interruptible(&ch->ch_flag_wait);
+				}
+			}
+		}
+
+		/*
+		 *  If a module select code is needed, drop one in.  If space
+		 *  was reserved for one, but none is needed, recover the space.
+		 */
+
+		if (mod != nd->nd_tx_module) {
+			if (b != mbuf) {
+				mbuf[-1] = 0xf0 | mod;
+				nd->nd_tx_module = mod;
+			} else {
+				b--;
+			}
+		}
+	}
+
+	/*
+	 *  Send a synchronization sequence associated with the last open
+	 *  channel that sent data, and remember the time when the data was
+	 *  sent.
+	 */
+
+	in = nd->nd_seq_in;
+
+	if ((send_sync || nd->nd_seq_wait[in] != 0) && lastport >= 0) {
+		u8 *bb = b;
+
+		/*
+		 * Attempt the use the port that really wanted the sync.
+		 * This gets around a race condition where the "lastport" is in
+		 * the middle of the close() routine, and by the time we
+		 * send this command, it will have already acked the close, and
+		 * thus not send the sync response.
+		 */
+		if (wanted_sync_port >= 0)
+			lastport = wanted_sync_port;
+		/*
+		 * Set a flag just in case the port is in the middle of a close,
+		 * it will not be permitted to actually close until we get an
+		 * sync response, and clear the flag there.
+		 */
+		ch = nd->nd_chan + lastport;
+		ch->ch_flag |= CH_WAITING_SYNC;
+
+		mod = lastport >> 4;
+
+		if (mod != nd->nd_tx_module) {
+			bb[0] = 0xf0 + mod;
+			bb += 1;
+
+			nd->nd_tx_module = mod;
+		}
+
+		bb = set_cmd_header(bb, lastport, 12);
+		*bb++ = in;
+
+		nd->nd_seq_size[in] = bb - buf;
+		nd->nd_seq_time[in] = jiffies;
+
+		if (++in >= SEQ_MAX)
+			in = 0;
+
+		if (in != nd->nd_seq_out) {
+			b = bb;
+			nd->nd_seq_in = in;
+			nd->nd_unack += b - buf;
+		}
+	}
+
+	/*
+	 *  If there are no open ports, a sync cannot be sent.
+	 *  There is nothing left to wait for anyway, so wake any
+	 *  thread waiting for an acknowledgement.
+	 */
+
+	else if (nd->nd_seq_wait[in] != 0) {
+		nd->nd_seq_wait[in] = 0;
+
+		wake_up_interruptible(&nd->nd_seq_wque[in]);
+	}
+
+	/*
+	 *  If there is no traffic for an interval of IDLE_MAX, then
+	 *  send a single byte packet.
+	 */
+
+	if (b != buf) {
+		nd->nd_tx_time = jiffies;
+	} else if ((ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX) {
+		*b++ = 0xf0 | nd->nd_tx_module;
+		nd->nd_tx_time = jiffies;
+	}
+
+	n = b - buf;
+
+	if (n >= tsafe)
+		pr_info("%s - n(%i) >= tsafe(%i)\n",
+			__func__, n, tsafe);
+
+	if (tsend < 0)
+		dgrp_dump(buf, n);
+
+	nd->nd_tx_work = work;
+
+	return n;
+}
+
+/*
+ * dgrp_net_read()
+ * Data to be sent TO the PortServer from the "async." half of the driver.
+ */
+static ssize_t dgrp_net_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct nd_struct *nd;
+	long n;
+	u8 *local_buf;
+	u8 *b;
+	ssize_t rtn;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		return -ENXIO;
+
+	if (count < UIO_MIN)
+		return -EINVAL;
+
+	/*
+	 *  Only one read/write operation may be in progress at
+	 *  any given time.
+	 */
+
+	/*
+	 *  Grab the NET lock.
+	 */
+	down(&nd->nd_net_semaphore);
+
+	nd->nd_read_count++;
+
+	nd->nd_tx_ready = 0;
+
+	/*
+	 *  Determine the effective size of the buffer.
+	 */
+
+	if (nd->nd_remain > UIO_BASE)
+		pr_info_ratelimited("%s - nd_remain(%i) > UIO_BASE\n",
+				    __func__, nd->nd_remain);
+
+	b = local_buf = nd->nd_iobuf + UIO_BASE;
+
+	/*
+	 *  Generate data according to the node state.
+	 */
+
+	switch (nd->nd_state) {
+	/*
+	 *  Initialize the connection.
+	 */
+
+	case NS_IDLE:
+		if (nd->nd_mon_buf)
+			dgrp_monitor_reset(nd);
+
+		/*
+		 *  Request a Product ID Packet.
+		 */
+
+		b[0] = 0xfb;
+		b[1] = 0x01;
+		b += 2;
+
+		nd->nd_expect |= NR_IDENT;
+
+		/*
+		 *  Request a Server Capability ID Response.
+		 */
+
+		b[0] = 0xfb;
+		b[1] = 0x02;
+		b += 2;
+
+		nd->nd_expect |= NR_CAPABILITY;
+
+		/*
+		 *  Request a Server VPD Response.
+		 */
+
+		b[0] = 0xfb;
+		b[1] = 0x18;
+		b += 2;
+
+		nd->nd_expect |= NR_VPD;
+
+		nd->nd_state = NS_WAIT_QUERY;
+		break;
+
+	/*
+	 *  We do serious communication with the server only in
+	 *  the READY state.
+	 */
+
+	case NS_READY:
+		b = dgrp_send(nd, count) + local_buf;
+		break;
+
+	/*
+	 *  Send off an error after receiving a bogus message
+	 *  from the server.
+	 */
+
+	case NS_SEND_ERROR:
+		n = strlen(nd->nd_error);
+
+		b[0] = 0xff;
+		b[1] = n;
+		memcpy(b + 2, nd->nd_error, n);
+		b += 2 + n;
+
+		dgrp_net_idle(nd);
+		/*
+		 *  Set the active port count to zero.
+		 */
+		dgrp_chan_count(nd, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	n = b - local_buf;
+
+	if (n != 0) {
+		nd->nd_send_count++;
+
+		nd->nd_tx_byte   += n + nd->nd_link.lk_header_size;
+		nd->nd_tx_charge += n + nd->nd_link.lk_header_size;
+	}
+
+	rtn = copy_to_user((void __user *)buf, local_buf, n);
+	if (rtn) {
+		rtn = -EFAULT;
+		goto done;
+	}
+
+	*ppos += n;
+
+	rtn = n;
+
+	if (nd->nd_mon_buf)
+		dgrp_monitor_data(nd, RPDUMP_CLIENT, local_buf, n);
+
+	/*
+	 *  Release the NET lock.
+	 */
+done:
+	up(&nd->nd_net_semaphore);
+
+	return rtn;
+}
+
+/**
+ * dgrp_receive() -- decode data packets received from the remote PortServer.
+ * @nd: pointer to a node structure
+ */
+static void dgrp_receive(struct nd_struct *nd)
+{
+	struct ch_struct *ch;
+	u8 *buf;
+	u8 *b;
+	u8 *dbuf;
+	char *error;
+	long port;
+	long dlen;
+	long plen;
+	long remain;
+	long n;
+	long mlast;
+	long elast;
+	long mstat;
+	long estat;
+
+	char ID[3];
+
+	nd->nd_tx_time = jiffies;
+
+	ID_TO_CHAR(nd->nd_ID, ID);
+
+	b = buf = nd->nd_iobuf;
+	remain = nd->nd_remain;
+
+	/*
+	 *  Loop to process Realport protocol packets.
+	 */
+
+	while (remain > 0) {
+		int n0 = b[0] >> 4;
+		int n1 = b[0] & 0x0f;
+
+		if (n0 <= 12) {
+			port = (nd->nd_rx_module << 4) + n1;
+
+			if (port >= nd->nd_chan_count) {
+				error = "Improper Port Number";
+				goto prot_error;
+			}
+
+			ch = nd->nd_chan + port;
+		} else {
+			port = -1;
+			ch = NULL;
+		}
+
+		/*
+		 *  Process by major packet type.
+		 */
+
+		switch (n0) {
+
+		/*
+		 *  Process 1-byte header data packet.
+		 */
+
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+			dlen = n0 + 1;
+			plen = dlen + 1;
+
+			dbuf = b + 1;
+			goto data;
+
+		/*
+		 *  Process 2-byte header data packet.
+		 */
+
+		case 8:
+			if (remain < 3)
+				goto done;
+
+			dlen = b[1];
+			plen = dlen + 2;
+
+			dbuf = b + 2;
+			goto data;
+
+		/*
+		 *  Process 3-byte header data packet.
+		 */
+
+		case 9:
+			if (remain < 4)
+				goto done;
+
+			dlen = get_unaligned_be16(b + 1);
+			plen = dlen + 3;
+
+			dbuf = b + 3;
+
+		/*
+		 *  Common packet handling code.
+		 */
+
+data:
+			nd->nd_tx_work = 1;
+
+			/*
+			 *  Otherwise data should appear only when we are
+			 *  in the CS_READY state.
+			 */
+
+			if (ch->ch_state < CS_READY) {
+				error = "Data received before RWIN established";
+				goto prot_error;
+			}
+
+			/*
+			 *  Assure that the data received is within the
+			 *  allowable window.
+			 */
+
+			n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff;
+
+			if (dlen > n) {
+				error = "Receive data overrun";
+				goto prot_error;
+			}
+
+			/*
+			 *  If we received 3 or less characters,
+			 *  assume it is a human typing, and set RTIME
+			 *  to 10 milliseconds.
+			 *
+			 *  If we receive 10 or more characters,
+			 *  assume its not a human typing, and set RTIME
+			 *  to 100 milliseconds.
+			 */
+
+			if (ch->ch_edelay != DGRP_RTIME) {
+				if (ch->ch_rtime != ch->ch_edelay) {
+					ch->ch_rtime = ch->ch_edelay;
+					ch->ch_flag |= CH_PARAM;
+				}
+			} else if (dlen <= 3) {
+				if (ch->ch_rtime != 10) {
+					ch->ch_rtime = 10;
+					ch->ch_flag |= CH_PARAM;
+				}
+			} else {
+				if (ch->ch_rtime != DGRP_RTIME) {
+					ch->ch_rtime = DGRP_RTIME;
+					ch->ch_flag |= CH_PARAM;
+				}
+			}
+
+			/*
+			 *  If a portion of the packet is outside the
+			 *  buffer, shorten the effective length of the
+			 *  data packet to be the amount of data received.
+			 */
+
+			if (remain < plen)
+				dlen -= plen - remain;
+
+			/*
+			 *  Detect if receive flush is now complete.
+			 */
+
+			if ((ch->ch_flag & CH_RX_FLUSH) != 0 &&
+			    ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >=
+			    ((nd->nd_seq_in    - nd->nd_seq_out) & SEQ_MASK)) {
+				ch->ch_flag &= ~CH_RX_FLUSH;
+			}
+
+			/*
+			 *  If we are ready to receive, move the data into
+			 *  the receive buffer.
+			 */
+
+			ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff;
+
+			if (ch->ch_state == CS_READY &&
+			    (ch->ch_tun.un_open_count != 0) &&
+			    (ch->ch_tun.un_flag & UN_CLOSING) == 0 &&
+			    (ch->ch_cflag & CF_CREAD) != 0 &&
+			    (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 &&
+			    (ch->ch_send & RR_RX_FLUSH) == 0) {
+
+				if (ch->ch_rin + dlen >= RBUF_MAX) {
+					n = RBUF_MAX - ch->ch_rin;
+
+					memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n);
+
+					ch->ch_rin = 0;
+					dbuf += n;
+					dlen -= n;
+				}
+
+				memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen);
+
+				ch->ch_rin += dlen;
+
+
+				/*
+				 *  If we are not in fastcook mode, or
+				 *  if there is a fastcook thread
+				 *  waiting for data, send the data to
+				 *  the line discipline.
+				 */
+
+				if ((ch->ch_flag & CH_FAST_READ) == 0 ||
+				    ch->ch_inwait != 0) {
+					dgrp_input(ch);
+				}
+
+				/*
+				 *  If there is a read thread waiting
+				 *  in select, and we are in fastcook
+				 *  mode, wake him up.
+				 */
+
+				if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) &&
+				    (ch->ch_flag & CH_FAST_READ) != 0)
+					wake_up_interruptible(&ch->ch_tun.un_tty->read_wait);
+
+				/*
+				 * Wake any thread waiting in the
+				 * fastcook loop.
+				 */
+
+				if ((ch->ch_flag & CH_INPUT) != 0) {
+					ch->ch_flag &= ~CH_INPUT;
+
+					wake_up_interruptible(&ch->ch_flag_wait);
+				}
+			}
+
+			/*
+			 *  Fabricate and insert a data packet header to
+			 *  preceed the remaining data when it comes in.
+			 */
+
+			if (remain < plen) {
+				dlen = plen - remain;
+				b = buf;
+
+				b[0] = 0x90 + n1;
+				put_unaligned_be16(dlen, b + 1);
+
+				remain = 3;
+				goto done;
+			}
+			break;
+
+		/*
+		 *  Handle Window Sequence packets.
+		 */
+
+		case 10:
+			plen = 3;
+			if (remain < plen)
+				goto done;
+
+			nd->nd_tx_work = 1;
+
+			{
+				ushort tpos   = get_unaligned_be16(b + 1);
+
+				ushort ack    = (tpos          - ch->ch_s_tpos) & 0xffff;
+				ushort unack  = (ch->ch_s_tin  - ch->ch_s_tpos) & 0xffff;
+				ushort notify = (ch->ch_s_treq - ch->ch_s_tpos) & 0xffff;
+
+				if (ch->ch_state < CS_READY || ack > unack) {
+					error = "Improper Window Sequence";
+					goto prot_error;
+				}
+
+				ch->ch_s_tpos = tpos;
+
+				if (notify <= ack)
+					ch->ch_s_treq = tpos;
+			}
+			break;
+
+		/*
+		 *  Handle Command response packets.
+		 */
+
+		case 11:
+
+			/*
+			 * RealPort engine fix - 03/11/2004
+			 *
+			 * This check did not used to be here.
+			 *
+			 * We were using b[1] without verifying that the data
+			 * is actually there and valid. On a split packet, it
+			 * might not be yet.
+			 *
+			 * NOTE:  I have never actually seen the failure happen
+			 *        under Linux,  but since I have seen it occur
+			 *        under both Solaris and HP-UX,  the assumption
+			 *        is that it *could* happen here as well...
+			 */
+			if (remain < 2)
+				goto done;
+
+
+			switch (b[1]) {
+
+			/*
+			 *  Handle Open Response.
+			 */
+
+			case 11:
+				plen = 6;
+				if (remain < plen)
+					goto done;
+
+				nd->nd_tx_work = 1;
+
+				{
+					int req = b[2];
+					int resp = b[3];
+					port = get_unaligned_be16(b + 4);
+
+					if (port >= nd->nd_chan_count) {
+						error = "Open channel number out of range";
+						goto prot_error;
+					}
+
+					ch = nd->nd_chan + port;
+
+					/*
+					 *  How we handle an open response depends primarily
+					 *  on our current channel state.
+					 */
+
+					switch (ch->ch_state) {
+					case CS_IDLE:
+
+						/*
+						 *  Handle a delayed open.
+						 */
+
+						if (ch->ch_otype_waiting != 0 &&
+						    req == ch->ch_otype_waiting &&
+						    resp == 0) {
+							ch->ch_otype = req;
+							ch->ch_otype_waiting = 0;
+							ch->ch_state = CS_SEND_QUERY;
+							break;
+						}
+						goto open_error;
+
+					case CS_WAIT_OPEN:
+
+						/*
+						 *  Handle the open response.
+						 */
+
+						if (req == ch->ch_otype) {
+							switch (resp) {
+
+							/*
+							 *  On successful response, open the
+							 *  port and proceed normally.
+							 */
+
+							case 0:
+								ch->ch_state = CS_SEND_QUERY;
+								break;
+
+							/*
+							 *  On a busy response to a persistent open,
+							 *  remember that the open is pending.
+							 */
+
+							case 1:
+							case 2:
+								if (req != OTYPE_IMMEDIATE) {
+									ch->ch_otype_waiting = req;
+									ch->ch_state = CS_IDLE;
+									break;
+								}
+
+							/*
+							 *  Otherwise the server open failed.  If
+							 *  the Unix port is open, hang it up.
+							 */
+
+							default:
+								if (ch->ch_open_count != 0) {
+									ch->ch_flag |= CH_HANGUP;
+									dgrp_carrier(ch);
+									ch->ch_state = CS_IDLE;
+									break;
+								}
+
+								ch->ch_open_error = resp;
+								ch->ch_state = CS_IDLE;
+
+								wake_up_interruptible(&ch->ch_flag_wait);
+							}
+							break;
+						}
+
+						/*
+						 *  Handle delayed response arrival preceeding
+						 *  the open response we are waiting for.
+						 */
+
+						if (ch->ch_otype_waiting != 0 &&
+						    req == ch->ch_otype_waiting &&
+						    resp == 0) {
+							ch->ch_otype = ch->ch_otype_waiting;
+							ch->ch_otype_waiting = 0;
+							ch->ch_state = CS_WAIT_FAIL;
+							break;
+						}
+						goto open_error;
+
+
+					case CS_WAIT_FAIL:
+
+						/*
+						 *  Handle response to immediate open arriving
+						 *  after a delayed open success.
+						 */
+
+						if (req == OTYPE_IMMEDIATE) {
+							ch->ch_state = CS_SEND_QUERY;
+							break;
+						}
+						goto open_error;
+
+
+					case CS_WAIT_CANCEL:
+						/*
+						 *  Handle delayed open response arriving before
+						 *  the cancel response.
+						 */
+
+						if (req == ch->ch_otype_waiting &&
+						    resp == 0) {
+							ch->ch_otype_waiting = 0;
+							break;
+						}
+
+						/*
+						 *  Handle cancel response.
+						 */
+
+						if (req == 4 && resp == 0) {
+							ch->ch_otype_waiting = 0;
+							ch->ch_state = CS_IDLE;
+							break;
+						}
+						goto open_error;
+
+
+					case CS_WAIT_CLOSE:
+						/*
+						 *  Handle a successful response to a port
+						 *  close.
+						 */
+
+						if (req >= 3) {
+							ch->ch_state = CS_IDLE;
+							break;
+						}
+						goto open_error;
+
+open_error:
+					default:
+						{
+							error = "Improper Open Response";
+							goto prot_error;
+						}
+					}
+				}
+				break;
+
+			/*
+			 *  Handle Synchronize Response.
+			 */
+
+			case 13:
+				plen = 3;
+				if (remain < plen)
+					goto done;
+				{
+					int seq = b[2];
+					int s;
+
+					/*
+					 * If channel was waiting for this sync response,
+					 * unset the flag, and wake up anyone waiting
+					 * on the event.
+					 */
+					if (ch->ch_flag & CH_WAITING_SYNC) {
+						ch->ch_flag &= ~(CH_WAITING_SYNC);
+						wake_up_interruptible(&ch->ch_flag_wait);
+					}
+
+					if (((seq - nd->nd_seq_out) & SEQ_MASK) >=
+					    ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) {
+						break;
+					}
+
+					for (s = nd->nd_seq_out;; s = (s + 1) & SEQ_MASK) {
+						if (nd->nd_seq_wait[s] != 0) {
+							nd->nd_seq_wait[s] = 0;
+
+							wake_up_interruptible(&nd->nd_seq_wque[s]);
+						}
+
+						nd->nd_unack -= nd->nd_seq_size[s];
+
+						if (s == seq)
+							break;
+					}
+
+					nd->nd_seq_out = (seq + 1) & SEQ_MASK;
+				}
+				break;
+
+			/*
+			 *  Handle Sequence Response.
+			 */
+
+			case 15:
+				plen = 6;
+				if (remain < plen)
+					goto done;
+
+				{
+				/* Record that we have received the Sequence
+				 * Response, but we aren't interested in the
+				 * sequence numbers.  We were using RIN like it
+				 * was ROUT and that was causing problems,
+				 * fixed 7-13-2001 David Fries. See comment in
+				 * drp.h for ch_s_rin variable.
+					int rin = get_unaligned_be16(b + 2);
+					int tpos = get_unaligned_be16(b + 4);
+				*/
+
+					ch->ch_send   &= ~RR_SEQUENCE;
+					ch->ch_expect &= ~RR_SEQUENCE;
+				}
+				goto check_query;
+
+			/*
+			 *  Handle Status Response.
+			 */
+
+			case 17:
+				plen = 5;
+				if (remain < plen)
+					goto done;
+
+				{
+					ch->ch_s_elast = get_unaligned_be16(b + 2);
+					ch->ch_s_mlast = b[4];
+
+					ch->ch_expect &= ~RR_STATUS;
+					ch->ch_send   &= ~RR_STATUS;
+
+					/*
+					 *  CH_PHYS_CD is cleared because something _could_ be
+					 *  waiting for the initial sense of carrier... and if
+					 *  carrier is high immediately, we want to be sure to
+					 *  wake them as soon as possible.
+					 */
+					ch->ch_flag &= ~CH_PHYS_CD;
+
+					dgrp_carrier(ch);
+				}
+				goto check_query;
+
+			/*
+			 *  Handle Line Error Response.
+			 */
+
+			case 19:
+				plen = 14;
+				if (remain < plen)
+					goto done;
+
+				break;
+
+			/*
+			 *  Handle Buffer Response.
+			 */
+
+			case 21:
+				plen = 6;
+				if (remain < plen)
+					goto done;
+
+				{
+					ch->ch_s_rsize = get_unaligned_be16(b + 2);
+					ch->ch_s_tsize = get_unaligned_be16(b + 4);
+
+					ch->ch_send   &= ~RR_BUFFER;
+					ch->ch_expect &= ~RR_BUFFER;
+				}
+				goto check_query;
+
+			/*
+			 *  Handle Port Capability Response.
+			 */
+
+			case 23:
+				plen = 32;
+				if (remain < plen)
+					goto done;
+
+				{
+					ch->ch_send   &= ~RR_CAPABILITY;
+					ch->ch_expect &= ~RR_CAPABILITY;
+				}
+
+			/*
+			 *  When all queries are complete, set those parameters
+			 *  derived from the query results, then transition
+			 *  to the READY state.
+			 */
+
+check_query:
+				if (ch->ch_state == CS_WAIT_QUERY &&
+				    (ch->ch_expect & (RR_SEQUENCE |
+							RR_STATUS |
+							RR_BUFFER |
+							RR_CAPABILITY)) == 0) {
+					ch->ch_tmax  = ch->ch_s_tsize / 4;
+
+					if (ch->ch_edelay == DGRP_TTIME)
+						ch->ch_ttime = DGRP_TTIME;
+					else
+						ch->ch_ttime = ch->ch_edelay;
+
+					ch->ch_rmax = ch->ch_s_rsize / 4;
+
+					if (ch->ch_edelay == DGRP_RTIME)
+						ch->ch_rtime = DGRP_RTIME;
+					else
+						ch->ch_rtime = ch->ch_edelay;
+
+					ch->ch_rlow  = 2 * ch->ch_s_rsize / 8;
+					ch->ch_rhigh = 6 * ch->ch_s_rsize / 8;
+
+					ch->ch_state = CS_READY;
+
+					nd->nd_tx_work = 1;
+					wake_up_interruptible(&ch->ch_flag_wait);
+
+				}
+				break;
+
+			default:
+				goto decode_error;
+			}
+			break;
+
+		/*
+		 *  Handle Events.
+		 */
+
+		case 12:
+			plen = 4;
+			if (remain < plen)
+				goto done;
+
+			mlast = ch->ch_s_mlast;
+			elast = ch->ch_s_elast;
+
+			mstat = ch->ch_s_mlast = b[1];
+			estat = ch->ch_s_elast = get_unaligned_be16(b + 2);
+
+			/*
+			 *  Handle modem changes.
+			 */
+
+			if (((mstat ^ mlast) & DM_CD) != 0)
+				dgrp_carrier(ch);
+
+
+			/*
+			 *  Handle received break.
+			 */
+
+			if ((estat & ~elast & EV_RXB) != 0 &&
+			    (ch->ch_tun.un_open_count != 0) &&
+			    I_BRKINT(ch->ch_tun.un_tty) &&
+			    !(I_IGNBRK(ch->ch_tun.un_tty))) {
+
+				tty_buffer_request_room(ch->ch_tun.un_tty, 1);
+				tty_insert_flip_char(ch->ch_tun.un_tty, 0, TTY_BREAK);
+				tty_flip_buffer_push(ch->ch_tun.un_tty);
+
+			}
+
+			/*
+			 *  On transmit break complete, if more break traffic
+			 *  is waiting then send it.  Otherwise wake any threads
+			 *  waiting for transmitter empty.
+			 */
+
+			if ((~estat & elast & EV_TXB) != 0 &&
+			    (ch->ch_expect & RR_TX_BREAK) != 0) {
+
+				nd->nd_tx_work = 1;
+
+				ch->ch_expect &= ~RR_TX_BREAK;
+
+				if (ch->ch_break_time != 0) {
+					ch->ch_send |= RR_TX_BREAK;
+				} else {
+					ch->ch_send &= ~RR_TX_BREAK;
+					ch->ch_flag &= ~CH_TX_BREAK;
+					wake_up_interruptible(&ch->ch_flag_wait);
+				}
+			}
+			break;
+
+		case 13:
+		case 14:
+			error = "Unrecognized command";
+			goto prot_error;
+
+		/*
+		 *  Decode Special Codes.
+		 */
+
+		case 15:
+			switch (n1) {
+			/*
+			 *  One byte module select.
+			 */
+
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				plen = 1;
+				nd->nd_rx_module = n1;
+				break;
+
+			/*
+			 *  Two byte module select.
+			 */
+
+			case 8:
+				plen = 2;
+				if (remain < plen)
+					goto done;
+
+				nd->nd_rx_module = b[1];
+				break;
+
+			/*
+			 *  ID Request packet.
+			 */
+
+			case 11:
+				if (remain < 4)
+					goto done;
+
+				plen = get_unaligned_be16(b + 2);
+
+				if (plen < 12 || plen > 1000) {
+					error = "Response Packet length error";
+					goto prot_error;
+				}
+
+				nd->nd_tx_work = 1;
+
+				switch (b[1]) {
+				/*
+				 *  Echo packet.
+				 */
+
+				case 0:
+					nd->nd_send |= NR_ECHO;
+					break;
+
+				/*
+				 *  ID Response packet.
+				 */
+
+				case 1:
+					nd->nd_send |= NR_IDENT;
+					break;
+
+				/*
+				 *  ID Response packet.
+				 */
+
+				case 32:
+					nd->nd_send |= NR_PASSWORD;
+					break;
+
+				}
+				break;
+
+			/*
+			 *  Various node-level response packets.
+			 */
+
+			case 12:
+				if (remain < 4)
+					goto done;
+
+				plen = get_unaligned_be16(b + 2);
+
+				if (plen < 4 || plen > 1000) {
+					error = "Response Packet length error";
+					goto prot_error;
+				}
+
+				nd->nd_tx_work = 1;
+
+				switch (b[1]) {
+				/*
+				 *  Echo packet.
+				 */
+
+				case 0:
+					nd->nd_expect &= ~NR_ECHO;
+					break;
+
+				/*
+				 *  Product Response Packet.
+				 */
+
+				case 1:
+					{
+						int desclen;
+
+						nd->nd_hw_ver = (b[8] << 8) | b[9];
+						nd->nd_sw_ver = (b[10] << 8) | b[11];
+						nd->nd_hw_id = b[6];
+						desclen = ((plen - 12) > MAX_DESC_LEN) ? MAX_DESC_LEN :
+							plen - 12;
+
+						if (desclen <= 0) {
+							error = "Response Packet desclen error";
+							goto prot_error;
+						}
+
+						strncpy(nd->nd_ps_desc, b + 12, desclen);
+						nd->nd_ps_desc[desclen] = 0;
+					}
+
+					nd->nd_expect &= ~NR_IDENT;
+					break;
+
+				/*
+				 *  Capability Response Packet.
+				 */
+
+				case 2:
+					{
+						int nn = get_unaligned_be16(b + 4);
+
+						if (nn > CHAN_MAX)
+							nn = CHAN_MAX;
+
+						dgrp_chan_count(nd, nn);
+					}
+
+					nd->nd_expect &= ~NR_CAPABILITY;
+					break;
+
+				/*
+				 *  VPD Response Packet.
+				 */
+
+				case 15:
+					/*
+					 * NOTE: case 15 is here ONLY because the EtherLite
+					 * is broken, and sends a response to 24 back as 15.
+					 * To resolve this, the EtherLite firmware is now
+					 * fixed to send back 24 correctly, but, for backwards
+					 * compatibility, we now have reserved 15 for the
+					 * bad EtherLite response to 24 as well.
+					 */
+
+					/* Fallthru! */
+
+				case 24:
+
+					/*
+					 * If the product doesn't support VPD,
+					 * it will send back a null IDRESP,
+					 * which is a length of 4 bytes.
+					 */
+					if (plen > 4) {
+						memcpy(nd->nd_vpd, b + 4, min(plen - 4, (long) VPDSIZE));
+						nd->nd_vpd_len = min(plen - 4, (long) VPDSIZE);
+					}
+
+					nd->nd_expect &= ~NR_VPD;
+					break;
+
+				default:
+					goto decode_error;
+				}
+
+				if (nd->nd_expect == 0 &&
+				    nd->nd_state == NS_WAIT_QUERY) {
+					nd->nd_state = NS_READY;
+				}
+				break;
+
+			/*
+			 *  Debug packet.
+			 */
+
+			case 14:
+				if (remain < 4)
+					goto done;
+
+				plen = get_unaligned_be16(b + 2) + 4;
+
+				if (plen > 1000) {
+					error = "Debug Packet too large";
+					goto prot_error;
+				}
+
+				if (remain < plen)
+					goto done;
+				break;
+
+			/*
+			 *  Handle reset packet.
+			 */
+
+			case 15:
+				if (remain < 2)
+					goto done;
+
+				plen = 2 + b[1];
+
+				if (remain < plen)
+					goto done;
+
+				nd->nd_tx_work = 1;
+
+				n = b[plen];
+				b[plen] = 0;
+
+				b[plen] = n;
+
+				error = "Client Reset Acknowledge";
+				goto prot_error;
+
+			default:
+				goto decode_error;
+			}
+			break;
+
+		default:
+			goto decode_error;
+		}
+
+		b += plen;
+		remain -= plen;
+	}
+
+	/*
+	 *  When the buffer is exhausted, copy any data left at the
+	 *  top of the buffer back down to the bottom for the next
+	 *  read request.
+	 */
+
+done:
+	if (remain > 0 && b != buf)
+		memcpy(buf, b, remain);
+
+	nd->nd_remain = remain;
+	return;
+
+/*
+ *  Handle a decode error.
+ */
+
+decode_error:
+	error = "Protocol decode error";
+
+/*
+ *  Handle a general protocol error.
+ */
+
+prot_error:
+	nd->nd_remain = 0;
+	nd->nd_state = NS_SEND_ERROR;
+	nd->nd_error = error;
+}
+
+/*
+ * dgrp_net_write() -- write data to the network device.
+ *
+ * A zero byte write indicates that the connection to the RealPort
+ * device has been broken.
+ *
+ * A non-zero write indicates data from the RealPort device.
+ */
+static ssize_t dgrp_net_write(struct file *file, const char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct nd_struct *nd;
+	ssize_t rtn = 0;
+	long n;
+	long total = 0;
+
+	/*
+	 *  Get the node pointer, and quit if it doesn't exist.
+	 */
+	nd = (struct nd_struct *)(file->private_data);
+	if (!nd)
+		return -ENXIO;
+
+	/*
+	 *  Grab the NET lock.
+	 */
+	down(&nd->nd_net_semaphore);
+
+	nd->nd_write_count++;
+
+	/*
+	 *  Handle disconnect.
+	 */
+
+	if (count == 0) {
+		dgrp_net_idle(nd);
+		/*
+		 *  Set the active port count to zero.
+		 */
+		dgrp_chan_count(nd, 0);
+		goto unlock;
+	}
+
+	/*
+	 *  Loop to process entire receive packet.
+	 */
+
+	while (count > 0) {
+		n = UIO_MAX - nd->nd_remain;
+
+		if (n > count)
+			n = count;
+
+		nd->nd_rx_byte += n + nd->nd_link.lk_header_size;
+
+		rtn = copy_from_user(nd->nd_iobuf + nd->nd_remain,
+				     (void __user *) buf + total, n);
+		if (rtn) {
+			rtn = -EFAULT;
+			goto unlock;
+		}
+
+		*ppos += n;
+
+		total += n;
+
+		count -= n;
+
+		if (nd->nd_mon_buf)
+			dgrp_monitor_data(nd, RPDUMP_SERVER,
+					  nd->nd_iobuf + nd->nd_remain, n);
+
+		nd->nd_remain += n;
+
+		dgrp_receive(nd);
+	}
+
+	rtn = total;
+
+unlock:
+	/*
+	 *  Release the NET lock.
+	 */
+	up(&nd->nd_net_semaphore);
+
+	return rtn;
+}
+
+
+/*
+ * dgrp_net_select()
+ *  Determine whether a device is ready to be read or written to, and
+ *  sleep if not.
+ */
+static unsigned int dgrp_net_select(struct file *file,
+				    struct poll_table_struct *table)
+{
+	unsigned int retval = 0;
+	struct nd_struct *nd = file->private_data;
+
+	poll_wait(file, &nd->nd_tx_waitq, table);
+
+	if (nd->nd_tx_ready)
+		retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
+
+	retval |= POLLOUT | POLLWRNORM;        /* Always writeable */
+
+	return retval;
+}
+
+/*
+ * dgrp_net_ioctl
+ *
+ * Implement those functions which allow the network daemon to control
+ * the network parameters in the driver.  The ioctls include ones to
+ * get and set the link speed parameters for the PortServer.
+ */
+static long dgrp_net_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct nd_struct  *nd;
+	int    rtn = 0;
+	long   size = _IOC_SIZE(cmd);
+	struct link_struct link;
+
+	nd = file->private_data;
+
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		rtn = access_ok(VERIFY_WRITE, (void __user *) arg, size);
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		rtn = access_ok(VERIFY_READ,  (void __user *) arg, size);
+
+	if (!rtn)
+		return rtn;
+
+	switch (cmd) {
+	case DIGI_SETLINK:
+		if (size != sizeof(struct link_struct))
+			return -EINVAL;
+
+		if (copy_from_user((void *)(&link), (void __user *) arg, size))
+			return -EFAULT;
+
+		if (link.lk_fast_rate < 9600)
+			link.lk_fast_rate = 9600;
+
+		if (link.lk_slow_rate < 2400)
+			link.lk_slow_rate = 2400;
+
+		if (link.lk_fast_rate > 10000000)
+			link.lk_fast_rate = 10000000;
+
+		if (link.lk_slow_rate > link.lk_fast_rate)
+			link.lk_slow_rate = link.lk_fast_rate;
+
+		if (link.lk_fast_delay > 2000)
+			link.lk_fast_delay = 2000;
+
+		if (link.lk_slow_delay > 10000)
+			link.lk_slow_delay = 10000;
+
+		if (link.lk_fast_delay < 60)
+			link.lk_fast_delay = 60;
+
+		if (link.lk_slow_delay < link.lk_fast_delay)
+			link.lk_slow_delay = link.lk_fast_delay;
+
+		if (link.lk_header_size < 2)
+			link.lk_header_size = 2;
+
+		if (link.lk_header_size > 128)
+			link.lk_header_size = 128;
+
+		link.lk_fast_rate /= 8 * 1000 / dgrp_poll_tick;
+		link.lk_slow_rate /= 8 * 1000 / dgrp_poll_tick;
+
+		link.lk_fast_delay /= dgrp_poll_tick;
+		link.lk_slow_delay /= dgrp_poll_tick;
+
+		nd->nd_link = link;
+
+		break;
+
+	case DIGI_GETLINK:
+		if (size != sizeof(struct link_struct))
+			return -EINVAL;
+
+		if (copy_to_user((void __user *)arg, (void *)(&nd->nd_link),
+				 size))
+			return -EFAULT;
+
+		break;
+
+	default:
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+/**
+ * dgrp_poll_handler() -- handler for poll timer
+ *
+ * As each timer expires, it determines (a) whether the "transmit"
+ * waiter needs to be woken up, and (b) whether the poller needs to
+ * be rescheduled.
+ */
+void dgrp_poll_handler(unsigned long arg)
+{
+	struct dgrp_poll_data *poll_data;
+	struct nd_struct *nd;
+	struct link_struct *lk;
+	ulong time;
+	ulong poll_time;
+	ulong freq;
+	ulong lock_flags;
+
+	poll_data = (struct dgrp_poll_data *) arg;
+	freq = 1000 / poll_data->poll_tick;
+	poll_data->poll_round += 17;
+
+	if (poll_data->poll_round >= freq)
+		poll_data->poll_round -= freq;
+
+	/*
+	 * Loop to process all open nodes.
+	 *
+	 * For each node, determine the rate at which it should
+	 * be transmitting data.  Then if the node should wake up
+	 * and transmit data now, enable the net receive select
+	 * to get the transmit going.
+	 */
+
+	list_for_each_entry(nd, &nd_struct_list, list) {
+
+		lk = &nd->nd_link;
+
+		/*
+		 * Decrement statistics.  These are only for use with
+		 * KME, so don't worry that the operations are done
+		 * unlocked, and so the results are occassionally wrong.
+		 */
+
+		nd->nd_read_count -= (nd->nd_read_count +
+				      poll_data->poll_round) / freq;
+		nd->nd_write_count -= (nd->nd_write_count +
+				       poll_data->poll_round) / freq;
+		nd->nd_send_count -= (nd->nd_send_count +
+				      poll_data->poll_round) / freq;
+		nd->nd_tx_byte -= (nd->nd_tx_byte +
+				   poll_data->poll_round) / freq;
+		nd->nd_rx_byte -= (nd->nd_rx_byte +
+				   poll_data->poll_round) / freq;
+
+		/*
+		 * Wake the daemon to transmit data only when there is
+		 * enough byte credit to send data.
+		 *
+		 * The results are approximate because the operations
+		 * are performed unlocked, and we are inspecting
+		 * data asynchronously updated elsewhere.  The whole
+		 * thing is just approximation anyway, so that should
+		 * be okay.
+		 */
+
+		if (lk->lk_slow_rate >= UIO_MAX) {
+
+			nd->nd_delay = 0;
+			nd->nd_rate = UIO_MAX;
+
+			nd->nd_tx_deposit = nd->nd_tx_charge + 3 * UIO_MAX;
+			nd->nd_tx_credit  = 3 * UIO_MAX;
+
+		} else {
+
+			long rate;
+			long delay;
+			long deposit;
+			long charge;
+			long size;
+			long excess;
+
+			long seq_in = nd->nd_seq_in;
+			long seq_out = nd->nd_seq_out;
+
+			/*
+			 * If there are no outstanding packets, run at the
+			 * fastest rate.
+			 */
+
+			if (seq_in == seq_out) {
+				delay = 0;
+				rate = lk->lk_fast_rate;
+			}
+
+			/*
+			 * Otherwise compute the transmit rate based on the
+			 * delay since the oldest packet.
+			 */
+
+			else {
+				/*
+				 * The actual delay is computed as the
+				 * time since the oldest unacknowledged
+				 * packet was sent, minus the time it
+				 * took to send that packet to the server.
+				 */
+
+				delay = ((jiffies - nd->nd_seq_time[seq_out])
+					- (nd->nd_seq_size[seq_out] /
+					lk->lk_fast_rate));
+
+				/*
+				 * If the delay is less than the "fast"
+				 * delay, transmit full speed.  If greater
+				 * than the "slow" delay, transmit at the
+				 * "slow" speed.   In between, interpolate
+				 * between the fast and slow speeds.
+				 */
+
+				rate =
+				  (delay <= lk->lk_fast_delay ?
+				    lk->lk_fast_rate :
+				    delay >= lk->lk_slow_delay ?
+				      lk->lk_slow_rate :
+				      (lk->lk_slow_rate +
+				       (lk->lk_slow_delay - delay) *
+				       (lk->lk_fast_rate - lk->lk_slow_rate) /
+				       (lk->lk_slow_delay - lk->lk_fast_delay)
+				      )
+				  );
+			}
+
+			nd->nd_delay = delay;
+			nd->nd_rate = rate;
+
+			/*
+			 * Increase the transmit credit by depositing the
+			 * current transmit rate.
+			 */
+
+			deposit = nd->nd_tx_deposit;
+			charge  = nd->nd_tx_charge;
+
+			deposit += rate;
+
+			/*
+			 * If the available transmit credit becomes too large,
+			 * reduce the deposit to correct the value.
+			 *
+			 * Too large is the max of:
+			 *		6 times the header size
+			 *		3 times the current transmit rate.
+			 */
+
+			size = 2 * nd->nd_link.lk_header_size;
+
+			if (size < rate)
+				size = rate;
+
+			size *= 3;
+
+			excess = deposit - charge - size;
+
+			if (excess > 0)
+				deposit -= excess;
+
+			nd->nd_tx_deposit = deposit;
+			nd->nd_tx_credit  = deposit - charge;
+
+			/*
+			 * Wake the transmit task only if the transmit credit
+			 * is at least 3 times the transmit header size.
+			 */
+
+			size = 3 * lk->lk_header_size;
+
+			if (nd->nd_tx_credit < size)
+				continue;
+		}
+
+
+		/*
+		 * Enable the READ select to wake the daemon if there
+		 * is useful work for the drp_read routine to perform.
+		 */
+
+		if (waitqueue_active(&nd->nd_tx_waitq) &&
+		    (nd->nd_tx_work != 0 ||
+		    (ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX)) {
+			nd->nd_tx_ready = 1;
+
+			wake_up_interruptible(&nd->nd_tx_waitq);
+
+			/* not needed */
+			/* nd->nd_flag &= ~ND_SELECT; */
+		}
+	}
+
+
+	/*
+	 * Schedule ourself back at the nominal wakeup interval.
+	 */
+	spin_lock_irqsave(&poll_data->poll_lock, lock_flags);
+
+	poll_data->node_active_count--;
+	if (poll_data->node_active_count > 0) {
+		poll_data->node_active_count++;
+		poll_time = poll_data->timer.expires +
+			poll_data->poll_tick * HZ / 1000;
+
+		time = poll_time - jiffies;
+
+		if (time >= 2 * poll_data->poll_tick)
+			poll_time = jiffies + dgrp_poll_tick * HZ / 1000;
+
+		poll_data->timer.expires = poll_time;
+		add_timer(&poll_data->timer);
+	}
+
+	spin_unlock_irqrestore(&poll_data->poll_lock, lock_flags);
+}
diff --git a/drivers/staging/dgrp/dgrp_ports_ops.c b/drivers/staging/dgrp/dgrp_ports_ops.c
new file mode 100644
index 0000000..cd1fc20
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_ports_ops.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 1999-2000 Digi International (www.digi.com)
+ *     James Puzzo <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_ports_ops.c
+ *
+ *  Description:
+ *
+ *     Handle the file operations required for the /proc/dgrp/ports/...
+ *     devices.  Basically gathers tty status for the node and returns it.
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_ports_open(struct inode *, struct file *);
+
+static const struct file_operations ports_ops = {
+	.owner   = THIS_MODULE,
+	.open    = dgrp_ports_open,
+	.read    = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release
+};
+
+static struct inode_operations ports_inode_ops = {
+	.permission = dgrp_inode_permission
+};
+
+
+void dgrp_register_ports_hook(struct proc_dir_entry *de)
+{
+	struct nd_struct *node = de->data;
+
+	de->proc_iops = &ports_inode_ops;
+	de->proc_fops = &ports_ops;
+	node->nd_ports_de = de;
+}
+
+static void *dgrp_ports_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos == 0)
+		seq_puts(seq, "#num tty_open pr_open tot_wait MSTAT  IFLAG  OFLAG  CFLAG  BPS    DIGIFLAGS\n");
+
+	return pos;
+}
+
+static void *dgrp_ports_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct nd_struct *nd = seq->private;
+
+	if (*pos >= nd->nd_chan_count)
+		return NULL;
+
+	*pos += 1;
+
+	return pos;
+}
+
+static void dgrp_ports_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int dgrp_ports_seq_show(struct seq_file *seq, void *v)
+{
+	loff_t *pos = v;
+	struct nd_struct *nd;
+	struct ch_struct *ch;
+	struct un_struct *tun, *pun;
+	unsigned int totcnt;
+
+	nd = seq->private;
+	if (!nd)
+		return 0;
+
+	if (*pos >= nd->nd_chan_count)
+		return 0;
+
+	ch = &nd->nd_chan[*pos];
+	tun = &ch->ch_tun;
+	pun = &ch->ch_pun;
+
+	/*
+	 * If port is not open and no one is waiting to
+	 * open it, the modem signal values can't be
+	 * trusted, and will be zeroed.
+	 */
+	totcnt = tun->un_open_count +
+		pun->un_open_count +
+		ch->ch_wait_count[0] +
+		ch->ch_wait_count[1] +
+		ch->ch_wait_count[2];
+
+	seq_printf(seq, "%02d      %02d      %02d      %02d     0x%04X 0x%04X 0x%04X 0x%04X %-6d 0x%04X\n",
+		   (int) *pos,
+		   tun->un_open_count,
+		   pun->un_open_count,
+		   ch->ch_wait_count[0] +
+		   ch->ch_wait_count[1] +
+		   ch->ch_wait_count[2],
+		   (totcnt ? ch->ch_s_mlast : 0),
+		   ch->ch_s_iflag,
+		   ch->ch_s_oflag,
+		   ch->ch_s_cflag,
+		   (ch->ch_s_brate ? (1843200 / ch->ch_s_brate) : 0),
+		   ch->ch_digi.digi_flags);
+
+	return 0;
+}
+
+static const struct seq_operations ports_seq_ops = {
+	.start = dgrp_ports_seq_start,
+	.next  = dgrp_ports_seq_next,
+	.stop  = dgrp_ports_seq_stop,
+	.show  = dgrp_ports_seq_show,
+};
+
+/**
+ * dgrp_ports_open -- open the /proc/dgrp/ports/... device
+ * @inode: struct inode *
+ * @file: struct file *
+ *
+ * Open function to open the /proc/dgrp/ports device for a PortServer.
+ * This is the open function for struct file_operations
+ */
+static int dgrp_ports_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rtn;
+
+	rtn = seq_open(file, &ports_seq_ops);
+	if (!rtn) {
+		seq = file->private_data;
+		seq->private = PDE(inode)->data;
+	}
+
+	return rtn;
+}
diff --git a/drivers/staging/dgrp/dgrp_specproc.c b/drivers/staging/dgrp/dgrp_specproc.c
new file mode 100644
index 0000000..28f5c9a
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_specproc.c
@@ -0,0 +1,822 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     James Puzzo  <jamesp at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_specproc.c
+ *
+ *  Description:
+ *
+ *     Handle the "config" proc entry for the linux realport device driver
+ *     and provide slots for the "net" and "mon" devices
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+
+#include "dgrp_common.h"
+
+static struct dgrp_proc_entry dgrp_table[];
+static struct proc_dir_entry *dgrp_proc_dir_entry;
+
+static int dgrp_add_id(long id);
+static int dgrp_remove_nd(struct nd_struct *nd);
+static void unregister_dgrp_device(struct proc_dir_entry *de);
+static void register_dgrp_device(struct nd_struct *node,
+				 struct proc_dir_entry *root,
+				 void (*register_hook)(struct proc_dir_entry *de));
+
+/* File operation declarations */
+static int dgrp_gen_proc_open(struct inode *, struct file *);
+static int dgrp_gen_proc_close(struct inode *, struct file *);
+static int parse_write_config(char *);
+
+
+static const struct file_operations dgrp_proc_file_ops = {
+	.owner   = THIS_MODULE,
+	.open    = dgrp_gen_proc_open,
+	.release = dgrp_gen_proc_close,
+};
+
+static struct inode_operations proc_inode_ops = {
+	.permission = dgrp_inode_permission
+};
+
+
+static void register_proc_table(struct dgrp_proc_entry *,
+				struct proc_dir_entry *);
+static void unregister_proc_table(struct dgrp_proc_entry *,
+				  struct proc_dir_entry *);
+
+static struct dgrp_proc_entry dgrp_net_table[];
+static struct dgrp_proc_entry dgrp_mon_table[];
+static struct dgrp_proc_entry dgrp_ports_table[];
+static struct dgrp_proc_entry dgrp_dpa_table[];
+
+static ssize_t config_proc_write(struct file *file, const char __user *buffer,
+				 size_t count, loff_t *pos);
+
+static int nodeinfo_proc_open(struct inode *inode, struct file *file);
+static int info_proc_open(struct inode *inode, struct file *file);
+static int config_proc_open(struct inode *inode, struct file *file);
+
+static struct file_operations config_proc_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = config_proc_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+	.write   = config_proc_write
+};
+
+static struct file_operations info_proc_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = info_proc_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+};
+
+static struct file_operations nodeinfo_proc_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = nodeinfo_proc_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+};
+
+static struct dgrp_proc_entry dgrp_table[] = {
+	{
+		.id = DGRP_CONFIG,
+		.name = "config",
+		.mode = 0644,
+		.proc_file_ops = &config_proc_file_ops,
+	},
+	{
+		.id = DGRP_INFO,
+		.name = "info",
+		.mode = 0644,
+		.proc_file_ops = &info_proc_file_ops,
+	},
+	{
+		.id = DGRP_NODEINFO,
+		.name = "nodeinfo",
+		.mode = 0644,
+		.proc_file_ops = &nodeinfo_proc_file_ops,
+	},
+	{
+		.id = DGRP_NETDIR,
+		.name = "net",
+		.mode = 0500,
+		.child = dgrp_net_table
+	},
+	{
+		.id = DGRP_MONDIR,
+		.name = "mon",
+		.mode = 0500,
+		.child = dgrp_mon_table
+	},
+	{
+		.id = DGRP_PORTSDIR,
+		.name = "ports",
+		.mode = 0500,
+		.child = dgrp_ports_table
+	},
+	{
+		.id = DGRP_DPADIR,
+		.name = "dpa",
+		.mode = 0500,
+		.child = dgrp_dpa_table
+	}
+};
+
+static struct proc_dir_entry *net_entry_pointer;
+static struct proc_dir_entry *mon_entry_pointer;
+static struct proc_dir_entry *dpa_entry_pointer;
+static struct proc_dir_entry *ports_entry_pointer;
+
+static struct dgrp_proc_entry dgrp_net_table[] = {
+	{0}
+};
+
+static struct dgrp_proc_entry dgrp_mon_table[] = {
+	{0}
+};
+
+static struct dgrp_proc_entry dgrp_ports_table[] = {
+	{0}
+};
+
+static struct dgrp_proc_entry dgrp_dpa_table[] = {
+	{0}
+};
+
+void dgrp_unregister_proc(void)
+{
+	unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
+	net_entry_pointer = NULL;
+	mon_entry_pointer = NULL;
+	dpa_entry_pointer = NULL;
+	ports_entry_pointer = NULL;
+
+	if (dgrp_proc_dir_entry) {
+		remove_proc_entry(dgrp_proc_dir_entry->name,
+				  dgrp_proc_dir_entry->parent);
+		dgrp_proc_dir_entry = NULL;
+	}
+
+}
+
+void dgrp_register_proc(void)
+{
+	/*
+	 *	Register /proc/dgrp
+	 */
+	dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
+					  &dgrp_proc_file_ops);
+	register_proc_table(dgrp_table, dgrp_proc_dir_entry);
+}
+
+/*
+ * /proc/sys support
+ */
+static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
+{
+	if (!de || !de->low_ino)
+		return 0;
+	if (de->namelen != len)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
+
+
+/*
+ *  Scan the entries in table and add them all to /proc at the position
+ *  referred to by "root"
+ */
+static void register_proc_table(struct dgrp_proc_entry *table,
+				struct proc_dir_entry *root)
+{
+	struct proc_dir_entry *de;
+	int len;
+	mode_t mode;
+
+	for (; table->id; table++) {
+		/* Can't do anything without a proc name. */
+		if (!table->name)
+			continue;
+
+		/* Maybe we can't do anything with it... */
+		if (!table->proc_file_ops &&
+		    !table->child) {
+			pr_warn("dgrp: Can't register %s\n",
+				table->name);
+			continue;
+		}
+
+		len = strlen(table->name);
+		mode = table->mode;
+
+		de = NULL;
+		if (!table->child)
+			mode |= S_IFREG;
+		else {
+			mode |= S_IFDIR;
+			for (de = root->subdir; de; de = de->next) {
+				if (dgrp_proc_match(len, table->name, de))
+					break;
+			}
+			/* If the subdir exists already, de is non-NULL */
+		}
+
+		if (!de) {
+			de = create_proc_entry(table->name, mode, root);
+			if (!de)
+				continue;
+			de->data = (void *) table;
+			if (!table->child) {
+				de->proc_iops = &proc_inode_ops;
+				if (table->proc_file_ops)
+					de->proc_fops = table->proc_file_ops;
+				else
+					de->proc_fops = &dgrp_proc_file_ops;
+			}
+		}
+		table->de = de;
+		if (de->mode & S_IFDIR)
+			register_proc_table(table->child, de);
+
+		if (table->id == DGRP_NETDIR)
+			net_entry_pointer = de;
+
+		if (table->id == DGRP_MONDIR)
+			mon_entry_pointer = de;
+
+		if (table->id == DGRP_DPADIR)
+			dpa_entry_pointer = de;
+
+		if (table->id == DGRP_PORTSDIR)
+			ports_entry_pointer = de;
+	}
+}
+
+/*
+ * Unregister a /proc sysctl table and any subdirectories.
+ */
+static void unregister_proc_table(struct dgrp_proc_entry *table,
+				  struct proc_dir_entry *root)
+{
+	struct proc_dir_entry *de;
+	struct nd_struct *tmp;
+
+	list_for_each_entry(tmp, &nd_struct_list, list) {
+		if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
+			unregister_dgrp_device(tmp->nd_net_de);
+			dgrp_remove_node_class_sysfs_files(tmp);
+		}
+
+		if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
+			unregister_dgrp_device(tmp->nd_mon_de);
+
+		if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
+			unregister_dgrp_device(tmp->nd_dpa_de);
+
+		if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
+			unregister_dgrp_device(tmp->nd_ports_de);
+	}
+
+	for (; table->id; table++) {
+		de = table->de;
+
+		if (!de)
+			continue;
+		if (de->mode & S_IFDIR) {
+			if (!table->child) {
+				pr_alert("dgrp: malformed sysctl tree on free\n");
+				continue;
+			}
+			unregister_proc_table(table->child, de);
+
+	/* Don't unregister directories which still have entries */
+			if (de->subdir)
+				continue;
+		}
+
+		/* Don't unregister proc entries that are still being used.. */
+		if ((atomic_read(&de->count)) != 1) {
+			pr_alert("proc entry %s in use, not removing\n",
+				de->name);
+			continue;
+		}
+
+		remove_proc_entry(de->name, de->parent);
+		table->de = NULL;
+	}
+}
+
+static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
+{
+	struct proc_dir_entry *de;
+	struct dgrp_proc_entry *entry;
+	int ret = 0;
+
+	de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
+	if (!de || !de->data) {
+		ret = -ENXIO;
+		goto done;
+	}
+
+	entry = (struct dgrp_proc_entry *) de->data;
+	if (!entry) {
+		ret = -ENXIO;
+		goto done;
+	}
+
+	down(&entry->excl_sem);
+
+	if (entry->excl_cnt)
+		ret = -EBUSY;
+	else
+		entry->excl_cnt++;
+
+	up(&entry->excl_sem);
+
+done:
+	return ret;
+}
+
+static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
+{
+	struct proc_dir_entry *de;
+	struct dgrp_proc_entry *entry;
+
+	de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
+	if (!de || !de->data)
+		goto done;
+
+	entry = (struct dgrp_proc_entry *) de->data;
+	if (!entry)
+		goto done;
+
+	down(&entry->excl_sem);
+
+	if (entry->excl_cnt)
+		entry->excl_cnt = 0;
+
+	up(&entry->excl_sem);
+
+done:
+	return 0;
+}
+
+static void *config_proc_start(struct seq_file *m, loff_t *pos)
+{
+	return seq_list_start_head(&nd_struct_list, *pos);
+}
+
+static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &nd_struct_list, pos);
+}
+
+static void config_proc_stop(struct seq_file *m, void *v)
+{
+}
+
+static int config_proc_show(struct seq_file *m, void *v)
+{
+	struct nd_struct *nd;
+	char tmp_id[4];
+
+	if (v == &nd_struct_list) {
+		seq_puts(m, "#-----------------------------------------------------------------------------\n");
+		seq_puts(m, "#                        Avail\n");
+		seq_puts(m, "# ID  Major  State       Ports\n");
+		return 0;
+	}
+
+	nd = list_entry(v, struct nd_struct, list);
+
+	ID_TO_CHAR(nd->nd_ID, tmp_id);
+
+	seq_printf(m, "  %-2.2s  %-5ld  %-10.10s  %-5d\n",
+		   tmp_id,
+		   nd->nd_major,
+		   ND_STATE_STR(nd->nd_state),
+		   nd->nd_chan_count);
+
+	return 0;
+}
+
+static const struct seq_operations proc_config_ops = {
+	.start = config_proc_start,
+	.next  = config_proc_next,
+	.stop  = config_proc_stop,
+	.show  = config_proc_show
+};
+
+static int config_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &proc_config_ops);
+}
+
+
+/*
+ *  When writing configuration information, each "record" (i.e. each
+ *  write) is treated as an independent request.  See the "parse"
+ *  description for more details.
+ */
+static ssize_t config_proc_write(struct file *file, const char __user *buffer,
+				 size_t count, loff_t *pos)
+{
+	ssize_t retval;
+	char *inbuf, *sp;
+	char *line, *ldelim;
+
+	if (count > 32768)
+		return -EINVAL;
+
+	inbuf = sp = vzalloc(count + 1);
+	if (!inbuf)
+		return -ENOMEM;
+
+	if (copy_from_user(inbuf, buffer, count)) {
+		retval = -EFAULT;
+		goto done;
+	}
+
+	inbuf[count] = 0;
+
+	ldelim = "\n";
+
+	line = strpbrk(sp, ldelim);
+	while (line) {
+		*line = 0;
+		retval = parse_write_config(sp);
+		if (retval)
+			goto done;
+
+		sp = line + 1;
+		line = strpbrk(sp, ldelim);
+	}
+
+	retval = count;
+done:
+	vfree(inbuf);
+	return retval;
+}
+
+/*
+ *  ------------------------------------------------------------------------
+ *
+ *  The following are the functions to parse input
+ *
+ *  ------------------------------------------------------------------------
+ */
+static inline char *skip_past_ws(const char *str)
+{
+	while ((*str) && !isspace(*str))
+		++str;
+
+	return skip_spaces(str);
+}
+
+static int parse_id(char **c, char *cID)
+{
+	int tmp = **c;
+
+	if (isalnum(tmp) || (tmp == '_'))
+		cID[0] = tmp;
+	else
+		return -EINVAL;
+
+	(*c)++; tmp = **c;
+
+	if (isalnum(tmp) || (tmp == '_')) {
+		cID[1] = tmp;
+		(*c)++;
+	} else
+		cID[1] = 0;
+
+	return 0;
+}
+
+static int parse_add_config(char *buf)
+{
+	char *c = buf;
+	int  retval;
+	char cID[2];
+	long ID;
+
+	c = skip_past_ws(c);
+
+	retval = parse_id(&c, cID);
+	if (retval < 0)
+		return retval;
+
+	ID = CHAR_TO_ID(cID);
+
+	c = skip_past_ws(c);
+
+	return dgrp_add_id(ID);
+}
+
+static int parse_del_config(char *buf)
+{
+	char *c = buf;
+	int  retval;
+	struct nd_struct *nd;
+	char cID[2];
+	long ID;
+	long major;
+
+	c = skip_past_ws(c);
+
+	retval = parse_id(&c, cID);
+	if (retval < 0)
+		return retval;
+
+	ID = CHAR_TO_ID(cID);
+
+	c = skip_past_ws(c);
+
+	retval = kstrtol(c, 10, &major);
+	if (retval)
+		return retval;
+
+	nd = nd_struct_get(major);
+	if (!nd)
+		return -EINVAL;
+
+	if ((nd->nd_major != major) || (nd->nd_ID != ID))
+		return -EINVAL;
+
+	return dgrp_remove_nd(nd);
+}
+
+static int parse_chg_config(char *buf)
+{
+	return -EINVAL;
+}
+
+/*
+ *  The passed character buffer represents a single configuration request.
+ *  If the first character is a "+", it is parsed as a request to add a
+ *     PortServer
+ *  If the first character is a "-", it is parsed as a request to delete a
+ *     PortServer
+ *  If the first character is a "*", it is parsed as a request to change a
+ *     PortServer
+ *  Any other character (including whitespace) causes the record to be
+ *     ignored.
+ */
+static int parse_write_config(char *buf)
+{
+	int retval;
+
+	switch (buf[0]) {
+	case '+':
+		retval = parse_add_config(buf);
+		break;
+	case '-':
+		retval = parse_del_config(buf);
+		break;
+	case '*':
+		retval = parse_chg_config(buf);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+static int info_proc_show(struct seq_file *m, void *v)
+{
+	seq_printf(m, "version: %s\n", DIGI_VERSION);
+	seq_puts(m, "register_with_sysfs: 1\n");
+	seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
+		   dgrp_rawreadok, dgrp_rawreadok);
+	seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
+		   dgrp_poll_tick, dgrp_poll_tick);
+
+	return 0;
+}
+
+static int info_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, info_proc_show, NULL);
+}
+
+
+static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
+{
+	return seq_list_start_head(&nd_struct_list, *pos);
+}
+
+static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &nd_struct_list, pos);
+}
+
+static void nodeinfo_stop(struct seq_file *m, void *v)
+{
+}
+
+static int nodeinfo_show(struct seq_file *m, void *v)
+{
+	struct nd_struct *nd;
+	char hwver[8];
+	char swver[8];
+	char tmp_id[4];
+
+	if (v == &nd_struct_list) {
+		seq_puts(m, "#-----------------------------------------------------------------------------\n");
+		seq_puts(m, "#                 HW       HW   SW\n");
+		seq_puts(m, "# ID  State       Version  ID   Version  Description\n");
+		return 0;
+	}
+
+	nd = list_entry(v, struct nd_struct, list);
+
+	ID_TO_CHAR(nd->nd_ID, tmp_id);
+
+	if (nd->nd_state == NS_READY) {
+		sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
+			nd->nd_hw_ver & 0xff);
+		sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
+			nd->nd_sw_ver & 0xff);
+		seq_printf(m, "  %-2.2s  %-10.10s  %-7.7s  %-3d  %-7.7s  %-35.35s\n",
+			   tmp_id,
+			   ND_STATE_STR(nd->nd_state),
+			   hwver,
+			   nd->nd_hw_id,
+			   swver,
+			   nd->nd_ps_desc);
+
+	} else {
+		seq_printf(m, "  %-2.2s  %-10.10s\n",
+			   tmp_id,
+			   ND_STATE_STR(nd->nd_state));
+	}
+
+	return 0;
+}
+
+
+static const struct seq_operations nodeinfo_ops = {
+	.start = nodeinfo_start,
+	.next  = nodeinfo_next,
+	.stop  = nodeinfo_stop,
+	.show  = nodeinfo_show
+};
+
+static int nodeinfo_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &nodeinfo_ops);
+}
+
+/**
+ * dgrp_add_id() -- creates new nd struct and adds it to list
+ * @id: id of device to add
+ */
+static int dgrp_add_id(long id)
+{
+	struct nd_struct *nd;
+	int ret;
+	int i;
+
+	nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
+	if (!nd)
+		return -ENOMEM;
+
+	nd->nd_major = 0;
+	nd->nd_ID = id;
+
+	spin_lock_init(&nd->nd_lock);
+
+	init_waitqueue_head(&nd->nd_tx_waitq);
+	init_waitqueue_head(&nd->nd_mon_wqueue);
+	init_waitqueue_head(&nd->nd_dpa_wqueue);
+	for (i = 0; i < SEQ_MAX; i++)
+		init_waitqueue_head(&nd->nd_seq_wque[i]);
+
+	/* setup the structures to get the major number */
+	ret = dgrp_tty_init(nd);
+	if (ret)
+		goto error_out;
+
+	nd->nd_major = nd->nd_serial_ttdriver->major;
+
+	ret = nd_struct_add(nd);
+	if (ret)
+		goto error_out;
+
+	register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
+	register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
+	register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
+	register_dgrp_device(nd, ports_entry_pointer,
+			      dgrp_register_ports_hook);
+
+	return 0;
+
+error_out:
+	kfree(nd);
+	return ret;
+
+}
+
+static int dgrp_remove_nd(struct nd_struct *nd)
+{
+	int ret;
+
+	/* Check to see if the selected structure is in use */
+	if (nd->nd_tty_ref_cnt)
+		return -EBUSY;
+
+	if (nd->nd_net_de) {
+		unregister_dgrp_device(nd->nd_net_de);
+		dgrp_remove_node_class_sysfs_files(nd);
+	}
+
+	if (nd->nd_mon_de)
+		unregister_dgrp_device(nd->nd_mon_de);
+
+	if (nd->nd_ports_de)
+		unregister_dgrp_device(nd->nd_ports_de);
+
+	if (nd->nd_dpa_de)
+		unregister_dgrp_device(nd->nd_dpa_de);
+
+	dgrp_tty_uninit(nd);
+
+	ret = nd_struct_del(nd);
+	if (ret)
+		return ret;
+
+	kfree(nd);
+	return 0;
+}
+
+static void register_dgrp_device(struct nd_struct *node,
+				 struct proc_dir_entry *root,
+				 void (*register_hook)(struct proc_dir_entry *de))
+{
+	char buf[3];
+	struct proc_dir_entry *de;
+
+	ID_TO_CHAR(node->nd_ID, buf);
+
+	de = create_proc_entry(buf, 0600 | S_IFREG, root);
+	if (!de)
+		return;
+
+	de->data = (void *) node;
+
+	if (register_hook)
+		register_hook(de);
+
+}
+
+static void unregister_dgrp_device(struct proc_dir_entry *de)
+{
+	if (!de)
+		return;
+
+	/* Don't unregister proc entries that are still being used.. */
+	if ((atomic_read(&de->count)) != 1) {
+		pr_alert("%s - proc entry %s in use. Not removing.\n",
+			 __func__, de->name);
+		return;
+	}
+
+	remove_proc_entry(de->name, de->parent);
+	de = NULL;
+}
diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c
new file mode 100644
index 0000000..e5a3c88
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_sysfs.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+#include "dgrp_common.h"
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+
+
+#define PORTSERVER_DIVIDEND 1843200
+#define SERIAL_TYPE_NORMAL      1
+#define SERIAL_TYPE_CALLOUT     2
+#define SERIAL_TYPE_XPRINT      3
+
+
+static struct class *dgrp_class;
+static struct device *dgrp_class_nodes_dev;
+static struct device *dgrp_class_global_settings_dev;
+
+
+static ssize_t dgrp_class_version_show(struct class *class,
+				       struct class_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", DIGI_VERSION);
+}
+static CLASS_ATTR(driver_version, 0400, dgrp_class_version_show, NULL);
+
+
+static ssize_t dgrp_class_register_with_sysfs_show(struct device *c,
+						   struct device_attribute *attr,
+						   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "1\n");
+}
+static DEVICE_ATTR(register_with_sysfs, 0400,
+		   dgrp_class_register_with_sysfs_show, NULL);
+
+
+static ssize_t dgrp_class_rawreadok_show(struct device *c,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_rawreadok);
+}
+static ssize_t dgrp_class_rawreadok_store(struct device *c,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgrp_rawreadok);
+	return count;
+}
+static DEVICE_ATTR(rawreadok, 0600, dgrp_class_rawreadok_show,
+		   dgrp_class_rawreadok_store);
+
+
+static ssize_t dgrp_class_pollrate_show(struct device *c,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_poll_tick);
+}
+
+static ssize_t dgrp_class_pollrate_store(struct device *c,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgrp_poll_tick);
+	return count;
+}
+static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show,
+		   dgrp_class_pollrate_store);
+
+static struct attribute *dgrp_sysfs_global_settings_entries[] = {
+	&dev_attr_pollrate.attr,
+	&dev_attr_rawreadok.attr,
+	&dev_attr_register_with_sysfs.attr,
+	NULL
+};
+
+
+static struct attribute_group dgrp_global_settings_attribute_group = {
+	.name = NULL,
+	.attrs = dgrp_sysfs_global_settings_entries,
+};
+
+
+
+void dgrp_create_class_sysfs_files(void)
+{
+	int ret = 0;
+	int max_majors = 1U << (32 - MINORBITS);
+
+	dgrp_class = class_create(THIS_MODULE, "digi_realport");
+	ret = class_create_file(dgrp_class, &class_attr_driver_version);
+
+	dgrp_class_global_settings_dev = device_create(dgrp_class, NULL,
+		MKDEV(0, max_majors + 1), NULL, "driver_settings");
+
+	ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj,
+		&dgrp_global_settings_attribute_group);
+	if (ret) {
+		pr_alert("%s: failed to create sysfs global settings device attributes.\n",
+			__func__);
+		sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
+			&dgrp_global_settings_attribute_group);
+		return;
+	}
+
+	dgrp_class_nodes_dev = device_create(dgrp_class, NULL,
+		MKDEV(0, max_majors + 2), NULL, "nodes");
+
+}
+
+
+void dgrp_remove_class_sysfs_files(void)
+{
+	struct nd_struct *nd;
+	int max_majors = 1U << (32 - MINORBITS);
+
+	list_for_each_entry(nd, &nd_struct_list, list)
+		dgrp_remove_node_class_sysfs_files(nd);
+
+	sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
+		&dgrp_global_settings_attribute_group);
+
+	class_remove_file(dgrp_class, &class_attr_driver_version);
+
+	device_destroy(dgrp_class, MKDEV(0, max_majors + 1));
+	device_destroy(dgrp_class, MKDEV(0, max_majors + 2));
+	class_destroy(dgrp_class);
+}
+
+static ssize_t dgrp_node_state_show(struct device *c,
+				    struct device_attribute *attr, char *buf)
+{
+	struct nd_struct *nd;
+
+	if (!c)
+		return 0;
+	nd = (struct nd_struct *) dev_get_drvdata(c);
+	if (!nd)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ND_STATE_STR(nd->nd_state));
+}
+
+static DEVICE_ATTR(state, 0600, dgrp_node_state_show, NULL);
+
+static ssize_t dgrp_node_description_show(struct device *c,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct nd_struct *nd;
+
+	if (!c)
+		return 0;
+	nd = (struct nd_struct *) dev_get_drvdata(c);
+	if (!nd)
+		return 0;
+
+	if (nd->nd_state == NS_READY && nd->nd_ps_desc)
+		return snprintf(buf, PAGE_SIZE, "%s\n", nd->nd_ps_desc);
+	return 0;
+}
+static DEVICE_ATTR(description_info, 0600, dgrp_node_description_show, NULL);
+
+static ssize_t dgrp_node_hw_version_show(struct device *c,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct nd_struct *nd;
+
+	if (!c)
+		return 0;
+	nd = (struct nd_struct *) dev_get_drvdata(c);
+	if (!nd)
+		return 0;
+
+	if (nd->nd_state == NS_READY)
+		return snprintf(buf, PAGE_SIZE, "%d.%d\n",
+				(nd->nd_hw_ver >> 8) & 0xff,
+				nd->nd_hw_ver & 0xff);
+
+	return 0;
+}
+static DEVICE_ATTR(hw_version_info, 0600, dgrp_node_hw_version_show, NULL);
+
+static ssize_t dgrp_node_hw_id_show(struct device *c,
+				    struct device_attribute *attr, char *buf)
+{
+	struct nd_struct *nd;
+
+	if (!c)
+		return 0;
+	nd = (struct nd_struct *) dev_get_drvdata(c);
+	if (!nd)
+		return 0;
+
+
+	if (nd->nd_state == NS_READY)
+		return snprintf(buf, PAGE_SIZE, "%d\n", nd->nd_hw_id);
+	return 0;
+}
+static DEVICE_ATTR(hw_id_info, 0600, dgrp_node_hw_id_show, NULL);
+
+static ssize_t dgrp_node_sw_version_show(struct device *c,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct nd_struct *nd;
+
+	if (!c)
+		return 0;
+
+	nd = (struct nd_struct *) dev_get_drvdata(c);
+	if (!nd)
+		return 0;
+
+	if (nd->nd_state == NS_READY)
+		return snprintf(buf, PAGE_SIZE, "%d.%d\n",
+				(nd->nd_sw_ver >> 8) & 0xff,
+				nd->nd_sw_ver & 0xff);
+
+	return 0;
+}
+static DEVICE_ATTR(sw_version_info, 0600, dgrp_node_sw_version_show, NULL);
+
+
+static struct attribute *dgrp_sysfs_node_entries[] = {
+	&dev_attr_state.attr,
+	&dev_attr_description_info.attr,
+	&dev_attr_hw_version_info.attr,
+	&dev_attr_hw_id_info.attr,
+	&dev_attr_sw_version_info.attr,
+	NULL
+};
+
+
+static struct attribute_group dgrp_node_attribute_group = {
+	.name = NULL,
+	.attrs = dgrp_sysfs_node_entries,
+};
+
+
+void dgrp_create_node_class_sysfs_files(struct nd_struct *nd)
+{
+	int ret;
+	char name[10];
+
+	if (nd->nd_ID)
+		ID_TO_CHAR(nd->nd_ID, name);
+	else
+		sprintf(name, "node%ld", nd->nd_major);
+
+	nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev,
+		MKDEV(0, nd->nd_major), NULL, name);
+
+	ret = sysfs_create_group(&nd->nd_class_dev->kobj,
+				 &dgrp_node_attribute_group);
+
+	if (ret) {
+		pr_alert("%s: failed to create sysfs node device attributes.\n",
+			__func__);
+		sysfs_remove_group(&nd->nd_class_dev->kobj,
+				   &dgrp_node_attribute_group);
+		return;
+	}
+
+	dev_set_drvdata(nd->nd_class_dev, nd);
+
+}
+
+
+void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd)
+{
+	if (nd->nd_class_dev) {
+		sysfs_remove_group(&nd->nd_class_dev->kobj,
+				   &dgrp_node_attribute_group);
+
+		device_destroy(dgrp_class, MKDEV(0, nd->nd_major));
+		nd->nd_class_dev = NULL;
+	}
+}
+
+
+
+static ssize_t dgrp_tty_state_show(struct device *d,
+				   struct device_attribute *attr, char *buf)
+{
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state_info, 0600, dgrp_tty_state_show, NULL);
+
+static ssize_t dgrp_tty_baud_show(struct device *d,
+				  struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		un->un_open_count ? (PORTSERVER_DIVIDEND / ch->ch_s_brate) : 0);
+}
+static DEVICE_ATTR(baud_info, 0400, dgrp_tty_baud_show, NULL);
+
+
+static ssize_t dgrp_tty_msignals_show(struct device *d,
+				      struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+
+	if (ch->ch_open_count) {
+		return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+			(ch->ch_s_mlast & DM_RTS) ? "RTS" : "",
+			(ch->ch_s_mlast & DM_CTS) ? "CTS" : "",
+			(ch->ch_s_mlast & DM_DTR) ? "DTR" : "",
+			(ch->ch_s_mlast & DM_DSR) ? "DSR" : "",
+			(ch->ch_s_mlast & DM_CD) ? "DCD" : "",
+			(ch->ch_s_mlast & DM_RI)  ? "RI"  : "");
+	}
+	return 0;
+}
+static DEVICE_ATTR(msignals_info, 0400, dgrp_tty_msignals_show, NULL);
+
+
+static ssize_t dgrp_tty_iflag_show(struct device *d,
+				   struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_iflag);
+}
+static DEVICE_ATTR(iflag_info, 0600, dgrp_tty_iflag_show, NULL);
+
+
+static ssize_t dgrp_tty_cflag_show(struct device *d,
+				   struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_cflag);
+}
+static DEVICE_ATTR(cflag_info, 0600, dgrp_tty_cflag_show, NULL);
+
+
+static ssize_t dgrp_tty_oflag_show(struct device *d,
+				   struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_oflag);
+}
+static DEVICE_ATTR(oflag_info, 0600, dgrp_tty_oflag_show, NULL);
+
+
+static ssize_t dgrp_tty_digi_flag_show(struct device *d,
+				       struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag_info, 0600, dgrp_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgrp_tty_rxcount_show(struct device *d,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount_info, 0600, dgrp_tty_rxcount_show, NULL);
+
+
+static ssize_t dgrp_tty_txcount_show(struct device *d,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount_info, 0600, dgrp_tty_txcount_show, NULL);
+
+
+static ssize_t dgrp_tty_name_show(struct device *d,
+				  struct device_attribute *attr, char *buf)
+{
+	struct nd_struct *nd;
+	struct ch_struct *ch;
+	struct un_struct *un;
+	char name[10];
+
+	if (!d)
+		return 0;
+	un = (struct un_struct *) dev_get_drvdata(d);
+	if (!un)
+		return 0;
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+	nd = ch->ch_nd;
+	if (!nd)
+		return 0;
+
+	ID_TO_CHAR(nd->nd_ID, name);
+
+	return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+		un->un_type == SERIAL_TYPE_XPRINT ? "pr" : "tty",
+		name, ch->ch_portnum);
+}
+static DEVICE_ATTR(custom_name, 0600, dgrp_tty_name_show, NULL);
+
+
+static struct attribute *dgrp_sysfs_tty_entries[] = {
+	&dev_attr_state_info.attr,
+	&dev_attr_baud_info.attr,
+	&dev_attr_msignals_info.attr,
+	&dev_attr_iflag_info.attr,
+	&dev_attr_cflag_info.attr,
+	&dev_attr_oflag_info.attr,
+	&dev_attr_digi_flag_info.attr,
+	&dev_attr_rxcount_info.attr,
+	&dev_attr_txcount_info.attr,
+	&dev_attr_custom_name.attr,
+	NULL
+};
+
+
+static struct attribute_group dgrp_tty_attribute_group = {
+	.name = NULL,
+	.attrs = dgrp_sysfs_tty_entries,
+};
+
+
+void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c)
+{
+	int ret;
+
+	ret = sysfs_create_group(&c->kobj, &dgrp_tty_attribute_group);
+	if (ret) {
+		pr_alert("%s: failed to create sysfs tty device attributes.\n",
+			__func__);
+		sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
+		return;
+	}
+
+	dev_set_drvdata(c, un);
+
+}
+
+
+void dgrp_remove_tty_sysfs(struct device *c)
+{
+	sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
+}
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c
new file mode 100644
index 0000000..7d7de87
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_tty.c
@@ -0,0 +1,3331 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     Gene Olson    <Gene_Olson at digi dot com>
+ *     James Puzzo   <jamesp at digi dot com>
+ *     Jeff Randall
+ *     Scott Kilau   <scottk at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ *  Filename:
+ *
+ *     dgrp_tty.c
+ *
+ *  Description:
+ *
+ *     This file implements the tty driver functionality for the
+ *     RealPort driver software.
+ *
+ *  Author:
+ *
+ *     James A. Puzzo
+ *     Ann-Marie Westgate
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sched.h>
+
+#include "dgrp_common.h"
+
+#ifndef _POSIX_VDISABLE
+#define   _POSIX_VDISABLE ('\0')
+#endif
+
+/*
+ *	forward declarations
+ */
+
+static void drp_param(struct ch_struct *);
+static void dgrp_tty_close(struct tty_struct *, struct file *);
+
+/* ioctl helper functions */
+static int set_modem_info(struct ch_struct *, unsigned int, unsigned int *);
+static int get_modem_info(struct ch_struct *, unsigned int *);
+static void dgrp_set_custom_speed(struct ch_struct *, int);
+static int dgrp_tty_digigetedelay(struct tty_struct *, int *);
+static int dgrp_tty_digisetedelay(struct tty_struct *, int *);
+static int dgrp_send_break(struct ch_struct *, int);
+
+static ushort  tty_to_ch_flags(struct tty_struct *, char);
+static tcflag_t ch_to_tty_flags(unsigned short, char);
+
+static void dgrp_tty_input_start(struct tty_struct *);
+static void dgrp_tty_input_stop(struct tty_struct *);
+
+static void drp_wmove(struct ch_struct *, int, void*, int);
+
+static int dgrp_tty_open(struct tty_struct *, struct file *);
+static void dgrp_tty_close(struct tty_struct *, struct file *);
+static int dgrp_tty_write(struct tty_struct *, const unsigned char *, int);
+static int dgrp_tty_write_room(struct tty_struct *);
+static void dgrp_tty_flush_buffer(struct tty_struct *);
+static int dgrp_tty_chars_in_buffer(struct tty_struct *);
+static int dgrp_tty_ioctl(struct tty_struct *, unsigned int, unsigned long);
+static void dgrp_tty_set_termios(struct tty_struct *, struct ktermios *);
+static void dgrp_tty_stop(struct tty_struct *);
+static void dgrp_tty_start(struct tty_struct *);
+static void dgrp_tty_throttle(struct tty_struct *);
+static void dgrp_tty_unthrottle(struct tty_struct *);
+static void dgrp_tty_hangup(struct tty_struct *);
+static int dgrp_tty_put_char(struct tty_struct *, unsigned char);
+static int dgrp_tty_tiocmget(struct tty_struct *);
+static int dgrp_tty_tiocmset(struct tty_struct *, unsigned int, unsigned int);
+static int dgrp_tty_send_break(struct tty_struct *, int);
+static void dgrp_tty_send_xchar(struct tty_struct *, char);
+
+/*
+ *	tty defines
+ */
+#define	SERIAL_TYPE_NORMAL	1
+#define	SERIAL_TYPE_CALLOUT	2
+#define	SERIAL_TYPE_XPRINT	3
+
+
+/*
+ *	tty globals/statics
+ */
+
+
+#define PORTSERVER_DIVIDEND	1843200
+
+/*
+ *  Default transparent print information.
+ */
+static struct digi_struct digi_init = {
+	.digi_flags   = DIGI_COOK,	/* Flags			*/
+	.digi_maxcps  = 100,		/* Max CPS			*/
+	.digi_maxchar = 50,		/* Max chars in print queue	*/
+	.digi_bufsize = 100,		/* Printer buffer size		*/
+	.digi_onlen   = 4,		/* size of printer on string	*/
+	.digi_offlen  = 4,		/* size of printer off string	*/
+	.digi_onstr   = "\033[5i",	/* ANSI printer on string	*/
+	.digi_offstr  = "\033[4i",	/* ANSI printer off string	*/
+	.digi_term    = "ansi"		/* default terminal type	*/
+};
+
+/*
+ *	Define a local default termios struct. All ports will be created
+ *	with this termios initially.
+ *
+ *	This defines a raw port at 9600 baud, 8 data bits, no parity,
+ *	1 stop bit.
+ */
+static struct ktermios DefaultTermios = {
+	.c_iflag = (ICRNL | IXON),
+	.c_oflag = (OPOST | ONLCR),
+	.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+	.c_lflag = (ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL
+		    | ECHOKE | IEXTEN),
+	.c_cc    = INIT_C_CC,
+	.c_line  = 0,
+};
+
+/* Define our tty operations struct */
+static const struct tty_operations dgrp_tty_ops = {
+	.open            = dgrp_tty_open,
+	.close           = dgrp_tty_close,
+	.write           = dgrp_tty_write,
+	.write_room      = dgrp_tty_write_room,
+	.flush_buffer    = dgrp_tty_flush_buffer,
+	.chars_in_buffer = dgrp_tty_chars_in_buffer,
+	.flush_chars     = NULL,
+	.ioctl           = dgrp_tty_ioctl,
+	.set_termios     = dgrp_tty_set_termios,
+	.stop            = dgrp_tty_stop,
+	.start           = dgrp_tty_start,
+	.throttle        = dgrp_tty_throttle,
+	.unthrottle      = dgrp_tty_unthrottle,
+	.hangup          = dgrp_tty_hangup,
+	.put_char        = dgrp_tty_put_char,
+	.tiocmget        = dgrp_tty_tiocmget,
+	.tiocmset        = dgrp_tty_tiocmset,
+	.break_ctl       = dgrp_tty_send_break,
+	.send_xchar      = dgrp_tty_send_xchar
+};
+
+
+static int calc_baud_rate(struct un_struct *un)
+{
+	int i;
+	int brate;
+
+	struct baud_rates {
+		unsigned int rate;
+		unsigned int cflag;
+	};
+
+	static struct baud_rates baud_rates[] = {
+		{ 921600, B921600 },
+		{ 460800, B460800 },
+		{ 230400, B230400 },
+		{ 115200, B115200 },
+		{  57600, B57600  },
+		{  38400, B38400  },
+		{  19200, B19200  },
+		{   9600, B9600   },
+		{   4800, B4800   },
+		{   2400, B2400   },
+		{   1200, B1200   },
+		{    600, B600    },
+		{    300, B300    },
+		{    200, B200    },
+		{    150, B150    },
+		{    134, B134    },
+		{    110, B110    },
+		{     75, B75     },
+		{     50, B50     },
+		{      0, B9600  }
+	};
+
+	brate = C_BAUD(un->un_tty);
+
+	for (i = 0; baud_rates[i].rate; i++) {
+		if (baud_rates[i].cflag == brate)
+			break;
+	}
+
+	return baud_rates[i].rate;
+}
+
+static int calc_fastbaud_rate(struct un_struct *un, struct ktermios *uts)
+{
+	int i;
+	int brate;
+
+	ulong bauds[2][16] = {
+		{ /* fastbaud*/
+			0,      57600,	 76800,	115200,
+			131657, 153600, 230400, 460800,
+			921600, 1200,   1800,	2400,
+			4800,   9600,	19200,	38400 },
+		{ /* fastbaud & CBAUDEX */
+			0,      57600,	115200,	230400,
+			460800, 150,    200,    921600,
+			600,    1200,   1800,	2400,
+			4800,   9600,	19200,	38400 }
+	};
+
+	brate = C_BAUD(un->un_tty) & 0xff;
+
+	i = (uts->c_cflag & CBAUDEX) ? 1 : 0;
+
+
+	if ((i >= 0) && (i < 2) && (brate >= 0) && (brate < 16))
+		brate = bauds[i][brate];
+	else
+		brate = 0;
+
+	return brate;
+}
+
+/**
+ * drp_param() -- send parameter values to be sent to the node
+ * @ch: channel structure of port to modify
+ *
+ * Interprets the tty and modem changes made by an application
+ * program (by examining the termios structures) and sets up
+ * parameter values to be sent to the node.
+ */
+static void drp_param(struct ch_struct *ch)
+{
+	struct nd_struct *nd;
+	struct un_struct *un;
+	int   brate;
+	int   mflow;
+	int   xflag;
+	int   iflag;
+	struct ktermios *tts, *pts, *uts;
+
+	nd = ch->ch_nd;
+
+	/*
+	 *  If the terminal device is open, use it to set up all tty
+	 *  modes and functions.  Otherwise use the printer device.
+	 */
+
+	if (ch->ch_tun.un_open_count) {
+
+		un = &ch->ch_tun;
+		tts = &ch->ch_tun.un_tty->termios;
+
+		/*
+		 *  If both devices are open, copy critical line
+		 *  parameters from the tty device to the printer,
+		 *  so that if the tty is closed, the printer will
+		 *  continue without disruption.
+		 */
+
+		if (ch->ch_pun.un_open_count) {
+
+			pts = &ch->ch_pun.un_tty->termios;
+
+			pts->c_cflag ^=
+				(pts->c_cflag ^ tts->c_cflag) &
+				(CBAUD  | CSIZE | CSTOPB | CREAD | PARENB |
+				 PARODD | HUPCL | CLOCAL);
+
+			pts->c_iflag ^=
+				(pts->c_iflag ^ tts->c_iflag) &
+				(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK |
+				 ISTRIP | IXON   | IXANY  | IXOFF);
+
+			pts->c_cc[VSTART] = tts->c_cc[VSTART];
+			pts->c_cc[VSTOP] = tts->c_cc[VSTOP];
+		}
+	} else if (ch->ch_pun.un_open_count == 0) {
+		pr_warn("%s - ch_pun.un_open_count shouldn't be 0\n",
+		       __func__);
+		return;
+	} else {
+		un = &ch->ch_pun;
+	}
+
+	uts = &un->un_tty->termios;
+
+	/*
+	 * Determine if FAST writes can be performed.
+	 */
+
+	if ((ch->ch_digi.digi_flags & DIGI_COOK) != 0 &&
+	    (ch->ch_tun.un_open_count != 0)  &&
+	    !((un->un_tty)->ldisc->ops->flags & LDISC_FLAG_DEFINED) &&
+	    !(L_XCASE(un->un_tty))) {
+		ch->ch_flag |= CH_FAST_WRITE;
+	} else {
+		ch->ch_flag &= ~CH_FAST_WRITE;
+	}
+
+	/*
+	 *  If FAST writes can be performed, and OPOST is on in the
+	 *  terminal device, do OPOST handling in the server.
+	 */
+
+	if ((ch->ch_flag & CH_FAST_WRITE) &&
+	      O_OPOST(un->un_tty) != 0) {
+		int oflag = tty_to_ch_flags(un->un_tty, 'o');
+
+		/* add to ch_ocook any processing flags set in the termio */
+		ch->ch_ocook |= oflag & (OF_OLCUC |
+					 OF_ONLCR |
+					 OF_OCRNL |
+					 OF_ONLRET |
+					 OF_TABDLY);
+
+		/*
+		 * the hpux driver clears any flags set in ch_ocook
+		 * from the termios oflag.  It is STILL reported though
+		 * by a TCGETA
+		 */
+
+		oflag = ch_to_tty_flags(ch->ch_ocook, 'o');
+		uts->c_oflag &= ~oflag;
+
+	} else {
+		/* clear the ch->ch_ocook flag */
+		int oflag = ch_to_tty_flags(ch->ch_ocook, 'o');
+		uts->c_oflag |= oflag;
+		ch->ch_ocook = 0;
+	}
+
+	ch->ch_oflag = ch->ch_ocook;
+
+
+	ch->ch_flag &= ~CH_FAST_READ;
+
+	/*
+	 *  Generate channel flags
+	 */
+
+	if (C_BAUD(un->un_tty) == B0) {
+		if (!(ch->ch_flag & CH_BAUD0)) {
+			/* TODO : the HPUX driver flushes line */
+			/* TODO : discipline, I assume I don't have to */
+
+			ch->ch_tout = ch->ch_tin;
+			ch->ch_rout = ch->ch_rin;
+
+			ch->ch_break_time = 0;
+
+			ch->ch_send |= RR_TX_FLUSH | RR_RX_FLUSH;
+
+			ch->ch_mout &= ~(DM_DTR | DM_RTS);
+
+			ch->ch_flag |= CH_BAUD0;
+		}
+	} else if (ch->ch_custom_speed) {
+		ch->ch_brate = PORTSERVER_DIVIDEND / ch->ch_custom_speed ;
+
+		if (ch->ch_flag & CH_BAUD0) {
+			ch->ch_mout |= DM_DTR | DM_RTS;
+
+			ch->ch_flag &= ~CH_BAUD0;
+		}
+	} else {
+		/*
+		 * Baud rate mapping.
+		 *
+		 * If FASTBAUD isn't on, we can scan the new baud rate list
+		 * as required.
+		 *
+		 * However, if FASTBAUD is on, we must go to the old
+		 * baud rate mapping that existed many many moons ago,
+		 * for compatibility reasons.
+		 */
+
+		if (!(ch->ch_digi.digi_flags & DIGI_FAST))
+			brate = calc_baud_rate(un);
+		else
+			brate = calc_fastbaud_rate(un, uts);
+
+		if (brate == 0)
+			brate = 9600;
+
+		ch->ch_brate = PORTSERVER_DIVIDEND / brate;
+
+		if (ch->ch_flag & CH_BAUD0) {
+			ch->ch_mout |= DM_DTR | DM_RTS;
+
+			ch->ch_flag &= ~CH_BAUD0;
+		}
+	}
+
+	/*
+	 *  Generate channel cflags from the termio.
+	 */
+
+	ch->ch_cflag = tty_to_ch_flags(un->un_tty, 'c');
+
+	/*
+	 *  Generate channel iflags from the termio.
+	 */
+
+	iflag = (int) tty_to_ch_flags(un->un_tty, 'i');
+
+	if (START_CHAR(un->un_tty) == _POSIX_VDISABLE ||
+	    STOP_CHAR(un->un_tty) == _POSIX_VDISABLE) {
+		iflag &= ~(IF_IXON | IF_IXANY | IF_IXOFF);
+	}
+
+	ch->ch_iflag = iflag;
+
+	/*
+	 *  Generate flow control characters
+	 */
+
+	/*
+	 * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE}
+	 * is defined for the terminal device file, and the value
+	 * of one of the changable special control characters (see
+	 * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be
+	 * disabled, that is, no input data shall be recognized as
+	 * the disabled special character."
+	 *
+	 * OK, so we don't ever assign S/DXB XON or XOFF to _POSIX_VDISABLE.
+	 */
+
+	if (uts->c_cc[VSTART] != _POSIX_VDISABLE)
+		ch->ch_xon = uts->c_cc[VSTART];
+	if (uts->c_cc[VSTOP] != _POSIX_VDISABLE)
+		ch->ch_xoff = uts->c_cc[VSTOP];
+
+	ch->ch_lnext = (uts->c_cc[VLNEXT] == _POSIX_VDISABLE ? 0 :
+			uts->c_cc[VLNEXT]);
+
+	/*
+	 * Also, if either c_cc[START] or c_cc[STOP] is set to
+	 * _POSIX_VDISABLE, we can't really do software flow
+	 * control--in either direction--so we turn it off as
+	 * far as S/DXB is concerned.  In essence, if you disable
+	 * one, you disable the other too.
+	 */
+	if ((uts->c_cc[VSTART] == _POSIX_VDISABLE) ||
+	    (uts->c_cc[VSTOP] == _POSIX_VDISABLE))
+		ch->ch_iflag &= ~(IF_IXOFF | IF_IXON);
+
+	/*
+	 *  Update xflags.
+	 */
+
+	xflag = 0;
+
+	if (ch->ch_digi.digi_flags & DIGI_AIXON)
+		xflag = XF_XIXON;
+
+	if ((ch->ch_xxon == _POSIX_VDISABLE) ||
+	    (ch->ch_xxoff == _POSIX_VDISABLE))
+		xflag &= ~XF_XIXON;
+
+	ch->ch_xflag = xflag;
+
+
+	/*
+	 *  Figure effective DCD value.
+	 */
+
+	if (C_CLOCAL(un->un_tty))
+		ch->ch_flag |= CH_CLOCAL;
+	else
+		ch->ch_flag &= ~CH_CLOCAL;
+
+	/*
+	 *  Check modem signals
+	 */
+
+	dgrp_carrier(ch);
+
+	/*
+	 *  Get hardware handshake value.
+	 */
+
+	mflow = 0;
+
+	if (C_CRTSCTS(un->un_tty))
+		mflow |= (DM_RTS | DM_CTS);
+
+	if (ch->ch_digi.digi_flags & RTSPACE)
+		mflow |= DM_RTS;
+
+	if (ch->ch_digi.digi_flags & DTRPACE)
+		mflow |= DM_DTR;
+
+	if (ch->ch_digi.digi_flags & CTSPACE)
+		mflow |= DM_CTS;
+
+	if (ch->ch_digi.digi_flags & DSRPACE)
+		mflow |= DM_DSR;
+
+	if (ch->ch_digi.digi_flags & DCDPACE)
+		mflow |= DM_CD;
+
+	if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)
+		mflow |= DM_RTS_TOGGLE;
+
+	ch->ch_mflow = mflow;
+
+	/*
+	 *  Send the changes to the server.
+	 */
+
+	ch->ch_flag |= CH_PARAM;
+	(ch->ch_nd)->nd_tx_work = 1;
+
+	if (waitqueue_active(&ch->ch_flag_wait))
+		wake_up_interruptible(&ch->ch_flag_wait);
+}
+
+/*
+ * This function is just used as a callback for timeouts
+ * waiting on the ch_sleep flag.
+ */
+static void wake_up_drp_sleep_timer(unsigned long ptr)
+{
+	struct ch_struct *ch = (struct ch_struct *) ptr;
+	if (ch)
+		wake_up(&ch->ch_sleep);
+}
+
+
+/*
+ * Set up our own sleep that can't be cancelled
+ * until our timeout occurs.
+ */
+static void drp_my_sleep(struct ch_struct *ch)
+{
+	struct timer_list drp_wakeup_timer;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * First make sure we're ready to receive the wakeup.
+	 */
+
+	add_wait_queue(&ch->ch_sleep, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+
+	/*
+	 * Since we are uninterruptible, set a timer to
+	 * unset the uninterruptable state in 1 second.
+	 */
+
+	init_timer(&drp_wakeup_timer);
+	drp_wakeup_timer.function = wake_up_drp_sleep_timer;
+	drp_wakeup_timer.data = (unsigned long) ch;
+	drp_wakeup_timer.expires = jiffies + (1 * HZ);
+	add_timer(&drp_wakeup_timer);
+
+	schedule();
+
+	del_timer(&drp_wakeup_timer);
+
+	remove_wait_queue(&ch->ch_sleep, &wait);
+}
+
+/*
+ * dgrp_tty_open()
+ *
+ * returns:
+ *    -EBUSY    - this is a callout device and the normal device is active
+ *              - there is an error in opening the tty
+ *    -ENODEV   - the channel does not exist
+ *    -EAGAIN   - we are in the middle of hanging up or closing
+ *              - IMMEDIATE_OPEN fails
+ *    -ENXIO or -EAGAIN
+ *              - if the port is outside physical range
+ *    -EINTR    - the open is interrupted
+ *
+ */
+static int dgrp_tty_open(struct tty_struct *tty, struct file *file)
+{
+	int    retval = 0;
+	struct nd_struct  *nd;
+	struct ch_struct *ch;
+	struct un_struct  *un;
+	int    port;
+	int    delay_error;
+	int    otype;
+	int    unf;
+	int    wait_carrier;
+	int    category;
+	int    counts_were_incremented = 0;
+	ulong lock_flags;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * Do some initial checks to see if the node and port exist
+	 */
+
+	nd = nd_struct_get(MAJOR(tty_devnum(tty)));
+	port = PORT_NUM(MINOR(tty_devnum(tty)));
+	category = OPEN_CATEGORY(MINOR(tty_devnum(tty)));
+
+	if (!nd)
+		return -ENODEV;
+
+	if (port >= CHAN_MAX)
+		return -ENODEV;
+
+	/*
+	 *  The channel exists.
+	 */
+
+	ch = nd->nd_chan + port;
+
+	un = IS_PRINT(MINOR(tty_devnum(tty))) ? &ch->ch_pun : &ch->ch_tun;
+	un->un_tty = tty;
+	tty->driver_data = un;
+
+	/*
+	 * If we are in the middle of hanging up,
+	 * then return an error
+	 */
+	if (tty_hung_up_p(file)) {
+		retval = ((un->un_flag & UN_HUP_NOTIFY) ?
+			   -EAGAIN : -ERESTARTSYS);
+		goto done;
+	}
+
+	/*
+	 * If the port is in the middle of closing, then block
+	 * until it is done, then try again.
+	 */
+	retval = wait_event_interruptible(un->un_close_wait,
+			((un->un_flag & UN_CLOSING) == 0));
+
+	if (retval)
+		goto done;
+
+	/*
+	 * If the port is in the middle of a reopen after a network disconnect,
+	 * wait until it is done, then try again.
+	 */
+	retval = wait_event_interruptible(ch->ch_flag_wait,
+			((ch->ch_flag & CH_PORT_GONE) == 0));
+
+	if (retval)
+		goto done;
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+
+	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
+		if (un->un_flag & UN_NORMAL_ACTIVE) {
+			retval = -EBUSY;
+			goto done;
+		} else {
+			un->un_flag |= UN_CALLOUT_ACTIVE;
+		}
+	}
+
+	/*
+	 *  Loop waiting until the open can be successfully completed.
+	 */
+
+	spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+	nd->nd_tx_work = 1;
+
+	for (;;) {
+		wait_carrier = 0;
+
+		/*
+		 * Determine the open type from the flags provided.
+		 */
+
+		/*
+		 * If the port is not enabled, then exit
+		 */
+		if (test_bit(TTY_IO_ERROR, &tty->flags)) {
+			/* there was an error in opening the tty */
+			if (un->un_flag & UN_CALLOUT_ACTIVE)
+				retval = -EBUSY;
+			else
+				un->un_flag |= UN_NORMAL_ACTIVE;
+			goto unlock;
+		}
+
+		if (file->f_flags & O_NONBLOCK) {
+
+			/*
+			 * if the O_NONBLOCK is set, errors on read and write
+			 * must return -EAGAIN immediately and NOT sleep
+			 * on the waitqs.
+			 */
+			otype = OTYPE_IMMEDIATE;
+			delay_error = -EAGAIN;
+
+		} else if (!OPEN_WAIT_AVAIL(category) ||
+			  (file->f_flags & O_NDELAY) != 0) {
+			otype = OTYPE_IMMEDIATE;
+			delay_error = -EBUSY;
+
+		} else if (!OPEN_WAIT_CARRIER(category) ||
+			  ((ch->ch_digi.digi_flags & DIGI_FORCEDCD) != 0) ||
+			  C_CLOCAL(tty)) {
+			otype = OTYPE_PERSISTENT;
+			delay_error = 0;
+
+		} else {
+			otype = OTYPE_INCOMING;
+			delay_error = 0;
+		}
+
+		/*
+		 * Handle port currently outside physical port range.
+		 */
+
+		if (port >= nd->nd_chan_count) {
+			if (otype == OTYPE_IMMEDIATE) {
+				retval = (nd->nd_state == NS_READY) ?
+						-ENXIO : -EAGAIN;
+				goto unlock;
+			}
+		}
+
+		/*
+		 *  Handle port not currently open.
+		 */
+
+		else if (ch->ch_open_count == 0) {
+			/*
+			 * Return an error when an Incoming Open
+			 * response indicates the port is busy.
+			 */
+
+			if (ch->ch_open_error != 0 && otype == ch->ch_otype) {
+				retval = (ch->ch_open_error <= 2) ?
+					  delay_error : -ENXIO ;
+				goto unlock;
+			}
+
+			/*
+			 * Fail any new Immediate open if we do not have
+			 * a normal connection to the server.
+			 */
+
+			if (nd->nd_state != NS_READY &&
+			    otype == OTYPE_IMMEDIATE) {
+				retval = -EAGAIN;
+				goto unlock;
+			}
+
+			/*
+			 * If a Realport open of the correct type has
+			 * succeeded, complete the open.
+			 */
+
+			if (ch->ch_state == CS_READY && ch->ch_otype == otype)
+				break;
+		}
+
+		/*
+		 * Handle port already open and active as a device
+		 * of same category.
+		 */
+
+		else if ((ch->ch_category == category) ||
+			  IS_PRINT(MINOR(tty_devnum(tty)))) {
+			/*
+			 * Fail if opening the device now would
+			 * violate exclusive use.
+			 */
+			unf = ch->ch_tun.un_flag | ch->ch_pun.un_flag;
+
+			if ((file->f_flags & O_EXCL) || (unf & UN_EXCL)) {
+				retval = -EBUSY;
+				goto unlock;
+			}
+
+			/*
+			 * If the open device is in the hangup state, all
+			 * system calls fail except close().
+			 */
+
+			/* TODO : check on hangup_p calls */
+
+			if (ch->ch_flag & CH_HANGUP) {
+				retval = -ENXIO;
+				goto unlock;
+			}
+
+			/*
+			 * If the port is ready, and carrier is ignored
+			 * or present, then complete the open.
+			 */
+
+			if (ch->ch_state == CS_READY &&
+			    (otype != OTYPE_INCOMING ||
+			    ch->ch_flag & CH_VIRT_CD))
+				break;
+
+			wait_carrier = 1;
+		}
+
+		/*
+		 *  Handle port active with a different category device.
+		 */
+
+		else {
+			if (otype == OTYPE_IMMEDIATE) {
+				retval = delay_error;
+				goto unlock;
+			}
+		}
+
+		/*
+		 * Wait until conditions change, then take another
+		 * try at the open.
+		 */
+
+		ch->ch_wait_count[otype]++;
+
+		if (wait_carrier)
+			ch->ch_wait_carrier++;
+
+		/*
+		 * Prepare the task to accept the wakeup, then
+		 * release our locks and release control.
+		 */
+
+		add_wait_queue(&ch->ch_flag_wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+		/*
+		 * Give up control, we'll come back if we're
+		 * interrupted or are woken up.
+		 */
+		schedule();
+		remove_wait_queue(&ch->ch_flag_wait, &wait);
+
+		spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+		current->state = TASK_RUNNING;
+
+		ch->ch_wait_count[otype]--;
+
+		if (wait_carrier)
+			ch->ch_wait_carrier--;
+
+		nd->nd_tx_work = 1;
+
+		if (signal_pending(current)) {
+			retval = -EINTR;
+			goto unlock;
+		}
+	} /* end for(;;) */
+
+	/*
+	 *  The open has succeeded.  No turning back.
+	 */
+	counts_were_incremented = 1;
+	un->un_open_count++;
+	ch->ch_open_count++;
+
+	/*
+	 * Initialize the channel, if it's not already open.
+	 */
+
+	if (ch->ch_open_count == 1) {
+		ch->ch_flag = 0;
+		ch->ch_inwait = 0;
+		ch->ch_category = category;
+		ch->ch_pscan_state = 0;
+
+		/* TODO : find out what PS-1 bug Gene was referring to */
+		/* TODO : in the following comment. */
+
+		ch->ch_send = RR_TX_START | RR_RX_START;  /* PS-1 bug */
+
+		if (C_CLOCAL(tty) ||
+		    ch->ch_s_mlast & DM_CD ||
+		    ch->ch_digi.digi_flags & DIGI_FORCEDCD)
+			ch->ch_flag |= CH_VIRT_CD;
+		else if (OPEN_FORCES_CARRIER(category))
+			ch->ch_flag |= CH_VIRT_CD;
+
+	}
+
+	/*
+	 *  Initialize the unit, if it is not already open.
+	 */
+
+	if (un->un_open_count == 1) {
+		/*
+		 *  Since all terminal options are always sticky in Linux,
+		 *  we don't need the UN_STICKY flag to be handled specially.
+		 */
+		/* clears all the digi flags, leaves serial flags */
+		un->un_flag &= ~UN_DIGI_MASK;
+
+		if (file->f_flags & O_EXCL)
+			un->un_flag |= UN_EXCL;
+
+		/* TODO : include "session" and "pgrp" */
+
+		/*
+		 *  In Linux, all terminal parameters are intended to be sticky.
+		 *  as a result, we "remove" the code which once reset the ports
+		 *  to sane values.
+		 */
+
+		drp_param(ch);
+
+	}
+
+	un->un_flag |= UN_INITIALIZED;
+
+	retval = 0;
+
+unlock:
+
+	spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+done:
+	/*
+	 * Linux does a close for every open, even failed ones!
+	 */
+	if (!counts_were_incremented) {
+		un->un_open_count++;
+		ch->ch_open_count++;
+	}
+
+	if (retval)
+		dev_err(tty->dev, "tty open bad return (%i)\n", retval);
+
+	return retval;
+}
+
+
+
+
+/*
+ * dgrp_tty_close() -- close function for tty_operations
+ */
+static void dgrp_tty_close(struct tty_struct *tty, struct file *file)
+{
+	struct ch_struct *ch;
+	struct un_struct *un;
+	struct nd_struct *nd;
+	int	tpos;
+	int	port;
+	int	err = 0;
+	int	s = 0;
+	ulong  waketime;
+	ulong  lock_flags;
+	int sent_printer_offstr = 0;
+
+	port = PORT_NUM(MINOR(tty_devnum(tty)));
+
+	un = tty->driver_data;
+
+	if (!un)
+		return;
+
+	ch = un->un_ch;
+
+	if (!ch)
+		return;
+
+	nd = ch->ch_nd;
+
+	if (!nd)
+		return;
+
+	spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+
+	/* Used to be on channel basis, now we check on a unit basis. */
+	if (un->un_open_count != 1)
+		goto unlock;
+
+	/*
+	 * OK, its the last close on the unit
+	 */
+	un->un_flag |= UN_CLOSING;
+
+	/*
+	 * Notify the discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+
+	/*
+	 * Wait for output to drain only if this is
+	 * the last close against the channel
+	 */
+
+	if (ch->ch_open_count == 1) {
+		/*
+		 * If its the print device, we need to ensure at all costs that
+		 * the offstr will fit. If it won't, flush our tbuf.
+		 */
+		if (IS_PRINT(MINOR(tty_devnum(tty))) &&
+		    (((ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK) <
+		    ch->ch_digi.digi_offlen))
+			ch->ch_tin = ch->ch_tout;
+
+		/*
+		 * Turn off the printer.  Don't bother checking to see if its
+		 * IS_PRINT... Since this is the last close the flag is going
+		 * to be cleared, so we MUST make sure the offstr gets inserted
+		 * into tbuf.
+		 */
+
+		if ((ch->ch_flag & CH_PRON) != 0) {
+			drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+				  ch->ch_digi.digi_offlen);
+			ch->ch_flag &= ~CH_PRON;
+			sent_printer_offstr = 1;
+		}
+	}
+
+	/*
+	 *  Wait until either the output queue has drained, or we see
+	 *  absolutely no progress for 15 seconds.
+	 */
+
+	tpos = ch->ch_s_tpos;
+
+	waketime = jiffies + 15 * HZ;
+
+	for (;;) {
+
+		/*
+		 *  Make sure the port still exists.
+		 */
+
+		if (port >= nd->nd_chan_count) {
+			err = 1;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = 1;
+			break;
+		}
+
+		/*
+		 * If the port is idle (not opened on the server), we have
+		 * no way of draining/flushing/closing the port on that server.
+		 * So break out of loop.
+		 */
+		if (ch->ch_state == CS_IDLE)
+			break;
+
+		nd->nd_tx_work = 1;
+
+		/*
+		 *  Exit if the queues for this unit are empty,
+		 *  and either the other unit is still open or all
+		 *  data has drained.
+		 */
+
+		if ((un->un_tty)->ops->chars_in_buffer ?
+		    ((un->un_tty)->ops->chars_in_buffer)(un->un_tty) == 0 : 1) {
+
+			/*
+			 * We don't need to wait for a buffer to drain
+			 * if the other unit is open.
+			 */
+
+			if (ch->ch_open_count != un->un_open_count)
+				break;
+
+			/*
+			 *  The wait is complete when all queues are
+			 *  drained, and any break in progress is complete.
+			 */
+
+			if (ch->ch_tin == ch->ch_tout &&
+			    ch->ch_s_tin == ch->ch_s_tpos &&
+			    (ch->ch_send & RR_TX_BREAK) == 0) {
+				break;
+			}
+		}
+
+		/*
+		 * Flush TX data and exit the wait if NDELAY is set,
+		 * or this is not a DIGI printer, and the close timeout
+		 * expires.
+		 */
+
+		if ((file->f_flags & (O_NDELAY | O_NONBLOCK)) ||
+		    ((long)(jiffies - waketime) >= 0 &&
+		      (ch->ch_digi.digi_flags & DIGI_PRINTER) == 0)) {
+
+				/*
+				 * If we sent the printer off string, we cannot
+				 * flush our internal buffers, or we might lose
+				 * the offstr.
+				 */
+				if (!sent_printer_offstr)
+					dgrp_tty_flush_buffer(tty);
+
+				tty_ldisc_flush(tty);
+				break;
+		}
+
+		/*
+		 *  Otherwise take a short nap.
+		 */
+
+		ch->ch_flag |= CH_DRAIN;
+
+		spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+		schedule_timeout_interruptible(1);
+		s = signal_pending(current);
+
+		spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+		if (s) {
+			/*
+			 * If we had sent the printer off string, we now have
+			 * some problems.
+			 *
+			 * The system won't let us sleep since we got an error
+			 * back from sleep, presumably because the user did
+			 * a ctrl-c...
+			 * But we need to ensure that the offstr gets sent!
+			 * Thus, we have to do something else besides sleeping.
+			 * The plan:
+			 * 1) Make this task uninterruptable.
+			 * 2) Set up a timer to go off in 1 sec.
+			 * 3) Act as tho we just got out of the sleep above.
+			 *
+			 * Thankfully, in the real world, this just
+			 * never happens.
+			 */
+
+			if (sent_printer_offstr) {
+				spin_unlock_irqrestore(&nd->nd_lock,
+						       lock_flags);
+				drp_my_sleep(ch);
+				spin_lock_irqsave(&nd->nd_lock, lock_flags);
+			} else {
+				err = 1;
+				break;
+			}
+		}
+
+		/*
+		 *  Restart the wait if any progress is seen.
+		 */
+
+		if (ch->ch_s_tpos != tpos) {
+			tpos = ch->ch_s_tpos;
+
+			/* TODO:  this gives us timeout problems with nist ?? */
+			waketime = jiffies + 15 * HZ;
+		}
+	}
+
+	/*
+	 *  Close the line discipline
+	 */
+
+	/* this is done in tty_io.c */
+	/* if ((un->un_tty)->ldisc.close)
+	 *	((un->un_tty)->ldisc.close)(un->un_tty);
+	 */
+
+	/* don't do this here */
+	/* un->un_flag = 0; */
+
+	/*
+	 *  Flush the receive buffer on terminal unit close only.
+	 */
+
+	if (!IS_PRINT(MINOR(tty_devnum(tty))))
+		ch->ch_rout = ch->ch_rin;
+
+
+	/*
+	 * Don't permit the close to happen until we get any pending
+	 * sync request responses.
+	 * There could be other ports depending upon the response as well.
+	 *
+	 * Also, don't permit the close to happen until any parameter
+	 * changes have been sent out from the state machine as well.
+	 * This is required because of a ditty -a race with -HUPCL
+	 * We MUST make sure all channel parameters have been sent to the
+	 * Portserver before sending a close.
+	 */
+
+	if ((err != 1) && (ch->ch_state != CS_IDLE)) {
+		spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+		s = wait_event_interruptible(ch->ch_flag_wait,
+			((ch->ch_flag & (CH_WAITING_SYNC | CH_PARAM)) == 0));
+		spin_lock_irqsave(&nd->nd_lock, lock_flags);
+	}
+
+	/*
+	 * Cleanup the channel if last unit open.
+	 */
+
+	if (ch->ch_open_count == 1) {
+		ch->ch_flag = 0;
+		ch->ch_category = 0;
+		ch->ch_send = 0;
+		ch->ch_expect = 0;
+		ch->ch_tout = ch->ch_tin;
+		/* (un->un_tty)->device = 0; */
+
+		if (ch->ch_state == CS_READY)
+			ch->ch_state = CS_SEND_CLOSE;
+	}
+
+	/*
+	 * Send the changes to the server
+	 */
+	if (ch->ch_state != CS_IDLE) {
+		ch->ch_flag |= CH_PARAM;
+		wake_up_interruptible(&ch->ch_flag_wait);
+	}
+
+	nd->nd_tx_work = 1;
+	nd->nd_tx_ready = 1;
+
+unlock:
+	tty->closing = 0;
+
+	if (ch->ch_open_count <= 0)
+		dev_info(tty->dev,
+			 "%s - unexpected value for ch->ch_open_count: %i\n",
+			 __func__, ch->ch_open_count);
+	else
+		ch->ch_open_count--;
+
+	if (un->un_open_count <= 0)
+		dev_info(tty->dev,
+			 "%s - unexpected value for un->un_open_count: %i\n",
+			 __func__, un->un_open_count);
+	else
+		un->un_open_count--;
+
+	un->un_flag &= ~(UN_NORMAL_ACTIVE | UN_CALLOUT_ACTIVE | UN_CLOSING);
+	if (waitqueue_active(&un->un_close_wait))
+		wake_up_interruptible(&un->un_close_wait);
+
+	spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+	return;
+
+}
+
+static void drp_wmove(struct ch_struct *ch, int from_user, void *buf, int count)
+{
+	int n;
+	int ret = 0;
+
+	ch->ch_nd->nd_tx_work = 1;
+
+	n = TBUF_MAX - ch->ch_tin;
+
+	if (count >= n) {
+		if (from_user)
+			ret = copy_from_user(ch->ch_tbuf + ch->ch_tin,
+					     (void __user *) buf, n);
+		else
+			memcpy(ch->ch_tbuf + ch->ch_tin, buf, n);
+
+		buf = (char *) buf + n;
+		count -= n;
+		ch->ch_tin = 0;
+	}
+
+	if (from_user)
+		ret = copy_from_user(ch->ch_tbuf + ch->ch_tin,
+				     (void __user *) buf, count);
+	else
+		memcpy(ch->ch_tbuf + ch->ch_tin, buf, count);
+
+	ch->ch_tin += count;
+}
+
+
+static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space,
+					 int *un_flag)
+{
+	clock_t tt;
+	clock_t mt;
+	unsigned short tmax = 0;
+
+	/*
+	 * If the terminal device is busy, reschedule when
+	 * the terminal device becomes idle.
+	 */
+
+	if (ch->ch_tun.un_open_count != 0 &&
+	    ch->ch_tun.un_tty->ops->chars_in_buffer &&
+	    ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+		*un_flag = UN_PWAIT;
+		return 0;
+	}
+
+	/*
+	 * Assure that whenever there is printer data in the output
+	 * buffer, there always remains enough space after it to
+	 * turn the printer off.
+	 */
+	space -= ch->ch_digi.digi_offlen;
+
+	if (space <= 0) {
+		*un_flag = UN_EMPTY;
+		return 0;
+	}
+
+	/*
+	 * We measure printer CPS speed by incrementing
+	 * ch_cpstime by (HZ / digi_maxcps) for every
+	 * character we output, restricting output so
+	 * that ch_cpstime never exceeds lbolt.
+	 *
+	 * However if output has not been done for some
+	 * time, lbolt will grow to very much larger than
+	 * ch_cpstime, which would allow essentially
+	 * unlimited amounts of output until ch_cpstime
+	 * finally caught up.   To avoid this, we adjust
+	 * cps_time when necessary so the difference
+	 * between lbolt and ch_cpstime never results
+	 * in sending more than digi_bufsize characters.
+	 *
+	 * This nicely models a printer with an internal
+	 * buffer of digi_bufsize characters.
+	 *
+	 * Get the time between lbolt and ch->ch_cpstime;
+	 */
+
+	tt = jiffies - ch->ch_cpstime;
+
+	/*
+	 * Compute the time required to send digi_bufsize
+	 * characters.
+	 */
+
+	mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps;
+
+	/*
+	 * Compute the number of characters that can be sent
+	 * without violating the time constraint.   If the
+	 * direct calculation of this number is bigger than
+	 * digi_bufsize, limit the number to digi_bufsize,
+	 * and adjust cpstime to match.
+	 */
+
+	if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) {
+		tmax = ch->ch_digi.digi_bufsize;
+		ch->ch_cpstime = jiffies - mt;
+	} else {
+		tmax = ch->ch_digi.digi_maxcps * tt / HZ;
+	}
+
+	/*
+	 * If the time constraint now binds, limit the transmit
+	 * count accordingly, and tentatively arrange to be
+	 * rescheduled based on time.
+	 */
+
+	if (tmax < space) {
+		*un_flag = UN_TIME;
+		space = tmax;
+	}
+
+	/*
+	 * Compute the total number of characters we can
+	 * output before the total number of characters known
+	 * to be in the output queue exceeds digi_maxchar.
+	 */
+
+	tmax = (ch->ch_digi.digi_maxchar -
+		((ch->ch_tin - ch->ch_tout) & TBUF_MASK) -
+		((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff));
+
+
+	/*
+	 * If the digi_maxchar constraint now holds, limit
+	 * the transmit count accordingly, and arrange to
+	 * be rescheduled when the queue becomes empty.
+	 */
+
+	if (space > tmax) {
+		*un_flag = UN_EMPTY;
+		space = tmax;
+	}
+
+	if (space <= 0)
+		*un_flag |= UN_EMPTY;
+
+	return space;
+}
+
+
+static int dgrp_tty_write(struct tty_struct *tty,
+			  const unsigned char *buf,
+			  int count)
+{
+	struct nd_struct *nd;
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int	space;
+	int	n;
+	int	t;
+	int sendcount;
+	int un_flag;
+	ulong lock_flags;
+
+	if (tty == NULL)
+		return 0;
+
+	un = tty->driver_data;
+	if (!un)
+		return 0;
+
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+
+	nd = ch->ch_nd;
+	if (!nd)
+		return 0;
+
+	/*
+	 * Ignore the request if the channel is not ready.
+	 */
+	if (ch->ch_state != CS_READY)
+		return 0;
+
+	spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+	/*
+	 * Ignore the request if output is blocked.
+	 */
+	if ((un->un_flag & (UN_EMPTY | UN_LOW | UN_TIME | UN_PWAIT)) != 0) {
+		count = 0;
+		goto out;
+	}
+
+	/*
+	 * Also ignore the request if DPA has this port open,
+	 * and is flow controlled on reading more data.
+	 */
+	if (nd->nd_dpa_debug && nd->nd_dpa_flag & DPA_WAIT_SPACE &&
+		nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))) {
+		count = 0;
+		goto out;
+	}
+
+	/*
+	 *	Limit amount we will write to the amount of space
+	 *	available in the channel buffer.
+	 */
+	sendcount = 0;
+
+	space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+	/*
+	 * Handle the printer device.
+	 */
+
+	un_flag = UN_LOW;
+
+	if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+		clock_t tt;
+		clock_t mt;
+		unsigned short tmax = 0;
+
+		/*
+		 * If the terminal device is busy, reschedule when
+		 * the terminal device becomes idle.
+		 */
+
+		if (ch->ch_tun.un_open_count != 0 &&
+		    ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+			un->un_flag |= UN_PWAIT;
+			count = 0;
+			goto out;
+		}
+
+		/*
+		 * Assure that whenever there is printer data in the output
+		 * buffer, there always remains enough space after it to
+		 * turn the printer off.
+		 */
+		space -= ch->ch_digi.digi_offlen;
+
+		/*
+		 * Output the printer on string.
+		 */
+
+		if ((ch->ch_flag & CH_PRON) == 0) {
+			space -= ch->ch_digi.digi_onlen;
+
+			if (space < 0) {
+				un->un_flag |= UN_EMPTY;
+				(ch->ch_nd)->nd_tx_work = 1;
+				count = 0;
+				goto out;
+			}
+
+			drp_wmove(ch, 0, ch->ch_digi.digi_onstr,
+				ch->ch_digi.digi_onlen);
+
+			ch->ch_flag |= CH_PRON;
+		}
+
+		/*
+		 * We measure printer CPS speed by incrementing
+		 * ch_cpstime by (HZ / digi_maxcps) for every
+		 * character we output, restricting output so
+		 * that ch_cpstime never exceeds lbolt.
+		 *
+		 * However if output has not been done for some
+		 * time, lbolt will grow to very much larger than
+		 * ch_cpstime, which would allow essentially
+		 * unlimited amounts of output until ch_cpstime
+		 * finally caught up.   To avoid this, we adjust
+		 * cps_time when necessary so the difference
+		 * between lbolt and ch_cpstime never results
+		 * in sending more than digi_bufsize characters.
+		 *
+		 * This nicely models a printer with an internal
+		 * buffer of digi_bufsize characters.
+		 *
+		 * Get the time between lbolt and ch->ch_cpstime;
+		 */
+
+		tt = jiffies - ch->ch_cpstime;
+
+		/*
+		 * Compute the time required to send digi_bufsize
+		 * characters.
+		 */
+
+		mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps;
+
+		/*
+		 * Compute the number of characters that can be sent
+		 * without violating the time constraint.   If the
+		 * direct calculation of this number is bigger than
+		 * digi_bufsize, limit the number to digi_bufsize,
+		 * and adjust cpstime to match.
+		 */
+
+		if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) {
+			tmax = ch->ch_digi.digi_bufsize;
+			ch->ch_cpstime = jiffies - mt;
+		} else {
+			tmax = ch->ch_digi.digi_maxcps * tt / HZ;
+		}
+
+		/*
+		 * If the time constraint now binds, limit the transmit
+		 * count accordingly, and tentatively arrange to be
+		 * rescheduled based on time.
+		 */
+
+		if (tmax < space) {
+			space = tmax;
+			un_flag = UN_TIME;
+		}
+
+		/*
+		 * Compute the total number of characters we can
+		 * output before the total number of characters known
+		 * to be in the output queue exceeds digi_maxchar.
+		 */
+
+		tmax = (ch->ch_digi.digi_maxchar -
+			((ch->ch_tin - ch->ch_tout) & TBUF_MASK) -
+			((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff));
+
+
+		/*
+		 * If the digi_maxchar constraint now holds, limit
+		 * the transmit count accordingly, and arrange to
+		 * be rescheduled when the queue becomes empty.
+		 */
+
+		if (space > tmax) {
+			space = tmax;
+			un_flag = UN_EMPTY;
+		}
+
+	}
+	/*
+	 * Handle the terminal device.
+	 */
+	else {
+
+		/*
+		 * If the printer device is on, turn it off.
+		 */
+
+		if ((ch->ch_flag & CH_PRON) != 0) {
+
+			space -= ch->ch_digi.digi_offlen;
+
+			drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+				  ch->ch_digi.digi_offlen);
+
+			ch->ch_flag &= ~CH_PRON;
+		}
+	}
+
+	/*
+	 *	If space is 0 and its because the ch->tbuf
+	 *	is full, then Linux will handle a callback when queue
+	 *	space becomes available.
+	 *	tty_write returns count = 0
+	 */
+
+	if (space <= 0) {
+		/* the linux tty_io.c handles this if we return 0 */
+		/* if (fp->flags & O_NONBLOCK) return -EAGAIN; */
+
+		un->un_flag |= UN_EMPTY;
+		(ch->ch_nd)->nd_tx_work = 1;
+		count = 0;
+		goto out;
+	}
+
+	count = min(count, space);
+
+	if (count > 0) {
+
+		un->un_tbusy++;
+
+		/*
+		 *	Copy the buffer contents to the ch_tbuf
+		 *	being careful to wrap around the circular queue
+		 */
+
+		t = TBUF_MAX - ch->ch_tin;
+		n = count;
+
+		if (n >= t) {
+			memcpy(ch->ch_tbuf + ch->ch_tin, buf, t);
+			if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+				dgrp_dpa_data(nd, 0, (char *) buf, t);
+			buf += t;
+			n -= t;
+			ch->ch_tin = 0;
+			sendcount += n;
+		}
+
+		memcpy(ch->ch_tbuf + ch->ch_tin, buf, n);
+		if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+			dgrp_dpa_data(nd, 0, (char *) buf, n);
+		buf += n;
+		ch->ch_tin += n;
+		sendcount += n;
+
+		un->un_tbusy--;
+		(ch->ch_nd)->nd_tx_work = 1;
+		if (ch->ch_edelay != DGRP_RTIME) {
+			(ch->ch_nd)->nd_tx_ready = 1;
+			wake_up_interruptible(&nd->nd_tx_waitq);
+		}
+	}
+
+	ch->ch_txcount += count;
+
+	if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+
+		/*
+		 * Adjust ch_cpstime to account
+		 * for the characters just output.
+		 */
+
+		if (sendcount > 0) {
+			int cc = HZ * sendcount + ch->ch_cpsrem;
+
+			ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps;
+			ch->ch_cpsrem   = cc % ch->ch_digi.digi_maxcps;
+		}
+
+		/*
+		 * If we are now waiting on time, schedule ourself
+		 * back when we'll be able to send a block of
+		 * digi_maxchar characters.
+		 */
+
+		if ((un_flag & UN_TIME) != 0) {
+			ch->ch_waketime = (ch->ch_cpstime +
+				(ch->ch_digi.digi_maxchar * HZ /
+				ch->ch_digi.digi_maxcps));
+		}
+	}
+
+	/*
+	 * If the printer unit is waiting for completion
+	 * of terminal output, get him going again.
+	 */
+
+	if ((ch->ch_pun.un_flag & UN_PWAIT) != 0)
+		(ch->ch_nd)->nd_tx_work = 1;
+
+out:
+	spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+	return count;
+}
+
+
+/*
+ *	Put a character into ch->ch_buf
+ *
+ *	- used by the line discipline for OPOST processing
+ */
+
+static int dgrp_tty_put_char(struct tty_struct *tty, unsigned char new_char)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	ulong  lock_flags;
+	int space;
+	int retval = 0;
+
+	if (tty == NULL)
+		return 0;
+
+	un = tty->driver_data;
+	if (!un)
+		return 0;
+
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+
+	if (ch->ch_state != CS_READY)
+		return 0;
+
+	spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+
+	/*
+	 *	If space is 0 and its because the ch->tbuf
+	 *	Warn and dump the character, there isn't anything else
+	 *	we can do about it.  David_Fries@digi.com
+	 */
+
+	space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+	un->un_tbusy++;
+
+	/*
+	 * Output the printer on string if device is TXPrint.
+	 */
+	if (IS_PRINT(MINOR(tty_devnum(tty))) && (ch->ch_flag & CH_PRON) == 0) {
+		if (space < ch->ch_digi.digi_onlen) {
+			un->un_tbusy--;
+			goto out;
+		}
+		space -= ch->ch_digi.digi_onlen;
+		drp_wmove(ch, 0, ch->ch_digi.digi_onstr,
+			  ch->ch_digi.digi_onlen);
+		ch->ch_flag |= CH_PRON;
+	}
+
+	/*
+	 * Output the printer off string if device is NOT TXPrint.
+	 */
+
+	if (!IS_PRINT(MINOR(tty_devnum(tty))) &&
+	    ((ch->ch_flag & CH_PRON) != 0)) {
+		if (space < ch->ch_digi.digi_offlen) {
+			un->un_tbusy--;
+			goto out;
+		}
+
+		space -= ch->ch_digi.digi_offlen;
+		drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+			  ch->ch_digi.digi_offlen);
+		ch->ch_flag &= ~CH_PRON;
+	}
+
+	if (!space) {
+		un->un_tbusy--;
+		goto out;
+	}
+
+	/*
+	 *	Copy the character to the ch_tbuf being
+	 *	careful to wrap around the circular queue
+	 */
+	ch->ch_tbuf[ch->ch_tin] = new_char;
+	ch->ch_tin = (1 + ch->ch_tin) & TBUF_MASK;
+
+	if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+
+		/*
+		 * Adjust ch_cpstime to account
+		 * for the character just output.
+		 */
+
+		int cc = HZ + ch->ch_cpsrem;
+
+		ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps;
+		ch->ch_cpsrem   = cc % ch->ch_digi.digi_maxcps;
+
+		/*
+		 * If we are now waiting on time, schedule ourself
+		 * back when we'll be able to send a block of
+		 * digi_maxchar characters.
+		 */
+
+		ch->ch_waketime = (ch->ch_cpstime +
+			(ch->ch_digi.digi_maxchar * HZ /
+			ch->ch_digi.digi_maxcps));
+	}
+
+
+	un->un_tbusy--;
+	(ch->ch_nd)->nd_tx_work = 1;
+
+	retval = 1;
+out:
+	spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+	return retval;
+}
+
+
+
+/*
+ *	Flush TX buffer (make in == out)
+ *
+ *	check tty_ioctl.c  -- this is called after TCOFLUSH
+ */
+static void dgrp_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+	un = tty->driver_data;
+	if (!un)
+		return;
+
+	ch = un->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_tout = ch->ch_tin;
+	/* do NOT do this here! */
+	/* ch->ch_s_tpos = ch->ch_s_tin = 0; */
+
+	/* send the flush output command now */
+	ch->ch_send |= RR_TX_FLUSH;
+	(ch->ch_nd)->nd_tx_ready = 1;
+	(ch->ch_nd)->nd_tx_work = 1;
+	wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+	if (waitqueue_active(&tty->write_wait))
+		wake_up_interruptible(&tty->write_wait);
+
+	tty_wakeup(tty);
+
+}
+
+/*
+ *	Return space available in Tx buffer
+ *	count = ( ch->ch_tout - ch->ch_tin ) mod (TBUF_MAX - 1)
+ */
+static int dgrp_tty_write_room(struct tty_struct *tty)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int	count;
+
+	if (!tty)
+		return 0;
+
+	un = tty->driver_data;
+	if (!un)
+		return 0;
+
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+
+	count = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+	/* We *MUST* check this, and return 0 if the Printer Unit cannot
+	 * take any more data within its time constraints...  If we don't
+	 * return 0 and the printer has hit it time constraint, the ld will
+	 * call us back doing a put_char, which cannot be rejected!!!
+	 */
+	if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+		int un_flag = 0;
+		count = dgrp_calculate_txprint_bounds(ch, count, &un_flag);
+		if (count <= 0)
+			count = 0;
+
+		ch->ch_pun.un_flag |= un_flag;
+		(ch->ch_nd)->nd_tx_work = 1;
+	}
+
+	return count;
+}
+
+/*
+ *	Return number of characters that have not been transmitted yet.
+ *	chars_in_buffer = ( ch->ch_tin - ch->ch_tout ) mod (TBUF_MAX - 1)
+ *			+ ( ch->ch_s_tin - ch->ch_s_tout ) mod (0xffff)
+ *			= number of characters "in transit"
+ *
+ * Remember that sequence number math is always with a sixteen bit
+ * mask, not the TBUF_MASK.
+ */
+
+static int dgrp_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int	count;
+	int	count1;
+
+	if (!tty)
+		return 0;
+
+	un = tty->driver_data;
+	if (!un)
+		return 0;
+
+	ch = un->un_ch;
+	if (!ch)
+		return 0;
+
+	count1 = count = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+	count += (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff;
+	/* one for tbuf, one for the PS */
+
+	/*
+	 * If we are busy transmitting add 1
+	 */
+	count += un->un_tbusy;
+
+	return count;
+}
+
+
+/*****************************************************************************
+ *
+ * Helper applications for dgrp_tty_ioctl()
+ *
+ *****************************************************************************
+ */
+
+
+/**
+ * ch_to_tty_flags() -- convert channel flags to termio flags
+ * @ch_flag: Digi channel flags
+ * @flagtype: type of ch_flag (iflag, oflag or cflag)
+ *
+ * take the channel flags of the specified type and return the
+ * corresponding termio flag
+ */
+static tcflag_t ch_to_tty_flags(ushort ch_flag, char flagtype)
+{
+	tcflag_t retval = 0;
+
+	switch (flagtype) {
+	case 'i':
+		retval = ((ch_flag & IF_IGNBRK) ? IGNBRK : 0)
+		     | ((ch_flag & IF_BRKINT) ? BRKINT : 0)
+		     | ((ch_flag & IF_IGNPAR) ? IGNPAR : 0)
+		     | ((ch_flag & IF_PARMRK) ? PARMRK : 0)
+		     | ((ch_flag & IF_INPCK) ? INPCK  : 0)
+		     | ((ch_flag & IF_ISTRIP) ? ISTRIP : 0)
+		     | ((ch_flag & IF_IXON) ? IXON   : 0)
+		     | ((ch_flag & IF_IXANY) ? IXANY  : 0)
+		     | ((ch_flag & IF_IXOFF) ? IXOFF  : 0);
+		break;
+
+	case 'o':
+		retval = ((ch_flag & OF_OLCUC) ? OLCUC : 0)
+		     | ((ch_flag & OF_ONLCR) ? ONLCR  : 0)
+		     | ((ch_flag & OF_OCRNL) ? OCRNL  : 0)
+		     | ((ch_flag & OF_ONOCR) ? ONOCR  : 0)
+		     | ((ch_flag & OF_ONLRET) ? ONLRET : 0)
+		  /* | ((ch_flag & OF_OTAB3) ? OFILL  : 0) */
+		     | ((ch_flag & OF_TABDLY) ? TABDLY : 0);
+		break;
+
+	case 'c':
+		retval = ((ch_flag & CF_CSTOPB) ? CSTOPB : 0)
+		     | ((ch_flag & CF_CREAD) ? CREAD  : 0)
+		     | ((ch_flag & CF_PARENB) ? PARENB : 0)
+		     | ((ch_flag & CF_PARODD) ? PARODD : 0)
+		     | ((ch_flag & CF_HUPCL) ? HUPCL  : 0);
+
+		switch (ch_flag & CF_CSIZE) {
+		case CF_CS5:
+			retval |= CS5;
+			break;
+		case CF_CS6:
+			retval |= CS6;
+			break;
+		case CF_CS7:
+			retval |= CS7;
+			break;
+		case CF_CS8:
+			retval |= CS8;
+			break;
+		default:
+			retval |= CS8;
+			break;
+		}
+		break;
+	case 'x':
+		break;
+	case 'l':
+		break;
+	default:
+		return 0;
+	}
+
+	return retval;
+}
+
+
+/**
+ * tty_to_ch_flags() -- convert termio flags to digi channel flags
+ * @tty: pointer to a TTY structure holding flag to be converted
+ * @flagtype: identifies which flag (iflags, oflags, or cflags) should
+ *                 be converted
+ *
+ * take the termio flag of the specified type and return the
+ * corresponding Digi version of the flags
+ */
+static ushort tty_to_ch_flags(struct tty_struct *tty, char flagtype)
+{
+	ushort retval = 0;
+	tcflag_t tflag = 0;
+
+	switch (flagtype) {
+	case 'i':
+		tflag  = tty->termios.c_iflag;
+		retval = (I_IGNBRK(tty) ? IF_IGNBRK : 0)
+		      | (I_BRKINT(tty) ? IF_BRKINT : 0)
+		      | (I_IGNPAR(tty) ? IF_IGNPAR : 0)
+		      | (I_PARMRK(tty) ? IF_PARMRK : 0)
+		      | (I_INPCK(tty)  ? IF_INPCK  : 0)
+		      | (I_ISTRIP(tty) ? IF_ISTRIP : 0)
+		      | (I_IXON(tty)   ? IF_IXON   : 0)
+		      | (I_IXANY(tty)  ? IF_IXANY  : 0)
+		      | (I_IXOFF(tty)  ? IF_IXOFF  : 0);
+		break;
+	case 'o':
+		tflag  = tty->termios.c_oflag;
+		/*
+		 * If OPOST is set, then do the post processing in the
+		 * firmware by setting all the processing flags on.
+		 * If ~OPOST, then make sure we are not doing any
+		 * output processing!!
+		 */
+		if (!O_OPOST(tty))
+			retval = 0;
+		else
+			retval = (O_OLCUC(tty) ? OF_OLCUC : 0)
+			     | (O_ONLCR(tty)  ? OF_ONLCR  : 0)
+			     | (O_OCRNL(tty)  ? OF_OCRNL  : 0)
+			     | (O_ONOCR(tty)  ? OF_ONOCR  : 0)
+			     | (O_ONLRET(tty) ? OF_ONLRET : 0)
+			  /* | (O_OFILL(tty)  ? OF_TAB3   : 0) */
+			     | (O_TABDLY(tty) ? OF_TABDLY : 0);
+		break;
+	case 'c':
+		tflag  = tty->termios.c_cflag;
+		retval = (C_CSTOPB(tty) ? CF_CSTOPB : 0)
+		     | (C_CREAD(tty)  ? CF_CREAD  : 0)
+		     | (C_PARENB(tty) ? CF_PARENB : 0)
+		     | (C_PARODD(tty) ? CF_PARODD : 0)
+		     | (C_HUPCL(tty)  ? CF_HUPCL  : 0);
+		switch (C_CSIZE(tty)) {
+		case CS8:
+			retval |= CF_CS8;
+			break;
+		case CS7:
+			retval |= CF_CS7;
+			break;
+		case CS6:
+			retval |= CF_CS6;
+			break;
+		case CS5:
+			retval |= CF_CS5;
+			break;
+		default:
+			retval |= CF_CS8;
+			break;
+		}
+		break;
+	case 'x':
+		break;
+	case 'l':
+		break;
+	default:
+		return 0;
+	}
+
+	return retval;
+}
+
+
+static int dgrp_tty_send_break(struct tty_struct *tty, int msec)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int ret = -EIO;
+
+	if (!tty)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch)
+		return ret;
+
+	dgrp_send_break(ch, msec);
+	return 0;
+}
+
+
+/*
+ * This routine sends a break character out the serial port.
+ *
+ * duration is in 1/1000's of a second
+ */
+static int dgrp_send_break(struct ch_struct *ch, int msec)
+{
+	ulong x;
+
+	wait_event_interruptible(ch->ch_flag_wait,
+		((ch->ch_flag & CH_TX_BREAK) == 0));
+	ch->ch_break_time += max(msec, 250);
+	ch->ch_send |= RR_TX_BREAK;
+	ch->ch_flag |= CH_TX_BREAK;
+	(ch->ch_nd)->nd_tx_work = 1;
+
+	x = (msec * HZ) / 1000;
+	wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+	return 0;
+}
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgrp_tty_tiocmget(struct tty_struct *tty)
+{
+	unsigned int mlast;
+	struct un_struct *un = tty->driver_data;
+	struct ch_struct *ch;
+
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) |
+		(ch->ch_mout & (DM_RTS | DM_DTR)));
+
+	/* defined in /usr/include/asm/termios.h */
+	mlast =   ((mlast & DM_RTS) ? TIOCM_RTS : 0)
+		| ((mlast & DM_DTR) ? TIOCM_DTR : 0)
+		| ((mlast & DM_CD)  ? TIOCM_CAR : 0)
+		| ((mlast & DM_RI)  ? TIOCM_RNG : 0)
+		| ((mlast & DM_DSR) ? TIOCM_DSR : 0)
+		| ((mlast & DM_CTS) ? TIOCM_CTS : 0);
+
+	return mlast;
+}
+
+
+/*
+ *      Set modem lines
+ */
+static int dgrp_tty_tiocmset(struct tty_struct *tty,
+			     unsigned int set, unsigned int clear)
+{
+	ulong lock_flags;
+	struct un_struct *un = tty->driver_data;
+	struct ch_struct *ch;
+
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	if (set & TIOCM_RTS)
+		ch->ch_mout |= DM_RTS;
+
+	if (set & TIOCM_DTR)
+		ch->ch_mout |= DM_DTR;
+
+	if (clear & TIOCM_RTS)
+		ch->ch_mout &= ~(DM_RTS);
+
+	if (clear & TIOCM_DTR)
+		ch->ch_mout &= ~(DM_DTR);
+
+	spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags);
+	ch->ch_flag |= CH_PARAM;
+	(ch->ch_nd)->nd_tx_work = 1;
+	wake_up_interruptible(&ch->ch_flag_wait);
+
+	spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags);
+
+	return 0;
+}
+
+
+
+/*
+ *      Get current modem status
+ */
+static int get_modem_info(struct ch_struct *ch, unsigned int *value)
+{
+	unsigned int mlast;
+
+	mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) |
+		(ch->ch_mout    &  (DM_RTS | DM_DTR)));
+
+	/* defined in /usr/include/asm/termios.h */
+	mlast =   ((mlast & DM_RTS) ? TIOCM_RTS : 0)
+		| ((mlast & DM_DTR) ? TIOCM_DTR : 0)
+		| ((mlast & DM_CD)  ? TIOCM_CAR : 0)
+		| ((mlast & DM_RI)  ? TIOCM_RNG : 0)
+		| ((mlast & DM_DSR) ? TIOCM_DSR : 0)
+		| ((mlast & DM_CTS) ? TIOCM_CTS : 0);
+	put_user(mlast, (unsigned int __user *) value);
+
+	return 0;
+}
+
+/*
+ *      Set modem lines
+ */
+static int set_modem_info(struct ch_struct *ch, unsigned int command,
+			  unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+	int mval = 0;
+	ulong lock_flags;
+
+	error = access_ok(VERIFY_READ, (void __user *) value, sizeof(int));
+	if (error == 0)
+		return -EFAULT;
+
+	get_user(arg, (unsigned int __user *) value);
+	mval |= ((arg & TIOCM_RTS) ? DM_RTS : 0)
+		| ((arg & TIOCM_DTR) ? DM_DTR : 0);
+
+	switch (command) {
+	case TIOCMBIS:  /* set flags */
+		ch->ch_mout |= mval;
+		break;
+	case TIOCMBIC:  /* clear flags */
+		ch->ch_mout &= ~mval;
+		break;
+	case TIOCMSET:
+		ch->ch_mout = mval;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags);
+
+	ch->ch_flag |= CH_PARAM;
+	(ch->ch_nd)->nd_tx_work = 1;
+	wake_up_interruptible(&ch->ch_flag_wait);
+
+	spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags);
+
+	return 0;
+}
+
+
+/*
+ *  Assign the custom baud rate to the channel structure
+ */
+static void dgrp_set_custom_speed(struct ch_struct *ch, int newrate)
+{
+	int testdiv;
+	int testrate_high;
+	int testrate_low;
+
+	int deltahigh, deltalow;
+
+	if (newrate < 0)
+		newrate = 0;
+
+	/*
+	 * Since the divisor is stored in a 16-bit integer, we make sure
+	 * we don't allow any rates smaller than a 16-bit integer would allow.
+	 * And of course, rates above the dividend won't fly.
+	 */
+	if (newrate && newrate < ((PORTSERVER_DIVIDEND / 0xFFFF) + 1))
+		newrate = ((PORTSERVER_DIVIDEND / 0xFFFF) + 1);
+	if (newrate && newrate > PORTSERVER_DIVIDEND)
+		newrate = PORTSERVER_DIVIDEND;
+
+	while (newrate > 0) {
+		testdiv = PORTSERVER_DIVIDEND / newrate;
+
+		/*
+		 * If we try to figure out what rate the PortServer would use
+		 * with the test divisor, it will be either equal or higher
+		 * than the requested baud rate.  If we then determine the
+		 * rate with a divisor one higher, we will get the next lower
+		 * supported rate below the requested.
+		 */
+		testrate_high = PORTSERVER_DIVIDEND / testdiv;
+		testrate_low  = PORTSERVER_DIVIDEND / (testdiv + 1);
+
+		/*
+		 * If the rate for the requested divisor is correct, just
+		 * use it and be done.
+		 */
+		if (testrate_high == newrate)
+			break;
+
+		/*
+		 * Otherwise, pick the rate that is closer (i.e. whichever rate
+		 * has a smaller delta).
+		 */
+		deltahigh = testrate_high - newrate;
+		deltalow = newrate - testrate_low;
+
+		if (deltahigh < deltalow)
+			newrate = testrate_high;
+		else
+			newrate = testrate_low;
+
+		break;
+	}
+
+	ch->ch_custom_speed = newrate;
+
+	drp_param(ch);
+
+	return;
+}
+
+
+/*
+ # dgrp_tty_digiseta()
+ *
+ * Ioctl to set the information from ditty.
+ *
+ * NOTE: DIGI_IXON, DSRPACE, DCDPACE, and DTRPACE are unsupported.  JAR 990922
+ */
+static int dgrp_tty_digiseta(struct tty_struct *tty,
+			     struct digi_struct *new_info)
+{
+	struct un_struct *un = tty->driver_data;
+	struct ch_struct *ch;
+
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	if (copy_from_user(&ch->ch_digi, (void __user *) new_info,
+			   sizeof(struct digi_struct)))
+		return -EFAULT;
+
+	if ((ch->ch_digi.digi_flags & RTSPACE) ||
+	    (ch->ch_digi.digi_flags & CTSPACE))
+		tty->termios.c_cflag |= CRTSCTS;
+	else
+		tty->termios.c_cflag &= ~CRTSCTS;
+
+	if (ch->ch_digi.digi_maxcps < 1)
+		ch->ch_digi.digi_maxcps = 1;
+
+	if (ch->ch_digi.digi_maxcps > 10000)
+		ch->ch_digi.digi_maxcps = 10000;
+
+	if (ch->ch_digi.digi_bufsize < 10)
+		ch->ch_digi.digi_bufsize = 10;
+
+	if (ch->ch_digi.digi_maxchar < 1)
+		ch->ch_digi.digi_maxchar = 1;
+
+	if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+		ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+	if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+		ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+	if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+		ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+	/* make the changes now */
+	drp_param(ch);
+
+	return 0;
+}
+
+
+
+/*
+ * dgrp_tty_digigetedelay()
+ *
+ * Ioctl to get the current edelay setting.
+ *
+ *
+ *
+ */
+static int dgrp_tty_digigetedelay(struct tty_struct *tty, int *retinfo)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return -EFAULT;
+
+	un = tty->driver_data;
+
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	tmp = ch->ch_edelay;
+
+	if (copy_to_user((void __user *) retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+/*
+ * dgrp_tty_digisetedelay()
+ *
+ * Ioctl to set the EDELAY setting
+ *
+ */
+static int dgrp_tty_digisetedelay(struct tty_struct *tty, int *new_info)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int new_digi;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return -EFAULT;
+
+	un = tty->driver_data;
+
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	if (copy_from_user(&new_digi, (void __user *)new_info, sizeof(int)))
+		return -EFAULT;
+
+	ch->ch_edelay = new_digi;
+
+	/* make the changes now */
+	drp_param(ch);
+
+	return 0;
+}
+
+
+/*
+ *	The usual assortment of ioctl's
+ *
+ *	note:  use tty_check_change to make sure that we are not
+ *	changing the state of a terminal when we are not a process
+ *	in the forground.  See tty_io.c
+ *		rc = tty_check_change(tty);
+ *		if (rc) return rc;
+ */
+static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+	int rc;
+	struct digiflow_struct   dflow;
+
+	if (!tty)
+		return -ENODEV;
+
+	un = tty->driver_data;
+	if (!un)
+		return -ENODEV;
+
+	ch = un->un_ch;
+	if (!ch)
+		return -ENODEV;
+
+	switch (cmd) {
+
+	/*
+	 * Here are all the standard ioctl's that we MUST implement
+	 */
+
+	case TCSBRK:
+		/*
+		 * TCSBRK is SVID version: non-zero arg --> no break
+		 * this behaviour is exploited by tcdrain().
+		 *
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds
+		 */
+
+		rc = tty_check_change(tty);
+		if (rc)
+			return rc;
+		tty_wait_until_sent(tty, 0);
+
+		if (!arg)
+			rc = dgrp_send_break(ch, 250); /* 1/4 second */
+
+		if (dgrp_tty_chars_in_buffer(tty) != 0)
+			return -EINTR;
+
+		return 0;
+
+	case TCSBRKP:
+		/* support for POSIX tcsendbreak()
+		 *
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds so we'll ask for something
+		 * in the middle: 0.375 seconds.
+		 */
+		rc = tty_check_change(tty);
+		if (rc)
+			return rc;
+		tty_wait_until_sent(tty, 0);
+
+		rc = dgrp_send_break(ch, arg ? arg*250 : 250);
+
+		if (dgrp_tty_chars_in_buffer(tty) != 0)
+			return -EINTR;
+		return 0;
+
+	case TIOCSBRK:
+		rc = tty_check_change(tty);
+		if (rc)
+			return rc;
+		tty_wait_until_sent(tty, 0);
+
+		/*
+		 * RealPort doesn't support turning on a break unconditionally.
+		 * The RealPort device will stop sending a break automatically
+		 * after the specified time value that we send in.
+		 */
+		rc = dgrp_send_break(ch, 250); /* 1/4 second */
+
+		if (dgrp_tty_chars_in_buffer(tty) != 0)
+			return -EINTR;
+		return 0;
+
+	case TIOCCBRK:
+		/*
+		 * RealPort doesn't support turning off a break unconditionally.
+		 * The RealPort device will stop sending a break automatically
+		 * after the specified time value that was sent when turning on
+		 * the break.
+		 */
+		return 0;
+
+	case TIOCGSOFTCAR:
+		rc = access_ok(VERIFY_WRITE, (void __user *) arg,
+			       sizeof(long));
+		if (rc == 0)
+			return -EFAULT;
+		put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+		return 0;
+
+	case TIOCSSOFTCAR:
+		get_user(arg, (unsigned long __user *) arg);
+		tty->termios.c_cflag =
+			((tty->termios.c_cflag & ~CLOCAL) |
+			 (arg ? CLOCAL : 0));
+		return 0;
+
+	case TIOCMGET:
+		rc = access_ok(VERIFY_WRITE, (void __user *) arg,
+				 sizeof(unsigned int));
+		if (rc == 0)
+			return -EFAULT;
+		return get_modem_info(ch, (unsigned int *) arg);
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return set_modem_info(ch, cmd, (unsigned int *) arg);
+
+	/*
+	 * Here are any additional ioctl's that we want to implement
+	 */
+
+	case TCFLSH:
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */
+		rc = tty_check_change(tty);
+		if (rc)
+			return rc;
+
+		switch (arg) {
+		case TCIFLUSH:
+		case TCIOFLUSH:
+			/* only flush input if this is the only open unit */
+			if (!IS_PRINT(MINOR(tty_devnum(tty)))) {
+				ch->ch_rout = ch->ch_rin;
+				ch->ch_send |= RR_RX_FLUSH;
+				(ch->ch_nd)->nd_tx_work = 1;
+				(ch->ch_nd)->nd_tx_ready = 1;
+				wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+			}
+			if (arg == TCIFLUSH)
+				break;
+
+		case TCOFLUSH: /* flush output, or the receive buffer */
+			/*
+			 * This is handled in the tty_ioctl.c code
+			 * calling tty_flush_buffer
+			 */
+			break;
+
+		default:
+			/* POSIX.1 says return EINVAL if we got a bad arg */
+			return -EINVAL;
+		}
+		/* pretend we didn't recognize this IOCTL */
+		return -ENOIOCTLCMD;
+
+#ifdef TIOCGETP
+	case TIOCGETP:
+#endif
+	/*****************************************
+	Linux		HPUX		Function
+	TCSETA		TCSETA		- set the termios
+	TCSETAF		TCSETAF		- wait for drain first, then set termios
+	TCSETAW		TCSETAW		- wait for drain, flush the input queue, then set termios
+	- looking at the tty_ioctl code, these command all call our
+	tty_set_termios at the driver's end, when a TCSETA* is sent,
+	it is expecting the tty to have a termio structure,
+	NOT a termios stucture.  These two structures differ in size
+	and the tty_ioctl code does a conversion before processing them both.
+	- we should treat the TCSETAW TCSETAF ioctls the same, and let
+	the tty_ioctl code do the conversion stuff.
+
+	TCSETS
+	TCSETSF		(none)
+	TCSETSW
+	- the associated tty structure has a termios structure.
+	*****************************************/
+
+	case TCGETS:
+	case TCGETA:
+		return -ENOIOCTLCMD;
+
+	case TCSETAW:
+	case TCSETAF:
+	case TCSETSF:
+	case TCSETSW:
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */
+
+		/*
+		 * Also, now that we have TXPrint, we have to check
+		 * if this is the TXPrint device and the terminal
+		 * device is open. If so, do NOT run check_change,
+		 * as the terminal device is ALWAYS the parent.
+		 */
+		if (!IS_PRINT(MINOR(tty_devnum(tty))) ||
+		    !ch->ch_tun.un_open_count) {
+			rc = tty_check_change(tty);
+			if (rc)
+				return rc;
+		}
+
+		/* wait for all the characters in tbuf to drain */
+		tty_wait_until_sent(tty, 0);
+
+		if ((cmd == TCSETSF) || (cmd == TCSETAF)) {
+			/* flush the contents of the rbuf queue */
+			/* TODO:  check if this is print device? */
+			ch->ch_send |= RR_RX_FLUSH;
+			(ch->ch_nd)->nd_tx_ready = 1;
+			(ch->ch_nd)->nd_tx_work = 1;
+			wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+			/* do we need to do this?  just to be safe! */
+			ch->ch_rout = ch->ch_rin;
+		}
+
+		/* pretend we didn't recognize this */
+		return -ENOIOCTLCMD;
+
+	case TCXONC:
+		/*
+		 * The Linux Line Discipline (LD) would do this for us if we
+		 * let it, but we have the special firmware options to do this
+		 * the "right way" regardless of hardware or software flow
+		 * control so we'll do it outselves instead of letting the LD
+		 * do it.
+		 */
+		rc = tty_check_change(tty);
+		if (rc)
+			return rc;
+
+		switch (arg) {
+		case TCOON:
+			dgrp_tty_start(tty);
+			return 0;
+		case TCOOFF:
+			dgrp_tty_stop(tty);
+			return 0;
+		case TCION:
+			dgrp_tty_input_start(tty);
+			return 0;
+		case TCIOFF:
+			dgrp_tty_input_stop(tty);
+			return 0;
+		default:
+			return -EINVAL;
+		}
+
+	case DIGI_GETA:
+		/* get information for ditty */
+		if (copy_to_user((struct digi_struct __user *) arg,
+				 &ch->ch_digi, sizeof(struct digi_struct)))
+			return -EFAULT;
+		break;
+
+	case DIGI_SETAW:
+	case DIGI_SETAF:
+		/* wait for all the characters in tbuf to drain */
+		tty_wait_until_sent(tty, 0);
+
+		if (cmd == DIGI_SETAF) {
+			/* flush the contents of the rbuf queue */
+			/* send down a packet with RR_RX_FLUSH set */
+			ch->ch_send |= RR_RX_FLUSH;
+			(ch->ch_nd)->nd_tx_ready = 1;
+			(ch->ch_nd)->nd_tx_work = 1;
+			wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+			/* do we need to do this?  just to be safe! */
+			ch->ch_rout = ch->ch_rin;
+		}
+
+		/* pretend we didn't recognize this */
+
+	case DIGI_SETA:
+		return dgrp_tty_digiseta(tty, (struct digi_struct *) arg);
+
+	case DIGI_SEDELAY:
+		return dgrp_tty_digisetedelay(tty, (int *) arg);
+
+	case DIGI_GEDELAY:
+		return dgrp_tty_digigetedelay(tty, (int *) arg);
+
+	case DIGI_GETFLOW:
+	case DIGI_GETAFLOW:
+		if (cmd == (DIGI_GETFLOW)) {
+			dflow.startc = tty->termios.c_cc[VSTART];
+			dflow.stopc = tty->termios.c_cc[VSTOP];
+		} else {
+			dflow.startc = ch->ch_xxon;
+			dflow.stopc = ch->ch_xxoff;
+		}
+
+		if (copy_to_user((char __user *)arg, &dflow, sizeof(dflow)))
+			return -EFAULT;
+		break;
+
+	case DIGI_SETFLOW:
+	case DIGI_SETAFLOW:
+
+		if (copy_from_user(&dflow, (char __user *)arg, sizeof(dflow)))
+			return -EFAULT;
+
+		if (cmd == (DIGI_SETFLOW)) {
+			tty->termios.c_cc[VSTART] = dflow.startc;
+			tty->termios.c_cc[VSTOP] = dflow.stopc;
+		} else {
+			ch->ch_xxon = dflow.startc;
+			ch->ch_xxoff = dflow.stopc;
+		}
+		break;
+
+	case DIGI_GETCUSTOMBAUD:
+		rc = access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(int));
+		if (rc == 0)
+			return -EFAULT;
+		put_user(ch->ch_custom_speed, (unsigned int __user *) arg);
+		break;
+
+	case DIGI_SETCUSTOMBAUD:
+	{
+		int new_rate;
+
+		get_user(new_rate, (unsigned int __user *) arg);
+		dgrp_set_custom_speed(ch, new_rate);
+
+		break;
+	}
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+/*
+ *  This routine allows the tty driver to be notified when
+ *  the device's termios setting have changed.  Note that we
+ *  should be prepared to accept the case where old == NULL
+ *  and try to do something rational.
+ *
+ *  So we need to make sure that our copies of ch_oflag,
+ *  ch_clag, and ch_iflag reflect the tty->termios flags.
+ */
+static void dgrp_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+	struct ktermios *ts;
+	struct ch_struct *ch;
+	struct un_struct *un;
+
+	/* seems silly, but we have to check all these! */
+	if (!tty)
+		return;
+
+	un = tty->driver_data;
+	if (!un)
+		return;
+
+	ts = &tty->termios;
+
+	ch = un->un_ch;
+	if (!ch)
+		return;
+
+	drp_param(ch);
+
+	/* the CLOCAL flag has just been set */
+	if (!(old->c_cflag & CLOCAL) && C_CLOCAL(tty))
+		wake_up_interruptible(&un->un_open_wait);
+}
+
+
+/*
+ *	Throttle receiving data.  We just set a bit and stop reading
+ *	data out of the channel buffer.  It will back up and the
+ *	FEP will do whatever is necessary to stop the far end.
+ */
+static void dgrp_tty_throttle(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_flag |= CH_RXSTOP;
+}
+
+
+static void dgrp_tty_unthrottle(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_flag &= ~CH_RXSTOP;
+}
+
+/*
+ *	Stop the transmitter
+ */
+static void dgrp_tty_stop(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_send |= RR_TX_STOP;
+	ch->ch_send &= ~RR_TX_START;
+
+	/* make the change NOW! */
+	(ch->ch_nd)->nd_tx_ready = 1;
+	if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+		wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+}
+
+/*
+ *	Start the transmitter
+ */
+static void dgrp_tty_start(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	/* TODO: don't do anything if the transmitter is not stopped */
+
+	ch->ch_send |= RR_TX_START;
+	ch->ch_send &= ~RR_TX_STOP;
+
+	/* make the change NOW! */
+	(ch->ch_nd)->nd_tx_ready = 1;
+	(ch->ch_nd)->nd_tx_work = 1;
+	if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+		wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+/*
+ *	Stop the reciever
+ */
+static void dgrp_tty_input_stop(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_send |= RR_RX_STOP;
+	ch->ch_send &= ~RR_RX_START;
+	(ch->ch_nd)->nd_tx_ready = 1;
+	if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+		wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+
+static void dgrp_tty_send_xchar(struct tty_struct *tty, char c)
+{
+	struct un_struct *un;
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	un = tty->driver_data;
+	if (!un)
+		return;
+
+	ch = un->un_ch;
+	if (!ch)
+		return;
+	if (c == STOP_CHAR(tty))
+		ch->ch_send |= RR_RX_STOP;
+	else if (c == START_CHAR(tty))
+		ch->ch_send |= RR_RX_START;
+
+	ch->ch_nd->nd_tx_ready = 1;
+	ch->ch_nd->nd_tx_work = 1;
+
+	return;
+}
+
+
+static void dgrp_tty_input_start(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+
+	if (!tty)
+		return;
+
+	ch = ((struct un_struct *) tty->driver_data)->un_ch;
+	if (!ch)
+		return;
+
+	ch->ch_send |= RR_RX_START;
+	ch->ch_send &= ~RR_RX_STOP;
+	(ch->ch_nd)->nd_tx_ready = 1;
+	(ch->ch_nd)->nd_tx_work = 1;
+	if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+		wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+
+/*
+ *	Hangup the port.  Like a close, but don't wait for output
+ *	to drain.
+ *
+ *	How do we close all the channels that are open?
+ */
+static void dgrp_tty_hangup(struct tty_struct *tty)
+{
+	struct ch_struct *ch;
+	struct nd_struct *nd;
+	struct un_struct *un;
+
+	if (!tty)
+		return;
+
+	un = tty->driver_data;
+	if (!un)
+		return;
+
+	ch = un->un_ch;
+	if (!ch)
+		return;
+
+	nd = ch->ch_nd;
+
+	if (C_HUPCL(tty)) {
+		/* LOWER DTR */
+		ch->ch_mout &= ~DM_DTR;
+		/* Don't do this here */
+		/* ch->ch_flag |= CH_HANGUP; */
+		ch->ch_nd->nd_tx_ready = 1;
+		ch->ch_nd->nd_tx_work  = 1;
+		if (waitqueue_active(&ch->ch_flag_wait))
+			wake_up_interruptible(&ch->ch_flag_wait);
+	}
+
+}
+
+/************************************************************************/
+/*                                                                      */
+/*       TTY Initialization/Cleanup Functions                           */
+/*                                                                      */
+/************************************************************************/
+
+/*
+ *	Uninitialize the TTY portion of the supplied node.  Free all
+ *      memory and resources associated with this node.  Do it in reverse
+ *      allocation order: this might possibly result in less fragmentation
+ *      of memory, though I don't know this for sure.
+ */
+void
+dgrp_tty_uninit(struct nd_struct *nd)
+{
+	char id[3];
+
+	ID_TO_CHAR(nd->nd_ID, id);
+
+	if (nd->nd_ttdriver_flags & SERIAL_TTDRV_REG) {
+		tty_unregister_driver(nd->nd_serial_ttdriver);
+
+		kfree(nd->nd_serial_ttdriver->ttys);
+		nd->nd_serial_ttdriver->ttys = NULL;
+
+		put_tty_driver(nd->nd_serial_ttdriver);
+		nd->nd_ttdriver_flags &= ~SERIAL_TTDRV_REG;
+	}
+
+	if (nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG) {
+		tty_unregister_driver(nd->nd_callout_ttdriver);
+
+		kfree(nd->nd_callout_ttdriver->ttys);
+		nd->nd_callout_ttdriver->ttys = NULL;
+
+		put_tty_driver(nd->nd_callout_ttdriver);
+		nd->nd_ttdriver_flags &= ~CALLOUT_TTDRV_REG;
+	}
+
+	if (nd->nd_ttdriver_flags & XPRINT_TTDRV_REG) {
+		tty_unregister_driver(nd->nd_xprint_ttdriver);
+
+		kfree(nd->nd_xprint_ttdriver->ttys);
+		nd->nd_xprint_ttdriver->ttys = NULL;
+
+		put_tty_driver(nd->nd_xprint_ttdriver);
+		nd->nd_ttdriver_flags &= ~XPRINT_TTDRV_REG;
+	}
+}
+
+
+
+/*
+ *     Initialize the TTY portion of the supplied node.
+ */
+int
+dgrp_tty_init(struct nd_struct *nd)
+{
+	char id[3];
+	int  rc;
+	int  i;
+
+	ID_TO_CHAR(nd->nd_ID, id);
+
+	/*
+	 *  Initialize the TTDRIVER structures.
+	 */
+
+	nd->nd_serial_ttdriver = alloc_tty_driver(CHAN_MAX);
+	sprintf(nd->nd_serial_name,  "tty_dgrp_%s_", id);
+
+	nd->nd_serial_ttdriver->owner = THIS_MODULE;
+	nd->nd_serial_ttdriver->name = nd->nd_serial_name;
+	nd->nd_serial_ttdriver->name_base = 0;
+	nd->nd_serial_ttdriver->major = 0;
+	nd->nd_serial_ttdriver->minor_start = 0;
+	nd->nd_serial_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+	nd->nd_serial_ttdriver->subtype = SERIAL_TYPE_NORMAL;
+	nd->nd_serial_ttdriver->init_termios = DefaultTermios;
+	nd->nd_serial_ttdriver->driver_name = "dgrp";
+	nd->nd_serial_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+					 TTY_DRIVER_DYNAMIC_DEV |
+					 TTY_DRIVER_HARDWARE_BREAK);
+
+	/* The kernel wants space to store pointers to tty_structs. */
+	nd->nd_serial_ttdriver->ttys =
+		kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!nd->nd_serial_ttdriver->ttys)
+		return -ENOMEM;
+
+	tty_set_operations(nd->nd_serial_ttdriver, &dgrp_tty_ops);
+
+	if (!(nd->nd_ttdriver_flags & SERIAL_TTDRV_REG)) {
+		/*
+		 *   Register tty devices
+		 */
+		rc = tty_register_driver(nd->nd_serial_ttdriver);
+		if (rc < 0) {
+			/*
+			 * If errno is EBUSY, this means there are no more
+			 * slots available to have us auto-majored.
+			 * (Which is currently supported up to 256)
+			 *
+			 * We can still request majors above 256,
+			 * we just have to do it manually.
+			 */
+			if (rc == -EBUSY) {
+				int i;
+				int max_majors = 1U << (32 - MINORBITS);
+				for (i = 256; i < max_majors; i++) {
+					nd->nd_serial_ttdriver->major = i;
+					rc = tty_register_driver(nd->nd_serial_ttdriver);
+					if (rc >= 0)
+						break;
+				}
+				/* Really fail now, since we ran out
+				 * of majors to try. */
+				if (i == max_majors)
+					return rc;
+
+			} else {
+				return rc;
+			}
+		}
+		nd->nd_ttdriver_flags |= SERIAL_TTDRV_REG;
+	}
+
+	nd->nd_callout_ttdriver = alloc_tty_driver(CHAN_MAX);
+	sprintf(nd->nd_callout_name, "cu_dgrp_%s_",  id);
+
+	nd->nd_callout_ttdriver->owner = THIS_MODULE;
+	nd->nd_callout_ttdriver->name = nd->nd_callout_name;
+	nd->nd_callout_ttdriver->name_base = 0;
+	nd->nd_callout_ttdriver->major = nd->nd_serial_ttdriver->major;
+	nd->nd_callout_ttdriver->minor_start = 0x40;
+	nd->nd_callout_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+	nd->nd_callout_ttdriver->subtype = SERIAL_TYPE_CALLOUT;
+	nd->nd_callout_ttdriver->init_termios = DefaultTermios;
+	nd->nd_callout_ttdriver->driver_name = "dgrp";
+	nd->nd_callout_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+					  TTY_DRIVER_DYNAMIC_DEV |
+					  TTY_DRIVER_HARDWARE_BREAK);
+
+	/* The kernel wants space to store pointers to tty_structs. */
+	nd->nd_callout_ttdriver->ttys =
+		kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!nd->nd_callout_ttdriver->ttys)
+		return -ENOMEM;
+
+	tty_set_operations(nd->nd_callout_ttdriver, &dgrp_tty_ops);
+
+	if (dgrp_register_cudevices) {
+		if (!(nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG)) {
+			/*
+			 *   Register cu devices
+			 */
+			rc = tty_register_driver(nd->nd_callout_ttdriver);
+			if (rc < 0)
+				return rc;
+			nd->nd_ttdriver_flags |= CALLOUT_TTDRV_REG;
+		}
+	}
+
+
+	nd->nd_xprint_ttdriver = alloc_tty_driver(CHAN_MAX);
+	sprintf(nd->nd_xprint_name,  "pr_dgrp_%s_", id);
+
+	nd->nd_xprint_ttdriver->owner = THIS_MODULE;
+	nd->nd_xprint_ttdriver->name = nd->nd_xprint_name;
+	nd->nd_xprint_ttdriver->name_base = 0;
+	nd->nd_xprint_ttdriver->major = nd->nd_serial_ttdriver->major;
+	nd->nd_xprint_ttdriver->minor_start = 0x80;
+	nd->nd_xprint_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+	nd->nd_xprint_ttdriver->subtype = SERIAL_TYPE_XPRINT;
+	nd->nd_xprint_ttdriver->init_termios = DefaultTermios;
+	nd->nd_xprint_ttdriver->driver_name = "dgrp";
+	nd->nd_xprint_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+					 TTY_DRIVER_DYNAMIC_DEV |
+					 TTY_DRIVER_HARDWARE_BREAK);
+
+	/* The kernel wants space to store pointers to tty_structs. */
+	nd->nd_xprint_ttdriver->ttys =
+		kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!nd->nd_xprint_ttdriver->ttys)
+		return -ENOMEM;
+
+	tty_set_operations(nd->nd_xprint_ttdriver, &dgrp_tty_ops);
+
+	if (dgrp_register_prdevices) {
+		if (!(nd->nd_ttdriver_flags & XPRINT_TTDRV_REG)) {
+			/*
+			 *   Register transparent print devices
+			 */
+			rc = tty_register_driver(nd->nd_xprint_ttdriver);
+			if (rc < 0)
+				return rc;
+			nd->nd_ttdriver_flags |= XPRINT_TTDRV_REG;
+		}
+	}
+
+	for (i = 0; i < CHAN_MAX; i++) {
+		struct ch_struct *ch = nd->nd_chan + i;
+
+		ch->ch_nd = nd;
+		ch->ch_digi = digi_init;
+		ch->ch_edelay = 100;
+		ch->ch_custom_speed = 0;
+		ch->ch_portnum = i;
+		ch->ch_tun.un_ch = ch;
+		ch->ch_pun.un_ch = ch;
+		ch->ch_tun.un_type = SERIAL_TYPE_NORMAL;
+		ch->ch_pun.un_type = SERIAL_TYPE_XPRINT;
+
+		init_waitqueue_head(&(ch->ch_flag_wait));
+		init_waitqueue_head(&(ch->ch_sleep));
+
+		init_waitqueue_head(&(ch->ch_tun.un_open_wait));
+		init_waitqueue_head(&(ch->ch_tun.un_close_wait));
+
+		init_waitqueue_head(&(ch->ch_pun.un_open_wait));
+		init_waitqueue_head(&(ch->ch_pun.un_close_wait));
+		tty_port_init(&ch->port);
+		tty_port_init(&ch->port);
+	}
+	return 0;
+}
diff --git a/drivers/staging/dgrp/digirp.h b/drivers/staging/dgrp/digirp.h
new file mode 100644
index 0000000..33c1394
--- /dev/null
+++ b/drivers/staging/dgrp/digirp.h
@@ -0,0 +1,129 @@
+/************************************************************************
+ * HP-UX Realport Daemon interface file.
+ *
+ * Copyright (C) 1998, by Digi International.  All Rights Reserved.
+ ************************************************************************/
+
+#ifndef _DIGIDRP_H
+#define _DIGIDRP_H
+
+/************************************************************************
+ * This file contains defines for the ioctl() interface to
+ * the realport driver.   This ioctl() interface is used by the
+ * daemon to set speed setup parameters honored by the driver.
+ ************************************************************************/
+
+struct link_struct {
+	int lk_fast_rate;  /* Fast line rate to be used
+			      when the delay is less-equal
+			      to lk_fast_delay */
+
+	int lk_fast_delay; /* Fast line rate delay in
+			      milliseconds */
+
+	int lk_slow_rate;  /* Slow line rate to be used when
+			      the delay is greater-equal
+			      to lk_slow_delay */
+
+	int lk_slow_delay; /* Slow line rate delay in
+			      milliseconds */
+
+	int lk_header_size; /* Estimated packet header size
+			       when sent across the slowest
+			       link.  */
+};
+
+#define DIGI_GETLINK	_IOW('e', 103, struct link_struct)	/* Get link parameters */
+#define DIGI_SETLINK	_IOW('e', 104, struct link_struct)	/* Set link parameters */
+
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+struct	digiflow_struct {
+	unsigned char	startc;				/* flow cntl start char	*/
+	unsigned char	stopc;				/* flow cntl stop char	*/
+};
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON	0x0001		/* Handle IXON in the FEP	*/
+#define DIGI_FAST	0x0002		/* Fast baud rates		*/
+#define RTSPACE		0x0004		/* RTS input flow control	*/
+#define CTSPACE		0x0008		/* CTS output flow control	*/
+#define DSRPACE		0x0010		/* DSR output flow control	*/
+#define DCDPACE		0x0020		/* DCD output flow control	*/
+#define DTRPACE		0x0040		/* DTR input flow control	*/
+#define DIGI_COOK	0x0080		/* Cooked processing done in FEP */
+#define DIGI_FORCEDCD	0x0100		/* Force carrier		*/
+#define	DIGI_ALTPIN	0x0200		/* Alternate RJ-45 pin config	*/
+#define	DIGI_AIXON	0x0400		/* Aux flow control in fep	*/
+#define	DIGI_PRINTER	0x0800		/* Hold port open for flow cntrl */
+#define DIGI_PP_INPUT	0x1000		/* Change parallel port to input */
+#define DIGI_422	0x4000		/* Change parallel port to input */
+#define DIGI_RTS_TOGGLE	0x8000		/* Support RTS Toggle		 */
+
+
+/************************************************************************
+ * Values associated with transparent print
+ ************************************************************************/
+#define DIGI_PLEN	8		/* String length */
+#define	DIGI_TSIZ	10		/* Terminal string len */
+
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_struct {
+	unsigned short	digi_flags;		/* Flags (see above)	*/
+	unsigned short	digi_maxcps;		/* Max printer CPS	*/
+	unsigned short	digi_maxchar;		/* Max chars in print queue */
+	unsigned short	digi_bufsize;		/* Buffer size		*/
+	unsigned char	digi_onlen;		/* Length of ON string	*/
+	unsigned char	digi_offlen;		/* Length of OFF string	*/
+	char		digi_onstr[DIGI_PLEN];	/* Printer on string	*/
+	char		digi_offstr[DIGI_PLEN];	/* Printer off string	*/
+	char		digi_term[DIGI_TSIZ];	/* terminal string	*/
+};
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+/* Read params */
+#define DIGI_GETA	_IOR('e', 94, struct digi_struct)
+
+/* Set params */
+#define DIGI_SETA	_IOW('e', 95, struct digi_struct)
+
+/* Drain & set params	*/
+#define DIGI_SETAW	_IOW('e', 96, struct digi_struct)
+
+/* Drain, flush & set params */
+#define DIGI_SETAF	_IOW('e', 97, struct digi_struct)
+
+/* Get startc/stopc flow control characters */
+#define	DIGI_GETFLOW	_IOR('e', 99, struct digiflow_struct)
+
+/* Set startc/stopc flow control characters */
+#define	DIGI_SETFLOW	_IOW('e', 100, struct digiflow_struct)
+
+/* Get Aux. startc/stopc flow control chars */
+#define	DIGI_GETAFLOW	_IOR('e', 101, struct digiflow_struct)
+
+/* Set Aux. startc/stopc flow control chars */
+#define	DIGI_SETAFLOW	_IOW('e', 102, struct digiflow_struct)
+
+/* Set integer baud rate */
+#define	DIGI_SETCUSTOMBAUD	_IOW('e', 106, int)
+
+/* Get integer baud rate */
+#define	DIGI_GETCUSTOMBAUD	_IOR('e', 107, int)
+
+#define	DIGI_GEDELAY	_IOR('d', 246, int)	/* Get edelay */
+#define	DIGI_SEDELAY	_IOW('d', 247, int)	/* Get edelay */
+
+
+#endif /* _DIGIDRP_H */
diff --git a/drivers/staging/dgrp/drp.h b/drivers/staging/dgrp/drp.h
new file mode 100644
index 0000000..84a1e7b
--- /dev/null
+++ b/drivers/staging/dgrp/drp.h
@@ -0,0 +1,693 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ *     Gene Olson  <gene at digi dot com>
+ *     James Puzzo <jamesp at digi dot com>
+ *     Scott Kilau <scottk at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ */
+
+/************************************************************************
+ * Master include file for Linux Realport Driver.
+ ************************************************************************/
+
+#ifndef __DRP_H
+#define __DRP_H
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <linux/tty.h>
+
+
+#include "digirp.h"
+
+/************************************************************************
+ * Tuning parameters.
+ ************************************************************************/
+
+#define CHAN_MAX	64		/* Max # ports per server */
+
+#define SEQ_MAX		128		/* Max # transmit sequences (2^n) */
+#define SEQ_MASK	(SEQ_MAX-1)	/* Sequence buffer modulus mask */
+
+#define TBUF_MAX	4096		/* Size of transmit buffer (2^n) */
+#define RBUF_MAX	4096		/* Size of receive buffer (2^n) */
+
+#define TBUF_MASK	(TBUF_MAX-1)	/* Transmit buffer modulus mask */
+#define RBUF_MASK	(RBUF_MAX-1)	/* Receive buffer modulus mask */
+
+#define TBUF_LOW	1000		/* Transmit low water mark */
+
+#define UIO_BASE	1000		/* Base for write operations */
+#define UIO_MIN		2000		/* Minimum size application buffer */
+#define UIO_MAX		8100		/* Unix I/O buffer size */
+
+#define MON_MAX		65536		/* Monitor buffer size (2^n) */
+#define MON_MASK	(MON_MAX-1)	/* Monitor wrap mask */
+
+#define DPA_MAX		65536		/* DPA buffer size (2^n) */
+#define DPA_MASK	(DPA_MAX-1)	/* DPA wrap mask */
+#define DPA_HIGH_WATER	58000		/* Enforce flow control when
+					 * over this amount
+					 */
+
+#define IDLE_MAX	(20 * HZ)	/* Max TCP link idle time */
+
+#define MAX_DESC_LEN	100		/* Maximum length of stored PS
+					 * description
+					 */
+
+#define WRITEBUFLEN	((4096) + 4)    /* 4 extra for alignment play space */
+
+#define VPDSIZE		512
+
+/************************************************************************
+ * Minor device decoding conventions.
+ ************************************************************************
+ *
+ * For Linux, the net and mon devices are handled via "proc", so we
+ * only have to mux the "tty" devices.  Since every PortServer will
+ * have an individual major number, the PortServer number does not
+ * need to be encoded, and in fact, does not need to exist.
+ *
+ */
+
+/*
+ * Port device decoding conventions:
+ *
+ *	Device 00 - 3f        64 dial-in modem devices. (tty)
+ *	Device 40 - 7f        64 dial-out tty devices.  (cu)
+ *	Device 80 - bf        64 dial-out printer devices.
+ *
+ *  IS_PRINT(dev)		This is a printer device.
+ *
+ *  OPEN_CATEGORY(dev)		Specifies the device category.  No two
+ *				devices of different categories may be open
+ *				at the same time.
+ *
+ * The following require the category returned by OPEN_CATEGORY().
+ *
+ *  OPEN_WAIT_AVAIL(cat)	Waits on open until the device becomes
+ *				available.  Fails if NDELAY specified.
+ *
+ *  OPEN_WAIT_CARRIER(cat)	Waits on open if carrier is not present.
+ *				Succeeds if NDELAY is given.
+ *
+ *  OPEN_FORCES_CARRIER(cat)	Carrier is forced high on open.
+ *
+ */
+
+#define PORT_NUM(dev)			((dev) & 0x3f)
+
+#define OPEN_CATEGORY(dev)		((((dev) & 0x80) & 0x40))
+#define IS_PRINT(dev)			(((dev) & 0xff) >= 0x80)
+
+#define OPEN_WAIT_AVAIL(cat)		(((cat) & 0x40) == 0x000)
+#define OPEN_WAIT_CARRIER(cat)		(((cat) & 0x40) == 0x000)
+#define OPEN_FORCES_CARRIER(cat)	(((cat) & 0x40) != 0x000)
+
+
+/************************************************************************
+ * Modem signal defines for 16450/16550 compatible FEP.
+ * set in ch_mout, ch_mflow, ch_mlast etc
+ ************************************************************************/
+
+/* TODO : Re-verify that these modem signal definitions are correct */
+
+#define DM_DTR		0x01
+#define DM_RTS		0x02
+#define DM_RTS_TOGGLE	0x04
+
+#define DM_OUT1		0x04
+#define DM_OUT2		0x08
+
+#define DM_CTS		0x10
+#define DM_DSR		0x20
+#define DM_RI		0x40
+#define DM_CD		0x80		/* This is the DCD flag */
+
+
+/************************************************************************
+ * Realport Event Flags.
+ ************************************************************************/
+
+#define EV_OPU		0x0001		/* Ouput paused by client */
+#define EV_OPS		0x0002		/* Output paused by XOFF */
+#define EV_OPX		0x0004		/* Output paused by XXOFF */
+#define EV_OPH		0x0008		/* Output paused by MFLOW */
+#define EV_IPU		0x0010		/* Input paused by client */
+#define EV_IPS		0x0020		/* Input paused by hi/low water */
+#define EV_TXB		0x0040		/* Transmit break pending */
+#define EV_TXI		0x0080		/* Transmit immediate pending */
+#define EV_TXF		0x0100		/* Transmit flow control pending */
+#define EV_RXB		0x0200		/* Break received */
+
+
+/************************************************************************
+ * Realport CFLAGS.
+ ************************************************************************/
+
+#define CF_CS5		0x0000		/* 5 bit characters */
+#define CF_CS6		0x0010		/* 6 bit characters */
+#define CF_CS7		0x0020		/* 7 bit characters */
+#define CF_CS8		0x0030		/* 8 bit characters */
+#define CF_CSIZE	0x0030		/* Character size */
+#define CF_CSTOPB	0x0040		/* Two stop bits */
+#define CF_CREAD	0x0080		/* Enable receiver */
+#define CF_PARENB	0x0100		/* Enable parity */
+#define CF_PARODD	0x0200		/* Odd parity */
+#define CF_HUPCL	0x0400		/* Drop DTR on close */
+
+
+/************************************************************************
+ * Realport XFLAGS.
+ ************************************************************************/
+
+#define XF_XPAR		0x0001		/* Enable Mark/Space Parity */
+#define XF_XMODEM	0x0002		/* Enable in-band modem signalling */
+#define XF_XCASE	0x0004		/* Convert special characters */
+#define XF_XEDATA	0x0008		/* Error data in stream */
+#define XF_XTOSS	0x0010		/* Toss IXANY characters */
+#define XF_XIXON	0x0020		/* xxon/xxoff enable */
+
+
+/************************************************************************
+ * Realport IFLAGS.
+ ************************************************************************/
+
+#define IF_IGNBRK	0x0001		/* Ignore input break */
+#define IF_BRKINT	0x0002		/* Break interrupt */
+#define IF_IGNPAR	0x0004		/* Ignore error characters */
+#define IF_PARMRK	0x0008		/* Error chars marked with 0xff */
+#define IF_INPCK	0x0010		/* Input parity checking enabled */
+#define IF_ISTRIP	0x0020		/* Input chars masked with 0x7F */
+#define IF_IXON		0x0400		/* Output software flow control */
+#define IF_IXANY	0x0800		/* Restart output on any char */
+#define	IF_IXOFF	0x1000		/* Input software flow control */
+#define IF_DOSMODE	0x8000		/* 16450-compatible errors */
+
+
+/************************************************************************
+ * Realport OFLAGS.
+ ************************************************************************/
+
+#define OF_OLCUC	0x0002		/* Map lower to upper case */
+#define OF_ONLCR	0x0004		/* Map NL to CR-NL */
+#define OF_OCRNL	0x0008		/* Map CR to NL */
+#define OF_ONOCR	0x0010		/* No CR output at column 0 */
+#define OF_ONLRET	0x0020		/* Assume NL does NL/CR */
+#define OF_TAB3		0x1800		/* Tabs expand to 8 spaces */
+#define OF_TABDLY	0x1800		/* Tab delay */
+
+/************************************************************************
+ * Unit flag definitions for un_flag.
+ ************************************************************************/
+
+/* These are the DIGI unit flags */
+#define UN_EXCL		0x00010000	/* Exclusive open */
+#define UN_STICKY	0x00020000	/* TTY Settings are now sticky */
+#define UN_BUSY		0x00040000	/* Some work this channel */
+#define UN_PWAIT	0x00080000	/* Printer waiting for terminal */
+#define UN_TIME		0x00100000	/* Waiting on time */
+#define UN_EMPTY	0x00200000	/* Waiting output queue empty */
+#define UN_LOW		0x00400000	/* Waiting output low water */
+#define UN_DIGI_MASK	0x00FF0000	/* Waiting output low water */
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field
+ *
+ * these are the ASYNC flags copied from serial.h
+ *
+ */
+#define UN_HUP_NOTIFY	0x0001 /* Notify getty on hangups and
+				* closes on the callout port
+				*/
+#define UN_FOURPORT	0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define UN_SAK		0x0004	/* Secure Attention Key (Orange book) */
+#define UN_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define UN_SPD_MASK	0x0030
+#define UN_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+#define UN_SPD_VHI	0x0020	/* Use 115200 instead of 38400 bps */
+#define UN_SPD_CUST	0x0030	/* Use user-specified divisor */
+
+#define UN_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define UN_AUTO_IRQ	0x0080 /* Do automatic IRQ during autoconfiguration */
+
+#define UN_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define UN_PGRP_LOCKOUT	   0x0200 /* Lock out cua opens based on pgrp */
+#define UN_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define UN_FLAGS	0x0FFF	/* Possible legal async flags */
+#define UN_USR_MASK	0x0430	/* Legal flags that non-privileged
+				 * users can set or reset
+				 */
+
+#define UN_INITIALIZED		0x80000000 /* Serial port was initialized */
+#define UN_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define UN_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define UN_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define UN_CLOSING		0x08000000 /* Serial port is closing */
+#define UN_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define UN_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+#define UN_SHARE_IRQ		0x01000000 /* for multifunction cards */
+
+
+/************************************************************************
+ * Structure for terminal or printer unit.  struct un_struct
+ *
+ * Note that in some places the code assumes the "tty_t" is placed
+ * first in the structure.
+ ************************************************************************/
+
+struct un_struct {
+	struct tty_struct *un_tty;		/* System TTY struct */
+	struct ch_struct *un_ch;		/* Associated channel */
+
+	ushort     un_open_count;		/* Successful open count */
+	int		un_flag;		/* Unit flags */
+	ushort     un_tbusy;		/* Busy transmit count */
+
+	wait_queue_head_t  un_open_wait;
+	wait_queue_head_t  un_close_wait;
+	ushort	un_type;
+	struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Channel State Numbers for ch_state.
+ ************************************************************************/
+
+/*
+ * The ordering is important.
+ *
+ *    state <= CS_WAIT_CANCEL implies the channel is definitely closed.
+ *
+ *    state >= CS_WAIT_FAIL  implies the channel is definitely open.
+ *
+ *    state >= CS_READY implies data is allowed on the channel.
+ */
+
+enum dgrp_ch_state_t {
+	CS_IDLE = 0,	    /* Channel is idle */
+	CS_WAIT_OPEN = 1,   /* Waiting for Immediate Open Resp */
+	CS_WAIT_CANCEL = 2, /* Waiting for Per/Incom Cancel Resp */
+	CS_WAIT_FAIL = 3,   /* Waiting for Immed Open Failure */
+	CS_SEND_QUERY = 4,  /* Ready to send Port Query */
+	CS_WAIT_QUERY = 5,  /* Waiting for Port Query Response */
+	CS_READY = 6,	    /* Ready to accept commands and data */
+	CS_SEND_CLOSE =	7,  /* Ready to send Close Request */
+	CS_WAIT_CLOSE =	8   /* Waiting for Close Response */
+};
+
+/************************************************************************
+ * Device flag definitions for ch_flag.
+ ************************************************************************/
+
+/*
+ *  Note that the state of the two carrier based flags is key.	When
+ *  we check for carrier state transitions, we look at the current
+ *  physical state of the DCD line and compare it with PHYS_CD (which
+ *  was the state the last time we checked), and we also determine
+ *  a new virtual state (composite of the physical state, FORCEDCD,
+ *  CLOCAL, etc.) and compare it with VIRT_CD.
+ *
+ *  VIRTUAL transitions high will have the side effect of waking blocked
+ *  opens.
+ *
+ *  PHYSICAL transitions low will cause hangups to occur _IF_ the virtual
+ *  state is also low.	We DON'T want to hangup on a PURE virtual drop.
+ */
+
+#define CH_HANGUP	0x00002		/* Server port ready to close */
+
+#define CH_VIRT_CD	0x00004		/* Carrier was virtually present */
+#define CH_PHYS_CD	0x00008		/* Carrier was physically present */
+
+#define CH_CLOCAL	0x00010		/* CLOCAL set in cflags */
+#define CH_BAUD0	0x00020		/* Baud rate zero hangup */
+
+#define CH_FAST_READ	0x00040		/* Fast reads are enabled */
+#define CH_FAST_WRITE	0x00080		/* Fast writes are enabled */
+
+#define CH_PRON		0x00100		/* Printer on string active */
+#define CH_RX_FLUSH	0x00200		/* Flushing receive data */
+#define CH_LOW		0x00400		/* Thread waiting for LOW water */
+#define CH_EMPTY	0x00800		/* Thread waiting for EMPTY */
+#define CH_DRAIN	0x01000		/* Close is waiting to drain */
+#define CH_INPUT	0x02000		/* Thread waiting for INPUT */
+#define CH_RXSTOP	0x04000		/* Stop output to ldisc */
+#define CH_PARAM	0x08000		/* A parameter was updated */
+#define CH_WAITING_SYNC 0x10000		/* A pending sync was assigned
+					 * to this port.
+					 */
+#define CH_PORT_GONE	0x20000		/* Port has disappeared */
+#define CH_TX_BREAK	0x40000		/* TX Break to be sent,
+					 * but has not yet.
+					 */
+
+/************************************************************************
+ * Types of Open Requests for ch_otype.
+ ************************************************************************/
+
+#define OTYPE_IMMEDIATE	  0		/* Immediate Open */
+#define OTYPE_PERSISTENT  1		/* Persistent Open */
+#define OTYPE_INCOMING	  2		/* Incoming Open */
+
+
+/************************************************************************
+ * Request/Response flags.
+ ************************************************************************/
+
+#define RR_SEQUENCE	0x0001		/* Get server RLAST, TIN */
+#define RR_STATUS	0x0002		/* Get server MINT, EINT */
+#define RR_BUFFER	0x0004		/* Get server RSIZE, TSIZE */
+#define RR_CAPABILITY	0x0008		/* Get server port capabilities */
+
+#define RR_TX_FLUSH	0x0040		/* Flush output buffers */
+#define RR_RX_FLUSH	0x0080		/* Flush input buffers */
+
+#define RR_TX_STOP	0x0100		/* Pause output */
+#define RR_RX_STOP	0x0200		/* Pause input */
+#define RR_TX_START	0x0400		/* Start output */
+#define RR_RX_START	0x0800		/* Start input */
+
+#define RR_TX_BREAK	0x1000		/* Send BREAK */
+#define RR_TX_ICHAR	0x2000		/* Send character immediate */
+
+
+/************************************************************************
+ * Channel information structure.   struct ch_struct
+ ************************************************************************/
+
+struct ch_struct {
+	struct digi_struct ch_digi;		/* Digi variables */
+	int	ch_edelay;		/* Digi edelay */
+
+	struct tty_port port;
+	struct un_struct ch_tun;	/* Terminal unit info */
+	struct un_struct ch_pun;	/* Printer unit info */
+
+	struct nd_struct *ch_nd;	/* Node pointer */
+	u8  *ch_tbuf;		/* Local Transmit Buffer */
+	u8  *ch_rbuf;		/* Local Receive Buffer */
+	ulong	ch_cpstime;		/* Printer CPS time */
+	ulong	ch_waketime;		/* Printer wake time */
+
+	ulong	ch_flag;		/* CH_* flags */
+
+	enum dgrp_ch_state_t ch_state;		/* CS_* Protocol state */
+	ushort	ch_send;		/* Bit vector of RR_* requests */
+	ushort	ch_expect;		/* Bit vector of RR_* responses */
+	ushort	ch_wait_carrier;	/* Thread count waiting for carrier */
+	ushort	ch_wait_count[3];	/* Thread count waiting by otype */
+
+	ushort	ch_portnum;		/* Port number */
+	ushort	ch_open_count;		/* Successful open count */
+	ushort	ch_category;		/* Device category */
+	ushort	ch_open_error;		/* Last open error number */
+	ushort	ch_break_time;		/* Pending break request time */
+	ushort	ch_cpsrem;		/* Printer CPS remainder */
+	ushort	ch_ocook;		/* Realport fastcook oflags */
+	ushort	ch_inwait;		/* Thread count in CLIST input */
+
+	ushort	ch_tin;			/* Local transmit buffer in ptr */
+	ushort	ch_tout;		/* Local transmit buffer out ptr */
+	ushort	ch_s_tin;		/* Realport TIN */
+	ushort	ch_s_tpos;		/* Realport TPOS */
+	ushort	ch_s_tsize;		/* Realport TSIZE */
+	ushort	ch_s_treq;		/* Realport TREQ */
+	ushort	ch_s_elast;		/* Realport ELAST */
+
+	ushort	ch_rin;			/* Local receive buffer in ptr */
+	ushort	ch_rout;		/* Local receive buffer out ptr */
+	ushort	ch_s_rin;		/* Realport RIN */
+	/* David Fries 7-13-2001, ch_s_rin should be renamed ch_s_rout because
+	 * the variable we want to represent is the PortServer's ROUT, which is
+	 * the sequence number for the next byte the PortServer will send us.
+	 * RIN is the sequence number for the next byte the PortServer will
+	 * receive from the uart.  The port server will send data as long as
+	 * ROUT is less than RWIN.  What would happen is the port is opened, it
+	 * receives data, it gives the value of RIN, we set the RWIN to
+	 * RIN+RBUF_MAX-1, it sends us RWIN-ROUT bytes which overflows.	 ROUT
+	 * is set to zero when the port is opened, so we start at zero and
+	 * count up as data is received.
+	 */
+	ushort	ch_s_rwin;		/* Realport RWIN */
+	ushort	ch_s_rsize;		/* Realport RSIZE */
+
+	ushort	ch_tmax;		/* Local TMAX */
+	ushort	ch_ttime;		/* Local TTIME */
+	ushort	ch_rmax;		/* Local RMAX */
+	ushort	ch_rtime;		/* Local RTIME */
+	ushort	ch_rlow;		/* Local RLOW */
+	ushort	ch_rhigh;		/* Local RHIGH */
+
+	ushort	ch_s_tmax;		/* Realport TMAX */
+	ushort	ch_s_ttime;		/* Realport TTIME */
+	ushort	ch_s_rmax;		/* Realport RMAX */
+	ushort	ch_s_rtime;		/* Realport RTIME */
+	ushort	ch_s_rlow;		/* Realport RLOW */
+	ushort	ch_s_rhigh;		/* Realport RHIGH */
+
+	ushort	ch_brate;		/* Local baud rate */
+	ushort	ch_cflag;		/* Local tty cflags */
+	ushort	ch_iflag;		/* Local tty iflags */
+	ushort	ch_oflag;		/* Local tty oflags */
+	ushort	ch_xflag;		/* Local tty xflags */
+
+	ushort	ch_s_brate;		/* Realport BRATE */
+	ushort	ch_s_cflag;		/* Realport CFLAG */
+	ushort	ch_s_iflag;		/* Realport IFLAG */
+	ushort	ch_s_oflag;		/* Realport OFLAG */
+	ushort	ch_s_xflag;		/* Realport XFLAG */
+
+	u8	ch_otype;		/* Open request type */
+	u8	ch_pscan_savechar;	/* Last character read by parity scan */
+	u8	ch_pscan_state;		/* PScan State based on last 2 chars */
+	u8	ch_otype_waiting;	/* Type of open pending in server */
+	u8	ch_flush_seq;		/* Receive flush end sequence */
+	u8	ch_s_mlast;		/* Realport MLAST */
+
+	u8	ch_mout;		/* Local MOUT */
+	u8	ch_mflow;		/* Local MFLOW */
+	u8	ch_mctrl;		/* Local MCTRL */
+	u8	ch_xon;			/* Local XON */
+	u8	ch_xoff;		/* Local XOFF */
+	u8	ch_lnext;		/* Local LNEXT */
+	u8	ch_xxon;		/* Local XXON */
+	u8	ch_xxoff;		/* Local XXOFF */
+
+	u8	ch_s_mout;		/* Realport MOUT */
+	u8	ch_s_mflow;		/* Realport MFLOW */
+	u8	ch_s_mctrl;		/* Realport MCTRL */
+	u8	ch_s_xon;		/* Realport XON */
+	u8	ch_s_xoff;		/* Realport XOFF */
+	u8	ch_s_lnext;		/* Realport LNEXT */
+	u8	ch_s_xxon;		/* Realport XXON */
+	u8	ch_s_xxoff;		/* Realport XXOFF */
+
+	wait_queue_head_t ch_flag_wait;	/* Wait queue for ch_flag changes */
+	wait_queue_head_t ch_sleep;	/* Wait queue for my_sleep() */
+
+	int	ch_custom_speed;	/* Realport custom speed */
+	int	ch_txcount;		/* Running TX count */
+	int	ch_rxcount;		/* Running RX count */
+};
+
+
+/************************************************************************
+ * Node State definitions.
+ ************************************************************************/
+
+enum dgrp_nd_state_t {
+	NS_CLOSED = 0,	   /* Network device is closed */
+	NS_IDLE = 1,	   /* Network connection inactive */
+	NS_SEND_QUERY =	2, /* Send server query */
+	NS_WAIT_QUERY =	3, /* Wait for query response */
+	NS_READY = 4,	   /* Network ready */
+	NS_SEND_ERROR =	5  /* Must send error hangup */
+};
+
+#define ND_STATE_STR(x) \
+	((x) == NS_CLOSED     ? "CLOSED"     : \
+	((x) == NS_IDLE	      ? "IDLE"	     : \
+	((x) == NS_SEND_QUERY ? "SEND_QUERY" : \
+	((x) == NS_WAIT_QUERY ? "WAIT_QUERY" : \
+	((x) == NS_READY      ? "READY"	     : \
+	((x) == NS_SEND_ERROR ? "SEND_ERROR" : "UNKNOWN"))))))
+
+/************************************************************************
+ * Node Flag definitions.
+ ************************************************************************/
+
+#define ND_SELECT	0x0001		/* Multiple net read selects */
+#define ND_DEB_WAIT	0x0002		/* Debug Device waiting */
+
+
+/************************************************************************
+ * Monitoring flag definitions.
+ ************************************************************************/
+
+#define MON_WAIT_DATA	0x0001		/* Waiting for buffer data */
+#define MON_WAIT_SPACE	0x0002		/* Waiting for buffer space */
+
+/************************************************************************
+ * DPA flag definitions.
+ ************************************************************************/
+
+#define DPA_WAIT_DATA	0x0001		/* Waiting for buffer data */
+#define DPA_WAIT_SPACE	0x0002		/* Waiting for buffer space */
+
+
+/************************************************************************
+ * Definitions taken from Realport Dump.
+ ************************************************************************/
+
+#define RPDUMP_MAGIC	"Digi-RealPort-1.0"
+
+#define RPDUMP_MESSAGE	0xE2		/* Descriptive message */
+#define RPDUMP_RESET	0xE7		/* Connection reset */
+#define RPDUMP_CLIENT	0xE8		/* Client data */
+#define RPDUMP_SERVER	0xE9		/* Server data */
+
+
+/************************************************************************
+ * Node request/response definitions.
+ ************************************************************************/
+
+#define NR_ECHO		0x0001		/* Server echo packet */
+#define NR_IDENT	0x0002		/* Server Product ID */
+#define NR_CAPABILITY	0x0004		/* Server Capabilties */
+#define NR_VPD		0x0008		/* Server VPD, if any */
+#define NR_PASSWORD	0x0010		/* Server Password */
+
+/************************************************************************
+ * Registration status of the node's Linux struct tty_driver structures.
+ ************************************************************************/
+#define SERIAL_TTDRV_REG   0x0001     /* nd_serial_ttdriver registered	*/
+#define CALLOUT_TTDRV_REG  0x0002     /* nd_callout_ttdriver registered */
+#define XPRINT_TTDRV_REG   0x0004     /* nd_xprint_ttdriver registered	*/
+
+
+/************************************************************************
+ * Node structure.  There exists one of these for each associated
+ * realport server.
+ ************************************************************************/
+
+struct nd_struct {
+	struct list_head	list;
+	long	      nd_major;		   /* Node's major number	    */
+	long	      nd_ID;		   /* Node's ID code		    */
+
+	char	      nd_serial_name[50];   /* "tty_dgrp_<id>_" + null	    */
+	char	      nd_callout_name[50];  /* "cu_dgrp_<id>_" + null	    */
+	char	      nd_xprint_name[50];   /* "pr_dgrp_<id>_" + null	    */
+
+	char	     password[16];	  /* Password for server, if needed */
+	int	     nd_tty_ref_cnt;	  /* Linux tty reference count	   */
+
+	struct proc_dir_entry *nd_net_de; /* Dir entry for /proc/dgrp/net  */
+	struct proc_dir_entry *nd_mon_de; /* Dir entry for /proc/dgrp/mon  */
+	struct proc_dir_entry *nd_ports_de; /* Dir entry for /proc/dgrp/ports*/
+	struct proc_dir_entry *nd_dpa_de; /* Dir entry for /proc/dgrp/dpa  */
+
+	spinlock_t nd_lock;		  /* General node lock		   */
+
+	struct semaphore nd_net_semaphore; /* Net read/write lock	    */
+	struct semaphore nd_mon_semaphore; /* Monitor buffer lock	    */
+	spinlock_t nd_dpa_lock;		/* DPA buffer lock	     */
+
+	enum dgrp_nd_state_t nd_state;	  /* NS_* network state */
+	int	      nd_chan_count;	   /* # active channels		    */
+	int	      nd_flag;		   /* Node flags		    */
+	int	      nd_send;		   /* Responses to send		    */
+	int	      nd_expect;	   /* Responses we expect	    */
+
+	u8	 *nd_iobuf;	       /* Network R/W Buffer		*/
+	wait_queue_head_t nd_tx_waitq;	  /* Network select wait queue	   */
+
+	u8	 *nd_inputbuf;	       /* Input Buffer			*/
+	u8	 *nd_inputflagbuf;     /* Input Flags Buffer		*/
+
+	int	      nd_tx_deposit;	   /* Accumulated transmit deposits */
+	int	      nd_tx_charge;	   /* Accumulated transmit charges  */
+	int	      nd_tx_credit;	   /* Current TX credit		    */
+	int	      nd_tx_ready;	   /* Ready to transmit		    */
+	int	      nd_tx_work;	   /* TX work waiting		    */
+	ulong	     nd_tx_time;	  /* Last transmit time		   */
+	ulong	     nd_poll_time;	  /* Next scheduled poll time	   */
+
+	int	      nd_delay;		   /* Current TX delay		    */
+	int	      nd_rate;		   /* Current TX rate		    */
+	struct link_struct nd_link;		/* Link speed params.		 */
+
+	int	      nd_seq_in;	   /* TX seq in ptr		    */
+	int	      nd_seq_out;	   /* TX seq out ptr		    */
+	int	      nd_unack;		   /* Unacknowledged byte count	    */
+	int	      nd_remain;	   /* Remaining receive bytes	    */
+	int	      nd_tx_module;	   /* Current TX module #	    */
+	int	      nd_rx_module;	   /* Current RX module #	    */
+	char	     *nd_error;		   /* Protocol error message	    */
+
+	int	      nd_write_count;	   /* drp_write() call count	    */
+	int	      nd_read_count;	   /* drp_read() count		    */
+	int	      nd_send_count;	   /* TCP message sent		    */
+	int	      nd_tx_byte;	   /* Transmit byte count	    */
+	int	      nd_rx_byte;	   /* Receive byte count	    */
+
+	ulong	     nd_mon_lbolt;	 /* Monitor start time		   */
+	int	      nd_mon_flag;	  /* Monitor flags		    */
+	int	      nd_mon_in;	  /* Monitor in pointer		    */
+	int	      nd_mon_out;	  /* Monitor out pointer	    */
+	wait_queue_head_t nd_mon_wqueue;  /* Monitor wait queue (on flags)  */
+	u8	 *nd_mon_buf;	      /* Monitor buffer			*/
+
+	ulong	     nd_dpa_lbolt;	/* DPA start time	      */
+	int	     nd_dpa_flag;	/* DPA flags		      */
+	int	     nd_dpa_in;		/* DPA in pointer	      */
+	int	     nd_dpa_out;	/* DPA out pointer	      */
+	wait_queue_head_t nd_dpa_wqueue; /* DPA wait queue (on flags)  */
+	u8	  *nd_dpa_buf;	/* DPA buffer		      */
+
+	uint	     nd_dpa_debug;
+	uint	     nd_dpa_port;
+
+	wait_queue_head_t nd_seq_wque[SEQ_MAX];	  /* TX thread wait queues */
+	u8	  nd_seq_wait[SEQ_MAX];	  /* Transmit thread wait count */
+
+	ushort	     nd_seq_size[SEQ_MAX];   /* Transmit seq packet size   */
+	ulong	     nd_seq_time[SEQ_MAX];   /* Transmit seq packet time   */
+
+	ushort	     nd_hw_ver;		  /* HW version returned from PS   */
+	ushort	     nd_sw_ver;		  /* SW version returned from PS   */
+	uint	     nd_hw_id;		  /* HW ID returned from PS	   */
+	u8	  nd_ps_desc[MAX_DESC_LEN+1];  /* Description from PS	*/
+	uint	     nd_vpd_len;		/* VPD len, if any */
+	u8	     nd_vpd[VPDSIZE];		/* VPD, if any */
+
+	ulong	     nd_ttdriver_flags;	  /* Registration status	    */
+	struct tty_driver *nd_serial_ttdriver;	/* Linux TTYDRIVER structure */
+	struct tty_driver *nd_callout_ttdriver; /* Linux TTYDRIVER structure */
+	struct tty_driver *nd_xprint_ttdriver;	/* Linux TTYDRIVER structure */
+
+	u8	     *nd_writebuf;		/* Used to cache data read
+						 * from user
+						 */
+	struct ch_struct nd_chan[CHAN_MAX];  /* Channel array		    */
+	struct device *nd_class_dev;	/* Hang our sysfs stuff off of here */
+};
+
+#endif /* __DRP_H */
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 029725c..413da0d 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -3955,12 +3955,7 @@
 	 * EEPROM then we need to generate the last octet and set it on the
 	 * device
 	 */
-	if (adapter->rom_addr[0] == 0x00 &&
-	    adapter->rom_addr[1] == 0x00 &&
-	    adapter->rom_addr[2] == 0x00 &&
-	    adapter->rom_addr[3] == 0x00 &&
-	    adapter->rom_addr[4] == 0x00 &&
-	    adapter->rom_addr[5] == 0x00) {
+	if (is_zero_ether_addr(adapter->rom_addr)) {
 		/*
 		 * We need to randomly generate the last octet so we
 		 * decrease our chances of setting the mac address to
@@ -3995,16 +3990,14 @@
 static int et131x_pci_init(struct et131x_adapter *adapter,
 						struct pci_dev *pdev)
 {
-	int cap = pci_pcie_cap(pdev);
 	u16 max_payload;
-	u16 ctl;
 	int i, rc;
 
 	rc = et131x_init_eeprom(adapter);
 	if (rc < 0)
 		goto out;
 
-	if (!cap) {
+	if (!pci_is_pcie(pdev)) {
 		dev_err(&pdev->dev, "Missing PCIe capabilities\n");
 		goto err_out;
 	}
@@ -4012,7 +4005,7 @@
 	/* Let's set up the PORT LOGIC Register.  First we need to know what
 	 * the max_payload_size is
 	 */
-	if (pci_read_config_word(pdev, cap + PCI_EXP_DEVCAP, &max_payload)) {
+	if (pcie_capability_read_word(pdev, PCI_EXP_DEVCAP, &max_payload)) {
 		dev_err(&pdev->dev,
 		    "Could not read PCI config space for Max Payload Size\n");
 		goto err_out;
@@ -4049,17 +4042,10 @@
 	}
 
 	/* Change the max read size to 2k */
-	if (pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl)) {
+	if (pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+				PCI_EXP_DEVCTL_READRQ, 0x4 << 12)) {
 		dev_err(&pdev->dev,
-			"Could not read PCI config space for Max read size\n");
-		goto err_out;
-	}
-
-	ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | (0x04 << 12);
-
-	if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) {
-		dev_err(&pdev->dev,
-		      "Could not write PCI config space for Max read size\n");
+			"Couldn't change PCI config space for Max read size\n");
 		goto err_out;
 	}
 
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c
index f8b8e71..47cc365 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c
@@ -94,27 +94,27 @@
 u16 hdr_checksum(struct pseudo_hdr *pHdr);
 
 struct dsp_file_hdr {
-	u32  version_id;	// Version ID of this image format.
-	u32  package_id;	// Package ID of code release.
-	u32  build_date;	// Date/time stamp when file was built.
-	u32  commands_offset;	// Offset to attached commands in Pseudo Hdr format.
-	u32  loader_offset;	// Offset to bootloader code.
-	u32  loader_code_address;	// Start address of bootloader.
-	u32  loader_code_end;	// Where bootloader code ends.
+	u32  version_id;	/* Version ID of this image format. */
+	u32  package_id;	/* Package ID of code release. */
+	u32  build_date;	/* Date/time stamp when file was built. */
+	u32  commands_offset;	/* Offset to attached commands in Pseudo Hdr format. */
+	u32  loader_offset;	/* Offset to bootloader code. */
+	u32  loader_code_address;	/* Start address of bootloader. */
+	u32  loader_code_end;	/* Where bootloader code ends. */
 	u32  loader_code_size;
-	u32  version_data_offset;	// Offset were scrambled version data begins.
-	u32  version_data_size;	// Size, in words, of scrambled version data.
-	u32  nDspImages;	// Number of DSP images in file.
+	u32  version_data_offset;	/* Offset were scrambled version data begins. */
+	u32  version_data_size;	/* Size, in words, of scrambled version data. */
+	u32  nDspImages;	/* Number of DSP images in file. */
 } __attribute__ ((packed));
 
 struct dsp_image_info {
-	u32  coff_date;		// Date/time when DSP Coff image was built.
-	u32  begin_offset;	// Offset in file where image begins.
-	u32  end_offset;	// Offset in file where image begins.
-	u32  run_address;	// On chip Start address of DSP code.
-	u32  image_size;	// Size of image.
-	u32  version;		// Embedded version # of DSP code.
-	unsigned short checksum;	// Dsp File checksum
+	u32  coff_date;		/* Date/time when DSP Coff image was built. */
+	u32  begin_offset;	/* Offset in file where image begins. */
+	u32  end_offset;	/* Offset in file where image begins. */
+	u32  run_address;	/* On chip Start address of DSP code. */
+	u32  image_size;	/* Size of image. */
+	u32  version;		/* Embedded version # of DSP code. */
+	unsigned short checksum;	/* Dsp File checksum */
 	unsigned short pad1;
 } __attribute__ ((packed));
 
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index 31929ef..809fa48 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -73,7 +73,7 @@
 	}
 
 	ret = usb_control_msg(ft1000dev->dev, pipe, request, requesttype,
-			      value, index, data, size, LARGE_TIMEOUT);
+			      value, index, data, size, timeout);
 
 	if (ret > 0)
 		ret = 0;
@@ -110,7 +110,7 @@
 			     nRegIndx,
 			     Data,
 			     2,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_GET_TIMEOUT);
 
 	return ret;
 }
@@ -143,7 +143,7 @@
 			     nRegIndx,
 			     NULL,
 			     0,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_SET_TIMEOUT);
 
 	return ret;
 }
@@ -178,7 +178,7 @@
 			     indx,
 			     buffer,
 			     cnt,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_GET_TIMEOUT);
 
 	return ret;
 }
@@ -215,7 +215,7 @@
 			     indx,
 			     buffer,
 			     cnt,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_SET_TIMEOUT);
 
 	return ret;
 }
@@ -255,7 +255,7 @@
 			     indx,
 			     buffer,
 			     2,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_GET_TIMEOUT);
 
 	return ret;
 }
@@ -294,7 +294,7 @@
 			     indx,
 			     NULL,
 			     0,
-			     LARGE_TIMEOUT);
+			     USB_CTRL_SET_TIMEOUT);
 
 	return ret;
 }
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
index 642bb89..2aa6a1c 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
@@ -36,8 +36,6 @@
 
 #define FT1000_STATUS_CLOSING  0x01
 
-#define LARGE_TIMEOUT   5000
-
 #define DSPBCMSGID              0x10
 
 /* Electrabuzz specific DPRAM mapping */
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
index 80bde05..e26c6a8 100644
--- a/drivers/staging/gdm72xx/gdm_qos.c
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -106,8 +106,8 @@
 
 	for (i = 0 ; i < QOS_MAX; i++) {
 		INIT_LIST_HEAD(&qcb->qos_list[i]);
-		qcb->csr[i].QoSBufCount = 0;
-		qcb->csr[i].Enabled = 0;
+		qcb->csr[i].qos_buf_count = 0;
+		qcb->csr[i].enabled = 0;
 	}
 
 	qcb->qos_list_cnt = 0;
@@ -133,8 +133,8 @@
 	spin_lock_irqsave(&qcb->qos_lock, flags);
 
 	for (i = 0; i < QOS_MAX; i++) {
-		qcb->csr[i].QoSBufCount = 0;
-		qcb->csr[i].Enabled = 0;
+		qcb->csr[i].qos_buf_count = 0;
+		qcb->csr[i].enabled = 0;
 	}
 
 	qcb->qos_list_cnt = 0;
@@ -153,42 +153,42 @@
 {
 	int i;
 
-	if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) {
-		if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) ||
-		((Stream[1] & csr->IPToSMask) > csr->IPToSHigh))
+	if (csr->classifier_rule_en&IPTYPEOFSERVICE) {
+		if (((Stream[1] & csr->ip2s_mask) < csr->ip2s_lo) ||
+		((Stream[1] & csr->ip2s_mask) > csr->ip2s_hi))
 			return 1;
 	}
 
-	if (csr->ClassifierRuleEnable&PROTOCOL) {
-		if (Stream[9] != csr->Protocol)
+	if (csr->classifier_rule_en&PROTOCOL) {
+		if (Stream[9] != csr->protocol)
 			return 1;
 	}
 
-	if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) {
+	if (csr->classifier_rule_en&IPMASKEDSRCADDRESS) {
 		for (i = 0; i < 4; i++) {
-			if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) !=
-			(csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i]))
+			if ((Stream[12 + i] & csr->ipsrc_addrmask[i]) !=
+			(csr->ipsrc_addr[i] & csr->ipsrc_addrmask[i]))
 				return 1;
 		}
 	}
 
-	if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) {
+	if (csr->classifier_rule_en&IPMASKEDDSTADDRESS) {
 		for (i = 0; i < 4; i++) {
-			if ((Stream[16 + i] & csr->IPDstAddrMask[i]) !=
-			(csr->IPDstAddr[i] & csr->IPDstAddrMask[i]))
+			if ((Stream[16 + i] & csr->ipdst_addrmask[i]) !=
+			(csr->ipdst_addr[i] & csr->ipdst_addrmask[i]))
 				return 1;
 		}
 	}
 
-	if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) {
+	if (csr->classifier_rule_en&PROTOCOLSRCPORTRANGE) {
 		i = ((port[0]<<8)&0xff00)+port[1];
-		if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh))
+		if ((i < csr->srcport_lo) || (i > csr->srcport_hi))
 			return 1;
 	}
 
-	if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) {
+	if (csr->classifier_rule_en&PROTOCOLDSTPORTRANGE) {
 		i = ((port[2]<<8)&0xff00)+port[3];
-		if ((i < csr->DstPortLow) || (i > csr->DstPortHigh))
+		if ((i < csr->dstport_lo) || (i > csr->dstport_hi))
 			return 1;
 	}
 
@@ -208,8 +208,8 @@
 
 	if (IP_Ver == 4) {
 		for (i = 0; i < QOS_MAX; i++) {
-			if (qcb->csr[i].Enabled) {
-				if (qcb->csr[i].ClassifierRuleEnable) {
+			if (qcb->csr[i].enabled) {
+				if (qcb->csr[i].classifier_rule_en) {
 					if (chk_ipv4_rule(&qcb->csr[i], iph,
 					tcpudph) == 0)
 						return i;
@@ -230,14 +230,14 @@
 	INIT_LIST_HEAD(head);
 
 	for (i = 0; i < QOS_MAX; i++) {
-		if (qcb->csr[i].Enabled) {
-			if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) {
+		if (qcb->csr[i].enabled) {
+			if (qcb->csr[i].qos_buf_count < qcb->qos_limit_size) {
 				if (!list_empty(&qcb->qos_list[i])) {
 					entry = list_entry(
 					qcb->qos_list[i].prev,
 					struct qos_entry_s, list);
 					list_move_tail(&entry->list, head);
-					qcb->csr[i].QoSBufCount++;
+					qcb->csr[i].qos_buf_count++;
 
 					if (!list_empty(&qcb->qos_list[i]))
 						wprintk("QoS Index(%d) is piled!!\n", i);
@@ -322,8 +322,8 @@
 
 	if (mode) {
 		for (i = 0; i < QOS_MAX; i++) {
-			if (qcb->csr[i].Enabled == 0) {
-				qcb->csr[i].Enabled = 1;
+			if (qcb->csr[i].enabled == 0) {
+				qcb->csr[i].enabled = 1;
 				qcb->qos_list_cnt++;
 				return i;
 			}
@@ -365,7 +365,7 @@
 				eprintk("QoS ERROR: No SF\n");
 				return;
 			}
-			qcb->csr[index].QoSBufCount = buf[(i*5)+10];
+			qcb->csr[index].qos_buf_count = buf[(i*5)+10];
 		}
 
 		extract_qos_list(nic, &send_list);
@@ -391,38 +391,38 @@
 
 		spin_lock_irqsave(&qcb->qos_lock, flags);
 		qcb->csr[index].SFID = SFID;
-		qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00);
-		qcb->csr[index].ClassifierRuleEnable += buf[pos++];
-		if (qcb->csr[index].ClassifierRuleEnable == 0)
+		qcb->csr[index].classifier_rule_en = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].classifier_rule_en += buf[pos++];
+		if (qcb->csr[index].classifier_rule_en == 0)
 			qcb->qos_null_idx = index;
-		qcb->csr[index].IPToSMask = buf[pos++];
-		qcb->csr[index].IPToSLow = buf[pos++];
-		qcb->csr[index].IPToSHigh = buf[pos++];
-		qcb->csr[index].Protocol = buf[pos++];
-		qcb->csr[index].IPSrcAddrMask[0] = buf[pos++];
-		qcb->csr[index].IPSrcAddrMask[1] = buf[pos++];
-		qcb->csr[index].IPSrcAddrMask[2] = buf[pos++];
-		qcb->csr[index].IPSrcAddrMask[3] = buf[pos++];
-		qcb->csr[index].IPSrcAddr[0] = buf[pos++];
-		qcb->csr[index].IPSrcAddr[1] = buf[pos++];
-		qcb->csr[index].IPSrcAddr[2] = buf[pos++];
-		qcb->csr[index].IPSrcAddr[3] = buf[pos++];
-		qcb->csr[index].IPDstAddrMask[0] = buf[pos++];
-		qcb->csr[index].IPDstAddrMask[1] = buf[pos++];
-		qcb->csr[index].IPDstAddrMask[2] = buf[pos++];
-		qcb->csr[index].IPDstAddrMask[3] = buf[pos++];
-		qcb->csr[index].IPDstAddr[0] = buf[pos++];
-		qcb->csr[index].IPDstAddr[1] = buf[pos++];
-		qcb->csr[index].IPDstAddr[2] = buf[pos++];
-		qcb->csr[index].IPDstAddr[3] = buf[pos++];
-		qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00);
-		qcb->csr[index].SrcPortLow += buf[pos++];
-		qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00);
-		qcb->csr[index].SrcPortHigh += buf[pos++];
-		qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00);
-		qcb->csr[index].DstPortLow += buf[pos++];
-		qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00);
-		qcb->csr[index].DstPortHigh += buf[pos++];
+		qcb->csr[index].ip2s_mask = buf[pos++];
+		qcb->csr[index].ip2s_lo = buf[pos++];
+		qcb->csr[index].ip2s_hi = buf[pos++];
+		qcb->csr[index].protocol = buf[pos++];
+		qcb->csr[index].ipsrc_addrmask[0] = buf[pos++];
+		qcb->csr[index].ipsrc_addrmask[1] = buf[pos++];
+		qcb->csr[index].ipsrc_addrmask[2] = buf[pos++];
+		qcb->csr[index].ipsrc_addrmask[3] = buf[pos++];
+		qcb->csr[index].ipsrc_addr[0] = buf[pos++];
+		qcb->csr[index].ipsrc_addr[1] = buf[pos++];
+		qcb->csr[index].ipsrc_addr[2] = buf[pos++];
+		qcb->csr[index].ipsrc_addr[3] = buf[pos++];
+		qcb->csr[index].ipdst_addrmask[0] = buf[pos++];
+		qcb->csr[index].ipdst_addrmask[1] = buf[pos++];
+		qcb->csr[index].ipdst_addrmask[2] = buf[pos++];
+		qcb->csr[index].ipdst_addrmask[3] = buf[pos++];
+		qcb->csr[index].ipdst_addr[0] = buf[pos++];
+		qcb->csr[index].ipdst_addr[1] = buf[pos++];
+		qcb->csr[index].ipdst_addr[2] = buf[pos++];
+		qcb->csr[index].ipdst_addr[3] = buf[pos++];
+		qcb->csr[index].srcport_lo = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].srcport_lo += buf[pos++];
+		qcb->csr[index].srcport_hi = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].srcport_hi += buf[pos++];
+		qcb->csr[index].dstport_lo = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].dstport_lo += buf[pos++];
+		qcb->csr[index].dstport_hi = ((buf[pos++]<<8)&0xff00);
+		qcb->csr[index].dstport_hi += buf[pos++];
 
 		qcb->qos_limit_size = 254/qcb->qos_list_cnt;
 		spin_unlock_irqrestore(&qcb->qos_lock, flags);
@@ -444,7 +444,7 @@
 		INIT_LIST_HEAD(&free_list);
 
 		spin_lock_irqsave(&qcb->qos_lock, flags);
-		qcb->csr[index].Enabled = 0;
+		qcb->csr[index].enabled = 0;
 		qcb->qos_list_cnt--;
 		qcb->qos_limit_size = 254/qcb->qos_list_cnt;
 
diff --git a/drivers/staging/gdm72xx/gdm_qos.h b/drivers/staging/gdm72xx/gdm_qos.h
index 33f2bd4..8f18119 100644
--- a/drivers/staging/gdm72xx/gdm_qos.h
+++ b/drivers/staging/gdm72xx/gdm_qos.h
@@ -20,18 +20,18 @@
 
 #define BOOLEAN	u8
 
-#define QOS_MAX						16
-#define IPTYPEOFSERVICE				0x8000
-#define	PROTOCOL				0x4000
-#define	IPMASKEDSRCADDRESS			0x2000
-#define	IPMASKEDDSTADDRESS			0x1000
+#define QOS_MAX				16
+#define IPTYPEOFSERVICE			0x8000
+#define	PROTOCOL			0x4000
+#define	IPMASKEDSRCADDRESS		0x2000
+#define	IPMASKEDDSTADDRESS		0x1000
 #define	PROTOCOLSRCPORTRANGE		0x800
 #define	PROTOCOLDSTPORTRANGE		0x400
-#define	DSTMACADDR					0x200
-#define	SRCMACADDR					0x100
-#define	ETHERTYPE					0x80
+#define	DSTMACADDR			0x200
+#define	SRCMACADDR			0x100
+#define	ETHERTYPE			0x80
 #define	IEEE802_1DUSERPRIORITY		0x40
-#define	IEEE802_1QVLANID			0x10
+#define	IEEE802_1QVLANID		0x10
 
 struct gdm_wimax_csr_s {
 	/*	union{
@@ -51,28 +51,28 @@
 			Reserved:5;
 		} fields;
 	} */
-	BOOLEAN		Enabled;
-	u32			SFID;
-	u8			QoSBufCount;
-	u16		ClassifierRuleEnable;
-	u8			IPToSLow;
-	u8			IPToSHigh;
-	u8			IPToSMask;
-	u8			Protocol;
-	u8			IPSrcAddr[16];
-	u8			IPSrcAddrMask[16];
-	u8			IPDstAddr[16];
-	u8			IPDstAddrMask[16];
-	u16		SrcPortLow;
-	u16		SrcPortHigh;
-	u16		DstPortLow;
-	u16		DstPortHigh;
+	BOOLEAN		enabled;
+	u32		SFID;
+	u8		qos_buf_count;
+	u16		classifier_rule_en;
+	u8		ip2s_lo;
+	u8		ip2s_hi;
+	u8		ip2s_mask;
+	u8		protocol;
+	u8		ipsrc_addr[16];
+	u8		ipsrc_addrmask[16];
+	u8		ipdst_addr[16];
+	u8		ipdst_addrmask[16];
+	u16		srcport_lo;
+	u16		srcport_hi;
+	u16		dstport_lo;
+	u16		dstport_hi;
 };
 
 struct qos_entry_s {
-	struct list_head list;
-	struct sk_buff *skb;
-	struct net_device *dev;
+	struct list_head	list;
+	struct sk_buff		*skb;
+	struct net_device	*dev;
 
 };
 
@@ -81,7 +81,7 @@
 	u32			qos_list_cnt;
 	u32			qos_null_idx;
 	struct gdm_wimax_csr_s	csr[QOS_MAX];
-	spinlock_t	qos_lock;
+	spinlock_t		qos_lock;
 	u32			qos_limit_size;
 };
 
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
index 3e43c01..ca38d71 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.c
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -60,27 +60,20 @@
 
 static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
 {
-	struct sdio_tx *t = NULL;
+	struct sdio_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC);
 
-	t = kmalloc(sizeof(*t), GFP_ATOMIC);
-	if (t == NULL)
-		goto out;
-
-	memset(t, 0, sizeof(*t));
+	if (!t)
+		return NULL;
 
 	t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
-	if (t->buf == NULL)
-		goto out;
+	if (!t->buf) {
+		kfree(t);
+		return NULL;
+	}
 
 	t->tx_cxt = tx;
 
 	return t;
-out:
-	if (t) {
-		kfree(t->buf);
-		kfree(t);
-	}
-	return NULL;
 }
 
 static void free_tx_struct(struct sdio_tx *t)
@@ -93,20 +86,12 @@
 
 static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx)
 {
-	struct sdio_rx *r = NULL;
+	struct sdio_rx *r = kzalloc(sizeof(*r), GFP_ATOMIC);
 
-	r = kmalloc(sizeof(*r), GFP_ATOMIC);
-	if (r == NULL)
-		goto out;
-
-	memset(r, 0, sizeof(*r));
-
-	r->rx_cxt = rx;
+	if (r)
+		r->rx_cxt = rx;
 
 	return r;
-out:
-	kfree(r);
-	return NULL;
 }
 
 static void free_rx_struct(struct sdio_rx *r)
@@ -680,7 +665,7 @@
 	phy_dev->rcv_func = gdm_sdio_receive;
 
 	ret = init_sdio(sdev);
-	if (sdev < 0)
+	if (ret < 0)
 		goto out;
 
 	sdev->func = func;
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
index d48d49c..0c9e895 100644
--- a/drivers/staging/gdm72xx/gdm_usb.c
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -26,11 +26,11 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-#define TX_BUF_SIZE	2048
+#define TX_BUF_SIZE		2048
 #if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
-#define RX_BUF_SIZE	(128*1024)	/* For packet aggregation */
+#define RX_BUF_SIZE		(128*1024)	/* For packet aggregation */
 #else
-#define RX_BUF_SIZE	2048
+#define RX_BUF_SIZE		2048
 #endif
 
 #define GDM7205_PADDING		256
@@ -39,7 +39,7 @@
 #define B2H(x)		__be16_to_cpu(x)
 #define DB2H(x)		__be32_to_cpu(x)
 
-#define DOWNLOAD_CONF_VALUE		0x21
+#define DOWNLOAD_CONF_VALUE	0x21
 
 #ifdef CONFIG_WIMAX_GDM72XX_K_MODE
 
@@ -48,7 +48,7 @@
 static DEFINE_SPINLOCK(k_lock);
 static int k_mode_stop;
 
-#define K_WAIT_TIME	(2 * HZ / 100)
+#define K_WAIT_TIME		(2 * HZ / 100)
 
 #endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
 
@@ -73,29 +73,23 @@
 
 static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
 {
-	struct usb_tx *t = NULL;
+	struct usb_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC);
 
-	t = kmalloc(sizeof(*t), GFP_ATOMIC);
-	if (t == NULL)
-		goto out;
-
-	memset(t, 0, sizeof(*t));
+	if (!t)
+		return NULL;
 
 	t->urb = usb_alloc_urb(0, GFP_ATOMIC);
 	t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
-	if (t->urb == NULL || t->buf == NULL)
-		goto out;
+	if (!t->urb || !t->buf) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+		return NULL;
+	}
 
 	t->tx_cxt = tx;
 
 	return t;
-out:
-	if (t) {
-		usb_free_urb(t->urb);
-		kfree(t->buf);
-		kfree(t);
-	}
-	return NULL;
 }
 
 static void free_tx_struct(struct usb_tx *t)
@@ -109,28 +103,22 @@
 
 static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx)
 {
-	struct usb_rx *r = NULL;
+	struct usb_rx *r = kzalloc(sizeof(*r), GFP_ATOMIC);
 
-	r = kmalloc(sizeof(*r), GFP_ATOMIC);
-	if (r == NULL)
-		goto out;
-
-	memset(r, 0, sizeof(*r));
+	if (!r)
+		return NULL;
 
 	r->urb = usb_alloc_urb(0, GFP_ATOMIC);
 	r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
-	if (r->urb == NULL || r->buf == NULL)
-		goto out;
-
-	r->rx_cxt = rx;
-	return r;
-out:
-	if (r) {
+	if (!r->urb || !r->buf) {
 		usb_free_urb(r->urb);
 		kfree(r->buf);
 		kfree(r);
+		return NULL;
 	}
-	return NULL;
+
+	r->rx_cxt = rx;
+	return r;
 }
 
 static void free_rx_struct(struct usb_rx *r)
@@ -180,8 +168,7 @@
 	}
 
 	r = list_entry(rx->free_list.next, struct usb_rx, list);
-	list_del(&r->list);
-	list_add_tail(&r->list, &rx->used_list);
+	list_move_tail(&r->list, &rx->used_list);
 
 	return r;
 }
@@ -189,8 +176,7 @@
 /* Before this function is called, spin lock should be locked. */
 static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
 {
-	list_del(&r->list);
-	list_add(&r->list, &rx->free_list);
+	list_move(&r->list, &rx->free_list);
 }
 
 static int init_usb(struct usbwm_dev *udev)
diff --git a/drivers/staging/gdm72xx/gdm_usb.h b/drivers/staging/gdm72xx/gdm_usb.h
index ecb891f..f2c5451 100644
--- a/drivers/staging/gdm72xx/gdm_usb.h
+++ b/drivers/staging/gdm72xx/gdm_usb.h
@@ -18,8 +18,8 @@
 #include <linux/usb.h>
 #include <linux/list.h>
 
-#define B_DIFF_DL_DRV		(1<<4)
-#define B_DOWNLOAD			(1 << 5)
+#define B_DIFF_DL_DRV		(1 << 4)
+#define B_DOWNLOAD		(1 << 5)
 #define MAX_NR_SDU_BUF		64
 
 struct usb_tx {
@@ -29,7 +29,7 @@
 #endif
 	struct tx_cxt		*tx_cxt;
 
-	struct urb	*urb;
+	struct urb		*urb;
 	u8			*buf;
 
 	void (*callback)(void *cb_data);
@@ -44,14 +44,14 @@
 	struct list_head	pending_list;
 #endif
 
-	spinlock_t			lock;
+	spinlock_t		lock;
 };
 
 struct usb_rx {
 	struct list_head	list;
 	struct rx_cxt		*rx_cxt;
 
-	struct urb	*urb;
+	struct urb		*urb;
 	u8			*buf;
 
 	void (*callback)(void *cb_data, void *data, int len);
@@ -61,7 +61,7 @@
 struct rx_cxt {
 	struct list_head	free_list;
 	struct list_head	used_list;
-	spinlock_t			lock;
+	spinlock_t		lock;
 };
 
 struct usbwm_dev {
@@ -76,8 +76,8 @@
 	struct list_head	list;
 #endif
 
-	struct tx_cxt	tx;
-	struct rx_cxt	rx;
+	struct tx_cxt		tx;
+	struct rx_cxt		rx;
 
 	int padding;
 };
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
index 0716efc..6cb8107 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.c
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -258,12 +258,16 @@
 	if (!wm_event.ref_cnt) {
 		wm_event.sock = netlink_init(NETLINK_WIMAX,
 						gdm_wimax_event_rcv);
-		if (wm_event.sock)
-			wm_event.ref_cnt++;
-		INIT_LIST_HEAD(&wm_event.evtq);
-		INIT_LIST_HEAD(&wm_event.freeq);
-		INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
-		spin_lock_init(&wm_event.evt_lock);
+		if (wm_event.sock) {
+			INIT_LIST_HEAD(&wm_event.evtq);
+			INIT_LIST_HEAD(&wm_event.freeq);
+			INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
+			spin_lock_init(&wm_event.evt_lock);
+		}
+	}
+
+	if (wm_event.sock) {
+		wm_event.ref_cnt++;
 		return 0;
 	}
 
diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c
index e3dbd5a..0787188 100644
--- a/drivers/staging/gdm72xx/usb_boot.c
+++ b/drivers/staging/gdm72xx/usb_boot.c
@@ -18,25 +18,22 @@
 #include <linux/usb.h>
 #include <linux/unistd.h>
 #include <linux/slab.h>
+#include <linux/firmware.h>
 
 #include <asm/byteorder.h>
 #include "gdm_usb.h"
 #include "usb_boot.h"
 
-#define DN_KERNEL_MAGIC_NUMBER		0x10760001
-#define DN_ROOTFS_MAGIC_NUMBER		0x10760002
+#define DN_KERNEL_MAGIC_NUMBER	0x10760001
+#define DN_ROOTFS_MAGIC_NUMBER	0x10760002
 
-#define DOWNLOAD_SIZE	1024
-
-#define DH2B(x)		__cpu_to_be32(x)
-#define DL2H(x)		__le32_to_cpu(x)
-
-#define MIN(a, b)	((a) > (b) ? (b) : (a))
+#define DOWNLOAD_SIZE		1024
 
 #define MAX_IMG_CNT		16
-#define UIMG_PATH		"/lib/firmware/gdm72xx/gdmuimg.bin"
-#define KERN_PATH		"/lib/firmware/gdm72xx/zImage"
-#define FS_PATH			"/lib/firmware/gdm72xx/ramdisk.jffs2"
+#define FW_DIR			"gdm72xx/"
+#define FW_UIMG			"gdmuimg.bin"
+#define FW_KERN			"zImage"
+#define FW_FS			"ramdisk.jffs2"
 
 struct dn_header {
 	u32	magic_num;
@@ -44,23 +41,23 @@
 };
 
 struct img_header {
-	u32		magic_code;
-	u32		count;
-	u32		len;
-	u32		offset[MAX_IMG_CNT];
+	u32	magic_code;
+	u32	count;
+	u32	len;
+	u32	offset[MAX_IMG_CNT];
 	char	hostname[32];
 	char	date[32];
 };
 
 struct fw_info {
-	u32		id;
-	u32		len;
-	u32		kernel_len;
-	u32		rootfs_len;
-	u32		kernel_offset;
-	u32		rootfs_offset;
-	u32		fw_ver;
-	u32		mac_ver;
+	u32	id;
+	u32	len;
+	u32	kernel_len;
+	u32	rootfs_len;
+	u32	kernel_offset;
+	u32	rootfs_offset;
+	u32	fw_ver;
+	u32	mac_ver;
 	char	hostname[32];
 	char	userid[16];
 	char	date[32];
@@ -71,7 +68,7 @@
 {
 	int i;
 	for (i = 0; i < num; i++, arr++)
-		*arr = DL2H(*arr);
+		*arr = __le32_to_cpu(*arr);
 }
 
 static u8 *tx_buf;
@@ -107,44 +104,37 @@
 	return 0;
 }
 
-static int download_image(struct usb_device *usbdev, struct file *filp,
-				loff_t *pos, u32 img_len, u32 magic_num)
+static int download_image(struct usb_device *usbdev,
+				const struct firmware *firm,
+				loff_t pos, u32 img_len, u32 magic_num)
 {
 	struct dn_header h;
 	int ret = 0;
 	u32 size;
-	int len, readn;
 
-	size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
-	h.magic_num = DH2B(magic_num);
-	h.file_size = DH2B(size);
+	size = ALIGN(img_len, DOWNLOAD_SIZE);
+	h.magic_num = __cpu_to_be32(magic_num);
+	h.file_size = __cpu_to_be32(size);
 
 	ret = gdm_wibro_send(usbdev, &h, sizeof(h));
 	if (ret < 0)
-		goto out;
+		return ret;
 
-	readn = 0;
-	while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
+	while (img_len > 0) {
+		if (img_len > DOWNLOAD_SIZE)
+			size = DOWNLOAD_SIZE;
+		else
+			size = img_len;	/* the last chunk of data */
 
-		if (len < 0) {
-			ret = -1;
-			goto out;
-		}
-		readn += len;
+		memcpy(tx_buf, firm->data + pos, size);
+		ret = gdm_wibro_send(usbdev, tx_buf, size);
 
-		ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
 		if (ret < 0)
-			goto out;
-		if (readn >= img_len)
-			break;
-	}
+			return ret;
 
-	if (readn < img_len) {
-		printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
-			"Read = %d Requested = %d\n", readn, img_len);
-		ret = -EIO;
+		img_len -= size;
+		pos += size;
 	}
-out:
 
 	return ret;
 }
@@ -152,14 +142,19 @@
 int usb_boot(struct usb_device *usbdev, u16 pid)
 {
 	int i, ret = 0;
-	struct file *filp = NULL;
-	struct inode *inode = NULL;
-	static mm_segment_t fs;
 	struct img_header hdr;
 	struct fw_info fw_info;
 	loff_t pos = 0;
-	char *img_name = UIMG_PATH;
-	int len;
+	char *img_name = FW_DIR FW_UIMG;
+	const struct firmware *firm;
+
+	ret = request_firmware(&firm, img_name, &usbdev->dev);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "requesting firmware %s failed with error %d\n",
+			img_name, ret);
+		return ret;
+	}
 
 	tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
 	if (tx_buf == NULL) {
@@ -167,29 +162,12 @@
 		return -ENOMEM;
 	}
 
-	fs = get_fs();
-	set_fs(get_ds());
-
-	filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
-	if (IS_ERR(filp)) {
-		printk(KERN_ERR "Can't find %s.\n", img_name);
-		ret = PTR_ERR(filp);
-		goto restore_fs;
-	}
-
-	inode = filp->f_dentry->d_inode;
-	if (!S_ISREG(inode->i_mode)) {
-		printk(KERN_ERR "Invalid file type: %s\n", img_name);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
-	if (len != sizeof(hdr)) {
+	if (firm->size < sizeof(hdr)) {
 		printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
 		ret = -EIO;
 		goto out;
 	}
+	memcpy(&hdr, firm->data, sizeof(hdr));
 
 	array_le32_to_cpu((u32 *)&hdr, 19);
 #if 0
@@ -217,13 +195,12 @@
 		}
 
 		pos = hdr.offset[i];
-		len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
-					&pos);
-		if (len != sizeof(fw_info)) {
+		if (firm->size < sizeof(fw_info) + pos) {
 			printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
 			ret = -EIO;
 			goto out;
 		}
+		memcpy(&fw_info, firm->data + pos, sizeof(fw_info));
 
 		array_le32_to_cpu((u32 *)&fw_info, 8);
 #if 0
@@ -239,14 +216,23 @@
 			continue;
 
 		pos = hdr.offset[i] + fw_info.kernel_offset;
-		ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
-				DN_KERNEL_MAGIC_NUMBER);
+		if (firm->size < fw_info.kernel_len + pos) {
+			printk(KERN_ERR "gdmwm: Kernel FW is too small.\n");
+			goto out;
+		}
+
+		ret = download_image(usbdev, firm, pos,
+				fw_info.kernel_len, DN_KERNEL_MAGIC_NUMBER);
 		if (ret < 0)
 			goto out;
 		printk(KERN_INFO "GCT: Kernel download success.\n");
 
 		pos = hdr.offset[i] + fw_info.rootfs_offset;
-		ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
+		if (firm->size < fw_info.rootfs_len + pos) {
+			printk(KERN_ERR "gdmwm: Filesystem FW is too small.\n");
+			goto out;
+		}
+		ret = download_image(usbdev, firm, pos, fw_info.rootfs_len,
 				DN_ROOTFS_MAGIC_NUMBER);
 		if (ret < 0)
 			goto out;
@@ -260,10 +246,7 @@
 		ret = -EINVAL;
 	}
 out:
-	filp_close(filp, NULL);
-
-restore_fs:
-	set_fs(fs);
+	release_firmware(firm);
 	kfree(tx_buf);
 	return ret;
 }
@@ -293,38 +276,27 @@
 	return ret;
 }
 
-static int em_download_image(struct usb_device *usbdev, char *path,
+static int em_download_image(struct usb_device *usbdev, const char *img_name,
 				char *type_string)
 {
-	struct file *filp;
-	struct inode *inode;
-	static mm_segment_t fs;
 	char *buf = NULL;
 	loff_t pos = 0;
 	int ret = 0;
-	int len, readn = 0;
+	int len;
+	int img_len;
+	const struct firmware *firm;
 	#if defined(GDM7205_PADDING)
 	const int pad_size = GDM7205_PADDING;
 	#else
 	const int pad_size = 0;
 	#endif
 
-	fs = get_fs();
-	set_fs(get_ds());
-
-	filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
-	if (IS_ERR(filp)) {
-		printk(KERN_ERR "Can't find %s.\n", path);
-		set_fs(fs);
-		ret = -ENOENT;
-		goto restore_fs;
-	}
-
-	inode = filp->f_dentry->d_inode;
-	if (!S_ISREG(inode->i_mode)) {
-		printk(KERN_ERR "Invalid file type: %s\n", path);
-		ret = -EINVAL;
-		goto out;
+	ret = request_firmware(&firm, img_name, &usbdev->dev);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "requesting firmware %s failed with error %d\n",
+			img_name, ret);
+		return ret;
 	}
 
 	buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
@@ -338,18 +310,28 @@
 	if (ret < 0)
 		goto out;
 
-	while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
-					&pos))) {
-		if (len < 0) {
-			ret = -1;
-			goto out;
-		}
-		readn += len;
+	img_len = firm->size;
 
+	if (img_len <= 0) {
+		ret = -1;
+		goto out;
+	}
+
+	while (img_len > 0) {
+		if (img_len > DOWNLOAD_CHUCK)
+			len = DOWNLOAD_CHUCK;
+		else
+			len = img_len; /* the last chunk of data */
+
+		memcpy(buf+pad_size, firm->data + pos, len);
 		ret = gdm_wibro_send(usbdev, buf, len+pad_size);
+
 		if (ret < 0)
 			goto out;
 
+		img_len -= DOWNLOAD_CHUCK;
+		pos += DOWNLOAD_CHUCK;
+
 		ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
 		if (ret < 0)
 			goto out;
@@ -360,11 +342,7 @@
 		goto out;
 
 out:
-	filp_close(filp, NULL);
-
-restore_fs:
-	set_fs(fs);
-
+	release_firmware(firm);
 	kfree(buf);
 
 	return ret;
@@ -382,18 +360,20 @@
 int usb_emergency(struct usb_device *usbdev)
 {
 	int ret;
+	const char *kern_name = FW_DIR FW_KERN;
+	const char *fs_name = FW_DIR FW_FS;
 
-	ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
+	ret = em_download_image(usbdev, kern_name, KERNEL_TYPE_STRING);
 	if (ret < 0)
-		goto out;
+		return ret;
 	printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
 
-	ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
+	ret = em_download_image(usbdev, fs_name, FS_TYPE_STRING);
 	if (ret < 0)
-		goto out;
+		return ret;
 	printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
 
 	ret = em_fw_reset(usbdev);
-out:
+
 	return ret;
 }
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index 827e92de..40d0eca 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -104,6 +104,16 @@
 			print2byte(*(uint16_t *)(data + channels[k].location),
 				   &channels[k]);
 			break;
+		case 4:
+			if (!channels[k].is_signed) {
+				uint32_t val = *(uint32_t *)
+					(data + channels[k].location);
+				printf("%05f ", ((float)val +
+						 channels[k].offset)*
+				       channels[k].scale);
+
+			}
+			break;
 		case 8:
 			if (channels[k].is_signed) {
 				int64_t val = *(int64_t *)
diff --git a/drivers/staging/iio/Documentation/inkernel.txt b/drivers/staging/iio/Documentation/inkernel.txt
index a05823e..ab528409 100644
--- a/drivers/staging/iio/Documentation/inkernel.txt
+++ b/drivers/staging/iio/Documentation/inkernel.txt
@@ -48,11 +48,11 @@
 about this channel such as it's current reading.
 
 e.g.
-iio_st_read_channel_raw() - get a reading
-iio_st_read_channel_type() - get the type of channel
+iio_read_channel_raw() - get a reading
+iio_get_channel_type() - get the type of channel
 
 There is also provision for retrieving all of the channels associated
 with a given consumer.  This is useful for generic drivers such as
 iio_hwmon where the number and naming of channels is not known by the
-consumer driver.  To do this, use iio_st_channel_get_all.
+consumer driver.  To do this, use iio_channel_get_all.
 
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 04cd6ec..ca56c75 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -1,5 +1,5 @@
 #
-# Industrial I/O subsytem configuration
+# Industrial I/O subsystem configuration
 #
 menu "IIO staging drivers"
 	depends on IIO
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index cf3f948..04c2326 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -69,5 +69,5 @@
 1) Lots of cleanup and expansion.
 2) Some device require individual docs.
 
-Contact: Jonathan Cameron <jic23@cam.ac.uk>.
+Contact: Jonathan Cameron <jic23@kernel.org>.
 Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index 204106b..8e37d6e 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -390,7 +390,7 @@
 	return -EINVAL;
 }
 
-static struct iio_chan_spec adis16201_channels[] = {
+static const struct iio_chan_spec adis16201_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -565,7 +565,7 @@
 	return ret;
 }
 
-static int adis16201_remove(struct spi_device *spi)
+static int __devexit adis16201_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 03fcf6e..97c09f0 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -62,7 +62,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16201_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 
 	int i = 0;
 	s16 *data;
@@ -83,7 +82,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 22085e9..002fa9d 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -355,7 +355,7 @@
 	}
 }
 
-static struct iio_chan_spec adis16203_channels[] = {
+static const struct iio_chan_spec adis16203_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -500,7 +500,7 @@
 	return ret;
 }
 
-static int adis16203_remove(struct spi_device *spi)
+static int __devexit adis16203_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index c16b2b7..7507e1a 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -61,7 +61,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16203_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 
 	int i = 0;
 	s16 *data;
@@ -82,9 +81,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring,
-			      (u8 *)data,
-			      pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index 5f2e5f1..05bdb7c 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -397,7 +397,7 @@
 	return -EINVAL;
 }
 
-static struct iio_chan_spec adis16204_channels[] = {
+static const struct iio_chan_spec adis16204_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1, /* Note was not previously indexed */
@@ -558,7 +558,7 @@
 	return ret;
 }
 
-static int adis16204_remove(struct spi_device *spi)
+static int __devexit adis16204_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 1d2b31c..4c976be 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -59,7 +59,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16204_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0;
 	s16 *data;
 
@@ -79,7 +78,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index 4945705..b7333bf 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -390,7 +390,7 @@
 	return -EINVAL;
 }
 
-static struct iio_chan_spec adis16209_channels[] = {
+static const struct iio_chan_spec adis16209_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -573,7 +573,7 @@
 	return ret;
 }
 
-static int adis16209_remove(struct spi_device *spi)
+static int __devexit adis16209_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 1a4a55c..f939e29 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -59,7 +59,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16209_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0;
 	s16 *data;
 
@@ -79,7 +78,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 575f1af..c755089 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -372,8 +372,7 @@
 					loff_t off,
 					size_t count)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -394,8 +393,7 @@
 				char *buf, loff_t off,
 				size_t count)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -416,8 +414,7 @@
 				char *buf, loff_t off,
 				size_t count)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
 	return adis16220_capture_buffer_read(indio_dev, buf,
 					off, count,
@@ -666,7 +663,7 @@
 	return ret;
 }
 
-static int adis16220_remove(struct spi_device *spi)
+static int __devexit adis16220_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index b30b787..0fc26a49 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -448,7 +448,7 @@
 	return -EINVAL;
 }
 
-static struct iio_chan_spec adis16240_channels[] = {
+static const struct iio_chan_spec adis16240_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -619,7 +619,7 @@
 	return ret;
 }
 
-static int adis16240_remove(struct spi_device *spi)
+static int __devexit adis16240_remove(struct spi_device *spi)
 {
 
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 360dfed..caff8e2 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -56,7 +56,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16240_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 
 	int i = 0;
 	s16 *data;
@@ -77,7 +76,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c
index 8cf7cd9..fdd5fbd 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/staging/iio/accel/kxsd9.c
@@ -2,7 +2,7 @@
  * kxsd9.c	simple support for the Kionix KXSD9 3D
  *		accelerometer.
  *
- * Copyright (c) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -186,7 +186,7 @@
 		.address = KXSD9_REG_##axis,				\
 	}
 
-static struct iio_chan_spec kxsd9_channels[] = {
+static const struct iio_chan_spec kxsd9_channels[] = {
 	KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
 	{
 		.type = IIO_VOLTAGE,
@@ -286,6 +286,6 @@
 };
 module_spi_driver(kxsd9_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index ae5f225..f9bcd41 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -2,7 +2,7 @@
  * LISL02DQ.h -- support STMicroelectronics LISD02DQ
  *               3d 2g Linear Accelerometers via SPI
  *
- * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
  *
  * Loosely based upon tle62x0.c
  *
@@ -28,7 +28,7 @@
 /* Control Register (1 of 2) */
 #define LIS3L02DQ_REG_CTRL_1_ADDR		0x20
 /* Power ctrl - either bit set corresponds to on*/
-#define LIS3L02DQ_REG_CTRL_1_PD_ON	0xC0
+#define LIS3L02DQ_REG_CTRL_1_PD_ON		0xC0
 
 /* Decimation Factor  */
 #define LIS3L02DQ_DEC_MASK			0x30
@@ -73,14 +73,14 @@
 /* Interrupt related stuff */
 #define LIS3L02DQ_REG_WAKE_UP_CFG_ADDR			0x23
 
-/* Switch from or combination fo conditions to and */
+/* Switch from or combination of conditions to and */
 #define LIS3L02DQ_REG_WAKE_UP_CFG_BOOLEAN_AND		0x80
 
 /* Latch interrupt request,
  * if on ack must be given by reading the ack register */
 #define LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC		0x40
 
-/* Z Interrupt on High (above threshold)*/
+/* Z Interrupt on High (above threshold) */
 #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH	0x20
 /* Z Interrupt on Low */
 #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW	0x10
@@ -117,13 +117,13 @@
 #define LIS3L02DQ_REG_STATUS_Y_OVERRUN			0x20
 #define LIS3L02DQ_REG_STATUS_X_OVERRUN			0x10
 /* XYZ new data available - first is all 3 available? */
-#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA 0x08
+#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA		0x08
 #define LIS3L02DQ_REG_STATUS_Z_NEW_DATA			0x04
 #define LIS3L02DQ_REG_STATUS_Y_NEW_DATA			0x02
 #define LIS3L02DQ_REG_STATUS_X_NEW_DATA			0x01
 
 /* The accelerometer readings - low and high bytes.
-Form of high byte dependent on justification set in ctrl reg */
+ * Form of high byte dependent on justification set in ctrl reg */
 #define LIS3L02DQ_REG_OUT_X_L_ADDR			0x28
 #define LIS3L02DQ_REG_OUT_X_H_ADDR			0x29
 #define LIS3L02DQ_REG_OUT_Y_L_ADDR			0x2A
@@ -150,9 +150,9 @@
  * struct lis3l02dq_state - device instance specific data
  * @us:			actual spi_device
  * @trig:		data ready trigger registered with iio
+ * @buf_lock:		mutex to protect tx and rx
  * @tx:			transmit buffer
  * @rx:			receive buffer
- * @buf_lock:		mutex to protect tx and rx
  **/
 struct lis3l02dq_state {
 	struct spi_device		*us;
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 9d26348..21b0469 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -2,7 +2,7 @@
  * lis3l02dq.c	support STMicroelectronics LISD02DQ
  *		3d 2g Linear Accelerometers via SPI
  *
- * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -392,7 +392,7 @@
 		dev_err(&st->us->dev, "problem with setup control register 1");
 		goto err_ret;
 	}
-	/* Repeat as sometimes doesn't work first time?*/
+	/* Repeat as sometimes doesn't work first time? */
 	ret = lis3l02dq_spi_write_reg_8(indio_dev,
 					LIS3L02DQ_REG_CTRL_1_ADDR,
 					val);
@@ -538,7 +538,7 @@
 		.event_mask = LIS3L02DQ_EVENT_MASK,		\
 	 }
 
-static struct iio_chan_spec lis3l02dq_channels[] = {
+static const struct iio_chan_spec lis3l02dq_channels[] = {
 	LIS3L02DQ_CHAN(0, IIO_MOD_X),
 	LIS3L02DQ_CHAN(1, IIO_MOD_Y),
 	LIS3L02DQ_CHAN(2, IIO_MOD_Z),
@@ -686,7 +686,7 @@
 		goto error_ret;
 	}
 	st = iio_priv(indio_dev);
-	/* this is only used tor removal purposes */
+	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
 
 	st->us = spi;
@@ -780,21 +780,15 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int lis3l02dq_remove(struct spi_device *spi)
+static int __devexit lis3l02dq_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
 
-	ret = lis3l02dq_disable_all_events(indio_dev);
-	if (ret)
-		goto err_ret;
-
-	ret = lis3l02dq_stop_device(indio_dev);
-	if (ret)
-		goto err_ret;
+	lis3l02dq_disable_all_events(indio_dev);
+	lis3l02dq_stop_device(indio_dev);
 
 	if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
 		free_irq(st->us->irq, indio_dev);
@@ -804,8 +798,8 @@
 	lis3l02dq_unconfigure_buffer(indio_dev);
 
 	iio_device_free(indio_dev);
-err_ret:
-	return ret;
+
+	return 0;
 }
 
 static struct spi_driver lis3l02dq_driver = {
@@ -818,7 +812,7 @@
 };
 module_spi_driver(lis3l02dq_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("ST LIS3L02DQ Accelerometer SPI driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("spi:lis3l02dq");
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index f3da590..fa4190d 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -14,7 +14,7 @@
 #include "lis3l02dq.h"
 
 /**
- * combine_8_to_16() utility function to munge to u8s into u16
+ * combine_8_to_16() utility function to munge two u8s into u16
  **/
 static inline u16 combine_8_to_16(u8 lower, u8 upper)
 {
@@ -49,7 +49,7 @@
 
 /**
  * lis3l02dq_read_all() Reads all channels currently selected
- * @st:		device specific state
+ * @indio_dev:	IIO device state
  * @rx_array:	(dma capable) receive array, must be at least
  *		4*number of channels
  **/
@@ -137,7 +137,6 @@
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
-	struct iio_buffer *buffer = indio_dev->buffer;
 	int len = 0;
 	char *data;
 
@@ -155,7 +154,7 @@
 	if (indio_dev->scan_timestamp)
 		*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
 			= pf->timestamp;
-	buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
@@ -172,22 +171,22 @@
 	bool currentlyset;
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 
-/* Get the current event mask register */
+	/* Get the current event mask register */
 	ret = lis3l02dq_spi_read_reg_8(indio_dev,
 				       LIS3L02DQ_REG_CTRL_2_ADDR,
 				       &valold);
 	if (ret)
 		goto error_ret;
-/* Find out if data ready is already on */
+	/* Find out if data ready is already on */
 	currentlyset
 		= valold & LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
 
-/* Disable requested */
+	/* Disable requested */
 	if (!state && currentlyset) {
-		/* disable the data ready signal */
+		/* Disable the data ready signal */
 		valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
 
-		/* The double write is to overcome a hardware bug?*/
+		/* The double write is to overcome a hardware bug? */
 		ret = lis3l02dq_spi_write_reg_8(indio_dev,
 						LIS3L02DQ_REG_CTRL_2_ADDR,
 						valold);
@@ -199,10 +198,10 @@
 		if (ret)
 			goto error_ret;
 		st->trigger_on = false;
-/* Enable requested */
+	/* Enable requested */
 	} else if (state && !currentlyset) {
-		/* if not set, enable requested */
-		/* first disable all events */
+		/* If not set, enable requested
+		 * first disable all events */
 		ret = lis3l02dq_disable_all_events(indio_dev);
 		if (ret < 0)
 			goto error_ret;
@@ -241,7 +240,7 @@
 	if (state == false) {
 		/*
 		 * A possible quirk with the handler is currently worked around
-		 *  by ensuring outstanding read events are cleared.
+		 * by ensuring outstanding read events are cleared.
 		 */
 		ret = lis3l02dq_read_all(indio_dev, NULL);
 	}
@@ -252,7 +251,7 @@
 }
 
 /**
- * lis3l02dq_trig_try_reen() try renabling irq for data rdy trigger
+ * lis3l02dq_trig_try_reen() try reenabling irq for data rdy trigger
  * @trig:	the datardy trigger
  */
 static int lis3l02dq_trig_try_reen(struct iio_trigger *trig)
@@ -261,8 +260,8 @@
 	struct lis3l02dq_state *st = iio_priv(indio_dev);
 	int i;
 
-	/* If gpio still high (or high again) */
-	/* In theory possible we will need to do this several times */
+	/* If gpio still high (or high again)
+	 * In theory possible we will need to do this several times */
 	for (i = 0; i < 5; i++)
 		if (gpio_get_value(irq_to_gpio(st->us->irq)))
 			lis3l02dq_read_all(indio_dev, NULL);
diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h
index 131daac..c1016c5 100644
--- a/drivers/staging/iio/accel/sca3000.h
+++ b/drivers/staging/iio/accel/sca3000.h
@@ -2,7 +2,7 @@
  * sca3000.c -- support VTI sca3000 series accelerometers
  *              via SPI
  *
- * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
  *
  * Partly based upon tle62x0.c
  *
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index c218d71..ffd1697 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -5,7 +5,7 @@
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  *
- * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org>
  *
  * See industrialio/accels/sca3000.h for comments.
  */
@@ -450,7 +450,7 @@
 		.event_mask = SCA3000_EVENT_MASK,		\
 	 }
 
-static struct iio_chan_spec sca3000_channels[] = {
+static const struct iio_chan_spec sca3000_channels[] = {
 	SCA3000_CHAN(0, IIO_MOD_X),
 	SCA3000_CHAN(1, IIO_MOD_Y),
 	SCA3000_CHAN(2, IIO_MOD_Z),
@@ -1233,15 +1233,13 @@
 	return ret;
 }
 
-static int sca3000_remove(struct spi_device *spi)
+static int __devexit sca3000_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct sca3000_state *st = iio_priv(indio_dev);
-	int ret;
+
 	/* Must ensure no interrupts can be generated after this!*/
-	ret = sca3000_stop_all_interrupts(st);
-	if (ret)
-		return ret;
+	sca3000_stop_all_interrupts(st);
 	if (spi->irq)
 		free_irq(spi->irq, indio_dev);
 	iio_device_unregister(indio_dev);
@@ -1272,6 +1270,6 @@
 };
 module_spi_driver(sca3000_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index b7e1a002..cbec2f1 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -5,7 +5,7 @@
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  *
- * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org>
  *
  */
 
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 67711b7..a525143 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -68,20 +68,6 @@
 	  Say yes here to include ring buffer support in the AD799X
 	  ADC driver.
 
-config AD7476
-	tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
-	depends on SPI
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
-	help
-	  Say yes here to build support for Analog Devices
-	  AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495
-	  SPI analog to digital converters (ADC).
-	  If unsure, say N (but it's safe to say "Y").
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad7476.
-
 config AD7887
 	tristate "Analog Devices AD7887 ADC driver"
 	depends on SPI
@@ -96,11 +82,12 @@
 	  module will be called ad7887.
 
 config AD7780
-	tristate "Analog Devices AD7780 AD7781 ADC driver"
+	tristate "Analog Devices AD7780 and similar ADCs driver"
 	depends on SPI
 	depends on GPIOLIB
+	select AD_SIGMA_DELTA
 	help
-	  Say yes here to build support for Analog Devices
+	  Say yes here to build support for Analog Devices AD7170, AD7171,
 	  AD7780 and AD7781 SPI analog to digital converters (ADC).
 	  If unsure, say N (but it's safe to say "Y").
 
@@ -108,13 +95,12 @@
 	  module will be called ad7780.
 
 config AD7793
-	tristate "Analog Devices AD7792 AD7793 ADC driver"
+	tristate "Analog Devices AD7793 and similar ADCs driver"
 	depends on SPI
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
+	select AD_SIGMA_DELTA
 	help
-	  Say yes here to build support for Analog Devices
-	  AD7792 and AD7793 SPI analog to digital converters (ADC).
+	  Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
+	  AD7794 and AD7795 SPI analog to digital converters (ADC).
 	  If unsure, say N (but it's safe to say "Y").
 
 	  To compile this driver as a module, choose M here: the
@@ -131,8 +117,7 @@
 config AD7192
 	tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver"
 	depends on SPI
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
+	select AD_SIGMA_DELTA
 	help
 	  Say yes here to build support for Analog Devices AD7190,
 	  AD7192 or AD7195 SPI analog to digital converters (ADC).
@@ -200,6 +185,18 @@
 	  activate only one via device tree selection.  Provides direct access
 	  via sysfs.
 
+config MXS_LRADC
+	tristate "Freescale i.MX28 LRADC"
+	depends on ARCH_MXS
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for i.MX28 LRADC convertor
+	  built into these chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mxs-lradc.
+
 config SPEAR_ADC
 	tristate "ST SPEAr ADC"
 	depends on PLAT_SPEAR
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index 14e98b6..62ee02e 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -17,10 +17,6 @@
 ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
 obj-$(CONFIG_AD799X) += ad799x.o
 
-ad7476-y := ad7476_core.o
-ad7476-$(CONFIG_IIO_BUFFER) += ad7476_ring.o
-obj-$(CONFIG_AD7476) += ad7476.o
-
 ad7887-y := ad7887_core.o
 ad7887-$(CONFIG_IIO_BUFFER) += ad7887_ring.o
 obj-$(CONFIG_AD7887) += ad7887.o
@@ -38,4 +34,5 @@
 obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 19a064d..aeaa61d 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -23,6 +23,7 @@
 #include <linux/iio/trigger.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
 
 #include "ad7192.h"
 
@@ -57,6 +58,7 @@
 
 /* Mode Register Bit Designations (AD7192_REG_MODE) */
 #define AD7192_MODE_SEL(x)	(((x) & 0x7) << 21) /* Operation Mode Select */
+#define AD7192_MODE_SEL_MASK	(0x7 << 21) /* Operation Mode Select Mask */
 #define AD7192_MODE_DAT_STA	(1 << 20) /* Status Register transmission */
 #define AD7192_MODE_CLKSRC(x)	(((x) & 0x3) << 18) /* Clock Source Select */
 #define AD7192_MODE_SINC3	(1 << 15) /* SINC3 Filter Select */
@@ -91,7 +93,8 @@
 
 #define AD7192_CONF_CHOP	(1 << 23) /* CHOP enable */
 #define AD7192_CONF_REFSEL	(1 << 20) /* REFIN1/REFIN2 Reference Select */
-#define AD7192_CONF_CHAN(x)	(((x) & 0xFF) << 8) /* Channel select */
+#define AD7192_CONF_CHAN(x)	(((1 << (x)) & 0xFF) << 8) /* Channel select */
+#define AD7192_CONF_CHAN_MASK	(0xFF << 8) /* Channel select mask */
 #define AD7192_CONF_BURN	(1 << 7) /* Burnout current enable */
 #define AD7192_CONF_REFDET	(1 << 6) /* Reference detect enable */
 #define AD7192_CONF_BUF		(1 << 4) /* Buffered Mode Enable */
@@ -133,13 +136,7 @@
  */
 
 struct ad7192_state {
-	struct spi_device		*spi;
-	struct iio_trigger		*trig;
 	struct regulator		*reg;
-	struct ad7192_platform_data	*pdata;
-	wait_queue_head_t		wq_data_avail;
-	bool				done;
-	bool				irq_dis;
 	u16				int_vref_mv;
 	u32				mclk;
 	u32				f_order;
@@ -148,178 +145,45 @@
 	u32				scale_avail[8][2];
 	u8				gpocon;
 	u8				devid;
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	u8				data[4] ____cacheline_aligned;
+
+	struct ad_sigma_delta		sd;
 };
 
-static int __ad7192_write_reg(struct ad7192_state *st, bool locked,
-			      bool cs_change, unsigned char reg,
-			      unsigned size, unsigned val)
+static struct ad7192_state *ad_sigma_delta_to_ad7192(struct ad_sigma_delta *sd)
 {
-	u8 *data = st->data;
-	struct spi_transfer t = {
-		.tx_buf		= data,
-		.len		= size + 1,
-		.cs_change	= cs_change,
-	};
-	struct spi_message m;
-
-	data[0] = AD7192_COMM_WRITE | AD7192_COMM_ADDR(reg);
-
-	switch (size) {
-	case 3:
-		data[1] = val >> 16;
-		data[2] = val >> 8;
-		data[3] = val;
-		break;
-	case 2:
-		data[1] = val >> 8;
-		data[2] = val;
-		break;
-	case 1:
-		data[1] = val;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t, &m);
-
-	if (locked)
-		return spi_sync_locked(st->spi, &m);
-	else
-		return spi_sync(st->spi, &m);
+	return container_of(sd, struct ad7192_state, sd);
 }
 
-static int ad7192_write_reg(struct ad7192_state *st,
-			    unsigned reg, unsigned size, unsigned val)
+static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
 {
-	return __ad7192_write_reg(st, false, false, reg, size, val);
+	struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
+
+	st->conf &= ~AD7192_CONF_CHAN_MASK;
+	st->conf |= AD7192_CONF_CHAN(channel);
+
+	return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
 }
 
-static int __ad7192_read_reg(struct ad7192_state *st, bool locked,
-			     bool cs_change, unsigned char reg,
-			     int *val, unsigned size)
+static int ad7192_set_mode(struct ad_sigma_delta *sd,
+			   enum ad_sigma_delta_mode mode)
 {
-	u8 *data = st->data;
-	int ret;
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = data,
-			.len = 1,
-		}, {
-			.rx_buf = data,
-			.len = size,
-			.cs_change = cs_change,
-		},
-	};
-	struct spi_message m;
+	struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
 
-	data[0] = AD7192_COMM_READ | AD7192_COMM_ADDR(reg);
+	st->mode &= ~AD7192_MODE_SEL_MASK;
+	st->mode |= AD7192_MODE_SEL(mode);
 
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	if (locked)
-		ret = spi_sync_locked(st->spi, &m);
-	else
-		ret = spi_sync(st->spi, &m);
-
-	if (ret < 0)
-		return ret;
-
-	switch (size) {
-	case 3:
-		*val = data[0] << 16 | data[1] << 8 | data[2];
-		break;
-	case 2:
-		*val = data[0] << 8 | data[1];
-		break;
-	case 1:
-		*val = data[0];
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
+	return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
 }
 
-static int ad7192_read_reg(struct ad7192_state *st,
-			   unsigned reg, int *val, unsigned size)
-{
-	return __ad7192_read_reg(st, 0, 0, reg, val, size);
-}
+static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
+	.set_channel = ad7192_set_channel,
+	.set_mode = ad7192_set_mode,
+	.has_registers = true,
+	.addr_shift = 3,
+	.read_mask = BIT(6),
+};
 
-static int ad7192_read(struct ad7192_state *st, unsigned ch,
-		       unsigned len, int *val)
-{
-	int ret;
-	st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) |
-		AD7192_CONF_CHAN(1 << ch);
-	st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) |
-		AD7192_MODE_SEL(AD7192_MODE_SINGLE);
-
-	ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf);
-
-	spi_bus_lock(st->spi->master);
-	st->done = false;
-
-	ret = __ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3, st->mode);
-	if (ret < 0)
-		goto out;
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	ret = __ad7192_read_reg(st, 1, 0, AD7192_REG_DATA, val, len);
-out:
-	spi_bus_unlock(st->spi->master);
-
-	return ret;
-}
-
-static int ad7192_calibrate(struct ad7192_state *st, unsigned mode, unsigned ch)
-{
-	int ret;
-
-	st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) |
-		AD7192_CONF_CHAN(1 << ch);
-	st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | AD7192_MODE_SEL(mode);
-
-	ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf);
-
-	spi_bus_lock(st->spi->master);
-	st->done = false;
-
-	ret = __ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3,
-				 (st->devid != ID_AD7195) ?
-				 st->mode | AD7192_MODE_CLKDIV :
-				 st->mode);
-	if (ret < 0)
-		goto out;
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) |
-		AD7192_MODE_SEL(AD7192_MODE_IDLE);
-
-	ret = __ad7192_write_reg(st, 1, 0, AD7192_REG_MODE, 3, st->mode);
-out:
-	spi_bus_unlock(st->spi->master);
-
-	return ret;
-}
-
-static const u8 ad7192_calib_arr[8][2] = {
+static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
 	{AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1},
 	{AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1},
 	{AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN2},
@@ -332,45 +196,34 @@
 
 static int ad7192_calibrate_all(struct ad7192_state *st)
 {
-	int i, ret;
-
-	for (i = 0; i < ARRAY_SIZE(ad7192_calib_arr); i++) {
-		ret = ad7192_calibrate(st, ad7192_calib_arr[i][0],
-				       ad7192_calib_arr[i][1]);
-		if (ret)
-			goto out;
-	}
-
-	return 0;
-out:
-	dev_err(&st->spi->dev, "Calibration failed\n");
-	return ret;
+		return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr,
+				ARRAY_SIZE(ad7192_calib_arr));
 }
 
-static int ad7192_setup(struct ad7192_state *st)
+static int ad7192_setup(struct ad7192_state *st,
+	const struct ad7192_platform_data *pdata)
 {
-	struct iio_dev *indio_dev = spi_get_drvdata(st->spi);
-	struct ad7192_platform_data *pdata = st->pdata;
+	struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
 	unsigned long long scale_uv;
 	int i, ret, id;
 	u8 ones[6];
 
 	/* reset the serial interface */
 	memset(&ones, 0xFF, 6);
-	ret = spi_write(st->spi, &ones, 6);
+	ret = spi_write(st->sd.spi, &ones, 6);
 	if (ret < 0)
 		goto out;
 	msleep(1); /* Wait for at least 500us */
 
 	/* write/read test for device presence */
-	ret = ad7192_read_reg(st, AD7192_REG_ID, &id, 1);
+	ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id);
 	if (ret)
 		goto out;
 
 	id &= AD7192_ID_MASK;
 
 	if (id != st->devid)
-		dev_warn(&st->spi->dev, "device ID query failed (0x%X)\n", id);
+		dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X)\n", id);
 
 	switch (pdata->clock_source_sel) {
 	case AD7192_CLK_EXT_MCLK1_2:
@@ -423,11 +276,11 @@
 	if (pdata->burnout_curr_en)
 		st->conf |= AD7192_CONF_BURN;
 
-	ret = ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode);
+	ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
 	if (ret)
 		goto out;
 
-	ret = ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf);
+	ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
 	if (ret)
 		goto out;
 
@@ -448,181 +301,10 @@
 
 	return 0;
 out:
-	dev_err(&st->spi->dev, "setup failed\n");
+	dev_err(&st->sd.spi->dev, "setup failed\n");
 	return ret;
 }
 
-static int ad7192_ring_preenable(struct iio_dev *indio_dev)
-{
-	struct ad7192_state *st = iio_priv(indio_dev);
-	unsigned channel;
-	int ret;
-
-	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
-		return -EINVAL;
-
-	ret = iio_sw_buffer_preenable(indio_dev);
-	if (ret < 0)
-		return ret;
-
-	channel = find_first_bit(indio_dev->active_scan_mask,
-				 indio_dev->masklength);
-
-	st->mode  = (st->mode & ~AD7192_MODE_SEL(-1)) |
-		    AD7192_MODE_SEL(AD7192_MODE_CONT);
-	st->conf  = (st->conf & ~AD7192_CONF_CHAN(-1)) |
-		    AD7192_CONF_CHAN(1 << indio_dev->channels[channel].address);
-
-	ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf);
-
-	spi_bus_lock(st->spi->master);
-	__ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3, st->mode);
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-
-	return 0;
-}
-
-static int ad7192_ring_postdisable(struct iio_dev *indio_dev)
-{
-	struct ad7192_state *st = iio_priv(indio_dev);
-
-	st->mode  = (st->mode & ~AD7192_MODE_SEL(-1)) |
-		    AD7192_MODE_SEL(AD7192_MODE_IDLE);
-
-	st->done = false;
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	if (!st->irq_dis)
-		disable_irq_nosync(st->spi->irq);
-
-	__ad7192_write_reg(st, 1, 0, AD7192_REG_MODE, 3, st->mode);
-
-	return spi_bus_unlock(st->spi->master);
-}
-
-/**
- * ad7192_trigger_handler() bh of trigger launched polling to ring buffer
- **/
-static irqreturn_t ad7192_trigger_handler(int irq, void *p)
-{
-	struct iio_poll_func *pf = p;
-	struct iio_dev *indio_dev = pf->indio_dev;
-	struct iio_buffer *ring = indio_dev->buffer;
-	struct ad7192_state *st = iio_priv(indio_dev);
-	s64 dat64[2];
-	s32 *dat32 = (s32 *)dat64;
-
-	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
-		__ad7192_read_reg(st, 1, 1, AD7192_REG_DATA,
-				  dat32,
-				  indio_dev->channels[0].scan_type.realbits/8);
-
-	/* Guaranteed to be aligned with 8 byte boundary */
-	if (indio_dev->scan_timestamp)
-		dat64[1] = pf->timestamp;
-
-	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
-
-	iio_trigger_notify_done(indio_dev->trig);
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-
-	return IRQ_HANDLED;
-}
-
-static const struct iio_buffer_setup_ops ad7192_ring_setup_ops = {
-	.preenable = &ad7192_ring_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-	.postdisable = &ad7192_ring_postdisable,
-	.validate_scan_mask = &iio_validate_scan_mask_onehot,
-};
-
-static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
-{
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
-			&ad7192_trigger_handler, &ad7192_ring_setup_ops);
-}
-
-static void ad7192_ring_cleanup(struct iio_dev *indio_dev)
-{
-	iio_triggered_buffer_cleanup(indio_dev);
-}
-
-/**
- * ad7192_data_rdy_trig_poll() the event handler for the data rdy trig
- **/
-static irqreturn_t ad7192_data_rdy_trig_poll(int irq, void *private)
-{
-	struct ad7192_state *st = iio_priv(private);
-
-	st->done = true;
-	wake_up_interruptible(&st->wq_data_avail);
-	disable_irq_nosync(irq);
-	st->irq_dis = true;
-	iio_trigger_poll(st->trig, iio_get_time_ns());
-
-	return IRQ_HANDLED;
-}
-
-static struct iio_trigger_ops ad7192_trigger_ops = {
-	.owner = THIS_MODULE,
-};
-
-static int ad7192_probe_trigger(struct iio_dev *indio_dev)
-{
-	struct ad7192_state *st = iio_priv(indio_dev);
-	int ret;
-
-	st->trig = iio_trigger_alloc("%s-dev%d",
-					spi_get_device_id(st->spi)->name,
-					indio_dev->id);
-	if (st->trig == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st->trig->ops = &ad7192_trigger_ops;
-	ret = request_irq(st->spi->irq,
-			  ad7192_data_rdy_trig_poll,
-			  IRQF_TRIGGER_LOW,
-			  spi_get_device_id(st->spi)->name,
-			  indio_dev);
-	if (ret)
-		goto error_free_trig;
-
-	disable_irq_nosync(st->spi->irq);
-	st->irq_dis = true;
-	st->trig->dev.parent = &st->spi->dev;
-	st->trig->private_data = indio_dev;
-
-	ret = iio_trigger_register(st->trig);
-
-	/* select default trigger */
-	indio_dev->trig = st->trig;
-	if (ret)
-		goto error_free_irq;
-
-	return 0;
-
-error_free_irq:
-	free_irq(st->spi->irq, indio_dev);
-error_free_trig:
-	iio_trigger_free(st->trig);
-error_ret:
-	return ret;
-}
-
-static void ad7192_remove_trigger(struct iio_dev *indio_dev)
-{
-	struct ad7192_state *st = iio_priv(indio_dev);
-
-	iio_trigger_unregister(st->trig);
-	free_irq(st->spi->irq, indio_dev);
-	iio_trigger_free(st->trig);
-}
-
 static ssize_t ad7192_read_frequency(struct device *dev,
 		struct device_attribute *attr,
 		char *buf)
@@ -664,7 +346,7 @@
 
 	st->mode &= ~AD7192_MODE_RATE(-1);
 	st->mode |= AD7192_MODE_RATE(div);
-	ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode);
+	ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
 
 out:
 	mutex_unlock(&indio_dev->mlock);
@@ -676,7 +358,6 @@
 		ad7192_read_frequency,
 		ad7192_write_frequency);
 
-
 static ssize_t ad7192_show_scale_available(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
@@ -748,7 +429,7 @@
 		else
 			st->gpocon &= ~AD7192_GPOCON_BPDSW;
 
-		ad7192_write_reg(st, AD7192_REG_GPOCON, 1, st->gpocon);
+		ad_sd_write_reg(&st->sd, AD7192_REG_GPOCON, 1, st->gpocon);
 		break;
 	case AD7192_REG_MODE:
 		if (val)
@@ -756,7 +437,7 @@
 		else
 			st->mode &= ~AD7192_MODE_ACX;
 
-		ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode);
+		ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
 		break;
 	default:
 		ret = -EINVAL;
@@ -812,27 +493,11 @@
 			   long m)
 {
 	struct ad7192_state *st = iio_priv(indio_dev);
-	int ret, smpl = 0;
 	bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7192_read(st, chan->address,
-					chan->scan_type.realbits / 8, &smpl);
-		mutex_unlock(&indio_dev->mlock);
-
-		if (ret < 0)
-			return ret;
-
-		*val = (smpl >> chan->scan_type.shift) &
-			((1 << (chan->scan_type.realbits)) - 1);
-
-		return IIO_VAL_INT;
-
+		return ad_sigma_delta_single_conversion(indio_dev, chan, val);
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->type) {
 		case IIO_VOLTAGE:
@@ -883,16 +548,16 @@
 		ret = -EINVAL;
 		for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
 			if (val2 == st->scale_avail[i][1]) {
+				ret = 0;
 				tmp = st->conf;
 				st->conf &= ~AD7192_CONF_GAIN(-1);
 				st->conf |= AD7192_CONF_GAIN(i);
-
-				if (tmp != st->conf) {
-					ad7192_write_reg(st, AD7192_REG_CONF,
-							 3, st->conf);
-					ad7192_calibrate_all(st);
-				}
-				ret = 0;
+				if (tmp == st->conf)
+					break;
+				ad_sd_write_reg(&st->sd, AD7192_REG_CONF,
+						 3, st->conf);
+				ad7192_calibrate_all(st);
+				break;
 			}
 		break;
 	default:
@@ -904,15 +569,6 @@
 	return ret;
 }
 
-static int ad7192_validate_trigger(struct iio_dev *indio_dev,
-				   struct iio_trigger *trig)
-{
-	if (indio_dev->trig != trig)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
 			       struct iio_chan_spec const *chan,
 			       long mask)
@@ -925,7 +581,7 @@
 	.write_raw = &ad7192_write_raw,
 	.write_raw_get_fmt = &ad7192_write_raw_get_fmt,
 	.attrs = &ad7192_attribute_group,
-	.validate_trigger = ad7192_validate_trigger,
+	.validate_trigger = ad_sd_validate_trigger,
 	.driver_module = THIS_MODULE,
 };
 
@@ -934,60 +590,25 @@
 	.write_raw = &ad7192_write_raw,
 	.write_raw_get_fmt = &ad7192_write_raw_get_fmt,
 	.attrs = &ad7195_attribute_group,
-	.validate_trigger = ad7192_validate_trigger,
+	.validate_trigger = ad_sd_validate_trigger,
 	.driver_module = THIS_MODULE,
 };
 
-#define AD7192_CHAN_DIFF(_chan, _chan2, _name, _address, _si)		\
-	{ .type = IIO_VOLTAGE,						\
-	  .differential = 1,						\
-	  .indexed = 1,							\
-	  .extend_name = _name,						\
-	  .channel = _chan,						\
-	  .channel2 = _chan2,						\
-	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
-	  IIO_CHAN_INFO_SCALE_SHARED_BIT |				\
-	  IIO_CHAN_INFO_OFFSET_SHARED_BIT,				\
-	  .address = _address,						\
-	  .scan_index = _si,						\
-	  .scan_type =  IIO_ST('u', 24, 32, 0)}
-
-#define AD7192_CHAN(_chan, _address, _si)				\
-	{ .type = IIO_VOLTAGE,						\
-	  .indexed = 1,							\
-	  .channel = _chan,						\
-	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
-	  IIO_CHAN_INFO_SCALE_SHARED_BIT |				\
-	  IIO_CHAN_INFO_OFFSET_SHARED_BIT,				\
-	  .address = _address,						\
-	  .scan_index = _si,						\
-	  .scan_type =  IIO_ST('u', 24, 32, 0)}
-
-#define AD7192_CHAN_TEMP(_chan, _address, _si)				\
-	{ .type = IIO_TEMP,						\
-	  .indexed = 1,							\
-	  .channel = _chan,						\
-	  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |			\
-	  IIO_CHAN_INFO_SCALE_SEPARATE_BIT,				\
-	  .address = _address,						\
-	  .scan_index = _si,						\
-	  .scan_type =  IIO_ST('u', 24, 32, 0)}
-
-static struct iio_chan_spec ad7192_channels[] = {
-	AD7192_CHAN_DIFF(1, 2, NULL, AD7192_CH_AIN1P_AIN2M, 0),
-	AD7192_CHAN_DIFF(3, 4, NULL, AD7192_CH_AIN3P_AIN4M, 1),
-	AD7192_CHAN_TEMP(0, AD7192_CH_TEMP, 2),
-	AD7192_CHAN_DIFF(2, 2, "shorted", AD7192_CH_AIN2P_AIN2M, 3),
-	AD7192_CHAN(1, AD7192_CH_AIN1, 4),
-	AD7192_CHAN(2, AD7192_CH_AIN2, 5),
-	AD7192_CHAN(3, AD7192_CH_AIN3, 6),
-	AD7192_CHAN(4, AD7192_CH_AIN4, 7),
+static const struct iio_chan_spec ad7192_channels[] = {
+	AD_SD_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M, 24, 32, 0),
+	AD_SD_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M, 24, 32, 0),
+	AD_SD_TEMP_CHANNEL(2, AD7192_CH_TEMP, 24, 32, 0),
+	AD_SD_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M, 24, 32, 0),
+	AD_SD_CHANNEL(4, 1, AD7192_CH_AIN1, 24, 32, 0),
+	AD_SD_CHANNEL(5, 2, AD7192_CH_AIN2, 24, 32, 0),
+	AD_SD_CHANNEL(6, 3, AD7192_CH_AIN3, 24, 32, 0),
+	AD_SD_CHANNEL(7, 4, AD7192_CH_AIN4, 24, 32, 0),
 	IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
 static int __devinit ad7192_probe(struct spi_device *spi)
 {
-	struct ad7192_platform_data *pdata = spi->dev.platform_data;
+	const struct ad7192_platform_data *pdata = spi->dev.platform_data;
 	struct ad7192_state *st;
 	struct iio_dev *indio_dev;
 	int ret , voltage_uv = 0;
@@ -1017,8 +638,6 @@
 		voltage_uv = regulator_get_voltage(st->reg);
 	}
 
-	st->pdata = pdata;
-
 	if (pdata && pdata->vref_mv)
 		st->int_vref_mv = pdata->vref_mv;
 	else if (voltage_uv)
@@ -1027,7 +646,6 @@
 		dev_warn(&spi->dev, "reference voltage undefined\n");
 
 	spi_set_drvdata(spi, indio_dev);
-	st->spi = spi;
 	st->devid = spi_get_device_id(spi)->driver_data;
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
@@ -1039,17 +657,13 @@
 	else
 		indio_dev->info = &ad7192_info;
 
-	init_waitqueue_head(&st->wq_data_avail);
+	ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
 
-	ret = ad7192_register_ring_funcs_and_init(indio_dev);
+	ret = ad_sd_setup_buffer_and_trigger(indio_dev);
 	if (ret)
 		goto error_disable_reg;
 
-	ret = ad7192_probe_trigger(indio_dev);
-	if (ret)
-		goto error_ring_cleanup;
-
-	ret = ad7192_setup(st);
+	ret = ad7192_setup(st, pdata);
 	if (ret)
 		goto error_remove_trigger;
 
@@ -1059,9 +673,7 @@
 	return 0;
 
 error_remove_trigger:
-	ad7192_remove_trigger(indio_dev);
-error_ring_cleanup:
-	ad7192_ring_cleanup(indio_dev);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
@@ -1074,14 +686,13 @@
 	return ret;
 }
 
-static int ad7192_remove(struct spi_device *spi)
+static int __devexit ad7192_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ad7192_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	ad7192_remove_trigger(indio_dev);
-	ad7192_ring_cleanup(indio_dev);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
index 6141f4a..4c75114 100644
--- a/drivers/staging/iio/adc/ad7298_core.c
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -38,7 +38,7 @@
 		},							\
 	}
 
-static struct iio_chan_spec ad7298_channels[] = {
+static const struct iio_chan_spec ad7298_channels[] = {
 	{
 		.type = IIO_TEMP,
 		.indexed = 1,
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index 506016f..c2906a8 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -75,7 +75,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ad7298_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	s64 time_ns = 0;
 	__u16 buf[16];
 	int b_sent, i;
@@ -94,7 +93,7 @@
 						 indio_dev->masklength); i++)
 		buf[i] = be16_to_cpu(st->rx_buf[i]);
 
-	indio_dev->buffer->access->store_to(ring, (u8 *)buf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)buf);
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
deleted file mode 100644
index b1dd931..0000000
--- a/drivers/staging/iio/adc/ad7476.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * AD7476/5/7/8 (A) SPI ADC driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-#ifndef IIO_ADC_AD7476_H_
-#define IIO_ADC_AD7476_H_
-
-#define RES_MASK(bits)	((1 << (bits)) - 1)
-
-/*
- * TODO: struct ad7476_platform_data needs to go into include/linux/iio
- */
-
-struct ad7476_platform_data {
-	u16				vref_mv;
-};
-
-struct ad7476_chip_info {
-	u16				int_vref_mv;
-	struct iio_chan_spec		channel[2];
-};
-
-struct ad7476_state {
-	struct spi_device		*spi;
-	const struct ad7476_chip_info	*chip_info;
-	struct regulator		*reg;
-	u16				int_vref_mv;
-	struct spi_transfer		xfer;
-	struct spi_message		msg;
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	unsigned char			data[2] ____cacheline_aligned;
-};
-
-enum ad7476_supported_device_ids {
-	ID_AD7466,
-	ID_AD7467,
-	ID_AD7468,
-	ID_AD7475,
-	ID_AD7476,
-	ID_AD7477,
-	ID_AD7478,
-	ID_AD7495
-};
-
-#ifdef CONFIG_IIO_BUFFER
-int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev);
-void ad7476_ring_cleanup(struct iio_dev *indio_dev);
-#else /* CONFIG_IIO_BUFFER */
-
-static inline int
-ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
-{
-	return 0;
-}
-
-static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev)
-{
-}
-#endif /* CONFIG_IIO_BUFFER */
-#endif /* IIO_ADC_AD7476_H_ */
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
deleted file mode 100644
index 4d30a79..0000000
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-
-#include "ad7476.h"
-
-static int ad7476_scan_direct(struct ad7476_state *st)
-{
-	int ret;
-
-	ret = spi_sync(st->spi, &st->msg);
-	if (ret)
-		return ret;
-
-	return (st->data[0] << 8) | st->data[1];
-}
-
-static int ad7476_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	int ret;
-	struct ad7476_state *st = iio_priv(indio_dev);
-	unsigned int scale_uv;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7476_scan_direct(st);
-		mutex_unlock(&indio_dev->mlock);
-
-		if (ret < 0)
-			return ret;
-		*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
-			RES_MASK(st->chip_info->channel[0].scan_type.realbits);
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->int_vref_mv * 1000)
-			>> st->chip_info->channel[0].scan_type.realbits;
-		*val =  scale_uv/1000;
-		*val2 = (scale_uv%1000)*1000;
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-	return -EINVAL;
-}
-
-#define AD7476_CHAN(bits)					\
-	{							\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
-	IIO_CHAN_INFO_SCALE_SHARED_BIT,				\
-	.scan_type = {						\
-		.sign = 'u',					\
-		.realbits = bits,				\
-		.storagebits = 16,				\
-		.shift = 12 - bits,				\
-	},							\
-}
-
-static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
-	[ID_AD7466] = {
-		.channel[0] = AD7476_CHAN(12),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7467] = {
-		.channel[0] = AD7476_CHAN(10),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7468] = {
-		.channel[0] = AD7476_CHAN(8),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7475] = {
-		.channel[0] = AD7476_CHAN(12),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7476] = {
-		.channel[0] = AD7476_CHAN(12),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7477] = {
-		.channel[0] = AD7476_CHAN(10),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7478] = {
-		.channel[0] = AD7476_CHAN(8),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-	},
-	[ID_AD7495] = {
-		.channel[0] = AD7476_CHAN(12),
-		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
-		.int_vref_mv = 2500,
-	},
-};
-
-static const struct iio_info ad7476_info = {
-	.driver_module = THIS_MODULE,
-	.read_raw = &ad7476_read_raw,
-};
-
-static int __devinit ad7476_probe(struct spi_device *spi)
-{
-	struct ad7476_platform_data *pdata = spi->dev.platform_data;
-	struct ad7476_state *st;
-	struct iio_dev *indio_dev;
-	int ret, voltage_uv = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st = iio_priv(indio_dev);
-	st->reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(st->reg)) {
-		ret = regulator_enable(st->reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(st->reg);
-	}
-	st->chip_info =
-		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
-
-	if (st->chip_info->int_vref_mv)
-		st->int_vref_mv = st->chip_info->int_vref_mv;
-	else if (pdata && pdata->vref_mv)
-		st->int_vref_mv = pdata->vref_mv;
-	else if (voltage_uv)
-		st->int_vref_mv = voltage_uv / 1000;
-	else
-		dev_warn(&spi->dev, "reference voltage unspecified\n");
-
-	spi_set_drvdata(spi, indio_dev);
-
-	st->spi = spi;
-
-	/* Establish that the iio_dev is a child of the spi device */
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channel;
-	indio_dev->num_channels = 2;
-	indio_dev->info = &ad7476_info;
-	/* Setup default message */
-
-	st->xfer.rx_buf = &st->data;
-	st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
-
-	spi_message_init(&st->msg);
-	spi_message_add_tail(&st->xfer, &st->msg);
-
-	ret = ad7476_register_ring_funcs_and_init(indio_dev);
-	if (ret)
-		goto error_disable_reg;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_ring_unregister;
-	return 0;
-
-error_ring_unregister:
-	ad7476_ring_cleanup(indio_dev);
-error_disable_reg:
-	if (!IS_ERR(st->reg))
-		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-	iio_device_free(indio_dev);
-
-error_ret:
-	return ret;
-}
-
-static int ad7476_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad7476_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	ad7476_ring_cleanup(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad7476_id[] = {
-	{"ad7466", ID_AD7466},
-	{"ad7467", ID_AD7467},
-	{"ad7468", ID_AD7468},
-	{"ad7475", ID_AD7475},
-	{"ad7476", ID_AD7476},
-	{"ad7476a", ID_AD7476},
-	{"ad7477", ID_AD7477},
-	{"ad7477a", ID_AD7477},
-	{"ad7478", ID_AD7478},
-	{"ad7478a", ID_AD7478},
-	{"ad7495", ID_AD7495},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad7476_id);
-
-static struct spi_driver ad7476_driver = {
-	.driver = {
-		.name	= "ad7476",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad7476_probe,
-	.remove		= __devexit_p(ad7476_remove),
-	.id_table	= ad7476_id,
-};
-module_spi_driver(ad7476_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
deleted file mode 100644
index d087b21..0000000
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2010-2012 Analog Devices Inc.
- * Copyright (C) 2008 Jonathan Cameron
- *
- * Licensed under the GPL-2 or later.
- *
- * ad7476_ring.c
- */
-
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/triggered_buffer.h>
-
-#include "ad7476.h"
-
-static irqreturn_t ad7476_trigger_handler(int irq, void  *p)
-{
-	struct iio_poll_func *pf = p;
-	struct iio_dev *indio_dev = pf->indio_dev;
-	struct ad7476_state *st = iio_priv(indio_dev);
-	s64 time_ns;
-	__u8 *rxbuf;
-	int b_sent;
-
-	rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
-	if (rxbuf == NULL)
-		goto done;
-
-	b_sent = spi_read(st->spi, rxbuf,
-			  st->chip_info->channel[0].scan_type.storagebits / 8);
-	if (b_sent < 0)
-		goto done;
-
-	time_ns = iio_get_time_ns();
-
-	if (indio_dev->scan_timestamp)
-		memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
-			&time_ns, sizeof(time_ns));
-
-	indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
-done:
-	iio_trigger_notify_done(indio_dev->trig);
-	kfree(rxbuf);
-
-	return IRQ_HANDLED;
-}
-
-int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
-{
-	return iio_triggered_buffer_setup(indio_dev, NULL,
-			&ad7476_trigger_handler, NULL);
-}
-
-void ad7476_ring_cleanup(struct iio_dev *indio_dev)
-{
-	iio_triggered_buffer_cleanup(indio_dev);
-}
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h
index 10f5989..9221a74 100644
--- a/drivers/staging/iio/adc/ad7606.h
+++ b/drivers/staging/iio/adc/ad7606.h
@@ -51,7 +51,7 @@
 struct ad7606_chip_info {
 	const char			*name;
 	u16				int_vref_mv;
-	struct iio_chan_spec		*channels;
+	const struct iio_chan_spec	*channels;
 	unsigned			num_channels;
 };
 
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index ccb97fe..bae61cb 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -241,7 +241,7 @@
 		.scan_type = IIO_ST('s', 16, 16, 0),		\
 	}
 
-static struct iio_chan_spec ad7606_8_channels[] = {
+static const struct iio_chan_spec ad7606_8_channels[] = {
 	AD7606_CHANNEL(0),
 	AD7606_CHANNEL(1),
 	AD7606_CHANNEL(2),
@@ -253,7 +253,7 @@
 	IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
-static struct iio_chan_spec ad7606_6_channels[] = {
+static const struct iio_chan_spec ad7606_6_channels[] = {
 	AD7606_CHANNEL(0),
 	AD7606_CHANNEL(1),
 	AD7606_CHANNEL(2),
@@ -263,7 +263,7 @@
 	IIO_CHAN_SOFT_TIMESTAMP(6),
 };
 
-static struct iio_chan_spec ad7606_4_channels[] = {
+static const struct iio_chan_spec ad7606_4_channels[] = {
 	AD7606_CHANNEL(0),
 	AD7606_CHANNEL(1),
 	AD7606_CHANNEL(2),
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index f15afe4..ba04d0f 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -46,7 +46,6 @@
 	struct ad7606_state *st = container_of(work_s, struct ad7606_state,
 						poll_work);
 	struct iio_dev *indio_dev = iio_priv_to_dev(st);
-	struct iio_buffer *ring = indio_dev->buffer;
 	s64 time_ns;
 	__u8 *buf;
 	int ret;
@@ -84,7 +83,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
 
-	ring->access->store_to(indio_dev->buffer, buf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, buf);
 done:
 	gpio_set_value(st->pdata->gpio_convst, 0);
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index 19ee49c..0a1328b 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -1,5 +1,5 @@
 /*
- * AD7780/AD7781 SPI ADC driver
+ * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver
  *
  * Copyright 2011 Analog Devices Inc.
  *
@@ -20,6 +20,7 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
 
 #include "ad7780.h"
 
@@ -33,53 +34,53 @@
 #define AD7780_PAT0	(1 << 0)
 
 struct ad7780_chip_info {
-	struct iio_chan_spec		channel;
+	struct iio_chan_spec	channel;
+	unsigned int		pattern_mask;
+	unsigned int		pattern;
 };
 
 struct ad7780_state {
-	struct spi_device		*spi;
 	const struct ad7780_chip_info	*chip_info;
 	struct regulator		*reg;
-	struct ad7780_platform_data	*pdata;
-	wait_queue_head_t		wq_data_avail;
-	bool				done;
+	int				powerdown_gpio;
+	unsigned int	gain;
 	u16				int_vref_mv;
-	struct spi_transfer		xfer;
-	struct spi_message		msg;
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	unsigned int			data ____cacheline_aligned;
+
+	struct ad_sigma_delta sd;
 };
 
 enum ad7780_supported_device_ids {
+	ID_AD7170,
+	ID_AD7171,
 	ID_AD7780,
 	ID_AD7781,
 };
 
-static int ad7780_read(struct ad7780_state *st, int *val)
+static struct ad7780_state *ad_sigma_delta_to_ad7780(struct ad_sigma_delta *sd)
 {
-	int ret;
+	return container_of(sd, struct ad7780_state, sd);
+}
 
-	spi_bus_lock(st->spi->master);
+static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
+	enum ad_sigma_delta_mode mode)
+{
+	struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
+	unsigned val;
 
-	enable_irq(st->spi->irq);
-	st->done = false;
-	gpio_set_value(st->pdata->gpio_pdrst, 1);
+	switch (mode) {
+	case AD_SD_MODE_SINGLE:
+	case AD_SD_MODE_CONTINUOUS:
+		val = 1;
+		break;
+	default:
+		val = 0;
+		break;
+	}
 
-	ret = wait_event_interruptible(st->wq_data_avail, st->done);
-	disable_irq_nosync(st->spi->irq);
-	if (ret)
-		goto out;
+	if (gpio_is_valid(st->powerdown_gpio))
+		gpio_set_value(st->powerdown_gpio, val);
 
-	ret = spi_sync_locked(st->spi, &st->msg);
-	*val = be32_to_cpu(st->data);
-out:
-	gpio_set_value(st->pdata->gpio_pdrst, 0);
-	spi_bus_unlock(st->spi->master);
-
-	return ret;
+	return 0;
 }
 
 static int ad7780_read_raw(struct iio_dev *indio_dev,
@@ -89,87 +90,73 @@
 			   long m)
 {
 	struct ad7780_state *st = iio_priv(indio_dev);
-	struct iio_chan_spec channel = st->chip_info->channel;
-	int ret, smpl = 0;
 	unsigned long scale_uv;
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		ret = ad7780_read(st, &smpl);
-		mutex_unlock(&indio_dev->mlock);
-
-		if (ret < 0)
-			return ret;
-
-		if ((smpl & AD7780_ERR) ||
-			!((smpl & AD7780_PAT0) && !(smpl & AD7780_PAT1)))
-			return -EIO;
-
-		*val = (smpl >> channel.scan_type.shift) &
-			((1 << (channel.scan_type.realbits)) - 1);
-		*val -= (1 << (channel.scan_type.realbits - 1));
-
-		if (!(smpl & AD7780_GAIN))
-			*val *= 128;
-
-		return IIO_VAL_INT;
+		return ad_sigma_delta_single_conversion(indio_dev, chan, val);
 	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->int_vref_mv * 100000)
-			>> (channel.scan_type.realbits - 1);
+		scale_uv = (st->int_vref_mv * 100000 * st->gain)
+			>> (chan->scan_type.realbits - 1);
 		*val =  scale_uv / 100000;
 		*val2 = (scale_uv % 100000) * 10;
 		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val -= (1 << (chan->scan_type.realbits - 1));
+		return IIO_VAL_INT;
 	}
+
 	return -EINVAL;
 }
 
-static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
-	[ID_AD7780] = {
-		.channel = {
-			.type = IIO_VOLTAGE,
-			.indexed = 1,
-			.channel = 0,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_type = {
-				.sign = 'u',
-				.realbits = 24,
-				.storagebits = 32,
-				.shift = 8,
-			},
-		},
-	},
-	[ID_AD7781] = {
-		.channel = {
-			.type = IIO_VOLTAGE,
-			.indexed = 1,
-			.channel = 0,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_type = {
-				.sign = 'u',
-				.realbits = 20,
-				.storagebits = 32,
-				.shift = 12,
-			},
-		},
-	},
+static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
+	unsigned int raw_sample)
+{
+	struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
+	const struct ad7780_chip_info *chip_info = st->chip_info;
+
+	if ((raw_sample & AD7780_ERR) ||
+		((raw_sample & chip_info->pattern_mask) != chip_info->pattern))
+		return -EIO;
+
+	if (raw_sample & AD7780_GAIN)
+		st->gain = 1;
+	else
+		st->gain = 128;
+
+	return 0;
+}
+
+static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
+	.set_mode = ad7780_set_mode,
+	.postprocess_sample = ad7780_postprocess_sample,
+	.has_registers = false,
 };
 
-/**
- *  Interrupt handler
- */
-static irqreturn_t ad7780_interrupt(int irq, void *dev_id)
-{
-	struct ad7780_state *st = dev_id;
+#define AD7780_CHANNEL(bits, wordsize) \
+	AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits)
 
-	st->done = true;
-	wake_up_interruptible(&st->wq_data_avail);
-
-	return IRQ_HANDLED;
+static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
+	[ID_AD7170] = {
+		.channel = AD7780_CHANNEL(12, 24),
+		.pattern = 0x5,
+		.pattern_mask = 0x7,
+	},
+	[ID_AD7171] = {
+		.channel = AD7780_CHANNEL(16, 24),
+		.pattern = 0x5,
+		.pattern_mask = 0x7,
+	},
+	[ID_AD7780] = {
+		.channel = AD7780_CHANNEL(24, 32),
+		.pattern = 0x1,
+		.pattern_mask = 0x3,
+	},
+	[ID_AD7781] = {
+		.channel = AD7780_CHANNEL(20, 32),
+		.pattern = 0x1,
+		.pattern_mask = 0x3,
+	},
 };
 
 static const struct iio_info ad7780_info = {
@@ -184,16 +171,14 @@
 	struct iio_dev *indio_dev;
 	int ret, voltage_uv = 0;
 
-	if (!pdata) {
-		dev_dbg(&spi->dev, "no platform data?\n");
-		return -ENODEV;
-	}
-
 	indio_dev = iio_device_alloc(sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
+	st->gain = 1;
+
+	ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info);
 
 	st->reg = regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
@@ -207,8 +192,6 @@
 	st->chip_info =
 		&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-	st->pdata = pdata;
-
 	if (pdata && pdata->vref_mv)
 		st->int_vref_mv = pdata->vref_mv;
 	else if (voltage_uv)
@@ -217,7 +200,6 @@
 		dev_warn(&spi->dev, "reference voltage unspecified\n");
 
 	spi_set_drvdata(spi, indio_dev);
-	st->spi = spi;
 
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
@@ -226,40 +208,34 @@
 	indio_dev->num_channels = 1;
 	indio_dev->info = &ad7780_info;
 
-	init_waitqueue_head(&st->wq_data_avail);
+	if (pdata && gpio_is_valid(pdata->gpio_pdrst)) {
 
-	/* Setup default message */
-
-	st->xfer.rx_buf = &st->data;
-	st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8;
-
-	spi_message_init(&st->msg);
-	spi_message_add_tail(&st->xfer, &st->msg);
-
-	ret = gpio_request_one(st->pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW,
+		ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW,
 			       "AD7780 /PDRST");
-	if (ret) {
-		dev_err(&spi->dev, "failed to request GPIO PDRST\n");
-		goto error_disable_reg;
+		if (ret) {
+			dev_err(&spi->dev, "failed to request GPIO PDRST\n");
+			goto error_disable_reg;
+		}
+		st->powerdown_gpio = pdata->gpio_pdrst;
+	} else {
+		st->powerdown_gpio = -1;
 	}
 
-	ret = request_irq(spi->irq, ad7780_interrupt,
-		IRQF_TRIGGER_FALLING, spi_get_device_id(spi)->name, st);
+	ret = ad_sd_setup_buffer_and_trigger(indio_dev);
 	if (ret)
 		goto error_free_gpio;
 
-	disable_irq(spi->irq);
-
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_irq;
+		goto error_cleanup_buffer_and_trigger;
 
 	return 0;
 
-error_free_irq:
-	free_irq(spi->irq, st);
+error_cleanup_buffer_and_trigger:
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_free_gpio:
-	gpio_free(st->pdata->gpio_pdrst);
+	if (pdata && gpio_is_valid(pdata->gpio_pdrst))
+		gpio_free(pdata->gpio_pdrst);
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
@@ -272,14 +248,17 @@
 	return ret;
 }
 
-static int ad7780_remove(struct spi_device *spi)
+static int __devexit ad7780_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ad7780_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	free_irq(spi->irq, st);
-	gpio_free(st->pdata->gpio_pdrst);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
+
+	if (gpio_is_valid(st->powerdown_gpio))
+		gpio_free(st->powerdown_gpio);
+
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
 		regulator_put(st->reg);
@@ -290,6 +269,8 @@
 }
 
 static const struct spi_device_id ad7780_id[] = {
+	{"ad7170", ID_AD7170},
+	{"ad7171", ID_AD7171},
 	{"ad7780", ID_AD7780},
 	{"ad7781", ID_AD7781},
 	{}
@@ -308,5 +289,5 @@
 module_spi_driver(ad7780_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD7780/1 ADC");
+MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index 112e2b7..691a7be 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -1,5 +1,5 @@
 /*
- * AD7792/AD7793 SPI ADC driver
+ * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver
  *
  * Copyright 2011-2012 Analog Devices Inc.
  *
@@ -24,6 +24,7 @@
 #include <linux/iio/trigger.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
 
 #include "ad7793.h"
 
@@ -36,198 +37,65 @@
  */
 
 struct ad7793_chip_info {
-	struct iio_chan_spec		channel[7];
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
 };
 
 struct ad7793_state {
-	struct spi_device		*spi;
-	struct iio_trigger		*trig;
 	const struct ad7793_chip_info	*chip_info;
 	struct regulator		*reg;
-	struct ad7793_platform_data	*pdata;
-	wait_queue_head_t		wq_data_avail;
-	bool				done;
-	bool				irq_dis;
 	u16				int_vref_mv;
 	u16				mode;
 	u16				conf;
 	u32				scale_avail[8][2];
 
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	u8				data[4] ____cacheline_aligned;
+	struct ad_sigma_delta		sd;
+
 };
 
 enum ad7793_supported_device_ids {
+	ID_AD7785,
 	ID_AD7792,
 	ID_AD7793,
+	ID_AD7794,
+	ID_AD7795,
 };
 
-static int __ad7793_write_reg(struct ad7793_state *st, bool locked,
-			      bool cs_change, unsigned char reg,
-			      unsigned size, unsigned val)
+static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd)
 {
-	u8 *data = st->data;
-	struct spi_transfer t = {
-		.tx_buf		= data,
-		.len		= size + 1,
-		.cs_change	= cs_change,
-	};
-	struct spi_message m;
-
-	data[0] = AD7793_COMM_WRITE | AD7793_COMM_ADDR(reg);
-
-	switch (size) {
-	case 3:
-		data[1] = val >> 16;
-		data[2] = val >> 8;
-		data[3] = val;
-		break;
-	case 2:
-		data[1] = val >> 8;
-		data[2] = val;
-		break;
-	case 1:
-		data[1] = val;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t, &m);
-
-	if (locked)
-		return spi_sync_locked(st->spi, &m);
-	else
-		return spi_sync(st->spi, &m);
+	return container_of(sd, struct ad7793_state, sd);
 }
 
-static int ad7793_write_reg(struct ad7793_state *st,
-			    unsigned reg, unsigned size, unsigned val)
+static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
 {
-	return __ad7793_write_reg(st, false, false, reg, size, val);
+	struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
+
+	st->conf &= ~AD7793_CONF_CHAN_MASK;
+	st->conf |= AD7793_CONF_CHAN(channel);
+
+	return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf);
 }
 
-static int __ad7793_read_reg(struct ad7793_state *st, bool locked,
-			     bool cs_change, unsigned char reg,
-			     int *val, unsigned size)
+static int ad7793_set_mode(struct ad_sigma_delta *sd,
+			   enum ad_sigma_delta_mode mode)
 {
-	u8 *data = st->data;
-	int ret;
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = data,
-			.len = 1,
-		}, {
-			.rx_buf = data,
-			.len = size,
-			.cs_change = cs_change,
-		},
-	};
-	struct spi_message m;
+	struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
 
-	data[0] = AD7793_COMM_READ | AD7793_COMM_ADDR(reg);
+	st->mode &= ~AD7793_MODE_SEL_MASK;
+	st->mode |= AD7793_MODE_SEL(mode);
 
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	if (locked)
-		ret = spi_sync_locked(st->spi, &m);
-	else
-		ret = spi_sync(st->spi, &m);
-
-	if (ret < 0)
-		return ret;
-
-	switch (size) {
-	case 3:
-		*val = data[0] << 16 | data[1] << 8 | data[2];
-		break;
-	case 2:
-		*val = data[0] << 8 | data[1];
-		break;
-	case 1:
-		*val = data[0];
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
+	return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode);
 }
 
-static int ad7793_read_reg(struct ad7793_state *st,
-			   unsigned reg, int *val, unsigned size)
-{
-	return __ad7793_read_reg(st, 0, 0, reg, val, size);
-}
+static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
+	.set_channel = ad7793_set_channel,
+	.set_mode = ad7793_set_mode,
+	.has_registers = true,
+	.addr_shift = 3,
+	.read_mask = BIT(6),
+};
 
-static int ad7793_read(struct ad7793_state *st, unsigned ch,
-		       unsigned len, int *val)
-{
-	int ret;
-	st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch);
-	st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) |
-		AD7793_MODE_SEL(AD7793_MODE_SINGLE);
-
-	ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf);
-
-	spi_bus_lock(st->spi->master);
-	st->done = false;
-
-	ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE,
-				 sizeof(st->mode), st->mode);
-	if (ret < 0)
-		goto out;
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	ret = __ad7793_read_reg(st, 1, 0, AD7793_REG_DATA, val, len);
-out:
-	spi_bus_unlock(st->spi->master);
-
-	return ret;
-}
-
-static int ad7793_calibrate(struct ad7793_state *st, unsigned mode, unsigned ch)
-{
-	int ret;
-
-	st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch);
-	st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | AD7793_MODE_SEL(mode);
-
-	ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf);
-
-	spi_bus_lock(st->spi->master);
-	st->done = false;
-
-	ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE,
-				 sizeof(st->mode), st->mode);
-	if (ret < 0)
-		goto out;
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) |
-		AD7793_MODE_SEL(AD7793_MODE_IDLE);
-
-	ret = __ad7793_write_reg(st, 1, 0, AD7793_REG_MODE,
-				 sizeof(st->mode), st->mode);
-out:
-	spi_bus_unlock(st->spi->master);
-
-	return ret;
-}
-
-static const u8 ad7793_calib_arr[6][2] = {
+static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
 	{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M},
 	{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M},
 	{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M},
@@ -238,59 +106,49 @@
 
 static int ad7793_calibrate_all(struct ad7793_state *st)
 {
-	int i, ret;
-
-	for (i = 0; i < ARRAY_SIZE(ad7793_calib_arr); i++) {
-		ret = ad7793_calibrate(st, ad7793_calib_arr[i][0],
-				       ad7793_calib_arr[i][1]);
-		if (ret)
-			goto out;
-	}
-
-	return 0;
-out:
-	dev_err(&st->spi->dev, "Calibration failed\n");
-	return ret;
+	return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr,
+				   ARRAY_SIZE(ad7793_calib_arr));
 }
 
-static int ad7793_setup(struct ad7793_state *st)
+static int ad7793_setup(struct iio_dev *indio_dev,
+	const struct ad7793_platform_data *pdata)
 {
+	struct ad7793_state *st = iio_priv(indio_dev);
 	int i, ret = -1;
 	unsigned long long scale_uv;
 	u32 id;
 
 	/* reset the serial interface */
-	ret = spi_write(st->spi, (u8 *)&ret, sizeof(ret));
+	ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret));
 	if (ret < 0)
 		goto out;
 	msleep(1); /* Wait for at least 500us */
 
 	/* write/read test for device presence */
-	ret = ad7793_read_reg(st, AD7793_REG_ID, &id, 1);
+	ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id);
 	if (ret)
 		goto out;
 
 	id &= AD7793_ID_MASK;
 
-	if (!((id == AD7792_ID) || (id == AD7793_ID))) {
-		dev_err(&st->spi->dev, "device ID query failed\n");
+	if (!((id == AD7792_ID) || (id == AD7793_ID) || (id == AD7795_ID))) {
+		dev_err(&st->sd.spi->dev, "device ID query failed\n");
 		goto out;
 	}
 
-	st->mode  = (st->pdata->mode & ~AD7793_MODE_SEL(-1)) |
-			AD7793_MODE_SEL(AD7793_MODE_IDLE);
-	st->conf  = st->pdata->conf & ~AD7793_CONF_CHAN(-1);
+	st->mode = pdata->mode;
+	st->conf = pdata->conf;
 
-	ret = ad7793_write_reg(st, AD7793_REG_MODE, sizeof(st->mode), st->mode);
+	ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE);
 	if (ret)
 		goto out;
 
-	ret = ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf);
+	ret = ad7793_set_channel(&st->sd, 0);
 	if (ret)
 		goto out;
 
-	ret = ad7793_write_reg(st, AD7793_REG_IO,
-			       sizeof(st->pdata->io), st->pdata->io);
+	ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO,
+			       sizeof(pdata->io), pdata->io);
 	if (ret)
 		goto out;
 
@@ -301,7 +159,7 @@
 	/* Populate available ADC input ranges */
 	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
 		scale_uv = ((u64)st->int_vref_mv * 100000000)
-			>> (st->chip_info->channel[0].scan_type.realbits -
+			>> (st->chip_info->channels[0].scan_type.realbits -
 			(!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1));
 		scale_uv >>= i;
 
@@ -311,184 +169,10 @@
 
 	return 0;
 out:
-	dev_err(&st->spi->dev, "setup failed\n");
+	dev_err(&st->sd.spi->dev, "setup failed\n");
 	return ret;
 }
 
-static int ad7793_ring_preenable(struct iio_dev *indio_dev)
-{
-	struct ad7793_state *st = iio_priv(indio_dev);
-	unsigned channel;
-	int ret;
-
-	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
-		return -EINVAL;
-	ret = iio_sw_buffer_preenable(indio_dev);
-	if (ret < 0)
-		return ret;
-
-	channel = find_first_bit(indio_dev->active_scan_mask,
-				 indio_dev->masklength);
-
-	st->mode  = (st->mode & ~AD7793_MODE_SEL(-1)) |
-		    AD7793_MODE_SEL(AD7793_MODE_CONT);
-	st->conf  = (st->conf & ~AD7793_CONF_CHAN(-1)) |
-		    AD7793_CONF_CHAN(indio_dev->channels[channel].address);
-
-	ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf);
-
-	spi_bus_lock(st->spi->master);
-	__ad7793_write_reg(st, 1, 1, AD7793_REG_MODE,
-			   sizeof(st->mode), st->mode);
-
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-
-	return 0;
-}
-
-static int ad7793_ring_postdisable(struct iio_dev *indio_dev)
-{
-	struct ad7793_state *st = iio_priv(indio_dev);
-
-	st->mode  = (st->mode & ~AD7793_MODE_SEL(-1)) |
-		    AD7793_MODE_SEL(AD7793_MODE_IDLE);
-
-	st->done = false;
-	wait_event_interruptible(st->wq_data_avail, st->done);
-
-	if (!st->irq_dis)
-		disable_irq_nosync(st->spi->irq);
-
-	__ad7793_write_reg(st, 1, 0, AD7793_REG_MODE,
-			   sizeof(st->mode), st->mode);
-
-	return spi_bus_unlock(st->spi->master);
-}
-
-/**
- * ad7793_trigger_handler() bh of trigger launched polling to ring buffer
- **/
-
-static irqreturn_t ad7793_trigger_handler(int irq, void *p)
-{
-	struct iio_poll_func *pf = p;
-	struct iio_dev *indio_dev = pf->indio_dev;
-	struct iio_buffer *ring = indio_dev->buffer;
-	struct ad7793_state *st = iio_priv(indio_dev);
-	s64 dat64[2];
-	s32 *dat32 = (s32 *)dat64;
-
-	if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
-		__ad7793_read_reg(st, 1, 1, AD7793_REG_DATA,
-				  dat32,
-				  indio_dev->channels[0].scan_type.realbits/8);
-
-	/* Guaranteed to be aligned with 8 byte boundary */
-	if (indio_dev->scan_timestamp)
-		dat64[1] = pf->timestamp;
-
-	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
-
-	iio_trigger_notify_done(indio_dev->trig);
-	st->irq_dis = false;
-	enable_irq(st->spi->irq);
-
-	return IRQ_HANDLED;
-}
-
-static const struct iio_buffer_setup_ops ad7793_ring_setup_ops = {
-	.preenable = &ad7793_ring_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-	.postdisable = &ad7793_ring_postdisable,
-	.validate_scan_mask = &iio_validate_scan_mask_onehot,
-};
-
-static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
-{
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
-			&ad7793_trigger_handler, &ad7793_ring_setup_ops);
-}
-
-static void ad7793_ring_cleanup(struct iio_dev *indio_dev)
-{
-	iio_triggered_buffer_cleanup(indio_dev);
-}
-
-/**
- * ad7793_data_rdy_trig_poll() the event handler for the data rdy trig
- **/
-static irqreturn_t ad7793_data_rdy_trig_poll(int irq, void *private)
-{
-	struct ad7793_state *st = iio_priv(private);
-
-	st->done = true;
-	wake_up_interruptible(&st->wq_data_avail);
-	disable_irq_nosync(irq);
-	st->irq_dis = true;
-	iio_trigger_poll(st->trig, iio_get_time_ns());
-
-	return IRQ_HANDLED;
-}
-
-static struct iio_trigger_ops ad7793_trigger_ops = {
-	.owner = THIS_MODULE,
-};
-
-static int ad7793_probe_trigger(struct iio_dev *indio_dev)
-{
-	struct ad7793_state *st = iio_priv(indio_dev);
-	int ret;
-
-	st->trig = iio_trigger_alloc("%s-dev%d",
-					spi_get_device_id(st->spi)->name,
-					indio_dev->id);
-	if (st->trig == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st->trig->ops = &ad7793_trigger_ops;
-
-	ret = request_irq(st->spi->irq,
-			  ad7793_data_rdy_trig_poll,
-			  IRQF_TRIGGER_LOW,
-			  spi_get_device_id(st->spi)->name,
-			  indio_dev);
-	if (ret)
-		goto error_free_trig;
-
-	disable_irq_nosync(st->spi->irq);
-	st->irq_dis = true;
-	st->trig->dev.parent = &st->spi->dev;
-	st->trig->private_data = indio_dev;
-
-	ret = iio_trigger_register(st->trig);
-
-	/* select default trigger */
-	indio_dev->trig = st->trig;
-	if (ret)
-		goto error_free_irq;
-
-	return 0;
-
-error_free_irq:
-	free_irq(st->spi->irq, indio_dev);
-error_free_trig:
-	iio_trigger_free(st->trig);
-error_ret:
-	return ret;
-}
-
-static void ad7793_remove_trigger(struct iio_dev *indio_dev)
-{
-	struct ad7793_state *st = iio_priv(indio_dev);
-
-	iio_trigger_unregister(st->trig);
-	free_irq(st->spi->irq, indio_dev);
-	iio_trigger_free(st->trig);
-}
-
 static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19,
 					  17, 16, 12, 10, 8, 6, 4};
 
@@ -531,7 +215,7 @@
 			mutex_lock(&indio_dev->mlock);
 			st->mode &= ~AD7793_MODE_RATE(-1);
 			st->mode |= AD7793_MODE_RATE(i);
-			ad7793_write_reg(st, AD7793_REG_MODE,
+			ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
 					 sizeof(st->mode), st->mode);
 			mutex_unlock(&indio_dev->mlock);
 			ret = 0;
@@ -585,26 +269,16 @@
 			   long m)
 {
 	struct ad7793_state *st = iio_priv(indio_dev);
-	int ret, smpl = 0;
+	int ret;
 	unsigned long long scale_uv;
 	bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7793_read(st, chan->address,
-					chan->scan_type.realbits / 8, &smpl);
-		mutex_unlock(&indio_dev->mlock);
-
+		ret = ad_sigma_delta_single_conversion(indio_dev, chan, val);
 		if (ret < 0)
 			return ret;
 
-		*val = (smpl >> chan->scan_type.shift) &
-			((1 << (chan->scan_type.realbits)) - 1);
-
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
@@ -675,17 +349,18 @@
 		ret = -EINVAL;
 		for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
 			if (val2 == st->scale_avail[i][1]) {
+				ret = 0;
 				tmp = st->conf;
 				st->conf &= ~AD7793_CONF_GAIN(-1);
 				st->conf |= AD7793_CONF_GAIN(i);
 
-				if (tmp != st->conf) {
-					ad7793_write_reg(st, AD7793_REG_CONF,
-							 sizeof(st->conf),
-							 st->conf);
-					ad7793_calibrate_all(st);
-				}
-				ret = 0;
+				if (tmp == st->conf)
+					break;
+
+				ad_sd_write_reg(&st->sd, AD7793_REG_CONF,
+						sizeof(st->conf), st->conf);
+				ad7793_calibrate_all(st);
+				break;
 			}
 		break;
 	default:
@@ -696,15 +371,6 @@
 	return ret;
 }
 
-static int ad7793_validate_trigger(struct iio_dev *indio_dev,
-				   struct iio_trigger *trig)
-{
-	if (indio_dev->trig != trig)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev,
 			       struct iio_chan_spec const *chan,
 			       long mask)
@@ -717,172 +383,67 @@
 	.write_raw = &ad7793_write_raw,
 	.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
 	.attrs = &ad7793_attribute_group,
-	.validate_trigger = ad7793_validate_trigger,
+	.validate_trigger = ad_sd_validate_trigger,
 	.driver_module = THIS_MODULE,
 };
 
+#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \
+const struct iio_chan_spec _name##_channels[] = { \
+	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \
+	AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \
+	AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \
+	AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \
+	AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \
+	AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \
+	IIO_CHAN_SOFT_TIMESTAMP(6), \
+}
+
+#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \
+const struct iio_chan_spec _name##_channels[] = { \
+	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
+	AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
+	AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
+	AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \
+	AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \
+	AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \
+	AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
+	AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \
+	AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
+	IIO_CHAN_SOFT_TIMESTAMP(9), \
+}
+
+static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4);
+static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0);
+static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0);
+static DECLARE_AD7795_CHANNELS(ad7794, 16, 32);
+static DECLARE_AD7795_CHANNELS(ad7795, 24, 32);
+
 static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
-	[ID_AD7793] = {
-		.channel[0] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 0,
-			.channel2 = 0,
-			.address = AD7793_CH_AIN1P_AIN1M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 0,
-			.scan_type = IIO_ST('u', 24, 32, 0)
-		},
-		.channel[1] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 1,
-			.channel2 = 1,
-			.address = AD7793_CH_AIN2P_AIN2M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 1,
-			.scan_type = IIO_ST('u', 24, 32, 0)
-		},
-		.channel[2] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 2,
-			.channel2 = 2,
-			.address = AD7793_CH_AIN3P_AIN3M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 2,
-			.scan_type = IIO_ST('u', 24, 32, 0)
-		},
-		.channel[3] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.extend_name = "shorted",
-			.indexed = 1,
-			.channel = 2,
-			.channel2 = 2,
-			.address = AD7793_CH_AIN1M_AIN1M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 3,
-			.scan_type = IIO_ST('u', 24, 32, 0)
-		},
-		.channel[4] = {
-			.type = IIO_TEMP,
-			.indexed = 1,
-			.channel = 0,
-			.address = AD7793_CH_TEMP,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-			.scan_index = 4,
-			.scan_type = IIO_ST('u', 24, 32, 0),
-		},
-		.channel[5] = {
-			.type = IIO_VOLTAGE,
-			.extend_name = "supply",
-			.indexed = 1,
-			.channel = 4,
-			.address = AD7793_CH_AVDD_MONITOR,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 5,
-			.scan_type = IIO_ST('u', 24, 32, 0),
-		},
-		.channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
+	[ID_AD7785] = {
+		.channels = ad7785_channels,
+		.num_channels = ARRAY_SIZE(ad7785_channels),
 	},
 	[ID_AD7792] = {
-		.channel[0] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 0,
-			.channel2 = 0,
-			.address = AD7793_CH_AIN1P_AIN1M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 0,
-			.scan_type = IIO_ST('u', 16, 32, 0)
-		},
-		.channel[1] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 1,
-			.channel2 = 1,
-			.address = AD7793_CH_AIN2P_AIN2M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 1,
-			.scan_type = IIO_ST('u', 16, 32, 0)
-		},
-		.channel[2] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.indexed = 1,
-			.channel = 2,
-			.channel2 = 2,
-			.address = AD7793_CH_AIN3P_AIN3M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 2,
-			.scan_type = IIO_ST('u', 16, 32, 0)
-		},
-		.channel[3] = {
-			.type = IIO_VOLTAGE,
-			.differential = 1,
-			.extend_name = "shorted",
-			.indexed = 1,
-			.channel = 2,
-			.channel2 = 2,
-			.address = AD7793_CH_AIN1M_AIN1M,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 3,
-			.scan_type = IIO_ST('u', 16, 32, 0)
-		},
-		.channel[4] = {
-			.type = IIO_TEMP,
-			.indexed = 1,
-			.channel = 0,
-			.address = AD7793_CH_TEMP,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-			.scan_index = 4,
-			.scan_type = IIO_ST('u', 16, 32, 0),
-		},
-		.channel[5] = {
-			.type = IIO_VOLTAGE,
-			.extend_name = "supply",
-			.indexed = 1,
-			.channel = 4,
-			.address = AD7793_CH_AVDD_MONITOR,
-			.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-			.scan_index = 5,
-			.scan_type = IIO_ST('u', 16, 32, 0),
-		},
-		.channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
+		.channels = ad7792_channels,
+		.num_channels = ARRAY_SIZE(ad7792_channels),
+	},
+	[ID_AD7793] = {
+		.channels = ad7793_channels,
+		.num_channels = ARRAY_SIZE(ad7793_channels),
+	},
+	[ID_AD7794] = {
+		.channels = ad7794_channels,
+		.num_channels = ARRAY_SIZE(ad7794_channels),
+	},
+	[ID_AD7795] = {
+		.channels = ad7795_channels,
+		.num_channels = ARRAY_SIZE(ad7795_channels),
 	},
 };
 
 static int __devinit ad7793_probe(struct spi_device *spi)
 {
-	struct ad7793_platform_data *pdata = spi->dev.platform_data;
+	const struct ad7793_platform_data *pdata = spi->dev.platform_data;
 	struct ad7793_state *st;
 	struct iio_dev *indio_dev;
 	int ret, voltage_uv = 0;
@@ -903,6 +464,8 @@
 
 	st = iio_priv(indio_dev);
 
+	ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
+
 	st->reg = regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
@@ -915,8 +478,6 @@
 	st->chip_info =
 		&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-	st->pdata = pdata;
-
 	if (pdata && pdata->vref_mv)
 		st->int_vref_mv = pdata->vref_mv;
 	else if (voltage_uv)
@@ -925,26 +486,19 @@
 		st->int_vref_mv = 1170; /* Build-in ref */
 
 	spi_set_drvdata(spi, indio_dev);
-	st->spi = spi;
 
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channel;
-	indio_dev->num_channels = 7;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = st->chip_info->num_channels;
 	indio_dev->info = &ad7793_info;
 
-	init_waitqueue_head(&st->wq_data_avail);
-
-	ret = ad7793_register_ring_funcs_and_init(indio_dev);
+	ret = ad_sd_setup_buffer_and_trigger(indio_dev);
 	if (ret)
 		goto error_disable_reg;
 
-	ret = ad7793_probe_trigger(indio_dev);
-	if (ret)
-		goto error_unreg_ring;
-
-	ret = ad7793_setup(st);
+	ret = ad7793_setup(indio_dev, pdata);
 	if (ret)
 		goto error_remove_trigger;
 
@@ -955,9 +509,7 @@
 	return 0;
 
 error_remove_trigger:
-	ad7793_remove_trigger(indio_dev);
-error_unreg_ring:
-	ad7793_ring_cleanup(indio_dev);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
@@ -970,14 +522,13 @@
 	return ret;
 }
 
-static int ad7793_remove(struct spi_device *spi)
+static int __devexit ad7793_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ad7793_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	ad7793_remove_trigger(indio_dev);
-	ad7793_ring_cleanup(indio_dev);
+	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
@@ -990,8 +541,11 @@
 }
 
 static const struct spi_device_id ad7793_id[] = {
+	{"ad7785", ID_AD7785},
 	{"ad7792", ID_AD7792},
 	{"ad7793", ID_AD7793},
+	{"ad7794", ID_AD7794},
+	{"ad7795", ID_AD7795},
 	{}
 };
 MODULE_DEVICE_TABLE(spi, ad7793_id);
@@ -1008,5 +562,5 @@
 module_spi_driver(ad7793_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD7792/3 ADC");
+MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7793.h b/drivers/staging/iio/adc/ad7793.h
index 64f7d41..8fdd450a 100644
--- a/drivers/staging/iio/adc/ad7793.h
+++ b/drivers/staging/iio/adc/ad7793.h
@@ -41,6 +41,7 @@
 
 /* Mode Register Bit Designations (AD7793_REG_MODE) */
 #define AD7793_MODE_SEL(x)	(((x) & 0x7) << 13) /* Operation Mode Select */
+#define AD7793_MODE_SEL_MASK	(0x7 << 13) /* Operation Mode Select mask */
 #define AD7793_MODE_CLKSRC(x)	(((x) & 0x3) << 6) /* ADC Clock Source Select */
 #define AD7793_MODE_RATE(x)	((x) & 0xF) /* Filter Update Rate Select */
 
@@ -69,7 +70,8 @@
 #define AD7793_CONF_GAIN(x)	(((x) & 0x7) << 8) /* Gain Select */
 #define AD7793_CONF_REFSEL	(1 << 7) /* INT/EXT Reference Select */
 #define AD7793_CONF_BUF		(1 << 4) /* Buffered Mode Enable */
-#define AD7793_CONF_CHAN(x)	((x) & 0x7) /* Channel select */
+#define AD7793_CONF_CHAN(x)	((x) & 0xf) /* Channel select */
+#define AD7793_CONF_CHAN_MASK	0xf /* Channel select mask */
 
 #define AD7793_CH_AIN1P_AIN1M	0 /* AIN1(+) - AIN1(-) */
 #define AD7793_CH_AIN2P_AIN2M	1 /* AIN2(+) - AIN2(-) */
@@ -78,9 +80,15 @@
 #define AD7793_CH_TEMP		6 /* Temp Sensor */
 #define AD7793_CH_AVDD_MONITOR	7 /* AVDD Monitor */
 
+#define AD7795_CH_AIN4P_AIN4M	4 /* AIN4(+) - AIN4(-) */
+#define AD7795_CH_AIN5P_AIN5M	5 /* AIN5(+) - AIN5(-) */
+#define AD7795_CH_AIN6P_AIN6M	6 /* AIN6(+) - AIN6(-) */
+#define AD7795_CH_AIN1M_AIN1M	8 /* AIN1(-) - AIN1(-) */
+
 /* ID Register Bit Designations (AD7793_REG_ID) */
 #define AD7792_ID		0xA
 #define AD7793_ID		0xB
+#define AD7795_ID		0xF
 #define AD7793_ID_MASK		0xF
 
 /* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
index 397b849..5517905 100644
--- a/drivers/staging/iio/adc/ad7887_core.c
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -219,7 +219,7 @@
 	return ret;
 }
 
-static int ad7887_remove(struct spi_device *spi)
+static int __devexit ad7887_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ad7887_state *st = iio_priv(indio_dev);
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index c76fdb5..b39923b 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -95,7 +95,7 @@
 		memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
 		       &time_ns, sizeof(time_ns));
 
-	indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, buf);
 done:
 	kfree(buf);
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 858a685..86026d9 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -35,7 +35,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ad799x_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	s64 time_ns;
 	__u8 *rxbuf;
 	int b_sent;
@@ -78,7 +77,7 @@
 		memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
 			&time_ns, sizeof(time_ns));
 
-	ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, rxbuf);
 done:
 	kfree(rxbuf);
 out:
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index 348d051..7e9bd00 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -108,7 +108,7 @@
 	.scan_index = _index,				\
 }
 
-static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
+static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
 	LPC32XX_ADC_CHANNEL(0),
 	LPC32XX_ADC_CHANNEL(1),
 	LPC32XX_ADC_CHANNEL(2),
diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h
index 2cd0112..c746918 100644
--- a/drivers/staging/iio/adc/max1363.h
+++ b/drivers/staging/iio/adc/max1363.h
@@ -100,7 +100,7 @@
  */
 struct max1363_chip_info {
 	const struct iio_info		*info;
-	struct iio_chan_spec *channels;
+	const struct iio_chan_spec *channels;
 	int num_channels;
 	const enum max1363_modes	*mode_list;
 	enum max1363_modes		default_mode;
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index 6799ce2..d7b4ffc 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -335,12 +335,12 @@
 	IIO_CHAN_SOFT_TIMESTAMP(8)			\
 	}
 
-static struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
-static struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
-static struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
-static struct iio_chan_spec max1361_channels[] =
+static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
+static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
+static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
+static const struct iio_chan_spec max1361_channels[] =
 	MAX1363_4X_CHANS(10, MAX1363_EV_M);
-static struct iio_chan_spec max1363_channels[] =
+static const struct iio_chan_spec max1363_channels[] =
 	MAX1363_4X_CHANS(12, MAX1363_EV_M);
 
 /* Applies to max1236, max1237 */
@@ -392,9 +392,9 @@
 	MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0),	\
 	IIO_CHAN_SOFT_TIMESTAMP(24)			\
 	}
-static struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
-static struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
-static struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12);
+static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
+static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
+static const struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12);
 
 static const enum max1363_modes max11607_mode_list[] = {
 	_s0, _s1, _s2, _s3,
@@ -433,9 +433,9 @@
 	MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0),	\
 	IIO_CHAN_SOFT_TIMESTAMP(16)			\
 }
-static struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
-static struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10);
-static struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12);
+static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
+static const struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10);
+static const struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12);
 
 static const enum max1363_modes max11644_mode_list[] = {
 	_s0, _s1, s0to1, d0m1, d1m0,
@@ -449,8 +449,8 @@
 	IIO_CHAN_SOFT_TIMESTAMP(4)			\
 	}
 
-static struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
-static struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
+static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
+static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
 
 enum { max1361,
        max1362,
@@ -1367,7 +1367,7 @@
 	return ret;
 }
 
-static int max1363_remove(struct i2c_client *client)
+static int __devexit max1363_remove(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct max1363_state *st = iio_priv(indio_dev);
@@ -1434,11 +1434,11 @@
 		.name = "max1363",
 	},
 	.probe = max1363_probe,
-	.remove = max1363_remove,
+	.remove = __devexit_p(max1363_remove),
 	.id_table = max1363_id,
 };
 module_i2c_driver(max1363_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("Maxim 1363 ADC");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 774ae1b..5f74f3b 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -80,7 +80,7 @@
 
 	if (indio_dev->scan_timestamp)
 		memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
-	iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, rxbuf);
 
 done_free:
 	kfree(rxbuf);
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
new file mode 100644
index 0000000..ca7c1fa
--- /dev/null
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -0,0 +1,590 @@
+/*
+ * Freescale i.MX28 LRADC driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/stmp_device.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+
+#include <mach/mxs.h>
+#include <mach/common.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define DRIVER_NAME		"mxs-lradc"
+
+#define LRADC_MAX_DELAY_CHANS	4
+#define LRADC_MAX_MAPPED_CHANS	8
+#define LRADC_MAX_TOTAL_CHANS	16
+
+#define LRADC_DELAY_TIMER_HZ	2000
+
+/*
+ * Make this runtime configurable if necessary. Currently, if the buffered mode
+ * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before
+ * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000)
+ * seconds. The result is that the samples arrive every 500mS.
+ */
+#define LRADC_DELAY_TIMER_PER	200
+#define LRADC_DELAY_TIMER_LOOP	5
+
+static const char * const mxs_lradc_irq_name[] = {
+	"mxs-lradc-touchscreen",
+	"mxs-lradc-thresh0",
+	"mxs-lradc-thresh1",
+	"mxs-lradc-channel0",
+	"mxs-lradc-channel1",
+	"mxs-lradc-channel2",
+	"mxs-lradc-channel3",
+	"mxs-lradc-channel4",
+	"mxs-lradc-channel5",
+	"mxs-lradc-channel6",
+	"mxs-lradc-channel7",
+	"mxs-lradc-button0",
+	"mxs-lradc-button1",
+};
+
+struct mxs_lradc_chan {
+	uint8_t				slot;
+	uint8_t				flags;
+};
+
+struct mxs_lradc {
+	struct device		*dev;
+	void __iomem		*base;
+	int			irq[13];
+
+	uint32_t		*buffer;
+	struct iio_trigger	*trig;
+
+	struct mutex		lock;
+
+	uint8_t			enable;
+
+	struct completion	completion;
+};
+
+#define	LRADC_CTRL0				0x00
+#define LRADC_CTRL0_TOUCH_DETECT_ENABLE		(1 << 23)
+#define LRADC_CTRL0_TOUCH_SCREEN_TYPE		(1 << 22)
+
+#define	LRADC_CTRL1				0x10
+#define	LRADC_CTRL1_LRADC_IRQ(n)		(1 << (n))
+#define	LRADC_CTRL1_LRADC_IRQ_MASK		0x1fff
+#define	LRADC_CTRL1_LRADC_IRQ_EN(n)		(1 << ((n) + 16))
+#define	LRADC_CTRL1_LRADC_IRQ_EN_MASK		(0x1fff << 16)
+
+#define	LRADC_CTRL2				0x20
+#define	LRADC_CTRL2_TEMPSENSE_PWD		(1 << 15)
+
+#define	LRADC_CH(n)				(0x50 + (0x10 * (n)))
+#define	LRADC_CH_ACCUMULATE			(1 << 29)
+#define	LRADC_CH_NUM_SAMPLES_MASK		(0x1f << 24)
+#define	LRADC_CH_NUM_SAMPLES_OFFSET		24
+#define	LRADC_CH_VALUE_MASK			0x3ffff
+#define	LRADC_CH_VALUE_OFFSET			0
+
+#define	LRADC_DELAY(n)				(0xd0 + (0x10 * (n)))
+#define	LRADC_DELAY_TRIGGER_LRADCS_MASK		(0xff << 24)
+#define	LRADC_DELAY_TRIGGER_LRADCS_OFFSET	24
+#define	LRADC_DELAY_KICK			(1 << 20)
+#define	LRADC_DELAY_TRIGGER_DELAYS_MASK		(0xf << 16)
+#define	LRADC_DELAY_TRIGGER_DELAYS_OFFSET	16
+#define	LRADC_DELAY_LOOP_COUNT_MASK		(0x1f << 11)
+#define	LRADC_DELAY_LOOP_COUNT_OFFSET		11
+#define	LRADC_DELAY_DELAY_MASK			0x7ff
+#define	LRADC_DELAY_DELAY_OFFSET		0
+
+#define	LRADC_CTRL4				0x140
+#define	LRADC_CTRL4_LRADCSELECT_MASK(n)		(0xf << ((n) * 4))
+#define	LRADC_CTRL4_LRADCSELECT_OFFSET(n)	((n) * 4)
+
+/*
+ * Raw I/O operations
+ */
+static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
+			const struct iio_chan_spec *chan,
+			int *val, int *val2, long m)
+{
+	struct mxs_lradc *lradc = iio_priv(iio_dev);
+	int ret;
+
+	if (m != IIO_CHAN_INFO_RAW)
+		return -EINVAL;
+
+	/* Check for invalid channel */
+	if (chan->channel > LRADC_MAX_TOTAL_CHANS)
+		return -EINVAL;
+
+	/*
+	 * See if there is no buffered operation in progess. If there is, simply
+	 * bail out. This can be improved to support both buffered and raw IO at
+	 * the same time, yet the code becomes horribly complicated. Therefore I
+	 * applied KISS principle here.
+	 */
+	ret = mutex_trylock(&lradc->lock);
+	if (!ret)
+		return -EBUSY;
+
+	INIT_COMPLETION(lradc->completion);
+
+	/*
+	 * No buffered operation in progress, map the channel and trigger it.
+	 * Virtual channel 0 is always used here as the others are always not
+	 * used if doing raw sampling.
+	 */
+	writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+	writel(chan->channel, lradc->base + LRADC_CTRL4);
+	writel(0, lradc->base + LRADC_CH(0));
+
+	/* Enable the IRQ and start sampling the channel. */
+	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+	writel(1 << 0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+	/* Wait for completion on the channel, 1 second max. */
+	ret = wait_for_completion_killable_timeout(&lradc->completion, HZ);
+	if (!ret)
+		ret = -ETIMEDOUT;
+	if (ret < 0)
+		goto err;
+
+	/* Read the data. */
+	*val = readl(lradc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK;
+	ret = IIO_VAL_INT;
+
+err:
+	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	mutex_unlock(&lradc->lock);
+
+	return ret;
+}
+
+static const struct iio_info mxs_lradc_iio_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= mxs_lradc_read_raw,
+};
+
+/*
+ * IRQ Handling
+ */
+static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
+{
+	struct iio_dev *iio = data;
+	struct mxs_lradc *lradc = iio_priv(iio);
+	unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+
+	if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK))
+		return IRQ_NONE;
+
+	/*
+	 * Touchscreen IRQ handling code shall probably have priority
+	 * and therefore shall be placed here.
+	 */
+
+	if (iio_buffer_enabled(iio))
+		iio_trigger_poll(iio->trig, iio_get_time_ns());
+	else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
+		complete(&lradc->completion);
+
+	writel(reg & LRADC_CTRL1_LRADC_IRQ_MASK,
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Trigger handling
+ */
+static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *iio = pf->indio_dev;
+	struct mxs_lradc *lradc = iio_priv(iio);
+	struct iio_buffer *buffer = iio->buffer;
+	const uint32_t chan_value = LRADC_CH_ACCUMULATE |
+		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+	int i, j = 0;
+
+	for_each_set_bit(i, iio->active_scan_mask, iio->masklength) {
+		lradc->buffer[j] = readl(lradc->base + LRADC_CH(j));
+		writel(chan_value, lradc->base + LRADC_CH(j));
+		lradc->buffer[j] &= LRADC_CH_VALUE_MASK;
+		lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP;
+		j++;
+	}
+
+	if (iio->scan_timestamp) {
+		s64 *timestamp = (s64 *)((u8 *)lradc->buffer +
+					ALIGN(j, sizeof(s64)));
+		*timestamp = pf->timestamp;
+	}
+
+	iio_push_to_buffer(buffer, (u8 *)lradc->buffer);
+
+	iio_trigger_notify_done(iio->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *iio = trig->private_data;
+	struct mxs_lradc *lradc = iio_priv(iio);
+	const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
+
+	writel(LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + st);
+
+	return 0;
+}
+
+static const struct iio_trigger_ops mxs_lradc_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &mxs_lradc_configure_trigger,
+};
+
+static int mxs_lradc_trigger_init(struct iio_dev *iio)
+{
+	int ret;
+	struct iio_trigger *trig;
+
+	trig = iio_trigger_alloc("%s-dev%i", iio->name, iio->id);
+	if (trig == NULL)
+		return -ENOMEM;
+
+	trig->dev.parent = iio->dev.parent;
+	trig->private_data = iio;
+	trig->ops = &mxs_lradc_trigger_ops;
+
+	ret = iio_trigger_register(trig);
+	if (ret) {
+		iio_trigger_free(trig);
+		return ret;
+	}
+
+	iio->trig = trig;
+
+	return 0;
+}
+
+static void mxs_lradc_trigger_remove(struct iio_dev *iio)
+{
+	iio_trigger_unregister(iio->trig);
+	iio_trigger_free(iio->trig);
+}
+
+static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
+{
+	struct mxs_lradc *lradc = iio_priv(iio);
+	struct iio_buffer *buffer = iio->buffer;
+	int ret = 0, chan, ofs = 0, enable = 0;
+	uint32_t ctrl4 = 0;
+	uint32_t ctrl1_irq = 0;
+	const uint32_t chan_value = LRADC_CH_ACCUMULATE |
+		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+	const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS);
+
+	if (!len)
+		return -EINVAL;
+
+	/*
+	 * Lock the driver so raw access can not be done during buffered
+	 * operation. This simplifies the code a lot.
+	 */
+	ret = mutex_trylock(&lradc->lock);
+	if (!ret)
+		return -EBUSY;
+
+	lradc->buffer = kmalloc(len * sizeof(*lradc->buffer), GFP_KERNEL);
+	if (!lradc->buffer) {
+		ret = -ENOMEM;
+		goto err_mem;
+	}
+
+	ret = iio_sw_buffer_preenable(iio);
+	if (ret < 0)
+		goto err_buf;
+
+	writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+	for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) {
+		ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
+		ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
+		writel(chan_value, lradc->base + LRADC_CH(ofs));
+		enable |= 1 << ofs;
+		ofs++;
+	};
+
+	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+		lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+
+	writel(ctrl4, lradc->base + LRADC_CTRL4);
+	writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+
+	writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
+		lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET);
+
+	return 0;
+
+err_buf:
+	kfree(lradc->buffer);
+err_mem:
+	mutex_unlock(&lradc->lock);
+	return ret;
+}
+
+static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
+{
+	struct mxs_lradc *lradc = iio_priv(iio);
+
+	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+		lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+
+	writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	kfree(lradc->buffer);
+	mutex_unlock(&lradc->lock);
+
+	return 0;
+}
+
+static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
+					const unsigned long *mask)
+{
+	const int mw = bitmap_weight(mask, iio->masklength);
+
+	return mw <= LRADC_MAX_MAPPED_CHANS;
+}
+
+static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
+	.preenable = &mxs_lradc_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+	.postdisable = &mxs_lradc_buffer_postdisable,
+	.validate_scan_mask = &mxs_lradc_validate_scan_mask,
+};
+
+/*
+ * Driver initialization
+ */
+
+#define MXS_ADC_CHAN(idx, chan_type) {				\
+	.type = (chan_type),					\
+	.indexed = 1,						\
+	.scan_index = (idx),					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,		\
+	.channel = (idx),					\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = 18,					\
+		.storagebits = 32,				\
+	},							\
+}
+
+static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
+	MXS_ADC_CHAN(0, IIO_VOLTAGE),
+	MXS_ADC_CHAN(1, IIO_VOLTAGE),
+	MXS_ADC_CHAN(2, IIO_VOLTAGE),
+	MXS_ADC_CHAN(3, IIO_VOLTAGE),
+	MXS_ADC_CHAN(4, IIO_VOLTAGE),
+	MXS_ADC_CHAN(5, IIO_VOLTAGE),
+	MXS_ADC_CHAN(6, IIO_VOLTAGE),
+	MXS_ADC_CHAN(7, IIO_VOLTAGE),	/* VBATT */
+	MXS_ADC_CHAN(8, IIO_TEMP),	/* Temp sense 0 */
+	MXS_ADC_CHAN(9, IIO_TEMP),	/* Temp sense 1 */
+	MXS_ADC_CHAN(10, IIO_VOLTAGE),	/* VDDIO */
+	MXS_ADC_CHAN(11, IIO_VOLTAGE),	/* VTH */
+	MXS_ADC_CHAN(12, IIO_VOLTAGE),	/* VDDA */
+	MXS_ADC_CHAN(13, IIO_VOLTAGE),	/* VDDD */
+	MXS_ADC_CHAN(14, IIO_VOLTAGE),	/* VBG */
+	MXS_ADC_CHAN(15, IIO_VOLTAGE),	/* VDD5V */
+};
+
+static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
+{
+	int i;
+	const uint32_t cfg =
+		(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
+
+	stmp_reset_block(lradc->base);
+
+	for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
+		writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)),
+			lradc->base + LRADC_DELAY(i));
+
+	/* Start internal temperature sensing. */
+	writel(0, lradc->base + LRADC_CTRL2);
+}
+
+static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
+{
+	int i;
+
+	writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+		lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
+		writel(0, lradc->base + LRADC_DELAY(i));
+}
+
+static int __devinit mxs_lradc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxs_lradc *lradc;
+	struct iio_dev *iio;
+	struct resource *iores;
+	int ret = 0;
+	int i;
+
+	/* Allocate the IIO device. */
+	iio = iio_device_alloc(sizeof(*lradc));
+	if (!iio) {
+		dev_err(dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+
+	lradc = iio_priv(iio);
+
+	/* Grab the memory area */
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lradc->dev = &pdev->dev;
+	lradc->base = devm_request_and_ioremap(dev, iores);
+	if (!lradc->base) {
+		ret = -EADDRNOTAVAIL;
+		goto err_addr;
+	}
+
+	/* Grab all IRQ sources */
+	for (i = 0; i < 13; i++) {
+		lradc->irq[i] = platform_get_irq(pdev, i);
+		if (lradc->irq[i] < 0) {
+			ret = -EINVAL;
+			goto err_addr;
+		}
+
+		ret = devm_request_irq(dev, lradc->irq[i],
+					mxs_lradc_handle_irq, 0,
+					mxs_lradc_irq_name[i], iio);
+		if (ret)
+			goto err_addr;
+	}
+
+	platform_set_drvdata(pdev, iio);
+
+	init_completion(&lradc->completion);
+	mutex_init(&lradc->lock);
+
+	iio->name = pdev->name;
+	iio->dev.parent = &pdev->dev;
+	iio->info = &mxs_lradc_iio_info;
+	iio->modes = INDIO_DIRECT_MODE;
+	iio->channels = mxs_lradc_chan_spec;
+	iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec);
+
+	ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
+				&mxs_lradc_trigger_handler,
+				&mxs_lradc_buffer_ops);
+	if (ret)
+		goto err_addr;
+
+	ret = mxs_lradc_trigger_init(iio);
+	if (ret)
+		goto err_trig;
+
+	/* Register IIO device. */
+	ret = iio_device_register(iio);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device\n");
+		goto err_dev;
+	}
+
+	/* Configure the hardware. */
+	mxs_lradc_hw_init(lradc);
+
+	return 0;
+
+err_dev:
+	mxs_lradc_trigger_remove(iio);
+err_trig:
+	iio_triggered_buffer_cleanup(iio);
+err_addr:
+	iio_device_free(iio);
+	return ret;
+}
+
+static int __devexit mxs_lradc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iio = platform_get_drvdata(pdev);
+	struct mxs_lradc *lradc = iio_priv(iio);
+
+	mxs_lradc_hw_stop(lradc);
+
+	iio_device_unregister(iio);
+	iio_triggered_buffer_cleanup(iio);
+	mxs_lradc_trigger_remove(iio);
+	iio_device_free(iio);
+
+	return 0;
+}
+
+static const struct of_device_id mxs_lradc_dt_ids[] = {
+	{ .compatible = "fsl,imx28-lradc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+
+static struct platform_driver mxs_lradc_driver = {
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = mxs_lradc_dt_ids,
+	},
+	.probe	= mxs_lradc_probe,
+	.remove	= __devexit_p(mxs_lradc_remove),
+};
+
+module_platform_driver(mxs_lradc_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
index 64d630e..0b83e2e 100644
--- a/drivers/staging/iio/adc/spear_adc.c
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -189,7 +189,7 @@
 	},						\
 }
 
-static struct iio_chan_spec spear_adc_iio_channels[] = {
+static const struct iio_chan_spec spear_adc_iio_channels[] = {
 	SPEAR_ADC_CHAN(0),
 	SPEAR_ADC_CHAN(1),
 	SPEAR_ADC_CHAN(2),
@@ -330,36 +330,30 @@
 		goto errout3;
 	}
 
-	ret = clk_prepare(info->clk);
-	if (ret) {
-		dev_err(dev, "failed preparing clock\n");
-		goto errout4;
-	}
-
-	ret = clk_enable(info->clk);
+	ret = clk_prepare_enable(info->clk);
 	if (ret) {
 		dev_err(dev, "failed enabling clock\n");
-		goto errout5;
+		goto errout4;
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if ((irq < 0) || (irq >= NR_IRQS)) {
 		dev_err(dev, "failed getting interrupt resource\n");
 		ret = -EINVAL;
-		goto errout6;
+		goto errout5;
 	}
 
 	ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
 	if (ret < 0) {
 		dev_err(dev, "failed requesting interrupt\n");
-		goto errout6;
+		goto errout5;
 	}
 
 	if (of_property_read_u32(np, "sampling-frequency",
 				 &info->sampling_freq)) {
 		dev_err(dev, "sampling-frequency missing in DT\n");
 		ret = -EINVAL;
-		goto errout6;
+		goto errout5;
 	}
 
 	/*
@@ -389,16 +383,14 @@
 
 	ret = iio_device_register(iodev);
 	if (ret)
-		goto errout6;
+		goto errout5;
 
 	dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
 
 	return 0;
 
-errout6:
-	clk_disable(info->clk);
 errout5:
-	clk_unprepare(info->clk);
+	clk_disable_unprepare(info->clk);
 errout4:
 	clk_put(info->clk);
 errout3:
@@ -416,8 +408,7 @@
 
 	iio_device_unregister(iodev);
 	platform_set_drvdata(pdev, NULL);
-	clk_disable(info->clk);
-	clk_unprepare(info->clk);
+	clk_disable_unprepare(info->clk);
 	clk_put(info->clk);
 	iounmap(info->adc_base_spear6xx);
 	iio_device_free(iodev);
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index 9931e206..87151a7c 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -184,7 +184,7 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int adis16060_r_remove(struct spi_device *spi)
+static int __devexit adis16060_r_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
 	iio_device_free(spi_get_drvdata(spi));
@@ -210,7 +210,7 @@
 	return ret;
 }
 
-static int adis16060_w_remove(struct spi_device *spi)
+static int __devexit adis16060_w_remove(struct spi_device *spi)
 {
 	return 0;
 }
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 345e4fa..a739025 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -177,7 +177,7 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int adis16080_remove(struct spi_device *spi)
+static int __devexit adis16080_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
 	iio_device_free(spi_get_drvdata(spi));
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index bf61cd0..fbf96b0 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -154,7 +154,7 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int adis16130_remove(struct spi_device *spi)
+static int __devexit adis16130_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
 	iio_device_free(spi_get_drvdata(spi));
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index eb8e9d6..9571c03 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -700,24 +700,18 @@
 	return ret;
 }
 
-static int adis16260_remove(struct spi_device *spi)
+static int __devexit adis16260_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-
-	ret = adis16260_stop_device(indio_dev);
-	if (ret)
-		goto err_ret;
-
+	adis16260_stop_device(indio_dev);
 	adis16260_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16260_unconfigure_ring(indio_dev);
 	iio_device_free(indio_dev);
 
-err_ret:
-	return ret;
+	return 0;
 }
 
 /*
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index eeee8e7..e294cb4 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -62,7 +62,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adis16260_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
 	int i = 0;
 	s16 *data;
 
@@ -82,7 +81,7 @@
 	if (indio_dev->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
 
 	kfree(data);
 done:
diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c
index 6513119..d93527d 100644
--- a/drivers/staging/iio/gyro/adxrs450_core.c
+++ b/drivers/staging/iio/gyro/adxrs450_core.c
@@ -409,7 +409,7 @@
 	return ret;
 }
 
-static int adxrs450_remove(struct spi_device *spi)
+static int __devexit adxrs450_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
 	iio_device_free(spi_get_drvdata(spi));
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index 0cd4fe9..74e24e8 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -216,6 +216,6 @@
 }
 module_exit(iio_dummy_evgen_exit);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("IIO dummy driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c
index 27d27ec..5d49122 100644
--- a/drivers/staging/iio/iio_hwmon.c
+++ b/drivers/staging/iio/iio_hwmon.c
@@ -42,40 +42,17 @@
 				  struct device_attribute *attr,
 				  char *buf)
 {
-	long result;
-	int val, ret, scaleint, scalepart;
+	int result;
+	int ret;
 	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 	struct iio_hwmon_state *state = dev_get_drvdata(dev);
 
-	/*
-	 * No locking between this pair, so theoretically possible
-	 * the scale has changed.
-	 */
-	ret = iio_read_channel_raw(&state->channels[sattr->index],
-				      &val);
+	ret = iio_read_channel_processed(&state->channels[sattr->index],
+					&result);
 	if (ret < 0)
 		return ret;
 
-	ret = iio_read_channel_scale(&state->channels[sattr->index],
-					&scaleint, &scalepart);
-	if (ret < 0)
-		return ret;
-	switch (ret) {
-	case IIO_VAL_INT:
-		result = val * scaleint;
-		break;
-	case IIO_VAL_INT_PLUS_MICRO:
-		result = (s64)val * (s64)scaleint +
-			div_s64((s64)val * (s64)scalepart, 1000000LL);
-		break;
-	case IIO_VAL_INT_PLUS_NANO:
-		result = (s64)val * (s64)scaleint +
-			div_s64((s64)val * (s64)scalepart, 1000000000LL);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return sprintf(buf, "%ld\n", result);
+	return sprintf(buf, "%d\n", result);
 }
 
 static void iio_hwmon_free_attrs(struct iio_hwmon_state *st)
@@ -215,18 +192,8 @@
 	.remove = __devexit_p(iio_hwmon_remove),
 };
 
-static int iio_inkern_init(void)
-{
-	return platform_driver_register(&iio_hwmon_driver);
-}
-module_init(iio_inkern_init);
+module_platform_driver(iio_hwmon_driver);
 
-static void iio_inkern_exit(void)
-{
-	platform_driver_unregister(&iio_hwmon_driver);
-}
-module_exit(iio_inkern_exit);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("IIO to hwmon driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index 155a49a..dc6c728 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -63,7 +63,7 @@
  * This array of structures tells the IIO core about what the device
  * actually provides for a given channel.
  */
-static struct iio_chan_spec iio_dummy_channels[] = {
+static const struct iio_chan_spec iio_dummy_channels[] = {
 	/* indexed ADC channel in_voltage0_raw etc */
 	{
 		.type = IIO_VOLTAGE,
@@ -445,26 +445,20 @@
 	if (ret < 0)
 		goto error_free_device;
 
-	/* Configure buffered capture support. */
-	ret = iio_simple_dummy_configure_buffer(indio_dev);
+	/*
+	 * Configure buffered capture support and register the channels with the
+	 * buffer, but avoid the output channel being registered by reducing the
+	 * number of channels by 1.
+	 */
+	ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5);
 	if (ret < 0)
 		goto error_unregister_events;
 
-	/*
-	 * Register the channels with the buffer, but avoid the output
-	 * channel being registered by reducing the number of channels by 1.
-	 */
-	ret = iio_buffer_register(indio_dev, iio_dummy_channels, 5);
+	ret = iio_device_register(indio_dev);
 	if (ret < 0)
 		goto error_unconfigure_buffer;
 
-	ret = iio_device_register(indio_dev);
-	if (ret < 0)
-		goto error_unregister_buffer;
-
 	return 0;
-error_unregister_buffer:
-	iio_buffer_unregister(indio_dev);
 error_unconfigure_buffer:
 	iio_simple_dummy_unconfigure_buffer(indio_dev);
 error_unregister_events:
@@ -499,7 +493,6 @@
 	/* Device specific code to power down etc */
 
 	/* Buffered capture related cleanup */
-	iio_buffer_unregister(indio_dev);
 	iio_simple_dummy_unconfigure_buffer(indio_dev);
 
 	ret = iio_simple_dummy_events_unregister(indio_dev);
@@ -530,6 +523,7 @@
 		instances = 1;
 		return -EINVAL;
 	}
+
 	/* Fake a bus */
 	iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
 				 GFP_KERNEL);
@@ -558,6 +552,6 @@
 }
 module_exit(iio_dummy_exit);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("IIO dummy driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h
index 53975d9..c9e8702 100644
--- a/drivers/staging/iio/iio_simple_dummy.h
+++ b/drivers/staging/iio/iio_simple_dummy.h
@@ -95,10 +95,12 @@
 };
 
 #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *channels, unsigned int num_channels);
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
 #else
-static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *channels, unsigned int num_channels)
 {
 	return 0;
 };
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index bd628de..697d970 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -87,7 +87,7 @@
 	if (indio_dev->scan_timestamp)
 		*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
 			= iio_get_time_ns();
-	buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+	iio_push_to_buffer(buffer, (u8 *)data);
 
 	kfree(data);
 
@@ -126,7 +126,8 @@
 	.predisable = &iio_triggered_buffer_predisable,
 };
 
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *channels, unsigned int num_channels)
 {
 	int ret;
 	struct iio_buffer *buffer;
@@ -182,8 +183,15 @@
 	 * driven by a trigger.
 	 */
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+	ret = iio_buffer_register(indio_dev, channels, num_channels);
+	if (ret)
+		goto error_dealloc_pollfunc;
+
 	return 0;
 
+error_dealloc_pollfunc:
+	iio_dealloc_pollfunc(indio_dev->pollfunc);
 error_free_buffer:
 	iio_kfifo_free(indio_dev->buffer);
 error_ret:
@@ -197,6 +205,7 @@
  */
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
 {
+	iio_buffer_unregister(indio_dev);
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
 	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index a8e51bc0..de21d47 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -108,7 +108,7 @@
 	.vref_mv = 3300,
 };
 
-static struct iio_chan_spec ad5933_channels[] = {
+static const struct iio_chan_spec ad5933_channels[] = {
 	{
 		.type = IIO_TEMP,
 		.indexed = 1,
@@ -678,7 +678,7 @@
 			buf[0] = be16_to_cpu(buf[0]);
 		}
 		/* save datum to the ring */
-		ring->access->store_to(ring, (u8 *)buf, iio_get_time_ns());
+		iio_push_to_buffer(ring, (u8 *)buf);
 	} else {
 		/* no data available - try again later */
 		schedule_delayed_work(&st->work, st->poll_time_jiffies);
diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h
index 9dd9f14..d59d7ac 100644
--- a/drivers/staging/iio/imu/adis16400.h
+++ b/drivers/staging/iio/imu/adis16400.h
@@ -5,7 +5,7 @@
  *		3d 2.5gauss magnetometers via SPI
  *
  * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
- * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
  *
  * Loosely based upon lis3l02dq.h
  *
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index a618327..b302c9b 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -5,7 +5,7 @@
  *		3d Magnetometers via SPI
  *
  * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
- * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
  * Copyright (c) 2011 Analog Devices Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -612,7 +612,7 @@
 	}
 }
 
-static struct iio_chan_spec adis16400_channels[] = {
+static const struct iio_chan_spec adis16400_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -742,7 +742,7 @@
 	IIO_CHAN_SOFT_TIMESTAMP(12)
 };
 
-static struct iio_chan_spec adis16350_channels[] = {
+static const struct iio_chan_spec adis16350_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -867,7 +867,7 @@
 	IIO_CHAN_SOFT_TIMESTAMP(11)
 };
 
-static struct iio_chan_spec adis16300_channels[] = {
+static const struct iio_chan_spec adis16300_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -1206,15 +1206,12 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int adis16400_remove(struct spi_device *spi)
+static int __devexit adis16400_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev =  spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-	ret = adis16400_stop_device(indio_dev);
-	if (ret)
-		goto err_ret;
+	adis16400_stop_device(indio_dev);
 
 	adis16400_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
@@ -1222,9 +1219,6 @@
 	iio_device_free(indio_dev);
 
 	return 0;
-
-err_ret:
-	return ret;
 }
 
 static const struct spi_device_id adis16400_id[] = {
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index beec650..260bdd1 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -150,7 +150,7 @@
 	/* Guaranteed to be aligned with 8 byte boundary */
 	if (ring->scan_timestamp)
 		*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
-	ring->access->store_to(indio_dev->buffer, (u8 *) data, pf->timestamp);
+	iio_push_to_buffer(ring, (u8 *) data);
 
 done:
 	kfree(data);
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 31d22f5..6ee5567 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -63,6 +63,7 @@
 	struct regmap		*regmap;
 	struct mutex		lock;
 	unsigned int		lux_scale;
+	unsigned int		lux_uscale;
 	unsigned int		range;
 	unsigned int		adc_bit;
 	int			prox_scheme;
@@ -145,13 +146,22 @@
 static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
 {
 	int lux_data;
+	unsigned int data_x_range, lux_unshifted;
 
 	lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
 
 	if (lux_data < 0)
 		return lux_data;
 
-	*lux = (lux_data * chip->range * chip->lux_scale) >> chip->adc_bit;
+	/* To support fractional scaling, separate the unshifted lux
+	 * into two calculations: int scaling and micro-scaling.
+	 * lux_uscale ranges from 0-999999, so about 20 bits.  Split
+	 * the /1,000,000 in two to reduce the risk of over/underflow.
+	 */
+	data_x_range = lux_data * chip->range;
+	lux_unshifted = data_x_range * chip->lux_scale;
+	lux_unshifted += data_x_range / 1000 * chip->lux_uscale / 1000;
+	*lux = lux_unshifted >> chip->adc_bit;
 
 	return 0;
 }
@@ -339,6 +349,8 @@
 	mutex_lock(&chip->lock);
 	if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) {
 		chip->lux_scale = val;
+		/* With no write_raw_get_fmt(), val2 is a MICRO fraction. */
+		chip->lux_uscale = val2;
 		ret = 0;
 	}
 	mutex_unlock(&chip->lock);
@@ -379,7 +391,8 @@
 	case IIO_CHAN_INFO_CALIBSCALE:
 		if (chan->type == IIO_LIGHT) {
 			*val = chip->lux_scale;
-			ret = IIO_VAL_INT;
+			*val2 = chip->lux_uscale;
+			ret = IIO_VAL_INT_PLUS_MICRO;
 		}
 		break;
 	default:
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index 9d740be..954ca2c 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -805,7 +805,7 @@
 	return err;
 }
 
-static int tsl2563_remove(struct i2c_client *client)
+static int __devexit tsl2563_remove(struct i2c_client *client)
 {
 	struct tsl2563_chip *chip = i2c_get_clientdata(client);
 	struct iio_dev *indio_dev = iio_priv_to_dev(chip);
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index 6c3e50f..10e0954 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -1,6 +1,6 @@
 /*  Copyright (C) 2010 Texas Instruments
     Author: Shubhrajyoti Datta <shubhrajyoti@ti.com>
-    Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs.
+    Acknowledgement: Jonathan Cameron <jic23@kernel.org> for valuable inputs.
 
     Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
 
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index 3ccff18..8b9eceb 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -555,20 +555,15 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int ade7753_remove(struct spi_device *spi)
+static int __devexit ade7753_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-
-	ret = ade7753_stop_device(&(indio_dev->dev));
-	if (ret)
-		goto err_ret;
-
+	ade7753_stop_device(&indio_dev->dev);
 	iio_device_free(indio_dev);
-err_ret:
-	return ret;
+
+	return 0;
 }
 
 static struct spi_driver ade7753_driver = {
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index abb1e9c..76e0ade 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -577,21 +577,15 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int ade7754_remove(struct spi_device *spi)
+static int __devexit ade7754_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-	ret = ade7754_stop_device(&(indio_dev->dev));
-	if (ret)
-		goto err_ret;
-
+	ade7754_stop_device(&indio_dev->dev);
 	iio_device_free(indio_dev);
 
-err_ret:
-	return ret;
-
+	return 0;
 }
 
 static struct spi_driver ade7754_driver = {
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
index ec202b4..1e11ad5 100644
--- a/drivers/staging/iio/meter/ade7758.h
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -122,7 +122,7 @@
 	u8			*tx;
 	u8			*rx;
 	struct mutex		buf_lock;
-	struct iio_chan_spec	*ade7758_ring_channels;
+	const struct iio_chan_spec *ade7758_ring_channels;
 	struct spi_transfer	ring_xfer[4];
 	struct spi_message	ring_msg;
 	/*
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 7014a00..a0fef77 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -661,7 +661,7 @@
 	.attrs = ade7758_attributes,
 };
 
-static struct iio_chan_spec ade7758_channels[] = {
+static const struct iio_chan_spec ade7758_channels[] = {
 	{
 		.type = IIO_VOLTAGE,
 		.indexed = 1,
@@ -962,17 +962,13 @@
 	return ret;
 }
 
-static int ade7758_remove(struct spi_device *spi)
+static int __devexit ade7758_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ade7758_state *st = iio_priv(indio_dev);
-	int ret;
 
 	iio_device_unregister(indio_dev);
-	ret = ade7758_stop_device(&indio_dev->dev);
-	if (ret)
-		goto err_ret;
-
+	ade7758_stop_device(&indio_dev->dev);
 	ade7758_remove_trigger(indio_dev);
 	ade7758_uninitialize_ring(indio_dev);
 	ade7758_unconfigure_ring(indio_dev);
@@ -981,8 +977,7 @@
 
 	iio_device_free(indio_dev);
 
-err_ret:
-	return ret;
+	return 0;
 }
 
 static const struct spi_device_id ade7758_id[] = {
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 1ce10b2..9e49bacc 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -61,7 +61,6 @@
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
-	struct iio_buffer *ring = indio_dev->buffer;
 	struct ade7758_state *st = iio_priv(indio_dev);
 	s64 dat64[2];
 	u32 *dat32 = (u32 *)dat64;
@@ -74,7 +73,7 @@
 	if (indio_dev->scan_timestamp)
 		dat64[1] = pf->timestamp;
 
-	ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+	iio_push_to_buffer(indio_dev->buffer, (u8 *)dat64);
 
 	iio_trigger_notify_done(indio_dev->trig);
 
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index eb0a2a9..cb0707c 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -499,20 +499,15 @@
 }
 
 /* fixme, confirm ordering in this function */
-static int ade7759_remove(struct spi_device *spi)
+static int __devexit ade7759_remove(struct spi_device *spi)
 {
-	int ret;
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-	ret = ade7759_stop_device(&(indio_dev->dev));
-	if (ret)
-		goto err_ret;
-
+	ade7759_stop_device(&indio_dev->dev);
 	iio_device_free(indio_dev);
 
-err_ret:
-	return ret;
+	return 0;
 }
 
 static struct spi_driver ade7759_driver = {
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 9fb2f8b..7dae035 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -330,7 +330,7 @@
 	return 0;
 }
 
-static int ade7854_spi_remove(struct spi_device *spi)
+static int __devexit ade7854_spi_remove(struct spi_device *spi)
 {
 	ade7854_remove(spi_get_drvdata(spi));
 
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index f313859..4ba4d05e 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -575,7 +575,7 @@
 		       AD2S1210_REG_LOT_LOW_THRD);
 
 
-static struct iio_chan_spec ad2s1210_channels[] = {
+static const struct iio_chan_spec ad2s1210_channels[] = {
 	{
 		.type = IIO_ANGL,
 		.indexed = 1,
diff --git a/drivers/staging/iio/ring_hw.h b/drivers/staging/iio/ring_hw.h
index cad8a2e..39c14a7 100644
--- a/drivers/staging/iio/ring_hw.h
+++ b/drivers/staging/iio/ring_hw.h
@@ -5,7 +5,7 @@
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  *
- * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk>
+ * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org>
  *
  */
 
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index f61c8fd..3a45f9a 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -65,7 +65,7 @@
 /* Lock always held if their is a chance this may be called */
 /* Only one of these per ring may run concurrently - enforced by drivers */
 static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring,
-				unsigned char *data, s64 timestamp)
+				unsigned char *data)
 {
 	int ret = 0;
 	unsigned char *temp_ptr, *change_test_ptr;
@@ -256,11 +256,10 @@
 }
 
 static int iio_store_to_sw_rb(struct iio_buffer *r,
-			      u8 *data,
-			      s64 timestamp)
+			      u8 *data)
 {
 	struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
-	return iio_store_to_sw_ring(ring, data, timestamp);
+	return iio_store_to_sw_ring(ring, data);
 }
 
 static int iio_request_update_sw_rb(struct iio_buffer *r)
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
index b8abf54..7d32075 100644
--- a/drivers/staging/iio/trigger/Kconfig
+++ b/drivers/staging/iio/trigger/Kconfig
@@ -21,6 +21,8 @@
 config IIO_SYSFS_TRIGGER
 	tristate "SYSFS trigger"
 	depends on SYSFS
+	depends on HAVE_IRQ_WORK
+	select IRQ_WORK
 	help
 	  Provides support for using SYSFS entry as IIO triggers.
 	  If unsure, say N (but it's safe to say "Y").
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index ce6a7b1..52062d7 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -14,14 +14,18 @@
 #include <linux/delay.h>
 
 #include <asm/gptimers.h>
+#include <asm/portmux.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 
+#include "iio-trig-bfin-timer.h"
+
 struct bfin_timer {
 	unsigned short id, bit;
 	unsigned long irqbit;
 	int irq;
+	int pin;
 };
 
 /*
@@ -30,22 +34,22 @@
  */
 
 static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
-	{TIMER0_id,  TIMER0bit,  TIMER_STATUS_TIMIL0,  IRQ_TIMER0},
-	{TIMER1_id,  TIMER1bit,  TIMER_STATUS_TIMIL1,  IRQ_TIMER1},
-	{TIMER2_id,  TIMER2bit,  TIMER_STATUS_TIMIL2,  IRQ_TIMER2},
+	{TIMER0_id,  TIMER0bit,  TIMER_STATUS_TIMIL0,  IRQ_TIMER0, P_TMR0},
+	{TIMER1_id,  TIMER1bit,  TIMER_STATUS_TIMIL1,  IRQ_TIMER1, P_TMR1},
+	{TIMER2_id,  TIMER2bit,  TIMER_STATUS_TIMIL2,  IRQ_TIMER2, P_TMR2},
 #if (MAX_BLACKFIN_GPTIMERS > 3)
-	{TIMER3_id,  TIMER3bit,  TIMER_STATUS_TIMIL3,  IRQ_TIMER3},
-	{TIMER4_id,  TIMER4bit,  TIMER_STATUS_TIMIL4,  IRQ_TIMER4},
-	{TIMER5_id,  TIMER5bit,  TIMER_STATUS_TIMIL5,  IRQ_TIMER5},
-	{TIMER6_id,  TIMER6bit,  TIMER_STATUS_TIMIL6,  IRQ_TIMER6},
-	{TIMER7_id,  TIMER7bit,  TIMER_STATUS_TIMIL7,  IRQ_TIMER7},
+	{TIMER3_id,  TIMER3bit,  TIMER_STATUS_TIMIL3,  IRQ_TIMER3, P_TMR3},
+	{TIMER4_id,  TIMER4bit,  TIMER_STATUS_TIMIL4,  IRQ_TIMER4, P_TMR4},
+	{TIMER5_id,  TIMER5bit,  TIMER_STATUS_TIMIL5,  IRQ_TIMER5, P_TMR5},
+	{TIMER6_id,  TIMER6bit,  TIMER_STATUS_TIMIL6,  IRQ_TIMER6, P_TMR6},
+	{TIMER7_id,  TIMER7bit,  TIMER_STATUS_TIMIL7,  IRQ_TIMER7, P_TMR7},
 #endif
 #if (MAX_BLACKFIN_GPTIMERS > 8)
-	{TIMER8_id,  TIMER8bit,  TIMER_STATUS_TIMIL8,  IRQ_TIMER8},
-	{TIMER9_id,  TIMER9bit,  TIMER_STATUS_TIMIL9,  IRQ_TIMER9},
-	{TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10},
+	{TIMER8_id,  TIMER8bit,  TIMER_STATUS_TIMIL8,  IRQ_TIMER8, P_TMR8},
+	{TIMER9_id,  TIMER9bit,  TIMER_STATUS_TIMIL9,  IRQ_TIMER9, P_TMR9},
+	{TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10},
 #if (MAX_BLACKFIN_GPTIMERS > 11)
-	{TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11},
+	{TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11, P_TMR11},
 #endif
 #endif
 };
@@ -54,15 +58,33 @@
 	struct iio_trigger *trig;
 	struct bfin_timer *t;
 	unsigned timer_num;
+	bool output_enable;
+	unsigned int duty;
 	int irq;
 };
 
+static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
+{
+	struct bfin_tmr_state *st = trig->private_data;
+
+	if (get_gptimer_period(st->t->id) == 0)
+		return -EINVAL;
+
+	if (state)
+		enable_gptimers(st->t->bit);
+	else
+		disable_gptimers(st->t->bit);
+
+	return 0;
+}
+
 static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct bfin_tmr_state *st = trig->private_data;
-	long val;
+	unsigned long val;
+	bool enabled;
 	int ret;
 
 	ret = strict_strtoul(buf, 10, &val);
@@ -74,20 +96,25 @@
 		goto error_ret;
 	}
 
-	disable_gptimers(st->t->bit);
+	enabled = get_enabled_gptimers() & st->t->bit;
+
+	if (enabled)
+		disable_gptimers(st->t->bit);
 
 	if (!val)
 		goto error_ret;
 
 	val = get_sclk() / val;
-	if (val <= 4) {
+	if (val <= 4 || val <= st->duty) {
 		ret = -EINVAL;
 		goto error_ret;
 	}
 
 	set_gptimer_period(st->t->id, val);
-	set_gptimer_pwidth(st->t->id, 1);
-	enable_gptimers(st->t->bit);
+	set_gptimer_pwidth(st->t->id, val - st->duty);
+
+	if (enabled)
+		enable_gptimers(st->t->bit);
 
 error_ret:
 	return ret ? ret : count;
@@ -99,9 +126,15 @@
 {
 	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct bfin_tmr_state *st = trig->private_data;
+	unsigned int period = get_gptimer_period(st->t->id);
+	unsigned long val;
 
-	return sprintf(buf, "%lu\n",
-			get_sclk() / get_gptimer_period(st->t->id));
+	if (period == 0)
+		val = 0;
+	else
+		val = get_sclk() / get_gptimer_period(st->t->id);
+
+	return sprintf(buf, "%lu\n", val);
 }
 
 static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
@@ -121,7 +154,6 @@
 	NULL
 };
 
-
 static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
 {
 	struct bfin_tmr_state *st = devid;
@@ -145,11 +177,14 @@
 
 static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
 	.owner = THIS_MODULE,
+	.set_trigger_state = iio_bfin_tmr_set_state,
 };
 
 static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
 {
+	struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data;
 	struct bfin_tmr_state *st;
+	unsigned int config;
 	int ret;
 
 	st = kzalloc(sizeof(*st), GFP_KERNEL);
@@ -193,13 +228,43 @@
 		goto out4;
 	}
 
-	set_gptimer_config(st->t->id, OUT_DIS | PWM_OUT | PERIOD_CNT | IRQ_ENA);
+	config = PWM_OUT | PERIOD_CNT | IRQ_ENA;
+
+	if (pdata && pdata->output_enable) {
+		unsigned long long val;
+
+		st->output_enable = true;
+
+		ret = peripheral_request(st->t->pin, st->trig->name);
+		if (ret)
+			goto out_free_irq;
+
+		val = (unsigned long long)get_sclk() * pdata->duty_ns;
+		do_div(val, NSEC_PER_SEC);
+		st->duty = val;
+
+		/**
+		 * The interrupt will be generated at the end of the period,
+		 * since we want the interrupt to be generated at end of the
+		 * pulse we invert both polarity and duty cycle, so that the
+		 * pulse will be generated directly before the interrupt.
+		 */
+		if (pdata->active_low)
+			config |= PULSE_HI;
+	} else {
+		st->duty = 1;
+		config |= OUT_DIS;
+	}
+
+	set_gptimer_config(st->t->id, config);
 
 	dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
 		 st->timer_num, st->irq);
 	platform_set_drvdata(pdev, st);
 
 	return 0;
+out_free_irq:
+	free_irq(st->irq, st);
 out4:
 	iio_trigger_unregister(st->trig);
 out2:
@@ -215,6 +280,8 @@
 	struct bfin_tmr_state *st = platform_get_drvdata(pdev);
 
 	disable_gptimers(st->t->bit);
+	if (st->output_enable)
+		peripheral_free(st->t->pin);
 	free_irq(st->irq, st);
 	iio_trigger_unregister(st->trig);
 	iio_trigger_put(st->trig);
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.h b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h
new file mode 100644
index 0000000..c07321f
--- /dev/null
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h
@@ -0,0 +1,24 @@
+#ifndef __IIO_BFIN_TIMER_TRIGGER_H__
+#define __IIO_BFIN_TIMER_TRIGGER_H__
+
+/**
+ * struct iio_bfin_timer_trigger_pdata - timer trigger platform data
+ * @output_enable: Enable external trigger pulse generation.
+ * @active_low: Whether the trigger pulse is active low.
+ * @duty_ns: Length of the trigger pulse in nanoseconds.
+ *
+ * This struct is used to configure the output pulse generation of the blackfin
+ * timer trigger. If output_enable is set to true an external trigger signal
+ * will generated on the pin corresponding to the timer. This is useful for
+ * converters which needs an external signal to start conversion. active_low and
+ * duty_ns are used to configure the type of the trigger pulse. If output_enable
+ * is set to false no external trigger pulse will be generated and active_low
+ * and duty_ns are ignored.
+ **/
+struct iio_bfin_timer_trigger_pdata {
+	bool output_enable;
+	bool active_low;
+	unsigned int duty_ns;
+};
+
+#endif
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index 90b2684..5ff4d7fa 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -51,7 +51,7 @@
 	.owner = THIS_MODULE,
 };
 
-static int iio_gpio_trigger_probe(struct platform_device *pdev)
+static int __devinit iio_gpio_trigger_probe(struct platform_device *pdev)
 {
 	struct iio_gpio_trigger_info *trig_info;
 	struct iio_trigger *trig, *trig2;
@@ -130,7 +130,7 @@
 	return ret;
 }
 
-static int iio_gpio_trigger_remove(struct platform_device *pdev)
+static int __devexit iio_gpio_trigger_remove(struct platform_device *pdev)
 {
 	struct iio_trigger *trig, *trig2;
 	struct iio_gpio_trigger_info *trig_info;
@@ -153,7 +153,7 @@
 
 static struct platform_driver iio_gpio_trigger_driver = {
 	.probe = iio_gpio_trigger_probe,
-	.remove = iio_gpio_trigger_remove,
+	.remove = __devexit_p(iio_gpio_trigger_remove),
 	.driver = {
 		.name = "iio_gpio_trigger",
 		.owner = THIS_MODULE,
@@ -162,6 +162,6 @@
 
 module_platform_driver(iio_gpio_trigger_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index 4ceaa18..a3de76d 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -101,7 +101,7 @@
 	.set_trigger_state = &iio_trig_periodic_rtc_set_state,
 };
 
-static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
+static int __devinit iio_trig_periodic_rtc_probe(struct platform_device *dev)
 {
 	char **pdata = dev->dev.platform_data;
 	struct iio_prtc_trigger_info *trig_info;
@@ -167,7 +167,7 @@
 	return ret;
 }
 
-static int iio_trig_periodic_rtc_remove(struct platform_device *dev)
+static int __devexit iio_trig_periodic_rtc_remove(struct platform_device *dev)
 {
 	struct iio_trigger *trig, *trig2;
 	struct iio_prtc_trigger_info *trig_info;
@@ -188,7 +188,7 @@
 
 static struct platform_driver iio_trig_periodic_rtc_driver = {
 	.probe = iio_trig_periodic_rtc_probe,
-	.remove = iio_trig_periodic_rtc_remove,
+	.remove = __devexit_p(iio_trig_periodic_rtc_remove),
 	.driver = {
 		.name = "iio_prtc_trigger",
 		.owner = THIS_MODULE,
@@ -197,6 +197,6 @@
 
 module_platform_driver(iio_trig_periodic_rtc_driver);
 
-MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("Periodic realtime clock  trigger for the iio subsystem");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index fee4746..3bac972 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -10,12 +10,14 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/irq_work.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 
 struct iio_sysfs_trig {
 	struct iio_trigger *trig;
+	struct irq_work work;
 	int id;
 	struct list_head l;
 };
@@ -89,11 +91,21 @@
 	.release = &iio_trigger_sysfs_release,
 };
 
+static void iio_sysfs_trigger_work(struct irq_work *work)
+{
+	struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,
+							work);
+
+	iio_trigger_poll(trig->trig, 0);
+}
+
 static ssize_t iio_sysfs_trigger_poll(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct iio_trigger *trig = to_iio_trigger(dev);
-	iio_trigger_poll_chained(trig, 0);
+	struct iio_sysfs_trig *sysfs_trig = trig->private_data;
+
+	irq_work_queue(&sysfs_trig->work);
 
 	return count;
 }
@@ -148,6 +160,9 @@
 	t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
 	t->trig->ops = &iio_sysfs_trigger_ops;
 	t->trig->dev.parent = &iio_sysfs_trig_dev;
+	t->trig->private_data = t;
+
+	init_irq_work(&t->work, iio_sysfs_trigger_work);
 
 	ret = iio_trigger_register(t->trig);
 	if (ret)
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
new file mode 100644
index 0000000..14b4449
--- /dev/null
+++ b/drivers/staging/imx-drm/Kconfig
@@ -0,0 +1,35 @@
+config DRM_IMX
+	tristate "DRM Support for Freescale i.MX"
+	select DRM_KMS_HELPER
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_CMA_HELPER
+	depends on DRM && ARCH_MXC
+	help
+	  enable i.MX graphics support
+
+config DRM_IMX_FB_HELPER
+	tristate "provide legacy framebuffer /dev/fb0"
+	select DRM_KMS_CMA_HELPER
+	depends on DRM_IMX
+	help
+	  The DRM framework can provide a legacy /dev/fb0 framebuffer
+	  for your device. This is necessary to get a framebuffer console
+	  and also for appplications using the legacy framebuffer API
+
+config DRM_IMX_PARALLEL_DISPLAY
+	tristate "Support for parallel displays"
+	depends on DRM_IMX
+
+config DRM_IMX_IPUV3_CORE
+	tristate "IPUv3 core support"
+	depends on DRM_IMX
+	help
+	  Choose this if you have a i.MX5/6 system and want
+	  to use the IPU. This option only enables IPU base
+	  support.
+
+config DRM_IMX_IPUV3
+	tristate "DRM Support for i.MX IPUv3"
+	depends on DRM_IMX
+	help
+	  Choose this if you have a i.MX5 or i.MX6 processor.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
new file mode 100644
index 0000000..83a9056
--- /dev/null
+++ b/drivers/staging/imx-drm/Makefile
@@ -0,0 +1,9 @@
+
+imxdrm-objs := imx-drm-core.o imx-fb.o
+
+obj-$(CONFIG_DRM_IMX) += imxdrm.o
+
+obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
+obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
+obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
+obj-$(CONFIG_DRM_IMX_IPUV3)	+= ipuv3-crtc.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
new file mode 100644
index 0000000..e52adc4
--- /dev/null
+++ b/drivers/staging/imx-drm/TODO
@@ -0,0 +1,22 @@
+TODO:
+- get DRM Maintainer review for this code
+- Factor out more code to common helper functions
+- decide where to put the base driver. It is not specific to a subsystem
+  and would be used by DRM/KMS and media/V4L2
+- convert irq driver to irq_domain_add_linear
+
+Missing features (not necessarily for moving out of staging):
+
+- Add KMS plane support for CRTC driver
+- Add LDB (LVDS Display Bridge) support
+- Add i.MX6 HDMI support
+- Add support for IC (Image converter)
+- Add support for CSI (CMOS Sensor interface)
+- Add support for VDIC (Video Deinterlacer)
+
+Many work-in-progress patches for the above features exist. Contact
+Sascha Hauer <kernel@pengutronix.de> if you are interested in working
+on a specific feature.
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and
+Sascha Hauer <kernel@pengutronix.de>
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
new file mode 100644
index 0000000..1913199
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -0,0 +1,884 @@
+/*
+ * Freescale i.MX drm driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+#define MAX_CRTC	4
+
+struct crtc_cookie {
+	void *cookie;
+	int id;
+	struct list_head list;
+};
+
+struct imx_drm_device {
+	struct drm_device			*drm;
+	struct device				*dev;
+	struct list_head			crtc_list;
+	struct list_head			encoder_list;
+	struct list_head			connector_list;
+	struct mutex				mutex;
+	int					references;
+	int					pipes;
+	struct drm_fbdev_cma			*fbhelper;
+};
+
+struct imx_drm_crtc {
+	struct drm_crtc				*crtc;
+	struct list_head			list;
+	struct imx_drm_device			*imxdrm;
+	int					pipe;
+	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
+	struct module				*owner;
+	struct crtc_cookie			cookie;
+};
+
+struct imx_drm_encoder {
+	struct drm_encoder			*encoder;
+	struct list_head			list;
+	struct module				*owner;
+	struct list_head			possible_crtcs;
+};
+
+struct imx_drm_connector {
+	struct drm_connector			*connector;
+	struct list_head			list;
+	struct module				*owner;
+};
+
+static int imx_drm_driver_firstopen(struct drm_device *drm)
+{
+	if (!imx_drm_device_get())
+		return -EINVAL;
+
+	return 0;
+}
+
+static void imx_drm_driver_lastclose(struct drm_device *drm)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+
+	if (imxdrm->fbhelper)
+		drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+
+	imx_drm_device_put();
+}
+
+static int imx_drm_driver_unload(struct drm_device *drm)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+
+	drm_mode_config_cleanup(imxdrm->drm);
+	drm_kms_helper_poll_fini(imxdrm->drm);
+
+	return 0;
+}
+
+/*
+ * We don't care at all for crtc numbers, but the core expects the
+ * crtcs to be numbered
+ */
+static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
+		int num)
+{
+	struct imx_drm_crtc *imx_drm_crtc;
+
+	list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
+		if (imx_drm_crtc->pipe == num)
+			return imx_drm_crtc;
+	return NULL;
+}
+
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+		u32 interface_pix_fmt)
+{
+	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+	struct imx_drm_crtc *imx_crtc;
+	struct imx_drm_crtc_helper_funcs *helper;
+
+	mutex_lock(&imxdrm->mutex);
+
+	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+		if (imx_crtc->crtc == crtc)
+			goto found;
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return -EINVAL;
+found:
+	mutex_unlock(&imxdrm->mutex);
+
+	helper = &imx_crtc->imx_drm_helper_funcs;
+	if (helper->set_interface_pix_fmt)
+		return helper->set_interface_pix_fmt(crtc,
+				encoder_type, interface_pix_fmt);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
+{
+	return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
+
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
+{
+	drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
+
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
+{
+	drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
+
+static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+	struct imx_drm_crtc *imx_drm_crtc;
+	int ret;
+
+	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
+	if (!imx_drm_crtc)
+		return -EINVAL;
+
+	if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
+		return -ENOSYS;
+
+	ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
+			imx_drm_crtc->crtc);
+
+	return ret;
+}
+
+static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+	struct imx_drm_crtc *imx_drm_crtc;
+
+	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
+	if (!imx_drm_crtc)
+		return;
+
+	if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
+		return;
+
+	imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
+}
+
+static const struct file_operations imx_drm_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.release = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+	.mmap = drm_gem_cma_mmap,
+	.poll = drm_poll,
+	.fasync = drm_fasync,
+	.read = drm_read,
+	.llseek = noop_llseek,
+};
+
+static struct imx_drm_device *imx_drm_device;
+
+static struct imx_drm_device *__imx_drm_device(void)
+{
+	return imx_drm_device;
+}
+
+struct drm_device *imx_drm_device_get(void)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_encoder *enc;
+	struct imx_drm_connector *con;
+	struct imx_drm_crtc *crtc;
+
+	mutex_lock(&imxdrm->mutex);
+
+	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
+		if (!try_module_get(enc->owner)) {
+			dev_err(imxdrm->dev, "could not get module %s\n",
+					module_name(enc->owner));
+			goto unwind_enc;
+		}
+	}
+
+	list_for_each_entry(con, &imxdrm->connector_list, list) {
+		if (!try_module_get(con->owner)) {
+			dev_err(imxdrm->dev, "could not get module %s\n",
+					module_name(con->owner));
+			goto unwind_con;
+		}
+	}
+
+	list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
+		if (!try_module_get(crtc->owner)) {
+			dev_err(imxdrm->dev, "could not get module %s\n",
+					module_name(crtc->owner));
+			goto unwind_crtc;
+		}
+	}
+
+	imxdrm->references++;
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return imxdrm->drm;
+
+unwind_crtc:
+	list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
+		module_put(crtc->owner);
+unwind_con:
+	list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
+		module_put(con->owner);
+unwind_enc:
+	list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
+		module_put(enc->owner);
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return NULL;
+
+}
+EXPORT_SYMBOL_GPL(imx_drm_device_get);
+
+void imx_drm_device_put(void)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_encoder *enc;
+	struct imx_drm_connector *con;
+	struct imx_drm_crtc *crtc;
+
+	mutex_lock(&imxdrm->mutex);
+
+	list_for_each_entry(crtc, &imxdrm->crtc_list, list)
+		module_put(crtc->owner);
+
+	list_for_each_entry(con, &imxdrm->connector_list, list)
+		module_put(con->owner);
+
+	list_for_each_entry(enc, &imxdrm->encoder_list, list)
+		module_put(enc->owner);
+
+	imxdrm->references--;
+
+	mutex_unlock(&imxdrm->mutex);
+}
+EXPORT_SYMBOL_GPL(imx_drm_device_put);
+
+static int drm_mode_group_reinit(struct drm_device *dev)
+{
+	struct drm_mode_group *group = &dev->primary->mode_group;
+	uint32_t *id_list = group->id_list;
+	int ret;
+
+	ret = drm_mode_group_init_legacy_group(dev, group);
+	if (ret < 0)
+		return ret;
+
+	kfree(id_list);
+	return 0;
+}
+
+/*
+ * register an encoder to the drm core
+ */
+static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
+
+	drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
+			imx_drm_encoder->encoder->funcs,
+			imx_drm_encoder->encoder->encoder_type);
+
+	drm_mode_group_reinit(imxdrm->drm);
+
+	return 0;
+}
+
+/*
+ * unregister an encoder from the drm core
+ */
+static void imx_drm_encoder_unregister(struct imx_drm_encoder
+		*imx_drm_encoder)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	drm_encoder_cleanup(imx_drm_encoder->encoder);
+
+	drm_mode_group_reinit(imxdrm->drm);
+}
+
+/*
+ * register a connector to the drm core
+ */
+static int imx_drm_connector_register(
+		struct imx_drm_connector *imx_drm_connector)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
+			imx_drm_connector->connector->funcs,
+			imx_drm_connector->connector->connector_type);
+	drm_mode_group_reinit(imxdrm->drm);
+
+	return drm_sysfs_connector_add(imx_drm_connector->connector);
+}
+
+/*
+ * unregister a connector from the drm core
+ */
+static void imx_drm_connector_unregister(
+		struct imx_drm_connector *imx_drm_connector)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	drm_sysfs_connector_remove(imx_drm_connector->connector);
+	drm_connector_cleanup(imx_drm_connector->connector);
+
+	drm_mode_group_reinit(imxdrm->drm);
+}
+
+/*
+ * register a crtc to the drm core
+ */
+static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	int ret;
+
+	drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
+	if (ret)
+		return ret;
+
+	drm_crtc_helper_add(imx_drm_crtc->crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+	drm_mode_group_reinit(imxdrm->drm);
+
+	return 0;
+}
+
+/*
+ * Called by the CRTC driver when all CRTCs are registered. This
+ * puts all the pieces together and initializes the driver.
+ * Once this is called no more CRTCs can be registered since
+ * the drm core has hardcoded the number of crtcs in several
+ * places.
+ */
+static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	int ret;
+
+	imxdrm->drm = drm;
+
+	drm->dev_private = imxdrm;
+
+	/*
+	 * enable drm irq mode.
+	 * - with irq_enabled = 1, we can use the vblank feature.
+	 *
+	 * P.S. note that we wouldn't use drm irq handler but
+	 *      just specific driver own one instead because
+	 *      drm framework supports only one irq handler and
+	 *      drivers can well take care of their interrupts
+	 */
+	drm->irq_enabled = 1;
+
+	drm_mode_config_init(drm);
+	imx_drm_mode_config_init(drm);
+
+	mutex_lock(&imxdrm->mutex);
+
+	drm_kms_helper_poll_init(imxdrm->drm);
+
+	/* setup the grouping for the legacy output */
+	ret = drm_mode_group_init_legacy_group(imxdrm->drm,
+			&imxdrm->drm->primary->mode_group);
+	if (ret)
+		goto err_init;
+
+	ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+	if (ret)
+		goto err_init;
+
+	/*
+	 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+	 * by drm timer once a current process gives up ownership of
+	 * vblank event.(after drm_vblank_put function is called)
+	 */
+	imxdrm->drm->vblank_disable_allowed = 1;
+
+	ret = 0;
+
+err_init:
+	mutex_unlock(&imxdrm->mutex);
+
+	return ret;
+}
+
+static void imx_drm_update_possible_crtcs(void)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_encoder *enc;
+	struct crtc_cookie *cookie;
+
+	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
+		u32 possible_crtcs = 0;
+
+		list_for_each_entry(cookie, &enc->possible_crtcs, list) {
+			list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
+				if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
+						imx_drm_crtc->cookie.id == cookie->id) {
+					possible_crtcs |= 1 << imx_drm_crtc->pipe;
+				}
+			}
+		}
+		enc->encoder->possible_crtcs = possible_crtcs;
+		enc->encoder->possible_clones = possible_crtcs;
+	}
+}
+
+/*
+ * imx_drm_add_crtc - add a new crtc
+ *
+ * The return value if !NULL is a cookie for the caller to pass to
+ * imx_drm_remove_crtc later.
+ */
+int imx_drm_add_crtc(struct drm_crtc *crtc,
+		struct imx_drm_crtc **new_crtc,
+		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
+		struct module *owner, void *cookie, int id)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_crtc *imx_drm_crtc;
+	const struct drm_crtc_funcs *crtc_funcs;
+	int ret;
+
+	mutex_lock(&imxdrm->mutex);
+
+	if (imxdrm->references) {
+		ret = -EBUSY;
+		goto err_busy;
+	}
+
+	imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
+	if (!imx_drm_crtc) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
+	imx_drm_crtc->pipe = imxdrm->pipes++;
+	imx_drm_crtc->cookie.cookie = cookie;
+	imx_drm_crtc->cookie.id = id;
+
+	crtc_funcs = imx_drm_helper_funcs->crtc_funcs;
+
+	imx_drm_crtc->crtc = crtc;
+	imx_drm_crtc->imxdrm = imxdrm;
+
+	imx_drm_crtc->owner = owner;
+
+	list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+
+	*new_crtc = imx_drm_crtc;
+
+	ret = imx_drm_crtc_register(imx_drm_crtc);
+	if (ret)
+		goto err_register;
+
+	imx_drm_update_possible_crtcs();
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return 0;
+
+err_register:
+	kfree(imx_drm_crtc);
+err_alloc:
+err_busy:
+	mutex_unlock(&imxdrm->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
+
+/*
+ * imx_drm_remove_crtc - remove a crtc
+ */
+int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
+{
+	struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
+
+	mutex_lock(&imxdrm->mutex);
+
+	drm_crtc_cleanup(imx_drm_crtc->crtc);
+
+	list_del(&imx_drm_crtc->list);
+
+	drm_mode_group_reinit(imxdrm->drm);
+
+	mutex_unlock(&imxdrm->mutex);
+
+	kfree(imx_drm_crtc);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
+
+/*
+ * imx_drm_add_encoder - add a new encoder
+ */
+int imx_drm_add_encoder(struct drm_encoder *encoder,
+		struct imx_drm_encoder **newenc, struct module *owner)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_encoder *imx_drm_encoder;
+	int ret;
+
+	mutex_lock(&imxdrm->mutex);
+
+	if (imxdrm->references) {
+		ret = -EBUSY;
+		goto err_busy;
+	}
+
+	imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
+	if (!imx_drm_encoder) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	imx_drm_encoder->encoder = encoder;
+	imx_drm_encoder->owner = owner;
+
+	ret = imx_drm_encoder_register(imx_drm_encoder);
+	if (ret) {
+		kfree(imx_drm_encoder);
+		ret = -ENOMEM;
+		goto err_register;
+	}
+
+	list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
+
+	*newenc = imx_drm_encoder;
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return 0;
+
+err_register:
+	kfree(imx_drm_encoder);
+err_alloc:
+err_busy:
+	mutex_unlock(&imxdrm->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
+
+int imx_drm_encoder_add_possible_crtcs(
+		struct imx_drm_encoder *imx_drm_encoder,
+		struct device_node *np)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct of_phandle_args args;
+	struct crtc_cookie *c;
+	int ret = 0;
+	int i;
+
+	if (!list_empty(&imx_drm_encoder->possible_crtcs))
+		return -EBUSY;
+
+	for (i = 0; !ret; i++) {
+		ret = of_parse_phandle_with_args(np, "crtcs",
+				"#crtc-cells", i, &args);
+		if (ret < 0)
+			break;
+
+		c = kzalloc(sizeof(*c), GFP_KERNEL);
+		if (!c) {
+			of_node_put(args.np);
+			return -ENOMEM;
+		}
+
+		c->cookie = args.np;
+		c->id = args.args_count > 0 ? args.args[0] : 0;
+
+		of_node_put(args.np);
+
+		mutex_lock(&imxdrm->mutex);
+
+		list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
+
+		mutex_unlock(&imxdrm->mutex);
+	}
+
+	imx_drm_update_possible_crtcs();
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
+
+int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
+		struct drm_crtc *crtc)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_crtc *imx_crtc;
+	int i = 0;
+
+	mutex_lock(&imxdrm->mutex);
+
+	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
+		if (imx_crtc->crtc == crtc)
+			goto found;
+		i++;
+	}
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return -EINVAL;
+found:
+	mutex_unlock(&imxdrm->mutex);
+
+	return i;
+}
+
+/*
+ * imx_drm_remove_encoder - remove an encoder
+ */
+int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct crtc_cookie *c, *tmp;
+
+	mutex_lock(&imxdrm->mutex);
+
+	imx_drm_encoder_unregister(imx_drm_encoder);
+
+	list_del(&imx_drm_encoder->list);
+
+	list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
+			list)
+		kfree(c);
+
+	mutex_unlock(&imxdrm->mutex);
+
+	kfree(imx_drm_encoder);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
+
+/*
+ * imx_drm_add_connector - add a connector
+ */
+int imx_drm_add_connector(struct drm_connector *connector,
+		struct imx_drm_connector **new_con,
+		struct module *owner)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_connector *imx_drm_connector;
+	int ret;
+
+	mutex_lock(&imxdrm->mutex);
+
+	if (imxdrm->references) {
+		ret = -EBUSY;
+		goto err_busy;
+	}
+
+	imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
+	if (!imx_drm_connector) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	imx_drm_connector->connector = connector;
+	imx_drm_connector->owner = owner;
+
+	ret = imx_drm_connector_register(imx_drm_connector);
+	if (ret)
+		goto err_register;
+
+	list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
+
+	*new_con = imx_drm_connector;
+
+	mutex_unlock(&imxdrm->mutex);
+
+	return 0;
+
+err_register:
+	kfree(imx_drm_connector);
+err_alloc:
+err_busy:
+	mutex_unlock(&imxdrm->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_connector);
+
+void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	imxdrm->fbhelper = fbdev_helper;
+}
+EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
+
+/*
+ * imx_drm_remove_connector - remove a connector
+ */
+int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
+{
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+
+	mutex_lock(&imxdrm->mutex);
+
+	imx_drm_connector_unregister(imx_drm_connector);
+
+	list_del(&imx_drm_connector->list);
+
+	mutex_unlock(&imxdrm->mutex);
+
+	kfree(imx_drm_connector);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
+
+static struct drm_ioctl_desc imx_drm_ioctls[] = {
+	/* none so far */
+};
+
+static struct drm_driver imx_drm_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM,
+	.load			= imx_drm_driver_load,
+	.unload			= imx_drm_driver_unload,
+	.firstopen		= imx_drm_driver_firstopen,
+	.lastclose		= imx_drm_driver_lastclose,
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_cma_dumb_destroy,
+
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= imx_drm_enable_vblank,
+	.disable_vblank		= imx_drm_disable_vblank,
+	.ioctls			= imx_drm_ioctls,
+	.num_ioctls		= ARRAY_SIZE(imx_drm_ioctls),
+	.fops			= &imx_drm_driver_fops,
+	.name			= "imx-drm",
+	.desc			= "i.MX DRM graphics",
+	.date			= "20120507",
+	.major			= 1,
+	.minor			= 0,
+	.patchlevel		= 0,
+};
+
+static int imx_drm_platform_probe(struct platform_device *pdev)
+{
+	imx_drm_device->dev = &pdev->dev;
+
+	return drm_platform_init(&imx_drm_driver, pdev);
+}
+
+static int imx_drm_platform_remove(struct platform_device *pdev)
+{
+	drm_platform_exit(&imx_drm_driver, pdev);
+
+	return 0;
+}
+
+static struct platform_driver imx_drm_pdrv = {
+	.probe		= imx_drm_platform_probe,
+	.remove		= __devexit_p(imx_drm_platform_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "imx-drm",
+	},
+};
+
+static struct platform_device *imx_drm_pdev;
+
+static int __init imx_drm_init(void)
+{
+	int ret;
+
+	imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
+	if (!imx_drm_device)
+		return -ENOMEM;
+
+	mutex_init(&imx_drm_device->mutex);
+	INIT_LIST_HEAD(&imx_drm_device->crtc_list);
+	INIT_LIST_HEAD(&imx_drm_device->connector_list);
+	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
+
+	imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
+	if (!imx_drm_pdev) {
+		ret = -EINVAL;
+		goto err_pdev;
+	}
+
+	imx_drm_pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32),
+
+	ret = platform_driver_register(&imx_drm_pdrv);
+	if (ret)
+		goto err_pdrv;
+
+	return 0;
+
+err_pdrv:
+	platform_device_unregister(imx_drm_pdev);
+err_pdev:
+	kfree(imx_drm_device);
+
+	return ret;
+}
+
+static void __exit imx_drm_exit(void)
+{
+	platform_device_unregister(imx_drm_pdev);
+	platform_driver_unregister(&imx_drm_pdrv);
+
+	kfree(imx_drm_device);
+}
+
+module_init(imx_drm_init);
+module_exit(imx_drm_exit);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX drm driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
new file mode 100644
index 0000000..ae28a49
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -0,0 +1,58 @@
+#ifndef _IMX_DRM_H_
+#define _IMX_DRM_H_
+
+struct imx_drm_crtc;
+struct drm_fbdev_cma;
+
+struct imx_drm_crtc_helper_funcs {
+	int (*enable_vblank)(struct drm_crtc *crtc);
+	void (*disable_vblank)(struct drm_crtc *crtc);
+	int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
+			u32 pix_fmt);
+	const struct drm_crtc_helper_funcs *crtc_helper_funcs;
+	const struct drm_crtc_funcs *crtc_funcs;
+};
+
+int imx_drm_add_crtc(struct drm_crtc *crtc,
+		struct imx_drm_crtc **new_crtc,
+		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
+		struct module *owner, void *cookie, int id);
+int imx_drm_remove_crtc(struct imx_drm_crtc *);
+int imx_drm_init_drm(struct platform_device *pdev,
+		int preferred_bpp);
+int imx_drm_exit_drm(void);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
+
+struct imx_drm_encoder;
+int imx_drm_add_encoder(struct drm_encoder *encoder,
+		struct imx_drm_encoder **new_enc,
+		struct module *owner);
+int imx_drm_remove_encoder(struct imx_drm_encoder *);
+
+struct imx_drm_connector;
+int imx_drm_add_connector(struct drm_connector *connector,
+		struct imx_drm_connector **new_con,
+		struct module *owner);
+int imx_drm_remove_connector(struct imx_drm_connector *);
+
+void imx_drm_mode_config_init(struct drm_device *drm);
+
+struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+
+struct drm_device *imx_drm_device_get(void);
+void imx_drm_device_put(void);
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+		u32 interface_pix_fmt);
+void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
+
+struct device_node;
+
+int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
+		struct drm_crtc *crtc);
+int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
+		struct device_node *np);
+
+#endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
new file mode 100644
index 0000000..03a7b4e
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-fb.c
@@ -0,0 +1,47 @@
+/*
+ * i.MX drm driver
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * Based on Samsung Exynos code
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+};
+
+void imx_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 64;
+	dev->mode_config.min_height = 64;
+
+	/*
+	 * set max width and height as default value(4096x4096).
+	 * this value would be used to check framebuffer size limitation
+	 * at drm_mode_addfb().
+	 */
+	dev->mode_config.max_width = 4096;
+	dev->mode_config.max_height = 4096;
+
+	dev->mode_config.funcs = &imx_drm_mode_config_funcs;
+}
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
new file mode 100644
index 0000000..8331739
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-fbdev.c
@@ -0,0 +1,74 @@
+/*
+ * i.MX drm driver
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * Based on Samsung Exynos code
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+#define MAX_CONNECTOR		4
+#define PREFERRED_BPP		16
+
+static struct drm_fbdev_cma *fbdev_cma;
+
+static int legacyfb_depth = 16;
+
+module_param(legacyfb_depth, int, 0444);
+
+static int __init imx_fb_helper_init(void)
+{
+	struct drm_device *drm = imx_drm_device_get();
+
+	if (!drm)
+		return -EINVAL;
+
+	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+		pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
+		legacyfb_depth = 16;
+	}
+
+	fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
+			drm->mode_config.num_crtc, MAX_CONNECTOR);
+
+	if (IS_ERR(fbdev_cma)) {
+		imx_drm_device_put();
+		return PTR_ERR(fbdev_cma);
+	}
+
+	imx_drm_fb_helper_set(fbdev_cma);
+
+	return 0;
+}
+
+static void __exit imx_fb_helper_exit(void)
+{
+	imx_drm_fb_helper_set(NULL);
+	drm_fbdev_cma_fini(fbdev_cma);
+	imx_drm_device_put();
+}
+
+late_initcall(imx_fb_helper_init);
+module_exit(imx_fb_helper_exit);
+
+MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
new file mode 100644
index 0000000..28ed72e
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
new file mode 100644
index 0000000..74158dd
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __DRM_IPU_H__
+#define __DRM_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+#include <linux/fb.h>
+#include <linux/videodev2.h>
+
+struct ipu_soc;
+
+enum ipuv3_type {
+	IPUV3EX,
+	IPUV3M,
+	IPUV3H,
+};
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+	unsigned datamask_en:1;
+	unsigned interlaced:1;
+	unsigned odd_field_first:1;
+	unsigned clksel_en:1;
+	unsigned clkidle_en:1;
+	unsigned data_pol:1;	/* true = inverted */
+	unsigned clk_pol:1;	/* true = rising edge */
+	unsigned enable_pol:1;
+	unsigned Hsync_pol:1;	/* true = active high */
+	unsigned Vsync_pol:1;
+
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u16 h_start_width;
+	u16 h_sync_width;
+	u16 h_end_width;
+	u16 v_start_width;
+	u16 v_sync_width;
+	u16 v_end_width;
+	u32 v_to_h_sync;
+	unsigned long pixelclock;
+#define IPU_DI_CLKMODE_SYNC	(1 << 0)
+#define IPU_DI_CLKMODE_EXT	(1 << 1)
+	unsigned long clkflags;
+};
+
+enum ipu_color_space {
+	IPUV3_COLORSPACE_RGB,
+	IPUV3_COLORSPACE_YUV,
+	IPUV3_COLORSPACE_UNKNOWN,
+};
+
+struct ipuv3_channel;
+
+enum ipu_channel_irq {
+	IPU_IRQ_EOF = 0,
+	IPU_IRQ_NFACK = 64,
+	IPU_IRQ_NFB4EOF = 128,
+	IPU_IRQ_EOS = 192,
+};
+
+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+		enum ipu_channel_irq irq);
+
+#define IPU_IRQ_DP_SF_START		(448 + 2)
+#define IPU_IRQ_DP_SF_END		(448 + 3)
+#define IPU_IRQ_BG_SF_END		IPU_IRQ_DP_SF_END,
+#define IPU_IRQ_DC_FC_0			(448 + 8)
+#define IPU_IRQ_DC_FC_1			(448 + 9)
+#define IPU_IRQ_DC_FC_2			(448 + 10)
+#define IPU_IRQ_DC_FC_3			(448 + 11)
+#define IPU_IRQ_DC_FC_4			(448 + 12)
+#define IPU_IRQ_DC_FC_6			(448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0		(448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
+void ipu_idmac_put(struct ipuv3_channel *);
+
+int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
+int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+		bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+struct ipu_dc;
+struct ipu_di;
+struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
+void ipu_dc_put(struct ipu_dc *dc);
+int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+		u32 pixel_fmt, u32 width);
+void ipu_dc_enable_channel(struct ipu_dc *dc);
+void ipu_dc_disable_channel(struct ipu_dc *dc);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp);
+void ipu_di_put(struct ipu_di *);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_get_num(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_mbs, int burstsize);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC_BG	0
+#define IPU_DP_FLOW_SYNC_FG	1
+#define IPU_DP_FLOW_ASYNC0_BG	2
+#define IPU_DP_FLOW_ASYNC0_FG	3
+#define IPU_DP_FLOW_ASYNC1_BG	4
+#define IPU_DP_FLOW_ASYNC1_FG	5
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp,
+		enum ipu_color_space in, enum ipu_color_space out);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+		bool bg_chan);
+
+#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_UBO		IPU_CPMEM_WORD(0, 46, 22)
+#define IPU_FIELD_VBO		IPU_CPMEM_WORD(0, 68, 22)
+#define IPU_FIELD_IOX		IPU_CPMEM_WORD(0, 90, 4)
+#define IPU_FIELD_RDRW		IPU_CPMEM_WORD(0, 94, 1)
+#define IPU_FIELD_SO		IPU_CPMEM_WORD(0, 113, 1)
+#define IPU_FIELD_SLY		IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_SLUV		IPU_CPMEM_WORD(1, 128, 14)
+
+#define IPU_FIELD_XV		IPU_CPMEM_WORD(0, 0, 10)
+#define IPU_FIELD_YV		IPU_CPMEM_WORD(0, 10, 9)
+#define IPU_FIELD_XB		IPU_CPMEM_WORD(0, 19, 13)
+#define IPU_FIELD_YB		IPU_CPMEM_WORD(0, 32, 12)
+#define IPU_FIELD_NSB_B		IPU_CPMEM_WORD(0, 44, 1)
+#define IPU_FIELD_CF		IPU_CPMEM_WORD(0, 45, 1)
+#define IPU_FIELD_SX		IPU_CPMEM_WORD(0, 46, 12)
+#define IPU_FIELD_SY		IPU_CPMEM_WORD(0, 58, 11)
+#define IPU_FIELD_NS		IPU_CPMEM_WORD(0, 69, 10)
+#define IPU_FIELD_SDX		IPU_CPMEM_WORD(0, 79, 7)
+#define IPU_FIELD_SM		IPU_CPMEM_WORD(0, 86, 10)
+#define IPU_FIELD_SCC		IPU_CPMEM_WORD(0, 96, 1)
+#define IPU_FIELD_SCE		IPU_CPMEM_WORD(0, 97, 1)
+#define IPU_FIELD_SDY		IPU_CPMEM_WORD(0, 98, 7)
+#define IPU_FIELD_SDRX		IPU_CPMEM_WORD(0, 105, 1)
+#define IPU_FIELD_SDRY		IPU_CPMEM_WORD(0, 106, 1)
+#define IPU_FIELD_BPP		IPU_CPMEM_WORD(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	IPU_CPMEM_WORD(0, 110, 2)
+#define IPU_FIELD_DIM		IPU_CPMEM_WORD(0, 112, 1)
+#define IPU_FIELD_BNDM		IPU_CPMEM_WORD(0, 114, 3)
+#define IPU_FIELD_BM		IPU_CPMEM_WORD(0, 117, 2)
+#define IPU_FIELD_ROT		IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_HF		IPU_CPMEM_WORD(0, 120, 1)
+#define IPU_FIELD_VF		IPU_CPMEM_WORD(0, 121, 1)
+#define IPU_FIELD_THE		IPU_CPMEM_WORD(0, 122, 1)
+#define IPU_FIELD_CAP		IPU_CPMEM_WORD(0, 123, 1)
+#define IPU_FIELD_CAE		IPU_CPMEM_WORD(0, 124, 1)
+#define IPU_FIELD_FW		IPU_CPMEM_WORD(0, 125, 13)
+#define IPU_FIELD_FH		IPU_CPMEM_WORD(0, 138, 12)
+#define IPU_FIELD_EBA0		IPU_CPMEM_WORD(1, 0, 29)
+#define IPU_FIELD_EBA1		IPU_CPMEM_WORD(1, 29, 29)
+#define IPU_FIELD_ILO		IPU_CPMEM_WORD(1, 58, 20)
+#define IPU_FIELD_NPB		IPU_CPMEM_WORD(1, 78, 7)
+#define IPU_FIELD_PFS		IPU_CPMEM_WORD(1, 85, 4)
+#define IPU_FIELD_ALU		IPU_CPMEM_WORD(1, 89, 1)
+#define IPU_FIELD_ALBM		IPU_CPMEM_WORD(1, 90, 3)
+#define IPU_FIELD_ID		IPU_CPMEM_WORD(1, 93, 2)
+#define IPU_FIELD_TH		IPU_CPMEM_WORD(1, 95, 7)
+#define IPU_FIELD_SL		IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_WID0		IPU_CPMEM_WORD(1, 116, 3)
+#define IPU_FIELD_WID1		IPU_CPMEM_WORD(1, 119, 3)
+#define IPU_FIELD_WID2		IPU_CPMEM_WORD(1, 122, 3)
+#define IPU_FIELD_WID3		IPU_CPMEM_WORD(1, 125, 3)
+#define IPU_FIELD_OFS0		IPU_CPMEM_WORD(1, 128, 5)
+#define IPU_FIELD_OFS1		IPU_CPMEM_WORD(1, 133, 5)
+#define IPU_FIELD_OFS2		IPU_CPMEM_WORD(1, 138, 5)
+#define IPU_FIELD_OFS3		IPU_CPMEM_WORD(1, 143, 5)
+#define IPU_FIELD_SXYS		IPU_CPMEM_WORD(1, 148, 1)
+#define IPU_FIELD_CRE		IPU_CPMEM_WORD(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	IPU_CPMEM_WORD(1, 150, 1)
+
+struct ipu_cpmem_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_cpmem_word word[2];
+};
+
+void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
+u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
+struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
+void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
+
+static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
+{
+	int i;
+	void __iomem *base = p;
+
+	for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+		writel(0, base + i * sizeof(u32));
+}
+
+static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
+		int bufnum, dma_addr_t buf)
+{
+	if (bufnum)
+		ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
+	else
+		ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
+}
+
+static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
+		int xres, int yres)
+{
+	ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
+	ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
+}
+
+static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
+		int stride)
+{
+	ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
+}
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
+
+struct ipu_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+	int			bits_per_pixel;
+};
+
+struct ipu_image {
+	struct v4l2_pix_format pix;
+	struct v4l2_rect rect;
+	dma_addr_t phys;
+};
+
+int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
+		int width);
+
+int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
+		struct ipu_rgb *rgb);
+
+static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
+		int stride)
+{
+	ipu_ch_param_write_field(p, IPU_FIELD_SO, 1);
+	ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8);
+	ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1);
+};
+
+void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
+			int stride, int height);
+void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
+		u32 pixel_format, int stride, int u_offset, int v_offset);
+int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
+int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
+		struct ipu_image *image);
+
+enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
+
+static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
+		int burstsize)
+{
+	ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1);
+};
+
+struct ipu_client_platformdata {
+	int di;
+	int dc;
+	int dp;
+	int dmfc;
+	int dma[2];
+};
+
+#endif /* __DRM_IPU_H__ */
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
new file mode 100644
index 0000000..f381960
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <asm/mach/irq.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
+{
+	writel(value, ipu->cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+		unsigned offset)
+{
+	writel(value, ipu->idmac_reg + offset);
+}
+
+void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
+{
+	u32 val;
+
+	val = ipu_cm_read(ipu, IPU_SRM_PRI2);
+	val |= 0x8;
+	ipu_cm_write(ipu, val, IPU_SRM_PRI2);
+}
+EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
+
+struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+
+	return ipu->cpmem_base + channel->num;
+}
+EXPORT_SYMBOL_GPL(ipu_get_cpmem);
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
+	u32 val;
+
+	if (ipu->ipu_type == IPUV3EX)
+		ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
+
+	val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
+	val |= 1 << (channel->num % 32);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+
+void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = readl(&base->word[word].data[i]);
+	val &= ~(mask << ofs);
+	val |= v << ofs;
+	writel(val, &base->word[word].data[i]);
+
+	if ((bit + size - 1) / 32 > i) {
+		val = readl(&base->word[word].data[i + 1]);
+		val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+		val |= v >> (ofs ? (32 - ofs) : 0);
+		writel(val, &base->word[word].data[i + 1]);
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
+
+u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = readl(&base->word[word].data[i + 1]);
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
+
+int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
+		struct ipu_rgb *rgb)
+{
+	int bpp = 0, npb = 0, ro, go, bo, to;
+
+	ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+	go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+	bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+	to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+
+	ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
+	ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
+	ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
+	ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
+	ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
+	ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
+
+	if (rgb->transp.length) {
+		ipu_ch_param_write_field(p, IPU_FIELD_WID3,
+				rgb->transp.length - 1);
+		ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
+	} else {
+		ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
+		ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
+				rgb->bits_per_pixel);
+	}
+
+	switch (rgb->bits_per_pixel) {
+	case 32:
+		bpp = 0;
+		npb = 15;
+		break;
+	case 24:
+		bpp = 1;
+		npb = 19;
+		break;
+	case 16:
+		bpp = 3;
+		npb = 31;
+		break;
+	case 8:
+		bpp = 5;
+		npb = 63;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
+	ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
+	ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+
+int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
+		int width)
+{
+	int bpp = 0, npb = 0;
+
+	switch (width) {
+	case 32:
+		bpp = 0;
+		npb = 15;
+		break;
+	case 24:
+		bpp = 1;
+		npb = 19;
+		break;
+	case 16:
+		bpp = 3;
+		npb = 31;
+		break;
+	case 8:
+		bpp = 5;
+		npb = 63;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
+	ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
+	ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+
+void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
+		u32 pixel_format, int stride, int u_offset, int v_offset)
+{
+	switch (pixel_format) {
+	case V4L2_PIX_FMT_YUV420:
+		ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
+		ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
+		ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+
+void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
+		int stride, int height)
+{
+	int u_offset, v_offset;
+	int uv_stride = 0;
+
+	switch (pixel_format) {
+	case V4L2_PIX_FMT_YUV420:
+		uv_stride = stride / 2;
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_cpmem_set_yuv_planar_full(p, V4L2_PIX_FMT_YUV420, stride,
+				u_offset, v_offset);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
+
+static struct ipu_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+	.bits_per_pixel = 32,
+};
+
+static struct ipu_rgb def_bgr_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+	.bits_per_pixel = 32,
+};
+
+static struct ipu_rgb def_rgb_24 = {
+	.red	= { .offset =  0, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset = 16, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 24,
+};
+
+static struct ipu_rgb def_bgr_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 24,
+};
+
+static struct ipu_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 16,
+};
+
+#define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
+#define U_OFFSET(pix, x, y)	((pix->width * pix->height) + \
+					(pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y)	((pix->width * pix->height) + \
+					(pix->width * pix->height / 4) + \
+					(pix->width * (y) / 4) + (x) / 2)
+
+int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+		/* pix format */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
+		/* burst size */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		/* bits/pixel */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
+		/* pix format */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
+		/* burst size */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		/* bits/pixel */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
+		/* pix format */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
+		/* burst size */
+		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
+		break;
+	case V4L2_PIX_FMT_BGR24:
+		ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+
+int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
+		struct ipu_image *image)
+{
+	struct v4l2_pix_format *pix = &image->pix;
+	int y_offset, u_offset, v_offset;
+
+	pr_debug("%s: resolution: %dx%d stride: %d\n",
+			__func__, pix->width, pix->height,
+			pix->bytesperline);
+
+	ipu_cpmem_set_resolution(cpmem, image->rect.width,
+			image->rect.height);
+	ipu_cpmem_set_stride(cpmem, pix->bytesperline);
+
+	ipu_cpmem_set_fmt(cpmem, pix->pixelformat);
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = U_OFFSET(pix, image->rect.left,
+				image->rect.top) - y_offset;
+		v_offset = V_OFFSET(pix, image->rect.left,
+				image->rect.top) - y_offset;
+
+		ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
+				pix->bytesperline, u_offset, v_offset);
+		ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+				image->rect.left * 2 +
+				image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+				image->rect.left * 4 +
+				image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+				image->rect.left * 2 +
+				image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+				image->rect.left * 3 +
+				image->rect.top * image->pix.bytesperline);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+
+enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YVYU:
+		return IPUV3_COLORSPACE_YUV;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB565:
+		return IPUV3_COLORSPACE_RGB;
+	default:
+		return IPUV3_COLORSPACE_UNKNOWN;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+
+struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+{
+	struct ipuv3_channel *channel;
+
+	dev_dbg(ipu->dev, "%s %d\n", __func__, num);
+
+	if (num > 63)
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&ipu->channel_lock);
+
+	channel = &ipu->channel[num];
+
+	if (channel->busy) {
+		channel = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	channel->busy = 1;
+	channel->num = num;
+
+out:
+	mutex_unlock(&ipu->channel_lock);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+
+	dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
+
+	mutex_lock(&ipu->channel_lock);
+
+	channel->busy = 0;
+
+	mutex_unlock(&ipu->channel_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_put);
+
+#define idma_mask(ch)			(1 << (ch & 0x1f))
+
+void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+		bool doublebuffer)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	if (doublebuffer)
+		reg |= idma_mask(channel->num);
+	else
+		reg &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 val;
+
+	spin_lock_irqsave(&ipu->lock, lock_flags);
+
+	val = ipu_cm_read(ipu, IPU_DISP_GEN);
+
+	if (mask & IPU_CONF_DI0_EN)
+		val |= IPU_DI0_COUNTER_RELEASE;
+	if (mask & IPU_CONF_DI1_EN)
+		val |= IPU_DI1_COUNTER_RELEASE;
+
+	ipu_cm_write(ipu, val, IPU_DISP_GEN);
+
+	val = ipu_cm_read(ipu, IPU_CONF);
+	val |= mask;
+	ipu_cm_write(ipu, val, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->lock, lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_module_enable);
+
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 val;
+
+	spin_lock_irqsave(&ipu->lock, lock_flags);
+
+	val = ipu_cm_read(ipu, IPU_CONF);
+	val &= ~mask;
+	ipu_cm_write(ipu, val, IPU_CONF);
+
+	val = ipu_cm_read(ipu, IPU_DISP_GEN);
+
+	if (mask & IPU_CONF_DI0_EN)
+		val &= ~IPU_DI0_COUNTER_RELEASE;
+	if (mask & IPU_CONF_DI1_EN)
+		val &= ~IPU_DI1_COUNTER_RELEASE;
+
+	ipu_cm_write(ipu, val, IPU_DISP_GEN);
+
+	spin_unlock_irqrestore(&ipu->lock, lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_module_disable);
+
+void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	/* Mark buffer as ready. */
+	if (buf_num == 0)
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+	else
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val |= idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	u32 val;
+	unsigned long flags;
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(50);
+	while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
+			idma_mask(channel->num)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(ipu->dev, "disabling busy idmac channel %d\n",
+					channel->num);
+			break;
+		}
+		cpu_relax();
+	}
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	/* Disable DMA channel(s) */
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	/* Set channel buffers NOT to be ready */
+	ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+
+	if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
+			idma_mask(channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF0_RDY(channel->num));
+	}
+
+	if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
+			idma_mask(channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF1_RDY(channel->num));
+	}
+
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+	/* Reset the double buffer */
+	val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+
+static int ipu_reset(struct ipu_soc *ipu)
+{
+	unsigned long timeout;
+
+	ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+		if (time_after(jiffies, timeout))
+			return -ETIME;
+		cpu_relax();
+	}
+
+	mdelay(300);
+
+	return 0;
+}
+
+struct ipu_devtype {
+	const char *name;
+	unsigned long cm_ofs;
+	unsigned long cpmem_ofs;
+	unsigned long srm_ofs;
+	unsigned long tpm_ofs;
+	unsigned long disp0_ofs;
+	unsigned long disp1_ofs;
+	unsigned long dc_tmpl_ofs;
+	unsigned long vdi_ofs;
+	enum ipuv3_type type;
+};
+
+static struct ipu_devtype ipu_type_imx51 = {
+	.name = "IPUv3EX",
+	.cm_ofs = 0x1e000000,
+	.cpmem_ofs = 0x1f000000,
+	.srm_ofs = 0x1f040000,
+	.tpm_ofs = 0x1f060000,
+	.disp0_ofs = 0x1e040000,
+	.disp1_ofs = 0x1e048000,
+	.dc_tmpl_ofs = 0x1f080000,
+	.vdi_ofs = 0x1e068000,
+	.type = IPUV3EX,
+};
+
+static struct ipu_devtype ipu_type_imx53 = {
+	.name = "IPUv3M",
+	.cm_ofs = 0x06000000,
+	.cpmem_ofs = 0x07000000,
+	.srm_ofs = 0x07040000,
+	.tpm_ofs = 0x07060000,
+	.disp0_ofs = 0x06040000,
+	.disp1_ofs = 0x06048000,
+	.dc_tmpl_ofs = 0x07080000,
+	.vdi_ofs = 0x06068000,
+	.type = IPUV3M,
+};
+
+static struct ipu_devtype ipu_type_imx6q = {
+	.name = "IPUv3H",
+	.cm_ofs = 0x00200000,
+	.cpmem_ofs = 0x00300000,
+	.srm_ofs = 0x00340000,
+	.tpm_ofs = 0x00360000,
+	.disp0_ofs = 0x00240000,
+	.disp1_ofs = 0x00248000,
+	.dc_tmpl_ofs = 0x00380000,
+	.vdi_ofs = 0x00268000,
+	.type = IPUV3H,
+};
+
+static const struct of_device_id imx_ipu_dt_ids[] = {
+	{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+	{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+	{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
+
+static int ipu_submodules_init(struct ipu_soc *ipu,
+		struct platform_device *pdev, unsigned long ipu_base,
+		struct clk *ipu_clk)
+{
+	char *unit;
+	int ret;
+	struct device *dev = &pdev->dev;
+	const struct ipu_devtype *devtype = ipu->devtype;
+
+	ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
+			IPU_CONF_DI0_EN, ipu_clk);
+	if (ret) {
+		unit = "di0";
+		goto err_di_0;
+	}
+
+	ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
+			IPU_CONF_DI1_EN, ipu_clk);
+	if (ret) {
+		unit = "di1";
+		goto err_di_1;
+	}
+
+	ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
+			IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
+	if (ret) {
+		unit = "dc_template";
+		goto err_dc;
+	}
+
+	ret = ipu_dmfc_init(ipu, dev, ipu_base +
+			devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
+	if (ret) {
+		unit = "dmfc";
+		goto err_dmfc;
+	}
+
+	ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
+	if (ret) {
+		unit = "dp";
+		goto err_dp;
+	}
+
+	return 0;
+
+err_dp:
+	ipu_dmfc_exit(ipu);
+err_dmfc:
+	ipu_dc_exit(ipu);
+err_dc:
+	ipu_di_exit(ipu, 1);
+err_di_1:
+	ipu_di_exit(ipu, 0);
+err_di_0:
+	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+	return ret;
+}
+
+static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
+{
+	unsigned long status;
+	int i, bit, irq_base;
+
+	for (i = 0; i < num_regs; i++) {
+
+		status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
+		status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
+
+		irq_base = ipu->irq_start + regs[i] * 32;
+		for_each_set_bit(bit, &status, 32)
+			generic_handle_irq(irq_base + bit);
+	}
+}
+
+static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+	const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+	struct irq_chip *chip = irq_get_chip(irq);
+
+	chained_irq_enter(chip, desc);
+
+	ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+
+	chained_irq_exit(chip, desc);
+}
+
+static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+	const int int_reg[] = { 4, 5, 8, 9};
+	struct irq_chip *chip = irq_get_chip(irq);
+
+	chained_irq_enter(chip, desc);
+
+	ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+
+	chained_irq_exit(chip, desc);
+}
+
+static void ipu_ack_irq(struct irq_data *d)
+{
+	struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->irq - ipu->irq_start;
+
+	ipu_cm_write(ipu, 1 << (irq % 32), IPU_INT_STAT(irq / 32));
+}
+
+static void ipu_unmask_irq(struct irq_data *d)
+{
+	struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->irq - ipu->irq_start;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32));
+	reg |= 1 << (irq % 32);
+	ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
+static void ipu_mask_irq(struct irq_data *d)
+{
+	struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->irq - ipu->irq_start;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32));
+	reg &= ~(1 << (irq % 32));
+	ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
+static struct irq_chip ipu_irq_chip = {
+	.name = "IPU",
+	.irq_ack = ipu_ack_irq,
+	.irq_mask = ipu_mask_irq,
+	.irq_unmask = ipu_unmask_irq,
+};
+
+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+		enum ipu_channel_irq irq_type)
+{
+	return ipu->irq_start + irq_type + channel->num;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
+
+static void ipu_submodules_exit(struct ipu_soc *ipu)
+{
+	ipu_dp_exit(ipu);
+	ipu_dmfc_exit(ipu);
+	ipu_dc_exit(ipu);
+	ipu_di_exit(ipu, 1);
+	ipu_di_exit(ipu, 0);
+}
+
+static int platform_remove_devices_fn(struct device *dev, void *unused)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+	device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+}
+
+struct ipu_platform_reg {
+	struct ipu_client_platformdata pdata;
+	const char *name;
+};
+
+static const struct ipu_platform_reg client_reg[] = {
+	{
+		.pdata = {
+			.di = 0,
+			.dc = 5,
+			.dp = IPU_DP_FLOW_SYNC_BG,
+			.dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
+			.dma[1] = -EINVAL,
+		},
+		.name = "imx-ipuv3-crtc",
+	}, {
+		.pdata = {
+			.di = 1,
+			.dc = 1,
+			.dp = -EINVAL,
+			.dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
+			.dma[1] = -EINVAL,
+		},
+		.name = "imx-ipuv3-crtc",
+	},
+};
+
+static int ipu_client_id;
+
+static int ipu_add_subdevice_pdata(struct device *dev,
+		const struct ipu_platform_reg *reg)
+{
+	struct platform_device *pdev;
+
+	pdev = platform_device_register_data(dev, reg->name, ipu_client_id++,
+			&reg->pdata, sizeof(struct ipu_platform_reg));
+
+	return pdev ? 0 : -EINVAL;
+}
+
+static int ipu_add_client_devices(struct ipu_soc *ipu)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+		const struct ipu_platform_reg *reg = &client_reg[i];
+		ret = ipu_add_subdevice_pdata(ipu->dev, reg);
+		if (ret)
+			goto err_register;
+	}
+
+	return 0;
+
+err_register:
+	platform_device_unregister_children(to_platform_device(ipu->dev));
+
+	return ret;
+}
+
+static int ipu_irq_init(struct ipu_soc *ipu)
+{
+	int i;
+
+	ipu->irq_start = irq_alloc_descs(-1, 0, IPU_NUM_IRQS, 0);
+	if (ipu->irq_start < 0)
+		return ipu->irq_start;
+
+	for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) {
+		irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+		irq_set_chip_data(i, ipu);
+	}
+
+	irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler);
+	irq_set_handler_data(ipu->irq_sync, ipu);
+	irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler);
+	irq_set_handler_data(ipu->irq_err, ipu);
+
+	return 0;
+}
+
+static void ipu_irq_exit(struct ipu_soc *ipu)
+{
+	int i;
+
+	irq_set_chained_handler(ipu->irq_err, NULL);
+	irq_set_handler_data(ipu->irq_err, NULL);
+	irq_set_chained_handler(ipu->irq_sync, NULL);
+	irq_set_handler_data(ipu->irq_sync, NULL);
+
+	for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) {
+		set_irq_flags(i, 0);
+		irq_set_chip(i, NULL);
+		irq_set_chip_data(i, NULL);
+	}
+
+	irq_free_descs(ipu->irq_start, IPU_NUM_IRQS);
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(imx_ipu_dt_ids, &pdev->dev);
+	struct ipu_soc *ipu;
+	struct resource *res;
+	unsigned long ipu_base;
+	int i, ret, irq_sync, irq_err;
+	const struct ipu_devtype *devtype;
+
+	devtype = of_id->data;
+
+	dev_info(&pdev->dev, "Initializing %s\n", devtype->name);
+
+	irq_sync = platform_get_irq(pdev, 0);
+	irq_err = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	dev_info(&pdev->dev, "irq_sync: %d irq_err: %d\n",
+			irq_sync, irq_err);
+
+	if (!res || irq_sync < 0 || irq_err < 0)
+		return -ENODEV;
+
+	ipu_base = res->start;
+
+	ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
+	if (!ipu)
+		return -ENODEV;
+
+	for (i = 0; i < 64; i++)
+		ipu->channel[i].ipu = ipu;
+	ipu->devtype = devtype;
+	ipu->ipu_type = devtype->type;
+
+	spin_lock_init(&ipu->lock);
+	mutex_init(&ipu->channel_lock);
+
+	dev_info(&pdev->dev, "cm_reg:   0x%08lx\n",
+			ipu_base + devtype->cm_ofs);
+	dev_info(&pdev->dev, "idmac:    0x%08lx\n",
+			ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
+	dev_info(&pdev->dev, "cpmem:    0x%08lx\n",
+			ipu_base + devtype->cpmem_ofs);
+	dev_info(&pdev->dev, "disp0:    0x%08lx\n",
+			ipu_base + devtype->disp0_ofs);
+	dev_info(&pdev->dev, "disp1:    0x%08lx\n",
+			ipu_base + devtype->disp1_ofs);
+	dev_info(&pdev->dev, "srm:      0x%08lx\n",
+			ipu_base + devtype->srm_ofs);
+	dev_info(&pdev->dev, "tpm:      0x%08lx\n",
+			ipu_base + devtype->tpm_ofs);
+	dev_info(&pdev->dev, "dc:       0x%08lx\n",
+			ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
+	dev_info(&pdev->dev, "ic:       0x%08lx\n",
+			ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
+	dev_info(&pdev->dev, "dmfc:     0x%08lx\n",
+			ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
+	dev_info(&pdev->dev, "vdi:      0x%08lx\n",
+			ipu_base + devtype->vdi_ofs);
+
+	ipu->cm_reg = devm_ioremap(&pdev->dev,
+			ipu_base + devtype->cm_ofs, PAGE_SIZE);
+	ipu->idmac_reg = devm_ioremap(&pdev->dev,
+			ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
+			PAGE_SIZE);
+	ipu->cpmem_base = devm_ioremap(&pdev->dev,
+			ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
+
+	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) {
+		ret = -ENOMEM;
+		goto failed_ioremap;
+	}
+
+	ipu->clk = devm_clk_get(&pdev->dev, "bus");
+	if (IS_ERR(ipu->clk)) {
+		ret = PTR_ERR(ipu->clk);
+		dev_err(&pdev->dev, "clk_get failed with %d", ret);
+		goto failed_clk_get;
+	}
+
+	platform_set_drvdata(pdev, ipu);
+
+	clk_prepare_enable(ipu->clk);
+
+	ipu->dev = &pdev->dev;
+	ipu->irq_sync = irq_sync;
+	ipu->irq_err = irq_err;
+
+	ret = ipu_irq_init(ipu);
+	if (ret)
+		goto out_failed_irq;
+
+	ipu_reset(ipu);
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+			IPU_DISP_GEN);
+
+	ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
+	if (ret)
+		goto failed_submodules_init;
+
+	ret = ipu_add_client_devices(ipu);
+	if (ret) {
+		dev_err(&pdev->dev, "adding client devices failed with %d\n",
+				ret);
+		goto failed_add_clients;
+	}
+
+	return 0;
+
+failed_add_clients:
+	ipu_submodules_exit(ipu);
+failed_submodules_init:
+	ipu_irq_exit(ipu);
+out_failed_irq:
+	clk_disable_unprepare(ipu->clk);
+failed_clk_get:
+failed_ioremap:
+	return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	platform_device_unregister_children(pdev);
+	ipu_submodules_exit(ipu);
+	ipu_irq_exit(ipu);
+
+	clk_disable_unprepare(ipu->clk);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_driver = {
+	.driver = {
+		.name = "imx-ipuv3",
+		.of_match_table = imx_ipu_dt_ids,
+	},
+	.probe = ipu_probe,
+	.remove = __devexit_p(ipu_remove),
+};
+
+module_platform_driver(imx_ipu_driver);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
new file mode 100644
index 0000000..93c7579
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DC_MAP_CONF_PTR(n)	(0x108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	(0x144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+
+#define DC_WR_CH_CONF		0x0
+#define DC_WR_CH_ADDR		0x4
+#define DC_RL_CH(evt)		(8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN			0xd4
+#define DC_DISP_CONF1(disp)	(0xd8 + (disp) * 4)
+#define DC_DISP_CONF2(disp)	(0xe8 + (disp) * 4)
+#define DC_STAT			0x1c8
+
+#define WROD(lf)		(0x18 | ((lf) << 1))
+#define WRG			0x01
+
+#define SYNC_WAVE 0
+
+#define DC_GEN_SYNC_1_6_SYNC	(2 << 1)
+#define DC_GEN_SYNC_PRIORITY_1	(1 << 7)
+
+#define DC_WR_CH_CONF_WORD_SIZE_8		(0 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_16		(1 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_24		(2 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_32		(3 << 0)
+#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)	(((i) & 0x1) << 3)
+#define DC_WR_CH_CONF_DISP_ID_SERIAL		(2 << 3)
+#define DC_WR_CH_CONF_DISP_ID_ASYNC		(3 << 4)
+#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_NORMAL		(4 << 5)
+#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID(i)		(((i) & 0x1) << 3)
+
+#define IPU_DC_NUM_CHANNELS	10
+
+struct ipu_dc_priv;
+
+enum ipu_dc_map {
+	IPU_DC_MAP_RGB24,
+	IPU_DC_MAP_RGB565,
+};
+
+struct ipu_dc {
+	/* The display interface number assigned to this dc channel */
+	unsigned int		di;
+	void __iomem		*base;
+	struct ipu_dc_priv	*priv;
+	int			chno;
+	bool			in_use;
+};
+
+struct ipu_dc_priv {
+	void __iomem		*dc_reg;
+	void __iomem		*dc_tmpl_reg;
+	struct ipu_soc		*ipu;
+	struct device		*dev;
+	struct ipu_dc		channels[IPU_DC_NUM_CHANNELS];
+	struct mutex		mutex;
+};
+
+static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
+{
+	u32 reg;
+
+	reg = readl(dc->base + DC_RL_CH(event));
+	reg &= ~(0xffff << (16 * (event & 0x1)));
+	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+	writel(reg, dc->base + DC_RL_CH(event));
+}
+
+static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
+		int map, int wave, int glue, int sync)
+{
+	struct ipu_dc_priv *priv = dc->priv;
+	u32 reg;
+	int stop = 1;
+
+	reg = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
+	writel(reg, priv->dc_tmpl_reg + word * 8);
+	reg = operand >> 12 | opcode << 4 | stop << 9;
+	writel(reg, priv->dc_tmpl_reg + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+	switch (fmt) {
+	case V4L2_PIX_FMT_RGB24:
+		return IPU_DC_MAP_RGB24;
+	case V4L2_PIX_FMT_RGB565:
+		return IPU_DC_MAP_RGB565;
+	default:
+		return -EINVAL;
+	}
+}
+
+int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+		u32 pixel_fmt, u32 width)
+{
+	struct ipu_dc_priv *priv = dc->priv;
+	u32 reg = 0, map;
+
+	dc->di = ipu_di_get_num(di);
+
+	map = ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
+		return -EINVAL;
+	}
+
+	if (interlaced) {
+		dc_link_event(dc, DC_EVT_NL, 0, 3);
+		dc_link_event(dc, DC_EVT_EOL, 0, 2);
+		dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1);
+
+		/* Init template microcode */
+		dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+	} else {
+		if (dc->di) {
+			dc_link_event(dc, DC_EVT_NL, 2, 3);
+			dc_link_event(dc, DC_EVT_EOL, 3, 2);
+			dc_link_event(dc, DC_EVT_NEW_DATA, 4, 1);
+			/* Init template microcode */
+			dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		} else {
+			dc_link_event(dc, DC_EVT_NL, 5, 3);
+			dc_link_event(dc, DC_EVT_EOL, 6, 2);
+			dc_link_event(dc, DC_EVT_NEW_DATA, 7, 1);
+			/* Init template microcode */
+			dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		}
+	}
+	dc_link_event(dc, DC_EVT_NF, 0, 0);
+	dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
+	dc_link_event(dc, DC_EVT_EOF, 0, 0);
+	dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
+	dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
+	dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
+
+	reg = readl(dc->base + DC_WR_CH_CONF);
+	if (interlaced)
+		reg |= DC_WR_CH_CONF_FIELD_MODE;
+	else
+		reg &= ~DC_WR_CH_CONF_FIELD_MODE;
+	writel(reg, dc->base + DC_WR_CH_CONF);
+
+	writel(0x0, dc->base + DC_WR_CH_ADDR);
+	writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
+
+	ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+
+void ipu_dc_enable_channel(struct ipu_dc *dc)
+{
+	int di;
+	u32 reg;
+
+	di = dc->di;
+
+	reg = readl(dc->base + DC_WR_CH_CONF);
+	reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
+	writel(reg, dc->base + DC_WR_CH_CONF);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(struct ipu_dc *dc)
+{
+	struct ipu_dc_priv *priv = dc->priv;
+	u32 val;
+	int irq = 0, timeout = 50;
+
+	if (dc->chno == 1)
+		irq = IPU_IRQ_DC_FC_1;
+	else if (dc->chno == 5)
+		irq = IPU_IRQ_DP_SF_END;
+	else
+		return;
+
+	/* should wait for the interrupt here */
+	mdelay(50);
+
+	if (dc->di == 0)
+		val = 0x00000002;
+	else
+		val = 0x00000020;
+
+	/* Wait for DC triple buffer to empty */
+	while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
+		msleep(2);
+		timeout -= 2;
+		if (timeout <= 0)
+			break;
+	}
+
+	val = readl(dc->base + DC_WR_CH_CONF);
+	val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	writel(val, dc->base + DC_WR_CH_CONF);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+
+static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
+		int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xffff << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+
+	reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
+{
+	u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+
+	writel(reg & ~(0xffff << (16 * (map & 0x1))),
+		     priv->dc_reg + DC_MAP_CONF_PTR(map));
+}
+
+struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
+{
+	struct ipu_dc_priv *priv = ipu->dc_priv;
+	struct ipu_dc *dc;
+
+	if (channel >= IPU_DC_NUM_CHANNELS)
+		return ERR_PTR(-ENODEV);
+
+	dc = &priv->channels[channel];
+
+	mutex_lock(&priv->mutex);
+
+	if (dc->in_use) {
+		mutex_unlock(&priv->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	dc->in_use = 1;
+
+	mutex_unlock(&priv->mutex);
+
+	return dc;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_get);
+
+void ipu_dc_put(struct ipu_dc *dc)
+{
+	struct ipu_dc_priv *priv = dc->priv;
+
+	mutex_lock(&priv->mutex);
+	dc->in_use = 0;
+	mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_put);
+
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
+		unsigned long base, unsigned long template_base)
+{
+	struct ipu_dc_priv *priv;
+	static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
+		0x78, 0, 0x94, 0xb4};
+	int i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->mutex);
+
+	priv->dev = dev;
+	priv->ipu = ipu;
+	priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
+	priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
+	if (!priv->dc_reg || !priv->dc_tmpl_reg)
+		return -ENOMEM;
+
+	for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
+		priv->channels[i].chno = i;
+		priv->channels[i].priv = priv;
+		priv->channels[i].base = priv->dc_reg + channel_offsets[i];
+	}
+
+	writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
+			DC_WR_CH_CONF_PROG_DI_ID,
+			priv->channels[1].base + DC_WR_CH_CONF);
+	writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
+			priv->channels[5].base + DC_WR_CH_CONF);
+
+	writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN);
+
+	ipu->dc_priv = priv;
+
+	dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
+			base, template_base);
+
+	/* rgb24 */
+	ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
+
+	/* rgb565 */
+	ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
+
+	return 0;
+}
+
+void ipu_dc_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
new file mode 100644
index 0000000..67d974f
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+struct ipu_di {
+	void __iomem *base;
+	int id;
+	u32 module;
+	struct clk *clk_di;	/* display input clock */
+	struct clk *clk_ipu;	/* IPU bus clock */
+	struct clk *clk_di_pixel; /* resulting pixel clock */
+	struct clk_hw clk_hw_out;
+	char *clk_name;
+	bool inuse;
+	unsigned long clkflags;
+	struct ipu_soc *ipu;
+};
+
+static DEFINE_MUTEX(di_mutex);
+
+struct di_sync_config {
+	int run_count;
+	int run_src;
+	int offset_count;
+	int offset_src;
+	int repeat_count;
+	int cnt_clr_src;
+	int cnt_polarity_gen_en;
+	int cnt_polarity_clr_src;
+	int cnt_polarity_trigger_src;
+	int cnt_up;
+	int cnt_down;
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = 0,
+	DI_SYNC_CLK = 1,
+	DI_SYNC_INT_HSYNC = 2,
+	DI_SYNC_HSYNC = 3,
+	DI_SYNC_VSYNC = 4,
+	DI_SYNC_DE = 6,
+};
+
+#define SYNC_WAVE 0
+
+#define DI_GENERAL		0x0000
+#define DI_BS_CLKGEN0		0x0004
+#define DI_BS_CLKGEN1		0x0008
+#define DI_SW_GEN0(gen)		(0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		(0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN		0x0054
+#define DI_DW_GEN(gen)		(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	(0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF		0x015c
+#define DI_SSC			0x0160
+#define DI_POL			0x0164
+#define DI_AW0			0x0168
+#define DI_AW1			0x016c
+#define DI_SCR_CONF		0x0170
+#define DI_STAT			0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x)			((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x)			((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x)		((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x)		((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x)		((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x)		((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)	((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)		((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x)			((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x)			(x)
+#define DI_SW_GEN1_AUTO_RELOAD			(0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET		24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET		16
+
+#define DI_GEN_POLARITY_1			(1 << 0)
+#define DI_GEN_POLARITY_2			(1 << 1)
+#define DI_GEN_POLARITY_3			(1 << 2)
+#define DI_GEN_POLARITY_4			(1 << 3)
+#define DI_GEN_POLARITY_5			(1 << 4)
+#define DI_GEN_POLARITY_6			(1 << 5)
+#define DI_GEN_POLARITY_7			(1 << 6)
+#define DI_GEN_POLARITY_8			(1 << 7)
+#define DI_GEN_POLARITY_DISP_CLK		(1 << 17)
+#define DI_GEN_DI_CLK_EXT			(1 << 20)
+#define DI_GEN_DI_VSYNC_EXT			(1 << 21)
+
+#define DI_POL_DRDY_DATA_POLARITY		(1 << 7)
+#define DI_POL_DRDY_POLARITY_15			(1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET			13
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+	return readl(di->base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+	writel(value, di->base + offset);
+}
+
+static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
+{
+	u64 tmp = inrate;
+	int div;
+
+	tmp *= 16;
+
+	do_div(tmp, outrate);
+
+	div = tmp;
+
+	if (div < 0x10)
+		div = 0x10;
+
+#ifdef WTF_IS_THIS
+	/*
+	 * Freescale has this in their Kernel. It is neither clear what
+	 * it does nor why it does it
+	 */
+	if (div & 0x10)
+		div &= ~0x7;
+	else {
+		/* Round up divider if it gets us closer to desired pix clk */
+		if ((div & 0xC) == 0xC) {
+			div += 0x10;
+			div &= ~0xF;
+		}
+	}
+#endif
+	return div;
+}
+
+static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+	unsigned long outrate;
+	u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
+
+	if (div < 0x10)
+		div = 0x10;
+
+	outrate = (parent_rate / div) * 16;
+
+	return outrate;
+}
+
+static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+	unsigned long outrate;
+	int div;
+	u32 val;
+
+	div = ipu_di_clk_calc_div(*prate, rate);
+
+	outrate = (*prate / div) * 16;
+
+	val = ipu_di_read(di, DI_GENERAL);
+
+	if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
+		outrate = *prate / 2;
+
+	dev_dbg(di->ipu->dev,
+		"%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
+			__func__, *prate, div, outrate, rate);
+
+	return outrate;
+}
+
+static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+	int div;
+	u32 clkgen0;
+
+	clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
+
+	div = ipu_di_clk_calc_div(parent_rate, rate);
+
+	ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
+
+	dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
+			__func__, parent_rate, rate, div);
+	return 0;
+}
+
+static u8 clk_di_get_parent(struct clk_hw *hw)
+{
+	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+	u32 val;
+
+	val = ipu_di_read(di, DI_GENERAL);
+
+	return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
+}
+
+static int clk_di_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+	u32 val;
+
+	val = ipu_di_read(di, DI_GENERAL);
+
+	if (index)
+		val |= DI_GEN_DI_CLK_EXT;
+	else
+		val &= ~DI_GEN_DI_CLK_EXT;
+
+	ipu_di_write(di, val, DI_GENERAL);
+
+	return 0;
+}
+
+static struct clk_ops clk_di_ops = {
+	.round_rate = clk_di_round_rate,
+	.set_rate = clk_di_set_rate,
+	.recalc_rate = clk_di_recalc_rate,
+	.set_parent = clk_di_set_parent,
+	.get_parent = clk_di_get_parent,
+};
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+				     int wave_gen,
+				     int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
+		int set, int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
+		int start, int count)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct di_sync_config *c = &config[i];
+		int wave_gen = start + i + 1;
+
+		if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
+				(c->repeat_count >= 0x1000) ||
+				(c->cnt_up >= 0x400) ||
+				(c->cnt_down >= 0x400)) {
+			dev_err(di->ipu->dev, "DI%d counters out of range.\n",
+					di->id);
+			return;
+		}
+
+		reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+			DI_SW_GEN0_RUN_SRC(c->run_src) |
+			DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+			DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+		ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+		reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+			DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+			DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
+					c->cnt_polarity_trigger_src) |
+			DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+			DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+			DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+		/* Enable auto reload */
+		if (c->repeat_count == 0)
+			reg |= DI_SW_GEN1_AUTO_RELOAD;
+
+		ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+		reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+		reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+		reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+		ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+	}
+}
+
+static void ipu_di_sync_config_interlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig)
+{
+	u32 h_total = sig->width + sig->h_sync_width +
+		sig->h_start_width + sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width +
+		sig->v_start_width + sig->v_end_width;
+	u32 reg;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total / 2 - 1,
+			.run_src = DI_SYNC_CLK,
+		}, {
+			.run_count = h_total - 11,
+			.run_src = DI_SYNC_CLK,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total * 2 - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = 1,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height / 2,
+			.cnt_clr_src = 4,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_HSYNC,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = 9,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = v_total / 2,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_clr_src = DI_SYNC_HSYNC,
+			.cnt_down = 4,
+		}
+	};
+
+	ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+
+	/* set gentime select and tag sel */
+	reg = ipu_di_read(di, DI_SW_GEN1(9));
+	reg &= 0x1FFFFFFF;
+	reg |= (3 - 1) << 29 | 0x00008000;
+	ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+	ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+}
+
+static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig, int div)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+		} , {
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+			.offset_count = div * sig->v_to_h_sync,
+			.offset_src = DI_SYNC_CLK,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_CLK,
+			.cnt_down = sig->h_sync_width * 2,
+		} , {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = sig->v_sync_width * 2,
+		} , {
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		} , {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		},
+	};
+
+	ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+	ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 reg;
+	u32 di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+	int ret;
+	unsigned long round;
+	struct clk *parent;
+
+	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+		di->id, sig->width, sig->height);
+
+	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+		return -EINVAL;
+
+	if (sig->clkflags & IPU_DI_CLKMODE_EXT)
+		parent = di->clk_di;
+	else
+		parent = di->clk_ipu;
+
+	ret = clk_set_parent(di->clk_di_pixel, parent);
+	if (ret) {
+		dev_err(di->ipu->dev,
+			"setting pixel clock to parent %s failed with %d\n",
+				__clk_get_name(parent), ret);
+		return ret;
+	}
+
+	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
+		round = clk_get_rate(parent);
+	else
+		round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
+
+	ret = clk_set_rate(di->clk_di_pixel, round);
+
+	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width;
+
+	mutex_lock(&di_mutex);
+
+	div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
+	div = div / 16;		/* Now divider is integer portion */
+
+	/* Setup pixel clock timing */
+	/* Down time is half of period */
+	ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
+
+	ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
+	ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+	di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
+	di_gen |= DI_GEN_DI_VSYNC_EXT;
+
+	if (sig->interlaced) {
+		ipu_di_sync_config_interlaced(di, sig);
+
+		/* set y_sel = 1 */
+		di_gen |= 0x10000000;
+		di_gen |= DI_GEN_POLARITY_5;
+		di_gen |= DI_GEN_POLARITY_8;
+
+		vsync_cnt = 7;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		ipu_di_sync_config_noninterlaced(di, sig, div);
+
+		vsync_cnt = 3;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+	}
+
+	if (!sig->clk_pol)
+		di_gen |= DI_GEN_POLARITY_DISP_CLK;
+
+	ipu_di_write(di, di_gen, DI_GENERAL);
+
+	ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+		     DI_SYNC_AS_GEN);
+
+	reg = ipu_di_read(di, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+	if (sig->enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig->data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+
+	ipu_di_write(di, reg, DI_POL);
+
+	mutex_unlock(&di_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+	clk_prepare_enable(di->clk_di_pixel);
+
+	ipu_module_enable(di->ipu, di->module);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+	ipu_module_disable(di->ipu, di->module);
+
+	clk_disable_unprepare(di->clk_di_pixel);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_disable);
+
+int ipu_di_get_num(struct ipu_di *di)
+{
+	return di->id;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get_num);
+
+static DEFINE_MUTEX(ipu_di_lock);
+
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+{
+	struct ipu_di *di;
+
+	if (disp > 1)
+		return ERR_PTR(-EINVAL);
+
+	di = ipu->di_priv[disp];
+
+	mutex_lock(&ipu_di_lock);
+
+	if (di->inuse) {
+		di = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	di->inuse = true;
+out:
+	mutex_unlock(&ipu_di_lock);
+
+	return di;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+	mutex_lock(&ipu_di_lock);
+
+	di->inuse = false;
+
+	mutex_unlock(&ipu_di_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_di_put);
+
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+		unsigned long base,
+		u32 module, struct clk *clk_ipu)
+{
+	struct ipu_di *di;
+	int ret;
+	const char *di_parent[2];
+	struct clk_init_data init = {
+		.ops = &clk_di_ops,
+		.num_parents = 2,
+		.flags = 0,
+	};
+
+	if (id > 1)
+		return -ENODEV;
+
+	di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	ipu->di_priv[id] = di;
+
+	di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
+	if (IS_ERR(di->clk_di))
+		return PTR_ERR(di->clk_di);
+
+	di->module = module;
+	di->id = id;
+	di->clk_ipu = clk_ipu;
+	di->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!di->base)
+		return -ENOMEM;
+
+	di_parent[0] = __clk_get_name(di->clk_ipu);
+	di_parent[1] = __clk_get_name(di->clk_di);
+
+	ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
+
+	init.parent_names = (const char **)&di_parent;
+	di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
+			dev_name(dev), id);
+	if (!di->clk_name)
+		return -ENOMEM;
+
+	init.name = di->clk_name;
+
+	di->clk_hw_out.init = &init;
+	di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
+
+	if (IS_ERR(di->clk_di_pixel)) {
+		ret = PTR_ERR(di->clk_di_pixel);
+		goto failed_clk_register;
+	}
+
+	dev_info(dev, "DI%d base: 0x%08lx remapped to %p\n",
+			id, base, di->base);
+	di->inuse = false;
+	di->ipu = ipu;
+
+	return 0;
+
+failed_clk_register:
+
+	kfree(di->clk_name);
+
+	return ret;
+}
+
+void ipu_di_exit(struct ipu_soc *ipu, int id)
+{
+	struct ipu_di *di = ipu->di_priv[id];
+
+	clk_unregister(di->clk_di_pixel);
+	kfree(di->clk_name);
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
new file mode 100644
index 0000000..91821bc
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN		0x0000
+#define DMFC_WR_CHAN		0x0004
+#define DMFC_WR_CHAN_DEF	0x0008
+#define DMFC_DP_CHAN		0x000c
+#define DMFC_DP_CHAN_DEF	0x0010
+#define DMFC_GENERAL1		0x0014
+#define DMFC_GENERAL2		0x0018
+#define DMFC_IC_CTRL		0x001c
+#define DMFC_STAT		0x0020
+
+#define DMFC_WR_CHAN_1_28		0
+#define DMFC_WR_CHAN_2_41		8
+#define DMFC_WR_CHAN_1C_42		16
+#define DMFC_WR_CHAN_2C_43		24
+
+#define DMFC_DP_CHAN_5B_23		0
+#define DMFC_DP_CHAN_5F_27		8
+#define DMFC_DP_CHAN_6B_24		16
+#define DMFC_DP_CHAN_6F_29		24
+
+#define DMFC_FIFO_SIZE_64		(3 << 3)
+#define DMFC_FIFO_SIZE_128		(2 << 3)
+#define DMFC_FIFO_SIZE_256		(1 << 3)
+#define DMFC_FIFO_SIZE_512		(0 << 3)
+
+#define DMFC_SEGMENT(x)			((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_128		(0 << 6)
+#define DMFC_BURSTSIZE_64		(1 << 6)
+#define DMFC_BURSTSIZE_32		(2 << 6)
+#define DMFC_BURSTSIZE_16		(3 << 6)
+
+struct dmfc_channel_data {
+	int		ipu_channel;
+	unsigned long	channel_reg;
+	unsigned long	shift;
+	unsigned	eot_shift;
+	unsigned	max_fifo_lines;
+};
+
+static const struct dmfc_channel_data dmfcdata[] = {
+	{
+		.ipu_channel	= 23,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5B_23,
+		.eot_shift	= 20,
+		.max_fifo_lines	= 3,
+	}, {
+		.ipu_channel	= 24,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6B_24,
+		.eot_shift	= 22,
+		.max_fifo_lines	= 1,
+	}, {
+		.ipu_channel	= 27,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5F_27,
+		.eot_shift	= 21,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 28,
+		.channel_reg	= DMFC_WR_CHAN,
+		.shift		= DMFC_WR_CHAN_1_28,
+		.eot_shift	= 16,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 29,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6F_29,
+		.eot_shift	= 23,
+		.max_fifo_lines	= 1,
+	},
+};
+
+#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcdata)
+
+struct ipu_dmfc_priv;
+
+struct dmfc_channel {
+	unsigned			slots;
+	unsigned			slotmask;
+	unsigned			segment;
+	int				burstsize;
+	struct ipu_soc			*ipu;
+	struct ipu_dmfc_priv		*priv;
+	const struct dmfc_channel_data	*data;
+};
+
+struct ipu_dmfc_priv {
+	struct ipu_soc *ipu;
+	struct device *dev;
+	struct dmfc_channel channels[DMFC_NUM_CHANNELS];
+	struct mutex mutex;
+	unsigned long bandwidth_per_slot;
+	void __iomem *base;
+	int use_count;
+};
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+	mutex_lock(&priv->mutex);
+
+	if (!priv->use_count)
+		ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
+
+	priv->use_count++;
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+
+	mutex_lock(&priv->mutex);
+
+	priv->use_count--;
+
+	if (!priv->use_count)
+		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
+
+	if (priv->use_count < 0)
+		priv->use_count = 0;
+
+	mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
+		int segment, int burstsize)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+	u32 val, field;
+
+	dev_dbg(priv->dev,
+			"dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+			slots, segment, dmfc->data->ipu_channel);
+
+	if (!dmfc)
+		return -EINVAL;
+
+	switch (slots) {
+	case 1:
+		field = DMFC_FIFO_SIZE_64;
+		break;
+	case 2:
+		field = DMFC_FIFO_SIZE_128;
+		break;
+	case 4:
+		field = DMFC_FIFO_SIZE_256;
+		break;
+	case 8:
+		field = DMFC_FIFO_SIZE_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (burstsize) {
+	case 16:
+		field |= DMFC_BURSTSIZE_16;
+		break;
+	case 32:
+		field |= DMFC_BURSTSIZE_32;
+		break;
+	case 64:
+		field |= DMFC_BURSTSIZE_64;
+		break;
+	case 128:
+		field |= DMFC_BURSTSIZE_128;
+		break;
+	}
+
+	field |= DMFC_SEGMENT(segment);
+
+	val = readl(priv->base + dmfc->data->channel_reg);
+
+	val &= ~(0xff << dmfc->data->shift);
+	val |= field << dmfc->data->shift;
+
+	writel(val, priv->base + dmfc->data->channel_reg);
+
+	dmfc->slots = slots;
+	dmfc->segment = segment;
+	dmfc->burstsize = burstsize;
+	dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+	return 0;
+}
+
+static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
+		unsigned long bandwidth)
+{
+	int slots = 1;
+
+	while (slots * priv->bandwidth_per_slot < bandwidth)
+		slots *= 2;
+
+	return slots;
+}
+
+static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
+{
+	unsigned slotmask_need, slotmask_used = 0;
+	int i, segment = 0;
+
+	slotmask_need = (1 << slots) - 1;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		slotmask_used |= priv->channels[i].slotmask;
+
+	while (slotmask_need <= 0xff) {
+		if (!(slotmask_used & slotmask_need))
+			return segment;
+
+		slotmask_need <<= 1;
+		segment++;
+	}
+
+	return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+	int i;
+
+	dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
+			dmfc->slots, dmfc->segment);
+
+	mutex_lock(&priv->mutex);
+
+	if (!dmfc->slots)
+		goto out;
+
+	dmfc->slotmask = 0;
+	dmfc->slots = 0;
+	dmfc->segment = 0;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		priv->channels[i].slotmask = 0;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+		if (priv->channels[i].slots > 0) {
+			priv->channels[i].segment =
+				dmfc_find_slots(priv, priv->channels[i].slots);
+			priv->channels[i].slotmask =
+				((1 << priv->channels[i].slots) - 1) <<
+				priv->channels[i].segment;
+		}
+	}
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+		if (priv->channels[i].slots > 0)
+			ipu_dmfc_setup_channel(&priv->channels[i],
+					priv->channels[i].slots,
+					priv->channels[i].segment,
+					priv->channels[i].burstsize);
+	}
+out:
+	mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_pixel_per_second, int burstsize)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+	int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
+	int segment = 0, ret = 0;
+
+	dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+			bandwidth_pixel_per_second / 1000000,
+			dmfc->data->ipu_channel);
+
+	ipu_dmfc_free_bandwidth(dmfc);
+
+	mutex_lock(&priv->mutex);
+
+	if (slots > 8) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	segment = dmfc_find_slots(priv, slots);
+	if (segment < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
+
+out:
+	mutex_unlock(&priv->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+	struct ipu_dmfc_priv *priv = dmfc->priv;
+	u32 dmfc_gen1;
+
+	dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
+
+	if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
+		dmfc_gen1 |= 1 << dmfc->data->eot_shift;
+	else
+		dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
+
+	writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+{
+	struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
+	int i;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		if (dmfcdata[i].ipu_channel == ipu_channel)
+			return &priv->channels[i];
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+	ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+		struct clk *ipu_clk)
+{
+	struct ipu_dmfc_priv *priv;
+	int i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!priv->base)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->ipu = ipu;
+	mutex_init(&priv->mutex);
+
+	ipu->dmfc_priv = priv;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+		priv->channels[i].priv = priv;
+		priv->channels[i].ipu = ipu;
+		priv->channels[i].data = &dmfcdata[i];
+	}
+
+	writel(0x0, priv->base + DMFC_WR_CHAN);
+	writel(0x0, priv->base + DMFC_DP_CHAN);
+
+	/*
+	 * We have a total bandwidth of clkrate * 4pixel divided
+	 * into 8 slots.
+	 */
+	priv->bandwidth_per_slot = clk_get_rate(ipu_clk) / 8;
+
+	dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+			priv->bandwidth_per_slot / 1000000);
+
+	writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
+	writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
+	writel(0x00000003, priv->base + DMFC_GENERAL1);
+
+	return 0;
+}
+
+void ipu_dmfc_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
new file mode 100644
index 0000000..26aecaf
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF		0x0
+#define DP_GRAPH_WIND_CTRL	0x0004
+#define DP_FG_POS		0x0008
+#define DP_CSC_A_0		0x0044
+#define DP_CSC_A_1		0x0048
+#define DP_CSC_A_2		0x004C
+#define DP_CSC_A_3		0x0050
+#define DP_CSC_0		0x0054
+#define DP_CSC_1		0x0058
+
+#define DP_COM_CONF_FG_EN		(1 << 0)
+#define DP_COM_CONF_GWSEL		(1 << 1)
+#define DP_COM_CONF_GWAM		(1 << 2)
+#define DP_COM_CONF_GWCKE		(1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET	8
+#define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
+
+struct ipu_dp_priv;
+
+struct ipu_dp {
+	u32 flow;
+	bool in_use;
+	bool foreground;
+	enum ipu_color_space in_cs;
+};
+
+struct ipu_flow {
+	struct ipu_dp foreground;
+	struct ipu_dp background;
+	enum ipu_color_space out_cs;
+	void __iomem *base;
+	struct ipu_dp_priv *priv;
+};
+
+struct ipu_dp_priv {
+	struct ipu_soc *ipu;
+	struct device *dev;
+	void __iomem *base;
+	struct ipu_flow flow[3];
+	struct mutex mutex;
+	int use_count;
+};
+
+static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+
+static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
+{
+	if (dp->foreground)
+		return container_of(dp, struct ipu_flow, foreground);
+	else
+		return container_of(dp, struct ipu_flow, background);
+}
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
+		u8 alpha, bool bg_chan)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+	u32 reg;
+
+	mutex_lock(&priv->mutex);
+
+	reg = readl(flow->base + DP_COM_CONF);
+	if (bg_chan)
+		reg &= ~DP_COM_CONF_GWSEL;
+	else
+		reg |= DP_COM_CONF_GWSEL;
+	writel(reg, flow->base + DP_COM_CONF);
+
+	if (enable) {
+		reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
+		writel(reg | ((u32) alpha << 24),
+			     flow->base + DP_GRAPH_WIND_CTRL);
+
+		reg = readl(flow->base + DP_COM_CONF);
+		writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+	} else {
+		reg = readl(flow->base + DP_COM_CONF);
+		writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+	}
+
+	ipu_srm_dp_sync_update(priv->ipu);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+
+	writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
+
+	ipu_srm_dp_sync_update(priv->ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+
+static void ipu_dp_csc_init(struct ipu_flow *flow,
+		enum ipu_color_space in,
+		enum ipu_color_space out,
+		u32 place)
+{
+	u32 reg;
+
+	reg = readl(flow->base + DP_COM_CONF);
+	reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+	if (in == out) {
+		writel(reg, flow->base + DP_COM_CONF);
+		return;
+	}
+
+	if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
+		writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
+		writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
+		writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
+		writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
+		writel(0x3d6 | (0x0000 << 16) | (2 << 30),
+				flow->base + DP_CSC_0);
+		writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
+				flow->base + DP_CSC_1);
+	} else {
+		writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
+		writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
+		writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
+		writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
+		writel(0x000 | (0x3e42 << 16) | (1 << 30),
+				flow->base + DP_CSC_0);
+		writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
+				flow->base + DP_CSC_1);
+	}
+
+	reg |= place;
+
+	writel(reg, flow->base + DP_COM_CONF);
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp,
+		enum ipu_color_space in,
+		enum ipu_color_space out)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+
+	mutex_lock(&priv->mutex);
+
+	dp->in_cs = in;
+
+	if (!dp->foreground)
+		flow->out_cs = out;
+
+	if (flow->foreground.in_cs == flow->background.in_cs) {
+		/*
+		 * foreground and background are of same colorspace, put
+		 * colorspace converter after combining unit.
+		 */
+		ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
+				DP_COM_CONF_CSC_DEF_BOTH);
+	} else {
+		if (flow->foreground.in_cs == flow->out_cs)
+			/*
+			 * foreground identical to output, apply color
+			 * conversion on background
+			 */
+			ipu_dp_csc_init(flow, flow->background.in_cs,
+					flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
+		else
+			ipu_dp_csc_init(flow, flow->foreground.in_cs,
+					flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
+	}
+
+	ipu_srm_dp_sync_update(priv->ipu);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+
+	mutex_lock(&priv->mutex);
+
+	if (!priv->use_count)
+		ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
+
+	priv->use_count++;
+
+	if (dp->foreground) {
+		u32 reg;
+
+		reg = readl(flow->base + DP_COM_CONF);
+		reg |= DP_COM_CONF_FG_EN;
+		writel(reg, flow->base + DP_COM_CONF);
+
+		ipu_srm_dp_sync_update(priv->ipu);
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+
+	mutex_lock(&priv->mutex);
+
+	priv->use_count--;
+
+	if (dp->foreground) {
+		u32 reg, csc;
+
+		reg = readl(flow->base + DP_COM_CONF);
+		csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+		if (csc == DP_COM_CONF_CSC_DEF_FG)
+			reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+		reg &= ~DP_COM_CONF_FG_EN;
+		writel(reg, flow->base + DP_COM_CONF);
+
+		writel(0, flow->base + DP_FG_POS);
+		ipu_srm_dp_sync_update(priv->ipu);
+	}
+
+	if (!priv->use_count)
+		ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
+
+	if (priv->use_count < 0)
+		priv->use_count = 0;
+
+	mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
+{
+	struct ipu_dp_priv *priv = ipu->dp_priv;
+	struct ipu_dp *dp;
+
+	if (flow > 5)
+		return ERR_PTR(-EINVAL);
+
+	if (flow & 1)
+		dp = &priv->flow[flow >> 1].foreground;
+	else
+		dp = &priv->flow[flow >> 1].background;
+
+	if (dp->in_use)
+		return ERR_PTR(-EBUSY);
+
+	dp->in_use = true;
+
+	return dp;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+	dp->in_use = false;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_put);
+
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+{
+	struct ipu_dp_priv *priv;
+	int i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	priv->dev = dev;
+	priv->ipu = ipu;
+
+	ipu->dp_priv = priv;
+
+	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!priv->base) {
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	mutex_init(&priv->mutex);
+
+	for (i = 0; i < 3; i++) {
+		priv->flow[i].foreground.foreground = 1;
+		priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
+		priv->flow[i].priv = priv;
+	}
+
+	return 0;
+}
+
+void ipu_dp_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
new file mode 100644
index 0000000..5518028
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+struct ipu_soc;
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "imx-ipu-v3.h"
+
+#define IPUV3_CHANNEL_CSI0			 0
+#define IPUV3_CHANNEL_CSI1			 1
+#define IPUV3_CHANNEL_CSI2			 2
+#define IPUV3_CHANNEL_CSI3			 3
+#define IPUV3_CHANNEL_MEM_BG_SYNC		23
+#define IPUV3_CHANNEL_MEM_FG_SYNC		27
+#define IPUV3_CHANNEL_MEM_DC_SYNC		28
+#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA		31
+#define IPUV3_CHANNEL_MEM_DC_ASYNC		41
+#define IPUV3_CHANNEL_ROT_ENC_MEM		45
+#define IPUV3_CHANNEL_ROT_VF_MEM		46
+#define IPUV3_CHANNEL_ROT_PP_MEM		47
+#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT		48
+#define IPUV3_CHANNEL_ROT_VF_MEM_OUT		49
+#define IPUV3_CHANNEL_ROT_PP_MEM_OUT		50
+#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA		51
+
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_CM_IDMAC_REG_OFS	0x00008000
+#define IPU_CM_IC_REG_OFS	0x00020000
+#define IPU_CM_IRT_REG_OFS	0x00028000
+#define IPU_CM_CSI0_REG_OFS	0x00030000
+#define IPU_CM_CSI1_REG_OFS	0x00038000
+#define IPU_CM_SMFC_REG_OFS	0x00050000
+#define IPU_CM_DC_REG_OFS	0x00058000
+#define IPU_CM_DMFC_REG_OFS	0x00060000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)	(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00b8)
+#define IPU_SKIP			IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00d4)
+#define IPU_SNOOP			IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00dc)
+#define IPU_PM				IPU_CM_REG(0x00e0)
+#define IPU_GPR				IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT			IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT		IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * (n))
+#define IPU_INT_STAT(n)		IPU_CM_REG(0x0200 + 4 * (n))
+
+#define IPU_DI0_COUNTER_RELEASE			(1 << 24)
+#define IPU_DI1_COUNTER_RELEASE			(1 << 25)
+
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)		IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA			IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA		IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)		IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)			IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1		IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2		IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0		IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1		IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2		IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch)		IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch)		IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+#define IPU_NUM_IRQS	(32 * 5)
+
+enum ipu_modules {
+	IPU_CONF_CSI0_EN		= (1 << 0),
+	IPU_CONF_CSI1_EN		= (1 << 1),
+	IPU_CONF_IC_EN			= (1 << 2),
+	IPU_CONF_ROT_EN			= (1 << 3),
+	IPU_CONF_ISP_EN			= (1 << 4),
+	IPU_CONF_DP_EN			= (1 << 5),
+	IPU_CONF_DI0_EN			= (1 << 6),
+	IPU_CONF_DI1_EN			= (1 << 7),
+	IPU_CONF_SMFC_EN		= (1 << 8),
+	IPU_CONF_DC_EN			= (1 << 9),
+	IPU_CONF_DMFC_EN		= (1 << 10),
+
+	IPU_CONF_VDI_EN			= (1 << 12),
+
+	IPU_CONF_IDMAC_DIS		= (1 << 22),
+
+	IPU_CONF_IC_DMFC_SEL		= (1 << 25),
+	IPU_CONF_IC_DMFC_SYNC		= (1 << 26),
+	IPU_CONF_VDI_DMFC_SYNC		= (1 << 27),
+
+	IPU_CONF_CSI0_DATA_SOURCE	= (1 << 28),
+	IPU_CONF_CSI1_DATA_SOURCE	= (1 << 29),
+	IPU_CONF_IC_INPUT		= (1 << 30),
+	IPU_CONF_CSI_SEL		= (1 << 31),
+};
+
+struct ipuv3_channel {
+	unsigned int num;
+
+	bool enabled;
+	bool busy;
+
+	struct ipu_soc *ipu;
+};
+
+struct ipu_dc_priv;
+struct ipu_dmfc_priv;
+struct ipu_di;
+struct ipu_devtype;
+
+struct ipu_soc {
+	struct device		*dev;
+	const struct ipu_devtype	*devtype;
+	enum ipuv3_type		ipu_type;
+	spinlock_t		lock;
+	struct mutex		channel_lock;
+
+	void __iomem		*cm_reg;
+	void __iomem		*idmac_reg;
+	struct ipu_ch_param __iomem	*cpmem_base;
+
+	int			usecount;
+
+	struct clk		*clk;
+
+	struct ipuv3_channel	channel[64];
+
+	int			irq_start;
+	int			irq_sync;
+	int			irq_err;
+
+	struct ipu_dc_priv	*dc_priv;
+	struct ipu_dp_priv	*dp_priv;
+	struct ipu_dmfc_priv	*dmfc_priv;
+	struct ipu_di		*di_priv[2];
+};
+
+void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+		unsigned long base, u32 module, struct clk *ipu_clk);
+void ipu_di_exit(struct ipu_soc *ipu, int id);
+
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+		struct clk *ipu_clk);
+void ipu_dmfc_exit(struct ipu_soc *ipu);
+
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+void ipu_dp_exit(struct ipu_soc *ipu);
+
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+		unsigned long template_base);
+void ipu_dc_exit(struct ipu_soc *ipu);
+
+int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+void ipu_cpmem_exit(struct ipu_soc *ipu);
+
+#endif				/* __IPU_PRV_H__ */
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
new file mode 100644
index 0000000..78d3eda
--- /dev/null
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -0,0 +1,579 @@
+/*
+ * i.MX IPUv3 Graphics driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "ipu-v3/imx-ipu-v3.h"
+#include "imx-drm.h"
+
+#define DRIVER_DESC		"i.MX IPUv3 Graphics"
+
+struct ipu_framebuffer {
+	struct drm_framebuffer	base;
+	void			*virt;
+	dma_addr_t		phys;
+	size_t			len;
+};
+
+struct ipu_crtc {
+	struct drm_fb_helper	fb_helper;
+	struct ipu_framebuffer	ifb;
+	int			num_crtcs;
+	struct device		*dev;
+	struct drm_crtc		base;
+	struct imx_drm_crtc	*imx_crtc;
+	struct ipuv3_channel	*ipu_ch;
+	struct ipu_dc		*dc;
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct ipu_di		*di;
+	int			enabled;
+	struct ipu_priv		*ipu_priv;
+	struct drm_pending_vblank_event *page_flip_event;
+	struct drm_framebuffer	*newfb;
+	int			irq;
+	u32			interface_pix_fmt;
+	unsigned long		di_clkflags;
+};
+
+#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
+
+static int calc_vref(struct drm_display_mode *mode)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = mode->htotal;
+	vtotal = mode->vtotal;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return mode->clock * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref)
+{
+	return mode->hdisplay * mode->vdisplay * vref;
+}
+
+static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
+{
+	if (ipu_crtc->enabled)
+		return;
+
+	ipu_di_enable(ipu_crtc->di);
+	ipu_dmfc_enable_channel(ipu_crtc->dmfc);
+	ipu_idmac_enable_channel(ipu_crtc->ipu_ch);
+	ipu_dc_enable_channel(ipu_crtc->dc);
+	if (ipu_crtc->dp)
+		ipu_dp_enable_channel(ipu_crtc->dp);
+
+	ipu_crtc->enabled = 1;
+}
+
+static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
+{
+	if (!ipu_crtc->enabled)
+		return;
+
+	if (ipu_crtc->dp)
+		ipu_dp_disable_channel(ipu_crtc->dp);
+	ipu_dc_disable_channel(ipu_crtc->dc);
+	ipu_idmac_disable_channel(ipu_crtc->ipu_ch);
+	ipu_dmfc_disable_channel(ipu_crtc->dmfc);
+	ipu_di_disable(ipu_crtc->di);
+
+	ipu_crtc->enabled = 0;
+}
+
+static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	dev_info(ipu_crtc->dev, "%s mode: %d\n", __func__, mode);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		ipu_fb_enable(ipu_crtc);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		ipu_fb_disable(ipu_crtc);
+		break;
+	}
+}
+
+static int ipu_page_flip(struct drm_crtc *crtc,
+		struct drm_framebuffer *fb,
+		struct drm_pending_vblank_event *event)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	int ret;
+
+	if (ipu_crtc->newfb)
+		return -EBUSY;
+
+	ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
+	if (ret) {
+		dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
+		list_del(&event->base.link);
+
+		return ret;
+	}
+
+	ipu_crtc->newfb = fb;
+	ipu_crtc->page_flip_event = event;
+
+	return 0;
+}
+
+static const struct drm_crtc_funcs ipu_crtc_funcs = {
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.page_flip = ipu_page_flip,
+};
+
+static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct drm_gem_cma_object *cma_obj;
+	struct drm_framebuffer *fb = crtc->fb;
+	unsigned long phys;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!cma_obj) {
+		DRM_LOG_KMS("entry is null.\n");
+		return -EFAULT;
+	}
+
+	phys = cma_obj->paddr;
+	phys += x * (fb->bits_per_pixel >> 3);
+	phys += y * fb->pitches[0];
+
+	dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys);
+	dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y);
+
+	ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]);
+	ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch),
+			  0, phys);
+
+	return 0;
+}
+
+static int ipu_crtc_mode_set(struct drm_crtc *crtc,
+			       struct drm_display_mode *orig_mode,
+			       struct drm_display_mode *mode,
+			       int x, int y,
+			       struct drm_framebuffer *old_fb)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct drm_framebuffer *fb = ipu_crtc->base.fb;
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg = {};
+	u32 out_pixel_fmt;
+	struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch);
+	int bpp;
+	u32 v4l2_fmt;
+
+	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
+			mode->hdisplay);
+	dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
+			mode->vdisplay);
+
+	ipu_ch_param_zero(cpmem);
+
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		v4l2_fmt = V4L2_PIX_FMT_RGB32;
+		bpp = 32;
+		break;
+	case DRM_FORMAT_RGB565:
+		v4l2_fmt = V4L2_PIX_FMT_RGB565;
+		bpp = 16;
+		break;
+	case DRM_FORMAT_RGB888:
+		v4l2_fmt = V4L2_PIX_FMT_RGB24;
+		bpp = 24;
+		break;
+	default:
+		dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n",
+				fb->pixel_format);
+		return -EINVAL;
+	}
+
+	out_pixel_fmt = ipu_crtc->interface_pix_fmt;
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		sig_cfg.interlaced = 1;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		sig_cfg.Hsync_pol = 1;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		sig_cfg.Vsync_pol = 1;
+
+	sig_cfg.enable_pol = 1;
+	sig_cfg.clk_pol = 0;
+	sig_cfg.width = mode->hdisplay;
+	sig_cfg.height = mode->vdisplay;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
+	sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
+	sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
+
+	sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
+	sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
+	sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
+	sig_cfg.pixelclock = mode->clock * 1000;
+	sig_cfg.clkflags = ipu_crtc->di_clkflags;
+
+	sig_cfg.v_to_h_sync = 0;
+
+	if (ipu_crtc->dp) {
+		ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
+				IPUV3_COLORSPACE_RGB);
+		if (ret) {
+			dev_err(ipu_crtc->dev,
+				"initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+		ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1);
+	}
+
+	ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
+			out_pixel_fmt, mode->hdisplay);
+	if (ret) {
+		dev_err(ipu_crtc->dev,
+				"initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
+	if (ret) {
+		dev_err(ipu_crtc->dev,
+				"initializing panel failed with %d\n", ret);
+		return ret;
+	}
+
+	ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay);
+	ipu_cpmem_set_fmt(cpmem, v4l2_fmt);
+	ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch);
+
+	ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay);
+	if (ret) {
+		dev_err(ipu_crtc->dev,
+				"initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc,
+			calc_bandwidth(mode, calc_vref(mode)), 64);
+	if (ret) {
+		dev_err(ipu_crtc->dev,
+				"allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ipu_drm_set_base(crtc, x, y);
+
+	return 0;
+}
+
+static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
+{
+	struct drm_pending_vblank_event *e;
+	struct timeval now;
+	unsigned long flags;
+	struct drm_device *drm = ipu_crtc->base.dev;
+
+	spin_lock_irqsave(&drm->event_lock, flags);
+
+	e = ipu_crtc->page_flip_event;
+	if (!e) {
+		spin_unlock_irqrestore(&drm->event_lock, flags);
+		return;
+	}
+
+	do_gettimeofday(&now);
+	e->event.sequence = 0;
+	e->event.tv_sec = now.tv_sec;
+	e->event.tv_usec = now.tv_usec;
+	ipu_crtc->page_flip_event = NULL;
+
+	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
+
+	list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+
+	wake_up_interruptible(&e->base.file_priv->event_wait);
+
+	spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_crtc *ipu_crtc = dev_id;
+
+	imx_drm_handle_vblank(ipu_crtc->imx_crtc);
+
+	if (ipu_crtc->newfb) {
+		ipu_crtc->base.fb = ipu_crtc->newfb;
+		ipu_crtc->newfb = NULL;
+		ipu_drm_set_base(&ipu_crtc->base, 0, 0);
+		ipu_crtc_handle_pageflip(ipu_crtc);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void ipu_crtc_prepare(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	ipu_fb_disable(ipu_crtc);
+}
+
+static void ipu_crtc_commit(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	ipu_fb_enable(ipu_crtc);
+}
+
+static void ipu_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static struct drm_crtc_helper_funcs ipu_helper_funcs = {
+	.dpms = ipu_crtc_dpms,
+	.mode_fixup = ipu_crtc_mode_fixup,
+	.mode_set = ipu_crtc_mode_set,
+	.prepare = ipu_crtc_prepare,
+	.commit = ipu_crtc_commit,
+	.load_lut = ipu_crtc_load_lut,
+};
+
+static int ipu_enable_vblank(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	enable_irq(ipu_crtc->irq);
+
+	return 0;
+}
+
+static void ipu_disable_vblank(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	disable_irq(ipu_crtc->irq);
+}
+
+static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
+		u32 pixfmt)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	ipu_crtc->interface_pix_fmt = pixfmt;
+
+	switch (encoder_type) {
+	case DRM_MODE_ENCODER_LVDS:
+		ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
+			IPU_DI_CLKMODE_EXT;
+		break;
+	case DRM_MODE_ENCODER_NONE:
+		ipu_crtc->di_clkflags = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
+	.enable_vblank = ipu_enable_vblank,
+	.disable_vblank = ipu_disable_vblank,
+	.set_interface_pix_fmt = ipu_set_interface_pix_fmt,
+	.crtc_funcs = &ipu_crtc_funcs,
+	.crtc_helper_funcs = &ipu_helper_funcs,
+};
+
+static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
+{
+	if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch))
+		ipu_idmac_put(ipu_crtc->ipu_ch);
+	if (!IS_ERR_OR_NULL(ipu_crtc->dmfc))
+		ipu_dmfc_put(ipu_crtc->dmfc);
+	if (!IS_ERR_OR_NULL(ipu_crtc->dp))
+		ipu_dp_put(ipu_crtc->dp);
+	if (!IS_ERR_OR_NULL(ipu_crtc->di))
+		ipu_di_put(ipu_crtc->di);
+}
+
+static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
+		struct ipu_client_platformdata *pdata)
+{
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+	int ret;
+
+	ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]);
+	if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) {
+		ret = PTR_ERR(ipu_crtc->ipu_ch);
+		goto err_out;
+	}
+
+	ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
+	if (IS_ERR(ipu_crtc->dc)) {
+		ret = PTR_ERR(ipu_crtc->dc);
+		goto err_out;
+	}
+
+	ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]);
+	if (IS_ERR(ipu_crtc->dmfc)) {
+		ret = PTR_ERR(ipu_crtc->dmfc);
+		goto err_out;
+	}
+
+	if (pdata->dp >= 0) {
+		ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp);
+		if (IS_ERR(ipu_crtc->dp)) {
+			ret = PTR_ERR(ipu_crtc->ipu_ch);
+			goto err_out;
+		}
+	}
+
+	ipu_crtc->di = ipu_di_get(ipu, pdata->di);
+	if (IS_ERR(ipu_crtc->di)) {
+		ret = PTR_ERR(ipu_crtc->di);
+		goto err_out;
+	}
+
+	ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch,
+			IPU_IRQ_EOF);
+	ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
+			"imx_drm", ipu_crtc);
+	if (ret < 0) {
+		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
+		goto err_out;
+	}
+
+	disable_irq(ipu_crtc->irq);
+
+	return 0;
+err_out:
+	ipu_put_resources(ipu_crtc);
+
+	return ret;
+}
+
+static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
+		struct ipu_client_platformdata *pdata)
+{
+	int ret;
+
+	ret = ipu_get_resources(ipu_crtc, pdata);
+	if (ret) {
+		dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
+				ret);
+		return ret;
+	}
+
+	ret = imx_drm_add_crtc(&ipu_crtc->base,
+			&ipu_crtc->imx_crtc,
+			&ipu_crtc_helper_funcs, THIS_MODULE,
+			ipu_crtc->dev->parent->of_node, pdata->di);
+	if (ret) {
+		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
+		goto err_put_resources;
+	}
+
+	return 0;
+
+err_put_resources:
+	ipu_put_resources(ipu_crtc);
+
+	return ret;
+}
+
+static int __devinit ipu_drm_probe(struct platform_device *pdev)
+{
+	struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
+	struct ipu_crtc *ipu_crtc;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+	if (!ipu_crtc)
+		return -ENOMEM;
+
+	ipu_crtc->dev = &pdev->dev;
+
+	ret = ipu_crtc_init(ipu_crtc, pdata);
+
+	platform_set_drvdata(pdev, ipu_crtc);
+
+	return 0;
+}
+
+static int __devexit ipu_drm_remove(struct platform_device *pdev)
+{
+	struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+
+	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
+
+	ipu_put_resources(ipu_crtc);
+
+	return 0;
+}
+
+static struct platform_driver ipu_drm_driver = {
+	.driver = {
+		.name = "imx-ipuv3-crtc",
+	},
+	.probe = ipu_drm_probe,
+	.remove = __devexit_p(ipu_drm_remove),
+};
+module_platform_driver(ipu_drm_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
new file mode 100644
index 0000000..9b51d73
--- /dev/null
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -0,0 +1,261 @@
+/*
+ * i.MX drm driver - parallel display implementation
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/videodev2.h>
+
+#include "imx-drm.h"
+
+#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
+#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
+
+struct imx_parallel_display {
+	struct drm_connector connector;
+	struct imx_drm_connector *imx_drm_connector;
+	struct drm_encoder encoder;
+	struct imx_drm_encoder *imx_drm_encoder;
+	struct device *dev;
+	void *edid;
+	int edid_len;
+	u32 interface_pix_fmt;
+	int mode_valid;
+	struct drm_display_mode mode;
+};
+
+static enum drm_connector_status imx_pd_connector_detect(
+		struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void imx_pd_connector_destroy(struct drm_connector *connector)
+{
+	/* do not free here */
+}
+
+static int imx_pd_connector_get_modes(struct drm_connector *connector)
+{
+	struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+	int num_modes = 0;
+
+	if (imxpd->edid) {
+		drm_mode_connector_update_edid_property(connector, imxpd->edid);
+		num_modes = drm_add_edid_modes(connector, imxpd->edid);
+	}
+
+	if (imxpd->mode_valid) {
+		struct drm_display_mode *mode = drm_mode_create(connector->dev);
+		drm_mode_copy(mode, &imxpd->mode);
+		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+		drm_mode_probed_add(connector, mode);
+		num_modes++;
+	}
+
+	return num_modes;
+}
+
+static int imx_pd_connector_mode_valid(struct drm_connector *connector,
+			  struct drm_display_mode *mode)
+{
+	return 0;
+}
+
+static struct drm_encoder *imx_pd_connector_best_encoder(
+		struct drm_connector *connector)
+{
+	struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+
+	return &imxpd->encoder;
+}
+
+static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
+{
+	struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
+			imxpd->interface_pix_fmt);
+}
+
+static void imx_pd_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void imx_pd_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
+{
+	/* do not free here */
+}
+
+static struct drm_connector_funcs imx_pd_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = imx_pd_connector_detect,
+	.destroy = imx_pd_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
+	.get_modes = imx_pd_connector_get_modes,
+	.best_encoder = imx_pd_connector_best_encoder,
+	.mode_valid = imx_pd_connector_mode_valid,
+};
+
+static struct drm_encoder_funcs imx_pd_encoder_funcs = {
+	.destroy = imx_pd_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
+	.dpms = imx_pd_encoder_dpms,
+	.mode_fixup = imx_pd_encoder_mode_fixup,
+	.prepare = imx_pd_encoder_prepare,
+	.commit = imx_pd_encoder_commit,
+	.mode_set = imx_pd_encoder_mode_set,
+	.disable = imx_pd_encoder_disable,
+};
+
+static int imx_pd_register(struct imx_parallel_display *imxpd)
+{
+	int ret;
+
+	drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
+
+	imxpd->connector.funcs = &imx_pd_connector_funcs;
+	imxpd->encoder.funcs = &imx_pd_encoder_funcs;
+
+	imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+	imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+
+	drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
+	ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
+			THIS_MODULE);
+	if (ret) {
+		dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
+		return ret;
+	}
+
+	drm_connector_helper_add(&imxpd->connector,
+			&imx_pd_connector_helper_funcs);
+
+	ret = imx_drm_add_connector(&imxpd->connector,
+			&imxpd->imx_drm_connector, THIS_MODULE);
+	if (ret) {
+		imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+		dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
+		return ret;
+	}
+
+	imxpd->connector.encoder = &imxpd->encoder;
+
+	return 0;
+}
+
+static int __devinit imx_pd_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const u8 *edidp;
+	struct imx_parallel_display *imxpd;
+	int ret;
+	const char *fmt;
+
+	imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+	if (!imxpd)
+		return -ENOMEM;
+
+	edidp = of_get_property(np, "edid", &imxpd->edid_len);
+	if (edidp)
+		imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
+
+	ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
+	if (!ret) {
+		if (!strcmp(fmt, "rgb24"))
+			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+		else if (!strcmp(fmt, "rgb565"))
+			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+	}
+
+	imxpd->dev = &pdev->dev;
+
+	ret = imx_pd_register(imxpd);
+	if (ret)
+		return ret;
+
+	ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
+
+	platform_set_drvdata(pdev, imxpd);
+
+	return 0;
+}
+
+static int __devexit imx_pd_remove(struct platform_device *pdev)
+{
+	struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
+	struct drm_connector *connector = &imxpd->connector;
+	struct drm_encoder *encoder = &imxpd->encoder;
+
+	drm_mode_connector_detach_encoder(connector, encoder);
+
+	imx_drm_remove_connector(imxpd->imx_drm_connector);
+	imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+
+	return 0;
+}
+
+static const struct of_device_id imx_pd_dt_ids[] = {
+	{ .compatible = "fsl,imx-parallel-display", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver imx_pd_driver = {
+	.probe		= imx_pd_probe,
+	.remove		= __devexit_p(imx_pd_remove),
+	.driver		= {
+		.of_match_table = imx_pd_dt_ids,
+		.name	= "imx-parallel-display",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(imx_pd_driver);
+
+MODULE_DESCRIPTION("i.MX parallel display driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig
index af32178..4cf4706 100644
--- a/drivers/staging/ipack/Kconfig
+++ b/drivers/staging/ipack/Kconfig
@@ -4,6 +4,7 @@
 
 menuconfig IPACK_BUS
 	tristate "IndustryPack bus support"
+	depends on HAS_IOMEM
 	---help---
 	  If you say Y here you get support for the IndustryPack Framework
 	  for drivers for many types of boards that support this industrial
diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO
index b21d33ab..ffafe69 100644
--- a/drivers/staging/ipack/TODO
+++ b/drivers/staging/ipack/TODO
@@ -12,29 +12,8 @@
 TODO
 ====
 
-TPCI-200
---------
-
-* It has a linked list with the tpci200 devices it is managing. Get rid of it
-  and use driver_for_each_device() instead.
-
-IP-OCTAL
---------
-
-* It has a linked list which saves the devices it is currently
-  managing. It should use the driver_for_each_device() function. It is not there
-  due to the impossibility of using container_of macro to recover the
-  corresponding "struct ipoctal" because the attribute "struct ipack_device" is
-  a pointer. This code should be refactored.
-
-Ipack
------
-
-* The structures and API exported can be improved a lot. For example, the
-  way to unregistering IP module devices, doing the IP module driver a call to
-  remove_device() to notify the carrier driver, or the opposite with the call to
-  the ipack_driver_ops' remove() function could be improved.
-
+checkpatch.pl warnings
+cleanup
 
 Contact
 =======
diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c
index 2b83fa8..bb8aa70 100644
--- a/drivers/staging/ipack/bridges/tpci200.c
+++ b/drivers/staging/ipack/bridges/tpci200.c
@@ -14,38 +14,32 @@
 #include <linux/module.h>
 #include "tpci200.h"
 
-static struct ipack_bus_ops tpci200_bus_ops;
-
-/* TPCI200 controls registers */
-static int control_reg[] = {
-	TPCI200_CONTROL_A_REG,
-	TPCI200_CONTROL_B_REG,
-	TPCI200_CONTROL_C_REG,
-	TPCI200_CONTROL_D_REG
+static u16 tpci200_status_timeout[] = {
+	TPCI200_A_TIMEOUT,
+	TPCI200_B_TIMEOUT,
+	TPCI200_C_TIMEOUT,
+	TPCI200_D_TIMEOUT,
 };
 
-/* Linked list to save the registered devices */
-static LIST_HEAD(tpci200_list);
-
-static int tpci200_slot_unregister(struct ipack_device *dev);
+static u16 tpci200_status_error[] = {
+	TPCI200_A_ERROR,
+	TPCI200_B_ERROR,
+	TPCI200_C_ERROR,
+	TPCI200_D_ERROR,
+};
 
 static struct tpci200_board *check_slot(struct ipack_device *dev)
 {
 	struct tpci200_board *tpci200;
-	int found = 0;
 
 	if (dev == NULL)
 		return NULL;
 
-	list_for_each_entry(tpci200, &tpci200_list, list) {
-		if (tpci200->number == dev->bus_nr) {
-			found = 1;
-			break;
-		}
-	}
 
-	if (!found) {
-		dev_err(&dev->dev, "Carrier not found\n");
+	tpci200 = dev_get_drvdata(dev->bus->parent);
+
+	if (tpci200 == NULL) {
+		dev_info(&dev->dev, "carrier board not found\n");
 		return NULL;
 	}
 
@@ -59,216 +53,22 @@
 	return tpci200;
 }
 
-static inline unsigned char __tpci200_read8(void __iomem *address,
-					    unsigned long offset)
+static void tpci200_clear_mask(struct tpci200_board *tpci200,
+			       __le16 __iomem *addr, u16 mask)
 {
-	return ioread8(address + (offset^1));
+	unsigned long flags;
+	spin_lock_irqsave(&tpci200->regs_lock, flags);
+	iowrite16(ioread16(addr) & (~mask), addr);
+	spin_unlock_irqrestore(&tpci200->regs_lock, flags);
 }
 
-static inline unsigned short __tpci200_read16(void __iomem *address,
-					      unsigned long offset)
+static void tpci200_set_mask(struct tpci200_board *tpci200,
+			     __le16 __iomem *addr, u16 mask)
 {
-	return ioread16(address + offset);
-}
-
-static inline unsigned int __tpci200_read32(void __iomem *address,
-					    unsigned long offset)
-{
-	return swahw32(ioread32(address + offset));
-}
-
-static inline void __tpci200_write8(unsigned char value,
-				    void __iomem *address, unsigned long offset)
-{
-	iowrite8(value, address+(offset^1));
-}
-
-static inline void __tpci200_write16(unsigned short value,
-				     void __iomem *address,
-				     unsigned long offset)
-{
-	iowrite16(value, address+offset);
-}
-
-static inline void __tpci200_write32(unsigned int value,
-				     void __iomem *address,
-				     unsigned long offset)
-{
-	iowrite32(swahw32(value), address+offset);
-}
-
-static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
-						       int space)
-{
-	struct ipack_addr_space *addr;
-
-	switch (space) {
-	case IPACK_IO_SPACE:
-		addr = &dev->io_space;
-		break;
-	case IPACK_ID_SPACE:
-		addr = &dev->id_space;
-		break;
-	case IPACK_MEM_SPACE:
-		addr = &dev->mem_space;
-		break;
-	default:
-		dev_err(&dev->dev,
-			"Slot [%d:%d] space number %d doesn't exist !\n",
-			dev->bus_nr, dev->slot, space);
-		return NULL;
-		break;
-	}
-
-	if ((addr->size == 0) || (addr->address == NULL)) {
-		dev_err(&dev->dev, "Error, slot space not mapped !\n");
-		return NULL;
-	}
-
-	return addr;
-}
-
-static int tpci200_read8(struct ipack_device *dev, int space,
-			 unsigned long offset, unsigned char *value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if (offset >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-
-	*value = __tpci200_read8(addr->address, offset);
-
-	return 0;
-}
-
-static int tpci200_read16(struct ipack_device *dev, int space,
-			  unsigned long offset, unsigned short *value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if ((offset+2) >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-	*value = __tpci200_read16(addr->address, offset);
-
-	return 0;
-}
-
-static int tpci200_read32(struct ipack_device *dev, int space,
-			  unsigned long offset, unsigned int *value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if ((offset+4) >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-
-	*value = __tpci200_read32(addr->address, offset);
-
-	return 0;
-}
-
-static int tpci200_write8(struct ipack_device *dev, int space,
-			  unsigned long offset, unsigned char value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if (offset >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-
-	__tpci200_write8(value, addr->address, offset);
-
-	return 0;
-}
-
-static int tpci200_write16(struct ipack_device *dev, int space,
-			   unsigned long offset, unsigned short value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if ((offset+2) >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-
-	__tpci200_write16(value, addr->address, offset);
-
-	return 0;
-}
-
-static int tpci200_write32(struct ipack_device *dev, int space,
-			   unsigned long offset, unsigned int value)
-{
-	struct ipack_addr_space *addr;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	addr = get_slot_address_space(dev, space);
-	if (addr == NULL)
-		return -EINVAL;
-
-	if ((offset+4) >= addr->size) {
-		dev_err(&dev->dev, "Error, slot space offset error !\n");
-		return -EFAULT;
-	}
-
-	__tpci200_write32(value, addr->address, offset);
-
-	return 0;
+	unsigned long flags;
+	spin_lock_irqsave(&tpci200->regs_lock, flags);
+	iowrite16(ioread16(addr) | mask, addr);
+	spin_unlock_irqrestore(&tpci200->regs_lock, flags);
 }
 
 static void tpci200_unregister(struct tpci200_board *tpci200)
@@ -280,10 +80,12 @@
 	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
 	pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
 	pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
+	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
 
 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
 	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
+	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
 
 	pci_disable_device(tpci200->info->pdev);
 	pci_dev_put(tpci200->info->pdev);
@@ -293,62 +95,148 @@
 		tpci200->slots[i].io_phys.size = 0;
 		tpci200->slots[i].id_phys.address = NULL;
 		tpci200->slots[i].id_phys.size = 0;
+		tpci200->slots[i].int_phys.address = NULL;
+		tpci200->slots[i].int_phys.size = 0;
 		tpci200->slots[i].mem_phys.address = NULL;
 		tpci200->slots[i].mem_phys.size = 0;
 	}
 }
 
+static void tpci200_enable_irq(struct tpci200_board *tpci200,
+			       int islot)
+{
+	tpci200_set_mask(tpci200,
+			&tpci200->info->interface_regs->control[islot],
+			TPCI200_INT0_EN | TPCI200_INT1_EN);
+}
+
+static void tpci200_disable_irq(struct tpci200_board *tpci200,
+				int islot)
+{
+	tpci200_clear_mask(tpci200,
+			&tpci200->info->interface_regs->control[islot],
+			TPCI200_INT0_EN | TPCI200_INT1_EN);
+}
+
+static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq)
+{
+	irqreturn_t ret;
+
+	if (!slot_irq)
+		return -ENODEV;
+	ret = slot_irq->handler(slot_irq->arg);
+
+	return ret;
+}
+
 static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
 {
 	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
+	struct slot_irq *slot_irq;
+	irqreturn_t ret;
+	u16 status_reg;
 	int i;
-	unsigned short status_reg, reg_value;
-	unsigned short unhandled_ints = 0;
-	irqreturn_t ret = IRQ_NONE;
 
 	/* Read status register */
-	status_reg = readw(tpci200->info->interface_regs +
-			   TPCI200_STATUS_REG);
+	status_reg = ioread16(&tpci200->info->interface_regs->status);
 
-	if (status_reg & TPCI200_SLOT_INT_MASK) {
-		unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK;
-		/* callback to the IRQ handler for the corresponding slot */
-		for (i = 0; i < TPCI200_NB_SLOT; i++) {
-			if ((tpci200->slots[i].irq != NULL) &&
-			    (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) {
+	/* Did we cause the interrupt? */
+	if (!(status_reg & TPCI200_SLOT_INT_MASK))
+		return IRQ_NONE;
 
-				ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg);
-
-				/* Dummy reads */
-				readw(tpci200->slots[i].dev->io_space.address +
-				      0xC0);
-				readw(tpci200->slots[i].dev->io_space.address +
-				      0xC2);
-
-				unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)));
-			}
+	/* callback to the IRQ handler for the corresponding slot */
+	rcu_read_lock();
+	for (i = 0; i < TPCI200_NB_SLOT; i++) {
+		if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2 * i))))
+			continue;
+		slot_irq = rcu_dereference(tpci200->slots[i].irq);
+		ret = tpci200_slot_irq(slot_irq);
+		if (ret == -ENODEV) {
+			dev_info(&tpci200->info->pdev->dev,
+				 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
+				 tpci200->number, i);
+			tpci200_disable_irq(tpci200, i);
 		}
 	}
-	/* Interrupt not handled are disabled */
-	if (unhandled_ints) {
-		for (i = 0; i < TPCI200_NB_SLOT; i++) {
-			if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
-				dev_info(&tpci200->slots[i].dev->dev,
-					 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
-					 tpci200->number, i);
-				reg_value = readw(
-					tpci200->info->interface_regs +
-					control_reg[i]);
-				reg_value &=
-					~(TPCI200_INT0_EN | TPCI200_INT1_EN);
-				writew(reg_value,
-				       (tpci200->info->interface_regs +
-					control_reg[i]));
-			}
-		}
+	rcu_read_unlock();
+
+	return IRQ_HANDLED;
+}
+
+static int tpci200_free_irq(struct ipack_device *dev)
+{
+	struct slot_irq *slot_irq;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
+
+	if (tpci200->slots[dev->slot].irq == NULL) {
+		mutex_unlock(&tpci200->mutex);
+		return -EINVAL;
 	}
 
-	return ret;
+	tpci200_disable_irq(tpci200, dev->slot);
+	slot_irq = tpci200->slots[dev->slot].irq;
+	/* uninstall handler */
+	RCU_INIT_POINTER(tpci200->slots[dev->slot].irq, NULL);
+	synchronize_rcu();
+	kfree(slot_irq);
+	mutex_unlock(&tpci200->mutex);
+	return 0;
+}
+
+static int tpci200_request_irq(struct ipack_device *dev,
+			       irqreturn_t (*handler)(void *), void *arg)
+{
+	int res = 0;
+	struct slot_irq *slot_irq;
+	struct tpci200_board *tpci200;
+
+	tpci200 = check_slot(dev);
+	if (tpci200 == NULL)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
+
+	if (tpci200->slots[dev->slot].irq != NULL) {
+		dev_err(&dev->dev,
+			"Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
+			dev->slot);
+		res = -EINVAL;
+		goto out_unlock;
+	}
+
+	slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
+	if (slot_irq == NULL) {
+		dev_err(&dev->dev,
+			"Slot [%d:%d] unable to allocate memory for IRQ !\n",
+			dev->bus_nr, dev->slot);
+		res = -ENOMEM;
+		goto out_unlock;
+	}
+
+	/*
+	 * WARNING: Setup Interrupt Vector in the IndustryPack device
+	 * before an IRQ request.
+	 * Read the User Manual of your IndustryPack device to know
+	 * where to write the vector in memory.
+	 */
+	slot_irq->handler = handler;
+	slot_irq->arg = arg;
+	slot_irq->holder = dev;
+
+	rcu_assign_pointer(tpci200->slots[dev->slot].irq, slot_irq);
+	tpci200_enable_irq(tpci200, dev->slot);
+
+out_unlock:
+	mutex_unlock(&tpci200->mutex);
+	return res;
 }
 
 static int tpci200_register(struct tpci200_board *tpci200)
@@ -398,18 +286,21 @@
 
 	/* Map internal tpci200 driver user space */
 	tpci200->info->interface_regs =
-		ioremap(pci_resource_start(tpci200->info->pdev,
+		ioremap_nocache(pci_resource_start(tpci200->info->pdev,
 					   TPCI200_IP_INTERFACE_BAR),
 			TPCI200_IFACE_SIZE);
 	tpci200->info->ioidint_space =
-		ioremap(pci_resource_start(tpci200->info->pdev,
+		ioremap_nocache(pci_resource_start(tpci200->info->pdev,
 					   TPCI200_IO_ID_INT_SPACES_BAR),
 			TPCI200_IOIDINT_SIZE);
 	tpci200->info->mem8_space =
-		ioremap(pci_resource_start(tpci200->info->pdev,
+		ioremap_nocache(pci_resource_start(tpci200->info->pdev,
 					   TPCI200_MEM8_SPACE_BAR),
 			TPCI200_MEM8_SIZE);
 
+	/* Initialize lock that protects interface_regs */
+	spin_lock_init(&tpci200->regs_lock);
+
 	ioidint_base = pci_resource_start(tpci200->info->pdev,
 					  TPCI200_IO_ID_INT_SPACES_BAR);
 	mem_base = pci_resource_start(tpci200->info->pdev,
@@ -437,12 +328,16 @@
 			TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i;
 		tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE;
 
+		tpci200->slots[i].int_phys.address =
+			(void __iomem *)ioidint_base +
+			TPCI200_INT_SPACE_OFF + TPCI200_INT_SPACE_GAP * i;
+		tpci200->slots[i].int_phys.size = TPCI200_INT_SPACE_SIZE;
+
 		tpci200->slots[i].mem_phys.address =
 			(void __iomem *)mem_base + TPCI200_MEM8_GAP*i;
 		tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE;
 
-		writew(slot_ctrl, (tpci200->info->interface_regs +
-				   control_reg[i]));
+		writew(slot_ctrl, &tpci200->info->interface_regs->control[i]);
 	}
 
 	res = request_irq(tpci200->info->pdev->irq,
@@ -467,70 +362,6 @@
 	return res;
 }
 
-static int __tpci200_request_irq(struct tpci200_board *tpci200,
-				 struct ipack_device *dev)
-{
-	unsigned short slot_ctrl;
-
-	/* Set the default parameters of the slot
-	 * INT0 enabled, level sensitive
-	 * INT1 enabled, level sensitive
-	 * error interrupt disabled
-	 * timeout interrupt disabled
-	 * recover time disabled
-	 * clock rate 8 MHz
-	 */
-	slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN;
-	writew(slot_ctrl, (tpci200->info->interface_regs +
-			   control_reg[dev->slot]));
-
-	return 0;
-}
-
-static void __tpci200_free_irq(struct tpci200_board *tpci200,
-			       struct ipack_device *dev)
-{
-	unsigned short slot_ctrl;
-
-	/* Set the default parameters of the slot
-	 * INT0 disabled, level sensitive
-	 * INT1 disabled, level sensitive
-	 * error interrupt disabled
-	 * timeout interrupt disabled
-	 * recover time disabled
-	 * clock rate 8 MHz
-	 */
-	slot_ctrl = 0;
-	writew(slot_ctrl, (tpci200->info->interface_regs +
-			   control_reg[dev->slot]));
-}
-
-static int tpci200_free_irq(struct ipack_device *dev)
-{
-	struct slot_irq *slot_irq;
-	struct tpci200_board *tpci200;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&tpci200->mutex))
-		return -ERESTARTSYS;
-
-	if (tpci200->slots[dev->slot].irq == NULL) {
-		mutex_unlock(&tpci200->mutex);
-		return -EINVAL;
-	}
-
-	__tpci200_free_irq(tpci200, dev);
-	slot_irq = tpci200->slots[dev->slot].irq;
-	tpci200->slots[dev->slot].irq = NULL;
-	kfree(slot_irq);
-
-	mutex_unlock(&tpci200->mutex);
-	return 0;
-}
-
 static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
 {
 	struct ipack_addr_space *virt_addr_space;
@@ -562,6 +393,15 @@
 		}
 		virt_addr_space = &dev->id_space;
 		break;
+	case IPACK_INT_SPACE:
+		if (dev->int_space.address == NULL) {
+			dev_info(&dev->dev,
+				 "Slot [%d:%d] INT space not mapped !\n",
+				 dev->bus_nr, dev->slot);
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->int_space;
+		break;
 	case IPACK_MEM_SPACE:
 		if (dev->mem_space.address == NULL) {
 			dev_info(&dev->dev,
@@ -588,29 +428,6 @@
 	return 0;
 }
 
-static int tpci200_slot_unregister(struct ipack_device *dev)
-{
-	struct tpci200_board *tpci200;
-
-	if (dev == NULL)
-		return -ENODEV;
-
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
-		return -EINVAL;
-
-	tpci200_free_irq(dev);
-
-	if (mutex_lock_interruptible(&tpci200->mutex))
-		return -ERESTARTSYS;
-
-	ipack_device_unregister(dev);
-	tpci200->slots[dev->slot].dev = NULL;
-	mutex_unlock(&tpci200->mutex);
-
-	return 0;
-}
-
 static int tpci200_slot_map_space(struct ipack_device *dev,
 				  unsigned int memory_size, int space)
 {
@@ -654,6 +471,19 @@
 		phys_address = tpci200->slots[dev->slot].id_phys.address;
 		size_to_map = tpci200->slots[dev->slot].id_phys.size;
 		break;
+	case IPACK_INT_SPACE:
+		if (dev->int_space.address != NULL) {
+			dev_err(&dev->dev,
+				"Slot [%d:%d] INT space already mapped !\n",
+				tpci200->number, dev->slot);
+			res = -EINVAL;
+			goto out_unlock;
+		}
+		virt_addr_space = &dev->int_space;
+
+		phys_address = tpci200->slots[dev->slot].int_phys.address;
+		size_to_map = tpci200->slots[dev->slot].int_phys.size;
+		break;
 	case IPACK_MEM_SPACE:
 		if (dev->mem_space.address != NULL) {
 			dev_err(&dev->dev,
@@ -685,85 +515,109 @@
 
 	virt_addr_space->size = size_to_map;
 	virt_addr_space->address =
-		ioremap((unsigned long)phys_address, size_to_map);
+		ioremap_nocache((unsigned long)phys_address, size_to_map);
 
 out_unlock:
 	mutex_unlock(&tpci200->mutex);
 	return res;
 }
 
-static int tpci200_request_irq(struct ipack_device *dev, int vector,
-			       int (*handler)(void *), void *arg)
+static int tpci200_get_clockrate(struct ipack_device *dev)
 {
-	int res;
-	struct slot_irq *slot_irq;
-	struct tpci200_board *tpci200;
+	struct tpci200_board *tpci200 = check_slot(dev);
+	__le16 __iomem *addr;
 
-	tpci200 = check_slot(dev);
-	if (tpci200 == NULL)
+	if (!tpci200)
+		return -ENODEV;
+
+	addr = &tpci200->info->interface_regs->control[dev->slot];
+	return (ioread16(addr) & TPCI200_CLK32) ? 32 : 8;
+}
+
+static int tpci200_set_clockrate(struct ipack_device *dev, int mherz)
+{
+	struct tpci200_board *tpci200 = check_slot(dev);
+	__le16 __iomem *addr;
+
+	if (!tpci200)
+		return -ENODEV;
+
+	addr = &tpci200->info->interface_regs->control[dev->slot];
+
+	switch (mherz) {
+	case 8:
+		tpci200_clear_mask(tpci200, addr, TPCI200_CLK32);
+		break;
+	case 32:
+		tpci200_set_mask(tpci200, addr, TPCI200_CLK32);
+		break;
+	default:
 		return -EINVAL;
-
-	if (mutex_lock_interruptible(&tpci200->mutex))
-		return -ERESTARTSYS;
-
-	if (tpci200->slots[dev->slot].irq != NULL) {
-		dev_err(&dev->dev,
-			"Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
-			dev->slot);
-		res = -EINVAL;
-		goto out_unlock;
 	}
+	return 0;
+}
 
-	slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
-	if (slot_irq == NULL) {
-		dev_err(&dev->dev,
-			"Slot [%d:%d] unable to allocate memory for IRQ !\n",
-			dev->bus_nr, dev->slot);
-		res = -ENOMEM;
-		goto out_unlock;
-	}
+static int tpci200_get_error(struct ipack_device *dev)
+{
+	struct tpci200_board *tpci200 = check_slot(dev);
+	__le16 __iomem *addr;
+	u16 mask;
 
-	/*
-	 * WARNING: Setup Interrupt Vector in the IndustryPack device
-	 * before an IRQ request.
-	 * Read the User Manual of your IndustryPack device to know
-	 * where to write the vector in memory.
-	 */
-	slot_irq->vector = vector;
-	slot_irq->handler = handler;
-	slot_irq->arg = arg;
+	if (!tpci200)
+		return -ENODEV;
 
-	tpci200->slots[dev->slot].irq = slot_irq;
-	res = __tpci200_request_irq(tpci200, dev);
+	addr = &tpci200->info->interface_regs->status;
+	mask = tpci200_status_error[dev->slot];
+	return (ioread16(addr) & mask) ? 1 : 0;
+}
 
-out_unlock:
-	mutex_unlock(&tpci200->mutex);
-	return res;
+static int tpci200_get_timeout(struct ipack_device *dev)
+{
+	struct tpci200_board *tpci200 = check_slot(dev);
+	__le16 __iomem *addr;
+	u16 mask;
+
+	if (!tpci200)
+		return -ENODEV;
+
+	addr = &tpci200->info->interface_regs->status;
+	mask = tpci200_status_timeout[dev->slot];
+
+	return (ioread16(addr) & mask) ? 1 : 0;
+}
+
+static int tpci200_reset_timeout(struct ipack_device *dev)
+{
+	struct tpci200_board *tpci200 = check_slot(dev);
+	__le16 __iomem *addr;
+	u16 mask;
+
+	if (!tpci200)
+		return -ENODEV;
+
+	addr = &tpci200->info->interface_regs->status;
+	mask = tpci200_status_timeout[dev->slot];
+
+	iowrite16(mask, addr);
+	return 0;
 }
 
 static void tpci200_uninstall(struct tpci200_board *tpci200)
 {
-	int i;
-
-	for (i = 0; i < TPCI200_NB_SLOT; i++)
-		tpci200_slot_unregister(tpci200->slots[i].dev);
-
 	tpci200_unregister(tpci200);
 	kfree(tpci200->slots);
 }
 
-static struct ipack_bus_ops tpci200_bus_ops = {
+static const struct ipack_bus_ops tpci200_bus_ops = {
 	.map_space = tpci200_slot_map_space,
 	.unmap_space = tpci200_slot_unmap_space,
 	.request_irq = tpci200_request_irq,
 	.free_irq = tpci200_free_irq,
-	.read8 = tpci200_read8,
-	.read16 = tpci200_read16,
-	.read32 = tpci200_read32,
-	.write8 = tpci200_write8,
-	.write16 = tpci200_write16,
-	.write32 = tpci200_write32,
-	.remove_device = tpci200_slot_unregister,
+	.get_clockrate = tpci200_get_clockrate,
+	.set_clockrate = tpci200_set_clockrate,
+	.get_error     = tpci200_get_error,
+	.get_timeout   = tpci200_get_timeout,
+	.reset_timeout = tpci200_reset_timeout,
 };
 
 static int tpci200_install(struct tpci200_board *tpci200)
@@ -786,11 +640,12 @@
 	return 0;
 }
 
-static int tpci200_pciprobe(struct pci_dev *pdev,
-			    const struct pci_device_id *id)
+static int tpci200_pci_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
 {
 	int ret, i;
 	struct tpci200_board *tpci200;
+	u32 reg32;
 
 	tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
 	if (!tpci200)
@@ -798,10 +653,40 @@
 
 	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
 	if (!tpci200->info) {
-		kfree(tpci200);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out_err_info;
 	}
 
+	pci_dev_get(pdev);
+
+	/* Obtain a mapping of the carrier's PCI configuration registers */
+	ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR,
+				 KBUILD_MODNAME " Configuration Memory");
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
+		ret = -EBUSY;
+		goto out_err_pci_request;
+	}
+	tpci200->info->cfg_regs = ioremap_nocache(
+			pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
+			pci_resource_len(pdev, TPCI200_CFG_MEM_BAR));
+	if (!tpci200->info->cfg_regs) {
+		dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
+		ret = -EFAULT;
+		goto out_err_ioremap;
+	}
+
+	/* Disable byte swapping for 16 bit IP module access. This will ensure
+	 * that the Industrypack big endian byte order is preserved by the
+	 * carrier. */
+	reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC);
+	reg32 |= 1 << LAS_BIT_BIGENDIAN;
+	iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC);
+
+	reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC);
+	reg32 |= 1 << LAS_BIT_BIGENDIAN;
+	iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC);
+
 	/* Save struct pci_dev pointer */
 	tpci200->info->pdev = pdev;
 	tpci200->info->id_table = (struct pci_device_id *)id;
@@ -809,10 +694,9 @@
 	/* register the device and initialize it */
 	ret = tpci200_install(tpci200);
 	if (ret) {
-		dev_err(&pdev->dev, "Error during tpci200 install !\n");
-		kfree(tpci200->info);
-		kfree(tpci200);
-		return -ENODEV;
+		dev_err(&pdev->dev, "error during tpci200 install\n");
+		ret = -ENODEV;
+		goto out_err_install;
 	}
 
 	/* Register the carrier in the industry pack bus driver */
@@ -822,48 +706,46 @@
 	if (!tpci200->info->ipack_bus) {
 		dev_err(&pdev->dev,
 			"error registering the carrier on ipack driver\n");
-		tpci200_uninstall(tpci200);
-		kfree(tpci200->info);
-		kfree(tpci200);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto out_err_bus_register;
 	}
 
 	/* save the bus number given by ipack to logging purpose */
 	tpci200->number = tpci200->info->ipack_bus->bus_nr;
 	dev_set_drvdata(&pdev->dev, tpci200);
-	/* add the registered device in an internal linked list */
-	list_add_tail(&tpci200->list, &tpci200_list);
 
-	/*
-	 * Give the same IRQ number as the slot number.
-	 * The TPCI200 has assigned his own two IRQ by PCI bus driver
-	 */
 	for (i = 0; i < TPCI200_NB_SLOT; i++)
-		tpci200->slots[i].dev =
-			ipack_device_register(tpci200->info->ipack_bus, i, i);
+		ipack_device_register(tpci200->info->ipack_bus, i);
+	return 0;
+
+out_err_bus_register:
+	tpci200_uninstall(tpci200);
+out_err_install:
+	iounmap(tpci200->info->cfg_regs);
+out_err_ioremap:
+	pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
+out_err_pci_request:
+	pci_dev_put(pdev);
+	kfree(tpci200->info);
+out_err_info:
+	kfree(tpci200);
 	return ret;
 }
 
 static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 {
-	tpci200_uninstall(tpci200);
-	list_del(&tpci200->list);
 	ipack_bus_unregister(tpci200->info->ipack_bus);
+	tpci200_uninstall(tpci200);
+
 	kfree(tpci200->info);
 	kfree(tpci200);
 }
 
 static void __devexit tpci200_pci_remove(struct pci_dev *dev)
 {
-	struct tpci200_board *tpci200, *next;
+	struct tpci200_board *tpci200 = pci_get_drvdata(dev);
 
-	/* Search the registered device to uninstall it */
-	list_for_each_entry_safe(tpci200, next, &tpci200_list, list) {
-		if (tpci200->info->pdev == dev) {
-			__tpci200_pci_remove(tpci200);
-			break;
-		}
-	}
+	__tpci200_pci_remove(tpci200);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(tpci200_idtable) = {
@@ -877,7 +759,7 @@
 static struct pci_driver tpci200_pci_drv = {
 	.name = "tpci200",
 	.id_table = tpci200_idtable,
-	.probe = tpci200_pciprobe,
+	.probe = tpci200_pci_probe,
 	.remove = __devexit_p(tpci200_pci_remove),
 };
 
@@ -888,11 +770,6 @@
 
 static void __exit tpci200_drvr_exit_module(void)
 {
-	struct tpci200_board *tpci200, *next;
-
-	list_for_each_entry_safe(tpci200, next, &tpci200_list, list)
-		__tpci200_pci_remove(tpci200);
-
 	pci_unregister_driver(&tpci200_pci_drv);
 }
 
diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h
index d04510a..235d1fe 100644
--- a/drivers/staging/ipack/bridges/tpci200.h
+++ b/drivers/staging/ipack/bridges/tpci200.h
@@ -17,7 +17,6 @@
 #include <linux/limits.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
-#include <linux/interrupt.h>
 #include <linux/swab.h>
 #include <linux/io.h>
 
@@ -31,18 +30,21 @@
 #define TPCI200_SUBVENDOR_ID          0x1498
 #define TPCI200_SUBDEVICE_ID          0x300A
 
+#define TPCI200_CFG_MEM_BAR           0
 #define TPCI200_IP_INTERFACE_BAR      2
 #define TPCI200_IO_ID_INT_SPACES_BAR  3
 #define TPCI200_MEM16_SPACE_BAR       4
 #define TPCI200_MEM8_SPACE_BAR        5
 
-#define TPCI200_REVISION_REG          0x00
-#define TPCI200_CONTROL_A_REG         0x02
-#define TPCI200_CONTROL_B_REG         0x04
-#define TPCI200_CONTROL_C_REG         0x06
-#define TPCI200_CONTROL_D_REG         0x08
-#define TPCI200_RESET_REG             0x0A
-#define TPCI200_STATUS_REG            0x0C
+struct tpci200_regs {
+	__le16	revision;
+	/* writes to control should occur with the mutex held to protect
+	 * read-modify-write operations */
+	__le16  control[4];
+	__le16	reset;
+	__le16	status;
+	u8	reserved[242];
+} __packed;
 
 #define TPCI200_IFACE_SIZE            0x100
 
@@ -62,6 +64,7 @@
 #define TPCI200_MEM16_GAP             0x00800000
 #define TPCI200_MEM16_SIZE            0x00800000
 
+/* control field in tpci200_regs */
 #define TPCI200_INT0_EN               0x0040
 #define TPCI200_INT1_EN               0x0080
 #define TPCI200_INT0_EDGE             0x0010
@@ -71,11 +74,13 @@
 #define TPCI200_RECOVER_EN            0x0002
 #define TPCI200_CLK32                 0x0001
 
+/* reset field in tpci200_regs */
 #define TPCI200_A_RESET               0x0001
 #define TPCI200_B_RESET               0x0002
 #define TPCI200_C_RESET               0x0004
 #define TPCI200_D_RESET               0x0008
 
+/* status field in tpci200_regs */
 #define TPCI200_A_TIMEOUT             0x1000
 #define TPCI200_B_TIMEOUT             0x2000
 #define TPCI200_C_TIMEOUT             0x4000
@@ -97,6 +102,13 @@
 
 #define TPCI200_SLOT_INT_MASK         0x00FF
 
+/* PCI Configuration registers. The PCI bridge is a PLX Technology PCI9030. */
+#define LAS1_DESC		      0x2C
+#define LAS2_DESC		      0x30
+
+/* Bits in the LAS?_DESC registers */
+#define LAS_BIT_BIGENDIAN	      24
+
 #define VME_IOID_SPACE  "IOID"
 #define VME_MEM_SPACE  "MEM"
 
@@ -108,8 +120,9 @@
  *
  */
 struct slot_irq {
+	struct ipack_device *holder;
 	int		vector;
-	int		(*handler)(void *);
+	irqreturn_t	(*handler)(void *);
 	void		*arg;
 };
 
@@ -119,14 +132,15 @@
  * @irq		Slot IRQ infos
  * @io_phys	IO physical base address register of the slot
  * @id_phys	ID physical base address register of the slot
+ * @int_phys	INT physical base address register of the slot
  * @mem_phys	MEM physical base address register of the slot
  *
  */
 struct tpci200_slot {
-	struct ipack_device	*dev;
 	struct slot_irq		*irq;
 	struct ipack_addr_space io_phys;
 	struct ipack_addr_space id_phys;
+	struct ipack_addr_space int_phys;
 	struct ipack_addr_space mem_phys;
 };
 
@@ -141,15 +155,16 @@
 struct tpci200_infos {
 	struct pci_dev			*pdev;
 	struct pci_device_id		*id_table;
-	void __iomem			*interface_regs;
+	struct tpci200_regs __iomem	*interface_regs;
 	void __iomem			*ioidint_space;
 	void __iomem			*mem8_space;
+	void __iomem			*cfg_regs;
 	struct ipack_bus_device		*ipack_bus;
 };
 struct tpci200_board {
-	struct list_head	list;
 	unsigned int		number;
 	struct mutex		mutex;
+	spinlock_t		regs_lock;
 	struct tpci200_slot	*slots;
 	struct tpci200_infos	*info;
 };
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index a68d981c..d751edf 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -20,127 +20,68 @@
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
 #include <linux/atomic.h>
+#include <linux/io.h>
 #include "../ipack.h"
 #include "ipoctal.h"
 #include "scc2698.h"
 
-#define IP_OCTAL_MANUFACTURER_ID    0xF0
-#define IP_OCTAL_232_ID             0x22
-#define IP_OCTAL_422_ID             0x2A
-#define IP_OCTAL_485_ID             0x48
-
 #define IP_OCTAL_ID_SPACE_VECTOR    0x41
 #define IP_OCTAL_NB_BLOCKS          4
 
-static struct ipack_driver driver;
 static const struct tty_operations ipoctal_fops;
 
+struct ipoctal_channel {
+	struct ipoctal_stats		stats;
+	unsigned int			nb_bytes;
+	wait_queue_head_t		queue;
+	spinlock_t			lock;
+	unsigned int			pointer_read;
+	unsigned int			pointer_write;
+	atomic_t			open;
+	struct tty_port			tty_port;
+	union scc2698_channel __iomem	*regs;
+	union scc2698_block __iomem	*block_regs;
+	unsigned int			board_id;
+	unsigned char			*board_write;
+	u8				isr_rx_rdy_mask;
+	u8				isr_tx_rdy_mask;
+};
+
 struct ipoctal {
-	struct list_head		list;
 	struct ipack_device		*dev;
 	unsigned int			board_id;
-	struct scc2698_channel		*chan_regs;
-	struct scc2698_block		*block_regs;
-	struct ipoctal_stats		chan_stats[NR_CHANNELS];
-	unsigned int			nb_bytes[NR_CHANNELS];
-	unsigned int			count_wr[NR_CHANNELS];
-	wait_queue_head_t		queue[NR_CHANNELS];
-	spinlock_t			lock[NR_CHANNELS];
-	unsigned int			pointer_read[NR_CHANNELS];
-	unsigned int			pointer_write[NR_CHANNELS];
-	atomic_t			open[NR_CHANNELS];
+	struct ipoctal_channel		channel[NR_CHANNELS];
 	unsigned char			write;
-	struct tty_port			tty_port[NR_CHANNELS];
 	struct tty_driver		*tty_drv;
 };
 
-/* Linked list to save the registered devices */
-static LIST_HEAD(ipoctal_list);
-
-static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal,
-					unsigned char *dest,
-					unsigned char value)
-{
-	unsigned long offset;
-
-	offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address;
-	ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset,
-				       value);
-}
-
-static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal,
-					unsigned char *dest,
-					unsigned char value)
-{
-	ipoctal_write_io_reg(ipoctal, dest, value);
-}
-
-static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal,
-						unsigned char *src)
-{
-	unsigned long offset;
-	unsigned char value;
-
-	offset = ((void __iomem *) src) - ipoctal->dev->io_space.address;
-	ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset,
-				      &value);
-	return value;
-}
-
-static struct ipoctal *ipoctal_find_board(struct tty_struct *tty)
-{
-	struct ipoctal *p;
-
-	list_for_each_entry(p, &ipoctal_list, list) {
-		if (tty->driver->major == p->tty_drv->major)
-			return p;
-	}
-
-	return NULL;
-}
-
 static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
 {
-	struct ipoctal *ipoctal;
-	int channel = tty->index;
+	struct ipoctal_channel *channel;
 
-	ipoctal = ipoctal_find_board(tty);
+	channel = dev_get_drvdata(tty->dev);
 
-	if (ipoctal == NULL) {
-		dev_err(tty->dev, "Device not found. Major %d\n",
-			tty->driver->major);
-		return -ENODEV;
-	}
-
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_ENABLE_RX);
+	iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
 	return 0;
 }
 
 static int ipoctal_open(struct tty_struct *tty, struct file *file)
 {
-	int channel = tty->index;
 	int res;
-	struct ipoctal *ipoctal;
+	struct ipoctal_channel *channel;
 
-	ipoctal = ipoctal_find_board(tty);
+	channel = dev_get_drvdata(tty->dev);
 
-	if (ipoctal == NULL) {
-		dev_err(tty->dev, "Device not found. Major %d\n",
-			tty->driver->major);
-		return -ENODEV;
-	}
-
-	if (atomic_read(&ipoctal->open[channel]))
+	if (atomic_read(&channel->open))
 		return -EBUSY;
 
-	tty->driver_data = ipoctal;
+	tty->driver_data = channel;
 
-	res = tty_port_open(&ipoctal->tty_port[channel], tty, file);
+	res = tty_port_open(&channel->tty_port, tty, file);
 	if (res)
 		return res;
 
-	atomic_inc(&ipoctal->open[channel]);
+	atomic_inc(&channel->open);
 	return 0;
 }
 
@@ -154,175 +95,166 @@
 	stats->parity_err = 0;
 }
 
-static void ipoctal_free_channel(struct tty_struct *tty)
+static void ipoctal_free_channel(struct ipoctal_channel *channel)
 {
-	int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
-
-	if (ipoctal == NULL)
-		return;
-
-	ipoctal_reset_stats(&ipoctal->chan_stats[channel]);
-	ipoctal->pointer_read[channel] = 0;
-	ipoctal->pointer_write[channel] = 0;
-	ipoctal->nb_bytes[channel] = 0;
+	ipoctal_reset_stats(&channel->stats);
+	channel->pointer_read = 0;
+	channel->pointer_write = 0;
+	channel->nb_bytes = 0;
 }
 
 static void ipoctal_close(struct tty_struct *tty, struct file *filp)
 {
-	int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
+	struct ipoctal_channel *channel = tty->driver_data;
 
-	tty_port_close(&ipoctal->tty_port[channel], tty, filp);
+	tty_port_close(&channel->tty_port, tty, filp);
 
-	if (atomic_dec_and_test(&ipoctal->open[channel]))
-		ipoctal_free_channel(tty);
+	if (atomic_dec_and_test(&channel->open))
+		ipoctal_free_channel(channel);
 }
 
 static int ipoctal_get_icount(struct tty_struct *tty,
 			      struct serial_icounter_struct *icount)
 {
-	struct ipoctal *ipoctal = tty->driver_data;
-	int channel = tty->index;
+	struct ipoctal_channel *channel = tty->driver_data;
 
 	icount->cts = 0;
 	icount->dsr = 0;
 	icount->rng = 0;
 	icount->dcd = 0;
-	icount->rx = ipoctal->chan_stats[channel].rx;
-	icount->tx = ipoctal->chan_stats[channel].tx;
-	icount->frame = ipoctal->chan_stats[channel].framing_err;
-	icount->parity = ipoctal->chan_stats[channel].parity_err;
-	icount->brk = ipoctal->chan_stats[channel].rcv_break;
+	icount->rx = channel->stats.rx;
+	icount->tx = channel->stats.tx;
+	icount->frame = channel->stats.framing_err;
+	icount->parity = channel->stats.parity_err;
+	icount->brk = channel->stats.rcv_break;
 	return 0;
 }
 
-static int ipoctal_irq_handler(void *arg)
+static void ipoctal_irq_rx(struct ipoctal_channel *channel,
+			   struct tty_struct *tty, u8 sr)
 {
-	unsigned int channel;
-	unsigned int block;
-	unsigned char isr;
-	unsigned char sr;
-	unsigned char isr_tx_rdy, isr_rx_rdy;
 	unsigned char value;
-	unsigned char flag;
+	unsigned char flag = TTY_NORMAL;
+	u8 isr;
+
+	do {
+		value = ioread8(&channel->regs->r.rhr);
+		/* Error: count statistics */
+		if (sr & SR_ERROR) {
+			iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
+
+			if (sr & SR_OVERRUN_ERROR) {
+				channel->stats.overrun_err++;
+				/* Overrun doesn't affect the current character*/
+				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+			}
+			if (sr & SR_PARITY_ERROR) {
+				channel->stats.parity_err++;
+				flag = TTY_PARITY;
+			}
+			if (sr & SR_FRAMING_ERROR) {
+				channel->stats.framing_err++;
+				flag = TTY_FRAME;
+			}
+			if (sr & SR_RECEIVED_BREAK) {
+				iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
+				channel->stats.rcv_break++;
+				flag = TTY_BREAK;
+			}
+		}
+		tty_insert_flip_char(tty, value, flag);
+
+		/* Check if there are more characters in RX FIFO
+		 * If there are more, the isr register for this channel
+		 * has enabled the RxRDY|FFULL bit.
+		 */
+		isr = ioread8(&channel->block_regs->r.isr);
+		sr = ioread8(&channel->regs->r.sr);
+	} while (isr & channel->isr_rx_rdy_mask);
+
+	tty_flip_buffer_push(tty);
+}
+
+static void ipoctal_irq_tx(struct ipoctal_channel *channel)
+{
+	unsigned char value;
+	unsigned int *pointer_write = &channel->pointer_write;
+
+	if (channel->nb_bytes <= 0) {
+		channel->nb_bytes = 0;
+		return;
+	}
+
+	value = channel->tty_port.xmit_buf[*pointer_write];
+	iowrite8(value, &channel->regs->w.thr);
+	channel->stats.tx++;
+	(*pointer_write)++;
+	*pointer_write = *pointer_write % PAGE_SIZE;
+	channel->nb_bytes--;
+
+	if ((channel->nb_bytes == 0) &&
+	    (waitqueue_active(&channel->queue))) {
+
+		if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) {
+			*channel->board_write = 1;
+			wake_up_interruptible(&channel->queue);
+		}
+	}
+}
+
+static void ipoctal_irq_channel(struct ipoctal_channel *channel)
+{
+	u8 isr, sr;
 	struct tty_struct *tty;
+
+	/* If there is no client, skip the check */
+	if (!atomic_read(&channel->open))
+		return;
+
+	tty = tty_port_tty_get(&channel->tty_port);
+	if (!tty)
+		return;
+	/* The HW is organized in pair of channels.  See which register we need
+	 * to read from */
+	isr = ioread8(&channel->block_regs->r.isr);
+	sr = ioread8(&channel->regs->r.sr);
+
+	/* In case of RS-485, change from TX to RX when finishing TX.
+	 * Half-duplex. */
+	if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) &&
+	    (sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
+		iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
+		iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
+		iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
+		*channel->board_write = 1;
+		wake_up_interruptible(&channel->queue);
+	}
+
+	/* RX data */
+	if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY))
+		ipoctal_irq_rx(channel, tty, sr);
+
+	/* TX of each character */
+	if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
+		ipoctal_irq_tx(channel);
+
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static irqreturn_t ipoctal_irq_handler(void *arg)
+{
+	unsigned int i;
 	struct ipoctal *ipoctal = (struct ipoctal *) arg;
 
 	/* Check all channels */
-	for (channel = 0; channel < NR_CHANNELS; channel++) {
-		/* If there is no client, skip the check */
-		if (!atomic_read(&ipoctal->open[channel]))
-			continue;
+	for (i = 0; i < NR_CHANNELS; i++)
+		ipoctal_irq_channel(&ipoctal->channel[i]);
 
-		tty = tty_port_tty_get(&ipoctal->tty_port[channel]);
-		if (!tty)
-			continue;
+	/* Clear the IPack device interrupt */
+	readw(ipoctal->dev->int_space.address + ACK_INT_REQ0);
+	readw(ipoctal->dev->int_space.address + ACK_INT_REQ1);
 
-		/*
-		 * The HW is organized in pair of channels.
-		 * See which register we need to read from
-		 */
-		block = channel / 2;
-		isr = ipoctal_read_io_reg(ipoctal,
-					  &ipoctal->block_regs[block].u.r.isr);
-		sr = ipoctal_read_io_reg(ipoctal,
-					 &ipoctal->chan_regs[channel].u.r.sr);
-
-		if ((channel % 2) == 1) {
-			isr_tx_rdy = isr & ISR_TxRDY_B;
-			isr_rx_rdy = isr & ISR_RxRDY_FFULL_B;
-		} else {
-			isr_tx_rdy = isr & ISR_TxRDY_A;
-			isr_rx_rdy = isr & ISR_RxRDY_FFULL_A;
-		}
-
-		/* In case of RS-485, change from TX to RX when finishing TX.
-		 * Half-duplex.
-		 */
-		if ((ipoctal->board_id == IP_OCTAL_485_ID) &&
-		    (sr & SR_TX_EMPTY) &&
-		    (ipoctal->nb_bytes[channel] == 0)) {
-			ipoctal_write_io_reg(ipoctal,
-					     &ipoctal->chan_regs[channel].u.w.cr,
-					     CR_DISABLE_TX);
-			ipoctal_write_cr_cmd(ipoctal,
-					     &ipoctal->chan_regs[channel].u.w.cr,
-					     CR_CMD_NEGATE_RTSN);
-			ipoctal_write_io_reg(ipoctal,
-					     &ipoctal->chan_regs[channel].u.w.cr,
-					     CR_ENABLE_RX);
-			ipoctal->write = 1;
-			wake_up_interruptible(&ipoctal->queue[channel]);
-		}
-
-		/* RX data */
-		if (isr_rx_rdy && (sr & SR_RX_READY)) {
-			value = ipoctal_read_io_reg(ipoctal,
-						    &ipoctal->chan_regs[channel].u.r.rhr);
-			flag = TTY_NORMAL;
-
-			/* Error: count statistics */
-			if (sr & SR_ERROR) {
-				ipoctal_write_cr_cmd(ipoctal,
-						     &ipoctal->chan_regs[channel].u.w.cr,
-						     CR_CMD_RESET_ERR_STATUS);
-
-				if (sr & SR_OVERRUN_ERROR) {
-					ipoctal->chan_stats[channel].overrun_err++;
-					/* Overrun doesn't affect the current character*/
-					tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-				}
-				if (sr & SR_PARITY_ERROR) {
-					ipoctal->chan_stats[channel].parity_err++;
-					flag = TTY_PARITY;
-				}
-				if (sr & SR_FRAMING_ERROR) {
-					ipoctal->chan_stats[channel].framing_err++;
-					flag = TTY_FRAME;
-				}
-				if (sr & SR_RECEIVED_BREAK) {
-					ipoctal->chan_stats[channel].rcv_break++;
-					flag = TTY_BREAK;
-				}
-			}
-
-			tty_insert_flip_char(tty, value, flag);
-		}
-
-		/* TX of each character */
-		if (isr_tx_rdy && (sr & SR_TX_READY)) {
-			unsigned int *pointer_write =
-				&ipoctal->pointer_write[channel];
-
-			if (ipoctal->nb_bytes[channel] <= 0) {
-				ipoctal->nb_bytes[channel] = 0;
-				continue;
-			}
-
-			value = ipoctal->tty_port[channel].xmit_buf[*pointer_write];
-			ipoctal_write_io_reg(ipoctal,
-					     &ipoctal->chan_regs[channel].u.w.thr,
-					     value);
-			ipoctal->chan_stats[channel].tx++;
-			ipoctal->count_wr[channel]++;
-			(*pointer_write)++;
-			*pointer_write = *pointer_write % PAGE_SIZE;
-			ipoctal->nb_bytes[channel]--;
-
-			if ((ipoctal->nb_bytes[channel] == 0) &&
-			    (waitqueue_active(&ipoctal->queue[channel]))) {
-
-				if (ipoctal->board_id != IP_OCTAL_485_ID) {
-					ipoctal->write = 1;
-					wake_up_interruptible(&ipoctal->queue[channel]);
-				}
-			}
-		}
-
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
-	}
 	return IRQ_HANDLED;
 }
 
@@ -331,18 +263,15 @@
 	unsigned char manufacturerID;
 	unsigned char board_id;
 
-	dev->bus->ops->read8(dev, IPACK_ID_SPACE,
-			IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID);
-	if (manufacturerID != IP_OCTAL_MANUFACTURER_ID)
+
+	manufacturerID = ioread8(dev->id_space.address + IPACK_IDPROM_OFFSET_MANUFACTURER_ID);
+	if (manufacturerID != IPACK1_VENDOR_ID_SBS)
 		return -ENODEV;
-
-	dev->bus->ops->read8(dev, IPACK_ID_SPACE,
-			IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id);
-
+	board_id = ioread8(dev->id_space.address + IPACK_IDPROM_OFFSET_MODEL);
 	switch (board_id) {
-	case IP_OCTAL_232_ID:
-	case IP_OCTAL_422_ID:
-	case IP_OCTAL_485_ID:
+	case IPACK1_DEVICE_ID_SBS_OCTAL_232:
+	case IPACK1_DEVICE_ID_SBS_OCTAL_422:
+	case IPACK1_DEVICE_ID_SBS_OCTAL_485:
 		*id = board_id;
 		break;
 	default:
@@ -358,13 +287,16 @@
 };
 
 static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
-			     unsigned int slot, unsigned int vector)
+			     unsigned int slot)
 {
 	int res = 0;
 	int i;
 	struct tty_driver *tty;
 	char name[20];
 	unsigned char board_id;
+	struct ipoctal_channel *channel;
+	union scc2698_channel __iomem *chan_regs;
+	union scc2698_block __iomem *block_regs;
 
 	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
 						IPACK_ID_SPACE);
@@ -392,54 +324,61 @@
 		goto out_unregister_id_space;
 	}
 
+	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+						IPACK_INT_SPACE);
+	if (res) {
+		dev_err(&ipoctal->dev->dev,
+			"Unable to map slot [%d:%d] INT space!\n",
+			bus_nr, slot);
+		goto out_unregister_io_space;
+	}
+
 	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev,
 					   0x8000, IPACK_MEM_SPACE);
 	if (res) {
 		dev_err(&ipoctal->dev->dev,
 			"Unable to map slot [%d:%d] MEM space!\n",
 			bus_nr, slot);
-		goto out_unregister_io_space;
+		goto out_unregister_int_space;
 	}
 
 	/* Save the virtual address to access the registers easily */
-	ipoctal->chan_regs =
-		(struct scc2698_channel *) ipoctal->dev->io_space.address;
-	ipoctal->block_regs =
-		(struct scc2698_block *) ipoctal->dev->io_space.address;
+	chan_regs =
+		(union scc2698_channel __iomem *) ipoctal->dev->io_space.address;
+	block_regs =
+		(union scc2698_block __iomem *) ipoctal->dev->io_space.address;
 
 	/* Disable RX and TX before touching anything */
 	for (i = 0; i < NR_CHANNELS ; i++) {
-		ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
-				     CR_DISABLE_RX | CR_DISABLE_TX);
-		ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
-				     CR_CMD_RESET_RX);
-		ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
-				     CR_CMD_RESET_TX);
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->chan_regs[i].u.w.mr,
-				     MR1_CHRL_8_BITS | MR1_ERROR_CHAR |
-				     MR1_RxINT_RxRDY); /* mr1 */
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->chan_regs[i].u.w.mr,
-				     0); /* mr2 */
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->chan_regs[i].u.w.csr,
-				     TX_CLK_9600  | RX_CLK_9600);
+		struct ipoctal_channel *channel = &ipoctal->channel[i];
+		channel->regs = chan_regs + i;
+		channel->block_regs = block_regs + (i >> 1);
+		channel->board_write = &ipoctal->write;
+		channel->board_id = ipoctal->board_id;
+		if (i & 1) {
+			channel->isr_tx_rdy_mask = ISR_TxRDY_B;
+			channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_B;
+		} else {
+			channel->isr_tx_rdy_mask = ISR_TxRDY_A;
+			channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
+		}
+
+		iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+		iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
+		iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
+		iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
+			 &channel->regs->w.mr); /* mr1 */
+		iowrite8(0, &channel->regs->w.mr); /* mr2 */
+		iowrite8(TX_CLK_9600  | RX_CLK_9600, &channel->regs->w.csr);
 	}
 
 	for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->block_regs[i].u.w.acr,
-				     ACR_BRG_SET2);
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->block_regs[i].u.w.opcr,
-				     OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN |
-				     OPCR_MPOb_RTSN);
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->block_regs[i].u.w.imr,
-				     IMR_TxRDY_A | IMR_RxRDY_FFULL_A |
-				     IMR_DELTA_BREAK_A | IMR_TxRDY_B |
-				     IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B);
+		iowrite8(ACR_BRG_SET2, &block_regs[i].w.acr);
+		iowrite8(OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | OPCR_MPOb_RTSN,
+			 &block_regs[i].w.opcr);
+		iowrite8(IMR_TxRDY_A | IMR_RxRDY_FFULL_A | IMR_DELTA_BREAK_A |
+			 IMR_TxRDY_B | IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B,
+			 &block_regs[i].w.imr);
 	}
 
 	/*
@@ -447,10 +386,10 @@
 	 * Depending of the carrier these addresses are accesible or not.
 	 * More info in the datasheet.
 	 */
-	ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector,
+	ipoctal->dev->bus->ops->request_irq(ipoctal->dev,
 				       ipoctal_irq_handler, ipoctal);
-	ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_MEM_SPACE, 0,
-				       vector);
+	/* Dummy write */
+	iowrite8(1, ipoctal->dev->mem_space.address + 1);
 
 	/* Register the TTY device */
 
@@ -464,8 +403,8 @@
 
 	/* Fill struct tty_driver with ipoctal data */
 	tty->owner = THIS_MODULE;
-	tty->driver_name = "ipoctal";
-	sprintf(name, "ipoctal.%d.%d.", bus_nr, slot);
+	tty->driver_name = KBUILD_MODNAME;
+	sprintf(name, KBUILD_MODNAME ".%d.%d.", bus_nr, slot);
 	tty->name = name;
 	tty->major = 0;
 
@@ -490,32 +429,40 @@
 	ipoctal->tty_drv = tty;
 
 	for (i = 0; i < NR_CHANNELS; i++) {
-		tty_port_init(&ipoctal->tty_port[i]);
-		tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]);
-		ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops;
+		struct device *tty_dev;
 
-		ipoctal_reset_stats(&ipoctal->chan_stats[i]);
-		ipoctal->nb_bytes[i] = 0;
-		init_waitqueue_head(&ipoctal->queue[i]);
+		channel = &ipoctal->channel[i];
+		tty_port_init(&channel->tty_port);
+		tty_port_alloc_xmit_buf(&channel->tty_port);
+		channel->tty_port.ops = &ipoctal_tty_port_ops;
 
-		spin_lock_init(&ipoctal->lock[i]);
-		ipoctal->pointer_read[i] = 0;
-		ipoctal->pointer_write[i] = 0;
-		ipoctal->nb_bytes[i] = 0;
-		tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL);
+		ipoctal_reset_stats(&channel->stats);
+		channel->nb_bytes = 0;
+		init_waitqueue_head(&channel->queue);
+
+		spin_lock_init(&channel->lock);
+		channel->pointer_read = 0;
+		channel->pointer_write = 0;
+		tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
+		if (IS_ERR(tty_dev)) {
+			dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
+			continue;
+		}
+		dev_set_drvdata(tty_dev, channel);
 
 		/*
 		 * Enable again the RX. TX will be enabled when
 		 * there is something to send
 		 */
-		ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
-				     CR_ENABLE_RX);
+		iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
 	}
 
 	return 0;
 
 out_unregister_slot_unmap:
 	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE);
+out_unregister_int_space:
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_INT_SPACE);
 out_unregister_io_space:
 	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE);
 out_unregister_id_space:
@@ -523,23 +470,22 @@
 	return res;
 }
 
-static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal,
-					    unsigned int channel,
+static inline int ipoctal_copy_write_buffer(struct ipoctal_channel *channel,
 					    const unsigned char *buf,
 					    int count)
 {
 	unsigned long flags;
 	int i;
-	unsigned int *pointer_read = &ipoctal->pointer_read[channel];
+	unsigned int *pointer_read = &channel->pointer_read;
 
 	/* Copy the bytes from the user buffer to the internal one */
 	for (i = 0; i < count; i++) {
-		if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) {
-			spin_lock_irqsave(&ipoctal->lock[channel], flags);
-			ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i];
+		if (i <= (PAGE_SIZE - channel->nb_bytes)) {
+			spin_lock_irqsave(&channel->lock, flags);
+			channel->tty_port.xmit_buf[*pointer_read] = buf[i];
 			*pointer_read = (*pointer_read + 1) % PAGE_SIZE;
-			ipoctal->nb_bytes[channel]++;
-			spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+			channel->nb_bytes++;
+			spin_unlock_irqrestore(&channel->lock, flags);
 		} else {
 			break;
 		}
@@ -547,63 +493,44 @@
 	return i;
 }
 
-static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel,
-			 const unsigned char *buf, int count)
+static int ipoctal_write_tty(struct tty_struct *tty,
+			     const unsigned char *buf, int count)
 {
-	ipoctal->nb_bytes[channel] = 0;
-	ipoctal->count_wr[channel] = 0;
+	struct ipoctal_channel *channel = tty->driver_data;
+	unsigned int char_copied;
 
-	ipoctal_copy_write_buffer(ipoctal, channel, buf, count);
+	char_copied = ipoctal_copy_write_buffer(channel, buf, count);
 
 	/* As the IP-OCTAL 485 only supports half duplex, do it manually */
-	if (ipoctal->board_id == IP_OCTAL_485_ID) {
-		ipoctal_write_io_reg(ipoctal,
-				     &ipoctal->chan_regs[channel].u.w.cr,
-				     CR_DISABLE_RX);
-		ipoctal_write_cr_cmd(ipoctal,
-				     &ipoctal->chan_regs[channel].u.w.cr,
-				     CR_CMD_ASSERT_RTSN);
+	if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) {
+		iowrite8(CR_DISABLE_RX, &channel->regs->w.cr);
+		iowrite8(CR_CMD_ASSERT_RTSN, &channel->regs->w.cr);
 	}
 
 	/*
 	 * Send a packet and then disable TX to avoid failure after several send
 	 * operations
 	 */
-	ipoctal_write_io_reg(ipoctal,
-			     &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_ENABLE_TX);
-	wait_event_interruptible(ipoctal->queue[channel], ipoctal->write);
-	ipoctal_write_io_reg(ipoctal,
-			     &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_DISABLE_TX);
+	iowrite8(CR_ENABLE_TX, &channel->regs->w.cr);
+	wait_event_interruptible(channel->queue, *channel->board_write);
+	iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
 
-	ipoctal->write = 0;
-	return ipoctal->count_wr[channel];
-}
-
-static int ipoctal_write_tty(struct tty_struct *tty,
-			     const unsigned char *buf, int count)
-{
-	unsigned int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
-
-	return ipoctal_write(ipoctal, channel, buf, count);
+	*channel->board_write = 0;
+	return char_copied;
 }
 
 static int ipoctal_write_room(struct tty_struct *tty)
 {
-	int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
+	struct ipoctal_channel *channel = tty->driver_data;
 
-	return PAGE_SIZE - ipoctal->nb_bytes[channel];
+	return PAGE_SIZE - channel->nb_bytes;
 }
 
 static int ipoctal_chars_in_buffer(struct tty_struct *tty)
 {
-	int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
+	struct ipoctal_channel *channel = tty->driver_data;
 
-	return ipoctal->nb_bytes[channel];
+	return channel->nb_bytes;
 }
 
 static void ipoctal_set_termios(struct tty_struct *tty,
@@ -613,23 +540,17 @@
 	unsigned char mr1 = 0;
 	unsigned char mr2 = 0;
 	unsigned char csr = 0;
-	unsigned int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
+	struct ipoctal_channel *channel = tty->driver_data;
 	speed_t baud;
 
 	cflag = tty->termios.c_cflag;
 
 	/* Disable and reset everything before change the setup */
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_DISABLE_RX | CR_DISABLE_TX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_RX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_TX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_ERR_STATUS);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_MR);
+	iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
 
 	/* Set Bits per chars */
 	switch (cflag & CSIZE) {
@@ -666,8 +587,8 @@
 		mr2 |= MR2_STOP_BITS_LENGTH_1;
 
 	/* Set the flow control */
-	switch (ipoctal->board_id) {
-	case IP_OCTAL_232_ID:
+	switch (channel->board_id) {
+	case IPACK1_DEVICE_ID_SBS_OCTAL_232:
 		if (cflag & CRTSCTS) {
 			mr1 |= MR1_RxRTS_CONTROL_ON;
 			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON;
@@ -676,11 +597,11 @@
 			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
 		}
 		break;
-	case IP_OCTAL_422_ID:
+	case IPACK1_DEVICE_ID_SBS_OCTAL_422:
 		mr1 |= MR1_RxRTS_CONTROL_OFF;
 		mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
 		break;
-	case IP_OCTAL_485_ID:
+	case IPACK1_DEVICE_ID_SBS_OCTAL_485:
 		mr1 |= MR1_RxRTS_CONTROL_OFF;
 		mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF;
 		break;
@@ -742,45 +663,38 @@
 	mr1 |= MR1_RxINT_RxRDY;
 
 	/* Write the control registers */
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1);
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2);
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr);
+	iowrite8(mr1, &channel->regs->w.mr);
+	iowrite8(mr2, &channel->regs->w.mr);
+	iowrite8(csr, &channel->regs->w.csr);
 
 	/* Enable again the RX */
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_ENABLE_RX);
+	iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
 }
 
 static void ipoctal_hangup(struct tty_struct *tty)
 {
 	unsigned long flags;
-	int channel = tty->index;
-	struct ipoctal *ipoctal = tty->driver_data;
+	struct ipoctal_channel *channel = tty->driver_data;
 
-	if (ipoctal == NULL)
+	if (channel == NULL)
 		return;
 
-	spin_lock_irqsave(&ipoctal->lock[channel], flags);
-	ipoctal->nb_bytes[channel] = 0;
-	ipoctal->pointer_read[channel] = 0;
-	ipoctal->pointer_write[channel] = 0;
-	spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->nb_bytes = 0;
+	channel->pointer_read = 0;
+	channel->pointer_write = 0;
+	spin_unlock_irqrestore(&channel->lock, flags);
 
-	tty_port_hangup(&ipoctal->tty_port[channel]);
+	tty_port_hangup(&channel->tty_port);
 
-	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_DISABLE_RX | CR_DISABLE_TX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_RX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_TX);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_ERR_STATUS);
-	ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
-			     CR_CMD_RESET_MR);
+	iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
+	iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
 
-	clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags);
-	wake_up_interruptible(&ipoctal->tty_port[channel].open_wait);
+	clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
+	wake_up_interruptible(&channel->tty_port.open_wait);
 }
 
 static const struct tty_operations ipoctal_fops = {
@@ -795,27 +709,6 @@
 	.hangup =		ipoctal_hangup,
 };
 
-static int ipoctal_match(struct ipack_device *dev)
-{
-	int res;
-	unsigned char board_id;
-
-	if ((!dev->bus->ops) || (!dev->bus->ops->map_space) ||
-	    (!dev->bus->ops->unmap_space))
-		return 0;
-
-	res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
-	if (res)
-		return 0;
-
-	res = ipoctal_check_model(dev, &board_id);
-	dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
-	if (!res)
-		return 1;
-
-	return 0;
-}
-
 static int ipoctal_probe(struct ipack_device *dev)
 {
 	int res;
@@ -826,11 +719,11 @@
 		return -ENOMEM;
 
 	ipoctal->dev = dev;
-	res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq);
+	res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot);
 	if (res)
 		goto out_uninst;
 
-	list_add_tail(&ipoctal->list, &ipoctal_list);
+	dev_set_drvdata(&dev->dev, ipoctal);
 	return 0;
 
 out_uninst:
@@ -842,46 +735,57 @@
 {
 	int i;
 
+	ipoctal->dev->bus->ops->free_irq(ipoctal->dev);
+
 	for (i = 0; i < NR_CHANNELS; i++) {
+		struct ipoctal_channel *channel = &ipoctal->channel[i];
 		tty_unregister_device(ipoctal->tty_drv, i);
-		tty_port_free_xmit_buf(&ipoctal->tty_port[i]);
+		tty_port_free_xmit_buf(&channel->tty_port);
 	}
 
 	tty_unregister_driver(ipoctal->tty_drv);
 	put_tty_driver(ipoctal->tty_drv);
-	list_del(&ipoctal->list);
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE);
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_INT_SPACE);
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE);
+	ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE);
 	kfree(ipoctal);
 }
 
-static void ipoctal_remove(struct ipack_device *device)
+static void ipoctal_remove(struct ipack_device *idev)
 {
-	struct ipoctal *ipoctal, *next;
-
-	list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) {
-		if (ipoctal->dev == device)
-			__ipoctal_remove(ipoctal);
-	}
+	__ipoctal_remove(dev_get_drvdata(&idev->dev));
 }
 
-static struct ipack_driver_ops ipoctal_drv_ops = {
-	.match = ipoctal_match,
-	.probe = ipoctal_probe,
+static DEFINE_IPACK_DEVICE_TABLE(ipoctal_ids) = {
+	{ IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS,
+			IPACK1_DEVICE_ID_SBS_OCTAL_232) },
+	{ IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS,
+			IPACK1_DEVICE_ID_SBS_OCTAL_422) },
+	{ IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS,
+			IPACK1_DEVICE_ID_SBS_OCTAL_485) },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(ipack, ipoctal_ids);
+
+static const struct ipack_driver_ops ipoctal_drv_ops = {
+	.probe  = ipoctal_probe,
 	.remove = ipoctal_remove,
 };
 
+static struct ipack_driver driver = {
+	.ops      = &ipoctal_drv_ops,
+	.id_table = ipoctal_ids,
+};
+
 static int __init ipoctal_init(void)
 {
-	driver.ops = &ipoctal_drv_ops;
 	return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME);
 }
 
 static void __exit ipoctal_exit(void)
 {
-	struct ipoctal *p, *next;
-
-	list_for_each_entry_safe(p, next, &ipoctal_list, list)
-		p->dev->bus->ops->remove_device(p->dev);
-
 	ipack_driver_unregister(&driver);
 }
 
diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h
index 47f6269..96e8d8c 100644
--- a/drivers/staging/ipack/devices/scc2698.h
+++ b/drivers/staging/ipack/devices/scc2698.h
@@ -15,78 +15,74 @@
 #define SCC2698_H_
 
 /*
- * struct scc2698_channel - Channel access to scc2698 IO
+ * union scc2698_channel - Channel access to scc2698 IO
  *
  * dn value are only spacer.
  *
  */
-struct scc2698_channel {
-	union {
-		struct {
-			unsigned char d0, mr;  /* Mode register 1/2*/
-			unsigned char d1, sr;  /* Status register */
-			unsigned char d2, r1;  /* reserved */
-			unsigned char d3, rhr; /* Receive holding register (R) */
-			unsigned char junk[8]; /* other crap for block control */
-		} r; /* Read access */
-		struct {
-			unsigned char d0, mr;  /* Mode register 1/2 */
-			unsigned char d1, csr; /* Clock select register */
-			unsigned char d2, cr;  /* Command register */
-			unsigned char d3, thr; /* Transmit holding register */
-			unsigned char junk[8]; /* other crap for block control */
-		} w; /* Write access */
-	} u;
+union scc2698_channel {
+	struct {
+		u8 d0, mr;  /* Mode register 1/2*/
+		u8 d1, sr;  /* Status register */
+		u8 d2, r1;  /* reserved */
+		u8 d3, rhr; /* Receive holding register (R) */
+		u8 junk[8]; /* other crap for block control */
+	} __packed r; /* Read access */
+	struct {
+		u8 d0, mr;  /* Mode register 1/2 */
+		u8 d1, csr; /* Clock select register */
+		u8 d2, cr;  /* Command register */
+		u8 d3, thr; /* Transmit holding register */
+		u8 junk[8]; /* other crap for block control */
+	} __packed w; /* Write access */
 };
 
 /*
- * struct scc2698_block - Block access to scc2698 IO
+ * union scc2698_block - Block access to scc2698 IO
  *
  * The scc2698 contain 4 block.
  * Each block containt two channel a and b.
  * dn value are only spacer.
  *
  */
-struct scc2698_block {
-	union {
-		struct {
-			unsigned char d0, mra;  /* Mode register 1/2 (a) */
-			unsigned char d1, sra;  /* Status register (a) */
-			unsigned char d2, r1;   /* reserved */
-			unsigned char d3, rhra; /* Receive holding register (a) */
-			unsigned char d4, ipcr; /* Input port change register of block */
-			unsigned char d5, isr;  /* Interrupt status register of block */
-			unsigned char d6, ctur; /* Counter timer upper register of block */
-			unsigned char d7, ctlr; /* Counter timer lower register of block */
-			unsigned char d8, mrb;  /* Mode register 1/2 (b) */
-			unsigned char d9, srb;  /* Status register (b) */
-			unsigned char da, r2;   /* reserved */
-			unsigned char db, rhrb; /* Receive holding register (b) */
-			unsigned char dc, r3;   /* reserved */
-			unsigned char dd, ip;   /* Input port register of block */
-			unsigned char de, ctg;  /* Start counter timer of block */
-			unsigned char df, cts;  /* Stop counter timer of block */
-		} r; /* Read access */
-		struct {
-			unsigned char d0, mra;  /* Mode register 1/2 (a) */
-			unsigned char d1, csra; /* Clock select register (a) */
-			unsigned char d2, cra;  /* Command register (a) */
-			unsigned char d3, thra; /* Transmit holding register (a) */
-			unsigned char d4, acr;  /* Auxiliary control register of block */
-			unsigned char d5, imr;  /* Interrupt mask register of block  */
-			unsigned char d6, ctu;  /* Counter timer upper register of block */
-			unsigned char d7, ctl;  /* Counter timer lower register of block */
-			unsigned char d8, mrb;  /* Mode register 1/2 (b) */
-			unsigned char d9, csrb; /* Clock select register (a) */
-			unsigned char da, crb;  /* Command register (b) */
-			unsigned char db, thrb; /* Transmit holding register (b) */
-			unsigned char dc, r1;   /* reserved */
-			unsigned char dd, opcr; /* Output port configuration register of block */
-			unsigned char de, r2;   /* reserved */
-			unsigned char df, r3;   /* reserved */
-		} w; /* Write access */
-	} u;
-} ;
+union scc2698_block {
+	struct {
+		u8 d0, mra;  /* Mode register 1/2 (a) */
+		u8 d1, sra;  /* Status register (a) */
+		u8 d2, r1;   /* reserved */
+		u8 d3, rhra; /* Receive holding register (a) */
+		u8 d4, ipcr; /* Input port change register of block */
+		u8 d5, isr;  /* Interrupt status register of block */
+		u8 d6, ctur; /* Counter timer upper register of block */
+		u8 d7, ctlr; /* Counter timer lower register of block */
+		u8 d8, mrb;  /* Mode register 1/2 (b) */
+		u8 d9, srb;  /* Status register (b) */
+		u8 da, r2;   /* reserved */
+		u8 db, rhrb; /* Receive holding register (b) */
+		u8 dc, r3;   /* reserved */
+		u8 dd, ip;   /* Input port register of block */
+		u8 de, ctg;  /* Start counter timer of block */
+		u8 df, cts;  /* Stop counter timer of block */
+	} __packed r; /* Read access */
+	struct {
+		u8 d0, mra;  /* Mode register 1/2 (a) */
+		u8 d1, csra; /* Clock select register (a) */
+		u8 d2, cra;  /* Command register (a) */
+		u8 d3, thra; /* Transmit holding register (a) */
+		u8 d4, acr;  /* Auxiliary control register of block */
+		u8 d5, imr;  /* Interrupt mask register of block  */
+		u8 d6, ctu;  /* Counter timer upper register of block */
+		u8 d7, ctl;  /* Counter timer lower register of block */
+		u8 d8, mrb;  /* Mode register 1/2 (b) */
+		u8 d9, csrb; /* Clock select register (a) */
+		u8 da, crb;  /* Command register (b) */
+		u8 db, thrb; /* Transmit holding register (b) */
+		u8 dc, r1;   /* reserved */
+		u8 dd, opcr; /* Output port configuration register of block */
+		u8 de, r2;   /* reserved */
+		u8 df, r3;   /* reserved */
+	} __packed w; /* Write access */
+};
 
 #define MR1_CHRL_5_BITS             (0x0 << 0)
 #define MR1_CHRL_6_BITS             (0x1 << 0)
@@ -225,4 +221,7 @@
 #define ISR_DELTA_BREAK_B           (0x1 << 6)
 #define ISR_INPUT_PORT_CHANGE       (0x1 << 7)
 
+#define ACK_INT_REQ0			0
+#define ACK_INT_REQ1			2
+
 #endif /* SCC2698_H_ */
diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c
index c1cd97a..d1e0651 100644
--- a/drivers/staging/ipack/ipack.c
+++ b/drivers/staging/ipack/ipack.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
+#include <asm/io.h>
 #include "ipack.h"
 
 #define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
@@ -22,55 +23,190 @@
 static void ipack_device_release(struct device *dev)
 {
 	struct ipack_device *device = to_ipack_dev(dev);
+	kfree(device->id);
 	kfree(device);
 }
 
-static int ipack_bus_match(struct device *device, struct device_driver *driver)
+static inline const struct ipack_device_id *
+ipack_match_one_device(const struct ipack_device_id *id,
+		       const struct ipack_device *device)
 {
-	int ret;
-	struct ipack_device *dev = to_ipack_dev(device);
-	struct ipack_driver *drv = to_ipack_driver(driver);
+	if ((id->format == IPACK_ANY_FORMAT ||
+				id->format == device->id_format) &&
+	    (id->vendor == IPACK_ANY_ID || id->vendor == device->id_vendor) &&
+	    (id->device == IPACK_ANY_ID || id->device == device->id_device))
+		return id;
+	return NULL;
+}
 
-	if ((!drv->ops) || (!drv->ops->match))
-		return -EINVAL;
+static const struct ipack_device_id *
+ipack_match_id(const struct ipack_device_id *ids, struct ipack_device *idev)
+{
+	if (ids) {
+		while (ids->vendor || ids->device) {
+			if (ipack_match_one_device(ids, idev))
+				return ids;
+			ids++;
+		}
+	}
+	return NULL;
+}
 
-	ret = drv->ops->match(dev);
-	if (ret)
-		dev->driver = drv;
+static int ipack_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct ipack_device *idev = to_ipack_dev(dev);
+	struct ipack_driver *idrv = to_ipack_driver(drv);
+	const struct ipack_device_id *found_id;
 
-	return ret;
+	found_id = ipack_match_id(idrv->id_table, idev);
+	return found_id ? 1 : 0;
 }
 
 static int ipack_bus_probe(struct device *device)
 {
 	struct ipack_device *dev = to_ipack_dev(device);
+	struct ipack_driver *drv = to_ipack_driver(device->driver);
 
-	if (!dev->driver->ops->probe)
+	if (!drv->ops->probe)
 		return -EINVAL;
 
-	return dev->driver->ops->probe(dev);
+	return drv->ops->probe(dev);
 }
 
 static int ipack_bus_remove(struct device *device)
 {
 	struct ipack_device *dev = to_ipack_dev(device);
+	struct ipack_driver *drv = to_ipack_driver(device->driver);
 
-	if (!dev->driver->ops->remove)
+	if (!drv->ops->remove)
 		return -EINVAL;
 
-	dev->driver->ops->remove(dev);
+	drv->ops->remove(dev);
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG
+
+static int ipack_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct ipack_device *idev;
+
+	if (!dev)
+		return -ENODEV;
+
+	idev = to_ipack_dev(dev);
+
+	if (add_uevent_var(env,
+			   "MODALIAS=ipack:f%02Xv%08Xd%08X", idev->id_format,
+			   idev->id_vendor, idev->id_device))
+		return -ENOMEM;
+
+	return 0;
+}
+
+#else /* !CONFIG_HOTPLUG */
+
+#define ipack_uevent NULL
+
+#endif /* !CONFIG_HOTPLUG */
+
+#define ipack_device_attr(field, format_string)				\
+static ssize_t								\
+field##_show(struct device *dev, struct device_attribute *attr,		\
+		char *buf)						\
+{									\
+	struct ipack_device *idev = to_ipack_dev(dev);			\
+	return sprintf(buf, format_string, idev->field);		\
+}
+
+static ssize_t id_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
+{
+	unsigned int i, c, l, s;
+	struct ipack_device *idev = to_ipack_dev(dev);
+
+
+	switch (idev->id_format) {
+	case IPACK_ID_VERSION_1:
+		l = 0x7; s = 1; break;
+	case IPACK_ID_VERSION_2:
+		l = 0xf; s = 2; break;
+	default:
+		return -EIO;
+	}
+	c = 0;
+	for (i = 0; i < idev->id_avail; i++) {
+		if (i > 0) {
+			if ((i & l) == 0)
+				buf[c++] = '\n';
+			else if ((i & s) == 0)
+				buf[c++] = ' ';
+		}
+		sprintf(&buf[c], "%02x", idev->id[i]);
+		c += 2;
+	}
+	buf[c++] = '\n';
+	return c;
+}
+
+static ssize_t
+id_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ipack_device *idev = to_ipack_dev(dev);
+	switch (idev->id_format) {
+	case IPACK_ID_VERSION_1:
+		return sprintf(buf, "0x%02x\n", idev->id_vendor);
+	case IPACK_ID_VERSION_2:
+		return sprintf(buf, "0x%06x\n", idev->id_vendor);
+	default:
+		return -EIO;
+	}
+}
+
+static ssize_t
+id_device_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ipack_device *idev = to_ipack_dev(dev);
+	switch (idev->id_format) {
+	case IPACK_ID_VERSION_1:
+		return sprintf(buf, "0x%02x\n", idev->id_device);
+	case IPACK_ID_VERSION_2:
+		return sprintf(buf, "0x%04x\n", idev->id_device);
+	default:
+		return -EIO;
+	}
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ipack_device *idev = to_ipack_dev(dev);
+
+	return sprintf(buf, "ipac:f%02Xv%08Xd%08X", idev->id_format,
+		       idev->id_vendor, idev->id_device);
+}
+
+ipack_device_attr(id_format, "0x%hhu\n");
+
+static struct device_attribute ipack_dev_attrs[] = {
+	__ATTR_RO(id),
+	__ATTR_RO(id_device),
+	__ATTR_RO(id_format),
+	__ATTR_RO(id_vendor),
+	__ATTR_RO(modalias),
+};
+
 static struct bus_type ipack_bus_type = {
-	.name  = "ipack",
-	.probe = ipack_bus_probe,
-	.match = ipack_bus_match,
-	.remove = ipack_bus_remove,
+	.name      = "ipack",
+	.probe     = ipack_bus_probe,
+	.match     = ipack_bus_match,
+	.remove    = ipack_bus_remove,
+	.dev_attrs = ipack_dev_attrs,
+	.uevent	   = ipack_uevent,
 };
 
 struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
-					    struct ipack_bus_ops *ops)
+					    const struct ipack_bus_ops *ops)
 {
 	int bus_nr;
 	struct ipack_bus_device *bus;
@@ -93,8 +229,20 @@
 }
 EXPORT_SYMBOL_GPL(ipack_bus_register);
 
+static int ipack_unregister_bus_member(struct device *dev, void *data)
+{
+	struct ipack_device *idev = to_ipack_dev(dev);
+	struct ipack_bus_device *bus = data;
+
+	if (idev->bus_nr == bus->bus_nr)
+		ipack_device_unregister(idev);
+
+	return 1;
+}
+
 int ipack_bus_unregister(struct ipack_bus_device *bus)
 {
+	bus_for_each_dev(&ipack_bus_type, NULL, bus, ipack_unregister_bus_member);
 	ida_simple_remove(&ipack_ida, bus->bus_nr);
 	kfree(bus);
 	return 0;
@@ -102,7 +250,7 @@
 EXPORT_SYMBOL_GPL(ipack_bus_unregister);
 
 int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
-			  char *name)
+			  const char *name)
 {
 	edrv->driver.owner = owner;
 	edrv->driver.name = name;
@@ -117,8 +265,169 @@
 }
 EXPORT_SYMBOL_GPL(ipack_driver_unregister);
 
+static u16 ipack_crc_byte(u16 crc, u8 c)
+{
+	int i;
+
+	crc ^= c << 8;
+	for (i = 0; i < 8; i++)
+		crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0);
+	return crc;
+}
+
+/*
+ * The algorithm in lib/crc-ccitt.c does not seem to apply since it uses the
+ * opposite bit ordering.
+ */
+static u8 ipack_calc_crc1(struct ipack_device *dev)
+{
+	u8 c;
+	u16 crc;
+	unsigned int i;
+
+	crc = 0xffff;
+	for (i = 0; i < dev->id_avail; i++) {
+		c = (i != 11) ? dev->id[i] : 0;
+		crc = ipack_crc_byte(crc, c);
+	}
+	crc = ~crc;
+	return crc & 0xff;
+}
+
+static u16 ipack_calc_crc2(struct ipack_device *dev)
+{
+	u8 c;
+	u16 crc;
+	unsigned int i;
+
+	crc = 0xffff;
+	for (i = 0; i < dev->id_avail; i++) {
+		c = ((i != 0x18) && (i != 0x19)) ? dev->id[i] : 0;
+		crc = ipack_crc_byte(crc, c);
+	}
+	crc = ~crc;
+	return crc;
+}
+
+static void ipack_parse_id1(struct ipack_device *dev)
+{
+	u8 *id = dev->id;
+	u8 crc;
+
+	dev->id_vendor = id[4];
+	dev->id_device = id[5];
+	dev->speed_8mhz = 1;
+	dev->speed_32mhz = (id[7] == 'H');
+	crc = ipack_calc_crc1(dev);
+	dev->id_crc_correct = (crc == id[11]);
+	if (!dev->id_crc_correct) {
+		dev_warn(&dev->dev, "ID CRC invalid found 0x%x, expected 0x%x.\n",
+				id[11], crc);
+	}
+}
+
+static void ipack_parse_id2(struct ipack_device *dev)
+{
+	__be16 *id = (__be16 *) dev->id;
+	u16 flags, crc;
+
+	dev->id_vendor = ((be16_to_cpu(id[3]) & 0xff) << 16)
+			 + be16_to_cpu(id[4]);
+	dev->id_device = be16_to_cpu(id[5]);
+	flags = be16_to_cpu(id[10]);
+	dev->speed_8mhz = !!(flags & 2);
+	dev->speed_32mhz = !!(flags & 4);
+	crc = ipack_calc_crc2(dev);
+	dev->id_crc_correct = (crc == be16_to_cpu(id[12]));
+	if (!dev->id_crc_correct) {
+		dev_warn(&dev->dev, "ID CRC invalid found 0x%x, expected 0x%x.\n",
+				id[11], crc);
+	}
+}
+
+static int ipack_device_read_id(struct ipack_device *dev)
+{
+	u8 __iomem *idmem;
+	int i;
+	int ret = 0;
+
+	ret = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
+	if (ret) {
+		dev_err(&dev->dev, "error mapping memory\n");
+		return ret;
+	}
+	idmem = dev->id_space.address;
+
+	/* Determine ID PROM Data Format.  If we find the ids "IPAC" or "IPAH"
+	 * we are dealing with a IndustryPack  format 1 device.  If we detect
+	 * "VITA4 " (16 bit big endian formatted) we are dealing with a
+	 * IndustryPack format 2 device */
+	if ((ioread8(idmem + 1) == 'I') &&
+			(ioread8(idmem + 3) == 'P') &&
+			(ioread8(idmem + 5) == 'A') &&
+			((ioread8(idmem + 7) == 'C') ||
+			 (ioread8(idmem + 7) == 'H'))) {
+		dev->id_format = IPACK_ID_VERSION_1;
+		dev->id_avail = ioread8(idmem + 0x15);
+		if ((dev->id_avail < 0x0c) || (dev->id_avail > 0x40)) {
+			dev_warn(&dev->dev, "invalid id size");
+			dev->id_avail = 0x0c;
+		}
+	} else if ((ioread8(idmem + 0) == 'I') &&
+			(ioread8(idmem + 1) == 'V') &&
+			(ioread8(idmem + 2) == 'A') &&
+			(ioread8(idmem + 3) == 'T') &&
+			(ioread8(idmem + 4) == ' ') &&
+			(ioread8(idmem + 5) == '4')) {
+		dev->id_format = IPACK_ID_VERSION_2;
+		dev->id_avail = ioread16be(idmem + 0x16);
+		if ((dev->id_avail < 0x1a) || (dev->id_avail > 0x40)) {
+			dev_warn(&dev->dev, "invalid id size");
+			dev->id_avail = 0x1a;
+		}
+	} else {
+		dev->id_format = IPACK_ID_VERSION_INVALID;
+		dev->id_avail = 0;
+	}
+
+	if (!dev->id_avail) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* Obtain the amount of memory required to store a copy of the complete
+	 * ID ROM contents */
+	dev->id = kmalloc(dev->id_avail, GFP_KERNEL);
+	if (!dev->id) {
+		dev_err(&dev->dev, "dev->id alloc failed.\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	for (i = 0; i < dev->id_avail; i++) {
+		if (dev->id_format == IPACK_ID_VERSION_1)
+			dev->id[i] = ioread8(idmem + (i << 1) + 1);
+		else
+			dev->id[i] = ioread8(idmem + i);
+	}
+
+	/* now we can finally work with the copy */
+	switch (dev->id_format) {
+	case IPACK_ID_VERSION_1:
+		ipack_parse_id1(dev);
+		break;
+	case IPACK_ID_VERSION_2:
+		ipack_parse_id2(dev);
+		break;
+	}
+
+out:
+	dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
+
+	return ret;
+}
+
 struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
-					   int slot, int irqv)
+					   int slot)
 {
 	int ret;
 	struct ipack_device *dev;
@@ -132,13 +441,32 @@
 	dev->dev.parent = bus->parent;
 	dev->slot = slot;
 	dev->bus_nr = bus->bus_nr;
-	dev->irq = irqv;
 	dev->bus = bus;
 	dev_set_name(&dev->dev,
 		     "ipack-dev.%u.%u", dev->bus_nr, dev->slot);
 
+	if (bus->ops->set_clockrate(dev, 8))
+		dev_warn(&dev->dev, "failed to switch to 8 MHz operation for reading of device ID.\n");
+	if (bus->ops->reset_timeout(dev))
+		dev_warn(&dev->dev, "failed to reset potential timeout.");
+
+	ret = ipack_device_read_id(dev);
+	if (ret < 0) {
+		dev_err(&dev->dev, "error reading device id section.\n");
+		kfree(dev);
+		return NULL;
+	}
+
+	/* if the device supports 32 MHz operation, use it. */
+	if (dev->speed_32mhz) {
+		ret = bus->ops->set_clockrate(dev, 32);
+		if (ret < 0)
+			dev_err(&dev->dev, "failed to switch to 32 MHz operation.\n");
+	}
+
 	ret = device_register(&dev->dev);
 	if (ret < 0) {
+		kfree(dev->id);
 		kfree(dev);
 		return NULL;
 	}
diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h
index 8bc001e..d8e3bb6 100644
--- a/drivers/staging/ipack/ipack.h
+++ b/drivers/staging/ipack/ipack.h
@@ -9,7 +9,11 @@
  * Software Foundation; version 2 of the License.
  */
 
+#include <linux/mod_devicetable.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include "ipack_ids.h"
 
 #define IPACK_IDPROM_OFFSET_I			0x01
 #define IPACK_IDPROM_OFFSET_P			0x03
@@ -31,6 +35,7 @@
 	IPACK_IO_SPACE    = 0,
 	IPACK_ID_SPACE    = 1,
 	IPACK_MEM_SPACE   = 2,
+	IPACK_INT_SPACE,
 };
 
 /**
@@ -49,8 +54,6 @@
  *
  *	@bus_nr: IP bus number where the device is plugged
  *	@slot: Slot where the device is plugged in the carrier board
- *	@irq: IRQ vector
- *	@driver: Pointer to the ipack_driver that manages the device
  *	@bus: ipack_bus_device where the device is plugged to.
  *	@id_space: Virtual address to ID space.
  *	@io_space: Virtual address to IO space.
@@ -64,25 +67,30 @@
 struct ipack_device {
 	unsigned int bus_nr;
 	unsigned int slot;
-	unsigned int irq;
-	struct ipack_driver *driver;
 	struct ipack_bus_device *bus;
 	struct ipack_addr_space id_space;
 	struct ipack_addr_space io_space;
+	struct ipack_addr_space int_space;
 	struct ipack_addr_space mem_space;
 	struct device dev;
+	u8                      *id;
+	size_t			 id_avail;
+	u32			 id_vendor;
+	u32			 id_device;
+	u8			 id_format;
+	unsigned int		 id_crc_correct:1;
+	unsigned int		 speed_8mhz:1;
+	unsigned int		 speed_32mhz:1;
 };
 
 /**
  *	struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device
  *
- *	@match: Match function
  *	@probe: Probe function
  *	@remove: tell the driver that the carrier board wants to remove one device
  */
 
 struct ipack_driver_ops {
-	int (*match) (struct ipack_device *dev);
 	int (*probe) (struct ipack_device *dev);
 	void (*remove) (struct ipack_device *dev);
 };
@@ -95,7 +103,8 @@
  */
 struct ipack_driver {
 	struct device_driver driver;
-	struct ipack_driver_ops *ops;
+	const struct ipack_device_id *id_table;
+	const struct ipack_driver_ops *ops;
 };
 
 /**
@@ -105,26 +114,27 @@
  *	@unmap_space: unmap IP address space
  *	@request_irq: request IRQ
  *	@free_irq: free IRQ
- *	@read8: read unsigned char
- *	@read16: read unsigned short
- *	@read32: read unsigned int
- *	@write8: read unsigned char
- *	@write16: read unsigned short
- *	@write32: read unsigned int
- *	@remove_device: tell the bridge module that the device has been removed
+ *	@get_clockrate: Returns the clockrate the carrier is currently
+ *		communicating with the device at.
+ *	@set_clockrate: Sets the clock-rate for carrier / module communication.
+ *		Should return -EINVAL if the requested speed is not supported.
+ *	@get_error: Returns the error state for the slot the device is attached
+ *		to.
+ *	@get_timeout: Returns 1 if the communication with the device has
+ *		previously timed out.
+ *	@reset_timeout: Resets the state returned by get_timeout.
  */
 struct ipack_bus_ops {
 	int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space);
 	int (*unmap_space) (struct ipack_device *dev, int space);
-	int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg);
+	int (*request_irq) (struct ipack_device *dev,
+			    irqreturn_t (*handler)(void *), void *arg);
 	int (*free_irq) (struct ipack_device *dev);
-	int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value);
-	int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value);
-	int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value);
-	int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value);
-	int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value);
-	int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value);
-	int (*remove_device) (struct ipack_device *dev);
+	int (*get_clockrate) (struct ipack_device *dev);
+	int (*set_clockrate) (struct ipack_device *dev, int mherz);
+	int (*get_error) (struct ipack_device *dev);
+	int (*get_timeout) (struct ipack_device *dev);
+	int (*reset_timeout) (struct ipack_device *dev);
 };
 
 /**
@@ -139,7 +149,7 @@
 	struct device *parent;
 	int slots;
 	int bus_nr;
-	struct ipack_bus_ops *ops;
+	const struct ipack_bus_ops *ops;
 };
 
 /**
@@ -153,7 +163,7 @@
  * available bus device in ipack.
  */
 struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
-					    struct ipack_bus_ops *ops);
+					    const struct ipack_bus_ops *ops);
 
 /**
  *	ipack_bus_unregister -- unregister an ipack bus
@@ -166,7 +176,8 @@
  * Called by a ipack driver to register itself as a driver
  * that can manage ipack devices.
  */
-int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name);
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
+			  const char *name);
 void ipack_driver_unregister(struct ipack_driver *edrv);
 
 /**
@@ -174,10 +185,33 @@
  *
  * @bus: ipack bus device it is plugged to.
  * @slot: slot position in the bus device.
- * @irqv: IRQ vector for the mezzanine.
  *
  * Register a new ipack device (mezzanine device). The call is done by
  * the carrier device driver.
  */
-struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv);
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot);
 void ipack_device_unregister(struct ipack_device *dev);
+
+/**
+ * DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table
+ * @_table: device table name
+ *
+ * This macro is used to create a struct ipack_device_id array (a device table)
+ * in a generic manner.
+ */
+#define DEFINE_IPACK_DEVICE_TABLE(_table) \
+	const struct ipack_device_id _table[] __devinitconst
+
+/**
+ * IPACK_DEVICE - macro used to describe a specific IndustryPack device
+ * @_format: the format version (currently either 1 or 2, 8 bit value)
+ * @vend:    the 8 or 24 bit IndustryPack Vendor ID
+ * @dev:     the 8 or 16  bit IndustryPack Device ID
+ *
+ * This macro is used to create a struct ipack_device_id that matches a specific
+ * device.
+ */
+#define IPACK_DEVICE(_format, vend, dev) \
+	 .format = (_format), \
+	 .vendor = (vend), \
+	 .device = (dev)
diff --git a/drivers/staging/ipack/ipack_ids.h b/drivers/staging/ipack/ipack_ids.h
new file mode 100644
index 0000000..8153fee
--- /dev/null
+++ b/drivers/staging/ipack/ipack_ids.h
@@ -0,0 +1,32 @@
+/*
+ * IndustryPack Fromat, Vendor and Device IDs.
+ */
+
+/* ID section format versions */
+#define IPACK_ID_VERSION_INVALID	0x00
+#define IPACK_ID_VERSION_1		0x01
+#define IPACK_ID_VERSION_2		0x02
+
+/* Vendors and devices. Sort key: vendor first, device next. */
+#define IPACK1_VENDOR_ID_RESERVED1	0x00
+#define IPACK1_VENDOR_ID_RESERVED2	0xFF
+#define IPACK1_VENDOR_ID_UNREGISTRED01	0x01
+#define IPACK1_VENDOR_ID_UNREGISTRED02	0x02
+#define IPACK1_VENDOR_ID_UNREGISTRED03	0x03
+#define IPACK1_VENDOR_ID_UNREGISTRED04	0x04
+#define IPACK1_VENDOR_ID_UNREGISTRED05	0x05
+#define IPACK1_VENDOR_ID_UNREGISTRED06	0x06
+#define IPACK1_VENDOR_ID_UNREGISTRED07	0x07
+#define IPACK1_VENDOR_ID_UNREGISTRED08	0x08
+#define IPACK1_VENDOR_ID_UNREGISTRED09	0x09
+#define IPACK1_VENDOR_ID_UNREGISTRED10	0x0A
+#define IPACK1_VENDOR_ID_UNREGISTRED11	0x0B
+#define IPACK1_VENDOR_ID_UNREGISTRED12	0x0C
+#define IPACK1_VENDOR_ID_UNREGISTRED13	0x0D
+#define IPACK1_VENDOR_ID_UNREGISTRED14	0x0E
+#define IPACK1_VENDOR_ID_UNREGISTRED15	0x0F
+
+#define IPACK1_VENDOR_ID_SBS            0xF0
+#define IPACK1_DEVICE_ID_SBS_OCTAL_232  0x22
+#define IPACK1_DEVICE_ID_SBS_OCTAL_422  0x2A
+#define IPACK1_DEVICE_ID_SBS_OCTAL_485  0x48
diff --git a/drivers/staging/keucr/smcommon.h b/drivers/staging/keucr/smcommon.h
index 278bdb8..4d57203 100644
--- a/drivers/staging/keucr/smcommon.h
+++ b/drivers/staging/keucr/smcommon.h
@@ -25,7 +25,5 @@
 #define ERR_NoSmartMedia    0x003A /* Medium Not Present */
 
 /***************************************************************************/
-void StringCopy(char *, char *, int);
-int  StringCmp(char *, char *, int);
 
 #endif
diff --git a/drivers/staging/keucr/usb.c b/drivers/staging/keucr/usb.c
index 4833034..55a0b82 100644
--- a/drivers/staging/keucr/usb.c
+++ b/drivers/staging/keucr/usb.c
@@ -320,7 +320,7 @@
 
 	us->subclass = idesc->bInterfaceSubClass;
 	us->protocol = idesc->bInterfaceProtocol;
-	us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+	us->fflags = id->driver_info;
 	us->Power_IsResum = false;
 
 	if (us->fflags & US_FL_IGNORE_DEVICE)
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 5e319e3..7fe44a6 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -48,7 +48,13 @@
 				      const char *buf, size_t count)
 {
 	struct snd_line6_pcm *line6pcm = dev2pcm(dev);
-	int value = simple_strtoul(buf, NULL, 10);
+	int value;
+	int rv;
+
+	rv = kstrtoint(buf, 10, &value);
+	if (rv < 0)
+		return rv;
+
 	line6pcm->impulse_volume = value;
 
 	if (value > 0)
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
index bb99ee4..f97416b 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -353,10 +353,10 @@
 {
 	struct usb_line6_variax *variax =
 	    usb_get_intfdata(to_usb_interface(dev));
-	unsigned long value;
+	u8 value;
 	int ret;
 
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtou8(buf, 10, &value);
 	if (ret)
 		return ret;
 
@@ -387,10 +387,10 @@
 {
 	struct usb_line6_variax *variax =
 	    usb_get_intfdata(to_usb_interface(dev));
-	unsigned long value;
+	u8 value;
 	int ret;
 
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtou8(buf, 10, &value);
 	if (ret)
 		return ret;
 
diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig
index 43048e9..1235a789 100644
--- a/drivers/staging/nvec/Kconfig
+++ b/drivers/staging/nvec/Kconfig
@@ -28,7 +28,7 @@
 
 config NVEC_PAZ00
 	bool "Support for OEM specific functions on Compal PAZ00 based devices"
-	depends on MFD_NVEC && LEDS_CLASS && MACH_PAZ00
+	depends on MFD_NVEC && LEDS_CLASS
 	help
 	  Say Y to enable control of the yellow side leds on Compal PAZ00 based
 	  devices, e.g. Toshbia AC100 and Dynabooks AZ netbooks.
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index d0a7e40..24d8eeb 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -264,7 +264,7 @@
 	list_add_tail(&msg->node, &nvec->tx_data);
 	spin_unlock_irqrestore(&nvec->tx_lock, flags);
 
-	queue_work(nvec->wq, &nvec->tx_work);
+	queue_work(system_nrt_wq, &nvec->tx_work);
 
 	return 0;
 }
@@ -294,8 +294,10 @@
 
 	nvec->sync_write_pending = (data[1] << 8) + data[0];
 
-	if (nvec_write_async(nvec, data, size) < 0)
+	if (nvec_write_async(nvec, data, size) < 0) {
+		mutex_unlock(&nvec->sync_write_mutex);
 		return NULL;
+	}
 
 	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
 					nvec->sync_write_pending);
@@ -366,8 +368,7 @@
 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
 {
 	if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) {
-		dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n",
-			msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
+		dev_err(nvec->dev, "ec responded %*ph\n", 4, msg->data);
 		return -EINVAL;
 	}
 
@@ -470,7 +471,7 @@
 	if (!nvec_msg_is_event(nvec->rx))
 		complete(&nvec->ec_transfer);
 
-	queue_work(nvec->wq, &nvec->rx_work);
+	queue_work(system_nrt_wq, &nvec->rx_work);
 }
 
 /**
@@ -737,12 +738,14 @@
 		nvec->gpio = pdata->gpio;
 		nvec->i2c_addr = pdata->i2c_addr;
 	} else if (nvec->dev->of_node) {
-		nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0);
+		nvec->gpio = of_get_named_gpio(nvec->dev->of_node,
+					"request-gpios", 0);
 		if (nvec->gpio < 0) {
 			dev_err(&pdev->dev, "no gpio specified");
 			return -ENODEV;
 		}
-		if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) {
+		if (of_property_read_u32(nvec->dev->of_node,
+					"slave-addr", &nvec->i2c_addr)) {
 			dev_err(&pdev->dev, "no i2c address specified");
 			return -ENODEV;
 		}
@@ -769,7 +772,7 @@
 		return -ENODEV;
 	}
 
-	i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
+	i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk");
 	if (IS_ERR(i2c_clk)) {
 		dev_err(nvec->dev, "failed to get controller clock\n");
 		return -ENODEV;
@@ -791,13 +794,11 @@
 	INIT_LIST_HEAD(&nvec->tx_data);
 	INIT_WORK(&nvec->rx_work, nvec_dispatch);
 	INIT_WORK(&nvec->tx_work, nvec_request_master);
-	nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2);
 
 	err = devm_gpio_request_one(&pdev->dev, nvec->gpio, GPIOF_OUT_INIT_HIGH,
 					"nvec gpio");
 	if (err < 0) {
 		dev_err(nvec->dev, "couldn't request gpio\n");
-		destroy_workqueue(nvec->wq);
 		return -ENODEV;
 	}
 
@@ -805,7 +806,6 @@
 				"nvec", nvec);
 	if (err) {
 		dev_err(nvec->dev, "couldn't request irq\n");
-		destroy_workqueue(nvec->wq);
 		return -ENODEV;
 	}
 	disable_irq(nvec->irq);
@@ -859,7 +859,8 @@
 
 	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
 	mfd_remove_devices(nvec->dev);
-	destroy_workqueue(nvec->wq);
+	cancel_work_sync(&nvec->rx_work);
+	cancel_work_sync(&nvec->tx_work);
 
 	return 0;
 }
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 2c4bd74..d49c32a 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -11,6 +11,7 @@
  * License as published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
@@ -72,18 +73,16 @@
 
 	ver = dcon_read(dcon, DCON_REG_ID);
 	if ((ver >> 8) != 0xDC) {
-		printk(KERN_ERR "olpc-dcon:  DCON ID not 0xDCxx: 0x%04x instead.\n",
-			ver);
+		pr_err("DCON ID not 0xDCxx: 0x%04x instead.\n", ver);
 		rc = -ENXIO;
 		goto err;
 	}
 
 	if (is_init) {
-		printk(KERN_INFO "olpc-dcon:  Discovered DCON version %x\n",
-				ver & 0xFF);
+		pr_info("Discovered DCON version %x\n", ver & 0xFF);
 		rc = pdata->init(dcon);
 		if (rc != 0) {
-			printk(KERN_ERR "olpc-dcon:  Unable to init.\n");
+			pr_err("Unable to init.\n");
 			goto err;
 		}
 	}
@@ -137,8 +136,7 @@
 		x = 1;
 		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
 		if (x) {
-			printk(KERN_WARNING "olpc-dcon:  unable to force dcon to power up: %d!\n",
-				x);
+			pr_warn("unable to force dcon to power up: %d!\n", x);
 			return x;
 		}
 		msleep(10); /* we'll be conservative */
@@ -151,7 +149,7 @@
 		x = dcon_read(dcon, DCON_REG_ID);
 	}
 	if (x < 0) {
-		printk(KERN_ERR "olpc-dcon:  unable to stabilize dcon's smbus, reasserting power and praying.\n");
+		pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n");
 		BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
 		x = 0;
 		olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
@@ -222,8 +220,7 @@
 		x = 0;
 		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
 		if (x)
-			printk(KERN_WARNING "olpc-dcon:  unable to force dcon to power down: %d!\n",
-				x);
+			pr_warn("unable to force dcon to power down: %d!\n", x);
 		else
 			dcon->asleep = sleep;
 	} else {
@@ -232,8 +229,7 @@
 			dcon->disp_mode |= MODE_BL_ENABLE;
 		x = dcon_bus_stabilize(dcon, 1);
 		if (x)
-			printk(KERN_WARNING "olpc-dcon:  unable to reinit dcon hardware: %d!\n",
-				x);
+			pr_warn("unable to reinit dcon hardware: %d!\n", x);
 		else
 			dcon->asleep = sleep;
 
@@ -304,12 +300,11 @@
 
 	switch (source) {
 	case DCON_SOURCE_CPU:
-		printk(KERN_INFO "dcon_source_switch to CPU\n");
+		pr_info("dcon_source_switch to CPU\n");
 		/* Enable the scanline interrupt bit */
 		if (dcon_write(dcon, DCON_REG_MODE,
 				dcon->disp_mode | MODE_SCAN_INT))
-			printk(KERN_ERR
-			       "olpc-dcon:  couldn't enable scanline interrupt!\n");
+			pr_err("couldn't enable scanline interrupt!\n");
 		else {
 			/* Wait up to one second for the scanline interrupt */
 			wait_event_timeout(dcon_wait_queue,
@@ -317,11 +312,11 @@
 		}
 
 		if (!dcon->switched)
-			printk(KERN_ERR "olpc-dcon:  Timeout entering CPU mode; expect a screen glitch.\n");
+			pr_err("Timeout entering CPU mode; expect a screen glitch.\n");
 
 		/* Turn off the scanline interrupt */
 		if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode))
-			printk(KERN_ERR "olpc-dcon:  couldn't disable scanline interrupt!\n");
+			pr_err("couldn't disable scanline interrupt!\n");
 
 		/*
 		 * Ideally we'd like to disable interrupts here so that the
@@ -332,7 +327,7 @@
 		 * For now, we just hope..
 		 */
 		if (!dcon_blank_fb(dcon, false)) {
-			printk(KERN_ERR "olpc-dcon:  Failed to enter CPU mode\n");
+			pr_err("Failed to enter CPU mode\n");
 			dcon->pending_src = DCON_SOURCE_DCON;
 			return;
 		}
@@ -341,14 +336,14 @@
 		pdata->set_dconload(1);
 		getnstimeofday(&dcon->load_time);
 
-		printk(KERN_INFO "olpc-dcon: The CPU has control\n");
+		pr_info("The CPU has control\n");
 		break;
 	case DCON_SOURCE_DCON:
 	{
 		int t;
 		struct timespec delta_t;
 
-		printk(KERN_INFO "dcon_source_switch to DCON\n");
+		pr_info("dcon_source_switch to DCON\n");
 
 		add_wait_queue(&dcon_wait_queue, &wait);
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -362,7 +357,7 @@
 		set_current_state(TASK_RUNNING);
 
 		if (!dcon->switched) {
-			printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n");
+			pr_err("Timeout entering DCON mode; expect a screen glitch.\n");
 		} else {
 			/* sometimes the DCON doesn't follow its own rules,
 			 * and doesn't wait for two vsync pulses before
@@ -378,7 +373,7 @@
 			delta_t = timespec_sub(dcon->irq_time, dcon->load_time);
 			if (dcon->switched && delta_t.tv_sec == 0 &&
 					delta_t.tv_nsec < NSEC_PER_MSEC * 20) {
-				printk(KERN_ERR "olpc-dcon: missed loading, retrying\n");
+				pr_err("missed loading, retrying\n");
 				pdata->set_dconload(1);
 				mdelay(41);
 				pdata->set_dconload(0);
@@ -388,7 +383,7 @@
 		}
 
 		dcon_blank_fb(dcon, true);
-		printk(KERN_INFO "olpc-dcon: The DCON has control\n");
+		pr_info("The DCON has control\n");
 		break;
 	}
 	default:
@@ -476,7 +471,7 @@
 	if (ret)
 		return ret;
 
-	printk(KERN_INFO "dcon_freeze_store: %lu\n", output);
+	pr_info("dcon_freeze_store: %lu\n", output);
 
 	switch (output) {
 	case 0:
@@ -650,7 +645,7 @@
 	dcon_device = platform_device_alloc("dcon", -1);
 
 	if (dcon_device == NULL) {
-		printk(KERN_ERR "dcon:  Unable to create the DCON device\n");
+		pr_err("Unable to create the DCON device\n");
 		rc = -ENOMEM;
 		goto eirq;
 	}
@@ -658,7 +653,7 @@
 	platform_set_drvdata(dcon_device, dcon);
 
 	if (rc) {
-		printk(KERN_ERR "dcon:  Unable to add the DCON device\n");
+		pr_err("Unable to add the DCON device\n");
 		goto edev;
 	}
 
@@ -762,7 +757,7 @@
 
 	switch (status & 3) {
 	case 3:
-		printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n");
+		pr_debug("DCONLOAD_MISSED interrupt\n");
 		break;
 
 	case 2:	/* switch to DCON mode */
@@ -784,9 +779,9 @@
 			dcon->switched = true;
 			getnstimeofday(&dcon->irq_time);
 			wake_up(&dcon_wait_queue);
-			printk(KERN_DEBUG "olpc-dcon: switching w/ status 0/0\n");
+			pr_debug("switching w/ status 0/0\n");
 		} else {
-			printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n");
+			pr_debug("scanline interrupt w/CPU\n");
 		}
 	}
 
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index c87fdfa..77e8eb5 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -10,6 +10,9 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/cs5535.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
@@ -22,23 +25,23 @@
 	unsigned char lob;
 
 	if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) {
-		printk(KERN_ERR "olpc-dcon: failed to request STAT0 GPIO\n");
+		pr_err("failed to request STAT0 GPIO\n");
 		return -EIO;
 	}
 	if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) {
-		printk(KERN_ERR "olpc-dcon: failed to request STAT1 GPIO\n");
+		pr_err("failed to request STAT1 GPIO\n");
 		goto err_gp_stat1;
 	}
 	if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) {
-		printk(KERN_ERR "olpc-dcon: failed to request IRQ GPIO\n");
+		pr_err("failed to request IRQ GPIO\n");
 		goto err_gp_irq;
 	}
 	if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) {
-		printk(KERN_ERR "olpc-dcon: failed to request LOAD GPIO\n");
+		pr_err("failed to request LOAD GPIO\n");
 		goto err_gp_load;
 	}
 	if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) {
-		printk(KERN_ERR "olpc-dcon: failed to request BLANK GPIO\n");
+		pr_err("failed to request BLANK GPIO\n");
 		goto err_gp_blank;
 	}
 
@@ -83,7 +86,7 @@
 
 	/* Register the interrupt handler */
 	if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", dcon)) {
-		printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n");
+		pr_err("failed to request DCON's irq\n");
 		goto err_req_irq;
 	}
 
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
index 69415ee..352dd3d 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
@@ -6,6 +6,8 @@
  * License as published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
@@ -66,7 +68,7 @@
 	pdev = pci_get_device(PCI_VENDOR_ID_VIA,
 			      PCI_DEVICE_ID_VIA_VX855, NULL);
 	if (!pdev) {
-		printk(KERN_ERR "cannot find VX855 PCI ID\n");
+		pr_err("cannot find VX855 PCI ID\n");
 		return 1;
 	}
 
@@ -104,7 +106,7 @@
 	/* we're sharing the IRQ with ACPI */
 	irq = acpi_gbl_FADT.sci_interrupt;
 	if (request_irq(irq, &dcon_interrupt, IRQF_SHARED, "DCON", dcon)) {
-		printk(KERN_ERR PREFIX "DCON (IRQ%d) allocation failed\n", irq);
+		pr_err("DCON (IRQ%d) allocation failed\n", irq);
 		return 1;
 	}
 
diff --git a/drivers/staging/omap-thermal/omap-bandgap.c b/drivers/staging/omap-thermal/omap-bandgap.c
index c556abb..368a2e1 100644
--- a/drivers/staging/omap-thermal/omap-bandgap.c
+++ b/drivers/staging/omap-thermal/omap-bandgap.c
@@ -157,7 +157,7 @@
 	high = ts_data->adc_end_val - ts_data->adc_start_val;
 	mid = (high + low) / 2;
 
-	if (temp < bg_ptr->conv_table[high] || temp > bg_ptr->conv_table[high])
+	if (temp < bg_ptr->conv_table[low] || temp > bg_ptr->conv_table[high])
 		return -EINVAL;
 
 	while (low < high) {
@@ -953,12 +953,12 @@
 	for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
 		char *domain;
 
+		if (bg_ptr->conf->sensors[i].register_cooling)
+			bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i);
+
 		domain = bg_ptr->conf->sensors[i].domain;
 		if (bg_ptr->conf->expose_sensor)
 			bg_ptr->conf->expose_sensor(bg_ptr, i, domain);
-
-		if (bg_ptr->conf->sensors[i].register_cooling)
-			bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i);
 	}
 
 	/*
@@ -1037,20 +1037,20 @@
 
 		if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
 			rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr,
-								tsr->bgap_mode_ctrl);
+							tsr->bgap_mode_ctrl);
 		if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
 			rval->bg_counter = omap_bandgap_readl(bg_ptr,
-							      tsr->bgap_counter);
+							tsr->bgap_counter);
 		if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
 			rval->bg_threshold = omap_bandgap_readl(bg_ptr,
-								tsr->bgap_threshold);
+							tsr->bgap_threshold);
 			rval->bg_ctrl = omap_bandgap_readl(bg_ptr,
-							   tsr->bgap_mask_ctrl);
+						   tsr->bgap_mask_ctrl);
 		}
 
 		if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
 			rval->tshut_threshold = omap_bandgap_readl(bg_ptr,
-								   tsr->tshut_threshold);
+						   tsr->tshut_threshold);
 	}
 
 	return 0;
@@ -1074,8 +1074,9 @@
 
 		if (val == 0) {
 			if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
-				omap_bandgap_writel(bg_ptr, rval->tshut_threshold,
-							   tsr->tshut_threshold);
+				omap_bandgap_writel(bg_ptr,
+					rval->tshut_threshold,
+						   tsr->tshut_threshold);
 			/* Force immediate temperature measurement and update
 			 * of the DTEMP field
 			 */
diff --git a/drivers/staging/omap-thermal/omap-thermal-common.c b/drivers/staging/omap-thermal/omap-thermal-common.c
index 0675a5e..46ee0a9f 100644
--- a/drivers/staging/omap-thermal/omap-thermal-common.c
+++ b/drivers/staging/omap-thermal/omap-thermal-common.c
@@ -77,10 +77,16 @@
 					 unsigned long *temp)
 {
 	struct omap_thermal_data *data = thermal->devdata;
-	struct omap_bandgap *bg_ptr = data->bg_ptr;
-	struct omap_temp_sensor *s = &bg_ptr->conf->sensors[data->sensor_id];
+	struct omap_bandgap *bg_ptr;
+	struct omap_temp_sensor *s;
 	int ret, tmp, pcb_temp, slope, constant;
 
+	if (!data)
+		return 0;
+
+	bg_ptr = data->bg_ptr;
+	s = &bg_ptr->conf->sensors[data->sensor_id];
+
 	ret = omap_bandgap_read_temperature(bg_ptr, data->sensor_id, &tmp);
 	if (ret)
 		return ret;
@@ -227,26 +233,44 @@
 	.get_crit_temp = omap_thermal_get_crit_temp,
 };
 
-int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
-			       char *domain)
+static struct omap_thermal_data
+*omap_thermal_build_data(struct omap_bandgap *bg_ptr, int id)
 {
 	struct omap_thermal_data *data;
 
 	data = devm_kzalloc(bg_ptr->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		dev_err(bg_ptr->dev, "kzalloc fail\n");
-		return -ENOMEM;
+		return NULL;
 	}
 	data->sensor_id = id;
 	data->bg_ptr = bg_ptr;
 	data->mode = THERMAL_DEVICE_ENABLED;
 	INIT_WORK(&data->thermal_wq, omap_thermal_work);
 
+	return data;
+}
+
+int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
+			       char *domain)
+{
+	struct omap_thermal_pdata pdata;
+
+	data = omap_bandgap_get_sensor_data(bg_ptr, id);
+
+	if (!data)
+		data = omap_thermal_build_pdata(bg_ptr, id);
+
+	if (!data)
+		return -EINVAL;
+
 	/* TODO: remove TC1 TC2 */
 	/* Create thermal zone */
 	data->omap_thermal = thermal_zone_device_register(domain,
 				OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
-				0, FAST_TEMP_MONITORING_RATE, 0, 0);
+				1, 2, /*TODO: remove this when FW allows */
+				FAST_TEMP_MONITORING_RATE,
+				FAST_TEMP_MONITORING_RATE);
 	if (IS_ERR_OR_NULL(data->omap_thermal)) {
 		dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
 		return PTR_ERR(data->omap_thermal);
@@ -333,6 +357,11 @@
 	int tab_size, ret;
 
 	data = omap_bandgap_get_sensor_data(bg_ptr, id);
+	if (!data)
+		data = omap_thermal_build_pdata(bg_ptr, id);
+
+	if (!data)
+		return -EINVAL;
 
 	ret = omap_thermal_build_cpufreq_clip(bg_ptr, &tab_ptr, &tab_size);
 	if (ret < 0) {
@@ -349,6 +378,7 @@
 		return PTR_ERR(data->cool_dev);
 	}
 	bg_ptr->conf->sensors[id].cooling_data.freq_clip_count = tab_size;
+	omap_bandgap_set_sensor_data(bg_ptr, id, data);
 
 	return 0;
 }
diff --git a/drivers/staging/omap-thermal/omap4-thermal.c b/drivers/staging/omap-thermal/omap4-thermal.c
index fa9dbcd..04c02b6 100644
--- a/drivers/staging/omap-thermal/omap4-thermal.c
+++ b/drivers/staging/omap-thermal/omap4-thermal.c
@@ -77,15 +77,15 @@
 	.remove_sensor = omap_thermal_remove_sensor,
 	.sensors = {
 		{
-			.registers = &omap4430_mpu_temp_sensor_registers,
-			.ts_data = &omap4430_mpu_temp_sensor_data,
-			.domain = "cpu",
-			.slope = 0,
-			.constant = 20000,
-			.slope_pcb = 0,
-			.constant_pcb = 20000,
-			.register_cooling = omap_thermal_register_cpu_cooling,
-			.unregister_cooling = omap_thermal_unregister_cpu_cooling,
+		.registers = &omap4430_mpu_temp_sensor_registers,
+		.ts_data = &omap4430_mpu_temp_sensor_data,
+		.domain = "cpu",
+		.slope = 0,
+		.constant = 20000,
+		.slope_pcb = 0,
+		.constant_pcb = 20000,
+		.register_cooling = omap_thermal_register_cpu_cooling,
+		.unregister_cooling = omap_thermal_unregister_cpu_cooling,
 		},
 	},
 	.sensor_count = 1,
@@ -215,15 +215,15 @@
 	.remove_sensor = omap_thermal_remove_sensor,
 	.sensors = {
 		{
-			.registers = &omap4460_mpu_temp_sensor_registers,
-			.ts_data = &omap4460_mpu_temp_sensor_data,
-			.domain = "cpu",
-			.slope = OMAP_GRADIENT_SLOPE_4460,
-			.constant = OMAP_GRADIENT_CONST_4460,
-			.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
-			.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
-			.register_cooling = omap_thermal_register_cpu_cooling,
-			.unregister_cooling = omap_thermal_unregister_cpu_cooling,
+		.registers = &omap4460_mpu_temp_sensor_registers,
+		.ts_data = &omap4460_mpu_temp_sensor_data,
+		.domain = "cpu",
+		.slope = OMAP_GRADIENT_SLOPE_4460,
+		.constant = OMAP_GRADIENT_CONST_4460,
+		.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
+		.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
+		.register_cooling = omap_thermal_register_cpu_cooling,
+		.unregister_cooling = omap_thermal_unregister_cpu_cooling,
 		},
 	},
 	.sensor_count = 1,
@@ -244,15 +244,15 @@
 	.remove_sensor = omap_thermal_remove_sensor,
 	.sensors = {
 		{
-			.registers = &omap4460_mpu_temp_sensor_registers,
-			.ts_data = &omap4460_mpu_temp_sensor_data,
-			.domain = "cpu",
-			.slope = OMAP_GRADIENT_SLOPE_4470,
-			.constant = OMAP_GRADIENT_CONST_4470,
-			.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
-			.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
-			.register_cooling = omap_thermal_register_cpu_cooling,
-			.unregister_cooling = omap_thermal_unregister_cpu_cooling,
+		.registers = &omap4460_mpu_temp_sensor_registers,
+		.ts_data = &omap4460_mpu_temp_sensor_data,
+		.domain = "cpu",
+		.slope = OMAP_GRADIENT_SLOPE_4470,
+		.constant = OMAP_GRADIENT_CONST_4470,
+		.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
+		.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
+		.register_cooling = omap_thermal_register_cpu_cooling,
+		.unregister_cooling = omap_thermal_unregister_cpu_cooling,
 		},
 	},
 	.sensor_count = 1,
diff --git a/drivers/staging/omap-thermal/omap5-thermal.c b/drivers/staging/omap-thermal/omap5-thermal.c
index 0658af2..2f3a498 100644
--- a/drivers/staging/omap-thermal/omap5-thermal.c
+++ b/drivers/staging/omap-thermal/omap5-thermal.c
@@ -268,29 +268,29 @@
 	.remove_sensor = omap_thermal_remove_sensor,
 	.sensors = {
 		{
-			.registers = &omap5430_mpu_temp_sensor_registers,
-			.ts_data = &omap5430_mpu_temp_sensor_data,
-			.domain = "cpu",
-			.register_cooling = omap_thermal_register_cpu_cooling,
-			.unregister_cooling = omap_thermal_unregister_cpu_cooling,
-			.slope = OMAP_GRADIENT_SLOPE_5430_CPU,
-			.constant = OMAP_GRADIENT_CONST_5430_CPU,
-			.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
-			.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
+		.registers = &omap5430_mpu_temp_sensor_registers,
+		.ts_data = &omap5430_mpu_temp_sensor_data,
+		.domain = "cpu",
+		.register_cooling = omap_thermal_register_cpu_cooling,
+		.unregister_cooling = omap_thermal_unregister_cpu_cooling,
+		.slope = OMAP_GRADIENT_SLOPE_5430_CPU,
+		.constant = OMAP_GRADIENT_CONST_5430_CPU,
+		.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
+		.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
 		},
 		{
-			.registers = &omap5430_gpu_temp_sensor_registers,
-			.ts_data = &omap5430_gpu_temp_sensor_data,
-			.domain = "gpu",
-			.slope = OMAP_GRADIENT_SLOPE_5430_GPU,
-			.constant = OMAP_GRADIENT_CONST_5430_GPU,
-			.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
-			.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
+		.registers = &omap5430_gpu_temp_sensor_registers,
+		.ts_data = &omap5430_gpu_temp_sensor_data,
+		.domain = "gpu",
+		.slope = OMAP_GRADIENT_SLOPE_5430_GPU,
+		.constant = OMAP_GRADIENT_CONST_5430_GPU,
+		.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
+		.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
 		},
 		{
-			.registers = &omap5430_core_temp_sensor_registers,
-			.ts_data = &omap5430_core_temp_sensor_data,
-			.domain = "core",
+		.registers = &omap5430_core_temp_sensor_registers,
+		.ts_data = &omap5430_core_temp_sensor_data,
+		.domain = "core",
 		},
 	},
 	.sensor_count = 3,
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index 62e0022..732f2ad 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -155,6 +155,7 @@
 	struct drm_crtc *crtc = arg;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_framebuffer *old_fb = omap_crtc->old_fb;
+	struct drm_gem_object *bo;
 
 	omap_crtc->old_fb = NULL;
 
@@ -165,6 +166,9 @@
 	 * cycle.. for now go for correctness and later figure out speed..
 	 */
 	omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc);
+
+	bo = omap_framebuffer_bo(crtc->fb, 0);
+	drm_gem_object_unreference_unlocked(bo);
 }
 
 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
@@ -173,6 +177,7 @@
 {
 	struct drm_device *dev = crtc->dev;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct drm_gem_object *bo;
 
 	DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id);
 
@@ -185,16 +190,38 @@
 	omap_crtc->event = event;
 	crtc->fb = fb;
 
-	omap_gem_op_async(omap_framebuffer_bo(fb, 0), OMAP_GEM_READ,
-			page_flip_cb, crtc);
+	/*
+	 * Hold a reference temporarily until the crtc is updated
+	 * and takes the reference to the bo.  This avoids it
+	 * getting freed from under us:
+	 */
+	bo = omap_framebuffer_bo(fb, 0);
+	drm_gem_object_reference(bo);
+
+	omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
 
 	return 0;
 }
 
+static int omap_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_property *property, uint64_t val)
+{
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct omap_drm_private *priv = crtc->dev->dev_private;
+
+	if (property == priv->rotation_prop) {
+		crtc->invert_dimensions =
+				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
+	}
+
+	return omap_plane_set_property(omap_crtc->plane, property, val);
+}
+
 static const struct drm_crtc_funcs omap_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = omap_crtc_destroy,
 	.page_flip = omap_crtc_page_flip_locked,
+	.set_property = omap_crtc_set_property,
 };
 
 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
@@ -231,6 +258,8 @@
 	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
+	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+
 	return crtc;
 
 fail:
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 8619783..3ae3955 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -120,7 +120,7 @@
 	return 0;
 }
 
-irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
+static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
 {
 	struct dmm *dmm = arg;
 	uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS);
@@ -367,7 +367,7 @@
 	int num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
 	if (!block)
-		return 0;
+		return ERR_PTR(-ENOMEM);
 
 	block->fmt = TILFMT_PAGE;
 
@@ -404,8 +404,26 @@
  * Utils
  */
 
-/* calculate the tiler space address of a pixel in a view orientation */
-static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y)
+/* calculate the tiler space address of a pixel in a view orientation...
+ * below description copied from the display subsystem section of TRM:
+ *
+ * When the TILER is addressed, the bits:
+ *   [28:27] = 0x0 for 8-bit tiled
+ *             0x1 for 16-bit tiled
+ *             0x2 for 32-bit tiled
+ *             0x3 for page mode
+ *   [31:29] = 0x0 for 0-degree view
+ *             0x1 for 180-degree view + mirroring
+ *             0x2 for 0-degree view + mirroring
+ *             0x3 for 180-degree view
+ *             0x4 for 270-degree view + mirroring
+ *             0x5 for 270-degree view
+ *             0x6 for 90-degree view
+ *             0x7 for 90-degree view + mirroring
+ * Otherwise the bits indicated the corresponding bit address to access
+ * the SDRAM.
+ */
+static u32 tiler_get_address(enum tiler_fmt fmt, u32 orient, u32 x, u32 y)
 {
 	u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment;
 
@@ -417,8 +435,11 @@
 	x_mask = MASK(x_bits);
 	y_mask = MASK(y_bits);
 
-	if (x < 0 || x > x_mask || y < 0 || y > y_mask)
+	if (x < 0 || x > x_mask || y < 0 || y > y_mask) {
+		DBG("invalid coords: %u < 0 || %u > %u || %u < 0 || %u > %u",
+				x, x, x_mask, y, y, y_mask);
 		return 0;
+	}
 
 	/* account for mirroring */
 	if (orient & MASK_X_INVERT)
@@ -439,11 +460,22 @@
 {
 	BUG_ON(!validfmt(block->fmt));
 
-	return TILVIEW_8BIT + tiler_get_address(0, block->fmt,
+	return TILVIEW_8BIT + tiler_get_address(block->fmt, 0,
 			block->area.p0.x * geom[block->fmt].slot_w,
 			block->area.p0.y * geom[block->fmt].slot_h);
 }
 
+dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient,
+		uint32_t x, uint32_t y)
+{
+	struct tcm_pt *p = &block->area.p0;
+	BUG_ON(!validfmt(block->fmt));
+
+	return tiler_get_address(block->fmt, orient,
+			(p->x * geom[block->fmt].slot_w) + x,
+			(p->y * geom[block->fmt].slot_h) + y);
+}
+
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h)
 {
 	BUG_ON(!validfmt(fmt));
@@ -451,11 +483,14 @@
 	*h = round_up(*h, geom[fmt].slot_h);
 }
 
-uint32_t tiler_stride(enum tiler_fmt fmt)
+uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient)
 {
 	BUG_ON(!validfmt(fmt));
 
-	return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
+	if (orient & MASK_XY_FLIP)
+		return 1 << (CONT_HEIGHT_BITS + geom[fmt].x_shft);
+	else
+		return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
 }
 
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h)
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h
index 7b1052a..740911d 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.h
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.h
@@ -54,7 +54,18 @@
 #define TILER_WIDTH             (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS))
 #define TILER_HEIGHT            (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS))
 
-/* tiler space addressing bitfields */
+/*
+Table 15-11. Coding and Description of TILER Orientations
+S Y X	Description				Alternate description
+0 0 0	0-degree view				Natural view
+0 0 1	0-degree view with vertical mirror 	180-degree view with horizontal mirror
+0 1 0	0-degree view with horizontal mirror 	180-degree view with vertical mirror
+0 1 1	180-degree view
+1 0 0	90-degree view with vertical mirror	270-degree view with horizontal mirror
+1 0 1	270-degree view
+1 1 0	90-degree view
+1 1 1	90-degree view with horizontal mirror	270-degree view with vertical mirror
+ */
 #define MASK_XY_FLIP		(1 << 31)
 #define MASK_Y_INVERT		(1 << 30)
 #define MASK_X_INVERT		(1 << 29)
@@ -90,7 +101,9 @@
 
 /* utilities */
 dma_addr_t tiler_ssptr(struct tiler_block *block);
-uint32_t tiler_stride(enum tiler_fmt fmt);
+dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient,
+		uint32_t x, uint32_t y);
+uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 4beab94..2ec5264 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -571,8 +571,7 @@
 
 	dev->dev_private = priv;
 
-	priv->wq = alloc_workqueue("omapdrm",
-			WQ_UNBOUND | WQ_NON_REENTRANT, 1);
+	priv->wq = alloc_ordered_workqueue("omapdrm", 0);
 
 	INIT_LIST_HEAD(&priv->obj_list);
 
@@ -649,6 +648,8 @@
  */
 static void dev_lastclose(struct drm_device *dev)
 {
+	int i;
+
 	/* we don't support vga-switcheroo.. so just make sure the fbdev
 	 * mode is active
 	 */
@@ -657,6 +658,21 @@
 
 	DBG("lastclose: dev=%p", dev);
 
+	/* need to restore default rotation state.. not sure if there is
+	 * a cleaner way to restore properties to default state?  Maybe
+	 * a flag that properties should automatically be restored to
+	 * default state on lastclose?
+	 */
+	for (i = 0; i < priv->num_crtcs; i++) {
+		drm_object_property_set_value(&priv->crtcs[i]->base,
+				priv->rotation_prop, 0);
+	}
+
+	for (i = 0; i < priv->num_planes; i++) {
+		drm_object_property_set_value(&priv->planes[i]->base,
+				priv->rotation_prop, 0);
+	}
+
 	ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev);
 	if (ret)
 		DBG("failed to restore crtc mode");
@@ -761,7 +777,6 @@
 		.irq_postinstall = dev_irq_postinstall,
 		.irq_uninstall = dev_irq_uninstall,
 		.irq_handler = dev_irq_handler,
-		.reclaim_buffers = drm_core_reclaim_buffers,
 #ifdef CONFIG_DEBUG_FS
 		.debugfs_init = omap_debugfs_init,
 		.debugfs_cleanup = omap_debugfs_cleanup,
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 2092a91..9dc72d1 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -59,6 +59,27 @@
 	struct list_head obj_list;
 
 	bool has_dmm;
+
+	/* properties: */
+	struct drm_property *rotation_prop;
+	struct drm_property *zorder_prop;
+};
+
+/* this should probably be in drm-core to standardize amongst drivers */
+#define DRM_ROTATE_0	0
+#define DRM_ROTATE_90	1
+#define DRM_ROTATE_180	2
+#define DRM_ROTATE_270	3
+#define DRM_REFLECT_X	4
+#define DRM_REFLECT_Y	5
+
+/* parameters which describe (unrotated) coordinates of scanout within a fb: */
+struct omap_drm_window {
+	uint32_t rotation;
+	int32_t  crtc_x, crtc_y;		/* signed because can be offscreen */
+	uint32_t crtc_w, crtc_h;
+	uint32_t src_x, src_y;
+	uint32_t src_w, src_h;
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -87,6 +108,10 @@
 		uint32_t src_w, uint32_t src_h);
 void omap_plane_on_endwin(struct drm_plane *plane,
 		void (*fxn)(void *), void *arg);
+void omap_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj);
+int omap_plane_set_property(struct drm_plane *plane,
+		struct drm_property *property, uint64_t val);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_overlay_manager *mgr);
@@ -114,8 +139,8 @@
 int omap_framebuffer_replace(struct drm_framebuffer *a,
 		struct drm_framebuffer *b, void *arg,
 		void (*unpin)(void *arg, struct drm_gem_object *bo));
-void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
-		struct omap_overlay_info *info);
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
+		struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
 		struct drm_framebuffer *fb, struct drm_connector *from);
 void omap_framebuffer_flush(struct drm_framebuffer *fb,
@@ -157,8 +182,12 @@
 		bool remap);
 int omap_gem_put_pages(struct drm_gem_object *obj);
 uint32_t omap_gem_flags(struct drm_gem_object *obj);
+int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient,
+		int x, int y, dma_addr_t *paddr);
 uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj);
 size_t omap_gem_mmap_size(struct drm_gem_object *obj);
+int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h);
+int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient);
 
 struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
 		struct drm_gem_object *obj, int flags);
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 74260f0..446801d 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -18,6 +18,7 @@
  */
 
 #include "omap_drv.h"
+#include "omap_dmm_tiler.h"
 
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -137,30 +138,100 @@
 	.dirty = omap_framebuffer_dirty,
 };
 
+static uint32_t get_linear_addr(struct plane *plane,
+		const struct format *format, int n, int x, int y)
+{
+	uint32_t offset;
+
+	offset = plane->offset +
+			(x * format->planes[n].stride_bpp) +
+			(y * plane->pitch / format->planes[n].sub_y);
+
+	return plane->paddr + offset;
+}
+
 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
  */
-void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
-		struct omap_overlay_info *info)
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
+		struct omap_drm_window *win, struct omap_overlay_info *info)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 	const struct format *format = omap_fb->format;
 	struct plane *plane = &omap_fb->planes[0];
-	unsigned int offset;
+	uint32_t x, y, orient = 0;
 
-	offset = plane->offset +
-			(x * format->planes[0].stride_bpp) +
-			(y * plane->pitch / format->planes[0].sub_y);
+	info->color_mode = format->dss_format;
 
-	info->color_mode   = format->dss_format;
-	info->paddr        = plane->paddr + offset;
-	info->screen_width = plane->pitch / format->planes[0].stride_bpp;
+	info->pos_x      = win->crtc_x;
+	info->pos_y      = win->crtc_y;
+	info->out_width  = win->crtc_w;
+	info->out_height = win->crtc_h;
+	info->width      = win->src_w;
+	info->height     = win->src_h;
+
+	x = win->src_x;
+	y = win->src_y;
+
+	if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) {
+		uint32_t w = win->src_w;
+		uint32_t h = win->src_h;
+
+		switch (win->rotation & 0xf) {
+		default:
+			dev_err(fb->dev->dev, "invalid rotation: %02x",
+					(uint32_t)win->rotation);
+			/* fallthru to default to no rotation */
+		case 0:
+		case BIT(DRM_ROTATE_0):
+			orient = 0;
+			break;
+		case BIT(DRM_ROTATE_90):
+			orient = MASK_XY_FLIP | MASK_X_INVERT;
+			break;
+		case BIT(DRM_ROTATE_180):
+			orient = MASK_X_INVERT | MASK_Y_INVERT;
+			break;
+		case BIT(DRM_ROTATE_270):
+			orient = MASK_XY_FLIP | MASK_Y_INVERT;
+			break;
+		}
+
+		if (win->rotation & BIT(DRM_REFLECT_X))
+			orient ^= MASK_X_INVERT;
+
+		if (win->rotation & BIT(DRM_REFLECT_Y))
+			orient ^= MASK_Y_INVERT;
+
+		/* adjust x,y offset for flip/invert: */
+		if (orient & MASK_XY_FLIP)
+			swap(w, h);
+		if (orient & MASK_Y_INVERT)
+			y += h - 1;
+		if (orient & MASK_X_INVERT)
+			x += w - 1;
+
+		omap_gem_rotated_paddr(plane->bo, orient, x, y, &info->paddr);
+		info->rotation_type = OMAP_DSS_ROT_TILER;
+		info->screen_width  = omap_gem_tiled_stride(plane->bo, orient);
+	} else {
+		info->paddr         = get_linear_addr(plane, format, 0, x, y);
+		info->rotation_type = OMAP_DSS_ROT_DMA;
+		info->screen_width  = plane->pitch;
+	}
+
+	/* convert to pixels: */
+	info->screen_width /= format->planes[0].stride_bpp;
 
 	if (format->dss_format == OMAP_DSS_COLOR_NV12) {
 		plane = &omap_fb->planes[1];
-		offset = plane->offset +
-				(x * format->planes[1].stride_bpp) +
-				(y * plane->pitch / format->planes[1].sub_y);
-		info->p_uv_addr = plane->paddr + offset;
+
+		if (info->rotation_type == OMAP_DSS_ROT_TILER) {
+			WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED));
+			omap_gem_rotated_paddr(plane->bo, orient,
+					x/2, y/2, &info->p_uv_addr);
+		} else {
+			info->p_uv_addr = get_linear_addr(plane, format, 1, x, y);
+		}
 	} else {
 		info->p_uv_addr = 0;
 	}
@@ -377,7 +448,7 @@
 
 		size = pitch * mode_cmd->height / format->planes[i].sub_y;
 
-		if (size > (bos[i]->size - mode_cmd->offsets[i])) {
+		if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
 			dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
 					bos[i]->size - mode_cmd->offsets[i], size);
 			ret = -EINVAL;
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index 3a0d035..c828743 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -226,7 +226,8 @@
 	struct drm_device *dev = obj->dev;
 	struct omap_gem_object *omap_obj = to_omap_bo(obj);
 	struct page **pages;
-	int i, npages = obj->size >> PAGE_SHIFT;
+	int npages = obj->size >> PAGE_SHIFT;
+	int i, ret;
 	dma_addr_t *addrs;
 
 	WARN_ON(omap_obj->pages);
@@ -246,18 +247,32 @@
 	 */
 	if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
 		addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
+		if (!addrs) {
+			ret = -ENOMEM;
+			goto free_pages;
+		}
+
 		for (i = 0; i < npages; i++) {
 			addrs[i] = dma_map_page(dev->dev, pages[i],
 					0, PAGE_SIZE, DMA_BIDIRECTIONAL);
 		}
 	} else {
 		addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL);
+		if (!addrs) {
+			ret = -ENOMEM;
+			goto free_pages;
+		}
 	}
 
 	omap_obj->addrs = addrs;
 	omap_obj->pages = pages;
 
 	return 0;
+
+free_pages:
+	_drm_gem_put_pages(obj, pages, true, false);
+
+	return ret;
 }
 
 /** release backing pages */
@@ -339,6 +354,17 @@
 	return size;
 }
 
+/* get tiled size, returns -EINVAL if not tiled buffer */
+int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h)
+{
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+	if (omap_obj->flags & OMAP_BO_TILED) {
+		*w = omap_obj->width;
+		*h = omap_obj->height;
+		return 0;
+	}
+	return -EINVAL;
+}
 
 /* Normal handling for the case of faulting in non-tiled buffers */
 static int fault_1d(struct drm_gem_object *obj,
@@ -832,6 +858,36 @@
 	return ret;
 }
 
+/* Get rotated scanout address (only valid if already pinned), at the
+ * specified orientation and x,y offset from top-left corner of buffer
+ * (only valid for tiled 2d buffers)
+ */
+int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient,
+		int x, int y, dma_addr_t *paddr)
+{
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+	int ret = -EINVAL;
+
+	mutex_lock(&obj->dev->struct_mutex);
+	if ((omap_obj->paddr_cnt > 0) && omap_obj->block &&
+			(omap_obj->flags & OMAP_BO_TILED)) {
+		*paddr = tiler_tsptr(omap_obj->block, orient, x, y);
+		ret = 0;
+	}
+	mutex_unlock(&obj->dev->struct_mutex);
+	return ret;
+}
+
+/* Get tiler stride for the buffer (only valid for 2d tiled buffers) */
+int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient)
+{
+	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+	int ret = -EINVAL;
+	if (omap_obj->flags & OMAP_BO_TILED)
+		ret = tiler_stride(gem2fmt(omap_obj->flags), orient);
+	return ret;
+}
+
 /* acquire pages when needed (for example, for DMA where physically
  * contiguous buffer is not required
  */
@@ -1402,7 +1458,7 @@
 		 */
 		usergart[i].height = h;
 		usergart[i].height_shift = ilog2(h);
-		usergart[i].stride_pfn = tiler_stride(fmts[i]) >> PAGE_SHIFT;
+		usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT;
 		usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i);
 		for (j = 0; j < NUM_USERGART_ENTRIES; j++) {
 			struct usergart_entry *entry = &usergart[i].entry[j];
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index 7997be7..4bde639 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -20,6 +20,7 @@
 #include <linux/kfifo.h>
 
 #include "omap_drv.h"
+#include "omap_dmm_tiler.h"
 
 /* some hackery because omapdss has an 'enum omap_plane' (which would be
  * better named omap_plane_id).. and compiler seems unhappy about having
@@ -43,10 +44,9 @@
 	struct omap_overlay *ovl;
 	struct omap_overlay_info info;
 
-	/* Source values, converted to integers because we don't support
-	 * fractional positions:
-	 */
-	unsigned int src_x, src_y;
+	/* position/orientation of scanout within the fb: */
+	struct omap_drm_window win;
+
 
 	/* last fb that we pinned: */
 	struct drm_framebuffer *pinned_fb;
@@ -289,6 +289,7 @@
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_overlay_info *info = &omap_plane->info;
+	struct omap_drm_window *win = &omap_plane->win;
 	int ret;
 
 	ret = update_pin(plane, plane->fb);
@@ -299,11 +300,10 @@
 		return;
 	}
 
-	omap_framebuffer_update_scanout(plane->fb,
-			omap_plane->src_x, omap_plane->src_y, info);
+	omap_framebuffer_update_scanout(plane->fb, win, info);
 
 	DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name,
-			omap_plane->src_x, omap_plane->src_y,
+			win->src_x, win->src_y,
 			(u32)info->paddr, (u32)info->p_uv_addr,
 			info->screen_width);
 }
@@ -316,21 +316,18 @@
 		uint32_t src_w, uint32_t src_h)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_drm_window *win = &omap_plane->win;
+
+	win->crtc_x = crtc_x;
+	win->crtc_y = crtc_y;
+	win->crtc_w = crtc_w;
+	win->crtc_h = crtc_h;
 
 	/* src values are in Q16 fixed point, convert to integer: */
-	src_x = src_x >> 16;
-	src_y = src_y >> 16;
-	src_w = src_w >> 16;
-	src_h = src_h >> 16;
-
-	omap_plane->info.pos_x = crtc_x;
-	omap_plane->info.pos_y = crtc_y;
-	omap_plane->info.out_width = crtc_w;
-	omap_plane->info.out_height = crtc_h;
-	omap_plane->info.width = src_w;
-	omap_plane->info.height = src_h;
-	omap_plane->src_x = src_x;
-	omap_plane->src_y = src_y;
+	win->src_x = src_x >> 16;
+	win->src_y = src_y >> 16;
+	win->src_w = src_w >> 16;
+	win->src_h = src_h >> 16;
 
 	/* note: this is done after this fxn returns.. but if we need
 	 * to do a commit/update_scanout, etc before this returns we
@@ -359,6 +356,8 @@
 
 static int omap_plane_disable(struct drm_plane *plane)
 {
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	omap_plane->win.rotation = BIT(DRM_ROTATE_0);
 	return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 }
 
@@ -409,10 +408,79 @@
 	install_irq(plane);
 }
 
+/* helper to install properties which are common to planes and crtcs */
+void omap_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj)
+{
+	struct drm_device *dev = plane->dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	struct drm_property *prop;
+
+	prop = priv->rotation_prop;
+	if (!prop) {
+		const struct drm_prop_enum_list props[] = {
+				{ DRM_ROTATE_0,   "rotate-0" },
+				{ DRM_ROTATE_90,  "rotate-90" },
+				{ DRM_ROTATE_180, "rotate-180" },
+				{ DRM_ROTATE_270, "rotate-270" },
+				{ DRM_REFLECT_X,  "reflect-x" },
+				{ DRM_REFLECT_Y,  "reflect-y" },
+		};
+		prop = drm_property_create_bitmask(dev, 0, "rotation",
+				props, ARRAY_SIZE(props));
+		if (prop == NULL)
+			return;
+		priv->rotation_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, 0);
+
+        prop = priv->zorder_prop;
+        if (!prop) {
+		prop = drm_property_create_range(dev, 0, "zorder", 0, 3);
+		if (prop == NULL)
+			return;
+		priv->zorder_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, 0);
+}
+
+int omap_plane_set_property(struct drm_plane *plane,
+		struct drm_property *property, uint64_t val)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_drm_private *priv = plane->dev->dev_private;
+	int ret = -EINVAL;
+
+	if (property == priv->rotation_prop) {
+		struct omap_overlay *ovl = omap_plane->ovl;
+
+		DBG("%s: rotation: %02x", ovl->name, (uint32_t)val);
+		omap_plane->win.rotation = val;
+
+		if (ovl->is_enabled(ovl))
+			ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
+		else
+			ret = 0;
+	} else if (property == priv->zorder_prop) {
+		struct omap_overlay *ovl = omap_plane->ovl;
+
+		DBG("%s: zorder: %d", ovl->name, (uint32_t)val);
+		omap_plane->info.zorder = val;
+
+		if (ovl->is_enabled(ovl))
+			ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
+		else
+			ret = 0;
+	}
+
+	return ret;
+}
+
 static const struct drm_plane_funcs omap_plane_funcs = {
 		.update_plane = omap_plane_update,
 		.disable_plane = omap_plane_disable,
 		.destroy = omap_plane_destroy,
+		.set_property = omap_plane_set_property,
 };
 
 /* initialize plane */
@@ -455,6 +523,8 @@
 	drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
 			omap_plane->formats, omap_plane->nformats, priv);
 
+	omap_plane_install_properties(plane, &plane->base);
+
 	/* get our starting configuration, set defaults for parameters
 	 * we don't currently use, etc:
 	 */
@@ -463,7 +533,6 @@
 	omap_plane->info.rotation = OMAP_DSS_ROT_0;
 	omap_plane->info.global_alpha = 0xff;
 	omap_plane->info.mirror = 0;
-	omap_plane->info.mirror = 0;
 
 	/* Set defaults depending on whether we are a CRTC or overlay
 	 * layer.
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 758ce0a..64913ae 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -104,10 +104,10 @@
 	if (pd)
 		oz_pd_get(pd);
 	spin_unlock_bh(&g_cdev.lock);
-	if (pd == 0)
+	if (pd == NULL)
 		return -1;
 	ctx = oz_cdev_claim_ctx(pd);
-	if (ctx == 0)
+	if (ctx == NULL)
 		goto out2;
 	n = ctx->rd_in - ctx->rd_out;
 	if (n < 0)
@@ -157,11 +157,11 @@
 	if (pd)
 		oz_pd_get(pd);
 	spin_unlock_bh(&g_cdev.lock);
-	if (pd == 0)
+	if (pd == NULL)
 		return -1;
 	eb = &pd->elt_buff;
 	ei = oz_elt_info_alloc(eb);
-	if (ei == 0) {
+	if (ei == NULL) {
 		count = 0;
 		goto out;
 	}
@@ -410,7 +410,7 @@
 		return 0;
 	}
 	ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
-	if (ctx == 0)
+	if (ctx == NULL)
 		return -ENOMEM;
 	atomic_set(&ctx->ref_count, 1);
 	ctx->tx_seq_num = 1;
@@ -424,7 +424,7 @@
 		spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
 	}
 	spin_lock(&g_cdev.lock);
-	if ((g_cdev.active_pd == 0) &&
+	if ((g_cdev.active_pd == NULL) &&
 		(memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) {
 		oz_pd_get(pd);
 		g_cdev.active_pd = pd;
@@ -477,7 +477,7 @@
 	int ix;
 
 	ctx = oz_cdev_claim_ctx(pd);
-	if (ctx == 0) {
+	if (ctx == NULL) {
 		oz_trace("Cannot claim serial context.\n");
 		return;
 	}
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
index 7f66b4f..a48498b 100644
--- a/drivers/staging/ozwpan/ozevent.c
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -14,7 +14,7 @@
 #include "ozappif.h"
 /*------------------------------------------------------------------------------
  * Although the event mask is logically part of the oz_evtdev structure, it is
- * needed outside of this file so define it seperately to avoid the need to
+ * needed outside of this file so define it separately to avoid the need to
  * export definition of struct oz_evtdev.
  */
 u32 g_evt_mask;
@@ -39,8 +39,8 @@
  */
 void oz_event_init(void)
 {
-	/* Because g_evtdev is static external all fields initally zero so no
-	 * need to reinitialised those.
+	/* Because g_evtdev is static external all fields initially zero so no
+	 * need to reinitialized those.
 	 */
 	oz_trace("Event tracing initialized\n");
 	spin_lock_init(&g_evtdev.lock);
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index 251f07c..2e087ac 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -417,6 +417,44 @@
 /*------------------------------------------------------------------------------
  * Context: softirq
  */
+void oz_complete_buffered_urb(struct oz_port *port, struct oz_endpoint *ep,
+			struct urb *urb)
+{
+	u8 data_len, available_space, copy_len;
+
+	memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8));
+	if (data_len <= urb->transfer_buffer_length)
+		available_space = data_len;
+	else
+		available_space = urb->transfer_buffer_length;
+
+	if (++ep->out_ix == ep->buffer_size)
+		ep->out_ix = 0;
+	copy_len = ep->buffer_size - ep->out_ix;
+	if (copy_len >= available_space)
+		copy_len = available_space;
+	memcpy(urb->transfer_buffer, &ep->buffer[ep->out_ix], copy_len);
+
+	if (copy_len < available_space) {
+		memcpy((urb->transfer_buffer + copy_len), ep->buffer,
+						(available_space - copy_len));
+		ep->out_ix = available_space - copy_len;
+	} else {
+		ep->out_ix += copy_len;
+	}
+	urb->actual_length = available_space;
+	if (ep->out_ix == ep->buffer_size)
+		ep->out_ix = 0;
+
+	ep->buffered_units--;
+	oz_trace("Trying to give back buffered frame of size=%d\n",
+						available_space);
+	oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+}
+
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
 static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
 			struct urb *urb, u8 req_id)
 {
@@ -452,6 +490,18 @@
 		ep = port->in_ep[ep_addr];
 	else
 		ep = port->out_ep[ep_addr];
+
+	/*For interrupt endpoint check for buffered data
+	* & complete urb
+	*/
+	if (((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+						 && ep->buffered_units > 0) {
+		oz_free_urb_link(urbl);
+		spin_unlock_bh(&port->ozhcd->hcd_lock);
+		oz_complete_buffered_urb(port, ep, urb);
+		return 0;
+	}
+
 	if (ep && port->hpd) {
 		list_add_tail(&urbl->link, &ep->urb_list);
 		if (!in_dir && ep_addr && (ep->credit < 0)) {
@@ -883,13 +933,14 @@
 	} else {
 		int copy_len;
 		oz_trace("VENDOR-CLASS - cnf\n");
-		if (data_len <= urb->transfer_buffer_length)
-			copy_len = data_len;
-		else
-			copy_len = urb->transfer_buffer_length;
-		if (copy_len)
+		if (data_len) {
+			if (data_len <= urb->transfer_buffer_length)
+				copy_len = data_len;
+			else
+				copy_len = urb->transfer_buffer_length;
 			memcpy(urb->transfer_buffer, data, copy_len);
-		urb->actual_length = copy_len;
+			urb->actual_length = copy_len;
+		}
 		oz_complete_urb(hcd, urb, 0, 0);
 	}
 }
@@ -961,6 +1012,9 @@
 			urb->actual_length = copy_len;
 			oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
 			return;
+		} else {
+			oz_trace("buffering frame as URB is not available\n");
+			oz_hcd_buffer_data(ep, data, data_len);
 		}
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
@@ -1000,7 +1054,7 @@
 		ep = ep_from_link(e);
 		if (ep->credit < 0)
 			continue;
-		ep->credit += (now - ep->last_jiffies);
+		ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
 		if (ep->credit > ep->credit_ceiling)
 			ep->credit = ep->credit_ceiling;
 		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit);
@@ -1009,13 +1063,12 @@
 			urbl = list_first_entry(&ep->urb_list,
 				struct oz_urb_link, link);
 			urb = urbl->urb;
-			if (ep->credit < urb->number_of_packets)
+			if ((ep->credit + 1) < urb->number_of_packets)
 				break;
 			ep->credit -= urb->number_of_packets;
 			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0,
 				ep->credit);
-			list_del(&urbl->link);
-			list_add_tail(&urbl->link, &xfr_list);
+			list_move_tail(&urbl->link, &xfr_list);
 		}
 	}
 	spin_unlock_bh(&ozhcd->hcd_lock);
@@ -1052,7 +1105,7 @@
 			}
 			continue;
 		}
-		ep->credit += (now - ep->last_jiffies);
+		ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
 		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
 			0, 0, ep->credit);
 		ep->last_jiffies = now;
@@ -1064,7 +1117,7 @@
 			int len = 0;
 			int copy_len;
 			int i;
-			if (ep->credit < urb->number_of_packets)
+			if ((ep->credit + 1) < urb->number_of_packets)
 				break;
 			if (ep->buffered_units < urb->number_of_packets)
 				break;
@@ -1096,8 +1149,7 @@
 			urb->error_count = 0;
 			urb->start_frame = ep->start_frame;
 			ep->start_frame += urb->number_of_packets;
-			list_del(&urbl->link);
-			list_add_tail(&urbl->link, &xfr_list);
+			list_move_tail(&urbl->link, &xfr_list);
 			ep->credit -= urb->number_of_packets;
 			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
 				0, 0, ep->credit);
@@ -1129,8 +1181,7 @@
 				oz_trace("%ld: Request 0x%p timeout\n",
 						now, urbl->urb);
 				urbl->submit_jiffies = now;
-				list_del(e);
-				list_add_tail(e, &xfr_list);
+				list_move_tail(e, &xfr_list);
 			}
 		}
 		if (!list_empty(&ep->urb_list))
@@ -1167,10 +1218,16 @@
 		int buffer_size = 0;
 
 		oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
-		if ((ep_addr & USB_ENDPOINT_DIR_MASK) &&
-			((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			== USB_ENDPOINT_XFER_ISOC)) {
-			buffer_size = 24*1024;
+		if (ep_addr & USB_ENDPOINT_DIR_MASK) {
+			switch (hep->desc.bmAttributes &
+						USB_ENDPOINT_XFERTYPE_MASK) {
+			case USB_ENDPOINT_XFER_ISOC:
+				buffer_size = 24*1024;
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				buffer_size = 128;
+				break;
+			}
 		}
 
 		ep = oz_ep_alloc(mem_flags, buffer_size);
@@ -1247,16 +1304,14 @@
 			port->out_ep[i] = 0;
 			/* Remove from isoc list if present.
 			 */
-			list_del(e);
-			list_add_tail(e, &ep_list);
+			list_move_tail(e, &ep_list);
 		}
 		/* Gather IN endpoints.
 		 */
 		if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) {
 			e = &port->in_ep[i]->link;
 			port->in_ep[i] = 0;
-			list_del(e);
-			list_add_tail(e, &ep_list);
+			list_move_tail(e, &ep_list);
 		}
 	}
 	spin_unlock_bh(&ozhcd->hcd_lock);
@@ -1458,6 +1513,7 @@
 		int data_len = 0;
 		if ((setup->bRequestType & USB_DIR_IN) == 0)
 			data_len = wlength;
+		urb->actual_length = data_len;
 		if (oz_usb_control_req(port->hpd, req_id, setup,
 				urb->transfer_buffer, data_len)) {
 			rc = -ENOMEM;
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index c1ed6b2..ef6c5ab 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -59,6 +59,6 @@
 
 MODULE_AUTHOR("Chris Kelly");
 MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.10");
+MODULE_VERSION("1.0.13");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index 6c287ac..0b3648c 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -24,12 +24,6 @@
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_TX_POOL_SIZE	6
-/* Maximum number of uncompleted isoc frames that can be pending in network.
- */
-#define OZ_MAX_SUBMITTED_ISOC	16
-/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue.
- */
-#define OZ_MAX_TX_QUEUE_ISOC	32
 /*------------------------------------------------------------------------------
  */
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
@@ -752,8 +746,7 @@
  */
 static void oz_isoc_stream_free(struct oz_isoc_stream *st)
 {
-	if (st->skb)
-		kfree_skb(st->skb);
+	kfree_skb(st->skb);
 	kfree(st);
 }
 /*------------------------------------------------------------------------------
@@ -854,7 +847,7 @@
 		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
 			struct oz_tx_frame *isoc_unit = NULL;
 			int nb = pd->nb_queued_isoc_frames;
-			if (nb >= OZ_MAX_TX_QUEUE_ISOC) {
+			if (nb >= pd->isoc_latency) {
 				oz_trace2(OZ_TRACE_TX_FRAMES,
 						"Dropping ISOC Unit nb= %d\n",
 									nb);
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index ddf1341..d35b0ea 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -82,6 +82,7 @@
 	u8		heartbeat_requested;
 	u8		mode;
 	u8		ms_per_isoc;
+	unsigned	isoc_latency;
 	unsigned	max_stream_buffering;
 	int		nb_queued_frames;
 	int		nb_queued_isoc_frames;
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index a50ab18..cfb5160 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -220,6 +220,19 @@
 		pd->ms_per_isoc = body->ms_per_isoc;
 		if (!pd->ms_per_isoc)
 			pd->ms_per_isoc = 4;
+
+		switch (body->ms_isoc_latency & OZ_LATENCY_MASK) {
+		case OZ_ONE_MS_LATENCY:
+			pd->isoc_latency = (body->ms_isoc_latency &
+					~OZ_LATENCY_MASK) / pd->ms_per_isoc;
+			break;
+		case OZ_TEN_MS_LATENCY:
+			pd->isoc_latency = ((body->ms_isoc_latency &
+				~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc;
+			break;
+		default:
+			pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC;
+		}
 	}
 	if (body->max_len_div16)
 		pd->max_tx_size = ((u16)body->max_len_div16)<<4;
diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h
index 89aea28..755a08d 100644
--- a/drivers/staging/ozwpan/ozproto.h
+++ b/drivers/staging/ozwpan/ozproto.h
@@ -14,7 +14,7 @@
 
 /* Converts millisecs to jiffies.
  */
-#define oz_ms_to_jiffies(__x)	(((__x)*1000)/HZ)
+#define oz_ms_to_jiffies(__x)	msecs_to_jiffies(__x)
 
 /* Quantum milliseconds.
  */
@@ -30,6 +30,12 @@
 /* Maximun sizes of tx frames. */
 #define OZ_MAX_TX_SIZE		1514
 
+/* Maximum number of uncompleted isoc frames that can be pending in network. */
+#define OZ_MAX_SUBMITTED_ISOC	16
+
+/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. */
+#define OZ_MAX_TX_QUEUE_ISOC	32
+
 /* Application handler functions.
  */
 typedef int (*oz_app_init_fn_t)(void);
diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h
index 1e4edbe..17b09b9 100644
--- a/drivers/staging/ozwpan/ozprotocol.h
+++ b/drivers/staging/ozwpan/ozprotocol.h
@@ -65,6 +65,10 @@
 
 #define OZ_LAST_PN_HALF_CYCLE	127
 
+#define OZ_LATENCY_MASK		0xc0
+#define OZ_ONE_MS_LATENCY	0x40
+#define OZ_TEN_MS_LATENCY	0x80
+
 /* Connect request data structure.
  */
 struct oz_elt_connect_req {
@@ -73,7 +77,7 @@
 	u8	pd_info;
 	u8	session_id;
 	u8	presleep;
-	u8	resv2;
+	u8	ms_isoc_latency;
 	u8	host_vendor;
 	u8	keep_alive;
 	u16	apps;
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 39f9982..6e9f709 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -137,8 +137,8 @@
 #define r_ctr(x)        (parport_read_control((x)->port))
 #define r_dtr(x)        (parport_read_data((x)->port))
 #define r_str(x)        (parport_read_status((x)->port))
-#define w_ctr(x, y)     do { parport_write_control((x)->port, (y)); } while (0)
-#define w_dtr(x, y)     do { parport_write_data((x)->port, (y)); } while (0)
+#define w_ctr(x, y)     (parport_write_control((x)->port, (y)))
+#define w_dtr(x, y)     (parport_write_data((x)->port, (y)))
 
 /* this defines which bits are to be used and which ones to be ignored */
 /* logical or of the output bits involved in the scan matrix */
@@ -757,38 +757,38 @@
 		return;
 
 	/* The backlight is activated by setting the AUTOFEED line to +5V  */
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	bits.bl = on;
 	panel_set_bits();
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send a command to the LCD panel in serial mode */
 static void lcd_write_cmd_s(int cmd)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	lcd_send_serial(0x1F);	/* R/W=W, RS=0 */
 	lcd_send_serial(cmd & 0x0F);
 	lcd_send_serial((cmd >> 4) & 0x0F);
 	udelay(40);		/* the shortest command takes at least 40 us */
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send data to the LCD panel in serial mode */
 static void lcd_write_data_s(int data)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	lcd_send_serial(0x5F);	/* R/W=W, RS=1 */
 	lcd_send_serial(data & 0x0F);
 	lcd_send_serial((data >> 4) & 0x0F);
 	udelay(40);		/* the shortest data takes at least 40 us */
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send a command to the LCD panel in 8 bits parallel mode */
 static void lcd_write_cmd_p8(int cmd)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, cmd);
 	udelay(20);	/* maintain the data during 20 us before the strobe */
@@ -804,13 +804,13 @@
 	set_ctrl_bits();
 
 	udelay(120);	/* the shortest command takes at least 120 us */
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send data to the LCD panel in 8 bits parallel mode */
 static void lcd_write_data_p8(int data)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, data);
 	udelay(20);	/* maintain the data during 20 us before the strobe */
@@ -826,27 +826,27 @@
 	set_ctrl_bits();
 
 	udelay(45);	/* the shortest data takes at least 45 us */
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send a command to the TI LCD panel */
 static void lcd_write_cmd_tilcd(int cmd)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	/* present the data to the control port */
 	w_ctr(pprt, cmd);
 	udelay(60);
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 /* send data to the TI LCD panel */
 static void lcd_write_data_tilcd(int data)
 {
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	/* present the data to the data port */
 	w_dtr(pprt, data);
 	udelay(60);
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 }
 
 static void lcd_gotoxy(void)
@@ -879,14 +879,14 @@
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
 
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
 		lcd_send_serial(0x5F);	/* R/W=W, RS=1 */
 		lcd_send_serial(' ' & 0x0F);
 		lcd_send_serial((' ' >> 4) & 0x0F);
 		udelay(40);	/* the shortest data takes at least 40 us */
 	}
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
@@ -899,7 +899,7 @@
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
 
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
 		/* present the data to the data port */
 		w_dtr(pprt, ' ');
@@ -921,7 +921,7 @@
 		/* the shortest data takes at least 45 us */
 		udelay(45);
 	}
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
@@ -934,14 +934,14 @@
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
 
-	spin_lock(&pprt_lock);
+	spin_lock_irq(&pprt_lock);
 	for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
 		/* present the data to the data port */
 		w_dtr(pprt, ' ');
 		udelay(60);
 	}
 
-	spin_unlock(&pprt_lock);
+	spin_unlock_irq(&pprt_lock);
 
 	lcd_addr_x = lcd_addr_y = 0;
 	lcd_gotoxy();
@@ -1197,7 +1197,7 @@
 		break;
 	}
 
-	/* Check wether one flag was changed */
+	/* Check whether one flag was changed */
 	if (oldflags != lcd_flags) {
 		/* check whether one of B,C,D flags were changed */
 		if ((oldflags ^ lcd_flags) &
@@ -1212,7 +1212,7 @@
 			lcd_write_cmd(0x30
 				      | ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
 				      | ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
-		/* check wether L flag was changed */
+		/* check whether L flag was changed */
 		else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) {
 			if (lcd_flags & (LCD_FLAG_L))
 				lcd_backlight(1);
@@ -1886,11 +1886,11 @@
 static void panel_scan_timer(void)
 {
 	if (keypad_enabled && keypad_initialized) {
-		if (spin_trylock(&pprt_lock)) {
+		if (spin_trylock_irq(&pprt_lock)) {
 			phys_scan_contacts();
 
 			/* no need for the parport anymore */
-			spin_unlock(&pprt_lock);
+			spin_unlock_irq(&pprt_lock);
 		}
 
 		if (!inputs_stable || phys_curr != phys_prev)
diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig
index 8349887..843c541 100644
--- a/drivers/staging/ramster/Kconfig
+++ b/drivers/staging/ramster/Kconfig
@@ -1,13 +1,30 @@
+config ZCACHE2
+	bool "Dynamic compression of swap pages and clean pagecache pages"
+	depends on CRYPTO=y && SWAP=y && CLEANCACHE && FRONTSWAP && !ZCACHE 
+	select CRYPTO_LZO
+	default n
+	help
+	  Zcache2 doubles RAM efficiency while providing a significant
+	  performance boosts on many workloads.  Zcache2 uses
+	  compression and an in-kernel implementation of transcendent
+	  memory to store clean page cache pages and swap in RAM,
+	  providing a noticeable reduction in disk I/O.  Zcache2
+	  is a complete rewrite of the older zcache; it was intended to
+	  be a merge but that has been blocked due to political and
+	  technical disagreements.  It is intended that they will merge
+	  again in the future.  Until then, zcache2 is a single-node
+	  version of ramster.
+
 config RAMSTER
 	bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
-	depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET
-	select LZO_COMPRESS
-	select LZO_DECOMPRESS
+	depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE2=y
+	# must ensure struct page is 8-byte aligned
+	select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT
 	default n
 	help
 	  RAMster allows RAM on other machines in a cluster to be utilized
 	  dynamically and symmetrically instead of swapping to a local swap
 	  disk, thus improving performance on memory-constrained workloads
 	  while minimizing total RAM across the cluster.  RAMster, like
-	  zcache, compresses swap pages into local RAM, but then remotifies
+	  zcache2, compresses swap pages into local RAM, but then remotifies
 	  the compressed pages to another node in the RAMster cluster.
diff --git a/drivers/staging/ramster/Makefile b/drivers/staging/ramster/Makefile
index bcc13c8..2d8b9d0 100644
--- a/drivers/staging/ramster/Makefile
+++ b/drivers/staging/ramster/Makefile
@@ -1 +1,6 @@
-obj-$(CONFIG_RAMSTER)	+=	zcache-main.o tmem.o r2net.o xvmalloc.o cluster/
+zcache-y	:=		zcache-main.o tmem.o zbud.o
+zcache-$(CONFIG_RAMSTER)	+=	ramster/ramster.o ramster/r2net.o
+zcache-$(CONFIG_RAMSTER)	+=	ramster/nodemanager.o ramster/tcp.o
+zcache-$(CONFIG_RAMSTER)	+=	ramster/heartbeat.o ramster/masklog.o
+
+obj-$(CONFIG_ZCACHE2)	+=	zcache.o
diff --git a/drivers/staging/ramster/TODO b/drivers/staging/ramster/TODO
deleted file mode 100644
index 46fcf0c..0000000
--- a/drivers/staging/ramster/TODO
+++ /dev/null
@@ -1,13 +0,0 @@
-For this staging driver, RAMster duplicates code from drivers/staging/zcache
-then incorporates changes to the local copy of the code.  For V5, it also
-directly incorporates the soon-to-be-removed drivers/staging/zram/xvmalloc.[ch]
-as all testing has been done with xvmalloc rather than the new zsmalloc.
-Before RAMster can be promoted from staging, the zcache and RAMster drivers
-should be either merged or reorganized to separate out common code.
-
-Until V4, RAMster duplicated code from fs/ocfs2/cluster, but this made
-RAMster incompatible with ocfs2 running in the same kernel and included
-lots of code that could be removed.  As of V5, the ocfs2 code has been
-mined and made RAMster-specific, made to communicate with a userland
-ramster-tools package rather than ocfs2-tools, and can co-exist with ocfs2
-both in the same kernel and in userland on the same machine.
diff --git a/drivers/staging/ramster/cluster/Makefile b/drivers/staging/ramster/cluster/Makefile
deleted file mode 100644
index 9c69436..0000000
--- a/drivers/staging/ramster/cluster/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_RAMSTER) += ramster_nodemanager.o
-
-ramster_nodemanager-objs := heartbeat.o masklog.o nodemanager.o tcp.o
diff --git a/drivers/staging/ramster/cluster/heartbeat.c b/drivers/staging/ramster/cluster/heartbeat.c
deleted file mode 100644
index 0020949..0000000
--- a/drivers/staging/ramster/cluster/heartbeat.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/configfs.h>
-
-#include "heartbeat.h"
-#include "tcp.h"
-#include "nodemanager.h"
-
-#include "masklog.h"
-
-/*
- * The first heartbeat pass had one global thread that would serialize all hb
- * callback calls.  This global serializing sem should only be removed once
- * we've made sure that all callees can deal with being called concurrently
- * from multiple hb region threads.
- */
-static DECLARE_RWSEM(r2hb_callback_sem);
-
-/*
- * multiple hb threads are watching multiple regions.  A node is live
- * whenever any of the threads sees activity from the node in its region.
- */
-static DEFINE_SPINLOCK(r2hb_live_lock);
-static unsigned long r2hb_live_node_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
-
-static struct r2hb_callback {
-	struct list_head list;
-} r2hb_callbacks[R2HB_NUM_CB];
-
-enum r2hb_heartbeat_modes {
-	R2HB_HEARTBEAT_LOCAL		= 0,
-	R2HB_HEARTBEAT_GLOBAL,
-	R2HB_HEARTBEAT_NUM_MODES,
-};
-
-char *r2hb_heartbeat_mode_desc[R2HB_HEARTBEAT_NUM_MODES] = {
-		"local",	/* R2HB_HEARTBEAT_LOCAL */
-		"global",	/* R2HB_HEARTBEAT_GLOBAL */
-};
-
-unsigned int r2hb_dead_threshold = R2HB_DEFAULT_DEAD_THRESHOLD;
-unsigned int r2hb_heartbeat_mode = R2HB_HEARTBEAT_LOCAL;
-
-/* Only sets a new threshold if there are no active regions.
- *
- * No locking or otherwise interesting code is required for reading
- * r2hb_dead_threshold as it can't change once regions are active and
- * it's not interesting to anyone until then anyway. */
-static void r2hb_dead_threshold_set(unsigned int threshold)
-{
-	if (threshold > R2HB_MIN_DEAD_THRESHOLD) {
-		spin_lock(&r2hb_live_lock);
-		r2hb_dead_threshold = threshold;
-		spin_unlock(&r2hb_live_lock);
-	}
-}
-
-static int r2hb_global_hearbeat_mode_set(unsigned int hb_mode)
-{
-	int ret = -1;
-
-	if (hb_mode < R2HB_HEARTBEAT_NUM_MODES) {
-		spin_lock(&r2hb_live_lock);
-		r2hb_heartbeat_mode = hb_mode;
-		ret = 0;
-		spin_unlock(&r2hb_live_lock);
-	}
-
-	return ret;
-}
-
-void r2hb_exit(void)
-{
-}
-
-int r2hb_init(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(r2hb_callbacks); i++)
-		INIT_LIST_HEAD(&r2hb_callbacks[i].list);
-
-	memset(r2hb_live_node_bitmap, 0, sizeof(r2hb_live_node_bitmap));
-
-	return 0;
-}
-
-/* if we're already in a callback then we're already serialized by the sem */
-static void r2hb_fill_node_map_from_callback(unsigned long *map,
-					     unsigned bytes)
-{
-	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
-
-	memcpy(map, &r2hb_live_node_bitmap, bytes);
-}
-
-/*
- * get a map of all nodes that are heartbeating in any regions
- */
-void r2hb_fill_node_map(unsigned long *map, unsigned bytes)
-{
-	/* callers want to serialize this map and callbacks so that they
-	 * can trust that they don't miss nodes coming to the party */
-	down_read(&r2hb_callback_sem);
-	spin_lock(&r2hb_live_lock);
-	r2hb_fill_node_map_from_callback(map, bytes);
-	spin_unlock(&r2hb_live_lock);
-	up_read(&r2hb_callback_sem);
-}
-EXPORT_SYMBOL_GPL(r2hb_fill_node_map);
-
-/*
- * heartbeat configfs bits.  The heartbeat set is a default set under
- * the cluster set in nodemanager.c.
- */
-
-/* heartbeat set */
-
-struct r2hb_hb_group {
-	struct config_group hs_group;
-	/* some stuff? */
-};
-
-static struct r2hb_hb_group *to_r2hb_hb_group(struct config_group *group)
-{
-	return group ?
-		container_of(group, struct r2hb_hb_group, hs_group)
-		: NULL;
-}
-
-static struct config_item r2hb_config_item;
-
-static struct config_item *r2hb_hb_group_make_item(struct config_group *group,
-							  const char *name)
-{
-	int ret;
-
-	if (strlen(name) > R2HB_MAX_REGION_NAME_LEN) {
-		ret = -ENAMETOOLONG;
-		goto free;
-	}
-
-	config_item_put(&r2hb_config_item);
-
-	return &r2hb_config_item;
-free:
-	return ERR_PTR(ret);
-}
-
-static void r2hb_hb_group_drop_item(struct config_group *group,
-					   struct config_item *item)
-{
-	if (r2hb_global_heartbeat_active()) {
-		printk(KERN_NOTICE "ramster: Heartbeat %s "
-			"on region %s (%s)\n",
-			"stopped/aborted", config_item_name(item),
-			"no region");
-	}
-
-	config_item_put(item);
-}
-
-struct r2hb_hb_group_attribute {
-	struct configfs_attribute attr;
-	ssize_t (*show)(struct r2hb_hb_group *, char *);
-	ssize_t (*store)(struct r2hb_hb_group *, const char *, size_t);
-};
-
-static ssize_t r2hb_hb_group_show(struct config_item *item,
-					 struct configfs_attribute *attr,
-					 char *page)
-{
-	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
-	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
-		container_of(attr, struct r2hb_hb_group_attribute, attr);
-	ssize_t ret = 0;
-
-	if (r2hb_hb_group_attr->show)
-		ret = r2hb_hb_group_attr->show(reg, page);
-	return ret;
-}
-
-static ssize_t r2hb_hb_group_store(struct config_item *item,
-					  struct configfs_attribute *attr,
-					  const char *page, size_t count)
-{
-	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
-	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
-		container_of(attr, struct r2hb_hb_group_attribute, attr);
-	ssize_t ret = -EINVAL;
-
-	if (r2hb_hb_group_attr->store)
-		ret = r2hb_hb_group_attr->store(reg, page, count);
-	return ret;
-}
-
-static ssize_t r2hb_hb_group_threshold_show(struct r2hb_hb_group *group,
-						     char *page)
-{
-	return sprintf(page, "%u\n", r2hb_dead_threshold);
-}
-
-static ssize_t r2hb_hb_group_threshold_store(struct r2hb_hb_group *group,
-						    const char *page,
-						    size_t count)
-{
-	unsigned long tmp;
-	char *p = (char *)page;
-	int err;
-
-	err = kstrtoul(p, 10, &tmp);
-	if (err)
-		return err;
-
-	/* this will validate ranges for us. */
-	r2hb_dead_threshold_set((unsigned int) tmp);
-
-	return count;
-}
-
-static
-ssize_t r2hb_hb_group_mode_show(struct r2hb_hb_group *group,
-				       char *page)
-{
-	return sprintf(page, "%s\n",
-		       r2hb_heartbeat_mode_desc[r2hb_heartbeat_mode]);
-}
-
-static
-ssize_t r2hb_hb_group_mode_store(struct r2hb_hb_group *group,
-					const char *page, size_t count)
-{
-	unsigned int i;
-	int ret;
-	size_t len;
-
-	len = (page[count - 1] == '\n') ? count - 1 : count;
-	if (!len)
-		return -EINVAL;
-
-	for (i = 0; i < R2HB_HEARTBEAT_NUM_MODES; ++i) {
-		if (strnicmp(page, r2hb_heartbeat_mode_desc[i], len))
-			continue;
-
-		ret = r2hb_global_hearbeat_mode_set(i);
-		if (!ret)
-			printk(KERN_NOTICE "ramster: Heartbeat mode "
-						"set to %s\n",
-			       r2hb_heartbeat_mode_desc[i]);
-		return count;
-	}
-
-	return -EINVAL;
-
-}
-
-static struct r2hb_hb_group_attribute r2hb_hb_group_attr_threshold = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "dead_threshold",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2hb_hb_group_threshold_show,
-	.store	= r2hb_hb_group_threshold_store,
-};
-
-static struct r2hb_hb_group_attribute r2hb_hb_group_attr_mode = {
-	.attr   = { .ca_owner = THIS_MODULE,
-		.ca_name = "mode",
-		.ca_mode = S_IRUGO | S_IWUSR },
-	.show   = r2hb_hb_group_mode_show,
-	.store  = r2hb_hb_group_mode_store,
-};
-
-static struct configfs_attribute *r2hb_hb_group_attrs[] = {
-	&r2hb_hb_group_attr_threshold.attr,
-	&r2hb_hb_group_attr_mode.attr,
-	NULL,
-};
-
-static struct configfs_item_operations r2hb_hearbeat_group_item_ops = {
-	.show_attribute		= r2hb_hb_group_show,
-	.store_attribute	= r2hb_hb_group_store,
-};
-
-static struct configfs_group_operations r2hb_hb_group_group_ops = {
-	.make_item	= r2hb_hb_group_make_item,
-	.drop_item	= r2hb_hb_group_drop_item,
-};
-
-static struct config_item_type r2hb_hb_group_type = {
-	.ct_group_ops	= &r2hb_hb_group_group_ops,
-	.ct_item_ops	= &r2hb_hearbeat_group_item_ops,
-	.ct_attrs	= r2hb_hb_group_attrs,
-	.ct_owner	= THIS_MODULE,
-};
-
-/* this is just here to avoid touching group in heartbeat.h which the
- * entire damn world #includes */
-struct config_group *r2hb_alloc_hb_set(void)
-{
-	struct r2hb_hb_group *hs = NULL;
-	struct config_group *ret = NULL;
-
-	hs = kzalloc(sizeof(struct r2hb_hb_group), GFP_KERNEL);
-	if (hs == NULL)
-		goto out;
-
-	config_group_init_type_name(&hs->hs_group, "heartbeat",
-				    &r2hb_hb_group_type);
-
-	ret = &hs->hs_group;
-out:
-	if (ret == NULL)
-		kfree(hs);
-	return ret;
-}
-
-void r2hb_free_hb_set(struct config_group *group)
-{
-	struct r2hb_hb_group *hs = to_r2hb_hb_group(group);
-	kfree(hs);
-}
-
-/* hb callback registration and issuing */
-
-static struct r2hb_callback *hbcall_from_type(enum r2hb_callback_type type)
-{
-	if (type == R2HB_NUM_CB)
-		return ERR_PTR(-EINVAL);
-
-	return &r2hb_callbacks[type];
-}
-
-void r2hb_setup_callback(struct r2hb_callback_func *hc,
-			 enum r2hb_callback_type type,
-			 r2hb_cb_func *func,
-			 void *data,
-			 int priority)
-{
-	INIT_LIST_HEAD(&hc->hc_item);
-	hc->hc_func = func;
-	hc->hc_data = data;
-	hc->hc_priority = priority;
-	hc->hc_type = type;
-	hc->hc_magic = R2HB_CB_MAGIC;
-}
-EXPORT_SYMBOL_GPL(r2hb_setup_callback);
-
-int r2hb_register_callback(const char *region_uuid,
-			   struct r2hb_callback_func *hc)
-{
-	struct r2hb_callback_func *tmp;
-	struct list_head *iter;
-	struct r2hb_callback *hbcall;
-	int ret;
-
-	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
-	BUG_ON(!list_empty(&hc->hc_item));
-
-	hbcall = hbcall_from_type(hc->hc_type);
-	if (IS_ERR(hbcall)) {
-		ret = PTR_ERR(hbcall);
-		goto out;
-	}
-
-	down_write(&r2hb_callback_sem);
-
-	list_for_each(iter, &hbcall->list) {
-		tmp = list_entry(iter, struct r2hb_callback_func, hc_item);
-		if (hc->hc_priority < tmp->hc_priority) {
-			list_add_tail(&hc->hc_item, iter);
-			break;
-		}
-	}
-	if (list_empty(&hc->hc_item))
-		list_add_tail(&hc->hc_item, &hbcall->list);
-
-	up_write(&r2hb_callback_sem);
-	ret = 0;
-out:
-	mlog(ML_CLUSTER, "returning %d on behalf of %p for funcs %p\n",
-	     ret, __builtin_return_address(0), hc);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(r2hb_register_callback);
-
-void r2hb_unregister_callback(const char *region_uuid,
-			      struct r2hb_callback_func *hc)
-{
-	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
-
-	mlog(ML_CLUSTER, "on behalf of %p for funcs %p\n",
-	     __builtin_return_address(0), hc);
-
-	/* XXX Can this happen _with_ a region reference? */
-	if (list_empty(&hc->hc_item))
-		return;
-
-	down_write(&r2hb_callback_sem);
-
-	list_del_init(&hc->hc_item);
-
-	up_write(&r2hb_callback_sem);
-}
-EXPORT_SYMBOL_GPL(r2hb_unregister_callback);
-
-int r2hb_check_node_heartbeating_from_callback(u8 node_num)
-{
-	unsigned long testing_map[BITS_TO_LONGS(R2NM_MAX_NODES)];
-
-	r2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
-	if (!test_bit(node_num, testing_map)) {
-		mlog(ML_HEARTBEAT,
-		     "node (%u) does not have heartbeating enabled.\n",
-		     node_num);
-		return 0;
-	}
-
-	return 1;
-}
-EXPORT_SYMBOL_GPL(r2hb_check_node_heartbeating_from_callback);
-
-void r2hb_stop_all_regions(void)
-{
-}
-EXPORT_SYMBOL_GPL(r2hb_stop_all_regions);
-
-/*
- * this is just a hack until we get the plumbing which flips file systems
- * read only and drops the hb ref instead of killing the node dead.
- */
-int r2hb_global_heartbeat_active(void)
-{
-	return (r2hb_heartbeat_mode == R2HB_HEARTBEAT_GLOBAL);
-}
-EXPORT_SYMBOL(r2hb_global_heartbeat_active);
-
-/* added for RAMster */
-void r2hb_manual_set_node_heartbeating(int node_num)
-{
-	if (node_num < R2NM_MAX_NODES)
-		set_bit(node_num, r2hb_live_node_bitmap);
-}
-EXPORT_SYMBOL(r2hb_manual_set_node_heartbeating);
diff --git a/drivers/staging/ramster/cluster/nodemanager.c b/drivers/staging/ramster/cluster/nodemanager.c
deleted file mode 100644
index de0e5c8..0000000
--- a/drivers/staging/ramster/cluster/nodemanager.c
+++ /dev/null
@@ -1,992 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/configfs.h>
-
-#include "tcp.h"
-#include "nodemanager.h"
-#include "heartbeat.h"
-#include "masklog.h"
-
-/* for now we operate under the assertion that there can be only one
- * cluster active at a time.  Changing this will require trickling
- * cluster references throughout where nodes are looked up */
-struct r2nm_cluster *r2nm_single_cluster;
-
-char *r2nm_fence_method_desc[R2NM_FENCE_METHODS] = {
-		"reset",	/* R2NM_FENCE_RESET */
-		"panic",	/* R2NM_FENCE_PANIC */
-};
-
-struct r2nm_node *r2nm_get_node_by_num(u8 node_num)
-{
-	struct r2nm_node *node = NULL;
-
-	if (node_num >= R2NM_MAX_NODES || r2nm_single_cluster == NULL)
-		goto out;
-
-	read_lock(&r2nm_single_cluster->cl_nodes_lock);
-	node = r2nm_single_cluster->cl_nodes[node_num];
-	if (node)
-		config_item_get(&node->nd_item);
-	read_unlock(&r2nm_single_cluster->cl_nodes_lock);
-out:
-	return node;
-}
-EXPORT_SYMBOL_GPL(r2nm_get_node_by_num);
-
-int r2nm_configured_node_map(unsigned long *map, unsigned bytes)
-{
-	struct r2nm_cluster *cluster = r2nm_single_cluster;
-
-	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
-
-	if (cluster == NULL)
-		return -EINVAL;
-
-	read_lock(&cluster->cl_nodes_lock);
-	memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
-	read_unlock(&cluster->cl_nodes_lock);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(r2nm_configured_node_map);
-
-static struct r2nm_node *r2nm_node_ip_tree_lookup(struct r2nm_cluster *cluster,
-						  __be32 ip_needle,
-						  struct rb_node ***ret_p,
-						  struct rb_node **ret_parent)
-{
-	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
-	struct rb_node *parent = NULL;
-	struct r2nm_node *node, *ret = NULL;
-
-	while (*p) {
-		int cmp;
-
-		parent = *p;
-		node = rb_entry(parent, struct r2nm_node, nd_ip_node);
-
-		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
-				sizeof(ip_needle));
-		if (cmp < 0)
-			p = &(*p)->rb_left;
-		else if (cmp > 0)
-			p = &(*p)->rb_right;
-		else {
-			ret = node;
-			break;
-		}
-	}
-
-	if (ret_p != NULL)
-		*ret_p = p;
-	if (ret_parent != NULL)
-		*ret_parent = parent;
-
-	return ret;
-}
-
-struct r2nm_node *r2nm_get_node_by_ip(__be32 addr)
-{
-	struct r2nm_node *node = NULL;
-	struct r2nm_cluster *cluster = r2nm_single_cluster;
-
-	if (cluster == NULL)
-		goto out;
-
-	read_lock(&cluster->cl_nodes_lock);
-	node = r2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
-	if (node)
-		config_item_get(&node->nd_item);
-	read_unlock(&cluster->cl_nodes_lock);
-
-out:
-	return node;
-}
-EXPORT_SYMBOL_GPL(r2nm_get_node_by_ip);
-
-void r2nm_node_put(struct r2nm_node *node)
-{
-	config_item_put(&node->nd_item);
-}
-EXPORT_SYMBOL_GPL(r2nm_node_put);
-
-void r2nm_node_get(struct r2nm_node *node)
-{
-	config_item_get(&node->nd_item);
-}
-EXPORT_SYMBOL_GPL(r2nm_node_get);
-
-u8 r2nm_this_node(void)
-{
-	u8 node_num = R2NM_MAX_NODES;
-
-	if (r2nm_single_cluster && r2nm_single_cluster->cl_has_local)
-		node_num = r2nm_single_cluster->cl_local_node;
-
-	return node_num;
-}
-EXPORT_SYMBOL_GPL(r2nm_this_node);
-
-/* node configfs bits */
-
-static struct r2nm_cluster *to_r2nm_cluster(struct config_item *item)
-{
-	return item ?
-		container_of(to_config_group(item), struct r2nm_cluster,
-			     cl_group)
-		: NULL;
-}
-
-static struct r2nm_node *to_r2nm_node(struct config_item *item)
-{
-	return item ? container_of(item, struct r2nm_node, nd_item) : NULL;
-}
-
-static void r2nm_node_release(struct config_item *item)
-{
-	struct r2nm_node *node = to_r2nm_node(item);
-	kfree(node);
-}
-
-static ssize_t r2nm_node_num_read(struct r2nm_node *node, char *page)
-{
-	return sprintf(page, "%d\n", node->nd_num);
-}
-
-static struct r2nm_cluster *to_r2nm_cluster_from_node(struct r2nm_node *node)
-{
-	/* through the first node_set .parent
-	 * mycluster/nodes/mynode == r2nm_cluster->r2nm_node_group->r2nm_node */
-	return to_r2nm_cluster(node->nd_item.ci_parent->ci_parent);
-}
-
-enum {
-	R2NM_NODE_ATTR_NUM = 0,
-	R2NM_NODE_ATTR_PORT,
-	R2NM_NODE_ATTR_ADDRESS,
-	R2NM_NODE_ATTR_LOCAL,
-};
-
-static ssize_t r2nm_node_num_write(struct r2nm_node *node, const char *page,
-				   size_t count)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
-	unsigned long tmp;
-	char *p = (char *)page;
-	int err;
-
-	err = kstrtoul(p, 10, &tmp);
-	if (err)
-		return err;
-
-	if (tmp >= R2NM_MAX_NODES)
-		return -ERANGE;
-
-	/* once we're in the cl_nodes tree networking can look us up by
-	 * node number and try to use our address and port attributes
-	 * to connect to this node.. make sure that they've been set
-	 * before writing the node attribute? */
-	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
-	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
-		return -EINVAL; /* XXX */
-
-	write_lock(&cluster->cl_nodes_lock);
-	if (cluster->cl_nodes[tmp])
-		p = NULL;
-	else  {
-		cluster->cl_nodes[tmp] = node;
-		node->nd_num = tmp;
-		set_bit(tmp, cluster->cl_nodes_bitmap);
-	}
-	write_unlock(&cluster->cl_nodes_lock);
-	if (p == NULL)
-		return -EEXIST;
-
-	return count;
-}
-static ssize_t r2nm_node_ipv4_port_read(struct r2nm_node *node, char *page)
-{
-	return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
-}
-
-static ssize_t r2nm_node_ipv4_port_write(struct r2nm_node *node,
-					 const char *page, size_t count)
-{
-	unsigned long tmp;
-	char *p = (char *)page;
-	int err;
-
-	err = kstrtoul(p, 10, &tmp);
-	if (err)
-		return err;
-
-	if (tmp == 0)
-		return -EINVAL;
-	if (tmp >= (u16)-1)
-		return -ERANGE;
-
-	node->nd_ipv4_port = htons(tmp);
-
-	return count;
-}
-
-static ssize_t r2nm_node_ipv4_address_read(struct r2nm_node *node, char *page)
-{
-	return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
-}
-
-static ssize_t r2nm_node_ipv4_address_write(struct r2nm_node *node,
-					    const char *page,
-					    size_t count)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
-	int ret, i;
-	struct rb_node **p, *parent;
-	unsigned int octets[4];
-	__be32 ipv4_addr = 0;
-
-	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
-		     &octets[1], &octets[0]);
-	if (ret != 4)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(octets); i++) {
-		if (octets[i] > 255)
-			return -ERANGE;
-		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
-	}
-
-	ret = 0;
-	write_lock(&cluster->cl_nodes_lock);
-	if (r2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
-		ret = -EEXIST;
-	else {
-		rb_link_node(&node->nd_ip_node, parent, p);
-		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
-	}
-	write_unlock(&cluster->cl_nodes_lock);
-	if (ret)
-		return ret;
-
-	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
-
-	return count;
-}
-
-static ssize_t r2nm_node_local_read(struct r2nm_node *node, char *page)
-{
-	return sprintf(page, "%d\n", node->nd_local);
-}
-
-static ssize_t r2nm_node_local_write(struct r2nm_node *node, const char *page,
-				     size_t count)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
-	unsigned long tmp;
-	char *p = (char *)page;
-	ssize_t ret;
-	int err;
-
-	err = kstrtoul(p, 10, &tmp);
-	if (err)
-		return err;
-
-	tmp = !!tmp; /* boolean of whether this node wants to be local */
-
-	/* setting local turns on networking rx for now so we require having
-	 * set everything else first */
-	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
-	    !test_bit(R2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
-	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
-		return -EINVAL; /* XXX */
-
-	/* the only failure case is trying to set a new local node
-	 * when a different one is already set */
-	if (tmp && tmp == cluster->cl_has_local &&
-	    cluster->cl_local_node != node->nd_num)
-		return -EBUSY;
-
-	/* bring up the rx thread if we're setting the new local node. */
-	if (tmp && !cluster->cl_has_local) {
-		ret = r2net_start_listening(node);
-		if (ret)
-			return ret;
-	}
-
-	if (!tmp && cluster->cl_has_local &&
-	    cluster->cl_local_node == node->nd_num) {
-		r2net_stop_listening(node);
-		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
-	}
-
-	node->nd_local = tmp;
-	if (node->nd_local) {
-		cluster->cl_has_local = tmp;
-		cluster->cl_local_node = node->nd_num;
-	}
-
-	return count;
-}
-
-struct r2nm_node_attribute {
-	struct configfs_attribute attr;
-	ssize_t (*show)(struct r2nm_node *, char *);
-	ssize_t (*store)(struct r2nm_node *, const char *, size_t);
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_num = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "num",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_node_num_read,
-	.store	= r2nm_node_num_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_ipv4_port = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "ipv4_port",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_node_ipv4_port_read,
-	.store	= r2nm_node_ipv4_port_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_ipv4_address = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "ipv4_address",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_node_ipv4_address_read,
-	.store	= r2nm_node_ipv4_address_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_local = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "local",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_node_local_read,
-	.store	= r2nm_node_local_write,
-};
-
-static struct configfs_attribute *r2nm_node_attrs[] = {
-	[R2NM_NODE_ATTR_NUM] = &r2nm_node_attr_num.attr,
-	[R2NM_NODE_ATTR_PORT] = &r2nm_node_attr_ipv4_port.attr,
-	[R2NM_NODE_ATTR_ADDRESS] = &r2nm_node_attr_ipv4_address.attr,
-	[R2NM_NODE_ATTR_LOCAL] = &r2nm_node_attr_local.attr,
-	NULL,
-};
-
-static int r2nm_attr_index(struct configfs_attribute *attr)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(r2nm_node_attrs); i++) {
-		if (attr == r2nm_node_attrs[i])
-			return i;
-	}
-	BUG();
-	return 0;
-}
-
-static ssize_t r2nm_node_show(struct config_item *item,
-			      struct configfs_attribute *attr,
-			      char *page)
-{
-	struct r2nm_node *node = to_r2nm_node(item);
-	struct r2nm_node_attribute *r2nm_node_attr =
-		container_of(attr, struct r2nm_node_attribute, attr);
-	ssize_t ret = 0;
-
-	if (r2nm_node_attr->show)
-		ret = r2nm_node_attr->show(node, page);
-	return ret;
-}
-
-static ssize_t r2nm_node_store(struct config_item *item,
-			       struct configfs_attribute *attr,
-			       const char *page, size_t count)
-{
-	struct r2nm_node *node = to_r2nm_node(item);
-	struct r2nm_node_attribute *r2nm_node_attr =
-		container_of(attr, struct r2nm_node_attribute, attr);
-	ssize_t ret;
-	int attr_index = r2nm_attr_index(attr);
-
-	if (r2nm_node_attr->store == NULL) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (test_bit(attr_index, &node->nd_set_attributes))
-		return -EBUSY;
-
-	ret = r2nm_node_attr->store(node, page, count);
-	if (ret < count)
-		goto out;
-
-	set_bit(attr_index, &node->nd_set_attributes);
-out:
-	return ret;
-}
-
-static struct configfs_item_operations r2nm_node_item_ops = {
-	.release		= r2nm_node_release,
-	.show_attribute		= r2nm_node_show,
-	.store_attribute	= r2nm_node_store,
-};
-
-static struct config_item_type r2nm_node_type = {
-	.ct_item_ops	= &r2nm_node_item_ops,
-	.ct_attrs	= r2nm_node_attrs,
-	.ct_owner	= THIS_MODULE,
-};
-
-/* node set */
-
-struct r2nm_node_group {
-	struct config_group ns_group;
-	/* some stuff? */
-};
-
-#if 0
-static struct r2nm_node_group *to_r2nm_node_group(struct config_group *group)
-{
-	return group ?
-		container_of(group, struct r2nm_node_group, ns_group)
-		: NULL;
-}
-#endif
-
-struct r2nm_cluster_attribute {
-	struct configfs_attribute attr;
-	ssize_t (*show)(struct r2nm_cluster *, char *);
-	ssize_t (*store)(struct r2nm_cluster *, const char *, size_t);
-};
-
-static ssize_t r2nm_cluster_attr_write(const char *page, ssize_t count,
-					unsigned int *val)
-{
-	unsigned long tmp;
-	char *p = (char *)page;
-	int err;
-
-	err = kstrtoul(p, 10, &tmp);
-	if (err)
-		return err;
-
-	if (tmp == 0)
-		return -EINVAL;
-	if (tmp >= (u32)-1)
-		return -ERANGE;
-
-	*val = tmp;
-
-	return count;
-}
-
-static ssize_t r2nm_cluster_attr_idle_timeout_ms_read(
-	struct r2nm_cluster *cluster, char *page)
-{
-	return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
-}
-
-static ssize_t r2nm_cluster_attr_idle_timeout_ms_write(
-	struct r2nm_cluster *cluster, const char *page, size_t count)
-{
-	ssize_t ret;
-	unsigned int val = 0;
-
-	ret =  r2nm_cluster_attr_write(page, count, &val);
-
-	if (ret > 0) {
-		if (cluster->cl_idle_timeout_ms != val
-			&& r2net_num_connected_peers()) {
-			mlog(ML_NOTICE,
-			     "r2net: cannot change idle timeout after "
-			     "the first peer has agreed to it."
-			     "  %d connected peers\n",
-			     r2net_num_connected_peers());
-			ret = -EINVAL;
-		} else if (val <= cluster->cl_keepalive_delay_ms) {
-			mlog(ML_NOTICE, "r2net: idle timeout must be larger "
-			     "than keepalive delay\n");
-			ret = -EINVAL;
-		} else {
-			cluster->cl_idle_timeout_ms = val;
-		}
-	}
-
-	return ret;
-}
-
-static ssize_t r2nm_cluster_attr_keepalive_delay_ms_read(
-	struct r2nm_cluster *cluster, char *page)
-{
-	return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_keepalive_delay_ms_write(
-	struct r2nm_cluster *cluster, const char *page, size_t count)
-{
-	ssize_t ret;
-	unsigned int val = 0;
-
-	ret =  r2nm_cluster_attr_write(page, count, &val);
-
-	if (ret > 0) {
-		if (cluster->cl_keepalive_delay_ms != val
-		    && r2net_num_connected_peers()) {
-			mlog(ML_NOTICE,
-			     "r2net: cannot change keepalive delay after"
-			     " the first peer has agreed to it."
-			     "  %d connected peers\n",
-			     r2net_num_connected_peers());
-			ret = -EINVAL;
-		} else if (val >= cluster->cl_idle_timeout_ms) {
-			mlog(ML_NOTICE, "r2net: keepalive delay must be "
-			     "smaller than idle timeout\n");
-			ret = -EINVAL;
-		} else {
-			cluster->cl_keepalive_delay_ms = val;
-		}
-	}
-
-	return ret;
-}
-
-static ssize_t r2nm_cluster_attr_reconnect_delay_ms_read(
-	struct r2nm_cluster *cluster, char *page)
-{
-	return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_reconnect_delay_ms_write(
-	struct r2nm_cluster *cluster, const char *page, size_t count)
-{
-	return r2nm_cluster_attr_write(page, count,
-					&cluster->cl_reconnect_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_fence_method_read(
-	struct r2nm_cluster *cluster, char *page)
-{
-	ssize_t ret = 0;
-
-	if (cluster)
-		ret = sprintf(page, "%s\n",
-			      r2nm_fence_method_desc[cluster->cl_fence_method]);
-	return ret;
-}
-
-static ssize_t r2nm_cluster_attr_fence_method_write(
-	struct r2nm_cluster *cluster, const char *page, size_t count)
-{
-	unsigned int i;
-
-	if (page[count - 1] != '\n')
-		goto bail;
-
-	for (i = 0; i < R2NM_FENCE_METHODS; ++i) {
-		if (count != strlen(r2nm_fence_method_desc[i]) + 1)
-			continue;
-		if (strncasecmp(page, r2nm_fence_method_desc[i], count - 1))
-			continue;
-		if (cluster->cl_fence_method != i) {
-			printk(KERN_INFO "ramster: Changing fence method to %s\n",
-			       r2nm_fence_method_desc[i]);
-			cluster->cl_fence_method = i;
-		}
-		return count;
-	}
-
-bail:
-	return -EINVAL;
-}
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_idle_timeout_ms = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "idle_timeout_ms",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_cluster_attr_idle_timeout_ms_read,
-	.store	= r2nm_cluster_attr_idle_timeout_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_keepalive_delay_ms = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "keepalive_delay_ms",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_cluster_attr_keepalive_delay_ms_read,
-	.store	= r2nm_cluster_attr_keepalive_delay_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_reconnect_delay_ms = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "reconnect_delay_ms",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_cluster_attr_reconnect_delay_ms_read,
-	.store	= r2nm_cluster_attr_reconnect_delay_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_fence_method = {
-	.attr	= { .ca_owner = THIS_MODULE,
-		    .ca_name = "fence_method",
-		    .ca_mode = S_IRUGO | S_IWUSR },
-	.show	= r2nm_cluster_attr_fence_method_read,
-	.store	= r2nm_cluster_attr_fence_method_write,
-};
-
-static struct configfs_attribute *r2nm_cluster_attrs[] = {
-	&r2nm_cluster_attr_idle_timeout_ms.attr,
-	&r2nm_cluster_attr_keepalive_delay_ms.attr,
-	&r2nm_cluster_attr_reconnect_delay_ms.attr,
-	&r2nm_cluster_attr_fence_method.attr,
-	NULL,
-};
-static ssize_t r2nm_cluster_show(struct config_item *item,
-					struct configfs_attribute *attr,
-					char *page)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
-	struct r2nm_cluster_attribute *r2nm_cluster_attr =
-		container_of(attr, struct r2nm_cluster_attribute, attr);
-	ssize_t ret = 0;
-
-	if (r2nm_cluster_attr->show)
-		ret = r2nm_cluster_attr->show(cluster, page);
-	return ret;
-}
-
-static ssize_t r2nm_cluster_store(struct config_item *item,
-					struct configfs_attribute *attr,
-					const char *page, size_t count)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
-	struct r2nm_cluster_attribute *r2nm_cluster_attr =
-		container_of(attr, struct r2nm_cluster_attribute, attr);
-	ssize_t ret;
-
-	if (r2nm_cluster_attr->store == NULL) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = r2nm_cluster_attr->store(cluster, page, count);
-	if (ret < count)
-		goto out;
-out:
-	return ret;
-}
-
-static struct config_item *r2nm_node_group_make_item(struct config_group *group,
-						     const char *name)
-{
-	struct r2nm_node *node = NULL;
-
-	if (strlen(name) > R2NM_MAX_NAME_LEN)
-		return ERR_PTR(-ENAMETOOLONG);
-
-	node = kzalloc(sizeof(struct r2nm_node), GFP_KERNEL);
-	if (node == NULL)
-		return ERR_PTR(-ENOMEM);
-
-	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
-	config_item_init_type_name(&node->nd_item, name, &r2nm_node_type);
-	spin_lock_init(&node->nd_lock);
-
-	mlog(ML_CLUSTER, "r2nm: Registering node %s\n", name);
-
-	return &node->nd_item;
-}
-
-static void r2nm_node_group_drop_item(struct config_group *group,
-				      struct config_item *item)
-{
-	struct r2nm_node *node = to_r2nm_node(item);
-	struct r2nm_cluster *cluster =
-				to_r2nm_cluster(group->cg_item.ci_parent);
-
-	r2net_disconnect_node(node);
-
-	if (cluster->cl_has_local &&
-	    (cluster->cl_local_node == node->nd_num)) {
-		cluster->cl_has_local = 0;
-		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
-		r2net_stop_listening(node);
-	}
-
-	/* XXX call into net to stop this node from trading messages */
-
-	write_lock(&cluster->cl_nodes_lock);
-
-	/* XXX sloppy */
-	if (node->nd_ipv4_address)
-		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
-
-	/* nd_num might be 0 if the node number hasn't been set.. */
-	if (cluster->cl_nodes[node->nd_num] == node) {
-		cluster->cl_nodes[node->nd_num] = NULL;
-		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
-	}
-	write_unlock(&cluster->cl_nodes_lock);
-
-	mlog(ML_CLUSTER, "r2nm: Unregistered node %s\n",
-	     config_item_name(&node->nd_item));
-
-	config_item_put(item);
-}
-
-static struct configfs_group_operations r2nm_node_group_group_ops = {
-	.make_item	= r2nm_node_group_make_item,
-	.drop_item	= r2nm_node_group_drop_item,
-};
-
-static struct config_item_type r2nm_node_group_type = {
-	.ct_group_ops	= &r2nm_node_group_group_ops,
-	.ct_owner	= THIS_MODULE,
-};
-
-/* cluster */
-
-static void r2nm_cluster_release(struct config_item *item)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
-
-	kfree(cluster->cl_group.default_groups);
-	kfree(cluster);
-}
-
-static struct configfs_item_operations r2nm_cluster_item_ops = {
-	.release	= r2nm_cluster_release,
-	.show_attribute		= r2nm_cluster_show,
-	.store_attribute	= r2nm_cluster_store,
-};
-
-static struct config_item_type r2nm_cluster_type = {
-	.ct_item_ops	= &r2nm_cluster_item_ops,
-	.ct_attrs	= r2nm_cluster_attrs,
-	.ct_owner	= THIS_MODULE,
-};
-
-/* cluster set */
-
-struct r2nm_cluster_group {
-	struct configfs_subsystem cs_subsys;
-	/* some stuff? */
-};
-
-#if 0
-static struct r2nm_cluster_group *
-to_r2nm_cluster_group(struct config_group *group)
-{
-	return group ?
-		container_of(to_configfs_subsystem(group),
-				struct r2nm_cluster_group, cs_subsys)
-	       : NULL;
-}
-#endif
-
-static struct config_group *
-r2nm_cluster_group_make_group(struct config_group *group,
-							  const char *name)
-{
-	struct r2nm_cluster *cluster = NULL;
-	struct r2nm_node_group *ns = NULL;
-	struct config_group *r2hb_group = NULL, *ret = NULL;
-	void *defs = NULL;
-
-	/* this runs under the parent dir's i_mutex; there can be only
-	 * one caller in here at a time */
-	if (r2nm_single_cluster)
-		return ERR_PTR(-ENOSPC);
-
-	cluster = kzalloc(sizeof(struct r2nm_cluster), GFP_KERNEL);
-	ns = kzalloc(sizeof(struct r2nm_node_group), GFP_KERNEL);
-	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
-	r2hb_group = r2hb_alloc_hb_set();
-	if (cluster == NULL || ns == NULL || r2hb_group == NULL || defs == NULL)
-		goto out;
-
-	config_group_init_type_name(&cluster->cl_group, name,
-				    &r2nm_cluster_type);
-	config_group_init_type_name(&ns->ns_group, "node",
-				    &r2nm_node_group_type);
-
-	cluster->cl_group.default_groups = defs;
-	cluster->cl_group.default_groups[0] = &ns->ns_group;
-	cluster->cl_group.default_groups[1] = r2hb_group;
-	cluster->cl_group.default_groups[2] = NULL;
-	rwlock_init(&cluster->cl_nodes_lock);
-	cluster->cl_node_ip_tree = RB_ROOT;
-	cluster->cl_reconnect_delay_ms = R2NET_RECONNECT_DELAY_MS_DEFAULT;
-	cluster->cl_idle_timeout_ms    = R2NET_IDLE_TIMEOUT_MS_DEFAULT;
-	cluster->cl_keepalive_delay_ms = R2NET_KEEPALIVE_DELAY_MS_DEFAULT;
-	cluster->cl_fence_method       = R2NM_FENCE_RESET;
-
-	ret = &cluster->cl_group;
-	r2nm_single_cluster = cluster;
-
-out:
-	if (ret == NULL) {
-		kfree(cluster);
-		kfree(ns);
-		r2hb_free_hb_set(r2hb_group);
-		kfree(defs);
-		ret = ERR_PTR(-ENOMEM);
-	}
-
-	return ret;
-}
-
-static void r2nm_cluster_group_drop_item(struct config_group *group,
-						struct config_item *item)
-{
-	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
-	int i;
-	struct config_item *killme;
-
-	BUG_ON(r2nm_single_cluster != cluster);
-	r2nm_single_cluster = NULL;
-
-	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
-		killme = &cluster->cl_group.default_groups[i]->cg_item;
-		cluster->cl_group.default_groups[i] = NULL;
-		config_item_put(killme);
-	}
-
-	config_item_put(item);
-}
-
-static struct configfs_group_operations r2nm_cluster_group_group_ops = {
-	.make_group	= r2nm_cluster_group_make_group,
-	.drop_item	= r2nm_cluster_group_drop_item,
-};
-
-static struct config_item_type r2nm_cluster_group_type = {
-	.ct_group_ops	= &r2nm_cluster_group_group_ops,
-	.ct_owner	= THIS_MODULE,
-};
-
-static struct r2nm_cluster_group r2nm_cluster_group = {
-	.cs_subsys = {
-		.su_group = {
-			.cg_item = {
-				.ci_namebuf = "cluster",
-				.ci_type = &r2nm_cluster_group_type,
-			},
-		},
-	},
-};
-
-int r2nm_depend_item(struct config_item *item)
-{
-	return configfs_depend_item(&r2nm_cluster_group.cs_subsys, item);
-}
-
-void r2nm_undepend_item(struct config_item *item)
-{
-	configfs_undepend_item(&r2nm_cluster_group.cs_subsys, item);
-}
-
-int r2nm_depend_this_node(void)
-{
-	int ret = 0;
-	struct r2nm_node *local_node;
-
-	local_node = r2nm_get_node_by_num(r2nm_this_node());
-	if (!local_node) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = r2nm_depend_item(&local_node->nd_item);
-	r2nm_node_put(local_node);
-
-out:
-	return ret;
-}
-
-void r2nm_undepend_this_node(void)
-{
-	struct r2nm_node *local_node;
-
-	local_node = r2nm_get_node_by_num(r2nm_this_node());
-	BUG_ON(!local_node);
-
-	r2nm_undepend_item(&local_node->nd_item);
-	r2nm_node_put(local_node);
-}
-
-
-static void __exit exit_r2nm(void)
-{
-	/* XXX sync with hb callbacks and shut down hb? */
-	r2net_unregister_hb_callbacks();
-	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
-
-	r2net_exit();
-	r2hb_exit();
-}
-
-static int __init init_r2nm(void)
-{
-	int ret = -1;
-
-	ret = r2hb_init();
-	if (ret)
-		goto out;
-
-	ret = r2net_init();
-	if (ret)
-		goto out_r2hb;
-
-	ret = r2net_register_hb_callbacks();
-	if (ret)
-		goto out_r2net;
-
-	config_group_init(&r2nm_cluster_group.cs_subsys.su_group);
-	mutex_init(&r2nm_cluster_group.cs_subsys.su_mutex);
-	ret = configfs_register_subsystem(&r2nm_cluster_group.cs_subsys);
-	if (ret) {
-		printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
-		goto out_callbacks;
-	}
-
-	if (!ret)
-		goto out;
-
-	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
-out_callbacks:
-	r2net_unregister_hb_callbacks();
-out_r2net:
-	r2net_exit();
-out_r2hb:
-	r2hb_exit();
-out:
-	return ret;
-}
-
-MODULE_AUTHOR("Oracle");
-MODULE_LICENSE("GPL");
-
-module_init(init_r2nm)
-module_exit(exit_r2nm)
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
deleted file mode 100644
index d0a07d7..0000000
--- a/drivers/staging/ramster/cluster/tcp.c
+++ /dev/null
@@ -1,2256 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- *
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004 Oracle.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- * ----
- *
- * Callers for this were originally written against a very simple synchronus
- * API.  This implementation reflects those simple callers.  Some day I'm sure
- * we'll need to move to a more robust posting/callback mechanism.
- *
- * Transmit calls pass in kernel virtual addresses and block copying this into
- * the socket's tx buffers via a usual blocking sendmsg.  They'll block waiting
- * for a failed socket to timeout.  TX callers can also pass in a poniter to an
- * 'int' which gets filled with an errno off the wire in response to the
- * message they send.
- *
- * Handlers for unsolicited messages are registered.  Each socket has a page
- * that incoming data is copied into.  First the header, then the data.
- * Handlers are called from only one thread with a reference to this per-socket
- * page.  This page is destroyed after the handler call, so it can't be
- * referenced beyond the call.  Handlers may block but are discouraged from
- * doing so.
- *
- * Any framing errors (bad magic, large payload lengths) close a connection.
- *
- * Our sock_container holds the state we associate with a socket.  It's current
- * framing state is held there as well as the refcounting we do around when it
- * is safe to tear down the socket.  The socket is only finally torn down from
- * the container when the container loses all of its references -- so as long
- * as you hold a ref on the container you can trust that the socket is valid
- * for use with kernel socket APIs.
- *
- * Connections are initiated between a pair of nodes when the node with the
- * higher node number gets a heartbeat callback which indicates that the lower
- * numbered node has started heartbeating.  The lower numbered node is passive
- * and only accepts the connection if the higher numbered node is heartbeating.
- */
-
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/idr.h>
-#include <linux/kref.h>
-#include <linux/net.h>
-#include <linux/export.h>
-#include <linux/uaccess.h>
-#include <net/tcp.h>
-
-
-#include "heartbeat.h"
-#include "tcp.h"
-#include "nodemanager.h"
-#define MLOG_MASK_PREFIX ML_TCP
-#include "masklog.h"
-
-#include "tcp_internal.h"
-
-#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u"
-
-/*
- * In the following two log macros, the whitespace after the ',' just
- * before ##args is intentional. Otherwise, gcc 2.95 will eat the
- * previous token if args expands to nothing.
- */
-#define msglog(hdr, fmt, args...) do {					\
-	typeof(hdr) __hdr = (hdr);					\
-	mlog(ML_MSG, "[mag %u len %u typ %u stat %d sys_stat %d "	\
-	     "key %08x num %u] " fmt,					\
-	be16_to_cpu(__hdr->magic), be16_to_cpu(__hdr->data_len),	\
-	     be16_to_cpu(__hdr->msg_type), be32_to_cpu(__hdr->status),	\
-	     be32_to_cpu(__hdr->sys_status), be32_to_cpu(__hdr->key),	\
-	     be32_to_cpu(__hdr->msg_num) ,  ##args);			\
-} while (0)
-
-#define sclog(sc, fmt, args...) do {					\
-	typeof(sc) __sc = (sc);						\
-	mlog(ML_SOCKET, "[sc %p refs %d sock %p node %u page %p "	\
-	     "pg_off %zu] " fmt, __sc,					\
-	     atomic_read(&__sc->sc_kref.refcount), __sc->sc_sock,	\
-	    __sc->sc_node->nd_num, __sc->sc_page, __sc->sc_page_off ,	\
-	    ##args);							\
-} while (0)
-
-static DEFINE_RWLOCK(r2net_handler_lock);
-static struct rb_root r2net_handler_tree = RB_ROOT;
-
-static struct r2net_node r2net_nodes[R2NM_MAX_NODES];
-
-/* XXX someday we'll need better accounting */
-static struct socket *r2net_listen_sock;
-
-/*
- * listen work is only queued by the listening socket callbacks on the
- * r2net_wq.  teardown detaches the callbacks before destroying the workqueue.
- * quorum work is queued as sock containers are shutdown.. stop_listening
- * tears down all the node's sock containers, preventing future shutdowns
- * and queued quorum work, before canceling delayed quorum work and
- * destroying the work queue.
- */
-static struct workqueue_struct *r2net_wq;
-static struct work_struct r2net_listen_work;
-
-static struct r2hb_callback_func r2net_hb_up, r2net_hb_down;
-#define R2NET_HB_PRI 0x1
-
-static struct r2net_handshake *r2net_hand;
-static struct r2net_msg *r2net_keep_req, *r2net_keep_resp;
-
-static int r2net_sys_err_translations[R2NET_ERR_MAX] = {
-		[R2NET_ERR_NONE]	= 0,
-		[R2NET_ERR_NO_HNDLR]	= -ENOPROTOOPT,
-		[R2NET_ERR_OVERFLOW]	= -EOVERFLOW,
-		[R2NET_ERR_DIED]	= -EHOSTDOWN,};
-
-/* can't quite avoid *all* internal declarations :/ */
-static void r2net_sc_connect_completed(struct work_struct *work);
-static void r2net_rx_until_empty(struct work_struct *work);
-static void r2net_shutdown_sc(struct work_struct *work);
-static void r2net_listen_data_ready(struct sock *sk, int bytes);
-static void r2net_sc_send_keep_req(struct work_struct *work);
-static void r2net_idle_timer(unsigned long data);
-static void r2net_sc_postpone_idle(struct r2net_sock_container *sc);
-static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc);
-
-#ifdef CONFIG_DEBUG_FS
-static void r2net_init_nst(struct r2net_send_tracking *nst, u32 msgtype,
-			   u32 msgkey, struct task_struct *task, u8 node)
-{
-	INIT_LIST_HEAD(&nst->st_net_debug_item);
-	nst->st_task = task;
-	nst->st_msg_type = msgtype;
-	nst->st_msg_key = msgkey;
-	nst->st_node = node;
-}
-
-static inline void r2net_set_nst_sock_time(struct r2net_send_tracking *nst)
-{
-	nst->st_sock_time = ktime_get();
-}
-
-static inline void r2net_set_nst_send_time(struct r2net_send_tracking *nst)
-{
-	nst->st_send_time = ktime_get();
-}
-
-static inline void r2net_set_nst_status_time(struct r2net_send_tracking *nst)
-{
-	nst->st_status_time = ktime_get();
-}
-
-static inline void r2net_set_nst_sock_container(struct r2net_send_tracking *nst,
-						struct r2net_sock_container *sc)
-{
-	nst->st_sc = sc;
-}
-
-static inline void r2net_set_nst_msg_id(struct r2net_send_tracking *nst,
-					u32 msg_id)
-{
-	nst->st_id = msg_id;
-}
-
-static inline void r2net_set_sock_timer(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_timer = ktime_get();
-}
-
-static inline void r2net_set_data_ready_time(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_data_ready = ktime_get();
-}
-
-static inline void r2net_set_advance_start_time(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_advance_start = ktime_get();
-}
-
-static inline void r2net_set_advance_stop_time(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_advance_stop = ktime_get();
-}
-
-static inline void r2net_set_func_start_time(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_func_start = ktime_get();
-}
-
-static inline void r2net_set_func_stop_time(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_func_stop = ktime_get();
-}
-
-#else  /* CONFIG_DEBUG_FS */
-# define r2net_init_nst(a, b, c, d, e)
-# define r2net_set_nst_sock_time(a)
-# define r2net_set_nst_send_time(a)
-# define r2net_set_nst_status_time(a)
-# define r2net_set_nst_sock_container(a, b)
-# define r2net_set_nst_msg_id(a, b)
-# define r2net_set_sock_timer(a)
-# define r2net_set_data_ready_time(a)
-# define r2net_set_advance_start_time(a)
-# define r2net_set_advance_stop_time(a)
-# define r2net_set_func_start_time(a)
-# define r2net_set_func_stop_time(a)
-#endif /* CONFIG_DEBUG_FS */
-
-#ifdef CONFIG_RAMSTER_FS_STATS
-static ktime_t r2net_get_func_run_time(struct r2net_sock_container *sc)
-{
-	return ktime_sub(sc->sc_tv_func_stop, sc->sc_tv_func_start);
-}
-
-static void r2net_update_send_stats(struct r2net_send_tracking *nst,
-				    struct r2net_sock_container *sc)
-{
-	sc->sc_tv_status_total = ktime_add(sc->sc_tv_status_total,
-					   ktime_sub(ktime_get(),
-						     nst->st_status_time));
-	sc->sc_tv_send_total = ktime_add(sc->sc_tv_send_total,
-					 ktime_sub(nst->st_status_time,
-						   nst->st_send_time));
-	sc->sc_tv_acquiry_total = ktime_add(sc->sc_tv_acquiry_total,
-					    ktime_sub(nst->st_send_time,
-						      nst->st_sock_time));
-	sc->sc_send_count++;
-}
-
-static void r2net_update_recv_stats(struct r2net_sock_container *sc)
-{
-	sc->sc_tv_process_total = ktime_add(sc->sc_tv_process_total,
-					    r2net_get_func_run_time(sc));
-	sc->sc_recv_count++;
-}
-
-#else
-
-# define r2net_update_send_stats(a, b)
-
-# define r2net_update_recv_stats(sc)
-
-#endif /* CONFIG_RAMSTER_FS_STATS */
-
-static inline int r2net_reconnect_delay(void)
-{
-	return r2nm_single_cluster->cl_reconnect_delay_ms;
-}
-
-static inline int r2net_keepalive_delay(void)
-{
-	return r2nm_single_cluster->cl_keepalive_delay_ms;
-}
-
-static inline int r2net_idle_timeout(void)
-{
-	return r2nm_single_cluster->cl_idle_timeout_ms;
-}
-
-static inline int r2net_sys_err_to_errno(enum r2net_system_error err)
-{
-	int trans;
-	BUG_ON(err >= R2NET_ERR_MAX);
-	trans = r2net_sys_err_translations[err];
-
-	/* Just in case we mess up the translation table above */
-	BUG_ON(err != R2NET_ERR_NONE && trans == 0);
-	return trans;
-}
-
-struct r2net_node *r2net_nn_from_num(u8 node_num)
-{
-	BUG_ON(node_num >= ARRAY_SIZE(r2net_nodes));
-	return &r2net_nodes[node_num];
-}
-
-static u8 r2net_num_from_nn(struct r2net_node *nn)
-{
-	BUG_ON(nn == NULL);
-	return nn - r2net_nodes;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_prep_nsw(struct r2net_node *nn, struct r2net_status_wait *nsw)
-{
-	int ret = 0;
-
-	do {
-		if (!idr_pre_get(&nn->nn_status_idr, GFP_ATOMIC)) {
-			ret = -EAGAIN;
-			break;
-		}
-		spin_lock(&nn->nn_lock);
-		ret = idr_get_new(&nn->nn_status_idr, nsw, &nsw->ns_id);
-		if (ret == 0)
-			list_add_tail(&nsw->ns_node_item,
-				      &nn->nn_status_list);
-		spin_unlock(&nn->nn_lock);
-	} while (ret == -EAGAIN);
-
-	if (ret == 0)  {
-		init_waitqueue_head(&nsw->ns_wq);
-		nsw->ns_sys_status = R2NET_ERR_NONE;
-		nsw->ns_status = 0;
-	}
-
-	return ret;
-}
-
-static void r2net_complete_nsw_locked(struct r2net_node *nn,
-				      struct r2net_status_wait *nsw,
-				      enum r2net_system_error sys_status,
-				      s32 status)
-{
-	assert_spin_locked(&nn->nn_lock);
-
-	if (!list_empty(&nsw->ns_node_item)) {
-		list_del_init(&nsw->ns_node_item);
-		nsw->ns_sys_status = sys_status;
-		nsw->ns_status = status;
-		idr_remove(&nn->nn_status_idr, nsw->ns_id);
-		wake_up(&nsw->ns_wq);
-	}
-}
-
-static void r2net_complete_nsw(struct r2net_node *nn,
-			       struct r2net_status_wait *nsw,
-			       u64 id, enum r2net_system_error sys_status,
-			       s32 status)
-{
-	spin_lock(&nn->nn_lock);
-	if (nsw == NULL) {
-		if (id > INT_MAX)
-			goto out;
-
-		nsw = idr_find(&nn->nn_status_idr, id);
-		if (nsw == NULL)
-			goto out;
-	}
-
-	r2net_complete_nsw_locked(nn, nsw, sys_status, status);
-
-out:
-	spin_unlock(&nn->nn_lock);
-	return;
-}
-
-static void r2net_complete_nodes_nsw(struct r2net_node *nn)
-{
-	struct r2net_status_wait *nsw, *tmp;
-	unsigned int num_kills = 0;
-
-	assert_spin_locked(&nn->nn_lock);
-
-	list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) {
-		r2net_complete_nsw_locked(nn, nsw, R2NET_ERR_DIED, 0);
-		num_kills++;
-	}
-
-	mlog(0, "completed %d messages for node %u\n", num_kills,
-	     r2net_num_from_nn(nn));
-}
-
-static int r2net_nsw_completed(struct r2net_node *nn,
-			       struct r2net_status_wait *nsw)
-{
-	int completed;
-	spin_lock(&nn->nn_lock);
-	completed = list_empty(&nsw->ns_node_item);
-	spin_unlock(&nn->nn_lock);
-	return completed;
-}
-
-/* ------------------------------------------------------------ */
-
-static void sc_kref_release(struct kref *kref)
-{
-	struct r2net_sock_container *sc = container_of(kref,
-					struct r2net_sock_container, sc_kref);
-	BUG_ON(timer_pending(&sc->sc_idle_timeout));
-
-	sclog(sc, "releasing\n");
-
-	if (sc->sc_sock) {
-		sock_release(sc->sc_sock);
-		sc->sc_sock = NULL;
-	}
-
-	r2nm_undepend_item(&sc->sc_node->nd_item);
-	r2nm_node_put(sc->sc_node);
-	sc->sc_node = NULL;
-
-	r2net_debug_del_sc(sc);
-	kfree(sc);
-}
-
-static void sc_put(struct r2net_sock_container *sc)
-{
-	sclog(sc, "put\n");
-	kref_put(&sc->sc_kref, sc_kref_release);
-}
-static void sc_get(struct r2net_sock_container *sc)
-{
-	sclog(sc, "get\n");
-	kref_get(&sc->sc_kref);
-}
-static struct r2net_sock_container *sc_alloc(struct r2nm_node *node)
-{
-	struct r2net_sock_container *sc, *ret = NULL;
-	struct page *page = NULL;
-	int status = 0;
-
-	page = alloc_page(GFP_NOFS);
-	sc = kzalloc(sizeof(*sc), GFP_NOFS);
-	if (sc == NULL || page == NULL)
-		goto out;
-
-	kref_init(&sc->sc_kref);
-	r2nm_node_get(node);
-	sc->sc_node = node;
-
-	/* pin the node item of the remote node */
-	status = r2nm_depend_item(&node->nd_item);
-	if (status) {
-		mlog_errno(status);
-		r2nm_node_put(node);
-		goto out;
-	}
-	INIT_WORK(&sc->sc_connect_work, r2net_sc_connect_completed);
-	INIT_WORK(&sc->sc_rx_work, r2net_rx_until_empty);
-	INIT_WORK(&sc->sc_shutdown_work, r2net_shutdown_sc);
-	INIT_DELAYED_WORK(&sc->sc_keepalive_work, r2net_sc_send_keep_req);
-
-	init_timer(&sc->sc_idle_timeout);
-	sc->sc_idle_timeout.function = r2net_idle_timer;
-	sc->sc_idle_timeout.data = (unsigned long)sc;
-
-	sclog(sc, "alloced\n");
-
-	ret = sc;
-	sc->sc_page = page;
-	r2net_debug_add_sc(sc);
-	sc = NULL;
-	page = NULL;
-
-out:
-	if (page)
-		__free_page(page);
-	kfree(sc);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------ */
-
-static void r2net_sc_queue_work(struct r2net_sock_container *sc,
-				struct work_struct *work)
-{
-	sc_get(sc);
-	if (!queue_work(r2net_wq, work))
-		sc_put(sc);
-}
-static void r2net_sc_queue_delayed_work(struct r2net_sock_container *sc,
-					struct delayed_work *work,
-					int delay)
-{
-	sc_get(sc);
-	if (!queue_delayed_work(r2net_wq, work, delay))
-		sc_put(sc);
-}
-static void r2net_sc_cancel_delayed_work(struct r2net_sock_container *sc,
-					 struct delayed_work *work)
-{
-	if (cancel_delayed_work(work))
-		sc_put(sc);
-}
-
-static atomic_t r2net_connected_peers = ATOMIC_INIT(0);
-
-int r2net_num_connected_peers(void)
-{
-	return atomic_read(&r2net_connected_peers);
-}
-
-static void r2net_set_nn_state(struct r2net_node *nn,
-			       struct r2net_sock_container *sc,
-			       unsigned valid, int err)
-{
-	int was_valid = nn->nn_sc_valid;
-	int was_err = nn->nn_persistent_error;
-	struct r2net_sock_container *old_sc = nn->nn_sc;
-
-	assert_spin_locked(&nn->nn_lock);
-
-	if (old_sc && !sc)
-		atomic_dec(&r2net_connected_peers);
-	else if (!old_sc && sc)
-		atomic_inc(&r2net_connected_peers);
-
-	/* the node num comparison and single connect/accept path should stop
-	 * an non-null sc from being overwritten with another */
-	BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc);
-	mlog_bug_on_msg(err && valid, "err %d valid %u\n", err, valid);
-	mlog_bug_on_msg(valid && !sc, "valid %u sc %p\n", valid, sc);
-
-	if (was_valid && !valid && err == 0)
-		err = -ENOTCONN;
-
-	mlog(ML_CONN, "node %u sc: %p -> %p, valid %u -> %u, err %d -> %d\n",
-	     r2net_num_from_nn(nn), nn->nn_sc, sc, nn->nn_sc_valid, valid,
-	     nn->nn_persistent_error, err);
-
-	nn->nn_sc = sc;
-	nn->nn_sc_valid = valid ? 1 : 0;
-	nn->nn_persistent_error = err;
-
-	/* mirrors r2net_tx_can_proceed() */
-	if (nn->nn_persistent_error || nn->nn_sc_valid)
-		wake_up(&nn->nn_sc_wq);
-
-	if (!was_err && nn->nn_persistent_error) {
-		queue_delayed_work(r2net_wq, &nn->nn_still_up,
-				   msecs_to_jiffies(R2NET_QUORUM_DELAY_MS));
-	}
-
-	if (was_valid && !valid) {
-		printk(KERN_NOTICE "ramster: No longer connected to "
-		       SC_NODEF_FMT "\n",
-			old_sc->sc_node->nd_name, old_sc->sc_node->nd_num,
-			&old_sc->sc_node->nd_ipv4_address,
-			ntohs(old_sc->sc_node->nd_ipv4_port));
-		r2net_complete_nodes_nsw(nn);
-	}
-
-	if (!was_valid && valid) {
-		cancel_delayed_work(&nn->nn_connect_expired);
-		printk(KERN_NOTICE "ramster: %s " SC_NODEF_FMT "\n",
-		       r2nm_this_node() > sc->sc_node->nd_num ?
-		       "Connected to" : "Accepted connection from",
-		       sc->sc_node->nd_name, sc->sc_node->nd_num,
-			&sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port));
-	}
-
-	/* trigger the connecting worker func as long as we're not valid,
-	 * it will back off if it shouldn't connect.  This can be called
-	 * from node config teardown and so needs to be careful about
-	 * the work queue actually being up. */
-	if (!valid && r2net_wq) {
-		unsigned long delay;
-		/* delay if we're within a RECONNECT_DELAY of the
-		 * last attempt */
-		delay = (nn->nn_last_connect_attempt +
-			 msecs_to_jiffies(r2net_reconnect_delay()))
-			- jiffies;
-		if (delay > msecs_to_jiffies(r2net_reconnect_delay()))
-			delay = 0;
-		mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay);
-		queue_delayed_work(r2net_wq, &nn->nn_connect_work, delay);
-
-		/*
-		 * Delay the expired work after idle timeout.
-		 *
-		 * We might have lots of failed connection attempts that run
-		 * through here but we only cancel the connect_expired work when
-		 * a connection attempt succeeds.  So only the first enqueue of
-		 * the connect_expired work will do anything.  The rest will see
-		 * that it's already queued and do nothing.
-		 */
-		delay += msecs_to_jiffies(r2net_idle_timeout());
-		queue_delayed_work(r2net_wq, &nn->nn_connect_expired, delay);
-	}
-
-	/* keep track of the nn's sc ref for the caller */
-	if ((old_sc == NULL) && sc)
-		sc_get(sc);
-	if (old_sc && (old_sc != sc)) {
-		r2net_sc_queue_work(old_sc, &old_sc->sc_shutdown_work);
-		sc_put(old_sc);
-	}
-}
-
-/* see r2net_register_callbacks() */
-static void r2net_data_ready(struct sock *sk, int bytes)
-{
-	void (*ready)(struct sock *sk, int bytes);
-
-	read_lock(&sk->sk_callback_lock);
-	if (sk->sk_user_data) {
-		struct r2net_sock_container *sc = sk->sk_user_data;
-		sclog(sc, "data_ready hit\n");
-		r2net_set_data_ready_time(sc);
-		r2net_sc_queue_work(sc, &sc->sc_rx_work);
-		ready = sc->sc_data_ready;
-	} else {
-		ready = sk->sk_data_ready;
-	}
-	read_unlock(&sk->sk_callback_lock);
-
-	ready(sk, bytes);
-}
-
-/* see r2net_register_callbacks() */
-static void r2net_state_change(struct sock *sk)
-{
-	void (*state_change)(struct sock *sk);
-	struct r2net_sock_container *sc;
-
-	read_lock(&sk->sk_callback_lock);
-	sc = sk->sk_user_data;
-	if (sc == NULL) {
-		state_change = sk->sk_state_change;
-		goto out;
-	}
-
-	sclog(sc, "state_change to %d\n", sk->sk_state);
-
-	state_change = sc->sc_state_change;
-
-	switch (sk->sk_state) {
-
-	/* ignore connecting sockets as they make progress */
-	case TCP_SYN_SENT:
-	case TCP_SYN_RECV:
-		break;
-	case TCP_ESTABLISHED:
-		r2net_sc_queue_work(sc, &sc->sc_connect_work);
-		break;
-	default:
-		printk(KERN_INFO "ramster: Connection to "
-			SC_NODEF_FMT " shutdown, state %d\n",
-			sc->sc_node->nd_name, sc->sc_node->nd_num,
-			&sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port), sk->sk_state);
-		r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
-		break;
-
-	}
-out:
-	read_unlock(&sk->sk_callback_lock);
-	state_change(sk);
-}
-
-/*
- * we register callbacks so we can queue work on events before calling
- * the original callbacks.  our callbacks are careful to test user_data
- * to discover when they've reaced with r2net_unregister_callbacks().
- */
-static void r2net_register_callbacks(struct sock *sk,
-				     struct r2net_sock_container *sc)
-{
-	write_lock_bh(&sk->sk_callback_lock);
-
-	/* accepted sockets inherit the old listen socket data ready */
-	if (sk->sk_data_ready == r2net_listen_data_ready) {
-		sk->sk_data_ready = sk->sk_user_data;
-		sk->sk_user_data = NULL;
-	}
-
-	BUG_ON(sk->sk_user_data != NULL);
-	sk->sk_user_data = sc;
-	sc_get(sc);
-
-	sc->sc_data_ready = sk->sk_data_ready;
-	sc->sc_state_change = sk->sk_state_change;
-	sk->sk_data_ready = r2net_data_ready;
-	sk->sk_state_change = r2net_state_change;
-
-	mutex_init(&sc->sc_send_lock);
-
-	write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static int r2net_unregister_callbacks(struct sock *sk,
-					struct r2net_sock_container *sc)
-{
-	int ret = 0;
-
-	write_lock_bh(&sk->sk_callback_lock);
-	if (sk->sk_user_data == sc) {
-		ret = 1;
-		sk->sk_user_data = NULL;
-		sk->sk_data_ready = sc->sc_data_ready;
-		sk->sk_state_change = sc->sc_state_change;
-	}
-	write_unlock_bh(&sk->sk_callback_lock);
-
-	return ret;
-}
-
-/*
- * this is a little helper that is called by callers who have seen a problem
- * with an sc and want to detach it from the nn if someone already hasn't beat
- * them to it.  if an error is given then the shutdown will be persistent
- * and pending transmits will be canceled.
- */
-static void r2net_ensure_shutdown(struct r2net_node *nn,
-					struct r2net_sock_container *sc,
-				   int err)
-{
-	spin_lock(&nn->nn_lock);
-	if (nn->nn_sc == sc)
-		r2net_set_nn_state(nn, NULL, 0, err);
-	spin_unlock(&nn->nn_lock);
-}
-
-/*
- * This work queue function performs the blocking parts of socket shutdown.  A
- * few paths lead here.  set_nn_state will trigger this callback if it sees an
- * sc detached from the nn.  state_change will also trigger this callback
- * directly when it sees errors.  In that case we need to call set_nn_state
- * ourselves as state_change couldn't get the nn_lock and call set_nn_state
- * itself.
- */
-static void r2net_shutdown_sc(struct work_struct *work)
-{
-	struct r2net_sock_container *sc =
-		container_of(work, struct r2net_sock_container,
-			     sc_shutdown_work);
-	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-
-	sclog(sc, "shutting down\n");
-
-	/* drop the callbacks ref and call shutdown only once */
-	if (r2net_unregister_callbacks(sc->sc_sock->sk, sc)) {
-		/* we shouldn't flush as we're in the thread, the
-		 * races with pending sc work structs are harmless */
-		del_timer_sync(&sc->sc_idle_timeout);
-		r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
-		sc_put(sc);
-		kernel_sock_shutdown(sc->sc_sock, SHUT_RDWR);
-	}
-
-	/* not fatal so failed connects before the other guy has our
-	 * heartbeat can be retried */
-	r2net_ensure_shutdown(nn, sc, 0);
-	sc_put(sc);
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_handler_cmp(struct r2net_msg_handler *nmh, u32 msg_type,
-			     u32 key)
-{
-	int ret = memcmp(&nmh->nh_key, &key, sizeof(key));
-
-	if (ret == 0)
-		ret = memcmp(&nmh->nh_msg_type, &msg_type, sizeof(msg_type));
-
-	return ret;
-}
-
-static struct r2net_msg_handler *
-r2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p,
-				struct rb_node **ret_parent)
-{
-	struct rb_node **p = &r2net_handler_tree.rb_node;
-	struct rb_node *parent = NULL;
-	struct r2net_msg_handler *nmh, *ret = NULL;
-	int cmp;
-
-	while (*p) {
-		parent = *p;
-		nmh = rb_entry(parent, struct r2net_msg_handler, nh_node);
-		cmp = r2net_handler_cmp(nmh, msg_type, key);
-
-		if (cmp < 0)
-			p = &(*p)->rb_left;
-		else if (cmp > 0)
-			p = &(*p)->rb_right;
-		else {
-			ret = nmh;
-			break;
-		}
-	}
-
-	if (ret_p != NULL)
-		*ret_p = p;
-	if (ret_parent != NULL)
-		*ret_parent = parent;
-
-	return ret;
-}
-
-static void r2net_handler_kref_release(struct kref *kref)
-{
-	struct r2net_msg_handler *nmh;
-	nmh = container_of(kref, struct r2net_msg_handler, nh_kref);
-
-	kfree(nmh);
-}
-
-static void r2net_handler_put(struct r2net_msg_handler *nmh)
-{
-	kref_put(&nmh->nh_kref, r2net_handler_kref_release);
-}
-
-/* max_len is protection for the handler func.  incoming messages won't
- * be given to the handler if their payload is longer than the max. */
-int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
-			   r2net_msg_handler_func *func, void *data,
-			   r2net_post_msg_handler_func *post_func,
-			   struct list_head *unreg_list)
-{
-	struct r2net_msg_handler *nmh = NULL;
-	struct rb_node **p, *parent;
-	int ret = 0;
-
-	if (max_len > R2NET_MAX_PAYLOAD_BYTES) {
-		mlog(0, "max_len for message handler out of range: %u\n",
-			max_len);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (!msg_type) {
-		mlog(0, "no message type provided: %u, %p\n", msg_type, func);
-		ret = -EINVAL;
-		goto out;
-
-	}
-	if (!func) {
-		mlog(0, "no message handler provided: %u, %p\n",
-		       msg_type, func);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	nmh = kzalloc(sizeof(struct r2net_msg_handler), GFP_NOFS);
-	if (nmh == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	nmh->nh_func = func;
-	nmh->nh_func_data = data;
-	nmh->nh_post_func = post_func;
-	nmh->nh_msg_type = msg_type;
-	nmh->nh_max_len = max_len;
-	nmh->nh_key = key;
-	/* the tree and list get this ref.. they're both removed in
-	 * unregister when this ref is dropped */
-	kref_init(&nmh->nh_kref);
-	INIT_LIST_HEAD(&nmh->nh_unregister_item);
-
-	write_lock(&r2net_handler_lock);
-	if (r2net_handler_tree_lookup(msg_type, key, &p, &parent))
-		ret = -EEXIST;
-	else {
-		rb_link_node(&nmh->nh_node, parent, p);
-		rb_insert_color(&nmh->nh_node, &r2net_handler_tree);
-		list_add_tail(&nmh->nh_unregister_item, unreg_list);
-
-		mlog(ML_TCP, "registered handler func %p type %u key %08x\n",
-		     func, msg_type, key);
-		/* we've had some trouble with handlers seemingly vanishing. */
-		mlog_bug_on_msg(r2net_handler_tree_lookup(msg_type, key, &p,
-							  &parent) == NULL,
-				"couldn't find handler we *just* registered "
-				"for type %u key %08x\n", msg_type, key);
-	}
-	write_unlock(&r2net_handler_lock);
-	if (ret)
-		goto out;
-
-out:
-	if (ret)
-		kfree(nmh);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(r2net_register_handler);
-
-void r2net_unregister_handler_list(struct list_head *list)
-{
-	struct r2net_msg_handler *nmh, *n;
-
-	write_lock(&r2net_handler_lock);
-	list_for_each_entry_safe(nmh, n, list, nh_unregister_item) {
-		mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n",
-		     nmh->nh_func, nmh->nh_msg_type, nmh->nh_key);
-		rb_erase(&nmh->nh_node, &r2net_handler_tree);
-		list_del_init(&nmh->nh_unregister_item);
-		kref_put(&nmh->nh_kref, r2net_handler_kref_release);
-	}
-	write_unlock(&r2net_handler_lock);
-}
-EXPORT_SYMBOL_GPL(r2net_unregister_handler_list);
-
-static struct r2net_msg_handler *r2net_handler_get(u32 msg_type, u32 key)
-{
-	struct r2net_msg_handler *nmh;
-
-	read_lock(&r2net_handler_lock);
-	nmh = r2net_handler_tree_lookup(msg_type, key, NULL, NULL);
-	if (nmh)
-		kref_get(&nmh->nh_kref);
-	read_unlock(&r2net_handler_lock);
-
-	return nmh;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
-{
-	int ret;
-	mm_segment_t oldfs;
-	struct kvec vec = {
-		.iov_len = len,
-		.iov_base = data,
-	};
-	struct msghdr msg = {
-		.msg_iovlen = 1,
-		.msg_iov = (struct iovec *)&vec,
-		.msg_flags = MSG_DONTWAIT,
-	};
-
-	oldfs = get_fs();
-	set_fs(get_ds());
-	ret = sock_recvmsg(sock, &msg, len, msg.msg_flags);
-	set_fs(oldfs);
-
-	return ret;
-}
-
-static int r2net_send_tcp_msg(struct socket *sock, struct kvec *vec,
-			      size_t veclen, size_t total)
-{
-	int ret;
-	mm_segment_t oldfs;
-	struct msghdr msg = {
-		.msg_iov = (struct iovec *)vec,
-		.msg_iovlen = veclen,
-	};
-
-	if (sock == NULL) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	oldfs = get_fs();
-	set_fs(get_ds());
-	ret = sock_sendmsg(sock, &msg, total);
-	set_fs(oldfs);
-	if (ret != total) {
-		mlog(ML_ERROR, "sendmsg returned %d instead of %zu\n", ret,
-		     total);
-		if (ret >= 0)
-			ret = -EPIPE; /* should be smarter, I bet */
-		goto out;
-	}
-
-	ret = 0;
-out:
-	if (ret < 0)
-		mlog(0, "returning error: %d\n", ret);
-	return ret;
-}
-
-static void r2net_sendpage(struct r2net_sock_container *sc,
-			   void *kmalloced_virt,
-			   size_t size)
-{
-	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-	ssize_t ret;
-
-	while (1) {
-		mutex_lock(&sc->sc_send_lock);
-		ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
-					virt_to_page(kmalloced_virt),
-					(long)kmalloced_virt & ~PAGE_MASK,
-					size, MSG_DONTWAIT);
-		mutex_unlock(&sc->sc_send_lock);
-		if (ret == size)
-			break;
-		if (ret == (ssize_t)-EAGAIN) {
-			mlog(0, "sendpage of size %zu to " SC_NODEF_FMT
-			     " returned EAGAIN\n", size, sc->sc_node->nd_name,
-				sc->sc_node->nd_num,
-				&sc->sc_node->nd_ipv4_address,
-				ntohs(sc->sc_node->nd_ipv4_port));
-			cond_resched();
-			continue;
-		}
-		mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT
-		     " failed with %zd\n", size, sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port), ret);
-		r2net_ensure_shutdown(nn, sc, 0);
-		break;
-	}
-}
-
-static void r2net_init_msg(struct r2net_msg *msg, u16 data_len,
-				u16 msg_type, u32 key)
-{
-	memset(msg, 0, sizeof(struct r2net_msg));
-	msg->magic = cpu_to_be16(R2NET_MSG_MAGIC);
-	msg->data_len = cpu_to_be16(data_len);
-	msg->msg_type = cpu_to_be16(msg_type);
-	msg->sys_status = cpu_to_be32(R2NET_ERR_NONE);
-	msg->status = 0;
-	msg->key = cpu_to_be32(key);
-}
-
-static int r2net_tx_can_proceed(struct r2net_node *nn,
-				struct r2net_sock_container **sc_ret,
-				int *error)
-{
-	int ret = 0;
-
-	spin_lock(&nn->nn_lock);
-	if (nn->nn_persistent_error) {
-		ret = 1;
-		*sc_ret = NULL;
-		*error = nn->nn_persistent_error;
-	} else if (nn->nn_sc_valid) {
-		kref_get(&nn->nn_sc->sc_kref);
-
-		ret = 1;
-		*sc_ret = nn->nn_sc;
-		*error = 0;
-	}
-	spin_unlock(&nn->nn_lock);
-
-	return ret;
-}
-
-/* Get a map of all nodes to which this node is currently connected to */
-void r2net_fill_node_map(unsigned long *map, unsigned bytes)
-{
-	struct r2net_sock_container *sc;
-	int node, ret;
-
-	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
-
-	memset(map, 0, bytes);
-	for (node = 0; node < R2NM_MAX_NODES; ++node) {
-		r2net_tx_can_proceed(r2net_nn_from_num(node), &sc, &ret);
-		if (!ret) {
-			set_bit(node, map);
-			sc_put(sc);
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(r2net_fill_node_map);
-
-int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
-			   size_t caller_veclen, u8 target_node, int *status)
-{
-	int ret = 0;
-	struct r2net_msg *msg = NULL;
-	size_t veclen, caller_bytes = 0;
-	struct kvec *vec = NULL;
-	struct r2net_sock_container *sc = NULL;
-	struct r2net_node *nn = r2net_nn_from_num(target_node);
-	struct r2net_status_wait nsw = {
-		.ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item),
-	};
-	struct r2net_send_tracking nst;
-
-	/* this may be a general bug fix */
-	init_waitqueue_head(&nsw.ns_wq);
-
-	r2net_init_nst(&nst, msg_type, key, current, target_node);
-
-	if (r2net_wq == NULL) {
-		mlog(0, "attempt to tx without r2netd running\n");
-		ret = -ESRCH;
-		goto out;
-	}
-
-	if (caller_veclen == 0) {
-		mlog(0, "bad kvec array length\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	caller_bytes = iov_length((struct iovec *)caller_vec, caller_veclen);
-	if (caller_bytes > R2NET_MAX_PAYLOAD_BYTES) {
-		mlog(0, "total payload len %zu too large\n", caller_bytes);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (target_node == r2nm_this_node()) {
-		ret = -ELOOP;
-		goto out;
-	}
-
-	r2net_debug_add_nst(&nst);
-
-	r2net_set_nst_sock_time(&nst);
-
-	wait_event(nn->nn_sc_wq, r2net_tx_can_proceed(nn, &sc, &ret));
-	if (ret)
-		goto out;
-
-	r2net_set_nst_sock_container(&nst, sc);
-
-	veclen = caller_veclen + 1;
-	vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC);
-	if (vec == NULL) {
-		mlog(0, "failed to %zu element kvec!\n", veclen);
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	msg = kmalloc(sizeof(struct r2net_msg), GFP_ATOMIC);
-	if (!msg) {
-		mlog(0, "failed to allocate a r2net_msg!\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	r2net_init_msg(msg, caller_bytes, msg_type, key);
-
-	vec[0].iov_len = sizeof(struct r2net_msg);
-	vec[0].iov_base = msg;
-	memcpy(&vec[1], caller_vec, caller_veclen * sizeof(struct kvec));
-
-	ret = r2net_prep_nsw(nn, &nsw);
-	if (ret)
-		goto out;
-
-	msg->msg_num = cpu_to_be32(nsw.ns_id);
-	r2net_set_nst_msg_id(&nst, nsw.ns_id);
-
-	r2net_set_nst_send_time(&nst);
-
-	/* finally, convert the message header to network byte-order
-	 * and send */
-	mutex_lock(&sc->sc_send_lock);
-	ret = r2net_send_tcp_msg(sc->sc_sock, vec, veclen,
-				 sizeof(struct r2net_msg) + caller_bytes);
-	mutex_unlock(&sc->sc_send_lock);
-	msglog(msg, "sending returned %d\n", ret);
-	if (ret < 0) {
-		mlog(0, "error returned from r2net_send_tcp_msg=%d\n", ret);
-		goto out;
-	}
-
-	/* wait on other node's handler */
-	r2net_set_nst_status_time(&nst);
-	wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw));
-
-	r2net_update_send_stats(&nst, sc);
-
-	/* Note that we avoid overwriting the callers status return
-	 * variable if a system error was reported on the other
-	 * side. Callers beware. */
-	ret = r2net_sys_err_to_errno(nsw.ns_sys_status);
-	if (status && !ret)
-		*status = nsw.ns_status;
-
-	mlog(0, "woken, returning system status %d, user status %d\n",
-	     ret, nsw.ns_status);
-out:
-	r2net_debug_del_nst(&nst); /* must be before dropping sc and node */
-	if (sc)
-		sc_put(sc);
-	kfree(vec);
-	kfree(msg);
-	r2net_complete_nsw(nn, &nsw, 0, 0, 0);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(r2net_send_message_vec);
-
-int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
-		       u8 target_node, int *status)
-{
-	struct kvec vec = {
-		.iov_base = data,
-		.iov_len = len,
-	};
-	return r2net_send_message_vec(msg_type, key, &vec, 1,
-				      target_node, status);
-}
-EXPORT_SYMBOL_GPL(r2net_send_message);
-
-static int r2net_send_status_magic(struct socket *sock, struct r2net_msg *hdr,
-				   enum r2net_system_error syserr, int err)
-{
-	struct kvec vec = {
-		.iov_base = hdr,
-		.iov_len = sizeof(struct r2net_msg),
-	};
-
-	BUG_ON(syserr >= R2NET_ERR_MAX);
-
-	/* leave other fields intact from the incoming message, msg_num
-	 * in particular */
-	hdr->sys_status = cpu_to_be32(syserr);
-	hdr->status = cpu_to_be32(err);
-	/* twiddle the magic */
-	hdr->magic = cpu_to_be16(R2NET_MSG_STATUS_MAGIC);
-	hdr->data_len = 0;
-
-	msglog(hdr, "about to send status magic %d\n", err);
-	/* hdr has been in host byteorder this whole time */
-	return r2net_send_tcp_msg(sock, &vec, 1, sizeof(struct r2net_msg));
-}
-
-/*
- * "data magic" is a long version of "status magic" where the message
- * payload actually contains data to be passed in reply to certain messages
- */
-static int r2net_send_data_magic(struct r2net_sock_container *sc,
-			  struct r2net_msg *hdr,
-			  void *data, size_t data_len,
-			  enum r2net_system_error syserr, int err)
-{
-	struct kvec vec[2];
-	int ret;
-
-	vec[0].iov_base = hdr;
-	vec[0].iov_len = sizeof(struct r2net_msg);
-	vec[1].iov_base = data;
-	vec[1].iov_len = data_len;
-
-	BUG_ON(syserr >= R2NET_ERR_MAX);
-
-	/* leave other fields intact from the incoming message, msg_num
-	 * in particular */
-	hdr->sys_status = cpu_to_be32(syserr);
-	hdr->status = cpu_to_be32(err);
-	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);  /* twiddle magic */
-	hdr->data_len = cpu_to_be16(data_len);
-
-	msglog(hdr, "about to send data magic %d\n", err);
-	/* hdr has been in host byteorder this whole time */
-	ret = r2net_send_tcp_msg(sc->sc_sock, vec, 2,
-			sizeof(struct r2net_msg) + data_len);
-	return ret;
-}
-
-/*
- * called by a message handler to convert an otherwise normal reply
- * message into a "data magic" message
- */
-void r2net_force_data_magic(struct r2net_msg *hdr, u16 msgtype, u32 msgkey)
-{
-	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);
-	hdr->msg_type = cpu_to_be16(msgtype);
-	hdr->key = cpu_to_be32(msgkey);
-}
-
-/* this returns -errno if the header was unknown or too large, etc.
- * after this is called the buffer us reused for the next message */
-static int r2net_process_message(struct r2net_sock_container *sc,
-				 struct r2net_msg *hdr)
-{
-	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-	int ret = 0, handler_status;
-	enum  r2net_system_error syserr;
-	struct r2net_msg_handler *nmh = NULL;
-	void *ret_data = NULL;
-	int data_magic = 0;
-
-	msglog(hdr, "processing message\n");
-
-	r2net_sc_postpone_idle(sc);
-
-	switch (be16_to_cpu(hdr->magic)) {
-
-	case R2NET_MSG_STATUS_MAGIC:
-		/* special type for returning message status */
-		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
-						be32_to_cpu(hdr->sys_status),
-						be32_to_cpu(hdr->status));
-		goto out;
-	case R2NET_MSG_KEEP_REQ_MAGIC:
-		r2net_sendpage(sc, r2net_keep_resp, sizeof(*r2net_keep_resp));
-		goto out;
-	case R2NET_MSG_KEEP_RESP_MAGIC:
-		goto out;
-	case R2NET_MSG_MAGIC:
-		break;
-	case R2NET_MSG_DATA_MAGIC:
-		/*
-		 * unlike a normal status magic, a data magic DOES
-		 * (MUST) have a handler, so the control flow is
-		 * a little funky here as a result
-		 */
-		data_magic = 1;
-		break;
-	default:
-		msglog(hdr, "bad magic\n");
-		ret = -EINVAL;
-		goto out;
-		break;
-	}
-
-	/* find a handler for it */
-	handler_status = 0;
-	nmh = r2net_handler_get(be16_to_cpu(hdr->msg_type),
-				be32_to_cpu(hdr->key));
-	if (!nmh) {
-		mlog(ML_TCP, "couldn't find handler for type %u key %08x\n",
-		     be16_to_cpu(hdr->msg_type), be32_to_cpu(hdr->key));
-		syserr = R2NET_ERR_NO_HNDLR;
-		goto out_respond;
-	}
-
-	syserr = R2NET_ERR_NONE;
-
-	if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len)
-		syserr = R2NET_ERR_OVERFLOW;
-
-	if (syserr != R2NET_ERR_NONE)
-		goto out_respond;
-
-	r2net_set_func_start_time(sc);
-	sc->sc_msg_key = be32_to_cpu(hdr->key);
-	sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
-	handler_status = (nmh->nh_func)(hdr, sizeof(struct r2net_msg) +
-					     be16_to_cpu(hdr->data_len),
-					nmh->nh_func_data, &ret_data);
-	if (data_magic) {
-		/*
-		 * handler handled data sent in reply to request
-		 * so complete the transaction
-		 */
-		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
-			be32_to_cpu(hdr->sys_status), handler_status);
-		goto out;
-	}
-	/*
-	 * handler changed magic to DATA_MAGIC to reply to request for data,
-	 * implies ret_data points to data to return and handler_status
-	 * is the number of bytes of data
-	 */
-	if (be16_to_cpu(hdr->magic) == R2NET_MSG_DATA_MAGIC) {
-		ret = r2net_send_data_magic(sc, hdr,
-						ret_data, handler_status,
-						syserr, 0);
-		hdr = NULL;
-		mlog(0, "sending data reply %d, syserr %d returned %d\n",
-			handler_status, syserr, ret);
-		r2net_set_func_stop_time(sc);
-
-		r2net_update_recv_stats(sc);
-		goto out;
-	}
-	r2net_set_func_stop_time(sc);
-
-	r2net_update_recv_stats(sc);
-
-out_respond:
-	/* this destroys the hdr, so don't use it after this */
-	mutex_lock(&sc->sc_send_lock);
-	ret = r2net_send_status_magic(sc->sc_sock, hdr, syserr,
-				      handler_status);
-	mutex_unlock(&sc->sc_send_lock);
-	hdr = NULL;
-	mlog(0, "sending handler status %d, syserr %d returned %d\n",
-	     handler_status, syserr, ret);
-
-	if (nmh) {
-		BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
-		if (nmh->nh_post_func)
-			(nmh->nh_post_func)(handler_status, nmh->nh_func_data,
-					    ret_data);
-	}
-
-out:
-	if (nmh)
-		r2net_handler_put(nmh);
-	return ret;
-}
-
-static int r2net_check_handshake(struct r2net_sock_container *sc)
-{
-	struct r2net_handshake *hand = page_address(sc->sc_page);
-	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-
-	if (hand->protocol_version != cpu_to_be64(R2NET_PROTOCOL_VERSION)) {
-		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " Advertised net "
-		       "protocol version %llu but %llu is required. "
-		       "Disconnecting.\n", sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port),
-		       (unsigned long long)be64_to_cpu(hand->protocol_version),
-		       R2NET_PROTOCOL_VERSION);
-
-		/* don't bother reconnecting if its the wrong version. */
-		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
-		return -1;
-	}
-
-	/*
-	 * Ensure timeouts are consistent with other nodes, otherwise
-	 * we can end up with one node thinking that the other must be down,
-	 * but isn't. This can ultimately cause corruption.
-	 */
-	if (be32_to_cpu(hand->r2net_idle_timeout_ms) !=
-				r2net_idle_timeout()) {
-		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a network "
-		       "idle timeout of %u ms, but we use %u ms locally. "
-		       "Disconnecting.\n", sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port),
-		       be32_to_cpu(hand->r2net_idle_timeout_ms),
-		       r2net_idle_timeout());
-		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
-		return -1;
-	}
-
-	if (be32_to_cpu(hand->r2net_keepalive_delay_ms) !=
-			r2net_keepalive_delay()) {
-		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a keepalive "
-		       "delay of %u ms, but we use %u ms locally. "
-		       "Disconnecting.\n", sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port),
-		       be32_to_cpu(hand->r2net_keepalive_delay_ms),
-		       r2net_keepalive_delay());
-		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
-		return -1;
-	}
-
-	if (be32_to_cpu(hand->r2hb_heartbeat_timeout_ms) !=
-			R2HB_MAX_WRITE_TIMEOUT_MS) {
-		printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a heartbeat "
-		       "timeout of %u ms, but we use %u ms locally. "
-		       "Disconnecting.\n", sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port),
-		       be32_to_cpu(hand->r2hb_heartbeat_timeout_ms),
-		       R2HB_MAX_WRITE_TIMEOUT_MS);
-		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
-		return -1;
-	}
-
-	sc->sc_handshake_ok = 1;
-
-	spin_lock(&nn->nn_lock);
-	/* set valid and queue the idle timers only if it hasn't been
-	 * shut down already */
-	if (nn->nn_sc == sc) {
-		r2net_sc_reset_idle_timer(sc);
-		atomic_set(&nn->nn_timeout, 0);
-		r2net_set_nn_state(nn, sc, 1, 0);
-	}
-	spin_unlock(&nn->nn_lock);
-
-	/* shift everything up as though it wasn't there */
-	sc->sc_page_off -= sizeof(struct r2net_handshake);
-	if (sc->sc_page_off)
-		memmove(hand, hand + 1, sc->sc_page_off);
-
-	return 0;
-}
-
-/* this demuxes the queued rx bytes into header or payload bits and calls
- * handlers as each full message is read off the socket.  it returns -error,
- * == 0 eof, or > 0 for progress made.*/
-static int r2net_advance_rx(struct r2net_sock_container *sc)
-{
-	struct r2net_msg *hdr;
-	int ret = 0;
-	void *data;
-	size_t datalen;
-
-	sclog(sc, "receiving\n");
-	r2net_set_advance_start_time(sc);
-
-	if (unlikely(sc->sc_handshake_ok == 0)) {
-		if (sc->sc_page_off < sizeof(struct r2net_handshake)) {
-			data = page_address(sc->sc_page) + sc->sc_page_off;
-			datalen = sizeof(struct r2net_handshake) -
-							sc->sc_page_off;
-			ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
-			if (ret > 0)
-				sc->sc_page_off += ret;
-		}
-
-		if (sc->sc_page_off == sizeof(struct r2net_handshake)) {
-			r2net_check_handshake(sc);
-			if (unlikely(sc->sc_handshake_ok == 0))
-				ret = -EPROTO;
-		}
-		goto out;
-	}
-
-	/* do we need more header? */
-	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
-		data = page_address(sc->sc_page) + sc->sc_page_off;
-		datalen = sizeof(struct r2net_msg) - sc->sc_page_off;
-		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
-		if (ret > 0) {
-			sc->sc_page_off += ret;
-			/* only swab incoming here.. we can
-			 * only get here once as we cross from
-			 * being under to over */
-			if (sc->sc_page_off == sizeof(struct r2net_msg)) {
-				hdr = page_address(sc->sc_page);
-				if (be16_to_cpu(hdr->data_len) >
-				    R2NET_MAX_PAYLOAD_BYTES)
-					ret = -EOVERFLOW;
-			}
-		}
-		if (ret <= 0)
-			goto out;
-	}
-
-	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
-		/* oof, still don't have a header */
-		goto out;
-	}
-
-	/* this was swabbed above when we first read it */
-	hdr = page_address(sc->sc_page);
-
-	msglog(hdr, "at page_off %zu\n", sc->sc_page_off);
-
-	/* do we need more payload? */
-	if (sc->sc_page_off - sizeof(struct r2net_msg) <
-					be16_to_cpu(hdr->data_len)) {
-		/* need more payload */
-		data = page_address(sc->sc_page) + sc->sc_page_off;
-		datalen = (sizeof(struct r2net_msg) +
-				be16_to_cpu(hdr->data_len)) -
-				sc->sc_page_off;
-		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
-		if (ret > 0)
-			sc->sc_page_off += ret;
-		if (ret <= 0)
-			goto out;
-	}
-
-	if (sc->sc_page_off - sizeof(struct r2net_msg) ==
-						be16_to_cpu(hdr->data_len)) {
-		/* we can only get here once, the first time we read
-		 * the payload.. so set ret to progress if the handler
-		 * works out. after calling this the message is toast */
-		ret = r2net_process_message(sc, hdr);
-		if (ret == 0)
-			ret = 1;
-		sc->sc_page_off = 0;
-	}
-
-out:
-	sclog(sc, "ret = %d\n", ret);
-	r2net_set_advance_stop_time(sc);
-	return ret;
-}
-
-/* this work func is triggerd by data ready.  it reads until it can read no
- * more.  it interprets 0, eof, as fatal.  if data_ready hits while we're doing
- * our work the work struct will be marked and we'll be called again. */
-static void r2net_rx_until_empty(struct work_struct *work)
-{
-	struct r2net_sock_container *sc =
-		container_of(work, struct r2net_sock_container, sc_rx_work);
-	int ret;
-
-	do {
-		ret = r2net_advance_rx(sc);
-	} while (ret > 0);
-
-	if (ret <= 0 && ret != -EAGAIN) {
-		struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-		sclog(sc, "saw error %d, closing\n", ret);
-		/* not permanent so read failed handshake can retry */
-		r2net_ensure_shutdown(nn, sc, 0);
-	}
-
-	sc_put(sc);
-}
-
-static int r2net_set_nodelay(struct socket *sock)
-{
-	int ret, val = 1;
-	mm_segment_t oldfs;
-
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-
-	/*
-	 * Dear unsuspecting programmer,
-	 *
-	 * Don't use sock_setsockopt() for SOL_TCP.  It doesn't check its level
-	 * argument and assumes SOL_SOCKET so, say, your TCP_NODELAY will
-	 * silently turn into SO_DEBUG.
-	 *
-	 * Yours,
-	 * Keeper of hilariously fragile interfaces.
-	 */
-	ret = sock->ops->setsockopt(sock, SOL_TCP, TCP_NODELAY,
-				    (char __user *)&val, sizeof(val));
-
-	set_fs(oldfs);
-	return ret;
-}
-
-static void r2net_initialize_handshake(void)
-{
-	r2net_hand->r2hb_heartbeat_timeout_ms = cpu_to_be32(
-		R2HB_MAX_WRITE_TIMEOUT_MS);
-	r2net_hand->r2net_idle_timeout_ms = cpu_to_be32(r2net_idle_timeout());
-	r2net_hand->r2net_keepalive_delay_ms = cpu_to_be32(
-		r2net_keepalive_delay());
-	r2net_hand->r2net_reconnect_delay_ms = cpu_to_be32(
-		r2net_reconnect_delay());
-}
-
-/* ------------------------------------------------------------ */
-
-/* called when a connect completes and after a sock is accepted.  the
- * rx path will see the response and mark the sc valid */
-static void r2net_sc_connect_completed(struct work_struct *work)
-{
-	struct r2net_sock_container *sc =
-			container_of(work, struct r2net_sock_container,
-			     sc_connect_work);
-
-	mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n",
-		(unsigned long long)R2NET_PROTOCOL_VERSION,
-		(unsigned long long)be64_to_cpu(r2net_hand->connector_id));
-
-	r2net_initialize_handshake();
-	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
-	sc_put(sc);
-}
-
-/* this is called as a work_struct func. */
-static void r2net_sc_send_keep_req(struct work_struct *work)
-{
-	struct r2net_sock_container *sc =
-		container_of(work, struct r2net_sock_container,
-			     sc_keepalive_work.work);
-
-	r2net_sendpage(sc, r2net_keep_req, sizeof(*r2net_keep_req));
-	sc_put(sc);
-}
-
-/* socket shutdown does a del_timer_sync against this as it tears down.
- * we can't start this timer until we've got to the point in sc buildup
- * where shutdown is going to be involved */
-static void r2net_idle_timer(unsigned long data)
-{
-	struct r2net_sock_container *sc = (struct r2net_sock_container *)data;
-#ifdef CONFIG_DEBUG_FS
-	unsigned long msecs = ktime_to_ms(ktime_get()) -
-		ktime_to_ms(sc->sc_tv_timer);
-#else
-	unsigned long msecs = r2net_idle_timeout();
-#endif
-
-	printk(KERN_NOTICE "ramster: Connection to " SC_NODEF_FMT " has been "
-	       "idle for %lu.%lu secs, shutting it down.\n",
-		sc->sc_node->nd_name, sc->sc_node->nd_num,
-		&sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port),
-	       msecs / 1000, msecs % 1000);
-
-	/*
-	 * Initialize the nn_timeout so that the next connection attempt
-	 * will continue in r2net_start_connect.
-	 */
-	/* Avoid spurious shutdowns... not sure if this is still necessary */
-	pr_err("ramster_idle_timer, skipping shutdown work\n");
-#if 0
-	/* old code used to do these two lines */
-	atomic_set(&nn->nn_timeout, 1);
-	r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
-#endif
-}
-
-static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc)
-{
-	r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
-	r2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
-		      msecs_to_jiffies(r2net_keepalive_delay()));
-	r2net_set_sock_timer(sc);
-	mod_timer(&sc->sc_idle_timeout,
-	       jiffies + msecs_to_jiffies(r2net_idle_timeout()));
-}
-
-static void r2net_sc_postpone_idle(struct r2net_sock_container *sc)
-{
-	/* Only push out an existing timer */
-	if (timer_pending(&sc->sc_idle_timeout))
-		r2net_sc_reset_idle_timer(sc);
-}
-
-/* this work func is kicked whenever a path sets the nn state which doesn't
- * have valid set.  This includes seeing hb come up, losing a connection,
- * having a connect attempt fail, etc. This centralizes the logic which decides
- * if a connect attempt should be made or if we should give up and all future
- * transmit attempts should fail */
-static void r2net_start_connect(struct work_struct *work)
-{
-	struct r2net_node *nn =
-		container_of(work, struct r2net_node, nn_connect_work.work);
-	struct r2net_sock_container *sc = NULL;
-	struct r2nm_node *node = NULL, *mynode = NULL;
-	struct socket *sock = NULL;
-	struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
-	int ret = 0, stop;
-	unsigned int timeout;
-
-	/* if we're greater we initiate tx, otherwise we accept */
-	if (r2nm_this_node() <= r2net_num_from_nn(nn))
-		goto out;
-
-	/* watch for racing with tearing a node down */
-	node = r2nm_get_node_by_num(r2net_num_from_nn(nn));
-	if (node == NULL) {
-		ret = 0;
-		goto out;
-	}
-
-	mynode = r2nm_get_node_by_num(r2nm_this_node());
-	if (mynode == NULL) {
-		ret = 0;
-		goto out;
-	}
-
-	spin_lock(&nn->nn_lock);
-	/*
-	 * see if we already have one pending or have given up.
-	 * For nn_timeout, it is set when we close the connection
-	 * because of the idle time out. So it means that we have
-	 * at least connected to that node successfully once,
-	 * now try to connect to it again.
-	 */
-	timeout = atomic_read(&nn->nn_timeout);
-	stop = (nn->nn_sc ||
-		(nn->nn_persistent_error &&
-		(nn->nn_persistent_error != -ENOTCONN || timeout == 0)));
-	spin_unlock(&nn->nn_lock);
-	if (stop)
-		goto out;
-
-	nn->nn_last_connect_attempt = jiffies;
-
-	sc = sc_alloc(node);
-	if (sc == NULL) {
-		mlog(0, "couldn't allocate sc\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
-	if (ret < 0) {
-		mlog(0, "can't create socket: %d\n", ret);
-		goto out;
-	}
-	sc->sc_sock = sock; /* freed by sc_kref_release */
-
-	sock->sk->sk_allocation = GFP_ATOMIC;
-
-	myaddr.sin_family = AF_INET;
-	myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
-	myaddr.sin_port = htons(0); /* any port */
-
-	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
-			      sizeof(myaddr));
-	if (ret) {
-		mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
-		     ret, &mynode->nd_ipv4_address);
-		goto out;
-	}
-
-	ret = r2net_set_nodelay(sc->sc_sock);
-	if (ret) {
-		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
-		goto out;
-	}
-
-	r2net_register_callbacks(sc->sc_sock->sk, sc);
-
-	spin_lock(&nn->nn_lock);
-	/* handshake completion will set nn->nn_sc_valid */
-	r2net_set_nn_state(nn, sc, 0, 0);
-	spin_unlock(&nn->nn_lock);
-
-	remoteaddr.sin_family = AF_INET;
-	remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
-	remoteaddr.sin_port = node->nd_ipv4_port;
-
-	ret = sc->sc_sock->ops->connect(sc->sc_sock,
-					(struct sockaddr *)&remoteaddr,
-					sizeof(remoteaddr),
-					O_NONBLOCK);
-	if (ret == -EINPROGRESS)
-		ret = 0;
-
-out:
-	if (ret) {
-		printk(KERN_NOTICE "ramster: Connect attempt to " SC_NODEF_FMT
-		       " failed with errno %d\n", sc->sc_node->nd_name,
-			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
-			ntohs(sc->sc_node->nd_ipv4_port), ret);
-		/* 0 err so that another will be queued and attempted
-		 * from set_nn_state */
-		if (sc)
-			r2net_ensure_shutdown(nn, sc, 0);
-	}
-	if (sc)
-		sc_put(sc);
-	if (node)
-		r2nm_node_put(node);
-	if (mynode)
-		r2nm_node_put(mynode);
-
-	return;
-}
-
-static void r2net_connect_expired(struct work_struct *work)
-{
-	struct r2net_node *nn =
-		container_of(work, struct r2net_node, nn_connect_expired.work);
-
-	spin_lock(&nn->nn_lock);
-	if (!nn->nn_sc_valid) {
-		printk(KERN_NOTICE "ramster: No connection established with "
-		       "node %u after %u.%u seconds, giving up.\n",
-		     r2net_num_from_nn(nn),
-		     r2net_idle_timeout() / 1000,
-		     r2net_idle_timeout() % 1000);
-
-		r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
-	}
-	spin_unlock(&nn->nn_lock);
-}
-
-static void r2net_still_up(struct work_struct *work)
-{
-}
-
-/* ------------------------------------------------------------ */
-
-void r2net_disconnect_node(struct r2nm_node *node)
-{
-	struct r2net_node *nn = r2net_nn_from_num(node->nd_num);
-
-	/* don't reconnect until it's heartbeating again */
-	spin_lock(&nn->nn_lock);
-	atomic_set(&nn->nn_timeout, 0);
-	r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
-	spin_unlock(&nn->nn_lock);
-
-	if (r2net_wq) {
-		cancel_delayed_work(&nn->nn_connect_expired);
-		cancel_delayed_work(&nn->nn_connect_work);
-		cancel_delayed_work(&nn->nn_still_up);
-		flush_workqueue(r2net_wq);
-	}
-}
-
-static void r2net_hb_node_down_cb(struct r2nm_node *node, int node_num,
-				  void *data)
-{
-	if (!node)
-		return;
-
-	if (node_num != r2nm_this_node())
-		r2net_disconnect_node(node);
-
-	BUG_ON(atomic_read(&r2net_connected_peers) < 0);
-}
-
-static void r2net_hb_node_up_cb(struct r2nm_node *node, int node_num,
-				void *data)
-{
-	struct r2net_node *nn = r2net_nn_from_num(node_num);
-
-	BUG_ON(!node);
-
-	/* ensure an immediate connect attempt */
-	nn->nn_last_connect_attempt = jiffies -
-		(msecs_to_jiffies(r2net_reconnect_delay()) + 1);
-
-	if (node_num != r2nm_this_node()) {
-		/* believe it or not, accept and node hearbeating testing
-		 * can succeed for this node before we got here.. so
-		 * only use set_nn_state to clear the persistent error
-		 * if that hasn't already happened */
-		spin_lock(&nn->nn_lock);
-		atomic_set(&nn->nn_timeout, 0);
-		if (nn->nn_persistent_error)
-			r2net_set_nn_state(nn, NULL, 0, 0);
-		spin_unlock(&nn->nn_lock);
-	}
-}
-
-void r2net_unregister_hb_callbacks(void)
-{
-	r2hb_unregister_callback(NULL, &r2net_hb_up);
-	r2hb_unregister_callback(NULL, &r2net_hb_down);
-}
-
-int r2net_register_hb_callbacks(void)
-{
-	int ret;
-
-	r2hb_setup_callback(&r2net_hb_down, R2HB_NODE_DOWN_CB,
-			    r2net_hb_node_down_cb, NULL, R2NET_HB_PRI);
-	r2hb_setup_callback(&r2net_hb_up, R2HB_NODE_UP_CB,
-			    r2net_hb_node_up_cb, NULL, R2NET_HB_PRI);
-
-	ret = r2hb_register_callback(NULL, &r2net_hb_up);
-	if (ret == 0)
-		ret = r2hb_register_callback(NULL, &r2net_hb_down);
-
-	if (ret)
-		r2net_unregister_hb_callbacks();
-
-	return ret;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_accept_one(struct socket *sock)
-{
-	int ret, slen;
-	struct sockaddr_in sin;
-	struct socket *new_sock = NULL;
-	struct r2nm_node *node = NULL;
-	struct r2nm_node *local_node = NULL;
-	struct r2net_sock_container *sc = NULL;
-	struct r2net_node *nn;
-
-	BUG_ON(sock == NULL);
-	ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type,
-			       sock->sk->sk_protocol, &new_sock);
-	if (ret)
-		goto out;
-
-	new_sock->type = sock->type;
-	new_sock->ops = sock->ops;
-	ret = sock->ops->accept(sock, new_sock, O_NONBLOCK);
-	if (ret < 0)
-		goto out;
-
-	new_sock->sk->sk_allocation = GFP_ATOMIC;
-
-	ret = r2net_set_nodelay(new_sock);
-	if (ret) {
-		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
-		goto out;
-	}
-
-	slen = sizeof(sin);
-	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
-				       &slen, 1);
-	if (ret < 0)
-		goto out;
-
-	node = r2nm_get_node_by_ip(sin.sin_addr.s_addr);
-	if (node == NULL) {
-		printk(KERN_NOTICE "ramster: Attempt to connect from unknown "
-		       "node at %pI4:%d\n", &sin.sin_addr.s_addr,
-		       ntohs(sin.sin_port));
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (r2nm_this_node() >= node->nd_num) {
-		local_node = r2nm_get_node_by_num(r2nm_this_node());
-		printk(KERN_NOTICE "ramster: Unexpected connect attempt seen "
-		       "at node '%s' (%u, %pI4:%d) from node '%s' (%u, "
-		       "%pI4:%d)\n", local_node->nd_name, local_node->nd_num,
-		       &(local_node->nd_ipv4_address),
-		       ntohs(local_node->nd_ipv4_port), node->nd_name,
-		       node->nd_num, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* this happens all the time when the other node sees our heartbeat
-	 * and tries to connect before we see their heartbeat */
-	if (!r2hb_check_node_heartbeating_from_callback(node->nd_num)) {
-		mlog(ML_CONN, "attempt to connect from node '%s' at "
-		     "%pI4:%d but it isn't heartbeating\n",
-		     node->nd_name, &sin.sin_addr.s_addr,
-		     ntohs(sin.sin_port));
-		ret = -EINVAL;
-		goto out;
-	}
-
-	nn = r2net_nn_from_num(node->nd_num);
-
-	spin_lock(&nn->nn_lock);
-	if (nn->nn_sc)
-		ret = -EBUSY;
-	else
-		ret = 0;
-	spin_unlock(&nn->nn_lock);
-	if (ret) {
-		printk(KERN_NOTICE "ramster: Attempt to connect from node '%s' "
-		       "at %pI4:%d but it already has an open connection\n",
-		       node->nd_name, &sin.sin_addr.s_addr,
-		       ntohs(sin.sin_port));
-		goto out;
-	}
-
-	sc = sc_alloc(node);
-	if (sc == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	sc->sc_sock = new_sock;
-	new_sock = NULL;
-
-	spin_lock(&nn->nn_lock);
-	atomic_set(&nn->nn_timeout, 0);
-	r2net_set_nn_state(nn, sc, 0, 0);
-	spin_unlock(&nn->nn_lock);
-
-	r2net_register_callbacks(sc->sc_sock->sk, sc);
-	r2net_sc_queue_work(sc, &sc->sc_rx_work);
-
-	r2net_initialize_handshake();
-	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
-
-out:
-	if (new_sock)
-		sock_release(new_sock);
-	if (node)
-		r2nm_node_put(node);
-	if (local_node)
-		r2nm_node_put(local_node);
-	if (sc)
-		sc_put(sc);
-	return ret;
-}
-
-static void r2net_accept_many(struct work_struct *work)
-{
-	struct socket *sock = r2net_listen_sock;
-	while (r2net_accept_one(sock) == 0)
-		cond_resched();
-}
-
-static void r2net_listen_data_ready(struct sock *sk, int bytes)
-{
-	void (*ready)(struct sock *sk, int bytes);
-
-	read_lock(&sk->sk_callback_lock);
-	ready = sk->sk_user_data;
-	if (ready == NULL) { /* check for teardown race */
-		ready = sk->sk_data_ready;
-		goto out;
-	}
-
-	/* ->sk_data_ready is also called for a newly established child socket
-	 * before it has been accepted and the acceptor has set up their
-	 * data_ready.. we only want to queue listen work for our listening
-	 * socket */
-	if (sk->sk_state == TCP_LISTEN) {
-		mlog(ML_TCP, "bytes: %d\n", bytes);
-		queue_work(r2net_wq, &r2net_listen_work);
-	}
-
-out:
-	read_unlock(&sk->sk_callback_lock);
-	ready(sk, bytes);
-}
-
-static int r2net_open_listening_sock(__be32 addr, __be16 port)
-{
-	struct socket *sock = NULL;
-	int ret;
-	struct sockaddr_in sin = {
-		.sin_family = PF_INET,
-		.sin_addr = { .s_addr = addr },
-		.sin_port = port,
-	};
-
-	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
-	if (ret < 0) {
-		printk(KERN_ERR "ramster: Error %d while creating socket\n",
-			ret);
-		goto out;
-	}
-
-	sock->sk->sk_allocation = GFP_ATOMIC;
-
-	write_lock_bh(&sock->sk->sk_callback_lock);
-	sock->sk->sk_user_data = sock->sk->sk_data_ready;
-	sock->sk->sk_data_ready = r2net_listen_data_ready;
-	write_unlock_bh(&sock->sk->sk_callback_lock);
-
-	r2net_listen_sock = sock;
-	INIT_WORK(&r2net_listen_work, r2net_accept_many);
-
-	sock->sk->sk_reuse = SK_CAN_REUSE;
-	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
-	if (ret < 0) {
-		printk(KERN_ERR "ramster: Error %d while binding socket at "
-			"%pI4:%u\n", ret, &addr, ntohs(port));
-		goto out;
-	}
-
-	ret = sock->ops->listen(sock, 64);
-	if (ret < 0)
-		printk(KERN_ERR "ramster: Error %d while listening on %pI4:%u\n",
-		       ret, &addr, ntohs(port));
-
-out:
-	if (ret) {
-		r2net_listen_sock = NULL;
-		if (sock)
-			sock_release(sock);
-	}
-	return ret;
-}
-
-/*
- * called from node manager when we should bring up our network listening
- * socket.  node manager handles all the serialization to only call this
- * once and to match it with r2net_stop_listening().  note,
- * r2nm_this_node() doesn't work yet as we're being called while it
- * is being set up.
- */
-int r2net_start_listening(struct r2nm_node *node)
-{
-	int ret = 0;
-
-	BUG_ON(r2net_wq != NULL);
-	BUG_ON(r2net_listen_sock != NULL);
-
-	mlog(ML_KTHREAD, "starting r2net thread...\n");
-	r2net_wq = create_singlethread_workqueue("r2net");
-	if (r2net_wq == NULL) {
-		mlog(ML_ERROR, "unable to launch r2net thread\n");
-		return -ENOMEM; /* ? */
-	}
-
-	ret = r2net_open_listening_sock(node->nd_ipv4_address,
-					node->nd_ipv4_port);
-	if (ret) {
-		destroy_workqueue(r2net_wq);
-		r2net_wq = NULL;
-	}
-
-	return ret;
-}
-
-/* again, r2nm_this_node() doesn't work here as we're involved in
- * tearing it down */
-void r2net_stop_listening(struct r2nm_node *node)
-{
-	struct socket *sock = r2net_listen_sock;
-	size_t i;
-
-	BUG_ON(r2net_wq == NULL);
-	BUG_ON(r2net_listen_sock == NULL);
-
-	/* stop the listening socket from generating work */
-	write_lock_bh(&sock->sk->sk_callback_lock);
-	sock->sk->sk_data_ready = sock->sk->sk_user_data;
-	sock->sk->sk_user_data = NULL;
-	write_unlock_bh(&sock->sk->sk_callback_lock);
-
-	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
-		struct r2nm_node *node = r2nm_get_node_by_num(i);
-		if (node) {
-			r2net_disconnect_node(node);
-			r2nm_node_put(node);
-		}
-	}
-
-	/* finish all work and tear down the work queue */
-	mlog(ML_KTHREAD, "waiting for r2net thread to exit....\n");
-	destroy_workqueue(r2net_wq);
-	r2net_wq = NULL;
-
-	sock_release(r2net_listen_sock);
-	r2net_listen_sock = NULL;
-}
-
-void r2net_hb_node_up_manual(int node_num)
-{
-	struct r2nm_node dummy;
-	if (r2nm_single_cluster == NULL)
-		pr_err("ramster: cluster not alive, node_up_manual ignored\n");
-	else {
-		r2hb_manual_set_node_heartbeating(node_num);
-		r2net_hb_node_up_cb(&dummy, node_num, NULL);
-	}
-}
-
-/* ------------------------------------------------------------ */
-
-int r2net_init(void)
-{
-	unsigned long i;
-
-	if (r2net_debugfs_init())
-		return -ENOMEM;
-
-	r2net_hand = kzalloc(sizeof(struct r2net_handshake), GFP_KERNEL);
-	r2net_keep_req = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
-	r2net_keep_resp = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
-	if (!r2net_hand || !r2net_keep_req || !r2net_keep_resp) {
-		kfree(r2net_hand);
-		kfree(r2net_keep_req);
-		kfree(r2net_keep_resp);
-		return -ENOMEM;
-	}
-
-	r2net_hand->protocol_version = cpu_to_be64(R2NET_PROTOCOL_VERSION);
-	r2net_hand->connector_id = cpu_to_be64(1);
-
-	r2net_keep_req->magic = cpu_to_be16(R2NET_MSG_KEEP_REQ_MAGIC);
-	r2net_keep_resp->magic = cpu_to_be16(R2NET_MSG_KEEP_RESP_MAGIC);
-
-	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
-		struct r2net_node *nn = r2net_nn_from_num(i);
-
-		atomic_set(&nn->nn_timeout, 0);
-		spin_lock_init(&nn->nn_lock);
-		INIT_DELAYED_WORK(&nn->nn_connect_work, r2net_start_connect);
-		INIT_DELAYED_WORK(&nn->nn_connect_expired,
-				  r2net_connect_expired);
-		INIT_DELAYED_WORK(&nn->nn_still_up, r2net_still_up);
-		/* until we see hb from a node we'll return einval */
-		nn->nn_persistent_error = -ENOTCONN;
-		init_waitqueue_head(&nn->nn_sc_wq);
-		idr_init(&nn->nn_status_idr);
-		INIT_LIST_HEAD(&nn->nn_status_list);
-	}
-
-	return 0;
-}
-
-void r2net_exit(void)
-{
-	kfree(r2net_hand);
-	kfree(r2net_keep_req);
-	kfree(r2net_keep_resp);
-	r2net_debugfs_exit();
-}
diff --git a/drivers/staging/ramster/r2net.c b/drivers/staging/ramster/r2net.c
deleted file mode 100644
index fc830c3..0000000
--- a/drivers/staging/ramster/r2net.c
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * r2net.c
- *
- * Copyright (c) 2011, Dan Magenheimer, Oracle Corp.
- *
- * Ramster_r2net provides an interface between zcache and r2net.
- *
- * FIXME: support more than two nodes
- */
-
-#include <linux/list.h>
-#include "cluster/tcp.h"
-#include "cluster/nodemanager.h"
-#include "tmem.h"
-#include "zcache.h"
-#include "ramster.h"
-
-#define RAMSTER_TESTING
-
-#define RMSTR_KEY	0x77347734
-
-enum {
-	RMSTR_TMEM_PUT_EPH = 100,
-	RMSTR_TMEM_PUT_PERS,
-	RMSTR_TMEM_ASYNC_GET_REQUEST,
-	RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
-	RMSTR_TMEM_ASYNC_GET_REPLY,
-	RMSTR_TMEM_FLUSH,
-	RMSTR_TMEM_FLOBJ,
-	RMSTR_TMEM_DESTROY_POOL,
-};
-
-#define RMSTR_R2NET_MAX_LEN \
-		(R2NET_MAX_PAYLOAD_BYTES - sizeof(struct tmem_xhandle))
-
-#include "cluster/tcp_internal.h"
-
-static struct r2nm_node *r2net_target_node;
-static int r2net_target_nodenum;
-
-int r2net_remote_target_node_set(int node_num)
-{
-	int ret = -1;
-
-	r2net_target_node = r2nm_get_node_by_num(node_num);
-	if (r2net_target_node != NULL) {
-		r2net_target_nodenum = node_num;
-		r2nm_node_put(r2net_target_node);
-		ret = 0;
-	}
-	return ret;
-}
-
-/* FIXME following buffer should be per-cpu, protected by preempt_disable */
-static char ramster_async_get_buf[R2NET_MAX_PAYLOAD_BYTES];
-
-static int ramster_remote_async_get_request_handler(struct r2net_msg *msg,
-				u32 len, void *data, void **ret_data)
-{
-	char *pdata;
-	struct tmem_xhandle xh;
-	int found;
-	size_t size = RMSTR_R2NET_MAX_LEN;
-	u16 msgtype = be16_to_cpu(msg->msg_type);
-	bool get_and_free = (msgtype == RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST);
-	unsigned long flags;
-
-	xh = *(struct tmem_xhandle *)msg->buf;
-	if (xh.xh_data_size > RMSTR_R2NET_MAX_LEN)
-		BUG();
-	pdata = ramster_async_get_buf;
-	*(struct tmem_xhandle *)pdata = xh;
-	pdata += sizeof(struct tmem_xhandle);
-	local_irq_save(flags);
-	found = zcache_get(xh.client_id, xh.pool_id, &xh.oid, xh.index,
-				pdata, &size, 1, get_and_free ? 1 : -1);
-	local_irq_restore(flags);
-	if (found < 0) {
-		/* a zero size indicates the get failed */
-		size = 0;
-	}
-	if (size > RMSTR_R2NET_MAX_LEN)
-		BUG();
-	*ret_data = pdata - sizeof(struct tmem_xhandle);
-	/* now make caller (r2net_process_message) handle specially */
-	r2net_force_data_magic(msg, RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY);
-	return size + sizeof(struct tmem_xhandle);
-}
-
-static int ramster_remote_async_get_reply_handler(struct r2net_msg *msg,
-				u32 len, void *data, void **ret_data)
-{
-	char *in = (char *)msg->buf;
-	int datalen = len - sizeof(struct r2net_msg);
-	int ret = -1;
-	struct tmem_xhandle *xh = (struct tmem_xhandle *)in;
-
-	in += sizeof(struct tmem_xhandle);
-	datalen -= sizeof(struct tmem_xhandle);
-	BUG_ON(datalen < 0 || datalen > PAGE_SIZE);
-	ret = zcache_localify(xh->pool_id, &xh->oid, xh->index,
-				in, datalen, xh->extra);
-#ifdef RAMSTER_TESTING
-	if (ret == -EEXIST)
-		pr_err("TESTING ArrgREP, aborted overwrite on racy put\n");
-#endif
-	return ret;
-}
-
-int ramster_remote_put_handler(struct r2net_msg *msg,
-				u32 len, void *data, void **ret_data)
-{
-	struct tmem_xhandle *xh;
-	char *p = (char *)msg->buf;
-	int datalen = len - sizeof(struct r2net_msg) -
-				sizeof(struct tmem_xhandle);
-	u16 msgtype = be16_to_cpu(msg->msg_type);
-	bool ephemeral = (msgtype == RMSTR_TMEM_PUT_EPH);
-	unsigned long flags;
-	int ret;
-
-	xh = (struct tmem_xhandle *)p;
-	p += sizeof(struct tmem_xhandle);
-	zcache_autocreate_pool(xh->client_id, xh->pool_id, ephemeral);
-	local_irq_save(flags);
-	ret = zcache_put(xh->client_id, xh->pool_id, &xh->oid, xh->index,
-				p, datalen, 1, ephemeral ? 1 : -1);
-	local_irq_restore(flags);
-	return ret;
-}
-
-int ramster_remote_flush_handler(struct r2net_msg *msg,
-				u32 len, void *data, void **ret_data)
-{
-	struct tmem_xhandle *xh;
-	char *p = (char *)msg->buf;
-
-	xh = (struct tmem_xhandle *)p;
-	p += sizeof(struct tmem_xhandle);
-	(void)zcache_flush(xh->client_id, xh->pool_id, &xh->oid, xh->index);
-	return 0;
-}
-
-int ramster_remote_flobj_handler(struct r2net_msg *msg,
-				u32 len, void *data, void **ret_data)
-{
-	struct tmem_xhandle *xh;
-	char *p = (char *)msg->buf;
-
-	xh = (struct tmem_xhandle *)p;
-	p += sizeof(struct tmem_xhandle);
-	(void)zcache_flush_object(xh->client_id, xh->pool_id, &xh->oid);
-	return 0;
-}
-
-int ramster_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode,
-				size_t expect_size, uint8_t expect_cksum,
-				void *extra)
-{
-	int ret = -1, status;
-	struct r2nm_node *node = NULL;
-	struct kvec vec[1];
-	size_t veclen = 1;
-	u32 msg_type;
-
-	node = r2nm_get_node_by_num(remotenode);
-	if (node == NULL)
-		goto out;
-	xh->client_id = r2nm_this_node(); /* which node is getting */
-	xh->xh_data_cksum = expect_cksum;
-	xh->xh_data_size = expect_size;
-	xh->extra = extra;
-	vec[0].iov_len = sizeof(*xh);
-	vec[0].iov_base = xh;
-	if (free)
-		msg_type = RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST;
-	else
-		msg_type = RMSTR_TMEM_ASYNC_GET_REQUEST;
-	ret = r2net_send_message_vec(msg_type, RMSTR_KEY,
-					vec, veclen, remotenode, &status);
-	r2nm_node_put(node);
-	if (ret < 0) {
-		/* FIXME handle bad message possibilities here? */
-		pr_err("UNTESTED ret<0 in ramster_remote_async_get\n");
-	}
-	ret = status;
-out:
-	return ret;
-}
-
-#ifdef RAMSTER_TESTING
-/* leave me here to see if it catches a weird crash */
-static void ramster_check_irq_counts(void)
-{
-	static int last_hardirq_cnt, last_softirq_cnt, last_preempt_cnt;
-	int cur_hardirq_cnt, cur_softirq_cnt, cur_preempt_cnt;
-
-	cur_hardirq_cnt = hardirq_count() >> HARDIRQ_SHIFT;
-	if (cur_hardirq_cnt > last_hardirq_cnt) {
-		last_hardirq_cnt = cur_hardirq_cnt;
-		if (!(last_hardirq_cnt&(last_hardirq_cnt-1)))
-			pr_err("RAMSTER TESTING RRP hardirq_count=%d\n",
-				last_hardirq_cnt);
-	}
-	cur_softirq_cnt = softirq_count() >> SOFTIRQ_SHIFT;
-	if (cur_softirq_cnt > last_softirq_cnt) {
-		last_softirq_cnt = cur_softirq_cnt;
-		if (!(last_softirq_cnt&(last_softirq_cnt-1)))
-			pr_err("RAMSTER TESTING RRP softirq_count=%d\n",
-				last_softirq_cnt);
-	}
-	cur_preempt_cnt = preempt_count() & PREEMPT_MASK;
-	if (cur_preempt_cnt > last_preempt_cnt) {
-		last_preempt_cnt = cur_preempt_cnt;
-		if (!(last_preempt_cnt&(last_preempt_cnt-1)))
-			pr_err("RAMSTER TESTING RRP preempt_count=%d\n",
-				last_preempt_cnt);
-	}
-}
-#endif
-
-int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size,
-				bool ephemeral, int *remotenode)
-{
-	int nodenum, ret = -1, status;
-	struct r2nm_node *node = NULL;
-	struct kvec vec[2];
-	size_t veclen = 2;
-	u32 msg_type;
-#ifdef RAMSTER_TESTING
-	struct r2net_node *nn;
-#endif
-
-	BUG_ON(size > RMSTR_R2NET_MAX_LEN);
-	xh->client_id = r2nm_this_node(); /* which node is putting */
-	vec[0].iov_len = sizeof(*xh);
-	vec[0].iov_base = xh;
-	vec[1].iov_len = size;
-	vec[1].iov_base = data;
-	node = r2net_target_node;
-	if (!node)
-		goto out;
-
-	nodenum = r2net_target_nodenum;
-
-	r2nm_node_get(node);
-
-#ifdef RAMSTER_TESTING
-	nn = r2net_nn_from_num(nodenum);
-	WARN_ON_ONCE(nn->nn_persistent_error || !nn->nn_sc_valid);
-#endif
-
-	if (ephemeral)
-		msg_type = RMSTR_TMEM_PUT_EPH;
-	else
-		msg_type = RMSTR_TMEM_PUT_PERS;
-#ifdef RAMSTER_TESTING
-	/* leave me here to see if it catches a weird crash */
-	ramster_check_irq_counts();
-#endif
-
-	ret = r2net_send_message_vec(msg_type, RMSTR_KEY, vec, veclen,
-						nodenum, &status);
-#ifdef RAMSTER_TESTING
-	if (ret != 0) {
-		static unsigned long cnt;
-		cnt++;
-		if (!(cnt&(cnt-1)))
-			pr_err("ramster_remote_put: message failed, ret=%d, cnt=%lu\n",
-				ret, cnt);
-		ret = -1;
-	}
-#endif
-	if (ret < 0)
-		ret = -1;
-	else {
-		ret = status;
-		*remotenode = nodenum;
-	}
-
-	r2nm_node_put(node);
-out:
-	return ret;
-}
-
-int ramster_remote_flush(struct tmem_xhandle *xh, int remotenode)
-{
-	int ret = -1, status;
-	struct r2nm_node *node = NULL;
-	struct kvec vec[1];
-	size_t veclen = 1;
-
-	node = r2nm_get_node_by_num(remotenode);
-	BUG_ON(node == NULL);
-	xh->client_id = r2nm_this_node(); /* which node is flushing */
-	vec[0].iov_len = sizeof(*xh);
-	vec[0].iov_base = xh;
-	BUG_ON(irqs_disabled());
-	BUG_ON(in_softirq());
-	ret = r2net_send_message_vec(RMSTR_TMEM_FLUSH, RMSTR_KEY,
-					vec, veclen, remotenode, &status);
-	r2nm_node_put(node);
-	return ret;
-}
-
-int ramster_remote_flush_object(struct tmem_xhandle *xh, int remotenode)
-{
-	int ret = -1, status;
-	struct r2nm_node *node = NULL;
-	struct kvec vec[1];
-	size_t veclen = 1;
-
-	node = r2nm_get_node_by_num(remotenode);
-	BUG_ON(node == NULL);
-	xh->client_id = r2nm_this_node(); /* which node is flobjing */
-	vec[0].iov_len = sizeof(*xh);
-	vec[0].iov_base = xh;
-	ret = r2net_send_message_vec(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
-					vec, veclen, remotenode, &status);
-	r2nm_node_put(node);
-	return ret;
-}
-
-/*
- * Handler registration
- */
-
-static LIST_HEAD(r2net_unreg_list);
-
-static void r2net_unregister_handlers(void)
-{
-	r2net_unregister_handler_list(&r2net_unreg_list);
-}
-
-int r2net_register_handlers(void)
-{
-	int status;
-
-	status = r2net_register_handler(RMSTR_TMEM_PUT_EPH, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_put_handler,
-				NULL, NULL, &r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_PUT_PERS, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_put_handler,
-				NULL, NULL, &r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REQUEST, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_async_get_request_handler,
-				NULL, NULL,
-				&r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
-				RMSTR_KEY, RMSTR_R2NET_MAX_LEN,
-				ramster_remote_async_get_request_handler,
-				NULL, NULL,
-				&r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_async_get_reply_handler,
-				NULL, NULL,
-				&r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_FLUSH, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_flush_handler,
-				NULL, NULL,
-				&r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	status = r2net_register_handler(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
-				RMSTR_R2NET_MAX_LEN,
-				ramster_remote_flobj_handler,
-				NULL, NULL,
-				&r2net_unreg_list);
-	if (status)
-		goto bail;
-
-	pr_info("ramster: r2net handlers registered\n");
-
-bail:
-	if (status) {
-		r2net_unregister_handlers();
-		pr_err("ramster: couldn't register r2net handlers\n");
-	}
-	return status;
-}
diff --git a/drivers/staging/ramster/ramster.h b/drivers/staging/ramster/ramster.h
index 0c9455e..1b71aea 100644
--- a/drivers/staging/ramster/ramster.h
+++ b/drivers/staging/ramster/ramster.h
@@ -1,118 +1,59 @@
+
 /*
- * ramster.h
+ * zcache/ramster.h
  *
- * Peer-to-peer transcendent memory
+ * Placeholder to resolve ramster references when !CONFIG_RAMSTER
+ * Real ramster.h lives in ramster subdirectory.
  *
  * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
  */
 
-#ifndef _RAMSTER_H_
-#define _RAMSTER_H_
+#ifndef _ZCACHE_RAMSTER_H_
+#define _ZCACHE_RAMSTER_H_
 
-/*
- * format of remote pampd:
- *   bit 0 == intransit
- *   bit 1 == is_remote... if this bit is set, then
- *   bit 2-9 == remotenode
- *   bit 10-22 == size
- *   bit 23-30 == cksum
- */
-#define FAKE_PAMPD_INTRANSIT_BITS	1
-#define FAKE_PAMPD_ISREMOTE_BITS	1
-#define FAKE_PAMPD_REMOTENODE_BITS	8
-#define FAKE_PAMPD_REMOTESIZE_BITS	13
-#define FAKE_PAMPD_CHECKSUM_BITS	8
-
-#define FAKE_PAMPD_INTRANSIT_SHIFT	0
-#define FAKE_PAMPD_ISREMOTE_SHIFT	(FAKE_PAMPD_INTRANSIT_SHIFT + \
-					 FAKE_PAMPD_INTRANSIT_BITS)
-#define FAKE_PAMPD_REMOTENODE_SHIFT	(FAKE_PAMPD_ISREMOTE_SHIFT + \
-					 FAKE_PAMPD_ISREMOTE_BITS)
-#define FAKE_PAMPD_REMOTESIZE_SHIFT	(FAKE_PAMPD_REMOTENODE_SHIFT + \
-					 FAKE_PAMPD_REMOTENODE_BITS)
-#define FAKE_PAMPD_CHECKSUM_SHIFT	(FAKE_PAMPD_REMOTESIZE_SHIFT + \
-					 FAKE_PAMPD_REMOTESIZE_BITS)
-
-#define FAKE_PAMPD_MASK(x)		((1UL << (x)) - 1)
-
-static inline void *pampd_make_remote(int remotenode, size_t size,
-					unsigned char cksum)
+#ifdef CONFIG_RAMSTER
+#include "ramster/ramster.h"
+#else
+static inline void ramster_init(bool x, bool y, bool z)
 {
-	unsigned long fake_pampd = 0;
-	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
-	fake_pampd |= ((unsigned long)remotenode &
-			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) <<
-				FAKE_PAMPD_REMOTENODE_SHIFT;
-	fake_pampd |= ((unsigned long)size &
-			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) <<
-				FAKE_PAMPD_REMOTESIZE_SHIFT;
-	fake_pampd |= ((unsigned long)cksum &
-			FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) <<
-				FAKE_PAMPD_CHECKSUM_SHIFT;
-	return (void *)fake_pampd;
 }
 
-static inline unsigned int pampd_remote_node(void *pampd)
+static inline void ramster_register_pamops(struct tmem_pamops *p)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-	return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) &
-		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS);
 }
 
-static inline unsigned int pampd_remote_size(void *pampd)
+static inline int ramster_remotify_pageframe(bool b)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-	return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) &
-		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS);
+	return 0;
 }
 
-static inline unsigned char pampd_remote_cksum(void *pampd)
+static inline void *ramster_pampd_free(void *v, struct tmem_pool *p,
+			struct tmem_oid *o, uint32_t u, bool b)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-	return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) &
-		FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS);
+	return NULL;
 }
 
-static inline bool pampd_is_remote(void *pampd)
+static inline int ramster_do_preload_flnode(struct tmem_pool *p)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-	return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) &
-		FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS);
+	return -1;
 }
 
-static inline bool pampd_is_intransit(void *pampd)
+static inline bool pampd_is_remote(void *v)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-	return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) &
-		FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS);
+	return false;
 }
 
-/* note that it is a BUG for intransit to be set without isremote also set */
-static inline void *pampd_mark_intransit(void *pampd)
+static inline void ramster_count_foreign_pages(bool b, int i)
 {
-	unsigned long fake_pampd = (unsigned long)pampd;
-
-	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
-	fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT;
-	return (void *)fake_pampd;
 }
 
-static inline void *pampd_mask_intransit_and_remote(void *marked_pampd)
+static inline void ramster_cpu_up(int cpu)
 {
-	unsigned long pampd = (unsigned long)marked_pampd;
-
-	pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT);
-	pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT);
-	return (void *)pampd;
 }
 
-extern int ramster_remote_async_get(struct tmem_xhandle *,
-				bool, int, size_t, uint8_t, void *extra);
-extern int ramster_remote_put(struct tmem_xhandle *, char *, size_t,
-				bool, int *);
-extern int ramster_remote_flush(struct tmem_xhandle *, int);
-extern int ramster_remote_flush_object(struct tmem_xhandle *, int);
-extern int r2net_register_handlers(void);
-extern int r2net_remote_target_node_set(int);
+static inline void ramster_cpu_down(int cpu)
+{
+}
+#endif
 
-#endif /* _TMEM_H */
+#endif /* _ZCACHE_RAMSTER_H */
diff --git a/drivers/staging/ramster/ramster/heartbeat.c b/drivers/staging/ramster/ramster/heartbeat.c
new file mode 100644
index 0000000..75d3fe8
--- /dev/null
+++ b/drivers/staging/ramster/ramster/heartbeat.c
@@ -0,0 +1,462 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+
+#include "heartbeat.h"
+#include "tcp.h"
+#include "nodemanager.h"
+
+#include "masklog.h"
+
+/*
+ * The first heartbeat pass had one global thread that would serialize all hb
+ * callback calls.  This global serializing sem should only be removed once
+ * we've made sure that all callees can deal with being called concurrently
+ * from multiple hb region threads.
+ */
+static DECLARE_RWSEM(r2hb_callback_sem);
+
+/*
+ * multiple hb threads are watching multiple regions.  A node is live
+ * whenever any of the threads sees activity from the node in its region.
+ */
+static DEFINE_SPINLOCK(r2hb_live_lock);
+static unsigned long r2hb_live_node_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
+
+static struct r2hb_callback {
+	struct list_head list;
+} r2hb_callbacks[R2HB_NUM_CB];
+
+enum r2hb_heartbeat_modes {
+	R2HB_HEARTBEAT_LOCAL		= 0,
+	R2HB_HEARTBEAT_GLOBAL,
+	R2HB_HEARTBEAT_NUM_MODES,
+};
+
+char *r2hb_heartbeat_mode_desc[R2HB_HEARTBEAT_NUM_MODES] = {
+		"local",	/* R2HB_HEARTBEAT_LOCAL */
+		"global",	/* R2HB_HEARTBEAT_GLOBAL */
+};
+
+unsigned int r2hb_dead_threshold = R2HB_DEFAULT_DEAD_THRESHOLD;
+unsigned int r2hb_heartbeat_mode = R2HB_HEARTBEAT_LOCAL;
+
+/* Only sets a new threshold if there are no active regions.
+ *
+ * No locking or otherwise interesting code is required for reading
+ * r2hb_dead_threshold as it can't change once regions are active and
+ * it's not interesting to anyone until then anyway. */
+static void r2hb_dead_threshold_set(unsigned int threshold)
+{
+	if (threshold > R2HB_MIN_DEAD_THRESHOLD) {
+		spin_lock(&r2hb_live_lock);
+		r2hb_dead_threshold = threshold;
+		spin_unlock(&r2hb_live_lock);
+	}
+}
+
+static int r2hb_global_hearbeat_mode_set(unsigned int hb_mode)
+{
+	int ret = -1;
+
+	if (hb_mode < R2HB_HEARTBEAT_NUM_MODES) {
+		spin_lock(&r2hb_live_lock);
+		r2hb_heartbeat_mode = hb_mode;
+		ret = 0;
+		spin_unlock(&r2hb_live_lock);
+	}
+
+	return ret;
+}
+
+void r2hb_exit(void)
+{
+}
+
+int r2hb_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(r2hb_callbacks); i++)
+		INIT_LIST_HEAD(&r2hb_callbacks[i].list);
+
+	memset(r2hb_live_node_bitmap, 0, sizeof(r2hb_live_node_bitmap));
+
+	return 0;
+}
+
+/* if we're already in a callback then we're already serialized by the sem */
+static void r2hb_fill_node_map_from_callback(unsigned long *map,
+					     unsigned bytes)
+{
+	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
+
+	memcpy(map, &r2hb_live_node_bitmap, bytes);
+}
+
+/*
+ * get a map of all nodes that are heartbeating in any regions
+ */
+void r2hb_fill_node_map(unsigned long *map, unsigned bytes)
+{
+	/* callers want to serialize this map and callbacks so that they
+	 * can trust that they don't miss nodes coming to the party */
+	down_read(&r2hb_callback_sem);
+	spin_lock(&r2hb_live_lock);
+	r2hb_fill_node_map_from_callback(map, bytes);
+	spin_unlock(&r2hb_live_lock);
+	up_read(&r2hb_callback_sem);
+}
+EXPORT_SYMBOL_GPL(r2hb_fill_node_map);
+
+/*
+ * heartbeat configfs bits.  The heartbeat set is a default set under
+ * the cluster set in nodemanager.c.
+ */
+
+/* heartbeat set */
+
+struct r2hb_hb_group {
+	struct config_group hs_group;
+	/* some stuff? */
+};
+
+static struct r2hb_hb_group *to_r2hb_hb_group(struct config_group *group)
+{
+	return group ?
+		container_of(group, struct r2hb_hb_group, hs_group)
+		: NULL;
+}
+
+static struct config_item r2hb_config_item;
+
+static struct config_item *r2hb_hb_group_make_item(struct config_group *group,
+							  const char *name)
+{
+	int ret;
+
+	if (strlen(name) > R2HB_MAX_REGION_NAME_LEN) {
+		ret = -ENAMETOOLONG;
+		goto free;
+	}
+
+	config_item_put(&r2hb_config_item);
+
+	return &r2hb_config_item;
+free:
+	return ERR_PTR(ret);
+}
+
+static void r2hb_hb_group_drop_item(struct config_group *group,
+					   struct config_item *item)
+{
+	if (r2hb_global_heartbeat_active()) {
+		pr_notice("ramster: Heartbeat %s on region %s (%s)\n",
+			"stopped/aborted", config_item_name(item),
+			"no region");
+	}
+
+	config_item_put(item);
+}
+
+struct r2hb_hb_group_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2hb_hb_group *, char *);
+	ssize_t (*store)(struct r2hb_hb_group *, const char *, size_t);
+};
+
+static ssize_t r2hb_hb_group_show(struct config_item *item,
+					 struct configfs_attribute *attr,
+					 char *page)
+{
+	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
+	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
+		container_of(attr, struct r2hb_hb_group_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2hb_hb_group_attr->show)
+		ret = r2hb_hb_group_attr->show(reg, page);
+	return ret;
+}
+
+static ssize_t r2hb_hb_group_store(struct config_item *item,
+					  struct configfs_attribute *attr,
+					  const char *page, size_t count)
+{
+	struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
+	struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
+		container_of(attr, struct r2hb_hb_group_attribute, attr);
+	ssize_t ret = -EINVAL;
+
+	if (r2hb_hb_group_attr->store)
+		ret = r2hb_hb_group_attr->store(reg, page, count);
+	return ret;
+}
+
+static ssize_t r2hb_hb_group_threshold_show(struct r2hb_hb_group *group,
+						     char *page)
+{
+	return sprintf(page, "%u\n", r2hb_dead_threshold);
+}
+
+static ssize_t r2hb_hb_group_threshold_store(struct r2hb_hb_group *group,
+						    const char *page,
+						    size_t count)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	/* this will validate ranges for us. */
+	r2hb_dead_threshold_set((unsigned int) tmp);
+
+	return count;
+}
+
+static
+ssize_t r2hb_hb_group_mode_show(struct r2hb_hb_group *group,
+				       char *page)
+{
+	return sprintf(page, "%s\n",
+		       r2hb_heartbeat_mode_desc[r2hb_heartbeat_mode]);
+}
+
+static
+ssize_t r2hb_hb_group_mode_store(struct r2hb_hb_group *group,
+					const char *page, size_t count)
+{
+	unsigned int i;
+	int ret;
+	size_t len;
+
+	len = (page[count - 1] == '\n') ? count - 1 : count;
+	if (!len)
+		return -EINVAL;
+
+	for (i = 0; i < R2HB_HEARTBEAT_NUM_MODES; ++i) {
+		if (strnicmp(page, r2hb_heartbeat_mode_desc[i], len))
+			continue;
+
+		ret = r2hb_global_hearbeat_mode_set(i);
+		if (!ret)
+			pr_notice("ramster: Heartbeat mode set to %s\n",
+			       r2hb_heartbeat_mode_desc[i]);
+		return count;
+	}
+
+	return -EINVAL;
+
+}
+
+static struct r2hb_hb_group_attribute r2hb_hb_group_attr_threshold = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "dead_threshold",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2hb_hb_group_threshold_show,
+	.store	= r2hb_hb_group_threshold_store,
+};
+
+static struct r2hb_hb_group_attribute r2hb_hb_group_attr_mode = {
+	.attr   = { .ca_owner = THIS_MODULE,
+		.ca_name = "mode",
+		.ca_mode = S_IRUGO | S_IWUSR },
+	.show   = r2hb_hb_group_mode_show,
+	.store  = r2hb_hb_group_mode_store,
+};
+
+static struct configfs_attribute *r2hb_hb_group_attrs[] = {
+	&r2hb_hb_group_attr_threshold.attr,
+	&r2hb_hb_group_attr_mode.attr,
+	NULL,
+};
+
+static struct configfs_item_operations r2hb_hearbeat_group_item_ops = {
+	.show_attribute		= r2hb_hb_group_show,
+	.store_attribute	= r2hb_hb_group_store,
+};
+
+static struct configfs_group_operations r2hb_hb_group_group_ops = {
+	.make_item	= r2hb_hb_group_make_item,
+	.drop_item	= r2hb_hb_group_drop_item,
+};
+
+static struct config_item_type r2hb_hb_group_type = {
+	.ct_group_ops	= &r2hb_hb_group_group_ops,
+	.ct_item_ops	= &r2hb_hearbeat_group_item_ops,
+	.ct_attrs	= r2hb_hb_group_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* this is just here to avoid touching group in heartbeat.h which the
+ * entire damn world #includes */
+struct config_group *r2hb_alloc_hb_set(void)
+{
+	struct r2hb_hb_group *hs = NULL;
+	struct config_group *ret = NULL;
+
+	hs = kzalloc(sizeof(struct r2hb_hb_group), GFP_KERNEL);
+	if (hs == NULL)
+		goto out;
+
+	config_group_init_type_name(&hs->hs_group, "heartbeat",
+				    &r2hb_hb_group_type);
+
+	ret = &hs->hs_group;
+out:
+	if (ret == NULL)
+		kfree(hs);
+	return ret;
+}
+
+void r2hb_free_hb_set(struct config_group *group)
+{
+	struct r2hb_hb_group *hs = to_r2hb_hb_group(group);
+	kfree(hs);
+}
+
+/* hb callback registration and issuing */
+
+static struct r2hb_callback *hbcall_from_type(enum r2hb_callback_type type)
+{
+	if (type == R2HB_NUM_CB)
+		return ERR_PTR(-EINVAL);
+
+	return &r2hb_callbacks[type];
+}
+
+void r2hb_setup_callback(struct r2hb_callback_func *hc,
+			 enum r2hb_callback_type type,
+			 r2hb_cb_func *func,
+			 void *data,
+			 int priority)
+{
+	INIT_LIST_HEAD(&hc->hc_item);
+	hc->hc_func = func;
+	hc->hc_data = data;
+	hc->hc_priority = priority;
+	hc->hc_type = type;
+	hc->hc_magic = R2HB_CB_MAGIC;
+}
+EXPORT_SYMBOL_GPL(r2hb_setup_callback);
+
+int r2hb_register_callback(const char *region_uuid,
+			   struct r2hb_callback_func *hc)
+{
+	struct r2hb_callback_func *tmp;
+	struct list_head *iter;
+	struct r2hb_callback *hbcall;
+	int ret;
+
+	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
+	BUG_ON(!list_empty(&hc->hc_item));
+
+	hbcall = hbcall_from_type(hc->hc_type);
+	if (IS_ERR(hbcall)) {
+		ret = PTR_ERR(hbcall);
+		goto out;
+	}
+
+	down_write(&r2hb_callback_sem);
+
+	list_for_each(iter, &hbcall->list) {
+		tmp = list_entry(iter, struct r2hb_callback_func, hc_item);
+		if (hc->hc_priority < tmp->hc_priority) {
+			list_add_tail(&hc->hc_item, iter);
+			break;
+		}
+	}
+	if (list_empty(&hc->hc_item))
+		list_add_tail(&hc->hc_item, &hbcall->list);
+
+	up_write(&r2hb_callback_sem);
+	ret = 0;
+out:
+	mlog(ML_CLUSTER, "returning %d on behalf of %p for funcs %p\n",
+	     ret, __builtin_return_address(0), hc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2hb_register_callback);
+
+void r2hb_unregister_callback(const char *region_uuid,
+			      struct r2hb_callback_func *hc)
+{
+	BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
+
+	mlog(ML_CLUSTER, "on behalf of %p for funcs %p\n",
+	     __builtin_return_address(0), hc);
+
+	/* XXX Can this happen _with_ a region reference? */
+	if (list_empty(&hc->hc_item))
+		return;
+
+	down_write(&r2hb_callback_sem);
+
+	list_del_init(&hc->hc_item);
+
+	up_write(&r2hb_callback_sem);
+}
+EXPORT_SYMBOL_GPL(r2hb_unregister_callback);
+
+int r2hb_check_node_heartbeating_from_callback(u8 node_num)
+{
+	unsigned long testing_map[BITS_TO_LONGS(R2NM_MAX_NODES)];
+
+	r2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
+	if (!test_bit(node_num, testing_map)) {
+		mlog(ML_HEARTBEAT,
+		     "node (%u) does not have heartbeating enabled.\n",
+		     node_num);
+		return 0;
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(r2hb_check_node_heartbeating_from_callback);
+
+void r2hb_stop_all_regions(void)
+{
+}
+EXPORT_SYMBOL_GPL(r2hb_stop_all_regions);
+
+/*
+ * this is just a hack until we get the plumbing which flips file systems
+ * read only and drops the hb ref instead of killing the node dead.
+ */
+int r2hb_global_heartbeat_active(void)
+{
+	return (r2hb_heartbeat_mode == R2HB_HEARTBEAT_GLOBAL);
+}
+EXPORT_SYMBOL(r2hb_global_heartbeat_active);
+
+/* added for RAMster */
+void r2hb_manual_set_node_heartbeating(int node_num)
+{
+	if (node_num < R2NM_MAX_NODES)
+		set_bit(node_num, r2hb_live_node_bitmap);
+}
+EXPORT_SYMBOL(r2hb_manual_set_node_heartbeating);
diff --git a/drivers/staging/ramster/cluster/heartbeat.h b/drivers/staging/ramster/ramster/heartbeat.h
similarity index 100%
rename from drivers/staging/ramster/cluster/heartbeat.h
rename to drivers/staging/ramster/ramster/heartbeat.h
diff --git a/drivers/staging/ramster/cluster/masklog.c b/drivers/staging/ramster/ramster/masklog.c
similarity index 100%
rename from drivers/staging/ramster/cluster/masklog.c
rename to drivers/staging/ramster/ramster/masklog.c
diff --git a/drivers/staging/ramster/cluster/masklog.h b/drivers/staging/ramster/ramster/masklog.h
similarity index 100%
rename from drivers/staging/ramster/cluster/masklog.h
rename to drivers/staging/ramster/ramster/masklog.h
diff --git a/drivers/staging/ramster/ramster/nodemanager.c b/drivers/staging/ramster/ramster/nodemanager.c
new file mode 100644
index 0000000..c0f4815
--- /dev/null
+++ b/drivers/staging/ramster/ramster/nodemanager.c
@@ -0,0 +1,995 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004, 2005, 2012 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+
+#include "tcp.h"
+#include "nodemanager.h"
+#include "heartbeat.h"
+#include "masklog.h"
+
+/* for now we operate under the assertion that there can be only one
+ * cluster active at a time.  Changing this will require trickling
+ * cluster references throughout where nodes are looked up */
+struct r2nm_cluster *r2nm_single_cluster;
+
+char *r2nm_fence_method_desc[R2NM_FENCE_METHODS] = {
+		"reset",	/* R2NM_FENCE_RESET */
+		"panic",	/* R2NM_FENCE_PANIC */
+};
+
+struct r2nm_node *r2nm_get_node_by_num(u8 node_num)
+{
+	struct r2nm_node *node = NULL;
+
+	if (node_num >= R2NM_MAX_NODES || r2nm_single_cluster == NULL)
+		goto out;
+
+	read_lock(&r2nm_single_cluster->cl_nodes_lock);
+	node = r2nm_single_cluster->cl_nodes[node_num];
+	if (node)
+		config_item_get(&node->nd_item);
+	read_unlock(&r2nm_single_cluster->cl_nodes_lock);
+out:
+	return node;
+}
+EXPORT_SYMBOL_GPL(r2nm_get_node_by_num);
+
+int r2nm_configured_node_map(unsigned long *map, unsigned bytes)
+{
+	struct r2nm_cluster *cluster = r2nm_single_cluster;
+
+	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
+
+	if (cluster == NULL)
+		return -EINVAL;
+
+	read_lock(&cluster->cl_nodes_lock);
+	memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
+	read_unlock(&cluster->cl_nodes_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(r2nm_configured_node_map);
+
+static struct r2nm_node *r2nm_node_ip_tree_lookup(struct r2nm_cluster *cluster,
+						  __be32 ip_needle,
+						  struct rb_node ***ret_p,
+						  struct rb_node **ret_parent)
+{
+	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct r2nm_node *node, *ret = NULL;
+
+	while (*p) {
+		int cmp;
+
+		parent = *p;
+		node = rb_entry(parent, struct r2nm_node, nd_ip_node);
+
+		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
+				sizeof(ip_needle));
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else if (cmp > 0)
+			p = &(*p)->rb_right;
+		else {
+			ret = node;
+			break;
+		}
+	}
+
+	if (ret_p != NULL)
+		*ret_p = p;
+	if (ret_parent != NULL)
+		*ret_parent = parent;
+
+	return ret;
+}
+
+struct r2nm_node *r2nm_get_node_by_ip(__be32 addr)
+{
+	struct r2nm_node *node = NULL;
+	struct r2nm_cluster *cluster = r2nm_single_cluster;
+
+	if (cluster == NULL)
+		goto out;
+
+	read_lock(&cluster->cl_nodes_lock);
+	node = r2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
+	if (node)
+		config_item_get(&node->nd_item);
+	read_unlock(&cluster->cl_nodes_lock);
+
+out:
+	return node;
+}
+EXPORT_SYMBOL_GPL(r2nm_get_node_by_ip);
+
+void r2nm_node_put(struct r2nm_node *node)
+{
+	config_item_put(&node->nd_item);
+}
+EXPORT_SYMBOL_GPL(r2nm_node_put);
+
+void r2nm_node_get(struct r2nm_node *node)
+{
+	config_item_get(&node->nd_item);
+}
+EXPORT_SYMBOL_GPL(r2nm_node_get);
+
+u8 r2nm_this_node(void)
+{
+	u8 node_num = R2NM_MAX_NODES;
+
+	if (r2nm_single_cluster && r2nm_single_cluster->cl_has_local)
+		node_num = r2nm_single_cluster->cl_local_node;
+
+	return node_num;
+}
+EXPORT_SYMBOL_GPL(r2nm_this_node);
+
+/* node configfs bits */
+
+static struct r2nm_cluster *to_r2nm_cluster(struct config_item *item)
+{
+	return item ?
+		container_of(to_config_group(item), struct r2nm_cluster,
+			     cl_group)
+		: NULL;
+}
+
+static struct r2nm_node *to_r2nm_node(struct config_item *item)
+{
+	return item ? container_of(item, struct r2nm_node, nd_item) : NULL;
+}
+
+static void r2nm_node_release(struct config_item *item)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	kfree(node);
+}
+
+static ssize_t r2nm_node_num_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%d\n", node->nd_num);
+}
+
+static struct r2nm_cluster *to_r2nm_cluster_from_node(struct r2nm_node *node)
+{
+	/* through the first node_set .parent
+	 * mycluster/nodes/mynode == r2nm_cluster->r2nm_node_group->r2nm_node */
+	return to_r2nm_cluster(node->nd_item.ci_parent->ci_parent);
+}
+
+enum {
+	R2NM_NODE_ATTR_NUM = 0,
+	R2NM_NODE_ATTR_PORT,
+	R2NM_NODE_ATTR_ADDRESS,
+	R2NM_NODE_ATTR_LOCAL,
+};
+
+static ssize_t r2nm_node_num_write(struct r2nm_node *node, const char *page,
+				   size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp >= R2NM_MAX_NODES)
+		return -ERANGE;
+
+	/* once we're in the cl_nodes tree networking can look us up by
+	 * node number and try to use our address and port attributes
+	 * to connect to this node.. make sure that they've been set
+	 * before writing the node attribute? */
+	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
+		return -EINVAL; /* XXX */
+
+	write_lock(&cluster->cl_nodes_lock);
+	if (cluster->cl_nodes[tmp])
+		p = NULL;
+	else  {
+		cluster->cl_nodes[tmp] = node;
+		node->nd_num = tmp;
+		set_bit(tmp, cluster->cl_nodes_bitmap);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+	if (p == NULL)
+		return -EEXIST;
+
+	return count;
+}
+static ssize_t r2nm_node_ipv4_port_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
+}
+
+static ssize_t r2nm_node_ipv4_port_write(struct r2nm_node *node,
+					 const char *page, size_t count)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp == 0)
+		return -EINVAL;
+	if (tmp >= (u16)-1)
+		return -ERANGE;
+
+	node->nd_ipv4_port = htons(tmp);
+
+	return count;
+}
+
+static ssize_t r2nm_node_ipv4_address_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
+}
+
+static ssize_t r2nm_node_ipv4_address_write(struct r2nm_node *node,
+					    const char *page,
+					    size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	int ret, i;
+	struct rb_node **p, *parent;
+	unsigned int octets[4];
+	__be32 ipv4_addr = 0;
+
+	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
+		     &octets[1], &octets[0]);
+	if (ret != 4)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(octets); i++) {
+		if (octets[i] > 255)
+			return -ERANGE;
+		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
+	}
+
+	ret = 0;
+	write_lock(&cluster->cl_nodes_lock);
+	if (r2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
+		ret = -EEXIST;
+	else {
+		rb_link_node(&node->nd_ip_node, parent, p);
+		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+	if (ret)
+		return ret;
+
+	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
+
+	return count;
+}
+
+static ssize_t r2nm_node_local_read(struct r2nm_node *node, char *page)
+{
+	return sprintf(page, "%d\n", node->nd_local);
+}
+
+static ssize_t r2nm_node_local_write(struct r2nm_node *node, const char *page,
+				     size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
+	unsigned long tmp;
+	char *p = (char *)page;
+	ssize_t ret;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	tmp = !!tmp; /* boolean of whether this node wants to be local */
+
+	/* setting local turns on networking rx for now so we require having
+	 * set everything else first */
+	if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
+	    !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
+		return -EINVAL; /* XXX */
+
+	/* the only failure case is trying to set a new local node
+	 * when a different one is already set */
+	if (tmp && tmp == cluster->cl_has_local &&
+	    cluster->cl_local_node != node->nd_num)
+		return -EBUSY;
+
+	/* bring up the rx thread if we're setting the new local node. */
+	if (tmp && !cluster->cl_has_local) {
+		ret = r2net_start_listening(node);
+		if (ret)
+			return ret;
+	}
+
+	if (!tmp && cluster->cl_has_local &&
+	    cluster->cl_local_node == node->nd_num) {
+		r2net_stop_listening(node);
+		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
+	}
+
+	node->nd_local = tmp;
+	if (node->nd_local) {
+		cluster->cl_has_local = tmp;
+		cluster->cl_local_node = node->nd_num;
+	}
+
+	return count;
+}
+
+struct r2nm_node_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2nm_node *, char *);
+	ssize_t (*store)(struct r2nm_node *, const char *, size_t);
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_num = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "num",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_num_read,
+	.store	= r2nm_node_num_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_ipv4_port = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "ipv4_port",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_ipv4_port_read,
+	.store	= r2nm_node_ipv4_port_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_ipv4_address = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "ipv4_address",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_ipv4_address_read,
+	.store	= r2nm_node_ipv4_address_write,
+};
+
+static struct r2nm_node_attribute r2nm_node_attr_local = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "local",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_node_local_read,
+	.store	= r2nm_node_local_write,
+};
+
+static struct configfs_attribute *r2nm_node_attrs[] = {
+	[R2NM_NODE_ATTR_NUM] = &r2nm_node_attr_num.attr,
+	[R2NM_NODE_ATTR_PORT] = &r2nm_node_attr_ipv4_port.attr,
+	[R2NM_NODE_ATTR_ADDRESS] = &r2nm_node_attr_ipv4_address.attr,
+	[R2NM_NODE_ATTR_LOCAL] = &r2nm_node_attr_local.attr,
+	NULL,
+};
+
+static int r2nm_attr_index(struct configfs_attribute *attr)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(r2nm_node_attrs); i++) {
+		if (attr == r2nm_node_attrs[i])
+			return i;
+	}
+	BUG();
+	return 0;
+}
+
+static ssize_t r2nm_node_show(struct config_item *item,
+			      struct configfs_attribute *attr,
+			      char *page)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_node_attribute *r2nm_node_attr =
+		container_of(attr, struct r2nm_node_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2nm_node_attr->show)
+		ret = r2nm_node_attr->show(node, page);
+	return ret;
+}
+
+static ssize_t r2nm_node_store(struct config_item *item,
+			       struct configfs_attribute *attr,
+			       const char *page, size_t count)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_node_attribute *r2nm_node_attr =
+		container_of(attr, struct r2nm_node_attribute, attr);
+	ssize_t ret;
+	int attr_index = r2nm_attr_index(attr);
+
+	if (r2nm_node_attr->store == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(attr_index, &node->nd_set_attributes))
+		return -EBUSY;
+
+	ret = r2nm_node_attr->store(node, page, count);
+	if (ret < count)
+		goto out;
+
+	set_bit(attr_index, &node->nd_set_attributes);
+out:
+	return ret;
+}
+
+static struct configfs_item_operations r2nm_node_item_ops = {
+	.release		= r2nm_node_release,
+	.show_attribute		= r2nm_node_show,
+	.store_attribute	= r2nm_node_store,
+};
+
+static struct config_item_type r2nm_node_type = {
+	.ct_item_ops	= &r2nm_node_item_ops,
+	.ct_attrs	= r2nm_node_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* node set */
+
+struct r2nm_node_group {
+	struct config_group ns_group;
+	/* some stuff? */
+};
+
+#if 0
+static struct r2nm_node_group *to_r2nm_node_group(struct config_group *group)
+{
+	return group ?
+		container_of(group, struct r2nm_node_group, ns_group)
+		: NULL;
+}
+#endif
+
+struct r2nm_cluster_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct r2nm_cluster *, char *);
+	ssize_t (*store)(struct r2nm_cluster *, const char *, size_t);
+};
+
+static ssize_t r2nm_cluster_attr_write(const char *page, ssize_t count,
+					unsigned int *val)
+{
+	unsigned long tmp;
+	char *p = (char *)page;
+	int err;
+
+	err = kstrtoul(p, 10, &tmp);
+	if (err)
+		return err;
+
+	if (tmp == 0)
+		return -EINVAL;
+	if (tmp >= (u32)-1)
+		return -ERANGE;
+
+	*val = tmp;
+
+	return count;
+}
+
+static ssize_t r2nm_cluster_attr_idle_timeout_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
+}
+
+static ssize_t r2nm_cluster_attr_idle_timeout_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	ssize_t ret;
+	unsigned int val = 0;
+
+	ret =  r2nm_cluster_attr_write(page, count, &val);
+
+	if (ret > 0) {
+		if (cluster->cl_idle_timeout_ms != val
+			&& r2net_num_connected_peers()) {
+			mlog(ML_NOTICE,
+			     "r2net: cannot change idle timeout after "
+			     "the first peer has agreed to it."
+			     "  %d connected peers\n",
+			     r2net_num_connected_peers());
+			ret = -EINVAL;
+		} else if (val <= cluster->cl_keepalive_delay_ms) {
+			mlog(ML_NOTICE,
+			     "r2net: idle timeout must be larger "
+			     "than keepalive delay\n");
+			ret = -EINVAL;
+		} else {
+			cluster->cl_idle_timeout_ms = val;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_keepalive_delay_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_keepalive_delay_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	ssize_t ret;
+	unsigned int val = 0;
+
+	ret =  r2nm_cluster_attr_write(page, count, &val);
+
+	if (ret > 0) {
+		if (cluster->cl_keepalive_delay_ms != val
+		    && r2net_num_connected_peers()) {
+			mlog(ML_NOTICE,
+			     "r2net: cannot change keepalive delay after"
+			     " the first peer has agreed to it."
+			     "  %d connected peers\n",
+			     r2net_num_connected_peers());
+			ret = -EINVAL;
+		} else if (val >= cluster->cl_idle_timeout_ms) {
+			mlog(ML_NOTICE,
+			     "r2net: keepalive delay must be "
+			     "smaller than idle timeout\n");
+			ret = -EINVAL;
+		} else {
+			cluster->cl_keepalive_delay_ms = val;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_reconnect_delay_ms_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_reconnect_delay_ms_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	return r2nm_cluster_attr_write(page, count,
+					&cluster->cl_reconnect_delay_ms);
+}
+
+static ssize_t r2nm_cluster_attr_fence_method_read(
+	struct r2nm_cluster *cluster, char *page)
+{
+	ssize_t ret = 0;
+
+	if (cluster)
+		ret = sprintf(page, "%s\n",
+			      r2nm_fence_method_desc[cluster->cl_fence_method]);
+	return ret;
+}
+
+static ssize_t r2nm_cluster_attr_fence_method_write(
+	struct r2nm_cluster *cluster, const char *page, size_t count)
+{
+	unsigned int i;
+
+	if (page[count - 1] != '\n')
+		goto bail;
+
+	for (i = 0; i < R2NM_FENCE_METHODS; ++i) {
+		if (count != strlen(r2nm_fence_method_desc[i]) + 1)
+			continue;
+		if (strncasecmp(page, r2nm_fence_method_desc[i], count - 1))
+			continue;
+		if (cluster->cl_fence_method != i) {
+			pr_info("ramster: Changing fence method to %s\n",
+			       r2nm_fence_method_desc[i]);
+			cluster->cl_fence_method = i;
+		}
+		return count;
+	}
+
+bail:
+	return -EINVAL;
+}
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_idle_timeout_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "idle_timeout_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_idle_timeout_ms_read,
+	.store	= r2nm_cluster_attr_idle_timeout_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_keepalive_delay_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "keepalive_delay_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_keepalive_delay_ms_read,
+	.store	= r2nm_cluster_attr_keepalive_delay_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_reconnect_delay_ms = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "reconnect_delay_ms",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_reconnect_delay_ms_read,
+	.store	= r2nm_cluster_attr_reconnect_delay_ms_write,
+};
+
+static struct r2nm_cluster_attribute r2nm_cluster_attr_fence_method = {
+	.attr	= { .ca_owner = THIS_MODULE,
+		    .ca_name = "fence_method",
+		    .ca_mode = S_IRUGO | S_IWUSR },
+	.show	= r2nm_cluster_attr_fence_method_read,
+	.store	= r2nm_cluster_attr_fence_method_write,
+};
+
+static struct configfs_attribute *r2nm_cluster_attrs[] = {
+	&r2nm_cluster_attr_idle_timeout_ms.attr,
+	&r2nm_cluster_attr_keepalive_delay_ms.attr,
+	&r2nm_cluster_attr_reconnect_delay_ms.attr,
+	&r2nm_cluster_attr_fence_method.attr,
+	NULL,
+};
+static ssize_t r2nm_cluster_show(struct config_item *item,
+					struct configfs_attribute *attr,
+					char *page)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	struct r2nm_cluster_attribute *r2nm_cluster_attr =
+		container_of(attr, struct r2nm_cluster_attribute, attr);
+	ssize_t ret = 0;
+
+	if (r2nm_cluster_attr->show)
+		ret = r2nm_cluster_attr->show(cluster, page);
+	return ret;
+}
+
+static ssize_t r2nm_cluster_store(struct config_item *item,
+					struct configfs_attribute *attr,
+					const char *page, size_t count)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	struct r2nm_cluster_attribute *r2nm_cluster_attr =
+		container_of(attr, struct r2nm_cluster_attribute, attr);
+	ssize_t ret;
+
+	if (r2nm_cluster_attr->store == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = r2nm_cluster_attr->store(cluster, page, count);
+	if (ret < count)
+		goto out;
+out:
+	return ret;
+}
+
+static struct config_item *r2nm_node_group_make_item(struct config_group *group,
+						     const char *name)
+{
+	struct r2nm_node *node = NULL;
+
+	if (strlen(name) > R2NM_MAX_NAME_LEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	node = kzalloc(sizeof(struct r2nm_node), GFP_KERNEL);
+	if (node == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
+	config_item_init_type_name(&node->nd_item, name, &r2nm_node_type);
+	spin_lock_init(&node->nd_lock);
+
+	mlog(ML_CLUSTER, "r2nm: Registering node %s\n", name);
+
+	return &node->nd_item;
+}
+
+static void r2nm_node_group_drop_item(struct config_group *group,
+				      struct config_item *item)
+{
+	struct r2nm_node *node = to_r2nm_node(item);
+	struct r2nm_cluster *cluster =
+				to_r2nm_cluster(group->cg_item.ci_parent);
+
+	r2net_disconnect_node(node);
+
+	if (cluster->cl_has_local &&
+	    (cluster->cl_local_node == node->nd_num)) {
+		cluster->cl_has_local = 0;
+		cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
+		r2net_stop_listening(node);
+	}
+
+	/* XXX call into net to stop this node from trading messages */
+
+	write_lock(&cluster->cl_nodes_lock);
+
+	/* XXX sloppy */
+	if (node->nd_ipv4_address)
+		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
+
+	/* nd_num might be 0 if the node number hasn't been set.. */
+	if (cluster->cl_nodes[node->nd_num] == node) {
+		cluster->cl_nodes[node->nd_num] = NULL;
+		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
+	}
+	write_unlock(&cluster->cl_nodes_lock);
+
+	mlog(ML_CLUSTER, "r2nm: Unregistered node %s\n",
+	     config_item_name(&node->nd_item));
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations r2nm_node_group_group_ops = {
+	.make_item	= r2nm_node_group_make_item,
+	.drop_item	= r2nm_node_group_drop_item,
+};
+
+static struct config_item_type r2nm_node_group_type = {
+	.ct_group_ops	= &r2nm_node_group_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* cluster */
+
+static void r2nm_cluster_release(struct config_item *item)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+
+	kfree(cluster->cl_group.default_groups);
+	kfree(cluster);
+}
+
+static struct configfs_item_operations r2nm_cluster_item_ops = {
+	.release	= r2nm_cluster_release,
+	.show_attribute		= r2nm_cluster_show,
+	.store_attribute	= r2nm_cluster_store,
+};
+
+static struct config_item_type r2nm_cluster_type = {
+	.ct_item_ops	= &r2nm_cluster_item_ops,
+	.ct_attrs	= r2nm_cluster_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* cluster set */
+
+struct r2nm_cluster_group {
+	struct configfs_subsystem cs_subsys;
+	/* some stuff? */
+};
+
+#if 0
+static struct r2nm_cluster_group *
+to_r2nm_cluster_group(struct config_group *group)
+{
+	return group ?
+		container_of(to_configfs_subsystem(group),
+				struct r2nm_cluster_group, cs_subsys)
+	       : NULL;
+}
+#endif
+
+static struct config_group *
+r2nm_cluster_group_make_group(struct config_group *group,
+							  const char *name)
+{
+	struct r2nm_cluster *cluster = NULL;
+	struct r2nm_node_group *ns = NULL;
+	struct config_group *r2hb_group = NULL, *ret = NULL;
+	void *defs = NULL;
+
+	/* this runs under the parent dir's i_mutex; there can be only
+	 * one caller in here at a time */
+	if (r2nm_single_cluster)
+		return ERR_PTR(-ENOSPC);
+
+	cluster = kzalloc(sizeof(struct r2nm_cluster), GFP_KERNEL);
+	ns = kzalloc(sizeof(struct r2nm_node_group), GFP_KERNEL);
+	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
+	r2hb_group = r2hb_alloc_hb_set();
+	if (cluster == NULL || ns == NULL || r2hb_group == NULL || defs == NULL)
+		goto out;
+
+	config_group_init_type_name(&cluster->cl_group, name,
+				    &r2nm_cluster_type);
+	config_group_init_type_name(&ns->ns_group, "node",
+				    &r2nm_node_group_type);
+
+	cluster->cl_group.default_groups = defs;
+	cluster->cl_group.default_groups[0] = &ns->ns_group;
+	cluster->cl_group.default_groups[1] = r2hb_group;
+	cluster->cl_group.default_groups[2] = NULL;
+	rwlock_init(&cluster->cl_nodes_lock);
+	cluster->cl_node_ip_tree = RB_ROOT;
+	cluster->cl_reconnect_delay_ms = R2NET_RECONNECT_DELAY_MS_DEFAULT;
+	cluster->cl_idle_timeout_ms    = R2NET_IDLE_TIMEOUT_MS_DEFAULT;
+	cluster->cl_keepalive_delay_ms = R2NET_KEEPALIVE_DELAY_MS_DEFAULT;
+	cluster->cl_fence_method       = R2NM_FENCE_RESET;
+
+	ret = &cluster->cl_group;
+	r2nm_single_cluster = cluster;
+
+out:
+	if (ret == NULL) {
+		kfree(cluster);
+		kfree(ns);
+		r2hb_free_hb_set(r2hb_group);
+		kfree(defs);
+		ret = ERR_PTR(-ENOMEM);
+	}
+
+	return ret;
+}
+
+static void r2nm_cluster_group_drop_item(struct config_group *group,
+						struct config_item *item)
+{
+	struct r2nm_cluster *cluster = to_r2nm_cluster(item);
+	int i;
+	struct config_item *killme;
+
+	BUG_ON(r2nm_single_cluster != cluster);
+	r2nm_single_cluster = NULL;
+
+	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
+		killme = &cluster->cl_group.default_groups[i]->cg_item;
+		cluster->cl_group.default_groups[i] = NULL;
+		config_item_put(killme);
+	}
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations r2nm_cluster_group_group_ops = {
+	.make_group	= r2nm_cluster_group_make_group,
+	.drop_item	= r2nm_cluster_group_drop_item,
+};
+
+static struct config_item_type r2nm_cluster_group_type = {
+	.ct_group_ops	= &r2nm_cluster_group_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct r2nm_cluster_group r2nm_cluster_group = {
+	.cs_subsys = {
+		.su_group = {
+			.cg_item = {
+				.ci_namebuf = "cluster",
+				.ci_type = &r2nm_cluster_group_type,
+			},
+		},
+	},
+};
+
+int r2nm_depend_item(struct config_item *item)
+{
+	return configfs_depend_item(&r2nm_cluster_group.cs_subsys, item);
+}
+
+void r2nm_undepend_item(struct config_item *item)
+{
+	configfs_undepend_item(&r2nm_cluster_group.cs_subsys, item);
+}
+
+int r2nm_depend_this_node(void)
+{
+	int ret = 0;
+	struct r2nm_node *local_node;
+
+	local_node = r2nm_get_node_by_num(r2nm_this_node());
+	if (!local_node) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = r2nm_depend_item(&local_node->nd_item);
+	r2nm_node_put(local_node);
+
+out:
+	return ret;
+}
+
+void r2nm_undepend_this_node(void)
+{
+	struct r2nm_node *local_node;
+
+	local_node = r2nm_get_node_by_num(r2nm_this_node());
+	BUG_ON(!local_node);
+
+	r2nm_undepend_item(&local_node->nd_item);
+	r2nm_node_put(local_node);
+}
+
+
+static void __exit exit_r2nm(void)
+{
+	/* XXX sync with hb callbacks and shut down hb? */
+	r2net_unregister_hb_callbacks();
+	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
+
+	r2net_exit();
+	r2hb_exit();
+}
+
+static int __init init_r2nm(void)
+{
+	int ret = -1;
+
+	ret = r2hb_init();
+	if (ret)
+		goto out;
+
+	ret = r2net_init();
+	if (ret)
+		goto out_r2hb;
+
+	ret = r2net_register_hb_callbacks();
+	if (ret)
+		goto out_r2net;
+
+	config_group_init(&r2nm_cluster_group.cs_subsys.su_group);
+	mutex_init(&r2nm_cluster_group.cs_subsys.su_mutex);
+	ret = configfs_register_subsystem(&r2nm_cluster_group.cs_subsys);
+	if (ret) {
+		pr_err("nodemanager: Registration returned %d\n", ret);
+		goto out_callbacks;
+	}
+
+	if (!ret)
+		goto out;
+
+	configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
+out_callbacks:
+	r2net_unregister_hb_callbacks();
+out_r2net:
+	r2net_exit();
+out_r2hb:
+	r2hb_exit();
+out:
+	return ret;
+}
+
+MODULE_AUTHOR("Oracle");
+MODULE_LICENSE("GPL");
+
+/* module_init(init_r2nm) */
+late_initcall(init_r2nm);
+/* module_exit(exit_r2nm) */
diff --git a/drivers/staging/ramster/cluster/nodemanager.h b/drivers/staging/ramster/ramster/nodemanager.h
similarity index 100%
rename from drivers/staging/ramster/cluster/nodemanager.h
rename to drivers/staging/ramster/ramster/nodemanager.h
diff --git a/drivers/staging/ramster/ramster/r2net.c b/drivers/staging/ramster/ramster/r2net.c
new file mode 100644
index 0000000..34818dc
--- /dev/null
+++ b/drivers/staging/ramster/ramster/r2net.c
@@ -0,0 +1,414 @@
+/*
+ * r2net.c
+ *
+ * Copyright (c) 2011-2012, Dan Magenheimer, Oracle Corp.
+ *
+ * Ramster_r2net provides an interface between zcache and r2net.
+ *
+ * FIXME: support more than two nodes
+ */
+
+#include <linux/list.h>
+#include "tcp.h"
+#include "nodemanager.h"
+#include "../tmem.h"
+#include "../zcache.h"
+#include "ramster.h"
+
+#define RAMSTER_TESTING
+
+#define RMSTR_KEY	0x77347734
+
+enum {
+	RMSTR_TMEM_PUT_EPH = 100,
+	RMSTR_TMEM_PUT_PERS,
+	RMSTR_TMEM_ASYNC_GET_REQUEST,
+	RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
+	RMSTR_TMEM_ASYNC_GET_REPLY,
+	RMSTR_TMEM_FLUSH,
+	RMSTR_TMEM_FLOBJ,
+	RMSTR_TMEM_DESTROY_POOL,
+};
+
+#define RMSTR_R2NET_MAX_LEN \
+		(R2NET_MAX_PAYLOAD_BYTES - sizeof(struct tmem_xhandle))
+
+#include "tcp_internal.h"
+
+static struct r2nm_node *r2net_target_node;
+static int r2net_target_nodenum;
+
+int r2net_remote_target_node_set(int node_num)
+{
+	int ret = -1;
+
+	r2net_target_node = r2nm_get_node_by_num(node_num);
+	if (r2net_target_node != NULL) {
+		r2net_target_nodenum = node_num;
+		r2nm_node_put(r2net_target_node);
+		ret = 0;
+	}
+	return ret;
+}
+
+/* FIXME following buffer should be per-cpu, protected by preempt_disable */
+static char ramster_async_get_buf[R2NET_MAX_PAYLOAD_BYTES];
+
+static int ramster_remote_async_get_request_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	char *pdata;
+	struct tmem_xhandle xh;
+	int found;
+	size_t size = RMSTR_R2NET_MAX_LEN;
+	u16 msgtype = be16_to_cpu(msg->msg_type);
+	bool get_and_free = (msgtype == RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST);
+	unsigned long flags;
+
+	xh = *(struct tmem_xhandle *)msg->buf;
+	if (xh.xh_data_size > RMSTR_R2NET_MAX_LEN)
+		BUG();
+	pdata = ramster_async_get_buf;
+	*(struct tmem_xhandle *)pdata = xh;
+	pdata += sizeof(struct tmem_xhandle);
+	local_irq_save(flags);
+	found = zcache_get_page(xh.client_id, xh.pool_id, &xh.oid, xh.index,
+				pdata, &size, true, get_and_free ? 1 : -1);
+	local_irq_restore(flags);
+	if (found < 0) {
+		/* a zero size indicates the get failed */
+		size = 0;
+	}
+	if (size > RMSTR_R2NET_MAX_LEN)
+		BUG();
+	*ret_data = pdata - sizeof(struct tmem_xhandle);
+	/* now make caller (r2net_process_message) handle specially */
+	r2net_force_data_magic(msg, RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY);
+	return size + sizeof(struct tmem_xhandle);
+}
+
+static int ramster_remote_async_get_reply_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	char *in = (char *)msg->buf;
+	int datalen = len - sizeof(struct r2net_msg);
+	int ret = -1;
+	struct tmem_xhandle *xh = (struct tmem_xhandle *)in;
+
+	in += sizeof(struct tmem_xhandle);
+	datalen -= sizeof(struct tmem_xhandle);
+	BUG_ON(datalen < 0 || datalen > PAGE_SIZE);
+	ret = ramster_localify(xh->pool_id, &xh->oid, xh->index,
+				in, datalen, xh->extra);
+#ifdef RAMSTER_TESTING
+	if (ret == -EEXIST)
+		pr_err("TESTING ArrgREP, aborted overwrite on racy put\n");
+#endif
+	return ret;
+}
+
+int ramster_remote_put_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+	int datalen = len - sizeof(struct r2net_msg) -
+				sizeof(struct tmem_xhandle);
+	u16 msgtype = be16_to_cpu(msg->msg_type);
+	bool ephemeral = (msgtype == RMSTR_TMEM_PUT_EPH);
+	unsigned long flags;
+	int ret;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	zcache_autocreate_pool(xh->client_id, xh->pool_id, ephemeral);
+	local_irq_save(flags);
+	ret = zcache_put_page(xh->client_id, xh->pool_id, &xh->oid, xh->index,
+				p, datalen, true, ephemeral);
+	local_irq_restore(flags);
+	return ret;
+}
+
+int ramster_remote_flush_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	(void)zcache_flush_page(xh->client_id, xh->pool_id,
+					&xh->oid, xh->index);
+	return 0;
+}
+
+int ramster_remote_flobj_handler(struct r2net_msg *msg,
+				u32 len, void *data, void **ret_data)
+{
+	struct tmem_xhandle *xh;
+	char *p = (char *)msg->buf;
+
+	xh = (struct tmem_xhandle *)p;
+	p += sizeof(struct tmem_xhandle);
+	(void)zcache_flush_object(xh->client_id, xh->pool_id, &xh->oid);
+	return 0;
+}
+
+int r2net_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode,
+				size_t expect_size, uint8_t expect_cksum,
+				void *extra)
+{
+	int nodenum, ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+	u32 msg_type;
+	struct r2net_node *nn;
+
+	node = r2nm_get_node_by_num(remotenode);
+	if (node == NULL)
+		goto out;
+	xh->client_id = r2nm_this_node(); /* which node is getting */
+	xh->xh_data_cksum = expect_cksum;
+	xh->xh_data_size = expect_size;
+	xh->extra = extra;
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+
+	node = r2net_target_node;
+	if (!node)
+		goto out;
+
+	nodenum = r2net_target_nodenum;
+
+	r2nm_node_get(node);
+	nn = r2net_nn_from_num(nodenum);
+	if (nn->nn_persistent_error || !nn->nn_sc_valid) {
+		ret = -ENOTCONN;
+		r2nm_node_put(node);
+		goto out;
+	}
+
+	if (free)
+		msg_type = RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST;
+	else
+		msg_type = RMSTR_TMEM_ASYNC_GET_REQUEST;
+	ret = r2net_send_message_vec(msg_type, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	if (ret < 0) {
+		if (ret == -ENOTCONN || ret == -EHOSTDOWN)
+			goto out;
+		if (ret == -EAGAIN)
+			goto out;
+		/* FIXME handle bad message possibilities here? */
+		pr_err("UNTESTED ret<0 in ramster_remote_async_get: ret=%d\n",
+				ret);
+	}
+	ret = status;
+out:
+	return ret;
+}
+
+#ifdef RAMSTER_TESTING
+/* leave me here to see if it catches a weird crash */
+static void ramster_check_irq_counts(void)
+{
+	static int last_hardirq_cnt, last_softirq_cnt, last_preempt_cnt;
+	int cur_hardirq_cnt, cur_softirq_cnt, cur_preempt_cnt;
+
+	cur_hardirq_cnt = hardirq_count() >> HARDIRQ_SHIFT;
+	if (cur_hardirq_cnt > last_hardirq_cnt) {
+		last_hardirq_cnt = cur_hardirq_cnt;
+		if (!(last_hardirq_cnt&(last_hardirq_cnt-1)))
+			pr_err("RAMSTER TESTING RRP hardirq_count=%d\n",
+				last_hardirq_cnt);
+	}
+	cur_softirq_cnt = softirq_count() >> SOFTIRQ_SHIFT;
+	if (cur_softirq_cnt > last_softirq_cnt) {
+		last_softirq_cnt = cur_softirq_cnt;
+		if (!(last_softirq_cnt&(last_softirq_cnt-1)))
+			pr_err("RAMSTER TESTING RRP softirq_count=%d\n",
+				last_softirq_cnt);
+	}
+	cur_preempt_cnt = preempt_count() & PREEMPT_MASK;
+	if (cur_preempt_cnt > last_preempt_cnt) {
+		last_preempt_cnt = cur_preempt_cnt;
+		if (!(last_preempt_cnt&(last_preempt_cnt-1)))
+			pr_err("RAMSTER TESTING RRP preempt_count=%d\n",
+				last_preempt_cnt);
+	}
+}
+#endif
+
+int r2net_remote_put(struct tmem_xhandle *xh, char *data, size_t size,
+				bool ephemeral, int *remotenode)
+{
+	int nodenum, ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[2];
+	size_t veclen = 2;
+	u32 msg_type;
+	struct r2net_node *nn;
+
+	BUG_ON(size > RMSTR_R2NET_MAX_LEN);
+	xh->client_id = r2nm_this_node(); /* which node is putting */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	vec[1].iov_len = size;
+	vec[1].iov_base = data;
+
+	node = r2net_target_node;
+	if (!node)
+		goto out;
+
+	nodenum = r2net_target_nodenum;
+
+	r2nm_node_get(node);
+
+	nn = r2net_nn_from_num(nodenum);
+	if (nn->nn_persistent_error || !nn->nn_sc_valid) {
+		ret = -ENOTCONN;
+		r2nm_node_put(node);
+		goto out;
+	}
+
+	if (ephemeral)
+		msg_type = RMSTR_TMEM_PUT_EPH;
+	else
+		msg_type = RMSTR_TMEM_PUT_PERS;
+#ifdef RAMSTER_TESTING
+	/* leave me here to see if it catches a weird crash */
+	ramster_check_irq_counts();
+#endif
+
+	ret = r2net_send_message_vec(msg_type, RMSTR_KEY, vec, veclen,
+						nodenum, &status);
+	if (ret < 0)
+		ret = -1;
+	else {
+		ret = status;
+		*remotenode = nodenum;
+	}
+
+	r2nm_node_put(node);
+out:
+	return ret;
+}
+
+int r2net_remote_flush(struct tmem_xhandle *xh, int remotenode)
+{
+	int ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+
+	node = r2nm_get_node_by_num(remotenode);
+	BUG_ON(node == NULL);
+	xh->client_id = r2nm_this_node(); /* which node is flushing */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	BUG_ON(irqs_disabled());
+	BUG_ON(in_softirq());
+	ret = r2net_send_message_vec(RMSTR_TMEM_FLUSH, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	return ret;
+}
+
+int r2net_remote_flush_object(struct tmem_xhandle *xh, int remotenode)
+{
+	int ret = -1, status;
+	struct r2nm_node *node = NULL;
+	struct kvec vec[1];
+	size_t veclen = 1;
+
+	node = r2nm_get_node_by_num(remotenode);
+	BUG_ON(node == NULL);
+	xh->client_id = r2nm_this_node(); /* which node is flobjing */
+	vec[0].iov_len = sizeof(*xh);
+	vec[0].iov_base = xh;
+	ret = r2net_send_message_vec(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
+					vec, veclen, remotenode, &status);
+	r2nm_node_put(node);
+	return ret;
+}
+
+/*
+ * Handler registration
+ */
+
+static LIST_HEAD(r2net_unreg_list);
+
+static void r2net_unregister_handlers(void)
+{
+	r2net_unregister_handler_list(&r2net_unreg_list);
+}
+
+int r2net_register_handlers(void)
+{
+	int status;
+
+	status = r2net_register_handler(RMSTR_TMEM_PUT_EPH, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_put_handler,
+				NULL, NULL, &r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_PUT_PERS, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_put_handler,
+				NULL, NULL, &r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REQUEST, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_request_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
+				RMSTR_KEY, RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_request_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_async_get_reply_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_FLUSH, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_flush_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	status = r2net_register_handler(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
+				RMSTR_R2NET_MAX_LEN,
+				ramster_remote_flobj_handler,
+				NULL, NULL,
+				&r2net_unreg_list);
+	if (status)
+		goto bail;
+
+	pr_info("ramster: r2net handlers registered\n");
+
+bail:
+	if (status) {
+		r2net_unregister_handlers();
+		pr_err("ramster: couldn't register r2net handlers\n");
+	}
+	return status;
+}
diff --git a/drivers/staging/ramster/ramster/ramster.c b/drivers/staging/ramster/ramster/ramster.c
new file mode 100644
index 0000000..c06709f3
--- /dev/null
+++ b/drivers/staging/ramster/ramster/ramster.c
@@ -0,0 +1,985 @@
+/*
+ * ramster.c
+ *
+ * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
+ *
+ * RAMster implements peer-to-peer transcendent memory, allowing a "cluster" of
+ * kernels to dynamically pool their RAM so that a RAM-hungry workload on one
+ * machine can temporarily and transparently utilize RAM on another machine
+ * which is presumably idle or running a non-RAM-hungry workload.
+ *
+ * RAMster combines a clustering and messaging foundation based on the ocfs2
+ * cluster layer with the in-kernel compression implementation of zcache, and
+ * adds code to glue them together.  When a page is "put" to RAMster, it is
+ * compressed and stored locally.  Periodically, a thread will "remotify" these
+ * pages by sending them via messages to a remote machine.  When the page is
+ * later needed as indicated by a page fault, a "get" is issued.  If the data
+ * is local, it is uncompressed and the fault is resolved.  If the data is
+ * remote, a message is sent to fetch the data and the faulting thread sleeps;
+ * when the data arrives, the thread awakens, the data is decompressed and
+ * the fault is resolved.
+
+ * As of V5, clusters up to eight nodes are supported; each node can remotify
+ * pages to one specified node, so clusters can be configured as clients to
+ * a "memory server".  Some simple policy is in place that will need to be
+ * refined over time.  Larger clusters and fault-resistant protocols can also
+ * be added over time.
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/lzo.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/frontswap.h>
+#include "../tmem.h"
+#include "../zcache.h"
+#include "../zbud.h"
+#include "ramster.h"
+#include "ramster_nodemanager.h"
+#include "tcp.h"
+
+#define RAMSTER_TESTING
+
+#ifndef CONFIG_SYSFS
+#error "ramster needs sysfs to define cluster nodes to use"
+#endif
+
+static bool use_cleancache __read_mostly;
+static bool use_frontswap __read_mostly;
+static bool use_frontswap_exclusive_gets __read_mostly;
+
+/* These must be sysfs not debugfs as they are checked/used by userland!! */
+static unsigned long ramster_interface_revision __read_mostly =
+	R2NM_API_VERSION; /* interface revision must match userspace! */
+static unsigned long ramster_pers_remotify_enable __read_mostly;
+static unsigned long ramster_eph_remotify_enable __read_mostly;
+static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
+#define MANUAL_NODES 8
+static bool ramster_nodes_manual_up[MANUAL_NODES] __read_mostly;
+static int ramster_remote_target_nodenum __read_mostly = -1;
+
+/* these counters are made available via debugfs */
+static long ramster_flnodes;
+static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0);
+static unsigned long ramster_flnodes_max;
+static long ramster_foreign_eph_pages;
+static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0);
+static unsigned long ramster_foreign_eph_pages_max;
+static long ramster_foreign_pers_pages;
+static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0);
+static unsigned long ramster_foreign_pers_pages_max;
+static unsigned long ramster_eph_pages_remoted;
+static unsigned long ramster_pers_pages_remoted;
+static unsigned long ramster_eph_pages_remote_failed;
+static unsigned long ramster_pers_pages_remote_failed;
+static unsigned long ramster_remote_eph_pages_succ_get;
+static unsigned long ramster_remote_pers_pages_succ_get;
+static unsigned long ramster_remote_eph_pages_unsucc_get;
+static unsigned long ramster_remote_pers_pages_unsucc_get;
+static unsigned long ramster_pers_pages_remote_nomem;
+static unsigned long ramster_remote_objects_flushed;
+static unsigned long ramster_remote_object_flushes_failed;
+static unsigned long ramster_remote_pages_flushed;
+static unsigned long ramster_remote_page_flushes_failed;
+/* FIXME frontswap selfshrinking knobs in debugfs? */
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#define	zdfs	debugfs_create_size_t
+#define	zdfs64	debugfs_create_u64
+static int __init ramster_debugfs_init(void)
+{
+	struct dentry *root = debugfs_create_dir("ramster", NULL);
+	if (root == NULL)
+		return -ENXIO;
+
+	zdfs("eph_pages_remoted", S_IRUGO, root, &ramster_eph_pages_remoted);
+	zdfs("pers_pages_remoted", S_IRUGO, root, &ramster_pers_pages_remoted);
+	zdfs("eph_pages_remote_failed", S_IRUGO, root,
+			&ramster_eph_pages_remote_failed);
+	zdfs("pers_pages_remote_failed", S_IRUGO, root,
+			&ramster_pers_pages_remote_failed);
+	zdfs("remote_eph_pages_succ_get", S_IRUGO, root,
+			&ramster_remote_eph_pages_succ_get);
+	zdfs("remote_pers_pages_succ_get", S_IRUGO, root,
+			&ramster_remote_pers_pages_succ_get);
+	zdfs("remote_eph_pages_unsucc_get", S_IRUGO, root,
+			&ramster_remote_eph_pages_unsucc_get);
+	zdfs("remote_pers_pages_unsucc_get", S_IRUGO, root,
+			&ramster_remote_pers_pages_unsucc_get);
+	zdfs("pers_pages_remote_nomem", S_IRUGO, root,
+			&ramster_pers_pages_remote_nomem);
+	zdfs("remote_objects_flushed", S_IRUGO, root,
+			&ramster_remote_objects_flushed);
+	zdfs("remote_pages_flushed", S_IRUGO, root,
+			&ramster_remote_pages_flushed);
+	zdfs("remote_object_flushes_failed", S_IRUGO, root,
+			&ramster_remote_object_flushes_failed);
+	zdfs("remote_page_flushes_failed", S_IRUGO, root,
+			&ramster_remote_page_flushes_failed);
+	zdfs("foreign_eph_pages", S_IRUGO, root,
+			&ramster_foreign_eph_pages);
+	zdfs("foreign_eph_pages_max", S_IRUGO, root,
+			&ramster_foreign_eph_pages_max);
+	zdfs("foreign_pers_pages", S_IRUGO, root,
+			&ramster_foreign_pers_pages);
+	zdfs("foreign_pers_pages_max", S_IRUGO, root,
+			&ramster_foreign_pers_pages_max);
+	return 0;
+}
+#undef	zdebugfs
+#undef	zdfs64
+#endif
+
+static LIST_HEAD(ramster_rem_op_list);
+static DEFINE_SPINLOCK(ramster_rem_op_list_lock);
+static DEFINE_PER_CPU(struct ramster_preload, ramster_preloads);
+
+static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem1);
+static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem2);
+
+static struct kmem_cache *ramster_flnode_cache __read_mostly;
+
+static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
+{
+	struct flushlist_node *flnode = NULL;
+	struct ramster_preload *kp;
+
+	kp = &__get_cpu_var(ramster_preloads);
+	flnode = kp->flnode;
+	BUG_ON(flnode == NULL);
+	kp->flnode = NULL;
+	ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic);
+	if (ramster_flnodes > ramster_flnodes_max)
+		ramster_flnodes_max = ramster_flnodes;
+	return flnode;
+}
+
+/* the "flush list" asynchronously collects pages to remotely flush */
+#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1)
+static void ramster_flnode_free(struct flushlist_node *flnode,
+				struct tmem_pool *pool)
+{
+	int flnodes;
+
+	flnodes = atomic_dec_return(&ramster_flnodes_atomic);
+	BUG_ON(flnodes < 0);
+	kmem_cache_free(ramster_flnode_cache, flnode);
+}
+
+int ramster_do_preload_flnode(struct tmem_pool *pool)
+{
+	struct ramster_preload *kp;
+	struct flushlist_node *flnode;
+	int ret = -ENOMEM;
+
+	BUG_ON(!irqs_disabled());
+	if (unlikely(ramster_flnode_cache == NULL))
+		BUG();
+	kp = &__get_cpu_var(ramster_preloads);
+	flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC);
+	if (unlikely(flnode == NULL) && kp->flnode == NULL)
+		BUG();  /* FIXME handle more gracefully, but how??? */
+	else if (kp->flnode == NULL)
+		kp->flnode = flnode;
+	else
+		kmem_cache_free(ramster_flnode_cache, flnode);
+	return ret;
+}
+
+/*
+ * Called by the message handler after a (still compressed) page has been
+ * fetched from the remote machine in response to an "is_remote" tmem_get
+ * or persistent tmem_localify.  For a tmem_get, "extra" is the address of
+ * the page that is to be filled to successfully resolve the tmem_get; for
+ * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
+ * in the local zcache).  "data" points to "size" bytes of (compressed) data
+ * passed in the message.  In the case of a persistent remote get, if
+ * pre-allocation was successful (see ramster_repatriate_preload), the page
+ * is placed into both local zcache and at "extra".
+ */
+int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
+			char *data, unsigned int size, void *extra)
+{
+	int ret = -ENOENT;
+	unsigned long flags;
+	struct tmem_pool *pool;
+	bool eph, delete = false;
+	void *pampd, *saved_hb;
+	struct tmem_obj *obj;
+
+	pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
+	if (unlikely(pool == NULL))
+		/* pool doesn't exist anymore */
+		goto out;
+	eph = is_ephemeral(pool);
+	local_irq_save(flags);  /* FIXME: maybe only disable softirqs? */
+	pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb);
+	if (pampd == NULL) {
+		/* hmmm... must have been a flush while waiting */
+#ifdef RAMSTER_TESTING
+		pr_err("UNTESTED pampd==NULL in ramster_localify\n");
+#endif
+		if (eph)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			ramster_remote_pers_pages_unsucc_get++;
+		obj = NULL;
+		goto finish;
+	} else if (unlikely(!pampd_is_remote(pampd))) {
+		/* hmmm... must have been a dup put while waiting */
+#ifdef RAMSTER_TESTING
+		pr_err("UNTESTED dup while waiting in ramster_localify\n");
+#endif
+		if (eph)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			ramster_remote_pers_pages_unsucc_get++;
+		obj = NULL;
+		pampd = NULL;
+		ret = -EEXIST;
+		goto finish;
+	} else if (size == 0) {
+		/* no remote data, delete the local is_remote pampd */
+		pampd = NULL;
+		if (eph)
+			ramster_remote_eph_pages_unsucc_get++;
+		else
+			BUG();
+		delete = true;
+		goto finish;
+	}
+	if (pampd_is_intransit(pampd)) {
+		/*
+		 *  a pampd is marked intransit if it is remote and space has
+		 *  been allocated for it locally (note, only happens for
+		 *  persistent pages, in which case the remote copy is freed)
+		 */
+		BUG_ON(eph);
+		pampd = pampd_mask_intransit_and_remote(pampd);
+		zbud_copy_to_zbud(pampd, data, size);
+	} else {
+		/*
+		 * setting pampd to NULL tells tmem_localify_finish to leave
+		 * pampd alone... meaning it is left pointing to the
+		 * remote copy
+		 */
+		pampd = NULL;
+		obj = NULL;
+	}
+	/*
+	 * but in all cases, we decompress direct-to-memory to complete
+	 * the remotify and return success
+	 */
+	BUG_ON(extra == NULL);
+	zcache_decompress_to_page(data, size, (struct page *)extra);
+	if (eph)
+		ramster_remote_eph_pages_succ_get++;
+	else
+		ramster_remote_pers_pages_succ_get++;
+	ret = 0;
+finish:
+	tmem_localify_finish(obj, index, pampd, saved_hb, delete);
+	zcache_put_pool(pool);
+	local_irq_restore(flags);
+out:
+	return ret;
+}
+
+void ramster_pampd_new_obj(struct tmem_obj *obj)
+{
+	obj->extra = NULL;
+}
+
+void ramster_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj,
+				bool pool_destroy)
+{
+	struct flushlist_node *flnode;
+
+	BUG_ON(preemptible());
+	if (obj->extra == NULL)
+		return;
+	if (pool_destroy && is_ephemeral(pool))
+		/* FIXME don't bother with remote eph data for now */
+		return;
+	BUG_ON(!pampd_is_remote(obj->extra));
+	flnode = ramster_flnode_alloc(pool);
+	flnode->xh.client_id = pampd_remote_node(obj->extra);
+	flnode->xh.pool_id = pool->pool_id;
+	flnode->xh.oid = obj->oid;
+	flnode->xh.index = FLUSH_ENTIRE_OBJECT;
+	flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ;
+	spin_lock(&ramster_rem_op_list_lock);
+	list_add(&flnode->rem_op.list, &ramster_rem_op_list);
+	spin_unlock(&ramster_rem_op_list_lock);
+}
+
+/*
+ * Called on a remote persistent tmem_get to attempt to preallocate
+ * local storage for the data contained in the remote persistent page.
+ * If successfully preallocated, returns the pampd, marked as remote and
+ * in_transit.  Else returns NULL.  Note that the appropriate tmem data
+ * structure must be locked.
+ */
+void *ramster_pampd_repatriate_preload(void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oidp, uint32_t index,
+					bool *intransit)
+{
+	int clen = pampd_remote_size(pampd), c;
+	void *ret_pampd = NULL;
+	unsigned long flags;
+	struct tmem_handle th;
+
+	BUG_ON(!pampd_is_remote(pampd));
+	BUG_ON(is_ephemeral(pool));
+	if (use_frontswap_exclusive_gets)
+		/* don't need local storage */
+		goto out;
+	if (pampd_is_intransit(pampd)) {
+		/*
+		 * to avoid multiple allocations (and maybe a memory leak)
+		 * don't preallocate if already in the process of being
+		 * repatriated
+		 */
+		*intransit = true;
+		goto out;
+	}
+	*intransit = false;
+	local_irq_save(flags);
+	th.client_id = pampd_remote_node(pampd);
+	th.pool_id = pool->pool_id;
+	th.oid = *oidp;
+	th.index = index;
+	ret_pampd = zcache_pampd_create(NULL, clen, true, false, &th);
+	if (ret_pampd != NULL) {
+		/*
+		 *  a pampd is marked intransit if it is remote and space has
+		 *  been allocated for it locally (note, only happens for
+		 *  persistent pages, in which case the remote copy is freed)
+		 */
+		ret_pampd = pampd_mark_intransit(ret_pampd);
+		c = atomic_dec_return(&ramster_remote_pers_pages);
+		WARN_ON_ONCE(c < 0);
+	} else {
+		ramster_pers_pages_remote_nomem++;
+	}
+	local_irq_restore(flags);
+out:
+	return ret_pampd;
+}
+
+/*
+ * Called on a remote tmem_get to invoke a message to fetch the page.
+ * Might sleep so no tmem locks can be held.  "extra" is passed
+ * all the way through the round-trip messaging to ramster_localify.
+ */
+int ramster_pampd_repatriate(void *fake_pampd, void *real_pampd,
+				struct tmem_pool *pool,
+				struct tmem_oid *oid, uint32_t index,
+				bool free, void *extra)
+{
+	struct tmem_xhandle xh;
+	int ret;
+
+	if (pampd_is_intransit(real_pampd))
+		/* have local space pre-reserved, so free remote copy */
+		free = true;
+	xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index);
+	/* unreliable request/response for now */
+	ret = r2net_remote_async_get(&xh, free,
+					pampd_remote_node(fake_pampd),
+					pampd_remote_size(fake_pampd),
+					pampd_remote_cksum(fake_pampd),
+					extra);
+	return ret;
+}
+
+bool ramster_pampd_is_remote(void *pampd)
+{
+	return pampd_is_remote(pampd);
+}
+
+int ramster_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
+{
+	int ret = -1;
+
+	if (new_pampd != NULL) {
+		if (obj->extra == NULL)
+			obj->extra = new_pampd;
+		/* enforce that all remote pages in an object reside
+		 * in the same node! */
+		else if (pampd_remote_node(new_pampd) !=
+				pampd_remote_node((void *)(obj->extra)))
+			BUG();
+		ret = 0;
+	}
+	return ret;
+}
+
+void *ramster_pampd_free(void *pampd, struct tmem_pool *pool,
+			      struct tmem_oid *oid, uint32_t index, bool acct)
+{
+	bool eph = is_ephemeral(pool);
+	void *local_pampd = NULL;
+	int c;
+
+	BUG_ON(preemptible());
+	BUG_ON(!pampd_is_remote(pampd));
+	WARN_ON(acct == false);
+	if (oid == NULL) {
+		/*
+		 * a NULL oid means to ignore this pampd free
+		 * as the remote freeing will be handled elsewhere
+		 */
+	} else if (eph) {
+		/* FIXME remote flush optional but probably good idea */
+	} else if (pampd_is_intransit(pampd)) {
+		/* did a pers remote get_and_free, so just free local */
+		local_pampd = pampd_mask_intransit_and_remote(pampd);
+	} else {
+		struct flushlist_node *flnode =
+			ramster_flnode_alloc(pool);
+
+		flnode->xh.client_id = pampd_remote_node(pampd);
+		flnode->xh.pool_id = pool->pool_id;
+		flnode->xh.oid = *oid;
+		flnode->xh.index = index;
+		flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE;
+		spin_lock(&ramster_rem_op_list_lock);
+		list_add(&flnode->rem_op.list, &ramster_rem_op_list);
+		spin_unlock(&ramster_rem_op_list_lock);
+		c = atomic_dec_return(&ramster_remote_pers_pages);
+		WARN_ON_ONCE(c < 0);
+	}
+	return local_pampd;
+}
+
+void ramster_count_foreign_pages(bool eph, int count)
+{
+	int c;
+
+	BUG_ON(count != 1 && count != -1);
+	if (eph) {
+		if (count > 0) {
+			c = atomic_inc_return(
+					&ramster_foreign_eph_pages_atomic);
+			if (c > ramster_foreign_eph_pages_max)
+				ramster_foreign_eph_pages_max = c;
+		} else {
+			c = atomic_dec_return(&ramster_foreign_eph_pages_atomic);
+			WARN_ON_ONCE(c < 0);
+		}
+		ramster_foreign_eph_pages = c;
+	} else {
+		if (count > 0) {
+			c = atomic_inc_return(
+					&ramster_foreign_pers_pages_atomic);
+			if (c > ramster_foreign_pers_pages_max)
+				ramster_foreign_pers_pages_max = c;
+		} else {
+			c = atomic_dec_return(
+					&ramster_foreign_pers_pages_atomic);
+			WARN_ON_ONCE(c < 0);
+		}
+		ramster_foreign_pers_pages = c;
+	}
+}
+
+/*
+ * For now, just push over a few pages every few seconds to
+ * ensure that it basically works
+ */
+static struct workqueue_struct *ramster_remotify_workqueue;
+static void ramster_remotify_process(struct work_struct *work);
+static DECLARE_DELAYED_WORK(ramster_remotify_worker,
+		ramster_remotify_process);
+
+static void ramster_remotify_queue_delayed_work(unsigned long delay)
+{
+	if (!queue_delayed_work(ramster_remotify_workqueue,
+				&ramster_remotify_worker, delay))
+		pr_err("ramster_remotify: bad workqueue\n");
+}
+
+static void ramster_remote_flush_page(struct flushlist_node *flnode)
+{
+	struct tmem_xhandle *xh;
+	int remotenode, ret;
+
+	preempt_disable();
+	xh = &flnode->xh;
+	remotenode = flnode->xh.client_id;
+	ret = r2net_remote_flush(xh, remotenode);
+	if (ret >= 0)
+		ramster_remote_pages_flushed++;
+	else
+		ramster_remote_page_flushes_failed++;
+	preempt_enable_no_resched();
+	ramster_flnode_free(flnode, NULL);
+}
+
+static void ramster_remote_flush_object(struct flushlist_node *flnode)
+{
+	struct tmem_xhandle *xh;
+	int remotenode, ret;
+
+	preempt_disable();
+	xh = &flnode->xh;
+	remotenode = flnode->xh.client_id;
+	ret = r2net_remote_flush_object(xh, remotenode);
+	if (ret >= 0)
+		ramster_remote_objects_flushed++;
+	else
+		ramster_remote_object_flushes_failed++;
+	preempt_enable_no_resched();
+	ramster_flnode_free(flnode, NULL);
+}
+
+int ramster_remotify_pageframe(bool eph)
+{
+	struct tmem_xhandle xh;
+	unsigned int size;
+	int remotenode, ret, zbuds;
+	struct tmem_pool *pool;
+	unsigned long flags;
+	unsigned char cksum;
+	char *p;
+	int i, j;
+	unsigned char *tmpmem[2];
+	struct tmem_handle th[2];
+	unsigned int zsize[2];
+
+	tmpmem[0] = __get_cpu_var(ramster_remoteputmem1);
+	tmpmem[1] = __get_cpu_var(ramster_remoteputmem2);
+	local_bh_disable();
+	zbuds = zbud_make_zombie_lru(&th[0], &tmpmem[0], &zsize[0], eph);
+	/* now OK to release lock set in caller */
+	local_bh_enable();
+	if (zbuds == 0)
+		goto out;
+	BUG_ON(zbuds > 2);
+	for (i = 0; i < zbuds; i++) {
+		xh.client_id = th[i].client_id;
+		xh.pool_id = th[i].pool_id;
+		xh.oid = th[i].oid;
+		xh.index = th[i].index;
+		size = zsize[i];
+		BUG_ON(size == 0 || size > zbud_max_buddy_size());
+		for (p = tmpmem[i], cksum = 0, j = 0; j < size; j++)
+			cksum += *p++;
+		ret = r2net_remote_put(&xh, tmpmem[i], size, eph, &remotenode);
+		if (ret != 0) {
+		/*
+		 * This is some form of a memory leak... if the remote put
+		 * fails, there will never be another attempt to remotify
+		 * this page.  But since we've dropped the zv pointer,
+		 * the page may have been freed or the data replaced
+		 * so we can't just "put it back" in the remote op list.
+		 * Even if we could, not sure where to put it in the list
+		 * because there may be flushes that must be strictly
+		 * ordered vs the put.  So leave this as a FIXME for now.
+		 * But count them so we know if it becomes a problem.
+		 */
+			if (eph)
+				ramster_eph_pages_remote_failed++;
+			else
+				ramster_pers_pages_remote_failed++;
+			break;
+		} else {
+			if (!eph)
+				atomic_inc(&ramster_remote_pers_pages);
+		}
+		if (eph)
+			ramster_eph_pages_remoted++;
+		else
+			ramster_pers_pages_remoted++;
+		/*
+		 * data was successfully remoted so change the local version to
+		 * point to the remote node where it landed
+		 */
+		local_bh_disable();
+		pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id);
+		local_irq_save(flags);
+		(void)tmem_replace(pool, &xh.oid, xh.index,
+				pampd_make_remote(remotenode, size, cksum));
+		local_irq_restore(flags);
+		zcache_put_pool(pool);
+		local_bh_enable();
+	}
+out:
+	return zbuds;
+}
+
+static void zcache_do_remotify_flushes(void)
+{
+	struct ramster_remotify_hdr *rem_op;
+	union remotify_list_node *u;
+
+	while (1) {
+		spin_lock(&ramster_rem_op_list_lock);
+		if (list_empty(&ramster_rem_op_list)) {
+			spin_unlock(&ramster_rem_op_list_lock);
+			goto out;
+		}
+		rem_op = list_first_entry(&ramster_rem_op_list,
+				struct ramster_remotify_hdr, list);
+		list_del_init(&rem_op->list);
+		spin_unlock(&ramster_rem_op_list_lock);
+		u = (union remotify_list_node *)rem_op;
+		switch (rem_op->op) {
+		case RAMSTER_REMOTIFY_FLUSH_PAGE:
+			ramster_remote_flush_page((struct flushlist_node *)u);
+			break;
+		case RAMSTER_REMOTIFY_FLUSH_OBJ:
+			ramster_remote_flush_object((struct flushlist_node *)u);
+			break;
+		default:
+			BUG();
+		}
+	}
+out:
+	return;
+}
+
+static void ramster_remotify_process(struct work_struct *work)
+{
+	static bool remotify_in_progress;
+	int i;
+
+	BUG_ON(irqs_disabled());
+	if (remotify_in_progress)
+		goto requeue;
+	if (ramster_remote_target_nodenum == -1)
+		goto requeue;
+	remotify_in_progress = true;
+	if (use_cleancache && ramster_eph_remotify_enable) {
+		for (i = 0; i < 100; i++) {
+			zcache_do_remotify_flushes();
+			(void)ramster_remotify_pageframe(true);
+		}
+	}
+	if (use_frontswap && ramster_pers_remotify_enable) {
+		for (i = 0; i < 100; i++) {
+			zcache_do_remotify_flushes();
+			(void)ramster_remotify_pageframe(false);
+		}
+	}
+	remotify_in_progress = false;
+requeue:
+	ramster_remotify_queue_delayed_work(HZ);
+}
+
+void __init ramster_remotify_init(void)
+{
+	unsigned long n = 60UL;
+	ramster_remotify_workqueue =
+		create_singlethread_workqueue("ramster_remotify");
+	ramster_remotify_queue_delayed_work(n * HZ);
+}
+
+static ssize_t ramster_manual_node_up_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	int i;
+	char *p = buf;
+	for (i = 0; i < MANUAL_NODES; i++)
+		if (ramster_nodes_manual_up[i])
+			p += sprintf(p, "%d ", i);
+	p += sprintf(p, "\n");
+	return p - buf;
+}
+
+static ssize_t ramster_manual_node_up_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int err;
+	unsigned long node_num;
+
+	err = kstrtoul(buf, 10, &node_num);
+	if (err) {
+		pr_err("ramster: bad strtoul?\n");
+		return -EINVAL;
+	}
+	if (node_num >= MANUAL_NODES) {
+		pr_err("ramster: bad node_num=%lu?\n", node_num);
+		return -EINVAL;
+	}
+	if (ramster_nodes_manual_up[node_num]) {
+		pr_err("ramster: node %d already up, ignoring\n",
+							(int)node_num);
+	} else {
+		ramster_nodes_manual_up[node_num] = true;
+		r2net_hb_node_up_manual((int)node_num);
+	}
+	return count;
+}
+
+static struct kobj_attribute ramster_manual_node_up_attr = {
+	.attr = { .name = "manual_node_up", .mode = 0644 },
+	.show = ramster_manual_node_up_show,
+	.store = ramster_manual_node_up_store,
+};
+
+static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	if (ramster_remote_target_nodenum == -1UL)
+		return sprintf(buf, "unset\n");
+	else
+		return sprintf(buf, "%d\n", ramster_remote_target_nodenum);
+}
+
+static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int err;
+	unsigned long node_num;
+
+	err = kstrtoul(buf, 10, &node_num);
+	if (err) {
+		pr_err("ramster: bad strtoul?\n");
+		return -EINVAL;
+	} else if (node_num == -1UL) {
+		pr_err("ramster: disabling all remotification, "
+			"data may still reside on remote nodes however\n");
+		return -EINVAL;
+	} else if (node_num >= MANUAL_NODES) {
+		pr_err("ramster: bad node_num=%lu?\n", node_num);
+		return -EINVAL;
+	} else if (!ramster_nodes_manual_up[node_num]) {
+		pr_err("ramster: node %d not up, ignoring setting "
+			"of remotification target\n", (int)node_num);
+	} else if (r2net_remote_target_node_set((int)node_num) >= 0) {
+		pr_info("ramster: node %d set as remotification target\n",
+				(int)node_num);
+		ramster_remote_target_nodenum = (int)node_num;
+	} else {
+		pr_err("ramster: bad num to node node_num=%d?\n",
+				(int)node_num);
+		return -EINVAL;
+	}
+	return count;
+}
+
+static struct kobj_attribute ramster_remote_target_nodenum_attr = {
+	.attr = { .name = "remote_target_nodenum", .mode = 0644 },
+	.show = ramster_remote_target_nodenum_show,
+	.store = ramster_remote_target_nodenum_store,
+};
+
+#define RAMSTER_SYSFS_RO(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", ramster_##_name); \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = ramster_##_name##_show, \
+	}
+
+#define RAMSTER_SYSFS_RW(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", ramster_##_name); \
+	} \
+	static ssize_t ramster_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+	{ \
+		int err; \
+		unsigned long enable; \
+		err = kstrtoul(buf, 10, &enable); \
+		if (err) \
+			return -EINVAL; \
+		ramster_##_name = enable; \
+		return count; \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0644 }, \
+		.show = ramster_##_name##_show, \
+		.store = ramster_##_name##_store, \
+	}
+
+#define RAMSTER_SYSFS_RO_ATOMIC(_name) \
+	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \
+	} \
+	static struct kobj_attribute ramster_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = ramster_##_name##_show, \
+	}
+
+RAMSTER_SYSFS_RO(interface_revision);
+RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages);
+RAMSTER_SYSFS_RW(pers_remotify_enable);
+RAMSTER_SYSFS_RW(eph_remotify_enable);
+
+static struct attribute *ramster_attrs[] = {
+	&ramster_interface_revision_attr.attr,
+	&ramster_remote_pers_pages_attr.attr,
+	&ramster_manual_node_up_attr.attr,
+	&ramster_remote_target_nodenum_attr.attr,
+	&ramster_pers_remotify_enable_attr.attr,
+	&ramster_eph_remotify_enable_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ramster_attr_group = {
+	.attrs = ramster_attrs,
+	.name = "ramster",
+};
+
+/*
+ * frontswap selfshrinking
+ */
+
+/* In HZ, controls frequency of worker invocation. */
+static unsigned int selfshrink_interval __read_mostly = 5;
+/* Enable/disable with sysfs. */
+static bool frontswap_selfshrinking __read_mostly;
+
+static void selfshrink_process(struct work_struct *work);
+static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
+
+/* Enable/disable with kernel boot option. */
+static bool use_frontswap_selfshrink __initdata = true;
+
+/*
+ * The default values for the following parameters were deemed reasonable
+ * by experimentation, may be workload-dependent, and can all be
+ * adjusted via sysfs.
+ */
+
+/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
+static unsigned int frontswap_hysteresis __read_mostly = 20;
+
+/*
+ * Number of selfshrink worker invocations to wait before observing that
+ * frontswap selfshrinking should commence. Note that selfshrinking does
+ * not use a separate worker thread.
+ */
+static unsigned int frontswap_inertia __read_mostly = 3;
+
+/* Countdown to next invocation of frontswap_shrink() */
+static unsigned long frontswap_inertia_counter;
+
+/*
+ * Invoked by the selfshrink worker thread, uses current number of pages
+ * in frontswap (frontswap_curr_pages()), previous status, and control
+ * values (hysteresis and inertia) to determine if frontswap should be
+ * shrunk and what the new frontswap size should be.  Note that
+ * frontswap_shrink is essentially a partial swapoff that immediately
+ * transfers pages from the "swap device" (frontswap) back into kernel
+ * RAM; despite the name, frontswap "shrinking" is very different from
+ * the "shrinker" interface used by the kernel MM subsystem to reclaim
+ * memory.
+ */
+static void frontswap_selfshrink(void)
+{
+	static unsigned long cur_frontswap_pages;
+	static unsigned long last_frontswap_pages;
+	static unsigned long tgt_frontswap_pages;
+
+	last_frontswap_pages = cur_frontswap_pages;
+	cur_frontswap_pages = frontswap_curr_pages();
+	if (!cur_frontswap_pages ||
+			(cur_frontswap_pages > last_frontswap_pages)) {
+		frontswap_inertia_counter = frontswap_inertia;
+		return;
+	}
+	if (frontswap_inertia_counter && --frontswap_inertia_counter)
+		return;
+	if (cur_frontswap_pages <= frontswap_hysteresis)
+		tgt_frontswap_pages = 0;
+	else
+		tgt_frontswap_pages = cur_frontswap_pages -
+			(cur_frontswap_pages / frontswap_hysteresis);
+	frontswap_shrink(tgt_frontswap_pages);
+}
+
+static int __init ramster_nofrontswap_selfshrink_setup(char *s)
+{
+	use_frontswap_selfshrink = false;
+	return 1;
+}
+
+__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
+
+static void selfshrink_process(struct work_struct *work)
+{
+	if (frontswap_selfshrinking && frontswap_enabled) {
+		frontswap_selfshrink();
+		schedule_delayed_work(&selfshrink_worker,
+			selfshrink_interval * HZ);
+	}
+}
+
+void ramster_cpu_up(int cpu)
+{
+	unsigned char *p1 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
+	unsigned char *p2 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
+	BUG_ON(!p1 || !p2);
+	per_cpu(ramster_remoteputmem1, cpu) = p1;
+	per_cpu(ramster_remoteputmem2, cpu) = p2;
+}
+
+void ramster_cpu_down(int cpu)
+{
+	struct ramster_preload *kp;
+
+	kfree(per_cpu(ramster_remoteputmem1, cpu));
+	per_cpu(ramster_remoteputmem1, cpu) = NULL;
+	kfree(per_cpu(ramster_remoteputmem2, cpu));
+	per_cpu(ramster_remoteputmem2, cpu) = NULL;
+	kp = &per_cpu(ramster_preloads, cpu);
+	if (kp->flnode) {
+		kmem_cache_free(ramster_flnode_cache, kp->flnode);
+		kp->flnode = NULL;
+	}
+}
+
+void ramster_register_pamops(struct tmem_pamops *pamops)
+{
+	pamops->free_obj = ramster_pampd_free_obj;
+	pamops->new_obj = ramster_pampd_new_obj;
+	pamops->replace_in_obj = ramster_pampd_replace_in_obj;
+	pamops->is_remote = ramster_pampd_is_remote;
+	pamops->repatriate = ramster_pampd_repatriate;
+	pamops->repatriate_preload = ramster_pampd_repatriate_preload;
+}
+
+void __init ramster_init(bool cleancache, bool frontswap,
+				bool frontswap_exclusive_gets)
+{
+	int ret = 0;
+
+	if (cleancache)
+		use_cleancache = true;
+	if (frontswap)
+		use_frontswap = true;
+	if (frontswap_exclusive_gets)
+		use_frontswap_exclusive_gets = true;
+	ramster_debugfs_init();
+	ret = sysfs_create_group(mm_kobj, &ramster_attr_group);
+	if (ret)
+		pr_err("ramster: can't create sysfs for ramster\n");
+	(void)r2net_register_handlers();
+	INIT_LIST_HEAD(&ramster_rem_op_list);
+	ramster_flnode_cache = kmem_cache_create("ramster_flnode",
+				sizeof(struct flushlist_node), 0, 0, NULL);
+	frontswap_selfshrinking = use_frontswap_selfshrink;
+	if (frontswap_selfshrinking) {
+		pr_info("ramster: Initializing frontswap selfshrink driver.\n");
+		schedule_delayed_work(&selfshrink_worker,
+					selfshrink_interval * HZ);
+	}
+	ramster_remotify_init();
+}
diff --git a/drivers/staging/ramster/ramster/ramster.h b/drivers/staging/ramster/ramster/ramster.h
new file mode 100644
index 0000000..12ae56f
--- /dev/null
+++ b/drivers/staging/ramster/ramster/ramster.h
@@ -0,0 +1,161 @@
+/*
+ * ramster.h
+ *
+ * Peer-to-peer transcendent memory
+ *
+ * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
+ */
+
+#ifndef _RAMSTER_RAMSTER_H_
+#define _RAMSTER_RAMSTER_H_
+
+#include "../tmem.h"
+
+enum ramster_remotify_op {
+	RAMSTER_REMOTIFY_FLUSH_PAGE,
+	RAMSTER_REMOTIFY_FLUSH_OBJ,
+};
+
+struct ramster_remotify_hdr {
+	enum ramster_remotify_op op;
+	struct list_head list;
+};
+
+struct flushlist_node {
+	struct ramster_remotify_hdr rem_op;
+	struct tmem_xhandle xh;
+};
+
+struct ramster_preload {
+	struct flushlist_node *flnode;
+};
+
+union remotify_list_node {
+	struct ramster_remotify_hdr rem_op;
+	struct {
+		struct ramster_remotify_hdr rem_op;
+		struct tmem_handle th;
+	} zbud_hdr;
+	struct flushlist_node flist;
+};
+
+/*
+ * format of remote pampd:
+ *   bit 0 is reserved for zbud (in-page buddy selection)
+ *   bit 1 == intransit
+ *   bit 2 == is_remote... if this bit is set, then
+ *   bit 3-10 == remotenode
+ *   bit 11-23 == size
+ *   bit 24-31 == cksum
+ */
+#define FAKE_PAMPD_INTRANSIT_BITS	1
+#define FAKE_PAMPD_ISREMOTE_BITS	1
+#define FAKE_PAMPD_REMOTENODE_BITS	8
+#define FAKE_PAMPD_REMOTESIZE_BITS	13
+#define FAKE_PAMPD_CHECKSUM_BITS	8
+
+#define FAKE_PAMPD_INTRANSIT_SHIFT	1
+#define FAKE_PAMPD_ISREMOTE_SHIFT	(FAKE_PAMPD_INTRANSIT_SHIFT + \
+					 FAKE_PAMPD_INTRANSIT_BITS)
+#define FAKE_PAMPD_REMOTENODE_SHIFT	(FAKE_PAMPD_ISREMOTE_SHIFT + \
+					 FAKE_PAMPD_ISREMOTE_BITS)
+#define FAKE_PAMPD_REMOTESIZE_SHIFT	(FAKE_PAMPD_REMOTENODE_SHIFT + \
+					 FAKE_PAMPD_REMOTENODE_BITS)
+#define FAKE_PAMPD_CHECKSUM_SHIFT	(FAKE_PAMPD_REMOTESIZE_SHIFT + \
+					 FAKE_PAMPD_REMOTESIZE_BITS)
+
+#define FAKE_PAMPD_MASK(x)		((1UL << (x)) - 1)
+
+static inline void *pampd_make_remote(int remotenode, size_t size,
+					unsigned char cksum)
+{
+	unsigned long fake_pampd = 0;
+	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
+	fake_pampd |= ((unsigned long)remotenode &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) <<
+				FAKE_PAMPD_REMOTENODE_SHIFT;
+	fake_pampd |= ((unsigned long)size &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) <<
+				FAKE_PAMPD_REMOTESIZE_SHIFT;
+	fake_pampd |= ((unsigned long)cksum &
+			FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) <<
+				FAKE_PAMPD_CHECKSUM_SHIFT;
+	return (void *)fake_pampd;
+}
+
+static inline unsigned int pampd_remote_node(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS);
+}
+
+static inline unsigned int pampd_remote_size(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS);
+}
+
+static inline unsigned char pampd_remote_cksum(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS);
+}
+
+static inline bool pampd_is_remote(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS);
+}
+
+static inline bool pampd_is_intransit(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+	return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) &
+		FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS);
+}
+
+/* note that it is a BUG for intransit to be set without isremote also set */
+static inline void *pampd_mark_intransit(void *pampd)
+{
+	unsigned long fake_pampd = (unsigned long)pampd;
+
+	fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
+	fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT;
+	return (void *)fake_pampd;
+}
+
+static inline void *pampd_mask_intransit_and_remote(void *marked_pampd)
+{
+	unsigned long pampd = (unsigned long)marked_pampd;
+
+	pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT);
+	pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT);
+	return (void *)pampd;
+}
+
+extern int r2net_remote_async_get(struct tmem_xhandle *,
+				bool, int, size_t, uint8_t, void *extra);
+extern int r2net_remote_put(struct tmem_xhandle *, char *, size_t,
+				bool, int *);
+extern int r2net_remote_flush(struct tmem_xhandle *, int);
+extern int r2net_remote_flush_object(struct tmem_xhandle *, int);
+extern int r2net_register_handlers(void);
+extern int r2net_remote_target_node_set(int);
+
+extern int ramster_remotify_pageframe(bool);
+extern void ramster_init(bool, bool, bool);
+extern void ramster_register_pamops(struct tmem_pamops *);
+extern int ramster_localify(int, struct tmem_oid *oidp, uint32_t, char *,
+				unsigned int, void *);
+extern void *ramster_pampd_free(void *, struct tmem_pool *, struct tmem_oid *,
+				uint32_t, bool);
+extern void ramster_count_foreign_pages(bool, int);
+extern int ramster_do_preload_flnode(struct tmem_pool *);
+extern void ramster_cpu_up(int);
+extern void ramster_cpu_down(int);
+
+#endif /* _RAMSTER_RAMSTER_H */
diff --git a/drivers/staging/ramster/cluster/ramster_nodemanager.h b/drivers/staging/ramster/ramster/ramster_nodemanager.h
similarity index 100%
rename from drivers/staging/ramster/cluster/ramster_nodemanager.h
rename to drivers/staging/ramster/ramster/ramster_nodemanager.h
diff --git a/drivers/staging/ramster/ramster/tcp.c b/drivers/staging/ramster/ramster/tcp.c
new file mode 100644
index 0000000..aa2a1a7
--- /dev/null
+++ b/drivers/staging/ramster/ramster/tcp.c
@@ -0,0 +1,2253 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ *
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * ----
+ *
+ * Callers for this were originally written against a very simple synchronus
+ * API.  This implementation reflects those simple callers.  Some day I'm sure
+ * we'll need to move to a more robust posting/callback mechanism.
+ *
+ * Transmit calls pass in kernel virtual addresses and block copying this into
+ * the socket's tx buffers via a usual blocking sendmsg.  They'll block waiting
+ * for a failed socket to timeout.  TX callers can also pass in a poniter to an
+ * 'int' which gets filled with an errno off the wire in response to the
+ * message they send.
+ *
+ * Handlers for unsolicited messages are registered.  Each socket has a page
+ * that incoming data is copied into.  First the header, then the data.
+ * Handlers are called from only one thread with a reference to this per-socket
+ * page.  This page is destroyed after the handler call, so it can't be
+ * referenced beyond the call.  Handlers may block but are discouraged from
+ * doing so.
+ *
+ * Any framing errors (bad magic, large payload lengths) close a connection.
+ *
+ * Our sock_container holds the state we associate with a socket.  It's current
+ * framing state is held there as well as the refcounting we do around when it
+ * is safe to tear down the socket.  The socket is only finally torn down from
+ * the container when the container loses all of its references -- so as long
+ * as you hold a ref on the container you can trust that the socket is valid
+ * for use with kernel socket APIs.
+ *
+ * Connections are initiated between a pair of nodes when the node with the
+ * higher node number gets a heartbeat callback which indicates that the lower
+ * numbered node has started heartbeating.  The lower numbered node is passive
+ * and only accepts the connection if the higher numbered node is heartbeating.
+ */
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/kref.h>
+#include <linux/net.h>
+#include <linux/export.h>
+#include <linux/uaccess.h>
+#include <net/tcp.h>
+
+
+#include "heartbeat.h"
+#include "tcp.h"
+#include "nodemanager.h"
+#define MLOG_MASK_PREFIX ML_TCP
+#include "masklog.h"
+
+#include "tcp_internal.h"
+
+#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u"
+
+/*
+ * In the following two log macros, the whitespace after the ',' just
+ * before ##args is intentional. Otherwise, gcc 2.95 will eat the
+ * previous token if args expands to nothing.
+ */
+#define msglog(hdr, fmt, args...) do {					\
+	typeof(hdr) __hdr = (hdr);					\
+	mlog(ML_MSG, "[mag %u len %u typ %u stat %d sys_stat %d "	\
+	     "key %08x num %u] " fmt,					\
+	be16_to_cpu(__hdr->magic), be16_to_cpu(__hdr->data_len),	\
+	     be16_to_cpu(__hdr->msg_type), be32_to_cpu(__hdr->status),	\
+	     be32_to_cpu(__hdr->sys_status), be32_to_cpu(__hdr->key),	\
+	     be32_to_cpu(__hdr->msg_num) ,  ##args);			\
+} while (0)
+
+#define sclog(sc, fmt, args...) do {					\
+	typeof(sc) __sc = (sc);						\
+	mlog(ML_SOCKET, "[sc %p refs %d sock %p node %u page %p "	\
+	     "pg_off %zu] " fmt, __sc,					\
+	     atomic_read(&__sc->sc_kref.refcount), __sc->sc_sock,	\
+	    __sc->sc_node->nd_num, __sc->sc_page, __sc->sc_page_off ,	\
+	    ##args);							\
+} while (0)
+
+static DEFINE_RWLOCK(r2net_handler_lock);
+static struct rb_root r2net_handler_tree = RB_ROOT;
+
+static struct r2net_node r2net_nodes[R2NM_MAX_NODES];
+
+/* XXX someday we'll need better accounting */
+static struct socket *r2net_listen_sock;
+
+/*
+ * listen work is only queued by the listening socket callbacks on the
+ * r2net_wq.  teardown detaches the callbacks before destroying the workqueue.
+ * quorum work is queued as sock containers are shutdown.. stop_listening
+ * tears down all the node's sock containers, preventing future shutdowns
+ * and queued quorum work, before canceling delayed quorum work and
+ * destroying the work queue.
+ */
+static struct workqueue_struct *r2net_wq;
+static struct work_struct r2net_listen_work;
+
+static struct r2hb_callback_func r2net_hb_up, r2net_hb_down;
+#define R2NET_HB_PRI 0x1
+
+static struct r2net_handshake *r2net_hand;
+static struct r2net_msg *r2net_keep_req, *r2net_keep_resp;
+
+static int r2net_sys_err_translations[R2NET_ERR_MAX] = {
+		[R2NET_ERR_NONE]	= 0,
+		[R2NET_ERR_NO_HNDLR]	= -ENOPROTOOPT,
+		[R2NET_ERR_OVERFLOW]	= -EOVERFLOW,
+		[R2NET_ERR_DIED]	= -EHOSTDOWN,};
+
+/* can't quite avoid *all* internal declarations :/ */
+static void r2net_sc_connect_completed(struct work_struct *work);
+static void r2net_rx_until_empty(struct work_struct *work);
+static void r2net_shutdown_sc(struct work_struct *work);
+static void r2net_listen_data_ready(struct sock *sk, int bytes);
+static void r2net_sc_send_keep_req(struct work_struct *work);
+static void r2net_idle_timer(unsigned long data);
+static void r2net_sc_postpone_idle(struct r2net_sock_container *sc);
+static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc);
+
+#ifdef CONFIG_DEBUG_FS
+static void r2net_init_nst(struct r2net_send_tracking *nst, u32 msgtype,
+			   u32 msgkey, struct task_struct *task, u8 node)
+{
+	INIT_LIST_HEAD(&nst->st_net_debug_item);
+	nst->st_task = task;
+	nst->st_msg_type = msgtype;
+	nst->st_msg_key = msgkey;
+	nst->st_node = node;
+}
+
+static inline void r2net_set_nst_sock_time(struct r2net_send_tracking *nst)
+{
+	nst->st_sock_time = ktime_get();
+}
+
+static inline void r2net_set_nst_send_time(struct r2net_send_tracking *nst)
+{
+	nst->st_send_time = ktime_get();
+}
+
+static inline void r2net_set_nst_status_time(struct r2net_send_tracking *nst)
+{
+	nst->st_status_time = ktime_get();
+}
+
+static inline void r2net_set_nst_sock_container(struct r2net_send_tracking *nst,
+						struct r2net_sock_container *sc)
+{
+	nst->st_sc = sc;
+}
+
+static inline void r2net_set_nst_msg_id(struct r2net_send_tracking *nst,
+					u32 msg_id)
+{
+	nst->st_id = msg_id;
+}
+
+static inline void r2net_set_sock_timer(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_timer = ktime_get();
+}
+
+static inline void r2net_set_data_ready_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_data_ready = ktime_get();
+}
+
+static inline void r2net_set_advance_start_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_advance_start = ktime_get();
+}
+
+static inline void r2net_set_advance_stop_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_advance_stop = ktime_get();
+}
+
+static inline void r2net_set_func_start_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_func_start = ktime_get();
+}
+
+static inline void r2net_set_func_stop_time(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_func_stop = ktime_get();
+}
+
+#else  /* CONFIG_DEBUG_FS */
+# define r2net_init_nst(a, b, c, d, e)
+# define r2net_set_nst_sock_time(a)
+# define r2net_set_nst_send_time(a)
+# define r2net_set_nst_status_time(a)
+# define r2net_set_nst_sock_container(a, b)
+# define r2net_set_nst_msg_id(a, b)
+# define r2net_set_sock_timer(a)
+# define r2net_set_data_ready_time(a)
+# define r2net_set_advance_start_time(a)
+# define r2net_set_advance_stop_time(a)
+# define r2net_set_func_start_time(a)
+# define r2net_set_func_stop_time(a)
+#endif /* CONFIG_DEBUG_FS */
+
+#ifdef CONFIG_RAMSTER_FS_STATS
+static ktime_t r2net_get_func_run_time(struct r2net_sock_container *sc)
+{
+	return ktime_sub(sc->sc_tv_func_stop, sc->sc_tv_func_start);
+}
+
+static void r2net_update_send_stats(struct r2net_send_tracking *nst,
+				    struct r2net_sock_container *sc)
+{
+	sc->sc_tv_status_total = ktime_add(sc->sc_tv_status_total,
+					   ktime_sub(ktime_get(),
+						     nst->st_status_time));
+	sc->sc_tv_send_total = ktime_add(sc->sc_tv_send_total,
+					 ktime_sub(nst->st_status_time,
+						   nst->st_send_time));
+	sc->sc_tv_acquiry_total = ktime_add(sc->sc_tv_acquiry_total,
+					    ktime_sub(nst->st_send_time,
+						      nst->st_sock_time));
+	sc->sc_send_count++;
+}
+
+static void r2net_update_recv_stats(struct r2net_sock_container *sc)
+{
+	sc->sc_tv_process_total = ktime_add(sc->sc_tv_process_total,
+					    r2net_get_func_run_time(sc));
+	sc->sc_recv_count++;
+}
+
+#else
+
+# define r2net_update_send_stats(a, b)
+
+# define r2net_update_recv_stats(sc)
+
+#endif /* CONFIG_RAMSTER_FS_STATS */
+
+static inline int r2net_reconnect_delay(void)
+{
+	return r2nm_single_cluster->cl_reconnect_delay_ms;
+}
+
+static inline int r2net_keepalive_delay(void)
+{
+	return r2nm_single_cluster->cl_keepalive_delay_ms;
+}
+
+static inline int r2net_idle_timeout(void)
+{
+	return r2nm_single_cluster->cl_idle_timeout_ms;
+}
+
+static inline int r2net_sys_err_to_errno(enum r2net_system_error err)
+{
+	int trans;
+	BUG_ON(err >= R2NET_ERR_MAX);
+	trans = r2net_sys_err_translations[err];
+
+	/* Just in case we mess up the translation table above */
+	BUG_ON(err != R2NET_ERR_NONE && trans == 0);
+	return trans;
+}
+
+struct r2net_node *r2net_nn_from_num(u8 node_num)
+{
+	BUG_ON(node_num >= ARRAY_SIZE(r2net_nodes));
+	return &r2net_nodes[node_num];
+}
+
+static u8 r2net_num_from_nn(struct r2net_node *nn)
+{
+	BUG_ON(nn == NULL);
+	return nn - r2net_nodes;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_prep_nsw(struct r2net_node *nn, struct r2net_status_wait *nsw)
+{
+	int ret = 0;
+
+	do {
+		if (!idr_pre_get(&nn->nn_status_idr, GFP_ATOMIC)) {
+			ret = -EAGAIN;
+			break;
+		}
+		spin_lock(&nn->nn_lock);
+		ret = idr_get_new(&nn->nn_status_idr, nsw, &nsw->ns_id);
+		if (ret == 0)
+			list_add_tail(&nsw->ns_node_item,
+				      &nn->nn_status_list);
+		spin_unlock(&nn->nn_lock);
+	} while (ret == -EAGAIN);
+
+	if (ret == 0)  {
+		init_waitqueue_head(&nsw->ns_wq);
+		nsw->ns_sys_status = R2NET_ERR_NONE;
+		nsw->ns_status = 0;
+	}
+
+	return ret;
+}
+
+static void r2net_complete_nsw_locked(struct r2net_node *nn,
+				      struct r2net_status_wait *nsw,
+				      enum r2net_system_error sys_status,
+				      s32 status)
+{
+	assert_spin_locked(&nn->nn_lock);
+
+	if (!list_empty(&nsw->ns_node_item)) {
+		list_del_init(&nsw->ns_node_item);
+		nsw->ns_sys_status = sys_status;
+		nsw->ns_status = status;
+		idr_remove(&nn->nn_status_idr, nsw->ns_id);
+		wake_up(&nsw->ns_wq);
+	}
+}
+
+static void r2net_complete_nsw(struct r2net_node *nn,
+			       struct r2net_status_wait *nsw,
+			       u64 id, enum r2net_system_error sys_status,
+			       s32 status)
+{
+	spin_lock(&nn->nn_lock);
+	if (nsw == NULL) {
+		if (id > INT_MAX)
+			goto out;
+
+		nsw = idr_find(&nn->nn_status_idr, id);
+		if (nsw == NULL)
+			goto out;
+	}
+
+	r2net_complete_nsw_locked(nn, nsw, sys_status, status);
+
+out:
+	spin_unlock(&nn->nn_lock);
+	return;
+}
+
+static void r2net_complete_nodes_nsw(struct r2net_node *nn)
+{
+	struct r2net_status_wait *nsw, *tmp;
+	unsigned int num_kills = 0;
+
+	assert_spin_locked(&nn->nn_lock);
+
+	list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) {
+		r2net_complete_nsw_locked(nn, nsw, R2NET_ERR_DIED, 0);
+		num_kills++;
+	}
+
+	mlog(0, "completed %d messages for node %u\n", num_kills,
+	     r2net_num_from_nn(nn));
+}
+
+static int r2net_nsw_completed(struct r2net_node *nn,
+			       struct r2net_status_wait *nsw)
+{
+	int completed;
+	spin_lock(&nn->nn_lock);
+	completed = list_empty(&nsw->ns_node_item);
+	spin_unlock(&nn->nn_lock);
+	return completed;
+}
+
+/* ------------------------------------------------------------ */
+
+static void sc_kref_release(struct kref *kref)
+{
+	struct r2net_sock_container *sc = container_of(kref,
+					struct r2net_sock_container, sc_kref);
+	BUG_ON(timer_pending(&sc->sc_idle_timeout));
+
+	sclog(sc, "releasing\n");
+
+	if (sc->sc_sock) {
+		sock_release(sc->sc_sock);
+		sc->sc_sock = NULL;
+	}
+
+	r2nm_undepend_item(&sc->sc_node->nd_item);
+	r2nm_node_put(sc->sc_node);
+	sc->sc_node = NULL;
+
+	r2net_debug_del_sc(sc);
+	kfree(sc);
+}
+
+static void sc_put(struct r2net_sock_container *sc)
+{
+	sclog(sc, "put\n");
+	kref_put(&sc->sc_kref, sc_kref_release);
+}
+static void sc_get(struct r2net_sock_container *sc)
+{
+	sclog(sc, "get\n");
+	kref_get(&sc->sc_kref);
+}
+static struct r2net_sock_container *sc_alloc(struct r2nm_node *node)
+{
+	struct r2net_sock_container *sc, *ret = NULL;
+	struct page *page = NULL;
+	int status = 0;
+
+	page = alloc_page(GFP_NOFS);
+	sc = kzalloc(sizeof(*sc), GFP_NOFS);
+	if (sc == NULL || page == NULL)
+		goto out;
+
+	kref_init(&sc->sc_kref);
+	r2nm_node_get(node);
+	sc->sc_node = node;
+
+	/* pin the node item of the remote node */
+	status = r2nm_depend_item(&node->nd_item);
+	if (status) {
+		mlog_errno(status);
+		r2nm_node_put(node);
+		goto out;
+	}
+	INIT_WORK(&sc->sc_connect_work, r2net_sc_connect_completed);
+	INIT_WORK(&sc->sc_rx_work, r2net_rx_until_empty);
+	INIT_WORK(&sc->sc_shutdown_work, r2net_shutdown_sc);
+	INIT_DELAYED_WORK(&sc->sc_keepalive_work, r2net_sc_send_keep_req);
+
+	init_timer(&sc->sc_idle_timeout);
+	sc->sc_idle_timeout.function = r2net_idle_timer;
+	sc->sc_idle_timeout.data = (unsigned long)sc;
+
+	sclog(sc, "alloced\n");
+
+	ret = sc;
+	sc->sc_page = page;
+	r2net_debug_add_sc(sc);
+	sc = NULL;
+	page = NULL;
+
+out:
+	if (page)
+		__free_page(page);
+	kfree(sc);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------ */
+
+static void r2net_sc_queue_work(struct r2net_sock_container *sc,
+				struct work_struct *work)
+{
+	sc_get(sc);
+	if (!queue_work(r2net_wq, work))
+		sc_put(sc);
+}
+static void r2net_sc_queue_delayed_work(struct r2net_sock_container *sc,
+					struct delayed_work *work,
+					int delay)
+{
+	sc_get(sc);
+	if (!queue_delayed_work(r2net_wq, work, delay))
+		sc_put(sc);
+}
+static void r2net_sc_cancel_delayed_work(struct r2net_sock_container *sc,
+					 struct delayed_work *work)
+{
+	if (cancel_delayed_work(work))
+		sc_put(sc);
+}
+
+static atomic_t r2net_connected_peers = ATOMIC_INIT(0);
+
+int r2net_num_connected_peers(void)
+{
+	return atomic_read(&r2net_connected_peers);
+}
+
+static void r2net_set_nn_state(struct r2net_node *nn,
+			       struct r2net_sock_container *sc,
+			       unsigned valid, int err)
+{
+	int was_valid = nn->nn_sc_valid;
+	int was_err = nn->nn_persistent_error;
+	struct r2net_sock_container *old_sc = nn->nn_sc;
+
+	assert_spin_locked(&nn->nn_lock);
+
+	if (old_sc && !sc)
+		atomic_dec(&r2net_connected_peers);
+	else if (!old_sc && sc)
+		atomic_inc(&r2net_connected_peers);
+
+	/* the node num comparison and single connect/accept path should stop
+	 * an non-null sc from being overwritten with another */
+	BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc);
+	mlog_bug_on_msg(err && valid, "err %d valid %u\n", err, valid);
+	mlog_bug_on_msg(valid && !sc, "valid %u sc %p\n", valid, sc);
+
+	if (was_valid && !valid && err == 0)
+		err = -ENOTCONN;
+
+	mlog(ML_CONN, "node %u sc: %p -> %p, valid %u -> %u, err %d -> %d\n",
+	     r2net_num_from_nn(nn), nn->nn_sc, sc, nn->nn_sc_valid, valid,
+	     nn->nn_persistent_error, err);
+
+	nn->nn_sc = sc;
+	nn->nn_sc_valid = valid ? 1 : 0;
+	nn->nn_persistent_error = err;
+
+	/* mirrors r2net_tx_can_proceed() */
+	if (nn->nn_persistent_error || nn->nn_sc_valid)
+		wake_up(&nn->nn_sc_wq);
+
+	if (!was_err && nn->nn_persistent_error) {
+		queue_delayed_work(r2net_wq, &nn->nn_still_up,
+				   msecs_to_jiffies(R2NET_QUORUM_DELAY_MS));
+	}
+
+	if (was_valid && !valid) {
+		pr_notice("ramster: No longer connected to " SC_NODEF_FMT "\n",
+			old_sc->sc_node->nd_name, old_sc->sc_node->nd_num,
+			&old_sc->sc_node->nd_ipv4_address,
+			ntohs(old_sc->sc_node->nd_ipv4_port));
+		r2net_complete_nodes_nsw(nn);
+	}
+
+	if (!was_valid && valid) {
+		cancel_delayed_work(&nn->nn_connect_expired);
+		pr_notice("ramster: %s " SC_NODEF_FMT "\n",
+		       r2nm_this_node() > sc->sc_node->nd_num ?
+		       "Connected to" : "Accepted connection from",
+		       sc->sc_node->nd_name, sc->sc_node->nd_num,
+			&sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port));
+	}
+
+	/* trigger the connecting worker func as long as we're not valid,
+	 * it will back off if it shouldn't connect.  This can be called
+	 * from node config teardown and so needs to be careful about
+	 * the work queue actually being up. */
+	if (!valid && r2net_wq) {
+		unsigned long delay;
+		/* delay if we're within a RECONNECT_DELAY of the
+		 * last attempt */
+		delay = (nn->nn_last_connect_attempt +
+			 msecs_to_jiffies(r2net_reconnect_delay()))
+			- jiffies;
+		if (delay > msecs_to_jiffies(r2net_reconnect_delay()))
+			delay = 0;
+		mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay);
+		queue_delayed_work(r2net_wq, &nn->nn_connect_work, delay);
+
+		/*
+		 * Delay the expired work after idle timeout.
+		 *
+		 * We might have lots of failed connection attempts that run
+		 * through here but we only cancel the connect_expired work when
+		 * a connection attempt succeeds.  So only the first enqueue of
+		 * the connect_expired work will do anything.  The rest will see
+		 * that it's already queued and do nothing.
+		 */
+		delay += msecs_to_jiffies(r2net_idle_timeout());
+		queue_delayed_work(r2net_wq, &nn->nn_connect_expired, delay);
+	}
+
+	/* keep track of the nn's sc ref for the caller */
+	if ((old_sc == NULL) && sc)
+		sc_get(sc);
+	if (old_sc && (old_sc != sc)) {
+		r2net_sc_queue_work(old_sc, &old_sc->sc_shutdown_work);
+		sc_put(old_sc);
+	}
+}
+
+/* see r2net_register_callbacks() */
+static void r2net_data_ready(struct sock *sk, int bytes)
+{
+	void (*ready)(struct sock *sk, int bytes);
+
+	read_lock(&sk->sk_callback_lock);
+	if (sk->sk_user_data) {
+		struct r2net_sock_container *sc = sk->sk_user_data;
+		sclog(sc, "data_ready hit\n");
+		r2net_set_data_ready_time(sc);
+		r2net_sc_queue_work(sc, &sc->sc_rx_work);
+		ready = sc->sc_data_ready;
+	} else {
+		ready = sk->sk_data_ready;
+	}
+	read_unlock(&sk->sk_callback_lock);
+
+	ready(sk, bytes);
+}
+
+/* see r2net_register_callbacks() */
+static void r2net_state_change(struct sock *sk)
+{
+	void (*state_change)(struct sock *sk);
+	struct r2net_sock_container *sc;
+
+	read_lock(&sk->sk_callback_lock);
+	sc = sk->sk_user_data;
+	if (sc == NULL) {
+		state_change = sk->sk_state_change;
+		goto out;
+	}
+
+	sclog(sc, "state_change to %d\n", sk->sk_state);
+
+	state_change = sc->sc_state_change;
+
+	switch (sk->sk_state) {
+
+	/* ignore connecting sockets as they make progress */
+	case TCP_SYN_SENT:
+	case TCP_SYN_RECV:
+		break;
+	case TCP_ESTABLISHED:
+		r2net_sc_queue_work(sc, &sc->sc_connect_work);
+		break;
+	default:
+		pr_info("ramster: Connection to "
+			SC_NODEF_FMT " shutdown, state %d\n",
+			sc->sc_node->nd_name, sc->sc_node->nd_num,
+			&sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), sk->sk_state);
+		r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
+		break;
+
+	}
+out:
+	read_unlock(&sk->sk_callback_lock);
+	state_change(sk);
+}
+
+/*
+ * we register callbacks so we can queue work on events before calling
+ * the original callbacks.  our callbacks are careful to test user_data
+ * to discover when they've reaced with r2net_unregister_callbacks().
+ */
+static void r2net_register_callbacks(struct sock *sk,
+				     struct r2net_sock_container *sc)
+{
+	write_lock_bh(&sk->sk_callback_lock);
+
+	/* accepted sockets inherit the old listen socket data ready */
+	if (sk->sk_data_ready == r2net_listen_data_ready) {
+		sk->sk_data_ready = sk->sk_user_data;
+		sk->sk_user_data = NULL;
+	}
+
+	BUG_ON(sk->sk_user_data != NULL);
+	sk->sk_user_data = sc;
+	sc_get(sc);
+
+	sc->sc_data_ready = sk->sk_data_ready;
+	sc->sc_state_change = sk->sk_state_change;
+	sk->sk_data_ready = r2net_data_ready;
+	sk->sk_state_change = r2net_state_change;
+
+	mutex_init(&sc->sc_send_lock);
+
+	write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static int r2net_unregister_callbacks(struct sock *sk,
+					struct r2net_sock_container *sc)
+{
+	int ret = 0;
+
+	write_lock_bh(&sk->sk_callback_lock);
+	if (sk->sk_user_data == sc) {
+		ret = 1;
+		sk->sk_user_data = NULL;
+		sk->sk_data_ready = sc->sc_data_ready;
+		sk->sk_state_change = sc->sc_state_change;
+	}
+	write_unlock_bh(&sk->sk_callback_lock);
+
+	return ret;
+}
+
+/*
+ * this is a little helper that is called by callers who have seen a problem
+ * with an sc and want to detach it from the nn if someone already hasn't beat
+ * them to it.  if an error is given then the shutdown will be persistent
+ * and pending transmits will be canceled.
+ */
+static void r2net_ensure_shutdown(struct r2net_node *nn,
+					struct r2net_sock_container *sc,
+				   int err)
+{
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_sc == sc)
+		r2net_set_nn_state(nn, NULL, 0, err);
+	spin_unlock(&nn->nn_lock);
+}
+
+/*
+ * This work queue function performs the blocking parts of socket shutdown.  A
+ * few paths lead here.  set_nn_state will trigger this callback if it sees an
+ * sc detached from the nn.  state_change will also trigger this callback
+ * directly when it sees errors.  In that case we need to call set_nn_state
+ * ourselves as state_change couldn't get the nn_lock and call set_nn_state
+ * itself.
+ */
+static void r2net_shutdown_sc(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container,
+			     sc_shutdown_work);
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+
+	sclog(sc, "shutting down\n");
+
+	/* drop the callbacks ref and call shutdown only once */
+	if (r2net_unregister_callbacks(sc->sc_sock->sk, sc)) {
+		/* we shouldn't flush as we're in the thread, the
+		 * races with pending sc work structs are harmless */
+		del_timer_sync(&sc->sc_idle_timeout);
+		r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
+		sc_put(sc);
+		kernel_sock_shutdown(sc->sc_sock, SHUT_RDWR);
+	}
+
+	/* not fatal so failed connects before the other guy has our
+	 * heartbeat can be retried */
+	r2net_ensure_shutdown(nn, sc, 0);
+	sc_put(sc);
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_handler_cmp(struct r2net_msg_handler *nmh, u32 msg_type,
+			     u32 key)
+{
+	int ret = memcmp(&nmh->nh_key, &key, sizeof(key));
+
+	if (ret == 0)
+		ret = memcmp(&nmh->nh_msg_type, &msg_type, sizeof(msg_type));
+
+	return ret;
+}
+
+static struct r2net_msg_handler *
+r2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p,
+				struct rb_node **ret_parent)
+{
+	struct rb_node **p = &r2net_handler_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct r2net_msg_handler *nmh, *ret = NULL;
+	int cmp;
+
+	while (*p) {
+		parent = *p;
+		nmh = rb_entry(parent, struct r2net_msg_handler, nh_node);
+		cmp = r2net_handler_cmp(nmh, msg_type, key);
+
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else if (cmp > 0)
+			p = &(*p)->rb_right;
+		else {
+			ret = nmh;
+			break;
+		}
+	}
+
+	if (ret_p != NULL)
+		*ret_p = p;
+	if (ret_parent != NULL)
+		*ret_parent = parent;
+
+	return ret;
+}
+
+static void r2net_handler_kref_release(struct kref *kref)
+{
+	struct r2net_msg_handler *nmh;
+	nmh = container_of(kref, struct r2net_msg_handler, nh_kref);
+
+	kfree(nmh);
+}
+
+static void r2net_handler_put(struct r2net_msg_handler *nmh)
+{
+	kref_put(&nmh->nh_kref, r2net_handler_kref_release);
+}
+
+/* max_len is protection for the handler func.  incoming messages won't
+ * be given to the handler if their payload is longer than the max. */
+int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
+			   r2net_msg_handler_func *func, void *data,
+			   r2net_post_msg_handler_func *post_func,
+			   struct list_head *unreg_list)
+{
+	struct r2net_msg_handler *nmh = NULL;
+	struct rb_node **p, *parent;
+	int ret = 0;
+
+	if (max_len > R2NET_MAX_PAYLOAD_BYTES) {
+		mlog(0, "max_len for message handler out of range: %u\n",
+			max_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!msg_type) {
+		mlog(0, "no message type provided: %u, %p\n", msg_type, func);
+		ret = -EINVAL;
+		goto out;
+
+	}
+	if (!func) {
+		mlog(0, "no message handler provided: %u, %p\n",
+		       msg_type, func);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nmh = kzalloc(sizeof(struct r2net_msg_handler), GFP_NOFS);
+	if (nmh == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	nmh->nh_func = func;
+	nmh->nh_func_data = data;
+	nmh->nh_post_func = post_func;
+	nmh->nh_msg_type = msg_type;
+	nmh->nh_max_len = max_len;
+	nmh->nh_key = key;
+	/* the tree and list get this ref.. they're both removed in
+	 * unregister when this ref is dropped */
+	kref_init(&nmh->nh_kref);
+	INIT_LIST_HEAD(&nmh->nh_unregister_item);
+
+	write_lock(&r2net_handler_lock);
+	if (r2net_handler_tree_lookup(msg_type, key, &p, &parent))
+		ret = -EEXIST;
+	else {
+		rb_link_node(&nmh->nh_node, parent, p);
+		rb_insert_color(&nmh->nh_node, &r2net_handler_tree);
+		list_add_tail(&nmh->nh_unregister_item, unreg_list);
+
+		mlog(ML_TCP, "registered handler func %p type %u key %08x\n",
+		     func, msg_type, key);
+		/* we've had some trouble with handlers seemingly vanishing. */
+		mlog_bug_on_msg(r2net_handler_tree_lookup(msg_type, key, &p,
+							  &parent) == NULL,
+				"couldn't find handler we *just* registered "
+				"for type %u key %08x\n", msg_type, key);
+	}
+	write_unlock(&r2net_handler_lock);
+	if (ret)
+		goto out;
+
+out:
+	if (ret)
+		kfree(nmh);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2net_register_handler);
+
+void r2net_unregister_handler_list(struct list_head *list)
+{
+	struct r2net_msg_handler *nmh, *n;
+
+	write_lock(&r2net_handler_lock);
+	list_for_each_entry_safe(nmh, n, list, nh_unregister_item) {
+		mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n",
+		     nmh->nh_func, nmh->nh_msg_type, nmh->nh_key);
+		rb_erase(&nmh->nh_node, &r2net_handler_tree);
+		list_del_init(&nmh->nh_unregister_item);
+		kref_put(&nmh->nh_kref, r2net_handler_kref_release);
+	}
+	write_unlock(&r2net_handler_lock);
+}
+EXPORT_SYMBOL_GPL(r2net_unregister_handler_list);
+
+static struct r2net_msg_handler *r2net_handler_get(u32 msg_type, u32 key)
+{
+	struct r2net_msg_handler *nmh;
+
+	read_lock(&r2net_handler_lock);
+	nmh = r2net_handler_tree_lookup(msg_type, key, NULL, NULL);
+	if (nmh)
+		kref_get(&nmh->nh_kref);
+	read_unlock(&r2net_handler_lock);
+
+	return nmh;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
+{
+	int ret;
+	mm_segment_t oldfs;
+	struct kvec vec = {
+		.iov_len = len,
+		.iov_base = data,
+	};
+	struct msghdr msg = {
+		.msg_iovlen = 1,
+		.msg_iov = (struct iovec *)&vec,
+		.msg_flags = MSG_DONTWAIT,
+	};
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+	ret = sock_recvmsg(sock, &msg, len, msg.msg_flags);
+	set_fs(oldfs);
+
+	return ret;
+}
+
+static int r2net_send_tcp_msg(struct socket *sock, struct kvec *vec,
+			      size_t veclen, size_t total)
+{
+	int ret;
+	mm_segment_t oldfs;
+	struct msghdr msg = {
+		.msg_iov = (struct iovec *)vec,
+		.msg_iovlen = veclen,
+	};
+
+	if (sock == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+	ret = sock_sendmsg(sock, &msg, total);
+	set_fs(oldfs);
+	if (ret != total) {
+		mlog(ML_ERROR, "sendmsg returned %d instead of %zu\n", ret,
+		     total);
+		if (ret >= 0)
+			ret = -EPIPE; /* should be smarter, I bet */
+		goto out;
+	}
+
+	ret = 0;
+out:
+	if (ret < 0)
+		mlog(0, "returning error: %d\n", ret);
+	return ret;
+}
+
+static void r2net_sendpage(struct r2net_sock_container *sc,
+			   void *kmalloced_virt,
+			   size_t size)
+{
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+	ssize_t ret;
+
+	while (1) {
+		mutex_lock(&sc->sc_send_lock);
+		ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
+					virt_to_page(kmalloced_virt),
+					(long)kmalloced_virt & ~PAGE_MASK,
+					size, MSG_DONTWAIT);
+		mutex_unlock(&sc->sc_send_lock);
+		if (ret == size)
+			break;
+		if (ret == (ssize_t)-EAGAIN) {
+			mlog(0, "sendpage of size %zu to " SC_NODEF_FMT
+			     " returned EAGAIN\n", size, sc->sc_node->nd_name,
+				sc->sc_node->nd_num,
+				&sc->sc_node->nd_ipv4_address,
+				ntohs(sc->sc_node->nd_ipv4_port));
+			cond_resched();
+			continue;
+		}
+		mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT
+		     " failed with %zd\n", size, sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), ret);
+		r2net_ensure_shutdown(nn, sc, 0);
+		break;
+	}
+}
+
+static void r2net_init_msg(struct r2net_msg *msg, u16 data_len,
+				u16 msg_type, u32 key)
+{
+	memset(msg, 0, sizeof(struct r2net_msg));
+	msg->magic = cpu_to_be16(R2NET_MSG_MAGIC);
+	msg->data_len = cpu_to_be16(data_len);
+	msg->msg_type = cpu_to_be16(msg_type);
+	msg->sys_status = cpu_to_be32(R2NET_ERR_NONE);
+	msg->status = 0;
+	msg->key = cpu_to_be32(key);
+}
+
+static int r2net_tx_can_proceed(struct r2net_node *nn,
+				struct r2net_sock_container **sc_ret,
+				int *error)
+{
+	int ret = 0;
+
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_persistent_error) {
+		ret = 1;
+		*sc_ret = NULL;
+		*error = nn->nn_persistent_error;
+	} else if (nn->nn_sc_valid) {
+		kref_get(&nn->nn_sc->sc_kref);
+
+		ret = 1;
+		*sc_ret = nn->nn_sc;
+		*error = 0;
+	}
+	spin_unlock(&nn->nn_lock);
+
+	return ret;
+}
+
+/* Get a map of all nodes to which this node is currently connected to */
+void r2net_fill_node_map(unsigned long *map, unsigned bytes)
+{
+	struct r2net_sock_container *sc;
+	int node, ret;
+
+	BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
+
+	memset(map, 0, bytes);
+	for (node = 0; node < R2NM_MAX_NODES; ++node) {
+		r2net_tx_can_proceed(r2net_nn_from_num(node), &sc, &ret);
+		if (!ret) {
+			set_bit(node, map);
+			sc_put(sc);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(r2net_fill_node_map);
+
+int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
+			   size_t caller_veclen, u8 target_node, int *status)
+{
+	int ret = 0;
+	struct r2net_msg *msg = NULL;
+	size_t veclen, caller_bytes = 0;
+	struct kvec *vec = NULL;
+	struct r2net_sock_container *sc = NULL;
+	struct r2net_node *nn = r2net_nn_from_num(target_node);
+	struct r2net_status_wait nsw = {
+		.ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item),
+	};
+	struct r2net_send_tracking nst;
+
+	/* this may be a general bug fix */
+	init_waitqueue_head(&nsw.ns_wq);
+
+	r2net_init_nst(&nst, msg_type, key, current, target_node);
+
+	if (r2net_wq == NULL) {
+		mlog(0, "attempt to tx without r2netd running\n");
+		ret = -ESRCH;
+		goto out;
+	}
+
+	if (caller_veclen == 0) {
+		mlog(0, "bad kvec array length\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	caller_bytes = iov_length((struct iovec *)caller_vec, caller_veclen);
+	if (caller_bytes > R2NET_MAX_PAYLOAD_BYTES) {
+		mlog(0, "total payload len %zu too large\n", caller_bytes);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (target_node == r2nm_this_node()) {
+		ret = -ELOOP;
+		goto out;
+	}
+
+	r2net_debug_add_nst(&nst);
+
+	r2net_set_nst_sock_time(&nst);
+
+	wait_event(nn->nn_sc_wq, r2net_tx_can_proceed(nn, &sc, &ret));
+	if (ret)
+		goto out;
+
+	r2net_set_nst_sock_container(&nst, sc);
+
+	veclen = caller_veclen + 1;
+	vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC);
+	if (vec == NULL) {
+		mlog(0, "failed to %zu element kvec!\n", veclen);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	msg = kmalloc(sizeof(struct r2net_msg), GFP_ATOMIC);
+	if (!msg) {
+		mlog(0, "failed to allocate a r2net_msg!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	r2net_init_msg(msg, caller_bytes, msg_type, key);
+
+	vec[0].iov_len = sizeof(struct r2net_msg);
+	vec[0].iov_base = msg;
+	memcpy(&vec[1], caller_vec, caller_veclen * sizeof(struct kvec));
+
+	ret = r2net_prep_nsw(nn, &nsw);
+	if (ret)
+		goto out;
+
+	msg->msg_num = cpu_to_be32(nsw.ns_id);
+	r2net_set_nst_msg_id(&nst, nsw.ns_id);
+
+	r2net_set_nst_send_time(&nst);
+
+	/* finally, convert the message header to network byte-order
+	 * and send */
+	mutex_lock(&sc->sc_send_lock);
+	ret = r2net_send_tcp_msg(sc->sc_sock, vec, veclen,
+				 sizeof(struct r2net_msg) + caller_bytes);
+	mutex_unlock(&sc->sc_send_lock);
+	msglog(msg, "sending returned %d\n", ret);
+	if (ret < 0) {
+		mlog(0, "error returned from r2net_send_tcp_msg=%d\n", ret);
+		goto out;
+	}
+
+	/* wait on other node's handler */
+	r2net_set_nst_status_time(&nst);
+	wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw) ||
+			nn->nn_persistent_error || !nn->nn_sc_valid);
+
+	r2net_update_send_stats(&nst, sc);
+
+	/* Note that we avoid overwriting the callers status return
+	 * variable if a system error was reported on the other
+	 * side. Callers beware. */
+	ret = r2net_sys_err_to_errno(nsw.ns_sys_status);
+	if (status && !ret)
+		*status = nsw.ns_status;
+
+	mlog(0, "woken, returning system status %d, user status %d\n",
+	     ret, nsw.ns_status);
+out:
+	r2net_debug_del_nst(&nst); /* must be before dropping sc and node */
+	if (sc)
+		sc_put(sc);
+	kfree(vec);
+	kfree(msg);
+	r2net_complete_nsw(nn, &nsw, 0, 0, 0);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(r2net_send_message_vec);
+
+int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
+		       u8 target_node, int *status)
+{
+	struct kvec vec = {
+		.iov_base = data,
+		.iov_len = len,
+	};
+	return r2net_send_message_vec(msg_type, key, &vec, 1,
+				      target_node, status);
+}
+EXPORT_SYMBOL_GPL(r2net_send_message);
+
+static int r2net_send_status_magic(struct socket *sock, struct r2net_msg *hdr,
+				   enum r2net_system_error syserr, int err)
+{
+	struct kvec vec = {
+		.iov_base = hdr,
+		.iov_len = sizeof(struct r2net_msg),
+	};
+
+	BUG_ON(syserr >= R2NET_ERR_MAX);
+
+	/* leave other fields intact from the incoming message, msg_num
+	 * in particular */
+	hdr->sys_status = cpu_to_be32(syserr);
+	hdr->status = cpu_to_be32(err);
+	/* twiddle the magic */
+	hdr->magic = cpu_to_be16(R2NET_MSG_STATUS_MAGIC);
+	hdr->data_len = 0;
+
+	msglog(hdr, "about to send status magic %d\n", err);
+	/* hdr has been in host byteorder this whole time */
+	return r2net_send_tcp_msg(sock, &vec, 1, sizeof(struct r2net_msg));
+}
+
+/*
+ * "data magic" is a long version of "status magic" where the message
+ * payload actually contains data to be passed in reply to certain messages
+ */
+static int r2net_send_data_magic(struct r2net_sock_container *sc,
+			  struct r2net_msg *hdr,
+			  void *data, size_t data_len,
+			  enum r2net_system_error syserr, int err)
+{
+	struct kvec vec[2];
+	int ret;
+
+	vec[0].iov_base = hdr;
+	vec[0].iov_len = sizeof(struct r2net_msg);
+	vec[1].iov_base = data;
+	vec[1].iov_len = data_len;
+
+	BUG_ON(syserr >= R2NET_ERR_MAX);
+
+	/* leave other fields intact from the incoming message, msg_num
+	 * in particular */
+	hdr->sys_status = cpu_to_be32(syserr);
+	hdr->status = cpu_to_be32(err);
+	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);  /* twiddle magic */
+	hdr->data_len = cpu_to_be16(data_len);
+
+	msglog(hdr, "about to send data magic %d\n", err);
+	/* hdr has been in host byteorder this whole time */
+	ret = r2net_send_tcp_msg(sc->sc_sock, vec, 2,
+			sizeof(struct r2net_msg) + data_len);
+	return ret;
+}
+
+/*
+ * called by a message handler to convert an otherwise normal reply
+ * message into a "data magic" message
+ */
+void r2net_force_data_magic(struct r2net_msg *hdr, u16 msgtype, u32 msgkey)
+{
+	hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);
+	hdr->msg_type = cpu_to_be16(msgtype);
+	hdr->key = cpu_to_be32(msgkey);
+}
+
+/* this returns -errno if the header was unknown or too large, etc.
+ * after this is called the buffer us reused for the next message */
+static int r2net_process_message(struct r2net_sock_container *sc,
+				 struct r2net_msg *hdr)
+{
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+	int ret = 0, handler_status;
+	enum  r2net_system_error syserr;
+	struct r2net_msg_handler *nmh = NULL;
+	void *ret_data = NULL;
+	int data_magic = 0;
+
+	msglog(hdr, "processing message\n");
+
+	r2net_sc_postpone_idle(sc);
+
+	switch (be16_to_cpu(hdr->magic)) {
+
+	case R2NET_MSG_STATUS_MAGIC:
+		/* special type for returning message status */
+		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
+						be32_to_cpu(hdr->sys_status),
+						be32_to_cpu(hdr->status));
+		goto out;
+	case R2NET_MSG_KEEP_REQ_MAGIC:
+		r2net_sendpage(sc, r2net_keep_resp, sizeof(*r2net_keep_resp));
+		goto out;
+	case R2NET_MSG_KEEP_RESP_MAGIC:
+		goto out;
+	case R2NET_MSG_MAGIC:
+		break;
+	case R2NET_MSG_DATA_MAGIC:
+		/*
+		 * unlike a normal status magic, a data magic DOES
+		 * (MUST) have a handler, so the control flow is
+		 * a little funky here as a result
+		 */
+		data_magic = 1;
+		break;
+	default:
+		msglog(hdr, "bad magic\n");
+		ret = -EINVAL;
+		goto out;
+		break;
+	}
+
+	/* find a handler for it */
+	handler_status = 0;
+	nmh = r2net_handler_get(be16_to_cpu(hdr->msg_type),
+				be32_to_cpu(hdr->key));
+	if (!nmh) {
+		mlog(ML_TCP, "couldn't find handler for type %u key %08x\n",
+		     be16_to_cpu(hdr->msg_type), be32_to_cpu(hdr->key));
+		syserr = R2NET_ERR_NO_HNDLR;
+		goto out_respond;
+	}
+
+	syserr = R2NET_ERR_NONE;
+
+	if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len)
+		syserr = R2NET_ERR_OVERFLOW;
+
+	if (syserr != R2NET_ERR_NONE) {
+		pr_err("ramster_r2net, message length problem\n");
+		goto out_respond;
+	}
+
+	r2net_set_func_start_time(sc);
+	sc->sc_msg_key = be32_to_cpu(hdr->key);
+	sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
+	handler_status = (nmh->nh_func)(hdr, sizeof(struct r2net_msg) +
+					     be16_to_cpu(hdr->data_len),
+					nmh->nh_func_data, &ret_data);
+	if (data_magic) {
+		/*
+		 * handler handled data sent in reply to request
+		 * so complete the transaction
+		 */
+		r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
+			be32_to_cpu(hdr->sys_status), handler_status);
+		goto out;
+	}
+	/*
+	 * handler changed magic to DATA_MAGIC to reply to request for data,
+	 * implies ret_data points to data to return and handler_status
+	 * is the number of bytes of data
+	 */
+	if (be16_to_cpu(hdr->magic) == R2NET_MSG_DATA_MAGIC) {
+		ret = r2net_send_data_magic(sc, hdr,
+						ret_data, handler_status,
+						syserr, 0);
+		hdr = NULL;
+		mlog(0, "sending data reply %d, syserr %d returned %d\n",
+			handler_status, syserr, ret);
+		r2net_set_func_stop_time(sc);
+
+		r2net_update_recv_stats(sc);
+		goto out;
+	}
+	r2net_set_func_stop_time(sc);
+
+	r2net_update_recv_stats(sc);
+
+out_respond:
+	/* this destroys the hdr, so don't use it after this */
+	mutex_lock(&sc->sc_send_lock);
+	ret = r2net_send_status_magic(sc->sc_sock, hdr, syserr,
+				      handler_status);
+	mutex_unlock(&sc->sc_send_lock);
+	hdr = NULL;
+	mlog(0, "sending handler status %d, syserr %d returned %d\n",
+	     handler_status, syserr, ret);
+
+	if (nmh) {
+		BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
+		if (nmh->nh_post_func)
+			(nmh->nh_post_func)(handler_status, nmh->nh_func_data,
+					    ret_data);
+	}
+
+out:
+	if (nmh)
+		r2net_handler_put(nmh);
+	return ret;
+}
+
+static int r2net_check_handshake(struct r2net_sock_container *sc)
+{
+	struct r2net_handshake *hand = page_address(sc->sc_page);
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+
+	if (hand->protocol_version != cpu_to_be64(R2NET_PROTOCOL_VERSION)) {
+		pr_notice("ramster: " SC_NODEF_FMT " Advertised net "
+		       "protocol version %llu but %llu is required. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       (unsigned long long)be64_to_cpu(hand->protocol_version),
+		       R2NET_PROTOCOL_VERSION);
+
+		/* don't bother reconnecting if its the wrong version. */
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	/*
+	 * Ensure timeouts are consistent with other nodes, otherwise
+	 * we can end up with one node thinking that the other must be down,
+	 * but isn't. This can ultimately cause corruption.
+	 */
+	if (be32_to_cpu(hand->r2net_idle_timeout_ms) !=
+				r2net_idle_timeout()) {
+		pr_notice("ramster: " SC_NODEF_FMT " uses a network "
+		       "idle timeout of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2net_idle_timeout_ms),
+		       r2net_idle_timeout());
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	if (be32_to_cpu(hand->r2net_keepalive_delay_ms) !=
+			r2net_keepalive_delay()) {
+		pr_notice("ramster: " SC_NODEF_FMT " uses a keepalive "
+		       "delay of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2net_keepalive_delay_ms),
+		       r2net_keepalive_delay());
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	if (be32_to_cpu(hand->r2hb_heartbeat_timeout_ms) !=
+			R2HB_MAX_WRITE_TIMEOUT_MS) {
+		pr_notice("ramster: " SC_NODEF_FMT " uses a heartbeat "
+		       "timeout of %u ms, but we use %u ms locally. "
+		       "Disconnecting.\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port),
+		       be32_to_cpu(hand->r2hb_heartbeat_timeout_ms),
+		       R2HB_MAX_WRITE_TIMEOUT_MS);
+		r2net_ensure_shutdown(nn, sc, -ENOTCONN);
+		return -1;
+	}
+
+	sc->sc_handshake_ok = 1;
+
+	spin_lock(&nn->nn_lock);
+	/* set valid and queue the idle timers only if it hasn't been
+	 * shut down already */
+	if (nn->nn_sc == sc) {
+		r2net_sc_reset_idle_timer(sc);
+		atomic_set(&nn->nn_timeout, 0);
+		r2net_set_nn_state(nn, sc, 1, 0);
+	}
+	spin_unlock(&nn->nn_lock);
+
+	/* shift everything up as though it wasn't there */
+	sc->sc_page_off -= sizeof(struct r2net_handshake);
+	if (sc->sc_page_off)
+		memmove(hand, hand + 1, sc->sc_page_off);
+
+	return 0;
+}
+
+/* this demuxes the queued rx bytes into header or payload bits and calls
+ * handlers as each full message is read off the socket.  it returns -error,
+ * == 0 eof, or > 0 for progress made.*/
+static int r2net_advance_rx(struct r2net_sock_container *sc)
+{
+	struct r2net_msg *hdr;
+	int ret = 0;
+	void *data;
+	size_t datalen;
+
+	sclog(sc, "receiving\n");
+	r2net_set_advance_start_time(sc);
+
+	if (unlikely(sc->sc_handshake_ok == 0)) {
+		if (sc->sc_page_off < sizeof(struct r2net_handshake)) {
+			data = page_address(sc->sc_page) + sc->sc_page_off;
+			datalen = sizeof(struct r2net_handshake) -
+							sc->sc_page_off;
+			ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+			if (ret > 0)
+				sc->sc_page_off += ret;
+		}
+
+		if (sc->sc_page_off == sizeof(struct r2net_handshake)) {
+			r2net_check_handshake(sc);
+			if (unlikely(sc->sc_handshake_ok == 0))
+				ret = -EPROTO;
+		}
+		goto out;
+	}
+
+	/* do we need more header? */
+	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
+		data = page_address(sc->sc_page) + sc->sc_page_off;
+		datalen = sizeof(struct r2net_msg) - sc->sc_page_off;
+		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+		if (ret > 0) {
+			sc->sc_page_off += ret;
+			/* only swab incoming here.. we can
+			 * only get here once as we cross from
+			 * being under to over */
+			if (sc->sc_page_off == sizeof(struct r2net_msg)) {
+				hdr = page_address(sc->sc_page);
+				if (be16_to_cpu(hdr->data_len) >
+				    R2NET_MAX_PAYLOAD_BYTES)
+					ret = -EOVERFLOW;
+				WARN_ON_ONCE(ret == -EOVERFLOW);
+			}
+		}
+		if (ret <= 0)
+			goto out;
+	}
+
+	if (sc->sc_page_off < sizeof(struct r2net_msg)) {
+		/* oof, still don't have a header */
+		goto out;
+	}
+
+	/* this was swabbed above when we first read it */
+	hdr = page_address(sc->sc_page);
+
+	msglog(hdr, "at page_off %zu\n", sc->sc_page_off);
+
+	/* do we need more payload? */
+	if (sc->sc_page_off - sizeof(struct r2net_msg) <
+					be16_to_cpu(hdr->data_len)) {
+		/* need more payload */
+		data = page_address(sc->sc_page) + sc->sc_page_off;
+		datalen = (sizeof(struct r2net_msg) +
+				be16_to_cpu(hdr->data_len)) -
+				sc->sc_page_off;
+		ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+		if (ret > 0)
+			sc->sc_page_off += ret;
+		if (ret <= 0)
+			goto out;
+	}
+
+	if (sc->sc_page_off - sizeof(struct r2net_msg) ==
+						be16_to_cpu(hdr->data_len)) {
+		/* we can only get here once, the first time we read
+		 * the payload.. so set ret to progress if the handler
+		 * works out. after calling this the message is toast */
+		ret = r2net_process_message(sc, hdr);
+		if (ret == 0)
+			ret = 1;
+		sc->sc_page_off = 0;
+	}
+
+out:
+	sclog(sc, "ret = %d\n", ret);
+	r2net_set_advance_stop_time(sc);
+	return ret;
+}
+
+/* this work func is triggerd by data ready.  it reads until it can read no
+ * more.  it interprets 0, eof, as fatal.  if data_ready hits while we're doing
+ * our work the work struct will be marked and we'll be called again. */
+static void r2net_rx_until_empty(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container, sc_rx_work);
+	int ret;
+
+	do {
+		ret = r2net_advance_rx(sc);
+	} while (ret > 0);
+
+	if (ret <= 0 && ret != -EAGAIN) {
+		struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+		sclog(sc, "saw error %d, closing\n", ret);
+		/* not permanent so read failed handshake can retry */
+		r2net_ensure_shutdown(nn, sc, 0);
+	}
+	sc_put(sc);
+}
+
+static int r2net_set_nodelay(struct socket *sock)
+{
+	int ret, val = 1;
+	mm_segment_t oldfs;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+
+	/*
+	 * Dear unsuspecting programmer,
+	 *
+	 * Don't use sock_setsockopt() for SOL_TCP.  It doesn't check its level
+	 * argument and assumes SOL_SOCKET so, say, your TCP_NODELAY will
+	 * silently turn into SO_DEBUG.
+	 *
+	 * Yours,
+	 * Keeper of hilariously fragile interfaces.
+	 */
+	ret = sock->ops->setsockopt(sock, SOL_TCP, TCP_NODELAY,
+				    (char __user *)&val, sizeof(val));
+
+	set_fs(oldfs);
+	return ret;
+}
+
+static void r2net_initialize_handshake(void)
+{
+	r2net_hand->r2hb_heartbeat_timeout_ms = cpu_to_be32(
+		R2HB_MAX_WRITE_TIMEOUT_MS);
+	r2net_hand->r2net_idle_timeout_ms = cpu_to_be32(r2net_idle_timeout());
+	r2net_hand->r2net_keepalive_delay_ms = cpu_to_be32(
+		r2net_keepalive_delay());
+	r2net_hand->r2net_reconnect_delay_ms = cpu_to_be32(
+		r2net_reconnect_delay());
+}
+
+/* ------------------------------------------------------------ */
+
+/* called when a connect completes and after a sock is accepted.  the
+ * rx path will see the response and mark the sc valid */
+static void r2net_sc_connect_completed(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+			container_of(work, struct r2net_sock_container,
+			     sc_connect_work);
+
+	mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n",
+		(unsigned long long)R2NET_PROTOCOL_VERSION,
+		(unsigned long long)be64_to_cpu(r2net_hand->connector_id));
+
+	r2net_initialize_handshake();
+	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
+	sc_put(sc);
+}
+
+/* this is called as a work_struct func. */
+static void r2net_sc_send_keep_req(struct work_struct *work)
+{
+	struct r2net_sock_container *sc =
+		container_of(work, struct r2net_sock_container,
+			     sc_keepalive_work.work);
+
+	r2net_sendpage(sc, r2net_keep_req, sizeof(*r2net_keep_req));
+	sc_put(sc);
+}
+
+/* socket shutdown does a del_timer_sync against this as it tears down.
+ * we can't start this timer until we've got to the point in sc buildup
+ * where shutdown is going to be involved */
+static void r2net_idle_timer(unsigned long data)
+{
+	struct r2net_sock_container *sc = (struct r2net_sock_container *)data;
+	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
+#ifdef CONFIG_DEBUG_FS
+	unsigned long msecs = ktime_to_ms(ktime_get()) -
+		ktime_to_ms(sc->sc_tv_timer);
+#else
+	unsigned long msecs = r2net_idle_timeout();
+#endif
+
+	pr_notice("ramster: Connection to " SC_NODEF_FMT " has been "
+	       "idle for %lu.%lu secs, shutting it down.\n",
+		sc->sc_node->nd_name, sc->sc_node->nd_num,
+		&sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port),
+	       msecs / 1000, msecs % 1000);
+
+	/*
+	 * Initialize the nn_timeout so that the next connection attempt
+	 * will continue in r2net_start_connect.
+	 */
+	atomic_set(&nn->nn_timeout, 1);
+	r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
+}
+
+static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc)
+{
+	r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
+	r2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
+		      msecs_to_jiffies(r2net_keepalive_delay()));
+	r2net_set_sock_timer(sc);
+	mod_timer(&sc->sc_idle_timeout,
+	       jiffies + msecs_to_jiffies(r2net_idle_timeout()));
+}
+
+static void r2net_sc_postpone_idle(struct r2net_sock_container *sc)
+{
+	/* Only push out an existing timer */
+	if (timer_pending(&sc->sc_idle_timeout))
+		r2net_sc_reset_idle_timer(sc);
+}
+
+/* this work func is kicked whenever a path sets the nn state which doesn't
+ * have valid set.  This includes seeing hb come up, losing a connection,
+ * having a connect attempt fail, etc. This centralizes the logic which decides
+ * if a connect attempt should be made or if we should give up and all future
+ * transmit attempts should fail */
+static void r2net_start_connect(struct work_struct *work)
+{
+	struct r2net_node *nn =
+		container_of(work, struct r2net_node, nn_connect_work.work);
+	struct r2net_sock_container *sc = NULL;
+	struct r2nm_node *node = NULL, *mynode = NULL;
+	struct socket *sock = NULL;
+	struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
+	int ret = 0, stop;
+	unsigned int timeout;
+
+	/* if we're greater we initiate tx, otherwise we accept */
+	if (r2nm_this_node() <= r2net_num_from_nn(nn))
+		goto out;
+
+	/* watch for racing with tearing a node down */
+	node = r2nm_get_node_by_num(r2net_num_from_nn(nn));
+	if (node == NULL) {
+		ret = 0;
+		goto out;
+	}
+
+	mynode = r2nm_get_node_by_num(r2nm_this_node());
+	if (mynode == NULL) {
+		ret = 0;
+		goto out;
+	}
+
+	spin_lock(&nn->nn_lock);
+	/*
+	 * see if we already have one pending or have given up.
+	 * For nn_timeout, it is set when we close the connection
+	 * because of the idle time out. So it means that we have
+	 * at least connected to that node successfully once,
+	 * now try to connect to it again.
+	 */
+	timeout = atomic_read(&nn->nn_timeout);
+	stop = (nn->nn_sc ||
+		(nn->nn_persistent_error &&
+		(nn->nn_persistent_error != -ENOTCONN || timeout == 0)));
+	spin_unlock(&nn->nn_lock);
+	if (stop)
+		goto out;
+
+	nn->nn_last_connect_attempt = jiffies;
+
+	sc = sc_alloc(node);
+	if (sc == NULL) {
+		mlog(0, "couldn't allocate sc\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	if (ret < 0) {
+		mlog(0, "can't create socket: %d\n", ret);
+		goto out;
+	}
+	sc->sc_sock = sock; /* freed by sc_kref_release */
+
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
+	myaddr.sin_family = AF_INET;
+	myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
+	myaddr.sin_port = htons(0); /* any port */
+
+	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
+			      sizeof(myaddr));
+	if (ret) {
+		mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
+		     ret, &mynode->nd_ipv4_address);
+		goto out;
+	}
+
+	ret = r2net_set_nodelay(sc->sc_sock);
+	if (ret) {
+		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
+		goto out;
+	}
+
+	r2net_register_callbacks(sc->sc_sock->sk, sc);
+
+	spin_lock(&nn->nn_lock);
+	/* handshake completion will set nn->nn_sc_valid */
+	r2net_set_nn_state(nn, sc, 0, 0);
+	spin_unlock(&nn->nn_lock);
+
+	remoteaddr.sin_family = AF_INET;
+	remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
+	remoteaddr.sin_port = node->nd_ipv4_port;
+
+	ret = sc->sc_sock->ops->connect(sc->sc_sock,
+					(struct sockaddr *)&remoteaddr,
+					sizeof(remoteaddr),
+					O_NONBLOCK);
+	if (ret == -EINPROGRESS)
+		ret = 0;
+
+out:
+	if (ret) {
+		pr_notice("ramster: Connect attempt to " SC_NODEF_FMT
+		       " failed with errno %d\n", sc->sc_node->nd_name,
+			sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
+			ntohs(sc->sc_node->nd_ipv4_port), ret);
+		/* 0 err so that another will be queued and attempted
+		 * from set_nn_state */
+		if (sc)
+			r2net_ensure_shutdown(nn, sc, 0);
+	}
+	if (sc)
+		sc_put(sc);
+	if (node)
+		r2nm_node_put(node);
+	if (mynode)
+		r2nm_node_put(mynode);
+
+	return;
+}
+
+static void r2net_connect_expired(struct work_struct *work)
+{
+	struct r2net_node *nn =
+		container_of(work, struct r2net_node, nn_connect_expired.work);
+
+	spin_lock(&nn->nn_lock);
+	if (!nn->nn_sc_valid) {
+		pr_notice("ramster: No connection established with "
+		       "node %u after %u.%u seconds, giving up.\n",
+		     r2net_num_from_nn(nn),
+		     r2net_idle_timeout() / 1000,
+		     r2net_idle_timeout() % 1000);
+
+		r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
+	}
+	spin_unlock(&nn->nn_lock);
+}
+
+static void r2net_still_up(struct work_struct *work)
+{
+}
+
+/* ------------------------------------------------------------ */
+
+void r2net_disconnect_node(struct r2nm_node *node)
+{
+	struct r2net_node *nn = r2net_nn_from_num(node->nd_num);
+
+	/* don't reconnect until it's heartbeating again */
+	spin_lock(&nn->nn_lock);
+	atomic_set(&nn->nn_timeout, 0);
+	r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
+	spin_unlock(&nn->nn_lock);
+
+	if (r2net_wq) {
+		cancel_delayed_work(&nn->nn_connect_expired);
+		cancel_delayed_work(&nn->nn_connect_work);
+		cancel_delayed_work(&nn->nn_still_up);
+		flush_workqueue(r2net_wq);
+	}
+}
+
+static void r2net_hb_node_down_cb(struct r2nm_node *node, int node_num,
+				  void *data)
+{
+	if (!node)
+		return;
+
+	if (node_num != r2nm_this_node())
+		r2net_disconnect_node(node);
+
+	BUG_ON(atomic_read(&r2net_connected_peers) < 0);
+}
+
+static void r2net_hb_node_up_cb(struct r2nm_node *node, int node_num,
+				void *data)
+{
+	struct r2net_node *nn = r2net_nn_from_num(node_num);
+
+	BUG_ON(!node);
+
+	/* ensure an immediate connect attempt */
+	nn->nn_last_connect_attempt = jiffies -
+		(msecs_to_jiffies(r2net_reconnect_delay()) + 1);
+
+	if (node_num != r2nm_this_node()) {
+		/* believe it or not, accept and node hearbeating testing
+		 * can succeed for this node before we got here.. so
+		 * only use set_nn_state to clear the persistent error
+		 * if that hasn't already happened */
+		spin_lock(&nn->nn_lock);
+		atomic_set(&nn->nn_timeout, 0);
+		if (nn->nn_persistent_error)
+			r2net_set_nn_state(nn, NULL, 0, 0);
+		spin_unlock(&nn->nn_lock);
+	}
+}
+
+void r2net_unregister_hb_callbacks(void)
+{
+	r2hb_unregister_callback(NULL, &r2net_hb_up);
+	r2hb_unregister_callback(NULL, &r2net_hb_down);
+}
+
+int r2net_register_hb_callbacks(void)
+{
+	int ret;
+
+	r2hb_setup_callback(&r2net_hb_down, R2HB_NODE_DOWN_CB,
+			    r2net_hb_node_down_cb, NULL, R2NET_HB_PRI);
+	r2hb_setup_callback(&r2net_hb_up, R2HB_NODE_UP_CB,
+			    r2net_hb_node_up_cb, NULL, R2NET_HB_PRI);
+
+	ret = r2hb_register_callback(NULL, &r2net_hb_up);
+	if (ret == 0)
+		ret = r2hb_register_callback(NULL, &r2net_hb_down);
+
+	if (ret)
+		r2net_unregister_hb_callbacks();
+
+	return ret;
+}
+
+/* ------------------------------------------------------------ */
+
+static int r2net_accept_one(struct socket *sock)
+{
+	int ret, slen;
+	struct sockaddr_in sin;
+	struct socket *new_sock = NULL;
+	struct r2nm_node *node = NULL;
+	struct r2nm_node *local_node = NULL;
+	struct r2net_sock_container *sc = NULL;
+	struct r2net_node *nn;
+
+	BUG_ON(sock == NULL);
+	ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type,
+			       sock->sk->sk_protocol, &new_sock);
+	if (ret)
+		goto out;
+
+	new_sock->type = sock->type;
+	new_sock->ops = sock->ops;
+	ret = sock->ops->accept(sock, new_sock, O_NONBLOCK);
+	if (ret < 0)
+		goto out;
+
+	new_sock->sk->sk_allocation = GFP_ATOMIC;
+
+	ret = r2net_set_nodelay(new_sock);
+	if (ret) {
+		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
+		goto out;
+	}
+
+	slen = sizeof(sin);
+	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
+				       &slen, 1);
+	if (ret < 0)
+		goto out;
+
+	node = r2nm_get_node_by_ip(sin.sin_addr.s_addr);
+	if (node == NULL) {
+		pr_notice("ramster: Attempt to connect from unknown "
+		       "node at %pI4:%d\n", &sin.sin_addr.s_addr,
+		       ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (r2nm_this_node() >= node->nd_num) {
+		local_node = r2nm_get_node_by_num(r2nm_this_node());
+		pr_notice("ramster: Unexpected connect attempt seen "
+		       "at node '%s' (%u, %pI4:%d) from node '%s' (%u, "
+		       "%pI4:%d)\n", local_node->nd_name, local_node->nd_num,
+		       &(local_node->nd_ipv4_address),
+		       ntohs(local_node->nd_ipv4_port), node->nd_name,
+		       node->nd_num, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* this happens all the time when the other node sees our heartbeat
+	 * and tries to connect before we see their heartbeat */
+	if (!r2hb_check_node_heartbeating_from_callback(node->nd_num)) {
+		mlog(ML_CONN, "attempt to connect from node '%s' at "
+		     "%pI4:%d but it isn't heartbeating\n",
+		     node->nd_name, &sin.sin_addr.s_addr,
+		     ntohs(sin.sin_port));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nn = r2net_nn_from_num(node->nd_num);
+
+	spin_lock(&nn->nn_lock);
+	if (nn->nn_sc)
+		ret = -EBUSY;
+	else
+		ret = 0;
+	spin_unlock(&nn->nn_lock);
+	if (ret) {
+		pr_notice("ramster: Attempt to connect from node '%s' "
+		       "at %pI4:%d but it already has an open connection\n",
+		       node->nd_name, &sin.sin_addr.s_addr,
+		       ntohs(sin.sin_port));
+		goto out;
+	}
+
+	sc = sc_alloc(node);
+	if (sc == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	sc->sc_sock = new_sock;
+	new_sock = NULL;
+
+	spin_lock(&nn->nn_lock);
+	atomic_set(&nn->nn_timeout, 0);
+	r2net_set_nn_state(nn, sc, 0, 0);
+	spin_unlock(&nn->nn_lock);
+
+	r2net_register_callbacks(sc->sc_sock->sk, sc);
+	r2net_sc_queue_work(sc, &sc->sc_rx_work);
+
+	r2net_initialize_handshake();
+	r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
+
+out:
+	if (new_sock)
+		sock_release(new_sock);
+	if (node)
+		r2nm_node_put(node);
+	if (local_node)
+		r2nm_node_put(local_node);
+	if (sc)
+		sc_put(sc);
+	return ret;
+}
+
+static void r2net_accept_many(struct work_struct *work)
+{
+	struct socket *sock = r2net_listen_sock;
+	while (r2net_accept_one(sock) == 0)
+		cond_resched();
+}
+
+static void r2net_listen_data_ready(struct sock *sk, int bytes)
+{
+	void (*ready)(struct sock *sk, int bytes);
+
+	read_lock(&sk->sk_callback_lock);
+	ready = sk->sk_user_data;
+	if (ready == NULL) { /* check for teardown race */
+		ready = sk->sk_data_ready;
+		goto out;
+	}
+
+	/* ->sk_data_ready is also called for a newly established child socket
+	 * before it has been accepted and the acceptor has set up their
+	 * data_ready.. we only want to queue listen work for our listening
+	 * socket */
+	if (sk->sk_state == TCP_LISTEN) {
+		mlog(ML_TCP, "bytes: %d\n", bytes);
+		queue_work(r2net_wq, &r2net_listen_work);
+	}
+
+out:
+	read_unlock(&sk->sk_callback_lock);
+	ready(sk, bytes);
+}
+
+static int r2net_open_listening_sock(__be32 addr, __be16 port)
+{
+	struct socket *sock = NULL;
+	int ret;
+	struct sockaddr_in sin = {
+		.sin_family = PF_INET,
+		.sin_addr = { .s_addr = addr },
+		.sin_port = port,
+	};
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	if (ret < 0) {
+		pr_err("ramster: Error %d while creating socket\n", ret);
+		goto out;
+	}
+
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
+	write_lock_bh(&sock->sk->sk_callback_lock);
+	sock->sk->sk_user_data = sock->sk->sk_data_ready;
+	sock->sk->sk_data_ready = r2net_listen_data_ready;
+	write_unlock_bh(&sock->sk->sk_callback_lock);
+
+	r2net_listen_sock = sock;
+	INIT_WORK(&r2net_listen_work, r2net_accept_many);
+
+	sock->sk->sk_reuse = /* SK_CAN_REUSE FIXME FOR 3.4 */ 1;
+	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
+	if (ret < 0) {
+		pr_err("ramster: Error %d while binding socket at %pI4:%u\n",
+			ret, &addr, ntohs(port));
+		goto out;
+	}
+
+	ret = sock->ops->listen(sock, 64);
+	if (ret < 0)
+		pr_err("ramster: Error %d while listening on %pI4:%u\n",
+		       ret, &addr, ntohs(port));
+
+out:
+	if (ret) {
+		r2net_listen_sock = NULL;
+		if (sock)
+			sock_release(sock);
+	}
+	return ret;
+}
+
+/*
+ * called from node manager when we should bring up our network listening
+ * socket.  node manager handles all the serialization to only call this
+ * once and to match it with r2net_stop_listening().  note,
+ * r2nm_this_node() doesn't work yet as we're being called while it
+ * is being set up.
+ */
+int r2net_start_listening(struct r2nm_node *node)
+{
+	int ret = 0;
+
+	BUG_ON(r2net_wq != NULL);
+	BUG_ON(r2net_listen_sock != NULL);
+
+	mlog(ML_KTHREAD, "starting r2net thread...\n");
+	r2net_wq = create_singlethread_workqueue("r2net");
+	if (r2net_wq == NULL) {
+		mlog(ML_ERROR, "unable to launch r2net thread\n");
+		return -ENOMEM; /* ? */
+	}
+
+	ret = r2net_open_listening_sock(node->nd_ipv4_address,
+					node->nd_ipv4_port);
+	if (ret) {
+		destroy_workqueue(r2net_wq);
+		r2net_wq = NULL;
+	}
+
+	return ret;
+}
+
+/* again, r2nm_this_node() doesn't work here as we're involved in
+ * tearing it down */
+void r2net_stop_listening(struct r2nm_node *node)
+{
+	struct socket *sock = r2net_listen_sock;
+	size_t i;
+
+	BUG_ON(r2net_wq == NULL);
+	BUG_ON(r2net_listen_sock == NULL);
+
+	/* stop the listening socket from generating work */
+	write_lock_bh(&sock->sk->sk_callback_lock);
+	sock->sk->sk_data_ready = sock->sk->sk_user_data;
+	sock->sk->sk_user_data = NULL;
+	write_unlock_bh(&sock->sk->sk_callback_lock);
+
+	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
+		struct r2nm_node *node = r2nm_get_node_by_num(i);
+		if (node) {
+			r2net_disconnect_node(node);
+			r2nm_node_put(node);
+		}
+	}
+
+	/* finish all work and tear down the work queue */
+	mlog(ML_KTHREAD, "waiting for r2net thread to exit....\n");
+	destroy_workqueue(r2net_wq);
+	r2net_wq = NULL;
+
+	sock_release(r2net_listen_sock);
+	r2net_listen_sock = NULL;
+}
+
+void r2net_hb_node_up_manual(int node_num)
+{
+	struct r2nm_node dummy;
+	if (r2nm_single_cluster == NULL)
+		pr_err("ramster: cluster not alive, node_up_manual ignored\n");
+	else {
+		r2hb_manual_set_node_heartbeating(node_num);
+		r2net_hb_node_up_cb(&dummy, node_num, NULL);
+	}
+}
+
+/* ------------------------------------------------------------ */
+
+int r2net_init(void)
+{
+	unsigned long i;
+
+	if (r2net_debugfs_init())
+		return -ENOMEM;
+
+	r2net_hand = kzalloc(sizeof(struct r2net_handshake), GFP_KERNEL);
+	r2net_keep_req = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
+	r2net_keep_resp = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
+	if (!r2net_hand || !r2net_keep_req || !r2net_keep_resp) {
+		kfree(r2net_hand);
+		kfree(r2net_keep_req);
+		kfree(r2net_keep_resp);
+		return -ENOMEM;
+	}
+
+	r2net_hand->protocol_version = cpu_to_be64(R2NET_PROTOCOL_VERSION);
+	r2net_hand->connector_id = cpu_to_be64(1);
+
+	r2net_keep_req->magic = cpu_to_be16(R2NET_MSG_KEEP_REQ_MAGIC);
+	r2net_keep_resp->magic = cpu_to_be16(R2NET_MSG_KEEP_RESP_MAGIC);
+
+	for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
+		struct r2net_node *nn = r2net_nn_from_num(i);
+
+		atomic_set(&nn->nn_timeout, 0);
+		spin_lock_init(&nn->nn_lock);
+		INIT_DELAYED_WORK(&nn->nn_connect_work, r2net_start_connect);
+		INIT_DELAYED_WORK(&nn->nn_connect_expired,
+				  r2net_connect_expired);
+		INIT_DELAYED_WORK(&nn->nn_still_up, r2net_still_up);
+		/* until we see hb from a node we'll return einval */
+		nn->nn_persistent_error = -ENOTCONN;
+		init_waitqueue_head(&nn->nn_sc_wq);
+		idr_init(&nn->nn_status_idr);
+		INIT_LIST_HEAD(&nn->nn_status_list);
+	}
+
+	return 0;
+}
+
+void r2net_exit(void)
+{
+	kfree(r2net_hand);
+	kfree(r2net_keep_req);
+	kfree(r2net_keep_resp);
+	r2net_debugfs_exit();
+}
diff --git a/drivers/staging/ramster/cluster/tcp.h b/drivers/staging/ramster/ramster/tcp.h
similarity index 100%
rename from drivers/staging/ramster/cluster/tcp.h
rename to drivers/staging/ramster/ramster/tcp.h
diff --git a/drivers/staging/ramster/cluster/tcp_internal.h b/drivers/staging/ramster/ramster/tcp_internal.h
similarity index 100%
rename from drivers/staging/ramster/cluster/tcp_internal.h
rename to drivers/staging/ramster/ramster/tcp_internal.h
diff --git a/drivers/staging/ramster/tmem.c b/drivers/staging/ramster/tmem.c
index 8f2f689..a2b7e03 100644
--- a/drivers/staging/ramster/tmem.c
+++ b/drivers/staging/ramster/tmem.c
@@ -1,33 +1,43 @@
 /*
  * In-kernel transcendent memory (generic implementation)
  *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
  *
  * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
  * "handles" (triples containing a pool id, and object id, and an index), to
  * pages in a page-accessible memory (PAM).  Tmem references the PAM pages via
  * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
  * set of functions (pamops).  Each pampd contains some representation of
- * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of
- * pages and must be able to insert, find, and delete these pages at a
- * potential frequency of thousands per second concurrently across many CPUs,
- * (and, if used with KVM, across many vcpus across many guests).
- * Tmem is tracked with a hierarchy of data structures, organized by
- * the elements in a handle-tuple: pool_id, object_id, and page index.
- * One or more "clients" (e.g. guests) each provide one or more tmem_pools.
- * Each pool, contains a hash table of rb_trees of tmem_objs.  Each
- * tmem_obj contains a radix-tree-like tree of pointers, with intermediate
- * nodes called tmem_objnodes.  Each leaf pointer in this tree points to
- * a pampd, which is accessible only through a small set of callbacks
- * registered by the PAM implementation (see tmem_register_pamops). Tmem
- * does all memory allocation via a set of callbacks registered by the tmem
- * host implementation (e.g. see tmem_register_hostops).
+ * PAGE_SIZE bytes worth of data. For those familiar with key-value stores,
+ * the tmem handle is a three-level hierarchical key, and the value is always
+ * reconstituted (but not necessarily stored) as PAGE_SIZE bytes and is
+ * referenced in the datastore by the pampd.  The hierarchy is required
+ * to ensure that certain invalidation functions can be performed efficiently
+ * (i.e. flush all indexes associated with this object_id, or
+ * flush all objects associated with this pool).
+ *
+ * Tmem must support potentially millions of pages and must be able to insert,
+ * find, and delete these pages at a potential frequency of thousands per
+ * second concurrently across many CPUs, (and, if used with KVM, across many
+ * vcpus across many guests).  Tmem is tracked with a hierarchy of data
+ * structures, organized by the elements in the handle-tuple: pool_id,
+ * object_id, and page index.  One or more "clients" (e.g. guests) each
+ * provide one or more tmem_pools.  Each pool, contains a hash table of
+ * rb_trees of tmem_objs.  Each tmem_obj contains a radix-tree-like tree
+ * of pointers, with intermediate nodes called tmem_objnodes.  Each leaf
+ * pointer in this tree points to a pampd, which is accessible only through
+ * a small set of callbacks registered by the PAM implementation (see
+ * tmem_register_pamops). Tmem only needs to memory allocation for objs
+ * and objnodes and this is done via a set of callbacks that must be
+ * registered by the tmem host implementation (e.g. see tmem_register_hostops).
  */
 
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/atomic.h>
+#ifdef CONFIG_RAMSTER
 #include <linux/delay.h>
+#endif
 
 #include "tmem.h"
 
@@ -52,7 +62,7 @@
 
 /*
  * A tmem host implementation must use this function to register
- * callbacks for a page-accessible memory (PAM) implementation
+ * callbacks for a page-accessible memory (PAM) implementation.
  */
 static struct tmem_pamops tmem_pamops;
 
@@ -67,42 +77,62 @@
  * So an rb_tree is an ideal data structure to manage tmem_objs.  But because
  * of the potentially huge number of tmem_objs, each pool manages a hashtable
  * of rb_trees to reduce search, insert, delete, and rebalancing time.
- * Each hashbucket also has a lock to manage concurrent access.
+ * Each hashbucket also has a lock to manage concurrent access and no
+ * searches, inserts, or deletions can be performed unless the lock is held.
+ * As a result, care must be taken to ensure tmem routines are not called
+ * recursively; the vast majority of the time, a recursive call may work
+ * but a deadlock will occur a small fraction of the time due to the
+ * hashbucket lock.
  *
- * The following routines manage tmem_objs.  When any tmem_obj is accessed,
- * the hashbucket lock must be held.
+ * The following routines manage tmem_objs.  In all of these routines,
+ * the hashbucket lock is already held.
  */
 
-/* searches for object==oid in pool, returns locked object if found */
-static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
-					struct tmem_oid *oidp)
+/* Search for object==oid in pool, returns object if found. */
+static struct tmem_obj *__tmem_obj_find(struct tmem_hashbucket *hb,
+					struct tmem_oid *oidp,
+					struct rb_node **parent,
+					struct rb_node ***link)
 {
-	struct rb_node *rbnode;
-	struct tmem_obj *obj;
+	struct rb_node *_parent = NULL, **rbnode;
+	struct tmem_obj *obj = NULL;
 
-	rbnode = hb->obj_rb_root.rb_node;
-	while (rbnode) {
-		BUG_ON(RB_EMPTY_NODE(rbnode));
-		obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
+	rbnode = &hb->obj_rb_root.rb_node;
+	while (*rbnode) {
+		BUG_ON(RB_EMPTY_NODE(*rbnode));
+		_parent = *rbnode;
+		obj = rb_entry(*rbnode, struct tmem_obj,
+			       rb_tree_node);
 		switch (tmem_oid_compare(oidp, &obj->oid)) {
 		case 0: /* equal */
 			goto out;
 		case -1:
-			rbnode = rbnode->rb_left;
+			rbnode = &(*rbnode)->rb_left;
 			break;
 		case 1:
-			rbnode = rbnode->rb_right;
+			rbnode = &(*rbnode)->rb_right;
 			break;
 		}
 	}
+
+	if (parent)
+		*parent = _parent;
+	if (link)
+		*link = rbnode;
 	obj = NULL;
 out:
 	return obj;
 }
 
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *);
+static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
+					struct tmem_oid *oidp)
+{
+	return __tmem_obj_find(hb, oidp, NULL, NULL);
+}
 
-/* free an object that has no more pampds in it */
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *, bool);
+
+/* Free an object that has no more pampds in it. */
 static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb)
 {
 	struct tmem_pool *pool;
@@ -113,7 +143,7 @@
 	pool = obj->pool;
 	BUG_ON(pool == NULL);
 	if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */
-		tmem_pampd_destroy_all_in_obj(obj);
+		tmem_pampd_destroy_all_in_obj(obj, false);
 	BUG_ON(obj->objnode_tree_root != NULL);
 	BUG_ON((long)obj->objnode_count != 0);
 	atomic_dec(&pool->obj_count);
@@ -125,15 +155,14 @@
 }
 
 /*
- * initialize, and insert an tmem_object_root (called only if find failed)
+ * Initialize, and insert an tmem_object_root (called only if find failed).
  */
 static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb,
 					struct tmem_pool *pool,
 					struct tmem_oid *oidp)
 {
 	struct rb_root *root = &hb->obj_rb_root;
-	struct rb_node **new = &(root->rb_node), *parent = NULL;
-	struct tmem_obj *this;
+	struct rb_node **new = NULL, *parent = NULL;
 
 	BUG_ON(pool == NULL);
 	atomic_inc(&pool->obj_count);
@@ -143,24 +172,15 @@
 	obj->oid = *oidp;
 	obj->objnode_count = 0;
 	obj->pampd_count = 0;
-	(*tmem_pamops.new_obj)(obj);
+#ifdef CONFIG_RAMSTER
+	if (tmem_pamops.new_obj != NULL)
+		(*tmem_pamops.new_obj)(obj);
+#endif
 	SET_SENTINEL(obj, OBJ);
-	while (*new) {
-		BUG_ON(RB_EMPTY_NODE(*new));
-		this = rb_entry(*new, struct tmem_obj, rb_tree_node);
-		parent = *new;
-		switch (tmem_oid_compare(oidp, &this->oid)) {
-		case 0:
-			BUG(); /* already present; should never happen! */
-			break;
-		case -1:
-			new = &(*new)->rb_left;
-			break;
-		case 1:
-			new = &(*new)->rb_right;
-			break;
-		}
-	}
+
+	if (__tmem_obj_find(hb, oidp, &parent, &new))
+		BUG();
+
 	rb_link_node(&obj->rb_tree_node, parent, new);
 	rb_insert_color(&obj->rb_tree_node, root);
 }
@@ -170,7 +190,7 @@
  * "ephemeral" vs "persistent".  These attributes apply to all tmem_objs
  * and all pampds that belong to a tmem_pool.  A tmem_pool is created
  * or deleted relatively rarely (for example, when a filesystem is
- * mounted or unmounted.
+ * mounted or unmounted).
  */
 
 /* flush all data from a pool and, optionally, free it */
@@ -188,7 +208,7 @@
 		while (rbnode != NULL) {
 			obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
 			rbnode = rb_next(rbnode);
-			tmem_pampd_destroy_all_in_obj(obj);
+			tmem_pampd_destroy_all_in_obj(obj, true);
 			tmem_obj_free(obj, hb);
 			(*tmem_hostops.obj_free)(obj, pool);
 		}
@@ -274,7 +294,7 @@
 }
 
 /*
- * lookup index in object and return associated pampd (or NULL if not found)
+ * Lookup index in object and return associated pampd (or NULL if not found).
  */
 static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
 {
@@ -316,6 +336,7 @@
 	return slot != NULL ? *slot : NULL;
 }
 
+#ifdef CONFIG_RAMSTER
 static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index,
 					void *new_pampd, bool no_free)
 {
@@ -333,6 +354,7 @@
 	}
 	return ret;
 }
+#endif
 
 static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index,
 					void *pampd)
@@ -470,7 +492,7 @@
 	return slot;
 }
 
-/* recursively walk the objnode_tree destroying pampds and objnodes */
+/* Recursively walk the objnode_tree destroying pampds and objnodes. */
 static void tmem_objnode_node_destroy(struct tmem_obj *obj,
 					struct tmem_objnode *objnode,
 					unsigned int ht)
@@ -495,7 +517,8 @@
 	}
 }
 
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj)
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj,
+						bool pool_destroy)
 {
 	if (obj->objnode_tree_root == NULL)
 		return;
@@ -510,7 +533,10 @@
 		obj->objnode_tree_height = 0;
 	}
 	obj->objnode_tree_root = NULL;
-	(*tmem_pamops.free_obj)(obj->pool, obj);
+#ifdef CONFIG_RAMSTER
+	if (tmem_pamops.free_obj != NULL)
+		(*tmem_pamops.free_obj)(obj->pool, obj, pool_destroy);
+#endif
 }
 
 /*
@@ -523,17 +549,16 @@
  */
 
 /*
- * "Put" a page, e.g. copy a page from the kernel into newly allocated
- * PAM space (if such space is available).  Tmem_put is complicated by
- * a corner case: What if a page with matching handle already exists in
- * tmem?  To guarantee coherency, one of two actions is necessary: Either
- * the data for the page must be overwritten, or the page must be
- * "flushed" so that the data is not accessible to a subsequent "get".
- * Since these "duplicate puts" are relatively rare, this implementation
- * always flushes for simplicity.
+ * "Put" a page, e.g. associate the passed pampd with the passed handle.
+ * Tmem_put is complicated by a corner case: What if a page with matching
+ * handle already exists in tmem?  To guarantee coherency, one of two
+ * actions is necessary: Either the data for the page must be overwritten,
+ * or the page must be "flushed" so that the data is not accessible to a
+ * subsequent "get".  Since these "duplicate puts" are relatively rare,
+ * this implementation always flushes for simplicity.
  */
 int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
-		char *data, size_t size, bool raw, int ephemeral)
+		bool raw, void *pampd_to_use)
 {
 	struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL;
 	void *pampd = NULL, *pampd_del = NULL;
@@ -566,19 +591,17 @@
 	}
 	BUG_ON(obj == NULL);
 	BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound));
-	pampd = (*tmem_pamops.create)(data, size, raw, ephemeral,
-					obj->pool, &obj->oid, index);
-	if (unlikely(pampd == NULL))
-		goto free;
+	pampd = pampd_to_use;
+	BUG_ON(pampd_to_use == NULL);
 	ret = tmem_pampd_add_to_obj(obj, index, pampd);
 	if (unlikely(ret == -ENOMEM))
 		/* may have partially built objnode tree ("stump") */
 		goto delete_and_free;
+	(*tmem_pamops.create_finish)(pampd, is_ephemeral(pool));
 	goto out;
 
 delete_and_free:
 	(void)tmem_pampd_delete_from_obj(obj, index);
-free:
 	if (pampd)
 		(*tmem_pamops.free)(pampd, pool, NULL, 0, true);
 	if (objnew) {
@@ -590,6 +613,16 @@
 	return ret;
 }
 
+#ifdef CONFIG_RAMSTER
+/*
+ * For ramster only:  The following routines provide a two-step sequence
+ * to allow the caller to replace a pampd in the tmem data structures with
+ * another pampd. Here, we lookup the passed handle and, if found, return the
+ * associated pampd and object, leaving the hashbucket locked and returning
+ * a reference to it.  The caller is expected to immediately call the
+ * matching tmem_localify_finish routine which will handles the replacement
+ * and unlocks the hashbucket.
+ */
 void *tmem_localify_get_pampd(struct tmem_pool *pool, struct tmem_oid *oidp,
 				uint32_t index, struct tmem_obj **ret_obj,
 				void **saved_hb)
@@ -618,6 +651,7 @@
 	if (pampd != NULL) {
 		BUG_ON(obj == NULL);
 		(void)tmem_pampd_replace_in_obj(obj, index, pampd, 1);
+		(*tmem_pamops.create_finish)(pampd, is_ephemeral(obj->pool));
 	} else if (delete) {
 		BUG_ON(obj == NULL);
 		(void)tmem_pampd_delete_from_obj(obj, index);
@@ -625,6 +659,9 @@
 	spin_unlock(&hb->lock);
 }
 
+/*
+ * For ramster only.  Helper function to support asynchronous tmem_get.
+ */
 static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb,
 				struct tmem_pool *pool, struct tmem_oid *oidp,
 				uint32_t index, bool free, char *data)
@@ -633,7 +670,6 @@
 	bool intransit = false;
 	int ret = 0;
 
-
 	if (!is_ephemeral(pool))
 		new_pampd = (*tmem_pamops.repatriate_preload)(
 				old_pampd, pool, oidp, index, &intransit);
@@ -646,60 +682,91 @@
 	if (!intransit)
 		ret = (*tmem_pamops.repatriate)(old_pampd, new_pampd, pool,
 						oidp, index, free, data);
+	if (ret == -EAGAIN) {
+		/* rare I think, but should cond_resched()??? */
+		usleep_range(10, 1000);
+	} else if (ret == -ENOTCONN || ret == -EHOSTDOWN) {
+		ret = -1;
+	} else if (ret != 0 && ret != -ENOENT) {
+		ret = -1;
+	}
+	/* note hb->lock has now been unlocked */
 	return ret;
 }
 
 /*
- * "Get" a page, e.g. if one can be found, copy the tmem page with the
- * matching handle from PAM space to the kernel.  By tmem definition,
- * when a "get" is successful on an ephemeral page, the page is "flushed",
- * and when a "get" is successful on a persistent page, the page is retained
- * in tmem.  Note that to preserve
+ * For ramster only.  If a page in tmem matches the handle, replace the
+ * page so that any subsequent "get" gets the new page.  Returns 0 if
+ * there was a page to replace, else returns -1.
+ */
+int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
+			uint32_t index, void *new_pampd)
+{
+	struct tmem_obj *obj;
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0);
+	/* if we bug here, pamops wasn't properly set up for ramster */
+	BUG_ON(tmem_pamops.replace_in_obj == NULL);
+	ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+#endif
+
+/*
+ * "Get" a page, e.g. if a pampd can be found matching the passed handle,
+ * use a pamops callback to recreated the page from the pampd with the
+ * matching handle.  By tmem definition, when a "get" is successful on
+ * an ephemeral page, the page is "flushed", and when a "get" is successful
+ * on a persistent page, the page is retained in tmem.  Note that to preserve
  * coherency, "get" can never be skipped if tmem contains the data.
  * That is, if a get is done with a certain handle and fails, any
  * subsequent "get" must also fail (unless of course there is a
  * "put" done with the same handle).
-
  */
 int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
-		char *data, size_t *size, bool raw, int get_and_free)
+		char *data, size_t *sizep, bool raw, int get_and_free)
 {
 	struct tmem_obj *obj;
-	void *pampd;
+	void *pampd = NULL;
 	bool ephemeral = is_ephemeral(pool);
 	int ret = -1;
 	struct tmem_hashbucket *hb;
 	bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
-	bool lock_held = 0;
+	bool lock_held = false;
 	void **ppampd;
 
-again:
-	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
-	spin_lock(&hb->lock);
-	lock_held = 1;
-	obj = tmem_obj_find(hb, oidp);
-	if (obj == NULL)
-		goto out;
-	ppampd = __tmem_pampd_lookup_in_obj(obj, index);
-	if (ppampd == NULL)
-		goto out;
-	if (tmem_pamops.is_remote(*ppampd)) {
-		ret = tmem_repatriate(ppampd, hb, pool, oidp,
-					index, free, data);
-		lock_held = 0; /* note hb->lock has been unlocked */
-		if (ret == -EAGAIN) {
-			/* rare I think, but should cond_resched()??? */
-			usleep_range(10, 1000);
-			goto again;
-		} else if (ret != 0) {
-			if (ret != -ENOENT)
-				pr_err("UNTESTED case in tmem_get, ret=%d\n",
-						ret);
-			ret = -1;
+	do {
+		hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+		spin_lock(&hb->lock);
+		lock_held = true;
+		obj = tmem_obj_find(hb, oidp);
+		if (obj == NULL)
 			goto out;
+		ppampd = __tmem_pampd_lookup_in_obj(obj, index);
+		if (ppampd == NULL)
+			goto out;
+#ifdef CONFIG_RAMSTER
+		if ((tmem_pamops.is_remote != NULL) &&
+		     tmem_pamops.is_remote(*ppampd)) {
+			ret = tmem_repatriate(ppampd, hb, pool, oidp,
+						index, free, data);
+			/* tmem_repatriate releases hb->lock */
+			lock_held = false;
+			*sizep = PAGE_SIZE;
+			if (ret != -EAGAIN)
+				goto out;
 		}
-		goto out;
-	}
+#endif
+	} while (ret == -EAGAIN);
 	if (free)
 		pampd = tmem_pampd_delete_from_obj(obj, index);
 	else
@@ -715,10 +782,10 @@
 	}
 	if (free)
 		ret = (*tmem_pamops.get_data_and_free)(
-				data, size, raw, pampd, pool, oidp, index);
+				data, sizep, raw, pampd, pool, oidp, index);
 	else
 		ret = (*tmem_pamops.get_data)(
-				data, size, raw, pampd, pool, oidp, index);
+				data, sizep, raw, pampd, pool, oidp, index);
 	if (ret < 0)
 		goto out;
 	ret = 0;
@@ -762,30 +829,6 @@
 }
 
 /*
- * If a page in tmem matches the handle, replace the page so that any
- * subsequent "get" gets the new page.  Returns the new page if
- * there was a page to replace, else returns NULL.
- */
-int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
-			uint32_t index, void *new_pampd)
-{
-	struct tmem_obj *obj;
-	int ret = -1;
-	struct tmem_hashbucket *hb;
-
-	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
-	spin_lock(&hb->lock);
-	obj = tmem_obj_find(hb, oidp);
-	if (obj == NULL)
-		goto out;
-	new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0);
-	ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
-out:
-	spin_unlock(&hb->lock);
-	return ret;
-}
-
-/*
  * "Flush" all pages in tmem matching this oid.
  */
 int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp)
@@ -799,7 +842,7 @@
 	obj = tmem_obj_find(hb, oidp);
 	if (obj == NULL)
 		goto out;
-	tmem_pampd_destroy_all_in_obj(obj);
+	tmem_pampd_destroy_all_in_obj(obj, false);
 	tmem_obj_free(obj, hb);
 	(*tmem_hostops.obj_free)(obj, pool);
 	ret = 0;
diff --git a/drivers/staging/ramster/tmem.h b/drivers/staging/ramster/tmem.h
index 47f1918..adbe5a8 100644
--- a/drivers/staging/ramster/tmem.h
+++ b/drivers/staging/ramster/tmem.h
@@ -3,23 +3,20 @@
  *
  * Transcendent memory
  *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
  */
 
 #ifndef _TMEM_H_
 #define _TMEM_H_
 
+#include <linux/types.h>
 #include <linux/highmem.h>
 #include <linux/hash.h>
 #include <linux/atomic.h>
 
 /*
- * These are pre-defined by the Xen<->Linux ABI
+ * These are defined by the Xen<->Linux ABI so should remain consistent
  */
-#define TMEM_PUT_PAGE			4
-#define TMEM_GET_PAGE			5
-#define TMEM_FLUSH_PAGE			6
-#define TMEM_FLUSH_OBJECT		7
 #define TMEM_POOL_PERSIST		1
 #define TMEM_POOL_SHARED		2
 #define TMEM_POOL_PRECOMPRESSED		4
@@ -31,7 +28,7 @@
  * sentinels have proven very useful for debugging but can be removed
  * or disabled before final merge.
  */
-#define SENTINELS
+#undef SENTINELS
 #ifdef SENTINELS
 #define DECL_SENTINEL uint32_t sentinel;
 #define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL)
@@ -46,7 +43,7 @@
 #define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
 #endif
 
-#define ASSERT_SPINLOCK(_l)	WARN_ON(!spin_is_locked(_l))
+#define ASSERT_SPINLOCK(_l)	lockdep_assert_held(_l)
 
 /*
  * A pool is the highest-level data structure managed by tmem and
@@ -88,31 +85,6 @@
 	uint64_t oid[3];
 };
 
-struct tmem_xhandle {
-	uint8_t client_id;
-	uint8_t xh_data_cksum;
-	uint16_t xh_data_size;
-	uint16_t pool_id;
-	struct tmem_oid oid;
-	uint32_t index;
-	void *extra;
-};
-
-static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id,
-					struct tmem_pool *pool,
-					struct tmem_oid *oidp,
-					uint32_t index)
-{
-	struct tmem_xhandle xh;
-	xh.client_id = client_id;
-	xh.xh_data_cksum = (uint8_t)-1;
-	xh.xh_data_size = (uint16_t)-1;
-	xh.pool_id = pool->pool_id;
-	xh.oid = *oidp;
-	xh.index = index;
-	return xh;
-}
-
 static inline void tmem_oid_set_invalid(struct tmem_oid *oidp)
 {
 	oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL;
@@ -154,6 +126,34 @@
 				TMEM_HASH_BUCKET_BITS);
 }
 
+#ifdef CONFIG_RAMSTER
+struct tmem_xhandle {
+	uint8_t client_id;
+	uint8_t xh_data_cksum;
+	uint16_t xh_data_size;
+	uint16_t pool_id;
+	struct tmem_oid oid;
+	uint32_t index;
+	void *extra;
+};
+
+static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id,
+					struct tmem_pool *pool,
+					struct tmem_oid *oidp,
+					uint32_t index)
+{
+	struct tmem_xhandle xh;
+	xh.client_id = client_id;
+	xh.xh_data_cksum = (uint8_t)-1;
+	xh.xh_data_size = (uint16_t)-1;
+	xh.pool_id = pool->pool_id;
+	xh.oid = *oidp;
+	xh.index = index;
+	return xh;
+}
+#endif
+
+
 /*
  * A tmem_obj contains an identifier (oid), pointers to the parent
  * pool and the rb_tree to which it belongs, counters, and an ordered
@@ -171,11 +171,15 @@
 	unsigned int objnode_tree_height;
 	unsigned long objnode_count;
 	long pampd_count;
-	/* for current design of ramster, all pages belonging to
+#ifdef CONFIG_RAMSTER
+	/*
+	 * for current design of ramster, all pages belonging to
 	 * an object reside on the same remotenode and extra is
 	 * used to record the number of the remotenode so a
-	 * flush-object operation can specify it */
-	void *extra; /* for use by pampd implementation */
+	 * flush-object operation can specify it
+	 */
+	void *extra; /* for private use by pampd implementation */
+#endif
 	DECL_SENTINEL
 };
 
@@ -193,10 +197,17 @@
 	unsigned int slots_in_use;
 };
 
+struct tmem_handle {
+	struct tmem_oid oid; /* 24 bytes */
+	uint32_t index;
+	uint16_t pool_id;
+	uint16_t client_id;
+};
+
+
 /* pampd abstract datatype methods provided by the PAM implementation */
 struct tmem_pamops {
-	void *(*create)(char *, size_t, bool, int,
-			struct tmem_pool *, struct tmem_oid *, uint32_t);
+	void (*create_finish)(void *, bool);
 	int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *,
 				struct tmem_oid *, uint32_t);
 	int (*get_data_and_free)(char *, size_t *, bool, void *,
@@ -204,14 +215,16 @@
 				uint32_t);
 	void (*free)(void *, struct tmem_pool *,
 				struct tmem_oid *, uint32_t, bool);
-	void (*free_obj)(struct tmem_pool *, struct tmem_obj *);
-	bool (*is_remote)(void *);
+#ifdef CONFIG_RAMSTER
+	void (*new_obj)(struct tmem_obj *);
+	void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool);
 	void *(*repatriate_preload)(void *, struct tmem_pool *,
 					struct tmem_oid *, uint32_t, bool *);
 	int (*repatriate)(void *, void *, struct tmem_pool *,
 				struct tmem_oid *, uint32_t, bool, void *);
-	void (*new_obj)(struct tmem_obj *);
+	bool (*is_remote)(void *);
 	int (*replace_in_obj)(void *, struct tmem_obj *);
+#endif
 };
 extern void tmem_register_pamops(struct tmem_pamops *m);
 
@@ -226,9 +239,15 @@
 
 /* core tmem accessor functions */
 extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index,
-			char *, size_t, bool, int);
+			bool, void *);
 extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
 			char *, size_t *, bool, int);
+extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
+			uint32_t index);
+extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
+extern int tmem_destroy_pool(struct tmem_pool *);
+extern void tmem_new_pool(struct tmem_pool *, uint32_t);
+#ifdef CONFIG_RAMSTER
 extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
 			void *);
 extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *,
@@ -236,9 +255,5 @@
 				   void **);
 extern void tmem_localify_finish(struct tmem_obj *, uint32_t index,
 				 void *, void *, bool);
-extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
-			uint32_t index);
-extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
-extern int tmem_destroy_pool(struct tmem_pool *);
-extern void tmem_new_pool(struct tmem_pool *, uint32_t);
+#endif
 #endif /* _TMEM_H */
diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c
deleted file mode 100644
index 44ceb0b..0000000
--- a/drivers/staging/ramster/xvmalloc.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifdef CONFIG_ZRAM_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/errno.h>
-#include <linux/highmem.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "xvmalloc.h"
-#include "xvmalloc_int.h"
-
-static void stat_inc(u64 *value)
-{
-	*value = *value + 1;
-}
-
-static void stat_dec(u64 *value)
-{
-	*value = *value - 1;
-}
-
-static int test_flag(struct block_header *block, enum blockflags flag)
-{
-	return block->prev & BIT(flag);
-}
-
-static void set_flag(struct block_header *block, enum blockflags flag)
-{
-	block->prev |= BIT(flag);
-}
-
-static void clear_flag(struct block_header *block, enum blockflags flag)
-{
-	block->prev &= ~BIT(flag);
-}
-
-/*
- * Given <page, offset> pair, provide a dereferencable pointer.
- * This is called from xv_malloc/xv_free path, so it
- * needs to be fast.
- */
-static void *get_ptr_atomic(struct page *page, u16 offset)
-{
-	unsigned char *base;
-
-	base = kmap_atomic(page);
-	return base + offset;
-}
-
-static void put_ptr_atomic(void *ptr)
-{
-	kunmap_atomic(ptr);
-}
-
-static u32 get_blockprev(struct block_header *block)
-{
-	return block->prev & PREV_MASK;
-}
-
-static void set_blockprev(struct block_header *block, u16 new_offset)
-{
-	block->prev = new_offset | (block->prev & FLAGS_MASK);
-}
-
-static struct block_header *BLOCK_NEXT(struct block_header *block)
-{
-	return (struct block_header *)
-		((char *)block + block->size + XV_ALIGN);
-}
-
-/*
- * Get index of free list containing blocks of maximum size
- * which is less than or equal to given size.
- */
-static u32 get_index_for_insert(u32 size)
-{
-	if (unlikely(size > XV_MAX_ALLOC_SIZE))
-		size = XV_MAX_ALLOC_SIZE;
-	size &= ~FL_DELTA_MASK;
-	return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT;
-}
-
-/*
- * Get index of free list having blocks of size greater than
- * or equal to requested size.
- */
-static u32 get_index(u32 size)
-{
-	if (unlikely(size < XV_MIN_ALLOC_SIZE))
-		size = XV_MIN_ALLOC_SIZE;
-	size = ALIGN(size, FL_DELTA);
-	return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT;
-}
-
-/**
- * find_block - find block of at least given size
- * @pool: memory pool to search from
- * @size: size of block required
- * @page: page containing required block
- * @offset: offset within the page where block is located.
- *
- * Searches two level bitmap to locate block of at least
- * the given size. If such a block is found, it provides
- * <page, offset> to identify this block and returns index
- * in freelist where we found this block.
- * Otherwise, returns 0 and <page, offset> params are not touched.
- */
-static u32 find_block(struct xv_pool *pool, u32 size,
-			struct page **page, u32 *offset)
-{
-	ulong flbitmap, slbitmap;
-	u32 flindex, slindex, slbitstart;
-
-	/* There are no free blocks in this pool */
-	if (!pool->flbitmap)
-		return 0;
-
-	/* Get freelist index corresponding to this size */
-	slindex = get_index(size);
-	slbitmap = pool->slbitmap[slindex / BITS_PER_LONG];
-	slbitstart = slindex % BITS_PER_LONG;
-
-	/*
-	 * If freelist is not empty at this index, we found the
-	 * block - head of this list. This is approximate best-fit match.
-	 */
-	if (test_bit(slbitstart, &slbitmap)) {
-		*page = pool->freelist[slindex].page;
-		*offset = pool->freelist[slindex].offset;
-		return slindex;
-	}
-
-	/*
-	 * No best-fit found. Search a bit further in bitmap for a free block.
-	 * Second level bitmap consists of series of 32-bit chunks. Search
-	 * further in the chunk where we expected a best-fit, starting from
-	 * index location found above.
-	 */
-	slbitstart++;
-	slbitmap >>= slbitstart;
-
-	/* Skip this search if we were already at end of this bitmap chunk */
-	if ((slbitstart != BITS_PER_LONG) && slbitmap) {
-		slindex += __ffs(slbitmap) + 1;
-		*page = pool->freelist[slindex].page;
-		*offset = pool->freelist[slindex].offset;
-		return slindex;
-	}
-
-	/* Now do a full two-level bitmap search to find next nearest fit */
-	flindex = slindex / BITS_PER_LONG;
-
-	flbitmap = (pool->flbitmap) >> (flindex + 1);
-	if (!flbitmap)
-		return 0;
-
-	flindex += __ffs(flbitmap) + 1;
-	slbitmap = pool->slbitmap[flindex];
-	slindex = (flindex * BITS_PER_LONG) + __ffs(slbitmap);
-	*page = pool->freelist[slindex].page;
-	*offset = pool->freelist[slindex].offset;
-
-	return slindex;
-}
-
-/*
- * Insert block at <page, offset> in freelist of given pool.
- * freelist used depends on block size.
- */
-static void insert_block(struct xv_pool *pool, struct page *page, u32 offset,
-			struct block_header *block)
-{
-	u32 flindex, slindex;
-	struct block_header *nextblock;
-
-	slindex = get_index_for_insert(block->size);
-	flindex = slindex / BITS_PER_LONG;
-
-	block->link.prev_page = NULL;
-	block->link.prev_offset = 0;
-	block->link.next_page = pool->freelist[slindex].page;
-	block->link.next_offset = pool->freelist[slindex].offset;
-	pool->freelist[slindex].page = page;
-	pool->freelist[slindex].offset = offset;
-
-	if (block->link.next_page) {
-		nextblock = get_ptr_atomic(block->link.next_page,
-					block->link.next_offset);
-		nextblock->link.prev_page = page;
-		nextblock->link.prev_offset = offset;
-		put_ptr_atomic(nextblock);
-		/* If there was a next page then the free bits are set. */
-		return;
-	}
-
-	__set_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]);
-	__set_bit(flindex, &pool->flbitmap);
-}
-
-/*
- * Remove block from freelist. Index 'slindex' identifies the freelist.
- */
-static void remove_block(struct xv_pool *pool, struct page *page, u32 offset,
-			struct block_header *block, u32 slindex)
-{
-	u32 flindex = slindex / BITS_PER_LONG;
-	struct block_header *tmpblock;
-
-	if (block->link.prev_page) {
-		tmpblock = get_ptr_atomic(block->link.prev_page,
-				block->link.prev_offset);
-		tmpblock->link.next_page = block->link.next_page;
-		tmpblock->link.next_offset = block->link.next_offset;
-		put_ptr_atomic(tmpblock);
-	}
-
-	if (block->link.next_page) {
-		tmpblock = get_ptr_atomic(block->link.next_page,
-				block->link.next_offset);
-		tmpblock->link.prev_page = block->link.prev_page;
-		tmpblock->link.prev_offset = block->link.prev_offset;
-		put_ptr_atomic(tmpblock);
-	}
-
-	/* Is this block is at the head of the freelist? */
-	if (pool->freelist[slindex].page == page
-	   && pool->freelist[slindex].offset == offset) {
-
-		pool->freelist[slindex].page = block->link.next_page;
-		pool->freelist[slindex].offset = block->link.next_offset;
-
-		if (pool->freelist[slindex].page) {
-			struct block_header *tmpblock;
-			tmpblock = get_ptr_atomic(pool->freelist[slindex].page,
-					pool->freelist[slindex].offset);
-			tmpblock->link.prev_page = NULL;
-			tmpblock->link.prev_offset = 0;
-			put_ptr_atomic(tmpblock);
-		} else {
-			/* This freelist bucket is empty */
-			__clear_bit(slindex % BITS_PER_LONG,
-				    &pool->slbitmap[flindex]);
-			if (!pool->slbitmap[flindex])
-				__clear_bit(flindex, &pool->flbitmap);
-		}
-	}
-
-	block->link.prev_page = NULL;
-	block->link.prev_offset = 0;
-	block->link.next_page = NULL;
-	block->link.next_offset = 0;
-}
-
-/*
- * Allocate a page and add it to freelist of given pool.
- */
-static int grow_pool(struct xv_pool *pool, gfp_t flags)
-{
-	struct page *page;
-	struct block_header *block;
-
-	page = alloc_page(flags);
-	if (unlikely(!page))
-		return -ENOMEM;
-
-	stat_inc(&pool->total_pages);
-
-	spin_lock(&pool->lock);
-	block = get_ptr_atomic(page, 0);
-
-	block->size = PAGE_SIZE - XV_ALIGN;
-	set_flag(block, BLOCK_FREE);
-	clear_flag(block, PREV_FREE);
-	set_blockprev(block, 0);
-
-	insert_block(pool, page, 0, block);
-
-	put_ptr_atomic(block);
-	spin_unlock(&pool->lock);
-
-	return 0;
-}
-
-/*
- * Create a memory pool. Allocates freelist, bitmaps and other
- * per-pool metadata.
- */
-struct xv_pool *xv_create_pool(void)
-{
-	u32 ovhd_size;
-	struct xv_pool *pool;
-
-	ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
-	pool = kzalloc(ovhd_size, GFP_KERNEL);
-	if (!pool)
-		return NULL;
-
-	spin_lock_init(&pool->lock);
-
-	return pool;
-}
-EXPORT_SYMBOL_GPL(xv_create_pool);
-
-void xv_destroy_pool(struct xv_pool *pool)
-{
-	kfree(pool);
-}
-EXPORT_SYMBOL_GPL(xv_destroy_pool);
-
-/**
- * xv_malloc - Allocate block of given size from pool.
- * @pool: pool to allocate from
- * @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
- *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
- *
- * Allocation requests with size > XV_MAX_ALLOC_SIZE will fail.
- */
-int xv_malloc(struct xv_pool *pool, u32 size, struct page **page,
-		u32 *offset, gfp_t flags)
-{
-	int error;
-	u32 index, tmpsize, origsize, tmpoffset;
-	struct block_header *block, *tmpblock;
-
-	*page = NULL;
-	*offset = 0;
-	origsize = size;
-
-	if (unlikely(!size || size > XV_MAX_ALLOC_SIZE))
-		return -ENOMEM;
-
-	size = ALIGN(size, XV_ALIGN);
-
-	spin_lock(&pool->lock);
-
-	index = find_block(pool, size, page, offset);
-
-	if (!*page) {
-		spin_unlock(&pool->lock);
-		if (flags & GFP_NOWAIT)
-			return -ENOMEM;
-		error = grow_pool(pool, flags);
-		if (unlikely(error))
-			return error;
-
-		spin_lock(&pool->lock);
-		index = find_block(pool, size, page, offset);
-	}
-
-	if (!*page) {
-		spin_unlock(&pool->lock);
-		return -ENOMEM;
-	}
-
-	block = get_ptr_atomic(*page, *offset);
-
-	remove_block(pool, *page, *offset, block, index);
-
-	/* Split the block if required */
-	tmpoffset = *offset + size + XV_ALIGN;
-	tmpsize = block->size - size;
-	tmpblock = (struct block_header *)((char *)block + size + XV_ALIGN);
-	if (tmpsize) {
-		tmpblock->size = tmpsize - XV_ALIGN;
-		set_flag(tmpblock, BLOCK_FREE);
-		clear_flag(tmpblock, PREV_FREE);
-
-		set_blockprev(tmpblock, *offset);
-		if (tmpblock->size >= XV_MIN_ALLOC_SIZE)
-			insert_block(pool, *page, tmpoffset, tmpblock);
-
-		if (tmpoffset + XV_ALIGN + tmpblock->size != PAGE_SIZE) {
-			tmpblock = BLOCK_NEXT(tmpblock);
-			set_blockprev(tmpblock, tmpoffset);
-		}
-	} else {
-		/* This block is exact fit */
-		if (tmpoffset != PAGE_SIZE)
-			clear_flag(tmpblock, PREV_FREE);
-	}
-
-	block->size = origsize;
-	clear_flag(block, BLOCK_FREE);
-
-	put_ptr_atomic(block);
-	spin_unlock(&pool->lock);
-
-	*offset += XV_ALIGN;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(xv_malloc);
-
-/*
- * Free block identified with <page, offset>
- */
-void xv_free(struct xv_pool *pool, struct page *page, u32 offset)
-{
-	void *page_start;
-	struct block_header *block, *tmpblock;
-
-	offset -= XV_ALIGN;
-
-	spin_lock(&pool->lock);
-
-	page_start = get_ptr_atomic(page, 0);
-	block = (struct block_header *)((char *)page_start + offset);
-
-	/* Catch double free bugs */
-	BUG_ON(test_flag(block, BLOCK_FREE));
-
-	block->size = ALIGN(block->size, XV_ALIGN);
-
-	tmpblock = BLOCK_NEXT(block);
-	if (offset + block->size + XV_ALIGN == PAGE_SIZE)
-		tmpblock = NULL;
-
-	/* Merge next block if its free */
-	if (tmpblock && test_flag(tmpblock, BLOCK_FREE)) {
-		/*
-		 * Blocks smaller than XV_MIN_ALLOC_SIZE
-		 * are not inserted in any free list.
-		 */
-		if (tmpblock->size >= XV_MIN_ALLOC_SIZE) {
-			remove_block(pool, page,
-				    offset + block->size + XV_ALIGN, tmpblock,
-				    get_index_for_insert(tmpblock->size));
-		}
-		block->size += tmpblock->size + XV_ALIGN;
-	}
-
-	/* Merge previous block if its free */
-	if (test_flag(block, PREV_FREE)) {
-		tmpblock = (struct block_header *)((char *)(page_start) +
-						get_blockprev(block));
-		offset = offset - tmpblock->size - XV_ALIGN;
-
-		if (tmpblock->size >= XV_MIN_ALLOC_SIZE)
-			remove_block(pool, page, offset, tmpblock,
-				    get_index_for_insert(tmpblock->size));
-
-		tmpblock->size += block->size + XV_ALIGN;
-		block = tmpblock;
-	}
-
-	/* No used objects in this page. Free it. */
-	if (block->size == PAGE_SIZE - XV_ALIGN) {
-		put_ptr_atomic(page_start);
-		spin_unlock(&pool->lock);
-
-		__free_page(page);
-		stat_dec(&pool->total_pages);
-		return;
-	}
-
-	set_flag(block, BLOCK_FREE);
-	if (block->size >= XV_MIN_ALLOC_SIZE)
-		insert_block(pool, page, offset, block);
-
-	if (offset + block->size + XV_ALIGN != PAGE_SIZE) {
-		tmpblock = BLOCK_NEXT(block);
-		set_flag(tmpblock, PREV_FREE);
-		set_blockprev(tmpblock, offset);
-	}
-
-	put_ptr_atomic(page_start);
-	spin_unlock(&pool->lock);
-}
-EXPORT_SYMBOL_GPL(xv_free);
-
-u32 xv_get_object_size(void *obj)
-{
-	struct block_header *blk;
-
-	blk = (struct block_header *)((char *)(obj) - XV_ALIGN);
-	return blk->size;
-}
-EXPORT_SYMBOL_GPL(xv_get_object_size);
-
-/*
- * Returns total memory used by allocator (userdata + metadata)
- */
-u64 xv_get_total_size_bytes(struct xv_pool *pool)
-{
-	return pool->total_pages << PAGE_SHIFT;
-}
-EXPORT_SYMBOL_GPL(xv_get_total_size_bytes);
diff --git a/drivers/staging/ramster/xvmalloc.h b/drivers/staging/ramster/xvmalloc.h
deleted file mode 100644
index 5b1a81a..0000000
--- a/drivers/staging/ramster/xvmalloc.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _XV_MALLOC_H_
-#define _XV_MALLOC_H_
-
-#include <linux/types.h>
-
-struct xv_pool;
-
-struct xv_pool *xv_create_pool(void);
-void xv_destroy_pool(struct xv_pool *pool);
-
-int xv_malloc(struct xv_pool *pool, u32 size, struct page **page,
-			u32 *offset, gfp_t flags);
-void xv_free(struct xv_pool *pool, struct page *page, u32 offset);
-
-u32 xv_get_object_size(void *obj);
-u64 xv_get_total_size_bytes(struct xv_pool *pool);
-
-#endif
diff --git a/drivers/staging/ramster/xvmalloc_int.h b/drivers/staging/ramster/xvmalloc_int.h
deleted file mode 100644
index b5f1f7f..0000000
--- a/drivers/staging/ramster/xvmalloc_int.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _XV_MALLOC_INT_H_
-#define _XV_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-/* User configurable params */
-
-/* Must be power of two */
-#ifdef CONFIG_64BIT
-#define XV_ALIGN_SHIFT 3
-#else
-#define XV_ALIGN_SHIFT	2
-#endif
-#define XV_ALIGN	(1 << XV_ALIGN_SHIFT)
-#define XV_ALIGN_MASK	(XV_ALIGN - 1)
-
-/* This must be greater than sizeof(link_free) */
-#define XV_MIN_ALLOC_SIZE	32
-#define XV_MAX_ALLOC_SIZE	(PAGE_SIZE - XV_ALIGN)
-
-/*
- * Free lists are separated by FL_DELTA bytes
- * This value is 3 for 4k pages and 4 for 64k pages, for any
- * other page size, a conservative (PAGE_SHIFT - 9) is used.
- */
-#if PAGE_SHIFT == 16
-#define FL_DELTA_SHIFT 4
-#else
-#define FL_DELTA_SHIFT (PAGE_SHIFT - 9)
-#endif
-#define FL_DELTA	(1 << FL_DELTA_SHIFT)
-#define FL_DELTA_MASK	(FL_DELTA - 1)
-#define NUM_FREE_LISTS	((XV_MAX_ALLOC_SIZE - XV_MIN_ALLOC_SIZE) \
-				/ FL_DELTA + 1)
-
-#define MAX_FLI		DIV_ROUND_UP(NUM_FREE_LISTS, BITS_PER_LONG)
-
-/* End of user params */
-
-enum blockflags {
-	BLOCK_FREE,
-	PREV_FREE,
-	__NR_BLOCKFLAGS,
-};
-
-#define FLAGS_MASK	XV_ALIGN_MASK
-#define PREV_MASK	(~FLAGS_MASK)
-
-struct freelist_entry {
-	struct page *page;
-	u16 offset;
-	u16 pad;
-};
-
-struct link_free {
-	struct page *prev_page;
-	struct page *next_page;
-	u16 prev_offset;
-	u16 next_offset;
-};
-
-struct block_header {
-	union {
-		/* This common header must be XV_ALIGN bytes */
-		u8 common[XV_ALIGN];
-		struct {
-			u16 size;
-			u16 prev;
-		};
-	};
-	struct link_free link;
-};
-
-struct xv_pool {
-	ulong flbitmap;
-	ulong slbitmap[MAX_FLI];
-	u64 total_pages;	/* stats */
-	struct freelist_entry freelist[NUM_FREE_LISTS];
-	spinlock_t lock;
-};
-
-#endif
diff --git a/drivers/staging/ramster/zbud.c b/drivers/staging/ramster/zbud.c
new file mode 100644
index 0000000..a7c4361
--- /dev/null
+++ b/drivers/staging/ramster/zbud.c
@@ -0,0 +1,1060 @@
+/*
+ * zbud.c - Compression buddies allocator
+ *
+ * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
+ *
+ * Compression buddies ("zbud") provides for efficiently packing two
+ * (or, possibly in the future, more) compressed pages ("zpages") into
+ * a single "raw" pageframe and for tracking both zpages and pageframes
+ * so that whole pageframes can be easily reclaimed in LRU-like order.
+ * It is designed to be used in conjunction with transcendent memory
+ * ("tmem"); for example separate LRU lists are maintained for persistent
+ * vs. ephemeral pages.
+ *
+ * A zbudpage is an overlay for a struct page and thus each zbudpage
+ * refers to a physical pageframe of RAM.  When the caller passes a
+ * struct page from the kernel's page allocator, zbud "transforms" it
+ * to a zbudpage which sets/uses a different set of fields than the
+ * struct-page and thus must "untransform" it back by reinitializing
+ * certain fields before the struct-page can be freed.  The fields
+ * of a zbudpage include a page lock for controlling access to the
+ * corresponding pageframe, and there is a size field for each zpage.
+ * Each zbudpage also lives on two linked lists: a "budlist" which is
+ * used to support efficient buddying of zpages; and an "lru" which
+ * is used for reclaiming pageframes in approximately least-recently-used
+ * order.
+ *
+ * A zbudpageframe is a pageframe divided up into aligned 64-byte "chunks"
+ * which contain the compressed data for zero, one, or two zbuds.  Contained
+ * with the compressed data is a tmem_handle which is a key to allow
+ * the same data to be found via the tmem interface so the zpage can
+ * be invalidated (for ephemeral pages) or repatriated to the swap cache
+ * (for persistent pages).  The contents of a zbudpageframe must never
+ * be accessed without holding the page lock for the corresponding
+ * zbudpage and, to accomodate highmem machines, the contents may
+ * only be examined or changes when kmapped.  Thus, when in use, a
+ * kmapped zbudpageframe is referred to in the zbud code as "void *zbpg".
+ *
+ * Note that the term "zbud" refers to the combination of a zpage and
+ * a tmem_handle that is stored as one of possibly two "buddied" zpages;
+ * it also generically refers to this allocator... sorry for any confusion.
+ *
+ * A zbudref is a pointer to a struct zbudpage (which can be cast to a
+ * struct page), with the LSB either cleared or set to indicate, respectively,
+ * the first or second zpage in the zbudpageframe. Since a zbudref can be
+ * cast to a pointer, it is used as the tmem "pampd" pointer and uniquely
+ * references a stored tmem page and so is the only zbud data structure
+ * externally visible to zbud.c/zbud.h.
+ *
+ * Since we wish to reclaim entire pageframes but zpages may be randomly
+ * added and deleted to any given pageframe, we approximate LRU by
+ * promoting a pageframe to MRU when a zpage is added to it, but
+ * leaving it at the current place in the list when a zpage is deleted
+ * from it.  As a side effect, zpages that are difficult to buddy (e.g.
+ * very large paages) will be reclaimed faster than average, which seems
+ * reasonable.
+ *
+ * In the current implementation, no more than two zpages may be stored in
+ * any pageframe and no zpage ever crosses a pageframe boundary.  While
+ * other zpage allocation mechanisms may allow greater density, this two
+ * zpage-per-pageframe limit both ensures simple reclaim of pageframes
+ * (including garbage collection of references to the contents of those
+ * pageframes from tmem data structures) AND avoids the need for compaction.
+ * With additional complexity, zbud could be modified to support storing
+ * up to three zpages per pageframe or, to handle larger average zpages,
+ * up to three zpages per pair of pageframes, but it is not clear if the
+ * additional complexity would be worth it.  So consider it an exercise
+ * for future developers.
+ *
+ * Note also that zbud does no page allocation or freeing.  This is so
+ * that the caller has complete control over and, for accounting, visibility
+ * into if/when pages are allocated and freed.
+ *
+ * Finally, note that zbud limits the size of zpages it can store; the
+ * caller must check the zpage size with zbud_max_buddy_size before
+ * storing it, else BUGs will result.  User beware.
+ */
+
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/pagemap.h>
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include "tmem.h"
+#include "zcache.h"
+#include "zbud.h"
+
+/*
+ * We need to ensure that a struct zbudpage is never larger than a
+ * struct page.  This is checked with a BUG_ON in zbud_init.
+ *
+ * The unevictable field indicates that a zbud is being added to the
+ * zbudpage.  Since this is a two-phase process (due to tmem locking),
+ * this field locks the zbudpage against eviction when a zbud match
+ * or creation is in process.  Since this addition process may occur
+ * in parallel for two zbuds in one zbudpage, the field is a counter
+ * that must not exceed two.
+ */
+struct zbudpage {
+	union {
+		struct page page;
+		struct {
+			unsigned long space_for_flags;
+			struct {
+				unsigned zbud0_size:12;
+				unsigned zbud1_size:12;
+				unsigned unevictable:2;
+			};
+			struct list_head budlist;
+			struct list_head lru;
+		};
+	};
+};
+
+struct zbudref {
+	union {
+		struct zbudpage *zbudpage;
+		unsigned long zbudref;
+	};
+};
+
+#define CHUNK_SHIFT	6
+#define CHUNK_SIZE	(1 << CHUNK_SHIFT)
+#define CHUNK_MASK	(~(CHUNK_SIZE-1))
+#define NCHUNKS		(PAGE_SIZE >> CHUNK_SHIFT)
+#define MAX_CHUNK	(NCHUNKS-1)
+
+/*
+ * The following functions deal with the difference between struct
+ * page and struct zbudpage.  Note the hack of using the pageflags
+ * from struct page; this is to avoid duplicating all the complex
+ * pageflag macros.
+ */
+static inline void zbudpage_spin_lock(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	while (unlikely(test_and_set_bit_lock(PG_locked, &page->flags))) {
+		do {
+			cpu_relax();
+		} while (test_bit(PG_locked, &page->flags));
+	}
+}
+
+static inline void zbudpage_spin_unlock(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	clear_bit(PG_locked, &page->flags);
+}
+
+static inline int zbudpage_spin_trylock(struct zbudpage *zbudpage)
+{
+	return trylock_page((struct page *)zbudpage);
+}
+
+static inline int zbudpage_is_locked(struct zbudpage *zbudpage)
+{
+	return PageLocked((struct page *)zbudpage);
+}
+
+static inline void *kmap_zbudpage_atomic(struct zbudpage *zbudpage)
+{
+	return kmap_atomic((struct page *)zbudpage);
+}
+
+/*
+ * A dying zbudpage is an ephemeral page in the process of being evicted.
+ * Any data contained in the zbudpage is invalid and we are just waiting for
+ * the tmem pampds to be invalidated before freeing the page
+ */
+static inline int zbudpage_is_dying(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	return test_bit(PG_reclaim, &page->flags);
+}
+
+static inline void zbudpage_set_dying(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	set_bit(PG_reclaim, &page->flags);
+}
+
+static inline void zbudpage_clear_dying(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	clear_bit(PG_reclaim, &page->flags);
+}
+
+/*
+ * A zombie zbudpage is a persistent page in the process of being evicted.
+ * The data contained in the zbudpage is valid and we are just waiting for
+ * the tmem pampds to be invalidated before freeing the page
+ */
+static inline int zbudpage_is_zombie(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	return test_bit(PG_dirty, &page->flags);
+}
+
+static inline void zbudpage_set_zombie(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	set_bit(PG_dirty, &page->flags);
+}
+
+static inline void zbudpage_clear_zombie(struct zbudpage *zbudpage)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	clear_bit(PG_dirty, &page->flags);
+}
+
+static inline void kunmap_zbudpage_atomic(void *zbpg)
+{
+	kunmap_atomic(zbpg);
+}
+
+/*
+ * zbud "translation" and helper functions
+ */
+
+static inline struct zbudpage *zbudref_to_zbudpage(struct zbudref *zref)
+{
+	unsigned long zbud = (unsigned long)zref;
+	zbud &= ~1UL;
+	return (struct zbudpage *)zbud;
+}
+
+static inline struct zbudref *zbudpage_to_zbudref(struct zbudpage *zbudpage,
+							unsigned budnum)
+{
+	unsigned long zbud = (unsigned long)zbudpage;
+	BUG_ON(budnum > 1);
+	zbud |= budnum;
+	return (struct zbudref *)zbud;
+}
+
+static inline int zbudref_budnum(struct zbudref *zbudref)
+{
+	unsigned long zbud = (unsigned long)zbudref;
+	return zbud & 1UL;
+}
+
+static inline unsigned zbud_max_size(void)
+{
+	return MAX_CHUNK << CHUNK_SHIFT;
+}
+
+static inline unsigned zbud_size_to_chunks(unsigned size)
+{
+	BUG_ON(size == 0 || size > zbud_max_size());
+	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
+}
+
+/* can only be used between kmap_zbudpage_atomic/kunmap_zbudpage_atomic! */
+static inline char *zbud_data(void *zbpg,
+			unsigned budnum, unsigned size)
+{
+	char *p;
+
+	BUG_ON(size == 0 || size > zbud_max_size());
+	p = (char *)zbpg;
+	if (budnum == 1)
+		p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
+	return p;
+}
+
+/*
+ * These are all informative and exposed through debugfs... except for
+ * the arrays... anyone know how to do that?  To avoid confusion for
+ * debugfs viewers, some of these should also be atomic_long_t, but
+ * I don't know how to expose atomics via debugfs either...
+ */
+static unsigned long zbud_eph_pageframes;
+static unsigned long zbud_pers_pageframes;
+static unsigned long zbud_eph_zpages;
+static unsigned long zbud_pers_zpages;
+static u64 zbud_eph_zbytes;
+static u64 zbud_pers_zbytes;
+static unsigned long zbud_eph_evicted_pageframes;
+static unsigned long zbud_pers_evicted_pageframes;
+static unsigned long zbud_eph_cumul_zpages;
+static unsigned long zbud_pers_cumul_zpages;
+static u64 zbud_eph_cumul_zbytes;
+static u64 zbud_pers_cumul_zbytes;
+static unsigned long zbud_eph_cumul_chunk_counts[NCHUNKS];
+static unsigned long zbud_pers_cumul_chunk_counts[NCHUNKS];
+static unsigned long zbud_eph_buddied_count;
+static unsigned long zbud_pers_buddied_count;
+static unsigned long zbud_eph_unbuddied_count;
+static unsigned long zbud_pers_unbuddied_count;
+static unsigned long zbud_eph_zombie_count;
+static unsigned long zbud_pers_zombie_count;
+static atomic_t zbud_eph_zombie_atomic;
+static atomic_t zbud_pers_zombie_atomic;
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#define	zdfs	debugfs_create_size_t
+#define	zdfs64	debugfs_create_u64
+static int zbud_debugfs_init(void)
+{
+	struct dentry *root = debugfs_create_dir("zbud", NULL);
+	if (root == NULL)
+		return -ENXIO;
+
+	/*
+	 * would be nice to dump the sizes of the unbuddied
+	 * arrays, like was done with sysfs, but it doesn't
+	 * look like debugfs is flexible enough to do that
+	 */
+	zdfs64("eph_zbytes", S_IRUGO, root, &zbud_eph_zbytes);
+	zdfs64("eph_cumul_zbytes", S_IRUGO, root, &zbud_eph_cumul_zbytes);
+	zdfs64("pers_zbytes", S_IRUGO, root, &zbud_pers_zbytes);
+	zdfs64("pers_cumul_zbytes", S_IRUGO, root, &zbud_pers_cumul_zbytes);
+	zdfs("eph_cumul_zpages", S_IRUGO, root, &zbud_eph_cumul_zpages);
+	zdfs("eph_evicted_pageframes", S_IRUGO, root,
+				&zbud_eph_evicted_pageframes);
+	zdfs("eph_zpages", S_IRUGO, root, &zbud_eph_zpages);
+	zdfs("eph_pageframes", S_IRUGO, root, &zbud_eph_pageframes);
+	zdfs("eph_buddied_count", S_IRUGO, root, &zbud_eph_buddied_count);
+	zdfs("eph_unbuddied_count", S_IRUGO, root, &zbud_eph_unbuddied_count);
+	zdfs("pers_cumul_zpages", S_IRUGO, root, &zbud_pers_cumul_zpages);
+	zdfs("pers_evicted_pageframes", S_IRUGO, root,
+				&zbud_pers_evicted_pageframes);
+	zdfs("pers_zpages", S_IRUGO, root, &zbud_pers_zpages);
+	zdfs("pers_pageframes", S_IRUGO, root, &zbud_pers_pageframes);
+	zdfs("pers_buddied_count", S_IRUGO, root, &zbud_pers_buddied_count);
+	zdfs("pers_unbuddied_count", S_IRUGO, root, &zbud_pers_unbuddied_count);
+	zdfs("pers_zombie_count", S_IRUGO, root, &zbud_pers_zombie_count);
+	return 0;
+}
+#undef	zdfs
+#undef	zdfs64
+#endif
+
+/* protects the buddied list and all unbuddied lists */
+static DEFINE_SPINLOCK(zbud_eph_lists_lock);
+static DEFINE_SPINLOCK(zbud_pers_lists_lock);
+
+struct zbud_unbuddied {
+	struct list_head list;
+	unsigned count;
+};
+
+/* list N contains pages with N chunks USED and NCHUNKS-N unused */
+/* element 0 is never used but optimizing that isn't worth it */
+static struct zbud_unbuddied zbud_eph_unbuddied[NCHUNKS];
+static struct zbud_unbuddied zbud_pers_unbuddied[NCHUNKS];
+static LIST_HEAD(zbud_eph_lru_list);
+static LIST_HEAD(zbud_pers_lru_list);
+static LIST_HEAD(zbud_eph_buddied_list);
+static LIST_HEAD(zbud_pers_buddied_list);
+static LIST_HEAD(zbud_eph_zombie_list);
+static LIST_HEAD(zbud_pers_zombie_list);
+
+/*
+ * Given a struct page, transform it to a zbudpage so that it can be
+ * used by zbud and initialize fields as necessary.
+ */
+static inline struct zbudpage *zbud_init_zbudpage(struct page *page, bool eph)
+{
+	struct zbudpage *zbudpage = (struct zbudpage *)page;
+
+	BUG_ON(page == NULL);
+	INIT_LIST_HEAD(&zbudpage->budlist);
+	INIT_LIST_HEAD(&zbudpage->lru);
+	zbudpage->zbud0_size = 0;
+	zbudpage->zbud1_size = 0;
+	zbudpage->unevictable = 0;
+	if (eph)
+		zbud_eph_pageframes++;
+	else
+		zbud_pers_pageframes++;
+	return zbudpage;
+}
+
+/* "Transform" a zbudpage back to a struct page suitable to free. */
+static inline struct page *zbud_unuse_zbudpage(struct zbudpage *zbudpage,
+								bool eph)
+{
+	struct page *page = (struct page *)zbudpage;
+
+	BUG_ON(!list_empty(&zbudpage->budlist));
+	BUG_ON(!list_empty(&zbudpage->lru));
+	BUG_ON(zbudpage->zbud0_size != 0);
+	BUG_ON(zbudpage->zbud1_size != 0);
+	BUG_ON(!PageLocked(page));
+	BUG_ON(zbudpage->unevictable != 0);
+	BUG_ON(zbudpage_is_dying(zbudpage));
+	BUG_ON(zbudpage_is_zombie(zbudpage));
+	if (eph)
+		zbud_eph_pageframes--;
+	else
+		zbud_pers_pageframes--;
+	zbudpage_spin_unlock(zbudpage);
+	reset_page_mapcount(page);
+	init_page_count(page);
+	page->index = 0;
+	return page;
+}
+
+/* Mark a zbud as unused and do accounting */
+static inline void zbud_unuse_zbud(struct zbudpage *zbudpage,
+					int budnum, bool eph)
+{
+	unsigned size;
+
+	BUG_ON(!zbudpage_is_locked(zbudpage));
+	if (budnum == 0) {
+		size = zbudpage->zbud0_size;
+		zbudpage->zbud0_size = 0;
+	} else {
+		size = zbudpage->zbud1_size;
+		zbudpage->zbud1_size = 0;
+	}
+	if (eph) {
+		zbud_eph_zbytes -= size;
+		zbud_eph_zpages--;
+	} else {
+		zbud_pers_zbytes -= size;
+		zbud_pers_zpages--;
+	}
+}
+
+/*
+ * Given a zbudpage/budnum/size, a tmem handle, and a kmapped pointer
+ * to some data, set up the zbud appropriately including data copying
+ * and accounting.  Note that if cdata is NULL, the data copying is
+ * skipped.  (This is useful for lazy writes such as for RAMster.)
+ */
+static void zbud_init_zbud(struct zbudpage *zbudpage, struct tmem_handle *th,
+				bool eph, void *cdata,
+				unsigned budnum, unsigned size)
+{
+	char *to;
+	void *zbpg;
+	struct tmem_handle *to_th;
+	unsigned nchunks = zbud_size_to_chunks(size);
+
+	BUG_ON(!zbudpage_is_locked(zbudpage));
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	to = zbud_data(zbpg, budnum, size);
+	to_th = (struct tmem_handle *)to;
+	to_th->index = th->index;
+	to_th->oid = th->oid;
+	to_th->pool_id = th->pool_id;
+	to_th->client_id = th->client_id;
+	to += sizeof(struct tmem_handle);
+	if (cdata != NULL)
+		memcpy(to, cdata, size - sizeof(struct tmem_handle));
+	kunmap_zbudpage_atomic(zbpg);
+	if (budnum == 0)
+		zbudpage->zbud0_size = size;
+	else
+		zbudpage->zbud1_size = size;
+	if (eph) {
+		zbud_eph_cumul_chunk_counts[nchunks]++;
+		zbud_eph_zpages++;
+		zbud_eph_cumul_zpages++;
+		zbud_eph_zbytes += size;
+		zbud_eph_cumul_zbytes += size;
+	} else {
+		zbud_pers_cumul_chunk_counts[nchunks]++;
+		zbud_pers_zpages++;
+		zbud_pers_cumul_zpages++;
+		zbud_pers_zbytes += size;
+		zbud_pers_cumul_zbytes += size;
+	}
+}
+
+/*
+ * Given a locked dying zbudpage, read out the tmem handles from the data,
+ * unlock the page, then use the handles to tell tmem to flush out its
+ * references
+ */
+static void zbud_evict_tmem(struct zbudpage *zbudpage)
+{
+	int i, j;
+	uint32_t pool_id[2], client_id[2];
+	uint32_t index[2];
+	struct tmem_oid oid[2];
+	struct tmem_pool *pool;
+	void *zbpg;
+	struct tmem_handle *th;
+	unsigned size;
+
+	/* read out the tmem handles from the data and set aside */
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	for (i = 0, j = 0; i < 2; i++) {
+		size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
+		if (size) {
+			th = (struct tmem_handle *)zbud_data(zbpg, i, size);
+			client_id[j] = th->client_id;
+			pool_id[j] = th->pool_id;
+			oid[j] = th->oid;
+			index[j] = th->index;
+			j++;
+			zbud_unuse_zbud(zbudpage, i, true);
+		}
+	}
+	kunmap_zbudpage_atomic(zbpg);
+	zbudpage_spin_unlock(zbudpage);
+	/* zbudpage is now an unlocked dying... tell tmem to flush pointers */
+	for (i = 0; i < j; i++) {
+		pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
+		if (pool != NULL) {
+			tmem_flush_page(pool, &oid[i], index[i]);
+			zcache_put_pool(pool);
+		}
+	}
+}
+
+/*
+ * Externally callable zbud handling routines.
+ */
+
+/*
+ * Return the maximum size compressed page that can be stored (secretly
+ * setting aside space for the tmem handle.
+ */
+unsigned int zbud_max_buddy_size(void)
+{
+	return zbud_max_size() - sizeof(struct tmem_handle);
+}
+
+/*
+ * Given a zbud reference, free the corresponding zbud from all lists,
+ * mark it as unused, do accounting, and if the freeing of the zbud
+ * frees up an entire pageframe, return it to the caller (else NULL).
+ */
+struct page *zbud_free_and_delist(struct zbudref *zref, bool eph,
+				  unsigned int *zsize, unsigned int *zpages)
+{
+	unsigned long budnum = zbudref_budnum(zref);
+	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
+	struct page *page = NULL;
+	unsigned chunks, bud_size, other_bud_size;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+	struct zbud_unbuddied *unbud =
+		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
+
+
+	spin_lock(lists_lock);
+	zbudpage_spin_lock(zbudpage);
+	if (zbudpage_is_dying(zbudpage)) {
+		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
+		zbudpage_spin_unlock(zbudpage);
+		spin_unlock(lists_lock);
+		*zpages = 0;
+		*zsize = 0;
+		goto out;
+	}
+	if (budnum == 0) {
+		bud_size = zbudpage->zbud0_size;
+		other_bud_size = zbudpage->zbud1_size;
+	} else {
+		bud_size = zbudpage->zbud1_size;
+		other_bud_size = zbudpage->zbud0_size;
+	}
+	*zsize = bud_size - sizeof(struct tmem_handle);
+	*zpages = 1;
+	zbud_unuse_zbud(zbudpage, budnum, eph);
+	if (other_bud_size == 0) { /* was unbuddied: unlist and free */
+		chunks = zbud_size_to_chunks(bud_size) ;
+		if (zbudpage_is_zombie(zbudpage)) {
+			if (eph)
+				zbud_pers_zombie_count =
+				  atomic_dec_return(&zbud_eph_zombie_atomic);
+			else
+				zbud_pers_zombie_count =
+				  atomic_dec_return(&zbud_pers_zombie_atomic);
+			zbudpage_clear_zombie(zbudpage);
+		} else {
+			BUG_ON(list_empty(&unbud[chunks].list));
+			list_del_init(&zbudpage->budlist);
+			unbud[chunks].count--;
+		}
+		list_del_init(&zbudpage->lru);
+		spin_unlock(lists_lock);
+		if (eph)
+			zbud_eph_unbuddied_count--;
+		else
+			zbud_pers_unbuddied_count--;
+		page = zbud_unuse_zbudpage(zbudpage, eph);
+	} else { /* was buddied: move remaining buddy to unbuddied list */
+		chunks = zbud_size_to_chunks(other_bud_size) ;
+		if (!zbudpage_is_zombie(zbudpage)) {
+			list_del_init(&zbudpage->budlist);
+			list_add_tail(&zbudpage->budlist, &unbud[chunks].list);
+			unbud[chunks].count++;
+		}
+		if (eph) {
+			zbud_eph_buddied_count--;
+			zbud_eph_unbuddied_count++;
+		} else {
+			zbud_pers_unbuddied_count++;
+			zbud_pers_buddied_count--;
+		}
+		/* don't mess with lru, no need to move it */
+		zbudpage_spin_unlock(zbudpage);
+		spin_unlock(lists_lock);
+	}
+out:
+	return page;
+}
+
+/*
+ * Given a tmem handle, and a kmapped pointer to compressed data of
+ * the given size, try to find an unbuddied zbudpage in which to
+ * create a zbud. If found, put it there, mark the zbudpage unevictable,
+ * and return a zbudref to it.  Else return NULL.
+ */
+struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
+				void *cdata, unsigned size)
+{
+	struct zbudpage *zbudpage = NULL, *zbudpage2;
+	unsigned long budnum = 0UL;
+	unsigned nchunks;
+	int i, found_good_buddy = 0;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+	struct zbud_unbuddied *unbud =
+		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
+
+	size += sizeof(struct tmem_handle);
+	nchunks = zbud_size_to_chunks(size);
+	for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
+		spin_lock(lists_lock);
+		if (!list_empty(&unbud[i].list)) {
+			list_for_each_entry_safe(zbudpage, zbudpage2,
+				    &unbud[i].list, budlist) {
+				if (zbudpage_spin_trylock(zbudpage)) {
+					found_good_buddy = i;
+					goto found_unbuddied;
+				}
+			}
+		}
+		spin_unlock(lists_lock);
+	}
+	zbudpage = NULL;
+	goto out;
+
+found_unbuddied:
+	BUG_ON(!zbudpage_is_locked(zbudpage));
+	BUG_ON(!((zbudpage->zbud0_size == 0) ^ (zbudpage->zbud1_size == 0)));
+	if (zbudpage->zbud0_size == 0)
+		budnum = 0UL;
+	else if (zbudpage->zbud1_size == 0)
+		budnum = 1UL;
+	list_del_init(&zbudpage->budlist);
+	if (eph) {
+		list_add_tail(&zbudpage->budlist, &zbud_eph_buddied_list);
+		unbud[found_good_buddy].count--;
+		zbud_eph_unbuddied_count--;
+		zbud_eph_buddied_count++;
+		/* "promote" raw zbudpage to most-recently-used */
+		list_del_init(&zbudpage->lru);
+		list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
+	} else {
+		list_add_tail(&zbudpage->budlist, &zbud_pers_buddied_list);
+		unbud[found_good_buddy].count--;
+		zbud_pers_unbuddied_count--;
+		zbud_pers_buddied_count++;
+		/* "promote" raw zbudpage to most-recently-used */
+		list_del_init(&zbudpage->lru);
+		list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
+	}
+	zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
+	zbudpage->unevictable++;
+	BUG_ON(zbudpage->unevictable == 3);
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+out:
+	return zbudpage_to_zbudref(zbudpage, budnum);
+
+}
+
+/*
+ * Given a tmem handle, and a kmapped pointer to compressed data of
+ * the given size, and a newly allocated struct page, create an unevictable
+ * zbud in that new page and return a zbudref to it.
+ */
+struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
+					void *cdata, unsigned size,
+					struct page *newpage)
+{
+	struct zbudpage *zbudpage;
+	unsigned long budnum = 0;
+	unsigned nchunks;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+	struct zbud_unbuddied *unbud =
+		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
+
+#if 0
+	/* this may be worth it later to support decompress-in-place? */
+	static unsigned long counter;
+	budnum = counter++ & 1;	/* alternate using zbud0 and zbud1 */
+#endif
+
+	if (size  > zbud_max_buddy_size())
+		return NULL;
+	if (newpage == NULL)
+		return NULL;
+
+	size += sizeof(struct tmem_handle);
+	nchunks = zbud_size_to_chunks(size) ;
+	spin_lock(lists_lock);
+	zbudpage = zbud_init_zbudpage(newpage, eph);
+	zbudpage_spin_lock(zbudpage);
+	list_add_tail(&zbudpage->budlist, &unbud[nchunks].list);
+	if (eph) {
+		list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
+		zbud_eph_unbuddied_count++;
+	} else {
+		list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
+		zbud_pers_unbuddied_count++;
+	}
+	unbud[nchunks].count++;
+	zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
+	zbudpage->unevictable++;
+	BUG_ON(zbudpage->unevictable == 3);
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+	return zbudpage_to_zbudref(zbudpage, budnum);
+}
+
+/*
+ * Finish creation of a zbud by, assuming another zbud isn't being created
+ * in parallel, marking it evictable.
+ */
+void zbud_create_finish(struct zbudref *zref, bool eph)
+{
+	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+
+	spin_lock(lists_lock);
+	zbudpage_spin_lock(zbudpage);
+	BUG_ON(zbudpage_is_dying(zbudpage));
+	zbudpage->unevictable--;
+	BUG_ON((int)zbudpage->unevictable < 0);
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+}
+
+/*
+ * Given a zbudref and a struct page, decompress the data from
+ * the zbud into the physical page represented by the struct page
+ * by upcalling to zcache_decompress
+ */
+int zbud_decompress(struct page *data_page, struct zbudref *zref, bool eph,
+			void (*decompress)(char *, unsigned int, char *))
+{
+	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
+	unsigned long budnum = zbudref_budnum(zref);
+	void *zbpg;
+	char *to_va, *from_va;
+	unsigned size;
+	int ret = -1;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+
+	spin_lock(lists_lock);
+	zbudpage_spin_lock(zbudpage);
+	if (zbudpage_is_dying(zbudpage)) {
+		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
+		goto out;
+	}
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	to_va = kmap_atomic(data_page);
+	if (budnum == 0)
+		size = zbudpage->zbud0_size;
+	else
+		size = zbudpage->zbud1_size;
+	BUG_ON(size == 0 || size > zbud_max_size());
+	from_va = zbud_data(zbpg, budnum, size);
+	from_va += sizeof(struct tmem_handle);
+	size -= sizeof(struct tmem_handle);
+	decompress(from_va, size, to_va);
+	kunmap_atomic(to_va);
+	kunmap_zbudpage_atomic(zbpg);
+	ret = 0;
+out:
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+	return ret;
+}
+
+/*
+ * Given a zbudref and a kernel pointer, copy the data from
+ * the zbud to the kernel pointer.
+ */
+int zbud_copy_from_zbud(char *to_va, struct zbudref *zref,
+				size_t *sizep, bool eph)
+{
+	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
+	unsigned long budnum = zbudref_budnum(zref);
+	void *zbpg;
+	char *from_va;
+	unsigned size;
+	int ret = -1;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+
+	spin_lock(lists_lock);
+	zbudpage_spin_lock(zbudpage);
+	if (zbudpage_is_dying(zbudpage)) {
+		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
+		goto out;
+	}
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	if (budnum == 0)
+		size = zbudpage->zbud0_size;
+	else
+		size = zbudpage->zbud1_size;
+	BUG_ON(size == 0 || size > zbud_max_size());
+	from_va = zbud_data(zbpg, budnum, size);
+	from_va += sizeof(struct tmem_handle);
+	size -= sizeof(struct tmem_handle);
+	*sizep = size;
+	memcpy(to_va, from_va, size);
+
+	kunmap_zbudpage_atomic(zbpg);
+	ret = 0;
+out:
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+	return ret;
+}
+
+/*
+ * Given a zbudref and a kernel pointer, copy the data from
+ * the kernel pointer to the zbud.
+ */
+int zbud_copy_to_zbud(struct zbudref *zref, char *from_va, bool eph)
+{
+	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
+	unsigned long budnum = zbudref_budnum(zref);
+	void *zbpg;
+	char *to_va;
+	unsigned size;
+	int ret = -1;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+
+	spin_lock(lists_lock);
+	zbudpage_spin_lock(zbudpage);
+	if (zbudpage_is_dying(zbudpage)) {
+		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
+		goto out;
+	}
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	if (budnum == 0)
+		size = zbudpage->zbud0_size;
+	else
+		size = zbudpage->zbud1_size;
+	BUG_ON(size == 0 || size > zbud_max_size());
+	to_va = zbud_data(zbpg, budnum, size);
+	to_va += sizeof(struct tmem_handle);
+	size -= sizeof(struct tmem_handle);
+	memcpy(to_va, from_va, size);
+
+	kunmap_zbudpage_atomic(zbpg);
+	ret = 0;
+out:
+	zbudpage_spin_unlock(zbudpage);
+	spin_unlock(lists_lock);
+	return ret;
+}
+
+/*
+ * Choose an ephemeral LRU zbudpage that is evictable (not locked), ensure
+ * there are no references to it remaining, and return the now unused
+ * (and re-init'ed) struct page and the total amount of compressed
+ * data that was evicted.
+ */
+struct page *zbud_evict_pageframe_lru(unsigned int *zsize, unsigned int *zpages)
+{
+	struct zbudpage *zbudpage = NULL, *zbudpage2;
+	struct zbud_unbuddied *unbud = zbud_eph_unbuddied;
+	struct page *page = NULL;
+	bool irqs_disabled = irqs_disabled();
+
+	/*
+	 * Since this can be called indirectly from cleancache_put, which
+	 * has interrupts disabled, as well as frontswap_put, which does not,
+	 * we need to be able to handle both cases, even though it is ugly.
+	 */
+	if (irqs_disabled)
+		spin_lock(&zbud_eph_lists_lock);
+	else
+		spin_lock_bh(&zbud_eph_lists_lock);
+	*zsize = 0;
+	if (list_empty(&zbud_eph_lru_list))
+		goto unlock_out;
+	list_for_each_entry_safe(zbudpage, zbudpage2, &zbud_eph_lru_list, lru) {
+		/* skip a locked zbudpage */
+		if (unlikely(!zbudpage_spin_trylock(zbudpage)))
+			continue;
+		/* skip an unevictable zbudpage */
+		if (unlikely(zbudpage->unevictable != 0)) {
+			zbudpage_spin_unlock(zbudpage);
+			continue;
+		}
+		/* got a locked evictable page */
+		goto evict_page;
+
+	}
+unlock_out:
+	/* no unlocked evictable pages, give up */
+	if (irqs_disabled)
+		spin_unlock(&zbud_eph_lists_lock);
+	else
+		spin_unlock_bh(&zbud_eph_lists_lock);
+	goto out;
+
+evict_page:
+	list_del_init(&zbudpage->budlist);
+	list_del_init(&zbudpage->lru);
+	zbudpage_set_dying(zbudpage);
+	/*
+	 * the zbudpage is now "dying" and attempts to read, write,
+	 * or delete data from it will be ignored
+	 */
+	if (zbudpage->zbud0_size != 0 && zbudpage->zbud1_size !=  0) {
+		*zsize = zbudpage->zbud0_size + zbudpage->zbud1_size -
+				(2 * sizeof(struct tmem_handle));
+		*zpages = 2;
+	} else if (zbudpage->zbud0_size != 0) {
+		unbud[zbud_size_to_chunks(zbudpage->zbud0_size)].count--;
+		*zsize = zbudpage->zbud0_size - sizeof(struct tmem_handle);
+		*zpages = 1;
+	} else if (zbudpage->zbud1_size != 0) {
+		unbud[zbud_size_to_chunks(zbudpage->zbud1_size)].count--;
+		*zsize = zbudpage->zbud1_size - sizeof(struct tmem_handle);
+		*zpages = 1;
+	} else {
+		BUG();
+	}
+	spin_unlock(&zbud_eph_lists_lock);
+	zbud_eph_evicted_pageframes++;
+	if (*zpages == 1)
+		zbud_eph_unbuddied_count--;
+	else
+		zbud_eph_buddied_count--;
+	zbud_evict_tmem(zbudpage);
+	zbudpage_spin_lock(zbudpage);
+	zbudpage_clear_dying(zbudpage);
+	page = zbud_unuse_zbudpage(zbudpage, true);
+	if (!irqs_disabled)
+		local_bh_enable();
+out:
+	return page;
+}
+
+/*
+ * Choose a persistent LRU zbudpage that is evictable (not locked), zombify it,
+ * read the tmem_handle(s) out of it into the passed array, and return the
+ * number of zbuds.  Caller must perform necessary tmem functions and,
+ * indirectly, zbud functions to fetch any valid data and cause the
+ * now-zombified zbudpage to eventually be freed.  We track the zombified
+ * zbudpage count so it is possible to observe if there is a leak.
+ FIXME: describe (ramster) case where data pointers are passed in for memcpy
+ */
+unsigned int zbud_make_zombie_lru(struct tmem_handle *th, unsigned char **data,
+					unsigned int *zsize, bool eph)
+{
+	struct zbudpage *zbudpage = NULL, *zbudpag2;
+	struct tmem_handle *thfrom;
+	char *from_va;
+	void *zbpg;
+	unsigned size;
+	int ret = 0, i;
+	spinlock_t *lists_lock =
+		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
+	struct list_head *lru_list =
+		eph ? &zbud_eph_lru_list : &zbud_pers_lru_list;
+
+	spin_lock_bh(lists_lock);
+	if (list_empty(lru_list))
+		goto out;
+	list_for_each_entry_safe(zbudpage, zbudpag2, lru_list, lru) {
+		/* skip a locked zbudpage */
+		if (unlikely(!zbudpage_spin_trylock(zbudpage)))
+			continue;
+		/* skip an unevictable zbudpage */
+		if (unlikely(zbudpage->unevictable != 0)) {
+			zbudpage_spin_unlock(zbudpage);
+			continue;
+		}
+		/* got a locked evictable page */
+		goto zombify_page;
+	}
+	/* no unlocked evictable pages, give up */
+	goto out;
+
+zombify_page:
+	/* got an unlocked evictable page, zombify it */
+	list_del_init(&zbudpage->budlist);
+	zbudpage_set_zombie(zbudpage);
+	/* FIXME what accounting do I need to do here? */
+	list_del_init(&zbudpage->lru);
+	if (eph) {
+		list_add_tail(&zbudpage->lru, &zbud_eph_zombie_list);
+		zbud_eph_zombie_count =
+				atomic_inc_return(&zbud_eph_zombie_atomic);
+	} else {
+		list_add_tail(&zbudpage->lru, &zbud_pers_zombie_list);
+		zbud_pers_zombie_count =
+				atomic_inc_return(&zbud_pers_zombie_atomic);
+	}
+	/* FIXME what accounting do I need to do here? */
+	zbpg = kmap_zbudpage_atomic(zbudpage);
+	for (i = 0; i < 2; i++) {
+		size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
+		if (size) {
+			from_va = zbud_data(zbpg, i, size);
+			thfrom = (struct tmem_handle *)from_va;
+			from_va += sizeof(struct tmem_handle);
+			size -= sizeof(struct tmem_handle);
+			if (th != NULL)
+				th[ret] = *thfrom;
+			if (data != NULL)
+				memcpy(data[ret], from_va, size);
+			if (zsize != NULL)
+				*zsize++ = size;
+			ret++;
+		}
+	}
+	kunmap_zbudpage_atomic(zbpg);
+	zbudpage_spin_unlock(zbudpage);
+out:
+	spin_unlock_bh(lists_lock);
+	return ret;
+}
+
+void __init zbud_init(void)
+{
+	int i;
+
+#ifdef CONFIG_DEBUG_FS
+	zbud_debugfs_init();
+#endif
+	BUG_ON((sizeof(struct tmem_handle) * 2 > CHUNK_SIZE));
+	BUG_ON(sizeof(struct zbudpage) > sizeof(struct page));
+	for (i = 0; i < NCHUNKS; i++) {
+		INIT_LIST_HEAD(&zbud_eph_unbuddied[i].list);
+		INIT_LIST_HEAD(&zbud_pers_unbuddied[i].list);
+	}
+}
diff --git a/drivers/staging/ramster/zbud.h b/drivers/staging/ramster/zbud.h
new file mode 100644
index 0000000..891e8a7
--- /dev/null
+++ b/drivers/staging/ramster/zbud.h
@@ -0,0 +1,33 @@
+/*
+ * zbud.h
+ *
+ * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
+ *
+ */
+
+#ifndef _ZBUD_H_
+#define _ZBUD_H_
+
+#include "tmem.h"
+
+struct zbudref;
+
+extern unsigned int zbud_max_buddy_size(void);
+extern struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
+						void *cdata, unsigned size);
+extern struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
+						void *cdata, unsigned size,
+						struct page *newpage);
+extern void zbud_create_finish(struct zbudref *, bool);
+extern int zbud_decompress(struct page *, struct zbudref *, bool,
+				void (*func)(char *, unsigned int, char *));
+extern int zbud_copy_from_zbud(char *, struct zbudref *, size_t *, bool);
+extern int zbud_copy_to_zbud(struct zbudref *, char *, bool);
+extern struct page *zbud_free_and_delist(struct zbudref *, bool eph,
+						unsigned int *, unsigned int *);
+extern struct page *zbud_evict_pageframe_lru(unsigned int *, unsigned int *);
+extern unsigned int zbud_make_zombie_lru(struct tmem_handle *, unsigned char **,
+						unsigned int *, bool);
+extern void zbud_init(void);
+
+#endif /* _ZBUD_H_ */
diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c
index d46764b..a09dd5c 100644
--- a/drivers/staging/ramster/zcache-main.c
+++ b/drivers/staging/ramster/zcache-main.c
@@ -5,1391 +5,321 @@
  * Copyright (c) 2010,2011, Nitin Gupta
  *
  * Zcache provides an in-kernel "host implementation" for transcendent memory
- * and, thus indirectly, for cleancache and frontswap.  Zcache includes two
- * page-accessible memory [1] interfaces, both utilizing lzo1x compression:
- * 1) "compression buddies" ("zbud") is used for ephemeral pages
- * 2) xvmalloc is used for persistent pages.
- * Xvmalloc (based on the TLSF allocator) has very low fragmentation
- * so maximizes space efficiency, while zbud allows pairs (and potentially,
- * in the future, more than a pair of) compressed pages to be closely linked
- * so that reclaiming can be done via the kernel's physical-page-oriented
- * "shrinker" interface.
- *
- * [1] For a definition of page-accessible memory (aka PAM), see:
- *   http://marc.info/?l=linux-mm&m=127811271605009
- *  RAMSTER TODO:
- *   - handle remotifying of buddied pages (see zbud_remotify_zbpg)
- *   - kernel boot params: nocleancache/nofrontswap don't always work?!?
+ * ("tmem") and, thus indirectly, for cleancache and frontswap.  Zcache uses
+ * lzo1x compression to improve density and an embedded allocator called
+ * "zbud" which "buddies" two compressed pages semi-optimally in each physical
+ * pageframe.  Zbud is integrally tied into tmem to allow pageframes to
+ * be "reclaimed" efficiently.
  */
 
 #include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/highmem.h>
 #include <linux/list.h>
-#include <linux/lzo.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/atomic.h>
 #include <linux/math64.h>
+#include <linux/crypto.h>
+
+#include <linux/cleancache.h>
+#include <linux/frontswap.h>
 #include "tmem.h"
 #include "zcache.h"
+#include "zbud.h"
 #include "ramster.h"
-#include "cluster/tcp.h"
-
-#include "xvmalloc.h"	/* temporary until change to zsmalloc */
-
-#define	RAMSTER_TESTING
-
-#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP))
-#error "ramster is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP"
-#endif
-#ifdef CONFIG_CLEANCACHE
-#include <linux/cleancache.h>
-#endif
-#ifdef CONFIG_FRONTSWAP
-#include <linux/frontswap.h>
-#endif
-
-enum ramster_remotify_op {
-	RAMSTER_REMOTIFY_EPH_PUT,
-	RAMSTER_REMOTIFY_PERS_PUT,
-	RAMSTER_REMOTIFY_FLUSH_PAGE,
-	RAMSTER_REMOTIFY_FLUSH_OBJ,
-	RAMSTER_INTRANSIT_PERS
-};
-
-struct ramster_remotify_hdr {
-	enum ramster_remotify_op op;
-	struct list_head list;
-};
-
-#define ZBH_SENTINEL  0x43214321
-#define ZBPG_SENTINEL  0xdeadbeef
-
-#define ZBUD_MAX_BUDS 2
-
-struct zbud_hdr {
-	struct ramster_remotify_hdr rem_op;
-	uint16_t client_id;
-	uint16_t pool_id;
-	struct tmem_oid oid;
-	uint32_t index;
-	uint16_t size; /* compressed size in bytes, zero means unused */
-	DECL_SENTINEL
-};
-
-#define ZVH_SENTINEL  0x43214321
-static const int zv_max_page_size = (PAGE_SIZE / 8) * 7;
-
-struct zv_hdr {
-	struct ramster_remotify_hdr rem_op;
-	uint16_t client_id;
-	uint16_t pool_id;
-	struct tmem_oid oid;
-	uint32_t index;
-	DECL_SENTINEL
-};
-
-struct flushlist_node {
-	struct ramster_remotify_hdr rem_op;
-	struct tmem_xhandle xh;
-};
-
-union {
-	struct ramster_remotify_hdr rem_op;
-	struct zv_hdr zv;
-	struct zbud_hdr zbud;
-	struct flushlist_node flist;
-} remotify_list_node;
-
-static LIST_HEAD(zcache_rem_op_list);
-static DEFINE_SPINLOCK(zcache_rem_op_list_lock);
-
-#if 0
-/* this is more aggressive but may cause other problems? */
-#define ZCACHE_GFP_MASK	(GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN)
+#ifdef CONFIG_RAMSTER
+static int ramster_enabled;
 #else
+#define ramster_enabled 0
+#endif
+
+#ifndef __PG_WAS_ACTIVE
+static inline bool PageWasActive(struct page *page)
+{
+	return true;
+}
+
+static inline void SetPageWasActive(struct page *page)
+{
+}
+#endif
+
+#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
+static bool frontswap_has_exclusive_gets __read_mostly = true;
+#else
+static bool frontswap_has_exclusive_gets __read_mostly;
+static inline void frontswap_tmem_exclusive_gets(bool b)
+{
+}
+#endif
+
+static int zcache_enabled __read_mostly;
+static int disable_cleancache __read_mostly;
+static int disable_frontswap __read_mostly;
+static int disable_frontswap_ignore_nonactive __read_mostly;
+static int disable_cleancache_ignore_nonactive __read_mostly;
+static char *namestr __read_mostly = "zcache";
+
 #define ZCACHE_GFP_MASK \
 	(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-#endif
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
 
 MODULE_LICENSE("GPL");
 
-struct zcache_client {
-	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
-	struct xv_pool *xvpool;
-	bool allocated;
-	atomic_t refcount;
+/* crypto API for zcache  */
+#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
+static char zcache_comp_name[ZCACHE_COMP_NAME_SZ] __read_mostly;
+static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms __read_mostly;
+
+enum comp_op {
+	ZCACHE_COMPOP_COMPRESS,
+	ZCACHE_COMPOP_DECOMPRESS
 };
 
-static struct zcache_client zcache_host;
-static struct zcache_client zcache_clients[MAX_CLIENTS];
-
-static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
+static inline int zcache_comp_op(enum comp_op op,
+				const u8 *src, unsigned int slen,
+				u8 *dst, unsigned int *dlen)
 {
-	BUG_ON(cli == NULL);
-	if (cli == &zcache_host)
-		return LOCAL_CLIENT;
-	return cli - &zcache_clients[0];
-}
+	struct crypto_comp *tfm;
+	int ret = -1;
 
-static inline bool is_local_client(struct zcache_client *cli)
-{
-	return cli == &zcache_host;
-}
-
-/**********
- * Compression buddies ("zbud") provides for packing two (or, possibly
- * in the future, more) compressed ephemeral pages into a single "raw"
- * (physical) page and tracking them with data structures so that
- * the raw pages can be easily reclaimed.
- *
- * A zbud page ("zbpg") is an aligned page containing a list_head,
- * a lock, and two "zbud headers".  The remainder of the physical
- * page is divided up into aligned 64-byte "chunks" which contain
- * the compressed data for zero, one, or two zbuds.  Each zbpg
- * resides on: (1) an "unused list" if it has no zbuds; (2) a
- * "buddied" list if it is fully populated  with two zbuds; or
- * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
- * the one unbuddied zbud uses.  The data inside a zbpg cannot be
- * read or written unless the zbpg's lock is held.
- */
-
-struct zbud_page {
-	struct list_head bud_list;
-	spinlock_t lock;
-	struct zbud_hdr buddy[ZBUD_MAX_BUDS];
-	DECL_SENTINEL
-	/* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
-};
-
-#define CHUNK_SHIFT	6
-#define CHUNK_SIZE	(1 << CHUNK_SHIFT)
-#define CHUNK_MASK	(~(CHUNK_SIZE-1))
-#define NCHUNKS		(((PAGE_SIZE - sizeof(struct zbud_page)) & \
-				CHUNK_MASK) >> CHUNK_SHIFT)
-#define MAX_CHUNK	(NCHUNKS-1)
-
-static struct {
-	struct list_head list;
-	unsigned count;
-} zbud_unbuddied[NCHUNKS];
-/* list N contains pages with N chunks USED and NCHUNKS-N unused */
-/* element 0 is never used but optimizing that isn't worth it */
-static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
-
-struct list_head zbud_buddied_list;
-static unsigned long zcache_zbud_buddied_count;
-
-/* protects the buddied list and all unbuddied lists */
-static DEFINE_SPINLOCK(zbud_budlists_spinlock);
-
-static atomic_t zcache_zbud_curr_raw_pages;
-static atomic_t zcache_zbud_curr_zpages;
-static unsigned long zcache_zbud_curr_zbytes;
-static unsigned long zcache_zbud_cumul_zpages;
-static unsigned long zcache_zbud_cumul_zbytes;
-static unsigned long zcache_compress_poor;
-static unsigned long zcache_policy_percent_exceeded;
-static unsigned long zcache_mean_compress_poor;
-
-/*
- * RAMster counters
- * - Remote pages are pages with a local pampd but the data is remote
- * - Foreign pages are pages stored locally but belonging to another node
- */
-static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
-static unsigned long ramster_pers_remotify_enable;
-static unsigned long ramster_eph_remotify_enable;
-static unsigned long ramster_eph_pages_remoted;
-static unsigned long ramster_eph_pages_remote_failed;
-static unsigned long ramster_pers_pages_remoted;
-static unsigned long ramster_pers_pages_remote_failed;
-static unsigned long ramster_pers_pages_remote_nomem;
-static unsigned long ramster_remote_objects_flushed;
-static unsigned long ramster_remote_object_flushes_failed;
-static unsigned long ramster_remote_pages_flushed;
-static unsigned long ramster_remote_page_flushes_failed;
-static unsigned long ramster_remote_eph_pages_succ_get;
-static unsigned long ramster_remote_pers_pages_succ_get;
-static unsigned long ramster_remote_eph_pages_unsucc_get;
-static unsigned long ramster_remote_pers_pages_unsucc_get;
-static atomic_t ramster_curr_flnode_count = ATOMIC_INIT(0);
-static unsigned long ramster_curr_flnode_count_max;
-static atomic_t ramster_foreign_eph_pampd_count = ATOMIC_INIT(0);
-static unsigned long ramster_foreign_eph_pampd_count_max;
-static atomic_t ramster_foreign_pers_pampd_count = ATOMIC_INIT(0);
-static unsigned long ramster_foreign_pers_pampd_count_max;
-
-/* forward references */
-static void *zcache_get_free_page(void);
-static void zcache_free_page(void *p);
-
-/*
- * zbud helper functions
- */
-
-static inline unsigned zbud_max_buddy_size(void)
-{
-	return MAX_CHUNK << CHUNK_SHIFT;
-}
-
-static inline unsigned zbud_size_to_chunks(unsigned size)
-{
-	BUG_ON(size == 0 || size > zbud_max_buddy_size());
-	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
-}
-
-static inline int zbud_budnum(struct zbud_hdr *zh)
-{
-	unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
-	struct zbud_page *zbpg = NULL;
-	unsigned budnum = -1U;
-	int i;
-
-	for (i = 0; i < ZBUD_MAX_BUDS; i++)
-		if (offset == offsetof(typeof(*zbpg), buddy[i])) {
-			budnum = i;
-			break;
-		}
-	BUG_ON(budnum == -1U);
-	return budnum;
-}
-
-static char *zbud_data(struct zbud_hdr *zh, unsigned size)
-{
-	struct zbud_page *zbpg;
-	char *p;
-	unsigned budnum;
-
-	ASSERT_SENTINEL(zh, ZBH);
-	budnum = zbud_budnum(zh);
-	BUG_ON(size == 0 || size > zbud_max_buddy_size());
-	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
-	ASSERT_SPINLOCK(&zbpg->lock);
-	p = (char *)zbpg;
-	if (budnum == 0)
-		p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
-							CHUNK_MASK);
-	else if (budnum == 1)
-		p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
-	return p;
-}
-
-static void zbud_copy_from_pampd(char *data, size_t *size, struct zbud_hdr *zh)
-{
-	struct zbud_page *zbpg;
-	char *p;
-	unsigned budnum;
-
-	ASSERT_SENTINEL(zh, ZBH);
-	budnum = zbud_budnum(zh);
-	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
-	spin_lock(&zbpg->lock);
-	BUG_ON(zh->size > *size);
-	p = (char *)zbpg;
-	if (budnum == 0)
-		p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
-							CHUNK_MASK);
-	else if (budnum == 1)
-		p += PAGE_SIZE - ((zh->size + CHUNK_SIZE - 1) & CHUNK_MASK);
-	/* client should be filled in by caller */
-	memcpy(data, p, zh->size);
-	*size = zh->size;
-	spin_unlock(&zbpg->lock);
-}
-
-/*
- * zbud raw page management
- */
-
-static struct zbud_page *zbud_alloc_raw_page(void)
-{
-	struct zbud_page *zbpg = NULL;
-	struct zbud_hdr *zh0, *zh1;
-		zbpg = zcache_get_free_page();
-	if (likely(zbpg != NULL)) {
-		INIT_LIST_HEAD(&zbpg->bud_list);
-		zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
-		spin_lock_init(&zbpg->lock);
-		atomic_inc(&zcache_zbud_curr_raw_pages);
-		INIT_LIST_HEAD(&zbpg->bud_list);
-		SET_SENTINEL(zbpg, ZBPG);
-		zh0->size = 0; zh1->size = 0;
-		tmem_oid_set_invalid(&zh0->oid);
-		tmem_oid_set_invalid(&zh1->oid);
-	}
-	return zbpg;
-}
-
-static void zbud_free_raw_page(struct zbud_page *zbpg)
-{
-	struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
-
-	ASSERT_SENTINEL(zbpg, ZBPG);
-	BUG_ON(!list_empty(&zbpg->bud_list));
-	ASSERT_SPINLOCK(&zbpg->lock);
-	BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
-	BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
-	INVERT_SENTINEL(zbpg, ZBPG);
-	spin_unlock(&zbpg->lock);
-	atomic_dec(&zcache_zbud_curr_raw_pages);
-	zcache_free_page(zbpg);
-}
-
-/*
- * core zbud handling routines
- */
-
-static unsigned zbud_free(struct zbud_hdr *zh)
-{
-	unsigned size;
-
-	ASSERT_SENTINEL(zh, ZBH);
-	BUG_ON(!tmem_oid_valid(&zh->oid));
-	size = zh->size;
-	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
-	zh->size = 0;
-	tmem_oid_set_invalid(&zh->oid);
-	INVERT_SENTINEL(zh, ZBH);
-	zcache_zbud_curr_zbytes -= size;
-	atomic_dec(&zcache_zbud_curr_zpages);
-	return size;
-}
-
-static void zbud_free_and_delist(struct zbud_hdr *zh)
-{
-	unsigned chunks;
-	struct zbud_hdr *zh_other;
-	unsigned budnum = zbud_budnum(zh), size;
-	struct zbud_page *zbpg =
-		container_of(zh, struct zbud_page, buddy[budnum]);
-
-	/* FIXME, should be BUG_ON, pool destruction path doesn't disable
-	 * interrupts tmem_destroy_pool()->tmem_pampd_destroy_all_in_obj()->
-	 * tmem_objnode_node_destroy()-> zcache_pampd_free() */
-	WARN_ON(!irqs_disabled());
-	spin_lock(&zbpg->lock);
-	if (list_empty(&zbpg->bud_list)) {
-		/* ignore zombie page... see zbud_evict_pages() */
-		spin_unlock(&zbpg->lock);
-		return;
-	}
-	size = zbud_free(zh);
-	ASSERT_SPINLOCK(&zbpg->lock);
-	zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
-	if (zh_other->size == 0) { /* was unbuddied: unlist and free */
-		chunks = zbud_size_to_chunks(size) ;
-		spin_lock(&zbud_budlists_spinlock);
-		BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
-		list_del_init(&zbpg->bud_list);
-		zbud_unbuddied[chunks].count--;
-		spin_unlock(&zbud_budlists_spinlock);
-		zbud_free_raw_page(zbpg);
-	} else { /* was buddied: move remaining buddy to unbuddied list */
-		chunks = zbud_size_to_chunks(zh_other->size) ;
-		spin_lock(&zbud_budlists_spinlock);
-		list_del_init(&zbpg->bud_list);
-		zcache_zbud_buddied_count--;
-		list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
-		zbud_unbuddied[chunks].count++;
-		spin_unlock(&zbud_budlists_spinlock);
-		spin_unlock(&zbpg->lock);
-	}
-}
-
-static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
-					struct tmem_oid *oid,
-					uint32_t index, struct page *page,
-					void *cdata, unsigned size)
-{
-	struct zbud_hdr *zh0, *zh1, *zh = NULL;
-	struct zbud_page *zbpg = NULL, *ztmp;
-	unsigned nchunks;
-	char *to;
-	int i, found_good_buddy = 0;
-
-	nchunks = zbud_size_to_chunks(size) ;
-	for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
-		spin_lock(&zbud_budlists_spinlock);
-		if (!list_empty(&zbud_unbuddied[i].list)) {
-			list_for_each_entry_safe(zbpg, ztmp,
-				    &zbud_unbuddied[i].list, bud_list) {
-				if (spin_trylock(&zbpg->lock)) {
-					found_good_buddy = i;
-					goto found_unbuddied;
-				}
-			}
-		}
-		spin_unlock(&zbud_budlists_spinlock);
-	}
-	/* didn't find a good buddy, try allocating a new page */
-	zbpg = zbud_alloc_raw_page();
-	if (unlikely(zbpg == NULL))
-		goto out;
-	/* ok, have a page, now compress the data before taking locks */
-	spin_lock(&zbud_budlists_spinlock);
-	spin_lock(&zbpg->lock);
-	list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
-	zbud_unbuddied[nchunks].count++;
-	zh = &zbpg->buddy[0];
-	goto init_zh;
-
-found_unbuddied:
-	ASSERT_SPINLOCK(&zbpg->lock);
-	zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
-	BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
-	if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
-		ASSERT_SENTINEL(zh0, ZBH);
-		zh = zh1;
-	} else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
-		ASSERT_SENTINEL(zh1, ZBH);
-		zh = zh0;
-	} else
-		BUG();
-	list_del_init(&zbpg->bud_list);
-	zbud_unbuddied[found_good_buddy].count--;
-	list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
-	zcache_zbud_buddied_count++;
-
-init_zh:
-	SET_SENTINEL(zh, ZBH);
-	zh->size = size;
-	zh->index = index;
-	zh->oid = *oid;
-	zh->pool_id = pool_id;
-	zh->client_id = client_id;
-	to = zbud_data(zh, size);
-	memcpy(to, cdata, size);
-	spin_unlock(&zbpg->lock);
-	spin_unlock(&zbud_budlists_spinlock);
-	zbud_cumul_chunk_counts[nchunks]++;
-	atomic_inc(&zcache_zbud_curr_zpages);
-	zcache_zbud_cumul_zpages++;
-	zcache_zbud_curr_zbytes += size;
-	zcache_zbud_cumul_zbytes += size;
-out:
-	return zh;
-}
-
-static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
-{
-	struct zbud_page *zbpg;
-	unsigned budnum = zbud_budnum(zh);
-	size_t out_len = PAGE_SIZE;
-	char *to_va, *from_va;
-	unsigned size;
-	int ret = 0;
-
-	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
-	spin_lock(&zbpg->lock);
-	if (list_empty(&zbpg->bud_list)) {
-		/* ignore zombie page... see zbud_evict_pages() */
+	BUG_ON(!zcache_comp_pcpu_tfms);
+	tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu());
+	BUG_ON(!tfm);
+	switch (op) {
+	case ZCACHE_COMPOP_COMPRESS:
+		ret = crypto_comp_compress(tfm, src, slen, dst, dlen);
+		break;
+	case ZCACHE_COMPOP_DECOMPRESS:
+		ret = crypto_comp_decompress(tfm, src, slen, dst, dlen);
+		break;
+	default:
 		ret = -EINVAL;
-		goto out;
 	}
-	ASSERT_SENTINEL(zh, ZBH);
-	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
-	to_va = kmap_atomic(page);
-	size = zh->size;
-	from_va = zbud_data(zh, size);
-	ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
-	BUG_ON(ret != LZO_E_OK);
-	BUG_ON(out_len != PAGE_SIZE);
-	kunmap_atomic(to_va);
-out:
-	spin_unlock(&zbpg->lock);
+	put_cpu();
 	return ret;
 }
 
 /*
- * The following routines handle shrinking of ephemeral pages by evicting
- * pages "least valuable" first.
+ * policy parameters
  */
 
-static unsigned long zcache_evicted_raw_pages;
-static unsigned long zcache_evicted_buddied_pages;
-static unsigned long zcache_evicted_unbuddied_pages;
-
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
-						uint16_t poolid);
-static void zcache_put_pool(struct tmem_pool *pool);
-
-/*
- * Flush and free all zbuds in a zbpg, then free the pageframe
- */
-static void zbud_evict_zbpg(struct zbud_page *zbpg)
-{
-	struct zbud_hdr *zh;
-	int i, j;
-	uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS];
-	uint32_t index[ZBUD_MAX_BUDS];
-	struct tmem_oid oid[ZBUD_MAX_BUDS];
-	struct tmem_pool *pool;
-	unsigned long flags;
-
-	ASSERT_SPINLOCK(&zbpg->lock);
-	for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) {
-		zh = &zbpg->buddy[i];
-		if (zh->size) {
-			client_id[j] = zh->client_id;
-			pool_id[j] = zh->pool_id;
-			oid[j] = zh->oid;
-			index[j] = zh->index;
-			j++;
-		}
-	}
-	spin_unlock(&zbpg->lock);
-	for (i = 0; i < j; i++) {
-		pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
-		BUG_ON(pool == NULL);
-		local_irq_save(flags);
-		/* these flushes should dispose of any local storage */
-		tmem_flush_page(pool, &oid[i], index[i]);
-		local_irq_restore(flags);
-		zcache_put_pool(pool);
-	}
-}
-
-/*
- * Free nr pages.  This code is funky because we want to hold the locks
- * protecting various lists for as short a time as possible, and in some
- * circumstances the list may change asynchronously when the list lock is
- * not held.  In some cases we also trylock not only to avoid waiting on a
- * page in use by another cpu, but also to avoid potential deadlock due to
- * lock inversion.
- */
-static void zbud_evict_pages(int nr)
-{
-	struct zbud_page *zbpg;
-	int i, newly_unused_pages = 0;
-
-
-	/* now try freeing unbuddied pages, starting with least space avail */
-	for (i = 0; i < MAX_CHUNK; i++) {
-retry_unbud_list_i:
-		spin_lock_bh(&zbud_budlists_spinlock);
-		if (list_empty(&zbud_unbuddied[i].list)) {
-			spin_unlock_bh(&zbud_budlists_spinlock);
-			continue;
-		}
-		list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
-			if (unlikely(!spin_trylock(&zbpg->lock)))
-				continue;
-			zbud_unbuddied[i].count--;
-			spin_unlock(&zbud_budlists_spinlock);
-			zcache_evicted_unbuddied_pages++;
-			/* want budlists unlocked when doing zbpg eviction */
-			zbud_evict_zbpg(zbpg);
-			newly_unused_pages++;
-			local_bh_enable();
-			if (--nr <= 0)
-				goto evict_unused;
-			goto retry_unbud_list_i;
-		}
-		spin_unlock_bh(&zbud_budlists_spinlock);
-	}
-
-	/* as a last resort, free buddied pages */
-retry_bud_list:
-	spin_lock_bh(&zbud_budlists_spinlock);
-	if (list_empty(&zbud_buddied_list)) {
-		spin_unlock_bh(&zbud_budlists_spinlock);
-		goto evict_unused;
-	}
-	list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
-		if (unlikely(!spin_trylock(&zbpg->lock)))
-			continue;
-		zcache_zbud_buddied_count--;
-		spin_unlock(&zbud_budlists_spinlock);
-		zcache_evicted_buddied_pages++;
-		/* want budlists unlocked when doing zbpg eviction */
-		zbud_evict_zbpg(zbpg);
-		newly_unused_pages++;
-		local_bh_enable();
-		if (--nr <= 0)
-			goto evict_unused;
-		goto retry_bud_list;
-	}
-	spin_unlock_bh(&zbud_budlists_spinlock);
-
-evict_unused:
-	return;
-}
-
-static DEFINE_PER_CPU(unsigned char *, zcache_remoteputmem);
-
-static int zbud_remotify_zbud(struct tmem_xhandle *xh, char *data,
-				size_t size)
-{
-	struct tmem_pool *pool;
-	int i, remotenode, ret = -1;
-	unsigned char cksum, *p;
-	unsigned long flags;
-
-	for (p = data, cksum = 0, i = 0; i < size; i++)
-		cksum += *p;
-	ret = ramster_remote_put(xh, data, size, true, &remotenode);
-	if (ret == 0) {
-		/* data was successfully remoted so change the local version
-		 * to point to the remote node where it landed */
-		pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh->pool_id);
-		BUG_ON(pool == NULL);
-		local_irq_save(flags);
-		/* tmem_replace will also free up any local space */
-		(void)tmem_replace(pool, &xh->oid, xh->index,
-			pampd_make_remote(remotenode, size, cksum));
-		local_irq_restore(flags);
-		zcache_put_pool(pool);
-		ramster_eph_pages_remoted++;
-		ret = 0;
-	} else
-		ramster_eph_pages_remote_failed++;
-	return ret;
-}
-
-static int zbud_remotify_zbpg(struct zbud_page *zbpg)
-{
-	struct zbud_hdr *zh1, *zh2 = NULL;
-	struct tmem_xhandle xh1, xh2 = { 0 };
-	char *data1 = NULL, *data2 = NULL;
-	size_t size1 = 0, size2 = 0;
-	int ret = 0;
-	unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem);
-
-	ASSERT_SPINLOCK(&zbpg->lock);
-	if (zbpg->buddy[0].size == 0)
-		zh1 = &zbpg->buddy[1];
-	else if (zbpg->buddy[1].size == 0)
-		zh1 = &zbpg->buddy[0];
-	else {
-		zh1 = &zbpg->buddy[0];
-		zh2 = &zbpg->buddy[1];
-	}
-	/* don't remotify pages that are already remotified */
-	if (zh1->client_id != LOCAL_CLIENT)
-		zh1 = NULL;
-	if ((zh2 != NULL) && (zh2->client_id != LOCAL_CLIENT))
-		zh2 = NULL;
-
-	/* copy the data and metadata so can release lock */
-	if (zh1 != NULL) {
-		xh1.client_id = zh1->client_id;
-		xh1.pool_id = zh1->pool_id;
-		xh1.oid = zh1->oid;
-		xh1.index = zh1->index;
-		size1 = zh1->size;
-		data1 = zbud_data(zh1, size1);
-		memcpy(tmpmem, zbud_data(zh1, size1), size1);
-		data1 = tmpmem;
-		tmpmem += size1;
-	}
-	if (zh2 != NULL) {
-		xh2.client_id = zh2->client_id;
-		xh2.pool_id = zh2->pool_id;
-		xh2.oid = zh2->oid;
-		xh2.index = zh2->index;
-		size2 = zh2->size;
-		memcpy(tmpmem, zbud_data(zh2, size2), size2);
-		data2 = tmpmem;
-	}
-	spin_unlock(&zbpg->lock);
-	preempt_enable();
-
-	/* OK, no locks held anymore, remotify one or both zbuds */
-	if (zh1 != NULL)
-		ret = zbud_remotify_zbud(&xh1, data1, size1);
-	if (zh2 != NULL)
-		ret |= zbud_remotify_zbud(&xh2, data2, size2);
-	return ret;
-}
-
-void zbud_remotify_pages(int nr)
-{
-	struct zbud_page *zbpg;
-	int i, ret;
-
-	/*
-	 * for now just try remotifying unbuddied pages, starting with
-	 * least space avail
-	 */
-	for (i = 0; i < MAX_CHUNK; i++) {
-retry_unbud_list_i:
-		preempt_disable();  /* enable in zbud_remotify_zbpg */
-		spin_lock_bh(&zbud_budlists_spinlock);
-		if (list_empty(&zbud_unbuddied[i].list)) {
-			spin_unlock_bh(&zbud_budlists_spinlock);
-			preempt_enable();
-			continue; /* next i in for loop */
-		}
-		list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
-			if (unlikely(!spin_trylock(&zbpg->lock)))
-				continue; /* next list_for_each_entry */
-			zbud_unbuddied[i].count--;
-			/* want budlists unlocked when doing zbpg remotify */
-			spin_unlock_bh(&zbud_budlists_spinlock);
-			ret = zbud_remotify_zbpg(zbpg);
-			/* preemption is re-enabled in zbud_remotify_zbpg */
-			if (ret == 0) {
-				if (--nr <= 0)
-					goto out;
-				goto retry_unbud_list_i;
-			}
-			/* if fail to remotify any page, quit */
-			pr_err("TESTING zbud_remotify_pages failed on page,"
-				" trying to re-add\n");
-			spin_lock_bh(&zbud_budlists_spinlock);
-			spin_lock(&zbpg->lock);
-			list_add_tail(&zbpg->bud_list, &zbud_unbuddied[i].list);
-			zbud_unbuddied[i].count++;
-			spin_unlock(&zbpg->lock);
-			spin_unlock_bh(&zbud_budlists_spinlock);
-			pr_err("TESTING zbud_remotify_pages failed on page,"
-				" finished re-add\n");
-			goto out;
-		}
-		spin_unlock_bh(&zbud_budlists_spinlock);
-		preempt_enable();
-	}
-
-next_buddied_zbpg:
-	preempt_disable();  /* enable in zbud_remotify_zbpg */
-	spin_lock_bh(&zbud_budlists_spinlock);
-	if (list_empty(&zbud_buddied_list))
-		goto unlock_out;
-	list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
-		if (unlikely(!spin_trylock(&zbpg->lock)))
-			continue; /* next list_for_each_entry */
-		zcache_zbud_buddied_count--;
-		/* want budlists unlocked when doing zbpg remotify */
-		spin_unlock_bh(&zbud_budlists_spinlock);
-		ret = zbud_remotify_zbpg(zbpg);
-		/* preemption is re-enabled in zbud_remotify_zbpg */
-		if (ret == 0) {
-			if (--nr <= 0)
-				goto out;
-			goto next_buddied_zbpg;
-		}
-		/* if fail to remotify any page, quit */
-		pr_err("TESTING zbud_remotify_pages failed on BUDDIED page,"
-			" trying to re-add\n");
-		spin_lock_bh(&zbud_budlists_spinlock);
-		spin_lock(&zbpg->lock);
-		list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
-		zcache_zbud_buddied_count++;
-		spin_unlock(&zbpg->lock);
-		spin_unlock_bh(&zbud_budlists_spinlock);
-		pr_err("TESTING zbud_remotify_pages failed on BUDDIED page,"
-			" finished re-add\n");
-		goto out;
-	}
-unlock_out:
-	spin_unlock_bh(&zbud_budlists_spinlock);
-	preempt_enable();
-out:
-	return;
-}
-
-/* the "flush list" asynchronously collects pages to remotely flush */
-#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1)
-static void ramster_flnode_free(struct flushlist_node *,
-				struct tmem_pool *);
-
-static void zcache_remote_flush_page(struct flushlist_node *flnode)
-{
-	struct tmem_xhandle *xh;
-	int remotenode, ret;
-
-	preempt_disable();
-	xh = &flnode->xh;
-	remotenode = flnode->xh.client_id;
-	ret = ramster_remote_flush(xh, remotenode);
-	if (ret >= 0)
-		ramster_remote_pages_flushed++;
-	else
-		ramster_remote_page_flushes_failed++;
-	preempt_enable_no_resched();
-	ramster_flnode_free(flnode, NULL);
-}
-
-static void zcache_remote_flush_object(struct flushlist_node *flnode)
-{
-	struct tmem_xhandle *xh;
-	int remotenode, ret;
-
-	preempt_disable();
-	xh = &flnode->xh;
-	remotenode = flnode->xh.client_id;
-	ret = ramster_remote_flush_object(xh, remotenode);
-	if (ret >= 0)
-		ramster_remote_objects_flushed++;
-	else
-		ramster_remote_object_flushes_failed++;
-	preempt_enable_no_resched();
-	ramster_flnode_free(flnode, NULL);
-}
-
-static void zcache_remote_eph_put(struct zbud_hdr *zbud)
-{
-	/* FIXME */
-}
-
-static void zcache_remote_pers_put(struct zv_hdr *zv)
-{
-	struct tmem_xhandle xh;
-	uint16_t size;
-	bool ephemeral;
-	int remotenode, ret = -1;
-	char *data;
-	struct tmem_pool *pool;
-	unsigned long flags;
-	unsigned char cksum;
-	char *p;
-	int i;
-	unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem);
-
-	ASSERT_SENTINEL(zv, ZVH);
-	BUG_ON(zv->client_id != LOCAL_CLIENT);
-	local_bh_disable();
-	xh.client_id = zv->client_id;
-	xh.pool_id = zv->pool_id;
-	xh.oid = zv->oid;
-	xh.index = zv->index;
-	size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(size == 0 || size > zv_max_page_size);
-	data = (char *)zv + sizeof(*zv);
-	for (p = data, cksum = 0, i = 0; i < size; i++)
-		cksum += *p;
-	memcpy(tmpmem, data, size);
-	data = tmpmem;
-	pool = zcache_get_pool_by_id(zv->client_id, zv->pool_id);
-	ephemeral = is_ephemeral(pool);
-	zcache_put_pool(pool);
-	/* now OK to release lock set in caller */
-	spin_unlock(&zcache_rem_op_list_lock);
-	local_bh_enable();
-	preempt_disable();
-	ret = ramster_remote_put(&xh, data, size, ephemeral, &remotenode);
-	preempt_enable_no_resched();
-	if (ret != 0) {
-		/*
-		 * This is some form of a memory leak... if the remote put
-		 * fails, there will never be another attempt to remotify
-		 * this page.  But since we've dropped the zv pointer,
-		 * the page may have been freed or the data replaced
-		 * so we can't just "put it back" in the remote op list.
-		 * Even if we could, not sure where to put it in the list
-		 * because there may be flushes that must be strictly
-		 * ordered vs the put.  So leave this as a FIXME for now.
-		 * But count them so we know if it becomes a problem.
-		 */
-		ramster_pers_pages_remote_failed++;
-		goto out;
-	} else
-		atomic_inc(&ramster_remote_pers_pages);
-	ramster_pers_pages_remoted++;
-	/*
-	 * data was successfully remoted so change the local version to
-	 * point to the remote node where it landed
-	 */
-	local_bh_disable();
-	pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id);
-	local_irq_save(flags);
-	(void)tmem_replace(pool, &xh.oid, xh.index,
-			pampd_make_remote(remotenode, size, cksum));
-	local_irq_restore(flags);
-	zcache_put_pool(pool);
-	local_bh_enable();
-out:
-	return;
-}
-
-static void zcache_do_remotify_ops(int nr)
-{
-	struct ramster_remotify_hdr *rem_op;
-	union remotify_list_node *u;
-
-	while (1) {
-		if (!nr)
-			goto out;
-		spin_lock(&zcache_rem_op_list_lock);
-		if (list_empty(&zcache_rem_op_list)) {
-			spin_unlock(&zcache_rem_op_list_lock);
-			goto out;
-		}
-		rem_op = list_first_entry(&zcache_rem_op_list,
-				struct ramster_remotify_hdr, list);
-		list_del_init(&rem_op->list);
-		if (rem_op->op != RAMSTER_REMOTIFY_PERS_PUT)
-			spin_unlock(&zcache_rem_op_list_lock);
-		u = (union remotify_list_node *)rem_op;
-		switch (rem_op->op) {
-		case RAMSTER_REMOTIFY_EPH_PUT:
-BUG();
-			zcache_remote_eph_put((struct zbud_hdr *)rem_op);
-			break;
-		case RAMSTER_REMOTIFY_PERS_PUT:
-			zcache_remote_pers_put((struct zv_hdr *)rem_op);
-			break;
-		case RAMSTER_REMOTIFY_FLUSH_PAGE:
-			zcache_remote_flush_page((struct flushlist_node *)u);
-			break;
-		case RAMSTER_REMOTIFY_FLUSH_OBJ:
-			zcache_remote_flush_object((struct flushlist_node *)u);
-			break;
-		default:
-			BUG();
-		}
-	}
-out:
-	return;
-}
-
-/*
- * Communicate interface revision with userspace
- */
-#include "cluster/ramster_nodemanager.h"
-static unsigned long ramster_interface_revision  = R2NM_API_VERSION;
-
-/*
- * For now, just push over a few pages every few seconds to
- * ensure that it basically works
- */
-static struct workqueue_struct *ramster_remotify_workqueue;
-static void ramster_remotify_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(ramster_remotify_worker,
-		ramster_remotify_process);
-
-static void ramster_remotify_queue_delayed_work(unsigned long delay)
-{
-	if (!queue_delayed_work(ramster_remotify_workqueue,
-				&ramster_remotify_worker, delay))
-		pr_err("ramster_remotify: bad workqueue\n");
-}
-
-
-static int use_frontswap;
-static int use_cleancache;
-static int ramster_remote_target_nodenum = -1;
-static void ramster_remotify_process(struct work_struct *work)
-{
-	static bool remotify_in_progress;
-
-	BUG_ON(irqs_disabled());
-	if (remotify_in_progress)
-		ramster_remotify_queue_delayed_work(HZ);
-	else if (ramster_remote_target_nodenum != -1) {
-		remotify_in_progress = true;
-#ifdef CONFIG_CLEANCACHE
-	if (use_cleancache && ramster_eph_remotify_enable)
-		zbud_remotify_pages(5000); /* FIXME is this a good number? */
-#endif
-#ifdef CONFIG_FRONTSWAP
-	if (use_frontswap && ramster_pers_remotify_enable)
-		zcache_do_remotify_ops(500); /* FIXME is this a good number? */
-#endif
-		remotify_in_progress = false;
-		ramster_remotify_queue_delayed_work(HZ);
-	}
-}
-
-static void ramster_remotify_init(void)
-{
-	unsigned long n = 60UL;
-	ramster_remotify_workqueue =
-		create_singlethread_workqueue("ramster_remotify");
-	ramster_remotify_queue_delayed_work(n * HZ);
-}
-
-
-static void zbud_init(void)
-{
-	int i;
-
-	INIT_LIST_HEAD(&zbud_buddied_list);
-	zcache_zbud_buddied_count = 0;
-	for (i = 0; i < NCHUNKS; i++) {
-		INIT_LIST_HEAD(&zbud_unbuddied[i].list);
-		zbud_unbuddied[i].count = 0;
-	}
-}
-
-#ifdef CONFIG_SYSFS
-/*
- * These sysfs routines show a nice distribution of how many zbpg's are
- * currently (and have ever been placed) in each unbuddied list.  It's fun
- * to watch but can probably go away before final merge.
- */
-static int zbud_show_unbuddied_list_counts(char *buf)
-{
-	int i;
-	char *p = buf;
-
-	for (i = 0; i < NCHUNKS; i++)
-		p += sprintf(p, "%u ", zbud_unbuddied[i].count);
-	return p - buf;
-}
-
-static int zbud_show_cumul_chunk_counts(char *buf)
-{
-	unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
-	unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
-	unsigned long total_chunks_lte_42 = 0;
-	char *p = buf;
-
-	for (i = 0; i < NCHUNKS; i++) {
-		p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
-		chunks += zbud_cumul_chunk_counts[i];
-		total_chunks += zbud_cumul_chunk_counts[i];
-		sum_total_chunks += i * zbud_cumul_chunk_counts[i];
-		if (i == 21)
-			total_chunks_lte_21 = total_chunks;
-		if (i == 32)
-			total_chunks_lte_32 = total_chunks;
-		if (i == 42)
-			total_chunks_lte_42 = total_chunks;
-	}
-	p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
-		total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
-		chunks == 0 ? 0 : sum_total_chunks / chunks);
-	return p - buf;
-}
-#endif
-
-/**********
- * This "zv" PAM implementation combines the TLSF-based xvMalloc
- * with lzo1x compression to maximize the amount of data that can
- * be packed into a physical page.
- *
- * Zv represents a PAM page with the index and object (plus a "size" value
- * necessary for decompression) immediately preceding the compressed data.
- */
-
-/* rudimentary policy limits */
-/* total number of persistent pages may not exceed this percentage */
-static unsigned int zv_page_count_policy_percent = 75;
 /*
  * byte count defining poor compression; pages with greater zsize will be
  * rejected
  */
-static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7;
+static unsigned int zbud_max_zsize __read_mostly = (PAGE_SIZE / 8) * 7;
 /*
  * byte count defining poor *mean* compression; pages with greater zsize
  * will be rejected until sufficient better-compressed pages are accepted
  * driving the mean below this threshold
  */
-static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5;
-
-static atomic_t zv_curr_dist_counts[NCHUNKS];
-static atomic_t zv_cumul_dist_counts[NCHUNKS];
-
-
-static struct zv_hdr *zv_create(struct zcache_client *cli, uint32_t pool_id,
-				struct tmem_oid *oid, uint32_t index,
-				void *cdata, unsigned clen)
-{
-	struct page *page;
-	struct zv_hdr *zv = NULL;
-	uint32_t offset;
-	int alloc_size = clen + sizeof(struct zv_hdr);
-	int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-	int ret;
-
-	BUG_ON(!irqs_disabled());
-	BUG_ON(chunks >= NCHUNKS);
-	ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr),
-			&page, &offset, ZCACHE_GFP_MASK);
-	if (unlikely(ret))
-		goto out;
-	atomic_inc(&zv_curr_dist_counts[chunks]);
-	atomic_inc(&zv_cumul_dist_counts[chunks]);
-	zv = kmap_atomic(page) + offset;
-	zv->index = index;
-	zv->oid = *oid;
-	zv->pool_id = pool_id;
-	SET_SENTINEL(zv, ZVH);
-	INIT_LIST_HEAD(&zv->rem_op.list);
-	zv->client_id = get_client_id_from_client(cli);
-	zv->rem_op.op = RAMSTER_REMOTIFY_PERS_PUT;
-	if (zv->client_id == LOCAL_CLIENT) {
-		spin_lock(&zcache_rem_op_list_lock);
-		list_add_tail(&zv->rem_op.list, &zcache_rem_op_list);
-		spin_unlock(&zcache_rem_op_list_lock);
-	}
-	memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen);
-	kunmap_atomic(zv);
-out:
-	return zv;
-}
-
-/* similar to zv_create, but just reserve space, no data yet */
-static struct zv_hdr *zv_alloc(struct tmem_pool *pool,
-				struct tmem_oid *oid, uint32_t index,
-				unsigned clen)
-{
-	struct zcache_client *cli = pool->client;
-	struct page *page;
-	struct zv_hdr *zv = NULL;
-	uint32_t offset;
-	int ret;
-
-	BUG_ON(!irqs_disabled());
-	BUG_ON(!is_local_client(pool->client));
-	ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr),
-			&page, &offset, ZCACHE_GFP_MASK);
-	if (unlikely(ret))
-		goto out;
-	zv = kmap_atomic(page) + offset;
-	SET_SENTINEL(zv, ZVH);
-	INIT_LIST_HEAD(&zv->rem_op.list);
-	zv->client_id = LOCAL_CLIENT;
-	zv->rem_op.op = RAMSTER_INTRANSIT_PERS;
-	zv->index = index;
-	zv->oid = *oid;
-	zv->pool_id = pool->pool_id;
-	kunmap_atomic(zv);
-out:
-	return zv;
-}
-
-static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
-{
-	unsigned long flags;
-	struct page *page;
-	uint32_t offset;
-	uint16_t size = xv_get_object_size(zv);
-	int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-
-	ASSERT_SENTINEL(zv, ZVH);
-	BUG_ON(chunks >= NCHUNKS);
-	atomic_dec(&zv_curr_dist_counts[chunks]);
-	size -= sizeof(*zv);
-	spin_lock(&zcache_rem_op_list_lock);
-	size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(size == 0);
-	INVERT_SENTINEL(zv, ZVH);
-	if (!list_empty(&zv->rem_op.list))
-		list_del_init(&zv->rem_op.list);
-	spin_unlock(&zcache_rem_op_list_lock);
-	page = virt_to_page(zv);
-	offset = (unsigned long)zv & ~PAGE_MASK;
-	local_irq_save(flags);
-	xv_free(xvpool, page, offset);
-	local_irq_restore(flags);
-}
-
-static void zv_decompress(struct page *page, struct zv_hdr *zv)
-{
-	size_t clen = PAGE_SIZE;
-	char *to_va;
-	unsigned size;
-	int ret;
-
-	ASSERT_SENTINEL(zv, ZVH);
-	size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(size == 0);
-	to_va = kmap_atomic(page);
-	ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
-					size, to_va, &clen);
-	kunmap_atomic(to_va);
-	BUG_ON(ret != LZO_E_OK);
-	BUG_ON(clen != PAGE_SIZE);
-}
-
-static void zv_copy_from_pampd(char *data, size_t *bufsize, struct zv_hdr *zv)
-{
-	unsigned size;
-
-	ASSERT_SENTINEL(zv, ZVH);
-	size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(size == 0 || size > zv_max_page_size);
-	BUG_ON(size > *bufsize);
-	memcpy(data, (char *)zv + sizeof(*zv), size);
-	*bufsize = size;
-}
-
-static void zv_copy_to_pampd(struct zv_hdr *zv, char *data, size_t size)
-{
-	unsigned zv_size;
-
-	ASSERT_SENTINEL(zv, ZVH);
-	zv_size = xv_get_object_size(zv) - sizeof(*zv);
-	BUG_ON(zv_size != size);
-	BUG_ON(zv_size == 0 || zv_size > zv_max_page_size);
-	memcpy((char *)zv + sizeof(*zv), data, size);
-}
-
-#ifdef CONFIG_SYSFS
-/*
- * show a distribution of compression stats for zv pages.
- */
-
-static int zv_curr_dist_counts_show(char *buf)
-{
-	unsigned long i, n, chunks = 0, sum_total_chunks = 0;
-	char *p = buf;
-
-	for (i = 0; i < NCHUNKS; i++) {
-		n = atomic_read(&zv_curr_dist_counts[i]);
-		p += sprintf(p, "%lu ", n);
-		chunks += n;
-		sum_total_chunks += i * n;
-	}
-	p += sprintf(p, "mean:%lu\n",
-		chunks == 0 ? 0 : sum_total_chunks / chunks);
-	return p - buf;
-}
-
-static int zv_cumul_dist_counts_show(char *buf)
-{
-	unsigned long i, n, chunks = 0, sum_total_chunks = 0;
-	char *p = buf;
-
-	for (i = 0; i < NCHUNKS; i++) {
-		n = atomic_read(&zv_cumul_dist_counts[i]);
-		p += sprintf(p, "%lu ", n);
-		chunks += n;
-		sum_total_chunks += i * n;
-	}
-	p += sprintf(p, "mean:%lu\n",
-		chunks == 0 ? 0 : sum_total_chunks / chunks);
-	return p - buf;
-}
+static unsigned int zbud_max_mean_zsize __read_mostly = (PAGE_SIZE / 8) * 5;
 
 /*
- * setting zv_max_zsize via sysfs causes all persistent (e.g. swap)
- * pages that don't compress to less than this value (including metadata
- * overhead) to be rejected.  We don't allow the value to get too close
- * to PAGE_SIZE.
+ * for now, used named slabs so can easily track usage; later can
+ * either just use kmalloc, or perhaps add a slab-like allocator
+ * to more carefully manage total memory utilization
  */
-static ssize_t zv_max_zsize_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
-				    char *buf)
+static struct kmem_cache *zcache_objnode_cache;
+static struct kmem_cache *zcache_obj_cache;
+
+static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
+
+/* we try to keep these statistics SMP-consistent */
+static long zcache_obj_count;
+static atomic_t zcache_obj_atomic = ATOMIC_INIT(0);
+static long zcache_obj_count_max;
+static long zcache_objnode_count;
+static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0);
+static long zcache_objnode_count_max;
+static u64 zcache_eph_zbytes;
+static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0);
+static u64 zcache_eph_zbytes_max;
+static u64 zcache_pers_zbytes;
+static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0);
+static u64 zcache_pers_zbytes_max;
+static long zcache_eph_pageframes;
+static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0);
+static long zcache_eph_pageframes_max;
+static long zcache_pers_pageframes;
+static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0);
+static long zcache_pers_pageframes_max;
+static long zcache_pageframes_alloced;
+static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0);
+static long zcache_pageframes_freed;
+static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0);
+static long zcache_eph_zpages;
+static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0);
+static long zcache_eph_zpages_max;
+static long zcache_pers_zpages;
+static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0);
+static long zcache_pers_zpages_max;
+
+/* but for the rest of these, counting races are ok */
+static unsigned long zcache_flush_total;
+static unsigned long zcache_flush_found;
+static unsigned long zcache_flobj_total;
+static unsigned long zcache_flobj_found;
+static unsigned long zcache_failed_eph_puts;
+static unsigned long zcache_failed_pers_puts;
+static unsigned long zcache_failed_getfreepages;
+static unsigned long zcache_failed_alloc;
+static unsigned long zcache_put_to_flush;
+static unsigned long zcache_compress_poor;
+static unsigned long zcache_mean_compress_poor;
+static unsigned long zcache_eph_ate_tail;
+static unsigned long zcache_eph_ate_tail_failed;
+static unsigned long zcache_pers_ate_eph;
+static unsigned long zcache_pers_ate_eph_failed;
+static unsigned long zcache_evicted_eph_zpages;
+static unsigned long zcache_evicted_eph_pageframes;
+static unsigned long zcache_last_active_file_pageframes;
+static unsigned long zcache_last_inactive_file_pageframes;
+static unsigned long zcache_last_active_anon_pageframes;
+static unsigned long zcache_last_inactive_anon_pageframes;
+static unsigned long zcache_eph_nonactive_puts_ignored;
+static unsigned long zcache_pers_nonactive_puts_ignored;
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#define	zdfs	debugfs_create_size_t
+#define	zdfs64	debugfs_create_u64
+static int zcache_debugfs_init(void)
 {
-	return sprintf(buf, "%u\n", zv_max_zsize);
-}
+	struct dentry *root = debugfs_create_dir("zcache", NULL);
+	if (root == NULL)
+		return -ENXIO;
 
-static ssize_t zv_max_zsize_store(struct kobject *kobj,
-				    struct kobj_attribute *attr,
-				    const char *buf, size_t count)
+	zdfs("obj_count", S_IRUGO, root, &zcache_obj_count);
+	zdfs("obj_count_max", S_IRUGO, root, &zcache_obj_count_max);
+	zdfs("objnode_count", S_IRUGO, root, &zcache_objnode_count);
+	zdfs("objnode_count_max", S_IRUGO, root, &zcache_objnode_count_max);
+	zdfs("flush_total", S_IRUGO, root, &zcache_flush_total);
+	zdfs("flush_found", S_IRUGO, root, &zcache_flush_found);
+	zdfs("flobj_total", S_IRUGO, root, &zcache_flobj_total);
+	zdfs("flobj_found", S_IRUGO, root, &zcache_flobj_found);
+	zdfs("failed_eph_puts", S_IRUGO, root, &zcache_failed_eph_puts);
+	zdfs("failed_pers_puts", S_IRUGO, root, &zcache_failed_pers_puts);
+	zdfs("failed_get_free_pages", S_IRUGO, root,
+				&zcache_failed_getfreepages);
+	zdfs("failed_alloc", S_IRUGO, root, &zcache_failed_alloc);
+	zdfs("put_to_flush", S_IRUGO, root, &zcache_put_to_flush);
+	zdfs("compress_poor", S_IRUGO, root, &zcache_compress_poor);
+	zdfs("mean_compress_poor", S_IRUGO, root, &zcache_mean_compress_poor);
+	zdfs("eph_ate_tail", S_IRUGO, root, &zcache_eph_ate_tail);
+	zdfs("eph_ate_tail_failed", S_IRUGO, root, &zcache_eph_ate_tail_failed);
+	zdfs("pers_ate_eph", S_IRUGO, root, &zcache_pers_ate_eph);
+	zdfs("pers_ate_eph_failed", S_IRUGO, root, &zcache_pers_ate_eph_failed);
+	zdfs("evicted_eph_zpages", S_IRUGO, root, &zcache_evicted_eph_zpages);
+	zdfs("evicted_eph_pageframes", S_IRUGO, root,
+				&zcache_evicted_eph_pageframes);
+	zdfs("eph_pageframes", S_IRUGO, root, &zcache_eph_pageframes);
+	zdfs("eph_pageframes_max", S_IRUGO, root, &zcache_eph_pageframes_max);
+	zdfs("pers_pageframes", S_IRUGO, root, &zcache_pers_pageframes);
+	zdfs("pers_pageframes_max", S_IRUGO, root, &zcache_pers_pageframes_max);
+	zdfs("eph_zpages", S_IRUGO, root, &zcache_eph_zpages);
+	zdfs("eph_zpages_max", S_IRUGO, root, &zcache_eph_zpages_max);
+	zdfs("pers_zpages", S_IRUGO, root, &zcache_pers_zpages);
+	zdfs("pers_zpages_max", S_IRUGO, root, &zcache_pers_zpages_max);
+	zdfs("last_active_file_pageframes", S_IRUGO, root,
+				&zcache_last_active_file_pageframes);
+	zdfs("last_inactive_file_pageframes", S_IRUGO, root,
+				&zcache_last_inactive_file_pageframes);
+	zdfs("last_active_anon_pageframes", S_IRUGO, root,
+				&zcache_last_active_anon_pageframes);
+	zdfs("last_inactive_anon_pageframes", S_IRUGO, root,
+				&zcache_last_inactive_anon_pageframes);
+	zdfs("eph_nonactive_puts_ignored", S_IRUGO, root,
+				&zcache_eph_nonactive_puts_ignored);
+	zdfs("pers_nonactive_puts_ignored", S_IRUGO, root,
+				&zcache_pers_nonactive_puts_ignored);
+	zdfs64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes);
+	zdfs64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max);
+	zdfs64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes);
+	zdfs64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max);
+	return 0;
+}
+#undef	zdebugfs
+#undef	zdfs64
+#endif
+
+#define ZCACHE_DEBUG
+#ifdef ZCACHE_DEBUG
+/* developers can call this in case of ooms, e.g. to find memory leaks */
+void zcache_dump(void)
 {
-	unsigned long val;
-	int err;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	err = kstrtoul(buf, 10, &val);
-	if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
-		return -EINVAL;
-	zv_max_zsize = val;
-	return count;
+	pr_info("zcache: obj_count=%lu\n", zcache_obj_count);
+	pr_info("zcache: obj_count_max=%lu\n", zcache_obj_count_max);
+	pr_info("zcache: objnode_count=%lu\n", zcache_objnode_count);
+	pr_info("zcache: objnode_count_max=%lu\n", zcache_objnode_count_max);
+	pr_info("zcache: flush_total=%lu\n", zcache_flush_total);
+	pr_info("zcache: flush_found=%lu\n", zcache_flush_found);
+	pr_info("zcache: flobj_total=%lu\n", zcache_flobj_total);
+	pr_info("zcache: flobj_found=%lu\n", zcache_flobj_found);
+	pr_info("zcache: failed_eph_puts=%lu\n", zcache_failed_eph_puts);
+	pr_info("zcache: failed_pers_puts=%lu\n", zcache_failed_pers_puts);
+	pr_info("zcache: failed_get_free_pages=%lu\n",
+				zcache_failed_getfreepages);
+	pr_info("zcache: failed_alloc=%lu\n", zcache_failed_alloc);
+	pr_info("zcache: put_to_flush=%lu\n", zcache_put_to_flush);
+	pr_info("zcache: compress_poor=%lu\n", zcache_compress_poor);
+	pr_info("zcache: mean_compress_poor=%lu\n",
+				zcache_mean_compress_poor);
+	pr_info("zcache: eph_ate_tail=%lu\n", zcache_eph_ate_tail);
+	pr_info("zcache: eph_ate_tail_failed=%lu\n",
+				zcache_eph_ate_tail_failed);
+	pr_info("zcache: pers_ate_eph=%lu\n", zcache_pers_ate_eph);
+	pr_info("zcache: pers_ate_eph_failed=%lu\n",
+				zcache_pers_ate_eph_failed);
+	pr_info("zcache: evicted_eph_zpages=%lu\n", zcache_evicted_eph_zpages);
+	pr_info("zcache: evicted_eph_pageframes=%lu\n",
+				zcache_evicted_eph_pageframes);
+	pr_info("zcache: eph_pageframes=%lu\n", zcache_eph_pageframes);
+	pr_info("zcache: eph_pageframes_max=%lu\n", zcache_eph_pageframes_max);
+	pr_info("zcache: pers_pageframes=%lu\n", zcache_pers_pageframes);
+	pr_info("zcache: pers_pageframes_max=%lu\n",
+				zcache_pers_pageframes_max);
+	pr_info("zcache: eph_zpages=%lu\n", zcache_eph_zpages);
+	pr_info("zcache: eph_zpages_max=%lu\n", zcache_eph_zpages_max);
+	pr_info("zcache: pers_zpages=%lu\n", zcache_pers_zpages);
+	pr_info("zcache: pers_zpages_max=%lu\n", zcache_pers_zpages_max);
+	pr_info("zcache: eph_zbytes=%llu\n",
+				(unsigned long long)zcache_eph_zbytes);
+	pr_info("zcache: eph_zbytes_max=%llu\n",
+				(unsigned long long)zcache_eph_zbytes_max);
+	pr_info("zcache: pers_zbytes=%llu\n",
+				(unsigned long long)zcache_pers_zbytes);
+	pr_info("zcache: pers_zbytes_max=%llu\n",
+			(unsigned long long)zcache_pers_zbytes_max);
 }
-
-/*
- * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap)
- * pages that don't compress to less than this value (including metadata
- * overhead) to be rejected UNLESS the mean compression is also smaller
- * than this value.  In other words, we are load-balancing-by-zsize the
- * accepted pages.  Again, we don't allow the value to get too close
- * to PAGE_SIZE.
- */
-static ssize_t zv_max_mean_zsize_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
-				    char *buf)
-{
-	return sprintf(buf, "%u\n", zv_max_mean_zsize);
-}
-
-static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
-				    struct kobj_attribute *attr,
-				    const char *buf, size_t count)
-{
-	unsigned long val;
-	int err;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	err = kstrtoul(buf, 10, &val);
-	if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
-		return -EINVAL;
-	zv_max_mean_zsize = val;
-	return count;
-}
-
-/*
- * setting zv_page_count_policy_percent via sysfs sets an upper bound of
- * persistent (e.g. swap) pages that will be retained according to:
- *     (zv_page_count_policy_percent * totalram_pages) / 100)
- * when that limit is reached, further puts will be rejected (until
- * some pages have been flushed).  Note that, due to compression,
- * this number may exceed 100; it defaults to 75 and we set an
- * arbitrary limit of 150.  A poor choice will almost certainly result
- * in OOM's, so this value should only be changed prudently.
- */
-static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
-						 struct kobj_attribute *attr,
-						 char *buf)
-{
-	return sprintf(buf, "%u\n", zv_page_count_policy_percent);
-}
-
-static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj,
-						  struct kobj_attribute *attr,
-						  const char *buf, size_t count)
-{
-	unsigned long val;
-	int err;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	err = kstrtoul(buf, 10, &val);
-	if (err || (val == 0) || (val > 150))
-		return -EINVAL;
-	zv_page_count_policy_percent = val;
-	return count;
-}
-
-static struct kobj_attribute zcache_zv_max_zsize_attr = {
-		.attr = { .name = "zv_max_zsize", .mode = 0644 },
-		.show = zv_max_zsize_show,
-		.store = zv_max_zsize_store,
-};
-
-static struct kobj_attribute zcache_zv_max_mean_zsize_attr = {
-		.attr = { .name = "zv_max_mean_zsize", .mode = 0644 },
-		.show = zv_max_mean_zsize_show,
-		.store = zv_max_mean_zsize_store,
-};
-
-static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = {
-		.attr = { .name = "zv_page_count_policy_percent",
-			  .mode = 0644 },
-		.show = zv_page_count_policy_percent_show,
-		.store = zv_page_count_policy_percent_store,
-};
 #endif
 
 /*
  * zcache core code starts here
  */
 
-/* useful stats not collected by cleancache or frontswap */
-static unsigned long zcache_flush_total;
-static unsigned long zcache_flush_found;
-static unsigned long zcache_flobj_total;
-static unsigned long zcache_flobj_found;
-static unsigned long zcache_failed_eph_puts;
-static unsigned long zcache_nonactive_puts;
-static unsigned long zcache_failed_pers_puts;
+static struct zcache_client zcache_host;
+static struct zcache_client zcache_clients[MAX_CLIENTS];
+
+static inline bool is_local_client(struct zcache_client *cli)
+{
+	return cli == &zcache_host;
+}
+
+static struct zcache_client *zcache_get_client_by_id(uint16_t cli_id)
+{
+	struct zcache_client *cli = &zcache_host;
+
+	if (cli_id != LOCAL_CLIENT) {
+		if (cli_id >= MAX_CLIENTS)
+			goto out;
+		cli = &zcache_clients[cli_id];
+	}
+out:
+	return cli;
+}
 
 /*
  * Tmem operations assume the poolid implies the invoking client.
@@ -1398,21 +328,16 @@
  * of zcache would have one client per guest and each client might
  * have a poolid==N.
  */
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
+struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
 {
 	struct tmem_pool *pool = NULL;
 	struct zcache_client *cli = NULL;
 
-	if (cli_id == LOCAL_CLIENT)
-		cli = &zcache_host;
-	else {
-		if (cli_id >= MAX_CLIENTS)
-			goto out;
-		cli = &zcache_clients[cli_id];
-		if (cli == NULL)
-			goto out;
+	cli = zcache_get_client_by_id(cli_id);
+	if (cli == NULL)
+		goto out;
+	if (!is_local_client(cli))
 		atomic_inc(&cli->refcount);
-	}
 	if (poolid < MAX_POOLS_PER_CLIENT) {
 		pool = cli->tmem_pools[poolid];
 		if (pool != NULL)
@@ -1422,7 +347,7 @@
 	return pool;
 }
 
-static void zcache_put_pool(struct tmem_pool *pool)
+void zcache_put_pool(struct tmem_pool *pool)
 {
 	struct zcache_client *cli = NULL;
 
@@ -1430,173 +355,26 @@
 		BUG();
 	cli = pool->client;
 	atomic_dec(&pool->refcount);
-	atomic_dec(&cli->refcount);
+	if (!is_local_client(cli))
+		atomic_dec(&cli->refcount);
 }
 
 int zcache_new_client(uint16_t cli_id)
 {
-	struct zcache_client *cli = NULL;
+	struct zcache_client *cli;
 	int ret = -1;
 
-	if (cli_id == LOCAL_CLIENT)
-		cli = &zcache_host;
-	else if ((unsigned int)cli_id < MAX_CLIENTS)
-		cli = &zcache_clients[cli_id];
+	cli = zcache_get_client_by_id(cli_id);
 	if (cli == NULL)
 		goto out;
 	if (cli->allocated)
 		goto out;
 	cli->allocated = 1;
-#ifdef CONFIG_FRONTSWAP
-	cli->xvpool = xv_create_pool();
-	if (cli->xvpool == NULL)
-		goto out;
-#endif
 	ret = 0;
 out:
 	return ret;
 }
 
-/* counters for debugging */
-static unsigned long zcache_failed_get_free_pages;
-static unsigned long zcache_failed_alloc;
-static unsigned long zcache_put_to_flush;
-
-/*
- * for now, used named slabs so can easily track usage; later can
- * either just use kmalloc, or perhaps add a slab-like allocator
- * to more carefully manage total memory utilization
- */
-static struct kmem_cache *zcache_objnode_cache;
-static struct kmem_cache *zcache_obj_cache;
-static struct kmem_cache *ramster_flnode_cache;
-static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_obj_count_max;
-static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_objnode_count_max;
-
-/*
- * to avoid memory allocation recursion (e.g. due to direct reclaim), we
- * preload all necessary data structures so the hostops callbacks never
- * actually do a malloc
- */
-struct zcache_preload {
-	void *page;
-	struct tmem_obj *obj;
-	int nr;
-	struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
-	struct flushlist_node *flnode;
-};
-static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-
-static int zcache_do_preload(struct tmem_pool *pool)
-{
-	struct zcache_preload *kp;
-	struct tmem_objnode *objnode;
-	struct tmem_obj *obj;
-	struct flushlist_node *flnode;
-	void *page;
-	int ret = -ENOMEM;
-
-	if (unlikely(zcache_objnode_cache == NULL))
-		goto out;
-	if (unlikely(zcache_obj_cache == NULL))
-		goto out;
-	preempt_disable();
-	kp = &__get_cpu_var(zcache_preloads);
-	while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
-		preempt_enable_no_resched();
-		objnode = kmem_cache_alloc(zcache_objnode_cache,
-				ZCACHE_GFP_MASK);
-		if (unlikely(objnode == NULL)) {
-			zcache_failed_alloc++;
-			goto out;
-		}
-		preempt_disable();
-		kp = &__get_cpu_var(zcache_preloads);
-		if (kp->nr < ARRAY_SIZE(kp->objnodes))
-			kp->objnodes[kp->nr++] = objnode;
-		else
-			kmem_cache_free(zcache_objnode_cache, objnode);
-	}
-	preempt_enable_no_resched();
-	obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
-	if (unlikely(obj == NULL)) {
-		zcache_failed_alloc++;
-		goto out;
-	}
-	flnode = kmem_cache_alloc(ramster_flnode_cache, ZCACHE_GFP_MASK);
-	if (unlikely(flnode == NULL)) {
-		zcache_failed_alloc++;
-		goto out;
-	}
-	if (is_ephemeral(pool)) {
-		page = (void *)__get_free_page(ZCACHE_GFP_MASK);
-		if (unlikely(page == NULL)) {
-			zcache_failed_get_free_pages++;
-			kmem_cache_free(zcache_obj_cache, obj);
-			kmem_cache_free(ramster_flnode_cache, flnode);
-			goto out;
-		}
-	}
-	preempt_disable();
-	kp = &__get_cpu_var(zcache_preloads);
-	if (kp->obj == NULL)
-		kp->obj = obj;
-	else
-		kmem_cache_free(zcache_obj_cache, obj);
-	if (kp->flnode == NULL)
-		kp->flnode = flnode;
-	else
-		kmem_cache_free(ramster_flnode_cache, flnode);
-	if (is_ephemeral(pool)) {
-		if (kp->page == NULL)
-			kp->page = page;
-		else
-			free_page((unsigned long)page);
-	}
-	ret = 0;
-out:
-	return ret;
-}
-
-static int ramster_do_preload_flnode_only(struct tmem_pool *pool)
-{
-	struct zcache_preload *kp;
-	struct flushlist_node *flnode;
-	int ret = -ENOMEM;
-
-	BUG_ON(!irqs_disabled());
-	if (unlikely(ramster_flnode_cache == NULL))
-		BUG();
-	kp = &__get_cpu_var(zcache_preloads);
-	flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC);
-	if (unlikely(flnode == NULL) && kp->flnode == NULL)
-		BUG();  /* FIXME handle more gracefully, but how??? */
-	else if (kp->flnode == NULL)
-		kp->flnode = flnode;
-	else
-		kmem_cache_free(ramster_flnode_cache, flnode);
-	return ret;
-}
-
-static void *zcache_get_free_page(void)
-{
-	struct zcache_preload *kp;
-	void *page;
-
-	kp = &__get_cpu_var(zcache_preloads);
-	page = kp->page;
-	BUG_ON(page == NULL);
-	kp->page = NULL;
-	return page;
-}
-
-static void zcache_free_page(void *p)
-{
-	free_page((unsigned long)p);
-}
-
 /*
  * zcache implementation for tmem host ops
  */
@@ -1604,78 +382,56 @@
 static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
 {
 	struct tmem_objnode *objnode = NULL;
-	unsigned long count;
 	struct zcache_preload *kp;
+	int i;
 
 	kp = &__get_cpu_var(zcache_preloads);
-	if (kp->nr <= 0)
-		goto out;
-	objnode = kp->objnodes[kp->nr - 1];
+	for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
+		objnode = kp->objnodes[i];
+		if (objnode != NULL) {
+			kp->objnodes[i] = NULL;
+			break;
+		}
+	}
 	BUG_ON(objnode == NULL);
-	kp->objnodes[kp->nr - 1] = NULL;
-	kp->nr--;
-	count = atomic_inc_return(&zcache_curr_objnode_count);
-	if (count > zcache_curr_objnode_count_max)
-		zcache_curr_objnode_count_max = count;
-out:
+	zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic);
+	if (zcache_objnode_count > zcache_objnode_count_max)
+		zcache_objnode_count_max = zcache_objnode_count;
 	return objnode;
 }
 
 static void zcache_objnode_free(struct tmem_objnode *objnode,
 					struct tmem_pool *pool)
 {
-	atomic_dec(&zcache_curr_objnode_count);
-	BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
+	zcache_objnode_count =
+		atomic_dec_return(&zcache_objnode_atomic);
+	BUG_ON(zcache_objnode_count < 0);
 	kmem_cache_free(zcache_objnode_cache, objnode);
 }
 
 static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
 {
 	struct tmem_obj *obj = NULL;
-	unsigned long count;
 	struct zcache_preload *kp;
 
 	kp = &__get_cpu_var(zcache_preloads);
 	obj = kp->obj;
 	BUG_ON(obj == NULL);
 	kp->obj = NULL;
-	count = atomic_inc_return(&zcache_curr_obj_count);
-	if (count > zcache_curr_obj_count_max)
-		zcache_curr_obj_count_max = count;
+	zcache_obj_count = atomic_inc_return(&zcache_obj_atomic);
+	if (zcache_obj_count > zcache_obj_count_max)
+		zcache_obj_count_max = zcache_obj_count;
 	return obj;
 }
 
 static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
 {
-	atomic_dec(&zcache_curr_obj_count);
-	BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
+	zcache_obj_count =
+		atomic_dec_return(&zcache_obj_atomic);
+	BUG_ON(zcache_obj_count < 0);
 	kmem_cache_free(zcache_obj_cache, obj);
 }
 
-static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
-{
-	struct flushlist_node *flnode = NULL;
-	struct zcache_preload *kp;
-	int count;
-
-	kp = &__get_cpu_var(zcache_preloads);
-	flnode = kp->flnode;
-	BUG_ON(flnode == NULL);
-	kp->flnode = NULL;
-	count = atomic_inc_return(&ramster_curr_flnode_count);
-	if (count > ramster_curr_flnode_count_max)
-		ramster_curr_flnode_count_max = count;
-	return flnode;
-}
-
-static void ramster_flnode_free(struct flushlist_node *flnode,
-				struct tmem_pool *pool)
-{
-	atomic_dec(&ramster_curr_flnode_count);
-	BUG_ON(atomic_read(&ramster_curr_flnode_count) < 0);
-	kmem_cache_free(ramster_flnode_cache, flnode);
-}
-
 static struct tmem_hostops zcache_hostops = {
 	.obj_alloc = zcache_obj_alloc,
 	.obj_free = zcache_obj_free,
@@ -1683,218 +439,361 @@
 	.objnode_free = zcache_objnode_free,
 };
 
+static struct page *zcache_alloc_page(void)
+{
+	struct page *page = alloc_page(ZCACHE_GFP_MASK);
+
+	if (page != NULL)
+		zcache_pageframes_alloced =
+			atomic_inc_return(&zcache_pageframes_alloced_atomic);
+	return page;
+}
+
+#ifdef FRONTSWAP_HAS_UNUSE
+static void zcache_unacct_page(void)
+{
+	zcache_pageframes_freed =
+		atomic_inc_return(&zcache_pageframes_freed_atomic);
+}
+#endif
+
+static void zcache_free_page(struct page *page)
+{
+	long curr_pageframes;
+	static long max_pageframes, min_pageframes;
+
+	if (page == NULL)
+		BUG();
+	__free_page(page);
+	zcache_pageframes_freed =
+		atomic_inc_return(&zcache_pageframes_freed_atomic);
+	curr_pageframes = zcache_pageframes_alloced -
+			atomic_read(&zcache_pageframes_freed_atomic) -
+			atomic_read(&zcache_eph_pageframes_atomic) -
+			atomic_read(&zcache_pers_pageframes_atomic);
+	if (curr_pageframes > max_pageframes)
+		max_pageframes = curr_pageframes;
+	if (curr_pageframes < min_pageframes)
+		min_pageframes = curr_pageframes;
+#ifdef ZCACHE_DEBUG
+	if (curr_pageframes > 2L || curr_pageframes < -2L) {
+		/* pr_info here */
+	}
+#endif
+}
+
 /*
  * zcache implementations for PAM page descriptor ops
  */
 
-
-static inline void dec_and_check(atomic_t *pvar)
-{
-	atomic_dec(pvar);
-	/* later when all accounting is fixed, make this a BUG */
-	WARN_ON_ONCE(atomic_read(pvar) < 0);
-}
-
-static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_eph_pampd_count_max;
-static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_pers_pampd_count_max;
-
 /* forward reference */
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
+static void zcache_compress(struct page *from,
+				void **out_va, unsigned *out_len);
 
-static int zcache_pampd_eph_create(char *data, size_t size, bool raw,
-				struct tmem_pool *pool, struct tmem_oid *oid,
-				uint32_t index, void **pampd)
+static struct page *zcache_evict_eph_pageframe(void);
+
+static void *zcache_pampd_eph_create(char *data, size_t size, bool raw,
+					struct tmem_handle *th)
 {
-	int ret = -1;
-	void *cdata = data;
-	size_t clen = size;
-	struct zcache_client *cli = pool->client;
-	uint16_t client_id = get_client_id_from_client(cli);
-	struct page *page = NULL;
-	unsigned long count;
+	void *pampd = NULL, *cdata = data;
+	unsigned clen = size;
+	struct page *page = (struct page *)(data), *newpage;
 
 	if (!raw) {
-		page = virt_to_page(data);
-		ret = zcache_compress(page, &cdata, &clen);
-		if (ret == 0)
-			goto out;
-		if (clen == 0 || clen > zbud_max_buddy_size()) {
+		zcache_compress(page, &cdata, &clen);
+		if (clen > zbud_max_buddy_size()) {
 			zcache_compress_poor++;
 			goto out;
 		}
+	} else {
+		BUG_ON(clen > zbud_max_buddy_size());
 	}
-	*pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
-					index, page, cdata, clen);
-	if (*pampd == NULL) {
-		ret = -ENOMEM;
+
+	/* look for space via an existing match first */
+	pampd = (void *)zbud_match_prep(th, true, cdata, clen);
+	if (pampd != NULL)
+		goto got_pampd;
+
+	/* no match, now we need to find (or free up) a full page */
+	newpage = zcache_alloc_page();
+	if (newpage != NULL)
+		goto create_in_new_page;
+
+	zcache_failed_getfreepages++;
+	/* can't allocate a page, evict an ephemeral page via LRU */
+	newpage = zcache_evict_eph_pageframe();
+	if (newpage == NULL) {
+		zcache_eph_ate_tail_failed++;
 		goto out;
 	}
-	ret = 0;
-	count = atomic_inc_return(&zcache_curr_eph_pampd_count);
-	if (count > zcache_curr_eph_pampd_count_max)
-		zcache_curr_eph_pampd_count_max = count;
-	if (client_id != LOCAL_CLIENT) {
-		count = atomic_inc_return(&ramster_foreign_eph_pampd_count);
-		if (count > ramster_foreign_eph_pampd_count_max)
-			ramster_foreign_eph_pampd_count_max = count;
-	}
+	zcache_eph_ate_tail++;
+
+create_in_new_page:
+	pampd = (void *)zbud_create_prep(th, true, cdata, clen, newpage);
+	BUG_ON(pampd == NULL);
+	zcache_eph_pageframes =
+		atomic_inc_return(&zcache_eph_pageframes_atomic);
+	if (zcache_eph_pageframes > zcache_eph_pageframes_max)
+		zcache_eph_pageframes_max = zcache_eph_pageframes;
+
+got_pampd:
+	zcache_eph_zbytes =
+		atomic_long_add_return(clen, &zcache_eph_zbytes_atomic);
+	if (zcache_eph_zbytes > zcache_eph_zbytes_max)
+		zcache_eph_zbytes_max = zcache_eph_zbytes;
+	zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic);
+	if (zcache_eph_zpages > zcache_eph_zpages_max)
+		zcache_eph_zpages_max = zcache_eph_zpages;
+	if (ramster_enabled && raw)
+		ramster_count_foreign_pages(true, 1);
 out:
-	return ret;
+	return pampd;
 }
 
-static int zcache_pampd_pers_create(char *data, size_t size, bool raw,
-				struct tmem_pool *pool, struct tmem_oid *oid,
-				uint32_t index, void **pampd)
+static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
+					struct tmem_handle *th)
 {
-	int ret = -1;
-	void *cdata = data;
-	size_t clen = size;
-	struct zcache_client *cli = pool->client;
-	struct page *page;
-	unsigned long count;
-	unsigned long zv_mean_zsize;
-	struct zv_hdr *zv;
-	long curr_pers_pampd_count;
-	u64 total_zsize;
-#ifdef RAMSTER_TESTING
-	static bool pampd_neg_warned;
-#endif
+	void *pampd = NULL, *cdata = data;
+	unsigned clen = size;
+	struct page *page = (struct page *)(data), *newpage;
+	unsigned long zbud_mean_zsize;
+	unsigned long curr_pers_zpages, total_zsize;
 
-	curr_pers_pampd_count = atomic_read(&zcache_curr_pers_pampd_count) -
-			atomic_read(&ramster_remote_pers_pages);
-#ifdef RAMSTER_TESTING
-	/* should always be positive, but warn if accounting is off */
-	if (!pampd_neg_warned) {
-		pr_warn("ramster: bad accounting for curr_pers_pampd_count\n");
-		pampd_neg_warned = true;
+	if (data == NULL) {
+		BUG_ON(!ramster_enabled);
+		goto create_pampd;
 	}
-#endif
-	if (curr_pers_pampd_count >
-		    (zv_page_count_policy_percent * totalram_pages) / 100) {
-		zcache_policy_percent_exceeded++;
-		goto out;
-	}
-	if (raw)
-		goto ok_to_create;
-	page = virt_to_page(data);
-	if (zcache_compress(page, &cdata, &clen) == 0)
-		goto out;
+	curr_pers_zpages = zcache_pers_zpages;
+/* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */
+	if (!raw)
+		zcache_compress(page, &cdata, &clen);
 	/* reject if compression is too poor */
-	if (clen > zv_max_zsize) {
+	if (clen > zbud_max_zsize) {
 		zcache_compress_poor++;
 		goto out;
 	}
 	/* reject if mean compression is too poor */
-	if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
-		total_zsize = xv_get_total_size_bytes(cli->xvpool);
-		zv_mean_zsize = div_u64(total_zsize, curr_pers_pampd_count);
-		if (zv_mean_zsize > zv_max_mean_zsize) {
+	if ((clen > zbud_max_mean_zsize) && (curr_pers_zpages > 0)) {
+		total_zsize = zcache_pers_zbytes;
+		if ((long)total_zsize < 0)
+			total_zsize = 0;
+		zbud_mean_zsize = div_u64(total_zsize,
+					curr_pers_zpages);
+		if (zbud_mean_zsize > zbud_max_mean_zsize) {
 			zcache_mean_compress_poor++;
 			goto out;
 		}
 	}
-ok_to_create:
-	*pampd = (void *)zv_create(cli, pool->pool_id, oid, index, cdata, clen);
-	if (*pampd == NULL) {
-		ret = -ENOMEM;
+
+create_pampd:
+	/* look for space via an existing match first */
+	pampd = (void *)zbud_match_prep(th, false, cdata, clen);
+	if (pampd != NULL)
+		goto got_pampd;
+
+	/* no match, now we need to find (or free up) a full page */
+	newpage = zcache_alloc_page();
+	if (newpage != NULL)
+		goto create_in_new_page;
+	/*
+	 * FIXME do the following only if eph is oversized?
+	 * if (zcache_eph_pageframes >
+	 * (global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE) +
+	 * global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE)))
+	 */
+	zcache_failed_getfreepages++;
+	/* can't allocate a page, evict an ephemeral page via LRU */
+	newpage = zcache_evict_eph_pageframe();
+	if (newpage == NULL) {
+		zcache_pers_ate_eph_failed++;
 		goto out;
 	}
-	ret = 0;
-	count = atomic_inc_return(&zcache_curr_pers_pampd_count);
-	if (count > zcache_curr_pers_pampd_count_max)
-		zcache_curr_pers_pampd_count_max = count;
-	if (is_local_client(cli))
-		goto out;
-	zv = *(struct zv_hdr **)pampd;
-	count = atomic_inc_return(&ramster_foreign_pers_pampd_count);
-	if (count > ramster_foreign_pers_pampd_count_max)
-		ramster_foreign_pers_pampd_count_max = count;
+	zcache_pers_ate_eph++;
+
+create_in_new_page:
+	pampd = (void *)zbud_create_prep(th, false, cdata, clen, newpage);
+	BUG_ON(pampd == NULL);
+	zcache_pers_pageframes =
+		atomic_inc_return(&zcache_pers_pageframes_atomic);
+	if (zcache_pers_pageframes > zcache_pers_pageframes_max)
+		zcache_pers_pageframes_max = zcache_pers_pageframes;
+
+got_pampd:
+	zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic);
+	if (zcache_pers_zpages > zcache_pers_zpages_max)
+		zcache_pers_zpages_max = zcache_pers_zpages;
+	zcache_pers_zbytes =
+		atomic_long_add_return(clen, &zcache_pers_zbytes_atomic);
+	if (zcache_pers_zbytes > zcache_pers_zbytes_max)
+		zcache_pers_zbytes_max = zcache_pers_zbytes;
+	if (ramster_enabled && raw)
+		ramster_count_foreign_pages(false, 1);
 out:
-	return ret;
+	return pampd;
 }
 
-static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
-				struct tmem_pool *pool, struct tmem_oid *oid,
-				uint32_t index)
+/*
+ * This is called directly from zcache_put_page to pre-allocate space
+ * to store a zpage.
+ */
+void *zcache_pampd_create(char *data, unsigned int size, bool raw,
+					int eph, struct tmem_handle *th)
 {
 	void *pampd = NULL;
-	int ret;
-	bool ephemeral;
+	struct zcache_preload *kp;
+	struct tmem_objnode *objnode;
+	struct tmem_obj *obj;
+	int i;
 
-	BUG_ON(preemptible());
-	ephemeral = (eph == 1) || ((eph == 0) && is_ephemeral(pool));
-	if (ephemeral)
-		ret = zcache_pampd_eph_create(data, size, raw, pool,
-						oid, index, &pampd);
+	BUG_ON(!irqs_disabled());
+	/* pre-allocate per-cpu metadata */
+	BUG_ON(zcache_objnode_cache == NULL);
+	BUG_ON(zcache_obj_cache == NULL);
+	kp = &__get_cpu_var(zcache_preloads);
+	for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
+		objnode = kp->objnodes[i];
+		if (objnode == NULL) {
+			objnode = kmem_cache_alloc(zcache_objnode_cache,
+							ZCACHE_GFP_MASK);
+			if (unlikely(objnode == NULL)) {
+				zcache_failed_alloc++;
+				goto out;
+			}
+			kp->objnodes[i] = objnode;
+		}
+	}
+	if (kp->obj == NULL) {
+		obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
+		kp->obj = obj;
+	}
+	if (unlikely(kp->obj == NULL)) {
+		zcache_failed_alloc++;
+		goto out;
+	}
+	/*
+	 * ok, have all the metadata pre-allocated, now do the data
+	 * but since how we allocate the data is dependent on ephemeral
+	 * or persistent, we split the call here to different sub-functions
+	 */
+	if (eph)
+		pampd = zcache_pampd_eph_create(data, size, raw, th);
 	else
-		ret = zcache_pampd_pers_create(data, size, raw, pool,
-						oid, index, &pampd);
-	/* FIXME add some counters here for failed creates? */
+		pampd = zcache_pampd_pers_create(data, size, raw, th);
+out:
 	return pampd;
 }
 
 /*
+ * This is a pamops called via tmem_put and is necessary to "finish"
+ * a pampd creation.
+ */
+void zcache_pampd_create_finish(void *pampd, bool eph)
+{
+	zbud_create_finish((struct zbudref *)pampd, eph);
+}
+
+/*
+ * This is passed as a function parameter to zbud_decompress so that
+ * zbud need not be familiar with the details of crypto. It assumes that
+ * the bytes from_va and to_va through from_va+size-1 and to_va+size-1 are
+ * kmapped.  It must be successful, else there is a logic bug somewhere.
+ */
+static void zcache_decompress(char *from_va, unsigned int size, char *to_va)
+{
+	int ret;
+	unsigned int outlen = PAGE_SIZE;
+
+	ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size,
+				to_va, &outlen);
+	BUG_ON(ret);
+	BUG_ON(outlen != PAGE_SIZE);
+}
+
+/*
+ * Decompress from the kernel va to a pageframe
+ */
+void zcache_decompress_to_page(char *from_va, unsigned int size,
+					struct page *to_page)
+{
+	char *to_va = kmap_atomic(to_page);
+	zcache_decompress(from_va, size, to_va);
+	kunmap_atomic(to_va);
+}
+
+/*
  * fill the pageframe corresponding to the struct page with the data
  * from the passed pampd
  */
-static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
+static int zcache_pampd_get_data(char *data, size_t *sizep, bool raw,
 					void *pampd, struct tmem_pool *pool,
 					struct tmem_oid *oid, uint32_t index)
 {
-	int ret = 0;
+	int ret;
+	bool eph = !is_persistent(pool);
 
 	BUG_ON(preemptible());
-	BUG_ON(is_ephemeral(pool)); /* Fix later for shared pools? */
+	BUG_ON(eph);	/* fix later if shared pools get implemented */
 	BUG_ON(pampd_is_remote(pampd));
 	if (raw)
-		zv_copy_from_pampd(data, bufsize, pampd);
-	else
-		zv_decompress(virt_to_page(data), pampd);
-	return ret;
-}
-
-static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
-					void *pampd, struct tmem_pool *pool,
-					struct tmem_oid *oid, uint32_t index)
-{
-	int ret = 0;
-	unsigned long flags;
-	struct zcache_client *cli = pool->client;
-
-	BUG_ON(preemptible());
-	BUG_ON(pampd_is_remote(pampd));
-	if (is_ephemeral(pool)) {
-		local_irq_save(flags);
-		if (raw)
-			zbud_copy_from_pampd(data, bufsize, pampd);
-		else
-			ret = zbud_decompress(virt_to_page(data), pampd);
-		zbud_free_and_delist((struct zbud_hdr *)pampd);
-		local_irq_restore(flags);
-		if (!is_local_client(cli))
-			dec_and_check(&ramster_foreign_eph_pampd_count);
-		dec_and_check(&zcache_curr_eph_pampd_count);
-	} else {
-		if (is_local_client(cli))
-			BUG();
-		if (raw)
-			zv_copy_from_pampd(data, bufsize, pampd);
-		else
-			zv_decompress(virt_to_page(data), pampd);
-		zv_free(cli->xvpool, pampd);
-		if (!is_local_client(cli))
-			dec_and_check(&ramster_foreign_pers_pampd_count);
-		dec_and_check(&zcache_curr_pers_pampd_count);
-		ret = 0;
+		ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
+						sizep, eph);
+	else {
+		ret = zbud_decompress((struct page *)(data),
+					(struct zbudref *)pampd, false,
+					zcache_decompress);
+		*sizep = PAGE_SIZE;
 	}
 	return ret;
 }
 
-static bool zcache_pampd_is_remote(void *pampd)
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw,
+					void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oid, uint32_t index)
 {
-	return pampd_is_remote(pampd);
+	int ret;
+	bool eph = !is_persistent(pool);
+	struct page *page = NULL;
+	unsigned int zsize, zpages;
+
+	BUG_ON(preemptible());
+	BUG_ON(pampd_is_remote(pampd));
+	if (raw)
+		ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
+						sizep, eph);
+	else {
+		ret = zbud_decompress((struct page *)(data),
+					(struct zbudref *)pampd, eph,
+					zcache_decompress);
+		*sizep = PAGE_SIZE;
+	}
+	page = zbud_free_and_delist((struct zbudref *)pampd, eph,
+					&zsize, &zpages);
+	if (eph) {
+		if (page)
+			zcache_eph_pageframes =
+			    atomic_dec_return(&zcache_eph_pageframes_atomic);
+		zcache_eph_zpages =
+		    atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
+		zcache_eph_zbytes =
+		    atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
+	} else {
+		if (page)
+			zcache_pers_pageframes =
+			    atomic_dec_return(&zcache_pers_pageframes_atomic);
+		zcache_pers_zpages =
+		    atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
+		zcache_pers_zbytes =
+		    atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
+	}
+	if (!is_local_client(pool->client))
+		ramster_count_foreign_pages(eph, -1);
+	if (page)
+		zcache_free_page(page);
+	return ret;
 }
 
 /*
@@ -1904,362 +803,134 @@
 static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
 			      struct tmem_oid *oid, uint32_t index, bool acct)
 {
-	struct zcache_client *cli = pool->client;
-	bool eph = is_ephemeral(pool);
-	struct zv_hdr *zv;
+	struct page *page = NULL;
+	unsigned int zsize, zpages;
 
 	BUG_ON(preemptible());
 	if (pampd_is_remote(pampd)) {
-		WARN_ON(acct == false);
-		if (oid == NULL) {
-			/*
-			 * a NULL oid means to ignore this pampd free
-			 * as the remote freeing will be handled elsewhere
-			 */
-		} else if (eph) {
-			/* FIXME remote flush optional but probably good idea */
-			/* FIXME get these working properly again */
-			dec_and_check(&zcache_curr_eph_pampd_count);
-		} else if (pampd_is_intransit(pampd)) {
-			/* did a pers remote get_and_free, so just free local */
-			pampd = pampd_mask_intransit_and_remote(pampd);
-			goto local_pers;
-		} else {
-			struct flushlist_node *flnode =
-				ramster_flnode_alloc(pool);
-
-			flnode->xh.client_id = pampd_remote_node(pampd);
-			flnode->xh.pool_id = pool->pool_id;
-			flnode->xh.oid = *oid;
-			flnode->xh.index = index;
-			flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE;
-			spin_lock(&zcache_rem_op_list_lock);
-			list_add(&flnode->rem_op.list, &zcache_rem_op_list);
-			spin_unlock(&zcache_rem_op_list_lock);
-			dec_and_check(&zcache_curr_pers_pampd_count);
-			dec_and_check(&ramster_remote_pers_pages);
-		}
-	} else if (eph) {
-		zbud_free_and_delist((struct zbud_hdr *)pampd);
-		if (!is_local_client(pool->client))
-			dec_and_check(&ramster_foreign_eph_pampd_count);
-		if (acct)
-			/* FIXME get these working properly again */
-			dec_and_check(&zcache_curr_eph_pampd_count);
+		BUG_ON(!ramster_enabled);
+		pampd = ramster_pampd_free(pampd, pool, oid, index, acct);
+		if (pampd == NULL)
+			return;
+	}
+	if (is_ephemeral(pool)) {
+		page = zbud_free_and_delist((struct zbudref *)pampd,
+						true, &zsize, &zpages);
+		if (page)
+			zcache_eph_pageframes =
+			    atomic_dec_return(&zcache_eph_pageframes_atomic);
+		zcache_eph_zpages =
+		    atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
+		zcache_eph_zbytes =
+		    atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
+		/* FIXME CONFIG_RAMSTER... check acct parameter? */
 	} else {
-local_pers:
-		zv = (struct zv_hdr *)pampd;
-		if (!is_local_client(pool->client))
-			dec_and_check(&ramster_foreign_pers_pampd_count);
-		zv_free(cli->xvpool, zv);
-		if (acct)
-			/* FIXME get these working properly again */
-			dec_and_check(&zcache_curr_pers_pampd_count);
+		page = zbud_free_and_delist((struct zbudref *)pampd,
+						false, &zsize, &zpages);
+		if (page)
+			zcache_pers_pageframes =
+			    atomic_dec_return(&zcache_pers_pageframes_atomic);
+		zcache_pers_zpages =
+		     atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
+		zcache_pers_zbytes =
+		    atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
 	}
-}
-
-static void zcache_pampd_free_obj(struct tmem_pool *pool,
-					struct tmem_obj *obj)
-{
-	struct flushlist_node *flnode;
-
-	BUG_ON(preemptible());
-	if (obj->extra == NULL)
-		return;
-	BUG_ON(!pampd_is_remote(obj->extra));
-	flnode = ramster_flnode_alloc(pool);
-	flnode->xh.client_id = pampd_remote_node(obj->extra);
-	flnode->xh.pool_id = pool->pool_id;
-	flnode->xh.oid = obj->oid;
-	flnode->xh.index = FLUSH_ENTIRE_OBJECT;
-	flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ;
-	spin_lock(&zcache_rem_op_list_lock);
-	list_add(&flnode->rem_op.list, &zcache_rem_op_list);
-	spin_unlock(&zcache_rem_op_list_lock);
-}
-
-void zcache_pampd_new_obj(struct tmem_obj *obj)
-{
-	obj->extra = NULL;
-}
-
-int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
-{
-	int ret = -1;
-
-	if (new_pampd != NULL) {
-		if (obj->extra == NULL)
-			obj->extra = new_pampd;
-		/* enforce that all remote pages in an object reside
-		 * in the same node! */
-		else if (pampd_remote_node(new_pampd) !=
-				pampd_remote_node((void *)(obj->extra)))
-			BUG();
-		ret = 0;
-	}
-	return ret;
-}
-
-/*
- * Called by the message handler after a (still compressed) page has been
- * fetched from the remote machine in response to an "is_remote" tmem_get
- * or persistent tmem_localify.  For a tmem_get, "extra" is the address of
- * the page that is to be filled to successfully resolve the tmem_get; for
- * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
- * in the local zcache).  "data" points to "size" bytes of (compressed) data
- * passed in the message.  In the case of a persistent remote get, if
- * pre-allocation was successful (see zcache_repatriate_preload), the page
- * is placed into both local zcache and at "extra".
- */
-int zcache_localify(int pool_id, struct tmem_oid *oidp,
-			uint32_t index, char *data, size_t size,
-			void *extra)
-{
-	int ret = -ENOENT;
-	unsigned long flags;
-	struct tmem_pool *pool;
-	bool ephemeral, delete = false;
-	size_t clen = PAGE_SIZE;
-	void *pampd, *saved_hb;
-	struct tmem_obj *obj;
-
-	pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
-	if (unlikely(pool == NULL))
-		/* pool doesn't exist anymore */
-		goto out;
-	ephemeral = is_ephemeral(pool);
-	local_irq_save(flags);  /* FIXME: maybe only disable softirqs? */
-	pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb);
-	if (pampd == NULL) {
-		/* hmmm... must have been a flush while waiting */
-#ifdef RAMSTER_TESTING
-		pr_err("UNTESTED pampd==NULL in zcache_localify\n");
-#endif
-		if (ephemeral)
-			ramster_remote_eph_pages_unsucc_get++;
-		else
-			ramster_remote_pers_pages_unsucc_get++;
-		obj = NULL;
-		goto finish;
-	} else if (unlikely(!pampd_is_remote(pampd))) {
-		/* hmmm... must have been a dup put while waiting */
-#ifdef RAMSTER_TESTING
-		pr_err("UNTESTED dup while waiting in zcache_localify\n");
-#endif
-		if (ephemeral)
-			ramster_remote_eph_pages_unsucc_get++;
-		else
-			ramster_remote_pers_pages_unsucc_get++;
-		obj = NULL;
-		pampd = NULL;
-		ret = -EEXIST;
-		goto finish;
-	} else if (size == 0) {
-		/* no remote data, delete the local is_remote pampd */
-		pampd = NULL;
-		if (ephemeral)
-			ramster_remote_eph_pages_unsucc_get++;
-		else
-			BUG();
-		delete = true;
-		goto finish;
-	}
-	if (!ephemeral && pampd_is_intransit(pampd)) {
-		/* localify to zcache */
-		pampd = pampd_mask_intransit_and_remote(pampd);
-		zv_copy_to_pampd(pampd, data, size);
-	} else {
-		pampd = NULL;
-		obj = NULL;
-	}
-	if (extra != NULL) {
-		/* decompress direct-to-memory to complete remotify */
-		ret = lzo1x_decompress_safe((char *)data, size,
-						(char *)extra, &clen);
-		BUG_ON(ret != LZO_E_OK);
-		BUG_ON(clen != PAGE_SIZE);
-	}
-	if (ephemeral)
-		ramster_remote_eph_pages_succ_get++;
-	else
-		ramster_remote_pers_pages_succ_get++;
-	ret = 0;
-finish:
-	tmem_localify_finish(obj, index, pampd, saved_hb, delete);
-	zcache_put_pool(pool);
-	local_irq_restore(flags);
-out:
-	return ret;
-}
-
-/*
- * Called on a remote persistent tmem_get to attempt to preallocate
- * local storage for the data contained in the remote persistent page.
- * If successfully preallocated, returns the pampd, marked as remote and
- * in_transit.  Else returns NULL.  Note that the appropriate tmem data
- * structure must be locked.
- */
-static void *zcache_pampd_repatriate_preload(void *pampd,
-						struct tmem_pool *pool,
-						struct tmem_oid *oid,
-						uint32_t index,
-						bool *intransit)
-{
-	int clen = pampd_remote_size(pampd);
-	void *ret_pampd = NULL;
-	unsigned long flags;
-
-	if (!pampd_is_remote(pampd))
-		BUG();
-	if (is_ephemeral(pool))
-		BUG();
-	if (pampd_is_intransit(pampd)) {
-		/*
-		 * to avoid multiple allocations (and maybe a memory leak)
-		 * don't preallocate if already in the process of being
-		 * repatriated
-		 */
-		*intransit = true;
-		goto out;
-	}
-	*intransit = false;
-	local_irq_save(flags);
-	ret_pampd = (void *)zv_alloc(pool, oid, index, clen);
-	if (ret_pampd != NULL) {
-		/*
-		 *  a pampd is marked intransit if it is remote and space has
-		 *  been allocated for it locally (note, only happens for
-		 *  persistent pages, in which case the remote copy is freed)
-		 */
-		ret_pampd = pampd_mark_intransit(ret_pampd);
-		dec_and_check(&ramster_remote_pers_pages);
-	} else
-		ramster_pers_pages_remote_nomem++;
-	local_irq_restore(flags);
-out:
-	return ret_pampd;
-}
-
-/*
- * Called on a remote tmem_get to invoke a message to fetch the page.
- * Might sleep so no tmem locks can be held.  "extra" is passed
- * all the way through the round-trip messaging to zcache_localify.
- */
-static int zcache_pampd_repatriate(void *fake_pampd, void *real_pampd,
-				   struct tmem_pool *pool,
-				   struct tmem_oid *oid, uint32_t index,
-				   bool free, void *extra)
-{
-	struct tmem_xhandle xh;
-	int ret;
-
-	if (pampd_is_intransit(real_pampd))
-		/* have local space pre-reserved, so free remote copy */
-		free = true;
-	xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index);
-	/* unreliable request/response for now */
-	ret = ramster_remote_async_get(&xh, free,
-					pampd_remote_node(fake_pampd),
-					pampd_remote_size(fake_pampd),
-					pampd_remote_cksum(fake_pampd),
-					extra);
-#ifdef RAMSTER_TESTING
-	if (ret != 0 && ret != -ENOENT)
-		pr_err("TESTING zcache_pampd_repatriate returns, ret=%d\n",
-			ret);
-#endif
-	return ret;
+	if (!is_local_client(pool->client))
+		ramster_count_foreign_pages(is_ephemeral(pool), -1);
+	if (page)
+		zcache_free_page(page);
 }
 
 static struct tmem_pamops zcache_pamops = {
-	.create = zcache_pampd_create,
+	.create_finish = zcache_pampd_create_finish,
 	.get_data = zcache_pampd_get_data,
-	.free = zcache_pampd_free,
 	.get_data_and_free = zcache_pampd_get_data_and_free,
-	.free_obj = zcache_pampd_free_obj,
-	.is_remote = zcache_pampd_is_remote,
-	.repatriate_preload = zcache_pampd_repatriate_preload,
-	.repatriate = zcache_pampd_repatriate,
-	.new_obj = zcache_pampd_new_obj,
-	.replace_in_obj = zcache_pampd_replace_in_obj,
+	.free = zcache_pampd_free,
 };
 
 /*
  * zcache compression/decompression and related per-cpu stuff
  */
 
-#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
-#define LZO_DSTMEM_PAGE_ORDER 1
-static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
 static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
+#define ZCACHE_DSTMEM_ORDER 1
 
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
+static void zcache_compress(struct page *from, void **out_va, unsigned *out_len)
 {
-	int ret = 0;
+	int ret;
 	unsigned char *dmem = __get_cpu_var(zcache_dstmem);
-	unsigned char *wmem = __get_cpu_var(zcache_workmem);
 	char *from_va;
 
 	BUG_ON(!irqs_disabled());
-	if (unlikely(dmem == NULL || wmem == NULL))
-		goto out;  /* no buffer, so can't compress */
+	/* no buffer or no compressor so can't compress */
+	BUG_ON(dmem == NULL);
+	*out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER;
 	from_va = kmap_atomic(from);
 	mb();
-	ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
-	BUG_ON(ret != LZO_E_OK);
+	ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem,
+				out_len);
+	BUG_ON(ret);
 	*out_va = dmem;
 	kunmap_atomic(from_va);
-	ret = 1;
-out:
-	return ret;
 }
 
+static int zcache_comp_cpu_up(int cpu)
+{
+	struct crypto_comp *tfm;
+
+	tfm = crypto_alloc_comp(zcache_comp_name, 0, 0);
+	if (IS_ERR(tfm))
+		return NOTIFY_BAD;
+	*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm;
+	return NOTIFY_OK;
+}
+
+static void zcache_comp_cpu_down(int cpu)
+{
+	struct crypto_comp *tfm;
+
+	tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu);
+	crypto_free_comp(tfm);
+	*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL;
+}
 
 static int zcache_cpu_notifier(struct notifier_block *nb,
 				unsigned long action, void *pcpu)
 {
-	int cpu = (long)pcpu;
+	int ret, i, cpu = (long)pcpu;
 	struct zcache_preload *kp;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+		ret = zcache_comp_cpu_up(cpu);
+		if (ret != NOTIFY_OK) {
+			pr_err("%s: can't allocate compressor xform\n",
+				namestr);
+			return ret;
+		}
 		per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
-			GFP_KERNEL | __GFP_REPEAT,
-			LZO_DSTMEM_PAGE_ORDER),
-		per_cpu(zcache_workmem, cpu) =
-			kzalloc(LZO1X_MEM_COMPRESS,
-				GFP_KERNEL | __GFP_REPEAT);
-		per_cpu(zcache_remoteputmem, cpu) =
-			kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
+			GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER);
+		if (ramster_enabled)
+			ramster_cpu_up(cpu);
 		break;
 	case CPU_DEAD:
 	case CPU_UP_CANCELED:
-		kfree(per_cpu(zcache_remoteputmem, cpu));
-		per_cpu(zcache_remoteputmem, cpu) = NULL;
+		zcache_comp_cpu_down(cpu);
 		free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
-				LZO_DSTMEM_PAGE_ORDER);
+			ZCACHE_DSTMEM_ORDER);
 		per_cpu(zcache_dstmem, cpu) = NULL;
-		kfree(per_cpu(zcache_workmem, cpu));
-		per_cpu(zcache_workmem, cpu) = NULL;
 		kp = &per_cpu(zcache_preloads, cpu);
-		while (kp->nr) {
-			kmem_cache_free(zcache_objnode_cache,
-					kp->objnodes[kp->nr - 1]);
-			kp->objnodes[kp->nr - 1] = NULL;
-			kp->nr--;
+		for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
+			if (kp->objnodes[i])
+				kmem_cache_free(zcache_objnode_cache,
+						kp->objnodes[i]);
 		}
 		if (kp->obj) {
 			kmem_cache_free(zcache_obj_cache, kp->obj);
 			kp->obj = NULL;
 		}
-		if (kp->flnode) {
-			kmem_cache_free(ramster_flnode_cache, kp->flnode);
-			kp->flnode = NULL;
-		}
-		if (kp->page) {
-			free_page((unsigned long)kp->page);
-			kp->page = NULL;
-		}
+		if (ramster_enabled)
+			ramster_cpu_down(cpu);
 		break;
 	default:
 		break;
@@ -2271,314 +942,104 @@
 	.notifier_call = zcache_cpu_notifier
 };
 
-#ifdef CONFIG_SYSFS
-#define ZCACHE_SYSFS_RO(_name) \
-	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-		return sprintf(buf, "%lu\n", zcache_##_name); \
-	} \
-	static struct kobj_attribute zcache_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = zcache_##_name##_show, \
-	}
+/*
+ * The following code interacts with the zbud eviction and zbud
+ * zombify code to access LRU pages
+ */
 
-#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
-	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-	    return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
-	} \
-	static struct kobj_attribute zcache_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = zcache_##_name##_show, \
-	}
-
-#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
-	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-	    return _func(buf); \
-	} \
-	static struct kobj_attribute zcache_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = zcache_##_name##_show, \
-	}
-
-ZCACHE_SYSFS_RO(curr_obj_count_max);
-ZCACHE_SYSFS_RO(curr_objnode_count_max);
-ZCACHE_SYSFS_RO(flush_total);
-ZCACHE_SYSFS_RO(flush_found);
-ZCACHE_SYSFS_RO(flobj_total);
-ZCACHE_SYSFS_RO(flobj_found);
-ZCACHE_SYSFS_RO(failed_eph_puts);
-ZCACHE_SYSFS_RO(nonactive_puts);
-ZCACHE_SYSFS_RO(failed_pers_puts);
-ZCACHE_SYSFS_RO(zbud_curr_zbytes);
-ZCACHE_SYSFS_RO(zbud_cumul_zpages);
-ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
-ZCACHE_SYSFS_RO(zbud_buddied_count);
-ZCACHE_SYSFS_RO(evicted_raw_pages);
-ZCACHE_SYSFS_RO(evicted_unbuddied_pages);
-ZCACHE_SYSFS_RO(evicted_buddied_pages);
-ZCACHE_SYSFS_RO(failed_get_free_pages);
-ZCACHE_SYSFS_RO(failed_alloc);
-ZCACHE_SYSFS_RO(put_to_flush);
-ZCACHE_SYSFS_RO(compress_poor);
-ZCACHE_SYSFS_RO(mean_compress_poor);
-ZCACHE_SYSFS_RO(policy_percent_exceeded);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
-ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
-ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
-			zbud_show_unbuddied_list_counts);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
-			zbud_show_cumul_chunk_counts);
-ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts,
-			zv_curr_dist_counts_show);
-ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts,
-			zv_cumul_dist_counts_show);
-
-static struct attribute *zcache_attrs[] = {
-	&zcache_curr_obj_count_attr.attr,
-	&zcache_curr_obj_count_max_attr.attr,
-	&zcache_curr_objnode_count_attr.attr,
-	&zcache_curr_objnode_count_max_attr.attr,
-	&zcache_flush_total_attr.attr,
-	&zcache_flobj_total_attr.attr,
-	&zcache_flush_found_attr.attr,
-	&zcache_flobj_found_attr.attr,
-	&zcache_failed_eph_puts_attr.attr,
-	&zcache_nonactive_puts_attr.attr,
-	&zcache_failed_pers_puts_attr.attr,
-	&zcache_policy_percent_exceeded_attr.attr,
-	&zcache_compress_poor_attr.attr,
-	&zcache_mean_compress_poor_attr.attr,
-	&zcache_zbud_curr_raw_pages_attr.attr,
-	&zcache_zbud_curr_zpages_attr.attr,
-	&zcache_zbud_curr_zbytes_attr.attr,
-	&zcache_zbud_cumul_zpages_attr.attr,
-	&zcache_zbud_cumul_zbytes_attr.attr,
-	&zcache_zbud_buddied_count_attr.attr,
-	&zcache_evicted_raw_pages_attr.attr,
-	&zcache_evicted_unbuddied_pages_attr.attr,
-	&zcache_evicted_buddied_pages_attr.attr,
-	&zcache_failed_get_free_pages_attr.attr,
-	&zcache_failed_alloc_attr.attr,
-	&zcache_put_to_flush_attr.attr,
-	&zcache_zbud_unbuddied_list_counts_attr.attr,
-	&zcache_zbud_cumul_chunk_counts_attr.attr,
-	&zcache_zv_curr_dist_counts_attr.attr,
-	&zcache_zv_cumul_dist_counts_attr.attr,
-	&zcache_zv_max_zsize_attr.attr,
-	&zcache_zv_max_mean_zsize_attr.attr,
-	&zcache_zv_page_count_policy_percent_attr.attr,
-	NULL,
-};
-
-static struct attribute_group zcache_attr_group = {
-	.attrs = zcache_attrs,
-	.name = "zcache",
-};
-
-#define RAMSTER_SYSFS_RO(_name) \
-	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-		return sprintf(buf, "%lu\n", ramster_##_name); \
-	} \
-	static struct kobj_attribute ramster_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = ramster_##_name##_show, \
-	}
-
-#define RAMSTER_SYSFS_RW(_name) \
-	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-		return sprintf(buf, "%lu\n", ramster_##_name); \
-	} \
-	static ssize_t ramster_##_name##_store(struct kobject *kobj, \
-		struct kobj_attribute *attr, const char *buf, size_t count) \
-	{ \
-		int err; \
-		unsigned long enable; \
-		err = kstrtoul(buf, 10, &enable); \
-		if (err) \
-			return -EINVAL; \
-		ramster_##_name = enable; \
-		return count; \
-	} \
-	static struct kobj_attribute ramster_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0644 }, \
-		.show = ramster_##_name##_show, \
-		.store = ramster_##_name##_store, \
-	}
-
-#define RAMSTER_SYSFS_RO_ATOMIC(_name) \
-	static ssize_t ramster_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-	    return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \
-	} \
-	static struct kobj_attribute ramster_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = ramster_##_name##_show, \
-	}
-
-RAMSTER_SYSFS_RO(interface_revision);
-RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages);
-RAMSTER_SYSFS_RW(pers_remotify_enable);
-RAMSTER_SYSFS_RW(eph_remotify_enable);
-RAMSTER_SYSFS_RO(eph_pages_remoted);
-RAMSTER_SYSFS_RO(eph_pages_remote_failed);
-RAMSTER_SYSFS_RO(pers_pages_remoted);
-RAMSTER_SYSFS_RO(pers_pages_remote_failed);
-RAMSTER_SYSFS_RO(pers_pages_remote_nomem);
-RAMSTER_SYSFS_RO(remote_pages_flushed);
-RAMSTER_SYSFS_RO(remote_page_flushes_failed);
-RAMSTER_SYSFS_RO(remote_objects_flushed);
-RAMSTER_SYSFS_RO(remote_object_flushes_failed);
-RAMSTER_SYSFS_RO(remote_eph_pages_succ_get);
-RAMSTER_SYSFS_RO(remote_eph_pages_unsucc_get);
-RAMSTER_SYSFS_RO(remote_pers_pages_succ_get);
-RAMSTER_SYSFS_RO(remote_pers_pages_unsucc_get);
-RAMSTER_SYSFS_RO_ATOMIC(foreign_eph_pampd_count);
-RAMSTER_SYSFS_RO(foreign_eph_pampd_count_max);
-RAMSTER_SYSFS_RO_ATOMIC(foreign_pers_pampd_count);
-RAMSTER_SYSFS_RO(foreign_pers_pampd_count_max);
-RAMSTER_SYSFS_RO_ATOMIC(curr_flnode_count);
-RAMSTER_SYSFS_RO(curr_flnode_count_max);
-
-#define MANUAL_NODES 8
-static bool ramster_nodes_manual_up[MANUAL_NODES];
-static ssize_t ramster_manual_node_up_show(struct kobject *kobj,
-				struct kobj_attribute *attr, char *buf)
+static struct page *zcache_evict_eph_pageframe(void)
 {
-	int i;
-	char *p = buf;
-	for (i = 0; i < MANUAL_NODES; i++)
-		if (ramster_nodes_manual_up[i])
-			p += sprintf(p, "%d ", i);
-	p += sprintf(p, "\n");
-	return p - buf;
+	struct page *page;
+	unsigned int zsize = 0, zpages = 0;
+
+	page = zbud_evict_pageframe_lru(&zsize, &zpages);
+	if (page == NULL)
+		goto out;
+	zcache_eph_zbytes = atomic_long_sub_return(zsize,
+					&zcache_eph_zbytes_atomic);
+	zcache_eph_zpages = atomic_sub_return(zpages,
+					&zcache_eph_zpages_atomic);
+	zcache_evicted_eph_zpages++;
+	zcache_eph_pageframes =
+		atomic_dec_return(&zcache_eph_pageframes_atomic);
+	zcache_evicted_eph_pageframes++;
+out:
+	return page;
 }
 
-static ssize_t ramster_manual_node_up_store(struct kobject *kobj,
-		struct kobj_attribute *attr, const char *buf, size_t count)
+#ifdef FRONTSWAP_HAS_UNUSE
+static void unswiz(struct tmem_oid oid, u32 index,
+				unsigned *type, pgoff_t *offset);
+
+/*
+ *  Choose an LRU persistent pageframe and attempt to "unuse" it by
+ *  calling frontswap_unuse on both zpages.
+ *
+ *  This is work-in-progress.
+ */
+
+static int zcache_frontswap_unuse(void)
 {
-	int err;
-	unsigned long node_num;
+	struct tmem_handle th[2];
+	int ret = -ENOMEM;
+	int nzbuds, unuse_ret;
+	unsigned type;
+	struct page *newpage1 = NULL, *newpage2 = NULL;
+	struct page *evictpage1 = NULL, *evictpage2 = NULL;
+	pgoff_t offset;
 
-	err = kstrtoul(buf, 10, &node_num);
-	if (err) {
-		pr_err("ramster: bad strtoul?\n");
-		return -EINVAL;
+	newpage1 = alloc_page(ZCACHE_GFP_MASK);
+	newpage2 = alloc_page(ZCACHE_GFP_MASK);
+	if (newpage1 == NULL)
+		evictpage1 = zcache_evict_eph_pageframe();
+	if (newpage2 == NULL)
+		evictpage2 = zcache_evict_eph_pageframe();
+	if (evictpage1 == NULL || evictpage2 == NULL)
+		goto free_and_out;
+	/* ok, we have two pages pre-allocated */
+	nzbuds = zbud_make_zombie_lru(&th[0], NULL, NULL, false);
+	if (nzbuds == 0) {
+		ret = -ENOENT;
+		goto free_and_out;
 	}
-	if (node_num >= MANUAL_NODES) {
-		pr_err("ramster: bad node_num=%lu?\n", node_num);
-		return -EINVAL;
+	unswiz(th[0].oid, th[0].index, &type, &offset);
+	unuse_ret = frontswap_unuse(type, offset,
+				newpage1 != NULL ? newpage1 : evictpage1,
+				ZCACHE_GFP_MASK);
+	if (unuse_ret != 0)
+		goto free_and_out;
+	else if (evictpage1 != NULL)
+		zcache_unacct_page();
+	newpage1 = NULL;
+	evictpage1 = NULL;
+	if (nzbuds == 2) {
+		unswiz(th[1].oid, th[1].index, &type, &offset);
+		unuse_ret = frontswap_unuse(type, offset,
+				newpage2 != NULL ? newpage2 : evictpage2,
+				ZCACHE_GFP_MASK);
+		if (unuse_ret != 0) {
+			goto free_and_out;
+		} else if (evictpage2 != NULL) {
+			zcache_unacct_page();
+		}
 	}
-	if (ramster_nodes_manual_up[node_num]) {
-		pr_err("ramster: node %d already up, ignoring\n",
-							(int)node_num);
-	} else {
-		ramster_nodes_manual_up[node_num] = true;
-		r2net_hb_node_up_manual((int)node_num);
-	}
-	return count;
+	ret = 0;
+	goto out;
+
+free_and_out:
+	if (newpage1 != NULL)
+		__free_page(newpage1);
+	if (newpage2 != NULL)
+		__free_page(newpage2);
+	if (evictpage1 != NULL)
+		zcache_free_page(evictpage1);
+	if (evictpage2 != NULL)
+		zcache_free_page(evictpage2);
+out:
+	return ret;
 }
+#endif
 
-static struct kobj_attribute ramster_manual_node_up_attr = {
-	.attr = { .name = "manual_node_up", .mode = 0644 },
-	.show = ramster_manual_node_up_show,
-	.store = ramster_manual_node_up_store,
-};
-
-static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj,
-				struct kobj_attribute *attr, char *buf)
-{
-	if (ramster_remote_target_nodenum == -1UL)
-		return sprintf(buf, "unset\n");
-	else
-		return sprintf(buf, "%d\n", ramster_remote_target_nodenum);
-}
-
-static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj,
-		struct kobj_attribute *attr, const char *buf, size_t count)
-{
-	int err;
-	unsigned long node_num;
-
-	err = kstrtoul(buf, 10, &node_num);
-	if (err) {
-		pr_err("ramster: bad strtoul?\n");
-		return -EINVAL;
-	} else if (node_num == -1UL) {
-		pr_err("ramster: disabling all remotification, "
-			"data may still reside on remote nodes however\n");
-		return -EINVAL;
-	} else if (node_num >= MANUAL_NODES) {
-		pr_err("ramster: bad node_num=%lu?\n", node_num);
-		return -EINVAL;
-	} else if (!ramster_nodes_manual_up[node_num]) {
-		pr_err("ramster: node %d not up, ignoring setting "
-			"of remotification target\n", (int)node_num);
-	} else if (r2net_remote_target_node_set((int)node_num) >= 0) {
-		pr_info("ramster: node %d set as remotification target\n",
-				(int)node_num);
-		ramster_remote_target_nodenum = (int)node_num;
-	} else {
-		pr_err("ramster: bad num to node node_num=%d?\n",
-				(int)node_num);
-		return -EINVAL;
-	}
-	return count;
-}
-
-static struct kobj_attribute ramster_remote_target_nodenum_attr = {
-	.attr = { .name = "remote_target_nodenum", .mode = 0644 },
-	.show = ramster_remote_target_nodenum_show,
-	.store = ramster_remote_target_nodenum_store,
-};
-
-
-static struct attribute *ramster_attrs[] = {
-	&ramster_interface_revision_attr.attr,
-	&ramster_pers_remotify_enable_attr.attr,
-	&ramster_eph_remotify_enable_attr.attr,
-	&ramster_remote_pers_pages_attr.attr,
-	&ramster_eph_pages_remoted_attr.attr,
-	&ramster_eph_pages_remote_failed_attr.attr,
-	&ramster_pers_pages_remoted_attr.attr,
-	&ramster_pers_pages_remote_failed_attr.attr,
-	&ramster_pers_pages_remote_nomem_attr.attr,
-	&ramster_remote_pages_flushed_attr.attr,
-	&ramster_remote_page_flushes_failed_attr.attr,
-	&ramster_remote_objects_flushed_attr.attr,
-	&ramster_remote_object_flushes_failed_attr.attr,
-	&ramster_remote_eph_pages_succ_get_attr.attr,
-	&ramster_remote_eph_pages_unsucc_get_attr.attr,
-	&ramster_remote_pers_pages_succ_get_attr.attr,
-	&ramster_remote_pers_pages_unsucc_get_attr.attr,
-	&ramster_foreign_eph_pampd_count_attr.attr,
-	&ramster_foreign_eph_pampd_count_max_attr.attr,
-	&ramster_foreign_pers_pampd_count_attr.attr,
-	&ramster_foreign_pers_pampd_count_max_attr.attr,
-	&ramster_curr_flnode_count_attr.attr,
-	&ramster_curr_flnode_count_max_attr.attr,
-	&ramster_manual_node_up_attr.attr,
-	&ramster_remote_target_nodenum_attr.attr,
-	NULL,
-};
-
-static struct attribute_group ramster_attr_group = {
-	.attrs = ramster_attrs,
-	.name = "ramster",
-};
-
-#endif /* CONFIG_SYSFS */
 /*
  * When zcache is disabled ("frozen"), pools can be created and destroyed,
  * but all puts (and thus all other operations that require memory allocation)
@@ -2589,23 +1050,74 @@
 static bool zcache_freeze;
 
 /*
- * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
+ * This zcache shrinker interface reduces the number of ephemeral pageframes
+ * used by zcache to approximately the same as the total number of LRU_FILE
+ * pageframes in use.
  */
 static int shrink_zcache_memory(struct shrinker *shrink,
 				struct shrink_control *sc)
 {
+	static bool in_progress;
 	int ret = -1;
 	int nr = sc->nr_to_scan;
-	gfp_t gfp_mask = sc->gfp_mask;
+	int nr_evict = 0;
+	int nr_unuse = 0;
+	struct page *page;
+#ifdef FRONTSWAP_HAS_UNUSE
+	int unuse_ret;
+#endif
 
-	if (nr >= 0) {
-		if (!(gfp_mask & __GFP_FS))
-			/* does this case really need to be skipped? */
-			goto out;
-		zbud_evict_pages(nr);
+	if (nr <= 0)
+		goto skip_evict;
+
+	/* don't allow more than one eviction thread at a time */
+	if (in_progress)
+		goto skip_evict;
+
+	in_progress = true;
+
+	/* we are going to ignore nr, and target a different value */
+	zcache_last_active_file_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
+	zcache_last_inactive_file_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
+	nr_evict = zcache_eph_pageframes - zcache_last_active_file_pageframes +
+		zcache_last_inactive_file_pageframes;
+	while (nr_evict-- > 0) {
+		page = zcache_evict_eph_pageframe();
+		if (page == NULL)
+			break;
+		zcache_free_page(page);
 	}
-	ret = (int)atomic_read(&zcache_zbud_curr_raw_pages);
-out:
+
+	zcache_last_active_anon_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_ACTIVE_ANON);
+	zcache_last_inactive_anon_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_INACTIVE_ANON);
+	nr_unuse = zcache_pers_pageframes - zcache_last_active_anon_pageframes +
+		zcache_last_inactive_anon_pageframes;
+#ifdef FRONTSWAP_HAS_UNUSE
+	/* rate limit for testing */
+	if (nr_unuse > 32)
+		nr_unuse = 32;
+	while (nr_unuse-- > 0) {
+		unuse_ret = zcache_frontswap_unuse();
+		if (unuse_ret == -ENOMEM)
+			break;
+	}
+#endif
+	in_progress = false;
+
+skip_evict:
+	/* resample: has changed, but maybe not all the way yet */
+	zcache_last_active_file_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
+	zcache_last_inactive_file_pageframes =
+		global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
+	ret = zcache_eph_pageframes - zcache_last_active_file_pageframes +
+		zcache_last_inactive_file_pageframes;
+	if (ret < 0)
+		ret = 0;
 	return ret;
 }
 
@@ -2618,30 +1130,46 @@
  * zcache shims between cleancache/frontswap ops and tmem
  */
 
-int zcache_put(int cli_id, int pool_id, struct tmem_oid *oidp,
-			uint32_t index, char *data, size_t size,
-			bool raw, int ephemeral)
+/* FIXME rename these core routines to zcache_tmemput etc? */
+int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+				uint32_t index, void *page,
+				unsigned int size, bool raw, int ephemeral)
 {
 	struct tmem_pool *pool;
+	struct tmem_handle th;
 	int ret = -1;
+	void *pampd = NULL;
 
 	BUG_ON(!irqs_disabled());
 	pool = zcache_get_pool_by_id(cli_id, pool_id);
 	if (unlikely(pool == NULL))
 		goto out;
-	if (!zcache_freeze && zcache_do_preload(pool) == 0) {
-		/* preload does preempt_disable on success */
-		ret = tmem_put(pool, oidp, index, data, size, raw, ephemeral);
-		if (ret < 0) {
-			if (is_ephemeral(pool))
+	if (!zcache_freeze) {
+		ret = 0;
+		th.client_id = cli_id;
+		th.pool_id = pool_id;
+		th.oid = *oidp;
+		th.index = index;
+		pampd = zcache_pampd_create((char *)page, size, raw,
+				ephemeral, &th);
+		if (pampd == NULL) {
+			ret = -ENOMEM;
+			if (ephemeral)
 				zcache_failed_eph_puts++;
 			else
 				zcache_failed_pers_puts++;
+		} else {
+			if (ramster_enabled)
+				ramster_do_preload_flnode(pool);
+			ret = tmem_put(pool, oidp, index, 0, pampd);
+			if (ret < 0)
+				BUG();
 		}
 		zcache_put_pool(pool);
-		preempt_enable_no_resched();
 	} else {
 		zcache_put_to_flush++;
+		if (ramster_enabled)
+			ramster_do_preload_flnode(pool);
 		if (atomic_read(&pool->obj_count) > 0)
 			/* the put fails whether the flush succeeds or not */
 			(void)tmem_flush_page(pool, oidp, index);
@@ -2651,9 +1179,9 @@
 	return ret;
 }
 
-int zcache_get(int cli_id, int pool_id, struct tmem_oid *oidp,
-			uint32_t index, char *data, size_t *sizep,
-			bool raw, int get_and_free)
+int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+				uint32_t index, void *page,
+				size_t *sizep, bool raw, int get_and_free)
 {
 	struct tmem_pool *pool;
 	int ret = -1;
@@ -2667,22 +1195,21 @@
 	eph = is_ephemeral(pool);
 	if (likely(pool != NULL)) {
 		if (atomic_read(&pool->obj_count) > 0)
-			ret = tmem_get(pool, oidp, index, data, sizep,
-					raw, get_and_free);
+			ret = tmem_get(pool, oidp, index, (char *)(page),
+					sizep, raw, get_and_free);
 		zcache_put_pool(pool);
 	}
-	WARN_ONCE((!eph && (ret != 0)), "zcache_get fails on persistent pool, "
-			  "bad things are very likely to happen soon\n");
+	WARN_ONCE((!is_ephemeral(pool) && (ret != 0)),
+			"zcache_get fails on persistent pool, "
+			"bad things are very likely to happen soon\n");
 #ifdef RAMSTER_TESTING
 	if (ret != 0 && ret != -1 && !(ret == -EINVAL && is_ephemeral(pool)))
 		pr_err("TESTING zcache_get tmem_get returns ret=%d\n", ret);
 #endif
-	if (ret == -EAGAIN)
-		BUG(); /* FIXME... don't need this anymore??? let's ensure */
 	return ret;
 }
 
-int zcache_flush(int cli_id, int pool_id,
+int zcache_flush_page(int cli_id, int pool_id,
 				struct tmem_oid *oidp, uint32_t index)
 {
 	struct tmem_pool *pool;
@@ -2692,7 +1219,8 @@
 	local_irq_save(flags);
 	zcache_flush_total++;
 	pool = zcache_get_pool_by_id(cli_id, pool_id);
-	ramster_do_preload_flnode_only(pool);
+	if (ramster_enabled)
+		ramster_do_preload_flnode(pool);
 	if (likely(pool != NULL)) {
 		if (atomic_read(&pool->obj_count) > 0)
 			ret = tmem_flush_page(pool, oidp, index);
@@ -2704,7 +1232,8 @@
 	return ret;
 }
 
-int zcache_flush_object(int cli_id, int pool_id, struct tmem_oid *oidp)
+int zcache_flush_object(int cli_id, int pool_id,
+				struct tmem_oid *oidp)
 {
 	struct tmem_pool *pool;
 	int ret = -1;
@@ -2713,7 +1242,8 @@
 	local_irq_save(flags);
 	zcache_flobj_total++;
 	pool = zcache_get_pool_by_id(cli_id, pool_id);
-	ramster_do_preload_flnode_only(pool);
+	if (ramster_enabled)
+		ramster_do_preload_flnode(pool);
 	if (likely(pool != NULL)) {
 		if (atomic_read(&pool->obj_count) > 0)
 			ret = tmem_flush_object(pool, oidp);
@@ -2725,7 +1255,7 @@
 	return ret;
 }
 
-int zcache_client_destroy_pool(int cli_id, int pool_id)
+static int zcache_client_destroy_pool(int cli_id, int pool_id)
 {
 	struct tmem_pool *pool = NULL;
 	struct zcache_client *cli = NULL;
@@ -2752,16 +1282,15 @@
 	ret = tmem_destroy_pool(pool);
 	local_bh_enable();
 	kfree(pool);
-	pr_info("ramster: destroyed pool id=%d cli_id=%d\n", pool_id, cli_id);
+	if (cli_id == LOCAL_CLIENT)
+		pr_info("%s: destroyed local pool id=%d\n", namestr, pool_id);
+	else
+		pr_info("%s: destroyed pool id=%d, client=%d\n",
+				namestr, pool_id, cli_id);
 out:
 	return ret;
 }
 
-static int zcache_destroy_pool(int pool_id)
-{
-	return zcache_client_destroy_pool(LOCAL_CLIENT, pool_id);
-}
-
 int zcache_new_pool(uint16_t cli_id, uint32_t flags)
 {
 	int poolid = -1;
@@ -2777,7 +1306,7 @@
 	atomic_inc(&cli->refcount);
 	pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC);
 	if (pool == NULL) {
-		pr_info("ramster: pool creation failed: out of memory\n");
+		pr_info("%s: pool creation failed: out of memory\n", namestr);
 		goto out;
 	}
 
@@ -2785,7 +1314,7 @@
 		if (cli->tmem_pools[poolid] == NULL)
 			break;
 	if (poolid >= MAX_POOLS_PER_CLIENT) {
-		pr_info("ramster: pool creation failed: max exceeded\n");
+		pr_info("%s: pool creation failed: max exceeded\n", namestr);
 		kfree(pool);
 		poolid = -1;
 		goto out;
@@ -2796,11 +1325,11 @@
 	tmem_new_pool(pool, flags);
 	cli->tmem_pools[poolid] = pool;
 	if (cli_id == LOCAL_CLIENT)
-		pr_info("ramster: created %s tmem pool, id=%d, local client\n",
+		pr_info("%s: created %s local tmem pool, id=%d\n", namestr,
 			flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
 			poolid);
 	else
-		pr_info("ramster: created %s tmem pool, id=%d, client=%d\n",
+		pr_info("%s: created %s tmem pool, id=%d, client=%d\n", namestr,
 			flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
 			poolid, cli_id);
 out:
@@ -2814,30 +1343,37 @@
 	return zcache_new_pool(LOCAL_CLIENT, flags);
 }
 
-int zcache_autocreate_pool(int cli_id, int pool_id, bool ephemeral)
+int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph)
 {
 	struct tmem_pool *pool;
-	struct zcache_client *cli = NULL;
-	uint32_t flags = ephemeral ? 0 : TMEM_POOL_PERSIST;
+	struct zcache_client *cli;
+	uint32_t flags = eph ? 0 : TMEM_POOL_PERSIST;
 	int ret = -1;
 
+	BUG_ON(!ramster_enabled);
 	if (cli_id == LOCAL_CLIENT)
 		goto out;
 	if (pool_id >= MAX_POOLS_PER_CLIENT)
 		goto out;
-	else if ((unsigned int)cli_id < MAX_CLIENTS)
-		cli = &zcache_clients[cli_id];
-	if ((ephemeral && !use_cleancache) || (!ephemeral && !use_frontswap))
-		BUG(); /* FIXME, handle more gracefully later */
+	if (cli_id >= MAX_CLIENTS)
+		goto out;
+
+	cli = &zcache_clients[cli_id];
+	if ((eph && disable_cleancache) || (!eph && disable_frontswap)) {
+		pr_err("zcache_autocreate_pool: pool type disabled\n");
+		goto out;
+	}
 	if (!cli->allocated) {
-		if (zcache_new_client(cli_id))
-			BUG(); /* FIXME, handle more gracefully later */
+		if (zcache_new_client(cli_id)) {
+			pr_err("zcache_autocreate_pool: can't create client\n");
+			goto out;
+		}
 		cli = &zcache_clients[cli_id];
 	}
 	atomic_inc(&cli->refcount);
 	pool = cli->tmem_pools[pool_id];
 	if (pool != NULL) {
-		if (pool->persistent && ephemeral) {
+		if (pool->persistent && eph) {
 			pr_err("zcache_autocreate_pool: type mismatch\n");
 			goto out;
 		}
@@ -2846,7 +1382,7 @@
 	}
 	pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
 	if (pool == NULL) {
-		pr_info("ramster: pool creation failed: out of memory\n");
+		pr_info("%s: pool creation failed: out of memory\n", namestr);
 		goto out;
 	}
 	atomic_set(&pool->refcount, 0);
@@ -2854,14 +1390,11 @@
 	pool->pool_id = pool_id;
 	tmem_new_pool(pool, flags);
 	cli->tmem_pools[pool_id] = pool;
-	pr_info("ramster: AUTOcreated %s tmem poolid=%d, for remote client=%d\n",
-		flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+	pr_info("%s: AUTOcreated %s tmem poolid=%d, for remote client=%d\n",
+		namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
 		pool_id, cli_id);
 	ret = 0;
 out:
-	if (cli == NULL)
-		BUG(); /* FIXME, handle more gracefully later */
-		/* pr_err("zcache_autocreate_pool: failed\n"); */
 	if (cli != NULL)
 		atomic_dec(&cli->refcount);
 	return ret;
@@ -2875,7 +1408,6 @@
  * to translate in-kernel semantics to zcache semantics.
  */
 
-#ifdef CONFIG_CLEANCACHE
 static void zcache_cleancache_put_page(int pool_id,
 					struct cleancache_filekey key,
 					pgoff_t index, struct page *page)
@@ -2883,18 +1415,13 @@
 	u32 ind = (u32) index;
 	struct tmem_oid oid = *(struct tmem_oid *)&key;
 
-#ifdef __PG_WAS_ACTIVE
-	if (!PageWasActive(page)) {
-		zcache_nonactive_puts++;
+	if (!disable_cleancache_ignore_nonactive && !PageWasActive(page)) {
+		zcache_eph_nonactive_puts_ignored++;
 		return;
 	}
-#endif
-	if (likely(ind == index)) {
-		char *kva = page_address(page);
-
-		(void)zcache_put(LOCAL_CLIENT, pool_id, &oid, index,
-			kva, PAGE_SIZE, 0, 1);
-	}
+	if (likely(ind == index))
+		(void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index,
+					page, PAGE_SIZE, false, 1);
 }
 
 static int zcache_cleancache_get_page(int pool_id,
@@ -2903,21 +1430,16 @@
 {
 	u32 ind = (u32) index;
 	struct tmem_oid oid = *(struct tmem_oid *)&key;
+	size_t size;
 	int ret = -1;
 
-	preempt_disable();
 	if (likely(ind == index)) {
-		char *kva = page_address(page);
-		size_t size = PAGE_SIZE;
-
-		ret = zcache_get(LOCAL_CLIENT, pool_id, &oid, index,
-			kva, &size, 0, 0);
-#ifdef __PG_WAS_ACTIVE
+		ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index,
+					page, &size, false, 0);
+		BUG_ON(ret >= 0 && size != PAGE_SIZE);
 		if (ret == 0)
 			SetPageWasActive(page);
-#endif
 	}
-	preempt_enable();
 	return ret;
 }
 
@@ -2929,7 +1451,7 @@
 	struct tmem_oid oid = *(struct tmem_oid *)&key;
 
 	if (likely(ind == index))
-		(void)zcache_flush(LOCAL_CLIENT, pool_id, &oid, ind);
+		(void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
 }
 
 static void zcache_cleancache_flush_inode(int pool_id,
@@ -2943,7 +1465,7 @@
 static void zcache_cleancache_flush_fs(int pool_id)
 {
 	if (pool_id >= 0)
-		(void)zcache_destroy_pool(pool_id);
+		(void)zcache_client_destroy_pool(LOCAL_CLIENT, pool_id);
 }
 
 static int zcache_cleancache_init_fs(size_t pagesize)
@@ -2980,15 +1502,15 @@
 
 	return old_ops;
 }
-#endif
 
-#ifdef CONFIG_FRONTSWAP
 /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int zcache_frontswap_poolid = -1;
+static int zcache_frontswap_poolid __read_mostly = -1;
 
 /*
  * Swizzling increases objects per swaptype, increasing tmem concurrency
  * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
+ * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from
+ * frontswap_get_page(), but has side-effects. Hence using 8.
  */
 #define SWIZ_BITS		8
 #define SWIZ_MASK		((1 << SWIZ_BITS) - 1)
@@ -3002,47 +1524,64 @@
 	return oid;
 }
 
-static int zcache_frontswap_store(unsigned type, pgoff_t offset,
-				   struct page *page)
+#ifdef FRONTSWAP_HAS_UNUSE
+static void unswiz(struct tmem_oid oid, u32 index,
+				unsigned *type, pgoff_t *offset)
+{
+	*type = (unsigned)(oid.oid[0] >> SWIZ_BITS);
+	*offset = (pgoff_t)((index << SWIZ_BITS) |
+			(oid.oid[0] & SWIZ_MASK));
+}
+#endif
+
+static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
+					struct page *page)
 {
 	u64 ind64 = (u64)offset;
 	u32 ind = (u32)offset;
 	struct tmem_oid oid = oswiz(type, ind);
 	int ret = -1;
 	unsigned long flags;
-	char *kva;
 
 	BUG_ON(!PageLocked(page));
+	if (!disable_frontswap_ignore_nonactive && !PageWasActive(page)) {
+		zcache_pers_nonactive_puts_ignored++;
+		ret = -ERANGE;
+		goto out;
+	}
 	if (likely(ind64 == ind)) {
 		local_irq_save(flags);
-		kva = page_address(page);
-		ret = zcache_put(LOCAL_CLIENT, zcache_frontswap_poolid,
-				&oid, iswiz(ind), kva, PAGE_SIZE, 0, 0);
+		ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid,
+					&oid, iswiz(ind),
+					page, PAGE_SIZE, false, 0);
 		local_irq_restore(flags);
 	}
+out:
 	return ret;
 }
 
 /* returns 0 if the page was successfully gotten from frontswap, -1 if
  * was not present (should never happen!) */
-static int zcache_frontswap_load(unsigned type, pgoff_t offset,
-				   struct page *page)
+static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,
+					struct page *page)
 {
 	u64 ind64 = (u64)offset;
 	u32 ind = (u32)offset;
 	struct tmem_oid oid = oswiz(type, ind);
-	int ret = -1;
+	size_t size;
+	int ret = -1, get_and_free;
 
-	preempt_disable(); /* FIXME, remove this? */
+	if (frontswap_has_exclusive_gets)
+		get_and_free = 1;
+	else
+		get_and_free = -1;
 	BUG_ON(!PageLocked(page));
 	if (likely(ind64 == ind)) {
-		char *kva = page_address(page);
-		size_t size = PAGE_SIZE;
-
-		ret = zcache_get(LOCAL_CLIENT, zcache_frontswap_poolid,
-					&oid, iswiz(ind), kva, &size, 0, -1);
+		ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid,
+					&oid, iswiz(ind),
+					page, &size, false, get_and_free);
+		BUG_ON(ret >= 0 && size != PAGE_SIZE);
 	}
-	preempt_enable(); /* FIXME, remove this? */
 	return ret;
 }
 
@@ -3054,7 +1593,7 @@
 	struct tmem_oid oid = oswiz(type, ind);
 
 	if (likely(ind64 == ind))
-		(void)zcache_flush(LOCAL_CLIENT, zcache_frontswap_poolid,
+		(void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid,
 					&oid, iswiz(ind));
 }
 
@@ -3076,12 +1615,12 @@
 	/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
 	if (zcache_frontswap_poolid < 0)
 		zcache_frontswap_poolid =
-				zcache_local_new_pool(TMEM_POOL_PERSIST);
+			zcache_local_new_pool(TMEM_POOL_PERSIST);
 }
 
 static struct frontswap_ops zcache_frontswap_ops = {
-	.store = zcache_frontswap_store,
-	.load = zcache_frontswap_load,
+	.store = zcache_frontswap_put_page,
+	.load = zcache_frontswap_get_page,
 	.invalidate_page = zcache_frontswap_flush_page,
 	.invalidate_area = zcache_frontswap_flush_area,
 	.init = zcache_frontswap_init
@@ -3094,179 +1633,135 @@
 
 	return old_ops;
 }
-#endif
-
-/*
- * frontswap selfshrinking
- */
-
-#ifdef CONFIG_FRONTSWAP
-/* In HZ, controls frequency of worker invocation. */
-static unsigned int selfshrink_interval __read_mostly = 5;
-
-static void selfshrink_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
-
-/* Enable/disable with sysfs. */
-static bool frontswap_selfshrinking __read_mostly;
-
-/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink __initdata = true;
-
-/*
- * The default values for the following parameters were deemed reasonable
- * by experimentation, may be workload-dependent, and can all be
- * adjusted via sysfs.
- */
-
-/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
-static unsigned int frontswap_hysteresis __read_mostly = 20;
-
-/*
- * Number of selfshrink worker invocations to wait before observing that
- * frontswap selfshrinking should commence. Note that selfshrinking does
- * not use a separate worker thread.
- */
-static unsigned int frontswap_inertia __read_mostly = 3;
-
-/* Countdown to next invocation of frontswap_shrink() */
-static unsigned long frontswap_inertia_counter;
-
-/*
- * Invoked by the selfshrink worker thread, uses current number of pages
- * in frontswap (frontswap_curr_pages()), previous status, and control
- * values (hysteresis and inertia) to determine if frontswap should be
- * shrunk and what the new frontswap size should be.  Note that
- * frontswap_shrink is essentially a partial swapoff that immediately
- * transfers pages from the "swap device" (frontswap) back into kernel
- * RAM; despite the name, frontswap "shrinking" is very different from
- * the "shrinker" interface used by the kernel MM subsystem to reclaim
- * memory.
- */
-static void frontswap_selfshrink(void)
-{
-	static unsigned long cur_frontswap_pages;
-	static unsigned long last_frontswap_pages;
-	static unsigned long tgt_frontswap_pages;
-
-	last_frontswap_pages = cur_frontswap_pages;
-	cur_frontswap_pages = frontswap_curr_pages();
-	if (!cur_frontswap_pages ||
-			(cur_frontswap_pages > last_frontswap_pages)) {
-		frontswap_inertia_counter = frontswap_inertia;
-		return;
-	}
-	if (frontswap_inertia_counter && --frontswap_inertia_counter)
-		return;
-	if (cur_frontswap_pages <= frontswap_hysteresis)
-		tgt_frontswap_pages = 0;
-	else
-		tgt_frontswap_pages = cur_frontswap_pages -
-			(cur_frontswap_pages / frontswap_hysteresis);
-	frontswap_shrink(tgt_frontswap_pages);
-}
-
-static int __init ramster_nofrontswap_selfshrink_setup(char *s)
-{
-	use_frontswap_selfshrink = false;
-	return 1;
-}
-
-__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
-
-static void selfshrink_process(struct work_struct *work)
-{
-	if (frontswap_selfshrinking && frontswap_enabled) {
-		frontswap_selfshrink();
-		schedule_delayed_work(&selfshrink_worker,
-			selfshrink_interval * HZ);
-	}
-}
-
-static int ramster_enabled;
-
-static int __init ramster_selfshrink_init(void)
-{
-	frontswap_selfshrinking = ramster_enabled && use_frontswap_selfshrink;
-	if (frontswap_selfshrinking)
-		pr_info("ramster: Initializing frontswap "
-					"selfshrinking driver.\n");
-	else
-		return -ENODEV;
-
-	schedule_delayed_work(&selfshrink_worker, selfshrink_interval * HZ);
-
-	return 0;
-}
-
-subsys_initcall(ramster_selfshrink_init);
-#endif
 
 /*
  * zcache initialization
- * NOTE FOR NOW ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER OR
- * NOTHING HAPPENS!
+ * NOTE FOR NOW zcache or ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER
+ * OR NOTHING HAPPENS!
  */
 
-static int ramster_enabled;
+static int __init enable_zcache(char *s)
+{
+	zcache_enabled = 1;
+	return 1;
+}
+__setup("zcache", enable_zcache);
 
 static int __init enable_ramster(char *s)
 {
+	zcache_enabled = 1;
+#ifdef CONFIG_RAMSTER
 	ramster_enabled = 1;
+#endif
 	return 1;
 }
 __setup("ramster", enable_ramster);
 
 /* allow independent dynamic disabling of cleancache and frontswap */
 
-static int use_cleancache = 1;
-
 static int __init no_cleancache(char *s)
 {
-	pr_info("INIT no_cleancache called\n");
-	use_cleancache = 0;
+	disable_cleancache = 1;
 	return 1;
 }
 
-/*
- * FIXME: need to guarantee this gets checked before zcache_init is called
- * What is the correct way to achieve this?
- */
-early_param("nocleancache", no_cleancache);
-
-static int use_frontswap = 1;
+__setup("nocleancache", no_cleancache);
 
 static int __init no_frontswap(char *s)
 {
-	pr_info("INIT no_frontswap called\n");
-	use_frontswap = 0;
+	disable_frontswap = 1;
 	return 1;
 }
 
 __setup("nofrontswap", no_frontswap);
 
+static int __init no_frontswap_exclusive_gets(char *s)
+{
+	frontswap_has_exclusive_gets = false;
+	return 1;
+}
+
+__setup("nofrontswapexclusivegets", no_frontswap_exclusive_gets);
+
+static int __init no_frontswap_ignore_nonactive(char *s)
+{
+	disable_frontswap_ignore_nonactive = 1;
+	return 1;
+}
+
+__setup("nofrontswapignorenonactive", no_frontswap_ignore_nonactive);
+
+static int __init no_cleancache_ignore_nonactive(char *s)
+{
+	disable_cleancache_ignore_nonactive = 1;
+	return 1;
+}
+
+__setup("nocleancacheignorenonactive", no_cleancache_ignore_nonactive);
+
+static int __init enable_zcache_compressor(char *s)
+{
+	strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ);
+	zcache_enabled = 1;
+	return 1;
+}
+__setup("zcache=", enable_zcache_compressor);
+
+
+static int __init zcache_comp_init(void)
+{
+	int ret = 0;
+
+	/* check crypto algorithm */
+	if (*zcache_comp_name != '\0') {
+		ret = crypto_has_comp(zcache_comp_name, 0, 0);
+		if (!ret)
+			pr_info("zcache: %s not supported\n",
+					zcache_comp_name);
+	}
+	if (!ret)
+		strcpy(zcache_comp_name, "lzo");
+	ret = crypto_has_comp(zcache_comp_name, 0, 0);
+	if (!ret) {
+		ret = 1;
+		goto out;
+	}
+	pr_info("zcache: using %s compressor\n", zcache_comp_name);
+
+	/* alloc percpu transforms */
+	ret = 0;
+	zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *);
+	if (!zcache_comp_pcpu_tfms)
+		ret = 1;
+out:
+	return ret;
+}
+
 static int __init zcache_init(void)
 {
 	int ret = 0;
 
-#ifdef CONFIG_SYSFS
-	ret = sysfs_create_group(mm_kobj, &zcache_attr_group);
-	ret = sysfs_create_group(mm_kobj, &ramster_attr_group);
-	if (ret) {
-		pr_err("ramster: can't create sysfs\n");
-		goto out;
-	}
-#endif /* CONFIG_SYSFS */
-#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP)
 	if (ramster_enabled) {
+		namestr = "ramster";
+		ramster_register_pamops(&zcache_pamops);
+	}
+#ifdef CONFIG_DEBUG_FS
+	zcache_debugfs_init();
+#endif
+	if (zcache_enabled) {
 		unsigned int cpu;
 
-		(void)r2net_register_handlers();
 		tmem_register_hostops(&zcache_hostops);
 		tmem_register_pamops(&zcache_pamops);
 		ret = register_cpu_notifier(&zcache_cpu_notifier_block);
 		if (ret) {
-			pr_err("ramster: can't register cpu notifier\n");
+			pr_err("%s: can't register cpu notifier\n", namestr);
+			goto out;
+		}
+		ret = zcache_comp_init();
+		if (ret) {
+			pr_err("%s: compressor initialization failed\n",
+				namestr);
 			goto out;
 		}
 		for_each_online_cpu(cpu) {
@@ -3279,42 +1774,47 @@
 				sizeof(struct tmem_objnode), 0, 0, NULL);
 	zcache_obj_cache = kmem_cache_create("zcache_obj",
 				sizeof(struct tmem_obj), 0, 0, NULL);
-	ramster_flnode_cache = kmem_cache_create("ramster_flnode",
-				sizeof(struct flushlist_node), 0, 0, NULL);
-#endif
-#ifdef CONFIG_CLEANCACHE
-	pr_info("INIT ramster_enabled=%d use_cleancache=%d\n",
-					ramster_enabled, use_cleancache);
-	if (ramster_enabled && use_cleancache) {
+	ret = zcache_new_client(LOCAL_CLIENT);
+	if (ret) {
+		pr_err("%s: can't create client\n", namestr);
+		goto out;
+	}
+	zbud_init();
+	if (zcache_enabled && !disable_cleancache) {
 		struct cleancache_ops old_ops;
 
-		zbud_init();
 		register_shrinker(&zcache_shrinker);
 		old_ops = zcache_cleancache_register_ops();
-		pr_info("ramster: cleancache enabled using kernel "
-			"transcendent memory and compression buddies\n");
-		if (old_ops.init_fs != NULL)
-			pr_warning("ramster: cleancache_ops overridden");
-	}
+		pr_info("%s: cleancache enabled using kernel transcendent "
+			"memory and compression buddies\n", namestr);
+#ifdef ZCACHE_DEBUG
+		pr_info("%s: cleancache: ignorenonactive = %d\n",
+			namestr, !disable_cleancache_ignore_nonactive);
 #endif
-#ifdef CONFIG_FRONTSWAP
-	pr_info("INIT ramster_enabled=%d use_frontswap=%d\n",
-					ramster_enabled, use_frontswap);
-	if (ramster_enabled && use_frontswap) {
+		if (old_ops.init_fs != NULL)
+			pr_warn("%s: cleancache_ops overridden\n", namestr);
+	}
+	if (zcache_enabled && !disable_frontswap) {
 		struct frontswap_ops old_ops;
 
-		zcache_new_client(LOCAL_CLIENT);
 		old_ops = zcache_frontswap_register_ops();
-		pr_info("ramster: frontswap enabled using kernel "
-			"transcendent memory and xvmalloc\n");
-		if (old_ops.init != NULL)
-			pr_warning("ramster: frontswap_ops overridden");
-	}
-	if (ramster_enabled && (use_frontswap || use_cleancache))
-		ramster_remotify_init();
+		if (frontswap_has_exclusive_gets)
+			frontswap_tmem_exclusive_gets(true);
+		pr_info("%s: frontswap enabled using kernel transcendent "
+			"memory and compression buddies\n", namestr);
+#ifdef ZCACHE_DEBUG
+		pr_info("%s: frontswap: excl gets = %d active only = %d\n",
+			namestr, frontswap_has_exclusive_gets,
+			!disable_frontswap_ignore_nonactive);
 #endif
+		if (old_ops.init != NULL)
+			pr_warn("%s: frontswap_ops overridden\n", namestr);
+	}
+	if (ramster_enabled)
+		ramster_init(!disable_cleancache, !disable_frontswap,
+				frontswap_has_exclusive_gets);
 out:
 	return ret;
 }
 
-module_init(zcache_init)
+late_initcall(zcache_init);
diff --git a/drivers/staging/ramster/zcache.h b/drivers/staging/ramster/zcache.h
index 250b121..81722b3 100644
--- a/drivers/staging/ramster/zcache.h
+++ b/drivers/staging/ramster/zcache.h
@@ -1,22 +1,53 @@
+
 /*
  * zcache.h
  *
- * External zcache functions
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2012, Dan Magenheimer, Oracle Corp.
  */
 
 #ifndef _ZCACHE_H_
 #define _ZCACHE_H_
 
-extern int zcache_put(int, int, struct tmem_oid *, uint32_t,
-			char *, size_t, bool, int);
-extern int zcache_autocreate_pool(int, int, bool);
-extern int zcache_get(int, int, struct tmem_oid *, uint32_t,
-			char *, size_t *, bool, int);
-extern int zcache_flush(int, int, struct tmem_oid *, uint32_t);
-extern int zcache_flush_object(int, int, struct tmem_oid *);
-extern int zcache_localify(int, struct tmem_oid *, uint32_t,
-			char *, size_t, void *);
+struct zcache_preload {
+	struct tmem_obj *obj;
+	struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
+};
 
-#endif /* _ZCACHE_H */
+struct tmem_pool;
+
+#define MAX_POOLS_PER_CLIENT 16
+
+#define MAX_CLIENTS 16
+#define LOCAL_CLIENT ((uint16_t)-1)
+
+struct zcache_client {
+	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
+	bool allocated;
+	atomic_t refcount;
+};
+
+extern struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
+							uint16_t poolid);
+extern void zcache_put_pool(struct tmem_pool *pool);
+
+extern int zcache_put_page(int, int, struct tmem_oid *,
+				uint32_t, void *,
+				unsigned int, bool, int);
+extern int zcache_get_page(int, int, struct tmem_oid *, uint32_t,
+				void *, size_t *, bool, int);
+extern int zcache_flush_page(int, int, struct tmem_oid *, uint32_t);
+extern int zcache_flush_object(int, int, struct tmem_oid *);
+extern void zcache_decompress_to_page(char *, unsigned int, struct page *);
+
+#ifdef CONFIG_RAMSTER
+extern void *zcache_pampd_create(char *, unsigned int, bool, int,
+				struct tmem_handle *);
+int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph);
+#endif
+
+#define MAX_POOLS_PER_CLIENT 16
+
+#define MAX_CLIENTS 16
+#define LOCAL_CLIENT ((uint16_t)-1)
+
+#endif /* _ZCACHE_H_ */
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index b94c48b..5f5a3022 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -1094,7 +1094,7 @@
 
 	int (*reset_port)(struct net_device *dev);
 
-	/* Softmac-generated frames (mamagement) are TXed via this
+	/* Softmac-generated frames (management) are TXed via this
 	 * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
 	 * not set. As some cards may have different HW queues that
 	 * one might want to use for data and management frames
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 8173240..00f9af0 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <asm/uaccess.h>
+#include <linux/etherdevice.h>
 
 #include "dot11d.h"
 u8 rsn_authen_cipher_suite[16][4] = {
@@ -2110,13 +2111,7 @@
 inline void ieee80211_randomize_cell(struct ieee80211_device *ieee)
 {
 
-	get_random_bytes(ieee->current_network.bssid, ETH_ALEN);
-
-	/* an IBSS cell address must have the two less significant
-	 * bits of the first byte = 2
-	 */
-	ieee->current_network.bssid[0] &= ~0x01;
-	ieee->current_network.bssid[0] |= 0x02;
+	random_ether_addr(ieee->current_network.bssid);
 }
 
 /* called in user context only */
@@ -2808,9 +2803,7 @@
 			       param->u.crypt.key_len);
 		return -EINVAL;
 	}
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= WEP_KEYS)
 			return -EINVAL;
 		crypt = &ieee->crypt[param->u.crypt.idx];
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index 5d20490..1ef8fd6 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -14,6 +14,8 @@
  */
 
 
+#include <linux/etherdevice.h>
+
 #include "ieee80211.h"
 
 /* FIXME: add A freqs */
@@ -131,7 +133,6 @@
 {
 
 	int ret = 0;
-	u8 zero[] = {0,0,0,0,0,0};
 	unsigned long flags;
 
 	short ifup = ieee->proto_started;//dev->flags & IFF_UP;
@@ -161,7 +162,7 @@
 	spin_lock_irqsave(&ieee->lock, flags);
 
 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
-	ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
+	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
 	//printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]);
 
 	spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index fd22b75..20e5fb5 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -2377,7 +2377,7 @@
 				u8		u1bAIFS;
 				u32		u4bAcParam;
 				pAcParam = (PAC_PARAM)(&AcParam);
-				/* Retrieve paramters to update. */
+				/* Retrieve parameters to update. */
 				u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
 				u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
 					      (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
@@ -2413,7 +2413,7 @@
 			u8		u1bAIFS;
 			u32		u4bAcParam;
 
-			/* Retrieve paramters to update. */
+			/* Retrieve parameters to update. */
 			eACI = pAcParam->f.AciAifsn.f.ACI;
 			/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
 			u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h
index 3fca144..5339381 100644
--- a/drivers/staging/rtl8187se/r8180_hw.h
+++ b/drivers/staging/rtl8187se/r8180_hw.h
@@ -554,11 +554,16 @@
 /* by amy for power save		*/
 /* by amy for antenna			*/
 #define EEPROM_SW_REVD_OFFSET 0x3f
-/*  BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable.					*/
+
+/*  BIT[8-9] is for SW Antenna Diversity. 
+ *  Only the value EEPROM_SW_AD_ENABLE means enable, other values are disable.
+ */
 #define EEPROM_SW_AD_MASK			0x0300
 #define EEPROM_SW_AD_ENABLE			0x0100
 
-/* BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE.	*/
+/* BIT[10-11] determine if Antenna 1 is the Default Antenna.
+ * Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE.	
+ */
 #define EEPROM_DEF_ANT_MASK			0x0C00
 #define EEPROM_DEF_ANT_1			0x0400
 /*by amy for antenna																				*/
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 9144957..bf343199 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -1008,7 +1008,7 @@
 				u8		u1bAIFS;
 				u32		u4bAcParam;
 
-				/*  Retrieve paramters to update. */
+				/*  Retrieve parameters to update. */
 				eACI = pAcParam->f.AciAifsn.f.ACI;
 				u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime;
 				u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET)	|
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
index b526fa4..dd2a96b 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
@@ -265,10 +265,11 @@
 			case FW_SOURCE_IMG_FILE:
 			{
 				if (pfirmware->firmware_buf_size[init_step] == 0) {
-					const char *fw_name[3] = { "RTL8192E/boot.img",
-							   "RTL8192E/main.img",
-							   "RTL8192E/data.img"
-							 };
+					const char *fw_name[3] = {
+							RTL8192E_BOOT_IMG_FW,
+							RTL8192E_MAIN_IMG_FW,
+							RTL8192E_DATA_IMG_FW
+					};
 					const struct firmware	*fw_entry;
 					int rc;
 					rc = request_firmware(&fw_entry,
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
index caa8788..06d6abc 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
@@ -23,6 +23,10 @@
 
 #define GET_COMMAND_PACKET_FRAG_THRESHOLD(v)	(4*(v/4) - 8)
 
+#define RTL8192E_BOOT_IMG_FW	"RTL8192E/boot.img"
+#define RTL8192E_MAIN_IMG_FW	"RTL8192E/main.img"
+#define RTL8192E_DATA_IMG_FW	"RTL8192E/data.img"
+
 enum firmware_init_step {
 	FW_INIT_STEP0_BOOT = 0,
 	FW_INIT_STEP1_MAIN = 1,
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 4f602b2..81134d3 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -734,8 +734,7 @@
 
 	ring = &priv->tx_ring[BEACON_QUEUE];
 	pskb = __skb_dequeue(&ring->queue);
-	if (pskb)
-		kfree_skb(pskb);
+	kfree_skb(pskb);
 
 	pnewskb = rtllib_get_beacon(priv->rtllib);
 	if (!pnewskb)
@@ -3125,6 +3124,9 @@
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW);
+MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW);
+MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW);
 
 module_param(ifname, charp, S_IRUGO|S_IWUSR);
 module_param(hwwep, int, S_IRUGO|S_IWUSR);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 481b1e4..1853665 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -202,7 +202,7 @@
 
 	if (priv->ResetProgress == RESET_TYPE_SILENT) {
 		RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),
-			 "GPIOChangeRFWorkItemCallBack(): Silent Reseting!!!!!!!\n");
+			 "GPIOChangeRFWorkItemCallBack(): Silent Reset!!!!!!!\n");
 		return;
 	}
 
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
index ddadcc3..5abbee3 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
@@ -31,12 +31,10 @@
 	struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
 
 	u8 tmp;
-	int pos;
-	u8 LinkCtrlReg;
+	u16 LinkCtrlReg;
 
-	pos = pci_find_capability(priv->pdev, PCI_CAP_ID_EXP);
-	pci_read_config_byte(priv->pdev, pos + PCI_EXP_LNKCTL, &LinkCtrlReg);
-	priv->NdisAdapter.LinkCtrlReg = LinkCtrlReg;
+	pcie_capability_read_word(priv->pdev, PCI_EXP_LNKCTL, &LinkCtrlReg);
+	priv->NdisAdapter.LinkCtrlReg = (u8)LinkCtrlReg;
 
 	RT_TRACE(COMP_INIT, "Link Control Register =%x\n",
 		 priv->NdisAdapter.LinkCtrlReg);
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index d7460ae..9ac8d8e 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -2397,12 +2397,12 @@
 				 struct rtllib_network *network, u16 type);
 	int (*is_qos_active)(struct net_device *dev, struct sk_buff *skb);
 
-	/* Softmac-generated frames (mamagement) are TXed via this
+	/* Softmac-generated frames (management) are TXed via this
 	 * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
 	 * not set. As some cards may have different HW queues that
 	 * one might want to use for data and management frames
 	 * the option to have two callbacks might be useful.
-	 * This fucntion can't sleep.
+	 * This function can't sleep.
 	 */
 	int (*softmac_hard_start_xmit)(struct sk_buff *skb,
 			       struct net_device *dev);
@@ -2441,9 +2441,9 @@
 	 * it is called in a work_queue when switching to ad-hoc mode
 	 * or in behalf of iwlist scan when the card is associated
 	 * and root user ask for a scan.
-	 * the fucntion stop_scan should stop both the syncro and
+	 * the function stop_scan should stop both the syncro and
 	 * background scanning and can sleep.
-	 * The fucntion start_scan should initiate the background
+	 * The function start_scan should initiate the background
 	 * scanning and can't sleep.
 	 */
 	void (*scan_syncro)(struct net_device *dev);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index a21b4d9..4feecec 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -19,6 +19,7 @@
 #include <linux/random.h>
 #include <linux/delay.h>
 #include <linux/uaccess.h>
+#include <linux/etherdevice.h>
 #include "dot11d.h"
 
 short rtllib_is_54g(struct rtllib_network *net)
@@ -266,7 +267,7 @@
 		else
 			ieee->seq_ctrl[0]++;
 
-		/* check wether the managed packet queued greater than 5 */
+		/* check whether the managed packet queued greater than 5 */
 		if (!ieee->check_nic_enough_desc(ieee->dev, tcb_desc->queue_index) ||
 		    (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0) ||
 		    (ieee->queue_stop)) {
@@ -1687,7 +1688,7 @@
 		 * if the network does broadcast and the user did set essid
 		 * check if essid match
 		 * if the ap is not set, check that the user set the bssid
-		 * and the network does bradcast and that those two bssid match
+		 * and the network does broadcast and that those two bssid match
 		 */
 		if ((apset && apmatch &&
 		   ((ssidset && ssidbroad && ssidmatch) ||
@@ -1843,7 +1844,7 @@
 
 	bssid_match =
 	  (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) &&
-	  (memcmp(header->addr3, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0);
+	  (!is_broadcast_ether_addr(header->addr3));
 	if (bssid_match)
 		return -1;
 
@@ -2442,7 +2443,7 @@
 	return 0;
 }
 
-/* following are for a simplier TX queue management.
+/* following are for a simpler TX queue management.
  * Instead of using netif_[stop/wake]_queue the driver
  * will use these two functions (plus a reset one), that
  * will internally use the kernel netif_* and takes
@@ -2619,13 +2620,7 @@
 inline void rtllib_randomize_cell(struct rtllib_device *ieee)
 {
 
-	get_random_bytes(ieee->current_network.bssid, ETH_ALEN);
-
-	/* an IBSS cell address must have the two less significant
-	 * bits of the first byte = 2
-	 */
-	ieee->current_network.bssid[0] &= ~0x01;
-	ieee->current_network.bssid[0] |= 0x02;
+	random_ether_addr(ieee->current_network.bssid);
 }
 
 /* called in user context only */
@@ -3361,9 +3356,7 @@
 			       param->u.crypt.key_len);
 		return -EINVAL;
 	}
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= NUM_WEP_KEYS)
 			return -EINVAL;
 		crypt = &ieee->crypt_info.crypt[param->u.crypt.idx];
@@ -3411,8 +3404,7 @@
 
 		lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 
-		new_crypt = (struct lib80211_crypt_data *)
-			kmalloc(sizeof(*new_crypt), GFP_KERNEL);
+		new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
 			goto done;
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 1bb6b52e..740cf85 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -14,6 +14,8 @@
  */
 
 
+#include <linux/etherdevice.h>
+
 #include "rtllib.h"
 #include "dot11d.h"
 /* FIXME: add A freqs */
@@ -137,7 +139,6 @@
 {
 
 	int ret = 0;
-	u8 zero[] = {0, 0, 0, 0, 0, 0};
 	unsigned long flags;
 
 	short ifup = ieee->proto_started;
@@ -157,7 +158,7 @@
 		goto out;
 	}
 
-	if (memcmp(temp->sa_data, zero, ETH_ALEN) == 0) {
+	if (is_zero_ether_addr(temp->sa_data)) {
 		spin_lock_irqsave(&ieee->lock, flags);
 		memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
 		ieee->wap_set = 0;
@@ -177,7 +178,7 @@
 
 	ieee->cannot_notify = false;
 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
-	ieee->wap_set = (memcmp(temp->sa_data, zero, ETH_ALEN) != 0);
+	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
 
 	spin_unlock_irqrestore(&ieee->lock, flags);
 
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index 1c0a1db..13f45c3 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -2114,7 +2114,7 @@
                                   struct ieee80211_network * network, u16 type);
         int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
 
-	/* Softmac-generated frames (mamagement) are TXed via this
+	/* Softmac-generated frames (management) are TXed via this
 	 * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
 	 * not set. As some cards may have different HW queues that
 	 * one might want to use for data and management frames
@@ -2192,7 +2192,7 @@
 	int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network);
 
 
-	/* check whether Tx hw resouce available */
+	/* check whether Tx hw resource available */
 	short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
 	//added by wb for HT related
 //	void (*SwChnlByTimerHandler)(struct net_device *dev, int channel);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index f6ff8cf..7a07078 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -20,6 +20,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
+#include <linux/etherdevice.h>
+
 #include "dot11d.h"
 
 u8 rsn_authen_cipher_suite[16][4] = {
@@ -269,7 +271,7 @@
 		else
 			ieee->seq_ctrl[0]++;
 
-		/* check wether the managed packet queued greater than 5 */
+		/* check whether the managed packet queued greater than 5 */
 		if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\
 				(skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\
 				(ieee->queue_stop) ) {
@@ -1448,7 +1450,7 @@
 			( apset && apmatch &&
 				((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
 			/* if the ap is not set, check that the user set the bssid
-			 * and the network does bradcast and that those two bssid matches
+			 * and the network does broadcast and that those two bssid matches
 			 */
 			(!apset && ssidset && ssidbroad && ssidmatch)
 			){
@@ -2286,13 +2288,7 @@
 inline void ieee80211_randomize_cell(struct ieee80211_device *ieee)
 {
 
-	get_random_bytes(ieee->current_network.bssid, ETH_ALEN);
-
-	/* an IBSS cell address must have the two less significant
-	 * bits of the first byte = 2
-	 */
-	ieee->current_network.bssid[0] &= ~0x01;
-	ieee->current_network.bssid[0] |= 0x02;
+	random_ether_addr(ieee->current_network.bssid);
 }
 
 /* called in user context only */
@@ -2520,7 +2516,7 @@
 
 	/* until we do not set the state to IEEE80211_NOLINK
 	* there are no possibility to have someone else trying
-	* to start an association procdure (we get here with
+	* to start an association procedure (we get here with
 	* ieee->state = IEEE80211_ASSOCIATING).
 	* When we set the state to IEEE80211_NOLINK it is possible
 	* that the RX path run an attempt to associate, but
@@ -2969,9 +2965,7 @@
 			       param->u.crypt.key_len);
 		return -EINVAL;
 	}
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= WEP_KEYS)
 			return -EINVAL;
 		crypt = &ieee->crypt[param->u.crypt.idx];
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index cb5a3c3..421da8a 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -14,6 +14,8 @@
  */
 
 
+#include <linux/etherdevice.h>
+
 #include "ieee80211.h"
 #include "dot11d.h"
 /* FIXME: add A freqs */
@@ -136,7 +138,6 @@
 {
 
 	int ret = 0;
-	u8 zero[] = {0,0,0,0,0,0};
 	unsigned long flags;
 
 	short ifup = ieee->proto_started;//dev->flags & IFF_UP;
@@ -165,7 +166,7 @@
 	spin_lock_irqsave(&ieee->lock, flags);
 
 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
-	ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
+	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
 
 	spin_unlock_irqrestore(&ieee->lock, flags);
 
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 27d083a..1ebea3da 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -1,6 +1,6 @@
 /********************************************************************************************************************************
  * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is
- * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send
+ * related to TS, this part need some structure defined in QOS side code. Also TX RX is going to be resturctured, so how to send
  * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue.
  * WB 2008-05-27
  * *****************************************************************************************************************************/
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
index 0b1a1fc..a60b39c 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
@@ -15,7 +15,7 @@
 #define HT_OPMODE_MIXED			3
 
 //
-// MIMO Power Save Setings
+// MIMO Power Save Settings
 //
 #define MIMO_PS_STATIC				0
 #define MIMO_PS_DYNAMIC			1
@@ -242,7 +242,7 @@
 	u8				bEnableHT;
 	u8				bCurrentHTSupport;
 
-	u8				bRegBW40MHz;				// Tx 40MHz channel capablity
+	u8				bRegBW40MHz;				// Tx 40MHz channel capability
 	u8				bCurBW40MHz;				// Tx 40MHz channel capability
 
 	u8				bRegShortGI40MHz;			// Tx Short GI for 40Mhz
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
index e88a839..ebb5239 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
@@ -912,7 +912,7 @@
 
 	u8 i=0;
 
-	// filter out operational rate set not supported by AP, the lenth of it is 16
+	// filter out operational rate set not supported by AP, the length of it is 16
 	for(i=0;i<=15;i++){
 		pOperateMCS[i] = ieee->Regdot11HTOperationalRateSet[i]&pSupportMCS[i];
 	}
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 5981d66..5a2fab9 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -2232,24 +2232,15 @@
 	memset(priv->rx_urb, 0, sizeof(struct urb*) * MAX_RX_URB);
 	priv->pp_rxskb = kcalloc(MAX_RX_URB, sizeof(struct sk_buff *),
 				 GFP_KERNEL);
-	if (priv->pp_rxskb == NULL)
-		goto destroy;
+	if (!priv->pp_rxskb) {
+		kfree(priv->rx_urb);
 
-	goto _middle;
+		priv->pp_rxskb = NULL;
+		priv->rx_urb = NULL;
 
-
-destroy:
-	kfree(priv->pp_rxskb);
-	kfree(priv->rx_urb);
-
-	priv->pp_rxskb = NULL;
-	priv->rx_urb = NULL;
-
-	DMESGE("Endpoint Alloc Failure");
-	return -ENOMEM;
-
-
-_middle:
+		DMESGE("Endpoint Alloc Failure");
+		return -ENOMEM;
+	}
 
 	printk("End of initendpoints\n");
 	return 0;
@@ -2808,9 +2799,7 @@
 		(priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0);
 
 	priv->AcmControl = 0;
-	priv->pFirmware = kmalloc(sizeof(rt_firmware), GFP_KERNEL);
-	if (priv->pFirmware)
-	memset(priv->pFirmware, 0, sizeof(rt_firmware));
+	priv->pFirmware = kzalloc(sizeof(rt_firmware), GFP_KERNEL);
 
 	/* rx related queue */
 	skb_queue_head_init(&priv->rx_queue);
diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h
index e07f8b1..6c1d05e 100644
--- a/drivers/staging/rtl8192u/r819xU_HTType.h
+++ b/drivers/staging/rtl8192u/r819xU_HTType.h
@@ -16,7 +16,7 @@
 #define HT_OPMODE_MIXED			3
 
 //
-// MIMO Power Save Setings
+// MIMO Power Save Settings
 //
 #define MIMO_PS_STATIC				0
 #define MIMO_PS_DYNAMIC			1
diff --git a/drivers/staging/rtl8192u/r819xU_phyreg.h b/drivers/staging/rtl8192u/r819xU_phyreg.h
index 50f24dc..cca34c0 100644
--- a/drivers/staging/rtl8192u/r819xU_phyreg.h
+++ b/drivers/staging/rtl8192u/r819xU_phyreg.h
@@ -443,7 +443,7 @@
 #define bCCKRxIG                  			0x7f00
 #define bCCKLNAPolarity           		0x800000
 #define bCCKRx1stGain             		0x7f0000
-#define bCCKRFExtend              		0x20000000 //CCK Rx inital gain polarity
+#define bCCKRFExtend              		0x20000000 //CCK Rx initial gain polarity
 #define bCCKRxAGCSatLevel        		0x1f000000
 #define bCCKRxAGCSatCount       		0xe0
 #define bCCKRxRFSettle            		0x1f       //AGCsamp_dly
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index 62b5566..a074fe8 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -70,9 +70,7 @@
 #include "rtl871x_event.h"
 #include "rtl871x_led.h"
 
-#define SPEC_DEV_ID_NONE BIT(0)
 #define SPEC_DEV_ID_DISABLE_HT BIT(1)
-#define SPEC_DEV_ID_ENABLE_PS BIT(2)
 
 struct specific_device_id {
 	u32		flags;
@@ -127,13 +125,6 @@
 	u8 wifi_test;
 };
 
-/* For registry parameters */
-#define RGTRY_OFT(field) ((addr_t)FIELD_OFFSET(struct registry_priv, field))
-#define RGTRY_SZ(field)   sizeof(((struct registry_priv *)0)->field)
-#define BSSID_OFT(field) ((addr_t)FIELD_OFFSET(struct ndis_wlan_bssid_ex, \
-			 field))
-#define BSSID_SZ(field)   sizeof(((struct ndis_wlan_bssid_ex *)0)->field)
-
 struct dvobj_priv {
 	struct _adapter *padapter;
 	u32 nr_endpoint;
diff --git a/drivers/staging/rtl8712/ethernet.h b/drivers/staging/rtl8712/ethernet.h
index 882d61b..9095420 100644
--- a/drivers/staging/rtl8712/ethernet.h
+++ b/drivers/staging/rtl8712/ethernet.h
@@ -35,14 +35,6 @@
 
 /*!< Is Multicast Address? */
 #define RT_ETH_IS_MULTICAST(_pAddr)	((((u8 *)(_pAddr))[0]&0x01) != 0)
-/*!< Is Broadcast Address? */
-#define RT_ETH_IS_BROADCAST(_pAddr)	(				\
-			((u8 *)(_pAddr))[0] == 0xff	&&		\
-			((u8 *)(_pAddr))[1] == 0xff	&&		\
-			((u8 *)(_pAddr))[2] == 0xff	&&		\
-			((u8 *)(_pAddr))[3] == 0xff	&&		\
-			((u8 *)(_pAddr))[4] == 0xff	&&		\
-			((u8 *)(_pAddr))[5] == 0xff)
 
 #endif /* #ifndef __INC_ETHERNET_H */
 
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 448f00d..e00f791 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -96,7 +96,7 @@
 /* if wifi_test = 1, driver will disable the turbo mode and pass it to
  * firmware private.
  */
-static int wifi_test = 0;
+static int wifi_test;
 
 module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
 module_param(wifi_test, int, 0644);
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index 8e82ce2..c76732c 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -374,6 +374,8 @@
 		a_len -= ETH_HLEN;
 		/* Allocate new skb for releasing to upper layer */
 		sub_skb = dev_alloc_skb(nSubframe_Length + 12);
+		if (!sub_skb)
+			break;
 		skb_reserve(sub_skb, 12);
 		data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
 		memcpy(data_ptr, pdata, nSubframe_Length);
@@ -1094,6 +1096,8 @@
 			precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
 		} else {
 			precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
+			if (!precvframe->u.hdr.pkt)
+				return _FAIL;
 			precvframe->u.hdr.rx_head = pbuf;
 			precvframe->u.hdr.rx_data = pbuf;
 			precvframe->u.hdr.rx_tail = pbuf;
@@ -1127,6 +1131,9 @@
 		recvbuf2recvframe(padapter, pskb);
 		skb_reset_tail_pointer(pskb);
 		pskb->len = 0;
-		skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+		if (!skb_cloned(pskb))
+			skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+		else
+			consume_skb(pskb);
 	}
 }
diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h
index 8efbd1f..fd9e3fc 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.h
+++ b/drivers/staging/rtl8712/rtl8712_recv.h
@@ -41,7 +41,7 @@
 #define RECV_BLK_SZ 512
 #define RECV_BLK_CNT 16
 #define RECV_BLK_TH RECV_BLK_CNT
-#define MAX_RECVBUF_SZ (30720) /* 30K */
+#define MAX_RECVBUF_SZ 9100
 #define RECVBUFF_ALIGN_SZ 512
 #define RSVD_ROOM_SZ (0)
 /*These definition is used for Rx packet reordering.*/
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 3d23514..4e3f094 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -376,7 +376,7 @@
 {
 	struct _adapter *padapter = pxmitframe->padapter;
 	struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv;
-	struct tx_desc * ptxdesc = (struct tx_desc *)pxmitbuf->pbuf;
+	struct tx_desc *ptxdesc = (struct tx_desc *)pxmitbuf->pbuf;
 	struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *)
 		(pxmitbuf->pbuf + TXDESC_SIZE);
 	u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff);
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index 35e781f..c9a6a7f 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -407,9 +407,7 @@
 	if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) +
 			 param->u.crypt.key_len)
 		return -EINVAL;
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= WEP_KEYS) {
 			/* for large key indices, set the default (0) */
 			param->u.crypt.idx = 0;
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index f352b32..d3ab24e 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -131,10 +131,7 @@
 	u8 status = true;
 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 
-	if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
-	     bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
-	    (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
-	     bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) {
+	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) {
 		status = false;
 		return status;
 	}
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index dc7adc1..c51ad9e 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -28,6 +28,8 @@
 
 #define _RTL871X_MLME_C_
 
+#include <linux/etherdevice.h>
+
 #include "osdep_service.h"
 #include "drv_types.h"
 #include "recv_osdep.h"
@@ -146,9 +148,8 @@
 	unsigned long irqL;
 	struct list_head *phead, *plist;
 	struct wlan_network *pnetwork = NULL;
-	u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
-	if (!memcmp(zero_addr, addr, ETH_ALEN))
+	if (is_zero_ether_addr(addr))
 		return NULL;
 	spin_lock_irqsave(&scanned_queue->lock, irqL);
 	phead = get_list_head(scanned_queue);
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index 6024c4f..70ff924f 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -30,26 +30,7 @@
 #include "drv_types.h"
 
 
-#define FW_PWR0	0
-#define FW_PWR1		1
-#define FW_PWR2		2
-#define FW_PWR3		3
-
-
-#define HW_PWR0	7
-#define HW_PWR1		6
-#define HW_PWR2		2
-#define HW_PWR3	0
-#define HW_PWR4	8
-
-#define FW_PWRMSK	0x7
-
-
-#define XMIT_ALIVE	BIT(0)
-#define RECV_ALIVE	BIT(1)
 #define CMD_ALIVE	BIT(2)
-#define EVT_ALIVE	BIT(3)
-
 
 enum Power_Mgnt {
 	PS_MODE_ACTIVE	= 0	,
@@ -66,7 +47,6 @@
 	PS_MODE_NUM
 };
 
-
 /*
 	BIT[2:0] = HW state
 	BIT[3] = Protocol PS state, 0: register active state,
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index c9d1743..23ec684b 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/if_ether.h>
 #include <linux/kmemleak.h>
+#include <linux/etherdevice.h>
 
 #include "osdep_service.h"
 #include "drv_types.h"
@@ -331,8 +332,8 @@
 			return _FAIL;
 		if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
 			return _FAIL;
-		if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
-		    !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		if (is_zero_ether_addr(pattrib->bssid) ||
+		    is_zero_ether_addr(mybssid) ||
 		    (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
 			return _FAIL;
 		sta_addr = pattrib->src;
@@ -409,8 +410,8 @@
 		if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
 			return _FAIL;
 		/* check BSSID */
-		if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
-		     !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		if (is_zero_ether_addr(pattrib->bssid) ||
+		     is_zero_ether_addr(mybssid) ||
 		     (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
 			return _FAIL;
 		if (bmcast)
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index 7b92927..e33fd6d 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -58,7 +58,7 @@
 	u8 state[256];
 };
 
-static void arcfour_init(struct arc4context *parc4ctx, u8 * key, u32 key_len)
+static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len)
 {
 	u32	t, u;
 	u32	keyindex;
@@ -288,7 +288,7 @@
 	pmicdata->M = 0;
 }
 
-void r8712_secmicsetkey(struct mic_data *pmicdata, u8 * key)
+void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key)
 {
 	/* Set the key */
 	pmicdata->K0 = secmicgetuint32(key);
@@ -320,7 +320,7 @@
 	}
 }
 
-void r8712_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nbytes)
+void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes)
 {
 	/* This is simple */
 	while (nbytes > 0) {
@@ -1368,7 +1368,7 @@
 					   precvframe)->u.hdr.attrib;
 	struct	security_priv *psecuritypriv = &padapter->securitypriv;
 
-	pframe = (unsigned char *)((union recv_frame*)precvframe)->
+	pframe = (unsigned char *)((union recv_frame *)precvframe)->
 		 u.hdr.rx_data;
 	/* 4 start to encrypt each fragment */
 	if ((prxattrib->encrypt == _AES_)) {
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index c758c40..6b73843 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -37,7 +37,6 @@
 #include "recv_osdep.h"
 #include "xmit_osdep.h"
 #include "rtl8712_efuse.h"
-#include "usb_vendor_req.h"
 #include "usb_ops.h"
 #include "usb_osintf.h"
 
diff --git a/drivers/staging/rtl8712/usb_osintf.h b/drivers/staging/rtl8712/usb_osintf.h
index d95797aa..609f921 100644
--- a/drivers/staging/rtl8712/usb_osintf.h
+++ b/drivers/staging/rtl8712/usb_osintf.h
@@ -28,9 +28,6 @@
 
 #include "osdep_service.h"
 #include "drv_types.h"
-#include "usb_vendor_req.h"
-
-#define USBD_HALTED(Status) ((u32)(Status) >> 30 == 3)
 
 extern char *r8712_initmac;
 
diff --git a/drivers/staging/rtl8712/usb_vendor_req.h b/drivers/staging/rtl8712/usb_vendor_req.h
deleted file mode 100644
index 82335a8..0000000
--- a/drivers/staging/rtl8712/usb_vendor_req.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _USB_VENDOR_REQUEST_H_
-#define _USB_VENDOR_REQUEST_H_
-
-/*4	Set/Get Register related wIndex/Data */
-#define	RT_USB_RESET_MASK_OFF		0
-#define	RT_USB_RESET_MASK_ON		1
-#define	RT_USB_SLEEP_MASK_OFF		0
-#define	RT_USB_SLEEP_MASK_ON		1
-#define	RT_USB_LDO_ON			1
-#define	RT_USB_LDO_OFF			0
-
-/*4	Set/Get SYSCLK related	wValue or Data */
-#define	RT_USB_SYSCLK_32KHZ		0
-#define	RT_USB_SYSCLK_40MHZ		1
-#define	RT_USB_SYSCLK_60MHZ		2
-
-enum RT_USB_BREQUEST {
-	RT_USB_SET_REGISTER		= 1,
-	RT_USB_SET_SYSCLK		= 2,
-	RT_USB_GET_SYSCLK		= 3,
-	RT_USB_GET_REGISTER		= 4
-};
-
-enum RT_USB_WVALUE {
-	RT_USB_RESET_MASK	=	1,
-	RT_USB_SLEEP_MASK	=	2,
-	RT_USB_USB_HRCPWM	=	3,
-	RT_USB_LDO		=	4,
-	RT_USB_BOOT_TYPE	=	5
-};
-
-#endif
-
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index e1200fe8..bf1a9e6 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -79,7 +79,7 @@
 
 	case 1:
 		/* Read from card */
-		buf = kmalloc(cmnd->buf_len, GFP_KERNEL);
+		buf = kzalloc(cmnd->buf_len, GFP_KERNEL);
 		if (!buf)
 			TRACE_RET(chip, STATUS_NOMEM);
 
diff --git a/drivers/staging/rts5139/trace.h b/drivers/staging/rts5139/trace.h
index 0584b8a..c9dfb1e 100644
--- a/drivers/staging/rts5139/trace.h
+++ b/drivers/staging/rts5139/trace.h
@@ -93,35 +93,9 @@
 #endif
 
 #ifdef CONFIG_RTS5139_DEBUG
-static inline void rts51x_dump(u8 *buf, int buf_len)
-{
-	int i;
-	u8 tmp[16] = { 0 };
-	u8 *_ptr = buf;
-
-	for (i = 0; i < ((buf_len) / 16); i++) {
-		RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-			       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-			       _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
-			       _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
-			       _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
-			       _ptr[15]);
-		_ptr += 16;
-	}
-	if ((buf_len) % 16) {
-		memcpy(tmp, _ptr, (buf_len) % 16);
-		_ptr = tmp;
-		RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-			       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-			       _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
-			       _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
-			       _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
-			       _ptr[15]);
-	}
-}
-
-#define RTS51X_DUMP(buf, buf_len)	\
-		rts51x_dump((u8 *)(buf), (buf_len))
+#define RTS51X_DUMP(buf, buf_len)					\
+	print_hex_dump(KERN_DEBUG, RTS51X_TIP, DUMP_PREFIX_NONE,	\
+				16, 1, (buf), (buf_len), false)
 
 #define CATCH_TRIGGER(chip)					\
 do {								\
diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c
index 7cc2b53..16a5c16 100644
--- a/drivers/staging/rts_pstor/ms.c
+++ b/drivers/staging/rts_pstor/ms.c
@@ -109,9 +109,8 @@
 	u8 val, err_code = 0;
 	enum dma_data_direction dir;
 
-	if (!buf || !buf_len) {
+	if (!buf || !buf_len)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (trans_mode == MS_TM_AUTO_READ) {
 		dir = DMA_FROM_DEVICE;
@@ -151,18 +150,17 @@
 				    use_sg, dir, chip->mspro_timeout);
 	if (retval < 0) {
 		ms_set_err_code(chip, err_code);
-		if (retval == -ETIMEDOUT) {
+		if (retval == -ETIMEDOUT)
 			retval = STATUS_TIMEDOUT;
-		} else {
+		else
 			retval = STATUS_FAIL;
-		}
+
 		TRACE_RET(chip, retval);
 	}
 
 	RTSX_READ_REG(chip, MS_TRANS_CFG, &val);
-	if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
+	if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -173,9 +171,8 @@
 	struct ms_info *ms_card = &(chip->ms_card);
 	int retval, i;
 
-	if (!data || (data_len < cnt)) {
+	if (!data || (data_len < cnt))
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	rtsx_init_cmd(chip);
 
@@ -183,9 +180,8 @@
 		rtsx_add_cmd(chip, WRITE_REG_CMD,
 			     PPBUF_BASE2 + i, 0xFF, data[i]);
 	}
-	if (cnt % 2) {
+	if (cnt % 2)
 		rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF);
-	}
 
 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
@@ -238,9 +234,8 @@
 	int retval, i;
 	u8 *ptr;
 
-	if (!data) {
+	if (!data)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	rtsx_init_cmd(chip);
 
@@ -252,14 +247,13 @@
 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES);
 	rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
 
-	for (i = 0; i < data_len - 1; i++) {
+	for (i = 0; i < data_len - 1; i++)
 	       rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
-	}
-	if (data_len % 2) {
+
+	if (data_len % 2)
 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0);
-	} else {
+	else
 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1, 0, 0);
-	}
 
 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
 	if (retval < 0) {
@@ -293,9 +287,8 @@
 
 	ptr = rtsx_get_cmd_data(chip) + 1;
 
-	for (i = 0; i < data_len; i++) {
+	for (i = 0; i < data_len; i++)
 		data[i] = ptr[i];
-	}
 
 	if ((tpc == PRO_READ_SHORT_DATA) && (data_len == 8)) {
 		RTSX_DEBUGP("Read format progress:\n");
@@ -343,34 +336,31 @@
 	int retval;
 
 	if (CHK_HG8BIT(ms_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			ms_card->ms_clock = chip->asic_ms_hg_clk;
-		} else {
+		else
 			ms_card->ms_clock = chip->fpga_ms_hg_clk;
-		}
+
 	} else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			ms_card->ms_clock = chip->asic_ms_4bit_clk;
-		} else {
+		else
 			ms_card->ms_clock = chip->fpga_ms_4bit_clk;
-		}
+
 	} else {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			ms_card->ms_clock = chip->asic_ms_1bit_clk;
-		} else {
+		else
 			ms_card->ms_clock = chip->fpga_ms_1bit_clk;
-		}
 	}
 
 	retval = switch_clock(chip, ms_card->ms_clock);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = select_card(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -381,14 +371,12 @@
 	int retval;
 
 	retval = select_card(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = switch_clock(chip, ms_card->ms_clock);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -461,9 +449,8 @@
 	}
 
 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
-	if (retval < 0) {
+	if (retval < 0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -482,40 +469,37 @@
 	ms_card->pro_under_formatting = 0;
 
 	retval = ms_power_off_card3v3(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (!chip->ft2_fast_mode)
 		wait_timeout(250);
 
 	retval = enable_card_clock(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (chip->asic_code) {
 		retval = ms_pull_ctl_enable(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_MS_PULL_CTL_BIT | 0x20, 0);
 	}
 
 	if (!chip->ft2_fast_mode) {
 		retval = card_power_on(chip, MS_CARD);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		wait_timeout(150);
 
 #ifdef SUPPORT_OCP
-		if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+		if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 			oc_mask = MS_OC_NOW | MS_OC_EVER;
-		} else {
+		else
 			oc_mask = SD_OC_NOW | SD_OC_EVER;
-		}
+
 		if (chip->ocp_stat & oc_mask) {
 			RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n",
 				     chip->ocp_stat);
@@ -539,9 +523,8 @@
 	RTSX_WRITE_REG(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR);
 
 	retval = ms_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -553,26 +536,23 @@
 	u8 val;
 
 	retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG, 6, NO_WAIT_INT);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		}
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, PPBUF_BASE2 + 2, &val);
 	RTSX_DEBUGP("Type register: 0x%x\n", val);
 	if (val != 0x01) {
-		if (val != 0x02) {
+		if (val != 0x02)
 			ms_card->check_ms_flow = 1;
-		}
+
 		TRACE_RET(chip, STATUS_FAIL);
 	}
 
@@ -587,11 +567,11 @@
 	RTSX_DEBUGP("Class register: 0x%x\n", val);
 	if (val == 0) {
 		RTSX_READ_REG(chip, PPBUF_BASE2, &val);
-		if (val & WRT_PRTCT) {
+		if (val & WRT_PRTCT)
 			chip->card_wp |= MS_CARD;
-		} else {
+		else
 			chip->card_wp &= ~MS_CARD;
-		}
+
 	} else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) {
 		chip->card_wp |= MS_CARD;
 	} else {
@@ -606,11 +586,11 @@
 	if (val == 0) {
 		ms_card->ms_type &= 0x0F;
 	} else if (val == 7) {
-		if (switch_8bit_bus) {
+		if (switch_8bit_bus)
 			ms_card->ms_type |= MS_HG;
-		} else {
+		else
 			ms_card->ms_type &= 0x0F;
-		}
+
 	} else {
 		TRACE_RET(chip, STATUS_FAIL);
 	}
@@ -633,17 +613,15 @@
 
 		for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 			retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-			if (retval == STATUS_SUCCESS) {
+			if (retval == STATUS_SUCCESS)
 				break;
-			}
 		}
-		if (i == MS_MAX_RETRY_COUNT) {
+		if (i == MS_MAX_RETRY_COUNT)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
-		if (k > 100) {
+		if (k > 100)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		k++;
 		wait_timeout(100);
 	} while (!(val & INT_REG_CED));
@@ -653,16 +631,14 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (val & INT_REG_ERR) {
-		if (val & INT_REG_CMDNK) {
+		if (val & INT_REG_CMDNK)
 			chip->card_wp |= (MS_CARD);
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 	/* --  end confirm CPU startup */
 
@@ -681,9 +657,8 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -698,26 +673,22 @@
 	data[1] = 0;
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT, data, 2);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		}
 	}
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_WRITE_REG(chip, MS_CFG, 0x98, MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING);
 	ms_card->ms_type |= MS_8BIT;
 	retval = ms_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, NO_WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -730,19 +701,16 @@
 
 	for (i = 0; i < 3; i++) {
 		retval = ms_prepare_reset(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_identify_media_type(chip, switch_8bit_bus);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_confirm_cpu_startup(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_switch_parallel_bus(chip);
 		if (retval != STATUS_SUCCESS) {
@@ -756,18 +724,16 @@
 		}
 	}
 
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	/* Switch MS-PRO into Parallel mode */
 	RTSX_WRITE_REG(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4);
 	RTSX_WRITE_REG(chip, MS_CFG, PUSH_TIME_ODD, PUSH_TIME_ODD);
 
 	retval = ms_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	/* If MSPro HG Card, We shall try to switch to 8-bit bus */
 	if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) {
@@ -790,9 +756,8 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf[0] = 0;
 	buf[1] = mode;
@@ -802,19 +767,16 @@
 	buf[5] = 0;
 
 	retval = ms_write_bytes(chip, PRO_WRITE_REG , 6, NO_WAIT_INT, buf, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, MS_TRANS_CFG, buf);
-	if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) {
+	if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -836,15 +798,14 @@
 #endif
 
 	retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (CHK_MS8BIT(ms_card)) {
+	if (CHK_MS8BIT(ms_card))
 		data[0] = PARALLEL_8BIT_IF;
-	} else {
+	else
 		data[0] = PARALLEL_4BIT_IF;
-	}
+
 	data[1] = 0;
 
 	data[2] = 0x40;
@@ -856,24 +817,21 @@
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT, data, 8);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		}
 	}
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf = kmalloc(64 * 512, GFP_KERNEL);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			continue;
-		}
+
 		retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
 		if (retval != STATUS_SUCCESS) {
 			kfree(buf);
@@ -885,11 +843,10 @@
 		}
 		retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
 				0x40, WAIT_INT, 0, 0, buf, 64 * 512);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		} else {
+		else
 			rtsx_clear_ms_error(chip);
-		}
 	}
 	if (retval != STATUS_SUCCESS) {
 		kfree(buf);
@@ -963,9 +920,8 @@
 			}
 
 #ifdef SUPPORT_MSXC
-			if (buf[cur_addr_off + 8] == 0x13) {
+			if (buf[cur_addr_off + 8] == 0x13)
 				ms_card->ms_type |= MS_XC;
-			}
 #endif
 #ifdef SUPPORT_PCGL_1P18
 			found_sys_info = 1;
@@ -1046,18 +1002,15 @@
 
 #ifdef SUPPORT_MSXC
 	if (CHK_MSXC(ms_card)) {
-		if (class_code != 0x03) {
+		if (class_code != 0x03)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
-		if (class_code != 0x02) {
+		if (class_code != 0x02)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 #else
-	if (class_code != 0x02) {
+	if (class_code != 0x02)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 #endif
 
 	if (device_type != 0x00) {
@@ -1069,9 +1022,8 @@
 		}
 	}
 
-	if (sub_class & 0xC0) {
+	if (sub_class & 0xC0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n",
 		class_code, device_type, sub_class);
@@ -1117,23 +1069,20 @@
 	if (retval != STATUS_SUCCESS) {
 		if (ms_card->switch_8bit_fail) {
 			retval = ms_pro_reset_flow(chip, 0);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		} else {
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 	}
 
 	retval = ms_read_attribute_info(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 #ifdef XC_POWERCLASS
-	if (CHK_HG8BIT(ms_card)) {
+	if (CHK_HG8BIT(ms_card))
 		change_power_class = 0;
-	}
 
 	if (change_power_class && CHK_MSXC(ms_card)) {
 		u8 power_class_en = chip->ms_power_class_en;
@@ -1141,11 +1090,10 @@
 		RTSX_DEBUGP("power_class_en = 0x%x\n", power_class_en);
 		RTSX_DEBUGP("change_power_class = %d\n", change_power_class);
 
-		if (change_power_class) {
+		if (change_power_class)
 			power_class_en &= (1 << (change_power_class - 1));
-		} else {
+		else
 			power_class_en = 0;
-		}
 
 		if (power_class_en) {
 			u8 power_class_mode = (ms_card->raw_sys_info[46] & 0x18) >> 3;
@@ -1165,16 +1113,14 @@
 
 #ifdef SUPPORT_MAGIC_GATE
 	retval = mg_set_tpc_para_sub(chip, 0, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 #endif
 
-	if (CHK_HG8BIT(ms_card)) {
+	if (CHK_HG8BIT(ms_card))
 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 8;
-	} else {
+	else
 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1185,14 +1131,12 @@
 	u8 val[2];
 
 	retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) {
 		ms_set_err_code(chip, MS_FLASH_READ_ERROR);
@@ -1211,9 +1155,8 @@
 	u8 val, data[10];
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHK_MS4BIT(ms_card)) {
 		/* Parallel interface */
@@ -1233,9 +1176,8 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 
@@ -1244,15 +1186,14 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (val & INT_REG_CMDNK) {
 		ms_set_err_code(chip, MS_CMD_NK);
 		TRACE_RET(chip, STATUS_FAIL);
@@ -1260,20 +1201,18 @@
 	if (val & INT_REG_CED) {
 		if (val & INT_REG_ERR) {
 			retval = ms_read_status_reg(chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 	}
 
 	retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT, data, MS_EXTRA_SIZE);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (buf && buf_len) {
 		if (buf_len > MS_EXTRA_SIZE)
@@ -1291,45 +1230,40 @@
 	int retval, i;
 	u8 val, data[16];
 
-	if (!buf || (buf_len < MS_EXTRA_SIZE)) {
+	if (!buf || (buf_len < MS_EXTRA_SIZE))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6 + MS_EXTRA_SIZE);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(block_addr >> 8);
 	data[3] = (u8)block_addr;
 	data[4] = 0x40;
 	data[5] = page_num;
 
-	for (i = 6; i < MS_EXTRA_SIZE + 6; i++) {
+	for (i = 6; i < MS_EXTRA_SIZE + 6; i++)
 		data[i] = buf[i - 6];
-	}
 
 	retval = ms_write_bytes(chip, WRITE_REG , (6+MS_EXTRA_SIZE), NO_WAIT_INT, data, 16);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (val & INT_REG_CMDNK) {
 		ms_set_err_code(chip, MS_CMD_NK);
 		TRACE_RET(chip, STATUS_FAIL);
@@ -1352,15 +1286,14 @@
 	u8 val, data[6];
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(block_addr >> 8);
 	data[3] = (u8)block_addr;
@@ -1368,20 +1301,18 @@
 	data[5] = page_num;
 
 	retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (val & INT_REG_CMDNK) {
 		ms_set_err_code(chip, MS_CMD_NK);
 		TRACE_RET(chip, STATUS_FAIL);
@@ -1394,9 +1325,9 @@
 				TRACE_RET(chip, STATUS_FAIL);
 			}
 			retval = ms_read_status_reg(chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				ms_set_err_code(chip,  MS_FLASH_WRITE_ERROR);
-			}
+
 		} else {
 			if (!(val & INT_REG_BREQ)) {
 				ms_set_err_code(chip, MS_BREQ_ERROR);
@@ -1406,13 +1337,11 @@
 	}
 
 	retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, 0, NO_WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) {
+	if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1425,22 +1354,20 @@
 	u8 val, data[8], extra[MS_EXTRA_SIZE];
 
 	retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(phy_blk >> 8);
 	data[3] = (u8)phy_blk;
@@ -1450,20 +1377,17 @@
 	data[7] = 0xFF;
 
 	retval = ms_write_bytes(chip, WRITE_REG , 7, NO_WAIT_INT, data, 7);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (val & INT_REG_CMDNK) {
 		ms_set_err_code(chip, MS_CMD_NK);
@@ -1488,17 +1412,16 @@
 	u8 val, data[6];
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(phy_blk >> 8);
 	data[3] = (u8)phy_blk;
@@ -1506,21 +1429,18 @@
 	data[5] = 0;
 
 	retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 ERASE_RTY:
 	retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (val & INT_REG_CMDNK) {
 		if (i < 3) {
@@ -1546,9 +1466,8 @@
 
 static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len)
 {
-	if (!extra || (extra_len < MS_EXTRA_SIZE)) {
+	if (!extra || (extra_len < MS_EXTRA_SIZE))
 		return;
-	}
 
 	memset(extra, 0xFF, MS_EXTRA_SIZE);
 
@@ -1583,9 +1502,8 @@
 		}
 
 		retval = ms_write_extra_data(chip, phy_blk, i, extra, MS_EXTRA_SIZE);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1603,27 +1521,23 @@
 	RTSX_DEBUGP("start_page = %d, end_page = %d\n", start_page, end_page);
 
 	retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_read_status_reg(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, PPBUF_BASE2, &val);
 
 	if (val & BUF_FULL) {
 		retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (!(val & INT_REG_CED)) {
 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
@@ -1640,17 +1554,16 @@
 		ms_read_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE);
 
 		retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 
-		if (CHK_MS4BIT(ms_card)) {
+		if (CHK_MS4BIT(ms_card))
 			data[0] = 0x88;
-		} else {
+		else
 			data[0] = 0x80;
-		}
+
 		data[1] = 0;
 		data[2] = (u8)(old_blk >> 8);
 		data[3] = (u8)old_blk;
@@ -1658,20 +1571,17 @@
 		data[5] = i;
 
 		retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (val & INT_REG_CMDNK) {
 			ms_set_err_code(chip, MS_CMD_NK);
@@ -1689,15 +1599,14 @@
 				}
 
 				retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, 0, NO_WAIT_INT);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 
 				if (uncorrect_flag) {
 					ms_set_page_status(log_blk, setPS_NG, extra, MS_EXTRA_SIZE);
-					if (i == 0) {
+					if (i == 0)
 						extra[0] &= 0xEF;
-					}
+
 					ms_write_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE);
 					RTSX_DEBUGP("page %d : extra[0] = 0x%x\n", i, extra[0]);
 					MS_SET_BAD_BLOCK_FLG(ms_card);
@@ -1710,13 +1619,11 @@
 				for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT; rty_cnt++) {
 					retval = ms_transfer_tpc(chip, MS_TM_NORMAL_WRITE,
 							WRITE_PAGE_DATA, 0, NO_WAIT_INT);
-					if (retval == STATUS_SUCCESS) {
+					if (retval == STATUS_SUCCESS)
 						break;
-					}
 				}
-				if (rty_cnt == MS_MAX_RETRY_COUNT) {
+				if (rty_cnt == MS_MAX_RETRY_COUNT)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 
 			if (!(val & INT_REG_BREQ)) {
@@ -1730,45 +1637,41 @@
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 
-		if (CHK_MS4BIT(ms_card)) {
+		if (CHK_MS4BIT(ms_card))
 			data[0] = 0x88;
-		} else {
+		else
 			data[0] = 0x80;
-		}
+
 		data[1] = 0;
 		data[2] = (u8)(new_blk >> 8);
 		data[3] = (u8)new_blk;
 		data[4] = 0x20;
 		data[5] = i;
 
-		if ((extra[0] & 0x60) != 0x60) {
+		if ((extra[0] & 0x60) != 0x60)
 			data[6] = extra[0];
-		} else {
+		else
 			data[6] = 0xF8;
-		}
+
 		data[6 + 1] = 0xFF;
 		data[6 + 2] = (u8)(log_blk >> 8);
 		data[6 + 3] = (u8)log_blk;
 
-		for (j = 4; j <= MS_EXTRA_SIZE; j++) {
+		for (j = 4; j <= MS_EXTRA_SIZE; j++)
 			data[6 + j] = 0xFF;
-		}
 
 		retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), NO_WAIT_INT, data, 16);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (val & INT_REG_CMDNK) {
 			ms_set_err_code(chip, MS_CMD_NK);
@@ -1784,17 +1687,16 @@
 
 		if (i == 0) {
 			retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			ms_set_err_code(chip, MS_NO_ERROR);
 
-			if (CHK_MS4BIT(ms_card)) {
+			if (CHK_MS4BIT(ms_card))
 				data[0] = 0x88;
-			} else {
+			else
 				data[0] = 0x80;
-			}
+
 			data[1] = 0;
 			data[2] = (u8)(old_blk >> 8);
 			data[3] = (u8)old_blk;
@@ -1804,20 +1706,17 @@
 			data[7] = 0xFF;
 
 			retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 8);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			ms_set_err_code(chip, MS_NO_ERROR);
 			retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			if (val & INT_REG_CMDNK) {
 				ms_set_err_code(chip, MS_CMD_NK);
@@ -1848,28 +1747,24 @@
 #endif
 
 	retval = ms_prepare_reset(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_card->ms_type |= TYPE_MS;
 
 	retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_read_status_reg(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, PPBUF_BASE2, &val);
-	if (val & WRT_PRTCT) {
+	if (val & WRT_PRTCT)
 		chip->card_wp |= MS_CARD;
-	} else {
+	else
 		chip->card_wp &= ~MS_CARD;
-	}
 
 	i = 0;
 
@@ -1913,21 +1808,18 @@
 	}
 
 	retval = ms_read_page(chip, ms_card->boot_block, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	/* Read MS system information as sys_info */
 	rtsx_init_cmd(chip);
 
-	for (i = 0; i < 96; i++) {
+	for (i = 0; i < 96; i++)
 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0);
-	}
 
 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
-	if (retval < 0) {
+	if (retval < 0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ptr = rtsx_get_cmd_data(chip);
 	memcpy(ms_card->raw_sys_info, ptr, 96);
@@ -1938,21 +1830,18 @@
 	rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0);
 	rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0);
 
-	for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; reg_addr++) {
+	for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; reg_addr++)
 		rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
-	}
 
-	for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) {
+	for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++)
 		rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
-	}
 
 	rtsx_add_cmd(chip, READ_REG_CMD, MS_Device_Type, 0, 0);
 	rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0);
 
 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
-	if (retval < 0) {
+	if (retval < 0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ptr = rtsx_get_cmd_data(chip);
 
@@ -1975,9 +1864,8 @@
 		goto RE_SEARCH;
 	}
 
-	if ((ptr[14] == 1) || (ptr[14] == 3)) {
+	if ((ptr[14] == 1) || (ptr[14] == 3))
 		chip->card_wp |= MS_CARD;
-	}
 
 	/* BLOCK_SIZE_0, BLOCK_SIZE_1 */
 	block_size = ((u16)ptr[6] << 8) | ptr[7];
@@ -2026,17 +1914,15 @@
 	/* Switch I/F Mode */
 	if (ptr[15]) {
 		retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		RTSX_WRITE_REG(chip, PPBUF_BASE2, 0xFF, 0x88);
 		RTSX_WRITE_REG(chip, PPBUF_BASE2 + 1, 0xFF, 0);
 
 		retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG , 1, NO_WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		RTSX_WRITE_REG(chip, MS_CFG, 0x58 | MS_NO_CHECK_INT,
 				MS_BUS_WIDTH_4 | PUSH_TIME_ODD | MS_NO_CHECK_INT);
@@ -2044,11 +1930,10 @@
 		ms_card->ms_type |= MS_4BIT;
 	}
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
-	} else {
+	else
 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 1;
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2065,30 +1950,27 @@
 
 	size = ms_card->segment_cnt * sizeof(struct zone_entry);
 	ms_card->segment = vzalloc(size);
-	if (ms_card->segment == NULL) {
+	if (ms_card->segment == NULL)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_read_page(chip, ms_card->boot_block, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, INIT_FAIL);
-	}
 
 	reg_addr = PPBUF_BASE2;
 	for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) {
 		retval = rtsx_read_register(chip, reg_addr++, &val1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, INIT_FAIL);
-		}
+
 		retval = rtsx_read_register(chip, reg_addr++, &val2);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, INIT_FAIL);
-		}
 
 		defect_block = ((u16)val1 << 8) | val2;
-		if (defect_block == 0xFFFF) {
+		if (defect_block == 0xFFFF)
 			break;
-		}
+
 		seg_no = defect_block / 512;
 		ms_card->segment[seg_no].defect_list[ms_card->segment[seg_no].disable_count++] = defect_block;
 	}
@@ -2141,9 +2023,8 @@
 		return;
 
 	segment = &(ms_card->segment[seg_no]);
-	if (segment->l2p_table) {
+	if (segment->l2p_table)
 		segment->l2p_table[log_off] = phy_blk;
-	}
 }
 
 static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk)
@@ -2156,9 +2037,9 @@
 	segment = &(ms_card->segment[seg_no]);
 
 	segment->free_table[segment->set_index++] = phy_blk;
-	if (segment->set_index >= MS_FREE_TABLE_CNT) {
+	if (segment->set_index >= MS_FREE_TABLE_CNT)
 		segment->set_index = 0;
-	}
+
 	segment->unused_blk_cnt++;
 }
 
@@ -2175,9 +2056,9 @@
 
 	phy_blk = segment->free_table[segment->get_index];
 	segment->free_table[segment->get_index++] = 0xFFFF;
-	if (segment->get_index >= MS_FREE_TABLE_CNT) {
+	if (segment->get_index >= MS_FREE_TABLE_CNT)
 		segment->get_index = 0;
-	}
+
 	segment->unused_blk_cnt--;
 
 	return phy_blk;
@@ -2199,27 +2080,27 @@
 
 	if (us1 != us2) {
 		if (us1 == 0) {
-			if (!(chip->card_wp & MS_CARD)) {
+			if (!(chip->card_wp & MS_CARD))
 				ms_erase_block(chip, tmp_blk);
-			}
+
 			ms_set_unused_block(chip, tmp_blk);
 			segment->l2p_table[log_off] = phy_blk;
 		} else {
-			if (!(chip->card_wp & MS_CARD)) {
+			if (!(chip->card_wp & MS_CARD))
 				ms_erase_block(chip, phy_blk);
-			}
+
 			ms_set_unused_block(chip, phy_blk);
 		}
 	} else {
 		if (phy_blk < tmp_blk) {
-			if (!(chip->card_wp & MS_CARD)) {
+			if (!(chip->card_wp & MS_CARD))
 				ms_erase_block(chip, phy_blk);
-			}
+
 			ms_set_unused_block(chip, phy_blk);
 		} else {
-			if (!(chip->card_wp & MS_CARD)) {
+			if (!(chip->card_wp & MS_CARD))
 				ms_erase_block(chip, tmp_blk);
-			}
+
 			ms_set_unused_block(chip, tmp_blk);
 			segment->l2p_table[log_off] = phy_blk;
 		}
@@ -2240,9 +2121,8 @@
 
 	if (ms_card->segment == NULL) {
 		retval = ms_init_l2p_tbl(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, retval);
-		}
 	}
 
 	if (ms_card->segment[seg_no].build_flag) {
@@ -2250,27 +2130,24 @@
 		return STATUS_SUCCESS;
 	}
 
-	if (seg_no == 0) {
+	if (seg_no == 0)
 		table_size = 494;
-	} else {
+	else
 		table_size = 496;
-	}
 
 	segment = &(ms_card->segment[seg_no]);
 
 	if (segment->l2p_table == NULL) {
 		segment->l2p_table = (u16 *)vmalloc(table_size * 2);
-		if (segment->l2p_table == NULL) {
+		if (segment->l2p_table == NULL)
 			TRACE_GOTO(chip, BUILD_FAIL);
-		}
 	}
 	memset((u8 *)(segment->l2p_table), 0xff, table_size * 2);
 
 	if (segment->free_table == NULL) {
 		segment->free_table = (u16 *)vmalloc(MS_FREE_TABLE_CNT * 2);
-		if (segment->free_table == NULL) {
+		if (segment->free_table == NULL)
 			TRACE_GOTO(chip, BUILD_FAIL);
-		}
 	}
 	memset((u8 *)(segment->free_table), 0xff, MS_FREE_TABLE_CNT * 2);
 
@@ -2368,13 +2245,11 @@
 
 	/* Logical Address Confirmation Process */
 	if (seg_no == ms_card->segment_cnt - 1) {
-		if (segment->unused_blk_cnt < 2) {
+		if (segment->unused_blk_cnt < 2)
 			chip->card_wp |= MS_CARD;
-		}
 	} else {
-		if (segment->unused_blk_cnt < 1) {
+		if (segment->unused_blk_cnt < 1)
 			chip->card_wp |= MS_CARD;
-		}
 	}
 
 	if (chip->card_wp & MS_CARD)
@@ -2388,9 +2263,9 @@
 				return STATUS_SUCCESS;
 			}
 			retval = ms_init_page(chip, phy_blk, log_blk, 0, 1);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_GOTO(chip, BUILD_FAIL);
-			}
+
 			segment->l2p_table[log_blk-ms_start_idx[seg_no]] = phy_blk;
 			if (seg_no == ms_card->segment_cnt - 1) {
 				if (segment->unused_blk_cnt < 2) {
@@ -2419,16 +2294,14 @@
 				phy_blk = ms_get_unused_block(chip, 0);
 				retval = ms_copy_page(chip, tmp_blk, phy_blk,
 						log_blk, 0, ms_card->page_off + 1);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 
 				segment->l2p_table[log_blk] = phy_blk;
 
 				retval = ms_set_bad_block(chip, tmp_blk);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 		}
 	}
@@ -2458,14 +2331,12 @@
 	memset(ms_card, 0, sizeof(struct ms_info));
 
 	retval = enable_card_clock(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = select_card(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_card->ms_type = 0;
 
@@ -2473,27 +2344,24 @@
 	if (retval != STATUS_SUCCESS) {
 		if (ms_card->check_ms_flow) {
 			retval = reset_ms(chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		} else {
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 	}
 
 	retval = ms_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (!CHK_MSPRO(ms_card)) {
 		/* Build table for the last segment,
 		 * to check if L2P table block exists, erasing it
 		 */
 		retval = ms_build_l2p_tbl(chip, ms_card->total_block / 512 - 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	RTSX_DEBUGP("ms_card->ms_type = 0x%x\n", ms_card->ms_type);
@@ -2520,9 +2388,8 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2556,21 +2423,18 @@
 	RTSX_DEBUGP("--%s--\n", __func__);
 
 	if (chip->asic_code) {
-		if (ms_card->ms_clock > 30) {
+		if (ms_card->ms_clock > 30)
 			ms_card->ms_clock -= 20;
-		}
 	} else {
-		if (ms_card->ms_clock == CLK_80) {
+		if (ms_card->ms_clock == CLK_80)
 			ms_card->ms_clock = CLK_60;
-		} else if (ms_card->ms_clock == CLK_60) {
+		else if (ms_card->ms_clock == CLK_60)
 			ms_card->ms_clock = CLK_40;
-		}
 	}
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2616,15 +2480,13 @@
 	}
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+	if (srb->sc_data_direction == DMA_FROM_DEVICE)
 		trans_mode = MS_TM_AUTO_READ;
-	} else {
+	else
 		trans_mode = MS_TM_AUTO_WRITE;
-	}
 
 	RTSX_READ_REG(chip, MS_TRANS_CFG, &val);
 
@@ -2639,9 +2501,8 @@
 			ms_card->total_sec_cnt = 0;
 			if (val & MS_INT_BREQ) {
 				retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 
 				rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH);
 			}
@@ -2651,17 +2512,16 @@
 	if (!ms_card->seq_mode) {
 		ms_card->total_sec_cnt = 0;
 		if (sector_cnt >= SEQ_START_CRITERIA) {
-			if ((ms_card->capacity - start_sector) > 0xFE00) {
+			if ((ms_card->capacity - start_sector) > 0xFE00)
 				count = 0xFE00;
-			} else {
+			else
 				count = (u16)(ms_card->capacity - start_sector);
-			}
+
 			if (count > sector_cnt) {
-				if (mode_2k) {
+				if (mode_2k)
 					ms_card->seq_mode |= MODE_2K_SEQ;
-				} else {
+				else
 					ms_card->seq_mode |= MODE_512_SEQ;
-				}
 			}
 		} else {
 			count = sector_cnt;
@@ -2686,9 +2546,9 @@
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 
-		if (val & MS_INT_BREQ) {
+		if (val & MS_INT_BREQ)
 			ms_send_cmd(chip, PRO_STOP, WAIT_INT);
-		}
+
 		if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
 			RTSX_DEBUGP("MSPro CRC error, tune clock!\n");
 			chip->rw_need_retry = 1;
@@ -2739,11 +2599,10 @@
 		TRACE_RET(chip, STATUS_FAIL);
 	}
 
-	if (short_data_len >= 256) {
+	if (short_data_len >= 256)
 		cnt = 0;
-	} else {
+	else
 		cnt = (u8)short_data_len;
-	}
 
 	retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, MS_NO_CHECK_INT);
 	if (retval != STATUS_SUCCESS) {
@@ -2778,9 +2637,8 @@
 			ms_card->format_status = FORMAT_FAIL;
 			TRACE_RET(chip, STATUS_FAIL);
 		}
-		if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ | MS_INT_ERR)) {
+		if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ | MS_INT_ERR))
 			break;
-		}
 
 		wait_timeout(1);
 	}
@@ -2843,14 +2701,12 @@
 	RTSX_DEBUGP("--%s--\n", __func__);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	memset(buf, 0, 2);
 	switch (short_data_len) {
@@ -2874,25 +2730,22 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (quick_format) {
+	if (quick_format)
 		para = 0x0000;
-	} else {
+	else
 		para = 0x0001;
-	}
+
 	retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, MS_TRANS_CFG, &tmp);
 
-	if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) {
+	if (tmp & (MS_INT_CMDNK | MS_INT_ERR))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) {
 		ms_card->pro_under_formatting = 1;
@@ -2930,15 +2783,14 @@
 	}
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(phy_blk >> 8);
 	data[3] = (u8)phy_blk;
@@ -2950,16 +2802,14 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 
 	retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ptr = buf;
 
@@ -2972,9 +2822,9 @@
 		}
 
 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		if (val & INT_REG_CMDNK) {
 			ms_set_err_code(chip, MS_CMD_NK);
 			TRACE_RET(chip, STATUS_FAIL);
@@ -3006,15 +2856,14 @@
 		if (page_addr == (end_page - 1)) {
 			if (!(val & INT_REG_CED)) {
 				retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 
 			retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			if (!(val & INT_REG_CED)) {
 				ms_set_err_code(chip, MS_FLASH_READ_ERROR);
 				TRACE_RET(chip, STATUS_FAIL);
@@ -3079,15 +2928,14 @@
 
 	if (!start_page) {
 		retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
-		if (CHK_MS4BIT(ms_card)) {
+		if (CHK_MS4BIT(ms_card))
 			data[0] = 0x88;
-		} else {
+		else
 			data[0] = 0x80;
-		}
+
 		data[1] = 0;
 		data[2] = (u8)(old_blk >> 8);
 		data[3] = (u8)old_blk;
@@ -3097,74 +2945,66 @@
 		data[7] = 0xFF;
 
 		retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 8);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, NO_WAIT_INT);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, (6 + MS_EXTRA_SIZE));
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ms_set_err_code(chip, MS_NO_ERROR);
 
-	if (CHK_MS4BIT(ms_card)) {
+	if (CHK_MS4BIT(ms_card))
 		data[0] = 0x88;
-	} else {
+	else
 		data[0] = 0x80;
-	}
+
 	data[1] = 0;
 	data[2] = (u8)(new_blk >> 8);
 	data[3] = (u8)new_blk;
-	if ((end_page - start_page) == 1) {
+	if ((end_page - start_page) == 1)
 		data[4] = 0x20;
-	} else {
+	else
 		data[4] = 0;
-	}
+
 	data[5] = start_page;
 	data[6] = 0xF8;
 	data[7] = 0xFF;
 	data[8] = (u8)(log_blk >> 8);
 	data[9] = (u8)log_blk;
 
-	for (i = 0x0A; i < 0x10; i++) {
+	for (i = 0x0A; i < 0x10; i++)
 		data[i] = 0xFF;
-	}
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE, NO_WAIT_INT, data, 16);
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	ptr = buf;
 	for (page_addr = start_page; page_addr < end_page; page_addr++) {
@@ -3210,17 +3050,15 @@
 			ms_set_err_code(chip, MS_TO_ERROR);
 			rtsx_clear_ms_error(chip);
 
-			if (retval == -ETIMEDOUT) {
+			if (retval == -ETIMEDOUT)
 				TRACE_RET(chip, STATUS_TIMEDOUT);
-			} else {
+			else
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 
 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if ((end_page - start_page) == 1) {
 			if (!(val & INT_REG_CED)) {
@@ -3231,15 +3069,13 @@
 			if (page_addr == (end_page - 1)) {
 				if (!(val & INT_REG_CED)) {
 					retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT);
-					if (retval != STATUS_SUCCESS) {
+					if (retval != STATUS_SUCCESS)
 						TRACE_RET(chip, STATUS_FAIL);
-					}
 				}
 
 				retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 
 			if ((page_addr == (end_page - 1)) || (page_addr == ms_card->page_off)) {
@@ -3266,9 +3102,8 @@
 
 	retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
 			page_off, ms_card->page_off + 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	seg_no = old_blk >> 9;
 
@@ -3277,9 +3112,8 @@
 		ms_set_bad_block(chip, old_blk);
 	} else {
 		retval = ms_erase_block(chip, old_blk);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			ms_set_unused_block(chip, old_blk);
-		}
 	}
 
 	ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk);
@@ -3294,9 +3128,8 @@
 
 	if (start_page) {
 		retval = ms_copy_page(chip, old_blk, new_blk, log_blk, 0, start_page);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -3311,17 +3144,15 @@
 
 	if (delay_write->delay_write_flag) {
 		retval = ms_set_init_para(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		delay_write->delay_write_flag = 0;
 		retval = ms_finish_write(chip,
 				delay_write->old_phyblock, delay_write->new_phyblock,
 				delay_write->logblock, delay_write->pageoff);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -3330,11 +3161,10 @@
 
 static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip)
 {
-	if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+	if (srb->sc_data_direction == DMA_FROM_DEVICE)
 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
-	} else {
+	else
 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR);
-	}
 }
 
 static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 sector_cnt)
@@ -3449,11 +3279,11 @@
 	RTSX_DEBUGP("seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", seg_no, old_blk, new_blk);
 
 	while (total_sec_cnt) {
-		if ((start_page + total_sec_cnt) > (ms_card->page_off + 1)) {
+		if ((start_page + total_sec_cnt) > (ms_card->page_off + 1))
 			end_page = ms_card->page_off + 1;
-		} else {
+		else
 			end_page = start_page + (u8)total_sec_cnt;
-		}
+
 		page_cnt = end_page - start_page;
 
 		RTSX_DEBUGP("start_page = %d, end_page = %d, page_cnt = %d\n",
@@ -3482,9 +3312,9 @@
 		if (srb->sc_data_direction == DMA_TO_DEVICE) {
 			if (end_page == (ms_card->page_off + 1)) {
 				retval = ms_erase_block(chip, old_blk);
-				if (retval == STATUS_SUCCESS) {
+				if (retval == STATUS_SUCCESS)
 					ms_set_unused_block(chip, old_blk);
-				}
+
 				ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk);
 			}
 		}
@@ -3565,11 +3395,10 @@
 	struct ms_info *ms_card = &(chip->ms_card);
 	int retval;
 
-	if (CHK_MSPRO(ms_card)) {
+	if (CHK_MSPRO(ms_card))
 		retval = mspro_rw_multi_sector(srb, chip, start_sector, sector_cnt);
-	} else {
+	else
 		retval = ms_rw_multi_sector(srb, chip, start_sector, sector_cnt);
-	}
 
 	return retval;
 }
@@ -3609,14 +3438,12 @@
 	rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED);
 
 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	val = *rtsx_get_cmd_data(chip);
-	if (val & MS_INT_ERR) {
+	if (val & MS_INT_ERR)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -3678,9 +3505,8 @@
 		if (retval == STATUS_SUCCESS)
 			break;
 	}
-	if (i == MS_MAX_RETRY_COUNT) {
+	if (i == MS_MAX_RETRY_COUNT)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (check_ms_err(chip)) {
 		rtsx_clear_ms_error(chip);
@@ -3697,14 +3523,13 @@
 
 	RTSX_DEBUGP("--%s--\n", __func__);
 
-	if (type == 0) {
+	if (type == 0)
 		retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1);
-	} else {
+	else
 		retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
-	}
-	if (retval != STATUS_SUCCESS) {
+
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf[0] = 0;
 	buf[1] = 0;
@@ -3715,9 +3540,8 @@
 		buf[5] = mg_entry_num;
 	}
 	retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6, NO_WAIT_INT, buf, 6);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -3739,9 +3563,8 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = mg_send_ex_cmd(chip, MG_SET_LID, 0);
 	if (retval != STATUS_SUCCESS) {
@@ -3751,9 +3574,9 @@
 
 	memset(buf1, 0, 32);
 	rtsx_stor_get_xfer_buf(buf2, min(12, (int)scsi_bufflen(srb)), srb);
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++)
 		buf1[8+i] = buf2[4+i];
-	}
+
 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf1, 32);
 	if (retval != STATUS_SUCCESS) {
 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
@@ -3780,14 +3603,12 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf = kmalloc(1540, GFP_KERNEL);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	buf[0] = 0x04;
 	buf[1] = 0x1A;
@@ -3835,9 +3656,8 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = mg_send_ex_cmd(chip, MG_GET_ID, 0);
 	if (retval != STATUS_SUCCESS) {
@@ -3875,12 +3695,12 @@
 	bufflen = min(12, (int)scsi_bufflen(srb));
 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++)
 		buf[i] = buf[4+i];
-	}
-	for (i = 0; i < 24; i++) {
+
+	for (i = 0; i < 24; i++)
 		buf[8+i] = 0;
-	}
+
 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA,
 				32, WAIT_INT, buf, 32);
 	if (retval != STATUS_SUCCESS) {
@@ -3911,9 +3731,8 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0);
 	if (retval != STATUS_SUCCESS) {
@@ -3968,9 +3787,8 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0);
 	if (retval != STATUS_SUCCESS) {
@@ -3981,12 +3799,12 @@
 	bufflen = min(12, (int)scsi_bufflen(srb));
 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++)
 		buf[i] = buf[4+i];
-	}
-	for (i = 0; i < 24; i++) {
+
+	for (i = 0; i < 24; i++)
 		buf[8+i] = 0;
-	}
+
 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf, 32);
 	if (retval != STATUS_SUCCESS) {
 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
@@ -4016,14 +3834,12 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf = kmalloc(1028, GFP_KERNEL);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	buf[0] = 0x04;
 	buf[1] = 0x02;
@@ -4073,14 +3889,12 @@
 	ms_cleanup_work(chip);
 
 	retval = ms_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	buf = kmalloc(1028, GFP_KERNEL);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	bufflen = min(1028, (int)scsi_bufflen(srb));
 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
@@ -4088,11 +3902,10 @@
 	retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num);
 	if (retval != STATUS_SUCCESS) {
 		if (ms_card->mg_auth == 0) {
-			if ((buf[5] & 0xC0) != 0) {
+			if ((buf[5] & 0xC0) != 0)
 				set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
-			} else {
+			else
 				set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
-			}
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
 		}
@@ -4121,11 +3934,10 @@
 		if ((retval < 0) || check_ms_err(chip)) {
 			rtsx_clear_ms_error(chip);
 			if (ms_card->mg_auth == 0) {
-				if ((buf[5] & 0xC0) != 0) {
+				if ((buf[5] & 0xC0) != 0)
 					set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
-				} else {
+				else
 					set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
-				}
 			} else {
 				set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
 			}
@@ -4139,11 +3951,10 @@
 	if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) {
 		rtsx_clear_ms_error(chip);
 		if (ms_card->mg_auth == 0) {
-			if ((buf[5] & 0xC0) != 0) {
+			if ((buf[5] & 0xC0) != 0)
 				set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
-			} else {
+			else
 				set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
-			}
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
 		}
@@ -4187,14 +3998,13 @@
 	int retval;
 
 	retval = disable_card_clock(chip, MS_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (chip->asic_code) {
 		retval = ms_pull_ctl_disable(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		RTSX_WRITE_REG(chip, FPGA_PULL_CTL,
 			FPGA_MS_PULL_CTL_BIT | 0x20, FPGA_MS_PULL_CTL_BIT);
@@ -4202,9 +4012,8 @@
 	RTSX_WRITE_REG(chip, CARD_OE, MS_OUTPUT_EN, 0);
 	if (!chip->ft2_fast_mode) {
 		retval = card_power_off(chip, MS_CARD);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -4234,9 +4043,8 @@
 #endif
 
 	retval = ms_power_off_card3v3(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c
index 5fb05a2..afe9c2e 100644
--- a/drivers/staging/rts_pstor/rtsx.c
+++ b/drivers/staging/rts_pstor/rtsx.c
@@ -20,6 +20,8 @@
  *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/blkdev.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
@@ -170,14 +172,14 @@
 
 	/* check for state-transition errors */
 	if (chip->srb != NULL) {
-		printk(KERN_ERR "Error in %s: chip->srb = %p\n",
+		dev_err(&dev->pci->dev, "Error in %s: chip->srb = %p\n",
 			__func__, chip->srb);
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
 	/* fail the command if we are disconnecting */
 	if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
-		printk(KERN_INFO "Fail command during disconnect\n");
+		dev_info(&dev->pci->dev, "Fail command during disconnect\n");
 		srb->result = DID_NO_CONNECT << 16;
 		done(srb);
 		return 0;
@@ -204,14 +206,14 @@
 	struct rtsx_dev *dev = host_to_rtsx(host);
 	struct rtsx_chip *chip = dev->chip;
 
-	printk(KERN_INFO "%s called\n", __func__);
+	dev_info(&dev->pci->dev, "%s called\n", __func__);
 
 	scsi_lock(host);
 
 	/* Is this command still active? */
 	if (chip->srb != srb) {
 		scsi_unlock(host);
-		printk(KERN_INFO "-- nothing to abort\n");
+		dev_info(&dev->pci->dev, "-- nothing to abort\n");
 		return FAILED;
 	}
 
@@ -230,8 +232,9 @@
 static int device_reset(struct scsi_cmnd *srb)
 {
 	int result = 0;
+	struct rtsx_dev *dev = host_to_rtsx(srb->device->host);
 
-	printk(KERN_INFO "%s called\n", __func__);
+	dev_info(&dev->pci->dev, "%s called\n", __func__);
 
 	return result < 0 ? FAILED : SUCCESS;
 }
@@ -240,8 +243,9 @@
 static int bus_reset(struct scsi_cmnd *srb)
 {
 	int result = 0;
+	struct rtsx_dev *dev = host_to_rtsx(srb->device->host);
 
-	printk(KERN_INFO "%s called\n", __func__);
+	dev_info(&dev->pci->dev, "%s called\n", __func__);
 
 	return result < 0 ? FAILED : SUCCESS;
 }
@@ -303,14 +307,15 @@
 {
 	struct rtsx_chip *chip = dev->chip;
 
-	printk(KERN_INFO "%s: chip->msi_en = %d, pci->irq = %d\n",
-			__func__, chip->msi_en, dev->pci->irq);
+	dev_info(&dev->pci->dev, "%s: chip->msi_en = %d, pci->irq = %d\n",
+		 __func__, chip->msi_en, dev->pci->irq);
 
 	if (request_irq(dev->pci->irq, rtsx_interrupt,
 			chip->msi_en ? 0 : IRQF_SHARED,
 			CR_DRIVER_NAME, dev)) {
-		printk(KERN_ERR "rtsx: unable to grab IRQ %d, "
-		       "disabling device\n", dev->pci->irq);
+		dev_err(&dev->pci->dev,
+			"rtsx: unable to grab IRQ %d, disabling device\n",
+			dev->pci->irq);
 		return -1;
 	}
 
@@ -347,12 +352,8 @@
 	struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
 	struct rtsx_chip *chip;
 
-	printk(KERN_INFO "Ready to suspend\n");
-
-	if (!dev) {
-		printk(KERN_ERR "Invalid memory\n");
+	if (!dev)
 		return 0;
-	}
 
 	/* lock the device pointers */
 	mutex_lock(&(dev->dev_mutex));
@@ -386,12 +387,8 @@
 	struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
 	struct rtsx_chip *chip;
 
-	printk(KERN_INFO "Ready to resume\n");
-
-	if (!dev) {
-		printk(KERN_ERR "Invalid memory\n");
+	if (!dev)
 		return 0;
-	}
 
 	chip = dev->chip;
 
@@ -401,8 +398,9 @@
 	pci_set_power_state(pci, PCI_D0);
 	pci_restore_state(pci);
 	if (pci_enable_device(pci) < 0) {
-		printk(KERN_ERR "%s: pci_enable_device failed, "
-		       "disabling device\n", CR_DRIVER_NAME);
+		dev_err(&dev->pci->dev,
+			"%s: pci_enable_device failed, disabling device\n",
+			CR_DRIVER_NAME);
 		/* unlock the device pointers */
 		mutex_unlock(&dev->dev_mutex);
 		return -EIO;
@@ -435,12 +433,8 @@
 	struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
 	struct rtsx_chip *chip;
 
-	printk(KERN_INFO "Ready to shutdown\n");
-
-	if (!dev) {
-		printk(KERN_ERR "Invalid memory\n");
+	if (!dev)
 		return;
-	}
 
 	chip = dev->chip;
 
@@ -475,7 +469,7 @@
 
 		/* if the device has disconnected, we are free to exit */
 		if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
-			printk(KERN_INFO "-- rtsx-control exiting\n");
+			dev_info(&dev->pci->dev, "-- rtsx-control exiting\n");
 			mutex_unlock(&dev->dev_mutex);
 			break;
 		}
@@ -495,7 +489,7 @@
 		 * is UNKNOWN
 		 */
 		if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
-			printk(KERN_ERR "UNKNOWN data direction\n");
+			dev_err(&dev->pci->dev, "UNKNOWN data direction\n");
 			chip->srb->result = DID_ERROR << 16;
 		}
 
@@ -503,14 +497,14 @@
 		 * the maximum known LUN
 		 */
 		else if (chip->srb->device->id) {
-			printk(KERN_ERR "Bad target number (%d:%d)\n",
+			dev_err(&dev->pci->dev, "Bad target number (%d:%d)\n",
 				chip->srb->device->id,
 				chip->srb->device->lun);
 			chip->srb->result = DID_BAD_TARGET << 16;
 		}
 
 		else if (chip->srb->device->lun > chip->max_lun) {
-			printk(KERN_ERR "Bad LUN (%d:%d)\n",
+			dev_err(&dev->pci->dev, "Bad LUN (%d:%d)\n",
 				chip->srb->device->id,
 				chip->srb->device->lun);
 			chip->srb->result = DID_BAD_TARGET << 16;
@@ -534,7 +528,7 @@
 			chip->srb->scsi_done(chip->srb);
 		} else {
 SkipForAbort:
-			printk(KERN_ERR "scsi command aborted\n");
+			dev_err(&dev->pci->dev, "scsi command aborted\n");
 		}
 
 		if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
@@ -594,7 +588,7 @@
 
 		/* if the device has disconnected, we are free to exit */
 		if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
-			printk(KERN_INFO "-- rtsx-polling exiting\n");
+			dev_info(&dev->pci->dev, "-- rtsx-polling exiting\n");
 			mutex_unlock(&dev->dev_mutex);
 			break;
 		}
@@ -683,13 +677,13 @@
 /* Release all our dynamic resources */
 static void rtsx_release_resources(struct rtsx_dev *dev)
 {
-	printk(KERN_INFO "-- %s\n", __func__);
+	dev_info(&dev->pci->dev, "-- %s\n", __func__);
 
 	/* Tell the control thread to exit.  The SCSI host must
 	 * already have been removed so it won't try to queue
 	 * any more commands.
 	 */
-	printk(KERN_INFO "-- sending exit command to thread\n");
+	dev_info(&dev->pci->dev, "-- sending exit command to thread\n");
 	complete(&dev->cmnd_ready);
 	if (dev->ctl_thread)
 		wait_for_completion(&dev->control_exit);
@@ -774,8 +768,9 @@
 
 	/* Wait for the timeout to expire or for a disconnect */
 	if (delay_use > 0) {
-		printk(KERN_INFO "%s: waiting for device "
-				"to settle before scanning\n", CR_DRIVER_NAME);
+		dev_info(&dev->pci->dev,
+			 "%s: waiting for device to settle before scanning\n",
+			 CR_DRIVER_NAME);
 		wait_event_interruptible_timeout(dev->delay_wait,
 				rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT),
 				delay_use * HZ);
@@ -784,7 +779,8 @@
 	/* If the device is still connected, perform the scanning */
 	if (!rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
 		scsi_scan_host(rtsx_to_host(dev));
-		printk(KERN_INFO "%s: device scan complete\n", CR_DRIVER_NAME);
+		dev_info(&dev->pci->dev, "%s: device scan complete\n",
+			 CR_DRIVER_NAME);
 
 		/* Should we unbind if no devices were detected? */
 	}
@@ -906,14 +902,14 @@
 
 	err = pci_enable_device(pci);
 	if (err < 0) {
-		printk(KERN_ERR "PCI enable device failed!\n");
+		dev_err(&pci->dev, "PCI enable device failed!\n");
 		return err;
 	}
 
 	err = pci_request_regions(pci, CR_DRIVER_NAME);
 	if (err < 0) {
-		printk(KERN_ERR "PCI request regions for %s failed!\n",
-		       CR_DRIVER_NAME);
+		dev_err(&pci->dev, "PCI request regions for %s failed!\n",
+			CR_DRIVER_NAME);
 		pci_disable_device(pci);
 		return err;
 	}
@@ -924,7 +920,7 @@
 	 */
 	host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev));
 	if (!host) {
-		printk(KERN_ERR "Unable to allocate the scsi host\n");
+		dev_err(&pci->dev, "Unable to allocate the scsi host\n");
 		pci_release_regions(pci);
 		pci_disable_device(pci);
 		return -ENOMEM;
@@ -949,12 +945,12 @@
 	dev->pci = pci;
 	dev->irq = -1;
 
-	printk(KERN_INFO "Resource length: 0x%x\n",
-	       (unsigned int)pci_resource_len(pci, 0));
+	dev_info(&pci->dev, "Resource length: 0x%x\n",
+		 (unsigned int)pci_resource_len(pci, 0));
 	dev->addr = pci_resource_start(pci, 0);
 	dev->remap_addr = ioremap_nocache(dev->addr, pci_resource_len(pci, 0));
 	if (dev->remap_addr == NULL) {
-		printk(KERN_ERR "ioremap error\n");
+		dev_err(&pci->dev, "ioremap error\n");
 		err = -ENXIO;
 		goto errout;
 	}
@@ -963,13 +959,13 @@
 	 * Using "unsigned long" cast here to eliminate gcc warning in
 	 * 64-bit system
 	 */
-	printk(KERN_INFO "Original address: 0x%lx, remapped address: 0x%lx\n",
-	       (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));
+	dev_info(&pci->dev, "Original address: 0x%lx, remapped address: 0x%lx\n",
+		 (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));
 
 	dev->rtsx_resv_buf = dma_alloc_coherent(&(pci->dev), RTSX_RESV_BUF_LEN,
 			&(dev->rtsx_resv_buf_addr), GFP_KERNEL);
 	if (dev->rtsx_resv_buf == NULL) {
-		printk(KERN_ERR "alloc dma buffer fail\n");
+		dev_err(&pci->dev, "alloc dma buffer fail\n");
 		err = -ENXIO;
 		goto errout;
 	}
@@ -983,7 +979,7 @@
 
 	rtsx_init_options(dev->chip);
 
-	printk(KERN_INFO "pci->irq = %d\n", pci->irq);
+	dev_info(&pci->dev, "pci->irq = %d\n", pci->irq);
 
 	if (dev->chip->msi_en) {
 		if (pci_enable_msi(pci) < 0)
@@ -1008,7 +1004,7 @@
 	/* Start up our control thread */
 	th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
 	if (IS_ERR(th)) {
-		printk(KERN_ERR "Unable to start control thread\n");
+		dev_err(&pci->dev, "Unable to start control thread\n");
 		err = PTR_ERR(th);
 		goto errout;
 	}
@@ -1016,14 +1012,14 @@
 
 	err = scsi_add_host(host, &pci->dev);
 	if (err) {
-		printk(KERN_ERR "Unable to add the scsi host\n");
+		dev_err(&pci->dev, "Unable to add the scsi host\n");
 		goto errout;
 	}
 
 	/* Start up the thread for delayed SCSI-device scanning */
 	th = kthread_run(rtsx_scan_thread, dev, "rtsx-scan");
 	if (IS_ERR(th)) {
-		printk(KERN_ERR "Unable to start the device-scanning thread\n");
+		dev_err(&pci->dev, "Unable to start the device-scanning thread\n");
 		complete(&dev->scanning_done);
 		quiesce_and_remove_host(dev);
 		err = PTR_ERR(th);
@@ -1033,7 +1029,7 @@
 	/* Start up the thread for polling thread */
 	th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
 	if (IS_ERR(th)) {
-		printk(KERN_ERR "Unable to start the device-polling thread\n");
+		dev_err(&pci->dev, "Unable to start the device-polling thread\n");
 		quiesce_and_remove_host(dev);
 		err = PTR_ERR(th);
 		goto errout;
@@ -1046,7 +1042,7 @@
 
 	/* We come here if there are any problems */
 errout:
-	printk(KERN_ERR "rtsx_probe() failed\n");
+	dev_err(&pci->dev, "rtsx_probe() failed\n");
 	release_everything(dev);
 
 	return err;
@@ -1057,7 +1053,7 @@
 {
 	struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
 
-	printk(KERN_INFO "rtsx_remove() called\n");
+	dev_info(&pci->dev, "rtsx_remove() called\n");
 
 	quiesce_and_remove_host(dev);
 	release_everything(dev);
@@ -1090,18 +1086,18 @@
 
 static int __init rtsx_init(void)
 {
-	printk(KERN_INFO "Initializing Realtek PCIE storage driver...\n");
+	pr_info("Initializing Realtek PCIE storage driver...\n");
 
 	return pci_register_driver(&driver);
 }
 
 static void __exit rtsx_exit(void)
 {
-	printk(KERN_INFO "rtsx_exit() called\n");
+	pr_info("rtsx_exit() called\n");
 
 	pci_unregister_driver(&driver);
 
-	printk(KERN_INFO "%s module exit\n", CR_DRIVER_NAME);
+	pr_info("%s module exit\n", CR_DRIVER_NAME);
 }
 
 module_init(rtsx_init)
diff --git a/drivers/staging/rts_pstor/rtsx_card.c b/drivers/staging/rts_pstor/rtsx_card.c
index 4f971f2..539aa6a 100644
--- a/drivers/staging/rts_pstor/rtsx_card.c
+++ b/drivers/staging/rts_pstor/rtsx_card.c
@@ -309,11 +309,10 @@
 		if (chip->chip_insert_with_sdio) {
 			chip->chip_insert_with_sdio = 0;
 
-			if (CHECK_PID(chip, 0x5288)) {
+			if (CHECK_PID(chip, 0x5288))
 				rtsx_write_register(chip, 0xFE5A, 0x08, 0x00);
-			} else {
+			else
 				rtsx_write_register(chip, 0xFE70, 0x80, 0x00);
-			}
 		}
 
 		rtsx_write_register(chip, SDIO_CTRL, SDIO_CD_CTRL, 0);
@@ -379,11 +378,10 @@
 	if (chip->need_reset & XD_CARD) {
 		chip->card_exist |= XD_CARD;
 
-		if (chip->xd_show_cnt >= MAX_SHOW_CNT) {
+		if (chip->xd_show_cnt >= MAX_SHOW_CNT)
 			do_reset_xd_card(chip);
-		} else {
+		else
 			chip->xd_show_cnt++;
-		}
 	}
 	if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) {
 		if (chip->card_exist & XD_CARD) {
@@ -404,11 +402,10 @@
 	if (chip->need_reset & MS_CARD) {
 		chip->card_exist |= MS_CARD;
 
-		if (chip->ms_show_cnt >= MAX_SHOW_CNT) {
+		if (chip->ms_show_cnt >= MAX_SHOW_CNT)
 			do_reset_ms_card(chip);
-		} else {
+		else
 			chip->ms_show_cnt++;
-		}
 	}
 }
 
@@ -473,13 +470,12 @@
 				release_map |= MS_CARD;
 		}
 	} else {
-		if (chip->int_reg & XD_EXIST) {
+		if (chip->int_reg & XD_EXIST)
 			reset_map |= XD_CARD;
-		} else if (chip->int_reg & SD_EXIST) {
+		else if (chip->int_reg & SD_EXIST)
 			reset_map |= SD_CARD;
-		} else if (chip->int_reg & MS_EXIST) {
+		else if (chip->int_reg & MS_EXIST)
 			reset_map |= MS_CARD;
-		}
 	}
 
 	if (reset_map) {
@@ -489,21 +485,21 @@
 		for (i = 0; i < (DEBOUNCE_CNT); i++) {
 			chip->int_reg = rtsx_readl(chip, RTSX_BIPR);
 
-			if (chip->int_reg & XD_EXIST) {
+			if (chip->int_reg & XD_EXIST)
 				xd_cnt++;
-			} else {
+			else
 				xd_cnt = 0;
-			}
-			if (chip->int_reg & SD_EXIST) {
+
+			if (chip->int_reg & SD_EXIST)
 				sd_cnt++;
-			} else {
+			else
 				sd_cnt = 0;
-			}
-			if (chip->int_reg & MS_EXIST) {
+
+			if (chip->int_reg & MS_EXIST)
 				ms_cnt++;
-			} else {
+			else
 				ms_cnt = 0;
-			}
+
 			wait_timeout(30);
 		}
 
@@ -677,9 +673,8 @@
 
 	RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n", clk, chip->cur_clk);
 
-	if ((clk <= 2) || (N > max_N)) {
+	if ((clk <= 2) || (N > max_N))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	mcu_cnt = (u8)(125/clk + 3);
 	if (CHECK_PID(chip, 0x5209)) {
@@ -700,32 +695,29 @@
 	if (chip->ssc_en) {
 		if (CHECK_PID(chip, 0x5209)) {
 			if (chip->cur_card == SD_CARD) {
-				if (CHK_SD_SDR104(sd_card)) {
+				if (CHK_SD_SDR104(sd_card))
 					ssc_depth = chip->ssc_depth_sd_sdr104;
-				} else if (CHK_SD_SDR50(sd_card)) {
+				else if (CHK_SD_SDR50(sd_card))
 					ssc_depth = chip->ssc_depth_sd_sdr50;
-				} else if (CHK_SD_DDR50(sd_card)) {
+				else if (CHK_SD_DDR50(sd_card))
 					ssc_depth = double_depth(chip->ssc_depth_sd_ddr50);
-				} else if (CHK_SD_HS(sd_card)) {
+				else if (CHK_SD_HS(sd_card))
 					ssc_depth = double_depth(chip->ssc_depth_sd_hs);
-				} else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) {
+				else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card))
 					ssc_depth = double_depth(chip->ssc_depth_mmc_52m);
-				} else {
+				else
 					ssc_depth = double_depth(chip->ssc_depth_low_speed);
-				}
 			} else if (chip->cur_card == MS_CARD) {
 				if (CHK_MSPRO(ms_card)) {
-					if (CHK_HG8BIT(ms_card)) {
+					if (CHK_HG8BIT(ms_card))
 						ssc_depth = double_depth(chip->ssc_depth_ms_hg);
-					} else {
+					else
 						ssc_depth = double_depth(chip->ssc_depth_ms_4bit);
-					}
 				} else {
-					if (CHK_MS4BIT(ms_card)) {
+					if (CHK_MS4BIT(ms_card))
 						ssc_depth = double_depth(chip->ssc_depth_ms_4bit);
-					} else {
+					else
 						ssc_depth = double_depth(chip->ssc_depth_low_speed);
-					}
 				}
 			} else {
 				ssc_depth = double_depth(chip->ssc_depth_low_speed);
@@ -733,23 +725,23 @@
 
 			if (ssc_depth) {
 				if (div == CLK_DIV_2) {
-					if (ssc_depth > 1) {
+					if (ssc_depth > 1)
 						ssc_depth -= 1;
-					} else {
+					else
 						ssc_depth = SSC_DEPTH_4M;
-					}
+
 				} else if (div == CLK_DIV_4) {
-					if (ssc_depth > 2) {
+					if (ssc_depth > 2)
 						ssc_depth -= 2;
-					} else {
+					else
 						ssc_depth = SSC_DEPTH_4M;
-					}
+
 				} else if (div == CLK_DIV_8) {
-					if (ssc_depth > 3) {
+					if (ssc_depth > 3)
 						ssc_depth -= 3;
-					} else {
+					else
 						ssc_depth = SSC_DEPTH_4M;
-					}
+
 				}
 			}
 		} else {
@@ -760,11 +752,10 @@
 		ssc_depth = 0;
 	}
 
-	if (CHECK_PID(chip, 0x5209)) {
+	if (CHECK_PID(chip, 0x5209))
 		ssc_depth_mask = SSC_DEPTH_MASK;
-	} else {
+	else
 		ssc_depth_mask = 0x03;
-	}
 
 	RTSX_DEBUGP("ssc_depth = %d\n", ssc_depth);
 
@@ -781,9 +772,8 @@
 	}
 
 	retval = rtsx_send_cmd(chip, 0, WAIT_TIME);
-	if (retval < 0) {
+	if (retval < 0)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	udelay(10);
 	RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0);
@@ -976,25 +966,23 @@
 
 	rtsx_init_cmd(chip);
 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val1);
-	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) {
+	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD))
 		rtsx_add_cmd(chip, WRITE_REG_CMD, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_SUSPEND);
-	}
+
 	retval = rtsx_send_cmd(chip, 0, 100);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	udelay(chip->pmos_pwr_on_interval);
 
 	rtsx_init_cmd(chip);
 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val2);
-	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) {
+	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD))
 		rtsx_add_cmd(chip, WRITE_REG_CMD, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON);
-	}
+
 	retval = rtsx_send_cmd(chip, 0, 100);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1016,9 +1004,8 @@
 	}
 
 	RTSX_WRITE_REG(chip, CARD_PWR_CTL, mask, val);
-	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) {
+	if (CHECK_PID(chip, 0x5209) && (card == SD_CARD))
 		RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1029,9 +1016,8 @@
 	unsigned int lun = SCSI_LUN(srb);
 	int i;
 
-	if (chip->rw_card[lun] == NULL) {
+	if (chip->rw_card[lun] == NULL)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	for (i = 0; i < 3; i++) {
 		chip->rw_need_retry = 0;
@@ -1042,9 +1028,9 @@
 				rtsx_release_chip(chip);
 				TRACE_RET(chip, STATUS_FAIL);
 			}
-			if (detect_card_cd(chip, chip->cur_card) != STATUS_SUCCESS) {
+			if (detect_card_cd(chip, chip->cur_card) != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			if (!chip->rw_need_retry) {
 				RTSX_DEBUGP("RW fail, but no need to retry\n");
 				break;
@@ -1066,26 +1052,26 @@
 
 	if (CHECK_PID(chip, 0x5209) || CHECK_PID(chip, 0x5208)) {
 		mask = CARD_SHARE_MASK;
-		if (card == SD_CARD) {
+		if (card == SD_CARD)
 			value = CARD_SHARE_48_SD;
-		} else if (card == MS_CARD) {
+		else if (card == MS_CARD)
 			value = CARD_SHARE_48_MS;
-		} else if (card == XD_CARD) {
+		else if (card == XD_CARD)
 			value = CARD_SHARE_48_XD;
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	} else if (CHECK_PID(chip, 0x5288)) {
 		mask = 0x03;
-		if (card == SD_CARD) {
+		if (card == SD_CARD)
 			value = CARD_SHARE_BAROSSA_SD;
-		} else if (card == MS_CARD) {
+		else if (card == MS_CARD)
 			value = CARD_SHARE_BAROSSA_MS;
-		} else if (card == XD_CARD) {
+		else if (card == XD_CARD)
 			value = CARD_SHARE_BAROSSA_XD;
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	} else {
 		TRACE_RET(chip, STATUS_FAIL);
 	}
@@ -1103,24 +1089,23 @@
 	if (chip->cur_card != card) {
 		u8 mod;
 
-		if (card == SD_CARD) {
+		if (card == SD_CARD)
 			mod = SD_MOD_SEL;
-		} else if (card == MS_CARD) {
+		else if (card == MS_CARD)
 			mod = MS_MOD_SEL;
-		} else if (card == XD_CARD) {
+		else if (card == XD_CARD)
 			mod = XD_MOD_SEL;
-		} else if (card == SPI_CARD) {
+		else if (card == SPI_CARD)
 			mod = SPI_MOD_SEL;
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		RTSX_WRITE_REG(chip, CARD_SELECT, 0x07, mod);
 		chip->cur_card = card;
 
 		retval =  card_share_mode(chip, card);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1137,20 +1122,18 @@
 
 void turn_on_led(struct rtsx_chip *chip, u8 gpio)
 {
-	if (CHECK_PID(chip, 0x5288)) {
+	if (CHECK_PID(chip, 0x5288))
 		rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio));
-	} else {
+	else
 		rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0);
-	}
 }
 
 void turn_off_led(struct rtsx_chip *chip, u8 gpio)
 {
-	if (CHECK_PID(chip, 0x5288)) {
+	if (CHECK_PID(chip, 0x5288))
 		rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0);
-	} else {
+	else
 		rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio));
-	}
 }
 
 int detect_card_cd(struct rtsx_chip *chip, int card)
@@ -1169,67 +1152,60 @@
 	}
 
 	status = rtsx_readl(chip, RTSX_BIPR);
-	if (!(status & card_cd)) {
+	if (!(status & card_cd))
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
 
 int check_card_exist(struct rtsx_chip *chip, unsigned int lun)
 {
-	if (chip->card_exist & chip->lun2card[lun]) {
+	if (chip->card_exist & chip->lun2card[lun])
 		return 1;
-	}
 
 	return 0;
 }
 
 int check_card_ready(struct rtsx_chip *chip, unsigned int lun)
 {
-	if (chip->card_ready & chip->lun2card[lun]) {
+	if (chip->card_ready & chip->lun2card[lun])
 		return 1;
-	}
 
 	return 0;
 }
 
 int check_card_wp(struct rtsx_chip *chip, unsigned int lun)
 {
-	if (chip->card_wp & chip->lun2card[lun]) {
+	if (chip->card_wp & chip->lun2card[lun])
 		return 1;
-	}
 
 	return 0;
 }
 
 int check_card_fail(struct rtsx_chip *chip, unsigned int lun)
 {
-	if (chip->card_fail & chip->lun2card[lun]) {
+	if (chip->card_fail & chip->lun2card[lun])
 		return 1;
-	}
 
 	return 0;
 }
 
 int check_card_ejected(struct rtsx_chip *chip, unsigned int lun)
 {
-	if (chip->card_ejected & chip->lun2card[lun]) {
+	if (chip->card_ejected & chip->lun2card[lun])
 		return 1;
-	}
 
 	return 0;
 }
 
 u8 get_lun_card(struct rtsx_chip *chip, unsigned int lun)
 {
-	if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) {
+	if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD)
 		return (u8)XD_CARD;
-	} else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) {
+	else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD)
 		return (u8)SD_CARD;
-	} else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) {
+	else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD)
 		return (u8)MS_CARD;
-	}
 
 	return 0;
 }
diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c
index 5452069..d8e691b 100644
--- a/drivers/staging/rts_pstor/rtsx_chip.c
+++ b/drivers/staging/rts_pstor/rtsx_chip.c
@@ -105,11 +105,10 @@
 		reg |= DELINK_INT_EN;
 #ifdef SUPPORT_OCP
 	if (CHECK_PID(chip, 0x5209)) {
-		if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+		if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 			reg |= MS_OC_INT_EN | SD_OC_INT_EN;
-		} else {
+		else
 			reg |= SD_OC_INT_EN;
-		}
 	} else {
 		reg |= OC_INT_EN;
 	}
@@ -186,20 +185,20 @@
 		u8 cd_toggle_mask = 0;
 
 		RTSX_READ_REG(chip, TLPTISTAT, &tmp);
-		if (CHECK_PID(chip, 0x5209)) {
+		if (CHECK_PID(chip, 0x5209))
 			cd_toggle_mask = 0x10;
-		} else {
+		else
 			cd_toggle_mask = 0x08;
-		}
+
 		if (tmp & cd_toggle_mask) {
 			/* Disable sdio_bus_auto_switch */
-			if (CHECK_PID(chip, 0x5288)) {
+			if (CHECK_PID(chip, 0x5288))
 				RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x00);
-			} else if (CHECK_PID(chip, 0x5208)) {
+			else if (CHECK_PID(chip, 0x5208))
 				RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x00);
-			} else {
+			else
 				RTSX_WRITE_REG(chip, SDIO_CFG, SDIO_BUS_AUTO_SWITCH, 0);
-			}
+
 			RTSX_WRITE_REG(chip, TLPTISTAT, 0xFF, tmp);
 
 			chip->need_reset |= SD_CARD;
@@ -208,16 +207,14 @@
 
 			if (chip->asic_code) {
 				retval = sd_pull_ctl_enable(chip);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			} else {
 				RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0);
 			}
 			retval = card_share_mode(chip, SD_CARD);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			/* Enable sdio_bus_auto_switch */
 			if (CHECK_PID(chip, 0x5288)) {
@@ -232,11 +229,11 @@
 			chip->sd_io = 1;
 		}
 	} else {
-		if (CHECK_PID(chip, 0x5209)) {
+		if (CHECK_PID(chip, 0x5209))
 			RTSX_WRITE_REG(chip, TLPTISTAT, 0x10, 0x10);
-		} else {
+		else
 			RTSX_WRITE_REG(chip, TLPTISTAT, 0x08, 0x08);
-		}
+
 		chip->need_reset |= SD_CARD;
 	}
 
@@ -257,48 +254,47 @@
 
 		/* optimize PHY */
 		retval = rtsx_write_phy_register(chip, 0x00, 0xB966);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x01, 0x713F);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x03, 0xA549);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x06, 0xB235);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x07, 0xEF40);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x1E, 0xF8EB);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = rtsx_write_phy_register(chip, 0x19, 0xFE6C);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		wait_timeout(1);
 		retval = rtsx_write_phy_register(chip, 0x0A, 0x05C0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 
 		retval = rtsx_write_cfg_dw(chip, 1, 0x110, 0xFFFF, 0xFFFF);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		retval = rtsx_read_phy_register(chip, 0x08, &val);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		RTSX_DEBUGP("Read from phy 0x08: 0x%04x\n", val);
 
 		if (chip->phy_voltage) {
@@ -308,9 +304,9 @@
 			val |= chip->phy_voltage;
 			RTSX_DEBUGP("Write to phy 0x08: 0x%04x\n", val);
 			retval = rtsx_write_phy_register(chip, 0x08, val);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 		} else {
 			chip->phy_voltage = (u8)(val & 0x3F);
 			RTSX_DEBUGP("Default, chip->phy_voltage = 0x%x\n", chip->phy_voltage);
@@ -324,11 +320,11 @@
 
 #ifdef SUPPORT_OCP
 	/* SSC power on, OCD power on */
-	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+	if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 		RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, 0);
-	} else {
+	else
 		RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, MS_OC_POWER_DOWN);
-	}
+
 	if (CHECK_PID(chip, 0x5209)) {
 		RTSX_WRITE_REG(chip, OCPPARA1, SD_OCP_TIME_MASK | MS_OCP_TIME_MASK,
 				    SD_OCP_TIME_800 | MS_OCP_TIME_800);
@@ -352,9 +348,8 @@
 	RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, OC_POWER_DOWN);
 #endif
 
-	if (!CHECK_PID(chip, 0x5288)) {
+	if (!CHECK_PID(chip, 0x5288))
 		RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0xFF, 0x03);
-	}
 
 	/* Turn off LED */
 	RTSX_WRITE_REG(chip, CARD_GPIO, 0xFF, 0x03);
@@ -364,9 +359,8 @@
 
 	/* Card driving select */
 	RTSX_WRITE_REG(chip, CARD_DRIVE_SEL, 0xFF, chip->card_drive_sel);
-	if (CHECK_PID(chip, 0x5209)) {
+	if (CHECK_PID(chip, 0x5209))
 		RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_3v3);
-	}
 
 #ifdef LED_AUTO_BLINK
 	RTSX_WRITE_REG(chip, CARD_AUTO_BLINK, 0xFF,
@@ -394,36 +388,34 @@
 			if (CHK_SDIO_EXIST(chip)) {
 				if (CHECK_PID(chip, 0x5209)) {
 					retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
-					if (retval != STATUS_SUCCESS) {
+					if (retval != STATUS_SUCCESS)
 						TRACE_RET(chip, STATUS_FAIL);
-					}
+
 				} else if (CHECK_PID(chip, 0x5288)) {
 					retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
-					if (retval != STATUS_SUCCESS) {
+					if (retval != STATUS_SUCCESS)
 						TRACE_RET(chip, STATUS_FAIL);
-					}
 				}
 			}
 		} else {
-			if (CHECK_PID(chip, 0x5208)) {
+			if (CHECK_PID(chip, 0x5208))
 				RTSX_WRITE_REG(chip, ASPM_FORCE_CTL, 0xFF, 0x3F);
-			}
 
 			retval = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			chip->aspm_level[0] = chip->aspm_l0s_l1_en;
 			if (CHK_SDIO_EXIST(chip)) {
 				chip->aspm_level[1] = chip->aspm_l0s_l1_en;
-				if (CHECK_PID(chip, 0x5288)) {
+				if (CHECK_PID(chip, 0x5288))
 					retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
-				} else {
+				else
 					retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
-				}
-				if (retval != STATUS_SUCCESS) {
+
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 			}
 
 			chip->aspm_enabled = 1;
@@ -431,49 +423,45 @@
 	} else {
 		if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
 			retval = rtsx_write_phy_register(chip, 0x07, 0x0129);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 		retval = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	retval = rtsx_write_config_byte(chip, 0x81, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHK_SDIO_EXIST(chip)) {
-		if (CHECK_PID(chip, 0x5288)) {
+		if (CHECK_PID(chip, 0x5288))
 			retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF00, 0x0100);
-		} else {
+		else
 			retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF00, 0x0100);
-		}
-		if (retval != STATUS_SUCCESS) {
+
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	}
 
 	if (CHECK_PID(chip, 0x5209)) {
 		retval = rtsx_write_cfg_dw(chip, 0, 0x70C, 0xFF000000, 0x5B);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	if (CHECK_PID(chip, 0x5288)) {
 		if (!CHK_SDIO_EXIST(chip)) {
 			retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, 0x0103);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			retval = rtsx_write_cfg_dw(chip, 2, 0x84, 0xFF, 0x03);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 		}
 	}
 
@@ -499,29 +487,29 @@
 			if (chip->ic_version >= IC_VER_D) {
 				u16 reg;
 				retval = rtsx_read_phy_register(chip, 0x00, &reg);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 				reg &= 0xFE7F;
 				reg |= 0x80;
 				retval = rtsx_write_phy_register(chip, 0x00, reg);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 				retval = rtsx_read_phy_register(chip, 0x1C, &reg);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 				reg &= 0xFFF7;
 				retval = rtsx_write_phy_register(chip, 0x1C, reg);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 			}
 
-			if (chip->driver_first_load && (chip->ic_version < IC_VER_C)) {
+			if (chip->driver_first_load && (chip->ic_version < IC_VER_C))
 				rtsx_calibration(chip);
-			}
+
 		} else {
 			rtsx_enable_bus_int(chip);
 		}
@@ -550,18 +538,18 @@
 	RTSX_DEBUGP("In rtsx_reset_chip, chip->int_reg = 0x%x\n", chip->int_reg);
 	if (chip->int_reg & SD_EXIST) {
 #ifdef HW_AUTO_SWITCH_SD_BUS
-		if (CHECK_PID(chip, 0x5208) && (chip->ic_version < IC_VER_C)) {
+		if (CHECK_PID(chip, 0x5208) && (chip->ic_version < IC_VER_C))
 			retval = rtsx_pre_handle_sdio_old(chip);
-		} else {
+		else
 			retval = rtsx_pre_handle_sdio_new(chip);
-		}
+
 		RTSX_DEBUGP("chip->need_reset = 0x%x (rtsx_reset_chip)\n", (unsigned int)(chip->need_reset));
 #else  /* HW_AUTO_SWITCH_SD_BUS */
 		retval = rtsx_pre_handle_sdio_old(chip);
 #endif  /* HW_AUTO_SWITCH_SD_BUS */
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	} else {
 		chip->sd_io = 0;
 		RTSX_WRITE_REG(chip, SDIO_CTRL, SDIO_BUS_CTRL | SDIO_CD_CTRL, 0);
@@ -572,9 +560,8 @@
 		chip->need_reset |= XD_CARD;
 	if (chip->int_reg & MS_EXIST)
 		chip->need_reset |= MS_CARD;
-	if (chip->int_reg & CARD_EXIST) {
+	if (chip->int_reg & CARD_EXIST)
 		RTSX_WRITE_REG(chip, SSC_CTL1, SSC_RSTB, SSC_RSTB);
-	}
 
 	RTSX_DEBUGP("In rtsx_init_chip, chip->need_reset = 0x%x\n", (unsigned int)(chip->need_reset));
 
@@ -587,9 +574,8 @@
 
 	if (chip->remote_wakeup_en && !chip->auto_delink_en) {
 		RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x07);
-		if (chip->aux_pwr_exist) {
+		if (chip->aux_pwr_exist)
 			RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x33);
-		}
 	} else {
 		RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x04);
 		RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x30);
@@ -598,18 +584,16 @@
 	if (CHECK_PID(chip, 0x5208) && (chip->ic_version >= IC_VER_D)) {
 		RTSX_WRITE_REG(chip, PETXCFG, 0x1C, 0x14);
 	} else if (CHECK_PID(chip, 0x5209)) {
-		if (chip->force_clkreq_0) {
+		if (chip->force_clkreq_0)
 			RTSX_WRITE_REG(chip, PETXCFG, 0x08, 0x08);
-		} else {
+		else
 			RTSX_WRITE_REG(chip, PETXCFG, 0x08, 0x00);
-		}
 	}
 
 	if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
 		retval = rtsx_clr_phy_reg_bit(chip, 0x1C, 2);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	if (chip->ft2_fast_mode) {
@@ -665,11 +649,10 @@
 	u8 val = 0;
 
 	val = rtsx_readb(chip, 0x1C);
-	if ((val & 0x10) == 0) {
+	if ((val & 0x10) == 0)
 		chip->asic_code = 1;
-	} else {
+	else
 		chip->asic_code = 0;
-	}
 
 	chip->ic_version = val & 0x0F;
 	chip->phy_debug_mode = 0;
@@ -679,9 +662,9 @@
 	chip->ms_power_class_en = 0x03;
 
 	retval = rtsx_read_cfg_dw(chip, 0, 0x724, &lval);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	RTSX_DEBUGP("dw in 0x724: 0x%x\n", lval);
 	val = (u8)lval;
 	if (!(val & 0x80)) {
@@ -690,17 +673,16 @@
 		else
 			chip->lun_mode = SD_MS_2LUN;
 
-		if (val & 0x04) {
+		if (val & 0x04)
 			SET_SDIO_EXIST(chip);
-		} else {
+		else
 			CLR_SDIO_EXIST(chip);
-		}
 
-		if (val & 0x02) {
+		if (val & 0x02)
 			chip->hw_bypass_sd = 0;
-		} else {
+		else
 			chip->hw_bypass_sd = 1;
-		}
+
 	} else {
 		SET_SDIO_EXIST(chip);
 		chip->hw_bypass_sd = 0;
@@ -714,24 +696,21 @@
 		val = (u8)(lval >> 8);
 
 		clk = (val >> 5) & 0x07;
-		if (clk != 0x07) {
+		if (clk != 0x07)
 			chip->asic_sd_sdr50_clk = 98 - clk * 2;
-		}
 
-		if (val & 0x10) {
+		if (val & 0x10)
 			chip->auto_delink_en = 1;
-		} else {
+		else
 			chip->auto_delink_en = 0;
-		}
 
 		if (chip->ss_en == 2) {
 			chip->ss_en = 0;
 		} else {
-			if (val & 0x08) {
+			if (val & 0x08)
 				chip->ss_en = 1;
-			} else {
+			else
 				chip->ss_en = 0;
-			}
 		}
 
 		clk = val & 0x07;
@@ -750,21 +729,21 @@
 		if (clk != 0x03)
 			chip->asic_sd_ddr50_clk = (48 - clk * 2) * 2;
 
-		if (val & 0x01) {
+		if (val & 0x01)
 			chip->sdr104_en = 1;
-		} else {
+		else
 			chip->sdr104_en = 0;
-		}
-		if (val & 0x02) {
+
+		if (val & 0x02)
 			chip->ddr50_en = 1;
-		} else {
+		else
 			chip->ddr50_en = 0;
-		}
-		if (val & 0x04) {
+
+		if (val & 0x04)
 			chip->sdr50_en = 1;
-		} else {
+		else
 			chip->sdr50_en = 0;
-		}
+
 
 		val = (u8)(lval >> 24);
 
@@ -772,11 +751,10 @@
 		if (clk != 0x07)
 			chip->asic_sd_sdr104_clk = 206 - clk * 3;
 
-		if (val & 0x10) {
+		if (val & 0x10)
 			chip->power_down_in_ss = 1;
-		} else {
+		else
 			chip->power_down_in_ss = 0;
-		}
 
 		chip->ms_power_class_en = val & 0x03;
 	}
@@ -786,20 +764,19 @@
 
 		retval = rtsx_read_pci_cfg_byte(0x00,
 						0x1C, 0x02, 0x58, &reg58);
-		if (retval < 0) {
+		if (retval < 0)
 			return STATUS_SUCCESS;
-		}
+
 		retval = rtsx_read_pci_cfg_byte(0x00,
 						0x1C, 0x02, 0x5B, &reg5b);
-		if (retval < 0) {
+		if (retval < 0)
 			return STATUS_SUCCESS;
-		}
 
 		RTSX_DEBUGP("reg58 = 0x%x, reg5b = 0x%x\n", reg58, reg5b);
 
-		if ((reg58 == 0x00) && (reg5b == 0x01)) {
+		if ((reg58 == 0x00) && (reg5b == 0x01))
 			chip->auto_delink_en = 0;
-		}
+
 	}
 
 	return STATUS_SUCCESS;
@@ -813,24 +790,23 @@
 
 	RTSX_WRITE_REG(chip, CLK_SEL, 0x03, 0x03);
 	RTSX_READ_REG(chip, CLK_SEL, &val);
-	if (val == 0) {
+	if (val == 0)
 		chip->asic_code = 1;
-	} else {
+	else
 		chip->asic_code = 0;
-	}
 
 	if (chip->asic_code) {
 		retval = rtsx_read_phy_register(chip, 0x1C, &reg);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		RTSX_DEBUGP("Value of phy register 0x1C is 0x%x\n", reg);
 		chip->ic_version = (reg >> 4) & 0x07;
-		if (reg & PHY_DEBUG_MODE) {
+		if (reg & PHY_DEBUG_MODE)
 			chip->phy_debug_mode = 1;
-		} else {
+		else
 			chip->phy_debug_mode = 0;
-		}
+
 	} else {
 		RTSX_READ_REG(chip, 0xFE80, &val);
 		chip->ic_version = val;
@@ -839,33 +815,29 @@
 
 	RTSX_READ_REG(chip, PDINFO, &val);
 	RTSX_DEBUGP("PDINFO: 0x%x\n", val);
-	if (val & AUX_PWR_DETECTED) {
+	if (val & AUX_PWR_DETECTED)
 		chip->aux_pwr_exist = 1;
-	} else {
+	else
 		chip->aux_pwr_exist = 0;
-	}
 
 	RTSX_READ_REG(chip, 0xFE50, &val);
-	if (val & 0x01) {
+	if (val & 0x01)
 		chip->hw_bypass_sd = 1;
-	} else {
+	else
 		chip->hw_bypass_sd = 0;
-	}
 
 	rtsx_read_config_byte(chip, 0x0E, &val);
-	if (val & 0x80) {
+	if (val & 0x80)
 		SET_SDIO_EXIST(chip);
-	} else {
+	else
 		CLR_SDIO_EXIST(chip);
-	}
 
 	if (chip->use_hw_setting) {
 		RTSX_READ_REG(chip, CHANGE_LINK_STATE, &val);
-		if (val & 0x80) {
+		if (val & 0x80)
 			chip->auto_delink_en = 1;
-		} else {
+		else
 			chip->auto_delink_en = 0;
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -879,63 +851,57 @@
 
 	RTSX_WRITE_REG(chip, CLK_SEL, 0x03, 0x03);
 	RTSX_READ_REG(chip, CLK_SEL, &val);
-	if (val == 0) {
+	if (val == 0)
 		chip->asic_code = 1;
-	} else {
+	else
 		chip->asic_code = 0;
-	}
 
 	chip->ic_version = 0;
 	chip->phy_debug_mode = 0;
 
 	RTSX_READ_REG(chip, PDINFO, &val);
 	RTSX_DEBUGP("PDINFO: 0x%x\n", val);
-	if (val & AUX_PWR_DETECTED) {
+	if (val & AUX_PWR_DETECTED)
 		chip->aux_pwr_exist = 1;
-	} else {
+	else
 		chip->aux_pwr_exist = 0;
-	}
 
 	RTSX_READ_REG(chip, CARD_SHARE_MODE, &val);
 	RTSX_DEBUGP("CARD_SHARE_MODE: 0x%x\n", val);
-	if (val & 0x04) {
+	if (val & 0x04)
 		chip->baro_pkg = QFN;
-	} else {
+	else
 		chip->baro_pkg = LQFP;
-	}
 
 	RTSX_READ_REG(chip, 0xFE5A, &val);
-	if (val & 0x10) {
+	if (val & 0x10)
 		chip->hw_bypass_sd = 1;
-	} else {
+	else
 		chip->hw_bypass_sd = 0;
-	}
 
 	retval = rtsx_read_cfg_dw(chip, 0, 0x718, &lval);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	max_func = (u8)((lval >> 29) & 0x07);
 	RTSX_DEBUGP("Max function number: %d\n", max_func);
-	if (max_func == 0x02) {
+	if (max_func == 0x02)
 		SET_SDIO_EXIST(chip);
-	} else {
+	else
 		CLR_SDIO_EXIST(chip);
-	}
 
 	if (chip->use_hw_setting) {
 		RTSX_READ_REG(chip, CHANGE_LINK_STATE, &val);
-		if (val & 0x80) {
+		if (val & 0x80)
 			chip->auto_delink_en = 1;
-		} else {
+		else
 			chip->auto_delink_en = 0;
-		}
 
-		if (CHECK_BARO_PKG(chip, LQFP)) {
+		if (CHECK_BARO_PKG(chip, LQFP))
 			chip->lun_mode = SD_MS_1LUN;
-		} else {
+		else
 			chip->lun_mode = DEFAULT_SINGLE;
-		}
+
 	}
 
 	return STATUS_SUCCESS;
@@ -990,22 +956,21 @@
 		chip->rw_fail_cnt[i] = 0;
 	}
 
-	if (!check_sd_speed_prior(chip->sd_speed_prior)) {
+	if (!check_sd_speed_prior(chip->sd_speed_prior))
 		chip->sd_speed_prior = 0x01040203;
-	}
+
 	RTSX_DEBUGP("sd_speed_prior = 0x%08x\n", chip->sd_speed_prior);
 
-	if (!check_sd_current_prior(chip->sd_current_prior)) {
+	if (!check_sd_current_prior(chip->sd_current_prior))
 		chip->sd_current_prior = 0x00010203;
-	}
+
 	RTSX_DEBUGP("sd_current_prior = 0x%08x\n", chip->sd_current_prior);
 
-	if ((chip->sd_ddr_tx_phase > 31) || (chip->sd_ddr_tx_phase < 0)) {
+	if ((chip->sd_ddr_tx_phase > 31) || (chip->sd_ddr_tx_phase < 0))
 		chip->sd_ddr_tx_phase = 0;
-	}
-	if ((chip->mmc_ddr_tx_phase > 31) || (chip->mmc_ddr_tx_phase < 0)) {
+
+	if ((chip->mmc_ddr_tx_phase > 31) || (chip->mmc_ddr_tx_phase < 0))
 		chip->mmc_ddr_tx_phase = 0;
-	}
 
 	RTSX_WRITE_REG(chip, FPDCTL, SSC_POWER_DOWN, 0);
 	wait_timeout(200);
@@ -1014,24 +979,23 @@
 
 	if (CHECK_PID(chip, 0x5209)) {
 		retval = rts5209_init(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	} else if (CHECK_PID(chip, 0x5208)) {
 		retval = rts5208_init(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	} else if (CHECK_PID(chip, 0x5288)) {
 		retval = rts5288_init(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 	}
 
-	if (chip->ss_en == 2) {
+	if (chip->ss_en == 2)
 		chip->ss_en = 0;
-	}
 
 	RTSX_DEBUGP("chip->asic_code = %d\n", chip->asic_code);
 	RTSX_DEBUGP("chip->ic_version = 0x%x\n", chip->ic_version);
@@ -1068,9 +1032,8 @@
 	}
 
 	retval = rtsx_reset_chip(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1118,19 +1081,19 @@
 			chip->aspm_level[1] = reg1;
 		}
 
-		if ((reg0 & 0x03) && (reg1 & 0x03)) {
+		if ((reg0 & 0x03) && (reg1 & 0x03))
 			maybe_support_aspm = 1;
-		}
+
 	} else {
-		if (reg0 & 0x03) {
+		if (reg0 & 0x03)
 			maybe_support_aspm = 1;
-		}
+
 	}
 
 	if (reg_changed) {
-		if (maybe_support_aspm) {
+		if (maybe_support_aspm)
 			chip->aspm_l0s_l1_en = 0x03;
-		}
+
 		RTSX_DEBUGP("aspm_level[0] = 0x%02x, aspm_level[1] = 0x%02x\n",
 			      chip->aspm_level[0], chip->aspm_level[1]);
 
@@ -1177,13 +1140,13 @@
 			if (chip->ocp_int & MS_OC_INT)
 				ms_power_off_card3v3(chip);
 		} else {
-			if (chip->card_exist & SD_CARD) {
+			if (chip->card_exist & SD_CARD)
 				sd_power_off_card3v3(chip);
-			} else if (chip->card_exist & MS_CARD) {
+			else if (chip->card_exist & MS_CARD)
 				ms_power_off_card3v3(chip);
-			} else if (chip->card_exist & XD_CARD) {
+			else if (chip->card_exist & XD_CARD)
 				xd_power_off_card3v3(chip);
-			}
+
 		}
 
 		chip->ocp_int = 0;
@@ -1226,9 +1189,9 @@
 			if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) {
 				u32 val;
 				rtsx_read_cfg_dw(chip, 1, 0x04, &val);
-				if (val & 0x07) {
+				if (val & 0x07)
 					ss_allowed = 0;
-				}
+
 			}
 		}
 	} else {
@@ -1284,9 +1247,9 @@
 
 			turn_off_led(chip, LED_GPIO);
 
-			if (chip->auto_power_down && !chip->card_ready && !chip->sd_io) {
+			if (chip->auto_power_down && !chip->card_ready && !chip->sd_io)
 				rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL);
-			}
+
 		}
 	}
 
@@ -1299,9 +1262,9 @@
 		break;
 
 	case RTSX_STAT_IDLE:
-		if (chip->sd_io && !chip->sd_int) {
+		if (chip->sd_io && !chip->sd_int)
 			try_to_switch_sdio_ctrl(chip);
-		}
+
 		rtsx_enable_aspm(chip);
 		break;
 
@@ -1313,9 +1276,8 @@
 #ifdef SUPPORT_OCP
 	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
 #ifdef CONFIG_RTS_PSTOR_DEBUG
-		if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) {
+		if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER))
 			RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat);
-		}
 #endif
 
 		if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
@@ -1362,28 +1324,27 @@
 			if (chip->auto_delink_cnt == delink_stage1_cnt) {
 				rtsx_set_stat(chip, RTSX_STAT_DELINK);
 
-				if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
+				if (chip->asic_code && CHECK_PID(chip, 0x5208))
 					rtsx_set_phy_reg_bit(chip, 0x1C, 2);
-				}
+
 				if (chip->card_exist) {
 					RTSX_DEBUGP("False card inserted, do force delink\n");
 
-					if (enter_L1) {
+					if (enter_L1)
 						rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 1);
-					}
+
 					rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0x0A);
 
-					if (enter_L1) {
+					if (enter_L1)
 						rtsx_enter_L1(chip);
-					}
 
 					chip->auto_delink_cnt = delink_stage3_cnt + 1;
 				} else {
 					RTSX_DEBUGP("No card inserted, do delink\n");
 
-					if (enter_L1) {
+					if (enter_L1)
 						rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 1);
-					}
+
 #ifdef HW_INT_WRITE_CLR
 					if (CHECK_PID(chip, 0x5209)) {
 						rtsx_writel(chip, RTSX_BIPR, 0xFFFFFFFF);
@@ -1392,22 +1353,21 @@
 #endif
 					rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 0x02);
 
-					if (enter_L1) {
+					if (enter_L1)
 						rtsx_enter_L1(chip);
-					}
+
 				}
 			}
 
 			if (chip->auto_delink_cnt == delink_stage2_cnt) {
 				RTSX_DEBUGP("Try to do force delink\n");
 
-				if (enter_L1) {
+				if (enter_L1)
 					rtsx_exit_L1(chip);
-				}
 
-				if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
+				if (chip->asic_code && CHECK_PID(chip, 0x5208))
 					rtsx_set_phy_reg_bit(chip, 0x1C, 2);
-				}
+
 				rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0x0A);
 			}
 
@@ -1472,9 +1432,9 @@
 	for (i = 0; i < MAX_RW_REG_CNT; i++) {
 		val = rtsx_readl(chip, RTSX_HAIMR);
 		if ((val & (1 << 31)) == 0) {
-			if (data != (u8)val) {
+			if (data != (u8)val)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
+
 			return STATUS_SUCCESS;
 		}
 	}
@@ -1487,9 +1447,8 @@
 	u32 val = 2 << 30;
 	int i;
 
-	if (data) {
+	if (data)
 		*data = 0;
-	}
 
 	val |= (u32)(addr & 0x3FFF) << 16;
 
@@ -1497,18 +1456,15 @@
 
 	for (i = 0; i < MAX_RW_REG_CNT; i++) {
 		val = rtsx_readl(chip, RTSX_HAIMR);
-		if ((val & (1 << 31)) == 0) {
+		if ((val & (1 << 31)) == 0)
 			break;
-		}
 	}
 
-	if (i >= MAX_RW_REG_CNT) {
+	if (i >= MAX_RW_REG_CNT)
 		TRACE_RET(chip, STATUS_TIMEDOUT);
-	}
 
-	if (data) {
+	if (data)
 		*data = (u8)(val & 0xFF);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1537,9 +1493,8 @@
 
 		for (i = 0; i < MAX_RW_REG_CNT; i++) {
 			RTSX_READ_REG(chip, CFGRWCTL, &tmp);
-			if ((tmp & 0x80) == 0) {
+			if ((tmp & 0x80) == 0)
 				break;
-			}
 		}
 	}
 
@@ -1558,9 +1513,8 @@
 
 	for (i = 0; i < MAX_RW_REG_CNT; i++) {
 		RTSX_READ_REG(chip, CFGRWCTL, &tmp);
-		if ((tmp & 0x80) == 0) {
+		if ((tmp & 0x80) == 0)
 			break;
-		}
 	}
 
 	for (i = 0; i < 4; i++) {
@@ -1568,9 +1522,8 @@
 		data |= (u32)tmp << (i * 8);
 	}
 
-	if (val) {
+	if (val)
 		*val = data;
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1585,21 +1538,19 @@
 
 	RTSX_DEBUGP("%s\n", __func__);
 
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_NOMEM);
-	}
 
-	if ((len + offset) % 4) {
+	if ((len + offset) % 4)
 		dw_len = (len + offset) / 4 + 1;
-	} else {
+	else
 		dw_len = (len + offset) / 4;
-	}
+
 	RTSX_DEBUGP("dw_len = %d\n", dw_len);
 
 	data = vzalloc(dw_len * 4);
-	if (!data) {
+	if (!data)
 		TRACE_RET(chip, STATUS_NOMEM);
-	}
 
 	mask = vzalloc(dw_len * 4);
 	if (!mask) {
@@ -1645,17 +1596,16 @@
 
 	RTSX_DEBUGP("%s\n", __func__);
 
-	if ((len + offset) % 4) {
+	if ((len + offset) % 4)
 		dw_len = (len + offset) / 4 + 1;
-	} else {
+	else
 		dw_len = (len + offset) / 4;
-	}
+
 	RTSX_DEBUGP("dw_len = %d\n", dw_len);
 
 	data = (u32 *)vmalloc(dw_len * 4);
-	if (!data) {
+	if (!data)
 		TRACE_RET(chip, STATUS_NOMEM);
-	}
 
 	for (i = 0; i < dw_len; i++) {
 		retval = rtsx_read_cfg_dw(chip, func, aligned_addr + i * 4, data + i);
@@ -1700,9 +1650,8 @@
 		}
 	}
 
-	if (!finished) {
+	if (!finished)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1724,9 +1673,8 @@
 		}
 	}
 
-	if (!finished) {
+	if (!finished)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_READ_REG(chip, PHYDATA0, &tmp);
 	data = tmp;
@@ -1753,9 +1701,8 @@
 		udelay(1);
 	}
 
-	if (data & 0x80) {
+	if (data & 0x80)
 		TRACE_RET(chip, STATUS_TIMEDOUT);
-	}
 
 	RTSX_READ_REG(chip, EFUSE_DATA, &data);
 	if (val)
@@ -1786,9 +1733,8 @@
 			wait_timeout(3);
 		}
 
-		if (data & 0x80) {
+		if (data & 0x80)
 			TRACE_RET(chip, STATUS_TIMEDOUT);
-		}
 
 		wait_timeout(5);
 	}
@@ -1802,15 +1748,14 @@
 	u16 value;
 
 	retval = rtsx_read_phy_register(chip, reg, &value);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (value & (1 << bit)) {
 		value &= ~(1 << bit);
 		retval = rtsx_write_phy_register(chip, reg, value);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1822,15 +1767,14 @@
 	u16 value;
 
 	retval = rtsx_read_phy_register(chip, reg, &value);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	if (0 == (value & (1 << bit))) {
 		value |= (1 << bit);
 		retval = rtsx_write_phy_register(chip, reg, value);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1861,11 +1805,11 @@
 	if (CHK_SDIO_EXIST(chip)) {
 		u8 func_no;
 
-		if (CHECK_PID(chip, 0x5288)) {
+		if (CHECK_PID(chip, 0x5288))
 			func_no = 2;
-		} else {
+		else
 			func_no = 1;
-		}
+
 		rtsx_read_cfg_dw(chip, func_no, 0x84, &ultmp);
 		RTSX_DEBUGP("pm_dstate of function %d: 0x%x\n", (int)func_no, ultmp);
 		rtsx_write_cfg_dw(chip, func_no, 0x84, 0xFF, dstate);
@@ -1898,11 +1842,10 @@
 	}
 
 	if (CHK_SDIO_EXIST(chip)) {
-		if (CHECK_PID(chip, 0x5288)) {
+		if (CHECK_PID(chip, 0x5288))
 			rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF00, 0x0100);
-		} else {
+		else
 			rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF00, 0x0100);
-		}
 	}
 
 	if (chip->auto_delink_en) {
@@ -1953,11 +1896,11 @@
 	u32 ocp_int = 0;
 
 	if (CHECK_PID(chip, 0x5209)) {
-		if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+		if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 			ocp_int = MS_OC_INT | SD_OC_INT;
-		} else {
+		else
 			ocp_int = SD_OC_INT;
-		}
+
 	} else {
 		ocp_int = OC_INT;
 	}
@@ -1976,9 +1919,8 @@
 	chip->int_reg = rtsx_readl(chip, RTSX_BIPR);
 
 #ifdef HW_INT_WRITE_CLR
-	if (CHECK_PID(chip, 0x5209)) {
+	if (CHECK_PID(chip, 0x5209))
 		rtsx_writel(chip, RTSX_BIPR, chip->int_reg);
-	}
 #endif
 
 	if (((chip->int_reg & int_enable) == 0) || (chip->int_reg == 0xFFFFFFFF))
@@ -1988,9 +1930,8 @@
 		if (CHECK_PID(chip, 0x5209)) {
 			u8 val;
 			rtsx_read_config_byte(chip, 0x05, &val);
-			if (val & 0x04) {
+			if (val & 0x04)
 				return STATUS_FAIL;
-			}
 		}
 	}
 
@@ -2107,16 +2048,15 @@
 		RTSX_DEBUGP("Host enter S1\n");
 		rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, HOST_ENTER_S1);
 	} else if (pm_stat == PM_S3) {
-		if (chip->s3_pwr_off_delay > 0) {
+		if (chip->s3_pwr_off_delay > 0)
 			wait_timeout(chip->s3_pwr_off_delay);
-		}
+
 		RTSX_DEBUGP("Host enter S3\n");
 		rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, HOST_ENTER_S3);
 	}
 
-	if (chip->do_delink_before_power_down && chip->auto_delink_en) {
+	if (chip->do_delink_before_power_down && chip->auto_delink_en)
 		rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 2);
-	}
 
 	rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL);
 
@@ -2143,11 +2083,10 @@
 
 			if (CHK_SDIO_EXIST(chip)) {
 				u16 val = chip->aspm_l0s_l1_en | 0x0100;
-				if (CHECK_PID(chip, 0x5288)) {
+				if (CHECK_PID(chip, 0x5288))
 					rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, val);
-				} else {
+				else
 					rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFFFF, val);
-				}
 			}
 		}
 	}
@@ -2167,11 +2106,11 @@
 
 			if (chip->asic_code && CHECK_PID(chip, 0x5208))
 				rtsx_write_phy_register(chip, 0x07, 0x0129);
-			if (CHECK_PID(chip, 0x5208)) {
+			if (CHECK_PID(chip, 0x5208))
 				rtsx_write_register(chip, ASPM_FORCE_CTL, 0xF3, 0x30);
-			} else {
+			else
 				rtsx_write_config_byte(chip, LCTLR, 0x00);
-			}
+
 			wait_timeout(1);
 		}
 	}
@@ -2186,9 +2125,8 @@
 	u16 reg_addr;
 	u8 *ptr;
 
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	ptr = buf;
 	reg_addr = PPBUF_BASE2;
@@ -2199,9 +2137,8 @@
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0);
 
 		retval = rtsx_send_cmd(chip, 0, 250);
-		if (retval < 0) {
+		if (retval < 0)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		memcpy(ptr, rtsx_get_cmd_data(chip), 256);
 		ptr += 256;
@@ -2214,9 +2151,8 @@
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0);
 
 		retval = rtsx_send_cmd(chip, 0, 250);
-		if (retval < 0) {
+		if (retval < 0)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	memcpy(ptr, rtsx_get_cmd_data(chip), buf_len%256);
@@ -2231,9 +2167,8 @@
 	u16 reg_addr;
 	u8 *ptr;
 
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, STATUS_ERROR);
-	}
 
 	ptr = buf;
 	reg_addr = PPBUF_BASE2;
@@ -2246,9 +2181,8 @@
 		}
 
 		retval = rtsx_send_cmd(chip, 0, 250);
-		if (retval < 0) {
+		if (retval < 0)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	if (buf_len%256) {
@@ -2260,9 +2194,8 @@
 		}
 
 		retval = rtsx_send_cmd(chip, 0, 250);
-		if (retval < 0) {
+		if (retval < 0)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -2270,9 +2203,8 @@
 
 int rtsx_check_chip_exist(struct rtsx_chip *chip)
 {
-	if (rtsx_readl(chip, 0) == 0xFFFFFFFF) {
+	if (rtsx_readl(chip, 0) == 0xFFFFFFFF)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2288,17 +2220,15 @@
 #ifdef SUPPORT_OCP
 	if (ctl & OC_PDCTL) {
 		mask |= SD_OC_POWER_DOWN;
-		if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+		if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 			mask |= MS_OC_POWER_DOWN;
-		}
 	}
 #endif
 
 	if (mask) {
 		retval = rtsx_write_register(chip, FPDCTL, mask, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (CHECK_PID(chip, 0x5288))
 			wait_timeout(200);
@@ -2326,9 +2256,8 @@
 	if (mask) {
 		val = mask;
 		retval = rtsx_write_register(chip, FPDCTL, mask, val);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
diff --git a/drivers/staging/rts_pstor/rtsx_scsi.c b/drivers/staging/rts_pstor/rtsx_scsi.c
index f2e5842..86c41b3 100644
--- a/drivers/staging/rts_pstor/rtsx_scsi.c
+++ b/drivers/staging/rts_pstor/rtsx_scsi.c
@@ -135,9 +135,9 @@
 	default: what = "(unknown command)"; unknown_cmd = 1; break;
 	}
 
-	if (srb->cmnd[0] != TEST_UNIT_READY) {
+	if (srb->cmnd[0] != TEST_UNIT_READY)
 		RTSX_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
-	}
+
 	if (unknown_cmd) {
 		RTSX_DEBUGP("");
 		for (i = 0; i < srb->cmd_len && i < 16; i++)
@@ -317,11 +317,11 @@
 	};
 
 	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
-		if (chip->lun2card[lun] == SD_CARD) {
+		if (chip->lun2card[lun] == SD_CARD)
 			inquiry_string = inquiry_sd;
-		} else {
+		else
 			inquiry_string = inquiry_ms;
-		}
+
 	} else if (CHECK_LUN_MODE(chip, SD_MS_1LUN)) {
 		inquiry_string = inquiry_sdms;
 	} else {
@@ -329,9 +329,8 @@
 	}
 
 	buf = vmalloc(scsi_bufflen(srb));
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 #ifdef SUPPORT_MAGIC_GATE
 	if ((chip->mspro_formatter_enable) &&
@@ -340,23 +339,21 @@
 	if (chip->mspro_formatter_enable)
 #endif
 	{
-		if (!card || (card == MS_CARD)) {
+		if (!card || (card == MS_CARD))
 			pro_formatter_flag = 1;
-		}
 	}
 
 	if (pro_formatter_flag) {
-		if (scsi_bufflen(srb) < 56) {
+		if (scsi_bufflen(srb) < 56)
 			sendbytes = (unsigned char)(scsi_bufflen(srb));
-		} else {
+		else
 			sendbytes = 56;
-		}
+
 	} else {
-		if (scsi_bufflen(srb) < 36) {
+		if (scsi_bufflen(srb) < 36)
 			sendbytes = (unsigned char)(scsi_bufflen(srb));
-		} else {
+		else
 			sendbytes = 36;
-		}
 	}
 
 	if (sendbytes > 8) {
@@ -371,9 +368,8 @@
 	}
 
 	if (pro_formatter_flag) {
-		if (sendbytes > 36) {
+		if (sendbytes > 36)
 			memcpy(buf + 36, formatter_inquiry_str, sendbytes - 36);
-		}
 	}
 
 	scsi_set_resid(srb, 0);
@@ -467,9 +463,8 @@
 	}
 
 	buf = vmalloc(scsi_bufflen(srb));
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	tmp = (unsigned char *)sense;
 	memcpy(buf, tmp, scsi_bufflen(srb));
@@ -494,15 +489,15 @@
 
 	if (cmd == MODE_SENSE) {
 		sys_info_offset = 8;
-		if (data_size > 0x68) {
+		if (data_size > 0x68)
 			data_size = 0x68;
-		}
+
 		buf[i++] = 0x67;  /* Mode Data Length */
 	} else {
 		sys_info_offset = 12;
-		if (data_size > 0x6C) {
+		if (data_size > 0x6C)
 			data_size = 0x6C;
-		}
+
 		buf[i++] = 0x00;  /* Mode Data Length (MSB) */
 		buf[i++] = 0x6A;  /* Mode Data Length (LSB) */
 	}
@@ -520,11 +515,11 @@
 		}
 
 		/* WP */
-		if (check_card_wp(chip, lun)) {
+		if (check_card_wp(chip, lun))
 			buf[i++] = 0x80;
-		} else {
+		else
 			buf[i++] = 0x00;
-		}
+
 	} else {
 		buf[i++] = 0x00;	/* MediaType */
 		buf[i++] = 0x00;	/* WP */
@@ -545,11 +540,10 @@
 		if (data_size >= 11)
 			buf[i++] = 0x00;		/* No Access Control */
 		if (data_size >= 12) {
-			if (support_format) {
+			if (support_format)
 				buf[i++] = 0xC0;	/* SF, SGM */
-			} else {
+			else
 				buf[i++] = 0x00;
-			}
 		}
 	} else {
 		/* The Following Data is the content of "Page 0x20" */
@@ -560,11 +554,10 @@
 		if (data_size >= 7)
 			buf[i++] = 0x00;		/* No Access Control */
 		if (data_size >= 8) {
-			if (support_format) {
+			if (support_format)
 				buf[i++] = 0xC0;	/* SF, SGM */
-			} else {
+			else
 				buf[i++] = 0x00;
-			}
 		}
 	}
 
@@ -600,9 +593,8 @@
 	if ((chip->lun2card[lun] & MS_CARD)) {
 		if (!card || (card == MS_CARD)) {
 			dataSize = 108;
-			if (chip->mspro_formatter_enable) {
+			if (chip->mspro_formatter_enable)
 				pro_formatter_flag = 1;
-			}
 		}
 	}
 #else
@@ -615,9 +607,8 @@
 #endif
 
 	buf = kmalloc(dataSize, GFP_KERNEL);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	pageCode = srb->cmnd[2] & 0x3f;
 
@@ -632,11 +623,11 @@
 				dataSize = 4;
 				buf[0] = 0x03;
 				buf[1] = 0x00;
-				if (check_card_wp(chip, lun)) {
+				if (check_card_wp(chip, lun))
 					buf[2] = 0x80;
-				} else {
+				else
 					buf[2] = 0x00;
-				}
+
 				buf[3] = 0x00;
 			}
 		} else {
@@ -648,11 +639,10 @@
 				buf[0] = 0x00;
 				buf[1] = 0x06;
 				buf[2] = 0x00;
-				if (check_card_wp(chip, lun)) {
+				if (check_card_wp(chip, lun))
 					buf[3] = 0x80;
-				} else {
+				else
 					buf[3] = 0x00;
-				}
 				buf[4] = 0x00;
 				buf[5] = 0x00;
 				buf[6] = 0x00;
@@ -759,11 +749,11 @@
 
 	if (chip->rw_fail_cnt[lun] == 3) {
 		RTSX_DEBUGP("read/write fail three times in succession\n");
-		if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+		if (srb->sc_data_direction == DMA_FROM_DEVICE)
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
-		} else {
+		else
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
-		}
+
 		TRACE_RET(chip, TRANSPORT_FAILED);
 	}
 
@@ -776,9 +766,8 @@
 		if (CHECK_PID(chip, 0x5209) && chip->max_payload) {
 			u8 val = 0x10 | (chip->max_payload << 5);
 			retval = rtsx_write_cfg_dw(chip, 0, 0x78, 0xFF, val);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_ERROR);
-			}
 		}
 	}
 
@@ -789,11 +778,10 @@
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
 		} else {
 			chip->rw_fail_cnt[lun]++;
-			if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+			if (srb->sc_data_direction == DMA_FROM_DEVICE)
 				set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
-			} else {
+			else
 				set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
-			}
 		}
 		retval = TRANSPORT_FAILED;
 		TRACE_GOTO(chip, Exit);
@@ -808,9 +796,8 @@
 	if (srb->sc_data_direction == DMA_TO_DEVICE) {
 		if (CHECK_PID(chip, 0x5209) && chip->max_payload) {
 			retval = rtsx_write_cfg_dw(chip, 0, 0x78, 0xFF, 0x10);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_ERROR);
-			}
 		}
 	}
 
@@ -837,9 +824,8 @@
 	buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12;
 
 	buf = kmalloc(buf_len, GFP_KERNEL);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	buf[i++] = 0;
 	buf[i++] = 0;
@@ -864,22 +850,20 @@
 			buf[i++] = (unsigned char)(card_size >> 8);
 			buf[i++] = (unsigned char)card_size;
 
-			if (desc_cnt == 2) {
+			if (desc_cnt == 2)
 				buf[i++] = 2;
-			} else {
+			else
 				buf[i++] = 0;
-			}
 		} else {
 			buf[i++] = 0xFF;
 			buf[i++] = 0xFF;
 			buf[i++] = 0xFF;
 			buf[i++] = 0xFF;
 
-			if (desc_cnt == 2) {
+			if (desc_cnt == 2)
 				buf[i++] = 3;
-			} else {
+			else
 				buf[i++] = 0;
-			}
 		}
 
 		buf[i++] = 0x00;
@@ -916,9 +900,8 @@
 	}
 
 	buf = kmalloc(8, GFP_KERNEL);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	card_size = get_card_size(chip, lun);
 	buf[0] = (unsigned char)((card_size - 1) >> 24);
@@ -956,9 +939,8 @@
 	len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5];
 
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	retval = rtsx_force_power_on(chip, SSC_PDCTL);
 	if (retval != STATUS_SUCCESS) {
@@ -1016,9 +998,8 @@
 	} else {
 		len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
 		buf = (u8 *)vmalloc(len);
-		if (buf == NULL) {
+		if (buf == NULL)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		rtsx_stor_get_xfer_buf(buf, len, srb);
 		scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1061,9 +1042,8 @@
 	}
 
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	retval = rtsx_force_power_on(chip, SSC_PDCTL);
 	if (retval != STATUS_SUCCESS) {
@@ -1114,9 +1094,8 @@
 
 	len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
 	buf = (u8 *)vmalloc(len);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	rtsx_stor_get_xfer_buf(buf, len, srb);
 	scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1200,16 +1179,15 @@
 	clear = srb->cmnd[2];
 
 	buf = (unsigned char *)vmalloc(scsi_bufflen(srb));
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 	ptr = buf;
 
-	if (chip->trace_msg[chip->msg_idx].valid) {
+	if (chip->trace_msg[chip->msg_idx].valid)
 		msg_cnt = TRACE_ITEM_CNT;
-	} else {
+	else
 		msg_cnt = chip->msg_idx;
-	}
+
 	*(ptr++) = (u8)(msg_cnt >> 24);
 	*(ptr++) = (u8)(msg_cnt >> 16);
 	*(ptr++) = (u8)(msg_cnt >> 8);
@@ -1225,15 +1203,14 @@
 
 		*(ptr++) = (u8)(chip->trace_msg[idx].line >> 8);
 		*(ptr++) = (u8)(chip->trace_msg[idx].line);
-		for (j = 0; j < MSG_FUNC_LEN; j++) {
+		for (j = 0; j < MSG_FUNC_LEN; j++)
 			*(ptr++) = chip->trace_msg[idx].func[j];
-		}
-		for (j = 0; j < MSG_FILE_LEN; j++) {
+
+		for (j = 0; j < MSG_FILE_LEN; j++)
 			*(ptr++) = chip->trace_msg[idx].file[j];
-		}
-		for (j = 0; j < TIME_VAL_LEN; j++) {
+
+		for (j = 0; j < TIME_VAL_LEN; j++)
 			*(ptr++) = chip->trace_msg[idx].timeval_buf[j];
-		}
 	}
 
 	rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb);
@@ -1424,20 +1401,19 @@
 	len = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5];
 	len = min(len, (u16)scsi_bufflen(srb));
 
-	if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+	if (srb->sc_data_direction == DMA_FROM_DEVICE)
 		RTSX_DEBUGP("Read from device\n");
-	} else {
+	else
 		RTSX_DEBUGP("Write to device\n");
-	}
 
 	retval = rtsx_transfer_data(chip, 0, scsi_sglist(srb), len,
 			scsi_sg_count(srb), srb->sc_data_direction, 1000);
 	if (retval < 0) {
-		if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+		if (srb->sc_data_direction == DMA_FROM_DEVICE)
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
-		} else {
+		else
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
-		}
+
 		TRACE_RET(chip, TRANSPORT_FAILED);
 	}
 	scsi_set_resid(srb, 0);
@@ -1462,22 +1438,20 @@
 	status[0] = (u8)(chip->product_id);
 	status[1] = chip->ic_version;
 
-	if (chip->auto_delink_en) {
+	if (chip->auto_delink_en)
 		status[2] = 0x10;
-	} else {
+	else
 		status[2] = 0x00;
-	}
 
 	status[3] = 20;
 	status[4] = 10;
 	status[5] = 05;
 	status[6] = 21;
 
-	if (chip->card_wp) {
+	if (chip->card_wp)
 		status[7] = 0x20;
-	} else {
+	else
 		status[7] = 0x00;
-	}
 
 #ifdef SUPPORT_OCP
 	status[8] = 0;
@@ -1489,67 +1463,60 @@
 		oc_ever_mask = SD_OC_EVER;
 	}
 
-	if (chip->ocp_stat & oc_now_mask) {
+	if (chip->ocp_stat & oc_now_mask)
 		status[8] |= 0x02;
-	}
-	if (chip->ocp_stat & oc_ever_mask) {
+
+	if (chip->ocp_stat & oc_ever_mask)
 		status[8] |= 0x01;
-	}
 #endif
 
 	if (card == SD_CARD) {
 		if (CHK_SD(sd_card)) {
 			if (CHK_SD_HCXC(sd_card)) {
-				if (sd_card->capacity > 0x4000000) {
+				if (sd_card->capacity > 0x4000000)
 					status[0x0E] = 0x02;
-				} else {
+				else
 					status[0x0E] = 0x01;
-				}
 			} else {
 				status[0x0E] = 0x00;
 			}
 
-			if (CHK_SD_SDR104(sd_card)) {
+			if (CHK_SD_SDR104(sd_card))
 				status[0x0F] = 0x03;
-			} else if (CHK_SD_DDR50(sd_card)) {
+			else if (CHK_SD_DDR50(sd_card))
 				status[0x0F] = 0x04;
-			} else if (CHK_SD_SDR50(sd_card)) {
+			else if (CHK_SD_SDR50(sd_card))
 				status[0x0F] = 0x02;
-			} else if (CHK_SD_HS(sd_card)) {
+			else if (CHK_SD_HS(sd_card))
 				status[0x0F] = 0x01;
-			} else {
+			else
 				status[0x0F] = 0x00;
-			}
 		} else {
-			if (CHK_MMC_SECTOR_MODE(sd_card)) {
+			if (CHK_MMC_SECTOR_MODE(sd_card))
 				status[0x0E] = 0x01;
-			} else {
+			else
 				status[0x0E] = 0x00;
-			}
 
-			if (CHK_MMC_DDR52(sd_card)) {
+			if (CHK_MMC_DDR52(sd_card))
 				status[0x0F] = 0x03;
-			} else if (CHK_MMC_52M(sd_card)) {
+			else if (CHK_MMC_52M(sd_card))
 				status[0x0F] = 0x02;
-			} else if (CHK_MMC_26M(sd_card)) {
+			else if (CHK_MMC_26M(sd_card))
 				status[0x0F] = 0x01;
-			} else {
+			else
 				status[0x0F] = 0x00;
-			}
 		}
 	} else if (card == MS_CARD) {
 		if (CHK_MSPRO(ms_card)) {
-			if (CHK_MSXC(ms_card)) {
+			if (CHK_MSXC(ms_card))
 				status[0x0E] = 0x01;
-			} else {
+			else
 				status[0x0E] = 0x00;
-			}
 
-			if (CHK_HG8BIT(ms_card)) {
+			if (CHK_HG8BIT(ms_card))
 				status[0x0F] = 0x01;
-			} else {
+			else
 				status[0x0F] = 0x00;
-			}
 		}
 	}
 
@@ -1600,37 +1567,35 @@
 	if (phy_debug_mode) {
 		chip->phy_debug_mode = 1;
 		retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
+
 		rtsx_disable_bus_int(chip);
 
 		retval = rtsx_read_phy_register(chip, 0x1C, &reg);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
+
 		reg |= 0x0001;
 		retval = rtsx_write_phy_register(chip, 0x1C, reg);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
 	} else {
 		chip->phy_debug_mode = 0;
 		retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0x77);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
+
 		rtsx_enable_bus_int(chip);
 
 		retval = rtsx_read_phy_register(chip, 0x1C, &reg);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
+
 		reg &= 0xFFFE;
 		retval = rtsx_write_phy_register(chip, 0x1C, reg);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_FAILED);
-		}
 	}
 
 	return TRANSPORT_GOOD;
@@ -1737,9 +1702,8 @@
 
 	if (len) {
 		buf = (u8 *)vmalloc(len);
-		if (!buf) {
+		if (!buf)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		retval = rtsx_force_power_on(chip, SSC_PDCTL);
 		if (retval != STATUS_SUCCESS) {
@@ -1795,9 +1759,8 @@
 		len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
 
 		buf = (u8 *)vmalloc(len);
-		if (buf == NULL) {
+		if (buf == NULL)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		rtsx_stor_get_xfer_buf(buf, len, srb);
 		scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1886,9 +1849,8 @@
 	len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7];
 
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	retval = rtsx_force_power_on(chip, SSC_PDCTL);
 	if (retval != STATUS_SUCCESS) {
@@ -1934,9 +1896,8 @@
 
 	len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
 	buf = (u8 *)vmalloc(len);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	rtsx_stor_get_xfer_buf(buf, len, srb);
 	scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1980,9 +1941,8 @@
 	len = srb->cmnd[5];
 
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	retval = rtsx_force_power_on(chip, SSC_PDCTL);
 	if (retval != STATUS_SUCCESS) {
@@ -2029,9 +1989,8 @@
 
 	len = (u8)min(scsi_bufflen(srb), (unsigned int)len);
 	buf = (u8 *)vmalloc(len);
-	if (buf == NULL) {
+	if (buf == NULL)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	rtsx_stor_get_xfer_buf(buf, len, srb);
 	scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -2093,27 +2052,23 @@
 	vfree(buf);
 
 	retval = card_power_off(chip, SPI_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	if (chip->asic_code) {
 		retval = rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		wait_timeout(600);
 
 		retval = rtsx_write_phy_register(chip, 0x08, val);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		retval = rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 	}
 
 	return result;
@@ -2140,11 +2095,10 @@
 
 	RTSX_DEBUGP("%s: func = %d, addr = 0x%x, len = %d\n", __func__, func, addr, len);
 
-	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) {
+	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip))
 		func_max = 1;
-	} else {
+	else
 		func_max = 0;
-	}
 
 	if (func > func_max) {
 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
@@ -2152,9 +2106,8 @@
 	}
 
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	retval = rtsx_read_cfg_seq(chip, func, addr, buf, len);
 	if (retval != STATUS_SUCCESS) {
@@ -2193,11 +2146,10 @@
 
 	RTSX_DEBUGP("%s: func = %d, addr = 0x%x\n", __func__, func, addr);
 
-	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) {
+	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip))
 		func_max = 1;
-	} else {
+	else
 		func_max = 0;
-	}
 
 	if (func > func_max) {
 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
@@ -2206,9 +2158,8 @@
 
 	len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
 	buf = (u8 *)vmalloc(len);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	rtsx_stor_get_xfer_buf(buf, len, srb);
 	scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -2328,63 +2279,56 @@
 	rtsx_status[4] = (u8)lun;
 
 	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
-		if (chip->lun2card[lun] == SD_CARD) {
+		if (chip->lun2card[lun] == SD_CARD)
 			rtsx_status[5] = 2;
-		} else {
+		else
 			rtsx_status[5] = 3;
-		}
 	} else {
 		if (chip->card_exist) {
-			if (chip->card_exist & XD_CARD) {
+			if (chip->card_exist & XD_CARD)
 				rtsx_status[5] = 4;
-			} else if (chip->card_exist & SD_CARD) {
+			else if (chip->card_exist & SD_CARD)
 				rtsx_status[5] = 2;
-			} else if (chip->card_exist & MS_CARD) {
+			else if (chip->card_exist & MS_CARD)
 				rtsx_status[5] = 3;
-			} else {
+			else
 				rtsx_status[5] = 7;
-			}
 		} else {
 			rtsx_status[5] = 7;
 		}
 	}
 
-	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+	if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 		rtsx_status[6] = 2;
-	} else {
+	else
 		rtsx_status[6] = 1;
-	}
 
 	rtsx_status[7] = (u8)(chip->product_id);
 	rtsx_status[8] = chip->ic_version;
 
-	if (check_card_exist(chip, lun)) {
+	if (check_card_exist(chip, lun))
 		rtsx_status[9] = 1;
-	} else {
+	else
 		rtsx_status[9] = 0;
-	}
 
-	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
+	if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
 		rtsx_status[10] = 0;
-	} else {
+	else
 		rtsx_status[10] = 1;
-	}
 
 	if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
-		if (chip->lun2card[lun] == SD_CARD) {
+		if (chip->lun2card[lun] == SD_CARD)
 			rtsx_status[11] = SD_CARD;
-		} else {
+		else
 			rtsx_status[11] = MS_CARD;
-		}
 	} else {
 		rtsx_status[11] = XD_CARD | SD_CARD | MS_CARD;
 	}
 
-	if (check_card_ready(chip, lun)) {
+	if (check_card_ready(chip, lun))
 		rtsx_status[12] = 1;
-	} else {
+	else
 		rtsx_status[12] = 0;
-	}
 
 	if (get_lun_card(chip, lun) == XD_CARD) {
 		rtsx_status[13] = 0x40;
@@ -2421,29 +2365,26 @@
 	} else {
 		if (CHECK_LUN_MODE(chip, DEFAULT_SINGLE)) {
 #ifdef SUPPORT_SDIO
-			if (chip->sd_io && chip->sd_int) {
+			if (chip->sd_io && chip->sd_int)
 				rtsx_status[13] = 0x60;
-			} else {
+			else
 				rtsx_status[13] = 0x70;
-			}
 #else
 			rtsx_status[13] = 0x70;
 #endif
 		} else {
-			if (chip->lun2card[lun] == SD_CARD) {
+			if (chip->lun2card[lun] == SD_CARD)
 				rtsx_status[13] = 0x20;
-			} else {
+			else
 				rtsx_status[13] = 0x30;
-			}
 		}
 	}
 
 	rtsx_status[14] = 0x78;
-	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) {
+	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip))
 		rtsx_status[15] = 0x83;
-	} else {
+	else
 		rtsx_status[15] = 0x82;
-	}
 
 	buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(rtsx_status));
 	rtsx_stor_set_xfer_buf(rtsx_status, buf_len, srb);
@@ -2482,7 +2423,7 @@
 	unsigned int lun = SCSI_LUN(srb);
 	u8 gpio_dir;
 
-	if (CHECK_PID(chip, 0x5208) && CHECK_PID(chip, 0x5288)) {
+	if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) {
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 		TRACE_RET(chip, TRANSPORT_FAILED);
 	}
@@ -2538,9 +2479,8 @@
 
 	rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir);
 
-	if (result != STATUS_SUCCESS) {
+	if (result != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 	return TRANSPORT_GOOD;
 }
@@ -2610,13 +2550,12 @@
 	unsigned int lun = SCSI_LUN(srb);
 	u16 sec_cnt;
 
-	if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
+	if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10))
 		sec_cnt = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
-	} else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) {
+	else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6))
 		sec_cnt = srb->cmnd[4];
-	} else {
+	else
 		return;
-	}
 
 	if (chip->rw_cap[lun] >= GPIO_TOGGLE_THRESHOLD) {
 		toggle_gpio(chip, LED_GPIO);
@@ -2659,11 +2598,10 @@
 	}
 	rtsx_set_stat(chip, RTSX_STAT_RUN);
 
-	if (srb->cmnd[8] & 0x01) {
+	if (srb->cmnd[8] & 0x01)
 		quick_format = 0;
-	} else {
+	else
 		quick_format = 1;
-	}
 
 	if (!(chip->card_ready & MS_CARD)) {
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
@@ -2724,27 +2662,25 @@
 		TRACE_RET(chip, TRANSPORT_FAILED);
 	}
 
-	if (dev_info_id == 0x15) {
+	if (dev_info_id == 0x15)
 		buf_len = data_len = 0x3A;
-	} else {
+	else
 		buf_len = data_len = 0x6A;
-	}
 
 	buf = kmalloc(buf_len, GFP_KERNEL);
-	if (!buf) {
+	if (!buf)
 		TRACE_RET(chip, TRANSPORT_ERROR);
-	}
 
 	i = 0;
 	/*  GET Memory Stick Media Information Response Header */
 	buf[i++] = 0x00;		/* Data length MSB */
 	buf[i++] = data_len; 		/* Data length LSB */
 	/* Device Information Type Code */
-	if (CHK_MSXC(ms_card)) {
+	if (CHK_MSXC(ms_card))
 		buf[i++] = 0x03;
-	} else {
+	else
 		buf[i++] = 0x02;
-	}
+
 	/* SGM bit */
 	buf[i++] = 0x01;
 	/* Reserved */
@@ -2759,11 +2695,11 @@
 	/* Device Information ID Number */
 	buf[i++] = dev_info_id;
 	/* Device Information Length */
-	if (dev_info_id == 0x15) {
+	if (dev_info_id == 0x15)
 		data_len = 0x31;
-	} else {
+	else
 		data_len = 0x61;
-	}
+
 	buf[i++] = 0x00;		/* Data length MSB */
 	buf[i++] = data_len; 		/* Data length LSB */
 	/* Valid Bit */
@@ -2778,11 +2714,10 @@
 
 	rtsx_stor_set_xfer_buf(buf, buf_len, srb);
 
-	if (dev_info_id == 0x15) {
+	if (dev_info_id == 0x15)
 		scsi_set_resid(srb, scsi_bufflen(srb)-0x3C);
-	} else {
+	else
 		scsi_set_resid(srb, scsi_bufflen(srb)-0x6C);
-	}
 
 	kfree(buf);
 	return STATUS_SUCCESS;
@@ -2793,13 +2728,11 @@
 {
 	int retval = TRANSPORT_ERROR;
 
-	if (srb->cmnd[2] == MS_FORMAT) {
+	if (srb->cmnd[2] == MS_FORMAT)
 		retval = ms_format_cmnd(srb, chip);
-	}
 #ifdef SUPPORT_PCGL_1P18
-	else if (srb->cmnd[2] == GET_MS_INFORMATION) {
+	else if (srb->cmnd[2] == GET_MS_INFORMATION)
 		retval = get_ms_information(srb, chip);
-	}
 #endif
 
 	return retval;
@@ -2912,9 +2845,9 @@
 			(srb->cmnd[8] == 0x04) &&
 			(srb->cmnd[9] == 0x1C)) {
 			retval = mg_get_local_EKB(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -2926,9 +2859,9 @@
 			(srb->cmnd[8] == 0x00) &&
 			(srb->cmnd[9] == 0x24)) {
 			retval = mg_get_rsp_chg(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -2945,9 +2878,9 @@
 			(srb->cmnd[4] == 0x00) &&
 			(srb->cmnd[5] < 32)) {
 			retval = mg_get_ICV(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -3014,9 +2947,9 @@
 			(srb->cmnd[8] == 0x00) &&
 			(srb->cmnd[9] == 0x0C)) {
 			retval = mg_set_leaf_id(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -3028,9 +2961,9 @@
 			(srb->cmnd[8] == 0x00) &&
 			(srb->cmnd[9] == 0x0C)) {
 			retval = mg_chg(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -3042,9 +2975,9 @@
 			(srb->cmnd[8] == 0x00) &&
 			(srb->cmnd[9] == 0x0C)) {
 			retval = mg_rsp(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
@@ -3061,9 +2994,9 @@
 			(srb->cmnd[4] == 0x00) &&
 			(srb->cmnd[5] < 32)) {
 			retval = mg_set_ICV(srb, chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else {
 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
 			TRACE_RET(chip, TRANSPORT_FAILED);
diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c
index 54a4742..1f9a424 100644
--- a/drivers/staging/rts_pstor/rtsx_transport.c
+++ b/drivers/staging/rts_pstor/rtsx_transport.c
@@ -218,9 +218,9 @@
 	val |= (u32)data;
 
 	spin_lock_irq(&chip->rtsx->reg_lock);
-	if (chip->ci < (HOST_CMDS_BUF_LEN / 4)) {
+	if (chip->ci < (HOST_CMDS_BUF_LEN / 4))
 		cb[(chip->ci)++] = cpu_to_le32(val);
-	}
+
 	spin_unlock_irq(&chip->rtsx->reg_lock);
 }
 
@@ -244,15 +244,14 @@
 	long timeleft;
 	int err = 0;
 
-	if (card == SD_CARD) {
+	if (card == SD_CARD)
 		rtsx->check_card_cd = SD_EXIST;
-	} else if (card == MS_CARD) {
+	else if (card == MS_CARD)
 		rtsx->check_card_cd = MS_EXIST;
-	} else if (card == XD_CARD) {
+	else if (card == XD_CARD)
 		rtsx->check_card_cd = XD_EXIST;
-	} else {
+	else
 		rtsx->check_card_cd = 0;
-	}
 
 	spin_lock_irq(&rtsx->reg_lock);
 
@@ -281,11 +280,11 @@
 	}
 
 	spin_lock_irq(&rtsx->reg_lock);
-	if (rtsx->trans_result == TRANS_RESULT_FAIL) {
+	if (rtsx->trans_result == TRANS_RESULT_FAIL)
 		err = -EIO;
-	} else if (rtsx->trans_result == TRANS_RESULT_OK) {
+	else if (rtsx->trans_result == TRANS_RESULT_OK)
 		err = 0;
-	}
+
 	spin_unlock_irq(&rtsx->reg_lock);
 
 finish_send_cmd:
@@ -341,23 +340,21 @@
 	if ((sg == NULL) || (num_sg <= 0) || !offset || !index)
 		return -EIO;
 
-	if (dma_dir == DMA_TO_DEVICE) {
+	if (dma_dir == DMA_TO_DEVICE)
 		dir = HOST_TO_DEVICE;
-	} else if (dma_dir == DMA_FROM_DEVICE) {
+	else if (dma_dir == DMA_FROM_DEVICE)
 		dir = DEVICE_TO_HOST;
-	} else {
+	else
 		return -ENXIO;
-	}
 
-	if (card == SD_CARD) {
+	if (card == SD_CARD)
 		rtsx->check_card_cd = SD_EXIST;
-	} else if (card == MS_CARD) {
+	else if (card == MS_CARD)
 		rtsx->check_card_cd = MS_EXIST;
-	} else if (card == XD_CARD) {
+	else if (card == XD_CARD)
 		rtsx->check_card_cd = XD_EXIST;
-	} else {
+	else
 		rtsx->check_card_cd = 0;
-	}
 
 	spin_lock_irq(&rtsx->reg_lock);
 
@@ -405,11 +402,10 @@
 			*offset = 0;
 			*index = *index + 1;
 		}
-		if ((i == (sg_cnt - 1)) || !resid) {
+		if ((i == (sg_cnt - 1)) || !resid)
 			option = SG_VALID | SG_END | SG_TRANS_DATA;
-		} else {
+		else
 			option = SG_VALID | SG_TRANS_DATA;
-		}
 
 		rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
 
@@ -468,11 +464,11 @@
 	}
 
 	spin_lock_irq(&rtsx->reg_lock);
-	if (rtsx->trans_result == TRANS_RESULT_FAIL) {
+	if (rtsx->trans_result == TRANS_RESULT_FAIL)
 		err = -EIO;
-	} else if (rtsx->trans_result == TRANS_RESULT_OK) {
+	else if (rtsx->trans_result == TRANS_RESULT_OK)
 		err = 0;
-	}
+
 	spin_unlock_irq(&rtsx->reg_lock);
 
 out:
@@ -501,23 +497,21 @@
 	if ((sg == NULL) || (num_sg <= 0))
 		return -EIO;
 
-	if (dma_dir == DMA_TO_DEVICE) {
+	if (dma_dir == DMA_TO_DEVICE)
 		dir = HOST_TO_DEVICE;
-	} else if (dma_dir == DMA_FROM_DEVICE) {
+	else if (dma_dir == DMA_FROM_DEVICE)
 		dir = DEVICE_TO_HOST;
-	} else {
+	else
 		return -ENXIO;
-	}
 
-	if (card == SD_CARD) {
+	if (card == SD_CARD)
 		rtsx->check_card_cd = SD_EXIST;
-	} else if (card == MS_CARD) {
+	else if (card == MS_CARD)
 		rtsx->check_card_cd = MS_EXIST;
-	} else if (card == XD_CARD) {
+	else if (card == XD_CARD)
 		rtsx->check_card_cd = XD_EXIST;
-	} else {
+	else
 		rtsx->check_card_cd = 0;
-	}
 
 	spin_lock_irq(&rtsx->reg_lock);
 
@@ -537,11 +531,10 @@
 		u32 val = TRIG_DMA;
 		int sg_cnt, j;
 
-		if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8)) {
+		if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8))
 			sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8);
-		} else {
+		else
 			sg_cnt = (HOST_SG_TBL_BUF_LEN / 8);
-		}
 
 		chip->sgi = 0;
 		for (j = 0; j < sg_cnt; j++) {
@@ -552,11 +545,10 @@
 			RTSX_DEBUGP("DMA addr: 0x%x, Len: 0x%x\n",
 				     (unsigned int)addr, len);
 
-			if (j == (sg_cnt - 1)) {
+			if (j == (sg_cnt - 1))
 				option = SG_VALID | SG_END | SG_TRANS_DATA;
-			} else {
+			else
 				option = SG_VALID | SG_TRANS_DATA;
-			}
 
 			rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
 
@@ -615,11 +607,11 @@
 	}
 
 	spin_lock_irq(&rtsx->reg_lock);
-	if (rtsx->trans_result == TRANS_RESULT_FAIL) {
+	if (rtsx->trans_result == TRANS_RESULT_FAIL)
 		err = -EIO;
-	} else if (rtsx->trans_result == TRANS_RESULT_OK) {
+	else if (rtsx->trans_result == TRANS_RESULT_OK)
 		err = 0;
-	}
+
 	spin_unlock_irq(&rtsx->reg_lock);
 
 out:
@@ -647,27 +639,25 @@
 	if ((buf == NULL) || (len <= 0))
 		return -EIO;
 
-	if (dma_dir == DMA_TO_DEVICE) {
+	if (dma_dir == DMA_TO_DEVICE)
 		dir = HOST_TO_DEVICE;
-	} else if (dma_dir == DMA_FROM_DEVICE) {
+	else if (dma_dir == DMA_FROM_DEVICE)
 		dir = DEVICE_TO_HOST;
-	} else {
+	else
 		return -ENXIO;
-	}
 
 	addr = dma_map_single(&(rtsx->pci->dev), buf, len, dma_dir);
 	if (!addr)
 		return -ENOMEM;
 
-	if (card == SD_CARD) {
+	if (card == SD_CARD)
 		rtsx->check_card_cd = SD_EXIST;
-	} else if (card == MS_CARD) {
+	else if (card == MS_CARD)
 		rtsx->check_card_cd = MS_EXIST;
-	} else if (card == XD_CARD) {
+	else if (card == XD_CARD)
 		rtsx->check_card_cd = XD_EXIST;
-	} else {
+	else
 		rtsx->check_card_cd = 0;
-	}
 
 	val |= (u32)(dir & 0x01) << 29;
 	val |= (u32)(len & 0x00FFFFFF);
@@ -698,11 +688,11 @@
 	}
 
 	spin_lock_irq(&rtsx->reg_lock);
-	if (rtsx->trans_result == TRANS_RESULT_FAIL) {
+	if (rtsx->trans_result == TRANS_RESULT_FAIL)
 		err = -EIO;
-	} else if (rtsx->trans_result == TRANS_RESULT_OK) {
+	else if (rtsx->trans_result == TRANS_RESULT_OK)
 		err = 0;
-	}
+
 	spin_unlock_irq(&rtsx->reg_lock);
 
 out:
diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c
index 3cc9a48..c6a581c 100644
--- a/drivers/staging/rts_pstor/sd.c
+++ b/drivers/staging/rts_pstor/sd.c
@@ -192,9 +192,9 @@
 
 		stat_idx = 16;
 	} else if (rsp_type != SD_RSP_TYPE_R0) {
-		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) {
+		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++)
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
-		}
+
 		stat_idx = 5;
 	}
 
@@ -273,9 +273,8 @@
 	if ((rsp_type == SD_RSP_TYPE_R1) || (rsp_type == SD_RSP_TYPE_R1b)) {
 		if ((cmd_idx != SEND_RELATIVE_ADDR) && (cmd_idx != SEND_IF_COND)) {
 			if (cmd_idx != STOP_TRANSMISSION) {
-				if (ptr[1] & 0x80) {
+				if (ptr[1] & 0x80)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 #ifdef SUPPORT_SD_LOCK
 			if (ptr[1] & 0x7D)
@@ -294,11 +293,10 @@
 				RTSX_DEBUGP("ptr[3]: 0x%02x\n", ptr[3]);
 				TRACE_RET(chip, STATUS_FAIL);
 			}
-			if (ptr[3] & 0x01) {
+			if (ptr[3] & 0x01)
 				sd_card->sd_data_buf_ready = 1;
-			} else {
+			else
 				sd_card->sd_data_buf_ready = 0;
-			}
 		}
 	}
 
@@ -322,17 +320,15 @@
 	if (!buf)
 		buf_len = 0;
 
-	if (buf_len > 512) {
+	if (buf_len > 512)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	rtsx_init_cmd(chip);
 
 	if (cmd_len) {
 		RTSX_DEBUGP("SD/MMC CMD %d\n", cmd[0] - 0x40);
-		for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++) {
+		for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++)
 			rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0 + i, 0xFF, cmd[i]);
-		}
 	}
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, (u8)(byte_cnt >> 8));
@@ -344,9 +340,9 @@
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF,
 			SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END |
 			SD_CHECK_CRC7 | SD_RSP_LEN_6);
-	if (trans_mode != SD_TM_AUTO_TUNING) {
+	if (trans_mode != SD_TM_AUTO_TUNING)
 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
-	}
+
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, trans_mode | SD_TRANSFER_START);
 	rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END);
 
@@ -362,9 +358,8 @@
 
 	if (buf && buf_len) {
 		retval = rtsx_read_ppbuf(chip, buf, buf_len);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -390,9 +385,8 @@
 
 	if (buf && buf_len) {
 		retval = rtsx_write_ppbuf(chip, buf, buf_len);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	rtsx_init_cmd(chip);
@@ -450,15 +444,13 @@
 			break;
 	}
 
-	if (i == 6) {
+	if (i == 6)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	memcpy(sd_card->raw_csd, rsp + 1, 15);
 
-	if (CHECK_PID(chip, 0x5209)) {
+	if (CHECK_PID(chip, 0x5209))
 		RTSX_READ_REG(chip, REG_SD_CMD5, sd_card->raw_csd + 15);
-	}
 
 	RTSX_DEBUGP("CSD Response:\n");
 	RTSX_DUMP(sd_card->raw_csd, 16);
@@ -469,35 +461,34 @@
 	trans_speed = rsp[4];
 	if ((trans_speed & 0x07) == 0x02) {
 		if ((trans_speed & 0xf8) >= 0x30) {
-			if (chip->asic_code) {
+			if (chip->asic_code)
 				sd_card->sd_clock = 47;
-			} else {
+			else
 				sd_card->sd_clock = CLK_50;
-			}
+
 		} else if ((trans_speed & 0xf8) == 0x28) {
-			if (chip->asic_code) {
+			if (chip->asic_code)
 				sd_card->sd_clock = 39;
-			} else {
+			else
 				sd_card->sd_clock = CLK_40;
-			}
+
 		} else if ((trans_speed & 0xf8) == 0x20) {
-			if (chip->asic_code) {
+			if (chip->asic_code)
 				sd_card->sd_clock = 29;
-			} else {
+			else
 				sd_card->sd_clock = CLK_30;
-			}
+
 		} else if ((trans_speed & 0xf8) >= 0x10) {
-			if (chip->asic_code) {
+			if (chip->asic_code)
 				sd_card->sd_clock = 23;
-			} else {
+			else
 				sd_card->sd_clock = CLK_20;
-			}
+
 		} else if ((trans_speed & 0x08) >= 0x08) {
-			if (chip->asic_code) {
+			if (chip->asic_code)
 				sd_card->sd_clock = 19;
-			} else {
+			else
 				sd_card->sd_clock = CLK_20;
-			}
 		} else {
 			TRACE_RET(chip, STATUS_FAIL);
 		}
@@ -527,9 +518,9 @@
 	}
 
 	if (check_wp) {
-		if (rsp[15] & 0x30) {
+		if (rsp[15] & 0x30)
 			chip->card_wp |= SD_CARD;
-		}
+
 		RTSX_DEBUGP("CSD WP Status: 0x%x\n", rsp[15]);
 	}
 
@@ -568,22 +559,21 @@
 					CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
 			RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0);
 
-			if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_AUTO) {
+			if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_AUTO)
 				val = SD20_TX_NEG_EDGE;
-			} else if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) {
+			else if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY)
 				val = SD20_TX_14_AHEAD;
-			} else {
+			else
 				val = SD20_TX_NEG_EDGE;
-			}
+
 			RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, SD20_TX_SEL_MASK, val);
 
 			if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_AUTO) {
 				if (chip->asic_code) {
-					if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) {
+					if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card))
 						val = SD20_RX_14_DELAY;
-					} else {
+					else
 						val = SD20_RX_POS_EDGE;
-					}
 				} else {
 					val = SD20_RX_14_DELAY;
 				}
@@ -597,32 +587,28 @@
 	} else {
 		u8 val = 0;
 
-		if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) {
+		if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY)
 			val |= 0x10;
-		}
 
 		if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_AUTO) {
 			if (chip->asic_code) {
 				if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) {
-					if (val & 0x10) {
+					if (val & 0x10)
 						val |= 0x04;
-					} else {
+					else
 						val |= 0x08;
-					}
 				}
 			} else {
-				if (val & 0x10) {
+				if (val & 0x10)
 					val |= 0x04;
-				} else {
+				else
 					val |= 0x08;
-				}
 			}
 		} else if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_DELAY) {
-			if (val & 0x10) {
+			if (val & 0x10)
 				val |= 0x04;
-			} else {
+			else
 				val |= 0x08;
-			}
 		}
 
 		RTSX_WRITE_REG(chip, REG_SD_CFG1, 0x1C, val);
@@ -636,41 +622,40 @@
 	struct sd_info *sd_card = &(chip->sd_card);
 
 	if (CHK_SD_SDR104(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = chip->asic_sd_sdr104_clk;
-		} else {
+		else
 			sd_card->sd_clock = chip->fpga_sd_sdr104_clk;
-		}
+
 	} else if (CHK_SD_DDR50(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = chip->asic_sd_ddr50_clk;
-		} else {
+		else
 			sd_card->sd_clock = chip->fpga_sd_ddr50_clk;
-		}
+
 	} else if (CHK_SD_SDR50(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = chip->asic_sd_sdr50_clk;
-		} else {
+		else
 			sd_card->sd_clock = chip->fpga_sd_sdr50_clk;
-		}
+
 	} else if (CHK_SD_HS(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = chip->asic_sd_hs_clk;
-		} else {
+		else
 			sd_card->sd_clock = chip->fpga_sd_hs_clk;
-		}
+
 	} else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = chip->asic_mmc_52m_clk;
-		} else {
+		else
 			sd_card->sd_clock = chip->fpga_mmc_52m_clk;
-		}
+
 	} else if (CHK_MMC_26M(sd_card)) {
-		if (chip->asic_code) {
+		if (chip->asic_code)
 			sd_card->sd_clock = 48;
-		} else {
+		else
 			sd_card->sd_clock = CLK_50;
-		}
 	}
 }
 
@@ -683,13 +668,12 @@
 		val = clk_div;
 	} else {
 		mask = 0x60;
-		if (clk_div == SD_CLK_DIVIDE_0) {
+		if (clk_div == SD_CLK_DIVIDE_0)
 			val = 0x00;
-		} else if (clk_div == SD_CLK_DIVIDE_128) {
+		else if (clk_div == SD_CLK_DIVIDE_128)
 			val = 0x40;
-		} else if (clk_div == SD_CLK_DIVIDE_256) {
+		else if (clk_div == SD_CLK_DIVIDE_256)
 			val = 0x20;
-		}
 	}
 
 	RTSX_WRITE_REG(chip, REG_SD_CFG1, mask, val);
@@ -703,16 +687,14 @@
 	int retval;
 
 	retval = sd_set_sample_push_timing(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	sd_choose_proper_clock(chip);
 
 	retval = switch_clock(chip, sd_card->sd_clock);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -735,9 +717,8 @@
 	}
 
 	retval = sd_send_cmd_get_rsp(chip, cmd_idx, addr, cmd_type, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -750,21 +731,18 @@
 	u8 rsp[5];
 
 	retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, rsp, 5);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (rsp[1] & 0x02) {
+	if (rsp[1] & 0x02)
 		sd_card->sd_lock_status |= SD_LOCKED;
-	} else {
+	else
 		sd_card->sd_lock_status &= ~SD_LOCKED;
-	}
 
 	RTSX_DEBUGP("sd_card->sd_lock_status = 0x%x\n", sd_card->sd_lock_status);
 
-	if (rsp[1] & 0x01) {
+	if (rsp[1] & 0x01)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -779,13 +757,11 @@
 	for (i = 0; i < polling_cnt; i++) {
 		retval = sd_send_cmd_get_rsp(chip, SEND_STATUS,
 					     sd_card->sd_addr, SD_RSP_TYPE_R1, rsp, 5);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
-		if (((rsp[3] & 0x1E) == state) && ((rsp[3] & 0x01) == data_ready)) {
+		if (((rsp[3] & 0x1E) == state) && ((rsp[3] & 0x01) == data_ready))
 			return STATUS_SUCCESS;
-		}
 	}
 
 	TRACE_RET(chip, STATUS_FAIL);
@@ -798,18 +774,16 @@
 	if (voltage == SD_IO_3V3) {
 		if (chip->asic_code) {
 			retval = rtsx_write_phy_register(chip, 0x08, 0x4FC0 | chip->phy_voltage);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		} else {
 			RTSX_WRITE_REG(chip, SD_PAD_CTL, SD_IO_USING_1V8, 0);
 		}
 	} else if (voltage == SD_IO_1V8) {
 		if (chip->asic_code) {
 			retval = rtsx_write_phy_register(chip, 0x08, 0x4C40 | chip->phy_voltage);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		} else {
 			RTSX_WRITE_REG(chip, SD_PAD_CTL, SD_IO_USING_1V8, SD_IO_USING_1V8);
 		}
@@ -828,9 +802,8 @@
 	RTSX_WRITE_REG(chip, SD_BUS_STAT, SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, SD_CLK_TOGGLE_EN);
 
 	retval = sd_send_cmd_get_rsp(chip, VOLTAGE_SWITCH, 0, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	udelay(chip->sd_voltage_switch_delay);
 
@@ -842,9 +815,9 @@
 
 	RTSX_WRITE_REG(chip, SD_BUS_STAT, 0xFF, SD_CLK_FORCE_STOP);
 	retval = sd_change_bank_voltage(chip, SD_IO_1V8);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	wait_timeout(50);
 
 	RTSX_WRITE_REG(chip, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN);
@@ -893,9 +866,8 @@
 	if (tune_dir == TUNE_RX) {
 		SD_VP_CTL = SD_VPRX_CTL;
 		SD_DCMPS_CTL = SD_DCMPS_RX_CTL;
-		if (CHK_SD_DDR50(sd_card)) {
+		if (CHK_SD_DDR50(sd_card))
 			ddr_rx = 1;
-		}
 	} else {
 		SD_VP_CTL = SD_VPTX_CTL;
 		SD_DCMPS_CTL = SD_DCMPS_TX_CTL;
@@ -932,23 +904,22 @@
 		rtsx_add_cmd(chip, WRITE_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE, DCMPS_CHANGE);
 		rtsx_add_cmd(chip, CHECK_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE_DONE, DCMPS_CHANGE_DONE);
 		retval = rtsx_send_cmd(chip, SD_CARD, 100);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, Fail);
-		}
 
 		val = *rtsx_get_cmd_data(chip);
-		if (val & DCMPS_ERROR) {
+		if (val & DCMPS_ERROR)
 			TRACE_GOTO(chip, Fail);
-		}
-		if ((val & DCMPS_CURRENT_PHASE) != sample_point) {
+
+		if ((val & DCMPS_CURRENT_PHASE) != sample_point)
 			TRACE_GOTO(chip, Fail);
-		}
+
 		RTSX_WRITE_REG(chip, SD_DCMPS_CTL, DCMPS_CHANGE, 0);
-		if (ddr_rx) {
+		if (ddr_rx)
 			RTSX_WRITE_REG(chip, SD_VP_CTL, PHASE_CHANGE, 0);
-		} else {
+		else
 			RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0);
-		}
+
 		udelay(50);
 	}
 
@@ -978,9 +949,8 @@
 	u8 cmd[5], buf[8];
 
 	retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	cmd[0] = 0x40 | SEND_SCR;
 	cmd[1] = 0;
@@ -996,9 +966,8 @@
 
 	memcpy(sd_card->raw_scr, buf, 8);
 
-	if ((buf[0] & 0x0F) == 0) {
+	if ((buf[0] & 0x0F) == 0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1172,13 +1141,12 @@
 		 */
 		u16 cc = ((u16)buf[0] << 8) | buf[1];
 		RTSX_DEBUGP("Maximum current consumption: %dmA\n", cc);
-		if ((cc == 0) || (cc > 800)) {
+		if ((cc == 0) || (cc > 800))
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = sd_query_switch_result(chip, func_group, func_to_switch, buf, 64);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if ((cc > 400) || (func_to_switch > CURRENT_LIMIT_400)) {
 			RTSX_WRITE_REG(chip, OCPPARA2, SD_OCP_THD_MASK, chip->sd_800mA_ocp_thd);
@@ -1192,13 +1160,12 @@
 static u8 downgrade_switch_mode(u8 func_group, u8 func_to_switch)
 {
 	if (func_group == SD_FUNC_GROUP_1) {
-		if (func_to_switch > HS_SUPPORT) {
+		if (func_to_switch > HS_SUPPORT)
 			func_to_switch--;
-		}
+
 	} else if (func_group == SD_FUNC_GROUP_4) {
-		if (func_to_switch > CURRENT_LIMIT_200) {
+		if (func_to_switch > CURRENT_LIMIT_200)
 			func_to_switch--;
-		}
 	}
 
 	return func_to_switch;
@@ -1241,9 +1208,8 @@
 		wait_timeout(20);
 	}
 
-	if (!switch_good) {
+	if (!switch_good)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1258,9 +1224,8 @@
 	/* Get supported functions */
 	retval = sd_check_switch_mode(chip, SD_CHECK_MODE,
 			NO_ARGUMENT, NO_ARGUMENT, bus_width);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	sd_card->func_group1_mask &= ~(sd_card->sd_switch_fail);
 
@@ -1289,9 +1254,9 @@
 			break;
 
 		case HS_SUPPORT:
-			if (sd_card->func_group1_mask & HS_SUPPORT_MASK) {
+			if (sd_card->func_group1_mask & HS_SUPPORT_MASK)
 				func_to_switch = HS_SUPPORT;
-			}
+
 			break;
 
 		default:
@@ -1299,9 +1264,9 @@
 		}
 
 
-		if (func_to_switch) {
+		if (func_to_switch)
 			break;
-		}
+
 	}
 	RTSX_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x", func_to_switch);
 
@@ -1330,23 +1295,21 @@
 			TRACE_RET(chip, STATUS_FAIL);
 		}
 
-		if (func_to_switch == SDR104_SUPPORT) {
+		if (func_to_switch == SDR104_SUPPORT)
 			SET_SD_SDR104(sd_card);
-		} else if (func_to_switch == DDR50_SUPPORT) {
+		else if (func_to_switch == DDR50_SUPPORT)
 			SET_SD_DDR50(sd_card);
-		} else if (func_to_switch == SDR50_SUPPORT) {
+		else if (func_to_switch == SDR50_SUPPORT)
 			SET_SD_SDR50(sd_card);
-		} else {
+		else
 			SET_SD_HS(sd_card);
-		}
 	}
 
 	if (CHK_SD_DDR50(sd_card)) {
 		RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, 0x06, 0x04);
 		retval = sd_set_sample_push_timing(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	if (!func_to_switch || (func_to_switch == HS_SUPPORT)) {
@@ -1362,36 +1325,35 @@
 	for (i = 0; i < 4; i++) {
 		switch ((u8)(chip->sd_current_prior >> (i*8))) {
 		case CURRENT_LIMIT_800:
-			if (sd_card->func_group4_mask & CURRENT_LIMIT_800_MASK) {
+			if (sd_card->func_group4_mask & CURRENT_LIMIT_800_MASK)
 				func_to_switch = CURRENT_LIMIT_800;
-			}
+
 			break;
 
 		case CURRENT_LIMIT_600:
-			if (sd_card->func_group4_mask & CURRENT_LIMIT_600_MASK) {
+			if (sd_card->func_group4_mask & CURRENT_LIMIT_600_MASK)
 				func_to_switch = CURRENT_LIMIT_600;
-			}
+
 			break;
 
 		case CURRENT_LIMIT_400:
-			if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK) {
+			if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK)
 				func_to_switch = CURRENT_LIMIT_400;
-			}
+
 			break;
 
 		case CURRENT_LIMIT_200:
-			if (sd_card->func_group4_mask & CURRENT_LIMIT_200_MASK) {
+			if (sd_card->func_group4_mask & CURRENT_LIMIT_200_MASK)
 				func_to_switch = CURRENT_LIMIT_200;
-			}
+
 			break;
 
 		default:
 			continue;
 		}
 
-		if (func_to_switch != 0xFF) {
+		if (func_to_switch != 0xFF)
 			break;
-		}
 	}
 
 	RTSX_DEBUGP("SD_FUNC_GROUP_4: func_to_switch = 0x%02x", func_to_switch);
@@ -1399,16 +1361,14 @@
 	if (func_to_switch <= CURRENT_LIMIT_800) {
 		retval = sd_check_switch(chip, SD_FUNC_GROUP_4, func_to_switch, bus_width);
 		if (retval != STATUS_SUCCESS) {
-			if (sd_check_err_code(chip, SD_NO_CARD)) {
+			if (sd_check_err_code(chip, SD_NO_CARD))
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 		RTSX_DEBUGP("Switch current limit finished! (%d)\n", retval);
 	}
 
-	if (CHK_SD_DDR50(sd_card)) {
+	if (CHK_SD_DDR50(sd_card))
 		RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, 0x06, 0);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1438,9 +1398,8 @@
 	u8 cmd[5];
 
 	retval = sd_change_phase(chip, sample_point, TUNE_RX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	cmd[0] = 0x40 | SEND_TUNING_PATTERN;
 	cmd[1] = 0;
@@ -1467,16 +1426,14 @@
 	u8 cmd[5];
 
 	retval = sd_change_phase(chip, sample_point, TUNE_RX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("sd ddr tuning rx\n");
 
 	retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	cmd[0] = 0x40 | SD_STATUS;
 	cmd[1] = 0;
@@ -1502,18 +1459,16 @@
 	int retval;
 	u8 cmd[5], bus_width;
 
-	if (CHK_MMC_8BIT(sd_card)) {
+	if (CHK_MMC_8BIT(sd_card))
 		bus_width = SD_BUS_WIDTH_8;
-	} else if (CHK_MMC_4BIT(sd_card)) {
+	else if (CHK_MMC_4BIT(sd_card))
 		bus_width = SD_BUS_WIDTH_4;
-	} else {
+	else
 		bus_width = SD_BUS_WIDTH_1;
-	}
 
 	retval = sd_change_phase(chip, sample_point, TUNE_RX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("mmc ddr tuning rx\n");
 
@@ -1541,9 +1496,8 @@
 	int retval;
 
 	retval = sd_change_phase(chip, sample_point, TUNE_TX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, SD_RSP_80CLK_TIMEOUT_EN);
 
@@ -1568,26 +1522,23 @@
 	u8 cmd[5], bus_width;
 
 	retval = sd_change_phase(chip, sample_point, TUNE_TX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHK_SD(sd_card)) {
 		bus_width = SD_BUS_WIDTH_4;
 	} else {
-		if (CHK_MMC_8BIT(sd_card)) {
+		if (CHK_MMC_8BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_8;
-		} else if (CHK_MMC_4BIT(sd_card)) {
+		else if (CHK_MMC_4BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_4;
-		} else {
+		else
 			bus_width = SD_BUS_WIDTH_1;
-		}
 	}
 
 	retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, SD_RSP_80CLK_TIMEOUT_EN);
 
@@ -1621,11 +1572,10 @@
 	u8 final_phase = 0xFF;
 
 	if (phase_map == 0xFFFFFFFF) {
-		if (tune_dir == TUNE_RX) {
+		if (tune_dir == TUNE_RX)
 			final_phase = (u8)chip->sd_default_rx_phase;
-		} else {
+		else
 			final_phase = (u8)chip->sd_default_tx_phase;
-		}
 
 		goto Search_Finish;
 	}
@@ -1666,9 +1616,9 @@
 		path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1;
 		path[0].len += path[cont_path_cnt - 1].len;
 		path[0].mid = path[0].start + path[0].len / 2;
-		if (path[0].mid < 0) {
+		if (path[0].mid < 0)
 			path[0].mid += MAX_PHASE + 1;
-		}
+
 		cont_path_cnt--;
 	}
 
@@ -1696,11 +1646,10 @@
 				int temp_final_phase =
 					path[final_path_idx].end - (max_len - (6 + temp_mid));
 
-				if (temp_final_phase < 0) {
+				if (temp_final_phase < 0)
 					final_phase = (u8)(temp_final_phase + MAX_PHASE + 1);
-				} else {
+				else
 					final_phase = (u8)temp_final_phase;
-				}
 			}
 		} else if (CHK_SD_SDR50(sd_card)) {
 			if (max_len > 12) {
@@ -1708,11 +1657,10 @@
 				int temp_final_phase =
 					path[final_path_idx].end - (max_len - (3 + temp_mid));
 
-				if (temp_final_phase < 0) {
+				if (temp_final_phase < 0)
 					final_phase = (u8)(temp_final_phase + MAX_PHASE + 1);
-				} else {
+				else
 					final_phase = (u8)temp_final_phase;
-				}
 			}
 		}
 	}
@@ -1732,17 +1680,16 @@
 	int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point);
 
 	if (CHK_SD(sd_card)) {
-		if (CHK_SD_DDR50(sd_card)) {
+		if (CHK_SD_DDR50(sd_card))
 			tuning_cmd = sd_ddr_tuning_rx_cmd;
-		} else {
+		else
 			tuning_cmd = sd_sdr_tuning_rx_cmd;
-		}
+
 	} else {
-		if (CHK_MMC_DDR52(sd_card)) {
+		if (CHK_MMC_DDR52(sd_card))
 			tuning_cmd = mmc_ddr_tunning_rx_cmd;
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	for (i = 0; i < 3; i++) {
@@ -1754,27 +1701,24 @@
 			}
 
 			retval = tuning_cmd(chip, (u8)j);
-			if (retval == STATUS_SUCCESS) {
+			if (retval == STATUS_SUCCESS)
 				raw_phase_map[i] |= 1 << j;
-			}
 		}
 	}
 
 	phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2];
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < 3; i++)
 		RTSX_DEBUGP("RX raw_phase_map[%d] = 0x%08x\n", i, raw_phase_map[i]);
-	}
+
 	RTSX_DEBUGP("RX phase_map = 0x%08x\n", phase_map);
 
 	final_phase = sd_search_final_phase(chip, phase_map, TUNE_RX);
-	if (final_phase == 0xFF) {
+	if (final_phase == 0xFF)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_change_phase(chip, final_phase, TUNE_RX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1799,15 +1743,13 @@
 		}
 
 		retval = sd_change_phase(chip, (u8)i, TUNE_TX);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			continue;
-		}
 
 		retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
 				SD_RSP_TYPE_R1, NULL, 0);
-		if ((retval == STATUS_SUCCESS) || !sd_check_err_code(chip, SD_RSP_TIMEOUT)) {
+		if ((retval == STATUS_SUCCESS) || !sd_check_err_code(chip, SD_RSP_TIMEOUT))
 			phase_map |= 1 << i;
-		}
 	}
 
 	RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
@@ -1815,14 +1757,12 @@
 	RTSX_DEBUGP("DDR TX pre tune phase_map = 0x%08x\n", phase_map);
 
 	final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX);
-	if (final_phase == 0xFF) {
+	if (final_phase == 0xFF)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_change_phase(chip, final_phase, TUNE_TX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("DDR TX pre tune phase: %d\n", (int)final_phase);
 
@@ -1839,17 +1779,16 @@
 	int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point);
 
 	if (CHK_SD(sd_card)) {
-		if (CHK_SD_DDR50(sd_card)) {
+		if (CHK_SD_DDR50(sd_card))
 			tuning_cmd = sd_ddr_tuning_tx_cmd;
-		} else {
+		else
 			tuning_cmd = sd_sdr_tuning_tx_cmd;
-		}
+
 	} else {
-		if (CHK_MMC_DDR52(sd_card)) {
+		if (CHK_MMC_DDR52(sd_card))
 			tuning_cmd = sd_ddr_tuning_tx_cmd;
-		} else {
+		else
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	for (i = 0; i < 3; i++) {
@@ -1863,27 +1802,24 @@
 			}
 
 			retval = tuning_cmd(chip, (u8)j);
-			if (retval == STATUS_SUCCESS) {
+			if (retval == STATUS_SUCCESS)
 				raw_phase_map[i] |= 1 << j;
-			}
 		}
 	}
 
 	phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2];
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < 3; i++)
 		RTSX_DEBUGP("TX raw_phase_map[%d] = 0x%08x\n", i, raw_phase_map[i]);
-	}
+
 	RTSX_DEBUGP("TX phase_map = 0x%08x\n", phase_map);
 
 	final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX);
-	if (final_phase == 0xFF) {
+	if (final_phase == 0xFF)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_change_phase(chip, final_phase, TUNE_TX);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1893,14 +1829,12 @@
 	int retval;
 
 	retval = sd_tuning_tx(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_tuning_rx(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -1911,26 +1845,22 @@
 
 	if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
 		retval = sd_ddr_pre_tuning_tx(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		retval = sd_change_phase(chip, (u8)chip->sd_ddr_tx_phase, TUNE_TX);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	retval = sd_tuning_rx(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
 		retval = sd_tuning_tx(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1942,26 +1872,22 @@
 
 	if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
 		retval = sd_ddr_pre_tuning_tx(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		retval = sd_change_phase(chip, (u8)chip->mmc_ddr_tx_phase, TUNE_TX);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	retval = sd_tuning_rx(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
 		retval = sd_tuning_tx(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -1974,9 +1900,8 @@
 	int re_tuning = 0;
 
 	retval = select_card(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHECK_PID(chip, 0x5209) &&
 			(CHK_SD30_SPEED(sd_card) || CHK_MMC_DDR52(sd_card))) {
@@ -1987,26 +1912,22 @@
 	}
 
 	retval = switch_clock(chip, sd_card->sd_clock);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (re_tuning) {
 		if (CHK_SD(sd_card)) {
-			if (CHK_SD_DDR50(sd_card)) {
+			if (CHK_SD_DDR50(sd_card))
 				retval = sd_ddr_tuning(chip);
-			} else {
+			else
 				retval = sd_sdr_tuning(chip);
-			}
 		} else {
-			if (CHK_MMC_DDR52(sd_card)) {
+			if (CHK_MMC_DDR52(sd_card))
 				retval = mmc_ddr_tuning(chip);
-			}
 		}
 
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	return STATUS_SUCCESS;
@@ -2017,11 +1938,10 @@
 	struct sd_info *sd_card = &(chip->sd_card);
 	int retval;
 
-	if (chip->asic_code) {
+	if (chip->asic_code)
 		sd_card->sd_clock = 29;
-	} else {
+	else
 		sd_card->sd_clock = CLK_30;
-	}
 
 	sd_card->sd_type = 0;
 	sd_card->seq_mode = 0;
@@ -2037,9 +1957,8 @@
 	chip->sd_io = 0;
 
 	retval = sd_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
-	}
 
 	if (CHECK_PID(chip, 0x5209)) {
 		RTSX_WRITE_REG(chip, REG_SD_CFG1, 0xFF,
@@ -2053,9 +1972,8 @@
 	RTSX_WRITE_REG(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR);
 
 	retval = select_card(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2122,9 +2040,8 @@
 	}
 
 	retval = rtsx_send_cmd(chip, SD_CARD, 100);
-	if (retval < 0) {
+	if (retval < 0)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2133,42 +2050,37 @@
 {
 	int retval;
 
-	if (CHECK_PID(chip, 0x5209)) {
+	if (CHECK_PID(chip, 0x5209))
 		RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF);
-	}
 
 	retval = sd_power_off_card3v3(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if (!chip->ft2_fast_mode) {
+	if (!chip->ft2_fast_mode)
 		wait_timeout(250);
-	}
 
 	retval = enable_card_clock(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (chip->asic_code) {
 		retval = sd_pull_ctl_enable(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0);
 	}
 
 	if (chip->ft2_fast_mode) {
-		if (CHECK_PID(chip, 0x5209)) {
+		if (CHECK_PID(chip, 0x5209))
 			RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON);
-		}
+
 	} else {
 		retval = card_power_on(chip, SD_CARD);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		wait_timeout(260);
 
 #ifdef SUPPORT_OCP
@@ -2214,13 +2126,12 @@
 	if (CHK_SD(sd_card)) {
 		bus_width = SD_BUS_WIDTH_4;
 	} else {
-		if (CHK_MMC_8BIT(sd_card)) {
+		if (CHK_MMC_8BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_8;
-		} else if (CHK_MMC_4BIT(sd_card)) {
+		else if (CHK_MMC_4BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_4;
-		} else {
+		else
 			bus_width = SD_BUS_WIDTH_1;
-		}
 	}
 
 	retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd,
@@ -2243,9 +2154,8 @@
 
 	retval = sd_send_cmd_get_rsp(chip, APP_CMD,
 			sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	cmd[0] = 0x40 | SD_STATUS;
 	cmd[1] = 0;
@@ -2273,9 +2183,8 @@
 
 	/* Check SD Machanical Write-Protect Switch */
 	val = rtsx_readl(chip, RTSX_BIPR);
-	if (val & SD_WRITE_PROTECT) {
+	if (val & SD_WRITE_PROTECT)
 		chip->card_wp |= SD_CARD;
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -2307,14 +2216,12 @@
 #endif
 
 	retval = sd_prepare_reset(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_dummy_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip) && try_sdio) {
 		int rty_cnt = 0;
@@ -2348,9 +2255,8 @@
 	/* Start Initialization Process of SD Card */
 RTY_SD_RST:
 	retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 	       TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	wait_timeout(20);
 
@@ -2377,9 +2283,8 @@
 		voltage = SUPPORT_VOLTAGE;
 
 		retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 		       TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		wait_timeout(20);
 	}
@@ -2393,42 +2298,38 @@
 			}
 
 			j++;
-			if (j < 3) {
+			if (j < 3)
 				goto RTY_SD_RST;
-			} else {
+			else
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 
 		retval = sd_send_cmd_get_rsp(chip, SD_APP_OP_COND, voltage, SD_RSP_TYPE_R3, rsp, 5);
 		if (retval != STATUS_SUCCESS) {
 			k++;
-			if (k < 3) {
+			if (k < 3)
 				goto RTY_SD_RST;
-			} else {
+			else
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 
 		i++;
 		wait_timeout(20);
 	} while (!(rsp[1] & 0x80) && (i < 255));
 
-	if (i == 255) {
+	if (i == 255)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (hi_cap_flow) {
-		if (rsp[1] & 0x40) {
+		if (rsp[1] & 0x40)
 			SET_SD_HCXC(sd_card);
-		} else {
+		else
 			CLR_SD_HCXC(sd_card);
-		}
-		if (CHECK_PID(chip, 0x5209) && CHK_SD_HCXC(sd_card) && !sd20_mode) {
+
+		if (CHECK_PID(chip, 0x5209) && CHK_SD_HCXC(sd_card) && !sd20_mode)
 			support_1v8 = (rsp[1] & 0x01) ? 1 : 0;
-		} else {
+		else
 			support_1v8 = 0;
-		}
 	} else {
 		CLR_SD_HCXC(sd_card);
 		support_1v8 = 0;
@@ -2437,46 +2338,39 @@
 
 	if (support_1v8) {
 		retval = sd_voltage_switch(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 	retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	for (i = 0; i < 3; i++) {
 		retval = sd_send_cmd_get_rsp(chip, SEND_RELATIVE_ADDR, 0, SD_RSP_TYPE_R6, rsp, 5);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		sd_card->sd_addr = (u32)rsp[1] << 24;
 		sd_card->sd_addr += (u32)rsp[2] << 16;
 
-		if (sd_card->sd_addr) {
+		if (sd_card->sd_addr)
 			break;
-		}
 	}
 
 	retval = sd_check_csd(chip, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_select_card(chip, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 SD_UNLOCK_ENTRY:
 	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (sd_card->sd_lock_status & SD_LOCKED) {
 		sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST);
@@ -2487,23 +2381,21 @@
 #endif
 
 	retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	retval = sd_send_cmd_get_rsp(chip, SET_CLR_CARD_DETECT, 0, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (support_1v8) {
 		retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		switch_bus_width = SD_BUS_WIDTH_4;
 	} else {
@@ -2511,14 +2403,12 @@
 	}
 
 	retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (!(sd_card->raw_csd[4] & 0x40))
 		sd_dont_switch = 1;
@@ -2537,9 +2427,9 @@
 		if (retval == STATUS_SUCCESS) {
 			retval = sd_switch_function(chip, switch_bus_width);
 			if (retval != STATUS_SUCCESS) {
-				if (CHECK_PID(chip, 0x5209)) {
+				if (CHECK_PID(chip, 0x5209))
 					sd_change_bank_voltage(chip, SD_IO_3V3);
-				}
+
 				sd_init_power(chip);
 				sd_dont_switch = 1;
 				try_sdio = 0;
@@ -2548,9 +2438,9 @@
 			}
 		} else {
 			if (support_1v8) {
-				if (CHECK_PID(chip, 0x5209)) {
+				if (CHECK_PID(chip, 0x5209))
 					sd_change_bank_voltage(chip, SD_IO_3V3);
-				}
+
 				sd_init_power(chip);
 				sd_dont_switch = 1;
 				try_sdio = 0;
@@ -2562,13 +2452,12 @@
 
 	if (!support_1v8) {
 		retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
+
 		retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	}
 
 #ifdef SUPPORT_SD_LOCK
@@ -2581,24 +2470,22 @@
 		RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_1v8);
 
 		retval = sd_set_init_para(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
-		if (CHK_SD_DDR50(sd_card)) {
+		if (CHK_SD_DDR50(sd_card))
 			retval = sd_ddr_tuning(chip);
-		} else {
+		else
 			retval = sd_sdr_tuning(chip);
-		}
 
 		if (retval != STATUS_SUCCESS) {
 			if (sd20_mode) {
 				TRACE_RET(chip, STATUS_FAIL);
 			} else {
 				retval = sd_init_power(chip);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 				try_sdio = 0;
 				sd20_mode = 1;
 				goto Switch_Fail;
@@ -2609,9 +2496,8 @@
 
 		if (CHK_SD_DDR50(sd_card)) {
 			retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				read_lba0 = 0;
-			}
 		}
 
 		if (read_lba0) {
@@ -2621,9 +2507,9 @@
 					TRACE_RET(chip, STATUS_FAIL);
 				} else {
 					retval = sd_init_power(chip);
-					if (retval != STATUS_SUCCESS) {
+					if (retval != STATUS_SUCCESS)
 						TRACE_RET(chip, STATUS_FAIL);
-					}
+
 					try_sdio = 0;
 					sd20_mode = 1;
 					goto Switch_Fail;
@@ -2633,9 +2519,8 @@
 	}
 
 	retval = sd_check_wp_state(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
 
@@ -2659,9 +2544,8 @@
 	int len;
 
 	retval = sd_send_cmd_get_rsp(chip, BUSTEST_W, 0, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, SWITCH_FAIL);
-	}
 
 	if (width == MMC_8BIT_BUS) {
 		buf[0] = 0x55;
@@ -2690,9 +2574,8 @@
 			rtsx_read_register(chip, REG_SD_STAT1, &val1);
 			rtsx_read_register(chip, REG_SD_STAT2, &val2);
 			rtsx_clear_sd_error(chip);
-			if ((val1 & 0xE0) || val2) {
+			if ((val1 & 0xE0) || val2)
 				TRACE_RET(chip, SWITCH_ERR);
-			}
 		} else {
 			rtsx_clear_sd_error(chip);
 			rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0);
@@ -2712,11 +2595,10 @@
 
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, 0x40 | BUSTEST_R);
 
-	if (width == MMC_8BIT_BUS) {
+	if (width == MMC_8BIT_BUS)
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0x08);
-	} else {
+	else
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0x04);
-	}
 
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, 1);
 	rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, 0);
@@ -2729,9 +2611,8 @@
 	rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END);
 
 	rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2, 0, 0);
-	if (width == MMC_8BIT_BUS) {
+	if (width == MMC_8BIT_BUS)
 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 1, 0, 0);
-	}
 
 	retval = rtsx_send_cmd(chip, SD_CARD, 100);
 	if (retval < 0) {
@@ -2747,15 +2628,14 @@
 			u8 rsp[5];
 			u32 arg;
 
-			if (CHK_MMC_DDR52(sd_card)) {
+			if (CHK_MMC_DDR52(sd_card))
 				arg = 0x03B70600;
-			} else {
+			else
 				arg = 0x03B70200;
-			}
+
 			retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, SD_RSP_TYPE_R1b, rsp, 5);
-			if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) {
+			if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR))
 				return SWITCH_SUCCESS;
-			}
 		}
 	} else {
 		RTSX_DEBUGP("BUSTEST_R [4bits]: 0x%02x\n", ptr[0]);
@@ -2763,15 +2643,14 @@
 			u8 rsp[5];
 			u32 arg;
 
-			if (CHK_MMC_DDR52(sd_card)) {
+			if (CHK_MMC_DDR52(sd_card))
 				arg = 0x03B70500;
-			} else {
+			else
 				arg = 0x03B70100;
-			}
+
 			retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, SD_RSP_TYPE_R1b, rsp, 5);
-			if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) {
+			if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR))
 				return SWITCH_SUCCESS;
-			}
 		}
 	}
 
@@ -2845,11 +2724,10 @@
 			card_type_mask = 0x03;
 		}
 #else
-		if (chip->sd_ctl & SUPPORT_MMC_DDR_MODE) {
+		if (chip->sd_ctl & SUPPORT_MMC_DDR_MODE)
 			card_type_mask = 0x07;
-		} else {
+		else
 			card_type_mask = 0x03;
-		}
 #endif
 	} else {
 		card_type_mask = 0x03;
@@ -2859,11 +2737,10 @@
 		u8 rsp[5];
 
 		if (card_type & 0x04) {
-			if (switch_ddr) {
+			if (switch_ddr)
 				SET_MMC_DDR52(sd_card);
-			} else {
+			else
 				SET_MMC_52M(sd_card);
-			}
 		} else if (card_type & 0x02) {
 			SET_MMC_52M(sd_card);
 		} else {
@@ -2872,16 +2749,14 @@
 
 		retval = sd_send_cmd_get_rsp(chip, SWITCH,
 				0x03B90100, SD_RSP_TYPE_R1b, rsp, 5);
-		if ((retval != STATUS_SUCCESS) || (rsp[4] & MMC_SWITCH_ERR)) {
+		if ((retval != STATUS_SUCCESS) || (rsp[4] & MMC_SWITCH_ERR))
 			CLR_MMC_HS(sd_card);
-		}
 	}
 
 	sd_choose_proper_clock(chip);
 	retval = switch_clock(chip, sd_card->sd_clock);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	/* Test Bus Procedure */
 	retval = mmc_test_switch_bus(chip, MMC_8BIT_BUS);
@@ -2929,17 +2804,15 @@
 
 Switch_Fail:
 	retval = sd_prepare_reset(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, retval);
-	}
 
 	SET_MMC(sd_card);
 
 RTY_MMC_RST:
 	retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 	       TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	do {
 		if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) {
@@ -2973,56 +2846,47 @@
 		i++;
 	} while (!(rsp[1] & 0x80) && (i < 255));
 
-	if (i == 255) {
+	if (i == 255)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
-	if ((rsp[1] & 0x60) == 0x40) {
+	if ((rsp[1] & 0x60) == 0x40)
 		SET_MMC_SECTOR_MODE(sd_card);
-	} else {
+	else
 		CLR_MMC_SECTOR_MODE(sd_card);
-	}
 
 	retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	sd_card->sd_addr = 0x00100000;
 	retval = sd_send_cmd_get_rsp(chip, SET_RELATIVE_ADDR, sd_card->sd_addr, SD_RSP_TYPE_R6, rsp, 5);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_check_csd(chip, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	spec_ver = (sd_card->raw_csd[0] & 0x3C) >> 2;
 
 	retval = sd_select_card(chip, 1);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 MMC_UNLOCK_ENTRY:
 	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 #endif
 
 	retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	chip->card_bus_width[chip->card2lun[SD_CARD]] = 1;
 
@@ -3039,22 +2903,20 @@
 			}
 		}
 
-		if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0)) {
+		if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0))
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (switch_ddr && CHK_MMC_DDR52(sd_card)) {
 			retval = sd_set_init_para(chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 
 			retval = mmc_ddr_tuning(chip);
 			if (retval != STATUS_SUCCESS) {
 				retval = sd_init_power(chip);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 				switch_ddr = 0;
 				TRACE_GOTO(chip, Switch_Fail);
 			}
@@ -3064,9 +2926,9 @@
 				retval = sd_read_lba0(chip);
 				if (retval != STATUS_SUCCESS) {
 					retval = sd_init_power(chip);
-					if (retval != STATUS_SUCCESS) {
+					if (retval != STATUS_SUCCESS)
 						TRACE_RET(chip, STATUS_FAIL);
-					}
+
 					switch_ddr = 0;
 					TRACE_GOTO(chip, Switch_Fail);
 				}
@@ -3082,9 +2944,8 @@
 #endif
 
 	temp = rtsx_readl(chip, RTSX_BIPR);
-	if (temp & SD_WRITE_PROTECT) {
+	if (temp & SD_WRITE_PROTECT)
 		chip->card_wp |= SD_CARD;
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -3100,36 +2961,31 @@
 	chip->capacity[chip->card2lun[SD_CARD]] = 0;
 
 	retval = enable_card_clock(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (chip->ignore_sd && CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) {
 		if (chip->asic_code) {
 			retval = sd_pull_ctl_enable(chip);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		} else {
 			retval = rtsx_write_register(chip, FPGA_PULL_CTL,
 						     FPGA_SD_PULL_CTL_BIT | 0x20, 0);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 		retval = card_share_mode(chip, SD_CARD);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		chip->sd_io = 1;
 		TRACE_RET(chip, STATUS_FAIL);
 	}
 
 	retval = sd_init_power(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (chip->sd_ctl & RESET_MMC_FIRST) {
 		retval = reset_mmc(chip);
@@ -3168,18 +3024,17 @@
 	}
 
 	retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_L, 0xFF, 0);
 	RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_H, 0xFF, 2);
 
 	chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity;
 
 	retval = sd_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("sd_card->sd_type = 0x%x\n", sd_card->sd_type);
 
@@ -3205,33 +3060,29 @@
 	chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity = 0;
 
 	retval = enable_card_clock(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_init_power(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = reset_mmc(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
+
 	RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_L, 0xFF, 0);
 	RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_H, 0xFF, 2);
 
 	chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity;
 
 	retval = sd_set_init_para(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_DEBUGP("In reset_mmc_only, sd_card->sd_type = 0x%x\n", sd_card->sd_type);
 
@@ -3255,9 +3106,8 @@
 
 		retval = sd_send_cmd_get_rsp(chip, SEND_STATUS,
 				sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (sd_card->sd_data_buf_ready) {
 			return sd_send_cmd_get_rsp(chip, SEND_STATUS,
@@ -3277,19 +3127,18 @@
 
 	if (sd_card->seq_mode) {
 		retval = sd_switch_clock(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			return;
-		}
 
 		retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
 				SD_RSP_TYPE_R1b, NULL, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			sd_set_err_code(chip, SD_STS_ERR);
-		}
+
 		retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			sd_set_err_code(chip, SD_STS_ERR);
-		}
+
 		sd_card->seq_mode = 0;
 
 		rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH);
@@ -3302,9 +3151,8 @@
 	int retval;
 
 	if (chip->asic_code) {
-		if (sd_card->sd_clock > 30) {
+		if (sd_card->sd_clock > 30)
 			sd_card->sd_clock -= 20;
-		}
 	} else {
 		switch (sd_card->sd_clock) {
 		case CLK_200:
@@ -3337,9 +3185,8 @@
 	}
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -3377,11 +3224,10 @@
 		}
 	}
 
-	if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card)) {
+	if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card))
 		data_addr = start_sector << 9;
-	} else {
+	else
 		data_addr = start_sector;
-	}
 
 	sd_clr_err_code(chip);
 
@@ -3436,21 +3282,19 @@
 
 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
 
-	if (CHK_MMC_8BIT(sd_card)) {
+	if (CHK_MMC_8BIT(sd_card))
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8);
-	} else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card)) {
+	else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card))
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-	} else {
+	else
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_1);
-	}
 
 	if (sd_card->seq_mode) {
 		cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END |
 				SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
 		if (CHECK_PID(chip, 0x5209)) {
-			if (!CHK_SD30_SPEED(sd_card)) {
+			if (!CHK_SD30_SPEED(sd_card))
 				cfg2 |= SD_NO_CHECK_WAIT_CRC_TO;
-			}
 		}
 		rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2);
 
@@ -3480,9 +3324,8 @@
 			cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END |
 					SD_CHECK_CRC7 | SD_RSP_LEN_6;
 			if (CHECK_PID(chip, 0x5209)) {
-				if (!CHK_SD30_SPEED(sd_card)) {
+				if (!CHK_SD30_SPEED(sd_card))
 					cfg2 |= SD_NO_CHECK_WAIT_CRC_TO;
-				}
 			}
 			rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2);
 
@@ -3523,9 +3366,8 @@
 			cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END |
 					SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
 			if (CHECK_PID(chip, 0x5209)) {
-				if (!CHK_SD30_SPEED(sd_card)) {
+				if (!CHK_SD30_SPEED(sd_card))
 					cfg2 |= SD_NO_CHECK_WAIT_CRC_TO;
-				}
 			}
 			rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2);
 
@@ -3550,11 +3392,10 @@
 
 		sd_card->seq_mode = 0;
 
-		if (retval == -ETIMEDOUT) {
+		if (retval == -ETIMEDOUT)
 			err = STATUS_TIMEDOUT;
-		} else {
+		else
 			err = STATUS_FAIL;
-		}
 
 		rtsx_read_register(chip, REG_SD_STAT1, &stat);
 		rtsx_clear_sd_error(chip);
@@ -3640,9 +3481,8 @@
 
 	RTSX_DEBUGP("EXT SD/MMC CMD %d\n", cmd_idx);
 
-	if (rsp_type == SD_RSP_TYPE_R1b) {
+	if (rsp_type == SD_RSP_TYPE_R1b)
 		timeout = 3000;
-	}
 
 RTY_SEND_CMD:
 
@@ -3662,14 +3502,14 @@
 	rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END);
 
 	if (rsp_type == SD_RSP_TYPE_R2) {
-		for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) {
+		for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++)
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
-		}
+
 		stat_idx = 17;
 	} else if (rsp_type != SD_RSP_TYPE_R0) {
-		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) {
+		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++)
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
-		}
+
 		stat_idx = 6;
 	}
 	rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0, 0);
@@ -3683,9 +3523,8 @@
 
 			if (rsp_type & SD_WAIT_BUSY_END) {
 				retval = sd_check_data0_status(chip);
-				if (retval != STATUS_SUCCESS) {
+				if (retval != STATUS_SUCCESS)
 					TRACE_RET(chip, retval);
-				}
 			} else {
 				sd_set_err_code(chip, SD_TO_ERR);
 			}
@@ -3693,9 +3532,8 @@
 		TRACE_RET(chip, STATUS_FAIL);
 	}
 
-	if (rsp_type == SD_RSP_TYPE_R0) {
+	if (rsp_type == SD_RSP_TYPE_R0)
 		return STATUS_SUCCESS;
-	}
 
 	ptr = rtsx_get_cmd_data(chip) + 1;
 
@@ -3724,9 +3562,8 @@
 	if ((cmd_idx == SELECT_CARD) || (cmd_idx == APP_CMD) ||
 			(cmd_idx == SEND_STATUS) || (cmd_idx == STOP_TRANSMISSION)) {
 		if ((cmd_idx != STOP_TRANSMISSION) && (special_check == 0)) {
-			if (ptr[1] & 0x80) {
+			if (ptr[1] & 0x80)
 				TRACE_RET(chip, STATUS_FAIL);
-			}
 		}
 #ifdef SUPPORT_SD_LOCK
 		if (ptr[1] & 0x7D)
@@ -3736,26 +3573,23 @@
 		{
 			TRACE_RET(chip, STATUS_FAIL);
 		}
-		if (ptr[2] & 0xF8) {
+		if (ptr[2] & 0xF8)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		if (cmd_idx == SELECT_CARD) {
 			if (rsp_type == SD_RSP_TYPE_R2) {
-				if ((ptr[3] & 0x1E) != 0x04) {
+				if ((ptr[3] & 0x1E) != 0x04)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
+
 			} else if (rsp_type == SD_RSP_TYPE_R0) {
-				if ((ptr[3] & 0x1E) != 0x03) {
+				if ((ptr[3] & 0x1E) != 0x03)
 					TRACE_RET(chip, STATUS_FAIL);
-				}
 			}
 		}
 	}
 
-	if (rsp && rsp_len) {
+	if (rsp && rsp_len)
 		memcpy(rsp, ptr, rsp_len);
-	}
 
 	return STATUS_SUCCESS;
 }
@@ -3765,29 +3599,27 @@
 	int retval, rsp_len;
 	u16 reg_addr;
 
-	if (rsp_type == SD_RSP_TYPE_R0) {
+	if (rsp_type == SD_RSP_TYPE_R0)
 		return STATUS_SUCCESS;
-	}
 
 	rtsx_init_cmd(chip);
 
 	if (rsp_type == SD_RSP_TYPE_R2) {
-		for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) {
+		for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++)
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0);
-		}
+
 		rsp_len = 17;
 	} else if (rsp_type != SD_RSP_TYPE_R0) {
-		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) {
+		for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++)
 			rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0);
-		}
+
 		rsp_len = 6;
 	}
 	rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0xFF, 0);
 
 	retval = rtsx_send_cmd(chip, SD_CARD, 100);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (rsp) {
 		int min_len = (rsp_len < len) ? rsp_len : len;
@@ -3858,9 +3690,8 @@
 	}
 
 	buf[5] = (1 == CHK_SD(sd_card)) ?  0x01 : 0x02;
-	if (chip->card_wp & SD_CARD) {
+	if (chip->card_wp & SD_CARD)
 		buf[5] |= 0x80;
-	}
 
 	buf[6] = (u8)(sd_card->sd_addr >> 16);
 	buf[7] = (u8)(sd_card->sd_addr >> 24);
@@ -3875,9 +3706,8 @@
 
 static inline int get_rsp_type(struct scsi_cmnd *srb, u8 *rsp_type, int *rsp_len)
 {
-	if (!rsp_type || !rsp_len) {
+	if (!rsp_type || !rsp_len)
 		return STATUS_FAIL;
-	}
 
 	switch (srb->cmnd[10]) {
 	case 0x03:
@@ -3927,9 +3757,8 @@
 	}
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 	if (sd_card->pre_cmd_err) {
 		sd_card->pre_cmd_err = 0;
@@ -3938,12 +3767,11 @@
 	}
 
 	cmd_idx = srb->cmnd[2] & 0x3F;
-	if (srb->cmnd[1] & 0x02) {
+	if (srb->cmnd[1] & 0x02)
 		standby = 1;
-	}
-	if (srb->cmnd[1] & 0x01) {
+
+	if (srb->cmnd[1] & 0x01)
 		acmd = 1;
-	}
 
 	arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) |
 		((u32)srb->cmnd[5] << 8) | srb->cmnd[6];
@@ -3956,64 +3784,56 @@
 	sd_card->last_rsp_type = rsp_type;
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
 		if (CHK_MMC_8BIT(sd_card)) {
 			retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
 			retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
 		}
 	}
 #else
 	retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 #endif
 
 	if (standby) {
 		retval = sd_select_card(chip, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-		}
 	}
 
 	if (acmd) {
 		retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-		}
 	}
 
 	retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
 			sd_card->rsp, rsp_len, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-	}
 
 	if (standby) {
 		retval = sd_select_card(chip, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-		}
 	}
 
 #ifdef SUPPORT_SD_LOCK
 	retval = sd_update_lock_status(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-	}
 #endif
 
 	scsi_set_resid(srb, 0);
@@ -4024,9 +3844,8 @@
 	set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
 	release_sd_card(chip);
 	do_reset_sd_card(chip);
-	if (!(chip->card_ready & SD_CARD)) {
+	if (!(chip->card_ready & SD_CARD))
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
-	}
 
 	TRACE_RET(chip, TRANSPORT_FAILED);
 }
@@ -4053,20 +3872,18 @@
 	}
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 	cmd_idx = srb->cmnd[2] & 0x3F;
-	if (srb->cmnd[1] & 0x04) {
+	if (srb->cmnd[1] & 0x04)
 		send_cmd12 = 1;
-	}
-	if (srb->cmnd[1] & 0x02) {
+
+	if (srb->cmnd[1] & 0x02)
 		standby = 1;
-	}
-	if (srb->cmnd[1] & 0x01) {
+
+	if (srb->cmnd[1] & 0x01)
 		acmd = 1;
-	}
 
 	data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9];
 
@@ -4078,19 +3895,17 @@
 	sd_card->last_rsp_type = rsp_type;
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
-		if (CHK_MMC_8BIT(sd_card)) {
+		if (CHK_MMC_8BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_8;
-		} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
+		else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card))
 			bus_width = SD_BUS_WIDTH_4;
-		} else {
+		else
 			bus_width = SD_BUS_WIDTH_1;
-		}
 	} else {
 		bus_width = SD_BUS_WIDTH_4;
 	}
@@ -4102,24 +3917,21 @@
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
 	if (standby) {
 		retval = sd_select_card(chip, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
 	if (acmd) {
 		retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
 	if (data_len <= 512) {
@@ -4138,9 +3950,8 @@
 		cmd[4] = srb->cmnd[6];
 
 		buf = kmalloc(data_len, GFP_KERNEL);
-		if (buf == NULL) {
+		if (buf == NULL)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt,
 				       blk_cnt, bus_width, buf, data_len, 2000);
@@ -4195,56 +4006,48 @@
 	}
 
 	retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-	}
 
 	if (standby) {
 		retval = sd_select_card(chip, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
 	if (send_cmd12) {
 		retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION,
 				0, SD_RSP_TYPE_R1b, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 
 		retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
+
 		retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-		}
 	}
 
-	if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) {
+	if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04))
 		cmd13_checkbit = 1;
-	}
 
 	for (i = 0; i < 3; i++) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
 			SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		}
 	}
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
-	}
 
 	scsi_set_resid(srb, 0);
 	return TRANSPORT_GOOD;
@@ -4252,14 +4055,13 @@
 SD_Execute_Read_Cmd_Failed:
 	sd_card->pre_cmd_err = 1;
 	set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
-	if (read_err) {
+	if (read_err)
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
-	}
+
 	release_sd_card(chip);
 	do_reset_sd_card(chip);
-	if (!(chip->card_ready & SD_CARD)) {
+	if (!(chip->card_ready & SD_CARD))
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
-	}
 
 	TRACE_RET(chip, TRANSPORT_FAILED);
 }
@@ -4291,20 +4093,18 @@
 	}
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 	cmd_idx = srb->cmnd[2] & 0x3F;
-	if (srb->cmnd[1] & 0x04) {
+	if (srb->cmnd[1] & 0x04)
 		send_cmd12 = 1;
-	}
-	if (srb->cmnd[1] & 0x02) {
+
+	if (srb->cmnd[1] & 0x02)
 		standby = 1;
-	}
-	if (srb->cmnd[1] & 0x01) {
+
+	if (srb->cmnd[1] & 0x01)
 		acmd = 1;
-	}
 
 	data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9];
 	arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) |
@@ -4325,75 +4125,66 @@
 	sd_card->last_rsp_type = rsp_type;
 
 	retval = sd_switch_clock(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 	if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
 		if (CHK_MMC_8BIT(sd_card)) {
 			retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
+
 		} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
 			retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-			if (retval != STATUS_SUCCESS) {
+			if (retval != STATUS_SUCCESS)
 				TRACE_RET(chip, TRANSPORT_FAILED);
-			}
 		}
 	}
 #else
 	retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, TRANSPORT_FAILED);
-	}
 #endif
 
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
 	if (standby) {
 		retval = sd_select_card(chip, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
 	if (acmd) {
 		retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
 	retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
 			sd_card->rsp, rsp_len, 0);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-	}
 
 	if (data_len <= 512) {
 		u16 i;
 		u8 *buf;
 
 		buf = kmalloc(data_len, GFP_KERNEL);
-		if (buf == NULL) {
+		if (buf == NULL)
 			TRACE_RET(chip, TRANSPORT_ERROR);
-		}
 
 		rtsx_stor_get_xfer_buf(buf, data_len, srb);
 
 #ifdef SUPPORT_SD_LOCK
-		if (cmd_idx == LOCK_UNLOCK) {
+		if (cmd_idx == LOCK_UNLOCK)
 			lock_cmd_type = buf[0] & 0x0F;
-		}
 #endif
 
 		if (data_len > 256) {
@@ -4485,11 +4276,11 @@
 		}
 
 		rtsx_init_cmd(chip);
-		if (CHECK_PID(chip, 0x5209)) {
+		if (CHECK_PID(chip, 0x5209))
 			rtsx_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS, SD_DAT0_STATUS);
-		} else {
+		else
 			rtsx_add_cmd(chip, CHECK_REG_CMD, 0xFD30, 0x02, 0x02);
-		}
+
 		rtsx_send_cmd(chip, SD_CARD, 250);
 
 		retval = sd_update_lock_status(chip);
@@ -4502,61 +4293,53 @@
 
 	if (standby) {
 		retval = sd_select_card(chip, 1);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
 	if (send_cmd12) {
 		retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION,
 				0, SD_RSP_TYPE_R1b, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
 	if (data_len < 512) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
 				SD_RSP_TYPE_R1, NULL, 0, 0);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 
 		retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
+
 		rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-		}
 	}
 
-	if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) {
+	if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04))
 		cmd13_checkbit = 1;
-	}
 
 	for (i = 0; i < 3; i++) {
 		retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
 			SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit);
-		if (retval == STATUS_SUCCESS) {
+		if (retval == STATUS_SUCCESS)
 			break;
-		}
 	}
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-	}
 
 #ifdef SUPPORT_SD_LOCK
 	if (cmd_idx == LOCK_UNLOCK) {
 		if (!lock_cmd_fail) {
 			RTSX_DEBUGP("lock_cmd_type = 0x%x\n", lock_cmd_type);
-			if (lock_cmd_type & SD_CLR_PWD) {
+			if (lock_cmd_type & SD_CLR_PWD)
 				sd_card->sd_lock_status &= ~SD_PWD_EXIST;
-			}
-			if (lock_cmd_type & SD_SET_PWD) {
+
+			if (lock_cmd_type & SD_SET_PWD)
 				sd_card->sd_lock_status |= SD_PWD_EXIST;
-			}
 		}
 
 		RTSX_DEBUGP("sd_lock_state = 0x%x, sd_card->sd_lock_status = 0x%x\n",
@@ -4593,14 +4376,13 @@
 SD_Execute_Write_Cmd_Failed:
 	sd_card->pre_cmd_err = 1;
 	set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
-	if (write_err) {
+	if (write_err)
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
-	}
+
 	release_sd_card(chip);
 	do_reset_sd_card(chip);
-	if (!(chip->card_ready & SD_CARD)) {
+	if (!(chip->card_ready & SD_CARD))
 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
-	}
 
 	TRACE_RET(chip, TRANSPORT_FAILED);
 }
@@ -4670,9 +4452,8 @@
 	switch (srb->cmnd[1] & 0x0F) {
 	case 0:
 #ifdef SUPPORT_SD_LOCK
-		if (0x64 == srb->cmnd[9]) {
+		if (0x64 == srb->cmnd[9])
 			sd_card->sd_lock_status |= SD_SDR_RST;
-		}
 #endif
 		retval = reset_sd_card(chip);
 		if (retval != STATUS_SUCCESS) {
@@ -4723,26 +4504,23 @@
 	int retval;
 
 	retval = disable_card_clock(chip, SD_CARD);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	RTSX_WRITE_REG(chip, CARD_OE, SD_OUTPUT_EN, 0);
 
 	if (!chip->ft2_fast_mode) {
 		retval = card_power_off(chip, SD_CARD);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
 		wait_timeout(50);
 	}
 
 	if (chip->asic_code) {
 		retval = sd_pull_ctl_disable(chip);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 	} else {
 		RTSX_WRITE_REG(chip, FPGA_PULL_CTL,
 			FPGA_SD_PULL_CTL_BIT | 0x20, FPGA_SD_PULL_CTL_BIT);
@@ -4774,19 +4552,16 @@
 	memset(sd_card->raw_scr, 0, 8);
 
 	retval = sd_power_off_card3v3(chip);
-	if (retval != STATUS_SUCCESS) {
+	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
-	}
 
 	if (CHECK_PID(chip, 0x5209)) {
 		retval = sd_change_bank_voltage(chip, SD_IO_3V3);
-		if (retval != STATUS_SUCCESS) {
+		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 
-		if (CHK_SD30_SPEED(sd_card)) {
+		if (CHK_SD30_SPEED(sd_card))
 			RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_3v3);
-		}
 
 		RTSX_WRITE_REG(chip, OCPPARA2, SD_OCP_THD_MASK, chip->sd_400mA_ocp_thd);
 	}
diff --git a/drivers/staging/rts_pstor/trace.h b/drivers/staging/rts_pstor/trace.h
index bc83b49..cf60a1b 100644
--- a/drivers/staging/rts_pstor/trace.h
+++ b/drivers/staging/rts_pstor/trace.h
@@ -83,33 +83,9 @@
 #endif
 
 #ifdef CONFIG_RTS_PSTOR_DEBUG
-static inline void rtsx_dump(u8 *buf, int buf_len)
-{
-	int i;
-	u8 tmp[16] = {0};
-	u8 *_ptr = buf;
-
-	for (i = 0; i < ((buf_len)/16); i++) {
-		RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-			"%02x %02x %02x %02x %02x %02x %02x %02x\n",
-			_ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5],
-			_ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11],
-			_ptr[12], _ptr[13], _ptr[14], _ptr[15]);
-		_ptr += 16;
-	}
-	if ((buf_len) % 16) {
-		memcpy(tmp, _ptr, (buf_len) % 16);
-		_ptr = tmp;
-		RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-			"%02x %02x %02x %02x %02x %02x %02x %02x\n",
-			_ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5],
-			_ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11],
-			_ptr[12], _ptr[13], _ptr[14], _ptr[15]);
-	}
-}
-
-#define RTSX_DUMP(buf, buf_len)		rtsx_dump((u8 *)(buf), (buf_len))
-
+#define RTSX_DUMP(buf, buf_len)					\
+	print_hex_dump(KERN_DEBUG, RTSX_STOR, DUMP_PREFIX_NONE,	\
+				16, 1, (buf), (buf_len), false)
 #else
 #define RTSX_DUMP(buf, buf_len)
 #endif
diff --git a/drivers/staging/sbe-2t3e3/2t3e3.h b/drivers/staging/sbe-2t3e3/2t3e3.h
index 383f2cf..ccad049 100644
--- a/drivers/staging/sbe-2t3e3/2t3e3.h
+++ b/drivers/staging/sbe-2t3e3/2t3e3.h
@@ -789,7 +789,6 @@
 void dc_receiver_onoff(struct channel *, u32);
 void dc_transmitter_onoff(struct channel *, u32);
 void dc_set_loopback(struct channel *, u32);
-u32 dc_init_descriptor_list(struct channel *);
 void dc_clear_descriptor_list(struct channel *);
 void dc_drop_descriptor_list(struct channel *);
 void dc_set_output_port(struct channel *);
diff --git a/drivers/staging/sbe-2t3e3/dc.c b/drivers/staging/sbe-2t3e3/dc.c
index 9e81d90..daadd6e 100644
--- a/drivers/staging/sbe-2t3e3/dc.c
+++ b/drivers/staging/sbe-2t3e3/dc.c
@@ -17,6 +17,8 @@
 #include "2t3e3.h"
 #include "ctrl.h"
 
+static int dc_init_descriptor_list(struct channel *sc);
+
 void dc_init(struct channel *sc)
 {
 	u32 val;
@@ -307,7 +309,7 @@
 			      SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE);
 }
 
-u32 dc_init_descriptor_list(struct channel *sc)
+static int dc_init_descriptor_list(struct channel *sc)
 {
 	u32 i, j;
 	struct sk_buff *m;
@@ -317,7 +319,7 @@
 					    sizeof(t3e3_rx_desc_t), GFP_KERNEL);
 	if (sc->ether.rx_ring == NULL) {
 		dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n");
-		return ENOMEM;
+		return -ENOMEM;
 	}
 
 	if (sc->ether.tx_ring == NULL)
@@ -327,7 +329,7 @@
 		kfree(sc->ether.rx_ring);
 		sc->ether.rx_ring = NULL;
 		dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n");
-		return ENOMEM;
+		return -ENOMEM;
 	}
 
 
@@ -351,7 +353,7 @@
 				sc->ether.tx_ring = NULL;
 				dev_err(&sc->pdev->dev, "SBE 2T3E3: token_alloc err:"
 					" no buffer space for RX ring\n");
-				return ENOBUFS;
+				return -ENOBUFS;
 			}
 			sc->ether.rx_data[i] = m;
 		}
diff --git a/drivers/staging/sbe-2t3e3/module.c b/drivers/staging/sbe-2t3e3/module.c
index cd778b3..8adb178 100644
--- a/drivers/staging/sbe-2t3e3/module.c
+++ b/drivers/staging/sbe-2t3e3/module.c
@@ -67,6 +67,7 @@
 	dev = alloc_hdlcdev(channel);
 	if (!dev) {
 		printk(KERN_ERR "SBE 2T3E3" ": Out of memory\n");
+		err = -ENOMEM;
 		goto free_regions;
 	}
 
@@ -82,8 +83,9 @@
 	else
 		channel->h.slot = 0;
 
-	if (setup_device(dev, channel))
-		goto free_regions;
+	err = setup_device(dev, channel);
+	if (err)
+		goto free_dev;
 
 	pci_read_config_dword(channel->pdev, 0x40, &val); /* mask sleep mode */
 	pci_write_config_dword(channel->pdev, 0x40, val & 0x3FFFFFFF);
@@ -92,14 +94,19 @@
 	pci_read_config_dword(channel->pdev, PCI_COMMAND, &channel->h.command);
 	t3e3_init(channel);
 
-	if (request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev)) {
+	err = request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev);
+	if (err) {
 		printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
-		goto free_regions;
+		goto unregister_dev;
 	}
 
 	pci_set_drvdata(pdev, channel);
 	return 0;
 
+unregister_dev:
+	unregister_hdlc_device(dev);
+free_dev:
+	free_netdev(dev);
 free_regions:
 	pci_release_regions(pdev);
 disable:
diff --git a/drivers/staging/sbe-2t3e3/netdev.c b/drivers/staging/sbe-2t3e3/netdev.c
index c7b5e8b..180c963 100644
--- a/drivers/staging/sbe-2t3e3/netdev.c
+++ b/drivers/staging/sbe-2t3e3/netdev.c
@@ -21,13 +21,13 @@
 #include <linux/interrupt.h>
 #include "2t3e3.h"
 
-int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct channel *sc = dev_to_priv(dev);
 	int cmd_2t3e3, len, rlen;
 	t3e3_param_t param;
 	t3e3_resp_t  resp;
-	void *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len);
+	void __user *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len);
 
 	if (cmd == SIOCWANDEV)
 		return hdlc_ioctl(dev, ifr, cmd);
@@ -82,7 +82,7 @@
 	return nstats;
 }
 
-int t3e3_open(struct net_device *dev)
+static int t3e3_open(struct net_device *dev)
 {
 	struct channel *sc = dev_to_priv(dev);
 	int ret = hdlc_open(dev);
@@ -97,7 +97,7 @@
 	return 0;
 }
 
-int t3e3_close(struct net_device *dev)
+static int t3e3_close(struct net_device *dev)
 {
 	struct channel *sc = dev_to_priv(dev);
 	hdlc_close(dev);
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index ca8946a..a414e52 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -719,7 +719,7 @@
 
 	if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT,
 		vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-		dev_dbg(&sep->pdev->dev, "[PID%d] remap_page_range failed\n",
+		dev_dbg(&sep->pdev->dev, "[PID%d] remap_pfn_range failed\n",
 						current->pid);
 		error = -EAGAIN;
 		goto end_function_with_error;
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index c90de96..099bc69 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -16,8 +16,6 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static bool debug;
-
 /* Version Information */
 #define DRIVER_VERSION "v2.14"
 #define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc"
@@ -184,11 +182,11 @@
 			       const char *function)
 {
 	if (!port) {
-		dbg("%s - port == NULL", function);
+		pr_debug("%s - port == NULL", function);
 		return -1;
 	}
 	if (!port->serial) {
-		dbg("%s - port->serial == NULL\n", function);
+		pr_debug("%s - port->serial == NULL\n", function);
 		return -1;
 	}
 
@@ -199,12 +197,12 @@
 				 const char *function)
 {
 	if (!serial) {
-		dbg("%s - serial == NULL\n", function);
+		pr_debug("%s - serial == NULL\n", function);
 		return -1;
 	}
 
 	if (!serial->type) {
-		dbg("%s - serial->type == NULL!", function);
+		pr_debug("%s - serial->type == NULL!", function);
 		return -1;
 	}
 
@@ -247,7 +245,6 @@
 	qt_port->shadowLSR =
 	    line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE |
 			   SERIAL_LSR_BI);
-	return;
 }
 
 static void ProcessModemStatus(struct quatech_port *qt_port,
@@ -256,7 +253,6 @@
 
 	qt_port->shadowMSR = modem_status;
 	wake_up_interruptible(&qt_port->wait);
-	return;
 }
 
 static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port,
@@ -276,7 +272,7 @@
 	status = urb->status;
 
 	if (status) {
-		dbg("nonzero write bulk status received:%d\n", status);
+		dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status);
 		return;
 	}
 
@@ -309,8 +305,8 @@
 
 	if (urb->status) {
 		qt_port->ReadBulkStopped = 1;
-		dbg("%s - nonzero write bulk status received: %d\n",
-		    __func__, urb->status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero write bulk status received: %d\n",
+			__func__, urb->status);
 		return;
 	}
 
@@ -325,21 +321,19 @@
 	/* index = MINOR(port->tty->device) - serial->minor; */
 	index = tty->index - serial->minor;
 
-	dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
+	dev_dbg(&port->dev, "%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
 
 	if (port_paranoia_check(port, __func__) != 0) {
-		dbg("%s - port_paranoia_check, exiting\n", __func__);
 		qt_port->ReadBulkStopped = 1;
 		goto exit;
 	}
 
-	if (!serial) {
-		dbg("%s - bad serial pointer, exiting\n", __func__);
+	if (!serial)
 		goto exit;
-	}
+
 	if (qt_port->closePending == 1) {
 		/* Were closing , stop reading */
-		dbg("%s - (qt_port->closepending == 1\n", __func__);
+		dev_dbg(&port->dev, "%s - (qt_port->closepending == 1\n", __func__);
 		qt_port->ReadBulkStopped = 1;
 		goto exit;
 	}
@@ -357,8 +351,8 @@
 	if (urb->status) {
 		qt_port->ReadBulkStopped = 1;
 
-		dbg("%s - nonzero read bulk status received: %d\n",
-		    __func__, urb->status);
+		dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
@@ -373,7 +367,7 @@
 				case 0x00:
 					/* line status change 4th byte must follow */
 					if (i > (RxCount - 4)) {
-						dbg("Illegal escape seuences in received data\n");
+						dev_dbg(&port->dev, "Illegal escape seuences in received data\n");
 						break;
 					}
 					ProcessLineStatus(qt_port, data[i + 3]);
@@ -383,9 +377,9 @@
 
 				case 0x01:
 					/* Modem status status change 4th byte must follow */
-					dbg("Modem status status.\n");
+					dev_dbg(&port->dev, "Modem status status.\n");
 					if (i > (RxCount - 4)) {
-						dbg("Illegal escape sequences in received data\n");
+						dev_dbg(&port->dev, "Illegal escape sequences in received data\n");
 						break;
 					}
 					ProcessModemStatus(qt_port,
@@ -394,7 +388,7 @@
 					flag = 1;
 					break;
 				case 0xff:
-					dbg("No status sequence.\n");
+					dev_dbg(&port->dev, "No status sequence.\n");
 
 					if (tty) {
 						ProcessRxChar(tty, port, data[i]);
@@ -423,8 +417,8 @@
 			  qt_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 	if (result)
-		dbg("%s - failed resubmitting read urb, error %d",
-		    __func__, result);
+		dev_dbg(&port->dev, "%s - failed resubmitting read urb, error %d",
+			__func__, result);
 	else {
 		if (RxCount) {
 			tty_flip_buffer_push(tty);
@@ -519,7 +513,6 @@
 	PortSettings += ((__u16) (device_data->porta));
 
 	length = sizeof(struct qt_get_device_data);
-	dbg("%s - PortSettings = 0x%x\n", __func__, PortSettings);
 
 	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 				 QT_SET_GET_DEVICE, 0x40, PortSettings,
@@ -693,6 +686,7 @@
 
 static int qt_startup(struct usb_serial *serial)
 {
+	struct device *dev = &serial->dev->dev;
 	struct usb_serial_port *port;
 	struct quatech_port *qt_port;
 	struct qt_get_device_data DeviceData;
@@ -704,8 +698,6 @@
 		port = serial->port[i];
 		qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL);
 		if (!qt_port) {
-			dbg("%s: kmalloc for quatech_port (%d) failed!.",
-			    __func__, i);
 			for (--i; i >= 0; i--) {
 				port = serial->port[i];
 				kfree(usb_get_serial_port_data(port));
@@ -720,25 +712,23 @@
 	}
 
 	status = qt_get_device(serial, &DeviceData);
-	if (status < 0) {
-		dbg(__FILE__ "box_get_device failed");
+	if (status < 0)
 		goto startup_error;
-	}
 
-	dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb);
+	dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb);
 
 	DeviceData.portb &= ~FULLPWRBIT;
-	dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb);
+	dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb);
 
 	status = qt_set_device(serial, &DeviceData);
 	if (status < 0) {
-		dbg(__FILE__ "qt_set_device failed\n");
+		dev_dbg(dev, "qt_set_device failed\n");
 		goto startup_error;
 	}
 
 	status = qt_get_device(serial, &DeviceData);
 	if (status < 0) {
-		dbg(__FILE__ "qt_get_device failed");
+		dev_dbg(dev, "qt_get_device failed\n");
 		goto startup_error;
 	}
 
@@ -782,29 +772,27 @@
 
 	status = BoxSetPrebufferLevel(serial);	/* sets to default value */
 	if (status < 0) {
-		dbg(__FILE__ "BoxSetPrebufferLevel failed\n");
+		dev_dbg(dev, "BoxSetPrebufferLevel failed\n");
 		goto startup_error;
 	}
 
 	status = BoxSetATC(serial, ATC_DISABLED);
 	if (status < 0) {
-		dbg(__FILE__ "BoxSetATC failed\n");
+		dev_dbg(dev, "BoxSetATC failed\n");
 		goto startup_error;
 	}
 
-	dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb);
+	dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb);
 
 	DeviceData.portb |= NEXT_BOARD_POWER_BIT;
-	dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb);
+	dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb);
 
 	status = qt_set_device(serial, &DeviceData);
 	if (status < 0) {
-		dbg(__FILE__ "qt_set_device failed\n");
+		dev_dbg(dev, "qt_set_device failed\n");
 		goto startup_error;
 	}
 
-	dbg("Exit Success %s\n", __func__);
-
 	return 0;
 
 startup_error:
@@ -815,8 +803,6 @@
 		usb_set_serial_port_data(port, NULL);
 	}
 
-	dbg("Exit fail %s\n", __func__);
-
 	return -EIO;
 }
 
@@ -871,10 +857,10 @@
 	/* Port specific setups */
 	result = qt_open_channel(serial, port->number, &ChannelData);
 	if (result < 0) {
-		dbg(__FILE__ "qt_open_channel failed\n");
+		dev_dbg(&port->dev, "qt_open_channel failed\n");
 		return result;
 	}
-	dbg(__FILE__ "qt_open_channel completed.\n");
+	dev_dbg(&port->dev, "qt_open_channel completed.\n");
 
 /* FIXME: are these needed?  Does it even do anything useful? */
 	quatech_port->shadowLSR = ChannelData.line_status &
@@ -886,10 +872,10 @@
 	/* Set Baud rate to default and turn off (default)flow control here */
 	result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR);
 	if (result < 0) {
-		dbg(__FILE__ "qt_setuart failed\n");
+		dev_dbg(&port->dev, "qt_setuart failed\n");
 		return result;
 	}
-	dbg(__FILE__ "qt_setuart completed.\n");
+	dev_dbg(&port->dev, "qt_setuart completed.\n");
 
 	/*
 	 * Put this here to make it responsive to stty and defaults set by
@@ -924,12 +910,12 @@
 
 	}
 
-	dbg("port number is %d\n", port->number);
-	dbg("serial number is %d\n", port->serial->minor);
-	dbg("Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
-	dbg("BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
-	dbg("Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress);
-	dbg("port's number in the device is %d\n", quatech_port->port_num);
+	dev_dbg(&port->dev, "port number is %d\n", port->number);
+	dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
+	dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
+	dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
+	dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress);
+	dev_dbg(&port->dev, "port's number in the device is %d\n", quatech_port->port_num);
 	quatech_port->read_urb = port->read_urb;
 
 	/* set up our bulk in urb */
@@ -942,7 +928,7 @@
 			  quatech_port->read_urb->transfer_buffer_length,
 			  qt_read_bulk_callback, quatech_port);
 
-	dbg("qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
+	dev_dbg(&port->dev, "qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
 	quatech_port->read_urb_busy = true;
 	result = usb_submit_urb(quatech_port->read_urb, GFP_KERNEL);
 	if (result) {
@@ -976,8 +962,6 @@
 			chars = port->write_urb->transfer_buffer_length;
 	}
 
-	dbg("%s - returns %d\n", __func__, chars);
-
 	return chars;
 }
 
@@ -999,7 +983,7 @@
 
 		wait--;
 		if (wait == 0) {
-			dbg("%s - TIMEOUT", __func__);
+			dev_dbg(&qt_port->port->dev, "%s - TIMEOUT", __func__);
 			return;
 		} else {
 			wait = 30;
@@ -1037,17 +1021,15 @@
 	/* Close uart channel */
 	status = qt_close_channel(serial, index);
 	if (status < 0)
-		dbg("%s - port %d qt_close_channel failed.\n",
-		    __func__, port->number);
+		dev_dbg(&port->dev, "%s - port %d qt_close_channel failed.\n", __func__, port->number);
 
 	port0->open_ports--;
 
-	dbg("qt_num_open_ports in close%d:in port%d\n",
-	    port0->open_ports, port->number);
+	dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n", port0->open_ports, port->number);
 
 	if (port0->open_ports == 0) {
 		if (serial->port[0]->interrupt_in_urb) {
-			dbg("%s", "Shutdown interrupt_in_urb\n");
+			dev_dbg(&port->dev, "%s", "Shutdown interrupt_in_urb\n");
 			usb_kill_urb(serial->port[0]->interrupt_in_urb);
 		}
 
@@ -1071,14 +1053,14 @@
 		return -ENODEV;
 
 	if (count == 0) {
-		dbg("%s - write request of 0 bytes\n", __func__);
+		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status == -EINPROGRESS) {
-			dbg("%s - already writing\n", __func__);
+			dev_dbg(&port->dev, "%s - already writing\n", __func__);
 			return 0;
 		}
 
@@ -1098,8 +1080,8 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (result)
-			dbg("%s - failed submitting write urb, error %d\n",
-			    __func__, result);
+			dev_dbg(&port->dev, "%s - failed submitting write urb, error %d\n",
+				__func__, result);
 		else
 			result = count;
 
@@ -1118,10 +1100,8 @@
 
 	int retval = -EINVAL;
 
-	if (port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port\n");
+	if (port_paranoia_check(port, __func__))
 		return -1;
-	}
 
 	serial = get_usb_serial(port, __func__);
 
@@ -1150,7 +1130,7 @@
 	struct usb_serial *serial = get_usb_serial(port, __func__);
 	unsigned int index;
 
-	dbg("%s cmd 0x%04x", __func__, cmd);
+	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
 
 	index = tty->index - serial->minor;
 
@@ -1183,7 +1163,7 @@
 		return 0;
 	}
 
-	dbg("%s -No ioctl for that one.  port = %d\n", __func__, port->number);
+	dev_dbg(&port->dev, "%s -No ioctl for that one.  port = %d\n", __func__, port->number);
 	return -ENOIOCTLCMD;
 }
 
@@ -1230,7 +1210,7 @@
 	else
 		new_LCR |= SERIAL_ONE_STOPB;
 
-	dbg("%s - 4\n", __func__);
+	dev_dbg(&port->dev, "%s - 4\n", __func__);
 
 	/* Thats the LCR stuff, go ahead and set it */
 	baud = tty_get_baud_rate(tty);
@@ -1238,7 +1218,7 @@
 		/* pick a default, any default... */
 		baud = 9600;
 
-	dbg("%s - got baud = %d\n", __func__, baud);
+	dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud);
 
 	divisor = MAX_BAUD_RATE / baud;
 	remainder = MAX_BAUD_RATE % baud;
@@ -1252,30 +1232,28 @@
 	status =
 	    qt_setuart(port->serial, index, (unsigned short)divisor, new_LCR);
 	if (status < 0) {
-		dbg(__FILE__ "qt_setuart failed\n");
+		dev_dbg(&port->dev, "qt_setuart failed\n");
 		return;
 	}
 
 	/* Now determine flow control */
 	if (cflag & CRTSCTS) {
-		dbg("%s - Enabling HW flow control port %d\n", __func__,
-		    port->number);
+		dev_dbg(&port->dev, "%s - Enabling HW flow control port %d\n", __func__, port->number);
 
 		/* Enable RTS/CTS flow control */
 		status = BoxSetHW_FlowCtrl(port->serial, index, 1);
 
 		if (status < 0) {
-			dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n");
+			dev_dbg(&port->dev, "BoxSetHW_FlowCtrl failed\n");
 			return;
 		}
 	} else {
 		/* Disable RTS/CTS flow control */
-		dbg("%s - disabling HW flow control port %d\n", __func__,
-		    port->number);
+		dev_dbg(&port->dev, "%s - disabling HW flow control port %d\n", __func__, port->number);
 
 		status = BoxSetHW_FlowCtrl(port->serial, index, 0);
 		if (status < 0) {
-			dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n");
+			dev_dbg(&port->dev, "BoxSetHW_FlowCtrl failed\n");
 			return;
 		}
 
@@ -1290,13 +1268,13 @@
 		    BoxSetSW_FlowCtrl(port->serial, index, stop_char,
 				      start_char);
 		if (status < 0)
-			dbg(__FILE__ "BoxSetSW_FlowCtrl (enabled) failed\n");
+			dev_dbg(&port->dev, "BoxSetSW_FlowCtrl (enabled) failed\n");
 
 	} else {
 		/* disable SW flow control */
 		status = BoxDisable_SW_FlowCtrl(port->serial, index);
 		if (status < 0)
-			dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
+			dev_dbg(&port->dev, "BoxSetSW_FlowCtrl (diabling) failed\n");
 
 	}
 	termios->c_cflag &= ~CMSPAR;
@@ -1410,7 +1388,7 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct usb_serial *serial = get_usb_serial(port, __func__);
 	struct quatech_port *qt_port = qt_get_port_private(port);
-	int retval = -ENODEV;
+	int retval;
 
 	if (!serial)
 		return -ENODEV;
@@ -1428,7 +1406,7 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct usb_serial *serial = get_usb_serial(port, __func__);
 	struct quatech_port *qt_port = qt_get_port_private(port);
-	int retval = -ENODEV;
+	int retval;
 
 	if (!serial)
 		return -ENODEV;
@@ -1456,7 +1434,6 @@
 	qt_port->RxHolding = 1;
 
 	mutex_unlock(&qt_port->lock);
-	return;
 }
 
 static void qt_unthrottle(struct tty_struct *tty)
@@ -1474,10 +1451,10 @@
 	mutex_lock(&qt_port->lock);
 
 	if (qt_port->RxHolding == 1) {
-		dbg("%s -qt_port->RxHolding == 1\n", __func__);
+		dev_dbg(&port->dev, "%s -qt_port->RxHolding == 1\n", __func__);
 
 		qt_port->RxHolding = 0;
-		dbg("%s - qt_port->RxHolding = 0\n", __func__);
+		dev_dbg(&port->dev, "%s - qt_port->RxHolding = 0\n", __func__);
 
 		/* if we have a bulk endpoint, start it up */
 		if ((serial->num_bulk_in) && (qt_port->ReadBulkStopped == 1)) {
@@ -1497,19 +1474,12 @@
 		}
 	}
 	mutex_unlock(&qt_port->lock);
-	return;
-
 }
 
 static int qt_calc_num_ports(struct usb_serial *serial)
 {
 	int num_ports;
 
-	dbg("numberofendpoints: %d\n",
-	    (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
-	dbg("numberofendpoints: %d\n",
-	    (int)serial->interface->altsetting->desc.bNumEndpoints);
-
 	num_ports =
 	    (serial->interface->cur_altsetting->desc.bNumEndpoints - 1) / 2;
 
@@ -1550,6 +1520,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/silicom/Kconfig b/drivers/staging/silicom/Kconfig
new file mode 100644
index 0000000..eda2e7d
--- /dev/null
+++ b/drivers/staging/silicom/Kconfig
@@ -0,0 +1,46 @@
+#
+# Silicom device configuration
+#
+
+config NET_VENDOR_SILICOM
+	bool "Silicom devices"
+	default y
+	depends on PCI
+	---help---
+	  If you have a network card (Ethernet) belonging to this class,
+	  say Y.
+
+	  Note that the answer to this question does not directly affect
+	  the kernel: saying N will just case the configurator to skip all
+	  the questions regarding Silicom chipsets. If you say Y, you will be asked
+	  for your specific chipset/driver in the following questions.
+
+if NET_VENDOR_SILICOM
+
+config SBYPASS
+	tristate "Silicom BypassCTL library support"
+	depends on PCI && NET
+	depends on m
+	---help---
+	  If you have a network (Ethernet) controller of this type, say Y
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called bypass.
+
+config BPCTL
+	tristate "Silicom BypassCTL net support"
+	depends on PCI && NET
+	depends on m
+	select SBYPASS
+	select NET_CORE
+	select MII
+	---help---
+	  If you have a network (Ethernet) controller of this type, say Y
+	  or M and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called bpctl_mod.
+
+
+endif # NET_VENDOR_SILICOM
diff --git a/drivers/staging/silicom/Makefile b/drivers/staging/silicom/Makefile
new file mode 100644
index 0000000..80e6d12
--- /dev/null
+++ b/drivers/staging/silicom/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Bypass network device drivers.
+#
+
+obj-$(CONFIG_BPCTL) += bpctl_mod.o
+obj-$(CONFIG_SBYPASS) += bypasslib/
+
+
+bpctl_mod-objs := bp_mod.o  bp_proc.o
diff --git a/drivers/staging/silicom/README b/drivers/staging/silicom/README
new file mode 100644
index 0000000..ae970b3
--- /dev/null
+++ b/drivers/staging/silicom/README
@@ -0,0 +1,14 @@
+
+Theory of Operation:
+
+The Silicom Bypass Network Interface Cards (NICs) are network cards with paired ports (2 or 4). 
+The pairs either act as a "wire" allowing the network packets to pass or insert the device in 
+between the two ports.  When paired with the on-board hardware watchdog or other failsafe, 
+they provide high availability for the network in the face of software outages or maintenance.
+
+The software requirements are for a kernel level driver that interfaces with the bypass and watchdog,
+as well as for control software. User control can be either the provided standalone executable 
+(/bin/bpctl) or the API exposed by the Silicom library.
+
+
+
diff --git a/drivers/staging/silicom/TODO b/drivers/staging/silicom/TODO
new file mode 100644
index 0000000..09d07b0
--- /dev/null
+++ b/drivers/staging/silicom/TODO
@@ -0,0 +1,8 @@
+TODO:
+	- checkpatch.pl cleanups
+	- locking audit
+	- single module with all functionality
+	- userland 
+	- fix monolithic build.
+
+
diff --git a/drivers/staging/silicom/bits.h b/drivers/staging/silicom/bits.h
new file mode 100644
index 0000000..8c411d0
--- /dev/null
+++ b/drivers/staging/silicom/bits.h
@@ -0,0 +1,56 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom  */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*    02/25/00 Hav Khauv        Initial version.                              */
+/******************************************************************************/
+
+#ifndef BITS_H
+#define BITS_H
+
+/******************************************************************************/
+/* Bit Mask definitions */
+/******************************************************************************/
+
+#define BIT_NONE            0x00
+#define BIT_0               0x01
+#define BIT_1               0x02
+#define BIT_2               0x04
+#define BIT_3               0x08
+#define BIT_4               0x10
+#define BIT_5               0x20
+#define BIT_6               0x40
+#define BIT_7               0x80
+#define BIT_8               0x0100
+#define BIT_9               0x0200
+#define BIT_10              0x0400
+#define BIT_11              0x0800
+#define BIT_12              0x1000
+#define BIT_13              0x2000
+#define BIT_14              0x4000
+#define BIT_15              0x8000
+#define BIT_16              0x010000
+#define BIT_17              0x020000
+#define BIT_18              0x040000
+#define BIT_19              0x080000
+#define BIT_20              0x100000
+#define BIT_21              0x200000
+#define BIT_22              0x400000
+#define BIT_23              0x800000
+#define BIT_24              0x01000000
+#define BIT_25              0x02000000
+#define BIT_26              0x04000000
+#define BIT_27              0x08000000
+#define BIT_28              0x10000000
+#define BIT_29              0x20000000
+#define BIT_30              0x40000000
+#define BIT_31              0x80000000
+
+#endif				/* BITS_H */
diff --git a/drivers/staging/silicom/bp_ioctl.h b/drivers/staging/silicom/bp_ioctl.h
new file mode 100644
index 0000000..57de34a
--- /dev/null
+++ b/drivers/staging/silicom/bp_ioctl.h
@@ -0,0 +1,140 @@
+/******************************************************************************/
+/*                                                                            */
+/* Silicom Bypass Control Utility, Copyright (c) 2005-2007 Silicom            */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef BP_IOCTL_H
+#define BP_IOCTL_H
+
+#define BP_CAP                   0x01	/* BIT_0 */
+#define BP_STATUS_CAP            0x02
+#define BP_STATUS_CHANGE_CAP     0x04
+#define SW_CTL_CAP               0x08
+#define BP_DIS_CAP               0x10
+#define BP_DIS_STATUS_CAP        0x20
+#define STD_NIC_CAP              0x40
+#define BP_PWOFF_ON_CAP          0x80
+#define BP_PWOFF_OFF_CAP         0x0100
+#define BP_PWOFF_CTL_CAP         0x0200
+#define BP_PWUP_ON_CAP           0x0400
+#define BP_PWUP_OFF_CAP          0x0800
+#define BP_PWUP_CTL_CAP          0x1000
+#define WD_CTL_CAP               0x2000
+#define WD_STATUS_CAP            0x4000
+#define WD_TIMEOUT_CAP           0x8000
+#define TX_CTL_CAP               0x10000
+#define TX_STATUS_CAP            0x20000
+#define TAP_CAP                  0x40000
+#define TAP_STATUS_CAP           0x80000
+#define TAP_STATUS_CHANGE_CAP    0x100000
+#define TAP_DIS_CAP              0x200000
+#define TAP_DIS_STATUS_CAP       0x400000
+#define TAP_PWUP_ON_CAP          0x800000
+#define TAP_PWUP_OFF_CAP         0x1000000
+#define TAP_PWUP_CTL_CAP         0x2000000
+#define NIC_CAP_NEG              0x4000000
+#define TPL_CAP                  0x8000000
+#define DISC_CAP                 0x10000000
+#define DISC_DIS_CAP             0x20000000
+#define DISC_PWUP_CTL_CAP        0x40000000
+
+#define TPL2_CAP_EX              0x01
+#define DISC_PORT_CAP_EX         0x02
+
+#define WD_MIN_TIME_MASK(val)      (val & 0xf)
+#define WD_STEP_COUNT_MASK(val)    ((val & 0xf) << 5)
+#define WDT_STEP_TIME              0x10	/* BIT_4 */
+
+#define WD_MIN_TIME_GET(desc)   (desc & 0xf)
+#define WD_STEP_COUNT_GET(desc) ((desc>>5) & 0xf)
+
+typedef enum {
+	IF_SCAN,
+	GET_DEV_NUM,
+	IS_BYPASS,
+	GET_BYPASS_SLAVE,
+	GET_BYPASS_CAPS,
+	GET_WD_SET_CAPS,
+	SET_BYPASS,
+	GET_BYPASS,
+	GET_BYPASS_CHANGE,
+	SET_BYPASS_WD,
+	GET_BYPASS_WD,
+	GET_WD_EXPIRE_TIME,
+	RESET_BYPASS_WD_TIMER,
+	SET_DIS_BYPASS,
+	GET_DIS_BYPASS,
+	SET_BYPASS_PWOFF,
+	GET_BYPASS_PWOFF,
+	SET_BYPASS_PWUP,
+	GET_BYPASS_PWUP,
+	SET_STD_NIC,
+	GET_STD_NIC,
+	SET_TX,
+	GET_TX,
+	SET_TAP,
+	GET_TAP,
+	GET_TAP_CHANGE,
+	SET_DIS_TAP,
+	GET_DIS_TAP,
+	SET_TAP_PWUP,
+	GET_TAP_PWUP,
+	SET_WD_EXP_MODE,
+	GET_WD_EXP_MODE,
+	SET_WD_AUTORESET,
+	GET_WD_AUTORESET,
+	SET_TPL,
+	GET_TPL,
+	SET_DISC,
+	GET_DISC,
+	GET_DISC_CHANGE,
+	SET_DIS_DISC,
+	GET_DIS_DISC,
+	SET_DISC_PWUP,
+	GET_DISC_PWUP,
+	GET_BYPASS_INFO = 100,
+	GET_BP_WAIT_AT_PWUP,
+	SET_BP_WAIT_AT_PWUP,
+	GET_BP_HW_RESET,
+	SET_BP_HW_RESET,
+	SET_DISC_PORT,
+	GET_DISC_PORT,
+	SET_DISC_PORT_PWUP,
+	GET_DISC_PORT_PWUP,
+	SET_BP_FORCE_LINK,
+	GET_BP_FORCE_LINK,
+#ifdef BP_SELF_TEST
+	SET_BP_SELF_TEST = 200,
+	GET_BP_SELF_TEST,
+#endif
+
+} CMND_TYPE_SD;
+
+/*
+* The major device number. We can't rely on dynamic
+* registration any more, because ioctls need to know
+* it.
+*/
+
+#define MAGIC_NUM 'J'
+
+/* for passing single values */
+struct bpctl_cmd {
+	int status;
+	int data[8];
+	int in_param[8];
+	int out_param[8];
+};
+
+#define IOCTL_TX_MSG(cmd) _IOWR(MAGIC_NUM, cmd, struct bpctl_cmd)
+
+#define DEVICE_NAME "bpctl"
+
+#endif
diff --git a/drivers/staging/silicom/bp_mod.c b/drivers/staging/silicom/bp_mod.c
new file mode 100644
index 0000000..3cfd051
--- /dev/null
+++ b/drivers/staging/silicom/bp_mod.c
@@ -0,0 +1,8931 @@
+/******************************************************************************/
+/*                                                                            */
+/* Bypass Control utility, Copyright (c) 2005-20011 Silicom                   */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*  Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.          */
+/*                                                                            */
+/*                                                                            */
+/******************************************************************************/
+#include <linux/version.h>
+
+#include <linux/kernel.h>	/* We're doing kernel work */
+#include <linux/module.h>	/* Specifically, a module */
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/rcupdate.h>
+#include <linux/etherdevice.h>
+
+#include <linux/uaccess.h>	/* for get_user and put_user */
+#include <linux/sched.h>
+#include <linux/ethtool.h>
+#include <linux/proc_fs.h>
+
+#include "bp_ioctl.h"
+#include "bp_mod.h"
+#include "bypass.h"
+#include "libbp_sd.h"
+
+#define SUCCESS 0
+#define BP_MOD_VER  "9.0.4"
+#define BP_MOD_DESCR "Silicom Bypass-SD Control driver"
+#define BP_SYNC_FLAG 1
+
+static int Device_Open = 0;
+static int major_num = 0;
+
+MODULE_AUTHOR("Anna Lukin, annal@silicom.co.il");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(BP_MOD_DESCR);
+MODULE_VERSION(BP_MOD_VER);
+spinlock_t bpvm_lock;
+
+#define lock_bpctl() 					\
+if (down_interruptible(&bpctl_sema)) {			\
+	return -ERESTARTSYS;				\
+}							\
+
+#define unlock_bpctl() 					\
+	up(&bpctl_sema);
+
+/* Media Types */
+typedef enum {
+	bp_copper = 0,
+	bp_fiber,
+	bp_cx4,
+	bp_none,
+} bp_media_type;
+
+struct pfs_unit_sd {
+	struct proc_dir_entry *proc_entry;
+	char proc_name[32];
+};
+
+struct bypass_pfs_sd {
+	char dir_name[32];
+	struct proc_dir_entry *bypass_entry;
+	struct pfs_unit_sd bypass_info;
+	struct pfs_unit_sd bypass_slave;
+	struct pfs_unit_sd bypass_caps;
+	struct pfs_unit_sd wd_set_caps;
+	struct pfs_unit_sd bypass;
+	struct pfs_unit_sd bypass_change;
+	struct pfs_unit_sd bypass_wd;
+	struct pfs_unit_sd wd_expire_time;
+	struct pfs_unit_sd reset_bypass_wd;
+	struct pfs_unit_sd dis_bypass;
+	struct pfs_unit_sd bypass_pwup;
+	struct pfs_unit_sd bypass_pwoff;
+	struct pfs_unit_sd std_nic;
+	struct pfs_unit_sd tap;
+	struct pfs_unit_sd dis_tap;
+	struct pfs_unit_sd tap_pwup;
+	struct pfs_unit_sd tap_change;
+	struct pfs_unit_sd wd_exp_mode;
+	struct pfs_unit_sd wd_autoreset;
+	struct pfs_unit_sd tpl;
+
+};
+
+typedef struct _bpctl_dev {
+	char *name;
+	char *desc;
+	struct pci_dev *pdev;	/* PCI device */
+	struct net_device *ndev;	/* net device */
+	unsigned long mem_map;
+	uint8_t bus;
+	uint8_t slot;
+	uint8_t func;
+	u_int32_t device;
+	u_int32_t vendor;
+	u_int32_t subvendor;
+	u_int32_t subdevice;
+	int ifindex;
+	uint32_t bp_caps;
+	uint32_t bp_caps_ex;
+	uint8_t bp_fw_ver;
+	int bp_ext_ver;
+	int wdt_status;
+	unsigned long bypass_wdt_on_time;
+	uint32_t bypass_timer_interval;
+	struct timer_list bp_timer;
+	uint32_t reset_time;
+	uint8_t bp_status_un;
+	atomic_t wdt_busy;
+	bp_media_type media_type;
+	int bp_tpl_flag;
+	struct timer_list bp_tpl_timer;
+	spinlock_t bypass_wr_lock;
+	int bp_10g;
+	int bp_10gb;
+	int bp_fiber5;
+	int bp_10g9;
+	int bp_i80;
+	int bp_540;
+	int (*hard_start_xmit_save) (struct sk_buff *skb,
+				     struct net_device *dev);
+	const struct net_device_ops *old_ops;
+	struct net_device_ops new_ops;
+	int bp_self_test_flag;
+	char *bp_tx_data;
+	struct bypass_pfs_sd bypass_pfs_set;
+
+} bpctl_dev_t;
+
+static bpctl_dev_t *bpctl_dev_arr;
+
+static struct semaphore bpctl_sema;
+static int device_num = 0;
+
+static int get_dev_idx(int ifindex);
+static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev);
+static int disc_status(bpctl_dev_t *pbpctl_dev);
+static int bypass_status(bpctl_dev_t *pbpctl_dev);
+static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left);
+static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev);
+static void if_scan_init(void);
+
+int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block);
+int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block);
+int bp_proc_create(void);
+
+int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
+int get_dev_idx_bsf(int bus, int slot, int func);
+
+static unsigned long str_to_hex(char *p);
+static int bp_device_event(struct notifier_block *unused,
+			   unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+	static bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
+	int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
+	/* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
+	/* return NOTIFY_DONE; */
+	if (!dev)
+		return NOTIFY_DONE;
+	if (event == NETDEV_REGISTER) {
+		{
+			struct ethtool_drvinfo drvinfo;
+			char cbuf[32];
+			char *buf = NULL;
+			char res[10];
+			int i = 0, ifindex, idx_dev = 0;
+			int bus = 0, slot = 0, func = 0;
+			ifindex = dev->ifindex;
+
+			memset(res, 0, 10);
+			memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
+
+			if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+				memset(&drvinfo, 0, sizeof(drvinfo));
+				dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
+			} else
+				return NOTIFY_DONE;
+			if (!drvinfo.bus_info)
+				return NOTIFY_DONE;
+			if (!strcmp(drvinfo.bus_info, "N/A"))
+				return NOTIFY_DONE;
+			memcpy(&cbuf, drvinfo.bus_info, 32);
+			buf = &cbuf[0];
+
+			while (*buf++ != ':') ;
+			for (i = 0; i < 10; i++, buf++) {
+				if (*buf == ':')
+					break;
+				res[i] = *buf;
+
+			}
+			buf++;
+			bus = str_to_hex(res);
+			memset(res, 0, 10);
+
+			for (i = 0; i < 10; i++, buf++) {
+				if (*buf == '.')
+					break;
+				res[i] = *buf;
+
+			}
+			buf++;
+			slot = str_to_hex(res);
+			func = str_to_hex(buf);
+			idx_dev = get_dev_idx_bsf(bus, slot, func);
+
+			if (idx_dev != -1) {
+
+				bpctl_dev_arr[idx_dev].ifindex = ifindex;
+				bpctl_dev_arr[idx_dev].ndev = dev;
+
+				bypass_proc_remove_dev_sd(&bpctl_dev_arr
+							  [idx_dev]);
+				bypass_proc_create_dev_sd(&bpctl_dev_arr
+							  [idx_dev]);
+
+			}
+
+		}
+		return NOTIFY_DONE;
+
+	}
+	if (event == NETDEV_UNREGISTER) {
+		int idx_dev = 0;
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if (bpctl_dev_arr[idx_dev].ndev == dev) {
+				bypass_proc_remove_dev_sd(&bpctl_dev_arr
+							  [idx_dev]);
+				bpctl_dev_arr[idx_dev].ndev = NULL;
+
+				return NOTIFY_DONE;
+
+			}
+
+		}
+		return NOTIFY_DONE;
+	}
+	if (event == NETDEV_CHANGENAME) {
+		int idx_dev = 0;
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if (bpctl_dev_arr[idx_dev].ndev == dev) {
+				bypass_proc_remove_dev_sd(&bpctl_dev_arr
+							  [idx_dev]);
+				bypass_proc_create_dev_sd(&bpctl_dev_arr
+							  [idx_dev]);
+
+				return NOTIFY_DONE;
+
+			}
+
+		}
+		return NOTIFY_DONE;
+
+	}
+
+	switch (event) {
+
+	case NETDEV_CHANGE:{
+			if (netif_carrier_ok(dev))
+				return NOTIFY_DONE;
+
+			if (((dev_num = get_dev_idx(dev->ifindex)) == -1) ||
+			    (!(pbpctl_dev = &bpctl_dev_arr[dev_num])))
+				return NOTIFY_DONE;
+
+			if ((is_bypass_fn(pbpctl_dev)) == 1)
+				pbpctl_dev_m = pbpctl_dev;
+			else
+				pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+			if (!pbpctl_dev_m)
+				return NOTIFY_DONE;
+			ret = bypass_status(pbpctl_dev_m);
+			if (ret == 1)
+				printk("bpmod: %s is in the Bypass mode now",
+				       dev->name);
+			ret_d = disc_status(pbpctl_dev_m);
+			if (ret_d == 1)
+				printk
+				    ("bpmod: %s is in the Disconnect mode now",
+				     dev->name);
+			if (ret || ret_d) {
+				wdt_timer(pbpctl_dev_m, &time_left);
+				if (time_left == -1)
+					printk("; WDT has expired");
+				printk(".\n");
+
+			}
+			return NOTIFY_DONE;
+
+		}
+
+	default:
+		return NOTIFY_DONE;
+
+	}
+	return NOTIFY_DONE;
+
+}
+
+static struct notifier_block bp_notifier_block = {
+	.notifier_call = bp_device_event,
+};
+
+static int device_open(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+	printk("device_open(%p)\n", file);
+#endif
+	Device_Open++;
+/*
+* Initialize the message
+*/
+	return SUCCESS;
+}
+
+static int device_release(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+	printk("device_release(%p,%p)\n", inode, file);
+#endif
+	Device_Open--;
+	return SUCCESS;
+}
+
+int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
+int wdt_time_left(bpctl_dev_t *pbpctl_dev);
+
+static void write_pulse(bpctl_dev_t *pbpctl_dev,
+			unsigned int ctrl_ext,
+			unsigned char value, unsigned char len)
+{
+	unsigned char ctrl_val = 0;
+	unsigned int i = len;
+	unsigned int ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_c = NULL;
+
+	if (pbpctl_dev->bp_i80)
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	if (pbpctl_dev->bp_540)
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+
+	if (pbpctl_dev->bp_10g9) {
+		if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev)))
+			return;
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+	}
+
+	while (i--) {
+		ctrl_val = (value >> i) & 0x1;
+		if (ctrl_val) {
+			if (pbpctl_dev->bp_10g9) {
+
+				/* To start management : MCLK 1, MDIO 1, output */
+				/* DATA 1 CLK 1 */
+				/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
+				BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+						ctrl_ext |
+						BP10G_MDIO_DATA_OUT9);
+				BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+						(ctrl | BP10G_MCLK_DATA_OUT9 |
+						 BP10G_MCLK_DIR_OUT9));
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
+								      BPCTLI_CTRL_EXT_MCLK_DIR5
+								      |
+								      BPCTLI_CTRL_EXT_MDIO_DIR5
+								      |
+								      BPCTLI_CTRL_EXT_MDIO_DATA5
+								      |
+								      BPCTLI_CTRL_EXT_MCLK_DATA5));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
+								      BPCTLI_CTRL_EXT_MDIO_DIR80
+								      |
+								      BPCTLI_CTRL_EXT_MDIO_DATA80));
+
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, (ctrl |
+									  BPCTLI_CTRL_EXT_MCLK_DIR80
+									  |
+									  BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+			} else if (pbpctl_dev->bp_540) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl |
+								   BP540_MDIO_DIR
+								   |
+								   BP540_MDIO_DATA
+								   |
+								   BP540_MCLK_DIR
+								   |
+								   BP540_MCLK_DATA));
+
+			} else if (pbpctl_dev->bp_10gb) {
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+						 (ctrl_ext | BP10GB_MDIO_SET |
+						  BP10GB_MCLK_SET) &
+						 ~(BP10GB_MCLK_DIR |
+						   BP10GB_MDIO_DIR |
+						   BP10GB_MDIO_CLR |
+						   BP10GB_MCLK_CLR));
+
+			} else if (!pbpctl_dev->bp_10g)
+				/* To start management : MCLK 1, MDIO 1, output */
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   (ctrl_ext |
+						    BPCTLI_CTRL_EXT_MCLK_DIR |
+						    BPCTLI_CTRL_EXT_MDIO_DIR |
+						    BPCTLI_CTRL_EXT_MDIO_DATA |
+						    BPCTLI_CTRL_EXT_MCLK_DATA));
+			else {
+
+				/* To start management : MCLK 1, MDIO 1, output*/
+				BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+						(ctrl_ext | BP10G_MCLK_DATA_OUT
+						 | BP10G_MDIO_DATA_OUT));
+
+			}
+
+			usec_delay(PULSE_TIME);
+			if (pbpctl_dev->bp_10g9) {
+
+				/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~(BP10G_MCLK_DATA_OUT9))); */
+				/* DATA 1 CLK 0 */
+				BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+						ctrl_ext |
+						BP10G_MDIO_DATA_OUT9);
+				BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+						(ctrl | BP10G_MCLK_DIR_OUT9) &
+						~BP10G_MCLK_DATA_OUT9);
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR5 |
+						     BPCTLI_CTRL_EXT_MDIO_DIR5 |
+						     BPCTLI_CTRL_EXT_MDIO_DATA5)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MCLK_DATA5)));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
+								      BPCTLI_CTRL_EXT_MDIO_DIR80
+								      |
+								      BPCTLI_CTRL_EXT_MDIO_DATA80));
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl |
+						     BPCTLI_CTRL_EXT_MCLK_DIR80)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MCLK_DATA80)));
+
+			} else if (pbpctl_dev->bp_540) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						(ctrl | BP540_MDIO_DIR |
+						 BP540_MDIO_DATA |
+						 BP540_MCLK_DIR) &
+						~(BP540_MCLK_DATA));
+
+			} else if (pbpctl_dev->bp_10gb) {
+
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+						 (ctrl_ext | BP10GB_MDIO_SET |
+						  BP10GB_MCLK_CLR) &
+						 ~(BP10GB_MCLK_DIR |
+						   BP10GB_MDIO_DIR |
+						   BP10GB_MDIO_CLR |
+						   BP10GB_MCLK_SET));
+
+			} else if (!pbpctl_dev->bp_10g)
+
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR |
+						     BPCTLI_CTRL_EXT_MDIO_DIR |
+						     BPCTLI_CTRL_EXT_MDIO_DATA)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MCLK_DATA)));
+			else {
+
+				BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+						((ctrl_ext |
+						  BP10G_MDIO_DATA_OUT) &
+						 ~(BP10G_MCLK_DATA_OUT)));
+			}
+
+			usec_delay(PULSE_TIME);
+
+		} else {
+			if (pbpctl_dev->bp_10g9) {
+				/* DATA 0 CLK 1 */
+				/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */
+				BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+						(ctrl_ext &
+						 ~BP10G_MDIO_DATA_OUT9));
+				BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+						(ctrl | BP10G_MCLK_DATA_OUT9 |
+						 BP10G_MCLK_DIR_OUT9));
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR5 |
+						     BPCTLI_CTRL_EXT_MDIO_DIR5 |
+						     BPCTLI_CTRL_EXT_MCLK_DATA5)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MDIO_DATA5)));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MDIO_DIR80)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MDIO_DATA80)));
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   (ctrl |
+						    BPCTLI_CTRL_EXT_MCLK_DIR80 |
+						    BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+			} else if (pbpctl_dev->bp_540) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP540_MCLK_DIR |
+						  BP540_MCLK_DATA |
+						  BP540_MDIO_DIR) &
+						 ~(BP540_MDIO_DATA)));
+
+			} else if (pbpctl_dev->bp_10gb) {
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+						 (ctrl_ext | BP10GB_MDIO_CLR |
+						  BP10GB_MCLK_SET) &
+						 ~(BP10GB_MCLK_DIR |
+						   BP10GB_MDIO_DIR |
+						   BP10GB_MDIO_SET |
+						   BP10GB_MCLK_CLR));
+
+			} else if (!pbpctl_dev->bp_10g)
+
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR |
+						     BPCTLI_CTRL_EXT_MDIO_DIR |
+						     BPCTLI_CTRL_EXT_MCLK_DATA)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MDIO_DATA)));
+			else {
+
+				BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+						((ctrl_ext |
+						  BP10G_MCLK_DATA_OUT) &
+						 ~BP10G_MDIO_DATA_OUT));
+
+			}
+			usec_delay(PULSE_TIME);
+			if (pbpctl_dev->bp_10g9) {
+				/* DATA 0 CLK 0 */
+				/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+				BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+						(ctrl_ext &
+						 ~BP10G_MDIO_DATA_OUT9));
+				BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+						((ctrl | BP10G_MCLK_DIR_OUT9) &
+						 ~(BP10G_MCLK_DATA_OUT9)));
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR5 |
+						     BPCTLI_CTRL_EXT_MDIO_DIR5)
+						    &
+						    ~(BPCTLI_CTRL_EXT_MCLK_DATA5
+						      |
+						      BPCTLI_CTRL_EXT_MDIO_DATA5)));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MDIO_DIR80)
+						    &
+						    ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl |
+						     BPCTLI_CTRL_EXT_MCLK_DIR80)
+						    &
+						    ~
+						    (BPCTLI_CTRL_EXT_MCLK_DATA80)));
+
+			} else if (pbpctl_dev->bp_540) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP540_MCLK_DIR |
+						  BP540_MDIO_DIR) &
+						 ~(BP540_MDIO_DATA |
+						   BP540_MCLK_DATA)));
+			} else if (pbpctl_dev->bp_10gb) {
+
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+						 (ctrl_ext | BP10GB_MDIO_CLR |
+						  BP10GB_MCLK_CLR) &
+						 ~(BP10GB_MCLK_DIR |
+						   BP10GB_MDIO_DIR |
+						   BP10GB_MDIO_SET |
+						   BP10GB_MCLK_SET));
+
+			} else if (!pbpctl_dev->bp_10g)
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl_ext |
+						     BPCTLI_CTRL_EXT_MCLK_DIR |
+						     BPCTLI_CTRL_EXT_MDIO_DIR) &
+						    ~(BPCTLI_CTRL_EXT_MCLK_DATA
+						      |
+						      BPCTLI_CTRL_EXT_MDIO_DATA)));
+			else {
+
+				BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+						(ctrl_ext &
+						 ~(BP10G_MCLK_DATA_OUT |
+						   BP10G_MDIO_DATA_OUT)));
+			}
+
+			usec_delay(PULSE_TIME);
+		}
+
+	}
+}
+
+static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext,
+		      unsigned char len)
+{
+	unsigned char ctrl_val = 0;
+	unsigned int i = len;
+	unsigned int ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_c = NULL;
+
+	if (pbpctl_dev->bp_i80)
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	if (pbpctl_dev->bp_540)
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+	if (pbpctl_dev->bp_10g9) {
+		if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev)))
+			return -1;
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+	}
+
+
+	while (i--) {
+		if (pbpctl_dev->bp_10g9) {
+			/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~BP10G_MCLK_DATA_OUT9)); */
+			/* DATA ? CLK 0 */
+			BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+					((ctrl | BP10G_MCLK_DIR_OUT9) &
+					 ~(BP10G_MCLK_DATA_OUT9)));
+
+		} else if (pbpctl_dev->bp_fiber5) {
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+							       BPCTLI_CTRL_EXT_MCLK_DIR5)
+							      &
+							      ~
+							      (BPCTLI_CTRL_EXT_MDIO_DIR5
+							       |
+							       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+
+		} else if (pbpctl_dev->bp_i80) {
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+					   (ctrl_ext &
+					    ~BPCTLI_CTRL_EXT_MDIO_DIR80));
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+					   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80)
+					    & ~(BPCTLI_CTRL_EXT_MCLK_DATA80)));
+
+		} else if (pbpctl_dev->bp_540) {
+			BP10G_WRITE_REG(pbpctl_dev, ESDP,
+					((ctrl | BP540_MCLK_DIR) &
+					 ~(BP540_MDIO_DIR | BP540_MCLK_DATA)));
+
+		} else if (pbpctl_dev->bp_10gb) {
+
+			BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+					 (ctrl_ext | BP10GB_MDIO_DIR |
+					  BP10GB_MCLK_CLR) & ~(BP10GB_MCLK_DIR |
+							       BP10GB_MDIO_CLR |
+							       BP10GB_MDIO_SET |
+							       BP10GB_MCLK_SET));
+
+		} else if (!pbpctl_dev->bp_10g)
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+								   BPCTLI_CTRL_EXT_MCLK_DIR)
+								  &
+								  ~
+								  (BPCTLI_CTRL_EXT_MDIO_DIR
+								   |
+								   BPCTLI_CTRL_EXT_MCLK_DATA)));
+		else {
+
+			BP10G_WRITE_REG(pbpctl_dev, EODSDP, ((ctrl_ext | BP10G_MDIO_DATA_OUT) & ~BP10G_MCLK_DATA_OUT));	/* ? */
+			/*    printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP);); */
+
+		}
+
+		usec_delay(PULSE_TIME);
+		if (pbpctl_dev->bp_10g9) {
+			/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
+			/* DATA ? CLK 1 */
+			BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+					(ctrl | BP10G_MCLK_DATA_OUT9 |
+					 BP10G_MCLK_DIR_OUT9));
+
+		} else if (pbpctl_dev->bp_fiber5) {
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+							       BPCTLI_CTRL_EXT_MCLK_DIR5
+							       |
+							       BPCTLI_CTRL_EXT_MCLK_DATA5)
+							      &
+							      ~
+							      (BPCTLI_CTRL_EXT_MDIO_DIR5)));
+
+		} else if (pbpctl_dev->bp_i80) {
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+					   (ctrl_ext &
+					    ~(BPCTLI_CTRL_EXT_MDIO_DIR80)));
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+					   (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
+					    BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+		} else if (pbpctl_dev->bp_540) {
+			BP10G_WRITE_REG(pbpctl_dev, ESDP,
+					((ctrl | BP540_MCLK_DIR |
+					  BP540_MCLK_DATA) &
+					 ~(BP540_MDIO_DIR)));
+
+		} else if (pbpctl_dev->bp_10gb) {
+			BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+					 (ctrl_ext | BP10GB_MDIO_DIR |
+					  BP10GB_MCLK_SET) & ~(BP10GB_MCLK_DIR |
+							       BP10GB_MDIO_CLR |
+							       BP10GB_MDIO_SET |
+							       BP10GB_MCLK_CLR));
+
+		} else if (!pbpctl_dev->bp_10g)
+			BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+								   BPCTLI_CTRL_EXT_MCLK_DIR
+								   |
+								   BPCTLI_CTRL_EXT_MCLK_DATA)
+								  &
+								  ~
+								  (BPCTLI_CTRL_EXT_MDIO_DIR)));
+		else {
+
+			BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+					(ctrl_ext | BP10G_MCLK_DATA_OUT |
+					 BP10G_MDIO_DATA_OUT));
+
+		}
+		if (pbpctl_dev->bp_10g9) {
+			ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
+
+		} else if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_i80)) {
+			ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		} else if (pbpctl_dev->bp_540) {
+			ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
+		} else if (pbpctl_dev->bp_10gb)
+			ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+
+		else if (!pbpctl_dev->bp_10g)
+			ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		else
+			ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
+
+		usec_delay(PULSE_TIME);
+		if (pbpctl_dev->bp_10g9) {
+			if (ctrl_ext & BP10G_MDIO_DATA_IN9)
+				ctrl_val |= 1 << i;
+
+		} else if (pbpctl_dev->bp_fiber5) {
+			if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA5)
+				ctrl_val |= 1 << i;
+		} else if (pbpctl_dev->bp_i80) {
+			if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA80)
+				ctrl_val |= 1 << i;
+		} else if (pbpctl_dev->bp_540) {
+			if (ctrl_ext & BP540_MDIO_DATA)
+				ctrl_val |= 1 << i;
+		} else if (pbpctl_dev->bp_10gb) {
+			if (ctrl_ext & BP10GB_MDIO_DATA)
+				ctrl_val |= 1 << i;
+
+		} else if (!pbpctl_dev->bp_10g) {
+
+			if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA)
+				ctrl_val |= 1 << i;
+		} else {
+
+			if (ctrl_ext & BP10G_MDIO_DATA_IN)
+				ctrl_val |= 1 << i;
+		}
+
+	}
+
+	return ctrl_val;
+}
+
+static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value,
+		      unsigned char addr)
+{
+	uint32_t ctrl_ext = 0, ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_c = NULL;
+	unsigned long flags;
+	if (pbpctl_dev->bp_10g9) {
+		if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev)))
+			return;
+	}
+	if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) &&
+	    (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER))
+		wdt_time_left(pbpctl_dev);
+
+#ifdef BP_SYNC_FLAG
+	spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 1);
+#endif
+	if (pbpctl_dev->bp_10g9) {
+
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+		/* DATA 0 CLK 0 */
+		/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+	} else if (pbpctl_dev->bp_540) {
+		ctrl = ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
+						    BP540_MDIO_DIR |
+						    BP540_MCLK_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+
+	} else if (!pbpctl_dev->bp_10g) {
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)));
+	} else {
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+	}
+	usec_delay(CMND_INTERVAL);
+
+	/*send sync cmd */
+	write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN);
+	/*send wr cmd */
+	write_pulse(pbpctl_dev, ctrl_ext, WR_CMD_VAL, WR_CMD_LEN);
+	write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN);
+
+	/*write data */
+	write_pulse(pbpctl_dev, ctrl_ext, value, WR_DATA_LEN);
+	if (pbpctl_dev->bp_10g9) {
+		/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		/* DATA 0 CLK 0 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+	} else if (pbpctl_dev->bp_540) {
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
+						    BP540_MDIO_DIR |
+						    BP540_MCLK_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+	} else if (pbpctl_dev->bp_10gb) {
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+
+	} else if (!pbpctl_dev->bp_10g)
+
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)));
+	else {
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+
+	}
+
+	usec_delay(CMND_INTERVAL * 4);
+
+	if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) &&
+	    (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER) && (addr == CMND_REG_ADDR))
+		pbpctl_dev->bypass_wdt_on_time = jiffies;
+#ifdef BP_SYNC_FLAG
+	spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 0);
+#endif
+
+}
+
+static void write_data(bpctl_dev_t *pbpctl_dev, unsigned char value)
+{
+	write_reg(pbpctl_dev, value, CMND_REG_ADDR);
+}
+
+static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr)
+{
+	uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0;
+	bpctl_dev_t *pbpctl_dev_c = NULL;
+
+#ifdef BP_SYNC_FLAG
+	unsigned long flags;
+	spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 1);
+#endif
+	if (pbpctl_dev->bp_10g9) {
+		if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev)))
+			return -1;
+	}
+
+	if (pbpctl_dev->bp_10g9) {
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+
+		/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		/* DATA 0 CLK 0 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+	} else if (pbpctl_dev->bp_540) {
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
+						    BP540_MDIO_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+#if 0
+
+		/*BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, (ctrl_ext | BP10GB_MCLK_DIR | BP10GB_MDIO_DIR|
+		   BP10GB_MCLK_CLR|BP10GB_MDIO_CLR));
+		   ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+		   printk("1reg=%x\n", ctrl_ext); */
+
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, ((ctrl_ext |
+							      BP10GB_MCLK_SET |
+							      BP10GB_MDIO_CLR))
+				 & ~(BP10GB_MCLK_CLR | BP10GB_MDIO_SET |
+				     BP10GB_MCLK_DIR | BP10GB_MDIO_DIR));
+
+		/*   bnx2x_set_spio(pbpctl_dev, 5, MISC_REGISTERS_SPIO_OUTPUT_LOW);
+		   bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_OUTPUT_LOW);
+		   bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_INPUT_HI_Z); */
+
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+
+		printk("2reg=%x\n", ctrl_ext);
+
+#ifdef BP_SYNC_FLAG
+		spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+		atomic_set(&pbpctl_dev->wdt_busy, 0);
+#endif
+
+		return 0;
+
+#endif
+
+	} else if (!pbpctl_dev->bp_10g) {
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)));
+	} else {
+
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+
+	}
+
+	usec_delay(CMND_INTERVAL);
+
+	/*send sync cmd */
+	write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN);
+	/*send rd cmd */
+	write_pulse(pbpctl_dev, ctrl_ext, RD_CMD_VAL, RD_CMD_LEN);
+	/*send addr */
+	write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN);
+	/*read data */
+	/* zero */
+	if (pbpctl_dev->bp_10g9) {
+		/* DATA 0 CLK 1 */
+		/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext | BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				(ctrl | BP10G_MCLK_DATA_OUT9 |
+				 BP10G_MCLK_DIR_OUT9));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DATA5)));
+
+	} else if (pbpctl_dev->bp_i80) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+				   (ctrl_ext &
+				    ~(BPCTLI_CTRL_EXT_MDIO_DATA80 |
+				      BPCTLI_CTRL_EXT_MDIO_DIR80)));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
+				    BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+	} else if (pbpctl_dev->bp_540) {
+		BP10G_WRITE_REG(pbpctl_dev, ESDP,
+				(((ctrl | BP540_MDIO_DIR | BP540_MCLK_DIR |
+				   BP540_MCLK_DATA) & ~BP540_MDIO_DATA)));
+
+	} else if (pbpctl_dev->bp_10gb) {
+
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_DIR | BP10GB_MCLK_SET)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_SET |
+				     BP10GB_MDIO_CLR | BP10GB_MCLK_CLR));
+
+	} else if (!pbpctl_dev->bp_10g)
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DATA)));
+	else {
+
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext | BP10G_MCLK_DATA_OUT |
+				 BP10G_MDIO_DATA_OUT));
+
+
+	}
+	usec_delay(PULSE_TIME);
+
+	ctrl_value = read_pulse(pbpctl_dev, ctrl_ext, RD_DATA_LEN);
+
+	if (pbpctl_dev->bp_10g9) {
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+
+		/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		/* DATA 0 CLK 0 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+	} else if (pbpctl_dev->bp_540) {
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
+						    BP540_MDIO_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+
+	} else if (!pbpctl_dev->bp_10g) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)));
+	} else {
+
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+
+	}
+
+	usec_delay(CMND_INTERVAL * 4);
+#ifdef BP_SYNC_FLAG
+	spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 0);
+#endif
+
+	return ctrl_value;
+}
+
+static int wdt_pulse(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0, ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_c = NULL;
+
+#ifdef BP_SYNC_FLAG
+	unsigned long flags;
+
+	spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+
+	if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
+		return -1;
+#endif
+	if (pbpctl_dev->bp_10g9) {
+		if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev)))
+			return -1;
+	}
+
+	if (pbpctl_dev->bp_10g9) {
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
+		ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
+
+		/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		/* DATA 0 CLK 0 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+	} else if (pbpctl_dev->bp_540) {
+		ctrl_ext = ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
+						    BP540_MDIO_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+
+	} else if (!pbpctl_dev->bp_10g) {
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)));
+	} else {
+
+		ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+		ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+
+	}
+	if (pbpctl_dev->bp_10g9) {
+		/*   BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */
+		/* DATA 0 CLK 1 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				(ctrl | BP10G_MCLK_DATA_OUT9 |
+				 BP10G_MCLK_DIR_OUT9));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MCLK_DATA5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MDIO_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
+				    BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+	} else if (pbpctl_dev->bp_540) {
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
+						    BP540_MDIO_DIR |
+						    BP540_MCLK_DIR |
+						    BP540_MCLK_DATA) &
+						   ~BP540_MDIO_DATA));
+
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_SET)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_CLR));
+
+	} else if (!pbpctl_dev->bp_10g)
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MCLK_DATA)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MDIO_DATA)));
+	else {
+
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				((ctrl_ext | BP10G_MCLK_DATA_OUT) &
+				 ~BP10G_MDIO_DATA_OUT));
+
+	}
+
+	usec_delay(WDT_INTERVAL);
+	if (pbpctl_dev->bp_10g9) {
+		/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
+		/* DATA 0 CLK 0 */
+		BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
+				(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
+		BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
+				((ctrl | BP10G_MCLK_DIR_OUT9) &
+				 ~(BP10G_MCLK_DATA_OUT9)));
+
+	} else if (pbpctl_dev->bp_fiber5) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MCLK_DIR5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DIR5)
+						      &
+						      ~
+						      (BPCTLI_CTRL_EXT_MCLK_DATA5
+						       |
+						       BPCTLI_CTRL_EXT_MDIO_DATA5)));
+	} else if (pbpctl_dev->bp_i80) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
+						       BPCTLI_CTRL_EXT_MDIO_DIR80)
+						      &
+						      ~BPCTLI_CTRL_EXT_MDIO_DATA80));
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+				   ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
+				    ~BPCTLI_CTRL_EXT_MCLK_DATA80));
+
+	} else if (pbpctl_dev->bp_540) {
+		BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
+						    BP540_MDIO_DIR) &
+						   ~(BP540_MDIO_DATA |
+						     BP540_MCLK_DATA)));
+
+	} else if (pbpctl_dev->bp_10gb) {
+		ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
+		BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
+				 (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
+				 & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
+				     BP10GB_MDIO_SET | BP10GB_MCLK_SET));
+
+	} else if (!pbpctl_dev->bp_10g)
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MCLK_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DATA)));
+	else {
+
+		BP10G_WRITE_REG(pbpctl_dev, EODSDP,
+				(ctrl_ext &
+				 ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
+	}
+	if ((pbpctl_dev->wdt_status == WDT_STATUS_EN)	/*&&
+							   (pbpctl_dev->bp_ext_ver<PXG4BPFI_VER) */ )
+		pbpctl_dev->bypass_wdt_on_time = jiffies;
+#ifdef BP_SYNC_FLAG
+	spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#endif
+	usec_delay(CMND_INTERVAL * 4);
+	return 0;
+}
+
+static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value)
+{
+
+	uint32_t ctrl_ext = 0;
+#ifdef BP_SYNC_FLAG
+	unsigned long flags;
+#endif
+	wdt_time_left(pbpctl_dev);
+#ifdef BP_SYNC_FLAG
+	spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 1);
+#endif
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+						   BPCTLI_CTRL_EXT_SDP6_DIR |
+						   BPCTLI_CTRL_EXT_SDP7_DIR) &
+						  ~(BPCTLI_CTRL_EXT_SDP6_DATA |
+						    BPCTLI_CTRL_EXT_SDP7_DATA)));
+
+	usec_delay(INIT_CMND_INTERVAL);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+						   BPCTLI_CTRL_EXT_SDP6_DIR |
+						   BPCTLI_CTRL_EXT_SDP7_DIR |
+						   BPCTLI_CTRL_EXT_SDP6_DATA) &
+						  ~
+						  (BPCTLI_CTRL_EXT_SDP7_DATA)));
+	usec_delay(INIT_CMND_INTERVAL);
+
+	while (value) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
+				   BPCTLI_CTRL_EXT_SDP6_DIR |
+				   BPCTLI_CTRL_EXT_SDP7_DIR |
+				   BPCTLI_CTRL_EXT_SDP6_DATA |
+				   BPCTLI_CTRL_EXT_SDP7_DATA);
+		usec_delay(PULSE_INTERVAL);
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_SDP6_DIR
+							   |
+							   BPCTLI_CTRL_EXT_SDP7_DIR
+							   |
+							   BPCTLI_CTRL_EXT_SDP6_DATA)
+							  &
+							  ~BPCTLI_CTRL_EXT_SDP7_DATA));
+		usec_delay(PULSE_INTERVAL);
+		value--;
+
+	}
+	usec_delay(INIT_CMND_INTERVAL - PULSE_INTERVAL);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+						   BPCTLI_CTRL_EXT_SDP6_DIR |
+						   BPCTLI_CTRL_EXT_SDP7_DIR) &
+						  ~(BPCTLI_CTRL_EXT_SDP6_DATA |
+						    BPCTLI_CTRL_EXT_SDP7_DATA)));
+	usec_delay(WDT_TIME_CNT);
+	if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
+		pbpctl_dev->bypass_wdt_on_time = jiffies;
+#ifdef BP_SYNC_FLAG
+	spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+	atomic_set(&pbpctl_dev->wdt_busy, 0);
+#endif
+
+}
+
+static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+
+#ifdef BP_SYNC_FLAG
+	unsigned long flags;
+
+	spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
+#else
+
+	if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
+		return -1;
+#endif
+	wdt_time_left(pbpctl_dev);
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |	/* 1 */
+			   BPCTLI_CTRL_EXT_SDP7_DIR |
+			   BPCTLI_CTRL_EXT_SDP7_DATA);
+	usec_delay(PULSE_INTERVAL);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |	/* 0 */
+						   BPCTLI_CTRL_EXT_SDP7_DIR) &
+						  ~BPCTLI_CTRL_EXT_SDP7_DATA));
+
+	usec_delay(PULSE_INTERVAL);
+	if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
+		pbpctl_dev->bypass_wdt_on_time = jiffies;
+#ifdef BP_SYNC_FLAG
+	spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
+#endif
+
+	return 0;
+}
+
+void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value)
+{
+	uint32_t ctrl_ext = 0;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |	/* 0 */
+						   BPCTLI_CTRL_EXT_SDP6_DIR) &
+						  ~BPCTLI_CTRL_EXT_SDP6_DATA));
+
+	usec_delay(PULSE_INTERVAL);
+	while (value) {
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |	/* 1 */
+				   BPCTLI_CTRL_EXT_SDP6_DIR |
+				   BPCTLI_CTRL_EXT_SDP6_DATA);
+		usec_delay(PULSE_INTERVAL);
+		value--;
+	}
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |	/* 0 */
+						   BPCTLI_CTRL_EXT_SDP6_DIR) &
+						  ~BPCTLI_CTRL_EXT_SDP6_DATA));
+	usec_delay(PULSE_INTERVAL);
+}
+
+/*  #endif  OLD_FW */
+#ifdef BYPASS_DEBUG
+
+int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter)
+{
+	uint32_t ctrl_ext = 0;
+
+	if (!pbpctl_dev)
+		return -1;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter);
+
+	pbpctl_dev->bypass_wdt_status = 0;
+	if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+		write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter);
+	} else {
+		wdt_time_left(pbpctl_dev);
+		if (pbpctl_dev->wdt_status == WDT_STATUS_EN) {
+			pbpctl_dev->wdt_status = 0;
+			data_pulse(pbpctl_dev, counter);
+			pbpctl_dev->wdt_status = WDT_STATUS_EN;
+			pbpctl_dev->bypass_wdt_on_time = jiffies;
+
+		} else
+			data_pulse(pbpctl_dev, counter);
+	}
+
+	return 0;
+}
+
+int zero_set_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0, ctrl_value = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+		printk("zero_set");
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+
+		BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+							   BPCTLI_CTRL_EXT_MCLK_DIR)
+							  &
+							  ~
+							  (BPCTLI_CTRL_EXT_MCLK_DATA
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DIR
+							   |
+							   BPCTLI_CTRL_EXT_MDIO_DATA)));
+
+	}
+	return ctrl_value;
+}
+
+int pulse_get2_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0, ctrl_value = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+		printk("pulse_get_fn\n");
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		ctrl_value = read_pulse_2(pbpctl_dev, ctrl_ext);
+		printk("read:%d\n", ctrl_value);
+	}
+	return ctrl_value;
+}
+
+int pulse_get1_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0, ctrl_value = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+
+		printk("pulse_get_fn\n");
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		ctrl_value = read_pulse_1(pbpctl_dev, ctrl_ext);
+		printk("read:%d\n", ctrl_value);
+	}
+	return ctrl_value;
+}
+
+int gpio6_set_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
+			   BPCTLI_CTRL_EXT_SDP6_DIR |
+			   BPCTLI_CTRL_EXT_SDP6_DATA);
+	return 0;
+}
+
+int gpio7_set_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
+			   BPCTLI_CTRL_EXT_SDP7_DIR |
+			   BPCTLI_CTRL_EXT_SDP7_DATA);
+	return 0;
+}
+
+int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+						   BPCTLI_CTRL_EXT_SDP7_DIR) &
+						  ~BPCTLI_CTRL_EXT_SDP7_DATA));
+	return 0;
+}
+
+int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+
+	ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
+						   BPCTLI_CTRL_EXT_SDP6_DIR) &
+						  ~BPCTLI_CTRL_EXT_SDP6_DATA));
+	return 0;
+}
+#endif				/*BYPASS_DEBUG */
+
+static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int idx_dev = 0;
+
+	if (pbpctl_dev == NULL)
+		return NULL;
+
+	if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) {
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus)
+			    && (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot)
+			    && ((bpctl_dev_arr[idx_dev].func == 1)
+				&& (pbpctl_dev->func == 0))) {
+
+				return &(bpctl_dev_arr[idx_dev]);
+			}
+			if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) &&
+			    (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) &&
+			    ((bpctl_dev_arr[idx_dev].func == 3)
+			     && (pbpctl_dev->func == 2))) {
+
+				return &(bpctl_dev_arr[idx_dev]);
+			}
+		}
+	}
+	return NULL;
+}
+
+static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int idx_dev = 0;
+
+	if (pbpctl_dev == NULL)
+		return NULL;
+
+	if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) {
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus)
+			    && (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot)
+			    && ((bpctl_dev_arr[idx_dev].func == 0)
+				&& (pbpctl_dev->func == 1))) {
+
+				return &(bpctl_dev_arr[idx_dev]);
+			}
+			if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) &&
+			    (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) &&
+			    ((bpctl_dev_arr[idx_dev].func == 2)
+			     && (pbpctl_dev->func == 3))) {
+
+				return &(bpctl_dev_arr[idx_dev]);
+			}
+		}
+	}
+	return NULL;
+}
+
+/**************************************/
+/**************INTEL API***************/
+/**************************************/
+
+static void write_data_port_int(bpctl_dev_t *pbpctl_dev,
+				unsigned char ctrl_value)
+{
+	uint32_t value;
+
+	value = BPCTL_READ_REG(pbpctl_dev, CTRL);
+/* Make SDP0 Pin Directonality to Output */
+	value |= BPCTLI_CTRL_SDP0_DIR;
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value);
+
+	value &= ~BPCTLI_CTRL_SDP0_DATA;
+	value |= ((ctrl_value & 0x1) << BPCTLI_CTRL_SDP0_SHIFT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value);
+
+	value = (BPCTL_READ_REG(pbpctl_dev, CTRL_EXT));
+/* Make SDP2 Pin Directonality to Output */
+	value |= BPCTLI_CTRL_EXT_SDP6_DIR;
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value);
+
+	value &= ~BPCTLI_CTRL_EXT_SDP6_DATA;
+	value |= (((ctrl_value & 0x2) >> 1) << BPCTLI_CTRL_EXT_SDP6_SHIFT);
+	BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value);
+
+}
+
+static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+		return -1;
+	atomic_set(&pbpctl_dev->wdt_busy, 1);
+	write_data_port_int(pbpctl_dev, value & 0x3);
+	write_data_port_int(pbpctl_dev_b, ((value & 0xc) >> 2));
+	atomic_set(&pbpctl_dev->wdt_busy, 0);
+
+	return 0;
+}
+
+static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev)
+{
+
+	if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
+		return -1;
+
+	if ((write_data_int(pbpctl_dev, RESET_WDT_INT)) < 0)
+		return -1;
+	msec_delay_bp(CMND_INTERVAL_INT);
+	if ((write_data_int(pbpctl_dev, CMND_OFF_INT)) < 0)
+		return -1;
+	msec_delay_bp(CMND_INTERVAL_INT);
+
+	if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
+		pbpctl_dev->bypass_wdt_on_time = jiffies;
+
+	return 0;
+}
+
+/*************************************/
+/************* COMMANDS **************/
+/*************************************/
+
+/* CMND_ON  0x4 (100)*/
+int cmnd_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+			return 0;
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
+			write_data(pbpctl_dev, CMND_ON);
+		else
+			data_pulse(pbpctl_dev, CMND_ON);
+		ret = 0;
+	}
+	return ret;
+}
+
+/* CMND_OFF  0x2 (10)*/
+int cmnd_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, CMND_OFF_INT);
+			msec_delay_bp(CMND_INTERVAL_INT);
+		} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
+			write_data(pbpctl_dev, CMND_OFF);
+		else
+			data_pulse(pbpctl_dev, CMND_OFF);
+		ret = 0;
+	};
+	return ret;
+}
+
+/* BYPASS_ON (0xa)*/
+int bypass_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & BP_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, BYPASS_ON_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			pbpctl_dev->bp_status_un = 0;
+		} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			write_data(pbpctl_dev, BYPASS_ON);
+			if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+				msec_delay_bp(LATCH_DELAY);
+		} else
+			data_pulse(pbpctl_dev, BYPASS_ON);
+		ret = 0;
+	};
+	return ret;
+}
+
+/* BYPASS_OFF (0x8 111)*/
+int bypass_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & BP_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			pbpctl_dev->bp_status_un = 0;
+		} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			write_data(pbpctl_dev, BYPASS_OFF);
+			if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+				msec_delay_bp(LATCH_DELAY);
+		} else
+			data_pulse(pbpctl_dev, BYPASS_OFF);
+		ret = 0;
+	}
+	return ret;
+}
+
+/* TAP_OFF (0x9)*/
+int tap_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	if ((pbpctl_dev->bp_caps & TAP_CAP)
+	    && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) {
+		write_data(pbpctl_dev, TAP_OFF);
+		msec_delay_bp(LATCH_DELAY);
+		ret = 0;
+	};
+	return ret;
+}
+
+/* TAP_ON (0xb)*/
+int tap_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	if ((pbpctl_dev->bp_caps & TAP_CAP)
+	    && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) {
+		write_data(pbpctl_dev, TAP_ON);
+		msec_delay_bp(LATCH_DELAY);
+		ret = 0;
+	};
+	return ret;
+}
+
+/* DISC_OFF (0x9)*/
+int disc_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
+		write_data(pbpctl_dev, DISC_OFF);
+		msec_delay_bp(LATCH_DELAY);
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+/* DISC_ON (0xb)*/
+int disc_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
+		write_data(pbpctl_dev, /*DISC_ON */ 0x85);
+		msec_delay_bp(LATCH_DELAY);
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+/* DISC_PORT_ON */
+int disc_port_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1) {
+
+			write_data(pbpctl_dev_m, TX_DISA);
+		} else {
+
+			write_data(pbpctl_dev_m, TX_DISB);
+		}
+
+		msec_delay_bp(LATCH_DELAY);
+
+	}
+	return ret;
+}
+
+/* DISC_PORT_OFF */
+int disc_port_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1)
+			write_data(pbpctl_dev_m, TX_ENA);
+		else
+			write_data(pbpctl_dev_m, TX_ENB);
+
+		msec_delay_bp(LATCH_DELAY);
+
+	}
+	return ret;
+}
+
+/*TWO_PORT_LINK_HW_EN (0xe)*/
+int tpl_hw_on(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0, ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
+		cmnd_on(pbpctl_dev);
+		write_data(pbpctl_dev, TPL2_ON);
+		msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		cmnd_off(pbpctl_dev);
+		return ret;
+	}
+
+	if (TPL_IF_SERIES(pbpctl_dev->subdevice)) {
+		ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL);
+		BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL,
+				   ((ctrl | BPCTLI_CTRL_SWDPIO0) &
+				    ~BPCTLI_CTRL_SWDPIN0));
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+/*TWO_PORT_LINK_HW_DIS (0xc)*/
+int tpl_hw_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0, ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+		return BP_NOT_CAP;
+	if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
+		cmnd_on(pbpctl_dev);
+		write_data(pbpctl_dev, TPL2_OFF);
+		msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		cmnd_off(pbpctl_dev);
+		return ret;
+	}
+	if (TPL_IF_SERIES(pbpctl_dev->subdevice)) {
+		ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL);
+		BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL,
+				   (ctrl | BPCTLI_CTRL_SWDPIO0 |
+				    BPCTLI_CTRL_SWDPIN0));
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+/* WDT_OFF (0x6 110)*/
+int wdt_off(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			bypass_off(pbpctl_dev);
+		} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
+			write_data(pbpctl_dev, WDT_OFF);
+		else
+			data_pulse(pbpctl_dev, WDT_OFF);
+		pbpctl_dev->wdt_status = WDT_STATUS_DIS;
+		ret = 0;
+	};
+	return ret;
+}
+
+/* WDT_ON (0x10)*/
+
+/***Global***/
+static unsigned int
+    wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 };
+
+int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout)
+{
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		unsigned int pulse = 0, temp_value = 0, temp_cnt = 0;
+		pbpctl_dev->wdt_status = 0;
+
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			for (; wdt_val_array[temp_cnt]; temp_cnt++)
+				if (timeout <= wdt_val_array[temp_cnt])
+					break;
+
+			if (!wdt_val_array[temp_cnt])
+				temp_cnt--;
+
+			timeout = wdt_val_array[temp_cnt];
+			temp_cnt += 0x7;
+
+			write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			pbpctl_dev->bp_status_un = 0;
+			write_data_int(pbpctl_dev, temp_cnt);
+			pbpctl_dev->bypass_wdt_on_time = jiffies;
+			msec_delay_bp(CMND_INTERVAL_INT);
+			pbpctl_dev->bypass_timer_interval = timeout;
+		} else {
+			timeout =
+			    (timeout <
+			     TIMEOUT_UNIT ? TIMEOUT_UNIT : (timeout >
+							    WDT_TIMEOUT_MAX ?
+							    WDT_TIMEOUT_MAX :
+							    timeout));
+			temp_value = timeout / 100;
+			while ((temp_value >>= 1))
+				temp_cnt++;
+			if (timeout > ((1 << temp_cnt) * 100))
+				temp_cnt++;
+			pbpctl_dev->bypass_wdt_on_time = jiffies;
+			pulse = (WDT_ON | temp_cnt);
+			if (pbpctl_dev->bp_ext_ver == OLD_IF_VER)
+				data_pulse(pbpctl_dev, pulse);
+			else
+				write_data(pbpctl_dev, pulse);
+			pbpctl_dev->bypass_timer_interval =
+			    (1 << temp_cnt) * 100;
+		}
+		pbpctl_dev->wdt_status = WDT_STATUS_EN;
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+{
+	u32 swsm;
+
+	swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
+
+	swsm &= ~(BPCTLI_SWSM_SMBI | BPCTLI_SWSM_SWESMBI);
+
+	BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm);
+}
+
+s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+{
+	u32 swsm;
+	s32 ret_val = 0;
+	s32 timeout = 8192 + 1;
+	s32 i = 0;
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
+		if (!(swsm & BPCTLI_SWSM_SMBI))
+			break;
+
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		printk
+		    ("bpctl_mod: Driver can't access device - SMBI bit is set.\n");
+		ret_val = -1;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
+		BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm | BPCTLI_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (BPCTL_READ_REG(pbpctl_dev, SWSM) & BPCTLI_SWSM_SWESMBI)
+			break;
+
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		bp75_put_hw_semaphore_generic(pbpctl_dev);
+		printk("bpctl_mod: Driver can't access the NVM\n");
+		ret_val = -1;
+		goto out;
+	}
+
+ out:
+	return ret_val;
+}
+
+static void bp75_release_phy(bpctl_dev_t *pbpctl_dev)
+{
+	u16 mask = BPCTLI_SWFW_PHY0_SM;
+	u32 swfw_sync;
+
+	if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3))
+		mask = BPCTLI_SWFW_PHY1_SM;
+
+	while (bp75_get_hw_semaphore_generic(pbpctl_dev) != 0) ;
+	/* Empty */
+
+	swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync);
+
+	bp75_put_hw_semaphore_generic(pbpctl_dev);
+}
+
+static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev)
+{
+	u16 mask = BPCTLI_SWFW_PHY0_SM;
+	u32 swfw_sync;
+	u32 swmask;
+	u32 fwmask;
+	s32 ret_val = 0;
+	s32 i = 0, timeout = 200;
+
+	if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3))
+		mask = BPCTLI_SWFW_PHY1_SM;
+
+	swmask = mask;
+	fwmask = mask << 16;
+
+	while (i < timeout) {
+		if (bp75_get_hw_semaphore_generic(pbpctl_dev)) {
+			ret_val = -1;
+			goto out;
+		}
+
+		swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		bp75_put_hw_semaphore_generic(pbpctl_dev);
+		mdelay(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		printk
+		    ("bpctl_mod: Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -1;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync);
+
+	bp75_put_hw_semaphore_generic(pbpctl_dev);
+
+ out:
+	return ret_val;
+}
+
+s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+{
+	u32 i, mdic = 0;
+	s32 ret_val = 0;
+	u32 phy_addr = 1;
+
+	mdic = ((offset << BPCTLI_MDIC_REG_SHIFT) |
+		(phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_READ));
+
+	BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic);
+
+	for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = BPCTL_READ_REG(pbpctl_dev, MDIC);
+		if (mdic & BPCTLI_MDIC_READY)
+			break;
+	}
+	if (!(mdic & BPCTLI_MDIC_READY)) {
+		printk("bpctl_mod: MDI Read did not complete\n");
+		ret_val = -1;
+		goto out;
+	}
+	if (mdic & BPCTLI_MDIC_ERROR) {
+		printk("bpctl_mod: MDI Error\n");
+		ret_val = -1;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+ out:
+	return ret_val;
+}
+
+s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+{
+	u32 i, mdic = 0;
+	s32 ret_val = 0;
+	u32 phy_addr = 1;
+
+	mdic = (((u32) data) |
+		(offset << BPCTLI_MDIC_REG_SHIFT) |
+		(phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_WRITE));
+
+	BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic);
+
+	for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = BPCTL_READ_REG(pbpctl_dev, MDIC);
+		if (mdic & BPCTLI_MDIC_READY)
+			break;
+	}
+	if (!(mdic & BPCTLI_MDIC_READY)) {
+		printk("bpctl_mod: MDI Write did not complete\n");
+		ret_val = -1;
+		goto out;
+	}
+	if (mdic & BPCTLI_MDIC_ERROR) {
+		printk("bpctl_mod: MDI Error\n");
+		ret_val = -1;
+		goto out;
+	}
+
+ out:
+	return ret_val;
+}
+
+static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+{
+	s32 ret_val = 0;
+
+	ret_val = bp75_acquire_phy(pbpctl_dev);
+	if (ret_val)
+		goto out;
+
+	if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = bp75_write_phy_reg_mdic(pbpctl_dev,
+						  BPCTLI_IGP01E1000_PHY_PAGE_SELECT,
+						  (u16) offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val =
+	    bp75_read_phy_reg_mdic(pbpctl_dev,
+				   BPCTLI_MAX_PHY_REG_ADDRESS & offset, data);
+
+ release:
+	bp75_release_phy(pbpctl_dev);
+ out:
+	return ret_val;
+}
+
+static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+{
+	s32 ret_val = 0;
+
+	ret_val = bp75_acquire_phy(pbpctl_dev);
+	if (ret_val)
+		goto out;
+
+	if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = bp75_write_phy_reg_mdic(pbpctl_dev,
+						  BPCTLI_IGP01E1000_PHY_PAGE_SELECT,
+						  (u16) offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val =
+	    bp75_write_phy_reg_mdic(pbpctl_dev,
+				    BPCTLI_MAX_PHY_REG_ADDRESS & offset, data);
+
+ release:
+	bp75_release_phy(pbpctl_dev);
+
+ out:
+	return ret_val;
+}
+
+/* SET_TX  (non-Bypass command :)) */
+static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state)
+{
+	int ret = 0, ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		if (!tx_state) {
+			if (pbpctl_dev->bp_540) {
+				ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						(ctrl | BP10G_SDP1_DIR |
+						 BP10G_SDP1_DATA));
+
+			} else {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   (ctrl | BPCTLI_CTRL_SDP1_DIR
+						    | BPCTLI_CTRL_SWDPIN1));
+			}
+		} else {
+			if (pbpctl_dev->bp_540) {
+				ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP10G_SDP1_DIR) &
+						 ~BP10G_SDP1_DATA));
+			} else {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl |
+						     BPCTLI_CTRL_SDP1_DIR) &
+						    ~BPCTLI_CTRL_SWDPIN1));
+			}
+			return ret;
+
+		}
+	} else if (pbpctl_dev->bp_caps & TX_CTL_CAP) {
+		if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) {
+			if (tx_state) {
+				uint16_t mii_reg;
+				if (!
+				    (ret =
+				     bp75_read_phy_reg(pbpctl_dev,
+						       BPCTLI_PHY_CONTROL,
+						       &mii_reg))) {
+					if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) {
+						ret =
+						    bp75_write_phy_reg
+						    (pbpctl_dev,
+						     BPCTLI_PHY_CONTROL,
+						     mii_reg &
+						     ~BPCTLI_MII_CR_POWER_DOWN);
+					}
+				}
+			} else {
+				uint16_t mii_reg;
+				if (!
+				    (ret =
+				     bp75_read_phy_reg(pbpctl_dev,
+						       BPCTLI_PHY_CONTROL,
+						       &mii_reg))) {
+
+					mii_reg |= BPCTLI_MII_CR_POWER_DOWN;
+					ret =
+					    bp75_write_phy_reg(pbpctl_dev,
+							       BPCTLI_PHY_CONTROL,
+							       mii_reg);
+				}
+			}
+
+		}
+		if (pbpctl_dev->bp_fiber5) {
+			ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+
+		} else if (pbpctl_dev->bp_10gb)
+			ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO);
+
+		else if (!pbpctl_dev->bp_10g)
+			ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		else
+			ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+
+		if (!tx_state)
+			if (pbpctl_dev->bp_10g9) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						(ctrl | BP10G_SDP3_DATA |
+						 BP10G_SDP3_DIR));
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   (ctrl |
+						    BPCTLI_CTRL_EXT_SDP6_DIR |
+						    BPCTLI_CTRL_EXT_SDP6_DATA));
+
+			} else if (pbpctl_dev->bp_10gb) {
+				if ((pbpctl_dev->func == 1)
+				    || (pbpctl_dev->func == 3))
+					BP10GB_WRITE_REG(pbpctl_dev,
+							 MISC_REG_GPIO,
+							 (ctrl |
+							  BP10GB_GPIO0_SET_P1) &
+							 ~(BP10GB_GPIO0_CLR_P1 |
+							   BP10GB_GPIO0_OE_P1));
+				else
+					BP10GB_WRITE_REG(pbpctl_dev,
+							 MISC_REG_GPIO,
+							 (ctrl |
+							  BP10GB_GPIO0_OE_P0 |
+							  BP10GB_GPIO0_SET_P0));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   (ctrl | BPCTLI_CTRL_SDP1_DIR
+						    | BPCTLI_CTRL_SWDPIN1));
+
+			} else if (pbpctl_dev->bp_540) {
+				ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						(ctrl | BP10G_SDP1_DIR |
+						 BP10G_SDP1_DATA));
+
+			}
+
+			else if (!pbpctl_dev->bp_10g)
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   (ctrl | BPCTLI_CTRL_SWDPIO0 |
+						    BPCTLI_CTRL_SWDPIN0));
+
+			else
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						(ctrl | BP10G_SDP0_DATA |
+						 BP10G_SDP0_DIR));
+
+		else {
+			if (pbpctl_dev->bp_10g9) {
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP10G_SDP3_DIR) &
+						 ~BP10G_SDP3_DATA));
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
+						   ((ctrl |
+						     BPCTLI_CTRL_EXT_SDP6_DIR) &
+						    ~BPCTLI_CTRL_EXT_SDP6_DATA));
+
+			} else if (pbpctl_dev->bp_10gb) {
+				if ((bpctl_dev_arr->func == 1)
+				    || (bpctl_dev_arr->func == 3))
+					BP10GB_WRITE_REG(pbpctl_dev,
+							 MISC_REG_GPIO,
+							 (ctrl |
+							  BP10GB_GPIO0_CLR_P1) &
+							 ~(BP10GB_GPIO0_SET_P1 |
+							   BP10GB_GPIO0_OE_P1));
+				else
+					BP10GB_WRITE_REG(pbpctl_dev,
+							 MISC_REG_GPIO,
+							 (ctrl |
+							  BP10GB_GPIO0_OE_P0 |
+							  BP10GB_GPIO0_CLR_P0));
+
+			} else if (pbpctl_dev->bp_i80) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl |
+						     BPCTLI_CTRL_SDP1_DIR) &
+						    ~BPCTLI_CTRL_SWDPIN1));
+			} else if (pbpctl_dev->bp_540) {
+				ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP10G_SDP1_DIR) &
+						 ~BP10G_SDP1_DATA));
+			}
+
+			else if (!pbpctl_dev->bp_10g) {
+				BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+						   ((ctrl | BPCTLI_CTRL_SWDPIO0)
+						    & ~BPCTLI_CTRL_SWDPIN0));
+				if (!PEGF_IF_SERIES(pbpctl_dev->subdevice)) {
+					BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
+							   (ctrl &
+							    ~
+							    (BPCTLI_CTRL_SDP0_DATA
+							     |
+							     BPCTLI_CTRL_SDP0_DIR)));
+				}
+			} else
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP10G_SDP0_DIR) &
+						 ~BP10G_SDP0_DATA));
+
+		}
+
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+
+}
+
+/* SET_FORCE_LINK  (non-Bypass command :)) */
+static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state)
+{
+	int ret = 0, ctrl = 0;
+
+	if (DBI_IF_SERIES(pbpctl_dev->subdevice)) {
+
+		if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) {
+
+			ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
+			if (!tx_state)
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						ctrl & ~BP10G_SDP1_DIR);
+			else
+				BP10G_WRITE_REG(pbpctl_dev, ESDP,
+						((ctrl | BP10G_SDP1_DIR) &
+						 ~BP10G_SDP1_DATA));
+			return ret;
+		}
+
+	}
+	return BP_NOT_CAP;
+}
+
+/*RESET_CONT 0x20 */
+int reset_cont(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+			return BP_NOT_CAP;
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
+			write_data(pbpctl_dev, RESET_CONT);
+		else
+			data_pulse(pbpctl_dev, RESET_CONT);
+		ret = 0;
+	};
+	return ret;
+}
+
+/*DIS_BYPASS_CAP 0x22 */
+int dis_bypass_cap(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+		} else {
+			write_data(pbpctl_dev, BYPASS_OFF);
+			msec_delay_bp(LATCH_DELAY);
+			write_data(pbpctl_dev, DIS_BYPASS_CAP);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+		}
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/*EN_BYPASS_CAP 0x24 */
+int en_bypass_cap(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+		} else {
+			write_data(pbpctl_dev, EN_BYPASS_CAP);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+		}
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/* BYPASS_STATE_PWRON 0x26*/
+int bypass_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
+		write_data(pbpctl_dev, BYPASS_STATE_PWRON);
+		if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+			msec_delay_bp(DFLT_PWRON_DELAY);
+		else
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/* NORMAL_STATE_PWRON 0x28*/
+int normal_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)
+	    || (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) {
+		write_data(pbpctl_dev, NORMAL_STATE_PWRON);
+		if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+			msec_delay_bp(DFLT_PWRON_DELAY);
+		else
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/* BYPASS_STATE_PWROFF 0x27*/
+int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) {
+		write_data(pbpctl_dev, BYPASS_STATE_PWROFF);
+		msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/* NORMAL_STATE_PWROFF 0x29*/
+int normal_state_pwroff(bpctl_dev_t *pbpctl_dev)
+{
+	if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
+		write_data(pbpctl_dev, NORMAL_STATE_PWROFF);
+		msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/*TAP_STATE_PWRON 0x2a*/
+int tap_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
+		write_data(pbpctl_dev, TAP_STATE_PWRON);
+		msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/*DIS_TAP_CAP 0x2c*/
+int dis_tap_cap(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
+		write_data(pbpctl_dev, DIS_TAP_CAP);
+		msec_delay_bp(BYPASS_CAP_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/*EN_TAP_CAP 0x2e*/
+int en_tap_cap(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
+		write_data(pbpctl_dev, EN_TAP_CAP);
+		msec_delay_bp(BYPASS_CAP_DELAY);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+/*DISC_STATE_PWRON 0x2a*/
+int disc_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			write_data(pbpctl_dev, DISC_STATE_PWRON);
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/*DIS_DISC_CAP 0x2c*/
+int dis_disc_cap(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			write_data(pbpctl_dev, DIS_DISC_CAP);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/*DISC_STATE_PWRON 0x2a*/
+int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+
+	return BP_NOT_CAP;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1)
+			write_data(pbpctl_dev_m, TX_DISA_PWRUP);
+		else
+			write_data(pbpctl_dev_m, TX_DISB_PWRUP);
+
+		msec_delay_bp(LATCH_DELAY);
+
+	}
+	return ret;
+}
+
+int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+	return BP_NOT_CAP;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1)
+			write_data(pbpctl_dev_m, TX_ENA_PWRUP);
+		else
+			write_data(pbpctl_dev_m, TX_ENB_PWRUP);
+
+		msec_delay_bp(LATCH_DELAY);
+
+	}
+	return ret;
+}
+
+/*EN_TAP_CAP 0x2e*/
+int en_disc_cap(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			write_data(pbpctl_dev, EN_DISC_CAP);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int std_nic_on(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
+
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			pbpctl_dev->bp_status_un = 0;
+			return BP_OK;
+		}
+
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			write_data(pbpctl_dev, STD_NIC_ON);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+			return BP_OK;
+
+		}
+
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			wdt_off(pbpctl_dev);
+
+			if (pbpctl_dev->bp_caps & BP_CAP) {
+				write_data(pbpctl_dev, BYPASS_OFF);
+				msec_delay_bp(LATCH_DELAY);
+			}
+
+			if (pbpctl_dev->bp_caps & TAP_CAP) {
+				write_data(pbpctl_dev, TAP_OFF);
+				msec_delay_bp(LATCH_DELAY);
+			}
+
+			write_data(pbpctl_dev, NORMAL_STATE_PWRON);
+			if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+				msec_delay_bp(DFLT_PWRON_DELAY);
+			else
+				msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+
+			if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
+				write_data(pbpctl_dev, DIS_BYPASS_CAP);
+				msec_delay_bp(BYPASS_CAP_DELAY);
+			}
+
+			if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
+				write_data(pbpctl_dev, DIS_TAP_CAP);
+				msec_delay_bp(BYPASS_CAP_DELAY);
+
+			}
+			return 0;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int std_nic_off(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
+			msec_delay_bp(BYPASS_DELAY_INT);
+			return BP_OK;
+		}
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			write_data(pbpctl_dev, STD_NIC_OFF);
+			msec_delay_bp(BYPASS_CAP_DELAY);
+			return BP_OK;
+
+		}
+
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+
+			if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
+				write_data(pbpctl_dev, TAP_STATE_PWRON);
+				msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+			}
+
+			if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
+				write_data(pbpctl_dev, BYPASS_STATE_PWRON);
+				if (pbpctl_dev->bp_ext_ver > PXG2BPI_VER)
+					msec_delay_bp(LATCH_DELAY +
+						      EEPROM_WR_DELAY);
+				else
+					msec_delay_bp(DFLT_PWRON_DELAY);
+			}
+
+			if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
+				write_data(pbpctl_dev, EN_TAP_CAP);
+				msec_delay_bp(BYPASS_CAP_DELAY);
+			}
+			if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
+				write_data(pbpctl_dev, EN_DISC_CAP);
+				msec_delay_bp(BYPASS_CAP_DELAY);
+			}
+
+			if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
+				write_data(pbpctl_dev, EN_BYPASS_CAP);
+				msec_delay_bp(BYPASS_CAP_DELAY);
+			}
+
+			return 0;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int wdt_time_left(bpctl_dev_t *pbpctl_dev)
+{
+
+	/* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */
+	unsigned long curr_time = jiffies, delta_time = 0, wdt_on_time =
+	    pbpctl_dev->bypass_wdt_on_time, delta_time_msec = 0;
+	int time_left = 0;
+
+	switch (pbpctl_dev->wdt_status) {
+	case WDT_STATUS_DIS:
+		time_left = 0;
+		break;
+	case WDT_STATUS_EN:
+		delta_time =
+		    (curr_time >=
+		     wdt_on_time) ? (curr_time - wdt_on_time) : (~wdt_on_time +
+								 curr_time);
+		delta_time_msec = jiffies_to_msecs(delta_time);
+		time_left = pbpctl_dev->bypass_timer_interval - delta_time_msec;
+		if (time_left < 0) {
+			time_left = -1;
+			pbpctl_dev->wdt_status = WDT_STATUS_EXP;
+		}
+		break;
+	case WDT_STATUS_EXP:
+		time_left = -1;
+		break;
+	}
+
+	return time_left;
+}
+
+static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left)
+{
+	int ret = 0;
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		{
+			if (pbpctl_dev->wdt_status == WDT_STATUS_UNKNOWN)
+				ret = BP_NOT_CAP;
+			else
+				*time_left = wdt_time_left(pbpctl_dev);
+		}
+
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev)
+{
+
+	int ret = 0;
+
+	if ((pbpctl_dev->bp_caps & WD_CTL_CAP) &&
+	    (pbpctl_dev->wdt_status != WDT_STATUS_UNKNOWN)) {
+		if (pbpctl_dev->wdt_status == WDT_STATUS_DIS)
+			return 0;
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
+			ret = wdt_pulse(pbpctl_dev);
+		else if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+			ret = wdt_pulse_int(pbpctl_dev);
+		else
+			ret = send_wdt_pulse(pbpctl_dev);
+		/* if (ret==-1)
+		    mod_timer(&pbpctl_dev->bp_timer, jiffies+1);*/
+		return 1;
+	}
+	return BP_NOT_CAP;
+}
+
+static void wd_reset_timer(unsigned long param)
+{
+	bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+#ifdef BP_SELF_TEST
+	struct sk_buff *skb_tmp;
+#endif
+
+	if ((pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) &&
+	    ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)) {
+		mod_timer(&pbpctl_dev->bp_timer, jiffies + 1);
+		return;
+	}
+#ifdef BP_SELF_TEST
+
+	if (pbpctl_dev->bp_self_test_flag == 1) {
+		skb_tmp = dev_alloc_skb(BPTEST_DATA_LEN + 2);
+		if ((skb_tmp) && (pbpctl_dev->ndev) && (pbpctl_dev->bp_tx_data)) {
+			memcpy(skb_put(skb_tmp, BPTEST_DATA_LEN),
+			       pbpctl_dev->bp_tx_data, BPTEST_DATA_LEN);
+			skb_tmp->dev = pbpctl_dev->ndev;
+			skb_tmp->protocol =
+			    eth_type_trans(skb_tmp, pbpctl_dev->ndev);
+			skb_tmp->ip_summed = CHECKSUM_UNNECESSARY;
+			netif_receive_skb(skb_tmp);
+			goto bp_timer_reload;
+			return;
+		}
+	}
+#endif
+
+	wdt_timer_reload(pbpctl_dev);
+#ifdef BP_SELF_TEST
+ bp_timer_reload:
+#endif
+	if (pbpctl_dev->reset_time) {
+		mod_timer(&pbpctl_dev->bp_timer,
+			  jiffies + (HZ * pbpctl_dev->reset_time) / 1000);
+	}
+}
+
+/*WAIT_AT_PWRUP 0x80   */
+int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+			write_data(pbpctl_dev, BP_WAIT_AT_PWUP_EN);
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/*DIS_WAIT_AT_PWRUP       0x81 */
+int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+
+		if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+			write_data(pbpctl_dev, BP_WAIT_AT_PWUP_DIS);
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/*EN_HW_RESET  0x82   */
+
+int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+			write_data(pbpctl_dev, BP_HW_RESET_EN);
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/*DIS_HW_RESET             0x83   */
+
+int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+			write_data(pbpctl_dev, BP_HW_RESET_DIS);
+			msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
+
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+
+int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode)
+{
+	uint32_t status_reg = 0, status_reg1 = 0;
+
+	if ((pbpctl_dev->bp_caps & (TAP_STATUS_CAP | DISC_CAP)) &&
+	    (pbpctl_dev->bp_caps & BP_CAP)) {
+		if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) {
+
+			if ((pbpctl_dev->bp_ext_ver >= 0x8) &&
+			    (mode == 2) && (pbpctl_dev->bp_caps & DISC_CAP)) {
+				status_reg1 =
+				    read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR);
+				if (!(status_reg1 & WDTE_DISC_BPN_MASK))
+					write_reg(pbpctl_dev,
+						  status_reg1 |
+						  WDTE_DISC_BPN_MASK,
+						  STATUS_DISC_REG_ADDR);
+				return BP_OK;
+			}
+		}
+		status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR);
+
+		if ((mode == 0) && (pbpctl_dev->bp_caps & BP_CAP)) {
+			if (pbpctl_dev->bp_ext_ver >= 0x8) {
+				status_reg1 =
+				    read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR);
+				if (status_reg1 & WDTE_DISC_BPN_MASK)
+					write_reg(pbpctl_dev,
+						  status_reg1 &
+						  ~WDTE_DISC_BPN_MASK,
+						  STATUS_DISC_REG_ADDR);
+			}
+			if (status_reg & WDTE_TAP_BPN_MASK)
+				write_reg(pbpctl_dev,
+					  status_reg & ~WDTE_TAP_BPN_MASK,
+					  STATUS_TAP_REG_ADDR);
+			return BP_OK;
+
+		} else if ((mode == 1) && (pbpctl_dev->bp_caps & TAP_CAP)) {
+			if (!(status_reg & WDTE_TAP_BPN_MASK))
+				write_reg(pbpctl_dev,
+					  status_reg | WDTE_TAP_BPN_MASK,
+					  STATUS_TAP_REG_ADDR);
+			/*else return BP_NOT_CAP; */
+			return BP_OK;
+		}
+
+	}
+	return BP_NOT_CAP;
+}
+
+int bypass_fw_ver(bpctl_dev_t *pbpctl_dev)
+{
+	if (is_bypass_fn(pbpctl_dev))
+		return read_reg(pbpctl_dev, VER_REG_ADDR);
+	else
+		return BP_NOT_CAP;
+}
+
+int bypass_sign_check(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (is_bypass_fn(pbpctl_dev))
+		return (((read_reg(pbpctl_dev, PIC_SIGN_REG_ADDR)) ==
+			 PIC_SIGN_VALUE) ? 1 : 0);
+	else
+		return BP_NOT_CAP;
+}
+
+static int tx_status(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl = 0;
+	bpctl_dev_t *pbpctl_dev_m;
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+
+		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
+		if (pbpctl_dev->bp_i80)
+			return ((ctrl & BPCTLI_CTRL_SWDPIN1) != 0 ? 0 : 1);
+		if (pbpctl_dev->bp_540) {
+			ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+
+			return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1);
+		}
+
+	}
+
+	if (pbpctl_dev->bp_caps & TX_CTL_CAP) {
+		if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) {
+			uint16_t mii_reg;
+			if (!
+			    (bp75_read_phy_reg
+			     (pbpctl_dev, BPCTLI_PHY_CONTROL, &mii_reg))) {
+				if (mii_reg & BPCTLI_MII_CR_POWER_DOWN)
+					return 0;
+
+				else
+					return 1;
+			}
+			return -1;
+		}
+
+		if (pbpctl_dev->bp_10g9) {
+			return ((BP10G_READ_REG(pbpctl_dev, ESDP) &
+				 BP10G_SDP3_DATA) != 0 ? 0 : 1);
+
+		} else if (pbpctl_dev->bp_fiber5) {
+			ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+			if (ctrl & BPCTLI_CTRL_EXT_SDP6_DATA)
+				return 0;
+			return 1;
+		} else if (pbpctl_dev->bp_10gb) {
+			ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO);
+			BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO,
+					 (ctrl | BP10GB_GPIO0_OE_P1) &
+					 ~(BP10GB_GPIO0_SET_P1 |
+					   BP10GB_GPIO0_CLR_P1));
+
+			if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3))
+				return (((BP10GB_READ_REG
+					  (pbpctl_dev,
+					   MISC_REG_GPIO)) & BP10GB_GPIO0_P1) !=
+					0 ? 0 : 1);
+			else
+				return (((BP10GB_READ_REG
+					  (pbpctl_dev,
+					   MISC_REG_GPIO)) & BP10GB_GPIO0_P0) !=
+					0 ? 0 : 1);
+		}
+
+		if (!pbpctl_dev->bp_10g) {
+
+			ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
+			if (pbpctl_dev->bp_i80)
+				return ((ctrl & BPCTLI_CTRL_SWDPIN1) !=
+					0 ? 0 : 1);
+			if (pbpctl_dev->bp_540) {
+				ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
+
+				return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1);
+			}
+
+			return ((ctrl & BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1);
+		} else
+			return ((BP10G_READ_REG(pbpctl_dev, ESDP) &
+				 BP10G_SDP0_DATA) != 0 ? 0 : 1);
+
+	}
+	return BP_NOT_CAP;
+}
+
+static int bp_force_link_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (DBI_IF_SERIES(pbpctl_dev->subdevice)) {
+
+		if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) {
+			return ((BP10G_READ_REG(pbpctl_dev, ESDP) &
+				 BP10G_SDP1_DIR) != 0 ? 1 : 0);
+
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int bypass_from_last_read(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t ctrl_ext = 0;
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if ((pbpctl_dev->bp_caps & SW_CTL_CAP)
+	    && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) {
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT);
+		BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL_EXT,
+				   (ctrl_ext & ~BPCTLI_CTRL_EXT_SDP7_DIR));
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT);
+		if (ctrl_ext & BPCTLI_CTRL_EXT_SDP7_DATA)
+			return 0;
+		return 1;
+	} else
+		return BP_NOT_CAP;
+}
+
+int bypass_status_clear(bpctl_dev_t *pbpctl_dev)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if ((pbpctl_dev->bp_caps & SW_CTL_CAP)
+	    && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) {
+
+		send_bypass_clear_pulse(pbpctl_dev_b, 1);
+		return 0;
+	} else
+		return BP_NOT_CAP;
+}
+
+int bypass_flag_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if ((pbpctl_dev->bp_caps & BP_CAP)) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+				  BYPASS_FLAG_MASK) ==
+				 BYPASS_FLAG_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & BP_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			uint32_t status_reg = 0;
+			status_reg = read_reg(pbpctl_dev, STATUS_REG_ADDR);
+			write_reg(pbpctl_dev, status_reg & ~BYPASS_FLAG_MASK,
+				  STATUS_REG_ADDR);
+			return 0;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int bypass_change_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & BP_STATUS_CHANGE_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			ret = bypass_flag_status(pbpctl_dev);
+			bypass_flag_status_clear(pbpctl_dev);
+		} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			ret = bypass_flag_status(pbpctl_dev);
+			bypass_flag_status_clear(pbpctl_dev);
+		} else {
+			ret = bypass_from_last_read(pbpctl_dev);
+			bypass_status_clear(pbpctl_dev);
+		}
+	}
+	return ret;
+}
+
+int bypass_off_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & BP_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+				  BYPASS_OFF_MASK) == BYPASS_OFF_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+static int bypass_status(bpctl_dev_t *pbpctl_dev)
+{
+	u32 ctrl_ext = 0;
+	if (pbpctl_dev->bp_caps & BP_CAP) {
+
+		bpctl_dev_t *pbpctl_dev_b = NULL;
+
+		if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+			return BP_NOT_CAP;
+
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+
+			if (!pbpctl_dev->bp_status_un)
+				return (((BPCTL_READ_REG
+					  (pbpctl_dev_b,
+					   CTRL_EXT)) &
+					 BPCTLI_CTRL_EXT_SDP7_DATA) !=
+					0 ? 1 : 0);
+			else
+				return BP_NOT_CAP;
+		}
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+
+			if (pbpctl_dev->bp_10g9) {
+				ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL);
+				BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL,
+						(ctrl_ext | BP10G_I2C_CLK_OUT));
+				return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) &
+					 BP10G_I2C_CLK_IN) != 0 ? 0 : 1);
+
+			} else if (pbpctl_dev->bp_540) {
+				return (((BP10G_READ_REG(pbpctl_dev_b, ESDP)) &
+					 BP10G_SDP0_DATA) != 0 ? 0 : 1);
+			}
+
+			else if ((pbpctl_dev->bp_fiber5)
+				 || (pbpctl_dev->bp_i80)) {
+				return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) &
+					 BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1);
+			} else if (pbpctl_dev->bp_10gb) {
+				ctrl_ext =
+				    BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO);
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO,
+						 (ctrl_ext | BP10GB_GPIO3_OE_P0)
+						 & ~(BP10GB_GPIO3_SET_P0 |
+						     BP10GB_GPIO3_CLR_P0));
+
+				return (((BP10GB_READ_REG
+					  (pbpctl_dev,
+					   MISC_REG_GPIO)) & BP10GB_GPIO3_P0) !=
+					0 ? 0 : 1);
+			}
+
+			else if (!pbpctl_dev->bp_10g)
+				return (((BPCTL_READ_REG
+					  (pbpctl_dev_b,
+					   CTRL_EXT)) &
+					 BPCTLI_CTRL_EXT_SDP7_DATA) !=
+					0 ? 0 : 1);
+
+			else {
+				ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP);
+				BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
+						(ctrl_ext |
+						 BP10G_SDP7_DATA_OUT));
+				return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) &
+					 BP10G_SDP7_DATA_IN) != 0 ? 0 : 1);
+			}
+
+		} else if (pbpctl_dev->media_type == bp_copper) {
+
+			return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) &
+				 BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0);
+		} else {
+			if ((bypass_status_clear(pbpctl_dev)) >= 0)
+				return bypass_from_last_read(pbpctl_dev);
+		}
+
+	}
+	return BP_NOT_CAP;
+}
+
+int default_pwron_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
+			if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+				return ((((read_reg
+					   (pbpctl_dev,
+					    STATUS_REG_ADDR)) & DFLT_PWRON_MASK)
+					 == DFLT_PWRON_MASK) ? 0 : 1);
+			}
+		}		/*else if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&&
+				   (pbpctl_dev->bp_caps&BP_PWUP_ON_CAP))
+				   return 1; */
+	}
+	return BP_NOT_CAP;
+}
+
+static int default_pwroff_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	/*if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&&
+	   (pbpctl_dev->bp_caps&BP_PWOFF_ON_CAP))
+	   return 1; */
+	if ((pbpctl_dev->bp_caps & SW_CTL_CAP)
+	    && (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
+		return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+			  DFLT_PWROFF_MASK) == DFLT_PWROFF_MASK) ? 0 : 1);
+	}
+	return BP_NOT_CAP;
+}
+
+int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+				  DIS_BYPASS_CAP_MASK) ==
+				 DIS_BYPASS_CAP_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int cmd_en_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+				  CMND_EN_MASK) == CMND_EN_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int wdt_en_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+				  WDT_EN_MASK) == WDT_EN_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout)
+{
+	int ret = 0;
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+			    WDT_EN_MASK) {
+				u8 wdt_val;
+				wdt_val = read_reg(pbpctl_dev, WDT_REG_ADDR);
+				*timeout = (1 << wdt_val) * 100;
+			} else
+				*timeout = 0;
+		} else {
+			int curr_wdt_status = pbpctl_dev->wdt_status;
+			if (curr_wdt_status == WDT_STATUS_UNKNOWN)
+				*timeout = -1;
+			else
+				*timeout =
+				    curr_wdt_status ==
+				    0 ? 0 : pbpctl_dev->bypass_timer_interval;
+		};
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+int bypass_support(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+			ret =
+			    ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) &
+			       BYPASS_SUPPORT_MASK) ==
+			      BYPASS_SUPPORT_MASK) ? 1 : 0);
+		} else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+			ret = 1;
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+int tap_support(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+			ret =
+			    ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) &
+			       TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) ? 1 : 0);
+		} else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+			ret = 0;
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+int normal_support(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+			ret =
+			    ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) &
+			       NORMAL_UNSUPPORT_MASK) ==
+			      NORMAL_UNSUPPORT_MASK) ? 0 : 1);
+		} else
+			ret = 1;
+	};
+	return ret;
+}
+
+int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev)
+{
+	if ((pbpctl_dev->bp_caps & SW_CTL_CAP) &&
+	    (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER))
+		return read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR);
+	return BP_NOT_CAP;
+
+}
+
+int tap_flag_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  TAP_FLAG_MASK) == TAP_FLAG_MASK) ? 1 : 0);
+
+	}
+	return BP_NOT_CAP;
+}
+
+int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t status_reg = 0;
+	if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+			status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR);
+			write_reg(pbpctl_dev, status_reg & ~TAP_FLAG_MASK,
+				  STATUS_TAP_REG_ADDR);
+			return 0;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int tap_change_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+		if (pbpctl_dev->bp_caps & TAP_CAP) {
+			if (pbpctl_dev->bp_caps & BP_CAP) {
+				ret = tap_flag_status(pbpctl_dev);
+				tap_flag_status_clear(pbpctl_dev);
+			} else {
+				ret = bypass_from_last_read(pbpctl_dev);
+				bypass_status_clear(pbpctl_dev);
+			}
+		}
+	}
+	return ret;
+}
+
+int tap_off_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  TAP_OFF_MASK) == TAP_OFF_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int tap_status(bpctl_dev_t *pbpctl_dev)
+{
+	u32 ctrl_ext = 0;
+
+	if (pbpctl_dev->bp_caps & TAP_CAP) {
+		bpctl_dev_t *pbpctl_dev_b = NULL;
+
+		if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+			return BP_NOT_CAP;
+
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			if (!pbpctl_dev->bp_10g)
+				return (((BPCTL_READ_REG
+					  (pbpctl_dev_b,
+					   CTRL_EXT)) &
+					 BPCTLI_CTRL_EXT_SDP6_DATA) !=
+					0 ? 0 : 1);
+			else {
+				ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP);
+				BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
+						(ctrl_ext |
+						 BP10G_SDP6_DATA_OUT));
+				return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) &
+					 BP10G_SDP6_DATA_IN) != 0 ? 0 : 1);
+			}
+
+		} else if (pbpctl_dev->media_type == bp_copper)
+			return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) &
+				 BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0);
+		else {
+			if ((bypass_status_clear(pbpctl_dev)) >= 0)
+				return bypass_from_last_read(pbpctl_dev);
+		}
+
+	}
+	return BP_NOT_CAP;
+}
+
+int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  DFLT_PWRON_TAP_MASK) ==
+				 DFLT_PWRON_TAP_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  DIS_TAP_CAP_MASK) ==
+				 DIS_TAP_CAP_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int disc_flag_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & DISC_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8)
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  DISC_FLAG_MASK) == DISC_FLAG_MASK) ? 1 : 0);
+
+	}
+	return BP_NOT_CAP;
+}
+
+int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+{
+	uint32_t status_reg = 0;
+	if (pbpctl_dev->bp_caps & DISC_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8) {
+			status_reg = read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR);
+			write_reg(pbpctl_dev, status_reg & ~DISC_FLAG_MASK,
+				  STATUS_DISC_REG_ADDR);
+			return BP_OK;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int disc_change_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	if (pbpctl_dev->bp_caps & DISC_CAP) {
+		ret = disc_flag_status(pbpctl_dev);
+		disc_flag_status_clear(pbpctl_dev);
+		return ret;
+	}
+	return BP_NOT_CAP;
+}
+
+int disc_off_status(bpctl_dev_t *pbpctl_dev)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+	u32 ctrl_ext = 0;
+
+	if (pbpctl_dev->bp_caps & DISC_CAP) {
+		if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+			return BP_NOT_CAP;
+		if (DISCF_IF_SERIES(pbpctl_dev->subdevice))
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0);
+
+		if (pbpctl_dev->bp_i80) {
+			return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT)) &
+				 BPCTLI_CTRL_EXT_SDP6_DATA) != 0 ? 1 : 0);
+
+		}
+		if (pbpctl_dev->bp_540) {
+			ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, ESDP);
+			return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) &
+				 BP10G_SDP2_DATA) != 0 ? 1 : 0);
+
+		}
+		if (pbpctl_dev->media_type == bp_copper) {
+
+#if 0
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0);
+#endif
+			if (!pbpctl_dev->bp_10g)
+				return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) &
+					 BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0);
+			else
+				return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) &
+					 BP10G_SDP1_DATA) != 0 ? 1 : 0);
+
+		} else {
+
+			if (pbpctl_dev->bp_10g9) {
+				ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL);
+				BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL,
+						(ctrl_ext |
+						 BP10G_I2C_DATA_OUT));
+				return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) &
+					 BP10G_I2C_DATA_IN) != 0 ? 1 : 0);
+
+			} else if (pbpctl_dev->bp_fiber5) {
+				return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) &
+					 BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0);
+			} else if (pbpctl_dev->bp_10gb) {
+				ctrl_ext =
+				    BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO);
+				BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO,
+						 (ctrl_ext | BP10GB_GPIO3_OE_P1)
+						 & ~(BP10GB_GPIO3_SET_P1 |
+						     BP10GB_GPIO3_CLR_P1));
+
+				return (((BP10GB_READ_REG
+					  (pbpctl_dev,
+					   MISC_REG_GPIO)) & BP10GB_GPIO3_P1) !=
+					0 ? 1 : 0);
+			}
+			if (!pbpctl_dev->bp_10g) {
+
+				return (((BPCTL_READ_REG
+					  (pbpctl_dev_b,
+					   CTRL_EXT)) &
+					 BPCTLI_CTRL_EXT_SDP6_DATA) !=
+					0 ? 1 : 0);
+			} else {
+				ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP);
+				BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
+						(ctrl_ext |
+						 BP10G_SDP6_DATA_OUT));
+				return (((BP10G_READ_REG(pbpctl_dev_b, EODSDP))
+					 & BP10G_SDP6_DATA_IN) != 0 ? 1 : 0);
+			}
+
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+static int disc_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ctrl = 0;
+	if (pbpctl_dev->bp_caps & DISC_CAP) {
+
+		if ((ctrl = disc_off_status(pbpctl_dev)) < 0)
+			return ctrl;
+		return ((ctrl == 0) ? 1 : 0);
+
+	}
+	return BP_NOT_CAP;
+}
+
+int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8)
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  DFLT_PWRON_DISC_MASK) ==
+				 DFLT_PWRON_DISC_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & DIS_DISC_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8)
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  DIS_DISC_CAP_MASK) ==
+				 DIS_DISC_CAP_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int disc_port_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	bpctl_dev_t *pbpctl_dev_m;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1) {
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  TX_DISA_MASK) == TX_DISA_MASK) ? 1 : 0);
+		} else
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  TX_DISB_MASK) == TX_DISB_MASK) ? 1 : 0);
+
+	}
+	return ret;
+}
+
+int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	bpctl_dev_t *pbpctl_dev_m;
+
+	if ((is_bypass_fn(pbpctl_dev)) == 1)
+		pbpctl_dev_m = pbpctl_dev;
+	else
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m == NULL)
+		return BP_NOT_CAP;
+
+	if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
+		if (is_bypass_fn(pbpctl_dev) == 1)
+			return ret;
+		/*  return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
+		else
+			return ret;
+		/*   return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
+
+	}
+	return ret;
+}
+
+int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER)
+			return 0;	/* bypass mode */
+		else if (pbpctl_dev->bp_ext_ver == PXG2TBPI_VER)
+			return 1;	/* tap mode */
+		else if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) {
+			if (pbpctl_dev->bp_ext_ver >= 0x8) {
+				if (((read_reg
+				      (pbpctl_dev,
+				       STATUS_DISC_REG_ADDR)) &
+				     WDTE_DISC_BPN_MASK) == WDTE_DISC_BPN_MASK)
+					return 2;
+			}
+			return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
+				  WDTE_TAP_BPN_MASK) ==
+				 WDTE_TAP_BPN_MASK) ? 1 : 0);
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+int tpl2_flag_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
+		return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+			  TPL2_FLAG_MASK) == TPL2_FLAG_MASK) ? 1 : 0);
+
+	}
+	return BP_NOT_CAP;
+}
+
+int tpl_hw_status(bpctl_dev_t *pbpctl_dev)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+		return BP_NOT_CAP;
+
+	if (TPL_IF_SERIES(pbpctl_dev->subdevice))
+		return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) &
+			 BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0);
+	return BP_NOT_CAP;
+}
+
+
+int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		if (pbpctl_dev->bp_ext_ver >= 0x8)
+			return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) &
+				  WAIT_AT_PWUP_MASK) ==
+				 WAIT_AT_PWUP_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+
+		if (pbpctl_dev->bp_ext_ver >= 0x8)
+			return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) &
+				  EN_HW_RESET_MASK) ==
+				 EN_HW_RESET_MASK) ? 1 : 0);
+	}
+	return BP_NOT_CAP;
+}
+
+
+int std_nic_status(bpctl_dev_t *pbpctl_dev)
+{
+	int status_val = 0;
+
+	if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+			return BP_NOT_CAP;
+		if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+			return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) &
+				  STD_NIC_ON_MASK) == STD_NIC_ON_MASK) ? 1 : 0);
+		}
+
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			if (pbpctl_dev->bp_caps & BP_CAP) {
+				status_val =
+				    read_reg(pbpctl_dev, STATUS_REG_ADDR);
+				if (((!(status_val & WDT_EN_MASK))
+				     && ((status_val & STD_NIC_MASK) ==
+					 STD_NIC_MASK)))
+					status_val = 1;
+				else
+					return 0;
+			}
+			if (pbpctl_dev->bp_caps & TAP_CAP) {
+				status_val =
+				    read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR);
+				if ((status_val & STD_NIC_TAP_MASK) ==
+				    STD_NIC_TAP_MASK)
+					status_val = 1;
+				else
+					return 0;
+			}
+			if (pbpctl_dev->bp_caps & TAP_CAP) {
+				if ((disc_off_status(pbpctl_dev)))
+					status_val = 1;
+				else
+					return 0;
+			}
+
+			return status_val;
+		}
+	}
+	return BP_NOT_CAP;
+}
+
+/******************************************************/
+/**************SW_INIT*********************************/
+/******************************************************/
+void bypass_caps_init(bpctl_dev_t *pbpctl_dev)
+{
+	u_int32_t ctrl_ext = 0;
+	bpctl_dev_t *pbpctl_dev_m = NULL;
+
+#ifdef BYPASS_DEBUG
+	int ret = 0;
+	if (!(INTEL_IF_SERIES(adapter->bp_device_block.subdevice))) {
+		ret = read_reg(pbpctl_dev, VER_REG_ADDR);
+		printk("VER_REG reg1=%x\n", ret);
+		ret = read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR);
+		printk("PRODUCT_CAP reg=%x\n", ret);
+		ret = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR);
+		printk("STATUS_TAP reg1=%x\n", ret);
+		ret = read_reg(pbpctl_dev, 0x7);
+		printk("SIG_REG reg1=%x\n", ret);
+		ret = read_reg(pbpctl_dev, STATUS_REG_ADDR);
+		printk("STATUS_REG_ADDR=%x\n", ret);
+		ret = read_reg(pbpctl_dev, WDT_REG_ADDR);
+		printk("WDT_REG_ADDR=%x\n", ret);
+		ret = read_reg(pbpctl_dev, TMRL_REG_ADDR);
+		printk("TMRL_REG_ADDR=%x\n", ret);
+		ret = read_reg(pbpctl_dev, TMRH_REG_ADDR);
+		printk("TMRH_REG_ADDR=%x\n", ret);
+	}
+#endif
+	if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_10g9)) {
+		pbpctl_dev->media_type = bp_fiber;
+	} else if (pbpctl_dev->bp_10gb) {
+		if (BP10GB_CX4_SERIES(pbpctl_dev->subdevice))
+			pbpctl_dev->media_type = bp_cx4;
+		else
+			pbpctl_dev->media_type = bp_fiber;
+
+	}
+
+	else if (pbpctl_dev->bp_540)
+		pbpctl_dev->media_type = bp_none;
+	else if (!pbpctl_dev->bp_10g) {
+
+		ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
+		if ((ctrl_ext & BPCTLI_CTRL_EXT_LINK_MODE_MASK) == 0x0)
+			pbpctl_dev->media_type = bp_copper;
+		else
+			pbpctl_dev->media_type = bp_fiber;
+
+	} else {
+		if (BP10G_CX4_SERIES(pbpctl_dev->subdevice))
+			pbpctl_dev->media_type = bp_cx4;
+		else
+			pbpctl_dev->media_type = bp_fiber;
+	}
+
+	if (is_bypass_fn(pbpctl_dev)) {
+
+		pbpctl_dev->bp_caps |= BP_PWOFF_ON_CAP;
+		if (pbpctl_dev->media_type == bp_fiber)
+			pbpctl_dev->bp_caps |=
+			    (TX_CTL_CAP | TX_STATUS_CAP | TPL_CAP);
+
+		if (TPL_IF_SERIES(pbpctl_dev->subdevice)) {
+			pbpctl_dev->bp_caps |= TPL_CAP;
+		}
+
+		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
+			pbpctl_dev->bp_caps |=
+			    (BP_CAP | BP_STATUS_CAP | SW_CTL_CAP |
+			     BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWOFF_OFF_CAP
+			     | WD_CTL_CAP | WD_STATUS_CAP | STD_NIC_CAP |
+			     WD_TIMEOUT_CAP);
+
+			pbpctl_dev->bp_ext_ver = OLD_IF_VER;
+			return;
+		}
+
+		if ((pbpctl_dev->bp_fw_ver == 0xff) &&
+		    OLD_IF_SERIES(pbpctl_dev->subdevice)) {
+
+			pbpctl_dev->bp_caps |=
+			    (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP |
+			     SW_CTL_CAP | BP_PWUP_ON_CAP | WD_CTL_CAP |
+			     WD_STATUS_CAP | WD_TIMEOUT_CAP);
+
+			pbpctl_dev->bp_ext_ver = OLD_IF_VER;
+			return;
+		}
+
+		else {
+			switch (pbpctl_dev->bp_fw_ver) {
+			case BP_FW_VER_A0:
+			case BP_FW_VER_A1:{
+					pbpctl_dev->bp_ext_ver =
+					    (pbpctl_dev->
+					     bp_fw_ver & EXT_VER_MASK);
+					break;
+				}
+			default:{
+					if ((bypass_sign_check(pbpctl_dev)) !=
+					    1) {
+						pbpctl_dev->bp_caps = 0;
+						return;
+					}
+					pbpctl_dev->bp_ext_ver =
+					    (pbpctl_dev->
+					     bp_fw_ver & EXT_VER_MASK);
+				}
+			}
+		}
+
+		if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
+			pbpctl_dev->bp_caps |=
+			    (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP |
+			     SW_CTL_CAP | BP_DIS_CAP | BP_DIS_STATUS_CAP |
+			     BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP
+			     | WD_CTL_CAP | STD_NIC_CAP | WD_STATUS_CAP |
+			     WD_TIMEOUT_CAP);
+		else if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
+			int cap_reg;
+
+			pbpctl_dev->bp_caps |=
+			    (SW_CTL_CAP | WD_CTL_CAP | WD_STATUS_CAP |
+			     WD_TIMEOUT_CAP);
+			cap_reg = get_bp_prod_caps(pbpctl_dev);
+
+			if ((cap_reg & NORMAL_UNSUPPORT_MASK) ==
+			    NORMAL_UNSUPPORT_MASK)
+				pbpctl_dev->bp_caps |= NIC_CAP_NEG;
+			else
+				pbpctl_dev->bp_caps |= STD_NIC_CAP;
+
+			if ((normal_support(pbpctl_dev)) == 1)
+
+				pbpctl_dev->bp_caps |= STD_NIC_CAP;
+
+			else
+				pbpctl_dev->bp_caps |= NIC_CAP_NEG;
+			if ((cap_reg & BYPASS_SUPPORT_MASK) ==
+			    BYPASS_SUPPORT_MASK) {
+				pbpctl_dev->bp_caps |=
+				    (BP_CAP | BP_STATUS_CAP |
+				     BP_STATUS_CHANGE_CAP | BP_DIS_CAP |
+				     BP_DIS_STATUS_CAP | BP_PWUP_ON_CAP |
+				     BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP);
+				if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER7)
+					pbpctl_dev->bp_caps |=
+					    BP_PWOFF_ON_CAP | BP_PWOFF_OFF_CAP |
+					    BP_PWOFF_CTL_CAP;
+			}
+			if ((cap_reg & TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) {
+				pbpctl_dev->bp_caps |=
+				    (TAP_CAP | TAP_STATUS_CAP |
+				     TAP_STATUS_CHANGE_CAP | TAP_DIS_CAP |
+				     TAP_DIS_STATUS_CAP | TAP_PWUP_ON_CAP |
+				     TAP_PWUP_OFF_CAP | TAP_PWUP_CTL_CAP);
+			}
+			if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) {
+				if ((cap_reg & DISC_SUPPORT_MASK) ==
+				    DISC_SUPPORT_MASK)
+					pbpctl_dev->bp_caps |=
+					    (DISC_CAP | DISC_DIS_CAP |
+					     DISC_PWUP_CTL_CAP);
+				if ((cap_reg & TPL2_SUPPORT_MASK) ==
+				    TPL2_SUPPORT_MASK) {
+					pbpctl_dev->bp_caps_ex |= TPL2_CAP_EX;
+					pbpctl_dev->bp_caps |= TPL_CAP;
+					pbpctl_dev->bp_tpl_flag =
+					    tpl2_flag_status(pbpctl_dev);
+				}
+
+			}
+
+			if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER9) {
+				if ((cap_reg & DISC_PORT_SUPPORT_MASK) ==
+				    DISC_PORT_SUPPORT_MASK) {
+					pbpctl_dev->bp_caps_ex |=
+					    DISC_PORT_CAP_EX;
+					pbpctl_dev->bp_caps |=
+					    (TX_CTL_CAP | TX_STATUS_CAP);
+				}
+
+			}
+
+		}
+		if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
+			if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
+			    WDT_EN_MASK)
+				pbpctl_dev->wdt_status = WDT_STATUS_EN;
+			else
+				pbpctl_dev->wdt_status = WDT_STATUS_DIS;
+		}
+
+	} else if ((P2BPFI_IF_SERIES(pbpctl_dev->subdevice)) ||
+		   (PEGF5_IF_SERIES(pbpctl_dev->subdevice)) ||
+		   (PEGF80_IF_SERIES(pbpctl_dev->subdevice)) ||
+		   (BP10G9_IF_SERIES(pbpctl_dev->subdevice))) {
+		pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP);
+	}
+	if ((pbpctl_dev->subdevice & 0xa00) == 0xa00)
+		pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP);
+	if (PEG5_IF_SERIES(pbpctl_dev->subdevice))
+		pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP);
+
+	if (BP10GB_IF_SERIES(pbpctl_dev->subdevice)) {
+		pbpctl_dev->bp_caps &= ~(TX_CTL_CAP | TX_STATUS_CAP);
+	}
+	pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+	if (pbpctl_dev_m != NULL) {
+		int cap_reg = 0;
+		if (pbpctl_dev_m->bp_ext_ver >= 0x9) {
+			cap_reg = get_bp_prod_caps(pbpctl_dev_m);
+			if ((cap_reg & DISC_PORT_SUPPORT_MASK) ==
+			    DISC_PORT_SUPPORT_MASK)
+				pbpctl_dev->bp_caps |=
+				    (TX_CTL_CAP | TX_STATUS_CAP);
+			pbpctl_dev->bp_caps_ex |= DISC_PORT_CAP_EX;
+		}
+	}
+}
+
+int bypass_off_init(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+		return dis_bypass_cap(pbpctl_dev);
+	wdt_off(pbpctl_dev);
+	if (pbpctl_dev->bp_caps & BP_CAP)
+		bypass_off(pbpctl_dev);
+	if (pbpctl_dev->bp_caps & TAP_CAP)
+		tap_off(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+	return 0;
+}
+
+void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+{
+#ifdef BP_SELF_TEST
+	bpctl_dev_t *pbpctl_dev_sl = NULL;
+#endif
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+
+		del_timer_sync(&pbpctl_dev->bp_timer);
+#ifdef BP_SELF_TEST
+		pbpctl_dev_sl = get_status_port_fn(pbpctl_dev);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31))
+		if (pbpctl_dev_sl && (pbpctl_dev_sl->ndev)
+		    && (pbpctl_dev_sl->ndev->hard_start_xmit)
+		    && (pbpctl_dev_sl->hard_start_xmit_save)) {
+			rtnl_lock();
+			pbpctl_dev_sl->ndev->hard_start_xmit =
+			    pbpctl_dev_sl->hard_start_xmit_save;
+			rtnl_unlock();
+		}
+#else
+		if (pbpctl_dev_sl && (pbpctl_dev_sl->ndev)) {
+			if ((pbpctl_dev_sl->ndev->netdev_ops)
+			    && (pbpctl_dev_sl->old_ops)) {
+				rtnl_lock();
+				pbpctl_dev_sl->ndev->netdev_ops =
+				    pbpctl_dev_sl->old_ops;
+				pbpctl_dev_sl->old_ops = NULL;
+
+				rtnl_unlock();
+
+			}
+
+		}
+
+#endif
+#endif
+	}
+
+}
+
+int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+{
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		init_timer(&pbpctl_dev->bp_timer);
+		pbpctl_dev->bp_timer.function = &wd_reset_timer;
+		pbpctl_dev->bp_timer.data = (unsigned long)pbpctl_dev;
+		return 1;
+	}
+	return BP_NOT_CAP;
+}
+
+#ifdef BP_SELF_TEST
+int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
+	int idx_dev = 0;
+	struct ethhdr *eth = (struct ethhdr *)skb->data;
+
+	for (idx_dev = 0;
+	     ((bpctl_dev_arr[idx_dev].ndev != NULL) && (idx_dev < device_num));
+	     idx_dev++) {
+		if (bpctl_dev_arr[idx_dev].ndev == dev) {
+			pbpctl_dev = &bpctl_dev_arr[idx_dev];
+			break;
+		}
+	}
+	if (!pbpctl_dev)
+		return 1;
+	if ((htons(ETH_P_BPTEST) == eth->h_proto)) {
+
+		pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
+		if (pbpctl_dev_m) {
+
+			if (bypass_status(pbpctl_dev_m)) {
+				cmnd_on(pbpctl_dev_m);
+				bypass_off(pbpctl_dev_m);
+				cmnd_off(pbpctl_dev_m);
+			}
+			wdt_timer_reload(pbpctl_dev_m);
+		}
+		dev_kfree_skb_irq(skb);
+		return 0;
+	}
+	return pbpctl_dev->hard_start_xmit_save(skb, dev);
+}
+#endif
+
+int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+{
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (pbpctl_dev->reset_time != param) {
+			if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+				pbpctl_dev->reset_time =
+				    (param <
+				     WDT_AUTO_MIN_INT) ? WDT_AUTO_MIN_INT :
+				    param;
+			else
+				pbpctl_dev->reset_time = param;
+			if (param)
+				mod_timer(&pbpctl_dev->bp_timer, jiffies);
+		}
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		return pbpctl_dev->reset_time;
+	}
+	return BP_NOT_CAP;
+}
+
+#ifdef  BP_SELF_TEST
+
+int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param)
+{
+	bpctl_dev_t *pbpctl_dev_sl = NULL;
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		pbpctl_dev->bp_self_test_flag = param == 0 ? 0 : 1;
+		pbpctl_dev_sl = get_status_port_fn(pbpctl_dev);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31))
+		if ((pbpctl_dev_sl->ndev) &&
+		    (pbpctl_dev_sl->ndev->hard_start_xmit)) {
+			rtnl_lock();
+			if (pbpctl_dev->bp_self_test_flag == 1) {
+
+				pbpctl_dev_sl->hard_start_xmit_save =
+				    pbpctl_dev_sl->ndev->hard_start_xmit;
+				pbpctl_dev_sl->ndev->hard_start_xmit =
+				    bp_hard_start_xmit;
+			} else if (pbpctl_dev_sl->hard_start_xmit_save) {
+				pbpctl_dev_sl->ndev->hard_start_xmit =
+				    pbpctl_dev_sl->hard_start_xmit_save;
+			}
+			rtnl_unlock();
+		}
+#else
+		if ((pbpctl_dev_sl->ndev) && (pbpctl_dev_sl->ndev->netdev_ops)) {
+			rtnl_lock();
+			if (pbpctl_dev->bp_self_test_flag == 1) {
+
+				pbpctl_dev_sl->old_ops =
+				    pbpctl_dev_sl->ndev->netdev_ops;
+				pbpctl_dev_sl->new_ops =
+				    *pbpctl_dev_sl->old_ops;
+				pbpctl_dev_sl->new_ops.ndo_start_xmit =
+				    bp_hard_start_xmit;
+				pbpctl_dev_sl->ndev->netdev_ops =
+				    &pbpctl_dev_sl->new_ops;
+
+			} else if (pbpctl_dev_sl->old_ops) {
+				pbpctl_dev_sl->ndev->netdev_ops =
+				    pbpctl_dev_sl->old_ops;
+				pbpctl_dev_sl->old_ops = NULL;
+			}
+			rtnl_unlock();
+		}
+#endif
+
+		set_bypass_wd_auto(pbpctl_dev, param);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_bp_self_test(bpctl_dev_t *pbpctl_dev)
+{
+
+	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
+		if (pbpctl_dev->bp_self_test_flag == 1)
+			return pbpctl_dev->reset_time;
+		else
+			return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+#endif
+
+/**************************************************************/
+/************************* API ********************************/
+/**************************************************************/
+
+int is_bypass_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0);
+}
+
+int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+{
+	int ret = 0;
+
+	if (!(pbpctl_dev->bp_caps & BP_CAP))
+		return BP_NOT_CAP;
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (!bypass_mode)
+		ret = bypass_off(pbpctl_dev);
+	else
+		ret = bypass_on(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+
+	return ret;
+}
+
+int get_bypass_fn(bpctl_dev_t *pbpctl_dev)
+{
+	return bypass_status(pbpctl_dev);
+}
+
+int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return bypass_change_status(pbpctl_dev);
+}
+
+int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!(pbpctl_dev->bp_caps & BP_DIS_CAP))
+		return BP_NOT_CAP;
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (dis_param)
+		ret = dis_bypass_cap(pbpctl_dev);
+	else
+		ret = en_bypass_cap(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+	return ret;
+}
+
+int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return dis_bypass_cap_status(pbpctl_dev);
+}
+
+int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!(pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP))
+		return BP_NOT_CAP;
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (bypass_mode)
+		ret = bypass_state_pwroff(pbpctl_dev);
+	else
+		ret = normal_state_pwroff(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+	return ret;
+}
+
+int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return default_pwroff_status(pbpctl_dev);
+}
+
+int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!(pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP))
+		return BP_NOT_CAP;
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (bypass_mode)
+		ret = bypass_state_pwron(pbpctl_dev);
+	else
+		ret = normal_state_pwron(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+	return ret;
+}
+
+int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return default_pwron_status(pbpctl_dev);
+}
+
+int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!(pbpctl_dev->bp_caps & WD_CTL_CAP))
+		return BP_NOT_CAP;
+
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (!timeout)
+		ret = wdt_off(pbpctl_dev);
+	else {
+		wdt_on(pbpctl_dev, timeout);
+		ret = pbpctl_dev->bypass_timer_interval;
+	}
+	cmnd_off(pbpctl_dev);
+	return ret;
+}
+
+int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return wdt_programmed(pbpctl_dev, timeout);
+}
+
+int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return wdt_timer(pbpctl_dev, time_left);
+}
+
+int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return wdt_timer_reload(pbpctl_dev);
+}
+
+int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int bp_status = 0;
+
+	unsigned int step_value = TIMEOUT_MAX_STEP + 1, bit_cnt = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
+		return BP_NOT_CAP;
+
+	while ((step_value >>= 1))
+		bit_cnt++;
+
+	if (is_bypass_fn(pbpctl_dev)) {
+		bp_status =
+		    WD_STEP_COUNT_MASK(bit_cnt) | WDT_STEP_TIME |
+		    WD_MIN_TIME_MASK(TIMEOUT_UNIT / 100);
+	} else
+		return -1;
+
+	return bp_status;
+}
+
+int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!(pbpctl_dev->bp_caps & STD_NIC_CAP))
+		return BP_NOT_CAP;
+
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	if (nic_mode)
+		ret = std_nic_on(pbpctl_dev);
+	else
+		ret = std_nic_off(pbpctl_dev);
+	cmnd_off(pbpctl_dev);
+	return ret;
+}
+
+int get_std_nic_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return std_nic_status(pbpctl_dev);
+}
+
+int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & TAP_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (!tap_mode)
+			tap_off(pbpctl_dev);
+		else
+			tap_on(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_tap_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return tap_status(pbpctl_dev);
+}
+
+int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)
+	    && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (tap_mode)
+			ret = tap_state_pwron(pbpctl_dev);
+		else
+			ret = normal_state_pwron(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((ret = default_pwron_tap_status(pbpctl_dev)) < 0)
+		return ret;
+	return ((ret == 0) ? 1 : 0);
+}
+
+int get_tap_change_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return tap_change_status(pbpctl_dev);
+}
+
+int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & TAP_DIS_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (dis_param)
+			ret = dis_tap_cap(pbpctl_dev);
+		else
+			ret = en_tap_cap(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+		return ret;
+	} else
+		return BP_NOT_CAP;
+}
+
+int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return dis_tap_cap_status(pbpctl_dev);
+}
+
+int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & DISC_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (!disc_mode)
+			disc_off(pbpctl_dev);
+		else
+			disc_on(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+
+		return BP_OK;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_disc_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	ret = disc_status(pbpctl_dev);
+
+	return ret;
+}
+
+int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP)
+	    && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (disc_mode)
+			ret = disc_state_pwron(pbpctl_dev);
+		else
+			ret = normal_state_pwron(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+	} else
+		ret = BP_NOT_CAP;
+	return ret;
+}
+
+int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	ret = default_pwron_disc_status(pbpctl_dev);
+	return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0));
+}
+
+int get_disc_change_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	ret = disc_change_status(pbpctl_dev);
+	return ret;
+}
+
+int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & DISC_DIS_CAP)
+	    && ((cmnd_on(pbpctl_dev)) >= 0)) {
+		if (dis_param)
+			ret = dis_disc_cap(pbpctl_dev);
+		else
+			ret = en_disc_cap(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+		return ret;
+	} else
+		return BP_NOT_CAP;
+}
+
+int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	ret = dis_disc_cap_status(pbpctl_dev);
+
+	return ret;
+}
+
+int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+{
+	int ret = BP_NOT_CAP;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!disc_mode)
+		ret = disc_port_off(pbpctl_dev);
+	else
+		ret = disc_port_on(pbpctl_dev);
+
+	return ret;
+}
+
+int get_disc_port_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return disc_port_status(pbpctl_dev);
+}
+
+int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+{
+	int ret = BP_NOT_CAP;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (!disc_mode)
+		ret = normal_port_state_pwron(pbpctl_dev);
+	else
+		ret = disc_port_state_pwron(pbpctl_dev);
+
+	return ret;
+}
+
+int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((ret = default_pwron_disc_port_status(pbpctl_dev)) < 0)
+		return ret;
+	return ((ret == 0) ? 1 : 0);
+}
+
+int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return wdt_exp_mode_status(pbpctl_dev);
+}
+
+int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return wdt_exp_mode(pbpctl_dev, param);
+}
+
+int reset_cont_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((ret = cmnd_on(pbpctl_dev)) < 0)
+		return ret;
+	return reset_cont(pbpctl_dev);
+}
+
+int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state)
+{
+
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & TPL_CAP) &&
+	    (pbpctl_dev->bp_caps & SW_CTL_CAP)) {
+		if ((pbpctl_dev->bp_tpl_flag))
+			return BP_NOT_CAP;
+	} else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) {
+		if ((pbpctl_dev_b->bp_caps & TPL_CAP) &&
+		    (pbpctl_dev_b->bp_tpl_flag))
+			return BP_NOT_CAP;
+	}
+	return set_tx(pbpctl_dev, tx_state);
+}
+
+int set_bp_force_link_fn(int dev_num, int tx_state)
+{
+	static bpctl_dev_t *bpctl_dev_curr;
+
+	if ((dev_num < 0) || (dev_num > device_num)
+	    || (bpctl_dev_arr[dev_num].pdev == NULL))
+		return -1;
+	bpctl_dev_curr = &bpctl_dev_arr[dev_num];
+
+	return set_bp_force_link(bpctl_dev_curr, tx_state);
+}
+
+int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return set_bypass_wd_auto(pbpctl_dev, param);
+}
+
+int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return get_bypass_wd_auto(pbpctl_dev);
+}
+
+#ifdef BP_SELF_TEST
+int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return set_bp_self_test(pbpctl_dev, param);
+}
+
+int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return get_bp_self_test(pbpctl_dev);
+}
+
+#endif
+
+int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	return pbpctl_dev->bp_caps;
+
+}
+
+int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out)
+{
+	int idx_dev = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) {
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus)
+			    && (bpctl_dev_arr[idx_dev].slot ==
+				pbpctl_dev->slot)) {
+				if ((pbpctl_dev->func == 0)
+				    && (bpctl_dev_arr[idx_dev].func == 1)) {
+					*pbpctl_dev_out =
+					    &bpctl_dev_arr[idx_dev];
+					return 1;
+				}
+				if ((pbpctl_dev->func == 2) &&
+				    (bpctl_dev_arr[idx_dev].func == 3)) {
+					*pbpctl_dev_out =
+					    &bpctl_dev_arr[idx_dev];
+					return 1;
+				}
+			}
+		}
+		return -1;
+	} else
+		return 0;
+}
+
+int is_bypass(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2))
+		return 1;
+	else
+		return 0;
+}
+
+int get_tx_fn(bpctl_dev_t *pbpctl_dev)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+	if (!pbpctl_dev)
+		return -1;
+
+	if ((pbpctl_dev->bp_caps & TPL_CAP) &&
+	    (pbpctl_dev->bp_caps & SW_CTL_CAP)) {
+		if ((pbpctl_dev->bp_tpl_flag))
+			return BP_NOT_CAP;
+	} else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) {
+		if ((pbpctl_dev_b->bp_caps & TPL_CAP) &&
+		    (pbpctl_dev_b->bp_tpl_flag))
+			return BP_NOT_CAP;
+	}
+	return tx_status(pbpctl_dev);
+}
+
+int get_bp_force_link_fn(int dev_num)
+{
+	static bpctl_dev_t *bpctl_dev_curr;
+
+	if ((dev_num < 0) || (dev_num > device_num)
+	    || (bpctl_dev_arr[dev_num].pdev == NULL))
+		return -1;
+	bpctl_dev_curr = &bpctl_dev_arr[dev_num];
+
+	return bp_force_link_status(bpctl_dev_curr);
+}
+
+static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->media_type == bp_fiber)
+		return ((BPCTL_READ_REG(pbpctl_dev, CTRL) &
+			 BPCTLI_CTRL_SWDPIN1));
+	else
+		return ((BPCTL_READ_REG(pbpctl_dev, STATUS) &
+			 BPCTLI_STATUS_LU));
+
+}
+
+static void bp_tpl_timer_fn(unsigned long param)
+{
+	bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+	uint32_t link1, link2;
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+
+	if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+		return;
+
+	if (!pbpctl_dev->bp_tpl_flag) {
+		set_tx(pbpctl_dev_b, 1);
+		set_tx(pbpctl_dev, 1);
+		return;
+	}
+	link1 = get_bypass_link_status(pbpctl_dev);
+
+	link2 = get_bypass_link_status(pbpctl_dev_b);
+	if ((link1) && (tx_status(pbpctl_dev))) {
+		if ((!link2) && (tx_status(pbpctl_dev_b))) {
+			set_tx(pbpctl_dev, 0);
+		} else if (!tx_status(pbpctl_dev_b)) {
+			set_tx(pbpctl_dev_b, 1);
+		}
+	} else if ((!link1) && (tx_status(pbpctl_dev))) {
+		if ((link2) && (tx_status(pbpctl_dev_b))) {
+			set_tx(pbpctl_dev_b, 0);
+		}
+	} else if ((link1) && (!tx_status(pbpctl_dev))) {
+		if ((link2) && (tx_status(pbpctl_dev_b))) {
+			set_tx(pbpctl_dev, 1);
+		}
+	} else if ((!link1) && (!tx_status(pbpctl_dev))) {
+		if ((link2) && (tx_status(pbpctl_dev_b))) {
+			set_tx(pbpctl_dev, 1);
+		}
+	}
+
+	mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ);
+}
+
+void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+{
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+	if (!pbpctl_dev)
+		return;
+	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
+
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		del_timer_sync(&pbpctl_dev->bp_tpl_timer);
+		pbpctl_dev->bp_tpl_flag = 0;
+		pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
+		if (pbpctl_dev_b)
+			set_tx(pbpctl_dev_b, 1);
+		set_tx(pbpctl_dev, 1);
+	}
+	return;
+}
+
+int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		init_timer(&pbpctl_dev->bp_tpl_timer);
+		pbpctl_dev->bp_tpl_timer.function = &bp_tpl_timer_fn;
+		pbpctl_dev->bp_tpl_timer.data = (unsigned long)pbpctl_dev;
+		return BP_OK;
+	}
+	return BP_NOT_CAP;
+}
+
+int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+{
+	if (!pbpctl_dev)
+		return -1;
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		if ((param) && (!pbpctl_dev->bp_tpl_flag)) {
+			pbpctl_dev->bp_tpl_flag = param;
+			mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + 1);
+			return BP_OK;
+		};
+		if ((!param) && (pbpctl_dev->bp_tpl_flag))
+			remove_bypass_tpl_auto(pbpctl_dev);
+
+		return BP_OK;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+{
+	if (!pbpctl_dev)
+		return -1;
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		return pbpctl_dev->bp_tpl_flag;
+	}
+	return BP_NOT_CAP;
+}
+
+int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode)
+{
+
+	bpctl_dev_t *pbpctl_dev_b = NULL;
+	if (!pbpctl_dev)
+		return -1;
+
+	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
+
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		if (tpl_mode) {
+			if ((pbpctl_dev_b = get_status_port_fn(pbpctl_dev)))
+				set_tx(pbpctl_dev_b, 1);
+			set_tx(pbpctl_dev, 1);
+		}
+		if ((TPL_IF_SERIES(pbpctl_dev->subdevice)) ||
+		    (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX)) {
+			pbpctl_dev->bp_tpl_flag = tpl_mode;
+			if (!tpl_mode)
+				tpl_hw_off(pbpctl_dev);
+			else
+				tpl_hw_on(pbpctl_dev);
+		} else
+			set_bypass_tpl_auto(pbpctl_dev, tpl_mode);
+		return 0;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_tpl_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = BP_NOT_CAP;
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_caps & TPL_CAP) {
+		if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX)
+			return tpl2_flag_status(pbpctl_dev);
+		ret = pbpctl_dev->bp_tpl_flag;
+	}
+	return ret;
+}
+
+int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		/* bp_lock(pbp_device_block); */
+		cmnd_on(pbpctl_dev);
+		if (!tap_mode)
+			bp_wait_at_pwup_dis(pbpctl_dev);
+		else
+			bp_wait_at_pwup_en(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+
+		/* bp_unlock(pbp_device_block); */
+		return BP_OK;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	/* bp_lock(pbp_device_block); */
+	ret = bp_wait_at_pwup_status(pbpctl_dev);
+	/* bp_unlock(pbp_device_block); */
+
+	return ret;
+}
+
+int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+{
+	if (!pbpctl_dev)
+		return -1;
+
+	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
+		/*   bp_lock(pbp_device_block); */
+		cmnd_on(pbpctl_dev);
+
+		if (!tap_mode)
+			bp_hw_reset_dis(pbpctl_dev);
+		else
+			bp_hw_reset_en(pbpctl_dev);
+		cmnd_off(pbpctl_dev);
+		/*    bp_unlock(pbp_device_block); */
+		return BP_OK;
+	}
+	return BP_NOT_CAP;
+}
+
+int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev)
+{
+	int ret = 0;
+	if (!pbpctl_dev)
+		return -1;
+
+	/* bp_lock(pbp_device_block); */
+	ret = bp_hw_reset_status(pbpctl_dev);
+
+	/* bp_unlock(pbp_device_block); */
+
+	return ret;
+}
+
+
+int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name,
+		       char *add_param)
+{
+	if (!pbpctl_dev)
+		return -1;
+	if (!is_bypass_fn(pbpctl_dev))
+		return -1;
+	strcpy(dev_name, pbpctl_dev->name);
+	*add_param = pbpctl_dev->bp_fw_ver;
+	return 0;
+}
+
+int get_dev_idx_bsf(int bus, int slot, int func)
+{
+	int idx_dev = 0;
+	for (idx_dev = 0;
+	     ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num));
+	     idx_dev++) {
+		if ((bus == bpctl_dev_arr[idx_dev].bus)
+		    && (slot == bpctl_dev_arr[idx_dev].slot)
+		    && (func == bpctl_dev_arr[idx_dev].func))
+
+			return idx_dev;
+	}
+	return -1;
+}
+
+static void str_low(char *str)
+{
+	int i;
+
+	for (i = 0; i < strlen(str); i++)
+		if ((str[i] >= 65) && (str[i] <= 90))
+			str[i] += 32;
+}
+
+static unsigned long str_to_hex(char *p)
+{
+	unsigned long hex = 0;
+	unsigned long length = strlen(p), shift = 0;
+	unsigned char dig = 0;
+
+	str_low(p);
+	length = strlen(p);
+
+	if (length == 0)
+		return 0;
+
+	do {
+		dig = p[--length];
+		dig = dig < 'a' ? (dig - '0') : (dig - 'a' + 0xa);
+		hex |= (dig << shift);
+		shift += 4;
+	} while (length);
+	return hex;
+}
+
+static int get_dev_idx(int ifindex)
+{
+	int idx_dev = 0;
+
+	for (idx_dev = 0;
+	     ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num));
+	     idx_dev++) {
+		if (ifindex == bpctl_dev_arr[idx_dev].ifindex)
+			return idx_dev;
+	}
+
+	return -1;
+}
+
+static bpctl_dev_t *get_dev_idx_p(int ifindex)
+{
+	int idx_dev = 0;
+
+	for (idx_dev = 0;
+	     ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num));
+	     idx_dev++) {
+		if (ifindex == bpctl_dev_arr[idx_dev].ifindex)
+			return &bpctl_dev_arr[idx_dev];
+	}
+
+	return NULL;
+}
+
+static void if_scan_init(void)
+{
+	int idx_dev = 0;
+	struct net_device *dev;
+	int ifindex;
+	/* rcu_read_lock(); */
+	/* rtnl_lock();     */
+	/* rcu_read_lock(); */
+#if 1
+#if (LINUX_VERSION_CODE >= 0x020618)
+	for_each_netdev(&init_net, dev)
+#elif (LINUX_VERSION_CODE >= 0x20616)
+	for_each_netdev(dev)
+#else
+	for (dev = dev_base; dev; dev = dev->next)
+#endif
+	{
+
+		struct ethtool_drvinfo drvinfo;
+		char cbuf[32];
+		char *buf = NULL;
+		char res[10];
+		int i = 0;
+		int bus = 0, slot = 0, func = 0;
+		ifindex = dev->ifindex;
+
+		memset(res, 0, 10);
+		memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
+
+		if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+			memset(&drvinfo, 0, sizeof(drvinfo));
+			dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
+		} else
+			continue;
+		if (!drvinfo.bus_info)
+			continue;
+		if (!strcmp(drvinfo.bus_info, "N/A"))
+			continue;
+		memcpy(&cbuf, drvinfo.bus_info, 32);
+		buf = &cbuf[0];
+
+		while (*buf++ != ':') ;
+		for (i = 0; i < 10; i++, buf++) {
+			if (*buf == ':')
+				break;
+			res[i] = *buf;
+
+		}
+		buf++;
+		bus = str_to_hex(res);
+		memset(res, 0, 10);
+
+		for (i = 0; i < 10; i++, buf++) {
+			if (*buf == '.')
+				break;
+			res[i] = *buf;
+
+		}
+		buf++;
+		slot = str_to_hex(res);
+		func = str_to_hex(buf);
+		idx_dev = get_dev_idx_bsf(bus, slot, func);
+
+		if (idx_dev != -1) {
+
+			bpctl_dev_arr[idx_dev].ifindex = ifindex;
+			bpctl_dev_arr[idx_dev].ndev = dev;
+
+		}
+
+	}
+#endif
+	/* rtnl_unlock();     */
+	/* rcu_read_unlock(); */
+
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
+static int device_ioctl(struct inode *inode,	/* see include/linux/fs.h */
+			struct file *file,	/* ditto */
+			unsigned int ioctl_num,	/* number and param for ioctl */
+			unsigned long ioctl_param)
+#else
+static long device_ioctl(struct file *file,	/* ditto */
+			 unsigned int ioctl_num,	/* number and param for ioctl */
+			 unsigned long ioctl_param)
+#endif
+{
+	struct bpctl_cmd bpctl_cmd;
+	int dev_idx = 0;
+	bpctl_dev_t *pbpctl_dev_out;
+	void __user *argp = (void __user *)ioctl_param;
+	int ret = 0;
+	unsigned long flags;
+
+	static bpctl_dev_t *pbpctl_dev;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
+	/* lock_kernel(); */
+#endif
+	lock_bpctl();
+	/* local_irq_save(flags); */
+	/* if(!spin_trylock_irqsave(&bpvm_lock)){
+	   local_irq_restore(flags);
+	   unlock_bpctl();
+	   unlock_kernel();
+	   return -1;
+	   } */
+	/* spin_lock_irqsave(&bpvm_lock, flags); */
+
+/*
+* Switch according to the ioctl called
+*/
+	if (ioctl_num == IOCTL_TX_MSG(IF_SCAN)) {
+		if_scan_init();
+		ret = SUCCESS;
+		goto bp_exit;
+	}
+	if (copy_from_user(&bpctl_cmd, argp, sizeof(struct bpctl_cmd))) {
+
+		ret = -EFAULT;
+		goto bp_exit;
+	}
+
+	if (ioctl_num == IOCTL_TX_MSG(GET_DEV_NUM)) {
+		bpctl_cmd.out_param[0] = device_num;
+		if (copy_to_user
+		    (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) {
+			ret = -EFAULT;
+			goto bp_exit;
+		}
+		ret = SUCCESS;
+		goto bp_exit;
+
+	}
+	/* lock_bpctl();      */
+	/* preempt_disable(); */
+	local_irq_save(flags);
+	if (!spin_trylock(&bpvm_lock)) {
+		local_irq_restore(flags);
+		unlock_bpctl();
+		return -1;
+	}
+
+/*    	preempt_disable();
+	rcu_read_lock();
+      	spin_lock_irqsave(&bpvm_lock, flags);
+*/
+	if ((bpctl_cmd.in_param[5]) ||
+	    (bpctl_cmd.in_param[6]) || (bpctl_cmd.in_param[7]))
+		dev_idx = get_dev_idx_bsf(bpctl_cmd.in_param[5],
+					  bpctl_cmd.in_param[6],
+					  bpctl_cmd.in_param[7]);
+	else if (bpctl_cmd.in_param[1] == 0)
+		dev_idx = bpctl_cmd.in_param[0];
+	else
+		dev_idx = get_dev_idx(bpctl_cmd.in_param[1]);
+
+	if (dev_idx < 0 || dev_idx > device_num) {
+		/* unlock_bpctl();
+		   preempt_enable(); */
+		ret = -EOPNOTSUPP;
+		/* preempt_enable();
+		   rcu_read_unlock();  */
+		spin_unlock_irqrestore(&bpvm_lock, flags);
+		goto bp_exit;
+	}
+
+	bpctl_cmd.out_param[0] = bpctl_dev_arr[dev_idx].bus;
+	bpctl_cmd.out_param[1] = bpctl_dev_arr[dev_idx].slot;
+	bpctl_cmd.out_param[2] = bpctl_dev_arr[dev_idx].func;
+	bpctl_cmd.out_param[3] = bpctl_dev_arr[dev_idx].ifindex;
+
+	if ((bpctl_dev_arr[dev_idx].bp_10gb)
+	    && (!(bpctl_dev_arr[dev_idx].ifindex))) {
+		printk("Please load network driver for %s adapter!\n",
+		       bpctl_dev_arr[dev_idx].name);
+		bpctl_cmd.status = -1;
+		ret = SUCCESS;
+		/* preempt_enable(); */
+		/* rcu_read_unlock(); */
+		spin_unlock_irqrestore(&bpvm_lock, flags);
+		goto bp_exit;
+
+	}
+	if ((bpctl_dev_arr[dev_idx].bp_10gb) && (bpctl_dev_arr[dev_idx].ndev)) {
+		if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) {
+			if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) {
+				printk
+				    ("Please bring up network interfaces for %s adapter!\n",
+				     bpctl_dev_arr[dev_idx].name);
+				bpctl_cmd.status = -1;
+				ret = SUCCESS;
+				/* preempt_enable(); */
+				/* rcu_read_unlock(); */
+				spin_unlock_irqrestore(&bpvm_lock, flags);
+				goto bp_exit;
+			}
+
+		}
+	}
+
+	if ((dev_idx < 0) || (dev_idx > device_num)
+	    || (bpctl_dev_arr[dev_idx].pdev == NULL)) {
+		bpctl_cmd.status = -1;
+		goto bpcmd_exit;
+	}
+
+	pbpctl_dev = &bpctl_dev_arr[dev_idx];
+
+	switch (ioctl_num) {
+	case IOCTL_TX_MSG(SET_BYPASS_PWOFF):
+		bpctl_cmd.status =
+		    set_bypass_pwoff_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_PWOFF):
+		bpctl_cmd.status = get_bypass_pwoff_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_BYPASS_PWUP):
+		bpctl_cmd.status =
+		    set_bypass_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_PWUP):
+		bpctl_cmd.status = get_bypass_pwup_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_BYPASS_WD):
+		bpctl_cmd.status =
+		    set_bypass_wd_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_WD):
+		bpctl_cmd.status =
+		    get_bypass_wd_fn(pbpctl_dev, (int *)&(bpctl_cmd.data[0]));
+		break;
+
+	case IOCTL_TX_MSG(GET_WD_EXPIRE_TIME):
+		bpctl_cmd.status =
+		    get_wd_expire_time_fn(pbpctl_dev,
+					  (int *)&(bpctl_cmd.data[0]));
+		break;
+
+	case IOCTL_TX_MSG(RESET_BYPASS_WD_TIMER):
+		bpctl_cmd.status = reset_bypass_wd_timer_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(GET_WD_SET_CAPS):
+		bpctl_cmd.status = get_wd_set_caps_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_STD_NIC):
+		bpctl_cmd.status =
+		    set_std_nic_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_STD_NIC):
+		bpctl_cmd.status = get_std_nic_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_TAP):
+		bpctl_cmd.status =
+		    set_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_TAP):
+		bpctl_cmd.status = get_tap_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(GET_TAP_CHANGE):
+		bpctl_cmd.status = get_tap_change_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_DIS_TAP):
+		bpctl_cmd.status =
+		    set_dis_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_DIS_TAP):
+		bpctl_cmd.status = get_dis_tap_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_TAP_PWUP):
+		bpctl_cmd.status =
+		    set_tap_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_TAP_PWUP):
+		bpctl_cmd.status = get_tap_pwup_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_WD_EXP_MODE):
+		bpctl_cmd.status =
+		    set_wd_exp_mode_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_WD_EXP_MODE):
+		bpctl_cmd.status = get_wd_exp_mode_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(GET_DIS_BYPASS):
+		bpctl_cmd.status = get_dis_bypass_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_DIS_BYPASS):
+		bpctl_cmd.status =
+		    set_dis_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_CHANGE):
+		bpctl_cmd.status = get_bypass_change_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS):
+		bpctl_cmd.status = get_bypass_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_BYPASS):
+		bpctl_cmd.status =
+		    set_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_CAPS):
+		bpctl_cmd.status = get_bypass_caps_fn(pbpctl_dev);
+		/*preempt_enable(); */
+		/*rcu_read_unlock();*/
+		spin_unlock_irqrestore(&bpvm_lock, flags);
+		if (copy_to_user
+		    (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) {
+			/*unlock_bpctl();   */
+			/*preempt_enable(); */
+			ret = -EFAULT;
+			goto bp_exit;
+		}
+		goto bp_exit;
+
+	case IOCTL_TX_MSG(GET_BYPASS_SLAVE):
+		bpctl_cmd.status =
+		    get_bypass_slave_fn(pbpctl_dev, &pbpctl_dev_out);
+		if (bpctl_cmd.status == 1) {
+			bpctl_cmd.out_param[4] = pbpctl_dev_out->bus;
+			bpctl_cmd.out_param[5] = pbpctl_dev_out->slot;
+			bpctl_cmd.out_param[6] = pbpctl_dev_out->func;
+			bpctl_cmd.out_param[7] = pbpctl_dev_out->ifindex;
+		}
+		break;
+
+	case IOCTL_TX_MSG(IS_BYPASS):
+		bpctl_cmd.status = is_bypass(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_TX):
+		bpctl_cmd.status = set_tx_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+	case IOCTL_TX_MSG(GET_TX):
+		bpctl_cmd.status = get_tx_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_WD_AUTORESET):
+		bpctl_cmd.status =
+		    set_wd_autoreset_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+
+		break;
+	case IOCTL_TX_MSG(GET_WD_AUTORESET):
+
+		bpctl_cmd.status = get_wd_autoreset_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_DISC):
+		bpctl_cmd.status =
+		    set_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+	case IOCTL_TX_MSG(GET_DISC):
+		bpctl_cmd.status = get_disc_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(GET_DISC_CHANGE):
+		bpctl_cmd.status = get_disc_change_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_DIS_DISC):
+		bpctl_cmd.status =
+		    set_dis_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+	case IOCTL_TX_MSG(GET_DIS_DISC):
+		bpctl_cmd.status = get_dis_disc_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_DISC_PWUP):
+		bpctl_cmd.status =
+		    set_disc_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+	case IOCTL_TX_MSG(GET_DISC_PWUP):
+		bpctl_cmd.status = get_disc_pwup_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(GET_BYPASS_INFO):
+
+		bpctl_cmd.status =
+		    get_bypass_info_fn(pbpctl_dev, (char *)&bpctl_cmd.data,
+				       (char *)&bpctl_cmd.out_param[4]);
+		break;
+
+	case IOCTL_TX_MSG(SET_TPL):
+		bpctl_cmd.status =
+		    set_tpl_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_TPL):
+		bpctl_cmd.status = get_tpl_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_BP_WAIT_AT_PWUP):
+		bpctl_cmd.status =
+		    set_bp_wait_at_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BP_WAIT_AT_PWUP):
+		bpctl_cmd.status = get_bp_wait_at_pwup_fn(pbpctl_dev);
+		break;
+	case IOCTL_TX_MSG(SET_BP_HW_RESET):
+		bpctl_cmd.status =
+		    set_bp_hw_reset_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BP_HW_RESET):
+		bpctl_cmd.status = get_bp_hw_reset_fn(pbpctl_dev);
+		break;
+#ifdef BP_SELF_TEST
+	case IOCTL_TX_MSG(SET_BP_SELF_TEST):
+		bpctl_cmd.status =
+		    set_bp_self_test_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+
+		break;
+	case IOCTL_TX_MSG(GET_BP_SELF_TEST):
+		bpctl_cmd.status = get_bp_self_test_fn(pbpctl_dev);
+		break;
+
+#endif
+#if 0
+	case IOCTL_TX_MSG(SET_DISC_PORT):
+		bpctl_cmd.status =
+		    set_disc_port_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_DISC_PORT):
+		bpctl_cmd.status = get_disc_port_fn(pbpctl_dev);
+		break;
+
+	case IOCTL_TX_MSG(SET_DISC_PORT_PWUP):
+		bpctl_cmd.status =
+		    set_disc_port_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_DISC_PORT_PWUP):
+		bpctl_cmd.status = get_disc_port_pwup_fn(pbpctl_dev);
+		break;
+#endif
+	case IOCTL_TX_MSG(SET_BP_FORCE_LINK):
+		bpctl_cmd.status =
+		    set_bp_force_link_fn(dev_idx, bpctl_cmd.in_param[2]);
+		break;
+
+	case IOCTL_TX_MSG(GET_BP_FORCE_LINK):
+		bpctl_cmd.status = get_bp_force_link_fn(dev_idx);
+		break;
+
+	default:
+		/*    unlock_bpctl(); */
+
+		ret = -EOPNOTSUPP;
+		/* preempt_enable(); */
+		/* rcu_read_unlock();*/
+		spin_unlock_irqrestore(&bpvm_lock, flags);
+		goto bp_exit;
+	}
+	/* unlock_bpctl();   */
+	/* preempt_enable(); */
+ bpcmd_exit:
+	/* rcu_read_unlock(); */
+	spin_unlock_irqrestore(&bpvm_lock, flags);
+	if (copy_to_user(argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd)))
+		ret = -EFAULT;
+	ret = SUCCESS;
+ bp_exit:
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
+	/* unlock_kernel(); */
+#endif
+	/* spin_unlock_irqrestore(&bpvm_lock, flags); */
+	unlock_bpctl();
+	/* unlock_kernel(); */
+	return ret;
+}
+
+struct file_operations Fops = {
+	.owner = THIS_MODULE,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
+	.ioctl = device_ioctl,
+#else
+	.unlocked_ioctl = device_ioctl,
+#endif
+
+	.open = device_open,
+	.release = device_release,	/* a.k.a. close */
+};
+
+#ifndef PCI_DEVICE
+#define PCI_DEVICE(vend,dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#endif
+
+#define SILICOM_E1000BP_ETHERNET_DEVICE(device_id) {\
+	PCI_DEVICE(SILICOM_VID, device_id)}
+
+typedef enum {
+	PXG2BPFI,
+	PXG2BPFIL,
+	PXG2BPFILX,
+	PXG2BPFILLX,
+	PXGBPI,
+	PXGBPIG,
+	PXG2TBFI,
+	PXG4BPI,
+	PXG4BPFI,
+	PEG4BPI,
+	PEG2BPI,
+	PEG4BPIN,
+	PEG2BPFI,
+	PEG2BPFILX,
+	PMCXG2BPFI,
+	PMCXG2BPFIN,
+	PEG4BPII,
+	PEG4BPFII,
+	PXG4BPFILX,
+	PMCXG2BPIN,
+	PMCXG4BPIN,
+	PXG2BISC1,
+	PEG2TBFI,
+	PXG2TBI,
+	PXG4BPFID,
+	PEG4BPFI,
+	PEG4BPIPT,
+	PXG6BPI,
+	PEG4BPIL,
+	PMCXG2BPIN2,
+	PMCXG4BPIN2,
+	PMCX2BPI,
+	PEG2BPFID,
+	PEG2BPFIDLX,
+	PMCX4BPI,
+	MEG2BPFILN,
+	MEG2BPFINX,
+	PEG4BPFILX,
+	PE10G2BPISR,
+	PE10G2BPILR,
+	MHIO8AD,
+	PE10G2BPICX4,
+	PEG2BPI5,
+	PEG6BPI,
+	PEG4BPFI5,
+	PEG4BPFI5LX,
+	MEG2BPFILXLN,
+	PEG2BPIX1,
+	MEG2BPFILXNX,
+	XE10G2BPIT,
+	XE10G2BPICX4,
+	XE10G2BPISR,
+	XE10G2BPILR,
+	PEG4BPIIO,
+	XE10G2BPIXR,
+	PE10GDBISR,
+	PE10GDBILR,
+	PEG2BISC6,
+	PEG6BPIFC,
+	PE10G2BPTCX4,
+	PE10G2BPTSR,
+	PE10G2BPTLR,
+	PE10G2BPTT,
+	PEG4BPI6,
+	PEG4BPFI6,
+	PEG4BPFI6LX,
+	PEG4BPFI6ZX,
+	PEG2BPI6,
+	PEG2BPFI6,
+	PEG2BPFI6LX,
+	PEG2BPFI6ZX,
+	PEG2BPFI6FLXM,
+	PEG4BPI6FC,
+	PEG4BPFI6FC,
+	PEG4BPFI6FCLX,
+	PEG4BPFI6FCZX,
+	PEG6BPI6,
+	PEG2BPI6SC6,
+	MEG2BPI6,
+	XEG2BPI6,
+	MEG4BPI6,
+	PEG2BPFI5,
+	PEG2BPFI5LX,
+	PXEG4BPFI,
+	M1EG2BPI6,
+	M1EG2BPFI6,
+	M1EG2BPFI6LX,
+	M1EG2BPFI6ZX,
+	M1EG4BPI6,
+	M1EG4BPFI6,
+	M1EG4BPFI6LX,
+	M1EG4BPFI6ZX,
+	M1EG6BPI6,
+	M1E2G4BPi80,
+	M1E2G4BPFi80,
+	M1E2G4BPFi80LX,
+	M1E2G4BPFi80ZX,
+	PE210G2SPI9,
+	M1E10G2BPI9CX4,
+	M1E10G2BPI9SR,
+	M1E10G2BPI9LR,
+	M1E10G2BPI9T,
+	PE210G2BPI9CX4,
+	PE210G2BPI9SR,
+	PE210G2BPI9LR,
+	PE210G2BPI9T,
+	M2EG2BPFI6,
+	M2EG2BPFI6LX,
+	M2EG2BPFI6ZX,
+	M2EG4BPI6,
+	M2EG4BPFI6,
+	M2EG4BPFI6LX,
+	M2EG4BPFI6ZX,
+	M2EG6BPI6,
+	PEG2DBI6,
+	PEG2DBFI6,
+	PEG2DBFI6LX,
+	PEG2DBFI6ZX,
+	PE2G4BPi80,
+	PE2G4BPFi80,
+	PE2G4BPFi80LX,
+	PE2G4BPFi80ZX,
+	PE2G4BPi80L,
+	M6E2G8BPi80A,
+
+	PE2G2BPi35,
+	PAC1200BPi35,
+	PE2G2BPFi35,
+	PE2G2BPFi35LX,
+	PE2G2BPFi35ZX,
+	PE2G4BPi35,
+	PE2G4BPi35L,
+	PE2G4BPFi35,
+	PE2G4BPFi35LX,
+	PE2G4BPFi35ZX,
+
+	PE2G6BPi35,
+	PE2G6BPi35CX,
+
+	PE2G2BPi80,
+	PE2G2BPFi80,
+	PE2G2BPFi80LX,
+	PE2G2BPFi80ZX,
+	M2E10G2BPI9CX4,
+	M2E10G2BPI9SR,
+	M2E10G2BPI9LR,
+	M2E10G2BPI9T,
+	M6E2G8BPi80,
+	PE210G2DBi9SR,
+	PE210G2DBi9SRRB,
+	PE210G2DBi9LR,
+	PE210G2DBi9LRRB,
+	PE310G4DBi940SR,
+	PE310G4BPi9T,
+	PE310G4BPi9SR,
+	PE310G4BPi9LR,
+	PE210G2BPi40,
+} board_t;
+
+typedef struct _bpmod_info_t {
+	unsigned int vendor;
+	unsigned int device;
+	unsigned int subvendor;
+	unsigned int subdevice;
+	unsigned int index;
+	char *bp_name;
+
+} bpmod_info_t;
+
+typedef struct _dev_desc {
+	char *name;
+} dev_desc_t;
+
+dev_desc_t dev_desc[] = {
+	{"Silicom Bypass PXG2BPFI-SD series adapter"},
+	{"Silicom Bypass PXG2BPFIL-SD series adapter"},
+	{"Silicom Bypass PXG2BPFILX-SD series adapter"},
+	{"Silicom Bypass PXG2BPFILLX-SD series adapter"},
+	{"Silicom Bypass PXG2BPI-SD series adapter"},
+	{"Silicom Bypass PXG2BPIG-SD series adapter"},
+	{"Silicom Bypass PXG2TBFI-SD series adapter"},
+	{"Silicom Bypass PXG4BPI-SD series adapter"},
+	{"Silicom Bypass PXG4BPFI-SD series adapter"},
+	{"Silicom Bypass PEG4BPI-SD series adapter"},
+	{"Silicom Bypass PEG2BPI-SD series adapter"},
+	{"Silicom Bypass PEG4BPIN-SD series adapter"},
+	{"Silicom Bypass PEG2BPFI-SD series adapter"},
+	{"Silicom Bypass PEG2BPFI-LX-SD series adapter"},
+	{"Silicom Bypass PMCX2BPFI-SD series adapter"},
+	{"Silicom Bypass PMCX2BPFI-N series adapter"},
+	{"Intel Bypass PEG2BPII series adapter"},
+	{"Intel Bypass PEG2BPFII series adapter"},
+	{"Silicom Bypass PXG4BPFILX-SD series adapter"},
+	{"Silicom Bypass PMCX2BPI-N series adapter"},
+	{"Silicom Bypass PMCX4BPI-N series adapter"},
+	{"Silicom Bypass PXG2BISC1-SD series adapter"},
+	{"Silicom Bypass PEG2TBFI-SD series adapter"},
+	{"Silicom Bypass PXG2TBI-SD series adapter"},
+	{"Silicom Bypass PXG4BPFID-SD series adapter"},
+	{"Silicom Bypass PEG4BPFI-SD series adapter"},
+	{"Silicom Bypass PEG4BPIPT-SD series adapter"},
+	{"Silicom Bypass PXG6BPI-SD series adapter"},
+	{"Silicom Bypass PEG4BPIL-SD series adapter"},
+	{"Silicom Bypass PMCX2BPI-N2 series adapter"},
+	{"Silicom Bypass PMCX4BPI-N2 series adapter"},
+	{"Silicom Bypass PMCX2BPI-SD series adapter"},
+	{"Silicom Bypass PEG2BPFID-SD series adapter"},
+	{"Silicom Bypass PEG2BPFIDLX-SD series adapter"},
+	{"Silicom Bypass PMCX4BPI-SD series adapter"},
+	{"Silicom Bypass MEG2BPFILN-SD series adapter"},
+	{"Silicom Bypass MEG2BPFINX-SD series adapter"},
+	{"Silicom Bypass PEG4BPFILX-SD series adapter"},
+	{"Silicom Bypass PE10G2BPISR-SD series adapter"},
+	{"Silicom Bypass PE10G2BPILR-SD series adapter"},
+	{"Silicom Bypass MHIO8AD-SD series adapter"},
+	{"Silicom Bypass PE10G2BPICX4-SD series adapter"},
+	{"Silicom Bypass PEG2BPI5-SD series adapter"},
+	{"Silicom Bypass PEG6BPI5-SD series adapter"},
+	{"Silicom Bypass PEG4BPFI5-SD series adapter"},
+	{"Silicom Bypass PEG4BPFI5LX-SD series adapter"},
+	{"Silicom Bypass MEG2BPFILXLN-SD series adapter"},
+	{"Silicom Bypass PEG2BPIX1-SD series adapter"},
+	{"Silicom Bypass MEG2BPFILXNX-SD series adapter"},
+	{"Silicom Bypass XE10G2BPIT-SD series adapter"},
+	{"Silicom Bypass XE10G2BPICX4-SD series adapter"},
+	{"Silicom Bypass XE10G2BPISR-SD series adapter"},
+	{"Silicom Bypass XE10G2BPILR-SD series adapter"},
+	{"Intel Bypass PEG2BPFII0 series adapter"},
+	{"Silicom Bypass XE10G2BPIXR series adapter"},
+	{"Silicom Bypass PE10G2DBISR series adapter"},
+	{"Silicom Bypass PEG2BI5SC6 series adapter"},
+	{"Silicom Bypass PEG6BPI5FC series adapter"},
+
+	{"Silicom Bypass PE10G2BPTCX4 series adapter"},
+	{"Silicom Bypass PE10G2BPTSR series adapter"},
+	{"Silicom Bypass PE10G2BPTLR series adapter"},
+	{"Silicom Bypass PE10G2BPTT series adapter"},
+	{"Silicom Bypass PEG4BPI6 series adapter"},
+	{"Silicom Bypass PEG4BPFI6 series adapter"},
+	{"Silicom Bypass PEG4BPFI6LX series adapter"},
+	{"Silicom Bypass PEG4BPFI6ZX series adapter"},
+	{"Silicom Bypass PEG2BPI6 series adapter"},
+	{"Silicom Bypass PEG2BPFI6 series adapter"},
+	{"Silicom Bypass PEG2BPFI6LX series adapter"},
+	{"Silicom Bypass PEG2BPFI6ZX series adapter"},
+	{"Silicom Bypass PEG2BPFI6FLXM series adapter"},
+	{"Silicom Bypass PEG4BPI6FC series adapter"},
+	{"Silicom Bypass PEG4BPFI6FC series adapter"},
+	{"Silicom Bypass PEG4BPFI6FCLX series adapter"},
+	{"Silicom Bypass PEG4BPFI6FCZX series adapter"},
+	{"Silicom Bypass PEG6BPI6 series adapter"},
+	{"Silicom Bypass PEG2BPI6SC6 series adapter"},
+	{"Silicom Bypass MEG2BPI6 series adapter"},
+	{"Silicom Bypass XEG2BPI6 series adapter"},
+	{"Silicom Bypass MEG4BPI6 series adapter"},
+	{"Silicom Bypass PEG2BPFI5-SD series adapter"},
+	{"Silicom Bypass PEG2BPFI5LX-SD series adapter"},
+	{"Silicom Bypass PXEG4BPFI-SD series adapter"},
+	{"Silicom Bypass MxEG2BPI6 series adapter"},
+	{"Silicom Bypass MxEG2BPFI6 series adapter"},
+	{"Silicom Bypass MxEG2BPFI6LX series adapter"},
+	{"Silicom Bypass MxEG2BPFI6ZX series adapter"},
+	{"Silicom Bypass MxEG4BPI6 series adapter"},
+	{"Silicom Bypass MxEG4BPFI6 series adapter"},
+	{"Silicom Bypass MxEG4BPFI6LX series adapter"},
+	{"Silicom Bypass MxEG4BPFI6ZX series adapter"},
+	{"Silicom Bypass MxEG6BPI6 series adapter"},
+	{"Silicom Bypass MxE2G4BPi80 series adapter"},
+	{"Silicom Bypass MxE2G4BPFi80 series adapter"},
+	{"Silicom Bypass MxE2G4BPFi80LX series adapter"},
+	{"Silicom Bypass MxE2G4BPFi80ZX series adapter"},
+
+	{"Silicom Bypass PE210G2SPI9 series adapter"},
+
+	{"Silicom Bypass MxE210G2BPI9CX4 series adapter"},
+	{"Silicom Bypass MxE210G2BPI9SR series adapter"},
+	{"Silicom Bypass MxE210G2BPI9LR series adapter"},
+	{"Silicom Bypass MxE210G2BPI9T series adapter"},
+
+	{"Silicom Bypass PE210G2BPI9CX4 series adapter"},
+	{"Silicom Bypass PE210G2BPI9SR series adapter"},
+	{"Silicom Bypass PE210G2BPI9LR series adapter"},
+	{"Silicom Bypass PE210G2BPI9T series adapter"},
+
+	{"Silicom Bypass M2EG2BPFI6 series adapter"},
+	{"Silicom Bypass M2EG2BPFI6LX series adapter"},
+	{"Silicom Bypass M2EG2BPFI6ZX series adapter"},
+	{"Silicom Bypass M2EG4BPI6 series adapter"},
+	{"Silicom Bypass M2EG4BPFI6 series adapter"},
+	{"Silicom Bypass M2EG4BPFI6LX series adapter"},
+	{"Silicom Bypass M2EG4BPFI6ZX series adapter"},
+	{"Silicom Bypass M2EG6BPI6 series adapter"},
+
+	{"Silicom Bypass PEG2DBI6    series adapter"},
+	{"Silicom Bypass PEG2DBFI6   series adapter"},
+	{"Silicom Bypass PEG2DBFI6LX series adapter"},
+	{"Silicom Bypass PEG2DBFI6ZX series adapter"},
+
+	{"Silicom Bypass PE2G4BPi80 series adapter"},
+	{"Silicom Bypass PE2G4BPFi80 series adapter"},
+	{"Silicom Bypass PE2G4BPFi80LX series adapter"},
+	{"Silicom Bypass PE2G4BPFi80ZX series adapter"},
+
+	{"Silicom Bypass PE2G4BPi80L series adapter"},
+	{"Silicom Bypass MxE2G8BPi80A series adapter"},
+
+	{"Silicom Bypass PE2G2BPi35 series adapter"},
+	{"Silicom Bypass PAC1200BPi35 series adapter"},
+	{"Silicom Bypass PE2G2BPFi35 series adapter"},
+	{"Silicom Bypass PE2G2BPFi35LX series adapter"},
+	{"Silicom Bypass PE2G2BPFi35ZX series adapter"},
+
+	{"Silicom Bypass PE2G4BPi35 series adapter"},
+	{"Silicom Bypass PE2G4BPi35L series adapter"},
+	{"Silicom Bypass PE2G4BPFi35 series adapter"},
+	{"Silicom Bypass PE2G4BPFi35LX series adapter"},
+	{"Silicom Bypass PE2G4BPFi35ZX series adapter"},
+
+	{"Silicom Bypass PE2G6BPi35 series adapter"},
+	{"Silicom Bypass PE2G6BPi35CX series adapter"},
+
+	{"Silicom Bypass PE2G2BPi80 series adapter"},
+	{"Silicom Bypass PE2G2BPFi80 series adapter"},
+	{"Silicom Bypass PE2G2BPFi80LX series adapter"},
+	{"Silicom Bypass PE2G2BPFi80ZX series adapter"},
+
+	{"Silicom Bypass M2E10G2BPI9CX4 series adapter"},
+	{"Silicom Bypass M2E10G2BPI9SR series adapter"},
+	{"Silicom Bypass M2E10G2BPI9LR series adapter"},
+	{"Silicom Bypass M2E10G2BPI9T series adapter"},
+	{"Silicom Bypass MxE2G8BPi80 series adapter"},
+	{"Silicom Bypass PE210G2DBi9SR series adapter"},
+	{"Silicom Bypass PE210G2DBi9SRRB series adapter"},
+	{"Silicom Bypass PE210G2DBi9LR series adapter"},
+	{"Silicom Bypass PE210G2DBi9LRRB series adapter"},
+	{"Silicom Bypass PE310G4DBi9-SR series adapter"},
+	{"Silicom Bypass PE310G4BPi9T series adapter"},
+	{"Silicom Bypass PE310G4BPi9SR series adapter"},
+	{"Silicom Bypass PE310G4BPi9LR series adapter"},
+	{"Silicom Bypass PE210G2BPi40T series adapter"},
+	{0},
+};
+
+static bpmod_info_t tx_ctl_pci_tbl[] = {
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFI_SSID, PXG2BPFI,
+	 "PXG2BPFI-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFIL_SSID, PXG2BPFIL,
+	 "PXG2BPFIL-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILX_SSID, PXG2BPFILX,
+	 "PXG2BPFILX-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILLX_SSID, PXG2BPFILLX,
+	 "PXG2BPFILLXSD"},
+	{0x8086, 0x1010, SILICOM_SVID, SILICOM_PXGBPI_SSID, PXGBPI,
+	 "PXG2BPI-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PXGBPIG_SSID, PXGBPIG,
+	 "PXG2BPIG-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2TBFI_SSID, PXG2TBFI,
+	 "PXG2TBFI-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI,
+	 "PXG4BPI-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI,
+	 "PXG4BPFI-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFILX_SSID, PXG4BPFILX,
+	 "PXG4BPFILX-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PEG4BPI_SSID, PEG4BPI,
+	 "PEXG4BPI-SD"},
+	{0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPI_SSID, PEG2BPI,
+	 "PEG2BPI-SD"},
+	{0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIN_SSID, PEG4BPIN,
+	 "PEG4BPI-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFI_SSID, PEG2BPFI,
+	 "PEG2BPFI-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFILX_SSID, PEG2BPFILX,
+	 "PEG2BPFILX-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PMCXG2BPFI_SSID, PMCXG2BPFI,
+	 "PMCX2BPFI-SD"},
+	{0x8086, 0x107a, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPFIN_SSID,
+	 PMCXG2BPFIN, "PMCX2BPFI-N"},
+	{0x8086, INTEL_PEG4BPII_PID, 0x8086, INTEL_PEG4BPII_SSID, PEG4BPII,
+	 "PEG4BPII"},
+	{0x8086, INTEL_PEG4BPIIO_PID, 0x8086, INTEL_PEG4BPIIO_SSID, PEG4BPIIO,
+	 "PEG4BPII0"},
+	{0x8086, INTEL_PEG4BPFII_PID, 0x8086, INTEL_PEG4BPFII_SSID, PEG4BPFII,
+	 "PEG4BPFII"},
+	{0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN_SSID,
+	 PMCXG2BPIN, "PMCX2BPI-N"},
+	{0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN_SSID,
+	 PMCXG4BPIN, "PMCX4BPI-N"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1,
+	 "PXG2BISC1-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2TBFI_SSID, PEG2TBFI,
+	 "PEG2TBFI-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI,
+	 "PXG2TBI-SD"},
+	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFID_SSID, PXG4BPFID,
+	 "PXG4BPFID-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI,
+	 "PEG4BPFI-SD"},
+	{0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIPT_SSID, PEG4BPIPT,
+	 "PEG4BPIPT-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG6BPI_SSID, PXG6BPI,
+	 "PXG6BPI-SD"},
+	{0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPIL_SSID /*PCI_ANY_ID */ , PEG4BPIL, "PEG4BPIL-SD"},
+	{0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN2_SSID,
+	 PMCXG2BPIN2, "PMCX2BPI-N2"},
+	{0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN2_SSID,
+	 PMCXG4BPIN2, "PMCX4BPI-N2"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX2BPI_SSID, PMCX2BPI,
+	 "PMCX2BPI-SD"},
+	{0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX4BPI_SSID, PMCX4BPI,
+	 "PMCX4BPI-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFID_SSID, PEG2BPFID,
+	 "PEG2BPFID-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFIDLX_SSID, PEG2BPFIDLX,
+	 "PEG2BPFIDLXSD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILN_SSID, MEG2BPFILN,
+	 "MEG2BPFILN-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFINX_SSID, MEG2BPFINX,
+	 "MEG2BPFINX-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFILX_SSID, PEG4BPFILX,
+	 "PEG4BPFILX-SD"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPISR_SSID,
+	 PE10G2BPISR, "PE10G2BPISR"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPILR_SSID,
+	 PE10G2BPILR, "PE10G2BPILR"},
+	{0x8086, 0x10a9, SILICOM_SVID, SILICOM_MHIO8AD_SSID, MHIO8AD,
+	 "MHIO8AD-SD"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPICX4_SSID,
+	 PE10G2BPISR, "PE10G2BPICX4"},
+	{0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPI5_SSID /*PCI_ANY_ID */ , PEG2BPI5, "PEG2BPI5-SD"},
+	{0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG6BPI_SSID /*PCI_ANY_ID */ , PEG6BPI, "PEG6BPI5"},
+	{0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG4BPFI5_SSID,
+	 PEG4BPFI5, "PEG4BPFI5"},
+	{0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI5LX_SSID, PEG4BPFI5LX, "PEG4BPFI5LX"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXLN_SSID, MEG2BPFILXLN,
+	 "MEG2BPFILXLN"},
+	{0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPIX1_SSID, PEG2BPIX1,
+	 "PEG2BPIX1-SD"},
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXNX_SSID, MEG2BPFILXNX,
+	 "MEG2BPFILXNX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPIT_SSID, XE10G2BPIT,
+	 "XE10G2BPIT"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPICX4_SSID,
+	 XE10G2BPICX4, "XE10G2BPICX4"},
+	{0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPISR_SSID, XE10G2BPISR,
+	 "XE10G2BPISR"},
+	{0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPILR_SSID, XE10G2BPILR,
+	 "XE10G2BPILR"},
+	{0x8086, 0x10C6, NOKIA_XE10G2BPIXR_SVID, NOKIA_XE10G2BPIXR_SSID,
+	 XE10G2BPIXR, "XE10G2BPIXR"},
+	{0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBISR_SSID, PE10GDBISR,
+	 "PE10G2DBISR"},
+	{0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBILR_SSID, PE10GDBILR,
+	 "PE10G2DBILR"},
+	{0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BISC6_SSID /*PCI_ANY_ID */ , PEG2BISC6, "PEG2BI5SC6"},
+	{0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG6BPIFC_SSID /*PCI_ANY_ID */ , PEG6BPIFC, "PEG6BPI5FC"},
+
+	{BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID,
+	 SILICOM_PE10G2BPTCX4_SSID, PE10G2BPTCX4, "PE10G2BPTCX4"},
+	{BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID,
+	 SILICOM_PE10G2BPTSR_SSID, PE10G2BPTSR, "PE10G2BPTSR"},
+	{BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID,
+	 SILICOM_PE10G2BPTLR_SSID, PE10G2BPTLR, "PE10G2BPTLR"},
+	{BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID,
+	 SILICOM_PE10G2BPTT_SSID, PE10G2BPTT, "PE10G2BPTT"},
+
+	/* {BROADCOM_VID, BROADCOM_PE10G2_PID, PCI_ANY_ID, PCI_ANY_ID, PE10G2BPTCX4, "PE10G2BPTCX4"}, */
+
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPI6_SSID /*PCI_ANY_ID */ , PEG4BPI6, "PEG4BPI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6_SSID /*PCI_ANY_ID */ , PEG4BPFI6, "PEG4BPFI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6LX_SSID /*PCI_ANY_ID */ , PEG4BPFI6LX, "PEG4BPFI6LX"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6ZX, "PEG4BPFI6ZX"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPI6_SSID /*PCI_ANY_ID */ , PEG2BPI6, "PEG2BPI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPFI6_SSID /*PCI_ANY_ID */ , PEG2BPFI6, "PEG2BPFI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPFI6LX_SSID /*PCI_ANY_ID */ , PEG2BPFI6LX, "PEG2BPFI6LX"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG2BPFI6ZX, "PEG2BPFI6ZX"},
+	{0x8086, 0x10e7, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPFI6FLXM_SSID /*PCI_ANY_ID */ , PEG2BPFI6FLXM,
+	 "PEG2BPFI6FLXM"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPI6FC_SSID /*PCI_ANY_ID */ , PEG4BPI6FC, "PEG4BPI6FC"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6FC_SSID /*PCI_ANY_ID */ , PEG4BPFI6FC, "PEG4BPFI6FC"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6FCLX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCLX,
+	 "PEG4BPFI6FCLX"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG4BPFI6FCZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCZX,
+	 "PEG4BPFI6FCZX"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG6BPI6_SSID /*PCI_ANY_ID */ , PEG6BPI6, "PEG6BPI6"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPI6SC6_SSID /*PCI_ANY_ID */ , PEG2BPI6SC6,
+	 "PEG6BPI62SC6"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_MEG4BPI6_SSID /*PCI_ANY_ID */ , MEG4BPI6, "MEG4BPI6"},
+
+	{0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG2BPFI5_SSID,
+	 PEG2BPFI5, "PEG2BPFI5"},
+	{0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2BPFI5LX_SSID, PEG2BPFI5LX, "PEG2BPFI5LX"},
+
+	{0x8086, 0x105f, SILICOM_SVID, SILICOM_PXEG4BPFI_SSID, PXEG4BPFI,
+	 "PXEG4BPFI-SD"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG2BPI6_SSID /*PCI_ANY_ID */ , M1EG2BPI6, "MxEG2BPI6"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG2BPFI6_SSID /*PCI_ANY_ID */ , M1EG2BPFI6, "MxEG2BPFI6"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6LX,
+	 "MxEG2BPFI6LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6ZX,
+	 "MxEG2BPFI6ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG4BPI6_SSID /*PCI_ANY_ID */ , M1EG4BPI6, "MxEG4BPI6"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG4BPFI6_SSID /*PCI_ANY_ID */ , M1EG4BPFI6, "MxEG4BPFI6"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6LX,
+	 "MxEG4BPFI6LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6ZX,
+	 "MxEG4BPFI6ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1EG6BPI6_SSID /*PCI_ANY_ID */ , M1EG6BPI6, "MxEG6BPI6"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E2G4BPi80_SSID /*PCI_ANY_ID */ , M1E2G4BPi80, "MxE2G4BPi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E2G4BPFi80_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80,
+	 "MxE2G4BPFi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E2G4BPFi80LX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80LX,
+	 "MxE2G4BPFi80LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80ZX,
+	 "MxE2G4BPFi80ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG2BPFI6_SSID /*PCI_ANY_ID */ , M2EG2BPFI6, "M2EG2BPFI6"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6LX,
+	 "M2EG2BPFI6LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6ZX,
+	 "M2EG2BPFI6ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG4BPI6_SSID /*PCI_ANY_ID */ , M2EG4BPI6, "M2EG4BPI6"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG4BPFI6_SSID /*PCI_ANY_ID */ , M2EG4BPFI6, "M2EG4BPFI6"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6LX,
+	 "M2EG4BPFI6LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6ZX,
+	 "M2EG4BPFI6ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2EG6BPI6_SSID /*PCI_ANY_ID */ , M2EG6BPI6, "M2EG6BPI6"},
+
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2DBI6_SSID /*PCI_ANY_ID */ , PEG2DBI6, "PEG2DBI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2DBFI6_SSID /*PCI_ANY_ID */ , PEG2DBFI6, "PEG2DBFI6"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2DBFI6LX_SSID /*PCI_ANY_ID */ , PEG2DBFI6LX, "PEG2DBFI6LX"},
+	{0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PEG2DBFI6ZX_SSID /*PCI_ANY_ID */ , PEG2DBFI6ZX, "PEG2DBFI6ZX"},
+
+	{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE210G2DBi9SR_SSID, PE210G2DBi9SR, "PE210G2DBi9SR"},
+	{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE210G2DBi9LR_SSID, PE210G2DBi9LR, "PE210G2DBi9LR"},
+	{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE310G4DBi940SR_SSID, PE310G4DBi940SR, "PE310G4DBi9SR"},
+
+	{0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE310G4BPi9T_SSID, PE310G4BPi9T, "PE310G4BPi9T"},
+	{0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE310G4BPi9SR_SSID, PE310G4BPi9SR, "PE310G4BPi9SR"},
+	{0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE310G4BPi9LR_SSID, PE310G4BPi9LR, "PE310G4BPi9LR"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPi80_SSID /*PCI_ANY_ID */ , PE2G4BPi80, "PE2G4BPi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi80_SSID /*PCI_ANY_ID */ , PE2G4BPFi80, "PE2G4BPFi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80LX,
+	 "PE2G4BPFi80LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80ZX,
+	 "PE2G4BPFi80ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPi80L_SSID /*PCI_ANY_ID */ , PE2G4BPi80L, "PE2G4BPi80L"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M6E2G8BPi80A_SSID /*PCI_ANY_ID */ , M6E2G8BPi80A,
+	 "MxE2G8BPi80A"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPi35_SSID /*PCI_ANY_ID */ , PE2G2BPi35, "PE2G2BPi35"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PAC1200BPi35_SSID /*PCI_ANY_ID */ , PAC1200BPi35,
+	 "PAC1200BPi35"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi35_SSID /*PCI_ANY_ID */ , PE2G2BPFi35, "PE2G2BPFi35"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35LX,
+	 "PE2G2BPFi35LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35ZX,
+	 "PE2G2BPFi35ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPi35_SSID /*PCI_ANY_ID */ , PE2G4BPi35, "PE2G4BPi35"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPi35L_SSID /*PCI_ANY_ID */ , PE2G4BPi35L, "PE2G4BPi35L"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi35_SSID /*PCI_ANY_ID */ , PE2G4BPFi35, "PE2G4BPFi35"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35LX,
+	 "PE2G4BPFi35LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G4BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35ZX,
+	 "PE2G4BPFi35ZX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G6BPi35_SSID /*PCI_ANY_ID */ , PE2G6BPi35, "PE2G6BPi35"},
+
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa0, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa1, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa2, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa3, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa4, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa5, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa6, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa7, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa8, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa9, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaa, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaab, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaac, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaad, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaae, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaf, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab0, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab1, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab2, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab3, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab4, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab5, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab6, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab7, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab8, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab9, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaba, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabb, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabc, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabd, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabe, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabf, PE2G6BPi35CX,
+	 "PE2G6BPi35CX"},
+
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPi80_SSID /*PCI_ANY_ID */ , PE2G2BPi80, "PE2G2BPi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi80_SSID /*PCI_ANY_ID */ , PE2G2BPFi80, "PE2G2BPFi80"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80LX,
+	 "PE2G2BPFi80LX"},
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE2G2BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80ZX,
+	 "PE2G2BPFi80ZX"},
+
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"},
+	{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"},
+
+#if 0
+	{0x8086, 0x10fb, 0x8086, INTEL_PE210G2SPI9_SSID, PE210G2SPI9,
+	 "PE210G2SPI9"},
+#endif
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M1E10G2BPI9CX4,
+	 "MxE210G2BPI9CX4"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9SR,
+	 "MxE210G2BPI9SR"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9LR,
+	 "MxE210G2BPI9LR"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M1E10G2BPI9T_SSID /*PCI_ANY_ID */ , M1E10G2BPI9T,
+	 "MxE210G2BPI9T"},
+
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M2E10G2BPI9CX4,
+	 "M2E10G2BPI9CX4"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9SR,
+	 "M2E10G2BPI9SR"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9LR,
+	 "M2E10G2BPI9LR"},
+	{0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M2E10G2BPI9T_SSID /*PCI_ANY_ID */ , M2E10G2BPI9T,
+	 "M2E10G2BPI9T"},
+
+	{0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9CX4_SSID,
+	 PE210G2BPI9CX4, "PE210G2BPI9CX4"},
+	{0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9SR_SSID,
+	 PE210G2BPI9SR, "PE210G2BPI9SR"},
+	{0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9LR_SSID,
+	 PE210G2BPI9LR, "PE210G2BPI9LR"},
+	{0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9T_SSID, PE210G2BPI9T,
+	 "PE210G2BPI9T"},
+
+#if 0
+	{0x1374, 0x2c, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI,
+	 "PXG4BPI-SD"},
+
+	{0x1374, 0x2d, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI,
+	 "PXG4BPFI-SD"},
+
+	{0x1374, 0x3f, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI,
+	 "PXG2TBI-SD"},
+
+	{0x1374, 0x3d, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1,
+	 "PXG2BISC1-SD"},
+
+	{0x1374, 0x40, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI,
+	 "PEG4BPFI-SD"},
+
+#ifdef BP_SELF_TEST
+	{0x1374, 0x28, SILICOM_SVID, 0x28, PXGBPI, "PXG2BPI-SD"},
+#endif
+#endif
+	{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_M6E2G8BPi80_SSID /*PCI_ANY_ID */ , M6E2G8BPi80, "MxE2G8BPi80"},
+	{0x8086, 0x1528, SILICOM_SVID /*PCI_ANY_ID */ ,
+	 SILICOM_PE210G2BPi40_SSID /*PCI_ANY_ID */ , PE210G2BPi40,
+	 "PE210G2BPi40T"},
+
+	/* required last entry */
+	{0,}
+};
+
+/*
+* Initialize the module - Register the character device
+*/
+
+static int __init bypass_init_module(void)
+{
+	int ret_val, idx, idx_dev = 0;
+	struct pci_dev *pdev1 = NULL;
+	unsigned long mmio_start, mmio_len;
+
+	printk(BP_MOD_DESCR " v" BP_MOD_VER "\n");
+	ret_val = register_chrdev(major_num, DEVICE_NAME, &Fops);
+	if (ret_val < 0) {
+		printk("%s failed with %d\n", DEVICE_NAME, ret_val);
+		return ret_val;
+	}
+	major_num = ret_val;	/* dynamic */
+	for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) {
+		while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor,
+					       tx_ctl_pci_tbl[idx].device,
+					       tx_ctl_pci_tbl[idx].subvendor,
+					       tx_ctl_pci_tbl[idx].subdevice,
+					       pdev1))) {
+
+			device_num++;
+		}
+	}
+	if (!device_num) {
+		printk("No such device\n");
+		unregister_chrdev(major_num, DEVICE_NAME);
+		return -1;
+	}
+
+	bpctl_dev_arr = kmalloc((device_num) * sizeof(bpctl_dev_t), GFP_KERNEL);
+
+	if (!bpctl_dev_arr) {
+		printk("Allocation error\n");
+		unregister_chrdev(major_num, DEVICE_NAME);
+		return -1;
+	}
+	memset(bpctl_dev_arr, 0, ((device_num) * sizeof(bpctl_dev_t)));
+
+	pdev1 = NULL;
+	for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) {
+		while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor,
+					       tx_ctl_pci_tbl[idx].device,
+					       tx_ctl_pci_tbl[idx].subvendor,
+					       tx_ctl_pci_tbl[idx].subdevice,
+					       pdev1))) {
+			bpctl_dev_arr[idx_dev].pdev = pdev1;
+
+			mmio_start = pci_resource_start(pdev1, 0);
+			mmio_len = pci_resource_len(pdev1, 0);
+
+			bpctl_dev_arr[idx_dev].desc =
+			    dev_desc[tx_ctl_pci_tbl[idx].index].name;
+			bpctl_dev_arr[idx_dev].name =
+			    tx_ctl_pci_tbl[idx].bp_name;
+			bpctl_dev_arr[idx_dev].device =
+			    tx_ctl_pci_tbl[idx].device;
+			bpctl_dev_arr[idx_dev].vendor =
+			    tx_ctl_pci_tbl[idx].vendor;
+			bpctl_dev_arr[idx_dev].subdevice =
+			    tx_ctl_pci_tbl[idx].subdevice;
+			bpctl_dev_arr[idx_dev].subvendor =
+			    tx_ctl_pci_tbl[idx].subvendor;
+			/* bpctl_dev_arr[idx_dev].pdev=pdev1; */
+			bpctl_dev_arr[idx_dev].func = PCI_FUNC(pdev1->devfn);
+			bpctl_dev_arr[idx_dev].slot = PCI_SLOT(pdev1->devfn);
+			bpctl_dev_arr[idx_dev].bus = pdev1->bus->number;
+			bpctl_dev_arr[idx_dev].mem_map =
+			    (unsigned long)ioremap(mmio_start, mmio_len);
+#ifdef BP_SYNC_FLAG
+			spin_lock_init(&bpctl_dev_arr[idx_dev].bypass_wr_lock);
+#endif
+			if (BP10G9_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice))
+				bpctl_dev_arr[idx_dev].bp_10g9 = 1;
+			if (BP10G_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice))
+				bpctl_dev_arr[idx_dev].bp_10g = 1;
+			if (PEG540_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) {
+
+				bpctl_dev_arr[idx_dev].bp_540 = 1;
+			}
+			if (PEGF5_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice))
+				bpctl_dev_arr[idx_dev].bp_fiber5 = 1;
+			if (PEG80_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice))
+				bpctl_dev_arr[idx_dev].bp_i80 = 1;
+			if (PEGF80_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice))
+				bpctl_dev_arr[idx_dev].bp_i80 = 1;
+			if ((bpctl_dev_arr[idx_dev].subdevice & 0xa00) == 0xa00)
+				bpctl_dev_arr[idx_dev].bp_i80 = 1;
+			if (BP10GB_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) {
+				if (bpctl_dev_arr[idx_dev].ifindex == 0) {
+					unregister_chrdev(major_num,
+							  DEVICE_NAME);
+					printk
+					    ("Please load network driver for %s adapter!\n",
+					     bpctl_dev_arr[idx_dev].name);
+					return -1;
+				}
+
+				if (bpctl_dev_arr[idx_dev].ndev) {
+					if (!
+					    (bpctl_dev_arr[idx_dev].ndev->
+					     flags & IFF_UP)) {
+						if (!
+						    (bpctl_dev_arr[idx_dev].
+						     ndev->flags & IFF_UP)) {
+							unregister_chrdev
+							    (major_num,
+							     DEVICE_NAME);
+							printk
+							    ("Please bring up network interfaces for %s adapter!\n",
+							     bpctl_dev_arr
+							     [idx_dev].name);
+							return -1;
+						}
+
+					}
+				}
+				bpctl_dev_arr[idx_dev].bp_10gb = 1;
+			}
+
+			if (!bpctl_dev_arr[idx_dev].bp_10g9) {
+
+				if (is_bypass_fn(&bpctl_dev_arr[idx_dev])) {
+					printk(KERN_INFO "%s found, ",
+					       bpctl_dev_arr[idx_dev].name);
+					if ((OLD_IF_SERIES
+					     (bpctl_dev_arr[idx_dev].subdevice))
+					    ||
+					    (INTEL_IF_SERIES
+					     (bpctl_dev_arr[idx_dev].
+					      subdevice)))
+						bpctl_dev_arr[idx_dev].
+						    bp_fw_ver = 0xff;
+					else
+						bpctl_dev_arr[idx_dev].
+						    bp_fw_ver =
+						    bypass_fw_ver(&bpctl_dev_arr
+								  [idx_dev]);
+					if ((bpctl_dev_arr[idx_dev].bp_10gb ==
+					     1)
+					    && (bpctl_dev_arr[idx_dev].
+						bp_fw_ver == 0xff)) {
+						int cnt = 100;
+						while (cnt--) {
+							iounmap((void
+								 *)
+								(bpctl_dev_arr
+								 [idx_dev].
+								 mem_map));
+							mmio_start =
+							    pci_resource_start
+							    (pdev1, 0);
+							mmio_len =
+							    pci_resource_len
+							    (pdev1, 0);
+
+							bpctl_dev_arr[idx_dev].
+							    mem_map =
+							    (unsigned long)
+							    ioremap(mmio_start,
+								    mmio_len);
+
+							bpctl_dev_arr[idx_dev].
+							    bp_fw_ver =
+							    bypass_fw_ver
+							    (&bpctl_dev_arr
+							     [idx_dev]);
+							if (bpctl_dev_arr
+							    [idx_dev].
+							    bp_fw_ver == 0xa8)
+								break;
+
+						}
+					}
+					/* bpctl_dev_arr[idx_dev].bp_fw_ver=0xa8; */
+					printk("firmware version: 0x%x\n",
+					       bpctl_dev_arr[idx_dev].
+					       bp_fw_ver);
+				}
+				bpctl_dev_arr[idx_dev].wdt_status =
+				    WDT_STATUS_UNKNOWN;
+				bpctl_dev_arr[idx_dev].reset_time = 0;
+				atomic_set(&bpctl_dev_arr[idx_dev].wdt_busy, 0);
+				bpctl_dev_arr[idx_dev].bp_status_un = 1;
+
+				bypass_caps_init(&bpctl_dev_arr[idx_dev]);
+
+				init_bypass_wd_auto(&bpctl_dev_arr[idx_dev]);
+				init_bypass_tpl_auto(&bpctl_dev_arr[idx_dev]);
+				if (NOKIA_SERIES
+				    (bpctl_dev_arr[idx_dev].subdevice))
+					reset_cont(&bpctl_dev_arr[idx_dev]);
+			}
+#ifdef BP_SELF_TEST
+			if ((bpctl_dev_arr[idx_dev].bp_tx_data =
+			     kmalloc(BPTEST_DATA_LEN, GFP_KERNEL))) {
+
+				memset(bpctl_dev_arr[idx_dev].bp_tx_data, 0x0,
+				       BPTEST_DATA_LEN);
+
+				memset(bpctl_dev_arr[idx_dev].bp_tx_data, 0xff,
+				       6);
+				memset(bpctl_dev_arr[idx_dev].bp_tx_data + 6,
+				       0x0, 1);
+				memset(bpctl_dev_arr[idx_dev].bp_tx_data + 7,
+				       0xaa, 5);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+				bpctl_dev_arr[idx_dev].bp_tx_data[12] =
+				    (ETH_P_BPTEST >> 8) & 0xff;
+				bpctl_dev_arr[idx_dev].bp_tx_data[13] =
+				    ETH_P_BPTEST & 0xff;
+#else
+				*(__be16 *) (bpctl_dev_arr[idx_dev].bp_tx_data +
+					     12) = htons(ETH_P_BPTEST);
+#endif
+
+			} else
+				printk("bp_ctl: Memory allocation error!\n");
+#endif
+			idx_dev++;
+
+		}
+	}
+	if_scan_init();
+
+	sema_init(&bpctl_sema, 1);
+	spin_lock_init(&bpvm_lock);
+	{
+
+		bpctl_dev_t *pbpctl_dev_c = NULL;
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if (bpctl_dev_arr[idx_dev].bp_10g9) {
+				pbpctl_dev_c =
+				    get_status_port_fn(&bpctl_dev_arr[idx_dev]);
+				if (is_bypass_fn(&bpctl_dev_arr[idx_dev])) {
+					printk(KERN_INFO "%s found, ",
+					       bpctl_dev_arr[idx_dev].name);
+					bpctl_dev_arr[idx_dev].bp_fw_ver =
+					    bypass_fw_ver(&bpctl_dev_arr
+							  [idx_dev]);
+					printk("firmware version: 0x%x\n",
+					       bpctl_dev_arr[idx_dev].
+					       bp_fw_ver);
+
+				}
+				bpctl_dev_arr[idx_dev].wdt_status =
+				    WDT_STATUS_UNKNOWN;
+				bpctl_dev_arr[idx_dev].reset_time = 0;
+				atomic_set(&bpctl_dev_arr[idx_dev].wdt_busy, 0);
+				bpctl_dev_arr[idx_dev].bp_status_un = 1;
+
+				bypass_caps_init(&bpctl_dev_arr[idx_dev]);
+
+				init_bypass_wd_auto(&bpctl_dev_arr[idx_dev]);
+				init_bypass_tpl_auto(&bpctl_dev_arr[idx_dev]);
+
+			}
+
+		}
+	}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+	inter_module_register("is_bypass_sd", THIS_MODULE, &is_bypass_sd);
+	inter_module_register("get_bypass_slave_sd", THIS_MODULE,
+			      &get_bypass_slave_sd);
+	inter_module_register("get_bypass_caps_sd", THIS_MODULE,
+			      &get_bypass_caps_sd);
+	inter_module_register("get_wd_set_caps_sd", THIS_MODULE,
+			      &get_wd_set_caps_sd);
+	inter_module_register("set_bypass_sd", THIS_MODULE, &set_bypass_sd);
+	inter_module_register("get_bypass_sd", THIS_MODULE, &get_bypass_sd);
+	inter_module_register("get_bypass_change_sd", THIS_MODULE,
+			      &get_bypass_change_sd);
+	inter_module_register("set_dis_bypass_sd", THIS_MODULE,
+			      &set_dis_bypass_sd);
+	inter_module_register("get_dis_bypass_sd", THIS_MODULE,
+			      &get_dis_bypass_sd);
+	inter_module_register("set_bypass_pwoff_sd", THIS_MODULE,
+			      &set_bypass_pwoff_sd);
+	inter_module_register("get_bypass_pwoff_sd", THIS_MODULE,
+			      &get_bypass_pwoff_sd);
+	inter_module_register("set_bypass_pwup_sd", THIS_MODULE,
+			      &set_bypass_pwup_sd);
+	inter_module_register("get_bypass_pwup_sd", THIS_MODULE,
+			      &get_bypass_pwup_sd);
+	inter_module_register("get_bypass_wd_sd", THIS_MODULE,
+			      &get_bypass_wd_sd);
+	inter_module_register("set_bypass_wd_sd", THIS_MODULE,
+			      &set_bypass_wd_sd);
+	inter_module_register("get_wd_expire_time_sd", THIS_MODULE,
+			      &get_wd_expire_time_sd);
+	inter_module_register("reset_bypass_wd_timer_sd", THIS_MODULE,
+			      &reset_bypass_wd_timer_sd);
+	inter_module_register("set_std_nic_sd", THIS_MODULE, &set_std_nic_sd);
+	inter_module_register("get_std_nic_sd", THIS_MODULE, &get_std_nic_sd);
+	inter_module_register("set_tx_sd", THIS_MODULE, &set_tx_sd);
+	inter_module_register("get_tx_sd", THIS_MODULE, &get_tx_sd);
+	inter_module_register("set_tpl_sd", THIS_MODULE, &set_tpl_sd);
+	inter_module_register("get_tpl_sd", THIS_MODULE, &get_tpl_sd);
+
+	inter_module_register("set_bp_hw_reset_sd", THIS_MODULE,
+			      &set_bp_hw_reset_sd);
+	inter_module_register("get_bp_hw_reset_sd", THIS_MODULE,
+			      &get_bp_hw_reset_sd);
+
+	inter_module_register("set_tap_sd", THIS_MODULE, &set_tap_sd);
+	inter_module_register("get_tap_sd", THIS_MODULE, &get_tap_sd);
+	inter_module_register("get_tap_change_sd", THIS_MODULE,
+			      &get_tap_change_sd);
+	inter_module_register("set_dis_tap_sd", THIS_MODULE, &set_dis_tap_sd);
+	inter_module_register("get_dis_tap_sd", THIS_MODULE, &get_dis_tap_sd);
+	inter_module_register("set_tap_pwup_sd", THIS_MODULE, &set_tap_pwup_sd);
+	inter_module_register("get_tap_pwup_sd", THIS_MODULE, &get_tap_pwup_sd);
+	inter_module_register("set_bp_disc_sd", THIS_MODULE, &set_bp_disc_sd);
+	inter_module_register("get_bp_disc_sd", THIS_MODULE, &get_bp_disc_sd);
+	inter_module_register("get_bp_disc_change_sd", THIS_MODULE,
+			      &get_bp_disc_change_sd);
+	inter_module_register("set_bp_dis_disc_sd", THIS_MODULE,
+			      &set_bp_dis_disc_sd);
+	inter_module_register("get_bp_dis_disc_sd", THIS_MODULE,
+			      &get_bp_dis_disc_sd);
+	inter_module_register("set_bp_disc_pwup_sd", THIS_MODULE,
+			      &set_bp_disc_pwup_sd);
+	inter_module_register("get_bp_disc_pwup_sd", THIS_MODULE,
+			      &get_bp_disc_pwup_sd);
+	inter_module_register("set_wd_exp_mode_sd", THIS_MODULE,
+			      &set_wd_exp_mode_sd);
+	inter_module_register("get_wd_exp_mode_sd", THIS_MODULE,
+			      &get_wd_exp_mode_sd);
+	inter_module_register("set_wd_autoreset_sd", THIS_MODULE,
+			      &set_wd_autoreset_sd);
+	inter_module_register("get_wd_autoreset_sd", THIS_MODULE,
+			      &get_wd_autoreset_sd);
+	inter_module_register("get_bypass_info_sd", THIS_MODULE,
+			      &get_bypass_info_sd);
+	inter_module_register("bp_if_scan_sd", THIS_MODULE, &bp_if_scan_sd);
+
+#endif
+	register_netdevice_notifier(&bp_notifier_block);
+#ifdef BP_PROC_SUPPORT
+	{
+		int i = 0;
+		/* unsigned long flags; */
+		/* rcu_read_lock(); */
+		bp_proc_create();
+		for (i = 0; i < device_num; i++) {
+			if (bpctl_dev_arr[i].ifindex) {
+				/* spin_lock_irqsave(&bpvm_lock, flags); */
+				bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]);
+				bypass_proc_create_dev_sd(&bpctl_dev_arr[i]);
+				/* spin_unlock_irqrestore(&bpvm_lock, flags); */
+			}
+
+		}
+		/* rcu_read_unlock(); */
+	}
+#endif
+
+	return 0;
+}
+
+/*
+* Cleanup - unregister the appropriate file from /proc
+*/
+static void __exit bypass_cleanup_module(void)
+{
+	int i;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
+	int ret;
+#endif
+	unregister_netdevice_notifier(&bp_notifier_block);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+	inter_module_unregister("is_bypass_sd");
+	inter_module_unregister("get_bypass_slave_sd");
+	inter_module_unregister("get_bypass_caps_sd");
+	inter_module_unregister("get_wd_set_caps_sd");
+	inter_module_unregister("set_bypass_sd");
+	inter_module_unregister("get_bypass_sd");
+	inter_module_unregister("get_bypass_change_sd");
+	inter_module_unregister("set_dis_bypass_sd");
+	inter_module_unregister("get_dis_bypass_sd");
+	inter_module_unregister("set_bypass_pwoff_sd");
+	inter_module_unregister("get_bypass_pwoff_sd");
+	inter_module_unregister("set_bypass_pwup_sd");
+	inter_module_unregister("get_bypass_pwup_sd");
+	inter_module_unregister("set_bypass_wd_sd");
+	inter_module_unregister("get_bypass_wd_sd");
+	inter_module_unregister("get_wd_expire_time_sd");
+	inter_module_unregister("reset_bypass_wd_timer_sd");
+	inter_module_unregister("set_std_nic_sd");
+	inter_module_unregister("get_std_nic_sd");
+	inter_module_unregister("set_tx_sd");
+	inter_module_unregister("get_tx_sd");
+	inter_module_unregister("set_tpl_sd");
+	inter_module_unregister("get_tpl_sd");
+	inter_module_unregister("set_tap_sd");
+	inter_module_unregister("get_tap_sd");
+	inter_module_unregister("get_tap_change_sd");
+	inter_module_unregister("set_dis_tap_sd");
+	inter_module_unregister("get_dis_tap_sd");
+	inter_module_unregister("set_tap_pwup_sd");
+	inter_module_unregister("get_tap_pwup_sd");
+	inter_module_unregister("set_bp_disc_sd");
+	inter_module_unregister("get_bp_disc_sd");
+	inter_module_unregister("get_bp_disc_change_sd");
+	inter_module_unregister("set_bp_dis_disc_sd");
+	inter_module_unregister("get_bp_dis_disc_sd");
+	inter_module_unregister("set_bp_disc_pwup_sd");
+	inter_module_unregister("get_bp_disc_pwup_sd");
+	inter_module_unregister("set_wd_exp_mode_sd");
+	inter_module_unregister("get_wd_exp_mode_sd");
+	inter_module_unregister("set_wd_autoreset_sd");
+	inter_module_unregister("get_wd_autoreset_sd");
+	inter_module_unregister("get_bypass_info_sd");
+	inter_module_unregister("bp_if_scan_sd");
+
+#endif
+
+	for (i = 0; i < device_num; i++) {
+		/* unsigned long flags; */
+#ifdef BP_PROC_SUPPORT
+/*	spin_lock_irqsave(&bpvm_lock, flags);
+	rcu_read_lock(); */
+		bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]);
+/*	spin_unlock_irqrestore(&bpvm_lock, flags);        
+	rcu_read_unlock(); */
+#endif
+		remove_bypass_wd_auto(&bpctl_dev_arr[i]);
+		bpctl_dev_arr[i].reset_time = 0;
+
+		remove_bypass_tpl_auto(&bpctl_dev_arr[i]);
+	}
+
+	/* unmap all devices */
+	for (i = 0; i < device_num; i++) {
+#ifdef BP_SELF_TEST
+		if (bpctl_dev_arr[i].bp_tx_data)
+			kfree(bpctl_dev_arr[i].bp_tx_data);
+#endif
+		iounmap((void *)(bpctl_dev_arr[i].mem_map));
+	}
+
+	/* free all devices space */
+	if (bpctl_dev_arr)
+		kfree(bpctl_dev_arr);
+
+/*
+* Unregister the device                             
+*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
+	ret = unregister_chrdev(major_num, DEVICE_NAME);
+/*
+* If there's an error, report it
+*/
+	if (ret < 0)
+		printk("Error in module_unregister_chrdev: %d\n", ret);
+#else
+	unregister_chrdev(major_num, DEVICE_NAME);
+
+#endif
+}
+
+module_init(bypass_init_module);
+module_exit(bypass_cleanup_module);
+
+int is_bypass_sd(int ifindex)
+{
+	return is_bypass(get_dev_idx_p(ifindex));
+}
+
+int set_bypass_sd(int ifindex, int bypass_mode)
+{
+
+	return set_bypass_fn(get_dev_idx_p(ifindex), bypass_mode);
+}
+
+int get_bypass_sd(int ifindex)
+{
+
+	return get_bypass_fn(get_dev_idx_p(ifindex));
+}
+
+int get_bypass_change_sd(int ifindex)
+{
+
+	return get_bypass_change_fn(get_dev_idx_p(ifindex));
+}
+
+int set_dis_bypass_sd(int ifindex, int dis_param)
+{
+	return set_dis_bypass_fn(get_dev_idx_p(ifindex), dis_param);
+}
+
+int get_dis_bypass_sd(int ifindex)
+{
+
+	return get_dis_bypass_fn(get_dev_idx_p(ifindex));
+}
+
+int set_bypass_pwoff_sd(int ifindex, int bypass_mode)
+{
+	return set_bypass_pwoff_fn(get_dev_idx_p(ifindex), bypass_mode);
+
+}
+
+int get_bypass_pwoff_sd(int ifindex)
+{
+	return get_bypass_pwoff_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_bypass_pwup_sd(int ifindex, int bypass_mode)
+{
+	return set_bypass_pwup_fn(get_dev_idx_p(ifindex), bypass_mode);
+
+}
+
+int get_bypass_pwup_sd(int ifindex)
+{
+	return get_bypass_pwup_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set)
+{
+	if ((is_bypass(get_dev_idx_p(if_index))) <= 0)
+		return BP_NOT_CAP;
+	*ms_timeout_set = set_bypass_wd_fn(get_dev_idx_p(if_index), ms_timeout);
+	return 0;
+}
+
+int get_bypass_wd_sd(int ifindex, int *timeout)
+{
+	return get_bypass_wd_fn(get_dev_idx_p(ifindex), timeout);
+
+}
+
+int get_wd_expire_time_sd(int ifindex, int *time_left)
+{
+	return get_wd_expire_time_fn(get_dev_idx_p(ifindex), time_left);
+}
+
+int reset_bypass_wd_timer_sd(int ifindex)
+{
+	return reset_bypass_wd_timer_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_wd_set_caps_sd(int ifindex)
+{
+	return get_wd_set_caps_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_std_nic_sd(int ifindex, int nic_mode)
+{
+	return set_std_nic_fn(get_dev_idx_p(ifindex), nic_mode);
+
+}
+
+int get_std_nic_sd(int ifindex)
+{
+	return get_std_nic_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_tap_sd(int ifindex, int tap_mode)
+{
+	return set_tap_fn(get_dev_idx_p(ifindex), tap_mode);
+
+}
+
+int get_tap_sd(int ifindex)
+{
+	return get_tap_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_tap_pwup_sd(int ifindex, int tap_mode)
+{
+	return set_tap_pwup_fn(get_dev_idx_p(ifindex), tap_mode);
+
+}
+
+int get_tap_pwup_sd(int ifindex)
+{
+	return get_tap_pwup_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_tap_change_sd(int ifindex)
+{
+	return get_tap_change_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_dis_tap_sd(int ifindex, int dis_param)
+{
+	return set_dis_tap_fn(get_dev_idx_p(ifindex), dis_param);
+
+}
+
+int get_dis_tap_sd(int ifindex)
+{
+	return get_dis_tap_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_bp_disc_sd(int ifindex, int disc_mode)
+{
+	return set_disc_fn(get_dev_idx_p(ifindex), disc_mode);
+
+}
+
+int get_bp_disc_sd(int ifindex)
+{
+	return get_disc_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_bp_disc_pwup_sd(int ifindex, int disc_mode)
+{
+	return set_disc_pwup_fn(get_dev_idx_p(ifindex), disc_mode);
+
+}
+
+int get_bp_disc_pwup_sd(int ifindex)
+{
+	return get_disc_pwup_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_bp_disc_change_sd(int ifindex)
+{
+	return get_disc_change_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_bp_dis_disc_sd(int ifindex, int dis_param)
+{
+	return set_dis_disc_fn(get_dev_idx_p(ifindex), dis_param);
+
+}
+
+int get_bp_dis_disc_sd(int ifindex)
+{
+	return get_dis_disc_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_wd_exp_mode_sd(int ifindex)
+{
+	return get_wd_exp_mode_fn(get_dev_idx_p(ifindex));
+}
+
+int set_wd_exp_mode_sd(int ifindex, int param)
+{
+	return set_wd_exp_mode_fn(get_dev_idx_p(ifindex), param);
+
+}
+
+int reset_cont_sd(int ifindex)
+{
+	return reset_cont_fn(get_dev_idx_p(ifindex));
+
+}
+
+int set_tx_sd(int ifindex, int tx_state)
+{
+	return set_tx_fn(get_dev_idx_p(ifindex), tx_state);
+
+}
+
+int set_tpl_sd(int ifindex, int tpl_state)
+{
+	return set_tpl_fn(get_dev_idx_p(ifindex), tpl_state);
+
+}
+
+int set_bp_hw_reset_sd(int ifindex, int status)
+{
+	return set_bp_hw_reset_fn(get_dev_idx_p(ifindex), status);
+
+}
+
+int set_wd_autoreset_sd(int ifindex, int param)
+{
+	return set_wd_autoreset_fn(get_dev_idx_p(ifindex), param);
+
+}
+
+int get_wd_autoreset_sd(int ifindex)
+{
+	return get_wd_autoreset_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_bypass_caps_sd(int ifindex)
+{
+	return get_bypass_caps_fn(get_dev_idx_p(ifindex));
+}
+
+int get_bypass_slave_sd(int ifindex)
+{
+	bpctl_dev_t *pbpctl_dev_out;
+	int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out);
+	if (ret == 1)
+		return pbpctl_dev_out->ifindex;
+	return -1;
+
+}
+
+int get_tx_sd(int ifindex)
+{
+	return get_tx_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_tpl_sd(int ifindex)
+{
+	return get_tpl_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_bp_hw_reset_sd(int ifindex)
+{
+	return get_bp_hw_reset_fn(get_dev_idx_p(ifindex));
+
+}
+
+int get_bypass_info_sd(int ifindex, struct bp_info *bp_info)
+{
+	return get_bypass_info_fn(get_dev_idx_p(ifindex), bp_info->prod_name, &bp_info->fw_ver);
+}
+
+int bp_if_scan_sd(void)
+{
+	if_scan_init();
+	return 0;
+}
+
+EXPORT_SYMBOL_NOVERS(is_bypass_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_slave_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_caps_sd);
+EXPORT_SYMBOL_NOVERS(get_wd_set_caps_sd);
+EXPORT_SYMBOL_NOVERS(set_bypass_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_change_sd);
+EXPORT_SYMBOL_NOVERS(set_dis_bypass_sd);
+EXPORT_SYMBOL_NOVERS(get_dis_bypass_sd);
+EXPORT_SYMBOL_NOVERS(set_bypass_pwoff_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_pwoff_sd);
+EXPORT_SYMBOL_NOVERS(set_bypass_pwup_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_pwup_sd);
+EXPORT_SYMBOL_NOVERS(set_bypass_wd_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_wd_sd);
+EXPORT_SYMBOL_NOVERS(get_wd_expire_time_sd);
+EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer_sd);
+EXPORT_SYMBOL_NOVERS(set_std_nic_sd);
+EXPORT_SYMBOL_NOVERS(get_std_nic_sd);
+EXPORT_SYMBOL_NOVERS(set_tx_sd);
+EXPORT_SYMBOL_NOVERS(get_tx_sd);
+EXPORT_SYMBOL_NOVERS(set_tpl_sd);
+EXPORT_SYMBOL_NOVERS(get_tpl_sd);
+EXPORT_SYMBOL_NOVERS(set_bp_hw_reset_sd);
+EXPORT_SYMBOL_NOVERS(get_bp_hw_reset_sd);
+EXPORT_SYMBOL_NOVERS(set_tap_sd);
+EXPORT_SYMBOL_NOVERS(get_tap_sd);
+EXPORT_SYMBOL_NOVERS(get_tap_change_sd);
+EXPORT_SYMBOL_NOVERS(set_dis_tap_sd);
+EXPORT_SYMBOL_NOVERS(get_dis_tap_sd);
+EXPORT_SYMBOL_NOVERS(set_tap_pwup_sd);
+EXPORT_SYMBOL_NOVERS(get_tap_pwup_sd);
+EXPORT_SYMBOL_NOVERS(set_wd_exp_mode_sd);
+EXPORT_SYMBOL_NOVERS(get_wd_exp_mode_sd);
+EXPORT_SYMBOL_NOVERS(set_wd_autoreset_sd);
+EXPORT_SYMBOL_NOVERS(get_wd_autoreset_sd);
+EXPORT_SYMBOL_NOVERS(set_bp_disc_sd);
+EXPORT_SYMBOL_NOVERS(get_bp_disc_sd);
+EXPORT_SYMBOL_NOVERS(get_bp_disc_change_sd);
+EXPORT_SYMBOL_NOVERS(set_bp_dis_disc_sd);
+EXPORT_SYMBOL_NOVERS(get_bp_dis_disc_sd);
+EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup_sd);
+EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup_sd);
+EXPORT_SYMBOL_NOVERS(get_bypass_info_sd);
+EXPORT_SYMBOL_NOVERS(bp_if_scan_sd);
+
+#define BP_PROC_DIR "bypass"
+
+#define GPIO6_SET_ENTRY_SD           "gpio6_set"
+#define GPIO6_CLEAR_ENTRY_SD         "gpio6_clear"
+
+#define GPIO7_SET_ENTRY_SD           "gpio7_set"
+#define GPIO7_CLEAR_ENTRY_SD         "gpio7_clear"
+
+#define PULSE_SET_ENTRY_SD            "pulse_set"
+#define ZERO_SET_ENTRY_SD            "zero_set"
+#define PULSE_GET1_ENTRY_SD            "pulse_get1"
+#define PULSE_GET2_ENTRY_SD            "pulse_get2"
+
+#define CMND_ON_ENTRY_SD              "cmnd_on"
+#define CMND_OFF_ENTRY_SD             "cmnd_off"
+#define RESET_CONT_ENTRY_SD           "reset_cont"
+
+ /*COMMANDS*/
+#define BYPASS_INFO_ENTRY_SD     "bypass_info"
+#define BYPASS_SLAVE_ENTRY_SD    "bypass_slave"
+#define BYPASS_CAPS_ENTRY_SD     "bypass_caps"
+#define WD_SET_CAPS_ENTRY_SD     "wd_set_caps"
+#define BYPASS_ENTRY_SD          "bypass"
+#define BYPASS_CHANGE_ENTRY_SD   "bypass_change"
+#define BYPASS_WD_ENTRY_SD       "bypass_wd"
+#define WD_EXPIRE_TIME_ENTRY_SD  "wd_expire_time"
+#define RESET_BYPASS_WD_ENTRY_SD "reset_bypass_wd"
+#define DIS_BYPASS_ENTRY_SD      "dis_bypass"
+#define BYPASS_PWUP_ENTRY_SD     "bypass_pwup"
+#define BYPASS_PWOFF_ENTRY_SD     "bypass_pwoff"
+#define STD_NIC_ENTRY_SD         "std_nic"
+#define STD_NIC_ENTRY_SD         "std_nic"
+#define TAP_ENTRY_SD             "tap"
+#define TAP_CHANGE_ENTRY_SD      "tap_change"
+#define DIS_TAP_ENTRY_SD         "dis_tap"
+#define TAP_PWUP_ENTRY_SD        "tap_pwup"
+#define TWO_PORT_LINK_ENTRY_SD   "two_port_link"
+#define WD_EXP_MODE_ENTRY_SD     "wd_exp_mode"
+#define WD_AUTORESET_ENTRY_SD    "wd_autoreset"
+#define TPL_ENTRY_SD             "tpl"
+#define WAIT_AT_PWUP_ENTRY_SD    "wait_at_pwup"
+#define HW_RESET_ENTRY_SD        "hw_reset"
+#define DISC_ENTRY_SD             "disc"
+#define DISC_CHANGE_ENTRY_SD      "disc_change"
+#define DIS_DISC_ENTRY_SD         "dis_disc"
+#define DISC_PWUP_ENTRY_SD        "disc_pwup"
+static struct proc_dir_entry *bp_procfs_dir;
+
+static struct proc_dir_entry *proc_getdir(char *name,
+					  struct proc_dir_entry *proc_dir)
+{
+	struct proc_dir_entry *pde = proc_dir;
+
+	for (pde = pde->subdir; pde; pde = pde->next) {
+		if (pde->namelen && (strcmp(name, pde->name) == 0)) {
+			/* directory exists */
+			break;
+		}
+	}
+	if (pde == (struct proc_dir_entry *)0) {
+		/* create the directory */
+#if (LINUX_VERSION_CODE > 0x20300)
+		pde = proc_mkdir(name, proc_dir);
+#else
+		pde = create_proc_entry(name, S_IFDIR, proc_dir);
+#endif
+		if (pde == (struct proc_dir_entry *)0) {
+
+			return pde;
+		}
+	}
+
+	return pde;
+}
+
+int bp_proc_create(void)
+{
+	bp_procfs_dir = proc_getdir(BP_PROC_DIR, init_net.proc_net);
+	if (bp_procfs_dir == (struct proc_dir_entry *)0) {
+		printk(KERN_DEBUG
+		       "Could not create procfs nicinfo directory %s\n",
+		       BP_PROC_DIR);
+		return -1;
+	}
+	return 0;
+}
+
+int
+bypass_proc_create_entry_sd(struct pfs_unit_sd *pfs_unit_curr,
+			    char *proc_name,
+			    write_proc_t *write_proc,
+			    read_proc_t *read_proc,
+			    struct proc_dir_entry *parent_pfs, void *data)
+{
+	strcpy(pfs_unit_curr->proc_name, proc_name);
+	pfs_unit_curr->proc_entry = create_proc_entry(pfs_unit_curr->proc_name,
+						      S_IFREG | S_IRUSR |
+						      S_IWUSR | S_IRGRP |
+						      S_IROTH, parent_pfs);
+	if (pfs_unit_curr->proc_entry == NULL)
+		return -1;
+
+	pfs_unit_curr->proc_entry->read_proc = read_proc;
+	pfs_unit_curr->proc_entry->write_proc = write_proc;
+	pfs_unit_curr->proc_entry->data = data;
+
+	return 0;
+
+}
+
+int
+get_bypass_info_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+	int len = 0;
+
+	len += sprintf(page, "Name\t\t\t%s\n", pbp_device_block->name);
+	len +=
+	    sprintf(page + len, "Firmware version\t0x%x\n",
+		    pbp_device_block->bp_fw_ver);
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_slave_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0;
+	bpctl_dev_t *pbp_device_block_slave = NULL;
+	int idx_dev = 0;
+	struct net_device *net_slave_dev = NULL;
+
+	if ((pbp_device_block->func == 0) || (pbp_device_block->func == 2)) {
+		for (idx_dev = 0;
+		     ((bpctl_dev_arr[idx_dev].pdev != NULL)
+		      && (idx_dev < device_num)); idx_dev++) {
+			if ((bpctl_dev_arr[idx_dev].bus ==
+			     pbp_device_block->bus)
+			    && (bpctl_dev_arr[idx_dev].slot ==
+				pbp_device_block->slot)) {
+				if ((pbp_device_block->func == 0)
+				    && (bpctl_dev_arr[idx_dev].func == 1)) {
+					pbp_device_block_slave =
+					    &bpctl_dev_arr[idx_dev];
+					break;
+				}
+				if ((pbp_device_block->func == 2) &&
+				    (bpctl_dev_arr[idx_dev].func == 3)) {
+					pbp_device_block_slave =
+					    &bpctl_dev_arr[idx_dev];
+					break;
+				}
+			}
+		}
+	} else
+		pbp_device_block_slave = pbp_device_block;
+	if (!pbp_device_block_slave) {
+		len = sprintf(page, "fail\n");
+		*eof = 1;
+		return len;
+	}
+	net_slave_dev = pbp_device_block_slave->ndev;
+	if (net_slave_dev) {
+		if (net_slave_dev)
+			len = sprintf(page, "%s\n", net_slave_dev->name);
+		else
+			len = sprintf(page, "fail\n");
+
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_caps_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_caps_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "-1\n");
+	else
+		len = sprintf(page, "0x%x\n", ret);
+	*eof = 1;
+	return len;
+
+}
+
+int
+get_wd_set_caps_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_set_caps_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "-1\n");
+	else
+		len = sprintf(page, "0x%x\n", ret);
+	*eof = 1;
+	return len;
+}
+
+int
+set_bypass_pfs(struct file *file, const char *buffer,
+	       unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_tap_pfs(struct file *file, const char *buffer,
+	    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_tap_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_disc_pfs(struct file *file, const char *buffer,
+	     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_disc_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_bypass_pfs(char *page, char **start, off_t off, int count,
+	       int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_pfs(char *page, char **start, off_t off, int count,
+	    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_pfs(char *page, char **start, off_t off, int count,
+	     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_change_pfs(char *page, char **start, off_t off, int count,
+		      int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_change_pfs(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_change_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+#define isdigit(c) (c >= '0' && c <= '9')
+__inline static int atoi(char **s)
+{
+	int i = 0;
+	while (isdigit(**s))
+		i = i * 10 + *((*s)++) - '0';
+	return i;
+}
+
+int
+set_bypass_wd_pfs(struct file *file, const char *buffer,
+		  unsigned long count, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+	int timeout;
+	int ret;
+
+	ret = kstrtoint_from_user(buffer, count, 10, &timeout);
+	if (ret)
+		return ret;
+	set_bypass_wd_fn(pbp_device_block, timeout);
+
+	return count;
+}
+
+int
+get_bypass_wd_pfs(char *page, char **start, off_t off, int count,
+		  int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0, timeout = 0;
+
+	ret = get_bypass_wd_fn(pbp_device_block, &timeout);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (timeout == -1)
+		len = sprintf(page, "unknown\n");
+	else if (timeout == 0)
+		len = sprintf(page, "disable\n");
+	else
+		len = sprintf(page, "%d\n", timeout);
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_wd_expire_time_pfs(char *page, char **start, off_t off, int count,
+		       int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0, timeout = 0;
+
+	ret = get_wd_expire_time_fn(pbp_device_block, &timeout);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (timeout == -1)
+		len = sprintf(page, "expire\n");
+	else if (timeout == 0)
+		len = sprintf(page, "disable\n");
+
+	else
+		len = sprintf(page, "%d\n", timeout);
+	*eof = 1;
+	return len;
+}
+
+int
+get_tpl_pfs(char *page, char **start, off_t off, int count,
+	    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tpl_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+#ifdef PMC_FIX_FLAG
+int
+get_wait_at_pwup_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bp_wait_at_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_hw_reset_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bp_hw_reset_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+#endif				/*PMC_WAIT_FLAG */
+
+int
+reset_bypass_wd_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = reset_bypass_wd_timer_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "disable\n");
+	else if (ret == 1)
+		len = sprintf(page, "success\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_dis_bypass_pfs(struct file *file, const char *buffer,
+		   unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_dis_bypass_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_dis_tap_pfs(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_dis_tap_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_dis_disc_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_dis_disc_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_dis_bypass_pfs(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_bypass_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_dis_tap_pfs(char *page, char **start, off_t off, int count,
+		int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_tap_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_dis_disc_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_disc_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_bypass_pwup_pfs(struct file *file, const char *buffer,
+		    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_pwup_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_bypass_pwoff_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_pwoff_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_tap_pwup_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_tap_pwup_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_disc_pwup_pfs(struct file *file, const char *buffer,
+		  unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_disc_pwup_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_bypass_pwup_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_pwoff_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_pwoff_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_pwup_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_pwup_pfs(char *page, char **start, off_t off, int count,
+		  int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_std_nic_pfs(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count >= sizeof(kbuf))
+		return -EINVAL;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_std_nic_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+get_std_nic_pfs(char *page, char **start, off_t off, int count,
+		int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_std_nic_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_wd_exp_mode_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_exp_mode_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "tap\n");
+	else if (ret == 0)
+		len = sprintf(page, "bypass\n");
+	else if (ret == 2)
+		len = sprintf(page, "disc\n");
+
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_wd_exp_mode_pfs(struct file *file, const char *buffer,
+		    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "tap") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "bypass") == 0)
+		bypass_param = 0;
+	else if (strcmp(kbuf, "disc") == 0)
+		bypass_param = 2;
+
+	set_wd_exp_mode_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+get_wd_autoreset_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_autoreset_fn(pbp_device_block);
+	if (ret >= 0)
+		len = sprintf(page, "%d\n", ret);
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_wd_autoreset_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+	int timeout;
+	int ret;
+
+	ret = kstrtoint_from_user(buffer, count, 10, &timeout);
+	if (ret)
+		return ret;
+	set_wd_autoreset_fn(pbp_device_block, timeout);
+
+	return count;
+}
+
+int
+set_tpl_pfs(struct file *file, const char *buffer,
+	    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_tpl_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+#ifdef PMC_FIX_FLAG
+int
+set_wait_at_pwup_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_bp_wait_at_pwup_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+int
+set_hw_reset_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_bp_hw_reset_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+#endif				/*PMC_FIX_FLAG */
+
+int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block)
+{
+	struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set);
+	static struct proc_dir_entry *procfs_dir = NULL;
+	int ret = 0;
+
+	if (!pbp_device_block->ndev)
+		return -1;
+	sprintf(current_pfs->dir_name, "bypass_%s",
+		pbp_device_block->ndev->name);
+
+	if (!bp_procfs_dir)
+		return -1;
+
+	/* create device proc dir */
+	procfs_dir = proc_getdir(current_pfs->dir_name, bp_procfs_dir);
+	if (procfs_dir == 0) {
+		printk(KERN_DEBUG "Could not create procfs directory %s\n",
+		       current_pfs->dir_name);
+		return -1;
+	}
+	current_pfs->bypass_entry = procfs_dir;
+
+	if (bypass_proc_create_entry_sd(&(current_pfs->bypass_info), BYPASS_INFO_ENTRY_SD, NULL,	/* write */
+					get_bypass_info_pfs,	/* read  */
+					procfs_dir, pbp_device_block))
+		ret = -1;
+
+	if (pbp_device_block->bp_caps & SW_CTL_CAP) {
+
+		/* Create set param proc's */
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_slave), BYPASS_SLAVE_ENTRY_SD, NULL,	/* write */
+						get_bypass_slave_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_caps), BYPASS_CAPS_ENTRY_SD, NULL,	/* write */
+						get_bypass_caps_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_set_caps), WD_SET_CAPS_ENTRY_SD, NULL,	/* write */
+						get_wd_set_caps_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_wd), BYPASS_WD_ENTRY_SD, set_bypass_wd_pfs,	/* write */
+						get_bypass_wd_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_expire_time), WD_EXPIRE_TIME_ENTRY_SD, NULL,	/* write */
+						get_wd_expire_time_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->reset_bypass_wd), RESET_BYPASS_WD_ENTRY_SD, NULL,	/* write */
+						reset_bypass_wd_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->std_nic), STD_NIC_ENTRY_SD, set_std_nic_pfs,	/* write */
+						get_std_nic_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (pbp_device_block->bp_caps & BP_CAP) {
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass), BYPASS_ENTRY_SD, set_bypass_pfs,	/* write */
+							get_bypass_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_bypass), DIS_BYPASS_ENTRY_SD, set_dis_bypass_pfs,	/* write */
+							get_dis_bypass_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwup), BYPASS_PWUP_ENTRY_SD, set_bypass_pwup_pfs,	/* write */
+							get_bypass_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwoff), BYPASS_PWOFF_ENTRY_SD, set_bypass_pwoff_pfs,	/* write */
+							get_bypass_pwoff_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_change), BYPASS_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_bypass_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+
+		if (pbp_device_block->bp_caps & TAP_CAP) {
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap), TAP_ENTRY_SD, set_tap_pfs,	/* write */
+							get_tap_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_TAP_ENTRY_SD, set_dis_tap_pfs,	/* write */
+							get_dis_tap_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), TAP_PWUP_ENTRY_SD, set_tap_pwup_pfs,	/* write */
+							get_tap_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), TAP_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_tap_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+		if (pbp_device_block->bp_caps & DISC_CAP) {
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap), DISC_ENTRY_SD, set_disc_pfs,	/* write */
+							get_disc_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+#if 1
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_DISC_ENTRY_SD, set_dis_disc_pfs,	/* write */
+							get_dis_disc_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+#endif
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), DISC_PWUP_ENTRY_SD, set_disc_pwup_pfs,	/* write */
+							get_disc_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), DISC_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_disc_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_exp_mode), WD_EXP_MODE_ENTRY_SD, set_wd_exp_mode_pfs,	/* write */
+						get_wd_exp_mode_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_autoreset), WD_AUTORESET_ENTRY_SD, set_wd_autoreset_pfs,	/* write */
+						get_wd_autoreset_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), TPL_ENTRY_SD, set_tpl_pfs,	/* write */
+						get_tpl_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+#ifdef PMC_FIX_FLAG
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), WAIT_AT_PWUP_ENTRY_SD, set_wait_at_pwup_pfs,	/* write */
+						get_wait_at_pwup_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), HW_RESET_ENTRY_SD, set_hw_reset_pfs,	/* write */
+						get_hw_reset_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+#endif
+
+	}
+	if (ret < 0)
+		printk(KERN_DEBUG "Create proc entry failed\n");
+
+	return ret;
+}
+
+int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block)
+{
+
+	struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set;
+	struct proc_dir_entry *pde = current_pfs->bypass_entry, *pde_curr =
+	    NULL;
+	char name[256];
+
+	if (!pde)
+		return 0;
+	for (pde = pde->subdir; pde;) {
+		strcpy(name, pde->name);
+		pde_curr = pde;
+		pde = pde->next;
+		remove_proc_entry(name, current_pfs->bypass_entry);
+	}
+	if (!pde)
+		remove_proc_entry(current_pfs->dir_name, bp_procfs_dir);
+	current_pfs->bypass_entry = NULL;
+
+	return 0;
+}
diff --git a/drivers/staging/silicom/bp_mod.h b/drivers/staging/silicom/bp_mod.h
new file mode 100644
index 0000000..b8275f5
--- /dev/null
+++ b/drivers/staging/silicom/bp_mod.h
@@ -0,0 +1,704 @@
+/******************************************************************************/
+/*                                                                            */
+/* Bypass Control utility, Copyright (c) 2005 Silicom                         */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/* bp_mod.h                                                                   */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef BP_MOD_H
+#define BP_MOD_H
+#include "bits.h"
+
+#define EXPORT_SYMBOL_NOVERS EXPORT_SYMBOL
+
+#define usec_delay(x) udelay(x)
+#ifndef msec_delay_bp
+#define msec_delay_bp(x)			\
+do {						\
+	int  i;					\
+	if (1) {				\
+		for (i = 0; i < 1000; i++) {	\
+			udelay(x) ;		\
+		}				\
+	} else {				\
+		msleep(x);			\
+	}					\
+} while (0)
+
+#endif
+
+#include <linux/param.h>
+
+#ifndef jiffies_to_msecs
+#define jiffies_to_msecs(x) _kc_jiffies_to_msecs(x)
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+	return (1000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+	return (j + (HZ / 1000) - 1) / (HZ / 1000);
+#else
+	return (j * 1000) / HZ;
+#endif
+}
+#endif
+
+#define SILICOM_VID              0x1374
+#define SILICOM_SVID             0x1374
+
+#define SILICOM_PXG2BPFI_SSID    0x0026
+#define SILICOM_PXG2BPFILX_SSID  0x0027
+#define SILICOM_PXGBPI_SSID      0x0028
+#define SILICOM_PXGBPIG_SSID     0x0029
+#define SILICOM_PXG2TBFI_SSID    0x002a
+#define SILICOM_PXG4BPI_SSID     0x002c
+#define SILICOM_PXG4BPFI_SSID    0x002d
+#define SILICOM_PXG4BPFILX_SSID  0x002e
+#define SILICOM_PXG2BPFIL_SSID   0x002F
+#define SILICOM_PXG2BPFILLX_SSID 0x0030
+#define SILICOM_PEG4BPI_SSID     0x0031
+#define SILICOM_PEG2BPI_SSID     0x0037
+#define SILICOM_PEG4BPIN_SSID    0x0038
+#define SILICOM_PEG2BPFI_SSID    0x0039
+#define SILICOM_PEG2BPFILX_SSID  0x003A
+#define SILICOM_PMCXG2BPFI_SSID  0x003B
+#define NOKIA_PMCXG2BPFIN_SSID   0x0510
+#define NOKIA_PMCXG2BPIN_SSID    0x0513
+#define NOKIA_PMCXG4BPIN_SSID    0x0514
+#define NOKIA_PMCXG2BPFIN_SVID   0x13B8
+#define NOKIA_PMCXG2BPIN2_SSID    0x0515
+#define NOKIA_PMCXG4BPIN2_SSID    0x0516
+#define SILICOM_PMCX2BPI_SSID       0x041
+#define SILICOM_PMCX4BPI_SSID       0x042
+#define SILICOM_PXG2BISC1_SSID   0x003d
+#define SILICOM_PEG2TBFI_SSID    0x003E
+#define SILICOM_PXG2TBI_SSID     0x003f
+#define SILICOM_PXG4BPFID_SSID   0x0043
+#define SILICOM_PEG4BPFI_SSID    0x0040
+#define SILICOM_PEG4BPIPT_SSID   0x0044
+#define SILICOM_PXG6BPI_SSID     0x0045
+#define SILICOM_PEG4BPIL_SSID    0x0046
+#define SILICOM_PEG2BPI5_SSID    0x0052
+#define SILICOM_PEG6BPI_SSID    0x0053
+#define SILICOM_PEG4BPFI5_SSID   0x0050
+#define SILICOM_PEG4BPFI5LX_SSID   0x0051
+#define SILICOM_PEG2BISC6_SSID 0x54
+
+#define SILICOM_PEG6BPIFC_SSID 0x55
+
+#define SILICOM_PEG2BPFI5_SSID   0x0056
+#define SILICOM_PEG2BPFI5LX_SSID   0x0057
+
+#define SILICOM_PXEG4BPFI_SSID    0x0058
+
+#define SILICOM_PEG2BPFID_SSID   0x0047
+#define SILICOM_PEG2BPFIDLX_SSID  0x004C
+#define SILICOM_MEG2BPFILN_SSID  0x0048
+#define SILICOM_MEG2BPFINX_SSID  0x0049
+#define SILICOM_PEG4BPFILX_SSID  0x004A
+#define SILICOM_MHIO8AD_SSID    0x004F
+
+#define SILICOM_MEG2BPFILXLN_SSID 0x004b
+#define SILICOM_PEG2BPIX1_SSID    0x004d
+#define SILICOM_MEG2BPFILXNX_SSID 0x004e
+
+#define SILICOM_PE10G2BPISR_SSID  0x0102
+#define SILICOM_PE10G2BPILR_SSID  0x0103
+#define SILICOM_PE10G2BPICX4_SSID  0x0101
+
+#define SILICOM_XE10G2BPILR_SSID 0x0163
+#define SILICOM_XE10G2BPISR_SSID 0x0162
+#define SILICOM_XE10G2BPICX4_SSID 0x0161
+#define SILICOM_XE10G2BPIT_SSID   0x0160
+
+#define SILICOM_PE10GDBISR_SSID   0x0181
+#define SILICOM_PE10GDBILR_SSID   0x0182
+
+#define SILICOM_PE210G2DBi9SR_SSID	    0x0188
+#define SILICOM_PE210G2DBi9SRRB_SSID	0x0188
+#define SILICOM_PE210G2DBi9LR_SSID	    0x0189
+#define SILICOM_PE210G2DBi9LRRB_SSID	0x0189
+#define SILICOM_PE310G4DBi940SR_SSID	0x018C
+
+#define SILICOM_PE310G4BPi9T_SSID       0x130
+#define SILICOM_PE310G4BPi9SR_SSID        0x132
+#define SILICOM_PE310G4BPi9LR_SSID        0x133
+
+#define NOKIA_XE10G2BPIXR_SVID   0x13B8
+#define NOKIA_XE10G2BPIXR_SSID   0x051C
+
+#define INTEL_PEG4BPII_PID   0x10A0
+#define INTEL_PEG4BPFII_PID   0x10A1
+#define INTEL_PEG4BPII_SSID   0x11A0
+#define INTEL_PEG4BPFII_SSID   0x11A1
+
+#define INTEL_PEG4BPIIO_SSID   0x10A0
+#define INTEL_PEG4BPIIO_PID   0x105e
+
+#define BROADCOM_VID         0x14e4
+#define BROADCOM_PE10G2_PID  0x164e
+
+#define SILICOM_PE10G2BPTCX4_SSID 0x0141
+#define SILICOM_PE10G2BPTSR_SSID  0x0142
+#define SILICOM_PE10G2BPTLR_SSID  0x0143
+#define SILICOM_PE10G2BPTT_SSID   0x0140
+
+#define SILICOM_PEG4BPI6_SSID     0x0320
+#define SILICOM_PEG4BPFI6_SSID    0x0321
+#define SILICOM_PEG4BPFI6LX_SSID    0x0322
+#define SILICOM_PEG4BPFI6ZX_SSID    0x0323
+
+#define SILICOM_PEG2BPI6_SSID    0x0300
+#define SILICOM_PEG2BPFI6_SSID    0x0301
+#define SILICOM_PEG2BPFI6LX_SSID    0x0302
+#define SILICOM_PEG2BPFI6ZX_SSID    0x0303
+#define SILICOM_PEG2BPFI6FLXM_SSID  0x0304
+
+#define SILICOM_PEG2DBI6_SSID    0x0308
+#define SILICOM_PEG2DBFI6_SSID    0x0309
+#define SILICOM_PEG2DBFI6LX_SSID    0x030A
+#define SILICOM_PEG2DBFI6ZX_SSID    0x030B
+
+#define SILICOM_MEG2BPI6_SSID     0x0310
+#define SILICOM_XEG2BPI6_SSID    0x0318
+#define SILICOM_PEG4BPI6FC_SSID     0x0328
+#define SILICOM_PEG4BPFI6FC_SSID    0x0329
+#define SILICOM_PEG4BPFI6FCLX_SSID    0x032A
+#define SILICOM_PEG4BPFI6FCZX_SSID    0x032B
+
+#define SILICOM_PEG6BPI6_SSID     0x0340
+
+#define SILICOM_PEG2BPI6SC6_SSID     0x0360
+
+#define SILICOM_MEG2BPI6_SSID     0x0310
+#define SILICOM_XEG2BPI6_SSID     0x0318
+#define SILICOM_MEG4BPI6_SSID     0x0330
+
+#define SILICOM_PE2G4BPi80L_SSID    0x0380
+
+#define SILICOM_M6E2G8BPi80A_SSID    0x0474
+
+#define SILICOM_PE2G4BPi35_SSID    0x03d8
+
+#define SILICOM_PE2G4BPFi80_SSID    0x0381
+#define SILICOM_PE2G4BPFi80LX_SSID    0x0382
+#define SILICOM_PE2G4BPFi80ZX_SSID    0x0383
+
+#define SILICOM_PE2G4BPi80_SSID    0x0388
+
+#define SILICOM_PE2G2BPi80_SSID    0x0390
+#define SILICOM_PE2G2BPFi80_SSID    0x0391
+#define SILICOM_PE2G2BPFi80LX_SSID    0x0392
+#define SILICOM_PE2G2BPFi80ZX_SSID    0x0393
+
+#define SILICOM_PE2G4BPi35L_SSID    0x03D0
+#define SILICOM_PE2G4BPFi35_SSID    0x03D1
+#define SILICOM_PE2G4BPFi35LX_SSID    0x03D2
+#define SILICOM_PE2G4BPFi35ZX_SSID    0x03D3
+
+#define SILICOM_PE2G2BPi35_SSID    0x03c0
+#define SILICOM_PAC1200BPi35_SSID    0x03cc
+#define SILICOM_PE2G2BPFi35_SSID    0x03C1
+#define SILICOM_PE2G2BPFi35LX_SSID    0x03C2
+#define SILICOM_PE2G2BPFi35ZX_SSID    0x03C3
+
+#define SILICOM_PE2G6BPi35_SSID    0x03E0
+#define SILICOM_PE2G6BPi35CX_SSID  0x0AA0
+
+#define INTEL_PE210G2SPI9_SSID     0x00C
+
+#define SILICOM_M1EG2BPI6_SSID     0x400
+
+#define SILICOM_M1EG2BPFI6_SSID     0x0401
+#define SILICOM_M1EG2BPFI6LX_SSID     0x0402
+#define SILICOM_M1EG2BPFI6ZX_SSID     0x0403
+
+#define SILICOM_M1EG4BPI6_SSID     0x0420
+
+#define SILICOM_M1EG4BPFI6_SSID       0x0421
+#define SILICOM_M1EG4BPFI6LX_SSID     0x0422
+#define SILICOM_M1EG4BPFI6ZX_SSID     0x0423
+
+#define SILICOM_M1EG6BPI6_SSID     0x0440
+
+#define SILICOM_M1E2G4BPi80_SSID     0x0460
+#define SILICOM_M1E2G4BPFi80_SSID       0x0461
+#define SILICOM_M1E2G4BPFi80LX_SSID     0x0462
+#define SILICOM_M1E2G4BPFi80ZX_SSID     0x0463
+
+#define SILICOM_M6E2G8BPi80_SSID        0x0470
+#define SILICOM_PE210G2BPi40_SSID       0x01a0
+
+#define PEG540_IF_SERIES(pid) \
+	((pid == SILICOM_PE210G2BPi40_SSID))
+
+#define OLD_IF_SERIES(pid)\
+	((pid == SILICOM_PXG2BPFI_SSID) || \
+	 (pid == SILICOM_PXG2BPFILX_SSID))
+
+#define P2BPFI_IF_SERIES(pid) \
+	((pid == SILICOM_PXG2BPFI_SSID) || \
+	 (pid == SILICOM_PXG2BPFILX_SSID) || \
+	 (pid == SILICOM_PEG2BPFI_SSID) || \
+	 (pid == SILICOM_PEG2BPFID_SSID) || \
+	 (pid == SILICOM_PEG2BPFIDLX_SSID) || \
+	 (pid == SILICOM_MEG2BPFILN_SSID) || \
+	 (pid == SILICOM_MEG2BPFINX_SSID) || \
+	 (pid == SILICOM_PEG4BPFILX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI_SSID) || \
+	 (pid == SILICOM_PXEG4BPFI_SSID) || \
+	 (pid == SILICOM_PXG4BPFID_SSID) || \
+	 (pid == SILICOM_PEG2TBFI_SSID) || \
+	 (pid == SILICOM_PE10G2BPISR_SSID) || \
+	 (pid == SILICOM_PE10G2BPILR_SSID) || \
+	 (pid == SILICOM_PEG2BPFILX_SSID) || \
+	 (pid == SILICOM_PMCXG2BPFI_SSID) || \
+	 (pid == SILICOM_MHIO8AD_SSID) || \
+	 (pid == SILICOM_PEG4BPFI5LX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI5_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6FC_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6FCLX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6FCZX_SSID) || \
+	 (pid == NOKIA_PMCXG2BPFIN_SSID) || \
+	 (pid == SILICOM_MEG2BPFILXLN_SSID) || \
+	 (pid == SILICOM_MEG2BPFILXNX_SSID) || \
+	 (pid == SILICOM_XE10G2BPIT_SSID) || \
+	 (pid == SILICOM_XE10G2BPICX4_SSID) || \
+	 (pid == SILICOM_XE10G2BPISR_SSID) || \
+	 (pid == NOKIA_XE10G2BPIXR_SSID) || \
+	 (pid == SILICOM_PE10GDBISR_SSID) || \
+	 (pid == SILICOM_PE10GDBILR_SSID) || \
+	 (pid == SILICOM_XE10G2BPILR_SSID))
+
+#define INTEL_IF_SERIES(pid) \
+	((pid == INTEL_PEG4BPII_SSID) || \
+	 (pid == INTEL_PEG4BPIIO_SSID) || \
+	 (pid == INTEL_PEG4BPFII_SSID))
+
+#define NOKIA_SERIES(pid) \
+	((pid == NOKIA_PMCXG2BPIN_SSID) || \
+	 (pid == NOKIA_PMCXG4BPIN_SSID) || \
+	 (pid == SILICOM_PMCX4BPI_SSID) || \
+	 (pid == NOKIA_PMCXG2BPFIN_SSID) || \
+	 (pid == SILICOM_PMCXG2BPFI_SSID) || \
+	 (pid == NOKIA_PMCXG2BPIN2_SSID) || \
+	 (pid == NOKIA_PMCXG4BPIN2_SSID) || \
+	 (pid == SILICOM_PMCX2BPI_SSID))
+
+#define DISCF_IF_SERIES(pid) \
+	(pid == SILICOM_PEG2TBFI_SSID)
+
+#define PEGF_IF_SERIES(pid) \
+	((pid == SILICOM_PEG2BPFI_SSID) || \
+	 (pid == SILICOM_PEG2BPFID_SSID) || \
+	 (pid == SILICOM_PEG2BPFIDLX_SSID) || \
+	 (pid == SILICOM_PEG2BPFILX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI_SSID) || \
+	 (pid == SILICOM_PXEG4BPFI_SSID) || \
+	 (pid == SILICOM_MEG2BPFILN_SSID) || \
+	 (pid == SILICOM_MEG2BPFINX_SSID) || \
+	 (pid == SILICOM_PEG4BPFILX_SSID) || \
+	 (pid == SILICOM_PEG2TBFI_SSID) || \
+	 (pid == SILICOM_MEG2BPFILXLN_SSID) || \
+	 (pid == SILICOM_MEG2BPFILXNX_SSID))
+
+#define TPL_IF_SERIES(pid) \
+	((pid == SILICOM_PXG2BPFIL_SSID) || \
+	 (pid == SILICOM_PXG2BPFILLX_SSID) || \
+	 (pid == SILICOM_PXG2TBFI_SSID) || \
+	 (pid == SILICOM_PXG4BPFID_SSID) || \
+	 (pid == SILICOM_PXG4BPFI_SSID))
+
+#define BP10G_IF_SERIES(pid) \
+	((pid == SILICOM_PE10G2BPISR_SSID) || \
+	 (pid == SILICOM_PE10G2BPICX4_SSID) || \
+	 (pid == SILICOM_PE10G2BPILR_SSID) || \
+	 (pid == SILICOM_XE10G2BPIT_SSID) || \
+	 (pid == SILICOM_XE10G2BPICX4_SSID) || \
+	 (pid == SILICOM_XE10G2BPISR_SSID) || \
+	 (pid == NOKIA_XE10G2BPIXR_SSID) || \
+	 (pid == SILICOM_PE10GDBISR_SSID) || \
+	 (pid == SILICOM_PE10GDBILR_SSID) || \
+	 (pid == SILICOM_XE10G2BPILR_SSID))
+
+#define BP10GB_IF_SERIES(pid) \
+	((pid == SILICOM_PE10G2BPTCX4_SSID) || \
+	 (pid == SILICOM_PE10G2BPTSR_SSID) || \
+	 (pid == SILICOM_PE10G2BPTLR_SSID) || \
+	 (pid == SILICOM_PE10G2BPTT_SSID))
+
+#define BP10G_CX4_SERIES(pid) \
+	(pid == SILICOM_PE10G2BPICX4_SSID)
+
+#define BP10GB_CX4_SERIES(pid) \
+	(pid == SILICOM_PE10G2BPTCX4_SSID)
+
+#define SILICOM_M2EG2BPFI6_SSID       0x0501
+#define SILICOM_M2EG2BPFI6LX_SSID     0x0502
+#define SILICOM_M2EG2BPFI6ZX_SSID     0x0503
+#define SILICOM_M2EG4BPI6_SSID        0x0520
+
+#define SILICOM_M2EG4BPFI6_SSID       0x0521
+#define SILICOM_M2EG4BPFI6LX_SSID     0x0522
+#define SILICOM_M2EG4BPFI6ZX_SSID     0x0523
+
+#define SILICOM_M2EG6BPI6_SSID     0x0540
+
+#define SILICOM_M1E10G2BPI9CX4_SSID  0x481
+#define SILICOM_M1E10G2BPI9SR_SSID   0x482
+#define SILICOM_M1E10G2BPI9LR_SSID   0x483
+#define SILICOM_M1E10G2BPI9T_SSID    0x480
+
+#define SILICOM_M2E10G2BPI9CX4_SSID  0x581
+#define SILICOM_M2E10G2BPI9SR_SSID   0x582
+#define SILICOM_M2E10G2BPI9LR_SSID   0x583
+#define SILICOM_M2E10G2BPI9T_SSID    0x580
+
+#define SILICOM_PE210G2BPI9CX4_SSID  0x121
+#define SILICOM_PE210G2BPI9SR_SSID   0x122
+#define SILICOM_PE210G2BPI9LR_SSID   0x123
+#define SILICOM_PE210G2BPI9T_SSID    0x120
+
+#define DBI_IF_SERIES(pid) \
+	((pid == SILICOM_PE10GDBISR_SSID) || \
+	 (pid == SILICOM_PE10GDBILR_SSID) || \
+	 (pid == SILICOM_XE10G2BPILR_SSID) || \
+	 (pid == SILICOM_PE210G2DBi9LR_SSID))
+
+#define PEGF5_IF_SERIES(pid) \
+	((pid == SILICOM_PEG2BPFI5_SSID) || \
+	 (pid == SILICOM_PEG2BPFI5LX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6LX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6ZX_SSID) || \
+	 (pid == SILICOM_PEG2BPFI6_SSID) || \
+	 (pid == SILICOM_PEG2BPFI6LX_SSID) || \
+	 (pid == SILICOM_PEG2BPFI6ZX_SSID) || \
+	 (pid == SILICOM_PEG2BPFI6FLXM_SSID) || \
+	 (pid == SILICOM_PEG2DBFI6_SSID) || \
+	 (pid == SILICOM_PEG2DBFI6LX_SSID) || \
+	 (pid == SILICOM_PEG2DBFI6ZX_SSID) || \
+	 (pid == SILICOM_PEG4BPI6FC_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6FCLX_SSID) || \
+	 (pid == SILICOM_PEG4BPI6FC_SSID) || \
+	 (pid == SILICOM_M1EG2BPFI6_SSID) || \
+	 (pid == SILICOM_M1EG2BPFI6LX_SSID) || \
+	 (pid == SILICOM_M1EG2BPFI6ZX_SSID) || \
+	 (pid == SILICOM_M1EG4BPFI6_SSID) || \
+	 (pid == SILICOM_M1EG4BPFI6LX_SSID) || \
+	 (pid == SILICOM_M1EG4BPFI6ZX_SSID) || \
+	 (pid == SILICOM_M2EG2BPFI6_SSID) || \
+	 (pid == SILICOM_M2EG2BPFI6LX_SSID) || \
+	 (pid == SILICOM_M2EG2BPFI6ZX_SSID) || \
+	 (pid == SILICOM_M2EG4BPFI6_SSID) || \
+	 (pid == SILICOM_M2EG4BPFI6LX_SSID) || \
+	 (pid == SILICOM_M2EG4BPFI6ZX_SSID) || \
+	 (pid == SILICOM_PEG4BPFI6FCZX_SSID))
+
+#define PEG5_IF_SERIES(pid) \
+	((pid == SILICOM_PEG4BPI6_SSID) || \
+	 (pid == SILICOM_PEG2BPI6_SSID) || \
+	 (pid == SILICOM_PEG4BPI6FC_SSID) || \
+	 (pid == SILICOM_PEG6BPI6_SSID) || \
+	 (pid == SILICOM_PEG2BPI6SC6_SSID) || \
+	 (pid == SILICOM_MEG2BPI6_SSID) || \
+	 (pid == SILICOM_XEG2BPI6_SSID) || \
+	 (pid == SILICOM_MEG4BPI6_SSID) || \
+	 (pid == SILICOM_M1EG2BPI6_SSID) || \
+	 (pid == SILICOM_M1EG4BPI6_SSID) || \
+	 (pid == SILICOM_M1EG6BPI6_SSID) || \
+	 (pid == SILICOM_PEG6BPI_SSID) || \
+	 (pid == SILICOM_PEG4BPIL_SSID) || \
+	 (pid == SILICOM_PEG2BISC6_SSID) || \
+	 (pid == SILICOM_PEG2BPI5_SSID))
+
+#define PEG80_IF_SERIES(pid) \
+	((pid == SILICOM_M1E2G4BPi80_SSID) || \
+	 (pid == SILICOM_M6E2G8BPi80_SSID) || \
+	 (pid == SILICOM_PE2G4BPi80L_SSID) || \
+	 (pid == SILICOM_M6E2G8BPi80A_SSID) || \
+	 (pid == SILICOM_PE2G2BPi35_SSID) || \
+	 (pid == SILICOM_PAC1200BPi35_SSID) || \
+	 (pid == SILICOM_PE2G4BPi35_SSID) || \
+	 (pid == SILICOM_PE2G4BPi35L_SSID) || \
+	 (pid == SILICOM_PE2G6BPi35_SSID) || \
+	 (pid == SILICOM_PE2G2BPi80_SSID) || \
+	 (pid == SILICOM_PE2G4BPi80_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80LX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80LX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35LX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35ZX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35LX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35ZX_SSID))
+
+#define PEGF80_IF_SERIES(pid) \
+	((pid == SILICOM_PE2G4BPFi80_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80LX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \
+	 (pid == SILICOM_M1E2G4BPFi80_SSID) || \
+	 (pid == SILICOM_M1E2G4BPFi80LX_SSID) || \
+	 (pid == SILICOM_M1E2G4BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80LX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi80ZX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35LX_SSID) || \
+	 (pid == SILICOM_PE2G2BPFi35ZX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35LX_SSID) || \
+	 (pid == SILICOM_PE2G4BPFi35ZX_SSID))
+
+#define BP10G9_IF_SERIES(pid) \
+	((pid == INTEL_PE210G2SPI9_SSID) || \
+	 (pid == SILICOM_M1E10G2BPI9CX4_SSID) || \
+	 (pid == SILICOM_M1E10G2BPI9SR_SSID) || \
+	 (pid == SILICOM_M1E10G2BPI9LR_SSID) || \
+	 (pid == SILICOM_M1E10G2BPI9T_SSID) || \
+	 (pid == SILICOM_M2E10G2BPI9CX4_SSID) || \
+	 (pid == SILICOM_M2E10G2BPI9SR_SSID) || \
+	 (pid == SILICOM_M2E10G2BPI9LR_SSID) || \
+	 (pid == SILICOM_M2E10G2BPI9T_SSID) || \
+	 (pid == SILICOM_PE210G2BPI9CX4_SSID) || \
+	 (pid == SILICOM_PE210G2BPI9SR_SSID) || \
+	 (pid == SILICOM_PE210G2BPI9LR_SSID) || \
+	 (pid == SILICOM_PE210G2DBi9SR_SSID) || \
+	 (pid == SILICOM_PE210G2DBi9SRRB_SSID) || \
+	 (pid == SILICOM_PE210G2DBi9LR_SSID) || \
+	 (pid == SILICOM_PE210G2DBi9LRRB_SSID) || \
+	 (pid == SILICOM_PE310G4DBi940SR_SSID) || \
+	 (pid == SILICOM_PEG2BISC6_SSID) || \
+	 (pid == SILICOM_PE310G4BPi9T_SSID) || \
+	 (pid == SILICOM_PE310G4BPi9SR_SSID) || \
+	 (pid == SILICOM_PE310G4BPi9LR_SSID) || \
+	 (pid == SILICOM_PE210G2BPI9T_SSID))
+
+/*******************************************************/
+/* 1G INTERFACE ****************************************/
+/*******************************************************/
+
+/* Intel Registers */
+#define BPCTLI_CTRL          0x00000
+#define BPCTLI_CTRL_SWDPIO0  0x00400000
+#define BPCTLI_CTRL_SWDPIN0  0x00040000
+
+#define BPCTLI_CTRL_EXT 0x00018	/* Extended Device Control - RW */
+#define BPCTLI_STATUS   0x00008	/* Device Status - RO */
+
+/* HW related */
+#define BPCTLI_CTRL_EXT_SDP6_DATA 0x00000040	/* Value of SW Defineable Pin 6 */
+#define BPCTLI_CTRL_EXT_SDP7_DATA 0x00000080	/* Value of SW Defineable Pin 7 */
+#define BPCTLI_CTRL_SDP0_DATA     0x00040000	/* SWDPIN 0 value */
+#define BPCTLI_CTRL_EXT_SDP6_DIR  0x00000400	/* Direction of SDP6 0=in 1=out */
+#define BPCTLI_CTRL_EXT_SDP7_DIR  0x00000800	/* Direction of SDP7 0=in 1=out */
+#define BPCTLI_CTRL_SDP0_DIR      0x00400000	/* SDP0 Input or output */
+#define BPCTLI_CTRL_SWDPIN1       0x00080000
+#define BPCTLI_CTRL_SDP1_DIR      0x00800000
+
+#define BPCTLI_STATUS_LU          0x00000002	/* Link up.0=no,1=link */
+
+#define BPCTLI_CTRL_SDP0_SHIFT     18
+#define BPCTLI_CTRL_EXT_SDP6_SHIFT 6
+
+#define BPCTLI_STATUS_TBIMODE     0x00000020
+#define BPCTLI_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define BPCTLI_CTRL_EXT_LINK_MODE_MASK         0x00C00000
+
+#define BPCTLI_CTRL_EXT_MCLK_DIR  BPCTLI_CTRL_EXT_SDP7_DIR
+#define BPCTLI_CTRL_EXT_MCLK_DATA BPCTLI_CTRL_EXT_SDP7_DATA
+#define BPCTLI_CTRL_EXT_MDIO_DIR  BPCTLI_CTRL_EXT_SDP6_DIR
+#define BPCTLI_CTRL_EXT_MDIO_DATA BPCTLI_CTRL_EXT_SDP6_DATA
+
+#define BPCTLI_CTRL_EXT_MCLK_DIR5  BPCTLI_CTRL_SDP1_DIR
+#define BPCTLI_CTRL_EXT_MCLK_DATA5 BPCTLI_CTRL_SWDPIN1
+#define BPCTLI_CTRL_EXT_MCLK_DIR80  BPCTLI_CTRL_EXT_SDP6_DIR
+#define BPCTLI_CTRL_EXT_MCLK_DATA80 BPCTLI_CTRL_EXT_SDP6_DATA
+#define BPCTLI_CTRL_EXT_MDIO_DIR5  BPCTLI_CTRL_SWDPIO0
+#define BPCTLI_CTRL_EXT_MDIO_DATA5 BPCTLI_CTRL_SWDPIN0
+#define BPCTLI_CTRL_EXT_MDIO_DIR80  BPCTLI_CTRL_SWDPIO0
+#define BPCTLI_CTRL_EXT_MDIO_DATA80 BPCTLI_CTRL_SWDPIN0
+
+#define BPCTL_WRITE_REG(a, reg, value) \
+	(writel((value), (void *)(((a)->mem_map) + BPCTLI_##reg)))
+
+#define BPCTL_READ_REG(a, reg) ( \
+	readl((void *)((a)->mem_map) + BPCTLI_##reg))
+
+#define BPCTL_WRITE_FLUSH(a) BPCTL_READ_REG(a, STATUS)
+
+#define BPCTL_BP_WRITE_REG(a, reg, value) ({ \
+	BPCTL_WRITE_REG(a, reg, value); \
+	BPCTL_WRITE_FLUSH(a); })
+
+/**************************************************************/
+/************** 82575 Interface********************************/
+/**************************************************************/
+
+#define BPCTLI_MII_CR_POWER_DOWN       0x0800
+#define BPCTLI_PHY_CONTROL      0x00	/* Control Register */
+#define BPCTLI_MDIC     0x00020	/* MDI Control - RW */
+#define BPCTLI_IGP01E1000_PHY_PAGE_SELECT        0x1F	/* Page Select */
+#define BPCTLI_MAX_PHY_REG_ADDRESS    0x1F	/* 5 bit address bus (0-0x1F) */
+
+#define BPCTLI_MDIC_DATA_MASK 0x0000FFFF
+#define BPCTLI_MDIC_REG_MASK  0x001F0000
+#define BPCTLI_MDIC_REG_SHIFT 16
+#define BPCTLI_MDIC_PHY_MASK  0x03E00000
+#define BPCTLI_MDIC_PHY_SHIFT 21
+#define BPCTLI_MDIC_OP_WRITE  0x04000000
+#define BPCTLI_MDIC_OP_READ   0x08000000
+#define BPCTLI_MDIC_READY     0x10000000
+#define BPCTLI_MDIC_INT_EN    0x20000000
+#define BPCTLI_MDIC_ERROR     0x40000000
+
+#define BPCTLI_SWFW_PHY0_SM  0x02
+#define BPCTLI_SWFW_PHY1_SM  0x04
+
+#define BPCTLI_SW_FW_SYNC  0x05B5C	/* Software-Firmware Synchronization - RW */
+
+#define BPCTLI_SWSM      0x05B50	/* SW Semaphore */
+#define BPCTLI_FWSM      0x05B54	/* FW Semaphore */
+
+#define BPCTLI_SWSM_SMBI         0x00000001	/* Driver Semaphore bit */
+#define BPCTLI_SWSM_SWESMBI      0x00000002	/* FW Semaphore bit */
+#define BPCTLI_MAX_PHY_MULTI_PAGE_REG 0xF
+#define BPCTLI_GEN_POLL_TIMEOUT          640
+
+/********************************************************/
+
+/********************************************************/
+/* 10G INTERFACE ****************************************/
+/********************************************************/
+
+#define BP10G_I2CCTL              0x28
+
+/* I2CCTL Bit Masks */
+#define BP10G_I2C_CLK_IN    0x00000001
+#define BP10G_I2C_CLK_OUT   0x00000002
+#define BP10G_I2C_DATA_IN   0x00000004
+#define BP10G_I2C_DATA_OUT  0x00000008
+
+#define BP10G_ESDP                0x20
+
+#define BP10G_SDP0_DIR            0x100
+#define BP10G_SDP1_DIR            0x200
+#define BP10G_SDP3_DIR            0x800
+#define BP10G_SDP4_DIR            BIT_12
+#define BP10G_SDP5_DIR            0x2000
+#define BP10G_SDP0_DATA           0x001
+#define BP10G_SDP1_DATA           0x002
+#define BP10G_SDP3_DATA           0x008
+#define BP10G_SDP4_DATA           0x010
+#define BP10G_SDP5_DATA           0x020
+
+#define BP10G_SDP2_DIR            0x400
+#define BP10G_SDP2_DATA            0x4
+
+#define BP10G_EODSDP              0x28
+
+#define BP10G_SDP6_DATA_IN        0x001
+#define BP10G_SDP6_DATA_OUT       0x002
+
+#define BP10G_SDP7_DATA_IN        0x004
+#define BP10G_SDP7_DATA_OUT       0x008
+
+#define BP10G_MCLK_DATA_OUT       BP10G_SDP7_DATA_OUT
+#define BP10G_MDIO_DATA_OUT       BP10G_SDP6_DATA_OUT
+#define BP10G_MDIO_DATA_IN        BP10G_SDP6_DATA_IN
+
+#define BP10G_MDIO_DATA           /*BP10G_SDP5_DATA*/ BP10G_SDP3_DATA
+#define BP10G_MDIO_DIR            /*BP10G_SDP5_DIR*/  BP10G_SDP3_DATA
+
+/*#define BP10G_MCLK_DATA_OUT9       BP10G_I2C_CLK_OUT
+#define BP10G_MDIO_DATA_OUT9       BP10G_I2C_DATA_OUT*/
+
+				       /*#define BP10G_MCLK_DATA_OUT9*//*BP10G_I2C_DATA_OUT */
+#define BP10G_MDIO_DATA_OUT9           BP10G_I2C_DATA_OUT	/*BP10G_I2C_CLK_OUT */
+
+/* VIA EOSDP ! */
+#define BP10G_MCLK_DATA_OUT9           BP10G_SDP4_DATA
+#define BP10G_MCLK_DIR_OUT9            BP10G_SDP4_DIR
+
+/*#define BP10G_MDIO_DATA_IN9        BP10G_I2C_DATA_IN*/
+
+#define BP10G_MDIO_DATA_IN9           BP10G_I2C_DATA_IN	/*BP10G_I2C_CLK_IN */
+
+#define BP540_MDIO_DATA           /*BP10G_SDP5_DATA*/ BP10G_SDP0_DATA
+#define BP540_MDIO_DIR            /*BP10G_SDP5_DIR*/  BP10G_SDP0_DIR
+#define BP540_MCLK_DATA       BP10G_SDP2_DATA
+#define BP540_MCLK_DIR       BP10G_SDP2_DIR
+
+#define BP10G_WRITE_REG(a, reg, value) \
+	(writel((value), (void *)(((a)->mem_map) + BP10G_##reg)))
+
+#define BP10G_READ_REG(a, reg) ( \
+	readl((void *)((a)->mem_map) + BP10G_##reg))
+
+/*****BROADCOM*******************************************/
+
+#define BP10GB_MISC_REG_GPIO						 0xa490
+#define BP10GB_GPIO3_P0                              BIT_3
+#define BP10GB_GPIO3_P1                              BIT_7
+
+#define BP10GB_GPIO3_SET_P0                          BIT_11
+#define BP10GB_GPIO3_CLR_P0                          BIT_19
+#define BP10GB_GPIO3_OE_P0                           BIT_27
+
+#define BP10GB_GPIO3_SET_P1                          BIT_15
+#define BP10GB_GPIO3_CLR_P1                          BIT_23
+#define BP10GB_GPIO3_OE_P1                           BIT_31
+
+#define BP10GB_GPIO0_P1                              0x10
+#define BP10GB_GPIO0_P0                              0x1
+#define BP10GB_GPIO0_CLR_P0                          0x10000
+#define BP10GB_GPIO0_CLR_P1                          0x100000
+#define BP10GB_GPIO0_SET_P0                          0x100
+#define BP10GB_GPIO0_SET_P1                          0x1000
+
+#define BP10GB_GPIO0_OE_P1                           0x10000000
+#define BP10GB_GPIO0_OE_P0                           0x1000000
+
+#define BP10GB_MISC_REG_SPIO						 0xa4fc
+#define BP10GB_GPIO4_OE                              BIT_28
+#define BP10GB_GPIO5_OE                              BIT_29
+#define BP10GB_GPIO4_CLR                             BIT_20
+#define BP10GB_GPIO5_CLR                             BIT_21
+#define BP10GB_GPIO4_SET                             BIT_12
+#define BP10GB_GPIO5_SET                             BIT_13
+#define BP10GB_GPIO4                                 BIT_4
+#define BP10GB_GPIO5                                 BIT_5
+
+#define BP10GB_MCLK_DIR  BP10GB_GPIO5_OE
+#define BP10GB_MDIO_DIR  BP10GB_GPIO4_OE
+
+#define BP10GB_MCLK_DATA BP10GB_GPIO5
+#define BP10GB_MDIO_DATA BP10GB_GPIO4
+
+#define BP10GB_MCLK_SET BP10GB_GPIO5_SET
+#define BP10GB_MDIO_SET BP10GB_GPIO4_SET
+
+#define BP10GB_MCLK_CLR BP10GB_GPIO5_CLR
+#define BP10GB_MDIO_CLR BP10GB_GPIO4_CLR
+
+#define BP10GB_WRITE_REG(a, reg, value) \
+	(writel((value), (void *)(((a)->mem_map) + BP10GB_##reg)))
+
+#define BP10GB_READ_REG(a, reg) ( \
+	readl((void *)((a)->mem_map) + BP10GB_##reg))
+
+#endif
+
+int bp_proc_create(void);
diff --git a/drivers/staging/silicom/bp_proc.c b/drivers/staging/silicom/bp_proc.c
new file mode 100644
index 0000000..6ad4b27
--- /dev/null
+++ b/drivers/staging/silicom/bp_proc.c
@@ -0,0 +1,1350 @@
+/******************************************************************************/
+/*                                                                            */
+/* Copyright (c) 2004-2006 Silicom, Ltd                                       */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/******************************************************************************/
+
+#include <linux/version.h>
+#if defined(CONFIG_SMP) && ! defined(__SMP__)
+#define __SMP__
+#endif
+
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <asm/uaccess.h>
+//#include <linux/smp_lock.h>
+#include "bp_mod.h"
+
+#define BP_PROC_DIR "bypass"
+//#define BYPASS_SUPPORT "bypass"
+
+#ifdef  BYPASS_SUPPORT
+
+#define GPIO6_SET_ENTRY_SD           "gpio6_set"
+#define GPIO6_CLEAR_ENTRY_SD         "gpio6_clear"
+
+#define GPIO7_SET_ENTRY_SD           "gpio7_set"
+#define GPIO7_CLEAR_ENTRY_SD         "gpio7_clear"
+
+#define PULSE_SET_ENTRY_SD            "pulse_set"
+#define ZERO_SET_ENTRY_SD            "zero_set"
+#define PULSE_GET1_ENTRY_SD            "pulse_get1"
+#define PULSE_GET2_ENTRY_SD            "pulse_get2"
+
+#define CMND_ON_ENTRY_SD              "cmnd_on"
+#define CMND_OFF_ENTRY_SD             "cmnd_off"
+#define RESET_CONT_ENTRY_SD           "reset_cont"
+
+ /*COMMANDS*/
+#define BYPASS_INFO_ENTRY_SD     "bypass_info"
+#define BYPASS_SLAVE_ENTRY_SD    "bypass_slave"
+#define BYPASS_CAPS_ENTRY_SD     "bypass_caps"
+#define WD_SET_CAPS_ENTRY_SD     "wd_set_caps"
+#define BYPASS_ENTRY_SD          "bypass"
+#define BYPASS_CHANGE_ENTRY_SD   "bypass_change"
+#define BYPASS_WD_ENTRY_SD       "bypass_wd"
+#define WD_EXPIRE_TIME_ENTRY_SD  "wd_expire_time"
+#define RESET_BYPASS_WD_ENTRY_SD "reset_bypass_wd"
+#define DIS_BYPASS_ENTRY_SD      "dis_bypass"
+#define BYPASS_PWUP_ENTRY_SD     "bypass_pwup"
+#define BYPASS_PWOFF_ENTRY_SD     "bypass_pwoff"
+#define STD_NIC_ENTRY_SD         "std_nic"
+#define STD_NIC_ENTRY_SD         "std_nic"
+#define TAP_ENTRY_SD             "tap"
+#define TAP_CHANGE_ENTRY_SD      "tap_change"
+#define DIS_TAP_ENTRY_SD         "dis_tap"
+#define TAP_PWUP_ENTRY_SD        "tap_pwup"
+#define TWO_PORT_LINK_ENTRY_SD   "two_port_link"
+#define WD_EXP_MODE_ENTRY_SD     "wd_exp_mode"
+#define WD_AUTORESET_ENTRY_SD    "wd_autoreset"
+#define TPL_ENTRY_SD             "tpl"
+#define WAIT_AT_PWUP_ENTRY_SD    "wait_at_pwup"
+#define HW_RESET_ENTRY_SD        "hw_reset"
+#define DISC_ENTRY_SD             "disc"
+#define DISC_CHANGE_ENTRY_SD      "disc_change"
+#define DIS_DISC_ENTRY_SD         "dis_disc"
+#define DISC_PWUP_ENTRY_SD        "disc_pwup"
+#endif				//bypass_support
+static struct proc_dir_entry *bp_procfs_dir;
+
+static struct proc_dir_entry *proc_getdir(char *name,
+					  struct proc_dir_entry *proc_dir)
+{
+	struct proc_dir_entry *pde = proc_dir;
+	for (pde = pde->subdir; pde; pde = pde->next) {
+		if (pde->namelen && (strcmp(name, pde->name) == 0)) {
+			/* directory exists */
+			break;
+		}
+	}
+	if (pde == (struct proc_dir_entry *)0) {
+		/* create the directory */
+		pde = create_proc_entry(name, S_IFDIR, proc_dir);
+		if (pde == (struct proc_dir_entry *)0) {
+			return (pde);
+		}
+	}
+	return (pde);
+}
+
+#ifdef BYPASS_SUPPORT
+
+int
+bypass_proc_create_entry_sd(struct pfs_unit *pfs_unit_curr,
+			    char *proc_name,
+			    write_proc_t * write_proc,
+			    read_proc_t * read_proc,
+			    struct proc_dir_entry *parent_pfs, void *data)
+{
+	strcpy(pfs_unit_curr->proc_name, proc_name);
+	pfs_unit_curr->proc_entry = create_proc_entry(pfs_unit_curr->proc_name,
+						      S_IFREG | S_IRUSR |
+						      S_IWUSR | S_IRGRP |
+						      S_IROTH, parent_pfs);
+	if (pfs_unit_curr->proc_entry == 0) {
+
+		return -1;
+	}
+
+	pfs_unit_curr->proc_entry->read_proc = read_proc;
+	pfs_unit_curr->proc_entry->write_proc = write_proc;
+	pfs_unit_curr->proc_entry->data = data;
+
+	return 0;
+
+}
+
+int
+get_bypass_info_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+	int len = 0;
+
+	len += sprintf(page, "Name\t\t\t%s\n", pbp_device_block->bp_name);
+	len +=
+	    sprintf(page + len, "Firmware version\t0x%x\n",
+		    pbp_device_block->bp_fw_ver);
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_slave_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	struct pci_dev *pci_slave_dev = pbp_device_block->bp_slave;
+	struct net_device *net_slave_dev;
+	int len = 0;
+
+	if (is_bypass_fn(pbp_device_block)) {
+		net_slave_dev = pci_get_drvdata(pci_slave_dev);
+		if (net_slave_dev)
+			len = sprintf(page, "%s\n", net_slave_dev->name);
+		else
+			len = sprintf(page, "fail\n");
+	} else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_caps_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_caps_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "-1\n");
+	else
+		len = sprintf(page, "0x%x\n", ret);
+	*eof = 1;
+	return len;
+
+}
+
+int
+get_wd_set_caps_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_set_caps_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "-1\n");
+	else
+		len = sprintf(page, "0x%x\n", ret);
+	*eof = 1;
+	return len;
+}
+
+int
+set_bypass_pfs(struct file *file, const char *buffer,
+	       unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_tap_pfs(struct file *file, const char *buffer,
+	    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_tap_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_disc_pfs(struct file *file, const char *buffer,
+	     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_disc_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_bypass_pfs(char *page, char **start, off_t off, int count,
+	       int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_pfs(char *page, char **start, off_t off, int count,
+	    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_pfs(char *page, char **start, off_t off, int count,
+	     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_change_pfs(char *page, char **start, off_t off, int count,
+		      int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_change_pfs(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_change_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_change_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_bypass_wd_pfs(struct file *file, const char *buffer,
+		  unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	unsigned int timeout = 0;
+	char *timeout_ptr = kbuf;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	timeout_ptr = kbuf;
+	timeout = atoi(&timeout_ptr);
+
+	set_bypass_wd_fn(pbp_device_block, timeout);
+
+	return count;
+}
+
+int
+get_bypass_wd_pfs(char *page, char **start, off_t off, int count,
+		  int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0, timeout = 0;
+
+	ret = get_bypass_wd_fn(pbp_device_block, &timeout);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (timeout == -1)
+		len = sprintf(page, "unknown\n");
+	else if (timeout == 0)
+		len = sprintf(page, "disable\n");
+	else
+		len = sprintf(page, "%d\n", timeout);
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_wd_expire_time_pfs(char *page, char **start, off_t off, int count,
+		       int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0, timeout = 0;
+
+	ret = get_wd_expire_time_fn(pbp_device_block, &timeout);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (timeout == -1)
+		len = sprintf(page, "expire\n");
+	else if (timeout == 0)
+		len = sprintf(page, "disable\n");
+
+	else
+		len = sprintf(page, "%d\n", timeout);
+	*eof = 1;
+	return len;
+}
+
+int
+get_tpl_pfs(char *page, char **start, off_t off, int count,
+	    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tpl_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+#ifdef PMC_FIX_FLAG
+int
+get_wait_at_pwup_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bp_wait_at_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_hw_reset_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bp_hw_reset_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 1)
+		len = sprintf(page, "on\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+
+	*eof = 1;
+	return len;
+}
+
+#endif				/*PMC_WAIT_FLAG */
+
+int
+reset_bypass_wd_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = reset_bypass_wd_timer_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "disable\n");
+	else if (ret == 1)
+		len = sprintf(page, "success\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_dis_bypass_pfs(struct file *file, const char *buffer,
+		   unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_dis_bypass_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_dis_tap_pfs(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_dis_tap_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_dis_disc_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_dis_disc_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_dis_bypass_pfs(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_bypass_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_dis_tap_pfs(char *page, char **start, off_t off, int count,
+		int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_tap_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_dis_disc_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_dis_disc_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_bypass_pwup_pfs(struct file *file, const char *buffer,
+		    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_pwup_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_bypass_pwoff_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_bypass_pwoff_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+set_tap_pwup_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_tap_pwup_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+set_disc_pwup_pfs(struct file *file, const char *buffer,
+		  unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tap_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tap_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tap_param = 0;
+
+	set_disc_pwup_fn(pbp_device_block, tap_param);
+
+	return count;
+}
+
+int
+get_bypass_pwup_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_bypass_pwoff_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_bypass_pwoff_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_tap_pwup_pfs(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_tap_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_disc_pwup_pfs(char *page, char **start, off_t off, int count,
+		  int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_disc_pwup_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_std_nic_pfs(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		bypass_param = 0;
+
+	set_std_nic_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+get_std_nic_pfs(char *page, char **start, off_t off, int count,
+		int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_std_nic_fn(pbp_device_block);
+	if (ret == BP_NOT_CAP)
+		len = sprintf(page, "fail\n");
+	else if (ret == 0)
+		len = sprintf(page, "off\n");
+	else
+		len = sprintf(page, "on\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+get_wd_exp_mode_pfs(char *page, char **start, off_t off, int count,
+		    int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_exp_mode_fn(pbp_device_block);
+	if (ret == 1)
+		len = sprintf(page, "tap\n");
+	else if (ret == 0)
+		len = sprintf(page, "bypass\n");
+	else if (ret == 2)
+		len = sprintf(page, "disc\n");
+
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_wd_exp_mode_pfs(struct file *file, const char *buffer,
+		    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int bypass_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "tap") == 0)
+		bypass_param = 1;
+	else if (strcmp(kbuf, "bypass") == 0)
+		bypass_param = 0;
+	else if (strcmp(kbuf, "disc") == 0)
+		bypass_param = 2;
+
+	set_wd_exp_mode_fn(pbp_device_block, bypass_param);
+
+	return count;
+}
+
+int
+get_wd_autoreset_pfs(char *page, char **start, off_t off, int count,
+		     int *eof, void *data)
+{
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int len = 0, ret = 0;
+
+	ret = get_wd_autoreset_fn(pbp_device_block);
+	if (ret >= 0)
+		len = sprintf(page, "%d\n", ret);
+	else
+		len = sprintf(page, "fail\n");
+
+	*eof = 1;
+	return len;
+}
+
+int
+set_wd_autoreset_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+	u32 timeout = 0;
+	char *timeout_ptr = kbuf;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	timeout_ptr = kbuf;
+	timeout = atoi(&timeout_ptr);
+
+	set_wd_autoreset_fn(pbp_device_block, timeout);
+
+	return count;
+}
+
+int
+set_tpl_pfs(struct file *file, const char *buffer,
+	    unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_tpl_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+#ifdef PMC_FIX_FLAG
+int
+set_wait_at_pwup_pfs(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_bp_wait_at_pwup_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+int
+set_hw_reset_pfs(struct file *file, const char *buffer,
+		 unsigned long count, void *data)
+{
+
+	char kbuf[256];
+	bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data;
+
+	int tpl_param = 0, length = 0;
+
+	if (count > (sizeof(kbuf) - 1))
+		return -1;
+
+	if (copy_from_user(&kbuf, buffer, count)) {
+		return -1;
+	}
+
+	kbuf[count] = '\0';
+	length = strlen(kbuf);
+	if (kbuf[length - 1] == '\n')
+		kbuf[--length] = '\0';
+
+	if (strcmp(kbuf, "on") == 0)
+		tpl_param = 1;
+	else if (strcmp(kbuf, "off") == 0)
+		tpl_param = 0;
+
+	set_bp_hw_reset_fn(pbp_device_block, tpl_param);
+
+	return count;
+}
+
+#endif				/*PMC_FIX_FLAG */
+
+int bypass_proc_create_dev_sd(bpctl_dev_t * pbp_device_block)
+{
+	struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set);
+	static struct proc_dir_entry *procfs_dir = NULL;
+	int ret = 0;
+
+	sprintf(current_pfs->dir_name, "bypass_%s", dev->name);
+
+	if (!bp_procfs_dir)
+		return -1;
+
+	/* create device proc dir */
+	procfs_dir = proc_getdir(current_pfs->dir_name, bp_procfs_dir);
+	if (procfs_dir == 0) {
+		printk(KERN_DEBUG "Could not create procfs directory %s\n",
+		       current_pfs->dir_name);
+		return -1;
+	}
+	current_pfs->bypass_entry = procfs_dir;
+
+	if (bypass_proc_create_entry(&(current_pfs->bypass_info), BYPASS_INFO_ENTRY_SD, NULL,	/* write */
+				     get_bypass_info_pfs,	/* read  */
+				     procfs_dir, pbp_device_block))
+		ret = -1;
+
+	if (pbp_device_block->bp_caps & SW_CTL_CAP) {
+
+		/* Create set param proc's */
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_slave), BYPASS_SLAVE_ENTRY_SD, NULL,	/* write */
+						get_bypass_slave_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_caps), BYPASS_CAPS_ENTRY_SD, NULL,	/* write */
+						get_bypass_caps_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_set_caps), WD_SET_CAPS_ENTRY_SD, NULL,	/* write */
+						get_wd_set_caps_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->bypass_wd), BYPASS_WD_ENTRY_SD, set_bypass_wd_pfs,	/* write */
+						get_bypass_wd_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_expire_time), WD_EXPIRE_TIME_ENTRY_SD, NULL,	/* write */
+						get_wd_expire_time_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->reset_bypass_wd), RESET_BYPASS_WD_ENTRY_SD, NULL,	/* write */
+						reset_bypass_wd_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->std_nic), STD_NIC_ENTRY_SD, set_std_nic_pfs,	/* write */
+						get_std_nic_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (pbp_device_block->bp_caps & BP_CAP) {
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass), BYPASS_ENTRY_SD, set_bypass_pfs,	/* write */
+							get_bypass_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_bypass), DIS_BYPASS_ENTRY_SD, set_dis_bypass_pfs,	/* write */
+							get_dis_bypass_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwup), BYPASS_PWUP_ENTRY_SD, set_bypass_pwup_pfs,	/* write */
+							get_bypass_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwoff), BYPASS_PWOFF_ENTRY_SD, set_bypass_pwoff_pfs,	/* write */
+							get_bypass_pwoff_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->bypass_change), BYPASS_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_bypass_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+
+		if (pbp_device_block->bp_caps & TAP_CAP) {
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap), TAP_ENTRY_SD, set_tap_pfs,	/* write */
+							get_tap_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_TAP_ENTRY_SD, set_dis_tap_pfs,	/* write */
+							get_dis_tap_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), TAP_PWUP_ENTRY_SD, set_tap_pwup_pfs,	/* write */
+							get_tap_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), TAP_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_tap_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+		if (pbp_device_block->bp_caps & DISC_CAP) {
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap), DISC_ENTRY_SD, set_disc_pfs,	/* write */
+							get_disc_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+#if 1
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_DISC_ENTRY_SD, set_dis_disc_pfs,	/* write */
+							get_dis_disc_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+#endif
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), DISC_PWUP_ENTRY_SD, set_disc_pwup_pfs,	/* write */
+							get_disc_pwup_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+
+			if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), DISC_CHANGE_ENTRY_SD, NULL,	/* write */
+							get_disc_change_pfs,	/* read  */
+							procfs_dir,
+							pbp_device_block))
+				ret = -1;
+		}
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_exp_mode), WD_EXP_MODE_ENTRY_SD, set_wd_exp_mode_pfs,	/* write */
+						get_wd_exp_mode_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+		if (bypass_proc_create_entry_sd(&(current_pfs->wd_autoreset), WD_AUTORESET_ENTRY_SD, set_wd_autoreset_pfs,	/* write */
+						get_wd_autoreset_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), TPL_ENTRY_SD, set_tpl_pfs,	/* write */
+						get_tpl_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+#ifdef PMC_FIX_FLAG
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), WAIT_AT_PWUP_ENTRY_SD, set_wait_at_pwup_pfs,	/* write */
+						get_wait_at_pwup_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+		if (bypass_proc_create_entry_sd(&(current_pfs->tpl), HW_RESET_ENTRY_SD, set_hw_reset_pfs,	/* write */
+						get_hw_reset_pfs,	/* read  */
+						procfs_dir, pbp_device_block))
+			ret = -1;
+
+#endif
+
+	}
+	if (ret < 0)
+		printk(KERN_DEBUG "Create proc entry failed\n");
+
+	return ret;
+}
+
+int bypass_proc_remove_dev_sd(bpctl_dev_t * pbp_device_block)
+{
+
+	struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set;
+	struct proc_dir_entry *pde = current_pfs->bypass_entry, *pde_curr =
+	    NULL;
+	char name[256];
+
+	for (pde = pde->subdir; pde;) {
+		strcpy(name, pde->name);
+		pde_curr = pde;
+		pde = pde->next;
+		remove_proc_entry(name, current_pfs->bypass_entry);
+	}
+	if (!pde)
+		remove_proc_entry(current_pfs->dir_name, bp_procfs_dir);
+
+	return 0;
+}
+
+#endif				/* BYPASS_SUPPORT */
diff --git a/drivers/staging/silicom/bypass.h b/drivers/staging/silicom/bypass.h
new file mode 100644
index 0000000..08fa7a0
--- /dev/null
+++ b/drivers/staging/silicom/bypass.h
@@ -0,0 +1,202 @@
+/******************************************************************************/
+/*                                                                            */
+/* Bypass Control utility, Copyright (c) 2005 Silicom                         */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef BYPASS_H
+#define BYPASS_H
+
+/* Bypass related */
+
+#define SYNC_CMD_VAL               2	/* 10b */
+#define SYNC_CMD_LEN               2
+
+#define WR_CMD_VAL                 2	/* 10b */
+#define WR_CMD_LEN                 2
+
+#define RD_CMD_VAL                 1	/* 10b */
+#define RD_CMD_LEN                 2
+
+#define ADDR_CMD_LEN               4
+
+#define WR_DATA_LEN                8
+#define RD_DATA_LEN                8
+
+#define PIC_SIGN_REG_ADDR          0x7
+#define PIC_SIGN_VALUE         0xcd
+
+#define STATUS_REG_ADDR           0
+#define WDT_EN_MASK            0x01	/* BIT_0 */
+#define CMND_EN_MASK           0x02	/* BIT_1 */
+#define DIS_BYPASS_CAP_MASK    0x04	/* BIT_2    Bypass Cap is disable*/
+#define DFLT_PWRON_MASK        0x08	/* BIT_3 */
+#define BYPASS_OFF_MASK        0x10	/* BIT_4 */
+#define BYPASS_FLAG_MASK       0x20	/* BIT_5 */
+#define STD_NIC_MASK           (DIS_BYPASS_CAP_MASK | BYPASS_OFF_MASK | DFLT_PWRON_MASK)
+#define WD_EXP_FLAG_MASK       0x40	/* BIT_6 */
+#define DFLT_PWROFF_MASK       0x80	/* BIT_7 */
+#define STD_NIC_PWOFF_MASK     (DIS_BYPASS_CAP_MASK | BYPASS_OFF_MASK | DFLT_PWRON_MASK | DFLT_PWROFF_MASK)
+
+#define PRODUCT_CAP_REG_ADDR   0x5
+#define BYPASS_SUPPORT_MASK    0x01	/* BIT_0 */
+#define TAP_SUPPORT_MASK       0x02	/* BIT_1 */
+#define NORMAL_UNSUPPORT_MASK  0x04	/* BIT_2 */
+#define DISC_SUPPORT_MASK      0x08	/* BIT_3 */
+#define TPL2_SUPPORT_MASK      0x10	/* BIT_4 */
+#define DISC_PORT_SUPPORT_MASK 0x20	/* BIT_5 */
+
+#define STATUS_TAP_REG_ADDR    0x6
+#define WDTE_TAP_BPN_MASK      0x01	/* BIT_1    1 when wdt expired -> TAP, 0 - Bypass */
+#define DIS_TAP_CAP_MASK       0x04	/* BIT_2    TAP Cap is disable*/
+#define DFLT_PWRON_TAP_MASK    0x08	/* BIT_3    */
+#define TAP_OFF_MASK           0x10	/* BIT_4    */
+#define TAP_FLAG_MASK          0x20	/* BIT_5    */
+#define TX_DISA_MASK            0x40
+#define TX_DISB_MASK            0x80
+
+#define STD_NIC_TAP_MASK       (DIS_TAP_CAP_MASK | TAP_OFF_MASK | DFLT_PWRON_TAP_MASK)
+
+#define STATUS_DISC_REG_ADDR    13
+#define WDTE_DISC_BPN_MASK      0x01	/* BIT_0    1 when wdt expired -> TAP, 0 - Bypass */
+#define STD_NIC_ON_MASK         0x02	/* BIT_1    */
+#define DIS_DISC_CAP_MASK       0x04	/* BIT_2    TAP Cap is disable*/
+#define DFLT_PWRON_DISC_MASK    0x08	/* BIT_3    */
+#define DISC_OFF_MASK           0x10	/* BIT_4    */
+#define DISC_FLAG_MASK          0x20	/* BIT_5    */
+#define TPL2_FLAG_MASK          0x40	/* BIT_6    */
+#define STD_NIC_DISC_MASK       DIS_DISC_CAP_MASK
+
+#define CONT_CONFIG_REG_ADDR    12
+#define EN_HW_RESET_MASK       0x2	/* BIT_1 */
+#define WAIT_AT_PWUP_MASK      0x1	/* BIT_0 */
+
+#define VER_REG_ADDR               0x1
+#define BP_FW_VER_A0         0xa0
+#define BP_FW_VER_A1         0xa1
+
+#define INT_VER_MASK           0xf0
+#define EXT_VER_MASK           0xf
+/* */
+#define PXG2BPI_VER            0x0
+#define PXG2TBPI_VER           0x1
+#define PXE2TBPI_VER           0x2
+#define PXG4BPFI_VER           0x4
+#define BP_FW_EXT_VER7         0x6
+#define BP_FW_EXT_VER8         0x8
+#define BP_FW_EXT_VER9         0x9
+
+#define OLD_IF_VER              -1
+
+#define CMND_REG_ADDR              10	/* 1010b */
+#define WDT_REG_ADDR               4
+#define TMRL_REG_ADDR              2
+#define TMRH_REG_ADDR              3
+
+/* NEW_FW */
+#define WDT_INTERVAL               1	/* 5     //8   */
+#define WDT_CMND_INTERVAL          200	/* 50          */
+#define CMND_INTERVAL              200	/* 100    usec */
+#define PULSE_TIME                 100
+
+/* OLD_FW */
+#define INIT_CMND_INTERVAL         40
+#define PULSE_INTERVAL             5
+#define WDT_TIME_CNT               3
+
+/* Intel Commands */
+
+#define CMND_OFF_INT               0xf
+#define PWROFF_BYPASS_ON_INT       0x5
+#define BYPASS_ON_INT              0x6
+#define DIS_BYPASS_CAP_INT         0x4
+#define RESET_WDT_INT              0x1
+
+/* Intel timing */
+
+#define BYPASS_DELAY_INT           4	/* msec */
+#define CMND_INTERVAL_INT          2	/* msec */
+
+/* Silicom Commands */
+#define CMND_ON                    0x4
+#define CMND_OFF                   0x2
+#define BYPASS_ON                  0xa
+#define BYPASS_OFF                 0x8
+#define PORT_LINK_EN               0xe
+#define PORT_LINK_DIS              0xc
+#define WDT_ON                     0x10	/* 0x1f (11111) - max */
+#define TIMEOUT_UNIT           100
+#define TIMEOUT_MAX_STEP       15
+#define WDT_TIMEOUT_MIN        100	/*  msec */
+#define WDT_TIMEOUT_MAX        3276800	/*  msec */
+#define WDT_AUTO_MIN_INT           500
+#define WDT_TIMEOUT_DEF        WDT_TIMEOUT_MIN
+#define WDT_OFF                    0x6
+#define WDT_RELOAD                 0x9
+#define RESET_CONT                 0x20
+#define DIS_BYPASS_CAP             0x22
+#define EN_BYPASS_CAP              0x24
+#define BYPASS_STATE_PWRON         0x26
+#define NORMAL_STATE_PWRON         0x28
+#define BYPASS_STATE_PWROFF        0x27
+#define NORMAL_STATE_PWROFF        0x29
+#define TAP_ON                     0xb
+#define TAP_OFF                    0x9
+#define TAP_STATE_PWRON            0x2a
+#define DIS_TAP_CAP                0x2c
+#define EN_TAP_CAP                 0x2e
+#define STD_NIC_OFF       0x86
+#define STD_NIC_ON       0x84
+#define DISC_ON           0x85
+#define DISC_OFF          0x8a
+#define DISC_STATE_PWRON  0x87
+#define DIS_DISC_CAP      0x88
+#define EN_DISC_CAP       0x89
+#define TPL2_ON                    0x8c
+#define TPL2_OFF                   0x8b
+#define BP_WAIT_AT_PWUP_EN        0x80
+#define BP_WAIT_AT_PWUP_DIS       0x81
+#define BP_HW_RESET_EN             0x82
+#define BP_HW_RESET_DIS            0x83
+
+#define TX_DISA                0x8d
+#define TX_DISB                0x8e
+#define TX_ENA                 0xA0
+#define TX_ENB                 0xA1
+
+#define TX_DISA_PWRUP          0xA2
+#define TX_DISB_PWRUP          0xA3
+#define TX_ENA_PWRUP           0xA4
+#define TX_ENB_PWRUP           0xA5
+
+#define BYPASS_CAP_DELAY           21	/* msec */
+#define DFLT_PWRON_DELAY           10	/* msec */
+#define LATCH_DELAY                13	/* msec */
+#define EEPROM_WR_DELAY             8	/* msec */
+
+#define BP_LINK_MON_DELAY          4	/* sec */
+
+#define BP_FW_EXT_VER0                 0xa0
+#define BP_FW_EXT_VER1                 0xa1
+#define BP_FW_EXT_VER2                0xb1
+
+#define BP_OK        0
+#define BP_NOT_CAP  -1
+#define WDT_STATUS_EXP -2
+#define WDT_STATUS_UNKNOWN -1
+#define WDT_STATUS_EN 1
+#define WDT_STATUS_DIS 0
+
+#ifdef BP_SELF_TEST
+#define ETH_P_BPTEST 0xabba
+
+#define BPTEST_DATA_LEN 60
+#endif
+
+#endif				/* BYPASS_H */
diff --git a/drivers/staging/silicom/bypasslib/Makefile b/drivers/staging/silicom/bypasslib/Makefile
new file mode 100644
index 0000000..80e8b9bc
--- /dev/null
+++ b/drivers/staging/silicom/bypasslib/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Bypass network device drivers.
+#
+
+obj-$(CONFIG_SBYPASS) += bypass.o
+
diff --git a/drivers/staging/silicom/bypasslib/bp_ioctl.h b/drivers/staging/silicom/bypasslib/bp_ioctl.h
new file mode 100644
index 0000000..040c6fa
--- /dev/null
+++ b/drivers/staging/silicom/bypasslib/bp_ioctl.h
@@ -0,0 +1,198 @@
+/******************************************************************************/
+/*                                                                            */
+/* bypass library, Copyright (c) 2004-2006 Silicom, Ltd                       */
+/* Corporation.                                                               */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef BP_IOCTL_H
+#define BP_IOCTL_H
+
+#define BP_CAP                   0x01	//BIT_0
+#define BP_STATUS_CAP            0x02	//BIT_1
+#define BP_STATUS_CHANGE_CAP     0x04	//BIT_2
+#define SW_CTL_CAP               0x08	//BIT_3
+#define BP_DIS_CAP               0x10	//BIT_4
+#define BP_DIS_STATUS_CAP        0x20	//BIT_5
+#define STD_NIC_CAP              0x40	//BIT_6
+#define BP_PWOFF_ON_CAP          0x80	//BIT_7
+#define BP_PWOFF_OFF_CAP         0x0100	//BIT_8
+#define BP_PWOFF_CTL_CAP         0x0200	//BIT_9
+#define BP_PWUP_ON_CAP           0x0400	//BIT_10
+#define BP_PWUP_OFF_CAP          0x0800	//BIT_11
+#define BP_PWUP_CTL_CAP          0x1000	//BIT_12
+#define WD_CTL_CAP               0x2000	//BIT_13
+#define WD_STATUS_CAP            0x4000	//BIT_14
+#define WD_TIMEOUT_CAP           0x8000	//BIT_15
+#define TX_CTL_CAP               0x10000	//BIT_16
+#define TX_STATUS_CAP            0x20000	//BIT_17
+#define TAP_CAP                  0x40000	//BIT_18
+#define TAP_STATUS_CAP           0x80000	//BIT_19
+#define TAP_STATUS_CHANGE_CAP    0x100000	//BIT_20
+#define TAP_DIS_CAP              0x200000	//BIT_21
+#define TAP_DIS_STATUS_CAP       0x400000	//BIT_22
+#define TAP_PWUP_ON_CAP          0x800000	//BIT_23
+#define TAP_PWUP_OFF_CAP         0x1000000	//BIT 24
+#define TAP_PWUP_CTL_CAP         0x2000000	//BIT 25
+#define NIC_CAP_NEG              0x4000000	//BIT 26
+#define TPL_CAP                  0x8000000	//BIT 27
+#define DISC_CAP                 0x10000000	//BIT 28
+#define DISC_DIS_CAP             0x20000000	//BIT 29
+#define DISC_PWUP_CTL_CAP        0x40000000	//BIT 30
+
+#define WD_MIN_TIME_MASK(val)      (val & 0xf)
+#define WD_STEP_COUNT_MASK(val)    ((val & 0xf) << 5)
+#define WDT_STEP_TIME              0x10	//BIT_4
+
+#define WD_MIN_TIME_GET(desc)   (desc & 0xf)
+#define WD_STEP_COUNT_GET(desc) (desc>>5) & 0xf
+
+typedef enum {
+	IS_BYPASS = 1,
+	GET_BYPASS_SLAVE,
+	GET_BYPASS_CAPS,
+	GET_WD_SET_CAPS,
+	SET_BYPASS,
+	GET_BYPASS,
+	GET_BYPASS_CHANGE,
+	SET_BYPASS_WD,
+	GET_BYPASS_WD,
+	GET_WD_EXPIRE_TIME,
+	RESET_BYPASS_WD_TIMER,
+	SET_DIS_BYPASS,
+	GET_DIS_BYPASS,
+	SET_BYPASS_PWOFF,
+	GET_BYPASS_PWOFF,
+	SET_BYPASS_PWUP,
+	GET_BYPASS_PWUP,
+	SET_STD_NIC,
+	GET_STD_NIC,
+	SET_TX,
+	GET_TX,
+	SET_TAP,
+	GET_TAP,
+	GET_TAP_CHANGE,
+	SET_DIS_TAP,
+	GET_DIS_TAP,
+	SET_TAP_PWUP,
+	GET_TAP_PWUP,
+	SET_WD_EXP_MODE,
+	GET_WD_EXP_MODE,
+	SET_WD_AUTORESET,
+	GET_WD_AUTORESET,
+	SET_TPL,
+	GET_TPL,
+	SET_DISC,
+	GET_DISC,
+	GET_DISC_CHANGE,
+	SET_DIS_DISC,
+	GET_DIS_DISC,
+	SET_DISC_PWUP,
+	GET_DISC_PWUP,
+
+	GET_BYPASS_INFO = 100,
+	GET_BP_WAIT_AT_PWUP,
+	SET_BP_WAIT_AT_PWUP,
+	GET_BP_HW_RESET,
+	SET_BP_HW_RESET,
+} CMND_TYPE;
+
+typedef enum {
+	IF_SCAN_SD,
+	GET_DEV_NUM_SD,
+	IS_BYPASS_SD,
+	GET_BYPASS_SLAVE_SD,
+	GET_BYPASS_CAPS_SD,
+	GET_WD_SET_CAPS_SD,
+	SET_BYPASS_SD,
+	GET_BYPASS_SD,
+	GET_BYPASS_CHANGE_SD,
+	SET_BYPASS_WD_SD,
+	GET_BYPASS_WD_SD,
+	GET_WD_EXPIRE_TIME_SD,
+	RESET_BYPASS_WD_TIMER_SD,
+	SET_DIS_BYPASS_SD,
+	GET_DIS_BYPASS_SD,
+	SET_BYPASS_PWOFF_SD,
+	GET_BYPASS_PWOFF_SD,
+	SET_BYPASS_PWUP_SD,
+	GET_BYPASS_PWUP_SD,
+	SET_STD_NIC_SD,
+	GET_STD_NIC_SD,
+	SET_TX_SD,
+	GET_TX_SD,
+	SET_TAP_SD,
+	GET_TAP_SD,
+	GET_TAP_CHANGE_SD,
+	SET_DIS_TAP_SD,
+	GET_DIS_TAP_SD,
+	SET_TAP_PWUP_SD,
+	GET_TAP_PWUP_SD,
+	SET_WD_EXP_MODE_SD,
+	GET_WD_EXP_MODE_SD,
+	SET_WD_AUTORESET_SD,
+	GET_WD_AUTORESET_SD,
+	SET_TPL_SD,
+	GET_TPL_SD,
+	SET_DISC_SD,
+	GET_DISC_SD,
+	GET_DISC_CHANGE_SD,
+	SET_DIS_DISC_SD,
+	GET_DIS_DISC_SD,
+	SET_DISC_PWUP_SD,
+	GET_DISC_PWUP_SD,
+
+	GET_BYPASS_INFO_SD = 100,
+	GET_BP_WAIT_AT_PWUP_SD,
+	SET_BP_WAIT_AT_PWUP_SD,
+	GET_BP_HW_RESET_SD,
+	SET_BP_HW_RESET_SD,
+
+} CMND_TYPE_SD;
+
+#define SIOCGIFBYPASS SIOCDEVPRIVATE+10
+
+struct bp_info {
+	char prod_name[14];
+	unsigned char fw_ver;
+};
+
+/* for passing single values */
+struct if_bypass {
+	char if_name[IFNAMSIZ];
+	int cmd;
+	int data;
+};
+struct if_bypass_info {
+	char if_name[IFNAMSIZ];
+	char cmd;
+	struct bp_info bp_info;
+};
+
+/*
+* The major device number. We can't rely on dynamic
+* registration any more, because ioctls need to know
+* it.
+*/
+
+#define MAGIC_NUM 'J'
+
+/* for passing single values */
+struct bpctl_cmd {
+	int status;
+	int data[8];
+	int in_param[8];
+	int out_param[8];
+};
+
+#define IOCTL_TX_MSG(cmd) _IOWR(MAGIC_NUM, cmd, struct bpctl_cmd)
+
+#define DEVICE_NAME "bpctl"
+
+#endif
diff --git a/drivers/staging/silicom/bypasslib/bplibk.h b/drivers/staging/silicom/bypasslib/bplibk.h
new file mode 100644
index 0000000..a1c85ee
--- /dev/null
+++ b/drivers/staging/silicom/bypasslib/bplibk.h
@@ -0,0 +1,47 @@
+/******************************************************************************/
+/*                                                                            */
+/* bypass library, Copyright (c) 2004 Silicom, Ltd                            */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/* bplib.h                                                                    */
+/*                                                                            */
+/******************************************************************************/
+#ifndef BYPASS_H
+#define BYPASS_H
+
+#include "bp_ioctl.h"
+#include "libbp_sd.h"
+
+#define IF_NAME            "eth"
+#define SILICOM_VID        0x1374
+#define SILICOM_BP_PID_MIN 0x24
+#define SILICOM_BP_PID_MAX 0x5f
+#define INTEL_PEG4BPII_PID  0x10a0
+#define INTEL_PEG4BPFII_PID 0x10a1
+
+#define PEGII_IF_SERIES(vid, pid) \
+        ((vid==0x8086)&& \
+        ((pid==INTEL_PEG4BPII_PID)||   \
+          (pid==INTEL_PEG4BPFII_PID)))
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+#define pci_get_class pci_find_class
+
+#define pci_get_device pci_find_device
+
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
+#define EXPORT_SYMBOL_NOVERS EXPORT_SYMBOL
+#endif
+
+#ifdef BP_VENDOR_SUPPORT
+char *bp_desc_array[] =
+    { "e1000bp", "e1000bpe", "slcm5700", "bnx2xbp", "ixgbp", "ixgbpe", NULL };
+#endif
+
+#endif
diff --git a/drivers/staging/silicom/bypasslib/bypass.c b/drivers/staging/silicom/bypasslib/bypass.c
new file mode 100644
index 0000000..527829d
--- /dev/null
+++ b/drivers/staging/silicom/bypasslib/bypass.c
@@ -0,0 +1,529 @@
+/******************************************************************************/
+/*                                                                            */
+/* bypass library, Copyright (c) 2004-2007 Silicom, Ltd                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/*                                                                            */
+/* bypass.c                                                                    */
+/*                                                                            */
+/******************************************************************************/
+
+#include <linux/version.h>
+#if defined(CONFIG_SMP) && ! defined(__SMP__)
+#define __SMP__
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <asm/unistd.h>
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include <linux/netdevice.h>	// struct device, and other headers
+#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+#include <linux/ethtool.h>
+
+#include <net/net_namespace.h>
+
+#include "bplibk.h"
+
+#define MOD_NAME "bypass"
+
+#define VERSION "\n"MOD_NAME" version 9.0.4\n"
+
+MODULE_AUTHOR("www.silicom.co.il");
+
+MODULE_LICENSE("GPL");
+
+int init_lib_module(void);
+void cleanup_lib_module(void);
+
+static int do_cmd(struct net_device *dev, struct ifreq *ifr, int cmd, int *data)
+{
+	int ret = -1;
+	struct if_bypass *bypass_cb;
+	static int (*ioctl) (struct net_device *, struct ifreq *, int);
+
+	bypass_cb = (struct if_bypass *)ifr;
+	bypass_cb->cmd = cmd;
+	bypass_cb->data = *data;
+	if ((dev->netdev_ops) && (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
+		ret = ioctl(dev, ifr, SIOCGIFBYPASS);
+		*data = bypass_cb->data;
+	}
+
+	return ret;
+}
+
+static int doit(int cmd, int if_index, int *data)
+{
+	struct ifreq ifr;
+	int ret = -1;
+	struct net_device *dev;
+	struct net_device *n;
+	for_each_netdev_safe(&init_net, dev, n) {
+
+		if (dev->ifindex == if_index) {
+			ret = do_cmd(dev, &ifr, cmd, data);
+			if (ret < 0)
+				ret = -1;
+
+		}
+	}
+
+	return ret;
+}
+
+#define bp_symbol_get(fn_name) symbol_get(fn_name)
+#define bp_symbol_put(fn_name) symbol_put(fn_name)
+
+#define SET_BPLIB_INT_FN(fn_name, arg_type, arg, ret) \
+    ({ int (* fn_ex)(arg_type)=NULL; \
+    fn_ex=bp_symbol_get(fn_name##_sd); \
+       if(fn_ex) {  \
+        ret= fn_ex(arg); \
+       bp_symbol_put(fn_name##_sd); \
+       } else ret=-1; \
+    })
+
+#define  SET_BPLIB_INT_FN2(fn_name, arg_type, arg, arg_type1, arg1, ret) \
+    ({ int (* fn_ex)(arg_type,arg_type1)=NULL; \
+        fn_ex=bp_symbol_get(fn_name##_sd); \
+       if(fn_ex) {  \
+        ret= fn_ex(arg,arg1); \
+        bp_symbol_put(fn_name##_sd); \
+       } else ret=-1; \
+    })
+#define SET_BPLIB_INT_FN3(fn_name, arg_type, arg, arg_type1, arg1,arg_type2, arg2, ret) \
+    ({ int (* fn_ex)(arg_type,arg_type1, arg_type2)=NULL; \
+        fn_ex=bp_symbol_get(fn_name##_sd); \
+       if(fn_ex) {  \
+        ret= fn_ex(arg,arg1,arg2); \
+        bp_symbol_put(fn_name##_sd); \
+       } else ret=-1; \
+    })
+
+#define DO_BPLIB_GET_ARG_FN(fn_name,ioctl_val, if_index) \
+    ({    int data, ret=0; \
+            if(is_dev_sd(if_index)){ \
+            SET_BPLIB_INT_FN(fn_name, int, if_index, ret); \
+            return ret; \
+            }  \
+            return doit(ioctl_val,if_index, &data); \
+    })
+
+#define DO_BPLIB_SET_ARG_FN(fn_name,ioctl_val,if_index,arg) \
+    ({    int data, ret=0; \
+            if(is_dev_sd(if_index)){ \
+            SET_BPLIB_INT_FN2(fn_name, int, if_index, int, arg, ret); \
+            return ret; \
+            }  \
+	    data=arg; \
+            return doit(ioctl_val,if_index, &data); \
+    })
+
+static int is_dev_sd(int if_index)
+{
+	int ret = 0;
+	SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
+	return (ret >= 0 ? 1 : 0);
+}
+
+int is_bypass_dev(int if_index)
+{
+	struct pci_dev *pdev = NULL;
+	struct net_device *dev = NULL;
+	struct ifreq ifr;
+	int ret = 0, data = 0;
+
+	while ((pdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) {
+		if ((dev = pci_get_drvdata(pdev)) != NULL)
+			if (((dev = pci_get_drvdata(pdev)) != NULL) &&
+			    (dev->ifindex == if_index)) {
+				if ((pdev->vendor == SILICOM_VID) &&
+				    (pdev->device >= SILICOM_BP_PID_MIN) &&
+				    (pdev->device <= SILICOM_BP_PID_MAX))
+					goto send_cmd;
+#if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO)
+				else {
+					struct ethtool_drvinfo info;
+					const struct ethtool_ops *ops =
+					    dev->ethtool_ops;
+					int k = 0;
+
+					if (ops->get_drvinfo) {
+						memset(&info, 0, sizeof(info));
+						info.cmd = ETHTOOL_GDRVINFO;
+						ops->get_drvinfo(dev, &info);
+						for (; bp_desc_array[k]; k++)
+							if (!
+							    (strcmp
+							     (bp_desc_array[k],
+							      info.driver)))
+								goto send_cmd;
+
+					}
+
+				}
+#endif
+				return -1;
+			}
+	}
+ send_cmd:
+	ret = do_cmd(dev, &ifr, IS_BYPASS, &data);
+	return (ret < 0 ? -1 : ret);
+}
+
+int is_bypass(int if_index)
+{
+	int ret = 0;
+	SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
+
+	if (ret < 0)
+		return is_bypass_dev(if_index);
+	return ret;
+}
+
+int get_bypass_slave(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
+}
+
+int get_bypass_caps(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
+}
+
+int get_wd_set_caps(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index);
+}
+
+int set_bypass(int if_index, int bypass_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode);
+}
+
+int get_bypass(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
+}
+
+int get_bypass_change(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
+}
+
+int set_dis_bypass(int if_index, int dis_bypass)
+{
+	DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index,
+			    dis_bypass);
+}
+
+int get_dis_bypass(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
+}
+
+int set_bypass_pwoff(int if_index, int bypass_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index,
+			    bypass_mode);
+}
+
+int get_bypass_pwoff(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
+}
+
+int set_bypass_pwup(int if_index, int bypass_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index,
+			    bypass_mode);
+}
+
+int get_bypass_pwup(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
+}
+
+int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
+{
+	int data = ms_timeout, ret = 0;
+	if (is_dev_sd(if_index))
+		SET_BPLIB_INT_FN3(set_bypass_wd, int, if_index, int, ms_timeout,
+				  int *, ms_timeout_set, ret);
+	else {
+		ret = doit(SET_BYPASS_WD, if_index, &data);
+		if (ret > 0) {
+			*ms_timeout_set = ret;
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+int get_bypass_wd(int if_index, int *ms_timeout_set)
+{
+	int *data = ms_timeout_set, ret = 0;
+	if (is_dev_sd(if_index))
+		SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *,
+				  ms_timeout_set, ret);
+	else
+		ret = doit(GET_BYPASS_WD, if_index, data);
+	return ret;
+}
+
+int get_wd_expire_time(int if_index, int *ms_time_left)
+{
+	int *data = ms_time_left, ret = 0;
+	if (is_dev_sd(if_index))
+		SET_BPLIB_INT_FN2(get_wd_expire_time, int, if_index, int *,
+				  ms_time_left, ret);
+	else {
+		ret = doit(GET_WD_EXPIRE_TIME, if_index, data);
+		if ((ret == 0) && (*data != 0))
+			ret = 1;
+	}
+	return ret;
+}
+
+int reset_bypass_wd_timer(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER,
+			    if_index);
+}
+
+int set_std_nic(int if_index, int bypass_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode);
+}
+
+int get_std_nic(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
+}
+
+int set_tx(int if_index, int tx_state)
+{
+	DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state);
+}
+
+int get_tx(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
+}
+
+int set_tap(int if_index, int tap_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode);
+}
+
+int get_tap(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
+}
+
+int get_tap_change(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
+}
+
+int set_dis_tap(int if_index, int dis_tap)
+{
+	DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap);
+}
+
+int get_dis_tap(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
+}
+
+int set_tap_pwup(int if_index, int tap_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode);
+}
+
+int get_tap_pwup(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
+}
+
+int set_bp_disc(int if_index, int disc_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode);
+}
+
+int get_bp_disc(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
+}
+
+int get_bp_disc_change(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index);
+}
+
+int set_bp_dis_disc(int if_index, int dis_disc)
+{
+	DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc);
+}
+
+int get_bp_dis_disc(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index);
+}
+
+int set_bp_disc_pwup(int if_index, int disc_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index,
+			    disc_mode);
+}
+
+int get_bp_disc_pwup(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index);
+}
+
+int set_wd_exp_mode(int if_index, int mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode);
+}
+
+int get_wd_exp_mode(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index);
+}
+
+int set_wd_autoreset(int if_index, int time)
+{
+	DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time);
+}
+
+int get_wd_autoreset(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
+}
+
+int set_tpl(int if_index, int tpl_mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode);
+}
+
+int get_tpl(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
+}
+
+int set_bp_hw_reset(int if_index, int mode)
+{
+	DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode);
+}
+
+int get_bp_hw_reset(int if_index)
+{
+	DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index);
+}
+
+int get_bypass_info(int if_index, struct bp_info *bp_info)
+{
+	int ret = 0;
+	if (is_dev_sd(if_index)) {
+		SET_BPLIB_INT_FN2(get_bypass_info, int, if_index,
+				  struct bp_info *, bp_info, ret);
+	} else {
+		static int (*ioctl) (struct net_device *, struct ifreq *, int);
+		struct net_device *dev;
+
+		struct net_device *n;
+		for_each_netdev_safe(&init_net, dev, n) {
+			if (dev->ifindex == if_index) {
+				struct if_bypass_info *bypass_cb;
+				struct ifreq ifr;
+
+				memset(&ifr, 0, sizeof(ifr));
+				bypass_cb = (struct if_bypass_info *)&ifr;
+				bypass_cb->cmd = GET_BYPASS_INFO;
+
+				if ((dev->netdev_ops) &&
+				    (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
+					ret = ioctl(dev, &ifr, SIOCGIFBYPASS);
+				}
+
+				else
+					ret = -1;
+				if (ret == 0)
+					memcpy(bp_info, &bypass_cb->bp_info,
+					       sizeof(struct bp_info));
+				ret = (ret < 0 ? -1 : 0);
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+int init_lib_module()
+{
+
+	printk(VERSION);
+	return 0;
+}
+
+void cleanup_lib_module()
+{
+}
+
+EXPORT_SYMBOL_NOVERS(is_bypass);
+EXPORT_SYMBOL_NOVERS(get_bypass_slave);
+EXPORT_SYMBOL_NOVERS(get_bypass_caps);
+EXPORT_SYMBOL_NOVERS(get_wd_set_caps);
+EXPORT_SYMBOL_NOVERS(set_bypass);
+EXPORT_SYMBOL_NOVERS(get_bypass);
+EXPORT_SYMBOL_NOVERS(get_bypass_change);
+EXPORT_SYMBOL_NOVERS(set_dis_bypass);
+EXPORT_SYMBOL_NOVERS(get_dis_bypass);
+EXPORT_SYMBOL_NOVERS(set_bypass_pwoff);
+EXPORT_SYMBOL_NOVERS(get_bypass_pwoff);
+EXPORT_SYMBOL_NOVERS(set_bypass_pwup);
+EXPORT_SYMBOL_NOVERS(get_bypass_pwup);
+EXPORT_SYMBOL_NOVERS(set_bypass_wd);
+EXPORT_SYMBOL_NOVERS(get_bypass_wd);
+EXPORT_SYMBOL_NOVERS(get_wd_expire_time);
+EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer);
+EXPORT_SYMBOL_NOVERS(set_std_nic);
+EXPORT_SYMBOL_NOVERS(get_std_nic);
+EXPORT_SYMBOL_NOVERS(set_tx);
+EXPORT_SYMBOL_NOVERS(get_tx);
+EXPORT_SYMBOL_NOVERS(set_tap);
+EXPORT_SYMBOL_NOVERS(get_tap);
+EXPORT_SYMBOL_NOVERS(get_tap_change);
+EXPORT_SYMBOL_NOVERS(set_dis_tap);
+EXPORT_SYMBOL_NOVERS(get_dis_tap);
+EXPORT_SYMBOL_NOVERS(set_tap_pwup);
+EXPORT_SYMBOL_NOVERS(get_tap_pwup);
+EXPORT_SYMBOL_NOVERS(set_bp_disc);
+EXPORT_SYMBOL_NOVERS(get_bp_disc);
+EXPORT_SYMBOL_NOVERS(get_bp_disc_change);
+EXPORT_SYMBOL_NOVERS(set_bp_dis_disc);
+EXPORT_SYMBOL_NOVERS(get_bp_dis_disc);
+EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup);
+EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup);
+EXPORT_SYMBOL_NOVERS(set_wd_exp_mode);
+EXPORT_SYMBOL_NOVERS(get_wd_exp_mode);
+EXPORT_SYMBOL_NOVERS(set_wd_autoreset);
+EXPORT_SYMBOL_NOVERS(get_wd_autoreset);
+EXPORT_SYMBOL_NOVERS(set_tpl);
+EXPORT_SYMBOL_NOVERS(get_tpl);
+EXPORT_SYMBOL_NOVERS(set_bp_hw_reset);
+EXPORT_SYMBOL_NOVERS(get_bp_hw_reset);
+EXPORT_SYMBOL_NOVERS(get_bypass_info);
+
+module_init(init_lib_module);
+module_exit(cleanup_lib_module);
diff --git a/drivers/staging/silicom/bypasslib/libbp_sd.h b/drivers/staging/silicom/bypasslib/libbp_sd.h
new file mode 100644
index 0000000..3b4f836
--- /dev/null
+++ b/drivers/staging/silicom/bypasslib/libbp_sd.h
@@ -0,0 +1,509 @@
+/******************************************************************************/
+/*                                                                            */
+/* bypass library, Copyright (c) 2004 Silicom, Ltd                            */
+/* Corporation.                                                               */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/* Ver 1.0.0                                                                  */
+/*                                                                            */
+/* libbypass.h                                                                */
+/*                                                                            */
+/******************************************************************************/
+
+/**
+ * is_bypass - check if device is a Bypass controlling device
+ * @if_index: network device index
+ *
+ * Output:
+ *  1 -  if device is bypass controlling device, 
+ *  0 -  if device is bypass slave device
+ * -1 -  device not support Bypass
+ **/
+int is_bypass_sd(int if_index);
+
+/**
+ * get_bypass_slave - get second port participate in the Bypass pair
+ * @if_index: network device index
+ *
+ * Output:
+ *  network device index of the slave device
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int get_bypass_slave_sd(int if_index);
+
+/**
+ * get_bypass_caps - get second port participate in the Bypass pair
+ * @if_index: network device index
+ *
+ * Output:
+ * flags word on success;flag word is a 32-bit mask word with each bit defines different 
+ * capability as described bellow.
+ * Value of 1 for supporting this feature. 0 for not supporting this feature.
+ * -1 - on failure (if the device is not capable of the operation or not a Bypass device)
+ * Bit	feature	                description
+ * 
+ * 0	BP_CAP	                The interface is Bypass capable in general
+ * 
+ * 1	BP_STATUS_CAP	        The interface can report of the current Bypass mode
+ * 
+ * 2	BP_STATUS_CHANGE_CAP	The interface can report on a change to bypass mode from 
+ *                              the last time the mode was defined
+ * 
+ * 3	SW_CTL_CAP	            The interface is Software controlled capable for bypass/non bypass modes.
+ * 
+ * 4	BP_DIS_CAP	            The interface is capable of disabling the Bypass mode at all times. 
+ *                              This mode will retain its mode even during power loss and also after 
+ *                              power recovery. This will overcome on any bypass operation due to 
+ *                              watchdog timeout or set bypass command.
+ * 
+ * 5	BP_DIS_STATUS_CAP	    The interface can report of the current DIS_BP_CAP
+ * 
+ * 6	STD_NIC_CAP	            The interface is capable to be configured to operate as standard, non Bypass, 
+ *                              NIC interface (have direct connection to interfaces at all power modes)
+ * 
+ * 7	BP_PWOFF_NO_CAP	        The interface can be in Bypass mode at power off state
+ * 
+ * 8	BP_PWOFF_OFF_CAP	    The interface can disconnect the Bypass mode at power off state without 
+ *                              effecting all the other states of operation
+ * 
+ * 9	BP_PWOFF_CTL_CAP	    The behavior of the Bypass mode at Power-off state can be controlled by 
+ *                              software without effecting any other state
+ * 
+ *10    BP_PWUP_ON_CAP	        The interface can be in Bypass mode when power is turned on 
+ *                              (until the system take control of the bypass functionality)
+ * 
+ *11	BP_PWUP_OFF_CAP	        The interface can disconnect from Bypass mode when power is turned on 
+ *                              (until the system take control of the bypass functionality)
+ * 
+ *12	BP_PWUP_CTL_CAP	        The behavior of the Bypass mode at Power-up can be controlled by software
+ * 
+ *13	WD_CTL_CAP	            The interface has watchdog capabilities to turn to Bypass mode when not reset 
+ *                              for defined period of time.
+ * 
+ *14	WD_STATUS_CAP	        The interface can report on the watchdog status (Active/inactive)
+ * 
+ *15	WD_TIMEOUT_CAP	        The interface can report the time left till watchdog triggers to Bypass mode.
+ * 
+ *16-31 RESERVED	
+ *
+ * **/
+int get_bypass_caps_sd(int if_index);
+
+/**
+ * get_wd_set_caps - Obtain watchdog timer setting capabilities
+ * @if_index: network device index
+ *
+ * Output:
+ * 
+ * Set of numbers defining the various parameters of the watchdog capable 
+ * to be set to as described bellow.
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ * 
+ * Bit	feature	        description
+ * 
+ * 0-3	WD_MIN_TIME	    The interface WD minimal time period  in 100mS units
+ * 
+ * 4	WD_STEP_TIME	The steps of the WD timer in 
+ *                      0 - for linear steps (WD_MIN_TIME * X)
+ *                      1 - for multiply by 2 from previous step (WD_MIN_TIME * 2^X)
+ * 
+ * 5-8	WD_STEP_COUNT	Number of steps the WD timer supports in 2^X 
+ *                      (X bit available for defining the value)
+ * 
+ * 
+ * 
+ **/
+int get_wd_set_caps_sd(int if_index);
+
+/**
+ * set_bypass - set Bypass state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  bypass mode (1=on, 0=off) 
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int set_bypass_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass - Get Bypass mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int get_bypass_sd(int if_index);
+
+/**
+ * get_bypass_change - Get change of Bypass mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int get_bypass_change_sd(int if_index);
+
+/**
+ * set_dis_bypass - Set Disable Bypass mode
+ * @if_index: network device index of the controlling device
+ * @dis_bypass: disable bypass(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int set_dis_bypass_sd(int if_index, int dis_bypass);
+
+/**
+ * get_dis_bypass - Get Disable Bypass mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal Bypass mode/ Disable bypass)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int get_dis_bypass_sd(int if_index);
+
+/**
+ * set_bypass_pwoff - Set Bypass mode at power-off state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: bypass mode setting at power off state (1=BP en, 0=BP Dis)
+ * Output:
+ *  0 - on success 
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int set_bypass_pwoff_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass_pwoff - Get Bypass mode state at power-off state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable bypass at power off state / normal Bypass mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int get_bypass_pwoff_sd(int if_index);
+
+/**
+ * set_bypass_pwup - Set Bypass mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: bypass mode setting at power up state (1=BP en, 0=BP Dis)
+ * Output:
+ *  0 - on success 
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int set_bypass_pwup_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass_pwup - Get Bypass mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable bypass at power up state / normal Bypass mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int get_bypass_pwup_sd(int if_index);
+
+/**
+ * set_bypass_wd - Set watchdog state
+ * @if_index: network device index of the controlling device
+ * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog timer
+ * @ms_timeout_set(output): requested timeout (in ms units), 
+ *                          that the adapter supports and will be used by the watchdog
+ * Output:
+ * 0  - on success 
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set);
+
+/**
+ * get_bypass_wd - Get watchdog state
+ * @if_index: network device index of the controlling device
+ * @ms_timeout (output): WDT timeout (in ms units), 
+ *                       -1 for unknown wdt status
+ *                        0 if WDT is disabled
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int get_bypass_wd_sd(int if_index, int *ms_timeout_set);
+
+/**
+ * get_wd_expire_time - Get watchdog expire
+ * @if_index: network device index of the controlling device
+ * @ms_time_left (output): time left till watchdog time expire, 
+ *                       -1 if WDT has expired
+ *                       0  if WDT is disabled
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device or unknown wdt status) 
+ **/
+int get_wd_expire_time_sd(int if_index, int *ms_time_left);
+
+/**
+ * reset_bypass_wd_timer - Reset watchdog timer
+ * @if_index: network device index of the controlling device
+ * 
+ * Output:
+ * 1  - on success
+ * 0 - watchdog is not configured
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device or unknown wdt status) 
+ **/
+int reset_bypass_wd_timer_sd(int if_index);
+
+/**
+ * set_std_nic - Standard NIC mode of operation
+ * @if_index: network device index of the controlling device
+ * @nic_mode: 0/1 (Default Bypass mode / Standard NIC mode)
+ * 
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int set_std_nic_sd(int if_index, int nic_mode);
+
+/**
+ * get_std_nic - Get Standard NIC mode setting
+ * @if_index: network device index of the controlling device
+ * 
+ * Output:
+ * 0/1 (Default Bypass mode / Standard NIC mode) on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device) 
+ **/
+int get_std_nic_sd(int if_index);
+
+/**
+ * set_tx - set transmitter enable/disable 
+ * @if_index: network device index of the controlling device
+ * @tx_state: 0/1 (Transmit Disable / Transmit Enable)
+ * 
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ) 
+ **/
+int set_tx_sd(int if_index, int tx_state);
+
+/**
+ * get_std_nic - get transmitter state (disable / enable)
+ * @if_index: network device index of the controlling device
+ * 
+ * Output:
+ * 0/1 (ransmit Disable / Transmit Enable) on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass) 
+ **/
+int get_tx_sd(int if_index);
+
+/**
+ * set_tap - set TAP state
+ * @if_index: network device index of the controlling device
+ * @tap_mode: 1 tap mode , 0 normal nic mode 
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support TAP or it's a slave device) 
+ **/
+int set_tap_sd(int if_index, int tap_mode);
+
+/**
+ * get_tap - Get TAP mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support TAP or it's a slave device) 
+ **/
+int get_tap_sd(int if_index);
+
+/**
+ * get_tap_change - Get change of TAP mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support TAP or it's a slave device) 
+ **/
+int get_tap_change_sd(int if_index);
+
+/**
+ * set_dis_tap - Set Disable TAP mode
+ * @if_index: network device index of the controlling device
+ * @dis_tap: disable tap(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP 
+ *                  or it's a slave device) 
+ **/
+int set_dis_tap_sd(int if_index, int dis_tap);
+
+/**
+ * get_dis_tap - Get Disable TAP mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal TAP mode/ Disable TAP)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP 
+ *                  or it's a slave device) 
+ **/
+int get_dis_tap_sd(int if_index);
+
+/**
+ * set_tap_pwup - Set TAP mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: tap mode setting at power up state (1=TAP en, 0=TAP Dis)
+ * Output:
+ *  0 - on success 
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP 
+ *                  or it's a slave device) 
+ **/
+int set_tap_pwup_sd(int if_index, int tap_mode);
+
+/**
+ * get_tap_pwup - Get TAP mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable TAP at power up state / normal TAP mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP 
+ *                  or it's a slave device) 
+ **/
+int get_tap_pwup_sd(int if_index);
+
+/**
+ * set_bp_disc - set Disconnect state
+ * @if_index: network device index of the controlling device
+ * @tap_mode: 1 disc mode , 0 non-disc mode 
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support Disconnect or it's a slave device) 
+ **/
+int set_bp_disc_sd(int if_index, int disc_mode);
+
+/**
+ * get_bp_disc - Get Disconnect mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Disconnect or it's a slave device) 
+ **/
+int get_bp_disc_sd(int if_index);
+
+/**
+ * get_bp_disc_change - Get change of Disconnect mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Disconnect or it's a slave device) 
+ **/
+int get_bp_disc_change_sd(int if_index);
+
+/**
+ * set_bp_dis_disc - Set Disable Disconnect mode
+ * @if_index: network device index of the controlling device
+ * @dis_tap: disable tap(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable ofthe operation ordevice not support Disconnect 
+ *                  or it's a slave device) 
+ **/
+int set_bp_dis_disc_sd(int if_index, int dis_disc);
+
+/**
+ * get_dis_tap - Get Disable Disconnect mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal Disconnect mode/ Disable Disconnect)
+ * -1 - on failure (device is not capable of the operation ordevice not support Disconnect 
+ *                  or it's a slave device) 
+ **/
+int get_bp_dis_disc_sd(int if_index);
+
+/**
+ * set_bp_disc_pwup - Set Disconnect mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @disc_mode: tap mode setting at power up state (1=Disc en, 0=Disc Dis)
+ * Output:
+ *  0 - on success 
+ * -1 - on failure (device is not capable of the operation ordevice not support Disconnect 
+ *                  or it's a slave device) 
+ **/
+int set_bp_disc_pwup_sd(int if_index, int disc_mode);
+
+/**
+ * get_bp_disc_pwup - Get Disconnect mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable Disconnect at power up state / normal Disconnect mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP 
+ *                  or it's a slave device) 
+ **/
+int get_bp_disc_pwup_sd(int if_index);
+
+/**
+ * set_wd_exp_mode - Set adapter state when WDT expired.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode) 
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int set_wd_exp_mode_sd(int if_index, int bypass_mode);
+
+/**
+ * get_wd_exp_mode - Get adapter state when WDT expired.
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (bypass/tap) on success
+ * -1 - on failure (device not support Bypass or it's a slave device) 
+ **/
+int get_wd_exp_mode_sd(int if_index);
+
+/**
+ * set_wd_autoreset - reset WDT periodically.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode) 
+ * Output:
+ * 1  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device or unknown wdt status) 
+ **/
+int set_wd_autoreset_sd(int if_index, int time);
+
+/**
+ * set_wd_autoreset - reset WDT periodically.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode) 
+ * Output:
+ * 1  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass 
+ *                  or it's a slave device or unknown wdt status) 
+ **/
+int get_wd_autoreset_sd(int if_index);
+
+/**
+ * set_tpl - set TPL state
+ * @if_index: network device index of the controlling device
+ * @tpl_mode: 1 tpl mode , 0 normal nic mode 
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support TPL) 
+ **/
+int set_tpl_sd(int if_index, int tpl_mode);
+
+/**
+ * get_tpl - Get TPL mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support TPL or it's a slave device) 
+ **/
+int get_tpl_sd(int if_index);
+
+int get_bypass_info_sd(int if_index, struct bp_info *bp_info);
+int bp_if_scan_sd(void);
+/*int get_dev_num_sd(void);*/
diff --git a/drivers/staging/silicom/libbp_sd.h b/drivers/staging/silicom/libbp_sd.h
new file mode 100644
index 0000000..065277f
--- /dev/null
+++ b/drivers/staging/silicom/libbp_sd.h
@@ -0,0 +1,550 @@
+/******************************************************************************/
+/*                                                                            */
+/* bypass library, Copyright (c) 2004 Silicom, Ltd                            */
+/* Corporation.                                                               */
+/*                                                                            */
+/* This program is free software; you can redistribute it and/or modify       */
+/* it under the terms of the GNU General Public License as published by       */
+/* the Free Software Foundation, located in the file LICENSE.                 */
+/*                                                                            */
+/* Ver 1.0.0                                                                  */
+/*                                                                            */
+/* libbypass.h                                                                */
+/*                                                                            */
+/******************************************************************************/
+
+#define BP_CAP                   0x01	/* BIT_0 */
+#define BP_STATUS_CAP            0x02
+#define BP_STATUS_CHANGE_CAP     0x04
+#define SW_CTL_CAP               0x08
+#define BP_DIS_CAP               0x10
+#define BP_DIS_STATUS_CAP        0x20
+#define STD_NIC_CAP              0x40
+#define BP_PWOFF_ON_CAP          0x80
+#define BP_PWOFF_OFF_CAP         0x0100
+#define BP_PWOFF_CTL_CAP         0x0200
+#define BP_PWUP_ON_CAP           0x0400
+#define BP_PWUP_OFF_CAP          0x0800
+#define BP_PWUP_CTL_CAP          0x1000
+#define WD_CTL_CAP               0x2000
+#define WD_STATUS_CAP            0x4000
+#define WD_TIMEOUT_CAP           0x8000
+#define TX_CTL_CAP               0x10000
+#define TX_STATUS_CAP            0x20000
+#define TAP_CAP                  0x40000
+#define TAP_STATUS_CAP           0x80000
+#define TAP_STATUS_CHANGE_CAP    0x100000
+#define TAP_DIS_CAP              0x200000
+#define TAP_DIS_STATUS_CAP       0x400000
+#define TAP_PWUP_ON_CAP          0x800000
+#define TAP_PWUP_OFF_CAP         0x1000000
+#define TAP_PWUP_CTL_CAP         0x2000000
+#define NIC_CAP_NEG              0x4000000	/* BIT 26 */
+
+#define WD_MIN_TIME_GET(desc)   (desc & 0xf)
+#define WDT_STEP_TIME           0x10
+
+struct bp_info {
+	char prod_name[14];
+	unsigned char fw_ver;
+};
+
+/**
+ * is_bypass - check if device is a Bypass controlling device
+ * @if_index: network device index
+ *
+ * Output:
+ *  1 -  if device is bypass controlling device,
+ *  0 -  if device is bypass slave device
+ * -1 -  device not support Bypass
+ **/
+int is_bypass_sd(int if_index);
+
+/**
+ * get_bypass_slave - get second port participate in the Bypass pair
+ * @if_index: network device index
+ *
+ * Output:
+ *  network device index of the slave device
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int get_bypass_slave_sd(int if_index);
+
+/**
+ * get_bypass_caps - get second port participate in the Bypass pair
+ * @if_index: network device index
+ *
+ * Output:
+ * flags word on success;flag word is a 32-bit mask word with each bit defines different
+ * capability as described bellow.
+ * Value of 1 for supporting this feature. 0 for not supporting this feature.
+ * -1 - on failure (if the device is not capable of the operation or not a Bypass device)
+ * Bit	feature	                description
+ *
+ * 0	BP_CAP	                The interface is Bypass capable in general
+ *
+ * 1	BP_STATUS_CAP	        The interface can report of the current Bypass mode
+ *
+ * 2	BP_STATUS_CHANGE_CAP	The interface can report on a change to bypass mode from
+ *                              the last time the mode was defined
+ *
+ * 3	SW_CTL_CAP	            The interface is Software controlled capable for bypass/non bypass modes.
+ *
+ * 4	BP_DIS_CAP	            The interface is capable of disabling the Bypass mode at all times.
+ *                              This mode will retain its mode even during power loss and also after
+ *                              power recovery. This will overcome on any bypass operation due to
+ *                              watchdog timeout or set bypass command.
+ *
+ * 5	BP_DIS_STATUS_CAP	    The interface can report of the current DIS_BP_CAP
+ *
+ * 6	STD_NIC_CAP	            The interface is capable to be configured to operate as standard, non Bypass,
+ *                              NIC interface (have direct connection to interfaces at all power modes)
+ *
+ * 7	BP_PWOFF_NO_CAP	        The interface can be in Bypass mode at power off state
+ *
+ * 8	BP_PWOFF_OFF_CAP	    The interface can disconnect the Bypass mode at power off state without
+ *                              effecting all the other states of operation
+ *
+ * 9	BP_PWOFF_CTL_CAP	    The behavior of the Bypass mode at Power-off state can be controlled by
+ *                              software without effecting any other state
+ *
+ *10    BP_PWUP_ON_CAP	        The interface can be in Bypass mode when power is turned on
+ *                              (until the system take control of the bypass functionality)
+ *
+ *11	BP_PWUP_OFF_CAP	        The interface can disconnect from Bypass mode when power is turned on
+ *                              (until the system take control of the bypass functionality)
+ *
+ *12	BP_PWUP_CTL_CAP	        The behavior of the Bypass mode at Power-up can be controlled by software
+ *
+ *13	WD_CTL_CAP	            The interface has watchdog capabilities to turn to Bypass mode when not reset
+ *                              for defined period of time.
+ *
+ *14	WD_STATUS_CAP	        The interface can report on the watchdog status (Active/inactive)
+ *
+ *15	WD_TIMEOUT_CAP	        The interface can report the time left till watchdog triggers to Bypass mode.
+ *
+ *16-31 RESERVED
+ *
+ * **/
+int get_bypass_caps_sd(int if_index);
+
+/**
+ * get_wd_set_caps - Obtain watchdog timer setting capabilities
+ * @if_index: network device index
+ *
+ * Output:
+ *
+ * Set of numbers defining the various parameters of the watchdog capable
+ * to be set to as described bellow.
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ *
+ * Bit	feature	        description
+ *
+ * 0-3	WD_MIN_TIME	    The interface WD minimal time period  in 100mS units
+ *
+ * 4	WD_STEP_TIME	The steps of the WD timer in
+ *                      0 - for linear steps (WD_MIN_TIME * X)
+ *                      1 - for multiply by 2 from previous step (WD_MIN_TIME * 2^X)
+ *
+ * 5-8	WD_STEP_COUNT	Number of steps the WD timer supports in 2^X
+ *                      (X bit available for defining the value)
+ *
+ *
+ *
+ **/
+int get_wd_set_caps_sd(int if_index);
+
+/**
+ * set_bypass - set Bypass state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  bypass mode (1=on, 0=off)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int set_bypass_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass - Get Bypass mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int get_bypass_sd(int if_index);
+
+/**
+ * get_bypass_change - Get change of Bypass mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int get_bypass_change_sd(int if_index);
+
+/**
+ * set_dis_bypass - Set Disable Bypass mode
+ * @if_index: network device index of the controlling device
+ * @dis_bypass: disable bypass(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int set_dis_bypass_sd(int if_index, int dis_bypass);
+
+/**
+ * get_dis_bypass - Get Disable Bypass mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal Bypass mode/ Disable bypass)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int get_dis_bypass_sd(int if_index);
+
+/**
+ * set_bypass_pwoff - Set Bypass mode at power-off state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: bypass mode setting at power off state (1=BP en, 0=BP Dis)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int set_bypass_pwoff_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass_pwoff - Get Bypass mode state at power-off state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable bypass at power off state / normal Bypass mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int get_bypass_pwoff_sd(int if_index);
+
+/**
+ * set_bypass_pwup - Set Bypass mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: bypass mode setting at power up state (1=BP en, 0=BP Dis)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int set_bypass_pwup_sd(int if_index, int bypass_mode);
+
+/**
+ * get_bypass_pwup - Get Bypass mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable bypass at power up state / normal Bypass mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int get_bypass_pwup_sd(int if_index);
+
+/**
+ * set_bypass_wd - Set watchdog state
+ * @if_index: network device index of the controlling device
+ * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog timer
+ * @ms_timeout_set(output): requested timeout (in ms units),
+ *                          that the adapter supports and will be used by the watchdog
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set);
+
+/**
+ * get_bypass_wd - Get watchdog state
+ * @if_index: network device index of the controlling device
+ * @ms_timeout (output): WDT timeout (in ms units),
+ *                       -1 for unknown wdt status
+ *                        0 if WDT is disabled
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int get_bypass_wd_sd(int if_index, int *ms_timeout_set);
+
+/**
+ * get_wd_expire_time - Get watchdog expire
+ * @if_index: network device index of the controlling device
+ * @ms_time_left (output): time left till watchdog time expire,
+ *                       -1 if WDT has expired
+ *                       0  if WDT is disabled
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device or unknown wdt status)
+ **/
+int get_wd_expire_time_sd(int if_index, int *ms_time_left);
+
+/**
+ * reset_bypass_wd_timer - Reset watchdog timer
+ * @if_index: network device index of the controlling device
+ *
+ * Output:
+ * 1  - on success
+ * 0 - watchdog is not configured
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device or unknown wdt status)
+ **/
+int reset_bypass_wd_timer_sd(int if_index);
+
+/**
+ * set_std_nic - Standard NIC mode of operation
+ * @if_index: network device index of the controlling device
+ * @nic_mode: 0/1 (Default Bypass mode / Standard NIC mode)
+ *
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int set_std_nic_sd(int if_index, int nic_mode);
+
+/**
+ * get_std_nic - Get Standard NIC mode setting
+ * @if_index: network device index of the controlling device
+ *
+ * Output:
+ * 0/1 (Default Bypass mode / Standard NIC mode) on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device)
+ **/
+int get_std_nic_sd(int if_index);
+
+/**
+ * set_tx - set transmitter enable/disable
+ * @if_index: network device index of the controlling device
+ * @tx_state: 0/1 (Transmit Disable / Transmit Enable)
+ *
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation )
+ **/
+int set_tx_sd(int if_index, int tx_state);
+
+/**
+ * get_tx - get transmitter state (disable / enable)
+ * @if_index: network device index of the controlling device
+ *
+ * Output:
+ * 0/1 (ransmit Disable / Transmit Enable) on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass)
+ **/
+int get_tx_sd(int if_index);
+
+/**
+ * set_tpl - set TPL enable/disable
+ * @if_index: network device index of the controlling device
+ * @tx_state: 0/1 (TPL Disable / TPL Enable)
+ *
+ * Output:
+ * 0  - on success
+ * -1 - on failure (device is not capable of the operation )
+ **/
+int set_tpl_sd(int if_index, int tpl_state);
+
+/**
+ * get_tpl - get TPL state (disable / enable)
+ * @if_index: network device index of the controlling device
+ *
+ * Output:
+ * 0/1 (TPL Disable / TPL Enable) on success
+ * -1 - on failure (device is not capable of the operation)
+ **/
+int get_tpl_sd(int if_index);
+
+int get_bp_hw_reset_sd(int if_index);
+
+int set_bp_hw_reset_sd(int if_index, int status);
+
+/**
+ * set_tap - set TAP state
+ * @if_index: network device index of the controlling device
+ * @tap_mode: 1 tap mode , 0 normal nic mode
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support TAP or it's a slave device)
+ **/
+int set_tap_sd(int if_index, int tap_mode);
+
+/**
+ * get_tap - Get TAP mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support TAP or it's a slave device)
+ **/
+int get_tap_sd(int if_index);
+
+/**
+ * get_tap_change - Get change of TAP mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support TAP or it's a slave device)
+ **/
+int get_tap_change_sd(int if_index);
+
+/**
+ * set_dis_tap - Set Disable TAP mode
+ * @if_index: network device index of the controlling device
+ * @dis_tap: disable tap(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP
+ *                  or it's a slave device)
+ **/
+int set_dis_tap_sd(int if_index, int dis_tap);
+
+/**
+ * get_dis_tap - Get Disable TAP mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal TAP mode/ Disable TAP)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP
+ *                  or it's a slave device)
+ **/
+int get_dis_tap_sd(int if_index);
+
+/**
+ * set_tap_pwup - Set TAP mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @bypass_mode: tap mode setting at power up state (1=TAP en, 0=TAP Dis)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP
+ *                  or it's a slave device)
+ **/
+int set_tap_pwup_sd(int if_index, int tap_mode);
+
+/**
+ * get_tap_pwup - Get TAP mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable TAP at power up state / normal TAP mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP
+ *                  or it's a slave device)
+ **/
+int get_tap_pwup_sd(int if_index);
+
+/**
+ * set_wd_exp_mode - Set adapter state when WDT expired.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int set_wd_exp_mode_sd(int if_index, int bypass_mode);
+
+/**
+ * get_wd_exp_mode - Get adapter state when WDT expired.
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (bypass/tap) on success
+ * -1 - on failure (device not support Bypass or it's a slave device)
+ **/
+int get_wd_exp_mode_sd(int if_index);
+
+/**
+ * set_wd_autoreset - reset WDT periodically.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode)
+ * Output:
+ * 1  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device or unknown wdt status)
+ **/
+int set_wd_autoreset_sd(int if_index, int time);
+
+/**
+ * set_wd_autoreset - reset WDT periodically.
+ * @if_index: network device index of the controlling device
+ * @bypass_mode:  adapter mode (1=tap mode, 0=bypass mode)
+ * Output:
+ * 1  - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support Bypass
+ *                  or it's a slave device or unknown wdt status)
+ **/
+int get_wd_autoreset_sd(int if_index);
+/**
+ * set_disc - set DISC state
+ * @if_index: network device index of the controlling device
+ * @tap_mode: 1 DISC mode , 0 normal nic mode
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device not support disconnect or it's a slave device)
+ **/
+int set_bp_disc_sd(int if_index, int disc_mode);
+
+/**
+ * get_disc - Get disc mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support disconnect or it's a slave device)
+ **/
+int get_bp_disc_sd(int if_index);
+
+/**
+ * get_disc_change - Get change of DISC mode state from last status check
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - (off/on) on success
+ * -1 - on failure (device not support disconnect or it's a slave device)
+ **/
+int get_bp_disc_change_sd(int if_index);
+
+/**
+ * set_dis_disc - Set Disable DISC mode
+ * @if_index: network device index of the controlling device
+ * @dis_disc: disable disconnect(1=dis, 0=en)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support DISC
+ *                  or it's a slave device)
+ **/
+int set_bp_dis_disc_sd(int if_index, int dis_disc);
+
+/**
+ * get_dis_disc - Get Disable DISC mode state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (normal DISC mode/ Disable DISC)
+ * -1 - on failure (device is not capable of the operation ordevice not support TAP
+ *                  or it's a slave device)
+ **/
+int get_bp_dis_disc_sd(int if_index);
+
+/**
+ * set_disc_pwup - Set DISC mode at power-up state
+ * @if_index: network device index of the controlling device
+ * @disc_mode: DISC mode setting at power up state (1= en, 0= Dis)
+ * Output:
+ *  0 - on success
+ * -1 - on failure (device is not capable of the operation ordevice not support DISC
+ *                  or it's a slave device)
+ **/
+int set_bp_disc_pwup_sd(int if_index, int disc_mode);
+
+/**
+ * get_disc_pwup - Get DISC mode state at power-up state
+ * @if_index: network device index of the controlling device
+ * Output:
+ *  0/1 - on success (Disable DISC at power up state / normal DISC mode)
+ * -1 - on failure (device is not capable of the operation ordevice not support DISC
+ *                  or it's a slave device)
+ **/
+int get_bp_disc_pwup_sd(int if_index);
+
+int get_bypass_info_sd(int if_index, struct bp_info *bp_info);
+int bp_if_scan_sd(void);
+/*int get_dev_num_sd(void);*/
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 56829fc..cd920da 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -514,8 +514,7 @@
 		file = "slicoss/gbrcvucode.sys";
 		break;
 	default:
-		ASSERT(0);
-		break;
+		return -ENOENT;
 	}
 
 	ret = request_firmware(&fw, file, &adapter->pcidev->dev);
@@ -529,15 +528,16 @@
 	index += 4;
 	switch (adapter->devid) {
 	case SLIC_2GB_DEVICE_ID:
-		if (rcvucodelen != OasisRcvUCodeLen)
+		if (rcvucodelen != OasisRcvUCodeLen) {
+			release_firmware(fw);
 			return -EINVAL;
+		}
 		break;
 	case SLIC_1GB_DEVICE_ID:
-		if (rcvucodelen != GBRcvUCodeLen)
+		if (rcvucodelen != GBRcvUCodeLen) {
+			release_firmware(fw);
 			return -EINVAL;
-		break;
-	default:
-		ASSERT(0);
+		}
 		break;
 	}
 	/* start download */
@@ -2552,7 +2552,6 @@
 		if (status == 0)
 			slic_mcast_set_mask(adapter);
 	}
-	return;
 }
 
 #define  XMIT_FAIL_LINK_STATE               1
@@ -3132,7 +3131,6 @@
 {
 	struct adapter *adapter = netdev_priv(dev);
 	struct sliccard *card = adapter->card;
-	u32 locked = 0;
 	int status;
 
 	ASSERT(adapter);
@@ -3142,7 +3140,6 @@
 
 	spin_lock_irqsave(&slic_global.driver_lock.lock,
 				slic_global.driver_lock.flags);
-	locked = 1;
 	if (!adapter->activated) {
 		card->adapters_activated++;
 		slic_global.num_slic_ports_active++;
@@ -3156,23 +3153,15 @@
 			slic_global.num_slic_ports_active--;
 			adapter->activated = 0;
 		}
-		if (locked) {
-			spin_unlock_irqrestore(&slic_global.driver_lock.lock,
-						slic_global.driver_lock.flags);
-			locked = 0;
-		}
-		return status;
+		goto spin_unlock;
 	}
 	if (!card->master)
 		card->master = adapter;
 
-	if (locked) {
-		spin_unlock_irqrestore(&slic_global.driver_lock.lock,
-					slic_global.driver_lock.flags);
-		locked = 0;
-	}
-
-	return 0;
+spin_unlock:
+	spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+			       slic_global.driver_lock.flags);
+	return status;
 }
 
 static void slic_card_cleanup(struct sliccard *card)
@@ -3712,9 +3701,8 @@
 					phys_shmem);
 	ASSERT(adapter->pshmem);
 
-	memset(adapter->pshmem, 0, sizeof(struct slic_shmem));
-
-	return;
+	if (adapter->pshmem)
+		memset(adapter->pshmem, 0, sizeof(struct slic_shmem));
 }
 
 static const struct net_device_ops slic_netdev_ops = {
diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h
index 333f33c..8599861 100644
--- a/drivers/staging/sm7xxfb/sm7xx.h
+++ b/drivers/staging/sm7xxfb/sm7xx.h
@@ -29,7 +29,7 @@
 #define dac_reg	(0x3c8)
 #define dac_val	(0x3c9)
 
-extern char __iomem *smtc_RegBaseAddress;
+extern void __iomem *smtc_RegBaseAddress;
 #define smtc_mmiowb(dat, reg)	writeb(dat, smtc_RegBaseAddress + reg)
 #define smtc_mmioww(dat, reg)	writew(dat, smtc_RegBaseAddress + reg)
 #define smtc_mmiowl(dat, reg)	writel(dat, smtc_RegBaseAddress + reg)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
index 1c1780c..f27182d 100644
--- a/drivers/staging/sm7xxfb/sm7xxfb.c
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -43,11 +43,11 @@
 	u16 chip_id;
 	u8  chip_rev_id;
 
-	unsigned char __iomem *m_pMMIO;
-	char __iomem *m_pLFB;
-	char *m_pDPR;
-	char *m_pVPR;
-	char *m_pCPR;
+	void __iomem *lfb;	/* linear frame buffer */
+	void __iomem *dp_regs;	/* drawing processor control regs */
+	void __iomem *vp_regs;	/* video processor control regs */
+	void __iomem *cp_regs;	/* capture processor control regs */
+	void __iomem *mmio;	/* memory map IO port */
 
 	u_int width;
 	u_int height;
@@ -56,8 +56,7 @@
 	u32 colreg[17];
 };
 
-char __iomem *smtc_RegBaseAddress;	/* Memory Map IO starting address */
-char __iomem *smtc_VRAMBaseAddress;	/* video memory starting address */
+void __iomem *smtc_RegBaseAddress;	/* Memory Map IO starting address */
 
 static struct fb_var_screeninfo smtcfb_var = {
 	.xres           = 1024,
@@ -72,14 +71,20 @@
 	.height         = -1,
 	.width          = -1,
 	.vmode          = FB_VMODE_NONINTERLACED,
+	.nonstd         = 0,
+	.accel_flags    = FB_ACCELF_TEXT,
 };
 
 static struct fb_fix_screeninfo smtcfb_fix = {
-	.id             = "sm712fb",
+	.id             = "smXXXfb",
 	.type           = FB_TYPE_PACKED_PIXELS,
 	.visual         = FB_VISUAL_TRUECOLOR,
 	.line_length    = 800 * 3,
 	.accel          = FB_ACCEL_SMI_LYNX,
+	.type_aux       = 0,
+	.xpanstep       = 0,
+	.ypanstep       = 0,
+	.ywrapstep      = 0,
 };
 
 struct vesa_mode {
@@ -545,28 +550,28 @@
 	smtc_mmiowb(0x67, 0x3c2);
 
 	/* set VPR registers */
-	writel(0x0, sfb->m_pVPR + 0x0C);
-	writel(0x0, sfb->m_pVPR + 0x40);
+	writel(0x0, sfb->vp_regs + 0x0C);
+	writel(0x0, sfb->vp_regs + 0x40);
 
 	/* set data width */
 	m_nScreenStride =
 		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
 	switch (sfb->fb.var.bits_per_pixel) {
 	case 8:
-		writel(0x0, sfb->m_pVPR + 0x0);
+		writel(0x0, sfb->vp_regs + 0x0);
 		break;
 	case 16:
-		writel(0x00020000, sfb->m_pVPR + 0x0);
+		writel(0x00020000, sfb->vp_regs + 0x0);
 		break;
 	case 24:
-		writel(0x00040000, sfb->m_pVPR + 0x0);
+		writel(0x00040000, sfb->vp_regs + 0x0);
 		break;
 	case 32:
-		writel(0x00030000, sfb->m_pVPR + 0x0);
+		writel(0x00030000, sfb->vp_regs + 0x0);
 		break;
 	}
 	writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
-	       sfb->m_pVPR + 0x10);
+	       sfb->vp_regs + 0x10);
 
 }
 
@@ -673,9 +678,9 @@
 };
 
 /*
- * alloc struct smtcfb_info and assign the default value
+ * alloc struct smtcfb_info and assign default values
  */
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
 {
 	struct smtcfb_info *sfb;
 
@@ -686,32 +691,12 @@
 
 	sfb->pdev = pdev;
 
-	/* init sfb->fb with default value */
-
-	sfb->fb.flags = FBINFO_FLAG_DEFAULT;
-	sfb->fb.fbops = &smtcfb_ops;
-
-	sfb->fb.fix = smtcfb_fix;
-	strcpy(sfb->fb.fix.id, name);
-
-	sfb->fb.fix.type        = FB_TYPE_PACKED_PIXELS;
-	sfb->fb.fix.type_aux    = 0;
-	sfb->fb.fix.xpanstep    = 0;
-	sfb->fb.fix.ypanstep    = 0;
-	sfb->fb.fix.ywrapstep   = 0;
-	sfb->fb.fix.accel       = FB_ACCEL_SMI_LYNX;
-
-	sfb->fb.var             = smtcfb_var;
-	sfb->fb.var.nonstd      = 0;
-	sfb->fb.var.activate    = FB_ACTIVATE_NOW;
-	sfb->fb.var.height      = -1;
-	sfb->fb.var.width       = -1;
-	sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
-	sfb->fb.var.vmode       = FB_VMODE_NONINTERLACED;
-
-	sfb->fb.pseudo_palette  = sfb->colreg;
-
-	sfb->fb.par = sfb;
+	sfb->fb.flags          = FBINFO_FLAG_DEFAULT;
+	sfb->fb.fbops          = &smtcfb_ops;
+	sfb->fb.fix            = smtcfb_fix;
+	sfb->fb.var            = smtcfb_var;
+	sfb->fb.pseudo_palette = sfb->colreg;
+	sfb->fb.par            = sfb;
 
 	return sfb;
 }
@@ -751,7 +736,7 @@
 
 	sfb->fb.fix.smem_len = smem_len;
 
-	sfb->fb.screen_base = smtc_VRAMBaseAddress;
+	sfb->fb.screen_base = sfb->lfb;
 
 	if (!sfb->fb.screen_base) {
 		dev_err(&pdev->dev,
@@ -788,9 +773,8 @@
 {
 	struct smtcfb_info *sfb;
 	u_long smem_size = 0x00800000;	/* default 8MB */
-	char name[16];
 	int err;
-	unsigned long pFramebufferPhysical;
+	unsigned long mmio_base;
 
 	dev_info(&pdev->dev, "Silicon Motion display driver.");
 
@@ -798,7 +782,9 @@
 	if (err)
 		return err;
 
-	sfb = smtc_alloc_fb_info(pdev, name);
+	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
+
+	sfb = smtc_alloc_fb_info(pdev);
 
 	if (!sfb) {
 		err = -ENOMEM;
@@ -806,7 +792,6 @@
 	}
 
 	sfb->chip_id = ent->device;
-	sprintf(name, "sm%Xfb", sfb->chip_id);
 
 	pci_set_drvdata(pdev, sfb);
 
@@ -829,33 +814,28 @@
 		sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
 #endif
 	/* Map address and memory detection */
-	pFramebufferPhysical = pci_resource_start(pdev, 0);
+	mmio_base = pci_resource_start(pdev, 0);
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
 
 	switch (sfb->chip_id) {
 	case 0x710:
 	case 0x712:
-		sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
+		sfb->fb.fix.mmio_start = mmio_base + 0x00400000;
 		sfb->fb.fix.mmio_len = 0x00400000;
 		smem_size = SM712_VIDEOMEMORYSIZE;
 #ifdef __BIG_ENDIAN
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    ioremap(pFramebufferPhysical, 0x00c00000));
+		sfb->lfb = ioremap(mmio_base, 0x00c00000);
 #else
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    ioremap(pFramebufferPhysical, 0x00800000));
+		sfb->lfb = ioremap(mmio_base, 0x00800000);
 #endif
-		sfb->m_pMMIO = (smtc_RegBaseAddress =
-		    smtc_VRAMBaseAddress + 0x00700000);
-		sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
-		sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
+		sfb->mmio = (smtc_RegBaseAddress =
+		    sfb->lfb + 0x00700000);
+		sfb->dp_regs = sfb->lfb + 0x00408000;
+		sfb->vp_regs = sfb->lfb + 0x0040c000;
 #ifdef __BIG_ENDIAN
 		if (sfb->fb.var.bits_per_pixel == 32) {
-			smtc_VRAMBaseAddress += 0x800000;
-			sfb->m_pLFB += 0x800000;
-			dev_info(&pdev->dev,
-				 "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
-				  smtc_VRAMBaseAddress, sfb->m_pLFB);
+			sfb->lfb += 0x800000;
+			dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
 		}
 #endif
 		if (!smtc_RegBaseAddress) {
@@ -879,15 +859,14 @@
 #endif
 		break;
 	case 0x720:
-		sfb->fb.fix.mmio_start = pFramebufferPhysical;
+		sfb->fb.fix.mmio_start = mmio_base;
 		sfb->fb.fix.mmio_len = 0x00200000;
 		smem_size = SM722_VIDEOMEMORYSIZE;
-		sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    sfb->m_pDPR + 0x00200000);
-		sfb->m_pMMIO = (smtc_RegBaseAddress =
-		    sfb->m_pDPR + 0x000c0000);
-		sfb->m_pVPR = sfb->m_pDPR + 0x800;
+		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
+		sfb->lfb = sfb->dp_regs + 0x00200000;
+		sfb->mmio = (smtc_RegBaseAddress =
+		    sfb->dp_regs + 0x000c0000);
+		sfb->vp_regs = sfb->dp_regs + 0x800;
 
 		smtc_seqw(0x62, 0xff);
 		smtc_seqw(0x6a, 0x0d);
diff --git a/drivers/staging/speakup/i18n.c b/drivers/staging/speakup/i18n.c
index ca01734..7c1658b 100644
--- a/drivers/staging/speakup/i18n.c
+++ b/drivers/staging/speakup/i18n.c
@@ -555,6 +555,7 @@
 			&& index <= MSG_FORMATTED_END)
 				&& !fmt_validate(speakup_default_msgs[index],
 				newstr)) {
+				kfree(newstr);
 				return -EINVAL;
 			}
 			spk_lock(flags);
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
index 42cdafe..e2f5c81 100644
--- a/drivers/staging/speakup/speakup_soft.c
+++ b/drivers/staging/speakup/speakup_soft.c
@@ -40,13 +40,13 @@
 static unsigned char get_index(void);
 
 static struct miscdevice synth_device;
-static int initialized;
+static int init_pos;
 static int misc_registered;
 
 static struct var_t vars[] = {
 	{ CAPS_START, .u.s = {"\x01+3p" } },
 	{ CAPS_STOP, .u.s = {"\x01-3p" } },
-	{ RATE, .u.n = {"\x01%ds", 5, 0, 9, 0, 0, NULL } },
+	{ RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
 	{ PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
 	{ VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
 	{ TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
@@ -194,7 +194,7 @@
 	unsigned long flags;
 	spk_lock(flags);
 	synth_soft.alive = 0;
-	initialized = 0;
+	init_pos = 0;
 	spk_unlock(flags);
 	/* Make sure we let applications go before leaving */
 	speakup_start_ttys();
@@ -239,13 +239,8 @@
 			ch = '\x18';
 		} else if (synth_buffer_empty()) {
 			break;
-		} else if (!initialized) {
-			if (*init) {
-				ch = *init;
-				init++;
-			} else {
-				initialized = 1;
-			}
+		} else if (init[init_pos]) {
+			ch = init[init_pos++];
 		} else {
 			ch = synth_buffer_getc();
 		}
diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c
index b303c91..1cfa0b0 100644
--- a/drivers/staging/telephony/ixj.c
+++ b/drivers/staging/telephony/ixj.c
@@ -7057,7 +7057,7 @@
 		printk(KERN_INFO "Enable Line Monitor\n");
 
 	if (ixjdebug & 0x0002)
-		printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n");
+		printk(KERN_INFO "Set Line Monitor to Asynchronous Mode\n");
 
 	if (ixj_WriteDSPCommand(0x7E01, j))		/* Asynchronous Line Monitor */
 		return -1;
@@ -7068,7 +7068,7 @@
 	if (ixj_WriteDSPCommand(0x5151, j))		/* Enable DTMF detection */
 		return -1;
 
-	if (ixj_WriteDSPCommand(0x6E01, j))		/* Set Asyncronous Tone Generation */
+	if (ixj_WriteDSPCommand(0x6E01, j))		/* Set Asynchronous Tone Generation */
 		return -1;
 
 	set_rec_depth(j, 2);	/* Set Record Channel Limit to 2 frames */
diff --git a/drivers/staging/tidspbridge/Documentation/error-codes b/drivers/staging/tidspbridge/Documentation/error-codes
index 12826e2..ad73cba 100644
--- a/drivers/staging/tidspbridge/Documentation/error-codes
+++ b/drivers/staging/tidspbridge/Documentation/error-codes
@@ -69,7 +69,7 @@
     Invalid pointer or handler.
 
 [EEXIST]
-    Attempted to create a channel manager  when one already exists.
+    Attempted to create a channel manager when one already exists.
 
 [EINVAL]
     Invalid argument.
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h
index 7cb5871..543a127 100644
--- a/drivers/staging/tidspbridge/core/_tiomap.h
+++ b/drivers/staging/tidspbridge/core/_tiomap.h
@@ -219,7 +219,7 @@
 /* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */
 #define MBX_CORE2_RESOURCES 1
 
-/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */
+/* MBX_PM_MAX_RESOURCES: TOTAL Clock Resources. */
 #define MBX_PM_MAX_RESOURCES 11
 
 /*  Power Management Commands */
diff --git a/drivers/staging/tidspbridge/core/chnl_sm.c b/drivers/staging/tidspbridge/core/chnl_sm.c
index e0c7e4c..16fa346 100644
--- a/drivers/staging/tidspbridge/core/chnl_sm.c
+++ b/drivers/staging/tidspbridge/core/chnl_sm.c
@@ -20,7 +20,7 @@
  *      The lower edge functions must be implemented by the Bridge driver
  *      writer, and are declared in chnl_sm.h.
  *
- *      Care is taken in this code to prevent simulataneous access to channel
+ *      Care is taken in this code to prevent simultaneous access to channel
  *      queues from
  *      1. Threads.
  *      2. io_dpc(), scheduled from the io_isr() as an event.
@@ -34,7 +34,7 @@
  *  Channel Invariant:
  *      There is an important invariant condition which must be maintained per
  *      channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of
- *      which may cause timeouts and/or failure offunction sync_wait_on_event.
+ *      which may cause timeouts and/or failure of function sync_wait_on_event.
  *      This invariant condition is:
  *
  *          list_empty(&pchnl->io_completions) ==> pchnl->sync_event is reset
@@ -94,7 +94,7 @@
 	struct dev_object *dev_obj;
 	u8 dw_state;
 	bool is_eos;
-	struct chnl_mgr *chnl_mgr_obj = pchnl->chnl_mgr_obj;
+	struct chnl_mgr *chnl_mgr_obj;
 	u8 *host_sys_buf = NULL;
 	bool sched_dpc = false;
 	u16 mb_val = 0;
@@ -153,6 +153,7 @@
 	 * If DPC is scheduled in process context (iosm_schedule) and any
 	 * non-mailbox interrupt occurs, that DPC will run and break CS. Hence
 	 * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */
+	chnl_mgr_obj = pchnl->chnl_mgr_obj;
 	spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
 	omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
 	if (pchnl->chnl_type == CHNL_PCPY) {
@@ -602,7 +603,7 @@
 		/*  Since DSPStream_Reclaim() does not take a timeout
 		 *  parameter, we pass the stream's timeout value to
 		 *  bridge_chnl_get_ioc. We cannot determine whether or not
-		 *  we have waited in User mode. Since the stream's timeout
+		 *  we have waited in user mode. Since the stream's timeout
 		 *  value may be non-zero, we still have to set the event.
 		 *  Therefore, this optimization is taken out.
 		 *
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
index c7df34e..b647207 100644
--- a/drivers/staging/tidspbridge/core/dsp-clock.c
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
@@ -16,12 +16,14 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+#define L4_34XX_BASE		0x48000000
+
 #include <linux/types.h>
 
 /*  ----------------------------------- Host OS */
 #include <dspbridge/host_os.h>
 #include <plat/dmtimer.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 480a384..e322fb7 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -837,8 +837,8 @@
 /*
  *  ======== io_dpc ========
  *      Deferred procedure call for shared memory channel driver ISR.  Carries
- *      out the dispatch of I/O as a non-preemptible event.It can only be
- *      pre-empted      by an ISR.
+ *      out the dispatch of I/O as a non-preemptible event. It can only be
+ *      pre-empted by an ISR.
  */
 void io_dpc(unsigned long ref_data)
 {
@@ -877,7 +877,7 @@
 						  pio_mgr->intr_val);
 			}
 		}
-		/* Proc-copy chanel dispatch */
+		/* Proc-copy channel dispatch */
 		input_chnl(pio_mgr, NULL, IO_SERVICE);
 		output_chnl(pio_mgr, NULL, IO_SERVICE);
 
@@ -938,7 +938,7 @@
 /*
  *  ======== io_request_chnl ========
  *  Purpose:
- *      Request chanenel I/O from the DSP. Sets flags in shared memory, then
+ *      Request channel I/O from the DSP. Sets flags in shared memory, then
  *      interrupts the DSP.
  */
 void io_request_chnl(struct io_mgr *io_manager, struct chnl_object *pchnl,
@@ -2208,7 +2208,7 @@
 			module_struct->num_sects);
 
 		/*
-		 * The section name strings start immedialty following
+		 * The section name strings start immediately following
 		 * the array of dll_sect structures.
 		 */
 		sect_str = (char *) &module_struct->
diff --git a/drivers/staging/tidspbridge/core/sync.c b/drivers/staging/tidspbridge/core/sync.c
index 995986a..7bb550a 100644
--- a/drivers/staging/tidspbridge/core/sync.c
+++ b/drivers/staging/tidspbridge/core/sync.c
@@ -49,7 +49,7 @@
  * @timeout	timeout on waiting for the evetns.
  * @pu_index	index of the event set.
  *
- * This functios will wait until any of the array element is set or until
+ * These functions will wait until any of the array element is set or until
  * timeout. In case of success the function will return 0 and
  * @pu_index will store the index of the array element set or in case
  * of timeout the function will return -ETIME or in case of
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index f9609ce..066a3ce 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -16,7 +16,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 
 #include <linux/types.h>
 /*  ----------------------------------- Host OS */
@@ -328,7 +328,7 @@
 					   ul_num_bytes, mem_type);
 		return status;
 	}
-	/* copy the data from  DSP memory, */
+	/* copy the data from DSP memory */
 	memcpy(host_buff, (void *)(dsp_base_addr + offset), ul_num_bytes);
 	return status;
 }
@@ -415,10 +415,10 @@
 		/* Assert RST1 i.e only the RST only for DSP megacell */
 		if (!status) {
 			/*
-			 * XXX: ioremapping  MUST be removed once ctrl
+			 * XXX: OMAP343X_CTRL_BASE ioremapping  MUST be removed once ctrl
 			 * function is made available.
 			 */
-			void __iomem *ctrl = ioremap(OMAP343X_CTRL_BASE, SZ_4K);
+			void __iomem *ctrl = ioremap(0x48002000, SZ_4K);
 			if (!ctrl)
 				return -ENOMEM;
 
@@ -1745,7 +1745,7 @@
 	pa_next = page_to_phys(page[0]);
 	while (!status && (i < num_pages)) {
 		/*
-		 * Reuse pa_next from the previous iteraion to avoid
+		 * Reuse pa_next from the previous iteration to avoid
 		 * an extra va2pa call
 		 */
 		pa_curr = pa_next;
diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
index 16a4aaf..dafa6d9 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
@@ -19,7 +19,7 @@
 /*  ----------------------------------- Host OS */
 #include <dspbridge/host_os.h>
 
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
@@ -356,7 +356,7 @@
 		dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
 		return 0;
 	} else if ((dev_context->brd_state == BRD_RUNNING)) {
-		/* Send a prenotificatio to DSP */
+		/* Send a prenotification to DSP */
 		dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
 		sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
 		return 0;
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.c b/drivers/staging/tidspbridge/core/tiomap_io.c
index 7fda10c..f53ed98 100644
--- a/drivers/staging/tidspbridge/core/tiomap_io.c
+++ b/drivers/staging/tidspbridge/core/tiomap_io.c
@@ -16,7 +16,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c
index 453ef74..1dce36f 100644
--- a/drivers/staging/tidspbridge/core/wdt.c
+++ b/drivers/staging/tidspbridge/core/wdt.c
@@ -25,6 +25,7 @@
 #include <dspbridge/host_os.h>
 
 
+#define OMAP34XX_WDT3_BASE 		(0x49000000 + 0x30000)
 #define INT_34XX_WDT3_IRQ 		(36 + NR_IRQS)
 
 static struct dsp_wdt_setting dsp_wdt;
@@ -61,9 +62,9 @@
 
 	dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
 
-	if (dsp_wdt.fclk) {
+	if (!IS_ERR(dsp_wdt.fclk)) {
 		dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
-		if (!dsp_wdt.iclk) {
+		if (IS_ERR(dsp_wdt.iclk)) {
 			clk_put(dsp_wdt.fclk);
 			dsp_wdt.fclk = NULL;
 			ret = -EFAULT;
diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c
index 60d22ea..404af18 100644
--- a/drivers/staging/tidspbridge/dynload/tramp.c
+++ b/drivers/staging/tidspbridge/dynload/tramp.c
@@ -81,7 +81,7 @@
  * Description: Generate a trampoline symbol name (ASCII) using the value
  *	  of the symbol.  This places the new name into the user buffer.
  *	  The name is fixed in length and of the form: __$dbTR__xxxxxxxx
- *	  (where "xxxxxxxx" is the hex value.
+ *	  (where "xxxxxxxx" is the hex value).
  */
 static void priv_tramp_sym_gen_name(u32 value, char *dst)
 {
@@ -414,7 +414,7 @@
 			/*  Copy the symbol contents into the flat table */
 			*new_sym = cur_sym->sym_info;
 
-			/*  Now finaize the symbol.  If it is in the tramp
+			/*  Now finalize the symbol.  If it is in the tramp
 			 * section, we need to adjust for the section start.
 			 * If it is external then we don't need to adjust at
 			 * all.
@@ -773,7 +773,7 @@
 	int ret_val = 0;
 	struct tramp_img_dup_relo *dup_relo = NULL;
 
-	/*  Determinne if this image packet is already being tracked in the
+	/*  Determine if this image packet is already being tracked in the
 	   dup list for other trampolines. */
 	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
 
@@ -998,7 +998,7 @@
 /*
  * Function:	dload_tramp_pkt_update
  * Description: Update the duplicate copy of this image packet, which the
- *	  trampoline layer is already tracking.  This is call is critical
+ *	  trampoline layer is already tracking.  This call is critical
  *	  to make if trampolines were generated anywhere within the
  *	  packet and first pass relo continued on the remainder.  The
  *	  trampoline layer needs the updates image data so when 2nd
diff --git a/drivers/staging/tidspbridge/gen/uuidutil.c b/drivers/staging/tidspbridge/gen/uuidutil.c
index b44656c..b7d8313 100644
--- a/drivers/staging/tidspbridge/gen/uuidutil.c
+++ b/drivers/staging/tidspbridge/gen/uuidutil.c
@@ -26,27 +26,6 @@
 /*  ----------------------------------- This */
 #include <dspbridge/uuidutil.h>
 
-/*
- *  ======== uuid_uuid_to_string ========
- *  Purpose:
- *      Converts a struct dsp_uuid to a string.
- *      Note: snprintf format specifier is:
- *      %[flags] [width] [.precision] [{h | l | I64 | L}]type
- */
-void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
-			 s32 size)
-{
-	s32 i;			/* return result from snprintf. */
-
-	i = snprintf(sz_uuid, size,
-		     "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X",
-		     uuid_obj->data1, uuid_obj->data2, uuid_obj->data3,
-		     uuid_obj->data4, uuid_obj->data5,
-		     uuid_obj->data6[0], uuid_obj->data6[1],
-		     uuid_obj->data6[2], uuid_obj->data6[3],
-		     uuid_obj->data6[4], uuid_obj->data6[5]);
-}
-
 static s32 uuid_hex_to_bin(char *buf, s32 len)
 {
 	s32 i;
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c
index 8a93d55..71cb822 100644
--- a/drivers/staging/tidspbridge/hw/hw_mmu.c
+++ b/drivers/staging/tidspbridge/hw/hw_mmu.c
@@ -61,7 +61,7 @@
  *       Type		: hw_status
  *       Description     : 0		 -- No errors occurred
  *			 RET_BAD_NULL_PARAM     -- A Pointer
- *						Paramater was set to NULL
+ *						Parameter was set to NULL
  *
  * PURPOSE:	      : Flush the TLB entry pointed by the
  *			lock counter register
@@ -103,7 +103,7 @@
  *
  *       Type	    	: hw_status
  *       Description     : 0		 -- No errors occurred
- *			 RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *			 RET_BAD_NULL_PARAM     -- A Pointer Parameter
  *						   was set to NULL
  *			 RET_PARAM_OUT_OF_RANGE -- Input Parameter out
  *						   of Range
@@ -148,7 +148,7 @@
  *
  *       Type	    	: hw_status
  *       Description     : 0		 -- No errors occurred
- *			 RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *			 RET_BAD_NULL_PARAM     -- A Pointer Parameter
  *							was set to NULL
  *			 RET_PARAM_OUT_OF_RANGE -- Input Parameter
  *							out of Range
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
index 0c7ec04..0fcda197 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
@@ -51,7 +51,7 @@
 #define BRDIOCTL_POSTSCALE_NOTIFY (BRDIOCTL_PWRCONTROL + 0xA)
 #define BRDIOCTL_CONSTRAINT_REQUEST (BRDIOCTL_PWRCONTROL + 0xB)
 
-/* Number of actual DSP-MMU TLB entrries */
+/* Number of actual DSP-MMU TLB entries */
 #define BRDIOCTL_NUMOFMMUTLB        32
 
 struct bridge_ioctl_extproc {
diff --git a/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
index 7424c88..d4cb394 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
@@ -22,7 +22,7 @@
  *  mailbox interrupt's cmd value received. The class value are defined
  *  as a bit (10 thru 15) being set.
  *
- *  Note: Only 16 bits of each  is used. Other 16 bit data reg available.
+ *  Note: Only 16 bits of each is used. Other 16 bit data reg available.
  *
  *   16 bit Mbx bit defns:
  *
diff --git a/drivers/staging/tidspbridge/include/dspbridge/node.h b/drivers/staging/tidspbridge/include/dspbridge/node.h
index 7397b7a..68ed74a 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/node.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/node.h
@@ -220,7 +220,7 @@
  *  Parameters:
  *      noderes:              Node resource info handle returned from
  *                                 node_allocate().
- *      pr_ctxt:                Poninter to process context data.
+ *      pr_ctxt:                Pointer to process context data.
  *  Returns:
  *      0:            Success.
  *      -EFAULT:        Invalid hnode.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/ntfy.h b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h
index cbc8819..6bb94d2 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/ntfy.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h
@@ -78,7 +78,7 @@
  * ntfy_delete() - delete list of nofy events registered.
  * @ntfy_obj:	Pointer to the ntfy object structure.
  *
- * This function is used to remove all the notify events  registered.
+ * This function is used to remove all the notify events registered.
  * unregister function is not needed in this function, to unregister
  * a ntfy_event please look at ntfy_register function.
  *
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
index a82380e..851b356 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/proc.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -263,7 +263,7 @@
  *  Returns:
  *      0     :   Success.
  *      -EFAULT :   Invalid processor handle.
- *      -EPERM   :   General failure while retireving processor trace
+ *      -EPERM   :   General failure while retrieving processor trace
  *		      Buffer.
  *  Requires:
  *      pbuf is not NULL
diff --git a/drivers/staging/tidspbridge/include/dspbridge/strm.h b/drivers/staging/tidspbridge/include/dspbridge/strm.h
index dacf0c2..97aee4c 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/strm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/strm.h
@@ -203,7 +203,7 @@
  *      index:         Stream index.
  *      pattr:          Pointer to structure containing attributes to be
  *                      applied to stream. Cannot be NULL.
- *      strmres:     Location to store stream resuorce info handle on output.
+ *      strmres:     Location to store stream resource info handle on output.
  *  Returns:
  *      0:        Success.
  *      -EFAULT:    Invalid hnode.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/sync.h b/drivers/staging/tidspbridge/include/dspbridge/sync.h
index b1e75eb..58a0d5c 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/sync.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/sync.h
@@ -78,7 +78,7 @@
  * @event:	events to wait for it.
  * @timeout	timeout on waiting for the evetn.
  *
- * This functios will wait until @event is set or until timeout. In case of
+ * This function will wait until @event is set or until timeout. In case of
  * success the function will return 0 and
  * in case of timeout the function will return -ETIME
  * in case of signal the function will return -ERESTARTSYS
@@ -106,7 +106,7 @@
  * @timeout	timeout on waiting for the evetns.
  * @pu_index	index of the event set.
  *
- * This functios will wait until any of the array element is set or until
+ * This function will wait until any of the array element is set or until
  * timeout. In case of success the function will return 0 and
  * @pu_index will store the index of the array element set and in case
  * of timeout the function will return -ETIME.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
index 9a99475..414bf71 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
@@ -22,26 +22,6 @@
 #define MAXUUIDLEN  37
 
 /*
- *  ======== uuid_uuid_to_string ========
- *  Purpose:
- *      Converts a dsp_uuid to an ANSI string.
- *  Parameters:
- *      uuid_obj:      Pointer to a dsp_uuid object.
- *      sz_uuid:    Pointer to a buffer to receive a NULL-terminated UUID
- *                  string.
- *      size:	    Maximum size of the sz_uuid string.
- *  Returns:
- *  Requires:
- *      uuid_obj & sz_uuid are non-NULL values.
- *  Ensures:
- *      Lenghth of sz_uuid is less than MAXUUIDLEN.
- *  Details:
- *      UUID string limit currently set at MAXUUIDLEN.
- */
-void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
-			 s32 size);
-
-/*
  *  ======== uuid_uuid_from_string ========
  *  Purpose:
  *      Converts an ANSI string to a dsp_uuid.
diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c
index 12a1d34..9d52c3c 100644
--- a/drivers/staging/tidspbridge/rmgr/dbdcd.c
+++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c
@@ -346,11 +346,13 @@
 	struct dcd_manager *dcd_mgr_obj = hdcd_mgr;	/* ptr to DCD mgr */
 	struct cod_libraryobj *lib = NULL;
 	int status = 0;
+	int len;
 	u32 ul_addr = 0;	/* Used by cod_get_section */
 	u32 ul_len = 0;		/* Used by cod_get_section */
 	u32 dw_buf_size;	/* Used by REG functions */
 	char sz_reg_key[DCD_MAXPATHLENGTH];
 	char *sz_uuid;		/*[MAXUUIDLEN]; */
+	char *tmp;
 	struct dcd_key_elem *dcd_key = NULL;
 	char sz_sect_name[MAXUUIDLEN + 2];	/* ".[UUID]\0" */
 	char *psz_coff_buf;
@@ -395,7 +397,7 @@
 		}
 
 		/* Create UUID value to set in registry. */
-		uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
+		snprintf(sz_uuid, MAXUUIDLEN, "%pUL", obj_uuid);
 
 		if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
 			strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
@@ -429,12 +431,27 @@
 	}
 
 	/* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
+	len = strlen(sz_uuid);
+	if (len + 1 > sizeof(sz_sect_name)) {
+		status = -EPERM;
+		goto func_end;
+	}
 
 	/* Create section name based on node UUID. A period is
 	 * pre-pended to the UUID string to form the section name.
 	 * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
+
+	len -= 4;	/* uuid has 4 delimiters '-' */
+	tmp = sz_uuid;
+
 	strncpy(sz_sect_name, ".", 2);
-	strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
+	do {
+		char *uuid = strsep(&tmp, "-");
+		if (!uuid)
+			break;
+		len -= strlen(uuid);
+		strncat(sz_sect_name, uuid, strlen(uuid) + 1);
+	} while (len && strncat(sz_sect_name, "_", 2));
 
 	/* Get section information. */
 	status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
@@ -463,7 +480,7 @@
 	status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
 #endif
 	if (!status) {
-		/* Compres DSP buffer to conform to PC format. */
+		/* Compress DSP buffer to conform to PC format. */
 		if (strstr(dcd_key->path, "iva") == NULL) {
 			compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
 		} else {
@@ -666,7 +683,7 @@
 			status = -EPERM;
 		}
 		/* Create UUID value to find match in registry. */
-		uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+		snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
 		if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
 			strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
 		else
@@ -706,7 +723,7 @@
 		} else {
 			status = -EPERM;
 		}
-		uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+		snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
 		if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
 			strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
 		else
@@ -797,7 +814,7 @@
 			status = -EPERM;
 
 		/* Create UUID value to set in registry. */
-		uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+		snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
 		if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
 			strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
 		else
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c
index 3cac014..bddea1d 100644
--- a/drivers/staging/tidspbridge/rmgr/drv_interface.c
+++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c
@@ -16,7 +16,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <plat/dsp.h>
+#include <linux/platform_data/dsp-omap.h>
 
 #include <linux/types.h>
 #include <linux/platform_device.h>
@@ -613,16 +613,6 @@
 #endif
 };
 
-static int __init bridge_init(void)
-{
-	return platform_driver_register(&bridge_driver);
-}
-
-static void __exit bridge_exit(void)
-{
-	platform_driver_unregister(&bridge_driver);
-}
-
 /* To remove all process resources before removing the process from the
  * process context list */
 int drv_remove_all_resources(void *process_ctxt)
@@ -636,6 +626,4 @@
 	return status;
 }
 
-/* Bridge driver initialization and de-initialization functions */
-module_init(bridge_init);
-module_exit(bridge_exit);
+module_platform_driver(bridge_driver);
diff --git a/drivers/staging/tidspbridge/rmgr/dspdrv.c b/drivers/staging/tidspbridge/rmgr/dspdrv.c
index dc767b1..d460f58 100644
--- a/drivers/staging/tidspbridge/rmgr/dspdrv.c
+++ b/drivers/staging/tidspbridge/rmgr/dspdrv.c
@@ -72,7 +72,7 @@
 
 	/* Unwind whatever was loaded */
 	if (status) {
-		/* irrespective of the status of dev_remove_device we conitinue
+		/* irrespective of the status of dev_remove_device we continue
 		 * unloading. Get the Driver Object iterate through and remove.
 		 * Reset the status to E_FAIL to avoid going through
 		 * api_init_complete2. */
@@ -92,7 +92,7 @@
 func_cont:
 	/* Attempt to Start the Board */
 	if (!status) {
-		/* BRD_AutoStart could fail if the dsp execuetable is not the
+		/* BRD_AutoStart could fail if the dsp executable is not the
 		 * correct one. We should not propagate that error
 		 * into the device loader. */
 		(void)api_init_complete2();
diff --git a/drivers/staging/tidspbridge/rmgr/mgr.c b/drivers/staging/tidspbridge/rmgr/mgr.c
index 8a1e928..b32ba0a 100644
--- a/drivers/staging/tidspbridge/rmgr/mgr.c
+++ b/drivers/staging/tidspbridge/rmgr/mgr.c
@@ -262,8 +262,8 @@
 				    IVAPROCTYPE_ARM7)
 					proc_detect = true;
 			}
-			/* User applciatiuons aonly check for chip type, so
-			 * this clumsy overwrite */
+			/* User applications only check for chip type, so
+			 * this is a clumsy overwrite */
 			processor_info->processor_type = DSPTYPE64;
 		} else {
 			dev_dbg(bridge, "%s: Failed to get DCD processor info "
diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c
index 30d5480..6309221b 100644
--- a/drivers/staging/tidspbridge/rmgr/nldr.c
+++ b/drivers/staging/tidspbridge/rmgr/nldr.c
@@ -898,7 +898,7 @@
 				nldr_obj->ovly_table[i].execute_sects++;
 
 		} else {
-			/* Put in "other" sectins */
+			/* Put in "other" sections */
 			status =
 			    add_ovly_sect(nldr_obj,
 					  &nldr_obj->
diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c
index 7fb426c..c2fc613 100644
--- a/drivers/staging/tidspbridge/rmgr/node.c
+++ b/drivers/staging/tidspbridge/rmgr/node.c
@@ -1613,7 +1613,7 @@
 		return -EFAULT;
 
 	hnode_mgr = hnode->node_mgr;
-	/* Enter hnode_mgr critical section (since we're accessing
+	/* Enter hnode_mgr critical section since we're accessing
 	 * data that could be changed by node_change_priority() and
 	 * node_connect(). */
 	mutex_lock(&hnode_mgr->node_mgr_lock);
@@ -2714,8 +2714,7 @@
 		hnode->ntype = node_type = pndb_props->ntype;
 
 		/* Create UUID value to set in registry. */
-		uuid_uuid_to_string((struct dsp_uuid *)node_uuid, sz_uuid,
-				    MAXUUIDLEN);
+		snprintf(sz_uuid, MAXUUIDLEN, "%pUL", node_uuid);
 		dev_dbg(bridge, "(node) UUID: %s\n", sz_uuid);
 
 		/* Fill in message args that come from NDB */
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
index 7e4f12f..5e43938 100644
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -300,7 +300,7 @@
 	if (status)
 		goto func_end;
 
-	/* If we made it this far, create the Proceesor object: */
+	/* If we made it this far, create the Processor object: */
 	p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
 	/* Fill out the Processor Object: */
 	if (p_proc_object == NULL) {
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
index dd13c02..199b1d4 100644
--- a/drivers/staging/usbip/Kconfig
+++ b/drivers/staging/usbip/Kconfig
@@ -1,6 +1,6 @@
 config USBIP_CORE
-	tristate "USB/IP support (EXPERIMENTAL)"
-	depends on USB && NET && EXPERIMENTAL
+	tristate "USB/IP support"
+	depends on USB && NET
 	default N
 	---help---
 	  This enables pushing USB packets over IP to allow remote
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 92ced35..c8d79a7 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -187,10 +187,14 @@
 	}
 
 	/* 1. stop threads */
-	if (ud->tcp_rx)
+	if (ud->tcp_rx) {
 		kthread_stop_put(ud->tcp_rx);
-	if (ud->tcp_tx)
+		ud->tcp_rx = NULL;
+	}
+	if (ud->tcp_tx) {
 		kthread_stop_put(ud->tcp_tx);
+		ud->tcp_tx = NULL;
+	}
 
 	/*
 	 * 2. close the socket
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 1d5b3fc..694cfd7 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -155,7 +155,7 @@
 	 * eventually reassigned to the device as far as driver matching
 	 * condition is kept.
 	 *
-	 * Unfortunatelly, an existing usbip connection will be dropped
+	 * Unfortunately, an existing usbip connection will be dropped
 	 * due to this driver unbinding. So, skip here.
 	 * A user may need to set a special configuration value before
 	 * exporting the device.
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 70f23026..57f11f9 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -22,7 +22,9 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <net/sock.h>
 
 #include "usbip_common.h"
@@ -36,6 +38,8 @@
 unsigned long usbip_debug_flag;
 #endif
 EXPORT_SYMBOL_GPL(usbip_debug_flag);
+module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)");
 
 /* FIXME */
 struct device_attribute dev_attr_usbip_debug;
@@ -157,8 +161,7 @@
 	dev_dbg(dev, "have_langid %d, string_langid %d\n",
 		udev->have_langid, udev->string_langid);
 
-	dev_dbg(dev, "maxchild %d, children %p\n",
-		udev->maxchild, udev->children);
+	dev_dbg(dev, "maxchild %d\n", udev->maxchild);
 }
 
 static void usbip_dump_request_type(__u8 rt)
diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac
index bf5cf49..43e641e 100644
--- a/drivers/staging/usbip/userspace/configure.ac
+++ b/drivers/staging/usbip/userspace/configure.ac
@@ -56,11 +56,11 @@
 	    [AS_HELP_STRING([--with-tcp-wrappers],
 			    [use the libwrap (TCP wrappers) library])],
 	    dnl [ACTION-IF-GIVEN]
-	    [saved_LIBS="$LIBS"
-	     if test "$withval" = "yes"; then
+	    [if test "$withval" = "yes"; then
 		     AC_MSG_RESULT([yes])
 		     AC_MSG_CHECKING([for hosts_access in -lwrap])
-		     LIBS="-lwrap $LIBS"
+		     saved_LIBS="$LIBS"
+		     LIBS="-lwrap $saved_LIBS"
 		     AC_TRY_LINK(
 		       [int hosts_access(); int allow_severity, deny_severity;],
 		       [hosts_access()],
@@ -69,9 +69,9 @@
 				  [use tcp wrapper]) wrap_LIB="-lwrap"],
 		       [AC_MSG_RESULT([not found]); exit 1])
 	     else
-		     AC_MSG_RESULT([no])
-	     fi
-	     LIBS="$saved_LIBS"],
+		     AC_MSG_RESULT([no]);
+		     LIBS="$saved_LIBS"
+	     fi],
 	    dnl [ACTION-IF-NOT-GIVEN]
 	    [AC_MSG_RESULT([(default)])
 	     AC_MSG_CHECKING([for hosts_access in -lwrap])
diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8
index 1653bb2..6e0d745 100644
--- a/drivers/staging/usbip/userspace/doc/usbip.8
+++ b/drivers/staging/usbip/userspace/doc/usbip.8
@@ -3,69 +3,87 @@
 usbip \- manage USB/IP devices
 .SH SYNOPSIS
 .B usbip
-[\fIoptions\fR]
+[\foptions\R] <\fIcommand\fR> <\fIargs\fR>
 
 .SH DESCRIPTION
-Devices exported by USB/IP servers can be listed, attached and
-detached using this program.
+On a USB/IP server, devices can be listed, bound, and unbound using
+this program.  On a USB/IP client, devices exported by USB/IP servers
+can be listed, attached and detached.
 
 .SH OPTIONS
 .HP
-\fB\-a\fR, \fB\-\-attach\fR <host> <bus_id>
-.IP
-Attach a remote USB device.
-.PP
-
-.HP
-\fB\-x\fR, \fB\-\-attachall\fR <host>
-.IP
-Attach all remote USB devices on the specific host.
-.PP
-
-.HP
-\fB\-d\fR, \fB\-\-detach\fR <ports>
-.IP
-Detach an imported USB device.
-.PP
-
-.HP
-\fB\-l\fR, \fB\-\-list\fR <hosts>
-.IP
-List exported USB devices.
-.PP
-
-.HP
-\fB\-p\fR, \fB\-\-port\fR
-.IP
-List virtual USB port status.
-.PP
-
-.HP
-\fB\-D\fR, \fB\-\-debug\fR
+\fB\-\-debug\fR
 .IP
 Print debugging information.
 .PP
 
 .HP
-\fB\-v\fR, \fB\-\-version\fR
+\fB\-\-log\fR
 .IP
-Show version.
+Log to syslog.
 .PP
 
+.SH COMMANDS
+.HP
+\fBversion\fR
+.IP
+Show version and exit.
+.PP
+
+.HP
+\fBhelp\fR [\fIcommand\fR]
+.IP
+Print the program help message, or help on a specific command, and
+then exit.
+.PP
+
+.HP
+\fBattach\fR \-\-host=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
+.IP
+Attach a remote USB device.
+.PP
+
+.HP
+\fBdetach\fR \-\-port=<\fIport\fR>
+.IP
+Detach an imported USB device.
+.PP
+
+.HP
+\fBbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Make a device exportable.
+.PP
+
+.HP
+\fBunbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Stop exporting a device so it can be used by a local driver.
+.PP
+
+.HP
+\fBlist\fR \-\-remote=<\fIhost\fR>
+.IP
+List USB devices exported by a remote host.
+.PP
+
+.HP
+\fBlist\fR \-\-local
+.IP
+List local USB devices.
+.PP
+
+
 .SH EXAMPLES
 
-    client:# usbip --list server
+    client:# usbip list --remote=server
         - List exportable usb devices on the server.
 
-    client:# usbip --attach server 1-2
+    client:# usbip attach --host=server --busid=1-2
         - Connect the remote USB device.
 
-    client:# usbip --port
-        - Show virtual port status.
-
-    client:# usbip --detach 0
+    client:# usbip detach --port=0
         - Detach the usb device.
 
 .SH "SEE ALSO"
-\fBusbipd\fP\fB(8)\fB\fP,
-\fBusbip_attach_driver\fP\fB(8)\fB\fP
+\fBusbipd\fP\fB(8)\fB\fP
diff --git a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 b/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8
deleted file mode 100644
index d43bbd6..0000000
--- a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8
+++ /dev/null
@@ -1,42 +0,0 @@
-.TH USBIP_BIND_DRIVER "8" "February 2009" "usbip" "System Administration Utilities"
-.SH NAME
-usbip_bind_driver \- change driver binding for USB/IP
-
-.SH SYNOPSIS
-.B usbip_bind_driver
-[\fIoptions\fR]
-
-.SH DESCRIPTION
-Driver bindings for USB devices can be changed using
-this program. It is used to export and unexport USB
-devices over USB/IP.
-
-.SH OPTIONS
-.TP
-\fB\-u\fR, \fB\-\-usbip\fR <busid>
-Make a device exportable
-.TP
-\fB\-o\fR, \fB\-\-other\fR <busid>
-Use a device by a local driver
-.TP
-\fB\-l\fR, \fB\-\-list\fR
-Print usb devices and their drivers
-.TP
-\fB\-L\fR, \fB\-\-list2\fR
-Print usb devices and their drivers in parseable mode
-
-.SH EXAMPLES
-
-    server:# usbip_bind_driver --list
-        - List driver assignments for usb devices.
-
-    server:# usbip_bind_driver --usbip 1-2
-        - Bind usbip-host.ko to the device of busid 1-2.
-        - A usb device 1-2 is now exportable to other hosts!
-
-    server:# usbip_bind_driver --other 1-2
-        - Shutdown exporting and use the device locally.
-
-.SH "SEE ALSO"
-\fBusbip\fP\fB(8)\fB\fP,
-\fBusbipd\fP\fB(8)\fB\fP
diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8
index 006559f..d896936 100644
--- a/drivers/staging/usbip/userspace/doc/usbipd.8
+++ b/drivers/staging/usbip/userspace/doc/usbipd.8
@@ -10,7 +10,7 @@
 provides USB/IP clients access to exported USB devices.
 
 Devices have to explicitly be exported using
-.B usbip_bind_driver
+.B usbip bind
 before usbipd makes them available to other hosts.
 
 The daemon accepts connections from USB/IP clients
@@ -29,6 +29,11 @@
 Print debugging information.
 .PP
 
+\fB\-h\fR, \fB\-\-help\fR
+.IP
+Print the program help message and exit.
+.PP
+
 .HP
 \fB\-v\fR, \fB\-\-version\fR
 .IP
@@ -48,15 +53,14 @@
     server:# usbipd -D
         - Start usbip daemon.
 
-    server:# usbip_bind_driver --list
+    server:# usbip list --local
         - List driver assignments for usb devices.
 
-    server:# usbip_bind_driver --usbip 1-2
+    server:# usbip bind --busid=1-2
         - Bind usbip-host.ko to the device of busid 1-2.
         - A usb device 1-2 is now exportable to other hosts!
-        - Use 'usbip_bind_driver --other 1-2' when you want to shutdown exporting and use the device locally.
+        - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally.
 
 .SH "SEE ALSO"
-\fBusbip\fP\fB(8)\fB\fP,
-\fBusbip_attach_driver\fP\fB(8)\fB\fP
+\fBusbip\fP\fB(8)\fB\fP
 
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 12a9a5f..620d1be 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -220,7 +220,7 @@
 
 	pr_info("changed %d\n", changed);
 
-	if (hcd->state == HC_STATE_SUSPENDED)
+	if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1))
 		usb_hcd_resume_root_hub(hcd);
 
 done:
@@ -749,6 +749,7 @@
 {
 	struct vhci_unlink *unlink, *tmp;
 
+	spin_lock(&the_controller->lock);
 	spin_lock(&vdev->priv_lock);
 
 	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
@@ -757,9 +758,12 @@
 		kfree(unlink);
 	}
 
-	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+	while (!list_empty(&vdev->unlink_rx)) {
 		struct urb *urb;
 
+		unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink,
+			list);
+
 		/* give back URB of unanswered unlink request */
 		pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
 
@@ -774,18 +778,24 @@
 
 		urb->status = -ENODEV;
 
-		spin_lock(&the_controller->lock);
 		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+
+		list_del(&unlink->list);
+
+		spin_unlock(&vdev->priv_lock);
 		spin_unlock(&the_controller->lock);
 
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
 				     urb->status);
 
-		list_del(&unlink->list);
+		spin_lock(&the_controller->lock);
+		spin_lock(&vdev->priv_lock);
+
 		kfree(unlink);
 	}
 
 	spin_unlock(&vdev->priv_lock);
+	spin_unlock(&the_controller->lock);
 }
 
 /*
@@ -804,11 +814,14 @@
 	}
 
 	/* kill threads related to this sdev, if v.c. exists */
-	if (vdev->ud.tcp_rx)
+	if (vdev->ud.tcp_rx) {
 		kthread_stop_put(vdev->ud.tcp_rx);
-	if (vdev->ud.tcp_tx)
+		vdev->ud.tcp_rx = NULL;
+	}
+	if (vdev->ud.tcp_tx) {
 		kthread_stop_put(vdev->ud.tcp_tx);
-
+		vdev->ud.tcp_tx = NULL;
+	}
 	pr_info("stop threads\n");
 
 	/* active connection is closed */
@@ -828,11 +841,11 @@
 	 *	disable endpoints. pending urbs are unlinked(dequeued).
 	 *
 	 * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
-	 * deteched device should release used urbs in a cleanup function(i.e.
+	 * detached device should release used urbs in a cleanup function (i.e.
 	 * xxx_disconnect()). Therefore, vhci_hcd does not need to release
 	 * pushed urbs and their private data in this function.
 	 *
-	 * NOTE: vhci_dequeue() must be considered carefully. When shutdowning
+	 * NOTE: vhci_dequeue() must be considered carefully. When shutting down
 	 * a connection, vhci_shutdown_connection() expects vhci_dequeue()
 	 * gives back pushed urbs and frees their private data by request of
 	 * the cleanup function of a USB driver. When unlinking a urb with an
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c
index 4bf8e05..dad8281 100644
--- a/drivers/staging/vme/devices/vme_pio2_core.c
+++ b/drivers/staging/vme/devices/vme_pio2_core.c
@@ -10,6 +10,8 @@
  * option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -163,15 +165,13 @@
 	int retval = 0;
 
 	if (bus_num == 0) {
-		printk(KERN_ERR "%s: No cards, skipping registration\n",
-			driver_name);
+		pr_err("No cards, skipping registration\n");
 		goto err_nocard;
 	}
 
 	if (bus_num > PIO2_CARDS_MAX) {
-		printk(KERN_ERR
-			"%s: Driver only able to handle %d PIO2 Cards\n",
-			driver_name, PIO2_CARDS_MAX);
+		pr_err("Driver only able to handle %d PIO2 Cards\n",
+		       PIO2_CARDS_MAX);
 		bus_num = PIO2_CARDS_MAX;
 	}
 
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index e25645e..c3f94f3 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -64,13 +64,13 @@
  *
  * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't
  * even support the tsi148 chipset (which has 8 master and 8 slave windows).
- * We'll run with this or now as far as possible, however it probably makes
+ * We'll run with this for now as far as possible, however it probably makes
  * sense to get rid of the old mappings and just do everything dynamically.
  *
  * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as
  * defined above and try to support at least some of the interface from
- * http://www.vmelinux.org/ as an alternative drive can be written providing a
- * saner interface later.
+ * http://www.vmelinux.org/ as an alternative the driver can be written
+ * providing a saner interface later.
  *
  * The vmelinux.org driver never supported slave images, the devices reserved
  * for slaves were repurposed to support all 8 master images on the UniverseII!
@@ -242,7 +242,7 @@
 }
 
 /*
- * We are going ot alloc a page during init per window for small transfers.
+ * We are going to alloc a page during init per window for small transfers.
  * Small transfers will go user space -> buffer -> VME. Larger (more than a
  * page) transfers will lock the user space buffer into memory and then
  * transfer the data directly from the user space buffers out to VME.
@@ -396,7 +396,7 @@
 	default:
 		retval = -EINVAL;
 	}
-	
+
 	mutex_unlock(&image[minor].mutex);
 
 	if (retval > 0)
diff --git a/drivers/staging/vt6655/80211mgr.h b/drivers/staging/vt6655/80211mgr.h
index 3bdab3f..65780f2 100644
--- a/drivers/staging/vt6655/80211mgr.h
+++ b/drivers/staging/vt6655/80211mgr.h
@@ -186,7 +186,7 @@
 
 
 //
-// Cipher Suite Selectors defiened in 802.11i
+// Cipher Suite Selectors defined in 802.11i
 //
 #define WLAN_11i_CSS_USE_GROUP              0
 #define WLAN_11i_CSS_WEP40                  1
diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c
index e7b93a2..8d2c6a7 100644
--- a/drivers/staging/vt6655/baseband.c
+++ b/drivers/staging/vt6655/baseband.c
@@ -28,8 +28,8 @@
  * Functions:
  *      BBuGetFrameTime        - Calculate data frame transmitting time
  *      BBvCaculateParameter   - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
- *      BBbReadEmbeded         - Embeded read baseband register via MAC
- *      BBbWriteEmbeded        - Embeded write baseband register via MAC
+ *      BBbReadEmbedded         - Embedded read baseband register via MAC
+ *      BBbWriteEmbedded        - Embedded write baseband register via MAC
  *      BBbIsRegBitsOn         - Test if baseband register bits on
  *      BBbIsRegBitsOff        - Test if baseband register bits off
  *      BBbVT3253Init          - VIA VT3253 baseband chip init code
@@ -40,7 +40,7 @@
  * Revision History:
  *      06-10-2003 Bryan YC Fan:  Re-write codes to support VT3253 spec.
  *      08-07-2003 Bryan YC Fan:  Add MAXIM2827/2825 and RFMD2959 support.
- *      08-26-2003 Kyle Hsu    :  Modify BBuGetFrameTime() and BBvCaculateParameter().
+ *      08-26-2003 Kyle Hsu    :  Modify BBuGetFrameTime() and BBvCalculateParameter().
  *                                cancel the setting of MAC_REG_SOFTPWRCTL on BBbVT3253Init().
  *                                Add the comments.
  *      09-01-2003 Bryan YC Fan:  RF & BB tables updated.
@@ -1826,7 +1826,7 @@
 }
 
 /*
- * Description: Caculate Length, Service, and Signal fields of Phy for Tx
+ * Description: Calculate Length, Service, and Signal fields of Phy for Tx
  *
  * Parameters:
  *  In:
@@ -1842,7 +1842,7 @@
  *
  */
 void
-BBvCaculateParameter (
+BBvCalculateParameter (
     PSDevice pDevice,
     unsigned int cbFrameLength,
     unsigned short wRate,
@@ -2001,7 +2001,7 @@
 }
 
 /*
- * Description: Read a byte from BASEBAND, by embeded programming
+ * Description: Read a byte from BASEBAND, by embedded programming
  *
  * Parameters:
  *  In:
@@ -2013,7 +2013,7 @@
  * Return Value: true if succeeded; false if failed.
  *
  */
-bool BBbReadEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData)
+bool BBbReadEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData)
 {
     unsigned short ww;
     unsigned char byValue;
@@ -2043,7 +2043,7 @@
 
 
 /*
- * Description: Write a Byte to BASEBAND, by embeded programming
+ * Description: Write a Byte to BASEBAND, by embedded programming
  *
  * Parameters:
  *  In:
@@ -2056,7 +2056,7 @@
  * Return Value: true if succeeded; false if failed.
  *
  */
-bool BBbWriteEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData)
+bool BBbWriteEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData)
 {
     unsigned short ww;
     unsigned char byValue;
@@ -2102,7 +2102,7 @@
 {
     unsigned char byOrgData;
 
-    BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData);
+    BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
     return (byOrgData & byTestBits) == byTestBits;
 }
 
@@ -2125,7 +2125,7 @@
 {
     unsigned char byOrgData;
 
-    BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData);
+    BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
     return (byOrgData & byTestBits) == 0;
 }
 
@@ -2155,14 +2155,14 @@
     if (byRFType == RF_RFMD2959) {
         if (byLocalID <= REV_ID_VT3253_A1) {
             for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) {
-                bResult &= BBbWriteEmbeded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]);
+                bResult &= BBbWriteEmbedded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]);
             }
         } else {
             for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) {
-                bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]);
+                bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]);
             }
             for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) {
-        	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]);
+        	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]);
             }
             VNSvOutPortD(dwIoBase + MAC_REG_ITRTMSET, 0x23);
             MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
@@ -2177,10 +2177,10 @@
         pDevice->ldBmThreshold[3] = 0;
     } else if ((byRFType == RF_AIROHA) || (byRFType == RF_AL2230S) ) {
         for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
     	}
         for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
     	}
         pDevice->abyBBVGA[0] = 0x1C;
         pDevice->abyBBVGA[1] = 0x10;
@@ -2192,10 +2192,10 @@
         pDevice->ldBmThreshold[3] = 0;
     } else if (byRFType == RF_UW2451) {
         for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
-    	        bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
+    	        bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
     	}
         for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
     	}
         VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23);
         MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
@@ -2210,28 +2210,28 @@
         pDevice->ldBmThreshold[3] = 0;
     } else if (byRFType == RF_UW2452) {
         for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
-            bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
+            bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
     	}
         // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
-        //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41);
+        //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
         // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
-        //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28);
+        //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
         // Select VC1/VC2, CR215 = 0x02->0x06
-        bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06);
+        bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06);
 
         //{{RobertYu:20050125, request by Jack
-        bResult &= BBbWriteEmbeded(dwIoBase,0x90,0x20);
-        bResult &= BBbWriteEmbeded(dwIoBase,0x97,0xeb);
+        bResult &= BBbWriteEmbedded(dwIoBase,0x90,0x20);
+        bResult &= BBbWriteEmbedded(dwIoBase,0x97,0xeb);
         //}}
 
         //{{RobertYu:20050221, request by Jack
-        bResult &= BBbWriteEmbeded(dwIoBase,0xa6,0x00);
-        bResult &= BBbWriteEmbeded(dwIoBase,0xa8,0x30);
+        bResult &= BBbWriteEmbedded(dwIoBase,0xa6,0x00);
+        bResult &= BBbWriteEmbedded(dwIoBase,0xa8,0x30);
         //}}
-        bResult &= BBbWriteEmbeded(dwIoBase,0xb0,0x58);
+        bResult &= BBbWriteEmbedded(dwIoBase,0xb0,0x58);
 
         for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
     	}
         //VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); // RobertYu: 20050104, 20050131 disable PA_Delay
         //MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); // RobertYu: 20050104, 20050131 disable PA_Delay
@@ -2248,10 +2248,10 @@
 
     } else if (byRFType == RF_VT3226) {
         for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
     	}
         for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
     	}
         pDevice->abyBBVGA[0] = 0x1C;
         pDevice->abyBBVGA[1] = 0x10;
@@ -2266,20 +2266,20 @@
          //{{ RobertYu: 20050104
     } else if (byRFType == RF_AIROHA7230) {
         for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
     	}
 
         //{{ RobertYu:20050223, request by JerryChung
         // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
-        //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41);
+        //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
         // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
-        //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28);
+        //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
         // Select VC1/VC2, CR215 = 0x02->0x06
-        bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06);
+        bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06);
         //}}
 
         for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
-    	    bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
+    	    bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
     	}
         pDevice->abyBBVGA[0] = 0x1C;
         pDevice->abyBBVGA[1] = 0x10;
@@ -2297,8 +2297,8 @@
     }
 
     if (byLocalID > REV_ID_VT3253_A1) {
-        BBbWriteEmbeded(dwIoBase, 0x04, 0x7F);
-        BBbWriteEmbeded(dwIoBase, 0x0D, 0x01);
+        BBbWriteEmbedded(dwIoBase, 0x04, 0x7F);
+        BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);
     }
 
     return bResult;
@@ -2324,7 +2324,7 @@
     int  ii;
     unsigned char byBase = 1;
     for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) {
-        BBbReadEmbeded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs);
+        BBbReadEmbedded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs);
         pbyBBRegs += byBase;
     }
 }
@@ -2350,39 +2350,39 @@
     unsigned long dwIoBase = pDevice->PortOffset;
 
     //CR C9 = 0x00
-    BBbReadEmbeded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201
-    BBbWriteEmbeded(dwIoBase, 0xC9, 0);
-    BBbReadEmbeded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77
-    BBbWriteEmbeded(dwIoBase, 0x4D, 0x90);
+    BBbReadEmbedded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201
+    BBbWriteEmbedded(dwIoBase, 0xC9, 0);
+    BBbReadEmbedded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77
+    BBbWriteEmbedded(dwIoBase, 0x4D, 0x90);
 
     //CR 88 = 0x02(CCK), 0x03(OFDM)
-    BBbReadEmbeded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136
+    BBbReadEmbedded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136
 
     if (pDevice->uConnectionRate <= RATE_11M) { //CCK
         // Enable internal digital loopback: CR33 |= 0000 0001
-        BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33
-        BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33
+        BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
+        BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33
         // CR154 = 0x00
-        BBbWriteEmbeded(dwIoBase, 0x9A, 0);   //CR154
+        BBbWriteEmbedded(dwIoBase, 0x9A, 0);   //CR154
 
-        BBbWriteEmbeded(dwIoBase, 0x88, 0x02);//CR239
+        BBbWriteEmbedded(dwIoBase, 0x88, 0x02);//CR239
     }
     else { //OFDM
         // Enable internal digital loopback:CR154 |= 0000 0001
-        BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154
-        BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154
+        BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
+        BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154
         // CR33 = 0x00
-        BBbWriteEmbeded(dwIoBase, 0x21, 0);   //CR33
+        BBbWriteEmbedded(dwIoBase, 0x21, 0);   //CR33
 
-        BBbWriteEmbeded(dwIoBase, 0x88, 0x03);//CR239
+        BBbWriteEmbedded(dwIoBase, 0x88, 0x03);//CR239
     }
 
     //CR14 = 0x00
-    BBbWriteEmbeded(dwIoBase, 0x0E, 0);//CR14
+    BBbWriteEmbedded(dwIoBase, 0x0E, 0);//CR14
 
     // Disable TX_IQUN
-    BBbReadEmbeded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09);
-    BBbWriteEmbeded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE));
+    BBbReadEmbedded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09);
+    BBbWriteEmbedded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE));
 }
 
 /*
@@ -2403,22 +2403,22 @@
     unsigned char byData;
     unsigned long dwIoBase = pDevice->PortOffset;
 
-    BBbWriteEmbeded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201
-    BBbWriteEmbeded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136
-    BBbWriteEmbeded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136
-    BBbWriteEmbeded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77
+    BBbWriteEmbedded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201
+    BBbWriteEmbedded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136
+    BBbWriteEmbedded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136
+    BBbWriteEmbedded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77
 
     if (pDevice->uConnectionRate <= RATE_11M) { // CCK
         // Set the CR33 Bit2 to disable internal Loopback.
-        BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33
-        BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33
+        BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
+        BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33
     }
     else { // OFDM
-        BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154
-        BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154
+        BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
+        BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154
     }
-    BBbReadEmbeded(dwIoBase, 0x0E, &byData);//CR14
-    BBbWriteEmbeded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14
+    BBbReadEmbedded(dwIoBase, 0x0E, &byData);//CR14
+    BBbWriteEmbedded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14
 
 }
 
@@ -2442,7 +2442,7 @@
     unsigned char byBBRxConf=0;
     unsigned char byBBVGA=0;
 
-    BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
+    BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
 
     if (pDevice->bShortSlotTime) {
         byBBRxConf &= 0xDF;//1101 1111
@@ -2451,12 +2451,12 @@
     }
 
     // patch for 3253B0 Baseband with Cardbus module
-    BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byBBVGA);
+    BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byBBVGA);
     if (byBBVGA == pDevice->abyBBVGA[0]) {
         byBBRxConf |= 0x20;//0010 0000
     }
 
-    BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
+    BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
 
 }
 
@@ -2464,9 +2464,9 @@
 {
     unsigned char byBBRxConf=0;
 
-    BBbWriteEmbeded(pDevice->PortOffset, 0xE7, byData);
+    BBbWriteEmbedded(pDevice->PortOffset, 0xE7, byData);
 
-    BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
+    BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
     // patch for 3253B0 Baseband with Cardbus module
     if (byData == pDevice->abyBBVGA[0]) {
         byBBRxConf |= 0x20;//0010 0000
@@ -2476,7 +2476,7 @@
         byBBRxConf |= 0x20;//0010 0000
     }
     pDevice->byBBVGACurrent = byData;
-    BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
+    BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
 }
 
 
@@ -2495,10 +2495,10 @@
 void
 BBvSoftwareReset (unsigned long dwIoBase)
 {
-    BBbWriteEmbeded(dwIoBase, 0x50, 0x40);
-    BBbWriteEmbeded(dwIoBase, 0x50, 0);
-    BBbWriteEmbeded(dwIoBase, 0x9C, 0x01);
-    BBbWriteEmbeded(dwIoBase, 0x9C, 0);
+    BBbWriteEmbedded(dwIoBase, 0x50, 0x40);
+    BBbWriteEmbedded(dwIoBase, 0x50, 0);
+    BBbWriteEmbedded(dwIoBase, 0x9C, 0x01);
+    BBbWriteEmbedded(dwIoBase, 0x9C, 0);
 }
 
 /*
@@ -2518,9 +2518,9 @@
 {
     unsigned char byOrgData;
 
-    BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData);
+    BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
     byOrgData |= BIT0;
-    BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData);
+    BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
 }
 
 /*
@@ -2540,9 +2540,9 @@
 {
     unsigned char byOrgData;
 
-    BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData);
+    BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
     byOrgData &= ~(BIT0);
-    BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData);
+    BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
 }
 
 /*
@@ -2567,7 +2567,7 @@
 #ifdef	PLICE_DEBUG
 	//printk("Enter BBvSetTxAntennaMode\n");
 #endif
-    BBbReadEmbeded(dwIoBase, 0x09, &byBBTxConf);//CR09
+    BBbReadEmbedded(dwIoBase, 0x09, &byBBTxConf);//CR09
     if (byAntennaMode == ANT_DIVERSITY) {
         // bit 1 is diversity
         byBBTxConf |= 0x02;
@@ -2581,7 +2581,7 @@
         byBBTxConf &= 0xFD; // 1111 1101
         byBBTxConf |= 0x04;
     }
-    BBbWriteEmbeded(dwIoBase, 0x09, byBBTxConf);//CR09
+    BBbWriteEmbedded(dwIoBase, 0x09, byBBTxConf);//CR09
 }
 
 
@@ -2606,7 +2606,7 @@
 {
     unsigned char byBBRxConf;
 
-    BBbReadEmbeded(dwIoBase, 0x0A, &byBBRxConf);//CR10
+    BBbReadEmbedded(dwIoBase, 0x0A, &byBBRxConf);//CR10
     if (byAntennaMode == ANT_DIVERSITY) {
         byBBRxConf |= 0x01;
 
@@ -2616,7 +2616,7 @@
         byBBRxConf &= 0xFE; // 1111 1110
         byBBRxConf |= 0x02;
     }
-    BBbWriteEmbeded(dwIoBase, 0x0A, byBBRxConf);//CR10
+    BBbWriteEmbedded(dwIoBase, 0x0A, byBBRxConf);//CR10
 }
 
 
@@ -2635,15 +2635,15 @@
 void
 BBvSetDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
 {
-    BBbWriteEmbeded(dwIoBase, 0x0C, 0x17);//CR12
-    BBbWriteEmbeded(dwIoBase, 0x0D, 0xB9);//CR13
+    BBbWriteEmbedded(dwIoBase, 0x0C, 0x17);//CR12
+    BBbWriteEmbedded(dwIoBase, 0x0D, 0xB9);//CR13
 }
 
 void
 BBvExitDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
 {
-    BBbWriteEmbeded(dwIoBase, 0x0C, 0x00);//CR12
-    BBbWriteEmbeded(dwIoBase, 0x0D, 0x01);//CR13
+    BBbWriteEmbedded(dwIoBase, 0x0C, 0x00);//CR12
+    BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);//CR13
 }
 
 
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index be2d689..9b5bc9c 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -73,12 +73,12 @@
 
 #define BBvClearFOE(dwIoBase)                               \
 {                                                           \
-    BBbWriteEmbeded(dwIoBase, 0xB1, 0);                     \
+    BBbWriteEmbedded(dwIoBase, 0xB1, 0);                     \
 }
 
 #define BBvSetFOE(dwIoBase)                                 \
 {                                                           \
-    BBbWriteEmbeded(dwIoBase, 0xB1, 0x0C);                  \
+    BBbWriteEmbedded(dwIoBase, 0xB1, 0x0C);                  \
 }
 
 
@@ -97,7 +97,7 @@
     );
 
 void
-BBvCaculateParameter (
+BBvCalculateParameter (
     PSDevice pDevice,
     unsigned int cbFrameLength,
     unsigned short wRate,
@@ -107,8 +107,8 @@
     unsigned char *pbyPhySgn
     );
 
-bool BBbReadEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData);
-bool BBbWriteEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData);
+bool BBbReadEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData);
+bool BBbWriteEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData);
 
 void BBvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyBBRegs);
 void BBvLoopbackOn(PSDevice pDevice);
diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c
index fcffa4f..fe57fb8 100644
--- a/drivers/staging/vt6655/bssdb.c
+++ b/drivers/staging/vt6655/bssdb.c
@@ -784,8 +784,8 @@
 /*+
  *
  * Routine Description:
- *    Find an empty node and allocated; if no empty found,
- *    instand used of most inactive one.
+ *    Find an empty node and allocat it; if there is no empty node,
+ *    then use the most inactive one.
  *
  * Return Value:
  *    None
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 2721e07..319ca48 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -28,9 +28,9 @@
  *      CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet
  *      CARDvSetLoopbackMode - Set Loopback mode
  *      CARDbSoftwareReset - Sortware reset NIC
- *      CARDqGetTSFOffset - Caculate TSFOffset
+ *      CARDqGetTSFOffset - Calculate TSFOffset
  *      CARDbGetCurrentTSF - Read Current NIC TSF counter
- *      CARDqGetNextTBTT - Caculate Next Beacon TSF counter
+ *      CARDqGetNextTBTT - Calculate Next Beacon TSF counter
  *      CARDvSetFirstNextTBTT - Set NIC Beacon time
  *      CARDvUpdateNextTBTT - Sync. NIC Beacon time
  *      CARDbRadioPowerOff - Turn Off NIC Radio Power
@@ -100,7 +100,7 @@
 
 static
 void
-s_vCaculateOFDMRParameter(
+s_vCalculateOFDMRParameter(
     unsigned char byRate,
     CARD_PHY_TYPE ePHYType,
     unsigned char *pbyTxRate,
@@ -111,7 +111,7 @@
 /*---------------------  Export Functions  --------------------------*/
 
 /*
- * Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode.
+ * Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode.
  *
  * Parameters:
  *  In:
@@ -126,7 +126,7 @@
  */
 static
 void
-s_vCaculateOFDMRParameter (
+s_vCalculateOFDMRParameter (
     unsigned char byRate,
     CARD_PHY_TYPE ePHYType,
     unsigned char *pbyTxRate,
@@ -251,7 +251,7 @@
     MACvSelectPage1(pDevice->PortOffset);
 
     //RSPINF_b_1
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          VNTWIFIbyGetACKTxRate(RATE_1M, pvSupportRateIEs, pvExtSupportRateIEs),
                          PK_TYPE_11B,
@@ -262,7 +262,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     ///RSPINF_b_2
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          VNTWIFIbyGetACKTxRate(RATE_2M, pvSupportRateIEs, pvExtSupportRateIEs),
                          PK_TYPE_11B,
@@ -273,7 +273,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_b_5
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          VNTWIFIbyGetACKTxRate(RATE_5M, pvSupportRateIEs, pvExtSupportRateIEs),
                          PK_TYPE_11B,
@@ -284,7 +284,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_b_11
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          VNTWIFIbyGetACKTxRate(RATE_11M, pvSupportRateIEs, pvExtSupportRateIEs),
                          PK_TYPE_11B,
@@ -295,51 +295,51 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_a_6
-    s_vCaculateOFDMRParameter(RATE_6M,
+    s_vCalculateOFDMRParameter(RATE_6M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_9
-    s_vCaculateOFDMRParameter(RATE_9M,
+    s_vCalculateOFDMRParameter(RATE_9M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_12
-    s_vCaculateOFDMRParameter(RATE_12M,
+    s_vCalculateOFDMRParameter(RATE_12M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_18
-    s_vCaculateOFDMRParameter(RATE_18M,
+    s_vCalculateOFDMRParameter(RATE_18M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_24
-    s_vCaculateOFDMRParameter(RATE_24M,
+    s_vCalculateOFDMRParameter(RATE_24M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_36
-    s_vCaculateOFDMRParameter(
+    s_vCalculateOFDMRParameter(
                               VNTWIFIbyGetACKTxRate(RATE_36M, pvSupportRateIEs, pvExtSupportRateIEs),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_48
-    s_vCaculateOFDMRParameter(
+    s_vCalculateOFDMRParameter(
                               VNTWIFIbyGetACKTxRate(RATE_48M, pvSupportRateIEs, pvExtSupportRateIEs),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_54
-    s_vCaculateOFDMRParameter(
+    s_vCalculateOFDMRParameter(
                               VNTWIFIbyGetACKTxRate(RATE_54M, pvSupportRateIEs, pvExtSupportRateIEs),
                               ePHYType,
                               &byTxRate,
@@ -461,22 +461,22 @@
             pDevice->abyBBVGA[0] = 0x20;
             pDevice->abyBBVGA[2] = 0x10;
             pDevice->abyBBVGA[3] = 0x10;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x1C) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
             }
         } else if (pDevice->byRFType == RF_UW2452) {
             MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
             pDevice->abyBBVGA[0] = 0x18;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x14) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0x57);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0x57);
             }
         } else {
             MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
         }
-        BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x03);
+        BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x03);
         bySlot = C_SLOT_SHORT;
         bySIFS = C_SIFS_A;
         byDIFS = C_SIFS_A + 2*C_SLOT_SHORT;
@@ -490,19 +490,19 @@
             pDevice->abyBBVGA[0] = 0x1C;
             pDevice->abyBBVGA[2] = 0x00;
             pDevice->abyBBVGA[3] = 0x00;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x20) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
             }
         } else if (pDevice->byRFType == RF_UW2452) {
             pDevice->abyBBVGA[0] = 0x14;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x18) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
             }
         }
-        BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x02);
+        BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x02);
         bySlot = C_SLOT_LONG;
         bySIFS = C_SIFS_BG;
         byDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
@@ -517,19 +517,19 @@
             pDevice->abyBBVGA[0] = 0x1C;
             pDevice->abyBBVGA[2] = 0x00;
             pDevice->abyBBVGA[3] = 0x00;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x20) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
             }
         } else if (pDevice->byRFType == RF_UW2452) {
             pDevice->abyBBVGA[0] = 0x14;
-            BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData);
+            BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
             if (byData == 0x18) {
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
-                BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+                BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
             }
         }
-        BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x08);
+        BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x08);
         bySIFS = C_SIFS_BG;
         if(VNTWIFIbIsShortSlotTime(wCapInfo)) {
             bySlot = C_SLOT_SHORT;
@@ -1354,7 +1354,8 @@
 /*
  *
  * Description:
- *    Do Quiet, It will called by either ISR (after start) or VNTWIFI (before start) so do not need SPINLOCK
+ *    Do Quiet, It will be called by either ISR(after start) 
+ *    or VNTWIFI(before start) so we do not need a SPINLOCK
  *
  * Parameters:
  *  In:
@@ -1738,7 +1739,7 @@
     MACvSelectPage1(pDevice->PortOffset);
 
     //RSPINF_b_1
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          CARDwGetCCKControlRate((void *)pDevice, RATE_1M),
                          PK_TYPE_11B,
@@ -1749,7 +1750,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     ///RSPINF_b_2
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          CARDwGetCCKControlRate((void *)pDevice, RATE_2M),
                          PK_TYPE_11B,
@@ -1760,7 +1761,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_b_5
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          CARDwGetCCKControlRate((void *)pDevice, RATE_5M),
                          PK_TYPE_11B,
@@ -1771,7 +1772,7 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_b_11
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          CARDwGetCCKControlRate((void *)pDevice, RATE_11M),
                          PK_TYPE_11B,
@@ -1782,56 +1783,56 @@
 
     VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
     //RSPINF_a_6
-    s_vCaculateOFDMRParameter(RATE_6M,
+    s_vCalculateOFDMRParameter(RATE_6M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_9
-    s_vCaculateOFDMRParameter(RATE_9M,
+    s_vCalculateOFDMRParameter(RATE_9M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_12
-    s_vCaculateOFDMRParameter(RATE_12M,
+    s_vCalculateOFDMRParameter(RATE_12M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_18
-    s_vCaculateOFDMRParameter(RATE_18M,
+    s_vCalculateOFDMRParameter(RATE_18M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
    VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_24
-    s_vCaculateOFDMRParameter(RATE_24M,
+    s_vCalculateOFDMRParameter(RATE_24M,
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_36
-    s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M),
+    s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_48
-    s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M),
+    s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime));
     //RSPINF_a_54
-    s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
+    s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
     VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime));
 
     //RSPINF_a_72
-    s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
+    s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
                               ePHYType,
                               &byTxRate,
                               &byRsvTime);
@@ -2041,7 +2042,7 @@
 
 
 /*
- * Description: Caculate TSF offset of two TSF input
+ * Description: Calculate TSF offset of two TSF input
  *              Get TSF Offset from RxBCN's TSF and local TSF
  *
  * Parameters:
diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c
index efbb8f4..b86ec1b 100644
--- a/drivers/staging/vt6655/datarate.c
+++ b/drivers/staging/vt6655/datarate.c
@@ -126,7 +126,7 @@
 /*+
  *
  * Routine Description:
- *      Rate fallback Algorithm Implementaion
+ *      Rate fallback Algorithm Implementation
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index c5e6b98..e54e00b 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -327,7 +327,7 @@
 //flags for driver status
 #define     DEVICE_FLAGS_OPENED          0x00010000UL
 #define     DEVICE_FLAGS_WOL_ENABLED     0x00080000UL
-//flags for capbilities
+//flags for capabilities
 #define     DEVICE_FLAGS_TX_ALIGN        0x01000000UL
 #define     DEVICE_FLAGS_HAVE_CAM        0x02000000UL
 #define     DEVICE_FLAGS_FLOW_CTRL       0x04000000UL
@@ -567,7 +567,7 @@
     bool bPrvActive4RadioOFF;
     bool bGPIOBlockRead;
 
-    // Beacon releated
+    // Beacon related
     unsigned short wSeqCounter;
     unsigned short wBCNBufLen;
     bool bBeaconBufReady;
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 89d1c22..9e3b3f2b 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -290,7 +290,7 @@
 
 
 static int  vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent);
-static bool vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO);
+static void vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO);
 static void device_free_info(PSDevice pDevice);
 static bool device_get_pci_info(PSDevice, struct pci_dev* pcid);
 static void device_print_info(PSDevice pDevice);
@@ -347,21 +347,22 @@
 
 
 
-static char* get_chip_name(int chip_id) {
-    int i;
-    for (i=0;chip_info_table[i].name!=NULL;i++)
-        if (chip_info_table[i].chip_id==chip_id)
-            break;
-    return chip_info_table[i].name;
+static char* get_chip_name(int chip_id)
+{
+	int i;
+	for (i = 0; chip_info_table[i].name != NULL; i++)
+		if (chip_info_table[i].chip_id == chip_id)
+			break;
+	return chip_info_table[i].name;
 }
 
 static void __devexit vt6655_remove(struct pci_dev *pcid)
 {
-    PSDevice pDevice=pci_get_drvdata(pcid);
+	PSDevice pDevice = pci_get_drvdata(pcid);
 
-    if (pDevice==NULL)
-        return;
-    device_free_info(pDevice);
+	if (pDevice == NULL)
+		return;
+	device_free_info(pDevice);
 
 }
 
@@ -397,31 +398,29 @@
     }
 }
 */
-static void
-device_get_options(PSDevice pDevice, int index, char* devname) {
+static void device_get_options(PSDevice pDevice, int index, char* devname)
+{
+	POPTIONS pOpts = &(pDevice->sOpts);
 
-    POPTIONS pOpts = &(pDevice->sOpts);
-  pOpts->nRxDescs0=RX_DESC_DEF0;
-  pOpts->nRxDescs1=RX_DESC_DEF1;
-  pOpts->nTxDescs[0]=TX_DESC_DEF0;
-  pOpts->nTxDescs[1]=TX_DESC_DEF1;
-pOpts->flags|=DEVICE_FLAGS_IP_ALIGN;
-  pOpts->int_works=INT_WORKS_DEF;
-  pOpts->rts_thresh=RTS_THRESH_DEF;
-  pOpts->frag_thresh=FRAG_THRESH_DEF;
-  pOpts->data_rate=DATA_RATE_DEF;
-  pOpts->channel_num=CHANNEL_DEF;
+	pOpts->nRxDescs0 = RX_DESC_DEF0;
+	pOpts->nRxDescs1 = RX_DESC_DEF1;
+	pOpts->nTxDescs[0] = TX_DESC_DEF0;
+	pOpts->nTxDescs[1] = TX_DESC_DEF1;
+	pOpts->flags |= DEVICE_FLAGS_IP_ALIGN;
+	pOpts->int_works = INT_WORKS_DEF;
+	pOpts->rts_thresh = RTS_THRESH_DEF;
+	pOpts->frag_thresh = FRAG_THRESH_DEF;
+	pOpts->data_rate = DATA_RATE_DEF;
+	pOpts->channel_num = CHANNEL_DEF;
 
-pOpts->flags|=DEVICE_FLAGS_PREAMBLE_TYPE;
-pOpts->flags|=DEVICE_FLAGS_OP_MODE;
-//pOpts->flags|=DEVICE_FLAGS_PS_MODE;
-  pOpts->short_retry=SHORT_RETRY_DEF;
-  pOpts->long_retry=LONG_RETRY_DEF;
-  pOpts->bbp_type=BBP_TYPE_DEF;
-pOpts->flags|=DEVICE_FLAGS_80211h_MODE;
-pOpts->flags|=DEVICE_FLAGS_DiversityANT;
-
-
+	pOpts->flags |= DEVICE_FLAGS_PREAMBLE_TYPE;
+	pOpts->flags |= DEVICE_FLAGS_OP_MODE;
+	//pOpts->flags|=DEVICE_FLAGS_PS_MODE;
+	pOpts->short_retry = SHORT_RETRY_DEF;
+	pOpts->long_retry = LONG_RETRY_DEF;
+	pOpts->bbp_type = BBP_TYPE_DEF;
+	pOpts->flags |= DEVICE_FLAGS_80211h_MODE;
+	pOpts->flags |= DEVICE_FLAGS_DiversityANT;
 }
 
 static void
@@ -518,7 +517,7 @@
 
 
 //
-// Initialiation of MAC & BBP registers
+// Initialisation of MAC & BBP registers
 //
 
 static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
@@ -894,18 +893,15 @@
     return true;
 }
 
-
 static const struct net_device_ops device_netdev_ops = {
-    .ndo_open               = device_open,
-    .ndo_stop               = device_close,
-    .ndo_do_ioctl           = device_ioctl,
-    .ndo_get_stats          = device_get_stats,
-    .ndo_start_xmit         = device_xmit,
-    .ndo_set_rx_mode	    = device_set_multi,
+	.ndo_open               = device_open,
+	.ndo_stop               = device_close,
+	.ndo_do_ioctl           = device_ioctl,
+	.ndo_get_stats          = device_get_stats,
+	.ndo_start_xmit         = device_xmit,
+	.ndo_set_rx_mode	= device_set_multi,
 };
 
-
-
 static int __devinit
 vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
 {
@@ -926,7 +922,7 @@
 
     if (dev == NULL) {
         printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n");
-        return -ENODEV;
+        return -ENOMEM;
     }
 
     // Chain it all together
@@ -939,9 +935,7 @@
         bFirst=false;
     }
 
-    if (!vt6655_init_info(pcid, &pDevice, pChip_info)) {
-        return -ENOMEM;
-    }
+    vt6655_init_info(pcid, &pDevice, pChip_info);
     pDevice->dev = dev;
     pDevice->next_module = root_device_dev;
     root_device_dev = dev;
@@ -1064,7 +1058,7 @@
     //Mask out the options cannot be set to the chip
     pDevice->sOpts.flags &= pChip_info->flags;
 
-    //Enable the chip specified capbilities
+    //Enable the chip specified capabilities
     pDevice->flags = pDevice->sOpts.flags | (pChip_info->flags & 0xFF000000UL);
     pDevice->tx_80211 = device_dma0_tx_80211;
     pDevice->sMgmtObj.pAdapter = (void *)pDevice;
@@ -1105,7 +1099,7 @@
 
 }
 
-static bool __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
+static void __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
     PCHIP_INFO pChip_info) {
 
     PSDevice p;
@@ -1129,8 +1123,6 @@
     (*ppDevice)->multicast_limit =32;
 
     spin_lock_init(&((*ppDevice)->lock));
-
-    return true;
 }
 
 static bool device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) {
@@ -1678,7 +1670,7 @@
                 uFrameSize = pTD->pTDInfo->dwReqCount - uFIFOHeaderSize;
                 pTxBufHead = (PSTxBufHead) (pTD->pTDInfo->buf);
                 // Update the statistics based on the Transmit status
-                // now, we DO'NT check TSR0_CDH
+                // now, we DONT check TSR0_CDH
 
                 STAvUpdateTDStatCounter(&pDevice->scStatistic,
                         byTsr0, byTsr1,
@@ -2660,7 +2652,7 @@
         (pDevice->byLocalID != REV_ID_VT3253_B0) &&
         (pDevice->bBSSIDFilter == true)) {
         // update RSSI
-        //BBbReadEmbeded(pDevice->PortOffset, 0x3E, &byRSSI);
+        //BBbReadEmbedded(pDevice->PortOffset, 0x3E, &byRSSI);
         //pDevice->uCurrRSSI = byRSSI;
     }
     */
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index e8a71ba..373e9e4 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -718,7 +718,7 @@
     if ((*pbyRSSI != 0) &&
         (pMgmt->pCurrBSS!=NULL)) {
         RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
-        // Moniter if RSSI is too strong.
+        // Monitor if RSSI is too strong.
         pMgmt->pCurrBSS->byRSSIStatCnt++;
         pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT;
         pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm;
diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c
index 6ac6f45..67b1b88 100644
--- a/drivers/staging/vt6655/hostap.c
+++ b/drivers/staging/vt6655/hostap.c
@@ -495,9 +495,7 @@
 		return -EINVAL;
 	}
 
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= MAX_GROUP_KEY)
 			return -EINVAL;
         iNodeIndex = 0;
@@ -716,9 +714,7 @@
 
 	param->u.crypt.err = 0;
 
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
         iNodeIndex = 0;
 	} else {
 	    if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c
index ef197ef..afed6e3 100644
--- a/drivers/staging/vt6655/ioctl.c
+++ b/drivers/staging/vt6655/ioctl.c
@@ -111,7 +111,7 @@
 		break;
 
 	case WLAN_CMD_ZONETYPE_SET:
-		/* mike add :cann't support. */
+		/* mike add :can't support. */
 		result = -EOPNOTSUPP;
 		break;
 
@@ -539,11 +539,8 @@
 			pMgmt->abyIBSSSuppRates[3] |= BIT7;
 		}
 
-		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n",
-			pMgmt->abyIBSSSuppRates[2],
-			pMgmt->abyIBSSSuppRates[3],
-			pMgmt->abyIBSSSuppRates[4],
-			pMgmt->abyIBSSSuppRates[5]);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n",
+				4, pMgmt->abyIBSSSuppRates + 2);
 
 		netif_stop_queue(pDevice->dev);
 		spin_lock_irq(&pDevice->lock);
diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c
index 77aad7f..5cdda8d 100644
--- a/drivers/staging/vt6655/iwctl.c
+++ b/drivers/staging/vt6655/iwctl.c
@@ -358,7 +358,7 @@
 
 
 /*
- * Wireless Handler : set frequence or channel
+ * Wireless Handler : set frequency or channel
  */
 
 int iwctl_siwfreq(struct net_device *dev,
@@ -404,7 +404,7 @@
 }
 
 /*
- * Wireless Handler : get frequence or channel
+ * Wireless Handler : get frequency or channel
  */
 
 int iwctl_giwfreq(struct net_device *dev,
@@ -1346,7 +1346,7 @@
 
 		}else if(index>0){
 	//when the length is 0 the request only changes the default transmit key index
-	//check the new key has a non zero lenget
+	//check the new key if it has a non zero length
 	if(pDevice->bEncryptionEnable==false)
 	{
 		rc = -EINVAL;
diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c
index 774b0d4..194fedc 100644
--- a/drivers/staging/vt6655/key.c
+++ b/drivers/staging/vt6655/key.c
@@ -372,7 +372,7 @@
     int  i;
 
     if (is_broadcast_ether_addr(pbyBSSID)) {
-        // dealte all key
+        // delete all keys
         if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
             for (i=0;i<MAX_KEY_TABLE;i++) {
                 pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index f8d1651..30c2615 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -56,9 +56,9 @@
  *      MACbSafeStop - Stop MAC function
  *      MACbShutdown - Shut down MAC
  *      MACvInitialize - Initialize MAC
- *      MACvSetCurrRxDescAddr - Set Rx Descriptos Address
- *      MACvSetCurrTx0DescAddr - Set Tx0 Descriptos Address
- *      MACvSetCurrTx1DescAddr - Set Tx1 Descriptos Address
+ *      MACvSetCurrRxDescAddr - Set Rx Descriptors Address
+ *      MACvSetCurrTx0DescAddr - Set Tx0 Descriptors Address
+ *      MACvSetCurrTx1DescAddr - Set Tx1 Descriptors Address
  *      MACvTimer0MicroSDelay - Micro Second Delay Loop by MAC
  *
  * Revision History:
@@ -1498,7 +1498,7 @@
 
     wOffset += (uKeyIdx * 4);
     for (ii=0;ii<4;ii++) {
-        // alway push 128 bits
+        // always push 128 bits
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
         VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
         VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
@@ -1567,7 +1567,7 @@
     wOffset++;
     wOffset++;
     wOffset += (uKeyIdx * 4);
-    // alway push 128 bits
+    // always push 128 bits
     for (ii=0; ii<3; ii++) {
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
         VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
@@ -1696,7 +1696,7 @@
 
     wOffset += (uKeyIdx * 4);
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, idx:%d\n", wOffset, *pdwKey, uKeyIdx);
-    // alway push 128 bits
+    // always push 128 bits
     for (ii=0; ii<4; ii++) {
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
         VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index e3ccfee..adfb366 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -586,7 +586,7 @@
 #define PKT_TYPE_NONE           0x00    // turn off receiver
 #define PKT_TYPE_ALL_MULTICAST  0x80
 #define PKT_TYPE_PROMISCUOUS    0x40
-#define PKT_TYPE_DIRECTED       0x20    // obselete, directed address is always accepted
+#define PKT_TYPE_DIRECTED       0x20    // obsolete, directed address is always accepted
 #define PKT_TYPE_BROADCAST      0x10
 #define PKT_TYPE_MULTICAST      0x08
 #define PKT_TYPE_ERROR_WPA      0x04
diff --git a/drivers/staging/vt6655/mib.c b/drivers/staging/vt6655/mib.c
index 1b91a83..63ae4ad 100644
--- a/drivers/staging/vt6655/mib.c
+++ b/drivers/staging/vt6655/mib.c
@@ -191,7 +191,7 @@
         pStatistic->ullRsrOK++;
 
         if (cbFrameLength >= ETH_ALEN) {
-            // update counters in case that successful transmit
+            // update counters in case of successful transmit
             if (byRSR & RSR_ADDRBROAD) {
                 pStatistic->ullRxBroadcastFrames++;
                 pStatistic->ullRxBroadcastBytes += (unsigned long long) cbFrameLength;
diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c
index 4c0b02e..661d534 100644
--- a/drivers/staging/vt6655/power.c
+++ b/drivers/staging/vt6655/power.c
@@ -207,7 +207,7 @@
     if (pDevice->bCmdRunning)
         return false;
 
-    // Froce PSEN on
+    // Force PSEN on
     MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
 
     // check if all TD are empty,
diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c
index aa69665..aaa231a 100644
--- a/drivers/staging/vt6655/rf.c
+++ b/drivers/staging/vt6655/rf.c
@@ -26,7 +26,7 @@
  * Date: Feb. 19, 2004
  *
  * Functions:
- *      IFRFbWriteEmbeded      - Embeded write RF register via MAC
+ *      IFRFbWriteEmbedded      - Embedded write RF register via MAC
  *
  * Revision History:
  *
@@ -453,18 +453,18 @@
     BBvPowerSaveModeOFF(dwIoBase); //RobertYu:20050106, have DC value for Calibration
 
     for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++)
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[ii]);
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[ii]);
 
     // PLL On
     MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
 
     //Calibration
     MACvTimer0MicroSDelay(dwIoBase, 150);//150us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:diable
+    bResult &= IFRFbWriteEmbedded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:disable
     MACvTimer0MicroSDelay(dwIoBase, 30);//30us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:diable, RCK:active
+    bResult &= IFRFbWriteEmbedded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:disable, RCK:active
     MACvTimer0MicroSDelay(dwIoBase, 30);//30us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:diable, RCK:diable
+    bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:disable, RCK:disable
 
     MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3    |
                                                      SOFTPWRCTL_SWPE2    |
@@ -490,9 +490,9 @@
     // PLLON Off
     MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
 
-    bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0
-    bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1
-    bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4
+    bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0
+    bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1
+    bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4
 
     // PLLOn On
     MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
@@ -574,7 +574,7 @@
 /*---------------------  Export Functions  --------------------------*/
 
 /*
- * Description: Write to IF/RF, by embeded programming
+ * Description: Write to IF/RF, by embedded programming
  *
  * Parameters:
  *  In:
@@ -586,7 +586,7 @@
  * Return Value: true if succeeded; false if failed.
  *
  */
-bool IFRFbWriteEmbeded (unsigned long dwIoBase, unsigned long dwData)
+bool IFRFbWriteEmbedded (unsigned long dwIoBase, unsigned long dwData)
 {
     unsigned short ww;
     unsigned long dwValue;
@@ -669,11 +669,11 @@
 
     //patch abnormal AL2230 frequency output
 //2008-8-21 chester <add>
-    IFRFbWriteEmbeded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+    IFRFbWriteEmbedded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
 
 
     for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++)
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[ii]);
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[ii]);
 //2008-8-21 chester <add>
 MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us
 
@@ -681,11 +681,11 @@
     MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
 
     MACvTimer0MicroSDelay(dwIoBase, 150);//150us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+    bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
     MACvTimer0MicroSDelay(dwIoBase, 30);//30us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+    bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
     MACvTimer0MicroSDelay(dwIoBase, 30);//30us
-    bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]);
+    bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]);
 
     MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3    |
                                                      SOFTPWRCTL_SWPE2    |
@@ -704,8 +704,8 @@
 
     bResult = true;
 
-    bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]);
-    bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]);
+    bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]);
+    bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]);
 
     // Set Channel[7] = 0 to tell H/W channel is changing now.
     VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F));
@@ -817,7 +817,7 @@
 
     switch (pDevice->byRFType) {
         case RF_AIROHA7230 :
-            bResult = IFRFbWriteEmbeded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
+            bResult = IFRFbWriteEmbedded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
             break;
         default :
             bResult = true;
@@ -1072,23 +1072,23 @@
     switch (pDevice->byRFType) {
 
         case RF_AIROHA :
-            bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
+            bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
             if (uRATE <= RATE_11M) {
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             } else {
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             }
             break;
 
 
         case RF_AL2230S :
-            bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
+            bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
             if (uRATE <= RATE_11M) {
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             }else {
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
-                bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             }
 
             break;
@@ -1098,7 +1098,7 @@
             dwMax7230Pwr = 0x080C0B00 | ( (byPwr) << 12 ) |
                            (BY_AL7230_REG_LEN << 3 )  | IFREGCTL_REGW;
 
-            bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwMax7230Pwr);
+            bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwMax7230Pwr);
             break;
 
 
@@ -1166,24 +1166,24 @@
     if( (byOldChannel <= CB_MAX_CHANNEL_24G) && (byNewChannel > CB_MAX_CHANNEL_24G) )
     {
         // Change from 2.4G to 5G
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15
     }
     else if( (byOldChannel > CB_MAX_CHANNEL_24G) && (byNewChannel <= CB_MAX_CHANNEL_24G) )
     {
         // change from 5G to 2.4G
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[2]); //Reg2
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[3]); //Reg3
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[5]); //Reg5
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[7]); //Reg7
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[10]);//Reg10
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[12]);//Reg12
-        bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[15]);//Reg15
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[2]); //Reg2
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[3]); //Reg3
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[5]); //Reg5
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[7]); //Reg7
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[10]);//Reg10
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[12]);//Reg12
+        bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[15]);//Reg15
     }
 
     return bResult;
diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h
index 73f0969..1da0fdeb 100644
--- a/drivers/staging/vt6655/rf.h
+++ b/drivers/staging/vt6655/rf.h
@@ -75,7 +75,7 @@
 
 /*---------------------  Export Functions  --------------------------*/
 
-bool IFRFbWriteEmbeded(unsigned long dwIoBase, unsigned long dwData);
+bool IFRFbWriteEmbedded(unsigned long dwIoBase, unsigned long dwData);
 bool RFbSelectChannel(unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel);
 bool RFbInit (
     PSDevice  pDevice
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index 6935b37..4972e57 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -27,7 +27,7 @@
  * Functions:
  *      s_vGenerateTxParameter - Generate tx dma required parameter.
  *      vGenerateMACHeader - Translate 802.3 to 802.11 header
- *      cbGetFragCount - Caculate fragment number count
+ *      cbGetFragCount - Calculate fragment number count
  *      csBeacon_xmit - beacon tx function
  *      csMgmt_xmit - management tx function
  *      s_cbFillTxBufHead - fulfill tx dma buffer header
@@ -733,11 +733,11 @@
         if (byFBOption == AUTO_FB_NONE) {
             PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
@@ -759,11 +759,11 @@
             // Auto Fallback
             PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
@@ -788,7 +788,7 @@
             // Auto Fallback
             PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -805,7 +805,7 @@
         } else {
             PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -823,7 +823,7 @@
     else {
             PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -871,11 +871,11 @@
         if (byFBOption == AUTO_FB_NONE) {
             PSRTS_g pBuf = (PSRTS_g)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
@@ -904,11 +904,11 @@
         else {
            PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
@@ -946,7 +946,7 @@
         if (byFBOption == AUTO_FB_NONE) {
             PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -975,7 +975,7 @@
         else {
             PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -1005,7 +1005,7 @@
     else if (byPktType == PK_TYPE_11B) {
         PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
         //Get SignalField,ServiceField,Length
-        BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+        BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
             (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
         );
         pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -1065,7 +1065,7 @@
             // Auto Fall back
             PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
 
@@ -1092,7 +1092,7 @@
         } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
             PSCTS pBuf = (PSCTS)pvCTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
@@ -2568,7 +2568,7 @@
     if (bIsPSPOLL) {
         // The MAC will automatically replace the Duration-field of MAC header by Duration-field
         // of  FIFO control header.
-        // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
+        // This will cause AID-field of PS-POLL packet to be incorrect (Because PS-POLL's AID field is
         // in the same place of other packet's Duration-field).
         // And it will cause Cisco-AP to issue Disassociation-packet
         if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
@@ -2664,7 +2664,7 @@
                                                           wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
     }
 
-    BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType,
+    BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType,
         (unsigned short *)&(wLen), (unsigned char *)&(pTxDataHead->byServiceField), (unsigned char *)&(pTxDataHead->bySignalField)
     );
     pTxDataHead->wTransmitLength = cpu_to_le16(wLen);
@@ -2860,7 +2860,7 @@
 
     // SetPower will cause error power TX state for OFDM Date packet in TX buffer.
     // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability.
-    //                    And cmd timer will wait data pkt TX finish before scanning so it's OK
+    //                    And cmd timer will wait data pkt TX to finish before scanning so it's OK
     //                    to set power here.
     if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
         RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh);
@@ -2957,7 +2957,7 @@
     pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)cbMacHdLen << 10);
 
     // Notes:
-    // Although spec says MMPDU can be fragmented; In most case,
+    // Although spec says MMPDU can be fragmented; In most casses,
     // no one will send a MMPDU under fragmentation. With RTS may occur.
     pDevice->bAES = false;  //Set FRAGCTL_WEPTYP
 
diff --git a/drivers/staging/vt6655/tcrc.c b/drivers/staging/vt6655/tcrc.c
index f9c28bf8..1313c4c 100644
--- a/drivers/staging/vt6655/tcrc.c
+++ b/drivers/staging/vt6655/tcrc.c
@@ -18,7 +18,7 @@
  *
  * File: tcrc.c
  *
- * Purpose: Implement functions to caculate CRC
+ * Purpose: Implement functions to calculate CRC
  *
  * Author: Tevin Chen
  *
diff --git a/drivers/staging/vt6655/tcrc.h b/drivers/staging/vt6655/tcrc.h
index d044985..a204421 100644
--- a/drivers/staging/vt6655/tcrc.h
+++ b/drivers/staging/vt6655/tcrc.h
@@ -18,7 +18,7 @@
  *
  * File: tcrc.h
  *
- * Purpose: Implement functions to caculate CRC
+ * Purpose: Implement functions to calculate CRC
  *
  * Author: Tevin Chen
  *
diff --git a/drivers/staging/vt6655/tether.c b/drivers/staging/vt6655/tether.c
index 1cf8508..28554bf 100644
--- a/drivers/staging/vt6655/tether.c
+++ b/drivers/staging/vt6655/tether.c
@@ -25,7 +25,7 @@
  * Date: May 21, 1996
  *
  * Functions:
- *      ETHbyGetHashIndexByCrc32 - Caculate multicast hash value by CRC32
+ *      ETHbyGetHashIndexByCrc32 - Calculate multicast hash value by CRC32
  *      ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not
  *
  * Revision History:
@@ -50,7 +50,7 @@
 
 
 /*
- * Description: Caculate multicast hash value by CRC32
+ * Description: Calculate multicast hash value by CRC32
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6655/tkip.c b/drivers/staging/vt6655/tkip.c
index ed3eac1..f141ba1 100644
--- a/drivers/staging/vt6655/tkip.c
+++ b/drivers/staging/vt6655/tkip.c
@@ -170,7 +170,7 @@
 
 
 /*
- * Description: Caculate RC4Key fom TK, TA, and TSC
+ * Description: Calculate RC4Key fom TK, TA, and TSC
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c
index d645ecd..62c44b8 100644
--- a/drivers/staging/vt6655/vntwifi.c
+++ b/drivers/staging/vt6655/vntwifi.c
@@ -60,7 +60,7 @@
  * Parameters:
  *  In:
  *      pMgmtHandle - pointer to management object
- *      eOPMode     - Opreation Mode
+ *      eOPMode     - Operation Mode
  *  Out:
  *      none
  *
diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c
index 7b5b99c..94bd1fc 100644
--- a/drivers/staging/vt6655/wcmd.c
+++ b/drivers/staging/vt6655/wcmd.c
@@ -121,7 +121,7 @@
 
     /*
      * temporarily stop Beacon packet for AdHoc Server
-     * if all of the following coditions are met:
+     * if all of the following conditions are met:
      *  (1) STA is in AdHoc mode
      *  (2) VT3253 is programmed as automatic Beacon Transmitting
      *  (3) One of the following conditions is met
@@ -812,8 +812,8 @@
                             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n");
                         }
                         pMgmt->sNodeDBTable[ii].wEnQueueCnt--;
-                        // check if sta ps enable, wait next pspoll
-                        // if sta ps disable, send all pending buffers.
+                        // check if sta ps enabled, and wait next pspoll.
+                        // if sta ps disable, then send all pending buffers.
                         if (pMgmt->sNodeDBTable[ii].bPSEnable)
                             break;
                     }
diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c
index c46d5190..b6f99ec 100644
--- a/drivers/staging/vt6655/wmgr.c
+++ b/drivers/staging/vt6655/wmgr.c
@@ -26,8 +26,8 @@
  * Date: May 8, 2002
  *
  * Functions:
- *      nsMgrObjectInitial - Initialize Management Objet data structure
- *      vMgrObjectReset - Reset Management Objet data structure
+ *      nsMgrObjectInitial - Initialize Management Object data structure
+ *      vMgrObjectReset - Reset Management Object data structure
  *      vMgrAssocBeginSta - Start associate function
  *      vMgrReAssocBeginSta - Start reassociate function
  *      vMgrDisassocBeginSta - Start disassociate function
@@ -54,7 +54,7 @@
  *      bMgrPrepareBeaconToSend - Prepare Beacon frame
  *      s_vMgrLogStatus - Log 802.11 Status
  *      vMgrRxManagePacket - Rcv management frame dispatch function
- *      s_vMgrFormatTIM- Assember TIM field of beacon
+ *      s_vMgrFormatTIM- Assembler TIM field of beacon
  *      vMgrTimerInit- Initial 1-sec and command call back funtions
  *
  * Revision History:
@@ -425,7 +425,7 @@
 /*+
  *
  * Routine Description:
- *    Reset the management object  structure.
+ *    Reset the management object structure.
  *
  * Return Value:
  *    None.
@@ -1287,14 +1287,14 @@
     vMgrDecodeAuthen(&sFrame);
     switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){
         case 1:
-            //AP funciton
+            //AP function
             s_vMgrRxAuthenSequence_1(pDevice,pMgmt, &sFrame);
             break;
         case 2:
             s_vMgrRxAuthenSequence_2(pDevice, pMgmt, &sFrame);
             break;
         case 3:
-            //AP funciton
+            //AP function
             s_vMgrRxAuthenSequence_3(pDevice, pMgmt, &sFrame);
             break;
         case 4:
@@ -1923,7 +1923,7 @@
             byIEChannel = sFrame.pDSParms->byCurrChannel;
         }
         if (byCurrChannel != byIEChannel) {
-            // adjust channel info. bcs we rcv adjcent channel pakckets
+            // adjust channel info. bcs we rcv adjacent channel packets
             bChannelHit = false;
             byCurrChannel = byIEChannel;
         }
@@ -2081,7 +2081,7 @@
                 }
             }
             //
-            // Basic Rate Set may change dynamiclly
+            // Basic Rate Set may change dynamically
             //
             if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) {
                 uRateLen = WLAN_RATES_MAXLEN_11B;
@@ -2134,7 +2134,7 @@
     }
 
 //    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon 2 \n");
-    // check if CF field exisit
+    // check if CF field exists
     if (WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)) {
         if (sFrame.pCFParms->wCFPDurRemaining > 0) {
             // TODO: deal with CFP period to set NAV
@@ -2244,7 +2244,7 @@
 		    if (pMgmt->sNodeDBTable[0].uInActiveCount != 0)
 		 	    pMgmt->sNodeDBTable[0].uInActiveCount = 0;
 
-            // adhoc mode:TSF updated only when beacon larger then local TSF
+            // adhoc mode:TSF updated only when beacon larger than local TSF
             if (bTSFLargeDiff && bTSFOffsetPostive &&
                 (pMgmt->eCurrState == WMAC_STATE_JOINTED))
                 bUpdateTSF = true;
@@ -2252,7 +2252,7 @@
             // During dpc, already in spinlocked.
             if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) {
 
-                // Update the STA, (Techically the Beacons of all the IBSS nodes
+                // Update the STA, (Technically the Beacons of all the IBSS nodes
 		        // should be identical, but that's not happening in practice.
                 pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
                                                         (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
@@ -2305,7 +2305,7 @@
 */
             }
 
-            // if other stations jointed, indicate connect to upper layer..
+            // if other stations joined, indicate connection to upper layer..
             if (pMgmt->eCurrState == WMAC_STATE_STARTED) {
                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n");
                 pMgmt->eCurrState = WMAC_STATE_JOINTED;
@@ -3081,8 +3081,8 @@
                //   }
            // }
   //   if( uSameBssidNum>=2) {	 //we only check AP in hidden sssid  mode
-        if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||           //networkmanager 0.7.0 does not give the pairwise-key selsection,
-             (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {         // so we need re-selsect it according to real pairwise-key info.
+        if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||           //networkmanager 0.7.0 does not give the pairwise-key selection,
+             (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {         // so we need re-select it according to real pairwise-key info.
                if(pCurr->bWPAValid == true)  {   //WPA-PSK
                           pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
 		    if(pCurr->abyPKType[0] == WPA_TKIP) {
@@ -3193,7 +3193,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -3310,7 +3310,7 @@
             *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
             sFrame.pRSNWPA->len +=2;
 
-            // RSN Capabilites
+            // RSN Capabilities
             *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
             sFrame.pRSNWPA->len +=2;
             sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
@@ -3420,7 +3420,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -3611,7 +3611,7 @@
  *
  *
  * Return Value:
- *    A ptr to frame or NULL on allocation failue
+ *    A ptr to frame or NULL on allocation failure
  *
 -*/
 
@@ -3652,7 +3652,7 @@
     memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
     memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
 
-    // Set the capibility and listen interval
+    // Set the capability and listen interval
     *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
     *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
 
@@ -3762,7 +3762,7 @@
 
         sFrame.pRSNWPA->len +=6;
 
-        // RSN Capabilites
+        // RSN Capabilities
 
         *pbyRSN++=0x00;
         *pbyRSN++=0x00;
@@ -3831,7 +3831,7 @@
         }
         sFrame.pRSN->len +=6;
 
-        // RSN Capabilites
+        // RSN Capabilities
         if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
             memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
         } else {
@@ -3886,7 +3886,7 @@
  *
  *
  * Return Value:
- *    A ptr to frame or NULL on allocation failue
+ *    A ptr to frame or NULL on allocation failure
  *
 -*/
 
@@ -3929,7 +3929,7 @@
     memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
     memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
 
-    /* Set the capibility and listen interval */
+    /* Set the capability and listen interval */
     *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
     *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
 
@@ -4019,7 +4019,7 @@
 
         sFrame.pRSNWPA->len +=6;
 
-        // RSN Capabilites
+        // RSN Capabilities
         *pbyRSN++=0x00;
         *pbyRSN++=0x00;
         sFrame.pRSNWPA->len +=2;
@@ -4087,7 +4087,7 @@
         }
         sFrame.pRSN->len +=6;
 
-        // RSN Capabilites
+        // RSN Capabilities
         if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
             memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
         } else {
@@ -4138,7 +4138,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -4212,7 +4212,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -4333,7 +4333,7 @@
             byIEChannel = sFrame.pDSParms->byCurrChannel;
         }
         if (byCurrChannel != byIEChannel) {
-            // adjust channel info. bcs we rcv adjcent channel pakckets
+            // adjust channel info. bcs we rcv adjacent channel packets
             bChannelHit = false;
             byCurrChannel = byIEChannel;
         }
diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h
index e3ae562..bfa67ae 100644
--- a/drivers/staging/vt6655/wmgr.h
+++ b/drivers/staging/vt6655/wmgr.h
@@ -286,7 +286,7 @@
     CMD_STATE               eCommandState;
     unsigned int	uScanChannel;
 
-    // Desire joinning BSS vars
+    // Desire joining BSS vars
     unsigned char abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
     unsigned char abyDesireBSSID[WLAN_BSSID_LEN];
 
@@ -310,7 +310,7 @@
     unsigned int	uScanEndCh;
     unsigned short wScanSteps;
     unsigned int	uScanBSSType;
-    // Desire scannig vars
+    // Desire scanning vars
     unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
     unsigned char abyScanBSSID[WLAN_BSSID_LEN];
 
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index 0afb9fe..4412fe9 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -229,7 +229,7 @@
  * Parameters:
  *  In:
  *      byCmd    - Search type
- *      byEncrypt- Encrcypt Type
+ *      byEncrypt- Encrypt Type
  *      pBSSList - BSS list
  *  Out:
  *      none
diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c
index 744799c..884db1a 100644
--- a/drivers/staging/vt6655/wpa2.c
+++ b/drivers/staging/vt6655/wpa2.c
@@ -175,16 +175,16 @@
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
                         bUseGK = true;
                     } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) {
-                        // Invialid CSS, continue to parsing
+                        // Invalid CSS, continue to parsing
                     } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) {
                         if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
                             pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
                         else
-                            ; // Invialid CSS, continue to parsing
+                            ; // Invalid CSS, continue to parsing
                     } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) {
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
                     } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) {
-                        // Invialid CSS, continue to parsing
+                        // Invalid CSS, continue to parsing
                     } else {
                         // any vendor checks here
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
@@ -329,7 +329,7 @@
         }
         pRSNIEs->len +=6;
 
-        // RSN Capabilites
+        // RSN Capabilities
         if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
             memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
         } else {
diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c
index 732ba88..2b6ae1e 100644
--- a/drivers/staging/vt6655/wpactl.c
+++ b/drivers/staging/vt6655/wpactl.c
@@ -77,7 +77,7 @@
 
 /*
  * Description:
- *      register netdev for wpa supplicant deamon
+ *      register netdev for wpa supplicant daemon
  *
  * Parameters:
  *  In:
@@ -164,7 +164,7 @@
 
 /*
  * Description:
- *      Set enable/disable dev for wpa supplicant deamon
+ *      Set enable/disable dev for wpa supplicant daemon
  *
  * Parameters:
  *  In:
@@ -847,7 +847,7 @@
           if(!bWepEnabled)  pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
 	else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
             //pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
-            //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encrytion
+            //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encryption
            }
 //mike save old encryption status
 	pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus;
diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c
index 66e2eea..82e93cb 100644
--- a/drivers/staging/vt6655/wroute.c
+++ b/drivers/staging/vt6655/wroute.c
@@ -18,7 +18,7 @@
  *
  * File: wroute.c
  *
- * Purpose: handle WMAC frame relay & filterring
+ * Purpose: handle WMAC frame relay & filtering
  *
  * Author: Lyndon Chen
  *
diff --git a/drivers/staging/vt6656/80211mgr.h b/drivers/staging/vt6656/80211mgr.h
index 515b9c1..e5db73b 100644
--- a/drivers/staging/vt6656/80211mgr.h
+++ b/drivers/staging/vt6656/80211mgr.h
@@ -191,7 +191,7 @@
 
 
 //
-// Cipher Suite Selectors defiened in 802.11i
+// Cipher Suite Selectors defined in 802.11i
 //
 #define WLAN_11i_CSS_USE_GROUP              0
 #define WLAN_11i_CSS_WEP40                  1
@@ -720,7 +720,7 @@
 
 } WLAN_FR_AUTHEN, *PWLAN_FR_AUTHEN;
 
-// Deauthenication
+// Deauthentication
 typedef struct tagWLAN_FR_DEAUTHEN {
 
     unsigned int                    uType;
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index 06f27f6..3855015 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -27,7 +27,7 @@
  *
  * Functions:
  *      BBuGetFrameTime        - Calculate data frame transmitting time
- *      BBvCaculateParameter   - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
+ *      BBvCalculateParameter   - Calculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
  *      BBbVT3184Init          - VIA VT3184 baseband chip init code
  *      BBvLoopbackOn          - Turn on BaseBand Loopback mode
  *      BBvLoopbackOff         - Turn off BaseBand Loopback mode
@@ -741,7 +741,7 @@
 }
 
 /*
- * Description: Caculate Length, Service, and Signal fields of Phy for Tx
+ * Description: Calculate Length, Service, and Signal fields of Phy for Tx
  *
  * Parameters:
  *  In:
@@ -757,7 +757,7 @@
  *
  */
 void
-BBvCaculateParameter (
+BBvCalculateParameter (
       PSDevice pDevice,
       unsigned int cbFrameLength,
       WORD wRate,
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index 8db8cd0..844d5a8 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -104,7 +104,7 @@
      WORD wRate
     );
 
-void BBvCaculateParameter(PSDevice pDevice,
+void BBvCalculateParameter(PSDevice pDevice,
 			  unsigned int cbFrameLength,
 			  WORD wRate,
 			  BYTE byPacketType,
diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c
index 0999367..2ac066d 100644
--- a/drivers/staging/vt6656/bssdb.c
+++ b/drivers/staging/vt6656/bssdb.c
@@ -226,7 +226,7 @@
                 if (pSelect == NULL) {
                     pSelect = pCurrBSS;
                 } else {
-                    // compare RSSI, select signal strong one
+                    // compare RSSI, select the strongest signal 
                     if (pCurrBSS->uRSSI < pSelect->uRSSI) {
                         pSelect = pCurrBSS;
                     }
@@ -274,9 +274,9 @@
             if (pMgmt->sBSSList[ii].bActive &&
 		!compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
 				    pMgmt->abyCurrBSSID)) {
- //mike mark: there are two same BSSID in list if that AP is in hidden ssid mode,one 's SSID is null,
- //                 but other's is obvious, so if it acssociate with your STA  exactly,you must keep two
- //                 of them!!!!!!!!!
+ //mike mark: there are two BSSID's in list. If that AP is in hidden ssid mode, one SSID is null,
+ //                 but other's might not be obvious, so if it associate's with your STA,
+ //                 you must keep the two of them!!
                // bKeepCurrBSSID = FALSE;
                 continue;
             }
@@ -489,7 +489,7 @@
     }
 
     if (pDevice->bUpdateBBVGA) {
-        // Moniter if RSSI is too strong.
+        // Monitor if RSSI is too strong.
         pBSSList->byRSSIStatCnt = 0;
         RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
         pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX;
@@ -621,7 +621,7 @@
 
     if (pRxPacket->uRSSI != 0) {
         RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &ldBm);
-        // Moniter if RSSI is too strong.
+        // Monitor if RSSI is too strong.
         pBSSList->byRSSIStatCnt++;
         pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
         pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm;
@@ -687,8 +687,8 @@
 /*+
  *
  * Routine Description:
- *    Find an empty node and allocated; if no empty found,
- *    instand used of most inactive one.
+ *    Find an empty node and allocate it; if no empty node
+ *    is found, then use the most inactive one.
  *
  * Return Value:
  *    None
@@ -718,7 +718,7 @@
         }
     }
 
-    // if not found replace uInActiveCount is largest one.
+    // if not found replace uInActiveCount with the largest one.
     if ( ii == (MAX_NODE_NUM + 1)) {
         *puNodeIndex = SelectIndex;
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Replace inactive node = %d\n", SelectIndex);
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index e3ddc0b..826520b 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -28,9 +28,9 @@
  *      CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet
  *      CARDvSetLoopbackMode - Set Loopback mode
  *      CARDbSoftwareReset - Sortware reset NIC
- *      CARDqGetTSFOffset - Caculate TSFOffset
+ *      CARDqGetTSFOffset - Calculate TSFOffset
  *      CARDbGetCurrentTSF - Read Current NIC TSF counter
- *      CARDqGetNextTBTT - Caculate Next Beacon TSF counter
+ *      CARDqGetNextTBTT - Calculate Next Beacon TSF counter
  *      CARDvSetFirstNextTBTT - Set NIC Beacon time
  *      CARDvUpdateNextTBTT - Sync. NIC Beacon time
  *      CARDbRadioPowerOff - Turn Off NIC Radio Power
@@ -40,7 +40,7 @@
  *
  * Revision History:
  *      06-10-2003 Bryan YC Fan:  Re-write codes to support VT3253 spec.
- *      08-26-2003 Kyle Hsu:      Modify the defination type of dwIoBase.
+ *      08-26-2003 Kyle Hsu:      Modify the definition type of dwIoBase.
  *      09-01-2003 Bryan YC Fan:  Add vUpdateIFS().
  *
  */
@@ -200,7 +200,7 @@
 }
 
 /*
- * Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode.
+ * Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode.
  *
  * Parameters:
  *  In:
@@ -214,7 +214,7 @@
  *
  */
 void
-CARDvCaculateOFDMRParameter (
+CARDvCalculateOFDMRParameter (
       WORD wRate,
       BYTE byBBType,
      PBYTE pbyTxRate,
@@ -337,7 +337,7 @@
     int     i;
 
     //RSPINF_b_1
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          swGetCCKControlRate(pDevice, RATE_1M),
                          PK_TYPE_11B,
@@ -347,7 +347,7 @@
     );
 
     ///RSPINF_b_2
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          swGetCCKControlRate(pDevice, RATE_2M),
                          PK_TYPE_11B,
@@ -357,7 +357,7 @@
     );
 
     //RSPINF_b_5
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          swGetCCKControlRate(pDevice, RATE_5M),
                          PK_TYPE_11B,
@@ -367,7 +367,7 @@
     );
 
     //RSPINF_b_11
-    BBvCaculateParameter(pDevice,
+    BBvCalculateParameter(pDevice,
                          14,
                          swGetCCKControlRate(pDevice, RATE_11M),
                          PK_TYPE_11B,
@@ -377,55 +377,55 @@
     );
 
     //RSPINF_a_6
-    CARDvCaculateOFDMRParameter (RATE_6M,
+    CARDvCalculateOFDMRParameter (RATE_6M,
                                  byBBType,
                                  &abyTxRate[0],
                                  &abyRsvTime[0]);
 
     //RSPINF_a_9
-    CARDvCaculateOFDMRParameter (RATE_9M,
+    CARDvCalculateOFDMRParameter (RATE_9M,
                                  byBBType,
                                  &abyTxRate[1],
                                  &abyRsvTime[1]);
 
     //RSPINF_a_12
-    CARDvCaculateOFDMRParameter (RATE_12M,
+    CARDvCalculateOFDMRParameter (RATE_12M,
                                  byBBType,
                                  &abyTxRate[2],
                                  &abyRsvTime[2]);
 
     //RSPINF_a_18
-    CARDvCaculateOFDMRParameter (RATE_18M,
+    CARDvCalculateOFDMRParameter (RATE_18M,
                                  byBBType,
                                  &abyTxRate[3],
                                  &abyRsvTime[3]);
 
     //RSPINF_a_24
-    CARDvCaculateOFDMRParameter (RATE_24M,
+    CARDvCalculateOFDMRParameter (RATE_24M,
                                  byBBType,
                                  &abyTxRate[4],
                                  &abyRsvTime[4]);
 
     //RSPINF_a_36
-    CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_36M),
+    CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_36M),
                                  byBBType,
                                  &abyTxRate[5],
                                  &abyRsvTime[5]);
 
     //RSPINF_a_48
-    CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_48M),
+    CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_48M),
                                  byBBType,
                                  &abyTxRate[6],
                                  &abyRsvTime[6]);
 
     //RSPINF_a_54
-    CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M),
+    CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M),
                                  byBBType,
                                  &abyTxRate[7],
                                  &abyRsvTime[7]);
 
     //RSPINF_a_72
-    CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M),
+    CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M),
                                  byBBType,
                                  &abyTxRate[8],
                                  &abyRsvTime[8]);
@@ -640,7 +640,7 @@
 
 
 /*
- * Description: Caculate TSF offset of two TSF input
+ * Description: Calculate TSF offset of two TSF input
  *              Get TSF Offset from RxBCN's TSF and local TSF
  *
  * Parameters:
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index 171dd68..6370d103 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -478,7 +478,7 @@
     unsigned int                        cbTD;
 
     //
-    //  Variables to track resources for the Interript In Pipe
+    //  Variables to track resources for the Interrupt In Pipe
     //
     INT_BUFFER                  intBuf;
     BOOL                        fKillEventPollingThread;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index 3aa895e..28edf9e 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -748,7 +748,7 @@
     if ((*pbyRSSI != 0) &&
         (pMgmt->pCurrBSS!=NULL)) {
         RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
-        // Moniter if RSSI is too strong.
+        // Monitor if RSSI is too strong.
         pMgmt->pCurrBSS->byRSSIStatCnt++;
         pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT;
         pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm;
diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c
index 682002a..0a73d40 100644
--- a/drivers/staging/vt6656/hostap.c
+++ b/drivers/staging/vt6656/hostap.c
@@ -18,7 +18,7 @@
  *
  * File: hostap.c
  *
- * Purpose: handle hostap deamon ioctl input/out functions
+ * Purpose: handle hostap daemon ioctl input/out functions
  *
  * Author: Lyndon Chen
  *
@@ -48,7 +48,7 @@
 
 /*
  * Description:
- *      register net_device (AP) for hostap deamon
+ *      register net_device (AP) for hostap daemon
  *
  * Parameters:
  *  In:
@@ -176,7 +176,7 @@
 
 /*
  * Description:
- *      remove station function supported for hostap deamon
+ *      remove station function supported for hostap daemon
  *
  * Parameters:
  *  In:
@@ -204,7 +204,7 @@
 
 /*
  * Description:
- *      add a station from hostap deamon
+ *      add a station from hostap daemon
  *
  * Parameters:
  *  In:
@@ -439,9 +439,7 @@
 		return -EINVAL;
 	}
 
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
 		if (param->u.crypt.idx >= MAX_GROUP_KEY)
 			return -EINVAL;
         iNodeIndex = 0;
@@ -663,9 +661,7 @@
 
 	param->u.crypt.err = 0;
 
-	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+	if (is_broadcast_ether_addr(param->sta_addr)) {
         iNodeIndex = 0;
 	} else {
 	    if (BSSbIsSTAInNodeDB(pDevice, param->sta_addr, &iNodeIndex) == FALSE) {
@@ -686,7 +682,7 @@
 
 /*
  * Description:
- *      vt6656_hostap_ioctl main function supported for hostap deamon.
+ *      vt6656_hostap_ioctl main function supported for hostap daemon.
  *
  * Parameters:
  *  In:
@@ -732,8 +728,8 @@
 		break;
 	case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR:
 	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n");
-		return -EOPNOTSUPP;
-		break;
+		ret = -EOPNOTSUPP;
+		goto out;
 	case VIAWGET_HOSTAPD_FLUSH:
 	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n");
         spin_lock_irq(&pDevice->lock);
@@ -777,13 +773,13 @@
 
 	case VIAWGET_HOSTAPD_STA_CLEAR_STATS:
 	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n");
-	    return -EOPNOTSUPP;
-
+	    ret = -EOPNOTSUPP;
+	    goto out;
 	default:
 	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6656_hostap_ioctl: unknown cmd=%d\n",
 		       (int)param->cmd);
-		return -EOPNOTSUPP;
-		break;
+		ret = -EOPNOTSUPP;
+		goto out;
 	}
 
 
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index eba4b50..bba31ca 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -149,7 +149,7 @@
 					pMgmt->sNodeDBTable[0].bRxPSPoll =
 						FALSE;
 				} else if (pMgmt->byDTIMCount == 0) {
-					/* check if mutltcast tx bufferring */
+					/* check if multicast tx buffering */
 					pMgmt->byDTIMCount =
 						pMgmt->byDTIMPeriod-1;
 					pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE;
diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c
index 5b9a84f..b6af5f6 100644
--- a/drivers/staging/vt6656/ioctl.c
+++ b/drivers/staging/vt6656/ioctl.c
@@ -526,11 +526,8 @@
 			pMgmt->abyIBSSSuppRates[3] |= BIT7;
 		}
 
-		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n",
-			pMgmt->abyIBSSSuppRates[2],
-			pMgmt->abyIBSSSuppRates[3],
-			pMgmt->abyIBSSSuppRates[4],
-			pMgmt->abyIBSSSuppRates[5]);
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n",
+			4, pMgmt->abyIBSSSuppRates + 2);
 
 		netif_stop_queue(pDevice->dev);
 		spin_lock_irq(&pDevice->lock);
@@ -620,7 +617,7 @@
 			result = -EFAULT;
 			break;
 		}
-		/* for some AP maybe good authenticate */
+		/* for some AP's maybe a good authentication */
 		if (wpa_Result.key_mgmt == 0x20)
 			pMgmt->Cisco_cckm = 1;
 		else
@@ -644,7 +641,7 @@
 		break;
 
 	default:
-		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not support..\n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not supported..\n");
 	}
 
 	return result;
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index 8b9894b..8f19874 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -674,7 +674,7 @@
 			jj++;
 		}
 
-		wrq->flags = 1; // Should be define'd
+		wrq->flags = 1; // Should be defined
 		wrq->length = jj;
 		memcpy(extra, sock, sizeof(struct sockaddr) * jj);
 		memcpy(extra + sizeof(struct sockaddr) * jj, qual, sizeof(struct iw_quality) * jj);
diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c
index ee62a06..a61fcb95 100644
--- a/drivers/staging/vt6656/key.c
+++ b/drivers/staging/vt6656/key.c
@@ -403,7 +403,7 @@
     BOOL    bReturnValue = FALSE;
 
     if (is_broadcast_ether_addr(pbyBSSID)) {
-        // dealte all key
+        // delete all keys
         if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
             for (i=0;i<MAX_KEY_TABLE;i++) {
                 pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
@@ -618,7 +618,7 @@
 
 
 /*
- * Description: Check Pairewise Key
+ * Description: Check Pairwise Key
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index d536756..ad422de 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -29,14 +29,14 @@
  *   vt6656_probe - module initial (insmod) driver entry
  *   device_remove1 - module remove entry
  *   device_open - allocate dma/descripter resource & initial mac/bbp function
- *   device_xmit - asynchrous data tx function
+ *   device_xmit - asynchronous data tx function
  *   device_set_multi - set mac filter
  *   device_ioctl - ioctl entry
- *   device_close - shutdown mac/bbp & free dma/descripter resource
+ *   device_close - shutdown mac/bbp & free dma/descriptor resource
  *   device_alloc_frag_buf - rx fragement pre-allocated function
  *   device_free_tx_bufs - free tx buffer function
  *   device_dma0_tx_80211- tx 802.11 frame via dma0
- *   device_dma0_xmit- tx PS bufferred frame via dma0
+ *   device_dma0_xmit- tx PS buffered frame via dma0
  *   device_init_registers- initial MAC & BBP & RF internal registers.
  *   device_init_rings- initial tx/rx ring buffer
  *   device_init_defrag_cb- initial & allocate de-fragement buffer.
@@ -316,7 +316,7 @@
 
 
 //
-// Initialiation of MAC & BBP registers
+// Initialization of MAC & BBP registers
 //
 
 static BOOL device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
@@ -639,7 +639,7 @@
   viawget_wpa_header *wpahdr;
   int ii=0;
  // wait_queue_head_t	Set_wait;
-  //send device close to wpa_supplicnat layer
+  //send device close to wpa_supplicant layer
     if (pDevice->bWPADEVUp==TRUE) {
                  wpahdr = (viawget_wpa_header *)pDevice->skb->data;
                  wpahdr->type = VIAWGET_DEVICECLOSE_MSG;
@@ -1010,7 +1010,7 @@
     }
 
     if (device_init_defrag_cb(pDevice)== FALSE) {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Initial defragement cb fail \n");
+        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Initial defragment cb fail \n");
         goto free_rx_tx;
     }
 
@@ -1296,7 +1296,7 @@
     return crc;
 }
 
-//find out  the start  position of str2 from str1
+//find out the start  position of str2 from str1
 static unsigned char *kstrstr(const unsigned char *str1,
 			      const unsigned char *str2) {
   int str1_len = strlen(str1);
@@ -1345,7 +1345,7 @@
        }
 
    memset(buf2,0,100);
-   memcpy(buf2,start_p,end_p-start_p);    //get the tartget line
+   memcpy(buf2,start_p,end_p-start_p);    //get the target line
    buf2[end_p-start_p]='\0';
 
    //find value
@@ -1396,7 +1396,7 @@
 	  }
 
      if(!(filp->f_op) || !(filp->f_op->read) ||!(filp->f_op->write)) {
-           printk("file %s cann't readable or writable?\n",config_path);
+           printk("file %s is not read or writeable?\n",config_path);
 	  result = -1;
 	  goto error1;
      	}
@@ -1969,7 +1969,7 @@
 
 	default:
 		rc = -EOPNOTSUPP;
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not support..%x\n", cmd);
+        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not supported..%x\n", cmd);
 
 
     }
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index b313677..ab3a554 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -19,7 +19,7 @@
  *
  * File: power.c
  *
- * Purpose: Handles 802.11 power management  functions
+ * Purpose: Handles 802.11 power management functions
  *
  * Author: Lyndon Chen
  *
diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c
index 3fd0478..593cdc7 100644
--- a/drivers/staging/vt6656/rf.c
+++ b/drivers/staging/vt6656/rf.c
@@ -26,7 +26,7 @@
  * Date: Feb. 19, 2004
  *
  * Functions:
- *      IFRFbWriteEmbeded      - Embeded write RF register via MAC
+ *      IFRFbWriteEmbedded      - Embedded write RF register via MAC
  *
  * Revision History:
  *
@@ -711,7 +711,7 @@
 /*---------------------  Export Functions  --------------------------*/
 
 /*
- * Description: Write to IF/RF, by embeded programming
+ * Description: Write to IF/RF, by embedded programming
  *
  * Parameters:
  *  In:
@@ -722,7 +722,7 @@
  * Return Value: TRUE if succeeded; FALSE if failed.
  *
  */
-BOOL IFRFbWriteEmbeded (PSDevice pDevice, DWORD dwData)
+BOOL IFRFbWriteEmbedded (PSDevice pDevice, DWORD dwData)
 {
     BYTE        pbyData[4];
 
@@ -828,23 +828,23 @@
         case RF_AL2230 :
             if (pDevice->byCurPwr >= AL2230_PWR_IDX_LEN)
                 return FALSE;
-            bResult &= IFRFbWriteEmbeded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]);
+            bResult &= IFRFbWriteEmbedded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]);
             if (uRATE <= RATE_11M)
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             else
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             break;
 
         case RF_AL2230S :
             if (pDevice->byCurPwr >= AL2230_PWR_IDX_LEN)
                 return FALSE;
-            bResult &= IFRFbWriteEmbeded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]);
+            bResult &= IFRFbWriteEmbedded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]);
             if (uRATE <= RATE_11M) {
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             }else {
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
             }
             break;
 
@@ -854,10 +854,10 @@
                 DWORD       dwMax7230Pwr;
 
                 if (uRATE <= RATE_11M) { //RobertYu:20060426, for better 11b mask
-                    bResult &= IFRFbWriteEmbeded(pDevice, 0x111BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
+                    bResult &= IFRFbWriteEmbedded(pDevice, 0x111BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
                 }
                 else {
-                    bResult &= IFRFbWriteEmbeded(pDevice, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
+                    bResult &= IFRFbWriteEmbedded(pDevice, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
                 }
 
                 if (pDevice->byCurPwr > AL7230_PWR_IDX_LEN) return FALSE;
@@ -866,7 +866,7 @@
                 dwMax7230Pwr = 0x080C0B00 | ( (pDevice->byCurPwr) << 12 ) |
                                  (BY_AL7230_REG_LEN << 3 )  | IFREGCTL_REGW;
 
-                bResult &= IFRFbWriteEmbeded(pDevice, dwMax7230Pwr);
+                bResult &= IFRFbWriteEmbedded(pDevice, dwMax7230Pwr);
                 break;
             }
             break;
@@ -879,7 +879,7 @@
                 return FALSE;
             dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x17 << 8 ) /* Reg7 */ |
                            (BY_VT3226_REG_LEN << 3 )  | IFREGCTL_REGW;
-            bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr);
+            bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr);
             break;
         }
 
@@ -894,27 +894,27 @@
 
                 dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0xE07 << 8 ) /* Reg7 */ |   //RobertYu:20060420, TWIF 1.10
                                (BY_VT3226_REG_LEN << 3 )  | IFREGCTL_REGW;
-                bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr);
+                bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr);
 
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x03C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x03C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW);
                 if (pDevice->sMgmtObj.eScanState != WMAC_NO_SCANNING) {
                     // scanning, the channel number is pDevice->uScanChannel
                     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11B mode uCurrChannel[%d]\n", pDevice->sMgmtObj.uScanChannel);
-                    bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uScanChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate
+                    bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uScanChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate
                 } else {
                     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11B mode uCurrChannel[%d]\n", pDevice->sMgmtObj.uCurrChannel);
-                    bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uCurrChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate
+                    bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uCurrChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate
                 }
 
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x015C0800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060420, ok now, new switching power (mini-pci can have bigger power consumption)
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x015C0800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060420, ok now, new switching power (mini-pci can have bigger power consumption)
             } else {
                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11G mode\n");
                 dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x7 << 8 ) /* Reg7 */ |   //RobertYu:20060420, TWIF 1.10
                                (BY_VT3226_REG_LEN << 3 )  | IFREGCTL_REGW;
-                bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr);
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x00C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060327
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111
-                bResult &= IFRFbWriteEmbeded(pDevice, 0x00900800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111
+                bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr);
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x00C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060327
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111
+                bResult &= IFRFbWriteEmbedded(pDevice, 0x00900800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111
             }
             break;
         }
@@ -929,7 +929,7 @@
 
             dwVT3342Pwr =  ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x27 << 8 ) /* Reg7 */ |
                             (BY_VT3342_REG_LEN << 3 )  | IFREGCTL_REGW;
-            bResult &= IFRFbWriteEmbeded(pDevice, dwVT3342Pwr);
+            bResult &= IFRFbWriteEmbedded(pDevice, dwVT3342Pwr);
             break;
         }
 
@@ -1048,7 +1048,7 @@
                     wLength1,
                     abyArray
                     );
-    //Channle Table 0
+    //Channel Table 0
     wValue = 0;
     while ( wLength2 > 0 ) {
 
@@ -1106,7 +1106,7 @@
                     wLength1,
                     abyArray);
 
-        //Channle Table 0
+        //Channel Table 0
         wValue = 0;
         while ( wLength2 > 0 ) {
 
@@ -1141,9 +1141,9 @@
 
     bResult = TRUE;
     if( b11bMode )
-        bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[byChannel-1]);
+        bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[byChannel-1]);
     else
-        bResult &= IFRFbWriteEmbeded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060412
+        bResult &= IFRFbWriteEmbedded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060412
 
     return bResult;
 }
diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h
index f5ba8fd..72eb27a 100644
--- a/drivers/staging/vt6656/rf.h
+++ b/drivers/staging/vt6656/rf.h
@@ -63,7 +63,7 @@
 extern const BYTE RFaby11aChannelIndex[200];
 /*---------------------  Export Functions  --------------------------*/
 
-BOOL IFRFbWriteEmbeded(PSDevice pDevice, DWORD dwData);
+BOOL IFRFbWriteEmbedded(PSDevice pDevice, DWORD dwData);
 BOOL RFbSetPower(PSDevice pDevice, unsigned int uRATE, unsigned int uCH);
 
 BOOL RFbRawSetPower(
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index b6e04e7..3390838 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -841,7 +841,7 @@
 	if ((uDMAIdx == TYPE_ATIMDMA) || (uDMAIdx == TYPE_BEACONDMA)) {
 		PSTxDataHead_ab pBuf = (PSTxDataHead_ab) pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             //Get Duration and TimeStampOff
@@ -858,10 +858,10 @@
             if (byFBOption == AUTO_FB_NONE) {
                 PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
                 //Get SignalField,ServiceField,Length
-                BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+                BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                     (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
                 );
-                BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+                BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                     (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
                 );
                 //Get Duration and TimeStamp
@@ -881,10 +881,10 @@
                 // Auto Fallback
                 PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
                 //Get SignalField,ServiceField,Length
-                BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+                BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                     (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
                 );
-                BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+                BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                     (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
                 );
                 //Get Duration and TimeStamp
@@ -907,7 +907,7 @@
             // Auto Fallback
             PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             //Get Duration and TimeStampOff
@@ -924,7 +924,7 @@
         } else {
             PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             //Get Duration and TimeStampOff
@@ -942,7 +942,7 @@
     else if (byPktType == PK_TYPE_11B) {
             PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
                 (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             //Get Duration and TimeStampOff
@@ -987,17 +987,17 @@
         uRTSFrameLen -= 4;
     }
 
-    // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account.
+    // Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, so we don't need to take them into account.
     //       Otherwise, we need to modified codes for them.
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
         if (byFBOption == AUTO_FB_NONE) {
             PSRTS_g pBuf = (PSRTS_g)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
@@ -1035,11 +1035,11 @@
         else {
            PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
             );
             pBuf->wTransmitLength_a = cpu_to_le16(wLen);
@@ -1084,7 +1084,7 @@
         if (byFBOption == AUTO_FB_NONE) {
             PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -1119,7 +1119,7 @@
         else {
             PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
             );
             pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -1155,7 +1155,7 @@
     else if (byPktType == PK_TYPE_11B) {
         PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
         //Get SignalField,ServiceField,Length
-        BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+        BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
             (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
         );
         pBuf->wTransmitLength = cpu_to_le16(wLen);
@@ -1221,7 +1221,7 @@
             // Auto Fall back
             PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
@@ -1246,7 +1246,7 @@
         } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
             PSCTS pBuf = (PSCTS)pvCTS;
             //Get SignalField,ServiceField,Length
-            BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
                 (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
             );
             pBuf->wTransmitLength_b = cpu_to_le16(wLen);
@@ -1827,7 +1827,7 @@
  *
  * Parameters:
  *  In:
- *      pDevice         - Pointer to adpater
+ *      pDevice         - Pointer to adapter
  *      dwTxBufferAddr  - Transmit Buffer
  *      pPacket         - Packet from upper layer
  *      cbPacketSize    - Transmit Data Length
@@ -2198,7 +2198,7 @@
 
     if (bIsPSPOLL) {
         // The MAC will automatically replace the Duration-field of MAC header by Duration-field
-        // of  FIFO control header.
+        // of FIFO control header.
         // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
         // in the same place of other packet's Duration-field).
         // And it will cause Cisco-AP to issue Disassociation-packet
@@ -2272,7 +2272,7 @@
         wCurrentRate = RATE_6M;
         pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
         //Get SignalField,ServiceField,Length
-        BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
+        BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
             (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField)
         );
         //Get Duration and TimeStampOff
@@ -2285,7 +2285,7 @@
         pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
         pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
         //Get SignalField,ServiceField,Length
-        BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
+        BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
             (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField)
         );
         //Get Duration and TimeStampOff
@@ -2473,7 +2473,7 @@
         cbMacHdLen = WLAN_HDR_ADDR3_LEN;
     }
 
-    // hostapd deamon ext support rate patch
+    // hostapd daemon ext support rate patch
     if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
 
         if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) {
@@ -2591,7 +2591,7 @@
     pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc);
     memcpy(pbyPayloadHead, (skb->data + cbMacHdLen), cbFrameBodySize);
 
-    // replace support rate, patch for hostapd deamon( only support 11M)
+    // replace support rate, patch for hostapd daemon( only support 11M)
     if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
         if (cbExtSuppRate != 0) {
             if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0)
@@ -2770,7 +2770,7 @@
                 pMgmt->abyPSTxMap[0] |= byMask[0];
                 return 0;
             }
-            // muticast/broadcast data rate
+            // multicast/broadcast data rate
 
             if (pDevice->byBBType != BB_TYPE_11A)
                 pDevice->wCurrentRate = RATE_2M;
@@ -2855,7 +2855,7 @@
 			  }
 			  PRINT_K("Authentication completed!!\n");
                         }
-		    else if((Key_info & BIT3) && (Descriptor_type==2) &&  //RSN pairse-key challenge
+		    else if((Key_info & BIT3) && (Descriptor_type==2) &&  //RSN pairwise-key challenge
 			       (Key_info & BIT8) && (Key_info & BIT9)) {
 			  pDevice->fWPA_Authened = TRUE;
                             PRINT_K("WPA2 Authentication completed!!\n");
diff --git a/drivers/staging/vt6656/tcrc.c b/drivers/staging/vt6656/tcrc.c
index e25021e..2237eeb 100644
--- a/drivers/staging/vt6656/tcrc.c
+++ b/drivers/staging/vt6656/tcrc.c
@@ -18,7 +18,7 @@
  *
  * File: tcrc.c
  *
- * Purpose: Implement functions to caculate CRC
+ * Purpose: Implement functions to calculate CRC
  *
  * Author: Tevin Chen
  *
diff --git a/drivers/staging/vt6656/tcrc.h b/drivers/staging/vt6656/tcrc.h
index 4dfd01e..dc54bd8 100644
--- a/drivers/staging/vt6656/tcrc.h
+++ b/drivers/staging/vt6656/tcrc.h
@@ -18,7 +18,7 @@
  *
  * File: tcrc.h
  *
- * Purpose: Implement functions to caculate CRC
+ * Purpose: Implement functions to calculate CRC
  *
  * Author: Tevin Chen
  *
diff --git a/drivers/staging/vt6656/tether.c b/drivers/staging/vt6656/tether.c
index 4f368f1..083b215 100644
--- a/drivers/staging/vt6656/tether.c
+++ b/drivers/staging/vt6656/tether.c
@@ -25,7 +25,7 @@
  * Date: May 21, 1996
  *
  * Functions:
- *      ETHbyGetHashIndexByCrc32 - Caculate multicast hash value by CRC32
+ *      ETHbyGetHashIndexByCrc32 - Calculate multicast hash value by CRC32
  *      ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not
  *
  * Revision History:
@@ -50,7 +50,7 @@
 
 
 /*
- * Description: Caculate multicast hash value by CRC32
+ * Description: Calculate multicast hash value by CRC32
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c
index 0715636..003123e 100644
--- a/drivers/staging/vt6656/tkip.c
+++ b/drivers/staging/vt6656/tkip.c
@@ -168,7 +168,7 @@
 
 
 /*
- * Description: Caculate RC4Key fom TK, TA, and TSC
+ * Description: Calculate RC4Key fom TK, TA, and TSC
  *
  * Parameters:
  *  In:
diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c
index 9d2caa8..586fbe1 100644
--- a/drivers/staging/vt6656/wcmd.c
+++ b/drivers/staging/vt6656/wcmd.c
@@ -263,7 +263,7 @@
  *
  *
  * Return Value:
- *    A ptr to Tx frame or NULL on allocation failue
+ *    A ptr to Tx frame or NULL on allocation failure
  *
 -*/
 
@@ -751,7 +751,7 @@
                       pDevice->nTxDataTimeCout = 0;
 		 }
 		 else {
-		   // printk("mike:-->First time triger TimerTxData InSleep\n");
+		   // printk("mike:-->First time trigger TimerTxData InSleep\n");
 		 }
 		pDevice->IsTxDataTrigger = TRUE;
                 add_timer(&pDevice->sTimerTxData);
@@ -794,7 +794,7 @@
 			DBG_PRT(MSG_LEVEL_DEBUG,
 				KERN_INFO "vMgrCreateOwnIBSS fail!\n");
                 }
-                // alway turn off unicast bit
+                // always turn off unicast bit
                 MACvRegBitsOff(pDevice, MAC_REG_RCR, RCR_UNICAST);
                 pDevice->byRxMode &= ~RCR_UNICAST;
                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode );
@@ -946,7 +946,7 @@
                   pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
                   pItemSSID->len = 0;
                   memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN);
-                //clear dessire SSID
+                //clear desired SSID
                 pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
                 pItemSSID->len = 0;
                 memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN);
diff --git a/drivers/staging/vt6656/wctl.c b/drivers/staging/vt6656/wctl.c
index c231ae7..9249263 100644
--- a/drivers/staging/vt6656/wctl.c
+++ b/drivers/staging/vt6656/wctl.c
@@ -89,7 +89,7 @@
             ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH);
         }
     }
-    /* Not fount in cache - insert */
+    /* Not found in cache - insert */
     pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr];
     pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
     memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index f08e2d1..7db6a8d 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -27,7 +27,7 @@
  *
  * Functions:
  *      nsMgrObjectInitial - Initialize Management Objet data structure
- *      vMgrObjectReset - Reset Management Objet data structure
+ *      vMgrObjectReset - Reset Management Object data structure
  *      vMgrAssocBeginSta - Start associate function
  *      vMgrReAssocBeginSta - Start reassociate function
  *      vMgrDisassocBeginSta - Start disassociate function
@@ -54,7 +54,7 @@
  *      bMgrPrepareBeaconToSend - Prepare Beacon frame
  *      s_vMgrLogStatus - Log 802.11 Status
  *      vMgrRxManagePacket - Rcv management frame dispatch function
- *      s_vMgrFormatTIM- Assember TIM field of beacon
+ *      s_vMgrFormatTIM- Assembler TIM field of beacon
  *      vMgrTimerInit- Initial 1-sec and command call back funtions
  *
  * Revision History:
@@ -2032,7 +2032,7 @@
                 }
 
                 //
-                // Preamble may change dynamiclly
+                // Preamble may change dynamically
                 //
                 byOldPreambleType = pDevice->byPreambleType;
                 if (WLAN_GET_CAP_INFO_SHORTPREAMBLE(pBSSList->wCapInfo)) {
@@ -2044,7 +2044,7 @@
                 if (pDevice->byPreambleType != byOldPreambleType)
                     CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
             //
-            // Basic Rate Set may change dynamiclly
+            // Basic Rate Set may change dynamically
             //
             if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) {
                 uRateLen = WLAN_RATES_MAXLEN_11B;
@@ -2188,7 +2188,7 @@
             // During dpc, already in spinlocked.
             if (BSSbIsSTAInNodeDB(pDevice, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) {
 
-                // Update the STA, (Techically the Beacons of all the IBSS nodes
+                // Update the STA, (Technically the Beacons of all the IBSS nodes
 		        // should be identical, but that's not happening in practice.
                 pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
                                                         (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
@@ -2722,7 +2722,7 @@
             memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
 
             // Add current BSS to Candidate list
-            // This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
+            // This should only work for WPA2 BSS, and WPA2 BSS check must be done before.
             if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
 		BOOL bResult = bAdd_PMKID_Candidate((void *) pDevice,
 						    pMgmt->abyCurrBSSID,
@@ -3181,7 +3181,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -3353,7 +3353,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -3528,7 +3528,7 @@
     memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
     memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
 
-    // Set the capibility and listen interval
+    // Set the capability and listen interval
     *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
     *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
 
@@ -3749,7 +3749,7 @@
  *
  *
  * Return Value:
- *    A ptr to frame or NULL on allocation failue
+ *    A ptr to frame or NULL on allocation failure
  *
 -*/
 
@@ -3792,7 +3792,7 @@
     memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
     memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
 
-    /* Set the capibility and listen interval */
+    /* Set the capability and listen interval */
     *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
     *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
 
@@ -4004,7 +4004,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
@@ -4077,7 +4077,7 @@
  *
  *
  * Return Value:
- *    PTR to frame; or NULL on allocation failue
+ *    PTR to frame; or NULL on allocation failure
  *
 -*/
 
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index b16d4dd..f6429a2 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -231,7 +231,7 @@
  * Parameters:
  *  In:
  *      byCmd    - Search type
- *      byEncrypt- Encrcypt Type
+ *      byEncrypt- Encrypt Type
  *      pBSSList - BSS list
  *  Out:
  *      none
diff --git a/drivers/staging/vt6656/wpa2.c b/drivers/staging/vt6656/wpa2.c
index d4f3f75..c092697 100644
--- a/drivers/staging/vt6656/wpa2.c
+++ b/drivers/staging/vt6656/wpa2.c
@@ -174,16 +174,16 @@
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
                         bUseGK = TRUE;
                     } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) {
-                        // Invialid CSS, continue to parsing
+                        // Invalid CSS, continue parsing
                     } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) {
                         if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
                             pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
                         else
-                            ; // Invialid CSS, continue to parsing
+                            ; // Invalid CSS, continue parsing
                     } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) {
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
                     } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) {
-                        // Invialid CSS, continue to parsing
+                        // Invalid CSS, continue parsing
                     } else {
                         // any vendor checks here
                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c
index 5435e82..3e65aa1 100644
--- a/drivers/staging/vt6656/wpactl.c
+++ b/drivers/staging/vt6656/wpactl.c
@@ -74,7 +74,7 @@
 
 /*
  * Description:
- *      register netdev for wpa supplicant deamon
+ *      register netdev for wpa supplicant daemon
  *
  * Parameters:
  *  In:
@@ -154,7 +154,7 @@
 
 /*
  * Description:
- *      Set enable/disable dev for wpa supplicant deamon
+ *      Set enable/disable dev for wpa supplicant daemon
  *
  * Parameters:
  *  In:
@@ -326,7 +326,7 @@
 	if ((byKeyDecMode == KEY_CTL_TKIP) &&
 		(param->u.wpa_key.key_len != MAX_KEY_LEN)) {
 		// TKIP Key must be 256 bits
-		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return - TKIP Key must be 256 bits!\n");
 		return -EINVAL;
     }
 	// Check AES key length
diff --git a/drivers/staging/winbond/Kconfig b/drivers/staging/winbond/Kconfig
index 132671d..a29f608 100644
--- a/drivers/staging/winbond/Kconfig
+++ b/drivers/staging/winbond/Kconfig
@@ -1,6 +1,6 @@
 config W35UND
 	tristate "IS89C35 WLAN USB driver"
-	depends on MAC80211 && WLAN && USB && EXPERIMENTAL
+	depends on MAC80211 && WLAN && USB
 	default n
 	---help---
 	  This is highly experimental driver for Winbond WIFI card.
diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h
index d798057..84effc4 100644
--- a/drivers/staging/winbond/localpara.h
+++ b/drivers/staging/winbond/localpara.h
@@ -137,7 +137,7 @@
 	u8	iPowerSaveMode; /* 0 indicates on, 1 indicates off */
 	u8	ATIMmode;
 	u8	ExcludeUnencrypted;
-	/* Unit ime count for the decision to enter PS mode */
+	/* Unit time count for the decision to enter PS mode */
 	u16	CheckCountForPS;
 	u8	boHasTxActivity;/* tx activity has occurred */
 	u8	boMacPsValid;	/* Power save mode obtained from H/W is valid or not */
@@ -187,7 +187,7 @@
 	u8	reserved7[3];
 
 	struct	chan_info CurrentChan;	/* Current channel no. and channel band. It may be changed by scanning. */
-	u8	boHandover;		/* Roaming, Hnadover to other AP. */
+	u8	boHandover;		/* Roaming, Handover to other AP. */
 	u8	boCCAbusy;
 
 	u16	CWMax;			/* It may not be the real value that H/W used */
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
index c9f0e8f..1b8b8ac 100644
--- a/drivers/staging/winbond/mds.c
+++ b/drivers/staging/winbond/mds.c
@@ -569,7 +569,7 @@
 	unsigned char	SendOK = true;
 	u8	RetryCount, TxRate;
 
-	if (pT02->T02_IgnoreResult) /* Don't care the result */
+	if (pT02->T02_IgnoreResult) /* Don't care about the result */
 		return;
 	if (pT02->T02_IsLastMpdu) {
 		/* TODO: DTO -- get the retry count and fragment count */
diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c
index 1b52ebd..560c0ab 100644
--- a/drivers/staging/winbond/mto.c
+++ b/drivers/staging/winbond/mto.c
@@ -23,7 +23,7 @@
 #include "core.h"
 
 /* Declare SQ3 to rate and fragmentation threshold table */
-/* Declare fragmentation thresholds table */
+/* Declare fragmentation threshold table */
 #define MTO_MAX_FRAG_TH_LEVELS		5
 #define MTO_MAX_DATA_RATE_LEVELS	12
 
diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c
index 77a3fff..cabae34 100644
--- a/drivers/staging/winbond/phy_calibration.c
+++ b/drivers/staging/winbond/phy_calibration.c
@@ -399,7 +399,7 @@
 	val |= MASK_ADC_DC_CAL_STR;
 	hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
 
-	/* e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" */
+	/* e. The results are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" */
 #ifdef _DEBUG
 	hw_get_dxx_reg(phw_data, REG_OFFSET_READ, &val);
 	PHY_DEBUG(("[CAL]    REG_OFFSET_READ = 0x%08X\n", val));
@@ -720,7 +720,7 @@
 		for (capture_time = 0; capture_time < 10; capture_time++) {
 			/*
 			 * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
-			 *    enable "IQ alibration Mode II"
+			 *    enable "IQ calibration Mode II"
 			 */
 			reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
 			reg_mode_ctrl &= ~MASK_IQCAL_MODE;
@@ -750,7 +750,7 @@
 
 			/*
 			 * d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to
-			 *    enable "IQ alibration Mode II"
+			 *    enable "IQ calibration Mode II"
 			 */
 			/* hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); */
 			hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
@@ -980,7 +980,7 @@
 	phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
 	/* ; [BB-chip]: Calibration (6f).Send test pattern */
 	/* ; [BB-chip]: Calibration (6g). Search RXGCL optimal value */
-	/* ; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table */
+	/* ; [BB-chip]: Calibration (6h). Calculate TX-path IQ imbalance and setting TX path IQ compensation table */
 	/* phy_set_rf_data(phw_data, 3, (3<<24)|0x025586); */
 
 	msleep(30); /* 20060612.1.a 30ms delay. Add the follow 2 lines */
@@ -1373,7 +1373,7 @@
 /***************************************************************/
 void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency)
 {
-/* figo 20050523 marked this flag for can't compile for relesase */
+/* figo 20050523 marked this flag for can't compile for release */
 #ifdef _DEBUG
 	s32     rx_cal_reg[4];
 	u32     val;
@@ -1397,7 +1397,7 @@
 
 	/*  ; [BB-chip]: Calibration (7f). Send test pattern */
 	/*	; [BB-chip]: Calibration (7g). Search RXGCL optimal value */
-	/*	; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table */
+	/*	; [BB-chip]: Calibration (7h). Calculate RX-path IQ imbalance and setting RX path IQ compensation table */
 
 	result = _rx_iq_calibration_loop_winbond(phw_data, 12589, frequency);
 
@@ -1454,7 +1454,7 @@
 
 	_rxadc_dc_offset_cancellation_winbond(phw_data, frequency);
 	/* _txidac_dc_offset_cancellation_winbond(phw_data); */
-	/* _txqdac_dc_offset_cacellation_winbond(phw_data); */
+	/* _txqdac_dc_offset_cancellation_winbond(phw_data); */
 
 	_tx_iq_calibration_winbond(phw_data);
 	_rx_iq_calibration_winbond(phw_data, frequency);
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
index 1b38d6d..5ecf9a1 100644
--- a/drivers/staging/winbond/reg.c
+++ b/drivers/staging/winbond/reg.c
@@ -693,7 +693,7 @@
 	(0x0E << 24) | 0x5557DC, /* 1555F ; IBSC  (0x0E) -- IRLNA & IRLNB (PTAT & Const current)=01/01; FA5976B_1.3F */
 	(0x10 << 24) | 0x000C20, /* 00030 ; TMODA (0x10) -- LNA_gain_step=0011 ; LNA=15/16dB */
 	(0x11 << 24) | 0x0C0022, /* 03000 ; TMODB (0x11) -- Turn ON RX-Q path Test Switch; To improve IQ path group delay (FA5976A_1.3C) */
-	(0x12 << 24) | 0x000024  /* TMODC (0x12) -- Turn OFF Tempearure sensor */
+	(0x12 << 24) | 0x000024  /* TMODC (0x12) -- Turn OFF Temperature sensor */
 };
 
 u32 w89rf242_channel_data_24[][2] = {
diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h
index 8f4596c..652ae70 100644
--- a/drivers/staging/winbond/sme_api.h
+++ b/drivers/staging/winbond/sme_api.h
@@ -12,7 +12,6 @@
 #include "localpara.h"
 
 /****************** CONSTANT AND MACRO SECTION ******************************/
-#define _INLINE				__inline
 
 #define MEDIA_STATE_DISCONNECTED	0
 #define MEDIA_STATE_CONNECTED		1
@@ -26,17 +25,17 @@
 
 /* OID_802_11_BSSID */
 s8 sme_get_bssid(void *pcore_data, u8 *pbssid);
-s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Not use */
+s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Unused */
 s8 sme_set_desired_bssid(void *pcore_data, u8 *pbssid);
 
 /* OID_802_11_SSID */
 s8 sme_get_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);
-s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Not use */
+s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Unused */
 s8 sme_set_desired_ssid(void *pcore_data, u8 *pssid, u8 ssid_len);
 
 /* OID_802_11_INFRASTRUCTURE_MODE */
 s8 sme_get_bss_type(void *pcore_data, u8 *pbss_type);
-s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Not use */
+s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Unused */
 s8 sme_set_desired_bss_type(void *pcore_data, u8 bss_type);
 
 /* OID_802_11_FRAGMENTATION_THRESHOLD */
@@ -107,7 +106,7 @@
 s8 sme_set_reload_defaults(void *pcore_data, u8 reload_type);
 
 
-/*------------------------- none-standard ----------------------------------*/
+/*------------------------- non-standard ----------------------------------*/
 s8 sme_get_connect_status(void *pcore_data, u8 *pstatus);
 /*--------------------------------------------------------------------------*/
 
@@ -138,7 +137,7 @@
 s8 sme_get_txrate_policy(void *pcore_data, u8 *policy);
 s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin);
 s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax);
-s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff);
+s8 sme_get_ms_radio_mode(void *pcore_data, u8 *pMsRadioOff);
 s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff);
 
 void sme_get_tx_power_level(void *pcore_data, u32 *TxPower);
diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c
index da595f1..1bff7d1 100644
--- a/drivers/staging/winbond/wb35reg.c
+++ b/drivers/staging/winbond/wb35reg.c
@@ -217,7 +217,7 @@
  * This command will be executed with a user defined value. When it completes,
  * this value is useful. For example, hal_set_current_channel will use it.
  * true  : read command process successfully
- * false : register not support
+ * false : register not supported
  */
 unsigned char Wb35Reg_WriteWithCallbackValue(struct hw_data *pHwData,
 						u16 RegisterNo,
@@ -631,7 +631,7 @@
  *  CardComputeCrc --
  *
  *  Description:
- *    Runs the AUTODIN II CRC algorithm on buffer Buffer of length, Length.
+ *    Runs the AUTODIN II CRC algorithm on the buffers Buffer length.
  *
  *  Arguments:
  *    Buffer - the input buffer
diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c
index 5df39d4..30a77cc 100644
--- a/drivers/staging/winbond/wb35tx.c
+++ b/drivers/staging/winbond/wb35tx.c
@@ -1,13 +1,13 @@
-//============================================================================
-//  Copyright (c) 1996-2002 Winbond Electronic Corporation
-//
-//  Module Name:
-//    Wb35Tx.c
-//
-//  Abstract:
-//    Processing the Tx message and put into down layer
-//
-//============================================================================
+/*
+ *  Copyright (c) 1996-2002 Winbond Electronic Corporation
+ *
+ *  Module Name:
+ *    Wb35Tx.c
+ *
+ *  Abstract:
+ *    Processing the Tx message and put into down layer
+ *
+ */
 #include <linux/usb.h>
 #include <linux/gfp.h>
 
@@ -15,7 +15,7 @@
 #include "mds_f.h"
 
 unsigned char
-Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer)
+Wb35Tx_get_tx_buffer(struct hw_data *pHwData, u8 **pBuffer)
 {
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
@@ -25,28 +25,29 @@
 
 static void Wb35Tx(struct wbsoft_priv *adapter);
 
-static void Wb35Tx_complete(struct urb * pUrb)
+static void Wb35Tx_complete(struct urb *pUrb)
 {
 	struct wbsoft_priv *adapter = pUrb->context;
-	struct hw_data *	pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 	struct wb35_mds *pMds = &adapter->Mds;
 
 	printk("wb35: tx complete\n");
-	// Variable setting
+	/* Variable setting */
 	pWb35Tx->EP4vm_state = VM_COMPLETED;
-	pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
-	pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
+	pWb35Tx->EP4VM_status = pUrb->status; /* Store the last result of Irp */
+	/* Set the owner. Free the owner bit always. */
+	pMds->TxOwner[pWb35Tx->TxSendIndex] = 0;
 	pWb35Tx->TxSendIndex++;
 	pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
 
-	if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
+	if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
 		goto error;
 
 	if (pWb35Tx->tx_halt)
 		goto error;
 
-	// The URB is completed, check the result
+	/* The URB is completed, check the result */
 	if (pWb35Tx->EP4VM_status != 0) {
 		printk("URB submission failed\n");
 		pWb35Tx->EP4vm_state = VM_STOP;
@@ -64,43 +65,42 @@
 
 static void Wb35Tx(struct wbsoft_priv *adapter)
 {
-	struct hw_data *	pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 	u8		*pTxBufferAddress;
 	struct wb35_mds *pMds = &adapter->Mds;
-	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx4Urb;
-	int         	retv;
+	struct urb *pUrb = (struct urb *)pWb35Tx->Tx4Urb;
+	int		retv;
 	u32		SendIndex;
 
-
 	if (pHwData->SurpriseRemove)
 		goto cleanup;
 
 	if (pWb35Tx->tx_halt)
 		goto cleanup;
 
-	// Ownership checking
+	/* Ownership checking */
 	SendIndex = pWb35Tx->TxSendIndex;
-	if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
+	/* No more data need to be sent, return immediately */
+	if (!pMds->TxOwner[SendIndex])
 		goto cleanup;
 
 	pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
-	//
-	// Issuing URB
-	//
+
+	/* Issuing URB */
 	usb_fill_bulk_urb(pUrb, pHwData->udev,
 			  usb_sndbulkpipe(pHwData->udev, 4),
-			  pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
+			  pTxBufferAddress, pMds->TxBufferSize[SendIndex],
 			  Wb35Tx_complete, adapter);
 
 	pWb35Tx->EP4vm_state = VM_RUNNING;
 	retv = usb_submit_urb(pUrb, GFP_ATOMIC);
-	if (retv<0) {
+	if (retv < 0) {
 		printk("EP4 Tx Irp sending error\n");
 		goto cleanup;
 	}
 
-	// Check if driver needs issue Irp for EP2
+	/* Check if driver needs issue Irp for EP2 */
 	pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
 	if (pWb35Tx->TxFillCount > 12)
 		Wb35Tx_EP2VM_start(adapter);
@@ -115,10 +115,10 @@
 
 void Wb35Tx_start(struct wbsoft_priv *adapter)
 {
-	struct hw_data * pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
-	// Allow only one thread to run into function
+	/* Allow only one thread to run into function */
 	if (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) {
 		pWb35Tx->EP4vm_state = VM_RUNNING;
 		Wb35Tx(adapter);
@@ -126,7 +126,7 @@
 		atomic_dec(&pWb35Tx->TxFireCounter);
 }
 
-unsigned char Wb35Tx_initial(struct hw_data * pHwData)
+unsigned char Wb35Tx_initial(struct hw_data *pHwData)
 {
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
@@ -135,54 +135,50 @@
 		return false;
 
 	pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!pWb35Tx->Tx2Urb)
-	{
-		usb_free_urb( pWb35Tx->Tx4Urb );
+	if (!pWb35Tx->Tx2Urb) {
+		usb_free_urb(pWb35Tx->Tx4Urb);
 		return false;
 	}
 
 	return true;
 }
 
-//======================================================
-void Wb35Tx_stop(struct hw_data * pHwData)
+void Wb35Tx_stop(struct hw_data *pHwData)
 {
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
-	// Trying to canceling the Trp of EP2
+	/* Try to cancel the Trp of EP2 */
 	if (pWb35Tx->EP2vm_state == VM_RUNNING)
-		usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+		/* Only use unlink, let Wb35Tx_destroy free them */
+		usb_unlink_urb(pWb35Tx->Tx2Urb);
 	pr_debug("EP2 Tx stop\n");
 
-	// Trying to canceling the Irp of EP4
+	/* Try to cancel the Irp of EP4 */
 	if (pWb35Tx->EP4vm_state == VM_RUNNING)
-		usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+		/* Only use unlink, let Wb35Tx_destroy free them */
+		usb_unlink_urb(pWb35Tx->Tx4Urb);
 	pr_debug("EP4 Tx stop\n");
 }
 
-//======================================================
-void Wb35Tx_destroy(struct hw_data * pHwData)
+void Wb35Tx_destroy(struct hw_data *pHwData)
 {
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
-	// Wait for VM stop
+	/* Wait for VM stop */
 	do {
-		msleep(10);  // Delay for waiting function enter 940623.1.a
-	} while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
-	msleep(10);  // Delay for waiting function enter 940623.1.b
+		msleep(10); /* Delay for waiting function enter 940623.1.a */
+	} while ((pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP));
+	msleep(10); /* Delay for waiting function enter 940623.1.b */
 
-	if (pWb35Tx->Tx4Urb)
-		usb_free_urb( pWb35Tx->Tx4Urb );
-
-	if (pWb35Tx->Tx2Urb)
-		usb_free_urb( pWb35Tx->Tx2Urb );
+	usb_free_urb(pWb35Tx->Tx4Urb);
+	usb_free_urb(pWb35Tx->Tx2Urb);
 
 	pr_debug("Wb35Tx_destroy OK\n");
 }
 
 void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
 {
-	struct hw_data * pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 	unsigned char Trigger = false;
 
@@ -199,46 +195,45 @@
 
 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
 
-static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
+static void Wb35Tx_EP2VM_complete(struct urb *pUrb)
 {
 	struct wbsoft_priv *adapter = pUrb->context;
-	struct hw_data *	pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct T02_descriptor	T02, TSTATUS;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
-	u32 *		pltmp = (u32 *)pWb35Tx->EP2_buf;
+	u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
 	u32		i;
 	u16		InterruptInLength;
 
-
-	// Variable setting
+	/* Variable setting */
 	pWb35Tx->EP2vm_state = VM_COMPLETED;
 	pWb35Tx->EP2VM_status = pUrb->status;
 
-	// For Linux 2.4. Interrupt will always trigger
-	if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
+	/* For Linux 2.4. Interrupt will always trigger */
+	if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
 		goto error;
 
 	if (pWb35Tx->tx_halt)
 		goto error;
 
-	//The Urb is completed, check the result
+	/* The Urb is completed, check the result */
 	if (pWb35Tx->EP2VM_status != 0) {
 		printk("EP2 IoCompleteRoutine return error\n");
-		pWb35Tx->EP2vm_state= VM_STOP;
+		pWb35Tx->EP2vm_state = VM_STOP;
 		goto error;
 	}
 
-	// Update the Tx result
+	/* Update the Tx result */
 	InterruptInLength = pUrb->actual_length;
-	// Modify for minimum memory access and DWORD alignment.
-	T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
-	InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
-	InterruptInLength >>= 2; // InterruptInLength/4
+	/* Modify for minimum memory access and DWORD alignment. */
+	T02.value = cpu_to_le32(pltmp[0]) >> 8; /* [31:8] -> [24:0] */
+	InterruptInLength -= 1; /* 20051221.1.c Modify the follow for more stable */
+	InterruptInLength >>= 2; /* InterruptInLength/4 */
 	for (i = 1; i <= InterruptInLength; i++) {
 		T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
 
-		TSTATUS.value = T02.value;  //20061009 anson's endian
-		Mds_SendComplete( adapter, &TSTATUS );
+		TSTATUS.value = T02.value;  /* 20061009 anson's endian */
+		Mds_SendComplete(adapter, &TSTATUS);
 		T02.value = cpu_to_le32(pltmp[i]) >> 8;
 	}
 
@@ -250,10 +245,10 @@
 
 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
 {
-	struct hw_data *	pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
-	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx2Urb;
-	u32 *	pltmp = (u32 *)pWb35Tx->EP2_buf;
+	struct urb *pUrb = (struct urb *)pWb35Tx->Tx2Urb;
+	u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
 	int		retv;
 
 	if (pHwData->SurpriseRemove)
@@ -262,11 +257,10 @@
 	if (pWb35Tx->tx_halt)
 		goto error;
 
-	//
-	// Issuing URB
-	//
-	usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2),
-			  pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32);
+	/* Issuing URB */
+	usb_fill_int_urb(pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev, 2),
+			 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete,
+			 adapter, 32);
 
 	pWb35Tx->EP2vm_state = VM_RUNNING;
 	retv = usb_submit_urb(pUrb, GFP_ATOMIC);
@@ -284,10 +278,10 @@
 
 void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
 {
-	struct hw_data * pHwData = &adapter->sHwData;
+	struct hw_data *pHwData = &adapter->sHwData;
 	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 
-	// Allow only one thread to run into function
+	/* Allow only one thread to run into function */
 	if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
 		pWb35Tx->EP2vm_state = VM_RUNNING;
 		Wb35Tx_EP2VM(adapter);
diff --git a/drivers/staging/winbond/wb35tx_s.h b/drivers/staging/winbond/wb35tx_s.h
index f70f433..715f87d 100644
--- a/drivers/staging/winbond/wb35tx_s.h
+++ b/drivers/staging/winbond/wb35tx_s.h
@@ -3,45 +3,37 @@
 
 #include "mds_s.h"
 
-//====================================
-// IS89C35 Tx related definition
-//====================================
-#define TX_INTERFACE			0	// Interface 1
-#define TX_PIPE					3	// endpoint 4
-#define TX_INTERRUPT			1	// endpoint 2
-#define MAX_INTERRUPT_LENGTH	64	// It must be 64 for EP2 hardware
+/* IS89C35 Tx related definition */
+#define TX_INTERFACE		0	/* Interface 1 */
+#define TX_PIPE			3	/* Endpoint 4 */
+#define TX_INTERRUPT		1	/* Endpoint 2 */
+#define MAX_INTERRUPT_LENGTH	64	/* It must be 64 for EP2 hardware */
 
-
-
-//====================================
-// Internal variable for module
-//====================================
-
-
+/* Internal variable for module */
 struct wb35_tx {
-	// For Tx buffer
+	/* For Tx buffer */
 	u8	TxBuffer[ MAX_USB_TX_BUFFER_NUMBER ][ MAX_USB_TX_BUFFER ];
 
-	// For Interrupt pipe
+	/* For Interrupt pipe */
 	u8	EP2_buf[MAX_INTERRUPT_LENGTH];
 
-	atomic_t	TxResultCount;// For thread control of EP2 931130.4.m
-	atomic_t	TxFireCounter;// For thread control of EP4 931130.4.n
-	u32			ByteTransfer;
+	atomic_t	TxResultCount; /* For thread control of EP2 931130.4.m */
+	atomic_t	TxFireCounter; /* For thread control of EP4 931130.4.n */
+	u32		ByteTransfer;
 
-	u32	    TxSendIndex;// The next index of Mds array to be sent
-	u32	    EP2vm_state; // for EP2vm state
-	u32	    EP4vm_state; // for EP4vm state
-	u32	    tx_halt; // Stopping VM
+	u32	TxSendIndex; /* The next index of Mds array to be sent */
+	u32	EP2vm_state; /* for EP2vm state */
+	u32	EP4vm_state; /* for EP4vm state */
+	u32	tx_halt; /* Stopping VM */
 
-	struct urb *				Tx4Urb;
-	struct urb *				Tx2Urb;
+	struct urb	*Tx4Urb;
+	struct urb	*Tx2Urb;
 
 	int		EP2VM_status;
 	int		EP4VM_status;
 
-	u32	TxFillCount; // 20060928
-	u32	TxTimer; // 20060928 Add if sending packet not great than 13
+	u32	TxFillCount; /* 20060928 */
+	u32	TxTimer; /* 20060928 Add if sending packet is greater than 13 */
 };
 
 #endif
diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu
index 5f1cfb8f..bfad7dc 100644
--- a/drivers/staging/wlags49_h2/README.ubuntu
+++ b/drivers/staging/wlags49_h2/README.ubuntu
@@ -46,12 +46,12 @@
 changes to the Makefile and uncomment -DHERMES25. This will build
 driver wlags49_h25_cs.
 
-Note: You can detemine the type with command "pccardctrl info"
+Note: You can determine the type with command "pccardctrl info"
         MANIFID: 0156,0002 = HERMES - not supported by this driver
         MANIFID: 0156,0003 = HERMES II   (Wireless B)
         MANIFID: 0156,0004 = HERMES II.5 (Wireless B/G)
 
-After succesfull compile type command
+After successful compile type command
 
 sudo make install
 
@@ -81,7 +81,7 @@
 - Addaptations of Andrey Borzenkov applied to 7.22 source
 - Alterations to avoid most HCF_ASSERTs
 -- Switching interrupts off and on in the HCF
--- Bugfixes, things that were aparently wrong like reporting link status
+-- Bugfixes, things that were apparently wrong like reporting link status
    change which checked a variable that was not changed in HCF anymore.
 -- Used on WEP but setting keys via SIOCSIWENCODEEXT was not supported
 -- Recovery actions added
@@ -93,7 +93,7 @@
 changed; the former ioctl functions are now called before "open" and
 after "close", which was not expected. One of the problems was enable/
 disable of interrupts in the HCF. Interrupt handling starts at "open"
-so if a former "ioctl" routinge is called before "open" or after "close"
+so if a former "ioctl" routine is called before "open" or after "close"
 then nothing should be done with interrupt switching in the HCF. Once
 this was solved most HCF_ASSERTS went away.
 
@@ -120,8 +120,8 @@
 does not work anymore but it provides some information about all the
 settings.
 
-I have not have personal contact with Agere, but others have. Agere
-agreed to make their software available under the BSD licence.
+I have no personal contact with Agere, but others have. Agere
+agreed to make their software available under the BSD license.
 This driver is based on the 7.22 version.
 
 The following was mailed by Agere to Andrey Borzenkov about this:
diff --git a/drivers/staging/wlags49_h2/TODO b/drivers/staging/wlags49_h2/TODO
index 94032b6..f1a4561 100644
--- a/drivers/staging/wlags49_h2/TODO
+++ b/drivers/staging/wlags49_h2/TODO
@@ -1,4 +1,4 @@
-First of all, the best thing would be that this driver becomes obsolte by
+First of all, the best thing would be that this driver becomes obsolete by
 adding support for Hermes II and Hermes II.5 cards to the existing orinoco
 driver. The orinoco driver currently only supports Hermes I based cards.
 Since this will not happen by magic and has not happened until now this
@@ -10,11 +10,11 @@
 
 TODO:
 	- verify against a Hermes II.5 card
-	- verify with WPA encription (both with H2 and H2.5 cards)
+	- verify with WPA encryption (both with H2 and H2.5 cards)
 	- sometimes the card does not initialize correctly, retry mechanisms
-	  are build in to catch most cases but not all
+	  are built in to catch most cases but not all
 	- once the driver runs it is very stable, but I have the impression
-	  some the crittical sections take to long
+	  that some of the critical sections take some time.
 	- the driver is split into a Hermes II and a Hermes II.5 part, it
 	  would be nice to handle both with one module instead of two
 	- review by the wireless developer community
@@ -25,7 +25,7 @@
 DONE:
 	- verified against a Hermes II card (Thomson Speedtouch 110 PCMCIA
 	  card)
-	- verified with WEP encription
+	- verified with WEP encryption
 
 Please send any patches or complaints about this driver to Greg
 Kroah-Hartman <greg@kroah.com> and Cc: Henk de Groot <pe1dnn@amsat.org>
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 4235446..4aac26d 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -508,7 +508,7 @@
  *    - HCF_ACT_INT_FORCE_ON enable interrupt generation by WaveLAN NIC
  *    - HCF_ACT_INT_OFF      disable interrupt generation by WaveLAN NIC
  *    - HCF_ACT_INT_ON       compensate 1 HCF_ACT_INT_OFF, enable interrupt generation if balance reached
- *    - HCF_ACT_PRS_SCAN     Hermes Probe Respons Scan (F102) command
+ *    - HCF_ACT_PRS_SCAN     Hermes Probe Response Scan (F102) command
  *    - HCF_ACT_RX_ACK       acknowledge non-DMA receiver to Hermes
  *    - HCF_ACT_SCAN         Hermes Inquire Scan (F101) command (non-WARP only)
  *    - HCF_ACT_SLEEP        DDS Sleep request
@@ -571,7 +571,7 @@
  * The F/W is wokenup by the HCF when the NIC Interrupts mode are disabled, i.e. at the first HCF_ACT_INT_OFF
  * after going into sleep.
  *
- * The following Miscellanuous actions are defined:
+ * The following Miscellaneous actions are defined:
  *
  * o HCF_ACT_RX_ACK: Receiver Acknowledgement (non-DMA, non-USB mode only)
  * Acking the receiver, frees the NIC memory used to hold the Rx frame and allows the F/W to
@@ -579,7 +579,7 @@
  * If the MSF does not need access (any longer) to the current frame, e.g. because it is rejected based on the
  * look ahead or copied to another buffer, the receiver may be acked. Acking earlier is assumed to have the
  * potential of improving the performance.
- * If the MSF does not explitly ack te receiver, the acking is done implicitly if:
+ * If the MSF does not explicitly ack the receiver, the acking is done implicitly if:
  * - the received frame fits in the look ahead buffer, by the hcf_service_nic call that reported the Rx frame
  * - if not in the above step, by hcf_rcv_msg (assuming hcf_rcv_msg is called)
  * - if neither of the above implicit acks nor an explicit ack by the MSF, by the first hcf_service_nic after
@@ -591,9 +591,9 @@
  * The Inquire Tallies command requests the F/W to provide its current set of tallies.
  * See also hcf_get_info with CFG_TALLIES as parameter.
  *
- * o HCF_ACT_PRS_SCAN: Inquire Probe Respons Scan command
+ * o HCF_ACT_PRS_SCAN: Inquire Probe Response Scan command
  * This command is only operational if the F/W is enabled.
- * The Probe Respons Scan command starts a scan sequence.
+ * The Probe Response Scan command starts a scan sequence.
  * The HCF puts the result of this action in an MSF defined buffer (see CFG_RID_LOG_STRCT).
  *
  * o HCF_ACT_SCAN: Inquire Scan command
@@ -606,7 +606,7 @@
  * - NIC interrupts are not disabled while required by parameter action.
  * - an invalid code is specified in parameter action.
  * - HCF_ACT_INT_ON commands outnumber the HCF_ACT_INT_OFF commands.
- * - reentrancy, may be  caused by calling hcf_functions without adequate protection against NIC interrupts or
+ * - reentrancy, may be caused by calling hcf_functions without adequate protection against NIC interrupts or
  *   multi-threading
  *
  * - Since the HCF does not maintain status information relative to the F/W enabled state, it is not asserted
@@ -625,7 +625,7 @@
  *   change in HREG_EV_STAT matching a bit in HREG_INT_EN, i.e. not if invoked as result of another device
  *   generating an interrupt on the shared interrupt line.
  *   Note 1: it has been observed that under certain adverse conditions on certain platforms the writing of
- *   HREG_INT_EN can apparently fail, therefor it is paramount that HREG_INT_EN is written again with 0 for
+ *   HREG_INT_EN can apparently fail, therefore it is paramount that HREG_INT_EN is written again with 0 for
  *   each and every call to HCF_ACT_INT_OFF.
  *   Note 2: it has been observed that under certain H/W & S/W architectures this logic is called when there is
  *   no NIC at all. To cater for this, the value of HREG_INT_EN is validated. If the unused bit 0x0100 is set,
@@ -902,7 +902,7 @@
  * - A command other than Continue, Enable, Disable, Connect or Disconnect is given.
  * - An invalid combination of the subfields is given or a bit outside the subfields is given.
  * - any return code besides HCF_SUCCESS.
- * - reentrancy, may be  caused by calling a hcf_function without adequate protection against NIC interrupts or
+ * - reentrancy, may be caused by calling a hcf_function without adequate protection against NIC interrupts or
  *   multi-threading
  *
  *.DIAGRAM
@@ -1030,7 +1030,7 @@
  * hcf_connect passes the MSF-defined location of the IFB to the HCF and grants or revokes access right for the
  * HCF to the IFB. Revoking is done by specifying HCF_DISCONNECT rather than an I/O address for the parameter
  * io_base.  Every call of hcf_connect in "connect" mode, must eventually be followed by a call of hcf_connect
- * in "disconnect" mode. Clalling hcf_connect in "connect"/"disconnect" mode can not be nested.
+ * in "disconnect" mode. Calling hcf_connect in "connect"/"disconnect" mode can not be nested.
  * The IFB address must be used as a handle with all subsequent HCF-function calls and the HCF uses the IFB
  * address as a handle when it performs a call(back) of an MSF-function (i.e. msf_assert).
  *
@@ -1058,7 +1058,7 @@
  *   specification for S/W reset
  *   Note 2: it turns out that on some H/W constellations, the clock to access the EEProm is not lowered
  *   to an appropriate frequency by HREG_IO_SRESET. By giving an HCMD_INI first, this problem is worked around.
- *2b: Experimentally it is determined over a wide range of F/W versions that waiting for the for Cmd bit in
+ *2b: Experimentally it is determined over a wide range of F/W versions that are waiting for the for Cmd bit in
  *   Ev register gives a workable strategy. The available documentation does not give much clues.
  *4: clear and initialize the IFB
  *   The HCF house keeping info is designed such that zero is the appropriate initial value for as much as
diff --git a/drivers/staging/wlags49_h2/hcfcfg.h b/drivers/staging/wlags49_h2/hcfcfg.h
index 39fb4d3..869b5c3 100644
--- a/drivers/staging/wlags49_h2/hcfcfg.h
+++ b/drivers/staging/wlags49_h2/hcfcfg.h
@@ -21,7 +21,7 @@
 * hcfcfg.tpl list all #defines which must be specified to:
 *   adjust the HCF functions defined in HCF.C to the characteristics of a specific environment
 *		o maximum sizes for messages
-*		o Endianess
+*		o Endianness
 *	Compiler specific macros
 *		o port I/O macros
 *		o type definitions
diff --git a/drivers/staging/wlags49_h2/hcfdef.h b/drivers/staging/wlags49_h2/hcfdef.h
index 30744e1..74c0f71 100644
--- a/drivers/staging/wlags49_h2/hcfdef.h
+++ b/drivers/staging/wlags49_h2/hcfdef.h
@@ -652,15 +652,15 @@
 #if 0 //get compiler going
 #if HCF_EX_INT_TICK != HREG_EV_TICK
 ;? out dated checking
-err: someone redefined these macros while the implemenation assumes they are equal;
+err: someone redefined these macros while the implementation assumes they are equal;
 #endif
 #if HCF_EX_INT_TX_OK != HFS_TX_CNTL_TX_OK || HFS_TX_CNTL_TX_OK != HREG_EV_TX_OK
 ;? out dated checking
-err: someone redefined these macros while the implemenation assumes they are equal;
+err: someone redefined these macros while the implementation assumes they are equal;
 #endif
 #if HCF_EX_INT_TX_EX != HFS_TX_CNTL_TX_EX || HFS_TX_CNTL_TX_EX != HREG_EV_TX_EX
 ;? out dated checking
-err: someone redefined these macros while the implemenation assumes they are equal;
+err: someone redefined these macros while the implementation assumes they are equal;
 #endif
 #endif // 0 get compiler going
 
diff --git a/drivers/staging/wlags49_h2/mdd.h b/drivers/staging/wlags49_h2/mdd.h
index 5c3515f..0c91497 100644
--- a/drivers/staging/wlags49_h2/mdd.h
+++ b/drivers/staging/wlags49_h2/mdd.h
@@ -652,7 +652,7 @@
 #define CFG_CNF_WDS_ADDR6				0xFC16		//[AP] Port 6 MAC Adrs of corresponding WDS Link node
 #define CFG_CNF_PM_MCAST_BUF			0xFC17		//[AP] Switch for PM buffereing of Multicast Messages
 #define CFG_CNF_MCAST_PM_BUF			CFG_CNF_PM_MCAST_BUF	//name does not match H-II spec
-#define CFG_CNF_REJECT_ANY				0xFC18		//[AP] Switch for PM buffereing of Multicast Messages
+#define CFG_CNF_REJECT_ANY				0xFC18		//[AP] Switch for PM buffering of Multicast Messages
 
 #define CFG_CNF_ENCRYPTION				0xFC20		//select en/de-cryption of Tx/Rx messages
 #define CFG_CNF_AUTHENTICATION			0xFC21		//[STA] selects Authentication algorithm
@@ -844,13 +844,13 @@
 
 
 #define HCF_SUCCESS					0x00	// OK
-#define HCF_ERR_TIME_OUT			0x04	// Expected Hermes event did not occure in expected time
+#define HCF_ERR_TIME_OUT			0x04	// Expected Hermes event did not occur in expected time
 #define HCF_ERR_NO_NIC				0x05	/* card not found (usually yanked away during hcfio_in_string
 										  	 * Also: card is either absent or disabled while it should be neither */
 #define HCF_ERR_LEN					0x08	/* buffer size insufficient
 		 								  	 *		  -	IFB_ConfigTable too small
 		 								  	 *		  -	hcf_get_info buffer has a size of 0 or 1 or less than needed
-		 							  		 *			to accomodate all data
+		 							  		 *			to accommodate all data
 		 							  		 *		  -	hcf_put_info: CFG_DLNV_DATA exceeds intermediate
 											 *		  buffer size */
 #define HCF_ERR_INCOMP_PRI			0x09	// primary functions are not compatible
@@ -1004,7 +1004,7 @@
 #define CFG_CURRENT_LINK_STATUS			0x090B		//Latest link status got through 0xF200 LinkEvent
 
 /*============================================================ INFORMATION FRAMES =========================*/
-#define CFG_INFO_FRAME_MIN				0xF000		//lowest value representing an Informatio Frame
+#define CFG_INFO_FRAME_MIN				0xF000		//lowest value representing an Information Frame
 
 #define CFG_TALLIES						0xF100		//Communications Tallies
 #define CFG_SCAN						0xF101		//Scan results
diff --git a/drivers/staging/wlags49_h2/sta_h2.c b/drivers/staging/wlags49_h2/sta_h2.c
index f9a3852..00dffe2 100644
--- a/drivers/staging/wlags49_h2/sta_h2.c
+++ b/drivers/staging/wlags49_h2/sta_h2.c
@@ -26,7 +26,7 @@
 
 
 #include "hcfcfg.h"				// to get hcf_16 etc defined as well as
-                                // possible settings which inluence mdd.h or dhf.h
+                                // possible settings which influence mdd.h or dhf.h
 #include "mdd.h"   				//to get COMP_ID_STA etc defined
 #include "dhf.h"   				//used to be "fhfmem.h", to get memblock,plugrecord,
 
diff --git a/drivers/staging/wlags49_h2/sta_h25.c b/drivers/staging/wlags49_h2/sta_h25.c
index 86ca1cdd8..5b6f670 100644
--- a/drivers/staging/wlags49_h2/sta_h25.c
+++ b/drivers/staging/wlags49_h2/sta_h25.c
@@ -25,7 +25,7 @@
 
 
 #include "hcfcfg.h"				// to get hcf_16 etc defined as well as
-                                // possible settings which inluence mdd.h or dhf.h
+                                // possible settings which influence mdd.h or dhf.h
 #include "mdd.h"   				//to get COMP_ID_STA etc defined
 #include "dhf.h"   				//used to be "fhfmem.h", to get memblock,plugrecord,
 
diff --git a/drivers/staging/wlags49_h2/wl_enc.h b/drivers/staging/wlags49_h2/wl_enc.h
index 46629f3..1804611 100644
--- a/drivers/staging/wlags49_h2/wl_enc.h
+++ b/drivers/staging/wlags49_h2/wl_enc.h
@@ -106,7 +106,7 @@
 
 
 /*******************************************************************************
- * function prrottypes
+ * function prototypes
  ******************************************************************************/
 int wl_wep_code( char *szCrypt, char *szDest, void *Data, int nLen );
 
diff --git a/drivers/staging/wlags49_h2/wl_if.h b/drivers/staging/wlags49_h2/wl_if.h
index 6a26130..6d66dab 100644
--- a/drivers/staging/wlags49_h2/wl_if.h
+++ b/drivers/staging/wlags49_h2/wl_if.h
@@ -95,7 +95,7 @@
 //              Manufacture ID: 0156,0003
 // Lowest measurment for noise floor seen is value 54
 // Highest signal strength in close proximity to the AP seen is value 118
-// Very good must be arround 100 (otherwise its never "full scale"
+// Very good must be around 100 (otherwise its never "full scale"
 // All other constants are derrived from these. This makes the signal gauge
 // work for me...
 #define HCF_MIN_SIGNAL_LEVEL        54
diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h
index 553601f..b230781 100644
--- a/drivers/staging/wlags49_h2/wl_internal.h
+++ b/drivers/staging/wlags49_h2/wl_internal.h
@@ -11,7 +11,7 @@
  *
  *------------------------------------------------------------------------------
  *
- *   Header for defintions and macros internal to the drvier.
+ *   Header for definitions and macros internal to the drvier.
  *
  *------------------------------------------------------------------------------
  *
@@ -838,7 +838,7 @@
 	DESC_STRCT  *rx_packet[NUM_RX_DESC];
 	DESC_STRCT  *rx_reclaim_desc, *tx_reclaim_desc; // Descriptors for host-reclaim purposes (see HCF)
 	int         tx_rsc_ind; // DMA Tx resource indicator is maintained in the MSF, not in the HCF
-	int         rx_rsc_ind; // Also added rx rsource indicator so that cleanup can be performed if alloc fails
+	int         rx_rsc_ind; // Also added rx resource indicator so that cleanup can be performed if alloc fails
 	int         status;
 } DMA_STRCT;
 
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index 2041078..f5f120a 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -63,7 +63,7 @@
  *  constant definitions
  ******************************************************************************/
 
-/* Allow support for calling system fcns to access F/W iamge file */
+/* Allow support for calling system fcns to access F/W image file */
 #define __KERNEL_SYSCALLS__
 
 /*******************************************************************************
@@ -128,7 +128,7 @@
 #include <wl_pci.h>
 #endif  /* BUS_PCI */
 /*******************************************************************************
- *	macro defintions
+ *	macro definitions
  ******************************************************************************/
 #define VALID_PARAM(C) \
 	{ \
@@ -1163,7 +1163,7 @@
 				CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_major ),
 				CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_minor ));
 
-	/* now we wil get the MAC address of the card */
+	/* now we will get the MAC address of the card */
 	lp->ltvRecord.len = 4;
 	if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP  ) {
 		lp->ltvRecord.typ = CFG_NIC_MAC_ADDR;
@@ -1374,7 +1374,7 @@
 	lp->ltvRecord.len = 2;
 	lp->ltvRecord.typ = CFG_CNTL_OPT;
 
-	/* The Card Services build must ALWAYS configure for 16-bit I/O. PCI or
+	/* The Card Services build must ALWAYS be configured for 16-bit I/O. PCI or
 	   CardBus can be set to either 16/32 bit I/O, or Bus Master DMA, but only
 	   for Hermes-2.5 */
 #ifdef BUS_PCMCIA
@@ -1627,7 +1627,7 @@
 		lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( lp->TxRateControl[0] );
 #endif  // WARP
 
-//;?skip temporarily to see whether the RID or something else is the probelm hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
+//;?skip temporarily to see whether the RID or something else is the problem hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
 
 		DBG_TRACE( DbgInfo, "CFG_TX_RATE_CNTL 2.4GHz           : 0x%04x\n",
 				   lp->TxRateControl[0] );
@@ -2474,7 +2474,7 @@
  *
  *  DESCRIPTION:
  *
- *      This function perfroms a check on the device and calls wl_remove() if
+ *      This function performs a check on the device and calls wl_remove() if
  *  necessary. This function can be used for all bus types, but exists mostly
  *  for the benefit of the Card Services driver, as there are times when
  *  wl_remove() does not get called.
@@ -2596,7 +2596,7 @@
 			lp->portState = WVLAN_PORT_STATE_ENABLED;   //;?bad mnemonic, NIC iso PORT
 #ifdef ENABLE_DMA
 			if ( lp->use_dma ) {
-				wl_pci_dma_hcf_supply( lp );  //;?always succes?
+				wl_pci_dma_hcf_supply( lp );  //;?always successful?
 			}
 #endif
 		}
@@ -2874,7 +2874,7 @@
  *  DESCRIPTION:
  *
  *      This function will perform the tedious task of endian translating all
- *  fields withtin a mailbox message which need translating.
+ *  fields within a mailbox message which need translating.
  *
  *  PARAMETERS:
  *
@@ -2989,7 +2989,7 @@
  *
  *  DESCRIPTION:
  *
- *      This function will process the mailbox data.
+ *      This function processes the mailbox data.
  *
  *  PARAMETERS:
  *
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 824b852..fb42140 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -652,7 +652,6 @@
     wl_unlock( lp, &flags );
 
     DBG_LEAVE( DbgInfo );
-    return;
 } // wl_tx_timeout
 /*============================================================================*/
 
@@ -836,8 +835,7 @@
         txF->frame.port = port;
         /* Move the frame to the txQ */
         /* NOTE: Here's where we would do priority queueing */
-        list_del( &( txF->node ));
-        list_add( &( txF->node ), &( lp->txQ[0] ));
+        list_move(&(txF->node), &(lp->txQ[0]));
 
         lp->txQ_count++;
         if( lp->txQ_count >= DEFAULT_NUM_TX_FRAMES ) {
@@ -1252,7 +1250,7 @@
 
     netif_stop_queue( dev );
 
-    /* Allocate virutal devices for WDS support if needed */
+    /* Allocate virtual devices for WDS support if needed */
     WL_WDS_DEVICE_ALLOC( lp );
 
     DBG_LEAVE( DbgInfo );
@@ -1292,7 +1290,6 @@
     free_netdev( dev );
 
     DBG_LEAVE( DbgInfo );
-    return;
 } // wl_device_dealloc
 /*============================================================================*/
 
@@ -1547,7 +1544,6 @@
     WL_WDS_NETIF_STOP_QUEUE( lp );
 
     DBG_LEAVE( DbgInfo );
-    return;
 } // wl_wds_device_alloc
 /*============================================================================*/
 
@@ -1593,7 +1589,6 @@
     }
 
     DBG_LEAVE( DbgInfo );
-    return;
 } // wl_wds_device_dealloc
 /*============================================================================*/
 
@@ -1604,7 +1599,7 @@
  *  DESCRIPTION:
  *
  *      Used to start the netif queues of all the "virtual" network devices
- *      which repesent the WDS ports.
+ *      which represent the WDS ports.
  *
  *  PARAMETERS:
  *
@@ -1629,8 +1624,6 @@
             }
         }
     }
-
-    return;
 } // wl_wds_netif_start_queue
 /*============================================================================*/
 
@@ -1641,7 +1634,7 @@
  *  DESCRIPTION:
  *
  *      Used to stop the netif queues of all the "virtual" network devices
- *      which repesent the WDS ports.
+ *      which represent the WDS ports.
  *
  *  PARAMETERS:
  *
@@ -1666,8 +1659,6 @@
             }
         }
     }
-
-    return;
 } // wl_wds_netif_stop_queue
 /*============================================================================*/
 
@@ -1678,7 +1669,7 @@
  *  DESCRIPTION:
  *
  *      Used to wake the netif queues of all the "virtual" network devices
- *      which repesent the WDS ports.
+ *      which represent the WDS ports.
  *
  *  PARAMETERS:
  *
@@ -1703,8 +1694,6 @@
             }
         }
     }
-
-    return;
 } // wl_wds_netif_wake_queue
 /*============================================================================*/
 
@@ -1715,7 +1704,7 @@
  *  DESCRIPTION:
  *
  *      Used to signal the network layer that carrier is present on all of the
- *      "virtual" network devices which repesent the WDS ports.
+ *      "virtual" network devices which represent the WDS ports.
  *
  *  PARAMETERS:
  *
@@ -1738,8 +1727,6 @@
             }
         }
     }
-
-    return;
 } // wl_wds_netif_carrier_on
 /*============================================================================*/
 
@@ -1750,7 +1737,7 @@
  *  DESCRIPTION:
  *
  *      Used to signal the network layer that carrier is NOT present on all of
- *      the "virtual" network devices which repesent the WDS ports.
+ *      the "virtual" network devices which represent the WDS ports.
  *
  *  PARAMETERS:
  *
@@ -1763,18 +1750,15 @@
  ******************************************************************************/
 void wl_wds_netif_carrier_off( struct wl_private *lp )
 {
-    int count;
-    /*------------------------------------------------------------------------*/
+	int count;
 
-    if( lp != NULL ) {
-        for( count = 0; count < NUM_WDS_PORTS; count++ ) {
-            if( lp->wds_port[count].is_registered ) {
-                netif_carrier_off( lp->wds_port[count].dev );
-            }
-        }
-    }
+	if(lp != NULL) {
+		for(count = 0; count < NUM_WDS_PORTS; count++) {
+			if(lp->wds_port[count].is_registered)
+				netif_carrier_off(lp->wds_port[count].dev);
+		}
+	}
 
-    return;
 } // wl_wds_netif_carrier_off
 /*============================================================================*/
 
@@ -1810,22 +1794,19 @@
 
     DBG_FUNC( "wl_send_dma" );
 
-    if( lp == NULL )
-    {
+    if( lp == NULL ) {
         DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
         return FALSE;
     }
 
-    if( lp->dev == NULL )
-    {
+    if( lp->dev == NULL ) {
         DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
         return FALSE;
     }
 
     /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */
 
-    if( skb == NULL )
-    {
+    if( skb == NULL ) {
         DBG_WARNING (DbgInfo, "Nothing to send.\n");
         return FALSE;
     }
@@ -1835,8 +1816,7 @@
     /* Get a free descriptor */
     desc = wl_pci_dma_get_tx_packet( lp );
 
-    if( desc == NULL )
-    {
+    if( desc == NULL ) {
         if( lp->netif_queue_on == TRUE ) {
             netif_stop_queue( lp->dev );
             WL_WDS_NETIF_STOP_QUEUE( lp );
@@ -1852,8 +1832,7 @@
 
     desc_next = desc->next_desc_addr;
 
-    if( desc_next->buf_addr == NULL )
-    {
+    if( desc_next->buf_addr == NULL ) {
         DBG_ERROR( DbgInfo, "DMA descriptor buf_addr is NULL\n" );
         return FALSE;
     }
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 0b31b01..a09c3ac 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -223,7 +223,7 @@
  ******************************************************************************/
 void wl_adapter_cleanup_module( void )
 {
-	//;?how comes wl_adapter_cleanup_module is located in a seemingly pci specific module
+	//;?how come wl_adapter_cleanup_module is located in a seemingly pci specific module
     DBG_FUNC( "wl_adapter_cleanup_module" );
     DBG_ENTER( DbgInfo );
 
@@ -385,7 +385,7 @@
  *  DESCRIPTION:
  *
  *      Registered in the pci_driver structure, this function is called when the
- *  PCI subsystem finds a new PCI device which matches the infomation contained
+ *  PCI subsystem finds a new PCI device which matches the information contained
  *  in the pci_device_id table.
  *
  *  PARAMETERS:
@@ -424,7 +424,7 @@
  *  DESCRIPTION:
  *
  *      Registered in the pci_driver structure, this function is called when the
- *  PCI subsystem detects that a PCI device which matches the infomation
+ *  PCI subsystem detects that a PCI device which matches the information
  *  contained in the pci_device_id table has been removed.
  *
  *  PARAMETERS:
@@ -899,7 +899,7 @@
  *  DESCRIPTION:
  *
  *      Allocates a single Rx packet, consisting of two descriptors and one
- *      contiguous buffer. THe buffer starts with the hermes-specific header.
+ *      contiguous buffer. The buffer starts with the hermes-specific header.
  *      One descriptor points at the start, the other at offset 0x3a of the
  *      buffer.
  *
diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c
index f30e5ee..87e1e41 100644
--- a/drivers/staging/wlags49_h2/wl_priv.c
+++ b/drivers/staging/wlags49_h2/wl_priv.c
@@ -225,7 +225,7 @@
  *
  *  DESCRIPTION:
  *
- *      Disonnect from the UIL after a request has been completed.
+ *      Disconnect from the UIL after a request has been completed.
  *
  *  PARAMETERS:
  *
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index 0e49272..beabf59 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -910,7 +910,7 @@
 	memset(byte_field, '\0', 3);
 
 	while (value[value_offset] != '\0') {
-		/* Skip over the colon chars seperating the bytes, if they exist */
+		/* Skip over the colon chars separating the bytes, if they exist */
 		if (value[value_offset] == ':') {
 			value_offset++;
 			continue;
diff --git a/drivers/staging/wlags49_h2/wl_version.h b/drivers/staging/wlags49_h2/wl_version.h
index 3deacfa..037b526 100644
--- a/drivers/staging/wlags49_h2/wl_version.h
+++ b/drivers/staging/wlags49_h2/wl_version.h
@@ -152,7 +152,7 @@
 
 
 /*******************************************************************************
- *  bus architechture specific defines, includes, etc.
+ *  bus architecture specific defines, includes, etc.
  ******************************************************************************/
 /*
  * There doesn't seem to be a difference for PCMCIA and PCI anymore, at least
diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c
index 7ff0a10..f553366 100644
--- a/drivers/staging/wlags49_h2/wl_wext.c
+++ b/drivers/staging/wlags49_h2/wl_wext.c
@@ -62,6 +62,7 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/etherdevice.h>
 #include <asm/uaccess.h>
 
 #include <debug.h>
@@ -173,7 +174,7 @@
 
 	switch (key_idx) {
 	case 0:
-		if (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) {
+		if (!is_broadcast_ether_addr(addr)) {
 			ltv->len = 7;
 			ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY;
 			memcpy(&ltv->u.u8[0], addr, ETH_ALEN);
@@ -605,7 +606,7 @@
 		if (retries < 10) {
 			retries++;
 
-			/* Holding the lock too long, make a gap to allow other processes */
+			/* Holding the lock too long, makes a gap to allow other processes */
 			wl_unlock(lp, &flags);
 			wl_lock( lp, &flags );
 
@@ -617,7 +618,7 @@
 				goto out_unlock;
 			}
 
-			/* Holding the lock too long, make a gap to allow other processes */
+			/* Holding the lock too long, makes a gap to allow other processes */
 			wl_unlock(lp, &flags);
 			wl_lock( lp, &flags );
 
@@ -630,7 +631,7 @@
 		}
 	}
 
-	/* Holding the lock too long, make a gap to allow other processes */
+	/* Holding the lock too long, makes a gap to allow other processes */
 	wl_unlock(lp, &flags);
 	wl_lock( lp, &flags );
 
@@ -693,7 +694,7 @@
 
 	/* Encryption */
 
-	/* Holding the lock too long, make a gap to allow other processes */
+	/* Holding the lock too long, makes a gap to allow other processes */
 	wl_unlock(lp, &flags);
 	wl_lock( lp, &flags );
 
@@ -720,7 +721,7 @@
 
 	// Retry Limits and Lifetime - NOT SUPPORTED
 
-	/* Holding the lock too long, make a gap to allow other processes */
+	/* Holding the lock too long, makes a gap to allow other processes */
 	wl_unlock(lp, &flags);
 	wl_lock( lp, &flags );
 
@@ -2595,7 +2596,7 @@
 	int		    retries = 0;
 	/*------------------------------------------------------------------------*/
 
-	//;? Note: shows results as trace, retruns always 0 unless BUSY
+	//;? Note: shows results as trace, returns always 0 unless BUSY
 
 	DBG_FUNC( "wireless_set_scan" );
 	DBG_ENTER( DbgInfo );
@@ -2645,7 +2646,7 @@
 
 	DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNEL result      : 0x%x\n", status );
 
-	// Holding the lock too long, make a gap to allow other processes
+	// Holding the lock too long, makes a gap to allow other processes
 	wl_unlock(lp, &flags);
 	wl_lock( lp, &flags );
 
@@ -2656,7 +2657,7 @@
 			DBG_TRACE( DbgInfo, "Reset card to recover, attempt: %d\n", retries );
 			wl_reset( dev );
 
-			// Holding the lock too long, make a gap to allow other processes
+			// Holding the lock too long, makes a gap to allow other processes
 			wl_unlock(lp, &flags);
 			wl_lock( lp, &flags );
 
@@ -2673,7 +2674,7 @@
 
 	status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
 
-	// Holding the lock too long, make a gap to allow other processes
+	// Holding the lock too long, makes a gap to allow other processes
 	wl_unlock(lp, &flags);
 	wl_lock( lp, &flags );
 
@@ -2681,7 +2682,7 @@
 
 	/* Initiate the scan */
 	/* NOTE: Using HCF_ACT_SCAN has been removed, as using HCF_ACT_ACS_SCAN to
-	   retrieve probe responses must always be used to support WPA */
+	   retrieve probe response must always be used to support WPA */
 	status = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN );
 
 	if( status == HCF_SUCCESS ) {
@@ -3054,7 +3055,7 @@
 	 * Make sure that there is no data queued up in the firmware
 	 * before setting the TKIP keys. If this check is not
 	 * performed, some data may be sent out with incorrect MIC
-	 * and cause synchronizarion errors with the AP
+	 * and cause synchronization errors with the AP
 	 */
 	/* Check every 1ms for 100ms */
 	for (count = 0; count < 100; count++) {
@@ -3654,7 +3655,7 @@
 	   this event BEFORE sending the association event, as there are timing
 	   issues with the hostap supplicant. The supplicant will attempt to process
 	   an EAPOL-Key frame from an AP before receiving this information, which
-	   is required properly process the said frame. */
+	   is required for a proper processed frame. */
 	wl_wext_event_assoc_ie( dev );
 
 	/* Get the BSSID */
diff --git a/drivers/staging/wlags49_h25/Kconfig b/drivers/staging/wlags49_h25/Kconfig
index bf5664a..dd8dc4d 100644
--- a/drivers/staging/wlags49_h25/Kconfig
+++ b/drivers/staging/wlags49_h25/Kconfig
@@ -8,4 +8,4 @@
 	Driver for wireless cards using Agere's HERMES II.5 chipset
 	which are identified with Manufacture ID: 0156,0004
 	The software is a modified version of wl_lkm_722_abg.tar.gz
-	from the Agere Systems website, addapted for Ubuntu 9.04.
+	from the Agere Systems website, adapted for Ubuntu 9.04.
diff --git a/drivers/staging/wlags49_h25/TODO b/drivers/staging/wlags49_h25/TODO
index 94032b6..ec71ad3 100644
--- a/drivers/staging/wlags49_h25/TODO
+++ b/drivers/staging/wlags49_h25/TODO
@@ -1,4 +1,4 @@
-First of all, the best thing would be that this driver becomes obsolte by
+First of all, the best thing would be that this driver becomes obsolete by
 adding support for Hermes II and Hermes II.5 cards to the existing orinoco
 driver. The orinoco driver currently only supports Hermes I based cards.
 Since this will not happen by magic and has not happened until now this
@@ -10,11 +10,11 @@
 
 TODO:
 	- verify against a Hermes II.5 card
-	- verify with WPA encription (both with H2 and H2.5 cards)
+	- verify with WPA encryption (both with H2 and H2.5 cards)
 	- sometimes the card does not initialize correctly, retry mechanisms
 	  are build in to catch most cases but not all
 	- once the driver runs it is very stable, but I have the impression
-	  some the crittical sections take to long
+	  some the critical sections take to long
 	- the driver is split into a Hermes II and a Hermes II.5 part, it
 	  would be nice to handle both with one module instead of two
 	- review by the wireless developer community
@@ -25,7 +25,7 @@
 DONE:
 	- verified against a Hermes II card (Thomson Speedtouch 110 PCMCIA
 	  card)
-	- verified with WEP encription
+	- verified with WEP encryption
 
 Please send any patches or complaints about this driver to Greg
 Kroah-Hartman <greg@kroah.com> and Cc: Henk de Groot <pe1dnn@amsat.org>
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 0970127..18c06a5 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -1,7 +1,7 @@
 /* cfg80211 Interface for prism2_usb module */
 
 
-/* Prism2 channell/frequency/bitrate declarations */
+/* Prism2 channel/frequency/bitrate declarations */
 static const struct ieee80211_channel prism2_channels[] = {
 	{ .center_freq = 2412 },
 	{ .center_freq = 2417 },
@@ -329,9 +329,9 @@
 
 int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 {
-	struct net_device *dev = request->wdev->netdev;
+	struct net_device *dev;
 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
-	wlandevice_t *wlandev = dev->ml_priv;
+	wlandevice_t *wlandev;
 	struct p80211msg_dot11req_scan msg1;
 	struct p80211msg_dot11req_scan_results msg2;
 	struct cfg80211_bss *bss;
@@ -345,6 +345,9 @@
 	if (!request)
 		return -EINVAL;
 
+	dev = request->wdev->netdev;
+	wlandev = dev->ml_priv;
+
 	if (priv->scan_request && priv->scan_request != request)
 		return -EBUSY;
 
@@ -499,7 +502,7 @@
 			goto exit;
 	}
 
-	/* Set the authorisation */
+	/* Set the authorization */
 	if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
 		((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
 			msg_join.authtype.data = P80211ENUM_authalg_opensystem;
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 7843dfd..f180c3d 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -2140,11 +2140,7 @@
 ----------------------------------------------------------------*/
 int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len)
 {
-	int result;
-
-	result = hfa384x_dorrid_wait(hw, rid, buf, len);
-
-	return result;
+	return hfa384x_dorrid_wait(hw, rid, buf, len);
 }
 
 /*----------------------------------------------------------------
@@ -3790,7 +3786,7 @@
 #endif
 	if ((urb->status == -ESHUTDOWN) ||
 	    (urb->status == -ENODEV) || (hw == NULL))
-		goto done;
+		return;
 
 retry:
 	spin_lock_irqsave(&hw->ctlxq.lock, flags);
@@ -3803,7 +3799,7 @@
 	 */
 	if (list_empty(&hw->ctlxq.active)) {
 		spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
-		goto done;
+		return;
 	}
 
 	/*
@@ -3886,9 +3882,6 @@
 
 	if (run_queue)
 		hfa384x_usbctlxq_run(hw);
-
-done:
-	;
 }
 
 /*----------------------------------------------------------------
@@ -3985,15 +3978,10 @@
 		if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) {
 			spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
 			hfa384x_usbctlxq_run(hw);
-			goto done;
+			return;
 		}
 	}
-
 	spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
-
-done:
-	;
-
 }
 
 /*----------------------------------------------------------------
@@ -4057,23 +4045,20 @@
 static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx)
 {
 	unsigned long flags;
-	int ret;
 
 	spin_lock_irqsave(&hw->ctlxq.lock, flags);
 
 	if (hw->wlandev->hwremoved) {
 		spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
-		ret = -ENODEV;
-	} else {
-		ctlx->state = CTLX_PENDING;
-		list_add_tail(&ctlx->list, &hw->ctlxq.pending);
-
-		spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
-		hfa384x_usbctlxq_run(hw);
-		ret = 0;
+		return -ENODEV;
 	}
 
-	return ret;
+	ctlx->state = CTLX_PENDING;
+	list_add_tail(&ctlx->list, &hw->ctlxq.pending);
+	spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
+	hfa384x_usbctlxq_run(hw);
+
+	return 0;
 }
 
 /*----------------------------------------------------------------
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index f53a27a..3df753b 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -559,17 +559,17 @@
 	/* Sanity checks */
 	if (skb == NULL) {	/* bad skb */
 		pr_debug("Called w/ null skb.\n");
-		goto exit;
+		return;
 	}
 	frmmeta = P80211SKB_FRMMETA(skb);
 	if (frmmeta == NULL) {	/* no magic */
 		pr_debug("Called w/ bad frmmeta magic.\n");
-		goto exit;
+		return;
 	}
 	rxmeta = frmmeta->rx;
 	if (rxmeta == NULL) {	/* bad meta ptr */
 		pr_debug("Called w/ bad rxmeta ptr.\n");
-		goto exit;
+		return;
 	}
 
 	/* Free rxmeta */
@@ -577,8 +577,6 @@
 
 	/* Clear skb->cb */
 	memset(skb->cb, 0, sizeof(skb->cb));
-exit:
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -660,5 +658,4 @@
 	else
 		printk(KERN_ERR "Freeing an skb (%p) w/ no frmmeta.\n", skb);
 	dev_kfree_skb(skb);
-	return;
 }
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 0f51b4a..750330f 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -240,10 +240,7 @@
 {
 	/* Enqueue for post-irq processing */
 	skb_queue_tail(&wlandev->nsd_rxq, skb);
-
 	tasklet_schedule(&wlandev->rx_bh);
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -464,7 +461,7 @@
 /*----------------------------------------------------------------
 * p80211knetdev_set_multicast_list
 *
-* Called from higher lavers whenever there's a need to set/clear
+* Called from higher layers whenever there's a need to set/clear
 * promiscuous mode or rewrite the multicast list.
 *
 * Arguments:
@@ -644,7 +641,7 @@
 	p80211item_unk392_t *mibattr;
 	p80211item_pstr6_t *macaddr;
 	p80211item_uint32_t *resultcode;
-	int result = 0;
+	int result;
 
 	/* If we're running, we don't allow MAC address changes */
 	if (netif_running(dev))
@@ -806,15 +803,13 @@
 * Arguments:
 *	wlandev		ptr to the wlandev structure for the
 *			interface.
-* Returns:
-*	zero on success, non-zero otherwise.
 * Call Context:
 *	Should be process thread.  We'll assume it might be
 *	interrupt though.  When we add support for statically
 *	compiled drivers, this function will be called in the
 *	context of the kernel startup code.
 ----------------------------------------------------------------*/
-int wlan_unsetup(wlandevice_t *wlandev)
+void wlan_unsetup(wlandevice_t *wlandev)
 {
 	struct wireless_dev *wdev;
 
@@ -827,8 +822,6 @@
 		free_netdev(wlandev->netdev);
 		wlandev->netdev = NULL;
 	}
-
-	return 0;
 }
 
 /*----------------------------------------------------------------
@@ -852,13 +845,7 @@
 ----------------------------------------------------------------*/
 int register_wlandev(wlandevice_t *wlandev)
 {
-	int i = 0;
-
-	i = register_netdev(wlandev->netdev);
-	if (i)
-		return i;
-
-	return 0;
+	return register_netdev(wlandev->netdev);
 }
 
 /*----------------------------------------------------------------
diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h
index 8588417..2fecca2 100644
--- a/drivers/staging/wlan-ng/p80211netdev.h
+++ b/drivers/staging/wlan-ng/p80211netdev.h
@@ -235,7 +235,7 @@
 		u8 *iv, u8 *icv);
 
 int wlan_setup(wlandevice_t *wlandev, struct device *physdev);
-int wlan_unsetup(wlandevice_t *wlandev);
+void wlan_unsetup(wlandevice_t *wlandev);
 int register_wlandev(wlandevice_t *wlandev);
 int unregister_wlandev(wlandevice_t *wlandev);
 void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb);
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index 179194e..cdfd808 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -73,7 +73,7 @@
 #include "p80211req.h"
 
 static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg);
-static int p80211req_mibset_mibget(wlandevice_t *wlandev,
+static void p80211req_mibset_mibget(wlandevice_t *wlandev,
 				   struct p80211msg_dot11req_mibget *mib_msg,
 				   int isget);
 
@@ -155,32 +155,29 @@
 	switch (msg->msgcode) {
 
 	case DIDmsg_lnxreq_hostwep:{
-			struct p80211msg_lnxreq_hostwep *req =
-			    (struct p80211msg_lnxreq_hostwep *) msg;
-			wlandev->hostwep &=
-			    ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT);
-			if (req->decrypt.data == P80211ENUM_truth_true)
-				wlandev->hostwep |= HOSTWEP_DECRYPT;
-			if (req->encrypt.data == P80211ENUM_truth_true)
-				wlandev->hostwep |= HOSTWEP_ENCRYPT;
+		struct p80211msg_lnxreq_hostwep *req =
+			(struct p80211msg_lnxreq_hostwep *) msg;
+		wlandev->hostwep &=
+				~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT);
+		if (req->decrypt.data == P80211ENUM_truth_true)
+			wlandev->hostwep |= HOSTWEP_DECRYPT;
+		if (req->encrypt.data == P80211ENUM_truth_true)
+			wlandev->hostwep |= HOSTWEP_ENCRYPT;
 
-			break;
-		}
+	break;
+	}
 	case DIDmsg_dot11req_mibget:
 	case DIDmsg_dot11req_mibset:{
-			int isget = (msg->msgcode == DIDmsg_dot11req_mibget);
-			struct p80211msg_dot11req_mibget *mib_msg =
-			    (struct p80211msg_dot11req_mibget *) msg;
-			p80211req_mibset_mibget(wlandev, mib_msg, isget);
-		}
-	default:
-		;
+		int isget = (msg->msgcode == DIDmsg_dot11req_mibget);
+		struct p80211msg_dot11req_mibget *mib_msg =
+			(struct p80211msg_dot11req_mibget *) msg;
+		p80211req_mibset_mibget(wlandev, mib_msg, isget);
+	break;
+	}
 	}			/* switch msg->msgcode */
-
-	return;
 }
 
-static int p80211req_mibset_mibget(wlandevice_t *wlandev,
+static void p80211req_mibset_mibget(wlandevice_t *wlandev,
 				   struct p80211msg_dot11req_mibget *mib_msg,
 				   int isget)
 {
@@ -190,76 +187,65 @@
 
 	switch (mibitem->did) {
 	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0:{
-			if (!isget)
-				wep_change_key(wlandev, 0, key, pstr->len);
-			break;
-		}
-	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1:{
-			if (!isget)
-				wep_change_key(wlandev, 1, key, pstr->len);
-			break;
-		}
-	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2:{
-			if (!isget)
-				wep_change_key(wlandev, 2, key, pstr->len);
-			break;
-		}
-	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3:{
-			if (!isget)
-				wep_change_key(wlandev, 3, key, pstr->len);
-			break;
-		}
-	case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID:{
-			u32 *data = (u32 *) mibitem->data;
-
-			if (isget) {
-				*data =
-				    wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
-			} else {
-				wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK);
-
-				wlandev->hostwep |=
-				    (*data & HOSTWEP_DEFAULTKEY_MASK);
-			}
-			break;
-		}
-	case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked:{
-			u32 *data = (u32 *) mibitem->data;
-
-			if (isget) {
-				if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
-					*data = P80211ENUM_truth_true;
-				else
-					*data = P80211ENUM_truth_false;
-			} else {
-				wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED);
-				if (*data == P80211ENUM_truth_true)
-					wlandev->hostwep |=
-					    HOSTWEP_PRIVACYINVOKED;
-			}
-			break;
-		}
-	case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted:{
-			u32 *data = (u32 *) mibitem->data;
-
-			if (isget) {
-				if (wlandev->hostwep &
-				    HOSTWEP_EXCLUDEUNENCRYPTED)
-					*data = P80211ENUM_truth_true;
-				else
-					*data = P80211ENUM_truth_false;
-			} else {
-				wlandev->hostwep &=
-				    ~(HOSTWEP_EXCLUDEUNENCRYPTED);
-				if (*data == P80211ENUM_truth_true)
-					wlandev->hostwep |=
-					    HOSTWEP_EXCLUDEUNENCRYPTED;
-			}
-			break;
-		}
-	default:
-		;
+		if (!isget)
+			wep_change_key(wlandev, 0, key, pstr->len);
+	break;
 	}
+	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1:{
+		if (!isget)
+			wep_change_key(wlandev, 1, key, pstr->len);
+	break;
+	}
+	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2:{
+		if (!isget)
+			wep_change_key(wlandev, 2, key, pstr->len);
+	break;
+	}
+	case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3:{
+		if (!isget)
+			wep_change_key(wlandev, 3, key, pstr->len);
+	break;
+	}
+	case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID:{
+		u32 *data = (u32 *) mibitem->data;
 
-	return 0;
+		if (isget) {
+			*data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
+		} else {
+			wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK);
+			wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK);
+		}
+	break;
+	}
+	case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked:{
+		u32 *data = (u32 *) mibitem->data;
+
+		if (isget) {
+			if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
+				*data = P80211ENUM_truth_true;
+			else
+				*data = P80211ENUM_truth_false;
+		} else {
+			wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED);
+			if (*data == P80211ENUM_truth_true)
+				wlandev->hostwep |= HOSTWEP_PRIVACYINVOKED;
+		}
+	break;
+	}
+	case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted:{
+		u32 *data = (u32 *) mibitem->data;
+
+		if (isget) {
+			if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
+				*data = P80211ENUM_truth_true;
+			else
+				*data = P80211ENUM_truth_false;
+		} else {
+			wlandev->hostwep &= ~(HOSTWEP_EXCLUDEUNENCRYPTED);
+			if (*data == P80211ENUM_truth_true)
+				wlandev->hostwep |= HOSTWEP_EXCLUDEUNENCRYPTED;
+		}
+	break;
+	}
+	}
 }
diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h
index f043090..8cb4fc6 100644
--- a/drivers/staging/wlan-ng/p80211types.h
+++ b/drivers/staging/wlan-ng/p80211types.h
@@ -197,7 +197,7 @@
 					P80211DID_LSB_ACCESS)
 
 /*----------------------------------------------------------------*/
-/* The following structure types are used for the represenation */
+/* The following structure types are used for the representation */
 /*  of ENUMint type metadata. */
 
 typedef struct p80211enumpair {
diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c
index 80c2d3b..77e50a4 100644
--- a/drivers/staging/wlan-ng/p80211wep.c
+++ b/drivers/staging/wlan-ng/p80211wep.c
@@ -134,10 +134,8 @@
 		return -1;
 
 #ifdef WEP_DEBUG
-	printk(KERN_DEBUG
-	       "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-	       keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5],
-	       key[6], key[7]);
+	printk(KERN_DEBUG "WEP key %d len %d = %*phC\n", keynum, keylen,
+			  8, key);
 #endif
 
 	wlandev->wep_keylens[keynum] = keylen;
@@ -184,10 +182,8 @@
 	keylen += 3;		/* add in IV bytes */
 
 #ifdef WEP_DEBUG
-	printk(KERN_DEBUG
-	       "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len,
-	       key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5],
-	       key[6], key[7]);
+	printk(KERN_DEBUG "D %d: %*ph (%d %d) %*phC\n", len, 3, key,
+			  keyidx, keylen, 5, key + 3);
 #endif
 
 	/* set up the RC4 state */
@@ -263,10 +259,8 @@
 	keylen += 3;		/* add in IV bytes */
 
 #ifdef WEP_DEBUG
-	printk(KERN_DEBUG
-	       "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len,
-	       iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4],
-	       key[5], key[6], key[7]);
+	printk(KERN_DEBUG "E %d (%d/%d %d) %*ph %*phC\n", len,
+			  iv[3], keynum, keylen, 3, key, 5, key + 3);
 #endif
 
 	/* set up the RC4 state */
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index 66c9aa9..0dfd2a4 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -123,27 +123,27 @@
 /* s-record image processing */
 
 /* Data records */
-unsigned int ns3data;
-struct s3datarec s3data[S3DATA_MAX];
+static unsigned int ns3data;
+static struct s3datarec s3data[S3DATA_MAX];
 
 /* Plug records */
-unsigned int ns3plug;
-struct s3plugrec s3plug[S3PLUG_MAX];
+static unsigned int ns3plug;
+static struct s3plugrec s3plug[S3PLUG_MAX];
 
 /* CRC records */
-unsigned int ns3crc;
-struct s3crcrec s3crc[S3CRC_MAX];
+static unsigned int ns3crc;
+static struct s3crcrec s3crc[S3CRC_MAX];
 
 /* Info records */
-unsigned int ns3info;
-struct s3inforec s3info[S3INFO_MAX];
+static unsigned int ns3info;
+static struct s3inforec s3info[S3INFO_MAX];
 
 /* S7 record (there _better_ be only one) */
-u32 startaddr;
+static u32 startaddr;
 
 /* Load image chunks */
-unsigned int nfchunks;
-struct imgchunk fchunk[CHUNKS_MAX];
+static unsigned int nfchunks;
+static struct imgchunk fchunk[CHUNKS_MAX];
 
 /* Note that for the following pdrec_t arrays, the len and code */
 /*   fields are stored in HOST byte order. The mkpdrlist() function */
@@ -151,11 +151,11 @@
 /*----------------------------------------------------------------*/
 /* PDA, built from [card|newfile]+[addfile1+addfile2...] */
 
-struct pda pda;
-hfa384x_compident_t nicid;
-hfa384x_caplevel_t rfid;
-hfa384x_caplevel_t macid;
-hfa384x_caplevel_t priid;
+static struct pda pda;
+static hfa384x_compident_t nicid;
+static hfa384x_caplevel_t rfid;
+static hfa384x_caplevel_t macid;
+static hfa384x_caplevel_t priid;
 
 /*================================================================*/
 /* Local Function Declarations */
@@ -237,7 +237,7 @@
 *	0	- success
 *	~0	- failure
 ----------------------------------------------------------------*/
-int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
+static int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
 {
 	signed int result = 0;
 	struct p80211msg_dot11req_mibget getmsg;
@@ -376,7 +376,7 @@
 *	0	success
 *	~0	failure
 ----------------------------------------------------------------*/
-int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
+static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
 	     struct s3crcrec *s3crc, unsigned int ns3crc)
 {
 	int result = 0;
@@ -440,7 +440,7 @@
 * Returns:
 *	nothing
 ----------------------------------------------------------------*/
-void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
+static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
 {
 	int i;
 	for (i = 0; i < *nfchunks; i++)
@@ -462,7 +462,7 @@
 * Returns:
 *	nothing
 ----------------------------------------------------------------*/
-void free_srecs(void)
+static void free_srecs(void)
 {
 	ns3data = 0;
 	memset(s3data, 0, sizeof(s3data));
@@ -489,7 +489,7 @@
 *	0	- success
 *	~0	- failure (probably an errno)
 ----------------------------------------------------------------*/
-int mkimage(struct imgchunk *clist, unsigned int *ccnt)
+static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
 {
 	int result = 0;
 	int i;
@@ -582,7 +582,7 @@
 *	0	- success
 *	~0	- failure (probably an errno)
 ----------------------------------------------------------------*/
-int mkpdrlist(struct pda *pda)
+static int mkpdrlist(struct pda *pda)
 {
 	int result = 0;
 	u16 *pda16 = (u16 *) pda->buf;
@@ -656,7 +656,7 @@
 *	0	success
 *	~0	failure
 ----------------------------------------------------------------*/
-int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
+static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
 	      struct s3plugrec *s3plug, unsigned int ns3plug, struct pda *pda)
 {
 	int result = 0;
@@ -764,7 +764,7 @@
 *	0	- success
 *	~0	- failure (probably an errno)
 ----------------------------------------------------------------*/
-int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
+static int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
 {
 	int result = 0;
 	struct p80211msg_p2req_readpda msg;
@@ -806,7 +806,7 @@
 *
 * Note also that the start address record, originally an S7 record in
 * the srec file, is expected in the fw file to be like a data record but
-* with a certain address to make it identiable.
+* with a certain address to make it identifiable.
 *
 * Here's the SREC format that the fw should have come from:
 * S[37]nnaaaaaaaaddd...dddcc
@@ -854,7 +854,7 @@
 *	0	- success
 *	~0	- failure (probably an errno)
 ----------------------------------------------------------------*/
-int read_fwfile(const struct ihex_binrec *record)
+static int read_fwfile(const struct ihex_binrec *record)
 {
 	int		i;
 	int		rcnt = 0;
@@ -978,7 +978,7 @@
 *	0	success
 *	~0	failure
 ----------------------------------------------------------------*/
-int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
+static int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 	       unsigned int nfchunks)
 {
 	int result = 0;
@@ -1130,7 +1130,7 @@
 	return result;
 }
 
-int validate_identity(void)
+static int validate_identity(void)
 {
 	int i;
 	int result = 1;
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 1dfd9aa..8d2277bb 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -242,7 +242,6 @@
 ----------------------------------------------------------------*/
 static void prism2sta_reset(wlandevice_t *wlandev)
 {
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -988,7 +987,6 @@
 				   hfa384x_InfFrame_t *inf)
 {
 	pr_debug("received infoframe:HANDOVER (unhandled)\n");
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1035,8 +1033,6 @@
 		for (i = 0; i < cnt; i++, dst++, src16++)
 			*dst += le16_to_cpu(*src16);
 	}
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1093,8 +1089,6 @@
 		printk(KERN_ERR "setconfig(joinreq) failed, result=%d\n",
 		       result);
 	}
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1194,7 +1188,6 @@
 	atomic_set(&hw->channel_info.done, 2);
 
 	hw->channel_info.count = n;
-	return;
 }
 
 void prism2sta_processing_defer(struct work_struct *data)
@@ -1218,7 +1211,7 @@
 
 	/* Now let's handle the linkstatus stuff */
 	if (hw->link_status == hw->link_status_new)
-		goto failed;
+		return;
 
 	hw->link_status = hw->link_status_new;
 
@@ -1272,7 +1265,7 @@
 				pr_debug
 				    ("getconfig(0x%02x) failed, result = %d\n",
 				     HFA384x_RID_CURRENTBSSID, result);
-				goto failed;
+				return;
 			}
 
 			result = hfa384x_drvr_getconfig(hw,
@@ -1282,7 +1275,7 @@
 				pr_debug
 				    ("getconfig(0x%02x) failed, result = %d\n",
 				     HFA384x_RID_CURRENTSSID, result);
-				goto failed;
+				return;
 			}
 			prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
 						(p80211pstrd_t *) &
@@ -1296,7 +1289,7 @@
 				pr_debug
 				    ("getconfig(0x%02x) failed, result = %d\n",
 				     HFA384x_RID_PORTSTATUS, result);
-				goto failed;
+				return;
 			}
 			wlandev->macmode =
 			    (portstatus == HFA384x_PSTATUS_CONN_IBSS) ?
@@ -1355,7 +1348,7 @@
 		if (result) {
 			pr_debug("getconfig(0x%02x) failed, result = %d\n",
 				 HFA384x_RID_CURRENTBSSID, result);
-			goto failed;
+			return;
 		}
 
 		result = hfa384x_drvr_getconfig(hw,
@@ -1364,7 +1357,7 @@
 		if (result) {
 			pr_debug("getconfig(0x%02x) failed, result = %d\n",
 				 HFA384x_RID_CURRENTSSID, result);
-			goto failed;
+			return;
 		}
 		prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
 					(p80211pstrd_t *) &wlandev->ssid);
@@ -1443,14 +1436,10 @@
 		/* This is bad, IO port problems? */
 		printk(KERN_WARNING
 		       "unknown linkstatus=0x%02x\n", hw->link_status);
-		goto failed;
-		break;
+		return;
 	}
 
 	wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED);
-
-failed:
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1478,8 +1467,6 @@
 	hw->link_status_new = le16_to_cpu(inf->info.linkstatus.linkstatus);
 
 	schedule_work(&hw->link_bh);
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1540,8 +1527,6 @@
 			printk(KERN_WARNING
 "authfail assocstatus info frame received for authenticated station.\n");
 	}
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1731,7 +1716,6 @@
 		       "setconfig(authenticatestation) failed, result=%d\n",
 		       result);
 	}
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1758,8 +1742,6 @@
 	hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
 
 	hw->psusercount = le16_to_cpu(inf->info.psusercnt.usercnt);
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1825,7 +1807,6 @@
 		       "Unknown info type=0x%02x\n", inf->infotype);
 		break;
 	}
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1850,8 +1831,6 @@
 void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status)
 {
 	pr_debug("TxExc status=0x%x.\n", status);
-
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1875,7 +1854,6 @@
 	pr_debug("Tx Complete, status=0x%04x\n", status);
 	/* update linux network stats */
 	wlandev->linux_stats.tx_packets++;
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1897,7 +1875,6 @@
 void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb)
 {
 	p80211netdev_rx(wlandev, skb);
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1919,7 +1896,6 @@
 void prism2sta_ev_alloc(wlandevice_t *wlandev)
 {
 	netif_wake_queue(wlandev->netdev);
-	return;
 }
 
 /*----------------------------------------------------------------
@@ -1988,12 +1964,12 @@
 	int result = 0;
 
 	if (hw->wlandev->hwremoved)
-		goto done;
+		return;
 
 	/* we don't care if we're in AP mode */
 	if ((wlandev->macmode == WLAN_MACMODE_NONE) ||
 	    (wlandev->macmode == WLAN_MACMODE_ESS_AP)) {
-		goto done;
+		return;
 	}
 
 	/* It only makes sense to poll these in non-IBSS */
@@ -2004,7 +1980,7 @@
 
 		if (result) {
 			printk(KERN_ERR "error fetching commsqual\n");
-			goto done;
+			return;
 		}
 
 		pr_debug("commsqual %d %d %d\n",
@@ -2021,7 +1997,7 @@
 	if (result) {
 		pr_debug("get signal rate failed, result = %d\n",
 			 result);
-		goto done;
+		return;
 	}
 
 	switch (mibitem->data) {
@@ -2048,7 +2024,7 @@
 	if (result) {
 		pr_debug("getconfig(0x%02x) failed, result = %d\n",
 			 HFA384x_RID_CURRENTBSSID, result);
-		goto done;
+		return;
 	}
 
 	result = hfa384x_drvr_getconfig(hw,
@@ -2057,16 +2033,13 @@
 	if (result) {
 		pr_debug("getconfig(0x%02x) failed, result = %d\n",
 			 HFA384x_RID_CURRENTSSID, result);
-		goto done;
+		return;
 	}
 	prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
 				(p80211pstrd_t *) &wlandev->ssid);
 
 	/* Reschedule timer */
 	mod_timer(&hw->commsqual_timer, jiffies + HZ);
-
-done:
-	;
 }
 
 void prism2sta_commsqual_timer(unsigned long data)
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 64ffd70..f775c54 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -6,6 +6,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/sizes.h>
 #include <linux/module.h>
 
 #ifdef CONFIG_MTRR
@@ -329,6 +330,7 @@
 {
 	u16 xres, yres;
 	struct xgi_hw_device_info *hw_info = &xgifb_info->hw_info;
+	unsigned long required_mem;
 
 	if (xgifb_info->chip == XG21) {
 		if (xgifb_info->display2 == XGIFB_DISP_LCD) {
@@ -345,13 +347,13 @@
 			}
 
 		}
-		return myindex;
+		goto check_memory;
 
 	}
 
 	/* FIXME: for now, all is valid on XG27 */
 	if (xgifb_info->chip == XG27)
-		return myindex;
+		goto check_memory;
 
 	if (!(XGIbios_mode[myindex].chipset & MD_XGI315))
 		return -1;
@@ -539,6 +541,12 @@
 	case XGIFB_DISP_NONE:
 		break;
 	}
+
+check_memory:
+	required_mem = XGIbios_mode[myindex].xres * XGIbios_mode[myindex].yres *
+		       XGIbios_mode[myindex].bpp / 8;
+	if (required_mem > xgifb_info->video_size)
+		return -1;
 	return myindex;
 
 }
@@ -913,17 +921,10 @@
 			}
 
 			if ((filter >= 0) && (filter <= 7)) {
-				pr_debug("FilterTable[%d]-%d: %02x %02x %02x %02x\n",
+				pr_debug("FilterTable[%d]-%d: %*ph\n",
 					 filter_tb, filter,
-					 XGI_TV_filter[filter_tb].
-						filter[filter][0],
-					 XGI_TV_filter[filter_tb].
-						filter[filter][1],
-					 XGI_TV_filter[filter_tb].
-						filter[filter][2],
-					 XGI_TV_filter[filter_tb].
-						filter[filter][3]
-				);
+					 4, XGI_TV_filter[filter_tb].
+						   filter[filter]);
 				xgifb_reg_set(
 					XGIPART2,
 					0x35,
@@ -1404,11 +1405,10 @@
 		if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual
 				|| var->xoffset)
 			return -EINVAL;
-	} else {
-		if (var->xoffset + info->var.xres > info->var.xres_virtual
+	} else if (var->xoffset + info->var.xres > info->var.xres_virtual
 				|| var->yoffset + info->var.yres
-						> info->var.yres_virtual)
-			return -EINVAL;
+						> info->var.yres_virtual) {
+		return -EINVAL;
 	}
 	err = XGIfb_pan_var(var, info);
 	if (err < 0)
@@ -1471,6 +1471,9 @@
 		xgifb_reg_set(XGISR, IND_SIS_DRAM_SIZE, 0x51);
 
 	reg = xgifb_reg_get(XGISR, IND_SIS_DRAM_SIZE);
+	if (!reg)
+		return -1;
+
 	switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) {
 	case XGI_DRAM_SIZE_1MB:
 		xgifb_info->video_size = 0x100000;
@@ -1701,6 +1704,7 @@
 	struct fb_info *fb_info;
 	struct xgifb_video_info *xgifb_info;
 	struct xgi_hw_device_info *hw_info;
+	unsigned long video_size_max;
 
 	fb_info = framebuffer_alloc(sizeof(*xgifb_info), &pdev->dev);
 	if (!fb_info)
@@ -1721,6 +1725,7 @@
 	xgifb_info->subsysvendor = pdev->subsystem_vendor;
 	xgifb_info->subsysdevice = pdev->subsystem_device;
 
+	video_size_max = pci_resource_len(pdev, 0);
 	xgifb_info->video_base = pci_resource_start(pdev, 0);
 	xgifb_info->mmio_base = pci_resource_start(pdev, 1);
 	xgifb_info->mmio_size = pci_resource_len(pdev, 1);
@@ -1777,10 +1782,10 @@
 	hw_info->jChipType = xgifb_info->chip;
 
 	if (XGIfb_get_dram_size(xgifb_info)) {
-		dev_err(&pdev->dev,
-			"Fatal error: Unable to determine RAM size.\n");
-		ret = -ENODEV;
-		goto error_disable;
+		xgifb_info->video_size = min_t(unsigned long, video_size_max,
+						SZ_16M);
+	} else if (xgifb_info->video_size > video_size_max) {
+		xgifb_info->video_size = video_size_max;
 	}
 
 	/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
index 69078d9..77137e4 100644
--- a/drivers/staging/xgifb/vb_def.h
+++ b/drivers/staging/xgifb/vb_def.h
@@ -3,9 +3,7 @@
 #include "../../video/sis/initdef.h"
 
 #define VB_XGI301C      0x0020 /* for 301C */
-#define VB_YPbPr1080i   0x03
 
-#define LVDSCRT1Len     15
 #define SupportCRT2in301C       0x0100  /* for 301C */
 #define SetCHTVOverScan         0x8000
 
@@ -22,15 +20,6 @@
 
 #define XGI_CRT2_PORT_00        (0x00 - 0x030)
 
-/* =============================================================
-   for 310
-============================================================== */
-#define ModeSoftSetting              0x04
-
-/* ---------------- SetMode Stack */
-#define CRT1Len           15
-#define VCLKLen           4
-
 #define SupportAllCRT2      0x0078
 #define NoSupportTV         0x0070
 #define NoSupportHiVisionTV 0x0060
@@ -115,16 +104,6 @@
 #define ActiveHiTV            0x08
 #define ActiveYPbPr           0x10
 
-/* --------------------------------------------------------- */
-/* translated from asm code 301def.h */
-/*  */
-/* --------------------------------------------------------- */
-#define LVDSCRT1Len_H        8
-#define LVDSCRT1Len_V        7
-#define LCDDesDataLen        6
-#define LVDSDesDataLen2      8
-#define LCDDesDataLen2       8
-
 #define NTSC1024x768HT       1908
 
 #define YPbPrTV525iHT        1716 /* YPbPr */
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 80dba6a..7739dbd 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -1269,7 +1269,7 @@
 	if (temp <= 2)
 		temp &= 0x03;
 	else
-		temp = ((temp & 0x04) >> 1) || ((~temp) & 0x01);
+		temp = ((temp & 0x04) >> 1) | ((~temp) & 0x01);
 
 	xgifb_reg_set(pVBInfo->P3d4, 0x4A, CR4A);
 
@@ -1299,8 +1299,6 @@
 
 	outb(0x67, (pVBInfo->BaseAddr + 0x12)); /* 3c2 <- 67 ,ynlai */
 
-	pVBInfo->ISXPDOS = 0;
-
 	pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14;
 	pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24;
 	pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10;
@@ -1494,7 +1492,6 @@
 	XGINew_SetModeScratch(HwDeviceExtension, pVBInfo);
 
 	xgifb_reg_set(pVBInfo->P3d4, 0x8c, 0x87);
-	xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x31);
 
 	return 1;
 } /* end of init */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index e81149f..e95a165 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -23,20 +23,18 @@
 
 void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 {
-	pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable;
-	pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable;
-	pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex;
-	pVBInfo->XGINEWUB_CRT1Table
-			= (struct XGI_CRT1TableStruct *) XGI_CRT1Table;
+	pVBInfo->StandTable = &XGI330_StandTable;
+	pVBInfo->EModeIDTable = XGI330_EModeIDTable;
+	pVBInfo->RefIndex = XGI330_RefIndex;
+	pVBInfo->XGINEWUB_CRT1Table = XGI_CRT1Table;
 
-	pVBInfo->MCLKData = (struct SiS_MCLKData *) XGI340New_MCLKData;
-	pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI340_ECLKData;
-	pVBInfo->VCLKData = (struct SiS_VCLKData *) XGI_VCLKData;
-	pVBInfo->VBVCLKData = (struct SiS_VBVCLKData *) XGI_VBVCLKData;
+	pVBInfo->MCLKData = XGI340New_MCLKData;
+	pVBInfo->ECLKData = XGI340_ECLKData;
+	pVBInfo->VCLKData = XGI_VCLKData;
+	pVBInfo->VBVCLKData = XGI_VBVCLKData;
 	pVBInfo->ScreenOffset = XGI330_ScreenOffset;
-	pVBInfo->StResInfo = (struct SiS_StResInfo_S *) XGI330_StResInfo;
-	pVBInfo->ModeResInfo
-			= (struct SiS_ModeResInfo_S *) XGI330_ModeResInfo;
+	pVBInfo->StResInfo = XGI330_StResInfo;
+	pVBInfo->ModeResInfo = XGI330_ModeResInfo;
 
 	pVBInfo->LCDResInfo = 0;
 	pVBInfo->LCDTypeInfo = 0;
@@ -56,24 +54,9 @@
 	pVBInfo->SR21 = 0xa3;
 	pVBInfo->SR22 = 0xfb;
 
-	pVBInfo->NTSCTiming = XGI330_NTSCTiming;
-	pVBInfo->PALTiming = XGI330_PALTiming;
-	pVBInfo->HiTVExtTiming = XGI330_HiTVExtTiming;
-	pVBInfo->HiTVSt1Timing = XGI330_HiTVSt1Timing;
-	pVBInfo->HiTVSt2Timing = XGI330_HiTVSt2Timing;
-	pVBInfo->HiTVTextTiming = XGI330_HiTVTextTiming;
-	pVBInfo->YPbPr750pTiming = XGI330_YPbPr750pTiming;
-	pVBInfo->YPbPr525pTiming = XGI330_YPbPr525pTiming;
-	pVBInfo->YPbPr525iTiming = XGI330_YPbPr525iTiming;
-	pVBInfo->HiTVGroup3Data = XGI330_HiTVGroup3Data;
-	pVBInfo->HiTVGroup3Simu = XGI330_HiTVGroup3Simu;
-	pVBInfo->HiTVGroup3Text = XGI330_HiTVGroup3Text;
-	pVBInfo->Ren525pGroup3 = XGI330_Ren525pGroup3;
-	pVBInfo->Ren750pGroup3 = XGI330_Ren750pGroup3;
-
-	pVBInfo->TimingH = (struct XGI_TimingHStruct *) XGI_TimingH;
-	pVBInfo->TimingV = (struct XGI_TimingVStruct *) XGI_TimingV;
-	pVBInfo->UpdateCRT1 = (struct XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table;
+	pVBInfo->TimingH = XGI_TimingH;
+	pVBInfo->TimingV = XGI_TimingV;
+	pVBInfo->UpdateCRT1 = XGI_UpdateCRT1Table;
 
 	/* 310 customization related */
 	if ((pVBInfo->VBType & VB_SIS301LV) || (pVBInfo->VBType & VB_SIS302LV))
@@ -86,8 +69,7 @@
 
 	if (ChipType == XG27) {
 		unsigned char temp;
-		pVBInfo->MCLKData
-			= (struct SiS_MCLKData *) XGI27New_MCLKData;
+		pVBInfo->MCLKData = XGI27New_MCLKData;
 		pVBInfo->CR40 = XGI27_cr41;
 		pVBInfo->XGINew_CR97 = 0xc1;
 		pVBInfo->SR15 = XG27_SR13;
@@ -116,11 +98,9 @@
 	i = XGI_SetCRT2ToLCDA;
 	if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 		tempah |= 0x01;
-	} else {
-		if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
-			if (pVBInfo->VBInfo & SetInSlaveMode)
-				tempah |= 0x01;
-		}
+	} else if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
+		if (pVBInfo->VBInfo & SetInSlaveMode)
+			tempah |= 0x01;
 	}
 
 	tempah |= 0x20; /* screen off */
@@ -165,10 +145,9 @@
 		if ((modeflag & Charx8Dot) && i == 0x13) { /* ifndef Dot9 */
 			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
 				ARdata = 0;
-			} else {
-				if ((pVBInfo->VBInfo &
+			} else if ((pVBInfo->VBInfo &
 				     (SetCRT2ToTV | SetCRT2ToLCD)) &&
-				    (pVBInfo->VBInfo & SetInSlaveMode))
+				    (pVBInfo->VBInfo & SetInSlaveMode)) {
 					ARdata = 0;
 			}
 		}
@@ -258,59 +237,45 @@
 		}
 
 		if (pVBInfo->VBInfo & SetCRT2ToHiVision) { /* for HiTV */
-			if ((pVBInfo->VBType & VB_SIS301LV) &&
-			    (pVBInfo->VBExtInfo == VB_YPbPr1080i)) {
-				tempax |= SupportYPbPr750p;
-				if ((pVBInfo->VBInfo & SetInSlaveMode) &&
-				    ((resinfo == 3) ||
-				     (resinfo == 4) ||
-				     (resinfo > 7)))
+			tempax |= SupportHiVision;
+			if ((pVBInfo->VBInfo & SetInSlaveMode) &&
+			    ((resinfo == 4) ||
+			     (resinfo == 3 &&
+			      (pVBInfo->SetFlag & TVSimuMode)) ||
+			     (resinfo > 7)))
 					return 0;
-			} else {
-				tempax |= SupportHiVision;
-				if ((pVBInfo->VBInfo & SetInSlaveMode) &&
-				    ((resinfo == 4) ||
-				     (resinfo == 3 &&
-				      (pVBInfo->SetFlag & TVSimuMode)) ||
-				     (resinfo > 7)))
-						return 0;
-			}
-		} else {
-			if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO |
+		} else if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO |
 					       SetCRT2ToSVIDEO |
 					       SetCRT2ToSCART |
 					       SetCRT2ToYPbPr525750 |
 					       SetCRT2ToHiVision)) {
-				tempax |= SupportTV;
+			tempax |= SupportTV;
 
-				if (pVBInfo->VBType & (VB_SIS301B |
-						       VB_SIS302B |
-						       VB_SIS301LV |
-						       VB_SIS302LV |
-						       VB_XGI301C))
-					tempax |= SupportTV1024;
+			if (pVBInfo->VBType & (VB_SIS301B |
+					       VB_SIS302B |
+					       VB_SIS301LV |
+					       VB_SIS302LV |
+					       VB_XGI301C))
+				tempax |= SupportTV1024;
 
-				if (!(pVBInfo->VBInfo & TVSetPAL) &&
-				    (modeflag & NoSupportSimuTV) &&
-				    (pVBInfo->VBInfo & SetInSlaveMode) &&
-				    (!(pVBInfo->VBInfo & SetNotSimuMode)))
-					return 0;
-			}
+			if (!(pVBInfo->VBInfo & TVSetPAL) &&
+			    (modeflag & NoSupportSimuTV) &&
+			    (pVBInfo->VBInfo & SetInSlaveMode) &&
+			    (!(pVBInfo->VBInfo & SetNotSimuMode)))
+				return 0;
 		}
-	} else { /* for LVDS */
-		if (pVBInfo->VBInfo & SetCRT2ToLCD) {
-			tempax |= SupportLCD;
+	} else if (pVBInfo->VBInfo & SetCRT2ToLCD) { /* for LVDS */
+		tempax |= SupportLCD;
 
-			if (resinfo > 0x08)
-				return 0; /* 1024x768 */
+		if (resinfo > 0x08)
+			return 0; /* 1024x768 */
 
-			if (pVBInfo->LCDResInfo < Panel_1024x768) {
-				if (resinfo > 0x07)
-					return 0; /* 800x600 */
+		if (pVBInfo->LCDResInfo < Panel_1024x768) {
+			if (resinfo > 0x07)
+				return 0; /* 800x600 */
 
-				if (resinfo == 0x04)
-					return 0; /* 512x384 */
-			}
+			if (resinfo == 0x04)
+				return 0; /* 512x384 */
 		}
 	}
 
@@ -969,13 +934,8 @@
 			}
 
 			/* 301lv */
-			if ((pVBInfo->VBType & VB_SIS301LV) &&
-			    !(pVBInfo->VBExtInfo == VB_YPbPr1080i)) {
-				if (pVBInfo->VBExtInfo == YPbPr750p)
-					VCLKIndex = XGI_YPbPr750pVCLK;
-				else if (pVBInfo->VBExtInfo == YPbPr525p)
-					VCLKIndex = YPbPr525pVCLK;
-				else if (pVBInfo->SetFlag & RPLLDIV2XO)
+			if (pVBInfo->VBType & VB_SIS301LV) {
+				if (pVBInfo->SetFlag & RPLLDIV2XO)
 					VCLKIndex = YPbPr525iVCLK_2;
 				else
 					VCLKIndex = YPbPr525iVCLK;
@@ -991,13 +951,11 @@
 								Ext_CRTVCLK;
 			VCLKIndex &= IndexMask;
 		}
-	} else { /* LVDS */
-		if ((pVBInfo->LCDResInfo == Panel_800x600) ||
-		    (pVBInfo->LCDResInfo == Panel_320x480))
-			VCLKIndex = VCLK40; /* LVDSXlat1VCLK */
-		else
-			VCLKIndex = VCLK65_315 + 2; /* LVDSXlat2VCLK,
-						       LVDSXlat3VCLK  */
+	} else if ((pVBInfo->LCDResInfo == Panel_800x600) ||
+		   (pVBInfo->LCDResInfo == Panel_320x480)) { /* LVDS */
+		VCLKIndex = VCLK40; /* LVDSXlat1VCLK */
+	} else {
+		VCLKIndex = VCLK65_315 + 2; /* LVDSXlat2VCLK, LVDSXlat3VCLK */
 	}
 
 	return VCLKIndex;
@@ -1352,7 +1310,7 @@
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short i, tempdx, tempcx, tempbx, tempal, modeflag, table;
+	unsigned short i, tempdx, tempbx, tempal, modeflag, table;
 
 	struct XGI330_LCDDataTablStruct *tempdi = NULL;
 
@@ -1377,15 +1335,6 @@
 		tempal = (tempal & 0x0f);
 	}
 
-	tempcx = LCDLenList[tempbx];
-
-	if (pVBInfo->LCDInfo & EnableScalingLCD) { /* ScaleLCD */
-		if ((tempbx == 5) || (tempbx) == 7)
-			tempcx = LCDDesDataLen2;
-		else if ((tempbx == 3) || (tempbx == 8))
-			tempcx = LVDSDesDataLen2;
-	}
-
 	switch (tempbx) {
 	case 0:
 	case 1:
@@ -1403,14 +1352,6 @@
 	case 5:
 		tempdi = XGI_LCDDesDataTable;
 		break;
-	case 6:
-		tempdi = XGI_EPLCHLCDRegPtr;
-		break;
-	case 7:
-	case 8:
-	case 9:
-		tempdi = NULL;
-		break;
 	default:
 		break;
 	}
@@ -1764,62 +1705,20 @@
 		default:
 			break;
 		}
-	} else if (table == 6) {
-		switch (tempdi[i].DATAPTR) {
-		case 0:
-			return &XGI_CH7017LV1024x768[tempal];
-			break;
-		case 1:
-			return &XGI_CH7017LV1400x1050[tempal];
-			break;
-		default:
-			break;
-		}
 	}
 	return NULL;
 }
 
-static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo,
+static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeNo,
 		unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short i, tempdx, tempbx, tempal, modeflag, table;
-	struct XGI330_TVDataTablStruct *tempdi = NULL;
+	unsigned short i, tempdx, tempal, modeflag;
 
-	tempbx = BX;
 	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 	tempal = tempal & 0x3f;
-	table = tempbx;
-
-	switch (tempbx) {
-	case 0:
-		tempdi = NULL;
-		break;
-	case 1:
-		tempdi = NULL;
-		break;
-	case 2:
-	case 6:
-		tempdi = xgifb_chrontel_tv;
-		break;
-	case 3:
-		tempdi = NULL;
-		break;
-	case 4:
-		tempdi = XGI_TVDataTable;
-		break;
-	case 5:
-		tempdi = NULL;
-		break;
-	default:
-		break;
-	}
-
-	if (tempdi == NULL) /* OEMUtil */
-		return NULL;
-
 	tempdx = pVBInfo->TVInfo;
 
 	if (pVBInfo->VBInfo & SetInSlaveMode)
@@ -1830,78 +1729,14 @@
 
 	i = 0;
 
-	while (tempdi[i].MASK != 0xffff) {
-		if ((tempdx & tempdi[i].MASK) == tempdi[i].CAP)
+	while (XGI_TVDataTable[i].MASK != 0xffff) {
+		if ((tempdx & XGI_TVDataTable[i].MASK) ==
+			XGI_TVDataTable[i].CAP)
 			break;
 		i++;
 	}
 
-	if (table == 0x04) {
-		switch (tempdi[i].DATAPTR) {
-		case 0:
-			return &XGI_ExtPALData[tempal];
-			break;
-		case 1:
-			return &XGI_ExtNTSCData[tempal];
-			break;
-		case 2:
-			return &XGI_StPALData[tempal];
-			break;
-		case 3:
-			return &XGI_StNTSCData[tempal];
-			break;
-		case 4:
-			return &XGI_ExtHiTVData[tempal];
-			break;
-		case 5:
-			return &XGI_St2HiTVData[tempal];
-			break;
-		case 6:
-			return &XGI_ExtYPbPr525iData[tempal];
-			break;
-		case 7:
-			return &XGI_ExtYPbPr525pData[tempal];
-			break;
-		case 8:
-			return &XGI_ExtYPbPr750pData[tempal];
-			break;
-		case 9:
-			return &XGI_StYPbPr525iData[tempal];
-			break;
-		case 10:
-			return &XGI_StYPbPr525pData[tempal];
-			break;
-		case 11:
-			return &XGI_StYPbPr750pData[tempal];
-			break;
-		case 12: /* avoid system hang */
-			return &XGI_ExtNTSCData[tempal];
-			break;
-		case 13:
-			return &XGI_St1HiTVData[tempal];
-			break;
-		default:
-			break;
-		}
-	} else if (table == 0x02) {
-		switch (tempdi[i].DATAPTR) {
-		case 0:
-			return &XGI_CHTVUNTSCData[tempal];
-			break;
-		case 1:
-			return &XGI_CHTVONTSCData[tempal];
-			break;
-		case 2:
-			return &XGI_CHTVUPALData[tempal];
-			break;
-		case 3:
-			return &XGI_CHTVOPALData[tempal];
-			break;
-		default:
-			break;
-		}
-	}
-	return NULL;
+	return &XGI_TVDataTable[i].DATAPTR[tempal];
 }
 
 static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex,
@@ -1914,9 +1749,8 @@
 	tempbx = 2;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = (struct SiS_LVDSData *)XGI_GetLcdPtr(tempbx,
-				ModeNo, ModeIdIndex, RefreshRateTableIndex,
-				pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+				       RefreshRateTableIndex, pVBInfo);
 		pVBInfo->VGAHT = LCDPtr->VGAHT;
 		pVBInfo->VGAVT = LCDPtr->VGAVT;
 		pVBInfo->HT = LCDPtr->LCDHT;
@@ -1962,11 +1796,8 @@
 	tempbx = 0;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = (struct XGI_LVDSCRT1HDataStruct *)
-				XGI_GetLcdPtr(tempbx, ModeNo,
-					      ModeIdIndex,
-					      RefreshRateTableIndex,
-					      pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+				       RefreshRateTableIndex, pVBInfo);
 
 		for (i = 0; i < 8; i++)
 			pVBInfo->TimingH[0].data[i] = LCDPtr[0].Reg[i];
@@ -1977,13 +1808,8 @@
 	tempbx = 1;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr1 = (struct XGI_LVDSCRT1VDataStruct *)
-				XGI_GetLcdPtr(
-					tempbx,
-					ModeNo,
-					ModeIdIndex,
-					RefreshRateTableIndex,
-					pVBInfo);
+		LCDPtr1 = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+					RefreshRateTableIndex, pVBInfo);
 		for (i = 0; i < 7; i++)
 			pVBInfo->TimingV[0].data[i] = LCDPtr1[0].Reg[i];
 	}
@@ -2075,23 +1901,11 @@
 	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 	tempbx = 3;
 	if (pVBInfo->LCDInfo & EnableScalingLCD)
-		LCDPtr1 =
-		    (struct XGI330_LCDDataDesStruct2 *)
-				XGI_GetLcdPtr(
-					  tempbx,
-					  ModeNo,
-					  ModeIdIndex,
-					  RefreshRateTableIndex,
-					  pVBInfo);
+		LCDPtr1 = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+					RefreshRateTableIndex, pVBInfo);
 	else
-		LCDPtr =
-		    (struct XGI_LCDDesStruct *)
-				XGI_GetLcdPtr(
-					  tempbx,
-					  ModeNo,
-					  ModeIdIndex,
-					  RefreshRateTableIndex,
-					  pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+				       RefreshRateTableIndex, pVBInfo);
 
 	XGI_GetLCDSync(&tempax, &tempbx, pVBInfo);
 	push1 = tempbx;
@@ -2438,8 +2252,8 @@
 			| VB_SIS301LV | VB_SIS302LV | VB_XGI301C)) {
 		if ((!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) &&
 		    (pVBInfo->SetFlag & ProgrammingCRT2)) {
-			*di_0 = (unsigned char) XGI_VBVCLKData[tempal].SR2B;
-			*di_1 = XGI_VBVCLKData[tempal].SR2C;
+			*di_0 = XGI_VBVCLKData[tempal].Part4_A;
+			*di_1 = XGI_VBVCLKData[tempal].Part4_B;
 		}
 	} else {
 		*di_0 = XGI_VCLKData[tempal].SR2B;
@@ -2634,21 +2448,16 @@
 
 	temp = xgifb_reg_get(pVBInfo->P3d4, 0x38);
 
-	if (pVBInfo->IF_DEF_LCDA == 1) {
-
-		if (((HwDeviceExtension->jChipType >= XG20) ||
-		     (HwDeviceExtension->jChipType >= XG40)) &&
-		    (pVBInfo->IF_DEF_LVDS == 0)) {
-			if (pVBInfo->VBType &
-			    (VB_SIS302B |
-			     VB_SIS301LV |
-			     VB_SIS302LV |
-			     VB_XGI301C)) {
-				if (temp & EnableDualEdge) {
-					tempbx |= SetCRT2ToDualEdge;
-					if (temp & SetToLCDA)
-						tempbx |= XGI_SetCRT2ToLCDA;
-				}
+	if (pVBInfo->IF_DEF_LVDS == 0) {
+		if (pVBInfo->VBType &
+		    (VB_SIS302B |
+		     VB_SIS301LV |
+		     VB_SIS302LV |
+		     VB_XGI301C)) {
+			if (temp & EnableDualEdge) {
+				tempbx |= SetCRT2ToDualEdge;
+				if (temp & SetToLCDA)
+					tempbx |= XGI_SetCRT2ToLCDA;
 			}
 		}
 	}
@@ -2687,11 +2496,10 @@
 				temp = 0x09FC;
 			else
 				temp = 0x097C;
+		} else if (pVBInfo->IF_DEF_HiVision == 1) {
+			temp = 0x01FC;
 		} else {
-			if (pVBInfo->IF_DEF_HiVision == 1)
-				temp = 0x01FC;
-			else
-				temp = 0x017C;
+			temp = 0x017C;
 		}
 	} else { /* 3nd party chip */
 		temp = SetCRT2ToLCD;
@@ -2702,19 +2510,17 @@
 		tempbx = 0;
 	}
 
-	if (pVBInfo->IF_DEF_LCDA == 1) { /* Select Display Device */
-		if (!(pVBInfo->VBType & VB_NoLCD)) {
-			if (tempbx & XGI_SetCRT2ToLCDA) {
-				if (tempbx & SetSimuScanMode)
-					tempbx &= (~(SetCRT2ToLCD |
-						     SetCRT2ToRAMDAC |
-						     SwitchCRT2));
-				else
-					tempbx &= (~(SetCRT2ToLCD |
-						     SetCRT2ToRAMDAC |
-						     SetCRT2ToTV |
-						     SwitchCRT2));
-			}
+	if (!(pVBInfo->VBType & VB_NoLCD)) {
+		if (tempbx & XGI_SetCRT2ToLCDA) {
+			if (tempbx & SetSimuScanMode)
+				tempbx &= (~(SetCRT2ToLCD |
+					     SetCRT2ToRAMDAC |
+					     SwitchCRT2));
+			else
+				tempbx &= (~(SetCRT2ToLCD |
+					     SetCRT2ToRAMDAC |
+					     SetCRT2ToTV |
+					     SwitchCRT2));
 		}
 	}
 
@@ -2777,11 +2583,9 @@
 	if (!(tempbx & DisableCRT2Display)) {
 		if ((!(tempbx & DriverMode)) ||
 		    (!(modeflag & CRT2Mode))) {
-			if (pVBInfo->IF_DEF_LCDA == 1) {
-				if (!(tempbx & XGI_SetCRT2ToLCDA))
-					tempbx |= (SetInSlaveMode |
-						   SetSimuScanMode);
-			}
+			if (!(tempbx & XGI_SetCRT2ToLCDA))
+				tempbx |= (SetInSlaveMode |
+					   SetSimuScanMode);
 		}
 
 		/* LCD+TV can't support in slave mode
@@ -2867,19 +2671,17 @@
 			if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 				if (pVBInfo->VBInfo & SetInSlaveMode)
 					tempbx &= (~RPLLDIV2XO);
-			} else {
-				if (tempbx &
-				    (TVSetYPbPr525p | TVSetYPbPr750p))
+			} else if (tempbx &
+				    (TVSetYPbPr525p | TVSetYPbPr750p)) {
 					tempbx &= (~RPLLDIV2XO);
-				else if (!(pVBInfo->VBType &
+			} else if (!(pVBInfo->VBType &
 					 (VB_SIS301B |
 					  VB_SIS302B |
 					  VB_SIS301LV |
 					  VB_SIS302LV |
 					  VB_XGI301C))) {
-					if (tempbx & TVSimuMode)
-						tempbx &= (~RPLLDIV2XO);
-				}
+				if (tempbx & TVSimuMode)
+					tempbx &= (~RPLLDIV2XO);
 			}
 		}
 	}
@@ -2960,20 +2762,6 @@
 			tempbx |= SetLCDtoNonExpanding;
 	}
 
-	if (pVBInfo->IF_DEF_ExpLink == 1) {
-		if (modeflag & HalfDCLK) {
-			if (!(tempbx & SetLCDtoNonExpanding)) {
-				tempbx |= XGI_EnableLVDSDDA;
-			} else {
-				if (pVBInfo->LCDResInfo == Panel_1024x768) {
-					if (resinfo == 4) {/* 512x384 */
-						tempbx |= XGI_EnableLVDSDDA;
-					}
-				}
-			}
-		}
-	}
-
 	if (pVBInfo->VBInfo & SetInSlaveMode) {
 		if (pVBInfo->VBInfo & SetNotSimuMode)
 			tempbx |= XGI_LCDVESATiming;
@@ -3122,33 +2910,6 @@
 	xgifb_reg_and_or(pVBInfo->P3d4, 0x48, ~tempbh, tempbl);
 }
 
-/* --------------------------------------------------------------------- */
-/* Function : XGI_XG21SetPanelDelay */
-/* Input : */
-/* Output : */
-/* Description : */
-/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */
-/* : bl : 2 ; T2 : the duration signal on and Vdd on */
-/* : bl : 3 ; T3 : the duration between CPL off and signal off */
-/* : bl : 4 ; T4 : the duration signal off and Vdd off */
-/* --------------------------------------------------------------------- */
-static void XGI_XG21SetPanelDelay(struct xgifb_video_info *xgifb_info,
-		unsigned short tempbl,
-		struct vb_device_info *pVBInfo)
-{
-	if (tempbl == 1)
-		mdelay(xgifb_info->lvds_data.PSC_S1);
-
-	if (tempbl == 2)
-		mdelay(xgifb_info->lvds_data.PSC_S2);
-
-	if (tempbl == 3)
-		mdelay(xgifb_info->lvds_data.PSC_S3);
-
-	if (tempbl == 4)
-		mdelay(xgifb_info->lvds_data.PSC_S4);
-}
-
 static void XGI_DisplayOn(struct xgifb_video_info *xgifb_info,
 		struct xgi_hw_device_info *pXGIHWDE,
 		struct vb_device_info *pVBInfo)
@@ -3160,12 +2921,12 @@
 			if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x1)) {
 				/* LVDS VDD on */
 				XGI_XG21BLSignalVDD(0x01, 0x01, pVBInfo);
-				XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo);
+				mdelay(xgifb_info->lvds_data.PSC_S2);
 			}
 			if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x20))
 				/* LVDS signal on */
 				XGI_XG21BLSignalVDD(0x20, 0x20, pVBInfo);
-			XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo);
+			mdelay(xgifb_info->lvds_data.PSC_S3);
 			/* LVDS backlight on */
 			XGI_XG21BLSignalVDD(0x02, 0x02, pVBInfo);
 		} else {
@@ -3180,12 +2941,12 @@
 			if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x1)) {
 				/* LVDS VDD on */
 				XGI_XG27BLSignalVDD(0x01, 0x01, pVBInfo);
-				XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo);
+				mdelay(xgifb_info->lvds_data.PSC_S2);
 			}
 			if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x20))
 				/* LVDS signal on */
 				XGI_XG27BLSignalVDD(0x20, 0x20, pVBInfo);
-			XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo);
+			mdelay(xgifb_info->lvds_data.PSC_S3);
 			/* LVDS backlight on */
 			XGI_XG27BLSignalVDD(0x02, 0x02, pVBInfo);
 		} else {
@@ -3205,7 +2966,7 @@
 		if (pVBInfo->IF_DEF_LVDS == 1) {
 			/* LVDS backlight off */
 			XGI_XG21BLSignalVDD(0x02, 0x00, pVBInfo);
-			XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo);
+			mdelay(xgifb_info->lvds_data.PSC_S3);
 		} else {
 			/* DVO/DVI signal off */
 			XGI_XG21BLSignalVDD(0x20, 0x00, pVBInfo);
@@ -3216,7 +2977,7 @@
 		if ((XGI_XG27GetPSCValue(pVBInfo) & 0x2)) {
 			/* LVDS backlight off */
 			XGI_XG27BLSignalVDD(0x02, 0x00, pVBInfo);
-			XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo);
+			mdelay(xgifb_info->lvds_data.PSC_S3);
 		}
 
 		if (pVBInfo->IF_DEF_LVDS == 0)
@@ -3378,7 +3139,6 @@
 	unsigned short tempax = 0, tempbx, modeflag, resinfo;
 
 	struct SiS_LCDData *LCDPtr = NULL;
-	struct SiS_TVData *TVPtr = NULL;
 
 	/* si+Ext_ResInfo */
 	modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
@@ -3395,9 +3155,8 @@
 	tempbx = 4;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = (struct SiS_LCDData *) XGI_GetLcdPtr(tempbx,
-				ModeNo, ModeIdIndex, RefreshRateTableIndex,
-				pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+				       RefreshRateTableIndex, pVBInfo);
 
 		pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX;
 		pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT;
@@ -3479,10 +3238,10 @@
 	}
 
 	if (pVBInfo->VBInfo & (SetCRT2ToTV)) {
-		tempbx = 4;
-		TVPtr = (struct SiS_TVData *) XGI_GetTVPtr(tempbx,
-				ModeNo, ModeIdIndex, RefreshRateTableIndex,
-				pVBInfo);
+		struct SiS_TVData const *TVPtr;
+
+		TVPtr = XGI_GetTVPtr(ModeNo, ModeIdIndex, RefreshRateTableIndex,
+				     pVBInfo);
 
 		pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX;
 		pVBInfo->RVBHCFACT = TVPtr->RVBHCFACT;
@@ -3882,16 +3641,9 @@
 				| VB_SIS302LV | VB_XGI301C)))
 			temp += 2;
 
-		if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
-			if (pVBInfo->VBType & VB_SIS301LV) {
-				if (pVBInfo->VBExtInfo == VB_YPbPr1080i) {
-					if (resinfo == 7)
-						temp -= 2;
-				}
-			} else if (resinfo == 7) {
+		if ((pVBInfo->VBInfo & SetCRT2ToHiVision) &&
+		    !(pVBInfo->VBType & VB_SIS301LV) && (resinfo == 7))
 				temp -= 2;
-			}
-		}
 	}
 
 	/* 0x05 Horizontal Display Start */
@@ -4061,18 +3813,16 @@
 		} else {
 			tempbx -= 10;
 		}
-	} else {
-		if (pVBInfo->TVInfo & TVSimuMode) {
-			if (pVBInfo->TVInfo & TVSetPAL) {
-				if (pVBInfo->VBType & VB_SIS301LV) {
-					if (!(pVBInfo->TVInfo &
-					    (TVSetYPbPr525p |
-					     TVSetYPbPr750p |
-					     TVSetHiVision)))
-						tempbx += 40;
-				} else {
+	} else if (pVBInfo->TVInfo & TVSimuMode) {
+		if (pVBInfo->TVInfo & TVSetPAL) {
+			if (pVBInfo->VBType & VB_SIS301LV) {
+				if (!(pVBInfo->TVInfo &
+				    (TVSetYPbPr525p |
+				     TVSetYPbPr750p |
+				     TVSetHiVision)))
 					tempbx += 40;
-				}
+			} else {
+				tempbx += 40;
 			}
 		}
 	}
@@ -4154,7 +3904,7 @@
 {
 	unsigned short i, j, tempax, tempbx, tempcx, temp, push1, push2,
 			modeflag, resinfo, crt2crtc;
-	unsigned char *TimingPoint;
+	unsigned char const *TimingPoint;
 
 	unsigned long longtemp, tempeax, tempebx, temp2, tempecx;
 
@@ -4186,33 +3936,33 @@
 	tempax = (tempax & 0xff00) >> 8;
 
 	xgifb_reg_set(pVBInfo->Part2Port, 0x0, tempax);
-	TimingPoint = pVBInfo->NTSCTiming;
+	TimingPoint = XGI330_NTSCTiming;
 
 	if (pVBInfo->TVInfo & TVSetPAL)
-		TimingPoint = pVBInfo->PALTiming;
+		TimingPoint = XGI330_PALTiming;
 
 	if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
-		TimingPoint = pVBInfo->HiTVExtTiming;
+		TimingPoint = XGI330_HiTVExtTiming;
 
 		if (pVBInfo->VBInfo & SetInSlaveMode)
-			TimingPoint = pVBInfo->HiTVSt2Timing;
+			TimingPoint = XGI330_HiTVSt2Timing;
 
 		if (pVBInfo->SetFlag & TVSimuMode)
-			TimingPoint = pVBInfo->HiTVSt1Timing;
+			TimingPoint = XGI330_HiTVSt1Timing;
 
 		if (!(modeflag & Charx8Dot))
-			TimingPoint = pVBInfo->HiTVTextTiming;
+			TimingPoint = XGI330_HiTVTextTiming;
 	}
 
 	if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) {
 		if (pVBInfo->TVInfo & TVSetYPbPr525i)
-			TimingPoint = pVBInfo->YPbPr525iTiming;
+			TimingPoint = XGI330_YPbPr525iTiming;
 
 		if (pVBInfo->TVInfo & TVSetYPbPr525p)
-			TimingPoint = pVBInfo->YPbPr525pTiming;
+			TimingPoint = XGI330_YPbPr525pTiming;
 
 		if (pVBInfo->TVInfo & TVSetYPbPr750p)
-			TimingPoint = pVBInfo->YPbPr750pTiming;
+			TimingPoint = XGI330_YPbPr750pTiming;
 	}
 
 	for (i = 0x01, j = 0; i <= 0x2D; i++, j++)
@@ -4385,11 +4135,9 @@
 						temp += 1;
 				}
 			}
-		} else {
-			if (pVBInfo->VBInfo & SetInSlaveMode) {
-				if (ModeNo == 0x2f)
-					temp += 1;
-			}
+		} else if (pVBInfo->VBInfo & SetInSlaveMode) {
+			if (ModeNo == 0x2f)
+				temp += 1;
 		}
 	}
 
@@ -4644,8 +4392,8 @@
 
 	/* Customized LCDB Des no add */
 	tempbx = 5;
-	LCDBDesPtr = (struct XGI_LCDDesStruct *) XGI_GetLcdPtr(tempbx, ModeNo,
-			ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	LCDBDesPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex,
+				   RefreshRateTableIndex, pVBInfo);
 	tempah = pVBInfo->LCDResInfo;
 	tempah &= PanelResInfo;
 
@@ -4876,7 +4624,7 @@
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short i;
-	unsigned char *tempdi;
+	unsigned char const *tempdi;
 	unsigned short modeflag;
 
 	/* si+Ext_ResInfo */
@@ -4905,18 +4653,18 @@
 		if (pVBInfo->TVInfo & TVSetYPbPr525i)
 			return;
 
-		tempdi = pVBInfo->HiTVGroup3Data;
+		tempdi = XGI330_HiTVGroup3Data;
 		if (pVBInfo->SetFlag & TVSimuMode) {
-			tempdi = pVBInfo->HiTVGroup3Simu;
+			tempdi = XGI330_HiTVGroup3Simu;
 			if (!(modeflag & Charx8Dot))
-				tempdi = pVBInfo->HiTVGroup3Text;
+				tempdi = XGI330_HiTVGroup3Text;
 		}
 
 		if (pVBInfo->TVInfo & TVSetYPbPr525p)
-			tempdi = pVBInfo->Ren525pGroup3;
+			tempdi = XGI330_Ren525pGroup3;
 
 		if (pVBInfo->TVInfo & TVSetYPbPr750p)
-			tempdi = pVBInfo->Ren750pGroup3;
+			tempdi = XGI330_Ren750pGroup3;
 
 		for (i = 0; i <= 0x3E; i++)
 			xgifb_reg_set(pVBInfo->Part3Port, i, tempdi[i]);
@@ -5054,13 +4802,11 @@
 		if (pVBInfo->VBInfo & SetCRT2ToLCD) {
 			if (tempax > 800)
 				tempax -= 800;
-		} else {
-			if (pVBInfo->VGAHDE > 800) {
-				if (pVBInfo->VGAHDE == 1024)
-					tempax = (tempax * 25 / 32) - 1;
-				else
-					tempax = (tempax * 20 / 32) - 1;
-			}
+		} else if (pVBInfo->VGAHDE > 800) {
+			if (pVBInfo->VGAHDE == 1024)
+				tempax = (tempax * 25 / 32) - 1;
+			else
+				tempax = (tempax * 20 / 32) - 1;
 		}
 		tempax -= 1;
 
@@ -5101,9 +4847,7 @@
 	}
 	/* end 301b */
 
-	if (pVBInfo->ISXPDOS == 0)
-		XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-				pVBInfo);
+	XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 }
 
 static void XGINew_EnableCRT2(struct vb_device_info *pVBInfo)
@@ -6414,12 +6158,10 @@
 			if (pVBInfo->SetFlag & EnableChA) {
 				/* Power on */
 				xgifb_reg_set(pVBInfo->Part1Port, 0x1E, 0x20);
-			} else {
-				if (pVBInfo->VBInfo & SetCRT2ToDualEdge) {
-					/* Power on */
-					xgifb_reg_set(pVBInfo->Part1Port,
-							0x1E, 0x20);
-				}
+			} else if (pVBInfo->VBInfo & SetCRT2ToDualEdge) {
+				/* Power on */
+				xgifb_reg_set(pVBInfo->Part1Port,
+						0x1E, 0x20);
 			}
 		}
 
@@ -6607,7 +6349,6 @@
 	struct vb_device_info *pVBInfo = &VBINF;
 	pVBInfo->BaseAddr = xgifb_info->vga_base;
 	pVBInfo->IF_DEF_LVDS = 0;
-	pVBInfo->IF_DEF_LCDA = 1;
 
 	if (HwDeviceExtension->jChipType >= XG20) {
 		pVBInfo->IF_DEF_YPbPr = 0;
@@ -6678,16 +6419,14 @@
 				XGI_SetLCDAGroup(ModeNo, ModeIdIndex,
 						HwDeviceExtension, pVBInfo);
 			}
-		} else {
-			if (!(pVBInfo->VBInfo & SwitchCRT2)) {
-				XGI_SetCRT1Group(xgifb_info,
-						HwDeviceExtension, ModeNo,
-						ModeIdIndex, pVBInfo);
-				if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
-					XGI_SetLCDAGroup(ModeNo, ModeIdIndex,
-							HwDeviceExtension,
-							pVBInfo);
-				}
+		} else if (!(pVBInfo->VBInfo & SwitchCRT2)) {
+			XGI_SetCRT1Group(xgifb_info,
+					HwDeviceExtension, ModeNo,
+					ModeIdIndex, pVBInfo);
+			if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
+				XGI_SetLCDAGroup(ModeNo, ModeIdIndex,
+						HwDeviceExtension,
+						pVBInfo);
 			}
 		}
 
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index 22c8eb9..70158c2 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -43,13 +43,6 @@
 	unsigned short LCDVRS;
 };
 
-struct XGI_LCDDataTablStruct {
-	unsigned char  PANELID;
-	unsigned short MASK;
-	unsigned short CAP;
-	unsigned short DATAPTR;
-};
-
 struct XGI330_LCDDataDesStruct2 {
 	unsigned short LCDHDES;
 	unsigned short LCDHRS;
@@ -59,19 +52,6 @@
 	unsigned short LCDVSync;
 };
 
-
-struct XGI330_TVDataStruct {
-	unsigned short RVBHCMAX;
-	unsigned short RVBHCFACT;
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short TVHDE;
-	unsigned short TVVDE;
-	unsigned short RVBHRS;
-	unsigned char FlickerMode;
-	unsigned short HALFRVBHRS;
-};
-
 struct XGI330_LCDDataTablStruct {
 	unsigned char  PANELID;
 	unsigned short MASK;
@@ -82,7 +62,7 @@
 struct XGI330_TVDataTablStruct {
 	unsigned short MASK;
 	unsigned short CAP;
-	unsigned short DATAPTR;
+	struct SiS_TVData const *DATAPTR;
 };
 
 
@@ -137,10 +117,10 @@
 	unsigned short LVDSVSYNC;
 	unsigned char  VCLKData1;
 	unsigned char  VCLKData2;
-	unsigned char  PSC_S1;
-	unsigned char  PSC_S2;
-	unsigned char  PSC_S3;
-	unsigned char  PSC_S4;
+	unsigned char  PSC_S1; /* Duration between CPL on and signal on */
+	unsigned char  PSC_S2; /* Duration signal on and Vdd on */
+	unsigned char  PSC_S3; /* Duration between CPL off and signal off */
+	unsigned char  PSC_S4; /* Duration signal off and Vdd off */
 	unsigned char  PSC_S5;
 };
 
@@ -155,7 +135,6 @@
 };
 
 struct vb_device_info {
-	unsigned char  ISXPDOS;
 	unsigned long   P3c4, P3d4, P3c0, P3ce, P3c2, P3cc;
 	unsigned long   P3ca, P3c6, P3c7, P3c8, P3c9, P3da;
 	unsigned long   Part0Port, Part1Port, Part2Port;
@@ -168,12 +147,10 @@
 	unsigned short   ModeType;
 	unsigned short   IF_DEF_LVDS, IF_DEF_TRUMPION, IF_DEF_DSTN;
 	unsigned short   IF_DEF_CRT2Monitor;
-	unsigned short   IF_DEF_LCDA, IF_DEF_YPbPr;
-	unsigned short   IF_DEF_ExpLink;
+	unsigned short   IF_DEF_YPbPr;
 	unsigned short   IF_DEF_HiVision;
 	unsigned short   LCDResInfo, LCDTypeInfo, VBType;/*301b*/
 	unsigned short   VBInfo, TVInfo, LCDInfo;
-	unsigned short   VBExtInfo;/*301lv*/
 	unsigned short   SetFlag;
 	unsigned short   NewFlickerMode;
 	unsigned short   SelectCRT2Rate;
@@ -197,20 +174,6 @@
 	struct SiS_MCLKData  *MCLKData;
 	struct XGI_ECLKDataStruct  *ECLKData;
 
-	unsigned char   *NTSCTiming;
-	unsigned char   *PALTiming;
-	unsigned char   *HiTVExtTiming;
-	unsigned char   *HiTVSt1Timing;
-	unsigned char   *HiTVSt2Timing;
-	unsigned char   *HiTVTextTiming;
-	unsigned char   *YPbPr750pTiming;
-	unsigned char   *YPbPr525pTiming;
-	unsigned char   *YPbPr525iTiming;
-	unsigned char   *HiTVGroup3Data;
-	unsigned char   *HiTVGroup3Simu;
-	unsigned char   *HiTVGroup3Text;
-	unsigned char   *Ren525pGroup3;
-	unsigned char   *Ren750pGroup3;
 	unsigned char   *ScreenOffset;
 	unsigned char   *pXGINew_DRAMTypeDefinition;
 	unsigned char   XGINew_CR97;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index 1c16846..180aae0 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -403,13 +403,6 @@
 	  0x03, 0xDE, 0xC0, 0x84, 0xBF, 0x04, 0x90} }  /* 0x47 */
 };
 
-static unsigned char XGI_CH7017LV1024x768[] = {
-	0x60, 0x02, 0x00, 0x07, 0x40, 0xED,
-	0xA3, 0xC8, 0xC7, 0xAC, 0xE0, 0x02};
-static unsigned char XGI_CH7017LV1400x1050[] = {
-	0x60, 0x03, 0x11, 0x00, 0x40, 0xE3,
-	0xAD, 0xDB, 0xF6, 0xAC, 0xE0, 0x02};
-
 /*add for new UNIVGABIOS*/
 static struct SiS_LCDData  XGI_StLCD1024x768Data[] = {
 	{62,  25, 800,  546, 1344, 806},
@@ -525,18 +518,7 @@
 	{1,   1,  2160, 1250, 2160, 1250}  /* 09 (1600x1200) */
 };
 
-static struct SiS_LCDData  XGI_CetLCD1400x1050Data[] = {
-	{1, 1, 1688, 1066, 1688, 1066}, /* 00 (320x200,320x400,
-					       640x200,640x400) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 01 (320x350,640x350) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 02 (360x400,720x400) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 03 (720x350) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 04 (640x480x60Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 05 (800x600x60Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 06 (1024x768x60Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* 07 (1280x1024x60Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}  /* 08 (1400x1050x60Hz) */
-};
+#define XGI_CetLCD1400x1050Data XGI_CetLCD1280x1024Data
 
 static struct SiS_LCDData  XGI_NoScalingData[] = {
 	{1, 1, 800,  449,  800,  449},
@@ -583,17 +565,7 @@
 	{1,   1,   1688, 1066, 1688, 1066}  /* ; 07 (1280x1024x75Hz) */
 };
 
-static struct SiS_LCDData  XGI_CetLCD1280x1024x75Data[] = {
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 00 (320x200,320x400,
-						 640x200,640x400) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 01 (320x350,640x350) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 02 (360x400,720x400) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 03 (720x350) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 04 (640x480x75Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 05 (800x600x75Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}, /* ; 06 (1024x768x75Hz) */
-	{1, 1, 1688, 1066, 1688, 1066}  /* ; 07 (1280x1024x75Hz) */
-};
+#define XGI_CetLCD1280x1024x75Data XGI_CetLCD1280x1024Data
 
 static struct SiS_LCDData  XGI_NoScalingDatax75[] = {
 	{1, 1, 800,  449,  800,  449},  /* ; 00 (320x200, 320x400,
@@ -903,7 +875,7 @@
 	{9, 1337, 0,   771,  112, 6}  /* ; 0A (1280x768x60Hz) */
 };
 
-static struct XGI330_TVDataStruct  XGI_StPALData[] = {
+static const struct SiS_TVData XGI_StPALData[] = {
 	{1, 1, 864, 525, 1270, 400, 100, 0, 760},
 	{1, 1, 864, 525, 1270, 350, 100, 0, 760},
 	{1, 1, 864, 525, 1270, 400,   0, 0, 720},
@@ -912,7 +884,7 @@
 	{1, 1, 864, 525, 1270, 600,  50, 0,   0}
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtPALData[] = {
+static const struct SiS_TVData XGI_ExtPALData[] = {
 	{2,  1, 1080, 463, 1270, 500,  50, 0,  50},
 	{15, 7, 1152, 413, 1270, 500,  50, 0,  50},
 	{2,  1, 1080, 463, 1270, 500,  50, 0,  50},
@@ -923,7 +895,7 @@
 	{3,  2, 1080, 619, 1270, 540, 438, 0, 438}
 };
 
-static struct XGI330_TVDataStruct  XGI_StNTSCData[] = {
+static const struct SiS_TVData XGI_StNTSCData[] = {
 	{1, 1, 858, 525, 1270, 400, 50, 0, 760},
 	{1, 1, 858, 525, 1270, 350, 50, 0, 640},
 	{1, 1, 858, 525, 1270, 400,  0, 0, 720},
@@ -931,7 +903,7 @@
 	{1, 1, 858, 525, 1270, 480,  0, 0, 760}
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtNTSCData[] = {
+static const struct SiS_TVData XGI_ExtNTSCData[] = {
 	{9,     5, 1001, 453, 1270, 420, 171, 0, 171},
 	{12,    5,  858, 403, 1270, 420, 171, 0, 171},
 	{9,     5, 1001, 453, 1270, 420, 171, 0, 171},
@@ -943,7 +915,7 @@
 	{3,     2, 1001, 533, 1270, 420,   0, 0,   0}
 };
 
-static struct XGI330_TVDataStruct  XGI_St1HiTVData[] = {
+static const struct SiS_TVData XGI_St1HiTVData[] = {
 	{1, 1, 892,  563, 690,  800, 0,     0, 0}, /* 00 (320x200,320x400,
 							  640x200,640x400) */
 	{1, 1, 892,  563, 690,  700, 0,     0, 0}, /* 01 (320x350,640x350) */
@@ -953,7 +925,7 @@
 	{8, 5, 1050, 683, 1648, 960, 0x150, 1, 0}  /* 05 (400x300,800x600) */
 };
 
-static struct XGI330_TVDataStruct  XGI_St2HiTVData[] = {
+static const struct SiS_TVData XGI_St2HiTVData[] = {
 	{3, 1, 840,  483, 1648, 960, 0x032, 0, 0}, /* 00 (320x200,320x400,
 							  640x200,640x400) */
 	{1, 1, 892,  563, 690,  700, 0,     0, 0}, /* 01 (320x350,640x350) */
@@ -963,7 +935,7 @@
 	{8, 5, 1050, 683, 1648, 960, 0x17C, 1, 0}  /* 05 (400x300,800x600) */
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtHiTVData[] = {
+static const struct SiS_TVData XGI_ExtHiTVData[] = {
 	{6,  1,  840,  563,  1632, 960, 0,     0, 0}, /* 00 (320x200,320x400,
 							     640x200,640x400) */
 	{3,  1,  960,  563,  1632, 960, 0,     0, 0}, /* 01 (320x350,640x350) */
@@ -978,7 +950,7 @@
 	{8,  5,  1750, 803,  1648, 960, 0x128, 0, 0}  /* 0A (1280x720) */
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtYPbPr525iData[] = {
+static const struct SiS_TVData XGI_ExtYPbPr525iData[] = {
 	{  9,  5,  1001, 453, 1270, 420, 171,   0, 171},
 	{ 12,  5,   858, 403, 1270, 420, 171,   0, 171},
 	{  9,  5,  1001, 453, 1270, 420, 171,   0, 171},
@@ -990,7 +962,7 @@
 	{  3,   2, 1001, 533, 1250, 420,   0,   0,   0}
 };
 
-static struct XGI330_TVDataStruct  XGI_StYPbPr525iData[] = {
+static const struct SiS_TVData XGI_StYPbPr525iData[] = {
 	{1, 1, 858, 525, 1270, 400, 50, 0, 760},
 	{1, 1, 858, 525, 1270, 350, 50, 0, 640},
 	{1, 1, 858, 525, 1270, 400,  0, 0, 720},
@@ -998,7 +970,7 @@
 	{1, 1, 858, 525, 1270, 480,  0, 0, 760},
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtYPbPr525pData[] = {
+static const struct SiS_TVData XGI_ExtYPbPr525pData[] = {
 	{  9,   5,  1001, 453, 1270, 420, 171, 0, 171},
 	{ 12,   5,   858, 403, 1270, 420, 171, 0, 171},
 	{  9,   5,  1001, 453, 1270, 420, 171, 0, 171},
@@ -1010,7 +982,7 @@
 	{  3,   2,  1001, 533, 1270, 420,   0, 0,   0}
 };
 
-static struct XGI330_TVDataStruct  XGI_StYPbPr525pData[] = {
+static const struct SiS_TVData XGI_StYPbPr525pData[] = {
 	{1, 1, 1716, 525, 1270, 400, 50, 0, 760},
 	{1, 1, 1716, 525, 1270, 350, 50, 0, 640},
 	{1, 1, 1716, 525, 1270, 400,  0, 0, 720},
@@ -1018,7 +990,7 @@
 	{1, 1, 1716, 525, 1270, 480,  0, 0, 760},
 };
 
-static struct XGI330_TVDataStruct  XGI_ExtYPbPr750pData[] = {
+static const struct SiS_TVData XGI_ExtYPbPr750pData[] = {
 	{ 3, 1,  935, 470, 1130, 680,  50, 0, 0}, /* 00 (320x200,320x400,
 							 640x200,640x400) */
 	{24, 7,  935, 420, 1130, 680,  50, 0, 0}, /* 01 (320x350,640x350) */
@@ -1033,7 +1005,7 @@
 	{10, 9, 1320, 830, 1130, 640,  50, 0, 0}
 };
 
-static struct XGI330_TVDataStruct  XGI_StYPbPr750pData[] = {
+static const struct SiS_TVData XGI_StYPbPr750pData[] = {
 	{1, 1, 1650, 750, 1280, 400, 50, 0, 760},
 	{1, 1, 1650, 750, 1280, 350, 50, 0, 640},
 	{1, 1, 1650, 750, 1280, 400,  0, 0, 720},
@@ -1041,7 +1013,7 @@
 	{1, 1, 1650, 750, 1280, 480,  0, 0, 760},
 };
 
-static unsigned char XGI330_NTSCTiming[] = {
+static const unsigned char XGI330_NTSCTiming[] = {
 	0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c,
 	0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a,
 	0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b,
@@ -1052,7 +1024,7 @@
 	0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00
 };
 
-static unsigned char XGI330_PALTiming[] = {
+static const unsigned char XGI330_PALTiming[] = {
 	0x21, 0x5A, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70,
 	0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d,
 	0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b,
@@ -1063,7 +1035,7 @@
 	0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00
 };
 
-static unsigned char XGI330_HiTVExtTiming[] = {
+static const unsigned char XGI330_HiTVExtTiming[] = {
 	0x2D, 0x60, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x64,
 	0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D,
 	0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F,
@@ -1075,7 +1047,7 @@
 	0x27, 0x00, 0xfc, 0xff, 0x6a, 0x00
 };
 
-static unsigned char XGI330_HiTVSt1Timing[] = {
+static const unsigned char XGI330_HiTVSt1Timing[] = {
 	0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x65,
 	0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D,
 	0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F,
@@ -1087,7 +1059,7 @@
 	0x0E, 0x00, 0xfc, 0xff, 0x2d, 0x00
 };
 
-static unsigned char XGI330_HiTVSt2Timing[] = {
+static const unsigned char XGI330_HiTVSt2Timing[] = {
 	0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x64,
 	0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D,
 	0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F,
@@ -1099,7 +1071,7 @@
 	0x27, 0x00, 0xFC, 0xff, 0x6a, 0x00
 };
 
-static unsigned char XGI330_HiTVTextTiming[] = {
+static const unsigned char XGI330_HiTVTextTiming[] = {
 	0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x65,
 	0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D,
 	0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F,
@@ -1111,7 +1083,7 @@
 	0x11, 0x00, 0xFC, 0xFF, 0x32, 0x00
 };
 
-static unsigned char XGI330_YPbPr750pTiming[] = {
+static const unsigned char XGI330_YPbPr750pTiming[] = {
 	0x30, 0x1d, 0xe8, 0x09, 0x09, 0xed, 0x0c, 0x0c,
 	0x98, 0x0a, 0x01, 0x0c, 0x06, 0x0d, 0x04, 0x0a,
 	0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x3f,
@@ -1123,7 +1095,7 @@
 	0x11, 0x00, 0xfc, 0xff, 0x32, 0x00
 };
 
-static unsigned char XGI330_YPbPr525pTiming[] = {
+static const unsigned char XGI330_YPbPr525pTiming[] = {
 	0x3E, 0x11, 0x06, 0x09, 0x0b, 0x0c, 0x0c, 0x0c,
 	0x98, 0x0a, 0x01, 0x0d, 0x06, 0x0d, 0x04, 0x0a,
 	0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x3f,
@@ -1135,7 +1107,7 @@
 	0x11, 0x00, 0xFC, 0xFF, 0x32, 0x00
 };
 
-static unsigned char XGI330_YPbPr525iTiming[] = {
+static const unsigned char XGI330_YPbPr525iTiming[] = {
 	0x1B, 0x21, 0x03, 0x09, 0x05, 0x06, 0x0C, 0x0C,
 	0x94, 0x49, 0x01, 0x0A, 0x06, 0x0D, 0x04, 0x0A,
 	0x06, 0x14, 0x0D, 0x04, 0x0A, 0x00, 0x85, 0x1B,
@@ -1147,7 +1119,7 @@
 	0x44, 0x00, 0xDB, 0x02, 0x3B, 0x00
 };
 
-static unsigned char XGI330_HiTVGroup3Data[] = {
+static const unsigned char XGI330_HiTVGroup3Data[] = {
 	0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0x5F,
 	0x05, 0x21, 0xB2, 0xB2, 0x55, 0x77, 0x2A, 0xA6,
 	0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20,
@@ -1158,7 +1130,7 @@
 	0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01
 };
 
-static unsigned char XGI330_HiTVGroup3Simu[] = {
+static const unsigned char XGI330_HiTVGroup3Simu[] = {
 	0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0x95,
 	0xDB, 0x20, 0xB8, 0xB8, 0x55, 0x47, 0x2A, 0xA6,
 	0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20,
@@ -1169,7 +1141,7 @@
 	0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01
 };
 
-static unsigned char XGI330_HiTVGroup3Text[] = {
+static const unsigned char XGI330_HiTVGroup3Text[] = {
 	0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0xA7,
 	0xF5, 0x20, 0xCE, 0xCE, 0x55, 0x47, 0x2A, 0xA6,
 	0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20,
@@ -1180,7 +1152,7 @@
 	0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01
 };
 
-static unsigned char XGI330_Ren525pGroup3[] = {
+static const unsigned char XGI330_Ren525pGroup3[] = {
 	0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13,
 	0xB1, 0x41, 0x62, 0x62, 0xFF, 0xF4, 0x45, 0xa6,
 	0x25, 0x2F, 0x67, 0xF6, 0xbf, 0xFF, 0x8E, 0x20,
@@ -1191,7 +1163,7 @@
 	0x1a, 0x1F, 0x25, 0x2a, 0x4C, 0xAA, 0x01
 };
 
-static unsigned char XGI330_Ren750pGroup3[] = {
+static const unsigned char XGI330_Ren750pGroup3[] = {
 	0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a,
 	0x54, 0x41, 0xE7, 0xE7, 0xFF, 0xF4, 0x45, 0xa6,
 	0x25, 0x2F, 0x67, 0xF6, 0xbf, 0xFF, 0x8E, 0x20,
@@ -1236,17 +1208,7 @@
 	{1688, 1066, 1688, 1066}
 };
 
-static struct SiS_LVDSData  XGI_LVDS1280x1024Data_2[] = {
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{1344, 806, 1344, 806},
-	{800,  449, 1280, 801},
-	{800,  525, 1280, 813}
-};
+#define XGI_LVDS1280x1024Data_2 XGI_LVDS1024x768Data_2
 
 static struct SiS_LVDSData  XGI_LVDS1400x1050Data_1[] = {
 	{928,   416, 1688, 1066},
@@ -1532,42 +1494,6 @@
 	{0, 1328,   0,  771, 112, 6}  /* ; 0A (1280x768x75Hz) */
 };
 
-static struct SiS_LVDSData  XGI_CHTVUNTSCData[] = {
-	{ 840, 600,  840, 600},
-	{ 840, 600,  840, 600},
-	{ 840, 600,  840, 600},
-	{ 840, 600,  840, 600},
-	{ 784, 600,  784, 600},
-	{1064, 750, 1064, 750}
-};
-
-static struct SiS_LVDSData  XGI_CHTVONTSCData[] = {
-	{ 840, 525,  840, 525},
-	{ 840, 525,  840, 525},
-	{ 840, 525,  840, 525},
-	{ 840, 525,  840, 525},
-	{ 784, 525,  784, 525},
-	{1040, 700, 1040, 700}
-};
-
-static struct SiS_LVDSData  XGI_CHTVUPALData[] = {
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{ 840, 750,  840, 750},
-	{ 936, 836,  936, 836}
-};
-
-static struct SiS_LVDSData  XGI_CHTVOPALData[] = {
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{1008, 625, 1008, 625},
-	{840,  625,  840, 625},
-	{960,  750,  960, 750}
-};
-
 /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
 static struct XGI_LVDSCRT1HDataStruct  XGI_LVDSCRT11024x768_1_H[] = {
 	{ {0x4B, 0x27, 0x8F, 0x32, 0x1B, 0x00, 0x45, 0x00} }, /* 00 (320x) */
@@ -1933,49 +1859,21 @@
 	{0xFF, 0x0000, 0x0000, 0}
 };
 
-static struct XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[] = {
-	{Panel_1024x768, 0x0000, 0x0000, 0}, /* XGI_CH7017LV1024x768 */
-	{Panel_1400x1050, 0x0000, 0x0000, 1}, /* XGI_CH7017LV1400x1050 */
-	{0xFF, 0x0000, 0x0000, 0}
-};
-
-static struct XGI330_TVDataTablStruct XGI_TVDataTable[] = {
-	{0x09E1, 0x0001, 0}, /* XGI_ExtPALData */
-	{0x09E1, 0x0000, 1}, /* XGI_ExtNTSCData */
-	{0x09E1, 0x0801, 2}, /* XGI_StPALData */
-	{0x09E1, 0x0800, 3}, /* XGI_StNTSCData */
-	{0x49E0, 0x0100, 4}, /* XGI_ExtHiTVData */
-	{0x49E0, 0x4100, 5}, /* XGI_St2HiTVData */
-	{0x49E0, 0x4900, 13}, /* XGI_St1HiTVData */
-	{0x09E0, 0x0020, 6}, /* XGI_ExtYPbPr525iData */
-	{0x09E0, 0x0040, 7}, /* XGI_ExtYPbPr525pData */
-	{0x09E0, 0x0080, 8}, /* XGI_ExtYPbPr750pData */
-	{0x09E0, 0x0820, 9}, /* XGI_StYPbPr525iData */
-	{0x09E0, 0x0840, 10}, /* XGI_StYPbPr525pData */
-	{0x09E0, 0x0880, 11}, /* XGI_StYPbPr750pData */
-	{0xffff, 0x0000, 12}  /* END */
-};
-
-/* Chrontel 7017 TV List */
-static struct XGI330_TVDataTablStruct xgifb_chrontel_tv[] = {
-	{0x0011, 0x0000, 0}, /* UNTSC */
-	{0x0011, 0x0010, 1}, /* ONTSC */
-	{0x0011, 0x0001, 2}, /* UPAL */
-	{0x0011, 0x0011, 3}, /* OPAL */
-	{0xFFFF, 0x0000, 4}
-};
-
-static unsigned short LCDLenList[] = {
-	LVDSCRT1Len_H,
-	LVDSCRT1Len_V,
-	LVDSDataLen,
-	LCDDesDataLen,
-	LCDDataLen,
-	LCDDesDataLen,
-	0,
-	LCDDesDataLen,
-	LCDDesDataLen,
-	0
+static const struct XGI330_TVDataTablStruct XGI_TVDataTable[] = {
+	{0x09E1, 0x0001, XGI_ExtPALData},
+	{0x09E1, 0x0000, XGI_ExtNTSCData},
+	{0x09E1, 0x0801, XGI_StPALData},
+	{0x09E1, 0x0800, XGI_StNTSCData},
+	{0x49E0, 0x0100, XGI_ExtHiTVData},
+	{0x49E0, 0x4100, XGI_St2HiTVData},
+	{0x49E0, 0x4900, XGI_St1HiTVData},
+	{0x09E0, 0x0020, XGI_ExtYPbPr525iData},
+	{0x09E0, 0x0040, XGI_ExtYPbPr525pData},
+	{0x09E0, 0x0080, XGI_ExtYPbPr750pData},
+	{0x09E0, 0x0820, XGI_StYPbPr525iData},
+	{0x09E0, 0x0840, XGI_StYPbPr525pData},
+	{0x09E0, 0x0880, XGI_StYPbPr750pData},
+	{0xffff, 0x0000, XGI_ExtNTSCData},
 };
 
 /* Dual link only */
@@ -2336,7 +2234,7 @@
 	{0xFF, 0x00,   0}  /* End mark */
 };
 
-static struct SiS_VCLKData XGI_VBVCLKData[] = {
+static struct SiS_VBVCLKData XGI_VBVCLKData[] = {
 	{0x1B, 0xE1,  25}, /* 00 (25.175MHz) */
 	{0x4E, 0xE4,  28}, /* 01 (28.322MHz) */
 	{0x57, 0xE4,  31}, /* 02 (31.500MHz) */
diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c
index eaa9021..56c8e60 100644
--- a/drivers/staging/zcache/tmem.c
+++ b/drivers/staging/zcache/tmem.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
  *
- * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
+ * The primary purpose of Transcendent Memory ("tmem") is to map object-oriented
  * "handles" (triples containing a pool id, and object id, and an index), to
  * pages in a page-accessible memory (PAM).  Tmem references the PAM pages via
  * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 8b0bcb6..09a9d35 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -75,9 +75,140 @@
 #include <linux/cpumask.h>
 #include <linux/cpu.h>
 #include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
 
 #include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN		8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ *  - Large number of size classes is potentially wasteful as free page are
+ *    spread across these classes
+ *  - Small number of size classes causes large internal fragmentation
+ *  - Probably its better to use specific size classes (empirically
+ *    determined). NOTE: all those class sizes must be set as multiple of
+ *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ *  (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA	16
+#define ZS_SIZE_CLASSES		((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+					ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+	ZS_ALMOST_FULL,
+	ZS_ALMOST_EMPTY,
+	_ZS_NR_FULLNESS_GROUPS,
+
+	ZS_EMPTY,
+	ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ *	n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ *	ZS_ALMOST_FULL	when n > N / f
+ *	ZS_EMPTY	when n == 0
+ *	ZS_FULL		when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+	/*
+	 * Size of objects stored in this class. Must be multiple
+	 * of ZS_ALIGN.
+	 */
+	int size;
+	unsigned int index;
+
+	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+	int pages_per_zspage;
+
+	spinlock_t lock;
+
+	/* stats */
+	u64 pages_allocated;
+
+	struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+	/* Handle of next free chunk (encodes <PFN, obj_idx>) */
+	void *next;
+};
+
+struct zs_pool {
+	struct size_class size_class[ZS_SIZE_CLASSES];
+
+	gfp_t flags;	/* allocation flags used when growing pool */
+	const char *name;
+};
 
 /*
  * A zspage's class index and fullness group
@@ -88,6 +219,30 @@
 #define CLASS_IDX_MASK	((1 << CLASS_IDX_BITS) - 1)
 #define FULLNESS_MASK	((1 << FULLNESS_BITS) - 1)
 
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * 1) Implements local_flush_tlb_kernel_range() and 2) Performs VM mapping
+ * faster than copying, then it should be added here so that
+ * USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use page table
+ * mapping rather than copying
+ * for object mapping.
+*/
+#if defined(CONFIG_ARM)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+	struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+	char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+	char *vm_addr; /* address of kmap_atomic()'ed pages */
+	enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
 static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
 
@@ -470,16 +625,83 @@
 	return page;
 }
 
-static void zs_copy_map_object(char *buf, struct page *firstpage,
-				int off, int size)
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
 {
-	struct page *pages[2];
+	/*
+	 * Make sure we don't leak memory if a cpu UP notification
+	 * and zs_init() race and both call zs_cpu_up() on the same cpu
+	 */
+	if (area->vm)
+		return 0;
+	area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+	if (!area->vm)
+		return -ENOMEM;
+	return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+	if (area->vm)
+		free_vm_area(area->vm);
+	area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+				struct page *pages[2], int off, int size)
+{
+	BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+	area->vm_addr = area->vm->addr;
+	return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+				struct page *pages[2], int off, int size)
+{
+	unsigned long addr = (unsigned long)area->vm_addr;
+	unsigned long end = addr + (PAGE_SIZE * 2);
+
+	flush_cache_vunmap(addr, end);
+	unmap_kernel_range_noflush(addr, PAGE_SIZE * 2);
+	local_flush_tlb_kernel_range(addr, end);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+	/*
+	 * Make sure we don't leak memory if a cpu UP notification
+	 * and zs_init() race and both call zs_cpu_up() on the same cpu
+	 */
+	if (area->vm_buf)
+		return 0;
+	area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+	if (!area->vm_buf)
+		return -ENOMEM;
+	return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+	if (area->vm_buf)
+		free_page((unsigned long)area->vm_buf);
+	area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+			struct page *pages[2], int off, int size)
+{
 	int sizes[2];
 	void *addr;
+	char *buf = area->vm_buf;
 
-	pages[0] = firstpage;
-	pages[1] = get_next_page(firstpage);
-	BUG_ON(!pages[1]);
+	/* disable page faults to match kmap_atomic() return conditions */
+	pagefault_disable();
+
+	/* no read fastpath */
+	if (area->vm_mm == ZS_MM_WO)
+		goto out;
 
 	sizes[0] = PAGE_SIZE - off;
 	sizes[1] = size - sizes[0];
@@ -491,18 +713,20 @@
 	addr = kmap_atomic(pages[1]);
 	memcpy(buf + sizes[0], addr, sizes[1]);
 	kunmap_atomic(addr);
+out:
+	return area->vm_buf;
 }
 
-static void zs_copy_unmap_object(char *buf, struct page *firstpage,
-				int off, int size)
+static void __zs_unmap_object(struct mapping_area *area,
+			struct page *pages[2], int off, int size)
 {
-	struct page *pages[2];
 	int sizes[2];
 	void *addr;
+	char *buf = area->vm_buf;
 
-	pages[0] = firstpage;
-	pages[1] = get_next_page(firstpage);
-	BUG_ON(!pages[1]);
+	/* no write fastpath */
+	if (area->vm_mm == ZS_MM_RO)
+		goto out;
 
 	sizes[0] = PAGE_SIZE - off;
 	sizes[1] = size - sizes[0];
@@ -514,34 +738,31 @@
 	addr = kmap_atomic(pages[1]);
 	memcpy(addr, buf + sizes[0], sizes[1]);
 	kunmap_atomic(addr);
+
+out:
+	/* enable page faults to match kunmap_atomic() return conditions */
+	pagefault_enable();
 }
 
+#endif /* USE_PGTABLE_MAPPING */
+
 static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
 				void *pcpu)
 {
-	int cpu = (long)pcpu;
+	int ret, cpu = (long)pcpu;
 	struct mapping_area *area;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
 		area = &per_cpu(zs_map_area, cpu);
-		/*
-		 * Make sure we don't leak memory if a cpu UP notification
-		 * and zs_init() race and both call zs_cpu_up() on the same cpu
-		 */
-		if (area->vm_buf)
-			return 0;
-		area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
-		if (!area->vm_buf)
-			return -ENOMEM;
-		return 0;
+		ret = __zs_cpu_up(area);
+		if (ret)
+			return notifier_from_errno(ret);
 		break;
 	case CPU_DEAD:
 	case CPU_UP_CANCELED:
 		area = &per_cpu(zs_map_area, cpu);
-		if (area->vm_buf)
-			free_page((unsigned long)area->vm_buf);
-		area->vm_buf = NULL;
+		__zs_cpu_down(area);
 		break;
 	}
 
@@ -758,28 +979,36 @@
 	enum fullness_group fg;
 	struct size_class *class;
 	struct mapping_area *area;
+	struct page *pages[2];
 
 	BUG_ON(!handle);
 
+	/*
+	 * Because we use per-cpu mapping areas shared among the
+	 * pools/users, we can't allow mapping in interrupt context
+	 * because it can corrupt another users mappings.
+	 */
+	BUG_ON(in_interrupt());
+
 	obj_handle_to_location(handle, &page, &obj_idx);
 	get_zspage_mapping(get_first_page(page), &class_idx, &fg);
 	class = &pool->size_class[class_idx];
 	off = obj_idx_to_offset(page, obj_idx, class->size);
 
 	area = &get_cpu_var(zs_map_area);
+	area->vm_mm = mm;
 	if (off + class->size <= PAGE_SIZE) {
 		/* this object is contained entirely within a page */
 		area->vm_addr = kmap_atomic(page);
 		return area->vm_addr + off;
 	}
 
-	/* disable page faults to match kmap_atomic() return conditions */
-	pagefault_disable();
+	/* this object spans two pages */
+	pages[0] = page;
+	pages[1] = get_next_page(page);
+	BUG_ON(!pages[1]);
 
-	if (mm != ZS_MM_WO)
-		zs_copy_map_object(area->vm_buf, page, off, class->size);
-	area->vm_addr = NULL;
-	return area->vm_buf;
+	return __zs_map_object(area, pages, off, class->size);
 }
 EXPORT_SYMBOL_GPL(zs_map_object);
 
@@ -793,17 +1022,6 @@
 	struct size_class *class;
 	struct mapping_area *area;
 
-	area = &__get_cpu_var(zs_map_area);
-	/* single-page object fastpath */
-	if (area->vm_addr) {
-		kunmap_atomic(area->vm_addr);
-		goto out;
-	}
-
-	/* no write fastpath */
-	if (area->vm_mm == ZS_MM_RO)
-		goto pfenable;
-
 	BUG_ON(!handle);
 
 	obj_handle_to_location(handle, &page, &obj_idx);
@@ -811,12 +1029,18 @@
 	class = &pool->size_class[class_idx];
 	off = obj_idx_to_offset(page, obj_idx, class->size);
 
-	zs_copy_unmap_object(area->vm_buf, page, off, class->size);
+	area = &__get_cpu_var(zs_map_area);
+	if (off + class->size <= PAGE_SIZE)
+		kunmap_atomic(area->vm_addr);
+	else {
+		struct page *pages[2];
 
-pfenable:
-	/* enable page faults to match kunmap_atomic() return conditions */
-	pagefault_enable();
-out:
+		pages[0] = page;
+		pages[1] = get_next_page(page);
+		BUG_ON(!pages[1]);
+
+		__zs_unmap_object(area, pages, off, class->size);
+	}
 	put_cpu_var(zs_map_area);
 }
 EXPORT_SYMBOL_GPL(zs_unmap_object);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644
index 52805176..0000000
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN		8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
-	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- *  - Large number of size classes is potentially wasteful as free page are
- *    spread across these classes
- *  - Small number of size classes causes large internal fragmentation
- *  - Probably its better to use specific size classes (empirically
- *    determined). NOTE: all those class sizes must be set as multiple of
- *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- *  (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA	16
-#define ZS_SIZE_CLASSES		((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
-					ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
-	ZS_ALMOST_FULL,
-	ZS_ALMOST_EMPTY,
-	_ZS_NR_FULLNESS_GROUPS,
-
-	ZS_EMPTY,
-	ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- *	n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- *	ZS_ALMOST_FULL	when n > N / f
- *	ZS_EMPTY	when n == 0
- *	ZS_FULL		when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
-	char *vm_buf; /* copy buffer for objects that span pages */
-	char *vm_addr; /* address of kmap_atomic()'ed pages */
-	enum zs_mapmode vm_mm; /* mapping mode */
-};
-
-struct size_class {
-	/*
-	 * Size of objects stored in this class. Must be multiple
-	 * of ZS_ALIGN.
-	 */
-	int size;
-	unsigned int index;
-
-	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
-	int pages_per_zspage;
-
-	spinlock_t lock;
-
-	/* stats */
-	u64 pages_allocated;
-
-	struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
-	/* Handle of next free chunk (encodes <PFN, obj_idx>) */
-	void *next;
-};
-
-struct zs_pool {
-	struct size_class size_class[ZS_SIZE_CLASSES];
-
-	gfp_t flags;	/* allocation flags used when growing pool */
-	const char *name;
-};
-
-#endif
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 0c4760f..240f7aa 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -662,7 +662,7 @@
 {
 	*value = strchr(textbuf, '=');
 	if (!*value) {
-		pr_err("Unable to locate \"=\" seperator for key,"
+		pr_err("Unable to locate \"=\" separator for key,"
 				" ignoring request.\n");
 		return -1;
 	}
@@ -1269,7 +1269,7 @@
 		comma_ptr = strchr(value, ',');
 
 		if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) {
-			pr_err("Detected value seperator \",\", but"
+			pr_err("Detected value separator \",\", but"
 				" key \"%s\" does not allow a value list,"
 				" protocol error.\n", param->name);
 			return -1;
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 830cd62..d8e05ee 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -214,8 +214,8 @@
 	  If you haven't heard about it, it's safe to say N.
 
 config CYZ_INTR
-	bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && CYCLADES
+	bool "Cyclades-Z interrupt mode operation"
+	depends on CYCLADES
 	help
 	  The Cyclades-Z family of multiport cards allows 2 (two) driver op
 	  modes: polling and interrupt. In polling mode, the driver will check
@@ -285,7 +285,7 @@
 
 config NOZOMI
 	tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
-	depends on PCI && EXPERIMENTAL
+	depends on PCI
 	help
 	  If you have a HSDPA driver Broadband Wireless Data Card -
 	  Globe Trotter PCMCIA card, say Y here.
@@ -294,7 +294,7 @@
 	  will be called nozomi.
 
 config ISI
-	tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
+	tristate "Multi-Tech multiport card support"
 	depends on SERIAL_NONSTANDARD && PCI
 	select FW_LOADER
 	help
@@ -317,7 +317,6 @@
 
 config N_GSM
 	tristate "GSM MUX line discipline support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
 	depends on NET
 	help
 	  This line discipline provides support for the GSM MUX protocol and
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 0282a83..f47b734 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -76,7 +76,7 @@
 
 config HVC_UDBG
        bool "udbg based fake hypervisor console"
-       depends on PPC && EXPERIMENTAL
+       depends on PPC
        select HVC_DRIVER
        default n
        help
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 7f80f15..4a65299 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -558,7 +558,7 @@
 	struct hvc_struct *hp = tty->driver_data;
 
 	if (!hp)
-		return -1;
+		return 0;
 
 	return hp->outbuf_size - hp->n_outbuf;
 }
diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c
index 57c8b48..d2af155 100644
--- a/drivers/tty/ipwireless/network.c
+++ b/drivers/tty/ipwireless/network.c
@@ -274,7 +274,12 @@
 		network->xaccm[0] = ~0U;
 		network->xaccm[3] = 0x60000000U;
 		network->raccm = ~0U;
-		ppp_register_channel(channel);
+		if (ppp_register_channel(channel) < 0) {
+			printk(KERN_ERR IPWIRELESS_PCCARD_NAME
+					": unable to register PPP channel\n");
+			kfree(channel);
+			return;
+		}
 		spin_lock_irqsave(&network->lock, flags);
 		network->ppp_channel = channel;
 	}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 3e210a4..1e8e8ce 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -488,7 +488,7 @@
 	default:
 		if (!(control & 0x01)) {
 			pr_cont("I N(S)%d N(R)%d",
-				(control & 0x0E) >> 1, (control & 0xE) >> 5);
+				(control & 0x0E) >> 1, (control & 0xE0) >> 5);
 		} else switch (control & 0x0F) {
 			case RR:
 				pr_cont("RR(%d)", (control & 0xE0) >> 5);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 2bace84..a82b399 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -628,6 +628,7 @@
 	index = devpts_new_index(inode);
 	if (index < 0) {
 		retval = index;
+		mutex_unlock(&devpts_mutex);
 		goto err_file;
 	}
 
@@ -667,7 +668,6 @@
 	mutex_unlock(&tty_mutex);
 	devpts_kill_index(inode, index);
 err_file:
-        mutex_unlock(&devpts_mutex);
 	tty_free_file(filp);
 	return retval;
 }
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index d4e0b07..3ba4234 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -290,6 +290,9 @@
 				  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
 		.flags		= UART_CAP_FIFO,
 	},
+	[PORT_8250_CIR] = {
+		.name		= "CIR port"
+	}
 };
 
 /* Uart divisor latch read */
@@ -1037,6 +1040,7 @@
 	unsigned char save_lcr, save_mcr;
 	struct uart_port *port = &up->port;
 	unsigned long flags;
+	unsigned int old_capabilities;
 
 	if (!port->iobase && !port->mapbase && !port->membase)
 		return;
@@ -1087,6 +1091,7 @@
 			/*
 			 * We failed; there's nothing here
 			 */
+			spin_unlock_irqrestore(&port->lock, flags);
 			DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
 				       scratch2, scratch3);
 			goto out;
@@ -1110,6 +1115,7 @@
 		status1 = serial_in(up, UART_MSR) & 0xF0;
 		serial_out(up, UART_MCR, save_mcr);
 		if (status1 != 0x90) {
+			spin_unlock_irqrestore(&port->lock, flags);
 			DEBUG_AUTOCONF("LOOP test failed (%02x) ",
 				       status1);
 			goto out;
@@ -1132,8 +1138,6 @@
 	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(up, UART_IIR) >> 6;
 
-	DEBUG_AUTOCONF("iir=%d ", scratch);
-
 	switch (scratch) {
 	case 0:
 		autoconfig_8250(up);
@@ -1167,19 +1171,13 @@
 
 	serial_out(up, UART_LCR, save_lcr);
 
-	if (up->capabilities != uart_config[port->type].flags) {
-		printk(KERN_WARNING
-		       "ttyS%d: detected caps %08x should be %08x\n",
-		       serial_index(port), up->capabilities,
-		       uart_config[port->type].flags);
-	}
-
 	port->fifosize = uart_config[up->port.type].fifo_size;
+	old_capabilities = up->capabilities; 
 	up->capabilities = uart_config[port->type].flags;
 	up->tx_loadsz = uart_config[port->type].tx_loadsz;
 
 	if (port->type == PORT_UNKNOWN)
-		goto out;
+		goto out_lock;
 
 	/*
 	 * Reset the UART.
@@ -1196,8 +1194,16 @@
 	else
 		serial_out(up, UART_IER, 0);
 
- out:
+out_lock:
 	spin_unlock_irqrestore(&port->lock, flags);
+	if (up->capabilities != old_capabilities) {
+		printk(KERN_WARNING
+		       "ttyS%d: detected caps %08x should be %08x\n",
+		       serial_index(port), old_capabilities,
+		       up->capabilities);
+	}
+out:
+	DEBUG_AUTOCONF("iir=%d ", scratch);
 	DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name);
 }
 
@@ -1897,6 +1903,9 @@
 	unsigned char lsr, iir;
 	int retval;
 
+	if (port->type == PORT_8250_CIR)
+		return -ENODEV;
+
 	port->fifosize = uart_config[up->port.type].fifo_size;
 	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 	up->capabilities = uart_config[up->port.type].flags;
@@ -2554,7 +2563,10 @@
 {
 	struct uart_8250_port *up =
 		container_of(port, struct uart_8250_port, port);
-	int ret = 0;
+	int ret;
+
+	if (port->type == PORT_8250_CIR)
+		return -ENODEV;
 
 	ret = serial8250_request_std_resource(up);
 	if (ret == 0 && port->type == PORT_RSA) {
@@ -2573,6 +2585,9 @@
 	int probeflags = PROBE_ANY;
 	int ret;
 
+	if (port->type == PORT_8250_CIR)
+		return;
+
 	/*
 	 * Find the region that we can probe for.  This in turn
 	 * tells us whether we can probe for the type of port.
@@ -2672,6 +2687,9 @@
 		return;
 	first = 0;
 
+	if (nr_uarts > UART_NR)
+		nr_uarts = UART_NR;
+
 	for (i = 0; i < nr_uarts; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 		struct uart_port *port = &up->port;
@@ -2681,6 +2699,7 @@
 
 		init_timer(&up->timer);
 		up->timer.function = serial8250_timeout;
+		up->cur_iotype = 0xFF;
 
 		/*
 		 * ALPHA_KLUDGE_MCR needs to be killed.
@@ -2732,13 +2751,9 @@
 
 	for (i = 0; i < nr_uarts; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
-		up->cur_iotype = 0xFF;
-	}
 
-	serial8250_isa_init_ports();
-
-	for (i = 0; i < nr_uarts; i++) {
-		struct uart_8250_port *up = &serial8250_ports[i];
+		if (up->port.dev)
+			continue;
 
 		up->port.dev = dev;
 
@@ -2863,9 +2878,6 @@
 
 static int __init serial8250_console_init(void)
 {
-	if (nr_uarts > UART_NR)
-		nr_uarts = UART_NR;
-
 	serial8250_isa_init_ports();
 	register_console(&serial8250_console);
 	return 0;
@@ -3147,8 +3159,9 @@
 	mutex_lock(&serial_mutex);
 
 	uart = serial8250_find_match_or_unused(&up->port);
-	if (uart) {
-		uart_remove_one_port(&serial8250_reg, &uart->port);
+	if (uart && uart->port.type != PORT_8250_CIR) {
+		if (uart->port.dev)
+			uart_remove_one_port(&serial8250_reg, &uart->port);
 
 		uart->port.iobase       = up->port.iobase;
 		uart->port.membase      = up->port.membase;
@@ -3232,8 +3245,7 @@
 {
 	int ret;
 
-	if (nr_uarts > UART_NR)
-		nr_uarts = UART_NR;
+	serial8250_isa_init_ports();
 
 	printk(KERN_INFO "Serial: 8250/16550 driver, "
 		"%d ports, IRQ sharing %sabled\n", nr_uarts,
@@ -3248,11 +3260,15 @@
 	if (ret)
 		goto out;
 
+	ret = serial8250_pnp_init();
+	if (ret)
+		goto unreg_uart_drv;
+
 	serial8250_isa_devs = platform_device_alloc("serial8250",
 						    PLAT8250_DEV_LEGACY);
 	if (!serial8250_isa_devs) {
 		ret = -ENOMEM;
-		goto unreg_uart_drv;
+		goto unreg_pnp;
 	}
 
 	ret = platform_device_add(serial8250_isa_devs);
@@ -3268,6 +3284,8 @@
 	platform_device_del(serial8250_isa_devs);
 put_dev:
 	platform_device_put(serial8250_isa_devs);
+unreg_pnp:
+	serial8250_pnp_exit();
 unreg_uart_drv:
 #ifdef CONFIG_SPARC
 	sunserial_unregister_minors(&serial8250_reg, UART_NR);
@@ -3292,6 +3310,8 @@
 	platform_driver_unregister(&serial8250_isa_driver);
 	platform_device_unregister(isa_dev);
 
+	serial8250_pnp_exit();
+
 #ifdef CONFIG_SPARC
 	sunserial_unregister_minors(&serial8250_reg, UART_NR);
 #else
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 0c5e908..5a76f9c 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -97,3 +97,12 @@
 #else
 #define ALPHA_KLUDGE_MCR 0
 #endif
+
+#ifdef CONFIG_SERIAL_8250_PNP
+int serial8250_pnp_init(void);
+void serial8250_pnp_exit(void);
+#else
+static inline int serial8250_pnp_init(void) { return 0; }
+static inline void serial8250_pnp_exit(void) { }
+#endif
+
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index fdab80a..17b7d26 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1181,6 +1181,8 @@
 #define PCI_SUBDEVICE_ID_OCTPRO422	0x0208
 #define PCI_SUBDEVICE_ID_POCTAL232	0x0308
 #define PCI_SUBDEVICE_ID_POCTAL422	0x0408
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_00	0x2500
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_30	0x2530
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe
 #define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
 #define PCI_DEVICE_ID_ADVANTECH_PCI3620	0x3620
@@ -3286,8 +3288,11 @@
 		 * For now just used the hex ID 0x950a.
 		 */
 	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
-		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
-		pbn_b0_2_115200 },
+		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
+		0, 0, pbn_b0_2_115200 },
+	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
+		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
+		0, 0, pbn_b0_2_115200 },
 	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_2_1130000 },
@@ -4309,7 +4314,7 @@
 		pciserial_resume_ports(priv);
 }
 
-static struct pci_error_handlers serial8250_err_handler = {
+static const struct pci_error_handlers serial8250_err_handler = {
 	.error_detected = serial8250_io_error_detected,
 	.slot_reset = serial8250_io_slot_reset,
 	.resume = serial8250_io_resume,
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index fde5aa6..f8ee250 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -1,5 +1,5 @@
 /*
- *  Probe module for 8250/16550-type ISAPNP serial ports.
+ *  Probe for 8250/16550-type ISAPNP serial ports.
  *
  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
  *
@@ -25,7 +25,7 @@
 #include "8250.h"
 
 #define UNKNOWN_DEV 0x3000
-
+#define CIR_PORT	0x0800
 
 static const struct pnp_device_id pnp_dev_table[] = {
 	/* Archtek America Corp. */
@@ -362,6 +362,9 @@
 	{	"PNPCXXX",		UNKNOWN_DEV	},
 	/* More unknown PnP modems */
 	{	"PNPDXXX",		UNKNOWN_DEV	},
+	/* Winbond CIR port, should not be probed. We should keep track
+	   of it to prevent the legacy serial driver from probing it */
+	{	"WEC1022",		CIR_PORT	},
 	{	"",			0	}
 };
 
@@ -409,7 +412,7 @@
  * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
  * table.
  */
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
+static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
 {
 	if (!(check_name(pnp_dev_name(dev)) ||
 		(dev->card && check_name(dev->card->name))))
@@ -428,7 +431,7 @@
 	int ret, line, flags = dev_id->driver_data;
 
 	if (flags & UNKNOWN_DEV) {
-		ret = serial_pnp_guess_board(dev, &flags);
+		ret = serial_pnp_guess_board(dev);
 		if (ret < 0)
 			return ret;
 	}
@@ -436,7 +439,10 @@
 	memset(&uart, 0, sizeof(uart));
 	if (pnp_irq_valid(dev, 0))
 		uart.port.irq = pnp_irq(dev, 0);
-	if (pnp_port_valid(dev, 0)) {
+	if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
+		uart.port.iobase = pnp_port_start(dev, 2);
+		uart.port.iotype = UPIO_PORT;
+	} else if (pnp_port_valid(dev, 0)) {
 		uart.port.iobase = pnp_port_start(dev, 0);
 		uart.port.iotype = UPIO_PORT;
 	} else if (pnp_mem_valid(dev, 0)) {
@@ -451,6 +457,10 @@
 		"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
 		       uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
 #endif
+	if (flags & CIR_PORT) {
+		uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+		uart.port.type = PORT_8250_CIR;
+	}
 
 	uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
 	if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
@@ -459,7 +469,7 @@
 	uart.port.dev = &dev->dev;
 
 	line = serial8250_register_8250_port(&uart);
-	if (line < 0)
+	if (line < 0 || (flags & CIR_PORT))
 		return -ENODEV;
 
 	pnp_set_drvdata(dev, (void *)((long)line + 1));
@@ -507,18 +517,13 @@
 	.id_table	= pnp_dev_table,
 };
 
-static int __init serial8250_pnp_init(void)
+int serial8250_pnp_init(void)
 {
 	return pnp_register_driver(&serial_pnp_driver);
 }
 
-static void __exit serial8250_pnp_exit(void)
+void serial8250_pnp_exit(void)
 {
 	pnp_unregister_driver(&serial_pnp_driver);
 }
 
-module_init(serial8250_pnp_init);
-module_exit(serial8250_pnp_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index a27dd05..f3d283f 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -33,6 +33,14 @@
 	  Most people will say Y or M here, so that they can use serial mice,
 	  modems and similar devices connecting to the standard serial ports.
 
+config SERIAL_8250_PNP
+	bool "8250/16550 PNP device support" if EXPERT
+	depends on SERIAL_8250 && PNP
+	default y
+	---help---
+	  This builds standard PNP serial support. You may be able to
+	  disable this feature if you only need legacy serial support.
+
 config SERIAL_8250_CONSOLE
 	bool "Console on 8250/16550 and compatible serial port"
 	depends on SERIAL_8250=y
@@ -85,14 +93,6 @@
 	  disable this feature if you only need legacy serial support.
 	  Saves about 9K.
 
-config SERIAL_8250_PNP
-	tristate "8250/16550 PNP device support" if EXPERT
-	depends on SERIAL_8250 && PNP
-	default SERIAL_8250
-	help
-	  This builds standard PNP serial support. You may be able to
-	  disable this feature if you only need legacy serial support.
-
 config SERIAL_8250_HP300
 	tristate
 	depends on SERIAL_8250 && HP300
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index d7533c7..108fe7f 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -2,8 +2,9 @@
 # Makefile for the 8250 serial device drivers.
 #
 
-obj-$(CONFIG_SERIAL_8250)		+= 8250.o
-obj-$(CONFIG_SERIAL_8250_PNP)		+= 8250_pnp.o
+obj-$(CONFIG_SERIAL_8250)		+= 8250_core.o
+8250_core-y				:= 8250.o
+8250_core-$(CONFIG_SERIAL_8250_PNP)	+= 8250_pnp.o
 obj-$(CONFIG_SERIAL_8250_GSC)		+= 8250_gsc.o
 obj-$(CONFIG_SERIAL_8250_PCI)		+= 8250_pci.o
 obj-$(CONFIG_SERIAL_8250_HP300)		+= 8250_hp300.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26907cf..233fbaa 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -141,6 +141,25 @@
 
 	  Say Y if you have an external 8250/16C550 UART.  If unsure, say N.
 
+config SERIAL_KGDB_NMI
+	bool "Serial console over KGDB NMI debugger port"
+	depends on KGDB_SERIAL_CONSOLE
+	help
+	  This special driver allows you to temporary use NMI debugger port
+	  as a normal console (assuming that the port is attached to KGDB).
+
+	  Unlike KDB's disable_nmi command, with this driver you are always
+	  able to go back to the debugger using KGDB escape sequence ($3#33).
+	  This is because this console driver processes the input in NMI
+	  context, and thus is able to intercept the magic sequence.
+
+	  Note that since the console interprets input and uses polling
+	  communication methods, for things like PPP you still must fully
+	  detach debugger port from the KGDB NMI (i.e. disable_nmi), and
+	  use raw console.
+
+	  If unsure, say N.
+
 config SERIAL_KS8695
 	bool "Micrel KS8695 (Centaur) serial port support"
 	depends on ARCH_KS8695
@@ -693,7 +712,7 @@
 
 config SERIAL_SH_SCI_DMA
 	bool "DMA support"
-	depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
+	depends on SERIAL_SH_SCI && SH_DMAE
 
 config SERIAL_PNX8XXX
 	bool "Enable PNX8XXX SoCs' UART Support"
@@ -1304,7 +1323,7 @@
 
 config SERIAL_IFX6X60
         tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
-	depends on GPIOLIB && SPI && EXPERIMENTAL
+	depends on GPIOLIB && SPI
 	help
 	  Support for the IFX6x60 modem devices on Intel MID platforms.
 
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index ce88667..4f694da 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -61,6 +61,7 @@
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
+obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
 obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index cede938..d7e1ede 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1284,11 +1284,40 @@
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+static void pl011_quiesce_irqs(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	unsigned char __iomem *regs = uap->port.membase;
+
+	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
+	/*
+	 * There is no way to clear TXIM as this is "ready to transmit IRQ", so
+	 * we simply mask it. start_tx() will unmask it.
+	 *
+	 * Note we can race with start_tx(), and if the race happens, the
+	 * polling user might get another interrupt just after we clear it.
+	 * But it should be OK and can happen even w/o the race, e.g.
+	 * controller immediately got some new data and raised the IRQ.
+	 *
+	 * And whoever uses polling routines assumes that it manages the device
+	 * (including tx queue), so we're also fine with start_tx()'s caller
+	 * side.
+	 */
+	writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
+}
+
 static int pl011_get_poll_char(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int status;
 
+	/*
+	 * The caller might need IRQs lowered, e.g. if used with KDB NMI
+	 * debugger.
+	 */
+	pl011_quiesce_irqs(port);
+
 	status = readw(uap->port.membase + UART01x_FR);
 	if (status & UART01x_FR_RXFE)
 		return NO_POLL_CHAR;
@@ -1309,10 +1338,9 @@
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_startup(struct uart_port *port)
+static int pl011_hwinit(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	unsigned int cr;
 	int retval;
 
 	/* Optionaly enable pins to be muxed in and configured */
@@ -1337,6 +1365,37 @@
 	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
 
 	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (uap->port.dev->platform_data) {
+		struct amba_pl011_data *plat;
+
+		plat = uap->port.dev->platform_data;
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
+static int pl011_startup(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	unsigned int cr;
+	int retval;
+
+	retval = pl011_hwinit(port);
+	if (retval)
+		goto clk_dis;
+
+	writew(uap->im, uap->port.membase + UART011_IMSC);
+
+	/*
 	 * Allocate the IRQ
 	 */
 	retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
@@ -1395,19 +1454,10 @@
 	writew(uap->im, uap->port.membase + UART011_IMSC);
 	spin_unlock_irq(&uap->port.lock);
 
-	if (uap->port.dev->platform_data) {
-		struct amba_pl011_data *plat;
-
-		plat = uap->port.dev->platform_data;
-		if (plat->init)
-			plat->init();
-	}
-
 	return 0;
 
  clk_dis:
 	clk_disable_unprepare(uap->clk);
- out:
 	return retval;
 }
 
@@ -1595,13 +1645,26 @@
 			old_cr &= ~ST_UART011_CR_OVSFACT;
 	}
 
+	/*
+	 * Workaround for the ST Micro oversampling variants to
+	 * increase the bitrate slightly, by lowering the divisor,
+	 * to avoid delayed sampling of start bit at high speeds,
+	 * else we see data corruption.
+	 */
+	if (uap->vendor->oversampling) {
+		if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
+			quot -= 1;
+		else if ((baud > 3250000) && (quot > 2))
+			quot -= 2;
+	}
 	/* Set baud rate */
 	writew(quot & 0x3f, port->membase + UART011_FBRD);
 	writew(quot >> 6, port->membase + UART011_IBRD);
 
 	/*
 	 * ----------v----------v----------v----------v-----
-	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+	 * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
+	 * UART011_FBRD & UART011_IBRD.
 	 * ----------^----------^----------^----------^-----
 	 */
 	writew(lcr_h, port->membase + uap->lcrh_rx);
@@ -1688,6 +1751,7 @@
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
+	.poll_init     = pl011_hwinit,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index b418947..d0dd919 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -71,7 +71,7 @@
 
 /**************************************************************/
 
-#define HW_BUF_SPD_THRESHOLD    9600
+#define HW_BUF_SPD_THRESHOLD    2400
 
 /*
  * Check, if transmit buffers are processed
@@ -417,6 +417,7 @@
 			clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
 			clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
 		}
+		cpm_uart_initbd(pinfo);
 		cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
 	}
 	/* Install interrupt handler. */
@@ -500,16 +501,28 @@
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
 	smc_t __iomem *smcp = pinfo->smcp;
 	scc_t __iomem *sccp = pinfo->sccp;
+	int maxidl;
 
 	pr_debug("CPM uart[%d]:set_termios\n", port->line);
 
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-	if (baud <= HW_BUF_SPD_THRESHOLD ||
+	if (baud < HW_BUF_SPD_THRESHOLD ||
 	    (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
 		pinfo->rx_fifosize = 1;
 	else
 		pinfo->rx_fifosize = RX_BUF_SIZE;
 
+	/* MAXIDL is the timeout after which a receive buffer is closed
+	 * when not full if no more characters are received.
+	 * We calculate it from the baudrate so that the duration is
+	 * always the same at standard rates: about 4ms.
+	 */
+	maxidl = baud / 2400;
+	if (maxidl < 1)
+		maxidl = 1;
+	if (maxidl > 0x10)
+		maxidl = 0x10;
+
 	/* Character length programmed into the mode register is the
 	 * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
 	 * 1 or 2 stop bits, minus 1.
@@ -610,6 +623,7 @@
 		 * SMC/SCC receiver is disabled.
 		 */
 		out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+		out_be16(&pinfo->smcup->smc_maxidl, maxidl);
 
 		/* Set the mode register.  We want to keep a copy of the
 		 * enables, because we want to put them back if they were
@@ -622,6 +636,7 @@
 		    SMCMR_SM_UART | prev_mode);
 	} else {
 		out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+		out_be16(&pinfo->sccup->scc_maxidl, maxidl);
 		out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
 	}
 
@@ -798,7 +813,7 @@
 	cpm_set_scc_fcr(sup);
 
 	out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
-	out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+	out_be16(&sup->scc_maxidl, 0x10);
 	out_be16(&sup->scc_brkcr, 1);
 	out_be16(&sup->scc_parec, 0);
 	out_be16(&sup->scc_frmec, 0);
@@ -872,7 +887,7 @@
 
 	/* Using idle character time requires some additional tuning.  */
 	out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
-	out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+	out_be16(&up->smc_maxidl, 0x10);
 	out_be16(&up->smc_brklen, 0);
 	out_be16(&up->smc_brkec, 0);
 	out_be16(&up->smc_brkcr, 1);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 5952b25..efeb8be 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1373,8 +1373,7 @@
 	val |= UCR3_AWAKEN;
 	writel(val, sport->port.membase + UCR3);
 
-	if (sport)
-		uart_suspend_port(&imx_reg, &sport->port);
+	uart_suspend_port(&imx_reg, &sport->port);
 
 	return 0;
 }
@@ -1389,8 +1388,7 @@
 	val &= ~UCR3_AWAKEN;
 	writel(val, sport->port.membase + UCR3);
 
-	if (sport)
-		uart_resume_port(&imx_reg, &sport->port);
+	uart_resume_port(&imx_reg, &sport->port);
 
 	return 0;
 }
@@ -1540,7 +1538,7 @@
 	ret = uart_add_one_port(&imx_reg, &sport->port);
 	if (ret)
 		goto deinit;
-	platform_set_drvdata(pdev, &sport->port);
+	platform_set_drvdata(pdev, sport);
 
 	return 0;
 deinit:
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 7545fe1..5ab3c3b 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -54,7 +54,7 @@
 static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
 static void jsm_io_resume(struct pci_dev *pdev);
 
-static struct pci_error_handlers jsm_err_handler = {
+static const struct pci_error_handlers jsm_err_handler = {
 	.error_detected = jsm_io_error_detected,
 	.slot_reset = jsm_io_slot_reset,
 	.resume = jsm_io_resume,
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
new file mode 100644
index 0000000..d185247
--- /dev/null
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -0,0 +1,402 @@
+/*
+ * KGDB NMI serial console
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/atomic.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/kfifo.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+
+static int kgdb_nmi_knock = 1;
+module_param_named(knock, kgdb_nmi_knock, int, 0600);
+MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \
+			"must be used to enter the debugger; when set to 0, " \
+			"hitting return key is enough to enter the debugger; " \
+			"when set to -1, the debugger is entered immediately " \
+			"upon NMI");
+
+static char *kgdb_nmi_magic = "$3#33";
+module_param_named(magic, kgdb_nmi_magic, charp, 0600);
+MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
+
+static bool kgdb_nmi_tty_enabled;
+
+static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
+{
+	int i;
+
+	if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
+		return;
+
+	for (i = 0; i < c; i++)
+		dbg_io_ops->write_char(s[i]);
+}
+
+static struct tty_driver *kgdb_nmi_tty_driver;
+
+static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
+{
+	*idx = co->index;
+	return kgdb_nmi_tty_driver;
+}
+
+static struct console kgdb_nmi_console = {
+	.name	= "ttyNMI",
+	.write	= kgdb_nmi_console_write,
+	.device	= kgdb_nmi_console_device,
+	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+	.index	= -1,
+};
+
+/*
+ * This is usually the maximum rate on debug ports. We make fifo large enough
+ * to make copy-pasting to the terminal usable.
+ */
+#define KGDB_NMI_BAUD		115200
+#define KGDB_NMI_FIFO_SIZE	roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
+
+struct kgdb_nmi_tty_priv {
+	struct tty_port port;
+	struct tasklet_struct tlet;
+	STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
+};
+
+static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
+{
+	return container_of(port, struct kgdb_nmi_tty_priv, port);
+}
+
+/*
+ * Our debugging console is polled in a tasklet, so we'll check for input
+ * every tick. In HZ-less mode, we should program the next tick.  We have
+ * to use the lowlevel stuff as no locks should be grabbed.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void kgdb_tty_poke(void)
+{
+	tick_program_event(ktime_get(), 0);
+}
+#else
+static inline void kgdb_tty_poke(void) {}
+#endif
+
+static struct tty_port *kgdb_nmi_port;
+
+static void kgdb_tty_recv(int ch)
+{
+	struct kgdb_nmi_tty_priv *priv;
+	char c = ch;
+
+	if (!kgdb_nmi_port || ch < 0)
+		return;
+	/*
+	 * Can't use port->tty->driver_data as tty might be not there. Tasklet
+	 * will check for tty and will get the ref, but here we don't have to
+	 * do that, and actually, we can't: we're in NMI context, no locks are
+	 * possible.
+	 */
+	priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
+	kfifo_in(&priv->fifo, &c, 1);
+	kgdb_tty_poke();
+}
+
+static int kgdb_nmi_poll_one_knock(void)
+{
+	static int n;
+	int c = -1;
+	const char *magic = kgdb_nmi_magic;
+	size_t m = strlen(magic);
+	bool printch = 0;
+
+	c = dbg_io_ops->read_char();
+	if (c == NO_POLL_CHAR)
+		return c;
+
+	if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) {
+		return 1;
+	} else if (c == magic[n]) {
+		n = (n + 1) % m;
+		if (!n)
+			return 1;
+		printch = 1;
+	} else {
+		n = 0;
+	}
+
+	if (kgdb_nmi_tty_enabled) {
+		kgdb_tty_recv(c);
+		return 0;
+	}
+
+	if (printch) {
+		kdb_printf("%c", c);
+		return 0;
+	}
+
+	kdb_printf("\r%s %s to enter the debugger> %*s",
+		   kgdb_nmi_knock ? "Type" : "Hit",
+		   kgdb_nmi_knock ? magic  : "<return>", (int)m, "");
+	while (m--)
+		kdb_printf("\b");
+	return 0;
+}
+
+/**
+ * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
+ *
+ * "Serial ports are often noisy, especially when muxed over another port (we
+ * often use serial over the headset connector). Noise on the async command
+ * line just causes characters that are ignored, on a command line that blocked
+ * execution noise would be catastrophic." -- Colin Cross
+ *
+ * So, this function implements KGDB/KDB knocking on the serial line: we won't
+ * enter the debugger until we receive a known magic phrase (which is actually
+ * "$3#33", known as "escape to KDB" command. There is also a relaxed variant
+ * of knocking, i.e. just pressing the return key is enough to enter the
+ * debugger. And if knocking is disabled, the function always returns 1.
+ */
+bool kgdb_nmi_poll_knock(void)
+{
+	if (kgdb_nmi_knock < 0)
+		return 1;
+
+	while (1) {
+		int ret;
+
+		ret = kgdb_nmi_poll_one_knock();
+		if (ret == NO_POLL_CHAR)
+			return 0;
+		else if (ret == 1)
+			break;
+	}
+	return 1;
+}
+
+/*
+ * The tasklet is cheap, it does not cause wakeups when reschedules itself,
+ * instead it waits for the next tick.
+ */
+static void kgdb_nmi_tty_receiver(unsigned long data)
+{
+	struct kgdb_nmi_tty_priv *priv = (void *)data;
+	struct tty_struct *tty;
+	char ch;
+
+	tasklet_schedule(&priv->tlet);
+
+	if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
+		return;
+
+	/* Port is there, but tty might be hung up, check. */
+	tty = tty_port_tty_get(kgdb_nmi_port);
+	if (!tty)
+		return;
+
+	while (kfifo_out(&priv->fifo, &ch, 1))
+		tty_insert_flip_char(priv->port.tty, ch, TTY_NORMAL);
+	tty_flip_buffer_push(priv->port.tty);
+
+	tty_kref_put(tty);
+}
+
+static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
+{
+	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+	kgdb_nmi_port = port;
+	tasklet_schedule(&priv->tlet);
+	return 0;
+}
+
+static void kgdb_nmi_tty_shutdown(struct tty_port *port)
+{
+	struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
+
+	tasklet_kill(&priv->tlet);
+	kgdb_nmi_port = NULL;
+}
+
+static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
+	.activate	= kgdb_nmi_tty_activate,
+	.shutdown	= kgdb_nmi_tty_shutdown,
+};
+
+static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
+{
+	struct kgdb_nmi_tty_priv *priv;
+	int ret;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	INIT_KFIFO(priv->fifo);
+	tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
+	tty_port_init(&priv->port);
+	priv->port.ops = &kgdb_nmi_tty_port_ops;
+	tty->driver_data = priv;
+
+	ret = tty_port_install(&priv->port, drv, tty);
+	if (ret) {
+		pr_err("%s: can't install tty port: %d\n", __func__, ret);
+		goto err;
+	}
+	return 0;
+err:
+	kfree(priv);
+	return ret;
+}
+
+static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
+{
+	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+	tty->driver_data = NULL;
+	kfree(priv);
+}
+
+static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
+{
+	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+	return tty_port_open(&priv->port, tty, file);
+}
+
+static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
+{
+	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+	tty_port_close(&priv->port, tty, file);
+}
+
+static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
+{
+	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+	tty_port_hangup(&priv->port);
+}
+
+static int kgdb_nmi_tty_write_room(struct tty_struct *tty)
+{
+	/* Actually, we can handle any amount as we use polled writes. */
+	return 2048;
+}
+
+static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c)
+{
+	int i;
+
+	for (i = 0; i < c; i++)
+		dbg_io_ops->write_char(buf[i]);
+	return c;
+}
+
+static const struct tty_operations kgdb_nmi_tty_ops = {
+	.open		= kgdb_nmi_tty_open,
+	.close		= kgdb_nmi_tty_close,
+	.install	= kgdb_nmi_tty_install,
+	.cleanup	= kgdb_nmi_tty_cleanup,
+	.hangup		= kgdb_nmi_tty_hangup,
+	.write_room	= kgdb_nmi_tty_write_room,
+	.write		= kgdb_nmi_tty_write,
+};
+
+static int kgdb_nmi_enable_console(int argc, const char *argv[])
+{
+	kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off"));
+	return 0;
+}
+
+int kgdb_register_nmi_console(void)
+{
+	int ret;
+
+	if (!arch_kgdb_ops.enable_nmi)
+		return 0;
+
+	kgdb_nmi_tty_driver = alloc_tty_driver(1);
+	if (!kgdb_nmi_tty_driver) {
+		pr_err("%s: cannot allocate tty\n", __func__);
+		return -ENOMEM;
+	}
+	kgdb_nmi_tty_driver->driver_name	= "ttyNMI";
+	kgdb_nmi_tty_driver->name		= "ttyNMI";
+	kgdb_nmi_tty_driver->num		= 1;
+	kgdb_nmi_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
+	kgdb_nmi_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
+	kgdb_nmi_tty_driver->flags		= TTY_DRIVER_REAL_RAW;
+	kgdb_nmi_tty_driver->init_termios	= tty_std_termios;
+	tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
+				     KGDB_NMI_BAUD, KGDB_NMI_BAUD);
+	tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
+
+	ret = tty_register_driver(kgdb_nmi_tty_driver);
+	if (ret) {
+		pr_err("%s: can't register tty driver: %d\n", __func__, ret);
+		goto err_drv_reg;
+	}
+
+	ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]",
+			   "switch to Linux NMI console", 0);
+	if (ret) {
+		pr_err("%s: can't register kdb command: %d\n", __func__, ret);
+		goto err_kdb_reg;
+	}
+
+	register_console(&kgdb_nmi_console);
+	arch_kgdb_ops.enable_nmi(1);
+
+	return 0;
+err_kdb_reg:
+	tty_unregister_driver(kgdb_nmi_tty_driver);
+err_drv_reg:
+	put_tty_driver(kgdb_nmi_tty_driver);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
+
+int kgdb_unregister_nmi_console(void)
+{
+	int ret;
+
+	if (!arch_kgdb_ops.enable_nmi)
+		return 0;
+	arch_kgdb_ops.enable_nmi(0);
+
+	kdb_unregister("nmi_console");
+
+	ret = unregister_console(&kgdb_nmi_console);
+	if (ret)
+		return ret;
+
+	ret = tty_unregister_driver(kgdb_nmi_tty_driver);
+	if (ret)
+		return ret;
+	put_tty_driver(kgdb_nmi_tty_driver);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 2b42a01..3f63d83 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -145,6 +145,8 @@
 
 static void cleanup_kgdboc(void)
 {
+	if (kgdb_unregister_nmi_console())
+		return;
 	kgdboc_unregister_kbd();
 	if (configured == 1)
 		kgdb_unregister_io_module(&kgdboc_io_ops);
@@ -198,11 +200,18 @@
 	if (err)
 		goto noconfig;
 
+	err = kgdb_register_nmi_console();
+	if (err)
+		goto nmi_con_failed;
+
 	configured = 1;
 
 	return 0;
 
+nmi_con_failed:
+	kgdb_unregister_io_module(&kgdboc_io_ops);
 noconfig:
+	kgdboc_unregister_kbd();
 	config[0] = 0;
 	configured = 0;
 	cleanup_kgdboc();
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 46043c2..0f24486 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -827,14 +827,16 @@
 
 	/* find out the index for the chip we are removing */
 	for (i = 0; i < MAX_MAX3100; i++)
-		if (max3100s[i] == s)
+		if (max3100s[i] == s) {
+			dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
+			uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
+			kfree(max3100s[i]);
+			max3100s[i] = NULL;
 			break;
+		}
 
-	dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
-	uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
-	kfree(max3100s[i]);
-	max3100s[i] = NULL;
-
+	WARN_ON(i == MAX_MAX3100);
+	
 	/* check if this is the last chip we have */
 	for (i = 0; i < MAX_MAX3100; i++)
 		if (max3100s[i]) {
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index f19d04e..8cf5770 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -598,7 +598,7 @@
 };
 #endif
 
-static struct psc_ops *psc_ops;
+static const struct psc_ops *psc_ops;
 
 /* ======================================================================== */
 /* UART operations                                                          */
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 6898413..6db3baa 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -781,6 +781,7 @@
 	auart_port[pdev->id] = NULL;
 	free_irq(s->irq, s);
 out_free_clk:
+	put_device(s->dev);
 	clk_put(s->clk);
 out_free:
 	kfree(s);
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f175385..ccc2f35 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -334,6 +334,10 @@
 static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr)
 {
 	unsigned int flag;
+	unsigned char ch = 0;
+
+	if (likely(lsr & UART_LSR_DR))
+		ch = serial_in(up, UART_RX);
 
 	up->port.icount.rx++;
 	flag = TTY_NORMAL;
@@ -1222,10 +1226,8 @@
 {
 	struct uart_omap_port *up = dev_get_drvdata(dev);
 
-	if (up) {
-		uart_suspend_port(&serial_omap_reg, &up->port);
-		flush_work_sync(&up->qos_work);
-	}
+	uart_suspend_port(&serial_omap_reg, &up->port);
+	flush_work_sync(&up->qos_work);
 
 	return 0;
 }
@@ -1234,8 +1236,8 @@
 {
 	struct uart_omap_port *up = dev_get_drvdata(dev);
 
-	if (up)
-		uart_resume_port(&serial_omap_reg, &up->port);
+	uart_resume_port(&serial_omap_reg, &up->port);
+
 	return 0;
 }
 #endif
@@ -1553,17 +1555,14 @@
 static int serial_omap_runtime_resume(struct device *dev)
 {
 	struct uart_omap_port *up = dev_get_drvdata(dev);
-	struct omap_uart_port_info *pdata = dev->platform_data;
 
-	if (up && pdata) {
-			u32 loss_cnt = serial_omap_get_context_loss_count(up);
+	u32 loss_cnt = serial_omap_get_context_loss_count(up);
 
-			if (up->context_loss_cnt != loss_cnt)
-				serial_omap_restore_context(up);
+	if (up->context_loss_cnt != loss_cnt)
+		serial_omap_restore_context(up);
 
-		up->latency = up->calc_latency;
-		schedule_work(&up->qos_work);
-	}
+	up->latency = up->calc_latency;
+	schedule_work(&up->qos_work);
 
 	return 0;
 }
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index bdaa06f..7f04717 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -876,11 +876,24 @@
 
 static struct console s3c24xx_serial_console;
 
+static int __init s3c24xx_serial_console_init(void)
+{
+	register_console(&s3c24xx_serial_console);
+	return 0;
+}
+console_initcall(s3c24xx_serial_console_init);
+
 #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
 #else
 #define S3C24XX_SERIAL_CONSOLE NULL
 #endif
 
+#ifdef CONFIG_CONSOLE_POLL
+static int s3c24xx_serial_get_poll_char(struct uart_port *port);
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+			 unsigned char c);
+#endif
+
 static struct uart_ops s3c24xx_serial_ops = {
 	.pm		= s3c24xx_serial_pm,
 	.tx_empty	= s3c24xx_serial_tx_empty,
@@ -899,6 +912,10 @@
 	.request_port	= s3c24xx_serial_request_port,
 	.config_port	= s3c24xx_serial_config_port,
 	.verify_port	= s3c24xx_serial_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char = s3c24xx_serial_get_poll_char,
+	.poll_put_char = s3c24xx_serial_put_poll_char,
+#endif
 };
 
 static struct uart_driver s3c24xx_uart_drv = {
@@ -1316,6 +1333,36 @@
 	return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int s3c24xx_serial_get_poll_char(struct uart_port *port)
+{
+	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	unsigned int ufstat;
+
+	ufstat = rd_regl(port, S3C2410_UFSTAT);
+	if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+		return NO_POLL_CHAR;
+
+	return rd_regb(port, S3C2410_URXH);
+}
+
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+		unsigned char c)
+{
+	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+
+	while (!s3c24xx_serial_console_txrdy(port, ufcon))
+		cpu_relax();
+	wr_regb(cons_uart, S3C2410_UTXH, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
 static void
 s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
 {
@@ -1684,7 +1731,7 @@
 	ret = uart_register_driver(&s3c24xx_uart_drv);
 	if (ret < 0) {
 		pr_err("Failed to register Samsung UART driver\n");
-		return -1;
+		return ret;
 	}
 
 	return platform_driver_register(&samsung_serial_driver);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 05d767c..b7086d0 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -213,7 +213,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static void sccnxp_set_baud(struct uart_port *port, int baud)
+static int sccnxp_set_baud(struct uart_port *port, int baud)
 {
 	struct sccnxp_port *s = dev_get_drvdata(port->dev);
 	int div_std, tmp_baud, bestbaud = baud, besterr = -1;
@@ -244,8 +244,11 @@
 	sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE);
 	sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr);
 
-	dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n",
-		baud, bestbaud);
+	if (baud != bestbaud)
+		dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n",
+			baud, bestbaud);
+
+	return bestbaud;
 }
 
 static void sccnxp_enable_irq(struct uart_port *port, int mask)
@@ -528,7 +531,6 @@
 
 	/* Mask termios capabilities we don't support */
 	termios->c_cflag &= ~CMSPAR;
-	termios->c_iflag &= ~(IXON | IXOFF | IXANY);
 
 	/* Disable RX & TX, reset break condition, status and FIFOs */
 	sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET |
@@ -548,8 +550,8 @@
 	case CS7:
 		mr1 = MR1_BITS_7;
 		break;
-	default:
 	case CS8:
+	default:
 		mr1 = MR1_BITS_8;
 		break;
 	}
@@ -587,11 +589,14 @@
 	baud = uart_get_baud_rate(port, termios, old, 50,
 				  (s->flags & SCCNXP_HAVE_MR0) ?
 				  230400 : 38400);
-	sccnxp_set_baud(port, baud);
+	baud = sccnxp_set_baud(port, baud);
 
 	/* Update timeout according to new baud rate */
 	uart_update_timeout(port, termios->c_cflag, baud);
 
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+
 	/* Enable RX & TX */
 	sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
 
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 046279c..0fcfd98 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2129,6 +2129,7 @@
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
+	int ret;
 
 	if (!state || !state->uart_port)
 		return -1;
@@ -2137,6 +2138,22 @@
 	if (!(port->ops->poll_get_char && port->ops->poll_put_char))
 		return -1;
 
+	if (port->ops->poll_init) {
+		struct tty_port *tport = &state->port;
+
+		ret = 0;
+		mutex_lock(&tport->mutex);
+		/*
+		 * We don't set ASYNCB_INITIALIZED as we only initialized the
+		 * hw, e.g. state->xmit is still uninitialized.
+		 */
+		if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
+			ret = port->ops->poll_init(port);
+		mutex_unlock(&tport->mutex);
+		if (ret)
+			return ret;
+	}
+
 	if (options) {
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 		return uart_set_options(port, NULL, baud, parity, bits, flow);
@@ -2501,9 +2518,12 @@
 {
 	struct uart_state *state = uport->state;
 	struct tty_port *port = &state->port;
-	struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
+	struct tty_ldisc *ld = NULL;
 	struct pps_event_time ts;
+	struct tty_struct *tty = port->tty;
 
+	if (tty)
+	        ld = tty_ldisc_ref(tty);
 	if (ld && ld->ops->dcd_change)
 		pps_get_ts(&ts);
 
@@ -2516,12 +2536,12 @@
 	if (port->flags & ASYNC_CHECK_CD) {
 		if (status)
 			wake_up_interruptible(&port->open_wait);
-		else if (port->tty)
-			tty_hangup(port->tty);
+		else if (tty)
+			tty_hangup(tty);
 	}
 
 	if (ld && ld->ops->dcd_change)
-		ld->ops->dcd_change(port->tty, status, &ts);
+		ld->ops->dcd_change(tty, status, &ts);
 	if (ld)
 		tty_ldisc_deref(ld);
 }
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index 7c13639..9bd004f 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -548,8 +548,8 @@
 
 static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
 	{
-		.membase	= (void *) KS8695_UART_VA,
-		.mapbase	= KS8695_UART_VA,
+		.membase	= KS8695_UART_VA,
+		.mapbase	= KS8695_UART_PA,
 		.iotype		= SERIAL_IO_MEM,
 		.irq		= KS8695_IRQ_UART_TX,
 		.uartclk	= KS8695_CLOCK_RATE * 16,
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7065df6..4c90b510 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -13,7 +13,6 @@
 	default y if PXA3xx
 	default y if ARCH_EP93XX
 	default y if ARCH_AT91
-	default y if ARCH_PNX4008
 	default y if MFD_TC6393XB
 	default y if ARCH_W90X900
 	default y if ARCH_DAVINCI_DA8XX
@@ -48,6 +47,7 @@
 	default y if SPARC_LEON
 	default y if ARCH_MMP
 	default y if MACH_LOONGSON1
+	default y if PLAT_ORION
 	default PCI
 
 # some non-PCI HCDs implement xHCI
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index d7e422d..e1f8b2c 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -307,6 +307,34 @@
 #define FW_GET_BYTE(p) (*((__u8 *) (p)))
 
 #define FW_DIR "ueagle-atm/"
+#define EAGLE_FIRMWARE FW_DIR "eagle.fw"
+#define ADI930_FIRMWARE FW_DIR "adi930.fw"
+#define EAGLE_I_FIRMWARE FW_DIR "eagleI.fw"
+#define EAGLE_II_FIRMWARE FW_DIR "eagleII.fw"
+#define EAGLE_III_FIRMWARE FW_DIR "eagleIII.fw"
+#define EAGLE_IV_FIRMWARE FW_DIR "eagleIV.fw"
+
+#define DSP4I_FIRMWARE FW_DIR "DSP4i.bin"
+#define DSP4P_FIRMWARE FW_DIR "DSP4p.bin"
+#define DSP9I_FIRMWARE FW_DIR "DSP9i.bin"
+#define DSP9P_FIRMWARE FW_DIR "DSP9p.bin"
+#define DSPEI_FIRMWARE FW_DIR "DSPei.bin"
+#define DSPEP_FIRMWARE FW_DIR "DSPep.bin"
+#define FPGA930_FIRMWARE FW_DIR "930-fpga.bin"
+
+#define CMV4P_FIRMWARE FW_DIR "CMV4p.bin"
+#define CMV4PV2_FIRMWARE FW_DIR "CMV4p.bin.v2"
+#define CMV4I_FIRMWARE FW_DIR "CMV4i.bin"
+#define CMV4IV2_FIRMWARE FW_DIR "CMV4i.bin.v2"
+#define CMV9P_FIRMWARE FW_DIR "CMV9p.bin"
+#define CMV9PV2_FIRMWARE FW_DIR "CMV9p.bin.v2"
+#define CMV9I_FIRMWARE FW_DIR "CMV9i.bin"
+#define CMV9IV2_FIRMWARE FW_DIR "CMV9i.bin.v2"
+#define CMVEP_FIRMWARE FW_DIR "CMVep.bin"
+#define CMVEPV2_FIRMWARE FW_DIR "CMVep.bin.v2"
+#define CMVEI_FIRMWARE FW_DIR "CMVei.bin"
+#define CMVEIV2_FIRMWARE FW_DIR "CMVei.bin.v2"
+
 #define UEA_FW_NAME_MAX 30
 #define NB_MODEM 4
 
@@ -694,26 +722,26 @@
 static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
 {
 	int ret;
-	char *fw_name = FW_DIR "eagle.fw";
+	char *fw_name = EAGLE_FIRMWARE;
 
 	uea_enters(usb);
 	uea_info(usb, "pre-firmware device, uploading firmware\n");
 
 	switch (ver) {
 	case ADI930:
-		fw_name = FW_DIR "adi930.fw";
+		fw_name = ADI930_FIRMWARE;
 		break;
 	case EAGLE_I:
-		fw_name = FW_DIR "eagleI.fw";
+		fw_name = EAGLE_I_FIRMWARE;
 		break;
 	case EAGLE_II:
-		fw_name = FW_DIR "eagleII.fw";
+		fw_name = EAGLE_II_FIRMWARE;
 		break;
 	case EAGLE_III:
-		fw_name = FW_DIR "eagleIII.fw";
+		fw_name = EAGLE_III_FIRMWARE;
 		break;
 	case EAGLE_IV:
-		fw_name = FW_DIR "eagleIV.fw";
+		fw_name = EAGLE_IV_FIRMWARE;
 		break;
 	}
 
@@ -869,19 +897,19 @@
 
 	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
 		if (IS_ISDN(sc))
-			dsp_name = FW_DIR "DSP4i.bin";
+			dsp_name = DSP4I_FIRMWARE;
 		else
-			dsp_name = FW_DIR "DSP4p.bin";
+			dsp_name = DSP4P_FIRMWARE;
 	} else if (UEA_CHIP_VERSION(sc) == ADI930) {
 		if (IS_ISDN(sc))
-			dsp_name = FW_DIR "DSP9i.bin";
+			dsp_name = DSP9I_FIRMWARE;
 		else
-			dsp_name = FW_DIR "DSP9p.bin";
+			dsp_name = DSP9P_FIRMWARE;
 	} else {
 		if (IS_ISDN(sc))
-			dsp_name = FW_DIR "DSPei.bin";
+			dsp_name = DSPEI_FIRMWARE;
 		else
-			dsp_name = FW_DIR "DSPep.bin";
+			dsp_name = DSPEP_FIRMWARE;
 	}
 
 	ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev);
@@ -1925,7 +1953,7 @@
 	int ret, size, u, ln;
 	const u8 *pfw;
 	u8 value;
-	char *fw_name = FW_DIR "930-fpga.bin";
+	char *fw_name = FPGA930_FIRMWARE;
 
 	uea_enters(INS_TO_USBDEV(sc));
 
@@ -2753,3 +2781,28 @@
 MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka");
 MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(EAGLE_FIRMWARE);
+MODULE_FIRMWARE(ADI930_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_I_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_II_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_III_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_IV_FIRMWARE);
+MODULE_FIRMWARE(DSP4I_FIRMWARE);
+MODULE_FIRMWARE(DSP4P_FIRMWARE);
+MODULE_FIRMWARE(DSP9I_FIRMWARE);
+MODULE_FIRMWARE(DSP9P_FIRMWARE);
+MODULE_FIRMWARE(DSPEI_FIRMWARE);
+MODULE_FIRMWARE(DSPEP_FIRMWARE);
+MODULE_FIRMWARE(FPGA930_FIRMWARE);
+MODULE_FIRMWARE(CMV4P_FIRMWARE);
+MODULE_FIRMWARE(CMV4PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV4I_FIRMWARE);
+MODULE_FIRMWARE(CMV4IV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9P_FIRMWARE);
+MODULE_FIRMWARE(CMV9PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9I_FIRMWARE);
+MODULE_FIRMWARE(CMV9IV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEP_FIRMWARE);
+MODULE_FIRMWARE(CMVEPV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEI_FIRMWARE);
+MODULE_FIRMWARE(CMVEIV2_FIRMWARE);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index ee62b35..35f10bf 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -84,7 +84,7 @@
 #include <linux/ratelimit.h>
 
 #ifdef VERBOSE_DEBUG
-static int usbatm_print_packet(const unsigned char *data, int len);
+static int usbatm_print_packet(struct usbatm_data *instance, const unsigned char *data, int len);
 #define PACKETDEBUG(arg...)	usbatm_print_packet(arg)
 #define vdbg(arg...)		dev_dbg(arg)
 #else
@@ -230,8 +230,8 @@
 	struct usbatm_channel *channel = urb->context;
 	int ret;
 
-	vdbg("%s: submitting urb 0x%p, size %u",
-	     __func__, urb, urb->transfer_buffer_length);
+	/* vdbg("%s: submitting urb 0x%p, size %u",
+	     __func__, urb, urb->transfer_buffer_length); */
 
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
 	if (ret) {
@@ -261,8 +261,8 @@
 	unsigned long flags;
 	int status = urb->status;
 
-	vdbg("%s: urb 0x%p, status %d, actual_length %d",
-	     __func__, urb, status, urb->actual_length);
+	/* vdbg("%s: urb 0x%p, status %d, actual_length %d",
+	     __func__, urb, status, urb->actual_length); */
 
 	/* usually in_interrupt(), but not always */
 	spin_lock_irqsave(&channel->lock, flags);
@@ -311,7 +311,7 @@
 	int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
 	u8 pti = ((source[3] & 0xe) >> 1);
 
-	vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
+	vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
 
 	if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
 		instance->cached_vpi = vpi;
@@ -381,7 +381,9 @@
 			goto out;
 		}
 
-		vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
+		vdbg(&instance->usb_intf->dev,
+		     "%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)",
+		     __func__, length, pdu_length, vcc);
 
 		if (!(skb = dev_alloc_skb(length))) {
 			if (printk_ratelimit())
@@ -391,7 +393,9 @@
 			goto out;
 		}
 
-		vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
+		vdbg(&instance->usb_intf->dev,
+		     "%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)",
+		     __func__, skb, skb->truesize);
 
 		if (!atm_charge(vcc, skb->truesize)) {
 			atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n",
@@ -405,10 +409,11 @@
 					length);
 		__skb_put(skb, length);
 
-		vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
+		vdbg(&instance->usb_intf->dev,
+		     "%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
 		     __func__, skb, skb->len, skb->truesize);
 
-		PACKETDEBUG(skb->data, skb->len);
+		PACKETDEBUG(instance, skb->data, skb->len);
 
 		vcc->push(vcc, skb);
 
@@ -474,7 +479,8 @@
 	unsigned int bytes_written;
 	unsigned int stride = instance->tx_channel.stride;
 
-	vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
+	vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u",
+	     __func__, skb->len, avail_space);
 	UDSL_ASSERT(instance, !(avail_space % stride));
 
 	for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
@@ -534,7 +540,8 @@
 	struct urb *urb;
 
 	while ((urb = usbatm_pop_urb(&instance->rx_channel))) {
-		vdbg("%s: processing urb 0x%p", __func__, urb);
+		vdbg(&instance->usb_intf->dev,
+		     "%s: processing urb 0x%p", __func__, urb);
 
 		if (usb_pipeisoc(urb->pipe)) {
 			unsigned char *merge_start = NULL;
@@ -608,7 +615,8 @@
 						  buffer + bytes_written,
 						  buf_size - bytes_written);
 
-		vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",
+		vdbg(&instance->usb_intf->dev,
+		     "%s: wrote %u bytes from skb 0x%p to urb 0x%p",
 		     __func__, bytes_written, skb, urb);
 
 		if (!UDSL_SKB(skb)->len) {
@@ -664,7 +672,8 @@
 	struct usbatm_control *ctrl = UDSL_SKB(skb);
 	int err;
 
-	vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
+	vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
+	     skb, skb->len);
 
 	/* racy disconnection check - fine */
 	if (!instance || instance->disconnected) {
@@ -688,7 +697,7 @@
 		goto fail;
 	}
 
-	PACKETDEBUG(skb->data, skb->len);
+	PACKETDEBUG(instance, skb->data, skb->len);
 
 	/* initialize the control block */
 	ctrl->atm.vcc = vcc;
@@ -1202,7 +1211,7 @@
 		if (i >= num_rcv_urbs)
 			list_add_tail(&urb->urb_list, &channel->list);
 
-		vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p",
+		vdbg(&intf->dev, "%s: alloced buffer 0x%p buf size %u urb 0x%p",
 		     __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
 	}
 
@@ -1359,7 +1368,8 @@
 ************/
 
 #ifdef VERBOSE_DEBUG
-static int usbatm_print_packet(const unsigned char *data, int len)
+static int usbatm_print_packet(struct usbatm_data *instance,
+			       const unsigned char *data, int len)
 {
 	unsigned char buffer[256];
 	int i = 0, j = 0;
@@ -1369,7 +1379,7 @@
 		sprintf(buffer, "%.3d :", i);
 		for (j = 0; (j < 16) && (i < len); j++, i++)
 			sprintf(buffer, "%s %2.2x", buffer, data[i]);
-		dbg("%s", buffer);
+		dev_dbg(&instance->usb_intf->dev, "%s", buffer);
 	}
 	return i;
 }
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index 47e499c..1ea932a 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -13,7 +13,6 @@
 config USB_CHIPIDEA_UDC
 	bool "ChipIdea device controller"
 	depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
-	select USB_GADGET_DUALSPEED
 	help
 	  Say Y here to enable device controller functionality of the
 	  ChipIdea driver.
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 5c66d9c..d92ca32 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
+
 obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 
 ci_hdrc-y				:= core.o
@@ -15,5 +17,5 @@
 endif
 
 ifneq ($(CONFIG_OF_DEVICE),)
-	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_imx.o
+	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_imx.o usbmisc_imx6q.o
 endif
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index d738603..e25d126 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -139,6 +139,7 @@
 	enum ci_role			role;
 	bool				is_otg;
 	struct work_struct		work;
+	struct work_struct		vbus_work;
 	struct workqueue_struct		*wq;
 
 	struct dma_pool			*qh_pool;
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index ef60d06..0f5ca4b 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -20,8 +20,10 @@
 #include <linux/usb/chipidea.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "ci.h"
+#include "ci13xxx_imx.h"
 
 #define pdev_to_phy(pdev) \
 	((struct usb_phy *)platform_get_drvdata(pdev))
@@ -34,6 +36,55 @@
 	struct regulator *reg_vbus;
 };
 
+static const struct usbmisc_ops *usbmisc_ops;
+
+/* Common functions shared by usbmisc drivers */
+
+int usbmisc_set_ops(const struct usbmisc_ops *ops)
+{
+	if (usbmisc_ops)
+		return -EBUSY;
+
+	usbmisc_ops = ops;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usbmisc_set_ops);
+
+void usbmisc_unset_ops(const struct usbmisc_ops *ops)
+{
+	usbmisc_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(usbmisc_unset_ops);
+
+int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
+{
+	struct device_node *np = dev->of_node;
+	struct of_phandle_args args;
+	int ret;
+
+	usbdev->dev = dev;
+
+	ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
+					0, &args);
+	if (ret) {
+		dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
+			ret);
+		memset(usbdev, 0, sizeof(*usbdev));
+		return ret;
+	}
+	usbdev->index = args.args[0];
+	of_node_put(args.np);
+
+	if (of_find_property(np, "disable-over-current", NULL))
+		usbdev->disable_oc = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
+
+/* End of common functions shared by usbmisc drivers*/
+
 static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata  = {
 	.name			= "ci13xxx_imx",
 	.flags			= CI13XXX_REQUIRE_TRANSCEIVER |
@@ -49,8 +100,13 @@
 	struct device_node *phy_np;
 	struct resource *res;
 	struct regulator *reg_vbus;
+	struct pinctrl *pinctrl;
 	int ret;
 
+	if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
+		&& !usbmisc_ops)
+		return -EPROBE_DEFER;
+
 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
@@ -63,6 +119,11 @@
 		return -ENOENT;
 	}
 
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n",
+			PTR_ERR(pinctrl));
+
 	data->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(data->clk)) {
 		dev_err(&pdev->dev,
@@ -120,6 +181,16 @@
 		*pdev->dev.dma_mask = DMA_BIT_MASK(32);
 		dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask);
 	}
+
+	if (usbmisc_ops && usbmisc_ops->init) {
+		ret = usbmisc_ops->init(&pdev->dev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"usbmisc init failed, ret=%d\n", ret);
+			goto err;
+		}
+	}
+
 	plat_ci = ci13xxx_add_device(&pdev->dev,
 				pdev->resource, pdev->num_resources,
 				&ci13xxx_imx_platdata);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h
new file mode 100644
index 0000000..2e88acc
--- /dev/null
+++ b/drivers/usb/chipidea/ci13xxx_imx.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* Used to set SoC specific callbacks */
+struct usbmisc_ops {
+	/* It's called once when probe a usb device */
+	int (*init)(struct device *dev);
+};
+
+struct usbmisc_usb_device {
+	struct device *dev; /* usb controller device */
+	int index;
+
+	int disable_oc:1; /* over current detect disabled */
+};
+
+int usbmisc_set_ops(const struct usbmisc_ops *ops);
+void usbmisc_unset_ops(const struct usbmisc_ops *ops);
+int
+usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 1083585..f69d029 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -273,14 +273,13 @@
 	struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
 	enum ci_role role = ci_otg_role(ci);
 
-	hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
-
 	if (role != ci->role) {
 		dev_dbg(ci->dev, "switching from %s to %s\n",
 			ci_role(ci)->name, ci->roles[role]->name);
 
 		ci_role_stop(ci);
 		ci_role_start(ci, role);
+		enable_irq(ci->irq);
 	}
 }
 
@@ -320,17 +319,22 @@
 {
 	struct ci13xxx *ci = data;
 	irqreturn_t ret = IRQ_NONE;
+	u32 otgsc = 0;
 
-	if (ci->is_otg) {
-		u32 sts = hw_read(ci, OP_OTGSC, ~0);
+	if (ci->is_otg)
+		otgsc = hw_read(ci, OP_OTGSC, ~0);
 
-		if (sts & OTGSC_IDIS) {
-			queue_work(ci->wq, &ci->work);
-			ret = IRQ_HANDLED;
-		}
+	if (ci->role != CI_ROLE_END)
+		ret = ci_role(ci)->irq(ci);
+
+	if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
+		hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+		disable_irq_nosync(ci->irq);
+		queue_work(ci->wq, &ci->work);
+		ret = IRQ_HANDLED;
 	}
 
-	return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
+	return ret;
 }
 
 static DEFINE_IDA(ci_ida);
@@ -462,6 +466,8 @@
 
 	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
 		ci->is_otg = true;
+		/* ID pin needs 1ms debouce time, we delay 2ms for safe */
+		mdelay(2);
 		ci->role = ci_otg_role(ci);
 	} else {
 		ci->role = ci->roles[CI_ROLE_HOST]
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index d214448..2f45bba 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -305,6 +305,18 @@
 	return reg;
 }
 
+static void hw_enable_vbus_intr(struct ci13xxx *ci)
+{
+	hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
+	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
+	queue_work(ci->wq, &ci->vbus_work);
+}
+
+static void hw_disable_vbus_intr(struct ci13xxx *ci)
+{
+	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
+}
+
 /**
  * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
  *                                interruption)
@@ -371,6 +383,16 @@
 	return 0;
 }
 
+static void vbus_work(struct work_struct *work)
+{
+	struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
+
+	if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
+		usb_gadget_vbus_connect(&ci->gadget);
+	else
+		usb_gadget_vbus_disconnect(&ci->gadget);
+}
+
 /******************************************************************************
  * UTIL block
  *****************************************************************************/
@@ -1370,6 +1392,7 @@
 		if (is_active) {
 			pm_runtime_get_sync(&_gadget->dev);
 			hw_device_reset(ci, USBMODE_CM_DC);
+			hw_enable_vbus_intr(ci);
 			hw_device_state(ci, ci->ep0out->qh.dma);
 		} else {
 			hw_device_state(ci, 0);
@@ -1544,8 +1567,10 @@
 	pm_runtime_get_sync(&ci->gadget.dev);
 	if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
 		if (ci->vbus_active) {
-			if (ci->platdata->flags & CI13XXX_REGS_SHARED)
+			if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
 				hw_device_reset(ci, USBMODE_CM_DC);
+				hw_enable_vbus_intr(ci);
+			}
 		} else {
 			pm_runtime_put_sync(&ci->gadget.dev);
 			goto done;
@@ -1651,6 +1676,13 @@
 	} else {
 		retval = IRQ_NONE;
 	}
+
+	intr = hw_read(ci, OP_OTGSC, ~0);
+	hw_write(ci, OP_OTGSC, ~0, intr);
+
+	if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
+		queue_work(ci->wq, &ci->vbus_work);
+
 	spin_unlock(&ci->lock);
 
 	return retval;
@@ -1726,6 +1758,7 @@
 		retval = hw_device_reset(ci, USBMODE_CM_DC);
 		if (retval)
 			goto put_transceiver;
+		hw_enable_vbus_intr(ci);
 	}
 
 	retval = device_register(&ci->gadget.dev);
@@ -1788,6 +1821,9 @@
 	if (ci == NULL)
 		return;
 
+	hw_disable_vbus_intr(ci);
+	cancel_work_sync(&ci->vbus_work);
+
 	usb_del_gadget_udc(&ci->gadget);
 
 	destroy_eps(ci);
@@ -1828,6 +1864,7 @@
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
 	ci->roles[CI_ROLE_GADGET] = rdrv;
+	INIT_WORK(&ci->vbus_work, vbus_work);
 
 	return 0;
 }
diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c
new file mode 100644
index 0000000..416e3fc
--- /dev/null
+++ b/drivers/usb/chipidea/usbmisc_imx6q.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include "ci13xxx_imx.h"
+
+#define USB_DEV_MAX 4
+
+#define BM_OVER_CUR_DIS		BIT(7)
+
+struct imx6q_usbmisc {
+	void __iomem *base;
+	spinlock_t lock;
+	struct clk *clk;
+	struct usbmisc_usb_device usbdev[USB_DEV_MAX];
+};
+
+static struct imx6q_usbmisc *usbmisc;
+
+static struct usbmisc_usb_device *get_usbdev(struct device *dev)
+{
+	int i, ret;
+
+	for (i = 0; i < USB_DEV_MAX; i++) {
+		if (usbmisc->usbdev[i].dev == dev)
+			return &usbmisc->usbdev[i];
+		else if (!usbmisc->usbdev[i].dev)
+			break;
+	}
+
+	if (i >= USB_DEV_MAX)
+		return ERR_PTR(-EBUSY);
+
+	ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &usbmisc->usbdev[i];
+}
+
+static int usbmisc_imx6q_init(struct device *dev)
+{
+
+	struct usbmisc_usb_device *usbdev;
+	unsigned long flags;
+	u32 reg;
+
+	usbdev = get_usbdev(dev);
+	if (IS_ERR(usbdev))
+		return PTR_ERR(usbdev);
+
+	if (usbdev->disable_oc) {
+		spin_lock_irqsave(&usbmisc->lock, flags);
+		reg = readl(usbmisc->base + usbdev->index * 4);
+		writel(reg | BM_OVER_CUR_DIS,
+			usbmisc->base + usbdev->index * 4);
+		spin_unlock_irqrestore(&usbmisc->lock, flags);
+	}
+
+	return 0;
+}
+
+static const struct usbmisc_ops imx6q_usbmisc_ops = {
+	.init = usbmisc_imx6q_init,
+};
+
+static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-usbmisc"},
+	{ /* sentinel */ }
+};
+
+static int __devinit usbmisc_imx6q_probe(struct platform_device *pdev)
+{
+	struct resource	*res;
+	struct imx6q_usbmisc *data;
+	int ret;
+
+	if (usbmisc)
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	spin_lock_init(&data->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!data->base)
+		return -EADDRNOTAVAIL;
+
+	data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev,
+			"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
+		return PTR_ERR(data->clk);
+	}
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"clk_prepare_enable failed, err=%d\n", ret);
+		return ret;
+	}
+
+	ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
+	if (ret) {
+		clk_disable_unprepare(data->clk);
+		return ret;
+	}
+
+	usbmisc = data;
+
+	return 0;
+}
+
+static int __devexit usbmisc_imx6q_remove(struct platform_device *pdev)
+{
+	usbmisc_unset_ops(&imx6q_usbmisc_ops);
+	clk_disable_unprepare(usbmisc->clk);
+	return 0;
+}
+
+static struct platform_driver usbmisc_imx6q_driver = {
+	.probe = usbmisc_imx6q_probe,
+	.remove = __devexit_p(usbmisc_imx6q_remove),
+	.driver = {
+		.name = "usbmisc_imx6q",
+		.owner = THIS_MODULE,
+		.of_match_table = usbmisc_imx6q_dt_ids,
+	 },
+};
+
+int __init usbmisc_imx6q_drv_init(void)
+{
+	return platform_driver_register(&usbmisc_imx6q_driver);
+}
+subsys_initcall(usbmisc_imx6q_drv_init);
+
+void __exit usbmisc_imx6q_drv_exit(void)
+{
+	platform_driver_unregister(&usbmisc_imx6q_driver);
+}
+module_exit(usbmisc_imx6q_drv_exit);
+
+MODULE_ALIAS("platform:usbmisc-imx6q");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ff7b5a8..36f2be4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -39,7 +39,6 @@
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/serial.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 9981984..f70c1a1 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -56,7 +56,7 @@
 
 config USB_OTG
 	bool "OTG support"
-	depends on USB && EXPERIMENTAL
+	depends on USB
 	depends on USB_SUSPEND
 	default n
 	help
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index f4bdd0c..7199adc 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -702,6 +702,8 @@
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
 			    "descriptor/%s: %d\n", cfgno, "start", result);
+			if (result != -EPIPE)
+				goto err;
 			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index d956965..f460de3 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -496,6 +496,7 @@
 	char *pages_start, *data_end, *speed;
 	unsigned int length;
 	ssize_t total_written = 0;
+	struct usb_device *childdev = NULL;
 
 	/* don't bother with anything else if we're not writing any data */
 	if (*nbytes <= 0)
@@ -589,14 +590,12 @@
 	free_pages((unsigned long)pages_start, 1);
 
 	/* Now look at all of this device's children. */
-	for (chix = 0; chix < usbdev->maxchild; chix++) {
-		struct usb_device *childdev = usbdev->children[chix];
-
+	usb_hub_for_each_child(usbdev, chix, childdev) {
 		if (childdev) {
 			usb_lock_device(childdev);
 			ret = usb_device_dump(buffer, nbytes, skip_bytes,
 					      file_offset, childdev, bus,
-					      level + 1, chix, ++cnt);
+					      level + 1, chix - 1, ++cnt);
 			usb_unlock_device(childdev);
 			if (ret == -EFAULT)
 				return total_written;
@@ -624,7 +623,7 @@
 	/* print devices for all busses */
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 		/* recurse through all children of the root hub */
-		if (!bus->root_hub)
+		if (!bus_to_hcd(bus)->rh_registered)
 			continue;
 		usb_lock_device(bus->root_hub);
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index ebb8a9d..e0356cb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1928,6 +1928,38 @@
 	return 0;
 }
 
+static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
+{
+	struct usbdevfs_disconnect_claim dc;
+	struct usb_interface *intf;
+
+	if (copy_from_user(&dc, arg, sizeof(dc)))
+		return -EFAULT;
+
+	intf = usb_ifnum_to_if(ps->dev, dc.interface);
+	if (!intf)
+		return -EINVAL;
+
+	if (intf->dev.driver) {
+		struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
+				strncmp(dc.driver, intf->dev.driver->name,
+					sizeof(dc.driver)) != 0)
+			return -EBUSY;
+
+		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
+				strncmp(dc.driver, intf->dev.driver->name,
+					sizeof(dc.driver)) == 0)
+			return -EBUSY;
+
+		dev_dbg(&intf->dev, "disconnect by usbfs\n");
+		usb_driver_release_interface(driver, intf);
+	}
+
+	return claimintf(ps, dc.interface);
+}
+
 /*
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
@@ -2101,6 +2133,9 @@
 	case USBDEVFS_GET_CAPABILITIES:
 		ret = proc_get_capabilities(ps, p);
 		break;
+	case USBDEVFS_DISCONNECT_CLAIM:
+		ret = proc_disconnect_claim(ps, p);
+		break;
 	}
 	usb_unlock_device(dev);
 	if (ret >= 0)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 445455a..ddd820d 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -125,10 +125,9 @@
 {
 	struct usb_dynid *dynid, *n;
 	struct usb_driver *usb_driver = to_usb_driver(driver);
-	u32 idVendor = 0;
-	u32 idProduct = 0;
-	int fields = 0;
-	int retval = 0;
+	u32 idVendor;
+	u32 idProduct;
+	int fields;
 
 	fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
 	if (fields < 2)
@@ -141,14 +140,10 @@
 		    (id->idProduct == idProduct)) {
 			list_del(&dynid->node);
 			kfree(dynid);
-			retval = 0;
 			break;
 		}
 	}
 	spin_unlock(&usb_driver->dynids.lock);
-
-	if (retval)
-		return retval;
 	return count;
 }
 static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index db7fe50..68cc653 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -24,10 +24,6 @@
 #define to_ep_device(_dev) \
 	container_of(_dev, struct ep_device, dev)
 
-struct device_type usb_ep_device_type = {
-	.name =		"usb_endpoint",
-};
-
 struct ep_attribute {
 	struct attribute attr;
 	ssize_t (*show)(struct usb_device *,
@@ -172,6 +168,11 @@
 	kfree(ep_dev);
 }
 
+struct device_type usb_ep_device_type = {
+	.name =		"usb_endpoint",
+	.release = ep_device_release,
+};
+
 int usb_create_ep_devs(struct device *parent,
 			struct usb_host_endpoint *endpoint,
 			struct usb_device *udev)
@@ -190,7 +191,6 @@
 	ep_dev->dev.groups = ep_dev_groups;
 	ep_dev->dev.type = &usb_ep_device_type;
 	ep_dev->dev.parent = parent;
-	ep_dev->dev.release = ep_device_release;
 	dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
 
 	retval = device_register(&ep_dev->dev);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index bc84106..1e741bc 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -22,6 +22,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/bcd.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -123,9 +124,8 @@
  */
 
 /*-------------------------------------------------------------------------*/
-
-#define KERNEL_REL	((LINUX_VERSION_CODE >> 16) & 0x0ff)
-#define KERNEL_VER	((LINUX_VERSION_CODE >> 8) & 0x0ff)
+#define KERNEL_REL	bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
+#define KERNEL_VER	bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
 
 /* usb 3.0 root hub device descriptor */
 static const u8 usb3_rh_dev_descriptor[18] = {
@@ -1011,10 +1011,7 @@
 	if (retval) {
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				dev_name(&usb_dev->dev), retval);
-	}
-	mutex_unlock(&usb_bus_list_lock);
-
-	if (retval == 0) {
+	} else {
 		spin_lock_irq (&hcd_root_hub_lock);
 		hcd->rh_registered = 1;
 		spin_unlock_irq (&hcd_root_hub_lock);
@@ -1023,6 +1020,7 @@
 		if (HCD_DEAD(hcd))
 			usb_hc_died (hcd);	/* This time clean up */
 	}
+	mutex_unlock(&usb_bus_list_lock);
 
 	return retval;
 }
@@ -2153,15 +2151,8 @@
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
 	struct usb_hcd		*hcd = __hcd;
-	unsigned long		flags;
 	irqreturn_t		rc;
 
-	/* 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);
-
 	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
 		rc = IRQ_NONE;
 	else if (hcd->driver->irq(hcd) == IRQ_NONE)
@@ -2169,7 +2160,6 @@
 	else
 		rc = IRQ_HANDLED;
 
-	local_irq_restore(flags);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_irq);
@@ -2357,14 +2347,6 @@
 	int retval;
 
 	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.
-		 */
-		if (irqflags & IRQF_SHARED)
-			irqflags &= ~IRQF_DISABLED;
-
 		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
 				hcd->driver->description, hcd->self.busnum);
 		retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 128a804..673ee46 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -39,6 +39,13 @@
 #endif
 #endif
 
+struct usb_port {
+	struct usb_device *child;
+	struct device dev;
+	struct dev_state *port_owner;
+	enum usb_port_connect_type connect_type;
+};
+
 struct usb_hub {
 	struct device		*intfdev;	/* the "interface" device */
 	struct usb_device	*hdev;
@@ -83,7 +90,7 @@
 	u8			indicator[USB_MAXCHILDREN];
 	struct delayed_work	leds;
 	struct delayed_work	init_work;
-	struct dev_state	**port_owners;
+	struct usb_port		**ports;
 };
 
 static inline int hub_is_superspeed(struct usb_device *hdev)
@@ -156,6 +163,8 @@
 #define HUB_DEBOUNCE_STEP	  25
 #define HUB_DEBOUNCE_STABLE	 100
 
+#define to_usb_port(_dev) \
+	container_of(_dev, struct usb_port, dev)
 
 static int usb_reset_and_verify_device(struct usb_device *udev);
 
@@ -174,7 +183,7 @@
 /* Note that hdev or one of its children must be locked! */
 static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
 {
-	if (!hdev || !hdev->actconfig)
+	if (!hdev || !hdev->actconfig || !hdev->maxchild)
 		return NULL;
 	return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
@@ -869,8 +878,8 @@
 	struct usb_device *hdev = hub->hdev;
 	int ret = 0;
 
-	if (hdev->children[port1-1] && set_state)
-		usb_set_device_state(hdev->children[port1-1],
+	if (hub->ports[port1 - 1]->child && set_state)
+		usb_set_device_state(hub->ports[port1 - 1]->child,
 				USB_STATE_NOTATTACHED);
 	if (!hub->error && !hub_is_superspeed(hub->hdev))
 		ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
@@ -1026,7 +1035,7 @@
 	 * which ports need attention.
 	 */
 	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-		struct usb_device *udev = hdev->children[port1-1];
+		struct usb_device *udev = hub->ports[port1 - 1]->child;
 		u16 portstatus, portchange;
 
 		portstatus = portchange = 0;
@@ -1191,8 +1200,8 @@
 	if (type != HUB_SUSPEND) {
 		/* Disconnect all the children */
 		for (i = 0; i < hdev->maxchild; ++i) {
-			if (hdev->children[i])
-				usb_disconnect(&hdev->children[i]);
+			if (hub->ports[i]->child)
+				usb_disconnect(&hub->ports[i]->child);
 		}
 	}
 
@@ -1222,6 +1231,52 @@
 	return 0;
 }
 
+static void usb_port_device_release(struct device *dev)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+
+	kfree(port_dev);
+}
+
+static void usb_hub_remove_port_device(struct usb_hub *hub,
+				       int port1)
+{
+	device_unregister(&hub->ports[port1 - 1]->dev);
+}
+
+struct device_type usb_port_device_type = {
+	.name =		"usb_port",
+	.release =	usb_port_device_release,
+};
+
+static int usb_hub_create_port_device(struct usb_hub *hub,
+				      int port1)
+{
+	struct usb_port *port_dev = NULL;
+	int retval;
+
+	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
+	if (!port_dev) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	hub->ports[port1 - 1] = port_dev;
+	port_dev->dev.parent = hub->intfdev;
+	port_dev->dev.type = &usb_port_device_type;
+	dev_set_name(&port_dev->dev, "port%d", port1);
+
+	retval = device_register(&port_dev->dev);
+	if (retval)
+		goto error_register;
+	return 0;
+
+error_register:
+	put_device(&port_dev->dev);
+exit:
+	return retval;
+}
+
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
@@ -1231,7 +1286,7 @@
 	u16 hubstatus, hubchange;
 	u16 wHubCharacteristics;
 	unsigned int pipe;
-	int maxp, ret;
+	int maxp, ret, i;
 	char *message = "out of memory";
 
 	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
@@ -1271,11 +1326,9 @@
 	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
 		(hdev->maxchild == 1) ? "" : "s");
 
-	hdev->children = kzalloc(hdev->maxchild *
-				sizeof(struct usb_device *), GFP_KERNEL);
-	hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *),
-				GFP_KERNEL);
-	if (!hdev->children || !hub->port_owners) {
+	hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *),
+			     GFP_KERNEL);
+	if (!hub->ports) {
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -1484,6 +1537,11 @@
 	if (hub->has_indicators && blinkenlights)
 		hub->indicator [0] = INDICATOR_CYCLE;
 
+	for (i = 0; i < hdev->maxchild; i++)
+		if (usb_hub_create_port_device(hub, i + 1) < 0)
+			dev_err(hub->intfdev,
+				"couldn't create port%d device.\n", i + 1);
+
 	hub_activate(hub, HUB_INIT);
 	return 0;
 
@@ -1508,6 +1566,7 @@
 {
 	struct usb_hub *hub = usb_get_intfdata(intf);
 	struct usb_device *hdev = interface_to_usbdev(intf);
+	int i;
 
 	/* Take the hub off the event list and don't let it be added again */
 	spin_lock_irq(&hub_event_lock);
@@ -1523,14 +1582,16 @@
 	hub_quiesce(hub, HUB_DISCONNECT);
 
 	usb_set_intfdata (intf, NULL);
+
+	for (i = 0; i < hdev->maxchild; i++)
+		usb_hub_remove_port_device(hub, i + 1);
 	hub->hdev->maxchild = 0;
 
 	if (hub->hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs--;
 
 	usb_free_urb(hub->urb);
-	kfree(hdev->children);
-	kfree(hub->port_owners);
+	kfree(hub->ports);
 	kfree(hub->descriptor);
 	kfree(hub->status);
 	kfree(hub->buffer);
@@ -1617,6 +1678,7 @@
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
 	struct usb_device *hdev = interface_to_usbdev (intf);
+	struct usb_hub *hub = hdev_to_hub(hdev);
 
 	/* assert ifno == 0 (part of hub spec) */
 	switch (code) {
@@ -1630,11 +1692,11 @@
 		else {
 			info->nports = hdev->maxchild;
 			for (i = 0; i < info->nports; i++) {
-				if (hdev->children[i] == NULL)
+				if (hub->ports[i]->child == NULL)
 					info->port[i] = 0;
 				else
 					info->port[i] =
-						hdev->children[i]->devnum;
+						hub->ports[i]->child->devnum;
 			}
 		}
 		spin_unlock_irq(&device_state_lock);
@@ -1662,7 +1724,7 @@
 	/* This assumes that devices not managed by the hub driver
 	 * will always have maxchild equal to 0.
 	 */
-	*ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
+	*ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner);
 	return 0;
 }
 
@@ -1699,16 +1761,14 @@
 
 void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
 {
+	struct usb_hub *hub = hdev_to_hub(hdev);
 	int n;
-	struct dev_state **powner;
 
-	n = find_port_owner(hdev, 1, &powner);
-	if (n == 0) {
-		for (; n < hdev->maxchild; (++n, ++powner)) {
-			if (*powner == owner)
-				*powner = NULL;
-		}
+	for (n = 0; n < hdev->maxchild; n++) {
+		if (hub->ports[n]->port_owner == owner)
+			hub->ports[n]->port_owner = NULL;
 	}
+
 }
 
 /* The caller must hold udev's lock */
@@ -1719,17 +1779,17 @@
 	if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
 		return false;
 	hub = hdev_to_hub(udev->parent);
-	return !!hub->port_owners[udev->portnum - 1];
+	return !!hub->ports[udev->portnum - 1]->port_owner;
 }
 
-
 static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 {
+	struct usb_hub *hub = hdev_to_hub(udev);
 	int i;
 
 	for (i = 0; i < udev->maxchild; ++i) {
-		if (udev->children[i])
-			recursively_mark_NOTATTACHED(udev->children[i]);
+		if (hub->ports[i]->child)
+			recursively_mark_NOTATTACHED(hub->ports[i]->child);
 	}
 	if (udev->state == USB_STATE_SUSPENDED)
 		udev->active_duration -= jiffies;
@@ -1893,6 +1953,7 @@
 void usb_disconnect(struct usb_device **pdev)
 {
 	struct usb_device	*udev = *pdev;
+	struct usb_hub		*hub = hdev_to_hub(udev);
 	int			i;
 
 	/* mark the device as inactive, so any further urb submissions for
@@ -1907,8 +1968,8 @@
 
 	/* Free up all the children before we remove this device */
 	for (i = 0; i < udev->maxchild; i++) {
-		if (udev->children[i])
-			usb_disconnect(&udev->children[i]);
+		if (hub->ports[i]->child)
+			usb_disconnect(&hub->ports[i]->child);
 	}
 
 	/* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -2113,7 +2174,8 @@
 		return;
 
 	if (hub_is_superspeed(hdev)) {
-		if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+		if (le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable)
+				& (1 << port))
 			removable = false;
 	} else {
 		if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
@@ -3072,7 +3134,7 @@
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
 
-		udev = hdev->children [port1-1];
+		udev = hub->ports[port1 - 1]->child;
 		if (udev && udev->can_submit) {
 			dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
 			if (PMSG_IS_AUTO(msg))
@@ -3999,7 +4061,7 @@
 
 	remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
 	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-		struct usb_device	*udev = hdev->children[port1 - 1];
+		struct usb_device	*udev = hub->ports[port1 - 1]->child;
 		int			delta;
 
 		if (!udev)
@@ -4063,7 +4125,7 @@
 #endif
 
 	/* Try to resuscitate an existing device */
-	udev = hdev->children[port1-1];
+	udev = hub->ports[port1 - 1]->child;
 	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
 			udev->state != USB_STATE_NOTATTACHED) {
 		usb_lock_device(udev);
@@ -4092,7 +4154,7 @@
 
 	/* Disconnect any existing devices under this port */
 	if (udev)
-		usb_disconnect(&hdev->children[port1-1]);
+		usb_disconnect(&hub->ports[port1 - 1]->child);
 	clear_bit(port1, hub->change_bits);
 
 	/* We can forget about a "removed" device when there's a physical
@@ -4228,7 +4290,7 @@
 		if (hdev->state == USB_STATE_NOTATTACHED)
 			status = -ENOTCONN;
 		else
-			hdev->children[port1-1] = udev;
+			hub->ports[port1 - 1]->child = udev;
 		spin_unlock_irq(&device_state_lock);
 
 		/* Run it through the hoops (find a driver, etc) */
@@ -4236,7 +4298,7 @@
 			status = usb_new_device(udev);
 			if (status) {
 				spin_lock_irq(&device_state_lock);
-				hdev->children[port1-1] = NULL;
+				hub->ports[port1 - 1]->child = NULL;
 				spin_unlock_irq(&device_state_lock);
 			}
 		}
@@ -4282,7 +4344,7 @@
 	int ret;
 
 	hdev = hub->hdev;
-	udev = hdev->children[port-1];
+	udev = hub->ports[port - 1]->child;
 	if (!hub_is_superspeed(hdev)) {
 		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
 			return 0;
@@ -4436,7 +4498,7 @@
 				 */
 				if (!(portstatus & USB_PORT_STAT_ENABLE)
 				    && !connect_change
-				    && hdev->children[i-1]) {
+				    && hub->ports[i - 1]->child) {
 					dev_err (hub_dev,
 					    "port %i "
 					    "disabled by hub (EMI?), "
@@ -4993,3 +5055,75 @@
 	schedule_work(&iface->reset_ws);
 }
 EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+/**
+ * usb_hub_find_child - Get the pointer of child device
+ * attached to the port which is specified by @port1.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num to indicate which port the child device
+ *	is attached to.
+ *
+ * USB drivers call this function to get hub's child device
+ * pointer.
+ *
+ * Return NULL if input param is invalid and
+ * child's usb_device pointer if non-NULL.
+ */
+struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+		int port1)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	if (port1 < 1 || port1 > hdev->maxchild)
+		return NULL;
+	return hub->ports[port1 - 1]->child;
+}
+EXPORT_SYMBOL_GPL(usb_hub_find_child);
+
+/**
+ * usb_set_hub_port_connect_type - set hub port connect type.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ * @type: connect type of the port
+ */
+void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
+	enum usb_port_connect_type type)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	hub->ports[port1 - 1]->connect_type = type;
+}
+
+/**
+ * usb_get_hub_port_connect_type - Get the port's connect type
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ *
+ * Return connect type of the port and if input params are
+ * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
+ */
+enum usb_port_connect_type
+usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	return hub->ports[port1 - 1]->connect_type;
+}
+
+#ifdef CONFIG_ACPI
+/**
+ * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ *
+ * Return port's acpi handle if successful, NULL if params are
+ * invaild.
+ */
+acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+	int port1)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
+}
+#endif
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 0ab7da2..1ed5afd 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -146,8 +146,6 @@
 	dr->wIndex = cpu_to_le16(index);
 	dr->wLength = cpu_to_le16(size);
 
-	/* dbg("usb_control_msg"); */
-
 	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
 	kfree(dr);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index e77a8e8..fdefd9c 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -209,7 +209,7 @@
 	 * for all devices.  It will affect things like hub resets
 	 * and EMF-related port disables.
 	 */
-	if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+	if (!(udev->quirks & USB_QUIRK_RESET))
 		udev->persist_enabled = 1;
 #endif	/* CONFIG_PM */
 }
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 682e825..818e4a0 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -196,7 +196,7 @@
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
-	return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS));
+	return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
 }
 
 static ssize_t
@@ -204,15 +204,15 @@
 		const char *buf, size_t count)
 {
 	struct usb_device	*udev = to_usb_device(dev);
-	int			config;
+	int			val;
 
-	if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+	if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
 		return -EINVAL;
 	usb_lock_device(udev);
-	if (config)
-		udev->quirks |= USB_QUIRK_RESET_MORPHS;
+	if (val)
+		udev->quirks |= USB_QUIRK_RESET;
 	else
-		udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
+		udev->quirks &= ~USB_QUIRK_RESET;
 	usb_unlock_device(udev);
 	return count;
 }
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 8947b20..0ef7d42 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -19,20 +19,91 @@
 
 #include "usb.h"
 
-static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
+/**
+ * usb_acpi_power_manageable - check whether usb port has
+ * acpi power resource.
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ *
+ * Return true if the port has acpi power resource and false if no.
+ */
+bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
+{
+	acpi_handle port_handle;
+	int port1 = index + 1;
+
+	port_handle = usb_get_hub_port_acpi_handle(hdev,
+		port1);
+	if (port_handle)
+		return acpi_bus_power_manageable(port_handle);
+	else
+		return false;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
+
+/**
+ * usb_acpi_set_power_state - control usb port's power via acpi power
+ * resource
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ * @enable: power state expected to be set
+ *
+ * Notice to use usb_acpi_power_manageable() to check whether the usb port
+ * has acpi power resource before invoking this function.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
+{
+	acpi_handle port_handle;
+	unsigned char state;
+	int port1 = index + 1;
+	int error = -EINVAL;
+
+	port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev,
+		port1);
+	if (!port_handle)
+		return error;
+
+	if (enable)
+		state = ACPI_STATE_D0;
+	else
+		state = ACPI_STATE_D3_COLD;
+
+	error = acpi_bus_set_power(port_handle, state);
+	if (!error)
+		dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n",
+			port1, enable);
+	else
+		dev_dbg(&hdev->dev, "The power of hub port failed to be set\n");
+
+	return error;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
+
+static int usb_acpi_check_port_connect_type(struct usb_device *hdev,
+	acpi_handle handle, int port1)
 {
 	acpi_status status;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *upc;
+	struct acpi_pld pld;
 	int ret = 0;
 
-	status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
-
+	/*
+	 * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is
+	 * user visible and _UPC indicates whether it is connectable. If
+	 * the port was visible and connectable, it could be freely connected
+	 * and disconnected with USB devices. If no visible and connectable,
+	 * a usb device is directly hard-wired to the port. If no visible and
+	 * no connectable, the port would be not used.
+	 */
+	status = acpi_get_physical_device_location(handle, &pld);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
+	status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
 	upc = buffer.pointer;
-
 	if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
 		|| upc->package.count != 4) {
 		ret = -EINVAL;
@@ -40,69 +111,107 @@
 	}
 
 	if (upc->package.elements[0].integer.value)
-		udev->removable = USB_DEVICE_REMOVABLE;
-	else
-		udev->removable = USB_DEVICE_FIXED;
+		if (pld.user_visible)
+			usb_set_hub_port_connect_type(hdev, port1,
+				USB_PORT_CONNECT_TYPE_HOT_PLUG);
+		else
+			usb_set_hub_port_connect_type(hdev, port1,
+				USB_PORT_CONNECT_TYPE_HARD_WIRED);
+	else if (!pld.user_visible)
+		usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED);
 
 out:
 	kfree(upc);
 	return ret;
 }
 
-static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle)
-{
-	acpi_status status;
-	struct acpi_pld pld;
-
-	status = acpi_get_physical_device_location(handle, &pld);
-
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-
-	if (pld.user_visible)
-		udev->removable = USB_DEVICE_REMOVABLE;
-	else
-		udev->removable = USB_DEVICE_FIXED;
-
-	return 0;
-}
-
 static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
 {
 	struct usb_device *udev;
-	struct device *parent;
 	acpi_handle *parent_handle;
-
-	if (!is_usb_device(dev))
-		return -ENODEV;
-
-	udev = to_usb_device(dev);
-	parent = dev->parent;
-	parent_handle = DEVICE_ACPI_HANDLE(parent);
-
-	if (!parent_handle)
-		return -ENODEV;
-
-	*handle = acpi_get_child(parent_handle, udev->portnum);
-
-	if (!*handle)
-		return -ENODEV;
+	int port_num;
 
 	/*
-	 * PLD will tell us whether a port is removable to the user or
-	 * not. If we don't get an answer from PLD (it's not present
-	 * or it's malformed) then try to infer it from UPC. If a
-	 * device isn't connectable then it's probably not removable.
+	 * In the ACPI DSDT table, only usb root hub and usb ports are
+	 * acpi device nodes. The hierarchy like following.
+	 * Device (EHC1)
+	 *	Device (HUBN)
+	 *		Device (PR01)
+	 *			Device (PR11)
+	 *			Device (PR12)
+	 *			Device (PR13)
+	 *			...
+	 * So all binding process is divided into two parts. binding
+	 * root hub and usb ports.
 	 */
-	if (usb_acpi_check_pld(udev, *handle) != 0)
-		usb_acpi_check_upc(udev, *handle);
+	if (is_usb_device(dev)) {
+		udev = to_usb_device(dev);
+		if (udev->parent) {
+			enum usb_port_connect_type type;
+
+			/*
+			 * According usb port's connect type to set usb device's
+			 * removability.
+			 */
+			type = usb_get_hub_port_connect_type(udev->parent,
+				udev->portnum);
+			switch (type) {
+			case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+				udev->removable = USB_DEVICE_REMOVABLE;
+				break;
+			case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+				udev->removable = USB_DEVICE_FIXED;
+				break;
+			default:
+				udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN;
+				break;
+			}
+
+			return -ENODEV;
+		}
+
+		/* root hub's parent is the usb hcd. */
+		parent_handle = DEVICE_ACPI_HANDLE(dev->parent);
+		*handle = acpi_get_child(parent_handle, udev->portnum);
+		if (!*handle)
+			return -ENODEV;
+		return 0;
+	} else if (is_usb_port(dev)) {
+		sscanf(dev_name(dev), "port%d", &port_num);
+		/* Get the struct usb_device point of port's hub */
+		udev = to_usb_device(dev->parent->parent);
+
+		/*
+		 * The root hub ports' parent is the root hub. The non-root-hub
+		 * ports' parent is the parent hub port which the hub is
+		 * connected to.
+		 */
+		if (!udev->parent) {
+			*handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+				port_num);
+			if (!*handle)
+				return -ENODEV;
+		} else {
+			parent_handle =
+				usb_get_hub_port_acpi_handle(udev->parent,
+				udev->portnum);
+			if (!parent_handle)
+				return -ENODEV;
+
+			*handle = acpi_get_child(parent_handle,	port_num);
+			if (!*handle)
+				return -ENODEV;
+		}
+		usb_acpi_check_port_connect_type(udev, *handle, port_num);
+	} else
+		return -ENODEV;
 
 	return 0;
 }
 
 static struct acpi_bus_type usb_acpi_bus = {
 	.bus = &usb_bus_type,
-	.find_bridge = NULL,
+	.find_bridge = usb_acpi_find_device,
 	.find_device = usb_acpi_find_device,
 };
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index acb103c..1c528c1 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,4 +1,5 @@
 #include <linux/pm.h>
+#include <linux/acpi.h>
 
 struct dev_state;
 
@@ -115,6 +116,7 @@
 extern struct device_type usb_device_type;
 extern struct device_type usb_if_device_type;
 extern struct device_type usb_ep_device_type;
+extern struct device_type usb_port_device_type;
 extern struct usb_device_driver usb_generic_driver;
 
 static inline int is_usb_device(const struct device *dev)
@@ -132,6 +134,11 @@
 	return dev->type == &usb_ep_device_type;
 }
 
+static inline int is_usb_port(const struct device *dev)
+{
+	return dev->type == &usb_port_device_type;
+}
+
 /* Do the same for device drivers and interface drivers. */
 
 static inline int is_usb_device_driver(struct device_driver *drv)
@@ -162,10 +169,16 @@
 extern void usb_notify_remove_device(struct usb_device *udev);
 extern void usb_notify_add_bus(struct usb_bus *ubus);
 extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern enum usb_port_connect_type
+	usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
+extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
+	enum usb_port_connect_type type);
 
 #ifdef CONFIG_ACPI
 extern int usb_acpi_register(void);
 extern void usb_acpi_unregister(void);
+extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+	int port1);
 #else
 static inline int usb_acpi_register(void) { return 0; };
 static inline void usb_acpi_unregister(void) { };
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d13c60f4..f6a6e07 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -2,8 +2,6 @@
 	tristate "DesignWare USB3 DRD Core Support"
 	depends on (USB && USB_GADGET)
 	select USB_OTG_UTILS
-	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SUPERSPEED
 	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a68ff53..b415c0c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -50,6 +50,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
 
+#include <linux/usb/otg.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -99,6 +100,7 @@
 
 	ret = test_bit(id, dwc3_devs);
 	WARN(!ret, "dwc3: ID %d not in use\n", id);
+	smp_mb__before_clear_bit();
 	clear_bit(id, dwc3_devs);
 }
 EXPORT_SYMBOL_GPL(dwc3_put_device_id);
@@ -136,6 +138,8 @@
 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
+	usb_phy_init(dwc->usb2_phy);
+	usb_phy_init(dwc->usb3_phy);
 	mdelay(100);
 
 	/* Clear USB3 PHY reset */
@@ -464,12 +468,24 @@
 		return -ENOMEM;
 	}
 
-	regs = devm_ioremap(dev, res->start, resource_size(res));
+	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
 	if (!regs) {
 		dev_err(dev, "ioremap failed\n");
 		return -ENOMEM;
 	}
 
+	dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
+		dev_err(dev, "no usb2 phy configured\n");
+		return -EPROBE_DEFER;
+	}
+
+	dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
+		dev_err(dev, "no usb3 phy configured\n");
+		return -EPROBE_DEFER;
+	}
+
 	spin_lock_init(&dwc->lock);
 	platform_set_drvdata(pdev, dwc);
 
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 151eca8..243affc 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -457,7 +457,6 @@
 enum dwc3_ep0_next {
 	DWC3_EP0_UNKNOWN = 0,
 	DWC3_EP0_COMPLETE,
-	DWC3_EP0_NRDY_SETUP,
 	DWC3_EP0_NRDY_DATA,
 	DWC3_EP0_NRDY_STATUS,
 };
@@ -624,6 +623,8 @@
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
  * @mode: mode of operation
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
  * @is_selfpowered: true when we are selfpowered
  * @three_stage_setup: set if we perform a three phase setup
  * @ep0_bounced: true when we used bounce buffer
@@ -667,6 +668,9 @@
 	struct usb_gadget	gadget;
 	struct usb_gadget_driver *gadget_driver;
 
+	struct usb_phy		*usb2_phy;
+	struct usb_phy		*usb3_phy;
+
 	void __iomem		*regs;
 	size_t			regs_size;
 
@@ -779,7 +783,6 @@
 #define DEPEVT_STREAMEVT_NOTFOUND	2
 
 /* Control-only Status */
-#define DEPEVT_STATUS_CONTROL_SETUP	0
 #define DEPEVT_STATUS_CONTROL_DATA	1
 #define DEPEVT_STATUS_CONTROL_STATUS	2
 
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index b8f0038..ca65978 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -19,16 +19,74 @@
 #include <linux/platform_data/dwc3-exynos.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include "core.h"
 
 struct dwc3_exynos {
 	struct platform_device	*dwc3;
+	struct platform_device	*usb2_phy;
+	struct platform_device	*usb3_phy;
 	struct device		*dev;
 
 	struct clk		*clk;
 };
 
+static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
+{
+	struct nop_usb_xceiv_platform_data pdata;
+	struct platform_device	*pdev;
+	int			ret;
+
+	memset(&pdata, 0x00, sizeof(pdata));
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	if (!pdev)
+		return -ENOMEM;
+
+	exynos->usb2_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB2;
+
+	ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err1;
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	if (!pdev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	exynos->usb3_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB3;
+
+	ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(exynos->usb2_phy);
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(exynos->usb3_phy);
+	if (ret)
+		goto err3;
+
+	return 0;
+
+err3:
+	platform_device_del(exynos->usb2_phy);
+
+err2:
+	platform_device_put(exynos->usb3_phy);
+
+err1:
+	platform_device_put(exynos->usb2_phy);
+
+	return ret;
+}
+
 static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
 {
 	struct dwc3_exynos_data	*pdata = pdev->dev.platform_data;
@@ -51,6 +109,12 @@
 	if (devid < 0)
 		goto err1;
 
+	ret = dwc3_exynos_register_phys(exynos);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't register PHYs\n");
+		goto err1;
+	}
+
 	dwc3 = platform_device_alloc("dwc3", devid);
 	if (!dwc3) {
 		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
@@ -120,6 +184,8 @@
 	struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
 
 	platform_device_unregister(exynos->dwc3);
+	platform_device_unregister(exynos->usb2_phy);
+	platform_device_unregister(exynos->usb3_phy);
 
 	dwc3_put_device_id(exynos->dwc3->id);
 
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 479dc04..ee57a10 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -48,6 +48,9 @@
 #include <linux/io.h>
 #include <linux/of.h>
 
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
 #include "core.h"
 
 /*
@@ -131,6 +134,8 @@
 	spinlock_t		lock;
 
 	struct platform_device	*dwc3;
+	struct platform_device	*usb2_phy;
+	struct platform_device	*usb3_phy;
 	struct device		*dev;
 
 	int			irq;
@@ -152,6 +157,59 @@
 	writel(value, base + offset);
 }
 
+static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
+{
+	struct nop_usb_xceiv_platform_data pdata;
+	struct platform_device	*pdev;
+	int			ret;
+
+	memset(&pdata, 0x00, sizeof(pdata));
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	if (!pdev)
+		return -ENOMEM;
+
+	omap->usb2_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB2;
+
+	ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err1;
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	if (!pdev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	omap->usb3_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB3;
+
+	ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(omap->usb2_phy);
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(omap->usb3_phy);
+	if (ret)
+		goto err3;
+
+	return 0;
+
+err3:
+	platform_device_del(omap->usb2_phy);
+
+err2:
+	platform_device_put(omap->usb3_phy);
+
+err1:
+	platform_device_put(omap->usb2_phy);
+
+	return ret;
+}
 
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
@@ -251,6 +309,12 @@
 		return -ENOMEM;
 	}
 
+	ret = dwc3_omap_register_phys(omap);
+	if (ret) {
+		dev_err(dev, "couldn't register PHYs\n");
+		return ret;
+	}
+
 	devid = dwc3_get_device_id();
 	if (devid < 0)
 		return -ENODEV;
@@ -371,6 +435,8 @@
 	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
 
 	platform_device_unregister(omap->dwc3);
+	platform_device_unregister(omap->usb2_phy);
+	platform_device_unregister(omap->usb3_phy);
 
 	dwc3_put_device_id(omap->dwc3->id);
 
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index a9ca9ad..94f550e 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -42,6 +42,9 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
 #include "core.h"
 
 /* FIXME define these in <linux/pci_ids.h> */
@@ -51,8 +54,64 @@
 struct dwc3_pci {
 	struct device		*dev;
 	struct platform_device	*dwc3;
+	struct platform_device	*usb2_phy;
+	struct platform_device	*usb3_phy;
 };
 
+static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue)
+{
+	struct nop_usb_xceiv_platform_data pdata;
+	struct platform_device	*pdev;
+	int			ret;
+
+	memset(&pdata, 0x00, sizeof(pdata));
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	if (!pdev)
+		return -ENOMEM;
+
+	glue->usb2_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB2;
+
+	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err1;
+
+	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	if (!pdev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	glue->usb3_phy = pdev;
+	pdata.type = USB_PHY_TYPE_USB3;
+
+	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(glue->usb2_phy);
+	if (ret)
+		goto err2;
+
+	ret = platform_device_add(glue->usb3_phy);
+	if (ret)
+		goto err3;
+
+	return 0;
+
+err3:
+	platform_device_del(glue->usb2_phy);
+
+err2:
+	platform_device_put(glue->usb3_phy);
+
+err1:
+	platform_device_put(glue->usb2_phy);
+
+	return ret;
+}
+
 static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 		const struct pci_device_id *id)
 {
@@ -80,6 +139,12 @@
 	pci_set_power_state(pci, PCI_D0);
 	pci_set_master(pci);
 
+	ret = dwc3_pci_register_phys(glue);
+	if (ret) {
+		dev_err(dev, "couldn't register PHYs\n");
+		return ret;
+	}
+
 	devid = dwc3_get_device_id();
 	if (devid < 0) {
 		ret = -ENOMEM;
@@ -144,6 +209,8 @@
 {
 	struct dwc3_pci	*glue = pci_get_drvdata(pci);
 
+	platform_device_unregister(glue->usb2_phy);
+	platform_device_unregister(glue->usb3_phy);
 	dwc3_put_device_id(glue->dwc3->id);
 	platform_device_unregister(glue->dwc3);
 	pci_set_drvdata(pci, NULL);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index e4d5ca8..d7da073 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -125,7 +125,6 @@
 		struct dwc3_request *req)
 {
 	struct dwc3		*dwc = dep->dwc;
-	int			ret = 0;
 
 	req->request.actual	= 0;
 	req->request.status	= -EINPROGRESS;
@@ -156,16 +155,72 @@
 
 		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
 				DWC3_EP0_DIR_IN);
-	} else if (dwc->delayed_status) {
+
+		return 0;
+	}
+
+	/*
+	 * In case gadget driver asked us to delay the STATUS phase,
+	 * handle it here.
+	 */
+	if (dwc->delayed_status) {
+		unsigned	direction;
+
+		direction = !dwc->ep0_expect_in;
 		dwc->delayed_status = false;
 
 		if (dwc->ep0state == EP0_STATUS_PHASE)
-			__dwc3_ep0_do_control_status(dwc, dwc->eps[1]);
+			__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
 		else
 			dev_dbg(dwc->dev, "too early for delayed status\n");
+
+		return 0;
 	}
 
-	return ret;
+	/*
+	 * Unfortunately we have uncovered a limitation wrt the Data Phase.
+	 *
+	 * Section 9.4 says we can wait for the XferNotReady(DATA) event to
+	 * come before issueing Start Transfer command, but if we do, we will
+	 * miss situations where the host starts another SETUP phase instead of
+	 * the DATA phase.  Such cases happen at least on TD.7.6 of the Link
+	 * Layer Compliance Suite.
+	 *
+	 * The problem surfaces due to the fact that in case of back-to-back
+	 * SETUP packets there will be no XferNotReady(DATA) generated and we
+	 * will be stuck waiting for XferNotReady(DATA) forever.
+	 *
+	 * By looking at tables 9-13 and 9-14 of the Databook, we can see that
+	 * it tells us to start Data Phase right away. It also mentions that if
+	 * we receive a SETUP phase instead of the DATA phase, core will issue
+	 * XferComplete for the DATA phase, before actually initiating it in
+	 * the wire, with the TRB's status set to "SETUP_PENDING". Such status
+	 * can only be used to print some debugging logs, as the core expects
+	 * us to go through to the STATUS phase and start a CONTROL_STATUS TRB,
+	 * just so it completes right away, without transferring anything and,
+	 * only then, we can go back to the SETUP phase.
+	 *
+	 * Because of this scenario, SNPS decided to change the programming
+	 * model of control transfers and support on-demand transfers only for
+	 * the STATUS phase. To fix the issue we have now, we will always wait
+	 * for gadget driver to queue the DATA phase's struct usb_request, then
+	 * start it right away.
+	 *
+	 * If we're actually in a 2-stage transfer, we will wait for
+	 * XferNotReady(STATUS).
+	 */
+	if (dwc->three_stage_setup) {
+		unsigned        direction;
+
+		direction = dwc->ep0_expect_in;
+		dwc->ep0state = EP0_DATA_PHASE;
+
+		__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
+
+		dep->flags &= ~DWC3_EP0_DIR_IN;
+	}
+
+	return 0;
 }
 
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
@@ -207,9 +262,14 @@
 
 static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
 {
-	struct dwc3_ep		*dep = dwc->eps[0];
+	struct dwc3_ep		*dep;
+
+	/* reinitialize physical ep1 */
+	dep = dwc->eps[1];
+	dep->flags = DWC3_EP_ENABLED;
 
 	/* stall is always issued on EP0 */
+	dep = dwc->eps[0];
 	__dwc3_gadget_ep_set_halt(dep, 1);
 	dep->flags = DWC3_EP_ENABLED;
 	dwc->delayed_status = false;
@@ -698,6 +758,7 @@
 	struct dwc3_trb		*trb;
 	struct dwc3_ep		*ep0;
 	u32			transferred;
+	u32			status;
 	u32			length;
 	u8			epnum;
 
@@ -710,6 +771,17 @@
 	ur = &r->request;
 
 	trb = dwc->ep0_trb;
+
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING) {
+		dev_dbg(dwc->dev, "Setup Pending received\n");
+
+		if (r)
+			dwc3_gadget_giveback(ep0, r, -ECONNRESET);
+
+		return;
+	}
+
 	length = trb->size & DWC3_TRB_SIZE_MASK;
 
 	if (dwc->ep0_bounced) {
@@ -745,8 +817,11 @@
 {
 	struct dwc3_request	*r;
 	struct dwc3_ep		*dep;
+	struct dwc3_trb		*trb;
+	u32			status;
 
 	dep = dwc->eps[0];
+	trb = dwc->ep0_trb;
 
 	if (!list_empty(&dep->request_list)) {
 		r = next_request(&dep->request_list);
@@ -766,6 +841,10 @@
 		}
 	}
 
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING)
+		dev_dbg(dwc->dev, "Setup Pending received\n");
+
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 }
@@ -799,12 +878,6 @@
 	}
 }
 
-static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
-		const struct dwc3_event_depevt *event)
-{
-	dwc3_ep0_out_start(dwc);
-}
-
 static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
 		struct dwc3_ep *dep, struct dwc3_request *req)
 {
@@ -857,29 +930,6 @@
 	WARN_ON(ret < 0);
 }
 
-static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
-		const struct dwc3_event_depevt *event)
-{
-	struct dwc3_ep		*dep;
-	struct dwc3_request	*req;
-
-	dep = dwc->eps[0];
-
-	if (list_empty(&dep->request_list)) {
-		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
-		dep->flags |= DWC3_EP_PENDING_REQUEST;
-
-		if (event->endpoint_number)
-			dep->flags |= DWC3_EP0_DIR_IN;
-		return;
-	}
-
-	req = next_request(&dep->request_list);
-	dep = dwc->eps[event->endpoint_number];
-
-	__dwc3_ep0_do_control_data(dwc, dep, req);
-}
-
 static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 {
 	struct dwc3		*dwc = dep->dwc;
@@ -911,100 +961,61 @@
 	__dwc3_ep0_do_control_status(dwc, dep);
 }
 
+static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32			cmd;
+	int			ret;
+
+	if (!dep->resource_index)
+		return;
+
+	cmd = DWC3_DEPCMD_ENDTRANSFER;
+	cmd |= DWC3_DEPCMD_CMDIOC;
+	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
+	memset(&params, 0, sizeof(params));
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	WARN_ON_ONCE(ret);
+	dep->resource_index = 0;
+}
+
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 {
 	dwc->setup_packet_pending = true;
 
-	/*
-	 * This part is very tricky: If we have just handled
-	 * XferNotReady(Setup) and we're now expecting a
-	 * XferComplete but, instead, we receive another
-	 * XferNotReady(Setup), we should STALL and restart
-	 * the state machine.
-	 *
-	 * In all other cases, we just continue waiting
-	 * for the XferComplete event.
-	 *
-	 * We are a little bit unsafe here because we're
-	 * not trying to ensure that last event was, indeed,
-	 * XferNotReady(Setup).
-	 *
-	 * Still, we don't expect any condition where that
-	 * should happen and, even if it does, it would be
-	 * another error condition.
-	 */
-	if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
-		switch (event->status) {
-		case DEPEVT_STATUS_CONTROL_SETUP:
-			dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
-			dwc3_ep0_stall_and_restart(dwc);
-			break;
-		case DEPEVT_STATUS_CONTROL_DATA:
-			/* FALLTHROUGH */
-		case DEPEVT_STATUS_CONTROL_STATUS:
-			/* FALLTHROUGH */
-		default:
-			dev_vdbg(dwc->dev, "waiting for XferComplete\n");
-		}
-
-		return;
-	}
-
 	switch (event->status) {
-	case DEPEVT_STATUS_CONTROL_SETUP:
-		dev_vdbg(dwc->dev, "Control Setup\n");
-
-		dwc->ep0state = EP0_SETUP_PHASE;
-
-		dwc3_ep0_do_control_setup(dwc, event);
-		break;
-
 	case DEPEVT_STATUS_CONTROL_DATA:
 		dev_vdbg(dwc->dev, "Control Data\n");
 
-		dwc->ep0state = EP0_DATA_PHASE;
-
-		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
-			dev_vdbg(dwc->dev, "Expected %d got %d\n",
-					dwc->ep0_next_event,
-					DWC3_EP0_NRDY_DATA);
-
-			dwc3_ep0_stall_and_restart(dwc);
-			return;
-		}
-
 		/*
-		 * One of the possible error cases is when Host _does_
-		 * request for Data Phase, but it does so on the wrong
-		 * direction.
+		 * We already have a DATA transfer in the controller's cache,
+		 * if we receive a XferNotReady(DATA) we will ignore it, unless
+		 * it's for the wrong direction.
 		 *
-		 * Here, we already know ep0_next_event is DATA (see above),
-		 * so we only need to check for direction.
+		 * In that case, we must issue END_TRANSFER command to the Data
+		 * Phase we already have started and issue SetStall on the
+		 * control endpoint.
 		 */
 		if (dwc->ep0_expect_in != event->endpoint_number) {
+			struct dwc3_ep	*dep = dwc->eps[dwc->ep0_expect_in];
+
 			dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+			dwc3_ep0_end_control_data(dwc, dep);
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
 
-		dwc3_ep0_do_control_data(dwc, event);
 		break;
 
 	case DEPEVT_STATUS_CONTROL_STATUS:
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS)
+			return;
+
 		dev_vdbg(dwc->dev, "Control Status\n");
 
 		dwc->ep0state = EP0_STATUS_PHASE;
 
-		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
-			dev_vdbg(dwc->dev, "Expected %d got %d\n",
-					dwc->ep0_next_event,
-					DWC3_EP0_NRDY_STATUS);
-
-			dwc3_ep0_stall_and_restart(dwc);
-			return;
-		}
-
 		if (dwc->delayed_status) {
 			WARN_ON_ONCE(event->endpoint_number != 1);
 			dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c2813c2b..c9e729a 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -434,15 +434,25 @@
 
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 		const struct usb_endpoint_descriptor *desc,
-		const struct usb_ss_ep_comp_descriptor *comp_desc)
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool ignore)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 
 	memset(&params, 0x00, sizeof(params));
 
 	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
-		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
-		| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1);
+		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
+
+	/* Burst size is only needed in SuperSpeed mode */
+	if (dwc->gadget.speed == USB_SPEED_SUPER) {
+		u32 burst = dep->endpoint.maxburst - 1;
+
+		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
+	}
+
+	if (ignore)
+		params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
 
 	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
 		| DWC3_DEPCFG_XFER_NOT_READY_EN;
@@ -501,7 +511,8 @@
  */
 static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 		const struct usb_endpoint_descriptor *desc,
-		const struct usb_ss_ep_comp_descriptor *comp_desc)
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool ignore)
 {
 	struct dwc3		*dwc = dep->dwc;
 	u32			reg;
@@ -513,7 +524,7 @@
 			return ret;
 	}
 
-	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore);
 	if (ret)
 		return ret;
 
@@ -561,27 +572,7 @@
 	if (!list_empty(&dep->req_queued)) {
 		dwc3_stop_active_transfer(dwc, dep->number);
 
-		/*
-		 * NOTICE: We are violating what the Databook says about the
-		 * EndTransfer command. Ideally we would _always_ wait for the
-		 * EndTransfer Command Completion IRQ, but that's causing too
-		 * much trouble synchronizing between us and gadget driver.
-		 *
-		 * We have discussed this with the IP Provider and it was
-		 * suggested to giveback all requests here, but give HW some
-		 * extra time to synchronize with the interconnect. We're using
-		 * an arbitraty 100us delay for that.
-		 *
-		 * Note also that a similar handling was tested by Synopsys
-		 * (thanks a lot Paul) and nothing bad has come out of it.
-		 * In short, what we're doing is:
-		 *
-		 * - Issue EndTransfer WITH CMDIOC bit set
-		 * - Wait 100us
-		 * - giveback all requests to gadget driver
-		 */
-		udelay(100);
-
+		/* - giveback all requests to gadget driver */
 		while (!list_empty(&dep->req_queued)) {
 			req = next_request(&dep->req_queued);
 
@@ -660,6 +651,12 @@
 	dep = to_dwc3_ep(ep);
 	dwc = dep->dwc;
 
+	if (dep->flags & DWC3_EP_ENABLED) {
+		dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+				dep->name);
+		return 0;
+	}
+
 	switch (usb_endpoint_type(desc)) {
 	case USB_ENDPOINT_XFER_CONTROL:
 		strlcat(dep->name, "-control", sizeof(dep->name));
@@ -677,16 +674,10 @@
 		dev_err(dwc->dev, "invalid endpoint transfer type\n");
 	}
 
-	if (dep->flags & DWC3_EP_ENABLED) {
-		dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
-				dep->name);
-		return 0;
-	}
-
 	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
+	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -1105,12 +1096,9 @@
 		}
 
 		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
-		if (ret && ret != -EBUSY) {
-			struct dwc3	*dwc = dep->dwc;
-
+		if (ret && ret != -EBUSY)
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
-		}
 	}
 
 	/*
@@ -1119,16 +1107,14 @@
 	 *    core may not see the modified TRB(s).
 	 */
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-			(dep->flags & DWC3_EP_BUSY)) {
+			(dep->flags & DWC3_EP_BUSY) &&
+			!(dep->flags & DWC3_EP_MISSED_ISOC)) {
 		WARN_ON_ONCE(!dep->resource_index);
 		ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
 				false);
-		if (ret && ret != -EBUSY) {
-			struct dwc3	*dwc = dep->dwc;
-
+		if (ret && ret != -EBUSY)
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
-		}
 	}
 
 	/*
@@ -1533,14 +1519,14 @@
 	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err0;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err1;
@@ -1765,7 +1751,7 @@
 		int		i;
 
 		for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
-			struct dwc3_ep	*dep = dwc->eps[i];
+			dep = dwc->eps[i];
 
 			if (!(dep->flags & DWC3_EP_ENABLED))
 				continue;
@@ -1892,6 +1878,25 @@
 	if (!dep->resource_index)
 		return;
 
+	/*
+	 * NOTICE: We are violating what the Databook says about the
+	 * EndTransfer command. Ideally we would _always_ wait for the
+	 * EndTransfer Command Completion IRQ, but that's causing too
+	 * much trouble synchronizing between us and gadget driver.
+	 *
+	 * We have discussed this with the IP Provider and it was
+	 * suggested to giveback all requests here, but give HW some
+	 * extra time to synchronize with the interconnect. We're using
+	 * an arbitraty 100us delay for that.
+	 *
+	 * Note also that a similar handling was tested by Synopsys
+	 * (thanks a lot Paul) and nothing bad has come out of it.
+	 * In short, what we're doing is:
+	 *
+	 * - Issue EndTransfer WITH CMDIOC bit set
+	 * - Wait 100us
+	 */
+
 	cmd = DWC3_DEPCMD_ENDTRANSFER;
 	cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
 	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
@@ -1899,6 +1904,8 @@
 	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
 	WARN_ON_ONCE(ret);
 	dep->resource_index = 0;
+
+	udelay(100);
 }
 
 static void dwc3_stop_active_transfers(struct dwc3 *dwc)
@@ -2156,14 +2163,14 @@
 	}
 
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
index 89dcf15..e426ad6 100644
--- a/drivers/usb/early/ehci-dbgp.c
+++ b/drivers/usb/early/ehci-dbgp.c
@@ -491,7 +491,7 @@
  * Return -ENODEV for any general failure
  * Return -EIO if wait for port fails
  */
-int dbgp_external_startup(void)
+static int _dbgp_external_startup(void)
 {
 	int devnum;
 	struct usb_debug_descriptor dbgp_desc;
@@ -613,6 +613,11 @@
 		goto try_again;
 	return -ENODEV;
 }
+
+int dbgp_external_startup(struct usb_hcd *hcd)
+{
+	return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup();
+}
 EXPORT_SYMBOL_GPL(dbgp_external_startup);
 
 static int ehci_reset_port(int port)
@@ -804,7 +809,7 @@
 		dbgp_ehci_status("ehci skip - already configured");
 	}
 
-	ret = dbgp_external_startup();
+	ret = _dbgp_external_startup();
 	if (ret == -EIO)
 		goto next_debug_port;
 
@@ -934,7 +939,7 @@
 		ctrl = readl(&ehci_debug->control);
 		if (!(ctrl & DBGP_ENABLED)) {
 			dbgp_not_safe = 1;
-			dbgp_external_startup();
+			_dbgp_external_startup();
 		} else {
 			cmd |= CMD_RUN;
 			writel(cmd, &ehci_regs->command);
@@ -974,10 +979,14 @@
 	.index =	-1,
 };
 
-int dbgp_reset_prep(void)
+int dbgp_reset_prep(struct usb_hcd *hcd)
 {
+	int ret = xen_dbgp_reset_prep(hcd);
 	u32 ctrl;
 
+	if (ret)
+		return ret;
+
 	dbgp_not_safe = 1;
 	if (!ehci_debug)
 		return 0;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 51ab5fd..dfb51a4 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -154,16 +154,25 @@
 
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
-	select USB_GADGET_DUALSPEED
 	depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 
+config USB_BCM63XX_UDC
+	tristate "Broadcom BCM63xx Peripheral Controller"
+	depends on BCM63XX
+	help
+	   Many Broadcom BCM63xx chipsets (such as the BCM6328) have a
+	   high speed USB Device Port with support for four fixed endpoints
+	   (plus endpoint zero).
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "bcm63xx_udc".
+
 config USB_FSL_USB2
 	tristate "Freescale Highspeed USB DR Peripheral Controller"
 	depends on FSL_SOC || ARCH_MXC
-	select USB_GADGET_DUALSPEED
 	select USB_FSL_MPH_DR_OF if OF
 	help
 	   Some of Freescale PowerPC and i.MX processors have a High Speed
@@ -179,7 +188,6 @@
 config USB_FUSB300
 	tristate "Faraday FUSB300 USB Peripheral Controller"
 	depends on !PHYS_ADDR_T_64BIT
-	select USB_GADGET_DUALSPEED
 	help
 	   Faraday usb device controller FUSB300 driver
 
@@ -227,7 +235,6 @@
 
 config USB_R8A66597
 	tristate "Renesas R8A66597 USB Peripheral Controller"
-	select USB_GADGET_DUALSPEED
 	help
 	   R8A66597 is a discrete USB host and peripheral controller chip that
 	   supports both full and high speed USB 2.0 data transfers.
@@ -240,7 +247,6 @@
 config USB_RENESAS_USBHS_UDC
 	tristate 'Renesas USBHS controller'
 	depends on USB_RENESAS_USBHS
-	select USB_GADGET_DUALSPEED
 	help
 	   Renesas USBHS is a discrete USB host and peripheral controller chip
 	   that supports both full and high speed USB 2.0 data transfers.
@@ -268,7 +274,6 @@
 config USB_S3C_HSOTG
 	tristate "S3C HS/OtG USB Device controller"
 	depends on S3C_DEV_USB_HSOTG
-	select USB_GADGET_DUALSPEED
 	help
 	  The Samsung S3C64XX USB2.0 high-speed gadget controller
 	  integrated into the S3C64XX series SoC.
@@ -305,7 +310,6 @@
 config USB_S3C_HSUDC
 	tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
 	depends on ARCH_S3C24XX
-	select USB_GADGET_DUALSPEED
 	help
 	  Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
 	  integrated with dual speed USB 2.0 device controller. It has
@@ -315,7 +319,6 @@
 
 config USB_MV_UDC
 	tristate "Marvell USB2.0 Device Controller"
-	select USB_GADGET_DUALSPEED
 	help
 	  Marvell Socs (including PXA and MMP series) include a high speed
 	  USB2.0 OTG controller, which can be configured as high speed or
@@ -338,14 +341,12 @@
 config USB_GADGET_MUSB_HDRC
 	tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
 	depends on USB_MUSB_HDRC
-	select USB_GADGET_DUALSPEED
 	help
 	  This OTG-capable silicon IP is used in dual designs including
 	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
 config USB_M66592
 	tristate "Renesas M66592 USB Peripheral Controller"
-	select USB_GADGET_DUALSPEED
 	help
 	   M66592 is a discrete USB peripheral controller chip that
 	   supports both full and high speed USB 2.0 data transfers.
@@ -362,7 +363,6 @@
 config USB_AMD5536UDC
 	tristate "AMD5536 UDC"
 	depends on PCI
-	select USB_GADGET_DUALSPEED
 	help
 	   The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
 	   It is a USB Highspeed DMA capable USB device controller. Beside ep0
@@ -389,7 +389,6 @@
 
 config USB_NET2272
 	tristate "PLX NET2272"
-	select USB_GADGET_DUALSPEED
 	help
 	  PLX NET2272 is a USB peripheral controller which supports
 	  both full and high speed USB 2.0 data transfers.
@@ -413,7 +412,6 @@
 config USB_NET2280
 	tristate "NetChip 228x"
 	depends on PCI
-	select USB_GADGET_DUALSPEED
 	help
 	   NetChip 2280 / 2282 is a PCI based USB peripheral controller which
 	   supports both full and high speed USB 2.0 data transfers.
@@ -443,7 +441,6 @@
 config USB_EG20T
 	tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
 	depends on PCI
-	select USB_GADGET_DUALSPEED
 	help
 	  This is a USB device driver for EG20T PCH.
 	  EG20T PCH is the platform controller hub that is used in Intel's
@@ -470,8 +467,6 @@
 config USB_DUMMY_HCD
 	tristate "Dummy HCD (DEVELOPMENT)"
 	depends on USB=y || (USB=m && USB_GADGET=m)
-	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SUPERSPEED
 	help
 	  This host controller driver emulates USB, looping all data transfer
 	  requests back to a USB "gadget driver" in the same host.  The host
@@ -496,18 +491,15 @@
 
 endmenu
 
-# Selected by UDC drivers that support high-speed operation.
-config USB_GADGET_DUALSPEED
-	bool
-
-# Selected by UDC drivers that support super-speed opperation
-config USB_GADGET_SUPERSPEED
-	bool
-	depends on USB_GADGET_DUALSPEED
-
 #
 # USB Gadget Drivers
 #
+
+# composite based drivers
+config USB_LIBCOMPOSITE
+	tristate
+	depends on USB_GADGET
+
 choice
 	tristate "USB Gadget Drivers"
 	default USB_ETH
@@ -531,6 +523,7 @@
 
 config USB_ZERO
 	tristate "Gadget Zero (DEVELOPMENT)"
+	select USB_LIBCOMPOSITE
 	help
 	  Gadget Zero is a two-configuration device.  It either sinks and
 	  sources bulk data; or it loops back a configurable number of
@@ -564,8 +557,9 @@
 	  one serve as the USB host instead (in the "B-Host" role).
 
 config USB_AUDIO
-	tristate "Audio Gadget (EXPERIMENTAL)"
+	tristate "Audio Gadget"
 	depends on SND
+	select USB_LIBCOMPOSITE
 	select SND_PCM
 	help
 	  This Gadget Audio driver is compatible with USB Audio Class
@@ -594,6 +588,7 @@
 config USB_ETH
 	tristate "Ethernet Gadget (with CDC Ethernet support)"
 	depends on NET
+	select USB_LIBCOMPOSITE
 	select CRC32
 	help
 	  This driver implements Ethernet style communication, in one of
@@ -629,6 +624,7 @@
 config USB_ETH_RNDIS
 	bool "RNDIS support"
 	depends on USB_ETH
+	select USB_LIBCOMPOSITE
 	default y
 	help
 	   Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
@@ -647,6 +643,7 @@
 config USB_ETH_EEM
        bool "Ethernet Emulation Model (EEM) support"
        depends on USB_ETH
+	select USB_LIBCOMPOSITE
        default n
        help
          CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
@@ -663,6 +660,7 @@
 config USB_G_NCM
 	tristate "Network Control Model (NCM) support"
 	depends on NET
+	select USB_LIBCOMPOSITE
 	select CRC32
 	help
 	  This driver implements USB CDC NCM subclass standard. NCM is
@@ -674,8 +672,7 @@
 	  dynamically linked module called "g_ncm".
 
 config USB_GADGETFS
-	tristate "Gadget Filesystem (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Gadget Filesystem"
 	help
 	  This driver provides a filesystem based API that lets user mode
 	  programs implement a single-configuration USB device, including
@@ -683,15 +680,12 @@
 	  All endpoints, transfer speeds, and transfer types supported by
 	  the hardware are available, through read() and write() calls.
 
-	  Currently, this option is still labelled as EXPERIMENTAL because
-	  of existing race conditions in the underlying in-kernel AIO core.
-
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "gadgetfs".
 
 config USB_FUNCTIONFS
-	tristate "Function Filesystem (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Function Filesystem"
+	select USB_LIBCOMPOSITE
 	select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
 	help
 	  The Function Filesystem (FunctionFS) lets one create USB
@@ -755,6 +749,7 @@
 config USB_MASS_STORAGE
 	tristate "Mass Storage Gadget"
 	depends on BLOCK
+	select USB_LIBCOMPOSITE
 	help
 	  The Mass Storage Gadget acts as a USB Mass Storage disk drive.
 	  As its storage repository it can use a regular file or a block
@@ -770,6 +765,7 @@
 config USB_GADGET_TARGET
 	tristate "USB Gadget Target Fabric Module"
 	depends on TARGET_CORE
+	select USB_LIBCOMPOSITE
 	help
 	  This fabric is an USB gadget. Two USB protocols are supported that is
 	  BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
@@ -779,6 +775,7 @@
 
 config USB_G_SERIAL
 	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
+	select USB_LIBCOMPOSITE
 	help
 	  The Serial Gadget talks to the Linux-USB generic serial driver.
 	  This driver supports a CDC-ACM module option, which can be used
@@ -797,8 +794,9 @@
 	  make MS-Windows work with CDC ACM.
 
 config USB_MIDI_GADGET
-	tristate "MIDI Gadget (EXPERIMENTAL)"
-	depends on SND && EXPERIMENTAL
+	tristate "MIDI Gadget"
+	depends on SND
+	select USB_LIBCOMPOSITE
 	select SND_RAWMIDI
 	help
 	  The MIDI Gadget acts as a USB Audio device, with one MIDI
@@ -812,6 +810,7 @@
 
 config USB_G_PRINTER
 	tristate "Printer Gadget"
+	select USB_LIBCOMPOSITE
 	help
 	  The Printer Gadget channels data between the USB host and a
 	  userspace program driving the print engine. The user space
@@ -828,6 +827,7 @@
 config USB_CDC_COMPOSITE
 	tristate "CDC Composite Device (Ethernet and ACM)"
 	depends on NET
+	select USB_LIBCOMPOSITE
 	help
 	  This driver provides two functions in one configuration:
 	  a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
@@ -842,6 +842,7 @@
 config USB_G_NOKIA
 	tristate "Nokia composite gadget"
 	depends on PHONET
+	select USB_LIBCOMPOSITE
 	help
 	  The Nokia composite gadget provides support for acm, obex
 	  and phonet in only one composite gadget driver.
@@ -852,6 +853,7 @@
 config USB_G_ACM_MS
 	tristate "CDC Composite Device (ACM and mass storage)"
 	depends on BLOCK
+	select USB_LIBCOMPOSITE
 	help
 	  This driver provides two functions in one configuration:
 	  a mass storage, and a CDC ACM (serial port) link.
@@ -860,9 +862,10 @@
 	  dynamically linked module called "g_acm_ms".
 
 config USB_G_MULTI
-	tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
+	tristate "Multifunction Composite Gadget"
 	depends on BLOCK && NET
 	select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
+	select USB_LIBCOMPOSITE
 	help
 	  The Multifunction Composite Gadget provides Ethernet (RNDIS
 	  and/or CDC Ethernet), mass storage and ACM serial link
@@ -903,6 +906,7 @@
 
 config USB_G_HID
 	tristate "HID Gadget"
+	select USB_LIBCOMPOSITE
 	help
 	  The HID gadget driver provides generic emulation of USB
 	  Human Interface Devices (HID).
@@ -913,8 +917,10 @@
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "g_hid".
 
+# Standalone / single function gadgets
 config USB_G_DBGP
 	tristate "EHCI Debug Device Gadget"
+	select USB_LIBCOMPOSITE
 	help
 	  This gadget emulates an EHCI Debug device. This is useful when you want
 	  to interact with an EHCI Debug Port.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 3fd8cd0..307be5f 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -4,6 +4,9 @@
 ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_GADGET)	+= udc-core.o
+obj-$(CONFIG_USB_LIBCOMPOSITE)	+= libcomposite.o
+libcomposite-y			:= usbstring.o config.o epautoconf.o
+libcomposite-y			+= composite.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2272)	+= net2272.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
@@ -16,6 +19,7 @@
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 obj-$(CONFIG_USB_ATMEL_USBA)	+= atmel_usba_udc.o
+obj-$(CONFIG_USB_BCM63XX_UDC)	+= bcm63xx_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 fsl_usb2_udc-y			:= fsl_udc_core.o
 fsl_usb2_udc-$(CONFIG_ARCH_MXC)	+= fsl_mxc_udc.o
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
index 75b8a69..5a7f289 100644
--- a/drivers/usb/gadget/acm_ms.c
+++ b/drivers/usb/gadget/acm_ms.c
@@ -15,7 +15,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
+#include <linux/module.h>
 
 #include "u_serial.h"
 
@@ -41,15 +41,12 @@
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_mass_storage.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
 	.bLength =		sizeof device_desc,
@@ -89,17 +86,11 @@
 	NULL,
 };
 
-
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -157,7 +148,6 @@
 
 static int __init acm_ms_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 	void			*retp;
@@ -174,44 +164,22 @@
 		goto fail0;
 	}
 
-	/* set bcdDevice */
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0) {
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	} else {
-		WARNING(cdev, "controller '%s' not recognized; trying %s\n",
-				gadget->name,
-				acm_ms_config_driver.label);
-		device_desc.bcdDevice =
-			cpu_to_le16(0x0300 | 0x0099);
-	}
-
 	/*
 	 * Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
-
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail1;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail1;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	/* register our configuration */
 	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
 	if (status < 0)
 		goto fail1;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
 			DRIVER_DESC);
 	fsg_common_put(&fsg_common);
@@ -232,11 +200,12 @@
 	return 0;
 }
 
-static struct usb_composite_driver acm_ms_driver = {
+static __refdata struct usb_composite_driver acm_ms_driver = {
 	.name		= "g_acm_ms",
 	.dev		= &device_desc,
 	.max_speed	= USB_SPEED_SUPER,
 	.strings	= dev_strings,
+	.bind		= acm_ms_bind,
 	.unbind		= __exit_p(acm_ms_unbind),
 };
 
@@ -246,7 +215,7 @@
 
 static int __init init(void)
 {
-	return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
+	return usb_composite_probe(&acm_ms_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 187d211..fc0ec5e 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1401,7 +1401,7 @@
 }
 
 static int amd5536_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int amd5536_stop(struct usb_gadget_driver *driver);
 /* gadget operations */
 static const struct usb_gadget_ops udc_ops = {
@@ -1914,7 +1914,7 @@
 
 /* Called by gadget driver to register itself */
 static int amd5536_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct udc		*dev = udc;
 	int			retval;
@@ -1932,7 +1932,7 @@
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 
-	retval = bind(&dev->gadget);
+	retval = bind(&dev->gadget, driver);
 
 	/* Some gadget drivers use both ep0 directions.
 	 * NOTE: to gadget driver, ep0 is just one endpoint...
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 1e35963..89d90b5 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -469,7 +469,7 @@
 				const struct usb_endpoint_descriptor *desc)
 {
 	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
-	struct at91_udc	*udc = ep->udc;
+	struct at91_udc *udc;
 	u16		maxpacket;
 	u32		tmp;
 	unsigned long	flags;
@@ -483,6 +483,7 @@
 		return -EINVAL;
 	}
 
+	udc = ep->udc;
 	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
 		DBG("bogus device state\n");
 		return -ESHUTDOWN;
@@ -1699,7 +1700,7 @@
 	int		retval;
 	struct resource	*res;
 
-	if (!dev->platform_data) {
+	if (!dev->platform_data && !pdev->dev.of_node) {
 		/* small (so we copy it) but critical! */
 		DBG("missing platform_data\n");
 		return -ENODEV;
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 9889924..231b0ef 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -12,35 +12,21 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
+#include "gadget_chips.h"
 #define DRIVER_DESC		"Linux USB Audio Gadget"
 #define DRIVER_VERSION		"Feb 2, 2012"
 
-/*-------------------------------------------------------------------------*/
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -149,39 +135,18 @@
 
 static int __init audio_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	int			status;
 
-	gcnum = usb_gadget_controller_number(cdev->gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else {
-		ERROR(cdev, "controller '%s' not recognized; trying %s\n",
-			cdev->gadget->name,
-			audio_config_driver.label);
-		device_desc.bcdDevice =
-			__constant_cpu_to_le16(0x0300 | 0x0099);
-	}
-
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		cdev->gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
 	if (status < 0)
 		goto fail;
+	usb_composite_overwrite_options(cdev, &coverwrite);
 
 	INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
 	return 0;
@@ -198,17 +163,18 @@
 	return 0;
 }
 
-static struct usb_composite_driver audio_driver = {
+static __refdata struct usb_composite_driver audio_driver = {
 	.name		= "g_audio",
 	.dev		= &device_desc,
 	.strings	= audio_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= audio_bind,
 	.unbind		= __exit_p(audio_unbind),
 };
 
 static int __init init(void)
 {
-	return usb_composite_probe(&audio_driver, audio_bind);
+	return usb_composite_probe(&audio_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
new file mode 100644
index 0000000..9ca7922
--- /dev/null
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -0,0 +1,2464 @@
+/*
+ * bcm63xx_udc.c -- BCM63xx UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
+ * Copyright (C) 2012 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_iudma.h>
+#include <bcm63xx_dev_usb_usbd.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+#define DRV_MODULE_NAME		"bcm63xx_udc"
+
+static const char bcm63xx_ep0name[] = "ep0";
+static const char *const bcm63xx_ep_name[] = {
+	bcm63xx_ep0name,
+	"ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int",
+};
+
+static bool use_fullspeed;
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*
+ * RX IRQ coalescing options:
+ *
+ * false (default) - one IRQ per DATAx packet.  Slow but reliable.  The
+ * driver is able to pass the "testusb" suite and recover from conditions like:
+ *
+ *   1) Device queues up a 2048-byte RX IUDMA transaction on an OUT bulk ep
+ *   2) Host sends 512 bytes of data
+ *   3) Host decides to reconfigure the device and sends SET_INTERFACE
+ *   4) Device shuts down the endpoint and cancels the RX transaction
+ *
+ * true - one IRQ per transfer, for transfers <= 2048B.  Generates
+ * considerably fewer IRQs, but error recovery is less robust.  Does not
+ * reliably pass "testusb".
+ *
+ * TX always uses coalescing, because we can cancel partially complete TX
+ * transfers by repeatedly flushing the FIFO.  The hardware doesn't allow
+ * this on RX.
+ */
+static bool irq_coalesce;
+module_param(irq_coalesce, bool, S_IRUGO);
+MODULE_PARM_DESC(irq_coalesce, "take one IRQ per RX transfer");
+
+#define BCM63XX_NUM_EP			5
+#define BCM63XX_NUM_IUDMA		6
+#define BCM63XX_NUM_FIFO_PAIRS		3
+
+#define IUDMA_RESET_TIMEOUT_US		10000
+
+#define IUDMA_EP0_RXCHAN		0
+#define IUDMA_EP0_TXCHAN		1
+
+#define IUDMA_MAX_FRAGMENT		2048
+#define BCM63XX_MAX_CTRL_PKT		64
+
+#define BCMEP_CTRL			0x00
+#define BCMEP_ISOC			0x01
+#define BCMEP_BULK			0x02
+#define BCMEP_INTR			0x03
+
+#define BCMEP_OUT			0x00
+#define BCMEP_IN			0x01
+
+#define BCM63XX_SPD_FULL		1
+#define BCM63XX_SPD_HIGH		0
+
+#define IUDMA_DMAC_OFFSET		0x200
+#define IUDMA_DMAS_OFFSET		0x400
+
+enum bcm63xx_ep0_state {
+	EP0_REQUEUE,
+	EP0_IDLE,
+	EP0_IN_DATA_PHASE_SETUP,
+	EP0_IN_DATA_PHASE_COMPLETE,
+	EP0_OUT_DATA_PHASE_SETUP,
+	EP0_OUT_DATA_PHASE_COMPLETE,
+	EP0_OUT_STATUS_PHASE,
+	EP0_IN_FAKE_STATUS_PHASE,
+	EP0_SHUTDOWN,
+};
+
+static const char __maybe_unused bcm63xx_ep0_state_names[][32] = {
+	"REQUEUE",
+	"IDLE",
+	"IN_DATA_PHASE_SETUP",
+	"IN_DATA_PHASE_COMPLETE",
+	"OUT_DATA_PHASE_SETUP",
+	"OUT_DATA_PHASE_COMPLETE",
+	"OUT_STATUS_PHASE",
+	"IN_FAKE_STATUS_PHASE",
+	"SHUTDOWN",
+};
+
+/**
+ * struct iudma_ch_cfg - Static configuration for an IUDMA channel.
+ * @ep_num: USB endpoint number.
+ * @n_bds: Number of buffer descriptors in the ring.
+ * @ep_type: Endpoint type (control, bulk, interrupt).
+ * @dir: Direction (in, out).
+ * @n_fifo_slots: Number of FIFO entries to allocate for this channel.
+ * @max_pkt_hs: Maximum packet size in high speed mode.
+ * @max_pkt_fs: Maximum packet size in full speed mode.
+ */
+struct iudma_ch_cfg {
+	int				ep_num;
+	int				n_bds;
+	int				ep_type;
+	int				dir;
+	int				n_fifo_slots;
+	int				max_pkt_hs;
+	int				max_pkt_fs;
+};
+
+static const struct iudma_ch_cfg iudma_defaults[] = {
+
+	/* This controller was designed to support a CDC/RNDIS application.
+	   It may be possible to reconfigure some of the endpoints, but
+	   the hardware limitations (FIFO sizing and number of DMA channels)
+	   may significantly impact flexibility and/or stability.  Change
+	   these values at your own risk.
+
+	      ep_num       ep_type           n_fifo_slots    max_pkt_fs
+	idx      |  n_bds     |         dir       |  max_pkt_hs  |
+	 |       |    |       |          |        |      |       |       */
+	[0] = { -1,   4, BCMEP_CTRL, BCMEP_OUT,  32,    64,     64 },
+	[1] = {  0,   4, BCMEP_CTRL, BCMEP_OUT,  32,    64,     64 },
+	[2] = {  2,  16, BCMEP_BULK, BCMEP_OUT, 128,   512,     64 },
+	[3] = {  1,  16, BCMEP_BULK, BCMEP_IN,  128,   512,     64 },
+	[4] = {  4,   4, BCMEP_INTR, BCMEP_OUT,  32,    64,     64 },
+	[5] = {  3,   4, BCMEP_INTR, BCMEP_IN,   32,    64,     64 },
+};
+
+struct bcm63xx_udc;
+
+/**
+ * struct iudma_ch - Represents the current state of a single IUDMA channel.
+ * @ch_idx: IUDMA channel index (0 to BCM63XX_NUM_IUDMA-1).
+ * @ep_num: USB endpoint number.  -1 for ep0 RX.
+ * @enabled: Whether bcm63xx_ep_enable() has been called.
+ * @max_pkt: "Chunk size" on the USB interface.  Based on interface speed.
+ * @is_tx: true for TX, false for RX.
+ * @bep: Pointer to the associated endpoint.  NULL for ep0 RX.
+ * @udc: Reference to the device controller.
+ * @read_bd: Next buffer descriptor to reap from the hardware.
+ * @write_bd: Next BD available for a new packet.
+ * @end_bd: Points to the final BD in the ring.
+ * @n_bds_used: Number of BD entries currently occupied.
+ * @bd_ring: Base pointer to the BD ring.
+ * @bd_ring_dma: Physical (DMA) address of bd_ring.
+ * @n_bds: Total number of BDs in the ring.
+ *
+ * ep0 has two IUDMA channels (IUDMA_EP0_RXCHAN and IUDMA_EP0_TXCHAN), as it is
+ * bidirectional.  The "struct usb_ep" associated with ep0 is for TX (IN)
+ * only.
+ *
+ * Each bulk/intr endpoint has a single IUDMA channel and a single
+ * struct usb_ep.
+ */
+struct iudma_ch {
+	unsigned int			ch_idx;
+	int				ep_num;
+	bool				enabled;
+	int				max_pkt;
+	bool				is_tx;
+	struct bcm63xx_ep		*bep;
+	struct bcm63xx_udc		*udc;
+
+	struct bcm_enet_desc		*read_bd;
+	struct bcm_enet_desc		*write_bd;
+	struct bcm_enet_desc		*end_bd;
+	int				n_bds_used;
+
+	struct bcm_enet_desc		*bd_ring;
+	dma_addr_t			bd_ring_dma;
+	unsigned int			n_bds;
+};
+
+/**
+ * struct bcm63xx_ep - Internal (driver) state of a single endpoint.
+ * @ep_num: USB endpoint number.
+ * @iudma: Pointer to IUDMA channel state.
+ * @ep: USB gadget layer representation of the EP.
+ * @udc: Reference to the device controller.
+ * @queue: Linked list of outstanding requests for this EP.
+ * @halted: 1 if the EP is stalled; 0 otherwise.
+ */
+struct bcm63xx_ep {
+	unsigned int			ep_num;
+	struct iudma_ch			*iudma;
+	struct usb_ep			ep;
+	struct bcm63xx_udc		*udc;
+	struct list_head		queue;
+	unsigned			halted:1;
+};
+
+/**
+ * struct bcm63xx_req - Internal (driver) state of a single request.
+ * @queue: Links back to the EP's request list.
+ * @req: USB gadget layer representation of the request.
+ * @offset: Current byte offset into the data buffer (next byte to queue).
+ * @bd_bytes: Number of data bytes in outstanding BD entries.
+ * @iudma: IUDMA channel used for the request.
+ */
+struct bcm63xx_req {
+	struct list_head		queue;		/* ep's requests */
+	struct usb_request		req;
+	unsigned int			offset;
+	unsigned int			bd_bytes;
+	struct iudma_ch			*iudma;
+};
+
+/**
+ * struct bcm63xx_udc - Driver/hardware private context.
+ * @lock: Spinlock to mediate access to this struct, and (most) HW regs.
+ * @dev: Generic Linux device structure.
+ * @pd: Platform data (board/port info).
+ * @usbd_clk: Clock descriptor for the USB device block.
+ * @usbh_clk: Clock descriptor for the USB host block.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ * @usbd_regs: Base address of the USBD/USB20D block.
+ * @iudma_regs: Base address of the USBD's associated IUDMA block.
+ * @bep: Array of endpoints, including ep0.
+ * @iudma: Array of all IUDMA channels used by this controller.
+ * @cfg: USB configuration number, from SET_CONFIGURATION wValue.
+ * @iface: USB interface number, from SET_INTERFACE wIndex.
+ * @alt_iface: USB alt interface number, from SET_INTERFACE wValue.
+ * @ep0_ctrl_req: Request object for bcm63xx_udc-initiated ep0 transactions.
+ * @ep0_ctrl_buf: Data buffer for ep0_ctrl_req.
+ * @ep0state: Current state of the ep0 state machine.
+ * @ep0_wq: Workqueue struct used to wake up the ep0 state machine.
+ * @wedgemap: Bitmap of wedged endpoints.
+ * @ep0_req_reset: USB reset is pending.
+ * @ep0_req_set_cfg: Need to spoof a SET_CONFIGURATION packet.
+ * @ep0_req_set_iface: Need to spoof a SET_INTERFACE packet.
+ * @ep0_req_shutdown: Driver is shutting down; requesting ep0 to halt activity.
+ * @ep0_req_completed: ep0 request has completed; worker has not seen it yet.
+ * @ep0_reply: Pending reply from gadget driver.
+ * @ep0_request: Outstanding ep0 request.
+ * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>.
+ * @debugfs_usbd: debugfs file "usbd" for controller state.
+ * @debugfs_iudma: debugfs file "usbd" for IUDMA state.
+ */
+struct bcm63xx_udc {
+	spinlock_t			lock;
+
+	struct device			*dev;
+	struct bcm63xx_usbd_platform_data *pd;
+	struct clk			*usbd_clk;
+	struct clk			*usbh_clk;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+
+	void __iomem			*usbd_regs;
+	void __iomem			*iudma_regs;
+
+	struct bcm63xx_ep		bep[BCM63XX_NUM_EP];
+	struct iudma_ch			iudma[BCM63XX_NUM_IUDMA];
+
+	int				cfg;
+	int				iface;
+	int				alt_iface;
+
+	struct bcm63xx_req		ep0_ctrl_req;
+	u8				*ep0_ctrl_buf;
+
+	int				ep0state;
+	struct work_struct		ep0_wq;
+
+	unsigned long			wedgemap;
+
+	unsigned			ep0_req_reset:1;
+	unsigned			ep0_req_set_cfg:1;
+	unsigned			ep0_req_set_iface:1;
+	unsigned			ep0_req_shutdown:1;
+
+	unsigned			ep0_req_completed:1;
+	struct usb_request		*ep0_reply;
+	struct usb_request		*ep0_request;
+
+	struct dentry			*debugfs_root;
+	struct dentry			*debugfs_usbd;
+	struct dentry			*debugfs_iudma;
+};
+
+static const struct usb_ep_ops bcm63xx_udc_ep_ops;
+
+/***********************************************************************
+ * Convenience functions
+ ***********************************************************************/
+
+static inline struct bcm63xx_udc *gadget_to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct bcm63xx_udc, gadget);
+}
+
+static inline struct bcm63xx_ep *our_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct bcm63xx_ep, ep);
+}
+
+static inline struct bcm63xx_req *our_req(struct usb_request *req)
+{
+	return container_of(req, struct bcm63xx_req, req);
+}
+
+static inline u32 usbd_readl(struct bcm63xx_udc *udc, u32 off)
+{
+	return bcm_readl(udc->usbd_regs + off);
+}
+
+static inline void usbd_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+	bcm_writel(val, udc->usbd_regs + off);
+}
+
+static inline u32 usb_dma_readl(struct bcm63xx_udc *udc, u32 off)
+{
+	return bcm_readl(udc->iudma_regs + off);
+}
+
+static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+	bcm_writel(val, udc->iudma_regs + off);
+}
+
+static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off)
+{
+	return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+}
+
+static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+	bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+}
+
+static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off)
+{
+	return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+}
+
+static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+	bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+}
+
+static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled)
+{
+	if (is_enabled) {
+		clk_enable(udc->usbh_clk);
+		clk_enable(udc->usbd_clk);
+		udelay(10);
+	} else {
+		clk_disable(udc->usbd_clk);
+		clk_disable(udc->usbh_clk);
+	}
+}
+
+/***********************************************************************
+ * Low-level IUDMA / FIFO operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep_dma_select - Helper function to set up the init_sel signal.
+ * @udc: Reference to the device controller.
+ * @idx: Desired init_sel value.
+ *
+ * The "init_sel" signal is used as a selection index for both endpoints
+ * and IUDMA channels.  Since these do not map 1:1, the use of this signal
+ * depends on the context.
+ */
+static void bcm63xx_ep_dma_select(struct bcm63xx_udc *udc, int idx)
+{
+	u32 val = usbd_readl(udc, USBD_CONTROL_REG);
+
+	val &= ~USBD_CONTROL_INIT_SEL_MASK;
+	val |= idx << USBD_CONTROL_INIT_SEL_SHIFT;
+	usbd_writel(udc, val, USBD_CONTROL_REG);
+}
+
+/**
+ * bcm63xx_set_stall - Enable/disable stall on one endpoint.
+ * @udc: Reference to the device controller.
+ * @bep: Endpoint on which to operate.
+ * @is_stalled: true to enable stall, false to disable.
+ *
+ * See notes in bcm63xx_update_wedge() regarding automatic clearing of
+ * halt/stall conditions.
+ */
+static void bcm63xx_set_stall(struct bcm63xx_udc *udc, struct bcm63xx_ep *bep,
+	bool is_stalled)
+{
+	u32 val;
+
+	val = USBD_STALL_UPDATE_MASK |
+		(is_stalled ? USBD_STALL_ENABLE_MASK : 0) |
+		(bep->ep_num << USBD_STALL_EPNUM_SHIFT);
+	usbd_writel(udc, val, USBD_STALL_REG);
+}
+
+/**
+ * bcm63xx_fifo_setup - (Re)initialize FIFO boundaries and settings.
+ * @udc: Reference to the device controller.
+ *
+ * These parameters depend on the USB link speed.  Settings are
+ * per-IUDMA-channel-pair.
+ */
+static void bcm63xx_fifo_setup(struct bcm63xx_udc *udc)
+{
+	int is_hs = udc->gadget.speed == USB_SPEED_HIGH;
+	u32 i, val, rx_fifo_slot, tx_fifo_slot;
+
+	/* set up FIFO boundaries and packet sizes; this is done in pairs */
+	rx_fifo_slot = tx_fifo_slot = 0;
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i += 2) {
+		const struct iudma_ch_cfg *rx_cfg = &iudma_defaults[i];
+		const struct iudma_ch_cfg *tx_cfg = &iudma_defaults[i + 1];
+
+		bcm63xx_ep_dma_select(udc, i >> 1);
+
+		val = (rx_fifo_slot << USBD_RXFIFO_CONFIG_START_SHIFT) |
+			((rx_fifo_slot + rx_cfg->n_fifo_slots - 1) <<
+			 USBD_RXFIFO_CONFIG_END_SHIFT);
+		rx_fifo_slot += rx_cfg->n_fifo_slots;
+		usbd_writel(udc, val, USBD_RXFIFO_CONFIG_REG);
+		usbd_writel(udc,
+			    is_hs ? rx_cfg->max_pkt_hs : rx_cfg->max_pkt_fs,
+			    USBD_RXFIFO_EPSIZE_REG);
+
+		val = (tx_fifo_slot << USBD_TXFIFO_CONFIG_START_SHIFT) |
+			((tx_fifo_slot + tx_cfg->n_fifo_slots - 1) <<
+			 USBD_TXFIFO_CONFIG_END_SHIFT);
+		tx_fifo_slot += tx_cfg->n_fifo_slots;
+		usbd_writel(udc, val, USBD_TXFIFO_CONFIG_REG);
+		usbd_writel(udc,
+			    is_hs ? tx_cfg->max_pkt_hs : tx_cfg->max_pkt_fs,
+			    USBD_TXFIFO_EPSIZE_REG);
+
+		usbd_readl(udc, USBD_TXFIFO_EPSIZE_REG);
+	}
+}
+
+/**
+ * bcm63xx_fifo_reset_ep - Flush a single endpoint's FIFO.
+ * @udc: Reference to the device controller.
+ * @ep_num: Endpoint number.
+ */
+static void bcm63xx_fifo_reset_ep(struct bcm63xx_udc *udc, int ep_num)
+{
+	u32 val;
+
+	bcm63xx_ep_dma_select(udc, ep_num);
+
+	val = usbd_readl(udc, USBD_CONTROL_REG);
+	val |= USBD_CONTROL_FIFO_RESET_MASK;
+	usbd_writel(udc, val, USBD_CONTROL_REG);
+	usbd_readl(udc, USBD_CONTROL_REG);
+}
+
+/**
+ * bcm63xx_fifo_reset - Flush all hardware FIFOs.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_fifo_reset(struct bcm63xx_udc *udc)
+{
+	int i;
+
+	for (i = 0; i < BCM63XX_NUM_FIFO_PAIRS; i++)
+		bcm63xx_fifo_reset_ep(udc, i);
+}
+
+/**
+ * bcm63xx_ep_init - Initial (one-time) endpoint initialization.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_ep_init(struct bcm63xx_udc *udc)
+{
+	u32 i, val;
+
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+		const struct iudma_ch_cfg *cfg = &iudma_defaults[i];
+
+		if (cfg->ep_num < 0)
+			continue;
+
+		bcm63xx_ep_dma_select(udc, cfg->ep_num);
+		val = (cfg->ep_type << USBD_EPNUM_TYPEMAP_TYPE_SHIFT) |
+			((i >> 1) << USBD_EPNUM_TYPEMAP_DMA_CH_SHIFT);
+		usbd_writel(udc, val, USBD_EPNUM_TYPEMAP_REG);
+	}
+}
+
+/**
+ * bcm63xx_ep_setup - Configure per-endpoint settings.
+ * @udc: Reference to the device controller.
+ *
+ * This needs to be rerun if the speed/cfg/intf/altintf changes.
+ */
+static void bcm63xx_ep_setup(struct bcm63xx_udc *udc)
+{
+	u32 val, i;
+
+	usbd_writel(udc, USBD_CSR_SETUPADDR_DEF, USBD_CSR_SETUPADDR_REG);
+
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+		const struct iudma_ch_cfg *cfg = &iudma_defaults[i];
+		int max_pkt = udc->gadget.speed == USB_SPEED_HIGH ?
+			      cfg->max_pkt_hs : cfg->max_pkt_fs;
+		int idx = cfg->ep_num;
+
+		udc->iudma[i].max_pkt = max_pkt;
+
+		if (idx < 0)
+			continue;
+		udc->bep[idx].ep.maxpacket = max_pkt;
+
+		val = (idx << USBD_CSR_EP_LOG_SHIFT) |
+		      (cfg->dir << USBD_CSR_EP_DIR_SHIFT) |
+		      (cfg->ep_type << USBD_CSR_EP_TYPE_SHIFT) |
+		      (udc->cfg << USBD_CSR_EP_CFG_SHIFT) |
+		      (udc->iface << USBD_CSR_EP_IFACE_SHIFT) |
+		      (udc->alt_iface << USBD_CSR_EP_ALTIFACE_SHIFT) |
+		      (max_pkt << USBD_CSR_EP_MAXPKT_SHIFT);
+		usbd_writel(udc, val, USBD_CSR_EP_REG(idx));
+	}
+}
+
+/**
+ * iudma_write - Queue a single IUDMA transaction.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to use.
+ * @breq: Request containing the transaction data.
+ *
+ * For RX IUDMA, this will queue a single buffer descriptor, as RX IUDMA
+ * does not honor SOP/EOP so the handling of multiple buffers is ambiguous.
+ * So iudma_write() may be called several times to fulfill a single
+ * usb_request.
+ *
+ * For TX IUDMA, this can queue multiple buffer descriptors if needed.
+ */
+static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,
+	struct bcm63xx_req *breq)
+{
+	int first_bd = 1, last_bd = 0, extra_zero_pkt = 0;
+	unsigned int bytes_left = breq->req.length - breq->offset;
+	const int max_bd_bytes = !irq_coalesce && !iudma->is_tx ?
+		iudma->max_pkt : IUDMA_MAX_FRAGMENT;
+
+	iudma->n_bds_used = 0;
+	breq->bd_bytes = 0;
+	breq->iudma = iudma;
+
+	if ((bytes_left % iudma->max_pkt == 0) && bytes_left && breq->req.zero)
+		extra_zero_pkt = 1;
+
+	do {
+		struct bcm_enet_desc *d = iudma->write_bd;
+		u32 dmaflags = 0;
+		unsigned int n_bytes;
+
+		if (d == iudma->end_bd) {
+			dmaflags |= DMADESC_WRAP_MASK;
+			iudma->write_bd = iudma->bd_ring;
+		} else {
+			iudma->write_bd++;
+		}
+		iudma->n_bds_used++;
+
+		n_bytes = min_t(int, bytes_left, max_bd_bytes);
+		if (n_bytes)
+			dmaflags |= n_bytes << DMADESC_LENGTH_SHIFT;
+		else
+			dmaflags |= (1 << DMADESC_LENGTH_SHIFT) |
+				    DMADESC_USB_ZERO_MASK;
+
+		dmaflags |= DMADESC_OWNER_MASK;
+		if (first_bd) {
+			dmaflags |= DMADESC_SOP_MASK;
+			first_bd = 0;
+		}
+
+		/*
+		 * extra_zero_pkt forces one more iteration through the loop
+		 * after all data is queued up, to send the zero packet
+		 */
+		if (extra_zero_pkt && !bytes_left)
+			extra_zero_pkt = 0;
+
+		if (!iudma->is_tx || iudma->n_bds_used == iudma->n_bds ||
+		    (n_bytes == bytes_left && !extra_zero_pkt)) {
+			last_bd = 1;
+			dmaflags |= DMADESC_EOP_MASK;
+		}
+
+		d->address = breq->req.dma + breq->offset;
+		mb();
+		d->len_stat = dmaflags;
+
+		breq->offset += n_bytes;
+		breq->bd_bytes += n_bytes;
+		bytes_left -= n_bytes;
+	} while (!last_bd);
+
+	usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK,
+			ENETDMAC_CHANCFG_REG(iudma->ch_idx));
+}
+
+/**
+ * iudma_read - Check for IUDMA buffer completion.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to use.
+ *
+ * This checks to see if ALL of the outstanding BDs on the DMA channel
+ * have been filled.  If so, it returns the actual transfer length;
+ * otherwise it returns -EBUSY.
+ */
+static int iudma_read(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
+{
+	int i, actual_len = 0;
+	struct bcm_enet_desc *d = iudma->read_bd;
+
+	if (!iudma->n_bds_used)
+		return -EINVAL;
+
+	for (i = 0; i < iudma->n_bds_used; i++) {
+		u32 dmaflags;
+
+		dmaflags = d->len_stat;
+
+		if (dmaflags & DMADESC_OWNER_MASK)
+			return -EBUSY;
+
+		actual_len += (dmaflags & DMADESC_LENGTH_MASK) >>
+			      DMADESC_LENGTH_SHIFT;
+		if (d == iudma->end_bd)
+			d = iudma->bd_ring;
+		else
+			d++;
+	}
+
+	iudma->read_bd = d;
+	iudma->n_bds_used = 0;
+	return actual_len;
+}
+
+/**
+ * iudma_reset_channel - Stop DMA on a single channel.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to reset.
+ */
+static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
+{
+	int timeout = IUDMA_RESET_TIMEOUT_US;
+	struct bcm_enet_desc *d;
+	int ch_idx = iudma->ch_idx;
+
+	if (!iudma->is_tx)
+		bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));
+
+	/* stop DMA, then wait for the hardware to wrap up */
+	usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx));
+
+	while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) &
+				   ENETDMAC_CHANCFG_EN_MASK) {
+		udelay(1);
+
+		/* repeatedly flush the FIFO data until the BD completes */
+		if (iudma->is_tx && iudma->ep_num >= 0)
+			bcm63xx_fifo_reset_ep(udc, iudma->ep_num);
+
+		if (!timeout--) {
+			dev_err(udc->dev, "can't reset IUDMA channel %d\n",
+				ch_idx);
+			break;
+		}
+		if (timeout == IUDMA_RESET_TIMEOUT_US / 2) {
+			dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",
+				 ch_idx);
+			usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK,
+					ENETDMAC_CHANCFG_REG(ch_idx));
+		}
+	}
+	usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx));
+
+	/* don't leave "live" HW-owned entries for the next guy to step on */
+	for (d = iudma->bd_ring; d <= iudma->end_bd; d++)
+		d->len_stat = 0;
+	mb();
+
+	iudma->read_bd = iudma->write_bd = iudma->bd_ring;
+	iudma->n_bds_used = 0;
+
+	/* set up IRQs, UBUS burst size, and BD base for this channel */
+	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
+			ENETDMAC_IRMASK_REG(ch_idx));
+	usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx));
+
+	usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx));
+	usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx));
+}
+
+/**
+ * iudma_init_channel - One-time IUDMA channel initialization.
+ * @udc: Reference to the device controller.
+ * @ch_idx: Channel to initialize.
+ */
+static int iudma_init_channel(struct bcm63xx_udc *udc, unsigned int ch_idx)
+{
+	struct iudma_ch *iudma = &udc->iudma[ch_idx];
+	const struct iudma_ch_cfg *cfg = &iudma_defaults[ch_idx];
+	unsigned int n_bds = cfg->n_bds;
+	struct bcm63xx_ep *bep = NULL;
+
+	iudma->ep_num = cfg->ep_num;
+	iudma->ch_idx = ch_idx;
+	iudma->is_tx = !!(ch_idx & 0x01);
+	if (iudma->ep_num >= 0) {
+		bep = &udc->bep[iudma->ep_num];
+		bep->iudma = iudma;
+		INIT_LIST_HEAD(&bep->queue);
+	}
+
+	iudma->bep = bep;
+	iudma->udc = udc;
+
+	/* ep0 is always active; others are controlled by the gadget driver */
+	if (iudma->ep_num <= 0)
+		iudma->enabled = true;
+
+	iudma->n_bds = n_bds;
+	iudma->bd_ring = dmam_alloc_coherent(udc->dev,
+		n_bds * sizeof(struct bcm_enet_desc),
+		&iudma->bd_ring_dma, GFP_KERNEL);
+	if (!iudma->bd_ring)
+		return -ENOMEM;
+	iudma->end_bd = &iudma->bd_ring[n_bds - 1];
+
+	return 0;
+}
+
+/**
+ * iudma_init - One-time initialization of all IUDMA channels.
+ * @udc: Reference to the device controller.
+ *
+ * Enable DMA, flush channels, and enable global IUDMA IRQs.
+ */
+static int iudma_init(struct bcm63xx_udc *udc)
+{
+	int i, rc;
+
+	usb_dma_writel(udc, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
+
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+		rc = iudma_init_channel(udc, i);
+		if (rc)
+			return rc;
+		iudma_reset_channel(udc, &udc->iudma[i]);
+	}
+
+	usb_dma_writel(udc, BIT(BCM63XX_NUM_IUDMA)-1, ENETDMA_GLB_IRQMASK_REG);
+	return 0;
+}
+
+/**
+ * iudma_uninit - Uninitialize IUDMA channels.
+ * @udc: Reference to the device controller.
+ *
+ * Kill global IUDMA IRQs, flush channels, and kill DMA.
+ */
+static void iudma_uninit(struct bcm63xx_udc *udc)
+{
+	int i;
+
+	usb_dma_writel(udc, 0, ENETDMA_GLB_IRQMASK_REG);
+
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i++)
+		iudma_reset_channel(udc, &udc->iudma[i]);
+
+	usb_dma_writel(udc, 0, ENETDMA_CFG_REG);
+}
+
+/***********************************************************************
+ * Other low-level USBD operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_set_ctrl_irqs - Mask/unmask control path interrupts.
+ * @udc: Reference to the device controller.
+ * @enable_irqs: true to enable, false to disable.
+ */
+static void bcm63xx_set_ctrl_irqs(struct bcm63xx_udc *udc, bool enable_irqs)
+{
+	u32 val;
+
+	usbd_writel(udc, 0, USBD_STATUS_REG);
+
+	val = BIT(USBD_EVENT_IRQ_USB_RESET) |
+	      BIT(USBD_EVENT_IRQ_SETUP) |
+	      BIT(USBD_EVENT_IRQ_SETCFG) |
+	      BIT(USBD_EVENT_IRQ_SETINTF) |
+	      BIT(USBD_EVENT_IRQ_USB_LINK);
+	usbd_writel(udc, enable_irqs ? val : 0, USBD_EVENT_IRQ_MASK_REG);
+	usbd_writel(udc, val, USBD_EVENT_IRQ_STATUS_REG);
+}
+
+/**
+ * bcm63xx_select_phy_mode - Select between USB device and host mode.
+ * @udc: Reference to the device controller.
+ * @is_device: true for device, false for host.
+ *
+ * This should probably be reworked to use the drivers/usb/otg
+ * infrastructure.
+ *
+ * By default, the AFE/pullups are disabled in device mode, until
+ * bcm63xx_select_pullup() is called.
+ */
+static void bcm63xx_select_phy_mode(struct bcm63xx_udc *udc, bool is_device)
+{
+	u32 val, portmask = BIT(udc->pd->port_no);
+
+	if (BCMCPU_IS_6328()) {
+		/* configure pinmux to sense VBUS signal */
+		val = bcm_gpio_readl(GPIO_PINMUX_OTHR_REG);
+		val &= ~GPIO_PINMUX_OTHR_6328_USB_MASK;
+		val |= is_device ? GPIO_PINMUX_OTHR_6328_USB_DEV :
+			       GPIO_PINMUX_OTHR_6328_USB_HOST;
+		bcm_gpio_writel(val, GPIO_PINMUX_OTHR_REG);
+	}
+
+	val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+	if (is_device) {
+		val |= (portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+		val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+	} else {
+		val &= ~(portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+		val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+	}
+	bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+
+	val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
+	if (is_device)
+		val |= USBH_PRIV_SWAP_USBD_MASK;
+	else
+		val &= ~USBH_PRIV_SWAP_USBD_MASK;
+	bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
+}
+
+/**
+ * bcm63xx_select_pullup - Enable/disable the pullup on D+
+ * @udc: Reference to the device controller.
+ * @is_on: true to enable the pullup, false to disable.
+ *
+ * If the pullup is active, the host will sense a FS/HS device connected to
+ * the port.  If the pullup is inactive, the host will think the USB
+ * device has been disconnected.
+ */
+static void bcm63xx_select_pullup(struct bcm63xx_udc *udc, bool is_on)
+{
+	u32 val, portmask = BIT(udc->pd->port_no);
+
+	val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+	if (is_on)
+		val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+	else
+		val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+	bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+}
+
+/**
+ * bcm63xx_uninit_udc_hw - Shut down the hardware prior to driver removal.
+ * @udc: Reference to the device controller.
+ *
+ * This just masks the IUDMA IRQs and releases the clocks.  It is assumed
+ * that bcm63xx_udc_stop() has already run, and the clocks are stopped.
+ */
+static void bcm63xx_uninit_udc_hw(struct bcm63xx_udc *udc)
+{
+	set_clocks(udc, true);
+	iudma_uninit(udc);
+	set_clocks(udc, false);
+
+	clk_put(udc->usbd_clk);
+	clk_put(udc->usbh_clk);
+}
+
+/**
+ * bcm63xx_init_udc_hw - Initialize the controller hardware and data structures.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)
+{
+	int i, rc = 0;
+	u32 val;
+
+	udc->ep0_ctrl_buf = devm_kzalloc(udc->dev, BCM63XX_MAX_CTRL_PKT,
+					 GFP_KERNEL);
+	if (!udc->ep0_ctrl_buf)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	for (i = 0; i < BCM63XX_NUM_EP; i++) {
+		struct bcm63xx_ep *bep = &udc->bep[i];
+
+		bep->ep.name = bcm63xx_ep_name[i];
+		bep->ep_num = i;
+		bep->ep.ops = &bcm63xx_udc_ep_ops;
+		list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);
+		bep->halted = 0;
+		bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT;
+		bep->udc = udc;
+		bep->ep.desc = NULL;
+		INIT_LIST_HEAD(&bep->queue);
+	}
+
+	udc->gadget.ep0 = &udc->bep[0].ep;
+	list_del(&udc->bep[0].ep.ep_list);
+
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->ep0state = EP0_SHUTDOWN;
+
+	udc->usbh_clk = clk_get(udc->dev, "usbh");
+	if (IS_ERR(udc->usbh_clk))
+		return -EIO;
+
+	udc->usbd_clk = clk_get(udc->dev, "usbd");
+	if (IS_ERR(udc->usbd_clk)) {
+		clk_put(udc->usbh_clk);
+		return -EIO;
+	}
+
+	set_clocks(udc, true);
+
+	val = USBD_CONTROL_AUTO_CSRS_MASK |
+	      USBD_CONTROL_DONE_CSRS_MASK |
+	      (irq_coalesce ? USBD_CONTROL_RXZSCFG_MASK : 0);
+	usbd_writel(udc, val, USBD_CONTROL_REG);
+
+	val = USBD_STRAPS_APP_SELF_PWR_MASK |
+	      USBD_STRAPS_APP_RAM_IF_MASK |
+	      USBD_STRAPS_APP_CSRPRGSUP_MASK |
+	      USBD_STRAPS_APP_8BITPHY_MASK |
+	      USBD_STRAPS_APP_RMTWKUP_MASK;
+
+	if (udc->gadget.max_speed == USB_SPEED_HIGH)
+		val |= (BCM63XX_SPD_HIGH << USBD_STRAPS_SPEED_SHIFT);
+	else
+		val |= (BCM63XX_SPD_FULL << USBD_STRAPS_SPEED_SHIFT);
+	usbd_writel(udc, val, USBD_STRAPS_REG);
+
+	bcm63xx_set_ctrl_irqs(udc, false);
+
+	usbd_writel(udc, 0, USBD_EVENT_IRQ_CFG_LO_REG);
+
+	val = USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_ENUM_ON) |
+	      USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_SET_CSRS);
+	usbd_writel(udc, val, USBD_EVENT_IRQ_CFG_HI_REG);
+
+	rc = iudma_init(udc);
+	set_clocks(udc, false);
+	if (rc)
+		bcm63xx_uninit_udc_hw(udc);
+
+	return 0;
+}
+
+/***********************************************************************
+ * Standard EP gadget operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep_enable - Enable one endpoint.
+ * @ep: Endpoint to enable.
+ * @desc: Contains max packet, direction, etc.
+ *
+ * Most of the endpoint parameters are fixed in this controller, so there
+ * isn't much for this function to do.
+ */
+static int bcm63xx_ep_enable(struct usb_ep *ep,
+	const struct usb_endpoint_descriptor *desc)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	struct iudma_ch *iudma = bep->iudma;
+	unsigned long flags;
+
+	if (!ep || !desc || ep->name == bcm63xx_ep0name)
+		return -EINVAL;
+
+	if (!udc->driver)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (iudma->enabled) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+
+	iudma->enabled = true;
+	BUG_ON(!list_empty(&bep->queue));
+
+	iudma_reset_channel(udc, iudma);
+
+	bep->halted = 0;
+	bcm63xx_set_stall(udc, bep, false);
+	clear_bit(bep->ep_num, &udc->wedgemap);
+
+	ep->desc = desc;
+	ep->maxpacket = usb_endpoint_maxp(desc);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/**
+ * bcm63xx_ep_disable - Disable one endpoint.
+ * @ep: Endpoint to disable.
+ */
+static int bcm63xx_ep_disable(struct usb_ep *ep)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	struct iudma_ch *iudma = bep->iudma;
+	struct list_head *pos, *n;
+	unsigned long flags;
+
+	if (!ep || !ep->desc)
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (!iudma->enabled) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+	iudma->enabled = false;
+
+	iudma_reset_channel(udc, iudma);
+
+	if (!list_empty(&bep->queue)) {
+		list_for_each_safe(pos, n, &bep->queue) {
+			struct bcm63xx_req *breq =
+				list_entry(pos, struct bcm63xx_req, queue);
+
+			usb_gadget_unmap_request(&udc->gadget, &breq->req,
+						 iudma->is_tx);
+			list_del(&breq->queue);
+			breq->req.status = -ESHUTDOWN;
+
+			spin_unlock_irqrestore(&udc->lock, flags);
+			breq->req.complete(&iudma->bep->ep, &breq->req);
+			spin_lock_irqsave(&udc->lock, flags);
+		}
+	}
+	ep->desc = NULL;
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/**
+ * bcm63xx_udc_alloc_request - Allocate a new request.
+ * @ep: Endpoint associated with the request.
+ * @mem_flags: Flags to pass to kzalloc().
+ */
+static struct usb_request *bcm63xx_udc_alloc_request(struct usb_ep *ep,
+	gfp_t mem_flags)
+{
+	struct bcm63xx_req *breq;
+
+	breq = kzalloc(sizeof(*breq), mem_flags);
+	if (!breq)
+		return NULL;
+	return &breq->req;
+}
+
+/**
+ * bcm63xx_udc_free_request - Free a request.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to free.
+ */
+static void bcm63xx_udc_free_request(struct usb_ep *ep,
+	struct usb_request *req)
+{
+	struct bcm63xx_req *breq = our_req(req);
+	kfree(breq);
+}
+
+/**
+ * bcm63xx_udc_queue - Queue up a new request.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to add.
+ * @mem_flags: Unused.
+ *
+ * If the queue is empty, start this request immediately.  Otherwise, add
+ * it to the list.
+ *
+ * ep0 replies are sent through this function from the gadget driver, but
+ * they are treated differently because they need to be handled by the ep0
+ * state machine.  (Sometimes they are replies to control requests that
+ * were spoofed by this driver, and so they shouldn't be transmitted at all.)
+ */
+static int bcm63xx_udc_queue(struct usb_ep *ep, struct usb_request *req,
+	gfp_t mem_flags)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	struct bcm63xx_req *breq = our_req(req);
+	unsigned long flags;
+	int rc = 0;
+
+	if (unlikely(!req || !req->complete || !req->buf || !ep))
+		return -EINVAL;
+
+	req->actual = 0;
+	req->status = 0;
+	breq->offset = 0;
+
+	if (bep == &udc->bep[0]) {
+		/* only one reply per request, please */
+		if (udc->ep0_reply)
+			return -EINVAL;
+
+		udc->ep0_reply = req;
+		schedule_work(&udc->ep0_wq);
+		return 0;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (!bep->iudma->enabled) {
+		rc = -ESHUTDOWN;
+		goto out;
+	}
+
+	rc = usb_gadget_map_request(&udc->gadget, req, bep->iudma->is_tx);
+	if (rc == 0) {
+		list_add_tail(&breq->queue, &bep->queue);
+		if (list_is_singular(&bep->queue))
+			iudma_write(udc, bep->iudma, breq);
+	}
+
+out:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return rc;
+}
+
+/**
+ * bcm63xx_udc_dequeue - Remove a pending request from the queue.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to remove.
+ *
+ * If the request is not at the head of the queue, this is easy - just nuke
+ * it.  If the request is at the head of the queue, we'll need to stop the
+ * DMA transaction and then queue up the successor.
+ */
+static int bcm63xx_udc_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	struct bcm63xx_req *breq = our_req(req), *cur;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (list_empty(&bep->queue)) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	cur = list_first_entry(&bep->queue, struct bcm63xx_req, queue);
+	usb_gadget_unmap_request(&udc->gadget, &breq->req, bep->iudma->is_tx);
+
+	if (breq == cur) {
+		iudma_reset_channel(udc, bep->iudma);
+		list_del(&breq->queue);
+
+		if (!list_empty(&bep->queue)) {
+			struct bcm63xx_req *next;
+
+			next = list_first_entry(&bep->queue,
+				struct bcm63xx_req, queue);
+			iudma_write(udc, bep->iudma, next);
+		}
+	} else {
+		list_del(&breq->queue);
+	}
+
+out:
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	req->status = -ESHUTDOWN;
+	req->complete(ep, req);
+
+	return rc;
+}
+
+/**
+ * bcm63xx_udc_set_halt - Enable/disable STALL flag in the hardware.
+ * @ep: Endpoint to halt.
+ * @value: Zero to clear halt; nonzero to set halt.
+ *
+ * See comments in bcm63xx_update_wedge().
+ */
+static int bcm63xx_udc_set_halt(struct usb_ep *ep, int value)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	bcm63xx_set_stall(udc, bep, !!value);
+	bep->halted = value;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/**
+ * bcm63xx_udc_set_wedge - Stall the endpoint until the next reset.
+ * @ep: Endpoint to wedge.
+ *
+ * See comments in bcm63xx_update_wedge().
+ */
+static int bcm63xx_udc_set_wedge(struct usb_ep *ep)
+{
+	struct bcm63xx_ep *bep = our_ep(ep);
+	struct bcm63xx_udc *udc = bep->udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	set_bit(bep->ep_num, &udc->wedgemap);
+	bcm63xx_set_stall(udc, bep, true);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_ep_ops bcm63xx_udc_ep_ops = {
+	.enable		= bcm63xx_ep_enable,
+	.disable	= bcm63xx_ep_disable,
+
+	.alloc_request	= bcm63xx_udc_alloc_request,
+	.free_request	= bcm63xx_udc_free_request,
+
+	.queue		= bcm63xx_udc_queue,
+	.dequeue	= bcm63xx_udc_dequeue,
+
+	.set_halt	= bcm63xx_udc_set_halt,
+	.set_wedge	= bcm63xx_udc_set_wedge,
+};
+
+/***********************************************************************
+ * EP0 handling
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep0_setup_callback - Drop spinlock to invoke ->setup callback.
+ * @udc: Reference to the device controller.
+ * @ctrl: 8-byte SETUP request.
+ */
+static int bcm63xx_ep0_setup_callback(struct bcm63xx_udc *udc,
+	struct usb_ctrlrequest *ctrl)
+{
+	int rc;
+
+	spin_unlock_irq(&udc->lock);
+	rc = udc->driver->setup(&udc->gadget, ctrl);
+	spin_lock_irq(&udc->lock);
+	return rc;
+}
+
+/**
+ * bcm63xx_ep0_spoof_set_cfg - Synthesize a SET_CONFIGURATION request.
+ * @udc: Reference to the device controller.
+ *
+ * Many standard requests are handled automatically in the hardware, but
+ * we still need to pass them to the gadget driver so that it can
+ * reconfigure the interfaces/endpoints if necessary.
+ *
+ * Unfortunately we are not able to send a STALL response if the host
+ * requests an invalid configuration.  If this happens, we'll have to be
+ * content with printing a warning.
+ */
+static int bcm63xx_ep0_spoof_set_cfg(struct bcm63xx_udc *udc)
+{
+	struct usb_ctrlrequest ctrl;
+	int rc;
+
+	ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_DEVICE;
+	ctrl.bRequest = USB_REQ_SET_CONFIGURATION;
+	ctrl.wValue = cpu_to_le16(udc->cfg);
+	ctrl.wIndex = 0;
+	ctrl.wLength = 0;
+
+	rc = bcm63xx_ep0_setup_callback(udc, &ctrl);
+	if (rc < 0) {
+		dev_warn_ratelimited(udc->dev,
+			"hardware auto-acked bad SET_CONFIGURATION(%d) request\n",
+			udc->cfg);
+	}
+	return rc;
+}
+
+/**
+ * bcm63xx_ep0_spoof_set_iface - Synthesize a SET_INTERFACE request.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_ep0_spoof_set_iface(struct bcm63xx_udc *udc)
+{
+	struct usb_ctrlrequest ctrl;
+	int rc;
+
+	ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_INTERFACE;
+	ctrl.bRequest = USB_REQ_SET_INTERFACE;
+	ctrl.wValue = cpu_to_le16(udc->alt_iface);
+	ctrl.wIndex = cpu_to_le16(udc->iface);
+	ctrl.wLength = 0;
+
+	rc = bcm63xx_ep0_setup_callback(udc, &ctrl);
+	if (rc < 0) {
+		dev_warn_ratelimited(udc->dev,
+			"hardware auto-acked bad SET_INTERFACE(%d,%d) request\n",
+			udc->iface, udc->alt_iface);
+	}
+	return rc;
+}
+
+/**
+ * bcm63xx_ep0_map_write - dma_map and iudma_write a single request.
+ * @udc: Reference to the device controller.
+ * @ch_idx: IUDMA channel number.
+ * @req: USB gadget layer representation of the request.
+ */
+static void bcm63xx_ep0_map_write(struct bcm63xx_udc *udc, int ch_idx,
+	struct usb_request *req)
+{
+	struct bcm63xx_req *breq = our_req(req);
+	struct iudma_ch *iudma = &udc->iudma[ch_idx];
+
+	BUG_ON(udc->ep0_request);
+	udc->ep0_request = req;
+
+	req->actual = 0;
+	breq->offset = 0;
+	usb_gadget_map_request(&udc->gadget, req, iudma->is_tx);
+	iudma_write(udc, iudma, breq);
+}
+
+/**
+ * bcm63xx_ep0_complete - Set completion status and "stage" the callback.
+ * @udc: Reference to the device controller.
+ * @req: USB gadget layer representation of the request.
+ * @status: Status to return to the gadget driver.
+ */
+static void bcm63xx_ep0_complete(struct bcm63xx_udc *udc,
+	struct usb_request *req, int status)
+{
+	req->status = status;
+	if (status)
+		req->actual = 0;
+	if (req->complete) {
+		spin_unlock_irq(&udc->lock);
+		req->complete(&udc->bep[0].ep, req);
+		spin_lock_irq(&udc->lock);
+	}
+}
+
+/**
+ * bcm63xx_ep0_nuke_reply - Abort request from the gadget driver due to
+ *   reset/shutdown.
+ * @udc: Reference to the device controller.
+ * @is_tx: Nonzero for TX (IN), zero for RX (OUT).
+ */
+static void bcm63xx_ep0_nuke_reply(struct bcm63xx_udc *udc, int is_tx)
+{
+	struct usb_request *req = udc->ep0_reply;
+
+	udc->ep0_reply = NULL;
+	usb_gadget_unmap_request(&udc->gadget, req, is_tx);
+	if (udc->ep0_request == req) {
+		udc->ep0_req_completed = 0;
+		udc->ep0_request = NULL;
+	}
+	bcm63xx_ep0_complete(udc, req, -ESHUTDOWN);
+}
+
+/**
+ * bcm63xx_ep0_read_complete - Close out the pending ep0 request; return
+ *   transfer len.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_ep0_read_complete(struct bcm63xx_udc *udc)
+{
+	struct usb_request *req = udc->ep0_request;
+
+	udc->ep0_req_completed = 0;
+	udc->ep0_request = NULL;
+
+	return req->actual;
+}
+
+/**
+ * bcm63xx_ep0_internal_request - Helper function to submit an ep0 request.
+ * @udc: Reference to the device controller.
+ * @ch_idx: IUDMA channel number.
+ * @length: Number of bytes to TX/RX.
+ *
+ * Used for simple transfers performed by the ep0 worker.  This will always
+ * use ep0_ctrl_req / ep0_ctrl_buf.
+ */
+static void bcm63xx_ep0_internal_request(struct bcm63xx_udc *udc, int ch_idx,
+	int length)
+{
+	struct usb_request *req = &udc->ep0_ctrl_req.req;
+
+	req->buf = udc->ep0_ctrl_buf;
+	req->length = length;
+	req->complete = NULL;
+
+	bcm63xx_ep0_map_write(udc, ch_idx, req);
+}
+
+/**
+ * bcm63xx_ep0_do_setup - Parse new SETUP packet and decide how to handle it.
+ * @udc: Reference to the device controller.
+ *
+ * EP0_IDLE probably shouldn't ever happen.  EP0_REQUEUE means we're ready
+ * for the next packet.  Anything else means the transaction requires multiple
+ * stages of handling.
+ */
+static enum bcm63xx_ep0_state bcm63xx_ep0_do_setup(struct bcm63xx_udc *udc)
+{
+	int rc;
+	struct usb_ctrlrequest *ctrl = (void *)udc->ep0_ctrl_buf;
+
+	rc = bcm63xx_ep0_read_complete(udc);
+
+	if (rc < 0) {
+		dev_err(udc->dev, "missing SETUP packet\n");
+		return EP0_IDLE;
+	}
+
+	/*
+	 * Handle 0-byte IN STATUS acknowledgement.  The hardware doesn't
+	 * ALWAYS deliver these 100% of the time, so if we happen to see one,
+	 * just throw it away.
+	 */
+	if (rc == 0)
+		return EP0_REQUEUE;
+
+	/* Drop malformed SETUP packets */
+	if (rc != sizeof(*ctrl)) {
+		dev_warn_ratelimited(udc->dev,
+			"malformed SETUP packet (%d bytes)\n", rc);
+		return EP0_REQUEUE;
+	}
+
+	/* Process new SETUP packet arriving on ep0 */
+	rc = bcm63xx_ep0_setup_callback(udc, ctrl);
+	if (rc < 0) {
+		bcm63xx_set_stall(udc, &udc->bep[0], true);
+		return EP0_REQUEUE;
+	}
+
+	if (!ctrl->wLength)
+		return EP0_REQUEUE;
+	else if (ctrl->bRequestType & USB_DIR_IN)
+		return EP0_IN_DATA_PHASE_SETUP;
+	else
+		return EP0_OUT_DATA_PHASE_SETUP;
+}
+
+/**
+ * bcm63xx_ep0_do_idle - Check for outstanding requests if ep0 is idle.
+ * @udc: Reference to the device controller.
+ *
+ * In state EP0_IDLE, the RX descriptor is either pending, or has been
+ * filled with a SETUP packet from the host.  This function handles new
+ * SETUP packets, control IRQ events (which can generate fake SETUP packets),
+ * and reset/shutdown events.
+ *
+ * Returns 0 if work was done; -EAGAIN if nothing to do.
+ */
+static int bcm63xx_ep0_do_idle(struct bcm63xx_udc *udc)
+{
+	if (udc->ep0_req_reset) {
+		udc->ep0_req_reset = 0;
+	} else if (udc->ep0_req_set_cfg) {
+		udc->ep0_req_set_cfg = 0;
+		if (bcm63xx_ep0_spoof_set_cfg(udc) >= 0)
+			udc->ep0state = EP0_IN_FAKE_STATUS_PHASE;
+	} else if (udc->ep0_req_set_iface) {
+		udc->ep0_req_set_iface = 0;
+		if (bcm63xx_ep0_spoof_set_iface(udc) >= 0)
+			udc->ep0state = EP0_IN_FAKE_STATUS_PHASE;
+	} else if (udc->ep0_req_completed) {
+		udc->ep0state = bcm63xx_ep0_do_setup(udc);
+		return udc->ep0state == EP0_IDLE ? -EAGAIN : 0;
+	} else if (udc->ep0_req_shutdown) {
+		udc->ep0_req_shutdown = 0;
+		udc->ep0_req_completed = 0;
+		udc->ep0_request = NULL;
+		iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]);
+		usb_gadget_unmap_request(&udc->gadget,
+			&udc->ep0_ctrl_req.req, 0);
+
+		/* bcm63xx_udc_pullup() is waiting for this */
+		mb();
+		udc->ep0state = EP0_SHUTDOWN;
+	} else if (udc->ep0_reply) {
+		/*
+		 * This could happen if a USB RESET shows up during an ep0
+		 * transaction (especially if a laggy driver like gadgetfs
+		 * is in use).
+		 */
+		dev_warn(udc->dev, "nuking unexpected reply\n");
+		bcm63xx_ep0_nuke_reply(udc, 0);
+	} else {
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/**
+ * bcm63xx_ep0_one_round - Handle the current ep0 state.
+ * @udc: Reference to the device controller.
+ *
+ * Returns 0 if work was done; -EAGAIN if nothing to do.
+ */
+static int bcm63xx_ep0_one_round(struct bcm63xx_udc *udc)
+{
+	enum bcm63xx_ep0_state ep0state = udc->ep0state;
+	bool shutdown = udc->ep0_req_reset || udc->ep0_req_shutdown;
+
+	switch (udc->ep0state) {
+	case EP0_REQUEUE:
+		/* set up descriptor to receive SETUP packet */
+		bcm63xx_ep0_internal_request(udc, IUDMA_EP0_RXCHAN,
+					     BCM63XX_MAX_CTRL_PKT);
+		ep0state = EP0_IDLE;
+		break;
+	case EP0_IDLE:
+		return bcm63xx_ep0_do_idle(udc);
+	case EP0_IN_DATA_PHASE_SETUP:
+		/*
+		 * Normal case: TX request is in ep0_reply (queued by the
+		 * callback), or will be queued shortly.  When it's here,
+		 * send it to the HW and go to EP0_IN_DATA_PHASE_COMPLETE.
+		 *
+		 * Shutdown case: Stop waiting for the reply.  Just
+		 * REQUEUE->IDLE.  The gadget driver is NOT expected to
+		 * queue anything else now.
+		 */
+		if (udc->ep0_reply) {
+			bcm63xx_ep0_map_write(udc, IUDMA_EP0_TXCHAN,
+					      udc->ep0_reply);
+			ep0state = EP0_IN_DATA_PHASE_COMPLETE;
+		} else if (shutdown) {
+			ep0state = EP0_REQUEUE;
+		}
+		break;
+	case EP0_IN_DATA_PHASE_COMPLETE: {
+		/*
+		 * Normal case: TX packet (ep0_reply) is in flight; wait for
+		 * it to finish, then go back to REQUEUE->IDLE.
+		 *
+		 * Shutdown case: Reset the TX channel, send -ESHUTDOWN
+		 * completion to the gadget driver, then REQUEUE->IDLE.
+		 */
+		if (udc->ep0_req_completed) {
+			udc->ep0_reply = NULL;
+			bcm63xx_ep0_read_complete(udc);
+			/*
+			 * the "ack" sometimes gets eaten (see
+			 * bcm63xx_ep0_do_idle)
+			 */
+			ep0state = EP0_REQUEUE;
+		} else if (shutdown) {
+			iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]);
+			bcm63xx_ep0_nuke_reply(udc, 1);
+			ep0state = EP0_REQUEUE;
+		}
+		break;
+	}
+	case EP0_OUT_DATA_PHASE_SETUP:
+		/* Similar behavior to EP0_IN_DATA_PHASE_SETUP */
+		if (udc->ep0_reply) {
+			bcm63xx_ep0_map_write(udc, IUDMA_EP0_RXCHAN,
+					      udc->ep0_reply);
+			ep0state = EP0_OUT_DATA_PHASE_COMPLETE;
+		} else if (shutdown) {
+			ep0state = EP0_REQUEUE;
+		}
+		break;
+	case EP0_OUT_DATA_PHASE_COMPLETE: {
+		/* Similar behavior to EP0_IN_DATA_PHASE_COMPLETE */
+		if (udc->ep0_req_completed) {
+			udc->ep0_reply = NULL;
+			bcm63xx_ep0_read_complete(udc);
+
+			/* send 0-byte ack to host */
+			bcm63xx_ep0_internal_request(udc, IUDMA_EP0_TXCHAN, 0);
+			ep0state = EP0_OUT_STATUS_PHASE;
+		} else if (shutdown) {
+			iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]);
+			bcm63xx_ep0_nuke_reply(udc, 0);
+			ep0state = EP0_REQUEUE;
+		}
+		break;
+	}
+	case EP0_OUT_STATUS_PHASE:
+		/*
+		 * Normal case: 0-byte OUT ack packet is in flight; wait
+		 * for it to finish, then go back to REQUEUE->IDLE.
+		 *
+		 * Shutdown case: just cancel the transmission.  Don't bother
+		 * calling the completion, because it originated from this
+		 * function anyway.  Then go back to REQUEUE->IDLE.
+		 */
+		if (udc->ep0_req_completed) {
+			bcm63xx_ep0_read_complete(udc);
+			ep0state = EP0_REQUEUE;
+		} else if (shutdown) {
+			iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]);
+			udc->ep0_request = NULL;
+			ep0state = EP0_REQUEUE;
+		}
+		break;
+	case EP0_IN_FAKE_STATUS_PHASE: {
+		/*
+		 * Normal case: we spoofed a SETUP packet and are now
+		 * waiting for the gadget driver to send a 0-byte reply.
+		 * This doesn't actually get sent to the HW because the
+		 * HW has already sent its own reply.  Once we get the
+		 * response, return to IDLE.
+		 *
+		 * Shutdown case: return to IDLE immediately.
+		 *
+		 * Note that the ep0 RX descriptor has remained queued
+		 * (and possibly unfilled) during this entire transaction.
+		 * The HW datapath (IUDMA) never even sees SET_CONFIGURATION
+		 * or SET_INTERFACE transactions.
+		 */
+		struct usb_request *r = udc->ep0_reply;
+
+		if (!r) {
+			if (shutdown)
+				ep0state = EP0_IDLE;
+			break;
+		}
+
+		bcm63xx_ep0_complete(udc, r, 0);
+		udc->ep0_reply = NULL;
+		ep0state = EP0_IDLE;
+		break;
+	}
+	case EP0_SHUTDOWN:
+		break;
+	}
+
+	if (udc->ep0state == ep0state)
+		return -EAGAIN;
+
+	udc->ep0state = ep0state;
+	return 0;
+}
+
+/**
+ * bcm63xx_ep0_process - ep0 worker thread / state machine.
+ * @w: Workqueue struct.
+ *
+ * bcm63xx_ep0_process is triggered any time an event occurs on ep0.  It
+ * is used to synchronize ep0 events and ensure that both HW and SW events
+ * occur in a well-defined order.  When the ep0 IUDMA queues are idle, it may
+ * synthesize SET_CONFIGURATION / SET_INTERFACE requests that were consumed
+ * by the USBD hardware.
+ *
+ * The worker function will continue iterating around the state machine
+ * until there is nothing left to do.  Usually "nothing left to do" means
+ * that we're waiting for a new event from the hardware.
+ */
+static void bcm63xx_ep0_process(struct work_struct *w)
+{
+	struct bcm63xx_udc *udc = container_of(w, struct bcm63xx_udc, ep0_wq);
+	spin_lock_irq(&udc->lock);
+	while (bcm63xx_ep0_one_round(udc) == 0)
+		;
+	spin_unlock_irq(&udc->lock);
+}
+
+/***********************************************************************
+ * Standard UDC gadget operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_udc_get_frame - Read current SOF frame number from the HW.
+ * @gadget: USB slave device.
+ */
+static int bcm63xx_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+
+	return (usbd_readl(udc, USBD_STATUS_REG) &
+		USBD_STATUS_SOF_MASK) >> USBD_STATUS_SOF_SHIFT;
+}
+
+/**
+ * bcm63xx_udc_pullup - Enable/disable pullup on D+ line.
+ * @gadget: USB slave device.
+ * @is_on: 0 to disable pullup, 1 to enable.
+ *
+ * See notes in bcm63xx_select_pullup().
+ */
+static int bcm63xx_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+	unsigned long flags;
+	int i, rc = -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (is_on && udc->ep0state == EP0_SHUTDOWN) {
+		udc->gadget.speed = USB_SPEED_UNKNOWN;
+		udc->ep0state = EP0_REQUEUE;
+		bcm63xx_fifo_setup(udc);
+		bcm63xx_fifo_reset(udc);
+		bcm63xx_ep_setup(udc);
+
+		bitmap_zero(&udc->wedgemap, BCM63XX_NUM_EP);
+		for (i = 0; i < BCM63XX_NUM_EP; i++)
+			bcm63xx_set_stall(udc, &udc->bep[i], false);
+
+		bcm63xx_set_ctrl_irqs(udc, true);
+		bcm63xx_select_pullup(gadget_to_udc(gadget), true);
+		rc = 0;
+	} else if (!is_on && udc->ep0state != EP0_SHUTDOWN) {
+		bcm63xx_select_pullup(gadget_to_udc(gadget), false);
+
+		udc->ep0_req_shutdown = 1;
+		spin_unlock_irqrestore(&udc->lock, flags);
+
+		while (1) {
+			schedule_work(&udc->ep0_wq);
+			if (udc->ep0state == EP0_SHUTDOWN)
+				break;
+			msleep(50);
+		}
+		bcm63xx_set_ctrl_irqs(udc, false);
+		cancel_work_sync(&udc->ep0_wq);
+		return 0;
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return rc;
+}
+
+/**
+ * bcm63xx_udc_start - Start the controller.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ */
+static int bcm63xx_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+	unsigned long flags;
+
+	if (!driver || driver->max_speed < USB_SPEED_HIGH ||
+	    !driver->setup)
+		return -EINVAL;
+	if (!udc)
+		return -ENODEV;
+	if (udc->driver)
+		return -EBUSY;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	set_clocks(udc, true);
+	bcm63xx_fifo_setup(udc);
+	bcm63xx_ep_init(udc);
+	bcm63xx_ep_setup(udc);
+	bcm63xx_fifo_reset(udc);
+	bcm63xx_select_phy_mode(udc, true);
+
+	udc->driver = driver;
+	driver->driver.bus = NULL;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.dev.of_node = udc->dev->of_node;
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/**
+ * bcm63xx_udc_stop - Shut down the controller.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ */
+static int bcm63xx_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+
+	/*
+	 * If we switch the PHY too abruptly after dropping D+, the host
+	 * will often complain:
+	 *
+	 *     hub 1-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
+	 */
+	msleep(100);
+
+	bcm63xx_select_phy_mode(udc, false);
+	set_clocks(udc, false);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops bcm63xx_udc_ops = {
+	.get_frame	= bcm63xx_udc_get_frame,
+	.pullup		= bcm63xx_udc_pullup,
+	.udc_start	= bcm63xx_udc_start,
+	.udc_stop	= bcm63xx_udc_stop,
+};
+
+/***********************************************************************
+ * IRQ handling
+ ***********************************************************************/
+
+/**
+ * bcm63xx_update_cfg_iface - Read current configuration/interface settings.
+ * @udc: Reference to the device controller.
+ *
+ * This controller intercepts SET_CONFIGURATION and SET_INTERFACE messages.
+ * The driver never sees the raw control packets coming in on the ep0
+ * IUDMA channel, but at least we get an interrupt event to tell us that
+ * new values are waiting in the USBD_STATUS register.
+ */
+static void bcm63xx_update_cfg_iface(struct bcm63xx_udc *udc)
+{
+	u32 reg = usbd_readl(udc, USBD_STATUS_REG);
+
+	udc->cfg = (reg & USBD_STATUS_CFG_MASK) >> USBD_STATUS_CFG_SHIFT;
+	udc->iface = (reg & USBD_STATUS_INTF_MASK) >> USBD_STATUS_INTF_SHIFT;
+	udc->alt_iface = (reg & USBD_STATUS_ALTINTF_MASK) >>
+			 USBD_STATUS_ALTINTF_SHIFT;
+	bcm63xx_ep_setup(udc);
+}
+
+/**
+ * bcm63xx_update_link_speed - Check to see if the link speed has changed.
+ * @udc: Reference to the device controller.
+ *
+ * The link speed update coincides with a SETUP IRQ.  Returns 1 if the
+ * speed has changed, so that the caller can update the endpoint settings.
+ */
+static int bcm63xx_update_link_speed(struct bcm63xx_udc *udc)
+{
+	u32 reg = usbd_readl(udc, USBD_STATUS_REG);
+	enum usb_device_speed oldspeed = udc->gadget.speed;
+
+	switch ((reg & USBD_STATUS_SPD_MASK) >> USBD_STATUS_SPD_SHIFT) {
+	case BCM63XX_SPD_HIGH:
+		udc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case BCM63XX_SPD_FULL:
+		udc->gadget.speed = USB_SPEED_FULL;
+		break;
+	default:
+		/* this should never happen */
+		udc->gadget.speed = USB_SPEED_UNKNOWN;
+		dev_err(udc->dev,
+			"received SETUP packet with invalid link speed\n");
+		return 0;
+	}
+
+	if (udc->gadget.speed != oldspeed) {
+		dev_info(udc->dev, "link up, %s-speed mode\n",
+			 udc->gadget.speed == USB_SPEED_HIGH ? "high" : "full");
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * bcm63xx_update_wedge - Iterate through wedged endpoints.
+ * @udc: Reference to the device controller.
+ * @new_status: true to "refresh" wedge status; false to clear it.
+ *
+ * On a SETUP interrupt, we need to manually "refresh" the wedge status
+ * because the controller hardware is designed to automatically clear
+ * stalls in response to a CLEAR_FEATURE request from the host.
+ *
+ * On a RESET interrupt, we do want to restore all wedged endpoints.
+ */
+static void bcm63xx_update_wedge(struct bcm63xx_udc *udc, bool new_status)
+{
+	int i;
+
+	for_each_set_bit(i, &udc->wedgemap, BCM63XX_NUM_EP) {
+		bcm63xx_set_stall(udc, &udc->bep[i], new_status);
+		if (!new_status)
+			clear_bit(i, &udc->wedgemap);
+	}
+}
+
+/**
+ * bcm63xx_udc_ctrl_isr - ISR for control path events (USBD).
+ * @irq: IRQ number (unused).
+ * @dev_id: Reference to the device controller.
+ *
+ * This is where we handle link (VBUS) down, USB reset, speed changes,
+ * SET_CONFIGURATION, and SET_INTERFACE events.
+ */
+static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id)
+{
+	struct bcm63xx_udc *udc = dev_id;
+	u32 stat;
+	bool disconnected = false;
+
+	stat = usbd_readl(udc, USBD_EVENT_IRQ_STATUS_REG) &
+	       usbd_readl(udc, USBD_EVENT_IRQ_MASK_REG);
+
+	usbd_writel(udc, stat, USBD_EVENT_IRQ_STATUS_REG);
+
+	spin_lock(&udc->lock);
+	if (stat & BIT(USBD_EVENT_IRQ_USB_LINK)) {
+		/* VBUS toggled */
+
+		if (!(usbd_readl(udc, USBD_EVENTS_REG) &
+		      USBD_EVENTS_USB_LINK_MASK) &&
+		      udc->gadget.speed != USB_SPEED_UNKNOWN)
+			dev_info(udc->dev, "link down\n");
+
+		udc->gadget.speed = USB_SPEED_UNKNOWN;
+		disconnected = true;
+	}
+	if (stat & BIT(USBD_EVENT_IRQ_USB_RESET)) {
+		bcm63xx_fifo_setup(udc);
+		bcm63xx_fifo_reset(udc);
+		bcm63xx_ep_setup(udc);
+
+		bcm63xx_update_wedge(udc, false);
+
+		udc->ep0_req_reset = 1;
+		schedule_work(&udc->ep0_wq);
+		disconnected = true;
+	}
+	if (stat & BIT(USBD_EVENT_IRQ_SETUP)) {
+		if (bcm63xx_update_link_speed(udc)) {
+			bcm63xx_fifo_setup(udc);
+			bcm63xx_ep_setup(udc);
+		}
+		bcm63xx_update_wedge(udc, true);
+	}
+	if (stat & BIT(USBD_EVENT_IRQ_SETCFG)) {
+		bcm63xx_update_cfg_iface(udc);
+		udc->ep0_req_set_cfg = 1;
+		schedule_work(&udc->ep0_wq);
+	}
+	if (stat & BIT(USBD_EVENT_IRQ_SETINTF)) {
+		bcm63xx_update_cfg_iface(udc);
+		udc->ep0_req_set_iface = 1;
+		schedule_work(&udc->ep0_wq);
+	}
+	spin_unlock(&udc->lock);
+
+	if (disconnected && udc->driver)
+		udc->driver->disconnect(&udc->gadget);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * bcm63xx_udc_data_isr - ISR for data path events (IUDMA).
+ * @irq: IRQ number (unused).
+ * @dev_id: Reference to the IUDMA channel that generated the interrupt.
+ *
+ * For the two ep0 channels, we have special handling that triggers the
+ * ep0 worker thread.  For normal bulk/intr channels, either queue up
+ * the next buffer descriptor for the transaction (incomplete transaction),
+ * or invoke the completion callback (complete transactions).
+ */
+static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)
+{
+	struct iudma_ch *iudma = dev_id;
+	struct bcm63xx_udc *udc = iudma->udc;
+	struct bcm63xx_ep *bep;
+	struct usb_request *req = NULL;
+	struct bcm63xx_req *breq = NULL;
+	int rc;
+	bool is_done = false;
+
+	spin_lock(&udc->lock);
+
+	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
+			ENETDMAC_IR_REG(iudma->ch_idx));
+	bep = iudma->bep;
+	rc = iudma_read(udc, iudma);
+
+	/* special handling for EP0 RX (0) and TX (1) */
+	if (iudma->ch_idx == IUDMA_EP0_RXCHAN ||
+	    iudma->ch_idx == IUDMA_EP0_TXCHAN) {
+		req = udc->ep0_request;
+		breq = our_req(req);
+
+		/* a single request could require multiple submissions */
+		if (rc >= 0) {
+			req->actual += rc;
+
+			if (req->actual >= req->length || breq->bd_bytes > rc) {
+				udc->ep0_req_completed = 1;
+				is_done = true;
+				schedule_work(&udc->ep0_wq);
+
+				/* "actual" on a ZLP is 1 byte */
+				req->actual = min(req->actual, req->length);
+			} else {
+				/* queue up the next BD (same request) */
+				iudma_write(udc, iudma, breq);
+			}
+		}
+	} else if (!list_empty(&bep->queue)) {
+		breq = list_first_entry(&bep->queue, struct bcm63xx_req, queue);
+		req = &breq->req;
+
+		if (rc >= 0) {
+			req->actual += rc;
+
+			if (req->actual >= req->length || breq->bd_bytes > rc) {
+				is_done = true;
+				list_del(&breq->queue);
+
+				req->actual = min(req->actual, req->length);
+
+				if (!list_empty(&bep->queue)) {
+					struct bcm63xx_req *next;
+
+					next = list_first_entry(&bep->queue,
+						struct bcm63xx_req, queue);
+					iudma_write(udc, iudma, next);
+				}
+			} else {
+				iudma_write(udc, iudma, breq);
+			}
+		}
+	}
+	spin_unlock(&udc->lock);
+
+	if (is_done) {
+		usb_gadget_unmap_request(&udc->gadget, req, iudma->is_tx);
+		if (req->complete)
+			req->complete(&bep->ep, req);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/***********************************************************************
+ * Debug filesystem
+ ***********************************************************************/
+
+/*
+ * bcm63xx_usbd_dbg_show - Show USBD controller state.
+ * @s: seq_file to which the information will be written.
+ * @p: Unused.
+ *
+ * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/usbd
+ */
+static int bcm63xx_usbd_dbg_show(struct seq_file *s, void *p)
+{
+	struct bcm63xx_udc *udc = s->private;
+
+	if (!udc->driver)
+		return -ENODEV;
+
+	seq_printf(s, "ep0 state: %s\n",
+		   bcm63xx_ep0_state_names[udc->ep0state]);
+	seq_printf(s, "  pending requests: %s%s%s%s%s%s%s\n",
+		   udc->ep0_req_reset ? "reset " : "",
+		   udc->ep0_req_set_cfg ? "set_cfg " : "",
+		   udc->ep0_req_set_iface ? "set_iface " : "",
+		   udc->ep0_req_shutdown ? "shutdown " : "",
+		   udc->ep0_request ? "pending " : "",
+		   udc->ep0_req_completed ? "completed " : "",
+		   udc->ep0_reply ? "reply " : "");
+	seq_printf(s, "cfg: %d; iface: %d; alt_iface: %d\n",
+		   udc->cfg, udc->iface, udc->alt_iface);
+	seq_printf(s, "regs:\n");
+	seq_printf(s, "  control: %08x; straps: %08x; status: %08x\n",
+		   usbd_readl(udc, USBD_CONTROL_REG),
+		   usbd_readl(udc, USBD_STRAPS_REG),
+		   usbd_readl(udc, USBD_STATUS_REG));
+	seq_printf(s, "  events:  %08x; stall:  %08x\n",
+		   usbd_readl(udc, USBD_EVENTS_REG),
+		   usbd_readl(udc, USBD_STALL_REG));
+
+	return 0;
+}
+
+/*
+ * bcm63xx_iudma_dbg_show - Show IUDMA status and descriptors.
+ * @s: seq_file to which the information will be written.
+ * @p: Unused.
+ *
+ * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/iudma
+ */
+static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
+{
+	struct bcm63xx_udc *udc = s->private;
+	int ch_idx, i;
+	u32 sram2, sram3;
+
+	if (!udc->driver)
+		return -ENODEV;
+
+	for (ch_idx = 0; ch_idx < BCM63XX_NUM_IUDMA; ch_idx++) {
+		struct iudma_ch *iudma = &udc->iudma[ch_idx];
+		struct list_head *pos;
+
+		seq_printf(s, "IUDMA channel %d -- ", ch_idx);
+		switch (iudma_defaults[ch_idx].ep_type) {
+		case BCMEP_CTRL:
+			seq_printf(s, "control");
+			break;
+		case BCMEP_BULK:
+			seq_printf(s, "bulk");
+			break;
+		case BCMEP_INTR:
+			seq_printf(s, "interrupt");
+			break;
+		}
+		seq_printf(s, ch_idx & 0x01 ? " tx" : " rx");
+		seq_printf(s, " [ep%d]:\n",
+			   max_t(int, iudma_defaults[ch_idx].ep_num, 0));
+		seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n",
+			   usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)),
+			   usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)),
+			   usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)),
+			   usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx)));
+
+		sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx));
+		sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx));
+		seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n",
+			   usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)),
+			   sram2 >> 16, sram2 & 0xffff,
+			   sram3 >> 16, sram3 & 0xffff,
+			   usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx)));
+		seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,
+			   iudma->n_bds);
+
+		if (iudma->bep) {
+			i = 0;
+			list_for_each(pos, &iudma->bep->queue)
+				i++;
+			seq_printf(s, "; %d queued\n", i);
+		} else {
+			seq_printf(s, "\n");
+		}
+
+		for (i = 0; i < iudma->n_bds; i++) {
+			struct bcm_enet_desc *d = &iudma->bd_ring[i];
+
+			seq_printf(s, "  %03x (%02x): len_stat: %04x_%04x; pa %08x",
+				   i * sizeof(*d), i,
+				   d->len_stat >> 16, d->len_stat & 0xffff,
+				   d->address);
+			if (d == iudma->read_bd)
+				seq_printf(s, "   <<RD");
+			if (d == iudma->write_bd)
+				seq_printf(s, "   <<WR");
+			seq_printf(s, "\n");
+		}
+
+		seq_printf(s, "\n");
+	}
+
+	return 0;
+}
+
+static int bcm63xx_usbd_dbg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, bcm63xx_usbd_dbg_show, inode->i_private);
+}
+
+static int bcm63xx_iudma_dbg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, bcm63xx_iudma_dbg_show, inode->i_private);
+}
+
+static const struct file_operations usbd_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= bcm63xx_usbd_dbg_open,
+	.llseek		= seq_lseek,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static const struct file_operations iudma_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= bcm63xx_iudma_dbg_open,
+	.llseek		= seq_lseek,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+
+/**
+ * bcm63xx_udc_init_debugfs - Create debugfs entries.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
+{
+	struct dentry *root, *usbd, *iudma;
+
+	if (!IS_ENABLED(CONFIG_USB_GADGET_DEBUG_FS))
+		return;
+
+	root = debugfs_create_dir(udc->gadget.name, NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+
+	usbd = debugfs_create_file("usbd", 0400, root, udc,
+			&usbd_dbg_fops);
+	if (!usbd)
+		goto err_usbd;
+	iudma = debugfs_create_file("iudma", 0400, root, udc,
+			&iudma_dbg_fops);
+	if (!iudma)
+		goto err_iudma;
+
+	udc->debugfs_root = root;
+	udc->debugfs_usbd = usbd;
+	udc->debugfs_iudma = iudma;
+	return;
+err_iudma:
+	debugfs_remove(usbd);
+err_usbd:
+	debugfs_remove(root);
+err_root:
+	dev_err(udc->dev, "debugfs is not available\n");
+}
+
+/**
+ * bcm63xx_udc_cleanup_debugfs - Remove debugfs entries.
+ * @udc: Reference to the device controller.
+ *
+ * debugfs_remove() is safe to call with a NULL argument.
+ */
+static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
+{
+	debugfs_remove(udc->debugfs_iudma);
+	debugfs_remove(udc->debugfs_usbd);
+	debugfs_remove(udc->debugfs_root);
+	udc->debugfs_iudma = NULL;
+	udc->debugfs_usbd = NULL;
+	udc->debugfs_root = NULL;
+}
+
+/***********************************************************************
+ * Driver init/exit
+ ***********************************************************************/
+
+/**
+ * bcm63xx_udc_gadget_release - Called from device_release().
+ * @dev: Unused.
+ *
+ * We get a warning if this function doesn't exist, but it's empty because
+ * we don't have to free any of the memory allocated with the devm_* APIs.
+ */
+static void bcm63xx_udc_gadget_release(struct device *dev)
+{
+}
+
+/**
+ * bcm63xx_udc_probe - Initialize a new instance of the UDC.
+ * @pdev: Platform device struct from the bcm63xx BSP code.
+ *
+ * Note that platform data is required, because pd.port_no varies from chip
+ * to chip and is used to switch the correct USB port to device mode.
+ */
+static int __devinit bcm63xx_udc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
+	struct bcm63xx_udc *udc;
+	struct resource *res;
+	int rc = -ENOMEM, i, irq;
+
+	udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+	if (!udc) {
+		dev_err(dev, "cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, udc);
+	udc->dev = dev;
+	udc->pd = pd;
+
+	if (!pd) {
+		dev_err(dev, "missing platform data\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "error finding USBD resource\n");
+		return -ENXIO;
+	}
+	udc->usbd_regs = devm_request_and_ioremap(dev, res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "error finding IUDMA resource\n");
+		return -ENXIO;
+	}
+	udc->iudma_regs = devm_request_and_ioremap(dev, res);
+
+	if (!udc->usbd_regs || !udc->iudma_regs) {
+		dev_err(dev, "error requesting resources\n");
+		return -ENXIO;
+	}
+
+	spin_lock_init(&udc->lock);
+	INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
+	dev_set_name(&udc->gadget.dev, "gadget");
+
+	udc->gadget.ops = &bcm63xx_udc_ops;
+	udc->gadget.name = dev_name(dev);
+	udc->gadget.dev.parent = dev;
+	udc->gadget.dev.release = bcm63xx_udc_gadget_release;
+	udc->gadget.dev.dma_mask = dev->dma_mask;
+
+	if (!pd->use_fullspeed && !use_fullspeed)
+		udc->gadget.max_speed = USB_SPEED_HIGH;
+	else
+		udc->gadget.max_speed = USB_SPEED_FULL;
+
+	/* request clocks, allocate buffers, and clear any pending IRQs */
+	rc = bcm63xx_init_udc_hw(udc);
+	if (rc)
+		return rc;
+
+	rc = -ENXIO;
+
+	/* IRQ resource #0: control interrupt (VBUS, speed, etc.) */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "missing IRQ resource #0\n");
+		goto out_uninit;
+	}
+	if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0,
+			     dev_name(dev), udc) < 0) {
+		dev_err(dev, "error requesting IRQ #%d\n", irq);
+		goto out_uninit;
+	}
+
+	/* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */
+	for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+		irq = platform_get_irq(pdev, i + 1);
+		if (irq < 0) {
+			dev_err(dev, "missing IRQ resource #%d\n", i + 1);
+			goto out_uninit;
+		}
+		if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0,
+				     dev_name(dev), &udc->iudma[i]) < 0) {
+			dev_err(dev, "error requesting IRQ #%d\n", irq);
+			goto out_uninit;
+		}
+	}
+
+	rc = device_register(&udc->gadget.dev);
+	if (rc)
+		goto out_uninit;
+
+	bcm63xx_udc_init_debugfs(udc);
+	rc = usb_add_gadget_udc(dev, &udc->gadget);
+	if (!rc)
+		return 0;
+
+	bcm63xx_udc_cleanup_debugfs(udc);
+	device_unregister(&udc->gadget.dev);
+out_uninit:
+	bcm63xx_uninit_udc_hw(udc);
+	return rc;
+}
+
+/**
+ * bcm63xx_udc_remove - Remove the device from the system.
+ * @pdev: Platform device struct from the bcm63xx BSP code.
+ */
+static int __devexit bcm63xx_udc_remove(struct platform_device *pdev)
+{
+	struct bcm63xx_udc *udc = platform_get_drvdata(pdev);
+
+	bcm63xx_udc_cleanup_debugfs(udc);
+	usb_del_gadget_udc(&udc->gadget);
+	device_unregister(&udc->gadget.dev);
+	BUG_ON(udc->driver);
+
+	platform_set_drvdata(pdev, NULL);
+	bcm63xx_uninit_udc_hw(udc);
+
+	return 0;
+}
+
+static struct platform_driver bcm63xx_udc_driver = {
+	.probe		= bcm63xx_udc_probe,
+	.remove		= __devexit_p(bcm63xx_udc_remove),
+	.driver		= {
+		.name	= DRV_MODULE_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(bcm63xx_udc_driver);
+
+MODULE_DESCRIPTION("BCM63xx USB Peripheral Controller");
+MODULE_AUTHOR("Kevin Cernekee <cernekee@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index 725550f..1e4bb77 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 
 #include "u_ether.h"
@@ -34,6 +33,7 @@
 #define CDC_PRODUCT_NUM		0xa4aa	/* CDC Composite: ECM + ACM */
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /*
  * Kbuild is not very cooperative with respect to linking separately
@@ -43,10 +43,6 @@
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_ecm.c"
@@ -92,15 +88,10 @@
 
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -152,7 +143,6 @@
 
 static int __init cdc_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 
@@ -172,47 +162,22 @@
 	if (status < 0)
 		goto fail0;
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else {
-		/* We assume that can_support_ecm() tells the truth;
-		 * but if the controller isn't recognized at all then
-		 * that assumption is a bit more likely to be wrong.
-		 */
-		WARNING(cdev, "controller '%s' not recognized; trying %s\n",
-				gadget->name,
-				cdc_config_driver.label);
-		device_desc.bcdDevice =
-			cpu_to_le16(0x0300 | 0x0099);
-	}
-
-
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
 
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail1;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail1;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	/* register our configuration */
 	status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
 	if (status < 0)
 		goto fail1;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
 			DRIVER_DESC);
 
@@ -232,11 +197,12 @@
 	return 0;
 }
 
-static struct usb_composite_driver cdc_driver = {
+static __refdata struct usb_composite_driver cdc_driver = {
 	.name		= "g_cdc",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= cdc_bind,
 	.unbind		= __exit_p(cdc_unbind),
 };
 
@@ -246,7 +212,7 @@
 
 static int __init init(void)
 {
-	return usb_composite_probe(&cdc_driver, cdc_bind);
+	return usb_composite_probe(&cdc_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3f72110d..957f973 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -28,44 +28,6 @@
  * with the relevant device-wide data.
  */
 
-/* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ	1024
-
-static struct usb_composite_driver *composite;
-static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
-
-/* Some systems will need runtime overrides for the  product identifiers
- * published in the device descriptor, either numbers or strings or both.
- * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-static ushort idVendor;
-module_param(idVendor, ushort, 0644);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, 0644);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0644);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, 0644);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, 0644);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
-static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0644);
-MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
-
-static char composite_manufacturer[50];
-
-/*-------------------------------------------------------------------------*/
 /**
  * next_ep_desc() - advance to the next EP descriptor
  * @t: currect pointer within descriptor array
@@ -192,6 +154,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(config_ep_by_speed);
 
 /**
  * usb_add_function() - add a function to a configuration
@@ -250,6 +213,7 @@
 				function->name, function, value);
 	return value;
 }
+EXPORT_SYMBOL_GPL(usb_add_function);
 
 /**
  * usb_function_deactivate - prevent function and gadget enumeration
@@ -286,6 +250,7 @@
 	spin_unlock_irqrestore(&cdev->lock, flags);
 	return status;
 }
+EXPORT_SYMBOL_GPL(usb_function_deactivate);
 
 /**
  * usb_function_activate - allow function and gadget enumeration
@@ -300,9 +265,10 @@
 int usb_function_activate(struct usb_function *function)
 {
 	struct usb_composite_dev	*cdev = function->config->cdev;
+	unsigned long			flags;
 	int				status = 0;
 
-	spin_lock(&cdev->lock);
+	spin_lock_irqsave(&cdev->lock, flags);
 
 	if (WARN_ON(cdev->deactivations == 0))
 		status = -EINVAL;
@@ -312,9 +278,10 @@
 			status = usb_gadget_connect(cdev->gadget);
 	}
 
-	spin_unlock(&cdev->lock);
+	spin_unlock_irqrestore(&cdev->lock, flags);
 	return status;
 }
+EXPORT_SYMBOL_GPL(usb_function_activate);
 
 /**
  * usb_interface_id() - allocate an unused interface ID
@@ -351,16 +318,18 @@
 	}
 	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(usb_interface_id);
 
 static int config_buf(struct usb_configuration *config,
 		enum usb_device_speed speed, void *buf, u8 type)
 {
 	struct usb_config_descriptor	*c = buf;
 	void				*next = buf + USB_DT_CONFIG_SIZE;
-	int				len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
+	int				len;
 	struct usb_function		*f;
 	int				status;
 
+	len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
 	/* write the config descriptor */
 	c = buf;
 	c->bLength = USB_DT_CONFIG_SIZE;
@@ -790,6 +759,7 @@
 				config->bConfigurationValue, status);
 	return status;
 }
+EXPORT_SYMBOL_GPL(usb_add_config);
 
 static void remove_config(struct usb_composite_dev *cdev,
 			      struct usb_configuration *config)
@@ -889,10 +859,10 @@
 static int get_string(struct usb_composite_dev *cdev,
 		void *buf, u16 language, int id)
 {
+	struct usb_composite_driver	*composite = cdev->driver;
 	struct usb_configuration	*c;
 	struct usb_function		*f;
 	int				len;
-	const char			*str;
 
 	/* Yes, not only is USB's I18N support probably more than most
 	 * folk will ever care about ... also, it's all supported here.
@@ -932,26 +902,6 @@
 		return s->bLength;
 	}
 
-	/* Otherwise, look up and return a specified string.  First
-	 * check if the string has not been overridden.
-	 */
-	if (cdev->manufacturer_override == id)
-		str = iManufacturer ?: composite->iManufacturer ?:
-			composite_manufacturer;
-	else if (cdev->product_override == id)
-		str = iProduct ?: composite->iProduct;
-	else if (cdev->serial_override == id)
-		str = iSerialNumber ?: composite->iSerialNumber;
-	else
-		str = NULL;
-	if (str) {
-		struct usb_gadget_strings strings = {
-			.language = language,
-			.strings  = &(struct usb_string) { 0xff, str }
-		};
-		return usb_gadget_get_string(&strings, 0xff, buf);
-	}
-
 	/* String IDs are device-scoped, so we look up each string
 	 * table we're told about.  These lookups are infrequent;
 	 * simpler-is-better here.
@@ -1003,6 +953,7 @@
 	}
 	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(usb_string_id);
 
 /**
  * usb_string_ids() - allocate unused string IDs in batch
@@ -1034,6 +985,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(usb_string_ids_tab);
 
 /**
  * usb_string_ids_n() - allocate unused string IDs in batch
@@ -1062,7 +1014,7 @@
 	c->next_string_id += n;
 	return next + 1;
 }
-
+EXPORT_SYMBOL_GPL(usb_string_ids_n);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1359,8 +1311,8 @@
 	spin_lock_irqsave(&cdev->lock, flags);
 	if (cdev->config)
 		reset_config(cdev);
-	if (composite->disconnect)
-		composite->disconnect(cdev);
+	if (cdev->driver->disconnect)
+		cdev->driver->disconnect(cdev);
 	spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
@@ -1396,35 +1348,67 @@
 				struct usb_configuration, list);
 		remove_config(cdev, c);
 	}
-	if (composite->unbind)
-		composite->unbind(cdev);
+	if (cdev->driver->unbind)
+		cdev->driver->unbind(cdev);
 
 	if (cdev->req) {
 		kfree(cdev->req->buf);
 		usb_ep_free_request(gadget->ep0, cdev->req);
 	}
 	device_remove_file(&gadget->dev, &dev_attr_suspended);
+	kfree(cdev->def_manufacturer);
 	kfree(cdev);
 	set_gadget_data(gadget, NULL);
-	composite = NULL;
 }
 
-static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
+static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
+		const struct usb_device_descriptor *old)
 {
-	if (!*desc) {
-		int ret = usb_string_id(cdev);
-		if (unlikely(ret < 0))
-			WARNING(cdev, "failed to override string ID\n");
-		else
-			*desc = ret;
-	}
+	__le16 idVendor;
+	__le16 idProduct;
+	__le16 bcdDevice;
+	u8 iSerialNumber;
+	u8 iManufacturer;
+	u8 iProduct;
 
-	return *desc;
+	/*
+	 * these variables may have been set in
+	 * usb_composite_overwrite_options()
+	 */
+	idVendor = new->idVendor;
+	idProduct = new->idProduct;
+	bcdDevice = new->bcdDevice;
+	iSerialNumber = new->iSerialNumber;
+	iManufacturer = new->iManufacturer;
+	iProduct = new->iProduct;
+
+	*new = *old;
+	if (idVendor)
+		new->idVendor = idVendor;
+	if (idProduct)
+		new->idProduct = idProduct;
+	if (bcdDevice)
+		new->bcdDevice = bcdDevice;
+	else
+		new->bcdDevice = cpu_to_le16(get_default_bcdDevice());
+	if (iSerialNumber)
+		new->iSerialNumber = iSerialNumber;
+	if (iManufacturer)
+		new->iManufacturer = iManufacturer;
+	if (iProduct)
+		new->iProduct = iProduct;
 }
 
-static int composite_bind(struct usb_gadget *gadget)
+static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
+{
+	return container_of(gdrv, struct usb_composite_driver, gadget_driver);
+}
+
+static int composite_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *gdriver)
 {
 	struct usb_composite_dev	*cdev;
+	struct usb_composite_driver	*composite = to_cdriver(gdriver);
 	int				status = -ENOMEM;
 
 	cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
@@ -1440,13 +1424,12 @@
 	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!cdev->req)
 		goto fail;
-	cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
 	if (!cdev->req->buf)
 		goto fail;
 	cdev->req->complete = composite_setup_complete;
 	gadget->ep0->driver_data = cdev;
 
-	cdev->bufsiz = USB_BUFSIZ;
 	cdev->driver = composite;
 
 	/*
@@ -1467,49 +1450,11 @@
 	 * serial number), register function drivers, potentially update
 	 * power state and consumption, etc
 	 */
-	status = composite_gadget_bind(cdev);
+	status = composite->bind(cdev);
 	if (status < 0)
 		goto fail;
 
-	cdev->desc = *composite->dev;
-
-	/* standardized runtime overrides for device ID data */
-	if (idVendor)
-		cdev->desc.idVendor = cpu_to_le16(idVendor);
-	else
-		idVendor = le16_to_cpu(cdev->desc.idVendor);
-	if (idProduct)
-		cdev->desc.idProduct = cpu_to_le16(idProduct);
-	else
-		idProduct = le16_to_cpu(cdev->desc.idProduct);
-	if (bcdDevice)
-		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-	else
-		bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
-
-	/* string overrides */
-	if (iManufacturer || !cdev->desc.iManufacturer) {
-		if (!iManufacturer && !composite->iManufacturer &&
-		    !*composite_manufacturer)
-			snprintf(composite_manufacturer,
-				 sizeof composite_manufacturer,
-				 "%s %s with %s",
-				 init_utsname()->sysname,
-				 init_utsname()->release,
-				 gadget->name);
-
-		cdev->manufacturer_override =
-			override_id(cdev, &cdev->desc.iManufacturer);
-	}
-
-	if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
-		cdev->product_override =
-			override_id(cdev, &cdev->desc.iProduct);
-
-	if (iSerialNumber ||
-	    (!cdev->desc.iSerialNumber && composite->iSerialNumber))
-		cdev->serial_override =
-			override_id(cdev, &cdev->desc.iSerialNumber);
+	update_unchanged_dev_desc(&cdev->desc, composite->dev);
 
 	/* has userspace failed to provide a serial number? */
 	if (composite->needs_serial && !cdev->desc.iSerialNumber)
@@ -1546,8 +1491,8 @@
 				f->suspend(f);
 		}
 	}
-	if (composite->suspend)
-		composite->suspend(cdev);
+	if (cdev->driver->suspend)
+		cdev->driver->suspend(cdev);
 
 	cdev->suspended = 1;
 
@@ -1565,8 +1510,8 @@
 	 * suspend/resume callbacks?
 	 */
 	DBG(cdev, "resume\n");
-	if (composite->resume)
-		composite->resume(cdev);
+	if (cdev->driver->resume)
+		cdev->driver->resume(cdev);
 	if (cdev->config) {
 		list_for_each_entry(f, &cdev->config->functions, list) {
 			if (f->resume)
@@ -1584,13 +1529,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver composite_driver = {
-#ifdef CONFIG_USB_GADGET_SUPERSPEED
-	.max_speed	= USB_SPEED_SUPER,
-#else
-	.max_speed	= USB_SPEED_HIGH,
-#endif
-
+static const struct usb_gadget_driver composite_driver_template = {
+	.bind		= composite_bind,
 	.unbind		= composite_unbind,
 
 	.setup		= composite_setup,
@@ -1623,25 +1563,26 @@
  * while it was binding.  That would usually be done in order to wait for
  * some userspace participation.
  */
-int usb_composite_probe(struct usb_composite_driver *driver,
-			       int (*bind)(struct usb_composite_dev *cdev))
+int usb_composite_probe(struct usb_composite_driver *driver)
 {
-	if (!driver || !driver->dev || !bind || composite)
+	struct usb_gadget_driver *gadget_driver;
+
+	if (!driver || !driver->dev || !driver->bind)
 		return -EINVAL;
 
 	if (!driver->name)
 		driver->name = "composite";
-	if (!driver->iProduct)
-		driver->iProduct = driver->name;
-	composite_driver.function =  (char *) driver->name;
-	composite_driver.driver.name = driver->name;
-	composite_driver.max_speed =
-		min_t(u8, composite_driver.max_speed, driver->max_speed);
-	composite = driver;
-	composite_gadget_bind = bind;
 
-	return usb_gadget_probe_driver(&composite_driver, composite_bind);
+	driver->gadget_driver = composite_driver_template;
+	gadget_driver = &driver->gadget_driver;
+
+	gadget_driver->function =  (char *) driver->name;
+	gadget_driver->driver.name = driver->name;
+	gadget_driver->max_speed = driver->max_speed;
+
+	return usb_gadget_probe_driver(gadget_driver);
 }
+EXPORT_SYMBOL_GPL(usb_composite_probe);
 
 /**
  * usb_composite_unregister() - unregister a composite driver
@@ -1652,10 +1593,9 @@
  */
 void usb_composite_unregister(struct usb_composite_driver *driver)
 {
-	if (composite != driver)
-		return;
-	usb_gadget_unregister_driver(&composite_driver);
+	usb_gadget_unregister_driver(&driver->gadget_driver);
 }
+EXPORT_SYMBOL_GPL(usb_composite_unregister);
 
 /**
  * usb_composite_setup_continue() - Continue with the control transfer
@@ -1692,4 +1632,60 @@
 
 	spin_unlock_irqrestore(&cdev->lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_composite_setup_continue);
 
+static char *composite_default_mfr(struct usb_gadget *gadget)
+{
+	char *mfr;
+	int len;
+
+	len = snprintf(NULL, 0, "%s %s with %s", init_utsname()->sysname,
+			init_utsname()->release, gadget->name);
+	len++;
+	mfr = kmalloc(len, GFP_KERNEL);
+	if (!mfr)
+		return NULL;
+	snprintf(mfr, len, "%s %s with %s", init_utsname()->sysname,
+			init_utsname()->release, gadget->name);
+	return mfr;
+}
+
+void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
+		struct usb_composite_overwrite *covr)
+{
+	struct usb_device_descriptor	*desc = &cdev->desc;
+	struct usb_gadget_strings	*gstr = cdev->driver->strings[0];
+	struct usb_string		*dev_str = gstr->strings;
+
+	if (covr->idVendor)
+		desc->idVendor = cpu_to_le16(covr->idVendor);
+
+	if (covr->idProduct)
+		desc->idProduct = cpu_to_le16(covr->idProduct);
+
+	if (covr->bcdDevice)
+		desc->bcdDevice = cpu_to_le16(covr->bcdDevice);
+
+	if (covr->serial_number) {
+		desc->iSerialNumber = dev_str[USB_GADGET_SERIAL_IDX].id;
+		dev_str[USB_GADGET_SERIAL_IDX].s = covr->serial_number;
+	}
+	if (covr->manufacturer) {
+		desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
+		dev_str[USB_GADGET_MANUFACTURER_IDX].s = covr->manufacturer;
+
+	} else if (!strlen(dev_str[USB_GADGET_MANUFACTURER_IDX].s)) {
+		desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
+		cdev->def_manufacturer = composite_default_mfr(cdev->gadget);
+		dev_str[USB_GADGET_MANUFACTURER_IDX].s = cdev->def_manufacturer;
+	}
+
+	if (covr->product) {
+		desc->iProduct = dev_str[USB_GADGET_PRODUCT_IDX].id;
+		dev_str[USB_GADGET_PRODUCT_IDX].s = covr->product;
+	}
+}
+EXPORT_SYMBOL_GPL(usb_composite_overwrite_options);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Brownell");
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 7542a72c..e3a9892 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/device.h>
@@ -53,7 +54,7 @@
 	}
 	return dest - (u8 *)buf;
 }
-
+EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf);
 
 /**
  * usb_gadget_config_buf - builts a complete configuration descriptor
@@ -106,6 +107,7 @@
 	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
 	return len;
 }
+EXPORT_SYMBOL_GPL(usb_gadget_config_buf);
 
 /**
  * usb_copy_descriptors - copy a vector of USB descriptors
@@ -155,4 +157,4 @@
 
 	return ret;
 }
-
+EXPORT_SYMBOL_GPL(usb_copy_descriptors);
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index 19d7bb0..87d1650 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -13,9 +13,6 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-/* See comments in "zero.c" */
-#include "epautoconf.c"
-
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 #include "u_serial.c"
 #endif
@@ -292,7 +289,8 @@
 	return -ENODEV;
 }
 
-static int __init dbgp_bind(struct usb_gadget *gadget)
+static int __init dbgp_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	int err, stp;
 
@@ -402,9 +400,10 @@
 	return err;
 }
 
-static struct usb_gadget_driver dbgp_driver = {
+static __refdata struct usb_gadget_driver dbgp_driver = {
 	.function = "dbgp",
 	.max_speed = USB_SPEED_HIGH,
+	.bind = dbgp_bind,
 	.unbind = dbgp_unbind,
 	.setup = dbgp_setup,
 	.disconnect = dbgp_disconnect,
@@ -416,7 +415,7 @@
 
 static int __init dbgp_init(void)
 {
-	return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind);
+	return usb_gadget_probe_driver(&dbgp_driver);
 }
 
 static void __exit dbgp_exit(void)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index afdbb1c..0f7541b 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -909,6 +909,7 @@
 	dum->devstatus = 0;
 
 	dum->driver = driver;
+	dum->gadget.dev.driver = &driver->driver;
 	dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
 			driver->driver.name);
 	return 0;
@@ -923,6 +924,7 @@
 	dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
 			driver->driver.name);
 
+	dum->gadget.dev.driver = NULL;
 	dum->driver = NULL;
 
 	return 0;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 51f3d42..a777f7b 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
@@ -22,17 +23,6 @@
 
 #include "gadget_chips.h"
 
-
-/* we must assign addresses for configurable endpoints (like net2280) */
-static unsigned epnum;
-
-// #define MANY_ENDPOINTS
-#ifdef MANY_ENDPOINTS
-/* more than 15 configurable endpoints */
-static unsigned in_epnum;
-#endif
-
-
 /*
  * This should work with endpoints from controller drivers sharing the
  * same endpoint naming convention.  By example:
@@ -176,16 +166,14 @@
 	if (isdigit (ep->name [2])) {
 		u8	num = simple_strtoul (&ep->name [2], NULL, 10);
 		desc->bEndpointAddress |= num;
-#ifdef	MANY_ENDPOINTS
 	} else if (desc->bEndpointAddress & USB_DIR_IN) {
-		if (++in_epnum > 15)
+		if (++gadget->in_epnum > 15)
 			return 0;
-		desc->bEndpointAddress = USB_DIR_IN | in_epnum;
-#endif
+		desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
 	} else {
-		if (++epnum > 15)
+		if (++gadget->out_epnum > 15)
 			return 0;
-		desc->bEndpointAddress |= epnum;
+		desc->bEndpointAddress |= gadget->out_epnum;
 	}
 
 	/* report (variable) full speed bulk maxpacket */
@@ -328,6 +316,7 @@
 	ep->comp_desc = NULL;
 	return ep;
 }
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
 
 /**
  * usb_ep_autoconfig() - choose an endpoint matching the
@@ -367,7 +356,7 @@
 {
 	return usb_ep_autoconfig_ss(gadget, desc, NULL);
 }
-
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
 
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
@@ -385,9 +374,7 @@
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
 		ep->driver_data = NULL;
 	}
-#ifdef	MANY_ENDPOINTS
-	in_epnum = 0;
-#endif
-	epnum = 0;
+	gadget->in_epnum = 0;
+	gadget->out_epnum = 0;
 }
-
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index a28f6ffc..18c3f42 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -14,8 +14,6 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
-
 
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
@@ -102,11 +100,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_ecm.c"
 #include "f_subset.c"
 #ifdef	USB_ETH_RNDIS
@@ -117,6 +110,7 @@
 #include "u_ether.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
@@ -195,17 +189,10 @@
 	NULL,
 };
 
-
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -288,7 +275,6 @@
 
 static int __init eth_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 
@@ -323,42 +309,15 @@
 		device_desc.bNumConfigurations = 2;
 	}
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else {
-		/* We assume that can_support_ecm() tells the truth;
-		 * but if the controller isn't recognized at all then
-		 * that assumption is a bit more likely to be wrong.
-		 */
-		dev_warn(&gadget->dev,
-				"controller '%s' not recognized; trying %s\n",
-				gadget->name,
-				eth_config_driver.label);
-		device_desc.bcdDevice =
-			cpu_to_le16(0x0300 | 0x0099);
-	}
-
-
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
 
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	/* register our configuration(s); RNDIS first, if it's used */
 	if (has_rndis()) {
@@ -372,6 +331,7 @@
 	if (status < 0)
 		goto fail;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
 			DRIVER_DESC);
 
@@ -388,11 +348,12 @@
 	return 0;
 }
 
-static struct usb_composite_driver eth_driver = {
+static __refdata struct usb_composite_driver eth_driver = {
 	.name		= "g_ether",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_SUPER,
+	.bind		= eth_bind,
 	.unbind		= __exit_p(eth_unbind),
 };
 
@@ -402,7 +363,7 @@
 
 static int __init init(void)
 {
-	return usb_composite_probe(&eth_driver, eth_bind);
+	return usb_composite_probe(&eth_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 30b908f..95bc94f 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -897,10 +897,7 @@
 		return -ENOMEM;
 
 	/* export host's Ethernet address in CDC format */
-	snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
-		"%02X%02X%02X%02X%02X%02X",
-		ethaddr[0], ethaddr[1], ethaddr[2],
-		ethaddr[3], ethaddr[4], ethaddr[5]);
+	snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
 	ecm_string_defs[1].s = ecm->ethaddr;
 
 	ecm->port.cdc_filter = DEFAULT_FILTER;
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 16a8b1c..511e527 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 #include <linux/hid.h>
 #include <linux/cdev.h>
@@ -18,6 +17,7 @@
 #include <linux/poll.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
+#include <linux/sched.h>
 #include <linux/usb/g_hid.h>
 
 static int major, minors;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 4f1142e..3a7668b 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -213,7 +213,6 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/freezer.h>
-#include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -349,7 +348,6 @@
 
 	const char *vendor_name;		/*  8 characters or less */
 	const char *product_name;		/* 16 characters or less */
-	u16 release;
 
 	char			can_stall;
 };
@@ -2773,18 +2771,7 @@
 	bh->next = common->buffhds;
 
 	/* Prepare inquiryString */
-	if (cfg->release != 0xffff) {
-		i = cfg->release;
-	} else {
-		i = usb_gadget_controller_number(gadget);
-		if (i >= 0) {
-			i = 0x0300 + i;
-		} else {
-			WARNING(common, "controller '%s' not recognized\n",
-				gadget->name);
-			i = 0x0399;
-		}
-	}
+	i = get_default_bcdDevice();
 	snprintf(common->inquiry_string, sizeof common->inquiry_string,
 		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
 		 /* Assume product name dependent on the first LUN */
@@ -3110,7 +3097,6 @@
 	/* Let MSF use defaults */
 	cfg->vendor_name = 0;
 	cfg->product_name = 0;
-	cfg->release = 0xffff;
 
 	cfg->ops = NULL;
 	cfg->private_data = NULL;
diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
index 2f7e8f2..8ed1259 100644
--- a/drivers/usb/gadget/f_midi.c
+++ b/drivers/usb/gadget/f_midi.c
@@ -21,7 +21,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include <sound/core.h>
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index aab8ede..b651b52 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -1346,10 +1346,7 @@
 		return -ENOMEM;
 
 	/* export host's Ethernet address in CDC format */
-	snprintf(ncm->ethaddr, sizeof ncm->ethaddr,
-		"%02X%02X%02X%02X%02X%02X",
-		ethaddr[0], ethaddr[1], ethaddr[2],
-		ethaddr[3], ethaddr[4], ethaddr[5]);
+	snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr);
 	ncm_string_defs[1].s = ncm->ethaddr;
 
 	spin_lock_init(&ncm->lock);
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 5c1b68b..3c126fd 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -795,7 +795,7 @@
 	u16			w_value = le16_to_cpu(ctrl->wValue);
 	u16			w_length = le16_to_cpu(ctrl->wLength);
 
-	req->length = USB_BUFSIZ;
+	req->length = USB_COMP_EP0_BUFSIZ;
 
 	/* composite driver infrastructure handles everything except
 	 * the two control test requests.
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 21ab474..4060c0b 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -436,10 +436,7 @@
 		return -ENOMEM;
 
 	/* export host's Ethernet address in CDC format */
-	snprintf(geth->ethaddr, sizeof geth->ethaddr,
-		"%02X%02X%02X%02X%02X%02X",
-		ethaddr[0], ethaddr[1], ethaddr[2],
-		ethaddr[3], ethaddr[4], ethaddr[5]);
+	snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
 	geth_string_defs[1].s = geth->ethaddr;
 
 	geth->port.cdc_filter = DEFAULT_FILTER;
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
index e7cc4de..d3c6cff 100644
--- a/drivers/usb/gadget/f_uac2.c
+++ b/drivers/usb/gadget/f_uac2.c
@@ -463,7 +463,7 @@
 	return err;
 }
 
-static int __devexit snd_uac2_remove(struct platform_device *pdev)
+static int snd_uac2_remove(struct platform_device *pdev)
 {
 	struct snd_card *card = platform_get_drvdata(pdev);
 
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index a896d73..3f7d640 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -251,26 +251,12 @@
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
+#include <linux/usb/composite.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
-
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
 #define DRIVER_VERSION		"1 September 2010"
@@ -3213,7 +3199,6 @@
 static int __init check_parameters(struct fsg_dev *fsg)
 {
 	int	prot;
-	int	gcnum;
 
 	/* Store the default values */
 	mod_data.transport_type = USB_PR_BULK;
@@ -3228,16 +3213,8 @@
 	if (gadget_is_at91(fsg->gadget))
 		mod_data.can_stall = 0;
 
-	if (mod_data.release == 0xffff) {	// Parameter wasn't set
-		gcnum = usb_gadget_controller_number(fsg->gadget);
-		if (gcnum >= 0)
-			mod_data.release = 0x0300 + gcnum;
-		else {
-			WARNING(fsg, "controller '%s' not recognized\n",
-				fsg->gadget->name);
-			mod_data.release = 0x0399;
-		}
-	}
+	if (mod_data.release == 0xffff)
+		mod_data.release = get_default_bcdDevice();
 
 	prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
 
@@ -3331,7 +3308,8 @@
 }
 
 
-static int __init fsg_bind(struct usb_gadget *gadget)
+static int __init fsg_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	struct fsg_dev		*fsg = the_fsg;
 	int			rc;
@@ -3603,9 +3581,10 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver		fsg_driver = {
+static __refdata struct usb_gadget_driver		fsg_driver = {
 	.max_speed	= USB_SPEED_SUPER,
 	.function	= (char *) fsg_string_product,
+	.bind		= fsg_bind,
 	.unbind		= fsg_unbind,
 	.disconnect	= fsg_disconnect,
 	.setup		= fsg_setup,
@@ -3653,7 +3632,8 @@
 	if ((rc = fsg_alloc()) != 0)
 		return rc;
 	fsg = the_fsg;
-	if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
+	rc = usb_gadget_probe_driver(&fsg_driver);
+	if (rc != 0)
 		kref_put(&fsg->ref, fsg_release);
 	return rc;
 }
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 3def828..6ae70cb 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1255,7 +1255,7 @@
 }
 
 static int fsl_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int fsl_stop(struct usb_gadget_driver *driver);
 /* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
@@ -1951,7 +1951,7 @@
  * Called by initialization code of gadget drivers
 *----------------------------------------------------------------*/
 static int fsl_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	int retval = -ENODEV;
 	unsigned long flags = 0;
@@ -1976,7 +1976,7 @@
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 
 	/* bind udc driver to gadget driver */
-	retval = bind(&udc_controller->gadget);
+	retval = bind(&udc_controller->gadget, driver);
 	if (retval) {
 		VDBG("bind to %s --> %d", driver->driver.name, retval);
 		udc_controller->gadget.dev.driver = NULL;
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index cdd9454..72cd5e6 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -1311,7 +1311,7 @@
 static struct fusb300 *the_controller;
 
 static int fusb300_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct fusb300 *fusb300 = the_controller;
 	int retval;
@@ -1339,7 +1339,7 @@
 		goto error;
 	}
 
-	retval = bind(&fusb300->gadget);
+	retval = bind(&fusb300->gadget, driver);
 	if (retval) {
 		pr_err("bind to driver error (%d)\n", retval);
 		device_del(&fusb300->gadget.dev);
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index d3ace90..3953dd4 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -13,7 +13,6 @@
 #define pr_fmt(fmt) "g_ffs: " fmt
 
 #include <linux/module.h>
-#include <linux/utsname.h>
 
 /*
  * kbuild is not very cooperative with respect to linking separately
@@ -22,12 +21,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
 #  if defined USB_ETH_RNDIS
 #    undef USB_ETH_RNDIS
@@ -76,6 +69,8 @@
 	struct ffs_data *ffs_data;
 };
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static struct usb_device_descriptor gfs_dev_desc = {
 	.bLength		= sizeof gfs_dev_desc,
 	.bDescriptorType	= USB_DT_DEVICE,
@@ -117,6 +112,9 @@
 
 /* String IDs are assigned dynamically */
 static struct usb_string gfs_strings[] = {
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 	{ .s = "FunctionFS + RNDIS" },
 #endif
@@ -163,13 +161,13 @@
 static int gfs_unbind(struct usb_composite_dev *cdev);
 static int gfs_do_config(struct usb_configuration *c);
 
-static struct usb_composite_driver gfs_driver = {
+static __refdata struct usb_composite_driver gfs_driver = {
 	.name		= DRIVER_NAME,
 	.dev		= &gfs_dev_desc,
 	.strings	= gfs_dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= gfs_bind,
 	.unbind		= gfs_unbind,
-	.iProduct	= DRIVER_DESC,
 };
 
 static DEFINE_MUTEX(gfs_lock);
@@ -268,7 +266,7 @@
 	}
 	gfs_registered = true;
 
-	ret = usb_composite_probe(&gfs_driver, gfs_bind);
+	ret = usb_composite_probe(&gfs_driver);
 	if (unlikely(ret < 0))
 		gfs_registered = false;
 
@@ -357,6 +355,7 @@
 	ret = usb_string_ids_tab(cdev, gfs_strings);
 	if (unlikely(ret < 0))
 		goto error;
+	gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
 
 	for (i = func_num; --i; ) {
 		ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
@@ -369,9 +368,10 @@
 
 	for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
 		struct gfs_configuration *c = gfs_configurations + i;
+		int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
 
-		c->c.label			= gfs_strings[i].s;
-		c->c.iConfiguration		= gfs_strings[i].id;
+		c->c.label			= gfs_strings[sid].s;
+		c->c.iConfiguration		= gfs_strings[sid].id;
 		c->c.bConfigurationValue	= 1 + i;
 		c->c.bmAttributes		= USB_CONFIG_ATT_SELFPOWER;
 
@@ -379,7 +379,7 @@
 		if (unlikely(ret < 0))
 			goto error_unbind;
 	}
-
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	return 0;
 
 error_unbind:
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index b8b3a34..bcd04bc 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -15,6 +15,8 @@
 #ifndef __GADGET_CHIPS_H
 #define __GADGET_CHIPS_H
 
+#include <linux/usb/gadget.h>
+
 /*
  * NOTICE: the entries below are alphabetical and should be kept
  * that way.
@@ -25,106 +27,12 @@
  * If you have forgotten the alphabetical order let VIM/EMACS
  * do that for you.
  */
-#define gadget_is_amd5536udc(g)		(!strcmp("amd5536udc", (g)->name))
 #define gadget_is_at91(g)		(!strcmp("at91_udc", (g)->name))
-#define gadget_is_atmel_usba(g)		(!strcmp("atmel_usba_udc", (g)->name))
-#define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
-#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
-#define gadget_is_dummy(g)		(!strcmp("dummy_udc", (g)->name))
-#define gadget_is_dwc3(g)		(!strcmp("dwc3-gadget", (g)->name))
-#define gadget_is_fsl_qe(g)		(!strcmp("fsl_qe_udc", (g)->name))
-#define gadget_is_fsl_usb2(g)		(!strcmp("fsl-usb2-udc", (g)->name))
 #define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name))
-#define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name))
-#define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name))
-#define gadget_is_lpc32xx(g)		(!strcmp("lpc32xx_udc", (g)->name))
-#define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name))
 #define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name))
-#define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name))
 #define gadget_is_net2280(g)		(!strcmp("net2280", (g)->name))
-#define gadget_is_omap(g)		(!strcmp("omap_udc", (g)->name))
-#define gadget_is_pch(g)		(!strcmp("pch_udc", (g)->name))
 #define gadget_is_pxa(g)		(!strcmp("pxa25x_udc", (g)->name))
 #define gadget_is_pxa27x(g)		(!strcmp("pxa27x_udc", (g)->name))
-#define gadget_is_r8a66597(g)		(!strcmp("r8a66597_udc", (g)->name))
-#define gadget_is_renesas_usbhs(g)	(!strcmp("renesas_usbhs_udc", (g)->name))
-#define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name))
-#define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name))
-#define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))
-
-/**
- * usb_gadget_controller_number - support bcdDevice id convention
- * @gadget: the controller being driven
- *
- * Return a 2-digit BCD value associated with the peripheral controller,
- * suitable for use as part of a bcdDevice value, or a negative error code.
- *
- * NOTE:  this convention is purely optional, and has no meaning in terms of
- * any USB specification.  If you want to use a different convention in your
- * gadget driver firmware -- maybe a more formal revision ID -- feel free.
- *
- * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
- * to change their behavior accordingly.  For example it might help avoiding
- * some chip bug.
- */
-static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
-{
-	if (gadget_is_net2280(gadget))
-		return 0x01;
-	else if (gadget_is_dummy(gadget))
-		return 0x02;
-	else if (gadget_is_pxa(gadget))
-		return 0x03;
-	else if (gadget_is_goku(gadget))
-		return 0x06;
-	else if (gadget_is_omap(gadget))
-		return 0x08;
-	else if (gadget_is_pxa27x(gadget))
-		return 0x11;
-	else if (gadget_is_s3c2410(gadget))
-		return 0x12;
-	else if (gadget_is_at91(gadget))
-		return 0x13;
-	else if (gadget_is_imx(gadget))
-		return 0x14;
-	else if (gadget_is_musbhdrc(gadget))
-		return 0x16;
-	else if (gadget_is_atmel_usba(gadget))
-		return 0x18;
-	else if (gadget_is_fsl_usb2(gadget))
-		return 0x19;
-	else if (gadget_is_amd5536udc(gadget))
-		return 0x20;
-	else if (gadget_is_m66592(gadget))
-		return 0x21;
-	else if (gadget_is_fsl_qe(gadget))
-		return 0x22;
-	else if (gadget_is_ci13xxx_pci(gadget))
-		return 0x23;
-	else if (gadget_is_langwell(gadget))
-		return 0x24;
-	else if (gadget_is_r8a66597(gadget))
-		return 0x25;
-	else if (gadget_is_s3c_hsotg(gadget))
-		return 0x26;
-	else if (gadget_is_pch(gadget))
-		return 0x27;
-	else if (gadget_is_ci13xxx_msm(gadget))
-		return 0x28;
-	else if (gadget_is_renesas_usbhs(gadget))
-		return 0x29;
-	else if (gadget_is_s3c_hsudc(gadget))
-		return 0x30;
-	else if (gadget_is_net2272(gadget))
-		return 0x31;
-	else if (gadget_is_dwc3(gadget))
-		return 0x32;
-	else if (gadget_is_lpc32xx(gadget))
-		return 0x33;
-
-	return -ENOENT;
-}
-
 
 /**
  * gadget_supports_altsettings - return true if altsettings work
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 681bd03..881aab8 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -22,7 +22,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 #include <linux/device.h>
 
@@ -31,16 +30,13 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
 #include "gadget_chips.h"
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "f_midi.c"
 
 /*-------------------------------------------------------------------------*/
@@ -51,6 +47,8 @@
 static const char shortname[] = "g_midi";
 static const char longname[] = "MIDI Gadget";
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static int index = SNDRV_DEFAULT_IDX1;
 module_param(index, int, S_IRUGO);
 MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
@@ -85,9 +83,7 @@
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-#define STRING_DESCRIPTION_IDX		2
+#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_device_descriptor device_desc = {
 	.bLength =		USB_DT_DEVICE_SIZE,
@@ -102,8 +98,9 @@
 };
 
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s	= "Grey Innovation",
-	[STRING_PRODUCT_IDX].s		= "MIDI Gadget",
+	[USB_GADGET_MANUFACTURER_IDX].s	= "Grey Innovation",
+	[USB_GADGET_PRODUCT_IDX].s	= "MIDI Gadget",
+	[USB_GADGET_SERIAL_IDX].s	= "",
 	[STRING_DESCRIPTION_IDX].s	= "MIDI",
 	{  } /* end of list */
 };
@@ -140,61 +137,35 @@
 
 static int __init midi_bind(struct usb_composite_dev *cdev)
 {
-	struct usb_gadget *gadget = cdev->gadget;
-	int gcnum, status;
+	int status;
 
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		return status;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		return status;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
-
-	/* config description */
-	status = usb_string_id(cdev);
-	if (status < 0)
-		return status;
-	strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
-	midi_config.iConfiguration = status;
-
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum < 0) {
-		/* gmidi is so simple (no altsettings) that
-		 * it SHOULD NOT have problems with bulk-capable hardware.
-		 * so warn about unrecognized controllers, don't panic.
-		 */
-		pr_warning("%s: controller '%s' not recognized\n",
-			   __func__, gadget->name);
-		device_desc.bcdDevice = cpu_to_le16(0x9999);
-	} else {
-		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-	}
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+	midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id;
 
 	status = usb_add_config(cdev, &midi_config, midi_bind_config);
 	if (status < 0)
 		return status;
-
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	pr_info("%s\n", longname);
 	return 0;
 }
 
-static struct usb_composite_driver midi_driver = {
+static __refdata struct usb_composite_driver midi_driver = {
 	.name		= (char *) longname,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= midi_bind,
 	.unbind		= __exit_p(midi_unbind),
 };
 
 static int __init midi_init(void)
 {
-	return usb_composite_probe(&midi_driver, midi_bind);
+	return usb_composite_probe(&midi_driver);
 }
 module_init(midi_init);
 
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 9fd7886..51037cb 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -994,7 +994,7 @@
 }
 
 static int goku_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int goku_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops goku_ops = {
@@ -1348,7 +1348,7 @@
  * the driver might get unbound.
  */
 static int goku_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct goku_udc	*dev = the_controller;
 	int			retval;
@@ -1368,7 +1368,7 @@
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
-	retval = bind(&dev->gadget);
+	retval = bind(&dev->gadget, driver);
 	if (retval) {
 		DBG(dev, "bind to driver %s --> error %d\n",
 				driver->driver.name, retval);
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index 3493adf..74130f6 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -15,7 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
+#include "gadget_chips.h"
 #define DRIVER_DESC		"HID Gadget"
 #define DRIVER_VERSION		"2010/03/16"
 
@@ -33,12 +36,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_hid.c"
 
 
@@ -50,6 +47,7 @@
 static LIST_HEAD(hidg_func_list);
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
 	.bLength =		sizeof device_desc,
@@ -92,15 +90,10 @@
 
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -150,7 +143,7 @@
 {
 	struct usb_gadget *gadget = cdev->gadget;
 	struct list_head *tmp;
-	int status, gcnum, funcs = 0;
+	int status, funcs = 0;
 
 	list_for_each(tmp, &hidg_func_list)
 		funcs++;
@@ -163,38 +156,22 @@
 	if (status < 0)
 		return status;
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
-
-
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
 
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		return status;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		return status;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	/* register our configuration */
 	status = usb_add_config(cdev, &config_driver, do_config);
 	if (status < 0)
 		return status;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 
 	return 0;
@@ -242,11 +219,12 @@
 /****************************** Some noise ******************************/
 
 
-static struct usb_composite_driver hidg_driver = {
+static __refdata struct usb_composite_driver hidg_driver = {
 	.name		= "g_hid",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= hid_bind,
 	.unbind		= __exit_p(hid_unbind),
 };
 
@@ -272,7 +250,7 @@
 	if (status < 0)
 		return status;
 
-	status = usb_composite_probe(&hidg_driver, hid_bind);
+	status = usb_composite_probe(&hidg_driver);
 	if (status < 0)
 		platform_driver_unregister(&hidg_plat_driver);
 
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index e58b164..4bb6d53 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -828,7 +828,6 @@
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	case USB_SPEED_HIGH:
 		/* fails if caller didn't provide that descriptor... */
 		ep->desc = &data->hs_desc;
@@ -836,7 +835,6 @@
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
-#endif
 	default:
 		DBG(data->dev, "unconnected, %s init abandoned\n",
 				data->name);
@@ -1324,7 +1322,6 @@
  * Unrecognized ep0 requests may be handled in user space.
  */
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 static void make_qualifier (struct dev_data *dev)
 {
 	struct usb_qualifier_descriptor		qual;
@@ -1347,7 +1344,6 @@
 
 	memcpy (dev->rbuf, &qual, sizeof qual);
 }
-#endif
 
 static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
@@ -1427,7 +1423,6 @@
 			dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
 			req->buf = dev->dev;
 			break;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			if (!dev->hs_config)
 				break;
@@ -1437,7 +1432,6 @@
 			break;
 		case USB_DT_OTHER_SPEED_CONFIG:
 			// FALLTHROUGH
-#endif
 		case USB_DT_CONFIG:
 			value = config_buf (dev,
 					w_value >> 8,
@@ -1685,8 +1679,8 @@
 
 static struct dev_data		*the_device;
 
-static int
-gadgetfs_bind (struct usb_gadget *gadget)
+static int gadgetfs_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	struct dev_data		*dev = the_device;
 
@@ -1763,12 +1757,8 @@
 }
 
 static struct usb_gadget_driver gadgetfs_driver = {
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-	.max_speed	= USB_SPEED_HIGH,
-#else
-	.max_speed	= USB_SPEED_FULL,
-#endif
 	.function	= (char *) driver_desc,
+	.bind		= gadgetfs_bind,
 	.unbind		= gadgetfs_unbind,
 	.setup		= gadgetfs_setup,
 	.disconnect	= gadgetfs_disconnect,
@@ -1783,7 +1773,8 @@
 
 static void gadgetfs_nop(struct usb_gadget *arg) { }
 
-static int gadgetfs_probe (struct usb_gadget *gadget)
+static int gadgetfs_probe(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	CHIP = gadget->name;
 	return -EISNAM;
@@ -1791,6 +1782,7 @@
 
 static struct usb_gadget_driver probe_driver = {
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= gadgetfs_probe,
 	.unbind		= gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
@@ -1900,7 +1892,12 @@
 
 	/* triggers gadgetfs_bind(); then we can enumerate. */
 	spin_unlock_irq (&dev->lock);
-	value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind);
+	if (dev->hs_config)
+		gadgetfs_driver.max_speed = USB_SPEED_HIGH;
+	else
+		gadgetfs_driver.max_speed = USB_SPEED_FULL;
+
+	value = usb_gadget_probe_driver(&gadgetfs_driver);
 	if (value != 0) {
 		kfree (dev->buf);
 		dev->buf = NULL;
@@ -2039,7 +2036,7 @@
 		return -ESRCH;
 
 	/* fake probe to determine $CHIP */
-	(void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe);
+	usb_gadget_probe_driver(&probe_driver);
 	if (!CHIP)
 		return -ENODEV;
 
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
index f1ec99e..f696fb9 100644
--- a/drivers/usb/gadget/lpc32xx_udc.c
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -141,8 +141,6 @@
 	u32                     totalints;
 
 	bool			wedge;
-
-	const struct usb_endpoint_descriptor *desc;
 };
 
 /*
@@ -556,10 +554,8 @@
 
 	if (udc->enabled && udc->vbus) {
 		proc_ep_show(s, &udc->ep[0]);
-		list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
-			if (ep->desc)
-				proc_ep_show(s, ep);
-		}
+		list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list)
+			proc_ep_show(s, ep);
 	}
 
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -1453,7 +1449,6 @@
 
 		if (i != 0)
 			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-		ep->desc = NULL;
 		ep->ep.maxpacket = ep->maxpacket;
 		INIT_LIST_HEAD(&ep->queue);
 		ep->req_pending = 0;
@@ -1515,7 +1510,7 @@
 		done(ep, req, status);
 	}
 
-	if (ep->desc && status == -ESHUTDOWN) {
+	if (status == -ESHUTDOWN) {
 		uda_disable_hwepint(ep->udc, ep->hwep_num);
 		udc_disable_hwep(ep->udc, ep->hwep_num);
 	}
@@ -1658,9 +1653,6 @@
 
 	nuke(ep, -ESHUTDOWN);
 
-	/* restore the endpoint's pristine config */
-	ep->desc = NULL;
-
 	/* Clear all DMA statuses for this EP */
 	udc_ep_dma_disable(udc, ep->hwep_num);
 	writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
@@ -1696,7 +1688,7 @@
 	unsigned long flags;
 
 	/* Verify EP data */
-	if ((!_ep) || (!ep) || (!desc) || (ep->desc) ||
+	if ((!_ep) || (!ep) || (!desc) ||
 	    (desc->bDescriptorType != USB_DT_ENDPOINT)) {
 		dev_dbg(udc->dev, "bad ep or descriptor\n");
 		return -EINVAL;
@@ -1754,7 +1746,6 @@
 
 	/* Initialize endpoint to match the selected descriptor */
 	ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
-	ep->desc = desc;
 	ep->ep.maxpacket = maxpacket;
 
 	/* Map hardware endpoint from base and direction */
@@ -1837,7 +1828,7 @@
 
 	udc = ep->udc;
 
-	if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) {
+	if (!_ep) {
 		dev_dbg(udc->dev, "invalid ep\n");
 		return -EINVAL;
 	}
@@ -1976,7 +1967,7 @@
 	struct lpc32xx_udc *udc = ep->udc;
 	unsigned long flags;
 
-	if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1))
+	if ((!ep) || (ep->hwep_num <= 1))
 		return -EINVAL;
 
 	/* Don't halt an IN EP */
@@ -2262,7 +2253,7 @@
 	case USB_RECIP_ENDPOINT:
 		tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
 		ep = &udc->ep[tmp];
-		if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc))
+		if ((tmp == 0) || (tmp >= NUM_ENDPOINTS))
 			return -EOPNOTSUPP;
 
 		if (wIndex & USB_DIR_IN) {
@@ -2599,9 +2590,8 @@
 	return 0;
 }
 
-static int lpc32xx_start(struct usb_gadget_driver *driver,
-			 int (*bind)(struct usb_gadget *));
-static int lpc32xx_stop(struct usb_gadget_driver *driver);
+static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *);
+static int lpc32xx_stop(struct usb_gadget *, struct usb_gadget_driver *);
 
 static const struct usb_gadget_ops lpc32xx_udc_ops = {
 	.get_frame		= lpc32xx_get_frame,
@@ -2609,8 +2599,8 @@
 	.set_selfpowered	= lpc32xx_set_selfpowered,
 	.vbus_session		= lpc32xx_vbus_session,
 	.pullup			= lpc32xx_pullup,
-	.start			= lpc32xx_start,
-	.stop			= lpc32xx_stop,
+	.udc_start		= lpc32xx_start,
+	.udc_stop		= lpc32xx_stop,
 };
 
 static void nop_release(struct device *dev)
@@ -2618,10 +2608,9 @@
 	/* nothing to free */
 }
 
-static struct lpc32xx_udc controller = {
+static const struct lpc32xx_udc controller_template = {
 	.gadget = {
 		.ops	= &lpc32xx_udc_ops,
-		.ep0	= &controller.ep[0].ep,
 		.name	= driver_name,
 		.dev	= {
 			.init_name = "gadget",
@@ -2633,7 +2622,6 @@
 			.name	= "ep0",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 0,
 		.hwep_num	= 0, /* Can be 0 or 1, has special handling */
@@ -2645,7 +2633,6 @@
 			.name	= "ep1-int",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 2,
 		.hwep_num	= 0, /* 2 or 3, will be set later */
@@ -2657,7 +2644,6 @@
 			.name	= "ep2-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 4,
 		.hwep_num	= 0, /* 4 or 5, will be set later */
@@ -2669,7 +2655,6 @@
 			.name	= "ep3-iso",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 1023,
 		.hwep_num_base	= 6,
 		.hwep_num	= 0, /* 6 or 7, will be set later */
@@ -2681,7 +2666,6 @@
 			.name	= "ep4-int",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 8,
 		.hwep_num	= 0, /* 8 or 9, will be set later */
@@ -2693,7 +2677,6 @@
 			.name	= "ep5-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 10,
 		.hwep_num	= 0, /* 10 or 11, will be set later */
@@ -2705,7 +2688,6 @@
 			.name	= "ep6-iso",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 1023,
 		.hwep_num_base	= 12,
 		.hwep_num	= 0, /* 12 or 13, will be set later */
@@ -2717,7 +2699,6 @@
 			.name	= "ep7-int",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 14,
 		.hwep_num	= 0,
@@ -2729,7 +2710,6 @@
 			.name	= "ep8-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 16,
 		.hwep_num	= 0,
@@ -2741,7 +2721,6 @@
 			.name	= "ep9-iso",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 1023,
 		.hwep_num_base	= 18,
 		.hwep_num	= 0,
@@ -2753,7 +2732,6 @@
 			.name	= "ep10-int",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 20,
 		.hwep_num	= 0,
@@ -2765,7 +2743,6 @@
 			.name	= "ep11-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 22,
 		.hwep_num	= 0,
@@ -2777,7 +2754,6 @@
 			.name	= "ep12-iso",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 1023,
 		.hwep_num_base	= 24,
 		.hwep_num	= 0,
@@ -2789,7 +2765,6 @@
 			.name	= "ep13-int",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 26,
 		.hwep_num	= 0,
@@ -2801,7 +2776,6 @@
 			.name	= "ep14-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 64,
 		.hwep_num_base	= 28,
 		.hwep_num	= 0,
@@ -2813,7 +2787,6 @@
 			.name	= "ep15-bulk",
 			.ops	= &lpc32xx_ep_ops,
 		},
-		.udc		= &controller,
 		.maxpacket	= 1023,
 		.hwep_num_base	= 30,
 		.hwep_num	= 0,
@@ -2987,14 +2960,13 @@
 	return IRQ_HANDLED;
 }
 
-static int lpc32xx_start(struct usb_gadget_driver *driver,
-			 int (*bind)(struct usb_gadget *))
+static int lpc32xx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver)
 {
-	struct lpc32xx_udc *udc = &controller;
-	int retval, i;
+	struct lpc32xx_udc *udc = to_udc(gadget);
+	int i;
 
-	if (!driver || driver->max_speed < USB_SPEED_FULL ||
-	    !bind || !driver->setup) {
+	if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) {
 		dev_err(udc->dev, "bad parameter.\n");
 		return -EINVAL;
 	}
@@ -3011,18 +2983,6 @@
 	udc->selfpowered = 1;
 	udc->vbus = 0;
 
-	retval = bind(&udc->gadget);
-	if (retval) {
-		dev_err(udc->dev, "bind() returned %d\n", retval);
-		udc->enabled = 0;
-		udc->selfpowered = 0;
-		udc->driver = NULL;
-		udc->gadget.dev.driver = NULL;
-		return retval;
-	}
-
-	dev_dbg(udc->dev, "bound to %s\n", driver->driver.name);
-
 	/* Force VBUS process once to check for cable insertion */
 	udc->last_vbus = udc->vbus = 0;
 	schedule_work(&udc->vbus_job);
@@ -3034,22 +2994,19 @@
 	return 0;
 }
 
-static int lpc32xx_stop(struct usb_gadget_driver *driver)
+static int lpc32xx_stop(struct usb_gadget *gadget,
+			struct usb_gadget_driver *driver)
 {
 	int i;
-	struct lpc32xx_udc *udc = &controller;
+	struct lpc32xx_udc *udc = to_udc(gadget);
 
-	if (!driver || driver != udc->driver || !driver->unbind)
+	if (!driver || driver != udc->driver)
 		return -EINVAL;
 
-	/* Disable USB pullup */
-	isp1301_pullup_enable(udc, 0, 1);
-
 	for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
 		disable_irq(udc->udp_irq[i]);
 
 	if (udc->clocked) {
-
 		spin_lock(&udc->lock);
 		stop_activity(udc);
 		spin_unlock(&udc->lock);
@@ -3069,20 +3026,16 @@
 	}
 
 	udc->enabled = 0;
-	pullup(udc, 0);
-
-	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
 
-	dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name);
 	return 0;
 }
 
 static void lpc32xx_udc_shutdown(struct platform_device *dev)
 {
 	/* Force disconnect on reboot */
-	struct lpc32xx_udc *udc = &controller;
+	struct lpc32xx_udc *udc = platform_get_drvdata(dev);
 
 	pullup(udc, 0);
 }
@@ -3120,12 +3073,21 @@
 static int __init lpc32xx_udc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct lpc32xx_udc *udc = &controller;
+	struct lpc32xx_udc *udc;
 	int retval, i;
 	struct resource *res;
 	dma_addr_t dma_handle;
 	struct device_node *isp1301_node;
 
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	memcpy(udc, &controller_template, sizeof(*udc));
+	for (i = 0; i <= 15; i++)
+		udc->ep[i].udc = udc;
+	udc->gadget.ep0 = &udc->ep[0].ep;
+
 	/* init software state */
 	udc->gadget.dev.parent = dev;
 	udc->pdev = pdev;
@@ -3140,8 +3102,10 @@
 	}
 
 	udc->isp1301_i2c_client = isp1301_get_client(isp1301_node);
-	if (!udc->isp1301_i2c_client)
-		return -EPROBE_DEFER;
+	if (!udc->isp1301_i2c_client) {
+		retval = -EPROBE_DEFER;
+		goto phy_fail;
+	}
 
 	dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n",
 		 udc->isp1301_i2c_client->addr);
@@ -3160,8 +3124,10 @@
 	 *  IORESOURCE_IRQ, USB transceiver interrupt number
 	 */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENXIO;
+	if (!res) {
+		retval = -ENXIO;
+		goto resource_fail;
+	}
 
 	spin_lock_init(&udc->lock);
 
@@ -3171,7 +3137,8 @@
 		if (udc->udp_irq[i] < 0) {
 			dev_err(udc->dev,
 				"irq resource %d not available!\n", i);
-			return udc->udp_irq[i];
+			retval = udc->udp_irq[i];
+			goto irq_fail;
 		}
 	}
 
@@ -3179,7 +3146,8 @@
 	udc->io_p_size = resource_size(res);
 	if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) {
 		dev_err(udc->dev, "someone's using UDC memory\n");
-		return -EBUSY;
+		retval = -EBUSY;
+		goto request_mem_region_fail;
 	}
 
 	udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size);
@@ -3208,7 +3176,7 @@
 	udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
 	if (IS_ERR(udc->usb_otg_clk)) {
 		dev_err(udc->dev, "failed to acquire USB otg clock\n");
-		retval = PTR_ERR(udc->usb_slv_clk);
+		retval = PTR_ERR(udc->usb_otg_clk);
 		goto usb_otg_clk_get_fail;
 	}
 
@@ -3376,7 +3344,11 @@
 io_map_fail:
 	release_mem_region(udc->io_p_start, udc->io_p_size);
 	dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
-
+request_mem_region_fail:
+irq_fail:
+resource_fail:
+phy_fail:
+	kfree(udc);
 	return retval;
 }
 
@@ -3414,6 +3386,7 @@
 	clk_put(udc->usb_pll_clk);
 	iounmap(udc->udp_baseaddr);
 	release_mem_region(udc->io_p_start, udc->io_p_size);
+	kfree(udc);
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index cf6bd62..b6401f1 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1466,7 +1466,7 @@
 static struct m66592 *the_controller;
 
 static int m66592_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct m66592 *m66592 = the_controller;
 	int retval;
@@ -1492,7 +1492,7 @@
 		goto error;
 	}
 
-	retval = bind(&m66592->gadget);
+	retval = bind(&m66592->gadget, driver);
 	if (retval) {
 		pr_err("bind to driver error (%d)\n", retval);
 		device_del(&m66592->gadget.dev);
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 1f376eb..080e577 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -29,9 +29,8 @@
 
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/usb/ch9.h>
-
+#include <linux/module.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -47,14 +46,10 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "f_mass_storage.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor msg_device_desc = {
 	.bLength =		sizeof msg_device_desc,
@@ -85,6 +80,22 @@
 	NULL,
 };
 
+static struct usb_string strings_dev[] = {
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+	.language       = 0x0409,       /* en-us */
+	.strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
 
 /****************************** Configurations ******************************/
 
@@ -143,10 +154,15 @@
 {
 	int status;
 
+	status = usb_string_ids_tab(cdev, strings_dev);
+	if (status < 0)
+		return status;
+	msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
 	status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
 	if (status < 0)
 		return status;
-
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&cdev->gadget->dev,
 		 DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 	set_bit(0, &msg_registered);
@@ -156,12 +172,13 @@
 
 /****************************** Some noise ******************************/
 
-static struct usb_composite_driver msg_driver = {
+static __refdata struct usb_composite_driver msg_driver = {
 	.name		= "g_mass_storage",
 	.dev		= &msg_device_desc,
-	.iProduct	= DRIVER_DESC,
 	.max_speed	= USB_SPEED_SUPER,
 	.needs_serial	= 1,
+	.strings	= dev_strings,
+	.bind		= msg_bind,
 };
 
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -170,7 +187,7 @@
 
 static int __init msg_init(void)
 {
-	return usb_composite_probe(&msg_driver, msg_bind);
+	return usb_composite_probe(&msg_driver);
 }
 module_init(msg_init);
 
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index c37fb33..88472bf 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -14,10 +14,8 @@
 
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 
-
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
 #endif
@@ -42,12 +40,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_mass_storage.c"
 
 #include "u_serial.c"
@@ -61,7 +53,7 @@
 #endif
 #include "u_ether.c"
 
-
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /***************************** Device Descriptor ****************************/
 
@@ -112,21 +104,16 @@
 
 
 enum {
-#ifdef CONFIG_USB_G_MULTI_RNDIS
-	MULTI_STRING_RNDIS_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
+	MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
 	MULTI_STRING_CDC_CONFIG_IDX,
-#endif
 };
 
 static struct usb_string strings_dev[] = {
-#ifdef CONFIG_USB_G_MULTI_RNDIS
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	[MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
 	[MULTI_STRING_CDC_CONFIG_IDX].s   = "Multifunction with CDC ECM",
-#endif
 	{  } /* end of list */
 };
 
@@ -260,7 +247,7 @@
 static int __ref multi_bind(struct usb_composite_dev *cdev)
 {
 	struct usb_gadget *gadget = cdev->gadget;
-	int status, gcnum;
+	int status;
 
 	if (!can_support_ecm(cdev->gadget)) {
 		dev_err(&gadget->dev, "controller '%s' not usable\n",
@@ -288,19 +275,11 @@
 		}
 	}
 
-	/* set bcdDevice */
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0) {
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	} else {
-		WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
-	}
-
 	/* allocate string IDs */
 	status = usb_string_ids_tab(cdev, strings_dev);
 	if (unlikely(status < 0))
 		goto fail2;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	/* register configurations */
 	status = rndis_config_register(cdev);
@@ -310,6 +289,7 @@
 	status = cdc_config_register(cdev);
 	if (unlikely(status < 0))
 		goto fail2;
+	usb_composite_overwrite_options(cdev, &coverwrite);
 
 	/* we're done */
 	dev_info(&gadget->dev, DRIVER_DESC "\n");
@@ -338,20 +318,20 @@
 /****************************** Some noise ******************************/
 
 
-static struct usb_composite_driver multi_driver = {
+static __refdata struct usb_composite_driver multi_driver = {
 	.name		= "g_multi",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= multi_bind,
 	.unbind		= __exit_p(multi_unbind),
-	.iProduct	= DRIVER_DESC,
 	.needs_serial	= 1,
 };
 
 
 static int __init multi_init(void)
 {
-	return usb_composite_probe(&multi_driver, multi_bind);
+	return usb_composite_probe(&multi_driver);
 }
 module_init(multi_init);
 
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 75db2c3..ea45224 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -51,9 +51,8 @@
 #define EPSTATUS_TIMEOUT	10000
 #define PRIME_TIMEOUT		10000
 #define READSAFE_TIMEOUT	1000
-#define DTD_TIMEOUT		1000
 
-#define LOOPS_USEC_SHIFT	4
+#define LOOPS_USEC_SHIFT	1
 #define LOOPS_USEC		(1 << LOOPS_USEC_SHIFT)
 #define LOOPS(timeout)		((timeout) >> LOOPS_USEC_SHIFT)
 
@@ -64,7 +63,6 @@
 
 /* controller device global variable */
 static struct mv_udc	*the_controller;
-int mv_usb_otgsc;
 
 static void nuke(struct mv_ep *ep, int status);
 static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
@@ -357,17 +355,24 @@
 	return retval;
 }
 
-
 static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
 		dma_addr_t *dma, int *is_last)
 {
-	u32 temp;
 	struct mv_dtd *dtd;
 	struct mv_udc *udc;
+	struct mv_dqh *dqh;
+	u32 temp, mult = 0;
 
 	/* how big will this transfer be? */
-	*length = min(req->req.length - req->req.actual,
-			(unsigned)EP_MAX_LENGTH_TRANSFER);
+	if (usb_endpoint_xfer_isoc(req->ep->ep.desc)) {
+		dqh = req->ep->dqh;
+		mult = (dqh->max_packet_length >> EP_QUEUE_HEAD_MULT_POS)
+				& 0x3;
+		*length = min(req->req.length - req->req.actual,
+				(unsigned)(mult * req->ep->ep.maxpacket));
+	} else
+		*length = min(req->req.length - req->req.actual,
+				(unsigned)EP_MAX_LENGTH_TRANSFER);
 
 	udc = req->ep->udc;
 
@@ -375,7 +380,7 @@
 	 * Be careful that no _GFP_HIGHMEM is set,
 	 * or we can not use dma_to_virt
 	 */
-	dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma);
+	dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, dma);
 	if (dtd == NULL)
 		return dtd;
 
@@ -409,6 +414,8 @@
 	if (*is_last && !req->req.no_interrupt)
 		temp |= DTD_IOC;
 
+	temp |= mult << 10;
+
 	dtd->size_ioc_sts = temp;
 
 	mb();
@@ -708,6 +715,7 @@
 	struct mv_req *req = container_of(_req, struct mv_req, req);
 	struct mv_udc *udc = ep->udc;
 	unsigned long flags;
+	int retval;
 
 	/* catch various bogus parameters */
 	if (!_req || !req->req.complete || !req->req.buf
@@ -719,10 +727,6 @@
 		dev_err(&udc->dev->dev, "%s, bad ep", __func__);
 		return -EINVAL;
 	}
-	if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
-		if (req->req.length > ep->ep.maxpacket)
-			return -EMSGSIZE;
-	}
 
 	udc = ep->udc;
 	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
@@ -755,15 +759,17 @@
 
 	/* build dtds and push them to device queue */
 	if (!req_to_dtd(req)) {
-		int retval;
 		retval = queue_dtd(ep, req);
 		if (retval) {
 			spin_unlock_irqrestore(&udc->lock, flags);
-			return retval;
+			dev_err(&udc->dev->dev, "Failed to queue dtd\n");
+			goto err_unmap_dma;
 		}
 	} else {
 		spin_unlock_irqrestore(&udc->lock, flags);
-		return -ENOMEM;
+		dev_err(&udc->dev->dev, "Failed to dma_pool_alloc\n");
+		retval = -ENOMEM;
+		goto err_unmap_dma;
 	}
 
 	/* Update ep0 state */
@@ -775,6 +781,22 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	return 0;
+
+err_unmap_dma:
+	if (req->mapped) {
+		dma_unmap_single(ep->udc->gadget.dev.parent,
+				req->req.dma, req->req.length,
+				((ep_dir(ep) == EP_DIR_IN) ?
+				DMA_TO_DEVICE : DMA_FROM_DEVICE));
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	} else
+		dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+				req->req.dma, req->req.length,
+				((ep_dir(ep) == EP_DIR_IN) ?
+				DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+	return retval;
 }
 
 static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
@@ -1065,7 +1087,7 @@
 	tmp |= USBMODE_CTRL_MODE_DEVICE;
 
 	/* turn setup lockout off, require setup tripwire in usbcmd */
-	tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE;
+	tmp |= USBMODE_SETUP_LOCK_OFF;
 
 	writel(tmp, &udc->op_regs->usbmode);
 
@@ -1199,12 +1221,16 @@
 			udc_start(udc);
 		}
 	} else if (udc->driver && udc->softconnect) {
+		if (!udc->active)
+			goto out;
+
 		/* stop all the transfer in queue*/
 		stop_activity(udc, udc->driver);
 		udc_stop(udc);
 		mv_udc_disable(udc);
 	}
 
+out:
 	spin_unlock_irqrestore(&udc->lock, flags);
 	return retval;
 }
@@ -1243,7 +1269,7 @@
 }
 
 static int mv_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int mv_udc_stop(struct usb_gadget_driver *driver);
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops mv_ops = {
@@ -1348,7 +1374,7 @@
 }
 
 static int mv_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct mv_udc *udc = the_controller;
 	int retval = 0;
@@ -1373,7 +1399,7 @@
 
 	spin_unlock_irqrestore(&udc->lock, flags);
 
-	retval = bind(&udc->gadget);
+	retval = bind(&udc->gadget, driver);
 	if (retval) {
 		dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
 				driver->driver.name, retval);
@@ -1499,15 +1525,17 @@
 	}
 
 	/* prime the data phase */
-	if (!req_to_dtd(req))
+	if (!req_to_dtd(req)) {
 		retval = queue_dtd(ep, req);
-	else{	/* no mem */
+		if (retval) {
+			dev_err(&udc->dev->dev,
+				"Failed to queue dtd when prime status\n");
+			goto out;
+		}
+	} else{	/* no mem */
 		retval = -ENOMEM;
-		goto out;
-	}
-
-	if (retval) {
-		dev_err(&udc->dev->dev, "response error on GET_STATUS request\n");
+		dev_err(&udc->dev->dev,
+			"Failed to dma_pool_alloc when prime status\n");
 		goto out;
 	}
 
@@ -1515,6 +1543,15 @@
 
 	return 0;
 out:
+	if (req->mapped) {
+		dma_unmap_single(ep->udc->gadget.dev.parent,
+				req->req.dma, req->req.length,
+				((ep_dir(ep) == EP_DIR_IN) ?
+				DMA_TO_DEVICE : DMA_FROM_DEVICE));
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
 	return retval;
 }
 
@@ -2468,9 +2505,11 @@
 	u32 mode;
 
 	/* reset controller mode to IDLE */
+	mv_udc_enable(udc);
 	mode = readl(&udc->op_regs->usbmode);
 	mode &= ~3;
 	writel(mode, &udc->op_regs->usbmode);
+	mv_udc_disable(udc);
 }
 
 static struct platform_driver udc_driver = {
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index 8953003..a22ad9a 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -20,8 +20,8 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
-
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
 #include "u_ether.h"
 
@@ -36,11 +36,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_ncm.c"
 #include "u_ether.c"
 
@@ -57,6 +52,7 @@
 #define CDC_PRODUCT_NUM		0xa4a1	/* Linux-USB Ethernet Gadget */
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
 	.bLength =		sizeof device_desc,
@@ -97,17 +93,11 @@
 	NULL,
 };
 
-
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	{  } /* end of list */
 };
 
@@ -149,7 +139,6 @@
 
 static int __init gncm_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 
@@ -158,48 +147,22 @@
 	if (status < 0)
 		return status;
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else {
-		/* We assume that can_support_ecm() tells the truth;
-		 * but if the controller isn't recognized at all then
-		 * that assumption is a bit more likely to be wrong.
-		 */
-		dev_warn(&gadget->dev,
-			 "controller '%s' not recognized; trying %s\n",
-			 gadget->name,
-			 ncm_config_driver.label);
-		device_desc.bcdDevice =
-			cpu_to_le16(0x0300 | 0x0099);
-	}
-
-
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
 
-	/* device descriptor strings: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
 	status = usb_add_config(cdev, &ncm_config_driver,
 				ncm_do_config);
 	if (status < 0)
 		goto fail;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
 
 	return 0;
@@ -215,11 +178,12 @@
 	return 0;
 }
 
-static struct usb_composite_driver ncm_driver = {
+static __refdata struct usb_composite_driver ncm_driver = {
 	.name		= "g_ncm",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= gncm_bind,
 	.unbind		= __exit_p(gncm_unbind),
 };
 
@@ -229,7 +193,7 @@
 
 static int __init init(void)
 {
-	return usb_composite_probe(&ncm_driver, gncm_bind);
+	return usb_composite_probe(&ncm_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
index c7fb772..661600a 100644
--- a/drivers/usb/gadget/nokia.c
+++ b/drivers/usb/gadget/nokia.c
@@ -16,7 +16,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include "u_serial.h"
@@ -38,11 +37,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_ecm.c"
@@ -52,23 +46,23 @@
 #include "u_ether.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define NOKIA_VENDOR_ID			0x0421	/* Nokia */
 #define NOKIA_PRODUCT_ID		0x01c8	/* Nokia Gadget */
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-#define STRING_DESCRIPTION_IDX		2
+#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
 
 static char manufacturer_nokia[] = "Nokia";
 static const char product_nokia[] = NOKIA_LONG_NAME;
 static const char description_nokia[] = "PC-Suite Configuration";
 
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
-	[STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+	[USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia,
+	[USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	[STRING_DESCRIPTION_IDX].s = description_nokia,
 	{  } /* end of list */
 };
@@ -90,6 +84,7 @@
 	.bDeviceClass		= USB_CLASS_COMM,
 	.idVendor		= __constant_cpu_to_le16(NOKIA_VENDOR_ID),
 	.idProduct		= __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+	.bcdDevice		= cpu_to_le16(NOKIA_VERSION_NUM),
 	/* .iManufacturer = DYNAMIC */
 	/* .iProduct = DYNAMIC */
 	.bNumConfigurations =	1,
@@ -151,7 +146,6 @@
 
 static int __init nokia_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 
@@ -167,41 +161,17 @@
 	if (status < 0)
 		goto err_ether;
 
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto err_usb;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto err_usb;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-
-	device_desc.iProduct = status;
-
-	/* config description */
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto err_usb;
-	strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+	status = strings_dev[STRING_DESCRIPTION_IDX].id;
 	nokia_config_500ma_driver.iConfiguration = status;
 	nokia_config_100ma_driver.iConfiguration = status;
 
-	/* set up other descriptors */
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
-	else {
-		/* this should only work with hw that supports altsettings
-		 * and several endpoints, anything else, panic.
-		 */
-		pr_err("nokia_bind: controller '%s' not recognized\n",
-			gadget->name);
+	if (!gadget_supports_altsettings(gadget))
 		goto err_usb;
-	}
 
 	/* finally register the configuration */
 	status = usb_add_config(cdev, &nokia_config_500ma_driver,
@@ -214,6 +184,7 @@
 	if (status < 0)
 		goto err_usb;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
 
 	return 0;
@@ -237,17 +208,18 @@
 	return 0;
 }
 
-static struct usb_composite_driver nokia_driver = {
+static __refdata struct usb_composite_driver nokia_driver = {
 	.name		= "g_nokia",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_HIGH,
+	.bind		= nokia_bind,
 	.unbind		= __exit_p(nokia_unbind),
 };
 
 static int __init nokia_init(void)
 {
-	return usb_composite_probe(&nokia_driver, nokia_bind);
+	return usb_composite_probe(&nokia_driver);
 }
 module_init(nokia_init);
 
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index f9132ad..2a4749c 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -1308,7 +1308,7 @@
 }
 
 static int omap_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int omap_udc_stop(struct usb_gadget_driver *driver);
 
 static struct usb_gadget_ops omap_gadget_ops = {
@@ -2040,7 +2040,7 @@
 }
 
 static int omap_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	int		status = -ENODEV;
 	struct omap_ep	*ep;
@@ -2082,7 +2082,7 @@
 	if (udc->dc_clk != NULL)
 		omap_udc_enable_clock(1);
 
-	status = bind(&udc->gadget);
+	status = bind(&udc->gadget, driver);
 	if (status) {
 		DBG("bind to %s --> %d\n", driver->driver.name, status);
 		udc->gadget.dev.driver = NULL;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index f4fb71c..6490c00 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -1236,7 +1236,7 @@
 }
 
 static int pch_udc_start(struct usb_gadget_driver *driver,
-	int (*bind)(struct usb_gadget *));
+	int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pch_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops pch_udc_ops = {
 	.get_frame = pch_udc_pcd_get_frame,
@@ -2982,7 +2982,7 @@
 }
 
 static int pch_udc_start(struct usb_gadget_driver *driver,
-	int (*bind)(struct usb_gadget *))
+	int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct pch_udc_dev	*dev = pch_udc;
 	int			retval;
@@ -3006,7 +3006,7 @@
 	dev->gadget.dev.driver = &driver->driver;
 
 	/* Invoke the bind routine of the gadget driver */
-	retval = bind(&dev->gadget);
+	retval = bind(&dev->gadget, driver);
 
 	if (retval) {
 		dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n",
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index f1f9290..e156e3f 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -22,7 +22,6 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 #include <linux/fs.h>
@@ -38,25 +37,13 @@
 #include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/g_printer.h>
 
 #include "gadget_chips.h"
 
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
-/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define DRIVER_DESC		"Printer Gadget"
 #define DRIVER_VERSION		"2007 OCT 06"
@@ -120,8 +107,7 @@
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static char *iSerialNum;
-module_param(iSerialNum, charp, S_IRUGO);
+module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO);
 MODULE_PARM_DESC(iSerialNum, "1");
 
 static char *iPNPstring;
@@ -141,18 +127,10 @@
  * descriptors are built on demand.
  */
 
-#define STRING_MANUFACTURER		1
-#define STRING_PRODUCT			2
-#define STRING_SERIALNUM		3
-
 /* holds our biggest descriptor */
 #define USB_DESC_BUFSIZE		256
 #define USB_BUFSIZE			8192
 
-/* This device advertises one configuration. */
-#define DEV_CONFIG_VALUE		1
-#define	PRINTER_INTERFACE		0
-
 static struct usb_device_descriptor device_desc = {
 	.bLength =		sizeof device_desc,
 	.bDescriptorType =	USB_DT_DEVICE,
@@ -162,16 +140,12 @@
 	.bDeviceProtocol =	0,
 	.idVendor =		cpu_to_le16(PRINTER_VENDOR_NUM),
 	.idProduct =		cpu_to_le16(PRINTER_PRODUCT_NUM),
-	.iManufacturer =	STRING_MANUFACTURER,
-	.iProduct =		STRING_PRODUCT,
-	.iSerialNumber =	STRING_SERIALNUM,
 	.bNumConfigurations =	1
 };
 
 static struct usb_interface_descriptor intf_desc = {
 	.bLength =		sizeof intf_desc,
 	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	PRINTER_INTERFACE,
 	.bNumEndpoints =	2,
 	.bInterfaceClass =	USB_CLASS_PRINTER,
 	.bInterfaceSubClass =	1,	/* Printer Sub-Class */
@@ -252,7 +226,6 @@
 
 /* descriptors that are built on-demand */
 
-static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
 static char				serial_num [40] = "1";
 static char				pnp_string [1024] =
@@ -260,9 +233,9 @@
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
-	{ STRING_MANUFACTURER,	manufacturer, },
-	{ STRING_PRODUCT,	product_desc, },
-	{ STRING_SERIALNUM,	serial_num, },
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = product_desc,
+	[USB_GADGET_SERIAL_IDX].s =	serial_num,
 	{  }		/* end of list */
 };
 
@@ -871,25 +844,13 @@
 	int			result = 0;
 
 	/* Free the current interface */
-	switch (dev->interface) {
-	case PRINTER_INTERFACE:
-		printer_reset_interface(dev);
-		break;
-	}
+	printer_reset_interface(dev);
 
-	switch (number) {
-	case PRINTER_INTERFACE:
-		result = set_printer_interface(dev);
-		if (result) {
-			printer_reset_interface(dev);
-		} else {
-			dev->interface = PRINTER_INTERFACE;
-		}
-		break;
-	default:
-		result = -EINVAL;
-		/* FALL THROUGH */
-	}
+	result = set_printer_interface(dev);
+	if (result)
+		printer_reset_interface(dev);
+	else
+		dev->interface = number;
 
 	if (!result)
 		INFO(dev, "Using interface %x\n", number);
@@ -972,7 +933,7 @@
 		switch (ctrl->bRequest) {
 		case 0: /* Get the IEEE-1284 PNP String */
 			/* Only one printer interface is supported. */
-			if ((wIndex>>8) != PRINTER_INTERFACE)
+			if ((wIndex>>8) != dev->interface)
 				break;
 
 			value = (pnp_string[0]<<8)|pnp_string[1];
@@ -983,7 +944,7 @@
 
 		case 1: /* Get Port Status */
 			/* Only one printer interface is supported. */
-			if (wIndex != PRINTER_INTERFACE)
+			if (wIndex != dev->interface)
 				break;
 
 			*(u8 *)req->buf = dev->printer_status;
@@ -992,7 +953,7 @@
 
 		case 2: /* Soft Reset */
 			/* Only one printer interface is supported. */
-			if (wIndex != PRINTER_INTERFACE)
+			if (wIndex != dev->interface)
 				break;
 
 			printer_soft_reset(dev);
@@ -1020,6 +981,37 @@
 static int __init printer_func_bind(struct usb_configuration *c,
 		struct usb_function *f)
 {
+	struct printer_dev *dev = container_of(f, struct printer_dev, function);
+	struct usb_composite_dev *cdev = c->cdev;
+	struct usb_ep		*in_ep, *out_ep;
+	int id;
+
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	intf_desc.bInterfaceNumber = id;
+
+	/* all we really need is bulk IN/OUT */
+	in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
+	if (!in_ep) {
+autoconf_fail:
+		dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
+			cdev->gadget->name);
+		return -ENODEV;
+	}
+	in_ep->driver_data = in_ep;	/* claim */
+
+	out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
+	if (!out_ep)
+		goto autoconf_fail;
+	out_ep->driver_data = out_ep;	/* claim */
+
+	/* assumes that all endpoints are dual-speed */
+	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+
+	dev->in_ep = in_ep;
+	dev->out_ep = out_ep;
 	return 0;
 }
 
@@ -1035,7 +1027,8 @@
 	int ret = -ENOTSUPP;
 
 	if (!alt)
-		ret = set_interface(dev, PRINTER_INTERFACE);
+		ret = set_interface(dev, intf);
+
 	return ret;
 }
 
@@ -1107,13 +1100,13 @@
 {
 	struct usb_gadget	*gadget = c->cdev->gadget;
 	struct printer_dev	*dev;
-	struct usb_ep		*in_ep, *out_ep;
 	int			status = -ENOMEM;
-	int			gcnum;
 	size_t			len;
 	u32			i;
 	struct usb_request	*req;
 
+	usb_ep_autoconfig_reset(gadget);
+
 	dev = &usb_printer_gadget;
 
 	dev->function.name = shortname;
@@ -1125,6 +1118,10 @@
 	dev->function.set_alt = printer_func_set_alt;
 	dev->function.disable = printer_func_disable;
 
+	status = usb_add_function(c, &dev->function);
+	if (status)
+		return status;
+
 	/* Setup the sysfs files for the printer gadget. */
 	dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
 				  NULL, "g_printer");
@@ -1145,23 +1142,6 @@
 		goto fail;
 	}
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0) {
-		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-	} else {
-		dev_warn(&gadget->dev, "controller '%s' not recognized\n",
-			gadget->name);
-		/* unrecognized, but safe unless bulk is REALLY quirky */
-		device_desc.bcdDevice =
-			cpu_to_le16(0xFFFF);
-	}
-	snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-
-	if (iSerialNum)
-		strlcpy(serial_num, iSerialNum, sizeof serial_num);
-
 	if (iPNPstring)
 		strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
 
@@ -1169,26 +1149,6 @@
 	pnp_string[0] = (len >> 8) & 0xFF;
 	pnp_string[1] = len & 0xFF;
 
-	/* all we really need is bulk IN/OUT */
-	usb_ep_autoconfig_reset(gadget);
-	in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc);
-	if (!in_ep) {
-autoconf_fail:
-		dev_err(&gadget->dev, "can't autoconfigure on %s\n",
-			gadget->name);
-		return -ENODEV;
-	}
-	in_ep->driver_data = in_ep;	/* claim */
-
-	out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc);
-	if (!out_ep)
-		goto autoconf_fail;
-	out_ep->driver_data = out_ep;	/* claim */
-
-	/* assumes that all endpoints are dual-speed */
-	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
-	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-
 	usb_gadget_set_selfpowered(gadget);
 
 	if (gadget->is_otg) {
@@ -1215,9 +1175,6 @@
 	dev->current_rx_bytes = 0;
 	dev->current_rx_buf = NULL;
 
-	dev->in_ep = in_ep;
-	dev->out_ep = out_ep;
-
 	for (i = 0; i < QLEN; i++) {
 		req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
 		if (!req) {
@@ -1250,8 +1207,6 @@
 	dev->gadget = gadget;
 
 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
-	INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
-			in_ep->name);
 	return 0;
 
 fail:
@@ -1266,14 +1221,28 @@
 
 static int __init printer_bind(struct usb_composite_dev *cdev)
 {
-	return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+	int ret;
+
+	ret = usb_string_ids_tab(cdev, strings);
+	if (ret < 0)
+		return ret;
+	device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
+	device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
+
+	ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+	if (ret)
+		return ret;
+	usb_composite_overwrite_options(cdev, &coverwrite);
+	return ret;
 }
 
-static struct usb_composite_driver printer_driver = {
+static __refdata struct usb_composite_driver printer_driver = {
 	.name           = shortname,
 	.dev            = &device_desc,
 	.strings        = dev_strings,
 	.max_speed      = USB_SPEED_HIGH,
+	.bind		= printer_bind,
 	.unbind		= printer_unbind,
 };
 
@@ -1297,7 +1266,7 @@
 		return status;
 	}
 
-	status = usb_composite_probe(&printer_driver, printer_bind);
+	status = usb_composite_probe(&printer_driver);
 	if (status) {
 		class_destroy(usb_gadget_class);
 		unregister_chrdev_region(g_printer_devno, 1);
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 907ad3e..8efbf08 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -33,7 +33,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
-#include <linux/err.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/io.h>
@@ -1000,7 +999,7 @@
 }
 
 static int pxa25x_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pxa25x_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops pxa25x_udc_ops = {
@@ -1258,7 +1257,7 @@
  * the driver might get unbound.
  */
 static int pxa25x_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct pxa25x_udc	*dev = the_controller;
 	int			retval;
@@ -1286,7 +1285,7 @@
 		dev->gadget.dev.driver = NULL;
 		return retval;
 	}
-	retval = bind(&dev->gadget);
+	retval = bind(&dev->gadget, driver);
 	if (retval) {
 		DMSG("bind to driver %s --> error %d\n",
 				driver->driver.name, retval);
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 861f4df..2eca1e7 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -225,7 +225,7 @@
 		dev->stats.read.bytes, dev->stats.read.ops);
 
 	for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
-		if (dev->ep [i].desc == NULL)
+		if (dev->ep[i].ep.desc == NULL)
 			continue;
 		DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
 	}
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 644b430..979ddad 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1672,7 +1672,7 @@
 }
 
 static int pxa27x_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops pxa_udc_ops = {
@@ -1803,7 +1803,7 @@
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  */
 static int pxa27x_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct pxa_udc *udc = the_controller;
 	int retval;
@@ -1826,7 +1826,7 @@
 		dev_err(udc->dev, "device_add error %d\n", retval);
 		goto add_fail;
 	}
-	retval = bind(&udc->gadget);
+	retval = bind(&udc->gadget, driver);
 	if (retval) {
 		dev_err(udc->dev, "bind to driver %s --> error %d\n",
 			driver->driver.name, retval);
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index b35babe..e4192b8 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -863,26 +863,8 @@
 		 */
 		pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
 			__func__, MsgType, MsgLength);
-		{
-			unsigned i;
-			for (i = 0; i < MsgLength; i += 16) {
-				pr_debug("%03d: "
-					" %02x %02x %02x %02x"
-					" %02x %02x %02x %02x"
-					" %02x %02x %02x %02x"
-					" %02x %02x %02x %02x"
-					"\n",
-					i,
-					buf[i], buf [i+1],
-						buf[i+2], buf[i+3],
-					buf[i+4], buf [i+5],
-						buf[i+6], buf[i+7],
-					buf[i+8], buf [i+9],
-						buf[i+10], buf[i+11],
-					buf[i+12], buf [i+13],
-						buf[i+14], buf[i+15]);
-			}
-		}
+		print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
+				     buf, MsgLength);
 		break;
 	}
 
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 0bb617e..6f696ee 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -2197,7 +2197,7 @@
 	/* issue soft reset */
 	writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL);
 
-	timeout = 1000;
+	timeout = 10000;
 	do {
 		grstctl = readl(hsotg->regs + GRSTCTL);
 	} while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0);
@@ -2207,7 +2207,7 @@
 		return -EINVAL;
 	}
 
-	timeout = 1000;
+	timeout = 10000;
 
 	while (1) {
 		u32 grstctl = readl(hsotg->regs + GRSTCTL);
@@ -3516,7 +3516,7 @@
 	hsotg->dev = dev;
 	hsotg->plat = plat;
 
-	hsotg->clk = clk_get(&pdev->dev, "otg");
+	hsotg->clk = devm_clk_get(&pdev->dev, "otg");
 	if (IS_ERR(hsotg->clk)) {
 		dev_err(dev, "cannot get otg clock\n");
 		return PTR_ERR(hsotg->clk);
@@ -3667,7 +3667,6 @@
 
 err_clk:
 	clk_disable_unprepare(hsotg->clk);
-	clk_put(hsotg->clk);
 
 	return ret;
 }
@@ -3693,7 +3692,6 @@
 	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
 	clk_disable_unprepare(hsotg->clk);
-	clk_put(hsotg->clk);
 
 	device_unregister(&hsotg->gadget.dev);
 	return 0;
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index e26a4e7..d8e785d 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -135,7 +135,6 @@
  * @dev: The device reference used by probe function.
  * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
  * @regs: Remapped base address of controller's register space.
- * @mem_rsrc: Device memory resource used for remapping device register space.
  * irq: IRQ number used by the controller.
  * uclk: Reference to the controller clock.
  * ep0state: Current state of EP0.
@@ -150,7 +149,6 @@
 	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
 	spinlock_t lock;
 	void __iomem *regs;
-	struct resource *mem_rsrc;
 	int irq;
 	struct clk *uclk;
 	int ep0state;
@@ -835,9 +833,9 @@
 {
 	struct s3c_hsudc_req *hsreq;
 
-	hsreq = kzalloc(sizeof *hsreq, gfp_flags);
+	hsreq = kzalloc(sizeof(*hsreq), gfp_flags);
 	if (!hsreq)
-		return 0;
+		return NULL;
 
 	INIT_LIST_HEAD(&hsreq->queue);
 	return &hsreq->req;
@@ -906,16 +904,16 @@
 			csr = readl((u32)hsudc->regs + offset);
 			if (!(csr & S3C_ESR_TX_SUCCESS) &&
 				(s3c_hsudc_write_fifo(hsep, hsreq) == 1))
-				hsreq = 0;
+				hsreq = NULL;
 		} else {
 			csr = readl((u32)hsudc->regs + offset);
 			if ((csr & S3C_ESR_RX_SUCCESS)
 				   && (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
-				hsreq = 0;
+				hsreq = NULL;
 		}
 	}
 
-	if (hsreq != 0)
+	if (hsreq)
 		list_add_tail(&hsreq->queue, &hsep->queue);
 
 	spin_unlock_irqrestore(&hsudc->lock, flags);
@@ -1271,7 +1269,7 @@
 	struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
 	int ret, i;
 
-	hsudc = kzalloc(sizeof(struct s3c_hsudc) +
+	hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
 			sizeof(struct s3c_hsudc_ep) * pd->epnum,
 			GFP_KERNEL);
 	if (!hsudc) {
@@ -1296,25 +1294,12 @@
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(dev, "unable to obtain driver resource data\n");
-		ret = -ENODEV;
-		goto err_res;
-	}
 
-	hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res),
-				dev_name(&pdev->dev));
-	if (!hsudc->mem_rsrc) {
-		dev_err(dev, "failed to reserve register area\n");
-		ret = -ENODEV;
-		goto err_res;
-	}
-
-	hsudc->regs = ioremap(res->start, resource_size(res));
+	hsudc->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hsudc->regs) {
 		dev_err(dev, "error mapping device register area\n");
 		ret = -EBUSY;
-		goto err_remap;
+		goto err_res;
 	}
 
 	spin_lock_init(&hsudc->lock);
@@ -1337,21 +1322,22 @@
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(dev, "unable to obtain IRQ number\n");
-		goto err_irq;
+		goto err_res;
 	}
 	hsudc->irq = ret;
 
-	ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
+	ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0,
+				driver_name, hsudc);
 	if (ret < 0) {
 		dev_err(dev, "irq request failed\n");
-		goto err_irq;
+		goto err_res;
 	}
 
-	hsudc->uclk = clk_get(&pdev->dev, "usb-device");
+	hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device");
 	if (IS_ERR(hsudc->uclk)) {
 		dev_err(dev, "failed to find usb-device clock source\n");
 		ret = PTR_ERR(hsudc->uclk);
-		goto err_clk;
+		goto err_res;
 	}
 	clk_enable(hsudc->uclk);
 
@@ -1377,21 +1363,12 @@
 	device_unregister(&hsudc->gadget.dev);
 err_add_device:
 	clk_disable(hsudc->uclk);
-	clk_put(hsudc->uclk);
-err_clk:
-	free_irq(hsudc->irq, hsudc);
-err_irq:
-	iounmap(hsudc->regs);
-
-err_remap:
-	release_mem_region(res->start, resource_size(res));
 err_res:
 	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		usb_put_phy(hsudc->transceiver);
 
 	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
-	kfree(hsudc);
 	return ret;
 }
 
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index f2e51f5..c33e942 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -12,6 +12,8 @@
  * (at your option) any later version.
  */
 
+#define pr_fmt(fmt) "s3c2410_udc: " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -27,6 +29,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/prefetch.h>
+#include <linux/io.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -35,7 +38,6 @@
 #include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <mach/irqs.h>
@@ -115,7 +117,7 @@
 			sizeof(printk_buf)-len, fmt, args);
 	va_end(args);
 
-	return printk(KERN_DEBUG "%s", printk_buf);
+	return pr_debug("%s", printk_buf);
 }
 #else
 static int dprintk(int level, const char *fmt, ...)
@@ -125,10 +127,10 @@
 #endif
 static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
 {
-	u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+	u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
 	u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
-	u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
-	u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+	u32 ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2;
+	u32 ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2;
 
 	addr_reg       = udc_read(S3C2410_UDC_FUNC_ADDR_REG);
 	pwr_reg        = udc_read(S3C2410_UDC_PWR_REG);
@@ -164,10 +166,10 @@
 		 "EP2_I_CSR2     : 0x%04X\n"
 		 "EP2_O_CSR1     : 0x%04X\n"
 		 "EP2_O_CSR2     : 0x%04X\n",
-			addr_reg,pwr_reg,ep_int_reg,usb_int_reg,
+			addr_reg, pwr_reg, ep_int_reg, usb_int_reg,
 			ep_int_en_reg, usb_int_en_reg, ep0_csr,
-			ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2,
-			ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2
+			ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2,
+			ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2
 		);
 
 	return 0;
@@ -230,7 +232,7 @@
 {
 	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
 
-	udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY
+	udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
 				| S3C2410_UDC_EP0_CSR_DE),
 			S3C2410_UDC_EP0_CSR_REG);
 }
@@ -263,7 +265,7 @@
 
 	list_del_init(&req->queue);
 
-	if (likely (req->req.status == -EINPROGRESS))
+	if (likely(req->req.status == -EINPROGRESS))
 		req->req.status = status;
 	else
 		status = req->req.status;
@@ -280,9 +282,9 @@
 	if (&ep->queue == NULL)
 		return;
 
-	while (!list_empty (&ep->queue)) {
+	while (!list_empty(&ep->queue)) {
 		struct s3c2410_request *req;
-		req = list_entry (ep->queue.next, struct s3c2410_request,
+		req = list_entry(ep->queue.next, struct s3c2410_request,
 				queue);
 		s3c2410_udc_done(ep, req, status);
 	}
@@ -389,10 +391,10 @@
 
 		if (idx == 0) {
 			/* Reset signal => no need to say 'data sent' */
-			if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+			if (!(udc_read(S3C2410_UDC_USB_INT_REG)
 					& S3C2410_UDC_USBINT_RESET))
 				s3c2410_udc_set_ep0_de_in(base_addr);
-			ep->dev->ep0state=EP0_IDLE;
+			ep->dev->ep0state = EP0_IDLE;
 		} else {
 			udc_write(idx, S3C2410_UDC_INDEX_REG);
 			ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
@@ -406,7 +408,7 @@
 	} else {
 		if (idx == 0) {
 			/* Reset signal => no need to say 'data sent' */
-			if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+			if (!(udc_read(S3C2410_UDC_USB_INT_REG)
 					& S3C2410_UDC_USBINT_RESET))
 				s3c2410_udc_set_ep0_ipr(base_addr);
 		} else {
@@ -442,7 +444,7 @@
 	u8		*buf;
 	u32		ep_csr;
 	unsigned	bufferspace;
-	int		is_last=1;
+	int		is_last = 1;
 	unsigned	avail;
 	int		fifo_count = 0;
 	u32		idx;
@@ -510,7 +512,7 @@
 	/* Only ep0 debug messages are interesting */
 	if (idx == 0)
 		dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",
-			__func__, fifo_count,is_last);
+			__func__, fifo_count, is_last);
 
 	if (is_last) {
 		if (idx == 0) {
@@ -542,7 +544,7 @@
 
 static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq)
 {
-	unsigned char *outbuf = (unsigned char*)crq;
+	unsigned char *outbuf = (unsigned char *)crq;
 	int bytes_read = 0;
 
 	udc_write(0, S3C2410_UDC_INDEX_REG);
@@ -648,7 +650,7 @@
 
 	switch (crq->bRequest) {
 	case USB_REQ_SET_CONFIGURATION:
-		dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...\n");
 
 		if (crq->bRequestType == USB_RECIP_DEVICE) {
 			dev->req_config = 1;
@@ -657,7 +659,7 @@
 		break;
 
 	case USB_REQ_SET_INTERFACE:
-		dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...\n");
 
 		if (crq->bRequestType == USB_RECIP_INTERFACE) {
 			dev->req_config = 1;
@@ -666,7 +668,7 @@
 		break;
 
 	case USB_REQ_SET_ADDRESS:
-		dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...\n");
 
 		if (crq->bRequestType == USB_RECIP_DEVICE) {
 			tmp = crq->wValue & 0x7F;
@@ -679,13 +681,12 @@
 		break;
 
 	case USB_REQ_GET_STATUS:
-		dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+		dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...\n");
 		s3c2410_udc_clear_ep0_opr(base_addr);
 
 		if (dev->req_std) {
-			if (!s3c2410_udc_get_status(dev, crq)) {
+			if (!s3c2410_udc_get_status(dev, crq))
 				return;
-			}
 		}
 		break;
 
@@ -750,7 +751,7 @@
 		/* deferred i/o == no response yet */
 	} else if (dev->req_pending) {
 		dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
-		dev->req_pending=0;
+		dev->req_pending = 0;
 	}
 
 	dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
@@ -801,16 +802,14 @@
 
 	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */
 		dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
-		if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
+		if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req)
 			s3c2410_udc_write_fifo(ep, req);
-		}
 		break;
 
 	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */
 		dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
-		if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
-			s3c2410_udc_read_fifo(ep,req);
-		}
+		if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req)
+			s3c2410_udc_read_fifo(ep, req);
 		break;
 
 	case EP0_END_XFER:
@@ -836,7 +835,7 @@
 	u32			ep_csr1;
 	u32			idx;
 
-	if (likely (!list_empty(&ep->queue)))
+	if (likely(!list_empty(&ep->queue)))
 		req = list_entry(ep->queue.next,
 				struct s3c2410_request, queue);
 	else
@@ -858,9 +857,8 @@
 			return;
 		}
 
-		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {
-			s3c2410_udc_write_fifo(ep,req);
-		}
+		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
+			s3c2410_udc_write_fifo(ep, req);
 	} else {
 		udc_write(idx, S3C2410_UDC_INDEX_REG);
 		ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);
@@ -873,9 +871,8 @@
 			return;
 		}
 
-		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
-			s3c2410_udc_read_fifo(ep,req);
-		}
+		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req)
+			s3c2410_udc_read_fifo(ep, req);
 	}
 }
 
@@ -1057,7 +1054,7 @@
 	struct s3c2410_ep	*ep;
 	u32			max, tmp;
 	unsigned long		flags;
-	u32			csr1,csr2;
+	u32			csr1, csr2;
 	u32			int_en_reg;
 
 	ep = to_s3c2410_ep(_ep);
@@ -1073,7 +1070,7 @@
 
 	max = usb_endpoint_maxp(desc) & 0x1fff;
 
-	local_irq_save (flags);
+	local_irq_save(flags);
 	_ep->maxpacket = max & 0x7ff;
 	ep->ep.desc = desc;
 	ep->halted = 0;
@@ -1117,11 +1114,11 @@
 
 	/* print some debug message */
 	tmp = desc->bEndpointAddress;
-	dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
-		 _ep->name,ep->num, tmp,
+	dprintk(DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+		 _ep->name, ep->num, tmp,
 		 desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
 
-	local_irq_restore (flags);
+	local_irq_restore(flags);
 	s3c2410_udc_set_halt(_ep, 0);
 
 	return 0;
@@ -1149,7 +1146,7 @@
 	ep->ep.desc = NULL;
 	ep->halted = 1;
 
-	s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
+	s3c2410_udc_nuke(ep->dev, ep, -ESHUTDOWN);
 
 	/* disable irqs */
 	int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
@@ -1170,16 +1167,16 @@
 {
 	struct s3c2410_request *req;
 
-	dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);
+	dprintk(DEBUG_VERBOSE, "%s(%p,%d)\n", __func__, _ep, mem_flags);
 
 	if (!_ep)
 		return NULL;
 
-	req = kzalloc (sizeof(struct s3c2410_request), mem_flags);
+	req = kzalloc(sizeof(struct s3c2410_request), mem_flags);
 	if (!req)
 		return NULL;
 
-	INIT_LIST_HEAD (&req->queue);
+	INIT_LIST_HEAD(&req->queue);
 	return &req->req;
 }
 
@@ -1197,7 +1194,7 @@
 	if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name))
 		return;
 
-	WARN_ON (!list_empty (&req->queue));
+	WARN_ON(!list_empty(&req->queue));
 	kfree(req);
 }
 
@@ -1220,12 +1217,12 @@
 	}
 
 	dev = ep->dev;
-	if (unlikely (!dev->driver
+	if (unlikely(!dev->driver
 			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
 		return -ESHUTDOWN;
 	}
 
-	local_irq_save (flags);
+	local_irq_save(flags);
 
 	if (unlikely(!_req || !_req->complete
 			|| !_req->buf || !list_empty(&req->queue))) {
@@ -1233,7 +1230,7 @@
 			dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
 		else {
 			dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
-				__func__, !_req->complete,!_req->buf,
+				__func__, !_req->complete, !_req->buf,
 				!list_empty(&req->queue));
 		}
 
@@ -1299,7 +1296,7 @@
 	}
 
 	/* pio or dma irq handler advances the queue. */
-	if (likely (req != 0))
+	if (likely(req))
 		list_add_tail(&req->queue, &ep->queue);
 
 	local_irq_restore(flags);
@@ -1329,11 +1326,11 @@
 
 	udc = to_s3c2410_udc(ep->gadget);
 
-	local_irq_save (flags);
+	local_irq_save(flags);
 
-	list_for_each_entry (req, &ep->queue, queue) {
+	list_for_each_entry(req, &ep->queue, queue) {
 		if (&req->req == _req) {
-			list_del_init (&req->queue);
+			list_del_init(&req->queue);
 			_req->status = -ECONNRESET;
 			retval = 0;
 			break;
@@ -1348,7 +1345,7 @@
 		s3c2410_udc_done(ep, req, -ECONNRESET);
 	}
 
-	local_irq_restore (flags);
+	local_irq_restore(flags);
 	return retval;
 }
 
@@ -1367,7 +1364,7 @@
 		return -EINVAL;
 	}
 
-	local_irq_save (flags);
+	local_irq_save(flags);
 
 	idx = ep->bEndpointAddress & 0x7F;
 
@@ -1376,7 +1373,7 @@
 		s3c2410_udc_set_ep0_de_out(base_addr);
 	} else {
 		udc_write(idx, S3C2410_UDC_INDEX_REG);
-		ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)
+		ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
 				? S3C2410_UDC_IN_CSR1_REG
 				: S3C2410_UDC_OUT_CSR1_REG);
 
@@ -1404,7 +1401,7 @@
 	}
 
 	ep->halted = value ? 1 : 0;
-	local_irq_restore (flags);
+	local_irq_restore(flags);
 
 	return 0;
 }
@@ -1484,9 +1481,9 @@
 			}
 			s3c2410_udc_disable(udc);
 		}
-	}
-	else
+	} else {
 		return -EOPNOTSUPP;
+	}
 
 	return 0;
 }
@@ -1542,7 +1539,7 @@
 }
 
 static int s3c2410_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops s3c2410_ops = {
@@ -1617,20 +1614,20 @@
 	u32 i;
 
 	/* device/ep0 records init */
-	INIT_LIST_HEAD (&dev->gadget.ep_list);
-	INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
 	dev->ep0state = EP0_IDLE;
 
 	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
 		struct s3c2410_ep *ep = &dev->ep[i];
 
 		if (i != 0)
-			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+			list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
 
 		ep->dev = dev;
 		ep->ep.desc = NULL;
 		ep->halted = 0;
-		INIT_LIST_HEAD (&ep->queue);
+		INIT_LIST_HEAD(&ep->queue);
 	}
 }
 
@@ -1668,7 +1665,7 @@
 }
 
 static int s3c2410_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	struct s3c2410_udc *udc = the_controller;
 	int		retval;
@@ -1683,13 +1680,13 @@
 		return -EBUSY;
 
 	if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
-		printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
+		dev_err(&udc->gadget.dev, "Invalid driver: bind %p setup %p speed %d\n",
 			bind, driver->setup, driver->max_speed);
 		return -EINVAL;
 	}
 #if defined(MODULE)
 	if (!driver->unbind) {
-		printk(KERN_ERR "Invalid driver: no unbind method\n");
+		dev_err(&udc->gadget.dev, "Invalid driver: no unbind method\n");
 		return -EINVAL;
 	}
 #endif
@@ -1699,15 +1696,17 @@
 	udc->gadget.dev.driver = &driver->driver;
 
 	/* Bind the driver */
-	if ((retval = device_add(&udc->gadget.dev)) != 0) {
-		printk(KERN_ERR "Error in device_add() : %d\n",retval);
+	retval = device_add(&udc->gadget.dev);
+	if (retval) {
+		dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
 		goto register_error;
 	}
 
 	dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
 		driver->driver.name);
 
-	if ((retval = bind(&udc->gadget)) != 0) {
+	retval = bind(&udc->gadget, driver);
+	if (retval) {
 		device_del(&udc->gadget.dev);
 		goto register_error;
 	}
@@ -1865,7 +1864,7 @@
 		memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
 	}
 
-	spin_lock_init (&udc->lock);
+	spin_lock_init(&udc->lock);
 	udc_info = pdev->dev.platform_data;
 
 	rsrc_start = S3C2410_PA_USBDEV;
@@ -2028,7 +2027,8 @@
 }
 
 #ifdef CONFIG_PM
-static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+static int
+s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
 {
 	s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
 
@@ -2073,7 +2073,7 @@
 
 	s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
 	if (IS_ERR(s3c2410_udc_debugfs_root)) {
-		printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+		pr_err("%s: debugfs dir creation failed %ld\n",
 			gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
 		s3c2410_udc_debugfs_root = NULL;
 	}
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 665c074..44752f5 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -37,17 +36,13 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_acm.c"
 #include "f_obex.c"
 #include "f_serial.c"
 #include "u_serial.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* Thanks to NetChip Technologies for donating this product ID.
 *
@@ -61,15 +56,12 @@
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-#define STRING_DESCRIPTION_IDX		2
-
-static char manufacturer[50];
+#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = GS_VERSION_NAME,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	[STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
 	{  } /* end of list */
 };
@@ -94,7 +86,7 @@
 	/* .bMaxPacketSize0 = f(hardware) */
 	.idVendor =		cpu_to_le16(GS_VENDOR_ID),
 	/* .idProduct =	f(use_acm) */
-	/* .bcdDevice = f(hardware) */
+	.bcdDevice = cpu_to_le16(GS_VERSION_NUM),
 	/* .iManufacturer = DYNAMIC */
 	/* .iProduct = DYNAMIC */
 	.bNumConfigurations =	1,
@@ -162,8 +154,6 @@
 
 static int __init gs_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
-	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 
 	status = gserial_setup(cdev->gadget, n_ports);
@@ -174,50 +164,14 @@
 	 * contents can be overridden by the composite_dev glue.
 	 */
 
-	/* device description: manufacturer, product */
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-	status = usb_string_id(cdev);
+	status = usb_string_ids_tab(cdev, strings_dev);
 	if (status < 0)
 		goto fail;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-
-	device_desc.iProduct = status;
-
-	/* config description */
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail;
-	strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+	status = strings_dev[STRING_DESCRIPTION_IDX].id;
 	serial_config_driver.iConfiguration = status;
 
-	/* set up other descriptors */
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum);
-	else {
-		/* this is so simple (for now, no altsettings) that it
-		 * SHOULD NOT have problems with bulk-capable hardware.
-		 * so warn about unrcognized controllers -- don't panic.
-		 *
-		 * things like configuration and altsetting numbering
-		 * can need hardware-specific attention though.
-		 */
-		pr_warning("gs_bind: controller '%s' not recognized\n",
-			gadget->name);
-		device_desc.bcdDevice =
-			cpu_to_le16(GS_VERSION_NUM | 0x0099);
-	}
-
 	if (gadget_is_otg(cdev->gadget)) {
 		serial_config_driver.descriptors = otg_desc;
 		serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -229,6 +183,7 @@
 	if (status < 0)
 		goto fail;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	INFO(cdev, "%s\n", GS_VERSION_NAME);
 
 	return 0;
@@ -238,11 +193,12 @@
 	return status;
 }
 
-static struct usb_composite_driver gserial_driver = {
+static __refdata struct usb_composite_driver gserial_driver = {
 	.name		= "g_serial",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_SUPER,
+	.bind		= gs_bind,
 };
 
 static int __init init(void)
@@ -271,7 +227,7 @@
 	}
 	strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
 
-	return usb_composite_probe(&gserial_driver, gs_bind);
+	return usb_composite_probe(&gserial_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index 5444866..eaa1005 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -25,13 +25,10 @@
 #include <target/configfs_macros.h>
 #include <asm/unaligned.h>
 
-#include "usbstring.c"
-#include "epautoconf.c"
-#include "config.c"
-#include "composite.c"
-
 #include "tcm_usb_gadget.h"
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static struct target_fabric_configfs *usbg_fabric_configfs;
 
 static inline struct f_uas *to_f_uas(struct usb_function *f)
@@ -1977,7 +1974,6 @@
 	.bInterfaceClass =      USB_CLASS_MASS_STORAGE,
 	.bInterfaceSubClass =   USB_SC_SCSI,
 	.bInterfaceProtocol =   USB_PR_BULK,
-	.iInterface =           USB_G_STR_INT_UAS,
 };
 
 static struct usb_interface_descriptor uasp_intf_desc = {
@@ -1988,7 +1984,6 @@
 	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
 	.bInterfaceSubClass =	USB_SC_SCSI,
 	.bInterfaceProtocol =	USB_PR_UAS,
-	.iInterface =		USB_G_STR_INT_BBB,
 };
 
 static struct usb_endpoint_descriptor uasp_bi_desc = {
@@ -2209,20 +2204,16 @@
 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
 	.idVendor =		cpu_to_le16(UAS_VENDOR_ID),
 	.idProduct =		cpu_to_le16(UAS_PRODUCT_ID),
-	.iManufacturer =	USB_G_STR_MANUFACTOR,
-	.iProduct =		USB_G_STR_PRODUCT,
-	.iSerialNumber =	USB_G_STR_SERIAL,
-
 	.bNumConfigurations =   1,
 };
 
 static struct usb_string	usbg_us_strings[] = {
-	{ USB_G_STR_MANUFACTOR,	"Target Manufactor"},
-	{ USB_G_STR_PRODUCT,	"Target Product"},
-	{ USB_G_STR_SERIAL,	"000000000001"},
-	{ USB_G_STR_CONFIG,	"default config"},
-	{ USB_G_STR_INT_UAS,	"USB Attached SCSI"},
-	{ USB_G_STR_INT_BBB,	"Bulk Only Transport"},
+	[USB_GADGET_MANUFACTURER_IDX].s	= "Target Manufactor",
+	[USB_GADGET_PRODUCT_IDX].s	= "Target Product",
+	[USB_GADGET_SERIAL_IDX].s	= "000000000001",
+	[USB_G_STR_CONFIG].s		= "default config",
+	[USB_G_STR_INT_UAS].s		= "USB Attached SCSI",
+	[USB_G_STR_INT_BBB].s		= "Bulk Only Transport",
 	{ },
 };
 
@@ -2244,7 +2235,6 @@
 static struct usb_configuration usbg_config_driver = {
 	.label                  = "Linux Target",
 	.bConfigurationValue    = 1,
-	.iConfiguration		= USB_G_STR_CONFIG,
 	.bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 };
 
@@ -2417,6 +2407,9 @@
 	fu->function.disable = usbg_disable;
 	fu->tpg = the_only_tpg_I_currently_have;
 
+	bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id;
+	uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id;
+
 	ret = usb_add_function(c, &fu->function);
 	if (ret)
 		goto err;
@@ -2431,22 +2424,38 @@
 {
 	int ret;
 
+	ret = usb_string_ids_tab(cdev, usbg_us_strings);
+	if (ret)
+		return ret;
+
+	usbg_device_desc.iManufacturer =
+		usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id;
+	usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id;
+	usbg_device_desc.iSerialNumber =
+		usbg_us_strings[USB_GADGET_SERIAL_IDX].id;
+	usbg_config_driver.iConfiguration =
+		usbg_us_strings[USB_G_STR_CONFIG].id;
+
 	ret = usb_add_config(cdev, &usbg_config_driver,
 			usbg_cfg_bind);
+	if (ret)
+		return ret;
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	return 0;
 }
 
-static struct usb_composite_driver usbg_driver = {
+static __refdata struct usb_composite_driver usbg_driver = {
 	.name           = "g_target",
 	.dev            = &usbg_device_desc,
 	.strings        = usbg_strings,
 	.max_speed      = USB_SPEED_SUPER,
+	.bind		= usb_target_bind,
 	.unbind         = guas_unbind,
 };
 
 static int usbg_attach(struct usbg_tpg *tpg)
 {
-	return usb_composite_probe(&usbg_driver, usb_target_bind);
+	return usb_composite_probe(&usbg_driver);
 }
 
 static void usbg_detach(struct usbg_tpg *tpg)
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h
index bb18999..8289219 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.h
+++ b/drivers/usb/gadget/tcm_usb_gadget.h
@@ -16,12 +16,11 @@
 #define UASP_SS_EP_COMP_LOG_STREAMS 4
 #define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
 
-#define USB_G_STR_MANUFACTOR    1
-#define USB_G_STR_PRODUCT       2
-#define USB_G_STR_SERIAL        3
-#define USB_G_STR_CONFIG        4
-#define USB_G_STR_INT_UAS       5
-#define USB_G_STR_INT_BBB       6
+enum {
+	USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX,
+	USB_G_STR_INT_UAS,
+	USB_G_STR_INT_BBB,
+};
 
 #define USB_G_ALT_INT_BBB       0
 #define USB_G_ALT_INT_UAS       1
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 0e52309..b9c4690 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -14,6 +14,7 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/device.h>
 #include <linux/ctype.h>
@@ -83,17 +84,10 @@
 
 #define DEFAULT_QLEN	2	/* double buffering by default */
 
-
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 static unsigned qmult = 5;
 module_param(qmult, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
 
-#else	/* full speed (low speed doesn't do bulk) */
-#define qmult		1
-#endif
-
 /* for dual-speed hardware, use deeper queues at high/super speed */
 static inline int qlen(struct usb_gadget *gadget)
 {
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index e5e44f8..f3cd969 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -118,7 +118,7 @@
  */
 static inline int usb_gadget_start(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
 	return gadget->ops->start(driver, bind);
 }
@@ -262,8 +262,8 @@
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
 	if (udc_is_newstyle(udc)) {
-		udc->driver->disconnect(udc->gadget);
 		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
 		udc->driver->unbind(udc->gadget);
 		usb_gadget_udc_stop(udc->gadget, udc->driver);
 	} else {
@@ -311,13 +311,12 @@
 
 /* ------------------------------------------------------------------------- */
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
 {
 	struct usb_udc		*udc = NULL;
 	int			ret;
 
-	if (!driver || !bind || !driver->setup)
+	if (!driver || !driver->bind || !driver->setup)
 		return -EINVAL;
 
 	mutex_lock(&udc_lock);
@@ -339,7 +338,7 @@
 	udc->dev.driver = &driver->driver;
 
 	if (udc_is_newstyle(udc)) {
-		ret = bind(udc->gadget);
+		ret = driver->bind(udc->gadget, driver);
 		if (ret)
 			goto err1;
 		ret = usb_gadget_udc_start(udc->gadget, driver);
@@ -350,7 +349,7 @@
 		usb_gadget_connect(udc->gadget);
 	} else {
 
-		ret = usb_gadget_start(udc->gadget, driver, bind);
+		ret = usb_gadget_start(udc->gadget, driver, driver->bind);
 		if (ret)
 			goto err1;
 
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 4d25b90..1f49fce 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -9,6 +9,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/device.h>
@@ -68,4 +69,4 @@
 	buf [1] = USB_DT_STRING;
 	return buf [0];
 }
-
+EXPORT_SYMBOL_GPL(usb_gadget_get_string);
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index 120e134..69cf5c2 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -23,16 +23,12 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "uvc_queue.c"
 #include "uvc_video.c"
 #include "uvc_v4l2.c"
 #include "f_uvc.c"
 
+USB_GADGET_COMPOSITE_OPTIONS();
 /* --------------------------------------------------------------------------
  * Device descriptor
  */
@@ -47,13 +43,12 @@
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-#define STRING_DESCRIPTION_IDX		2
+#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_string webcam_strings[] = {
-	[STRING_MANUFACTURER_IDX].s = webcam_vendor_label,
-	[STRING_PRODUCT_IDX].s = webcam_product_label,
+	[USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
+	[USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
+	[USB_GADGET_SERIAL_IDX].s = "",
 	[STRING_DESCRIPTION_IDX].s = webcam_config_label,
 	{  }
 };
@@ -358,26 +353,22 @@
 	/* Allocate string descriptor numbers ... note that string contents
 	 * can be overridden by the composite_dev glue.
 	 */
-	if ((ret = usb_string_id(cdev)) < 0)
+	ret = usb_string_ids_tab(cdev, webcam_strings);
+	if (ret < 0)
 		goto error;
-	webcam_strings[STRING_MANUFACTURER_IDX].id = ret;
-	webcam_device_descriptor.iManufacturer = ret;
-
-	if ((ret = usb_string_id(cdev)) < 0)
-		goto error;
-	webcam_strings[STRING_PRODUCT_IDX].id = ret;
-	webcam_device_descriptor.iProduct = ret;
-
-	if ((ret = usb_string_id(cdev)) < 0)
-		goto error;
-	webcam_strings[STRING_DESCRIPTION_IDX].id = ret;
-	webcam_config_driver.iConfiguration = ret;
+	webcam_device_descriptor.iManufacturer =
+		webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
+	webcam_device_descriptor.iProduct =
+		webcam_strings[USB_GADGET_PRODUCT_IDX].id;
+	webcam_config_driver.iConfiguration =
+		webcam_strings[STRING_DESCRIPTION_IDX].id;
 
 	/* Register our configuration. */
 	if ((ret = usb_add_config(cdev, &webcam_config_driver,
 					webcam_config_bind)) < 0)
 		goto error;
 
+	usb_composite_overwrite_options(cdev, &coverwrite);
 	INFO(cdev, "Webcam Video Gadget\n");
 	return 0;
 
@@ -390,18 +381,19 @@
  * Driver
  */
 
-static struct usb_composite_driver webcam_driver = {
+static __refdata struct usb_composite_driver webcam_driver = {
 	.name		= "g_webcam",
 	.dev		= &webcam_device_descriptor,
 	.strings	= webcam_device_strings,
 	.max_speed	= USB_SPEED_SUPER,
+	.bind		= webcam_bind,
 	.unbind		= webcam_unbind,
 };
 
 static int __init
 webcam_init(void)
 {
-	return usb_composite_probe(&webcam_driver, webcam_bind);
+	return usb_composite_probe(&webcam_driver);
 }
 
 static void __exit
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 12ad516..6bf4c06 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -42,7 +42,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include "g_zero.h"
@@ -58,15 +57,11 @@
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_sourcesink.c"
 #include "f_loopback.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define DRIVER_VERSION		"Cinco de Mayo 2008"
 
@@ -141,20 +136,13 @@
 #endif
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX		0
-#define STRING_PRODUCT_IDX		1
-#define STRING_SERIAL_IDX		2
-
-static char manufacturer[50];
-
 /* default serial number takes at least two packets */
 static char serial[] = "0123456789.0123456789.0123456789";
 
 static struct usb_string strings_dev[] = {
-	[STRING_MANUFACTURER_IDX].s = manufacturer,
-	[STRING_PRODUCT_IDX].s = longname,
-	[STRING_SERIAL_IDX].s = serial,
+	[USB_GADGET_MANUFACTURER_IDX].s = "",
+	[USB_GADGET_PRODUCT_IDX].s = longname,
+	[USB_GADGET_SERIAL_IDX].s = serial,
 	{  }			/* end of list */
 };
 
@@ -265,30 +253,18 @@
 
 static int __init zero_bind(struct usb_composite_dev *cdev)
 {
-	int			gcnum;
-	struct usb_gadget	*gadget = cdev->gadget;
-	int			id;
+	int			status;
 
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 */
-	id = usb_string_id(cdev);
-	if (id < 0)
-		return id;
-	strings_dev[STRING_MANUFACTURER_IDX].id = id;
-	device_desc.iManufacturer = id;
+	status = usb_string_ids_tab(cdev, strings_dev);
+	if (status < 0)
+		return status;
 
-	id = usb_string_id(cdev);
-	if (id < 0)
-		return id;
-	strings_dev[STRING_PRODUCT_IDX].id = id;
-	device_desc.iProduct = id;
-
-	id = usb_string_id(cdev);
-	if (id < 0)
-		return id;
-	strings_dev[STRING_SERIAL_IDX].id = id;
-	device_desc.iSerialNumber = id;
+	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+	device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;
 
 	setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
 
@@ -303,28 +279,10 @@
 		loopback_add(cdev, autoresume != 0);
 	}
 
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-	else {
-		/* gadget zero is so simple (for now, no altsettings) that
-		 * it SHOULD NOT have problems with bulk-capable hardware.
-		 * so just warn about unrcognized controllers -- don't panic.
-		 *
-		 * things like configuration and altsetting numbering
-		 * can need hardware-specific attention though.
-		 */
-		pr_warning("%s: controller '%s' not recognized\n",
-			longname, gadget->name);
-		device_desc.bcdDevice = cpu_to_le16(0x9999);
-	}
+	usb_composite_overwrite_options(cdev, &coverwrite);
 
 	INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
 
-	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-		init_utsname()->sysname, init_utsname()->release,
-		gadget->name);
-
 	return 0;
 }
 
@@ -334,11 +292,12 @@
 	return 0;
 }
 
-static struct usb_composite_driver zero_driver = {
+static __refdata struct usb_composite_driver zero_driver = {
 	.name		= "zero",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.max_speed	= USB_SPEED_SUPER,
+	.bind		= zero_bind,
 	.unbind		= zero_unbind,
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
@@ -349,7 +308,7 @@
 
 static int __init init(void)
 {
-	return usb_composite_probe(&zero_driver, zero_bind);
+	return usb_composite_probe(&zero_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 075d2ec..3f1431d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -18,8 +18,8 @@
 	  module will be called c67x00.
 
 config USB_XHCI_HCD
-	tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
-	depends on USB && USB_ARCH_HAS_XHCI && EXPERIMENTAL
+	tristate "xHCI HCD (USB 3.0) support"
+	depends on USB && USB_ARCH_HAS_XHCI
 	---help---
 	  The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
 	  "SuperSpeed" host controller hardware.
@@ -262,7 +262,7 @@
 
 config USB_ISP1760_HCD
 	tristate "ISP 1760 HCD support"
-	depends on USB && EXPERIMENTAL
+	depends on USB
 	---help---
 	  The ISP1760 chip is a USB 2.0 host controller.
 
@@ -292,7 +292,7 @@
 	depends on USB && USB_ARCH_HAS_OHCI
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
 	select USB_OTG_UTILS if ARCH_OMAP
-	select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008
+	depends on USB_ISP1301 || !ARCH_LPC32XX
 	---help---
 	  The Open Host Controller Interface (OHCI) is a standard for accessing
 	  USB 1.1 host controller hardware.  It does more in hardware than Intel's
@@ -376,7 +376,7 @@
 
 config USB_OHCI_HCD_SSB
 	bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)"
-	depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL
+	depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD)
 	select USB_HCD_SSB
 	select USB_OHCI_HCD_PLATFORM
 	default n
@@ -414,21 +414,21 @@
 
 config USB_OHCI_HCD_PLATFORM
 	bool "Generic OHCI driver for a platform device"
-	depends on USB_OHCI_HCD && EXPERIMENTAL
+	depends on USB_OHCI_HCD
 	default n
 	---help---
 	  Adds an OHCI host driver for a generic platform device, which
-	  provieds a memory space and an irq.
+	  provides a memory space and an irq.
 
 	  If unsure, say N.
 
 config USB_EHCI_HCD_PLATFORM
 	bool "Generic EHCI driver for a platform device"
-	depends on USB_EHCI_HCD && EXPERIMENTAL
+	depends on USB_EHCI_HCD
 	default n
 	---help---
 	  Adds an EHCI host driver for a generic platform device, which
-	  provieds a memory space and an irq.
+	  provides a memory space and an irq.
 
 	  If unsure, say N.
 
@@ -450,7 +450,7 @@
 
 config USB_UHCI_HCD
 	tristate "UHCI HCD (most Intel and VIA) support"
-	depends on USB && (PCI || SPARC_LEON)
+	depends on USB && (PCI || SPARC_LEON || ARCH_VT8500)
 	---help---
 	  The Universal Host Controller Interface is a standard by Intel for
 	  accessing the USB hardware in the PC (which is also called the USB
@@ -468,7 +468,15 @@
 config USB_UHCI_SUPPORT_NON_PCI_HC
 	bool
 	depends on USB_UHCI_HCD
-	default y if SPARC_LEON
+	default y if (SPARC_LEON || ARCH_VT8500)
+
+config USB_UHCI_PLATFORM
+	bool "Generic UHCI Platform Driver support"
+	depends on USB_UHCI_SUPPORT_NON_PCI_HC
+	default y if ARCH_VT8500
+	---help---
+	  Enable support for generic UHCI platform devices that require no
+	  additional configuration.
 
 config USB_UHCI_BIG_ENDIAN_MMIO
 	bool
@@ -583,8 +591,7 @@
 	  module will be called renesas-usbhs.
 
 config USB_WHCI_HCD
-	tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Wireless USB Host Controller Interface (WHCI) driver"
 	depends on PCI && USB && UWB
 	select USB_WUSB
 	select UWB_WHCI
@@ -596,8 +603,7 @@
 	  will be called "whci-hcd".
 
 config USB_HWA_HCD
-	tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Host Wire Adapter (HWA) driver"
 	depends on USB && UWB
 	select USB_WUSB
 	select UWB_HWA
@@ -648,7 +654,7 @@
 
 config USB_HCD_BCMA
 	tristate "BCMA usb host driver"
-	depends on BCMA && EXPERIMENTAL
+	depends on BCMA
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
@@ -660,7 +666,7 @@
 
 config USB_HCD_SSB
 	tristate "SSB usb host driver"
-	depends on SSB && EXPERIMENTAL
+	depends on SSB
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index a47e2cf..411bb74 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -150,31 +150,24 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-				driver->description)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		retval = -EBUSY;
-		goto fail_request_resource;
-	}
-
-	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (hcd->regs == NULL) {
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		retval = -EFAULT;
-		goto fail_ioremap;
+		goto fail_request_resource;
 	}
 
-	iclk = clk_get(&pdev->dev, "ehci_clk");
+	iclk = devm_clk_get(&pdev->dev, "ehci_clk");
 	if (IS_ERR(iclk)) {
 		dev_err(&pdev->dev, "Error getting interface clock\n");
 		retval = -ENOENT;
-		goto fail_get_iclk;
+		goto fail_request_resource;
 	}
-	fclk = clk_get(&pdev->dev, "uhpck");
+	fclk = devm_clk_get(&pdev->dev, "uhpck");
 	if (IS_ERR(fclk)) {
 		dev_err(&pdev->dev, "Error getting function clock\n");
 		retval = -ENOENT;
-		goto fail_get_fclk;
+		goto fail_request_resource;
 	}
 
 	atmel_start_ehci(pdev);
@@ -187,13 +180,6 @@
 
 fail_add_hcd:
 	atmel_stop_ehci(pdev);
-	clk_put(fclk);
-fail_get_fclk:
-	clk_put(iclk);
-fail_get_iclk:
-	iounmap(hcd->regs);
-fail_ioremap:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
 	usb_put_hcd(hcd);
 fail_create_hcd:
@@ -209,13 +195,9 @@
 
 	ehci_shutdown(hcd);
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 
 	atmel_stop_ehci(pdev);
-	clk_put(fclk);
-	clk_put(iclk);
 	fclk = iclk = NULL;
 
 	return 0;
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index cba10d6..65c945e 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -98,23 +98,17 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug("request_mem_region failed");
-		ret = -EBUSY;
-		goto err1;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hcd->regs) {
-		pr_debug("ioremap failed");
+		pr_debug("devm_request_and_ioremap failed");
 		ret = -ENOMEM;
-		goto err2;
+		goto err1;
 	}
 
 	if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) {
 		printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
 		ret = -ENODEV;
-		goto err3;
+		goto err1;
 	}
 
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
@@ -125,10 +119,6 @@
 	}
 
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-err3:
-	iounmap(hcd->regs);
-err2:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
 	usb_put_hcd(hcd);
 	return ret;
@@ -140,8 +130,6 @@
 
 	usb_remove_hcd(hcd);
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	platform_set_drvdata(pdev, NULL);
 
diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c
index caaa3e5..d91708d 100644
--- a/drivers/usb/host/ehci-cns3xxx.c
+++ b/drivers/usb/host/ehci-cns3xxx.c
@@ -105,27 +105,17 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-				driver->description)) {
-		dev_dbg(dev, "controller already in use\n");
-		retval = -EBUSY;
-		goto err1;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (hcd->regs == NULL) {
 		dev_dbg(dev, "error mapping memory\n");
 		retval = -EFAULT;
-		goto err2;
+		goto err1;
 	}
 
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval == 0)
 		return retval;
 
-	iounmap(hcd->regs);
-err2:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
 	usb_put_hcd(hcd);
 
@@ -137,8 +127,6 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
 	/*
 	 * EHCI and OHCI share the same clock and power,
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index f0c00de..1599806 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -653,10 +653,8 @@
 						seen [seen_count++].qh = p.qh;
 				} else
 					temp = 0;
-				if (p.qh) {
-					tag = Q_NEXT_TYPE(ehci, hw->hw_next);
-					p = p.qh->qh_next;
-				}
+				tag = Q_NEXT_TYPE(ehci, hw->hw_next);
+				p = p.qh->qh_next;
 				break;
 			case Q_TYPE_FSTN:
 				temp = scnprintf (next, size,
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index b7451b2..9bfde82 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -210,11 +210,11 @@
 	usb_put_hcd(hcd);
 }
 
-static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
+static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
 			       enum fsl_usb2_phy_modes phy_mode,
 			       unsigned int port_offset)
 {
-	u32 portsc, temp;
+	u32 portsc;
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	void __iomem *non_ehci = hcd->regs;
 	struct device *dev = hcd->self.controller;
@@ -232,9 +232,15 @@
 	case FSL_USB2_PHY_ULPI:
 		if (pdata->controller_ver) {
 			/* controller version 1.6 or above */
-			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL,
+					ULPI_PHY_CLK_SEL);
+			/*
+			 * Due to controller issue of PHY_CLK_VALID in ULPI
+			 * mode, we set USB_CTRL_USB_EN before checking
+			 * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
+			 */
+			clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
+					UTMI_PHY_EN, USB_CTRL_USB_EN);
 		}
 		portsc |= PORT_PTS_ULPI;
 		break;
@@ -247,9 +253,7 @@
 	case FSL_USB2_PHY_UTMI:
 		if (pdata->controller_ver) {
 			/* controller version 1.6 or above */
-			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				UTMI_PHY_EN | USB_CTRL_USB_EN);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
 			mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
 						become stable - 10ms*/
 		}
@@ -262,23 +266,33 @@
 	case FSL_USB2_PHY_NONE:
 		break;
 	}
+
+	if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) {
+		/* check PHY_CLK_VALID to get phy clk valid */
+		if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
+				PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
+			printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
+			return -EINVAL;
+		}
+	}
+
 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
+
+	if (phy_mode != FSL_USB2_PHY_ULPI)
+		setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN);
+
+	return 0;
 }
 
-static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
 	struct usb_hcd *hcd = ehci_to_hcd(ehci);
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
-	u32 temp;
 
 	pdata = hcd->self.controller->platform_data;
 
-	/* Enable PHY interface in the control reg. */
 	if (pdata->have_sysif_regs) {
-		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-
 		/*
 		* Turn on cache snooping hardware, since some PowerPC platforms
 		* wholly rely on hardware to deal with cache coherent
@@ -293,7 +307,8 @@
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+		if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+			return -EINVAL;
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -307,9 +322,12 @@
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+				return -EINVAL;
+
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1))
+				return -EINVAL;
 	}
 
 	if (pdata->have_sysif_regs) {
@@ -322,12 +340,15 @@
 #endif
 		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
 	}
+
+	return 0;
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-	ehci_fsl_usb_setup(ehci);
+	if (ehci_fsl_usb_setup(ehci))
+		return -EINVAL;
 	ehci_port_power(ehci, 0);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 8840368..dbd292e 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -61,4 +61,5 @@
 #define PLL_RESET               (1<<8)
 #define UTMI_PHY_EN             (1<<9)
 #define ULPI_PHY_CLK_SEL        (1<<10)
+#define PHY_CLK_VALID		(1<<17)
 #endif				/* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index 22ca45c..3180cb3 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -127,12 +127,6 @@
 	hcd->rsrc_start = res.start;
 	hcd->rsrc_len = resource_size(&res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-		rv = -EBUSY;
-		goto err_rmr;
-	}
-
 	irq = irq_of_parse_and_map(dn, 0);
 	if (irq == NO_IRQ) {
 		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -140,9 +134,9 @@
 		goto err_irq;
 	}
 
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&op->dev, &res);
 	if (!hcd->regs) {
-		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+		pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
 		goto err_ioremap;
 	}
@@ -161,17 +155,13 @@
 
 	rv = usb_add_hcd(hcd, irq, 0);
 	if (rv)
-		goto err_ehci;
+		goto err_ioremap;
 
 	return 0;
 
-err_ehci:
-	iounmap(hcd->regs);
 err_ioremap:
 	irq_dispose_mapping(irq);
 err_irq:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
 	usb_put_hcd(hcd);
 
 	return rv;
@@ -188,9 +178,7 @@
 
 	usb_remove_hcd(hcd);
 
-	iounmap(hcd->regs);
 	irq_dispose_mapping(hcd->irq);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index b05c686..6bf6c42 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -228,7 +228,7 @@
 
 	/* If the EHCI debug controller is active, special care must be
 	 * taken before and after a host controller reset */
-	if (ehci->debug && !dbgp_reset_prep())
+	if (ehci->debug && !dbgp_reset_prep(ehci_to_hcd(ehci)))
 		ehci->debug = NULL;
 
 	command |= CMD_RESET;
@@ -251,7 +251,7 @@
 		tdi_reset (ehci);
 
 	if (ehci->debug)
-		dbgp_external_startup();
+		dbgp_external_startup(ehci_to_hcd(ehci));
 
 	ehci->port_c_suspend = ehci->suspended_ports =
 			ehci->resuming_ports = 0;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index c788022..914ce93 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -353,10 +353,10 @@
 		goto shutdown;
 
 	if (unlikely(ehci->debug)) {
-		if (!dbgp_reset_prep())
+		if (!dbgp_reset_prep(hcd))
 			ehci->debug = NULL;
 		else
-			dbgp_external_startup();
+			dbgp_external_startup(hcd);
 	}
 
 	/* Ideally and we've got a real resume here, and no port's power
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index 488d401..f224c0a 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -98,30 +98,19 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-				driver->description)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		retval = -EBUSY;
-		goto fail_request_resource;
-	}
-
-	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (hcd->regs == NULL) {
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		retval = -EFAULT;
-		goto fail_ioremap;
+		goto fail_request_resource;
 	}
 
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval)
-		goto fail_add_hcd;
+		goto fail_request_resource;
 
 	return retval;
 
-fail_add_hcd:
-	iounmap(hcd->regs);
-fail_ioremap:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
 	usb_put_hcd(hcd);
 fail_create_hcd:
@@ -134,8 +123,6 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c
index a283e59..ca75965 100644
--- a/drivers/usb/host/ehci-ls1x.c
+++ b/drivers/usb/host/ehci-ls1x.c
@@ -106,29 +106,19 @@
 	hcd->rsrc_start	= res->start;
 	hcd->rsrc_len	= resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		ret = -EBUSY;
-		goto err_put_hcd;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (hcd->regs == NULL) {
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		ret = -EFAULT;
-		goto err_release_region;
+		goto err_put_hcd;
 	}
 
-	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret)
-		goto err_iounmap;
+		goto err_put_hcd;
 
 	return ret;
 
-err_iounmap:
-	iounmap(hcd->regs);
-err_release_region:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
 	usb_put_hcd(hcd);
 	return ret;
@@ -139,8 +129,6 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 17dd9e9..4af4dc5 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -133,7 +133,7 @@
 
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		ret = -ENOMEM;
@@ -145,17 +145,17 @@
 	 * powering up VBUS, mapping of registers address space and power
 	 * management.
 	 */
-	phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
 	if (IS_ERR_OR_NULL(phy)) {
 		dev_err(&pdev->dev, "unable to find transceiver\n");
 		ret = -ENODEV;
-		goto unmap;
+		goto put_hcd;
 	}
 
 	ret = otg_set_host(phy->otg, &hcd->self);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "unable to register with transceiver\n");
-		goto put_transceiver;
+		goto put_hcd;
 	}
 
 	device_init_wakeup(&pdev->dev, 1);
@@ -168,10 +168,6 @@
 
 	return 0;
 
-put_transceiver:
-	usb_put_phy(phy);
-unmap:
-	iounmap(hcd->regs);
 put_hcd:
 	usb_put_hcd(hcd);
 
@@ -187,7 +183,6 @@
 	pm_runtime_set_suspended(&pdev->dev);
 
 	otg_set_host(phy->otg, NULL);
-	usb_put_phy(phy);
 
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index f6df1cc..f7bfc0b 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -161,7 +161,7 @@
 		return -ENOMEM;
 
 	size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
-	ehci_mv = kzalloc(size, GFP_KERNEL);
+	ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (ehci_mv == NULL) {
 		dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
 		retval = -ENOMEM;
@@ -175,12 +175,12 @@
 	ehci_mv->clknum = pdata->clknum;
 	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
 		ehci_mv->clk[clk_i] =
-		    clk_get(&pdev->dev, pdata->clkname[clk_i]);
+		    devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
 		if (IS_ERR(ehci_mv->clk[clk_i])) {
 			dev_err(&pdev->dev, "error get clck \"%s\"\n",
 				pdata->clkname[clk_i]);
 			retval = PTR_ERR(ehci_mv->clk[clk_i]);
-			goto err_put_clk;
+			goto err_clear_drvdata;
 		}
 	}
 
@@ -188,34 +188,36 @@
 	if (r == NULL) {
 		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
 		retval = -ENODEV;
-		goto err_put_clk;
+		goto err_clear_drvdata;
 	}
 
-	ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
+	ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start,
+					 resource_size(r));
 	if (ehci_mv->phy_regs == 0) {
 		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
 		retval = -EFAULT;
-		goto err_put_clk;
+		goto err_clear_drvdata;
 	}
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
 	if (!r) {
 		dev_err(&pdev->dev, "no I/O memory resource defined\n");
 		retval = -ENODEV;
-		goto err_iounmap_phyreg;
+		goto err_clear_drvdata;
 	}
 
-	ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
+	ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start,
+					 resource_size(r));
 	if (ehci_mv->cap_regs == NULL) {
 		dev_err(&pdev->dev, "failed to map I/O memory\n");
 		retval = -EFAULT;
-		goto err_iounmap_phyreg;
+		goto err_clear_drvdata;
 	}
 
 	retval = mv_ehci_enable(ehci_mv);
 	if (retval) {
 		dev_err(&pdev->dev, "init phy error %d\n", retval);
-		goto err_iounmap_capreg;
+		goto err_clear_drvdata;
 	}
 
 	offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
@@ -239,7 +241,7 @@
 	ehci_mv->mode = pdata->mode;
 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
-		ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+		ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
 		if (IS_ERR_OR_NULL(ehci_mv->otg)) {
 			dev_err(&pdev->dev,
 				"unable to find transceiver\n");
@@ -252,7 +254,7 @@
 			dev_err(&pdev->dev,
 				"unable to register with transceiver\n");
 			retval = -ENODEV;
-			goto err_put_transceiver;
+			goto err_disable_clk;
 		}
 		/* otg will enable clock before use as host */
 		mv_ehci_disable(ehci_mv);
@@ -286,22 +288,10 @@
 err_set_vbus:
 	if (pdata->set_vbus)
 		pdata->set_vbus(0);
-#ifdef CONFIG_USB_OTG_UTILS
-err_put_transceiver:
-	if (!IS_ERR_OR_NULL(ehci_mv->otg))
-		usb_put_phy(ehci_mv->otg);
-#endif
 err_disable_clk:
 	mv_ehci_disable(ehci_mv);
-err_iounmap_capreg:
-	iounmap(ehci_mv->cap_regs);
-err_iounmap_phyreg:
-	iounmap(ehci_mv->phy_regs);
-err_put_clk:
-	for (clk_i--; clk_i >= 0; clk_i--)
-		clk_put(ehci_mv->clk[clk_i]);
+err_clear_drvdata:
 	platform_set_drvdata(pdev, NULL);
-	kfree(ehci_mv);
 err_put_hcd:
 	usb_put_hcd(hcd);
 
@@ -317,10 +307,8 @@
 	if (hcd->rh_registered)
 		usb_remove_hcd(hcd);
 
-	if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
+	if (!IS_ERR_OR_NULL(ehci_mv->otg))
 		otg_set_host(ehci_mv->otg->otg, NULL);
-		usb_put_phy(ehci_mv->otg);
-	}
 
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
 		if (ehci_mv->pdata->set_vbus)
@@ -329,15 +317,8 @@
 		mv_ehci_disable(ehci_mv);
 	}
 
-	iounmap(ehci_mv->cap_regs);
-	iounmap(ehci_mv->phy_regs);
-
-	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
-		clk_put(ehci_mv->clk[clk_i]);
-
 	platform_set_drvdata(pdev, NULL);
 
-	kfree(ehci_mv);
 	usb_put_hcd(hcd);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 3420137..959e1a4 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -121,7 +121,7 @@
 	if (!hcd)
 		return -ENOMEM;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		ret = -ENOMEM;
 		goto err_alloc;
@@ -131,34 +131,28 @@
 	if (!res) {
 		dev_err(dev, "Found HC with no register addr. Check setup!\n");
 		ret = -ENODEV;
-		goto err_get_resource;
+		goto err_alloc;
 	}
 
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dev_dbg(dev, "controller already in use\n");
-		ret = -EBUSY;
-		goto err_request_mem;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hcd->regs) {
 		dev_err(dev, "error mapping memory\n");
 		ret = -EFAULT;
-		goto err_ioremap;
+		goto err_alloc;
 	}
 
 	/* enable clocks */
-	priv->usbclk = clk_get(dev, "ipg");
+	priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(priv->usbclk)) {
 		ret = PTR_ERR(priv->usbclk);
-		goto err_clk;
+		goto err_alloc;
 	}
 	clk_prepare_enable(priv->usbclk);
 
-	priv->ahbclk = clk_get(dev, "ahb");
+	priv->ahbclk = devm_clk_get(&pdev->dev, "ahb");
 	if (IS_ERR(priv->ahbclk)) {
 		ret = PTR_ERR(priv->ahbclk);
 		goto err_clk_ahb;
@@ -166,7 +160,7 @@
 	clk_prepare_enable(priv->ahbclk);
 
 	/* "dr" device has its own clock on i.MX51 */
-	priv->phyclk = clk_get(dev, "phy");
+	priv->phyclk = devm_clk_get(&pdev->dev, "phy");
 	if (IS_ERR(priv->phyclk))
 		priv->phyclk = NULL;
 	if (priv->phyclk)
@@ -245,23 +239,12 @@
 	if (pdata && pdata->exit)
 		pdata->exit(pdev);
 err_init:
-	if (priv->phyclk) {
+	if (priv->phyclk)
 		clk_disable_unprepare(priv->phyclk);
-		clk_put(priv->phyclk);
-	}
 
 	clk_disable_unprepare(priv->ahbclk);
-	clk_put(priv->ahbclk);
 err_clk_ahb:
 	clk_disable_unprepare(priv->usbclk);
-	clk_put(priv->usbclk);
-err_clk:
-	iounmap(hcd->regs);
-err_ioremap:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_request_mem:
-err_get_resource:
-	kfree(priv);
 err_alloc:
 	usb_put_hcd(hcd);
 	return ret;
@@ -280,22 +263,14 @@
 		usb_phy_shutdown(pdata->otg);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	platform_set_drvdata(pdev, NULL);
 
 	clk_disable_unprepare(priv->usbclk);
-	clk_put(priv->usbclk);
 	clk_disable_unprepare(priv->ahbclk);
-	clk_put(priv->ahbclk);
 
-	if (priv->phyclk) {
+	if (priv->phyclk)
 		clk_disable_unprepare(priv->phyclk);
-		clk_put(priv->phyclk);
-	}
-
-	kfree(priv);
 
 	return 0;
 }
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 4b1d896..764e010 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -82,10 +82,14 @@
 {
 	struct usb_hcd *hcd;
 	struct resource *res_mem;
+	struct usb_ehci_pdata *pdata = dev->dev.platform_data;
 	int irq;
 	int err = -ENOMEM;
 
-	BUG_ON(!dev->dev.platform_data);
+	if (!pdata) {
+		WARN_ON(1);
+		return -ENODEV;
+	}
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -101,10 +105,18 @@
 		return -ENXIO;
 	}
 
+	if (pdata->power_on) {
+		err = pdata->power_on(dev);
+		if (err < 0)
+			return err;
+	}
+
 	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
 			     dev_name(&dev->dev));
-	if (!hcd)
-		return -ENOMEM;
+	if (!hcd) {
+		err = -ENOMEM;
+		goto err_power;
+	}
 
 	hcd->rsrc_start = res_mem->start;
 	hcd->rsrc_len = resource_size(res_mem);
@@ -116,8 +128,10 @@
 	}
 
 	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs)
+	if (!hcd->regs) {
+		err = -ENOMEM;
 		goto err_release_region;
+	}
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err)
 		goto err_iounmap;
@@ -132,12 +146,17 @@
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
 	usb_put_hcd(hcd);
+err_power:
+	if (pdata->power_off)
+		pdata->power_off(dev);
+
 	return err;
 }
 
 static int __devexit ehci_platform_remove(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct usb_ehci_pdata *pdata = dev->dev.platform_data;
 
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
@@ -145,6 +164,9 @@
 	usb_put_hcd(hcd);
 	platform_set_drvdata(dev, NULL);
 
+	if (pdata->power_off)
+		pdata->power_off(dev);
+
 	return 0;
 }
 
@@ -153,14 +175,32 @@
 static int ehci_platform_suspend(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_ehci_pdata *pdata = dev->platform_data;
+	struct platform_device *pdev =
+		container_of(dev, struct platform_device, dev);
 	bool do_wakeup = device_may_wakeup(dev);
+	int ret;
 
-	return ehci_suspend(hcd, do_wakeup);
+	ret = ehci_suspend(hcd, do_wakeup);
+
+	if (pdata->power_suspend)
+		pdata->power_suspend(pdev);
+
+	return ret;
 }
 
 static int ehci_platform_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_ehci_pdata *pdata = dev->platform_data;
+	struct platform_device *pdev =
+		container_of(dev, struct platform_device, dev);
+
+	if (pdata->power_on) {
+		int err = pdata->power_on(pdev);
+		if (err < 0)
+			return err;
+	}
 
 	ehci_resume(hcd, false);
 	return 0;
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index bbbe89d..fa937d0 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -114,12 +114,6 @@
 	hcd->rsrc_start = res.start;
 	hcd->rsrc_len = resource_size(&res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-		rv = -EBUSY;
-		goto err_rmr;
-	}
-
 	irq = irq_of_parse_and_map(dn, 0);
 	if (irq == NO_IRQ) {
 		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -127,9 +121,9 @@
 		goto err_irq;
 	}
 
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&op->dev, &res);
 	if (!hcd->regs) {
-		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+		pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
 		goto err_ioremap;
 	}
@@ -139,8 +133,10 @@
 	if (np != NULL) {
 		/* claim we really affected by usb23 erratum */
 		if (!of_address_to_resource(np, 0, &res))
-			ehci->ohci_hcctrl_reg = ioremap(res.start +
-					OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
+			ehci->ohci_hcctrl_reg =
+				devm_ioremap(&op->dev,
+					     res.start + OHCI_HCCTRL_OFFSET,
+					     OHCI_HCCTRL_LEN);
 		else
 			pr_debug("%s: no ohci offset in fdt\n", __FILE__);
 		if (!ehci->ohci_hcctrl_reg) {
@@ -169,19 +165,13 @@
 
 	rv = usb_add_hcd(hcd, irq, 0);
 	if (rv)
-		goto err_ehci;
+		goto err_ioremap;
 
 	return 0;
 
-err_ehci:
-	if (ehci->has_amcc_usb23)
-		iounmap(ehci->ohci_hcctrl_reg);
-	iounmap(hcd->regs);
 err_ioremap:
 	irq_dispose_mapping(irq);
 err_irq:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
 	usb_put_hcd(hcd);
 
 	return rv;
@@ -202,9 +192,7 @@
 
 	usb_remove_hcd(hcd);
 
-	iounmap(hcd->regs);
 	irq_dispose_mapping(hcd->irq);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
 	/* use request_mem_region to test if the ohci driver is loaded.  if so
 	 * ensure the ohci core is operational.
@@ -222,8 +210,6 @@
 				pr_debug("%s: no ohci offset in fdt\n", __FILE__);
 			of_node_put(np);
 		}
-
-		iounmap(ehci->ohci_hcctrl_reg);
 	}
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 9d8f1dd..d055503 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -128,7 +128,7 @@
 	}
 
 	s5p_ehci->hcd = hcd;
-	s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
+	s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
 
 	if (IS_ERR(s5p_ehci->clk)) {
 		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
@@ -138,7 +138,7 @@
 
 	err = clk_enable(s5p_ehci->clk);
 	if (err)
-		goto fail_clken;
+		goto fail_clk;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -184,8 +184,6 @@
 
 fail_io:
 	clk_disable(s5p_ehci->clk);
-fail_clken:
-	clk_put(s5p_ehci->clk);
 fail_clk:
 	usb_put_hcd(hcd);
 	return err;
@@ -203,7 +201,6 @@
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 
 	clk_disable(s5p_ehci->clk);
-	clk_put(s5p_ehci->clk);
 
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index 0c9e43c..efad02d 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -112,17 +112,11 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug("request_mem_region failed");
-		ret = -EBUSY;
-		goto err1;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hcd->regs) {
 		pr_debug("ioremap failed");
 		ret = -ENOMEM;
-		goto err2;
+		goto err1;
 	}
 
 	/* Root hub has integrated TT. */
@@ -135,9 +129,6 @@
 		return ret;
 	}
 
-	iounmap(hcd->regs);
-err2:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
 	usb_put_hcd(hcd);
 	return ret;
@@ -148,8 +139,6 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	platform_set_drvdata(pdev, NULL);
 
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index b3f1e36..6081e1e 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -125,33 +125,27 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-				driver->description)) {
-		dev_dbg(&pdev->dev, "controller already in use\n");
-		ret = -EBUSY;
-		goto fail_request_resource;
-	}
-
-	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (hcd->regs == NULL) {
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		ret = -ENXIO;
-		goto fail_ioremap;
+		goto fail_request_resource;
 	}
 
-	priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv),
+			    GFP_KERNEL);
 	if (!priv) {
 		dev_dbg(&pdev->dev, "error allocating priv data\n");
 		ret = -ENOMEM;
-		goto fail_alloc;
+		goto fail_request_resource;
 	}
 
 	/* These are optional, we don't care if they fail */
-	priv->fclk = clk_get(&pdev->dev, "usb_fck");
+	priv->fclk = devm_clk_get(&pdev->dev, "usb_fck");
 	if (IS_ERR(priv->fclk))
 		priv->fclk = NULL;
 
-	priv->iclk = clk_get(&pdev->dev, "usb_ick");
+	priv->iclk = devm_clk_get(&pdev->dev, "usb_ick");
 	if (IS_ERR(priv->iclk))
 		priv->iclk = NULL;
 
@@ -176,14 +170,6 @@
 	clk_disable(priv->iclk);
 	clk_disable(priv->fclk);
 
-	clk_put(priv->iclk);
-	clk_put(priv->fclk);
-
-	kfree(priv);
-fail_alloc:
-	iounmap(hcd->regs);
-fail_ioremap:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
 	usb_put_hcd(hcd);
 fail_create_hcd:
@@ -198,19 +184,12 @@
 	struct usb_hcd *hcd = priv->hcd;
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	platform_set_drvdata(pdev, NULL);
 
 	clk_disable(priv->fclk);
 	clk_disable(priv->iclk);
 
-	clk_put(priv->fclk);
-	clk_put(priv->iclk);
-
-	kfree(priv);
-
 	return 0;
 }
 
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 26dedb3..6223d175 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -27,7 +27,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 #include <mach/iomap.h>
 
 #define TEGRA_USB_DMA_ALIGN 32
@@ -49,7 +49,7 @@
 
 	clk_prepare_enable(tegra->emc_clk);
 	clk_prepare_enable(tegra->clk);
-	tegra_usb_phy_power_on(tegra->phy);
+	usb_phy_set_suspend(&tegra->phy->u_phy, 0);
 	tegra->host_resumed = 1;
 }
 
@@ -58,7 +58,7 @@
 	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
 
 	tegra->host_resumed = 0;
-	tegra_usb_phy_power_off(tegra->phy);
+	usb_phy_set_suspend(&tegra->phy->u_phy, 1);
 	clk_disable_unprepare(tegra->clk);
 	clk_disable_unprepare(tegra->emc_clk);
 }
@@ -634,7 +634,8 @@
 
 	setup_vbus_gpio(pdev, pdata);
 
-	tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
+	tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
+			     GFP_KERNEL);
 	if (!tegra)
 		return -ENOMEM;
 
@@ -642,13 +643,12 @@
 					dev_name(&pdev->dev));
 	if (!hcd) {
 		dev_err(&pdev->dev, "Unable to create HCD\n");
-		err = -ENOMEM;
-		goto fail_hcd;
+		return -ENOMEM;
 	}
 
 	platform_set_drvdata(pdev, tegra);
 
-	tegra->clk = clk_get(&pdev->dev, NULL);
+	tegra->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(tegra->clk)) {
 		dev_err(&pdev->dev, "Can't get ehci clock\n");
 		err = PTR_ERR(tegra->clk);
@@ -657,9 +657,9 @@
 
 	err = clk_prepare_enable(tegra->clk);
 	if (err)
-		goto fail_clken;
+		goto fail_clk;
 
-	tegra->emc_clk = clk_get(&pdev->dev, "emc");
+	tegra->emc_clk = devm_clk_get(&pdev->dev, "emc");
 	if (IS_ERR(tegra->emc_clk)) {
 		dev_err(&pdev->dev, "Can't get emc clock\n");
 		err = PTR_ERR(tegra->emc_clk);
@@ -677,7 +677,7 @@
 	}
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
-	hcd->regs = ioremap(res->start, resource_size(res));
+	hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 	if (!hcd->regs) {
 		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
 		err = -ENOMEM;
@@ -702,7 +702,7 @@
 		default:
 			err = -ENODEV;
 			dev_err(&pdev->dev, "unknown usb instance\n");
-			goto fail_phy;
+			goto fail_io;
 		}
 	}
 
@@ -712,10 +712,12 @@
 	if (IS_ERR(tegra->phy)) {
 		dev_err(&pdev->dev, "Failed to open USB phy\n");
 		err = -ENXIO;
-		goto fail_phy;
+		goto fail_io;
 	}
 
-	err = tegra_usb_phy_power_on(tegra->phy);
+	usb_phy_init(&tegra->phy->u_phy);
+
+	err = usb_phy_set_suspend(&tegra->phy->u_phy, 0);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to power on the phy\n");
 		goto fail;
@@ -733,7 +735,8 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->operating_mode == TEGRA_USB_OTG) {
-		tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		tegra->transceiver =
+			devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
 		if (!IS_ERR_OR_NULL(tegra->transceiver))
 			otg_set_host(tegra->transceiver->otg, &hcd->self);
 	}
@@ -757,25 +760,16 @@
 
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
-	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver))
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_phy(tegra->transceiver);
-	}
 #endif
-	tegra_usb_phy_close(tegra->phy);
-fail_phy:
-	iounmap(hcd->regs);
+	usb_phy_shutdown(&tegra->phy->u_phy);
 fail_io:
 	clk_disable_unprepare(tegra->emc_clk);
-	clk_put(tegra->emc_clk);
 fail_emc_clk:
 	clk_disable_unprepare(tegra->clk);
-fail_clken:
-	clk_put(tegra->clk);
 fail_clk:
 	usb_put_hcd(hcd);
-fail_hcd:
-	kfree(tegra);
 	return err;
 }
 
@@ -792,26 +786,19 @@
 	pm_runtime_put_noidle(&pdev->dev);
 
 #ifdef CONFIG_USB_OTG_UTILS
-	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver))
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_phy(tegra->transceiver);
-	}
 #endif
 
 	usb_remove_hcd(hcd);
-
-	tegra_usb_phy_close(tegra->phy);
-	iounmap(hcd->regs);
-
 	usb_put_hcd(hcd);
 
+	usb_phy_shutdown(&tegra->phy->u_phy);
+
 	clk_disable_unprepare(tegra->clk);
-	clk_put(tegra->clk);
 
 	clk_disable_unprepare(tegra->emc_clk);
-	clk_put(tegra->emc_clk);
 
-	kfree(tegra);
 	return 0;
 }
 
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index eb896a2..20dbdcb 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -118,7 +118,8 @@
 			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
 			return;
 		}
-		ehci_warn(ehci, "Waited too long for the async schedule status, giving up\n");
+		ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
+				want, actual);
 	}
 	ehci->ASS_poll_count = 0;
 
@@ -163,7 +164,8 @@
 			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
 			return;
 		}
-		ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n");
+		ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
+				want, actual);
 	}
 	ehci->PSS_poll_count = 0;
 
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
index 4d147c4..96722bf 100644
--- a/drivers/usb/host/ehci-vt8500.c
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -16,6 +16,7 @@
  *
  */
 
+#include <linux/of.h>
 #include <linux/platform_device.h>
 
 static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
@@ -106,17 +107,11 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug("request_mem_region failed");
-		ret = -EBUSY;
-		goto err1;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hcd->regs) {
 		pr_debug("ioremap failed");
 		ret = -ENOMEM;
-		goto err2;
+		goto err1;
 	}
 
 	ehci = hcd_to_ehci(hcd);
@@ -129,9 +124,6 @@
 		return ret;
 	}
 
-	iounmap(hcd->regs);
-err2:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
 	usb_put_hcd(hcd);
 	return ret;
@@ -142,14 +134,18 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
 
+static const struct of_device_id vt8500_ehci_ids[] = {
+	{ .compatible = "via,vt8500-ehci", },
+	{ .compatible = "wm,prizm-ehci", },
+	{}
+};
+
 static struct platform_driver vt8500_ehci_driver = {
 	.probe		= vt8500_ehci_drv_probe,
 	.remove		= vt8500_ehci_drv_remove,
@@ -157,7 +153,9 @@
 	.driver = {
 		.name	= "vt8500-ehci",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(vt8500_ehci_ids),
 	}
 };
 
 MODULE_ALIAS("platform:vt8500-ehci");
+MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 39f24fa..6a3f921a 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -152,12 +152,6 @@
 	hcd->rsrc_start = res.start;
 	hcd->rsrc_len = resource_size(&res);
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-		rv = -EBUSY;
-		goto err_rmr;
-	}
-
 	irq = irq_of_parse_and_map(dn, 0);
 	if (!irq) {
 		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -165,11 +159,11 @@
 		goto err_irq;
 	}
 
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	hcd->regs = devm_request_and_ioremap(&op->dev, &res);
 	if (!hcd->regs) {
-		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+		pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
-		goto err_ioremap;
+		goto err_irq;
 	}
 
 	ehci = hcd_to_ehci(hcd);
@@ -200,12 +194,7 @@
 	if (rv == 0)
 		return 0;
 
-	iounmap(hcd->regs);
-
-err_ioremap:
 err_irq:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
 	usb_put_hcd(hcd);
 
 	return rv;
@@ -227,9 +216,6 @@
 
 	usb_remove_hcd(hcd);
 
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
 	usb_put_hcd(hcd);
 
 	return 0;
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 2dc8a40..8f18538 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -261,8 +261,7 @@
 	struct list_head *node = list->next;
 
 	if (!list_empty(list)) {
-		list_del(node);
-		list_add_tail(node, list);
+		list_move_tail(node, list);
 	}
 }
 
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 22ff6b3a..1e77129 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -133,6 +133,8 @@
 			ver = FSL_USB_VER_1_6;
 		else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
 			ver = FSL_USB_VER_2_2;
+		else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4"))
+			ver = FSL_USB_VER_2_4;
 		else /* for previous controller versions */
 			ver = FSL_USB_VER_OLD;
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index aaa8d2b..0bf72f9 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -467,7 +467,8 @@
 	/* From the GPIO notifying the over-current situation, find
 	 * out the corresponding port */
 	at91_for_each_port(port) {
-		if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
+		if (gpio_is_valid(pdata->overcurrent_pin[port]) &&
+				gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
 			gpio = pdata->overcurrent_pin[port];
 			break;
 		}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 2b1e8d8..6780010 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1049,7 +1049,7 @@
 #define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 
-#if defined(CONFIG_ARCH_PNX4008) || defined(CONFIG_ARCH_LPC32XX)
+#ifdef CONFIG_ARCH_LPC32XX
 #include "ohci-nxp.c"
 #define PLATFORM_DRIVER		usb_hcd_nxp_driver
 #endif
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index a446386..e068f03 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -2,7 +2,6 @@
  * driver for NXP USB Host devices
  *
  * Currently supported OHCI host devices:
- * - Philips PNX4008
  * - NXP LPC32xx
  *
  * Authors: Dmitry Chigirev <source@mvista.com>
@@ -66,38 +65,6 @@
 static struct clk *usb_dev_clk;
 static struct clk *usb_otg_clk;
 
-static void isp1301_configure_pnx4008(void)
-{
-	/* PNX4008 only supports DAT_SE0 USB mode */
-	/* PNX4008 R2A requires setting the MAX603 to output 3.6V */
-	/* Power up externel charge-pump */
-
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0 | MC1_SPEED_REG);
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
-		~(MC1_DAT_SE0 | MC1_SPEED_REG));
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_MODE_CONTROL_2,
-		MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL);
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
-		~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_OTG_CONTROL_1, OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
-		~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, 0xFF);
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
-		0xFF);
-	i2c_smbus_write_byte_data(isp1301_i2c_client,
-		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR,
-		0xFF);
-}
-
 static void isp1301_configure_lpc32xx(void)
 {
 	/* LPC32XX only supports DAT_SE0 USB mode */
@@ -149,10 +116,7 @@
 
 static void isp1301_configure(void)
 {
-	if (machine_is_pnx4008())
-		isp1301_configure_pnx4008();
-	else
-		isp1301_configure_lpc32xx();
+	isp1301_configure_lpc32xx();
 }
 
 static inline void isp1301_vbus_on(void)
@@ -241,47 +205,6 @@
 	.start_port_reset = ohci_start_port_reset,
 };
 
-static void nxp_set_usb_bits(void)
-{
-	if (machine_is_pnx4008()) {
-		start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
-		start_int_ack(SE_USB_OTG_ATX_INT_N);
-		start_int_umask(SE_USB_OTG_ATX_INT_N);
-
-		start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
-		start_int_ack(SE_USB_OTG_TIMER_INT);
-		start_int_umask(SE_USB_OTG_TIMER_INT);
-
-		start_int_set_rising_edge(SE_USB_I2C_INT);
-		start_int_ack(SE_USB_I2C_INT);
-		start_int_umask(SE_USB_I2C_INT);
-
-		start_int_set_rising_edge(SE_USB_INT);
-		start_int_ack(SE_USB_INT);
-		start_int_umask(SE_USB_INT);
-
-		start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
-		start_int_ack(SE_USB_NEED_CLK_INT);
-		start_int_umask(SE_USB_NEED_CLK_INT);
-
-		start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
-		start_int_ack(SE_USB_AHB_NEED_CLK_INT);
-		start_int_umask(SE_USB_AHB_NEED_CLK_INT);
-	}
-}
-
-static void nxp_unset_usb_bits(void)
-{
-	if (machine_is_pnx4008()) {
-		start_int_mask(SE_USB_OTG_ATX_INT_N);
-		start_int_mask(SE_USB_OTG_TIMER_INT);
-		start_int_mask(SE_USB_I2C_INT);
-		start_int_mask(SE_USB_INT);
-		start_int_mask(SE_USB_NEED_CLK_INT);
-		start_int_mask(SE_USB_AHB_NEED_CLK_INT);
-	}
-}
-
 static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = 0;
@@ -355,7 +278,7 @@
 	usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
 	if (IS_ERR(usb_otg_clk)) {
 		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
-		ret = PTR_ERR(usb_dev_clk);
+		ret = PTR_ERR(usb_otg_clk);
 		goto out6;
 	}
 
@@ -376,9 +299,6 @@
 		goto out8;
 	}
 
-	/* Set all USB bits in the Start Enable register */
-	nxp_set_usb_bits();
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "Failed to get MEM resource\n");
@@ -413,7 +333,6 @@
 
 	nxp_stop_hc();
 out8:
-	nxp_unset_usb_bits();
 	usb_put_hcd(hcd);
 out7:
 	clk_disable(usb_otg_clk);
@@ -441,7 +360,6 @@
 	nxp_stop_hc();
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
-	nxp_unset_usb_bits();
 	clk_disable(usb_pll_clk);
 	clk_put(usb_pll_clk);
 	clk_disable(usb_dev_clk);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index f8b2d91..4531d03 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -24,7 +24,7 @@
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include <plat/fpga.h>
 
 #include <mach/hardware.h>
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 670c705..e24ec9f 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -83,10 +83,14 @@
 {
 	struct usb_hcd *hcd;
 	struct resource *res_mem;
+	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
 	int irq;
 	int err = -ENOMEM;
 
-	BUG_ON(!dev->dev.platform_data);
+	if (!pdata) {
+		WARN_ON(1);
+		return -ENODEV;
+	}
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -103,10 +107,18 @@
 		return -ENXIO;
 	}
 
+	if (pdata->power_on) {
+		err = pdata->power_on(dev);
+		if (err < 0)
+			return err;
+	}
+
 	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
 			dev_name(&dev->dev));
-	if (!hcd)
-		return -ENOMEM;
+	if (!hcd) {
+		err = -ENOMEM;
+		goto err_power;
+	}
 
 	hcd->rsrc_start = res_mem->start;
 	hcd->rsrc_len = resource_size(res_mem);
@@ -118,8 +130,10 @@
 	}
 
 	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs)
+	if (!hcd->regs) {
+		err = -ENOMEM;
 		goto err_release_region;
+	}
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err)
 		goto err_iounmap;
@@ -134,12 +148,17 @@
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
 	usb_put_hcd(hcd);
+err_power:
+	if (pdata->power_off)
+		pdata->power_off(dev);
+
 	return err;
 }
 
 static int __devexit ohci_platform_remove(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
 
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
@@ -147,6 +166,9 @@
 	usb_put_hcd(hcd);
 	platform_set_drvdata(dev, NULL);
 
+	if (pdata->power_off)
+		pdata->power_off(dev);
+
 	return 0;
 }
 
@@ -154,12 +176,28 @@
 
 static int ohci_platform_suspend(struct device *dev)
 {
+	struct usb_ohci_pdata *pdata = dev->platform_data;
+	struct platform_device *pdev =
+		container_of(dev, struct platform_device, dev);
+
+	if (pdata->power_suspend)
+		pdata->power_suspend(pdev);
+
 	return 0;
 }
 
 static int ohci_platform_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_ohci_pdata *pdata = dev->platform_data;
+	struct platform_device *pdev =
+		container_of(dev, struct platform_device, dev);
+
+	if (pdata->power_on) {
+		int err = pdata->power_on(pdev);
+		if (err < 0)
+			return err;
+	}
 
 	ohci_finish_controller_resume(hcd);
 	return 0;
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e1a3cc6..77f4402 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -23,6 +23,8 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 #include <mach/hardware.h>
 #include <mach/ohci.h>
 #include <mach/pxa3xx-u2d.h>
@@ -272,6 +274,67 @@
 	clk_disable_unprepare(ohci->clk);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ohci_dt_ids[] = {
+	{ .compatible = "marvell,pxa-ohci" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids);
+
+static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pxaohci_platform_data *pdata;
+	u32 tmp;
+
+	if (!np)
+		return 0;
+
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &pxa_ohci_dma_mask;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (of_get_property(np, "marvell,enable-port1", NULL))
+		pdata->flags |= ENABLE_PORT1;
+	if (of_get_property(np, "marvell,enable-port2", NULL))
+		pdata->flags |= ENABLE_PORT2;
+	if (of_get_property(np, "marvell,enable-port3", NULL))
+		pdata->flags |= ENABLE_PORT3;
+	if (of_get_property(np, "marvell,port-sense-low", NULL))
+		pdata->flags |= POWER_SENSE_LOW;
+	if (of_get_property(np, "marvell,power-control-low", NULL))
+		pdata->flags |= POWER_CONTROL_LOW;
+	if (of_get_property(np, "marvell,no-oc-protection", NULL))
+		pdata->flags |= NO_OC_PROTECTION;
+	if (of_get_property(np, "marvell,oc-mode-perport", NULL))
+		pdata->flags |= OC_MODE_PERPORT;
+	if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp))
+		pdata->power_on_delay = tmp;
+	if (!of_property_read_u32(np, "marvell,port-mode", &tmp))
+		pdata->port_mode = tmp;
+	if (!of_property_read_u32(np, "marvell,power-budget", &tmp))
+		pdata->power_budget = tmp;
+
+	pdev->dev.platform_data = pdata;
+
+	return 0;
+}
+#else
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -297,6 +360,10 @@
 	struct resource *r;
 	struct clk *usb_clk;
 
+	retval = ohci_pxa_of_init(pdev);
+	if (retval)
+		return retval;
+
 	inf = pdev->dev.platform_data;
 
 	if (!inf)
@@ -544,6 +611,7 @@
 	.driver		= {
 		.name	= "pxa27x-ohci",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(pxa_ohci_dt_ids),
 #ifdef CONFIG_PM
 		.pm	= &ohci_hcd_pxa27x_pm_ops,
 #endif
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index 41e378f..84201cd 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -56,7 +56,7 @@
 		goto err3;
 	}
 
-	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval != 0)
 		goto err4;
 	return retval;
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 4c634eb..fcc09e5 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2029,15 +2029,14 @@
 static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
 {
 	int chix;
+	struct usb_device *childdev;
 
 	if (udev->state == USB_STATE_CONFIGURED &&
 	    udev->parent && udev->parent->devnum > 1 &&
 	    udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
 		map[udev->devnum/32] |= (1 << (udev->devnum % 32));
 
-	for (chix = 0; chix < udev->maxchild; chix++) {
-		struct usb_device *childdev = udev->children[chix];
-
+	usb_hub_for_each_child(udev, chix, childdev) {
 		if (childdev)
 			collect_usb_address_map(childdev, map);
 	}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 91ce1c0..619b05f 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -156,7 +156,7 @@
 	writeb(SL_SETUP /* | ep->epnum */, data_reg);
 	writeb(usb_pipedevice(urb->pipe), data_reg);
 
-	/* always OUT/data0 */ ;
+	/* always OUT/data0 */
 	sl811_write(sl811, bank + SL11H_HOSTCTLREG,
 			control | SL11H_HCTLMASK_OUT);
 	ep->length = 0;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e4db350..4b9e9ab 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -846,6 +846,11 @@
 #define PLATFORM_DRIVER		uhci_grlib_driver
 #endif
 
+#ifdef CONFIG_USB_UHCI_PLATFORM
+#include "uhci-platform.c"
+#define PLATFORM_DRIVER		uhci_platform_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
 #error "missing bus glue for uhci-hcd"
 #endif
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
new file mode 100644
index 0000000..e478049
--- /dev/null
+++ b/drivers/usb/host/uhci-platform.c
@@ -0,0 +1,157 @@
+/*
+ * Generic UHCI HCD (Host Controller Driver) for Platform Devices
+ *
+ * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This file is based on uhci-grlib.c
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+static int uhci_platform_init(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	uhci->rh_numports = uhci_count_ports(hcd);
+
+	/* Set up pointers to to generic functions */
+	uhci->reset_hc = uhci_generic_reset_hc;
+	uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
+
+	/* No special actions need to be taken for the functions below */
+	uhci->configure_hc = NULL;
+	uhci->resume_detect_interrupts_are_broken = NULL;
+	uhci->global_suspend_mode_is_broken = NULL;
+
+	/* Reset if the controller isn't already safely quiescent. */
+	check_and_reset_hc(uhci);
+	return 0;
+}
+
+static const struct hc_driver uhci_platform_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"Generic UHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct uhci_hcd),
+
+	/* Generic hardware linkage */
+	.irq =			uhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB11,
+
+	/* Basic lifecycle operations */
+	.reset =		uhci_platform_init,
+	.start =		uhci_start,
+#ifdef CONFIG_PM
+	.pci_suspend =		NULL,
+	.pci_resume =		NULL,
+	.bus_suspend =		uhci_rh_suspend,
+	.bus_resume =		uhci_rh_resume,
+#endif
+	.stop =			uhci_stop,
+
+	.urb_enqueue =		uhci_urb_enqueue,
+	.urb_dequeue =		uhci_urb_dequeue,
+
+	.endpoint_disable =	uhci_hcd_endpoint_disable,
+	.get_frame_number =	uhci_hcd_get_frame_number,
+
+	.hub_status_data =	uhci_hub_status_data,
+	.hub_control =		uhci_hub_control,
+};
+
+
+static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct uhci_hcd	*uhci;
+	struct resource *res;
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
+			pdev->name);
+	if (!hcd)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_err("%s: request_mem_region failed\n", __func__);
+		ret = -EBUSY;
+		goto err_rmr;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_err("%s: ioremap failed\n", __func__);
+		ret = -ENOMEM;
+		goto err_irq;
+	}
+	uhci = hcd_to_uhci(hcd);
+
+	uhci->regs = hcd->regs;
+
+	ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED |
+								IRQF_SHARED);
+	if (ret)
+		goto err_uhci;
+
+	return 0;
+
+err_uhci:
+	iounmap(hcd->regs);
+err_irq:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+static int uhci_hcd_platform_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+/* Make sure the controller is quiescent and that we're not using it
+ * any more.  This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel.  Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_hcd_platform_shutdown(struct platform_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+	uhci_hc_died(hcd_to_uhci(hcd));
+}
+
+static const struct of_device_id platform_uhci_ids[] = {
+	{ .compatible = "platform-uhci", },
+	{}
+};
+
+static struct platform_driver uhci_platform_driver = {
+	.probe		= uhci_hcd_platform_probe,
+	.remove		= uhci_hcd_platform_remove,
+	.shutdown	= uhci_hcd_platform_shutdown,
+	.driver = {
+		.name = "platform-uhci",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(platform_uhci_ids),
+	},
+};
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
index 1e141f7..c3a6478 100644
--- a/drivers/usb/host/whci/hcd.c
+++ b/drivers/usb/host/whci/hcd.c
@@ -238,16 +238,16 @@
 
 static int whc_probe(struct umc_dev *umc)
 {
-	int ret = -ENOMEM;
+	int ret;
 	struct usb_hcd *usb_hcd;
-	struct wusbhc *wusbhc = NULL;
-	struct whc *whc = NULL;
+	struct wusbhc *wusbhc;
+	struct whc *whc;
 	struct device *dev = &umc->dev;
 
 	usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
 	if (usb_hcd == NULL) {
 		dev_err(dev, "unable to create hcd\n");
-		goto error;
+		return -ENOMEM;
 	}
 
 	usb_hcd->wireless = 1;
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 76083ae..dc31c42 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -436,7 +436,7 @@
 	int i;
 	int ntds = 0;
 	struct whc_std *std = NULL;
-	struct whc_page_list_entry *entry;
+	struct whc_page_list_entry *new_pl_virt;
 	dma_addr_t prev_end = 0;
 	size_t pl_len;
 	int p = 0;
@@ -508,12 +508,15 @@
 
 			pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
 
-			std->pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
-			if (std->pl_virt == NULL) {
+			new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
+			if (new_pl_virt == NULL) {
+				kfree(std->pl_virt);
+				std->pl_virt = NULL;
 				return -ENOMEM;
 			}
+			std->pl_virt = new_pl_virt;
 
-			for (;p < std->num_pointers; p++, entry++) {
+			for (;p < std->num_pointers; p++) {
 				std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
 				dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
 			}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index d5eb357..aa90ad4 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -29,7 +29,7 @@
 #define	PORT_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
 			 PORT_RC | PORT_PLC | PORT_PE)
 
-/* usb 1.1 root hub device descriptor */
+/* USB 3.0 BOS descriptor and a capability descriptor, combined */
 static u8 usb_bos_descriptor [] = {
 	USB_DT_BOS_SIZE,		/*  __u8 bLength, 5 bytes */
 	USB_DT_BOS,			/*  __u8 bDescriptorType */
@@ -422,7 +422,7 @@
 	xhci_writel(xhci, temp, port_array[port_id]);
 }
 
-void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
+static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
 		__le32 __iomem **port_array, int port_id, u16 wake_mask)
 {
 	u32 temp;
@@ -808,6 +808,12 @@
 
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);
+
+			temp = usb_acpi_power_manageable(hcd->self.root_hub,
+					wIndex);
+			if (temp)
+				usb_acpi_set_power_state(hcd->self.root_hub,
+						wIndex, true);
 			break;
 		case USB_PORT_FEAT_RESET:
 			temp = (temp | PORT_RESET);
@@ -907,6 +913,16 @@
 			xhci_disable_port(hcd, xhci, wIndex,
 					port_array[wIndex], temp);
 			break;
+		case USB_PORT_FEAT_POWER:
+			xhci_writel(xhci, temp & ~PORT_POWER,
+				port_array[wIndex]);
+
+			temp = usb_acpi_power_manageable(hcd->self.root_hub,
+					wIndex);
+			if (temp)
+				usb_acpi_set_power_state(hcd->self.root_hub,
+						wIndex, false);
+			break;
 		default:
 			goto error;
 		}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 77689bd..487bc08 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1772,6 +1772,7 @@
 {
 	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
 	struct dev_info	*dev_info, *next;
+	struct xhci_cd  *cur_cd, *next_cd;
 	unsigned long	flags;
 	int size;
 	int i, j, num_ports;
@@ -1795,6 +1796,11 @@
 		xhci_ring_free(xhci, xhci->cmd_ring);
 	xhci->cmd_ring = NULL;
 	xhci_dbg(xhci, "Freed command ring\n");
+	list_for_each_entry_safe(cur_cd, next_cd,
+			&xhci->cancel_cmd_list, cancel_cmd_list) {
+		list_del(&cur_cd->cancel_cmd_list);
+		kfree(cur_cd);
+	}
 
 	for (i = 1; i < MAX_HC_SLOTS; ++i)
 		xhci_free_virt_device(xhci, i);
@@ -2340,6 +2346,7 @@
 	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
 	if (!xhci->cmd_ring)
 		goto fail;
+	INIT_LIST_HEAD(&xhci->cancel_cmd_list);
 	xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
 	xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
 			(unsigned long long)xhci->cmd_ring->first_seg->dma);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 9bfd4ca11..8345d7c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -103,6 +103,7 @@
 		 * PPT chipsets.
 		 */
 		xhci->quirks |= XHCI_SPURIOUS_REBOOT;
+		xhci->quirks |= XHCI_AVOID_BEI;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
 			pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 643c2f3..c6ebb17 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -280,12 +280,123 @@
 /* Ring the host controller doorbell after placing a command on the ring */
 void xhci_ring_cmd_db(struct xhci_hcd *xhci)
 {
+	if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING))
+		return;
+
 	xhci_dbg(xhci, "// Ding dong!\n");
 	xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
 	/* Flush PCI posted writes */
 	xhci_readl(xhci, &xhci->dba->doorbell[0]);
 }
 
+static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
+{
+	u64 temp_64;
+	int ret;
+
+	xhci_dbg(xhci, "Abort command ring\n");
+
+	if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
+		xhci_dbg(xhci, "The command ring isn't running, "
+				"Have the command ring been stopped?\n");
+		return 0;
+	}
+
+	temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+	if (!(temp_64 & CMD_RING_RUNNING)) {
+		xhci_dbg(xhci, "Command ring had been stopped\n");
+		return 0;
+	}
+	xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
+	xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
+			&xhci->op_regs->cmd_ring);
+
+	/* Section 4.6.1.2 of xHCI 1.0 spec says software should
+	 * time the completion od all xHCI commands, including
+	 * the Command Abort operation. If software doesn't see
+	 * CRR negated in a timely manner (e.g. longer than 5
+	 * seconds), then it should assume that the there are
+	 * larger problems with the xHC and assert HCRST.
+	 */
+	ret = handshake(xhci, &xhci->op_regs->cmd_ring,
+			CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
+	if (ret < 0) {
+		xhci_err(xhci, "Stopped the command ring failed, "
+				"maybe the host is dead\n");
+		xhci->xhc_state |= XHCI_STATE_DYING;
+		xhci_quiesce(xhci);
+		xhci_halt(xhci);
+		return -ESHUTDOWN;
+	}
+
+	return 0;
+}
+
+static int xhci_queue_cd(struct xhci_hcd *xhci,
+		struct xhci_command *command,
+		union xhci_trb *cmd_trb)
+{
+	struct xhci_cd *cd;
+	cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
+	if (!cd)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&cd->cancel_cmd_list);
+
+	cd->command = command;
+	cd->cmd_trb = cmd_trb;
+	list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
+
+	return 0;
+}
+
+/*
+ * Cancel the command which has issue.
+ *
+ * Some commands may hang due to waiting for acknowledgement from
+ * usb device. It is outside of the xHC's ability to control and
+ * will cause the command ring is blocked. When it occurs software
+ * should intervene to recover the command ring.
+ * See Section 4.6.1.1 and 4.6.1.2
+ */
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
+		union xhci_trb *cmd_trb)
+{
+	int retval = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+
+	if (xhci->xhc_state & XHCI_STATE_DYING) {
+		xhci_warn(xhci, "Abort the command ring,"
+				" but the xHCI is dead.\n");
+		retval = -ESHUTDOWN;
+		goto fail;
+	}
+
+	/* queue the cmd desriptor to cancel_cmd_list */
+	retval = xhci_queue_cd(xhci, command, cmd_trb);
+	if (retval) {
+		xhci_warn(xhci, "Queuing command descriptor failed.\n");
+		goto fail;
+	}
+
+	/* abort command ring */
+	retval = xhci_abort_cmd_ring(xhci);
+	if (retval) {
+		xhci_err(xhci, "Abort command ring failed\n");
+		if (unlikely(retval == -ESHUTDOWN)) {
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
+			xhci_dbg(xhci, "xHCI host controller is dead.\n");
+			return retval;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&xhci->lock, flags);
+	return retval;
+}
+
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
 		unsigned int slot_id,
 		unsigned int ep_index,
@@ -1059,6 +1170,20 @@
 	}
 }
 
+/* Complete the command and detele it from the devcie's command queue.
+ */
+static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
+		struct xhci_command *command, u32 status)
+{
+	command->status = status;
+	list_del(&command->cmd_list);
+	if (command->completion)
+		complete(command->completion);
+	else
+		xhci_free_command(xhci, command);
+}
+
+
 /* Check to see if a command in the device's command queue matches this one.
  * Signal the completion or free the command, and return 1.  Return 0 if the
  * completed command isn't at the head of the command list.
@@ -1077,15 +1202,144 @@
 	if (xhci->cmd_ring->dequeue != command->command_trb)
 		return 0;
 
-	command->status = GET_COMP_CODE(le32_to_cpu(event->status));
-	list_del(&command->cmd_list);
-	if (command->completion)
-		complete(command->completion);
-	else
-		xhci_free_command(xhci, command);
+	xhci_complete_cmd_in_cmd_wait_list(xhci, command,
+			GET_COMP_CODE(le32_to_cpu(event->status)));
 	return 1;
 }
 
+/*
+ * Finding the command trb need to be cancelled and modifying it to
+ * NO OP command. And if the command is in device's command wait
+ * list, finishing and freeing it.
+ *
+ * If we can't find the command trb, we think it had already been
+ * executed.
+ */
+static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
+{
+	struct xhci_segment *cur_seg;
+	union xhci_trb *cmd_trb;
+	u32 cycle_state;
+
+	if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
+		return;
+
+	/* find the current segment of command ring */
+	cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
+			xhci->cmd_ring->dequeue, &cycle_state);
+
+	/* find the command trb matched by cd from command ring */
+	for (cmd_trb = xhci->cmd_ring->dequeue;
+			cmd_trb != xhci->cmd_ring->enqueue;
+			next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
+		/* If the trb is link trb, continue */
+		if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
+			continue;
+
+		if (cur_cd->cmd_trb == cmd_trb) {
+
+			/* If the command in device's command list, we should
+			 * finish it and free the command structure.
+			 */
+			if (cur_cd->command)
+				xhci_complete_cmd_in_cmd_wait_list(xhci,
+					cur_cd->command, COMP_CMD_STOP);
+
+			/* get cycle state from the origin command trb */
+			cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
+				& TRB_CYCLE;
+
+			/* modify the command trb to NO OP command */
+			cmd_trb->generic.field[0] = 0;
+			cmd_trb->generic.field[1] = 0;
+			cmd_trb->generic.field[2] = 0;
+			cmd_trb->generic.field[3] = cpu_to_le32(
+					TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
+			break;
+		}
+	}
+}
+
+static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
+{
+	struct xhci_cd *cur_cd, *next_cd;
+
+	if (list_empty(&xhci->cancel_cmd_list))
+		return;
+
+	list_for_each_entry_safe(cur_cd, next_cd,
+			&xhci->cancel_cmd_list, cancel_cmd_list) {
+		xhci_cmd_to_noop(xhci, cur_cd);
+		list_del(&cur_cd->cancel_cmd_list);
+		kfree(cur_cd);
+	}
+}
+
+/*
+ * traversing the cancel_cmd_list. If the command descriptor according
+ * to cmd_trb is found, the function free it and return 1, otherwise
+ * return 0.
+ */
+static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
+		union xhci_trb *cmd_trb)
+{
+	struct xhci_cd *cur_cd, *next_cd;
+
+	if (list_empty(&xhci->cancel_cmd_list))
+		return 0;
+
+	list_for_each_entry_safe(cur_cd, next_cd,
+			&xhci->cancel_cmd_list, cancel_cmd_list) {
+		if (cur_cd->cmd_trb == cmd_trb) {
+			if (cur_cd->command)
+				xhci_complete_cmd_in_cmd_wait_list(xhci,
+					cur_cd->command, COMP_CMD_STOP);
+			list_del(&cur_cd->cancel_cmd_list);
+			kfree(cur_cd);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
+ * trb pointed by the command ring dequeue pointer is the trb we want to
+ * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
+ * traverse the cancel_cmd_list to trun the all of the commands according
+ * to command descriptor to NO-OP trb.
+ */
+static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
+		int cmd_trb_comp_code)
+{
+	int cur_trb_is_good = 0;
+
+	/* Searching the cmd trb pointed by the command ring dequeue
+	 * pointer in command descriptor list. If it is found, free it.
+	 */
+	cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
+			xhci->cmd_ring->dequeue);
+
+	if (cmd_trb_comp_code == COMP_CMD_ABORT)
+		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+	else if (cmd_trb_comp_code == COMP_CMD_STOP) {
+		/* traversing the cancel_cmd_list and canceling
+		 * the command according to command descriptor
+		 */
+		xhci_cancel_cmd_in_cd_list(xhci);
+
+		xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
+		/*
+		 * ring command ring doorbell again to restart the
+		 * command ring
+		 */
+		if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
+			xhci_ring_cmd_db(xhci);
+	}
+	return cur_trb_is_good;
+}
+
 static void handle_cmd_completion(struct xhci_hcd *xhci,
 		struct xhci_event_cmd *event)
 {
@@ -1111,6 +1365,22 @@
 		xhci->error_bitmask |= 1 << 5;
 		return;
 	}
+
+	if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
+		(GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
+		/* If the return value is 0, we think the trb pointed by
+		 * command ring dequeue pointer is a good trb. The good
+		 * trb means we don't want to cancel the trb, but it have
+		 * been stopped by host. So we should handle it normally.
+		 * Otherwise, driver should invoke inc_deq() and return.
+		 */
+		if (handle_stopped_cmd_ring(xhci,
+				GET_COMP_CODE(le32_to_cpu(event->status)))) {
+			inc_deq(xhci, xhci->cmd_ring);
+			return;
+		}
+	}
+
 	switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
 		& TRB_TYPE_BITMASK) {
 	case TRB_TYPE(TRB_ENABLE_SLOT):
@@ -2003,6 +2273,8 @@
  */
 static int handle_tx_event(struct xhci_hcd *xhci,
 		struct xhci_transfer_event *event)
+	__releases(&xhci->lock)
+	__acquires(&xhci->lock)
 {
 	struct xhci_virt_device *xdev;
 	struct xhci_virt_ep *ep;
@@ -2580,7 +2852,7 @@
 			xhci_err(xhci, "Ring expansion failed\n");
 			return -ENOMEM;
 		}
-	};
+	}
 
 	if (enqueue_is_link_trb(ep_ring)) {
 		struct xhci_ring *ring = ep_ring;
@@ -3400,7 +3672,9 @@
 			} else {
 				td->last_trb = ep_ring->enqueue;
 				field |= TRB_IOC;
-				if (xhci->hci_version == 0x100) {
+				if (xhci->hci_version == 0x100 &&
+						!(xhci->quirks &
+							XHCI_AVOID_BEI)) {
 					/* Set BEI bit except for the last td */
 					if (i < num_tds - 1)
 						field |= TRB_BEI;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6ece0ed..8d7fcbb 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -52,7 +52,7 @@
  * handshake done).  There are two failure modes:  "usec" have passed (major
  * hardware flakeout), or the register reads as all-ones (hardware removed).
  */
-static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
 		      u32 mask, u32 done, int usec)
 {
 	u32	result;
@@ -105,9 +105,10 @@
 
 	ret = handshake(xhci, &xhci->op_regs->status,
 			STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
-	if (!ret)
+	if (!ret) {
 		xhci->xhc_state |= XHCI_STATE_HALTED;
-	else
+		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+	} else
 		xhci_warn(xhci, "Host not halted after %u microseconds.\n",
 				XHCI_MAX_HALT_USEC);
 	return ret;
@@ -470,6 +471,8 @@
 
 	dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
 	dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+	if (!dmi_product_name || !dmi_sys_vendor)
+		return false;
 
 	if (!(strstr(dmi_sys_vendor, "Hewlett-Packard")))
 		return false;
@@ -581,6 +584,7 @@
 		return -ENODEV;
 	}
 	xhci->shared_hcd->state = HC_STATE_RUNNING;
+	xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
 
 	if (xhci->quirks & XHCI_NEC_HOST)
 		xhci_ring_cmd_db(xhci);
@@ -886,7 +890,7 @@
 	command &= ~CMD_RUN;
 	xhci_writel(xhci, command, &xhci->op_regs->command);
 	if (handshake(xhci, &xhci->op_regs->status,
-		      STS_HALT, STS_HALT, 100*100)) {
+		      STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) {
 		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
 		spin_unlock_irq(&xhci->lock);
 		return -ETIMEDOUT;
@@ -1948,7 +1952,7 @@
 				xhci->num_active_eps);
 }
 
-unsigned int xhci_get_block_size(struct usb_device *udev)
+static unsigned int xhci_get_block_size(struct usb_device *udev)
 {
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
@@ -1966,7 +1970,8 @@
 	}
 }
 
-unsigned int xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw)
+static unsigned int
+xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw)
 {
 	if (interval_bw->overhead[LS_OVERHEAD_TYPE])
 		return LS_OVERHEAD;
@@ -2521,6 +2526,7 @@
 	struct completion *cmd_completion;
 	u32 *cmd_status;
 	struct xhci_virt_device *virt_dev;
+	union xhci_trb *cmd_trb;
 
 	spin_lock_irqsave(&xhci->lock, flags);
 	virt_dev = xhci->devs[udev->slot_id];
@@ -2566,6 +2572,7 @@
 	}
 	init_completion(cmd_completion);
 
+	cmd_trb = xhci->cmd_ring->dequeue;
 	if (!ctx_change)
 		ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
 				udev->slot_id, must_succeed);
@@ -2587,14 +2594,17 @@
 	/* Wait for the configure endpoint command to complete */
 	timeleft = wait_for_completion_interruptible_timeout(
 			cmd_completion,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	if (timeleft <= 0) {
 		xhci_warn(xhci, "%s while waiting for %s command\n",
 				timeleft == 0 ? "Timeout" : "Signal",
 				ctx_change == 0 ?
 					"configure endpoint" :
 					"evaluate context");
-		/* FIXME cancel the configure endpoint command */
+		/* cancel the configure endpoint command */
+		ret = xhci_cancel_cmd(xhci, command, cmd_trb);
+		if (ret < 0)
+			return ret;
 		return -ETIME;
 	}
 
@@ -3543,8 +3553,10 @@
 	unsigned long flags;
 	int timeleft;
 	int ret;
+	union xhci_trb *cmd_trb;
 
 	spin_lock_irqsave(&xhci->lock, flags);
+	cmd_trb = xhci->cmd_ring->dequeue;
 	ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
 	if (ret) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3556,12 +3568,12 @@
 
 	/* XXX: how much time for xHC slot assignment? */
 	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	if (timeleft <= 0) {
 		xhci_warn(xhci, "%s while waiting for a slot\n",
 				timeleft == 0 ? "Timeout" : "Signal");
-		/* FIXME cancel the enable slot request */
-		return 0;
+		/* cancel the enable slot request */
+		return xhci_cancel_cmd(xhci, NULL, cmd_trb);
 	}
 
 	if (!xhci->slot_id) {
@@ -3622,6 +3634,7 @@
 	struct xhci_slot_ctx *slot_ctx;
 	struct xhci_input_control_ctx *ctrl_ctx;
 	u64 temp_64;
+	union xhci_trb *cmd_trb;
 
 	if (!udev->slot_id) {
 		xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
@@ -3660,6 +3673,7 @@
 	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
 
 	spin_lock_irqsave(&xhci->lock, flags);
+	cmd_trb = xhci->cmd_ring->dequeue;
 	ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
 					udev->slot_id);
 	if (ret) {
@@ -3672,7 +3686,7 @@
 
 	/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
 	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	/* FIXME: From section 4.3.4: "Software shall be responsible for timing
 	 * the SetAddress() "recovery interval" required by USB and aborting the
 	 * command on a timeout.
@@ -3680,7 +3694,10 @@
 	if (timeleft <= 0) {
 		xhci_warn(xhci, "%s while waiting for address device command\n",
 				timeleft == 0 ? "Timeout" : "Signal");
-		/* FIXME cancel the address device command */
+		/* cancel the address device command */
+		ret = xhci_cancel_cmd(xhci, NULL, cmd_trb);
+		if (ret < 0)
+			return ret;
 		return -ETIME;
 	}
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 1a05908..53df4e7 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1256,6 +1256,16 @@
 	union xhci_trb		*last_trb;
 };
 
+/* xHCI command default timeout value */
+#define XHCI_CMD_DEFAULT_TIMEOUT	(5 * HZ)
+
+/* command descriptor */
+struct xhci_cd {
+	struct list_head	cancel_cmd_list;
+	struct xhci_command	*command;
+	union xhci_trb		*cmd_trb;
+};
+
 struct xhci_dequeue_state {
 	struct xhci_segment *new_deq_seg;
 	union xhci_trb *new_deq_ptr;
@@ -1421,6 +1431,11 @@
 	/* data structures */
 	struct xhci_device_context_array *dcbaa;
 	struct xhci_ring	*cmd_ring;
+	unsigned int            cmd_ring_state;
+#define CMD_RING_STATE_RUNNING         (1 << 0)
+#define CMD_RING_STATE_ABORTED         (1 << 1)
+#define CMD_RING_STATE_STOPPED         (1 << 2)
+	struct list_head        cancel_cmd_list;
 	unsigned int		cmd_ring_reserved_trbs;
 	struct xhci_ring	*event_ring;
 	struct xhci_erst	erst;
@@ -1496,6 +1511,7 @@
 #define XHCI_INTEL_HOST		(1 << 12)
 #define XHCI_SPURIOUS_REBOOT	(1 << 13)
 #define XHCI_COMP_MODE_QUIRK	(1 << 14)
+#define XHCI_AVOID_BEI		(1 << 15)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1704,6 +1720,8 @@
 
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+		u32 mask, u32 done, int usec);
 void xhci_quiesce(struct xhci_hcd *xhci);
 int xhci_halt(struct xhci_hcd *xhci);
 int xhci_reset(struct xhci_hcd *xhci);
@@ -1794,6 +1812,8 @@
 		unsigned int slot_id, unsigned int ep_index,
 		struct xhci_dequeue_state *deq_state);
 void xhci_stop_endpoint_command_watchdog(unsigned long arg);
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
+		union xhci_trb *cmd_trb);
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
 		unsigned int ep_index, unsigned int stream_id);
 
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 1bfcd02..a8f0523 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -244,3 +244,8 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called yurex.
 
+config USB_EZUSB_FX2
+	tristate "Functions for loading firmware on EZUSB chips"
+	help
+	  Say Y here if you need EZUSB device support.
+	  (Cypress FX/FX2/FX2LP microcontrollers)
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 796ce7eb..3e99a64 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -11,6 +11,7 @@
 obj-$(CONFIG_USB_CYTHERM)		+= cytherm.o
 obj-$(CONFIG_USB_EMI26)			+= emi26.o
 obj-$(CONFIG_USB_EMI62)			+= emi62.o
+obj-$(CONFIG_USB_EZUSB_FX2)		+= ezusb.o
 obj-$(CONFIG_USB_FTDI_ELAN)		+= ftdi-elan.o
 obj-$(CONFIG_USB_IDMOUSE)		+= idmouse.o
 obj-$(CONFIG_USB_IOWARRIOR)		+= iowarrior.o
diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c
new file mode 100644
index 0000000..4223d76
--- /dev/null
+++ b/drivers/usb/misc/ezusb.c
@@ -0,0 +1,160 @@
+/*
+ * EZ-USB specific functions used by some of the USB to Serial drivers.
+ *
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/ihex.h>
+
+struct ezusb_fx_type {
+	/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
+	unsigned short cpucs_reg;
+	unsigned short max_internal_adress;
+};
+
+struct ezusb_fx_type ezusb_fx1 = {
+	.cpucs_reg = 0x7F92,
+	.max_internal_adress = 0x1B3F,
+};
+
+struct ezusb_fx_type ezusb_fx2 = {
+	.cpucs_reg = 0xE600,
+	.max_internal_adress = 0x3FFF,
+};
+
+/* Commands for writing to memory */
+#define WRITE_INT_RAM 0xA0
+#define WRITE_EXT_RAM 0xA3
+
+int ezusb_writememory(struct usb_device *dev, int address,
+				unsigned char *data, int length, __u8 request)
+{
+	int result;
+	unsigned char *transfer_buffer;
+
+	if (!dev)
+		return -ENODEV;
+
+	transfer_buffer = kmemdup(data, length, GFP_KERNEL);
+	if (!transfer_buffer) {
+		dev_err(&dev->dev, "%s - kmalloc(%d) failed.\n",
+							__func__, length);
+		return -ENOMEM;
+	}
+	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+				 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				 address, 0, transfer_buffer, length, 3000);
+
+	kfree(transfer_buffer);
+	return result;
+}
+EXPORT_SYMBOL_GPL(ezusb_writememory);
+
+int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg,
+			 unsigned char reset_bit)
+{
+	int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM);
+	if (response < 0)
+		dev_err(&dev->dev, "%s-%d failed: %d\n",
+						__func__, reset_bit, response);
+	return response;
+}
+
+int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit)
+{
+	return ezusb_set_reset(dev, ezusb_fx1.cpucs_reg, reset_bit);
+}
+EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset);
+
+int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit)
+{
+	return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit);
+}
+EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
+
+static int ezusb_ihex_firmware_download(struct usb_device *dev,
+					struct ezusb_fx_type fx,
+					const char *firmware_path)
+{
+	int ret = -ENOENT;
+	const struct firmware *firmware = NULL;
+	const struct ihex_binrec *record;
+
+	if (request_ihex_firmware(&firmware, firmware_path,
+				  &dev->dev)) {
+		dev_err(&dev->dev,
+			"%s - request \"%s\" failed\n",
+			__func__, firmware_path);
+		goto out;
+	}
+
+	ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
+	if (ret < 0)
+		goto out;
+
+	record = (const struct ihex_binrec *)firmware->data;
+	for (; record; record = ihex_next_binrec(record)) {
+		if (be32_to_cpu(record->addr) > fx.max_internal_adress) {
+			ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
+						(unsigned char *)record->data,
+						be16_to_cpu(record->len), WRITE_EXT_RAM);
+			if (ret < 0) {
+				dev_err(&dev->dev, "%s - ezusb_writememory "
+					"failed writing internal memory "
+					"(%d %04X %p %d)\n", __func__, ret,
+					be32_to_cpu(record->addr), record->data,
+					be16_to_cpu(record->len));
+				goto out;
+			}
+		}
+	}
+
+	ret = ezusb_set_reset(dev, fx.cpucs_reg, 1);
+	if (ret < 0)
+		goto out;
+	record = (const struct ihex_binrec *)firmware->data;
+	for (; record; record = ihex_next_binrec(record)) {
+		if (be32_to_cpu(record->addr) <= fx.max_internal_adress) {
+			ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
+						(unsigned char *)record->data,
+						be16_to_cpu(record->len), WRITE_INT_RAM);
+			if (ret < 0) {
+				dev_err(&dev->dev, "%s - ezusb_writememory "
+					"failed writing external memory "
+					"(%d %04X %p %d)\n", __func__, ret,
+					be32_to_cpu(record->addr), record->data,
+					be16_to_cpu(record->len));
+				goto out;
+			}
+		}
+	}
+	ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
+out:
+	release_firmware(firmware);
+	return ret;
+}
+
+int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
+				     const char *firmware_path)
+{
+	return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path);
+}
+EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download);
+
+int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
+				     const char *firmware_path)
+{
+	return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path);
+}
+EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
+
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index a2702cb..8089479 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -868,9 +868,6 @@
 
 	dbg(2, "%s: enter", __func__);
 
-	if (udev == NULL)
-		dev_info(&interface->dev, "udev is NULL.\n");
-
 	/* allocate memory for our device state and initialize it */
 
 	dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 1084124..b9b356a 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -338,7 +338,7 @@
 				thistime -= partial;
 			} else
 				break;
-		};
+		}
 		if (result) {
 			dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
 				result);
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 6259f0d..23a0b7f 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -12,7 +12,6 @@
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
 	select USB_OTG_UTILS
-	select USB_GADGET_DUALSPEED
 	help
 	  Say Y here if your system has a dual role high speed USB
 	  controller based on the Mentor Graphics silicon IP.  Then
@@ -20,7 +19,7 @@
 	  it's being used with, including the USB peripheral role,
 	  or the USB host role, or both.
 
-	  Texas Instruments familiies using this IP include DaVinci
+	  Texas Instruments families using this IP include DaVinci
 	  (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010.
 
 	  Analog Devices parts using this IP include Blackfin BF54x,
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 7a95ab8..457f25e 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <plat/usb.h>
 
@@ -107,9 +108,8 @@
 	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
 
 	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
-	if (is_otg_enabled(musb))
-		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
-			    AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+	musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
+			AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
 }
 
 /*
@@ -173,9 +173,6 @@
 			    MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
 		break;
 	case OTG_STATE_B_IDLE:
-		if (!is_peripheral_enabled(musb))
-			break;
-
 		devctl = musb_readb(mregs, MUSB_DEVCTL);
 		if (devctl & MUSB_DEVCTL_BDEVICE)
 			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
@@ -192,9 +189,6 @@
 {
 	static unsigned long last_timer;
 
-	if (!is_otg_enabled(musb))
-		return;
-
 	if (timeout == 0)
 		timeout = jiffies + msecs_to_jiffies(3);
 
@@ -271,8 +265,7 @@
 		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
 		int err;
 
-		err = is_host_enabled(musb) && (musb->int_usb &
-						MUSB_INTR_VBUSERROR);
+		err = musb->int_usb & MUSB_INTR_VBUSERROR;
 		if (err) {
 			/*
 			 * The Mentor core doesn't debounce VBUS as needed
@@ -289,7 +282,7 @@
 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
 			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 			WARNING("VBUS error workaround (delay coming)\n");
-		} else if (is_host_enabled(musb) && drvvbus) {
+		} else if (drvvbus) {
 			MUSB_HST_MODE(musb);
 			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -326,7 +319,7 @@
 	}
 
 	/* Poll for ID change */
-	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+	if (musb->xceiv->state == OTG_STATE_B_IDLE)
 		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 
 	spin_unlock_irqrestore(&musb->lock, flags);
@@ -369,8 +362,7 @@
 	if (IS_ERR_OR_NULL(musb->xceiv))
 		return -ENODEV;
 
-	if (is_host_enabled(musb))
-		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+	setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
 
 	/* Reset the musb */
 	if (data->reset)
@@ -400,8 +392,7 @@
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
 	struct omap_musb_board_data *data = plat->board_data;
 
-	if (is_host_enabled(musb))
-		del_timer_sync(&otg_workaround);
+	del_timer_sync(&otg_workaround);
 
 	/* Shutdown the on-chip PHY and its PLL. */
 	if (data->set_phy_power)
@@ -468,6 +459,7 @@
 	struct clk			*clk;
 
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -475,38 +467,47 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	musb = platform_device_alloc("musb-hdrc", musbid);
 	if (!musb) {
 		dev_err(&pdev->dev, "failed to allocate musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	phy_clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(phy_clk)) {
 		dev_err(&pdev->dev, "failed to get PHY clock\n");
 		ret = PTR_ERR(phy_clk);
-		goto err2;
+		goto err3;
 	}
 
 	clk = clk_get(&pdev->dev, "ick");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		ret = PTR_ERR(clk);
-		goto err3;
+		goto err4;
 	}
 
 	ret = clk_enable(phy_clk);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to enable PHY clock\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = clk_enable(clk);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to enable clock\n");
-		goto err5;
+		goto err6;
 	}
 
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &am35x_dmamask;
 	musb->dev.coherent_dma_mask	= am35x_dmamask;
@@ -524,38 +525,41 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err6;
+		goto err7;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err6;
+		goto err7;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err6;
+		goto err7;
 	}
 
 	return 0;
 
-err6:
+err7:
 	clk_disable(clk);
 
-err5:
+err6:
 	clk_disable(phy_clk);
 
-err4:
+err5:
 	clk_put(clk);
 
-err3:
+err4:
 	clk_put(phy_clk);
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -567,6 +571,7 @@
 {
 	struct am35x_glue	*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	clk_disable(glue->clk);
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 428e6aa..e8cff9b 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <asm/cacheflush.h>
 
@@ -184,8 +185,8 @@
 	}
 
 	/* Start sampling ID pin, when plug is removed from MUSB */
-	if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
-		|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+	if ((musb->xceiv->state == OTG_STATE_B_IDLE
+		|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON) ||
 		(musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
 		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 		musb->a_wait_bcon = TIMER_DELAY;
@@ -228,18 +229,13 @@
 
 			val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
 			musb_writeb(musb->mregs, MUSB_INTRUSB, val);
-			if (is_otg_enabled(musb))
-				musb->xceiv->state = OTG_STATE_B_IDLE;
-			else
-				musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
+			musb->xceiv->state = OTG_STATE_B_IDLE;
 		}
 		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 		break;
 	case OTG_STATE_B_IDLE:
-
-		if (!is_peripheral_enabled(musb))
-			break;
-		/* Start a new session.  It seems that MUSB needs taking
+		/*
+		 * Start a new session.  It seems that MUSB needs taking
 		 * some time to recognize the type of the plug inserted?
 		 */
 		val = musb_readw(musb->mregs, MUSB_DEVCTL);
@@ -295,10 +291,7 @@
 
 static void bfin_musb_enable(struct musb *musb)
 {
-	if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
-		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
-		musb->a_wait_bcon = TIMER_DELAY;
-	}
+	/* REVISIT is this really correct ? */
 }
 
 static void bfin_musb_disable(struct musb *musb)
@@ -323,12 +316,6 @@
 	return 0;
 }
 
-static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
-{
-	if (!is_otg_enabled(musb) && is_host_enabled(musb))
-		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
-}
-
 static int bfin_musb_vbus_status(struct musb *musb)
 {
 	return 0;
@@ -424,12 +411,10 @@
 
 	bfin_musb_reg_init(musb);
 
-	if (is_host_enabled(musb)) {
-		setup_timer(&musb_conn_timer,
-			musb_conn_timer_handler, (unsigned long) musb);
-	}
-	if (is_peripheral_enabled(musb))
-		musb->xceiv->set_power = bfin_musb_set_power;
+	setup_timer(&musb_conn_timer, musb_conn_timer_handler,
+			(unsigned long) musb);
+
+	musb->xceiv->set_power = bfin_musb_set_power;
 
 	musb->isr = blackfin_interrupt;
 	musb->double_buffer_not_ok = true;
@@ -454,7 +439,6 @@
 	.disable	= bfin_musb_disable,
 
 	.set_mode	= bfin_musb_set_mode,
-	.try_idle	= bfin_musb_try_idle,
 
 	.vbus_status	= bfin_musb_vbus_status,
 	.set_vbus	= bfin_musb_set_vbus,
@@ -471,6 +455,7 @@
 	struct bfin_glue		*glue;
 
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -478,12 +463,21 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
-	if (!musb) {
-		dev_err(&pdev->dev, "failed to allocate musb device\n");
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
 		goto err1;
 	}
 
+	musb = platform_device_alloc("musb-hdrc", musbid);
+	if (!musb) {
+		dev_err(&pdev->dev, "failed to allocate musb device\n");
+		goto err2;
+	}
+
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &bfin_dmamask;
 	musb->dev.coherent_dma_mask	= bfin_dmamask;
@@ -499,26 +493,29 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err2;
+		goto err3;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err2;
+		goto err3;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err2;
+		goto err3;
 	}
 
 	return 0;
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -530,6 +527,7 @@
 {
 	struct bfin_glue		*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	kfree(glue);
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 8637c1f..e19da82 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1316,7 +1316,7 @@
 }
 
 /* Instantiate a software object representing a DMA controller. */
-struct dma_controller *__init
+struct dma_controller *__devinit
 dma_controller_create(struct musb *musb, void __iomem *mregs)
 {
 	struct cppi		*controller;
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 0f9fcec..ce11d20 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <mach/da8xx.h>
 #include <mach/usb.h>
@@ -155,9 +156,8 @@
 	musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
 
 	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
-	if (is_otg_enabled(musb))
-		musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
-			    DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
+	musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
+			DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
 }
 
 /**
@@ -231,9 +231,6 @@
 			    MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);
 		break;
 	case OTG_STATE_B_IDLE:
-		if (!is_peripheral_enabled(musb))
-			break;
-
 		/*
 		 * There's no ID-changed IRQ, so we have no good way to tell
 		 * when to switch to the A-Default state machine (by setting
@@ -263,9 +260,6 @@
 {
 	static unsigned long last_timer;
 
-	if (!is_otg_enabled(musb))
-		return;
-
 	if (timeout == 0)
 		timeout = jiffies + msecs_to_jiffies(3);
 
@@ -333,8 +327,7 @@
 		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
 		int err;
 
-		err = is_host_enabled(musb) && (musb->int_usb &
-						MUSB_INTR_VBUSERROR);
+		err = musb->int_usb & USB_INTR_VBUSERROR;
 		if (err) {
 			/*
 			 * The Mentor core doesn't debounce VBUS as needed
@@ -351,7 +344,7 @@
 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
 			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 			WARNING("VBUS error workaround (delay coming)\n");
-		} else if (is_host_enabled(musb) && drvvbus) {
+		} else if (drvvbus) {
 			MUSB_HST_MODE(musb);
 			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -382,7 +375,7 @@
 		musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
 
 	/* Poll for ID change */
-	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+	if (musb->xceiv->state == OTG_STATE_B_IDLE)
 		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 
 	spin_unlock_irqrestore(&musb->lock, flags);
@@ -430,8 +423,7 @@
 	if (IS_ERR_OR_NULL(musb->xceiv))
 		goto fail;
 
-	if (is_host_enabled(musb))
-		setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
+	setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
 
 	/* Reset the controller */
 	musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
@@ -454,8 +446,7 @@
 
 static int da8xx_musb_exit(struct musb *musb)
 {
-	if (is_host_enabled(musb))
-		del_timer_sync(&otg_workaround);
+	del_timer_sync(&otg_workaround);
 
 	phy_off();
 
@@ -489,6 +480,7 @@
 	struct clk			*clk;
 
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -496,25 +488,34 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	musb = platform_device_alloc("musb-hdrc", musbid);
 	if (!musb) {
 		dev_err(&pdev->dev, "failed to allocate musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	clk = clk_get(&pdev->dev, "usb20");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		ret = PTR_ERR(clk);
-		goto err2;
+		goto err3;
 	}
 
 	ret = clk_enable(clk);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to enable clock\n");
-		goto err3;
+		goto err4;
 	}
 
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &da8xx_dmamask;
 	musb->dev.coherent_dma_mask	= da8xx_dmamask;
@@ -531,32 +532,35 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err4;
+		goto err5;
 	}
 
 	return 0;
 
-err4:
+err5:
 	clk_disable(clk);
 
-err3:
+err4:
 	clk_put(clk);
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -568,6 +572,7 @@
 {
 	struct da8xx_glue		*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	clk_disable(glue->clk);
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 472c8b4..606bfd0 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -33,6 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <mach/cputype.h>
 #include <mach/hardware.h>
@@ -115,8 +116,7 @@
 		dma_off = 0;
 
 	/* force a DRVVBUS irq so we can start polling for ID change */
-	if (is_otg_enabled(musb))
-		musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+	musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
 			DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
 }
 
@@ -234,10 +234,8 @@
 			MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
 		break;
 	case OTG_STATE_B_IDLE:
-		if (!is_peripheral_enabled(musb))
-			break;
-
-		/* There's no ID-changed IRQ, so we have no good way to tell
+		/*
+		 * There's no ID-changed IRQ, so we have no good way to tell
 		 * when to switch to the A-Default state machine (by setting
 		 * the DEVCTL.SESSION flag).
 		 *
@@ -315,8 +313,7 @@
 		u8	devctl = musb_readb(mregs, MUSB_DEVCTL);
 		int	err = musb->int_usb & MUSB_INTR_VBUSERROR;
 
-		err = is_host_enabled(musb)
-				&& (musb->int_usb & MUSB_INTR_VBUSERROR);
+		err = musb->int_usb & MUSB_INTR_VBUSERROR;
 		if (err) {
 			/* The Mentor core doesn't debounce VBUS as needed
 			 * to cope with device connect current spikes. This
@@ -332,7 +329,7 @@
 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
 			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 			WARNING("VBUS error workaround (delay coming)\n");
-		} else if (is_host_enabled(musb) && drvvbus) {
+		} else if (drvvbus) {
 			MUSB_HST_MODE(musb);
 			otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -365,8 +362,7 @@
 	musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
 
 	/* poll for ID change */
-	if (is_otg_enabled(musb)
-			&& musb->xceiv->state == OTG_STATE_B_IDLE)
+	if (musb->xceiv->state == OTG_STATE_B_IDLE)
 		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 
 	spin_unlock_irqrestore(&musb->lock, flags);
@@ -397,8 +393,7 @@
 	if (revision == 0)
 		goto fail;
 
-	if (is_host_enabled(musb))
-		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+	setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
 
 	davinci_musb_source_power(musb, 0, 1);
 
@@ -419,12 +414,7 @@
 	if (cpu_is_davinci_dm355()) {
 		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP);
 
-		if (is_host_enabled(musb)) {
-			deepsleep &= ~DRVVBUS_OVERRIDE;
-		} else {
-			deepsleep &= ~DRVVBUS_FORCE;
-			deepsleep |= DRVVBUS_OVERRIDE;
-		}
+		deepsleep &= ~DRVVBUS_FORCE;
 		__raw_writel(deepsleep, DM355_DEEPSLEEP);
 	}
 
@@ -453,8 +443,7 @@
 
 static int davinci_musb_exit(struct musb *musb)
 {
-	if (is_host_enabled(musb))
-		del_timer_sync(&otg_workaround);
+	del_timer_sync(&otg_workaround);
 
 	/* force VBUS off */
 	if (cpu_is_davinci_dm355()) {
@@ -468,7 +457,7 @@
 	davinci_musb_source_power(musb, 0 /*off*/, 1);
 
 	/* delay, to avoid problems with module reload */
-	if (is_host_enabled(musb) && musb->xceiv->otg->default_a) {
+	if (musb->xceiv->otg->default_a) {
 		int	maxdelay = 30;
 		u8	devctl, warn = 0;
 
@@ -523,6 +512,7 @@
 	struct clk			*clk;
 
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -530,25 +520,34 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	musb = platform_device_alloc("musb-hdrc", musbid);
 	if (!musb) {
 		dev_err(&pdev->dev, "failed to allocate musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	clk = clk_get(&pdev->dev, "usb");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		ret = PTR_ERR(clk);
-		goto err2;
+		goto err3;
 	}
 
 	ret = clk_enable(clk);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to enable clock\n");
-		goto err3;
+		goto err4;
 	}
 
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &davinci_dmamask;
 	musb->dev.coherent_dma_mask	= davinci_dmamask;
@@ -565,32 +564,35 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err4;
+		goto err5;
 	}
 
 	return 0;
 
-err4:
+err5:
 	clk_disable(clk);
 
-err3:
+err4:
 	clk_put(clk);
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -602,6 +604,7 @@
 {
 	struct davinci_glue		*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	clk_disable(glue->clk);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 26f1bef..bb56a0e8 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -99,6 +99,8 @@
 #include <linux/prefetch.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/idr.h>
+#include <linux/dma-mapping.h>
 
 #include "musb_core.h"
 
@@ -114,6 +116,7 @@
 
 #define MUSB_DRIVER_NAME "musb-hdrc"
 const char musb_driver_name[] = MUSB_DRIVER_NAME;
+static DEFINE_IDA(musb_ida);
 
 MODULE_DESCRIPTION(DRIVER_INFO);
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -130,6 +133,35 @@
 
 /*-------------------------------------------------------------------------*/
 
+int musb_get_id(struct device *dev, gfp_t gfp_mask)
+{
+	int ret;
+	int id;
+
+	ret = ida_pre_get(&musb_ida, gfp_mask);
+	if (!ret) {
+		dev_err(dev, "failed to reserve resource for id\n");
+		return -ENOMEM;
+	}
+
+	ret = ida_get_new(&musb_ida, &id);
+	if (ret < 0) {
+		dev_err(dev, "failed to allocate a new id\n");
+		return ret;
+	}
+
+	return id;
+}
+EXPORT_SYMBOL_GPL(musb_get_id);
+
+void musb_put_id(struct device *dev, int id)
+{
+
+	dev_dbg(dev, "removing id %d\n", id);
+	ida_remove(&musb_ida, id);
+}
+EXPORT_SYMBOL_GPL(musb_put_id);
+
 #ifndef CONFIG_BLACKFIN
 static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
 {
@@ -234,6 +266,9 @@
 	struct musb *musb = hw_ep->musb;
 	void __iomem *fifo = hw_ep->fifo;
 
+	if (unlikely(len == 0))
+		return;
+
 	prefetch((u8 *)src);
 
 	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
@@ -276,6 +311,9 @@
 	struct musb *musb = hw_ep->musb;
 	void __iomem *fifo = hw_ep->fifo;
 
+	if (unlikely(len == 0))
+		return;
+
 	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
 			'R', hw_ep->epnum, fifo, len, dst);
 
@@ -348,7 +386,7 @@
 /*
  * Handles OTG hnp timeouts, such as b_ase0_brst
  */
-void musb_otg_timer_func(unsigned long data)
+static void musb_otg_timer_func(unsigned long data)
 {
 	struct musb	*musb = (struct musb *)data;
 	unsigned long	flags;
@@ -643,8 +681,7 @@
 				break;
 		case OTG_STATE_B_PERIPHERAL:
 			musb_g_suspend(musb);
-			musb->is_active = is_otg_enabled(musb)
-					&& otg->gadget->b_hnp_enable;
+			musb->is_active = otg->gadget->b_hnp_enable;
 			if (musb->is_active) {
 				musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
 				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
@@ -660,8 +697,7 @@
 			break;
 		case OTG_STATE_A_HOST:
 			musb->xceiv->state = OTG_STATE_A_SUSPEND;
-			musb->is_active = is_otg_enabled(musb)
-					&& otg->host->b_hnp_enable;
+			musb->is_active = otg->host->b_hnp_enable;
 			break;
 		case OTG_STATE_B_HOST:
 			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -749,7 +785,7 @@
 		case OTG_STATE_A_SUSPEND:
 			usb_hcd_resume_root_hub(musb_to_hcd(musb));
 			musb_root_disconnect(musb);
-			if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+			if (musb->a_wait_bcon != 0)
 				musb_platform_try_idle(musb, jiffies
 					+ msecs_to_jiffies(musb->a_wait_bcon));
 			break;
@@ -787,7 +823,7 @@
 	 */
 	if (int_usb & MUSB_INTR_RESET) {
 		handled = IRQ_HANDLED;
-		if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
+		if ((devctl & MUSB_DEVCTL_HM) != 0) {
 			/*
 			 * Looks like non-HS BABBLE can be ignored, but
 			 * HS BABBLE is an error condition. For HS the solution
@@ -801,7 +837,7 @@
 				ERR("Stopping host session -- babble\n");
 				musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
 			}
-		} else if (is_peripheral_capable()) {
+		} else {
 			dev_dbg(musb->controller, "BUS RESET as %s\n",
 				otg_state_string(musb->xceiv->state));
 			switch (musb->xceiv->state) {
@@ -925,25 +961,16 @@
 	devctl = musb_readb(regs, MUSB_DEVCTL);
 	devctl &= ~MUSB_DEVCTL_SESSION;
 
-	if (is_otg_enabled(musb)) {
-		/* session started after:
-		 * (a) ID-grounded irq, host mode;
-		 * (b) vbus present/connect IRQ, peripheral mode;
-		 * (c) peripheral initiates, using SRP
-		 */
-		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
-			musb->is_active = 1;
-		else
-			devctl |= MUSB_DEVCTL_SESSION;
-
-	} else if (is_host_enabled(musb)) {
-		/* assume ID pin is hard-wired to ground */
+	/* session started after:
+	 * (a) ID-grounded irq, host mode;
+	 * (b) vbus present/connect IRQ, peripheral mode;
+	 * (c) peripheral initiates, using SRP
+	 */
+	if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+		musb->is_active = 1;
+	else
 		devctl |= MUSB_DEVCTL_SESSION;
 
-	} else /* peripheral is enabled */ {
-		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
-			musb->is_active = 1;
-	}
 	musb_platform_enable(musb);
 	musb_writeb(regs, MUSB_DEVCTL, devctl);
 }
@@ -1007,8 +1034,6 @@
 	musb_generic_disable(musb);
 	spin_unlock_irqrestore(&musb->lock, flags);
 
-	if (!is_otg_enabled(musb) && is_host_enabled(musb))
-		usb_remove_hcd(musb_to_hcd(musb));
 	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
 	musb_platform_exit(musb);
 
@@ -1302,7 +1327,7 @@
 		if (offset < 0) {
 			pr_debug("%s: mem overrun, ep %d\n",
 					musb_driver_name, epn);
-			return -EINVAL;
+			return offset;
 		}
 		epn++;
 		musb->nr_endpoints = max(epn, musb->nr_endpoints);
@@ -1330,7 +1355,7 @@
 {
 	u8 epnum = 0;
 	struct musb_hw_ep *hw_ep;
-	void *mbase = musb->mregs;
+	void __iomem *mbase = musb->mregs;
 	int ret = 0;
 
 	dev_dbg(musb->controller, "<== static silicon ep config\n");
@@ -1571,13 +1596,10 @@
 			/* musb_ep_select(musb->mregs, ep_num); */
 			/* REVISIT just retval = ep->rx_irq(...) */
 			retval = IRQ_HANDLED;
-			if (devctl & MUSB_DEVCTL_HM) {
-				if (is_host_capable())
-					musb_host_rx(musb, ep_num);
-			} else {
-				if (is_peripheral_capable())
-					musb_g_rx(musb, ep_num);
-			}
+			if (devctl & MUSB_DEVCTL_HM)
+				musb_host_rx(musb, ep_num);
+			else
+				musb_g_rx(musb, ep_num);
 		}
 
 		reg >>= 1;
@@ -1592,13 +1614,10 @@
 			/* musb_ep_select(musb->mregs, ep_num); */
 			/* REVISIT just retval |= ep->tx_irq(...) */
 			retval = IRQ_HANDLED;
-			if (devctl & MUSB_DEVCTL_HM) {
-				if (is_host_capable())
-					musb_host_tx(musb, ep_num);
-			} else {
-				if (is_peripheral_capable())
-					musb_g_tx(musb, ep_num);
-			}
+			if (devctl & MUSB_DEVCTL_HM)
+				musb_host_tx(musb, ep_num);
+			else
+				musb_g_tx(musb, ep_num);
 		}
 		reg >>= 1;
 		ep_num++;
@@ -1634,22 +1653,16 @@
 	} else {
 		/* endpoints 1..15 */
 		if (transmit) {
-			if (devctl & MUSB_DEVCTL_HM) {
-				if (is_host_capable())
-					musb_host_tx(musb, epnum);
-			} else {
-				if (is_peripheral_capable())
-					musb_g_tx(musb, epnum);
-			}
+			if (devctl & MUSB_DEVCTL_HM)
+				musb_host_tx(musb, epnum);
+			else
+				musb_g_tx(musb, epnum);
 		} else {
 			/* receive */
-			if (devctl & MUSB_DEVCTL_HM) {
-				if (is_host_capable())
-					musb_host_rx(musb, epnum);
-			} else {
-				if (is_peripheral_capable())
-					musb_g_rx(musb, epnum);
-			}
+			if (devctl & MUSB_DEVCTL_HM)
+				musb_host_rx(musb, epnum);
+			else
+				musb_g_rx(musb, epnum);
 		}
 	}
 }
@@ -1785,10 +1798,9 @@
 static void musb_irq_work(struct work_struct *data)
 {
 	struct musb *musb = container_of(data, struct musb, irq_work);
-	static int old_state;
 
-	if (musb->xceiv->state != old_state) {
-		old_state = musb->xceiv->state;
+	if (musb->xceiv->state != musb->xceiv_old_state) {
+		musb->xceiv_old_state = musb->xceiv->state;
 		sysfs_notify(&musb->controller->kobj, NULL, "mode");
 	}
 }
@@ -1862,15 +1874,15 @@
 		dma_controller_destroy(c);
 	}
 
-	kfree(musb);
+	usb_put_hcd(musb_to_hcd(musb));
 }
 
 /*
  * Perform generic per-controller initialization.
  *
- * @pDevice: the controller (already clocked, etc)
- * @nIrq: irq
- * @mregs: virtual address of controller registers,
+ * @dev: the controller (already clocked, etc)
+ * @nIrq: IRQ number
+ * @ctrl: virtual address of controller registers,
  *	not yet corrected for platform-specific offsets
  */
 static int __devinit
@@ -1879,6 +1891,7 @@
 	int			status;
 	struct musb		*musb;
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct usb_hcd		*hcd;
 
 	/* The driver might handle more features than the board; OK.
 	 * Fail when the board needs a feature that's not enabled.
@@ -1901,7 +1914,6 @@
 	pm_runtime_enable(musb->controller);
 
 	spin_lock_init(&musb->lock);
-	musb->board_mode = plat->mode;
 	musb->board_set_power = plat->set_power;
 	musb->min_power = plat->min_power;
 	musb->ops = plat->platform_ops;
@@ -1972,7 +1984,7 @@
 		goto fail3;
 	}
 	musb->nIrq = nIrq;
-/* FIXME this handles wakeup irqs wrong */
+	/* FIXME this handles wakeup irqs wrong */
 	if (enable_irq_wake(nIrq) == 0) {
 		musb->irq_wake = 1;
 		device_init_wakeup(dev, 1);
@@ -1981,58 +1993,25 @@
 	}
 
 	/* host side needs more setup */
-	if (is_host_enabled(musb)) {
-		struct usb_hcd	*hcd = musb_to_hcd(musb);
+	hcd = musb_to_hcd(musb);
+	otg_set_host(musb->xceiv->otg, &hcd->self);
+	hcd->self.otg_port = 1;
+	musb->xceiv->otg->host = &hcd->self;
+	hcd->power_budget = 2 * (plat->power ? : 250);
 
-		otg_set_host(musb->xceiv->otg, &hcd->self);
-
-		if (is_otg_enabled(musb))
-			hcd->self.otg_port = 1;
-		musb->xceiv->otg->host = &hcd->self;
-		hcd->power_budget = 2 * (plat->power ? : 250);
-
-		/* program PHY to use external vBus if required */
-		if (plat->extvbus) {
-			u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
-			busctl |= MUSB_ULPI_USE_EXTVBUS;
-			musb_write_ulpi_buscontrol(musb->mregs, busctl);
-		}
+	/* program PHY to use external vBus if required */
+	if (plat->extvbus) {
+		u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
+		busctl |= MUSB_ULPI_USE_EXTVBUS;
+		musb_write_ulpi_buscontrol(musb->mregs, busctl);
 	}
 
-	/* For the host-only role, we can activate right away.
-	 * (We expect the ID pin to be forcibly grounded!!)
-	 * Otherwise, wait till the gadget driver hooks up.
-	 */
-	if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
-		struct usb_hcd	*hcd = musb_to_hcd(musb);
+	MUSB_DEV_MODE(musb);
+	musb->xceiv->otg->default_a = 0;
+	musb->xceiv->state = OTG_STATE_B_IDLE;
 
-		MUSB_HST_MODE(musb);
-		musb->xceiv->otg->default_a = 1;
-		musb->xceiv->state = OTG_STATE_A_IDLE;
+	status = musb_gadget_setup(musb);
 
-		status = usb_add_hcd(musb_to_hcd(musb), 0, 0);
-
-		hcd->self.uses_pio_for_control = 1;
-		dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n",
-			"HOST", status,
-			musb_readb(musb->mregs, MUSB_DEVCTL),
-			(musb_readb(musb->mregs, MUSB_DEVCTL)
-					& MUSB_DEVCTL_BDEVICE
-				? 'B' : 'A'));
-
-	} else /* peripheral is enabled */ {
-		MUSB_DEV_MODE(musb);
-		musb->xceiv->otg->default_a = 0;
-		musb->xceiv->state = OTG_STATE_B_IDLE;
-
-		status = musb_gadget_setup(musb);
-
-		dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n",
-			is_otg_enabled(musb) ? "OTG" : "PERIPHERAL",
-			status,
-			musb_readb(musb->mregs, MUSB_DEVCTL));
-
-	}
 	if (status < 0)
 		goto fail3;
 
@@ -2048,28 +2027,13 @@
 
 	pm_runtime_put(musb->controller);
 
-	dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
-			({char *s;
-			 switch (musb->board_mode) {
-			 case MUSB_HOST:		s = "Host"; break;
-			 case MUSB_PERIPHERAL:	s = "Peripheral"; break;
-			 default:		s = "OTG"; break;
-			 }; s; }),
-			ctrl,
-			(is_dma_capable() && musb->dma_controller)
-			? "DMA" : "PIO",
-			musb->nIrq);
-
 	return 0;
 
 fail5:
 	musb_exit_debugfs(musb);
 
 fail4:
-	if (!is_otg_enabled(musb) && is_host_enabled(musb))
-		usb_remove_hcd(musb_to_hcd(musb));
-	else
-		musb_gadget_cleanup(musb);
+	musb_gadget_cleanup(musb);
 
 fail3:
 	pm_runtime_put_sync(musb->controller);
@@ -2096,11 +2060,6 @@
 /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
  * bridge to a platform device; this driver then suffices.
  */
-
-#ifndef CONFIG_MUSB_PIO_ONLY
-static u64	*orig_dma_mask;
-#endif
-
 static int __devinit musb_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
@@ -2119,10 +2078,6 @@
 		return -ENOMEM;
 	}
 
-#ifndef CONFIG_MUSB_PIO_ONLY
-	/* clobbered by use_dma=n */
-	orig_dma_mask = dev->dma_mask;
-#endif
 	status = musb_init_controller(dev, irq, base);
 	if (status < 0)
 		iounmap(base);
@@ -2132,7 +2087,8 @@
 
 static int __devexit musb_remove(struct platform_device *pdev)
 {
-	struct musb	*musb = dev_to_musb(&pdev->dev);
+	struct device	*dev = &pdev->dev;
+	struct musb	*musb = dev_to_musb(dev);
 	void __iomem	*ctrl_base = musb->ctrl_base;
 
 	/* this gets called on rmmod.
@@ -2145,9 +2101,9 @@
 
 	musb_free(musb);
 	iounmap(ctrl_base);
-	device_init_wakeup(&pdev->dev, 0);
+	device_init_wakeup(dev, 0);
 #ifndef CONFIG_MUSB_PIO_ONLY
-	pdev->dev.dma_mask = orig_dma_mask;
+	dma_set_mask(dev, *dev->parent->dma_mask);
 #endif
 	return 0;
 }
@@ -2160,11 +2116,9 @@
 	void __iomem *musb_base = musb->mregs;
 	void __iomem *epio;
 
-	if (is_host_enabled(musb)) {
-		musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
-		musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
-		musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
-	}
+	musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
+	musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+	musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
 	musb->context.power = musb_readb(musb_base, MUSB_POWER);
 	musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
 	musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
@@ -2203,30 +2157,29 @@
 			musb->context.index_regs[i].rxfifosz =
 					musb_read_rxfifosz(musb_base);
 		}
-		if (is_host_enabled(musb)) {
-			musb->context.index_regs[i].txtype =
-				musb_readb(epio, MUSB_TXTYPE);
-			musb->context.index_regs[i].txinterval =
-				musb_readb(epio, MUSB_TXINTERVAL);
-			musb->context.index_regs[i].rxtype =
-				musb_readb(epio, MUSB_RXTYPE);
-			musb->context.index_regs[i].rxinterval =
-				musb_readb(epio, MUSB_RXINTERVAL);
 
-			musb->context.index_regs[i].txfunaddr =
-				musb_read_txfunaddr(musb_base, i);
-			musb->context.index_regs[i].txhubaddr =
-				musb_read_txhubaddr(musb_base, i);
-			musb->context.index_regs[i].txhubport =
-				musb_read_txhubport(musb_base, i);
+		musb->context.index_regs[i].txtype =
+			musb_readb(epio, MUSB_TXTYPE);
+		musb->context.index_regs[i].txinterval =
+			musb_readb(epio, MUSB_TXINTERVAL);
+		musb->context.index_regs[i].rxtype =
+			musb_readb(epio, MUSB_RXTYPE);
+		musb->context.index_regs[i].rxinterval =
+			musb_readb(epio, MUSB_RXINTERVAL);
 
-			musb->context.index_regs[i].rxfunaddr =
-				musb_read_rxfunaddr(musb_base, i);
-			musb->context.index_regs[i].rxhubaddr =
-				musb_read_rxhubaddr(musb_base, i);
-			musb->context.index_regs[i].rxhubport =
-				musb_read_rxhubport(musb_base, i);
-		}
+		musb->context.index_regs[i].txfunaddr =
+			musb_read_txfunaddr(musb_base, i);
+		musb->context.index_regs[i].txhubaddr =
+			musb_read_txhubaddr(musb_base, i);
+		musb->context.index_regs[i].txhubport =
+			musb_read_txhubport(musb_base, i);
+
+		musb->context.index_regs[i].rxfunaddr =
+			musb_read_rxfunaddr(musb_base, i);
+		musb->context.index_regs[i].rxhubaddr =
+			musb_read_rxhubaddr(musb_base, i);
+		musb->context.index_regs[i].rxhubport =
+			musb_read_rxhubport(musb_base, i);
 	}
 }
 
@@ -2237,11 +2190,9 @@
 	void __iomem *ep_target_regs;
 	void __iomem *epio;
 
-	if (is_host_enabled(musb)) {
-		musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
-		musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
-		musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
-	}
+	musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
+	musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
+	musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
 	musb_writeb(musb_base, MUSB_POWER, musb->context.power);
 	musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
 	musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
@@ -2280,33 +2231,31 @@
 				musb->context.index_regs[i].rxfifoadd);
 		}
 
-		if (is_host_enabled(musb)) {
-			musb_writeb(epio, MUSB_TXTYPE,
+		musb_writeb(epio, MUSB_TXTYPE,
 				musb->context.index_regs[i].txtype);
-			musb_writeb(epio, MUSB_TXINTERVAL,
+		musb_writeb(epio, MUSB_TXINTERVAL,
 				musb->context.index_regs[i].txinterval);
-			musb_writeb(epio, MUSB_RXTYPE,
+		musb_writeb(epio, MUSB_RXTYPE,
 				musb->context.index_regs[i].rxtype);
-			musb_writeb(epio, MUSB_RXINTERVAL,
+		musb_writeb(epio, MUSB_RXINTERVAL,
 
-			musb->context.index_regs[i].rxinterval);
-			musb_write_txfunaddr(musb_base, i,
+				musb->context.index_regs[i].rxinterval);
+		musb_write_txfunaddr(musb_base, i,
 				musb->context.index_regs[i].txfunaddr);
-			musb_write_txhubaddr(musb_base, i,
+		musb_write_txhubaddr(musb_base, i,
 				musb->context.index_regs[i].txhubaddr);
-			musb_write_txhubport(musb_base, i,
+		musb_write_txhubport(musb_base, i,
 				musb->context.index_regs[i].txhubport);
 
-			ep_target_regs =
-				musb_read_target_reg_base(i, musb_base);
+		ep_target_regs =
+			musb_read_target_reg_base(i, musb_base);
 
-			musb_write_rxfunaddr(ep_target_regs,
+		musb_write_rxfunaddr(ep_target_regs,
 				musb->context.index_regs[i].rxfunaddr);
-			musb_write_rxhubaddr(ep_target_regs,
+		musb_write_rxhubaddr(ep_target_regs,
 				musb->context.index_regs[i].rxhubaddr);
-			musb_write_rxhubport(ep_target_regs,
+		musb_write_rxhubport(ep_target_regs,
 				musb->context.index_regs[i].rxhubport);
-		}
 	}
 	musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
 }
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 586105b..c158aac 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -71,10 +71,6 @@
 #include <linux/usb/hcd.h>
 #include "musb_host.h"
 
-#define	is_peripheral_enabled(musb)	((musb)->board_mode != MUSB_HOST)
-#define	is_host_enabled(musb)		((musb)->board_mode != MUSB_PERIPHERAL)
-#define	is_otg_enabled(musb)		((musb)->board_mode == MUSB_OTG)
-
 /* NOTE:  otg and peripheral-only state machines start at B_IDLE.
  * OTG or host-only go to A_IDLE when ID is sensed.
  */
@@ -88,8 +84,6 @@
 
 /****************************** PERIPHERAL ROLE *****************************/
 
-#define	is_peripheral_capable()	(1)
-
 extern irqreturn_t musb_g_ep0_irq(struct musb *);
 extern void musb_g_tx(struct musb *, u8);
 extern void musb_g_rx(struct musb *, u8);
@@ -101,8 +95,6 @@
 
 /****************************** HOST ROLE ***********************************/
 
-#define	is_host_capable()	(1)
-
 extern irqreturn_t musb_h_ep0_irq(struct musb *);
 extern void musb_host_tx(struct musb *, u8);
 extern void musb_host_rx(struct musb *, u8);
@@ -376,7 +368,6 @@
 	u16 epmask;
 	u8 nr_endpoints;
 
-	u8 board_mode;		/* enum musb_mode */
 	int			(*board_set_power)(int state);
 
 	u8			min_power;	/* vbus for periph, in mA/2 */
@@ -446,6 +437,10 @@
 #ifdef MUSB_CONFIG_PROC_FS
 	struct proc_dir_entry *proc_entry;
 #endif
+	int			xceiv_old_state;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry		*debugfs_root;
+#endif
 };
 
 static inline struct musb *gadget_to_musb(struct usb_gadget *g)
@@ -484,7 +479,7 @@
 static inline int musb_read_fifosize(struct musb *musb,
 		struct musb_hw_ep *hw_ep, u8 epnum)
 {
-	void *mbase = musb->mregs;
+	void __iomem *mbase = musb->mregs;
 	u8 reg = 0;
 
 	/* read from core using indexed model */
@@ -526,6 +521,8 @@
 
 extern void musb_start(struct musb *musb);
 extern void musb_stop(struct musb *musb);
+extern int musb_get_id(struct device *dev, gfp_t gfp_mask);
+extern void musb_put_id(struct device *dev, int id);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
 extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 40a37c9..1d6e8af 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -103,8 +103,6 @@
 	{  }	/* Terminating Entry */
 };
 
-static struct dentry *musb_debugfs_root;
-
 static int musb_regdump_show(struct seq_file *s, void *unused)
 {
 	struct musb		*musb = s->private;
@@ -241,7 +239,7 @@
 	struct dentry		*file;
 	int			ret;
 
-	root = debugfs_create_dir("musb", NULL);
+	root = debugfs_create_dir(dev_name(musb->controller), NULL);
 	if (!root) {
 		ret = -ENOMEM;
 		goto err0;
@@ -261,7 +259,7 @@
 		goto err1;
 	}
 
-	musb_debugfs_root = root;
+	musb->debugfs_root = root;
 
 	return 0;
 
@@ -274,5 +272,5 @@
 
 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
 {
-	debugfs_remove_recursive(musb_debugfs_root);
+	debugfs_remove_recursive(musb->debugfs_root);
 }
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 3a97c4e..24d3921 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -178,7 +178,7 @@
 extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
 
 
-extern struct dma_controller *__init
+extern struct dma_controller *__devinit
 dma_controller_create(struct musb *, void __iomem *);
 
 extern void dma_controller_destroy(struct dma_controller *);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 494772f..444346e1 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -31,11 +31,13 @@
 
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -45,6 +47,10 @@
 
 #include "musb_core.h"
 
+#ifdef CONFIG_OF
+static const struct of_device_id musb_dsps_of_match[];
+#endif
+
 /**
  * avoid using musb_readx()/musb_writex() as glue layer should not be
  * dependent on musb core layer symbols.
@@ -105,6 +111,8 @@
 	/* miscellaneous stuff */
 	u32		musb_core_offset;
 	u8		poll_seconds;
+	/* number of musb instances */
+	u8		instances;
 };
 
 /**
@@ -112,9 +120,10 @@
  */
 struct dsps_glue {
 	struct device *dev;
-	struct platform_device *musb;	/* child musb pdev */
+	struct platform_device *musb[2];	/* child musb pdev */
 	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
-	struct timer_list timer;	/* otg_workaround timer */
+	struct timer_list timer[2];	/* otg_workaround timer */
+	unsigned long last_timer[2];    /* last timer data for each instance */
 };
 
 /**
@@ -137,9 +146,8 @@
 	dsps_writel(reg_base, wrp->epintr_set, epmask);
 	dsps_writel(reg_base, wrp->coreintr_set, coremask);
 	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
-	if (is_otg_enabled(musb))
-		dsps_writel(reg_base, wrp->coreintr_set,
-			    (1 << wrp->drvvbus) << wrp->usb_shift);
+	dsps_writel(reg_base, wrp->coreintr_set,
+		    (1 << wrp->drvvbus) << wrp->usb_shift);
 }
 
 /**
@@ -165,8 +173,8 @@
 	struct musb *musb = (void *)_musb;
 	void __iomem *mregs = musb->mregs;
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
 	u8 devctl;
 	unsigned long flags;
@@ -200,12 +208,9 @@
 			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
 		break;
 	case OTG_STATE_B_IDLE:
-		if (!is_peripheral_enabled(musb))
-			break;
-
 		devctl = dsps_readb(mregs, MUSB_DEVCTL);
 		if (devctl & MUSB_DEVCTL_BDEVICE)
-			mod_timer(&glue->timer,
+			mod_timer(&glue->timer[pdev->id],
 					jiffies + wrp->poll_seconds * HZ);
 		else
 			musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -219,12 +224,8 @@
 static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
 {
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
-	static unsigned long last_timer;
-
-	if (!is_otg_enabled(musb))
-		return;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
 	if (timeout == 0)
 		timeout = jiffies + msecs_to_jiffies(3);
@@ -234,22 +235,23 @@
 				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
 		dev_dbg(musb->controller, "%s active, deleting timer\n",
 				otg_state_string(musb->xceiv->state));
-		del_timer(&glue->timer);
-		last_timer = jiffies;
+		del_timer(&glue->timer[pdev->id]);
+		glue->last_timer[pdev->id] = jiffies;
 		return;
 	}
 
-	if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
+	if (time_after(glue->last_timer[pdev->id], timeout) &&
+				timer_pending(&glue->timer[pdev->id])) {
 		dev_dbg(musb->controller,
 			"Longer idle timer already pending, ignoring...\n");
 		return;
 	}
-	last_timer = timeout;
+	glue->last_timer[pdev->id] = timeout;
 
 	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
 		otg_state_string(musb->xceiv->state),
 			jiffies_to_msecs(timeout - jiffies));
-	mod_timer(&glue->timer, timeout);
+	mod_timer(&glue->timer[pdev->id], timeout);
 }
 
 static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -257,8 +259,8 @@
 	struct musb  *musb = hci;
 	void __iomem *reg_base = musb->ctrl_base;
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
 	unsigned long flags;
 	irqreturn_t ret = IRQ_NONE;
@@ -293,7 +295,7 @@
 	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
 	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
 	 */
-	if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
+	if (usbintr & MUSB_INTR_BABBLE)
 		pr_info("CAUTION: musb: Babble Interrupt Occured\n");
 
 	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@@ -302,8 +304,7 @@
 		u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
 		int err;
 
-		err = is_host_enabled(musb) && (musb->int_usb &
-						MUSB_INTR_VBUSERROR);
+		err = musb->int_usb & MUSB_INTR_VBUSERROR;
 		if (err) {
 			/*
 			 * The Mentor core doesn't debounce VBUS as needed
@@ -318,15 +319,15 @@
 			 */
 			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
-			mod_timer(&glue->timer,
+			mod_timer(&glue->timer[pdev->id],
 					jiffies + wrp->poll_seconds * HZ);
 			WARNING("VBUS error workaround (delay coming)\n");
-		} else if (is_host_enabled(musb) && drvvbus) {
+		} else if (drvvbus) {
 			musb->is_active = 1;
 			MUSB_HST_MODE(musb);
 			musb->xceiv->otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
-			del_timer(&glue->timer);
+			del_timer(&glue->timer[pdev->id]);
 		} else {
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
@@ -352,8 +353,9 @@
 		dsps_writel(reg_base, wrp->eoi, 1);
 
 	/* Poll for ID change */
-	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
-		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+	if (musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&glue->timer[pdev->id],
+			 jiffies + wrp->poll_seconds * HZ);
 
 	spin_unlock_irqrestore(&musb->lock, flags);
 
@@ -364,8 +366,8 @@
 {
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
 	struct omap_musb_board_data *data = plat->board_data;
 	void __iomem *reg_base = musb->ctrl_base;
@@ -375,8 +377,7 @@
 	/* mentor core register starts at offset of 0x400 from musb base */
 	musb->mregs += wrp->musb_core_offset;
 
-	/* NOP driver needs change if supporting dual instance */
-	usb_nop_xceiv_register();
+	/* Get the NOP PHY */
 	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
 	if (IS_ERR_OR_NULL(musb->xceiv))
 		return -ENODEV;
@@ -388,8 +389,7 @@
 		goto err0;
 	}
 
-	if (is_host_enabled(musb))
-		setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+	setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
 
 	/* Reset the musb */
 	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
@@ -420,11 +420,10 @@
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
 	struct omap_musb_board_data *data = plat->board_data;
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
-	if (is_host_enabled(musb))
-		del_timer_sync(&glue->timer);
+	del_timer_sync(&glue->timer[pdev->id]);
 
 	/* Shutdown the on-chip PHY and its PLL. */
 	if (data->set_phy_power)
@@ -454,11 +453,13 @@
 	struct device *dev = glue->dev;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct musb_hdrc_platform_data  *pdata = dev->platform_data;
+	struct device_node *np = pdev->dev.of_node;
+	struct musb_hdrc_config	*config;
 	struct platform_device	*musb;
 	struct resource *res;
 	struct resource	resources[2];
 	char res_name[10];
-	int ret;
+	int ret, musbid;
 
 	/* get memory resource */
 	sprintf(res_name, "musb%d", id);
@@ -483,62 +484,107 @@
 	resources[1] = *res;
 	resources[1].name = "mc";
 
-	/* allocate the child platform device */
-	musb = platform_device_alloc("musb-hdrc", -1);
-	if (!musb) {
-		dev_err(dev, "failed to allocate musb device\n");
+	/* get the musb id */
+	musbid = musb_get_id(dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(dev, "failed to allocate musb id\n");
 		ret = -ENOMEM;
 		goto err0;
 	}
+	/* allocate the child platform device */
+	musb = platform_device_alloc("musb-hdrc", musbid);
+	if (!musb) {
+		dev_err(dev, "failed to allocate musb device\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
 
+	musb->id			= musbid;
 	musb->dev.parent		= dev;
 	musb->dev.dma_mask		= &musb_dmamask;
 	musb->dev.coherent_dma_mask	= musb_dmamask;
 
-	glue->musb			= musb;
-
-	pdata->platform_ops		= &dsps_ops;
+	glue->musb[id]			= musb;
 
 	ret = platform_device_add_resources(musb, resources, 2);
 	if (ret) {
 		dev_err(dev, "failed to add resources\n");
-		goto err1;
+		goto err2;
 	}
 
+	if (np) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&pdev->dev,
+				"failed to allocate musb platfrom data\n");
+			ret = -ENOMEM;
+			goto err2;
+		}
+
+		config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
+		if (!config) {
+			dev_err(&pdev->dev,
+				"failed to allocate musb hdrc config\n");
+			goto err2;
+		}
+
+		of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
+		sprintf(res_name, "port%d-mode", id);
+		of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
+		of_property_read_u32(np, "power", (u32 *)&pdata->power);
+		config->multipoint = of_property_read_bool(np, "multipoint");
+
+		pdata->config		= config;
+	}
+
+	pdata->platform_ops		= &dsps_ops;
+
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(dev, "failed to add platform_data\n");
-		goto err1;
+		goto err2;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(dev, "failed to register musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	return 0;
 
-err1:
+err2:
 	platform_device_put(musb);
+err1:
+	musb_put_id(dev, musbid);
 err0:
 	return ret;
 }
 
-static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
+static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id)
 {
-	platform_device_del(glue->musb);
-	platform_device_put(glue->musb);
+	musb_put_id(glue->dev, glue->musb[id]->id);
+	platform_device_del(glue->musb[id]);
+	platform_device_put(glue->musb[id]);
 }
 
 static int __devinit dsps_probe(struct platform_device *pdev)
 {
-	const struct platform_device_id *id = platform_get_device_id(pdev);
-	const struct dsps_musb_wrapper *wrp =
-				(struct dsps_musb_wrapper *)id->driver_data;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match;
+	const struct dsps_musb_wrapper *wrp;
 	struct dsps_glue *glue;
 	struct resource *iomem;
-	int ret;
+	int ret, i;
+
+	match = of_match_node(musb_dsps_of_match, np);
+	if (!match) {
+		dev_err(&pdev->dev, "fail to get matching of_match struct\n");
+		ret = -EINVAL;
+		goto err0;
+	}
+	wrp = match->data;
 
 	/* allocate glue */
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
@@ -575,11 +621,16 @@
 		goto err2;
 	}
 
-	/* create the child platform device for first instances of musb */
-	ret = dsps_create_musb_pdev(glue, 0);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "failed to create child pdev\n");
-		goto err3;
+	/* create the child platform device for all instances of musb */
+	for (i = 0; i < wrp->instances ; i++) {
+		ret = dsps_create_musb_pdev(glue, i);
+		if (ret != 0) {
+			dev_err(&pdev->dev, "failed to create child pdev\n");
+			/* release resources of previously created instances */
+			for (i--; i >= 0 ; i--)
+				dsps_delete_musb_pdev(glue, i);
+			goto err3;
+		}
 	}
 
 	return 0;
@@ -597,9 +648,12 @@
 static int __devexit dsps_remove(struct platform_device *pdev)
 {
 	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	int i;
 
 	/* delete the child platform device */
-	dsps_delete_musb_pdev(glue);
+	for (i = 0; i < wrp->instances ; i++)
+		dsps_delete_musb_pdev(glue, i);
 
 	/* disable usbss clocks */
 	pm_runtime_put(&pdev->dev);
@@ -665,6 +719,7 @@
 	.rxep_bitmap		= (0xfffe << 16),
 	.musb_core_offset	= 0x400,
 	.poll_seconds		= 2,
+	.instances		= 2,
 };
 
 static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
@@ -676,13 +731,14 @@
 };
 MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
 
+#ifdef CONFIG_OF
 static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
-	{ .compatible = "musb-ti81xx", },
-	{ .compatible = "ti,ti81xx-musb", },
-	{ .compatible = "ti,am335x-musb", },
+	{ .compatible = "ti,musb-am33xx",
+		.data = (void *) &ti81xx_driver_data, },
 	{  },
 };
 MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
+#endif
 
 static struct platform_driver dsps_usbss_driver = {
 	.probe		= dsps_probe,
@@ -690,7 +746,7 @@
 	.driver         = {
 		.name   = "musb-dsps",
 		.pm	= &dsps_pm_ops,
-		.of_match_table	= musb_dsps_of_match,
+		.of_match_table	= of_match_ptr(musb_dsps_of_match),
 	},
 	.id_table	= musb_dsps_id_table,
 };
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index f7194cf..d0b87e7 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -373,7 +373,7 @@
 		request_size = min_t(size_t, request->length - request->actual,
 					musb_ep->dma->max_len);
 
-		use_dma = (request->dma != DMA_ADDR_INVALID);
+		use_dma = (request->dma != DMA_ADDR_INVALID && request_size);
 
 		/* MUSB_TXCSR_P_ISO is still set correctly */
 
@@ -644,8 +644,8 @@
 	struct usb_request	*request = &req->request;
 	struct musb_ep		*musb_ep;
 	void __iomem		*epio = musb->endpoints[epnum].regs;
-	unsigned		fifo_count = 0;
-	u16			len;
+	unsigned		len = 0;
+	u16			fifo_count;
 	u16			csr = musb_readw(epio, MUSB_RXCSR);
 	struct musb_hw_ep	*hw_ep = &musb->endpoints[epnum];
 	u8			use_mode_1;
@@ -655,7 +655,7 @@
 	else
 		musb_ep = &hw_ep->ep_out;
 
-	len = musb_ep->packet_sz;
+	fifo_count = musb_ep->packet_sz;
 
 	/* Check if EP is disabled */
 	if (!musb_ep->desc) {
@@ -704,15 +704,14 @@
 	}
 
 	if (csr & MUSB_RXCSR_RXPKTRDY) {
-		len = musb_readw(epio, MUSB_RXCOUNT);
+		fifo_count = musb_readw(epio, MUSB_RXCOUNT);
 
 		/*
-		 * Enable Mode 1 on RX transfers only when short_not_ok flag
-		 * is set. Currently short_not_ok flag is set only from
-		 * file_storage and f_mass_storage drivers
+		 *  use mode 1 only if we expect data of at least ep packet_sz
+		 *  and have not yet received a short packet
 		 */
-
-		if (request->short_not_ok && len == musb_ep->packet_sz)
+		if ((request->length - request->actual >= musb_ep->packet_sz) &&
+			(fifo_count >= musb_ep->packet_sz))
 			use_mode_1 = 1;
 		else
 			use_mode_1 = 0;
@@ -723,31 +722,11 @@
 				struct dma_controller	*c;
 				struct dma_channel	*channel;
 				int			use_dma = 0;
+				int transfer_size;
 
 				c = musb->dma_controller;
 				channel = musb_ep->dma;
 
-	/* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
-	 * mode 0 only. So we do not get endpoint interrupts due to DMA
-	 * completion. We only get interrupts from DMA controller.
-	 *
-	 * We could operate in DMA mode 1 if we knew the size of the tranfer
-	 * in advance. For mass storage class, request->length = what the host
-	 * sends, so that'd work.  But for pretty much everything else,
-	 * request->length is routinely more than what the host sends. For
-	 * most these gadgets, end of is signified either by a short packet,
-	 * or filling the last byte of the buffer.  (Sending extra data in
-	 * that last pckate should trigger an overflow fault.)  But in mode 1,
-	 * we don't get DMA completion interrupt for short packets.
-	 *
-	 * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
-	 * to get endpoint interrupt on every DMA req, but that didn't seem
-	 * to work reliably.
-	 *
-	 * REVISIT an updated g_file_storage can set req->short_not_ok, which
-	 * then becomes usable as a runtime "use mode 1" hint...
-	 */
-
 				/* Experimental: Mode1 works with mass storage use cases */
 				if (use_mode_1) {
 					csr |= MUSB_RXCSR_AUTOCLEAR;
@@ -764,34 +743,29 @@
 						csr | MUSB_RXCSR_DMAMODE);
 					musb_writew(epio, MUSB_RXCSR, csr);
 
+					transfer_size = min(request->length - request->actual,
+							channel->max_len);
+					musb_ep->dma->desired_mode = 1;
+
 				} else {
 					if (!musb_ep->hb_mult &&
 						musb_ep->hw_ep->rx_double_buffered)
 						csr |= MUSB_RXCSR_AUTOCLEAR;
 					csr |= MUSB_RXCSR_DMAENAB;
 					musb_writew(epio, MUSB_RXCSR, csr);
+
+					transfer_size = min(request->length - request->actual,
+							(unsigned)fifo_count);
+					musb_ep->dma->desired_mode = 0;
 				}
 
-				if (request->actual < request->length) {
-					int transfer_size = 0;
-					if (use_mode_1) {
-						transfer_size = min(request->length - request->actual,
-								channel->max_len);
-						musb_ep->dma->desired_mode = 1;
-					} else {
-						transfer_size = min(request->length - request->actual,
-								(unsigned)len);
-						musb_ep->dma->desired_mode = 0;
-					}
-
-					use_dma = c->channel_program(
-							channel,
-							musb_ep->packet_sz,
-							channel->desired_mode,
-							request->dma
-							+ request->actual,
-							transfer_size);
-				}
+				use_dma = c->channel_program(
+						channel,
+						musb_ep->packet_sz,
+						channel->desired_mode,
+						request->dma
+						+ request->actual,
+						transfer_size);
 
 				if (use_dma)
 					return;
@@ -808,8 +782,8 @@
 				channel = musb_ep->dma;
 
 				/* In case first packet is short */
-				if (len < musb_ep->packet_sz)
-					transfer_size = len;
+				if (fifo_count < musb_ep->packet_sz)
+					transfer_size = fifo_count;
 				else if (request->short_not_ok)
 					transfer_size =	min(request->length -
 							request->actual,
@@ -817,7 +791,7 @@
 				else
 					transfer_size = min(request->length -
 							request->actual,
-							(unsigned)len);
+							(unsigned)fifo_count);
 
 				csr &= ~MUSB_RXCSR_DMAMODE;
 				csr |= (MUSB_RXCSR_DMAENAB |
@@ -845,10 +819,10 @@
 			}
 #endif	/* Mentor's DMA */
 
-			fifo_count = request->length - request->actual;
+			len = request->length - request->actual;
 			dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
 					musb_ep->end_point.name,
-					len, fifo_count,
+					fifo_count, len,
 					musb_ep->packet_sz);
 
 			fifo_count = min_t(unsigned, len, fifo_count);
@@ -901,7 +875,8 @@
 	}
 
 	/* reach the end or short packet detected */
-	if (request->actual == request->length || len < musb_ep->packet_sz)
+	if (request->actual == request->length ||
+	    fifo_count < musb_ep->packet_sz)
 		musb_g_giveback(musb_ep, request, 0);
 }
 
@@ -1885,8 +1860,7 @@
 	musb->g.dev.release = musb_gadget_release;
 	musb->g.name = musb_driver_name;
 
-	if (is_otg_enabled(musb))
-		musb->g.is_otg = 1;
+	musb->g.is_otg = 1;
 
 	musb_g_init_endpoints(musb);
 
@@ -1932,11 +1906,14 @@
 {
 	struct musb		*musb = gadget_to_musb(g);
 	struct usb_otg		*otg = musb->xceiv->otg;
+	struct usb_hcd		*hcd = musb_to_hcd(musb);
 	unsigned long		flags;
-	int			retval = -EINVAL;
+	int			retval = 0;
 
-	if (driver->max_speed < USB_SPEED_HIGH)
-		goto err0;
+	if (driver->max_speed < USB_SPEED_HIGH) {
+		retval = -EINVAL;
+		goto err;
+	}
 
 	pm_runtime_get_sync(musb->controller);
 
@@ -1950,49 +1927,30 @@
 
 	otg_set_peripheral(otg, &musb->g);
 	musb->xceiv->state = OTG_STATE_B_IDLE;
-
-	/*
-	 * FIXME this ignores the softconnect flag.  Drivers are
-	 * allowed hold the peripheral inactive until for example
-	 * userspace hooks up printer hardware or DSP codecs, so
-	 * hosts only see fully functional devices.
-	 */
-
-	if (!is_otg_enabled(musb))
-		musb_start(musb);
-
 	spin_unlock_irqrestore(&musb->lock, flags);
 
-	if (is_otg_enabled(musb)) {
-		struct usb_hcd	*hcd = musb_to_hcd(musb);
-
-		dev_dbg(musb->controller, "OTG startup...\n");
-
-		/* REVISIT:  funcall to other code, which also
-		 * handles power budgeting ... this way also
-		 * ensures HdrcStart is indirectly called.
-		 */
-		retval = usb_add_hcd(musb_to_hcd(musb), 0, 0);
-		if (retval < 0) {
-			dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
-			goto err2;
-		}
-
-		if ((musb->xceiv->last_event == USB_EVENT_ID)
-					&& otg->set_vbus)
-			otg_set_vbus(otg, 1);
-
-		hcd->self.uses_pio_for_control = 1;
+	/* REVISIT:  funcall to other code, which also
+	 * handles power budgeting ... this way also
+	 * ensures HdrcStart is indirectly called.
+	 */
+	retval = usb_add_hcd(hcd, 0, 0);
+	if (retval < 0) {
+		dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
+		goto err;
 	}
+
+	if ((musb->xceiv->last_event == USB_EVENT_ID)
+				&& otg->set_vbus)
+		otg_set_vbus(otg, 1);
+
+	hcd->self.uses_pio_for_control = 1;
+
 	if (musb->xceiv->last_event == USB_EVENT_NONE)
 		pm_runtime_put(musb->controller);
 
 	return 0;
 
-err2:
-	if (!is_otg_enabled(musb))
-		musb_stop(musb);
-err0:
+err:
 	return retval;
 }
 
@@ -2070,16 +2028,12 @@
 	musb_platform_try_idle(musb, 0);
 	spin_unlock_irqrestore(&musb->lock, flags);
 
-	if (is_otg_enabled(musb)) {
-		usb_remove_hcd(musb_to_hcd(musb));
-		/* FIXME we need to be able to register another
-		 * gadget driver here and have everything work;
-		 * that currently misbehaves.
-		 */
-	}
-
-	if (!is_otg_enabled(musb))
-		musb_stop(musb);
+	usb_remove_hcd(musb_to_hcd(musb));
+	/*
+	 * FIXME we need to be able to register another
+	 * gadget driver here and have everything work;
+	 * that currently misbehaves.
+	 */
 
 	pm_runtime_put(musb->controller);
 
@@ -2241,13 +2195,11 @@
 	if (devctl & MUSB_DEVCTL_BDEVICE) {
 		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
 		musb->g.is_a_peripheral = 0;
-	} else if (is_otg_enabled(musb)) {
+	} else {
 		musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
 		musb->g.is_a_peripheral = 1;
-	} else
-		WARN_ON(1);
+	}
 
 	/* start with default limits on VBUS power draw */
-	(void) musb_gadget_vbus_draw(&musb->g,
-			is_otg_enabled(musb) ? 8 : 100);
+	(void) musb_gadget_vbus_draw(&musb->g, 8);
 }
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 1ae378d5..3df6a76 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -693,6 +693,8 @@
 	void __iomem		*epio = hw_ep->regs;
 	struct musb_qh		*qh = musb_ep_get_qh(hw_ep, !is_out);
 	u16			packet_sz = qh->maxpacket;
+	u8			use_dma = 1;
+	u16			csr;
 
 	dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s "
 				"h_addr%02x h_port%02x bytes %d\n",
@@ -704,9 +706,17 @@
 
 	musb_ep_select(mbase, epnum);
 
+	if (is_out && !len) {
+		use_dma = 0;
+		csr = musb_readw(epio, MUSB_TXCSR);
+		csr &= ~MUSB_TXCSR_DMAENAB;
+		musb_writew(epio, MUSB_TXCSR, csr);
+		hw_ep->tx_channel = NULL;
+	}
+
 	/* candidate for DMA? */
 	dma_controller = musb->dma_controller;
-	if (is_dma_capable() && epnum && dma_controller) {
+	if (use_dma && is_dma_capable() && epnum && dma_controller) {
 		dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
 		if (!dma_channel) {
 			dma_channel = dma_controller->channel_alloc(
@@ -813,9 +823,28 @@
 		if (load_count) {
 			/* PIO to load FIFO */
 			qh->segsize = load_count;
-			musb_write_fifo(hw_ep, load_count, buf);
+			if (!buf) {
+				sg_miter_start(&qh->sg_miter, urb->sg, 1,
+						SG_MITER_ATOMIC
+						| SG_MITER_FROM_SG);
+				if (!sg_miter_next(&qh->sg_miter)) {
+					dev_err(musb->controller,
+							"error: sg"
+							"list empty\n");
+					sg_miter_stop(&qh->sg_miter);
+					goto finish;
+				}
+				buf = qh->sg_miter.addr + urb->sg->offset +
+					urb->actual_length;
+				load_count = min_t(u32, load_count,
+						qh->sg_miter.length);
+				musb_write_fifo(hw_ep, load_count, buf);
+				qh->sg_miter.consumed = load_count;
+				sg_miter_stop(&qh->sg_miter);
+			} else
+				musb_write_fifo(hw_ep, load_count, buf);
 		}
-
+finish:
 		/* re-enable interrupt */
 		musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -882,6 +911,73 @@
 	}
 }
 
+/* Schedule next QH from musb->in_bulk/out_bulk and move the current qh to
+ * the end; avoids starvation for other endpoints.
+ */
+static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep,
+	int is_in)
+{
+	struct dma_channel	*dma;
+	struct urb		*urb;
+	void __iomem		*mbase = musb->mregs;
+	void __iomem		*epio = ep->regs;
+	struct musb_qh		*cur_qh, *next_qh;
+	u16			rx_csr, tx_csr;
+
+	musb_ep_select(mbase, ep->epnum);
+	if (is_in) {
+		dma = is_dma_capable() ? ep->rx_channel : NULL;
+
+		/* clear nak timeout bit */
+		rx_csr = musb_readw(epio, MUSB_RXCSR);
+		rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+		rx_csr &= ~MUSB_RXCSR_DATAERROR;
+		musb_writew(epio, MUSB_RXCSR, rx_csr);
+
+		cur_qh = first_qh(&musb->in_bulk);
+	} else {
+		dma = is_dma_capable() ? ep->tx_channel : NULL;
+
+		/* clear nak timeout bit */
+		tx_csr = musb_readw(epio, MUSB_TXCSR);
+		tx_csr |= MUSB_TXCSR_H_WZC_BITS;
+		tx_csr &= ~MUSB_TXCSR_H_NAKTIMEOUT;
+		musb_writew(epio, MUSB_TXCSR, tx_csr);
+
+		cur_qh = first_qh(&musb->out_bulk);
+	}
+	if (cur_qh) {
+		urb = next_urb(cur_qh);
+		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+			musb->dma_controller->channel_abort(dma);
+			urb->actual_length += dma->actual_len;
+			dma->actual_len = 0L;
+		}
+		musb_save_toggle(cur_qh, is_in, urb);
+
+		if (is_in) {
+			/* move cur_qh to end of queue */
+			list_move_tail(&cur_qh->ring, &musb->in_bulk);
+
+			/* get the next qh from musb->in_bulk */
+			next_qh = first_qh(&musb->in_bulk);
+
+			/* set rx_reinit and schedule the next qh */
+			ep->rx_reinit = 1;
+		} else {
+			/* move cur_qh to end of queue */
+			list_move_tail(&cur_qh->ring, &musb->out_bulk);
+
+			/* get the next qh from musb->out_bulk */
+			next_qh = first_qh(&musb->out_bulk);
+
+			/* set tx_reinit and schedule the next qh */
+			ep->tx_reinit = 1;
+		}
+		musb_start_urb(musb, is_in, next_qh);
+	}
+}
 
 /*
  * Service the default endpoint (ep0) as host.
@@ -1116,6 +1212,7 @@
 	void __iomem		*mbase = musb->mregs;
 	struct dma_channel	*dma;
 	bool			transfer_pending = false;
+	static bool use_sg;
 
 	musb_ep_select(mbase, epnum);
 	tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1146,23 +1243,31 @@
 		status = -ETIMEDOUT;
 
 	} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
-		dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum);
-
-		/* NOTE:  this code path would be a good place to PAUSE a
-		 * transfer, if there's some other (nonperiodic) tx urb
-		 * that could use this fifo.  (dma complicates it...)
-		 * That's already done for bulk RX transfers.
-		 *
-		 * if (bulk && qh->ring.next != &musb->out_bulk), then
-		 * we have a candidate... NAKing is *NOT* an error
-		 */
-		musb_ep_select(mbase, epnum);
-		musb_writew(epio, MUSB_TXCSR,
-				MUSB_TXCSR_H_WZC_BITS
-				| MUSB_TXCSR_TXPKTRDY);
-		return;
+		if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1
+				&& !list_is_singular(&musb->out_bulk)) {
+			dev_dbg(musb->controller,
+				"NAK timeout on TX%d ep\n", epnum);
+			musb_bulk_nak_timeout(musb, hw_ep, 0);
+		} else {
+			dev_dbg(musb->controller,
+				"TX end=%d device not responding\n", epnum);
+			/* NOTE:  this code path would be a good place to PAUSE a
+			 * transfer, if there's some other (nonperiodic) tx urb
+			 * that could use this fifo.  (dma complicates it...)
+			 * That's already done for bulk RX transfers.
+			 *
+			 * if (bulk && qh->ring.next != &musb->out_bulk), then
+			 * we have a candidate... NAKing is *NOT* an error
+			 */
+			musb_ep_select(mbase, epnum);
+			musb_writew(epio, MUSB_TXCSR,
+					MUSB_TXCSR_H_WZC_BITS
+					| MUSB_TXCSR_TXPKTRDY);
+		}
+			return;
 	}
 
+done:
 	if (status) {
 		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
 			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1437,38 @@
 		length = qh->maxpacket;
 	/* Unmap the buffer so that CPU can use it */
 	usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-	musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+
+	/*
+	 * We need to map sg if the transfer_buffer is
+	 * NULL.
+	 */
+	if (!urb->transfer_buffer)
+		use_sg = true;
+
+	if (use_sg) {
+		/* sg_miter_start is already done in musb_ep_program */
+		if (!sg_miter_next(&qh->sg_miter)) {
+			dev_err(musb->controller, "error: sg list empty\n");
+			sg_miter_stop(&qh->sg_miter);
+			status = -EINVAL;
+			goto done;
+		}
+		urb->transfer_buffer = qh->sg_miter.addr;
+		length = min_t(u32, length, qh->sg_miter.length);
+		musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+		qh->sg_miter.consumed = length;
+		sg_miter_stop(&qh->sg_miter);
+	} else {
+		musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+	}
+
 	qh->segsize = length;
 
+	if (use_sg) {
+		if (offset + length >= urb->transfer_buffer_length)
+			use_sg = false;
+	}
+
 	musb_ep_select(mbase, epnum);
 	musb_writew(epio, MUSB_TXCSR,
 			MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1380,50 +1514,6 @@
 
 #endif
 
-/* Schedule next QH from musb->in_bulk and move the current qh to
- * the end; avoids starvation for other endpoints.
- */
-static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
-{
-	struct dma_channel	*dma;
-	struct urb		*urb;
-	void __iomem		*mbase = musb->mregs;
-	void __iomem		*epio = ep->regs;
-	struct musb_qh		*cur_qh, *next_qh;
-	u16			rx_csr;
-
-	musb_ep_select(mbase, ep->epnum);
-	dma = is_dma_capable() ? ep->rx_channel : NULL;
-
-	/* clear nak timeout bit */
-	rx_csr = musb_readw(epio, MUSB_RXCSR);
-	rx_csr |= MUSB_RXCSR_H_WZC_BITS;
-	rx_csr &= ~MUSB_RXCSR_DATAERROR;
-	musb_writew(epio, MUSB_RXCSR, rx_csr);
-
-	cur_qh = first_qh(&musb->in_bulk);
-	if (cur_qh) {
-		urb = next_urb(cur_qh);
-		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
-			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
-			musb->dma_controller->channel_abort(dma);
-			urb->actual_length += dma->actual_len;
-			dma->actual_len = 0L;
-		}
-		musb_save_toggle(cur_qh, 1, urb);
-
-		/* move cur_qh to end of queue */
-		list_move_tail(&cur_qh->ring, &musb->in_bulk);
-
-		/* get the next qh from musb->in_bulk */
-		next_qh = first_qh(&musb->in_bulk);
-
-		/* set rx_reinit and schedule the next qh */
-		ep->rx_reinit = 1;
-		musb_start_urb(musb, 1, next_qh);
-	}
-}
-
 /*
  * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
  * and high-bandwidth IN transfer cases.
@@ -1442,6 +1532,8 @@
 	bool			done = false;
 	u32			status;
 	struct dma_channel	*dma;
+	static bool use_sg;
+	unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
 	musb_ep_select(mbase, epnum);
 
@@ -1500,7 +1592,7 @@
 			if (usb_pipebulk(urb->pipe)
 					&& qh->mux == 1
 					&& !list_is_singular(&musb->in_bulk)) {
-				musb_bulk_rx_nak_timeout(musb, hw_ep);
+				musb_bulk_nak_timeout(musb, hw_ep, 1);
 				return;
 			}
 			musb_ep_select(mbase, epnum);
@@ -1756,10 +1848,43 @@
 #endif	/* Mentor DMA */
 
 		if (!dma) {
+			unsigned int received_len;
+
 			/* Unmap the buffer so that CPU can use it */
 			usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-			done = musb_host_packet_rx(musb, urb,
-					epnum, iso_err);
+
+			/*
+			 * We need to map sg if the transfer_buffer is
+			 * NULL.
+			 */
+			if (!urb->transfer_buffer) {
+				use_sg = true;
+				sg_miter_start(&qh->sg_miter, urb->sg, 1,
+						sg_flags);
+			}
+
+			if (use_sg) {
+				if (!sg_miter_next(&qh->sg_miter)) {
+					dev_err(musb->controller, "error: sg list empty\n");
+					sg_miter_stop(&qh->sg_miter);
+					status = -EINVAL;
+					done = true;
+					goto finish;
+				}
+				urb->transfer_buffer = qh->sg_miter.addr;
+				received_len = urb->actual_length;
+				qh->offset = 0x0;
+				done = musb_host_packet_rx(musb, urb, epnum,
+						iso_err);
+				/* Calculate the number of bytes received */
+				received_len = urb->actual_length -
+					received_len;
+				qh->sg_miter.consumed = received_len;
+				sg_miter_stop(&qh->sg_miter);
+			} else {
+				done = musb_host_packet_rx(musb, urb,
+						epnum, iso_err);
+			}
 			dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");
 		}
 	}
@@ -1768,6 +1893,9 @@
 	urb->actual_length += xfer_len;
 	qh->offset += xfer_len;
 	if (done) {
+		if (use_sg)
+			use_sg = false;
+
 		if (urb->status == -EINPROGRESS)
 			urb->status = status;
 		musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
@@ -1863,14 +1991,14 @@
 		else
 			head = &musb->out_bulk;
 
-		/* Enable bulk RX NAK timeout scheme when bulk requests are
+		/* Enable bulk RX/TX NAK timeout scheme when bulk requests are
 		 * multiplexed.  This scheme doen't work in high speed to full
 		 * speed scenario as NAK interrupts are not coming from a
 		 * full speed device connected to a high speed device.
 		 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
 		 * 4 (8 frame or 8ms) for FS device.
 		 */
-		if (is_in && qh->dev)
+		if (qh->dev)
 			qh->intv_reg =
 				(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
 		goto success;
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
index 622d09f..5a9c8fe 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -35,6 +35,8 @@
 #ifndef _MUSB_HOST_H
 #define _MUSB_HOST_H
 
+#include <linux/scatterlist.h>
+
 static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
 {
 	return container_of((void *) musb, struct usb_hcd, hcd_priv);
@@ -71,6 +73,7 @@
 	u16			maxpacket;
 	u16			frame;		/* for periodic schedule */
 	unsigned		iso_idx;	/* in urb->iso_frame_desc[] */
+	struct sg_mapping_iter sg_miter;	/* for highmem in PIO mode */
 };
 
 /* map from control or bulk queue head to the first qh on that ring */
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index 22ec3e3..f705791 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -81,8 +81,7 @@
 		switch (musb->xceiv->state) {
 		case OTG_STATE_A_HOST:
 			musb->xceiv->state = OTG_STATE_A_SUSPEND;
-			musb->is_active = is_otg_enabled(musb)
-					&& otg->host->b_hnp_enable;
+			musb->is_active = otg->host->b_hnp_enable;
 			if (musb->is_active)
 				mod_timer(&musb->otg_timer, jiffies
 					+ msecs_to_jiffies(
@@ -91,8 +90,7 @@
 			break;
 		case OTG_STATE_B_HOST:
 			musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
-			musb->is_active = is_otg_enabled(musb)
-					&& otg->host->b_hnp_enable;
+			musb->is_active = otg->host->b_hnp_enable;
 			musb_platform_try_idle(musb, 0);
 			break;
 		default:
@@ -190,8 +188,7 @@
 
 	switch (musb->xceiv->state) {
 	case OTG_STATE_A_SUSPEND:
-		if (is_otg_enabled(musb)
-				&& otg->host->b_hnp_enable) {
+		if (otg->host->b_hnp_enable) {
 			musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
 			musb->g.is_a_peripheral = 1;
 			break;
@@ -273,7 +270,7 @@
 			musb_port_suspend(musb, false);
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+			if (!hcd->self.is_b_host)
 				musb_platform_set_vbus(musb, 0);
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
@@ -369,7 +366,7 @@
 			 * initialization logic, e.g. for OTG, or change any
 			 * logic relating to VBUS power-up.
 			 */
-			if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+			if (!hcd->self.is_b_host)
 				musb_start(musb);
 			break;
 		case USB_PORT_FEAT_RESET:
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index c1be687..0fc6ca6 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -380,7 +380,7 @@
 	kfree(controller);
 }
 
-struct dma_controller *__init
+struct dma_controller *__devinit
 dma_controller_create(struct musb *musb, void __iomem *base)
 {
 	struct musb_dma_controller *controller;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 5fdb9da..a538fe1 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -30,10 +30,12 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/err.h>
+#include <linux/delay.h>
 #include <linux/usb/musb-omap.h>
 
 #include "musb_core.h"
@@ -44,6 +46,7 @@
 	struct platform_device	*musb;
 	enum omap_musb_vbus_id_status status;
 	struct work_struct	omap_musb_mailbox_work;
+	u32 __iomem		*control_otghs;
 };
 #define glue_to_musb(g)		platform_get_drvdata(g->musb)
 
@@ -51,6 +54,26 @@
 
 static struct timer_list musb_idle_timer;
 
+/**
+ * omap4_usb_phy_mailbox - write to usb otg mailbox
+ * @glue: struct omap2430_glue *
+ * @val: the value to be written to the mailbox
+ *
+ * On detection of a device (ID pin is grounded), this API should be called
+ * to set AVALID, VBUSVALID and ID pin is grounded.
+ *
+ * When OMAP is connected to a host (OMAP in device mode), this API
+ * is called to set AVALID, VBUSVALID and ID pin in high impedance.
+ *
+ * XXX: This function will be removed once we have a seperate driver for
+ * control module
+ */
+static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val)
+{
+	if (glue->control_otghs)
+		writel(val, glue->control_otghs);
+}
+
 static void musb_do_idle(unsigned long _musb)
 {
 	struct musb	*musb = (void *)_musb;
@@ -140,7 +163,6 @@
 	struct usb_otg	*otg = musb->xceiv->otg;
 	u8		devctl;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-	int ret = 1;
 	/* HDRC controls CPEN, but beware current surges during device
 	 * connect.  They can trigger transient overcurrent conditions
 	 * that must be ignored.
@@ -150,6 +172,7 @@
 
 	if (is_on) {
 		if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+			int loops = 100;
 			/* start the session */
 			devctl |= MUSB_DEVCTL_SESSION;
 			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
@@ -159,17 +182,18 @@
 			 */
 			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
 
+				mdelay(5);
 				cpu_relax();
 
-				if (time_after(jiffies, timeout)) {
+				if (time_after(jiffies, timeout)
+				    || loops-- <= 0) {
 					dev_err(musb->controller,
 					"configured as A device timeout");
-					ret = -EINVAL;
 					break;
 				}
 			}
 
-			if (ret && otg->set_vbus)
+			if (otg->set_vbus)
 				otg_set_vbus(otg, 1);
 		} else {
 			musb->is_active = 1;
@@ -245,6 +269,7 @@
 
 static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 {
+	u32 val;
 	struct musb *musb = glue_to_musb(glue);
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *pdata = dev->platform_data;
@@ -258,9 +283,10 @@
 		otg->default_a = true;
 		musb->xceiv->state = OTG_STATE_A_IDLE;
 		musb->xceiv->last_event = USB_EVENT_ID;
-		if (!is_otg_enabled(musb) || musb->gadget_driver) {
+		if (musb->gadget_driver) {
 			pm_runtime_get_sync(dev);
-			usb_phy_init(musb->xceiv);
+			val = AVALID | VBUSVALID;
+			omap4_usb_phy_mailbox(glue, val);
 			omap2430_musb_set_vbus(musb, 1);
 		}
 		break;
@@ -273,7 +299,8 @@
 		musb->xceiv->last_event = USB_EVENT_VBUS;
 		if (musb->gadget_driver)
 			pm_runtime_get_sync(dev);
-		usb_phy_init(musb->xceiv);
+		val = IDDIG | AVALID | VBUSVALID;
+		omap4_usb_phy_mailbox(glue, val);
 		break;
 
 	case OMAP_MUSB_ID_FLOAT:
@@ -281,17 +308,17 @@
 		dev_dbg(dev, "VBUS Disconnect\n");
 
 		musb->xceiv->last_event = USB_EVENT_NONE;
-		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
-			if (musb->gadget_driver) {
-				pm_runtime_mark_last_busy(dev);
-				pm_runtime_put_autosuspend(dev);
-			}
+		if (musb->gadget_driver) {
+			pm_runtime_mark_last_busy(dev);
+			pm_runtime_put_autosuspend(dev);
+		}
 
 		if (data->interface_type == MUSB_INTERFACE_UTMI) {
 			if (musb->xceiv->otg->set_vbus)
 				otg_set_vbus(musb->xceiv->otg, 0);
 		}
-		usb_phy_shutdown(musb->xceiv);
+		val = SESSEND | IDDIG;
+		omap4_usb_phy_mailbox(glue, val);
 		break;
 	default:
 		dev_dbg(dev, "ID float\n");
@@ -366,6 +393,7 @@
 static void omap2430_musb_enable(struct musb *musb)
 {
 	u8		devctl;
+	u32		val;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
@@ -375,7 +403,8 @@
 	switch (glue->status) {
 
 	case OMAP_MUSB_ID_GROUND:
-		usb_phy_init(musb->xceiv);
+		val = AVALID | VBUSVALID;
+		omap4_usb_phy_mailbox(glue, val);
 		if (data->interface_type != MUSB_INTERFACE_UTMI)
 			break;
 		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -394,7 +423,8 @@
 		break;
 
 	case OMAP_MUSB_VBUS_VALID:
-		usb_phy_init(musb->xceiv);
+		val = IDDIG | AVALID | VBUSVALID;
+		omap4_usb_phy_mailbox(glue, val);
 		break;
 
 	default:
@@ -404,11 +434,14 @@
 
 static void omap2430_musb_disable(struct musb *musb)
 {
+	u32 val;
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 
-	if (glue->status != OMAP_MUSB_UNKNOWN)
-		usb_phy_shutdown(musb->xceiv);
+	if (glue->status != OMAP_MUSB_UNKNOWN) {
+		val = SESSEND | IDDIG;
+		omap4_usb_phy_mailbox(glue, val);
+	}
 }
 
 static int omap2430_musb_exit(struct musb *musb)
@@ -438,9 +471,14 @@
 static int __devinit omap2430_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct omap_musb_board_data	*data;
 	struct platform_device		*musb;
 	struct omap2430_glue		*glue;
+	struct device_node		*np = pdev->dev.of_node;
+	struct musb_hdrc_config		*config;
+	struct resource			*res;
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -448,12 +486,21 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
-	if (!musb) {
-		dev_err(&pdev->dev, "failed to allocate musb device\n");
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
 		goto err0;
 	}
 
+	musb = platform_device_alloc("musb-hdrc", musbid);
+	if (!musb) {
+		dev_err(&pdev->dev, "failed to allocate musb device\n");
+		goto err1;
+	}
+
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &omap2430_dmamask;
 	musb->dev.coherent_dma_mask	= omap2430_dmamask;
@@ -462,6 +509,48 @@
 	glue->musb			= musb;
 	glue->status			= OMAP_MUSB_UNKNOWN;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+	glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res);
+	if (glue->control_otghs == NULL)
+		dev_dbg(&pdev->dev, "Failed to obtain control memory\n");
+
+	if (np) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&pdev->dev,
+				"failed to allocate musb platfrom data\n");
+			ret = -ENOMEM;
+			goto err1;
+		}
+
+		data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+		if (!data) {
+			dev_err(&pdev->dev,
+					"failed to allocate musb board data\n");
+			ret = -ENOMEM;
+			goto err1;
+		}
+
+		config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
+		if (!data) {
+			dev_err(&pdev->dev,
+				"failed to allocate musb hdrc config\n");
+			goto err1;
+		}
+
+		of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
+		of_property_read_u32(np, "interface_type",
+						(u32 *)&data->interface_type);
+		of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps);
+		of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
+		of_property_read_u32(np, "power", (u32 *)&pdata->power);
+		config->multipoint = of_property_read_bool(np, "multipoint");
+
+		pdata->board_data	= data;
+		pdata->config		= config;
+	}
+
 	pdata->platform_ops		= &omap2430_ops;
 
 	platform_set_drvdata(pdev, glue);
@@ -478,13 +567,13 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err1;
+		goto err2;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err1;
+		goto err2;
 	}
 
 	pm_runtime_enable(&pdev->dev);
@@ -492,14 +581,17 @@
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	return 0;
 
-err1:
+err2:
 	platform_device_put(musb);
 
+err1:
+	musb_put_id(&pdev->dev, musbid);
+
 err0:
 	return ret;
 }
@@ -509,8 +601,8 @@
 	struct omap2430_glue		*glue = platform_get_drvdata(pdev);
 
 	cancel_work_sync(&glue->omap_musb_mailbox_work);
-	platform_device_del(glue->musb);
-	platform_device_put(glue->musb);
+	musb_put_id(&pdev->dev, glue->musb->id);
+	platform_device_unregister(glue->musb);
 
 	return 0;
 }
@@ -559,12 +651,26 @@
 #define DEV_PM_OPS	NULL
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id omap2430_id_table[] = {
+	{
+		.compatible = "ti,omap4-musb"
+	},
+	{
+		.compatible = "ti,omap3-musb"
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap2430_id_table);
+#endif
+
 static struct platform_driver omap2430_driver = {
 	.probe		= omap2430_probe,
 	.remove		= __devexit_p(omap2430_remove),
 	.driver		= {
 		.name	= "musb-omap2430",
 		.pm	= DEV_PM_OPS,
+		.of_match_table = of_match_ptr(omap2430_id_table),
 	},
 };
 
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index 40b3c02..b85f397 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -49,4 +49,13 @@
 #define OTG_FORCESTDBY		0x414
 #	define	ENABLEFORCE		(1 << 0)
 
+/*
+ * Control Module bit definitions
+ * XXX: Will be removed once we have a driver for control module.
+ */
+#define	AVALID				BIT(0)
+#define	BVALID				BIT(1)
+#define	VBUSVALID			BIT(2)
+#define	SESSEND				BIT(3)
+#define	IDDIG				BIT(4)
 #endif	/* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 3416254..dc4d75e 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -24,6 +24,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include "musb_core.h"
 
@@ -153,7 +154,7 @@
 }
 
 static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
-						void __iomem *buf, u16 len)
+						void *buf, u16 len)
 {
 	u32		val;
 	int		i;
@@ -437,14 +438,13 @@
 		if (is_host_active(musb) && (musb->port1_status >> 16))
 			goto done;
 
-		if (is_peripheral_enabled(musb) && !musb->gadget_driver) {
+		if (!musb->gadget_driver) {
 			wakeups = 0;
 		} else {
 			wakeups = TUSB_PRCM_WHOSTDISCON
 				| TUSB_PRCM_WBUS
 					| TUSB_PRCM_WVBUS;
-			if (is_otg_enabled(musb))
-				wakeups |= TUSB_PRCM_WID;
+			wakeups |= TUSB_PRCM_WID;
 		}
 		tusb_allow_idle(musb, wakeups);
 	}
@@ -582,21 +582,12 @@
  *
  * Note that if a mini-A cable is plugged in the ID line will stay down as
  * the weak ID pull-up is not able to pull the ID up.
- *
- * REVISIT: It would be possible to add support for changing between host
- * and peripheral modes in non-OTG configurations by reconfiguring hardware
- * and then setting musb->board_mode. For now, only support OTG mode.
  */
 static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)
 {
 	void __iomem	*tbase = musb->ctrl_base;
 	u32		otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
 
-	if (musb->board_mode != MUSB_OTG) {
-		ERR("Changing mode currently only supported in OTG mode\n");
-		return -EINVAL;
-	}
-
 	otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
 	phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
 	phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
@@ -652,10 +643,7 @@
 	if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
 		int	default_a;
 
-		if (is_otg_enabled(musb))
-			default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
-		else
-			default_a = is_host_enabled(musb);
+		default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
 		dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B');
 		otg->default_a = default_a;
 		tusb_musb_set_vbus(musb, default_a);
@@ -669,8 +657,7 @@
 	if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
 
 		/* B-dev state machine:  no vbus ~= disconnect */
-		if ((is_otg_enabled(musb) && !otg->default_a)
-				|| !is_host_enabled(musb)) {
+		if (!otg->default_a) {
 			/* ? musb_root_disconnect(musb); */
 			musb->port1_status &=
 				~(USB_PORT_STAT_CONNECTION
@@ -1119,10 +1106,8 @@
 	}
 	musb->isr = tusb_musb_interrupt;
 
-	if (is_peripheral_enabled(musb)) {
-		musb->xceiv->set_power = tusb_draw_power;
-		the_musb = musb;
-	}
+	musb->xceiv->set_power = tusb_draw_power;
+	the_musb = musb;
 
 	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
@@ -1175,6 +1160,7 @@
 	struct tusb6010_glue		*glue;
 
 	int				ret = -ENOMEM;
+	int				musbid;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
@@ -1182,12 +1168,21 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
-	if (!musb) {
-		dev_err(&pdev->dev, "failed to allocate musb device\n");
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
 		goto err1;
 	}
 
+	musb = platform_device_alloc("musb-hdrc", musbid);
+	if (!musb) {
+		dev_err(&pdev->dev, "failed to allocate musb device\n");
+		goto err2;
+	}
+
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= &tusb_dmamask;
 	musb->dev.coherent_dma_mask	= tusb_dmamask;
@@ -1203,26 +1198,29 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err2;
+		goto err3;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err2;
+		goto err3;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err2;
+		goto err3;
 	}
 
 	return 0;
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -1234,6 +1232,7 @@
 {
 	struct tusb6010_glue		*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	kfree(glue);
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index b67b4bc..7a62b95 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -17,7 +17,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <plat/dma.h>
-#include <plat/mux.h>
 
 #include "musb_core.h"
 #include "tusb6010.h"
@@ -662,7 +661,7 @@
 	kfree(tusb_dma);
 }
 
-struct dma_controller *__init
+struct dma_controller *__devinit
 dma_controller_create(struct musb *musb, void __iomem *base)
 {
 	void __iomem		*tbase = musb->ctrl_base;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index a8c0fad..d62a91f 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -74,25 +74,34 @@
 		goto err0;
 	}
 
-	musb = platform_device_alloc("musb-hdrc", -1);
+	/* get the musb id */
+	musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
+	if (musbid < 0) {
+		dev_err(&pdev->dev, "failed to allocate musb id\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	musb = platform_device_alloc("musb-hdrc", musbid);
 	if (!musb) {
 		dev_err(&pdev->dev, "failed to allocate musb device\n");
-		goto err1;
+		goto err2;
 	}
 
 	clk = clk_get(&pdev->dev, "usb");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		ret = PTR_ERR(clk);
-		goto err2;
+		goto err3;
 	}
 
 	ret = clk_enable(clk);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to enable clock\n");
-		goto err3;
+		goto err4;
 	}
 
+	musb->id			= musbid;
 	musb->dev.parent		= &pdev->dev;
 	musb->dev.dma_mask		= pdev->dev.dma_mask;
 	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask;
@@ -109,32 +118,35 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err4;
+		goto err5;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err4;
+		goto err5;
 	}
 
 	return 0;
 
-err4:
+err5:
 	clk_disable(clk);
 
-err3:
+err4:
 	clk_put(clk);
 
-err2:
+err3:
 	platform_device_put(musb);
 
+err2:
+	musb_put_id(&pdev->dev, musbid);
+
 err1:
 	kfree(glue);
 
@@ -146,6 +158,7 @@
 {
 	struct ux500_glue	*glue = platform_get_drvdata(pdev);
 
+	musb_put_id(&pdev->dev, glue->musb->id);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	clk_disable(glue->clk);
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index d05c7fb..639d58e 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -364,7 +364,7 @@
 	kfree(controller);
 }
 
-struct dma_controller *__init
+struct dma_controller *__devinit
 dma_controller_create(struct musb *musb, void __iomem *base)
 {
 	struct ux500_dma_controller *controller;
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 13fd1ddf..d8c8a42 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -68,7 +68,7 @@
 
 config TWL6030_USB
 	tristate "TWL6030 USB Transceiver Driver"
-	depends on TWL4030_CORE
+	depends on TWL4030_CORE && OMAP_USB2
 	select USB_OTG_UTILS
 	help
 	  Enable this to support the USB OTG transceiver on TWL6030
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 23c798c..c19d1d7 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -544,9 +544,13 @@
  */
 static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	struct fsl_otg *otg_dev;
 
-	if (!otg || otg_dev != fsl_otg_dev)
+	if (!otg)
+		return -ENODEV;
+
+	otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	otg->host = host;
@@ -590,12 +594,15 @@
 static int fsl_otg_set_peripheral(struct usb_otg *otg,
 					struct usb_gadget *gadget)
 {
-	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	struct fsl_otg *otg_dev;
 
+	if (!otg)
+		return -ENODEV;
+
+	otg_dev = container_of(otg->phy, struct fsl_otg, phy);
 	VDBG("otg_dev 0x%x\n", (int)otg_dev);
 	VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
-
-	if (!otg || otg_dev != fsl_otg_dev)
+	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	if (!gadget) {
@@ -660,10 +667,13 @@
 /* B-device start SRP */
 static int fsl_otg_start_srp(struct usb_otg *otg)
 {
-	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	struct fsl_otg *otg_dev;
 
-	if (!otg || otg_dev != fsl_otg_dev
-	    || otg->phy->state != OTG_STATE_B_IDLE)
+	if (!otg || otg->phy->state != OTG_STATE_B_IDLE)
+		return -ENODEV;
+
+	otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	otg_dev->fsm.b_bus_req = 1;
@@ -675,9 +685,13 @@
 /* A_host suspend will call this function to start hnp */
 static int fsl_otg_start_hnp(struct usb_otg *otg)
 {
-	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	struct fsl_otg *otg_dev;
 
-	if (!otg || otg_dev != fsl_otg_dev)
+	if (!otg)
+		return -ENODEV;
+
+	otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
 	DBG("start_hnp...n");
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 7a88667..81f1f9a 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -36,7 +36,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #include <mach/usb.h>
 
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c
index c1a67cb..88db976 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/otg/mxs-phy.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/workqueue.h>
 
 #define DRIVER_NAME "mxs_phy"
 
@@ -34,9 +35,16 @@
 #define BM_USBPHY_CTRL_ENUTMILEVEL2		BIT(14)
 #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT	BIT(1)
 
+/*
+ * Amount of delay in miliseconds to safely enable ENHOSTDISCONDETECT bit
+ * so that connection and reset processing can be completed for the root hub.
+ */
+#define MXY_PHY_ENHOSTDISCONDETECT_DELAY	250
+
 struct mxs_phy {
 	struct usb_phy phy;
 	struct clk *clk;
+	struct delayed_work enhostdiscondetect_work;
 };
 
 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
@@ -62,6 +70,7 @@
 
 	clk_prepare_enable(mxs_phy->clk);
 	mxs_phy_hw_init(mxs_phy);
+	INIT_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, NULL);
 
 	return 0;
 }
@@ -76,13 +85,34 @@
 	clk_disable_unprepare(mxs_phy->clk);
 }
 
+static void mxs_phy_enhostdiscondetect_delay(struct work_struct *ws)
+{
+	struct mxs_phy *mxs_phy = container_of(ws, struct mxs_phy,
+						enhostdiscondetect_work.work);
+
+	/* Enable HOSTDISCONDETECT after delay. */
+	dev_dbg(mxs_phy->phy.dev, "Setting ENHOSTDISCONDETECT\n");
+	writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+				mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET);
+}
+
 static int mxs_phy_on_connect(struct usb_phy *phy, int port)
 {
+	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
 	dev_dbg(phy->dev, "Connect on port %d\n", port);
 
-	mxs_phy_hw_init(to_mxs_phy(phy));
-	writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-			phy->io_priv + HW_USBPHY_CTRL_SET);
+	mxs_phy_hw_init(mxs_phy);
+
+	/*
+	 * Delay enabling ENHOSTDISCONDETECT so that connection and
+	 * reset processing can be completed for the root hub.
+	 */
+	dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n");
+	PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work,
+			mxs_phy_enhostdiscondetect_delay);
+	schedule_delayed_work(&mxs_phy->enhostdiscondetect_work,
+			msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY));
 
 	return 0;
 }
@@ -91,6 +121,8 @@
 {
 	dev_dbg(phy->dev, "Disconnect on port %d\n", port);
 
+	/* No need to delay before clearing ENHOSTDISCONDETECT. */
+	dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n");
 	writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
 			phy->io_priv + HW_USBPHY_CTRL_CLR);
 
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index 803f958..e52e35e 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -30,6 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 #include <linux/slab.h>
 
 struct nop_usb_xceiv {
@@ -94,7 +95,9 @@
 
 static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
 {
+	struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
 	struct nop_usb_xceiv	*nop;
+	enum usb_phy_type	type = USB_PHY_TYPE_USB2;
 	int err;
 
 	nop = kzalloc(sizeof *nop, GFP_KERNEL);
@@ -107,6 +110,9 @@
 		return -ENOMEM;
 	}
 
+	if (pdata)
+		type = pdata->type;
+
 	nop->dev		= &pdev->dev;
 	nop->phy.dev		= nop->dev;
 	nop->phy.label		= "nop-xceiv";
@@ -117,7 +123,7 @@
 	nop->phy.otg->set_host		= nop_set_host;
 	nop->phy.otg->set_peripheral	= nop_set_peripheral;
 
-	err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2);
+	err = usb_add_phy(&nop->phy, type);
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 1bf60a2..a30c041 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -159,7 +159,7 @@
 	unsigned long	flags;
 	struct usb_phy	*phy;
 
-	if (x && x->type != USB_PHY_TYPE_UNDEFINED) {
+	if (x->type != USB_PHY_TYPE_UNDEFINED) {
 		dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
 		return -EINVAL;
 	}
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 523cad5..f0d2e75 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -585,23 +585,28 @@
 	struct twl4030_usb	*twl;
 	int			status, err;
 	struct usb_otg		*otg;
-
-	if (!pdata) {
-		dev_dbg(&pdev->dev, "platform_data not available\n");
-		return -EINVAL;
-	}
+	struct device_node	*np = pdev->dev.of_node;
 
 	twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
+	if (np)
+		of_property_read_u32(np, "usb_mode",
+				(enum twl4030_usb_mode *)&twl->usb_mode);
+	else if (pdata)
+		twl->usb_mode = pdata->usb_mode;
+	else {
+		dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
+		return -EINVAL;
+	}
+
 	otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
 	if (!otg)
 		return -ENOMEM;
 
 	twl->dev		= &pdev->dev;
 	twl->irq		= platform_get_irq(pdev, 0);
-	twl->usb_mode		= pdata->usb_mode;
 	twl->vbus_supplied	= false;
 	twl->asleep		= 1;
 	twl->linkstat		= OMAP_MUSB_UNKNOWN;
@@ -690,12 +695,21 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_usb_id_table[] = {
+	{ .compatible = "ti,twl4030-usb" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
+#endif
+
 static struct platform_driver twl4030_usb_driver = {
 	.probe		= twl4030_usb_probe,
 	.remove		= __exit_p(twl4030_usb_remove),
 	.driver		= {
 		.name	= "twl4030_usb",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(twl4030_usb_id_table),
 	},
 };
 
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index 6907d8d..fcadef7 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -25,8 +25,9 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/usb/otg.h>
 #include <linux/usb/musb-omap.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/omap_usb.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
@@ -87,7 +88,7 @@
 #define	VBUS_DET			BIT(2)
 
 struct twl6030_usb {
-	struct usb_phy		phy;
+	struct phy_companion	comparator;
 	struct device		*dev;
 
 	/* for vbus reporting with irqs disabled */
@@ -104,10 +105,10 @@
 	u8			asleep;
 	bool			irq_enabled;
 	bool			vbus_enable;
-	unsigned long		features;
+	const char		*regulator;
 };
 
-#define phy_to_twl(x)		container_of((x), struct twl6030_usb, phy)
+#define	comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
 
 /*-------------------------------------------------------------------------*/
 
@@ -137,50 +138,9 @@
 	return ret;
 }
 
-static int twl6030_phy_init(struct usb_phy *x)
+static int twl6030_start_srp(struct phy_companion *comparator)
 {
-	struct twl6030_usb *twl;
-	struct device *dev;
-	struct twl4030_usb_data *pdata;
-
-	twl = phy_to_twl(x);
-	dev  = twl->dev;
-	pdata = dev->platform_data;
-
-	if (twl->linkstat == OMAP_MUSB_ID_GROUND)
-		pdata->phy_power(twl->dev, 1, 1);
-	else
-		pdata->phy_power(twl->dev, 0, 1);
-
-	return 0;
-}
-
-static void twl6030_phy_shutdown(struct usb_phy *x)
-{
-	struct twl6030_usb *twl;
-	struct device *dev;
-	struct twl4030_usb_data *pdata;
-
-	twl = phy_to_twl(x);
-	dev  = twl->dev;
-	pdata = dev->platform_data;
-	pdata->phy_power(twl->dev, 0, 0);
-}
-
-static int twl6030_phy_suspend(struct usb_phy *x, int suspend)
-{
-	struct twl6030_usb *twl = phy_to_twl(x);
-	struct device *dev = twl->dev;
-	struct twl4030_usb_data *pdata = dev->platform_data;
-
-	pdata->phy_suspend(dev, suspend);
-
-	return 0;
-}
-
-static int twl6030_start_srp(struct usb_otg *otg)
-{
-	struct twl6030_usb *twl = phy_to_twl(otg->phy);
+	struct twl6030_usb *twl = comparator_to_twl(comparator);
 
 	twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
 	twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
@@ -193,13 +153,6 @@
 
 static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
 {
-	char *regulator_name;
-
-	if (twl->features & TWL6025_SUBCLASS)
-		regulator_name = "ldousb";
-	else
-		regulator_name = "vusb";
-
 	/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
 	twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
 
@@ -209,7 +162,7 @@
 	/* Program MISC2 register and set bit VUSB_IN_VBAT */
 	twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
 
-	twl->usb3v3 = regulator_get(twl->dev, regulator_name);
+	twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
 	if (IS_ERR(twl->usb3v3))
 		return -ENODEV;
 
@@ -313,23 +266,8 @@
 	return IRQ_HANDLED;
 }
 
-static int twl6030_set_peripheral(struct usb_otg *otg,
-		struct usb_gadget *gadget)
+static int twl6030_enable_irq(struct twl6030_usb *twl)
 {
-	if (!otg)
-		return -ENODEV;
-
-	otg->gadget = gadget;
-	if (!gadget)
-		otg->phy->state = OTG_STATE_UNDEFINED;
-
-	return 0;
-}
-
-static int twl6030_enable_irq(struct usb_phy *x)
-{
-	struct twl6030_usb *twl = phy_to_twl(x);
-
 	twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
@@ -362,9 +300,9 @@
 							CHARGERUSB_CTRL1);
 }
 
-static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
+static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
 {
-	struct twl6030_usb *twl = phy_to_twl(otg->phy);
+	struct twl6030_usb *twl = comparator_to_twl(comparator);
 
 	twl->vbus_enable = enabled;
 	schedule_work(&twl->set_vbus_work);
@@ -372,52 +310,44 @@
 	return 0;
 }
 
-static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-	if (!otg)
-		return -ENODEV;
-
-	otg->host = host;
-	if (!host)
-		otg->phy->state = OTG_STATE_UNDEFINED;
-	return 0;
-}
-
 static int __devinit twl6030_usb_probe(struct platform_device *pdev)
 {
+	u32 ret;
 	struct twl6030_usb	*twl;
 	int			status, err;
-	struct twl4030_usb_data *pdata;
-	struct usb_otg		*otg;
-	struct device *dev = &pdev->dev;
-	pdata = dev->platform_data;
+	struct device_node	*np = pdev->dev.of_node;
+	struct device		*dev = &pdev->dev;
+	struct twl4030_usb_data	*pdata = dev->platform_data;
 
 	twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
-	otg = devm_kzalloc(dev, sizeof *otg, GFP_KERNEL);
-	if (!otg)
-		return -ENOMEM;
-
 	twl->dev		= &pdev->dev;
 	twl->irq1		= platform_get_irq(pdev, 0);
 	twl->irq2		= platform_get_irq(pdev, 1);
-	twl->features		= pdata->features;
 	twl->linkstat		= OMAP_MUSB_UNKNOWN;
 
-	twl->phy.dev		= twl->dev;
-	twl->phy.label		= "twl6030";
-	twl->phy.otg		= otg;
-	twl->phy.init		= twl6030_phy_init;
-	twl->phy.shutdown	= twl6030_phy_shutdown;
-	twl->phy.set_suspend	= twl6030_phy_suspend;
+	twl->comparator.set_vbus	= twl6030_set_vbus;
+	twl->comparator.start_srp	= twl6030_start_srp;
 
-	otg->phy		= &twl->phy;
-	otg->set_host		= twl6030_set_host;
-	otg->set_peripheral	= twl6030_set_peripheral;
-	otg->set_vbus		= twl6030_set_vbus;
-	otg->start_srp		= twl6030_start_srp;
+	ret = omap_usb2_set_comparator(&twl->comparator);
+	if (ret == -ENODEV) {
+		dev_info(&pdev->dev, "phy not ready, deferring probe");
+		return -EPROBE_DEFER;
+	}
+
+	if (np) {
+		twl->regulator = "usb";
+	} else if (pdata) {
+		if (pdata->features & TWL6025_SUBCLASS)
+			twl->regulator = "ldousb";
+		else
+			twl->regulator = "vusb";
+	} else {
+		dev_err(&pdev->dev, "twl6030 initialized without pdata\n");
+		return -EINVAL;
+	}
 
 	/* init spinlock for workqueue */
 	spin_lock_init(&twl->lock);
@@ -427,7 +357,6 @@
 		dev_err(&pdev->dev, "ldo init failed\n");
 		return err;
 	}
-	usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
@@ -458,9 +387,7 @@
 	}
 
 	twl->asleep = 0;
-	pdata->phy_init(dev);
-	twl6030_phy_suspend(&twl->phy, 0);
-	twl6030_enable_irq(&twl->phy);
+	twl6030_enable_irq(twl);
 	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
 
 	return 0;
@@ -470,10 +397,6 @@
 {
 	struct twl6030_usb *twl = platform_get_drvdata(pdev);
 
-	struct twl4030_usb_data *pdata;
-	struct device *dev = &pdev->dev;
-	pdata = dev->platform_data;
-
 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
 		REG_INT_MSK_LINE_C);
 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
@@ -481,19 +404,27 @@
 	free_irq(twl->irq1, twl);
 	free_irq(twl->irq2, twl);
 	regulator_put(twl->usb3v3);
-	pdata->phy_exit(twl->dev);
 	device_remove_file(twl->dev, &dev_attr_vbus);
 	cancel_work_sync(&twl->set_vbus_work);
 
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id twl6030_usb_id_table[] = {
+	{ .compatible = "ti,twl6030-usb" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
+#endif
+
 static struct platform_driver twl6030_usb_driver = {
 	.probe		= twl6030_usb_probe,
 	.remove		= __exit_p(twl6030_usb_remove),
 	.driver		= {
 		.name	= "twl6030_usb",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(twl6030_usb_id_table),
 	},
 };
 
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index e7cf84f..63c339b 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -4,6 +4,15 @@
 comment "USB Physical Layer drivers"
 	depends on USB || USB_GADGET
 
+config OMAP_USB2
+	tristate "OMAP USB2 PHY Driver"
+	select USB_OTG_UTILS
+	help
+	  Enable this to support the transceiver that is part of SOC. This
+	  driver takes care of all the PHY functionality apart from comparator.
+	  The USB OTG controller communicates with the comparator using this
+	  driver.
+
 config USB_ISP1301
 	tristate "NXP ISP1301 USB transceiver support"
 	depends on USB || USB_GADGET
@@ -15,3 +24,11 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called isp1301.
+
+config MV_U3D_PHY
+	bool "Marvell USB 3.0 PHY controller Driver"
+	depends on USB_MV_U3D
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Marvell USB 3.0 phy controller for Marvell
+	  SoC.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index eca095b..b069f29 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -4,4 +4,7 @@
 
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
+obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
+obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
+obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
index b19f4932..18dbf7e 100644
--- a/drivers/usb/phy/isp1301.c
+++ b/drivers/usb/phy/isp1301.c
@@ -15,12 +15,6 @@
 
 #define DRV_NAME		"isp1301"
 
-#define ISP1301_I2C_ADDR	0x2C
-
-static const unsigned short normal_i2c[] = {
-	ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
-};
-
 static const struct i2c_device_id isp1301_id[] = {
 	{ "isp1301", 0 },
 	{ }
diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c
new file mode 100644
index 0000000..9f1c5d3
--- /dev/null
+++ b/drivers/usb/phy/mv_u3d_phy.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_u3d_phy.h"
+
+/*
+ * struct mv_u3d_phy - transceiver driver state
+ * @phy: transceiver structure
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @base: usb phy register memory base
+ */
+struct mv_u3d_phy {
+	struct usb_phy	phy;
+	struct mv_usb_platform_data *plat;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*base;
+};
+
+static u32 mv_u3d_phy_read(void __iomem *base, u32 reg)
+{
+	void __iomem *addr, *data;
+
+	addr = base;
+	data = base + 0x4;
+
+	writel_relaxed(reg, addr);
+	return readl_relaxed(data);
+}
+
+static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value)
+{
+	void __iomem *addr, *data;
+	u32 tmp;
+
+	addr = base;
+	data = base + 0x4;
+
+	writel_relaxed(reg, addr);
+	tmp = readl_relaxed(data);
+	tmp |= value;
+	writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value)
+{
+	void __iomem *addr, *data;
+	u32 tmp;
+
+	addr = base;
+	data = base + 0x4;
+
+	writel_relaxed(reg, addr);
+	tmp = readl_relaxed(data);
+	tmp &= ~value;
+	writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
+{
+	void __iomem *addr, *data;
+
+	addr = base;
+	data = base + 0x4;
+
+	writel_relaxed(reg, addr);
+	writel_relaxed(value, data);
+}
+
+void mv_u3d_phy_shutdown(struct usb_phy *phy)
+{
+	struct mv_u3d_phy *mv_u3d_phy;
+	void __iomem *base;
+	u32 val;
+
+	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+	base = mv_u3d_phy->base;
+
+	/* Power down Reference Analog current, bit 15
+	 * Power down PLL, bit 14
+	 * Power down Receiver, bit 13
+	 * Power down Transmitter, bit 12
+	 * of USB3_POWER_PLL_CONTROL register
+	 */
+	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+	val &= ~(USB3_POWER_PLL_CONTROL_PU);
+	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+
+	if (mv_u3d_phy->clk)
+		clk_disable(mv_u3d_phy->clk);
+}
+
+static int mv_u3d_phy_init(struct usb_phy *phy)
+{
+	struct mv_u3d_phy *mv_u3d_phy;
+	void __iomem *base;
+	u32 val, count;
+
+	/* enable usb3 phy */
+	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+
+	if (mv_u3d_phy->clk)
+		clk_enable(mv_u3d_phy->clk);
+
+	base = mv_u3d_phy->base;
+
+	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+	val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK);
+	val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT;
+	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+	udelay(100);
+
+	mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+			USB3_RESET_CONTROL_RESET_PIPE);
+	udelay(100);
+
+	mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+			USB3_RESET_CONTROL_RESET_PIPE
+			| USB3_RESET_CONTROL_RESET_PHY);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+	val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK
+		| USB3_POWER_PLL_CONTROL_PHY_MODE_MASK);
+	val |=  (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT)
+		| (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT);
+	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+	udelay(100);
+
+	mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL,
+		USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE);
+	val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK
+		| USB3_SQUELCH_FFE_FFE_RES_SEL_MASK
+		| USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK);
+	val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT)
+		| (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT)
+		| (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT));
+	mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_GEN1_SET0);
+	val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK;
+	val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT;
+	mv_u3d_phy_write(base, USB3_GEN1_SET0, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_GEN2_SET0);
+	val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK
+		| USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK
+		| USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK);
+	val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT)
+		| (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT)
+		| (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT)
+		| (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT));
+	mv_u3d_phy_write(base, USB3_GEN2_SET0, val);
+	udelay(100);
+
+	mv_u3d_phy_read(base, USB3_TX_EMPPH);
+	val &= ~(USB3_TX_EMPPH_AMP_MASK
+		| USB3_TX_EMPPH_EN_MASK
+		| USB3_TX_EMPPH_AMP_FORCE_MASK
+		| USB3_TX_EMPPH_PAR1_MASK
+		| USB3_TX_EMPPH_PAR2_MASK);
+	val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT)
+		| (1 << USB3_TX_EMPPH_EN_SHIFT)
+		| (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT)
+		| (0x1C << USB3_TX_EMPPH_PAR1_SHIFT)
+		| (1 << USB3_TX_EMPPH_PAR2_SHIFT));
+
+	mv_u3d_phy_write(base, USB3_TX_EMPPH, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_GEN2_SET1);
+	val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK
+		| USB3_GEN2_SET1_G2_RX_SELMUPF_MASK
+		| USB3_GEN2_SET1_G2_RX_SELMUFI_MASK
+		| USB3_GEN2_SET1_G2_RX_SELMUFF_MASK);
+	val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT)
+		| (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT)
+		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT)
+		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT));
+	mv_u3d_phy_write(base, USB3_GEN2_SET1, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN);
+	val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK;
+	val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT;
+	mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC);
+	val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK;
+	val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT;
+	mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL);
+	val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK;
+	val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT;
+	mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE);
+	val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK
+		| USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK
+		| USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK);
+	val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT)
+		| (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT));
+	mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val);
+	udelay(100);
+
+	val = mv_u3d_phy_read(base, USB3_TXDETRX);
+	val &= ~(USB3_TXDETRX_VTHSEL_MASK);
+	val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT;
+	mv_u3d_phy_write(base, USB3_TXDETRX, val);
+	udelay(100);
+
+	dev_dbg(mv_u3d_phy->dev, "start calibration\n");
+
+calstart:
+	/* Perform Manual Calibration */
+	mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL,
+		1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT);
+
+	mdelay(1);
+
+	count = 0;
+	while (1) {
+		val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL);
+		if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT))
+			break;
+		else if (count > 50) {
+			dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n");
+			goto calstart;
+		}
+		count++;
+		mdelay(1);
+	}
+
+	/* active PIPE interface */
+	mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL,
+		1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE);
+
+	return 0;
+}
+
+static int __devinit mv_u3d_phy_probe(struct platform_device *pdev)
+{
+	struct mv_u3d_phy *mv_u3d_phy;
+	struct mv_usb_platform_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem	*phy_base;
+	int	ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing mem resource\n");
+		return -ENODEV;
+	}
+
+	phy_base = devm_request_and_ioremap(dev, res);
+	if (!phy_base) {
+		dev_err(dev, "%s: register mapping failed\n", __func__);
+		return -ENXIO;
+	}
+
+	mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL);
+	if (!mv_u3d_phy)
+		return -ENOMEM;
+
+	mv_u3d_phy->dev			= &pdev->dev;
+	mv_u3d_phy->plat		= pdata;
+	mv_u3d_phy->base		= phy_base;
+	mv_u3d_phy->phy.dev		= mv_u3d_phy->dev;
+	mv_u3d_phy->phy.label		= "mv-u3d-phy";
+	mv_u3d_phy->phy.init		= mv_u3d_phy_init;
+	mv_u3d_phy->phy.shutdown	= mv_u3d_phy_shutdown;
+
+	ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3);
+	if (ret)
+		goto err;
+
+	if (!mv_u3d_phy->clk)
+		mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy");
+
+	platform_set_drvdata(pdev, mv_u3d_phy);
+
+	dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n");
+err:
+	return ret;
+}
+
+static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
+{
+	struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&mv_u3d_phy->phy);
+
+	if (mv_u3d_phy->clk) {
+		clk_put(mv_u3d_phy->clk);
+		mv_u3d_phy->clk = NULL;
+	}
+
+	return 0;
+}
+
+static struct platform_driver mv_u3d_phy_driver = {
+	.probe		= mv_u3d_phy_probe,
+	.remove		= __devexit_p(mv_u3d_phy_remove),
+	.driver		= {
+		.name	= "mv-u3d-phy",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(mv_u3d_phy_driver);
+MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller");
+MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mv-u3d-phy");
diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/mv_u3d_phy.h
new file mode 100644
index 0000000..2a658cb
--- /dev/null
+++ b/drivers/usb/phy/mv_u3d_phy.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __MV_U3D_PHY_H
+#define __MV_U3D_PHY_H
+
+#define USB3_POWER_PLL_CONTROL		0x1
+#define USB3_KVCO_CALI_CONTROL		0x2
+#define USB3_IMPEDANCE_CALI_CTRL	0x3
+#define USB3_IMPEDANCE_TX_SSC		0x4
+#define USB3_SQUELCH_FFE		0x6
+#define USB3_GEN1_SET0			0xD
+#define USB3_GEN2_SET0			0xF
+#define USB3_GEN2_SET1			0x10
+#define USB3_DIGITAL_LOOPBACK_EN	0x23
+#define USB3_PHY_ISOLATION_MODE		0x26
+#define USB3_TXDETRX			0x48
+#define USB3_TX_EMPPH			0x5E
+#define USB3_RESET_CONTROL		0x90
+#define USB3_PIPE_SM_CTRL		0x91
+
+#define USB3_RESET_CONTROL_RESET_PIPE			0x1
+#define USB3_RESET_CONTROL_RESET_PHY			0x2
+
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK	(0x1F << 0)
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT	0
+#define USB3_PLL_25MHZ					0x2
+#define USB3_PLL_26MHZ					0x5
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK		(0x7 << 5)
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT		5
+#define USB3_POWER_PLL_CONTROL_PU_MASK			(0xF << 12)
+#define USB3_POWER_PLL_CONTROL_PU_SHIFT			12
+#define USB3_POWER_PLL_CONTROL_PU			(0xF << 12)
+
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK	(0x1 << 12)
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT	12
+#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT		14
+#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT		15
+
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK		0xF
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT		0
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK		(0x7 << 4)
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT		4
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK		(0x1F << 8)
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT		8
+
+#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK		(0x1 << 15)
+#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT		11
+
+#define USB3_GEN2_SET0_G2_TX_AMP_MASK			(0x1F << 1)
+#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT			1
+#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT		6
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK		(0xF << 7)
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT		7
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK		(0x1 << 11)
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT		11
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK		(0x1 << 15)
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT		15
+
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK		(0x7 << 0)
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT		0
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK		(0x7 << 3)
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT		3
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK		(0x3 << 6)
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT		6
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK		(0x3 << 8)
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT		8
+
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK		(0x3 << 10)
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT		10
+
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK	(0x7 << 12)
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT	12
+
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK		(0x3F << 0)
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT		0
+
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK		0xF
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT	0
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK		(0xF << 4)
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT	4
+#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK	(0x1 << 8)
+
+#define USB3_TXDETRX_VTHSEL_MASK			(0x3 << 4)
+#define USB3_TXDETRX_VTHSEL_SHIFT			4
+
+#define USB3_TX_EMPPH_AMP_MASK				(0xF << 0)
+#define USB3_TX_EMPPH_AMP_SHIFT				0
+#define USB3_TX_EMPPH_EN_MASK				(0x1 << 6)
+#define USB3_TX_EMPPH_EN_SHIFT				6
+#define USB3_TX_EMPPH_AMP_FORCE_MASK			(0x1 << 7)
+#define USB3_TX_EMPPH_AMP_FORCE_SHIFT			7
+#define USB3_TX_EMPPH_PAR1_MASK				(0x1F << 8)
+#define USB3_TX_EMPPH_PAR1_SHIFT			8
+#define USB3_TX_EMPPH_PAR2_MASK				(0x1 << 13)
+#define USB3_TX_EMPPH_PAR2_SHIFT			13
+
+#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE			15
+
+#endif /* __MV_U3D_PHY_H */
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
new file mode 100644
index 0000000..15ab3d6
--- /dev/null
+++ b/drivers/usb/phy/omap-usb2.c
@@ -0,0 +1,271 @@
+/*
+ * omap-usb2.c - USB PHY, talking to musb controller in OMAP.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/usb/omap_usb.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+
+/**
+ * omap_usb2_set_comparator - links the comparator present in the sytem with
+ *	this phy
+ * @comparator - the companion phy(comparator) for this phy
+ *
+ * The phy companion driver should call this API passing the phy_companion
+ * filled with set_vbus and start_srp to be used by usb phy.
+ *
+ * For use by phy companion driver
+ */
+int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+	struct omap_usb	*phy;
+	struct usb_phy	*x = usb_get_phy(USB_PHY_TYPE_USB2);
+
+	if (IS_ERR(x))
+		return -ENODEV;
+
+	phy = phy_to_omapusb(x);
+	phy->comparator = comparator;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
+
+/**
+ * omap_usb_phy_power - power on/off the phy using control module reg
+ * @phy: struct omap_usb *
+ * @on: 0 or 1, based on powering on or off the PHY
+ *
+ * XXX: Remove this function once control module driver gets merged
+ */
+static void omap_usb_phy_power(struct omap_usb *phy, int on)
+{
+	u32 val;
+
+	if (on) {
+		val = readl(phy->control_dev);
+		if (val & PHY_PD) {
+			writel(~PHY_PD, phy->control_dev);
+			/* XXX: add proper documentation for this delay */
+			mdelay(200);
+		}
+	} else {
+		writel(PHY_PD, phy->control_dev);
+	}
+}
+
+static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
+{
+	struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+	if (!phy->comparator)
+		return -ENODEV;
+
+	return phy->comparator->set_vbus(phy->comparator, enabled);
+}
+
+static int omap_usb_start_srp(struct usb_otg *otg)
+{
+	struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+	if (!phy->comparator)
+		return -ENODEV;
+
+	return phy->comparator->start_srp(phy->comparator);
+}
+
+static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+	struct usb_phy	*phy = otg->phy;
+
+	otg->host = host;
+	if (!host)
+		phy->state = OTG_STATE_UNDEFINED;
+
+	return 0;
+}
+
+static int omap_usb_set_peripheral(struct usb_otg *otg,
+		struct usb_gadget *gadget)
+{
+	struct usb_phy	*phy = otg->phy;
+
+	otg->gadget = gadget;
+	if (!gadget)
+		phy->state = OTG_STATE_UNDEFINED;
+
+	return 0;
+}
+
+static int omap_usb2_suspend(struct usb_phy *x, int suspend)
+{
+	u32 ret;
+	struct omap_usb *phy = phy_to_omapusb(x);
+
+	if (suspend && !phy->is_suspended) {
+		omap_usb_phy_power(phy, 0);
+		pm_runtime_put_sync(phy->dev);
+		phy->is_suspended = 1;
+	} else if (!suspend && phy->is_suspended) {
+		ret = pm_runtime_get_sync(phy->dev);
+		if (ret < 0) {
+			dev_err(phy->dev, "get_sync failed with err %d\n",
+									ret);
+			return ret;
+		}
+		omap_usb_phy_power(phy, 1);
+		phy->is_suspended = 0;
+	}
+
+	return 0;
+}
+
+static int __devinit omap_usb2_probe(struct platform_device *pdev)
+{
+	struct omap_usb			*phy;
+	struct usb_otg			*otg;
+	struct resource			*res;
+
+	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy) {
+		dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
+		return -ENOMEM;
+	}
+
+	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n");
+		return -ENOMEM;
+	}
+
+	phy->dev		= &pdev->dev;
+
+	phy->phy.dev		= phy->dev;
+	phy->phy.label		= "omap-usb2";
+	phy->phy.set_suspend	= omap_usb2_suspend;
+	phy->phy.otg		= otg;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+	phy->control_dev = devm_request_and_ioremap(&pdev->dev, res);
+	if (phy->control_dev == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENXIO;
+	}
+
+	phy->is_suspended	= 1;
+	omap_usb_phy_power(phy, 0);
+
+	otg->set_host		= omap_usb_set_host;
+	otg->set_peripheral	= omap_usb_set_peripheral;
+	otg->set_vbus		= omap_usb_set_vbus;
+	otg->start_srp		= omap_usb_start_srp;
+	otg->phy		= &phy->phy;
+
+	phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
+	if (IS_ERR(phy->wkupclk)) {
+		dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
+		return PTR_ERR(phy->wkupclk);
+	}
+	clk_prepare(phy->wkupclk);
+
+	usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2);
+
+	platform_set_drvdata(pdev, phy);
+
+	pm_runtime_enable(phy->dev);
+
+	return 0;
+}
+
+static int __devexit omap_usb2_remove(struct platform_device *pdev)
+{
+	struct omap_usb	*phy = platform_get_drvdata(pdev);
+
+	clk_unprepare(phy->wkupclk);
+	usb_remove_phy(&phy->phy);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int omap_usb2_runtime_suspend(struct device *dev)
+{
+	struct platform_device	*pdev = to_platform_device(dev);
+	struct omap_usb	*phy = platform_get_drvdata(pdev);
+
+	clk_disable(phy->wkupclk);
+
+	return 0;
+}
+
+static int omap_usb2_runtime_resume(struct device *dev)
+{
+	u32 ret = 0;
+	struct platform_device	*pdev = to_platform_device(dev);
+	struct omap_usb	*phy = platform_get_drvdata(pdev);
+
+	ret = clk_enable(phy->wkupclk);
+	if (ret < 0)
+		dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+
+	return ret;
+}
+
+static const struct dev_pm_ops omap_usb2_pm_ops = {
+	SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume,
+		NULL)
+};
+
+#define DEV_PM_OPS     (&omap_usb2_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_usb2_id_table[] = {
+	{ .compatible = "ti,omap-usb2" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
+static struct platform_driver omap_usb2_driver = {
+	.probe		= omap_usb2_probe,
+	.remove		= __devexit_p(omap_usb2_remove),
+	.driver		= {
+		.name	= "omap-usb2",
+		.owner	= THIS_MODULE,
+		.pm	= DEV_PM_OPS,
+		.of_match_table = of_match_ptr(omap_usb2_id_table),
+	},
+};
+
+module_platform_driver(omap_usb2_driver);
+
+MODULE_ALIAS("platform: omap_usb2");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("OMAP USB2 phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c
new file mode 100644
index 0000000..4739903
--- /dev/null
+++ b/drivers/usb/phy/tegra_usb_phy.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Erik Gilling <konkers@google.com>
+ *	Benoit Goby <benoit@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/resource.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <asm/mach-types.h>
+#include <mach/gpio-tegra.h>
+#include <linux/usb/tegra_usb_phy.h>
+#include <mach/iomap.h>
+
+#define ULPI_VIEWPORT		0x170
+
+#define USB_PORTSC1		0x184
+#define   USB_PORTSC1_PTS(x)	(((x) & 0x3) << 30)
+#define   USB_PORTSC1_PSPD(x)	(((x) & 0x3) << 26)
+#define   USB_PORTSC1_PHCD	(1 << 23)
+#define   USB_PORTSC1_WKOC	(1 << 22)
+#define   USB_PORTSC1_WKDS	(1 << 21)
+#define   USB_PORTSC1_WKCN	(1 << 20)
+#define   USB_PORTSC1_PTC(x)	(((x) & 0xf) << 16)
+#define   USB_PORTSC1_PP	(1 << 12)
+#define   USB_PORTSC1_SUSP	(1 << 7)
+#define   USB_PORTSC1_PE	(1 << 2)
+#define   USB_PORTSC1_CCS	(1 << 0)
+
+#define USB_SUSP_CTRL		0x400
+#define   USB_WAKE_ON_CNNT_EN_DEV	(1 << 3)
+#define   USB_WAKE_ON_DISCON_EN_DEV	(1 << 4)
+#define   USB_SUSP_CLR		(1 << 5)
+#define   USB_PHY_CLK_VALID	(1 << 7)
+#define   UTMIP_RESET			(1 << 11)
+#define   UHSIC_RESET			(1 << 11)
+#define   UTMIP_PHY_ENABLE		(1 << 12)
+#define   ULPI_PHY_ENABLE	(1 << 13)
+#define   USB_SUSP_SET		(1 << 14)
+#define   USB_WAKEUP_DEBOUNCE_COUNT(x)	(((x) & 0x7) << 16)
+
+#define USB1_LEGACY_CTRL	0x410
+#define   USB1_NO_LEGACY_MODE			(1 << 0)
+#define   USB1_VBUS_SENSE_CTL_MASK		(3 << 1)
+#define   USB1_VBUS_SENSE_CTL_VBUS_WAKEUP	(0 << 1)
+#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
+						(1 << 1)
+#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD	(2 << 1)
+#define   USB1_VBUS_SENSE_CTL_A_SESS_VLD	(3 << 1)
+
+#define ULPI_TIMING_CTRL_0	0x424
+#define   ULPI_OUTPUT_PINMUX_BYP	(1 << 10)
+#define   ULPI_CLKOUT_PINMUX_BYP	(1 << 11)
+
+#define ULPI_TIMING_CTRL_1	0x428
+#define   ULPI_DATA_TRIMMER_LOAD	(1 << 0)
+#define   ULPI_DATA_TRIMMER_SEL(x)	(((x) & 0x7) << 1)
+#define   ULPI_STPDIRNXT_TRIMMER_LOAD	(1 << 16)
+#define   ULPI_STPDIRNXT_TRIMMER_SEL(x)	(((x) & 0x7) << 17)
+#define   ULPI_DIR_TRIMMER_LOAD		(1 << 24)
+#define   ULPI_DIR_TRIMMER_SEL(x)	(((x) & 0x7) << 25)
+
+#define UTMIP_PLL_CFG1		0x804
+#define   UTMIP_XTAL_FREQ_COUNT(x)		(((x) & 0xfff) << 0)
+#define   UTMIP_PLLU_ENABLE_DLY_COUNT(x)	(((x) & 0x1f) << 27)
+
+#define UTMIP_XCVR_CFG0		0x808
+#define   UTMIP_XCVR_SETUP(x)			(((x) & 0xf) << 0)
+#define   UTMIP_XCVR_LSRSLEW(x)			(((x) & 0x3) << 8)
+#define   UTMIP_XCVR_LSFSLEW(x)			(((x) & 0x3) << 10)
+#define   UTMIP_FORCE_PD_POWERDOWN		(1 << 14)
+#define   UTMIP_FORCE_PD2_POWERDOWN		(1 << 16)
+#define   UTMIP_FORCE_PDZI_POWERDOWN		(1 << 18)
+#define   UTMIP_XCVR_HSSLEW_MSB(x)		(((x) & 0x7f) << 25)
+
+#define UTMIP_BIAS_CFG0		0x80c
+#define   UTMIP_OTGPD			(1 << 11)
+#define   UTMIP_BIASPD			(1 << 10)
+
+#define UTMIP_HSRX_CFG0		0x810
+#define   UTMIP_ELASTIC_LIMIT(x)	(((x) & 0x1f) << 10)
+#define   UTMIP_IDLE_WAIT(x)		(((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1		0x814
+#define   UTMIP_HS_SYNC_START_DLY(x)	(((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0		0x820
+#define   UTMIP_FS_PREABMLE_J		(1 << 19)
+#define   UTMIP_HS_DISCON_DISABLE	(1 << 8)
+
+#define UTMIP_MISC_CFG0		0x824
+#define   UTMIP_DPDM_OBSERVE		(1 << 26)
+#define   UTMIP_DPDM_OBSERVE_SEL(x)	(((x) & 0xf) << 27)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_J	UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_K	UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define   UTMIP_SUSPEND_EXIT_ON_EDGE	(1 << 22)
+
+#define UTMIP_MISC_CFG1		0x828
+#define   UTMIP_PLL_ACTIVE_DLY_COUNT(x)	(((x) & 0x1f) << 18)
+#define   UTMIP_PLLU_STABLE_COUNT(x)	(((x) & 0xfff) << 6)
+
+#define UTMIP_DEBOUNCE_CFG0	0x82c
+#define   UTMIP_BIAS_DEBOUNCE_A(x)	(((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0	0x830
+#define   UTMIP_PD_CHRG			(1 << 0)
+
+#define UTMIP_SPARE_CFG0	0x834
+#define   FUSE_SETUP_SEL		(1 << 3)
+
+#define UTMIP_XCVR_CFG1		0x838
+#define   UTMIP_FORCE_PDDISC_POWERDOWN	(1 << 0)
+#define   UTMIP_FORCE_PDCHRP_POWERDOWN	(1 << 2)
+#define   UTMIP_FORCE_PDDR_POWERDOWN	(1 << 4)
+#define   UTMIP_XCVR_TERM_RANGE_ADJ(x)	(((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1		0x83c
+#define   UTMIP_BIAS_PDTRK_COUNT(x)	(((x) & 0x1f) << 3)
+
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+struct tegra_xtal_freq {
+	int freq;
+	u8 enable_delay;
+	u8 stable_count;
+	u8 active_delay;
+	u8 xtal_freq_count;
+	u16 debounce;
+};
+
+static const struct tegra_xtal_freq tegra_freq_table[] = {
+	{
+		.freq = 12000000,
+		.enable_delay = 0x02,
+		.stable_count = 0x2F,
+		.active_delay = 0x04,
+		.xtal_freq_count = 0x76,
+		.debounce = 0x7530,
+	},
+	{
+		.freq = 13000000,
+		.enable_delay = 0x02,
+		.stable_count = 0x33,
+		.active_delay = 0x05,
+		.xtal_freq_count = 0x7F,
+		.debounce = 0x7EF4,
+	},
+	{
+		.freq = 19200000,
+		.enable_delay = 0x03,
+		.stable_count = 0x4B,
+		.active_delay = 0x06,
+		.xtal_freq_count = 0xBB,
+		.debounce = 0xBB80,
+	},
+	{
+		.freq = 26000000,
+		.enable_delay = 0x04,
+		.stable_count = 0x66,
+		.active_delay = 0x09,
+		.xtal_freq_count = 0xFE,
+		.debounce = 0xFDE8,
+	},
+};
+
+static struct tegra_utmip_config utmip_default[] = {
+	[0] = {
+		.hssync_start_delay = 9,
+		.idle_wait_delay = 17,
+		.elastic_limit = 16,
+		.term_range_adj = 6,
+		.xcvr_setup = 9,
+		.xcvr_lsfslew = 1,
+		.xcvr_lsrslew = 1,
+	},
+	[2] = {
+		.hssync_start_delay = 9,
+		.idle_wait_delay = 17,
+		.elastic_limit = 16,
+		.term_range_adj = 6,
+		.xcvr_setup = 9,
+		.xcvr_lsfslew = 2,
+		.xcvr_lsrslew = 2,
+	},
+};
+
+static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
+{
+	return (phy->instance == 1);
+}
+
+static int utmip_pad_open(struct tegra_usb_phy *phy)
+{
+	phy->pad_clk = clk_get_sys("utmip-pad", NULL);
+	if (IS_ERR(phy->pad_clk)) {
+		pr_err("%s: can't get utmip pad clock\n", __func__);
+		return PTR_ERR(phy->pad_clk);
+	}
+
+	if (phy->instance == 0) {
+		phy->pad_regs = phy->regs;
+	} else {
+		phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
+		if (!phy->pad_regs) {
+			pr_err("%s: can't remap usb registers\n", __func__);
+			clk_put(phy->pad_clk);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+static void utmip_pad_close(struct tegra_usb_phy *phy)
+{
+	if (phy->instance != 0)
+		iounmap(phy->pad_regs);
+	clk_put(phy->pad_clk);
+}
+
+static void utmip_pad_power_on(struct tegra_usb_phy *phy)
+{
+	unsigned long val, flags;
+	void __iomem *base = phy->pad_regs;
+
+	clk_prepare_enable(phy->pad_clk);
+
+	spin_lock_irqsave(&utmip_pad_lock, flags);
+
+	if (utmip_pad_count++ == 0) {
+		val = readl(base + UTMIP_BIAS_CFG0);
+		val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+		writel(val, base + UTMIP_BIAS_CFG0);
+	}
+
+	spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+	clk_disable_unprepare(phy->pad_clk);
+}
+
+static int utmip_pad_power_off(struct tegra_usb_phy *phy)
+{
+	unsigned long val, flags;
+	void __iomem *base = phy->pad_regs;
+
+	if (!utmip_pad_count) {
+		pr_err("%s: utmip pad already powered off\n", __func__);
+		return -EINVAL;
+	}
+
+	clk_prepare_enable(phy->pad_clk);
+
+	spin_lock_irqsave(&utmip_pad_lock, flags);
+
+	if (--utmip_pad_count == 0) {
+		val = readl(base + UTMIP_BIAS_CFG0);
+		val |= UTMIP_OTGPD | UTMIP_BIASPD;
+		writel(val, base + UTMIP_BIAS_CFG0);
+	}
+
+	spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+	clk_disable_unprepare(phy->pad_clk);
+
+	return 0;
+}
+
+static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+{
+	unsigned long timeout = 2000;
+	do {
+		if ((readl(reg) & mask) == result)
+			return 0;
+		udelay(1);
+		timeout--;
+	} while (timeout);
+	return -1;
+}
+
+static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	if (phy->instance == 0) {
+		val = readl(base + USB_SUSP_CTRL);
+		val |= USB_SUSP_SET;
+		writel(val, base + USB_SUSP_CTRL);
+
+		udelay(10);
+
+		val = readl(base + USB_SUSP_CTRL);
+		val &= ~USB_SUSP_SET;
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	if (phy->instance == 2) {
+		val = readl(base + USB_PORTSC1);
+		val |= USB_PORTSC1_PHCD;
+		writel(val, base + USB_PORTSC1);
+	}
+
+	if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
+		pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	if (phy->instance == 0) {
+		val = readl(base + USB_SUSP_CTRL);
+		val |= USB_SUSP_CLR;
+		writel(val, base + USB_SUSP_CTRL);
+
+		udelay(10);
+
+		val = readl(base + USB_SUSP_CTRL);
+		val &= ~USB_SUSP_CLR;
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	if (phy->instance == 2) {
+		val = readl(base + USB_PORTSC1);
+		val &= ~USB_PORTSC1_PHCD;
+		writel(val, base + USB_PORTSC1);
+	}
+
+	if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+						     USB_PHY_CLK_VALID))
+		pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+	struct tegra_utmip_config *config = phy->config;
+
+	val = readl(base + USB_SUSP_CTRL);
+	val |= UTMIP_RESET;
+	writel(val, base + USB_SUSP_CTRL);
+
+	if (phy->instance == 0) {
+		val = readl(base + USB1_LEGACY_CTRL);
+		val |= USB1_NO_LEGACY_MODE;
+		writel(val, base + USB1_LEGACY_CTRL);
+	}
+
+	val = readl(base + UTMIP_TX_CFG0);
+	val &= ~UTMIP_FS_PREABMLE_J;
+	writel(val, base + UTMIP_TX_CFG0);
+
+	val = readl(base + UTMIP_HSRX_CFG0);
+	val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+	val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+	val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+	writel(val, base + UTMIP_HSRX_CFG0);
+
+	val = readl(base + UTMIP_HSRX_CFG1);
+	val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+	val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+	writel(val, base + UTMIP_HSRX_CFG1);
+
+	val = readl(base + UTMIP_DEBOUNCE_CFG0);
+	val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+	val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+	writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+	val = readl(base + UTMIP_MISC_CFG0);
+	val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+	writel(val, base + UTMIP_MISC_CFG0);
+
+	val = readl(base + UTMIP_MISC_CFG1);
+	val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
+	val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+		UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+	writel(val, base + UTMIP_MISC_CFG1);
+
+	val = readl(base + UTMIP_PLL_CFG1);
+	val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+	val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+		UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+	writel(val, base + UTMIP_PLL_CFG1);
+
+	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+		val = readl(base + USB_SUSP_CTRL);
+		val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	utmip_pad_power_on(phy);
+
+	val = readl(base + UTMIP_XCVR_CFG0);
+	val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+		 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
+		 UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
+		 UTMIP_XCVR_HSSLEW_MSB(~0));
+	val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+	val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+	val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+	writel(val, base + UTMIP_XCVR_CFG0);
+
+	val = readl(base + UTMIP_XCVR_CFG1);
+	val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+		 UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+	val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+	writel(val, base + UTMIP_XCVR_CFG1);
+
+	val = readl(base + UTMIP_BAT_CHRG_CFG0);
+	val &= ~UTMIP_PD_CHRG;
+	writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+	val = readl(base + UTMIP_BIAS_CFG1);
+	val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+	val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+	writel(val, base + UTMIP_BIAS_CFG1);
+
+	if (phy->instance == 0) {
+		val = readl(base + UTMIP_SPARE_CFG0);
+		if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
+			val &= ~FUSE_SETUP_SEL;
+		else
+			val |= FUSE_SETUP_SEL;
+		writel(val, base + UTMIP_SPARE_CFG0);
+	}
+
+	if (phy->instance == 2) {
+		val = readl(base + USB_SUSP_CTRL);
+		val |= UTMIP_PHY_ENABLE;
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	val = readl(base + USB_SUSP_CTRL);
+	val &= ~UTMIP_RESET;
+	writel(val, base + USB_SUSP_CTRL);
+
+	if (phy->instance == 0) {
+		val = readl(base + USB1_LEGACY_CTRL);
+		val &= ~USB1_VBUS_SENSE_CTL_MASK;
+		val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
+		writel(val, base + USB1_LEGACY_CTRL);
+
+		val = readl(base + USB_SUSP_CTRL);
+		val &= ~USB_SUSP_SET;
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	utmi_phy_clk_enable(phy);
+
+	if (phy->instance == 2) {
+		val = readl(base + USB_PORTSC1);
+		val &= ~USB_PORTSC1_PTS(~0);
+		writel(val, base + USB_PORTSC1);
+	}
+
+	return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	utmi_phy_clk_disable(phy);
+
+	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+		val = readl(base + USB_SUSP_CTRL);
+		val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+		val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+		writel(val, base + USB_SUSP_CTRL);
+	}
+
+	val = readl(base + USB_SUSP_CTRL);
+	val |= UTMIP_RESET;
+	writel(val, base + USB_SUSP_CTRL);
+
+	val = readl(base + UTMIP_BAT_CHRG_CFG0);
+	val |= UTMIP_PD_CHRG;
+	writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+	val = readl(base + UTMIP_XCVR_CFG0);
+	val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+	       UTMIP_FORCE_PDZI_POWERDOWN;
+	writel(val, base + UTMIP_XCVR_CFG0);
+
+	val = readl(base + UTMIP_XCVR_CFG1);
+	val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+	       UTMIP_FORCE_PDDR_POWERDOWN;
+	writel(val, base + UTMIP_XCVR_CFG1);
+
+	return utmip_pad_power_off(phy);
+}
+
+static void utmi_phy_preresume(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	val = readl(base + UTMIP_TX_CFG0);
+	val |= UTMIP_HS_DISCON_DISABLE;
+	writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_postresume(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	val = readl(base + UTMIP_TX_CFG0);
+	val &= ~UTMIP_HS_DISCON_DISABLE;
+	writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
+				   enum tegra_usb_phy_port_speed port_speed)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	val = readl(base + UTMIP_MISC_CFG0);
+	val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+	if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+		val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+	else
+		val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+	writel(val, base + UTMIP_MISC_CFG0);
+	udelay(1);
+
+	val = readl(base + UTMIP_MISC_CFG0);
+	val |= UTMIP_DPDM_OBSERVE;
+	writel(val, base + UTMIP_MISC_CFG0);
+	udelay(10);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+
+	val = readl(base + UTMIP_MISC_CFG0);
+	val &= ~UTMIP_DPDM_OBSERVE;
+	writel(val, base + UTMIP_MISC_CFG0);
+	udelay(10);
+}
+
+static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
+{
+	int ret;
+	unsigned long val;
+	void __iomem *base = phy->regs;
+	struct tegra_ulpi_config *config = phy->config;
+
+	gpio_direction_output(config->reset_gpio, 0);
+	msleep(5);
+	gpio_direction_output(config->reset_gpio, 1);
+
+	clk_prepare_enable(phy->clk);
+	msleep(1);
+
+	val = readl(base + USB_SUSP_CTRL);
+	val |= UHSIC_RESET;
+	writel(val, base + USB_SUSP_CTRL);
+
+	val = readl(base + ULPI_TIMING_CTRL_0);
+	val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+	writel(val, base + ULPI_TIMING_CTRL_0);
+
+	val = readl(base + USB_SUSP_CTRL);
+	val |= ULPI_PHY_ENABLE;
+	writel(val, base + USB_SUSP_CTRL);
+
+	val = 0;
+	writel(val, base + ULPI_TIMING_CTRL_1);
+
+	val |= ULPI_DATA_TRIMMER_SEL(4);
+	val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
+	val |= ULPI_DIR_TRIMMER_SEL(4);
+	writel(val, base + ULPI_TIMING_CTRL_1);
+	udelay(10);
+
+	val |= ULPI_DATA_TRIMMER_LOAD;
+	val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+	val |= ULPI_DIR_TRIMMER_LOAD;
+	writel(val, base + ULPI_TIMING_CTRL_1);
+
+	/* Fix VbusInvalid due to floating VBUS */
+	ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
+	if (ret) {
+		pr_err("%s: ulpi write failed\n", __func__);
+		return ret;
+	}
+
+	ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
+	if (ret) {
+		pr_err("%s: ulpi write failed\n", __func__);
+		return ret;
+	}
+
+	val = readl(base + USB_PORTSC1);
+	val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
+	writel(val, base + USB_PORTSC1);
+
+	val = readl(base + USB_SUSP_CTRL);
+	val |= USB_SUSP_CLR;
+	writel(val, base + USB_SUSP_CTRL);
+	udelay(100);
+
+	val = readl(base + USB_SUSP_CTRL);
+	val &= ~USB_SUSP_CLR;
+	writel(val, base + USB_SUSP_CTRL);
+
+	return 0;
+}
+
+static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
+{
+	unsigned long val;
+	void __iomem *base = phy->regs;
+	struct tegra_ulpi_config *config = phy->config;
+
+	/* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+	 * Controller to immediately bring the ULPI PHY out of low power
+	 */
+	val = readl(base + USB_PORTSC1);
+	val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
+	writel(val, base + USB_PORTSC1);
+
+	clk_disable(phy->clk);
+	return gpio_direction_output(config->reset_gpio, 0);
+}
+
+static int	tegra_phy_init(struct usb_phy *x)
+{
+	struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+	struct tegra_ulpi_config *ulpi_config;
+	int err;
+
+	if (phy_is_ulpi(phy)) {
+		ulpi_config = phy->config;
+		phy->clk = clk_get_sys(NULL, ulpi_config->clk);
+		if (IS_ERR(phy->clk)) {
+			pr_err("%s: can't get ulpi clock\n", __func__);
+			err = -ENXIO;
+			goto err1;
+		}
+		if (!gpio_is_valid(ulpi_config->reset_gpio))
+			ulpi_config->reset_gpio =
+				of_get_named_gpio(phy->dev->of_node,
+						  "nvidia,phy-reset-gpio", 0);
+		if (!gpio_is_valid(ulpi_config->reset_gpio)) {
+			pr_err("%s: invalid reset gpio: %d\n", __func__,
+			       ulpi_config->reset_gpio);
+			err = -EINVAL;
+			goto err1;
+		}
+		gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
+		gpio_direction_output(ulpi_config->reset_gpio, 0);
+		phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+		phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
+	} else {
+		err = utmip_pad_open(phy);
+		if (err < 0)
+			goto err1;
+	}
+	return 0;
+err1:
+	clk_disable_unprepare(phy->pll_u);
+	clk_put(phy->pll_u);
+	return err;
+}
+
+static void tegra_usb_phy_close(struct usb_phy *x)
+{
+	struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+
+	if (phy_is_ulpi(phy))
+		clk_put(phy->clk);
+	else
+		utmip_pad_close(phy);
+	clk_disable_unprepare(phy->pll_u);
+	clk_put(phy->pll_u);
+	kfree(phy);
+}
+
+static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
+{
+	if (phy_is_ulpi(phy))
+		return ulpi_phy_power_on(phy);
+	else
+		return utmi_phy_power_on(phy);
+}
+
+static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
+{
+	if (phy_is_ulpi(phy))
+		return ulpi_phy_power_off(phy);
+	else
+		return utmi_phy_power_off(phy);
+}
+
+static int	tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
+{
+	struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+	if (suspend)
+		return tegra_usb_phy_power_off(phy);
+	else
+		return tegra_usb_phy_power_on(phy);
+}
+
+struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
+	void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
+{
+	struct tegra_usb_phy *phy;
+	unsigned long parent_rate;
+	int i;
+	int err;
+
+	phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
+	if (!phy)
+		return ERR_PTR(-ENOMEM);
+
+	phy->instance = instance;
+	phy->regs = regs;
+	phy->config = config;
+	phy->mode = phy_mode;
+	phy->dev = dev;
+
+	if (!phy->config) {
+		if (phy_is_ulpi(phy)) {
+			pr_err("%s: ulpi phy configuration missing", __func__);
+			err = -EINVAL;
+			goto err0;
+		} else {
+			phy->config = &utmip_default[instance];
+		}
+	}
+
+	phy->pll_u = clk_get_sys(NULL, "pll_u");
+	if (IS_ERR(phy->pll_u)) {
+		pr_err("Can't get pll_u clock\n");
+		err = PTR_ERR(phy->pll_u);
+		goto err0;
+	}
+	clk_prepare_enable(phy->pll_u);
+
+	parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
+	for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
+		if (tegra_freq_table[i].freq == parent_rate) {
+			phy->freq = &tegra_freq_table[i];
+			break;
+		}
+	}
+	if (!phy->freq) {
+		pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+		err = -EINVAL;
+		goto err1;
+	}
+
+	phy->u_phy.init = tegra_phy_init;
+	phy->u_phy.shutdown = tegra_usb_phy_close;
+	phy->u_phy.set_suspend = tegra_usb_phy_suspend;
+
+	return phy;
+
+err1:
+	clk_disable_unprepare(phy->pll_u);
+	clk_put(phy->pll_u);
+err0:
+	kfree(phy);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_preresume(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_postresume(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+				 enum tegra_usb_phy_port_speed port_speed)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_restore_start(phy, port_speed);
+}
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_restore_end(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_clk_disable(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+	if (!phy_is_ulpi(phy))
+		utmi_phy_clk_enable(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 681da06..072edc1 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -432,17 +432,16 @@
 	}
 
 	/* usb private data */
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		dev_err(&pdev->dev, "Could not allocate priv\n");
 		return -ENOMEM;
 	}
 
-	priv->base = ioremap_nocache(res->start, resource_size(res));
+	priv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!priv->base) {
 		dev_err(&pdev->dev, "ioremap error.\n");
-		ret = -ENOMEM;
-		goto probe_end_kfree;
+		return -ENOMEM;
 	}
 
 	/*
@@ -485,7 +484,7 @@
 	/* call pipe and module init */
 	ret = usbhs_pipe_probe(priv);
 	if (ret < 0)
-		goto probe_end_iounmap;
+		return ret;
 
 	ret = usbhs_fifo_probe(priv);
 	if (ret < 0)
@@ -546,10 +545,6 @@
 	usbhs_fifo_remove(priv);
 probe_end_pipe_exit:
 	usbhs_pipe_remove(priv);
-probe_end_iounmap:
-	iounmap(priv->base);
-probe_end_kfree:
-	kfree(priv);
 
 	dev_info(&pdev->dev, "probe failed\n");
 
@@ -576,8 +571,6 @@
 	usbhs_mod_remove(priv);
 	usbhs_fifo_remove(priv);
 	usbhs_pipe_remove(priv);
-	iounmap(priv->base);
-	kfree(priv);
 
 	return 0;
 }
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 82a628f..35c5208 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -209,14 +209,18 @@
 	return (int)irq_state->intsts0 & CTSQ_MASK;
 }
 
-static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
-				      struct usbhs_irq_state *state)
+static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
+				     struct usbhs_irq_state *state)
 {
 	struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+	u16 intenb0, intenb1;
 
 	state->intsts0 = usbhs_read(priv, INTSTS0);
 	state->intsts1 = usbhs_read(priv, INTSTS1);
 
+	intenb0 = usbhs_read(priv, INTENB0);
+	intenb1 = usbhs_read(priv, INTENB1);
+
 	/* mask */
 	if (mod) {
 		state->brdysts = usbhs_read(priv, BRDYSTS);
@@ -226,6 +230,20 @@
 		state->bempsts &= mod->irq_bempsts;
 		state->brdysts &= mod->irq_brdysts;
 	}
+
+	/*
+	 * Check whether the irq enable registers and the irq status are set
+	 * when IRQF_SHARED is set.
+	 */
+	if (priv->irqflags & IRQF_SHARED) {
+		if (!(intenb0 & state->intsts0) &&
+		    !(intenb1 & state->intsts1) &&
+		    !(state->bempsts) &&
+		    !(state->brdysts))
+			return -EIO;
+	}
+
+	return 0;
 }
 
 /*
@@ -238,7 +256,8 @@
 	struct usbhs_priv *priv = data;
 	struct usbhs_irq_state irq_state;
 
-	usbhs_status_get_each_irq(priv, &irq_state);
+	if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
+		return IRQ_NONE;
 
 	/*
 	 * clear interrupt
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 325d291..76f4622 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -42,11 +42,6 @@
 
 	  If unsure, say N.
 
-config USB_EZUSB
-	bool "Functions for loading firmware on EZUSB chips"
-	help
-	    Say Y here if you need EZUSB device support.
-
 config USB_SERIAL_GENERIC
 	bool "USB Generic Serial Driver"
 	help
@@ -94,7 +89,7 @@
 
 config USB_SERIAL_WHITEHEAT
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
-	select USB_EZUSB
+	select USB_EZUSB_FX2
 	help
 	  Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
 	  USB to serial converter device.
@@ -281,7 +276,7 @@
 
 config USB_SERIAL_KEYSPAN_PDA
 	tristate "USB Keyspan PDA Single Port Serial Driver"
-	select USB_EZUSB
+	select USB_EZUSB_FX2
 	help
 	  Say Y here if you want to use a Keyspan PDA single port USB to
 	  serial converter device.  This driver makes use of firmware
@@ -292,7 +287,7 @@
 
 config USB_SERIAL_KEYSPAN
 	tristate "USB Keyspan USA-xxx Serial Driver"
-	select USB_EZUSB
+	select USB_EZUSB_FX2
 	---help---
 	  Say Y here if you want to use Keyspan USB to serial converter
 	  devices.  This driver makes use of Keyspan's official firmware
@@ -596,7 +591,7 @@
 
 config USB_SERIAL_XIRCOM
 	tristate "USB Xircom / Entregra Single Port Serial Driver"
-	select USB_EZUSB
+	select USB_EZUSB_FX2
 	help
 	  Say Y here if you want to use a Xircom or Entregra single port USB to
 	  serial converter device.  This driver makes use of firmware
@@ -660,6 +655,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called zio.
 
+config USB_SERIAL_ZTE
+	tristate "ZTE USB serial driver"
+	help
+	  Say Y here if you want to use a ZTE USB to serial device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zte.
+
 config USB_SERIAL_SSU100
 	tristate "USB Quatech SSU-100 Single Port Serial Driver"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 1dc483a8..3b3e730 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -9,7 +9,6 @@
 usbserial-y := usb-serial.o generic.o bus.o
 
 usbserial-$(CONFIG_USB_SERIAL_CONSOLE)	+= console.o
-usbserial-$(CONFIG_USB_EZUSB)		+= ezusb.o
 
 obj-$(CONFIG_USB_SERIAL_AIRCABLE)		+= aircable.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
@@ -63,3 +62,4 @@
 obj-$(CONFIG_USB_SERIAL_XIRCOM)			+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)		+= vivopay-serial.o
 obj-$(CONFIG_USB_SERIAL_ZIO)			+= zio.o
+obj-$(CONFIG_USB_SERIAL_ZTE)			+= zte_ev.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index d634e66..54e1bb6 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -52,8 +52,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static bool debug;
-
 /* Vendor and Product ID */
 #define AIRCABLE_VID		0x16CA
 #define AIRCABLE_USB_PID	0x1502
@@ -196,6 +194,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 3b98fb7..cf2522c 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -37,7 +37,6 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 
-static bool debug;
 /*
  * Version information
  */
@@ -650,8 +649,7 @@
 		/*
 		 * Not sure what this data meant...
 		 */
-		usb_serial_debug_data(debug, &port->dev,
-				      __func__,
+		usb_serial_debug_data(&port->dev, __func__,
 				      urb->actual_length,
 				      urb->transfer_buffer);
 		break;
@@ -750,9 +748,6 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debug");
-
 /*
  * The following describes what I learned from studying the old
  * ark3116.c driver, disassembling the windows driver, and some lucky
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a46df73..9944942 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -37,8 +37,6 @@
 #include <linux/usb/serial.h>
 #include "belkin_sa.h"
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -206,8 +204,7 @@
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-					urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	/* Handle known interrupt data */
 	/* ignore data[0] and data[1] */
@@ -515,6 +512,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index cabd1b1..e9c7046 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -70,8 +70,6 @@
 #define CH341_NBREAK_BITS_REG2 0x40
 
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x4348, 0x5523) },
 	{ USB_DEVICE(0x1a86, 0x7523) },
@@ -93,8 +91,9 @@
 			     u16 value, u16 index)
 {
 	int r;
-	dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
-		(int)request, (int)value, (int)index);
+
+	dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n",
+		USB_DIR_OUT|0x40, (int)request, (int)value, (int)index);
 
 	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
 			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
@@ -108,8 +107,10 @@
 			    char *buf, unsigned bufsize)
 {
 	int r;
-	dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
-		(int)request, (int)value, (int)index, buf, (int)bufsize);
+
+	dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n",
+		USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf,
+		(int)bufsize);
 
 	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
 			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -320,7 +321,7 @@
 	if (r)
 		goto out;
 
-	dbg("%s - submitting interrupt urb", __func__);
+	dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__);
 	r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (r) {
 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -390,19 +391,19 @@
 				__func__, r);
 		goto out;
 	}
-	dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x",
-			__func__, break_reg[0], break_reg[1]);
+	dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n",
+		__func__, break_reg[0], break_reg[1]);
 	if (break_state != 0) {
-		dbg("%s - Enter break state requested", __func__);
+		dev_dbg(&port->dev, "%s - Enter break state requested\n", __func__);
 		break_reg[0] &= ~CH341_NBREAK_BITS_REG1;
 		break_reg[1] &= ~CH341_NBREAK_BITS_REG2;
 	} else {
-		dbg("%s - Leave break state requested", __func__);
+		dev_dbg(&port->dev, "%s - Leave break state requested\n", __func__);
 		break_reg[0] |= CH341_NBREAK_BITS_REG1;
 		break_reg[1] |= CH341_NBREAK_BITS_REG2;
 	}
-	dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x",
-			__func__, break_reg[0], break_reg[1]);
+	dev_dbg(&port->dev, "%s - New ch341 break register contents - reg1: %x, reg2: %x\n",
+		__func__, break_reg[0], break_reg[1]);
 	reg_contents = get_unaligned_le16(break_reg);
 	r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG,
 			ch341_break_reg, reg_contents);
@@ -451,16 +452,16 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    urb->status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
+			__func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    urb->status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
+			__func__, urb->status);
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
+	usb_serial_debug_data(&port->dev, __func__,
 			      urb->actual_length, urb->transfer_buffer);
 
 	if (actual_length >= 4) {
@@ -536,15 +537,16 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd);
 
 	switch (cmd) {
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number);
 		return wait_modem_info(port, arg);
 
 	default:
-		dbg("%s not supported = 0x%04x", __func__, cmd);
+		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
 		break;
 	}
 
@@ -572,7 +574,7 @@
 		  | ((status & CH341_BIT_RI)	? TIOCM_RI  : 0)
 		  | ((status & CH341_BIT_DCD)	? TIOCM_CD  : 0);
 
-	dbg("%s - result = %x", __func__, result);
+	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
 
 	return result;
 }
@@ -617,6 +619,3 @@
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 9a56428..5f3bcd3 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -20,8 +22,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
-
 struct usbcons_info {
 	int			magic;
 	int			break_flag;
@@ -68,8 +68,6 @@
 	struct tty_struct *tty = NULL;
 	struct ktermios dummy;
 
-	dbg("%s", __func__);
-
 	if (options) {
 		baud = simple_strtoul(options, NULL, 10);
 		s = options;
@@ -113,8 +111,7 @@
 	serial = usb_serial_get_by_index(co->index);
 	if (serial == NULL) {
 		/* no device is connected yet, sorry :( */
-		printk(KERN_ERR "No USB device connected to ttyUSB%i\n",
-		       co->index);
+		pr_err("No USB device connected to ttyUSB%i\n", co->index);
 		return -ENODEV;
 	}
 
@@ -213,10 +210,10 @@
 	if (count == 0)
 		return;
 
-	dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
+	pr_debug("%s - port %d, %d byte(s)\n", __func__, port->number, count);
 
 	if (!port->port.console) {
-		dbg("%s - port not opened", __func__);
+		pr_debug("%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -237,7 +234,7 @@
 			retval = serial->type->write(NULL, port, buf, i);
 		else
 			retval = usb_serial_generic_write(NULL, port, buf, i);
-		dbg("%s - return value : %d", __func__, retval);
+		pr_debug("%s - return value : %d\n", __func__, retval);
 		if (lf) {
 			/* append CR after LF */
 			unsigned char cr = 13;
@@ -247,7 +244,7 @@
 			else
 				retval = usb_serial_generic_write(NULL,
 								port, &cr, 1);
-			dbg("%s - return value : %d", __func__, retval);
+			pr_debug("%s - return value : %d\n", __func__, retval);
 		}
 		buf += i;
 		count -= i;
@@ -284,10 +281,8 @@
 	}
 }
 
-void usb_serial_console_init(int serial_debug, int minor)
+void usb_serial_console_init(int minor)
 {
-	debug = serial_debug;
-
 	if (minor == 0) {
 		/*
 		 * Call register_console() if this is the first device plugged
@@ -302,7 +297,7 @@
 		 * register_console). console_write() is called immediately
 		 * from register_console iff CON_PRINTBUFFER is set in flags.
 		 */
-		dbg("registering the USB serial console.");
+		pr_debug("registering the USB serial console.\n");
 		register_console(&usbcons);
 	}
 }
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ba5e07e1..28af5ac 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -52,8 +52,6 @@
 static void cp210x_release(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
 	{ USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
@@ -304,9 +302,8 @@
 	kfree(buf);
 
 	if (result != size) {
-		dbg("%s - Unable to send config request, "
-				"request=0x%x size=%d result=%d",
-				__func__, request, size, result);
+		dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n",
+			__func__, request, size, result);
 		if (result > 0)
 			result = -EPROTO;
 
@@ -361,9 +358,8 @@
 	kfree(buf);
 
 	if ((size > 2 && result != size) || result < 0) {
-		dbg("%s - Unable to send request, "
-				"request=0x%x size=%d result=%d",
-				__func__, request, size, result);
+		dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n",
+			__func__, request, size, result);
 		if (result > 0)
 			result = -EPROTO;
 
@@ -487,13 +483,14 @@
 static void cp210x_get_termios_port(struct usb_serial_port *port,
 	unsigned int *cflagp, unsigned int *baudp)
 {
+	struct device *dev = &port->dev;
 	unsigned int cflag, modem_ctl[4];
 	unsigned int baud;
 	unsigned int bits;
 
 	cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
 
-	dbg("%s - baud rate = %d", __func__, baud);
+	dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);
 	*baudp = baud;
 
 	cflag = *cflagp;
@@ -502,31 +499,30 @@
 	cflag &= ~CSIZE;
 	switch (bits & BITS_DATA_MASK) {
 	case BITS_DATA_5:
-		dbg("%s - data bits = 5", __func__);
+		dev_dbg(dev, "%s - data bits = 5\n", __func__);
 		cflag |= CS5;
 		break;
 	case BITS_DATA_6:
-		dbg("%s - data bits = 6", __func__);
+		dev_dbg(dev, "%s - data bits = 6\n", __func__);
 		cflag |= CS6;
 		break;
 	case BITS_DATA_7:
-		dbg("%s - data bits = 7", __func__);
+		dev_dbg(dev, "%s - data bits = 7\n", __func__);
 		cflag |= CS7;
 		break;
 	case BITS_DATA_8:
-		dbg("%s - data bits = 8", __func__);
+		dev_dbg(dev, "%s - data bits = 8\n", __func__);
 		cflag |= CS8;
 		break;
 	case BITS_DATA_9:
-		dbg("%s - data bits = 9 (not supported, using 8 data bits)",
-								__func__);
+		dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__);
 		cflag |= CS8;
 		bits &= ~BITS_DATA_MASK;
 		bits |= BITS_DATA_8;
 		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
 		break;
 	default:
-		dbg("%s - Unknown number of data bits, using 8", __func__);
+		dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);
 		cflag |= CS8;
 		bits &= ~BITS_DATA_MASK;
 		bits |= BITS_DATA_8;
@@ -536,29 +532,29 @@
 
 	switch (bits & BITS_PARITY_MASK) {
 	case BITS_PARITY_NONE:
-		dbg("%s - parity = NONE", __func__);
+		dev_dbg(dev, "%s - parity = NONE\n", __func__);
 		cflag &= ~PARENB;
 		break;
 	case BITS_PARITY_ODD:
-		dbg("%s - parity = ODD", __func__);
+		dev_dbg(dev, "%s - parity = ODD\n", __func__);
 		cflag |= (PARENB|PARODD);
 		break;
 	case BITS_PARITY_EVEN:
-		dbg("%s - parity = EVEN", __func__);
+		dev_dbg(dev, "%s - parity = EVEN\n", __func__);
 		cflag &= ~PARODD;
 		cflag |= PARENB;
 		break;
 	case BITS_PARITY_MARK:
-		dbg("%s - parity = MARK", __func__);
+		dev_dbg(dev, "%s - parity = MARK\n", __func__);
 		cflag |= (PARENB|PARODD|CMSPAR);
 		break;
 	case BITS_PARITY_SPACE:
-		dbg("%s - parity = SPACE", __func__);
+		dev_dbg(dev, "%s - parity = SPACE\n", __func__);
 		cflag &= ~PARODD;
 		cflag |= (PARENB|CMSPAR);
 		break;
 	default:
-		dbg("%s - Unknown parity mode, disabling parity", __func__);
+		dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);
 		cflag &= ~PARENB;
 		bits &= ~BITS_PARITY_MASK;
 		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
@@ -568,21 +564,19 @@
 	cflag &= ~CSTOPB;
 	switch (bits & BITS_STOP_MASK) {
 	case BITS_STOP_1:
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(dev, "%s - stop bits = 1\n", __func__);
 		break;
 	case BITS_STOP_1_5:
-		dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)",
-								__func__);
+		dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);
 		bits &= ~BITS_STOP_MASK;
 		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
 		break;
 	case BITS_STOP_2:
-		dbg("%s - stop bits = 2", __func__);
+		dev_dbg(dev, "%s - stop bits = 2\n", __func__);
 		cflag |= CSTOPB;
 		break;
 	default:
-		dbg("%s - Unknown number of stop bits, using 1 stop bit",
-								__func__);
+		dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);
 		bits &= ~BITS_STOP_MASK;
 		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
 		break;
@@ -590,10 +584,10 @@
 
 	cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
 	if (modem_ctl[0] & 0x0008) {
-		dbg("%s - flow control = CRTSCTS", __func__);
+		dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
 		cflag |= CRTSCTS;
 	} else {
-		dbg("%s - flow control = NONE", __func__);
+		dev_dbg(dev, "%s - flow control = NONE\n", __func__);
 		cflag &= ~CRTSCTS;
 	}
 
@@ -640,7 +634,7 @@
 	 */
 	baud = cp210x_quantise_baudrate(baud);
 
-	dbg("%s - setting baud rate to %u", __func__, baud);
+	dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud);
 	if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
 							sizeof(baud))) {
 		dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
@@ -656,11 +650,12 @@
 static void cp210x_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
+	struct device *dev = &port->dev;
 	unsigned int cflag, old_cflag;
 	unsigned int bits;
 	unsigned int modem_ctl[4];
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(dev, "%s - port %d\n", __func__, port->number);
 
 	if (!tty)
 		return;
@@ -678,34 +673,31 @@
 		switch (cflag & CSIZE) {
 		case CS5:
 			bits |= BITS_DATA_5;
-			dbg("%s - data bits = 5", __func__);
+			dev_dbg(dev, "%s - data bits = 5\n", __func__);
 			break;
 		case CS6:
 			bits |= BITS_DATA_6;
-			dbg("%s - data bits = 6", __func__);
+			dev_dbg(dev, "%s - data bits = 6\n", __func__);
 			break;
 		case CS7:
 			bits |= BITS_DATA_7;
-			dbg("%s - data bits = 7", __func__);
+			dev_dbg(dev, "%s - data bits = 7\n", __func__);
 			break;
 		case CS8:
 			bits |= BITS_DATA_8;
-			dbg("%s - data bits = 8", __func__);
+			dev_dbg(dev, "%s - data bits = 8\n", __func__);
 			break;
 		/*case CS9:
 			bits |= BITS_DATA_9;
-			dbg("%s - data bits = 9", __func__);
+			dev_dbg(dev, "%s - data bits = 9\n", __func__);
 			break;*/
 		default:
-			dbg("cp210x driver does not "
-					"support the number of bits requested,"
-					" using 8 bit mode");
+			dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n");
 				bits |= BITS_DATA_8;
 				break;
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
-			dbg("Number of data bits requested "
-					"not supported by device");
+			dev_dbg(dev, "Number of data bits requested not supported by device\n");
 	}
 
 	if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
@@ -714,25 +706,25 @@
 		bits &= ~BITS_PARITY_MASK;
 		if (cflag & PARENB) {
 			if (cflag & CMSPAR) {
-			    if (cflag & PARODD) {
-				    bits |= BITS_PARITY_MARK;
-				    dbg("%s - parity = MARK", __func__);
-			    } else {
-				    bits |= BITS_PARITY_SPACE;
-				    dbg("%s - parity = SPACE", __func__);
-			    }
+				if (cflag & PARODD) {
+					bits |= BITS_PARITY_MARK;
+					dev_dbg(dev, "%s - parity = MARK\n", __func__);
+				} else {
+					bits |= BITS_PARITY_SPACE;
+					dev_dbg(dev, "%s - parity = SPACE\n", __func__);
+				}
 			} else {
-			    if (cflag & PARODD) {
-				    bits |= BITS_PARITY_ODD;
-				    dbg("%s - parity = ODD", __func__);
-			    } else {
-				    bits |= BITS_PARITY_EVEN;
-				    dbg("%s - parity = EVEN", __func__);
-			    }
+				if (cflag & PARODD) {
+					bits |= BITS_PARITY_ODD;
+					dev_dbg(dev, "%s - parity = ODD\n", __func__);
+				} else {
+					bits |= BITS_PARITY_EVEN;
+					dev_dbg(dev, "%s - parity = EVEN\n", __func__);
+				}
 			}
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
-			dbg("Parity mode not supported by device");
+			dev_dbg(dev, "Parity mode not supported by device\n");
 	}
 
 	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
@@ -740,37 +732,36 @@
 		bits &= ~BITS_STOP_MASK;
 		if (cflag & CSTOPB) {
 			bits |= BITS_STOP_2;
-			dbg("%s - stop bits = 2", __func__);
+			dev_dbg(dev, "%s - stop bits = 2\n", __func__);
 		} else {
 			bits |= BITS_STOP_1;
-			dbg("%s - stop bits = 1", __func__);
+			dev_dbg(dev, "%s - stop bits = 1\n", __func__);
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
-			dbg("Number of stop bits requested "
-					"not supported by device");
+			dev_dbg(dev, "Number of stop bits requested not supported by device\n");
 	}
 
 	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
 		cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
-		dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
-				__func__, modem_ctl[0], modem_ctl[1],
-				modem_ctl[2], modem_ctl[3]);
+		dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
+			__func__, modem_ctl[0], modem_ctl[1],
+			modem_ctl[2], modem_ctl[3]);
 
 		if (cflag & CRTSCTS) {
 			modem_ctl[0] &= ~0x7B;
 			modem_ctl[0] |= 0x09;
 			modem_ctl[1] = 0x80;
-			dbg("%s - flow control = CRTSCTS", __func__);
+			dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
 		} else {
 			modem_ctl[0] &= ~0x7B;
 			modem_ctl[0] |= 0x01;
 			modem_ctl[1] |= 0x40;
-			dbg("%s - flow control = NONE", __func__);
+			dev_dbg(dev, "%s - flow control = NONE\n", __func__);
 		}
 
-		dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
-				__func__, modem_ctl[0], modem_ctl[1],
-				modem_ctl[2], modem_ctl[3]);
+		dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
+			__func__, modem_ctl[0], modem_ctl[1],
+			modem_ctl[2], modem_ctl[3]);
 		cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16);
 	}
 
@@ -805,7 +796,7 @@
 		control |= CONTROL_WRITE_DTR;
 	}
 
-	dbg("%s - control = 0x%.4x", __func__, control);
+	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
 
 	return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
 }
@@ -833,7 +824,7 @@
 		|((control & CONTROL_RING)? TIOCM_RI  : 0)
 		|((control & CONTROL_DCD) ? TIOCM_CD  : 0);
 
-	dbg("%s - control = 0x%.2x", __func__, control);
+	dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control);
 
 	return result;
 }
@@ -847,8 +838,8 @@
 		state = BREAK_OFF;
 	else
 		state = BREAK_ON;
-	dbg("%s - turning break %s", __func__,
-			state == BREAK_OFF ? "off" : "on");
+	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
+		state == BREAK_OFF ? "off" : "on");
 	cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
 }
 
@@ -865,7 +856,6 @@
 		if (!port_priv)
 			return -ENOMEM;
 
-		memset(port_priv, 0x00, sizeof(*port_priv));
 		port_priv->bInterfaceNumber =
 		    serial->interface->cur_altsetting->desc.bInterfaceNumber;
 
@@ -892,6 +882,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable verbose debugging messages");
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 3aa0b53..2a7aecc 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -43,8 +43,6 @@
 
 #define CYBERJACK_LOCAL_BUF_SIZE 32
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -136,7 +134,8 @@
 		if (result)
 			dev_err(&serial->dev->dev,
 				"usb_submit_urb(read int) failed\n");
-		dbg("%s - usb_submit_urb(int urb)", __func__);
+		dev_dbg(&serial->dev->dev, "%s - usb_submit_urb(int urb)\n",
+			__func__);
 	}
 
 	return 0;
@@ -167,7 +166,7 @@
 	unsigned long flags;
 	int result = 0;
 
-	dbg("%s - usb_clear_halt", __func__);
+	dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__);
 	usb_clear_halt(port->serial->dev, port->write_urb->pipe);
 
 	priv = usb_get_serial_port_data(port);
@@ -192,18 +191,19 @@
 static int cyberjack_write(struct tty_struct *tty,
 	struct usb_serial_port *port, const unsigned char *buf, int count)
 {
+	struct device *dev = &port->dev;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 	int result;
 	int wrexpected;
 
 	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
+		dev_dbg(dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
 	if (!test_and_clear_bit(0, &port->write_urbs_free)) {
-		dbg("%s - already writing", __func__);
+		dev_dbg(dev, "%s - already writing\n", __func__);
 		return 0;
 	}
 
@@ -220,13 +220,12 @@
 	/* Copy data */
 	memcpy(priv->wrbuf + priv->wrfilled, buf, count);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-		priv->wrbuf + priv->wrfilled);
+	usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled);
 	priv->wrfilled += count;
 
 	if (priv->wrfilled >= 3) {
 		wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
-		dbg("%s - expected data: %d", __func__, wrexpected);
+		dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected);
 	} else
 		wrexpected = sizeof(priv->wrbuf);
 
@@ -234,7 +233,7 @@
 		/* We have enough data to begin transmission */
 		int length;
 
-		dbg("%s - transmitting data (frame 1)", __func__);
+		dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__);
 		length = (wrexpected > port->bulk_out_size) ?
 					port->bulk_out_size : wrexpected;
 
@@ -258,11 +257,11 @@
 			return 0;
 		}
 
-		dbg("%s - priv->wrsent=%d", __func__, priv->wrsent);
-		dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled);
+		dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
+		dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
 
 		if (priv->wrsent >= priv->wrfilled) {
-			dbg("%s - buffer cleaned", __func__);
+			dev_dbg(dev, "%s - buffer cleaned\n", __func__);
 			memset(priv->wrbuf, 0, sizeof(priv->wrbuf));
 			priv->wrfilled = 0;
 			priv->wrsent = 0;
@@ -284,6 +283,7 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	unsigned char *data = urb->transfer_buffer;
 	int status = urb->status;
 	int result;
@@ -292,8 +292,7 @@
 	if (status)
 		return;
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
+	usb_serial_debug_data(dev, __func__, urb->actual_length, data);
 
 	/* React only to interrupts signaling a bulk_in transfer */
 	if (urb->actual_length == 4 && data[0] == 0x01) {
@@ -307,7 +306,7 @@
 		old_rdtodo = priv->rdtodo;
 
 		if (old_rdtodo + size < old_rdtodo) {
-			dbg("To many bulk_in urbs to do.");
+			dev_dbg(dev, "To many bulk_in urbs to do.\n");
 			spin_unlock(&priv->lock);
 			goto resubmit;
 		}
@@ -315,17 +314,16 @@
 		/* "+=" is probably more fault tollerant than "=" */
 		priv->rdtodo += size;
 
-		dbg("%s - rdtodo: %d", __func__, priv->rdtodo);
+		dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo);
 
 		spin_unlock(&priv->lock);
 
 		if (!old_rdtodo) {
 			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 			if (result)
-				dev_err(&port->dev, "%s - failed resubmitting "
-					"read urb, error %d\n",
+				dev_err(dev, "%s - failed resubmitting read urb, error %d\n",
 					__func__, result);
-			dbg("%s - usb_submit_urb(read urb)", __func__);
+			dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__);
 		}
 	}
 
@@ -333,30 +331,30 @@
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result)
 		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
-	dbg("%s - usb_submit_urb(int urb)", __func__);
+	dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__);
 }
 
 static void cyberjack_read_bulk_callback(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	short todo;
 	int result;
 	int status = urb->status;
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
+	usb_serial_debug_data(dev, __func__, urb->actual_length, data);
 	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
+		dev_dbg(dev, "%s - nonzero read bulk status received: %d\n",
+			__func__, status);
 		return;
 	}
 
 	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
-		dbg("%s - ignoring since device not open", __func__);
+		dev_dbg(dev, "%s - ignoring since device not open\n", __func__);
 		return;
 	}
 	if (urb->actual_length) {
@@ -376,15 +374,15 @@
 
 	spin_unlock(&priv->lock);
 
-	dbg("%s - rdtodo: %d", __func__, todo);
+	dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo);
 
 	/* Continue to read if we have still urbs to do. */
 	if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) {
 		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (result)
-			dev_err(&port->dev, "%s - failed resubmitting read "
-				"urb, error %d\n", __func__, result);
-		dbg("%s - usb_submit_urb(read urb)", __func__);
+			dev_err(dev, "%s - failed resubmitting read urb, error %d\n",
+				__func__, result);
+		dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__);
 	}
 }
 
@@ -392,12 +390,13 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	int status = urb->status;
 
 	set_bit(0, &port->write_urbs_free);
 	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
+			__func__, status);
 		return;
 	}
 
@@ -407,7 +406,7 @@
 	if (priv->wrfilled) {
 		int length, blksize, result;
 
-		dbg("%s - transmitting data (frame n)", __func__);
+		dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__);
 
 		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
 			port->bulk_out_size : (priv->wrfilled - priv->wrsent);
@@ -422,8 +421,7 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (result) {
-			dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
+			dev_err(dev, "%s - failed submitting write urb, error %d\n",
 				__func__, result);
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled = 0;
@@ -431,14 +429,14 @@
 			goto exit;
 		}
 
-		dbg("%s - priv->wrsent=%d", __func__, priv->wrsent);
-		dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled);
+		dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
+		dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
 
 		blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
 
 		if (priv->wrsent >= priv->wrfilled ||
 					priv->wrsent >= blksize) {
-			dbg("%s - buffer cleaned", __func__);
+			dev_dbg(dev, "%s - buffer cleaned\n", __func__);
 			memset(priv->wrbuf, 0, sizeof(priv->wrbuf));
 			priv->wrfilled = 0;
 			priv->wrsent = 0;
@@ -456,6 +454,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index be34f15..1befce2 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -46,7 +46,6 @@
 #include "cypress_m8.h"
 
 
-static bool debug;
 static bool stats;
 static int interval;
 static bool unstable_bauds;
@@ -263,8 +262,9 @@
 		 * safest speed for a part like that.
 		 */
 		if (new_rate > 4800) {
-			dbg("%s - failed setting baud rate, device incapable "
-			    "speed %d", __func__, new_rate);
+			dev_dbg(&port->dev,
+				"%s - failed setting baud rate, device incapable speed %d\n",
+				__func__, new_rate);
 			return -1;
 		}
 	}
@@ -274,8 +274,9 @@
 			/* 300 and 600 baud rates are supported under
 			 * the generic firmware, but are not used with
 			 * NMEA and SiRF protocols */
-			dbg("%s - failed setting baud rate, unsupported speed "
-			    "of %d on Earthmate GPS", __func__, new_rate);
+			dev_dbg(&port->dev,
+				"%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS",
+				__func__, new_rate);
 			return -1;
 		}
 		break;
@@ -294,6 +295,7 @@
 {
 	int new_baudrate = 0, retval = 0, tries = 0;
 	struct cypress_private *priv;
+	struct device *dev = &port->dev;
 	u8 *feature_buffer;
 	const unsigned int feature_len = 5;
 	unsigned long flags;
@@ -312,16 +314,16 @@
 		/* 0 means 'Hang up' so doesn't change the true bit rate */
 		new_baudrate = priv->baud_rate;
 		if (baud_rate && baud_rate != priv->baud_rate) {
-			dbg("%s - baud rate is changing", __func__);
+			dev_dbg(dev, "%s - baud rate is changing\n", __func__);
 			retval = analyze_baud_rate(port, baud_rate);
 			if (retval >= 0) {
 				new_baudrate = retval;
-				dbg("%s - New baud rate set to %d",
-				    __func__, new_baudrate);
+				dev_dbg(dev, "%s - New baud rate set to %d\n",
+					__func__, new_baudrate);
 			}
 		}
-		dbg("%s - baud rate is being sent as %d",
-					__func__, new_baudrate);
+		dev_dbg(dev, "%s - baud rate is being sent as %d\n", __func__,
+			new_baudrate);
 
 		/* fill the feature_buffer with new configuration */
 		put_unaligned_le32(new_baudrate, feature_buffer);
@@ -333,9 +335,8 @@
 		/* 1 bit gap */
 		feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */
 
-		dbg("%s - device is being sent this feature report:",
-								__func__);
-		dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__,
+		dev_dbg(dev, "%s - device is being sent this feature report:\n", __func__);
+		dev_dbg(dev, "%s - %02X - %02X - %02X - %02X - %02X\n", __func__,
 			feature_buffer[0], feature_buffer[1],
 			feature_buffer[2], feature_buffer[3],
 			feature_buffer[4]);
@@ -355,8 +356,8 @@
 			 retval != -ENODEV);
 
 		if (retval != feature_len) {
-			dev_err(&port->dev, "%s - failed sending serial "
-				"line settings - %d\n", __func__, retval);
+			dev_err(dev, "%s - failed sending serial line settings - %d\n",
+				__func__, retval);
 			cypress_set_dead(port);
 		} else {
 			spin_lock_irqsave(&priv->lock, flags);
@@ -377,7 +378,7 @@
 			retval = -ENOTTY;
 			goto out;
 		}
-		dbg("%s - retreiving serial line settings", __func__);
+		dev_dbg(dev, "%s - retreiving serial line settings\n", __func__);
 		do {
 			retval = usb_control_msg(port->serial->dev,
 					usb_rcvctrlpipe(port->serial->dev, 0),
@@ -392,8 +393,8 @@
 						&& retval != -ENODEV);
 
 		if (retval != feature_len) {
-			dev_err(&port->dev, "%s - failed to retrieve serial "
-				"line settings - %d\n", __func__, retval);
+			dev_err(dev, "%s - failed to retrieve serial line settings - %d\n",
+				__func__, retval);
 			cypress_set_dead(port);
 			goto out;
 		} else {
@@ -474,14 +475,14 @@
 	if (interval > 0) {
 		priv->write_urb_interval = interval;
 		priv->read_urb_interval = interval;
-		dbg("%s - port %d read & write intervals forced to %d",
-		    __func__, port->number, interval);
+		dev_dbg(&port->dev, "%s - read & write intervals forced to %d\n",
+			__func__, interval);
 	} else {
 		priv->write_urb_interval = port->interrupt_out_urb->interval;
 		priv->read_urb_interval = port->interrupt_in_urb->interval;
-		dbg("%s - port %d intervals: read=%d write=%d",
-		    __func__, port->number,
-		    priv->read_urb_interval, priv->write_urb_interval);
+		dev_dbg(&port->dev, "%s - intervals: read=%d write=%d\n",
+			__func__, priv->read_urb_interval,
+			priv->write_urb_interval);
 	}
 	usb_set_serial_port_data(port, priv);
 
@@ -495,8 +496,7 @@
 	struct usb_serial_port *port = serial->port[0];
 
 	if (generic_startup(serial)) {
-		dbg("%s - Failed setting up port %d", __func__,
-				port->number);
+		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__);
 		return 1;
 	}
 
@@ -511,8 +511,9 @@
 		   handle GET_CONFIG requests; everything they've
 		   produced since that time crashes if this command is
 		   attempted :-( */
-		dbg("%s - Marking this device as unsafe for GET_CONFIG "
-		    "commands", __func__);
+		dev_dbg(&port->dev,
+			"%s - Marking this device as unsafe for GET_CONFIG commands\n",
+			__func__);
 		priv->get_cfg_unsafe = !0;
 	}
 
@@ -523,14 +524,14 @@
 static int cypress_hidcom_startup(struct usb_serial *serial)
 {
 	struct cypress_private *priv;
+	struct usb_serial_port *port = serial->port[0];
 
 	if (generic_startup(serial)) {
-		dbg("%s - Failed setting up port %d", __func__,
-				serial->port[0]->number);
+		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__);
 		return 1;
 	}
 
-	priv = usb_get_serial_port_data(serial->port[0]);
+	priv = usb_get_serial_port_data(port);
 	priv->chiptype = CT_CYPHIDCOM;
 
 	return 0;
@@ -540,14 +541,14 @@
 static int cypress_ca42v2_startup(struct usb_serial *serial)
 {
 	struct cypress_private *priv;
+	struct usb_serial_port *port = serial->port[0];
 
 	if (generic_startup(serial)) {
-		dbg("%s - Failed setting up port %d", __func__,
-				serial->port[0]->number);
+		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__);
 		return 1;
 	}
 
-	priv = usb_get_serial_port_data(serial->port[0]);
+	priv = usb_get_serial_port_data(port);
 	priv->chiptype = CT_CA42V2;
 
 	return 0;
@@ -649,7 +650,7 @@
 	kfifo_reset_out(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - stopping urbs", __func__);
+	dev_dbg(&port->dev, "%s - stopping urbs\n", __func__);
 	usb_kill_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
 
@@ -665,7 +666,7 @@
 {
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d, %d bytes", __func__, port->number, count);
+	dev_dbg(&port->dev, "%s - port %d, %d bytes\n", __func__, port->number, count);
 
 	/* line control commands, which need to be executed immediately,
 	   are not put into the buffer for obvious reasons.
@@ -691,17 +692,18 @@
 {
 	int count = 0, result, offset, actual_size;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	unsigned long flags;
 
 	if (!priv->comm_is_ok)
 		return;
 
-	dbg("%s - interrupt out size is %d", __func__,
-						port->interrupt_out_size);
+	dev_dbg(dev, "%s - interrupt out size is %d\n", __func__,
+		port->interrupt_out_size);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->write_urb_in_use) {
-		dbg("%s - can't write, urb in use", __func__);
+		dev_dbg(dev, "%s - can't write, urb in use\n", __func__);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
@@ -731,7 +733,7 @@
 
 	if (priv->cmd_ctrl) {
 		priv->cmd_count++;
-		dbg("%s - line control command being issued", __func__);
+		dev_dbg(dev, "%s - line control command being issued\n", __func__);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		goto send;
 	} else
@@ -753,7 +755,7 @@
 		port->interrupt_out_buffer[0] |= count;
 	}
 
-	dbg("%s - count is %d", __func__, count);
+	dev_dbg(dev, "%s - count is %d\n", __func__, count);
 
 send:
 	spin_lock_irqsave(&priv->lock, flags);
@@ -766,9 +768,8 @@
 		actual_size = count +
 			      (priv->pkt_fmt == packet_format_1 ? 2 : 1);
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-		port->interrupt_out_size,
-		port->interrupt_out_urb->transfer_buffer);
+	usb_serial_debug_data(dev, __func__, port->interrupt_out_size,
+			      port->interrupt_out_urb->transfer_buffer);
 
 	usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
 		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
@@ -807,7 +808,7 @@
 	room = kfifo_avail(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -832,7 +833,7 @@
 		| ((status & UART_RI)         ? TIOCM_RI  : 0)
 		| ((status & UART_CD)         ? TIOCM_CD  : 0);
 
-	dbg("%s - result = %x", __func__, result);
+	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
 
 	return result;
 }
@@ -867,7 +868,7 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd);
 
 	switch (cmd) {
 	/* This code comes from drivers/char/serial.c and ftdi_sio.c */
@@ -902,7 +903,7 @@
 	default:
 		break;
 	}
-	dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
+	dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd);
 	return -ENOIOCTLCMD;
 } /* cypress_ioctl */
 
@@ -911,6 +912,7 @@
 	struct usb_serial_port *port, struct ktermios *old_termios)
 {
 	struct cypress_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	int data_bits, stop_bits, parity_type, parity_enable;
 	unsigned cflag, iflag;
 	unsigned long flags;
@@ -984,23 +986,21 @@
 		data_bits = 3;
 		break;
 	default:
-		dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n",
-			__func__);
+		dev_err(dev, "%s - CSIZE was set, but not CS5-CS8\n", __func__);
 		data_bits = 3;
 	}
 	spin_lock_irqsave(&priv->lock, flags);
 	oldlines = priv->line_control;
 	if ((cflag & CBAUD) == B0) {
 		/* drop dtr and rts */
-		dbg("%s - dropping the lines, baud rate 0bps", __func__);
+		dev_dbg(dev, "%s - dropping the lines, baud rate 0bps\n", __func__);
 		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
 	} else
 		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
-			"%d data_bits (+5)", __func__, stop_bits,
-			parity_enable, parity_type, data_bits);
+	dev_dbg(dev, "%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)\n",
+		__func__, stop_bits, parity_enable, parity_type, data_bits);
 
 	cypress_serial_control(tty, port, tty_get_baud_rate(tty),
 			data_bits, stop_bits,
@@ -1017,8 +1017,7 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) {
-		dbg("Using custom termios settings for a baud rate of "
-				"4800bps.");
+		dev_dbg(dev, "Using custom termios settings for a baud rate of 4800bps.\n");
 		/* define custom termios settings for NMEA protocol */
 
 		tty->termios.c_iflag /* input modes - */
@@ -1067,7 +1066,7 @@
 	chars = kfifo_len(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 }
 
@@ -1112,6 +1111,7 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &urb->dev->dev;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned long flags;
@@ -1135,16 +1135,15 @@
 		/* FALLS THROUGH */
 	default:
 		/* something ugly is going on... */
-		dev_err(&urb->dev->dev,
-			"%s - unexpected nonzero read status received: %d\n",
-							__func__, status);
+		dev_err(dev, "%s - unexpected nonzero read status received: %d\n",
+			__func__, status);
 		cypress_set_dead(port);
 		return;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->rx_flags & THROTTLED) {
-		dbg("%s - now throttling", __func__);
+		dev_dbg(dev, "%s - now throttling\n", __func__);
 		priv->rx_flags |= ACTUALLY_THROTTLED;
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
@@ -1153,7 +1152,7 @@
 
 	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
-		dbg("%s - bad tty pointer - exiting", __func__);
+		dev_dbg(dev, "%s - bad tty pointer - exiting\n", __func__);
 		return;
 	}
 
@@ -1180,13 +1179,13 @@
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	if (result < bytes) {
-		dbg("%s - wrong packet size - received %d bytes but packet "
-		    "said %d bytes", __func__, result, bytes);
+		dev_dbg(dev,
+			"%s - wrong packet size - received %d bytes but packet said %d bytes\n",
+			__func__, result, bytes);
 		goto continue_read;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	/* check to see if status has changed */
@@ -1202,7 +1201,7 @@
 	 * though */
 	if (tty && !(tty->termios.c_cflag & CLOCAL) &&
 			!(priv->current_status & UART_CD)) {
-		dbg("%s - calling hangup", __func__);
+		dev_dbg(dev, "%s - calling hangup\n", __func__);
 		tty_hangup(tty);
 		goto continue_read;
 	}
@@ -1215,7 +1214,7 @@
 	if (priv->current_status & CYP_ERROR) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		tty_flag = TTY_PARITY;
-		dbg("%s - Parity Error detected", __func__);
+		dev_dbg(dev, "%s - Parity Error detected\n", __func__);
 	} else
 		spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1246,9 +1245,8 @@
 				priv->read_urb_interval);
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 		if (result && result != -EPERM) {
-			dev_err(&urb->dev->dev, "%s - failed resubmitting "
-					"read urb, error %d\n", __func__,
-					result);
+			dev_err(dev, "%s - failed resubmitting read urb, error %d\n",
+				__func__, result);
 			cypress_set_dead(port);
 		}
 	}
@@ -1259,6 +1257,7 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &urb->dev->dev;
 	int result;
 	int status = urb->status;
 
@@ -1270,8 +1269,8 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-						__func__, status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		priv->write_urb_in_use = 0;
 		return;
 	case -EPIPE: /* no break needed; clear halt and resubmit */
@@ -1279,21 +1278,19 @@
 			break;
 		usb_clear_halt(port->serial->dev, 0x02);
 		/* error in the urb, so we have to resubmit it */
-		dbg("%s - nonzero write bulk status received: %d",
+		dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
 			__func__, status);
 		port->interrupt_out_urb->transfer_buffer_length = 1;
 		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
 		if (!result)
 			return;
-		dev_err(&urb->dev->dev,
-			"%s - failed resubmitting write urb, error %d\n",
-							__func__, result);
+		dev_err(dev, "%s - failed resubmitting write urb, error %d\n",
+			__func__, result);
 		cypress_set_dead(port);
 		break;
 	default:
-		dev_err(&urb->dev->dev,
-			 "%s - unexpected nonzero write status received: %d\n",
-							__func__, status);
+		dev_err(dev, "%s - unexpected nonzero write status received: %d\n",
+			__func__, status);
 		cypress_set_dead(port);
 		break;
 	}
@@ -1310,8 +1307,6 @@
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(stats, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(stats, "Enable statistics or not");
 module_param(interval, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index afd9d2e..c86f68c 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -249,10 +249,6 @@
 static int digi_read_oob_callback(struct urb *urb);
 
 
-/* Statics */
-
-static bool debug;
-
 static const struct usb_device_id id_table_combined[] = {
 	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
 	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
@@ -404,14 +400,15 @@
 static int digi_write_oob_command(struct usb_serial_port *port,
 	unsigned char *buf, int count, int interruptible)
 {
-
 	int ret = 0;
 	int len;
 	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
 	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
 	unsigned long flags = 0;
 
-	dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count);
+	dev_dbg(&port->dev,
+		"digi_write_oob_command: TOP: port=%d, count=%d\n",
+		oob_priv->dp_port_num, count);
 
 	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
 	while (count > 0) {
@@ -467,7 +464,7 @@
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
-	dbg("digi_write_inb_command: TOP: port=%d, count=%d",
+	dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
 		priv->dp_port_num, count);
 
 	if (timeout)
@@ -549,7 +546,8 @@
 	unsigned long flags = 0;
 
 
-	dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
+	dev_dbg(&port->dev,
+		"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
 		port_priv->dp_port_num, modem_signals);
 
 	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
@@ -687,6 +685,7 @@
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
 	struct digi_port *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	unsigned int iflag = tty->termios.c_iflag;
 	unsigned int cflag = tty->termios.c_cflag;
 	unsigned int old_iflag = old_termios->c_iflag;
@@ -697,7 +696,9 @@
 	int i = 0;
 	speed_t baud;
 
-	dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag);
+	dev_dbg(dev,
+		"digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x\n",
+		priv->dp_port_num, iflag, old_iflag, cflag, old_cflag);
 
 	/* set baud rate */
 	baud = tty_get_baud_rate(tty);
@@ -773,7 +774,8 @@
 		case CS7: arg = DIGI_WORD_SIZE_7; break;
 		case CS8: arg = DIGI_WORD_SIZE_8; break;
 		default:
-			dbg("digi_set_termios: can't handle word size %d",
+			dev_dbg(dev,
+				"digi_set_termios: can't handle word size %d\n",
 				(cflag&CSIZE));
 			break;
 		}
@@ -866,7 +868,7 @@
 	}
 	ret = digi_write_oob_command(port, buf, i, 1);
 	if (ret != 0)
-		dbg("digi_set_termios: write oob failed, ret=%d", ret);
+		dev_dbg(dev, "digi_set_termios: write oob failed, ret=%d\n", ret);
 	tty_encode_baud_rate(tty, baud, baud);
 }
 
@@ -922,7 +924,8 @@
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
-	dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
+	dev_dbg(&port->dev,
+		"digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n",
 		priv->dp_port_num, count, in_interrupt());
 
 	/* copy user data (which can sleep) before getting spin lock */
@@ -981,7 +984,7 @@
 		dev_err_console(port,
 			"%s: usb_submit_urb failed, ret=%d, port=%d\n",
 			__func__, ret, priv->dp_port_num);
-	dbg("digi_write: returning %d", ret);
+	dev_dbg(&port->dev, "digi_write: returning %d\n", ret);
 	return ret;
 
 }
@@ -1012,7 +1015,7 @@
 
 	/* handle oob callback */
 	if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
-		dbg("digi_write_bulk_callback: oob callback");
+		dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n");
 		spin_lock(&priv->dp_port_lock);
 		priv->dp_write_urb_in_use = 0;
 		wake_up_interruptible(&port->write_wait);
@@ -1066,7 +1069,7 @@
 		room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
 
 	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
-	dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room);
+	dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room);
 	return room;
 
 }
@@ -1077,12 +1080,12 @@
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
 	if (priv->dp_write_urb_in_use) {
-		dbg("digi_chars_in_buffer: port=%d, chars=%d",
+		dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
 			priv->dp_port_num, port->bulk_out_size - 2);
 		/* return(port->bulk_out_size - 2); */
 		return 256;
 	} else {
-		dbg("digi_chars_in_buffer: port=%d, chars=%d",
+		dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
 			priv->dp_port_num, priv->dp_out_buf_len);
 		return priv->dp_out_buf_len;
 	}
@@ -1120,7 +1123,7 @@
 
 	ret = digi_write_oob_command(port, buf, 8, 1);
 	if (ret != 0)
-		dbg("digi_open: write oob failed, ret=%d", ret);
+		dev_dbg(&port->dev, "digi_open: write oob failed, ret=%d\n", ret);
 
 	/* set termios settings */
 	if (tty) {
@@ -1180,7 +1183,7 @@
 
 		ret = digi_write_oob_command(port, buf, 20, 0);
 		if (ret != 0)
-			dbg("digi_close: write oob failed, ret=%d", ret);
+			dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret);
 
 		/* wait for final commands on oob port to complete */
 		prepare_to_wait(&priv->dp_flush_wait, &wait,
@@ -1448,9 +1451,9 @@
 	tty_kref_put(tty);
 
 	if (opcode == DIGI_CMD_RECEIVE_DISABLE)
-		dbg("%s: got RECEIVE_DISABLE", __func__);
+		dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__);
 	else if (opcode != DIGI_CMD_RECEIVE_DATA)
-		dbg("%s: unknown opcode: %d", __func__, opcode);
+		dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode);
 
 	return throttled ? 1 : 0;
 
@@ -1484,7 +1487,7 @@
 		status = ((unsigned char *)urb->transfer_buffer)[i++];
 		val = ((unsigned char *)urb->transfer_buffer)[i++];
 
-		dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+		dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
 			opcode, line, status, val);
 
 		if (status != 0 || line >= serial->type->num_ports)
@@ -1552,6 +1555,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 34e8638..43ede4a 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -28,8 +28,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -134,6 +132,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
deleted file mode 100644
index 800e8eb..0000000
--- a/drivers/usb/serial/ezusb.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * EZ-USB specific functions used by some of the USB to Serial drivers.
- *
- * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License version
- *	2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
-#define CPUCS_REG    0x7F92
-
-int ezusb_writememory(struct usb_serial *serial, int address,
-				unsigned char *data, int length, __u8 request)
-{
-	int result;
-	unsigned char *transfer_buffer;
-
-	if (!serial->dev) {
-		printk(KERN_ERR "ezusb: %s - no physical device present, "
-		       "failing.\n", __func__);
-		return -ENODEV;
-	}
-
-	transfer_buffer = kmemdup(data, length, GFP_KERNEL);
-	if (!transfer_buffer) {
-		dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n",
-							__func__, length);
-		return -ENOMEM;
-	}
-	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-		     request, 0x40, address, 0, transfer_buffer, length, 3000);
-	kfree(transfer_buffer);
-	return result;
-}
-EXPORT_SYMBOL_GPL(ezusb_writememory);
-
-int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit)
-{
-	int response;
-
-	response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0);
-	if (response < 0)
-		dev_err(&serial->dev->dev, "%s- %d failed\n",
-						__func__, reset_bit);
-	return response;
-}
-EXPORT_SYMBOL_GPL(ezusb_set_reset);
-
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 79451ee..2444771 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -25,8 +25,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x1934, 0x0706) },
 	{ }					/* Terminating entry */
@@ -85,7 +83,7 @@
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
+	usb_serial_debug_data(&port->dev, __func__,
 			      urb->actual_length, urb->transfer_buffer);
 
 	f81232_update_line_status(port, data, actual_length);
@@ -389,7 +387,3 @@
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
 MODULE_LICENSE("GPL v2");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0c8d1c2..be84587 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -48,14 +48,9 @@
 #include "ftdi_sio.h"
 #include "ftdi_sio_ids.h"
 
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.6.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
-static bool debug;
 static __u16 vendor = FTDI_VID;
 static __u16 product;
 
@@ -584,6 +579,8 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	/*
 	 * ELV devices:
 	 */
@@ -1063,11 +1060,12 @@
 							unsigned int clear)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	unsigned urb_value;
 	int rv;
 
 	if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
-		dbg("%s - DTR|RTS not being set|cleared", __func__);
+		dev_dbg(dev, "%s - DTR|RTS not being set|cleared\n", __func__);
 		return 0;	/* no change */
 	}
 
@@ -1088,18 +1086,14 @@
 			       urb_value, priv->interface,
 			       NULL, 0, WDR_TIMEOUT);
 	if (rv < 0) {
-		dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
-				__func__,
-				(set & TIOCM_DTR) ? "HIGH" :
-				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
-				(set & TIOCM_RTS) ? "HIGH" :
-				(clear & TIOCM_RTS) ? "LOW" : "unchanged");
+		dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n",
+			__func__,
+			(set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+			(set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged");
 	} else {
-		dbg("%s - DTR %s, RTS %s", __func__,
-				(set & TIOCM_DTR) ? "HIGH" :
-				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
-				(set & TIOCM_RTS) ? "HIGH" :
-				(clear & TIOCM_RTS) ? "LOW" : "unchanged");
+		dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__,
+			(set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+			(set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged");
 		/* FIXME: locking on last_dtr_rts */
 		priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
 	}
@@ -1111,6 +1105,7 @@
 						struct usb_serial_port *port)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	__u32 div_value = 0;
 	int div_okay = 1;
 	int baud;
@@ -1146,7 +1141,7 @@
 	      alt_speed hack */
 
 	baud = tty_get_baud_rate(tty);
-	dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud);
+	dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud);
 
 	/* 2. Observe async-compatible custom_divisor hack, update baudrate
 	   if needed */
@@ -1155,8 +1150,8 @@
 	    ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
 	     (priv->custom_divisor)) {
 		baud = priv->baud_base / priv->custom_divisor;
-		dbg("%s - custom divisor %d sets baud rate to %d",
-				__func__, priv->custom_divisor, baud);
+		dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n",
+			__func__, priv->custom_divisor, baud);
 	}
 
 	/* 3. Convert baudrate to device-specific divisor */
@@ -1178,8 +1173,8 @@
 		case 115200: div_value = ftdi_sio_b115200; break;
 		} /* baud */
 		if (div_value == 0) {
-			dbg("%s - Baudrate (%d) requested is not supported",
-							__func__,  baud);
+			dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n",
+				__func__,  baud);
 			div_value = ftdi_sio_b9600;
 			baud = 9600;
 			div_okay = 0;
@@ -1189,7 +1184,7 @@
 		if (baud <= 3000000) {
 			div_value = ftdi_232am_baud_to_divisor(baud);
 		} else {
-			dbg("%s - Baud rate too high!", __func__);
+			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
 			baud = 9600;
 			div_value = ftdi_232am_baud_to_divisor(9600);
 			div_okay = 0;
@@ -1212,7 +1207,7 @@
 			}
 			div_value = ftdi_232bm_baud_to_divisor(baud);
 		} else {
-			dbg("%s - Baud rate too high!", __func__);
+			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
 			div_value = ftdi_232bm_baud_to_divisor(9600);
 			div_okay = 0;
 			baud = 9600;
@@ -1226,7 +1221,7 @@
 		} else if (baud < 1200) {
 			div_value = ftdi_232bm_baud_to_divisor(baud);
 		} else {
-			dbg("%s - Baud rate too high!", __func__);
+			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
 			div_value = ftdi_232bm_baud_to_divisor(9600);
 			div_okay = 0;
 			baud = 9600;
@@ -1235,7 +1230,7 @@
 	} /* priv->chip_type */
 
 	if (div_okay) {
-		dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
+		dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n",
 			__func__, baud, (unsigned long)div_value,
 			ftdi_chip_name[priv->chip_type]);
 	}
@@ -1281,7 +1276,7 @@
 	if (priv->flags & ASYNC_LOW_LATENCY)
 		l = 1;
 
-	dbg("%s: setting latency timer = %i", __func__, l);
+	dev_dbg(&port->dev, "%s: setting latency timer = %i\n", __func__, l);
 
 	rv = usb_control_msg(udev,
 			     usb_sndctrlpipe(udev, 0),
@@ -1436,8 +1431,8 @@
 
 	version = le16_to_cpu(udev->descriptor.bcdDevice);
 	interfaces = udev->actconfig->desc.bNumInterfaces;
-	dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__,
-			version, interfaces);
+	dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__,
+		version, interfaces);
 	if (interfaces > 1) {
 		int inter;
 
@@ -1467,8 +1462,9 @@
 		/* BM-type devices have a bug where bcdDevice gets set
 		 * to 0x200 when iSerialNumber is 0.  */
 		if (version < 0x500) {
-			dbg("%s: something fishy - bcdDevice too low for multi-interface device",
-					__func__);
+			dev_dbg(&port->dev,
+				"%s: something fishy - bcdDevice too low for multi-interface device\n",
+				__func__);
 		}
 	} else if (version < 0x200) {
 		/* Old device.  Assume it's the original SIO. */
@@ -1582,7 +1578,7 @@
 	int v = simple_strtoul(valbuf, NULL, 10);
 	int rv;
 
-	dbg("%s: setting event char = %i", __func__, v);
+	dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v);
 
 	rv = usb_control_msg(udev,
 			     usb_sndctrlpipe(udev, 0),
@@ -1591,7 +1587,7 @@
 			     v, priv->interface,
 			     NULL, 0, WDR_TIMEOUT);
 	if (rv < 0) {
-		dbg("Unable to write event character: %i", rv);
+		dev_dbg(&port->dev, "Unable to write event character: %i\n", rv);
 		return -EIO;
 	}
 
@@ -1610,7 +1606,7 @@
 	/* XXX I've no idea if the original SIO supports the event_char
 	 * sysfs parameter, so I'm playing it safe.  */
 	if (priv->chip_type != SIO) {
-		dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
+		dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]);
 		retval = device_create_file(&port->dev, &dev_attr_event_char);
 		if ((!retval) &&
 		    (priv->chip_type == FT232BM ||
@@ -1750,8 +1746,8 @@
 	if (latency > 99)
 		latency = 99;
 
-	dbg("%s setting NDI device latency to %d", __func__, latency);
-	dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
+	dev_dbg(&udev->dev, "%s setting NDI device latency to %d\n", __func__, latency);
+	dev_info(&udev->dev, "NDI device with a latency value of %d\n", latency);
 
 	/* FIXME: errors are not returned */
 	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
@@ -1969,7 +1965,7 @@
 	char *ch;
 
 	if (len < 2) {
-		dbg("malformed packet");
+		dev_dbg(&port->dev, "malformed packet\n");
 		return 0;
 	}
 
@@ -2084,12 +2080,12 @@
 			FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			urb_value , priv->interface,
 			NULL, 0, WDR_TIMEOUT) < 0) {
-		dev_err(&port->dev, "%s FAILED to enable/disable break state "
-			"(state was %d)\n", __func__, break_state);
+		dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n",
+			__func__, break_state);
 	}
 
-	dbg("%s break state is %d - urb is %d", __func__,
-						break_state, urb_value);
+	dev_dbg(&port->dev, "%s break state is %d - urb is %d\n", __func__,
+		break_state, urb_value);
 
 }
 
@@ -2101,6 +2097,7 @@
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
 	struct usb_device *dev = port->serial->dev;
+	struct device *ddev = &port->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	struct ktermios *termios = &tty->termios;
 	unsigned int cflag = termios->c_cflag;
@@ -2114,20 +2111,20 @@
 	/* Force baud rate if this device requires it, unless it is set to
 	   B0. */
 	if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
-		dbg("%s: forcing baud rate for this device", __func__);
+		dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__);
 		tty_encode_baud_rate(tty, priv->force_baud,
 					priv->force_baud);
 	}
 
 	/* Force RTS-CTS if this device requires it. */
 	if (priv->force_rtscts) {
-		dbg("%s: forcing rtscts for this device", __func__);
+		dev_dbg(ddev, "%s: forcing rtscts for this device\n", __func__);
 		termios->c_cflag |= CRTSCTS;
 	}
 
 	cflag = termios->c_cflag;
 
-	if (old_termios == 0)
+	if (!old_termios)
 		goto no_skip;
 
 	if (old_termios->c_cflag == termios->c_cflag
@@ -2163,10 +2160,16 @@
 	}
 	if (cflag & CSIZE) {
 		switch (cflag & CSIZE) {
-		case CS7: urb_value |= 7; dbg("Setting CS7"); break;
-		case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+		case CS7:
+			urb_value |= 7;
+			dev_dbg(ddev, "Setting CS7\n");
+			break;
+		case CS8:
+			urb_value |= 8;
+			dev_dbg(ddev, "Setting CS8\n");
+			break;
 		default:
-			dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n");
+			dev_err(ddev, "CSIZE was set but not CS7-CS8\n");
 		}
 	}
 
@@ -2179,8 +2182,8 @@
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			    urb_value , priv->interface,
 			    NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
-		dev_err(&port->dev, "%s FAILED to set "
-			"databits/stopbits/parity\n", __func__);
+		dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n",
+			__func__);
 	}
 
 	/* Now do the baudrate */
@@ -2192,8 +2195,7 @@
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
 				    0, priv->interface,
 				    NULL, 0, WDR_TIMEOUT) < 0) {
-			dev_err(&port->dev,
-				"%s error from disable flowcontrol urb\n",
+			dev_err(ddev, "%s error from disable flowcontrol urb\n",
 				__func__);
 		}
 		/* Drop RTS and DTR */
@@ -2202,8 +2204,7 @@
 		/* set the baudrate determined before */
 		mutex_lock(&priv->cfg_lock);
 		if (change_speed(tty, port))
-			dev_err(&port->dev, "%s urb failed to set baudrate\n",
-				__func__);
+			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
 		mutex_unlock(&priv->cfg_lock);
 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
 		if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
@@ -2214,17 +2215,15 @@
 	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
 no_c_cflag_changes:
 	if (cflag & CRTSCTS) {
-		dbg("%s Setting to CRTSCTS flow control", __func__);
+		dev_dbg(ddev, "%s Setting to CRTSCTS flow control\n", __func__);
 		if (usb_control_msg(dev,
 				    usb_sndctrlpipe(dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
 				    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
 				    NULL, 0, WDR_TIMEOUT) < 0) {
-			dev_err(&port->dev,
-				"urb failed to set to rts/cts flow control\n");
+			dev_err(ddev, "urb failed to set to rts/cts flow control\n");
 		}
-
 	} else {
 		/*
 		 * Xon/Xoff code
@@ -2234,8 +2233,8 @@
 		 * code is executed.
 		 */
 		if (iflag & IXOFF) {
-			dbg("%s  request to enable xonxoff iflag=%04x",
-							__func__, iflag);
+			dev_dbg(ddev, "%s  request to enable xonxoff iflag=%04x\n",
+				__func__, iflag);
 			/* Try to enable the XON/XOFF on the ftdi_sio
 			 * Set the vstart and vstop -- could have been done up
 			 * above where a lot of other dereferencing is done but
@@ -2260,18 +2259,16 @@
 			/* else clause to only run if cflag ! CRTSCTS and iflag
 			 * ! XOFF. CHECKME Assuming XON/XOFF handled by tty
 			 * stack - not by device */
-			dbg("%s Turning off hardware flow control", __func__);
+			dev_dbg(ddev, "%s Turning off hardware flow control\n", __func__);
 			if (usb_control_msg(dev,
 					    usb_sndctrlpipe(dev, 0),
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
 					    0, priv->interface,
 					    NULL, 0, WDR_TIMEOUT) < 0) {
-				dev_err(&port->dev,
-					"urb failed to clear flow control\n");
+				dev_err(ddev, "urb failed to clear flow control\n");
 			}
 		}
-
 	}
 }
 
@@ -2365,7 +2362,7 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 
-	dbg("%s cmd 0x%04x", __func__, cmd);
+	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
 
 	/* Based on code from acm.c and others */
 	switch (cmd) {
@@ -2413,14 +2410,13 @@
 	/* This is not necessarily an error - turns out the higher layers
 	 * will do some ioctls themselves (see comment above)
 	 */
-	dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd);
+	dev_dbg(&port->dev, "%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h\n",
+		__func__, cmd);
 	return -ENOIOCTLCMD;
 }
 
 static int __init ftdi_init(void)
 {
-	int retval;
-
 	if (vendor > 0 && product > 0) {
 		/* Add user specified VID/PID to reserved element of table. */
 		int i;
@@ -2430,11 +2426,7 @@
 		id_table_combined[i].idVendor = vendor;
 		id_table_combined[i].idProduct = product;
 	}
-	retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
-	if (retval == 0)
-		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-			       DRIVER_DESC "\n");
-	return retval;
+	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
 }
 
 static void __exit ftdi_exit(void)
@@ -2450,8 +2442,6 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
 		__MODULE_STRING(FTDI_VID)")");
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 41fe582..57c12ef 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -517,6 +517,11 @@
  */
 #define FTDI_TAVIR_STK500_PID	0xFA33	/* STK500 AVR programmer */
 
+/*
+ * TIAO product ids (FTDI_VID)
+ * http://www.tiaowiki.com/w/Main_Page
+ */
+#define FTDI_TIAO_UMPA_PID	0x8a98	/* TIAO/DIYGADGET USB Multi-Protocol Adapter */
 
 
 /********************************/
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 2357079..9362f8f 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -16,8 +16,6 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x1404, 0xcddc) },
 	{ },
@@ -40,6 +38,3 @@
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 346c15a..3ee9264 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -41,9 +41,6 @@
 /* the mode to be set when the port ist opened */
 static int initial_mode = 1;
 
-/* debug flag */
-static bool debug;
-
 #define GARMIN_VENDOR_ID             0x091E
 
 /*
@@ -258,10 +255,7 @@
 	struct tty_struct *tty = tty_port_tty_get(&port->port);
 
 	if (tty && actual_length) {
-
-		usb_serial_debug_data(debug, &port->dev,
-					__func__, actual_length, data);
-
+		usb_serial_debug_data(&port->dev, __func__, actual_length, data);
 		tty_insert_flip_string(tty, data, actual_length);
 		tty_flip_buffer_push(tty);
 	}
@@ -303,8 +297,9 @@
 		state = garmin_data_p->state;
 		spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
-		dbg("%s - added: pkt: %d - %d bytes",
-			__func__, pkt->seq, data_length);
+		dev_dbg(&garmin_data_p->port->dev,
+			"%s - added: pkt: %d - %d bytes\n", __func__,
+			pkt->seq, data_length);
 
 		/* in serial mode, if someone is waiting for data from
 		   the device, convert and send the next packet to tty. */
@@ -359,7 +354,8 @@
 	__u8 *ptr = pkt;
 	unsigned  l = 0;
 
-	dbg("%s - pkt-id: 0x%X.", __func__, 0xFF & pkt_id);
+	dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__,
+		0xFF & pkt_id);
 
 	*ptr++ = DLE;
 	*ptr++ = ACK;
@@ -399,20 +395,20 @@
  */
 static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count)
 {
+	struct device *dev = &garmin_data_p->port->dev;
 	unsigned long flags;
 	const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
 	__le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
-
 	int cksum = 0;
 	int n = 0;
 	int pktid = recpkt[0];
 	int size = recpkt[1];
 
-	usb_serial_debug_data(debug, &garmin_data_p->port->dev,
-			       __func__, count-GSP_INITIAL_OFFSET, recpkt);
+	usb_serial_debug_data(&garmin_data_p->port->dev, __func__,
+			      count-GSP_INITIAL_OFFSET, recpkt);
 
 	if (size != (count-GSP_INITIAL_OFFSET-3)) {
-		dbg("%s - invalid size, expected %d bytes, got %d",
+		dev_dbg(dev, "%s - invalid size, expected %d bytes, got %d\n",
 			__func__, size, (count-GSP_INITIAL_OFFSET-3));
 		return -EINVPKT;
 	}
@@ -422,8 +418,8 @@
 
 	/* sanity check, remove after test ... */
 	if ((__u8 *)&(usbdata[3]) != recpkt) {
-		dbg("%s - ptr mismatch %p - %p",
-			__func__, &(usbdata[4]), recpkt);
+		dev_dbg(dev, "%s - ptr mismatch %p - %p\n", __func__,
+			&(usbdata[4]), recpkt);
 		return -EINVPKT;
 	}
 
@@ -433,7 +429,7 @@
 	}
 
 	if ((0xff & (cksum + *recpkt)) != 0) {
-		dbg("%s - invalid checksum, expected %02x, got %02x",
+		dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n",
 			__func__, 0xff & -cksum, 0xff & *recpkt);
 		return -EINVPKT;
 	}
@@ -480,6 +476,7 @@
 static int gsp_receive(struct garmin_data *garmin_data_p,
 		       const unsigned char *buf, int count)
 {
+	struct device *dev = &garmin_data_p->port->dev;
 	unsigned long flags;
 	int offs = 0;
 	int ack_or_nak_seen = 0;
@@ -500,7 +497,7 @@
 	skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
 	spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
-	/* dbg("%s - dle=%d skip=%d size=%d count=%d",
+	/* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n",
 		__func__, dleSeen, skip, size, count); */
 
 	if (size == 0)
@@ -530,12 +527,12 @@
 
 				if (data == ACK) {
 					ack_or_nak_seen = ACK;
-					dbg("ACK packet complete.");
+					dev_dbg(dev, "ACK packet complete.\n");
 				} else if (data == NAK) {
 					ack_or_nak_seen = NAK;
-					dbg("NAK packet complete.");
+					dev_dbg(dev, "NAK packet complete.\n");
 				} else {
-					dbg("packet complete - id=0x%X.",
+					dev_dbg(dev, "packet complete - id=0x%X.\n",
 						0xFF & data);
 					gsp_rec_packet(garmin_data_p, size);
 				}
@@ -557,7 +554,7 @@
 		}
 
 		if (size >= GPS_IN_BUFSIZ) {
-			dbg("%s - packet too large.", __func__);
+			dev_dbg(dev, "%s - packet too large.\n", __func__);
 			skip = 1;
 			size = GSP_INITIAL_OFFSET;
 			dleSeen = 0;
@@ -602,6 +599,7 @@
 static int gsp_send(struct garmin_data *garmin_data_p,
 		    const unsigned char *buf, int count)
 {
+	struct device *dev = &garmin_data_p->port->dev;
 	const unsigned char *src;
 	unsigned char *dst;
 	int pktid = 0;
@@ -610,12 +608,12 @@
 	int i = 0;
 	int k;
 
-	dbg("%s - state %d - %d bytes.", __func__,
-					garmin_data_p->state, count);
+	dev_dbg(dev, "%s - state %d - %d bytes.\n", __func__,
+		garmin_data_p->state, count);
 
 	k = garmin_data_p->outsize;
 	if ((k+count) > GPS_OUT_BUFSIZ) {
-		dbg("packet too large");
+		dev_dbg(dev, "packet too large\n");
 		garmin_data_p->outsize = 0;
 		return -4;
 	}
@@ -634,28 +632,28 @@
 		return 0;
 	}
 
-	dbg("%s - %d bytes in buffer, %d bytes in pkt.", __func__, k, i);
+	dev_dbg(dev, "%s - %d bytes in buffer, %d bytes in pkt.\n", __func__, k, i);
 
 	/* garmin_data_p->outbuffer now contains a complete packet */
 
-	usb_serial_debug_data(debug, &garmin_data_p->port->dev,
-				__func__, k, garmin_data_p->outbuffer);
+	usb_serial_debug_data(&garmin_data_p->port->dev, __func__, k,
+			      garmin_data_p->outbuffer);
 
 	garmin_data_p->outsize = 0;
 
 	if (GARMIN_LAYERID_APPL != getLayerId(garmin_data_p->outbuffer)) {
-		dbg("not an application packet (%d)",
+		dev_dbg(dev, "not an application packet (%d)\n",
 				getLayerId(garmin_data_p->outbuffer));
 		return -1;
 	}
 
 	if (pktid > 255) {
-		dbg("packet-id %d too large", pktid);
+		dev_dbg(dev, "packet-id %d too large\n", pktid);
 		return -2;
 	}
 
 	if (datalen > 255) {
-		dbg("packet-size %d too large", datalen);
+		dev_dbg(dev, "packet-size %d too large\n", datalen);
 		return -3;
 	}
 
@@ -722,7 +720,7 @@
 	struct garmin_packet *pkt = NULL;
 
 	while ((pkt = pkt_pop(garmin_data_p)) != NULL) {
-		dbg("%s - next pkt: %d", __func__, pkt->seq);
+		dev_dbg(&garmin_data_p->port->dev, "%s - next pkt: %d\n", __func__, pkt->seq);
 		result = gsp_send(garmin_data_p, pkt->data, pkt->size);
 		if (result > 0) {
 			kfree(pkt);
@@ -768,7 +766,9 @@
 		if (len >= GPS_IN_BUFSIZ) {
 			/* seems to be an invalid packet, ignore rest
 			   of input */
-			dbg("%s - packet size too large: %d", __func__, len);
+			dev_dbg(&garmin_data_p->port->dev,
+				"%s - packet size too large: %d\n",
+				__func__, len);
 			garmin_data_p->insize = 0;
 			count = 0;
 			result = -EINVPKT;
@@ -849,10 +849,10 @@
 	spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
 	usb_kill_urb(port->interrupt_in_urb);
-	dbg("%s - usb_reset_device", __func__);
+	dev_dbg(&port->dev, "%s - usb_reset_device\n", __func__);
 	status = usb_reset_device(port->serial->dev);
 	if (status)
-		dbg("%s - usb_reset_device failed: %d",
+		dev_dbg(&port->dev, "%s - usb_reset_device failed: %d\n",
 			__func__, status);
 	return status;
 }
@@ -889,7 +889,7 @@
 	if (status == 0) {
 		usb_kill_urb(port->interrupt_in_urb);
 
-		dbg("%s - adding interrupt input", __func__);
+		dev_dbg(&serial->dev->dev, "%s - adding interrupt input\n", __func__);
 		status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (status)
 			dev_err(&serial->dev->dev,
@@ -902,7 +902,7 @@
 	 * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles()
 	 */
 	if (status == 0) {
-		dbg("%s - starting session ...", __func__);
+		dev_dbg(&serial->dev->dev, "%s - starting session ...\n", __func__);
 		garmin_data_p->state = STATE_ACTIVE;
 
 		for (i = 0; i < 3; i++) {
@@ -952,8 +952,8 @@
 	struct usb_serial *serial = port->serial;
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d - mode=%d state=%d flags=0x%X", __func__,
-		port->number, garmin_data_p->mode,
+	dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",
+		__func__, port->number, garmin_data_p->mode,
 		garmin_data_p->state, garmin_data_p->flags);
 
 	if (!serial)
@@ -1032,7 +1032,7 @@
 
 	memcpy(buffer, buf, count);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
+	usb_serial_debug_data(&port->dev, __func__, count, buffer);
 
 	usb_fill_bulk_urb(urb, serial->dev,
 				usb_sndbulkpipe(serial->dev,
@@ -1073,11 +1073,12 @@
 static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
 					 const unsigned char *buf, int count)
 {
+	struct device *dev = &port->dev;
 	int pktid, pktsiz, len;
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 	__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count, buf);
+	usb_serial_debug_data(dev, __func__, count, buf);
 
 	if (garmin_data_p->state == STATE_RESET)
 		return -EIO;
@@ -1097,27 +1098,18 @@
 		    && GARMIN_LAYERID_PRIVATE ==
 				getLayerId(garmin_data_p->privpkt)) {
 
-			dbg("%s - processing private request %d",
+			dev_dbg(dev, "%s - processing private request %d\n",
 				__func__, pktid);
 
 			/* drop all unfinished transfers */
 			garmin_clear(garmin_data_p);
 
 			switch (pktid) {
-
-			case PRIV_PKTID_SET_DEBUG:
-				if (pktsiz != 4)
-					return -EINVPKT;
-				debug = __le32_to_cpu(privpkt[3]);
-				dbg("%s - debug level set to 0x%X",
-					__func__, debug);
-				break;
-
 			case PRIV_PKTID_SET_MODE:
 				if (pktsiz != 4)
 					return -EINVPKT;
 				garmin_data_p->mode = __le32_to_cpu(privpkt[3]);
-				dbg("%s - mode set to %d",
+				dev_dbg(dev, "%s - mode set to %d\n",
 					__func__, garmin_data_p->mode);
 				break;
 
@@ -1133,7 +1125,7 @@
 				if (pktsiz != 4)
 					return -EINVPKT;
 				initial_mode = __le32_to_cpu(privpkt[3]);
-				dbg("%s - initial_mode set to %d",
+				dev_dbg(dev, "%s - initial_mode set to %d\n",
 					__func__,
 					garmin_data_p->mode);
 				break;
@@ -1169,7 +1161,7 @@
 
 	if (garmin_data_p->flags & FLAGS_DROP_DATA) {
 		/* abort-transfer cmd is actice */
-		dbg("%s - pkt dropped", __func__);
+		dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__);
 	} else if (garmin_data_p->state != STATE_DISCONNECTED &&
 		garmin_data_p->state != STATE_RESET) {
 
@@ -1178,7 +1170,7 @@
 		   send it directly to the tty port */
 		if (garmin_data_p->flags & FLAGS_QUEUING) {
 			pkt_add(garmin_data_p, data, data_length);
-		} else if (bulk_data || 
+		} else if (bulk_data ||
 			   getLayerId(data) == GARMIN_LAYERID_APPL) {
 
 			spin_lock_irqsave(&garmin_data_p->lock, flags);
@@ -1208,18 +1200,17 @@
 	int retval;
 
 	if (!serial) {
-		dbg("%s - bad serial pointer, exiting", __func__);
+		dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__);
 		return;
 	}
 
 	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
+		dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
 			__func__, status);
 		return;
 	}
 
-	usb_serial_debug_data(debug, &port->dev,
-				__func__, urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	garmin_read_process(garmin_data_p, data, urb->actual_length, 1);
 
@@ -1239,11 +1230,11 @@
 			retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 			if (retval)
 				dev_err(&port->dev,
-					"%s - failed resubmitting read urb, "
-					"error %d\n", __func__, retval);
+					"%s - failed resubmitting read urb, error %d\n",
+					__func__, retval);
 		}
 	} else {
-		dbg("%s - end of bulk data", __func__);
+		dev_dbg(&port->dev, "%s - end of bulk data\n", __func__);
 		spin_lock_irqsave(&garmin_data_p->lock, flags);
 		garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
 		spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1268,23 +1259,23 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
 			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
 			__func__, status);
 		return;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-				urb->actual_length, urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+			      urb->transfer_buffer);
 
 	if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) &&
 	    0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY,
 				sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) {
 
-		dbg("%s - bulk data available.", __func__);
+		dev_dbg(&port->dev, "%s - bulk data available.\n", __func__);
 
 		if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
 
@@ -1319,7 +1310,7 @@
 		garmin_data_p->serial_num = __le32_to_cpup(
 					(__le32 *)(data+GARMIN_PKTHDR_LENGTH));
 
-		dbg("%s - start-of-session reply seen - serial %u.",
+		dev_dbg(&port->dev, "%s - start-of-session reply seen - serial %u.\n",
 			__func__, garmin_data_p->serial_num);
 	}
 
@@ -1495,7 +1486,5 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(debug, bool, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(initial_mode, int, S_IRUGO);
 MODULE_PARM_DESC(initial_mode, "Initial mode");
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 9b026bf..2966121 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -24,8 +24,6 @@
 #include <linux/kfifo.h>
 #include <linux/serial.h>
 
-static int debug;
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
 
 static __u16 vendor  = 0x05f9;
@@ -60,11 +58,10 @@
 
 #endif
 
-int usb_serial_generic_register(int _debug)
+int usb_serial_generic_register(void)
 {
 	int retval = 0;
 
-	debug = _debug;
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	generic_device_ids[0].idVendor = vendor;
 	generic_device_ids[0].idProduct = product;
@@ -171,8 +168,7 @@
 						urb->transfer_buffer,
 						port->bulk_out_size);
 	urb->transfer_buffer_length = count;
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-						urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, count, urb->transfer_buffer);
 	spin_lock_irqsave(&port->lock, flags);
 	port->tx_bytes += count;
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -365,8 +361,7 @@
 		return;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 	port->serial->type->process_read_urb(urb);
 
 	/* Throttle the device if requested by tty */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f435575..8e6faaf 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -190,9 +190,6 @@
 	{   230400,	1},
 };
 
-/* local variables */
-static bool debug;
-
 /* Number of outstanding Command Write Urbs */
 static atomic_t CmdUrbs = ATOMIC_INIT(0);
 
@@ -244,7 +241,7 @@
 				__u8 lsr, __u8 data);
 static int  send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command,
 				__u8 param);
-static int  calc_baud_rate_divisor(int baud_rate, int *divisor);
+static int  calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor);
 static int  send_cmd_write_baud_rate(struct edgeport_port *edge_port,
 				int baudRate);
 static void change_port_settings(struct tty_struct *tty,
@@ -286,6 +283,7 @@
  ************************************************************************/
 static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
 	__u32 BootCurVer;
 	__u32 BootNewVer;
 	__u8 BootMajorVersion;
@@ -311,7 +309,7 @@
 	response = request_ihex_firmware(&fw, fw_name,
 					 &edge_serial->serial->dev->dev);
 	if (response) {
-		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
+		dev_err(dev, "Failed to load image \"%s\" err %d\n",
 		       fw_name, response);
 		return;
 	}
@@ -330,20 +328,20 @@
 		     (BootMinorVersion << 16) +
 		      BootBuildNumber;
 
-	dbg("Current Boot Image version %d.%d.%d",
+	dev_dbg(dev, "Current Boot Image version %d.%d.%d\n",
 	    edge_serial->boot_descriptor.MajorVersion,
 	    edge_serial->boot_descriptor.MinorVersion,
 	    le16_to_cpu(edge_serial->boot_descriptor.BuildNumber));
 
 
 	if (BootNewVer > BootCurVer) {
-		dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d",
+		dev_dbg(dev, "**Update Boot Image from %d.%d.%d to %d.%d.%d\n",
 		    edge_serial->boot_descriptor.MajorVersion,
 		    edge_serial->boot_descriptor.MinorVersion,
 		    le16_to_cpu(edge_serial->boot_descriptor.BuildNumber),
 		    BootMajorVersion, BootMinorVersion, BootBuildNumber);
 
-		dbg("Downloading new Boot Image");
+		dev_dbg(dev, "Downloading new Boot Image\n");
 
 		for (rec = ihex_next_binrec(rec); rec;
 		     rec = ihex_next_binrec(rec)) {
@@ -362,7 +360,7 @@
 			}
 		}
 	} else {
-		dbg("Boot Image -- already up to date");
+		dev_dbg(dev, "Boot Image -- already up to date\n");
 	}
 	release_firmware(fw);
 }
@@ -379,7 +377,7 @@
 	struct usb_string_descriptor StringDesc;
 	struct usb_string_descriptor *pStringDesc;
 
-	dbg("%s - USB String ID = %d", __func__, Id);
+	dev_dbg(&dev->dev, "%s - USB String ID = %d\n", __func__, Id);
 
 	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc,
 						sizeof(StringDesc)))
@@ -400,34 +398,39 @@
 }
 #endif
 
-static void dump_product_info(struct edgeport_product_info *product_info)
+static void dump_product_info(struct edgeport_serial *edge_serial,
+			      struct edgeport_product_info *product_info)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
+
 	/* Dump Product Info structure */
-	dbg("**Product Information:");
-	dbg("  ProductId             %x", product_info->ProductId);
-	dbg("  NumPorts              %d", product_info->NumPorts);
-	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer);
-	dbg("  IsServer              %d", product_info->IsServer);
-	dbg("  IsRS232               %d", product_info->IsRS232);
-	dbg("  IsRS422               %d", product_info->IsRS422);
-	dbg("  IsRS485               %d", product_info->IsRS485);
-	dbg("  RomSize               %d", product_info->RomSize);
-	dbg("  RamSize               %d", product_info->RamSize);
-	dbg("  CpuRev                %x", product_info->CpuRev);
-	dbg("  BoardRev              %x", product_info->BoardRev);
-	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
-	    product_info->BootMinorVersion,
-	    le16_to_cpu(product_info->BootBuildNumber));
-	dbg("  FirmwareMajorVersion  %d.%d.%d",
-			product_info->FirmwareMajorVersion,
-			product_info->FirmwareMinorVersion,
-			le16_to_cpu(product_info->FirmwareBuildNumber));
-	dbg("  ManufactureDescDate   %d/%d/%d",
-			product_info->ManufactureDescDate[0],
-			product_info->ManufactureDescDate[1],
-			product_info->ManufactureDescDate[2]+1900);
-	dbg("  iDownloadFile         0x%x", product_info->iDownloadFile);
-	dbg("  EpicVer               %d", product_info->EpicVer);
+	dev_dbg(dev, "**Product Information:\n");
+	dev_dbg(dev, "  ProductId             %x\n", product_info->ProductId);
+	dev_dbg(dev, "  NumPorts              %d\n", product_info->NumPorts);
+	dev_dbg(dev, "  ProdInfoVer           %d\n", product_info->ProdInfoVer);
+	dev_dbg(dev, "  IsServer              %d\n", product_info->IsServer);
+	dev_dbg(dev, "  IsRS232               %d\n", product_info->IsRS232);
+	dev_dbg(dev, "  IsRS422               %d\n", product_info->IsRS422);
+	dev_dbg(dev, "  IsRS485               %d\n", product_info->IsRS485);
+	dev_dbg(dev, "  RomSize               %d\n", product_info->RomSize);
+	dev_dbg(dev, "  RamSize               %d\n", product_info->RamSize);
+	dev_dbg(dev, "  CpuRev                %x\n", product_info->CpuRev);
+	dev_dbg(dev, "  BoardRev              %x\n", product_info->BoardRev);
+	dev_dbg(dev, "  BootMajorVersion      %d.%d.%d\n",
+		product_info->BootMajorVersion,
+		product_info->BootMinorVersion,
+		le16_to_cpu(product_info->BootBuildNumber));
+	dev_dbg(dev, "  FirmwareMajorVersion  %d.%d.%d\n",
+		product_info->FirmwareMajorVersion,
+		product_info->FirmwareMinorVersion,
+		le16_to_cpu(product_info->FirmwareBuildNumber));
+	dev_dbg(dev, "  ManufactureDescDate   %d/%d/%d\n",
+		product_info->ManufactureDescDate[0],
+		product_info->ManufactureDescDate[1],
+		product_info->ManufactureDescDate[2]+1900);
+	dev_dbg(dev, "  iDownloadFile         0x%x\n",
+		product_info->iDownloadFile);
+	dev_dbg(dev, "  EpicVer               %d\n", product_info->EpicVer);
 }
 
 static void get_product_info(struct edgeport_serial *edge_serial)
@@ -462,7 +465,7 @@
 		product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_80251;
 	else
 		product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_I930;
- 
+
 	/* Determine Product type and set appropriate flags */
 	switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) {
 	case ION_DEVICE_ID_EDGEPORT_COMPATIBLE:
@@ -490,7 +493,7 @@
 		break;
 	}
 
-	dump_product_info(product_info);
+	dump_product_info(edge_serial, product_info);
 }
 
 static int get_epic_descriptor(struct edgeport_serial *ep)
@@ -500,6 +503,7 @@
 	struct edgeport_product_info *product_info = &ep->product_info;
 	struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
 	struct edge_compatibility_bits *bits;
+	struct device *dev = &serial->dev->dev;
 
 	ep->is_epic = 0;
 	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
@@ -509,8 +513,6 @@
 				 sizeof(struct edge_compatibility_descriptor),
 				 300);
 
-	dbg("%s result = %d", __func__, result);
-
 	if (result > 0) {
 		ep->is_epic = 1;
 		memset(product_info, 0, sizeof(struct edgeport_product_info));
@@ -524,23 +526,23 @@
 		product_info->EpicVer = epic->EpicVer;
 		product_info->Epic = epic->Supports;
 		product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
-		dump_product_info(product_info);
+		dump_product_info(ep, product_info);
 
 		bits = &ep->epic_descriptor.Supports;
-		dbg("**EPIC descriptor:");
-		dbg("  VendEnableSuspend: %s", bits->VendEnableSuspend	? "TRUE": "FALSE");
-		dbg("  IOSPOpen         : %s", bits->IOSPOpen		? "TRUE": "FALSE");
-		dbg("  IOSPClose        : %s", bits->IOSPClose		? "TRUE": "FALSE");
-		dbg("  IOSPChase        : %s", bits->IOSPChase		? "TRUE": "FALSE");
-		dbg("  IOSPSetRxFlow    : %s", bits->IOSPSetRxFlow	? "TRUE": "FALSE");
-		dbg("  IOSPSetTxFlow    : %s", bits->IOSPSetTxFlow	? "TRUE": "FALSE");
-		dbg("  IOSPSetXChar     : %s", bits->IOSPSetXChar	? "TRUE": "FALSE");
-		dbg("  IOSPRxCheck      : %s", bits->IOSPRxCheck	? "TRUE": "FALSE");
-		dbg("  IOSPSetClrBreak  : %s", bits->IOSPSetClrBreak	? "TRUE": "FALSE");
-		dbg("  IOSPWriteMCR     : %s", bits->IOSPWriteMCR	? "TRUE": "FALSE");
-		dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR	? "TRUE": "FALSE");
-		dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate	? "TRUE": "FALSE");
-		dbg("  TrueEdgeport     : %s", bits->TrueEdgeport	? "TRUE": "FALSE");
+		dev_dbg(dev, "**EPIC descriptor:\n");
+		dev_dbg(dev, "  VendEnableSuspend: %s\n", bits->VendEnableSuspend ? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPOpen         : %s\n", bits->IOSPOpen	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPClose        : %s\n", bits->IOSPClose	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPChase        : %s\n", bits->IOSPChase	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPSetRxFlow    : %s\n", bits->IOSPSetRxFlow	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPSetTxFlow    : %s\n", bits->IOSPSetTxFlow	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPSetXChar     : %s\n", bits->IOSPSetXChar	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPRxCheck      : %s\n", bits->IOSPRxCheck	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPSetClrBreak  : %s\n", bits->IOSPSetClrBreak	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPWriteMCR     : %s\n", bits->IOSPWriteMCR	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPWriteLCR     : %s\n", bits->IOSPWriteLCR	? "TRUE": "FALSE");
+		dev_dbg(dev, "  IOSPSetBaudRate  : %s\n", bits->IOSPSetBaudRate	? "TRUE": "FALSE");
+		dev_dbg(dev, "  TrueEdgeport     : %s\n", bits->TrueEdgeport	? "TRUE": "FALSE");
 	}
 
 	return result;
@@ -561,7 +563,8 @@
  *****************************************************************************/
 static void edge_interrupt_callback(struct urb *urb)
 {
-	struct edgeport_serial	*edge_serial = urb->context;
+	struct edgeport_serial *edge_serial = urb->context;
+	struct device *dev;
 	struct edgeport_port *edge_port;
 	struct usb_serial_port *port;
 	struct tty_struct *tty;
@@ -574,8 +577,6 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -584,36 +585,42 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-						__func__, status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
 		goto exit;
 	}
 
+	dev = &edge_serial->serial->dev->dev;
+
 	/* process this interrupt-read even if there are no ports open */
 	if (length) {
-		usb_serial_debug_data(debug, &edge_serial->serial->dev->dev,
-						__func__, length, data);
+		usb_serial_debug_data(dev, __func__, length, data);
 
 		if (length > 1) {
 			bytes_avail = data[0] | (data[1] << 8);
 			if (bytes_avail) {
 				spin_lock(&edge_serial->es_lock);
 				edge_serial->rxBytesAvail += bytes_avail;
-				dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __func__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);
+				dev_dbg(dev,
+					"%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n",
+					__func__, bytes_avail,
+					edge_serial->rxBytesAvail,
+					edge_serial->read_in_progress);
 
 				if (edge_serial->rxBytesAvail > 0 &&
 				    !edge_serial->read_in_progress) {
-					dbg("%s - posting a read", __func__);
+					dev_dbg(dev, "%s - posting a read\n", __func__);
 					edge_serial->read_in_progress = true;
 
 					/* we have pending bytes on the
 					   bulk in pipe, send a request */
 					result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 					if (result) {
-						dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result);
+						dev_err(dev,
+							"%s - usb_submit_urb(read bulk) failed with result = %d\n",
+							__func__, result);
 						edge_serial->read_in_progress = false;
 					}
 				}
@@ -633,9 +640,9 @@
 					spin_lock(&edge_port->ep_lock);
 					edge_port->txCredits += txCredits;
 					spin_unlock(&edge_port->ep_lock);
-					dbg("%s - txcredits for port%d = %d",
-							__func__, portNumber,
-							edge_port->txCredits);
+					dev_dbg(dev, "%s - txcredits for port%d = %d\n",
+						__func__, portNumber,
+						edge_port->txCredits);
 
 					/* tell the tty driver that something
 					   has changed */
@@ -673,49 +680,48 @@
 static void edge_bulk_in_callback(struct urb *urb)
 {
 	struct edgeport_serial	*edge_serial = urb->context;
+	struct device *dev;
 	unsigned char		*data = urb->transfer_buffer;
 	int			retval;
 	__u16			raw_data_length;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
+			__func__, status);
 		edge_serial->read_in_progress = false;
 		return;
 	}
 
 	if (urb->actual_length == 0) {
-		dbg("%s - read bulk callback with no data", __func__);
+		dev_dbg(&urb->dev->dev, "%s - read bulk callback with no data\n", __func__);
 		edge_serial->read_in_progress = false;
 		return;
 	}
 
+	dev = &edge_serial->serial->dev->dev;
 	raw_data_length = urb->actual_length;
 
-	usb_serial_debug_data(debug, &edge_serial->serial->dev->dev,
-					__func__, raw_data_length, data);
+	usb_serial_debug_data(dev, __func__, raw_data_length, data);
 
 	spin_lock(&edge_serial->es_lock);
 
 	/* decrement our rxBytes available by the number that we just got */
 	edge_serial->rxBytesAvail -= raw_data_length;
 
-	dbg("%s - Received = %d, rxBytesAvail %d", __func__,
-				raw_data_length, edge_serial->rxBytesAvail);
+	dev_dbg(dev, "%s - Received = %d, rxBytesAvail %d\n", __func__,
+		raw_data_length, edge_serial->rxBytesAvail);
 
 	process_rcvd_data(edge_serial, data, urb->actual_length);
 
 	/* check to see if there's any more data for us to read */
 	if (edge_serial->rxBytesAvail > 0) {
-		dbg("%s - posting a read", __func__);
+		dev_dbg(dev, "%s - posting a read\n", __func__);
 		retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 		if (retval) {
-			dev_err(&urb->dev->dev,
-				"%s - usb_submit_urb(read bulk) failed, "
-				"retval = %d\n", __func__, retval);
+			dev_err(dev,
+				"%s - usb_submit_urb(read bulk) failed, retval = %d\n",
+				__func__, retval);
 			edge_serial->read_in_progress = false;
 		}
 	} else {
@@ -737,11 +743,10 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&urb->dev->dev,
+			"%s - nonzero write bulk status received: %d\n",
+			__func__, status);
 	}
 
 	tty = tty_port_tty_get(&edge_port->port->port);
@@ -773,11 +778,9 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	atomic_dec(&CmdUrbs);
-	dbg("%s - FREE URB %p (outstanding %d)", __func__,
-					urb, atomic_read(&CmdUrbs));
+	dev_dbg(&urb->dev->dev, "%s - FREE URB %p (outstanding %d)\n",
+		__func__, urb, atomic_read(&CmdUrbs));
 
 
 	/* clean up the transfer buffer */
@@ -787,8 +790,9 @@
 	usb_free_urb(urb);
 
 	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-							__func__, status);
+		dev_dbg(&urb->dev->dev,
+			"%s - nonzero write bulk status received: %d\n",
+			__func__, status);
 		return;
 	}
 
@@ -819,12 +823,11 @@
 static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	struct usb_serial *serial;
 	struct edgeport_serial *edge_serial;
 	int response;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return -ENODEV;
 
@@ -875,9 +878,8 @@
 		response = usb_submit_urb(edge_serial->interrupt_read_urb,
 								GFP_KERNEL);
 		if (response) {
-			dev_err(&port->dev,
-				"%s - Error %d submitting control urb\n",
-							__func__, response);
+			dev_err(dev, "%s - Error %d submitting control urb\n",
+				__func__, response);
 		}
 	}
 
@@ -902,8 +904,7 @@
 	response = send_iosp_ext_cmd(edge_port, IOSP_CMD_OPEN_PORT, 0);
 
 	if (response < 0) {
-		dev_err(&port->dev, "%s - error sending open port command\n",
-								__func__);
+		dev_err(dev, "%s - error sending open port command\n", __func__);
 		edge_port->openPending = false;
 		return -ENODEV;
 	}
@@ -914,7 +915,7 @@
 
 	if (!edge_port->open) {
 		/* open timed out */
-		dbg("%s - open timedout", __func__);
+		dev_dbg(dev, "%s - open timedout\n", __func__);
 		edge_port->openPending = false;
 		return -ENODEV;
 	}
@@ -927,7 +928,7 @@
 	edge_port->txfifo.fifo	= kmalloc(edge_port->maxTxCredits, GFP_KERNEL);
 
 	if (!edge_port->txfifo.fifo) {
-		dbg("%s - no memory", __func__);
+		dev_dbg(dev, "%s - no memory\n", __func__);
 		edge_close(port);
 		return -ENOMEM;
 	}
@@ -937,15 +938,13 @@
 	edge_port->write_in_progress = false;
 
 	if (!edge_port->write_urb) {
-		dbg("%s - no memory", __func__);
+		dev_dbg(dev, "%s - no memory\n", __func__);
 		edge_close(port);
 		return -ENOMEM;
 	}
 
-	dbg("%s(%d) - Initialize TX fifo to %d bytes",
-			__func__, port->number, edge_port->maxTxCredits);
-
-	dbg("%s exited", __func__);
+	dev_dbg(dev, "%s(%d) - Initialize TX fifo to %d bytes\n",
+		__func__, port->number, edge_port->maxTxCredits);
 
 	return 0;
 }
@@ -963,6 +962,7 @@
  ************************************************************************/
 static void block_until_chase_response(struct edgeport_port *edge_port)
 {
+	struct device *dev = &edge_port->port->dev;
 	DEFINE_WAIT(wait);
 	__u16 lastCredits;
 	int timeout = 1*HZ;
@@ -974,11 +974,11 @@
 
 		/* Did we get our Chase response */
 		if (!edge_port->chaseResponsePending) {
-			dbg("%s - Got Chase Response", __func__);
+			dev_dbg(dev, "%s - Got Chase Response\n", __func__);
 
 			/* did we get all of our credit back? */
 			if (edge_port->txCredits == edge_port->maxTxCredits) {
-				dbg("%s - Got all credits", __func__);
+				dev_dbg(dev, "%s - Got all credits\n", __func__);
 				return;
 			}
 		}
@@ -994,12 +994,12 @@
 			loop--;
 			if (loop == 0) {
 				edge_port->chaseResponsePending = false;
-				dbg("%s - Chase TIMEOUT", __func__);
+				dev_dbg(dev, "%s - Chase TIMEOUT\n", __func__);
 				return;
 			}
 		} else {
 			/* Reset timeout value back to 10 seconds */
-			dbg("%s - Last %d, Current %d", __func__,
+			dev_dbg(dev, "%s - Last %d, Current %d\n", __func__,
 					lastCredits, edge_port->txCredits);
 			loop = 10;
 		}
@@ -1019,6 +1019,7 @@
  ************************************************************************/
 static void block_until_tx_empty(struct edgeport_port *edge_port)
 {
+	struct device *dev = &edge_port->port->dev;
 	DEFINE_WAIT(wait);
 	struct TxFifo *fifo = &edge_port->txfifo;
 	__u32 lastCount;
@@ -1031,7 +1032,7 @@
 
 		/* Is the Edgeport Buffer empty? */
 		if (lastCount == 0) {
-			dbg("%s - TX Buffer Empty", __func__);
+			dev_dbg(dev, "%s - TX Buffer Empty\n", __func__);
 			return;
 		}
 
@@ -1041,13 +1042,13 @@
 		schedule_timeout(timeout);
 		finish_wait(&edge_port->wait_chase, &wait);
 
-		dbg("%s wait", __func__);
+		dev_dbg(dev, "%s wait\n", __func__);
 
 		if (lastCount == fifo->count) {
 			/* No activity.. count down. */
 			loop--;
 			if (loop == 0) {
-				dbg("%s - TIMEOUT", __func__);
+				dev_dbg(dev, "%s - TIMEOUT\n", __func__);
 				return;
 			}
 		} else {
@@ -1068,8 +1069,6 @@
 	struct edgeport_port *edge_port;
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	edge_serial = usb_get_serial_data(port->serial);
 	edge_port = usb_get_serial_port_data(port);
 	if (edge_serial == NULL || edge_port == NULL)
@@ -1086,7 +1085,7 @@
 		/* flush and chase */
 		edge_port->chaseResponsePending = true;
 
-		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__);
+		dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__);
 		status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0);
 		if (status == 0)
 			/* block until chase finished */
@@ -1099,7 +1098,7 @@
 	    ((edge_serial->is_epic) &&
 	     (edge_serial->epic_descriptor.Supports.IOSPClose))) {
 	       /* close the port */
-		dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __func__);
+		dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLOSE_PORT\n", __func__);
 		send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0);
 	}
 
@@ -1119,8 +1118,6 @@
 	}
 	kfree(edge_port->txfifo.fifo);
 	edge_port->txfifo.fifo = NULL;
-
-	dbg("%s exited", __func__);
 }
 
 /*****************************************************************************
@@ -1141,8 +1138,6 @@
 	int secondhalf;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return -ENODEV;
 
@@ -1155,14 +1150,14 @@
 	copySize = min((unsigned int)count,
 				(edge_port->txCredits - fifo->count));
 
-	dbg("%s(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes",
-			__func__, port->number, count,
+	dev_dbg(&port->dev, "%s(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes\n",
+		__func__, port->number, count,
 			edge_port->txCredits - fifo->count, copySize);
 
 	/* catch writes of 0 bytes which the tty driver likes to give us,
 	   and when txCredits is empty */
 	if (copySize == 0) {
-		dbg("%s - copySize = Zero", __func__);
+		dev_dbg(&port->dev, "%s - copySize = Zero\n", __func__);
 		goto finish_write;
 	}
 
@@ -1175,13 +1170,12 @@
 	 */
 	bytesleft = fifo->size - fifo->head;
 	firsthalf = min(bytesleft, copySize);
-	dbg("%s - copy %d bytes of %d into fifo ", __func__,
-					firsthalf, bytesleft);
+	dev_dbg(&port->dev, "%s - copy %d bytes of %d into fifo \n", __func__,
+		firsthalf, bytesleft);
 
 	/* now copy our data */
 	memcpy(&fifo->fifo[fifo->head], data, firsthalf);
-	usb_serial_debug_data(debug, &port->dev, __func__,
-					firsthalf, &fifo->fifo[fifo->head]);
+	usb_serial_debug_data(&port->dev, __func__, firsthalf, &fifo->fifo[fifo->head]);
 
 	/* update the index and size */
 	fifo->head  += firsthalf;
@@ -1194,10 +1188,9 @@
 	secondhalf = copySize-firsthalf;
 
 	if (secondhalf) {
-		dbg("%s - copy rest of data %d", __func__, secondhalf);
+		dev_dbg(&port->dev, "%s - copy rest of data %d\n", __func__, secondhalf);
 		memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
-		usb_serial_debug_data(debug, &port->dev, __func__,
-					secondhalf, &fifo->fifo[fifo->head]);
+		usb_serial_debug_data(&port->dev, __func__, secondhalf, &fifo->fifo[fifo->head]);
 		/* update the index and size */
 		fifo->count += secondhalf;
 		fifo->head  += secondhalf;
@@ -1212,8 +1205,8 @@
 	send_more_port_data((struct edgeport_serial *)
 			usb_get_serial_data(port->serial), edge_port);
 
-	dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __func__,
-				copySize, edge_port->txCredits, fifo->count);
+	dev_dbg(&port->dev, "%s wrote %d byte(s) TxCredits %d, Fifo %d\n",
+		__func__, copySize, edge_port->txCredits, fifo->count);
 
 	return copySize;
 }
@@ -1236,6 +1229,7 @@
 					struct edgeport_port *edge_port)
 {
 	struct TxFifo	*fifo = &edge_port->txfifo;
+	struct device	*dev = &edge_port->port->dev;
 	struct urb	*urb;
 	unsigned char	*buffer;
 	int		status;
@@ -1245,16 +1239,14 @@
 	int		secondhalf;
 	unsigned long	flags;
 
-	dbg("%s(%d)", __func__, edge_port->port->number);
-
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
 
 	if (edge_port->write_in_progress ||
 	    !edge_port->open             ||
 	    (fifo->count == 0)) {
-		dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d",
-				__func__, edge_port->port->number,
-				fifo->count, edge_port->write_in_progress);
+		dev_dbg(dev, "%s(%d) EXIT - fifo %d, PendingWrite = %d\n",
+			__func__, edge_port->port->number,
+			fifo->count, edge_port->write_in_progress);
 		goto exit_send;
 	}
 
@@ -1266,7 +1258,7 @@
 	 * it's better to wait for more credits so we can do a larger write.
 	 */
 	if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits, EDGE_FW_BULK_MAX_PACKET_SIZE)) {
-		dbg("%s(%d) Not enough credit - fifo %d TxCredit %d",
+		dev_dbg(dev, "%s(%d) Not enough credit - fifo %d TxCredit %d\n",
 			__func__, edge_port->port->number, fifo->count,
 			edge_port->txCredits);
 		goto exit_send;
@@ -1315,8 +1307,7 @@
 	}
 
 	if (count)
-		usb_serial_debug_data(debug, &edge_port->port->dev,
-						__func__, count, &buffer[2]);
+		usb_serial_debug_data(&edge_port->port->dev, __func__, count, &buffer[2]);
 
 	/* fill up the urb with all of our data and submit it */
 	usb_fill_bulk_urb(urb, edge_serial->serial->dev,
@@ -1341,8 +1332,8 @@
 		edge_port->txCredits += count;
 		edge_port->icount.tx -= count;
 	}
-	dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d",
-			__func__, count, edge_port->txCredits, fifo->count);
+	dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n",
+		__func__, count, edge_port->txCredits, fifo->count);
 
 exit_send:
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
@@ -1363,17 +1354,13 @@
 	int room;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	if (edge_port == NULL)
 		return 0;
 	if (edge_port->closePending)
 		return 0;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!edge_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return 0;
 	}
 
@@ -1382,7 +1369,7 @@
 	room = edge_port->txCredits - edge_port->txfifo.count;
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -1403,15 +1390,13 @@
 	int num_chars;
 	unsigned long flags;
 
-	dbg("%s", __func__);
-
 	if (edge_port == NULL)
 		return 0;
 	if (edge_port->closePending)
 		return 0;
 
 	if (!edge_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return 0;
 	}
 
@@ -1420,8 +1405,8 @@
 						edge_port->txfifo.count;
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 	if (num_chars) {
-		dbg("%s(port %d) - returns %d", __func__,
-						port->number, num_chars);
+		dev_dbg(&port->dev, "%s(port %d) - returns %d\n", __func__,
+			port->number, num_chars);
 	}
 
 	return num_chars;
@@ -1439,13 +1424,11 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -1479,13 +1462,11 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -1517,18 +1498,14 @@
 	unsigned int cflag;
 
 	cflag = tty->termios.c_cflag;
-	dbg("%s - clfag %08x iflag %08x", __func__,
-	    tty->termios.c_cflag, tty->termios.c_iflag);
-	dbg("%s - old clfag %08x old iflag %08x", __func__,
-	    old_termios->c_cflag, old_termios->c_iflag);
-
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios.c_cflag, tty->termios.c_iflag);
+	dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag);
 
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -1556,7 +1533,7 @@
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
 	if (edge_port->maxTxCredits == edge_port->txCredits &&
 	    edge_port->txfifo.count == 0) {
-		dbg("%s -- Empty", __func__);
+		dev_dbg(&edge_port->port->dev, "%s -- Empty\n", __func__);
 		result = TIOCSER_TEMT;
 	}
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
@@ -1573,8 +1550,6 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	unsigned int mcr;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	mcr = edge_port->shadowMCR;
 	if (set & TIOCM_RTS)
 		mcr |= MCR_RTS;
@@ -1605,8 +1580,6 @@
 	unsigned int msr;
 	unsigned int mcr;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	msr = edge_port->shadowMSR;
 	mcr = edge_port->shadowMCR;
 	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
@@ -1616,9 +1589,6 @@
 		  | ((msr & EDGEPORT_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
 		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
-
-	dbg("%s -- %x", __func__, result);
-
 	return result;
 }
 
@@ -1642,8 +1612,8 @@
 	icount->brk = cnow.brk;
 	icount->buf_overrun = cnow.buf_overrun;
 
-	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
-			__func__,  port->number, icount->rx, icount->tx);
+	dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__,
+		port->number, icount->rx, icount->tx);
 	return 0;
 }
 
@@ -1686,19 +1656,19 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
 
 	switch (cmd) {
 	case TIOCSERGETLSR:
-		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCSERGETLSR\n", __func__,  port->number);
 		return get_lsr_info(edge_port, (unsigned int __user *) arg);
 
 	case TIOCGSERIAL:
-		dbg("%s (%d) TIOCGSERIAL", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__,  port->number);
 		return get_serial_info(edge_port, (struct serial_struct __user *) arg);
 
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number);
 		cprev = edge_port->icount;
 		while (1) {
 			prepare_to_wait(&edge_port->delta_msr_wait,
@@ -1745,7 +1715,7 @@
 		/* flush and chase */
 		edge_port->chaseResponsePending = true;
 
-		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__);
+		dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__);
 		status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0);
 		if (status == 0) {
 			/* block until chase finished */
@@ -1759,16 +1729,16 @@
 	    ((edge_serial->is_epic) &&
 	     (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
 		if (break_state == -1) {
-			dbg("%s - Sending IOSP_CMD_SET_BREAK", __func__);
+			dev_dbg(&port->dev, "%s - Sending IOSP_CMD_SET_BREAK\n", __func__);
 			status = send_iosp_ext_cmd(edge_port,
 						IOSP_CMD_SET_BREAK, 0);
 		} else {
-			dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __func__);
+			dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLEAR_BREAK\n", __func__);
 			status = send_iosp_ext_cmd(edge_port,
 						IOSP_CMD_CLEAR_BREAK, 0);
 		}
 		if (status)
-			dbg("%s - error sending break set/clear command.",
+			dev_dbg(&port->dev, "%s - error sending break set/clear command.\n",
 				__func__);
 	}
 }
@@ -1781,20 +1751,19 @@
 static void process_rcvd_data(struct edgeport_serial *edge_serial,
 				unsigned char *buffer, __u16 bufferLength)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
 	struct usb_serial_port *port;
 	struct edgeport_port *edge_port;
 	struct tty_struct *tty;
 	__u16 lastBufferLength;
 	__u16 rxLen;
 
-	dbg("%s", __func__);
-
 	lastBufferLength = bufferLength + 1;
 
 	while (bufferLength > 0) {
 		/* failsafe incase we get a message that we don't understand */
 		if (lastBufferLength == bufferLength) {
-			dbg("%s - stuck in loop, exiting it.", __func__);
+			dev_dbg(dev, "%s - stuck in loop, exiting it.\n", __func__);
 			break;
 		}
 		lastBufferLength = bufferLength;
@@ -1815,8 +1784,8 @@
 			++buffer;
 			--bufferLength;
 
-			dbg("%s - Hdr1=%02X Hdr2=%02X", __func__,
-			    edge_serial->rxHeader1, edge_serial->rxHeader2);
+			dev_dbg(dev, "%s - Hdr1=%02X Hdr2=%02X\n", __func__,
+				edge_serial->rxHeader1, edge_serial->rxHeader2);
 			/* Process depending on whether this header is
 			 * data or status */
 
@@ -1855,10 +1824,10 @@
 				    IOSP_GET_HDR_DATA_LEN(
 						edge_serial->rxHeader1,
 						edge_serial->rxHeader2);
-				dbg("%s - Data for Port %u Len %u",
-						__func__,
-						edge_serial->rxPort,
-						edge_serial->rxBytesRemaining);
+				dev_dbg(dev, "%s - Data for Port %u Len %u\n",
+					__func__,
+					edge_serial->rxPort,
+					edge_serial->rxBytesRemaining);
 
 				/* ASSERT(DevExt->RxPort < DevExt->NumPorts);
 				 * ASSERT(DevExt->RxBytesRemaining <
@@ -1896,7 +1865,7 @@
 					tty = tty_port_tty_get(
 						&edge_port->port->port);
 					if (tty) {
-						dbg("%s - Sending %d bytes to TTY for port %d",
+						dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n",
 							__func__, rxLen, edge_serial->rxPort);
 						edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
 						tty_kref_put(tty);
@@ -1935,6 +1904,7 @@
 	struct usb_serial_port *port;
 	struct edgeport_port *edge_port;
 	struct tty_struct *tty;
+	struct device *dev;
 	__u8 code = edge_serial->rxStatusCode;
 
 	/* switch the port pointer to the one being currently talked about */
@@ -1946,16 +1916,15 @@
 					__func__, edge_serial->rxPort);
 		return;
 	}
-
-	dbg("%s - port %d", __func__, edge_serial->rxPort);
+	dev = &port->dev;
 
 	if (code == IOSP_EXT_STATUS) {
 		switch (byte2) {
 		case IOSP_EXT_STATUS_CHASE_RSP:
 			/* we want to do EXT status regardless of port
 			 * open/closed */
-			dbg("%s - Port %u EXT CHASE_RSP Data = %02x",
-					__func__, edge_serial->rxPort, byte3);
+			dev_dbg(dev, "%s - Port %u EXT CHASE_RSP Data = %02x\n",
+				__func__, edge_serial->rxPort, byte3);
 			/* Currently, the only EXT_STATUS is Chase, so process
 			 * here instead of one more call to one more subroutine
 			 * If/when more EXT_STATUS, there'll be more work to do
@@ -1970,7 +1939,8 @@
 			return;
 
 		case IOSP_EXT_STATUS_RX_CHECK_RSP:
-			dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3);
+			dev_dbg(dev, "%s ========== Port %u CHECK_RSP Sequence = %02x =============\n",
+				__func__, edge_serial->rxPort, byte3);
 			/* Port->RxCheckRsp = true; */
 			return;
 		}
@@ -1979,7 +1949,8 @@
 	if (code == IOSP_STATUS_OPEN_RSP) {
 		edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
 		edge_port->maxTxCredits = edge_port->txCredits;
-		dbg("%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits);
+		dev_dbg(dev, "%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d\n",
+			__func__, edge_serial->rxPort, byte2, edge_port->txCredits);
 		handle_new_msr(edge_port, byte2);
 
 		/* send the current line settings to the port so we are
@@ -2008,27 +1979,27 @@
 	switch (code) {
 	/* Not currently sent by Edgeport */
 	case IOSP_STATUS_LSR:
-		dbg("%s - Port %u LSR Status = %02x",
-					__func__, edge_serial->rxPort, byte2);
+		dev_dbg(dev, "%s - Port %u LSR Status = %02x\n",
+			__func__, edge_serial->rxPort, byte2);
 		handle_new_lsr(edge_port, false, byte2, 0);
 		break;
 
 	case IOSP_STATUS_LSR_DATA:
-		dbg("%s - Port %u LSR Status = %02x, Data = %02x",
-				__func__, edge_serial->rxPort, byte2, byte3);
+		dev_dbg(dev, "%s - Port %u LSR Status = %02x, Data = %02x\n",
+			__func__, edge_serial->rxPort, byte2, byte3);
 		/* byte2 is LSR Register */
 		/* byte3 is broken data byte */
 		handle_new_lsr(edge_port, true, byte2, byte3);
 		break;
 	/*
 	 *	case IOSP_EXT_4_STATUS:
-	 *		dbg("%s - Port %u LSR Status = %02x Data = %02x",
+	 *		dev_dbg(dev, "%s - Port %u LSR Status = %02x Data = %02x\n",
 	 *			__func__, edge_serial->rxPort, byte2, byte3);
 	 *		break;
 	 */
 	case IOSP_STATUS_MSR:
-		dbg("%s - Port %u MSR Status = %02x",
-					__func__, edge_serial->rxPort, byte2);
+		dev_dbg(dev, "%s - Port %u MSR Status = %02x\n",
+			__func__, edge_serial->rxPort, byte2);
 		/*
 		 * Process this new modem status and generate appropriate
 		 * events, etc, based on the new status. This routine
@@ -2038,7 +2009,7 @@
 		break;
 
 	default:
-		dbg("%s - Unrecognized IOSP status code %u", __func__, code);
+		dev_dbg(dev, "%s - Unrecognized IOSP status code %u\n", __func__, code);
 		break;
 	}
 }
@@ -2073,8 +2044,6 @@
 {
 	struct  async_icount *icount;
 
-	dbg("%s %02x", __func__, newMsr);
-
 	if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
 			EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
@@ -2107,8 +2076,6 @@
 		(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
 	struct async_icount *icount;
 
-	dbg("%s - %02x", __func__, newLsr);
-
 	edge_port->shadowLSR = lsr;
 
 	if (newLsr & LSR_BREAK) {
@@ -2156,7 +2123,7 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-	dbg("%s - %x, %x, %d", __func__, extAddr, addr, length);
+	dev_dbg(&serial->dev->dev, "%s - %x, %x, %d\n", __func__, extAddr, addr, length);
 
 	transfer_buffer =  kmalloc(64, GFP_KERNEL);
 	if (!transfer_buffer) {
@@ -2173,8 +2140,7 @@
 		else
 			current_length = length;
 
-/*		dbg("%s - writing %x, %x, %d", __func__,
-					extAddr, addr, current_length); */
+/*		dev_dbg(&serial->dev->dev, "%s - writing %x, %x, %d\n", __func__, extAddr, addr, current_length); */
 		memcpy(transfer_buffer, data, current_length);
 		result = usb_control_msg(serial->dev,
 					usb_sndctrlpipe(serial->dev, 0),
@@ -2207,8 +2173,6 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-/*	dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); */
-
 	transfer_buffer =  kmalloc(64, GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n",
@@ -2223,8 +2187,6 @@
 			current_length = 64;
 		else
 			current_length = length;
-/*		dbg("%s - writing %x, %x, %d", __func__,
-					extAddr, addr, current_length); */
 		memcpy(transfer_buffer, data, current_length);
 		result = usb_control_msg(serial->dev,
 					usb_sndctrlpipe(serial->dev, 0),
@@ -2257,8 +2219,6 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-	dbg("%s - %x, %x, %d", __func__, extAddr, addr, length);
-
 	transfer_buffer =  kmalloc(64, GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_err(&serial->dev->dev,
@@ -2273,8 +2233,6 @@
 			current_length = 64;
 		else
 			current_length = length;
-/*		dbg("%s - %x, %x, %d", __func__,
-				extAddr, addr, current_length); */
 		result = usb_control_msg(serial->dev,
 					usb_rcvctrlpipe(serial->dev, 0),
 					USB_REQUEST_ION_READ_ROM,
@@ -2305,8 +2263,6 @@
 	int             length = 0;
 	int             status = 0;
 
-	dbg("%s - %d, %d", __func__, command, param);
-
 	buffer = kmalloc(10, GFP_ATOMIC);
 	if (!buffer) {
 		dev_err(&edge_port->port->dev,
@@ -2339,11 +2295,11 @@
 {
 	struct edgeport_serial *edge_serial =
 				usb_get_serial_data(edge_port->port->serial);
+	struct device *dev = &edge_port->port->dev;
 	int status = 0;
 	struct urb *urb;
 
-	usb_serial_debug_data(debug, &edge_port->port->dev,
-						__func__, length, buffer);
+	usb_serial_debug_data(dev, __func__, length, buffer);
 
 	/* Allocate our next urb */
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -2351,8 +2307,8 @@
 		return -ENOMEM;
 
 	atomic_inc(&CmdUrbs);
-	dbg("%s - ALLOCATE URB %p (outstanding %d)",
-				__func__, urb, atomic_read(&CmdUrbs));
+	dev_dbg(dev, "%s - ALLOCATE URB %p (outstanding %d)\n",
+		__func__, urb, atomic_read(&CmdUrbs));
 
 	usb_fill_bulk_urb(urb, edge_serial->serial->dev,
 			usb_sndbulkpipe(edge_serial->serial->dev,
@@ -2364,9 +2320,8 @@
 
 	if (status) {
 		/* something went wrong */
-		dev_err(&edge_port->port->dev,
-		    "%s - usb_submit_urb(write command) failed, status = %d\n",
-							__func__, status);
+		dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n",
+			__func__, status);
 		usb_kill_urb(urb);
 		usb_free_urb(urb);
 		atomic_dec(&CmdUrbs);
@@ -2378,7 +2333,7 @@
 
 	if (edge_port->commandPending) {
 		/* command timed out */
-		dbg("%s - command timed out", __func__);
+		dev_dbg(dev, "%s - command timed out\n", __func__);
 		status = -EINVAL;
 	}
 #endif
@@ -2396,6 +2351,7 @@
 {
 	struct edgeport_serial *edge_serial =
 				usb_get_serial_data(edge_port->port->serial);
+	struct device *dev = &edge_port->port->dev;
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	int cmdLen = 0;
@@ -2406,26 +2362,24 @@
 
 	if (edge_serial->is_epic &&
 	    !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) {
-		dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
-		    edge_port->port->number, baudRate);
+		dev_dbg(dev, "SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d\n",
+			edge_port->port->number, baudRate);
 		return 0;
 	}
 
-	dbg("%s - port = %d, baud = %d", __func__,
-					edge_port->port->number, baudRate);
+	dev_dbg(dev, "%s - port = %d, baud = %d\n", __func__,
+		edge_port->port->number, baudRate);
 
-	status = calc_baud_rate_divisor(baudRate, &divisor);
+	status = calc_baud_rate_divisor(dev, baudRate, &divisor);
 	if (status) {
-		dev_err(&edge_port->port->dev, "%s - bad baud rate\n",
-								__func__);
+		dev_err(dev, "%s - bad baud rate\n", __func__);
 		return status;
 	}
 
 	/* Alloc memory for the string of commands. */
 	cmdBuffer =  kmalloc(0x100, GFP_ATOMIC);
 	if (!cmdBuffer) {
-		dev_err(&edge_port->port->dev,
-			"%s - kmalloc(%d) failed.\n", __func__, 0x100);
+		dev_err(dev, "%s - kmalloc(%d) failed.\n", __func__, 0x100);
 		return -ENOMEM;
 	}
 	currCmd = cmdBuffer;
@@ -2456,14 +2410,11 @@
  *	this function calculates the proper baud rate divisor for the specified
  *	baud rate.
  *****************************************************************************/
-static int calc_baud_rate_divisor(int baudrate, int *divisor)
+static int calc_baud_rate_divisor(struct device *dev, int baudrate, int *divisor)
 {
 	int i;
 	__u16 custom;
 
-
-	dbg("%s - %d", __func__, baudrate);
-
 	for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
 		if (divisor_table[i].BaudRate == baudrate) {
 			*divisor = divisor_table[i].Divisor;
@@ -2480,7 +2431,7 @@
 
 		*divisor = custom;
 
-		dbg("%s - Baud %d = %d", __func__, baudrate, custom);
+		dev_dbg(dev, "%s - Baud %d = %d\n", __func__, baudrate, custom);
 		return 0;
 	}
 
@@ -2497,25 +2448,26 @@
 {
 	struct edgeport_serial *edge_serial =
 				usb_get_serial_data(edge_port->port->serial);
+	struct device *dev = &edge_port->port->dev;
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	unsigned long cmdLen = 0;
 	int status;
 
-	dbg("%s - write to %s register 0x%02x",
-			(regNum == MCR) ? "MCR" : "LCR", __func__, regValue);
+	dev_dbg(dev, "%s - write to %s register 0x%02x\n",
+		(regNum == MCR) ? "MCR" : "LCR", __func__, regValue);
 
 	if (edge_serial->is_epic &&
 	    !edge_serial->epic_descriptor.Supports.IOSPWriteMCR &&
 	    regNum == MCR) {
-		dbg("SendCmdWriteUartReg - Not writing to MCR Register");
+		dev_dbg(dev, "SendCmdWriteUartReg - Not writing to MCR Register\n");
 		return 0;
 	}
 
 	if (edge_serial->is_epic &&
 	    !edge_serial->epic_descriptor.Supports.IOSPWriteLCR &&
 	    regNum == LCR) {
-		dbg("SendCmdWriteUartReg - Not writing to LCR Register");
+		dev_dbg(dev, "SendCmdWriteUartReg - Not writing to LCR Register\n");
 		return 0;
 	}
 
@@ -2550,6 +2502,7 @@
 static void change_port_settings(struct tty_struct *tty,
 	struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+	struct device *dev = &edge_port->port->dev;
 	struct edgeport_serial *edge_serial =
 			usb_get_serial_data(edge_port->port->serial);
 	int baud;
@@ -2562,11 +2515,11 @@
 	__u8 txFlow;
 	int status;
 
-	dbg("%s - port %d", __func__, edge_port->port->number);
+	dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number);
 
 	if (!edge_port->open &&
 	    !edge_port->openPending) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -2575,20 +2528,20 @@
 	switch (cflag & CSIZE) {
 	case CS5:
 		lData = LCR_BITS_5; mask = 0x1f;
-		dbg("%s - data bits = 5", __func__);
+		dev_dbg(dev, "%s - data bits = 5\n", __func__);
 		break;
 	case CS6:
 		lData = LCR_BITS_6; mask = 0x3f;
-		dbg("%s - data bits = 6", __func__);
+		dev_dbg(dev, "%s - data bits = 6\n", __func__);
 		break;
 	case CS7:
 		lData = LCR_BITS_7; mask = 0x7f;
-		dbg("%s - data bits = 7", __func__);
+		dev_dbg(dev, "%s - data bits = 7\n", __func__);
 		break;
 	default:
 	case CS8:
 		lData = LCR_BITS_8;
-		dbg("%s - data bits = 8", __func__);
+		dev_dbg(dev, "%s - data bits = 8\n", __func__);
 		break;
 	}
 
@@ -2597,28 +2550,28 @@
 		if (cflag & CMSPAR) {
 			if (cflag & PARODD) {
 				lParity = LCR_PAR_MARK;
-				dbg("%s - parity = mark", __func__);
+				dev_dbg(dev, "%s - parity = mark\n", __func__);
 			} else {
 				lParity = LCR_PAR_SPACE;
-				dbg("%s - parity = space", __func__);
+				dev_dbg(dev, "%s - parity = space\n", __func__);
 			}
 		} else if (cflag & PARODD) {
 			lParity = LCR_PAR_ODD;
-			dbg("%s - parity = odd", __func__);
+			dev_dbg(dev, "%s - parity = odd\n", __func__);
 		} else {
 			lParity = LCR_PAR_EVEN;
-			dbg("%s - parity = even", __func__);
+			dev_dbg(dev, "%s - parity = even\n", __func__);
 		}
 	} else {
-		dbg("%s - parity = none", __func__);
+		dev_dbg(dev, "%s - parity = none\n", __func__);
 	}
 
 	if (cflag & CSTOPB) {
 		lStop = LCR_STOP_2;
-		dbg("%s - stop bits = 2", __func__);
+		dev_dbg(dev, "%s - stop bits = 2\n", __func__);
 	} else {
 		lStop = LCR_STOP_1;
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(dev, "%s - stop bits = 1\n", __func__);
 	}
 
 	/* figure out the flow control settings */
@@ -2626,9 +2579,9 @@
 	if (cflag & CRTSCTS) {
 		rxFlow |= IOSP_RX_FLOW_RTS;
 		txFlow |= IOSP_TX_FLOW_CTS;
-		dbg("%s - RTS/CTS is enabled", __func__);
+		dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__);
 	} else {
-		dbg("%s - RTS/CTS is disabled", __func__);
+		dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__);
 	}
 
 	/* if we are implementing XON/XOFF, set the start and stop character
@@ -2649,19 +2602,19 @@
 		/* if we are implementing INBOUND XON/XOFF */
 		if (I_IXOFF(tty)) {
 			rxFlow |= IOSP_RX_FLOW_XON_XOFF;
-			dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-					__func__, start_char, stop_char);
+			dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
+				__func__, start_char, stop_char);
 		} else {
-			dbg("%s - INBOUND XON/XOFF is disabled", __func__);
+			dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__);
 		}
 
 		/* if we are implementing OUTBOUND XON/XOFF */
 		if (I_IXON(tty)) {
 			txFlow |= IOSP_TX_FLOW_XON_XOFF;
-			dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-					__func__, start_char, stop_char);
+			dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
+				__func__, start_char, stop_char);
 		} else {
-			dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
+			dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__);
 		}
 	}
 
@@ -2704,7 +2657,7 @@
 		baud = 9600;
 	}
 
-	dbg("%s - baud rate = %d", __func__, baud);
+	dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);
 	status = send_cmd_write_baud_rate(edge_port, baud);
 	if (status == -1) {
 		/* Speed change was not possible - put back the old speed */
@@ -2746,9 +2699,10 @@
  ****************************************************************************/
 static void get_manufacturing_desc(struct edgeport_serial *edge_serial)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
 	int response;
 
-	dbg("getting manufacturer descriptor");
+	dev_dbg(dev, "getting manufacturer descriptor\n");
 
 	response = rom_read(edge_serial->serial,
 				(EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16,
@@ -2757,42 +2711,41 @@
 				(__u8 *)(&edge_serial->manuf_descriptor));
 
 	if (response < 1)
-		dev_err(&edge_serial->serial->dev->dev,
-			"error in getting manufacturer descriptor\n");
+		dev_err(dev, "error in getting manufacturer descriptor\n");
 	else {
 		char string[30];
-		dbg("**Manufacturer Descriptor");
-		dbg("  RomSize:        %dK",
+		dev_dbg(dev, "**Manufacturer Descriptor\n");
+		dev_dbg(dev, "  RomSize:        %dK\n",
 			edge_serial->manuf_descriptor.RomSize);
-		dbg("  RamSize:        %dK",
+		dev_dbg(dev, "  RamSize:        %dK\n",
 			edge_serial->manuf_descriptor.RamSize);
-		dbg("  CpuRev:         %d",
+		dev_dbg(dev, "  CpuRev:         %d\n",
 			edge_serial->manuf_descriptor.CpuRev);
-		dbg("  BoardRev:       %d",
+		dev_dbg(dev, "  BoardRev:       %d\n",
 			edge_serial->manuf_descriptor.BoardRev);
-		dbg("  NumPorts:       %d",
+		dev_dbg(dev, "  NumPorts:       %d\n",
 			edge_serial->manuf_descriptor.NumPorts);
-		dbg("  DescDate:       %d/%d/%d",
+		dev_dbg(dev, "  DescDate:       %d/%d/%d\n",
 			edge_serial->manuf_descriptor.DescDate[0],
 			edge_serial->manuf_descriptor.DescDate[1],
 			edge_serial->manuf_descriptor.DescDate[2]+1900);
 		unicode_to_ascii(string, sizeof(string),
 			edge_serial->manuf_descriptor.SerialNumber,
 			edge_serial->manuf_descriptor.SerNumLength/2);
-		dbg("  SerialNumber: %s", string);
+		dev_dbg(dev, "  SerialNumber: %s\n", string);
 		unicode_to_ascii(string, sizeof(string),
 			edge_serial->manuf_descriptor.AssemblyNumber,
 			edge_serial->manuf_descriptor.AssemblyNumLength/2);
-		dbg("  AssemblyNumber: %s", string);
+		dev_dbg(dev, "  AssemblyNumber: %s\n", string);
 		unicode_to_ascii(string, sizeof(string),
 		    edge_serial->manuf_descriptor.OemAssyNumber,
 		    edge_serial->manuf_descriptor.OemAssyNumLength/2);
-		dbg("  OemAssyNumber:  %s", string);
-		dbg("  UartType:       %d",
+		dev_dbg(dev, "  OemAssyNumber:  %s\n", string);
+		dev_dbg(dev, "  UartType:       %d\n",
 			edge_serial->manuf_descriptor.UartType);
-		dbg("  IonPid:         %d",
+		dev_dbg(dev, "  IonPid:         %d\n",
 			edge_serial->manuf_descriptor.IonPid);
-		dbg("  IonConfig:      %d",
+		dev_dbg(dev, "  IonConfig:      %d\n",
 			edge_serial->manuf_descriptor.IonConfig);
 	}
 }
@@ -2805,9 +2758,10 @@
  ****************************************************************************/
 static void get_boot_desc(struct edgeport_serial *edge_serial)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
 	int response;
 
-	dbg("getting boot descriptor");
+	dev_dbg(dev, "getting boot descriptor\n");
 
 	response = rom_read(edge_serial->serial,
 				(EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16,
@@ -2816,23 +2770,22 @@
 				(__u8 *)(&edge_serial->boot_descriptor));
 
 	if (response < 1)
-		dev_err(&edge_serial->serial->dev->dev,
-				"error in getting boot descriptor\n");
+		dev_err(dev, "error in getting boot descriptor\n");
 	else {
-		dbg("**Boot Descriptor:");
-		dbg("  BootCodeLength: %d",
-		    le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
-		dbg("  MajorVersion:   %d",
+		dev_dbg(dev, "**Boot Descriptor:\n");
+		dev_dbg(dev, "  BootCodeLength: %d\n",
+			le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
+		dev_dbg(dev, "  MajorVersion:   %d\n",
 			edge_serial->boot_descriptor.MajorVersion);
-		dbg("  MinorVersion:   %d",
+		dev_dbg(dev, "  MinorVersion:   %d\n",
 			edge_serial->boot_descriptor.MinorVersion);
-		dbg("  BuildNumber:    %d",
+		dev_dbg(dev, "  BuildNumber:    %d\n",
 			le16_to_cpu(edge_serial->boot_descriptor.BuildNumber));
-		dbg("  Capabilities:   0x%x",
+		dev_dbg(dev, "  Capabilities:   0x%x\n",
 		      le16_to_cpu(edge_serial->boot_descriptor.Capabilities));
-		dbg("  UConfig0:       %d",
+		dev_dbg(dev, "  UConfig0:       %d\n",
 			edge_serial->boot_descriptor.UConfig0);
-		dbg("  UConfig1:       %d",
+		dev_dbg(dev, "  UConfig1:       %d\n",
 			edge_serial->boot_descriptor.UConfig1);
 	}
 }
@@ -2844,6 +2797,7 @@
  ****************************************************************************/
 static void load_application_firmware(struct edgeport_serial *edge_serial)
 {
+	struct device *dev = &edge_serial->serial->dev->dev;
 	const struct ihex_binrec *rec;
 	const struct firmware *fw;
 	const char *fw_name;
@@ -2864,7 +2818,7 @@
 			break;
 
 		case EDGE_DOWNLOAD_FILE_NONE:
-			dbg("No download file specified, skipping download");
+			dev_dbg(dev, "No download file specified, skipping download\n");
 			return;
 
 		default:
@@ -2874,7 +2828,7 @@
 	response = request_ihex_firmware(&fw, fw_name,
 				    &edge_serial->serial->dev->dev);
 	if (response) {
-		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
+		dev_err(dev, "Failed to load image \"%s\" err %d\n",
 		       fw_name, response);
 		return;
 	}
@@ -2882,7 +2836,7 @@
 	rec = (const struct ihex_binrec *)fw->data;
 	build = (rec->data[2] << 8) | rec->data[3];
 
-	dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build);
+	dev_dbg(dev, "%s %d.%d.%d\n", fw_info, rec->data[0], rec->data[1], build);
 
 	edge_serial->product_info.FirmwareMajorVersion = rec->data[0];
 	edge_serial->product_info.FirmwareMinorVersion = rec->data[1];
@@ -2905,10 +2859,10 @@
 		}
 	}
 
-	dbg("sending exec_dl_code");
-	response = usb_control_msg (edge_serial->serial->dev, 
-				    usb_sndctrlpipe(edge_serial->serial->dev, 0), 
-				    USB_REQUEST_ION_EXEC_DL_CODE, 
+	dev_dbg(dev, "sending exec_dl_code\n");
+	response = usb_control_msg (edge_serial->serial->dev,
+				    usb_sndctrlpipe(edge_serial->serial->dev, 0),
+				    USB_REQUEST_ION_EXEC_DL_CODE,
 				    0x40, 0x4000, 0x0001, NULL, 0, 3000);
 
 	release_firmware(fw);
@@ -2923,6 +2877,7 @@
 	struct edgeport_serial *edge_serial;
 	struct edgeport_port *edge_port;
 	struct usb_device *dev;
+	struct device *ddev = &serial->dev->dev;
 	int i, j;
 	int response;
 	bool interrupt_in_found;
@@ -2974,32 +2929,31 @@
 	/* serial->num_ports = serial->product_info.NumPorts; */
 	if ((!edge_serial->is_epic) &&
 	    (edge_serial->product_info.NumPorts != serial->num_ports)) {
-		dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
-			 "vs. core thinking we have %d ports, email "
-			 "greg@kroah.com this information.\n",
+		dev_warn(ddev,
+			"Device Reported %d serial ports vs. core thinking we have %d ports, email greg@kroah.com this information.\n",
 			 edge_serial->product_info.NumPorts,
 			 serial->num_ports);
 	}
 
-	dbg("%s - time 1 %ld", __func__, jiffies);
+	dev_dbg(ddev, "%s - time 1 %ld\n", __func__, jiffies);
 
 	/* If not an EPiC device */
 	if (!edge_serial->is_epic) {
 		/* now load the application firmware into this device */
 		load_application_firmware(edge_serial);
 
-		dbg("%s - time 2 %ld", __func__, jiffies);
+		dev_dbg(ddev, "%s - time 2 %ld\n", __func__, jiffies);
 
 		/* Check current Edgeport EEPROM and update if necessary */
 		update_edgeport_E2PROM(edge_serial);
 
-		dbg("%s - time 3 %ld", __func__, jiffies);
+		dev_dbg(ddev, "%s - time 3 %ld\n", __func__, jiffies);
 
 		/* set the configuration to use #1 */
-/*		dbg("set_configuration 1"); */
+/*		dev_dbg(ddev, "set_configuration 1\n"); */
 /*		usb_set_configuration (dev, 1); */
 	}
-	dbg("  FirmwareMajorVersion  %d.%d.%d",
+	dev_dbg(ddev, "  FirmwareMajorVersion  %d.%d.%d\n",
 	    edge_serial->product_info.FirmwareMajorVersion,
 	    edge_serial->product_info.FirmwareMinorVersion,
 	    le16_to_cpu(edge_serial->product_info.FirmwareBuildNumber));
@@ -3011,8 +2965,7 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
 		if (edge_port == NULL) {
-			dev_err(&serial->dev->dev, "%s - Out of memory\n",
-								   __func__);
+			dev_err(ddev, "%s - Out of memory\n", __func__);
 			for (j = 0; j < i; ++j) {
 				kfree(usb_get_serial_port_data(serial->port[j]));
 				usb_set_serial_port_data(serial->port[j],
@@ -3044,19 +2997,19 @@
 			if (!interrupt_in_found &&
 			    (usb_endpoint_is_int_in(endpoint))) {
 				/* we found a interrupt in endpoint */
-				dbg("found interrupt in");
+				dev_dbg(ddev, "found interrupt in\n");
 
 				/* not set up yet, so do it now */
 				edge_serial->interrupt_read_urb =
 						usb_alloc_urb(0, GFP_KERNEL);
 				if (!edge_serial->interrupt_read_urb) {
-					dev_err(&dev->dev, "out of memory\n");
+					dev_err(ddev, "out of memory\n");
 					return -ENOMEM;
 				}
 				edge_serial->interrupt_in_buffer =
 					kmalloc(buffer_size, GFP_KERNEL);
 				if (!edge_serial->interrupt_in_buffer) {
-					dev_err(&dev->dev, "out of memory\n");
+					dev_err(ddev, "out of memory\n");
 					usb_free_urb(edge_serial->interrupt_read_urb);
 					return -ENOMEM;
 				}
@@ -3081,13 +3034,13 @@
 			if (!bulk_in_found &&
 				(usb_endpoint_is_bulk_in(endpoint))) {
 				/* we found a bulk in endpoint */
-				dbg("found bulk in");
+				dev_dbg(ddev, "found bulk in\n");
 
 				/* not set up yet, so do it now */
 				edge_serial->read_urb =
 						usb_alloc_urb(0, GFP_KERNEL);
 				if (!edge_serial->read_urb) {
-					dev_err(&dev->dev, "out of memory\n");
+					dev_err(ddev, "out of memory\n");
 					return -ENOMEM;
 				}
 				edge_serial->bulk_in_buffer =
@@ -3114,7 +3067,7 @@
 			if (!bulk_out_found &&
 			    (usb_endpoint_is_bulk_out(endpoint))) {
 				/* we found a bulk out endpoint */
-				dbg("found bulk out");
+				dev_dbg(ddev, "found bulk out\n");
 				edge_serial->bulk_out_endpoint =
 						endpoint->bEndpointAddress;
 				bulk_out_found = true;
@@ -3122,8 +3075,7 @@
 		}
 
 		if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
-			dev_err(&dev->dev, "Error - the proper endpoints "
-				"were not found!\n");
+			dev_err(ddev, "Error - the proper endpoints were not found!\n");
 			return -ENODEV;
 		}
 
@@ -3132,8 +3084,7 @@
 		response = usb_submit_urb(edge_serial->interrupt_read_urb,
 								GFP_KERNEL);
 		if (response)
-			dev_err(&dev->dev,
-				"%s - Error %d submitting control urb\n",
+			dev_err(ddev, "%s - Error %d submitting control urb\n",
 				__func__, response);
 	}
 	return response;
@@ -3148,8 +3099,6 @@
 {
 	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 
-	dbg("%s", __func__);
-
 	/* stop reads and writes on all ports */
 	/* free up our endpoint stuff */
 	if (edge_serial->is_epic) {
@@ -3173,8 +3122,6 @@
 	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 	int i;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
 
@@ -3190,6 +3137,3 @@
 MODULE_FIRMWARE("edgeport/boot2.fw");
 MODULE_FIRMWARE("edgeport/down.fw");
 MODULE_FIRMWARE("edgeport/down2.fw");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 765978a..a2209cd 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -201,8 +201,6 @@
 static unsigned char OperationalMinorVersion;
 static unsigned short OperationalBuildNumber;
 
-static bool debug;
-
 static int closing_wait = EDGE_CLOSING_WAIT;
 static bool ignore_cpu_rev;
 static int default_uart_mode;		/* RS232 */
@@ -233,8 +231,8 @@
 	if (status < 0)
 		return status;
 	if (status != size) {
-		dbg("%s - wanted to write %d, but only wrote %d",
-					     __func__, size, status);
+		dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n",
+			__func__, size, status);
 		return -ECOMM;
 	}
 	return 0;
@@ -251,8 +249,8 @@
 	if (status < 0)
 		return status;
 	if (status != size) {
-		dbg("%s - wanted to write %d, but only wrote %d",
-		     __func__, size, status);
+		dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n",
+			__func__, size, status);
 		return -ECOMM;
 	}
 	return 0;
@@ -270,7 +268,7 @@
 {
 	int port_number = port->number - port->serial->minor;
 
-	dbg("%s - port %d, mask %x", __func__, port_number, mask);
+	dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask);
 
 	return send_cmd(port->serial->dev,
 					UMPC_PURGE_PORT,
@@ -295,7 +293,7 @@
 	__u8 read_length;
 	__be16 be_start_address;
 
-	dbg("%s - @ %x for %d", __func__, start_address, length);
+	dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
 
 	/* Read in blocks of 64 bytes
 	 * (TI firmware can't handle more than 64 byte reads)
@@ -307,8 +305,7 @@
 			read_length = (__u8)length;
 
 		if (read_length > 1) {
-			dbg("%s - @ %x for %d", __func__,
-			     start_address, read_length);
+			dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length);
 		}
 		be_start_address = cpu_to_be16(start_address);
 		status = ti_vread_sync(dev, UMPC_MEMORY_READ,
@@ -317,13 +314,12 @@
 					buffer, read_length);
 
 		if (status) {
-			dbg("%s - ERROR %x", __func__, status);
+			dev_dbg(&dev->dev, "%s - ERROR %x\n", __func__, status);
 			return status;
 		}
 
 		if (read_length > 1)
-			usb_serial_debug_data(debug, &dev->dev, __func__,
-					      read_length, buffer);
+			usb_serial_debug_data(&dev->dev, __func__, read_length, buffer);
 
 		/* Update pointers/length */
 		start_address += read_length;
@@ -353,15 +349,14 @@
 				UMPC_MEMORY_READ, serial->TI_I2C_Type,
 				(__u16)(start_address+i), &buffer[i], 0x01);
 		if (status) {
-			dbg("%s - ERROR %x", __func__, status);
+			dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status);
 			return status;
 		}
 	}
 
-	dbg("%s - start_address = %x, length = %d",
-					__func__, start_address, length);
-	usb_serial_debug_data(debug, &serial->serial->dev->dev,
-					__func__, length, buffer);
+	dev_dbg(&serial->serial->dev->dev, "%s - start_address = %x, length = %d\n",
+		__func__, start_address, length);
+	usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer);
 
 	serial->TiReadI2C = 1;
 
@@ -398,10 +393,8 @@
 			return status;
 	}
 
-	dbg("%s - start_sddr = %x, length = %d",
-					__func__, start_address, length);
-	usb_serial_debug_data(debug, &serial->serial->dev->dev,
-					__func__, length, buffer);
+	dev_dbg(&serial->serial->dev->dev, "%s - start_sddr = %x, length = %d\n", __func__, start_address, length);
+	usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer);
 
 	return status;
 }
@@ -411,6 +404,7 @@
 static int write_i2c_mem(struct edgeport_serial *serial,
 		int start_address, int length, __u8 address_type, __u8 *buffer)
 {
+	struct device *dev = &serial->serial->dev->dev;
 	int status = 0;
 	int write_length;
 	__be16 be_start_address;
@@ -424,10 +418,9 @@
 	if (write_length > length)
 		write_length = length;
 
-	dbg("%s - BytesInFirstPage Addr = %x, length = %d",
-					__func__, start_address, write_length);
-	usb_serial_debug_data(debug, &serial->serial->dev->dev,
-						__func__, write_length, buffer);
+	dev_dbg(dev, "%s - BytesInFirstPage Addr = %x, length = %d\n",
+		__func__, start_address, write_length);
+	usb_serial_debug_data(dev, __func__, write_length, buffer);
 
 	/* Write first page */
 	be_start_address = cpu_to_be16(start_address);
@@ -436,7 +429,7 @@
 				(__force __u16)be_start_address,
 				buffer,	write_length);
 	if (status) {
-		dbg("%s - ERROR %d", __func__, status);
+		dev_dbg(dev, "%s - ERROR %d\n", __func__, status);
 		return status;
 	}
 
@@ -452,10 +445,9 @@
 		else
 			write_length = length;
 
-		dbg("%s - Page Write Addr = %x, length = %d",
-					__func__, start_address, write_length);
-		usb_serial_debug_data(debug, &serial->serial->dev->dev,
-					__func__, write_length, buffer);
+		dev_dbg(dev, "%s - Page Write Addr = %x, length = %d\n",
+			__func__, start_address, write_length);
+		usb_serial_debug_data(dev, __func__, write_length, buffer);
 
 		/* Write next page */
 		be_start_address = cpu_to_be16(start_address);
@@ -464,8 +456,7 @@
 				(__force __u16)be_start_address,
 				buffer, write_length);
 		if (status) {
-			dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n",
-					__func__, status);
+			dev_err(dev, "%s - ERROR %d\n", __func__, status);
 			return status;
 		}
 
@@ -508,7 +499,7 @@
 	if (status)
 		goto exit_is_tx_active;
 
-	dbg("%s - XByteCount    0x%X", __func__, oedb->XByteCount);
+	dev_dbg(&port->port->dev, "%s - XByteCount    0x%X\n", __func__, oedb->XByteCount);
 
 	/* and the LSR */
 	status = read_ram(port->port->serial->dev,
@@ -516,7 +507,7 @@
 
 	if (status)
 		goto exit_is_tx_active;
-	dbg("%s - LSR = 0x%X", __func__, *lsr);
+	dev_dbg(&port->port->dev, "%s - LSR = 0x%X\n", __func__, *lsr);
 
 	/* If either buffer has data or we are transmitting then return TRUE */
 	if ((oedb->XByteCount & 0x80) != 0)
@@ -527,7 +518,7 @@
 
 	/* We return Not Active if we get any kind of error */
 exit_is_tx_active:
-	dbg("%s - return %d", __func__, bytes_left);
+	dev_dbg(&port->port->dev, "%s - return %d\n", __func__, bytes_left);
 
 	kfree(lsr);
 	kfree(oedb);
@@ -599,14 +590,13 @@
 	 * configuration # 1, which is Config Descriptor 0.
 	 */
 
-	dbg("%s - Number of Interfaces = %d",
-				__func__, dev->config->desc.bNumInterfaces);
-	dbg("%s - MAX Power            = %d",
-				__func__, dev->config->desc.bMaxPower * 2);
+	dev_dbg(&dev->dev, "%s - Number of Interfaces = %d\n",
+		__func__, dev->config->desc.bNumInterfaces);
+	dev_dbg(&dev->dev, "%s - MAX Power            = %d\n",
+		__func__, dev->config->desc.bMaxPower * 2);
 
 	if (dev->config->desc.bNumInterfaces != 1) {
-		dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n",
-								__func__);
+		dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -684,7 +674,7 @@
 		cs = (__u8)(cs + buffer[i]);
 
 	if (cs != rom_desc->CheckSum) {
-		dbg("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs);
+		pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs);
 		return -EINVAL;
 	}
 	return 0;
@@ -736,11 +726,11 @@
 		if ((start_address + sizeof(struct ti_i2c_desc) +
 					rom_desc->Size) > TI_MAX_I2C_SIZE) {
 			status = -ENODEV;
-			dbg("%s - structure too big, erroring out.", __func__);
+			dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__);
 			break;
 		}
 
-		dbg("%s Type = 0x%x", __func__, rom_desc->Type);
+		dev_dbg(dev, "%s Type = 0x%x\n", __func__, rom_desc->Type);
 
 		/* Skip type 2 record */
 		ttype = rom_desc->Type & 0x0f;
@@ -779,18 +769,18 @@
 	int start_address;
 	struct ti_i2c_desc *rom_desc;
 	struct edge_ti_manuf_descriptor *desc;
+	struct device *dev = &serial->serial->dev->dev;
 
 	rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
 	if (!rom_desc) {
-		dev_err(&serial->serial->dev->dev, "%s - out of memory\n",
-								__func__);
+		dev_err(dev, "%s - out of memory\n", __func__);
 		return -ENOMEM;
 	}
 	start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION,
 								rom_desc);
 
 	if (!start_address) {
-		dbg("%s - Edge Descriptor not found in I2C", __func__);
+		dev_dbg(dev, "%s - Edge Descriptor not found in I2C\n", __func__);
 		status = -ENODEV;
 		goto exit;
 	}
@@ -804,12 +794,12 @@
 	status = valid_csum(rom_desc, buffer);
 
 	desc = (struct edge_ti_manuf_descriptor *)buffer;
-	dbg("%s - IonConfig      0x%x", __func__, desc->IonConfig);
-	dbg("%s - Version          %d", __func__, desc->Version);
-	dbg("%s - Cpu/Board      0x%x", __func__, desc->CpuRev_BoardRev);
-	dbg("%s - NumPorts         %d", __func__, desc->NumPorts);
-	dbg("%s - NumVirtualPorts  %d", __func__, desc->NumVirtualPorts);
-	dbg("%s - TotalPorts       %d", __func__, desc->TotalPorts);
+	dev_dbg(dev, "%s - IonConfig      0x%x\n", __func__, desc->IonConfig);
+	dev_dbg(dev, "%s - Version          %d\n", __func__, desc->Version);
+	dev_dbg(dev, "%s - Cpu/Board      0x%x\n", __func__, desc->CpuRev_BoardRev);
+	dev_dbg(dev, "%s - NumPorts         %d\n", __func__, desc->NumPorts);
+	dev_dbg(dev, "%s - NumVirtualPorts  %d\n", __func__, desc->NumVirtualPorts);
+	dev_dbg(dev, "%s - TotalPorts       %d\n", __func__, desc->TotalPorts);
 
 exit:
 	kfree(rom_desc);
@@ -855,8 +845,8 @@
 
 	err = request_firmware(&fw, fw_name, dev);
 	if (err) {
-		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
-		       fw_name, err);
+		dev_err(dev, "Failed to load image \"%s\" err %d\n",
+			fw_name, err);
 		kfree(buffer);
 		return err;
 	}
@@ -903,13 +893,13 @@
 /* Try to figure out what type of I2c we have */
 static int i2c_type_bootmode(struct edgeport_serial *serial)
 {
+	struct device *dev = &serial->serial->dev->dev;
 	int status;
 	u8 *data;
 
 	data = kmalloc(1, GFP_KERNEL);
 	if (!data) {
-		dev_err(&serial->serial->dev->dev,
-				"%s - out of memory\n", __func__);
+		dev_err(dev, "%s - out of memory\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -917,11 +907,11 @@
 	status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
 				DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01);
 	if (status)
-		dbg("%s - read 2 status error = %d", __func__, status);
+		dev_dbg(dev, "%s - read 2 status error = %d\n", __func__, status);
 	else
-		dbg("%s - read 2 data = 0x%x", __func__, *data);
+		dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data);
 	if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
-		dbg("%s - ROM_TYPE_II", __func__);
+		dev_dbg(dev, "%s - ROM_TYPE_II\n", __func__);
 		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
 		goto out;
 	}
@@ -930,16 +920,16 @@
 	status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
 				DTK_ADDR_SPACE_I2C_TYPE_III, 0,	data, 0x01);
 	if (status)
-		dbg("%s - read 3 status error = %d", __func__, status);
+		dev_dbg(dev, "%s - read 3 status error = %d\n", __func__, status);
 	else
-		dbg("%s - read 2 data = 0x%x", __func__, *data);
+		dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data);
 	if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
-		dbg("%s - ROM_TYPE_III", __func__);
+		dev_dbg(dev, "%s - ROM_TYPE_III\n", __func__);
 		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
 		goto out;
 	}
 
-	dbg("%s - Unknown", __func__);
+	dev_dbg(dev, "%s - Unknown\n", __func__);
 	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
 	status = -ENODEV;
 out:
@@ -1050,11 +1040,11 @@
 	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
 		struct ti_i2c_desc *rom_desc;
 
-		dbg("%s - RUNNING IN DOWNLOAD MODE", __func__);
+		dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__);
 
 		status = check_i2c_image(serial);
 		if (status) {
-			dbg("%s - DOWNLOAD MODE -- BAD I2C", __func__);
+			dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__);
 			return status;
 		}
 
@@ -1074,7 +1064,7 @@
 
 		/* Check version number of ION descriptor */
 		if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
-			dbg("%s - Wrong CPU Rev %d (Must be 2)",
+			dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
 				__func__, ti_cpu_rev(ti_manuf_desc));
 			kfree(ti_manuf_desc);
 			return -EINVAL;
@@ -1094,8 +1084,7 @@
 			struct ti_i2c_firmware_rec *firmware_version;
 			u8 *record;
 
-			dbg("%s - Found Type FIRMWARE (Type 2) record",
-								__func__);
+			dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", __func__);
 
 			firmware_version = kmalloc(sizeof(*firmware_version),
 								GFP_KERNEL);
@@ -1127,22 +1116,21 @@
 			download_new_ver = (OperationalMajorVersion << 8) +
 					   (OperationalMinorVersion);
 
-			dbg("%s - >> FW Versions Device %d.%d  Driver %d.%d",
-			    __func__,
-			    firmware_version->Ver_Major,
-			    firmware_version->Ver_Minor,
-			    OperationalMajorVersion,
-			    OperationalMinorVersion);
+			dev_dbg(dev, "%s - >> FW Versions Device %d.%d  Driver %d.%d\n",
+				__func__, firmware_version->Ver_Major,
+				firmware_version->Ver_Minor,
+				OperationalMajorVersion,
+				OperationalMinorVersion);
 
 			/* Check if we have an old version in the I2C and
 			   update if necessary */
 			if (download_cur_ver < download_new_ver) {
-				dbg("%s - Update I2C dld from %d.%d to %d.%d",
-				    __func__,
-				    firmware_version->Ver_Major,
-				    firmware_version->Ver_Minor,
-				    OperationalMajorVersion,
-				    OperationalMinorVersion);
+				dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n",
+					__func__,
+					firmware_version->Ver_Major,
+					firmware_version->Ver_Minor,
+					OperationalMajorVersion,
+					OperationalMinorVersion);
 
 				record = kmalloc(1, GFP_KERNEL);
 				if (!record) {
@@ -1196,9 +1184,7 @@
 				}
 
 				if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
-					dev_err(dev,
-						"%s - error resetting device\n",
-						__func__);
+					dev_err(dev, "%s - error resetting device\n", __func__);
 					kfree(record);
 					kfree(firmware_version);
 					kfree(rom_desc);
@@ -1206,15 +1192,14 @@
 					return -ENODEV;
 				}
 
-				dbg("%s - HARDWARE RESET", __func__);
+				dev_dbg(dev, "%s - HARDWARE RESET\n", __func__);
 
 				/* Reset UMP -- Back to BOOT MODE */
 				status = ti_vsend_sync(serial->serial->dev,
 						UMPC_HARDWARE_RESET,
 						0, 0, NULL, 0);
 
-				dbg("%s - HARDWARE RESET return %d",
-						__func__, status);
+				dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status);
 
 				/* return an error on purpose. */
 				kfree(record);
@@ -1249,8 +1234,7 @@
 				return -ENOMEM;
 			}
 
-			dbg("%s - Found Type BLANK FIRMWARE (Type F2) record",
-								__func__);
+			dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", __func__);
 
 			/*
 			 * In order to update the I2C firmware we must change
@@ -1292,7 +1276,7 @@
 							HEADER_SIZE, vheader);
 
 			if (status) {
-				dbg("%s - can't read header back", __func__);
+				dev_dbg(dev, "%s - can't read header back\n", __func__);
 				kfree(vheader);
 				kfree(header);
 				kfree(rom_desc);
@@ -1300,8 +1284,7 @@
 				return status;
 			}
 			if (memcmp(vheader, header, HEADER_SIZE)) {
-				dbg("%s - write download record failed",
-					__func__);
+				dev_dbg(dev, "%s - write download record failed\n", __func__);
 				kfree(vheader);
 				kfree(header);
 				kfree(rom_desc);
@@ -1312,13 +1295,13 @@
 			kfree(vheader);
 			kfree(header);
 
-			dbg("%s - Start firmware update", __func__);
+			dev_dbg(dev, "%s - Start firmware update\n", __func__);
 
 			/* Tell firmware to copy download image into I2C */
 			status = ti_vsend_sync(serial->serial->dev,
 					UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0);
 
-		  	dbg("%s - Update complete 0x%x", __func__, status);
+		  	dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status);
 			if (status) {
 				dev_err(dev,
 					"%s - UMPC_COPY_DNLD_TO_I2C failed\n",
@@ -1338,7 +1321,7 @@
 	/********************************************************************/
 	/* Boot Mode */
 	/********************************************************************/
-	dbg("%s - RUNNING IN BOOT MODE", __func__);
+	dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__);
 
 	/* Configure the TI device so we can use the BULK pipes for download */
 	status = config_boot_dev(serial->serial->dev);
@@ -1347,8 +1330,8 @@
 
 	if (le16_to_cpu(serial->serial->dev->descriptor.idVendor)
 							!= USB_VENDOR_ID_ION) {
-		dbg("%s - VID = 0x%x", __func__,
-		     le16_to_cpu(serial->serial->dev->descriptor.idVendor));
+		dev_dbg(dev, "%s - VID = 0x%x\n", __func__,
+			le16_to_cpu(serial->serial->dev->descriptor.idVendor));
 		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
 		goto stayinbootmode;
 	}
@@ -1385,8 +1368,8 @@
 
 		/* Check for version 2 */
 		if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
-			dbg("%s - Wrong CPU Rev %d (Must be 2)",
-					__func__, ti_cpu_rev(ti_manuf_desc));
+			dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
+				__func__, ti_cpu_rev(ti_manuf_desc));
 			kfree(ti_manuf_desc);
 			goto stayinbootmode;
 		}
@@ -1421,8 +1404,8 @@
 
 		err = request_firmware(&fw, fw_name, dev);
 		if (err) {
-			printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
-			       fw_name, err);
+			dev_err(dev, "Failed to load image \"%s\" err %d\n",
+				fw_name, err);
 			kfree(buffer);
 			return err;
 		}
@@ -1442,23 +1425,20 @@
 		header->CheckSum = cs;
 
 		/* Download the operational code  */
-		dbg("%s - Downloading operational code image (TI UMP)",
-								__func__);
+		dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__);
 		status = download_code(serial, buffer, buffer_size);
 
 		kfree(buffer);
 
 		if (status) {
-			dbg("%s - Error downloading operational code image",
-								__func__);
+			dev_dbg(dev, "%s - Error downloading operational code image\n", __func__);
 			return status;
 		}
 
 		/* Device will reboot */
 		serial->product_info.TiMode = TI_MODE_TRANSITIONING;
 
-		dbg("%s - Download successful -- Device rebooting...",
-								__func__);
+		dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);
 
 		/* return an error on purpose */
 		return -ENODEV;
@@ -1466,7 +1446,7 @@
 
 stayinbootmode:
 	/* Eprom is invalid or blank stay in boot mode */
-	dbg("%s - STAYING IN BOOT MODE", __func__);
+	dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
 	serial->product_info.TiMode = TI_MODE_BOOT;
 
 	return 0;
@@ -1487,7 +1467,7 @@
 {
 	int status = 0;
 
-	dbg("%s - %x", __func__, mcr);
+	dev_dbg(&port->port->dev, "%s - %x\n", __func__, mcr);
 
 	status = ti_do_config(port, UMPC_SET_CLR_DTR, mcr & MCR_DTR);
 	if (status)
@@ -1524,7 +1504,7 @@
 	struct async_icount *icount;
 	struct tty_struct *tty;
 
-	dbg("%s - %02x", __func__, msr);
+	dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, msr);
 
 	if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
 			EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
@@ -1566,7 +1546,7 @@
 						LSR_FRM_ERR | LSR_BREAK));
 	struct tty_struct *tty;
 
-	dbg("%s - %02x", __func__, new_lsr);
+	dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr);
 
 	edge_port->shadow_lsr = lsr;
 
@@ -1604,6 +1584,7 @@
 	struct edgeport_serial *edge_serial = urb->context;
 	struct usb_serial_port *port;
 	struct edgeport_port *edge_port;
+	struct device *dev;
 	unsigned char *data = urb->transfer_buffer;
 	int length = urb->actual_length;
 	int port_number;
@@ -1613,8 +1594,6 @@
 	__u8 msr;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -1623,7 +1602,7 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
 		    __func__, status);
 		return;
 	default:
@@ -1633,27 +1612,26 @@
 	}
 
 	if (!length) {
-		dbg("%s - no data in urb", __func__);
+		dev_dbg(&urb->dev->dev, "%s - no data in urb\n", __func__);
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &edge_serial->serial->dev->dev,
-						__func__, length, data);
+	dev = &edge_serial->serial->dev->dev;
+	usb_serial_debug_data(dev, __func__, length, data);
 
 	if (length != 2) {
-		dbg("%s - expecting packet of size 2, got %d",
-							__func__, length);
+		dev_dbg(dev, "%s - expecting packet of size 2, got %d\n", __func__, length);
 		goto exit;
 	}
 
 	port_number = TIUMP_GET_PORT_FROM_CODE(data[0]);
 	function    = TIUMP_GET_FUNC_FROM_CODE(data[0]);
-	dbg("%s - port_number %d, function %d, info 0x%x",
-	     __func__, port_number, function, data[1]);
+	dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__,
+		port_number, function, data[1]);
 	port = edge_serial->serial->port[port_number];
 	edge_port = usb_get_serial_port_data(port);
 	if (!edge_port) {
-		dbg("%s - edge_port not found", __func__);
+		dev_dbg(dev, "%s - edge_port not found\n", __func__);
 		return;
 	}
 	switch (function) {
@@ -1662,13 +1640,13 @@
 		if (lsr & UMP_UART_LSR_DATA_MASK) {
 			/* Save the LSR event for bulk read
 			   completion routine */
-			dbg("%s - LSR Event Port %u LSR Status = %02x",
-			     __func__, port_number, lsr);
+			dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n",
+				__func__, port_number, lsr);
 			edge_port->lsr_event = 1;
 			edge_port->lsr_mask = lsr;
 		} else {
-			dbg("%s - ===== Port %d LSR Status = %02x ======",
-			     __func__, port_number, lsr);
+			dev_dbg(dev, "%s - ===== Port %d LSR Status = %02x ======\n",
+				__func__, port_number, lsr);
 			handle_new_lsr(edge_port, 0, lsr, 0);
 		}
 		break;
@@ -1676,8 +1654,8 @@
 	case TIUMP_INTERRUPT_CODE_MSR:	/* MSR */
 		/* Copy MSR from UMP */
 		msr = data[1];
-		dbg("%s - ===== Port %u MSR Status = %02x ======",
-		     __func__, port_number, msr);
+		dev_dbg(dev, "%s - ===== Port %u MSR Status = %02x ======\n",
+			__func__, port_number, msr);
 		handle_new_msr(edge_port, msr);
 		break;
 
@@ -1700,14 +1678,13 @@
 static void edge_bulk_in_callback(struct urb *urb)
 {
 	struct edgeport_port *edge_port = urb->context;
+	struct device *dev = &edge_port->port->dev;
 	unsigned char *data = urb->transfer_buffer;
 	struct tty_struct *tty;
 	int retval = 0;
 	int port_number;
 	int status = urb->status;
 
-	dbg("%s", __func__);
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -1716,13 +1693,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dev_err(&urb->dev->dev,
-			"%s - nonzero read bulk status received: %d\n",
-			     __func__, status);
+		dev_err(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status);
 	}
 
 	if (status == -EPIPE)
@@ -1737,8 +1711,8 @@
 
 	if (edge_port->lsr_event) {
 		edge_port->lsr_event = 0;
-		dbg("%s ===== Port %u LSR Status = %02x, Data = %02x ======",
-		     __func__, port_number, edge_port->lsr_mask, *data);
+		dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n",
+			__func__, port_number, edge_port->lsr_mask, *data);
 		handle_new_lsr(edge_port, 1, edge_port->lsr_mask, *data);
 		/* Adjust buffer length/pointer */
 		--urb->actual_length;
@@ -1747,14 +1721,12 @@
 
 	tty = tty_port_tty_get(&edge_port->port->port);
 	if (tty && urb->actual_length) {
-		usb_serial_debug_data(debug, &edge_port->port->dev,
-					__func__, urb->actual_length, data);
+		usb_serial_debug_data(dev, __func__, urb->actual_length, data);
 		if (edge_port->close_pending)
-			dbg("%s - close pending, dropping data on the floor",
+			dev_dbg(dev, "%s - close pending, dropping data on the floor\n",
 								__func__);
 		else
-			edge_tty_recv(&edge_port->port->dev, tty, data,
-							urb->actual_length);
+			edge_tty_recv(dev, tty, data, urb->actual_length);
 		edge_port->icount.rx += urb->actual_length;
 	}
 	tty_kref_put(tty);
@@ -1769,9 +1741,7 @@
 
 	spin_unlock(&edge_port->ep_lock);
 	if (retval)
-		dev_err(&urb->dev->dev,
-			"%s - usb_submit_urb failed with result %d\n",
-			 __func__, retval);
+		dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval);
 }
 
 static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
@@ -1793,8 +1763,6 @@
 	int status = urb->status;
 	struct tty_struct *tty;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	edge_port->ep_write_urb_in_use = 0;
 
 	switch (status) {
@@ -1805,7 +1773,7 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
 		    __func__, status);
 		return;
 	default:
@@ -1830,8 +1798,6 @@
 	u16 open_settings;
 	u8 transaction_timeout;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return -ENODEV;
 
@@ -1850,9 +1816,8 @@
 		return -ENODEV;
 	}
 
-	dbg("%s - port_number = %d, uart_base = %04x, dma_address = %04x",
-				__func__, port_number, edge_port->uart_base,
-				edge_port->dma_address);
+	dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
+		__func__, port_number, edge_port->uart_base, edge_port->dma_address);
 
 	dev = port->serial->dev;
 
@@ -1885,7 +1850,7 @@
 			     UMP_PIPE_TRANS_TIMEOUT_ENA |
 			     (transaction_timeout << 2));
 
-	dbg("%s - Sending UMPC_OPEN_PORT", __func__);
+	dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__);
 
 	/* Tell TI to open and start the port */
 	status = send_cmd(dev, UMPC_OPEN_PORT,
@@ -1924,11 +1889,11 @@
 		return status;
 	}
 
-	dbg("ShadowMSR 0x%X", edge_port->shadow_msr);
+	dev_dbg(&port->dev, "ShadowMSR 0x%X\n", edge_port->shadow_msr);
 
 	/* Set Initial MCR */
 	edge_port->shadow_mcr = MCR_RTS | MCR_DTR;
-	dbg("ShadowMCR 0x%X", edge_port->shadow_mcr);
+	dev_dbg(&port->dev, "ShadowMCR 0x%X\n", edge_port->shadow_mcr);
 
 	edge_serial = edge_port->edge_serial;
 	if (mutex_lock_interruptible(&edge_serial->es_lock))
@@ -1980,8 +1945,6 @@
 
 	++edge_serial->num_ports_open;
 
-	dbg("%s - exited", __func__);
-
 	goto release_es_lock;
 
 unlink_int_urb:
@@ -1999,8 +1962,6 @@
 	struct usb_serial *serial = port->serial;
 	int port_number;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	edge_serial = usb_get_serial_data(port->serial);
 	edge_port = usb_get_serial_port_data(port);
 	if (edge_serial == NULL || edge_port == NULL)
@@ -2019,7 +1980,7 @@
 
 	/* assuming we can still talk to the device,
 	 * send a close port command to it */
-	dbg("%s - send umpc_close_port", __func__);
+	dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
 	port_number = port->number - port->serial->minor;
 
 	mutex_lock(&serial->disc_mutex);
@@ -2042,8 +2003,6 @@
 	}
 	mutex_unlock(&edge_serial->es_lock);
 	edge_port->close_pending = 0;
-
-	dbg("%s - exited", __func__);
 }
 
 static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -2051,10 +2010,8 @@
 {
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
+		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
@@ -2077,9 +2034,6 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
 
 	if (edge_port->ep_write_urb_in_use) {
@@ -2100,8 +2054,7 @@
 
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-				port->write_urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, count, port->write_urb->transfer_buffer);
 
 	/* set up our urb */
 	port->write_urb->transfer_buffer_length = count;
@@ -2130,8 +2083,6 @@
 	int room = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return 0;
 	if (edge_port->close_pending == 1)
@@ -2141,7 +2092,7 @@
 	room = kfifo_avail(&edge_port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -2152,8 +2103,6 @@
 	int chars = 0;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return 0;
 	if (edge_port->close_pending == 1)
@@ -2163,7 +2112,7 @@
 	chars = kfifo_len(&edge_port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 }
 
@@ -2173,8 +2122,6 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return;
 
@@ -2200,8 +2147,6 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (edge_port == NULL)
 		return;
 
@@ -2261,6 +2206,7 @@
 static void change_port_settings(struct tty_struct *tty,
 		struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+	struct device *dev = &edge_port->port->dev;
 	struct ump_uart_config *config;
 	int baud;
 	unsigned cflag;
@@ -2268,13 +2214,12 @@
 	int port_number = edge_port->port->number -
 					edge_port->port->serial->minor;
 
-	dbg("%s - port %d", __func__, edge_port->port->number);
+	dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number);
 
 	config = kmalloc (sizeof (*config), GFP_KERNEL);
 	if (!config) {
 		tty->termios = *old_termios;
-		dev_err(&edge_port->port->dev, "%s - out of memory\n",
-								__func__);
+		dev_err(dev, "%s - out of memory\n", __func__);
 		return;
 	}
 
@@ -2290,20 +2235,20 @@
 	switch (cflag & CSIZE) {
 	case CS5:
 		    config->bDataBits = UMP_UART_CHAR5BITS;
-		    dbg("%s - data bits = 5", __func__);
+		    dev_dbg(dev, "%s - data bits = 5\n", __func__);
 		    break;
 	case CS6:
 		    config->bDataBits = UMP_UART_CHAR6BITS;
-		    dbg("%s - data bits = 6", __func__);
+		    dev_dbg(dev, "%s - data bits = 6\n", __func__);
 		    break;
 	case CS7:
 		    config->bDataBits = UMP_UART_CHAR7BITS;
-		    dbg("%s - data bits = 7", __func__);
+		    dev_dbg(dev, "%s - data bits = 7\n", __func__);
 		    break;
 	default:
 	case CS8:
 		    config->bDataBits = UMP_UART_CHAR8BITS;
-		    dbg("%s - data bits = 8", __func__);
+		    dev_dbg(dev, "%s - data bits = 8\n", __func__);
 			    break;
 	}
 
@@ -2311,32 +2256,32 @@
 		if (cflag & PARODD) {
 			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
 			config->bParity = UMP_UART_ODDPARITY;
-			dbg("%s - parity = odd", __func__);
+			dev_dbg(dev, "%s - parity = odd\n", __func__);
 		} else {
 			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
 			config->bParity = UMP_UART_EVENPARITY;
-			dbg("%s - parity = even", __func__);
+			dev_dbg(dev, "%s - parity = even\n", __func__);
 		}
 	} else {
 		config->bParity = UMP_UART_NOPARITY;
-		dbg("%s - parity = none", __func__);
+		dev_dbg(dev, "%s - parity = none\n", __func__);
 	}
 
 	if (cflag & CSTOPB) {
 		config->bStopBits = UMP_UART_STOPBIT2;
-		dbg("%s - stop bits = 2", __func__);
+		dev_dbg(dev, "%s - stop bits = 2\n", __func__);
 	} else {
 		config->bStopBits = UMP_UART_STOPBIT1;
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(dev, "%s - stop bits = 1\n", __func__);
 	}
 
 	/* figure out the flow control settings */
 	if (cflag & CRTSCTS) {
 		config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW;
 		config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW;
-		dbg("%s - RTS/CTS is enabled", __func__);
+		dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__);
 	} else {
-		dbg("%s - RTS/CTS is disabled", __func__);
+		dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__);
 		tty->hw_stopped = 0;
 		restart_read(edge_port);
 	}
@@ -2349,18 +2294,18 @@
 	/* if we are implementing INBOUND XON/XOFF */
 	if (I_IXOFF(tty)) {
 		config->wFlags |= UMP_MASK_UART_FLAGS_IN_X;
-		dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-		     __func__, config->cXon, config->cXoff);
+		dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
+			__func__, config->cXon, config->cXoff);
 	} else
-		dbg("%s - INBOUND XON/XOFF is disabled", __func__);
+		dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__);
 
 	/* if we are implementing OUTBOUND XON/XOFF */
 	if (I_IXON(tty)) {
 		config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
-		dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-		     __func__, config->cXon, config->cXoff);
+		dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
+			__func__, config->cXon, config->cXoff);
 	} else
-		dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
+		dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__);
 
 	tty->termios.c_cflag &= ~CMSPAR;
 
@@ -2377,17 +2322,16 @@
 
 	/* FIXME: Recompute actual baud from divisor here */
 
-	dbg("%s - baud rate = %d, wBaudRate = %d", __func__, baud,
-							config->wBaudRate);
+	dev_dbg(dev, "%s - baud rate = %d, wBaudRate = %d\n", __func__, baud, config->wBaudRate);
 
-	dbg("wBaudRate:   %d", (int)(461550L / config->wBaudRate));
-	dbg("wFlags:    0x%x", config->wFlags);
-	dbg("bDataBits:   %d", config->bDataBits);
-	dbg("bParity:     %d", config->bParity);
-	dbg("bStopBits:   %d", config->bStopBits);
-	dbg("cXon:        %d", config->cXon);
-	dbg("cXoff:       %d", config->cXoff);
-	dbg("bUartMode:   %d", config->bUartMode);
+	dev_dbg(dev, "wBaudRate:   %d\n", (int)(461550L / config->wBaudRate));
+	dev_dbg(dev, "wFlags:    0x%x\n", config->wFlags);
+	dev_dbg(dev, "bDataBits:   %d\n", config->bDataBits);
+	dev_dbg(dev, "bParity:     %d\n", config->bParity);
+	dev_dbg(dev, "bStopBits:   %d\n", config->bStopBits);
+	dev_dbg(dev, "cXon:        %d\n", config->cXon);
+	dev_dbg(dev, "cXoff:       %d\n", config->cXoff);
+	dev_dbg(dev, "bUartMode:   %d\n", config->bUartMode);
 
 	/* move the word values into big endian mode */
 	cpu_to_be16s(&config->wFlags);
@@ -2397,8 +2341,8 @@
 				(__u8)(UMPM_UART1_PORT + port_number),
 				0, (__u8 *)config, sizeof(*config));
 	if (status)
-		dbg("%s - error %d when trying to write config to device",
-		     __func__, status);
+		dev_dbg(dev, "%s - error %d when trying to write config to device\n",
+			__func__, status);
 	kfree(config);
 }
 
@@ -2410,11 +2354,11 @@
 
 	cflag = tty->termios.c_cflag;
 
-	dbg("%s - clfag %08x iflag %08x", __func__,
-	    tty->termios.c_cflag, tty->termios.c_iflag);
-	dbg("%s - old clfag %08x old iflag %08x", __func__,
-	    old_termios->c_cflag, old_termios->c_iflag);
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__,
+		tty->termios.c_cflag, tty->termios.c_iflag);
+	dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
+		old_termios->c_cflag, old_termios->c_iflag);
+	dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
 
 	if (edge_port == NULL)
 		return;
@@ -2430,8 +2374,6 @@
 	unsigned int mcr;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
 	mcr = edge_port->shadow_mcr;
 	if (set & TIOCM_RTS)
@@ -2464,8 +2406,6 @@
 	unsigned int mcr;
 	unsigned long flags;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
 
 	msr = edge_port->shadow_msr;
@@ -2478,7 +2418,7 @@
 		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
-	dbg("%s -- %x", __func__, result);
+	dev_dbg(&port->dev, "%s -- %x\n", __func__, result);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	return result;
@@ -2538,15 +2478,15 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
-		dbg("%s - (%d) TIOCGSERIAL", __func__, port->number);
+		dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
 		return get_serial_info(edge_port,
 				(struct serial_struct __user *) arg);
 	case TIOCMIWAIT:
-		dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
+		dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
 		cprev = edge_port->icount;
 		while (1) {
 			interruptible_sleep_on(&edge_port->delta_msr_wait);
@@ -2578,8 +2518,6 @@
 	int status;
 	int bv = 0;	/* Off */
 
-	dbg("%s - state = %d", __func__, break_state);
-
 	/* chase the port close */
 	chase_port(edge_port, 0, 0);
 
@@ -2587,8 +2525,8 @@
 		bv = 1;	/* On */
 	status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv);
 	if (status)
-		dbg("%s - error %d sending break set/clear command.",
-		     __func__, status);
+		dev_dbg(&port->dev, "%s - error %d sending break set/clear command.\n",
+			__func__, status);
 }
 
 static int edge_startup(struct usb_serial *serial)
@@ -2655,7 +2593,6 @@
 
 static void edge_disconnect(struct usb_serial *serial)
 {
-	dbg("%s", __func__);
 }
 
 static void edge_release(struct usb_serial *serial)
@@ -2663,8 +2600,6 @@
 	int i;
 	struct edgeport_port *edge_port;
 
-	dbg("%s", __func__);
-
 	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = usb_get_serial_port_data(serial->port[i]);
 		kfifo_free(&edge_port->write_fifo);
@@ -2692,7 +2627,7 @@
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	unsigned int v = simple_strtoul(valbuf, NULL, 0);
 
-	dbg("%s: setting uart_mode = %d", __func__, v);
+	dev_dbg(dev, "%s: setting uart_mode = %d\n", __func__, v);
 
 	if (v < 256)
 		edge_port->bUartMode = v;
@@ -2789,9 +2724,6 @@
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE("edgeport/down3.bin");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 module_param(closing_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs");
 
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index c85a7eb..1068bf2 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -33,7 +33,6 @@
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
 #define DRIVER_DESC "USB PocketPC PDA driver"
 
-static bool debug;
 static int connect_retries = KP_RETRIES;
 static int initial_wait;
 
@@ -616,9 +615,6 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 module_param(connect_retries, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(connect_retries,
 		"Maximum number of connect retries (one second each)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 2cb30c5..20a132e 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -138,11 +138,10 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static bool debug;
-
 static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct usb_device *dev = port->serial->dev;
+	struct usb_device *udev = port->serial->dev;
+	struct device *dev = &port->dev;
 	u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT;
 	u8 *buf_flow_init;
 	int result;
@@ -154,8 +153,8 @@
 	/* --1: Tell the modem to initialize (we think) From sniffs this is
 	 *	always the first thing that gets sent to the modem during
 	 *	opening of the device */
-	dbg("%s: Sending SIO_INIT (we guess)", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	dev_dbg(dev, "%s: Sending SIO_INIT (we guess)\n", __func__);
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_INIT,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 0,
@@ -164,22 +163,19 @@
 			 0,
 			 100000);
 	if (result < 0)
-		dev_err(&port->dev,
-			"Init of modem failed (error = %d)\n", result);
+		dev_err(dev, "Init of modem failed (error = %d)\n", result);
 
 	/* reset the bulk pipes */
-	usb_clear_halt(dev,
-			usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress));
-	usb_clear_halt(dev,
-			usb_sndbulkpipe(dev, port->bulk_out_endpointAddress));
+	usb_clear_halt(udev, usb_rcvbulkpipe(udev, port->bulk_in_endpointAddress));
+	usb_clear_halt(udev, usb_sndbulkpipe(udev, port->bulk_out_endpointAddress));
 
 	/*--2: Start reading from the device */
-	dbg("%s: setting up bulk read callback", __func__);
+	dev_dbg(dev, "%s: setting up bulk read callback\n", __func__);
 	usb_wwan_open(tty, port);
 
 	/*--3: Tell the modem to open the floodgates on the rx bulk channel */
-	dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	dev_dbg(dev, "%s:asking modem for RxRead (RXBULK_ON)\n", __func__);
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_RXCTL,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 IPW_RXBULK_ON,
@@ -188,12 +184,11 @@
 			 0,
 			 100000);
 	if (result < 0)
-		dev_err(&port->dev,
-			"Enabling bulk RxRead failed (error = %d)\n", result);
+		dev_err(dev, "Enabling bulk RxRead failed (error = %d)\n", result);
 
 	/*--4: setup the initial flowcontrol */
-	dbg("%s:setting init flowcontrol (%s)", __func__, buf_flow_init);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	dev_dbg(dev, "%s:setting init flowcontrol (%s)\n", __func__, buf_flow_init);
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_HANDFLOW,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 0,
@@ -202,8 +197,7 @@
 			 0x10,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev,
-			"initial flowcontrol failed (error = %d)\n", result);
+		dev_err(dev, "initial flowcontrol failed (error = %d)\n", result);
 
 	kfree(buf_flow_init);
 	return 0;
@@ -233,12 +227,13 @@
 
 static void ipw_dtr_rts(struct usb_serial_port *port, int on)
 {
-	struct usb_device *dev = port->serial->dev;
+	struct usb_device *udev = port->serial->dev;
+	struct device *dev = &port->dev;
 	int result;
 
-	dbg("%s: on = %d", __func__, on);
+	dev_dbg(dev, "%s: on = %d\n", __func__, on);
 
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_SET_PIN,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR,
@@ -247,10 +242,9 @@
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev, "setting dtr failed (error = %d)\n",
-								result);
+		dev_err(dev, "setting dtr failed (error = %d)\n", result);
 
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_SET_PIN, USB_TYPE_VENDOR |
 					USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS,
@@ -259,18 +253,18 @@
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev, "setting rts failed (error = %d)\n",
-								result);
+		dev_err(dev, "setting rts failed (error = %d)\n", result);
 }
 
 static void ipw_close(struct usb_serial_port *port)
 {
-	struct usb_device *dev = port->serial->dev;
+	struct usb_device *udev = port->serial->dev;
+	struct device *dev = &port->dev;
 	int result;
 
 	/*--3: purge */
-	dbg("%s:sending purge", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	dev_dbg(dev, "%s:sending purge\n", __func__);
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_PURGE, USB_TYPE_VENDOR |
 			 		USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 0x03,
@@ -279,12 +273,12 @@
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev, "purge failed (error = %d)\n", result);
+		dev_err(dev, "purge failed (error = %d)\n", result);
 
 
 	/* send RXBULK_off (tell modem to stop transmitting bulk data on
 	   rx chan) */
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			 IPW_SIO_RXCTL,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 IPW_RXBULK_OFF,
@@ -294,8 +288,7 @@
 			 100000);
 
 	if (result < 0)
-		dev_err(&port->dev,
-			"Disabling bulk RxRead failed (error = %d)\n", result);
+		dev_err(dev, "Disabling bulk RxRead failed (error = %d)\n", result);
 
 	usb_wwan_close(port);
 }
@@ -328,6 +321,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 5a96692..e24e2d4 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -38,15 +38,9 @@
 #include <linux/usb/serial.h>
 #include <linux/usb/irda.h>
 
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.5"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
-static bool debug;
-
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size;
@@ -430,18 +424,12 @@
 
 static int __init ir_init(void)
 {
-	int retval;
-
 	if (buffer_size) {
 		ir_device.bulk_in_size = buffer_size;
 		ir_device.bulk_out_size = buffer_size;
 	}
 
-	retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table);
-	if (retval == 0)
-		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-			       DRIVER_DESC "\n");
-	return retval;
+	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table);
 }
 
 static void __exit ir_exit(void)
@@ -457,8 +445,6 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 module_param(xbof, int, 0);
 MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
 module_param(buffer_size, int, 0);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index bf38640..01da3ea 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -32,13 +32,6 @@
 #include "iuu_phoenix.h"
 #include <linux/random.h>
 
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-static bool debug = 1;
-#else
-static bool debug;
-#endif
-
 /*
  * Version Information
  */
@@ -72,7 +65,6 @@
 	u8 *writebuf;		/* buffer for writing to device */
 	int writelen;		/* num of byte to write to device */
 	u8 *buf;		/* used for initialize speed */
-	u8 *dbgbuf;		/* debug buffer */
 	u8 len;
 	int vcc;		/* vcc (either 3 or 5 V) */
 	u32 baud;
@@ -84,32 +76,31 @@
 static void iuu_free_buf(struct iuu_private *priv)
 {
 	kfree(priv->buf);
-	kfree(priv->dbgbuf);
 	kfree(priv->writebuf);
 }
 
-static int iuu_alloc_buf(struct iuu_private *priv)
+static int iuu_alloc_buf(struct usb_serial *serial, struct iuu_private *priv)
 {
 	priv->buf = kzalloc(256, GFP_KERNEL);
-	priv->dbgbuf = kzalloc(256, GFP_KERNEL);
 	priv->writebuf = kzalloc(256, GFP_KERNEL);
-	if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
+	if (!priv->buf || !priv->writebuf) {
 		iuu_free_buf(priv);
-		dbg("%s problem allocation buffer", __func__);
+		dev_dbg(&serial->dev->dev, "%s problem allocation buffer\n", __func__);
 		return -ENOMEM;
 	}
-	dbg("%s - Privates buffers allocation success", __func__);
+	dev_dbg(&serial->dev->dev, "%s - Privates buffers allocation success\n", __func__);
 	return 0;
 }
 
 static int iuu_startup(struct usb_serial *serial)
 {
 	struct iuu_private *priv;
+
 	priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
-	dbg("%s- priv allocation success", __func__);
+	dev_dbg(&serial->dev->dev, "%s- priv allocation success\n", __func__);
 	if (!priv)
 		return -ENOMEM;
-	if (iuu_alloc_buf(priv)) {
+	if (iuu_alloc_buf(serial, priv)) {
 		kfree(priv);
 		return -ENOMEM;
 	}
@@ -130,13 +121,13 @@
 
 	if (priv) {
 		iuu_free_buf(priv);
-		dbg("%s - I will free all", __func__);
+		dev_dbg(&port->dev, "%s - I will free all\n", __func__);
 		usb_set_serial_port_data(port, NULL);
 
-		dbg("%s - priv is not anymore in port structure", __func__);
+		dev_dbg(&port->dev, "%s - priv is not anymore in port structure\n", __func__);
 		kfree(priv);
 
-		dbg("%s priv is now kfree", __func__);
+		dev_dbg(&port->dev, "%s priv is now kfree\n", __func__);
 	}
 }
 
@@ -148,13 +139,13 @@
 	unsigned long flags;
 
 	/* FIXME: locking on tiomstatus */
-	dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __func__,
-	    port->number, set, clear);
+	dev_dbg(&port->dev, "%s msg : SET = 0x%04x, CLEAR = 0x%04x\n",
+		__func__, set, clear);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) {
-		dbg("%s TIOCMSET RESET called !!!", __func__);
+		dev_dbg(&port->dev, "%s TIOCMSET RESET called !!!\n", __func__);
 		priv->reset = 1;
 	}
 	if (set & TIOCM_RTS)
@@ -190,7 +181,7 @@
 	int status = urb->status;
 
 	if (status) {
-		dbg("%s - status = %d", __func__, status);
+		dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
 		/* error stop all */
 		return;
 	}
@@ -244,13 +235,13 @@
 	int status = urb->status;
 
 	if (status) {
-		dbg("%s - status = %d", __func__, status);
+		dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
 		/* error stop all */
 		return;
 	}
 
 	st = urb->transfer_buffer;
-	dbg("%s - enter", __func__);
+	dev_dbg(&port->dev, "%s - enter\n", __func__);
 	if (urb->actual_length == 1) {
 		switch (st[0]) {
 		case 0x1:
@@ -272,7 +263,7 @@
 	int result;
 	int status = urb->status;
 
-	dbg("%s - status = %d", __func__, status);
+	dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
 			  usb_rcvbulkpipe(port->serial->dev,
 					  port->bulk_in_endpointAddress),
@@ -311,9 +302,9 @@
 			 count, &actual, HZ * 1);
 
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - error = %2x", __func__, status);
+		dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
 	else
-		dbg("%s - write OK !", __func__);
+		dev_dbg(&port->dev, "%s - write OK !\n", __func__);
 	return status;
 }
 
@@ -331,9 +322,9 @@
 			 count, &actual, HZ * 1);
 
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - error = %2x", __func__, status);
+		dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
 	else
-		dbg("%s - read OK !", __func__);
+		dev_dbg(&port->dev, "%s - read OK !\n", __func__);
 	return status;
 }
 
@@ -357,9 +348,9 @@
 	status = bulk_immediate(port, buf, 8);
 	kfree(buf);
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - led error status = %2x", __func__, status);
+		dev_dbg(&port->dev, "%s - led error status = %2x\n", __func__, status);
 	else
-		dbg("%s - led OK !", __func__);
+		dev_dbg(&port->dev, "%s - led OK !\n", __func__);
 	return IUU_OPERATION_OK;
 }
 
@@ -445,7 +436,7 @@
 
 		status = bulk_immediate(port, (u8 *) priv->buf, Count);
 		if (status != 0) {
-			dbg("%s - write error ", __func__);
+			dev_dbg(&port->dev, "%s - write error\n", __func__);
 			return status;
 		}
 	} else if (frq == 3579000) {
@@ -554,12 +545,13 @@
 
 	status = bulk_immediate(port, (u8 *) priv->buf, Count);
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - write error ", __func__);
+		dev_dbg(&port->dev, "%s - write error\n", __func__);
 	return status;
 }
 
 static int iuu_uart_flush(struct usb_serial_port *port)
 {
+	struct device *dev = &port->dev;
 	int i;
 	int status;
 	u8 rxcmd = IUU_UART_RX;
@@ -571,27 +563,26 @@
 	for (i = 0; i < 2; i++) {
 		status = bulk_immediate(port, &rxcmd, 1);
 		if (status != IUU_OPERATION_OK) {
-			dbg("%s - uart_flush_write error", __func__);
+			dev_dbg(dev, "%s - uart_flush_write error\n", __func__);
 			return status;
 		}
 
 		status = read_immediate(port, &priv->len, 1);
 		if (status != IUU_OPERATION_OK) {
-			dbg("%s - uart_flush_read error", __func__);
+			dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
 			return status;
 		}
 
 		if (priv->len > 0) {
-			dbg("%s - uart_flush datalen is : %i ", __func__,
-			    priv->len);
+			dev_dbg(dev, "%s - uart_flush datalen is : %i\n", __func__, priv->len);
 			status = read_immediate(port, priv->buf, priv->len);
 			if (status != IUU_OPERATION_OK) {
-				dbg("%s - uart_flush_read error", __func__);
+				dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
 				return status;
 			}
 		}
 	}
-	dbg("%s - uart_flush_read OK!", __func__);
+	dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__);
 	iuu_led(port, 0, 0xF000, 0, 0xFF);
 	return status;
 }
@@ -610,10 +601,10 @@
 		return;
 	}
 
-	dbg("%s - %i chars to write", __func__, urb->actual_length);
+	dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length);
 	tty = tty_port_tty_get(&port->port);
 	if (data == NULL)
-		dbg("%s - data is NULL !!!", __func__);
+		dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__);
 	if (tty && urb->actual_length && data) {
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
@@ -627,7 +618,6 @@
 	struct iuu_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 	int result;
-	int i;
 	int buf_len;
 	char *buf_ptr = port->write_urb->transfer_buffer;
 
@@ -640,14 +630,8 @@
 	buf_len = priv->writelen;
 	priv->writelen = 0;
 	spin_unlock_irqrestore(&priv->lock, flags);
-	if (debug == 1) {
-		for (i = 0; i < buf_len; i++)
-			sprintf(priv->dbgbuf + i*2 ,
-				"%02X", priv->writebuf[i]);
-		priv->dbgbuf[buf_len+i*2] = 0;
-		dbg("%s - writing %i chars : %s", __func__,
-		    buf_len, priv->dbgbuf);
-	}
+	dev_dbg(&port->dev, "%s - writing %i chars : %*ph\n", __func__,
+		buf_len, buf_len, buf_ptr);
 	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
 			  usb_sndbulkpipe(port->serial->dev,
 					  port->bulk_out_endpointAddress),
@@ -683,18 +667,18 @@
 	priv->poll++;
 
 	if (status) {
-		dbg("%s - status = %d", __func__, status);
+		dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
 		/* error stop all */
 		return;
 	}
 	if (data == NULL)
-		dbg("%s - data is NULL !!!", __func__);
+		dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__);
 
 	if (urb->actual_length == 1  && data != NULL)
 		len = (int) data[0];
 
 	if (urb->actual_length > 1) {
-		dbg("%s - urb->actual_length = %i", __func__,
+		dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__,
 		    urb->actual_length);
 		error = 1;
 		return;
@@ -702,7 +686,7 @@
 	/* if len > 0 call readbuf */
 
 	if (len > 0 && error == 0) {
-		dbg("%s - call read buf - len to read is %i ",
+		dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n",
 			__func__, len);
 		status = iuu_read_buf(port, len);
 		return;
@@ -729,7 +713,7 @@
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	/* if nothing to write call again rxcmd */
-	dbg("%s - rxcmd recall", __func__);
+	dev_dbg(&port->dev, "%s - rxcmd recall\n", __func__);
 	iuu_led_activity_off(urb);
 }
 
@@ -769,7 +753,7 @@
 			  port->read_urb->transfer_buffer, 256,
 			  iuu_uart_read_callback, port);
 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	dbg("%s - submit result = %d", __func__, result);
+	dev_dbg(&port->dev, "%s - submit result = %d\n", __func__, result);
 }
 
 static int iuu_uart_on(struct usb_serial_port *port)
@@ -789,13 +773,13 @@
 
 	status = bulk_immediate(port, buf, 4);
 	if (status != IUU_OPERATION_OK) {
-		dbg("%s - uart_on error", __func__);
+		dev_dbg(&port->dev, "%s - uart_on error\n", __func__);
 		goto uart_enable_failed;
 	}
 	/*  iuu_reset() the card after iuu_uart_on() */
 	status = iuu_uart_flush(port);
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - uart_flush error", __func__);
+		dev_dbg(&port->dev, "%s - uart_flush error\n", __func__);
 uart_enable_failed:
 	kfree(buf);
 	return status;
@@ -813,7 +797,7 @@
 
 	status = bulk_immediate(port, buf, 1);
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - uart_off error", __func__);
+		dev_dbg(&port->dev, "%s - uart_off error\n", __func__);
 
 	kfree(buf);
 	return status;
@@ -830,7 +814,7 @@
 	u8 T1reload = 0;
 	unsigned int T1FrekvensHZ = 0;
 
-	dbg("%s - enter baud_base=%d", __func__, baud_base);
+	dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base);
 	dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
 
 	if (!dataout)
@@ -911,7 +895,7 @@
 
 	status = bulk_immediate(port, dataout, DataCount);
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - uart_off error", __func__);
+		dev_dbg(&port->dev, "%s - uart_off error\n", __func__);
 	kfree(dataout);
 	return status;
 }
@@ -932,7 +916,7 @@
 	/* Just use the ospeed. ispeed should be the same. */
 	baud = tty->termios.c_ospeed;
 
-	dbg("%s - enter c_ospeed or baud=%d", __func__, baud);
+	dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud);
 
 	/* compute the parity parameter */
 	parity = 0;
@@ -983,7 +967,7 @@
 	if (serial->dev) {
 		/* free writebuf */
 		/* shutdown our urbs */
-		dbg("%s - shutting down urbs", __func__);
+		dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
 		usb_kill_urb(port->write_urb);
 		usb_kill_urb(port->read_urb);
 		usb_kill_urb(port->interrupt_in_urb);
@@ -1006,6 +990,7 @@
 static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
+	struct device *dev = &port->dev;
 	u8 *buf;
 	int result;
 	int baud;
@@ -1017,7 +1002,7 @@
 	/* Re-encode speed */
 	tty_encode_baud_rate(tty, baud, baud);
 
-	dbg("%s -  port %d, baud %d", __func__, port->number, baud);
+	dev_dbg(dev, "%s - baud %d\n", __func__, baud);
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -1032,14 +1017,14 @@
 	result = usb_control_msg(port->serial->dev,	\
 				usb_rcvctrlpipe(port->serial->dev, 0),	\
 				b, a, c, d, buf, 1, 1000); \
-	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", a, b, c, d, result, \
+	dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n", a, b, c, d, result, \
 				buf[0]); } while (0);
 
 #define SOUP(a, b, c, d)  do { \
 	result = usb_control_msg(port->serial->dev,	\
 				usb_sndctrlpipe(port->serial->dev, 0),	\
 				b, a, c, d, NULL, 0, 1000); \
-	dbg("0x%x:0x%x:0x%x:0x%x  %d", a, b, c, d, result); } while (0)
+	dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x  %d\n", a, b, c, d, result); } while (0)
 
 	/*  This is not UART related but IUU USB driver related or something */
 	/*  like that. Basically no IUU will accept any commands from the USB */
@@ -1119,7 +1104,7 @@
 
 	iuu_uart_flush(port);
 
-	dbg("%s - initialization done", __func__);
+	dev_dbg(dev, "%s - initialization done\n", __func__);
 
 	memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
 	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
@@ -1129,11 +1114,10 @@
 			  read_rxcmd_callback, port);
 	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 	if (result) {
-		dev_err(&port->dev, "%s - failed submitting read urb,"
-			" error %d\n", __func__, result);
+		dev_err(dev, "%s - failed submitting read urb, error %d\n", __func__, result);
 		iuu_close(port);
 	} else {
-		dbg("%s - rxcmd OK", __func__);
+		dev_dbg(dev, "%s - rxcmd OK\n", __func__);
 	}
 
 	return result;
@@ -1159,9 +1143,9 @@
 	kfree(buf);
 
 	if (status != IUU_OPERATION_OK)
-		dbg("%s - vcc error status = %2x", __func__, status);
+		dev_dbg(&port->dev, "%s - vcc error status = %2x\n", __func__, status);
 	else
-		dbg("%s - vcc OK !", __func__);
+		dev_dbg(&port->dev, "%s - vcc OK !\n", __func__);
 
 	return status;
 }
@@ -1192,7 +1176,7 @@
 		goto fail_store_vcc_mode;
 	}
 
-	dbg("%s: setting vcc_mode = %ld", __func__, v);
+	dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v);
 
 	if ((v != 3) && (v != 5)) {
 		dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v);
@@ -1257,8 +1241,6 @@
 MODULE_LICENSE("GPL");
 
 MODULE_VERSION(DRIVER_VERSION);
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 module_param(xmas, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(xmas, "Xmas colors enabled or not");
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 7bcbb47..29c943d7 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -38,15 +38,12 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/usb/ezusb.h>
 #include "keyspan.h"
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -165,7 +162,7 @@
 	   so other rates can be generated if desired. */
 	baud_rate = tty_get_baud_rate(tty);
 	/* If no match or invalid, don't change */
-	if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
 				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
 		/* FIXME - more to do here to ensure rate changes cleanly */
 		/* FIXME - calcuate exact rate from divisor ? */
@@ -241,8 +238,8 @@
 		dataOffset = 1;
 	}
 
-	dbg("%s - for port %d (%d chars), flip=%d",
-	    __func__, port->number, count, p_priv->out_flip);
+	dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
+		__func__, port->number, count, p_priv->out_flip);
 
 	for (left = count; left > 0; left -= todo) {
 		todo = left;
@@ -255,11 +252,11 @@
 		this_urb = p_priv->out_urbs[flip];
 		if (this_urb == NULL) {
 			/* no bulk out, so return 0 bytes written */
-			dbg("%s - no output urb :(", __func__);
+			dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
 			return count;
 		}
 
-		dbg("%s - endpoint %d flip %d",
+		dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
 			__func__, usb_pipeendpoint(this_urb->pipe), flip);
 
 		if (this_urb->status == -EINPROGRESS) {
@@ -282,7 +279,7 @@
 
 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
 		if (err != 0)
-			dbg("usb_submit_urb(write bulk) failed (%d)", err);
+			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
 		p_priv->tx_start_time[flip] = jiffies;
 
 		/* Flip for next time if usa26 or usa28 interface
@@ -305,8 +302,8 @@
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
-		dbg("%s - nonzero status: %x on endpoint %d.",
-		    __func__, status, endpoint);
+		dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
+			__func__, status, endpoint);
 		return;
 	}
 
@@ -325,7 +322,7 @@
 				tty_insert_flip_char(tty, data[i], err);
 		} else {
 			/* some bytes had errors, every byte has status */
-			dbg("%s - RX error!!!!", __func__);
+			dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
 				int stat = data[i], flag = 0;
 				if (stat & RXERROR_OVERRUN)
@@ -345,7 +342,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 }
 
 /* Outdat handling is common for all devices */
@@ -356,7 +353,7 @@
 
 	port =  urb->context;
 	p_priv = usb_get_serial_port_data(port);
-	dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
+	dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
 
 	usb_serial_port_softint(port);
 }
@@ -374,7 +371,7 @@
 	p_priv = usb_get_serial_port_data(port);
 
 	if (p_priv->resend_cont) {
-		dbg("%s - sending setup", __func__);
+		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
 		keyspan_usa26_send_setup(port->serial, port,
 						p_priv->resend_cont - 1);
 	}
@@ -394,20 +391,22 @@
 	serial =  urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 	if (urb->actual_length != 9) {
-		dbg("%s - %d byte report??", __func__, urb->actual_length);
+		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
 		goto exit;
 	}
 
 	msg = (struct keyspan_usa26_portStatusMessage *)data;
 
 #if 0
-	dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
-	    __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
-	    msg->_txXoff, msg->rxEnabled, msg->controlResponse);
+	dev_dbg(&urb->dev->dev,
+		"%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
+		__func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
+		msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
+		msg->controlResponse);
 #endif
 
 	/* Now do something useful with the data */
@@ -415,7 +414,7 @@
 
 	/* Check port number from message and retrieve private data */
 	if (msg->port >= serial->num_ports) {
-		dbg("%s - Unexpected port number %d", __func__, msg->port);
+		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
 		goto exit;
 	}
 	port = serial->port[msg->port];
@@ -438,7 +437,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 exit: ;
 }
 
@@ -465,8 +464,8 @@
 
 	do {
 		if (status) {
-			dbg("%s - nonzero status: %x on endpoint %d.",
-			    __func__, status, usb_pipeendpoint(urb->pipe));
+			dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
+				__func__, status, usb_pipeendpoint(urb->pipe));
 			return;
 		}
 
@@ -484,7 +483,7 @@
 		/* Resubmit urb so we continue receiving */
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err != 0)
-			dbg("%s - resubmit read urb failed. (%d)",
+			dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
 							__func__, err);
 		p_priv->in_flip ^= 1;
 
@@ -505,7 +504,7 @@
 	p_priv = usb_get_serial_port_data(port);
 
 	if (p_priv->resend_cont) {
-		dbg("%s - sending setup", __func__);
+		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
 		keyspan_usa28_send_setup(port->serial, port,
 						p_priv->resend_cont - 1);
 	}
@@ -526,25 +525,28 @@
 	serial =  urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 
 	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
-		dbg("%s - bad length %d", __func__, urb->actual_length);
+		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
 		goto exit;
 	}
 
-	/*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__
-	    data[0], data[1], data[2], data[3], data[4], data[5],
-	    data[6], data[7], data[8], data[9], data[10], data[11]);*/
+	/*
+	dev_dbg(&urb->dev->dev,
+	  	"%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
+		data[0], data[1], data[2], data[3], data[4], data[5],
+		data[6], data[7], data[8], data[9], data[10], data[11]);
+	*/
 
 	/* Now do something useful with the data */
 	msg = (struct keyspan_usa28_portStatusMessage *)data;
 
 	/* Check port number from message and retrieve private data */
 	if (msg->port >= serial->num_ports) {
-		dbg("%s - Unexpected port number %d", __func__, msg->port);
+		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
 		goto exit;
 	}
 	port = serial->port[msg->port];
@@ -567,7 +569,7 @@
 		/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 exit: ;
 }
 
@@ -589,7 +591,7 @@
 		p_priv = usb_get_serial_port_data(port);
 
 		if (p_priv->resend_cont) {
-			dbg("%s - sending setup", __func__);
+			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
 			keyspan_usa49_send_setup(serial, port,
 						p_priv->resend_cont - 1);
 			break;
@@ -613,27 +615,29 @@
 	serial =  urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 
 	if (urb->actual_length !=
 			sizeof(struct keyspan_usa49_portStatusMessage)) {
-		dbg("%s - bad length %d", __func__, urb->actual_length);
+		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
 		goto exit;
 	}
 
-	/*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__,
-	    data[0], data[1], data[2], data[3], data[4], data[5],
-	    data[6], data[7], data[8], data[9], data[10]);*/
+	/*
+	dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
+		__func__, data[0], data[1], data[2], data[3], data[4],
+		data[5], data[6], data[7], data[8], data[9], data[10]);
+	*/
 
 	/* Now do something useful with the data */
 	msg = (struct keyspan_usa49_portStatusMessage *)data;
 
 	/* Check port number from message and retrieve private data */
 	if (msg->portNumber >= serial->num_ports) {
-		dbg("%s - Unexpected port number %d",
-					__func__, msg->portNumber);
+		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
+			__func__, msg->portNumber);
 		goto exit;
 	}
 	port = serial->port[msg->portNumber];
@@ -656,7 +660,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 exit:	;
 }
 
@@ -676,8 +680,8 @@
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
-		dbg("%s - nonzero status: %x on endpoint %d.", __func__,
-		    status, endpoint);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
+			__func__, status, endpoint);
 		return;
 	}
 
@@ -710,7 +714,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 }
 
 static void usa49wg_indat_callback(struct urb *urb)
@@ -725,7 +729,7 @@
 	serial = urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 
@@ -738,7 +742,7 @@
 
 			/* Check port number from message*/
 			if (data[i] >= serial->num_ports) {
-				dbg("%s - Unexpected port number %d",
+				dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
 					__func__, data[i]);
 				return;
 			}
@@ -778,7 +782,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 }
 
 /* not used, usa-49 doesn't have per-port control endpoints */
@@ -799,7 +803,7 @@
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (status) {
-		dbg("%s - nonzero status: %x on endpoint %d.",
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
 		    __func__, status, endpoint);
 		return;
 	}
@@ -828,7 +832,7 @@
 									err);
 			}  else {
 			/* some bytes had errors, every byte has status */
-				dbg("%s - RX error!!!!", __func__);
+				dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
 				for (i = 0; i + 1 < urb->actual_length; i += 2) {
 					int stat = data[i], flag = 0;
 					if (stat & RXERROR_OVERRUN)
@@ -850,7 +854,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 }
 
 
@@ -868,11 +872,11 @@
 	serial =  urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 	if (urb->actual_length < 14) {
-		dbg("%s - %d byte report??", __func__, urb->actual_length);
+		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
 		goto exit;
 	}
 
@@ -900,7 +904,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 exit:
 	;
 }
@@ -914,7 +918,7 @@
 	p_priv = usb_get_serial_port_data(port);
 
 	if (p_priv->resend_cont) {
-		dbg("%s - sending setup", __func__);
+		dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
 		keyspan_usa90_send_setup(port->serial, port,
 						p_priv->resend_cont - 1);
 	}
@@ -935,13 +939,13 @@
 	serial = urb->context;
 
 	if (status) {
-		dbg("%s - nonzero status: %x", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
 		return;
 	}
 
 	if (urb->actual_length !=
 			sizeof(struct keyspan_usa67_portStatusMessage)) {
-		dbg("%s - bad length %d", __func__, urb->actual_length);
+		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
 		return;
 	}
 
@@ -951,7 +955,7 @@
 
 	/* Check port number from message and retrieve private data */
 	if (msg->port >= serial->num_ports) {
-		dbg("%s - Unexpected port number %d", __func__, msg->port);
+		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
 		return;
 	}
 
@@ -973,7 +977,7 @@
 	/* Resubmit urb so we continue receiving */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
 }
 
 static void usa67_glocont_callback(struct urb *urb)
@@ -989,7 +993,7 @@
 		p_priv = usb_get_serial_port_data(port);
 
 		if (p_priv->resend_cont) {
-			dbg("%s - sending setup", __func__);
+			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
 			keyspan_usa67_send_setup(serial, port,
 						p_priv->resend_cont - 1);
 			break;
@@ -1068,8 +1072,7 @@
 		usb_clear_halt(urb->dev, urb->pipe);
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err != 0)
-			dbg("%s - submit urb %d failed (%d)",
-							__func__, i, err);
+			dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
 	}
 
 	/* Reset low level data toggle on out endpoints */
@@ -1092,7 +1095,7 @@
 		baud_rate = tty_get_baud_rate(tty);
 		/* If no match or invalid, leave as default */
 		if (baud_rate >= 0
-		    && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+		    && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
 					NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
 			p_priv->baud = baud_rate;
 		}
@@ -1142,7 +1145,7 @@
 	}
 
 	/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
-		dbg("%s - urb in progress", __func__);
+		dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
 	}*/
 
 	p_priv->out_flip = 0;
@@ -1162,18 +1165,15 @@
 /* download the firmware to a pre-renumeration device */
 static int keyspan_fake_startup(struct usb_serial *serial)
 {
-	int 				response;
-	const struct ihex_binrec 	*record;
-	char				*fw_name;
-	const struct firmware		*fw;
+	char	*fw_name;
 
-	dbg("Keyspan startup version %04x product %04x",
-	    le16_to_cpu(serial->dev->descriptor.bcdDevice),
-	    le16_to_cpu(serial->dev->descriptor.idProduct));
+	dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
+		le16_to_cpu(serial->dev->descriptor.bcdDevice),
+		le16_to_cpu(serial->dev->descriptor.idProduct));
 
 	if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
 								!= 0x8000) {
-		dbg("Firmware already loaded.  Quitting.");
+		dev_dbg(&serial->dev->dev, "Firmware already loaded.  Quitting.\n");
 		return 1;
 	}
 
@@ -1233,34 +1233,16 @@
 		return 1;
 	}
 
-	if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
-		dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
-		return 1;
+	dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
+
+	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
+		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
+			fw_name);
+		return -ENOENT;
 	}
 
-	dbg("Uploading Keyspan %s firmware.", fw_name);
-
-		/* download the firmware image */
-	response = ezusb_set_reset(serial, 1);
-
-	record = (const struct ihex_binrec *)fw->data;
-
-	while (record) {
-		response = ezusb_writememory(serial, be32_to_cpu(record->addr),
-					     (unsigned char *)record->data,
-					     be16_to_cpu(record->len), 0xa0);
-		if (response < 0) {
-			dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
-				response, be32_to_cpu(record->addr),
-				record->data, be16_to_cpu(record->len));
-			break;
-		}
-		record = ihex_next_binrec(record);
-	}
-	release_firmware(fw);
-		/* bring device out of reset. Renumeration will occur in a
-		   moment and the new device will bind to the real driver */
-	response = ezusb_set_reset(serial, 0);
+	/* after downloading firmware Renumeration will occur in a
+	  moment and the new device will bind to the real driver */
 
 	/* we don't want this device to have a driver assigned to it. */
 	return 1;
@@ -1296,10 +1278,10 @@
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
 
-	dbg("%s - alloc for endpoint %d.", __func__, endpoint);
+	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
 	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
 	if (urb == NULL) {
-		dbg("%s - alloc for endpoint %d failed.", __func__, endpoint);
+		dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
 		return NULL;
 	}
 
@@ -1332,7 +1314,7 @@
 		return NULL;
 	}
 
-	dbg("%s - using urb %p for %s endpoint %x",
+	dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
 	    __func__, urb, ep_type_name, endpoint);
 	return urb;
 }
@@ -1464,14 +1446,15 @@
 }
 
 /* usa19 function doesn't require prescaler */
-static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
+				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
 				   u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 		div,	/* divisor */
 		cnt;	/* inverse of divisor (programmed into 8051) */
 
-	dbg("%s - %d.", __func__, baud_rate);
+	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
 
 	/* prevent divide by zero...  */
 	b16 = baud_rate * 16L;
@@ -1498,19 +1481,20 @@
 	if (rate_hi)
 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
 	if (rate_low && rate_hi)
-		dbg("%s - %d %02x %02x.",
+		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
 				__func__, baud_rate, *rate_hi, *rate_low);
 	return KEYSPAN_BAUD_RATE_OK;
 }
 
 /* usa19hs function doesn't require prescaler */
-static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
-				   u8 *rate_low, u8 *prescaler, int portnum)
+static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
+				     u32 baud_rate, u32 baudclk, u8 *rate_hi,
+				     u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 			div;	/* divisor */
 
-	dbg("%s - %d.", __func__, baud_rate);
+	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
 
 	/* prevent divide by zero...  */
 	b16 = baud_rate * 16L;
@@ -1533,13 +1517,14 @@
 		*rate_hi = (u8) ((div >> 8) & 0xff);
 
 	if (rate_low && rate_hi)
-		dbg("%s - %d %02x %02x.",
+		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
 			__func__, baud_rate, *rate_hi, *rate_low);
 
 	return KEYSPAN_BAUD_RATE_OK;
 }
 
-static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
+				    u32 baud_rate, u32 baudclk, u8 *rate_hi,
 				    u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
@@ -1551,7 +1536,7 @@
 	u8	best_prescaler;
 	int	i;
 
-	dbg("%s - %d.", __func__, baud_rate);
+	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
 
 	/* prevent divide by zero */
 	b16 = baud_rate * 16L;
@@ -1596,20 +1581,21 @@
 		*rate_hi = (u8) ((div >> 8) & 0xff);
 	if (prescaler) {
 		*prescaler = best_prescaler;
-		/*  dbg("%s - %d %d", __func__, *prescaler, div); */
+		/*  dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
 	}
 	return KEYSPAN_BAUD_RATE_OK;
 }
 
 	/* USA-28 supports different maximum baud rates on each port */
-static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
-				    u8 *rate_low, u8 *prescaler, int portnum)
+static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
+				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
+				   u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 		div,	/* divisor */
 		cnt;	/* inverse of divisor (programmed into 8051) */
 
-	dbg("%s - %d.", __func__, baud_rate);
+	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
 
 		/* prevent divide by zero */
 	b16 = baud_rate * 16L;
@@ -1642,7 +1628,7 @@
 		*rate_low = (u8) (cnt & 0xff);
 	if (rate_hi)
 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
-	dbg("%s - %d OK.", __func__, baud_rate);
+	dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
 	return KEYSPAN_BAUD_RATE_OK;
 }
 
@@ -1658,7 +1644,7 @@
 	struct urb				*this_urb;
 	int 					device_port, err;
 
-	dbg("%s reset=%d", __func__, reset_port);
+	dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
 
 	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
@@ -1668,11 +1654,11 @@
 	outcont_urb = d_details->outcont_endpoints[port->number];
 	this_urb = p_priv->outcont_urb;
 
-	dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe));
+	dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
 
 		/* Make sure we have an urb then send the message */
 	if (this_urb == NULL) {
-		dbg("%s - oops no urb.", __func__);
+		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
 		return -1;
 	}
 
@@ -1681,7 +1667,7 @@
 	if ((reset_port + 1) > p_priv->resend_cont)
 		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		/*  dbg("%s - already writing", __func__); */
+		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
 		mdelay(5);
 		return -1;
 	}
@@ -1692,11 +1678,11 @@
 	if (p_priv->old_baud != p_priv->baud) {
 		p_priv->old_baud = p_priv->baud;
 		msg.setClocking = 0xff;
-		if (d_details->calculate_baud_rate
-		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
-			dbg("%s - Invalid baud rate %d requested, using 9600.",
-						__func__, p_priv->baud);
+		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
+						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
+						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
+			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
+				__func__, p_priv->baud);
 			msg.baudLo = 0;
 			msg.baudHi = 125;	/* Values for 9600 baud */
 			msg.prescaler = 10;
@@ -1790,12 +1776,12 @@
 
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
 #if 0
 	else {
-		dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__
-		    outcont_urb, this_urb->transfer_buffer_length,
-		    usb_pipeendpoint(this_urb->pipe));
+		dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
+			outcont_urb, this_urb->transfer_buffer_length,
+			usb_pipeendpoint(this_urb->pipe));
 	}
 #endif
 
@@ -1821,7 +1807,7 @@
 	/* only do something if we have a bulk out endpoint */
 	this_urb = p_priv->outcont_urb;
 	if (this_urb == NULL) {
-		dbg("%s - oops no urb.", __func__);
+		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
 		return -1;
 	}
 
@@ -1830,7 +1816,7 @@
 	if ((reset_port + 1) > p_priv->resend_cont)
 		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		dbg("%s already writing", __func__);
+		dev_dbg(&port->dev, "%s already writing\n", __func__);
 		mdelay(5);
 		return -1;
 	}
@@ -1838,9 +1824,10 @@
 	memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
 
 	msg.setBaudRate = 1;
-	if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
-		&msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
-		dbg("%s - Invalid baud rate requested %d.",
+	if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
+					   &msg.baudHi, &msg.baudLo, NULL,
+					   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
+		dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
 						__func__, p_priv->baud);
 		msg.baudLo = 0xff;
 		msg.baudHi = 0xb2;	/* Values for 9600 baud */
@@ -1915,10 +1902,10 @@
 
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - usb_submit_urb(setup) failed", __func__);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
 #if 0
 	else {
-		dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__,
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
 		    this_urb->transfer_buffer_length);
 	}
 #endif
@@ -1949,13 +1936,13 @@
 
 	/* Make sure we have an urb then send the message */
 	if (this_urb == NULL) {
-		dbg("%s - oops no urb for port %d.", __func__, port->number);
+		dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
 		return -1;
 	}
 
-	dbg("%s - endpoint %d port %d (%d)",
-			__func__, usb_pipeendpoint(this_urb->pipe),
-			port->number, device_port);
+	dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
+		__func__, usb_pipeendpoint(this_urb->pipe),
+		port->number, device_port);
 
 	/* Save reset port val for resend.
 	   Don't overwrite resend for open/close condition. */
@@ -1963,7 +1950,7 @@
 		p_priv->resend_cont = reset_port + 1;
 
 	if (this_urb->status == -EINPROGRESS) {
-		/*  dbg("%s - already writing", __func__); */
+		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
 		mdelay(5);
 		return -1;
 	}
@@ -1977,11 +1964,11 @@
 	if (p_priv->old_baud != p_priv->baud) {
 		p_priv->old_baud = p_priv->baud;
 		msg.setClocking = 0xff;
-		if (d_details->calculate_baud_rate
-		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
-			dbg("%s - Invalid baud rate %d requested, using 9600.",
-						__func__, p_priv->baud);
+		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
+						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
+						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
+			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
+				__func__, p_priv->baud);
 			msg.baudLo = 0;
 			msg.baudHi = 125;	/* Values for 9600 baud */
 			msg.prescaler = 10;
@@ -2100,12 +2087,12 @@
 	}
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
 #if 0
 	else {
-		dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__,
-			   outcont_urb, this_urb->transfer_buffer_length,
-			   usb_pipeendpoint(this_urb->pipe));
+		dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
+			outcont_urb, this_urb->transfer_buffer_length,
+			usb_pipeendpoint(this_urb->pipe));
 	}
 #endif
 
@@ -2131,7 +2118,7 @@
 	/* only do something if we have a bulk out endpoint */
 	this_urb = p_priv->outcont_urb;
 	if (this_urb == NULL) {
-		dbg("%s - oops no urb.", __func__);
+		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
 		return -1;
 	}
 
@@ -2140,7 +2127,7 @@
 	if ((reset_port + 1) > p_priv->resend_cont)
 		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		dbg("%s already writing", __func__);
+		dev_dbg(&port->dev, "%s already writing\n", __func__);
 		mdelay(5);
 		return -1;
 	}
@@ -2151,13 +2138,12 @@
 	if (p_priv->old_baud != p_priv->baud) {
 		p_priv->old_baud = p_priv->baud;
 		msg.setClocking = 0x01;
-		if (d_details->calculate_baud_rate
-		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
-			dbg("%s - Invalid baud rate %d requested, using 9600.",
-						__func__, p_priv->baud);
+		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
+						   &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
+			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
+				__func__, p_priv->baud);
 			p_priv->baud = 9600;
-			d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
+			d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
 				&msg.baudHi, &msg.baudLo, &prescaler, 0);
 		}
 		msg.setRxMode = 1;
@@ -2239,7 +2225,7 @@
 
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
 	return 0;
 }
 
@@ -2265,7 +2251,7 @@
 
 	/* Make sure we have an urb then send the message */
 	if (this_urb == NULL) {
-		dbg("%s - oops no urb for port %d.", __func__,
+		dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
 			port->number);
 		return -1;
 	}
@@ -2275,7 +2261,7 @@
 	if ((reset_port + 1) > p_priv->resend_cont)
 		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		/*  dbg("%s - already writing", __func__); */
+		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
 		mdelay(5);
 		return -1;
 	}
@@ -2288,11 +2274,11 @@
 	if (p_priv->old_baud != p_priv->baud) {
 		p_priv->old_baud = p_priv->baud;
 		msg.setClocking = 0xff;
-		if (d_details->calculate_baud_rate
-		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
-			dbg("%s - Invalid baud rate %d requested, using 9600.",
-						__func__, p_priv->baud);
+		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
+						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
+						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
+			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
+				__func__, p_priv->baud);
 			msg.baudLo = 0;
 			msg.baudHi = 125;	/* Values for 9600 baud */
 			msg.prescaler = 10;
@@ -2383,8 +2369,7 @@
 
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
-		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__,
-				err);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
 	return 0;
 }
 
@@ -2440,8 +2425,7 @@
 	/* Setup private data for serial driver */
 	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
 	if (!s_priv) {
-		dbg("%s - kmalloc for keyspan_serial_private failed.",
-								__func__);
+		dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -2454,7 +2438,7 @@
 		p_priv = kzalloc(sizeof(struct keyspan_port_private),
 								GFP_KERNEL);
 		if (!p_priv) {
-			dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i);
+			dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i);
 			return 1;
 		}
 		p_priv->device_details = d_details;
@@ -2466,14 +2450,12 @@
 	if (s_priv->instat_urb != NULL) {
 		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
 		if (err != 0)
-			dbg("%s - submit instat urb failed %d", __func__,
-				err);
+			dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
 	}
 	if (s_priv->indat_urb != NULL) {
 		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
 		if (err != 0)
-			dbg("%s - submit indat urb failed %d", __func__,
-				err);
+			dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
 	}
 
 	return 0;
@@ -2527,10 +2509,8 @@
 
 	s_priv = usb_get_serial_data(serial);
 
-	/*  dbg("Freeing serial->private."); */
 	kfree(s_priv);
 
-	/*  dbg("Freeing port->private."); */
 	/* Now free per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
@@ -2554,7 +2534,3 @@
 MODULE_FIRMWARE("keyspan/usa19w.fw");
 MODULE_FIRMWARE("keyspan/usa49w.fw");
 MODULE_FIRMWARE("keyspan/usa49wlc.fw");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index fe1c5d9..0a8a40b 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -64,19 +64,23 @@
 					 unsigned int clear);
 static int  keyspan_fake_startup	(struct usb_serial *serial);
 
-static int  keyspan_usa19_calc_baud	(u32 baud_rate, u32 baudclk, 
+static int  keyspan_usa19_calc_baud	(struct usb_serial_port *port,
+					 u32 baud_rate, u32 baudclk,
 					 u8 *rate_hi, u8 *rate_low,
 					 u8 *prescaler, int portnum);
 
-static int  keyspan_usa19w_calc_baud	(u32 baud_rate, u32 baudclk,
+static int  keyspan_usa19w_calc_baud	(struct usb_serial_port *port,
+					 u32 baud_rate, u32 baudclk,
 					 u8 *rate_hi, u8 *rate_low,
 					 u8 *prescaler, int portnum);
 
-static int  keyspan_usa28_calc_baud	(u32 baud_rate, u32 baudclk,
+static int  keyspan_usa28_calc_baud	(struct usb_serial_port *port,
+					 u32 baud_rate, u32 baudclk,
 					 u8 *rate_hi, u8 *rate_low,
 					 u8 *prescaler, int portnum);
 
-static int  keyspan_usa19hs_calc_baud	(u32 baud_rate, u32 baudclk,
+static int  keyspan_usa19hs_calc_baud	(struct usb_serial_port *port,
+					 u32 baud_rate, u32 baudclk,
 					 u8 *rate_hi, u8 *rate_low,
 					 u8 *prescaler, int portnum);
 
@@ -188,8 +192,9 @@
 		/* Endpoint used for global control functions */
 	int	glocont_endpoint;
 
-	int	(*calculate_baud_rate) (u32 baud_rate, u32 baudclk,
-			u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum);
+	int	(*calculate_baud_rate) (struct usb_serial_port *port,
+					u32 baud_rate, u32 baudclk,
+					u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum);
 	u32	baudclk;
 }; 
 
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index dcada86..ca43ecb4 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -25,13 +25,10 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
-
-static bool debug;
+#include <linux/usb/ezusb.h>
 
 /* make a simple define to handle if we are compiling keyspan_pda or xircom support */
 #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE)
@@ -137,8 +134,8 @@
 				 0,
 				 2000);
 	if (result < 0)
-		dbg("%s - error %d from usb_control_msg",
-		    __func__, result);
+		dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n",
+			__func__, result);
 }
 
 
@@ -160,12 +157,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
 		goto exit;
 	}
 
@@ -183,7 +178,7 @@
 		break;
 	case 1:
 		/* status interrupt */
-		dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+		dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]);
 		switch (data[1]) {
 		case 1: /* modemline change */
 			break;
@@ -229,7 +224,7 @@
 	/* just restart the receive interrupt URB */
 
 	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
-		dbg(" usb_submit_urb(read urb) failed");
+		dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
 }
 
 
@@ -308,8 +303,8 @@
 			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			value, 0, NULL, 0, 2000);
 	if (result < 0)
-		dbg("%s - error %d from usb_control_msg",
-		    __func__, result);
+		dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n",
+			__func__, result);
 	/* there is something funky about this.. the TCSBRK that 'cu' performs
 	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
 	   seconds apart, but it feels like the break sent isn't as long as it
@@ -347,7 +342,7 @@
 	speed = keyspan_pda_setbaud(serial, speed);
 
 	if (speed == 0) {
-		dbg("can't handle requested baud rate");
+		dev_dbg(&port->dev, "can't handle requested baud rate\n");
 		/* It hasn't changed so.. */
 		speed = tty_termios_baud_rate(old_termios);
 	}
@@ -459,7 +454,7 @@
 	   Block if we can't write anything at all, otherwise write as much as
 	   we can. */
 	if (count == 0) {
-		dbg(" write request of 0 bytes");
+		dev_dbg(&port->dev, "write request of 0 bytes\n");
 		return 0;
 	}
 
@@ -505,16 +500,16 @@
 				     1,
 				     2000);
 		if (rc > 0) {
-			dbg(" roomquery says %d", *room);
+			dev_dbg(&port->dev, "roomquery says %d\n", *room);
 			priv->tx_room = *room;
 		}
 		kfree(room);
 		if (rc < 0) {
-			dbg(" roomquery failed");
+			dev_dbg(&port->dev, "roomquery failed\n");
 			goto exit;
 		}
 		if (rc == 0) {
-			dbg(" roomquery returned 0 bytes");
+			dev_dbg(&port->dev, "roomquery returned 0 bytes\n");
 			rc = -EIO; /* device didn't return any data */
 			goto exit;
 		}
@@ -536,7 +531,7 @@
 
 		rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (rc) {
-			dbg(" usb_submit_urb(write bulk) failed");
+			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
 			goto exit;
 		}
 	} else {
@@ -639,11 +634,11 @@
 			     1,
 			     2000);
 	if (rc < 0) {
-		dbg("%s - roomquery failed", __func__);
+		dev_dbg(&port->dev, "%s - roomquery failed\n", __func__);
 		goto error;
 	}
 	if (rc == 0) {
-		dbg("%s - roomquery returned 0 bytes", __func__);
+		dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__);
 		rc = -EIO;
 		goto error;
 	}
@@ -654,7 +649,7 @@
 	/*Start reading from the device*/
 	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (rc) {
-		dbg("%s - usb_submit_urb(read int) failed", __func__);
+		dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__);
 		goto error;
 	}
 error:
@@ -678,11 +673,9 @@
 {
 	int response;
 	const char *fw_name;
-	const struct ihex_binrec *record;
-	const struct firmware *fw;
 
 	/* download the firmware here ... */
-	response = ezusb_set_reset(serial, 1);
+	response = ezusb_fx1_set_reset(serial->dev, 1);
 
 	if (0) { ; }
 #ifdef KEYSPAN
@@ -699,30 +692,15 @@
 			__func__);
 		return -ENODEV;
 	}
-	if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
+
+	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
 		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
 			fw_name);
 		return -ENOENT;
 	}
-	record = (const struct ihex_binrec *)fw->data;
 
-	while (record) {
-		response = ezusb_writememory(serial, be32_to_cpu(record->addr),
-					     (unsigned char *)record->data,
-					     be16_to_cpu(record->len), 0xa0);
-		if (response < 0) {
-			dev_err(&serial->dev->dev, "ezusb_writememory failed "
-				"for Keyspan PDA firmware (%d %04X %p %d)\n",
-				response, be32_to_cpu(record->addr),
-				record->data, be16_to_cpu(record->len));
-			break;
-		}
-		record = ihex_next_binrec(record);
-	}
-	release_firmware(fw);
-	/* bring device out of reset. Renumeration will occur in a moment
-	   and the new device will bind to the real driver */
-	response = ezusb_set_reset(serial, 0);
+	/* after downloading firmware Renumeration will occur in a
+	  moment and the new device will bind to the real driver */
 
 	/* we want this device to fail to have a driver assigned to it. */
 	return 1;
@@ -828,6 +806,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index def9ad2..3f6d737 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -49,8 +49,6 @@
 #include <linux/usb/serial.h>
 #include "kl5kusb105.h"
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -239,7 +237,9 @@
 		priv = kmalloc(sizeof(struct klsi_105_private),
 						   GFP_KERNEL);
 		if (!priv) {
-			dbg("%skmalloc for klsi_105_private failed.", __func__);
+			dev_dbg(&serial->interface->dev,
+				"%s - kmalloc for klsi_105_private failed.\n",
+				__func__);
 			i--;
 			goto err_cleanup;
 		}
@@ -344,14 +344,14 @@
 		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
 		retval = rc;
 	} else
-		dbg("%s - enabled reading", __func__);
+		dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
 
 	rc = klsi_105_get_line_state(port, &line_state);
 	if (rc >= 0) {
 		spin_lock_irqsave(&priv->lock, flags);
 		priv->line_state = line_state;
 		spin_unlock_irqrestore(&priv->lock, flags);
-		dbg("%s - read line state 0x%lx", __func__, line_state);
+		dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
 		retval = 0;
 	} else
 		retval = rc;
@@ -421,7 +421,7 @@
 		return;
 
 	if (urb->actual_length <= KLSI_HDR_LEN) {
-		dbg("%s - malformed packet", __func__);
+		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
 		return;
 	}
 
@@ -431,7 +431,7 @@
 
 	len = get_unaligned_le16(data);
 	if (len > urb->actual_length - KLSI_HDR_LEN) {
-		dbg("%s - packet length mismatch", __func__);
+		dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
 		len = urb->actual_length - KLSI_HDR_LEN;
 	}
 
@@ -445,6 +445,7 @@
 				 struct ktermios *old_termios)
 {
 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
+	struct device *dev = &port->dev;
 	unsigned int iflag = tty->termios.c_iflag;
 	unsigned int old_iflag = old_termios->c_iflag;
 	unsigned int cflag = tty->termios.c_cflag;
@@ -455,8 +456,7 @@
 
 	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
 	if (!cfg) {
-		dev_err(&port->dev, "%s - out of memory for config buffer.\n",
-				__func__);
+		dev_err(dev, "%s - out of memory for config buffer.\n", __func__);
 		return;
 	}
 
@@ -471,7 +471,7 @@
 	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
 		/* reassert DTR and (maybe) RTS on transition from B0 */
 		if ((old_cflag & CBAUD) == B0) {
-			dbg("%s: baud was B0", __func__);
+			dev_dbg(dev, "%s: baud was B0\n", __func__);
 #if 0
 			priv->control_state |= TIOCM_DTR;
 			/* don't set RTS if using hardware flow control */
@@ -509,14 +509,13 @@
 		priv->cfg.baudrate = kl5kusb105a_sio_b115200;
 		break;
 	default:
-		dbg("KLSI USB->Serial converter:"
-		    " unsupported baudrate request, using default of 9600");
-			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600");
+		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
 		baud = 9600;
 		break;
 	}
 	if ((cflag & CBAUD) == B0) {
-		dbg("%s: baud is B0", __func__);
+		dev_dbg(dev, "%s: baud is B0\n", __func__);
 		/* Drop RTS and DTR */
 		/* maybe this should be simulated by sending read
 		 * disable and read enable messages?
@@ -533,11 +532,11 @@
 		/* set the number of data bits */
 		switch (cflag & CSIZE) {
 		case CS5:
-			dbg("%s - 5 bits/byte not supported", __func__);
+			dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			goto err;
 		case CS6:
-			dbg("%s - 6 bits/byte not supported", __func__);
+			dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			goto err;
 		case CS7:
@@ -547,8 +546,7 @@
 			priv->cfg.databits = kl5kusb105a_dtb_8;
 			break;
 		default:
-			dev_err(&port->dev,
-				"CSIZE was not CS5-CS8, using default of 8\n");
+			dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n");
 			priv->cfg.databits = kl5kusb105a_dtb_8;
 			break;
 		}
@@ -616,7 +614,7 @@
 				(struct mct_u232_private *)port->private;
 	unsigned char lcr = priv->last_lcr;
 
-	dbg("%sstate=%d", __func__, break_state);
+	dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state);
 
 	/* LOCKING */
 	if (break_state)
@@ -645,7 +643,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->line_state = line_state;
 	spin_unlock_irqrestore(&priv->lock, flags);
-	dbg("%s - read line state 0x%lx", __func__, line_state);
+	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
 	return (int)line_state;
 }
 
@@ -681,6 +679,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "enable extensive debugging messages");
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index bf5c749..5c4d2fb 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -38,8 +38,6 @@
 #include <linux/ioctl.h>
 #include "kobil_sct.h"
 
-static bool debug;
-
 /* Version Information */
 #define DRIVER_VERSION "21/05/2004"
 #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
@@ -139,17 +137,16 @@
 
 	switch (priv->device_type) {
 	case KOBIL_ADAPTER_B_PRODUCT_ID:
-		printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");
+		dev_dbg(&serial->dev->dev, "KOBIL B1 PRO / KAAN PRO detected\n");
 		break;
 	case KOBIL_ADAPTER_K_PRODUCT_ID:
-		printk(KERN_DEBUG
-		  "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
+		dev_dbg(&serial->dev->dev, "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
 		break;
 	case KOBIL_USBTWIN_PRODUCT_ID:
-		printk(KERN_DEBUG "KOBIL USBTWIN detected\n");
+		dev_dbg(&serial->dev->dev, "KOBIL USBTWIN detected\n");
 		break;
 	case KOBIL_KAAN_SIM_PRODUCT_ID:
-		printk(KERN_DEBUG "KOBIL KAAN SIM detected\n");
+		dev_dbg(&serial->dev->dev, "KOBIL KAAN SIM detected\n");
 		break;
 	}
 	usb_set_serial_port_data(serial->port[0], priv);
@@ -164,13 +161,15 @@
 	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
 		endpoint = &altsetting->endpoint[i];
 		if (usb_endpoint_is_int_out(&endpoint->desc)) {
-			dbg("%s Found interrupt out endpoint. Address: %d",
+			dev_dbg(&serial->dev->dev,
+				"%s Found interrupt out endpoint. Address: %d\n",
 				__func__, endpoint->desc.bEndpointAddress);
 			priv->write_int_endpoint_address =
 				endpoint->desc.bEndpointAddress;
 		}
 		if (usb_endpoint_is_int_in(&endpoint->desc)) {
-			dbg("%s Found interrupt in  endpoint. Address: %d",
+			dev_dbg(&serial->dev->dev,
+				"%s Found interrupt in  endpoint. Address: %d\n",
 				__func__, endpoint->desc.bEndpointAddress);
 			priv->read_int_endpoint_address =
 				endpoint->desc.bEndpointAddress;
@@ -200,6 +199,7 @@
 
 static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
+	struct device *dev = &port->dev;
 	int result = 0;
 	struct kobil_private *priv;
 	unsigned char *transfer_buffer;
@@ -215,12 +215,10 @@
 
 	/* allocate write_urb */
 	if (!port->write_urb) {
-		dbg("%s - port %d  Allocating port->write_urb",
-						__func__, port->number);
+		dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__);
 		port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!port->write_urb) {
-			dbg("%s - port %d usb_alloc_urb failed",
-						__func__, port->number);
+			dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__);
 			kfree(transfer_buffer);
 			return -ENOMEM;
 		}
@@ -247,10 +245,9 @@
 			  transfer_buffer_length,
 			  KOBIL_TIMEOUT
 	);
-	dbg("%s - port %d Send get_HW_version URB returns: %i",
-		__func__, port->number, result);
-	dbg("Harware version: %i.%i.%i",
-		transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]);
+	dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result);
+	dev_dbg(dev, "Harware version: %i.%i.%i\n", transfer_buffer[0],
+		transfer_buffer[1], transfer_buffer[2]);
 
 	/* get firmware version */
 	result = usb_control_msg(port->serial->dev,
@@ -263,10 +260,9 @@
 			  transfer_buffer_length,
 			  KOBIL_TIMEOUT
 	);
-	dbg("%s - port %d Send get_FW_version URB returns: %i",
-					__func__, port->number, result);
-	dbg("Firmware version: %i.%i.%i",
-		transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]);
+	dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result);
+	dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0],
+		transfer_buffer[1], transfer_buffer[2]);
 
 	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
 			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
@@ -282,8 +278,7 @@
 			  0,
 			  KOBIL_TIMEOUT
 		);
-		dbg("%s - port %d Send set_baudrate URB returns: %i",
-					__func__, port->number, result);
+		dev_dbg(dev, "%s - Send set_baudrate URB returns: %i\n", __func__, result);
 
 		/* reset all queues */
 		result = usb_control_msg(port->serial->dev,
@@ -296,16 +291,14 @@
 			  0,
 			  KOBIL_TIMEOUT
 		);
-		dbg("%s - port %d Send reset_all_queues URB returns: %i",
-					__func__, port->number, result);
+		dev_dbg(dev, "%s - Send reset_all_queues URB returns: %i\n", __func__, result);
 	}
 	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
 	    priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
 	    priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
 		/* start reading (Adapter B 'cause PNP string) */
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
-		dbg("%s - port %d Send read URB returns: %i",
-					__func__, port->number, result);
+		dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result);
 	}
 
 	kfree(transfer_buffer);
@@ -333,11 +326,9 @@
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int status = urb->status;
-/*	char *dbg_data; */
 
 	if (status) {
-		dbg("%s - port %d Read int status not zero: %d",
-		    __func__, port->number, status);
+		dev_dbg(&port->dev, "%s - Read int status not zero: %d\n", __func__, status);
 		return;
 	}
 
@@ -346,6 +337,8 @@
 
 		/* BEGIN DEBUG */
 		/*
+		  char *dbg_data;
+
 		  dbg_data = kzalloc((3 *  purb->actual_length + 10)
 						* sizeof(char), GFP_KERNEL);
 		  if (! dbg_data) {
@@ -354,7 +347,7 @@
 		  for (i = 0; i < purb->actual_length; i++) {
 			  sprintf(dbg_data +3*i, "%02X ", data[i]);
 		  }
-		  dbg(" <-- %s", dbg_data);
+		  dev_dbg(&port->dev, " <-- %s\n", dbg_data);
 		  kfree(dbg_data);
 		*/
 		/* END DEBUG */
@@ -365,8 +358,7 @@
 	tty_kref_put(tty);
 
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
-	dbg("%s - port %d Send read URB returns: %i",
-			__func__, port->number, result);
+	dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
 }
 
 
@@ -384,22 +376,20 @@
 	struct kobil_private *priv;
 
 	if (count == 0) {
-		dbg("%s - port %d write request of 0 bytes",
-						__func__, port->number);
+		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
 	priv = usb_get_serial_port_data(port);
 
 	if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
-		dbg("%s - port %d Error: write request bigger than buffer size", __func__, port->number);
+		dev_dbg(&port->dev, "%s - Error: write request bigger than buffer size\n", __func__);
 		return -ENOMEM;
 	}
 
 	/* Copy data to buffer */
 	memcpy(priv->buf + priv->filled, buf, count);
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-						priv->buf + priv->filled);
+	usb_serial_debug_data(&port->dev, __func__, count, priv->buf + priv->filled);
 	priv->filled = priv->filled + count;
 
 	/* only send complete block. TWIN, KAAN SIM and adapter K
@@ -432,8 +422,7 @@
 
 			priv->cur_pos = priv->cur_pos + length;
 			result = usb_submit_urb(port->write_urb, GFP_NOIO);
-			dbg("%s - port %d Send write URB returns: %i",
-					__func__, port->number, result);
+			dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result);
 			todo = priv->filled - priv->cur_pos;
 
 			if (todo > 0)
@@ -448,8 +437,7 @@
 			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
 			result = usb_submit_urb(port->interrupt_in_urb,
 								GFP_NOIO);
-			dbg("%s - port %d Send read URB returns: %i",
-					__func__, port->number, result);
+			dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
 		}
 	}
 	return count;
@@ -493,8 +481,8 @@
 			  transfer_buffer_length,
 			  KOBIL_TIMEOUT);
 
-	dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x",
-	    __func__, port->number, result, transfer_buffer[0]);
+	dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n",
+		__func__, result, transfer_buffer[0]);
 
 	result = 0;
 	if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
@@ -507,6 +495,7 @@
 			   unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct device *dev = &port->dev;
 	struct kobil_private *priv;
 	int result;
 	int dtr = 0;
@@ -538,11 +527,9 @@
 
 	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
 		if (dtr != 0)
-			dbg("%s - port %d Setting DTR",
-						__func__, port->number);
+			dev_dbg(dev, "%s - Setting DTR\n", __func__);
 		else
-			dbg("%s - port %d Clearing DTR",
-						__func__, port->number);
+			dev_dbg(dev, "%s - Clearing DTR\n", __func__);
 		result = usb_control_msg(port->serial->dev,
 			  usb_rcvctrlpipe(port->serial->dev, 0),
 			  SUSBCRequest_SetStatusLinesOrQueues,
@@ -554,11 +541,9 @@
 			  KOBIL_TIMEOUT);
 	} else {
 		if (rts != 0)
-			dbg("%s - port %d Setting RTS",
-						__func__, port->number);
+			dev_dbg(dev, "%s - Setting RTS\n", __func__);
 		else
-			dbg("%s - port %d Clearing RTS",
-						__func__, port->number);
+			dev_dbg(dev, "%s - Clearing RTS\n", __func__);
 		result = usb_control_msg(port->serial->dev,
 			usb_rcvctrlpipe(port->serial->dev, 0),
 			SUSBCRequest_SetStatusLinesOrQueues,
@@ -569,8 +554,7 @@
 			0,
 			KOBIL_TIMEOUT);
 	}
-	dbg("%s - port %d Send set_status_line URB returns: %i",
-					__func__, port->number, result);
+	dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result);
 	kfree(transfer_buffer);
 	return (result < 0) ? result : 0;
 }
@@ -658,7 +642,8 @@
 			  KOBIL_TIMEOUT
 			);
 
-		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result);
+		dev_dbg(&port->dev,
+			"%s - Send reset_all_queues (FLUSH) URB returns: %i", __func__, result);
 		kfree(transfer_buffer);
 		return (result < 0) ? -EIO: 0;
 	default:
@@ -671,6 +656,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index df98cff..f394771 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -45,8 +45,6 @@
 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
 
-static bool debug;
-
 /*
  * Function prototypes
  */
@@ -214,7 +212,7 @@
 			value, rc);
 	else
 		tty_encode_baud_rate(tty, speed, speed);
-	dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
+	dev_dbg(&port->dev, "set_baud_rate: value: 0x%x, divisor: 0x%x\n", value, divisor);
 
 	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
 	   always sends two extra USB 'device request' messages after the
@@ -247,8 +245,8 @@
 	if (port && C_CRTSCTS(tty))
 	   cts_enable_byte = 1;
 
-	dbg("set_baud_rate: send second control message, data = %02X",
-							cts_enable_byte);
+	dev_dbg(&port->dev, "set_baud_rate: send second control message, data = %02X\n",
+		cts_enable_byte);
 	buf[0] = cts_enable_byte;
 	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			MCT_U232_SET_CTS_REQUEST,
@@ -263,7 +261,8 @@
 	return rc;
 } /* mct_u232_set_baud_rate */
 
-static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
+static int mct_u232_set_line_ctrl(struct usb_serial_port *port,
+				  unsigned char lcr)
 {
 	int rc;
 	unsigned char *buf;
@@ -273,20 +272,19 @@
 		return -ENOMEM;
 
 	buf[0] = lcr;
-	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+	rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
 			MCT_U232_SET_LINE_CTRL_REQUEST,
 			MCT_U232_SET_REQUEST_TYPE,
 			0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE,
 			WDR_TIMEOUT);
 	if (rc < 0)
-		dev_err(&serial->dev->dev,
-			"Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
-	dbg("set_line_ctrl: 0x%x", lcr);
+		dev_err(&port->dev, "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
+	dev_dbg(&port->dev, "set_line_ctrl: 0x%x\n", lcr);
 	kfree(buf);
 	return rc;
 } /* mct_u232_set_line_ctrl */
 
-static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
+static int mct_u232_set_modem_ctrl(struct usb_serial_port *port,
 				   unsigned int control_state)
 {
 	int rc;
@@ -304,25 +302,24 @@
 		mcr |= MCT_U232_MCR_RTS;
 
 	buf[0] = mcr;
-	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+	rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
 			MCT_U232_SET_MODEM_CTRL_REQUEST,
 			MCT_U232_SET_REQUEST_TYPE,
 			0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
 			WDR_TIMEOUT);
 	kfree(buf);
 
-	dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
+	dev_dbg(&port->dev, "set_modem_ctrl: state=0x%x ==> mcr=0x%x\n", control_state, mcr);
 
 	if (rc < 0) {
-		dev_err(&serial->dev->dev,
-			"Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
+		dev_err(&port->dev, "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
 		return rc;
 	}
 	return 0;
 } /* mct_u232_set_modem_ctrl */
 
-static int mct_u232_get_modem_stat(struct usb_serial *serial,
-						unsigned char *msr)
+static int mct_u232_get_modem_stat(struct usb_serial_port *port,
+				   unsigned char *msr)
 {
 	int rc;
 	unsigned char *buf;
@@ -332,19 +329,18 @@
 		*msr = 0;
 		return -ENOMEM;
 	}
-	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+	rc = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
 			MCT_U232_GET_MODEM_STAT_REQUEST,
 			MCT_U232_GET_REQUEST_TYPE,
 			0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
 			WDR_TIMEOUT);
 	if (rc < 0) {
-		dev_err(&serial->dev->dev,
-			"Get MODEM STATus failed (error = %d)\n", rc);
+		dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc);
 		*msr = 0;
 	} else {
 		*msr = buf[0];
 	}
-	dbg("get_modem_stat: 0x%x", *msr);
+	dev_dbg(&port->dev, "get_modem_stat: 0x%x\n", *msr);
 	kfree(buf);
 	return rc;
 } /* mct_u232_get_modem_stat */
@@ -363,8 +359,8 @@
 		icount->dcd++;
 } /* mct_u232_msr_to_icount */
 
-static void mct_u232_msr_to_state(unsigned int *control_state,
-						unsigned char msr)
+static void mct_u232_msr_to_state(struct usb_serial_port *port,
+				  unsigned int *control_state, unsigned char msr)
 {
 	/* Translate Control Line states */
 	if (msr & MCT_U232_MSR_DSR)
@@ -383,7 +379,7 @@
 		*control_state |=  TIOCM_CD;
 	else
 		*control_state &= ~TIOCM_CD;
-	dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
+	dev_dbg(&port->dev, "msr_to_state: msr=0x%x ==> state=0x%x\n", msr, *control_state);
 } /* mct_u232_msr_to_state */
 
 /*
@@ -465,14 +461,14 @@
 	control_state = priv->control_state;
 	last_lcr = priv->last_lcr;
 	spin_unlock_irqrestore(&priv->lock, flags);
-	mct_u232_set_modem_ctrl(serial, control_state);
-	mct_u232_set_line_ctrl(serial, last_lcr);
+	mct_u232_set_modem_ctrl(port, control_state);
+	mct_u232_set_line_ctrl(port, last_lcr);
 
 	/* Read modem status and update control state */
-	mct_u232_get_modem_stat(serial, &last_msr);
+	mct_u232_get_modem_stat(port, &last_msr);
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->last_msr = last_msr;
-	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+	mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -512,7 +508,7 @@
 			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
 		control_state = priv->control_state;
 		spin_unlock_irq(&priv->lock);
-		mct_u232_set_modem_ctrl(port->serial, control_state);
+		mct_u232_set_modem_ctrl(port, control_state);
 	}
 	mutex_unlock(&port->serial->disc_mutex);
 }
@@ -532,7 +528,6 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
-	struct usb_serial *serial = port->serial;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int retval;
@@ -547,22 +542,16 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
-	if (!serial) {
-		dbg("%s - bad serial pointer, exiting", __func__);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-					urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	/*
 	 * Work-a-round: handle the 'usual' bulk-in pipe here
@@ -588,7 +577,7 @@
 	priv->last_msr = data[MCT_U232_MSR_INDEX];
 
 	/* Record Control Line states */
-	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+	mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
 
 	mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
 
@@ -656,18 +645,18 @@
 
 	/* reassert DTR and RTS on transition from B0 */
 	if ((old_cflag & CBAUD) == B0) {
-		dbg("%s: baud was B0", __func__);
+		dev_dbg(&port->dev, "%s: baud was B0\n", __func__);
 		control_state |= TIOCM_DTR | TIOCM_RTS;
-		mct_u232_set_modem_ctrl(serial, control_state);
+		mct_u232_set_modem_ctrl(port, control_state);
 	}
 
 	mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty));
 
 	if ((cflag & CBAUD) == B0) {
-		dbg("%s: baud is B0", __func__);
+		dev_dbg(&port->dev, "%s: baud is B0\n", __func__);
 		/* Drop RTS and DTR */
 		control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-		mct_u232_set_modem_ctrl(serial, control_state);
+		mct_u232_set_modem_ctrl(port, control_state);
 	}
 
 	/*
@@ -704,7 +693,7 @@
 	last_lcr |= (cflag & CSTOPB) ?
 		MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
 
-	mct_u232_set_line_ctrl(serial, last_lcr);
+	mct_u232_set_line_ctrl(port, last_lcr);
 
 	/* save off the modified port settings */
 	spin_lock_irqsave(&priv->lock, flags);
@@ -716,7 +705,6 @@
 static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
 	unsigned char lcr;
 	unsigned long flags;
@@ -728,7 +716,7 @@
 		lcr |= MCT_U232_SET_BREAK;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	mct_u232_set_line_ctrl(serial, lcr);
+	mct_u232_set_line_ctrl(port, lcr);
 } /* mct_u232_break_ctl */
 
 
@@ -750,7 +738,6 @@
 			      unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
 	unsigned int control_state;
 	unsigned long flags;
@@ -769,7 +756,7 @@
 
 	priv->control_state = control_state;
 	spin_unlock_irqrestore(&priv->lock, flags);
-	return mct_u232_set_modem_ctrl(serial, control_state);
+	return mct_u232_set_modem_ctrl(port, control_state);
 }
 
 static void mct_u232_throttle(struct tty_struct *tty)
@@ -784,7 +771,7 @@
 		priv->control_state &= ~TIOCM_RTS;
 		control_state = priv->control_state;
 		spin_unlock_irq(&priv->lock);
-		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
+		mct_u232_set_modem_ctrl(port, control_state);
 	} else {
 		spin_unlock_irq(&priv->lock);
 	}
@@ -802,7 +789,7 @@
 		priv->control_state |= TIOCM_RTS;
 		control_state = priv->control_state;
 		spin_unlock_irq(&priv->lock);
-		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
+		mct_u232_set_modem_ctrl(port, control_state);
 	} else {
 		spin_unlock_irq(&priv->lock);
 	}
@@ -817,13 +804,13 @@
 	struct async_icount cnow, cprev;
 	unsigned long flags;
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
 
 	switch (cmd) {
 
 	case TIOCMIWAIT:
 
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__);
 
 		spin_lock_irqsave(&mct_u232_port->lock, flags);
 		cprev = mct_u232_port->icount;
@@ -879,8 +866,8 @@
 
 	spin_unlock_irqrestore(&mct_u232_port->lock, flags);
 
-	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
-		__func__,  port->number, icount->rx, icount->tx);
+	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n",
+		__func__,  icount->rx, icount->tx);
 	return 0;
 }
 
@@ -889,6 +876,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 2b0627b..0b257dd 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -52,9 +52,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-/* Input parameter constants. */
-static bool debug;
-
 /* UNI-Directional mode commands for device configure */
 #define UNI_CMD_OPEN	0x80
 #define UNI_CMD_CLOSE	0xFF
@@ -436,7 +433,3 @@
 MODULE_AUTHOR("Philip Nicastro");
 MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
 MODULE_DESCRIPTION(DRIVER_DESC);
-
-/* Module input parameters */
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 012f67b..1bf1ad0 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -71,8 +71,6 @@
 	struct urb		*write_urb_pool[NUM_URBS];
 };
 
-static bool debug;
-
 static struct usb_serial_driver moschip7720_2port_driver;
 
 #define USB_VENDOR_ID_MOSCHIP		0x9710
@@ -281,16 +279,19 @@
 	int ret_val;
 	unsigned long flags;
 	struct mos7715_parport *mos_parport = (void *)_mos_parport;
-	struct urbtracker *urbtrack;
+	struct urbtracker *urbtrack, *tmp;
 	struct list_head *cursor, *next;
+	struct device *dev;
 
 	/* if release function ran, game over */
 	if (unlikely(mos_parport->serial == NULL))
 		return;
 
+	dev = &mos_parport->serial->dev->dev;
+
 	/* try again to get the mutex */
 	if (!mutex_trylock(&mos_parport->serial->disc_mutex)) {
-		dbg("%s: rescheduling tasklet", __func__);
+		dev_dbg(dev, "%s: rescheduling tasklet\n", __func__);
 		tasklet_schedule(&mos_parport->urb_tasklet);
 		return;
 	}
@@ -305,20 +306,19 @@
 	if (list_empty(&mos_parport->deferred_urbs)) {
 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
 		mutex_unlock(&mos_parport->serial->disc_mutex);
-		dbg("%s: deferred_urbs list empty", __func__);
+		dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__);
 		return;
 	}
 
 	/* move contents of deferred_urbs list to active_urbs list and submit */
 	list_for_each_safe(cursor, next, &mos_parport->deferred_urbs)
 		list_move_tail(cursor, &mos_parport->active_urbs);
-	list_for_each_entry(urbtrack, &mos_parport->active_urbs,
+	list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs,
 			    urblist_entry) {
 		ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
-		dbg("%s: urb submitted", __func__);
+		dev_dbg(dev, "%s: urb submitted\n", __func__);
 		if (ret_val) {
-			dev_err(&mos_parport->serial->dev->dev,
-				"usb_submit_urb() failed: %d", ret_val);
+			dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val);
 			list_del(&urbtrack->urblist_entry);
 			kref_put(&urbtrack->ref_count, destroy_urbtracker);
 		}
@@ -334,7 +334,7 @@
 	int status = urb->status;
 
 	if (unlikely(status))
-		dbg("%s - nonzero urb status received: %d", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
 
 	/* remove the urbtracker from the active_urbs list */
 	spin_lock(&urbtrack->mos_parport->listlock);
@@ -389,7 +389,7 @@
 			      &mos_parport->deferred_urbs);
 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
 		tasklet_schedule(&mos_parport->urb_tasklet);
-		dbg("tasklet scheduled");
+		dev_dbg(&usbdev->dev, "tasklet scheduled");
 		return 0;
 	}
 
@@ -690,7 +690,7 @@
 	/* allocate and initialize parallel port control struct */
 	mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL);
 	if (mos_parport == NULL) {
-		dbg("mos7715_parport_init: kzalloc failed");
+		dev_dbg(&serial->dev->dev, "%s: kzalloc failed\n", __func__);
 		return -ENOMEM;
 	}
 	mos_parport->msg_pending = false;
@@ -743,6 +743,7 @@
 	int result;
 	int length;
 	int status = urb->status;
+	struct device *dev = &urb->dev->dev;
 	__u8 *data;
 	__u8 sp1;
 	__u8 sp2;
@@ -755,12 +756,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
 		goto exit;
 	}
 
@@ -777,7 +776,7 @@
 	 * 	oneukum 2007-03-14 */
 
 	if (unlikely(length != 4)) {
-		dbg("Wrong data !!!");
+		dev_dbg(dev, "Wrong data !!!\n");
 		return;
 	}
 
@@ -786,31 +785,29 @@
 
 	if ((sp1 | sp2) & 0x01) {
 		/* No Interrupt Pending in both the ports */
-		dbg("No Interrupt !!!");
+		dev_dbg(dev, "No Interrupt !!!\n");
 	} else {
 		switch (sp1 & 0x0f) {
 		case SERIAL_IIR_RLS:
-			dbg("Serial Port 1: Receiver status error or address "
-			    "bit detected in 9-bit mode\n");
+			dev_dbg(dev, "Serial Port 1: Receiver status error or address bit detected in 9-bit mode\n");
 			break;
 		case SERIAL_IIR_CTI:
-			dbg("Serial Port 1: Receiver time out");
+			dev_dbg(dev, "Serial Port 1: Receiver time out\n");
 			break;
 		case SERIAL_IIR_MS:
-			/* dbg("Serial Port 1: Modem status change"); */
+			/* dev_dbg(dev, "Serial Port 1: Modem status change\n"); */
 			break;
 		}
 
 		switch (sp2 & 0x0f) {
 		case SERIAL_IIR_RLS:
-			dbg("Serial Port 2: Receiver status error or address "
-			    "bit detected in 9-bit mode");
+			dev_dbg(dev, "Serial Port 2: Receiver status error or address bit detected in 9-bit mode\n");
 			break;
 		case SERIAL_IIR_CTI:
-			dbg("Serial Port 2: Receiver time out");
+			dev_dbg(dev, "Serial Port 2: Receiver time out\n");
 			break;
 		case SERIAL_IIR_MS:
-			/* dbg("Serial Port 2: Modem status change"); */
+			/* dev_dbg(dev, "Serial Port 2: Modem status change\n"); */
 			break;
 		}
 	}
@@ -818,9 +815,7 @@
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result)
-		dev_err(&urb->dev->dev,
-			"%s - Error %d submitting control urb\n",
-			__func__, result);
+		dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result);
 }
 
 /*
@@ -833,6 +828,7 @@
 	int result;
 	int length;
 	int status = urb->status;
+	struct device *dev = &urb->dev->dev;
 	__u8 *data;
 	__u8 iir;
 
@@ -845,12 +841,10 @@
 	case -ESHUTDOWN:
 	case -ENODEV:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
 		goto exit;
 	}
 
@@ -864,7 +858,7 @@
 	 * Byte 4: FIFO status for both */
 
 	if (unlikely(length != 4)) {
-		dbg("Wrong data !!!");
+		dev_dbg(dev, "Wrong data !!!\n");
 		return;
 	}
 
@@ -872,14 +866,13 @@
 	if (!(iir & 0x01)) {	/* serial port interrupt pending */
 		switch (iir & 0x0f) {
 		case SERIAL_IIR_RLS:
-			dbg("Serial Port: Receiver status error or address "
-			    "bit detected in 9-bit mode\n");
+			dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n\n");
 			break;
 		case SERIAL_IIR_CTI:
-			dbg("Serial Port: Receiver time out");
+			dev_dbg(dev, "Serial Port: Receiver time out\n");
 			break;
 		case SERIAL_IIR_MS:
-			/* dbg("Serial Port: Modem status change"); */
+			/* dev_dbg(dev, "Serial Port: Modem status change\n"); */
 			break;
 		}
 	}
@@ -897,9 +890,7 @@
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result)
-		dev_err(&urb->dev->dev,
-			"%s - Error %d submitting control urb\n",
-			__func__, result);
+		dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result);
 }
 
 /*
@@ -916,13 +907,13 @@
 	int status = urb->status;
 
 	if (status) {
-		dbg("nonzero read bulk status received: %d", status);
+		dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status);
 		return;
 	}
 
 	port = urb->context;
 
-	dbg("Entering...%s", __func__);
+	dev_dbg(&port->dev, "Entering...%s\n", __func__);
 
 	data = urb->transfer_buffer;
 
@@ -936,8 +927,7 @@
 	if (port->read_urb->status != -EINPROGRESS) {
 		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (retval)
-			dbg("usb_submit_urb(read bulk) failed, retval = %d",
-			    retval);
+			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval);
 	}
 }
 
@@ -953,13 +943,13 @@
 	int status = urb->status;
 
 	if (status) {
-		dbg("nonzero write bulk status received:%d", status);
+		dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status);
 		return;
 	}
 
 	mos7720_port = urb->context;
 	if (!mos7720_port) {
-		dbg("NULL mos7720_port pointer");
+		dev_dbg(&urb->dev->dev, "NULL mos7720_port pointer\n");
 		return ;
 	}
 
@@ -1061,9 +1051,7 @@
 	port_number = port->number - port->serial->minor;
 	read_mos_reg(serial, port_number, LSR, &data);
 
-	dbg("SS::%p LSR:%x", mos7720_port, data);
-
-	dbg("Check:Sending Command ..........");
+	dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data);
 
 	write_mos_reg(serial, dummy, SP1_REG, 0x02);
 	write_mos_reg(serial, dummy, SP2_REG, 0x02);
@@ -1122,20 +1110,16 @@
 	int chars = 0;
 	struct moschip_port *mos7720_port;
 
-	dbg("%s:entering ...........", __func__);
-
 	mos7720_port = usb_get_serial_port_data(port);
-	if (mos7720_port == NULL) {
-		dbg("%s:leaving ...........", __func__);
+	if (mos7720_port == NULL)
 		return 0;
-	}
 
 	for (i = 0; i < NUM_URBS; ++i) {
 		if (mos7720_port->write_urb_pool[i] &&
 		    mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
 			chars += URB_TRANSFER_BUFFER_SIZE;
 	}
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 }
 
@@ -1145,8 +1129,6 @@
 	struct moschip_port *mos7720_port;
 	int j;
 
-	dbg("mos7720_close:entering...");
-
 	serial = port->serial;
 
 	mos7720_port = usb_get_serial_port_data(port);
@@ -1166,9 +1148,7 @@
 
 	/* While closing port, shutdown all bulk read, write  *
 	 * and interrupt read if they exists, otherwise nop   */
-	dbg("Shutdown bulk write");
 	usb_kill_urb(port->write_urb);
-	dbg("Shutdown bulk read");
 	usb_kill_urb(port->read_urb);
 
 	mutex_lock(&serial->disc_mutex);
@@ -1182,8 +1162,6 @@
 	}
 	mutex_unlock(&serial->disc_mutex);
 	mos7720_port->open = 0;
-
-	dbg("Leaving %s", __func__);
 }
 
 static void mos7720_break(struct tty_struct *tty, int break_state)
@@ -1193,8 +1171,6 @@
 	struct usb_serial *serial;
 	struct moschip_port *mos7720_port;
 
-	dbg("Entering %s", __func__);
-
 	serial = port->serial;
 
 	mos7720_port = usb_get_serial_port_data(port);
@@ -1225,13 +1201,9 @@
 	int room = 0;
 	int i;
 
-	dbg("%s:entering ...........", __func__);
-
 	mos7720_port = usb_get_serial_port_data(port);
-	if (mos7720_port == NULL) {
-		dbg("%s:leaving ...........", __func__);
+	if (mos7720_port == NULL)
 		return -ENODEV;
-	}
 
 	/* FIXME: Locking */
 	for (i = 0; i < NUM_URBS; ++i) {
@@ -1240,7 +1212,7 @@
 			room += URB_TRANSFER_BUFFER_SIZE;
 	}
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -1257,15 +1229,11 @@
 	struct urb    *urb;
 	const unsigned char *current_position = data;
 
-	dbg("%s:entering ...........", __func__);
-
 	serial = port->serial;
 
 	mos7720_port = usb_get_serial_port_data(port);
-	if (mos7720_port == NULL) {
-		dbg("mos7720_port is NULL");
+	if (mos7720_port == NULL)
 		return -ENODEV;
-	}
 
 	/* try to find a free urb in the list */
 	urb = NULL;
@@ -1274,13 +1242,13 @@
 		if (mos7720_port->write_urb_pool[i] &&
 		    mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
 			urb = mos7720_port->write_urb_pool[i];
-			dbg("URB:%d", i);
+			dev_dbg(&port->dev, "URB:%d\n", i);
 			break;
 		}
 	}
 
 	if (urb == NULL) {
-		dbg("%s - no more free urbs", __func__);
+		dev_dbg(&port->dev, "%s - no more free urbs\n", __func__);
 		goto exit;
 	}
 
@@ -1296,7 +1264,7 @@
 	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
 
 	memcpy(urb->transfer_buffer, current_position, transfer_size);
-	usb_serial_debug_data(debug, &port->dev, __func__, transfer_size,
+	usb_serial_debug_data(&port->dev, __func__, transfer_size,
 			      urb->transfer_buffer);
 
 	/* fill urb with data and submit  */
@@ -1326,20 +1294,16 @@
 	struct moschip_port *mos7720_port;
 	int status;
 
-	dbg("%s- port %d", __func__, port->number);
-
 	mos7720_port = usb_get_serial_port_data(port);
 
 	if (mos7720_port == NULL)
 		return;
 
 	if (!mos7720_port->open) {
-		dbg("port not opened");
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
-	dbg("%s: Entering ..........", __func__);
-
 	/* if we are implementing XON/XOFF, send the stop character */
 	if (I_IXOFF(tty)) {
 		unsigned char stop_char = STOP_CHAR(tty);
@@ -1368,12 +1332,10 @@
 		return;
 
 	if (!mos7720_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
-	dbg("%s: Entering ..........", __func__);
-
 	/* if we are implementing XON/XOFF, send the start character */
 	if (I_IXOFF(tty)) {
 		unsigned char start_char = START_CHAR(tty);
@@ -1409,7 +1371,7 @@
 	 /***********************************************
 	 *      Init Sequence for higher rates
 	 ***********************************************/
-	dbg("Sending Setting Commands ..........");
+	dev_dbg(&port->dev, "Sending Setting Commands ..........\n");
 	port_number = port->number - port->serial->minor;
 
 	write_mos_reg(serial, port_number, IER, 0x00);
@@ -1478,7 +1440,7 @@
  *	this function calculates the proper baud rate divisor for the specified
  *	baud rate.
  *****************************************************************************/
-static int calc_baud_rate_divisor(int baudrate, int *divisor)
+static int calc_baud_rate_divisor(struct usb_serial_port *port, int baudrate, int *divisor)
 {
 	int i;
 	__u16 custom;
@@ -1486,7 +1448,7 @@
 	__u16 round;
 
 
-	dbg("%s - %d", __func__, baudrate);
+	dev_dbg(&port->dev, "%s - %d\n", __func__, baudrate);
 
 	for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
 		if (divisor_table[i].baudrate == baudrate) {
@@ -1508,11 +1470,11 @@
 			custom++;
 		*divisor = custom;
 
-		dbg("Baud %d = %d", baudrate, custom);
+		dev_dbg(&port->dev, "Baud %d = %d\n", baudrate, custom);
 		return 0;
 	}
 
-	dbg("Baud calculation Failed...");
+	dev_dbg(&port->dev, "Baud calculation Failed...\n");
 	return -EINVAL;
 }
 
@@ -1536,13 +1498,11 @@
 	port = mos7720_port->port;
 	serial = port->serial;
 
-	dbg("%s: Entering ..........", __func__);
-
 	number = port->number - port->serial->minor;
-	dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate);
+	dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudrate);
 
 	/* Calculate the Divisor */
-	status = calc_baud_rate_divisor(baudrate, &divisor);
+	status = calc_baud_rate_divisor(port, baudrate, &divisor);
 	if (status) {
 		dev_err(&port->dev, "%s - bad baud rate\n", __func__);
 		return status;
@@ -1591,15 +1551,11 @@
 	serial = port->serial;
 	port_number = port->number - port->serial->minor;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	if (!mos7720_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
-	dbg("%s: Entering ..........", __func__);
-
 	lData = UART_LCR_WLEN8;
 	lStop = 0x00;	/* 1 stop bit */
 	lParity = 0x00;	/* No parity */
@@ -1633,14 +1589,14 @@
 	if (cflag & PARENB) {
 		if (cflag & PARODD) {
 			lParity = UART_LCR_PARITY;
-			dbg("%s - parity = odd", __func__);
+			dev_dbg(&port->dev, "%s - parity = odd\n", __func__);
 		} else {
 			lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
-			dbg("%s - parity = even", __func__);
+			dev_dbg(&port->dev, "%s - parity = even\n", __func__);
 		}
 
 	} else {
-		dbg("%s - parity = none", __func__);
+		dev_dbg(&port->dev, "%s - parity = none\n", __func__);
 	}
 
 	if (cflag & CMSPAR)
@@ -1649,10 +1605,10 @@
 	/* Change the Stop bit */
 	if (cflag & CSTOPB) {
 		lStop = UART_LCR_STOP;
-		dbg("%s - stop bits = 2", __func__);
+		dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__);
 	} else {
 		lStop = 0x00;
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__);
 	}
 
 #define LCR_BITS_MASK		0x03	/* Mask for bits/char field */
@@ -1698,7 +1654,7 @@
 	baud = tty_get_baud_rate(tty);
 	if (!baud) {
 		/* pick a default, any default... */
-		dbg("Picked default baud...");
+		dev_dbg(&port->dev, "Picked default baud...\n");
 		baud = 9600;
 	}
 
@@ -1709,7 +1665,7 @@
 		return;
 	}
 
-	dbg("%s - baud rate = %d", __func__, baud);
+	dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud);
 	status = send_cmd_write_baud_rate(mos7720_port, baud);
 	/* FIXME: needs to write actual resulting baud back not just
 	   blindly do so */
@@ -1721,8 +1677,7 @@
 	if (port->read_urb->status != -EINPROGRESS) {
 		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (status)
-			dbg("usb_submit_urb(read bulk) failed, status = %d",
-			    status);
+			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
 	}
 }
 
@@ -1747,23 +1702,19 @@
 		return;
 
 	if (!mos7720_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
-	dbg("%s\n", "setting termios - ASPIRE");
+	dev_dbg(&port->dev, "setting termios - ASPIRE\n");
 
 	cflag = tty->termios.c_cflag;
 
-	dbg("%s - cflag %08x iflag %08x", __func__,
-	    tty->termios.c_cflag,
-	    RELEVANT_IFLAG(tty->termios.c_iflag));
+	dev_dbg(&port->dev, "%s - cflag %08x iflag %08x\n", __func__,
+		tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
 
-	dbg("%s - old cflag %08x old iflag %08x", __func__,
-	    old_termios->c_cflag,
-	    RELEVANT_IFLAG(old_termios->c_iflag));
-
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(&port->dev, "%s - old cflag %08x old iflag %08x\n", __func__,
+		old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
 
 	/* change the port settings to the new ones specified */
 	change_port_settings(tty, mos7720_port, old_termios);
@@ -1771,8 +1722,7 @@
 	if (port->read_urb->status != -EINPROGRESS) {
 		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (status)
-			dbg("usb_submit_urb(read bulk) failed, status = %d",
-			    status);
+			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
 	}
 }
 
@@ -1800,7 +1750,7 @@
 		read_mos_reg(port->serial, port_number, LSR, &data);
 		if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
 					== (UART_LSR_TEMT | UART_LSR_THRE)) {
-			dbg("%s -- Empty", __func__);
+			dev_dbg(&port->dev, "%s -- Empty\n", __func__);
 			result = TIOCSER_TEMT;
 		}
 	}
@@ -1817,8 +1767,6 @@
 	unsigned int mcr ;
 	unsigned int msr ;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	mcr = mos7720_port->shadowMCR;
 	msr = mos7720_port->shadowMSR;
 
@@ -1829,8 +1777,6 @@
 	  | ((msr & UART_MSR_RI)    ? TIOCM_RI :  0)   /* 0x080 */
 	  | ((msr & UART_MSR_DSR)   ? TIOCM_DSR : 0);  /* 0x100 */
 
-	dbg("%s -- %x", __func__, result);
-
 	return result;
 }
 
@@ -1840,8 +1786,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
 	unsigned int mcr ;
-	dbg("%s - port %d", __func__, port->number);
-	dbg("he was at tiocmset");
 
 	mcr = mos7720_port->shadowMCR;
 
@@ -1888,8 +1832,8 @@
 	icount->brk = cnow.brk;
 	icount->buf_overrun = cnow.buf_overrun;
 
-	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
-		port->number, icount->rx, icount->tx);
+	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
+		icount->rx, icount->tx);
 	return 0;
 }
 
@@ -1975,29 +1919,28 @@
 	if (mos7720_port == NULL)
 		return -ENODEV;
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - cmd = 0x%x", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCSERGETLSR:
-		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
+		dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
 		return get_lsr_info(tty, mos7720_port,
 					(unsigned int __user *)arg);
 
 	/* FIXME: These should be using the mode methods */
 	case TIOCMBIS:
 	case TIOCMBIC:
-		dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET",
-					__func__, port->number);
+		dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__);
 		return set_modem_info(mos7720_port, cmd,
 				      (unsigned int __user *)arg);
 
 	case TIOCGSERIAL:
-		dbg("%s (%d) TIOCGSERIAL", __func__,  port->number);
+		dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
 		return get_serial_info(mos7720_port,
 				       (struct serial_struct __user *)arg);
 
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+		dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
 		cprev = mos7720_port->icount;
 		while (1) {
 			if (signal_pending(current))
@@ -2030,13 +1973,6 @@
 	u16 product;
 	int ret_val;
 
-	dbg("%s: Entering ..........", __func__);
-
-	if (!serial) {
-		dbg("Invalid Handler");
-		return -ENODEV;
-	}
-
 	product = le16_to_cpu(serial->dev->descriptor.idProduct);
 	dev = serial->dev;
 
@@ -2081,8 +2017,8 @@
 		mos7720_port->port = serial->port[i];
 		usb_set_serial_port_data(serial->port[i], mos7720_port);
 
-		dbg("port number is %d", serial->port[i]->number);
-		dbg("serial number is %d", serial->minor);
+		dev_dbg(&dev->dev, "port number is %d\n", serial->port[i]->number);
+		dev_dbg(&dev->dev, "serial number is %d\n", serial->minor);
 	}
 
 
@@ -2106,7 +2042,7 @@
 #endif
 	/* LSR For Port 1 */
 	read_mos_reg(serial, 0, LSR, &data);
-	dbg("LSR:%x", data);
+	dev_dbg(&dev->dev, "LSR:%x\n", data);
 
 	return 0;
 }
@@ -2195,6 +2131,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 402c32d..d6d4eec 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -252,8 +252,6 @@
 	struct timer_list led_timer2;	/* Timer for LED off */
 };
 
-static bool debug;
-
 /*
  * mos7840_set_reg_sync
  * 	To set the Control register by calling usb_fill_control_urb function
@@ -265,7 +263,7 @@
 {
 	struct usb_device *dev = port->serial->dev;
 	val = val & 0x00ff;
-	dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val);
+	dev_dbg(&port->dev, "mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
 
 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
 			       MCS_WR_RTYPE, val, reg, NULL, 0,
@@ -293,7 +291,7 @@
 			      MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
 			      MOS_WDR_TIMEOUT);
 	*val = buf[0];
-	dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val);
+	dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val);
 
 	kfree(buf);
 	return ret;
@@ -316,21 +314,16 @@
 	if (port->serial->num_ports == 4) {
 		val |= (((__u16) port->number -
 				(__u16) (port->serial->minor)) + 1) << 8;
-		dbg("mos7840_set_uart_reg application number is %x", val);
 	} else {
 		if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
 			val |= (((__u16) port->number -
 			      (__u16) (port->serial->minor)) + 1) << 8;
-			dbg("mos7840_set_uart_reg application number is %x",
-			    val);
 		} else {
-			val |=
-			    (((__u16) port->number -
+			val |= (((__u16) port->number -
 			      (__u16) (port->serial->minor)) + 2) << 8;
-			dbg("mos7840_set_uart_reg application number is %x",
-			    val);
 		}
 	}
+	dev_dbg(&port->dev, "%s application number is %x\n", __func__, val);
 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
 			       MCS_WR_RTYPE, val, reg, NULL, 0,
 			       MOS_WDR_TIMEOUT);
@@ -354,27 +347,21 @@
 	if (!buf)
 		return -ENOMEM;
 
-	/* dbg("application number is %4x",
-	    (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
 	/* Wval  is same as application number */
 	if (port->serial->num_ports == 4) {
 		Wval =
 		    (((__u16) port->number - (__u16) (port->serial->minor)) +
 		     1) << 8;
-		dbg("mos7840_get_uart_reg application number is %x", Wval);
 	} else {
 		if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
 			Wval = (((__u16) port->number -
 			      (__u16) (port->serial->minor)) + 1) << 8;
-			dbg("mos7840_get_uart_reg application number is %x",
-			    Wval);
 		} else {
 			Wval = (((__u16) port->number -
 			      (__u16) (port->serial->minor)) + 2) << 8;
-			dbg("mos7840_get_uart_reg application number is %x",
-			    Wval);
 		}
 	}
+	dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval);
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
 			      MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
 			      MOS_WDR_TIMEOUT);
@@ -384,14 +371,13 @@
 	return ret;
 }
 
-static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
+static void mos7840_dump_serial_port(struct usb_serial_port *port,
+				     struct moschip_port *mos7840_port)
 {
 
-	dbg("***************************************");
-	dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset);
-	dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset);
-	dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset);
-	dbg("***************************************");
+	dev_dbg(&port->dev, "SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
+	dev_dbg(&port->dev, "ControlRegOffset is %2x\n", mos7840_port->ControlRegOffset);
+	dev_dbg(&port->dev, "DCRRegOffset is %2x\n", mos7840_port->DcrRegOffset);
 
 }
 
@@ -450,8 +436,6 @@
 {
 	struct async_icount *icount;
 
-	dbg("%s - %02x", __func__, new_lsr);
-
 	if (new_lsr & SERIAL_LSR_BI) {
 		/*
 		 * Parity and Framing errors only count if they
@@ -492,6 +476,7 @@
 {
 	unsigned char *data;
 	struct moschip_port *mos7840_port;
+	struct device *dev = &urb->dev->dev;
 	__u8 regval = 0x0;
 	int result = 0;
 	int status = urb->status;
@@ -506,21 +491,19 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
 		goto exit;
 	}
 
-	dbg("%s urb buffer size is %d", __func__, urb->actual_length);
-	dbg("%s mos7840_port->MsrLsr is %d port %d", __func__,
-	    mos7840_port->MsrLsr, mos7840_port->port_num);
+	dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
+	dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__,
+		mos7840_port->MsrLsr, mos7840_port->port_num);
 	data = urb->transfer_buffer;
 	regval = (__u8) data[0];
-	dbg("%s data is %x", __func__, regval);
+	dev_dbg(dev, "%s data is %x\n", __func__, regval);
 	if (mos7840_port->MsrLsr == 0)
 		mos7840_handle_new_msr(mos7840_port, regval);
 	else if (mos7840_port->MsrLsr == 1)
@@ -532,8 +515,7 @@
 		result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC);
 	spin_unlock(&mos7840_port->pool_lock);
 	if (result) {
-		dev_err(&urb->dev->dev,
-			"%s - Error %d submitting interrupt urb\n",
+		dev_err(dev, "%s - Error %d submitting interrupt urb\n",
 			__func__, result);
 	}
 }
@@ -570,12 +552,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-			urb->status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d",
+			__func__, urb->status);
 		break;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-			urb->status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d",
+			__func__, urb->status);
 	}
 }
 
@@ -650,12 +632,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
+		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __func__,
-		    status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
@@ -672,7 +654,7 @@
 	 * Byte 5 FIFO status for both */
 
 	if (length && length > 5) {
-		dbg("%s", "Wrong data !!!");
+		dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n");
 		return;
 	}
 
@@ -689,17 +671,17 @@
 		      (__u16) (serial->minor)) + 1) << 8;
 		if (mos7840_port->open) {
 			if (sp[i] & 0x01) {
-				dbg("SP%d No Interrupt !!!", i);
+				dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i);
 			} else {
 				switch (sp[i] & 0x0f) {
 				case SERIAL_IIR_RLS:
-					dbg("Serial Port %d: Receiver status error or ", i);
-					dbg("address bit detected in 9-bit mode");
+					dev_dbg(&urb->dev->dev, "Serial Port %d: Receiver status error or \n", i);
+					dev_dbg(&urb->dev->dev, "address bit detected in 9-bit mode\n");
 					mos7840_port->MsrLsr = 1;
 					wreg = LINE_STATUS_REGISTER;
 					break;
 				case SERIAL_IIR_MS:
-					dbg("Serial Port %d: Modem status change", i);
+					dev_dbg(&urb->dev->dev, "Serial Port %d: Modem status change\n", i);
 					mos7840_port->MsrLsr = 0;
 					wreg = MODEM_STATUS_REGISTER;
 					break;
@@ -731,11 +713,11 @@
 				       const char *function)
 {
 	if (!port) {
-		dbg("%s - port == NULL", function);
+		pr_debug("%s - port == NULL\n", function);
 		return -1;
 	}
 	if (!port->serial) {
-		dbg("%s - port->serial == NULL", function);
+		pr_debug("%s - port->serial == NULL\n", function);
 		return -1;
 	}
 
@@ -747,11 +729,11 @@
 					 const char *function)
 {
 	if (!serial) {
-		dbg("%s - serial == NULL", function);
+		pr_debug("%s - serial == NULL\n", function);
 		return -1;
 	}
 	if (!serial->type) {
-		dbg("%s - serial->type == NULL!", function);
+		pr_debug("%s - serial->type == NULL!\n", function);
 		return -1;
 	}
 
@@ -790,49 +772,44 @@
 	int status = urb->status;
 
 	mos7840_port = urb->context;
-	if (!mos7840_port) {
-		dbg("%s", "NULL mos7840_port pointer");
+	if (!mos7840_port)
 		return;
-	}
 
 	if (status) {
-		dbg("nonzero read bulk status received: %d", status);
+		dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status);
 		mos7840_port->read_urb_busy = false;
 		return;
 	}
 
-	port = (struct usb_serial_port *)mos7840_port->port;
+	port = mos7840_port->port;
 	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
 		mos7840_port->read_urb_busy = false;
 		return;
 	}
 
 	serial = mos7840_get_usb_serial(port, __func__);
 	if (!serial) {
-		dbg("%s", "Bad serial pointer");
 		mos7840_port->read_urb_busy = false;
 		return;
 	}
 
 	data = urb->transfer_buffer;
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	if (urb->actual_length) {
 		tty = tty_port_tty_get(&mos7840_port->port->port);
 		if (tty) {
 			tty_insert_flip_string(tty, data, urb->actual_length);
-			dbg(" %s ", data);
 			tty_flip_buffer_push(tty);
 			tty_kref_put(tty);
 		}
 		mos7840_port->icount.rx += urb->actual_length;
 		smp_wmb();
-		dbg("mos7840_port->icount.rx is %d:",
-		    mos7840_port->icount.rx);
+		dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx);
 	}
 
 	if (!mos7840_port->read_urb) {
-		dbg("%s", "URB KILLED !!!");
+		dev_dbg(&port->dev, "%s", "URB KILLED !!!\n");
 		mos7840_port->read_urb_busy = false;
 		return;
 	}
@@ -850,7 +827,7 @@
 	retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 
 	if (retval) {
-		dbg("usb_submit_urb(read bulk) failed, retval = %d", retval);
+		dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval);
 		mos7840_port->read_urb_busy = false;
 	}
 }
@@ -864,11 +841,13 @@
 static void mos7840_bulk_out_data_callback(struct urb *urb)
 {
 	struct moschip_port *mos7840_port;
+	struct usb_serial_port *port;
 	struct tty_struct *tty;
 	int status = urb->status;
 	int i;
 
 	mos7840_port = urb->context;
+	port = mos7840_port->port;
 	spin_lock(&mos7840_port->pool_lock);
 	for (i = 0; i < NUM_URBS; i++) {
 		if (urb == mos7840_port->write_urb_pool[i]) {
@@ -879,16 +858,14 @@
 	spin_unlock(&mos7840_port->pool_lock);
 
 	if (status) {
-		dbg("nonzero write bulk status received:%d", status);
+		dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status);
 		return;
 	}
 
-	if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
-	tty = tty_port_tty_get(&mos7840_port->port->port);
+	tty = tty_port_tty_get(&port->port);
 	if (tty && mos7840_port->open)
 		tty_wakeup(tty);
 	tty_kref_put(tty);
@@ -929,17 +906,13 @@
 	struct moschip_port *mos7840_port;
 	struct moschip_port *port0;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return -ENODEV;
-	}
 
 	serial = port->serial;
 
-	if (mos7840_serial_paranoia_check(serial, __func__)) {
-		dbg("%s", "Serial Paranoia failed");
+	if (mos7840_serial_paranoia_check(serial, __func__))
 		return -ENODEV;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 	port0 = mos7840_get_port_private(serial->port[0]);
@@ -990,20 +963,20 @@
 	Data = 0x0;
 	status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
 	if (status < 0) {
-		dbg("Reading Spreg failed");
+		dev_dbg(&port->dev, "Reading Spreg failed\n");
 		return -1;
 	}
 	Data |= 0x80;
 	status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
 	if (status < 0) {
-		dbg("writing Spreg failed");
+		dev_dbg(&port->dev, "writing Spreg failed\n");
 		return -1;
 	}
 
 	Data &= ~0x80;
 	status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
 	if (status < 0) {
-		dbg("writing Spreg failed");
+		dev_dbg(&port->dev, "writing Spreg failed\n");
 		return -1;
 	}
 	/* End of block to be checked */
@@ -1012,7 +985,7 @@
 	status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
 									&Data);
 	if (status < 0) {
-		dbg("Reading Controlreg failed");
+		dev_dbg(&port->dev, "Reading Controlreg failed\n");
 		return -1;
 	}
 	Data |= 0x08;		/* Driver done bit */
@@ -1020,7 +993,7 @@
 	status = mos7840_set_reg_sync(port,
 				mos7840_port->ControlRegOffset, Data);
 	if (status < 0) {
-		dbg("writing Controlreg failed");
+		dev_dbg(&port->dev, "writing Controlreg failed\n");
 		return -1;
 	}
 	/* do register settings here */
@@ -1031,21 +1004,21 @@
 	Data = 0x00;
 	status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
 	if (status < 0) {
-		dbg("disabling interrupts failed");
+		dev_dbg(&port->dev, "disabling interrupts failed\n");
 		return -1;
 	}
 	/* Set FIFO_CONTROL_REGISTER to the default value */
 	Data = 0x00;
 	status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
 	if (status < 0) {
-		dbg("Writing FIFO_CONTROL_REGISTER  failed");
+		dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER  failed\n");
 		return -1;
 	}
 
 	Data = 0xcf;
 	status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
 	if (status < 0) {
-		dbg("Writing FIFO_CONTROL_REGISTER  failed");
+		dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER  failed\n");
 		return -1;
 	}
 
@@ -1142,12 +1115,12 @@
 	 * (can't set it up in mos7840_startup as the  *
 	 * structures were not set up at that time.)   */
 
-	dbg("port number is %d", port->number);
-	dbg("serial number is %d", port->serial->minor);
-	dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
-	dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
-	dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress);
-	dbg("port's number in the device is %d", mos7840_port->port_num);
+	dev_dbg(&port->dev, "port number is %d\n", port->number);
+	dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
+	dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
+	dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
+	dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress);
+	dev_dbg(&port->dev, "port's number in the device is %d\n", mos7840_port->port_num);
 	mos7840_port->read_urb = port->read_urb;
 
 	/* set up our bulk in urb */
@@ -1171,8 +1144,7 @@
 			mos7840_bulk_in_callback, mos7840_port);
 	}
 
-	dbg("mos7840_open: bulkin endpoint is %d",
-	    port->bulk_in_endpointAddress);
+	dev_dbg(&port->dev, "%s: bulkin endpoint is %d\n", __func__, port->bulk_in_endpointAddress);
 	mos7840_port->read_urb_busy = true;
 	response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
 	if (response) {
@@ -1197,9 +1169,6 @@
 	mos7840_port->icount.tx = 0;
 	mos7840_port->icount.rx = 0;
 
-	dbg("usb_serial serial:%p       mos7840_port:%p\n      usb_serial_port port:%p",
-				serial, mos7840_port, port);
-
 	return 0;
 }
 
@@ -1221,10 +1190,8 @@
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return 0;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 	if (mos7840_port == NULL)
@@ -1238,7 +1205,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 
 }
@@ -1256,16 +1223,12 @@
 	int j;
 	__u16 Data;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
 	serial = mos7840_get_usb_serial(port, __func__);
-	if (!serial) {
-		dbg("%s", "Serial Paranoia failed");
+	if (!serial)
 		return;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 	port0 = mos7840_get_port_private(serial->port[0]);
@@ -1291,27 +1254,26 @@
 	 * and interrupt read if they exists                  */
 	if (serial->dev) {
 		if (mos7840_port->write_urb) {
-			dbg("%s", "Shutdown bulk write");
+			dev_dbg(&port->dev, "%s", "Shutdown bulk write\n");
 			usb_kill_urb(mos7840_port->write_urb);
 		}
 		if (mos7840_port->read_urb) {
-			dbg("%s", "Shutdown bulk read");
+			dev_dbg(&port->dev, "%s", "Shutdown bulk read\n");
 			usb_kill_urb(mos7840_port->read_urb);
 			mos7840_port->read_urb_busy = false;
 		}
 		if ((&mos7840_port->control_urb)) {
-			dbg("%s", "Shutdown control read");
+			dev_dbg(&port->dev, "%s", "Shutdown control read\n");
 			/*/      usb_kill_urb (mos7840_port->control_urb); */
 		}
 	}
 /*      if(mos7840_port->ctrl_buf != NULL) */
 /*              kfree(mos7840_port->ctrl_buf); */
 	port0->open_ports--;
-	dbg("mos7840_num_open_ports in close%d:in port%d",
-	    port0->open_ports, port->number);
+	dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);
 	if (port0->open_ports == 0) {
 		if (serial->port[0]->interrupt_in_urb) {
-			dbg("%s", "Shutdown interrupt_in_urb");
+			dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n");
 			usb_kill_urb(serial->port[0]->interrupt_in_urb);
 		}
 	}
@@ -1363,7 +1325,7 @@
 		/* No activity.. count down section */
 		wait--;
 		if (wait == 0) {
-			dbg("%s - TIMEOUT", __func__);
+			dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__);
 			return;
 		} else {
 			/* Reset timeout value back to seconds */
@@ -1384,16 +1346,12 @@
 	struct usb_serial *serial;
 	struct moschip_port *mos7840_port;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
 	serial = mos7840_get_usb_serial(port, __func__);
-	if (!serial) {
-		dbg("%s", "Serial Paranoia failed");
+	if (!serial)
 		return;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 
@@ -1411,8 +1369,7 @@
 
 	/* FIXME: no locking on shadowLCR anywhere in driver */
 	mos7840_port->shadowLCR = data;
-	dbg("mcs7840_break mos7840_port->shadowLCR is %x",
-	    mos7840_port->shadowLCR);
+	dev_dbg(&port->dev, "%s mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
 	mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
 			     mos7840_port->shadowLCR);
 }
@@ -1433,17 +1390,12 @@
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
-		dbg("%s", " mos7840_write_room:leaving ...........");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return -1;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
-	if (mos7840_port == NULL) {
-		dbg("%s", "mos7840_break:leaving ...........");
+	if (mos7840_port == NULL)
 		return -1;
-	}
 
 	spin_lock_irqsave(&mos7840_port->pool_lock, flags);
 	for (i = 0; i < NUM_URBS; ++i) {
@@ -1453,7 +1405,7 @@
 	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 
 	room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 
 }
@@ -1486,9 +1438,8 @@
 	Data = 0x00;
 	status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
 	mos7840_port->shadowLCR = Data;
-	dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data);
-	dbg("mos7840_write: mos7840_port->shadowLCR is %x",
-	    mos7840_port->shadowLCR);
+	dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data);
+	dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
 
 	/* Data = 0x03; */
 	/* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */
@@ -1501,34 +1452,27 @@
 	/* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
 	Data = 0x00;
 	status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
-	dbg("mos7840_write:DLL value is %x", Data);
+	dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data);
 
 	Data = 0x0;
 	status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
-	dbg("mos7840_write:DLM value is %x", Data);
+	dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data);
 
 	Data = Data & ~SERIAL_LCR_DLAB;
-	dbg("mos7840_write: mos7840_port->shadowLCR is %x",
-	    mos7840_port->shadowLCR);
+	dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
 	status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
 #endif
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Port Paranoia failed");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return -1;
-	}
 
 	serial = port->serial;
-	if (mos7840_serial_paranoia_check(serial, __func__)) {
-		dbg("%s", "Serial Paranoia failed");
+	if (mos7840_serial_paranoia_check(serial, __func__))
 		return -1;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
-	if (mos7840_port == NULL) {
-		dbg("%s", "mos7840_port is NULL");
+	if (mos7840_port == NULL)
 		return -1;
-	}
 
 	/* try to find a free urb in the list */
 	urb = NULL;
@@ -1538,14 +1482,14 @@
 		if (!mos7840_port->busy[i]) {
 			mos7840_port->busy[i] = 1;
 			urb = mos7840_port->write_urb_pool[i];
-			dbg("URB:%d", i);
+			dev_dbg(&port->dev, "URB:%d\n", i);
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 
 	if (urb == NULL) {
-		dbg("%s - no more free urbs", __func__);
+		dev_dbg(&port->dev, "%s - no more free urbs\n", __func__);
 		goto exit;
 	}
 
@@ -1585,7 +1529,7 @@
 	}
 
 	data1 = urb->transfer_buffer;
-	dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
+	dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
 
 	/* Turn on LED */
 	if (mos7840_port->has_led && !mos7840_port->led_flag) {
@@ -1608,7 +1552,7 @@
 	bytes_sent = transfer_size;
 	mos7840_port->icount.tx += transfer_size;
 	smp_wmb();
-	dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx);
+	dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
 exit:
 	return bytes_sent;
 
@@ -1626,12 +1570,8 @@
 	struct moschip_port *mos7840_port;
 	int status;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
-
-	dbg("- port %d", port->number);
 
 	mos7840_port = mos7840_get_port_private(port);
 
@@ -1639,7 +1579,7 @@
 		return;
 
 	if (!mos7840_port->open) {
-		dbg("%s", "port not opened");
+		dev_dbg(&port->dev, "%s", "port not opened\n");
 		return;
 	}
 
@@ -1672,16 +1612,14 @@
 	int status;
 	struct moschip_port *mos7840_port = mos7840_get_port_private(port);
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
 	if (mos7840_port == NULL)
 		return;
 
 	if (!mos7840_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -1726,7 +1664,7 @@
 	    | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
 	    | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
 
-	dbg("%s - 0x%04X", __func__, result);
+	dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
 
 	return result;
 }
@@ -1764,7 +1702,7 @@
 
 	status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
 	if (status < 0) {
-		dbg("setting MODEM_CONTROL_REGISTER Failed");
+		dev_dbg(&port->dev, "setting MODEM_CONTROL_REGISTER Failed\n");
 		return status;
 	}
 
@@ -1776,10 +1714,11 @@
  *	this function calculates the proper baud rate divisor for the specified
  *	baud rate.
  *****************************************************************************/
-static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
+static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
+					  int baudRate, int *divisor,
 					  __u16 *clk_sel_val)
 {
-	dbg("%s - %d", __func__, baudRate);
+	dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate);
 
 	if (baudRate <= 115200) {
 		*divisor = 115200 / baudRate;
@@ -1832,11 +1771,11 @@
 			custom++;
 		*divisor = custom;
 
-		dbg(" Baud %d = %d", baudrate, custom);
+		dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom);
 		return 0;
 	}
 
-	dbg("%s", " Baud calculation Failed...");
+	dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n");
 	return -1;
 #endif
 }
@@ -1860,21 +1799,17 @@
 	if (mos7840_port == NULL)
 		return -1;
 
-	port = (struct usb_serial_port *)mos7840_port->port;
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	port = mos7840_port->port;
+	if (mos7840_port_paranoia_check(port, __func__))
 		return -1;
-	}
 
-	if (mos7840_serial_paranoia_check(port->serial, __func__)) {
-		dbg("%s", "Invalid Serial");
+	if (mos7840_serial_paranoia_check(port->serial, __func__))
 		return -1;
-	}
 
 	number = mos7840_port->port->number - mos7840_port->port->serial->minor;
 
-	dbg("%s - port = %d, baud = %d", __func__,
-	    mos7840_port->port->number, baudRate);
+	dev_dbg(&port->dev, "%s - port = %d, baud = %d\n", __func__,
+		mos7840_port->port->number, baudRate);
 	/* reset clk_uart_sel in spregOffset */
 	if (baudRate > 115200) {
 #ifdef HW_flow_control
@@ -1885,7 +1820,7 @@
 		status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
 									Data);
 		if (status < 0) {
-			dbg("Writing spreg failed in set_serial_baud");
+			dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
 			return -1;
 		}
 #endif
@@ -1898,7 +1833,7 @@
 		status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
 									Data);
 		if (status < 0) {
-			dbg("Writing spreg failed in set_serial_baud");
+			dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
 			return -1;
 		}
 #endif
@@ -1908,19 +1843,19 @@
 	if (1) {		/* baudRate <= 115200) */
 		clk_sel_val = 0x0;
 		Data = 0x0;
-		status = mos7840_calc_baud_rate_divisor(baudRate, &divisor,
+		status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor,
 						   &clk_sel_val);
 		status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
 								 &Data);
 		if (status < 0) {
-			dbg("reading spreg failed in set_serial_baud");
+			dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n");
 			return -1;
 		}
 		Data = (Data & 0x8f) | clk_sel_val;
 		status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
 								Data);
 		if (status < 0) {
-			dbg("Writing spreg failed in set_serial_baud");
+			dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
 			return -1;
 		}
 		/* Calculate the Divisor */
@@ -1936,11 +1871,11 @@
 
 		/* Write the divisor */
 		Data = (unsigned char)(divisor & 0xff);
-		dbg("set_serial_baud Value to write DLL is %x", Data);
+		dev_dbg(&port->dev, "set_serial_baud Value to write DLL is %x\n", Data);
 		mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
 
 		Data = (unsigned char)((divisor & 0xff00) >> 8);
-		dbg("set_serial_baud Value to write DLM is %x", Data);
+		dev_dbg(&port->dev, "set_serial_baud Value to write DLM is %x\n", Data);
 		mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
 
 		/* Disable access to divisor latch */
@@ -1975,24 +1910,18 @@
 	if (mos7840_port == NULL)
 		return;
 
-	port = (struct usb_serial_port *)mos7840_port->port;
+	port = mos7840_port->port;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
-	if (mos7840_serial_paranoia_check(port->serial, __func__)) {
-		dbg("%s", "Invalid Serial");
+	if (mos7840_serial_paranoia_check(port->serial, __func__))
 		return;
-	}
 
 	serial = port->serial;
 
-	dbg("%s - port %d", __func__, mos7840_port->port->number);
-
 	if (!mos7840_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -2027,14 +1956,14 @@
 	if (cflag & PARENB) {
 		if (cflag & PARODD) {
 			lParity = LCR_PAR_ODD;
-			dbg("%s - parity = odd", __func__);
+			dev_dbg(&port->dev, "%s - parity = odd\n", __func__);
 		} else {
 			lParity = LCR_PAR_EVEN;
-			dbg("%s - parity = even", __func__);
+			dev_dbg(&port->dev, "%s - parity = even\n", __func__);
 		}
 
 	} else {
-		dbg("%s - parity = none", __func__);
+		dev_dbg(&port->dev, "%s - parity = none\n", __func__);
 	}
 
 	if (cflag & CMSPAR)
@@ -2043,10 +1972,10 @@
 	/* Change the Stop bit */
 	if (cflag & CSTOPB) {
 		lStop = LCR_STOP_2;
-		dbg("%s - stop bits = 2", __func__);
+		dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__);
 	} else {
 		lStop = LCR_STOP_1;
-		dbg("%s - stop bits = 1", __func__);
+		dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__);
 	}
 
 	/* Update the LCR with the correct value */
@@ -2054,8 +1983,8 @@
 	    ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
 	mos7840_port->shadowLCR |= (lData | lParity | lStop);
 
-	dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x",
-	    mos7840_port->shadowLCR);
+	dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is %x\n", __func__,
+		mos7840_port->shadowLCR);
 	/* Disable Interrupts */
 	Data = 0x00;
 	mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
@@ -2096,11 +2025,11 @@
 
 	if (!baud) {
 		/* pick a default, any default... */
-		dbg("%s", "Picked default baud...");
+		dev_dbg(&port->dev, "%s", "Picked default baud...\n");
 		baud = 9600;
 	}
 
-	dbg("%s - baud rate = %d", __func__, baud);
+	dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud);
 	status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
 
 	/* Enable Interrupts */
@@ -2111,15 +2040,15 @@
 		mos7840_port->read_urb_busy = true;
 		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 		if (status) {
-			dbg("usb_submit_urb(read bulk) failed, status = %d",
+			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
 			    status);
 			mos7840_port->read_urb_busy = false;
 		}
 	}
 	wake_up(&mos7840_port->delta_msr_wait);
 	mos7840_port->delta_msr_cond = 1;
-	dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
-	    mos7840_port->shadowLCR);
+	dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__,
+		mos7840_port->shadowLCR);
 }
 
 /*****************************************************************************
@@ -2137,17 +2066,13 @@
 	struct usb_serial *serial;
 	struct moschip_port *mos7840_port;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return;
-	}
 
 	serial = port->serial;
 
-	if (mos7840_serial_paranoia_check(serial, __func__)) {
-		dbg("%s", "Invalid Serial");
+	if (mos7840_serial_paranoia_check(serial, __func__))
 		return;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 
@@ -2155,26 +2080,26 @@
 		return;
 
 	if (!mos7840_port->open) {
-		dbg("%s - port not opened", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
-	dbg("%s", "setting termios - ");
+	dev_dbg(&port->dev, "%s", "setting termios - \n");
 
 	cflag = tty->termios.c_cflag;
 
-	dbg("%s - clfag %08x iflag %08x", __func__,
-	    tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
-	dbg("%s - old clfag %08x old iflag %08x", __func__,
-	    old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__,
+		tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
+	dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
+		old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
+	dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
 
 	/* change the port settings to the new ones specified */
 
 	mos7840_change_port_settings(tty, mos7840_port, old_termios);
 
 	if (!mos7840_port->read_urb) {
-		dbg("%s", "URB KILLED !!!!!");
+		dev_dbg(&port->dev, "%s", "URB KILLED !!!!!\n");
 		return;
 	}
 
@@ -2182,7 +2107,7 @@
 		mos7840_port->read_urb_busy = true;
 		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 		if (status) {
-			dbg("usb_submit_urb(read bulk) failed, status = %d",
+			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
 			    status);
 			mos7840_port->read_urb_busy = false;
 		}
@@ -2207,10 +2132,8 @@
 	unsigned int result = 0;
 
 	count = mos7840_chars_in_buffer(tty);
-	if (count == 0) {
-		dbg("%s -- Empty", __func__);
+	if (count == 0)
 		result = TIOCSER_TEMT;
-	}
 
 	if (copy_to_user(value, &result, sizeof(int)))
 		return -EFAULT;
@@ -2273,8 +2196,8 @@
 	icount->brk = cnow.brk;
 	icount->buf_overrun = cnow.buf_overrun;
 
-	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
-		port->number, icount->rx, icount->tx);
+	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
+		icount->rx, icount->tx);
 	return 0;
 }
 
@@ -2293,35 +2216,33 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 
-	if (mos7840_port_paranoia_check(port, __func__)) {
-		dbg("%s", "Invalid port");
+	if (mos7840_port_paranoia_check(port, __func__))
 		return -1;
-	}
 
 	mos7840_port = mos7840_get_port_private(port);
 
 	if (mos7840_port == NULL)
 		return -1;
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
 
 	switch (cmd) {
 		/* return number of bytes available */
 
 	case TIOCSERGETLSR:
-		dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
+		dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
 		return mos7840_get_lsr_info(tty, argp);
 
 	case TIOCGSERIAL:
-		dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
+		dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
 		return mos7840_get_serial_info(mos7840_port, argp);
 
 	case TIOCSSERIAL:
-		dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
+		dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
 		break;
 
 	case TIOCMIWAIT:
-		dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+		dev_dbg(&port->dev, "%s  TIOCMIWAIT\n", __func__);
 		cprev = mos7840_port->icount;
 		while (1) {
 			/* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
@@ -2437,11 +2358,6 @@
 	int i, status;
 	__u16 Data;
 
-	if (!serial) {
-		dbg("%s", "Invalid Handler");
-		return -1;
-	}
-
 	dev = serial->dev;
 
 	/* we set up the pointers to the endpoints in the mos7840_open *
@@ -2449,7 +2365,7 @@
 
 	/* set up port private structures */
 	for (i = 0; i < serial->num_ports; ++i) {
-		dbg ("mos7840_startup: configuring port %d............", i);
+		dev_dbg(&dev->dev, "mos7840_startup: configuring port %d............\n", i);
 		mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
 		if (mos7840_port == NULL) {
 			dev_err(&dev->dev, "%s - Out of memory\n", __func__);
@@ -2470,10 +2386,10 @@
 		 * usb-serial.c:get_free_serial() and cannot therefore be used
 		 * to index device instances */
 		mos7840_port->port_num = i + 1;
-		dbg ("serial->port[i]->number = %d", serial->port[i]->number);
-		dbg ("serial->port[i]->serial->minor = %d", serial->port[i]->serial->minor);
-		dbg ("mos7840_port->port_num = %d", mos7840_port->port_num);
-		dbg ("serial->minor = %d", serial->minor);
+		dev_dbg(&dev->dev, "serial->port[i]->number = %d\n", serial->port[i]->number);
+		dev_dbg(&dev->dev, "serial->port[i]->serial->minor = %d\n", serial->port[i]->serial->minor);
+		dev_dbg(&dev->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num);
+		dev_dbg(&dev->dev, "serial->minor = %d\n", serial->minor);
 
 		if (mos7840_port->port_num == 1) {
 			mos7840_port->SpRegOffset = 0x0;
@@ -2500,18 +2416,17 @@
 			mos7840_port->ControlRegOffset = 0xd;
 			mos7840_port->DcrRegOffset = 0x1c;
 		}
-		mos7840_dump_serial_port(mos7840_port);
+		mos7840_dump_serial_port(serial->port[i], mos7840_port);
 		mos7840_set_port_private(serial->port[i], mos7840_port);
 
 		/* enable rx_disable bit in control register */
 		status = mos7840_get_reg_sync(serial->port[i],
 				 mos7840_port->ControlRegOffset, &Data);
 		if (status < 0) {
-			dbg("Reading ControlReg failed status-0x%x", status);
+			dev_dbg(&dev->dev, "Reading ControlReg failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("ControlReg Reading success val is %x, status%d",
-			    Data, status);
+			dev_dbg(&dev->dev, "ControlReg Reading success val is %x, status%d\n", Data, status);
 		Data |= 0x08;	/* setting driver done bit */
 		Data |= 0x04;	/* sp1_bit to have cts change reflect in
 				   modem status reg */
@@ -2520,11 +2435,10 @@
 		status = mos7840_set_reg_sync(serial->port[i],
 					 mos7840_port->ControlRegOffset, Data);
 		if (status < 0) {
-			dbg("Writing ControlReg failed(rx_disable) status-0x%x", status);
+			dev_dbg(&dev->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status);
 			break;
 		} else
-			dbg("ControlReg Writing success(rx_disable) status%d",
-			    status);
+			dev_dbg(&dev->dev, "ControlReg Writing success(rx_disable) status%d\n", status);
 
 		/* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
 		   and 0x24 in DCR3 */
@@ -2532,61 +2446,57 @@
 		status = mos7840_set_reg_sync(serial->port[i],
 			 (__u16) (mos7840_port->DcrRegOffset + 0), Data);
 		if (status < 0) {
-			dbg("Writing DCR0 failed status-0x%x", status);
+			dev_dbg(&dev->dev, "Writing DCR0 failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("DCR0 Writing success status%d", status);
+			dev_dbg(&dev->dev, "DCR0 Writing success status%d\n", status);
 
 		Data = 0x05;
 		status = mos7840_set_reg_sync(serial->port[i],
 			 (__u16) (mos7840_port->DcrRegOffset + 1), Data);
 		if (status < 0) {
-			dbg("Writing DCR1 failed status-0x%x", status);
+			dev_dbg(&dev->dev, "Writing DCR1 failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("DCR1 Writing success status%d", status);
+			dev_dbg(&dev->dev, "DCR1 Writing success status%d\n", status);
 
 		Data = 0x24;
 		status = mos7840_set_reg_sync(serial->port[i],
 			 (__u16) (mos7840_port->DcrRegOffset + 2), Data);
 		if (status < 0) {
-			dbg("Writing DCR2 failed status-0x%x", status);
+			dev_dbg(&dev->dev, "Writing DCR2 failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("DCR2 Writing success status%d", status);
+			dev_dbg(&dev->dev, "DCR2 Writing success status%d\n", status);
 
 		/* write values in clkstart0x0 and clkmulti 0x20 */
 		Data = 0x0;
 		status = mos7840_set_reg_sync(serial->port[i],
 					 CLK_START_VALUE_REGISTER, Data);
 		if (status < 0) {
-			dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status);
+			dev_dbg(&dev->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("CLK_START_VALUE_REGISTER Writing success status%d", status);
+			dev_dbg(&dev->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status);
 
 		Data = 0x20;
 		status = mos7840_set_reg_sync(serial->port[i],
 					CLK_MULTI_REGISTER, Data);
 		if (status < 0) {
-			dbg("Writing CLK_MULTI_REGISTER failed status-0x%x",
-			    status);
+			dev_dbg(&dev->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status);
 			goto error;
 		} else
-			dbg("CLK_MULTI_REGISTER Writing success status%d",
-			    status);
+			dev_dbg(&dev->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status);
 
 		/* write value 0x0 to scratchpad register */
 		Data = 0x00;
 		status = mos7840_set_uart_reg(serial->port[i],
 						SCRATCH_PAD_REGISTER, Data);
 		if (status < 0) {
-			dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x",
-			    status);
+			dev_dbg(&dev->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
 			break;
 		} else
-			dbg("SCRATCH_PAD_REGISTER Writing success status%d",
-			    status);
+			dev_dbg(&dev->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status);
 
 		/* Zero Length flag register */
 		if ((mos7840_port->port_num != 1)
@@ -2596,31 +2506,25 @@
 			status = mos7840_set_reg_sync(serial->port[i],
 				      (__u16) (ZLP_REG1 +
 				      ((__u16)mos7840_port->port_num)), Data);
-			dbg("ZLIP offset %x",
-			    (__u16) (ZLP_REG1 +
-					((__u16) mos7840_port->port_num)));
+			dev_dbg(&dev->dev, "ZLIP offset %x\n",
+				(__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num)));
 			if (status < 0) {
-				dbg("Writing ZLP_REG%d failed status-0x%x",
-				    i + 2, status);
+				dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 2, status);
 				break;
 			} else
-				dbg("ZLP_REG%d Writing success status%d",
-				    i + 2, status);
+				dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 2, status);
 		} else {
 			Data = 0xff;
 			status = mos7840_set_reg_sync(serial->port[i],
 			      (__u16) (ZLP_REG1 +
 			      ((__u16)mos7840_port->port_num) - 0x1), Data);
-			dbg("ZLIP offset %x",
-			    (__u16) (ZLP_REG1 +
-				     ((__u16) mos7840_port->port_num) - 0x1));
+			dev_dbg(&dev->dev, "ZLIP offset %x\n",
+				(__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1));
 			if (status < 0) {
-				dbg("Writing ZLP_REG%d failed status-0x%x",
-				    i + 1, status);
+				dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 1, status);
 				break;
 			} else
-				dbg("ZLP_REG%d Writing success status%d",
-				    i + 1, status);
+				dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 1, status);
 
 		}
 		mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2661,16 +2565,15 @@
 						MODEM_CONTROL_REGISTER, 0x0300);
 		}
 	}
-	dbg ("mos7840_startup: all ports configured...........");
 
 	/* Zero Length flag enable */
 	Data = 0x0f;
 	status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
 	if (status < 0) {
-		dbg("Writing ZLP_REG5 failed status-0x%x", status);
+		dev_dbg(&dev->dev, "Writing ZLP_REG5 failed status-0x%x\n", status);
 		goto error;
 	} else
-		dbg("ZLP_REG5 Writing success status%d", status);
+		dev_dbg(&dev->dev, "ZLP_REG5 Writing success status%d\n", status);
 
 	/* setting configuration feature to one */
 	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -2700,11 +2603,6 @@
 	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
-	if (!serial) {
-		dbg("%s", "Invalid Handler");
-		return;
-	}
-
 	/* check for the ports to be closed,close the ports and disconnect */
 
 	/* free private structure allocated for serial port  *
@@ -2712,7 +2610,6 @@
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		mos7840_port = mos7840_get_port_private(serial->port[i]);
-		dbg ("mos7840_port %d = %p", i, mos7840_port);
 		if (mos7840_port) {
 			spin_lock_irqsave(&mos7840_port->pool_lock, flags);
 			mos7840_port->zombie = 1;
@@ -2732,11 +2629,6 @@
 	int i;
 	struct moschip_port *mos7840_port;
 
-	if (!serial) {
-		dbg("%s", "Invalid Handler");
-		return;
-	}
-
 	/* check for the ports to be closed,close the ports and disconnect */
 
 	/* free private structure allocated for serial port  *
@@ -2744,7 +2636,6 @@
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		mos7840_port = mos7840_get_port_private(serial->port[i]);
-		dbg("mos7840_port %d = %p", i, mos7840_port);
 		if (mos7840_port) {
 			if (mos7840_port->has_led) {
 				/* Turn off LED */
@@ -2801,6 +2692,3 @@
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index d95452c..1566f8f 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -21,8 +21,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x0a99, 0x0001) },	/* Talon Technology device */
 	{ USB_DEVICE(0x0df7, 0x0900) },	/* Mobile Action i-gotU */
@@ -55,8 +53,7 @@
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
-			      urb->actual_length, data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
@@ -123,6 +120,3 @@
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 6f3d705..6def58b 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -23,8 +23,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static bool debug;
-
 /*
  * Version Information
  */
@@ -164,31 +162,21 @@
 	struct omninet_header 	*header = (struct omninet_header *) &data[0];
 	int status = urb->status;
 	int result;
-	int i;
 
 	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n",
+			__func__, status);
 		return;
 	}
 
-	if (debug && header->oh_xxx != 0x30) {
-		if (urb->actual_length) {
-			printk(KERN_DEBUG "%s: omninet_read %d: ",
-			       __FILE__, header->oh_len);
-			for (i = 0; i < (header->oh_len +
-						OMNINET_HEADERLEN); i++)
-				printk("%.2x ", data[i]);
-			printk("\n");
-		}
-	}
-
 	if (urb->actual_length && header->oh_len) {
 		struct tty_struct *tty = tty_port_tty_get(&port->port);
-		tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+		if (tty) {
+			tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
 							header->oh_len);
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
+			tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
+		}
 	}
 
 	/* Continue trying to always read  */
@@ -212,12 +200,12 @@
 	int			result;
 
 	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
+		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
 	if (!test_and_clear_bit(0, &port->write_urbs_free)) {
-		dbg("%s - already writing", __func__);
+		dev_dbg(&port->dev, "%s - already writing\n", __func__);
 		return 0;
 	}
 
@@ -226,8 +214,8 @@
 	memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET,
 								buf, count);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-					wport->write_urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, count,
+			      wport->write_urb->transfer_buffer);
 
 	header->oh_seq 	= od->od_outseq++;
 	header->oh_len 	= count;
@@ -261,7 +249,7 @@
 	if (test_bit(0, &wport->write_urbs_free))
 		room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 
 	return room;
 }
@@ -275,8 +263,8 @@
 
 	set_bit(0, &port->write_urbs_free);
 	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n",
+			__func__, status);
 		return;
 	}
 
@@ -304,6 +292,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 02cb1b7..41b1647 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -32,8 +32,6 @@
  * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */
 #define DRIVER_DESC	"Opticon USB barcode to serial driver (1D)"
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x065a, 0x0009) },
 	{ },
@@ -78,17 +76,16 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+		dev_dbg(&priv->udev->dev, "%s - urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
+		dev_dbg(&priv->udev->dev, "%s - nonzero urb status received: %d\n",
+			__func__, status);
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length,
-			      data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	if (urb->actual_length > 2) {
 		data_length = urb->actual_length - 2;
@@ -229,8 +226,8 @@
 	kfree(urb->setup_packet);
 
 	if (status)
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&priv->udev->dev, "%s - nonzero write bulk status received: %d\n",
+			__func__, status);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	--priv->outstanding_urbs;
@@ -253,7 +250,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		dbg("%s - write limit hit", __func__);
+		dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
 		return 0;
 	}
 	priv->outstanding_urbs++;
@@ -276,7 +273,7 @@
 
 	memcpy(buffer, buf, count);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
+	usb_serial_debug_data(&port->dev, __func__, count, buffer);
 
 	/* The conncected devices do not have a bulk write endpoint,
 	 * to transmit data to de barcode device the control endpoint is used */
@@ -338,7 +335,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		dbg("%s - write limit hit", __func__);
+		dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
 		return 0;
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -394,7 +391,7 @@
 		result |= TIOCM_CTS;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - %x", __func__, result);
+	dev_dbg(&port->dev, "%s - %x\n", __func__, result);
 	return result;
 }
 
@@ -466,7 +463,7 @@
 	struct usb_serial_port *port = tty->driver_data;
 	struct opticon_private *priv = usb_get_serial_data(port->serial);
 
-	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -612,6 +609,3 @@
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5ce88d1..30cff03 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -870,7 +870,8 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
@@ -1257,8 +1258,6 @@
 	&option_1port_device, NULL
 };
 
-static bool debug;
-
 struct option_private {
 	u8 bInterfaceNumber;
 };
@@ -1369,18 +1368,19 @@
 {
 	int err;
 	int status = urb->status;
-	struct usb_serial_port *port =  urb->context;
+	struct usb_serial_port *port = urb->context;
+	struct device *dev = &port->dev;
 	struct usb_wwan_port_private *portdata =
 					usb_get_serial_port_data(port);
 
-	dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
+	dev_dbg(dev, "%s: urb %p port %p has data %p\n", __func__, urb, port, portdata);
 
 	if (status == 0) {
 		struct usb_ctrlrequest *req_pkt =
 				(struct usb_ctrlrequest *)urb->transfer_buffer;
 
 		if (!req_pkt) {
-			dbg("%s: NULL req_pkt", __func__);
+			dev_dbg(dev, "%s: NULL req_pkt\n", __func__);
 			return;
 		}
 		if ((req_pkt->bRequestType == 0xA1) &&
@@ -1390,7 +1390,7 @@
 					urb->transfer_buffer +
 					sizeof(struct usb_ctrlrequest));
 
-			dbg("%s: signal x%x", __func__, signals);
+			dev_dbg(dev, "%s: signal x%x\n", __func__, signals);
 
 			old_dcd_state = portdata->dcd_state;
 			portdata->cts_state = 1;
@@ -1406,17 +1406,17 @@
 				tty_kref_put(tty);
 			}
 		} else {
-			dbg("%s: type %x req %x", __func__,
+			dev_dbg(dev, "%s: type %x req %x\n", __func__,
 				req_pkt->bRequestType, req_pkt->bRequest);
 		}
 	} else
-		dev_err(&port->dev, "%s: error %d\n", __func__, status);
+		dev_err(dev, "%s: error %d\n", __func__, status);
 
 	/* Resubmit urb so we continue receiving IRQ data */
 	if (status != -ESHUTDOWN && status != -ENOENT) {
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err)
-			dbg("%s: resubmit intr urb failed. (%d)",
+			dev_dbg(dev, "%s: resubmit intr urb failed. (%d)\n",
 				__func__, err);
 	}
 }
@@ -1450,6 +1450,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 9f55556..933241f 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -66,8 +66,6 @@
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static bool debug;
-
 /* requests */
 #define	OTI6858_REQ_GET_STATUS		(USB_DIR_IN | USB_TYPE_VENDOR | 0x00)
 #define	OTI6858_REQ_T_GET_STATUS	0x01
@@ -256,11 +254,11 @@
 	priv->setup_done = 1;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s(): submitting interrupt urb", __func__);
+	dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result != 0) {
-		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
-				" with error %d\n", __func__, result);
+		dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n",
+			__func__, result);
 	}
 }
 
@@ -310,11 +308,11 @@
 	if (count == 0) {
 		priv->flags.write_urb_in_use = 0;
 
-		dbg("%s(): submitting interrupt urb", __func__);
+		dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__);
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
 		if (result != 0) {
-			dev_err(&port->dev, "%s(): usb_submit_urb() failed"
-				" with error %d\n", __func__, result);
+			dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n",
+				__func__, result);
 		}
 		return;
 	}
@@ -325,8 +323,8 @@
 	port->write_urb->transfer_buffer_length = count;
 	result = usb_submit_urb(port->write_urb, GFP_NOIO);
 	if (result != 0) {
-		dev_err_console(port, "%s(): usb_submit_urb() failed"
-			       " with error %d\n", __func__, result);
+		dev_err_console(port, "%s(): usb_submit_urb() failed with error %d\n",
+				__func__, result);
 		priv->flags.write_urb_in_use = 0;
 	}
 
@@ -420,10 +418,8 @@
 	__le16 divisor;
 	int br;
 
-	if (!tty) {
-		dbg("%s(): no tty structures", __func__);
+	if (!tty)
 		return;
-	}
 
 	cflag = tty->termios.c_cflag;
 
@@ -560,11 +556,11 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 	kfree(buf);
 
-	dbg("%s(): submitting interrupt urb", __func__);
+	dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result != 0) {
-		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
-			       " with error %d\n", __func__, result);
+		dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n",
+			__func__, result);
 		oti6858_close(port);
 		return result;
 	}
@@ -586,14 +582,14 @@
 	kfifo_reset_out(&port->write_fifo);
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	dbg("%s(): after buf_clear()", __func__);
+	dev_dbg(&port->dev, "%s(): after buf_clear()\n", __func__);
 
 	/* cancel scheduled setup */
 	cancel_delayed_work_sync(&priv->delayed_setup_work);
 	cancel_delayed_work_sync(&priv->delayed_write_work);
 
 	/* shutdown our urbs */
-	dbg("%s(): shutting down urbs", __func__);
+	dev_dbg(&port->dev, "%s(): shutting down urbs\n", __func__);
 	usb_kill_urb(port->write_urb);
 	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->interrupt_in_urb);
@@ -607,8 +603,8 @@
 	unsigned long flags;
 	u8 control;
 
-	dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
-				__func__, port->number, set, clear);
+	dev_dbg(&port->dev, "%s(set = 0x%08x, clear = 0x%08x)\n",
+		__func__, set, clear);
 
 	/* FIXME: check if this is correct (active high/low) */
 	spin_lock_irqsave(&priv->lock, flags);
@@ -655,7 +651,7 @@
 	if ((pin_state & PIN_DCD) != 0)
 		result |= TIOCM_CD;
 
-	dbg("%s() = 0x%08x", __func__, result);
+	dev_dbg(&port->dev, "%s() = 0x%08x\n", __func__, result);
 
 	return result;
 }
@@ -700,15 +696,14 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)",
-				__func__, port->number, cmd, arg);
+	dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg);
 
 	switch (cmd) {
 	case TIOCMIWAIT:
-		dbg("%s(): TIOCMIWAIT", __func__);
+		dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__);
 		return wait_modem_info(port, arg);
 	default:
-		dbg("%s(): 0x%04x not supported", __func__, cmd);
+		dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd);
 		break;
 	}
 	return -ENOIOCTLCMD;
@@ -738,12 +733,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s(): urb shutting down with status: %d",
-					__func__, status);
+		dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n",
+			__func__, status);
 		return;
 	default:
-		dbg("%s(): nonzero urb status received: %d",
-					__func__, status);
+		dev_dbg(&urb->dev->dev, "%s(): nonzero urb status received: %d\n",
+			__func__, status);
 		break;
 	}
 
@@ -759,8 +754,7 @@
 					priv->transient = 4;
 					priv->setup_done = 0;
 					resubmit = 0;
-					dbg("%s(): scheduling setup_line()",
-					    __func__);
+					dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__);
 					schedule_delayed_work(&priv->delayed_setup_work, 0);
 				}
 			}
@@ -774,8 +768,7 @@
 					priv->transient = 4;
 					priv->setup_done = 0;
 					resubmit = 0;
-					dbg("%s(): scheduling setup_line()",
-					    __func__);
+					dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__);
 					schedule_delayed_work(&priv->delayed_setup_work, 0);
 				}
 			}
@@ -826,7 +819,7 @@
 	if (resubmit) {
 		int result;
 
-/*		dbg("%s(): submitting interrupt urb", __func__); */
+/*		dev_dbg(&urb->dev->dev, "%s(): submitting interrupt urb\n", __func__); */
 		result = usb_submit_urb(urb, GFP_ATOMIC);
 		if (result != 0) {
 			dev_err(&urb->dev->dev,
@@ -851,7 +844,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (status != 0) {
-		dbg("%s(): unable to handle the error, exiting", __func__);
+		dev_dbg(&urb->dev->dev, "%s(): unable to handle the error, exiting\n", __func__);
 		return;
 	}
 
@@ -885,15 +878,13 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s(): urb shutting down with status: %d",
-					__func__, status);
+		dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", __func__, status);
 		priv->flags.write_urb_in_use = 0;
 		return;
 	default:
 		/* error in the urb, so we have to resubmit it */
-		dbg("%s(): nonzero write bulk status received: %d",
-					__func__, status);
-		dbg("%s(): overflow in write", __func__);
+		dev_dbg(&urb->dev->dev, "%s(): nonzero write bulk status received: %d\n", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s(): overflow in write\n", __func__);
 
 		port->write_urb->transfer_buffer_length = 1;
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -908,7 +899,7 @@
 	priv->flags.write_urb_in_use = 0;
 
 	/* schedule the interrupt urb if we are still open */
-	dbg("%s(): submitting interrupt urb", __func__);
+	dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result != 0) {
 		dev_err(&port->dev, "%s(): failed submitting int urb,"
@@ -922,7 +913,3 @@
 MODULE_AUTHOR(OTI6858_AUTHOR);
 MODULE_VERSION(OTI6858_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "enable debug output");
-
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 2b9108a..892ebdc7 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -36,8 +36,6 @@
  */
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -741,7 +739,7 @@
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__,
+	usb_serial_debug_data(&port->dev, __func__,
 			      urb->actual_length, urb->transfer_buffer);
 
 	pl2303_update_line_status(port, data, actual_length);
@@ -839,7 +837,3 @@
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index a4edc7e..9b1b96f 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -36,8 +36,6 @@
 #define UTSTARCOM_PRODUCT_UM175_V1		0x3712
 #define UTSTARCOM_PRODUCT_UM175_V2		0x3714
 #define UTSTARCOM_PRODUCT_UM175_ALLTEL		0x3715
-#define PANTECH_PRODUCT_UML190_VZW		0x3716
-#define PANTECH_PRODUCT_UML290_VZW		0x3718
 
 /* CMOTECH devices */
 #define CMOTECH_VENDOR_ID			0x16d8
@@ -68,11 +66,9 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) },  /* NMEA */
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) },  /* WMC */
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },  /* DIAG */
+	{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) },  /* NMEA */
+	{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) },  /* WMC */
+	{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) },  /* DIAG */
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index bfd5077..c3ddb65 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -22,8 +22,6 @@
 #define DRIVER_AUTHOR "Qualcomm Inc"
 #define DRIVER_DESC "Qualcomm USB Serial driver"
 
-static bool debug;
-
 #define DEVICE_G1K(v, p) \
 	USB_DEVICE(v, p), .driver_info = 1
 
@@ -305,6 +303,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL v2");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 7df9cdb..2cdfdcc 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -27,8 +27,6 @@
 #include <linux/serial_reg.h>
 #include <linux/uaccess.h>
 
-static bool debug;
-
 /* default urb timeout for usb operations */
 #define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
 
@@ -1089,7 +1087,7 @@
 	data = write_urb->transfer_buffer;
 	spin_lock_irqsave(&port_priv->urb_lock, flags);
 	if (port_priv->urb_in_use == true) {
-		printk(KERN_INFO "qt2_write - urb is in use\n");
+		dev_err(&port->dev, "qt2_write - urb is in use\n");
 		goto write_out;
 	}
 
@@ -1146,6 +1144,3 @@
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 36e9d9f..c949ce6 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -62,6 +62,7 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -81,11 +82,9 @@
 #define CONFIG_USB_SERIAL_SAFE_PADDED 0
 #endif
 
-static bool debug;
 static bool safe = 1;
 static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED;
 
-#define DRIVER_VERSION "v0.1"
 #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB Safe Encapsulated Serial"
 
@@ -100,9 +99,6 @@
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 module_param(safe, bool, 0);
 MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
 
@@ -315,13 +311,9 @@
 {
 	int i;
 
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
 	/* if we have vendor / product parameters patch them into id list */
 	if (vendor || product) {
-		printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n",
-		       vendor, product);
+		pr_info("vendor: %x product: %x\n", vendor, product);
 
 		for (i = 0; i < ARRAY_SIZE(id_table); i++) {
 			if (!id_table[i].idVendor && !id_table[i].idProduct) {
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index b14ebbd..01d882c 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -46,7 +46,6 @@
    allocations > PAGE_SIZE and the number of packets in a page
    is an integer 512 is the largest possible packet on EHCI */
 
-static bool debug;
 static bool nmea;
 
 /* Used in interface blacklisting */
@@ -518,7 +517,7 @@
 
 	memcpy(buffer, buf, writesize);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer);
+	usb_serial_debug_data(&port->dev, __func__, writesize, buffer);
 
 	usb_fill_bulk_urb(urb, serial->dev,
 			  usb_sndbulkpipe(serial->dev,
@@ -595,8 +594,8 @@
 				tty_flip_buffer_push(tty);
 
 				tty_kref_put(tty);
-				usb_serial_debug_data(debug, &port->dev,
-					__func__, urb->actual_length, data);
+				usb_serial_debug_data(&port->dev, __func__,
+						      urb->actual_length, data);
 			}
 		} else {
 			dev_dbg(&port->dev, "%s: empty read urb"
@@ -765,7 +764,6 @@
 			usb_sndbulkpipe(serial->dev, endpoint) | dir,
 			buf, len, callback, ctx);
 
-		/* debug */
 		dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,
 				dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
 	} else {
@@ -1082,6 +1080,3 @@
 
 module_param(nmea, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(nmea, "NMEA streaming");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index ab68a4d..9716efe 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -33,8 +33,6 @@
 #define DRIVER_VERSION	"v0.10"
 #define DRIVER_DESC 	"SPCP8x5 USB to serial adaptor driver"
 
-static bool debug;
-
 #define SPCP8x5_007_VID		0x04FC
 #define SPCP8x5_007_PID		0x0201
 #define SPCP8x5_008_VID		0x04fc
@@ -665,6 +663,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index cf2d30c..015810b 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -46,8 +46,6 @@
 #define FULLPWRBIT          0x00000080
 #define NEXT_BOARD_POWER_BIT        0x00000004
 
-static bool debug;
-
 /* Version Information */
 #define DRIVER_VERSION "v0.1"
 #define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver"
@@ -135,7 +133,7 @@
 	int result;
 
 	if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
-		dbg("%s - DTR|RTS not being set|cleared", __func__);
+		dev_dbg(&dev->dev, "%s - DTR|RTS not being set|cleared\n", __func__);
 		return 0;	/* no change */
 	}
 
@@ -148,7 +146,7 @@
 
 	result = ssu100_setregister(dev, 0, UART_MCR, urb_value);
 	if (result < 0)
-		dbg("%s Error from MODEM_CTRL urb", __func__);
+		dev_dbg(&dev->dev, "%s Error from MODEM_CTRL urb\n", __func__);
 
 	return result;
 }
@@ -164,7 +162,7 @@
 
 	result = ssu100_getdevice(dev, data);
 	if (result < 0) {
-		dbg("%s - get_device failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result);
 		goto out;
 	}
 
@@ -172,25 +170,25 @@
 
 	result = ssu100_setdevice(dev, data);
 	if (result < 0) {
-		dbg("%s - setdevice failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result);
 		goto out;
 	}
 
 	result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0);
 	if (result < 0) {
-		dbg("%s - set prebuffer level failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - set prebuffer level failed %i\n", __func__, result);
 		goto out;
 	}
 
 	result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0);
 	if (result < 0) {
-		dbg("%s - set ATFprebuffer level failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - set ATFprebuffer level failed %i\n", __func__, result);
 		goto out;
 	}
 
 	result = ssu100_getdevice(dev, data);
 	if (result < 0) {
-		dbg("%s - get_device failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result);
 		goto out;
 	}
 
@@ -201,7 +199,7 @@
 
 	result = ssu100_setdevice(dev, data);
 	if (result < 0) {
-		dbg("%s - setdevice failed %i", __func__, result);
+		dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result);
 		goto out;
 	}
 
@@ -249,7 +247,7 @@
 	if (!baud)
 		baud = 9600;
 
-	dbg("%s - got baud = %d\n", __func__, baud);
+	dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud);
 
 
 	divisor = MAX_BAUD_RATE / baud;
@@ -261,7 +259,7 @@
 
 	result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value);
 	if (result < 0)
-		dbg("%s - set uart failed", __func__);
+		dev_dbg(&port->dev, "%s - set uart failed\n", __func__);
 
 	if (cflag & CRTSCTS)
 		result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
@@ -270,7 +268,7 @@
 		result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
 					    0, 0);
 	if (result < 0)
-		dbg("%s - set HW flow control failed", __func__);
+		dev_dbg(&port->dev, "%s - set HW flow control failed\n", __func__);
 
 	if (I_IXOFF(tty) || I_IXON(tty)) {
 		u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty)));
@@ -282,7 +280,7 @@
 					    0, 0);
 
 	if (result < 0)
-		dbg("%s - set SW flow control failed", __func__);
+		dev_dbg(&port->dev, "%s - set SW flow control failed\n", __func__);
 
 }
 
@@ -304,7 +302,7 @@
 				 QT_TRANSFER_IN, 0x01,
 				 0, data, 2, 300);
 	if (result < 0) {
-		dbg("%s - open failed %i", __func__, result);
+		dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result);
 		kfree(data);
 		return result;
 	}
@@ -319,7 +317,7 @@
 /* set to 9600 */
 	result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300);
 	if (result < 0)
-		dbg("%s - set uart failed", __func__);
+		dev_dbg(&port->dev, "%s - set uart failed\n", __func__);
 
 	if (tty)
 		ssu100_set_termios(tty, port, &tty->termios);
@@ -423,7 +421,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s cmd 0x%04x", __func__, cmd);
+	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -437,7 +435,7 @@
 		break;
 	}
 
-	dbg("%s arg not supported", __func__);
+	dev_dbg(&port->dev, "%s arg not supported\n", __func__);
 
 	return -ENOIOCTLCMD;
 }
@@ -668,6 +666,3 @@
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index e53d2aa..701fffa8 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -20,8 +20,6 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static bool debug;
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x05e0, 0x0600) },
 	{ },
@@ -71,8 +69,7 @@
 		goto exit;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length,
-			      data);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
 
 	if (urb->actual_length > 1) {
 		data_length = urb->actual_length - 1;
@@ -292,6 +289,3 @@
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index f502a16..6f49392 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -40,7 +40,6 @@
 
 /* Defines */
 
-#define TI_DRIVER_VERSION	"v0.10"
 #define TI_DRIVER_AUTHOR	"Al Borchers <alborchers@steinerpoint.com>"
 #define TI_DRIVER_DESC		"TI USB 3410/5052 Serial Driver"
 
@@ -141,8 +140,8 @@
 static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
 	__u16 moduleid, __u16 value, __u8 *data, int size);
 
-static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
-	__u8 mask, __u8 byte);
+static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev,
+			 unsigned long addr, __u8 mask, __u8 byte);
 
 static int ti_download_firmware(struct ti_device *tdev);
 
@@ -150,7 +149,6 @@
 /* Data */
 
 /* module parameters */
-static bool debug;
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
 static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
 static unsigned int vendor_3410_count;
@@ -277,7 +275,6 @@
 
 MODULE_AUTHOR(TI_DRIVER_AUTHOR);
 MODULE_DESCRIPTION(TI_DRIVER_DESC);
-MODULE_VERSION(TI_DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
 MODULE_FIRMWARE("ti_3410.fw");
@@ -288,9 +285,6 @@
 MODULE_FIRMWARE("mts_mt9234mu.fw");
 MODULE_FIRMWARE("mts_mt9234zba.fw");
 
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes");
-
 module_param(closing_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(closing_wait,
     "Maximum wait for data to drain in close, in .01 secs, default is 4000");
@@ -316,7 +310,6 @@
 static int __init ti_init(void)
 {
 	int i, j, c;
-	int ret;
 
 	/* insert extra vendor and product ids */
 	c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
@@ -339,11 +332,7 @@
 		ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 	}
 
-	ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
-	if (ret == 0)
-		printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
-			       TI_DRIVER_DESC "\n");
-	return ret;
+	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
 }
 
 static void __exit ti_exit(void)
@@ -364,10 +353,11 @@
 	int i;
 
 
-	dbg("%s - product 0x%4X, num configurations %d, configuration value %d",
-	    __func__, le16_to_cpu(dev->descriptor.idProduct),
-	    dev->descriptor.bNumConfigurations,
-	    dev->actconfig->desc.bConfigurationValue);
+	dev_dbg(&dev->dev,
+		"%s - product 0x%4X, num configurations %d, configuration value %d",
+		__func__, le16_to_cpu(dev->descriptor.idProduct),
+		dev->descriptor.bNumConfigurations,
+		dev->actconfig->desc.bConfigurationValue);
 
 	/* create device structure */
 	tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
@@ -382,8 +372,8 @@
 	/* determine device type */
 	if (usb_match_id(serial->interface, ti_id_table_3410))
 		tdev->td_is_3410 = 1;
-	dbg("%s - device type is %s", __func__,
-				tdev->td_is_3410 ? "3410" : "5052");
+	dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
+		tdev->td_is_3410 ? "3410" : "5052");
 
 	/* if we have only 1 configuration, download firmware */
 	if (dev->descriptor.bNumConfigurations == 1) {
@@ -501,20 +491,17 @@
 
 	/* start interrupt urb the first time a port is opened on this device */
 	if (tdev->td_open_port_count == 0) {
-		dbg("%s - start interrupt in urb", __func__);
+		dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__);
 		urb = tdev->td_serial->port[0]->interrupt_in_urb;
 		if (!urb) {
-			dev_err(&port->dev, "%s - no interrupt urb\n",
-								__func__);
+			dev_err(&port->dev, "%s - no interrupt urb\n", __func__);
 			status = -EINVAL;
 			goto release_lock;
 		}
 		urb->context = tdev;
 		status = usb_submit_urb(urb, GFP_KERNEL);
 		if (status) {
-			dev_err(&port->dev,
-				"%s - submit interrupt urb failed, %d\n",
-					__func__, status);
+			dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __func__, status);
 			goto release_lock;
 		}
 	}
@@ -522,16 +509,16 @@
 	if (tty)
 		ti_set_termios(tty, port, &tty->termios);
 
-	dbg("%s - sending TI_OPEN_PORT", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT\n", __func__);
 	status = ti_command_out_sync(tdev, TI_OPEN_PORT,
 		(__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
 	if (status) {
 		dev_err(&port->dev, "%s - cannot send open command, %d\n",
-							__func__, status);
+			__func__, status);
 		goto unlink_int_urb;
 	}
 
-	dbg("%s - sending TI_START_PORT", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_START_PORT\n", __func__);
 	status = ti_command_out_sync(tdev, TI_START_PORT,
 		(__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
 	if (status) {
@@ -540,7 +527,7 @@
 		goto unlink_int_urb;
 	}
 
-	dbg("%s - sending TI_PURGE_PORT", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_PURGE_PORT\n", __func__);
 	status = ti_command_out_sync(tdev, TI_PURGE_PORT,
 		(__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0);
 	if (status) {
@@ -564,7 +551,7 @@
 	if (tty)
 		ti_set_termios(tty, port, &tty->termios);
 
-	dbg("%s - sending TI_OPEN_PORT (2)", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT (2)\n", __func__);
 	status = ti_command_out_sync(tdev, TI_OPEN_PORT,
 		(__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
 	if (status) {
@@ -573,7 +560,7 @@
 		goto unlink_int_urb;
 	}
 
-	dbg("%s - sending TI_START_PORT (2)", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_START_PORT (2)\n", __func__);
 	status = ti_command_out_sync(tdev, TI_START_PORT,
 		(__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
 	if (status) {
@@ -583,7 +570,7 @@
 	}
 
 	/* start read urb */
-	dbg("%s - start read urb", __func__);
+	dev_dbg(&port->dev, "%s - start read urb\n", __func__);
 	urb = port->read_urb;
 	if (!urb) {
 		dev_err(&port->dev, "%s - no read urb\n", __func__);
@@ -609,7 +596,7 @@
 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
 release_lock:
 	mutex_unlock(&tdev->td_open_close_lock);
-	dbg("%s - exit %d", __func__, status);
+	dev_dbg(&port->dev, "%s - exit %d\n", __func__, status);
 	return status;
 }
 
@@ -637,7 +624,7 @@
 
 	port_number = port->number - port->serial->minor;
 
-	dbg("%s - sending TI_CLOSE_PORT", __func__);
+	dev_dbg(&port->dev, "%s - sending TI_CLOSE_PORT\n", __func__);
 	status = ti_command_out_sync(tdev, TI_CLOSE_PORT,
 		     (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
 	if (status)
@@ -664,7 +651,7 @@
 	struct ti_port *tport = usb_get_serial_port_data(port);
 
 	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
+		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
 		return 0;
 	}
 
@@ -693,7 +680,7 @@
 	room = kfifo_avail(&tport->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
-	dbg("%s - returns %d", __func__, room);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
 	return room;
 }
 
@@ -712,7 +699,7 @@
 	chars = kfifo_len(&tport->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
-	dbg("%s - returns %d", __func__, chars);
+	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
 	return chars;
 }
 
@@ -755,8 +742,7 @@
 	struct ti_port *tport = usb_get_serial_port_data(port);
 	struct async_icount cnow = tport->tp_icount;
 
-	dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d",
-		__func__, port->number,
+	dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__,
 		cnow.rx, cnow.tx);
 
 	icount->cts = cnow.cts;
@@ -782,22 +768,22 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 
-	dbg("%s - port %d, cmd = 0x%04X", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd);
 
 	if (tport == NULL)
 		return -ENODEV;
 
 	switch (cmd) {
 	case TIOCGSERIAL:
-		dbg("%s - (%d) TIOCGSERIAL", __func__, port->number);
+		dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
 		return ti_get_serial_info(tport,
 				(struct serial_struct __user *)arg);
 	case TIOCSSERIAL:
-		dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
+		dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);
 		return ti_set_serial_info(tty, tport,
 				(struct serial_struct __user *)arg);
 	case TIOCMIWAIT:
-		dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
+		dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
 		cprev = tport->tp_icount;
 		while (1) {
 			interruptible_sleep_on(&tport->tp_msr_wait);
@@ -834,9 +820,9 @@
 	cflag = tty->termios.c_cflag;
 	iflag = tty->termios.c_iflag;
 
-	dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
-	dbg("%s - old clfag %08x, old iflag %08x", __func__,
-				old_termios->c_cflag, old_termios->c_iflag);
+	dev_dbg(&port->dev, "%s - cflag %08x, iflag %08x\n", __func__, cflag, iflag);
+	dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__,
+		old_termios->c_cflag, old_termios->c_iflag);
 
 	if (tport == NULL)
 		return;
@@ -926,8 +912,11 @@
 	if ((cflag & CBAUD) != B0)
 		tty_encode_baud_rate(tty, baud, baud);
 
-	dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
-	__func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
+	dev_dbg(&port->dev,
+		"%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
+		__func__, baud, config->wBaudRate, config->wFlags,
+		config->bDataBits, config->bParity, config->bStopBits,
+		config->cXon, config->cXoff, config->bUartMode);
 
 	cpu_to_be16s(&config->wBaudRate);
 	cpu_to_be16s(&config->wFlags);
@@ -979,7 +968,7 @@
 		| ((msr & TI_MSR_RI) ? TIOCM_RI : 0)
 		| ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0);
 
-	dbg("%s - 0x%04X", __func__, result);
+	dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
 
 	return result;
 }
@@ -1024,19 +1013,19 @@
 	struct ti_port *tport = usb_get_serial_port_data(port);
 	int status;
 
-	dbg("%s - state = %d", __func__, break_state);
+	dev_dbg(&port->dev, "%s - state = %d\n", __func__, break_state);
 
 	if (tport == NULL)
 		return;
 
 	ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0);
 
-	status = ti_write_byte(tport->tp_tdev,
+	status = ti_write_byte(port, tport->tp_tdev,
 		tport->tp_uart_base_addr + TI_UART_OFFSET_LCR,
 		TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0);
 
 	if (status)
-		dbg("%s - error setting break, %d", __func__, status);
+		dev_dbg(&port->dev, "%s - error setting break, %d\n", __func__, status);
 }
 
 
@@ -1061,18 +1050,17 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
-		dbg("%s - urb shutting down, %d", __func__, status);
+		dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
 		tdev->td_urb_error = 1;
 		return;
 	default:
-		dev_err(dev, "%s - nonzero urb status, %d\n",
-			__func__, status);
+		dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status);
 		tdev->td_urb_error = 1;
 		goto exit;
 	}
 
 	if (length != 2) {
-		dbg("%s - bad packet size, %d", __func__, length);
+		dev_dbg(dev, "%s - bad packet size, %d\n", __func__, length);
 		goto exit;
 	}
 
@@ -1084,8 +1072,8 @@
 	port_number = TI_GET_PORT_FROM_CODE(data[0]);
 	function = TI_GET_FUNC_FROM_CODE(data[0]);
 
-	dbg("%s - port_number %d, function %d, data 0x%02X",
-				__func__, port_number, function, data[1]);
+	dev_dbg(dev, "%s - port_number %d, function %d, data 0x%02X\n",
+		__func__, port_number, function, data[1]);
 
 	if (port_number >= serial->num_ports) {
 		dev_err(dev, "%s - bad port number, %d\n",
@@ -1102,12 +1090,12 @@
 	switch (function) {
 	case TI_CODE_DATA_ERROR:
 		dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n",
-					__func__, port_number, data[1]);
+			__func__, port_number, data[1]);
 		break;
 
 	case TI_CODE_MODEM_STATUS:
 		msr = data[1];
-		dbg("%s - port %d, msr 0x%02X", __func__, port_number, msr);
+		dev_dbg(dev, "%s - port %d, msr 0x%02X\n", __func__, port_number, msr);
 		ti_handle_new_msr(tport, msr);
 		break;
 
@@ -1140,7 +1128,7 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
-		dbg("%s - urb shutting down, %d", __func__, status);
+		dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
 		tport->tp_tdev->td_urb_error = 1;
 		wake_up_interruptible(&tport->tp_write_wait);
 		return;
@@ -1162,11 +1150,11 @@
 	tty = tty_port_tty_get(&port->port);
 	if (tty) {
 		if (urb->actual_length) {
-			usb_serial_debug_data(debug, dev, __func__,
-				urb->actual_length, urb->transfer_buffer);
+			usb_serial_debug_data(dev, __func__, urb->actual_length,
+					      urb->transfer_buffer);
 
 			if (!tport->tp_is_open)
-				dbg("%s - port closed, dropping data",
+				dev_dbg(dev, "%s - port closed, dropping data\n",
 					__func__);
 			else
 				ti_recv(&urb->dev->dev, tty,
@@ -1208,7 +1196,7 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
-		dbg("%s - urb shutting down, %d", __func__, status);
+		dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status);
 		tport->tp_tdev->td_urb_error = 1;
 		wake_up_interruptible(&tport->tp_write_wait);
 		return;
@@ -1268,8 +1256,8 @@
 
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-					port->write_urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, count,
+			      port->write_urb->transfer_buffer);
 
 	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
 			   usb_sndbulkpipe(port->serial->dev,
@@ -1307,7 +1295,7 @@
 	unsigned long flags;
 	int status;
 
-	status = ti_write_byte(tport->tp_tdev,
+	status = ti_write_byte(tport->tp_port, tport->tp_tdev,
 		tport->tp_uart_base_addr + TI_UART_OFFSET_MCR,
 		TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr);
 
@@ -1344,7 +1332,7 @@
 		goto free_data;
 	}
 
-	dbg("%s - lsr 0x%02X", __func__, data->bLSR);
+	dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR);
 
 	tport->tp_lsr = data->bLSR;
 
@@ -1401,7 +1389,7 @@
 	struct tty_struct *tty;
 	unsigned long flags;
 
-	dbg("%s - msr 0x%02X", __func__, msr);
+	dev_dbg(&tport->tp_port->dev, "%s - msr 0x%02X\n", __func__, msr);
 
 	if (msr & TI_MSR_DELTA_MASK) {
 		spin_lock_irqsave(&tport->tp_lock, flags);
@@ -1560,21 +1548,21 @@
 }
 
 
-static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
-	__u8 mask, __u8 byte)
+static int ti_write_byte(struct usb_serial_port *port,
+			struct ti_device *tdev, unsigned long addr,
+			__u8 mask, __u8 byte)
 {
 	int status;
 	unsigned int size;
 	struct ti_write_data_bytes *data;
-	struct device *dev = &tdev->td_serial->dev->dev;
 
-	dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X",
-					__func__, addr, mask, byte);
+	dev_dbg(&port->dev, "%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X\n", __func__,
+		addr, mask, byte);
 
 	size = sizeof(struct ti_write_data_bytes) + 2;
 	data = kmalloc(size, GFP_KERNEL);
 	if (!data) {
-		dev_err(dev, "%s - out of memory\n", __func__);
+		dev_err(&port->dev, "%s - out of memory\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -1590,7 +1578,7 @@
 		(__u8 *)data, size);
 
 	if (status < 0)
-		dev_err(dev, "%s - failed, %d\n", __func__, status);
+		dev_err(&port->dev, "%s - failed, %d\n", __func__, status);
 
 	kfree(data);
 
@@ -1615,7 +1603,7 @@
 					- sizeof(struct ti_firmware_header)));
 	header->bCheckSum = cs;
 
-	dbg("%s - downloading firmware", __func__);
+	dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
 	for (pos = 0; pos < size; pos += done) {
 		len = min(size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
 		status = usb_bulk_msg(dev, pipe, buffer + pos, len,
@@ -1691,7 +1679,7 @@
 		status = ti_do_download(dev, pipe, buffer, fw_p->size);
 		kfree(buffer);
 	} else {
-		dbg("%s ENOMEM\n", __func__);
+		dev_dbg(&dev->dev, "%s ENOMEM\n", __func__);
 		status = -ENOMEM;
 	}
 	release_firmware(fw_p);
@@ -1701,7 +1689,7 @@
 		return status;
 	}
 
-	dbg("%s - download successful", __func__);
+	dev_dbg(&dev->dev, "%s - download successful\n", __func__);
 
 	return 0;
 }
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index aa4b0d7..73b8e05 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -37,10 +39,7 @@
 #include <linux/kfifo.h>
 #include "pl2303.h"
 
-/*
- * Version Information
- */
-#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
 #define DRIVER_DESC "USB Serial Driver core"
 
 /* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead
@@ -50,7 +49,6 @@
    drivers depend on it.
 */
 
-static bool debug;
 /* initially all NULL */
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
 static DEFINE_MUTEX(table_lock);
@@ -87,7 +85,7 @@
 	unsigned int i, j;
 	int good_spot;
 
-	dbg("%s %d", __func__, num_ports);
+	dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports);
 
 	*minor = 0;
 	mutex_lock(&table_lock);
@@ -107,7 +105,7 @@
 
 		*minor = i;
 		j = 0;
-		dbg("%s - minor base = %d", __func__, *minor);
+		dev_dbg(&serial->interface->dev, "%s - minor base = %d\n", __func__, *minor);
 		for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
 			serial_table[i] = serial;
 			serial->port[j++]->number = i;
@@ -123,8 +121,6 @@
 {
 	int i;
 
-	dbg("%s", __func__);
-
 	mutex_lock(&table_lock);
 	for (i = 0; i < serial->num_ports; ++i)
 		serial_table[serial->minor + i] = NULL;
@@ -139,8 +135,6 @@
 
 	serial = to_usb_serial(kref);
 
-	dbg("%s - %s", __func__, serial->type->description);
-
 	/* return the minor range that this device had */
 	if (serial->minor != SERIAL_TTY_NO_MINOR)
 		return_serial(serial);
@@ -191,8 +185,6 @@
 	struct usb_serial_port *port;
 	int retval = -ENODEV;
 
-	dbg("%s", __func__);
-
 	serial = usb_serial_get_by_index(idx);
 	if (!serial)
 		return retval;
@@ -256,7 +248,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 	return tty_port_open(&port->port, tty, filp);
 }
 
@@ -287,14 +279,16 @@
 static void serial_hangup(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 	tty_port_hangup(&port->port);
 }
 
 static void serial_close(struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 	tty_port_close(&port->port, tty, filp);
 }
 
@@ -319,7 +313,7 @@
 	if (port->port.console)
 		return;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	tty->driver_data = NULL;
 
@@ -344,7 +338,8 @@
 	if (port->serial->dev->state == USB_STATE_NOTATTACHED)
 		goto exit;
 
-	dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
+	dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__,
+		port->number, count);
 
 	/* pass on to the driver specific version of this function */
 	retval = port->serial->type->write(tty, port, buf, count);
@@ -357,7 +352,8 @@
 static int serial_write_room(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 	/* pass on to the driver specific version of this function */
 	return port->serial->type->write_room(tty);
 }
@@ -365,7 +361,8 @@
 static int serial_chars_in_buffer(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	/* if the device was unplugged then any remaining characters
 	   fell out of the connector ;) */
@@ -378,7 +375,8 @@
 static void serial_throttle(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	/* pass on to the driver specific version of this function */
 	if (port->serial->type->throttle)
@@ -388,7 +386,8 @@
 static void serial_unthrottle(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	/* pass on to the driver specific version of this function */
 	if (port->serial->type->unthrottle)
@@ -401,7 +400,8 @@
 	struct usb_serial_port *port = tty->driver_data;
 	int retval = -ENODEV;
 
-	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
+	dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__,
+		port->number, cmd);
 
 	/* pass on to the driver specific version of this function
 	   if it is available */
@@ -415,7 +415,8 @@
 static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
+
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	/* pass on to the driver specific version of this function
 	   if it is available */
@@ -429,7 +430,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	/* pass on to the driver specific version of this function
 	   if it is available */
@@ -444,7 +445,6 @@
 	int i;
 	char tmp[40];
 
-	dbg("%s", __func__);
 	seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial = usb_serial_get_by_index(i);
@@ -489,7 +489,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	if (port->serial->type->tiocmget)
 		return port->serial->type->tiocmget(tty);
@@ -501,7 +501,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	if (port->serial->type->tiocmset)
 		return port->serial->type->tiocmset(tty, set, clear);
@@ -513,7 +513,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s - port %d", __func__, port->number);
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
 
 	if (port->serial->type->get_icount)
 		return port->serial->type->get_icount(tty, icount);
@@ -537,12 +537,12 @@
 		container_of(work, struct usb_serial_port, work);
 	struct tty_struct *tty;
 
-	dbg("%s - port %d", __func__, port->number);
-
 	tty = tty_port_tty_get(&port->port);
 	if (!tty)
 		return;
 
+	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+
 	tty_wakeup(tty);
 	tty_kref_put(tty);
 }
@@ -575,7 +575,7 @@
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	int i;
 
-	dbg ("%s - %s", __func__, dev_name(dev));
+	dev_dbg(dev, "%s\n", __func__);
 
 	/*
 	 * Stop all the traffic before cancelling the work, so that
@@ -644,12 +644,12 @@
 
 	id = usb_match_id(intf, drv->id_table);
 	if (id) {
-		dbg("static descriptor matches");
+		dev_dbg(&intf->dev, "static descriptor matches\n");
 		goto exit;
 	}
 	id = match_dynamic_id(intf, drv);
 	if (id)
-		dbg("dynamic descriptor matches");
+		dev_dbg(&intf->dev, "dynamic descriptor matches\n");
 exit:
 	return id;
 }
@@ -703,6 +703,7 @@
 static int usb_serial_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
+	struct device *ddev = &interface->dev;
 	struct usb_device *dev = interface_to_usbdev(interface);
 	struct usb_serial *serial = NULL;
 	struct usb_serial_port *port;
@@ -729,13 +730,13 @@
 	type = search_serial_device(interface);
 	if (!type) {
 		mutex_unlock(&table_lock);
-		dbg("none matched");
+		dev_dbg(ddev, "none matched\n");
 		return -ENODEV;
 	}
 
 	if (!try_module_get(type->driver.owner)) {
 		mutex_unlock(&table_lock);
-		dev_err(&interface->dev, "module get failed, exiting\n");
+		dev_err(ddev, "module get failed, exiting\n");
 		return -EIO;
 	}
 	mutex_unlock(&table_lock);
@@ -743,7 +744,7 @@
 	serial = create_serial(dev, interface, type);
 	if (!serial) {
 		module_put(type->driver.owner);
-		dev_err(&interface->dev, "%s - out of memory\n", __func__);
+		dev_err(ddev, "%s - out of memory\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -755,7 +756,7 @@
 		retval = type->probe(serial, id);
 
 		if (retval) {
-			dbg("sub driver rejected device");
+			dev_dbg(ddev, "sub driver rejected device\n");
 			usb_serial_put(serial);
 			module_put(type->driver.owner);
 			return retval;
@@ -770,28 +771,28 @@
 
 		if (usb_endpoint_is_bulk_in(endpoint)) {
 			/* we found a bulk in endpoint */
-			dbg("found bulk in on endpoint %d", i);
+			dev_dbg(ddev, "found bulk in on endpoint %d\n", i);
 			bulk_in_endpoint[num_bulk_in] = endpoint;
 			++num_bulk_in;
 		}
 
 		if (usb_endpoint_is_bulk_out(endpoint)) {
 			/* we found a bulk out endpoint */
-			dbg("found bulk out on endpoint %d", i);
+			dev_dbg(ddev, "found bulk out on endpoint %d\n", i);
 			bulk_out_endpoint[num_bulk_out] = endpoint;
 			++num_bulk_out;
 		}
 
 		if (usb_endpoint_is_int_in(endpoint)) {
 			/* we found a interrupt in endpoint */
-			dbg("found interrupt in on endpoint %d", i);
+			dev_dbg(ddev, "found interrupt in on endpoint %d\n", i);
 			interrupt_in_endpoint[num_interrupt_in] = endpoint;
 			++num_interrupt_in;
 		}
 
 		if (usb_endpoint_is_int_out(endpoint)) {
 			/* we found an interrupt out endpoint */
-			dbg("found interrupt out on endpoint %d", i);
+			dev_dbg(ddev, "found interrupt out on endpoint %d\n", i);
 			interrupt_out_endpoint[num_interrupt_out] = endpoint;
 			++num_interrupt_out;
 		}
@@ -815,7 +816,7 @@
 				endpoint = &iface_desc->endpoint[i].desc;
 				if (usb_endpoint_is_int_in(endpoint)) {
 					/* we found a interrupt in endpoint */
-					dbg("found interrupt in for Prolific device on separate interface");
+					dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n");
 					interrupt_in_endpoint[num_interrupt_in] = endpoint;
 					++num_interrupt_in;
 				}
@@ -827,7 +828,7 @@
 		 * properly during a later invocation of usb_serial_probe
 		 */
 		if (num_bulk_in == 0 || num_bulk_out == 0) {
-			dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
+			dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n");
 			usb_serial_put(serial);
 			module_put(type->driver.owner);
 			return -ENODEV;
@@ -840,14 +841,13 @@
 	if (type == &usb_serial_generic_device) {
 		num_ports = num_bulk_out;
 		if (num_ports == 0) {
-			dev_err(&interface->dev,
-			    "Generic device with no bulk out, not allowed.\n");
+			dev_err(ddev, "Generic device with no bulk out, not allowed.\n");
 			usb_serial_put(serial);
 			module_put(type->driver.owner);
 			return -EIO;
 		}
-		dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
-		dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
+		dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
+		dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
 	}
 #endif
 	if (!num_ports) {
@@ -865,8 +865,7 @@
 	serial->num_interrupt_out = num_interrupt_out;
 
 	/* found all that we need */
-	dev_info(&interface->dev, "%s converter detected\n",
-			type->description);
+	dev_info(ddev, "%s converter detected\n", type->description);
 
 	/* create our ports, we need as many as the max endpoints */
 	/* we don't use num_ports here because some devices have more
@@ -877,8 +876,7 @@
 	max_endpoints = max(max_endpoints, (int)serial->num_ports);
 	serial->num_port_pointers = max_endpoints;
 
-	dbg("%s - setting up %d port structures for this device",
-						__func__, max_endpoints);
+	dev_dbg(ddev, "setting up %d port structures for this device", max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
 		if (!port)
@@ -911,15 +909,13 @@
 			set_bit(j, &port->read_urbs_free);
 			port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
 			if (!port->read_urbs[j]) {
-				dev_err(&interface->dev,
-						"No free urbs available\n");
+				dev_err(ddev, "No free urbs available\n");
 				goto probe_error;
 			}
 			port->bulk_in_buffers[j] = kmalloc(buffer_size,
 								GFP_KERNEL);
 			if (!port->bulk_in_buffers[j]) {
-				dev_err(&interface->dev,
-					"Couldn't allocate bulk_in_buffer\n");
+				dev_err(ddev, "Couldn't allocate bulk_in_buffer\n");
 				goto probe_error;
 			}
 			usb_fill_bulk_urb(port->read_urbs[j], dev,
@@ -949,15 +945,13 @@
 			set_bit(j, &port->write_urbs_free);
 			port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
 			if (!port->write_urbs[j]) {
-				dev_err(&interface->dev,
-						"No free urbs available\n");
+				dev_err(ddev, "No free urbs available\n");
 				goto probe_error;
 			}
 			port->bulk_out_buffers[j] = kmalloc(buffer_size,
 								GFP_KERNEL);
 			if (!port->bulk_out_buffers[j]) {
-				dev_err(&interface->dev,
-					"Couldn't allocate bulk_out_buffer\n");
+				dev_err(ddev, "Couldn't allocate bulk_out_buffer\n");
 				goto probe_error;
 			}
 			usb_fill_bulk_urb(port->write_urbs[j], dev,
@@ -978,8 +972,7 @@
 			port = serial->port[i];
 			port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
 			if (!port->interrupt_in_urb) {
-				dev_err(&interface->dev,
-						"No free urbs available\n");
+				dev_err(ddev, "No free urbs available\n");
 				goto probe_error;
 			}
 			buffer_size = usb_endpoint_maxp(endpoint);
@@ -988,8 +981,7 @@
 			port->interrupt_in_buffer = kmalloc(buffer_size,
 								GFP_KERNEL);
 			if (!port->interrupt_in_buffer) {
-				dev_err(&interface->dev,
-				    "Couldn't allocate interrupt_in_buffer\n");
+				dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n");
 				goto probe_error;
 			}
 			usb_fill_int_urb(port->interrupt_in_urb, dev,
@@ -1000,7 +992,7 @@
 				endpoint->bInterval);
 		}
 	} else if (num_interrupt_in) {
-		dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
+		dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n");
 	}
 
 	if (serial->type->write_int_callback) {
@@ -1009,8 +1001,7 @@
 			port = serial->port[i];
 			port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
 			if (!port->interrupt_out_urb) {
-				dev_err(&interface->dev,
-						"No free urbs available\n");
+				dev_err(ddev, "No free urbs available\n");
 				goto probe_error;
 			}
 			buffer_size = usb_endpoint_maxp(endpoint);
@@ -1020,8 +1011,7 @@
 			port->interrupt_out_buffer = kmalloc(buffer_size,
 								GFP_KERNEL);
 			if (!port->interrupt_out_buffer) {
-				dev_err(&interface->dev,
-				  "Couldn't allocate interrupt_out_buffer\n");
+				dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n");
 				goto probe_error;
 			}
 			usb_fill_int_urb(port->interrupt_out_urb, dev,
@@ -1032,7 +1022,7 @@
 				endpoint->bInterval);
 		}
 	} else if (num_interrupt_out) {
-		dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
+		dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n");
 	}
 
 	usb_set_intfdata(interface, serial);
@@ -1060,7 +1050,7 @@
 	serial->disconnected = 1;
 
 	if (get_free_serial(serial, num_ports, &minor) == NULL) {
-		dev_err(&interface->dev, "No more free serial devices\n");
+		dev_err(ddev, "No more free serial devices\n");
 		goto probe_error;
 	}
 	serial->minor = minor;
@@ -1069,18 +1059,17 @@
 	for (i = 0; i < num_ports; ++i) {
 		port = serial->port[i];
 		dev_set_name(&port->dev, "ttyUSB%d", port->number);
-		dbg ("%s - registering %s", __func__, dev_name(&port->dev));
+		dev_dbg(ddev, "registering %s", dev_name(&port->dev));
 		device_enable_async_suspend(&port->dev);
 
 		retval = device_add(&port->dev);
 		if (retval)
-			dev_err(&port->dev, "Error registering port device, "
-				"continuing\n");
+			dev_err(ddev, "Error registering port device, continuing\n");
 	}
 
 	serial->disconnected = 0;
 
-	usb_serial_console_init(debug, minor);
+	usb_serial_console_init(minor);
 exit:
 	module_put(type->driver.owner);
 	return 0;
@@ -1099,7 +1088,6 @@
 	struct usb_serial_port *port;
 
 	usb_serial_console_disconnect(serial);
-	dbg("%s", __func__);
 
 	mutex_lock(&serial->disc_mutex);
 	/* must set a flag, to signal subdrivers */
@@ -1234,8 +1222,7 @@
 
 	result = bus_register(&usb_serial_bus_type);
 	if (result) {
-		printk(KERN_ERR "usb-serial: %s - registering bus driver "
-		       "failed\n", __func__);
+		pr_err("%s - registering bus driver failed\n", __func__);
 		goto exit_bus;
 	}
 
@@ -1255,29 +1242,24 @@
 	tty_set_operations(usb_serial_tty_driver, &serial_ops);
 	result = tty_register_driver(usb_serial_tty_driver);
 	if (result) {
-		printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
-		       __func__);
+		pr_err("%s - tty_register_driver failed\n", __func__);
 		goto exit_reg_driver;
 	}
 
 	/* register the USB driver */
 	result = usb_register(&usb_serial_driver);
 	if (result < 0) {
-		printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
-		       __func__);
+		pr_err("%s - usb_register failed\n", __func__);
 		goto exit_tty;
 	}
 
 	/* register the generic driver, if we should */
-	result = usb_serial_generic_register(debug);
+	result = usb_serial_generic_register();
 	if (result < 0) {
-		printk(KERN_ERR "usb-serial: %s - registering generic "
-		       "driver failed\n", __func__);
+		pr_err("%s - registering generic driver failed\n", __func__);
 		goto exit_generic;
 	}
 
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-
 	return result;
 
 exit_generic:
@@ -1290,8 +1272,7 @@
 	bus_unregister(&usb_serial_bus_type);
 
 exit_bus:
-	printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
-	       __func__, result);
+	pr_err("%s - returning with error %d\n", __func__, result);
 	put_tty_driver(usb_serial_tty_driver);
 	return result;
 }
@@ -1317,7 +1298,7 @@
 	do {								\
 		if (!type->function) {					\
 			type->function = usb_serial_generic_##function;	\
-			dbg("Had to override the " #function		\
+			pr_debug("Had to override the " #function	\
 				" usb serial operation with the generic one.");\
 			}						\
 	} while (0)
@@ -1360,12 +1341,10 @@
 
 	retval = usb_serial_bus_register(driver);
 	if (retval) {
-		printk(KERN_ERR "usb-serial: problem %d when registering "
-		       "driver %s\n", retval, driver->description);
+		pr_err("problem %d when registering driver %s\n", retval, driver->description);
 		list_del(&driver->driver_list);
 	} else
-		printk(KERN_INFO "USB Serial support registered for %s\n",
-						driver->description);
+		pr_info("USB Serial support registered for %s\n", driver->description);
 
 	mutex_unlock(&table_lock);
 	return retval;
@@ -1373,8 +1352,7 @@
 
 static void usb_serial_deregister(struct usb_serial_driver *device)
 {
-	printk(KERN_INFO "USB Serial deregistering driver %s\n",
-	       device->description);
+	pr_info("USB Serial deregistering driver %s\n", device->description);
 	mutex_lock(&table_lock);
 	list_del(&device->driver_list);
 	usb_serial_bus_deregister(device);
@@ -1425,9 +1403,10 @@
 
 	/* we only set the reset_resume field if the serial_driver has one */
 	for (sd = serial_drivers; *sd; ++sd) {
-		if ((*sd)->reset_resume)
+		if ((*sd)->reset_resume) {
 			udriver->reset_resume = usb_serial_reset_resume;
 			break;
+		}
 	}
 
 	rc = usb_register(udriver);
@@ -1477,6 +1456,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 72b678d..e42aa39 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -37,8 +37,6 @@
 #include <linux/serial.h>
 #include "usb-wwan.h"
 
-static bool debug;
-
 void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
 {
 	struct usb_serial *serial = port->serial;
@@ -178,7 +176,7 @@
 {
 	struct usb_serial_port *port = tty->driver_data;
 
-	dbg("%s cmd 0x%04x", __func__, cmd);
+	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -191,7 +189,7 @@
 		break;
 	}
 
-	dbg("%s arg not supported", __func__);
+	dev_dbg(&port->dev, "%s arg not supported\n", __func__);
 
 	return -ENOIOCTLCMD;
 }
@@ -212,7 +210,7 @@
 	portdata = usb_get_serial_port_data(port);
 	intfdata = port->serial->private;
 
-	dbg("%s: write (%d chars)", __func__, count);
+	dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
 
 	i = 0;
 	left = count;
@@ -229,8 +227,8 @@
 			usb_unlink_urb(this_urb);
 			continue;
 		}
-		dbg("%s: endpoint %d buf %d", __func__,
-		    usb_pipeendpoint(this_urb->pipe), i);
+		dev_dbg(&port->dev, "%s: endpoint %d buf %d\n", __func__,
+			usb_pipeendpoint(this_urb->pipe), i);
 
 		err = usb_autopm_get_interface_async(port->serial->interface);
 		if (err < 0)
@@ -249,8 +247,9 @@
 			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
 			err = usb_submit_urb(this_urb, GFP_ATOMIC);
 			if (err) {
-				dbg("usb_submit_urb %p (write bulk) failed "
-				    "(%d)", this_urb, err);
+				dev_dbg(&port->dev,
+					"usb_submit_urb %p (write bulk) failed (%d)\n",
+					this_urb, err);
 				clear_bit(i, &portdata->out_busy);
 				spin_lock_irqsave(&intfdata->susp_lock, flags);
 				intfdata->in_flight--;
@@ -267,7 +266,7 @@
 	}
 
 	count -= left;
-	dbg("%s: wrote (did %d)", __func__, count);
+	dev_dbg(&port->dev, "%s: wrote (did %d)\n", __func__, count);
 	return count;
 }
 EXPORT_SYMBOL(usb_wwan_write);
@@ -278,15 +277,17 @@
 	int endpoint;
 	struct usb_serial_port *port;
 	struct tty_struct *tty;
+	struct device *dev;
 	unsigned char *data = urb->transfer_buffer;
 	int status = urb->status;
 
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
+	dev = &port->dev;
 
 	if (status) {
-		dbg("%s: nonzero status: %d on endpoint %02x.",
-		    __func__, status, endpoint);
+		dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n",
+			__func__, status, endpoint);
 	} else {
 		tty = tty_port_tty_get(&port->port);
 		if (tty) {
@@ -295,7 +296,7 @@
 						urb->actual_length);
 				tty_flip_buffer_push(tty);
 			} else
-				dbg("%s: empty read urb received", __func__);
+				dev_dbg(dev, "%s: empty read urb received\n", __func__);
 			tty_kref_put(tty);
 		}
 
@@ -303,8 +304,7 @@
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err) {
 			if (err != -EPERM) {
-				printk(KERN_ERR "%s: resubmit read urb failed. "
-					"(%d)", __func__, err);
+				dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err);
 				/* busy also in error unless we are killed */
 				usb_mark_last_busy(port->serial->dev);
 			}
@@ -356,7 +356,7 @@
 			data_len += OUT_BUFLEN;
 	}
 
-	dbg("%s: %d", __func__, data_len);
+	dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
 	return data_len;
 }
 EXPORT_SYMBOL(usb_wwan_write_room);
@@ -378,7 +378,7 @@
 		if (this_urb && test_bit(i, &portdata->out_busy))
 			data_len += this_urb->transfer_buffer_length;
 	}
-	dbg("%s: %d", __func__, data_len);
+	dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
 	return data_len;
 }
 EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
@@ -401,8 +401,8 @@
 			continue;
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
-			dbg("%s: submit urb %d failed (%d) %d",
-			    __func__, i, err, urb->transfer_buffer_length);
+			dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n",
+				__func__, i, err, urb->transfer_buffer_length);
 		}
 	}
 
@@ -458,7 +458,9 @@
 
 	urb = usb_alloc_urb(0, GFP_KERNEL);	/* No ISO */
 	if (urb == NULL) {
-		dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
+		dev_dbg(&serial->interface->dev,
+			"%s: alloc for endpoint %d failed.\n", __func__,
+			endpoint);
 		return NULL;
 	}
 
@@ -522,8 +524,8 @@
 		port = serial->port[i];
 		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
 		if (!portdata) {
-			dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
-			    __func__, i);
+			dev_dbg(&port->dev, "%s: kmalloc for usb_wwan_port_private (%d) failed!.\n",
+				__func__, i);
 			return 1;
 		}
 		init_usb_anchor(&portdata->delayed);
@@ -548,7 +550,8 @@
 			continue;
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (err)
-			dbg("%s: submit irq_in urb failed %d", __func__, err);
+			dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
+				__func__, err);
 	}
 	usb_wwan_setup_urbs(serial);
 	return 0;
@@ -683,11 +686,11 @@
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		if (!port->interrupt_in_urb) {
-			dbg("%s: No interrupt URB for port %d", __func__, i);
+			dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
 			continue;
 		}
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
-		dbg("Submitted interrupt URB for port %d (result %d)", i, err);
+		dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
 		if (err < 0) {
 			dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
 				__func__, err);
@@ -733,6 +736,3 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index f253c91..1129aa7 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -51,9 +51,6 @@
 static int palm_os_4_probe(struct usb_serial *serial,
 					const struct usb_device_id *id);
 
-/* Parameters that may be passed into the module. */
-static bool debug;
-
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_3_probe },
@@ -310,8 +307,8 @@
 	 * Rumor has it this endpoint is used to notify when data
 	 * is ready to be read from the bulk ones.
 	 */
-	usb_serial_debug_data(debug, &port->dev, __func__,
-			      urb->actual_length, urb->transfer_buffer);
+	usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+			      urb->transfer_buffer);
 
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
@@ -443,8 +440,7 @@
 		dev_err(dev, "%s - error %d getting connection info\n",
 			__func__, retval);
 	else
-		usb_serial_debug_data(debug, &serial->dev->dev, __func__,
-				      retval, transfer_buffer);
+		usb_serial_debug_data(dev, __func__, retval, transfer_buffer);
 
 	kfree(transfer_buffer);
 	return 0;
@@ -625,6 +621,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index b36077d..346c7ef 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -32,12 +32,9 @@
 #include <linux/serial_reg.h>
 #include <linux/serial.h>
 #include <linux/usb/serial.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
+#include <linux/usb/ezusb.h>
 #include "whiteheat.h"			/* WhiteHEAT specific commands */
 
-static bool debug;
-
 #ifndef CMSPAR
 #define CMSPAR 0
 #endif
@@ -195,84 +192,15 @@
 static int whiteheat_firmware_download(struct usb_serial *serial,
 					const struct usb_device_id *id)
 {
-	int response, ret = -ENOENT;
-	const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
-	const struct ihex_binrec *record;
+	int response;
 
-	if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
-				  &serial->dev->dev)) {
-		dev_err(&serial->dev->dev,
-			"%s - request \"whiteheat.fw\" failed\n", __func__);
-		goto out;
+	response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat_loader.fw");
+	if (response >= 0) {
+		response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat.fw");
+		if (response >= 0)
+			return 0;
 	}
-	if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw",
-			     &serial->dev->dev)) {
-		dev_err(&serial->dev->dev,
-			"%s - request \"whiteheat_loader.fw\" failed\n",
-			__func__);
-		goto out;
-	}
-	ret = 0;
-	response = ezusb_set_reset (serial, 1);
-
-	record = (const struct ihex_binrec *)loader_fw->data;
-	while (record) {
-		response = ezusb_writememory (serial, be32_to_cpu(record->addr),
-					      (unsigned char *)record->data,
-					      be16_to_cpu(record->len), 0xa0);
-		if (response < 0) {
-			dev_err(&serial->dev->dev, "%s - ezusb_writememory "
-				"failed for loader (%d %04X %p %d)\n",
-				__func__, response, be32_to_cpu(record->addr),
-				record->data, be16_to_cpu(record->len));
-			break;
-		}
-		record = ihex_next_binrec(record);
-	}
-
-	response = ezusb_set_reset(serial, 0);
-
-	record = (const struct ihex_binrec *)firmware_fw->data;
-	while (record && be32_to_cpu(record->addr) < 0x1b40)
-		record = ihex_next_binrec(record);
-	while (record) {
-		response = ezusb_writememory (serial, be32_to_cpu(record->addr),
-					      (unsigned char *)record->data,
-					      be16_to_cpu(record->len), 0xa3);
-		if (response < 0) {
-			dev_err(&serial->dev->dev, "%s - ezusb_writememory "
-				"failed for first firmware step "
-				"(%d %04X %p %d)\n", __func__, response,
-				be32_to_cpu(record->addr), record->data,
-				be16_to_cpu(record->len));
-			break;
-		}
-		++record;
-	}
-
-	response = ezusb_set_reset(serial, 1);
-
-	record = (const struct ihex_binrec *)firmware_fw->data;
-	while (record && be32_to_cpu(record->addr) < 0x1b40) {
-		response = ezusb_writememory (serial, be32_to_cpu(record->addr),
-					      (unsigned char *)record->data,
-					      be16_to_cpu(record->len), 0xa0);
-		if (response < 0) {
-			dev_err(&serial->dev->dev, "%s - ezusb_writememory "
-				"failed for second firmware step "
-				"(%d %04X %p %d)\n", __func__, response,
-				be32_to_cpu(record->addr), record->data,
-				be16_to_cpu(record->len));
-			break;
-		}
-		++record;
-	}
-	ret = 0;
-	response = ezusb_set_reset (serial, 0);
- out:
-	release_firmware(loader_fw);
-	release_firmware(firmware_fw);
-	return ret;
+	return -ENOENT;
 }
 
 
@@ -533,7 +461,7 @@
 	struct serial_struct serstruct;
 	void __user *user_arg = (void __user *)arg;
 
-	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
+	dev_dbg(&port->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCGSERIAL:
@@ -580,7 +508,7 @@
 	int status = urb->status;
 
 	if (status) {
-		dbg("nonzero urb status: %d", status);
+		dev_dbg(&urb->dev->dev, "nonzero urb status: %d\n", status);
 		return;
 	}
 }
@@ -596,19 +524,18 @@
 
 	command_info = usb_get_serial_port_data(command_port);
 	if (!command_info) {
-		dbg("%s - command_info is NULL, exiting.", __func__);
+		dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__);
 		return;
 	}
 	if (status) {
-		dbg("%s - nonzero urb status: %d", __func__, status);
+		dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status);
 		if (status != -ENOENT)
 			command_info->command_finished = WHITEHEAT_CMD_FAILURE;
 		wake_up(&command_info->wait_command);
 		return;
 	}
 
-	usb_serial_debug_data(debug, &command_port->dev,
-				__func__, urb->actual_length, data);
+	usb_serial_debug_data(&command_port->dev, __func__, urb->actual_length, data);
 
 	if (data[0] == WHITEHEAT_CMD_COMPLETE) {
 		command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
@@ -619,19 +546,19 @@
 	} else if (data[0] == WHITEHEAT_EVENT) {
 		/* These are unsolicited reports from the firmware, hence no
 		   waiting command to wakeup */
-		dbg("%s - event received", __func__);
+		dev_dbg(&urb->dev->dev, "%s - event received\n", __func__);
 	} else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
 		memcpy(command_info->result_buffer, &data[1],
 						urb->actual_length - 1);
 		command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
 		wake_up(&command_info->wait_command);
 	} else
-		dbg("%s - bad reply from firmware", __func__);
+		dev_dbg(&urb->dev->dev, "%s - bad reply from firmware\n", __func__);
 
 	/* Continue trying to always read */
 	result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
 	if (result)
-		dbg("%s - failed resubmitting read urb, error %d",
+		dev_dbg(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n",
 			__func__, result);
 }
 
@@ -645,11 +572,12 @@
 	struct usb_serial_port *command_port;
 	struct whiteheat_command_private *command_info;
 	struct whiteheat_private *info;
+	struct device *dev = &port->dev;
 	__u8 *transfer_buffer;
 	int retval = 0;
 	int t;
 
-	dbg("%s - command %d", __func__, command);
+	dev_dbg(dev, "%s - command %d\n", __func__, command);
 
 	command_port = port->serial->port[COMMAND_PORT];
 	command_info = usb_get_serial_port_data(command_port);
@@ -662,7 +590,7 @@
 	command_port->write_urb->transfer_buffer_length = datasize + 1;
 	retval = usb_submit_urb(command_port->write_urb, GFP_NOIO);
 	if (retval) {
-		dbg("%s - submit urb failed", __func__);
+		dev_dbg(dev, "%s - submit urb failed\n", __func__);
 		goto exit;
 	}
 
@@ -673,19 +601,19 @@
 		usb_kill_urb(command_port->write_urb);
 
 	if (command_info->command_finished == false) {
-		dbg("%s - command timed out.", __func__);
+		dev_dbg(dev, "%s - command timed out.\n", __func__);
 		retval = -ETIMEDOUT;
 		goto exit;
 	}
 
 	if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) {
-		dbg("%s - command failed.", __func__);
+		dev_dbg(dev, "%s - command failed.\n", __func__);
 		retval = -EIO;
 		goto exit;
 	}
 
 	if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) {
-		dbg("%s - command completed.", __func__);
+		dev_dbg(dev, "%s - command completed.\n", __func__);
 		switch (command) {
 		case WHITEHEAT_GET_DTR_RTS:
 			info = usb_get_serial_port_data(port);
@@ -723,6 +651,7 @@
 static void firm_setup_port(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct device *dev = &port->dev;
 	struct whiteheat_port_settings port_settings;
 	unsigned int cflag = tty->termios.c_cflag;
 
@@ -736,7 +665,7 @@
 	default:
 	case CS8:	port_settings.bits = 8;   break;
 	}
-	dbg("%s - data bits = %d", __func__, port_settings.bits);
+	dev_dbg(dev, "%s - data bits = %d\n", __func__, port_settings.bits);
 
 	/* determine the parity */
 	if (cflag & PARENB)
@@ -752,14 +681,14 @@
 				port_settings.parity = WHITEHEAT_PAR_EVEN;
 	else
 		port_settings.parity = WHITEHEAT_PAR_NONE;
-	dbg("%s - parity = %c", __func__, port_settings.parity);
+	dev_dbg(dev, "%s - parity = %c\n", __func__, port_settings.parity);
 
 	/* figure out the stop bits requested */
 	if (cflag & CSTOPB)
 		port_settings.stop = 2;
 	else
 		port_settings.stop = 1;
-	dbg("%s - stop bits = %d", __func__, port_settings.stop);
+	dev_dbg(dev, "%s - stop bits = %d\n", __func__, port_settings.stop);
 
 	/* figure out the flow control settings */
 	if (cflag & CRTSCTS)
@@ -767,7 +696,7 @@
 						WHITEHEAT_HFLOW_RTS);
 	else
 		port_settings.hflow = WHITEHEAT_HFLOW_NONE;
-	dbg("%s - hardware flow control = %s %s %s %s", __func__,
+	dev_dbg(dev, "%s - hardware flow control = %s %s %s %s\n", __func__,
 	    (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "",
 	    (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "",
 	    (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "",
@@ -778,16 +707,15 @@
 		port_settings.sflow = WHITEHEAT_SFLOW_RXTX;
 	else
 		port_settings.sflow = WHITEHEAT_SFLOW_NONE;
-	dbg("%s - software flow control = %c", __func__, port_settings.sflow);
+	dev_dbg(dev, "%s - software flow control = %c\n", __func__, port_settings.sflow);
 
 	port_settings.xon = START_CHAR(tty);
 	port_settings.xoff = STOP_CHAR(tty);
-	dbg("%s - XON = %2x, XOFF = %2x",
-			__func__, port_settings.xon, port_settings.xoff);
+	dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff);
 
 	/* get the baud rate wanted */
 	port_settings.baud = tty_get_baud_rate(tty);
-	dbg("%s - baud rate = %d", __func__, port_settings.baud);
+	dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud);
 
 	/* fixme: should set validated settings */
 	tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud);
@@ -918,6 +846,3 @@
 
 MODULE_FIRMWARE("whiteheat.fw");
 MODULE_FIRMWARE("whiteheat_loader.fw");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c
new file mode 100644
index 0000000..39ee737
--- /dev/null
+++ b/drivers/usb/serial/zte_ev.c
@@ -0,0 +1,307 @@
+/*
+ * ZTE_EV USB serial driver
+ *
+ * Copyright (C) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (C) 2012 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on code found in a ZTE_ENV patch that modified
+ * the usb-serial generic driver.  Comments were left in that I think
+ * show the commands used to talk to the device, but I am not sure.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+#define  MAX_SETUP_DATA_SIZE	32
+
+static void debug_data(struct device *dev, const char *function, int len,
+		       const unsigned char *data, int result)
+{
+	dev_dbg(dev, "result = %d\n", result);
+	if (result == len)
+		dev_dbg(dev, "%s - length = %d, data = %*ph\n", function,
+			len, len, data);
+}
+
+static int zte_ev_usb_serial_open(struct tty_struct *tty,
+				  struct usb_serial_port *port)
+{
+	struct usb_device *udev = port->serial->dev;
+	struct device *dev = &port->dev;
+	int result = 0;
+	int len;
+	unsigned char *buf;
+
+	if (port->number != 0)
+		return -ENODEV;
+
+	buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* send 1st ctl cmd(CTL    21 22 01 00  00 00 00 00) */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0001, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	/* send  2st cmd and recieve data */
+	/*
+	 * 16.0  CTL    a1 21 00 00  00 00 07 00   CLASS              25.1.0(5)
+	 * 16.0  DI     00 96 00 00  00 00 08
+	 */
+	len = 0x0007;
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				 0x21, 0xa1,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 3 cmd */
+	/*
+	 * 16.0 CTL    21 20 00 00  00 00 07 00    CLASS                30.1.0
+	 * 16.0 DO     80 25 00 00  00 00 08       .%.....              30.2.0
+	 */
+	len = 0x0007;
+	buf[0] = 0x80;
+	buf[1] = 0x25;
+	buf[2] = 0x00;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+	buf[5] = 0x00;
+	buf[6] = 0x08;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x20, 0x21,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 4 cmd */
+	/*
+	 * 16.0 CTL    21 22 03 00  00 00 00 00
+	 */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0003, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	/* send 5 cmd */
+	/*
+	 * 16.0  CTL    a1 21 00 00  00 00 07 00   CLASS               33.1.0
+	 * 16.0  DI     80 25 00 00  00 00 08
+	 */
+	len = 0x0007;
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				 0x21, 0xa1,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 6 cmd */
+	/*
+	 * 16.0  CTL    21 20 00 00  00 00 07 00    CLASS               34.1.0
+	 * 16.0  DO     80 25 00 00  00 00 08
+	 */
+	len = 0x0007;
+	buf[0] = 0x80;
+	buf[1] = 0x25;
+	buf[2] = 0x00;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+	buf[5] = 0x00;
+	buf[6] = 0x08;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x20, 0x21,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+	kfree(buf);
+
+	return usb_serial_generic_open(tty, port);
+}
+
+/*
+ *       CTL    21 22 02 00  00 00 00 00         CLASS               338.1.0
+ *
+ * 16.1  DI     a1 20 00 00  00 00 02 00  02 00  . ........          340.1.0
+ * 16.0  CTL    21 22 03 00  00 00 00 00         CLASS               341.1.0
+ *
+ * 16.0  CTL    a1 21 00 00  00 00 07 00         CLASS               346.1.0(3)
+ * 16.0  DI     00 08 07 00  00 00 08            .......             346.2.0
+ *
+ * 16.0  CTL    21 20 00 00  00 00 07 00         CLASS               349.1.0
+ * 16.0  DO     00 c2 01 00  00 00 08            .......             349.2.0
+ *
+ * 16.0  CTL    21 22 03 00  00 00 00 00         CLASS               350.1.0(2)
+ *
+ * 16.0  CTL    a1 21 00 00  00 00 07 00         CLASS               352.1.0
+ * 16.0  DI     00 c2 01 00  00 00 08            .......             352.2.0
+ *
+ * 16.1  DI     a1 20 00 00  00 00 02 00  02 00  . ........          353.1.0
+ *
+ * 16.0  CTL    21 20 00 00  00 00 07 00         CLASS               354.1.0
+ * 16.0  DO     00 c2 01 00  00 00 08            .......             354.2.0
+ *
+ * 16.0  CTL    21 22 03 00  00 00 00 00
+*/
+
+static void zte_ev_usb_serial_close(struct usb_serial_port *port)
+{
+	struct usb_device *udev = port->serial->dev;
+	struct device *dev = &port->dev;
+	int result = 0;
+	int len;
+	unsigned char *buf;
+
+	if (port->number != 0)
+		return;
+
+	buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	/* send 1st ctl cmd(CTL    21 22 02 00  00 00 00 00) */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0002, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	/* send 2st ctl cmd(CTL    21 22 03 00  00 00 00 00 ) */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0003, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	/* send  3st cmd and recieve data */
+	/*
+	 * 16.0  CTL    a1 21 00 00  00 00 07 00      CLASS         25.1.0(5)
+	 * 16.0  DI     00 08 07 00  00 00 08
+	 */
+	len = 0x0007;
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				 0x21, 0xa1,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 4 cmd */
+	/*
+	 * 16.0 CTL    21 20 00 00  00 00 07 00      CLASS            30.1.0
+	 * 16.0  DO    00 c2 01 00  00 00 08         .%.....          30.2.0
+	 */
+	len = 0x0007;
+	buf[0] = 0x00;
+	buf[1] = 0xc2;
+	buf[2] = 0x01;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+	buf[5] = 0x00;
+	buf[6] = 0x08;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x20, 0x21,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 5 cmd */
+	/*
+	 * 16.0 CTL    21 22 03 00  00 00 00 00
+	 */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0003, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	/* send 6 cmd */
+	/*
+	 * 16.0  CTL    a1 21 00 00  00 00 07 00        CLASS          33.1.0
+	 * 16.0  DI     00 c2 01 00  00 00 08
+	 */
+	len = 0x0007;
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				 0x21, 0xa1,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 7 cmd */
+	/*
+	 * 16.0  CTL    21 20 00 00  00 00 07 00  CLASS               354.1.0
+	 * 16.0  DO     00 c2 01 00  00 00 08     .......             354.2.0
+	 */
+	len = 0x0007;
+	buf[0] = 0x00;
+	buf[1] = 0xc2;
+	buf[2] = 0x01;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+	buf[5] = 0x00;
+	buf[6] = 0x08;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x20, 0x21,
+				 0x0000, 0x0000, buf, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	debug_data(dev, __func__, len, buf, result);
+
+	/* send 8 cmd */
+	/*
+	 * 16.0 CTL    21 22 03 00  00 00 00 00
+	 */
+	len = 0;
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 0x22, 0x21,
+				 0x0003, 0x0000, NULL, len,
+				 HZ * USB_CTRL_GET_TIMEOUT);
+	dev_dbg(dev, "result = %d\n", result);
+
+	kfree(buf);
+
+	usb_serial_generic_close(port);
+}
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x19d2, 0xffff) },	/* AC8700 */
+	{ USB_DEVICE(0x19d2, 0xfffe) },
+	{ USB_DEVICE(0x19d2, 0xfffd) }, /* MG880 */
+	{ USB_DEVICE(0x05C6, 0x3197) },
+	{ USB_DEVICE(0x05C6, 0x6000) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_serial_driver zio_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"zte_ev",
+	},
+	.id_table =		id_table,
+	.num_ports =		1,
+	.open =			zte_ev_usb_serial_open,
+	.close =		zte_ev_usb_serial_close,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+	&zio_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 7691c86..0ae7bb6 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -213,17 +213,3 @@
 	  say 'Y' or 'M' here and the kernel will use the right driver.
 
 	  If you compile this driver as a module, it will be named uas.
-
-config USB_LIBUSUAL
-	bool "The shared table of common (or usual) storage devices"
-	depends on USB
-	help
-	  This module contains a table of common (or usual) devices
-	  for usb-storage and ub drivers, and allows to switch binding
-	  of these devices without rebuilding modules.
-
-	  Typical syntax of /etc/modprobe.d/*conf is:
-
-		options libusual bias="ub"
-
-	  If unsure, say N.
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 82e6416..4cd5548 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -12,16 +12,9 @@
 
 usb-storage-y := scsiglue.o protocol.o transport.o usb.o
 usb-storage-y += initializers.o sierra_ms.o option_ms.o
-
+usb-storage-y += usual-tables.o
 usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
 
-ifeq ($(CONFIG_USB_LIBUSUAL),)
-	usb-storage-y		+= usual-tables.o
-else
-	obj-$(CONFIG_USB)	+= usb-libusual.o
-	usb-libusual-y		:= libusual.o usual-tables.o
-endif
-
 obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= ums-alauda.o
 obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o
 obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= ums-datafab.o
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index bab8c8f..be5564c 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -137,7 +137,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id alauda_usb_ids[] = {
 #	include "unusual_alauda.h"
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index 5fe451d..070b5c0 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -41,7 +41,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id cypress_usb_ids[] = {
 #	include "unusual_cypress.h"
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 35e9c51..494fee5 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -86,7 +86,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id datafab_usb_ids[] = {
 #	include "unusual_datafab.h"
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index b28f2ad..118b134 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -29,9 +29,21 @@
 #include "protocol.h"
 #include "debug.h"
 
+#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
+#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
+#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
+#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
+#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
+#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
+
 MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
 MODULE_LICENSE("GPL");
-
+MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
+MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
+MODULE_FIRMWARE(SD_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_INIT_FIRMWARE);
+MODULE_FIRMWARE(MSP_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_RW_FIRMWARE);
 
 /*
  * The table of devices
@@ -40,7 +52,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-	.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+	.driver_info = (flags)}
 
 static struct usb_device_id ene_ub6250_usb_ids[] = {
 #	include "unusual_ene_ub6250.h"
@@ -1883,28 +1895,28 @@
 	/* For SD */
 	case SD_INIT1_PATTERN:
 		US_DEBUGP("SD_INIT1_PATTERN\n");
-		fw_name = "ene-ub6250/sd_init1.bin";
+		fw_name = SD_INIT1_FIRMWARE;
 		break;
 	case SD_INIT2_PATTERN:
 		US_DEBUGP("SD_INIT2_PATTERN\n");
-		fw_name = "ene-ub6250/sd_init2.bin";
+		fw_name = SD_INIT2_FIRMWARE;
 		break;
 	case SD_RW_PATTERN:
-		US_DEBUGP("SD_RDWR_PATTERN\n");
-		fw_name = "ene-ub6250/sd_rdwr.bin";
+		US_DEBUGP("SD_RW_PATTERN\n");
+		fw_name = SD_RW_FIRMWARE;
 		break;
 	/* For MS */
 	case MS_INIT_PATTERN:
 		US_DEBUGP("MS_INIT_PATTERN\n");
-		fw_name = "ene-ub6250/ms_init.bin";
+		fw_name = MS_INIT_FIRMWARE;
 		break;
 	case MSP_RW_PATTERN:
 		US_DEBUGP("MSP_RW_PATTERN\n");
-		fw_name = "ene-ub6250/msp_rdwr.bin";
+		fw_name = MSP_RW_FIRMWARE;
 		break;
 	case MS_RW_PATTERN:
 		US_DEBUGP("MS_RW_PATTERN\n");
-		fw_name = "ene-ub6250/ms_rdwr.bin";
+		fw_name = MS_RW_FIRMWARE;
 		break;
 	default:
 		US_DEBUGP("----------- Unknown PATTERN ----------\n");
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 042cf9e..e6df087 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -117,7 +117,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id freecom_usb_ids[] = {
 #	include "unusual_freecom.h"
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 31fa24e..ecea478 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -74,7 +74,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id isd200_usb_ids[] = {
 #	include "unusual_isd200.h"
@@ -83,7 +83,6 @@
 MODULE_DEVICE_TABLE(usb, isd200_usb_ids);
 
 #undef UNUSUAL_DEV
-#undef USUAL_DEV
 
 /*
  * The flags table
@@ -105,8 +104,6 @@
 };
 
 #undef UNUSUAL_DEV
-#undef USUAL_DEV
-
 
 /* Timeout defines (in Seconds) */
 
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index e3b9738..ddc7878 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -69,7 +69,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id jumpshot_usb_ids[] = {
 #	include "unusual_jumpshot.h"
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index a8708ea..f085ffb 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -57,7 +57,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id karma_usb_ids[] = {
 #	include "unusual_karma.h"
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
deleted file mode 100644
index fe3ffe1..0000000
--- a/drivers/usb/storage/libusual.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * libusual
- *
- * The libusual contains the table of devices common for ub and usb-storage.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb_usual.h>
-#include <linux/vmalloc.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-
-/*
- */
-#define USU_MOD_FL_THREAD   1	/* Thread is running */
-#define USU_MOD_FL_PRESENT  2	/* The module is loaded */
-
-struct mod_status {
-	unsigned long fls;
-};
-
-static struct mod_status stat[3];
-static DEFINE_SPINLOCK(usu_lock);
-
-/*
- */
-#define USB_US_DEFAULT_BIAS	USB_US_TYPE_STOR
-static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
-
-#define BIAS_NAME_SIZE  (sizeof("usb-storage"))
-static const char *bias_names[3] = { "none", "usb-storage", "ub" };
-
-static DEFINE_MUTEX(usu_probe_mutex);
-static DECLARE_COMPLETION(usu_end_notify);
-static atomic_t total_threads = ATOMIC_INIT(0);
-
-static int usu_probe_thread(void *arg);
-
-/*
- * @type: the module type as an integer
- */
-void usb_usual_set_present(int type)
-{
-	struct mod_status *st;
-	unsigned long flags;
-
-	if (type <= 0 || type >= 3)
-		return;
-	st = &stat[type];
-	spin_lock_irqsave(&usu_lock, flags);
-	st->fls |= USU_MOD_FL_PRESENT;
-	spin_unlock_irqrestore(&usu_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_usual_set_present);
-
-void usb_usual_clear_present(int type)
-{
-	struct mod_status *st;
-	unsigned long flags;
-
-	if (type <= 0 || type >= 3)
-		return;
-	st = &stat[type];
-	spin_lock_irqsave(&usu_lock, flags);
-	st->fls &= ~USU_MOD_FL_PRESENT;
-	spin_unlock_irqrestore(&usu_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_usual_clear_present);
-
-/*
- * Match the calling driver type against the table.
- * Returns: 0 if the device matches.
- */
-int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
-{
-	int id_type = USB_US_TYPE(id->driver_info);
-
-	if (caller_type <= 0 || caller_type >= 3)
-		return -EINVAL;
-
-	/* Drivers grab fixed assignment devices */
-	if (id_type == caller_type)
-		return 0;
-	/* Drivers grab devices biased to them */
-	if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias))
-		return 0;
-	return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(usb_usual_check_type);
-
-/*
- */
-static int usu_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
-{
-	int rc;
-	unsigned long type;
-	struct task_struct* task;
-	unsigned long flags;
-
-	type = USB_US_TYPE(id->driver_info);
-	if (type == 0)
-		type = atomic_read(&usu_bias);
-
-	spin_lock_irqsave(&usu_lock, flags);
-	if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) {
-		spin_unlock_irqrestore(&usu_lock, flags);
-		return -ENXIO;
-	}
-	stat[type].fls |= USU_MOD_FL_THREAD;
-	spin_unlock_irqrestore(&usu_lock, flags);
-
-	task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
-	if (IS_ERR(task)) {
-		rc = PTR_ERR(task);
-		printk(KERN_WARNING "libusual: "
-		    "Unable to start the thread for %s: %d\n",
-		    bias_names[type], rc);
-		spin_lock_irqsave(&usu_lock, flags);
-		stat[type].fls &= ~USU_MOD_FL_THREAD;
-		spin_unlock_irqrestore(&usu_lock, flags);
-		return rc;	/* Not being -ENXIO causes a message printed */
-	}
-	atomic_inc(&total_threads);
-
-	return -ENXIO;
-}
-
-static void usu_disconnect(struct usb_interface *intf)
-{
-	;	/* We should not be here. */
-}
-
-static struct usb_driver usu_driver = {
-	.name =		"libusual",
-	.probe =	usu_probe,
-	.disconnect =	usu_disconnect,
-	.id_table =	usb_storage_usb_ids,
-};
-
-/*
- * A whole new thread for a purpose of request_module seems quite stupid.
- * The request_module forks once inside again. However, if we attempt
- * to load a storage module from our own modprobe thread, that module
- * references our symbols, which cannot be resolved until our module is
- * initialized. I wish there was a way to wait for the end of initialization.
- * The module notifier reports MODULE_STATE_COMING only.
- * So, we wait until module->init ends as the next best thing.
- */
-static int usu_probe_thread(void *arg)
-{
-	int type = (unsigned long) arg;
-	struct mod_status *st = &stat[type];
-	int rc;
-	unsigned long flags;
-
-	mutex_lock(&usu_probe_mutex);
-	rc = request_module(bias_names[type]);
-	spin_lock_irqsave(&usu_lock, flags);
-	if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
-		/*
-		 * This should not happen, but let us keep tabs on it.
-		 */
-		printk(KERN_NOTICE "libusual: "
-		    "modprobe for %s succeeded, but module is not present\n",
-		    bias_names[type]);
-	}
-	st->fls &= ~USU_MOD_FL_THREAD;
-	spin_unlock_irqrestore(&usu_lock, flags);
-	mutex_unlock(&usu_probe_mutex);
-
-	complete_and_exit(&usu_end_notify, 0);
-}
-
-/*
- */
-static int __init usb_usual_init(void)
-{
-	int rc;
-
-	mutex_lock(&usu_probe_mutex);
-	rc = usb_register(&usu_driver);
-	mutex_unlock(&usu_probe_mutex);
-	return rc;
-}
-
-static void __exit usb_usual_exit(void)
-{
-	/*
-	 * We do not check for any drivers present, because
-	 * they keep us pinned with symbol references.
-	 */
-
-	usb_deregister(&usu_driver);
-
-	while (atomic_read(&total_threads) > 0) {
-		wait_for_completion(&usu_end_notify);
-		atomic_dec(&total_threads);
-	}
-}
-
-/*
- * Validate and accept the bias parameter.
- */
-static int usu_set_bias(const char *bias_s, struct kernel_param *kp)
-{
-	int i;
-	int len;
-	int bias_n = 0;
-
-	len = strlen(bias_s);
-	if (len == 0)
-		return -EDOM;
-	if (bias_s[len-1] == '\n')
-		--len;
-
-	for (i = 1; i < 3; i++) {
-		if (strncmp(bias_s, bias_names[i], len) == 0) {
-			bias_n = i;
-			break;
-		}
-	}
-	if (bias_n == 0)
-		return -EINVAL;
-
-	atomic_set(&usu_bias, bias_n);
-	return 0;
-}
-
-static int usu_get_bias(char *buffer, struct kernel_param *kp)
-{
-	return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)]));
-}
-
-module_init(usb_usual_init);
-module_exit(usb_usual_exit);
-
-module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR);
-__MODULE_PARM_TYPE(bias, "string");
-MODULE_PARM_DESC(bias, "Bias to usb-storage or ub");
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 886567a..cb79de6 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -67,7 +67,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id onetouch_usb_ids[] = {
 #	include "unusual_onetouch.h"
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 63cf282..d36446d 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -172,7 +172,7 @@
 		    initFunction, flags) \
 {\
 	USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-	.driver_info = (flags)|(USB_US_TYPE_STOR<<24)\
+	.driver_info = (flags) \
 }
 
 static const struct usb_device_id realtek_cr_ids[] = {
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 3252a62..7bd54e0 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -69,7 +69,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id sddr09_usb_ids[] = {
 #	include "unusual_sddr09.h"
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index c144078..d278c5a 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -46,7 +46,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id sddr55_usb_ids[] = {
 #	include "unusual_sddr55.h"
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index fa1ceeb..daf2fc5 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -168,7 +168,7 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id usbat_usb_ids[] = {
 #	include "unusual_usbat.h"
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
index 37539c8..17e3695 100644
--- a/drivers/usb/storage/sierra_ms.c
+++ b/drivers/usb/storage/sierra_ms.c
@@ -130,14 +130,13 @@
 	struct swoc_info *swocInfo;
 	struct usb_device *udev;
 	struct Scsi_Host *sh;
-	struct scsi_device *sd;
 
 	retries = 3;
 	result = 0;
 	udev = us->pusb_dev;
 
 	sh = us_to_host(us);
-	sd = scsi_get_host_dev(sh);
+	scsi_get_host_dev(sh);
 
 	US_DEBUGP("SWIMS: sierra_ms_init called\n");
 
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c70109e..c0543c8 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1331,7 +1331,7 @@
 	int result;
 
 	/*for these devices we must use the class specific method */
-	if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS)
+	if (us->pusb_dev->quirks & USB_QUIRK_RESET)
 		return -EPERM;
 
 	result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 638cd64..98b98ee 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -41,6 +41,7 @@
 struct uas_dev_info {
 	struct usb_interface *intf;
 	struct usb_device *udev;
+	struct usb_anchor cmd_urbs;
 	struct usb_anchor sense_urbs;
 	struct usb_anchor data_urbs;
 	int qdepth, resetting;
@@ -49,6 +50,7 @@
 	unsigned use_streams:1;
 	unsigned uas_sense_old:1;
 	struct scsi_cmnd *cmnd;
+	spinlock_t lock;
 };
 
 enum {
@@ -63,13 +65,13 @@
 	DATA_IN_URB_INFLIGHT    = (1 << 9),
 	DATA_OUT_URB_INFLIGHT   = (1 << 10),
 	COMMAND_COMPLETED       = (1 << 11),
+	COMMAND_ABORTED         = (1 << 12),
 };
 
 /* Overrides scsi_pointer */
 struct uas_cmd_info {
 	unsigned int state;
 	unsigned int stream;
-	unsigned int aborted;
 	struct urb *cmd_urb;
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
@@ -90,6 +92,7 @@
 	struct uas_cmd_info *cmdinfo;
 	struct uas_cmd_info *temp;
 	struct list_head list;
+	unsigned long flags;
 	int err;
 
 	spin_lock_irq(&uas_work_lock);
@@ -100,7 +103,10 @@
 		struct scsi_pointer *scp = (void *)cmdinfo;
 		struct scsi_cmnd *cmnd = container_of(scp,
 							struct scsi_cmnd, SCp);
-		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+		struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+		spin_lock_irqsave(&devinfo->lock, flags);
+		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+		spin_unlock_irqrestore(&devinfo->lock, flags);
 		if (err) {
 			list_del(&cmdinfo->list);
 			spin_lock_irq(&uas_work_lock);
@@ -162,7 +168,7 @@
 	struct uas_cmd_info *ci = (void *)&cmnd->SCp;
 
 	scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
-		    "%s%s%s%s%s%s%s%s%s%s%s\n",
+		    "%s%s%s%s%s%s%s%s%s%s%s%s\n",
 		    caller, cmnd, cmnd->request->tag,
 		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
 		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
@@ -174,13 +180,16 @@
 		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
 		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
 		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
-		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "");
+		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
+		    (ci->state & COMMAND_ABORTED)       ? " abort" : "");
 }
 
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 {
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
 
+	WARN_ON(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & (COMMAND_INFLIGHT |
 			      DATA_IN_URB_INFLIGHT |
 			      DATA_OUT_URB_INFLIGHT))
@@ -189,6 +198,10 @@
 	cmdinfo->state |= COMMAND_COMPLETED;
 	usb_free_urb(cmdinfo->data_in_urb);
 	usb_free_urb(cmdinfo->data_out_urb);
+	if (cmdinfo->state & COMMAND_ABORTED) {
+		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
+		cmnd->result = DID_ABORT << 16;
+	}
 	cmnd->scsi_done(cmnd);
 	return 0;
 }
@@ -216,6 +229,7 @@
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 	struct scsi_cmnd *cmnd;
 	struct uas_cmd_info *cmdinfo;
+	unsigned long flags;
 	u16 tag;
 
 	if (urb->status) {
@@ -229,20 +243,24 @@
 		return;
 	}
 
+	spin_lock_irqsave(&devinfo->lock, flags);
 	tag = be16_to_cpup(&iu->tag) - 1;
 	if (tag == 0)
 		cmnd = devinfo->cmnd;
 	else
 		cmnd = scsi_host_find_tag(shost, tag - 1);
+
 	if (!cmnd) {
-		if (iu->iu_id != IU_ID_RESPONSE) {
-			usb_free_urb(urb);
-			return;
+		if (iu->iu_id == IU_ID_RESPONSE) {
+			/* store results for uas_eh_task_mgmt() */
+			memcpy(&devinfo->response, iu, sizeof(devinfo->response));
 		}
-	} else {
-		cmdinfo = (void *)&cmnd->SCp;
+		usb_free_urb(urb);
+		spin_unlock_irqrestore(&devinfo->lock, flags);
+		return;
 	}
 
+	cmdinfo = (void *)&cmnd->SCp;
 	switch (iu->iu_id) {
 	case IU_ID_STATUS:
 		if (devinfo->cmnd == cmnd)
@@ -256,10 +274,16 @@
 			uas_sense(urb, cmnd);
 		if (cmnd->result != 0) {
 			/* cancel data transfers on error */
-			if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+			if (cmdinfo->state & DATA_IN_URB_INFLIGHT) {
+				spin_unlock_irqrestore(&devinfo->lock, flags);
 				usb_unlink_urb(cmdinfo->data_in_urb);
-			if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+				spin_lock_irqsave(&devinfo->lock, flags);
+			}
+			if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) {
+				spin_unlock_irqrestore(&devinfo->lock, flags);
 				usb_unlink_urb(cmdinfo->data_out_urb);
+				spin_lock_irqsave(&devinfo->lock, flags);
+			}
 		}
 		cmdinfo->state &= ~COMMAND_INFLIGHT;
 		uas_try_complete(cmnd, __func__);
@@ -270,23 +294,23 @@
 	case IU_ID_WRITE_READY:
 		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
 		break;
-	case IU_ID_RESPONSE:
-		/* store results for uas_eh_task_mgmt() */
-		memcpy(&devinfo->response, iu, sizeof(devinfo->response));
-		break;
 	default:
 		scmd_printk(KERN_ERR, cmnd,
 			"Bogus IU (%d) received on status pipe\n", iu->iu_id);
 	}
 	usb_free_urb(urb);
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static void uas_data_cmplt(struct urb *urb)
 {
 	struct scsi_cmnd *cmnd = urb->context;
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
 	struct scsi_data_buffer *sdb = NULL;
+	unsigned long flags;
 
+	spin_lock_irqsave(&devinfo->lock, flags);
 	if (cmdinfo->data_in_urb == urb) {
 		sdb = scsi_in(cmnd);
 		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
@@ -301,10 +325,8 @@
 	} else {
 		sdb->resid = sdb->length - urb->actual_length;
 	}
-	if (cmdinfo->aborted) {
-		return;
-	}
 	uas_try_complete(cmnd, __func__);
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
@@ -431,6 +453,7 @@
 	err = usb_submit_urb(urb, gfp);
 	if (err)
 		goto err;
+	usb_anchor_urb(urb, &devinfo->cmd_urbs);
 
 	return 0;
 
@@ -470,6 +493,7 @@
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	int err;
 
+	WARN_ON(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & SUBMIT_STATUS_URB) {
 		err = uas_submit_sense_urb(cmnd->device->host, gfp,
 					   cmdinfo->stream);
@@ -521,18 +545,22 @@
 
 	if (cmdinfo->state & ALLOC_CMD_URB) {
 		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd,
-							cmdinfo->stream);
+						     cmdinfo->stream);
 		if (!cmdinfo->cmd_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_CMD_URB;
 	}
 
 	if (cmdinfo->state & SUBMIT_CMD_URB) {
+		usb_get_urb(cmdinfo->cmd_urb);
 		if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
 			scmd_printk(KERN_INFO, cmnd,
 					"cmd urb submission failure\n");
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
+		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
+		usb_put_urb(cmdinfo->cmd_urb);
+		cmdinfo->cmd_urb = NULL;
 		cmdinfo->state &= ~SUBMIT_CMD_URB;
 		cmdinfo->state |= COMMAND_INFLIGHT;
 	}
@@ -546,12 +574,16 @@
 	struct scsi_device *sdev = cmnd->device;
 	struct uas_dev_info *devinfo = sdev->hostdata;
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	unsigned long flags;
 	int err;
 
 	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
 
-	if (devinfo->cmnd)
+	spin_lock_irqsave(&devinfo->lock, flags);
+	if (devinfo->cmnd) {
+		spin_unlock_irqrestore(&devinfo->lock, flags);
 		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
 
 	if (blk_rq_tagged(cmnd->request)) {
 		cmdinfo->stream = cmnd->request->tag + 2;
@@ -564,7 +596,6 @@
 
 	cmdinfo->state = SUBMIT_STATUS_URB |
 			ALLOC_CMD_URB | SUBMIT_CMD_URB;
-	cmdinfo->aborted = 0;
 
 	switch (cmnd->sc_data_direction) {
 	case DMA_FROM_DEVICE:
@@ -587,6 +618,7 @@
 	if (err) {
 		/* If we did nothing, give up now */
 		if (cmdinfo->state & SUBMIT_STATUS_URB) {
+			spin_unlock_irqrestore(&devinfo->lock, flags);
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
 		spin_lock(&uas_work_lock);
@@ -595,6 +627,7 @@
 		schedule_work(&uas_work);
 	}
 
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 	return 0;
 }
 
@@ -605,22 +638,28 @@
 {
 	struct Scsi_Host *shost = cmnd->device->host;
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
-	u16 tag = 9999; /* FIXME */
+	u16 tag = devinfo->qdepth - 1;
+	unsigned long flags;
 
+	spin_lock_irqsave(&devinfo->lock, flags);
 	memset(&devinfo->response, 0, sizeof(devinfo->response));
-	if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) {
+	if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
 		shost_printk(KERN_INFO, shost,
 			     "%s: %s: submit sense urb failed\n",
 			     __func__, fname);
+		spin_unlock_irqrestore(&devinfo->lock, flags);
 		return FAILED;
 	}
-	if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
+	if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
 		shost_printk(KERN_INFO, shost,
 			     "%s: %s: submit task mgmt urb failed\n",
 			     __func__, fname);
+		spin_unlock_irqrestore(&devinfo->lock, flags);
 		return FAILED;
 	}
-	if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) {
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
 		shost_printk(KERN_INFO, shost,
 			     "%s: %s timed out\n", __func__, fname);
 		return FAILED;
@@ -643,15 +682,15 @@
 static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 {
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+	unsigned long flags;
 	int ret;
 
 	uas_log_cmd_state(cmnd, __func__);
-	cmdinfo->aborted = 1;
+	spin_lock_irqsave(&devinfo->lock, flags);
+	cmdinfo->state |= COMMAND_ABORTED;
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 	ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
-	if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
-		usb_kill_urb(cmdinfo->data_in_urb);
-	if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
-		usb_kill_urb(cmdinfo->data_out_urb);
 	return ret;
 }
 
@@ -670,6 +709,7 @@
 	int err;
 
 	devinfo->resetting = 1;
+	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
 	err = usb_reset_device(udev);
@@ -694,7 +734,7 @@
 {
 	struct uas_dev_info *devinfo = sdev->hostdata;
 	scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
-	scsi_activate_tcq(sdev, devinfo->qdepth - 2);
+	scsi_activate_tcq(sdev, devinfo->qdepth - 3);
 	return 0;
 }
 
@@ -868,11 +908,13 @@
 	devinfo->intf = intf;
 	devinfo->udev = udev;
 	devinfo->resetting = 0;
+	init_usb_anchor(&devinfo->cmd_urbs);
 	init_usb_anchor(&devinfo->sense_urbs);
 	init_usb_anchor(&devinfo->data_urbs);
+	spin_lock_init(&devinfo->lock);
 	uas_configure_endpoints(devinfo);
 
-	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
+	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
 	if (result)
 		goto free;
 
@@ -913,6 +955,7 @@
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
 	scsi_remove_host(shost);
+	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
 	uas_free_streams(devinfo);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 62a31be..779cd95 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2038,25 +2038,25 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
 /* Control/Bulk transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(USB_SC_RBC, USB_PR_CB),
+USUAL_DEV(USB_SC_8020, USB_PR_CB),
+USUAL_DEV(USB_SC_QIC, USB_PR_CB),
+USUAL_DEV(USB_SC_UFI, USB_PR_CB),
+USUAL_DEV(USB_SC_8070, USB_PR_CB),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CB),
 
 /* Control/Bulk/Interrupt transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(USB_SC_RBC, USB_PR_CBI),
+USUAL_DEV(USB_SC_8020, USB_PR_CBI),
+USUAL_DEV(USB_SC_QIC, USB_PR_CBI),
+USUAL_DEV(USB_SC_UFI, USB_PR_CBI),
+USUAL_DEV(USB_SC_8070, USB_PR_CBI),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CBI),
 
 /* Bulk-only transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0),
+USUAL_DEV(USB_SC_RBC, USB_PR_BULK),
+USUAL_DEV(USB_SC_8020, USB_PR_BULK),
+USUAL_DEV(USB_SC_QIC, USB_PR_BULK),
+USUAL_DEV(USB_SC_UFI, USB_PR_BULK),
+USUAL_DEV(USB_SC_8070, USB_PR_BULK),
+USUAL_DEV(USB_SC_SCSI, USB_PR_BULK),
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index d012fe4..12aa726 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -114,7 +114,7 @@
 
 #define COMPLIANT_DEV	UNUSUAL_DEV
 
-#define USUAL_DEV(use_protocol, use_transport, use_type) \
+#define USUAL_DEV(use_protocol, use_transport) \
 { \
 	.useProtocol = use_protocol,	\
 	.useTransport = use_transport,	\
@@ -126,7 +126,7 @@
 };
 
 static struct us_unusual_dev for_dynamic_ids =
-		USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
+		USUAL_DEV(USB_SC_SCSI, USB_PR_BULK);
 
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
@@ -564,7 +564,7 @@
 	us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ?
 			idesc->bInterfaceProtocol :
 			unusual_dev->useTransport;
-	us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+	us->fflags = id->driver_info;
 	adjust_quirks(us);
 
 	if (us->fflags & US_FL_IGNORE_DEVICE) {
@@ -1041,13 +1041,10 @@
 	int size;
 
 	/*
-	 * If libusual is configured, let it decide whether a standard
-	 * device should be handled by usb-storage or by ub.
 	 * If the device isn't standard (is handled by a subdriver
 	 * module) then don't accept it.
 	 */
-	if (usb_usual_check_type(id, USB_US_TYPE_STOR) ||
-			usb_usual_ignore_device(intf))
+	if (usb_usual_ignore_device(intf))
 		return -ENXIO;
 
 	/*
@@ -1105,10 +1102,8 @@
 
 	/* register the driver, return usb_register return code if error */
 	retval = usb_register(&usb_storage_driver);
-	if (retval == 0) {
+	if (retval == 0)
 		pr_info("USB Mass Storage support registered.\n");
-		usb_usual_set_present(USB_US_TYPE_STOR);
-	}
 	return retval;
 }
 
@@ -1122,8 +1117,6 @@
 	 */
 	US_DEBUGP("-- calling usb_deregister()\n");
 	usb_deregister(&usb_storage_driver) ;
-
-	usb_usual_clear_present(USB_US_TYPE_STOR);
 }
 
 module_init(usb_stor_init);
diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c
index b969279..b78a526 100644
--- a/drivers/usb/storage/usual-tables.c
+++ b/drivers/usb/storage/usual-tables.c
@@ -34,31 +34,23 @@
 		    vendorName, productName, useProtocol, useTransport, \
 		    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
-
-#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
-		    vendorName, productName, useProtocol, useTransport, \
-		    initFunction, flags) \
-{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags) }
 
-#define USUAL_DEV(useProto, useTrans, useType) \
-{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
-  .driver_info = ((useType)<<24) }
+#define COMPLIANT_DEV	UNUSUAL_DEV
+
+#define USUAL_DEV(useProto, useTrans) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }
 
 struct usb_device_id usb_storage_usb_ids[] = {
 #	include "unusual_devs.h"
 	{ }		/* Terminating entry */
 };
-EXPORT_SYMBOL_GPL(usb_storage_usb_ids);
-
 MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);
 
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
 #undef USUAL_DEV
 
-
 /*
  * The table of devices to ignore
  */
@@ -95,7 +87,6 @@
 
 #undef UNUSUAL_DEV
 
-
 /* Return an error if a device is in the ignore_ids list */
 int usb_usual_ignore_device(struct usb_interface *intf)
 {
@@ -115,4 +106,3 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL_GPL(usb_usual_ignore_device);
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
index f29fdd7..8bf1976 100644
--- a/drivers/usb/wusbcore/Kconfig
+++ b/drivers/usb/wusbcore/Kconfig
@@ -2,8 +2,7 @@
 # Wireless USB Core configuration
 #
 config USB_WUSB
-	tristate "Enable Wireless USB extensions (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "Enable Wireless USB extensions"
 	depends on USB
 	depends on PCI
 	depends on UWB
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
index fa810a8..dd88441 100644
--- a/drivers/usb/wusbcore/security.c
+++ b/drivers/usb/wusbcore/security.c
@@ -202,7 +202,7 @@
 {
 	int result, bytes, secd_size;
 	struct device *dev = &usb_dev->dev;
-	struct usb_security_descriptor *secd;
+	struct usb_security_descriptor *secd, *new_secd;
 	const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
 	const void *itr, *top;
 	char buf[64];
@@ -221,11 +221,12 @@
 		goto out;
 	}
 	secd_size = le16_to_cpu(secd->wTotalLength);
-	secd = krealloc(secd, secd_size, GFP_KERNEL);
-	if (secd == NULL) {
+	new_secd = krealloc(secd, secd_size, GFP_KERNEL);
+	if (new_secd == NULL) {
 		dev_err(dev, "Can't allocate space for security descriptors\n");
 		goto out;
 	}
+	secd = new_secd;
 	result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
 				    0, secd, secd_size);
 	if (result < secd_size) {
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 9e4a924..a09b65e 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -46,8 +46,10 @@
 	wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
 	wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd);
 	wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
-	if (wa->xfer_result == NULL)
+	if (wa->xfer_result == NULL) {
+		result = -ENOMEM;
 		goto error_xfer_result_alloc;
+	}
 	result = wa_nep_create(wa, iface);
 	if (result < 0) {
 		dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 211a492..d8dedc7 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -76,9 +76,24 @@
 			schedule_work(&virqfd->inject);
 	}
 
-	if (flags & POLLHUP)
-		/* The eventfd is closing, detach from VFIO */
-		virqfd_deactivate(virqfd);
+	if (flags & POLLHUP) {
+		unsigned long flags;
+		spin_lock_irqsave(&virqfd->vdev->irqlock, flags);
+
+		/*
+		 * The eventfd is closing, if the virqfd has not yet been
+		 * queued for release, as determined by testing whether the
+		 * vdev pointer to it is still valid, queue it now.  As
+		 * with kvm irqfds, we know we won't race against the virqfd
+		 * going away because we hold wqh->lock to get here.
+		 */
+		if (*(virqfd->pvirqfd) == virqfd) {
+			*(virqfd->pvirqfd) = NULL;
+			virqfd_deactivate(virqfd);
+		}
+
+		spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags);
+	}
 
 	return 0;
 }
@@ -93,7 +108,6 @@
 static void virqfd_shutdown(struct work_struct *work)
 {
 	struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
-	struct virqfd **pvirqfd = virqfd->pvirqfd;
 	u64 cnt;
 
 	eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
@@ -101,7 +115,6 @@
 	eventfd_ctx_put(virqfd->eventfd);
 
 	kfree(virqfd);
-	*pvirqfd = NULL;
 }
 
 static void virqfd_inject(struct work_struct *work)
@@ -122,15 +135,11 @@
 	int ret = 0;
 	unsigned int events;
 
-	if (*pvirqfd)
-		return -EBUSY;
-
 	virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
 	if (!virqfd)
 		return -ENOMEM;
 
 	virqfd->pvirqfd = pvirqfd;
-	*pvirqfd = virqfd;
 	virqfd->vdev = vdev;
 	virqfd->handler = handler;
 	virqfd->thread = thread;
@@ -154,6 +163,23 @@
 	virqfd->eventfd = ctx;
 
 	/*
+	 * virqfds can be released by closing the eventfd or directly
+	 * through ioctl.  These are both done through a workqueue, so
+	 * we update the pointer to the virqfd under lock to avoid
+	 * pushing multiple jobs to release the same virqfd.
+	 */
+	spin_lock_irq(&vdev->irqlock);
+
+	if (*pvirqfd) {
+		spin_unlock_irq(&vdev->irqlock);
+		ret = -EBUSY;
+		goto fail;
+	}
+	*pvirqfd = virqfd;
+
+	spin_unlock_irq(&vdev->irqlock);
+
+	/*
 	 * Install our own custom wake-up handling so we are notified via
 	 * a callback whenever someone signals the underlying eventfd.
 	 */
@@ -187,19 +213,29 @@
 		fput(file);
 
 	kfree(virqfd);
-	*pvirqfd = NULL;
 
 	return ret;
 }
 
-static void virqfd_disable(struct virqfd *virqfd)
+static void virqfd_disable(struct vfio_pci_device *vdev,
+			   struct virqfd **pvirqfd)
 {
-	if (!virqfd)
-		return;
+	unsigned long flags;
 
-	virqfd_deactivate(virqfd);
+	spin_lock_irqsave(&vdev->irqlock, flags);
 
-	/* Block until we know all outstanding shutdown jobs have completed. */
+	if (*pvirqfd) {
+		virqfd_deactivate(*pvirqfd);
+		*pvirqfd = NULL;
+	}
+
+	spin_unlock_irqrestore(&vdev->irqlock, flags);
+
+	/*
+	 * Block until we know all outstanding shutdown jobs have completed.
+	 * Even if we don't queue the job, flush the wq to be sure it's
+	 * been released.
+	 */
 	flush_workqueue(vfio_irqfd_cleanup_wq);
 }
 
@@ -392,8 +428,8 @@
 static void vfio_intx_disable(struct vfio_pci_device *vdev)
 {
 	vfio_intx_set_signal(vdev, -1);
-	virqfd_disable(vdev->ctx[0].unmask);
-	virqfd_disable(vdev->ctx[0].mask);
+	virqfd_disable(vdev, &vdev->ctx[0].unmask);
+	virqfd_disable(vdev, &vdev->ctx[0].mask);
 	vdev->irq_type = VFIO_PCI_NUM_IRQS;
 	vdev->num_ctx = 0;
 	kfree(vdev->ctx);
@@ -539,8 +575,8 @@
 	vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
 
 	for (i = 0; i < vdev->num_ctx; i++) {
-		virqfd_disable(vdev->ctx[i].unmask);
-		virqfd_disable(vdev->ctx[i].mask);
+		virqfd_disable(vdev, &vdev->ctx[i].unmask);
+		virqfd_disable(vdev, &vdev->ctx[i].mask);
 	}
 
 	if (msix) {
@@ -577,7 +613,7 @@
 					     vfio_send_intx_eventfd, NULL,
 					     &vdev->ctx[0].unmask, fd);
 
-		virqfd_disable(vdev->ctx[0].unmask);
+		virqfd_disable(vdev, &vdev->ctx[0].unmask);
 	}
 
 	return 0;
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index f75da87..f49181c 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -228,7 +228,6 @@
 	data->port = pdata->flags;
 	if (data->port < 0) {
 		dev_err(&pdev->dev, "wrong platform data is assigned");
-		kfree(data);
 		return -EINVAL;
 	}
 
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index 92257ef..9a046a4 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -30,7 +30,7 @@
 #include <linux/platform_data/omap1_bl.h>
 
 #include <mach/hardware.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 
 #define OMAPBL_MAX_INTENSITY		0xff
 
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 7ae9d53..113d43a 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -131,7 +131,7 @@
 #define UPPER_MARGIN	32
 #define LOWER_MARGIN	32
 
-static resource_size_t da8xx_fb_reg_base;
+static void __iomem *da8xx_fb_reg_base;
 static struct resource *lcdc_regs;
 static unsigned int lcd_revision;
 static irq_handler_t lcdc_irq_handler;
@@ -951,7 +951,7 @@
 		clk_disable(par->lcdc_clk);
 		clk_put(par->lcdc_clk);
 		framebuffer_release(info);
-		iounmap((void __iomem *)da8xx_fb_reg_base);
+		iounmap(da8xx_fb_reg_base);
 		release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
 
 	}
@@ -1171,7 +1171,7 @@
 	if (!lcdc_regs)
 		return -EBUSY;
 
-	da8xx_fb_reg_base = (resource_size_t)ioremap(lcdc_regs->start, len);
+	da8xx_fb_reg_base = ioremap(lcdc_regs->start, len);
 	if (!da8xx_fb_reg_base) {
 		ret = -EBUSY;
 		goto err_request_mem;
@@ -1392,7 +1392,7 @@
 	clk_put(fb_clk);
 
 err_ioremap:
-	iounmap((void __iomem *)da8xx_fb_reg_base);
+	iounmap(da8xx_fb_reg_base);
 
 err_request_mem:
 	release_mem_region(lcdc_regs->start, len);
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index b4a632a..932abaa 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -553,7 +553,9 @@
 	int ret;
 	char *option = NULL;
 
-	dmi_check_system(dmi_system_table);
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
+	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+		dmi_check_system(dmi_system_table);
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
 		return -ENODEV;
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
index 4bc2b8a..663c308 100644
--- a/drivers/video/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -461,7 +461,7 @@
 done:
 	platform_set_drvdata(pdev, dsim);
 
-	dev_dbg(&pdev->dev, "%s() completed sucessfuly (%s mode)\n", __func__,
+	dev_dbg(&pdev->dev, "%s() completed successfully (%s mode)\n", __func__,
 		dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB");
 
 	return 0;
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index d3a3113..ed4cad8 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -27,8 +27,7 @@
 #include <linux/lcd.h>
 #include <linux/gpio.h>
 
-#include <plat/board-ams-delta.h>
-#include <mach/hardware.h>
+#include <mach/board-ams-delta.h>
 
 #include "omapfb.h"
 
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index e3880c4a0..b739600 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -25,7 +25,7 @@
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 
-#include <plat/lcd_mipid.h>
+#include <linux/platform_data/lcd-mipid.h>
 
 #include "omapfb.h"
 
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index 5914220..3aa62da 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -24,7 +24,7 @@
 #include <linux/platform_device.h>
 
 #include <asm/gpio.h>
-#include <plat/mux.h>
+#include <mach/mux.h>
 #include "omapfb.h"
 
 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
index 8e4a446..b244f06 100644
--- a/drivers/video/tmiofb.c
+++ b/drivers/video/tmiofb.c
@@ -694,6 +694,10 @@
 		dev_err(&dev->dev, "NULL platform data!\n");
 		return -EINVAL;
 	}
+	if (ccr == NULL || lcr == NULL || vram == NULL || irq < 0) {
+		dev_err(&dev->dev, "missing resources\n");
+		return -EINVAL;
+	}
 
 	info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev);
 
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index e0df92e..1425d22c 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -1603,7 +1603,7 @@
 {
 	int retval, i;
 	u32 data;
-	struct list_head *pos = NULL;
+	struct list_head *pos = NULL, *n;
 	struct vme_bridge *ca91cx42_bridge;
 	struct ca91cx42_driver *ca91cx42_device;
 	struct vme_master_resource *master_image;
@@ -1821,28 +1821,28 @@
 	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
 err_lm:
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->lm_resources) {
 		lm = list_entry(pos, struct vme_lm_resource, list);
 		list_del(pos);
 		kfree(lm);
 	}
 err_dma:
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->dma_resources) {
 		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
 		list_del(pos);
 		kfree(dma_ctrlr);
 	}
 err_slave:
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->slave_resources) {
 		slave_image = list_entry(pos, struct vme_slave_resource, list);
 		list_del(pos);
 		kfree(slave_image);
 	}
 err_master:
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->master_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->master_resources) {
 		master_image = list_entry(pos, struct vme_master_resource,
 			list);
 		list_del(pos);
@@ -1868,7 +1868,7 @@
 
 static void ca91cx42_remove(struct pci_dev *pdev)
 {
-	struct list_head *pos = NULL;
+	struct list_head *pos = NULL, *n;
 	struct vme_master_resource *master_image;
 	struct vme_slave_resource *slave_image;
 	struct vme_dma_resource *dma_ctrlr;
@@ -1905,28 +1905,28 @@
 	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
 
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->lm_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->lm_resources) {
 		lm = list_entry(pos, struct vme_lm_resource, list);
 		list_del(pos);
 		kfree(lm);
 	}
 
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->dma_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->dma_resources) {
 		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
 		list_del(pos);
 		kfree(dma_ctrlr);
 	}
 
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->slave_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->slave_resources) {
 		slave_image = list_entry(pos, struct vme_slave_resource, list);
 		list_del(pos);
 		kfree(slave_image);
 	}
 
 	/* resources are stored in link list */
-	list_for_each(pos, &ca91cx42_bridge->master_resources) {
+	list_for_each_safe(pos, n, &ca91cx42_bridge->master_resources) {
 		master_image = list_entry(pos, struct vme_master_resource,
 			list);
 		list_del(pos);
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index 880d924..5fbd08f 100644
--- a/drivers/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -2350,7 +2350,7 @@
 {
 	int retval, i, master_num;
 	u32 data;
-	struct list_head *pos = NULL;
+	struct list_head *pos = NULL, *n;
 	struct vme_bridge *tsi148_bridge;
 	struct tsi148_driver *tsi148_device;
 	struct vme_master_resource *master_image;
@@ -2615,28 +2615,28 @@
 err_crcsr:
 err_lm:
 	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->lm_resources) {
+	list_for_each_safe(pos, n, &tsi148_bridge->lm_resources) {
 		lm = list_entry(pos, struct vme_lm_resource, list);
 		list_del(pos);
 		kfree(lm);
 	}
 err_dma:
 	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->dma_resources) {
+	list_for_each_safe(pos, n, &tsi148_bridge->dma_resources) {
 		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
 		list_del(pos);
 		kfree(dma_ctrlr);
 	}
 err_slave:
 	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->slave_resources) {
+	list_for_each_safe(pos, n, &tsi148_bridge->slave_resources) {
 		slave_image = list_entry(pos, struct vme_slave_resource, list);
 		list_del(pos);
 		kfree(slave_image);
 	}
 err_master:
 	/* resources are stored in link list */
-	list_for_each(pos, &tsi148_bridge->master_resources) {
+	list_for_each_safe(pos, n, &tsi148_bridge->master_resources) {
 		master_image = list_entry(pos, struct vme_master_resource,
 			list);
 		list_del(pos);
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 5ceb1cd..7e98403 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -60,7 +60,6 @@
 
 config HDQ_MASTER_OMAP
 	tristate "OMAP HDQ driver"
-	depends on ARCH_OMAP2PLUS
 	help
 	  Say Y here if you want support for the 1-wire or HDQ Interface
 	  on an OMAP processor.
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 530a2d3..7c294f4 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -349,7 +349,7 @@
 			"pass: %d entering ASM\n", pass);
 		ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
 		dev_dbg(&ds1wm_data->pdev->dev,
-			"pass: %d begining nibble loop\n", pass);
+			"pass: %d beginning nibble loop\n", pass);
 
 		r_prime = 0;
 		d = 0;
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index fee195a..ca8e60b 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -18,8 +18,6 @@
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
 
-#include <asm/irq.h>
-
 #include "../w1.h"
 #include "../w1_int.h"
 
@@ -72,11 +70,11 @@
 };
 
 static int __devinit omap_hdq_probe(struct platform_device *pdev);
-static int omap_hdq_remove(struct platform_device *pdev);
+static int __devexit omap_hdq_remove(struct platform_device *pdev);
 
 static struct platform_driver omap_hdq_driver = {
 	.probe =	omap_hdq_probe,
-	.remove =	omap_hdq_remove,
+	.remove =	__devexit_p(omap_hdq_remove),
 	.driver =	{
 		.name =	"omap_hdq",
 	},
@@ -537,39 +535,35 @@
 		hdq_data->init_trans = 0;
 		mutex_unlock(&hdq_data->hdq_mutex);
 	}
-
-	return;
 }
 
 static int __devinit omap_hdq_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct hdq_data *hdq_data;
 	struct resource *res;
 	int ret, irq;
 	u8 rev;
 
-	hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
+	hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
 	if (!hdq_data) {
 		dev_dbg(&pdev->dev, "unable to allocate memory\n");
-		ret = -ENOMEM;
-		goto err_kmalloc;
+		return -ENOMEM;
 	}
 
-	hdq_data->dev = &pdev->dev;
+	hdq_data->dev = dev;
 	platform_set_drvdata(pdev, hdq_data);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_dbg(&pdev->dev, "unable to get resource\n");
-		ret = -ENXIO;
-		goto err_resource;
+		return -ENXIO;
 	}
 
-	hdq_data->hdq_base = ioremap(res->start, SZ_4K);
+	hdq_data->hdq_base = devm_request_and_ioremap(dev, res);
 	if (!hdq_data->hdq_base) {
 		dev_dbg(&pdev->dev, "ioremap failed\n");
-		ret = -EINVAL;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
 
 	hdq_data->hdq_usecount = 0;
@@ -590,7 +584,8 @@
 		goto err_irq;
 	}
 
-	ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data);
+	ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED,
+			"omap_hdq", hdq_data);
 	if (ret < 0) {
 		dev_dbg(&pdev->dev, "could not request irq\n");
 		goto err_irq;
@@ -615,19 +610,10 @@
 err_w1:
 	pm_runtime_disable(&pdev->dev);
 
-	iounmap(hdq_data->hdq_base);
-
-err_ioremap:
-err_resource:
-	platform_set_drvdata(pdev, NULL);
-	kfree(hdq_data);
-
-err_kmalloc:
 	return ret;
-
 }
 
-static int omap_hdq_remove(struct platform_device *pdev)
+static int __devexit omap_hdq_remove(struct platform_device *pdev)
 {
 	struct hdq_data *hdq_data = platform_get_drvdata(pdev);
 
@@ -643,27 +629,11 @@
 
 	/* remove module dependency */
 	pm_runtime_disable(&pdev->dev);
-	free_irq(platform_get_irq(pdev, 0), hdq_data);
-	platform_set_drvdata(pdev, NULL);
-	iounmap(hdq_data->hdq_base);
-	kfree(hdq_data);
 
 	return 0;
 }
 
-static int __init
-omap_hdq_init(void)
-{
-	return platform_driver_register(&omap_hdq_driver);
-}
-module_init(omap_hdq_init);
-
-static void __exit
-omap_hdq_exit(void)
-{
-	platform_driver_unregister(&omap_hdq_driver);
-}
-module_exit(omap_hdq_exit);
+module_platform_driver(omap_hdq_driver);
 
 module_param(w1_id, int, S_IRUSR);
 MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index df600d1..6012c4e 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/w1-gpio.h>
 #include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
@@ -42,12 +44,55 @@
 	return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id w1_gpio_dt_ids[] = {
+	{ .compatible = "w1-gpio" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
+
+static int w1_gpio_probe_dt(struct platform_device *pdev)
+{
+	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(w1_gpio_dt_ids, &pdev->dev);
+
+	if (!of_id)
+		return 0;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (of_get_property(np, "linux,open-drain", NULL))
+		pdata->is_open_drain = 1;
+
+	pdata->pin = of_get_gpio(np, 0);
+	pdata->ext_pullup_enable_pin = of_get_gpio(np, 1);
+	pdev->dev.platform_data = pdata;
+
+	return 0;
+}
+#else
+static int w1_gpio_probe_dt(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
 static int __init w1_gpio_probe(struct platform_device *pdev)
 {
 	struct w1_bus_master *master;
-	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct w1_gpio_platform_data *pdata;
 	int err;
 
+	err = w1_gpio_probe_dt(pdev);
+	if (err < 0)
+		return err;
+
+	pdata = pdev->dev.platform_data;
+
 	if (!pdata)
 		return -ENXIO;
 
@@ -59,6 +104,13 @@
 	if (err)
 		goto free_master;
 
+	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) {
+		err = gpio_request_one(pdata->ext_pullup_enable_pin,
+				       GPIOF_INIT_LOW, "w1 pullup");
+		if (err < 0)
+			goto free_gpio;
+	}
+
 	master->data = pdata;
 	master->read_bit = w1_gpio_read_bit;
 
@@ -72,15 +124,21 @@
 
 	err = w1_add_master_device(master);
 	if (err)
-		goto free_gpio;
+		goto free_gpio_ext_pu;
 
 	if (pdata->enable_external_pullup)
 		pdata->enable_external_pullup(1);
 
+	if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+		gpio_set_value(pdata->ext_pullup_enable_pin, 1);
+
 	platform_set_drvdata(pdev, master);
 
 	return 0;
 
+ free_gpio_ext_pu:
+	if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+		gpio_free(pdata->ext_pullup_enable_pin);
  free_gpio:
 	gpio_free(pdata->pin);
  free_master:
@@ -97,6 +155,9 @@
 	if (pdata->enable_external_pullup)
 		pdata->enable_external_pullup(0);
 
+	if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+		gpio_set_value(pdata->ext_pullup_enable_pin, 0);
+
 	w1_remove_master_device(master);
 	gpio_free(pdata->pin);
 	kfree(master);
@@ -135,6 +196,7 @@
 	.driver = {
 		.name	= "w1-gpio",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(w1_gpio_dt_ids),
 	},
 	.remove	= __exit_p(w1_gpio_remove),
 	.suspend = w1_gpio_suspend,
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 53d7571..ad1bb938 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -237,12 +237,12 @@
 	  here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
 
 config PNX4008_WATCHDOG
-	tristate "PNX4008 and LPC32XX Watchdog"
-	depends on ARCH_PNX4008 || ARCH_LPC32XX
+	tristate "LPC32XX Watchdog"
+	depends on ARCH_LPC32XX
 	select WATCHDOG_CORE
 	help
 	  Say Y here if to include support for the watchdog timer
-	  in the PNX4008 or LPC32XX processor.
+	  in the LPC32XX processor.
 	  This driver can be built as a module by choosing M. The module
 	  will be called pnx4008_wdt.
 
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 1eff743..ae60406 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -814,6 +814,9 @@
 	hpwdt_timer_reg = pci_mem_addr + 0x70;
 	hpwdt_timer_con = pci_mem_addr + 0x72;
 
+	/* Make sure that timer is disabled until /dev/watchdog is opened */
+	hpwdt_stop();
+
 	/* Make sure that we have a valid soft_margin */
 	if (hpwdt_change_timer(soft_margin))
 		hpwdt_change_timer(DEFAULT_MARGIN);
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 59e75d9..c1a4d3b 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -24,7 +24,19 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
-#include <mach/regs-timer.h>
+
+#define KS8695_TMR_OFFSET	(0xF0000 + 0xE400)
+#define KS8695_TMR_VA		(KS8695_IO_VA + KS8695_TMR_OFFSET)
+
+/*
+ * Timer registers
+ */
+#define KS8695_TMCON		(0x00)		/* Timer Control Register */
+#define KS8695_T0TC		(0x08)		/* Timer 0 Timeout Count Register */
+#define TMCON_T0EN		(1 << 0)	/* Timer 0 Enable */
+
+/* Timer0 Timeout Counter Register */
+#define T0TC_WATCHDOG		(0xff)		/* Enable watchdog mode */
 
 #define WDT_DEFAULT_TIME	5	/* seconds */
 #define WDT_MAX_TIME		171	/* seconds */
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 40f7bf1..e6a038a 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -193,7 +193,7 @@
 	int ret;
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
-	struct mpc8xxx_wdt_type *wdt_type;
+	const struct mpc8xxx_wdt_type *wdt_type;
 	u32 freq = fsl_get_sys_freq();
 	bool enabled;
 
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 6aa46a9..3796434 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -128,11 +128,12 @@
 void watchdog_unregister_device(struct watchdog_device *wdd)
 {
 	int ret;
-	int devno = wdd->cdev.dev;
+	int devno;
 
 	if (wdd == NULL)
 		return;
 
+	devno = wdd->cdev.dev;
 	ret = watchdog_dev_unregister(wdd);
 	if (ret)
 		pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index d80bea5..a4a3cab 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -18,7 +18,7 @@
 obj-$(CONFIG_XEN_TMEM)			+= tmem.o
 obj-$(CONFIG_SWIOTLB_XEN)		+= swiotlb-xen.o
 obj-$(CONFIG_XEN_DOM0)			+= pcpu.o
-obj-$(CONFIG_XEN_DOM0)			+= pci.o acpi.o
+obj-$(CONFIG_XEN_DOM0)			+= pci.o dbgp.o acpi.o
 obj-$(CONFIG_XEN_MCE_LOG)		+= mcelog.o
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= xen-pciback/
 obj-$(CONFIG_XEN_PRIVCMD)		+= xen-privcmd.o
diff --git a/drivers/xen/dbgp.c b/drivers/xen/dbgp.c
new file mode 100644
index 0000000..42569c7
--- /dev/null
+++ b/drivers/xen/dbgp.c
@@ -0,0 +1,48 @@
+#include <linux/pci.h>
+#include <linux/usb.h>
+#include <linux/usb/ehci_def.h>
+#include <linux/usb/hcd.h>
+#include <asm/xen/hypercall.h>
+#include <xen/interface/physdev.h>
+#include <xen/xen.h>
+
+static int xen_dbgp_op(struct usb_hcd *hcd, int op)
+{
+	const struct device *ctrlr = hcd_to_bus(hcd)->controller;
+	struct physdev_dbgp_op dbgp;
+
+	if (!xen_initial_domain())
+		return 0;
+
+	dbgp.op = op;
+
+#ifdef CONFIG_PCI
+	if (ctrlr->bus == &pci_bus_type) {
+		const struct pci_dev *pdev = to_pci_dev(ctrlr);
+
+		dbgp.u.pci.seg = pci_domain_nr(pdev->bus);
+		dbgp.u.pci.bus = pdev->bus->number;
+		dbgp.u.pci.devfn = pdev->devfn;
+		dbgp.bus = PHYSDEVOP_DBGP_BUS_PCI;
+	} else
+#endif
+		dbgp.bus = PHYSDEVOP_DBGP_BUS_UNKNOWN;
+
+	return HYPERVISOR_physdev_op(PHYSDEVOP_dbgp_op, &dbgp);
+}
+
+int xen_dbgp_reset_prep(struct usb_hcd *hcd)
+{
+	return xen_dbgp_op(hcd, PHYSDEVOP_DBGP_RESET_PREPARE);
+}
+
+int xen_dbgp_external_startup(struct usb_hcd *hcd)
+{
+	return xen_dbgp_op(hcd, PHYSDEVOP_DBGP_RESET_DONE);
+}
+
+#ifndef CONFIG_EARLY_PRINTK_DBGP
+#include <linux/export.h>
+EXPORT_SYMBOL_GPL(xen_dbgp_reset_prep);
+EXPORT_SYMBOL_GPL(xen_dbgp_external_startup);
+#endif
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 1ffd03b..7f12416 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -314,8 +314,9 @@
 		}
 	}
 
-	err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset,
-				pages, true);
+	err = gnttab_unmap_refs(map->unmap_ops + offset,
+			use_ptemod ? map->kmap_ops + offset : NULL, map->pages + offset,
+			pages);
 	if (err)
 		return err;
 
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 0bfc1ef..0067266 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -870,7 +870,8 @@
 EXPORT_SYMBOL_GPL(gnttab_map_refs);
 
 int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
-		      struct page **pages, unsigned int count, bool clear_pte)
+		      struct gnttab_map_grant_ref *kmap_ops,
+		      struct page **pages, unsigned int count)
 {
 	int i, ret;
 	bool lazy = false;
@@ -888,7 +889,8 @@
 	}
 
 	for (i = 0; i < count; i++) {
-		ret = m2p_remove_override(pages[i], clear_pte);
+		ret = m2p_remove_override(pages[i], kmap_ops ?
+				       &kmap_ops[i] : NULL);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index 0334272..92ff01d 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -871,7 +871,7 @@
 }
 
 /*add xen_pcibk AER handling*/
-static struct pci_error_handlers xen_pcibk_error_handler = {
+static const struct pci_error_handlers xen_pcibk_error_handler = {
 	.error_detected = xen_pcibk_error_detected,
 	.mmio_enabled = xen_pcibk_mmio_enabled,
 	.slot_reset = xen_pcibk_slot_reset,
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 0d195b5..9821b67 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -116,7 +116,7 @@
 #define BTRFS_FREE_SPACE_OBJECTID -11ULL
 
 /*
- * The inode number assigned to the special inode for sotring
+ * The inode number assigned to the special inode for storing
  * free ino cache
  */
 #define BTRFS_FREE_INO_OBJECTID -12ULL
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index ab53005..c9d7036 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -18,7 +18,7 @@
 #ifndef __DELAYED_REF__
 #define __DELAYED_REF__
 
-/* these are the possible values of struct btrfs_delayed_ref->action */
+/* these are the possible values of struct btrfs_delayed_ref_node->action */
 #define BTRFS_ADD_DELAYED_REF    1 /* add one backref to the tree */
 #define BTRFS_DROP_DELAYED_REF   2 /* delete one backref from the tree */
 #define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ec154f9..316b07a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1971,8 +1971,8 @@
 				      ordered_extent->len - 1, NULL, GFP_NOFS);
 
 	/*
-	 * This needs to be dont to make sure anybody waiting knows we are done
-	 * upating everything for this ordered extent.
+	 * This needs to be done to make sure anybody waiting knows we are done
+	 * updating everything for this ordered extent.
 	 */
 	btrfs_remove_ordered_extent(inode, ordered_extent);
 
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index a08306a..2075ddf 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -9,13 +9,14 @@
 	select CRYPTO_ARC4
 	select CRYPTO_ECB
 	select CRYPTO_DES
+	select CRYPTO_SHA256
 	help
 	  This is the client VFS module for the Common Internet File System
 	  (CIFS) protocol which is the successor to the Server Message Block
 	  (SMB) protocol, the native file sharing mechanism for most early
 	  PC operating systems.  The CIFS protocol is fully supported by
-	  file servers such as Windows 2000 (including Windows 2003, NT 4
-	  and Windows XP) as well by Samba (which provides excellent CIFS
+	  file servers such as Windows 2000 (including Windows 2003, Windows 2008,
+	  NT 4 and Windows XP) as well by Samba (which provides excellent CIFS
 	  server support for Linux and many other operating systems). Limited
 	  support for OS/2 and Windows ME and similar servers is provided as
 	  well.
@@ -114,6 +115,13 @@
 	  (such as Samba 3.10 and later) which can negotiate
 	  CIFS POSIX ACL support.  If unsure, say N.
 
+config CIFS_ACL
+	  bool "Provide CIFS ACL support"
+	  depends on CIFS_XATTR && KEYS
+	  help
+	    Allows fetching CIFS/NTFS ACL from the server.  The DACL blob
+	    is handed over to the application/caller.
+
 config CIFS_DEBUG2
 	bool "Enable additional CIFS debugging routines"
 	depends on CIFS
@@ -138,21 +146,6 @@
 	    IP addresses) which is needed for implicit mounts of DFS junction
 	    points. If unsure, say N.
 
-config CIFS_FSCACHE
-	  bool "Provide CIFS client caching support"
-	  depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
-	  help
-	    Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
-	    to be cached locally on disk through the general filesystem cache
-	    manager. If unsure, say N.
-
-config CIFS_ACL
-	  bool "Provide CIFS ACL support"
-	  depends on CIFS_XATTR && KEYS
-	  help
-	    Allows to fetch CIFS/NTFS ACL from the server.  The DACL blob
-	    is handed over to the application/caller.
-
 config CIFS_NFSD_EXPORT
 	  bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)"
 	  depends on CIFS && EXPERIMENTAL && BROKEN
@@ -161,7 +154,7 @@
 
 config CIFS_SMB2
 	bool "SMB2 network file system support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && INET && BROKEN
+	depends on CIFS && EXPERIMENTAL && INET
 	select NLS
 	select KEYS
 	select FSCACHE
@@ -178,3 +171,12 @@
 	  (compared to cifs) due to protocol improvements.
 
 	  Unless you are a developer or tester, say N.
+
+config CIFS_FSCACHE
+	  bool "Provide CIFS client caching support"
+	  depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
+	  help
+	    Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
+	    to be cached locally on disk through the general filesystem cache
+	    manager. If unsure, say N.
+
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index feee943..aa0d68b0 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -17,4 +17,4 @@
 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
 
 cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \
-			    smb2misc.o smb2pdu.o smb2inode.o
+			    smb2misc.o smb2pdu.o smb2inode.o smb2file.o
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 7dab9c0..53cf2aa 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -328,7 +328,7 @@
 	}
 
 ctoUTF16_out:
-	return i;
+	return j;
 }
 
 #ifdef CONFIG_CIFS_SMB2
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 05f4dc2..2ee5c54 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1222,7 +1222,7 @@
 	if (!open_file)
 		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
-	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
+	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
 	cifsFileInfo_put(open_file);
 	return pntsd;
 }
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 6a0d741..652f505 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -29,6 +29,7 @@
 #include "ntlmssp.h"
 #include <linux/ctype.h>
 #include <linux/random.h>
+#include <linux/highmem.h>
 
 /*
  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
@@ -37,11 +38,13 @@
  * the sequence number before this function is called. Also, this function
  * should be called with the server->srv_mutex held.
  */
-static int cifs_calc_signature(const struct kvec *iov, int n_vec,
+static int cifs_calc_signature(struct smb_rqst *rqst,
 			struct TCP_Server_Info *server, char *signature)
 {
 	int i;
 	int rc;
+	struct kvec *iov = rqst->rq_iov;
+	int n_vec = rqst->rq_nvec;
 
 	if (iov == NULL || signature == NULL || server == NULL)
 		return -EINVAL;
@@ -91,6 +94,16 @@
 		}
 	}
 
+	/* now hash over the rq_pages array */
+	for (i = 0; i < rqst->rq_npages; i++) {
+		struct kvec p_iov;
+
+		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
+		crypto_shash_update(&server->secmech.sdescmd5->shash,
+					p_iov.iov_base, p_iov.iov_len);
+		kunmap(rqst->rq_pages[i]);
+	}
+
 	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
 	if (rc)
 		cERROR(1, "%s: Could not generate md5 hash", __func__);
@@ -99,12 +112,12 @@
 }
 
 /* must be called with server->srv_mutex held */
-int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
+int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 		   __u32 *pexpected_response_sequence_number)
 {
 	int rc = 0;
 	char smb_signature[20];
-	struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base;
+	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
 	if ((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
@@ -125,7 +138,7 @@
 	*pexpected_response_sequence_number = server->sequence_number++;
 	server->sequence_number++;
 
-	rc = cifs_calc_signature(iov, n_vec, server, smb_signature);
+	rc = cifs_calc_signature(rqst, server, smb_signature);
 	if (rc)
 		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
 	else
@@ -134,6 +147,15 @@
 	return rc;
 }
 
+int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
+		   __u32 *pexpected_response_sequence)
+{
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = n_vec };
+
+	return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
+}
+
 /* must be called with server->srv_mutex held */
 int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
 		  __u32 *pexpected_response_sequence_number)
@@ -147,14 +169,14 @@
 			      pexpected_response_sequence_number);
 }
 
-int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,
+int cifs_verify_signature(struct smb_rqst *rqst,
 			  struct TCP_Server_Info *server,
 			  __u32 expected_sequence_number)
 {
 	unsigned int rc;
 	char server_response_sig[8];
 	char what_we_think_sig_should_be[20];
-	struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base;
+	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
 	if (cifs_pdu == NULL || server == NULL)
 		return -EINVAL;
@@ -186,8 +208,7 @@
 	cifs_pdu->Signature.Sequence.Reserved = 0;
 
 	mutex_lock(&server->srv_mutex);
-	rc = cifs_calc_signature(iov, nr_iov, server,
-				 what_we_think_sig_should_be);
+	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
 	mutex_unlock(&server->srv_mutex);
 
 	if (rc)
@@ -686,12 +707,17 @@
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
+	if (server->secmech.hmacsha256)
+		crypto_free_shash(server->secmech.hmacsha256);
+
 	if (server->secmech.md5)
 		crypto_free_shash(server->secmech.md5);
 
 	if (server->secmech.hmacmd5)
 		crypto_free_shash(server->secmech.hmacmd5);
 
+	kfree(server->secmech.sdeschmacsha256);
+
 	kfree(server->secmech.sdeschmacmd5);
 
 	kfree(server->secmech.sdescmd5);
@@ -716,6 +742,13 @@
 		goto crypto_allocate_md5_fail;
 	}
 
+	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	if (IS_ERR(server->secmech.hmacsha256)) {
+		cERROR(1, "could not allocate crypto hmacsha256\n");
+		rc = PTR_ERR(server->secmech.hmacsha256);
+		goto crypto_allocate_hmacsha256_fail;
+	}
+
 	size = sizeof(struct shash_desc) +
 			crypto_shash_descsize(server->secmech.hmacmd5);
 	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -727,7 +760,6 @@
 	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
 	server->secmech.sdeschmacmd5->shash.flags = 0x0;
 
-
 	size = sizeof(struct shash_desc) +
 			crypto_shash_descsize(server->secmech.md5);
 	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
@@ -739,12 +771,29 @@
 	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
 	server->secmech.sdescmd5->shash.flags = 0x0;
 
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.hmacsha256);
+	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdeschmacsha256) {
+		cERROR(1, "%s: Can't alloc hmacsha256\n", __func__);
+		rc = -ENOMEM;
+		goto crypto_allocate_hmacsha256_sdesc_fail;
+	}
+	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+	server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
 	return 0;
 
+crypto_allocate_hmacsha256_sdesc_fail:
+	kfree(server->secmech.sdescmd5);
+
 crypto_allocate_md5_sdesc_fail:
 	kfree(server->secmech.sdeschmacmd5);
 
 crypto_allocate_hmacmd5_sdesc_fail:
+	crypto_free_shash(server->secmech.hmacsha256);
+
+crypto_allocate_hmacsha256_fail:
 	crypto_free_shash(server->secmech.md5);
 
 crypto_allocate_md5_fail:
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index db8a404..a41044a 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -36,6 +36,7 @@
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 #include <linux/namei.h>
+#include <linux/random.h>
 #include <net/ipv6.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
@@ -51,7 +52,6 @@
 #ifdef CONFIG_CIFS_SMB2
 #include "smb2pdu.h"
 #endif
-#define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
 
 int cifsFYI = 0;
 int cifsERROR = 1;
@@ -89,6 +89,10 @@
 
 struct workqueue_struct	*cifsiod_wq;
 
+#ifdef CONFIG_CIFS_SMB2
+__u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
+#endif
+
 static int
 cifs_read_super(struct super_block *sb)
 {
@@ -160,13 +164,12 @@
 	struct super_block *sb = dentry->d_sb;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-	int rc = -EOPNOTSUPP;
+	struct TCP_Server_Info *server = tcon->ses->server;
 	unsigned int xid;
+	int rc = 0;
 
 	xid = get_xid();
 
-	buf->f_type = CIFS_MAGIC_NUMBER;
-
 	/*
 	 * PATH_MAX may be too long - it would presumably be total path,
 	 * but note that some servers (includinng Samba 3) have a shorter
@@ -178,27 +181,8 @@
 	buf->f_files = 0;	/* undefined */
 	buf->f_ffree = 0;	/* unlimited */
 
-	/*
-	 * We could add a second check for a QFS Unix capability bit
-	 */
-	if ((tcon->ses->capabilities & CAP_UNIX) &&
-	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
-		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
-
-	/*
-	 * Only need to call the old QFSInfo if failed on newer one,
-	 * e.g. by OS/2.
-	 **/
-	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
-		rc = CIFSSMBQFSInfo(xid, tcon, buf);
-
-	/*
-	 * Some old Windows servers also do not support level 103, retry with
-	 * older level one if old server failed the previous call or we
-	 * bypassed it because we detected that this was an older LANMAN sess
-	 */
-	if (rc)
-		rc = SMBOldQFSInfo(xid, tcon, buf);
+	if (server->ops->queryfs)
+		rc = server->ops->queryfs(xid, tcon, buf);
 
 	free_xid(xid);
 	return 0;
@@ -239,9 +223,10 @@
 		return NULL;
 	cifs_inode->cifsAttrs = 0x20;	/* default */
 	cifs_inode->time = 0;
-	/* Until the file is open and we have gotten oplock
-	info back from the server, can not assume caching of
-	file data or metadata */
+	/*
+	 * Until the file is open and we have gotten oplock info back from the
+	 * server, can not assume caching of file data or metadata.
+	 */
 	cifs_set_oplock_level(cifs_inode, 0);
 	cifs_inode->delete_pending = false;
 	cifs_inode->invalid_mapping = false;
@@ -249,11 +234,16 @@
 	cifs_inode->server_eof = 0;
 	cifs_inode->uniqueid = 0;
 	cifs_inode->createtime = 0;
-
-	/* Can not set i_flags here - they get immediately overwritten
-	   to zero by the VFS */
-/*	cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/
+#ifdef CONFIG_CIFS_SMB2
+	get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
+#endif
+	/*
+	 * Can not set i_flags here - they get immediately overwritten to zero
+	 * by the VFS.
+	 */
+	/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; */
 	INIT_LIST_HEAD(&cifs_inode->openFileList);
+	INIT_LIST_HEAD(&cifs_inode->llist);
 	return &cifs_inode->vfs_inode;
 }
 
@@ -360,7 +350,8 @@
 	cifs_show_security(s, tcon->ses->server);
 	cifs_show_cache_flavor(s, cifs_sb);
 
-	seq_printf(s, ",unc=%s", tcon->treeName);
+	seq_printf(s, ",unc=");
+	seq_escape(s, tcon->treeName, " \t\n\\");
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
 		seq_printf(s, ",multiuser");
@@ -957,7 +948,7 @@
 	struct cifsInodeInfo *cifsi = inode;
 
 	inode_init_once(&cifsi->vfs_inode);
-	mutex_init(&cifsi->lock_mutex);
+	init_rwsem(&cifsi->lock_sem);
 }
 
 static int
@@ -1127,6 +1118,10 @@
 	spin_lock_init(&cifs_file_list_lock);
 	spin_lock_init(&GlobalMid_Lock);
 
+#ifdef CONFIG_CIFS_SMB2
+	get_random_bytes(cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
+#endif
+
 	if (cifs_max_pending < 2) {
 		cifs_max_pending = 2;
 		cFYI(1, "cifs_max_pending set to min of 2");
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 1c49c5a..7163419 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -128,5 +128,5 @@
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "1.78"
+#define CIFS_VERSION   "2.0"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 977dc0e..f5af252 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -32,6 +32,8 @@
 #include "smb2pdu.h"
 #endif
 
+#define CIFS_MAGIC_NUMBER 0xFF534D42      /* the first four bytes of SMB PDUs */
+
 /*
  * The sizes of various internal tables and strings
  */
@@ -128,8 +130,10 @@
 struct cifs_secmech {
 	struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
 	struct crypto_shash *md5; /* md5 hash function */
+	struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
 	struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
 	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
+	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 };
 
 /* per smb session structure/fields */
@@ -158,9 +162,24 @@
  *****************************************************************
  */
 
+/*
+ * A smb_rqst represents a complete request to be issued to a server. It's
+ * formed by a kvec array, followed by an array of pages. Page data is assumed
+ * to start at the beginning of the first page.
+ */
+struct smb_rqst {
+	struct kvec	*rq_iov;	/* array of kvecs */
+	unsigned int	rq_nvec;	/* number of kvecs in array */
+	struct page	**rq_pages;	/* pointer to array of page ptrs */
+	unsigned int	rq_npages;	/* number pages in array */
+	unsigned int	rq_pagesz;	/* page size to use */
+	unsigned int	rq_tailsz;	/* length of last page */
+};
+
 enum smb_version {
 	Smb_1 = 1,
 	Smb_21,
+	Smb_30,
 };
 
 struct mid_q_entry;
@@ -171,17 +190,23 @@
 struct dfs_info3_param;
 struct cifs_fattr;
 struct smb_vol;
+struct cifs_fid;
+struct cifs_readdata;
+struct cifs_writedata;
+struct cifs_io_parms;
+struct cifs_search_info;
+struct cifsInodeInfo;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
 			   struct mid_q_entry *);
 	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 	/* setup request: allocate mid, sign message */
-	int (*setup_request)(struct cifs_ses *, struct kvec *, unsigned int,
-			     struct mid_q_entry **);
+	struct mid_q_entry *(*setup_request)(struct cifs_ses *,
+						struct smb_rqst *);
 	/* setup async request: allocate mid, sign message */
-	int (*setup_async_request)(struct TCP_Server_Info *, struct kvec *,
-				   unsigned int, struct mid_q_entry **);
+	struct mid_q_entry *(*setup_async_request)(struct TCP_Server_Info *,
+						struct smb_rqst *);
 	/* check response: verify signature, map error */
 	int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *,
 			     bool);
@@ -212,6 +237,10 @@
 	bool (*need_neg)(struct TCP_Server_Info *);
 	/* negotiate to the server */
 	int (*negotiate)(const unsigned int, struct cifs_ses *);
+	/* set negotiated write size */
+	unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *);
+	/* set negotiated read size */
+	unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *);
 	/* setup smb sessionn */
 	int (*sess_setup)(const unsigned int, struct cifs_ses *,
 			  const struct nls_table *);
@@ -235,10 +264,22 @@
 	int (*query_path_info)(const unsigned int, struct cifs_tcon *,
 			       struct cifs_sb_info *, const char *,
 			       FILE_ALL_INFO *, bool *);
+	/* query file data from the server */
+	int (*query_file_info)(const unsigned int, struct cifs_tcon *,
+			       struct cifs_fid *, FILE_ALL_INFO *);
 	/* get server index number */
 	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
 			    struct cifs_sb_info *, const char *,
 			    u64 *uniqueid, FILE_ALL_INFO *);
+	/* set size by path */
+	int (*set_path_size)(const unsigned int, struct cifs_tcon *,
+			     const char *, __u64, struct cifs_sb_info *, bool);
+	/* set size by file handle */
+	int (*set_file_size)(const unsigned int, struct cifs_tcon *,
+			     struct cifsFileInfo *, __u64, bool);
+	/* set attributes */
+	int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
+			     const unsigned int);
 	/* build a full path to the root of the mount */
 	char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
 				     struct cifs_tcon *);
@@ -256,10 +297,84 @@
 	/* remove directory */
 	int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
 		     struct cifs_sb_info *);
+	/* unlink file */
+	int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
+		      struct cifs_sb_info *);
+	/* open, rename and delete file */
+	int (*rename_pending_delete)(const char *, struct dentry *,
+				     const unsigned int);
+	/* send rename request */
+	int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
+		      const char *, struct cifs_sb_info *);
+	/* send create hardlink request */
+	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
+			       const char *, const char *,
+			       struct cifs_sb_info *);
+	/* open a file for non-posix mounts */
+	int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
+		    int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
+		    struct cifs_sb_info *);
+	/* set fid protocol-specific info */
+	void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
+	/* close a file */
+	void (*close)(const unsigned int, struct cifs_tcon *,
+		      struct cifs_fid *);
+	/* send a flush request to the server */
+	int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+	/* async read from the server */
+	int (*async_readv)(struct cifs_readdata *);
+	/* async write to the server */
+	int (*async_writev)(struct cifs_writedata *);
+	/* sync read from the server */
+	int (*sync_read)(const unsigned int, struct cifsFileInfo *,
+			 struct cifs_io_parms *, unsigned int *, char **,
+			 int *);
+	/* sync write to the server */
+	int (*sync_write)(const unsigned int, struct cifsFileInfo *,
+			  struct cifs_io_parms *, unsigned int *, struct kvec *,
+			  unsigned long);
+	/* open dir, start readdir */
+	int (*query_dir_first)(const unsigned int, struct cifs_tcon *,
+			       const char *, struct cifs_sb_info *,
+			       struct cifs_fid *, __u16,
+			       struct cifs_search_info *);
+	/* continue readdir */
+	int (*query_dir_next)(const unsigned int, struct cifs_tcon *,
+			      struct cifs_fid *,
+			      __u16, struct cifs_search_info *srch_inf);
+	/* close dir */
+	int (*close_dir)(const unsigned int, struct cifs_tcon *,
+			 struct cifs_fid *);
+	/* calculate a size of SMB message */
+	unsigned int (*calc_smb_size)(void *);
+	/* check for STATUS_PENDING and process it in a positive case */
+	bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+	/* send oplock break response */
+	int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
+			       struct cifsInodeInfo *);
+	/* query remote filesystem */
+	int (*queryfs)(const unsigned int, struct cifs_tcon *,
+		       struct kstatfs *);
+	/* send mandatory brlock to the server */
+	int (*mand_lock)(const unsigned int, struct cifsFileInfo *, __u64,
+			 __u64, __u32, int, int, bool);
+	/* unlock range of mandatory locks */
+	int (*mand_unlock_range)(struct cifsFileInfo *, struct file_lock *,
+				 const unsigned int);
+	/* push brlocks from the cache to the server */
+	int (*push_mand_locks)(struct cifsFileInfo *);
+	/* get lease key of the inode */
+	void (*get_lease_key)(struct inode *, struct cifs_fid *fid);
+	/* set lease key of the inode */
+	void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
+	/* generate new lease key */
+	void (*new_lease_key)(struct cifs_fid *fid);
 };
 
 struct smb_version_values {
 	char		*version_string;
+	__u16		protocol_id;
+	__u32		req_capabilities;
 	__u32		large_lock_type;
 	__u32		exclusive_lock_type;
 	__u32		shared_lock_type;
@@ -496,6 +611,51 @@
 }
 
 /*
+ * When the server supports very large reads and writes via POSIX extensions,
+ * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
+ * including the RFC1001 length.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however as we have to allocate an array of pointers for the
+ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ *
+ * For reads, there is a similar problem as we need to allocate an array
+ * of kvecs to handle the receive, though that should only need to be done
+ * once.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
+
+/*
+ * When the server doesn't allow large posix writes, only allow a rsize/wsize
+ * of 2^17-1 minus the size of the call header. That allows for a read or
+ * write up to the maximum size described by RFC1002.
+ */
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+
+/*
+ * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
+ * those values when posix extensions aren't in force. In actuality here, we
+ * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
+ * to be ok with the extra byte even though Windows doesn't send writes that
+ * are that large.
+ *
+ * Citation:
+ *
+ * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
+ */
+#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
+#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
+
+/*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
  */
@@ -559,6 +719,7 @@
 	__u16 session_flags;
 #endif /* CONFIG_CIFS_SMB2 */
 };
+
 /* no more than one of the following three session flags may be set */
 #define CIFS_SES_NT4 1
 #define CIFS_SES_OS2 2
@@ -665,6 +826,7 @@
 	u64 resource_id;		/* server resource id */
 	struct fscache_cookie *fscache;	/* cookie for share */
 #endif
+	struct list_head pending_opens;	/* list of incomplete opens */
 	/* BB add field for back pointer to sb struct(s)? */
 };
 
@@ -707,6 +869,15 @@
 /* This function is always expected to succeed */
 extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
 
+#define CIFS_OPLOCK_NO_CHANGE 0xfe
+
+struct cifs_pending_open {
+	struct list_head olist;
+	struct tcon_link *tlink;
+	__u8 lease_key[16];
+	__u32 oplock;
+};
+
 /*
  * This info hangs off the cifsFileInfo structure, pointed to by llist.
  * This is used to track byte stream locks on the file
@@ -740,16 +911,29 @@
 	bool smallBuf:1; /* so we know which buf_release function to call */
 };
 
+struct cifs_fid {
+	__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+	__u64 persistent_fid;	/* persist file id for smb2 */
+	__u64 volatile_fid;	/* volatile file id for smb2 */
+	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for smb2 */
+#endif
+	struct cifs_pending_open *pending_open;
+};
+
+struct cifs_fid_locks {
+	struct list_head llist;
+	struct cifsFileInfo *cfile;	/* fid that owns locks */
+	struct list_head locks;		/* locks held by fid above */
+};
+
 struct cifsFileInfo {
 	struct list_head tlist;	/* pointer to next fid owned by tcon */
 	struct list_head flist;	/* next fid (file instance) for this inode */
-	struct list_head llist;	/*
-				 * brlocks held by this fid, protected by
-				 * lock_mutex from cifsInodeInfo structure
-				 */
+	struct cifs_fid_locks *llist;	/* brlocks held by this fid */
 	unsigned int uid;	/* allows finding which FileInfo structure */
 	__u32 pid;		/* process id who opened file */
-	__u16 netfid;		/* file id from remote */
+	struct cifs_fid fid;	/* file id from remote */
 	/* BB add lock scope info here if needed */ ;
 	/* lock scope id (0 if none) */
 	struct dentry *dentry;
@@ -765,12 +949,60 @@
 
 struct cifs_io_parms {
 	__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+	__u64 persistent_fid;	/* persist file id for smb2 */
+	__u64 volatile_fid;	/* volatile file id for smb2 */
+#endif
 	__u32 pid;
 	__u64 offset;
 	unsigned int length;
 	struct cifs_tcon *tcon;
 };
 
+struct cifs_readdata;
+
+/* asynchronous read support */
+struct cifs_readdata {
+	struct kref			refcount;
+	struct list_head		list;
+	struct completion		done;
+	struct cifsFileInfo		*cfile;
+	struct address_space		*mapping;
+	__u64				offset;
+	unsigned int			bytes;
+	pid_t				pid;
+	int				result;
+	struct work_struct		work;
+	int (*read_into_pages)(struct TCP_Server_Info *server,
+				struct cifs_readdata *rdata,
+				unsigned int len);
+	struct kvec			iov;
+	unsigned int			pagesz;
+	unsigned int			tailsz;
+	unsigned int			nr_pages;
+	struct page			*pages[];
+};
+
+struct cifs_writedata;
+
+/* asynchronous write support */
+struct cifs_writedata {
+	struct kref			refcount;
+	struct list_head		list;
+	struct completion		done;
+	enum writeback_sync_modes	sync_mode;
+	struct work_struct		work;
+	struct cifsFileInfo		*cfile;
+	__u64				offset;
+	pid_t				pid;
+	unsigned int			bytes;
+	int				result;
+	unsigned int			pagesz;
+	unsigned int			tailsz;
+	unsigned int			nr_pages;
+	struct page			*pages[1];
+};
+
 /*
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
@@ -790,11 +1022,8 @@
 
 struct cifsInodeInfo {
 	bool can_cache_brlcks;
-	struct mutex lock_mutex;	/*
-					 * protect the field above and llist
-					 * from every cifsFileInfo structure
-					 * from openFileList
-					 */
+	struct list_head llist;	/* locks helb by this inode */
+	struct rw_semaphore lock_sem;	/* protect the fields above */
 	/* BB add in lists for dirty pages i.e. write caching info for oplock */
 	struct list_head openFileList;
 	__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
@@ -806,6 +1035,9 @@
 	u64  server_eof;		/* current file size on server -- protected by i_lock */
 	u64  uniqueid;			/* server inode number */
 	u64  createtime;		/* creation time on server */
+#ifdef CONFIG_CIFS_SMB2
+	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for this inode */
+#endif
 #ifdef CONFIG_CIFS_FSCACHE
 	struct fscache_cookie *fscache;
 #endif
@@ -1130,7 +1362,7 @@
 #define   CIFSSEC_MUST_SEAL	0x40040 /* not supported yet */
 #define   CIFSSEC_MUST_NTLMSSP	0x80080 /* raw ntlmssp with ntlmv2 */
 
-#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
+#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP)
 #define   CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
 #define   CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
 /*
@@ -1267,7 +1499,13 @@
 #define SMB1_VERSION_STRING	"1.0"
 extern struct smb_version_operations smb1_operations;
 extern struct smb_version_values smb1_values;
+#define SMB20_VERSION_STRING	"2.0"
+/*extern struct smb_version_operations smb20_operations; */ /* not needed yet */
+extern struct smb_version_values smb20_values;
 #define SMB21_VERSION_STRING	"2.1"
 extern struct smb_version_operations smb21_operations;
 extern struct smb_version_values smb21_values;
+#define SMB30_VERSION_STRING	"3.0"
+/*extern struct smb_version_operations smb30_operations; */ /* not needed yet */
+extern struct smb_version_values smb30_values;
 #endif	/* _CIFS_GLOB_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 3fb03e2..b9d59a9 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -2210,7 +2210,7 @@
 	__u8 DeletePending;
 	__u8 Directory;
 	__u16 Pad2;
-	__u64 IndexNumber;
+	__le64 IndexNumber;
 	__le32 EASize;
 	__le32 AccessFlags;
 	__u64 IndexNumber1;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index f1bbf83..5144e9fb 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -24,6 +24,7 @@
 
 struct statfs;
 struct smb_vol;
+struct smb_rqst;
 
 /*
  *****************************************************************
@@ -35,6 +36,8 @@
 extern void cifs_buf_release(void *);
 extern struct smb_hdr *cifs_small_buf_get(void);
 extern void cifs_small_buf_release(void *);
+extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
+					struct kvec *iov);
 extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
 			unsigned int /* length */);
 extern unsigned int _get_xid(void);
@@ -65,21 +68,22 @@
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
 					struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
-extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
-			   unsigned int nvec, mid_receive_t *receive,
-			   mid_callback_t *callback, void *cbdata,
-			   const int flags);
+extern int cifs_call_async(struct TCP_Server_Info *server,
+			struct smb_rqst *rqst,
+			mid_receive_t *receive, mid_callback_t *callback,
+			void *cbdata, const int flags);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 			    char *in_buf, int flags);
-extern int cifs_setup_request(struct cifs_ses *, struct kvec *, unsigned int,
-			      struct mid_q_entry **);
-extern int cifs_setup_async_request(struct TCP_Server_Info *, struct kvec *,
-				    unsigned int, struct mid_q_entry **);
+extern struct mid_q_entry *cifs_setup_request(struct cifs_ses *,
+				struct smb_rqst *);
+extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
+						struct smb_rqst *);
 extern int cifs_check_receive(struct mid_q_entry *mid,
 			struct TCP_Server_Info *server, bool log_error);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
@@ -99,7 +103,7 @@
 			    unsigned int bytes_written);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize(void *buf);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			struct TCP_Server_Info *server);
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
@@ -120,10 +124,14 @@
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
 				      int offset);
 extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
+extern int cifs_unlock_range(struct cifsFileInfo *cfile,
+			     struct file_lock *flock, const unsigned int xid);
+extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
 
-extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
-				struct file *file, struct tcon_link *tlink,
-				__u32 oplock);
+extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
+					      struct file *file,
+					      struct tcon_link *tlink,
+					      __u32 oplock);
 extern int cifs_posix_open(char *full_path, struct inode **inode,
 			   struct super_block *sb, int mode,
 			   unsigned int f_flags, __u32 *oplock, __u16 *netfid,
@@ -132,18 +140,23 @@
 extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
 				     FILE_UNIX_BASIC_INFO *info,
 				     struct cifs_sb_info *cifs_sb);
+extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *,
+					struct cifs_sb_info *);
 extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
 extern struct inode *cifs_iget(struct super_block *sb,
 			       struct cifs_fattr *fattr);
 
-extern int cifs_get_file_info(struct file *filp);
 extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			       FILE_ALL_INFO *data, struct super_block *sb,
 			       int xid, const __u16 *fid);
-extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
 			struct super_block *sb, unsigned int xid);
+extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+			      unsigned int xid, char *full_path, __u32 dosattr);
+extern int cifs_rename_pending_delete(const char *full_path,
+				      struct dentry *dentry,
+				      const unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
 			      struct cifs_fattr *fattr, struct inode *inode,
 			      const char *path, const __u16 *pfid);
@@ -169,6 +182,17 @@
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
 extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
+extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
+				    __u64 length, __u8 type,
+				    struct cifsLockInfo **conf_lock,
+				    bool rw_check);
+extern void cifs_add_pending_open(struct cifs_fid *fid,
+				  struct tcon_link *tlink,
+				  struct cifs_pending_open *open);
+extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
+					 struct tcon_link *tlink,
+					 struct cifs_pending_open *open);
+extern void cifs_del_pending_open(struct cifs_pending_open *open);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
@@ -179,6 +203,10 @@
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
+extern void cifs_move_llist(struct list_head *source, struct list_head *dest);
+extern void cifs_free_llist(struct list_head *llist);
+extern void cifs_del_lock_waiters(struct cifsLockInfo *lock);
+
 extern int cifs_negotiate_protocol(const unsigned int xid,
 				   struct cifs_ses *ses);
 extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
@@ -190,10 +218,10 @@
 		    const struct nls_table *);
 
 extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
-		const char *searchName, const struct nls_table *nls_codepage,
+		const char *searchName, struct cifs_sb_info *cifs_sb,
 		__u16 *searchHandle, __u16 search_flags,
 		struct cifs_search_info *psrch_inf,
-		int map, const char dirsep);
+		bool msearch);
 
 extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
 		__u16 searchHandle, __u16 search_flags,
@@ -265,13 +293,11 @@
 			const struct nls_table *nls_codepage);
 #endif /* possibly unneeded function */
 extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *fileName, __u64 size,
-			bool setAllocationSizeFlag,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			 const char *file_name, __u64 size,
+			 struct cifs_sb_info *cifs_sb, bool set_allocation);
 extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
-			 __u64 size, __u16 fileHandle, __u32 opener_pid,
-			bool AllocSizeFlag);
+			      struct cifsFileInfo *cfile, __u64 size,
+			      bool set_allocation);
 
 struct cifs_unix_set_info_args {
 	__u64	ctime;
@@ -303,22 +329,17 @@
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *name,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			  const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+			 const char *from_name, const char *to_name,
+			 struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
 				 int netfid, const char *target_name,
 				 const struct nls_table *nls_codepage,
 				 int remap_special_chars);
-extern int CIFSCreateHardLink(const unsigned int xid,
-			struct cifs_tcon *tcon,
-			const char *fromName, const char *toName,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+			      const char *from_name, const char *to_name,
+			      struct cifs_sb_info *cifs_sb);
 extern int CIFSUnixCreateHardLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
@@ -367,8 +388,7 @@
 			unsigned int *nbytes, const char *buf,
 			const char __user *ubuf, const int long_op);
 extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-			unsigned int *nbytes, struct kvec *iov, const int nvec,
-			const int long_op);
+			unsigned int *nbytes, struct kvec *iov, const int nvec);
 extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
 				 const char *search_name, __u64 *inode_number,
 				 const struct nls_table *nls_codepage,
@@ -397,10 +417,12 @@
 extern struct cifs_tcon *tconInfoAlloc(void);
 extern void tconInfoFree(struct cifs_tcon *);
 
-extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
+extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+		   __u32 *pexpected_response_sequence_number);
 extern int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
 			  __u32 *);
-extern int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
+extern int cifs_verify_signature(struct smb_rqst *rqst,
 				 struct TCP_Server_Info *server,
 				__u32 expected_sequence_number);
 extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
@@ -462,45 +484,9 @@
 extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
 			unsigned char *p24);
 
-/* asynchronous read support */
-struct cifs_readdata {
-	struct kref			refcount;
-	struct list_head		list;
-	struct completion		done;
-	struct cifsFileInfo		*cfile;
-	struct address_space		*mapping;
-	__u64				offset;
-	unsigned int			bytes;
-	pid_t				pid;
-	int				result;
-	struct list_head		pages;
-	struct work_struct		work;
-	int (*marshal_iov) (struct cifs_readdata *rdata,
-			    unsigned int remaining);
-	unsigned int			nr_iov;
-	struct kvec			iov[1];
-};
-
 void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
-
-/* asynchronous write support */
-struct cifs_writedata {
-	struct kref			refcount;
-	struct list_head		list;
-	struct completion		done;
-	enum writeback_sync_modes	sync_mode;
-	struct work_struct		work;
-	struct cifsFileInfo		*cfile;
-	__u64				offset;
-	pid_t				pid;
-	unsigned int			bytes;
-	int				result;
-	void (*marshal_iov) (struct kvec *iov,
-			     struct cifs_writedata *wdata);
-	unsigned int			nr_pages;
-	struct page			*pages[1];
-};
+int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
 int cifs_async_writev(struct cifs_writedata *wdata);
 void cifs_writev_complete(struct work_struct *work);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f0cf934..76d0d29 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -86,32 +86,6 @@
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-#ifdef CONFIG_HIGHMEM
-/*
- * On arches that have high memory, kmap address space is limited. By
- * serializing the kmap operations on those arches, we ensure that we don't
- * end up with a bunch of threads in writeback with partially mapped page
- * arrays, stuck waiting for kmap to come back. That situation prevents
- * progress and can deadlock.
- */
-static DEFINE_MUTEX(cifs_kmap_mutex);
-
-static inline void
-cifs_kmap_lock(void)
-{
-	mutex_lock(&cifs_kmap_mutex);
-}
-
-static inline void
-cifs_kmap_unlock(void)
-{
-	mutex_unlock(&cifs_kmap_mutex);
-}
-#else /* !CONFIG_HIGHMEM */
-#define cifs_kmap_lock() do { ; } while(0)
-#define cifs_kmap_unlock() do { ; } while(0)
-#endif /* CONFIG_HIGHMEM */
-
 /*
  * Mark as invalid, all open files on tree connections since they
  * were closed when session to server was lost.
@@ -751,6 +725,8 @@
 	ECHO_REQ *smb;
 	int rc = 0;
 	struct kvec iov;
+	struct smb_rqst rqst = { .rq_iov = &iov,
+				 .rq_nvec = 1 };
 
 	cFYI(1, "In echo request");
 
@@ -768,7 +744,7 @@
 	iov.iov_base = smb;
 	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-	rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
+	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
 			     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
 	if (rc)
 		cFYI(1, "Echo request failed: %d", rc);
@@ -902,15 +878,15 @@
 }
 
 int
-CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-	       const char *fileName, const struct nls_table *nls_codepage,
-	       int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	       struct cifs_sb_info *cifs_sb)
 {
 	DELETE_FILE_REQ *pSMB = NULL;
 	DELETE_FILE_RSP *pSMBr = NULL;
 	int rc = 0;
 	int bytes_returned;
 	int name_len;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 DelFileRetry:
 	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -919,15 +895,15 @@
 		return rc;
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
-				       PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
+					      PATH_MAX, cifs_sb->local_nls,
+					      remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {		/* BB improve check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->fileName, fileName, name_len);
+		strncpy(pSMB->fileName, name, name_len);
 	}
 	pSMB->SearchAttributes =
 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
@@ -1440,7 +1416,7 @@
 	return 0;
 }
 
-static int
+int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	int length, len;
@@ -1460,10 +1436,10 @@
 	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
 							HEADER_SIZE(server) + 1;
 
-	rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
-	rdata->iov[0].iov_len = len;
+	rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
+	rdata->iov.iov_len = len;
 
-	length = cifs_readv_from_socket(server, rdata->iov, 1, len);
+	length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
 	if (length < 0)
 		return length;
 	server->total_read += length;
@@ -1509,19 +1485,19 @@
 	len = data_offset - server->total_read;
 	if (len > 0) {
 		/* read any junk before data into the rest of smallbuf */
-		rdata->iov[0].iov_base = buf + server->total_read;
-		rdata->iov[0].iov_len = len;
-		length = cifs_readv_from_socket(server, rdata->iov, 1, len);
+		rdata->iov.iov_base = buf + server->total_read;
+		rdata->iov.iov_len = len;
+		length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
 		if (length < 0)
 			return length;
 		server->total_read += length;
 	}
 
 	/* set up first iov for signature check */
-	rdata->iov[0].iov_base = buf;
-	rdata->iov[0].iov_len = server->total_read;
+	rdata->iov.iov_base = buf;
+	rdata->iov.iov_len = server->total_read;
 	cFYI(1, "0: iov_base=%p iov_len=%zu",
-		rdata->iov[0].iov_base, rdata->iov[0].iov_len);
+		rdata->iov.iov_base, rdata->iov.iov_len);
 
 	/* how much data is in the response? */
 	data_len = server->ops->read_data_length(buf);
@@ -1531,23 +1507,11 @@
 		return cifs_readv_discard(server, mid);
 	}
 
-	/* marshal up the page array */
-	cifs_kmap_lock();
-	len = rdata->marshal_iov(rdata, data_len);
-	cifs_kmap_unlock();
-	data_len -= len;
+	length = rdata->read_into_pages(server, rdata, data_len);
+	if (length < 0)
+		return length;
 
-	/* issue the read if we have any iovecs left to fill */
-	if (rdata->nr_iov > 1) {
-		length = cifs_readv_from_socket(server, &rdata->iov[1],
-						rdata->nr_iov - 1, len);
-		if (length < 0)
-			return length;
-		server->total_read += length;
-	} else {
-		length = 0;
-	}
-
+	server->total_read += length;
 	rdata->bytes = length;
 
 	cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
@@ -1567,6 +1531,12 @@
 	struct cifs_readdata *rdata = mid->callback_data;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
+	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
+				 .rq_nvec = 1,
+				 .rq_pages = rdata->pages,
+				 .rq_npages = rdata->nr_pages,
+				 .rq_pagesz = rdata->pagesz,
+				 .rq_tailsz = rdata->tailsz };
 
 	cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
 		mid->mid, mid->mid_state, rdata->result, rdata->bytes);
@@ -1578,9 +1548,8 @@
 		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
 			int rc = 0;
 
-			rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
-						   server,
-						   mid->sequence_number + 1);
+			rc = cifs_verify_signature(&rqst, server,
+						  mid->sequence_number + 1);
 			if (rc)
 				cERROR(1, "SMB signature verification returned "
 				       "error = %d", rc);
@@ -1610,6 +1579,8 @@
 	READ_REQ *smb = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
+				 .rq_nvec = 1 };
 
 	cFYI(1, "%s: offset=%llu bytes=%u", __func__,
 		rdata->offset, rdata->bytes);
@@ -1632,7 +1603,7 @@
 	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
 
 	smb->AndXCommand = 0xFF;	/* none */
-	smb->Fid = rdata->cfile->netfid;
+	smb->Fid = rdata->cfile->fid.netfid;
 	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
 	if (wct == 12)
 		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
@@ -1649,13 +1620,12 @@
 	}
 
 	/* 4 for RFC1001 length + 1 for BCC */
-	rdata->iov[0].iov_base = smb;
-	rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
+	rdata->iov.iov_base = smb;
+	rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
 	kref_get(&rdata->refcount);
-	rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
-			     cifs_readv_receive, cifs_readv_callback,
-			     rdata, 0);
+	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
+			     cifs_readv_callback, rdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
@@ -1926,6 +1896,7 @@
 {
 	int i, rc;
 	struct inode *inode = wdata->cfile->dentry->d_inode;
+	struct TCP_Server_Info *server;
 
 	for (i = 0; i < wdata->nr_pages; i++) {
 		lock_page(wdata->pages[i]);
@@ -1933,7 +1904,8 @@
 	}
 
 	do {
-		rc = cifs_async_writev(wdata);
+		server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+		rc = server->ops->async_writev(wdata);
 	} while (rc == -EAGAIN);
 
 	for (i = 0; i < wdata->nr_pages; i++) {
@@ -2053,11 +2025,12 @@
 int
 cifs_async_writev(struct cifs_writedata *wdata)
 {
-	int i, rc = -EACCES;
+	int rc = -EACCES;
 	WRITE_REQ *smb = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
-	struct kvec *iov = NULL;
+	struct kvec iov;
+	struct smb_rqst rqst = { };
 
 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
 		wct = 14;
@@ -2073,18 +2046,11 @@
 	if (rc)
 		goto async_writev_out;
 
-	/* 1 iov per page + 1 for header */
-	iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
-	if (iov == NULL) {
-		rc = -ENOMEM;
-		goto async_writev_out;
-	}
-
 	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
 	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
 
 	smb->AndXCommand = 0xFF;	/* none */
-	smb->Fid = wdata->cfile->netfid;
+	smb->Fid = wdata->cfile->fid.netfid;
 	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
 	if (wct == 14)
 		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
@@ -2096,18 +2062,15 @@
 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
 	/* 4 for RFC1001 length + 1 for BCC */
-	iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
-	iov[0].iov_base = smb;
+	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
+	iov.iov_base = smb;
 
-	/*
-	 * This function should marshal up the page array into the kvec
-	 * array, reserving [0] for the header. It should kmap the pages
-	 * and set the iov_len properly for each one. It may also set
-	 * wdata->bytes too.
-	 */
-	cifs_kmap_lock();
-	wdata->marshal_iov(iov, wdata);
-	cifs_kmap_unlock();
+	rqst.rq_iov = &iov;
+	rqst.rq_nvec = 1;
+	rqst.rq_pages = wdata->pages;
+	rqst.rq_npages = wdata->nr_pages;
+	rqst.rq_pagesz = wdata->pagesz;
+	rqst.rq_tailsz = wdata->tailsz;
 
 	cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
 
@@ -2123,32 +2086,26 @@
 				(struct smb_com_writex_req *)smb;
 		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
 		put_bcc(wdata->bytes + 5, &smbw->hdr);
-		iov[0].iov_len += 4; /* pad bigger by four bytes */
+		iov.iov_len += 4; /* pad bigger by four bytes */
 	}
 
 	kref_get(&wdata->refcount);
-	rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
-			     NULL, cifs_writev_callback, wdata, 0);
+	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
+				cifs_writev_callback, wdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 	else
 		kref_put(&wdata->refcount, cifs_writedata_release);
 
-	/* send is done, unmap pages */
-	for (i = 0; i < wdata->nr_pages; i++)
-		kunmap(wdata->pages[i]);
-
 async_writev_out:
 	cifs_small_buf_release(smb);
-	kfree(iov);
 	return rc;
 }
 
 int
 CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-	      unsigned int *nbytes, struct kvec *iov, int n_vec,
-	      const int long_op)
+	      unsigned int *nbytes, struct kvec *iov, int n_vec)
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
@@ -2219,8 +2176,7 @@
 		iov[0].iov_len = smb_hdr_len + 8;
 
 
-	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
-			  long_op);
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
 	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 	if (rc) {
 		cFYI(1, "Send error Write2 = %d", rc);
@@ -2557,8 +2513,8 @@
 
 int
 CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-	      const char *fromName, const char *toName,
-	      const struct nls_table *nls_codepage, int remap)
+	      const char *from_name, const char *to_name,
+	      struct cifs_sb_info *cifs_sb)
 {
 	int rc = 0;
 	RENAME_REQ *pSMB = NULL;
@@ -2566,6 +2522,7 @@
 	int bytes_returned;
 	int name_len, name_len2;
 	__u16 count;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSSMBRename");
 renameRetry:
@@ -2580,9 +2537,9 @@
 			ATTR_DIRECTORY);
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-				       PATH_MAX, nls_codepage, remap);
+		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
+					      from_name, PATH_MAX,
+					      cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 		pSMB->OldFileName[name_len] = 0x04;	/* pad */
@@ -2590,17 +2547,18 @@
 		pSMB->OldFileName[name_len + 1] = 0x00;
 		name_len2 =
 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-				       toName, PATH_MAX, nls_codepage, remap);
+				       to_name, PATH_MAX, cifs_sb->local_nls,
+				       remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fromName, PATH_MAX);
+		name_len = strnlen(from_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->OldFileName, fromName, name_len);
-		name_len2 = strnlen(toName, PATH_MAX);
+		strncpy(pSMB->OldFileName, from_name, name_len);
+		name_len2 = strnlen(to_name, PATH_MAX);
 		name_len2++;	/* trailing null */
 		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
 		name_len2++;	/* trailing null */
 		name_len2++;	/* signature byte */
 	}
@@ -2948,8 +2906,8 @@
 
 int
 CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
-		   const char *fromName, const char *toName,
-		   const struct nls_table *nls_codepage, int remap)
+		   const char *from_name, const char *to_name,
+		   struct cifs_sb_info *cifs_sb)
 {
 	int rc = 0;
 	NT_RENAME_REQ *pSMB = NULL;
@@ -2957,6 +2915,7 @@
 	int bytes_returned;
 	int name_len, name_len2;
 	__u16 count;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 	cFYI(1, "In CIFSCreateHardLink");
 winCreateHardLinkRetry:
@@ -2976,8 +2935,8 @@
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-				       PATH_MAX, nls_codepage, remap);
+		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
+				       PATH_MAX, cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 
@@ -2986,17 +2945,18 @@
 		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
 		name_len2 =
 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-				       toName, PATH_MAX, nls_codepage, remap);
+				       to_name, PATH_MAX, cifs_sb->local_nls,
+				       remap);
 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
 		name_len2 *= 2;	/* convert to bytes */
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fromName, PATH_MAX);
+		name_len = strnlen(from_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->OldFileName, fromName, name_len);
-		name_len2 = strnlen(toName, PATH_MAX);
+		strncpy(pSMB->OldFileName, from_name, name_len);
+		name_len2 = strnlen(to_name, PATH_MAX);
 		name_len2++;	/* trailing null */
 		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
-		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
 		name_len2++;	/* trailing null */
 		name_len2++;	/* signature byte */
 	}
@@ -4254,10 +4214,9 @@
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
 CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
-	      const char *searchName,
-	      const struct nls_table *nls_codepage,
+	      const char *searchName, struct cifs_sb_info *cifs_sb,
 	      __u16 *pnetfid, __u16 search_flags,
-	      struct cifs_search_info *psrch_inf, int remap, const char dirsep)
+	      struct cifs_search_info *psrch_inf, bool msearch)
 {
 /* level 257 SMB_ */
 	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -4265,8 +4224,9 @@
 	T2_FFIRST_RSP_PARMS *parms;
 	int rc = 0;
 	int bytes_returned = 0;
-	int name_len;
+	int name_len, remap;
 	__u16 params, byte_count;
+	struct nls_table *nls_codepage;
 
 	cFYI(1, "In FindFirst for %s", searchName);
 
@@ -4276,6 +4236,9 @@
 	if (rc)
 		return rc;
 
+	nls_codepage = cifs_sb->local_nls;
+	remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
@@ -4284,24 +4247,29 @@
 		it got remapped to 0xF03A as if it were part of the
 		directory name instead of a wildcard */
 		name_len *= 2;
-		pSMB->FileName[name_len] = dirsep;
-		pSMB->FileName[name_len+1] = 0;
-		pSMB->FileName[name_len+2] = '*';
-		pSMB->FileName[name_len+3] = 0;
-		name_len += 4; /* now the trailing null */
-		pSMB->FileName[name_len] = 0; /* null terminate just in case */
-		pSMB->FileName[name_len+1] = 0;
-		name_len += 2;
+		if (msearch) {
+			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
+			pSMB->FileName[name_len+1] = 0;
+			pSMB->FileName[name_len+2] = '*';
+			pSMB->FileName[name_len+3] = 0;
+			name_len += 4; /* now the trailing null */
+			/* null terminate just in case */
+			pSMB->FileName[name_len] = 0;
+			pSMB->FileName[name_len+1] = 0;
+			name_len += 2;
+		}
 	} else {	/* BB add check for overrun of SMB buf BB */
 		name_len = strnlen(searchName, PATH_MAX);
 /* BB fix here and in unicode clause above ie
 		if (name_len > buffersize-header)
 			free buffer exit; BB */
 		strncpy(pSMB->FileName, searchName, name_len);
-		pSMB->FileName[name_len] = dirsep;
-		pSMB->FileName[name_len+1] = '*';
-		pSMB->FileName[name_len+2] = 0;
-		name_len += 3;
+		if (msearch) {
+			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
+			pSMB->FileName[name_len+1] = '*';
+			pSMB->FileName[name_len+2] = 0;
+			name_len += 3;
+		}
 	}
 
 	params = 12 + name_len /* includes null */ ;
@@ -4389,7 +4357,8 @@
 			psrch_inf->last_entry = psrch_inf->srch_entries_start +
 							lnoff;
 
-			*pnetfid = parms->SearchHandle;
+			if (pnetfid)
+				*pnetfid = parms->SearchHandle;
 		} else {
 			cifs_buf_release(pSMB);
 		}
@@ -5417,16 +5386,16 @@
 }
 
 
-/* We can not use write of zero bytes trick to
-   set file size due to need for large file support.  Also note that
-   this SetPathInfo is preferred to SetFileInfo based method in next
-   routine which is only needed to work around a sharing violation bug
-   in Samba which this routine can run into */
-
+/*
+ * We can not use write of zero bytes trick to set file size due to need for
+ * large file support. Also note that this SetPathInfo is preferred to
+ * SetFileInfo based method in next routine which is only needed to work around
+ * a sharing violation bugin Samba which this routine can run into.
+ */
 int
 CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-	      const char *fileName, __u64 size, bool SetAllocation,
-	      const struct nls_table *nls_codepage, int remap)
+	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
+	      bool set_allocation)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5434,6 +5403,8 @@
 	int name_len;
 	int rc = 0;
 	int bytes_returned = 0;
+	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
 	__u16 params, byte_count, data_count, param_offset, offset;
 
 	cFYI(1, "In SetEOF");
@@ -5445,14 +5416,14 @@
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
-				       PATH_MAX, nls_codepage, remap);
+		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
+				       PATH_MAX, cifs_sb->local_nls, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(file_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, fileName, name_len);
+		strncpy(pSMB->FileName, file_name, name_len);
 	}
 	params = 6 + name_len;
 	data_count = sizeof(struct file_end_of_file_info);
@@ -5466,7 +5437,7 @@
 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
 				InformationLevel) - 4;
 	offset = param_offset + params;
-	if (SetAllocation) {
+	if (set_allocation) {
 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
 			pSMB->InformationLevel =
 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
@@ -5513,8 +5484,8 @@
 }
 
 int
-CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
-		   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
+CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
 	struct file_end_of_file_info *parm_data;
@@ -5528,8 +5499,8 @@
 	if (rc)
 		return rc;
 
-	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
 
 	params = 6;
 	pSMB->MaxSetupCount = 0;
@@ -5558,8 +5529,8 @@
 				+ offset);
 	pSMB->DataOffset = cpu_to_le16(offset);
 	parm_data->FileSize = cpu_to_le64(size);
-	pSMB->Fid = fid;
-	if (SetAllocation) {
+	pSMB->Fid = cfile->fid.netfid;
+	if (set_allocation) {
 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
 			pSMB->InformationLevel =
 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6df6fa1..2fdbe08 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -82,8 +82,7 @@
 	Opt_serverino, Opt_noserverino,
 	Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
 	Opt_acl, Opt_noacl, Opt_locallease,
-	Opt_sign, Opt_seal, Opt_direct,
-	Opt_strictcache, Opt_noac,
+	Opt_sign, Opt_seal, Opt_noac,
 	Opt_fsc, Opt_mfsymlinks,
 	Opt_multiuser, Opt_sloppy,
 
@@ -160,10 +159,6 @@
 	{ Opt_locallease, "locallease" },
 	{ Opt_sign, "sign" },
 	{ Opt_seal, "seal" },
-	{ Opt_direct, "direct" },
-	{ Opt_direct, "directio" },
-	{ Opt_direct, "forcedirectio" },
-	{ Opt_strictcache, "strictcache" },
 	{ Opt_noac, "noac" },
 	{ Opt_fsc, "fsc" },
 	{ Opt_mfsymlinks, "mfsymlinks" },
@@ -277,6 +272,7 @@
 static const match_table_t cifs_smb_version_tokens = {
 	{ Smb_1, SMB1_VERSION_STRING },
 	{ Smb_21, SMB21_VERSION_STRING },
+	{ Smb_30, SMB30_VERSION_STRING },
 };
 
 static int ip_connect(struct TCP_Server_Info *server);
@@ -819,6 +815,10 @@
 		cifs_dump_mem("Bad SMB: ", buf,
 			min_t(unsigned int, server->total_read, 48));
 
+	if (server->ops->is_status_pending &&
+	    server->ops->is_status_pending(buf, server, length))
+		return -1;
+
 	if (!mid)
 		return length;
 
@@ -1075,6 +1075,10 @@
 		vol->ops = &smb21_operations;
 		vol->vals = &smb21_values;
 		break;
+	case Smb_30:
+		vol->ops = &smb21_operations; /* currently identical with 2.1 */
+		vol->vals = &smb30_values;
+		break;
 #endif
 	default:
 		cERROR(1, "Unknown vers= option specified: %s", value);
@@ -1101,8 +1105,6 @@
 	char *string = NULL;
 	char *tmp_end, *value;
 	char delim;
-	bool cache_specified = false;
-	static bool cache_warned = false;
 
 	separator[0] = ',';
 	separator[1] = 0;
@@ -1134,6 +1136,9 @@
 	/* default to using server inode numbers where available */
 	vol->server_ino = 1;
 
+	/* default is to use strict cifs caching semantics */
+	vol->strict_io = true;
+
 	vol->actimeo = CIFS_DEF_ACTIMEO;
 
 	/* FIXME: add autonegotiation -- for now, SMB1 is default */
@@ -1317,22 +1322,6 @@
 			 */
 			vol->seal = 1;
 			break;
-		case Opt_direct:
-			cache_specified = true;
-			vol->direct_io = true;
-			vol->strict_io = false;
-			cERROR(1, "The \"directio\" option will be removed in "
-				  "3.7. Please switch to the \"cache=none\" "
-				  "option.");
-			break;
-		case Opt_strictcache:
-			cache_specified = true;
-			vol->direct_io = false;
-			vol->strict_io = true;
-			cERROR(1, "The \"strictcache\" option will be removed "
-				"in 3.7. Please switch to the \"cache=strict\" "
-				"option.");
-			break;
 		case Opt_noac:
 			printk(KERN_WARNING "CIFS: Mount option noac not "
 				"supported. Instead set "
@@ -1676,8 +1665,13 @@
 			if (string == NULL)
 				goto out_nomem;
 
-			if (strnicmp(string, "TCP_NODELAY", 11) == 0)
+			if (strnicmp(string, "TCP_NODELAY", 11) == 0) {
+				printk(KERN_WARNING "CIFS: the "
+					"sockopt=TCP_NODELAY option has been "
+					"deprecated and will be removed "
+					"in 3.9\n");
 				vol->sockopt_tcp_nodelay = 1;
+			}
 			break;
 		case Opt_netbiosname:
 			string = match_strdup(args);
@@ -1762,7 +1756,6 @@
 				goto cifs_parse_mount_err;
 			break;
 		case Opt_cache:
-			cache_specified = true;
 			string = match_strdup(args);
 			if (string == NULL)
 				goto out_nomem;
@@ -1813,14 +1806,6 @@
 		printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
 				   "specified with no gid= option.\n");
 
-	/* FIXME: remove this block in 3.7 */
-	if (!cache_specified && !cache_warned) {
-		cache_warned = true;
-		printk(KERN_NOTICE "CIFS: no cache= option specified, using "
-				   "\"cache=loose\". This default will change "
-				   "to \"cache=strict\" in 3.7.\n");
-	}
-
 	kfree(mountdata_copy);
 	return 0;
 
@@ -2636,6 +2621,7 @@
 	tcon->retry = volume_info->retry;
 	tcon->nocase = volume_info->nocase;
 	tcon->local_lease = volume_info->local_lease;
+	INIT_LIST_HEAD(&tcon->pending_opens);
 
 	spin_lock(&cifs_tcp_ses_lock);
 	list_add(&tcon->tcon_list, &ses->tcon_list);
@@ -3261,146 +3247,6 @@
 			   "mount option supported");
 }
 
-/*
- * When the server supports very large reads and writes via POSIX extensions,
- * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
- * including the RFC1001 length.
- *
- * Note that this might make for "interesting" allocation problems during
- * writeback however as we have to allocate an array of pointers for the
- * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
- *
- * For reads, there is a similar problem as we need to allocate an array
- * of kvecs to handle the receive, though that should only need to be done
- * once.
- */
-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
-
-/*
- * When the server doesn't allow large posix writes, only allow a rsize/wsize
- * of 2^17-1 minus the size of the call header. That allows for a read or
- * write up to the maximum size described by RFC1002.
- */
-#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
-
-/*
- * The default wsize is 1M. find_get_pages seems to return a maximum of 256
- * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
- * a single wsize request with a single call.
- */
-#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
-
-/*
- * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
- * those values when posix extensions aren't in force. In actuality here, we
- * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
- * to be ok with the extra byte even though Windows doesn't send writes that
- * are that large.
- *
- * Citation:
- *
- * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
- */
-#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
-#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
-
-/*
- * On hosts with high memory, we can't currently support wsize/rsize that are
- * larger than we can kmap at once. Cap the rsize/wsize at
- * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
- * larger than that anyway.
- */
-#ifdef CONFIG_HIGHMEM
-#define CIFS_KMAP_SIZE_LIMIT	(LAST_PKMAP * PAGE_CACHE_SIZE)
-#else /* CONFIG_HIGHMEM */
-#define CIFS_KMAP_SIZE_LIMIT	(1<<24)
-#endif /* CONFIG_HIGHMEM */
-
-static unsigned int
-cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-	struct TCP_Server_Info *server = tcon->ses->server;
-	unsigned int wsize;
-
-	/* start with specified wsize, or default */
-	if (pvolume_info->wsize)
-		wsize = pvolume_info->wsize;
-	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-		wsize = CIFS_DEFAULT_IOSIZE;
-	else
-		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
-
-	/* can server support 24-bit write sizes? (via UNIX extensions) */
-	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
-
-	/*
-	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
-	 * Limit it to max buffer offered by the server, minus the size of the
-	 * WRITEX header, not including the 4 byte RFC1001 length.
-	 */
-	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
-	    (!(server->capabilities & CAP_UNIX) &&
-	     (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
-		wsize = min_t(unsigned int, wsize,
-				server->maxBuf - sizeof(WRITE_REQ) + 4);
-
-	/* limit to the amount that we can kmap at once */
-	wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
-
-	/* hard limit of CIFS_MAX_WSIZE */
-	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
-
-	return wsize;
-}
-
-static unsigned int
-cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-	struct TCP_Server_Info *server = tcon->ses->server;
-	unsigned int rsize, defsize;
-
-	/*
-	 * Set default value...
-	 *
-	 * HACK alert! Ancient servers have very small buffers. Even though
-	 * MS-CIFS indicates that servers are only limited by the client's
-	 * bufsize for reads, testing against win98se shows that it throws
-	 * INVALID_PARAMETER errors if you try to request too large a read.
-	 * OS/2 just sends back short reads.
-	 *
-	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
-	 * it can't handle a read request larger than its MaxBufferSize either.
-	 */
-	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
-		defsize = CIFS_DEFAULT_IOSIZE;
-	else if (server->capabilities & CAP_LARGE_READ_X)
-		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
-	else
-		defsize = server->maxBuf - sizeof(READ_RSP);
-
-	rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize;
-
-	/*
-	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
-	 * the client's MaxBufferSize.
-	 */
-	if (!(server->capabilities & CAP_LARGE_READ_X))
-		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
-
-	/* limit to the amount that we can kmap at once */
-	rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
-
-	/* hard limit of CIFS_MAX_RSIZE */
-	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
-
-	return rsize;
-}
-
 static void
 cleanup_volume_info_contents(struct smb_vol *volume_info)
 {
@@ -3651,8 +3497,8 @@
 	if (!tcon->ipc && server->ops->qfs_tcon)
 		server->ops->qfs_tcon(xid, tcon);
 
-	cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
-	cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
+	cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
+	cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
 
 	/* tune readahead according to rsize */
 	cifs_sb->bdi.ra_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 781025b..7c0a812 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -160,17 +160,18 @@
 static int
 cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	       struct tcon_link *tlink, unsigned oflags, umode_t mode,
-	       __u32 *oplock, __u16 *fileHandle, int *created)
+	       __u32 *oplock, struct cifs_fid *fid, int *created)
 {
 	int rc = -ENOENT;
 	int create_options = CREATE_NOT_DIR;
-	int desiredAccess;
+	int desired_access;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_tcon *tcon = tlink_tcon(tlink);
 	char *full_path = NULL;
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
 	int disposition;
+	struct TCP_Server_Info *server = tcon->ses->server;
 
 	*oplock = 0;
 	if (tcon->ses->server->oplocks)
@@ -185,8 +186,8 @@
 	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-		rc = cifs_posix_open(full_path, &newinode,
-			inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+		rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+				     oflags, oplock, &fid->netfid, xid);
 		switch (rc) {
 		case 0:
 			if (newinode == NULL) {
@@ -202,7 +203,7 @@
 				 * close it and proceed as if it were a normal
 				 * lookup.
 				 */
-				CIFSSMBClose(xid, tcon, *fileHandle);
+				CIFSSMBClose(xid, tcon, fid->netfid);
 				goto cifs_create_get_file_info;
 			}
 			/* success, no need to query */
@@ -244,11 +245,11 @@
 		 */
 	}
 
-	desiredAccess = 0;
+	desired_access = 0;
 	if (OPEN_FMODE(oflags) & FMODE_READ)
-		desiredAccess |= GENERIC_READ; /* is this too little? */
+		desired_access |= GENERIC_READ; /* is this too little? */
 	if (OPEN_FMODE(oflags) & FMODE_WRITE)
-		desiredAccess |= GENERIC_WRITE;
+		desired_access |= GENERIC_WRITE;
 
 	disposition = FILE_OVERWRITE_IF;
 	if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
@@ -260,8 +261,15 @@
 	else
 		cFYI(1, "Create flag not set in create function");
 
-	/* BB add processing to set equivalent of mode - e.g. via CreateX with
-	   ACLs */
+	/*
+	 * BB add processing to set equivalent of mode - e.g. via CreateX with
+	 * ACLs
+	 */
+
+	if (!server->ops->open) {
+		rc = -ENOSYS;
+		goto out;
+	}
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 	if (buf == NULL) {
@@ -279,28 +287,18 @@
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	if (tcon->ses->capabilities & CAP_NT_SMBS)
-		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-			 desiredAccess, create_options,
-			 fileHandle, oplock, buf, cifs_sb->local_nls,
-			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	else
-		rc = -EIO; /* no NT SMB support fall into legacy open below */
-
-	if (rc == -EIO) {
-		/* old server, retry the open legacy style */
-		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-			desiredAccess, create_options,
-			fileHandle, oplock, buf, cifs_sb->local_nls,
-			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	}
+	rc = server->ops->open(xid, tcon, full_path, disposition,
+			       desired_access, create_options, fid, oplock,
+			       buf, cifs_sb);
 	if (rc) {
 		cFYI(1, "cifs_create returned 0x%x", rc);
 		goto out;
 	}
 
-	/* If Open reported that we actually created a file
-	   then we now have to set the mode if possible */
+	/*
+	 * If Open reported that we actually created a file then we now have to
+	 * set the mode if possible.
+	 */
 	if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
 		struct cifs_unix_set_info_args args = {
 				.mode	= mode,
@@ -321,11 +319,13 @@
 			args.uid = NO_CHANGE_64;
 			args.gid = NO_CHANGE_64;
 		}
-		CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
-					current->tgid);
+		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,
+				       current->tgid);
 	} else {
-		/* BB implement mode setting via Windows security
-		   descriptors e.g. */
+		/*
+		 * BB implement mode setting via Windows security
+		 * descriptors e.g.
+		 */
 		/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 
 		/* Could set r/o dos attribute if mode & 0222 == 0 */
@@ -334,12 +334,14 @@
 cifs_create_get_file_info:
 	/* server might mask mode so we have to query for it */
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&newinode, full_path,
-					      inode->i_sb, xid);
+		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+					      xid);
 	else {
-		rc = cifs_get_inode_info(&newinode, full_path, buf,
-					 inode->i_sb, xid, fileHandle);
+		rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
+					 xid, &fid->netfid);
 		if (newinode) {
+			if (server->ops->set_lease_key)
+				server->ops->set_lease_key(newinode, fid);
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 				newinode->i_mode = mode;
 			if ((*oplock & CIFS_CREATE_ACTION) &&
@@ -356,7 +358,8 @@
 cifs_create_set_dentry:
 	if (rc != 0) {
 		cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
-		CIFSSMBClose(xid, tcon, *fileHandle);
+		if (server->ops->close)
+			server->ops->close(xid, tcon, fid);
 		goto out;
 	}
 	d_drop(direntry);
@@ -377,11 +380,14 @@
 	unsigned int xid;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	__u16 fileHandle;
+	struct TCP_Server_Info *server;
+	struct cifs_fid fid;
+	struct cifs_pending_open open;
 	__u32 oplock;
-	struct cifsFileInfo *pfile_info;
+	struct cifsFileInfo *file_info;
 
-	/* Posix open is only called (at lookup time) for file create now.  For
+	/*
+	 * Posix open is only called (at lookup time) for file create now. For
 	 * opens (rather than creates), because we do not know if it is a file
 	 * or directory yet, and current Samba no longer allows us to do posix
 	 * open on dirs, we could end up wasting an open call on what turns out
@@ -413,22 +419,34 @@
 		goto out_free_xid;
 
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+
+	if (server->ops->new_lease_key)
+		server->ops->new_lease_key(&fid);
+
+	cifs_add_pending_open(&fid, tlink, &open);
 
 	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-			    &oplock, &fileHandle, opened);
+			    &oplock, &fid, opened);
 
-	if (rc)
-		goto out;
-
-	rc = finish_open(file, direntry, generic_file_open, opened);
 	if (rc) {
-		CIFSSMBClose(xid, tcon, fileHandle);
+		cifs_del_pending_open(&open);
 		goto out;
 	}
 
-	pfile_info = cifs_new_fileinfo(fileHandle, file, tlink, oplock);
-	if (pfile_info == NULL) {
-		CIFSSMBClose(xid, tcon, fileHandle);
+	rc = finish_open(file, direntry, generic_file_open, opened);
+	if (rc) {
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &fid);
+		cifs_del_pending_open(&open);
+		goto out;
+	}
+
+	file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
+	if (file_info == NULL) {
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &fid);
+		cifs_del_pending_open(&open);
 		rc = -ENOMEM;
 	}
 
@@ -453,7 +471,9 @@
 	 */
 	unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
 	struct tcon_link *tlink;
-	__u16 fileHandle;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
+	struct cifs_fid fid;
 	__u32 oplock;
 	int created = FILE_CREATED;
 
@@ -465,10 +485,16 @@
 	if (IS_ERR(tlink))
 		goto out_free_xid;
 
+	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+
+	if (server->ops->new_lease_key)
+		server->ops->new_lease_key(&fid);
+
 	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-			    &oplock, &fileHandle, &created);
-	if (!rc)
-		CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+			    &oplock, &fid, &created);
+	if (!rc && server->ops->close)
+		server->ops->close(xid, tcon, &fid);
 
 	cifs_put_tlink(tlink);
 out_free_xid:
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 71e9ad9..7d7bbdc 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -169,16 +169,20 @@
 
 static int
 cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
-	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
-	     __u16 *pnetfid, unsigned int xid)
+	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
+	     struct cifs_fid *fid, unsigned int xid)
 {
 	int rc;
-	int desiredAccess;
+	int desired_access;
 	int disposition;
 	int create_options = CREATE_NOT_DIR;
 	FILE_ALL_INFO *buf;
+	struct TCP_Server_Info *server = tcon->ses->server;
 
-	desiredAccess = cifs_convert_flags(f_flags);
+	if (!server->ops->open)
+		return -ENOSYS;
+
+	desired_access = cifs_convert_flags(f_flags);
 
 /*********************************************************************
  *  open flag mapping table:
@@ -215,16 +219,9 @@
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	if (tcon->ses->capabilities & CAP_NT_SMBS)
-		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-			 desiredAccess, create_options, pnetfid, poplock, buf,
-			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	else
-		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-			desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
-			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-				& CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = server->ops->open(xid, tcon, full_path, disposition,
+			       desired_access, create_options, fid, oplock, buf,
+			       cifs_sb);
 
 	if (rc)
 		goto out;
@@ -234,7 +231,7 @@
 					      xid);
 	else
 		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-					 xid, pnetfid);
+					 xid, &fid->netfid);
 
 out:
 	kfree(buf);
@@ -242,48 +239,62 @@
 }
 
 struct cifsFileInfo *
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
 		  struct tcon_link *tlink, __u32 oplock)
 {
 	struct dentry *dentry = file->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
-	struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
-	struct cifsFileInfo *pCifsFile;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifsFileInfo *cfile;
+	struct cifs_fid_locks *fdlocks;
+	struct cifs_tcon *tcon = tlink_tcon(tlink);
 
-	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-	if (pCifsFile == NULL)
-		return pCifsFile;
+	cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+	if (cfile == NULL)
+		return cfile;
 
-	pCifsFile->count = 1;
-	pCifsFile->netfid = fileHandle;
-	pCifsFile->pid = current->tgid;
-	pCifsFile->uid = current_fsuid();
-	pCifsFile->dentry = dget(dentry);
-	pCifsFile->f_flags = file->f_flags;
-	pCifsFile->invalidHandle = false;
-	pCifsFile->tlink = cifs_get_tlink(tlink);
-	mutex_init(&pCifsFile->fh_mutex);
-	INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
-	INIT_LIST_HEAD(&pCifsFile->llist);
+	fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL);
+	if (!fdlocks) {
+		kfree(cfile);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&fdlocks->locks);
+	fdlocks->cfile = cfile;
+	cfile->llist = fdlocks;
+	down_write(&cinode->lock_sem);
+	list_add(&fdlocks->llist, &cinode->llist);
+	up_write(&cinode->lock_sem);
+
+	cfile->count = 1;
+	cfile->pid = current->tgid;
+	cfile->uid = current_fsuid();
+	cfile->dentry = dget(dentry);
+	cfile->f_flags = file->f_flags;
+	cfile->invalidHandle = false;
+	cfile->tlink = cifs_get_tlink(tlink);
+	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
+	mutex_init(&cfile->fh_mutex);
 
 	spin_lock(&cifs_file_list_lock);
-	list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
+	if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
+		oplock = fid->pending_open->oplock;
+	list_del(&fid->pending_open->olist);
+
+	tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
+
+	list_add(&cfile->tlist, &tcon->openFileList);
 	/* if readable file instance put first in list*/
 	if (file->f_mode & FMODE_READ)
-		list_add(&pCifsFile->flist, &pCifsInode->openFileList);
+		list_add(&cfile->flist, &cinode->openFileList);
 	else
-		list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
+		list_add_tail(&cfile->flist, &cinode->openFileList);
 	spin_unlock(&cifs_file_list_lock);
 
-	cifs_set_oplock_level(pCifsInode, oplock);
-	pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
-
-	file->private_data = pCifsFile;
-	return pCifsFile;
+	file->private_data = cfile;
+	return cfile;
 }
 
-static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
-
 struct cifsFileInfo *
 cifsFileInfo_get(struct cifsFileInfo *cifs_file)
 {
@@ -302,9 +313,12 @@
 {
 	struct inode *inode = cifs_file->dentry->d_inode;
 	struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
+	struct TCP_Server_Info *server = tcon->ses->server;
 	struct cifsInodeInfo *cifsi = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifsLockInfo *li, *tmp;
+	struct cifs_fid fid;
+	struct cifs_pending_open open;
 
 	spin_lock(&cifs_file_list_lock);
 	if (--cifs_file->count > 0) {
@@ -312,6 +326,12 @@
 		return;
 	}
 
+	if (server->ops->get_lease_key)
+		server->ops->get_lease_key(inode, &fid);
+
+	/* store open in pending opens to make sure we don't miss lease break */
+	cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
+
 	/* remove it from the lists */
 	list_del(&cifs_file->flist);
 	list_del(&cifs_file->tlist);
@@ -319,13 +339,13 @@
 	if (list_empty(&cifsi->openFileList)) {
 		cFYI(1, "closing last open instance for inode %p",
 			cifs_file->dentry->d_inode);
-
-		/* in strict cache mode we need invalidate mapping on the last
-		   close  because it may cause a error when we open this file
-		   again and get at least level II oplock */
+		/*
+		 * In strict cache mode we need invalidate mapping on the last
+		 * close  because it may cause a error when we open this file
+		 * again and get at least level II oplock.
+		 */
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
 			CIFS_I(inode)->invalid_mapping = true;
-
 		cifs_set_oplock_level(cifsi, 0);
 	}
 	spin_unlock(&cifs_file_list_lock);
@@ -333,23 +353,30 @@
 	cancel_work_sync(&cifs_file->oplock_break);
 
 	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+		struct TCP_Server_Info *server = tcon->ses->server;
 		unsigned int xid;
-		int rc;
+
 		xid = get_xid();
-		rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
-		free_xid(xid);
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &cifs_file->fid);
+		_free_xid(xid);
 	}
 
-	/* Delete any outstanding lock records. We'll lose them when the file
+	cifs_del_pending_open(&open);
+
+	/*
+	 * Delete any outstanding lock records. We'll lose them when the file
 	 * is closed anyway.
 	 */
-	mutex_lock(&cifsi->lock_mutex);
-	list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
+	down_write(&cifsi->lock_sem);
+	list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
 		list_del(&li->llist);
 		cifs_del_lock_waiters(li);
 		kfree(li);
 	}
-	mutex_unlock(&cifsi->lock_mutex);
+	list_del(&cifs_file->llist->llist);
+	kfree(cifs_file->llist);
+	up_write(&cifsi->lock_sem);
 
 	cifs_put_tlink(cifs_file->tlink);
 	dput(cifs_file->dentry);
@@ -357,17 +384,20 @@
 }
 
 int cifs_open(struct inode *inode, struct file *file)
+
 {
 	int rc = -EACCES;
 	unsigned int xid;
 	__u32 oplock;
 	struct cifs_sb_info *cifs_sb;
+	struct TCP_Server_Info *server;
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
-	struct cifsFileInfo *pCifsFile = NULL;
+	struct cifsFileInfo *cfile = NULL;
 	char *full_path = NULL;
 	bool posix_open_ok = false;
-	__u16 netfid;
+	struct cifs_fid fid;
+	struct cifs_pending_open open;
 
 	xid = get_xid();
 
@@ -378,6 +408,7 @@
 		return PTR_ERR(tlink);
 	}
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
 
 	full_path = build_path_from_dentry(file->f_path.dentry);
 	if (full_path == NULL) {
@@ -388,7 +419,7 @@
 	cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
 		 inode, file->f_flags, full_path);
 
-	if (tcon->ses->server->oplocks)
+	if (server->oplocks)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = 0;
@@ -399,7 +430,7 @@
 		/* can not refresh inode info since size could be stale */
 		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
 				cifs_sb->mnt_file_mode /* ignored */,
-				file->f_flags, &oplock, &netfid, xid);
+				file->f_flags, &oplock, &fid.netfid, xid);
 		if (rc == 0) {
 			cFYI(1, "posix open succeeded");
 			posix_open_ok = true;
@@ -415,20 +446,34 @@
 		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
 			 (rc != -EOPNOTSUPP)) /* path not found or net err */
 			goto out;
-		/* else fallthrough to retry open the old way on network i/o
-		   or DFS errors */
+		/*
+		 * Else fallthrough to retry open the old way on network i/o
+		 * or DFS errors.
+		 */
 	}
 
+	if (server->ops->get_lease_key)
+		server->ops->get_lease_key(inode, &fid);
+
+	cifs_add_pending_open(&fid, tlink, &open);
+
 	if (!posix_open_ok) {
+		if (server->ops->get_lease_key)
+			server->ops->get_lease_key(inode, &fid);
+
 		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
-				  file->f_flags, &oplock, &netfid, xid);
-		if (rc)
+				  file->f_flags, &oplock, &fid, xid);
+		if (rc) {
+			cifs_del_pending_open(&open);
 			goto out;
+		}
 	}
 
-	pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
-	if (pCifsFile == NULL) {
-		CIFSSMBClose(xid, tcon, netfid);
+	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
+	if (cfile == NULL) {
+		if (server->ops->close)
+			server->ops->close(xid, tcon, &fid);
+		cifs_del_pending_open(&open);
 		rc = -ENOMEM;
 		goto out;
 	}
@@ -436,8 +481,10 @@
 	cifs_fscache_set_inode_cookie(inode, file);
 
 	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
-		/* time to set mode which we can not set earlier due to
-		   problems creating new read-only files */
+		/*
+		 * Time to set mode which we can not set earlier due to
+		 * problems creating new read-only files.
+		 */
 		struct cifs_unix_set_info_args args = {
 			.mode	= inode->i_mode,
 			.uid	= NO_CHANGE_64,
@@ -447,8 +494,8 @@
 			.mtime	= NO_CHANGE_64,
 			.device	= 0,
 		};
-		CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
-					pCifsFile->pid);
+		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
+				       cfile->pid);
 	}
 
 out:
@@ -458,59 +505,66 @@
 	return rc;
 }
 
-/* Try to reacquire byte range locks that were released when session */
-/* to server was lost */
+/*
+ * Try to reacquire byte range locks that were released when session
+ * to server was lost
+ */
 static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 {
 	int rc = 0;
 
-/* BB list all locks open on this file and relock */
+	/* BB list all locks open on this file and relock */
 
 	return rc;
 }
 
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
+static int
+cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 {
 	int rc = -EACCES;
 	unsigned int xid;
 	__u32 oplock;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
-	struct cifsInodeInfo *pCifsInode;
+	struct TCP_Server_Info *server;
+	struct cifsInodeInfo *cinode;
 	struct inode *inode;
 	char *full_path = NULL;
-	int desiredAccess;
+	int desired_access;
 	int disposition = FILE_OPEN;
 	int create_options = CREATE_NOT_DIR;
-	__u16 netfid;
+	struct cifs_fid fid;
 
 	xid = get_xid();
-	mutex_lock(&pCifsFile->fh_mutex);
-	if (!pCifsFile->invalidHandle) {
-		mutex_unlock(&pCifsFile->fh_mutex);
+	mutex_lock(&cfile->fh_mutex);
+	if (!cfile->invalidHandle) {
+		mutex_unlock(&cfile->fh_mutex);
 		rc = 0;
 		free_xid(xid);
 		return rc;
 	}
 
-	inode = pCifsFile->dentry->d_inode;
+	inode = cfile->dentry->d_inode;
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = tlink_tcon(pCifsFile->tlink);
+	tcon = tlink_tcon(cfile->tlink);
+	server = tcon->ses->server;
 
-/* can not grab rename sem here because various ops, including
-   those that already have the rename sem can end up causing writepage
-   to get called and if the server was down that means we end up here,
-   and we can never tell if the caller already has the rename_sem */
-	full_path = build_path_from_dentry(pCifsFile->dentry);
+	/*
+	 * Can not grab rename sem here because various ops, including those
+	 * that already have the rename sem can end up causing writepage to get
+	 * called and if the server was down that means we end up here, and we
+	 * can never tell if the caller already has the rename_sem.
+	 */
+	full_path = build_path_from_dentry(cfile->dentry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
-		mutex_unlock(&pCifsFile->fh_mutex);
+		mutex_unlock(&cfile->fh_mutex);
 		free_xid(xid);
 		return rc;
 	}
 
-	cFYI(1, "inode = 0x%p file flags 0x%x for %s",
-		 inode, pCifsFile->f_flags, full_path);
+	cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, cfile->f_flags,
+	     full_path);
 
 	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
@@ -524,69 +578,72 @@
 		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
 		 * original open. Must mask them off for a reopen.
 		 */
-		unsigned int oflags = pCifsFile->f_flags &
+		unsigned int oflags = cfile->f_flags &
 						~(O_CREAT | O_EXCL | O_TRUNC);
 
 		rc = cifs_posix_open(full_path, NULL, inode->i_sb,
-				cifs_sb->mnt_file_mode /* ignored */,
-				oflags, &oplock, &netfid, xid);
+				     cifs_sb->mnt_file_mode /* ignored */,
+				     oflags, &oplock, &fid.netfid, xid);
 		if (rc == 0) {
 			cFYI(1, "posix reopen succeeded");
 			goto reopen_success;
 		}
-		/* fallthrough to retry open the old way on errors, especially
-		   in the reconnect path it is important to retry hard */
+		/*
+		 * fallthrough to retry open the old way on errors, especially
+		 * in the reconnect path it is important to retry hard
+		 */
 	}
 
-	desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
+	desired_access = cifs_convert_flags(cfile->f_flags);
 
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-	/* Can not refresh inode by passing in file_info buf to be returned
-	   by SMBOpen and then calling get_inode_info with returned buf
-	   since file might have write behind data that needs to be flushed
-	   and server version of file size can be stale. If we knew for sure
-	   that inode was not dirty locally we could do this */
+	if (server->ops->get_lease_key)
+		server->ops->get_lease_key(inode, &fid);
 
-	rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
-			 create_options, &netfid, &oplock, NULL,
-			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	/*
+	 * Can not refresh inode by passing in file_info buf to be returned by
+	 * CIFSSMBOpen and then calling get_inode_info with returned buf since
+	 * file might have write behind data that needs to be flushed and server
+	 * version of file size can be stale. If we knew for sure that inode was
+	 * not dirty locally we could do this.
+	 */
+	rc = server->ops->open(xid, tcon, full_path, disposition,
+			       desired_access, create_options, &fid, &oplock,
+			       NULL, cifs_sb);
 	if (rc) {
-		mutex_unlock(&pCifsFile->fh_mutex);
-		cFYI(1, "cifs_open returned 0x%x", rc);
+		mutex_unlock(&cfile->fh_mutex);
+		cFYI(1, "cifs_reopen returned 0x%x", rc);
 		cFYI(1, "oplock: %d", oplock);
 		goto reopen_error_exit;
 	}
 
 reopen_success:
-	pCifsFile->netfid = netfid;
-	pCifsFile->invalidHandle = false;
-	mutex_unlock(&pCifsFile->fh_mutex);
-	pCifsInode = CIFS_I(inode);
+	cfile->invalidHandle = false;
+	mutex_unlock(&cfile->fh_mutex);
+	cinode = CIFS_I(inode);
 
 	if (can_flush) {
 		rc = filemap_write_and_wait(inode->i_mapping);
 		mapping_set_error(inode->i_mapping, rc);
 
 		if (tcon->unix_ext)
-			rc = cifs_get_inode_info_unix(&inode,
-				full_path, inode->i_sb, xid);
+			rc = cifs_get_inode_info_unix(&inode, full_path,
+						      inode->i_sb, xid);
 		else
-			rc = cifs_get_inode_info(&inode,
-				full_path, NULL, inode->i_sb,
-				xid, NULL);
-	} /* else we are writing out data to server already
-	     and could deadlock if we tried to flush data, and
-	     since we do not know if we have data that would
-	     invalidate the current end of file on the server
-	     we can not go to the server to get the new inod
-	     info */
+			rc = cifs_get_inode_info(&inode, full_path, NULL,
+						 inode->i_sb, xid, NULL);
+	}
+	/*
+	 * Else we are writing out data to server already and could deadlock if
+	 * we tried to flush data, and since we do not know if we have data that
+	 * would invalidate the current end of file on the server we can not go
+	 * to the server to get the new inode info.
+	 */
 
-	cifs_set_oplock_level(pCifsInode, oplock);
-
-	cifs_relock_file(pCifsFile);
+	server->ops->set_fid(cfile, &fid, oplock);
+	cifs_relock_file(cfile);
 
 reopen_error_exit:
 	kfree(full_path);
@@ -609,42 +666,48 @@
 {
 	int rc = 0;
 	unsigned int xid;
-	struct cifsFileInfo *pCFileStruct = file->private_data;
-	char *ptmp;
+	struct cifsFileInfo *cfile = file->private_data;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
+	char *buf;
 
 	cFYI(1, "Closedir inode = 0x%p", inode);
 
+	if (cfile == NULL)
+		return rc;
+
 	xid = get_xid();
+	tcon = tlink_tcon(cfile->tlink);
+	server = tcon->ses->server;
 
-	if (pCFileStruct) {
-		struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
+	cFYI(1, "Freeing private data in close dir");
+	spin_lock(&cifs_file_list_lock);
+	if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+		cfile->invalidHandle = true;
+		spin_unlock(&cifs_file_list_lock);
+		if (server->ops->close_dir)
+			rc = server->ops->close_dir(xid, tcon, &cfile->fid);
+		else
+			rc = -ENOSYS;
+		cFYI(1, "Closing uncompleted readdir with rc %d", rc);
+		/* not much we can do if it fails anyway, ignore rc */
+		rc = 0;
+	} else
+		spin_unlock(&cifs_file_list_lock);
 
-		cFYI(1, "Freeing private data in close dir");
-		spin_lock(&cifs_file_list_lock);
-		if (!pCFileStruct->srch_inf.endOfSearch &&
-		    !pCFileStruct->invalidHandle) {
-			pCFileStruct->invalidHandle = true;
-			spin_unlock(&cifs_file_list_lock);
-			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
-			cFYI(1, "Closing uncompleted readdir with rc %d",
-				 rc);
-			/* not much we can do if it fails anyway, ignore rc */
-			rc = 0;
-		} else
-			spin_unlock(&cifs_file_list_lock);
-		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
-		if (ptmp) {
-			cFYI(1, "closedir free smb buf in srch struct");
-			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-			if (pCFileStruct->srch_inf.smallBuf)
-				cifs_small_buf_release(ptmp);
-			else
-				cifs_buf_release(ptmp);
-		}
-		cifs_put_tlink(pCFileStruct->tlink);
-		kfree(file->private_data);
-		file->private_data = NULL;
+	buf = cfile->srch_inf.ntwrk_buf_start;
+	if (buf) {
+		cFYI(1, "closedir free smb buf in srch struct");
+		cfile->srch_inf.ntwrk_buf_start = NULL;
+		if (cfile->srch_inf.smallBuf)
+			cifs_small_buf_release(buf);
+		else
+			cifs_buf_release(buf);
 	}
+
+	cifs_put_tlink(cfile->tlink);
+	kfree(file->private_data);
+	file->private_data = NULL;
 	/* BB can we lock the filestruct while this is going on? */
 	free_xid(xid);
 	return rc;
@@ -666,7 +729,7 @@
 	return lock;
 }
 
-static void
+void
 cifs_del_lock_waiters(struct cifsLockInfo *lock)
 {
 	struct cifsLockInfo *li, *tmp;
@@ -677,45 +740,47 @@
 }
 
 static bool
-cifs_find_fid_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
-			    __u64 length, __u8 type, struct cifsFileInfo *cur,
-			    struct cifsLockInfo **conf_lock)
+cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
+			    __u64 length, __u8 type, struct cifsFileInfo *cfile,
+			    struct cifsLockInfo **conf_lock, bool rw_check)
 {
 	struct cifsLockInfo *li;
+	struct cifsFileInfo *cur_cfile = fdlocks->cfile;
 	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
 
-	list_for_each_entry(li, &cfile->llist, llist) {
+	list_for_each_entry(li, &fdlocks->locks, llist) {
 		if (offset + length <= li->offset ||
 		    offset >= li->offset + li->length)
 			continue;
-		else if ((type & server->vals->shared_lock_type) &&
-			 ((server->ops->compare_fids(cur, cfile) &&
-			   current->tgid == li->pid) || type == li->type))
+		if (rw_check && server->ops->compare_fids(cfile, cur_cfile) &&
+		    current->tgid == li->pid)
 			continue;
-		else {
+		if ((type & server->vals->shared_lock_type) &&
+		    ((server->ops->compare_fids(cfile, cur_cfile) &&
+		     current->tgid == li->pid) || type == li->type))
+			continue;
+		if (conf_lock)
 			*conf_lock = li;
-			return true;
-		}
+		return true;
 	}
 	return false;
 }
 
-static bool
+bool
 cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
-			__u8 type, struct cifsLockInfo **conf_lock)
+			__u8 type, struct cifsLockInfo **conf_lock,
+			bool rw_check)
 {
 	bool rc = false;
-	struct cifsFileInfo *fid, *tmp;
+	struct cifs_fid_locks *cur;
 	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
 
-	spin_lock(&cifs_file_list_lock);
-	list_for_each_entry_safe(fid, tmp, &cinode->openFileList, flist) {
-		rc = cifs_find_fid_lock_conflict(fid, offset, length, type,
-						 cfile, conf_lock);
+	list_for_each_entry(cur, &cinode->llist, llist) {
+		rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
+						 cfile, conf_lock, rw_check);
 		if (rc)
 			break;
 	}
-	spin_unlock(&cifs_file_list_lock);
 
 	return rc;
 }
@@ -737,10 +802,10 @@
 	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
 	bool exist;
 
-	mutex_lock(&cinode->lock_mutex);
+	down_read(&cinode->lock_sem);
 
 	exist = cifs_find_lock_conflict(cfile, offset, length, type,
-					&conf_lock);
+					&conf_lock, false);
 	if (exist) {
 		flock->fl_start = conf_lock->offset;
 		flock->fl_end = conf_lock->offset + conf_lock->length - 1;
@@ -754,7 +819,7 @@
 	else
 		flock->fl_type = F_UNLCK;
 
-	mutex_unlock(&cinode->lock_mutex);
+	up_read(&cinode->lock_sem);
 	return rc;
 }
 
@@ -762,9 +827,9 @@
 cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
 {
 	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
-	mutex_lock(&cinode->lock_mutex);
-	list_add_tail(&lock->llist, &cfile->llist);
-	mutex_unlock(&cinode->lock_mutex);
+	down_write(&cinode->lock_sem);
+	list_add_tail(&lock->llist, &cfile->llist->locks);
+	up_write(&cinode->lock_sem);
 }
 
 /*
@@ -784,13 +849,13 @@
 
 try_again:
 	exist = false;
-	mutex_lock(&cinode->lock_mutex);
+	down_write(&cinode->lock_sem);
 
 	exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
-					lock->type, &conf_lock);
+					lock->type, &conf_lock, false);
 	if (!exist && cinode->can_cache_brlcks) {
-		list_add_tail(&lock->llist, &cfile->llist);
-		mutex_unlock(&cinode->lock_mutex);
+		list_add_tail(&lock->llist, &cfile->llist->locks);
+		up_write(&cinode->lock_sem);
 		return rc;
 	}
 
@@ -800,17 +865,17 @@
 		rc = -EACCES;
 	else {
 		list_add_tail(&lock->blist, &conf_lock->blist);
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		rc = wait_event_interruptible(lock->block_q,
 					(lock->blist.prev == &lock->blist) &&
 					(lock->blist.next == &lock->blist));
 		if (!rc)
 			goto try_again;
-		mutex_lock(&cinode->lock_mutex);
+		down_write(&cinode->lock_sem);
 		list_del_init(&lock->blist);
 	}
 
-	mutex_unlock(&cinode->lock_mutex);
+	up_write(&cinode->lock_sem);
 	return rc;
 }
 
@@ -831,7 +896,7 @@
 	if ((flock->fl_flags & FL_POSIX) == 0)
 		return 1;
 
-	mutex_lock(&cinode->lock_mutex);
+	down_read(&cinode->lock_sem);
 	posix_test_lock(file, flock);
 
 	if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
@@ -839,7 +904,7 @@
 		rc = 1;
 	}
 
-	mutex_unlock(&cinode->lock_mutex);
+	up_read(&cinode->lock_sem);
 	return rc;
 }
 
@@ -859,14 +924,14 @@
 		return rc;
 
 try_again:
-	mutex_lock(&cinode->lock_mutex);
+	down_write(&cinode->lock_sem);
 	if (!cinode->can_cache_brlcks) {
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		return rc;
 	}
 
 	rc = posix_lock_file(file, flock, NULL);
-	mutex_unlock(&cinode->lock_mutex);
+	up_write(&cinode->lock_sem);
 	if (rc == FILE_LOCK_DEFERRED) {
 		rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
 		if (!rc)
@@ -876,7 +941,7 @@
 	return rc;
 }
 
-static int
+int
 cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 {
 	unsigned int xid;
@@ -893,9 +958,10 @@
 	xid = get_xid();
 	tcon = tlink_tcon(cfile->tlink);
 
-	mutex_lock(&cinode->lock_mutex);
+	/* we are going to update can_cache_brlcks here - need a write access */
+	down_write(&cinode->lock_sem);
 	if (!cinode->can_cache_brlcks) {
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		free_xid(xid);
 		return rc;
 	}
@@ -906,7 +972,7 @@
 	 */
 	max_buf = tcon->ses->server->maxBuf;
 	if (!max_buf) {
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		free_xid(xid);
 		return -EINVAL;
 	}
@@ -915,7 +981,7 @@
 						sizeof(LOCKING_ANDX_RANGE);
 	buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
 	if (!buf) {
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		free_xid(xid);
 		return -ENOMEM;
 	}
@@ -923,7 +989,7 @@
 	for (i = 0; i < 2; i++) {
 		cur = buf;
 		num = 0;
-		list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
+		list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
 			if (li->type != types[i])
 				continue;
 			cur->Pid = cpu_to_le16(li->pid);
@@ -932,7 +998,8 @@
 			cur->OffsetLow = cpu_to_le32((u32)li->offset);
 			cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
 			if (++num == max_num) {
-				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+				stored_rc = cifs_lockv(xid, tcon,
+						       cfile->fid.netfid,
 						       (__u8)li->type, 0, num,
 						       buf);
 				if (stored_rc)
@@ -944,7 +1011,7 @@
 		}
 
 		if (num) {
-			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
 					       (__u8)types[i], 0, num, buf);
 			if (stored_rc)
 				rc = stored_rc;
@@ -952,7 +1019,7 @@
 	}
 
 	cinode->can_cache_brlcks = false;
-	mutex_unlock(&cinode->lock_mutex);
+	up_write(&cinode->lock_sem);
 
 	kfree(buf);
 	free_xid(xid);
@@ -987,9 +1054,10 @@
 
 	xid = get_xid();
 
-	mutex_lock(&cinode->lock_mutex);
+	/* we are going to update can_cache_brlcks here - need a write access */
+	down_write(&cinode->lock_sem);
 	if (!cinode->can_cache_brlcks) {
-		mutex_unlock(&cinode->lock_mutex);
+		up_write(&cinode->lock_sem);
 		free_xid(xid);
 		return rc;
 	}
@@ -1005,7 +1073,7 @@
 
 	/*
 	 * Allocating count locks is enough because no FL_POSIX locks can be
-	 * added to the list while we are holding cinode->lock_mutex that
+	 * added to the list while we are holding cinode->lock_sem that
 	 * protects locking operations of this inode.
 	 */
 	for (; i < count; i++) {
@@ -1038,7 +1106,7 @@
 			type = CIFS_WRLCK;
 		lck = list_entry(el, struct lock_to_push, llist);
 		lck->pid = flock->fl_pid;
-		lck->netfid = cfile->netfid;
+		lck->netfid = cfile->fid.netfid;
 		lck->length = length;
 		lck->type = type;
 		lck->offset = flock->fl_start;
@@ -1060,7 +1128,7 @@
 
 out:
 	cinode->can_cache_brlcks = false;
-	mutex_unlock(&cinode->lock_mutex);
+	up_write(&cinode->lock_sem);
 
 	free_xid(xid);
 	return rc;
@@ -1083,7 +1151,7 @@
 	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
 		return cifs_push_posix_locks(cfile);
 
-	return cifs_push_mandatory_locks(cfile);
+	return tcon->ses->server->ops->push_mand_locks(cfile);
 }
 
 static void
@@ -1104,7 +1172,8 @@
 	if (flock->fl_flags & FL_LEASE)
 		cFYI(1, "Lease on file - not implemented yet");
 	if (flock->fl_flags &
-	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
+	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP |
+	       FL_ACCESS | FL_LEASE | FL_CLOSE)))
 		cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
 
 	*type = server->vals->large_lock_type;
@@ -1134,15 +1203,6 @@
 }
 
 static int
-cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
-		    __u64 length, __u32 type, int lock, int unlock, bool wait)
-{
-	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
-			   current->tgid, length, offset, unlock, lock,
-			   (__u8)type, wait, 0);
-}
-
-static int
 cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
 	   bool wait_flag, bool posix_lck, unsigned int xid)
 {
@@ -1151,7 +1211,7 @@
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	__u16 netfid = cfile->netfid;
+	__u16 netfid = cfile->fid.netfid;
 
 	if (posix_lck) {
 		int posix_lock_type;
@@ -1175,11 +1235,11 @@
 		return rc;
 
 	/* BB we could chain these into one lock request BB */
-	rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, type,
-				 1, 0, false);
+	rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, type,
+				    1, 0, false);
 	if (rc == 0) {
-		rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
-					 type, 0, 1, false);
+		rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
+					    type, 0, 1, false);
 		flock->fl_type = F_UNLCK;
 		if (rc != 0)
 			cERROR(1, "Error unlocking previously locked "
@@ -1192,13 +1252,14 @@
 		return 0;
 	}
 
-	rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
-				 type | server->vals->shared_lock_type, 1, 0,
-				 false);
+	type &= ~server->vals->exclusive_lock_type;
+
+	rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
+				    type | server->vals->shared_lock_type,
+				    1, 0, false);
 	if (rc == 0) {
-		rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
-					 type | server->vals->shared_lock_type,
-					 0, 1, false);
+		rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
+			type | server->vals->shared_lock_type, 0, 1, false);
 		flock->fl_type = F_RDLCK;
 		if (rc != 0)
 			cERROR(1, "Error unlocking previously locked "
@@ -1209,7 +1270,7 @@
 	return 0;
 }
 
-static void
+void
 cifs_move_llist(struct list_head *source, struct list_head *dest)
 {
 	struct list_head *li, *tmp;
@@ -1217,7 +1278,7 @@
 		list_move(li, dest);
 }
 
-static void
+void
 cifs_free_llist(struct list_head *llist)
 {
 	struct cifsLockInfo *li, *tmp;
@@ -1228,7 +1289,7 @@
 	}
 }
 
-static int
+int
 cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
 		  unsigned int xid)
 {
@@ -1260,11 +1321,11 @@
 	if (!buf)
 		return -ENOMEM;
 
-	mutex_lock(&cinode->lock_mutex);
+	down_write(&cinode->lock_sem);
 	for (i = 0; i < 2; i++) {
 		cur = buf;
 		num = 0;
-		list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
+		list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
 			if (flock->fl_start > li->offset ||
 			    (flock->fl_start + length) <
 			    (li->offset + li->length))
@@ -1295,7 +1356,8 @@
 			 */
 			list_move(&li->llist, &tmp_llist);
 			if (++num == max_num) {
-				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+				stored_rc = cifs_lockv(xid, tcon,
+						       cfile->fid.netfid,
 						       li->type, num, 0, buf);
 				if (stored_rc) {
 					/*
@@ -1304,7 +1366,7 @@
 					 * list to the head of the file's list.
 					 */
 					cifs_move_llist(&tmp_llist,
-							&cfile->llist);
+							&cfile->llist->locks);
 					rc = stored_rc;
 				} else
 					/*
@@ -1318,23 +1380,24 @@
 				cur++;
 		}
 		if (num) {
-			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+			stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
 					       types[i], num, 0, buf);
 			if (stored_rc) {
-				cifs_move_llist(&tmp_llist, &cfile->llist);
+				cifs_move_llist(&tmp_llist,
+						&cfile->llist->locks);
 				rc = stored_rc;
 			} else
 				cifs_free_llist(&tmp_llist);
 		}
 	}
 
-	mutex_unlock(&cinode->lock_mutex);
+	up_write(&cinode->lock_sem);
 	kfree(buf);
 	return rc;
 }
 
 static int
-cifs_setlk(struct file *file,  struct file_lock *flock, __u32 type,
+cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
 	   bool wait_flag, bool posix_lck, int lock, int unlock,
 	   unsigned int xid)
 {
@@ -1343,7 +1406,6 @@
 	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	__u16 netfid = cfile->netfid;
 
 	if (posix_lck) {
 		int posix_lock_type;
@@ -1360,9 +1422,9 @@
 		if (unlock == 1)
 			posix_lock_type = CIFS_UNLCK;
 
-		rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
-				      flock->fl_start, length, NULL,
-				      posix_lock_type, wait_flag);
+		rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid,
+				      current->tgid, flock->fl_start, length,
+				      NULL, posix_lock_type, wait_flag);
 		goto out;
 	}
 
@@ -1379,8 +1441,8 @@
 		if (rc <= 0)
 			goto out;
 
-		rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
-					 type, 1, 0, wait_flag);
+		rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
+					    type, 1, 0, wait_flag);
 		if (rc) {
 			kfree(lock);
 			goto out;
@@ -1388,7 +1450,7 @@
 
 		cifs_lock_add(cfile, lock);
 	} else if (unlock)
-		rc = cifs_unlock_range(cfile, flock, xid);
+		rc = server->ops->mand_unlock_range(cfile, flock, xid);
 
 out:
 	if (flock->fl_flags & FL_POSIX)
@@ -1423,7 +1485,7 @@
 			tcon->ses->server);
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	netfid = cfile->netfid;
+	netfid = cfile->fid.netfid;
 	cinode = CIFS_I(file->f_path.dentry->d_inode);
 
 	if (cap_unix(tcon->ses) &&
@@ -1469,15 +1531,16 @@
 		cifsi->server_eof = end_of_write;
 }
 
-static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
-			  const char *write_data, size_t write_size,
-			  loff_t *poffset)
+static ssize_t
+cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
+	   size_t write_size, loff_t *offset)
 {
 	int rc = 0;
 	unsigned int bytes_written = 0;
 	unsigned int total_written;
 	struct cifs_sb_info *cifs_sb;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	unsigned int xid;
 	struct dentry *dentry = open_file->dentry;
 	struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
@@ -1486,9 +1549,13 @@
 	cifs_sb = CIFS_SB(dentry->d_sb);
 
 	cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
-	   *poffset, dentry->d_name.name);
+	     *offset, dentry->d_name.name);
 
-	pTcon = tlink_tcon(open_file->tlink);
+	tcon = tlink_tcon(open_file->tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->sync_write)
+		return -ENOSYS;
 
 	xid = get_xid();
 
@@ -1514,13 +1581,12 @@
 			/* iov[0] is reserved for smb header */
 			iov[1].iov_base = (char *)write_data + total_written;
 			iov[1].iov_len = len;
-			io_parms.netfid = open_file->netfid;
 			io_parms.pid = pid;
-			io_parms.tcon = pTcon;
-			io_parms.offset = *poffset;
+			io_parms.tcon = tcon;
+			io_parms.offset = *offset;
 			io_parms.length = len;
-			rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
-					   1, 0);
+			rc = server->ops->sync_write(xid, open_file, &io_parms,
+						     &bytes_written, iov, 1);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -1531,18 +1597,18 @@
 			}
 		} else {
 			spin_lock(&dentry->d_inode->i_lock);
-			cifs_update_eof(cifsi, *poffset, bytes_written);
+			cifs_update_eof(cifsi, *offset, bytes_written);
 			spin_unlock(&dentry->d_inode->i_lock);
-			*poffset += bytes_written;
+			*offset += bytes_written;
 		}
 	}
 
-	cifs_stats_bytes_written(pTcon, total_written);
+	cifs_stats_bytes_written(tcon, total_written);
 
 	if (total_written > 0) {
 		spin_lock(&dentry->d_inode->i_lock);
-		if (*poffset > dentry->d_inode->i_size)
-			i_size_write(dentry->d_inode, *poffset);
+		if (*offset > dentry->d_inode->i_size)
+			i_size_write(dentry->d_inode, *offset);
 		spin_unlock(&dentry->d_inode->i_lock);
 	}
 	mark_inode_dirty_sync(dentry->d_inode);
@@ -1718,27 +1784,6 @@
 	return rc;
 }
 
-/*
- * Marshal up the iov array, reserving the first one for the header. Also,
- * set wdata->bytes.
- */
-static void
-cifs_writepages_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
-{
-	int i;
-	struct inode *inode = wdata->cfile->dentry->d_inode;
-	loff_t size = i_size_read(inode);
-
-	/* marshal up the pages into iov array */
-	wdata->bytes = 0;
-	for (i = 0; i < wdata->nr_pages; i++) {
-		iov[i + 1].iov_len = min(size - page_offset(wdata->pages[i]),
-					(loff_t)PAGE_CACHE_SIZE);
-		iov[i + 1].iov_base = kmap(wdata->pages[i]);
-		wdata->bytes += iov[i + 1].iov_len;
-	}
-}
-
 static int cifs_writepages(struct address_space *mapping,
 			   struct writeback_control *wbc)
 {
@@ -1746,8 +1791,10 @@
 	bool done = false, scanned = false, range_whole = false;
 	pgoff_t end, index;
 	struct cifs_writedata *wdata;
+	struct TCP_Server_Info *server;
 	struct page *page;
 	int rc = 0;
+	loff_t isize = i_size_read(mapping->host);
 
 	/*
 	 * If wsize is smaller than the page cache size, default to writing
@@ -1852,7 +1899,7 @@
 			 */
 			set_page_writeback(page);
 
-			if (page_offset(page) >= mapping->host->i_size) {
+			if (page_offset(page) >= isize) {
 				done = true;
 				unlock_page(page);
 				end_page_writeback(page);
@@ -1883,7 +1930,12 @@
 		wdata->sync_mode = wbc->sync_mode;
 		wdata->nr_pages = nr_pages;
 		wdata->offset = page_offset(wdata->pages[0]);
-		wdata->marshal_iov = cifs_writepages_marshal_iov;
+		wdata->pagesz = PAGE_CACHE_SIZE;
+		wdata->tailsz =
+			min(isize - page_offset(wdata->pages[nr_pages - 1]),
+			    (loff_t)PAGE_CACHE_SIZE);
+		wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) +
+					wdata->tailsz;
 
 		do {
 			if (wdata->cfile != NULL)
@@ -1896,7 +1948,8 @@
 				break;
 			}
 			wdata->pid = wdata->cfile->pid;
-			rc = cifs_async_writev(wdata);
+			server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+			rc = server->ops->async_writev(wdata);
 		} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
 		for (i = 0; i < nr_pages; ++i)
@@ -2054,6 +2107,7 @@
 	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsFileInfo *smbfile = file->private_data;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2077,8 +2131,13 @@
 	}
 
 	tcon = tlink_tcon(smbfile->tlink);
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+		server = tcon->ses->server;
+		if (server->ops->flush)
+			rc = server->ops->flush(xid, tcon, &smbfile->fid);
+		else
+			rc = -ENOSYS;
+	}
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
@@ -2090,6 +2149,7 @@
 	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsFileInfo *smbfile = file->private_data;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct inode *inode = file->f_mapping->host;
@@ -2105,8 +2165,13 @@
 		file->f_path.dentry->d_name.name, datasync);
 
 	tcon = tlink_tcon(smbfile->tlink);
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+		server = tcon->ses->server;
+		if (server->ops->flush)
+			rc = server->ops->flush(xid, tcon, &smbfile->fid);
+		else
+			rc = -ENOSYS;
+	}
 
 	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
@@ -2172,20 +2237,6 @@
 }
 
 static void
-cifs_uncached_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
-{
-	int i;
-	size_t bytes = wdata->bytes;
-
-	/* marshal up the pages into iov array */
-	for (i = 0; i < wdata->nr_pages; i++) {
-		iov[i + 1].iov_len = min_t(size_t, bytes, PAGE_SIZE);
-		iov[i + 1].iov_base = kmap(wdata->pages[i]);
-		bytes -= iov[i + 1].iov_len;
-	}
-}
-
-static void
 cifs_uncached_writev_complete(struct work_struct *work)
 {
 	int i;
@@ -2215,6 +2266,9 @@
 cifs_uncached_retry_writev(struct cifs_writedata *wdata)
 {
 	int rc;
+	struct TCP_Server_Info *server;
+
+	server = tlink_tcon(wdata->cfile->tlink)->ses->server;
 
 	do {
 		if (wdata->cfile->invalidHandle) {
@@ -2222,7 +2276,7 @@
 			if (rc != 0)
 				continue;
 		}
-		rc = cifs_async_writev(wdata);
+		rc = server->ops->async_writev(wdata);
 	} while (rc == -EAGAIN);
 
 	return rc;
@@ -2257,6 +2311,10 @@
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
+
+	if (!tcon->ses->server->ops->async_writev)
+		return -ENOSYS;
+
 	offset = *poffset;
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
@@ -2298,7 +2356,8 @@
 		wdata->cfile = cifsFileInfo_get(open_file);
 		wdata->pid = pid;
 		wdata->bytes = cur_len;
-		wdata->marshal_iov = cifs_uncached_marshal_iov;
+		wdata->pagesz = PAGE_SIZE;
+		wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
 		rc = cifs_uncached_retry_writev(wdata);
 		if (rc) {
 			kref_put(&wdata->refcount, cifs_writedata_release);
@@ -2376,40 +2435,110 @@
 	return written;
 }
 
-ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
-			   unsigned long nr_segs, loff_t pos)
+static ssize_t
+cifs_writev(struct kiocb *iocb, const struct iovec *iov,
+	    unsigned long nr_segs, loff_t pos)
 {
-	struct inode *inode;
+	struct file *file = iocb->ki_filp;
+	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
+	struct inode *inode = file->f_mapping->host;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
+	ssize_t rc = -EACCES;
 
-	inode = iocb->ki_filp->f_path.dentry->d_inode;
+	BUG_ON(iocb->ki_pos != pos);
 
-	if (CIFS_I(inode)->clientCanCacheAll)
-		return generic_file_aio_write(iocb, iov, nr_segs, pos);
+	sb_start_write(inode->i_sb);
 
 	/*
-	 * In strict cache mode we need to write the data to the server exactly
-	 * from the pos to pos+len-1 rather than flush all affected pages
-	 * because it may cause a error with mandatory locks on these pages but
-	 * not on the region from pos to ppos+len-1.
+	 * We need to hold the sem to be sure nobody modifies lock list
+	 * with a brlock that prevents writing.
+	 */
+	down_read(&cinode->lock_sem);
+	if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+				     server->vals->exclusive_lock_type, NULL,
+				     true)) {
+		mutex_lock(&inode->i_mutex);
+		rc = __generic_file_aio_write(iocb, iov, nr_segs,
+					       &iocb->ki_pos);
+		mutex_unlock(&inode->i_mutex);
+	}
+
+	if (rc > 0 || rc == -EIOCBQUEUED) {
+		ssize_t err;
+
+		err = generic_write_sync(file, pos, rc);
+		if (err < 0 && rc > 0)
+			rc = err;
+	}
+
+	up_read(&cinode->lock_sem);
+	sb_end_write(inode->i_sb);
+	return rc;
+}
+
+ssize_t
+cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+		   unsigned long nr_segs, loff_t pos)
+{
+	struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsFileInfo *cfile = (struct cifsFileInfo *)
+						iocb->ki_filp->private_data;
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+
+#ifdef CONFIG_CIFS_SMB2
+	/*
+	 * If we have an oplock for read and want to write a data to the file
+	 * we need to store it in the page cache and then push it to the server
+	 * to be sure the next read will get a valid data.
+	 */
+	if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) {
+		ssize_t written;
+		int rc;
+
+		written = generic_file_aio_write(iocb, iov, nr_segs, pos);
+		rc = filemap_fdatawrite(inode->i_mapping);
+		if (rc)
+			return (ssize_t)rc;
+
+		return written;
+	}
+#endif
+
+	/*
+	 * For non-oplocked files in strict cache mode we need to write the data
+	 * to the server exactly from the pos to pos+len-1 rather than flush all
+	 * affected pages because it may cause a error with mandatory locks on
+	 * these pages but not on the region from pos to ppos+len-1.
 	 */
 
-	return cifs_user_writev(iocb, iov, nr_segs, pos);
+	if (!cinode->clientCanCacheAll)
+		return cifs_user_writev(iocb, iov, nr_segs, pos);
+
+	if (cap_unix(tcon->ses) &&
+	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+		return generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+	return cifs_writev(iocb, iov, nr_segs, pos);
 }
 
 static struct cifs_readdata *
-cifs_readdata_alloc(unsigned int nr_vecs, work_func_t complete)
+cifs_readdata_alloc(unsigned int nr_pages, work_func_t complete)
 {
 	struct cifs_readdata *rdata;
 
-	rdata = kzalloc(sizeof(*rdata) +
-			sizeof(struct kvec) * nr_vecs, GFP_KERNEL);
+	rdata = kzalloc(sizeof(*rdata) + (sizeof(struct page *) * nr_pages),
+			GFP_KERNEL);
 	if (rdata != NULL) {
 		kref_init(&rdata->refcount);
 		INIT_LIST_HEAD(&rdata->list);
 		init_completion(&rdata->done);
 		INIT_WORK(&rdata->work, complete);
-		INIT_LIST_HEAD(&rdata->pages);
 	}
+
 	return rdata;
 }
 
@@ -2426,25 +2555,25 @@
 }
 
 static int
-cifs_read_allocate_pages(struct list_head *list, unsigned int npages)
+cifs_read_allocate_pages(struct cifs_readdata *rdata, unsigned int nr_pages)
 {
 	int rc = 0;
-	struct page *page, *tpage;
+	struct page *page;
 	unsigned int i;
 
-	for (i = 0; i < npages; i++) {
+	for (i = 0; i < nr_pages; i++) {
 		page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
 		if (!page) {
 			rc = -ENOMEM;
 			break;
 		}
-		list_add(&page->lru, list);
+		rdata->pages[i] = page;
 	}
 
 	if (rc) {
-		list_for_each_entry_safe(page, tpage, list, lru) {
-			list_del(&page->lru);
-			put_page(page);
+		for (i = 0; i < nr_pages; i++) {
+			put_page(rdata->pages[i]);
+			rdata->pages[i] = NULL;
 		}
 	}
 	return rc;
@@ -2453,13 +2582,13 @@
 static void
 cifs_uncached_readdata_release(struct kref *refcount)
 {
-	struct page *page, *tpage;
 	struct cifs_readdata *rdata = container_of(refcount,
 					struct cifs_readdata, refcount);
+	unsigned int i;
 
-	list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-		list_del(&page->lru);
-		put_page(page);
+	for (i = 0; i < rdata->nr_pages; i++) {
+		put_page(rdata->pages[i]);
+		rdata->pages[i] = NULL;
 	}
 	cifs_readdata_release(refcount);
 }
@@ -2468,6 +2597,9 @@
 cifs_retry_async_readv(struct cifs_readdata *rdata)
 {
 	int rc;
+	struct TCP_Server_Info *server;
+
+	server = tlink_tcon(rdata->cfile->tlink)->ses->server;
 
 	do {
 		if (rdata->cfile->invalidHandle) {
@@ -2475,7 +2607,7 @@
 			if (rc != 0)
 				continue;
 		}
-		rc = cifs_async_readv(rdata);
+		rc = server->ops->async_readv(rdata);
 	} while (rc == -EAGAIN);
 
 	return rc;
@@ -2500,17 +2632,18 @@
 	int rc = 0;
 	struct iov_iter ii;
 	size_t pos = rdata->offset - offset;
-	struct page *page, *tpage;
 	ssize_t remaining = rdata->bytes;
 	unsigned char *pdata;
+	unsigned int i;
 
 	/* set up iov_iter and advance to the correct offset */
 	iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0);
 	iov_iter_advance(&ii, pos);
 
 	*copied = 0;
-	list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
+	for (i = 0; i < rdata->nr_pages; i++) {
 		ssize_t copy;
+		struct page *page = rdata->pages[i];
 
 		/* copy a whole page or whatever's left */
 		copy = min_t(ssize_t, remaining, PAGE_SIZE);
@@ -2530,9 +2663,6 @@
 				iov_iter_advance(&ii, copy);
 			}
 		}
-
-		list_del(&page->lru);
-		put_page(page);
 	}
 
 	return rc;
@@ -2544,59 +2674,56 @@
 	struct cifs_readdata *rdata = container_of(work,
 						struct cifs_readdata, work);
 
-	/* if the result is non-zero then the pages weren't kmapped */
-	if (rdata->result == 0) {
-		struct page *page;
-
-		list_for_each_entry(page, &rdata->pages, lru)
-			kunmap(page);
-	}
-
 	complete(&rdata->done);
 	kref_put(&rdata->refcount, cifs_uncached_readdata_release);
 }
 
 static int
-cifs_uncached_read_marshal_iov(struct cifs_readdata *rdata,
-				unsigned int remaining)
+cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
+			struct cifs_readdata *rdata, unsigned int len)
 {
-	int len = 0;
-	struct page *page, *tpage;
+	int total_read = 0, result = 0;
+	unsigned int i;
+	unsigned int nr_pages = rdata->nr_pages;
+	struct kvec iov;
 
-	rdata->nr_iov = 1;
-	list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-		if (remaining >= PAGE_SIZE) {
+	rdata->tailsz = PAGE_SIZE;
+	for (i = 0; i < nr_pages; i++) {
+		struct page *page = rdata->pages[i];
+
+		if (len >= PAGE_SIZE) {
 			/* enough data to fill the page */
-			rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-			rdata->iov[rdata->nr_iov].iov_len = PAGE_SIZE;
-			cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-				rdata->nr_iov, page->index,
-				rdata->iov[rdata->nr_iov].iov_base,
-				rdata->iov[rdata->nr_iov].iov_len);
-			++rdata->nr_iov;
-			len += PAGE_SIZE;
-			remaining -= PAGE_SIZE;
-		} else if (remaining > 0) {
+			iov.iov_base = kmap(page);
+			iov.iov_len = PAGE_SIZE;
+			cFYI(1, "%u: iov_base=%p iov_len=%zu",
+				i, iov.iov_base, iov.iov_len);
+			len -= PAGE_SIZE;
+		} else if (len > 0) {
 			/* enough for partial page, fill and zero the rest */
-			rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-			rdata->iov[rdata->nr_iov].iov_len = remaining;
-			cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-				rdata->nr_iov, page->index,
-				rdata->iov[rdata->nr_iov].iov_base,
-				rdata->iov[rdata->nr_iov].iov_len);
-			memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
-				'\0', PAGE_SIZE - remaining);
-			++rdata->nr_iov;
-			len += remaining;
-			remaining = 0;
+			iov.iov_base = kmap(page);
+			iov.iov_len = len;
+			cFYI(1, "%u: iov_base=%p iov_len=%zu",
+				i, iov.iov_base, iov.iov_len);
+			memset(iov.iov_base + len, '\0', PAGE_SIZE - len);
+			rdata->tailsz = len;
+			len = 0;
 		} else {
 			/* no need to hold page hostage */
-			list_del(&page->lru);
+			rdata->pages[i] = NULL;
+			rdata->nr_pages--;
 			put_page(page);
+			continue;
 		}
+
+		result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
+		kunmap(page);
+		if (result < 0)
+			break;
+
+		total_read += result;
 	}
 
-	return len;
+	return total_read > 0 ? total_read : result;
 }
 
 static ssize_t
@@ -2627,6 +2754,9 @@
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
 
+	if (!tcon->ses->server->ops->async_readv)
+		return -ENOSYS;
+
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
 	else
@@ -2647,15 +2777,17 @@
 			goto error;
 		}
 
-		rc = cifs_read_allocate_pages(&rdata->pages, npages);
+		rc = cifs_read_allocate_pages(rdata, npages);
 		if (rc)
 			goto error;
 
 		rdata->cfile = cifsFileInfo_get(open_file);
+		rdata->nr_pages = npages;
 		rdata->offset = offset;
 		rdata->bytes = cur_len;
 		rdata->pid = pid;
-		rdata->marshal_iov = cifs_uncached_read_marshal_iov;
+		rdata->pagesz = PAGE_SIZE;
+		rdata->read_into_pages = cifs_uncached_read_into_pages;
 
 		rc = cifs_retry_async_readv(rdata);
 error:
@@ -2706,6 +2838,10 @@
 	cifs_stats_bytes_read(tcon, total_read);
 	*poffset += total_read;
 
+	/* mask nodata case */
+	if (rc == -ENODATA)
+		rc = 0;
+
 	return total_read ? total_read : rc;
 }
 
@@ -2721,15 +2857,17 @@
 	return read;
 }
 
-ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
-			  unsigned long nr_segs, loff_t pos)
+ssize_t
+cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+		  unsigned long nr_segs, loff_t pos)
 {
-	struct inode *inode;
-
-	inode = iocb->ki_filp->f_path.dentry->d_inode;
-
-	if (CIFS_I(inode)->clientCanCacheRead)
-		return generic_file_aio_read(iocb, iov, nr_segs, pos);
+	struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifsFileInfo *cfile = (struct cifsFileInfo *)
+						iocb->ki_filp->private_data;
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+	int rc = -EACCES;
 
 	/*
 	 * In strict cache mode we need to read from the server all the time
@@ -2739,12 +2877,29 @@
 	 * on pages affected by this read but not on the region from pos to
 	 * pos+len-1.
 	 */
+	if (!cinode->clientCanCacheRead)
+		return cifs_user_readv(iocb, iov, nr_segs, pos);
 
-	return cifs_user_readv(iocb, iov, nr_segs, pos);
+	if (cap_unix(tcon->ses) &&
+	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+		return generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+	/*
+	 * We need to hold the sem to be sure nobody modifies lock list
+	 * with a brlock that prevents reading.
+	 */
+	down_read(&cinode->lock_sem);
+	if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+				     tcon->ses->server->vals->shared_lock_type,
+				     NULL, true))
+		rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+	up_read(&cinode->lock_sem);
+	return rc;
 }
 
-static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
-			 loff_t *poffset)
+static ssize_t
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
 {
 	int rc = -EACCES;
 	unsigned int bytes_read = 0;
@@ -2753,8 +2908,9 @@
 	unsigned int rsize;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	unsigned int xid;
-	char *current_offset;
+	char *cur_offset;
 	struct cifsFileInfo *open_file;
 	struct cifs_io_parms io_parms;
 	int buf_type = CIFS_NO_BUFFER;
@@ -2773,6 +2929,12 @@
 	}
 	open_file = file->private_data;
 	tcon = tlink_tcon(open_file->tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->sync_read) {
+		free_xid(xid);
+		return -ENOSYS;
+	}
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
@@ -2782,9 +2944,8 @@
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, "attempting read on write only file instance");
 
-	for (total_read = 0, current_offset = read_data;
-	     read_size > total_read;
-	     total_read += bytes_read, current_offset += bytes_read) {
+	for (total_read = 0, cur_offset = read_data; read_size > total_read;
+	     total_read += bytes_read, cur_offset += bytes_read) {
 		current_read_size = min_t(uint, read_size - total_read, rsize);
 		/*
 		 * For windows me and 9x we do not want to request more than it
@@ -2802,13 +2963,13 @@
 				if (rc != 0)
 					break;
 			}
-			io_parms.netfid = open_file->netfid;
 			io_parms.pid = pid;
 			io_parms.tcon = tcon;
-			io_parms.offset = *poffset;
+			io_parms.offset = *offset;
 			io_parms.length = current_read_size;
-			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
-					 &current_offset, &buf_type);
+			rc = server->ops->sync_read(xid, open_file, &io_parms,
+						    &bytes_read, &cur_offset,
+						    &buf_type);
 		}
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
@@ -2819,7 +2980,7 @@
 			}
 		} else {
 			cifs_stats_bytes_read(tcon, total_read);
-			*poffset += bytes_read;
+			*offset += bytes_read;
 		}
 	}
 	free_xid(xid);
@@ -2885,16 +3046,16 @@
 static void
 cifs_readv_complete(struct work_struct *work)
 {
+	unsigned int i;
 	struct cifs_readdata *rdata = container_of(work,
 						struct cifs_readdata, work);
-	struct page *page, *tpage;
 
-	list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-		list_del(&page->lru);
+	for (i = 0; i < rdata->nr_pages; i++) {
+		struct page *page = rdata->pages[i];
+
 		lru_cache_add_file(page);
 
 		if (rdata->result == 0) {
-			kunmap(page);
 			flush_dcache_page(page);
 			SetPageUptodate(page);
 		}
@@ -2905,49 +3066,48 @@
 			cifs_readpage_to_fscache(rdata->mapping->host, page);
 
 		page_cache_release(page);
+		rdata->pages[i] = NULL;
 	}
 	kref_put(&rdata->refcount, cifs_readdata_release);
 }
 
 static int
-cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining)
+cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
+			struct cifs_readdata *rdata, unsigned int len)
 {
-	int len = 0;
-	struct page *page, *tpage;
+	int total_read = 0, result = 0;
+	unsigned int i;
 	u64 eof;
 	pgoff_t eof_index;
+	unsigned int nr_pages = rdata->nr_pages;
+	struct kvec iov;
 
 	/* determine the eof that the server (probably) has */
 	eof = CIFS_I(rdata->mapping->host)->server_eof;
 	eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
 	cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
 
-	rdata->nr_iov = 1;
-	list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-		if (remaining >= PAGE_CACHE_SIZE) {
+	rdata->tailsz = PAGE_CACHE_SIZE;
+	for (i = 0; i < nr_pages; i++) {
+		struct page *page = rdata->pages[i];
+
+		if (len >= PAGE_CACHE_SIZE) {
 			/* enough data to fill the page */
-			rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-			rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
+			iov.iov_base = kmap(page);
+			iov.iov_len = PAGE_CACHE_SIZE;
 			cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-				rdata->nr_iov, page->index,
-				rdata->iov[rdata->nr_iov].iov_base,
-				rdata->iov[rdata->nr_iov].iov_len);
-			++rdata->nr_iov;
-			len += PAGE_CACHE_SIZE;
-			remaining -= PAGE_CACHE_SIZE;
-		} else if (remaining > 0) {
+				i, page->index, iov.iov_base, iov.iov_len);
+			len -= PAGE_CACHE_SIZE;
+		} else if (len > 0) {
 			/* enough for partial page, fill and zero the rest */
-			rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-			rdata->iov[rdata->nr_iov].iov_len = remaining;
+			iov.iov_base = kmap(page);
+			iov.iov_len = len;
 			cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-				rdata->nr_iov, page->index,
-				rdata->iov[rdata->nr_iov].iov_base,
-				rdata->iov[rdata->nr_iov].iov_len);
-			memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
-				'\0', PAGE_CACHE_SIZE - remaining);
-			++rdata->nr_iov;
-			len += remaining;
-			remaining = 0;
+				i, page->index, iov.iov_base, iov.iov_len);
+			memset(iov.iov_base + len,
+				'\0', PAGE_CACHE_SIZE - len);
+			rdata->tailsz = len;
+			len = 0;
 		} else if (page->index > eof_index) {
 			/*
 			 * The VFS will not try to do readahead past the
@@ -2958,22 +3118,33 @@
 			 * fill them until the writes are flushed.
 			 */
 			zero_user(page, 0, PAGE_CACHE_SIZE);
-			list_del(&page->lru);
 			lru_cache_add_file(page);
 			flush_dcache_page(page);
 			SetPageUptodate(page);
 			unlock_page(page);
 			page_cache_release(page);
+			rdata->pages[i] = NULL;
+			rdata->nr_pages--;
+			continue;
 		} else {
 			/* no need to hold page hostage */
-			list_del(&page->lru);
 			lru_cache_add_file(page);
 			unlock_page(page);
 			page_cache_release(page);
+			rdata->pages[i] = NULL;
+			rdata->nr_pages--;
+			continue;
 		}
+
+		result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
+		kunmap(page);
+		if (result < 0)
+			break;
+
+		total_read += result;
 	}
 
-	return len;
+	return total_read > 0 ? total_read : result;
 }
 
 static int cifs_readpages(struct file *file, struct address_space *mapping,
@@ -3027,6 +3198,7 @@
 	 * the rdata->pages, then we want them in increasing order.
 	 */
 	while (!list_empty(page_list)) {
+		unsigned int i;
 		unsigned int bytes = PAGE_CACHE_SIZE;
 		unsigned int expected_index;
 		unsigned int nr_pages = 1;
@@ -3096,14 +3268,18 @@
 		rdata->offset = offset;
 		rdata->bytes = bytes;
 		rdata->pid = pid;
-		rdata->marshal_iov = cifs_readpages_marshal_iov;
-		list_splice_init(&tmplist, &rdata->pages);
+		rdata->pagesz = PAGE_CACHE_SIZE;
+		rdata->read_into_pages = cifs_readpages_read_into_pages;
+
+		list_for_each_entry_safe(page, tpage, &tmplist, lru) {
+			list_del(&page->lru);
+			rdata->pages[rdata->nr_pages++] = page;
+		}
 
 		rc = cifs_retry_async_readv(rdata);
 		if (rc != 0) {
-			list_for_each_entry_safe(page, tpage, &rdata->pages,
-						 lru) {
-				list_del(&page->lru);
+			for (i = 0; i < rdata->nr_pages; i++) {
+				page = rdata->pages[i];
 				lru_cache_add_file(page);
 				unlock_page(page);
 				page_cache_release(page);
@@ -3347,6 +3523,7 @@
 						  oplock_break);
 	struct inode *inode = cfile->dentry->d_inode;
 	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	int rc = 0;
 
 	if (inode && S_ISREG(inode->i_mode)) {
@@ -3374,10 +3551,8 @@
 	 * disconnected since oplock already released by the server
 	 */
 	if (!cfile->oplock_break_cancelled) {
-		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
-				 current->tgid, 0, 0, 0, 0,
-				 LOCKING_ANDX_OPLOCK_RELEASE, false,
-				 cinode->clientCanCacheRead ? 1 : 0);
+		rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
+							     cinode);
 		cFYI(1, "Oplock release rc = %d", rc);
 	}
 }
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cb79c7e..afdff79 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -282,7 +282,8 @@
 	fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
 {
 	int rc;
 	unsigned int xid;
@@ -294,7 +295,7 @@
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
 	xid = get_xid();
-	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
 	if (!rc) {
 		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
 	} else if (rc == -EREMOTE) {
@@ -550,7 +551,8 @@
 	fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
 {
 	int rc;
 	unsigned int xid;
@@ -560,9 +562,13 @@
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifsFileInfo *cfile = filp->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+	struct TCP_Server_Info *server = tcon->ses->server;
+
+	if (!server->ops->query_file_info)
+		return -ENOSYS;
 
 	xid = get_xid();
-	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+	rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
 	switch (rc) {
 	case 0:
 		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -601,7 +607,9 @@
 		    FILE_ALL_INFO *data, struct super_block *sb, int xid,
 		    const __u16 *fid)
 {
-	int rc = 0, tmprc;
+	bool validinum = false;
+	__u16 srchflgs;
+	int rc = 0, tmprc = ENOSYS;
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
 	struct tcon_link *tlink;
@@ -609,6 +617,7 @@
 	char *buf = NULL;
 	bool adjust_tz = false;
 	struct cifs_fattr fattr;
+	struct cifs_search_info *srchinf = NULL;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -647,9 +656,38 @@
 	} else if (rc == -EREMOTE) {
 		cifs_create_dfs_fattr(&fattr, sb);
 		rc = 0;
-	} else {
+	} else if (rc == -EACCES && backup_cred(cifs_sb)) {
+			srchinf = kzalloc(sizeof(struct cifs_search_info),
+						GFP_KERNEL);
+			if (srchinf == NULL) {
+				rc = -ENOMEM;
+				goto cgii_exit;
+			}
+
+			srchinf->endOfSearch = false;
+			srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+
+			srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+					CIFS_SEARCH_CLOSE_AT_END |
+					CIFS_SEARCH_BACKUP_SEARCH;
+
+			rc = CIFSFindFirst(xid, tcon, full_path,
+				cifs_sb, NULL, srchflgs, srchinf, false);
+			if (!rc) {
+				data =
+				(FILE_ALL_INFO *)srchinf->srch_entries_start;
+
+				cifs_dir_info_to_fattr(&fattr,
+				(FILE_DIRECTORY_INFO *)data, cifs_sb);
+				fattr.cf_uniqueid = le64_to_cpu(
+				((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+				validinum = true;
+
+				cifs_buf_release(srchinf->ntwrk_buf_start);
+			}
+			kfree(srchinf);
+	} else
 		goto cgii_exit;
-	}
 
 	/*
 	 * If an inode wasn't passed in, then get the inode number
@@ -660,23 +698,21 @@
 	 */
 	if (*inode == NULL) {
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-			if (server->ops->get_srv_inum)
-				tmprc = server->ops->get_srv_inum(xid, tcon,
-					cifs_sb, full_path, &fattr.cf_uniqueid,
-					data);
-			else
-				tmprc = -ENOSYS;
-			if (tmprc || !fattr.cf_uniqueid) {
-				cFYI(1, "GetSrvInodeNum rc %d", tmprc);
-				fattr.cf_uniqueid = iunique(sb, ROOT_I);
-				cifs_autodisable_serverino(cifs_sb);
+			if (validinum == false) {
+				if (server->ops->get_srv_inum)
+					tmprc = server->ops->get_srv_inum(xid,
+						tcon, cifs_sb, full_path,
+						&fattr.cf_uniqueid, data);
+				if (tmprc) {
+					cFYI(1, "GetSrvInodeNum rc %d", tmprc);
+					fattr.cf_uniqueid = iunique(sb, ROOT_I);
+					cifs_autodisable_serverino(cifs_sb);
+				}
 			}
-		} else {
+		} else
 			fattr.cf_uniqueid = iunique(sb, ROOT_I);
-		}
-	} else {
+	} else
 		fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
-	}
 
 	/* query for SFU type info if supported and needed */
 	if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
@@ -876,25 +912,22 @@
 	return inode;
 }
 
-static int
+int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-		    char *full_path, __u32 dosattr)
+		   char *full_path, __u32 dosattr)
 {
-	int rc;
-	int oplock = 0;
-	__u16 netfid;
-	__u32 netpid;
 	bool set_time = false;
-	struct cifsFileInfo *open_file;
-	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon;
+	struct TCP_Server_Info *server;
 	FILE_BASIC_INFO	info_buf;
 
 	if (attrs == NULL)
 		return -EINVAL;
 
+	server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+	if (!server->ops->set_file_info)
+		return -ENOSYS;
+
 	if (attrs->ia_valid & ATTR_ATIME) {
 		set_time = true;
 		info_buf.LastAccessTime =
@@ -925,81 +958,17 @@
 	info_buf.CreationTime = 0;	/* don't change */
 	info_buf.Attributes = cpu_to_le32(dosattr);
 
-	/*
-	 * If the file is already open for write, just use that fileid
-	 */
-	open_file = find_writable_file(cifsInode, true);
-	if (open_file) {
-		netfid = open_file->netfid;
-		netpid = open_file->pid;
-		pTcon = tlink_tcon(open_file->tlink);
-		goto set_via_filehandle;
-	}
-
-	tlink = cifs_sb_tlink(cifs_sb);
-	if (IS_ERR(tlink)) {
-		rc = PTR_ERR(tlink);
-		tlink = NULL;
-		goto out;
-	}
-	pTcon = tlink_tcon(tlink);
-
-	/*
-	 * NT4 apparently returns success on this call, but it doesn't
-	 * really work.
-	 */
-	if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
-		rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-				     &info_buf, cifs_sb->local_nls,
-				     cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == 0) {
-			cifsInode->cifsAttrs = dosattr;
-			goto out;
-		} else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-			goto out;
-	}
-
-	cFYI(1, "calling SetFileInfo since SetPathInfo for "
-		 "times not supported by this server");
-	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-			 CREATE_NOT_DIR, &netfid, &oplock,
-			 NULL, cifs_sb->local_nls,
-			 cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-	if (rc != 0) {
-		if (rc == -EIO)
-			rc = -EINVAL;
-		goto out;
-	}
-
-	netpid = current->tgid;
-
-set_via_filehandle:
-	rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
-	if (!rc)
-		cifsInode->cifsAttrs = dosattr;
-
-	if (open_file == NULL)
-		CIFSSMBClose(xid, pTcon, netfid);
-	else
-		cifsFileInfo_put(open_file);
-out:
-	if (tlink != NULL)
-		cifs_put_tlink(tlink);
-	return rc;
+	return server->ops->set_file_info(inode, full_path, &info_buf, xid);
 }
 
 /*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
  * and rename it to a random name that hopefully won't conflict with
  * anything else.
  */
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
-			   unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+			   const unsigned int xid)
 {
 	int oplock = 0;
 	int rc;
@@ -1136,6 +1105,7 @@
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct iattr *attrs = NULL;
 	__u32 dosattr = 0, origattr = 0;
 
@@ -1145,6 +1115,7 @@
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
 
 	xid = get_xid();
 
@@ -1167,8 +1138,12 @@
 	}
 
 retry_std_delete:
-	rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
-			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (!server->ops->unlink) {
+		rc = -ENOSYS;
+		goto psx_del_no_retry;
+	}
+
+	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
 
 psx_del_no_retry:
 	if (!rc) {
@@ -1177,9 +1152,14 @@
 	} else if (rc == -ENOENT) {
 		d_drop(dentry);
 	} else if (rc == -ETXTBSY) {
-		rc = cifs_rename_pending_delete(full_path, dentry, xid);
-		if (rc == 0)
-			cifs_drop_nlink(inode);
+		if (server->ops->rename_pending_delete) {
+			rc = server->ops->rename_pending_delete(full_path,
+								dentry, xid);
+			if (rc == 0)
+				cifs_drop_nlink(inode);
+		}
+		if (rc == -ETXTBSY)
+			rc = -EBUSY;
 	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
 		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
 		if (attrs == NULL) {
@@ -1227,34 +1207,33 @@
 }
 
 static int
-cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
+cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
 		 const char *full_path, struct cifs_sb_info *cifs_sb,
 		 struct cifs_tcon *tcon, const unsigned int xid)
 {
 	int rc = 0;
-	struct inode *newinode = NULL;
+	struct inode *inode = NULL;
 
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+		rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
 					      xid);
 	else
-		rc = cifs_get_inode_info(&newinode, full_path, NULL,
-					 inode->i_sb, xid, NULL);
+		rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb,
+					 xid, NULL);
+
 	if (rc)
 		return rc;
 
-	d_instantiate(dentry, newinode);
 	/*
 	 * setting nlink not necessary except in cases where we failed to get it
-	 * from the server or was set bogus
+	 * from the server or was set bogus. Also, since this is a brand new
+	 * inode, no need to grab the i_lock before setting the i_nlink.
 	 */
-	spin_lock(&dentry->d_inode->i_lock);
-	if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
-		set_nlink(dentry->d_inode, 2);
-	spin_unlock(&dentry->d_inode->i_lock);
+	if (inode->i_nlink < 2)
+		set_nlink(inode, 2);
 	mode &= ~current_umask();
 	/* must turn on setgid bit if parent dir has it */
-	if (inode->i_mode & S_ISGID)
+	if (parent->i_mode & S_ISGID)
 		mode |= S_ISGID;
 
 	if (tcon->unix_ext) {
@@ -1267,8 +1246,8 @@
 		};
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 			args.uid = (__u64)current_fsuid();
-			if (inode->i_mode & S_ISGID)
-				args.gid = (__u64)inode->i_gid;
+			if (parent->i_mode & S_ISGID)
+				args.gid = (__u64)parent->i_gid;
 			else
 				args.gid = (__u64)current_fsgid();
 		} else {
@@ -1283,22 +1262,20 @@
 		struct TCP_Server_Info *server = tcon->ses->server;
 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
 		    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
-			server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
+			server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
 						   tcon, xid);
-		if (dentry->d_inode) {
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
-				dentry->d_inode->i_mode = (mode | S_IFDIR);
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+			inode->i_mode = (mode | S_IFDIR);
 
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				dentry->d_inode->i_uid = current_fsuid();
-				if (inode->i_mode & S_ISGID)
-					dentry->d_inode->i_gid = inode->i_gid;
-				else
-					dentry->d_inode->i_gid =
-								current_fsgid();
-			}
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+			inode->i_uid = current_fsuid();
+			if (inode->i_mode & S_ISGID)
+				inode->i_gid = parent->i_gid;
+			else
+				inode->i_gid = current_fsgid();
 		}
 	}
+	d_instantiate(dentry, inode);
 	return rc;
 }
 
@@ -1495,29 +1472,32 @@
 }
 
 static int
-cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
-	       const char *fromPath, struct dentry *to_dentry,
-	       const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+	       const char *from_path, struct dentry *to_dentry,
+	       const char *to_path)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	__u16 srcfid;
 	int oplock, rc;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
+	server = tcon->ses->server;
+
+	if (!server->ops->rename)
+		return -ENOSYS;
 
 	/* try path-based rename first */
-	rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
-			   cifs_sb->mnt_cifs_flags &
-				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
 
 	/*
-	 * don't bother with rename by filehandle unless file is busy and
-	 * source Note that cross directory moves do not work with
+	 * Don't bother with rename by filehandle unless file is busy and
+	 * source. Note that cross directory moves do not work with
 	 * rename by filehandle to various Windows servers.
 	 */
 	if (rc == 0 || rc != -ETXTBSY)
@@ -1528,29 +1508,28 @@
 		goto do_rename_exit;
 
 	/* open the file to be renamed -- we need DELETE perms */
-	rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+	rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
 			 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
-
 	if (rc == 0) {
-		rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+		rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
 				(const char *) to_dentry->d_name.name,
 				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-		CIFSSMBClose(xid, pTcon, srcfid);
+		CIFSSMBClose(xid, tcon, srcfid);
 	}
 do_rename_exit:
 	cifs_put_tlink(tlink);
 	return rc;
 }
 
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
-	struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+	    struct inode *target_dir, struct dentry *target_dentry)
 {
-	char *fromName = NULL;
-	char *toName = NULL;
+	char *from_name = NULL;
+	char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -1571,25 +1550,25 @@
 	 * we already have the rename sem so we do not need to
 	 * grab it again here to protect the path integrity
 	 */
-	fromName = build_path_from_dentry(source_dentry);
-	if (fromName == NULL) {
+	from_name = build_path_from_dentry(source_dentry);
+	if (from_name == NULL) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
-	toName = build_path_from_dentry(target_dentry);
-	if (toName == NULL) {
+	to_name = build_path_from_dentry(target_dentry);
+	if (to_name == NULL) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
 	}
 
-	rc = cifs_do_rename(xid, source_dentry, fromName,
-			    target_dentry, toName);
+	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+			    to_name);
 
 	if (rc == -EEXIST && tcon->unix_ext) {
 		/*
-		 * Are src and dst hardlinks of same inode? We can
-		 * only tell with unix extensions enabled
+		 * Are src and dst hardlinks of same inode? We can only tell
+		 * with unix extensions enabled.
 		 */
 		info_buf_source =
 			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1600,19 +1579,19 @@
 		}
 
 		info_buf_target = info_buf_source + 1;
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
-					info_buf_source,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+					     info_buf_source,
+					     cifs_sb->local_nls,
+					     cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 		if (tmprc != 0)
 			goto unlink_target;
 
-		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
-					info_buf_target,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+					     info_buf_target,
+					     cifs_sb->local_nls,
+					     cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 		if (tmprc == 0 && (info_buf_source->UniqueId ==
 				   info_buf_target->UniqueId)) {
@@ -1620,8 +1599,11 @@
 			rc = 0;
 			goto cifs_rename_exit;
 		}
-	} /* else ... BB we could add the same check for Windows by
-		     checking the UniqueId via FILE_INTERNAL_INFO */
+	}
+	/*
+	 * else ... BB we could add the same check for Windows by
+	 * checking the UniqueId via FILE_INTERNAL_INFO
+	 */
 
 unlink_target:
 	/* Try unlinking the target dentry if it's not negative */
@@ -1629,15 +1611,14 @@
 		tmprc = cifs_unlink(target_dir, target_dentry);
 		if (tmprc)
 			goto cifs_rename_exit;
-
-		rc = cifs_do_rename(xid, source_dentry, fromName,
-				    target_dentry, toName);
+		rc = cifs_do_rename(xid, source_dentry, from_name,
+				    target_dentry, to_name);
 	}
 
 cifs_rename_exit:
 	kfree(info_buf_source);
-	kfree(fromName);
-	kfree(toName);
+	kfree(from_name);
+	kfree(to_name);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -1862,7 +1843,8 @@
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink = NULL;
-	struct cifs_tcon *pTcon = NULL;
+	struct cifs_tcon *tcon = NULL;
+	struct TCP_Server_Info *server;
 	struct cifs_io_parms io_parms;
 
 	/*
@@ -1876,19 +1858,21 @@
 	 */
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		__u16 nfid = open_file->netfid;
-		__u32 npid = open_file->pid;
-		pTcon = tlink_tcon(open_file->tlink);
-		rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
-					npid, false);
+		tcon = tlink_tcon(open_file->tlink);
+		server = tcon->ses->server;
+		if (server->ops->set_file_size)
+			rc = server->ops->set_file_size(xid, tcon, open_file,
+							attrs->ia_size, false);
+		else
+			rc = -ENOSYS;
 		cifsFileInfo_put(open_file);
 		cFYI(1, "SetFSize for attrs rc = %d", rc);
 		if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 			unsigned int bytes_written;
 
-			io_parms.netfid = nfid;
-			io_parms.pid = npid;
-			io_parms.tcon = pTcon;
+			io_parms.netfid = open_file->fid.netfid;
+			io_parms.pid = open_file->pid;
+			io_parms.tcon = tcon;
 			io_parms.offset = 0;
 			io_parms.length = attrs->ia_size;
 			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1898,52 +1882,55 @@
 	} else
 		rc = -EINVAL;
 
-	if (rc != 0) {
-		if (pTcon == NULL) {
-			tlink = cifs_sb_tlink(cifs_sb);
-			if (IS_ERR(tlink))
-				return PTR_ERR(tlink);
-			pTcon = tlink_tcon(tlink);
-		}
+	if (!rc)
+		goto set_size_out;
 
-		/* Set file size by pathname rather than by handle
-		   either because no valid, writeable file handle for
-		   it was found or because there was an error setting
-		   it by handle */
-		rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
-				   false, cifs_sb->local_nls,
-				   cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
-		if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
-			__u16 netfid;
-			int oplock = 0;
-
-			rc = SMBLegacyOpen(xid, pTcon, full_path,
-				FILE_OPEN, GENERIC_WRITE,
-				CREATE_NOT_DIR, &netfid, &oplock, NULL,
-				cifs_sb->local_nls,
-				cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-			if (rc == 0) {
-				unsigned int bytes_written;
-
-				io_parms.netfid = netfid;
-				io_parms.pid = current->tgid;
-				io_parms.tcon = pTcon;
-				io_parms.offset = 0;
-				io_parms.length = attrs->ia_size;
-				rc = CIFSSMBWrite(xid, &io_parms,
-						  &bytes_written,
-						  NULL, NULL,  1);
-				cFYI(1, "wrt seteof rc %d", rc);
-				CIFSSMBClose(xid, pTcon, netfid);
-			}
-		}
-		if (tlink)
-			cifs_put_tlink(tlink);
+	if (tcon == NULL) {
+		tlink = cifs_sb_tlink(cifs_sb);
+		if (IS_ERR(tlink))
+			return PTR_ERR(tlink);
+		tcon = tlink_tcon(tlink);
+		server = tcon->ses->server;
 	}
 
+	/*
+	 * Set file size by pathname rather than by handle either because no
+	 * valid, writeable file handle for it was found or because there was
+	 * an error setting it by handle.
+	 */
+	if (server->ops->set_path_size)
+		rc = server->ops->set_path_size(xid, tcon, full_path,
+						attrs->ia_size, cifs_sb, false);
+	else
+		rc = -ENOSYS;
+	cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+	if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+		__u16 netfid;
+		int oplock = 0;
+
+		rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+				   GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+				   &oplock, NULL, cifs_sb->local_nls,
+				   cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc == 0) {
+			unsigned int bytes_written;
+
+			io_parms.netfid = netfid;
+			io_parms.pid = current->tgid;
+			io_parms.tcon = tcon;
+			io_parms.offset = 0;
+			io_parms.length = attrs->ia_size;
+			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+					  NULL,  1);
+			cFYI(1, "wrt seteof rc %d", rc);
+			CIFSSMBClose(xid, tcon, netfid);
+		}
+	}
+	if (tlink)
+		cifs_put_tlink(tlink);
+
+set_size_out:
 	if (rc == 0) {
 		cifsInode->server_eof = attrs->ia_size;
 		cifs_setsize(inode, attrs->ia_size);
@@ -2050,7 +2037,7 @@
 	args->device = 0;
 	open_file = find_writable_file(cifsInode, true);
 	if (open_file) {
-		u16 nfid = open_file->netfid;
+		u16 nfid = open_file->fid.netfid;
 		u32 npid = open_file->pid;
 		pTcon = tlink_tcon(open_file->tlink);
 		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index ae082a6..fd5009d 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -28,8 +28,6 @@
 #include "cifs_debug.h"
 #include "cifsfs.h"
 
-#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
-
 long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 {
 	struct inode *inode = filep->f_dentry->d_inode;
@@ -51,23 +49,6 @@
 	cifs_sb = CIFS_SB(inode->i_sb);
 
 	switch (command) {
-		static bool warned = false;
-		case CIFS_IOC_CHECKUMOUNT:
-			if (!warned) {
-				warned = true;
-				cERROR(1, "the CIFS_IOC_CHECKMOUNT ioctl will "
-					  "be deprecated in 3.7. Please "
-					  "migrate away from the use of "
-					  "umount.cifs");
-			}
-			cFYI(1, "User unmount attempted");
-			if (cifs_sb->mnt_uid == current_uid())
-				rc = 0;
-			else {
-				rc = -EACCES;
-				cFYI(1, "uids do not match");
-			}
-			break;
 #ifdef CONFIG_CIFS_POSIX
 		case FS_IOC_GETFLAGS:
 			if (pSMBFile == NULL)
@@ -75,8 +56,9 @@
 			tcon = tlink_tcon(pSMBFile->tlink);
 			caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 			if (CIFS_UNIX_EXTATTR_CAP & caps) {
-				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
-					&ExtAttrBits, &ExtAttrMask);
+				rc = CIFSGetExtAttr(xid, tcon,
+						    pSMBFile->fid.netfid,
+						    &ExtAttrBits, &ExtAttrMask);
 				if (rc == 0)
 					rc = put_user(ExtAttrBits &
 						FS_FL_USER_VISIBLE,
@@ -94,8 +76,12 @@
 					rc = -EFAULT;
 					break;
 				}
-				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
-					extAttrBits, &ExtAttrMask);*/
+				/*
+				 * rc = CIFSGetExtAttr(xid, tcon,
+				 *		       pSMBFile->fid.netfid,
+				 *		       extAttrBits,
+				 *		       &ExtAttrMask);
+				 */
 			}
 			cFYI(1, "set flags not implemented yet");
 			break;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index e6ce3b1..51dc2fb 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -391,72 +391,86 @@
 {
 	int rc = -EACCES;
 	unsigned int xid;
-	char *fromName = NULL;
-	char *toName = NULL;
+	char *from_name = NULL;
+	char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 	struct cifsInodeInfo *cifsInode;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
-	pTcon = tlink_tcon(tlink);
+	tcon = tlink_tcon(tlink);
 
 	xid = get_xid();
 
-	fromName = build_path_from_dentry(old_file);
-	toName = build_path_from_dentry(direntry);
-	if ((fromName == NULL) || (toName == NULL)) {
+	from_name = build_path_from_dentry(old_file);
+	to_name = build_path_from_dentry(direntry);
+	if ((from_name == NULL) || (to_name == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_hl_exit;
 	}
 
-	if (pTcon->unix_ext)
-		rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+	if (tcon->unix_ext)
+		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
 					    cifs_sb->local_nls,
 					    cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else {
-		rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-					cifs_sb->local_nls,
-					cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		server = tcon->ses->server;
+		if (!server->ops->create_hardlink)
+			return -ENOSYS;
+		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
+						  cifs_sb);
 		if ((rc == -EIO) || (rc == -EINVAL))
 			rc = -EOPNOTSUPP;
 	}
 
 	d_drop(direntry);	/* force new lookup from server of target */
 
-	/* if source file is cached (oplocked) revalidate will not go to server
-	   until the file is closed or oplock broken so update nlinks locally */
+	/*
+	 * if source file is cached (oplocked) revalidate will not go to server
+	 * until the file is closed or oplock broken so update nlinks locally
+	 */
 	if (old_file->d_inode) {
 		cifsInode = CIFS_I(old_file->d_inode);
 		if (rc == 0) {
 			spin_lock(&old_file->d_inode->i_lock);
 			inc_nlink(old_file->d_inode);
 			spin_unlock(&old_file->d_inode->i_lock);
-/* BB should we make this contingent on superblock flag NOATIME? */
-/*			old_file->d_inode->i_ctime = CURRENT_TIME;*/
-			/* parent dir timestamps will update from srv
-			within a second, would it really be worth it
-			to set the parent dir cifs inode time to zero
-			to force revalidate (faster) for it too? */
+			/*
+			 * BB should we make this contingent on superblock flag
+			 * NOATIME?
+			 */
+			/* old_file->d_inode->i_ctime = CURRENT_TIME; */
+			/*
+			 * parent dir timestamps will update from srv within a
+			 * second, would it really be worth it to set the parent
+			 * dir cifs inode time to zero to force revalidate
+			 * (faster) for it too?
+			 */
 		}
-		/* if not oplocked will force revalidate to get info
-		   on source file from srv */
+		/*
+		 * if not oplocked will force revalidate to get info on source
+		 * file from srv
+		 */
 		cifsInode->time = 0;
 
-		/* Will update parent dir timestamps from srv within a second.
-		   Would it really be worth it to set the parent dir (cifs
-		   inode) time field to zero to force revalidate on parent
-		   directory faster ie
-			CIFS_I(inode)->time = 0;  */
+		/*
+		 * Will update parent dir timestamps from srv within a second.
+		 * Would it really be worth it to set the parent dir (cifs
+		 * inode) time field to zero to force revalidate on parent
+		 * directory faster ie
+		 *
+		 * CIFS_I(inode)->time = 0;
+		 */
 	}
 
 cifs_hl_exit:
-	kfree(fromName);
-	kfree(toName);
+	kfree(from_name);
+	kfree(to_name);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index ce41fee..3a00c0d 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -466,7 +466,7 @@
 			list_for_each(tmp2, &tcon->openFileList) {
 				netfile = list_entry(tmp2, struct cifsFileInfo,
 						     tlist);
-				if (pSMB->Fid != netfile->netfid)
+				if (pSMB->Fid != netfile->fid.netfid)
 					continue;
 
 				cFYI(1, "file id match, oplock break");
@@ -579,3 +579,33 @@
 
 	return false;
 }
+
+void
+cifs_del_pending_open(struct cifs_pending_open *open)
+{
+	spin_lock(&cifs_file_list_lock);
+	list_del(&open->olist);
+	spin_unlock(&cifs_file_list_lock);
+}
+
+void
+cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
+			     struct cifs_pending_open *open)
+{
+#ifdef CONFIG_CIFS_SMB2
+	memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
+#endif
+	open->oplock = CIFS_OPLOCK_NO_CHANGE;
+	open->tlink = tlink;
+	fid->pending_open = open;
+	list_add_tail(&open->olist, &tlink_tcon(tlink)->pending_opens);
+}
+
+void
+cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
+		      struct cifs_pending_open *open)
+{
+	spin_lock(&cifs_file_list_lock);
+	cifs_add_pending_open_locked(fid, tlink, open);
+	spin_unlock(&cifs_file_list_lock);
+}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 581c225..d5ce9e2 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -110,7 +110,7 @@
 	{ERRnoroom, -ENOSPC},
 	{ERRrmuns, -EUSERS},
 	{ERRtimeout, -ETIME},
-	{ERRnoresource, -ENOBUFS},
+	{ERRnoresource, -EREMOTEIO},
 	{ERRtoomanyuids, -EUSERS},
 	{ERRbaduid, -EACCES},
 	{ERRusempx, -EIO},
@@ -412,7 +412,7 @@
 	 from NT_STATUS_INSUFFICIENT_RESOURCES to
 	 NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
 	{
-	ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
+	ERRDOS, ERRnoresource, NT_STATUS_INSUFFICIENT_RESOURCES}, {
 	ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
 	ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, {
 	ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, {
@@ -682,7 +682,7 @@
 	ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, {
 	ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, {
 	ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, {
-	ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
+	ERRDOS, ERRnoresource, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
 	ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, {
 	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, {
 	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, {
@@ -913,8 +913,9 @@
  * portion, the number of word parameters and the data portion of the message
  */
 unsigned int
-smbCalcSize(struct smb_hdr *ptr)
+smbCalcSize(void *buf)
 {
+	struct smb_hdr *ptr = (struct smb_hdr *)buf;
 	return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
 		2 /* size of the bcc field */ + get_bcc(ptr));
 }
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index d87f826..f9b5d3d 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -151,7 +151,7 @@
 	}
 }
 
-static void
+void
 cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
 		       struct cifs_sb_info *cifs_sb)
 {
@@ -220,7 +220,8 @@
 }
  */
 
-static int initiate_cifs_search(const unsigned int xid, struct file *file)
+static int
+initiate_cifs_search(const unsigned int xid, struct file *file)
 {
 	__u16 search_flags;
 	int rc = 0;
@@ -229,6 +230,7 @@
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	struct tcon_link *tlink = NULL;
 	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
 
 	if (file->private_data == NULL) {
 		tlink = cifs_sb_tlink(cifs_sb);
@@ -248,6 +250,13 @@
 		tcon = tlink_tcon(cifsFile->tlink);
 	}
 
+	server = tcon->ses->server;
+
+	if (!server->ops->query_dir_first) {
+		rc = -ENOSYS;
+		goto error_exit;
+	}
+
 	cifsFile->invalidHandle = true;
 	cifsFile->srch_inf.endOfSearch = false;
 
@@ -278,10 +287,10 @@
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
-		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags &
-			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+	rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
+					  &cifsFile->fid, search_flags,
+					  &cifsFile->srch_inf);
+
 	if (rc == 0)
 		cifsFile->invalidHandle = false;
 	/* BB add following call to handle readdir on new NTFS symlink errors
@@ -501,62 +510,67 @@
 	return rc;
 }
 
-/* find the corresponding entry in the search */
-/* Note that the SMB server returns search entries for . and .. which
-   complicates logic here if we choose to parse for them and we do not
-   assume that they are located in the findfirst return buffer.*/
-/* We start counting in the buffer with entry 2 and increment for every
-   entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
-	struct file *file, char **ppCurrentEntry, int *num_to_ret)
+/*
+ * Find the corresponding entry in the search. Note that the SMB server returns
+ * search entries for . and .. which complicates logic here if we choose to
+ * parse for them and we do not assume that they are located in the findfirst
+ * return buffer. We start counting in the buffer with entry 2 and increment for
+ * every entry (do not increment for . or .. entry).
+ */
+static int
+find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
+		struct file *file, char **current_entry, int *num_to_ret)
 {
 	__u16 search_flags;
 	int rc = 0;
 	int pos_in_buf = 0;
 	loff_t first_entry_in_buffer;
 	loff_t index_to_find = file->f_pos;
-	struct cifsFileInfo *cifsFile = file->private_data;
+	struct cifsFileInfo *cfile = file->private_data;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+	struct TCP_Server_Info *server = tcon->ses->server;
 	/* check if index in the buffer */
 
-	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
-	   (num_to_ret == NULL))
+	if (!server->ops->query_dir_first || !server->ops->query_dir_next)
+		return -ENOSYS;
+
+	if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
 		return -ENOENT;
 
-	*ppCurrentEntry = NULL;
-	first_entry_in_buffer =
-		cifsFile->srch_inf.index_of_last_entry -
-			cifsFile->srch_inf.entries_in_buffer;
+	*current_entry = NULL;
+	first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
+					cfile->srch_inf.entries_in_buffer;
 
-	/* if first entry in buf is zero then is first buffer
-	in search response data which means it is likely . and ..
-	will be in this buffer, although some servers do not return
-	. and .. for the root of a drive and for those we need
-	to start two entries earlier */
+	/*
+	 * If first entry in buf is zero then is first buffer
+	 * in search response data which means it is likely . and ..
+	 * will be in this buffer, although some servers do not return
+	 * . and .. for the root of a drive and for those we need
+	 * to start two entries earlier.
+	 */
 
 	dump_cifs_file_struct(file, "In fce ");
-	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
-	     is_dir_changed(file)) ||
-	   (index_to_find < first_entry_in_buffer)) {
+	if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
+	     is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		cFYI(1, "search backing up - close and restart search");
 		spin_lock(&cifs_file_list_lock);
-		if (!cifsFile->srch_inf.endOfSearch &&
-		    !cifsFile->invalidHandle) {
-			cifsFile->invalidHandle = true;
+		if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+			cfile->invalidHandle = true;
 			spin_unlock(&cifs_file_list_lock);
-			CIFSFindClose(xid, pTcon, cifsFile->netfid);
+			if (server->ops->close)
+				server->ops->close(xid, tcon, &cfile->fid);
 		} else
 			spin_unlock(&cifs_file_list_lock);
-		if (cifsFile->srch_inf.ntwrk_buf_start) {
+		if (cfile->srch_inf.ntwrk_buf_start) {
 			cFYI(1, "freeing SMB ff cache buf on search rewind");
-			if (cifsFile->srch_inf.smallBuf)
-				cifs_small_buf_release(cifsFile->srch_inf.
+			if (cfile->srch_inf.smallBuf)
+				cifs_small_buf_release(cfile->srch_inf.
 						ntwrk_buf_start);
 			else
-				cifs_buf_release(cifsFile->srch_inf.
+				cifs_buf_release(cfile->srch_inf.
 						ntwrk_buf_start);
-			cifsFile->srch_inf.ntwrk_buf_start = NULL;
+			cfile->srch_inf.ntwrk_buf_start = NULL;
 		}
 		rc = initiate_cifs_search(xid, file);
 		if (rc) {
@@ -565,65 +579,64 @@
 			return rc;
 		}
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
-		if (cifsFile->srch_inf.last_entry)
-			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-						cifsFile);
+		if (cfile->srch_inf.last_entry)
+			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
 	}
 
 	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
 	if (backup_cred(cifs_sb))
 		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
-	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
+	while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
+	       (rc == 0) && !cfile->srch_inf.endOfSearch) {
 		cFYI(1, "calling findnext2");
-		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
-				  &cifsFile->srch_inf);
+		rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
+						 search_flags,
+						 &cfile->srch_inf);
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
-		if (cifsFile->srch_inf.last_entry)
-			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-						cifsFile);
+		if (cfile->srch_inf.last_entry)
+			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
 		if (rc)
 			return -ENOENT;
 	}
-	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+	if (index_to_find < cfile->srch_inf.index_of_last_entry) {
 		/* we found the buffer that contains the entry */
 		/* scan and find it */
 		int i;
-		char *current_entry;
-		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
-			smbCalcSize((struct smb_hdr *)
-				cifsFile->srch_inf.ntwrk_buf_start);
+		char *cur_ent;
+		char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+			server->ops->calc_smb_size(
+					cfile->srch_inf.ntwrk_buf_start);
 
-		current_entry = cifsFile->srch_inf.srch_entries_start;
-		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
-					- cifsFile->srch_inf.entries_in_buffer;
+		cur_ent = cfile->srch_inf.srch_entries_start;
+		first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
+					- cfile->srch_inf.entries_in_buffer;
 		pos_in_buf = index_to_find - first_entry_in_buffer;
 		cFYI(1, "found entry - pos_in_buf %d", pos_in_buf);
 
-		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
+		for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
 			/* go entry by entry figuring out which is first */
-			current_entry = nxt_dir_entry(current_entry, end_of_smb,
-						cifsFile->srch_inf.info_level);
+			cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
+						cfile->srch_inf.info_level);
 		}
-		if ((current_entry == NULL) && (i < pos_in_buf)) {
+		if ((cur_ent == NULL) && (i < pos_in_buf)) {
 			/* BB fixme - check if we should flag this error */
 			cERROR(1, "reached end of buf searching for pos in buf"
-			  " %d index to find %lld rc %d",
-			  pos_in_buf, index_to_find, rc);
+				  " %d index to find %lld rc %d", pos_in_buf,
+				  index_to_find, rc);
 		}
 		rc = 0;
-		*ppCurrentEntry = current_entry;
+		*current_entry = cur_ent;
 	} else {
 		cFYI(1, "index not in buffer - could not findnext into it");
 		return 0;
 	}
 
-	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+	if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
 		cFYI(1, "can not return entries pos_in_buf beyond last");
 		*num_to_ret = 0;
 	} else
-		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
+		*num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
 
 	return rc;
 }
@@ -723,7 +736,7 @@
 	int rc = 0;
 	unsigned int xid;
 	int i;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	struct cifsFileInfo *cifsFile = NULL;
 	char *current_entry;
 	int num_to_fill = 0;
@@ -781,12 +794,12 @@
 			}
 		} /* else {
 			cifsFile->invalidHandle = true;
-			CIFSFindClose(xid, pTcon, cifsFile->netfid);
+			tcon->ses->server->close(xid, tcon, &cifsFile->fid);
 		} */
 
-		pTcon = tlink_tcon(cifsFile->tlink);
-		rc = find_cifs_entry(xid, pTcon, file,
-				&current_entry, &num_to_fill);
+		tcon = tlink_tcon(cifsFile->tlink);
+		rc = find_cifs_entry(xid, tcon, file, &current_entry,
+				     &num_to_fill);
 		if (rc) {
 			cFYI(1, "fce error %d", rc);
 			goto rddir2_exit;
@@ -798,7 +811,7 @@
 		}
 		cFYI(1, "loop through %d times filling dir for net buf %p",
 			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
-		max_len = smbCalcSize((struct smb_hdr *)
+		max_len = tcon->ses->server->ops->calc_smb_size(
 				cifsFile->srch_inf.ntwrk_buf_start);
 		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 
@@ -815,10 +828,12 @@
 					  num_to_fill, i);
 				break;
 			}
-			/* if buggy server returns . and .. late do
-			we want to check for that here? */
-			rc = cifs_filldir(current_entry, file,
-					filldir, direntry, tmp_buf, max_len);
+			/*
+			 * if buggy server returns . and .. late do we want to
+			 * check for that here?
+			 */
+			rc = cifs_filldir(current_entry, file, filldir,
+					  direntry, tmp_buf, max_len);
 			if (rc == -EOVERFLOW) {
 				rc = 0;
 				break;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 382c06d..76809f4 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -876,7 +876,8 @@
 	pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
 	smb_buf = (struct smb_hdr *)iov[0].iov_base;
 
-	if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError ==
+	if ((type == RawNTLMSSP) && (resp_buf_type != CIFS_NO_BUFFER) &&
+	    (smb_buf->Status.CifsError ==
 			cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
 		if (phase != NtLmNegotiate) {
 			cERROR(1, "Unexpected more processing error");
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3129ac7..56cc4be 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -17,6 +17,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
@@ -63,7 +65,7 @@
 static bool
 cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
 {
-	return ob1->netfid == ob2->netfid;
+	return ob1->fid.netfid == ob2->fid.netfid;
 }
 
 static unsigned int
@@ -410,6 +412,83 @@
 	return rc;
 }
 
+static unsigned int
+cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int wsize;
+
+	/* start with specified wsize, or default */
+	if (volume_info->wsize)
+		wsize = volume_info->wsize;
+	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+		wsize = CIFS_DEFAULT_IOSIZE;
+	else
+		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
+
+	/* can server support 24-bit write sizes? (via UNIX extensions) */
+	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+
+	/*
+	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
+	 * Limit it to max buffer offered by the server, minus the size of the
+	 * WRITEX header, not including the 4 byte RFC1001 length.
+	 */
+	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
+	    (!(server->capabilities & CAP_UNIX) &&
+	     (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+		wsize = min_t(unsigned int, wsize,
+				server->maxBuf - sizeof(WRITE_REQ) + 4);
+
+	/* hard limit of CIFS_MAX_WSIZE */
+	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+	return wsize;
+}
+
+static unsigned int
+cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int rsize, defsize;
+
+	/*
+	 * Set default value...
+	 *
+	 * HACK alert! Ancient servers have very small buffers. Even though
+	 * MS-CIFS indicates that servers are only limited by the client's
+	 * bufsize for reads, testing against win98se shows that it throws
+	 * INVALID_PARAMETER errors if you try to request too large a read.
+	 * OS/2 just sends back short reads.
+	 *
+	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+	 * it can't handle a read request larger than its MaxBufferSize either.
+	 */
+	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
+		defsize = CIFS_DEFAULT_IOSIZE;
+	else if (server->capabilities & CAP_LARGE_READ_X)
+		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
+	else
+		defsize = server->maxBuf - sizeof(READ_RSP);
+
+	rsize = volume_info->rsize ? volume_info->rsize : defsize;
+
+	/*
+	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+	 * the client's MaxBufferSize.
+	 */
+	if (!(server->capabilities & CAP_LARGE_READ_X))
+		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
+
+	/* hard limit of CIFS_MAX_RSIZE */
+	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
+
+	return rsize;
+}
+
 static void
 cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
 {
@@ -489,6 +568,13 @@
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 }
 
+static int
+cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+		     struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+	return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data);
+}
+
 static char *
 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
 			struct cifs_tcon *tcon)
@@ -607,6 +693,219 @@
 		cifsInode->cifsAttrs = dosattrs;
 }
 
+static int
+cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+	       int disposition, int desired_access, int create_options,
+	       struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+	       struct cifs_sb_info *cifs_sb)
+{
+	if (!(tcon->ses->capabilities & CAP_NT_SMBS))
+		return SMBLegacyOpen(xid, tcon, path, disposition,
+				     desired_access, create_options,
+				     &fid->netfid, oplock, buf,
+				     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+						& CIFS_MOUNT_MAP_SPECIAL_CHR);
+	return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
+			   create_options, &fid->netfid, oplock, buf,
+			   cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+}
+
+static void
+cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+	cfile->fid.netfid = fid->netfid;
+	cifs_set_oplock_level(cinode, oplock);
+	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+}
+
+static void
+cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	CIFSSMBClose(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return CIFSSMBFlush(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+	       struct cifs_io_parms *parms, unsigned int *bytes_read,
+	       char **buf, int *buf_type)
+{
+	parms->netfid = cfile->fid.netfid;
+	return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
+}
+
+static int
+cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+		struct cifs_io_parms *parms, unsigned int *written,
+		struct kvec *iov, unsigned long nr_segs)
+{
+
+	parms->netfid = cfile->fid.netfid;
+	return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
+}
+
+static int
+smb_set_file_info(struct inode *inode, const char *full_path,
+		  FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+	int oplock = 0;
+	int rc;
+	__u16 netfid;
+	__u32 netpid;
+	struct cifsFileInfo *open_file;
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct tcon_link *tlink = NULL;
+	struct cifs_tcon *tcon;
+	FILE_BASIC_INFO info_buf;
+
+	/* if the file is already open for write, just use that fileid */
+	open_file = find_writable_file(cinode, true);
+	if (open_file) {
+		netfid = open_file->fid.netfid;
+		netpid = open_file->pid;
+		tcon = tlink_tcon(open_file->tlink);
+		goto set_via_filehandle;
+	}
+
+	tlink = cifs_sb_tlink(cifs_sb);
+	if (IS_ERR(tlink)) {
+		rc = PTR_ERR(tlink);
+		tlink = NULL;
+		goto out;
+	}
+	tcon = tlink_tcon(tlink);
+
+	/*
+	 * NT4 apparently returns success on this call, but it doesn't really
+	 * work.
+	 */
+	if (!(tcon->ses->flags & CIFS_SES_NT4)) {
+		rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
+					cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc == 0) {
+			cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+			goto out;
+		} else if (rc != -EOPNOTSUPP && rc != -EINVAL)
+			goto out;
+	}
+
+	cFYI(1, "calling SetFileInfo since SetPathInfo for times not supported "
+		"by this server");
+	rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+			 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
+			 &netfid, &oplock, NULL, cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	if (rc != 0) {
+		if (rc == -EIO)
+			rc = -EINVAL;
+		goto out;
+	}
+
+	netpid = current->tgid;
+
+set_via_filehandle:
+	rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid);
+	if (!rc)
+		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+
+	if (open_file == NULL)
+		CIFSSMBClose(xid, tcon, netfid);
+	else
+		cifsFileInfo_put(open_file);
+out:
+	if (tlink != NULL)
+		cifs_put_tlink(tlink);
+	return rc;
+}
+
+static int
+cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *path, struct cifs_sb_info *cifs_sb,
+		     struct cifs_fid *fid, __u16 search_flags,
+		     struct cifs_search_info *srch_inf)
+{
+	return CIFSFindFirst(xid, tcon, path, cifs_sb,
+			     &fid->netfid, search_flags, srch_inf, true);
+}
+
+static int
+cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+		    struct cifs_fid *fid, __u16 search_flags,
+		    struct cifs_search_info *srch_inf)
+{
+	return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
+}
+
+static int
+cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+	       struct cifs_fid *fid)
+{
+	return CIFSFindClose(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+		     struct cifsInodeInfo *cinode)
+{
+	return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
+			   LOCKING_ANDX_OPLOCK_RELEASE, false,
+			   cinode->clientCanCacheRead ? 1 : 0);
+}
+
+static int
+cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+	     struct kstatfs *buf)
+{
+	int rc = -EOPNOTSUPP;
+
+	buf->f_type = CIFS_MAGIC_NUMBER;
+
+	/*
+	 * We could add a second check for a QFS Unix capability bit
+	 */
+	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
+		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
+
+	/*
+	 * Only need to call the old QFSInfo if failed on newer one,
+	 * e.g. by OS/2.
+	 **/
+	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
+		rc = CIFSSMBQFSInfo(xid, tcon, buf);
+
+	/*
+	 * Some old Windows servers also do not support level 103, retry with
+	 * older level one if old server failed the previous call or we
+	 * bypassed it because we detected that this was an older LANMAN sess
+	 */
+	if (rc)
+		rc = SMBOldQFSInfo(xid, tcon, buf);
+	return rc;
+}
+
+static int
+cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
+	       __u64 length, __u32 type, int lock, int unlock, bool wait)
+{
+	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
+			   current->tgid, length, offset, unlock, lock,
+			   (__u8)type, wait, 0);
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -630,6 +929,8 @@
 	.check_trans2 = cifs_check_trans2,
 	.need_neg = cifs_need_neg,
 	.negotiate = cifs_negotiate,
+	.negotiate_wsize = cifs_negotiate_wsize,
+	.negotiate_rsize = cifs_negotiate_rsize,
 	.sess_setup = CIFS_SessSetup,
 	.logoff = CIFSSMBLogoff,
 	.tree_connect = CIFSTCon,
@@ -638,12 +939,37 @@
 	.qfs_tcon = cifs_qfs_tcon,
 	.is_path_accessible = cifs_is_path_accessible,
 	.query_path_info = cifs_query_path_info,
+	.query_file_info = cifs_query_file_info,
 	.get_srv_inum = cifs_get_srv_inum,
+	.set_path_size = CIFSSMBSetEOF,
+	.set_file_size = CIFSSMBSetFileSize,
+	.set_file_info = smb_set_file_info,
 	.build_path_to_root = cifs_build_path_to_root,
 	.echo = CIFSSMBEcho,
 	.mkdir = CIFSSMBMkDir,
 	.mkdir_setinfo = cifs_mkdir_setinfo,
 	.rmdir = CIFSSMBRmDir,
+	.unlink = CIFSSMBDelFile,
+	.rename_pending_delete = cifs_rename_pending_delete,
+	.rename = CIFSSMBRename,
+	.create_hardlink = CIFSCreateHardLink,
+	.open = cifs_open_file,
+	.set_fid = cifs_set_fid,
+	.close = cifs_close_file,
+	.flush = cifs_flush_file,
+	.async_readv = cifs_async_readv,
+	.async_writev = cifs_async_writev,
+	.sync_read = cifs_sync_read,
+	.sync_write = cifs_sync_write,
+	.query_dir_first = cifs_query_dir_first,
+	.query_dir_next = cifs_query_dir_next,
+	.close_dir = cifs_close_dir,
+	.calc_smb_size = smbCalcSize,
+	.oplock_response = cifs_oplock_response,
+	.queryfs = cifs_queryfs,
+	.mand_lock = cifs_mand_lock,
+	.mand_unlock_range = cifs_unlock_range,
+	.push_mand_locks = cifs_push_mandatory_locks,
 };
 
 struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644
index 0000000..a93eec3
--- /dev/null
+++ b/fs/cifs/smb2file.c
@@ -0,0 +1,302 @@
+/*
+ *   fs/cifs/smb2file.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002, 2011
+ *   Author(s): Steve French (sfrench@us.ibm.com),
+ *              Pavel Shilovsky ((pshilovsky@samba.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
+#include "fscache.h"
+#include "smb2proto.h"
+
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+	oplock &= 0xFF;
+	if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
+		return;
+	if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+		cinode->clientCanCacheAll = true;
+		cinode->clientCanCacheRead = true;
+		cFYI(1, "Exclusive Oplock granted on inode %p",
+		     &cinode->vfs_inode);
+	} else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+		cinode->clientCanCacheAll = false;
+		cinode->clientCanCacheRead = true;
+		cFYI(1, "Level II Oplock granted on inode %p",
+		    &cinode->vfs_inode);
+	} else {
+		cinode->clientCanCacheAll = false;
+		cinode->clientCanCacheRead = false;
+	}
+}
+
+int
+smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+	       int disposition, int desired_access, int create_options,
+	       struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+	       struct cifs_sb_info *cifs_sb)
+{
+	int rc;
+	__le16 *smb2_path;
+	struct smb2_file_all_info *smb2_data = NULL;
+	__u8 smb2_oplock[17];
+
+	smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (smb2_path == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			    GFP_KERNEL);
+	if (smb2_data == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	desired_access |= FILE_READ_ATTRIBUTES;
+	*smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+	if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
+		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
+
+	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
+		       &fid->volatile_fid, desired_access, disposition,
+		       0, 0, smb2_oplock, smb2_data);
+	if (rc)
+		goto out;
+
+	if (buf) {
+		/* open response does not have IndexNumber field - get it */
+		rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
+				      fid->volatile_fid,
+				      &smb2_data->IndexNumber);
+		if (rc) {
+			/* let get_inode_info disable server inode numbers */
+			smb2_data->IndexNumber = 0;
+			rc = 0;
+		}
+		move_smb2_info_to_cifs(buf, smb2_data);
+	}
+
+	*oplock = *smb2_oplock;
+out:
+	kfree(smb2_data);
+	kfree(smb2_path);
+	return rc;
+}
+
+int
+smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
+		  const unsigned int xid)
+{
+	int rc = 0, stored_rc;
+	unsigned int max_num, num = 0, max_buf;
+	struct smb2_lock_element *buf, *cur;
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+	struct cifsLockInfo *li, *tmp;
+	__u64 length = 1 + flock->fl_end - flock->fl_start;
+	struct list_head tmp_llist;
+
+	INIT_LIST_HEAD(&tmp_llist);
+
+	/*
+	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
+	 * and check it for zero before using.
+	 */
+	max_buf = tcon->ses->server->maxBuf;
+	if (!max_buf)
+		return -EINVAL;
+
+	max_num = max_buf / sizeof(struct smb2_lock_element);
+	buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cur = buf;
+
+	down_write(&cinode->lock_sem);
+	list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
+		if (flock->fl_start > li->offset ||
+		    (flock->fl_start + length) <
+		    (li->offset + li->length))
+			continue;
+		if (current->tgid != li->pid)
+			continue;
+		if (cinode->can_cache_brlcks) {
+			/*
+			 * We can cache brlock requests - simply remove a lock
+			 * from the file's list.
+			 */
+			list_del(&li->llist);
+			cifs_del_lock_waiters(li);
+			kfree(li);
+			continue;
+		}
+		cur->Length = cpu_to_le64(li->length);
+		cur->Offset = cpu_to_le64(li->offset);
+		cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK);
+		/*
+		 * We need to save a lock here to let us add it again to the
+		 * file's list if the unlock range request fails on the server.
+		 */
+		list_move(&li->llist, &tmp_llist);
+		if (++num == max_num) {
+			stored_rc = smb2_lockv(xid, tcon,
+					       cfile->fid.persistent_fid,
+					       cfile->fid.volatile_fid,
+					       current->tgid, num, buf);
+			if (stored_rc) {
+				/*
+				 * We failed on the unlock range request - add
+				 * all locks from the tmp list to the head of
+				 * the file's list.
+				 */
+				cifs_move_llist(&tmp_llist,
+						&cfile->llist->locks);
+				rc = stored_rc;
+			} else
+				/*
+				 * The unlock range request succeed - free the
+				 * tmp list.
+				 */
+				cifs_free_llist(&tmp_llist);
+			cur = buf;
+			num = 0;
+		} else
+			cur++;
+	}
+	if (num) {
+		stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid,
+				       cfile->fid.volatile_fid, current->tgid,
+				       num, buf);
+		if (stored_rc) {
+			cifs_move_llist(&tmp_llist, &cfile->llist->locks);
+			rc = stored_rc;
+		} else
+			cifs_free_llist(&tmp_llist);
+	}
+	up_write(&cinode->lock_sem);
+
+	kfree(buf);
+	return rc;
+}
+
+static int
+smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
+		       struct smb2_lock_element *buf, unsigned int max_num)
+{
+	int rc = 0, stored_rc;
+	struct cifsFileInfo *cfile = fdlocks->cfile;
+	struct cifsLockInfo *li;
+	unsigned int num = 0;
+	struct smb2_lock_element *cur = buf;
+	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+
+	list_for_each_entry(li, &fdlocks->locks, llist) {
+		cur->Length = cpu_to_le64(li->length);
+		cur->Offset = cpu_to_le64(li->offset);
+		cur->Flags = cpu_to_le32(li->type |
+						SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
+		if (++num == max_num) {
+			stored_rc = smb2_lockv(xid, tcon,
+					       cfile->fid.persistent_fid,
+					       cfile->fid.volatile_fid,
+					       current->tgid, num, buf);
+			if (stored_rc)
+				rc = stored_rc;
+			cur = buf;
+			num = 0;
+		} else
+			cur++;
+	}
+	if (num) {
+		stored_rc = smb2_lockv(xid, tcon,
+				       cfile->fid.persistent_fid,
+				       cfile->fid.volatile_fid,
+				       current->tgid, num, buf);
+		if (stored_rc)
+			rc = stored_rc;
+	}
+
+	return rc;
+}
+
+int
+smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
+{
+	int rc = 0, stored_rc;
+	unsigned int xid;
+	unsigned int max_num, max_buf;
+	struct smb2_lock_element *buf;
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+	struct cifs_fid_locks *fdlocks;
+
+	xid = get_xid();
+	/* we are going to update can_cache_brlcks here - need a write access */
+	down_write(&cinode->lock_sem);
+	if (!cinode->can_cache_brlcks) {
+		up_write(&cinode->lock_sem);
+		free_xid(xid);
+		return rc;
+	}
+
+	/*
+	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
+	 * and check it for zero before using.
+	 */
+	max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
+	if (!max_buf) {
+		up_write(&cinode->lock_sem);
+		free_xid(xid);
+		return -EINVAL;
+	}
+
+	max_num = max_buf / sizeof(struct smb2_lock_element);
+	buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
+	if (!buf) {
+		up_write(&cinode->lock_sem);
+		free_xid(xid);
+		return -ENOMEM;
+	}
+
+	list_for_each_entry(fdlocks, &cinode->llist, llist) {
+		stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
+		if (stored_rc)
+			rc = stored_rc;
+	}
+
+	cinode->can_cache_brlcks = false;
+	kfree(buf);
+
+	up_write(&cinode->lock_sem);
+	free_xid(xid);
+	return rc;
+}
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 33c1d89..7c0e214 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -23,6 +23,8 @@
 #ifndef _SMB2_GLOB_H
 #define _SMB2_GLOB_H
 
+#define SMB2_MAGIC_NUMBER 0xFE534D42
+
 /*
  *****************************************************************
  * Constants go here
@@ -40,5 +42,17 @@
 #define SMB2_OP_MKDIR 5
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_DELETE 7
+#define SMB2_OP_HARDLINK 8
+#define SMB2_OP_SET_EOF 9
+
+/* Used when constructing chained read requests. */
+#define CHAINED_REQUEST 1
+#define START_OF_CHAIN 2
+#define END_OF_CHAIN 4
+#define RELATED_REQUEST 8
+
+#define SMB2_SIGNATURE_SIZE (16)
+#define SMB2_NTLMV2_SESSKEY_SIZE (16)
+#define SMB2_HMACSHA256_SIZE (32)
 
 #endif	/* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 2aa5cb0..7064824 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -47,6 +47,7 @@
 	int rc, tmprc = 0;
 	u64 persistent_fid, volatile_fid;
 	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 	if (!utf16_path)
@@ -54,7 +55,7 @@
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
 		       desired_access, create_disposition, file_attributes,
-		       create_options);
+		       create_options, &oplock, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
@@ -74,6 +75,22 @@
 		 * SMB2_open() call.
 		 */
 		break;
+	case SMB2_OP_RENAME:
+		tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
+				    (__le16 *)data);
+		break;
+	case SMB2_OP_HARDLINK:
+		tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
+					  volatile_fid, (__le16 *)data);
+		break;
+	case SMB2_OP_SET_EOF:
+		tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
+				     current->tgid, (__le64 *)data);
+		break;
+	case SMB2_OP_SET_INFO:
+		tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid,
+				      (FILE_BASIC_INFO *)data);
+		break;
 	default:
 		cERROR(1, "Invalid command");
 		break;
@@ -86,7 +103,7 @@
 	return rc;
 }
 
-static void
+void
 move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 {
 	memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
@@ -161,3 +178,80 @@
 				  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
 				  NULL, SMB2_OP_DELETE);
 }
+
+int
+smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+	    struct cifs_sb_info *cifs_sb)
+{
+	return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+				  0, CREATE_DELETE_ON_CLOSE, NULL,
+				  SMB2_OP_DELETE);
+}
+
+static int
+smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
+		   const char *from_name, const char *to_name,
+		   struct cifs_sb_info *cifs_sb, __u32 access, int command)
+{
+	__le16 *smb2_to_name = NULL;
+	int rc;
+
+	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
+	if (smb2_to_name == NULL) {
+		rc = -ENOMEM;
+		goto smb2_rename_path;
+	}
+
+	rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
+				FILE_OPEN, 0, 0, smb2_to_name, command);
+smb2_rename_path:
+	kfree(smb2_to_name);
+	return rc;
+}
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+		 const char *from_name, const char *to_name,
+		 struct cifs_sb_info *cifs_sb)
+{
+	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+				  DELETE, SMB2_OP_RENAME);
+}
+
+int
+smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *from_name, const char *to_name,
+		     struct cifs_sb_info *cifs_sb)
+{
+	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+				  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
+}
+
+int
+smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+		   const char *full_path, __u64 size,
+		   struct cifs_sb_info *cifs_sb, bool set_alloc)
+{
+	__le64 eof = cpu_to_le64(size);
+	return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
+				  FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
+				  SMB2_OP_SET_EOF);
+}
+
+int
+smb2_set_file_info(struct inode *inode, const char *full_path,
+		   FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct tcon_link *tlink;
+	int rc;
+
+	tlink = cifs_sb_tlink(cifs_sb);
+	if (IS_ERR(tlink))
+		return PTR_ERR(tlink);
+	rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
+				FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf,
+				SMB2_OP_SET_INFO);
+	cifs_put_tlink(tlink);
+	return rc;
+}
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index be41478..494c912 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -453,7 +453,8 @@
 	{STATUS_FILE_INVALID, -EIO, "STATUS_FILE_INVALID"},
 	{STATUS_ALLOTTED_SPACE_EXCEEDED, -EIO,
 	"STATUS_ALLOTTED_SPACE_EXCEEDED"},
-	{STATUS_INSUFFICIENT_RESOURCES, -EIO, "STATUS_INSUFFICIENT_RESOURCES"},
+	{STATUS_INSUFFICIENT_RESOURCES, -EREMOTEIO,
+				"STATUS_INSUFFICIENT_RESOURCES"},
 	{STATUS_DFS_EXIT_PATH_FOUND, -EIO, "STATUS_DFS_EXIT_PATH_FOUND"},
 	{STATUS_DEVICE_DATA_ERROR, -EIO, "STATUS_DEVICE_DATA_ERROR"},
 	{STATUS_DEVICE_NOT_CONNECTED, -EIO, "STATUS_DEVICE_NOT_CONNECTED"},
@@ -2455,7 +2456,8 @@
 		return 0;
 
 	/* mask facility */
-	if (log_err && (smb2err != (STATUS_MORE_PROCESSING_REQUIRED)))
+	if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
+	    (smb2err != STATUS_END_OF_FILE))
 		smb2_print_status(smb2err);
 	else if (cifsFYI & CIFS_RC)
 		smb2_print_status(smb2err);
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index e4d3b99..7b1c5e3 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -142,12 +142,19 @@
 	}
 
 	if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-		if (hdr->Status == 0 ||
-		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2) {
+		if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
 			/* error packets have 9 byte structure size */
 			cERROR(1, "Illegal response size %u for command %d",
 				   le16_to_cpu(pdu->StructureSize2), command);
 			return 1;
+		} else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0)
+			   && (le16_to_cpu(pdu->StructureSize2) != 44)
+			   && (le16_to_cpu(pdu->StructureSize2) != 36)) {
+			/* special case for SMB2.1 lease break message */
+			cERROR(1, "Illegal response size %d for oplock break",
+				   le16_to_cpu(pdu->StructureSize2));
+			return 1;
 		}
 	}
 
@@ -162,6 +169,9 @@
 	if (4 + len != clc_len) {
 		cFYI(1, "Calculated size %u length %u mismatch mid %llu",
 			clc_len, 4 + len, mid);
+		/* Windows 7 server returns 24 bytes more */
+		if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
+			return 0;
 		/* server can return one byte more */
 		if (clc_len == 4 + len + 1)
 			return 0;
@@ -244,7 +254,15 @@
 		    ((struct smb2_query_info_rsp *)hdr)->OutputBufferLength);
 		break;
 	case SMB2_READ:
+		*off = ((struct smb2_read_rsp *)hdr)->DataOffset;
+		*len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
+		break;
 	case SMB2_QUERY_DIRECTORY:
+		*off = le16_to_cpu(
+		  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset);
+		*len = le32_to_cpu(
+		  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
+		break;
 	case SMB2_IOCTL:
 	case SMB2_CHANGE_NOTIFY:
 	default:
@@ -287,8 +305,9 @@
  * portion, the number of word parameters and the data portion of the message.
  */
 unsigned int
-smb2_calc_size(struct smb2_hdr *hdr)
+smb2_calc_size(void *buf)
 {
+	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
 	struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
 	int offset; /* the offset from the beginning of SMB to data area */
 	int data_length; /* the length of the variable length data area */
@@ -347,3 +366,218 @@
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
 	return to;
 }
+
+__le32
+smb2_get_lease_state(struct cifsInodeInfo *cinode)
+{
+	if (cinode->clientCanCacheAll)
+		return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING;
+	else if (cinode->clientCanCacheRead)
+		return SMB2_LEASE_READ_CACHING;
+	return 0;
+}
+
+__u8 smb2_map_lease_to_oplock(__le32 lease_state)
+{
+	if (lease_state & SMB2_LEASE_WRITE_CACHING) {
+		if (lease_state & SMB2_LEASE_HANDLE_CACHING)
+			return SMB2_OPLOCK_LEVEL_BATCH;
+		else
+			return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+	} else if (lease_state & SMB2_LEASE_READ_CACHING)
+		return SMB2_OPLOCK_LEVEL_II;
+	return 0;
+}
+
+struct smb2_lease_break_work {
+	struct work_struct lease_break;
+	struct tcon_link *tlink;
+	__u8 lease_key[16];
+	__le32 lease_state;
+};
+
+static void
+cifs_ses_oplock_break(struct work_struct *work)
+{
+	struct smb2_lease_break_work *lw = container_of(work,
+				struct smb2_lease_break_work, lease_break);
+	int rc;
+
+	rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
+			      lw->lease_state);
+	cFYI(1, "Lease release rc %d", rc);
+	cifs_put_tlink(lw->tlink);
+	kfree(lw);
+}
+
+static bool
+smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
+{
+	struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
+	struct list_head *tmp, *tmp1, *tmp2;
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon;
+	struct cifsInodeInfo *cinode;
+	struct cifsFileInfo *cfile;
+	struct cifs_pending_open *open;
+	struct smb2_lease_break_work *lw;
+	bool found;
+	int ack_req = le32_to_cpu(rsp->Flags &
+				  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+
+	lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
+	if (!lw) {
+		cERROR(1, "Memory allocation failed during lease break check");
+		return false;
+	}
+
+	INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
+	lw->lease_state = rsp->NewLeaseState;
+
+	cFYI(1, "Checking for lease break");
+
+	/* look up tcon based on tid & uid */
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each(tmp, &server->smb_ses_list) {
+		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+
+		spin_lock(&cifs_file_list_lock);
+		list_for_each(tmp1, &ses->tcon_list) {
+			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+			list_for_each(tmp2, &tcon->openFileList) {
+				cfile = list_entry(tmp2, struct cifsFileInfo,
+						   tlist);
+				cinode = CIFS_I(cfile->dentry->d_inode);
+
+				if (memcmp(cinode->lease_key, rsp->LeaseKey,
+					   SMB2_LEASE_KEY_SIZE))
+					continue;
+
+				cFYI(1, "found in the open list");
+				cFYI(1, "lease key match, lease break 0x%d",
+				     le32_to_cpu(rsp->NewLeaseState));
+
+				smb2_set_oplock_level(cinode,
+				  smb2_map_lease_to_oplock(rsp->NewLeaseState));
+
+				if (ack_req)
+					cfile->oplock_break_cancelled = false;
+				else
+					cfile->oplock_break_cancelled = true;
+
+				queue_work(cifsiod_wq, &cfile->oplock_break);
+
+				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&cifs_tcp_ses_lock);
+				return true;
+			}
+
+			found = false;
+			list_for_each_entry(open, &tcon->pending_opens, olist) {
+				if (memcmp(open->lease_key, rsp->LeaseKey,
+					   SMB2_LEASE_KEY_SIZE))
+					continue;
+
+				if (!found && ack_req) {
+					found = true;
+					memcpy(lw->lease_key, open->lease_key,
+					       SMB2_LEASE_KEY_SIZE);
+					lw->tlink = cifs_get_tlink(open->tlink);
+					queue_work(cifsiod_wq,
+						   &lw->lease_break);
+				}
+
+				cFYI(1, "found in the pending open list");
+				cFYI(1, "lease key match, lease break 0x%d",
+				     le32_to_cpu(rsp->NewLeaseState));
+
+				open->oplock =
+				  smb2_map_lease_to_oplock(rsp->NewLeaseState);
+			}
+			if (found) {
+				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&cifs_tcp_ses_lock);
+				return true;
+			}
+		}
+		spin_unlock(&cifs_file_list_lock);
+	}
+	spin_unlock(&cifs_tcp_ses_lock);
+	kfree(lw);
+	cFYI(1, "Can not process lease break - no lease matched");
+	return false;
+}
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
+{
+	struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
+	struct list_head *tmp, *tmp1, *tmp2;
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon;
+	struct cifsInodeInfo *cinode;
+	struct cifsFileInfo *cfile;
+
+	cFYI(1, "Checking for oplock break");
+
+	if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+		return false;
+
+	if (rsp->StructureSize !=
+				smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+		if (le16_to_cpu(rsp->StructureSize) == 44)
+			return smb2_is_valid_lease_break(buffer, server);
+		else
+			return false;
+	}
+
+	cFYI(1, "oplock level 0x%d", rsp->OplockLevel);
+
+	/* look up tcon based on tid & uid */
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each(tmp, &server->smb_ses_list) {
+		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+		list_for_each(tmp1, &ses->tcon_list) {
+			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+			spin_lock(&cifs_file_list_lock);
+			list_for_each(tmp2, &tcon->openFileList) {
+				cfile = list_entry(tmp2, struct cifsFileInfo,
+						     tlist);
+				if (rsp->PersistentFid !=
+				    cfile->fid.persistent_fid ||
+				    rsp->VolatileFid !=
+				    cfile->fid.volatile_fid)
+					continue;
+
+				cFYI(1, "file id match, oplock break");
+				cinode = CIFS_I(cfile->dentry->d_inode);
+
+				if (!cinode->clientCanCacheAll &&
+				    rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
+					cfile->oplock_break_cancelled = true;
+				else
+					cfile->oplock_break_cancelled = false;
+
+				smb2_set_oplock_level(cinode,
+				  rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+
+				queue_work(cifsiod_wq, &cfile->oplock_break);
+
+				spin_unlock(&cifs_file_list_lock);
+				spin_unlock(&cifs_tcp_ses_lock);
+				return true;
+			}
+			spin_unlock(&cifs_file_list_lock);
+			spin_unlock(&cifs_tcp_ses_lock);
+			cFYI(1, "No matching file for oplock break");
+			return true;
+		}
+	}
+	spin_unlock(&cifs_tcp_ses_lock);
+	cFYI(1, "Can not process oplock break for non-existent connection");
+	return false;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 826209b..4d9dbe0 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -17,11 +17,15 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "smb2status.h"
+#include "smb2glob.h"
 
 static int
 change_conf(struct TCP_Server_Info *server)
@@ -63,6 +67,17 @@
 	server->in_flight--;
 	if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
 		rc = change_conf(server);
+	/*
+	 * Sometimes server returns 0 credits on oplock break ack - we need to
+	 * rebalance credits in this case.
+	 */
+	else if (server->in_flight > 0 && server->oplock_credits == 0 &&
+		 server->oplocks) {
+		if (server->credits > 1) {
+			server->credits--;
+			server->oplock_credits++;
+		}
+	}
 	spin_unlock(&server->req_lock);
 	wake_up(&server->request_q);
 	if (rc)
@@ -157,6 +172,42 @@
 	return rc;
 }
 
+static unsigned int
+smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int wsize;
+
+	/* start with specified wsize, or default */
+	wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
+	wsize = min_t(unsigned int, wsize, server->max_write);
+	/*
+	 * limit write size to 2 ** 16, because we don't support multicredit
+	 * requests now.
+	 */
+	wsize = min_t(unsigned int, wsize, 2 << 15);
+
+	return wsize;
+}
+
+static unsigned int
+smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+	struct TCP_Server_Info *server = tcon->ses->server;
+	unsigned int rsize;
+
+	/* start with specified rsize, or default */
+	rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
+	rsize = min_t(unsigned int, rsize, server->max_read);
+	/*
+	 * limit write size to 2 ** 16, because we don't support multicredit
+	 * requests now.
+	 */
+	rsize = min_t(unsigned int, rsize, 2 << 15);
+
+	return rsize;
+}
+
 static int
 smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
 			struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -164,13 +215,14 @@
 	int rc;
 	__u64 persistent_fid, volatile_fid;
 	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 	if (!utf16_path)
 		return -ENOMEM;
 
 	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
+		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
 	if (rc) {
 		kfree(utf16_path);
 		return rc;
@@ -190,6 +242,26 @@
 	return 0;
 }
 
+static int
+smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+		     struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+	int rc;
+	struct smb2_file_all_info *smb2_data;
+
+	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			    GFP_KERNEL);
+	if (smb2_data == NULL)
+		return -ENOMEM;
+
+	rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
+			     smb2_data);
+	if (!rc)
+		move_smb2_info_to_cifs(data, smb2_data);
+	kfree(smb2_data);
+	return rc;
+}
+
 static char *
 smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
 			struct cifs_tcon *tcon)
@@ -292,7 +364,221 @@
 #endif
 }
 
+static void
+smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+	cfile->fid.persistent_fid = fid->persistent_fid;
+	cfile->fid.volatile_fid = fid->volatile_fid;
+	smb2_set_oplock_level(cinode, oplock);
+	cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+}
+
+static void
+smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static int
+smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_fid *fid)
+{
+	return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static unsigned int
+smb2_read_data_offset(char *buf)
+{
+	struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+	return rsp->DataOffset;
+}
+
+static unsigned int
+smb2_read_data_length(char *buf)
+{
+	struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+	return le32_to_cpu(rsp->DataLength);
+}
+
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+	       struct cifs_io_parms *parms, unsigned int *bytes_read,
+	       char **buf, int *buf_type)
+{
+	parms->persistent_fid = cfile->fid.persistent_fid;
+	parms->volatile_fid = cfile->fid.volatile_fid;
+	return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
+static int
+smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+		struct cifs_io_parms *parms, unsigned int *written,
+		struct kvec *iov, unsigned long nr_segs)
+{
+
+	parms->persistent_fid = cfile->fid.persistent_fid;
+	parms->volatile_fid = cfile->fid.volatile_fid;
+	return SMB2_write(xid, parms, written, iov, nr_segs);
+}
+
+static int
+smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
+		   struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
+{
+	__le64 eof = cpu_to_le64(size);
+	return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
+			    cfile->fid.volatile_fid, cfile->pid, &eof);
+}
+
+static int
+smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *path, struct cifs_sb_info *cifs_sb,
+		     struct cifs_fid *fid, __u16 search_flags,
+		     struct cifs_search_info *srch_inf)
+{
+	__le16 *utf16_path;
+	int rc;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+	__u64 persistent_fid, volatile_fid;
+
+	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+
+	rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
+		       FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
+		       &oplock, NULL);
+	kfree(utf16_path);
+	if (rc) {
+		cERROR(1, "open dir failed");
+		return rc;
+	}
+
+	srch_inf->entries_in_buffer = 0;
+	srch_inf->index_of_last_entry = 0;
+	fid->persistent_fid = persistent_fid;
+	fid->volatile_fid = volatile_fid;
+
+	rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0,
+				  srch_inf);
+	if (rc) {
+		cERROR(1, "query directory failed");
+		SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+	}
+	return rc;
+}
+
+static int
+smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+		    struct cifs_fid *fid, __u16 search_flags,
+		    struct cifs_search_info *srch_inf)
+{
+	return SMB2_query_directory(xid, tcon, fid->persistent_fid,
+				    fid->volatile_fid, 0, srch_inf);
+}
+
+static int
+smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+	       struct cifs_fid *fid)
+{
+	return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+/*
+* If we negotiate SMB2 protocol and get STATUS_PENDING - update
+* the number of credits and return true. Otherwise - return false.
+*/
+static bool
+smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
+{
+	struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+
+	if (hdr->Status != STATUS_PENDING)
+		return false;
+
+	if (!length) {
+		spin_lock(&server->req_lock);
+		server->credits += le16_to_cpu(hdr->CreditRequest);
+		spin_unlock(&server->req_lock);
+		wake_up(&server->request_q);
+	}
+
+	return true;
+}
+
+static int
+smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+		     struct cifsInodeInfo *cinode)
+{
+	if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
+		return SMB2_lease_break(0, tcon, cinode->lease_key,
+					smb2_get_lease_state(cinode));
+
+	return SMB2_oplock_break(0, tcon, fid->persistent_fid,
+				 fid->volatile_fid,
+				 cinode->clientCanCacheRead ? 1 : 0);
+}
+
+static int
+smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+	     struct kstatfs *buf)
+{
+	int rc;
+	u64 persistent_fid, volatile_fid;
+	__le16 srch_path = 0; /* Null - open root of share */
+	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+	rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid,
+		       FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+	if (rc)
+		return rc;
+	buf->f_type = SMB2_MAGIC_NUMBER;
+	rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf);
+	SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+	return rc;
+}
+
+static bool
+smb2_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
+{
+	return ob1->fid.persistent_fid == ob2->fid.persistent_fid &&
+	       ob1->fid.volatile_fid == ob2->fid.volatile_fid;
+}
+
+static int
+smb2_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
+	       __u64 length, __u32 type, int lock, int unlock, bool wait)
+{
+	if (unlock && !lock)
+		type = SMB2_LOCKFLAG_UNLOCK;
+	return SMB2_lock(xid, tlink_tcon(cfile->tlink),
+			 cfile->fid.persistent_fid, cfile->fid.volatile_fid,
+			 current->tgid, length, offset, type, wait);
+}
+
+static void
+smb2_get_lease_key(struct inode *inode, struct cifs_fid *fid)
+{
+	memcpy(fid->lease_key, CIFS_I(inode)->lease_key, SMB2_LEASE_KEY_SIZE);
+}
+
+static void
+smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid)
+{
+	memcpy(CIFS_I(inode)->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
+}
+
+static void
+smb2_new_lease_key(struct cifs_fid *fid)
+{
+	get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
+}
+
 struct smb_version_operations smb21_operations = {
+	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
 	.check_receive = smb2_check_receive,
@@ -301,13 +587,19 @@
 	.get_credits_field = smb2_get_credits_field,
 	.get_credits = smb2_get_credits,
 	.get_next_mid = smb2_get_next_mid,
+	.read_data_offset = smb2_read_data_offset,
+	.read_data_length = smb2_read_data_length,
+	.map_error = map_smb2_to_linux_error,
 	.find_mid = smb2_find_mid,
 	.check_message = smb2_check_message,
 	.dump_detail = smb2_dump_detail,
 	.clear_stats = smb2_clear_stats,
 	.print_stats = smb2_print_stats,
+	.is_oplock_break = smb2_is_valid_oplock_break,
 	.need_neg = smb2_need_neg,
 	.negotiate = smb2_negotiate,
+	.negotiate_wsize = smb2_negotiate_wsize,
+	.negotiate_rsize = smb2_negotiate_rsize,
 	.sess_setup = SMB2_sess_setup,
 	.logoff = SMB2_logoff,
 	.tree_connect = SMB2_tcon,
@@ -317,16 +609,68 @@
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
 	.get_srv_inum = smb2_get_srv_inum,
+	.query_file_info = smb2_query_file_info,
+	.set_path_size = smb2_set_path_size,
+	.set_file_size = smb2_set_file_size,
+	.set_file_info = smb2_set_file_info,
 	.build_path_to_root = smb2_build_path_to_root,
 	.mkdir = smb2_mkdir,
 	.mkdir_setinfo = smb2_mkdir_setinfo,
 	.rmdir = smb2_rmdir,
+	.unlink = smb2_unlink,
+	.rename = smb2_rename_path,
+	.create_hardlink = smb2_create_hardlink,
+	.open = smb2_open_file,
+	.set_fid = smb2_set_fid,
+	.close = smb2_close_file,
+	.flush = smb2_flush_file,
+	.async_readv = smb2_async_readv,
+	.async_writev = smb2_async_writev,
+	.sync_read = smb2_sync_read,
+	.sync_write = smb2_sync_write,
+	.query_dir_first = smb2_query_dir_first,
+	.query_dir_next = smb2_query_dir_next,
+	.close_dir = smb2_close_dir,
+	.calc_smb_size = smb2_calc_size,
+	.is_status_pending = smb2_is_status_pending,
+	.oplock_response = smb2_oplock_response,
+	.queryfs = smb2_queryfs,
+	.mand_lock = smb2_mand_lock,
+	.mand_unlock_range = smb2_unlock_range,
+	.push_mand_locks = smb2_push_mandatory_locks,
+	.get_lease_key = smb2_get_lease_key,
+	.set_lease_key = smb2_set_lease_key,
+	.new_lease_key = smb2_new_lease_key,
 };
 
 struct smb_version_values smb21_values = {
 	.version_string = SMB21_VERSION_STRING,
+	.protocol_id = SMB21_PROT_ID,
+	.req_capabilities = 0, /* MBZ on negotiate req until SMB3 dialect */
+	.large_lock_type = 0,
+	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
+	.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
+	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
+	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
+	.lock_cmd = SMB2_LOCK,
+	.cap_unix = 0,
+	.cap_nt_find = SMB2_NT_FIND,
+	.cap_large_files = SMB2_LARGE_FILES,
+};
+
+struct smb_version_values smb30_values = {
+	.version_string = SMB30_VERSION_STRING,
+	.protocol_id = SMB30_PROT_ID,
+	.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+	.large_lock_type = 0,
+	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
+	.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
+	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
+	.header_size = sizeof(struct smb2_hdr),
+	.max_header_size = MAX_SMB2_HDR_SIZE,
+	.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
 	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 62b3f17..cf33622 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smb2pdu.c
  *
- *   Copyright (C) International Business Machines  Corp., 2009, 2011
+ *   Copyright (C) International Business Machines  Corp., 2009, 2012
  *                 Etersoft, 2012
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Pavel Shilovsky (pshilovsky@samba.org) 2012
@@ -31,7 +31,9 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/vfs.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/uaccess.h>
+#include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
@@ -42,6 +44,8 @@
 #include "cifs_debug.h"
 #include "ntlmssp.h"
 #include "smb2status.h"
+#include "smb2glob.h"
+#include "cifspdu.h"
 
 /*
  *  The following table defines the expected "StructureSize" of SMB2 requests
@@ -115,9 +119,9 @@
 	/* BB how does SMB2 do case sensitive? */
 	/* if (tcon->nocase)
 		hdr->Flags |= SMBFLG_CASELESS; */
-	/* if (tcon->ses && tcon->ses->server &&
+	if (tcon->ses && tcon->ses->server &&
 	    (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
-		hdr->Flags |= SMB2_FLAGS_SIGNED; */
+		hdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
 	pdu->StructureSize2 = cpu_to_le16(parmsize);
 	return;
@@ -300,24 +304,6 @@
 		cifs_buf_release(rsp);
 }
 
-#define SMB2_NUM_PROT 1
-
-#define SMB2_PROT   0
-#define SMB21_PROT  1
-#define BAD_PROT 0xFFFF
-
-#define SMB2_PROT_ID  0x0202
-#define SMB21_PROT_ID 0x0210
-#define BAD_PROT_ID   0xFFFF
-
-static struct {
-	int index;
-	__le16 name;
-} smb2protocols[] = {
-	{SMB2_PROT,  cpu_to_le16(SMB2_PROT_ID)},
-	{SMB21_PROT, cpu_to_le16(SMB21_PROT_ID)},
-	{BAD_PROT,   cpu_to_le16(BAD_PROT_ID)}
-};
 
 /*
  *
@@ -344,7 +330,6 @@
 	int resp_buftype;
 	struct TCP_Server_Info *server;
 	unsigned int sec_flags;
-	u16 i;
 	u16 temp = 0;
 	int blob_offset, blob_length;
 	char *security_blob;
@@ -373,11 +358,10 @@
 
 	req->hdr.SessionId = 0;
 
-	for (i = 0; i < SMB2_NUM_PROT; i++)
-		req->Dialects[i] = smb2protocols[i].name;
+	req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
 
-	req->DialectCount = cpu_to_le16(i);
-	inc_rfc1001_len(req, i * 2);
+	req->DialectCount = cpu_to_le16(1); /* One vers= at a time for now */
+	inc_rfc1001_len(req, 2);
 
 	/* only one of SMB2 signing flags may be set in SMB2 request */
 	if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
@@ -387,7 +371,9 @@
 
 	req->SecurityMode = cpu_to_le16(temp);
 
-	req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS);
+	req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities);
+
+	memcpy(req->ClientGUID, cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
 
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
@@ -403,17 +389,16 @@
 	if (rc != 0)
 		goto neg_exit;
 
-	if (rsp == NULL) {
-		rc = -EIO;
-		goto neg_exit;
-	}
-
 	cFYI(1, "mode 0x%x", rsp->SecurityMode);
 
-	if (rsp->DialectRevision == smb2protocols[SMB21_PROT].name)
+	/* BB we may eventually want to match the negotiated vs. requested
+	   dialect, even though we are only requesting one at a time */
+	if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID))
+		cFYI(1, "negotiated smb2.0 dialect");
+	else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID))
 		cFYI(1, "negotiated smb2.1 dialect");
-	else if (rsp->DialectRevision == smb2protocols[SMB2_PROT].name)
-		cFYI(1, "negotiated smb2 dialect");
+	else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
+		cFYI(1, "negotiated smb3.0 dialect");
 	else {
 		cERROR(1, "Illegal dialect returned by server %d",
 			   le16_to_cpu(rsp->DialectRevision));
@@ -438,6 +423,38 @@
 		rc = -EIO;
 		goto neg_exit;
 	}
+
+	cFYI(1, "sec_flags 0x%x", sec_flags);
+	if (sec_flags & CIFSSEC_MUST_SIGN) {
+		cFYI(1, "Signing required");
+		if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
+		      SMB2_NEGOTIATE_SIGNING_ENABLED))) {
+			cERROR(1, "signing required but server lacks support");
+			rc = -EOPNOTSUPP;
+			goto neg_exit;
+		}
+		server->sec_mode |= SECMODE_SIGN_REQUIRED;
+	} else if (sec_flags & CIFSSEC_MAY_SIGN) {
+		cFYI(1, "Signing optional");
+		if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+			cFYI(1, "Server requires signing");
+			server->sec_mode |= SECMODE_SIGN_REQUIRED;
+		} else {
+			server->sec_mode &=
+				~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+		}
+	} else {
+		cFYI(1, "Signing disabled");
+		if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+			cERROR(1, "Server requires packet signing to be enabled"
+				  " in /proc/fs/cifs/SecurityFlags.");
+			rc = -EOPNOTSUPP;
+			goto neg_exit;
+		}
+		server->sec_mode &=
+			~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+	}
+
 #ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
 	rc = decode_neg_token_init(security_blob, blob_length,
 				   &server->sec_type);
@@ -599,13 +616,14 @@
 
 	kfree(security_blob);
 	rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
-	if (rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
+	if (resp_buftype != CIFS_NO_BUFFER &&
+	    rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
 		if (phase != NtLmNegotiate) {
 			cERROR(1, "Unexpected more processing error");
 			goto ssetup_exit;
 		}
 		if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
-			le16_to_cpu(rsp->SecurityBufferOffset)) {
+				le16_to_cpu(rsp->SecurityBufferOffset)) {
 			cERROR(1, "Invalid security buffer offset %d",
 				  le16_to_cpu(rsp->SecurityBufferOffset));
 			rc = -EIO;
@@ -631,11 +649,6 @@
 	if (rc != 0)
 		goto ssetup_exit;
 
-	if (rsp == NULL) {
-		rc = -EIO;
-		goto ssetup_exit;
-	}
-
 	ses->session_flags = le16_to_cpu(rsp->SessionFlags);
 ssetup_exit:
 	free_rsp_buf(resp_buftype, rsp);
@@ -666,6 +679,8 @@
 
 	 /* since no tcon, smb2_init can not do this, so do here */
 	req->hdr.SessionId = ses->Suid;
+	if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+		req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
 	rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
 	/*
@@ -753,11 +768,6 @@
 		goto tcon_error_exit;
 	}
 
-	if (rsp == NULL) {
-		rc = -EIO;
-		goto tcon_exit;
-	}
-
 	if (tcon == NULL) {
 		ses->ipc_tid = rsp->hdr.TreeId;
 		goto tcon_exit;
@@ -830,18 +840,87 @@
 	return rc;
 }
 
+static struct create_lease *
+create_lease_buf(u8 *lease_key, u8 oplock)
+{
+	struct create_lease *buf;
+
+	buf = kmalloc(sizeof(struct create_lease), GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	memset(buf, 0, sizeof(struct create_lease));
+
+	buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
+	buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
+	if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+		buf->lcontext.LeaseState = SMB2_LEASE_WRITE_CACHING |
+					   SMB2_LEASE_READ_CACHING;
+	else if (oplock == SMB2_OPLOCK_LEVEL_II)
+		buf->lcontext.LeaseState = SMB2_LEASE_READ_CACHING;
+	else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
+		buf->lcontext.LeaseState = SMB2_LEASE_HANDLE_CACHING |
+					   SMB2_LEASE_READ_CACHING |
+					   SMB2_LEASE_WRITE_CACHING;
+
+	buf->ccontext.DataOffset = cpu_to_le16(offsetof
+					(struct create_lease, lcontext));
+	buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
+	buf->ccontext.NameOffset = cpu_to_le16(offsetof
+				(struct create_lease, Name));
+	buf->ccontext.NameLength = cpu_to_le16(4);
+	buf->Name[0] = 'R';
+	buf->Name[1] = 'q';
+	buf->Name[2] = 'L';
+	buf->Name[3] = 's';
+	return buf;
+}
+
+static __u8
+parse_lease_state(struct smb2_create_rsp *rsp)
+{
+	char *data_offset;
+	struct create_lease *lc;
+	bool found = false;
+
+	data_offset = (char *)rsp;
+	data_offset += 4 + le32_to_cpu(rsp->CreateContextsOffset);
+	lc = (struct create_lease *)data_offset;
+	do {
+		char *name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
+		if (le16_to_cpu(lc->ccontext.NameLength) != 4 ||
+		    strncmp(name, "RqLs", 4)) {
+			lc = (struct create_lease *)((char *)lc
+					+ le32_to_cpu(lc->ccontext.Next));
+			continue;
+		}
+		if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
+			return SMB2_OPLOCK_LEVEL_NOCHANGE;
+		found = true;
+		break;
+	} while (le32_to_cpu(lc->ccontext.Next) != 0);
+
+	if (!found)
+		return 0;
+
+	return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
+}
+
 int
 SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
 	  u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
-	  __u32 create_disposition, __u32 file_attributes, __u32 create_options)
+	  __u32 create_disposition, __u32 file_attributes, __u32 create_options,
+	  __u8 *oplock, struct smb2_file_all_info *buf)
 {
 	struct smb2_create_req *req;
 	struct smb2_create_rsp *rsp;
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses = tcon->ses;
-	struct kvec iov[2];
+	struct kvec iov[3];
 	int resp_buftype;
 	int uni_path_len;
+	__le16 *copy_path = NULL;
+	int copy_size;
 	int rc = 0;
 	int num_iovecs = 2;
 
@@ -856,10 +935,6 @@
 	if (rc)
 		return rc;
 
-	if (enable_oplocks)
-		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
-	else
-		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 	req->ImpersonationLevel = IL_IMPERSONATION;
 	req->DesiredAccess = cpu_to_le32(desired_access);
 	/* File attributes ignored on open (used in create though) */
@@ -869,7 +944,7 @@
 	req->CreateOptions = cpu_to_le32(create_options);
 	uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
 	req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)
-			- 1 /* pad */ - 4 /* do not count rfc1001 len field */);
+			- 8 /* pad */ - 4 /* do not count rfc1001 len field */);
 
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
@@ -880,6 +955,20 @@
 		req->NameLength = cpu_to_le16(uni_path_len - 2);
 		/* -1 since last byte is buf[0] which is sent below (path) */
 		iov[0].iov_len--;
+		if (uni_path_len % 8 != 0) {
+			copy_size = uni_path_len / 8 * 8;
+			if (copy_size < uni_path_len)
+				copy_size += 8;
+
+			copy_path = kzalloc(copy_size, GFP_KERNEL);
+			if (!copy_path)
+				return -ENOMEM;
+			memcpy((char *)copy_path, (const char *)path,
+				uni_path_len);
+			uni_path_len = copy_size;
+			path = copy_path;
+		}
+
 		iov[1].iov_len = uni_path_len;
 		iov[1].iov_base = path;
 		/*
@@ -888,10 +977,37 @@
 		 */
 		inc_rfc1001_len(req, uni_path_len - 1);
 	} else {
+		iov[0].iov_len += 7;
+		req->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
+				req->hdr.smb2_buf_length) + 8 - 1);
 		num_iovecs = 1;
 		req->NameLength = 0;
 	}
 
+	if (!server->oplocks)
+		*oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+	if (!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
+	    *oplock == SMB2_OPLOCK_LEVEL_NONE)
+		req->RequestedOplockLevel = *oplock;
+	else {
+		iov[num_iovecs].iov_base = create_lease_buf(oplock+1, *oplock);
+		if (iov[num_iovecs].iov_base == NULL) {
+			cifs_small_buf_release(req);
+			kfree(copy_path);
+			return -ENOMEM;
+		}
+		iov[num_iovecs].iov_len = sizeof(struct create_lease);
+		req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
+		req->CreateContextsOffset = cpu_to_le32(
+			sizeof(struct smb2_create_req) - 4 - 8 +
+			iov[num_iovecs-1].iov_len);
+		req->CreateContextsLength = cpu_to_le32(
+			sizeof(struct create_lease));
+		inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
+		num_iovecs++;
+	}
+
 	rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
 	rsp = (struct smb2_create_rsp *)iov[0].iov_base;
 
@@ -900,13 +1016,24 @@
 		goto creat_exit;
 	}
 
-	if (rsp == NULL) {
-		rc = -EIO;
-		goto creat_exit;
-	}
 	*persistent_fid = rsp->PersistentFileId;
 	*volatile_fid = rsp->VolatileFileId;
+
+	if (buf) {
+		memcpy(buf, &rsp->CreationTime, 32);
+		buf->AllocationSize = rsp->AllocationSize;
+		buf->EndOfFile = rsp->EndofFile;
+		buf->Attributes = rsp->FileAttributes;
+		buf->NumberOfLinks = cpu_to_le32(1);
+		buf->DeletePending = 0;
+	}
+
+	if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
+		*oplock = parse_lease_state(rsp);
+	else
+		*oplock = rsp->OplockLevel;
 creat_exit:
+	kfree(copy_path);
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
 }
@@ -950,11 +1077,6 @@
 		goto close_exit;
 	}
 
-	if (rsp == NULL) {
-		rc = -EIO;
-		goto close_exit;
-	}
-
 	/* BB FIXME - decode close response, update inode for caching */
 
 close_exit:
@@ -1019,10 +1141,10 @@
 	return 0;
 }
 
-int
-SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
-		u64 persistent_fid, u64 volatile_fid,
-		struct smb2_file_all_info *data)
+static int
+query_info(const unsigned int xid, struct cifs_tcon *tcon,
+	   u64 persistent_fid, u64 volatile_fid, u8 info_class,
+	   size_t output_len, size_t min_len, void *data)
 {
 	struct smb2_query_info_req *req;
 	struct smb2_query_info_rsp *rsp = NULL;
@@ -1044,37 +1166,56 @@
 		return rc;
 
 	req->InfoType = SMB2_O_INFO_FILE;
-	req->FileInfoClass = FILE_ALL_INFORMATION;
+	req->FileInfoClass = info_class;
 	req->PersistentFileId = persistent_fid;
 	req->VolatileFileId = volatile_fid;
 	/* 4 for rfc1002 length field and 1 for Buffer */
 	req->InputBufferOffset =
 		cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
-	req->OutputBufferLength =
-		cpu_to_le32(sizeof(struct smb2_file_all_info) + MAX_NAME * 2);
+	req->OutputBufferLength = cpu_to_le32(output_len);
 
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
 
 	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+	rsp = (struct smb2_query_info_rsp *)iov[0].iov_base;
+
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
 		goto qinf_exit;
 	}
 
-	rsp = (struct smb2_query_info_rsp *)iov[0].iov_base;
-
 	rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
 				   le32_to_cpu(rsp->OutputBufferLength),
-				   &rsp->hdr, sizeof(struct smb2_file_all_info),
-				   (char *)data);
+				   &rsp->hdr, min_len, data);
 
 qinf_exit:
 	free_rsp_buf(resp_buftype, rsp);
 	return rc;
 }
 
+int
+SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+		u64 persistent_fid, u64 volatile_fid,
+		struct smb2_file_all_info *data)
+{
+	return query_info(xid, tcon, persistent_fid, volatile_fid,
+			  FILE_ALL_INFORMATION,
+			  sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+			  sizeof(struct smb2_file_all_info), data);
+}
+
+int
+SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+		 u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
+{
+	return query_info(xid, tcon, persistent_fid, volatile_fid,
+			  FILE_INTERNAL_INFORMATION,
+			  sizeof(struct smb2_file_internal_info),
+			  sizeof(struct smb2_file_internal_info), uniqueid);
+}
+
 /*
  * This is a no-op for now. We're not really interested in the reply, but
  * rather in the fact that the server sent one and that server->lstrp
@@ -1102,6 +1243,8 @@
 	struct smb2_echo_req *req;
 	int rc = 0;
 	struct kvec iov;
+	struct smb_rqst rqst = { .rq_iov = &iov,
+				 .rq_nvec = 1 };
 
 	cFYI(1, "In echo request");
 
@@ -1115,7 +1258,7 @@
 	/* 4 for rfc1002 length field */
 	iov.iov_len = get_rfc1002_length(req) + 4;
 
-	rc = cifs_call_async(server, &iov, 1, NULL, smb2_echo_callback, server,
+	rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server,
 			     CIFS_ECHO_OP);
 	if (rc)
 		cFYI(1, "Echo request failed: %d", rc);
@@ -1123,3 +1266,945 @@
 	cifs_small_buf_release(req);
 	return rc;
 }
+
+int
+SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+	   u64 volatile_fid)
+{
+	struct smb2_flush_req *req;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+	struct kvec iov[1];
+	int resp_buftype;
+	int rc = 0;
+
+	cFYI(1, "Flush");
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+
+	if ((rc != 0) && tcon)
+		cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
+
+	free_rsp_buf(resp_buftype, iov[0].iov_base);
+	return rc;
+}
+
+/*
+ * To form a chain of read requests, any read requests after the first should
+ * have the end_of_chain boolean set to true.
+ */
+static int
+smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+		  unsigned int remaining_bytes, int request_type)
+{
+	int rc = -EACCES;
+	struct smb2_read_req *req = NULL;
+
+	rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+	if (rc)
+		return rc;
+	if (io_parms->tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+	req->PersistentFileId = io_parms->persistent_fid;
+	req->VolatileFileId = io_parms->volatile_fid;
+	req->ReadChannelInfoOffset = 0; /* reserved */
+	req->ReadChannelInfoLength = 0; /* reserved */
+	req->Channel = 0; /* reserved */
+	req->MinimumCount = 0;
+	req->Length = cpu_to_le32(io_parms->length);
+	req->Offset = cpu_to_le64(io_parms->offset);
+
+	if (request_type & CHAINED_REQUEST) {
+		if (!(request_type & END_OF_CHAIN)) {
+			/* 4 for rfc1002 length field */
+			req->hdr.NextCommand =
+				cpu_to_le32(get_rfc1002_length(req) + 4);
+		} else /* END_OF_CHAIN */
+			req->hdr.NextCommand = 0;
+		if (request_type & RELATED_REQUEST) {
+			req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+			/*
+			 * Related requests use info from previous read request
+			 * in chain.
+			 */
+			req->hdr.SessionId = 0xFFFFFFFF;
+			req->hdr.TreeId = 0xFFFFFFFF;
+			req->PersistentFileId = 0xFFFFFFFF;
+			req->VolatileFileId = 0xFFFFFFFF;
+		}
+	}
+	if (remaining_bytes > io_parms->length)
+		req->RemainingBytes = cpu_to_le32(remaining_bytes);
+	else
+		req->RemainingBytes = 0;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+	return rc;
+}
+
+static void
+smb2_readv_callback(struct mid_q_entry *mid)
+{
+	struct cifs_readdata *rdata = mid->callback_data;
+	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+	struct TCP_Server_Info *server = tcon->ses->server;
+	struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov.iov_base;
+	unsigned int credits_received = 1;
+	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
+				 .rq_nvec = 1,
+				 .rq_pages = rdata->pages,
+				 .rq_npages = rdata->nr_pages,
+				 .rq_pagesz = rdata->pagesz,
+				 .rq_tailsz = rdata->tailsz };
+
+	cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+		mid->mid, mid->mid_state, rdata->result, rdata->bytes);
+
+	switch (mid->mid_state) {
+	case MID_RESPONSE_RECEIVED:
+		credits_received = le16_to_cpu(buf->CreditRequest);
+		/* result already set, check signature */
+		if (server->sec_mode &
+		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+			int rc;
+
+			rc = smb2_verify_signature(&rqst, server);
+			if (rc)
+				cERROR(1, "SMB signature verification returned "
+				       "error = %d", rc);
+		}
+		/* FIXME: should this be counted toward the initiating task? */
+		task_io_account_read(rdata->bytes);
+		cifs_stats_bytes_read(tcon, rdata->bytes);
+		break;
+	case MID_REQUEST_SUBMITTED:
+	case MID_RETRY_NEEDED:
+		rdata->result = -EAGAIN;
+		break;
+	default:
+		if (rdata->result != -ENODATA)
+			rdata->result = -EIO;
+	}
+
+	if (rdata->result)
+		cifs_stats_fail_inc(tcon, SMB2_READ_HE);
+
+	queue_work(cifsiod_wq, &rdata->work);
+	DeleteMidQEntry(mid);
+	add_credits(server, credits_received, 0);
+}
+
+/* smb2_async_readv - send an async write, and set up mid to handle result */
+int
+smb2_async_readv(struct cifs_readdata *rdata)
+{
+	int rc;
+	struct smb2_hdr *buf;
+	struct cifs_io_parms io_parms;
+	struct smb_rqst rqst = { .rq_iov = &rdata->iov,
+				 .rq_nvec = 1 };
+
+	cFYI(1, "%s: offset=%llu bytes=%u", __func__,
+		rdata->offset, rdata->bytes);
+
+	io_parms.tcon = tlink_tcon(rdata->cfile->tlink);
+	io_parms.offset = rdata->offset;
+	io_parms.length = rdata->bytes;
+	io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
+	io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
+	io_parms.pid = rdata->pid;
+	rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0);
+	if (rc)
+		return rc;
+
+	buf = (struct smb2_hdr *)rdata->iov.iov_base;
+	/* 4 for rfc1002 length field */
+	rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
+
+	kref_get(&rdata->refcount);
+	rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
+			     cifs_readv_receive, smb2_readv_callback,
+			     rdata, 0);
+	if (rc) {
+		kref_put(&rdata->refcount, cifs_readdata_release);
+		cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
+	}
+
+	cifs_small_buf_release(buf);
+	return rc;
+}
+
+int
+SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+	  unsigned int *nbytes, char **buf, int *buf_type)
+{
+	int resp_buftype, rc = -EACCES;
+	struct smb2_read_rsp *rsp = NULL;
+	struct kvec iov[1];
+
+	*nbytes = 0;
+	rc = smb2_new_read_req(iov, io_parms, 0, 0);
+	if (rc)
+		return rc;
+
+	rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
+			  &resp_buftype, CIFS_LOG_ERROR);
+
+	rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+
+	if (rsp->hdr.Status == STATUS_END_OF_FILE) {
+		free_rsp_buf(resp_buftype, iov[0].iov_base);
+		return 0;
+	}
+
+	if (rc) {
+		cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+		cERROR(1, "Send error in read = %d", rc);
+	} else {
+		*nbytes = le32_to_cpu(rsp->DataLength);
+		if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+		    (*nbytes > io_parms->length)) {
+			cFYI(1, "bad length %d for count %d", *nbytes,
+				io_parms->length);
+			rc = -EIO;
+			*nbytes = 0;
+		}
+	}
+
+	if (*buf) {
+		memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
+		       *nbytes);
+		free_rsp_buf(resp_buftype, iov[0].iov_base);
+	} else if (resp_buftype != CIFS_NO_BUFFER) {
+		*buf = iov[0].iov_base;
+		if (resp_buftype == CIFS_SMALL_BUFFER)
+			*buf_type = CIFS_SMALL_BUFFER;
+		else if (resp_buftype == CIFS_LARGE_BUFFER)
+			*buf_type = CIFS_LARGE_BUFFER;
+	}
+	return rc;
+}
+
+/*
+ * Check the mid_state and signature on received buffer (if any), and queue the
+ * workqueue completion task.
+ */
+static void
+smb2_writev_callback(struct mid_q_entry *mid)
+{
+	struct cifs_writedata *wdata = mid->callback_data;
+	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+	unsigned int written;
+	struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
+	unsigned int credits_received = 1;
+
+	switch (mid->mid_state) {
+	case MID_RESPONSE_RECEIVED:
+		credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+		wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
+		if (wdata->result != 0)
+			break;
+
+		written = le32_to_cpu(rsp->DataLength);
+		/*
+		 * Mask off high 16 bits when bytes written as returned
+		 * by the server is greater than bytes requested by the
+		 * client. OS/2 servers are known to set incorrect
+		 * CountHigh values.
+		 */
+		if (written > wdata->bytes)
+			written &= 0xFFFF;
+
+		if (written < wdata->bytes)
+			wdata->result = -ENOSPC;
+		else
+			wdata->bytes = written;
+		break;
+	case MID_REQUEST_SUBMITTED:
+	case MID_RETRY_NEEDED:
+		wdata->result = -EAGAIN;
+		break;
+	default:
+		wdata->result = -EIO;
+		break;
+	}
+
+	if (wdata->result)
+		cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+
+	queue_work(cifsiod_wq, &wdata->work);
+	DeleteMidQEntry(mid);
+	add_credits(tcon->ses->server, credits_received, 0);
+}
+
+/* smb2_async_writev - send an async write, and set up mid to handle result */
+int
+smb2_async_writev(struct cifs_writedata *wdata)
+{
+	int rc = -EACCES;
+	struct smb2_write_req *req = NULL;
+	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+	struct kvec iov;
+	struct smb_rqst rqst;
+
+	rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
+	if (rc)
+		goto async_writev_out;
+
+	req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+
+	req->PersistentFileId = wdata->cfile->fid.persistent_fid;
+	req->VolatileFileId = wdata->cfile->fid.volatile_fid;
+	req->WriteChannelInfoOffset = 0;
+	req->WriteChannelInfoLength = 0;
+	req->Channel = 0;
+	req->Offset = cpu_to_le64(wdata->offset);
+	/* 4 for rfc1002 length field */
+	req->DataOffset = cpu_to_le16(
+				offsetof(struct smb2_write_req, Buffer) - 4);
+	req->RemainingBytes = 0;
+
+	/* 4 for rfc1002 length field and 1 for Buffer */
+	iov.iov_len = get_rfc1002_length(req) + 4 - 1;
+	iov.iov_base = req;
+
+	rqst.rq_iov = &iov;
+	rqst.rq_nvec = 1;
+	rqst.rq_pages = wdata->pages;
+	rqst.rq_npages = wdata->nr_pages;
+	rqst.rq_pagesz = wdata->pagesz;
+	rqst.rq_tailsz = wdata->tailsz;
+
+	cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+	req->Length = cpu_to_le32(wdata->bytes);
+
+	inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
+
+	kref_get(&wdata->refcount);
+	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
+				smb2_writev_callback, wdata, 0);
+
+	if (rc) {
+		kref_put(&wdata->refcount, cifs_writedata_release);
+		cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+	}
+
+async_writev_out:
+	cifs_small_buf_release(req);
+	return rc;
+}
+
+/*
+ * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
+ * The length field from io_parms must be at least 1 and indicates a number of
+ * elements with data to write that begins with position 1 in iov array. All
+ * data length is specified by count.
+ */
+int
+SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+	   unsigned int *nbytes, struct kvec *iov, int n_vec)
+{
+	int rc = 0;
+	struct smb2_write_req *req = NULL;
+	struct smb2_write_rsp *rsp = NULL;
+	int resp_buftype;
+	*nbytes = 0;
+
+	if (n_vec < 1)
+		return rc;
+
+	rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	if (io_parms->tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+	req->PersistentFileId = io_parms->persistent_fid;
+	req->VolatileFileId = io_parms->volatile_fid;
+	req->WriteChannelInfoOffset = 0;
+	req->WriteChannelInfoLength = 0;
+	req->Channel = 0;
+	req->Length = cpu_to_le32(io_parms->length);
+	req->Offset = cpu_to_le64(io_parms->offset);
+	/* 4 for rfc1002 length field */
+	req->DataOffset = cpu_to_le16(
+				offsetof(struct smb2_write_req, Buffer) - 4);
+	req->RemainingBytes = 0;
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field and 1 for Buffer */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+	/* length of entire message including data to be written */
+	inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
+
+	rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
+			  &resp_buftype, 0);
+	rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+
+	if (rc) {
+		cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
+		cERROR(1, "Send error in write = %d", rc);
+	} else
+		*nbytes = le32_to_cpu(rsp->DataLength);
+
+	free_rsp_buf(resp_buftype, rsp);
+	return rc;
+}
+
+static unsigned int
+num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
+{
+	int len;
+	unsigned int entrycount = 0;
+	unsigned int next_offset = 0;
+	FILE_DIRECTORY_INFO *entryptr;
+
+	if (bufstart == NULL)
+		return 0;
+
+	entryptr = (FILE_DIRECTORY_INFO *)bufstart;
+
+	while (1) {
+		entryptr = (FILE_DIRECTORY_INFO *)
+					((char *)entryptr + next_offset);
+
+		if ((char *)entryptr + size > end_of_buf) {
+			cERROR(1, "malformed search entry would overflow");
+			break;
+		}
+
+		len = le32_to_cpu(entryptr->FileNameLength);
+		if ((char *)entryptr + len + size > end_of_buf) {
+			cERROR(1, "directory entry name would overflow frame "
+				  "end of buf %p", end_of_buf);
+			break;
+		}
+
+		*lastentry = (char *)entryptr;
+		entrycount++;
+
+		next_offset = le32_to_cpu(entryptr->NextEntryOffset);
+		if (!next_offset)
+			break;
+	}
+
+	return entrycount;
+}
+
+/*
+ * Readdir/FindFirst
+ */
+int
+SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+		     u64 persistent_fid, u64 volatile_fid, int index,
+		     struct cifs_search_info *srch_inf)
+{
+	struct smb2_query_directory_req *req;
+	struct smb2_query_directory_rsp *rsp = NULL;
+	struct kvec iov[2];
+	int rc = 0;
+	int len;
+	int resp_buftype;
+	unsigned char *bufptr;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+	__le16 asteriks = cpu_to_le16('*');
+	char *end_of_smb;
+	unsigned int output_size = CIFSMaxBufSize;
+	size_t info_buf_size;
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	switch (srch_inf->info_level) {
+	case SMB_FIND_FILE_DIRECTORY_INFO:
+		req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
+		info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1;
+		break;
+	case SMB_FIND_FILE_ID_FULL_DIR_INFO:
+		req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
+		info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
+		break;
+	default:
+		cERROR(1, "info level %u isn't supported",
+		       srch_inf->info_level);
+		rc = -EINVAL;
+		goto qdir_exit;
+	}
+
+	req->FileIndex = cpu_to_le32(index);
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	len = 0x2;
+	bufptr = req->Buffer;
+	memcpy(bufptr, &asteriks, len);
+
+	req->FileNameOffset =
+		cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1 - 4);
+	req->FileNameLength = cpu_to_le16(len);
+	/*
+	 * BB could be 30 bytes or so longer if we used SMB2 specific
+	 * buffer lengths, but this is safe and close enough.
+	 */
+	output_size = min_t(unsigned int, output_size, server->maxBuf);
+	output_size = min_t(unsigned int, output_size, 2 << 15);
+	req->OutputBufferLength = cpu_to_le32(output_size);
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for RFC1001 length and 1 for Buffer */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+	iov[1].iov_base = (char *)(req->Buffer);
+	iov[1].iov_len = len;
+
+	inc_rfc1001_len(req, len - 1 /* Buffer */);
+
+	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
+	rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+		goto qdir_exit;
+	}
+
+	rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+			  le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+			  info_buf_size);
+	if (rc)
+		goto qdir_exit;
+
+	srch_inf->unicode = true;
+
+	if (srch_inf->ntwrk_buf_start) {
+		if (srch_inf->smallBuf)
+			cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+		else
+			cifs_buf_release(srch_inf->ntwrk_buf_start);
+	}
+	srch_inf->ntwrk_buf_start = (char *)rsp;
+	srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ +
+		(char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset);
+	/* 4 for rfc1002 length field */
+	end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr;
+	srch_inf->entries_in_buffer =
+			num_entries(srch_inf->srch_entries_start, end_of_smb,
+				    &srch_inf->last_entry, info_buf_size);
+	srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
+	cFYI(1, "num entries %d last_index %lld srch start %p srch end %p",
+		srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
+		srch_inf->srch_entries_start, srch_inf->last_entry);
+	if (resp_buftype == CIFS_LARGE_BUFFER)
+		srch_inf->smallBuf = false;
+	else if (resp_buftype == CIFS_SMALL_BUFFER)
+		srch_inf->smallBuf = true;
+	else
+		cERROR(1, "illegal search buffer type");
+
+	if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
+		srch_inf->endOfSearch = 1;
+	else
+		srch_inf->endOfSearch = 0;
+
+	return rc;
+
+qdir_exit:
+	free_rsp_buf(resp_buftype, rsp);
+	return rc;
+}
+
+static int
+send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+	       u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
+	       unsigned int num, void **data, unsigned int *size)
+{
+	struct smb2_set_info_req *req;
+	struct smb2_set_info_rsp *rsp = NULL;
+	struct kvec *iov;
+	int rc = 0;
+	int resp_buftype;
+	unsigned int i;
+	struct TCP_Server_Info *server;
+	struct cifs_ses *ses = tcon->ses;
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	if (!num)
+		return -EINVAL;
+
+	iov = kmalloc(sizeof(struct kvec) * num, GFP_KERNEL);
+	if (!iov)
+		return -ENOMEM;
+
+	rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
+	if (rc) {
+		kfree(iov);
+		return rc;
+	}
+
+	req->hdr.ProcessId = cpu_to_le32(pid);
+
+	req->InfoType = SMB2_O_INFO_FILE;
+	req->FileInfoClass = info_class;
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+
+	/* 4 for RFC1001 length and 1 for Buffer */
+	req->BufferOffset =
+			cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
+	req->BufferLength = cpu_to_le32(*size);
+
+	inc_rfc1001_len(req, *size - 1 /* Buffer */);
+
+	memcpy(req->Buffer, *data, *size);
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for RFC1001 length */
+	iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+	for (i = 1; i < num; i++) {
+		inc_rfc1001_len(req, size[i]);
+		le32_add_cpu(&req->BufferLength, size[i]);
+		iov[i].iov_base = (char *)data[i];
+		iov[i].iov_len = size[i];
+	}
+
+	rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
+	rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+
+	if (rc != 0) {
+		cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
+		goto out;
+	}
+out:
+	free_rsp_buf(resp_buftype, rsp);
+	kfree(iov);
+	return rc;
+}
+
+int
+SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+	    u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+	struct smb2_file_rename_info info;
+	void **data;
+	unsigned int size[2];
+	int rc;
+	int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+	data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
+			      /* 0 = fail if target already exists */
+	info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+	info.FileNameLength = cpu_to_le32(len);
+
+	data[0] = &info;
+	size[0] = sizeof(struct smb2_file_rename_info);
+
+	data[1] = target_file;
+	size[1] = len + 2 /* null */;
+
+	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			   current->tgid, FILE_RENAME_INFORMATION, 2, data,
+			   size);
+	kfree(data);
+	return rc;
+}
+
+int
+SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+		  u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+	struct smb2_file_link_info info;
+	void **data;
+	unsigned int size[2];
+	int rc;
+	int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+	data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
+			      /* 0 = fail if link already exists */
+	info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+	info.FileNameLength = cpu_to_le32(len);
+
+	data[0] = &info;
+	size[0] = sizeof(struct smb2_file_link_info);
+
+	data[1] = target_file;
+	size[1] = len + 2 /* null */;
+
+	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			   current->tgid, FILE_LINK_INFORMATION, 2, data, size);
+	kfree(data);
+	return rc;
+}
+
+int
+SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+	     u64 volatile_fid, u32 pid, __le64 *eof)
+{
+	struct smb2_file_eof_info info;
+	void *data;
+	unsigned int size;
+
+	info.EndOfFile = *eof;
+
+	data = &info;
+	size = sizeof(struct smb2_file_eof_info);
+
+	return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
+			     FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
+}
+
+int
+SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+	      u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf)
+{
+	unsigned int size;
+	size = sizeof(FILE_BASIC_INFO);
+	return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+			     current->tgid, FILE_BASIC_INFORMATION, 1,
+			     (void **)&buf, &size);
+}
+
+int
+SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+		  const u64 persistent_fid, const u64 volatile_fid,
+		  __u8 oplock_level)
+{
+	int rc;
+	struct smb2_oplock_break *req = NULL;
+
+	cFYI(1, "SMB2_oplock_break");
+	rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+
+	if (rc)
+		return rc;
+
+	req->VolatileFid = volatile_fid;
+	req->PersistentFid = persistent_fid;
+	req->OplockLevel = oplock_level;
+	req->hdr.CreditRequest = cpu_to_le16(1);
+
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
+	/* SMB2 buffer freed by function above */
+
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+		cFYI(1, "Send error in Oplock Break = %d", rc);
+	}
+
+	return rc;
+}
+
+static void
+copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
+			struct kstatfs *kst)
+{
+	kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
+			  le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
+	kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
+	kst->f_bfree  = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
+	kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+	return;
+}
+
+static int
+build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
+		   int outbuf_len, u64 persistent_fid, u64 volatile_fid)
+{
+	int rc;
+	struct smb2_query_info_req *req;
+
+	cFYI(1, "Query FSInfo level %d", level);
+
+	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	req->InfoType = SMB2_O_INFO_FILESYSTEM;
+	req->FileInfoClass = level;
+	req->PersistentFileId = persistent_fid;
+	req->VolatileFileId = volatile_fid;
+	/* 4 for rfc1002 length field and 1 for pad */
+	req->InputBufferOffset =
+			cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
+	req->OutputBufferLength = cpu_to_le32(
+		outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
+
+	iov->iov_base = (char *)req;
+	/* 4 for rfc1002 length field */
+	iov->iov_len = get_rfc1002_length(req) + 4;
+	return 0;
+}
+
+int
+SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+	      u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
+{
+	struct smb2_query_info_rsp *rsp = NULL;
+	struct kvec iov;
+	int rc = 0;
+	int resp_buftype;
+	struct cifs_ses *ses = tcon->ses;
+	struct smb2_fs_full_size_info *info = NULL;
+
+	rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
+				sizeof(struct smb2_fs_full_size_info),
+				persistent_fid, volatile_fid);
+	if (rc)
+		return rc;
+
+	rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+		goto qinf_exit;
+	}
+	rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+
+	info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
+		le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
+	rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+			  le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+			  sizeof(struct smb2_fs_full_size_info));
+	if (!rc)
+		copy_fs_info_to_kstatfs(info, fsdata);
+
+qinf_exit:
+	free_rsp_buf(resp_buftype, iov.iov_base);
+	return rc;
+}
+
+int
+smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+	   const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
+	   const __u32 num_lock, struct smb2_lock_element *buf)
+{
+	int rc = 0;
+	struct smb2_lock_req *req = NULL;
+	struct kvec iov[2];
+	int resp_buf_type;
+	unsigned int count;
+
+	cFYI(1, "smb2_lockv num lock %d", num_lock);
+
+	rc = small_smb2_init(SMB2_LOCK, tcon, (void **) &req);
+	if (rc)
+		return rc;
+
+	req->hdr.ProcessId = cpu_to_le32(pid);
+	req->LockCount = cpu_to_le16(num_lock);
+
+	req->PersistentFileId = persist_fid;
+	req->VolatileFileId = volatile_fid;
+
+	count = num_lock * sizeof(struct smb2_lock_element);
+	inc_rfc1001_len(req, count - sizeof(struct smb2_lock_element));
+
+	iov[0].iov_base = (char *)req;
+	/* 4 for rfc1002 length field and count for all locks */
+	iov[0].iov_len = get_rfc1002_length(req) + 4 - count;
+	iov[1].iov_base = (char *)buf;
+	iov[1].iov_len = count;
+
+	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
+	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+	if (rc) {
+		cFYI(1, "Send error in smb2_lockv = %d", rc);
+		cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
+	}
+
+	return rc;
+}
+
+int
+SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
+	  const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
+	  const __u64 length, const __u64 offset, const __u32 lock_flags,
+	  const bool wait)
+{
+	struct smb2_lock_element lock;
+
+	lock.Offset = cpu_to_le64(offset);
+	lock.Length = cpu_to_le64(length);
+	lock.Flags = cpu_to_le32(lock_flags);
+	if (!wait && lock_flags != SMB2_LOCKFLAG_UNLOCK)
+		lock.Flags |= cpu_to_le32(SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
+
+	return smb2_lockv(xid, tcon, persist_fid, volatile_fid, pid, 1, &lock);
+}
+
+int
+SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
+		 __u8 *lease_key, const __le32 lease_state)
+{
+	int rc;
+	struct smb2_lease_ack *req = NULL;
+
+	cFYI(1, "SMB2_lease_break");
+	rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+
+	if (rc)
+		return rc;
+
+	req->hdr.CreditRequest = cpu_to_le16(1);
+	req->StructureSize = cpu_to_le16(36);
+	inc_rfc1001_len(req, 12);
+
+	memcpy(req->LeaseKey, lease_key, 16);
+	req->LeaseState = lease_state;
+
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
+	/* SMB2 buffer freed by function above */
+
+	if (rc) {
+		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+		cFYI(1, "Send error in Lease Break = %d", rc);
+	}
+
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 15dc8ee..4cb4ced 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -150,6 +150,10 @@
 	__u8   ErrorData[1];  /* variable length */
 } __packed;
 
+#define SMB2_CLIENT_GUID_SIZE 16
+
+extern __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
+
 struct smb2_negotiate_req {
 	struct smb2_hdr hdr;
 	__le16 StructureSize; /* Must be 36 */
@@ -157,11 +161,17 @@
 	__le16 SecurityMode;
 	__le16 Reserved;	/* MBZ */
 	__le32 Capabilities;
-	__u8   ClientGUID[16];	/* MBZ */
+	__u8   ClientGUID[SMB2_CLIENT_GUID_SIZE];
 	__le64 ClientStartTime;	/* MBZ */
-	__le16 Dialects[2]; /* variable length */
+	__le16 Dialects[1]; /* One dialect (vers=) at a time for now */
 } __packed;
 
+/* Dialects */
+#define SMB20_PROT_ID 0x0202
+#define SMB21_PROT_ID 0x0210
+#define SMB30_PROT_ID 0x0300
+#define BAD_PROT_ID   0xFFFF
+
 /* SecurityMode flags */
 #define	SMB2_NEGOTIATE_SIGNING_ENABLED	0x0001
 #define SMB2_NEGOTIATE_SIGNING_REQUIRED	0x0002
@@ -169,6 +179,10 @@
 #define SMB2_GLOBAL_CAP_DFS		0x00000001
 #define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
 #define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
+#define SMB2_GLOBAL_CAP_MULTI_CHANNEL	0x00000008 /* New to SMB3 */
+#define SMB2_GLOBAL_CAP_PERSISTENT_HANDLES 0x00000010 /* New to SMB3 */
+#define SMB2_GLOBAL_CAP_DIRECTORY_LEASING  0x00000020 /* New to SMB3 */
+#define SMB2_GLOBAL_CAP_ENCRYPTION	0x00000040 /* New to SMB3 */
 /* Internal types */
 #define SMB2_NT_FIND			0x00100000
 #define SMB2_LARGE_FILES		0x00200000
@@ -307,6 +321,8 @@
 #define SMB2_OPLOCK_LEVEL_EXCLUSIVE	0x08
 #define SMB2_OPLOCK_LEVEL_BATCH		0x09
 #define SMB2_OPLOCK_LEVEL_LEASE		0xFF
+/* Non-spec internal type */
+#define SMB2_OPLOCK_LEVEL_NOCHANGE	0x99
 
 /* Desired Access Flags */
 #define FILE_READ_DATA_LE		cpu_to_le32(0x00000001)
@@ -404,7 +420,7 @@
 	__le16 NameLength;
 	__le32 CreateContextsOffset;
 	__le32 CreateContextsLength;
-	__u8   Buffer[1];
+	__u8   Buffer[8];
 } __packed;
 
 struct smb2_create_rsp {
@@ -428,6 +444,39 @@
 	__u8   Buffer[1];
 } __packed;
 
+struct create_context {
+	__le32 Next;
+	__le16 NameOffset;
+	__le16 NameLength;
+	__le16 Reserved;
+	__le16 DataOffset;
+	__le32 DataLength;
+	__u8 Buffer[0];
+} __packed;
+
+#define SMB2_LEASE_NONE			__constant_cpu_to_le32(0x00)
+#define SMB2_LEASE_READ_CACHING		__constant_cpu_to_le32(0x01)
+#define SMB2_LEASE_HANDLE_CACHING	__constant_cpu_to_le32(0x02)
+#define SMB2_LEASE_WRITE_CACHING	__constant_cpu_to_le32(0x04)
+
+#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS __constant_cpu_to_le32(0x02)
+
+#define SMB2_LEASE_KEY_SIZE 16
+
+struct lease_context {
+	__le64 LeaseKeyLow;
+	__le64 LeaseKeyHigh;
+	__le32 LeaseState;
+	__le32 LeaseFlags;
+	__le64 LeaseDuration;
+} __packed;
+
+struct create_lease {
+	struct create_context ccontext;
+	__u8   Name[8];
+	struct lease_context lcontext;
+} __packed;
+
 /* Currently defined values for close flags */
 #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB	cpu_to_le16(0x0001)
 struct smb2_close_req {
@@ -453,6 +502,108 @@
 	__le32 Attributes;
 } __packed;
 
+struct smb2_flush_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;	/* Must be 24 */
+	__le16 Reserved1;
+	__le32 Reserved2;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+} __packed;
+
+struct smb2_flush_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;
+	__le16 Reserved;
+} __packed;
+
+struct smb2_read_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 49 */
+	__u8   Padding; /* offset from start of SMB2 header to place read */
+	__u8   Reserved;
+	__le32 Length;
+	__le64 Offset;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le32 MinimumCount;
+	__le32 Channel; /* Reserved MBZ */
+	__le32 RemainingBytes;
+	__le16 ReadChannelInfoOffset; /* Reserved MBZ */
+	__le16 ReadChannelInfoLength; /* Reserved MBZ */
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_read_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 17 */
+	__u8   DataOffset;
+	__u8   Reserved;
+	__le32 DataLength;
+	__le32 DataRemaining;
+	__u32  Reserved2;
+	__u8   Buffer[1];
+} __packed;
+
+/* For write request Flags field below the following flag is defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+struct smb2_write_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 49 */
+	__le16 DataOffset; /* offset from start of SMB2 header to write data */
+	__le32 Length;
+	__le64 Offset;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le32 Channel; /* Reserved MBZ */
+	__le32 RemainingBytes;
+	__le16 WriteChannelInfoOffset; /* Reserved MBZ */
+	__le16 WriteChannelInfoLength; /* Reserved MBZ */
+	__le32 Flags;
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_write_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 17 */
+	__u8   DataOffset;
+	__u8   Reserved;
+	__le32 DataLength;
+	__le32 DataRemaining;
+	__u32  Reserved2;
+	__u8   Buffer[1];
+} __packed;
+
+#define SMB2_LOCKFLAG_SHARED_LOCK	0x0001
+#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK	0x0002
+#define SMB2_LOCKFLAG_UNLOCK		0x0004
+#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY	0x0010
+
+struct smb2_lock_element {
+	__le64 Offset;
+	__le64 Length;
+	__le32 Flags;
+	__le32 Reserved;
+} __packed;
+
+struct smb2_lock_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 48 */
+	__le16 LockCount;
+	__le32 Reserved;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	/* Followed by at least one */
+	struct smb2_lock_element locks[1];
+} __packed;
+
+struct smb2_lock_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 4 */
+	__le16 Reserved;
+} __packed;
+
 struct smb2_echo_req {
 	struct smb2_hdr hdr;
 	__le16 StructureSize;	/* Must be 4 */
@@ -465,6 +616,34 @@
 	__u16  Reserved;
 } __packed;
 
+/* search (query_directory) Flags field */
+#define SMB2_RESTART_SCANS		0x01
+#define SMB2_RETURN_SINGLE_ENTRY	0x02
+#define SMB2_INDEX_SPECIFIED		0x04
+#define SMB2_REOPEN			0x10
+
+struct smb2_query_directory_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 33 */
+	__u8   FileInformationClass;
+	__u8   Flags;
+	__le32 FileIndex;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__le16 FileNameOffset;
+	__le16 FileNameLength;
+	__le32 OutputBufferLength;
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_query_directory_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 9 */
+	__le16 OutputBufferOffset;
+	__le32 OutputBufferLength;
+	__u8   Buffer[1];
+} __packed;
+
 /* Possible InfoType values */
 #define SMB2_O_INFO_FILE	0x01
 #define SMB2_O_INFO_FILESYSTEM	0x02
@@ -495,11 +674,84 @@
 	__u8   Buffer[1];
 } __packed;
 
+struct smb2_set_info_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 33 */
+	__u8   InfoType;
+	__u8   FileInfoClass;
+	__le32 BufferLength;
+	__le16 BufferOffset;
+	__u16  Reserved;
+	__le32 AdditionalInformation;
+	__u64  PersistentFileId; /* opaque endianness */
+	__u64  VolatileFileId; /* opaque endianness */
+	__u8   Buffer[1];
+} __packed;
+
+struct smb2_set_info_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 2 */
+} __packed;
+
+struct smb2_oplock_break {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 24 */
+	__u8   OplockLevel;
+	__u8   Reserved;
+	__le32 Reserved2;
+	__u64  PersistentFid;
+	__u64  VolatileFid;
+} __packed;
+
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED cpu_to_le32(0x01)
+
+struct smb2_lease_break {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 44 */
+	__le16 Reserved;
+	__le32 Flags;
+	__u8   LeaseKey[16];
+	__le32 CurrentLeaseState;
+	__le32 NewLeaseState;
+	__le32 BreakReason;
+	__le32 AccessMaskHint;
+	__le32 ShareMaskHint;
+} __packed;
+
+struct smb2_lease_ack {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 36 */
+	__le16 Reserved;
+	__le32 Flags;
+	__u8   LeaseKey[16];
+	__le32 LeaseState;
+	__le64 LeaseDuration;
+} __packed;
+
 /*
  *	PDU infolevel structure definitions
  *	BB consider moving to a different header
  */
 
+/* File System Information Classes */
+#define FS_VOLUME_INFORMATION		1 /* Query */
+#define FS_LABEL_INFORMATION		2 /* Set */
+#define FS_SIZE_INFORMATION		3 /* Query */
+#define FS_DEVICE_INFORMATION		4 /* Query */
+#define FS_ATTRIBUTE_INFORMATION	5 /* Query */
+#define FS_CONTROL_INFORMATION		6 /* Query, Set */
+#define FS_FULL_SIZE_INFORMATION	7 /* Query */
+#define FS_OBJECT_ID_INFORMATION	8 /* Query, Set */
+#define FS_DRIVER_PATH_INFORMATION	9 /* Query */
+
+struct smb2_fs_full_size_info {
+	__le64 TotalAllocationUnits;
+	__le64 CallerAvailableAllocationUnits;
+	__le64 ActualAvailableAllocationUnits;
+	__le32 SectorsPerAllocationUnit;
+	__le32 BytesPerSector;
+} __packed;
+
 /* partial list of QUERY INFO levels */
 #define FILE_DIRECTORY_INFORMATION	1
 #define FILE_FULL_DIRECTORY_INFORMATION 2
@@ -548,6 +800,28 @@
 #define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
 #define FILE_STANDARD_LINK_INFORMATION	54
 
+struct smb2_file_internal_info {
+	__le64 IndexNumber;
+} __packed; /* level 6 Query */
+
+struct smb2_file_rename_info { /* encoding of request for level 10 */
+	__u8   ReplaceIfExists; /* 1 = replace existing target with new */
+				/* 0 = fail if target already exists */
+	__u8   Reserved[7];
+	__u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+	__le32 FileNameLength;
+	char   FileName[0];     /* New name to be assigned */
+} __packed; /* level 10 Set */
+
+struct smb2_file_link_info { /* encoding of request for level 11 */
+	__u8   ReplaceIfExists; /* 1 = replace existing link with new */
+				/* 0 = fail if link already exists */
+	__u8   Reserved[7];
+	__u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+	__le32 FileNameLength;
+	char   FileName[0];     /* Name to be assigned to new link */
+} __packed; /* level 11 Set */
+
 /*
  * This level 18, although with struct with same name is different from cifs
  * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
@@ -576,4 +850,8 @@
 	char   FileName[1];
 } __packed; /* level 18 Query */
 
+struct smb2_file_eof_info { /* encoding of request for level 10 */
+	__le64 EndOfFile; /* new end of file value */
+} __packed; /* level 20 Set */
+
 #endif				/* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index bfaa7b1..7d25f8b 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -26,6 +26,7 @@
 #include <linux/key-type.h>
 
 struct statfs;
+struct smb_rqst;
 
 /*
  *****************************************************************
@@ -34,24 +35,35 @@
  */
 extern int map_smb2_to_linux_error(char *buf, bool log_err);
 extern int smb2_check_message(char *buf, unsigned int length);
-extern unsigned int smb2_calc_size(struct smb2_hdr *hdr);
+extern unsigned int smb2_calc_size(void *buf);
 extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
 					  struct cifs_sb_info *cifs_sb);
 
+extern int smb2_verify_signature(struct smb_rqst *, struct TCP_Server_Info *);
 extern int smb2_check_receive(struct mid_q_entry *mid,
 			      struct TCP_Server_Info *server, bool log_error);
-extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
-			      unsigned int nvec, struct mid_q_entry **ret_mid);
-extern int smb2_setup_async_request(struct TCP_Server_Info *server,
-				    struct kvec *iov, unsigned int nvec,
-				    struct mid_q_entry **ret_mid);
+extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
+			      struct smb_rqst *rqst);
+extern struct mid_q_entry *smb2_setup_async_request(
+			struct TCP_Server_Info *server, struct smb_rqst *rqst);
 extern void smb2_echo_request(struct work_struct *work);
+extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
+extern __u8 smb2_map_lease_to_oplock(__le32 lease_state);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+				       struct TCP_Server_Info *srv);
 
+extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
+				   struct smb2_file_all_info *src);
 extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,
 				bool *adjust_tz);
+extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+			      const char *full_path, __u64 size,
+			      struct cifs_sb_info *cifs_sb, bool set_alloc);
+extern int smb2_set_file_info(struct inode *inode, const char *full_path,
+			      FILE_BASIC_INFO *buf, const unsigned int xid);
 extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -59,6 +71,24 @@
 			       struct cifs_tcon *tcon, const unsigned int xid);
 extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
+		       const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+			    const char *from_name, const char *to_name,
+			    struct cifs_sb_info *cifs_sb);
+extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+				const char *from_name, const char *to_name,
+				struct cifs_sb_info *cifs_sb);
+
+extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
+			  const char *full_path, int disposition,
+			  int desired_access, int create_options,
+			  struct cifs_fid *fid, __u32 *oplock,
+			  FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
+extern int smb2_unlock_range(struct cifsFileInfo *cfile,
+			     struct file_lock *flock, const unsigned int xid);
+extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
@@ -75,12 +105,55 @@
 extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
 		     __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
 		     __u32 desired_access, __u32 create_disposition,
-		     __u32 file_attributes, __u32 create_options);
+		     __u32 file_attributes, __u32 create_options,
+		     __u8 *oplock, struct smb2_file_all_info *buf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
+extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
+		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 			   u64 persistent_file_id, u64 volatile_file_id,
 			   struct smb2_file_all_info *data);
+extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+			    u64 persistent_fid, u64 volatile_fid,
+			    __le64 *uniqueid);
+extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+		     unsigned int *nbytes, char **buf, int *buf_type);
+extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+		      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+				u64 persistent_fid, u64 volatile_fid, int index,
+				struct cifs_search_info *srch_inf);
+extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+		       u64 persistent_fid, u64 volatile_fid,
+		       __le16 *target_file);
+extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+			     u64 persistent_fid, u64 volatile_fid,
+			     __le16 *target_file);
+extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
+			u64 persistent_fid, u64 volatile_fid, u32 pid,
+			__le64 *eof);
+extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+			 u64 persistent_fid, u64 volatile_fid,
+			 FILE_BASIC_INFO *buf);
+extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+			     const u64 persistent_fid, const u64 volatile_fid,
+			     const __u8 oplock_level);
+extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+			 u64 persistent_file_id, u64 volatile_file_id,
+			 struct kstatfs *FSData);
+extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
+		     const __u64 persist_fid, const __u64 volatile_fid,
+		     const __u32 pid, const __u64 length, const __u64 offset,
+		     const __u32 lockFlags, const bool wait);
+extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+		      const __u64 persist_fid, const __u64 volatile_fid,
+		      const __u32 pid, const __u32 num_lock,
+		      struct smb2_lock_element *buf);
+extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
+			    __u8 *lease_key, const __le32 lease_state);
 
 #endif			/* _SMB2PROTO_H */
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 31f5d42..2a5fdf2 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -30,12 +30,156 @@
 #include <linux/uaccess.h>
 #include <asm/processor.h>
 #include <linux/mempool.h>
+#include <linux/highmem.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "smb2proto.h"
 #include "cifs_debug.h"
 #include "smb2status.h"
+#include "smb2glob.h"
+
+static int
+smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+{
+	int i, rc;
+	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+	unsigned char *sigptr = smb2_signature;
+	struct kvec *iov = rqst->rq_iov;
+	int n_vec = rqst->rq_nvec;
+	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
+	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+	rc = crypto_shash_setkey(server->secmech.hmacsha256,
+		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+	if (rc) {
+		cERROR(1, "%s: Could not update with response\n", __func__);
+		return rc;
+	}
+
+	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+	if (rc) {
+		cERROR(1, "%s: Could not init md5\n", __func__);
+		return rc;
+	}
+
+	for (i = 0; i < n_vec; i++) {
+		if (iov[i].iov_len == 0)
+			continue;
+		if (iov[i].iov_base == NULL) {
+			cERROR(1, "null iovec entry");
+			return -EIO;
+		}
+		/*
+		 * The first entry includes a length field (which does not get
+		 * signed that occupies the first 4 bytes before the header).
+		 */
+		if (i == 0) {
+			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+				break; /* nothing to sign or corrupt header */
+			rc =
+			crypto_shash_update(
+				&server->secmech.sdeschmacsha256->shash,
+				iov[i].iov_base + 4, iov[i].iov_len - 4);
+		} else {
+			rc =
+			crypto_shash_update(
+				&server->secmech.sdeschmacsha256->shash,
+				iov[i].iov_base, iov[i].iov_len);
+		}
+		if (rc) {
+			cERROR(1, "%s: Could not update with payload\n",
+							__func__);
+			return rc;
+		}
+	}
+
+	/* now hash over the rq_pages array */
+	for (i = 0; i < rqst->rq_npages; i++) {
+		struct kvec p_iov;
+
+		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
+		crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+					p_iov.iov_base, p_iov.iov_len);
+		kunmap(rqst->rq_pages[i]);
+	}
+
+	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+				sigptr);
+	if (rc)
+		cERROR(1, "%s: Could not generate sha256 hash\n", __func__);
+
+	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+	return rc;
+}
+
+/* must be called with server->srv_mutex held */
+static int
+smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+{
+	int rc = 0;
+	struct smb2_hdr *smb2_pdu = rqst->rq_iov[0].iov_base;
+
+	if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+	    server->tcpStatus == CifsNeedNegotiate)
+		return rc;
+
+	if (!server->session_estab) {
+		strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+		return rc;
+	}
+
+	rc = smb2_calc_signature(rqst, server);
+
+	return rc;
+}
+
+int
+smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+{
+	unsigned int rc;
+	char server_response_sig[16];
+	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+
+	if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
+	    (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+	    (!server->session_estab))
+		return 0;
+
+	/*
+	 * BB what if signatures are supposed to be on for session but
+	 * server does not send one? BB
+	 */
+
+	/* Do not need to verify session setups with signature "BSRSPYL " */
+	if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+		cFYI(1, "dummy signature received for smb command 0x%x",
+			smb2_pdu->Command);
+
+	/*
+	 * Save off the origiginal signature so we can modify the smb and check
+	 * our calculated signature against what the server sent.
+	 */
+	memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+
+	memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+
+	mutex_lock(&server->srv_mutex);
+	rc = smb2_calc_signature(rqst, server);
+	mutex_unlock(&server->srv_mutex);
+
+	if (rc)
+		return rc;
+
+	if (memcmp(server_response_sig, smb2_pdu->Signature,
+		   SMB2_SIGNATURE_SIZE))
+		return -EACCES;
+	else
+		return 0;
+}
 
 /*
  * Set message id for the request. Should be called after wait_for_free_request
@@ -115,58 +259,66 @@
 		   bool log_error)
 {
 	unsigned int len = get_rfc1002_length(mid->resp_buf);
+	struct kvec iov;
+	struct smb_rqst rqst = { .rq_iov = &iov,
+				 .rq_nvec = 1 };
+
+	iov.iov_base = (char *)mid->resp_buf;
+	iov.iov_len = get_rfc1002_length(mid->resp_buf) + 4;
 
 	dump_smb(mid->resp_buf, min_t(u32, 80, len));
 	/* convert the length into a more usable form */
-	/* BB - uncomment with SMB2 signing implementation */
-	/* if ((len > 24) &&
+	if ((len > 24) &&
 	    (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
-		if (smb2_verify_signature(mid->resp_buf, server))
-			cERROR(1, "Unexpected SMB signature");
-	} */
+		int rc;
+
+		rc = smb2_verify_signature(&rqst, server);
+		if (rc)
+			cERROR(1, "SMB signature verification returned error = "
+			       "%d", rc);
+	}
 
 	return map_smb2_to_linux_error(mid->resp_buf, log_error);
 }
 
-int
-smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
-		   unsigned int nvec, struct mid_q_entry **ret_mid)
+struct mid_q_entry *
+smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 {
 	int rc;
-	struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
+	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
 	smb2_seq_num_into_buf(ses->server, hdr);
 
 	rc = smb2_get_mid_entry(ses, hdr, &mid);
 	if (rc)
-		return rc;
-	/* rc = smb2_sign_smb2(iov, nvec, ses->server);
-	if (rc)
-		delete_mid(mid); */
-	*ret_mid = mid;
-	return rc;
+		return ERR_PTR(rc);
+	rc = smb2_sign_rqst(rqst, ses->server);
+	if (rc) {
+		cifs_delete_mid(mid);
+		return ERR_PTR(rc);
+	}
+	return mid;
 }
 
-int
-smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
-			 unsigned int nvec, struct mid_q_entry **ret_mid)
+struct mid_q_entry *
+smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
-	int rc = 0;
-	struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
+	int rc;
+	struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
 	smb2_seq_num_into_buf(server, hdr);
 
 	mid = smb2_mid_entry_alloc(hdr, server);
 	if (mid == NULL)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	/* rc = smb2_sign_smb2(iov, nvec, server);
+	rc = smb2_sign_rqst(rqst, server);
 	if (rc) {
 		DeleteMidQEntry(mid);
-		return rc;
-	}*/
-	*ret_mid = mid;
-	return rc;
+		return ERR_PTR(rc);
+	}
+
+	return mid;
 }
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index d9b639b..2126ab1 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -27,6 +27,8 @@
 #include <linux/net.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
+#include <linux/tcp.h>
+#include <linux/highmem.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <linux/mempool.h>
@@ -109,8 +111,8 @@
 	mempool_free(midEntry, cifs_mid_poolp);
 }
 
-static void
-delete_mid(struct mid_q_entry *mid)
+void
+cifs_delete_mid(struct mid_q_entry *mid)
 {
 	spin_lock(&GlobalMid_Lock);
 	list_del(&mid->qhead);
@@ -119,18 +121,29 @@
 	DeleteMidQEntry(mid);
 }
 
+/*
+ * smb_send_kvec - send an array of kvecs to the server
+ * @server:	Server to send the data to
+ * @iov:	Pointer to array of kvecs
+ * @n_vec:	length of kvec array
+ * @sent:	amount of data sent on socket is stored here
+ *
+ * Our basic "send data to server" function. Should be called with srv_mutex
+ * held. The caller is responsible for handling the results.
+ */
 static int
-smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
+smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
+		size_t *sent)
 {
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	unsigned int len = iov[0].iov_len;
-	unsigned int total_len;
-	int first_vec = 0;
-	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+	unsigned int remaining;
+	size_t first_vec = 0;
 	struct socket *ssocket = server->ssocket;
 
+	*sent = 0;
+
 	if (ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
 
@@ -143,56 +156,60 @@
 	else
 		smb_msg.msg_flags = MSG_NOSIGNAL;
 
-	total_len = 0;
+	remaining = 0;
 	for (i = 0; i < n_vec; i++)
-		total_len += iov[i].iov_len;
-
-	cFYI(1, "Sending smb:  total_len %d", total_len);
-	dump_smb(iov[0].iov_base, len);
+		remaining += iov[i].iov_len;
 
 	i = 0;
-	while (total_len) {
+	while (remaining) {
+		/*
+		 * If blocking send, we try 3 times, since each can block
+		 * for 5 seconds. For nonblocking  we have to try more
+		 * but wait increasing amounts of time allowing time for
+		 * socket to clear.  The overall time we wait in either
+		 * case to send on the socket is about 15 seconds.
+		 * Similarly we wait for 15 seconds for a response from
+		 * the server in SendReceive[2] for the server to send
+		 * a response back for most types of requests (except
+		 * SMB Write past end of file which can be slow, and
+		 * blocking lock operations). NFS waits slightly longer
+		 * than CIFS, but this can make it take longer for
+		 * nonresponsive servers to be detected and 15 seconds
+		 * is more than enough time for modern networks to
+		 * send a packet.  In most cases if we fail to send
+		 * after the retries we will kill the socket and
+		 * reconnect which may clear the network problem.
+		 */
 		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
-				    n_vec - first_vec, total_len);
-		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
+				    n_vec - first_vec, remaining);
+		if (rc == -ENOSPC || rc == -EAGAIN) {
 			i++;
-			/*
-			 * If blocking send we try 3 times, since each can block
-			 * for 5 seconds. For nonblocking  we have to try more
-			 * but wait increasing amounts of time allowing time for
-			 * socket to clear.  The overall time we wait in either
-			 * case to send on the socket is about 15 seconds.
-			 * Similarly we wait for 15 seconds for a response from
-			 * the server in SendReceive[2] for the server to send
-			 * a response back for most types of requests (except
-			 * SMB Write past end of file which can be slow, and
-			 * blocking lock operations). NFS waits slightly longer
-			 * than CIFS, but this can make it take longer for
-			 * nonresponsive servers to be detected and 15 seconds
-			 * is more than enough time for modern networks to
-			 * send a packet.  In most cases if we fail to send
-			 * after the retries we will kill the socket and
-			 * reconnect which may clear the network problem.
-			 */
-			if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
-				cERROR(1, "sends on sock %p stuck for 15 seconds",
-				    ssocket);
+			if (i >= 14 || (!server->noblocksnd && (i > 2))) {
+				cERROR(1, "sends on sock %p stuck for 15 "
+					  "seconds", ssocket);
 				rc = -EAGAIN;
 				break;
 			}
 			msleep(1 << i);
 			continue;
 		}
+
 		if (rc < 0)
 			break;
 
-		if (rc == total_len) {
-			total_len = 0;
-			break;
-		} else if (rc > total_len) {
-			cERROR(1, "sent %d requested %d", rc, total_len);
+		/* send was at least partially successful */
+		*sent += rc;
+
+		if (rc == remaining) {
+			remaining = 0;
 			break;
 		}
+
+		if (rc > remaining) {
+			cERROR(1, "sent %d requested %d", rc, remaining);
+			break;
+		}
+
 		if (rc == 0) {
 			/* should never happen, letting socket clear before
 			   retrying is our only obvious option here */
@@ -200,7 +217,9 @@
 			msleep(500);
 			continue;
 		}
-		total_len -= rc;
+
+		remaining -= rc;
+
 		/* the line below resets i */
 		for (i = first_vec; i < n_vec; i++) {
 			if (iov[i].iov_len) {
@@ -215,16 +234,97 @@
 				}
 			}
 		}
+
 		i = 0; /* in case we get ENOSPC on the next send */
+		rc = 0;
+	}
+	return rc;
+}
+
+/**
+ * rqst_page_to_kvec - Turn a slot in the smb_rqst page array into a kvec
+ * @rqst: pointer to smb_rqst
+ * @idx: index into the array of the page
+ * @iov: pointer to struct kvec that will hold the result
+ *
+ * Helper function to convert a slot in the rqst->rq_pages array into a kvec.
+ * The page will be kmapped and the address placed into iov_base. The length
+ * will then be adjusted according to the ptailoff.
+ */
+void
+cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
+			struct kvec *iov)
+{
+	/*
+	 * FIXME: We could avoid this kmap altogether if we used
+	 * kernel_sendpage instead of kernel_sendmsg. That will only
+	 * work if signing is disabled though as sendpage inlines the
+	 * page directly into the fraglist. If userspace modifies the
+	 * page after we calculate the signature, then the server will
+	 * reject it and may break the connection. kernel_sendmsg does
+	 * an extra copy of the data and avoids that issue.
+	 */
+	iov->iov_base = kmap(rqst->rq_pages[idx]);
+
+	/* if last page, don't send beyond this offset into page */
+	if (idx == (rqst->rq_npages - 1))
+		iov->iov_len = rqst->rq_tailsz;
+	else
+		iov->iov_len = rqst->rq_pagesz;
+}
+
+static int
+smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+{
+	int rc;
+	struct kvec *iov = rqst->rq_iov;
+	int n_vec = rqst->rq_nvec;
+	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+	unsigned int i;
+	size_t total_len = 0, sent;
+	struct socket *ssocket = server->ssocket;
+	int val = 1;
+
+	cFYI(1, "Sending smb: smb_len=%u", smb_buf_length);
+	dump_smb(iov[0].iov_base, iov[0].iov_len);
+
+	/* cork the socket */
+	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
+				(char *)&val, sizeof(val));
+
+	rc = smb_send_kvec(server, iov, n_vec, &sent);
+	if (rc < 0)
+		goto uncork;
+
+	total_len += sent;
+
+	/* now walk the page array and send each page in it */
+	for (i = 0; i < rqst->rq_npages; i++) {
+		struct kvec p_iov;
+
+		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
+		rc = smb_send_kvec(server, &p_iov, 1, &sent);
+		kunmap(rqst->rq_pages[i]);
+		if (rc < 0)
+			break;
+
+		total_len += sent;
 	}
 
+uncork:
+	/* uncork it */
+	val = 0;
+	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
+				(char *)&val, sizeof(val));
+
 	if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
-		cFYI(1, "partial send (%d remaining), terminating session",
-			total_len);
-		/* If we have only sent part of an SMB then the next SMB
-		   could be taken as the remainder of this one.  We need
-		   to kill the socket so the server throws away the partial
-		   SMB */
+		cFYI(1, "partial send (wanted=%u sent=%zu): terminating "
+			"session", smb_buf_length + 4, total_len);
+		/*
+		 * If we have only sent part of an SMB then the next SMB could
+		 * be taken as the remainder of this one. We need to kill the
+		 * socket so the server throws away the partial SMB
+		 */
 		server->tcpStatus = CifsNeedReconnect;
 	}
 
@@ -236,6 +336,15 @@
 	return rc;
 }
 
+static int
+smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
+{
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = n_vec };
+
+	return smb_send_rqst(server, &rqst);
+}
+
 int
 smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 	 unsigned int smb_buf_length)
@@ -345,12 +454,11 @@
 	return 0;
 }
 
-int
-cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
-			 unsigned int nvec, struct mid_q_entry **ret_mid)
+struct mid_q_entry *
+cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
 	int rc;
-	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
 	/* enable signing if server requires it */
@@ -359,16 +467,15 @@
 
 	mid = AllocMidQEntry(hdr, server);
 	if (mid == NULL)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	rc = cifs_sign_smbv(iov, nvec, server, &mid->sequence_number);
+	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
 	if (rc) {
 		DeleteMidQEntry(mid);
-		return rc;
+		return ERR_PTR(rc);
 	}
 
-	*ret_mid = mid;
-	return 0;
+	return mid;
 }
 
 /*
@@ -376,9 +483,9 @@
  * the result. Caller is responsible for dealing with timeouts.
  */
 int
-cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
-		unsigned int nvec, mid_receive_t *receive,
-		mid_callback_t *callback, void *cbdata, const int flags)
+cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+		mid_receive_t *receive, mid_callback_t *callback,
+		void *cbdata, const int flags)
 {
 	int rc, timeout, optype;
 	struct mid_q_entry *mid;
@@ -391,12 +498,12 @@
 		return rc;
 
 	mutex_lock(&server->srv_mutex);
-	rc = server->ops->setup_async_request(server, iov, nvec, &mid);
-	if (rc) {
+	mid = server->ops->setup_async_request(server, rqst);
+	if (IS_ERR(mid)) {
 		mutex_unlock(&server->srv_mutex);
 		add_credits(server, 1, optype);
 		wake_up(&server->request_q);
-		return rc;
+		return PTR_ERR(mid);
 	}
 
 	mid->receive = receive;
@@ -411,7 +518,7 @@
 
 
 	cifs_in_send_inc(server);
-	rc = smb_sendv(server, iov, nvec);
+	rc = smb_send_rqst(server, rqst);
 	cifs_in_send_dec(server);
 	cifs_save_when_sent(mid);
 	mutex_unlock(&server->srv_mutex);
@@ -419,7 +526,7 @@
 	if (rc == 0)
 		return 0;
 
-	delete_mid(mid);
+	cifs_delete_mid(mid);
 	add_credits(server, 1, optype);
 	wake_up(&server->request_q);
 	return rc;
@@ -504,11 +611,13 @@
 	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
 		struct kvec iov;
 		int rc = 0;
+		struct smb_rqst rqst = { .rq_iov = &iov,
+					 .rq_nvec = 1 };
 
 		iov.iov_base = mid->resp_buf;
 		iov.iov_len = len;
 		/* FIXME: add code to kill session */
-		rc = cifs_verify_signature(&iov, 1, server,
+		rc = cifs_verify_signature(&rqst, server,
 					   mid->sequence_number + 1);
 		if (rc)
 			cERROR(1, "SMB signature verification returned error = "
@@ -519,22 +628,22 @@
 	return map_smb_to_linux_error(mid->resp_buf, log_error);
 }
 
-int
-cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
-		   unsigned int nvec, struct mid_q_entry **ret_mid)
+struct mid_q_entry *
+cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 {
 	int rc;
-	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct mid_q_entry *mid;
 
 	rc = allocate_mid(ses, hdr, &mid);
 	if (rc)
-		return rc;
-	rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number);
-	if (rc)
-		delete_mid(mid);
-	*ret_mid = mid;
-	return rc;
+		return ERR_PTR(rc);
+	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
+	if (rc) {
+		cifs_delete_mid(mid);
+		return ERR_PTR(rc);
+	}
+	return mid;
 }
 
 int
@@ -547,6 +656,8 @@
 	struct mid_q_entry *midQ;
 	char *buf = iov[0].iov_base;
 	unsigned int credits = 1;
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = n_vec };
 
 	timeout = flags & CIFS_TIMEOUT_MASK;
 	optype = flags & CIFS_OP_MASK;
@@ -584,13 +695,13 @@
 
 	mutex_lock(&ses->server->srv_mutex);
 
-	rc = ses->server->ops->setup_request(ses, iov, n_vec, &midQ);
-	if (rc) {
+	midQ = ses->server->ops->setup_request(ses, &rqst);
+	if (IS_ERR(midQ)) {
 		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(buf);
 		/* Update # of requests on wire to server */
 		add_credits(ses->server, 1, optype);
-		return rc;
+		return PTR_ERR(midQ);
 	}
 
 	midQ->mid_state = MID_REQUEST_SUBMITTED;
@@ -652,11 +763,11 @@
 	rc = ses->server->ops->check_receive(midQ, ses->server,
 					     flags & CIFS_LOG_ERROR);
 
-	/* mark it so buf will not be freed by delete_mid */
+	/* mark it so buf will not be freed by cifs_delete_mid */
 	if ((flags & CIFS_NO_RESP) == 0)
 		midQ->resp_buf = NULL;
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	add_credits(ses->server, credits, optype);
 
 	return rc;
@@ -762,7 +873,7 @@
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	add_credits(ses->server, 1, 0);
 
 	return rc;
@@ -846,7 +957,7 @@
 
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 	if (rc) {
-		delete_mid(midQ);
+		cifs_delete_mid(midQ);
 		mutex_unlock(&ses->server->srv_mutex);
 		return rc;
 	}
@@ -859,7 +970,7 @@
 	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0) {
-		delete_mid(midQ);
+		cifs_delete_mid(midQ);
 		return rc;
 	}
 
@@ -880,7 +991,7 @@
 			   blocking lock to return. */
 			rc = send_cancel(ses->server, in_buf, midQ);
 			if (rc) {
-				delete_mid(midQ);
+				cifs_delete_mid(midQ);
 				return rc;
 			}
 		} else {
@@ -892,7 +1003,7 @@
 			/* If we get -ENOLCK back the lock may have
 			   already been removed. Don't exit in this case. */
 			if (rc && rc != -ENOLCK) {
-				delete_mid(midQ);
+				cifs_delete_mid(midQ);
 				return rc;
 			}
 		}
@@ -929,7 +1040,7 @@
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-	delete_mid(midQ);
+	cifs_delete_mid(midQ);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
 	return rc;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index debdfe0..59f8db4 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -866,6 +866,12 @@
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
 COMPATIBLE_IOCTL(TIOCSIG)
+#ifdef TIOCSRS485
+COMPATIBLE_IOCTL(TIOCSRS485)
+#endif
+#ifdef TIOCGRS485
+COMPATIBLE_IOCTL(TIOCGRS485)
+#endif
 #ifdef TCGETS2
 COMPATIBLE_IOCTL(TCGETS2)
 COMPATIBLE_IOCTL(TCSETS2)
diff --git a/fs/dcache.c b/fs/dcache.c
index 8086636..693f95b 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -389,7 +389,7 @@
 	 * Inform try_to_ascend() that we are no longer attached to the
 	 * dentry tree
 	 */
-	dentry->d_flags |= DCACHE_DISCONNECTED;
+	dentry->d_flags |= DCACHE_DENTRY_KILLED;
 	if (parent)
 		spin_unlock(&parent->d_lock);
 	dentry_iput(dentry);
@@ -1048,7 +1048,7 @@
 	 * or deletion
 	 */
 	if (new != old->d_parent ||
-		 (old->d_flags & DCACHE_DISCONNECTED) ||
+		 (old->d_flags & DCACHE_DENTRY_KILLED) ||
 		 (!locked && read_seqretry(&rename_lock, seq))) {
 		spin_unlock(&new->d_lock);
 		new = NULL;
@@ -1134,6 +1134,8 @@
 	return 1;
 
 rename_retry:
+	if (locked)
+		goto again;
 	locked = 1;
 	write_seqlock(&rename_lock);
 	goto again;
@@ -1141,7 +1143,7 @@
 EXPORT_SYMBOL(have_submounts);
 
 /*
- * Search the dentry child list for the specified parent,
+ * Search the dentry child list of the specified parent,
  * and move any unused dentries to the end of the unused
  * list for prune_dcache(). We descend to the next level
  * whenever the d_subdirs list is non-empty and continue
@@ -1236,6 +1238,8 @@
 rename_retry:
 	if (found)
 		return found;
+	if (locked)
+		goto again;
 	locked = 1;
 	write_seqlock(&rename_lock);
 	goto again;
@@ -3035,6 +3039,8 @@
 	return;
 
 rename_retry:
+	if (locked)
+		goto again;
 	locked = 1;
 	write_seqlock(&rename_lock);
 	goto again;
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 2340f69..c5ca6ae 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -526,73 +526,51 @@
 	u32 elements;
 };
 
-static int u32_array_open(struct inode *inode, struct file *file)
-{
-	file->private_data = NULL;
-	return nonseekable_open(inode, file);
-}
-
-static size_t format_array(char *buf, size_t bufsize, const char *fmt,
-			   u32 *array, u32 array_size)
+static size_t u32_format_array(char *buf, size_t bufsize,
+			       u32 *array, int array_size)
 {
 	size_t ret = 0;
-	u32 i;
 
-	for (i = 0; i < array_size; i++) {
+	while (--array_size >= 0) {
 		size_t len;
+		char term = array_size ? ' ' : '\n';
 
-		len = snprintf(buf, bufsize, fmt, array[i]);
-		len++;	/* ' ' or '\n' */
+		len = snprintf(buf, bufsize, "%u%c", *array++, term);
 		ret += len;
 
-		if (buf) {
-			buf += len;
-			bufsize -= len;
-			buf[-1] = (i == array_size-1) ? '\n' : ' ';
-		}
+		buf += len;
+		bufsize -= len;
 	}
-
-	ret++;		/* \0 */
-	if (buf)
-		*buf = '\0';
-
 	return ret;
 }
 
-static char *format_array_alloc(const char *fmt, u32 *array,
-						u32 array_size)
+static int u32_array_open(struct inode *inode, struct file *file)
 {
-	size_t len = format_array(NULL, 0, fmt, array, array_size);
-	char *ret;
+	struct array_data *data = inode->i_private;
+	int size, elements = data->elements;
+	char *buf;
 
-	ret = kmalloc(len, GFP_KERNEL);
-	if (ret == NULL)
-		return NULL;
+	/*
+	 * Max size:
+	 *  - 10 digits + ' '/'\n' = 11 bytes per number
+	 *  - terminating NUL character
+	 */
+	size = elements*11;
+	buf = kmalloc(size+1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	buf[size] = 0;
 
-	format_array(ret, len, fmt, array, array_size);
-	return ret;
+	file->private_data = buf;
+	u32_format_array(buf, size, data->array, data->elements);
+
+	return nonseekable_open(inode, file);
 }
 
 static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
 			      loff_t *ppos)
 {
-	struct inode *inode = file->f_path.dentry->d_inode;
-	struct array_data *data = inode->i_private;
-	size_t size;
-
-	if (*ppos == 0) {
-		if (file->private_data) {
-			kfree(file->private_data);
-			file->private_data = NULL;
-		}
-
-		file->private_data = format_array_alloc("%u", data->array,
-							      data->elements);
-	}
-
-	size = 0;
-	if (file->private_data)
-		size = strlen(file->private_data);
+	size_t size = strlen(file->private_data);
 
 	return simple_read_from_buffer(buf, len, ppos,
 					file->private_data, size);
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 4733eab..6393fd6 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -28,7 +28,7 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 
-#define DEBUGFS_DEFAULT_MODE	0755
+#define DEBUGFS_DEFAULT_MODE	0700
 
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
@@ -291,9 +291,9 @@
 	.kill_sb =	kill_litter_super,
 };
 
-struct dentry *__create_file(const char *name, umode_t mode,
-				   struct dentry *parent, void *data,
-				   const struct file_operations *fops)
+static struct dentry *__create_file(const char *name, umode_t mode,
+				    struct dentry *parent, void *data,
+				    const struct file_operations *fops)
 {
 	struct dentry *dentry = NULL;
 	int error;
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index 63dc19c..27a6ba9 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -15,8 +15,8 @@
 #include "lock.h"
 #include "user.h"
 
-static uint64_t			dlm_cb_seq;
-static spinlock_t		dlm_cb_seq_spin;
+static uint64_t dlm_cb_seq;
+static DEFINE_SPINLOCK(dlm_cb_seq_spin);
 
 static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
 {
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 9ccf734..a0387dd 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -750,6 +750,7 @@
 static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
 {
 	struct sockaddr_storage *addr;
+	int rv;
 
 	if (len != sizeof(struct sockaddr_storage))
 		return -EINVAL;
@@ -762,6 +763,13 @@
 		return -ENOMEM;
 
 	memcpy(addr, buf, len);
+
+	rv = dlm_lowcomms_addr(cm->nodeid, addr, len);
+	if (rv) {
+		kfree(addr);
+		return rv;
+	}
+
 	cm->addr[cm->addr_count++] = addr;
 	return len;
 }
@@ -878,34 +886,7 @@
 	config_item_put(&sp->group.cg_item);
 }
 
-static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
-{
-	switch (x->ss_family) {
-	case AF_INET: {
-		struct sockaddr_in *sinx = (struct sockaddr_in *)x;
-		struct sockaddr_in *siny = (struct sockaddr_in *)y;
-		if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
-			return 0;
-		if (sinx->sin_port != siny->sin_port)
-			return 0;
-		break;
-	}
-	case AF_INET6: {
-		struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
-		struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
-		if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
-			return 0;
-		if (sinx->sin6_port != siny->sin6_port)
-			return 0;
-		break;
-	}
-	default:
-		return 0;
-	}
-	return 1;
-}
-
-static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
+static struct dlm_comm *get_comm(int nodeid)
 {
 	struct config_item *i;
 	struct dlm_comm *cm = NULL;
@@ -919,19 +900,11 @@
 	list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
 		cm = config_item_to_comm(i);
 
-		if (nodeid) {
-			if (cm->nodeid != nodeid)
-				continue;
-			found = 1;
-			config_item_get(i);
-			break;
-		} else {
-			if (!cm->addr_count || !addr_compare(cm->addr[0], addr))
-				continue;
-			found = 1;
-			config_item_get(i);
-			break;
-		}
+		if (cm->nodeid != nodeid)
+			continue;
+		found = 1;
+		config_item_get(i);
+		break;
 	}
 	mutex_unlock(&clusters_root.subsys.su_mutex);
 
@@ -995,7 +968,7 @@
 
 int dlm_comm_seq(int nodeid, uint32_t *seq)
 {
-	struct dlm_comm *cm = get_comm(nodeid, NULL);
+	struct dlm_comm *cm = get_comm(nodeid);
 	if (!cm)
 		return -EEXIST;
 	*seq = cm->seq;
@@ -1003,28 +976,6 @@
 	return 0;
 }
 
-int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
-{
-	struct dlm_comm *cm = get_comm(nodeid, NULL);
-	if (!cm)
-		return -EEXIST;
-	if (!cm->addr_count)
-		return -ENOENT;
-	memcpy(addr, cm->addr[0], sizeof(*addr));
-	put_comm(cm);
-	return 0;
-}
-
-int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
-{
-	struct dlm_comm *cm = get_comm(0, addr);
-	if (!cm)
-		return -EEXIST;
-	*nodeid = cm->nodeid;
-	put_comm(cm);
-	return 0;
-}
-
 int dlm_our_nodeid(void)
 {
 	return local_comm ? local_comm->nodeid : 0;
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index dbd35a0..f30697b 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -46,8 +46,6 @@
 int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
 		     int *count_out);
 int dlm_comm_seq(int nodeid, uint32_t *seq);
-int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
-int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
 int dlm_our_nodeid(void);
 int dlm_our_addr(struct sockaddr_storage *addr, int num);
 
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 9d3e485..871c1ab 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -604,6 +604,7 @@
 	struct idr		ls_recover_idr;
 	spinlock_t		ls_recover_idr_lock;
 	wait_queue_head_t	ls_wait_general;
+	wait_queue_head_t	ls_recover_lock_wait;
 	struct mutex		ls_clear_proc_locks;
 
 	struct list_head	ls_root_list;	/* root resources */
@@ -616,15 +617,40 @@
 	char			ls_name[1];
 };
 
-#define LSFL_WORK		0
-#define LSFL_RUNNING		1
-#define LSFL_RECOVERY_STOP	2
-#define LSFL_RCOM_READY		3
-#define LSFL_RCOM_WAIT		4
-#define LSFL_UEVENT_WAIT	5
-#define LSFL_TIMEWARN		6
-#define LSFL_CB_DELAY		7
-#define LSFL_NODIR		8
+/*
+ * LSFL_RECOVER_STOP - dlm_ls_stop() sets this to tell dlm recovery routines
+ * that they should abort what they're doing so new recovery can be started.
+ *
+ * LSFL_RECOVER_DOWN - dlm_ls_stop() sets this to tell dlm_recoverd that it
+ * should do down_write() on the in_recovery rw_semaphore. (doing down_write
+ * within dlm_ls_stop causes complaints about the lock acquired/released
+ * in different contexts.)
+ *
+ * LSFL_RECOVER_LOCK - dlm_recoverd holds the in_recovery rw_semaphore.
+ * It sets this after it is done with down_write() on the in_recovery
+ * rw_semaphore and clears it after it has released the rw_semaphore.
+ *
+ * LSFL_RECOVER_WORK - dlm_ls_start() sets this to tell dlm_recoverd that it
+ * should begin recovery of the lockspace.
+ *
+ * LSFL_RUNNING - set when normal locking activity is enabled.
+ * dlm_ls_stop() clears this to tell dlm locking routines that they should
+ * quit what they are doing so recovery can run.  dlm_recoverd sets
+ * this after recovery is finished.
+ */
+
+#define LSFL_RECOVER_STOP	0
+#define LSFL_RECOVER_DOWN	1
+#define LSFL_RECOVER_LOCK	2
+#define LSFL_RECOVER_WORK	3
+#define LSFL_RUNNING		4
+
+#define LSFL_RCOM_READY		5
+#define LSFL_RCOM_WAIT		6
+#define LSFL_UEVENT_WAIT	7
+#define LSFL_TIMEWARN		8
+#define LSFL_CB_DELAY		9
+#define LSFL_NODIR		10
 
 /* much of this is just saving user space pointers associated with the
    lock that we pass back to the user lib with an ast */
@@ -667,7 +693,7 @@
 
 static inline int dlm_recovery_stopped(struct dlm_ls *ls)
 {
-	return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	return test_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
 }
 
 static inline int dlm_no_directory(struct dlm_ls *ls)
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 952557d..2e99fb0 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -582,8 +582,6 @@
 	INIT_LIST_HEAD(&ls->ls_root_list);
 	init_rwsem(&ls->ls_root_sem);
 
-	down_write(&ls->ls_in_recovery);
-
 	spin_lock(&lslist_lock);
 	ls->ls_create_count = 1;
 	list_add(&ls->ls_list, &lslist);
@@ -597,13 +595,24 @@
 		}
 	}
 
-	/* needs to find ls in lslist */
+	init_waitqueue_head(&ls->ls_recover_lock_wait);
+
+	/*
+	 * Once started, dlm_recoverd first looks for ls in lslist, then
+	 * initializes ls_in_recovery as locked in "down" mode.  We need
+	 * to wait for the wakeup from dlm_recoverd because in_recovery
+	 * has to start out in down mode.
+	 */
+
 	error = dlm_recoverd_start(ls);
 	if (error) {
 		log_error(ls, "can't start dlm_recoverd %d", error);
 		goto out_callback;
 	}
 
+	wait_event(ls->ls_recover_lock_wait,
+		   test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
+
 	ls->ls_kobj.kset = dlm_kset;
 	error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
 				     "%s", ls->ls_name);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 5c1b0e3..331ea4f 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -140,6 +140,16 @@
 	struct connection *con;
 };
 
+struct dlm_node_addr {
+	struct list_head list;
+	int nodeid;
+	int addr_count;
+	struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+};
+
+static LIST_HEAD(dlm_node_addrs);
+static DEFINE_SPINLOCK(dlm_node_addrs_spin);
+
 static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
 static int dlm_local_count;
 static int dlm_allow_conn;
@@ -264,31 +274,146 @@
 	return NULL;
 }
 
-static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+static struct dlm_node_addr *find_node_addr(int nodeid)
 {
-	struct sockaddr_storage addr;
-	int error;
+	struct dlm_node_addr *na;
+
+	list_for_each_entry(na, &dlm_node_addrs, list) {
+		if (na->nodeid == nodeid)
+			return na;
+	}
+	return NULL;
+}
+
+static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
+{
+	switch (x->ss_family) {
+	case AF_INET: {
+		struct sockaddr_in *sinx = (struct sockaddr_in *)x;
+		struct sockaddr_in *siny = (struct sockaddr_in *)y;
+		if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
+			return 0;
+		if (sinx->sin_port != siny->sin_port)
+			return 0;
+		break;
+	}
+	case AF_INET6: {
+		struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
+		struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
+		if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
+			return 0;
+		if (sinx->sin6_port != siny->sin6_port)
+			return 0;
+		break;
+	}
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
+			  struct sockaddr *sa_out)
+{
+	struct sockaddr_storage sas;
+	struct dlm_node_addr *na;
 
 	if (!dlm_local_count)
 		return -1;
 
-	error = dlm_nodeid_to_addr(nodeid, &addr);
-	if (error)
-		return error;
+	spin_lock(&dlm_node_addrs_spin);
+	na = find_node_addr(nodeid);
+	if (na && na->addr_count)
+		memcpy(&sas, na->addr[0], sizeof(struct sockaddr_storage));
+	spin_unlock(&dlm_node_addrs_spin);
+
+	if (!na)
+		return -EEXIST;
+
+	if (!na->addr_count)
+		return -ENOENT;
+
+	if (sas_out)
+		memcpy(sas_out, &sas, sizeof(struct sockaddr_storage));
+
+	if (!sa_out)
+		return 0;
 
 	if (dlm_local_addr[0]->ss_family == AF_INET) {
-		struct sockaddr_in *in4  = (struct sockaddr_in *) &addr;
-		struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+		struct sockaddr_in *in4  = (struct sockaddr_in *) &sas;
+		struct sockaddr_in *ret4 = (struct sockaddr_in *) sa_out;
 		ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
 	} else {
-		struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;
-		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+		struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &sas;
+		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) sa_out;
 		ret6->sin6_addr = in6->sin6_addr;
 	}
 
 	return 0;
 }
 
+static int addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
+{
+	struct dlm_node_addr *na;
+	int rv = -EEXIST;
+
+	spin_lock(&dlm_node_addrs_spin);
+	list_for_each_entry(na, &dlm_node_addrs, list) {
+		if (!na->addr_count)
+			continue;
+
+		if (!addr_compare(na->addr[0], addr))
+			continue;
+
+		*nodeid = na->nodeid;
+		rv = 0;
+		break;
+	}
+	spin_unlock(&dlm_node_addrs_spin);
+	return rv;
+}
+
+int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len)
+{
+	struct sockaddr_storage *new_addr;
+	struct dlm_node_addr *new_node, *na;
+
+	new_node = kzalloc(sizeof(struct dlm_node_addr), GFP_NOFS);
+	if (!new_node)
+		return -ENOMEM;
+
+	new_addr = kzalloc(sizeof(struct sockaddr_storage), GFP_NOFS);
+	if (!new_addr) {
+		kfree(new_node);
+		return -ENOMEM;
+	}
+
+	memcpy(new_addr, addr, len);
+
+	spin_lock(&dlm_node_addrs_spin);
+	na = find_node_addr(nodeid);
+	if (!na) {
+		new_node->nodeid = nodeid;
+		new_node->addr[0] = new_addr;
+		new_node->addr_count = 1;
+		list_add(&new_node->list, &dlm_node_addrs);
+		spin_unlock(&dlm_node_addrs_spin);
+		return 0;
+	}
+
+	if (na->addr_count >= DLM_MAX_ADDR_COUNT) {
+		spin_unlock(&dlm_node_addrs_spin);
+		kfree(new_addr);
+		kfree(new_node);
+		return -ENOSPC;
+	}
+
+	na->addr[na->addr_count++] = new_addr;
+	spin_unlock(&dlm_node_addrs_spin);
+	kfree(new_node);
+	return 0;
+}
+
 /* Data available on socket or listen socket received a connect */
 static void lowcomms_data_ready(struct sock *sk, int count_unused)
 {
@@ -348,7 +473,7 @@
 }
 
 /* Make a socket active */
-static int add_sock(struct socket *sock, struct connection *con)
+static void add_sock(struct socket *sock, struct connection *con)
 {
 	con->sock = sock;
 
@@ -358,7 +483,6 @@
 	con->sock->sk->sk_state_change = lowcomms_state_change;
 	con->sock->sk->sk_user_data = con;
 	con->sock->sk->sk_allocation = GFP_NOFS;
-	return 0;
 }
 
 /* Add the port number to an IPv6 or 4 sockaddr and return the address
@@ -510,7 +634,7 @@
 				return;
 			}
 			make_sockaddr(&prim.ssp_addr, 0, &addr_len);
-			if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+			if (addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
 				unsigned char *b=(unsigned char *)&prim.ssp_addr;
 				log_print("reject connect from unknown addr");
 				print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE, 
@@ -747,7 +871,7 @@
 
 	/* Get the new node's NODEID */
 	make_sockaddr(&peeraddr, 0, &len);
-	if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
+	if (addr_to_nodeid(&peeraddr, &nodeid)) {
 		unsigned char *b=(unsigned char *)&peeraddr;
 		log_print("connect from non cluster node");
 		print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE, 
@@ -862,7 +986,7 @@
 	if (con->retries++ > MAX_CONNECT_RETRIES)
 		return;
 
-	if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&rem_addr)) {
+	if (nodeid_to_addr(con->nodeid, NULL, (struct sockaddr *)&rem_addr)) {
 		log_print("no address for nodeid %d", con->nodeid);
 		return;
 	}
@@ -928,11 +1052,11 @@
 /* Connect a new socket to its peer */
 static void tcp_connect_to_sock(struct connection *con)
 {
-	int result = -EHOSTUNREACH;
 	struct sockaddr_storage saddr, src_addr;
 	int addr_len;
 	struct socket *sock = NULL;
 	int one = 1;
+	int result;
 
 	if (con->nodeid == 0) {
 		log_print("attempt to connect sock 0 foiled");
@@ -944,10 +1068,8 @@
 		goto out;
 
 	/* Some odd races can cause double-connects, ignore them */
-	if (con->sock) {
-		result = 0;
+	if (con->sock)
 		goto out;
-	}
 
 	/* Create a socket to communicate with */
 	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
@@ -956,8 +1078,11 @@
 		goto out_err;
 
 	memset(&saddr, 0, sizeof(saddr));
-	if (dlm_nodeid_to_addr(con->nodeid, &saddr))
+	result = nodeid_to_addr(con->nodeid, &saddr, NULL);
+	if (result < 0) {
+		log_print("no address for nodeid %d", con->nodeid);
 		goto out_err;
+	}
 
 	sock->sk->sk_user_data = con;
 	con->rx_action = receive_from_sock;
@@ -983,8 +1108,7 @@
 	kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
 			  sizeof(one));
 
-	result =
-		sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
+	result = sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
 				   O_NONBLOCK);
 	if (result == -EINPROGRESS)
 		result = 0;
@@ -1002,11 +1126,17 @@
 	 * Some errors are fatal and this list might need adjusting. For other
 	 * errors we try again until the max number of retries is reached.
 	 */
-	if (result != -EHOSTUNREACH && result != -ENETUNREACH &&
-	    result != -ENETDOWN && result != -EINVAL
-	    && result != -EPROTONOSUPPORT) {
+	if (result != -EHOSTUNREACH &&
+	    result != -ENETUNREACH &&
+	    result != -ENETDOWN && 
+	    result != -EINVAL &&
+	    result != -EPROTONOSUPPORT) {
+		log_print("connect %d try %d error %d", con->nodeid,
+			  con->retries, result);
+		mutex_unlock(&con->sock_mutex);
+		msleep(1000);
 		lowcomms_connect_sock(con);
-		result = 0;
+		return;
 	}
 out:
 	mutex_unlock(&con->sock_mutex);
@@ -1044,10 +1174,8 @@
 	if (result < 0) {
 		log_print("Failed to set SO_REUSEADDR on socket: %d", result);
 	}
-	sock->sk->sk_user_data = con;
 	con->rx_action = tcp_accept_from_sock;
 	con->connect_action = tcp_connect_to_sock;
-	con->sock = sock;
 
 	/* Bind to our port */
 	make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
@@ -1358,8 +1486,7 @@
 				}
 				cond_resched();
 				goto out;
-			}
-			if (ret <= 0)
+			} else if (ret < 0)
 				goto send_error;
 		}
 
@@ -1376,7 +1503,6 @@
 		if (e->len == 0 && e->users == 0) {
 			list_del(&e->list);
 			free_entry(e);
-			continue;
 		}
 	}
 	spin_unlock(&con->writequeue_lock);
@@ -1394,7 +1520,6 @@
 	mutex_unlock(&con->sock_mutex);
 	if (!test_bit(CF_INIT_PENDING, &con->flags))
 		lowcomms_connect_sock(con);
-	return;
 }
 
 static void clean_one_writequeue(struct connection *con)
@@ -1414,6 +1539,7 @@
 int dlm_lowcomms_close(int nodeid)
 {
 	struct connection *con;
+	struct dlm_node_addr *na;
 
 	log_print("closing connection to node %d", nodeid);
 	con = nodeid2con(nodeid, 0);
@@ -1428,6 +1554,17 @@
 		clean_one_writequeue(con);
 		close_connection(con, true);
 	}
+
+	spin_lock(&dlm_node_addrs_spin);
+	na = find_node_addr(nodeid);
+	if (na) {
+		list_del(&na->list);
+		while (na->addr_count--)
+			kfree(na->addr[na->addr_count]);
+		kfree(na);
+	}
+	spin_unlock(&dlm_node_addrs_spin);
+
 	return 0;
 }
 
@@ -1577,3 +1714,17 @@
 fail:
 	return error;
 }
+
+void dlm_lowcomms_exit(void)
+{
+	struct dlm_node_addr *na, *safe;
+
+	spin_lock(&dlm_node_addrs_spin);
+	list_for_each_entry_safe(na, safe, &dlm_node_addrs, list) {
+		list_del(&na->list);
+		while (na->addr_count--)
+			kfree(na->addr[na->addr_count]);
+		kfree(na);
+	}
+	spin_unlock(&dlm_node_addrs_spin);
+}
diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
index 1311e64..67462e5 100644
--- a/fs/dlm/lowcomms.h
+++ b/fs/dlm/lowcomms.h
@@ -16,10 +16,12 @@
 
 int dlm_lowcomms_start(void);
 void dlm_lowcomms_stop(void);
+void dlm_lowcomms_exit(void);
 int dlm_lowcomms_close(int nodeid);
 void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
 void dlm_lowcomms_commit_buffer(void *mh);
 int dlm_lowcomms_connect_node(int nodeid);
+int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len);
 
 #endif				/* __LOWCOMMS_DOT_H__ */
 
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
index 5a59efa..079c0bd 100644
--- a/fs/dlm/main.c
+++ b/fs/dlm/main.c
@@ -17,6 +17,7 @@
 #include "user.h"
 #include "memory.h"
 #include "config.h"
+#include "lowcomms.h"
 
 static int __init init_dlm(void)
 {
@@ -78,6 +79,7 @@
 	dlm_config_exit();
 	dlm_memory_exit();
 	dlm_lockspace_exit();
+	dlm_lowcomms_exit();
 	dlm_unregister_debugfs();
 }
 
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index 862640a..476557b 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -616,13 +616,13 @@
 	down_write(&ls->ls_recv_active);
 
 	/*
-	 * Abort any recovery that's in progress (see RECOVERY_STOP,
+	 * Abort any recovery that's in progress (see RECOVER_STOP,
 	 * dlm_recovery_stopped()) and tell any other threads running in the
 	 * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
 	 */
 
 	spin_lock(&ls->ls_recover_lock);
-	set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	set_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
 	new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
 	ls->ls_recover_seq++;
 	spin_unlock(&ls->ls_recover_lock);
@@ -642,12 +642,16 @@
 	 *    when recovery is complete.
 	 */
 
-	if (new)
-		down_write(&ls->ls_in_recovery);
+	if (new) {
+		set_bit(LSFL_RECOVER_DOWN, &ls->ls_flags);
+		wake_up_process(ls->ls_recoverd_task);
+		wait_event(ls->ls_recover_lock_wait,
+			   test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
+	}
 
 	/*
 	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
-	 * running) has noticed RECOVERY_STOP above and quit processing the
+	 * running) has noticed RECOVER_STOP above and quit processing the
 	 * previous recovery.
 	 */
 
@@ -709,7 +713,8 @@
 		kfree(rv_old);
 	}
 
-	dlm_recoverd_kick(ls);
+	set_bit(LSFL_RECOVER_WORK, &ls->ls_flags);
+	wake_up_process(ls->ls_recoverd_task);
 	return 0;
 
  fail:
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 87f1a56..9d61947 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -581,7 +581,7 @@
 
 	spin_lock(&ls->ls_recover_lock);
 	status = ls->ls_recover_status;
-	stop = test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	stop = test_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
 	seq = ls->ls_recover_seq;
 	spin_unlock(&ls->ls_recover_lock);
 
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 88ce65f..32f9f89 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -41,6 +41,7 @@
 		set_bit(LSFL_RUNNING, &ls->ls_flags);
 		/* unblocks processes waiting to enter the dlm */
 		up_write(&ls->ls_in_recovery);
+		clear_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
 		error = 0;
 	}
 	spin_unlock(&ls->ls_recover_lock);
@@ -262,7 +263,7 @@
 	rv = ls->ls_recover_args;
 	ls->ls_recover_args = NULL;
 	if (rv && ls->ls_recover_seq == rv->seq)
-		clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+		clear_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
 	spin_unlock(&ls->ls_recover_lock);
 
 	if (rv) {
@@ -282,26 +283,34 @@
 		return -1;
 	}
 
+	down_write(&ls->ls_in_recovery);
+	set_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
+	wake_up(&ls->ls_recover_lock_wait);
+
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (!test_bit(LSFL_WORK, &ls->ls_flags))
+		if (!test_bit(LSFL_RECOVER_WORK, &ls->ls_flags) &&
+		    !test_bit(LSFL_RECOVER_DOWN, &ls->ls_flags))
 			schedule();
 		set_current_state(TASK_RUNNING);
 
-		if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
+		if (test_and_clear_bit(LSFL_RECOVER_DOWN, &ls->ls_flags)) {
+			down_write(&ls->ls_in_recovery);
+			set_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
+			wake_up(&ls->ls_recover_lock_wait);
+		}
+
+		if (test_and_clear_bit(LSFL_RECOVER_WORK, &ls->ls_flags))
 			do_ls_recovery(ls);
 	}
 
+	if (test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags))
+		up_write(&ls->ls_in_recovery);
+
 	dlm_put_lockspace(ls);
 	return 0;
 }
 
-void dlm_recoverd_kick(struct dlm_ls *ls)
-{
-	set_bit(LSFL_WORK, &ls->ls_flags);
-	wake_up_process(ls->ls_recoverd_task);
-}
-
 int dlm_recoverd_start(struct dlm_ls *ls)
 {
 	struct task_struct *p;
diff --git a/fs/dlm/recoverd.h b/fs/dlm/recoverd.h
index 866657c..8856079 100644
--- a/fs/dlm/recoverd.h
+++ b/fs/dlm/recoverd.h
@@ -14,7 +14,6 @@
 #ifndef __RECOVERD_DOT_H__
 #define __RECOVERD_DOT_H__
 
-void dlm_recoverd_kick(struct dlm_ls *ls);
 void dlm_recoverd_stop(struct dlm_ls *ls);
 int dlm_recoverd_start(struct dlm_ls *ls);
 void dlm_recoverd_suspend(struct dlm_ls *ls);
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index eb4ed9b..7ff4985 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -503,6 +503,13 @@
 #endif
 		return -EINVAL;
 
+#ifdef CONFIG_COMPAT
+	if (count > sizeof(struct dlm_write_request32) + DLM_RESNAME_MAXLEN)
+#else
+	if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
+#endif
+		return -EINVAL;
+
 	kbuf = kzalloc(count + 1, GFP_NOFS);
 	if (!kbuf)
 		return -ENOMEM;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 376aa77..2616d0e 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -479,7 +479,7 @@
 /**
  * ext2_free_blocks() -- Free given blocks and update quota and i_blocks
  * @inode:		inode
- * @block:		start physcial block to free
+ * @block:		start physical block to free
  * @count:		number of blocks to free
  */
 void ext2_free_blocks (struct inode * inode, unsigned long block,
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 90d901f..7320a66 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -483,7 +483,7 @@
  * ext3_free_blocks_sb() -- Free given blocks and update quota
  * @handle:			handle to this transaction
  * @sb:				super block
- * @block:			start physcial block to free
+ * @block:			start physical block to free
  * @count:			number of blocks to free
  * @pdquot_freed_blocks:	pointer to quota
  */
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index ff574b4..7e87e37 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -3207,7 +3207,7 @@
  *
  * - Within generic_file_write() for O_SYNC files.
  *   Here, there will be no transaction running. We wait for any running
- *   trasnaction to commit.
+ *   transaction to commit.
  *
  * - Within sys_sync(), kupdate and such.
  *   We wait on commit, if tol to.
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index dff171c..c862ee5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3313,7 +3313,7 @@
  * handle: The journal handle
  * inode:  The files inode
  * page:   A locked page that contains the offset "from"
- * from:   The starting byte offset (from the begining of the file)
+ * from:   The starting byte offset (from the beginning of the file)
  *         to begin discarding
  * len:    The length of bytes to discard
  * flags:  Optional flags that may be used:
@@ -3321,11 +3321,11 @@
  *         EXT4_DISCARD_PARTIAL_PG_ZERO_UNMAPPED
  *         Only zero the regions of the page whose buffer heads
  *         have already been unmapped.  This flag is appropriate
- *         for updateing the contents of a page whose blocks may
+ *         for updating the contents of a page whose blocks may
  *         have already been released, and we only want to zero
  *         out the regions that correspond to those released blocks.
  *
- * Returns zero on sucess or negative on failure.
+ * Returns zero on success or negative on failure.
  */
 static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
 		struct inode *inode, struct page *page, loff_t from,
@@ -3486,7 +3486,7 @@
  * @offset: The offset where the hole will begin
  * @len:    The length of the hole
  *
- * Returns: 0 on sucess or negative on failure
+ * Returns: 0 on success or negative on failure
  */
 
 int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
@@ -4008,7 +4008,7 @@
 
 	if (i_blocks <= ~0U) {
 		/*
-		 * i_blocks can be represnted in a 32 bit variable
+		 * i_blocks can be represented in a 32 bit variable
 		 * as multiple of 512 bytes
 		 */
 		raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
@@ -4169,7 +4169,7 @@
  *
  * - Within generic_file_write() for O_SYNC files.
  *   Here, there will be no transaction running. We wait for any running
- *   trasnaction to commit.
+ *   transaction to commit.
  *
  * - Within sys_sync(), kupdate and such.
  *   We wait on commit, if tol to.
@@ -4413,7 +4413,7 @@
  * worse case, the indexs blocks spread over different block groups
  *
  * If datablocks are discontiguous, they are possible to spread over
- * different block groups too. If they are contiuguous, with flexbg,
+ * different block groups too. If they are contiguous, with flexbg,
  * they could still across block group boundary.
  *
  * Also account for superblock, inode, quota and xattr blocks
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 8eae9477..08778f6 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4709,7 +4709,7 @@
  * ext4_group_add_blocks() -- Add given blocks to an existing group
  * @handle:			handle to this transaction
  * @sb:				super block
- * @block:			start physcial block to add to the block group
+ * @block:			start physical block to add to the block group
  * @count:			number of blocks to free
  *
  * This marks the blocks as free in the bitmap and buddy.
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index be3efc4..6d46c0d 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -577,10 +577,6 @@
 /*
  * Write a portion of b_io inodes which belong to @sb.
  *
- * If @only_this_sb is true, then find and write all such
- * inodes. Otherwise write only ones which go sequentially
- * in reverse order.
- *
  * Return the number of pages and/or inodes written.
  */
 static long writeback_sb_inodes(struct super_block *sb,
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index d652634..01c4975 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -612,6 +612,7 @@
 	struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
 	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
 	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
+	unsigned requested = 0;
 	int alloc_required;
 	int error = 0;
 	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
@@ -641,7 +642,8 @@
 		if (error)
 			goto out_unlock;
 
-		error = gfs2_inplace_reserve(ip, data_blocks + ind_blocks);
+		requested = data_blocks + ind_blocks;
+		error = gfs2_inplace_reserve(ip, requested);
 		if (error)
 			goto out_qunlock;
 	}
@@ -654,7 +656,7 @@
 	if (&ip->i_inode == sdp->sd_rindex)
 		rblocks += 2 * RES_STATFS;
 	if (alloc_required)
-		rblocks += gfs2_rg_blocks(ip);
+		rblocks += gfs2_rg_blocks(ip, requested);
 
 	error = gfs2_trans_begin(sdp, rblocks,
 				 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -868,8 +870,7 @@
 	brelse(dibh);
 failed:
 	gfs2_trans_end(sdp);
-	if (gfs2_mb_reserved(ip))
-		gfs2_inplace_release(ip);
+	gfs2_inplace_release(ip);
 	if (ip->i_res->rs_qa_qd_num)
 		gfs2_quota_unlock(ip);
 	if (inode == sdp->sd_rindex) {
@@ -1023,7 +1024,7 @@
 				  offset, nr_segs, gfs2_get_block_direct,
 				  NULL, NULL, 0);
 out:
-	gfs2_glock_dq_m(1, &gh);
+	gfs2_glock_dq(&gh);
 	gfs2_holder_uninit(&gh);
 	return rv;
 }
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 49cd7dd..1fd3ae2 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -786,7 +786,7 @@
 		goto out_rlist;
 
 	if (gfs2_rs_active(ip->i_res)) /* needs to be done with the rgrp glock held */
-		gfs2_rs_deltree(ip->i_res);
+		gfs2_rs_deltree(ip, ip->i_res);
 
 	error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
 				 RES_INDIRECT + RES_STATFS + RES_QUOTA,
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 382000f..30e2199 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -441,7 +441,7 @@
 		rblocks += data_blocks ? data_blocks : 1;
 	if (ind_blocks || data_blocks) {
 		rblocks += RES_STATFS + RES_QUOTA;
-		rblocks += gfs2_rg_blocks(ip);
+		rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);
 	}
 	ret = gfs2_trans_begin(sdp, rblocks, 0);
 	if (ret)
@@ -845,7 +845,7 @@
 				&max_bytes, &data_blocks, &ind_blocks);
 
 		rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
-			  RES_RG_HDR + gfs2_rg_blocks(ip);
+			  RES_RG_HDR + gfs2_rg_blocks(ip, data_blocks + ind_blocks);
 		if (gfs2_is_jdata(ip))
 			rblocks += data_blocks ? data_blocks : 1;
 
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 1ed81f4..e6c2fd5 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -186,20 +186,6 @@
 }
 
 /**
- * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
- * @gl: the glock
- *
- * If the glock is demotable, then we add it (or move it) to the end
- * of the glock LRU list.
- */
-
-static void __gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
-{
-	if (demote_ok(gl))
-		gfs2_glock_add_to_lru(gl);
-}
-
-/**
  * gfs2_glock_put_nolock() - Decrement reference count on glock
  * @gl: The glock to put
  *
@@ -883,7 +869,14 @@
 	return 0;
 }
 
-static void wait_on_holder(struct gfs2_holder *gh)
+/**
+ * gfs2_glock_wait - wait on a glock acquisition
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success
+ */
+
+int gfs2_glock_wait(struct gfs2_holder *gh)
 {
 	unsigned long time1 = jiffies;
 
@@ -894,12 +887,7 @@
 		gh->gh_gl->gl_hold_time = min(gh->gh_gl->gl_hold_time +
 					      GL_GLOCK_HOLD_INCR,
 					      GL_GLOCK_MAX_HOLD);
-}
-
-static void wait_on_demote(struct gfs2_glock *gl)
-{
-	might_sleep();
-	wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE);
+	return gh->gh_error;
 }
 
 /**
@@ -929,19 +917,6 @@
 	trace_gfs2_demote_rq(gl);
 }
 
-/**
- * gfs2_glock_wait - wait on a glock acquisition
- * @gh: the glock holder
- *
- * Returns: 0 on success
- */
-
-int gfs2_glock_wait(struct gfs2_holder *gh)
-{
-	wait_on_holder(gh);
-	return gh->gh_error;
-}
-
 void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
 {
 	struct va_format vaf;
@@ -979,7 +954,7 @@
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	struct list_head *insert_pt = NULL;
 	struct gfs2_holder *gh2;
-	int try_lock = 0;
+	int try_futile = 0;
 
 	BUG_ON(gh->gh_owner_pid == NULL);
 	if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
@@ -987,7 +962,7 @@
 
 	if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
 		if (test_bit(GLF_LOCK, &gl->gl_flags))
-			try_lock = 1;
+			try_futile = !may_grant(gl, gh);
 		if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags))
 			goto fail;
 	}
@@ -996,9 +971,8 @@
 		if (unlikely(gh2->gh_owner_pid == gh->gh_owner_pid &&
 		    (gh->gh_gl->gl_ops->go_type != LM_TYPE_FLOCK)))
 			goto trap_recursive;
-		if (try_lock &&
-		    !(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) &&
-		    !may_grant(gl, gh)) {
+		if (try_futile &&
+		    !(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) {
 fail:
 			gh->gh_error = GLR_TRYFAILED;
 			gfs2_holder_wake(gh);
@@ -1121,8 +1095,9 @@
 		    !test_bit(GLF_DEMOTE, &gl->gl_flags))
 			fast_path = 1;
 	}
-	if (!test_bit(GLF_LFLUSH, &gl->gl_flags))
-		__gfs2_glock_schedule_for_reclaim(gl);
+	if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
+		gfs2_glock_add_to_lru(gl);
+
 	trace_gfs2_glock_queue(gh, 0);
 	spin_unlock(&gl->gl_spin);
 	if (likely(fast_path))
@@ -1141,7 +1116,8 @@
 {
 	struct gfs2_glock *gl = gh->gh_gl;
 	gfs2_glock_dq(gh);
-	wait_on_demote(gl);
+	might_sleep();
+	wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE);
 }
 
 /**
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 4bdcf37..32cc4fd 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -94,6 +94,7 @@
 	/* A shortened, inline version of gfs2_trans_begin() */
 	tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
 	tr.tr_ip = (unsigned long)__builtin_return_address(0);
+	sb_start_intwrite(sdp->sd_vfs);
 	gfs2_log_reserve(sdp, tr.tr_reserved);
 	BUG_ON(current->journal_info);
 	current->journal_info = &tr;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index aaecc80..3d469d3 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -99,9 +99,26 @@
 #define GFS2_RDF_MASK		0xf0000000 /* mask for internal flags */
 	spinlock_t rd_rsspin;           /* protects reservation related vars */
 	struct rb_root rd_rstree;       /* multi-block reservation tree */
-	u32 rd_rs_cnt;                  /* count of current reservations */
 };
 
+struct gfs2_rbm {
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_bitmap *bi;	/* Bitmap must belong to the rgd */
+	u32 offset;		/* The offset is bitmap relative */
+};
+
+static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
+{
+	return rbm->rgd->rd_data0 + (rbm->bi->bi_start * GFS2_NBBY) + rbm->offset;
+}
+
+static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1,
+			       const struct gfs2_rbm *rbm2)
+{
+	return (rbm1->rgd == rbm2->rgd) && (rbm1->bi == rbm2->bi) && 
+	       (rbm1->offset == rbm2->offset);
+}
+
 enum gfs2_state_bits {
 	BH_Pinned = BH_PrivateStart,
 	BH_Escaped = BH_PrivateStart + 1,
@@ -250,18 +267,11 @@
 	/* components used during write (step 1): */
 	atomic_t rs_sizehint;         /* hint of the write size */
 
-	/* components used during inplace_reserve (step 2): */
-	u32 rs_requested; /* Filled in by caller of gfs2_inplace_reserve() */
-
-	/* components used during get_local_rgrp (step 3): */
-	struct gfs2_rgrpd *rs_rgd;    /* pointer to the gfs2_rgrpd */
 	struct gfs2_holder rs_rgd_gh; /* Filled in by get_local_rgrp */
 	struct rb_node rs_node;       /* link to other block reservations */
-
-	/* components used during block searches and assignments (step 4): */
-	struct gfs2_bitmap *rs_bi;    /* bitmap for the current allocation */
-	u32 rs_biblk;                 /* start block relative to the bi */
+	struct gfs2_rbm rs_rbm;       /* Start of reservation */
 	u32 rs_free;                  /* how many blocks are still free */
+	u64 rs_inum;                  /* Inode number for reservation */
 
 	/* ancillary quota stuff */
 	struct gfs2_quota_data *rs_qa_qd[2 * MAXQUOTAS];
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 753af3d..381893c 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -712,14 +712,9 @@
 	if (error)
 		goto fail_gunlock2;
 
-	/* The newly created inode needs a reservation so it can allocate
-	   xattrs. At the same time, we want new blocks allocated to the new
-	   dinode to be as contiguous as possible. Since we allocated the
-	   dinode block under the directory's reservation, we transfer
-	   ownership of that reservation to the new inode. The directory
-	   doesn't need a reservation unless it needs a new allocation. */
-	ip->i_res = dip->i_res;
-	dip->i_res = NULL;
+	error = gfs2_rs_alloc(ip);
+	if (error)
+		goto fail_gunlock2;
 
 	error = gfs2_acl_create(dip, inode);
 	if (error)
@@ -737,10 +732,7 @@
 		brelse(bh);
 
 	gfs2_trans_end(sdp);
-	/* Check if we reserved space in the rgrp. Function link_dinode may
-	   not, depending on whether alloc is required. */
-	if (gfs2_mb_reserved(dip))
-		gfs2_inplace_release(dip);
+	gfs2_inplace_release(dip);
 	gfs2_quota_unlock(dip);
 	mark_inode_dirty(inode);
 	gfs2_glock_dq_uninit_m(2, ghs);
@@ -897,7 +889,7 @@
 			goto out_gunlock_q;
 
 		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-					 gfs2_rg_blocks(dip) +
+					 gfs2_rg_blocks(dip, sdp->sd_max_dirres) +
 					 2 * RES_DINODE + RES_STATFS +
 					 RES_QUOTA, 0);
 		if (error)
@@ -1378,7 +1370,7 @@
 			goto out_gunlock_q;
 
 		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-					 gfs2_rg_blocks(ndip) +
+					 gfs2_rg_blocks(ndip, sdp->sd_max_dirres) +
 					 4 * RES_DINODE + 4 * RES_LEAF +
 					 RES_STATFS + RES_QUOTA + 4, 0);
 		if (error)
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index e5af9dc..e443966 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -19,6 +19,7 @@
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/quotaops.h>
+#include <linux/lockdep.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -766,6 +767,7 @@
 	return error;
 }
 
+static struct lock_class_key gfs2_quota_imutex_key;
 
 static int init_inodes(struct gfs2_sbd *sdp, int undo)
 {
@@ -803,6 +805,12 @@
 		fs_err(sdp, "can't get quota file inode: %d\n", error);
 		goto fail_rindex;
 	}
+	/*
+	 * i_mutex on quota files is special. Since this inode is hidden system
+	 * file, we are safe to define locking ourselves.
+	 */
+	lockdep_set_class(&sdp->sd_quota_inode->i_mutex,
+			  &gfs2_quota_imutex_key);
 
 	error = gfs2_rindex_update(sdp);
 	if (error)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..4021dec 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -765,6 +765,7 @@
 	struct gfs2_holder *ghs, i_gh;
 	unsigned int qx, x;
 	struct gfs2_quota_data *qd;
+	unsigned reserved;
 	loff_t offset;
 	unsigned int nalloc = 0, blocks;
 	int error;
@@ -781,7 +782,7 @@
 		return -ENOMEM;
 
 	sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
-	mutex_lock_nested(&ip->i_inode.i_mutex, I_MUTEX_QUOTA);
+	mutex_lock(&ip->i_inode.i_mutex);
 	for (qx = 0; qx < num_qd; qx++) {
 		error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE,
 					   GL_NOCACHE, &ghs[qx]);
@@ -811,13 +812,13 @@
 	 * two blocks need to be updated instead of 1 */
 	blocks = num_qd * data_blocks + RES_DINODE + num_qd + 3;
 
-	error = gfs2_inplace_reserve(ip, 1 +
-				     (nalloc * (data_blocks + ind_blocks)));
+	reserved = 1 + (nalloc * (data_blocks + ind_blocks));
+	error = gfs2_inplace_reserve(ip, reserved);
 	if (error)
 		goto out_alloc;
 
 	if (nalloc)
-		blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
+		blocks += gfs2_rg_blocks(ip, reserved) + nalloc * ind_blocks + RES_STATFS;
 
 	error = gfs2_trans_begin(sdp, blocks, 0);
 	if (error)
@@ -1598,7 +1599,7 @@
 		error = gfs2_inplace_reserve(ip, blocks);
 		if (error)
 			goto out_i;
-		blocks += gfs2_rg_blocks(ip);
+		blocks += gfs2_rg_blocks(ip, blocks);
 	}
 
 	/* Some quotas span block boundaries and can update two blocks,
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index c9ed814..3cc402c 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -35,9 +35,6 @@
 #define BFITNOENT ((u32)~0)
 #define NO_BLOCK ((u64)~0)
 
-#define RSRV_CONTENTION_FACTOR 4
-#define RGRP_RSRV_MAX_CONTENDERS 2
-
 #if BITS_PER_LONG == 32
 #define LBITMASK   (0x55555555UL)
 #define LBITSKIP55 (0x55555555UL)
@@ -67,53 +64,48 @@
 	        1, 0, 0, 0
 };
 
-static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
-			unsigned char old_state,
-			struct gfs2_bitmap **rbi);
+static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext,
+                         const struct gfs2_inode *ip, bool nowrap);
+
 
 /**
  * gfs2_setbit - Set a bit in the bitmaps
- * @rgd: the resource group descriptor
- * @buf2: the clone buffer that holds the bitmaps
- * @bi: the bitmap structure
- * @block: the block to set
+ * @rbm: The position of the bit to set
+ * @do_clone: Also set the clone bitmap, if it exists
  * @new_state: the new state of the block
  *
  */
 
-static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf2,
-			       struct gfs2_bitmap *bi, u32 block,
+static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone,
 			       unsigned char new_state)
 {
 	unsigned char *byte1, *byte2, *end, cur_state;
-	unsigned int buflen = bi->bi_len;
-	const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+	unsigned int buflen = rbm->bi->bi_len;
+	const unsigned int bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
 
-	byte1 = bi->bi_bh->b_data + bi->bi_offset + (block / GFS2_NBBY);
-	end = bi->bi_bh->b_data + bi->bi_offset + buflen;
+	byte1 = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset + (rbm->offset / GFS2_NBBY);
+	end = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset + buflen;
 
 	BUG_ON(byte1 >= end);
 
 	cur_state = (*byte1 >> bit) & GFS2_BIT_MASK;
 
 	if (unlikely(!valid_change[new_state * 4 + cur_state])) {
-		printk(KERN_WARNING "GFS2: buf_blk = 0x%llx old_state=%d, "
-		       "new_state=%d\n",
-		       (unsigned long long)block, cur_state, new_state);
-		printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%lx\n",
-		       (unsigned long long)rgd->rd_addr,
-		       (unsigned long)bi->bi_start);
-		printk(KERN_WARNING "GFS2: bi_offset=0x%lx bi_len=0x%lx\n",
-		       (unsigned long)bi->bi_offset,
-		       (unsigned long)bi->bi_len);
+		printk(KERN_WARNING "GFS2: buf_blk = 0x%x old_state=%d, "
+		       "new_state=%d\n", rbm->offset, cur_state, new_state);
+		printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%x\n",
+		       (unsigned long long)rbm->rgd->rd_addr,
+		       rbm->bi->bi_start);
+		printk(KERN_WARNING "GFS2: bi_offset=0x%x bi_len=0x%x\n",
+		       rbm->bi->bi_offset, rbm->bi->bi_len);
 		dump_stack();
-		gfs2_consist_rgrpd(rgd);
+		gfs2_consist_rgrpd(rbm->rgd);
 		return;
 	}
 	*byte1 ^= (cur_state ^ new_state) << bit;
 
-	if (buf2) {
-		byte2 = buf2 + bi->bi_offset + (block / GFS2_NBBY);
+	if (do_clone && rbm->bi->bi_clone) {
+		byte2 = rbm->bi->bi_clone + rbm->bi->bi_offset + (rbm->offset / GFS2_NBBY);
 		cur_state = (*byte2 >> bit) & GFS2_BIT_MASK;
 		*byte2 ^= (cur_state ^ new_state) << bit;
 	}
@@ -121,30 +113,21 @@
 
 /**
  * gfs2_testbit - test a bit in the bitmaps
- * @rgd: the resource group descriptor
- * @buffer: the buffer that holds the bitmaps
- * @buflen: the length (in bytes) of the buffer
- * @block: the block to read
+ * @rbm: The bit to test
  *
+ * Returns: The two bit block state of the requested bit
  */
 
-static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
-					 const unsigned char *buffer,
-					 unsigned int buflen, u32 block)
+static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm)
 {
-	const unsigned char *byte, *end;
-	unsigned char cur_state;
+	const u8 *buffer = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset;
+	const u8 *byte;
 	unsigned int bit;
 
-	byte = buffer + (block / GFS2_NBBY);
-	bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
-	end = buffer + buflen;
+	byte = buffer + (rbm->offset / GFS2_NBBY);
+	bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
 
-	gfs2_assert(rgd->rd_sbd, byte < end);
-
-	cur_state = (*byte >> bit) & GFS2_BIT_MASK;
-
-	return cur_state;
+	return (*byte >> bit) & GFS2_BIT_MASK;
 }
 
 /**
@@ -192,7 +175,7 @@
  */
 static inline int rs_cmp(u64 blk, u32 len, struct gfs2_blkreserv *rs)
 {
-	u64 startblk = gfs2_rs_startblk(rs);
+	u64 startblk = gfs2_rbm_to_block(&rs->rs_rbm);
 
 	if (blk >= startblk + rs->rs_free)
 		return 1;
@@ -202,36 +185,6 @@
 }
 
 /**
- * rs_find - Find a rgrp multi-block reservation that contains a given block
- * @rgd: The rgrp
- * @rgblk: The block we're looking for, relative to the rgrp
- */
-static struct gfs2_blkreserv *rs_find(struct gfs2_rgrpd *rgd, u32 rgblk)
-{
-	struct rb_node **newn;
-	int rc;
-	u64 fsblk = rgblk + rgd->rd_data0;
-
-	spin_lock(&rgd->rd_rsspin);
-	newn = &rgd->rd_rstree.rb_node;
-	while (*newn) {
-		struct gfs2_blkreserv *cur =
-			rb_entry(*newn, struct gfs2_blkreserv, rs_node);
-		rc = rs_cmp(fsblk, 1, cur);
-		if (rc < 0)
-			newn = &((*newn)->rb_left);
-		else if (rc > 0)
-			newn = &((*newn)->rb_right);
-		else {
-			spin_unlock(&rgd->rd_rsspin);
-			return cur;
-		}
-	}
-	spin_unlock(&rgd->rd_rsspin);
-	return NULL;
-}
-
-/**
  * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
  *       a block in a given allocation state.
  * @buf: the buffer that holds the bitmaps
@@ -262,8 +215,6 @@
 	u64 mask = 0x5555555555555555ULL;
 	u32 bit;
 
-	BUG_ON(state > 3);
-
 	/* Mask off bits we don't care about at the start of the search */
 	mask <<= spoint;
 	tmp = gfs2_bit_search(ptr, mask, state);
@@ -285,6 +236,131 @@
 }
 
 /**
+ * gfs2_rbm_from_block - Set the rbm based upon rgd and block number
+ * @rbm: The rbm with rgd already set correctly
+ * @block: The block number (filesystem relative)
+ *
+ * This sets the bi and offset members of an rbm based on a
+ * resource group and a filesystem relative block number. The
+ * resource group must be set in the rbm on entry, the bi and
+ * offset members will be set by this function.
+ *
+ * Returns: 0 on success, or an error code
+ */
+
+static int gfs2_rbm_from_block(struct gfs2_rbm *rbm, u64 block)
+{
+	u64 rblock = block - rbm->rgd->rd_data0;
+	u32 goal = (u32)rblock;
+	int x;
+
+	if (WARN_ON_ONCE(rblock > UINT_MAX))
+		return -EINVAL;
+	if (block >= rbm->rgd->rd_data0 + rbm->rgd->rd_data)
+		return -E2BIG;
+
+	for (x = 0; x < rbm->rgd->rd_length; x++) {
+		rbm->bi = rbm->rgd->rd_bits + x;
+		if (goal < (rbm->bi->bi_start + rbm->bi->bi_len) * GFS2_NBBY) {
+			rbm->offset = goal - (rbm->bi->bi_start * GFS2_NBBY);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_unaligned_extlen - Look for free blocks which are not byte aligned
+ * @rbm: Position to search (value/result)
+ * @n_unaligned: Number of unaligned blocks to check
+ * @len: Decremented for each block found (terminate on zero)
+ *
+ * Returns: true if a non-free block is encountered
+ */
+
+static bool gfs2_unaligned_extlen(struct gfs2_rbm *rbm, u32 n_unaligned, u32 *len)
+{
+	u64 block;
+	u32 n;
+	u8 res;
+
+	for (n = 0; n < n_unaligned; n++) {
+		res = gfs2_testbit(rbm);
+		if (res != GFS2_BLKST_FREE)
+			return true;
+		(*len)--;
+		if (*len == 0)
+			return true;
+		block = gfs2_rbm_to_block(rbm);
+		if (gfs2_rbm_from_block(rbm, block + 1))
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * gfs2_free_extlen - Return extent length of free blocks
+ * @rbm: Starting position
+ * @len: Max length to check
+ *
+ * Starting at the block specified by the rbm, see how many free blocks
+ * there are, not reading more than len blocks ahead. This can be done
+ * using memchr_inv when the blocks are byte aligned, but has to be done
+ * on a block by block basis in case of unaligned blocks. Also this
+ * function can cope with bitmap boundaries (although it must stop on
+ * a resource group boundary)
+ *
+ * Returns: Number of free blocks in the extent
+ */
+
+static u32 gfs2_free_extlen(const struct gfs2_rbm *rrbm, u32 len)
+{
+	struct gfs2_rbm rbm = *rrbm;
+	u32 n_unaligned = rbm.offset & 3;
+	u32 size = len;
+	u32 bytes;
+	u32 chunk_size;
+	u8 *ptr, *start, *end;
+	u64 block;
+
+	if (n_unaligned &&
+	    gfs2_unaligned_extlen(&rbm, 4 - n_unaligned, &len))
+		goto out;
+
+	n_unaligned = len & 3;
+	/* Start is now byte aligned */
+	while (len > 3) {
+		start = rbm.bi->bi_bh->b_data;
+		if (rbm.bi->bi_clone)
+			start = rbm.bi->bi_clone;
+		end = start + rbm.bi->bi_bh->b_size;
+		start += rbm.bi->bi_offset;
+		BUG_ON(rbm.offset & 3);
+		start += (rbm.offset / GFS2_NBBY);
+		bytes = min_t(u32, len / GFS2_NBBY, (end - start));
+		ptr = memchr_inv(start, 0, bytes);
+		chunk_size = ((ptr == NULL) ? bytes : (ptr - start));
+		chunk_size *= GFS2_NBBY;
+		BUG_ON(len < chunk_size);
+		len -= chunk_size;
+		block = gfs2_rbm_to_block(&rbm);
+		gfs2_rbm_from_block(&rbm, block + chunk_size);
+		n_unaligned = 3;
+		if (ptr)
+			break;
+		n_unaligned = len & 3;
+	}
+
+	/* Deal with any bits left over at the end */
+	if (n_unaligned)
+		gfs2_unaligned_extlen(&rbm, n_unaligned, &len);
+out:
+	return size - len;
+}
+
+/**
  * gfs2_bitcount - count the number of bits in a certain state
  * @rgd: the resource group descriptor
  * @buffer: the buffer that holds the bitmaps
@@ -487,6 +563,8 @@
 	if (!res)
 		error = -ENOMEM;
 
+	RB_CLEAR_NODE(&res->rs_node);
+
 	down_write(&ip->i_rw_mutex);
 	if (ip->i_res)
 		kmem_cache_free(gfs2_rsrv_cachep, res);
@@ -496,11 +574,12 @@
 	return error;
 }
 
-static void dump_rs(struct seq_file *seq, struct gfs2_blkreserv *rs)
+static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
 {
-	gfs2_print_dbg(seq, "  r: %llu s:%llu b:%u f:%u\n",
-		       rs->rs_rgd->rd_addr, gfs2_rs_startblk(rs), rs->rs_biblk,
-		       rs->rs_free);
+	gfs2_print_dbg(seq, "  B: n:%llu s:%llu b:%u f:%u\n",
+		       (unsigned long long)rs->rs_inum,
+		       (unsigned long long)gfs2_rbm_to_block(&rs->rs_rbm),
+		       rs->rs_rbm.offset, rs->rs_free);
 }
 
 /**
@@ -508,41 +587,26 @@
  * @rs: The reservation to remove
  *
  */
-static void __rs_deltree(struct gfs2_blkreserv *rs)
+static void __rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
 {
 	struct gfs2_rgrpd *rgd;
 
 	if (!gfs2_rs_active(rs))
 		return;
 
-	rgd = rs->rs_rgd;
-	/* We can't do this: The reason is that when the rgrp is invalidated,
-	   it's in the "middle" of acquiring the glock, but the HOLDER bit
-	   isn't set yet:
-	   BUG_ON(!gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl));*/
-	trace_gfs2_rs(NULL, rs, TRACE_RS_TREEDEL);
-
-	if (!RB_EMPTY_ROOT(&rgd->rd_rstree))
-		rb_erase(&rs->rs_node, &rgd->rd_rstree);
-	BUG_ON(!rgd->rd_rs_cnt);
-	rgd->rd_rs_cnt--;
+	rgd = rs->rs_rbm.rgd;
+	trace_gfs2_rs(rs, TRACE_RS_TREEDEL);
+	rb_erase(&rs->rs_node, &rgd->rd_rstree);
+	RB_CLEAR_NODE(&rs->rs_node);
 
 	if (rs->rs_free) {
 		/* return reserved blocks to the rgrp and the ip */
-		BUG_ON(rs->rs_rgd->rd_reserved < rs->rs_free);
-		rs->rs_rgd->rd_reserved -= rs->rs_free;
+		BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free);
+		rs->rs_rbm.rgd->rd_reserved -= rs->rs_free;
 		rs->rs_free = 0;
-		clear_bit(GBF_FULL, &rs->rs_bi->bi_flags);
+		clear_bit(GBF_FULL, &rs->rs_rbm.bi->bi_flags);
 		smp_mb__after_clear_bit();
 	}
-	/* We can't change any of the step 1 or step 2 components of the rs.
-	   E.g. We can't set rs_rgd to NULL because the rgd glock is held and
-	   dequeued through this pointer.
-	   Can't: atomic_set(&rs->rs_sizehint, 0);
-	   Can't: rs->rs_requested = 0;
-	   Can't: rs->rs_rgd = NULL;*/
-	rs->rs_bi = NULL;
-	rs->rs_biblk = 0;
 }
 
 /**
@@ -550,17 +614,16 @@
  * @rs: The reservation to remove
  *
  */
-void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
+void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
 {
 	struct gfs2_rgrpd *rgd;
 
-	if (!gfs2_rs_active(rs))
-		return;
-
-	rgd = rs->rs_rgd;
-	spin_lock(&rgd->rd_rsspin);
-	__rs_deltree(rs);
-	spin_unlock(&rgd->rd_rsspin);
+	rgd = rs->rs_rbm.rgd;
+	if (rgd) {
+		spin_lock(&rgd->rd_rsspin);
+		__rs_deltree(ip, rs);
+		spin_unlock(&rgd->rd_rsspin);
+	}
 }
 
 /**
@@ -572,8 +635,7 @@
 {
 	down_write(&ip->i_rw_mutex);
 	if (ip->i_res) {
-		gfs2_rs_deltree(ip->i_res);
-		trace_gfs2_rs(ip, ip->i_res, TRACE_RS_DELETE);
+		gfs2_rs_deltree(ip, ip->i_res);
 		BUG_ON(ip->i_res->rs_free);
 		kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
 		ip->i_res = NULL;
@@ -597,7 +659,7 @@
 	spin_lock(&rgd->rd_rsspin);
 	while ((n = rb_first(&rgd->rd_rstree))) {
 		rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
-		__rs_deltree(rs);
+		__rs_deltree(NULL, rs);
 	}
 	spin_unlock(&rgd->rd_rsspin);
 }
@@ -1270,211 +1332,276 @@
 
 /**
  * rs_insert - insert a new multi-block reservation into the rgrp's rb_tree
- * @bi: the bitmap with the blocks
  * @ip: the inode structure
- * @biblk: the 32-bit block number relative to the start of the bitmap
- * @amount: the number of blocks to reserve
  *
- * Returns: NULL - reservation was already taken, so not inserted
- *          pointer to the inserted reservation
  */
-static struct gfs2_blkreserv *rs_insert(struct gfs2_bitmap *bi,
-				       struct gfs2_inode *ip, u32 biblk,
-				       int amount)
+static void rs_insert(struct gfs2_inode *ip)
 {
 	struct rb_node **newn, *parent = NULL;
 	int rc;
 	struct gfs2_blkreserv *rs = ip->i_res;
-	struct gfs2_rgrpd *rgd = rs->rs_rgd;
-	u64 fsblock = gfs2_bi2rgd_blk(bi, biblk) + rgd->rd_data0;
+	struct gfs2_rgrpd *rgd = rs->rs_rbm.rgd;
+	u64 fsblock = gfs2_rbm_to_block(&rs->rs_rbm);
+
+	BUG_ON(gfs2_rs_active(rs));
 
 	spin_lock(&rgd->rd_rsspin);
 	newn = &rgd->rd_rstree.rb_node;
-	BUG_ON(!ip->i_res);
-	BUG_ON(gfs2_rs_active(rs));
-	/* Figure out where to put new node */
-	/*BUG_ON(!gfs2_glock_is_locked_by_me(rgd->rd_gl));*/
 	while (*newn) {
 		struct gfs2_blkreserv *cur =
 			rb_entry(*newn, struct gfs2_blkreserv, rs_node);
 
 		parent = *newn;
-		rc = rs_cmp(fsblock, amount, cur);
+		rc = rs_cmp(fsblock, rs->rs_free, cur);
 		if (rc > 0)
 			newn = &((*newn)->rb_right);
 		else if (rc < 0)
 			newn = &((*newn)->rb_left);
 		else {
 			spin_unlock(&rgd->rd_rsspin);
-			return NULL; /* reservation already in use */
+			WARN_ON(1);
+			return;
 		}
 	}
 
-	/* Do our reservation work */
-	rs = ip->i_res;
-	rs->rs_free = amount;
-	rs->rs_biblk = biblk;
-	rs->rs_bi = bi;
 	rb_link_node(&rs->rs_node, parent, newn);
 	rb_insert_color(&rs->rs_node, &rgd->rd_rstree);
 
-	/* Do our inode accounting for the reservation */
-	/*BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));*/
-
 	/* Do our rgrp accounting for the reservation */
-	rgd->rd_reserved += amount; /* blocks reserved */
-	rgd->rd_rs_cnt++; /* number of in-tree reservations */
+	rgd->rd_reserved += rs->rs_free; /* blocks reserved */
 	spin_unlock(&rgd->rd_rsspin);
-	trace_gfs2_rs(ip, rs, TRACE_RS_INSERT);
-	return rs;
+	trace_gfs2_rs(rs, TRACE_RS_INSERT);
 }
 
 /**
- * unclaimed_blocks - return number of blocks that aren't spoken for
- */
-static u32 unclaimed_blocks(struct gfs2_rgrpd *rgd)
-{
-	return rgd->rd_free_clone - rgd->rd_reserved;
-}
-
-/**
- * rg_mblk_search - find a group of multiple free blocks
+ * rg_mblk_search - find a group of multiple free blocks to form a reservation
  * @rgd: the resource group descriptor
- * @rs: the block reservation
  * @ip: pointer to the inode for which we're reserving blocks
+ * @requested: number of blocks required for this allocation
  *
- * This is very similar to rgblk_search, except we're looking for whole
- * 64-bit words that represent a chunk of 32 free blocks. I'm only focusing
- * on aligned dwords for speed's sake.
- *
- * Returns: 0 if successful or BFITNOENT if there isn't enough free space
  */
 
-static int rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
+			   unsigned requested)
 {
-	struct gfs2_bitmap *bi = rgd->rd_bits;
-	const u32 length = rgd->rd_length;
-	u32 blk;
-	unsigned int buf, x, search_bytes;
-	u8 *buffer = NULL;
-	u8 *ptr, *end, *nonzero;
-	u32 goal, rsv_bytes;
-	struct gfs2_blkreserv *rs;
-	u32 best_rs_bytes, unclaimed;
-	int best_rs_blocks;
+	struct gfs2_rbm rbm = { .rgd = rgd, };
+	u64 goal;
+	struct gfs2_blkreserv *rs = ip->i_res;
+	u32 extlen;
+	u32 free_blocks = rgd->rd_free_clone - rgd->rd_reserved;
+	int ret;
+
+	extlen = max_t(u32, atomic_read(&rs->rs_sizehint), requested);
+	extlen = clamp(extlen, RGRP_RSRV_MINBLKS, free_blocks);
+	if ((rgd->rd_free_clone < rgd->rd_reserved) || (free_blocks < extlen))
+		return;
 
 	/* Find bitmap block that contains bits for goal block */
 	if (rgrp_contains_block(rgd, ip->i_goal))
-		goal = ip->i_goal - rgd->rd_data0;
+		goal = ip->i_goal;
 	else
-		goal = rgd->rd_last_alloc;
-	for (buf = 0; buf < length; buf++) {
-		bi = rgd->rd_bits + buf;
-		/* Convert scope of "goal" from rgrp-wide to within
-		   found bit block */
-		if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY) {
-			goal -= bi->bi_start * GFS2_NBBY;
-			goto do_search;
-		}
+		goal = rgd->rd_last_alloc + rgd->rd_data0;
+
+	if (WARN_ON(gfs2_rbm_from_block(&rbm, goal)))
+		return;
+
+	ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, extlen, ip, true);
+	if (ret == 0) {
+		rs->rs_rbm = rbm;
+		rs->rs_free = extlen;
+		rs->rs_inum = ip->i_no_addr;
+		rs_insert(ip);
 	}
-	buf = 0;
-	goal = 0;
-
-do_search:
-	best_rs_blocks = max_t(int, atomic_read(&ip->i_res->rs_sizehint),
-			       (RGRP_RSRV_MINBLKS * rgd->rd_length));
-	best_rs_bytes = (best_rs_blocks *
-			 (1 + (RSRV_CONTENTION_FACTOR * rgd->rd_rs_cnt))) /
-		GFS2_NBBY; /* 1 + is for our not-yet-created reservation */
-	best_rs_bytes = ALIGN(best_rs_bytes, sizeof(u64));
-	unclaimed = unclaimed_blocks(rgd);
-	if (best_rs_bytes * GFS2_NBBY > unclaimed)
-		best_rs_bytes = unclaimed >> GFS2_BIT_SIZE;
-
-	for (x = 0; x <= length; x++) {
-		bi = rgd->rd_bits + buf;
-
-		if (test_bit(GBF_FULL, &bi->bi_flags))
-			goto skip;
-
-		WARN_ON(!buffer_uptodate(bi->bi_bh));
-		if (bi->bi_clone)
-			buffer = bi->bi_clone + bi->bi_offset;
-		else
-			buffer = bi->bi_bh->b_data + bi->bi_offset;
-
-		/* We have to keep the reservations aligned on u64 boundaries
-		   otherwise we could get situations where a byte can't be
-		   used because it's after a reservation, but a free bit still
-		   is within the reservation's area. */
-		ptr = buffer + ALIGN(goal >> GFS2_BIT_SIZE, sizeof(u64));
-		end = (buffer + bi->bi_len);
-		while (ptr < end) {
-			rsv_bytes = 0;
-			if ((ptr + best_rs_bytes) <= end)
-				search_bytes = best_rs_bytes;
-			else
-				search_bytes = end - ptr;
-			BUG_ON(!search_bytes);
-			nonzero = memchr_inv(ptr, 0, search_bytes);
-			/* If the lot is all zeroes, reserve the whole size. If
-			   there's enough zeroes to satisfy the request, use
-			   what we can. If there's not enough, keep looking. */
-			if (nonzero == NULL)
-				rsv_bytes = search_bytes;
-			else if ((nonzero - ptr) * GFS2_NBBY >=
-				 ip->i_res->rs_requested)
-				rsv_bytes = (nonzero - ptr);
-
-			if (rsv_bytes) {
-				blk = ((ptr - buffer) * GFS2_NBBY);
-				BUG_ON(blk >= bi->bi_len * GFS2_NBBY);
-				rs = rs_insert(bi, ip, blk,
-					       rsv_bytes * GFS2_NBBY);
-				if (IS_ERR(rs))
-					return PTR_ERR(rs);
-				if (rs)
-					return 0;
-			}
-			ptr += ALIGN(search_bytes, sizeof(u64));
-		}
-skip:
-		/* Try next bitmap block (wrap back to rgrp header
-		   if at end) */
-		buf++;
-		buf %= length;
-		goal = 0;
-	}
-
-	return BFITNOENT;
 }
 
 /**
- * try_rgrp_fit - See if a given reservation will fit in a given RG
- * @rgd: the RG data
- * @ip: the inode
+ * gfs2_next_unreserved_block - Return next block that is not reserved
+ * @rgd: The resource group
+ * @block: The starting block
+ * @length: The required length
+ * @ip: Ignore any reservations for this inode
  *
- * If there's room for the requested blocks to be allocated from the RG:
- * This will try to get a multi-block reservation first, and if that doesn't
- * fit, it will take what it can.
- *
- * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
+ * If the block does not appear in any reservation, then return the
+ * block number unchanged. If it does appear in the reservation, then
+ * keep looking through the tree of reservations in order to find the
+ * first block number which is not reserved.
  */
 
-static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block,
+				      u32 length,
+				      const struct gfs2_inode *ip)
 {
-	struct gfs2_blkreserv *rs = ip->i_res;
+	struct gfs2_blkreserv *rs;
+	struct rb_node *n;
+	int rc;
 
-	if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
+	spin_lock(&rgd->rd_rsspin);
+	n = rgd->rd_rstree.rb_node;
+	while (n) {
+		rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
+		rc = rs_cmp(block, length, rs);
+		if (rc < 0)
+			n = n->rb_left;
+		else if (rc > 0)
+			n = n->rb_right;
+		else
+			break;
+	}
+
+	if (n) {
+		while ((rs_cmp(block, length, rs) == 0) && (ip->i_res != rs)) {
+			block = gfs2_rbm_to_block(&rs->rs_rbm) + rs->rs_free;
+			n = n->rb_right;
+			if (n == NULL)
+				break;
+			rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
+		}
+	}
+
+	spin_unlock(&rgd->rd_rsspin);
+	return block;
+}
+
+/**
+ * gfs2_reservation_check_and_update - Check for reservations during block alloc
+ * @rbm: The current position in the resource group
+ * @ip: The inode for which we are searching for blocks
+ * @minext: The minimum extent length
+ *
+ * This checks the current position in the rgrp to see whether there is
+ * a reservation covering this block. If not then this function is a
+ * no-op. If there is, then the position is moved to the end of the
+ * contiguous reservation(s) so that we are pointing at the first
+ * non-reserved block.
+ *
+ * Returns: 0 if no reservation, 1 if @rbm has changed, otherwise an error
+ */
+
+static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
+					     const struct gfs2_inode *ip,
+					     u32 minext)
+{
+	u64 block = gfs2_rbm_to_block(rbm);
+	u32 extlen = 1;
+	u64 nblock;
+	int ret;
+
+	/*
+	 * If we have a minimum extent length, then skip over any extent
+	 * which is less than the min extent length in size.
+	 */
+	if (minext) {
+		extlen = gfs2_free_extlen(rbm, minext);
+		nblock = block + extlen;
+		if (extlen < minext)
+			goto fail;
+	}
+
+	/*
+	 * Check the extent which has been found against the reservations
+	 * and skip if parts of it are already reserved
+	 */
+	nblock = gfs2_next_unreserved_block(rbm->rgd, block, extlen, ip);
+	if (nblock == block)
 		return 0;
-	/* Look for a multi-block reservation. */
-	if (unclaimed_blocks(rgd) >= RGRP_RSRV_MINBLKS &&
-	    rg_mblk_search(rgd, ip) != BFITNOENT)
-		return 1;
-	if (unclaimed_blocks(rgd) >= rs->rs_requested)
-		return 1;
+fail:
+	ret = gfs2_rbm_from_block(rbm, nblock);
+	if (ret < 0)
+		return ret;
+	return 1;
+}
 
-	return 0;
+/**
+ * gfs2_rbm_find - Look for blocks of a particular state
+ * @rbm: Value/result starting position and final position
+ * @state: The state which we want to find
+ * @minext: The requested extent length (0 for a single block)
+ * @ip: If set, check for reservations
+ * @nowrap: Stop looking at the end of the rgrp, rather than wrapping
+ *          around until we've reached the starting point.
+ *
+ * Side effects:
+ * - If looking for free blocks, we set GBF_FULL on each bitmap which
+ *   has no free blocks in it.
+ *
+ * Returns: 0 on success, -ENOSPC if there is no block of the requested state
+ */
+
+static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext,
+			 const struct gfs2_inode *ip, bool nowrap)
+{
+	struct buffer_head *bh;
+	struct gfs2_bitmap *initial_bi;
+	u32 initial_offset;
+	u32 offset;
+	u8 *buffer;
+	int index;
+	int n = 0;
+	int iters = rbm->rgd->rd_length;
+	int ret;
+
+	/* If we are not starting at the beginning of a bitmap, then we
+	 * need to add one to the bitmap count to ensure that we search
+	 * the starting bitmap twice.
+	 */
+	if (rbm->offset != 0)
+		iters++;
+
+	while(1) {
+		if (test_bit(GBF_FULL, &rbm->bi->bi_flags) &&
+		    (state == GFS2_BLKST_FREE))
+			goto next_bitmap;
+
+		bh = rbm->bi->bi_bh;
+		buffer = bh->b_data + rbm->bi->bi_offset;
+		WARN_ON(!buffer_uptodate(bh));
+		if (state != GFS2_BLKST_UNLINKED && rbm->bi->bi_clone)
+			buffer = rbm->bi->bi_clone + rbm->bi->bi_offset;
+		initial_offset = rbm->offset;
+		offset = gfs2_bitfit(buffer, rbm->bi->bi_len, rbm->offset, state);
+		if (offset == BFITNOENT)
+			goto bitmap_full;
+		rbm->offset = offset;
+		if (ip == NULL)
+			return 0;
+
+		initial_bi = rbm->bi;
+		ret = gfs2_reservation_check_and_update(rbm, ip, minext);
+		if (ret == 0)
+			return 0;
+		if (ret > 0) {
+			n += (rbm->bi - initial_bi);
+			goto next_iter;
+		}
+		if (ret == -E2BIG) {
+			index = 0;
+			rbm->offset = 0;
+			n += (rbm->bi - initial_bi);
+			goto res_covered_end_of_rgrp;
+		}
+		return ret;
+
+bitmap_full:	/* Mark bitmap as full and fall through */
+		if ((state == GFS2_BLKST_FREE) && initial_offset == 0)
+			set_bit(GBF_FULL, &rbm->bi->bi_flags);
+
+next_bitmap:	/* Find next bitmap in the rgrp */
+		rbm->offset = 0;
+		index = rbm->bi - rbm->rgd->rd_bits;
+		index++;
+		if (index == rbm->rgd->rd_length)
+			index = 0;
+res_covered_end_of_rgrp:
+		rbm->bi = &rbm->rgd->rd_bits[index];
+		if ((index == 0) && nowrap)
+			break;
+		n++;
+next_iter:
+		if (n >= iters)
+			break;
+	}
+
+	return -ENOSPC;
 }
 
 /**
@@ -1489,34 +1616,33 @@
 
 static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip)
 {
-	u32 goal = 0, block;
-	u64 no_addr;
+	u64 block;
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	struct gfs2_glock *gl;
 	struct gfs2_inode *ip;
 	int error;
 	int found = 0;
-	struct gfs2_bitmap *bi;
+	struct gfs2_rbm rbm = { .rgd = rgd, .bi = rgd->rd_bits, .offset = 0 };
 
-	while (goal < rgd->rd_data) {
+	while (1) {
 		down_write(&sdp->sd_log_flush_lock);
-		block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, &bi);
+		error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, 0, NULL, true);
 		up_write(&sdp->sd_log_flush_lock);
-		if (block == BFITNOENT)
+		if (error == -ENOSPC)
+			break;
+		if (WARN_ON_ONCE(error))
 			break;
 
-		block = gfs2_bi2rgd_blk(bi, block);
-		/* rgblk_search can return a block < goal, so we need to
-		   keep it marching forward. */
-		no_addr = block + rgd->rd_data0;
-		goal = max(block + 1, goal + 1);
-		if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
+		block = gfs2_rbm_to_block(&rbm);
+		if (gfs2_rbm_from_block(&rbm, block + 1))
+			break;
+		if (*last_unlinked != NO_BLOCK && block <= *last_unlinked)
 			continue;
-		if (no_addr == skip)
+		if (block == skip)
 			continue;
-		*last_unlinked = no_addr;
+		*last_unlinked = block;
 
-		error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &gl);
+		error = gfs2_glock_get(sdp, block, &gfs2_inode_glops, CREATE, &gl);
 		if (error)
 			continue;
 
@@ -1543,6 +1669,19 @@
 	return;
 }
 
+static bool gfs2_select_rgrp(struct gfs2_rgrpd **pos, const struct gfs2_rgrpd *begin)
+{
+	struct gfs2_rgrpd *rgd = *pos;
+
+	rgd = gfs2_rgrpd_get_next(rgd);
+	if (rgd == NULL)
+		rgd = gfs2_rgrpd_get_next(NULL);
+	*pos = rgd;
+	if (rgd != begin) /* If we didn't wrap */
+		return true;
+	return false;
+}
+
 /**
  * gfs2_inplace_reserve - Reserve space in the filesystem
  * @ip: the inode to reserve space for
@@ -1562,103 +1701,96 @@
 
 	if (sdp->sd_args.ar_rgrplvb)
 		flags |= GL_SKIP;
-	rs->rs_requested = requested;
-	if (gfs2_assert_warn(sdp, requested)) {
-		error = -EINVAL;
-		goto out;
-	}
+	if (gfs2_assert_warn(sdp, requested))
+		return -EINVAL;
 	if (gfs2_rs_active(rs)) {
-		begin = rs->rs_rgd;
+		begin = rs->rs_rbm.rgd;
 		flags = 0; /* Yoda: Do or do not. There is no try */
 	} else if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal)) {
-		rs->rs_rgd = begin = ip->i_rgd;
+		rs->rs_rbm.rgd = begin = ip->i_rgd;
 	} else {
-		rs->rs_rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
+		rs->rs_rbm.rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
 	}
-	if (rs->rs_rgd == NULL)
+	if (rs->rs_rbm.rgd == NULL)
 		return -EBADSLT;
 
 	while (loops < 3) {
-		rg_locked = 0;
+		rg_locked = 1;
 
-		if (gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl)) {
-			rg_locked = 1;
-			error = 0;
-		} else if (!loops && !gfs2_rs_active(rs) &&
-			   rs->rs_rgd->rd_rs_cnt > RGRP_RSRV_MAX_CONTENDERS) {
-			/* If the rgrp already is maxed out for contenders,
-			   we can eliminate it as a "first pass" without even
-			   requesting the rgrp glock. */
-			error = GLR_TRYFAILED;
-		} else {
-			error = gfs2_glock_nq_init(rs->rs_rgd->rd_gl,
+		if (!gfs2_glock_is_locked_by_me(rs->rs_rbm.rgd->rd_gl)) {
+			rg_locked = 0;
+			error = gfs2_glock_nq_init(rs->rs_rbm.rgd->rd_gl,
 						   LM_ST_EXCLUSIVE, flags,
 						   &rs->rs_rgd_gh);
-			if (!error && sdp->sd_args.ar_rgrplvb) {
-				error = update_rgrp_lvb(rs->rs_rgd);
-				if (error) {
+			if (error == GLR_TRYFAILED)
+				goto next_rgrp;
+			if (unlikely(error))
+				return error;
+			if (sdp->sd_args.ar_rgrplvb) {
+				error = update_rgrp_lvb(rs->rs_rbm.rgd);
+				if (unlikely(error)) {
 					gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
 					return error;
 				}
 			}
 		}
-		switch (error) {
-		case 0:
-			if (gfs2_rs_active(rs)) {
-				if (unclaimed_blocks(rs->rs_rgd) +
-				    rs->rs_free >= rs->rs_requested) {
-					ip->i_rgd = rs->rs_rgd;
-					return 0;
-				}
-				/* We have a multi-block reservation, but the
-				   rgrp doesn't have enough free blocks to
-				   satisfy the request. Free the reservation
-				   and look for a suitable rgrp. */
-				gfs2_rs_deltree(rs);
-			}
-			if (try_rgrp_fit(rs->rs_rgd, ip)) {
-				if (sdp->sd_args.ar_rgrplvb)
-					gfs2_rgrp_bh_get(rs->rs_rgd);
-				ip->i_rgd = rs->rs_rgd;
-				return 0;
-			}
-			if (rs->rs_rgd->rd_flags & GFS2_RDF_CHECK) {
-				if (sdp->sd_args.ar_rgrplvb)
-					gfs2_rgrp_bh_get(rs->rs_rgd);
-				try_rgrp_unlink(rs->rs_rgd, &last_unlinked,
-						ip->i_no_addr);
-			}
-			if (!rg_locked)
-				gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
-			/* fall through */
-		case GLR_TRYFAILED:
-			rs->rs_rgd = gfs2_rgrpd_get_next(rs->rs_rgd);
-			rs->rs_rgd = rs->rs_rgd ? : begin; /* if NULL, wrap */
-			if (rs->rs_rgd != begin) /* If we didn't wrap */
-				break;
 
-			flags &= ~LM_FLAG_TRY;
-			loops++;
-			/* Check that fs hasn't grown if writing to rindex */
-			if (ip == GFS2_I(sdp->sd_rindex) &&
-			    !sdp->sd_rindex_uptodate) {
-				error = gfs2_ri_update(ip);
-				if (error)
-					goto out;
-			} else if (loops == 2)
-				/* Flushing the log may release space */
-				gfs2_log_flush(sdp, NULL);
-			break;
-		default:
-			goto out;
+		/* Skip unuseable resource groups */
+		if (rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
+			goto skip_rgrp;
+
+		if (sdp->sd_args.ar_rgrplvb)
+			gfs2_rgrp_bh_get(rs->rs_rbm.rgd);
+
+		/* Get a reservation if we don't already have one */
+		if (!gfs2_rs_active(rs))
+			rg_mblk_search(rs->rs_rbm.rgd, ip, requested);
+
+		/* Skip rgrps when we can't get a reservation on first pass */
+		if (!gfs2_rs_active(rs) && (loops < 1))
+			goto check_rgrp;
+
+		/* If rgrp has enough free space, use it */
+		if (rs->rs_rbm.rgd->rd_free_clone >= requested) {
+			ip->i_rgd = rs->rs_rbm.rgd;
+			return 0;
 		}
-	}
-	error = -ENOSPC;
 
-out:
-	if (error)
-		rs->rs_requested = 0;
-	return error;
+		/* Drop reservation, if we couldn't use reserved rgrp */
+		if (gfs2_rs_active(rs))
+			gfs2_rs_deltree(ip, rs);
+check_rgrp:
+		/* Check for unlinked inodes which can be reclaimed */
+		if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK)
+			try_rgrp_unlink(rs->rs_rbm.rgd, &last_unlinked,
+					ip->i_no_addr);
+skip_rgrp:
+		/* Unlock rgrp if required */
+		if (!rg_locked)
+			gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
+next_rgrp:
+		/* Find the next rgrp, and continue looking */
+		if (gfs2_select_rgrp(&rs->rs_rbm.rgd, begin))
+			continue;
+
+		/* If we've scanned all the rgrps, but found no free blocks
+		 * then this checks for some less likely conditions before
+		 * trying again.
+		 */
+		flags &= ~LM_FLAG_TRY;
+		loops++;
+		/* Check that fs hasn't grown if writing to rindex */
+		if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
+			error = gfs2_ri_update(ip);
+			if (error)
+				return error;
+		}
+		/* Flushing the log may release space */
+		if (loops == 2)
+			gfs2_log_flush(sdp, NULL);
+	}
+
+	return -ENOSPC;
 }
 
 /**
@@ -1672,15 +1804,8 @@
 {
 	struct gfs2_blkreserv *rs = ip->i_res;
 
-	if (!rs)
-		return;
-
-	if (!rs->rs_free)
-		gfs2_rs_deltree(rs);
-
 	if (rs->rs_rgd_gh.gh_gl)
 		gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
-	rs->rs_requested = 0;
 }
 
 /**
@@ -1693,173 +1818,47 @@
 
 static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
 {
-	struct gfs2_bitmap *bi = NULL;
-	u32 length, rgrp_block, buf_block;
-	unsigned int buf;
-	unsigned char type;
+	struct gfs2_rbm rbm = { .rgd = rgd, };
+	int ret;
 
-	length = rgd->rd_length;
-	rgrp_block = block - rgd->rd_data0;
+	ret = gfs2_rbm_from_block(&rbm, block);
+	WARN_ON_ONCE(ret != 0);
 
-	for (buf = 0; buf < length; buf++) {
-		bi = rgd->rd_bits + buf;
-		if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
-			break;
-	}
-
-	gfs2_assert(rgd->rd_sbd, buf < length);
-	buf_block = rgrp_block - bi->bi_start * GFS2_NBBY;
-
-	type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
-			   bi->bi_len, buf_block);
-
-	return type;
+	return gfs2_testbit(&rbm);
 }
 
-/**
- * rgblk_search - find a block in @state
- * @rgd: the resource group descriptor
- * @goal: the goal block within the RG (start here to search for avail block)
- * @state: GFS2_BLKST_XXX the before-allocation state to find
- * @rbi: address of the pointer to the bitmap containing the block found
- *
- * Walk rgrp's bitmap to find bits that represent a block in @state.
- *
- * This function never fails, because we wouldn't call it unless we
- * know (from reservation results, etc.) that a block is available.
- *
- * Scope of @goal is just within rgrp, not the whole filesystem.
- * Scope of @returned block is just within bitmap, not the whole filesystem.
- *
- * Returns: the block number found relative to the bitmap rbi
- */
-
-static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, unsigned char state,
-			struct gfs2_bitmap **rbi)
-{
-	struct gfs2_bitmap *bi = NULL;
-	const u32 length = rgd->rd_length;
-	u32 biblk = BFITNOENT;
-	unsigned int buf, x;
-	const u8 *buffer = NULL;
-
-	*rbi = NULL;
-	/* Find bitmap block that contains bits for goal block */
-	for (buf = 0; buf < length; buf++) {
-		bi = rgd->rd_bits + buf;
-		/* Convert scope of "goal" from rgrp-wide to within found bit block */
-		if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY) {
-			goal -= bi->bi_start * GFS2_NBBY;
-			goto do_search;
-		}
-	}
-	buf = 0;
-	goal = 0;
-
-do_search:
-	/* Search (up to entire) bitmap in this rgrp for allocatable block.
-	   "x <= length", instead of "x < length", because we typically start
-	   the search in the middle of a bit block, but if we can't find an
-	   allocatable block anywhere else, we want to be able wrap around and
-	   search in the first part of our first-searched bit block.  */
-	for (x = 0; x <= length; x++) {
-		bi = rgd->rd_bits + buf;
-
-		if (test_bit(GBF_FULL, &bi->bi_flags) &&
-		    (state == GFS2_BLKST_FREE))
-			goto skip;
-
-		/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
-		   bitmaps, so we must search the originals for that. */
-		buffer = bi->bi_bh->b_data + bi->bi_offset;
-		WARN_ON(!buffer_uptodate(bi->bi_bh));
-		if (state != GFS2_BLKST_UNLINKED && bi->bi_clone)
-			buffer = bi->bi_clone + bi->bi_offset;
-
-		while (1) {
-			struct gfs2_blkreserv *rs;
-			u32 rgblk;
-
-			biblk = gfs2_bitfit(buffer, bi->bi_len, goal, state);
-			if (biblk == BFITNOENT)
-				break;
-			/* Check if this block is reserved() */
-			rgblk = gfs2_bi2rgd_blk(bi, biblk);
-			rs = rs_find(rgd, rgblk);
-			if (rs == NULL)
-				break;
-
-			BUG_ON(rs->rs_bi != bi);
-			biblk = BFITNOENT;
-			/* This should jump to the first block after the
-			   reservation. */
-			goal = rs->rs_biblk + rs->rs_free;
-			if (goal >= bi->bi_len * GFS2_NBBY)
-				break;
-		}
-		if (biblk != BFITNOENT)
-			break;
-
-		if ((goal == 0) && (state == GFS2_BLKST_FREE))
-			set_bit(GBF_FULL, &bi->bi_flags);
-
-		/* Try next bitmap block (wrap back to rgrp header if at end) */
-skip:
-		buf++;
-		buf %= length;
-		goal = 0;
-	}
-
-	if (biblk != BFITNOENT)
-		*rbi = bi;
-
-	return biblk;
-}
 
 /**
  * gfs2_alloc_extent - allocate an extent from a given bitmap
- * @rgd: the resource group descriptor
- * @bi: the bitmap within the rgrp
- * @blk: the block within the bitmap
+ * @rbm: the resource group information
  * @dinode: TRUE if the first block we allocate is for a dinode
- * @n: The extent length
+ * @n: The extent length (value/result)
  *
- * Add the found bitmap buffer to the transaction.
+ * Add the bitmap buffer to the transaction.
  * Set the found bits to @new_state to change block's allocation state.
- * Returns: starting block number of the extent (fs scope)
  */
-static u64 gfs2_alloc_extent(struct gfs2_rgrpd *rgd, struct gfs2_bitmap *bi,
-			     u32 blk, bool dinode, unsigned int *n)
+static void gfs2_alloc_extent(const struct gfs2_rbm *rbm, bool dinode,
+			     unsigned int *n)
 {
+	struct gfs2_rbm pos = { .rgd = rbm->rgd, };
 	const unsigned int elen = *n;
-	u32 goal, rgblk;
-	const u8 *buffer = NULL;
-	struct gfs2_blkreserv *rs;
+	u64 block;
+	int ret;
 
-	*n = 0;
-	buffer = bi->bi_bh->b_data + bi->bi_offset;
-	gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-	gfs2_setbit(rgd, bi->bi_clone, bi, blk,
-		    dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
-	(*n)++;
-	goal = blk;
+	*n = 1;
+	block = gfs2_rbm_to_block(rbm);
+	gfs2_trans_add_bh(rbm->rgd->rd_gl, rbm->bi->bi_bh, 1);
+	gfs2_setbit(rbm, true, dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
+	block++;
 	while (*n < elen) {
-		goal++;
-		if (goal >= (bi->bi_len * GFS2_NBBY))
+		ret = gfs2_rbm_from_block(&pos, block);
+		if (ret || gfs2_testbit(&pos) != GFS2_BLKST_FREE)
 			break;
-		rgblk = gfs2_bi2rgd_blk(bi, goal);
-		rs = rs_find(rgd, rgblk);
-		if (rs) /* Oops, we bumped into someone's reservation */
-			break;
-		if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
-		    GFS2_BLKST_FREE)
-			break;
-		gfs2_setbit(rgd, bi->bi_clone, bi, goal, GFS2_BLKST_USED);
+		gfs2_trans_add_bh(pos.rgd->rd_gl, pos.bi->bi_bh, 1);
+		gfs2_setbit(&pos, true, GFS2_BLKST_USED);
 		(*n)++;
+		block++;
 	}
-	blk = gfs2_bi2rgd_blk(bi, blk);
-	rgd->rd_last_alloc = blk + *n - 1;
-	return rgd->rd_data0 + blk;
 }
 
 /**
@@ -1875,46 +1874,30 @@
 static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
 				     u32 blen, unsigned char new_state)
 {
-	struct gfs2_rgrpd *rgd;
-	struct gfs2_bitmap *bi = NULL;
-	u32 length, rgrp_blk, buf_blk;
-	unsigned int buf;
+	struct gfs2_rbm rbm;
 
-	rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
-	if (!rgd) {
+	rbm.rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
+	if (!rbm.rgd) {
 		if (gfs2_consist(sdp))
 			fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
 		return NULL;
 	}
 
-	length = rgd->rd_length;
-
-	rgrp_blk = bstart - rgd->rd_data0;
-
 	while (blen--) {
-		for (buf = 0; buf < length; buf++) {
-			bi = rgd->rd_bits + buf;
-			if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
-				break;
+		gfs2_rbm_from_block(&rbm, bstart);
+		bstart++;
+		if (!rbm.bi->bi_clone) {
+			rbm.bi->bi_clone = kmalloc(rbm.bi->bi_bh->b_size,
+						   GFP_NOFS | __GFP_NOFAIL);
+			memcpy(rbm.bi->bi_clone + rbm.bi->bi_offset,
+			       rbm.bi->bi_bh->b_data + rbm.bi->bi_offset,
+			       rbm.bi->bi_len);
 		}
-
-		gfs2_assert(rgd->rd_sbd, buf < length);
-
-		buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY;
-		rgrp_blk++;
-
-		if (!bi->bi_clone) {
-			bi->bi_clone = kmalloc(bi->bi_bh->b_size,
-					       GFP_NOFS | __GFP_NOFAIL);
-			memcpy(bi->bi_clone + bi->bi_offset,
-			       bi->bi_bh->b_data + bi->bi_offset,
-			       bi->bi_len);
-		}
-		gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-		gfs2_setbit(rgd, NULL, bi, buf_blk, new_state);
+		gfs2_trans_add_bh(rbm.rgd->rd_gl, rbm.bi->bi_bh, 1);
+		gfs2_setbit(&rbm, false, new_state);
 	}
 
-	return rgd;
+	return rbm.rgd;
 }
 
 /**
@@ -1956,46 +1939,41 @@
 }
 
 /**
- * claim_reserved_blks - Claim previously reserved blocks
- * @ip: the inode that's claiming the reservation
- * @dinode: 1 if this block is a dinode block, otherwise data block
- * @nblocks: desired extent length
+ * gfs2_adjust_reservation - Adjust (or remove) a reservation after allocation
+ * @ip: The inode we have just allocated blocks for
+ * @rbm: The start of the allocated blocks
+ * @len: The extent length
  *
- * Lay claim to previously reserved blocks.
- * Returns: Starting block number of the blocks claimed.
- * Sets *nblocks to the actual extent length allocated.
+ * Adjusts a reservation after an allocation has taken place. If the
+ * reservation does not match the allocation, or if it is now empty
+ * then it is removed.
  */
-static u64 claim_reserved_blks(struct gfs2_inode *ip, bool dinode,
-			       unsigned int *nblocks)
+
+static void gfs2_adjust_reservation(struct gfs2_inode *ip,
+				    const struct gfs2_rbm *rbm, unsigned len)
 {
 	struct gfs2_blkreserv *rs = ip->i_res;
-	struct gfs2_rgrpd *rgd = rs->rs_rgd;
-	struct gfs2_bitmap *bi;
-	u64 start_block = gfs2_rs_startblk(rs);
-	const unsigned int elen = *nblocks;
+	struct gfs2_rgrpd *rgd = rbm->rgd;
+	unsigned rlen;
+	u64 block;
+	int ret;
 
-	bi = rs->rs_bi;
-	gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-
-	for (*nblocks = 0; *nblocks < elen && rs->rs_free; (*nblocks)++) {
-		if (gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
-				 bi->bi_len, rs->rs_biblk) != GFS2_BLKST_FREE)
-			break;
-		gfs2_setbit(rgd, bi->bi_clone, bi, rs->rs_biblk,
-			    dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
-		rs->rs_biblk++;
-		rs->rs_free--;
-
-		BUG_ON(!rgd->rd_reserved);
-		rgd->rd_reserved--;
-		dinode = false;
+	spin_lock(&rgd->rd_rsspin);
+	if (gfs2_rs_active(rs)) {
+		if (gfs2_rbm_eq(&rs->rs_rbm, rbm)) {
+			block = gfs2_rbm_to_block(rbm);
+			ret = gfs2_rbm_from_block(&rs->rs_rbm, block + len);
+			rlen = min(rs->rs_free, len);
+			rs->rs_free -= rlen;
+			rgd->rd_reserved -= rlen;
+			trace_gfs2_rs(rs, TRACE_RS_CLAIM);
+			if (rs->rs_free && !ret)
+				goto out;
+		}
+		__rs_deltree(ip, rs);
 	}
-
-	trace_gfs2_rs(ip, rs, TRACE_RS_CLAIM);
-	if (!rs->rs_free || *nblocks != elen)
-		gfs2_rs_deltree(rs);
-
-	return start_block;
+out:
+	spin_unlock(&rgd->rd_rsspin);
 }
 
 /**
@@ -2014,47 +1992,40 @@
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	struct buffer_head *dibh;
-	struct gfs2_rgrpd *rgd;
+	struct gfs2_rbm rbm = { .rgd = ip->i_rgd, };
 	unsigned int ndata;
-	u32 goal, blk; /* block, within the rgrp scope */
+	u64 goal;
 	u64 block; /* block, within the file system scope */
 	int error;
-	struct gfs2_bitmap *bi;
 
-	/* Only happens if there is a bug in gfs2, return something distinctive
-	 * to ensure that it is noticed.
-	 */
-	if (ip->i_res->rs_requested == 0)
-		return -ECANCELED;
+	if (gfs2_rs_active(ip->i_res))
+		goal = gfs2_rbm_to_block(&ip->i_res->rs_rbm);
+	else if (!dinode && rgrp_contains_block(rbm.rgd, ip->i_goal))
+		goal = ip->i_goal;
+	else
+		goal = rbm.rgd->rd_last_alloc + rbm.rgd->rd_data0;
 
-	/* If we have a reservation, claim blocks from it. */
-	if (gfs2_rs_active(ip->i_res)) {
-		BUG_ON(!ip->i_res->rs_free);
-		rgd = ip->i_res->rs_rgd;
-		block = claim_reserved_blks(ip, dinode, nblocks);
-		if (*nblocks)
-			goto found_blocks;
+	gfs2_rbm_from_block(&rbm, goal);
+	error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, 0, ip, false);
+
+	if (error == -ENOSPC) {
+		gfs2_rbm_from_block(&rbm, goal);
+		error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, 0, NULL, false);
 	}
 
-	rgd = ip->i_rgd;
-
-	if (!dinode && rgrp_contains_block(rgd, ip->i_goal))
-		goal = ip->i_goal - rgd->rd_data0;
-	else
-		goal = rgd->rd_last_alloc;
-
-	blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, &bi);
-
 	/* Since all blocks are reserved in advance, this shouldn't happen */
-	if (blk == BFITNOENT) {
-		printk(KERN_WARNING "BFITNOENT, nblocks=%u\n", *nblocks);
-		printk(KERN_WARNING "FULL=%d\n",
-		       test_bit(GBF_FULL, &rgd->rd_bits->bi_flags));
+	if (error) {
+		fs_warn(sdp, "inum=%llu error=%d, nblocks=%u, full=%d\n",
+			(unsigned long long)ip->i_no_addr, error, *nblocks,
+			test_bit(GBF_FULL, &rbm.rgd->rd_bits->bi_flags));
 		goto rgrp_error;
 	}
 
-	block = gfs2_alloc_extent(rgd, bi, blk, dinode, nblocks);
-found_blocks:
+	gfs2_alloc_extent(&rbm, dinode, nblocks);
+	block = gfs2_rbm_to_block(&rbm);
+	rbm.rgd->rd_last_alloc = block - rbm.rgd->rd_data0;
+	if (gfs2_rs_active(ip->i_res))
+		gfs2_adjust_reservation(ip, &rbm, *nblocks);
 	ndata = *nblocks;
 	if (dinode)
 		ndata--;
@@ -2071,22 +2042,22 @@
 			brelse(dibh);
 		}
 	}
-	if (rgd->rd_free < *nblocks) {
+	if (rbm.rgd->rd_free < *nblocks) {
 		printk(KERN_WARNING "nblocks=%u\n", *nblocks);
 		goto rgrp_error;
 	}
 
-	rgd->rd_free -= *nblocks;
+	rbm.rgd->rd_free -= *nblocks;
 	if (dinode) {
-		rgd->rd_dinodes++;
-		*generation = rgd->rd_igeneration++;
+		rbm.rgd->rd_dinodes++;
+		*generation = rbm.rgd->rd_igeneration++;
 		if (*generation == 0)
-			*generation = rgd->rd_igeneration++;
+			*generation = rbm.rgd->rd_igeneration++;
 	}
 
-	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
-	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
-	gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_trans_add_bh(rbm.rgd->rd_gl, rbm.rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(rbm.rgd, rbm.rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_rgrp_ondisk2lvb(rbm.rgd->rd_rgl, rbm.rgd->rd_bits[0].bi_bh->b_data);
 
 	gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0);
 	if (dinode)
@@ -2100,14 +2071,14 @@
 		gfs2_quota_change(ip, ndata, ip->i_inode.i_uid,
 				  ip->i_inode.i_gid);
 
-	rgd->rd_free_clone -= *nblocks;
-	trace_gfs2_block_alloc(ip, rgd, block, *nblocks,
+	rbm.rgd->rd_free_clone -= *nblocks;
+	trace_gfs2_block_alloc(ip, rbm.rgd, block, *nblocks,
 			       dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
 	*bn = block;
 	return 0;
 
 rgrp_error:
-	gfs2_rgrp_error(rgd);
+	gfs2_rgrp_error(rbm.rgd);
 	return -EIO;
 }
 
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index ca6e267..2407795 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -46,7 +46,7 @@
 			     bool dinode, u64 *generation);
 
 extern int gfs2_rs_alloc(struct gfs2_inode *ip);
-extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
+extern void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs);
 extern void gfs2_rs_delete(struct gfs2_inode *ip);
 extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
 extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
@@ -73,30 +73,10 @@
 				   const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
 extern int gfs2_fitrim(struct file *filp, void __user *argp);
 
-/* This is how to tell if a multi-block reservation is "inplace" reserved: */
-static inline int gfs2_mb_reserved(struct gfs2_inode *ip)
+/* This is how to tell if a reservation is in the rgrp tree: */
+static inline bool gfs2_rs_active(struct gfs2_blkreserv *rs)
 {
-	if (ip->i_res && ip->i_res->rs_requested)
-		return 1;
-	return 0;
-}
-
-/* This is how to tell if a multi-block reservation is in the rgrp tree: */
-static inline int gfs2_rs_active(struct gfs2_blkreserv *rs)
-{
-	if (rs && rs->rs_bi)
-		return 1;
-	return 0;
-}
-
-static inline u32 gfs2_bi2rgd_blk(const struct gfs2_bitmap *bi, u32 blk)
-{
-	return (bi->bi_start * GFS2_NBBY) + blk;
-}
-
-static inline u64 gfs2_rs_startblk(const struct gfs2_blkreserv *rs)
-{
-	return gfs2_bi2rgd_blk(rs->rs_bi, rs->rs_biblk) + rs->rs_rgd->rd_data0;
+	return rs && !RB_EMPTY_NODE(&rs->rs_node);
 }
 
 #endif /* __RGRP_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index fc3168f..a8d90f2 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1366,6 +1366,8 @@
 	val = sdp->sd_tune.gt_statfs_quantum;
 	if (val != 30)
 		seq_printf(s, ",statfs_quantum=%d", val);
+	else if (sdp->sd_tune.gt_statfs_slow)
+		seq_puts(s, ",statfs_quantum=0");
 	val = sdp->sd_tune.gt_quota_quantum;
 	if (val != 60)
 		seq_printf(s, ",quota_quantum=%d", val);
@@ -1543,6 +1545,11 @@
 
 out_truncate:
 	gfs2_log_flush(sdp, ip->i_gl);
+	if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) {
+		struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
+		filemap_fdatawrite(metamapping);
+		filemap_fdatawait(metamapping);
+	}
 	write_inode_now(inode, 1);
 	gfs2_ail_flush(ip->i_gl, 0);
 
@@ -1557,7 +1564,7 @@
 out_unlock:
 	/* Error path for case 1 */
 	if (gfs2_rs_active(ip->i_res))
-		gfs2_rs_deltree(ip->i_res);
+		gfs2_rs_deltree(ip, ip->i_res);
 
 	if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
 		gfs2_glock_dq(&ip->i_iopen_gh);
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index a25c252f..bbdc78a 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -509,10 +509,9 @@
 /* Keep track of multi-block reservations as they are allocated/freed */
 TRACE_EVENT(gfs2_rs,
 
-	TP_PROTO(const struct gfs2_inode *ip, const struct gfs2_blkreserv *rs,
-		 u8 func),
+	TP_PROTO(const struct gfs2_blkreserv *rs, u8 func),
 
-	TP_ARGS(ip, rs, func),
+	TP_ARGS(rs, func),
 
 	TP_STRUCT__entry(
 		__field(        dev_t,  dev                     )
@@ -526,18 +525,17 @@
 	),
 
 	TP_fast_assign(
-		__entry->dev		= rs->rs_rgd ? rs->rs_rgd->rd_sbd->sd_vfs->s_dev : 0;
-		__entry->rd_addr	= rs->rs_rgd ? rs->rs_rgd->rd_addr : 0;
-		__entry->rd_free_clone	= rs->rs_rgd ? rs->rs_rgd->rd_free_clone : 0;
-		__entry->rd_reserved	= rs->rs_rgd ? rs->rs_rgd->rd_reserved : 0;
-		__entry->inum		= ip ? ip->i_no_addr : 0;
-		__entry->start		= gfs2_rs_startblk(rs);
+		__entry->dev		= rs->rs_rbm.rgd->rd_sbd->sd_vfs->s_dev;
+		__entry->rd_addr	= rs->rs_rbm.rgd->rd_addr;
+		__entry->rd_free_clone	= rs->rs_rbm.rgd->rd_free_clone;
+		__entry->rd_reserved	= rs->rs_rbm.rgd->rd_reserved;
+		__entry->inum		= rs->rs_inum;
+		__entry->start		= gfs2_rbm_to_block(&rs->rs_rbm);
 		__entry->free		= rs->rs_free;
 		__entry->func		= func;
 	),
 
-	TP_printk("%u,%u bmap %llu resrv %llu rg:%llu rf:%lu rr:%lu %s "
-		  "f:%lu",
+	TP_printk("%u,%u bmap %llu resrv %llu rg:%llu rf:%lu rr:%lu %s f:%lu",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  (unsigned long long)__entry->inum,
 		  (unsigned long long)__entry->start,
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index 41f42cd..bf2ae9a 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -28,11 +28,10 @@
 
 /* reserve either the number of blocks to be allocated plus the rg header
  * block, or all of the blocks in the rg, whichever is smaller */
-static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
+static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip, unsigned requested)
 {
-	const struct gfs2_blkreserv *rs = ip->i_res;
-	if (rs && rs->rs_requested < ip->i_rgd->rd_length)
-		return rs->rs_requested + 1;
+	if (requested < ip->i_rgd->rd_length)
+		return requested + 1;
 	return ip->i_rgd->rd_length;
 }
 
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 27a0b4a..db330e5 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -448,17 +448,18 @@
 }
 
 /**
- * ea_get_unstuffed - actually copies the unstuffed data into the
- *                    request buffer
+ * ea_iter_unstuffed - copies the unstuffed xattr data to/from the
+ *                     request buffer
  * @ip: The GFS2 inode
  * @ea: The extended attribute header structure
- * @data: The data to be copied
+ * @din: The data to be copied in
+ * @dout: The data to be copied out (one of din,dout will be NULL)
  *
  * Returns: errno
  */
 
-static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
-			    char *data)
+static int gfs2_iter_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+			       const char *din, char *dout)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	struct buffer_head **bh;
@@ -467,6 +468,8 @@
 	__be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
 	unsigned int x;
 	int error = 0;
+	unsigned char *pos;
+	unsigned cp_size;
 
 	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
 	if (!bh)
@@ -497,12 +500,21 @@
 			goto out;
 		}
 
-		memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
-		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+		pos = bh[x]->b_data + sizeof(struct gfs2_meta_header);
+		cp_size = (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize;
+
+		if (dout) {
+			memcpy(dout, pos, cp_size);
+			dout += sdp->sd_jbsize;
+		}
+
+		if (din) {
+			gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
+			memcpy(pos, din, cp_size);
+			din += sdp->sd_jbsize;
+		}
 
 		amount -= sdp->sd_jbsize;
-		data += sdp->sd_jbsize;
-
 		brelse(bh[x]);
 	}
 
@@ -523,7 +535,7 @@
 		memcpy(data, GFS2_EA2DATA(el->el_ea), len);
 		return len;
 	}
-	ret = ea_get_unstuffed(ip, el->el_ea, data);
+	ret = gfs2_iter_unstuffed(ip, el->el_ea, NULL, data);
 	if (ret < 0)
 		return ret;
 	return len;
@@ -727,7 +739,7 @@
 		goto out_gunlock_q;
 
 	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
-				 blks + gfs2_rg_blocks(ip) +
+				 blks + gfs2_rg_blocks(ip, blks) +
 				 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
 	if (error)
 		goto out_ipres;
@@ -1220,69 +1232,23 @@
 				size, flags, type);
 }
 
+
 static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
 				  struct gfs2_ea_header *ea, char *data)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct buffer_head **bh;
 	unsigned int amount = GFS2_EA_DATA_LEN(ea);
 	unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
-	__be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
-	unsigned int x;
-	int error;
+	int ret;
 
-	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
-	if (!bh)
-		return -ENOMEM;
+	ret = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
+	if (ret)
+		return ret;
 
-	error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
-	if (error)
-		goto out;
-
-	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
-				       bh + x);
-		if (error) {
-			while (x--)
-				brelse(bh[x]);
-			goto fail;
-		}
-		dataptrs++;
-	}
-
-	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_wait(sdp, bh[x]);
-		if (error) {
-			for (; x < nptrs; x++)
-				brelse(bh[x]);
-			goto fail;
-		}
-		if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
-			for (; x < nptrs; x++)
-				brelse(bh[x]);
-			error = -EIO;
-			goto fail;
-		}
-
-		gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
-
-		memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
-		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
-
-		amount -= sdp->sd_jbsize;
-		data += sdp->sd_jbsize;
-
-		brelse(bh[x]);
-	}
-
-out:
-	kfree(bh);
-	return error;
-
-fail:
+	ret = gfs2_iter_unstuffed(ip, ea, data, NULL);
 	gfs2_trans_end(sdp);
-	kfree(bh);
-	return error;
+
+	return ret;
 }
 
 int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
diff --git a/fs/libfs.c b/fs/libfs.c
index a74cb172..7cc37ca 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -874,7 +874,7 @@
 EXPORT_SYMBOL_GPL(generic_fh_to_dentry);
 
 /**
- * generic_fh_to_dentry - generic helper for the fh_to_parent export operation
+ * generic_fh_to_parent - generic helper for the fh_to_parent export operation
  * @sb:		filesystem to do the file handle conversion on
  * @fid:	file handle to convert
  * @fh_len:	length of the file handle in bytes
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index fb1a2be..8d80c990d 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -289,7 +289,6 @@
 	dprintk("lockd: freeing block %p...\n", block);
 
 	/* Remove block from file's list of blocks */
-	mutex_lock(&file->f_mutex);
 	list_del_init(&block->b_flist);
 	mutex_unlock(&file->f_mutex);
 
@@ -303,7 +302,7 @@
 static void nlmsvc_release_block(struct nlm_block *block)
 {
 	if (block != NULL)
-		kref_put(&block->b_count, nlmsvc_free_block);
+		kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex);
 }
 
 /*
diff --git a/fs/namespace.c b/fs/namespace.c
index 4d31f73..7bdf790 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1886,8 +1886,14 @@
 		return err;
 
 	err = -EINVAL;
-	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt)))
-		goto unlock;
+	if (unlikely(!check_mnt(real_mount(path->mnt)))) {
+		/* that's acceptable only for automounts done in private ns */
+		if (!(mnt_flags & MNT_SHRINKABLE))
+			goto unlock;
+		/* ... and for those we'd better have mountpoint still alive */
+		if (!real_mount(path->mnt)->mnt_ns)
+			goto unlock;
+	}
 
 	/* Refuse the same filesystem on the same mount point */
 	err = -EBUSY;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b8eda70..d2c7f5d 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1537,7 +1537,7 @@
 
 	/*
 	 * verify that any proto=/mountproto= options match the address
-	 * familiies in the addr=/mountaddr= options.
+	 * families in the addr=/mountaddr= options.
 	 */
 	if (protofamily != AF_UNSPEC &&
 	    protofamily != mnt->nfs_server.address.ss_family)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index dfafeb2..eb7cc91 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -462,9 +462,6 @@
 
 	err = ERR_PTR(-ENOMEM);
 	inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
-	if (h)
-		sysctl_head_finish(h);
-
 	if (!inode)
 		goto out;
 
@@ -473,6 +470,8 @@
 	d_add(dentry, inode);
 
 out:
+	if (h)
+		sysctl_head_finish(h);
 	sysctl_head_finish(head);
 	return err;
 }
diff --git a/fs/stat.c b/fs/stat.c
index 4078022..208039e 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -326,7 +326,7 @@
 
 
 /* ---------- LFS-64 ----------- */
-#ifdef __ARCH_WANT_STAT64
+#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64)
 
 #ifndef INIT_STRUCT_STAT64_PADDING
 #  define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st))
@@ -415,7 +415,7 @@
 		return error;
 	return cp_new_stat64(&stat, statbuf);
 }
-#endif /* __ARCH_WANT_STAT64 */
+#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
 
 /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
 void __inode_add_bytes(struct inode *inode, loff_t bytes)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index a7ac78f..3c9eb56 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -113,7 +113,7 @@
  *	@target:	object we're pointing to.
  *	@name:		name of the symlink.
  *
- *	This function does the same as sysf_create_link(), but it
+ *	This function does the same as sysfs_create_link(), but it
  *	doesn't warn if the link already exists.
  */
 int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index d7a9dd7..933b793 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -96,6 +96,7 @@
 		atomic_inc(&bp->b_hold);
 		list_add_tail(&bp->b_lru, &btp->bt_lru);
 		btp->bt_lru_nr++;
+		bp->b_lru_flags &= ~_XBF_LRU_DISPOSE;
 	}
 	spin_unlock(&btp->bt_lru_lock);
 }
@@ -154,7 +155,8 @@
 		struct xfs_buftarg *btp = bp->b_target;
 
 		spin_lock(&btp->bt_lru_lock);
-		if (!list_empty(&bp->b_lru)) {
+		if (!list_empty(&bp->b_lru) &&
+		    !(bp->b_lru_flags & _XBF_LRU_DISPOSE)) {
 			list_del_init(&bp->b_lru);
 			btp->bt_lru_nr--;
 			atomic_dec(&bp->b_hold);
@@ -1501,6 +1503,7 @@
 		 */
 		list_move(&bp->b_lru, &dispose);
 		btp->bt_lru_nr--;
+		bp->b_lru_flags |= _XBF_LRU_DISPOSE;
 	}
 	spin_unlock(&btp->bt_lru_lock);
 
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index d03b73b..7c0b6a0 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -38,27 +38,28 @@
 	XBRW_ZERO = 3,			/* Zero target memory */
 } xfs_buf_rw_t;
 
-#define XBF_READ	(1 << 0) /* buffer intended for reading from device */
-#define XBF_WRITE	(1 << 1) /* buffer intended for writing to device */
-#define XBF_READ_AHEAD	(1 << 2) /* asynchronous read-ahead */
-#define XBF_ASYNC	(1 << 4) /* initiator will not wait for completion */
-#define XBF_DONE	(1 << 5) /* all pages in the buffer uptodate */
-#define XBF_STALE	(1 << 6) /* buffer has been staled, do not find it */
+#define XBF_READ	 (1 << 0) /* buffer intended for reading from device */
+#define XBF_WRITE	 (1 << 1) /* buffer intended for writing to device */
+#define XBF_READ_AHEAD	 (1 << 2) /* asynchronous read-ahead */
+#define XBF_ASYNC	 (1 << 4) /* initiator will not wait for completion */
+#define XBF_DONE	 (1 << 5) /* all pages in the buffer uptodate */
+#define XBF_STALE	 (1 << 6) /* buffer has been staled, do not find it */
 
 /* I/O hints for the BIO layer */
-#define XBF_SYNCIO	(1 << 10)/* treat this buffer as synchronous I/O */
-#define XBF_FUA		(1 << 11)/* force cache write through mode */
-#define XBF_FLUSH	(1 << 12)/* flush the disk cache before a write */
+#define XBF_SYNCIO	 (1 << 10)/* treat this buffer as synchronous I/O */
+#define XBF_FUA		 (1 << 11)/* force cache write through mode */
+#define XBF_FLUSH	 (1 << 12)/* flush the disk cache before a write */
 
 /* flags used only as arguments to access routines */
-#define XBF_TRYLOCK	(1 << 16)/* lock requested, but do not wait */
-#define XBF_UNMAPPED	(1 << 17)/* do not map the buffer */
+#define XBF_TRYLOCK	 (1 << 16)/* lock requested, but do not wait */
+#define XBF_UNMAPPED	 (1 << 17)/* do not map the buffer */
 
 /* flags used only internally */
-#define _XBF_PAGES	(1 << 20)/* backed by refcounted pages */
-#define _XBF_KMEM	(1 << 21)/* backed by heap memory */
-#define _XBF_DELWRI_Q	(1 << 22)/* buffer on a delwri queue */
-#define _XBF_COMPOUND	(1 << 23)/* compound buffer */
+#define _XBF_PAGES	 (1 << 20)/* backed by refcounted pages */
+#define _XBF_KMEM	 (1 << 21)/* backed by heap memory */
+#define _XBF_DELWRI_Q	 (1 << 22)/* buffer on a delwri queue */
+#define _XBF_COMPOUND	 (1 << 23)/* compound buffer */
+#define _XBF_LRU_DISPOSE (1 << 24)/* buffer being discarded */
 
 typedef unsigned int xfs_buf_flags_t;
 
@@ -72,12 +73,13 @@
 	{ XBF_SYNCIO,		"SYNCIO" }, \
 	{ XBF_FUA,		"FUA" }, \
 	{ XBF_FLUSH,		"FLUSH" }, \
-	{ XBF_TRYLOCK,		"TRYLOCK" }, 	/* should never be set */\
+	{ XBF_TRYLOCK,		"TRYLOCK" },	/* should never be set */\
 	{ XBF_UNMAPPED,		"UNMAPPED" },	/* ditto */\
 	{ _XBF_PAGES,		"PAGES" }, \
 	{ _XBF_KMEM,		"KMEM" }, \
 	{ _XBF_DELWRI_Q,	"DELWRI_Q" }, \
-	{ _XBF_COMPOUND,	"COMPOUND" }
+	{ _XBF_COMPOUND,	"COMPOUND" }, \
+	{ _XBF_LRU_DISPOSE,	"LRU_DISPOSE" }
 
 typedef struct xfs_buftarg {
 	dev_t			bt_dev;
@@ -124,7 +126,12 @@
 	xfs_buf_flags_t		b_flags;	/* status flags */
 	struct semaphore	b_sema;		/* semaphore for lockables */
 
+	/*
+	 * concurrent access to b_lru and b_lru_flags are protected by
+	 * bt_lru_lock and not by b_sema
+	 */
 	struct list_head	b_lru;		/* lru list */
+	xfs_buf_flags_t		b_lru_flags;	/* internal lru status flags */
 	wait_queue_head_t	b_waiters;	/* unpin waiters */
 	struct list_head	b_list;
 	struct xfs_perag	*b_pag;		/* contains rbtree root */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index bdaf4cb..19e2380 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -919,6 +919,7 @@
 	struct xfs_mount	*mp = XFS_M(sb);
 
 	xfs_filestream_unmount(mp);
+	cancel_delayed_work_sync(&mp->m_sync_work);
 	xfs_unmountfs(mp);
 	xfs_syncd_stop(mp);
 	xfs_freesb(mp);
diff --git a/include/asm-generic/bitops/builtin-__ffs.h b/include/asm-generic/bitops/builtin-__ffs.h
new file mode 100644
index 0000000..90041e3
--- /dev/null
+++ b/include/asm-generic/bitops/builtin-__ffs.h
@@ -0,0 +1,15 @@
+#ifndef _ASM_GENERIC_BITOPS_BUILTIN___FFS_H_
+#define _ASM_GENERIC_BITOPS_BUILTIN___FFS_H_
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __always_inline unsigned long __ffs(unsigned long word)
+{
+	return __builtin_ctzl(word);
+}
+
+#endif
diff --git a/include/asm-generic/bitops/builtin-__fls.h b/include/asm-generic/bitops/builtin-__fls.h
new file mode 100644
index 0000000..0248f38
--- /dev/null
+++ b/include/asm-generic/bitops/builtin-__fls.h
@@ -0,0 +1,15 @@
+#ifndef _ASM_GENERIC_BITOPS_BUILTIN___FLS_H_
+#define _ASM_GENERIC_BITOPS_BUILTIN___FLS_H_
+
+/**
+ * __fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static __always_inline unsigned long __fls(unsigned long word)
+{
+	return (sizeof(word) * 8) - 1 - __builtin_clzl(word);
+}
+
+#endif
diff --git a/include/asm-generic/bitops/builtin-ffs.h b/include/asm-generic/bitops/builtin-ffs.h
new file mode 100644
index 0000000..0648258
--- /dev/null
+++ b/include/asm-generic/bitops/builtin-ffs.h
@@ -0,0 +1,17 @@
+#ifndef _ASM_GENERIC_BITOPS_BUILTIN_FFS_H_
+#define _ASM_GENERIC_BITOPS_BUILTIN_FFS_H_
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static __always_inline int ffs(int x)
+{
+	return __builtin_ffs(x);
+}
+
+#endif
diff --git a/include/asm-generic/bitops/builtin-fls.h b/include/asm-generic/bitops/builtin-fls.h
new file mode 100644
index 0000000..eda652d
--- /dev/null
+++ b/include/asm-generic/bitops/builtin-fls.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_GENERIC_BITOPS_BUILTIN_FLS_H_
+#define _ASM_GENERIC_BITOPS_BUILTIN_FLS_H_
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static __always_inline int fls(int x)
+{
+	return x ? sizeof(x) * 8 - __builtin_clz(x) : 0;
+}
+
+#endif
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 991ef01..3748ec92 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -691,9 +691,11 @@
 #define __NR_process_vm_writev 271
 __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
           compat_sys_process_vm_writev)
+#define __NR_kcmp 272
+__SYSCALL(__NR_kcmp, sys_kcmp)
 
 #undef __NR_syscalls
-#define __NR_syscalls 272
+#define __NR_syscalls 273
 
 /*
  * All syscalls below here should go away really,
diff --git a/include/clocksource/arm_generic.h b/include/clocksource/arm_generic.h
new file mode 100644
index 0000000..5b41b0d
--- /dev/null
+++ b/include/clocksource/arm_generic.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CLKSOURCE_ARM_GENERIC_H
+#define __CLKSOURCE_ARM_GENERIC_H
+
+extern int arm_generic_timer_init(void);
+
+#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4f2a762..90be989 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -138,9 +138,9 @@
 void acpi_pci_irq_disable (struct pci_dev *dev);
 
 struct acpi_pci_driver {
-	struct acpi_pci_driver *next;
-	int (*add)(acpi_handle handle);
-	void (*remove)(acpi_handle handle);
+	struct list_head node;
+	int (*add)(struct acpi_pci_root *root);
+	void (*remove)(struct acpi_pci_root *root);
 };
 
 int acpi_pci_register_driver(struct acpi_pci_driver *driver);
diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h
index 1d14b1dc..89a931b 100644
--- a/include/linux/atmel_tc.h
+++ b/include/linux/atmel_tc.h
@@ -63,7 +63,7 @@
 	struct platform_device	*pdev;
 	struct resource		*iomem;
 	void __iomem		*regs;
-	struct atmel_tcb_config	*tcb_config;
+	const struct atmel_tcb_config *tcb_config;
 	int			irq[3];
 	struct clk		*clk[3];
 	struct list_head	node;
diff --git a/include/linux/bcd.h b/include/linux/bcd.h
index 22ea563..18fff11 100644
--- a/include/linux/bcd.h
+++ b/include/linux/bcd.h
@@ -3,7 +3,20 @@
 
 #include <linux/compiler.h>
 
-unsigned bcd2bin(unsigned char val) __attribute_const__;
-unsigned char bin2bcd(unsigned val) __attribute_const__;
+#define bcd2bin(x)					\
+		(__builtin_constant_p((u8 )(x)) ?	\
+		const_bcd2bin(x) :			\
+		_bcd2bin(x))
+
+#define bin2bcd(x)					\
+		(__builtin_constant_p((u8 )(x)) ?	\
+		const_bin2bcd(x) :			\
+		_bin2bcd(x))
+
+#define const_bcd2bin(x)	(((x) & 0x0f) + ((x) >> 4) * 10)
+#define const_bin2bcd(x)	((((x) / 10) << 4) + (x) % 10)
+
+unsigned _bcd2bin(unsigned char val) __attribute_const__;
+unsigned char _bin2bcd(unsigned val) __attribute_const__;
 
 #endif /* _BCD_H */
diff --git a/include/linux/bcm2835_timer.h b/include/linux/bcm2835_timer.h
new file mode 100644
index 0000000..25680fe
--- /dev/null
+++ b/include/linux/bcm2835_timer.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012 Simon Arlott
+ *
+ * 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.
+ */
+
+#ifndef __BCM2835_TIMER_H
+#define __BCM2835_TIMER_H
+
+#include <asm/mach/time.h>
+
+extern struct sys_timer bcm2835_timer;
+
+#endif
diff --git a/include/linux/clk/bcm2835.h b/include/linux/clk/bcm2835.h
new file mode 100644
index 0000000..aa937f6
--- /dev/null
+++ b/include/linux/clk/bcm2835.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_CLK_BCM2835_H_
+#define __LINUX_CLK_BCM2835_H_
+
+void __init bcm2835_init_clocks(void);
+
+#endif
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 2f40791..934bc34 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -49,6 +49,13 @@
 #endif
 #endif
 
+#if __GNUC_MINOR__ >= 6
+/*
+ * Tell the optimizer that something else uses this function or variable.
+ */
+#define __visible __attribute__((externally_visible))
+#endif
+
 #if __GNUC_MINOR__ > 0
 #define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
 #endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 923d093..f430e41 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -278,6 +278,10 @@
 # define __section(S) __attribute__ ((__section__(#S)))
 #endif
 
+#ifndef __visible
+#define __visible
+#endif
+
 /* Are two types/vars the same type (ignoring qualifiers)? */
 #ifndef __same_type
 # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index caa34e5..5920079 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -206,6 +206,8 @@
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_DENTRY_KILLED	0x100000
+
 extern seqlock_t rename_lock;
 
 static inline int dname_external(struct dentry *dentry)
diff --git a/include/linux/device.h b/include/linux/device.h
index 52a5f15..af92883 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -536,6 +536,10 @@
 #else
 extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
 #endif
+extern void devres_for_each_res(struct device *dev, dr_release_t release,
+				dr_match_t match, void *match_data,
+				void (*fn)(struct device *, void *, void *),
+				void *data);
 extern void devres_free(void *res);
 extern void devres_add(struct device *dev, void *res);
 extern void *devres_find(struct device *dev, dr_release_t release,
@@ -891,12 +895,15 @@
 
 #ifdef CONFIG_PRINTK
 
-extern int __dev_printk(const char *level, const struct device *dev,
-			struct va_format *vaf);
+extern __printf(3, 0)
+int dev_vprintk_emit(int level, const struct device *dev,
+		     const char *fmt, va_list args);
+extern __printf(3, 4)
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...);
+
 extern __printf(3, 4)
 int dev_printk(const char *level, const struct device *dev,
-	       const char *fmt, ...)
-	;
+	       const char *fmt, ...);
 extern __printf(2, 3)
 int dev_emerg(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
@@ -914,6 +921,14 @@
 
 #else
 
+static inline __printf(3, 0)
+int dev_vprintk_emit(int level, const struct device *dev,
+		     const char *fmt, va_list args)
+{ return 0; }
+static inline __printf(3, 4)
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
+{ return 0; }
+
 static inline int __dev_printk(const char *level, const struct device *dev,
 			       struct va_format *vaf)
 { return 0; }
@@ -946,32 +961,6 @@
 
 #endif
 
-#define dev_level_ratelimited(dev_level, dev, fmt, ...)			\
-do {									\
-	static DEFINE_RATELIMIT_STATE(_rs,				\
-				      DEFAULT_RATELIMIT_INTERVAL,	\
-				      DEFAULT_RATELIMIT_BURST);		\
-	if (__ratelimit(&_rs))						\
-		dev_level(dev, fmt, ##__VA_ARGS__);			\
-} while (0)
-
-#define dev_emerg_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__)
-#define dev_alert_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__)
-#define dev_crit_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__)
-#define dev_err_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__)
-#define dev_warn_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
-#define dev_notice_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
-#define dev_info_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)
-#define dev_dbg_ratelimited(dev, fmt, ...)				\
-	dev_level_ratelimited(dev_dbg, dev, fmt, ##__VA_ARGS__)
-
 /*
  * Stupid hackaround for existing uses of non-printk uses dev_info
  *
@@ -998,6 +987,46 @@
 })
 #endif
 
+#define dev_level_ratelimited(dev_level, dev, fmt, ...)			\
+do {									\
+	static DEFINE_RATELIMIT_STATE(_rs,				\
+				      DEFAULT_RATELIMIT_INTERVAL,	\
+				      DEFAULT_RATELIMIT_BURST);		\
+	if (__ratelimit(&_rs))						\
+		dev_level(dev, fmt, ##__VA_ARGS__);			\
+} while (0)
+
+#define dev_emerg_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__)
+#define dev_alert_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__)
+#define dev_crit_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__)
+#define dev_err_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__)
+#define dev_warn_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
+#define dev_notice_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
+#define dev_info_ratelimited(dev, fmt, ...)				\
+	dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)
+#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
+#define dev_dbg_ratelimited(dev, fmt, ...)				\
+do {									\
+	static DEFINE_RATELIMIT_STATE(_rs,				\
+				      DEFAULT_RATELIMIT_INTERVAL,	\
+				      DEFAULT_RATELIMIT_BURST);		\
+	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);			\
+	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) &&	\
+	    __ratelimit(&_rs))						\
+		__dynamic_pr_debug(&descriptor, pr_fmt(fmt),		\
+				   ##__VA_ARGS__);			\
+} while (0)
+#else
+#define dev_dbg_ratelimited(dev, fmt, ...)			\
+	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#endif
+
 #ifdef VERBOSE_DEBUG
 #define dev_vdbg	dev_dbg
 #else
diff --git a/include/linux/efi-bgrt.h b/include/linux/efi-bgrt.h
new file mode 100644
index 0000000..051b21f
--- /dev/null
+++ b/include/linux/efi-bgrt.h
@@ -0,0 +1,21 @@
+#ifndef _LINUX_EFI_BGRT_H
+#define _LINUX_EFI_BGRT_H
+
+#ifdef CONFIG_ACPI_BGRT
+
+#include <linux/acpi.h>
+
+void efi_bgrt_init(void);
+
+/* The BGRT data itself; only valid if bgrt_image != NULL. */
+extern void *bgrt_image;
+extern size_t bgrt_image_size;
+extern struct acpi_table_bgrt *bgrt_tab;
+
+#else /* !CONFIG_ACPI_BGRT */
+
+static inline void efi_bgrt_init(void) {}
+
+#endif /* !CONFIG_ACPI_BGRT */
+
+#endif /* _LINUX_EFI_BGRT_H */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ec45ccd..8670eb1 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -496,6 +496,14 @@
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timespec *ts);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
+#ifdef CONFIG_X86
+extern void efi_late_init(void);
+extern void efi_free_boot_services(void);
+#else
+static inline void efi_late_init(void) {}
+static inline void efi_free_boot_services(void) {}
+#endif
+extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 extern u64 efi_get_iobase (void);
 extern u32 efi_mem_type (unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 999b4f5..0a05051 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -387,7 +387,11 @@
 #define NT_S390_PREFIX	0x305		/* s390 prefix register */
 #define NT_S390_LAST_BREAK	0x306	/* s390 breaking event address */
 #define NT_S390_SYSTEM_CALL	0x307	/* s390 system call restart data */
+#define NT_S390_TDB	0x308		/* s390 transaction diagnostic block */
 #define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */
+#define NT_ARM_TLS	0x401		/* ARM TLS register */
+#define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH	0x403		/* ARM hardware watchpoint registers */
 
 
 /* Note header in a PT_NOTE section */
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index cdd4014..7443a56 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -30,19 +30,19 @@
 
 /*
  * The standard cable name is to help support general notifier
- * and notifee device drivers to share the common names.
+ * and notifiee device drivers to share the common names.
  * Please use standard cable names unless your notifier device has
  * a very unique and abnormal cable or
  * the cable type is supposed to be used with only one unique
- * pair of notifier/notifee devices.
+ * pair of notifier/notifiee devices.
  *
  * Please add any other "standard" cables used with extcon dev.
  *
  * You may add a dot and number to specify version or specification
  * of the specific cable if it is required. (e.g., "Fast-charger.18"
  * and "Fast-charger.10" for 1.8A and 1.0A chargers)
- * However, the notifee and notifier should be able to handle such
- * string and if the notifee can negotiate the protocol or idenify,
+ * However, the notifiee and notifier should be able to handle such
+ * string and if the notifiee can negotiate the protocol or identify,
  * you don't need such convention. This convention is helpful when
  * notifier can distinguish but notifiee cannot.
  */
@@ -76,7 +76,7 @@
  * struct extcon_dev - An extcon device represents one external connector.
  * @name	The name of this extcon device. Parent device name is used
  *		if NULL.
- * @supported_cable	Array of supported cable name ending with NULL.
+ * @supported_cable	Array of supported cable names ending with NULL.
  *			If supported_cable is NULL, cable name related APIs
  *			are disabled.
  * @mutually_exclusive	Array of mutually exclusive set of cables that cannot
@@ -95,7 +95,7 @@
  * @state	Attach/detach state of this extcon. Do not provide at
  *		register-time
  * @nh	Notifier for the state change events from this extcon
- * @entry	To support list of extcon devices so that uses can search
+ * @entry	To support list of extcon devices so that users can search
  *		for extcon devices based on the extcon name.
  * @lock
  * @max_supported	Internal value to store the number of cables.
@@ -199,7 +199,7 @@
 /*
  * get/set_cable_state access each bit of the 32b encoded state value.
  * They are used to access the status of each cable based on the cable_name
- * or cable_index, which is retrived by extcon_find_cable_index
+ * or cable_index, which is retrieved by extcon_find_cable_index
  */
 extern int extcon_find_cable_index(struct extcon_dev *sdev,
 				   const char *cable_name);
@@ -226,9 +226,9 @@
 
 /*
  * Following APIs are to monitor every action of a notifier.
- * Registerer gets notified for every external port of a connection device.
+ * Registrar gets notified for every external port of a connection device.
  * Probably this could be used to debug an action of notifier; however,
- * we do not recommend to use this at normal 'notifiee' device drivers who
+ * we do not recommend to use this for normal 'notifiee' device drivers who
  * want to be notified by a specific external port of the notifier.
  */
 extern int extcon_register_notifier(struct extcon_dev *edev,
diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h
new file mode 100644
index 0000000..20e9eef
--- /dev/null
+++ b/include/linux/extcon/extcon-adc-jack.h
@@ -0,0 +1,71 @@
+/*
+ * include/linux/extcon/extcon-adc-jack.h
+ *
+ * Analog Jack extcon driver with ADC-based detection capability.
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _EXTCON_ADC_JACK_H_
+#define _EXTCON_ADC_JACK_H_ __FILE__
+
+#include <linux/module.h>
+#include <linux/extcon.h>
+
+/**
+ * struct adc_jack_cond - condition to use an extcon state
+ * @state      - the corresponding extcon state (if 0, this struct denotes
+ *             the last adc_jack_cond element among the array)
+ * @min_adc    - min adc value for this condition
+ * @max_adc    - max adc value for this condition
+ *
+ * For example, if { .state = 0x3, .min_adc = 100, .max_adc = 200}, it means
+ * that if ADC value is between (inclusive) 100 and 200, than the cable 0 and
+ * 1 are attached (1<<0 | 1<<1 == 0x3)
+ *
+ * Note that you don't need to describe condition for "no cable attached"
+ * because when no adc_jack_cond is met, state = 0 is automatically chosen.
+ */
+struct adc_jack_cond {
+	u32 state; /* extcon state value. 0 if invalid */
+	u32 min_adc;
+	u32 max_adc;
+};
+
+/**
+ * struct adc_jack_pdata - platform data for adc jack device.
+ * @name       - name of the extcon device. If null, "adc-jack" is used.
+ * @consumer_channel - Unique name to identify the channel on the consumer
+ *                   side. This typically describes the channels used within
+ *                   the consumer. E.g. 'battery_voltage'
+ * @cable_names        - array of cable names ending with null.
+ * @adc_contitions     - array of struct adc_jack_cond conditions ending
+ *                     with .state = 0 entry. This describes how to decode
+ *                     adc values into extcon state.
+ * @irq_flags  - irq flags used for the @irq
+ * @handling_delay_ms  - in some devices, we need to read ADC value some
+ *                     milli-seconds after the interrupt occurs. You may
+ *                     describe such delays with @handling_delay_ms, which
+ *                     is rounded-off by jiffies.
+ */
+struct adc_jack_pdata {
+	const char *name;
+	const char *consumer_channel;
+	/*
+	 * The last entry should be NULL
+	 */
+	const char **cable_names;
+	/* The last entry's state should be 0 */
+	struct adc_jack_cond *adc_conditions;
+
+	unsigned long irq_flags;
+	unsigned long handling_delay_ms; /* in ms */
+};
+
+#endif /* _EXTCON_ADC_JACK_H */
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 1e7c011..e4279fe 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -12,6 +12,9 @@
 	size_t size;
 	const u8 *data;
 	struct page **pages;
+
+	/* firmware loader private fields */
+	void *priv;
 };
 
 struct module;
@@ -44,6 +47,8 @@
 	void (*cont)(const struct firmware *fw, void *context));
 
 void release_firmware(const struct firmware *fw);
+int cache_firmware(const char *name);
+int uncache_firmware(const char *name);
 #else
 static inline int request_firmware(const struct firmware **fw,
 				   const char *name,
@@ -62,6 +67,16 @@
 static inline void release_firmware(const struct firmware *fw)
 {
 }
+
+static inline int cache_firmware(const char *name)
+{
+	return -ENOENT;
+}
+
+static inline int uncache_firmware(const char *name)
+{
+	return -EINVAL;
+}
 #endif
 
 #endif
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 15be561..a82296af 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -19,9 +19,11 @@
 
 #define FSL_UTMI_PHY_DLY	10	/*As per P1010RM, delay for UTMI
 				PHY CLK to become stable - 10ms*/
+#define FSL_USB_PHY_CLK_TIMEOUT	10000	/* uSec */
 #define FSL_USB_VER_OLD		0
 #define FSL_USB_VER_1_6		1
 #define FSL_USB_VER_2_2		2
+#define FSL_USB_VER_2_4		3
 
 #include <linux/types.h>
 
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 55e6d63..a52f2f4 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -10,6 +10,7 @@
 #include <linux/kallsyms.h>
 #include <linux/linkage.h>
 #include <linux/bitops.h>
+#include <linux/ptrace.h>
 #include <linux/ktime.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -18,6 +19,28 @@
 
 #include <asm/ftrace.h>
 
+/*
+ * If the arch supports passing the variable contents of
+ * function_trace_op as the third parameter back from the
+ * mcount call, then the arch should define this as 1.
+ */
+#ifndef ARCH_SUPPORTS_FTRACE_OPS
+#define ARCH_SUPPORTS_FTRACE_OPS 0
+#endif
+
+/*
+ * If the arch's mcount caller does not support all of ftrace's
+ * features, then it must call an indirect function that
+ * does. Or at least does enough to prevent any unwelcomed side effects.
+ */
+#if !defined(CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST) || \
+	!ARCH_SUPPORTS_FTRACE_OPS
+# define FTRACE_FORCE_LIST_FUNC 1
+#else
+# define FTRACE_FORCE_LIST_FUNC 0
+#endif
+
+
 struct module;
 struct ftrace_hash;
 
@@ -29,7 +52,10 @@
 		     void __user *buffer, size_t *lenp,
 		     loff_t *ppos);
 
-typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
+struct ftrace_ops;
+
+typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
+			      struct ftrace_ops *op, struct pt_regs *regs);
 
 /*
  * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are
@@ -45,12 +71,33 @@
  *           could be controled by following calls:
  *             ftrace_function_local_enable
  *             ftrace_function_local_disable
+ * SAVE_REGS - The ftrace_ops wants regs saved at each function called
+ *            and passed to the callback. If this flag is set, but the
+ *            architecture does not support passing regs
+ *            (ARCH_SUPPORTS_FTRACE_SAVE_REGS is not defined), then the
+ *            ftrace_ops will fail to register, unless the next flag
+ *            is set.
+ * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the
+ *            handler can handle an arch that does not save regs
+ *            (the handler tests if regs == NULL), then it can set
+ *            this flag instead. It will not fail registering the ftrace_ops
+ *            but, the regs field will be NULL if the arch does not support
+ *            passing regs to the handler.
+ *            Note, if this flag is set, the SAVE_REGS flag will automatically
+ *            get set upon registering the ftrace_ops, if the arch supports it.
+ * RECURSION_SAFE - The ftrace_ops can set this to tell the ftrace infrastructure
+ *            that the call back has its own recursion protection. If it does
+ *            not set this, then the ftrace infrastructure will add recursion
+ *            protection for the caller.
  */
 enum {
-	FTRACE_OPS_FL_ENABLED		= 1 << 0,
-	FTRACE_OPS_FL_GLOBAL		= 1 << 1,
-	FTRACE_OPS_FL_DYNAMIC		= 1 << 2,
-	FTRACE_OPS_FL_CONTROL		= 1 << 3,
+	FTRACE_OPS_FL_ENABLED			= 1 << 0,
+	FTRACE_OPS_FL_GLOBAL			= 1 << 1,
+	FTRACE_OPS_FL_DYNAMIC			= 1 << 2,
+	FTRACE_OPS_FL_CONTROL			= 1 << 3,
+	FTRACE_OPS_FL_SAVE_REGS			= 1 << 4,
+	FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED	= 1 << 5,
+	FTRACE_OPS_FL_RECURSION_SAFE		= 1 << 6,
 };
 
 struct ftrace_ops {
@@ -163,7 +210,8 @@
 	return *this_cpu_ptr(ops->disabled);
 }
 
-extern void ftrace_stub(unsigned long a0, unsigned long a1);
+extern void ftrace_stub(unsigned long a0, unsigned long a1,
+			struct ftrace_ops *op, struct pt_regs *regs);
 
 #else /* !CONFIG_FUNCTION_TRACER */
 /*
@@ -172,6 +220,10 @@
  */
 #define register_ftrace_function(ops) ({ 0; })
 #define unregister_ftrace_function(ops) ({ 0; })
+static inline int ftrace_nr_registered_ops(void)
+{
+	return 0;
+}
 static inline void clear_ftrace_function(void) { }
 static inline void ftrace_kill(void) { }
 static inline void ftrace_stop(void) { }
@@ -227,12 +279,33 @@
 
 extern int ftrace_text_reserved(void *start, void *end);
 
+extern int ftrace_nr_registered_ops(void);
+
+/*
+ * The dyn_ftrace record's flags field is split into two parts.
+ * the first part which is '0-FTRACE_REF_MAX' is a counter of
+ * the number of callbacks that have registered the function that
+ * the dyn_ftrace descriptor represents.
+ *
+ * The second part is a mask:
+ *  ENABLED - the function is being traced
+ *  REGS    - the record wants the function to save regs
+ *  REGS_EN - the function is set up to save regs.
+ *
+ * When a new ftrace_ops is registered and wants a function to save
+ * pt_regs, the rec->flag REGS is set. When the function has been
+ * set up to save regs, the REG_EN flag is set. Once a function
+ * starts saving regs it will do so until all ftrace_ops are removed
+ * from tracing that function.
+ */
 enum {
-	FTRACE_FL_ENABLED	= (1 << 30),
+	FTRACE_FL_ENABLED	= (1UL << 29),
+	FTRACE_FL_REGS		= (1UL << 30),
+	FTRACE_FL_REGS_EN	= (1UL << 31)
 };
 
-#define FTRACE_FL_MASK		(0x3UL << 30)
-#define FTRACE_REF_MAX		((1 << 30) - 1)
+#define FTRACE_FL_MASK		(0x7UL << 29)
+#define FTRACE_REF_MAX		((1UL << 29) - 1)
 
 struct dyn_ftrace {
 	union {
@@ -244,6 +317,8 @@
 };
 
 int ftrace_force_update(void);
+int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
+			 int remove, int reset);
 int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
 		       int len, int reset);
 int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
@@ -263,9 +338,23 @@
 	FTRACE_STOP_FUNC_RET		= (1 << 4),
 };
 
+/*
+ * The FTRACE_UPDATE_* enum is used to pass information back
+ * from the ftrace_update_record() and ftrace_test_record()
+ * functions. These are called by the code update routines
+ * to find out what is to be done for a given function.
+ *
+ *  IGNORE           - The function is already what we want it to be
+ *  MAKE_CALL        - Start tracing the function
+ *  MODIFY_CALL      - Stop saving regs for the function
+ *  MODIFY_CALL_REGS - Start saving regs for the function
+ *  MAKE_NOP         - Stop tracing the function
+ */
 enum {
 	FTRACE_UPDATE_IGNORE,
 	FTRACE_UPDATE_MAKE_CALL,
+	FTRACE_UPDATE_MODIFY_CALL,
+	FTRACE_UPDATE_MODIFY_CALL_REGS,
 	FTRACE_UPDATE_MAKE_NOP,
 };
 
@@ -317,7 +406,9 @@
 extern void ftrace_replace_code(int enable);
 extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
+extern void ftrace_regs_caller(void);
 extern void ftrace_call(void);
+extern void ftrace_regs_call(void);
 extern void mcount_call(void);
 
 void ftrace_modify_all_code(int command);
@@ -325,6 +416,15 @@
 #ifndef FTRACE_ADDR
 #define FTRACE_ADDR ((unsigned long)ftrace_caller)
 #endif
+
+#ifndef FTRACE_REGS_ADDR
+#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+# define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller)
+#else
+# define FTRACE_REGS_ADDR FTRACE_ADDR
+#endif
+#endif
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 extern void ftrace_graph_caller(void);
 extern int ftrace_enable_ftrace_graph_caller(void);
@@ -380,6 +480,39 @@
  */
 extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
 
+#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+/**
+ * ftrace_modify_call - convert from one addr to another (no nop)
+ * @rec: the mcount call site record
+ * @old_addr: the address expected to be currently called to
+ * @addr: the address to change to
+ *
+ * This is a very sensitive operation and great care needs
+ * to be taken by the arch.  The operation should carefully
+ * read the location, check to see if what is read is indeed
+ * what we expect it to be, and then on success of the compare,
+ * it should write to the location.
+ *
+ * The code segment at @rec->ip should be a caller to @old_addr
+ *
+ * Return must be:
+ *  0 on success
+ *  -EFAULT on error reading the location
+ *  -EINVAL on a failed compare of the contents
+ *  -EPERM  on error writing to the location
+ * Any other value will be considered a failure.
+ */
+extern int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+			      unsigned long addr);
+#else
+/* Should never be called */
+static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+				     unsigned long addr)
+{
+	return -EINVAL;
+}
+#endif
+
 /* May be defined in arch */
 extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
@@ -387,7 +520,7 @@
 
 extern void ftrace_disable_daemon(void);
 extern void ftrace_enable_daemon(void);
-#else
+#else /* CONFIG_DYNAMIC_FTRACE */
 static inline int skip_trace(unsigned long ip) { return 0; }
 static inline int ftrace_force_update(void) { return 0; }
 static inline void ftrace_disable_daemon(void) { }
@@ -405,6 +538,10 @@
 {
 	return 0;
 }
+static inline unsigned long ftrace_location(unsigned long ip)
+{
+	return 0;
+}
 
 /*
  * Again users of functions that have ftrace_ops may not
@@ -413,6 +550,7 @@
  */
 #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
 #define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
+#define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; })
 #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
 #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
 #define ftrace_free_filter(ops) do { } while (0)
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 305f23c..cab3da3d 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -132,11 +132,11 @@
 struct task_struct;
 
 #if !defined(CONFIG_VIRT_CPU_ACCOUNTING) && !defined(CONFIG_IRQ_TIME_ACCOUNTING)
-static inline void account_system_vtime(struct task_struct *tsk)
+static inline void vtime_account(struct task_struct *tsk)
 {
 }
 #else
-extern void account_system_vtime(struct task_struct *tsk);
+extern void vtime_account(struct task_struct *tsk);
 #endif
 
 #if defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
@@ -162,7 +162,7 @@
  */
 #define __irq_enter()					\
 	do {						\
-		account_system_vtime(current);		\
+		vtime_account(current);		\
 		add_preempt_count(HARDIRQ_OFFSET);	\
 		trace_hardirq_enter();			\
 	} while (0)
@@ -178,7 +178,7 @@
 #define __irq_exit()					\
 	do {						\
 		trace_hardirq_exit();			\
-		account_system_vtime(current);		\
+		vtime_account(current);		\
 		sub_preempt_count(HARDIRQ_OFFSET);	\
 	} while (0)
 
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
new file mode 100644
index 0000000..0aa5f4c
--- /dev/null
+++ b/include/linux/hid-sensor-hub.h
@@ -0,0 +1,160 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+#ifndef _HID_SENSORS_HUB_H
+#define _HID_SENSORS_HUB_H
+
+#include <linux/hid.h>
+#include <linux/hid-sensor-ids.h>
+
+/**
+ * struct hid_sensor_hub_attribute_info - Attribute info
+ * @usage_id:		Parent usage id of a physical device.
+ * @attrib_id:		Attribute id for this attribute.
+ * @report_id:		Report id in which this information resides.
+ * @index:		Field index in the report.
+ * @units:		Measurment unit for this attribute.
+ * @unit_expo:		Exponent used in the data.
+ * @size:		Size in bytes for data size.
+ */
+struct hid_sensor_hub_attribute_info {
+	u32 usage_id;
+	u32 attrib_id;
+	s32 report_id;
+	s32 index;
+	s32 units;
+	s32 unit_expo;
+	s32 size;
+};
+
+/**
+ * struct hid_sensor_hub_device - Stores the hub instance data
+ * @hdev:		Stores the hid instance.
+ * @vendor_id:		Vendor id of hub device.
+ * @product_id:		Product id of hub device.
+ */
+struct hid_sensor_hub_device {
+	struct hid_device *hdev;
+	u32 vendor_id;
+	u32 product_id;
+};
+
+/**
+ * struct hid_sensor_hub_callbacks - Client callback functions
+ * @pdev:		Platform device instance of the client driver.
+ * @suspend:		Suspend callback.
+ * @resume:		Resume callback.
+ * @capture_sample:	Callback to get a sample.
+ * @send_event:		Send notification to indicate all samples are
+ *			captured, process and send event
+ */
+struct hid_sensor_hub_callbacks {
+	struct platform_device *pdev;
+	int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*capture_sample)(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id, size_t raw_len, char *raw_data,
+			void *priv);
+	int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id,
+			 void *priv);
+};
+
+/* Registration functions */
+
+/**
+* sensor_hub_register_callback() - Register client callbacks
+* @hsdev:	Hub device instance.
+* @usage_id:	Usage id of the client (E.g. 0x200076 for Gyro).
+* @usage_callback: Callback function storage
+*
+* Used to register callbacks by client processing drivers. Sensor
+* hub core driver will call these callbacks to offload processing
+* of data streams and notifications.
+*/
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback);
+
+/**
+* sensor_hub_remove_callback() - Remove client callbacks
+* @hsdev:	Hub device instance.
+* @usage_id:	Usage id of the client (E.g. 0x200076 for Gyro).
+*
+* If there is a callback registred, this call will remove that
+* callbacks, so that it will stop data and event notifications.
+*/
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id);
+
+
+/* Hid sensor hub core interfaces */
+
+/**
+* sensor_hub_input_get_attribute_info() - Get an attribute information
+* @hsdev:	Hub device instance.
+* @type:	Type of this attribute, input/output/feature
+* @usage_id:	Attribute usage id of parent physical device as per spec
+* @attr_usage_id:	Attribute usage id as per spec
+* @info:	return information about attribute after parsing report
+*
+* Parses report and returns the attribute information such as report id,
+* field index, units and exponet etc.
+*/
+int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
+			u8 type,
+			u32 usage_id, u32 attr_usage_id,
+			struct hid_sensor_hub_attribute_info *info);
+
+/**
+* sensor_hub_input_attr_get_raw_value() - Synchronous read request
+* @usage_id:	Attribute usage id of parent physical device as per spec
+* @attr_usage_id:	Attribute usage id as per spec
+* @report_id:	Report id to look for
+*
+* Issues a synchronous read request for an input attribute. Returns
+* data upto 32 bits. Since client can get events, so this call should
+* not be used for data paths, this will impact performance.
+*/
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			u32 attr_usage_id, u32 report_id);
+/**
+* sensor_hub_set_feature() - Feature set request
+* @report_id:	Report id to look for
+* @field_index:	Field index inside a report
+* @value:	Value to set
+*
+* Used to set a field in feature report. For example this can set polling
+* interval, sensitivity, activate/deactivate state.
+*/
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 value);
+
+/**
+* sensor_hub_get_feature() - Feature get request
+* @report_id:	Report id to look for
+* @field_index:	Field index inside a report
+* @value:	Place holder for return value
+*
+* Used to get a field in feature report. For example this can get polling
+* interval, sensitivity, activate/deactivate state.
+*/
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 *value);
+#endif
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
new file mode 100644
index 0000000..ca8d7e9
--- /dev/null
+++ b/include/linux/hid-sensor-ids.h
@@ -0,0 +1,112 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+#ifndef _HID_SENSORS_IDS_H
+#define _HID_SENSORS_IDS_H
+
+#define HID_UP_SENSOR						0x00200000
+#define HID_MAX_PHY_DEVICES					0xFF
+
+/* Accel 3D (200073) */
+#define HID_USAGE_SENSOR_ACCEL_3D				0x200073
+#define HID_USAGE_SENSOR_ACCEL_X_AXIS				0x200453
+#define HID_USAGE_SENSOR_ACCEL_Y_AXIS				0x200454
+#define HID_USAGE_SENSOR_ACCEL_Z_AXIS				0x200455
+
+/* ALS (200041) */
+#define HID_USAGE_SENSOR_ALS					0x200041
+#define HID_USAGE_SENSOR_LIGHT_ILLUM				0x2004d1
+
+/* Gyro 3D: (200076) */
+#define HID_USAGE_SENSOR_GYRO_3D				0x200076
+#define HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS			0x200457
+#define HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS			0x200458
+#define HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS			0x200459
+
+/*ORIENTATION: Compass 3D: (200083) */
+#define HID_USAGE_SENSOR_COMPASS_3D				0x200083
+#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING			0x200471
+#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_X			0x200472
+#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Y			0x200473
+#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Z			0x200474
+
+#define HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH			0x200475
+#define HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH			0x200476
+#define HID_USAGE_SENSOR_ORIENT_MAGN_NORTH			0x200477
+#define HID_USAGE_SENSOR_ORIENT_TRUE_NORTH			0x200478
+
+#define HID_USAGE_SENSOR_ORIENT_DISTANCE			0x200479
+#define HID_USAGE_SENSOR_ORIENT_DISTANCE_X			0x20047A
+#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Y			0x20047B
+#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Z			0x20047C
+#define HID_USAGE_SENSOR_ORIENT_DISTANCE_OUT_OF_RANGE		0x20047D
+#define HID_USAGE_SENSOR_ORIENT_TILT				0x20047E
+#define HID_USAGE_SENSOR_ORIENT_TILT_X				0x20047F
+#define HID_USAGE_SENSOR_ORIENT_TILT_Y				0x200480
+#define HID_USAGE_SENSOR_ORIENT_TILT_Z				0x200481
+#define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX			0x200482
+#define HID_USAGE_SENSOR_ORIENT_QUATERNION			0x200483
+#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX			0x200484
+
+#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS		0x200485
+#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS		0x200486
+#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS		0x200487
+
+/* Units */
+#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED			0x00
+#define HID_USAGE_SENSOR_UNITS_LUX				0x01
+#define HID_USAGE_SENSOR_UNITS_KELVIN				0x01000100
+#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT			0x03000100
+#define HID_USAGE_SENSOR_UNITS_PASCAL				0xF1E1
+#define HID_USAGE_SENSOR_UNITS_NEWTON				0x11E1
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND		0x11F0
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD		0x11E0
+#define HID_USAGE_SENSOR_UNITS_FARAD				0xE14F2000
+#define HID_USAGE_SENSOR_UNITS_AMPERE				0x01001000
+#define HID_USAGE_SENSOR_UNITS_WATT				0x21d1
+#define HID_USAGE_SENSOR_UNITS_HENRY				0x21E1E000
+#define HID_USAGE_SENSOR_UNITS_OHM				0x21D1E000
+#define HID_USAGE_SENSOR_UNITS_VOLT				0x21D1F000
+#define HID_USAGE_SENSOR_UNITS_HERTZ				0x01F0
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD		0x14E0
+#define HID_USAGE_SENSOR_UNITS_RADIANS				0x12
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND		0x12F0
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD		0x12E0
+#define HID_USAGE_SENSOR_UNITS_SECOND				0x0110
+#define HID_USAGE_SENSOR_UNITS_GAUSS				0x01E1F000
+#define HID_USAGE_SENSOR_UNITS_GRAM				0x0101
+#define HID_USAGE_SENSOR_UNITS_CENTIMETER			0x11
+#define HID_USAGE_SENSOR_UNITS_G				0x1A
+#define HID_USAGE_SENSOR_UNITS_MILLISECOND			0x19
+#define HID_USAGE_SENSOR_UNITS_PERCENT				0x17
+#define HID_USAGE_SENSOR_UNITS_DEGREES				0x14
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND		0x15
+
+/* Common selectors */
+#define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL			0x20030E
+#define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS			0x20030F
+#define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT		0x200310
+#define HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT		0x200311
+#define HID_USAGE_SENSOR_PROP_ACCURACY				0x200312
+#define HID_USAGE_SENSOR_PROP_RESOLUTION			0x200313
+#define HID_USAGE_SENSOR_PROP_RANGE_MAXIMUM			0x200314
+#define HID_USAGE_SENSOR_PROP_RANGE_MINIMUM			0x200315
+#define HID_USAGE_SENSOR_PROP_REPORT_STATE			0x200316
+#define HID_USAGE_SENSOR_PROY_POWER_STATE			0x200319
+
+#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 42970de..7e1f37d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -414,7 +414,7 @@
 	__u16 dpad;			/* dpad input code */
 };
 
-#define HID_MAX_FIELDS 128
+#define HID_MAX_FIELDS 256
 
 struct hid_report {
 	struct list_head list;
@@ -626,6 +626,7 @@
  * @report_fixup: called before report descriptor parsing (NULL means nop)
  * @input_mapping: invoked on input registering before mapping an usage
  * @input_mapped: invoked on input registering after mapping an usage
+ * @input_configured: invoked just before the device is registered
  * @feature_mapping: invoked on feature registering
  * @suspend: invoked on suspend (NULL means nop)
  * @resume: invoked on resume if device was not reset (NULL means nop)
@@ -670,6 +671,8 @@
 	int (*input_mapped)(struct hid_device *hdev,
 			struct hid_input *hidinput, struct hid_field *field,
 			struct hid_usage *usage, unsigned long **bit, int *max);
+	void (*input_configured)(struct hid_device *hdev,
+				 struct hid_input *hidinput);
 	void (*feature_mapping)(struct hid_device *hdev,
 			struct hid_field *field,
 			struct hid_usage *usage);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 68ed7f7..e73b852 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -122,12 +122,53 @@
 #define REG_U32 4
 #define REG_U64 8
 
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER	4
+
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+
+#define KVP_OP_REGISTER1 100
+
 enum hv_kvp_exchg_op {
 	KVP_OP_GET = 0,
 	KVP_OP_SET,
 	KVP_OP_DELETE,
 	KVP_OP_ENUMERATE,
-	KVP_OP_REGISTER,
+	KVP_OP_GET_IP_INFO,
+	KVP_OP_SET_IP_INFO,
 	KVP_OP_COUNT /* Number of operations, must be last. */
 };
 
@@ -140,6 +181,39 @@
 	KVP_POOL_COUNT /* Number of pools, must be last. */
 };
 
+/*
+ * Some Hyper-V status codes.
+ */
+
+#define HV_S_OK				0x00000000
+#define HV_E_FAIL			0x80004005
+#define HV_S_CONT			0x80070103
+#define HV_ERROR_NOT_SUPPORTED		0x80070032
+#define HV_ERROR_MACHINE_LOCKED		0x800704F7
+#define HV_ERROR_DEVICE_NOT_CONNECTED	0x8007048F
+#define HV_INVALIDARG			0x80070057
+#define HV_GUID_NOTFOUND		0x80041002
+
+#define ADDR_FAMILY_NONE	0x00
+#define ADDR_FAMILY_IPV4	0x01
+#define ADDR_FAMILY_IPV6	0x02
+
+#define MAX_ADAPTER_ID_SIZE	128
+#define MAX_IP_ADDR_SIZE	1024
+#define MAX_GATEWAY_SIZE	512
+
+
+struct hv_kvp_ipaddr_value {
+	__u16	adapter_id[MAX_ADAPTER_ID_SIZE];
+	__u8	addr_family;
+	__u8	dhcp_enabled;
+	__u16	ip_addr[MAX_IP_ADDR_SIZE];
+	__u16	sub_net[MAX_IP_ADDR_SIZE];
+	__u16	gate_way[MAX_GATEWAY_SIZE];
+	__u16	dns_addr[MAX_IP_ADDR_SIZE];
+} __attribute__((packed));
+
+
 struct hv_kvp_hdr {
 	__u8 operation;
 	__u8 pool;
@@ -181,16 +255,26 @@
 };
 
 struct hv_kvp_msg {
-	struct hv_kvp_hdr	kvp_hdr;
+	union {
+		struct hv_kvp_hdr	kvp_hdr;
+		int error;
+	};
 	union {
 		struct hv_kvp_msg_get		kvp_get;
 		struct hv_kvp_msg_set		kvp_set;
 		struct hv_kvp_msg_delete	kvp_delete;
 		struct hv_kvp_msg_enumerate	kvp_enum_data;
+		struct hv_kvp_ipaddr_value      kvp_ip_val;
 		struct hv_kvp_register		kvp_register;
 	} body;
 } __attribute__((packed));
 
+struct hv_kvp_ip_msg {
+	__u8 operation;
+	__u8 pool;
+	struct hv_kvp_ipaddr_value      kvp_ip_val;
+} __attribute__((packed));
+
 #ifdef __KERNEL__
 #include <linux/scatterlist.h>
 #include <linux/list.h>
@@ -405,7 +489,7 @@
 struct vmtransfer_page_packet_header {
 	struct vmpacket_descriptor d;
 	u16 xfer_pageset_id;
-	bool sender_owns_set;
+	u8  sender_owns_set;
 	u8 reserved;
 	u32 range_cnt;
 	struct vmtransfer_page_range ranges[1];
@@ -559,7 +643,7 @@
 /* VMBus Version Supported parameters */
 struct vmbus_channel_version_supported {
 	struct vmbus_channel_message_header header;
-	bool version_supported;
+	u8 version_supported;
 } __packed;
 
 /* Offer Channel parameters */
@@ -568,7 +652,7 @@
 	struct vmbus_channel_offer offer;
 	u32 child_relid;
 	u8 monitorid;
-	bool monitor_allocated;
+	u8 monitor_allocated;
 } __packed;
 
 /* Rescind Offer parameters */
@@ -704,7 +788,7 @@
 
 struct vmbus_channel_version_response {
 	struct vmbus_channel_message_header header;
-	bool version_supported;
+	u8 version_supported;
 } __packed;
 
 enum vmbus_channel_state {
@@ -977,11 +1061,6 @@
 #define ICMSGHDRFLAG_REQUEST		2
 #define ICMSGHDRFLAG_RESPONSE		4
 
-#define HV_S_OK				0x00000000
-#define HV_E_FAIL			0x80004005
-#define HV_S_CONT			0x80070103
-#define HV_ERROR_NOT_SUPPORTED		0x80070032
-#define HV_ERROR_MACHINE_LOCKED		0x800704F7
 
 /*
  * While we want to handle util services as regular devices,
diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
new file mode 100644
index 0000000..2e4eab9
--- /dev/null
+++ b/include/linux/iio/adc/ad_sigma_delta.h
@@ -0,0 +1,173 @@
+/*
+ * Support code for Analog Devices Sigma-Delta ADCs
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+#ifndef __AD_SIGMA_DELTA_H__
+#define __AD_SIGMA_DELTA_H__
+
+enum ad_sigma_delta_mode {
+	AD_SD_MODE_CONTINUOUS = 0,
+	AD_SD_MODE_SINGLE = 1,
+	AD_SD_MODE_IDLE = 2,
+	AD_SD_MODE_POWERDOWN = 3,
+};
+
+/**
+ * struct ad_sigma_delta_calib_data - Calibration data for Sigma Delta devices
+ * @mode: Calibration mode.
+ * @channel: Calibration channel.
+ */
+struct ad_sd_calib_data {
+	unsigned int mode;
+	unsigned int channel;
+};
+
+struct ad_sigma_delta;
+struct iio_dev;
+
+/**
+ * struct ad_sigma_delta_info - Sigma Delta driver specific callbacks and options
+ * @set_channel: Will be called to select the current channel, may be NULL.
+ * @set_mode: Will be called to select the current mode, may be NULL.
+ * @postprocess_sample: Is called for each sampled data word, can be used to
+ *		modify or drop the sample data, it, may be NULL.
+ * @has_registers: true if the device has writable and readable registers, false
+ *		if there is just one read-only sample data shift register.
+ * @addr_shift: Shift of the register address in the communications register.
+ * @read_mask: Mask for the communications register having the read bit set.
+ */
+struct ad_sigma_delta_info {
+	int (*set_channel)(struct ad_sigma_delta *, unsigned int channel);
+	int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode);
+	int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample);
+	bool has_registers;
+	unsigned int addr_shift;
+	unsigned int read_mask;
+};
+
+/**
+ * struct ad_sigma_delta - Sigma Delta device struct
+ * @spi: The spi device associated with the Sigma Delta device.
+ * @trig: The IIO trigger associated with the Sigma Delta device.
+ *
+ * Most of the fields are private to the sigma delta library code and should not
+ * be accessed by individual drivers.
+ */
+struct ad_sigma_delta {
+	struct spi_device	*spi;
+	struct iio_trigger	*trig;
+
+/* private: */
+	struct completion	completion;
+	bool			irq_dis;
+
+	bool			bus_locked;
+
+	uint8_t			comm;
+
+	const struct ad_sigma_delta_info *info;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	uint8_t				data[4] ____cacheline_aligned;
+};
+
+static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd,
+	unsigned int channel)
+{
+	if (sd->info->set_channel)
+		return sd->info->set_channel(sd, channel);
+
+	return 0;
+}
+
+static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd,
+	unsigned int mode)
+{
+	if (sd->info->set_mode)
+		return sd->info->set_mode(sd, mode);
+
+	return 0;
+}
+
+static inline int ad_sigma_delta_postprocess_sample(struct ad_sigma_delta *sd,
+	unsigned int raw_sample)
+{
+	if (sd->info->postprocess_sample)
+		return sd->info->postprocess_sample(sd, raw_sample);
+
+	return 0;
+}
+
+void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm);
+int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
+	unsigned int size, unsigned int val);
+int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
+	unsigned int size, unsigned int *val);
+
+int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, int *val);
+int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
+	const struct ad_sd_calib_data *cd, unsigned int n);
+int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
+	struct spi_device *spi, const struct ad_sigma_delta_info *info);
+
+int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev);
+void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev);
+
+int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
+
+#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
+	_storagebits, _shift, _extend_name, _type) \
+	{ \
+		.type = (_type), \
+		.differential = (_channel2 == -1 ? 0 : 1), \
+		.indexed = 1, \
+		.channel = (_channel1), \
+		.channel2 = (_channel2), \
+		.address = (_address), \
+		.extend_name = (_extend_name), \
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+			IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+			IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
+		.scan_index = (_si), \
+		.scan_type = { \
+			.sign = 'u', \
+			.realbits = (_bits), \
+			.storagebits = (_storagebits), \
+			.shift = (_shift), \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
+#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
+	_storagebits, _shift) \
+	__AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
+		_storagebits, _shift, NULL, IIO_VOLTAGE)
+
+#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \
+	_storagebits, _shift) \
+	__AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \
+		_storagebits, _shift, "shorted", IIO_VOLTAGE)
+
+#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \
+	_storagebits, _shift) \
+	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
+		_storagebits, _shift, NULL, IIO_VOLTAGE)
+
+#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \
+	__AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \
+		_storagebits, _shift, NULL, IIO_TEMP)
+
+#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \
+	_shift) \
+	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
+		_storagebits, _shift, "supply", IIO_VOLTAGE)
+
+#endif
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 8ba516f..c629b3a 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -36,7 +36,7 @@
  * any of them not existing.
  **/
 struct iio_buffer_access_funcs {
-	int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp);
+	int (*store_to)(struct iio_buffer *buffer, u8 *data);
 	int (*read_first_n)(struct iio_buffer *buffer,
 			    size_t n,
 			    char __user *buf);
@@ -118,10 +118,8 @@
  * iio_push_to_buffer() - push to a registered buffer.
  * @buffer:		IIO buffer structure for device
  * @data:		the data to push to the buffer
- * @timestamp:		timestamp to associate with the data
  */
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
-		       s64 timestamp);
+int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data);
 
 int iio_update_demux(struct iio_dev *indio_dev);
 
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index e2657e6d..e875bcf 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -8,7 +8,7 @@
  * the Free Software Foundation.
  */
 #ifndef _IIO_INKERN_CONSUMER_H_
-#define _IIO_INKERN_CONSUMER_H
+#define _IIO_INKERN_CONSUMER_H_
 #include <linux/iio/types.h>
 
 struct iio_dev;
@@ -61,7 +61,7 @@
 
 /**
  * iio_read_channel_raw() - read from a given channel
- * @channel:		The channel being queried.
+ * @chan:		The channel being queried.
  * @val:		Value read back.
  *
  * Note raw reads from iio channels are in adc counts and hence
@@ -71,6 +71,21 @@
 			 int *val);
 
 /**
+ * iio_read_channel_processed() - read processed value from a given channel
+ * @chan:		The channel being queried.
+ * @val:		Value read back.
+ *
+ * Returns an error code or 0.
+ *
+ * This function will read a processed value from a channel. A processed value
+ * means that this value will have the correct unit and not some device internal
+ * representation. If the device does not support reporting a processed value
+ * the function will query the raw value and the channels scale and offset and
+ * do the appropriate transformation.
+ */
+int iio_read_channel_processed(struct iio_channel *chan, int *val);
+
+/**
  * iio_get_channel_type() - get the type of a channel
  * @channel:		The channel being queried.
  * @type:		The type of the channel.
@@ -82,7 +97,7 @@
 
 /**
  * iio_read_channel_scale() - read the scale value for a channel
- * @channel:		The channel being queried.
+ * @chan:		The channel being queried.
  * @val:		First part of value read back.
  * @val2:		Second part of value read back.
  *
@@ -93,4 +108,27 @@
 int iio_read_channel_scale(struct iio_channel *chan, int *val,
 			   int *val2);
 
+/**
+ * iio_convert_raw_to_processed() - Converts a raw value to a processed value
+ * @chan:		The channel being queried
+ * @raw:		The raw IIO to convert
+ * @processed:		The result of the conversion
+ * @scale:		Scale factor to apply during the conversion
+ *
+ * Returns an error code or 0.
+ *
+ * This function converts a raw value to processed value for a specific channel.
+ * A raw value is the device internal representation of a sample and the value
+ * returned by iio_read_channel_raw, so the unit of that value is device
+ * depended. A processed value on the other hand is value has a normed unit
+ * according with the IIO specification.
+ *
+ * The scale factor allows to increase the precession of the returned value. For
+ * a scale factor of 1 the function will return the result in the normal IIO
+ * unit for the channel type. E.g. millivolt for voltage channels, if you want
+ * nanovolts instead pass 1000 as the scale factor.
+ */
+int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
+	int *processed, unsigned int scale);
+
 #endif
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index be82936..c0ae76a 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -35,10 +35,13 @@
 	IIO_CHAN_INFO_FREQUENCY,
 	IIO_CHAN_INFO_PHASE,
 	IIO_CHAN_INFO_HARDWAREGAIN,
+	IIO_CHAN_INFO_HYSTERESIS,
 };
 
 #define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
 #define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
+#define IIO_CHAN_INFO_BITS(type) (IIO_CHAN_INFO_SHARED_BIT(type) | \
+				    IIO_CHAN_INFO_SEPARATE_BIT(type))
 
 #define IIO_CHAN_INFO_RAW_SEPARATE_BIT			\
 	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
@@ -100,6 +103,10 @@
 	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
 #define IIO_CHAN_INFO_HARDWAREGAIN_SHARED_BIT			\
 	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
+#define IIO_CHAN_INFO_HYSTERESIS_SEPARATE_BIT			\
+	IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HYSTERESIS)
+#define IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT			\
+	IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HYSTERESIS)
 
 enum iio_endian {
 	IIO_CPU,
@@ -164,7 +171,7 @@
  * IIO_ENUM() - Initialize enum extended channel attribute
  * @_name:	Attribute name
  * @_shared:	Whether the attribute is shared between all channels
- * @_e:		Pointer to a iio_enum struct
+ * @_e:		Pointer to an iio_enum struct
  *
  * This should usually be used together with IIO_ENUM_AVAILABLE()
  */
@@ -180,9 +187,9 @@
 /**
  * IIO_ENUM_AVAILABLE() - Initialize enum available extended channel attribute
  * @_name:	Attribute name ("_available" will be appended to the name)
- * @_e:		Pointer to a iio_enum struct
+ * @_e:		Pointer to an iio_enum struct
  *
- * Creates a read only attribute which list all the available enum items in a
+ * Creates a read only attribute which lists all the available enum items in a
  * space separated list. This should usually be used together with IIO_ENUM()
  */
 #define IIO_ENUM_AVAILABLE(_name, _e) \
@@ -229,6 +236,7 @@
  * @indexed:		Specify the channel has a numerical index. If not,
  *			the channel index number will be suppressed for sysfs
  *			attributes but not for event codes.
+ * @output:		Channel is output.
  * @differential:	Channel is differential.
  */
 struct iio_chan_spec {
@@ -255,6 +263,21 @@
 	unsigned		differential:1;
 };
 
+
+/**
+ * iio_channel_has_info() - Checks whether a channel supports a info attribute
+ * @chan: The channel to be queried
+ * @type: Type of the info attribute to be checked
+ *
+ * Returns true if the channels supports reporting values for the given info
+ * attribute type, false otherwise.
+ */
+static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
+	enum iio_chan_info_enum type)
+{
+	return chan->info_mask & IIO_CHAN_INFO_BITS(type);
+}
+
 #define IIO_ST(si, rb, sb, sh)						\
 	{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
 
@@ -312,6 +335,9 @@
  *			Meaning is event dependent.
  * @validate_trigger:	function to validate the trigger when the
  *			current trigger gets changed.
+ * @update_scan_mode:	function to configure device and scan buffer when
+ *			channels have changed
+ * @debugfs_reg_access:	function to read or write register value of device
  **/
 struct iio_info {
 	struct module			*driver_module;
@@ -367,10 +393,10 @@
  *			scan mask is valid for the device.
  */
 struct iio_buffer_setup_ops {
-	int				(*preenable)(struct iio_dev *);
-	int				(*postenable)(struct iio_dev *);
-	int				(*predisable)(struct iio_dev *);
-	int				(*postdisable)(struct iio_dev *);
+	int (*preenable)(struct iio_dev *);
+	int (*postenable)(struct iio_dev *);
+	int (*predisable)(struct iio_dev *);
+	int (*postdisable)(struct iio_dev *);
 	bool (*validate_scan_mask)(struct iio_dev *indio_dev,
 				   const unsigned long *scan_mask);
 };
@@ -516,6 +542,31 @@
 	return indio_dev ? dev_to_iio_dev(get_device(&indio_dev->dev)) : NULL;
 }
 
+
+/**
+ * iio_device_set_drvdata() - Set device driver data
+ * @indio_dev: IIO device structure
+ * @data: Driver specific data
+ *
+ * Allows to attach an arbitrary pointer to an IIO device, which can later be
+ * retrieved by iio_device_get_drvdata().
+ */
+static inline void iio_device_set_drvdata(struct iio_dev *indio_dev, void *data)
+{
+	dev_set_drvdata(&indio_dev->dev, data);
+}
+
+/**
+ * iio_device_get_drvdata() - Get device driver data
+ * @indio_dev: IIO device structure
+ *
+ * Returns the data previously set with iio_device_set_drvdata()
+ */
+static inline void *iio_device_get_drvdata(struct iio_dev *indio_dev)
+{
+	return dev_get_drvdata(&indio_dev->dev);
+}
+
 /* Can we make this smaller? */
 #define IIO_ALIGN L1_CACHE_BYTES
 /**
diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h
index 014d5a1..25eeac7 100644
--- a/include/linux/iio/kfifo_buf.h
+++ b/include/linux/iio/kfifo_buf.h
@@ -1,3 +1,5 @@
+#ifndef __LINUX_IIO_KFIFO_BUF_H__
+#define __LINUX_IIO_KFIFO_BUF_H__
 
 #include <linux/kfifo.h>
 #include <linux/iio/iio.h>
@@ -6,3 +8,4 @@
 struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
 void iio_kfifo_free(struct iio_buffer *r);
 
+#endif
diff --git a/include/linux/iio/machine.h b/include/linux/iio/machine.h
index 400a453..809a3f0 100644
--- a/include/linux/iio/machine.h
+++ b/include/linux/iio/machine.h
@@ -8,6 +8,9 @@
  * the Free Software Foundation.
  */
 
+#ifndef __LINUX_IIO_MACHINE_H__
+#define __LINUX_IIO_MACHINE_H__
+
 /**
  * struct iio_map - description of link between consumer and device channels
  * @adc_channel_label:	Label used to identify the channel on the provider.
@@ -22,3 +25,5 @@
 	const char *consumer_dev_name;
 	const char *consumer_channel;
 };
+
+#endif
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
index a981994..20239da 100644
--- a/include/linux/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -29,7 +29,7 @@
  * instances of a given device.
  **/
 struct iio_trigger_ops {
-	struct module			*owner;
+	struct module *owner;
 	int (*set_trigger_state)(struct iio_trigger *trig, bool state);
 	int (*try_reenable)(struct iio_trigger *trig);
 	int (*validate_device)(struct iio_trigger *trig,
@@ -39,7 +39,7 @@
 
 /**
  * struct iio_trigger - industrial I/O trigger device
- *
+ * @ops:		[DRIVER] operations structure
  * @id:			[INTERN] unique id number
  * @name:		[DRIVER] unique name
  * @dev:		[DRIVER] associated device (if relevant)
@@ -76,19 +76,19 @@
 static inline struct iio_trigger *to_iio_trigger(struct device *d)
 {
 	return container_of(d, struct iio_trigger, dev);
-};
+}
 
 static inline void iio_trigger_put(struct iio_trigger *trig)
 {
 	module_put(trig->ops->owner);
 	put_device(&trig->dev);
-};
+}
 
 static inline void iio_trigger_get(struct iio_trigger *trig)
 {
 	get_device(&trig->dev);
 	__module_get(trig->ops->owner);
-};
+}
 
 /**
  * iio_trigger_register() - register a trigger with the IIO core
@@ -104,7 +104,8 @@
 
 /**
  * iio_trigger_poll() - called on a trigger occurring
- * @trig: trigger which occurred
+ * @trig:	trigger which occurred
+ * @time:	timestamp when trigger occurred
  *
  * Typically called in relevant hardware interrupt handler.
  **/
diff --git a/include/linux/iio/trigger_consumer.h b/include/linux/iio/trigger_consumer.h
index 60d64b3..c4f8c74 100644
--- a/include/linux/iio/trigger_consumer.h
+++ b/include/linux/iio/trigger_consumer.h
@@ -7,6 +7,15 @@
  * the Free Software Foundation.
  */
 
+#ifndef __LINUX_IIO_TRIGGER_CONSUMER_H__
+#define __LINUX_IIO_TRIGGER_CONSUMER_H__
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+
+struct iio_dev;
+struct iio_trigger;
+
 /**
  * struct iio_poll_func - poll function pair
  *
@@ -50,3 +59,5 @@
  */
 int iio_triggered_buffer_postenable(struct iio_dev *indio_dev);
 int iio_triggered_buffer_predisable(struct iio_dev *indio_dev);
+
+#endif
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 44e3977..5c647ec 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -57,5 +57,6 @@
 #define IIO_VAL_INT_PLUS_MICRO 2
 #define IIO_VAL_INT_PLUS_NANO 3
 #define IIO_VAL_INT_PLUS_MICRO_DB 4
+#define IIO_VAL_FRACTIONAL 10
 
 #endif /* _IIO_TYPES_H_ */
diff --git a/include/linux/input.h b/include/linux/input.h
index 725dcd0..ba48743 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -1169,6 +1169,18 @@
 #include <linux/mod_devicetable.h>
 
 /**
+ * struct input_value - input value representation
+ * @type: type of value (EV_KEY, EV_ABS, etc)
+ * @code: the value code
+ * @value: the value
+ */
+struct input_value {
+	__u16 type;
+	__u16 code;
+	__s32 value;
+};
+
+/**
  * struct input_dev - represents an input device
  * @name: name of the device
  * @phys: physical path to the device in the system hierarchy
@@ -1203,11 +1215,7 @@
  *	software autorepeat
  * @timer: timer for software autorepeat
  * @rep: current values for autorepeat parameters (delay, rate)
- * @mt: pointer to array of struct input_mt_slot holding current values
- *	of tracked contacts
- * @mtsize: number of MT slots the device uses
- * @slot: MT slot currently being transmitted
- * @trkid: stores MT tracking ID for the current contact
+ * @mt: pointer to multitouch state
  * @absinfo: array of &struct input_absinfo elements holding information
  *	about absolute axes (current value, min, max, flat, fuzz,
  *	resolution)
@@ -1244,7 +1252,6 @@
  *	last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *	causes input_open_device*() fail with -ENODEV.
- * @sync: set to %true when there were no new events since last EV_SYN
  * @dev: driver model's view of this device
  * @h_list: list of input handles associated with the device. When
  *	accessing the list dev->mutex must be held
@@ -1287,10 +1294,7 @@
 
 	int rep[REP_CNT];
 
-	struct input_mt_slot *mt;
-	int mtsize;
-	int slot;
-	int trkid;
+	struct input_mt *mt;
 
 	struct input_absinfo *absinfo;
 
@@ -1312,12 +1316,14 @@
 	unsigned int users;
 	bool going_away;
 
-	bool sync;
-
 	struct device dev;
 
 	struct list_head	h_list;
 	struct list_head	node;
+
+	unsigned int num_vals;
+	unsigned int max_vals;
+	struct input_value *vals;
 };
 #define to_input_dev(d) container_of(d, struct input_dev, dev)
 
@@ -1378,6 +1384,9 @@
  * @event: event handler. This method is being called by input core with
  *	interrupts disabled and dev->event_lock spinlock held and so
  *	it may not sleep
+ * @events: event sequence handler. This method is being called by
+ *	input core with interrupts disabled and dev->event_lock
+ *	spinlock held and so it may not sleep
  * @filter: similar to @event; separates normal event handlers from
  *	"filters".
  * @match: called after comparing device's id with handler's id_table
@@ -1414,6 +1423,8 @@
 	void *private;
 
 	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+	void (*events)(struct input_handle *handle,
+		       const struct input_value *vals, unsigned int count);
 	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 	bool (*match)(struct input_handler *handler, struct input_dev *dev);
 	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h
index f867375..cc5cca7 100644
--- a/include/linux/input/mt.h
+++ b/include/linux/input/mt.h
@@ -15,12 +15,41 @@
 
 #define TRKID_MAX	0xffff
 
+#define INPUT_MT_POINTER	0x0001	/* pointer device, e.g. trackpad */
+#define INPUT_MT_DIRECT		0x0002	/* direct device, e.g. touchscreen */
+#define INPUT_MT_DROP_UNUSED	0x0004	/* drop contacts not seen in frame */
+#define INPUT_MT_TRACK		0x0008	/* use in-kernel tracking */
+
 /**
  * struct input_mt_slot - represents the state of an input MT slot
  * @abs: holds current values of ABS_MT axes for this slot
+ * @frame: last frame at which input_mt_report_slot_state() was called
+ * @key: optional driver designation of this slot
  */
 struct input_mt_slot {
 	int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
+	unsigned int frame;
+	unsigned int key;
+};
+
+/**
+ * struct input_mt - state of tracked contacts
+ * @trkid: stores MT tracking ID for the next contact
+ * @num_slots: number of MT slots the device uses
+ * @slot: MT slot currently being transmitted
+ * @flags: input_mt operation flags
+ * @frame: increases every time input_mt_sync_frame() is called
+ * @red: reduced cost matrix for in-kernel tracking
+ * @slots: array of slots holding current values of tracked contacts
+ */
+struct input_mt {
+	int trkid;
+	int num_slots;
+	int slot;
+	unsigned int flags;
+	unsigned int frame;
+	int *red;
+	struct input_mt_slot slots[];
 };
 
 static inline void input_mt_set_value(struct input_mt_slot *slot,
@@ -35,12 +64,18 @@
 	return slot->abs[code - ABS_MT_FIRST];
 }
 
-int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots);
+static inline bool input_mt_is_active(const struct input_mt_slot *slot)
+{
+	return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0;
+}
+
+int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
+			unsigned int flags);
 void input_mt_destroy_slots(struct input_dev *dev);
 
-static inline int input_mt_new_trkid(struct input_dev *dev)
+static inline int input_mt_new_trkid(struct input_mt *mt)
 {
-	return dev->trkid++ & TRKID_MAX;
+	return mt->trkid++ & TRKID_MAX;
 }
 
 static inline void input_mt_slot(struct input_dev *dev, int slot)
@@ -64,4 +99,20 @@
 void input_mt_report_finger_count(struct input_dev *dev, int count);
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
 
+void input_mt_sync_frame(struct input_dev *dev);
+
+/**
+ * struct input_mt_pos - contact position
+ * @x: horizontal coordinate
+ * @y: vertical coordinate
+ */
+struct input_mt_pos {
+	s16 x, y;
+};
+
+int input_mt_assign_slots(struct input_dev *dev, int *slots,
+			  const struct input_mt_pos *pos, int num_pos);
+
+int input_mt_get_slot_by_key(struct input_dev *dev, int key);
+
 #endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index c5f856a..5e4e617 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -430,6 +430,8 @@
 	NR_SOFTIRQS
 };
 
+#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))
+
 /* map softirq index to softirq name. update 'softirq_to_name' in
  * kernel/softirq.c when adding a new softirq.
  */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 7e83370..f3b99e1 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -256,72 +256,78 @@
 {
 }
 
-int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
+static inline int iommu_attach_group(struct iommu_domain *domain,
+				     struct iommu_group *group)
 {
 	return -ENODEV;
 }
 
-void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
+static inline void iommu_detach_group(struct iommu_domain *domain,
+				      struct iommu_group *group)
 {
 }
 
-struct iommu_group *iommu_group_alloc(void)
+static inline struct iommu_group *iommu_group_alloc(void)
 {
 	return ERR_PTR(-ENODEV);
 }
 
-void *iommu_group_get_iommudata(struct iommu_group *group)
+static inline void *iommu_group_get_iommudata(struct iommu_group *group)
 {
 	return NULL;
 }
 
-void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
-			       void (*release)(void *iommu_data))
+static inline void iommu_group_set_iommudata(struct iommu_group *group,
+					     void *iommu_data,
+					     void (*release)(void *iommu_data))
 {
 }
 
-int iommu_group_set_name(struct iommu_group *group, const char *name)
+static inline int iommu_group_set_name(struct iommu_group *group,
+				       const char *name)
 {
 	return -ENODEV;
 }
 
-int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+static inline int iommu_group_add_device(struct iommu_group *group,
+					 struct device *dev)
 {
 	return -ENODEV;
 }
 
-void iommu_group_remove_device(struct device *dev)
+static inline void iommu_group_remove_device(struct device *dev)
 {
 }
 
-int iommu_group_for_each_dev(struct iommu_group *group, void *data,
-			     int (*fn)(struct device *, void *))
+static inline int iommu_group_for_each_dev(struct iommu_group *group,
+					   void *data,
+					   int (*fn)(struct device *, void *))
 {
 	return -ENODEV;
 }
 
-struct iommu_group *iommu_group_get(struct device *dev)
+static inline struct iommu_group *iommu_group_get(struct device *dev)
 {
 	return NULL;
 }
 
-void iommu_group_put(struct iommu_group *group)
+static inline void iommu_group_put(struct iommu_group *group)
 {
 }
 
-int iommu_group_register_notifier(struct iommu_group *group,
-				  struct notifier_block *nb)
+static inline int iommu_group_register_notifier(struct iommu_group *group,
+						struct notifier_block *nb)
 {
 	return -ENODEV;
 }
 
-int iommu_group_unregister_notifier(struct iommu_group *group,
-				    struct notifier_block *nb)
+static inline int iommu_group_unregister_notifier(struct iommu_group *group,
+						  struct notifier_block *nb)
 {
 	return 0;
 }
 
-int iommu_group_id(struct iommu_group *group)
+static inline int iommu_group_id(struct iommu_group *group)
 {
 	return -ENODEV;
 }
diff --git a/include/linux/irqchip/bcm2835.h b/include/linux/irqchip/bcm2835.h
new file mode 100644
index 0000000..48a859b
--- /dev/null
+++ b/include/linux/irqchip/bcm2835.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_IRQCHIP_BCM2835_H_
+#define __LINUX_IRQCHIP_BCM2835_H_
+
+#include <asm/exception.h>
+
+extern void bcm2835_init_irq(void);
+
+extern asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+	struct pt_regs *regs);
+
+#endif
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 9a323d1..0ba014c 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -10,12 +10,10 @@
 
 struct irq_affinity_notify;
 struct proc_dir_entry;
-struct timer_rand_state;
 struct module;
 /**
  * struct irq_desc - interrupt descriptor
  * @irq_data:		per irq and chip data passed down to chip functions
- * @timer_rand_state:	pointer to timer rand state struct
  * @kstat_irqs:		irq stats per cpu
  * @handle_irq:		highlevel irq-events handler
  * @preflow_handler:	handler called before the flow handler (currently used by sparc)
diff --git a/include/linux/kdb.h b/include/linux/kdb.h
index 42d9e86..7f6fe6e 100644
--- a/include/linux/kdb.h
+++ b/include/linux/kdb.h
@@ -13,6 +13,14 @@
  * Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
  */
 
+typedef enum {
+	KDB_REPEAT_NONE = 0,	/* Do not repeat this command */
+	KDB_REPEAT_NO_ARGS,	/* Repeat the command without arguments */
+	KDB_REPEAT_WITH_ARGS,	/* Repeat the command including its arguments */
+} kdb_repeat_t;
+
+typedef int (*kdb_func_t)(int, const char **);
+
 #ifdef	CONFIG_KGDB_KDB
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -32,14 +40,6 @@
 
 #define KDB_MAXARGS    16 /* Maximum number of arguments to a function  */
 
-typedef enum {
-	KDB_REPEAT_NONE = 0,	/* Do not repeat this command */
-	KDB_REPEAT_NO_ARGS,	/* Repeat the command without arguments */
-	KDB_REPEAT_WITH_ARGS,	/* Repeat the command including its arguments */
-} kdb_repeat_t;
-
-typedef int (*kdb_func_t)(int, const char **);
-
 /* KDB return codes from a command or internal kdb function */
 #define KDB_NOTFOUND	(-1)
 #define KDB_ARGCOUNT	(-2)
@@ -149,11 +149,14 @@
 			       short, kdb_repeat_t);
 extern int kdb_unregister(char *);
 #else /* ! CONFIG_KGDB_KDB */
-#define kdb_printf(...)
-#define kdb_init(x)
-#define kdb_register(...)
-#define kdb_register_repeat(...)
-#define kdb_uregister(x)
+static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
+static inline void kdb_init(int level) {}
+static inline int kdb_register(char *cmd, kdb_func_t func, char *usage,
+			       char *help, short minlen) { return 0; }
+static inline int kdb_register_repeat(char *cmd, kdb_func_t func, char *usage,
+				      char *help, short minlen,
+				      kdb_repeat_t repeat) { return 0; }
+static inline int kdb_unregister(char *cmd) { return 0; }
 #endif	/* CONFIG_KGDB_KDB */
 enum {
 	KDB_NOT_INITIALIZED,
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 594b419..2451f1f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -91,7 +91,7 @@
 {							\
 	typeof(x) __x = x;				\
 	typeof(divisor) __d = divisor;			\
-	(((typeof(x))-1) >= 0 || (__x) >= 0) ?		\
+	(((typeof(x))-1) > 0 || (__x) > 0) ?		\
 		(((__x) + ((__d) / 2)) / (__d)) :	\
 		(((__x) - ((__d) / 2)) / (__d));	\
 }							\
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 2fbd905..36d12f0 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -130,4 +130,12 @@
 extern void account_steal_ticks(unsigned long ticks);
 extern void account_idle_ticks(unsigned long ticks);
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+extern void vtime_task_switch(struct task_struct *prev);
+extern void vtime_account_system(struct task_struct *tsk);
+extern void vtime_account_idle(struct task_struct *tsk);
+#else
+static inline void vtime_task_switch(struct task_struct *prev) { }
+#endif
+
 #endif /* _LINUX_KERNEL_STAT_H */
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index c4d2fc19..4dff0c6 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -240,6 +240,7 @@
  * hardware breakpoints.
  * @correct_hw_break: Allow an architecture to specify how to correct the
  * hardware debug registers.
+ * @enable_nmi: Manage NMI-triggered entry to KGDB
  */
 struct kgdb_arch {
 	unsigned char		gdb_bpt_instr[BREAK_INSTR_SIZE];
@@ -252,6 +253,8 @@
 	void	(*disable_hw_break)(struct pt_regs *regs);
 	void	(*remove_all_hw_break)(void);
 	void	(*correct_hw_break)(void);
+
+	void	(*enable_nmi)(bool on);
 };
 
 /**
@@ -283,6 +286,16 @@
 
 extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs);
 
+#ifdef CONFIG_SERIAL_KGDB_NMI
+extern int kgdb_register_nmi_console(void);
+extern int kgdb_unregister_nmi_console(void);
+extern bool kgdb_nmi_poll_knock(void);
+#else
+static inline int kgdb_register_nmi_console(void) { return 0; }
+static inline int kgdb_unregister_nmi_console(void) { return 0; }
+static inline bool kgdb_nmi_poll_knock(void) { return 1; }
+#endif
+
 extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
 extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
 extern struct kgdb_io *dbg_io_ops;
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index b6e1f8c..23755ba 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <linux/mutex.h>
+#include <linux/ftrace.h>
 
 #ifdef CONFIG_KPROBES
 #include <asm/kprobes.h>
@@ -48,14 +49,26 @@
 #define KPROBE_REENTER		0x00000004
 #define KPROBE_HIT_SSDONE	0x00000008
 
+/*
+ * If function tracer is enabled and the arch supports full
+ * passing of pt_regs to function tracing, then kprobes can
+ * optimize on top of function tracing.
+ */
+#if defined(CONFIG_FUNCTION_TRACER) && defined(ARCH_SUPPORTS_FTRACE_SAVE_REGS) \
+	&& defined(ARCH_SUPPORTS_KPROBES_ON_FTRACE)
+# define KPROBES_CAN_USE_FTRACE
+#endif
+
 /* Attach to insert probes on any functions which should be ignored*/
 #define __kprobes	__attribute__((__section__(".kprobes.text")))
+
 #else /* CONFIG_KPROBES */
 typedef int kprobe_opcode_t;
 struct arch_specific_insn {
 	int dummy;
 };
 #define __kprobes
+
 #endif /* CONFIG_KPROBES */
 
 struct kprobe;
@@ -128,6 +141,7 @@
 				   * NOTE:
 				   * this flag is only for optimized_kprobe.
 				   */
+#define KPROBE_FLAG_FTRACE	8 /* probe is using ftrace */
 
 /* Has this kprobe gone ? */
 static inline int kprobe_gone(struct kprobe *p)
@@ -146,6 +160,13 @@
 {
 	return p->flags & KPROBE_FLAG_OPTIMIZED;
 }
+
+/* Is this kprobe uses ftrace ? */
+static inline int kprobe_ftrace(struct kprobe *p)
+{
+	return p->flags & KPROBE_FLAG_FTRACE;
+}
+
 /*
  * Special probe type that uses setjmp-longjmp type tricks to resume
  * execution at a specified entry with a matching prototype corresponding
@@ -295,6 +316,12 @@
 #endif
 
 #endif /* CONFIG_OPTPROBES */
+#ifdef KPROBES_CAN_USE_FTRACE
+extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+				  struct ftrace_ops *ops, struct pt_regs *regs);
+extern int arch_prepare_kprobe_ftrace(struct kprobe *p);
+#endif
+
 
 /* Get the kprobe at this addr (if any) - called with preemption disabled */
 struct kprobe *get_kprobe(void *addr);
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 22ccf9d..8d81664 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -14,6 +14,11 @@
 	kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
 
 
+struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
+					  void *data,
+					  unsigned int cpu,
+					  const char *namefmt);
+
 /**
  * kthread_run - create and wake a thread.
  * @threadfn: the function to run until signal_pending(current).
@@ -34,9 +39,13 @@
 
 void kthread_bind(struct task_struct *k, unsigned int cpu);
 int kthread_stop(struct task_struct *k);
-int kthread_should_stop(void);
+bool kthread_should_stop(void);
+bool kthread_should_park(void);
 bool kthread_freezable_should_stop(bool *was_frozen);
 void *kthread_data(struct task_struct *k);
+int kthread_park(struct task_struct *k);
+void kthread_unpark(struct task_struct *k);
+void kthread_parkme(void);
 
 int kthreadd(void *unused);
 extern struct task_struct *kthreadd_task;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b70b48b..8a59e0a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -685,7 +685,7 @@
 static inline void kvm_guest_enter(void)
 {
 	BUG_ON(preemptible());
-	account_system_vtime(current);
+	vtime_account(current);
 	current->flags |= PF_VCPU;
 	/* KVM does not hold any references to rcu protected data when it
 	 * switches CPU into a guest mode. In fact switching to a guest mode
@@ -699,7 +699,7 @@
 
 static inline void kvm_guest_exit(void)
 {
-	account_system_vtime(current);
+	vtime_account(current);
 	current->flags &= ~PF_VCPU;
 }
 
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 1ac7f6e..ff9a9f8 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -19,7 +19,7 @@
 #include <linux/compiler.h>
 #include <linux/mutex.h>
 
-#define MIN_MEMORY_BLOCK_SIZE     (1 << SECTION_SIZE_BITS)
+#define MIN_MEMORY_BLOCK_SIZE     (1UL << SECTION_SIZE_BITS)
 
 struct memory_block {
 	unsigned long start_section_nr;
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
index 3d7ae4d..46c0f32 100644
--- a/include/linux/mfd/max77686.h
+++ b/include/linux/mfd/max77686.h
@@ -74,6 +74,7 @@
 struct max77686_regulator_data {
 	int id;
 	struct regulator_init_data *initdata;
+	struct device_node *of_node;
 };
 
 enum max77686_opmode {
diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h
index f4f0dfa..6823548 100644
--- a/include/linux/mfd/max8998.h
+++ b/include/linux/mfd/max8998.h
@@ -67,7 +67,7 @@
 /**
  * struct max8998_board - packages regulator init data
  * @regulators: array of defined regulators
- * @num_regulators: number of regultors used
+ * @num_regulators: number of regulators used
  * @irq_base: base IRQ number for max8998, required for IRQs
  * @ono: power onoff IRQ number for max8998
  * @buck_voltage_lock: Do NOT change the values of the following six
diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h
index f350fd0..9451471 100644
--- a/include/linux/mfd/tps6586x.h
+++ b/include/linux/mfd/tps6586x.h
@@ -14,6 +14,7 @@
 #define TPS6586X_SLEW_RATE_MASK         0x07
 
 enum {
+	TPS6586X_ID_SYS,
 	TPS6586X_ID_SM_0,
 	TPS6586X_ID_SM_1,
 	TPS6586X_ID_SM_2,
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index 61f0905..de20120 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -1,3 +1,15 @@
+/*
+ * include/linux/micrel_phy.h
+ *
+ * Micrel PHY IDs
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
 #ifndef _MICREL_PHY_H
 #define _MICREL_PHY_H
 
@@ -5,10 +17,11 @@
 
 #define PHY_ID_KSZ9021		0x00221610
 #define PHY_ID_KS8737		0x00221720
-#define PHY_ID_KS8041		0x00221510
-#define PHY_ID_KS8051		0x00221550
+#define PHY_ID_KSZ8021		0x00221555
+#define PHY_ID_KSZ8041		0x00221510
+#define PHY_ID_KSZ8051		0x00221550
 /* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
-#define PHY_ID_KS8001		0x0022161A
+#define PHY_ID_KSZ8001		0x0022161A
 
 /* struct phy_device dev_flags definitions */
 #define MICREL_PHY_50MHZ_CLK	0x00000001
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 6955045..fed3def 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -232,7 +232,7 @@
 	char	type[32];
 	char	compatible[128];
 #ifdef __KERNEL__
-	void	*data;
+	const void *data;
 #else
 	kernel_ulong_t data;
 #endif
@@ -600,4 +600,12 @@
 #define X86_MODEL_ANY  0
 #define X86_FEATURE_ANY 0	/* Same as FPU, you can't test for that */
 
+#define IPACK_ANY_FORMAT 0xff
+#define IPACK_ANY_ID (~0)
+struct ipack_device_id {
+	__u8  format;			/* Format version or IPACK_ANY_ID */
+	__u32 vendor;			/* Vendor ID or IPACK_ANY_ID */
+	__u32 device;			/* Device ID or IPACK_ANY_ID */
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 59dc05f3..5f49cc0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2720,9 +2720,6 @@
 	return dev->name;
 }
 
-extern int __netdev_printk(const char *level, const struct net_device *dev,
-			struct va_format *vaf);
-
 extern __printf(3, 4)
 int netdev_printk(const char *level, const struct net_device *dev,
 		  const char *format, ...);
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 9490a00..c25ccca 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -35,8 +35,10 @@
 	__u64			acq;	/* Admin CQ Base Address */
 };
 
+#define NVME_CAP_MQES(cap)	((cap) & 0xffff)
 #define NVME_CAP_TIMEOUT(cap)	(((cap) >> 24) & 0xff)
 #define NVME_CAP_STRIDE(cap)	(((cap) >> 32) & 0xf)
+#define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
 
 enum {
 	NVME_CC_ENABLE		= 1 << 0,
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 248fba2..9a22b5e 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -22,19 +22,24 @@
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
 	struct pci_bus *pbus = pdev->bus;
+
 	/* Find a PCI root bus */
 	while (!pci_is_root_bus(pbus))
 		pbus = pbus->parent;
-	return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
-					      pbus->number);
+
+	return DEVICE_ACPI_HANDLE(pbus->bridge);
 }
 
 static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 {
-	if (!pci_is_root_bus(pbus))
-		return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
-	return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
-					      pbus->number);
+	struct device *dev;
+
+	if (pci_is_root_bus(pbus))
+		dev = pbus->bridge;
+	else
+		dev = &pbus->self->dev;
+
+	return DEVICE_ACPI_HANDLE(dev);
 }
 #endif
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 5faa831..be1de01 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -254,10 +254,10 @@
 	u8		revision;	/* PCI revision, low byte of class word */
 	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
 	u8		pcie_cap;	/* PCI-E capability offset */
-	u8		pcie_type:4;	/* PCI-E device/port type */
 	u8		pcie_mpss:3;	/* PCI-E Max Payload Size Supported */
 	u8		rom_base_reg;	/* which config register controls the ROM */
 	u8		pin;  		/* which interrupt pin this device uses */
+	u16		pcie_flags_reg;	/* cached PCI-E Capabilities Register */
 
 	struct pci_driver *driver;	/* which driver has allocated this device */
 	u64		dma_mask;	/* Mask of the bits of bus address this
@@ -369,7 +369,6 @@
 
 extern struct pci_dev *alloc_pci_dev(void);
 
-#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
 #define	to_pci_dev(n) container_of(n, struct pci_dev, dev)
 #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
 
@@ -596,7 +595,7 @@
 	int  (*resume_early) (struct pci_dev *dev);
 	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
 	void (*shutdown) (struct pci_dev *dev);
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 	struct device_driver	driver;
 	struct pci_dynids dynids;
 };
@@ -734,9 +733,7 @@
 extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
-extern void __pci_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
-extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);
 extern void pci_sort_breadthfirst(void);
 #define dev_is_pci(d) ((d)->bus == &pci_bus_type)
@@ -755,6 +752,7 @@
 int pci_find_capability(struct pci_dev *dev, int cap);
 int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
 int pci_find_ext_capability(struct pci_dev *dev, int cap);
+int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap);
 int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
 int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
 struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
@@ -816,6 +814,39 @@
 	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
 }
 
+int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
+int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val);
+int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val);
+int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val);
+int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+				       u16 clear, u16 set);
+int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
+					u32 clear, u32 set);
+
+static inline int pcie_capability_set_word(struct pci_dev *dev, int pos,
+					   u16 set)
+{
+	return pcie_capability_clear_and_set_word(dev, pos, 0, set);
+}
+
+static inline int pcie_capability_set_dword(struct pci_dev *dev, int pos,
+					    u32 set)
+{
+	return pcie_capability_clear_and_set_dword(dev, pos, 0, set);
+}
+
+static inline int pcie_capability_clear_word(struct pci_dev *dev, int pos,
+					     u16 clear)
+{
+	return pcie_capability_clear_and_set_word(dev, pos, clear, 0);
+}
+
+static inline int pcie_capability_clear_dword(struct pci_dev *dev, int pos,
+					      u32 clear)
+{
+	return pcie_capability_clear_and_set_dword(dev, pos, clear, 0);
+}
+
 /* user-space driven config access */
 int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
 int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
@@ -1013,7 +1044,6 @@
 	module_driver(__pci_driver, pci_register_driver, \
 		       pci_unregister_driver)
 
-void pci_stop_and_remove_behind_bridge(struct pci_dev *dev);
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
 		  unsigned int vendor, unsigned int device,
@@ -1031,6 +1061,8 @@
 int pci_cfg_space_size(struct pci_dev *dev);
 unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 void pci_setup_bridge(struct pci_bus *bus);
+resource_size_t pcibios_window_alignment(struct pci_bus *bus,
+					 unsigned long type);
 
 #define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
 #define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
@@ -1472,7 +1504,7 @@
 /* Anonymous variables would be nice... */
 #define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class,	\
 				  class_shift, hook)			\
-	static const struct pci_fixup const __pci_fixup_##name __used	\
+	static const struct pci_fixup __pci_fixup_##name __used		\
 	__attribute__((__section__(#section), aligned((sizeof(void *)))))    \
 		= { vendor, device, class, class_shift, hook };
 
@@ -1650,6 +1682,15 @@
 	return !!pci_pcie_cap(dev);
 }
 
+/**
+ * pci_pcie_type - get the PCIe device/port type
+ * @dev: PCI device
+ */
+static inline int pci_pcie_type(const struct pci_dev *dev)
+{
+	return (dev->pcie_flags_reg & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
 void pci_request_acs(void);
 bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags);
 bool pci_acs_path_enabled(struct pci_dev *start,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6b4565c..8d3c427 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1847,7 +1847,6 @@
 #define PCI_DEVICE_ID_SIIG_8S_20x_650	0x2081
 #define PCI_DEVICE_ID_SIIG_8S_20x_850	0x2082
 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL	0x2050
-#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL	0x2530
 
 #define PCI_VENDOR_ID_RADISYS		0x1331
 
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 7fb75b1..20ae747 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -549,6 +549,7 @@
 #define  PCI_EXP_LNKCAP2_SLS_8_0GB 0x04	/* Current Link Speed 8.0GT/s */
 #define  PCI_EXP_LNKCAP2_CROSSLINK 0x100 /* Crosslink supported */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
+#define PCI_EXP_LNKSTA2		50	/* Link Status 2 */
 #define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
 
 /* Extended Capabilities (PCI-X 2.0 and Express) */
@@ -677,6 +678,12 @@
 #define  PCI_PWR_CAP_BUDGET(x)	((x) & 1)	/* Included in system budget */
 #define PCI_EXT_CAP_PWR_SIZEOF	16
 
+/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */
+#define PCI_VNDR_HEADER		4	/* Vendor-Specific Header */
+#define  PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define  PCI_VNDR_HEADER_REV(x)	(((x) >> 16) & 0xf)
+#define  PCI_VNDR_HEADER_LEN(x)	(((x) >> 20) & 0xfff)
+
 /*
  * Hypertransport sub capability types
  *
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
index 6775532..e6f91b1 100644
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -49,7 +49,7 @@
 	int (*resume) (struct pcie_device *dev);
 
 	/* Service Error Recovery Handler */
-	struct pci_error_handlers *err_handler;
+	const struct pci_error_handlers *err_handler;
 
 	/* Link Reset Capability - AER service driver specific */
 	pci_ers_result_t (*reset_link) (struct pci_dev *dev);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 33ed9d6..599afc4 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -130,8 +130,10 @@
 	PERF_SAMPLE_STREAM_ID			= 1U << 9,
 	PERF_SAMPLE_RAW				= 1U << 10,
 	PERF_SAMPLE_BRANCH_STACK		= 1U << 11,
+	PERF_SAMPLE_REGS_USER			= 1U << 12,
+	PERF_SAMPLE_STACK_USER			= 1U << 13,
 
-	PERF_SAMPLE_MAX = 1U << 12,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 14,		/* non-ABI */
 };
 
 /*
@@ -163,6 +165,15 @@
 	 PERF_SAMPLE_BRANCH_HV)
 
 /*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+	PERF_SAMPLE_REGS_ABI_NONE	= 0,
+	PERF_SAMPLE_REGS_ABI_32		= 1,
+	PERF_SAMPLE_REGS_ABI_64		= 2,
+};
+
+/*
  * The format of the data returned by read() on a perf event fd,
  * as specified by attr.read_format:
  *
@@ -194,6 +205,8 @@
 #define PERF_ATTR_SIZE_VER0	64	/* sizeof first published struct */
 #define PERF_ATTR_SIZE_VER1	72	/* add: config2 */
 #define PERF_ATTR_SIZE_VER2	80	/* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3	96	/* add: sample_regs_user */
+					/* add: sample_stack_user */
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
@@ -255,7 +268,10 @@
 				exclude_host   :  1, /* don't count in host   */
 				exclude_guest  :  1, /* don't count in guest  */
 
-				__reserved_1   : 43;
+				exclude_callchain_kernel : 1, /* exclude kernel callchains */
+				exclude_callchain_user   : 1, /* exclude user callchains */
+
+				__reserved_1   : 41;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -271,9 +287,25 @@
 		__u64		bp_len;
 		__u64		config2; /* extension of config1 */
 	};
-	__u64	branch_sample_type; /* enum branch_sample_type */
+	__u64	branch_sample_type; /* enum perf_branch_sample_type */
+
+	/*
+	 * Defines set of user regs to dump on samples.
+	 * See asm/perf_regs.h for details.
+	 */
+	__u64	sample_regs_user;
+
+	/*
+	 * Defines size of the user stack to dump on samples.
+	 */
+	__u32	sample_stack_user;
+
+	/* Align to u64. */
+	__u32	__reserved_2;
 };
 
+#define perf_flags(attr)	(*(&(attr)->read_format + 1))
+
 /*
  * Ioctls that can be done on a perf event fd:
  */
@@ -548,6 +580,13 @@
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
 	 *
 	 *	{ u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+	 *
+	 * 	{ u64			abi; # enum perf_sample_regs_abi
+	 * 	  u64			regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+	 *
+	 * 	{ u64			size;
+	 * 	  char			data[size];
+	 * 	  u64			dyn_size; } && PERF_SAMPLE_STACK_USER
 	 * };
 	 */
 	PERF_RECORD_SAMPLE			= 9,
@@ -609,6 +648,7 @@
 #include <linux/static_key.h>
 #include <linux/atomic.h>
 #include <linux/sysfs.h>
+#include <linux/perf_regs.h>
 #include <asm/local.h>
 
 struct perf_callchain_entry {
@@ -654,6 +694,11 @@
 	struct perf_branch_entry	entries[0];
 };
 
+struct perf_regs_user {
+	__u64		abi;
+	struct pt_regs	*regs;
+};
+
 struct task_struct;
 
 /*
@@ -1133,6 +1178,8 @@
 	struct perf_callchain_entry	*callchain;
 	struct perf_raw_record		*raw;
 	struct perf_branch_stack	*br_stack;
+	struct perf_regs_user		regs_user;
+	u64				stack_user_size;
 };
 
 static inline void perf_sample_data_init(struct perf_sample_data *data,
@@ -1142,7 +1189,10 @@
 	data->addr = addr;
 	data->raw  = NULL;
 	data->br_stack = NULL;
-	data->period	= period;
+	data->period = period;
+	data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE;
+	data->regs_user.regs = NULL;
+	data->stack_user_size = 0;
 }
 
 extern void perf_output_sample(struct perf_output_handle *handle,
@@ -1290,8 +1340,10 @@
 extern int perf_output_begin(struct perf_output_handle *handle,
 			     struct perf_event *event, unsigned int size);
 extern void perf_output_end(struct perf_output_handle *handle);
-extern void perf_output_copy(struct perf_output_handle *handle,
+extern unsigned int perf_output_copy(struct perf_output_handle *handle,
 			     const void *buf, unsigned int len);
+extern unsigned int perf_output_skip(struct perf_output_handle *handle,
+				     unsigned int len);
 extern int perf_swevent_get_recursion_context(void);
 extern void perf_swevent_put_recursion_context(int rctx);
 extern void perf_event_enable(struct perf_event *event);
diff --git a/include/linux/perf_regs.h b/include/linux/perf_regs.h
new file mode 100644
index 0000000..3c73d5f
--- /dev/null
+++ b/include/linux/perf_regs.h
@@ -0,0 +1,25 @@
+#ifndef _LINUX_PERF_REGS_H
+#define _LINUX_PERF_REGS_H
+
+#ifdef CONFIG_HAVE_PERF_REGS
+#include <asm/perf_regs.h>
+u64 perf_reg_value(struct pt_regs *regs, int idx);
+int perf_reg_validate(u64 mask);
+u64 perf_reg_abi(struct task_struct *task);
+#else
+static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+	return 0;
+}
+
+static inline int perf_reg_validate(u64 mask)
+{
+	return mask ? -ENOSYS : 0;
+}
+
+static inline u64 perf_reg_abi(struct task_struct *task)
+{
+	return PERF_SAMPLE_REGS_ABI_NONE;
+}
+#endif /* CONFIG_HAVE_PERF_REGS */
+#endif /* _LINUX_PERF_REGS_H */
diff --git a/include/linux/platform_data/ad5755.h b/include/linux/platform_data/ad5755.h
new file mode 100644
index 0000000..a5a1cb7
--- /dev/null
+++ b/include/linux/platform_data/ad5755.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+#ifndef __LINUX_PLATFORM_DATA_AD5755_H__
+#define __LINUX_PLATFORM_DATA_AD5755_H__
+
+enum ad5755_mode {
+	AD5755_MODE_VOLTAGE_0V_5V		= 0,
+	AD5755_MODE_VOLTAGE_0V_10V		= 1,
+	AD5755_MODE_VOLTAGE_PLUSMINUS_5V	= 2,
+	AD5755_MODE_VOLTAGE_PLUSMINUS_10V	= 3,
+	AD5755_MODE_CURRENT_4mA_20mA		= 4,
+	AD5755_MODE_CURRENT_0mA_20mA		= 5,
+	AD5755_MODE_CURRENT_0mA_24mA		= 6,
+};
+
+enum ad5755_dc_dc_phase {
+	AD5755_DC_DC_PHASE_ALL_SAME_EDGE		= 0,
+	AD5755_DC_DC_PHASE_A_B_SAME_EDGE_C_D_OPP_EDGE	= 1,
+	AD5755_DC_DC_PHASE_A_C_SAME_EDGE_B_D_OPP_EDGE	= 2,
+	AD5755_DC_DC_PHASE_90_DEGREE			= 3,
+};
+
+enum ad5755_dc_dc_freq {
+	AD5755_DC_DC_FREQ_250kHZ = 0,
+	AD5755_DC_DC_FREQ_410kHZ = 1,
+	AD5755_DC_DC_FREQ_650kHZ = 2,
+};
+
+enum ad5755_dc_dc_maxv {
+	AD5755_DC_DC_MAXV_23V	= 0,
+	AD5755_DC_DC_MAXV_24V5	= 1,
+	AD5755_DC_DC_MAXV_27V	= 2,
+	AD5755_DC_DC_MAXV_29V5	= 3,
+};
+
+enum ad5755_slew_rate {
+	AD5755_SLEW_RATE_64k	= 0,
+	AD5755_SLEW_RATE_32k	= 1,
+	AD5755_SLEW_RATE_16k	= 2,
+	AD5755_SLEW_RATE_8k	= 3,
+	AD5755_SLEW_RATE_4k	= 4,
+	AD5755_SLEW_RATE_2k	= 5,
+	AD5755_SLEW_RATE_1k	= 6,
+	AD5755_SLEW_RATE_500	= 7,
+	AD5755_SLEW_RATE_250	= 8,
+	AD5755_SLEW_RATE_125	= 9,
+	AD5755_SLEW_RATE_64	= 10,
+	AD5755_SLEW_RATE_32	= 11,
+	AD5755_SLEW_RATE_16	= 12,
+	AD5755_SLEW_RATE_8	= 13,
+	AD5755_SLEW_RATE_4	= 14,
+	AD5755_SLEW_RATE_0_5	= 15,
+};
+
+enum ad5755_slew_step_size {
+	AD5755_SLEW_STEP_SIZE_1 = 0,
+	AD5755_SLEW_STEP_SIZE_2 = 1,
+	AD5755_SLEW_STEP_SIZE_4 = 2,
+	AD5755_SLEW_STEP_SIZE_8 = 3,
+	AD5755_SLEW_STEP_SIZE_16 = 4,
+	AD5755_SLEW_STEP_SIZE_32 = 5,
+	AD5755_SLEW_STEP_SIZE_64 = 6,
+	AD5755_SLEW_STEP_SIZE_128 = 7,
+	AD5755_SLEW_STEP_SIZE_256 = 8,
+};
+
+/**
+ * struct ad5755_platform_data - AD5755 DAC driver platform data
+ * @ext_dc_dc_compenstation_resistor: Whether an external DC-DC converter
+ * compensation register is used.
+ * @dc_dc_phase: DC-DC converter phase.
+ * @dc_dc_freq: DC-DC converter frequency.
+ * @dc_dc_maxv: DC-DC maximum allowed boost voltage.
+ * @dac.mode: The mode to be used for the DAC output.
+ * @dac.ext_current_sense_resistor: Whether an external current sense resistor
+ * is used.
+ * @dac.enable_voltage_overrange: Whether to enable 20% voltage output overrange.
+ * @dac.slew.enable: Whether to enable digital slew.
+ * @dac.slew.rate: Slew rate of the digital slew.
+ * @dac.slew.step_size: Slew step size of the digital slew.
+ **/
+struct ad5755_platform_data {
+	bool ext_dc_dc_compenstation_resistor;
+	enum ad5755_dc_dc_phase dc_dc_phase;
+	enum ad5755_dc_dc_freq dc_dc_freq;
+	enum ad5755_dc_dc_maxv dc_dc_maxv;
+
+	struct {
+		enum ad5755_mode mode;
+		bool ext_current_sense_resistor;
+		bool enable_voltage_overrange;
+		struct {
+			bool enable;
+			enum ad5755_slew_rate rate;
+			enum ad5755_slew_step_size step_size;
+		} slew;
+	} dac[4];
+};
+
+#endif
diff --git a/include/linux/platform_data/ad7791.h b/include/linux/platform_data/ad7791.h
new file mode 100644
index 0000000..f9e4db1
--- /dev/null
+++ b/include/linux/platform_data/ad7791.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_PLATFORM_DATA_AD7791__
+#define __LINUX_PLATFORM_DATA_AD7791__
+
+/**
+ * struct ad7791_platform_data - AD7791 device platform data
+ * @buffered: If set to true configure the device for buffered input mode.
+ * @burnout_current: If set to true the 100mA burnout current is enabled.
+ * @unipolar: If set to true sample in unipolar mode, if set to false sample in
+ *		bipolar mode.
+ */
+struct ad7791_platform_data {
+	bool buffered;
+	bool burnout_current;
+	bool unipolar;
+};
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/mcbsp.h
rename to include/linux/platform_data/asoc-ti-mcbsp.h
diff --git a/arch/arm/plat-omap/include/plat/dsp.h b/include/linux/platform_data/dsp-omap.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/dsp.h
rename to include/linux/platform_data/dsp-omap.h
diff --git a/arch/arm/plat-omap/include/plat/keypad.h b/include/linux/platform_data/keypad-omap.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/keypad.h
rename to include/linux/platform_data/keypad-omap.h
diff --git a/arch/arm/plat-omap/include/plat/lcd_mipid.h b/include/linux/platform_data/lcd-mipid.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/lcd_mipid.h
rename to include/linux/platform_data/lcd-mipid.h
diff --git a/include/linux/platform_data/max197.h b/include/linux/platform_data/max197.h
new file mode 100644
index 0000000..e2a41dd
--- /dev/null
+++ b/include/linux/platform_data/max197.h
@@ -0,0 +1,21 @@
+/*
+ * Maxim MAX197 A/D Converter Driver
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/max197 file.
+ */
+
+/**
+ * struct max197_platform_data - MAX197 connectivity info
+ * @convert:	Function used to start a conversion with control byte ctrl.
+ *		It must return the raw data, or a negative error code.
+ */
+struct max197_platform_data {
+	int (*convert)(u8 ctrl);
+};
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/include/linux/platform_data/mtd-nand-omap2.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/nand.h
rename to include/linux/platform_data/mtd-nand-omap2.h
diff --git a/arch/arm/plat-omap/include/plat/onenand.h b/include/linux/platform_data/mtd-onenand-omap2.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/onenand.h
rename to include/linux/platform_data/mtd-onenand-omap2.h
diff --git a/include/linux/platform_data/pinctrl-coh901.h b/include/linux/platform_data/pinctrl-coh901.h
new file mode 100644
index 0000000..30dea25
--- /dev/null
+++ b/include/linux/platform_data/pinctrl-coh901.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2007-2012 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * GPIO block resgister definitions and inline macros for
+ * U300 GPIO COH 901 335 or COH 901 571/3
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_U300_GPIO_U300_H
+#define __MACH_U300_GPIO_U300_H
+
+/**
+ * struct u300_gpio_platform - U300 GPIO platform data
+ * @ports: number of GPIO block ports
+ * @gpio_base: first GPIO number for this block (use a free range)
+ * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
+ * @pinctrl_device: pin control device to spawn as child
+ */
+struct u300_gpio_platform {
+	u8 ports;
+	int gpio_base;
+	int gpio_irq_base;
+	struct platform_device *pinctrl_device;
+};
+
+#endif /* __MACH_U300_GPIO_U300_H */
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/include/linux/platform_data/remoteproc-omap.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/remoteproc.h
rename to include/linux/platform_data/remoteproc-omap.h
diff --git a/include/linux/platform_data/sht15.h b/include/linux/platform_data/sht15.h
new file mode 100644
index 0000000..33e0fd2
--- /dev/null
+++ b/include/linux/platform_data/sht15.h
@@ -0,0 +1,33 @@
+/*
+ * sht15.h - support for the SHT15 Temperature and Humidity Sensor
+ *
+ * Copyright (c) 2009 Jonathan Cameron
+ *
+ * Copyright (c) 2007 Wouter Horre
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * For further information, see the Documentation/hwmon/sht15 file.
+ */
+
+/**
+ * struct sht15_platform_data - sht15 connectivity info
+ * @gpio_data:		no. of gpio to which bidirectional data line is
+ *			connected.
+ * @gpio_sck:		no. of gpio to which the data clock is connected.
+ * @supply_mv:		supply voltage in mv. Overridden by regulator if
+ *			available.
+ * @checksum:		flag to indicate the checksum should be validated.
+ * @no_otp_reload:	flag to indicate no reload from OTP.
+ * @low_resolution:	flag to indicate the temp/humidity resolution to use.
+ */
+struct sht15_platform_data {
+	int gpio_data;
+	int gpio_sck;
+	int supply_mv;
+	bool checksum;
+	bool no_otp_reload;
+	bool low_resolution;
+};
diff --git a/arch/arm/plat-omap/include/plat/mcspi.h b/include/linux/platform_data/spi-omap2-mcspi.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/mcspi.h
rename to include/linux/platform_data/spi-omap2-mcspi.h
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/include/linux/platform_data/voltage-omap.h
similarity index 100%
rename from arch/arm/plat-omap/include/plat/voltage.h
rename to include/linux/platform_data/voltage-omap.h
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 60e9994..5711e95 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -14,11 +14,15 @@
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 
+#define PLATFORM_DEVID_NONE	(-1)
+#define PLATFORM_DEVID_AUTO	(-2)
+
 struct mfd_cell;
 
 struct platform_device {
 	const char	* name;
 	int		id;
+	bool		id_auto;
 	struct device	dev;
 	u32		num_resources;
 	struct resource	* resource;
diff --git a/include/linux/pm.h b/include/linux/pm.h
index f067e60..88f034a 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -638,6 +638,7 @@
 	} while (0)
 
 extern int device_pm_wait_for_dev(struct device *sub, struct device *dev);
+extern void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *));
 
 extern int pm_generic_prepare(struct device *dev);
 extern int pm_generic_suspend_late(struct device *dev);
@@ -677,6 +678,10 @@
 	return 0;
 }
 
+static inline void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *))
+{
+}
+
 #define pm_generic_prepare	NULL
 #define pm_generic_suspend	NULL
 #define pm_generic_resume	NULL
diff --git a/include/linux/power/generic-adc-battery.h b/include/linux/power/generic-adc-battery.h
new file mode 100644
index 0000000..b1ebe08
--- /dev/null
+++ b/include/linux/power/generic-adc-battery.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef GENERIC_ADC_BATTERY_H
+#define GENERIC_ADC_BATTERY_H
+
+/**
+ * struct gab_platform_data - platform_data for generic adc iio battery driver.
+ * @battery_info:         recommended structure to specify static power supply
+ *			   parameters
+ * @cal_charge:           calculate charge level.
+ * @gpio_charge_finished: gpio for the charger.
+ * @gpio_inverted:        Should be 1 if the GPIO is active low otherwise 0
+ * @jitter_delay:         delay required after the interrupt to check battery
+ *			  status.Default set is 10ms.
+ */
+struct gab_platform_data {
+	struct power_supply_info battery_info;
+	int	(*cal_charge)(long value);
+	int	gpio_charge_finished;
+	bool	gpio_inverted;
+	int     jitter_delay;
+};
+
+#endif /* GENERIC_ADC_BATTERY_H */
diff --git a/include/linux/power/smartreflex.h b/include/linux/power/smartreflex.h
index 3101e62..4a496eb 100644
--- a/include/linux/power/smartreflex.h
+++ b/include/linux/power/smartreflex.h
@@ -23,7 +23,7 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-#include <plat/voltage.h>
+#include <linux/platform_data/voltage-omap.h>
 
 /*
  * Different Smartreflex IPs version. The v1 is the 65nm version used in
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 115ead2..7c968e4f 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -191,6 +191,21 @@
 extern void rcu_idle_exit(void);
 extern void rcu_irq_enter(void);
 extern void rcu_irq_exit(void);
+
+#ifdef CONFIG_RCU_USER_QS
+extern void rcu_user_enter(void);
+extern void rcu_user_exit(void);
+extern void rcu_user_enter_after_irq(void);
+extern void rcu_user_exit_after_irq(void);
+extern void rcu_user_hooks_switch(struct task_struct *prev,
+				  struct task_struct *next);
+#else
+static inline void rcu_user_enter(void) { }
+static inline void rcu_user_exit(void) { }
+static inline void rcu_user_enter_after_irq(void) { }
+static inline void rcu_user_exit_after_irq(void) { }
+#endif /* CONFIG_RCU_USER_QS */
+
 extern void exit_rcu(void);
 
 /**
@@ -210,14 +225,12 @@
  * to nest RCU_NONIDLE() wrappers, but the nesting level is currently
  * quite limited.  If deeper nesting is required, it will be necessary
  * to adjust DYNTICK_TASK_NESTING_VALUE accordingly.
- *
- * This macro may be used from process-level code only.
  */
 #define RCU_NONIDLE(a) \
 	do { \
-		rcu_idle_exit(); \
+		rcu_irq_enter(); \
 		do { a; } while (0); \
-		rcu_idle_enter(); \
+		rcu_irq_exit(); \
 	} while (0)
 
 /*
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 7f7e00d..e3bcc3f 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -285,6 +285,7 @@
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
@@ -299,6 +300,8 @@
 	unsigned int ack_base;
 	unsigned int wake_base;
 	unsigned int irq_reg_stride;
+	unsigned int mask_invert;
+	bool runtime_pm;
 
 	int num_regs;
 
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index da339fd..c43cd35 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -177,6 +177,8 @@
 unsigned int regulator_get_mode(struct regulator *regulator);
 int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
 
+int regulator_allow_bypass(struct regulator *regulator, bool allow);
+
 /* regulator notifier block */
 int regulator_register_notifier(struct regulator *regulator,
 			      struct notifier_block *nb);
@@ -328,6 +330,12 @@
 	return REGULATOR_MODE_NORMAL;
 }
 
+static inline int regulator_allow_bypass(struct regulator *regulator,
+					 bool allow)
+{
+	return 0;
+}
+
 static inline int regulator_register_notifier(struct regulator *regulator,
 			      struct notifier_block *nb)
 {
@@ -352,4 +360,11 @@
 
 #endif
 
+static inline int regulator_set_voltage_tol(struct regulator *regulator,
+					    int new_uV, int tol_uV)
+{
+	return regulator_set_voltage(regulator,
+				     new_uV - tol_uV, new_uV + tol_uV);
+}
+
 #endif
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index bac4c87..7932a3b 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -32,6 +32,8 @@
 	REGULATOR_STATUS_NORMAL,
 	REGULATOR_STATUS_IDLE,
 	REGULATOR_STATUS_STANDBY,
+	/* The regulator is enabled but not regulating */
+	REGULATOR_STATUS_BYPASS,
 	/* in case that any other status doesn't apply */
 	REGULATOR_STATUS_UNDEFINED,
 };
@@ -58,6 +60,7 @@
  *	regulator_desc.n_voltages.  Voltages may be reported in any order.
  *
  * @set_current_limit: Configure a limit for a current-limited regulator.
+ *                     The driver should select the current closest to max_uA.
  * @get_current_limit: Get the configured limit for a current-limited regulator.
  *
  * @set_mode: Set the configured operating mode for the regulator.
@@ -67,6 +70,9 @@
  * @get_optimum_mode: Get the most efficient operating mode for the regulator
  *                    when running with the specified parameters.
  *
+ * @set_bypass: Set the regulator in bypass mode.
+ * @get_bypass: Get the regulator bypass mode state.
+ *
  * @enable_time: Time taken for the regulator voltage output voltage to
  *               stabilise after being enabled, in microseconds.
  * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
@@ -133,6 +139,10 @@
 	unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
 					  int output_uV, int load_uA);
 
+	/* control and report on bypass mode */
+	int (*set_bypass)(struct regulator_dev *dev, bool enable);
+	int (*get_bypass)(struct regulator_dev *dev, bool *enable);
+
 	/* the operations below are for configuration of regulator state when
 	 * its parent PMIC enters a global STANDBY/HIBERNATE state */
 
@@ -205,6 +215,8 @@
 	unsigned int vsel_mask;
 	unsigned int enable_reg;
 	unsigned int enable_mask;
+	unsigned int bypass_reg;
+	unsigned int bypass_mask;
 
 	unsigned int enable_time;
 };
@@ -221,7 +233,8 @@
  * @driver_data: private regulator data
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
- * @regmap: regmap to use for core regmap helpers
+ * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
+ *          insufficient.
  * @ena_gpio: GPIO controlling regulator enable.
  * @ena_gpio_invert: Sense for GPIO enable control.
  * @ena_gpio_flags: Flags to use when calling gpio_request_one()
@@ -253,6 +266,7 @@
 	int exclusive;
 	u32 use_count;
 	u32 open_count;
+	u32 bypass_count;
 
 	/* lists we belong to */
 	struct list_head list; /* list of all regulators */
@@ -310,6 +324,8 @@
 int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 				   unsigned int old_selector,
 				   unsigned int new_selector);
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
 
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 
diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h
new file mode 100644
index 0000000..5c45c85
--- /dev/null
+++ b/include/linux/regulator/fan53555.h
@@ -0,0 +1,60 @@
+/*
+ * fan53555.h - Fairchild Regulator FAN53555 Driver
+ *
+ * Copyright (C) 2012 Marvell Technology Ltd.
+ * Yunfan Zhang <yfzhang@marvell.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __FAN53555_H__
+
+/* VSEL ID */
+enum {
+	FAN53555_VSEL_ID_0 = 0,
+	FAN53555_VSEL_ID_1,
+};
+
+/* Transition slew rate limiting from a low to high voltage.
+ * -----------------------
+ *   Bin |Slew Rate(mV/uS)
+ * ------|----------------
+ *   000 |    64.00
+ * ------|----------------
+ *   001 |    32.00
+ * ------|----------------
+ *   010 |    16.00
+ * ------|----------------
+ *   011 |     8.00
+ * ------|----------------
+ *   100 |     4.00
+ * ------|----------------
+ *   101 |     2.00
+ * ------|----------------
+ *   110 |     1.00
+ * ------|----------------
+ *   111 |     0.50
+ * -----------------------
+ */
+enum {
+	FAN53555_SLEW_RATE_64MV = 0,
+	FAN53555_SLEW_RATE_32MV,
+	FAN53555_SLEW_RATE_16MV,
+	FAN53555_SLEW_RATE_8MV,
+	FAN53555_SLEW_RATE_4MV,
+	FAN53555_SLEW_RATE_2MV,
+	FAN53555_SLEW_RATE_1MV,
+	FAN53555_SLEW_RATE_0_5MV,
+};
+
+struct fan53555_platform_data {
+	struct regulator_init_data *regulator;
+	unsigned int slew_rate;
+	/* Sleep VSEL ID */
+	unsigned int sleep_vsel_id;
+};
+
+#endif /* __FAN53555_H__ */
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 40dd0a3..36adbc8 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -32,6 +32,7 @@
  *           board/machine.
  * STATUS:   Regulator can be enabled and disabled.
  * DRMS:     Dynamic Regulator Mode Switching is enabled for this regulator.
+ * BYPASS:   Regulator can be put into bypass mode
  */
 
 #define REGULATOR_CHANGE_VOLTAGE	0x1
@@ -39,6 +40,7 @@
 #define REGULATOR_CHANGE_MODE		0x4
 #define REGULATOR_CHANGE_STATUS		0x8
 #define REGULATOR_CHANGE_DRMS		0x10
+#define REGULATOR_CHANGE_BYPASS		0x20
 
 /**
  * struct regulator_state - regulator state during low power system states
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 23bddac..765dffb 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -273,11 +273,11 @@
 extern int runqueue_is_locked(int cpu);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
-extern void select_nohz_load_balancer(int stop_tick);
+extern void nohz_balance_enter_idle(int cpu);
 extern void set_cpu_sd_state_idle(void);
 extern int get_nohz_timer_target(void);
 #else
-static inline void select_nohz_load_balancer(int stop_tick) { }
+static inline void nohz_balance_enter_idle(int cpu) { }
 static inline void set_cpu_sd_state_idle(void) { }
 #endif
 
@@ -446,6 +446,9 @@
 #define MMF_VM_HUGEPAGE		17	/* set when VM_HUGEPAGE is set on vma */
 #define MMF_EXE_FILE_CHANGED	18	/* see prctl_set_mm_exe_file() */
 
+#define MMF_HAS_UPROBES		19	/* has uprobes */
+#define MMF_RECALC_UPROBES	20	/* MMF_HAS_UPROBES can be wrong */
+
 #define MMF_INIT_MASK		(MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
 
 struct sighand_struct {
@@ -678,11 +681,6 @@
 					 * (notably. ptrace) */
 };
 
-/* Context switch must be unlocked if interrupts are to be enabled */
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-# define __ARCH_WANT_UNLOCKED_CTXSW
-#endif
-
 /*
  * Bits in flags field of signal_struct.
  */
@@ -860,7 +858,6 @@
 #define SD_BALANCE_FORK		0x0008	/* Balance on fork, clone */
 #define SD_BALANCE_WAKE		0x0010  /* Balance on wakeup */
 #define SD_WAKE_AFFINE		0x0020	/* Wake task to waking CPU */
-#define SD_PREFER_LOCAL		0x0040  /* Prefer to keep tasks local to this domain */
 #define SD_SHARE_CPUPOWER	0x0080	/* Domain members share cpu power */
 #define SD_SHARE_PKG_RESOURCES	0x0200	/* Domain members share cpu pkg resources */
 #define SD_SERIALIZE		0x0400	/* Only a single load balancing instance */
@@ -1885,6 +1882,14 @@
 
 #endif
 
+static inline void rcu_switch(struct task_struct *prev,
+			      struct task_struct *next)
+{
+#ifdef CONFIG_RCU_USER_QS
+	rcu_user_hooks_switch(prev, next);
+#endif
+}
+
 static inline void tsk_restore_flags(struct task_struct *task,
 				unsigned long orig_flags, unsigned long flags)
 {
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 899fbb4..fb3c5a8 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -68,6 +68,8 @@
 
 #define VIDEO_FLAGS_NOCURSOR	(1 << 0) /* The video mode has no cursor set */
 
+#define VIDEO_CAPABILITY_SKIP_QUIRKS	(1 << 0)
+
 #ifdef __KERNEL__
 extern struct screen_info screen_info;
 
diff --git a/include/linux/security.h b/include/linux/security.h
index 3dea6a9..d143b8e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -118,6 +118,7 @@
 extern unsigned long mmap_min_addr;
 extern unsigned long dac_mmap_min_addr;
 #else
+#define mmap_min_addr		0UL
 #define dac_mmap_min_addr	0UL
 #endif
 
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 7cf0b68..f9b22ec 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -48,7 +48,8 @@
 #define PORT_TEGRA	20	/* NVIDIA Tegra internal UART */
 #define PORT_XR17D15X	21	/* Exar XR17D15x UART */
 #define PORT_LPC3220	22	/* NXP LPC32xx SoC "Standard" UART */
-#define PORT_MAX_8250	22	/* max port ID */
+#define PORT_8250_CIR	23	/* CIR infrared port, has its own driver */
+#define PORT_MAX_8250	23	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
@@ -274,6 +275,7 @@
 	int		(*verify_port)(struct uart_port *, struct serial_struct *);
 	int		(*ioctl)(struct uart_port *, unsigned int, unsigned long);
 #ifdef CONFIG_CONSOLE_POLL
+	int		(*poll_init)(struct uart_port *);
 	void	(*poll_put_char)(struct uart_port *, unsigned char);
 	int		(*poll_get_char)(struct uart_port *);
 #endif
diff --git a/include/linux/sht15.h b/include/linux/sht15.h
deleted file mode 100644
index f85c7c5..0000000
--- a/include/linux/sht15.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * sht15.h - support for the SHT15 Temperature and Humidity Sensor
- *
- * Copyright (c) 2009 Jonathan Cameron
- *
- * Copyright (c) 2007 Wouter Horre
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * For further information, see the Documentation/hwmon/sht15 file.
- */
-
-/**
- * struct sht15_platform_data - sht15 connectivity info
- * @gpio_data:		no. of gpio to which bidirectional data line is
- *			connected.
- * @gpio_sck:		no. of gpio to which the data clock is connected.
- * @supply_mv:		supply voltage in mv. Overridden by regulator if
- *			available.
- * @checksum:		flag to indicate the checksum should be validated.
- * @no_otp_reload:	flag to indicate no reload from OTP.
- * @low_resolution:	flag to indicate the temp/humidity resolution to use.
- */
-struct sht15_platform_data {
-	int gpio_data;
-	int gpio_sck;
-	int supply_mv;
-	bool checksum;
-	bool no_otp_reload;
-	bool low_resolution;
-};
-
diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h
new file mode 100644
index 0000000..e0106d8
--- /dev/null
+++ b/include/linux/smpboot.h
@@ -0,0 +1,43 @@
+#ifndef _LINUX_SMPBOOT_H
+#define _LINUX_SMPBOOT_H
+
+#include <linux/types.h>
+
+struct task_struct;
+/* Cookie handed to the thread_fn*/
+struct smpboot_thread_data;
+
+/**
+ * struct smp_hotplug_thread - CPU hotplug related thread descriptor
+ * @store:		Pointer to per cpu storage for the task pointers
+ * @list:		List head for core management
+ * @thread_should_run:	Check whether the thread should run or not. Called with
+ *			preemption disabled.
+ * @thread_fn:		The associated thread function
+ * @setup:		Optional setup function, called when the thread gets
+ *			operational the first time
+ * @cleanup:		Optional cleanup function, called when the thread
+ *			should stop (module exit)
+ * @park:		Optional park function, called when the thread is
+ *			parked (cpu offline)
+ * @unpark:		Optional unpark function, called when the thread is
+ *			unparked (cpu online)
+ * @thread_comm:	The base name of the thread
+ */
+struct smp_hotplug_thread {
+	struct task_struct __percpu	**store;
+	struct list_head		list;
+	int				(*thread_should_run)(unsigned int cpu);
+	void				(*thread_fn)(unsigned int cpu);
+	void				(*setup)(unsigned int cpu);
+	void				(*cleanup)(unsigned int cpu, bool online);
+	void				(*park)(unsigned int cpu);
+	void				(*unpark)(unsigned int cpu);
+	const char			*thread_comm;
+};
+
+int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread);
+void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread);
+int smpboot_thread_schedule(void);
+
+#endif
diff --git a/include/linux/task_work.h b/include/linux/task_work.h
index fb46b03..ca5a1cf 100644
--- a/include/linux/task_work.h
+++ b/include/linux/task_work.h
@@ -18,8 +18,7 @@
 
 static inline void exit_task_work(struct task_struct *task)
 {
-	if (unlikely(task->task_works))
-		task_work_run();
+	task_work_run();
 }
 
 #endif	/* _LINUX_TASK_WORK_H */
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index 3ca0269..932b763 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -281,9 +281,10 @@
 long st_kim_start(void *);
 long st_kim_stop(void *);
 
-void st_kim_recv(void *, const unsigned char *, long count);
 void st_kim_complete(void *);
 void kim_st_list_protocols(struct st_data_s *, void *);
+void st_kim_recv(void *, const unsigned char *, long);
+
 
 /*
  * BTS headers
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 6abd913..8c5a197 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -49,147 +49,112 @@
 #endif
 
 /*
- * Note that all tvec_bases are 2 byte aligned and lower bit of
- * base in timer_list is guaranteed to be zero. Use the LSB to
- * indicate whether the timer is deferrable.
+ * Note that all tvec_bases are at least 4 byte aligned and lower two bits
+ * of base in timer_list is guaranteed to be zero. Use them for flags.
  *
  * A deferrable timer will work normally when the system is busy, but
  * will not cause a CPU to come out of idle just to service it; instead,
  * the timer will be serviced when the CPU eventually wakes up with a
  * subsequent non-deferrable timer.
+ *
+ * An irqsafe timer is executed with IRQ disabled and it's safe to wait for
+ * the completion of the running instance from IRQ handlers, for example,
+ * by calling del_timer_sync().
+ *
+ * Note: The irq disabled callback execution is a special case for
+ * workqueue locking issues. It's not meant for executing random crap
+ * with interrupts disabled. Abuse is monitored!
  */
-#define TBASE_DEFERRABLE_FLAG		(0x1)
+#define TIMER_DEFERRABLE		0x1LU
+#define TIMER_IRQSAFE			0x2LU
 
-#define TIMER_INITIALIZER(_function, _expires, _data) {		\
+#define TIMER_FLAG_MASK			0x3LU
+
+#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
 		.entry = { .prev = TIMER_ENTRY_STATIC },	\
 		.function = (_function),			\
 		.expires = (_expires),				\
 		.data = (_data),				\
-		.base = &boot_tvec_bases,			\
+		.base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \
 		.slack = -1,					\
 		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
 			__FILE__ ":" __stringify(__LINE__))	\
 	}
 
-#define TBASE_MAKE_DEFERRED(ptr) ((struct tvec_base *)		\
-		  ((unsigned char *)(ptr) + TBASE_DEFERRABLE_FLAG))
+#define TIMER_INITIALIZER(_function, _expires, _data)		\
+	__TIMER_INITIALIZER((_function), (_expires), (_data), 0)
 
-#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) {\
-		.entry = { .prev = TIMER_ENTRY_STATIC },	\
-		.function = (_function),			\
-		.expires = (_expires),				\
-		.data = (_data),				\
-		.base = TBASE_MAKE_DEFERRED(&boot_tvec_bases),	\
-		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
-			__FILE__ ":" __stringify(__LINE__))	\
-	}
+#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data)	\
+	__TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE)
 
 #define DEFINE_TIMER(_name, _function, _expires, _data)		\
 	struct timer_list _name =				\
 		TIMER_INITIALIZER(_function, _expires, _data)
 
-void init_timer_key(struct timer_list *timer,
-		    const char *name,
-		    struct lock_class_key *key);
-void init_timer_deferrable_key(struct timer_list *timer,
-			       const char *name,
-			       struct lock_class_key *key);
-
-#ifdef CONFIG_LOCKDEP
-#define init_timer(timer)						\
-	do {								\
-		static struct lock_class_key __key;			\
-		init_timer_key((timer), #timer, &__key);		\
-	} while (0)
-
-#define init_timer_deferrable(timer)					\
-	do {								\
-		static struct lock_class_key __key;			\
-		init_timer_deferrable_key((timer), #timer, &__key);	\
-	} while (0)
-
-#define init_timer_on_stack(timer)					\
-	do {								\
-		static struct lock_class_key __key;			\
-		init_timer_on_stack_key((timer), #timer, &__key);	\
-	} while (0)
-
-#define setup_timer(timer, fn, data)					\
-	do {								\
-		static struct lock_class_key __key;			\
-		setup_timer_key((timer), #timer, &__key, (fn), (data));\
-	} while (0)
-
-#define setup_timer_on_stack(timer, fn, data)				\
-	do {								\
-		static struct lock_class_key __key;			\
-		setup_timer_on_stack_key((timer), #timer, &__key,	\
-					 (fn), (data));			\
-	} while (0)
-#define setup_deferrable_timer_on_stack(timer, fn, data)		\
-	do {								\
-		static struct lock_class_key __key;			\
-		setup_deferrable_timer_on_stack_key((timer), #timer,	\
-						    &__key, (fn),	\
-						    (data));		\
-	} while (0)
-#else
-#define init_timer(timer)\
-	init_timer_key((timer), NULL, NULL)
-#define init_timer_deferrable(timer)\
-	init_timer_deferrable_key((timer), NULL, NULL)
-#define init_timer_on_stack(timer)\
-	init_timer_on_stack_key((timer), NULL, NULL)
-#define setup_timer(timer, fn, data)\
-	setup_timer_key((timer), NULL, NULL, (fn), (data))
-#define setup_timer_on_stack(timer, fn, data)\
-	setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
-#define setup_deferrable_timer_on_stack(timer, fn, data)\
-	setup_deferrable_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
-#endif
+void init_timer_key(struct timer_list *timer, unsigned int flags,
+		    const char *name, struct lock_class_key *key);
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
 extern void init_timer_on_stack_key(struct timer_list *timer,
-				    const char *name,
+				    unsigned int flags, const char *name,
 				    struct lock_class_key *key);
 extern void destroy_timer_on_stack(struct timer_list *timer);
 #else
 static inline void destroy_timer_on_stack(struct timer_list *timer) { }
 static inline void init_timer_on_stack_key(struct timer_list *timer,
-					   const char *name,
+					   unsigned int flags, const char *name,
 					   struct lock_class_key *key)
 {
-	init_timer_key(timer, name, key);
+	init_timer_key(timer, flags, name, key);
 }
 #endif
 
-static inline void setup_timer_key(struct timer_list * timer,
-				const char *name,
-				struct lock_class_key *key,
-				void (*function)(unsigned long),
-				unsigned long data)
-{
-	timer->function = function;
-	timer->data = data;
-	init_timer_key(timer, name, key);
-}
+#ifdef CONFIG_LOCKDEP
+#define __init_timer(_timer, _flags)					\
+	do {								\
+		static struct lock_class_key __key;			\
+		init_timer_key((_timer), (_flags), #_timer, &__key);	\
+	} while (0)
 
-static inline void setup_timer_on_stack_key(struct timer_list *timer,
-					const char *name,
-					struct lock_class_key *key,
-					void (*function)(unsigned long),
-					unsigned long data)
-{
-	timer->function = function;
-	timer->data = data;
-	init_timer_on_stack_key(timer, name, key);
-}
+#define __init_timer_on_stack(_timer, _flags)				\
+	do {								\
+		static struct lock_class_key __key;			\
+		init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \
+	} while (0)
+#else
+#define __init_timer(_timer, _flags)					\
+	init_timer_key((_timer), (_flags), NULL, NULL)
+#define __init_timer_on_stack(_timer, _flags)				\
+	init_timer_on_stack_key((_timer), (_flags), NULL, NULL)
+#endif
 
-extern void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
-						const char *name,
-						struct lock_class_key *key,
-						void (*function)(unsigned long),
-						unsigned long data);
+#define init_timer(timer)						\
+	__init_timer((timer), 0)
+#define init_timer_deferrable(timer)					\
+	__init_timer((timer), TIMER_DEFERRABLE)
+#define init_timer_on_stack(timer)					\
+	__init_timer_on_stack((timer), 0)
+
+#define __setup_timer(_timer, _fn, _data, _flags)			\
+	do {								\
+		__init_timer((_timer), (_flags));			\
+		(_timer)->function = (_fn);				\
+		(_timer)->data = (_data);				\
+	} while (0)
+
+#define __setup_timer_on_stack(_timer, _fn, _data, _flags)		\
+	do {								\
+		__init_timer_on_stack((_timer), (_flags));		\
+		(_timer)->function = (_fn);				\
+		(_timer)->data = (_data);				\
+	} while (0)
+
+#define setup_timer(timer, fn, data)					\
+	__setup_timer((timer), (fn), (data), 0)
+#define setup_timer_on_stack(timer, fn, data)				\
+	__setup_timer_on_stack((timer), (fn), (data), 0)
+#define setup_deferrable_timer_on_stack(timer, fn, data)		\
+	__setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE)
 
 /**
  * timer_pending - is a timer pending?
diff --git a/include/linux/topology.h b/include/linux/topology.h
index fec12d6..d3cf0d6 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -129,7 +129,6 @@
 				| 1*SD_BALANCE_FORK			\
 				| 0*SD_BALANCE_WAKE			\
 				| 1*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
 				| 0*SD_SHARE_CPUPOWER			\
 				| 1*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
@@ -160,7 +159,6 @@
 				| 1*SD_BALANCE_FORK			\
 				| 0*SD_BALANCE_WAKE			\
 				| 1*SD_WAKE_AFFINE			\
-				| 0*SD_PREFER_LOCAL			\
 				| 0*SD_SHARE_CPUPOWER			\
 				| 0*SD_SHARE_PKG_RESOURCES		\
 				| 0*SD_SERIALIZE			\
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 802de56..2f322c3 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -136,6 +136,22 @@
 		postrcu;						\
 	} while (0)
 
+#ifndef MODULE
+#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)	\
+	static inline void trace_##name##_rcuidle(proto)		\
+	{								\
+		if (static_key_false(&__tracepoint_##name.key))		\
+			__DO_TRACE(&__tracepoint_##name,		\
+				TP_PROTO(data_proto),			\
+				TP_ARGS(data_args),			\
+				TP_CONDITION(cond),			\
+				rcu_idle_exit(),			\
+				rcu_idle_enter());			\
+	}
+#else
+#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
+#endif
+
 /*
  * Make sure the alignment of the structure in the __tracepoints section will
  * not add unwanted padding between the beginning of the section and the
@@ -151,16 +167,8 @@
 				TP_ARGS(data_args),			\
 				TP_CONDITION(cond),,);			\
 	}								\
-	static inline void trace_##name##_rcuidle(proto)		\
-	{								\
-		if (static_key_false(&__tracepoint_##name.key))		\
-			__DO_TRACE(&__tracepoint_##name,		\
-				TP_PROTO(data_proto),			\
-				TP_ARGS(data_args),			\
-				TP_CONDITION(cond),			\
-				rcu_idle_exit(),			\
-				rcu_idle_enter());			\
-	}								\
+	__DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),		\
+		PARAMS(cond), PARAMS(data_proto), PARAMS(data_args))	\
 	static inline int						\
 	register_trace_##name(void (*probe)(data_proto), void *data)	\
 	{								\
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index efe4b33..e6f0331 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -99,25 +99,27 @@
 
 struct uprobes_state {
 	struct xol_area		*xol_area;
-	atomic_t		count;
 };
+
 extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
-extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm,  unsigned long vaddr, bool verify);
+extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
 extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
 extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
 extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
 extern int uprobe_mmap(struct vm_area_struct *vma);
 extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
 extern void uprobe_free_utask(struct task_struct *t);
 extern void uprobe_copy_process(struct task_struct *t);
 extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
+extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch);
+extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch);
 extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
 extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
 extern void uprobe_notify_resume(struct pt_regs *regs);
 extern bool uprobe_deny_signal(void);
 extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
 extern void uprobe_clear_state(struct mm_struct *mm);
-extern void uprobe_reset_state(struct mm_struct *mm);
 #else /* !CONFIG_UPROBES */
 struct uprobes_state {
 };
@@ -138,6 +140,10 @@
 uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 }
+static inline void
+uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+}
 static inline void uprobe_notify_resume(struct pt_regs *regs)
 {
 }
@@ -158,8 +164,5 @@
 static inline void uprobe_clear_state(struct mm_struct *mm)
 {
 }
-static inline void uprobe_reset_state(struct mm_struct *mm)
-{
-}
 #endif /* !CONFIG_UPROBES */
 #endif	/* _LINUX_UPROBES_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 30d1ae3..07915a3 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -384,6 +384,13 @@
 	USB_DEVICE_FIXED,
 };
 
+enum usb_port_connect_type {
+	USB_PORT_CONNECT_TYPE_UNKNOWN = 0,
+	USB_PORT_CONNECT_TYPE_HOT_PLUG,
+	USB_PORT_CONNECT_TYPE_HARD_WIRED,
+	USB_PORT_NOT_USED,
+};
+
 /*
  * USB 3.0 Link Power Management (LPM) parameters.
  *
@@ -469,7 +476,6 @@
  *	access from userspace
  * @usbfs_dentry: usbfs dentry entry for the device
  * @maxchild: number of ports if hub
- * @children: child devices - USB devices that are attached to this hub
  * @quirks: quirks of the whole device
  * @urbnum: number of URBs submitted for the whole device
  * @active_duration: total time device is not suspended
@@ -543,7 +549,6 @@
 	struct list_head filelist;
 
 	int maxchild;
-	struct usb_device **children;
 
 	u32 quirks;
 	atomic_t urbnum;
@@ -572,6 +577,19 @@
 
 extern struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
+extern struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+	int port1);
+
+/**
+ * usb_hub_for_each_child - iterate over all child devices on the hub
+ * @hdev:  USB device belonging to the usb hub
+ * @port1: portnum associated with child device
+ * @child: child device pointer
+ */
+#define usb_hub_for_each_child(hdev, port1, child) \
+	for (port1 = 1,	child =	usb_hub_find_child(hdev, port1); \
+		port1 <= hdev->maxchild; \
+		child = usb_hub_find_child(hdev, ++port1))
 
 /* USB device locking */
 #define usb_lock_device(udev)		device_lock(&(udev)->dev)
@@ -584,6 +602,16 @@
 extern int usb_reset_device(struct usb_device *dev);
 extern void usb_queue_reset_device(struct usb_interface *dev);
 
+#ifdef CONFIG_ACPI
+extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
+	bool enable);
+extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
+#else
+static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
+	bool enable) { return 0; }
+static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
+	{ return true; }
+#endif
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index b6c2863..7692dc6 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -236,8 +236,8 @@
 
 		struct {
 			__u8 bHubHdrDecLat;
-			__u16 wHubDelay;
-			__u16 DeviceRemovable;
+			__le16 wHubDelay;
+			__le16 DeviceRemovable;
 		}  __attribute__ ((packed)) ss;
 	} u;
 } __attribute__ ((packed));
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 9d8c3b6..f8dda06 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -34,6 +34,8 @@
  * the composite model the host can use both functions at the same time.
  */
 
+#include <linux/bcd.h>
+#include <linux/version.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -46,6 +48,9 @@
  */
 #define USB_GADGET_DELAYED_STATUS       0x7fff	/* Impossibly large value */
 
+/* big enough to hold our biggest descriptor */
+#define USB_COMP_EP0_BUFSIZ	1024
+
 struct usb_configuration;
 
 /**
@@ -245,24 +250,31 @@
 void usb_remove_config(struct usb_composite_dev *,
 		struct usb_configuration *);
 
+/* predefined index for usb_composite_driver */
+enum {
+	USB_GADGET_MANUFACTURER_IDX	= 0,
+	USB_GADGET_PRODUCT_IDX,
+	USB_GADGET_SERIAL_IDX,
+	USB_GADGET_FIRST_AVAIL_IDX,
+};
+
 /**
  * struct usb_composite_driver - groups configurations into a gadget
  * @name: For diagnostics, identifies the driver.
- * @iProduct: Used as iProduct override if @dev->iProduct is not set.
- *	If NULL value of @name is taken.
- * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
- *	not set. If NULL a default "<system> <release> with <udc>" value
- *	will be used.
- * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
- *	not set.
  * @dev: Template descriptor for the device, including default device
  *	identifiers.
- * @strings: tables of strings, keyed by identifiers assigned during bind()
- *	and language IDs provided in control requests
+ * @strings: tables of strings, keyed by identifiers assigned during @bind
+ *	and language IDs provided in control requests. Note: The first entries
+ *	are predefined. The first entry that may be used is
+ *	USB_GADGET_FIRST_AVAIL_IDX
  * @max_speed: Highest speed the driver supports.
  * @needs_serial: set to 1 if the gadget needs userspace to provide
  * 	a serial number.  If one is not provided, warning will be printed.
- * @unbind: Reverses bind; called as a side effect of unregistering
+ * @bind: (REQUIRED) Used to allocate resources that are shared across the
+ *	whole device, such as string IDs, and add its configurations using
+ *	@usb_add_config(). This may fail by returning a negative errno
+ *	value; it should return zero on successful initialization.
+ * @unbind: Reverses @bind; called as a side effect of unregistering
  *	this driver.
  * @disconnect: optional driver disconnect method
  * @suspend: Notifies when the host stops sending USB traffic,
@@ -271,9 +283,9 @@
  *	before function notifications
  *
  * Devices default to reporting self powered operation.  Devices which rely
- * on bus powered operation should report this in their @bind() method.
+ * on bus powered operation should report this in their @bind method.
  *
- * Before returning from bind, various fields in the template descriptor
+ * Before returning from @bind, various fields in the template descriptor
  * may be overridden.  These include the idVendor/idProduct/bcdDevice values
  * normally to bind the appropriate host side driver, and the three strings
  * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
@@ -283,14 +295,12 @@
  */
 struct usb_composite_driver {
 	const char				*name;
-	const char				*iProduct;
-	const char				*iManufacturer;
-	const char				*iSerialNumber;
 	const struct usb_device_descriptor	*dev;
 	struct usb_gadget_strings		**strings;
 	enum usb_device_speed			max_speed;
 	unsigned		needs_serial:1;
 
+	int			(*bind)(struct usb_composite_dev *cdev);
 	int			(*unbind)(struct usb_composite_dev *);
 
 	void			(*disconnect)(struct usb_composite_dev *);
@@ -298,10 +308,10 @@
 	/* global suspend hooks */
 	void			(*suspend)(struct usb_composite_dev *);
 	void			(*resume)(struct usb_composite_dev *);
+	struct usb_gadget_driver		gadget_driver;
 };
 
-extern int usb_composite_probe(struct usb_composite_driver *driver,
-			       int (*bind)(struct usb_composite_dev *cdev));
+extern int usb_composite_probe(struct usb_composite_driver *driver);
 extern void usb_composite_unregister(struct usb_composite_driver *driver);
 extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
 
@@ -310,7 +320,6 @@
  * struct usb_composite_device - represents one composite usb gadget
  * @gadget: read-only, abstracts the gadget's usb peripheral controller
  * @req: used for control responses; buffer is pre-allocated
- * @bufsiz: size of buffer pre-allocated in @req
  * @config: the currently active configuration
  *
  * One of these devices is allocated and initialized before the
@@ -341,7 +350,6 @@
 struct usb_composite_dev {
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
-	unsigned			bufsiz;
 
 	struct usb_configuration	*config;
 
@@ -352,9 +360,7 @@
 	struct list_head		configs;
 	struct usb_composite_driver	*driver;
 	u8				next_string_id;
-	u8				manufacturer_override;
-	u8				product_override;
-	u8				serial_override;
+	char				*def_manufacturer;
 
 	/* the gadget driver won't enable the data pullup
 	 * while the deactivation count is nonzero.
@@ -375,6 +381,53 @@
 			      struct usb_string *str);
 extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
 
+/*
+ * Some systems will need runtime overrides for the  product identifiers
+ * published in the device descriptor, either numbers or strings or both.
+ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+struct usb_composite_overwrite {
+	u16	idVendor;
+	u16	idProduct;
+	u16	bcdDevice;
+	char	*serial_number;
+	char	*manufacturer;
+	char	*product;
+};
+#define USB_GADGET_COMPOSITE_OPTIONS()					\
+	static struct usb_composite_overwrite coverwrite;		\
+									\
+	module_param_named(idVendor, coverwrite.idVendor, ushort, S_IRUGO); \
+	MODULE_PARM_DESC(idVendor, "USB Vendor ID");			\
+									\
+	module_param_named(idProduct, coverwrite.idProduct, ushort, S_IRUGO); \
+	MODULE_PARM_DESC(idProduct, "USB Product ID");			\
+									\
+	module_param_named(bcdDevice, coverwrite.bcdDevice, ushort, S_IRUGO); \
+	MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");	\
+									\
+	module_param_named(iSerialNumber, coverwrite.serial_number, charp, \
+			S_IRUGO); \
+	MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");		\
+									\
+	module_param_named(iManufacturer, coverwrite.manufacturer, charp, \
+			S_IRUGO); \
+	MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");	\
+									\
+	module_param_named(iProduct, coverwrite.product, charp, S_IRUGO); \
+	MODULE_PARM_DESC(iProduct, "USB Product string")
+
+void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
+		struct usb_composite_overwrite *covr);
+
+static inline u16 get_default_bcdDevice(void)
+{
+	u16 bcdDevice;
+
+	bcdDevice = bin2bcd((LINUX_VERSION_CODE >> 16 & 0xff)) << 8;
+	bcdDevice |= bin2bcd((LINUX_VERSION_CODE >> 8 & 0xff));
+	return bcdDevice;
+}
 
 /* messaging utils */
 #define DBG(d, fmt, args...) \
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
index de4b9ed..daec99a 100644
--- a/include/linux/usb/ehci_def.h
+++ b/include/linux/usb/ehci_def.h
@@ -171,18 +171,18 @@
 #define USBMODE_CM_HC	(3<<0)		/* host controller mode */
 #define USBMODE_CM_IDLE	(0<<0)		/* idle state */
 
-	u32		reserved4[7];
+	u32		reserved4[6];
 
 /* Moorestown has some non-standard registers, partially due to the fact that
  * its EHCI controller has both TT and LPM support. HOSTPCx are extensions to
  * PORTSCx
  */
 	/* HOSTPC: offset 0x84 */
-	u32		hostpc[0];	/* HOSTPC extension */
+	u32		hostpc[1];	/* HOSTPC extension */
 #define HOSTPC_PHCD	(1<<22)		/* Phy clock disable */
 #define HOSTPC_PSPD	(3<<25)		/* Port speed detection */
 
-	u32		reserved5[17];
+	u32		reserved5[16];
 
 	/* USBMODE_EX: offset 0xc8 */
 	u32		usbmode_ex;	/* USB Device mode extension */
@@ -221,19 +221,36 @@
 extern struct console early_dbgp_console;
 #endif /* CONFIG_EARLY_PRINTK_DBGP */
 
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-/* Call backs from ehci host driver to ehci debug driver */
-extern int dbgp_external_startup(void);
-extern int dbgp_reset_prep(void);
+struct usb_hcd;
+
+#ifdef CONFIG_XEN_DOM0
+extern int xen_dbgp_reset_prep(struct usb_hcd *);
+extern int xen_dbgp_external_startup(struct usb_hcd *);
 #else
-static inline int dbgp_reset_prep(void)
+static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
 {
-	return 1;
+	return 1; /* Shouldn't this be 0? */
 }
-static inline int dbgp_external_startup(void)
+
+static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
 {
 	return -1;
 }
 #endif
 
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+/* Call backs from ehci host driver to ehci debug driver */
+extern int dbgp_external_startup(struct usb_hcd *);
+extern int dbgp_reset_prep(struct usb_hcd *hcd);
+#else
+static inline int dbgp_reset_prep(struct usb_hcd *hcd)
+{
+	return xen_dbgp_reset_prep(hcd);
+}
+static inline int dbgp_external_startup(struct usb_hcd *hcd)
+{
+	return xen_dbgp_external_startup(hcd);
+}
+#endif
+
 #endif /* __LINUX_USB_EHCI_DEF_H */
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 1894f42..c9d09f8 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -41,6 +41,14 @@
 	unsigned	big_endian_mmio:1;
 	unsigned	port_power_on:1;
 	unsigned	port_power_off:1;
+
+	/* Turn on all power and clocks */
+	int (*power_on)(struct platform_device *pdev);
+	/* Turn off all power and clocks */
+	void (*power_off)(struct platform_device *pdev);
+	/* Turn on only VBUS suspend power and hotplug detection,
+	 * turn off everything else */
+	void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_EHCI_PDRIVER_H */
diff --git a/include/linux/usb/ezusb.h b/include/linux/usb/ezusb.h
new file mode 100644
index 0000000..fc618d8
--- /dev/null
+++ b/include/linux/usb/ezusb.h
@@ -0,0 +1,16 @@
+#ifndef __EZUSB_H
+#define __EZUSB_H
+
+
+extern int ezusb_writememory(struct usb_device *dev, int address,
+			     unsigned char *data, int length, __u8 bRequest);
+
+extern int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit);
+extern int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit);
+
+extern int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
+					    const char *firmware_path);
+extern int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
+					    const char *firmware_path);
+
+#endif /* __EZUSB_H */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 9517466..5b6e508 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -474,7 +474,8 @@
 
 	/* Those two are deprecated */
 	int	(*start)(struct usb_gadget_driver *,
-			int (*bind)(struct usb_gadget *));
+			int (*bind)(struct usb_gadget *,
+				struct usb_gadget_driver *driver));
 	int	(*stop)(struct usb_gadget_driver *);
 };
 
@@ -502,6 +503,8 @@
  * @name: Identifies the controller hardware type.  Used in diagnostics
  *	and sometimes configuration.
  * @dev: Driver model state for this abstract device.
+ * @out_epnum: last used out ep number
+ * @in_epnum: last used in ep number
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -536,6 +539,8 @@
 	unsigned			a_alt_hnp_support:1;
 	const char			*name;
 	struct device			dev;
+	unsigned			out_epnum;
+	unsigned			in_epnum;
 };
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
@@ -558,14 +563,7 @@
  */
 static inline int gadget_is_dualspeed(struct usb_gadget *g)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	/* runtime test would check "g->max_speed" ... that might be
-	 * useful to work around hardware bugs, but is mostly pointless
-	 */
-	return 1;
-#else
-	return 0;
-#endif
+	return g->max_speed >= USB_SPEED_HIGH;
 }
 
 /**
@@ -575,15 +573,7 @@
  */
 static inline int gadget_is_superspeed(struct usb_gadget *g)
 {
-#ifdef CONFIG_USB_GADGET_SUPERSPEED
-	/*
-	 * runtime test would check "g->max_speed" ... that might be
-	 * useful to work around hardware bugs, but is mostly pointless
-	 */
-	return 1;
-#else
-	return 0;
-#endif
+	return g->max_speed >= USB_SPEED_SUPER;
 }
 
 /**
@@ -781,6 +771,7 @@
  *	when the host is disconnected.  May be called in_interrupt; this
  *	may not sleep.  Some devices can't detect disconnect, so this might
  *	not be called except as part of controller shutdown.
+ * @bind: the driver's bind callback
  * @unbind: Invoked when the driver is unbound from a gadget,
  *	usually from rmmod (after a disconnect is reported).
  *	Called in a context that permits sleeping.
@@ -835,6 +826,8 @@
 struct usb_gadget_driver {
 	char			*function;
 	enum usb_device_speed	max_speed;
+	int			(*bind)(struct usb_gadget *gadget,
+					struct usb_gadget_driver *driver);
 	void			(*unbind)(struct usb_gadget *);
 	int			(*setup)(struct usb_gadget *,
 					const struct usb_ctrlrequest *);
@@ -860,7 +853,6 @@
 /**
  * usb_gadget_probe_driver - probe a gadget driver
  * @driver: the driver being registered
- * @bind: the driver's bind callback
  * Context: can sleep
  *
  * Call this in your gadget driver's module initialization function,
@@ -869,8 +861,7 @@
  * registration call returns.  It's expected that the @bind() function will
  * be in init sections.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver);
 
 /**
  * usb_gadget_unregister_driver - unregister a gadget driver
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index c5fdb14..608050b2 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -135,8 +135,8 @@
 
 	unsigned int		irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
-	u64			rsrc_start;	/* memory/io resource start */
-	u64			rsrc_len;	/* memory/io resource length */
+	resource_size_t		rsrc_start;	/* memory/io resource start */
+	resource_size_t		rsrc_len;	/* memory/io resource length */
 	unsigned		power_budget;	/* in mA, 0 = no limit */
 
 	/* bandwidth_mutex should be taken before adding or removing
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
new file mode 100644
index 0000000..28884c7
--- /dev/null
+++ b/include/linux/usb/nop-usb-xceiv.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_USB_NOP_XCEIV_H
+#define __LINUX_USB_NOP_XCEIV_H
+
+#include <linux/usb/otg.h>
+
+struct nop_usb_xceiv_platform_data {
+	enum usb_phy_type type;
+};
+
+#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
+/* sometimes transceivers are accessed only through e.g. ULPI */
+extern void usb_nop_xceiv_register(void);
+extern void usb_nop_xceiv_unregister(void);
+#else
+static inline void usb_nop_xceiv_register(void)
+{
+}
+
+static inline void usb_nop_xceiv_unregister(void)
+{
+}
+#endif
+
+#endif /* __LINUX_USB_NOP_XCEIV_H */
diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h
index 2808f2a9..74e7755 100644
--- a/include/linux/usb/ohci_pdriver.h
+++ b/include/linux/usb/ohci_pdriver.h
@@ -33,6 +33,14 @@
 	unsigned	big_endian_desc:1;
 	unsigned	big_endian_mmio:1;
 	unsigned	no_big_frame_no:1;
+
+	/* Turn on all power and clocks */
+	int (*power_on)(struct platform_device *pdev);
+	/* Turn off all power and clocks */
+	void (*power_off)(struct platform_device *pdev);
+	/* Turn on only VBUS suspend power and hotplug detection,
+	 * turn off everything else */
+	void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_OHCI_PDRIVER_H */
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
new file mode 100644
index 0000000..0ea17f8
--- /dev/null
+++ b/include/linux/usb/omap_usb.h
@@ -0,0 +1,46 @@
+/*
+ * omap_usb.h -- omap usb2 phy header file
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_OMAP_USB2_H
+#define __DRIVERS_OMAP_USB2_H
+
+#include <linux/usb/otg.h>
+
+struct omap_usb {
+	struct usb_phy		phy;
+	struct phy_companion	*comparator;
+	struct device		*dev;
+	u32 __iomem		*control_dev;
+	struct clk		*wkupclk;
+	u8			is_suspended:1;
+};
+
+#define	PHY_PD	0x1
+
+#define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
+
+#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
+extern int omap_usb2_set_comparator(struct phy_companion *comparator);
+#else
+static inline int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* __DRIVERS_OMAP_USB_H */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 45824be..e8a5fe8 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -9,56 +9,7 @@
 #ifndef __LINUX_USB_OTG_H
 #define __LINUX_USB_OTG_H
 
-#include <linux/notifier.h>
-
-/* OTG defines lots of enumeration states before device reset */
-enum usb_otg_state {
-	OTG_STATE_UNDEFINED = 0,
-
-	/* single-role peripheral, and dual-role default-b */
-	OTG_STATE_B_IDLE,
-	OTG_STATE_B_SRP_INIT,
-	OTG_STATE_B_PERIPHERAL,
-
-	/* extra dual-role default-b states */
-	OTG_STATE_B_WAIT_ACON,
-	OTG_STATE_B_HOST,
-
-	/* dual-role default-a */
-	OTG_STATE_A_IDLE,
-	OTG_STATE_A_WAIT_VRISE,
-	OTG_STATE_A_WAIT_BCON,
-	OTG_STATE_A_HOST,
-	OTG_STATE_A_SUSPEND,
-	OTG_STATE_A_PERIPHERAL,
-	OTG_STATE_A_WAIT_VFALL,
-	OTG_STATE_A_VBUS_ERR,
-};
-
-enum usb_phy_events {
-	USB_EVENT_NONE,         /* no events or cable disconnected */
-	USB_EVENT_VBUS,         /* vbus valid event */
-	USB_EVENT_ID,           /* id was grounded */
-	USB_EVENT_CHARGER,      /* usb dedicated charger */
-	USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
-};
-
-/* associate a type with PHY */
-enum usb_phy_type {
-	USB_PHY_TYPE_UNDEFINED,
-	USB_PHY_TYPE_USB2,
-	USB_PHY_TYPE_USB3,
-};
-
-struct usb_phy;
-
-/* for transceivers connected thru an ULPI interface, the user must
- * provide access ops
- */
-struct usb_phy_io_ops {
-	int (*read)(struct usb_phy *x, u32 reg);
-	int (*write)(struct usb_phy *x, u32 val, u32 reg);
-};
+#include <linux/usb/phy.h>
 
 struct usb_otg {
 	u8			default_a;
@@ -85,134 +36,9 @@
 
 };
 
-/*
- * the otg driver needs to interact with both device side and host side
- * usb controllers.  it decides which controller is active at a given
- * moment, using the transceiver, ID signal, HNP and sometimes static
- * configuration information (including "board isn't wired for otg").
- */
-struct usb_phy {
-	struct device		*dev;
-	const char		*label;
-	unsigned int		 flags;
-
-	enum usb_phy_type	type;
-	enum usb_otg_state	state;
-	enum usb_phy_events	last_event;
-
-	struct usb_otg		*otg;
-
-	struct device		*io_dev;
-	struct usb_phy_io_ops	*io_ops;
-	void __iomem		*io_priv;
-
-	/* for notification of usb_phy_events */
-	struct atomic_notifier_head	notifier;
-
-	/* to pass extra port status to the root hub */
-	u16			port_status;
-	u16			port_change;
-
-	/* to support controllers that have multiple transceivers */
-	struct list_head	head;
-
-	/* initialize/shutdown the OTG controller */
-	int	(*init)(struct usb_phy *x);
-	void	(*shutdown)(struct usb_phy *x);
-
-	/* effective for B devices, ignored for A-peripheral */
-	int	(*set_power)(struct usb_phy *x,
-				unsigned mA);
-
-	/* for non-OTG B devices: set transceiver into suspend mode */
-	int	(*set_suspend)(struct usb_phy *x,
-				int suspend);
-
-	/* notify phy connect status change */
-	int	(*notify_connect)(struct usb_phy *x, int port);
-	int	(*notify_disconnect)(struct usb_phy *x, int port);
-};
-
-
-/* for board-specific init logic */
-extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
-extern void usb_remove_phy(struct usb_phy *);
-
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
-/* sometimes transceivers are accessed only through e.g. ULPI */
-extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
-#else
-static inline void usb_nop_xceiv_register(void)
-{
-}
-
-static inline void usb_nop_xceiv_unregister(void)
-{
-}
-#endif
-
-/* helpers for direct access thru low-level io interface */
-static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
-{
-	if (x->io_ops && x->io_ops->read)
-		return x->io_ops->read(x, reg);
-
-	return -EINVAL;
-}
-
-static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
-{
-	if (x->io_ops && x->io_ops->write)
-		return x->io_ops->write(x, val, reg);
-
-	return -EINVAL;
-}
-
-static inline int
-usb_phy_init(struct usb_phy *x)
-{
-	if (x->init)
-		return x->init(x);
-
-	return 0;
-}
-
-static inline void
-usb_phy_shutdown(struct usb_phy *x)
-{
-	if (x->shutdown)
-		x->shutdown(x);
-}
-
-/* for usb host and peripheral controller drivers */
 #ifdef CONFIG_USB_OTG_UTILS
-extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
-extern struct usb_phy *devm_usb_get_phy(struct device *dev,
-	enum usb_phy_type type);
-extern void usb_put_phy(struct usb_phy *);
-extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
 extern const char *otg_state_string(enum usb_otg_state state);
 #else
-static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
-{
-	return NULL;
-}
-
-static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
-	enum usb_phy_type type)
-{
-	return NULL;
-}
-
-static inline void usb_put_phy(struct usb_phy *x)
-{
-}
-
-static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
-{
-}
-
 static inline const char *otg_state_string(enum usb_otg_state state)
 {
 	return NULL;
@@ -262,42 +88,6 @@
 }
 
 static inline int
-usb_phy_set_power(struct usb_phy *x, unsigned mA)
-{
-	if (x && x->set_power)
-		return x->set_power(x, mA);
-	return 0;
-}
-
-/* Context: can sleep */
-static inline int
-usb_phy_set_suspend(struct usb_phy *x, int suspend)
-{
-	if (x->set_suspend != NULL)
-		return x->set_suspend(x, suspend);
-	else
-		return 0;
-}
-
-static inline int
-usb_phy_notify_connect(struct usb_phy *x, int port)
-{
-	if (x->notify_connect)
-		return x->notify_connect(x, port);
-	else
-		return 0;
-}
-
-static inline int
-usb_phy_notify_disconnect(struct usb_phy *x, int port)
-{
-	if (x->notify_disconnect)
-		return x->notify_disconnect(x, port);
-	else
-		return 0;
-}
-
-static inline int
 otg_start_srp(struct usb_otg *otg)
 {
 	if (otg && otg->start_srp)
@@ -306,31 +96,7 @@
 	return -ENOTSUPP;
 }
 
-/* notifiers */
-static inline int
-usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&x->notifier, nb);
-}
-
-static inline void
-usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
-	atomic_notifier_chain_unregister(&x->notifier, nb);
-}
-
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
 
-static inline const char *usb_phy_type_string(enum usb_phy_type type)
-{
-	switch (type) {
-	case USB_PHY_TYPE_USB2:
-		return "USB2 PHY";
-	case USB_PHY_TYPE_USB3:
-		return "USB3 PHY";
-	default:
-		return "UNKNOWN PHY TYPE";
-	}
-}
 #endif /* __LINUX_USB_OTG_H */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
new file mode 100644
index 0000000..06b5bae
--- /dev/null
+++ b/include/linux/usb/phy.h
@@ -0,0 +1,233 @@
+/* USB OTG (On The Go) defines */
+/*
+ *
+ * These APIs may be used between USB controllers.  USB device drivers
+ * (for either host or peripheral roles) don't use these calls; they
+ * continue to use just usb_device and usb_gadget.
+ */
+
+#ifndef __LINUX_USB_PHY_H
+#define __LINUX_USB_PHY_H
+
+#include <linux/notifier.h>
+
+enum usb_phy_events {
+	USB_EVENT_NONE,         /* no events or cable disconnected */
+	USB_EVENT_VBUS,         /* vbus valid event */
+	USB_EVENT_ID,           /* id was grounded */
+	USB_EVENT_CHARGER,      /* usb dedicated charger */
+	USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
+};
+
+/* associate a type with PHY */
+enum usb_phy_type {
+	USB_PHY_TYPE_UNDEFINED,
+	USB_PHY_TYPE_USB2,
+	USB_PHY_TYPE_USB3,
+};
+
+/* OTG defines lots of enumeration states before device reset */
+enum usb_otg_state {
+	OTG_STATE_UNDEFINED = 0,
+
+	/* single-role peripheral, and dual-role default-b */
+	OTG_STATE_B_IDLE,
+	OTG_STATE_B_SRP_INIT,
+	OTG_STATE_B_PERIPHERAL,
+
+	/* extra dual-role default-b states */
+	OTG_STATE_B_WAIT_ACON,
+	OTG_STATE_B_HOST,
+
+	/* dual-role default-a */
+	OTG_STATE_A_IDLE,
+	OTG_STATE_A_WAIT_VRISE,
+	OTG_STATE_A_WAIT_BCON,
+	OTG_STATE_A_HOST,
+	OTG_STATE_A_SUSPEND,
+	OTG_STATE_A_PERIPHERAL,
+	OTG_STATE_A_WAIT_VFALL,
+	OTG_STATE_A_VBUS_ERR,
+};
+
+struct usb_phy;
+struct usb_otg;
+
+/* for transceivers connected thru an ULPI interface, the user must
+ * provide access ops
+ */
+struct usb_phy_io_ops {
+	int (*read)(struct usb_phy *x, u32 reg);
+	int (*write)(struct usb_phy *x, u32 val, u32 reg);
+};
+
+struct usb_phy {
+	struct device		*dev;
+	const char		*label;
+	unsigned int		 flags;
+
+	enum usb_phy_type	type;
+	enum usb_otg_state	state;
+	enum usb_phy_events	last_event;
+
+	struct usb_otg		*otg;
+
+	struct device		*io_dev;
+	struct usb_phy_io_ops	*io_ops;
+	void __iomem		*io_priv;
+
+	/* for notification of usb_phy_events */
+	struct atomic_notifier_head	notifier;
+
+	/* to pass extra port status to the root hub */
+	u16			port_status;
+	u16			port_change;
+
+	/* to support controllers that have multiple transceivers */
+	struct list_head	head;
+
+	/* initialize/shutdown the OTG controller */
+	int	(*init)(struct usb_phy *x);
+	void	(*shutdown)(struct usb_phy *x);
+
+	/* effective for B devices, ignored for A-peripheral */
+	int	(*set_power)(struct usb_phy *x,
+				unsigned mA);
+
+	/* for non-OTG B devices: set transceiver into suspend mode */
+	int	(*set_suspend)(struct usb_phy *x,
+				int suspend);
+
+	/* notify phy connect status change */
+	int	(*notify_connect)(struct usb_phy *x, int port);
+	int	(*notify_disconnect)(struct usb_phy *x, int port);
+};
+
+
+/* for board-specific init logic */
+extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
+extern void usb_remove_phy(struct usb_phy *);
+
+/* helpers for direct access thru low-level io interface */
+static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
+{
+	if (x->io_ops && x->io_ops->read)
+		return x->io_ops->read(x, reg);
+
+	return -EINVAL;
+}
+
+static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
+{
+	if (x->io_ops && x->io_ops->write)
+		return x->io_ops->write(x, val, reg);
+
+	return -EINVAL;
+}
+
+static inline int
+usb_phy_init(struct usb_phy *x)
+{
+	if (x->init)
+		return x->init(x);
+
+	return 0;
+}
+
+static inline void
+usb_phy_shutdown(struct usb_phy *x)
+{
+	if (x->shutdown)
+		x->shutdown(x);
+}
+
+/* for usb host and peripheral controller drivers */
+#ifdef CONFIG_USB_OTG_UTILS
+extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
+extern struct usb_phy *devm_usb_get_phy(struct device *dev,
+	enum usb_phy_type type);
+extern void usb_put_phy(struct usb_phy *);
+extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
+#else
+static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
+{
+	return NULL;
+}
+
+static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
+	enum usb_phy_type type)
+{
+	return NULL;
+}
+
+static inline void usb_put_phy(struct usb_phy *x)
+{
+}
+
+static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
+{
+}
+
+#endif
+
+static inline int
+usb_phy_set_power(struct usb_phy *x, unsigned mA)
+{
+	if (x && x->set_power)
+		return x->set_power(x, mA);
+	return 0;
+}
+
+/* Context: can sleep */
+static inline int
+usb_phy_set_suspend(struct usb_phy *x, int suspend)
+{
+	if (x->set_suspend != NULL)
+		return x->set_suspend(x, suspend);
+	else
+		return 0;
+}
+
+static inline int
+usb_phy_notify_connect(struct usb_phy *x, int port)
+{
+	if (x->notify_connect)
+		return x->notify_connect(x, port);
+	else
+		return 0;
+}
+
+static inline int
+usb_phy_notify_disconnect(struct usb_phy *x, int port)
+{
+	if (x->notify_disconnect)
+		return x->notify_disconnect(x, port);
+	else
+		return 0;
+}
+
+/* notifiers */
+static inline int
+usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&x->notifier, nb);
+}
+
+static inline void
+usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&x->notifier, nb);
+}
+
+static inline const char *usb_phy_type_string(enum usb_phy_type type)
+{
+	switch (type) {
+	case USB_PHY_TYPE_USB2:
+		return "USB2 PHY";
+	case USB_PHY_TYPE_USB3:
+		return "USB3 PHY";
+	default:
+		return "UNKNOWN PHY TYPE";
+	}
+}
+#endif /* __LINUX_USB_PHY_H */
diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h
new file mode 100644
index 0000000..edd2ec2
--- /dev/null
+++ b/include/linux/usb/phy_companion.h
@@ -0,0 +1,34 @@
+/*
+ * phy-companion.h -- phy companion to indicate the comparator part of PHY
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_PHY_COMPANION_H
+#define __DRIVERS_PHY_COMPANION_H
+
+#include <linux/usb/otg.h>
+
+/* phy_companion to take care of VBUS, ID and srp capabilities */
+struct phy_companion {
+
+	/* effective for A-peripheral, ignored for B devices */
+	int	(*set_vbus)(struct phy_companion *x, bool enabled);
+
+	/* for B devices only:  start session with A-Host */
+	int	(*start_srp)(struct phy_companion *x);
+};
+
+#endif /* __DRIVERS_PHY_COMPANION_H */
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 3e93de7..52f944d 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -19,8 +19,8 @@
 /* device can't handle its Configuration or Interface strings */
 #define USB_QUIRK_CONFIG_INTF_STRINGS	0x00000008
 
-/*device will morph if reset, don't use reset for handling errors */
-#define USB_QUIRK_RESET_MORPHS		0x00000010
+/* device can't be reset(e.g morph devices), don't use reset */
+#define USB_QUIRK_RESET			0x00000010
 
 /* device has more interface descriptions than the bNumInterfaces count,
    and can't handle talking to these interfaces */
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 86c0b45..ef9be7e 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -301,17 +301,13 @@
 extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
 extern int usb_serial_resume(struct usb_interface *intf);
 
-extern int ezusb_writememory(struct usb_serial *serial, int address,
-			     unsigned char *data, int length, __u8 bRequest);
-extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
-
 /* USB Serial console functions */
 #ifdef CONFIG_USB_SERIAL_CONSOLE
-extern void usb_serial_console_init(int debug, int minor);
+extern void usb_serial_console_init(int minor);
 extern void usb_serial_console_exit(void);
 extern void usb_serial_console_disconnect(struct usb_serial *serial);
 #else
-static inline void usb_serial_console_init(int debug, int minor) { }
+static inline void usb_serial_console_init(int minor) { }
 static inline void usb_serial_console_exit(void) { }
 static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
 #endif
@@ -333,7 +329,7 @@
 extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
 extern void usb_serial_generic_disconnect(struct usb_serial *serial);
 extern void usb_serial_generic_release(struct usb_serial *serial);
-extern int usb_serial_generic_register(int debug);
+extern int usb_serial_generic_register(void);
 extern void usb_serial_generic_deregister(void);
 extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
 						 gfp_t mem_flags);
@@ -355,30 +351,14 @@
 extern struct bus_type usb_serial_bus_type;
 extern struct tty_driver *usb_serial_tty_driver;
 
-static inline void usb_serial_debug_data(int debug,
-					 struct device *dev,
+static inline void usb_serial_debug_data(struct device *dev,
 					 const char *function, int size,
 					 const unsigned char *data)
 {
-	int i;
-
-	if (debug) {
-		dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ",
-			   function, size);
-		for (i = 0; i < size; ++i)
-			printk("%.2x ", data[i]);
-		printk("\n");
-	}
+	dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+		function, size, size, data);
 }
 
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(format, arg...)						\
-do {									\
-	if (debug)							\
-		printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg);	\
-} while (0)
-
 /*
  * Macro for reporting errors in write path to avoid inifinite loop
  * when port is used as a console.
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
new file mode 100644
index 0000000..176b1ca
--- /dev/null
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __TEGRA_USB_PHY_H
+#define __TEGRA_USB_PHY_H
+
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+
+struct tegra_utmip_config {
+	u8 hssync_start_delay;
+	u8 elastic_limit;
+	u8 idle_wait_delay;
+	u8 term_range_adj;
+	u8 xcvr_setup;
+	u8 xcvr_lsfslew;
+	u8 xcvr_lsrslew;
+};
+
+struct tegra_ulpi_config {
+	int reset_gpio;
+	const char *clk;
+};
+
+enum tegra_usb_phy_port_speed {
+	TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
+	TEGRA_USB_PHY_PORT_SPEED_LOW,
+	TEGRA_USB_PHY_PORT_SPEED_HIGH,
+};
+
+enum tegra_usb_phy_mode {
+	TEGRA_USB_PHY_MODE_DEVICE,
+	TEGRA_USB_PHY_MODE_HOST,
+};
+
+struct tegra_xtal_freq;
+
+struct tegra_usb_phy {
+	int instance;
+	const struct tegra_xtal_freq *freq;
+	void __iomem *regs;
+	void __iomem *pad_regs;
+	struct clk *clk;
+	struct clk *pll_u;
+	struct clk *pad_clk;
+	enum tegra_usb_phy_mode mode;
+	void *config;
+	struct usb_phy *ulpi;
+	struct usb_phy u_phy;
+	struct device *dev;
+};
+
+struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
+	void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+				 enum tegra_usb_phy_port_speed port_speed);
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
+
+#endif /* __TEGRA_USB_PHY_H */
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index e84e769..bf99cd0 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -72,33 +72,9 @@
 enum { US_DO_ALL_FLAGS };
 #undef US_FLAG
 
-/*
- * The bias field for libusual and friends.
- */
-#define USB_US_TYPE_NONE   0
-#define USB_US_TYPE_STOR   1		/* usb-storage */
-#define USB_US_TYPE_UB     2		/* ub */
-
-#define USB_US_TYPE(flags) 		(((flags) >> 24) & 0xFF)
-#define USB_US_ORIG_FLAGS(flags)	((flags) & 0x00FFFFFF)
-
 #include <linux/usb/storage.h>
 
-/*
- */
 extern int usb_usual_ignore_device(struct usb_interface *intf);
 extern struct usb_device_id usb_storage_usb_ids[];
 
-#ifdef CONFIG_USB_LIBUSUAL
-
-extern void usb_usual_set_present(int type);
-extern void usb_usual_clear_present(int type);
-extern int usb_usual_check_type(const struct usb_device_id *, int type);
-#else
-
-#define usb_usual_set_present(t)	do { } while(0)
-#define usb_usual_clear_present(t)	do { } while(0)
-#define usb_usual_check_type(id, t)	(0)
-#endif /* CONFIG_USB_LIBUSUAL */
-
 #endif /* __LINUX_USB_USUAL_H */
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 3b74666..4abe28e4 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -131,6 +131,19 @@
 #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM		0x04
 #define USBDEVFS_CAP_BULK_SCATTER_GATHER	0x08
 
+/* USBDEVFS_DISCONNECT_CLAIM flags & struct */
+
+/* disconnect-and-claim if the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER	0x01
+/* disconnect-and-claim except when the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER	0x02
+
+struct usbdevfs_disconnect_claim {
+	unsigned int interface;
+	unsigned int flags;
+	char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
 #ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
@@ -211,5 +224,6 @@
 #define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
 #define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
 #define USBDEVFS_GET_CAPABILITIES  _IOR('U', 26, __u32)
+#define USBDEVFS_DISCONNECT_CLAIM  _IOR('U', 27, struct usbdevfs_disconnect_claim)
 
 #endif /* _LINUX_USBDEVICE_FS_H */
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
index 3adeff8..065e3ae 100644
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -19,6 +19,7 @@
 	unsigned int pin;
 	unsigned int is_open_drain:1;
 	void (*enable_external_pullup)(int enable);
+	unsigned int ext_pullup_enable_pin;
 };
 
 #endif /* _LINUX_W1_GPIO_H */
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 22e61fd..28e493b 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -84,6 +84,8 @@
 	__u32	bitmap;
 };
 
+#define XFRMA_REPLAY_ESN_MAX	4096
+
 struct xfrm_replay_state_esn {
 	unsigned int	bmp_len;
 	__u32		oseq;
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 0fedbd8..9fc7114 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -111,9 +111,8 @@
 	struct inet6_dev		*rt6i_idev;
 	unsigned long			_rt6i_peer;
 
-#ifdef CONFIG_XFRM
-	u32				rt6i_flow_cache_genid;
-#endif
+	u32				rt6i_genid;
+
 	/* more non-fragment space at head required */
 	unsigned short			rt6i_nfheader_len;
 
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index ae1cd6c..fd87963 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -102,6 +102,7 @@
 #endif
 	struct netns_ipvs	*ipvs;
 	struct sock		*diag_nlsk;
+	atomic_t		rt_genid;
 };
 
 
@@ -300,5 +301,14 @@
 }
 #endif
 
+static inline int rt_genid(struct net *net)
+{
+	return atomic_read(&net->rt_genid);
+}
+
+static inline void rt_genid_bump(struct net *net)
+{
+	atomic_inc(&net->rt_genid);
+}
 
 #endif /* __NET_NET_NAMESPACE_H */
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 1474dd6..eb24dbc 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -65,7 +65,6 @@
 	unsigned int sysctl_ping_group_range[2];
 	long sysctl_tcp_mem[3];
 
-	atomic_t rt_genid;
 	atomic_t dev_addr_genid;
 
 #ifdef CONFIG_IP_MROUTE
diff --git a/include/net/route.h b/include/net/route.h
index 776a27f..da22243 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -108,7 +108,7 @@
 
 struct in_device;
 extern int		ip_rt_init(void);
-extern void		rt_cache_flush(struct net *net, int how);
+extern void		rt_cache_flush(struct net *net);
 extern void		rt_flush_dev(struct net_device *dev);
 extern struct rtable *__ip_route_output_key(struct net *, struct flowi4 *flp);
 extern struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,
diff --git a/include/net/sock.h b/include/net/sock.h
index 72132ae..adb7da2 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1332,7 +1332,7 @@
 }
 
 static inline bool
-sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, unsigned int size)
+sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, int size)
 {
 	if (!sk_has_account(sk))
 		return true;
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index b0b4eb2..1905ca8 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -1,5 +1,5 @@
 /*
- * Trace files that want to automate creationg of all tracepoints defined
+ * Trace files that want to automate creation of all tracepoints defined
  * in their file should include this file. The following are macros that the
  * trace file may define:
  *
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index 5f889f1..08fa272 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -214,7 +214,7 @@
 
 	TP_printk("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s",
 		__entry->page,
-		page_to_pfn(__entry->page),
+		__entry->page ? page_to_pfn(__entry->page) : 0,
 		__entry->order,
 		__entry->migratetype,
 		show_gfp_flags(__entry->gfp_flags))
@@ -240,7 +240,7 @@
 
 	TP_printk("page=%p pfn=%lu order=%u migratetype=%d percpu_refill=%d",
 		__entry->page,
-		page_to_pfn(__entry->page),
+		__entry->page ? page_to_pfn(__entry->page) : 0,
 		__entry->order,
 		__entry->migratetype,
 		__entry->order == 0)
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index 11e27c3..f19fff8 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -187,6 +187,7 @@
 		    struct gnttab_map_grant_ref *kmap_ops,
 		    struct page **pages, unsigned int count);
 int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
-		      struct page **pages, unsigned int count, bool clear_pte);
+		      struct gnttab_map_grant_ref *kunmap_ops,
+		      struct page **pages, unsigned int count);
 
 #endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 9ce788d..bfa1d50 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -258,6 +258,22 @@
     uint8_t devfn;
 };
 
+#define PHYSDEVOP_DBGP_RESET_PREPARE    1
+#define PHYSDEVOP_DBGP_RESET_DONE       2
+
+#define PHYSDEVOP_DBGP_BUS_UNKNOWN      0
+#define PHYSDEVOP_DBGP_BUS_PCI          1
+
+#define PHYSDEVOP_dbgp_op               29
+struct physdev_dbgp_op {
+    /* IN */
+    uint8_t op;
+    uint8_t bus;
+    union {
+        struct physdev_pci_device pci;
+    } u;
+};
+
 /*
  * Notify that some PIRQ-bound event channels have been unmasked.
  * ** This command is obsolete since interface version 0x00030202 and is **
diff --git a/init/Kconfig b/init/Kconfig
index af6c7f8..73e4adf 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -267,31 +267,6 @@
 	depends on SYSCTL
 	default y
 
-config BSD_PROCESS_ACCT
-	bool "BSD Process Accounting"
-	help
-	  If you say Y here, a user level program will be able to instruct the
-	  kernel (via a special system call) to write process accounting
-	  information to a file: whenever a process exits, information about
-	  that process will be appended to the file by the kernel.  The
-	  information includes things such as creation time, owning user,
-	  command name, memory usage, controlling terminal etc. (the complete
-	  list is in the struct acct in <file:include/linux/acct.h>).  It is
-	  up to the user level program to do useful things with this
-	  information.  This is generally a good idea, so say Y.
-
-config BSD_PROCESS_ACCT_V3
-	bool "BSD Process Accounting version 3 file format"
-	depends on BSD_PROCESS_ACCT
-	default n
-	help
-	  If you say Y here, the process accounting information is written
-	  in a new file format that also logs the process IDs of each
-	  process and it's parent. Note that this file format is incompatible
-	  with previous v0/v1/v2 file formats, so you will need updated tools
-	  for processing it. A preliminary version of these tools is available
-	  at <http://www.gnu.org/software/acct/>.
-
 config FHANDLE
 	bool "open by fhandle syscalls"
 	select EXPORTFS
@@ -304,48 +279,6 @@
 	  get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2)
 	  syscalls.
 
-config TASKSTATS
-	bool "Export task/process statistics through netlink (EXPERIMENTAL)"
-	depends on NET
-	default n
-	help
-	  Export selected statistics for tasks/processes through the
-	  generic netlink interface. Unlike BSD process accounting, the
-	  statistics are available during the lifetime of tasks/processes as
-	  responses to commands. Like BSD accounting, they are sent to user
-	  space on task exit.
-
-	  Say N if unsure.
-
-config TASK_DELAY_ACCT
-	bool "Enable per-task delay accounting (EXPERIMENTAL)"
-	depends on TASKSTATS
-	help
-	  Collect information on time spent by a task waiting for system
-	  resources like cpu, synchronous block I/O completion and swapping
-	  in pages. Such statistics can help in setting a task's priorities
-	  relative to other tasks for cpu, io, rss limits etc.
-
-	  Say N if unsure.
-
-config TASK_XACCT
-	bool "Enable extended accounting over taskstats (EXPERIMENTAL)"
-	depends on TASKSTATS
-	help
-	  Collect extended task accounting data and send the data
-	  to userland for processing over the taskstats interface.
-
-	  Say N if unsure.
-
-config TASK_IO_ACCOUNTING
-	bool "Enable per-task storage I/O accounting (EXPERIMENTAL)"
-	depends on TASK_XACCT
-	help
-	  Collect information on the number of bytes of storage I/O which this
-	  task has caused.
-
-	  Say N if unsure.
-
 config AUDIT
 	bool "Auditing support"
 	depends on NET
@@ -391,6 +324,118 @@
 source "kernel/irq/Kconfig"
 source "kernel/time/Kconfig"
 
+menu "CPU/Task time and stats accounting"
+
+choice
+	prompt "Cputime accounting"
+	default TICK_CPU_ACCOUNTING if !PPC64
+	default VIRT_CPU_ACCOUNTING if PPC64
+
+# Kind of a stub config for the pure tick based cputime accounting
+config TICK_CPU_ACCOUNTING
+	bool "Simple tick based cputime accounting"
+	depends on !S390
+	help
+	  This is the basic tick based cputime accounting that maintains
+	  statistics about user, system and idle time spent on per jiffies
+	  granularity.
+
+	  If unsure, say Y.
+
+config VIRT_CPU_ACCOUNTING
+	bool "Deterministic task and CPU time accounting"
+	depends on HAVE_VIRT_CPU_ACCOUNTING
+	help
+	  Select this option to enable more accurate task and CPU time
+	  accounting.  This is done by reading a CPU counter on each
+	  kernel entry and exit and on transitions within the kernel
+	  between system, softirq and hardirq state, so there is a
+	  small performance impact.  In the case of s390 or IBM POWER > 5,
+	  this also enables accounting of stolen time on logically-partitioned
+	  systems.
+
+config IRQ_TIME_ACCOUNTING
+	bool "Fine granularity task level IRQ time accounting"
+	depends on HAVE_IRQ_TIME_ACCOUNTING
+	help
+	  Select this option to enable fine granularity task irq time
+	  accounting. This is done by reading a timestamp on each
+	  transitions between softirq and hardirq state, so there can be a
+	  small performance impact.
+
+	  If in doubt, say N here.
+
+endchoice
+
+config BSD_PROCESS_ACCT
+	bool "BSD Process Accounting"
+	help
+	  If you say Y here, a user level program will be able to instruct the
+	  kernel (via a special system call) to write process accounting
+	  information to a file: whenever a process exits, information about
+	  that process will be appended to the file by the kernel.  The
+	  information includes things such as creation time, owning user,
+	  command name, memory usage, controlling terminal etc. (the complete
+	  list is in the struct acct in <file:include/linux/acct.h>).  It is
+	  up to the user level program to do useful things with this
+	  information.  This is generally a good idea, so say Y.
+
+config BSD_PROCESS_ACCT_V3
+	bool "BSD Process Accounting version 3 file format"
+	depends on BSD_PROCESS_ACCT
+	default n
+	help
+	  If you say Y here, the process accounting information is written
+	  in a new file format that also logs the process IDs of each
+	  process and it's parent. Note that this file format is incompatible
+	  with previous v0/v1/v2 file formats, so you will need updated tools
+	  for processing it. A preliminary version of these tools is available
+	  at <http://www.gnu.org/software/acct/>.
+
+config TASKSTATS
+	bool "Export task/process statistics through netlink (EXPERIMENTAL)"
+	depends on NET
+	default n
+	help
+	  Export selected statistics for tasks/processes through the
+	  generic netlink interface. Unlike BSD process accounting, the
+	  statistics are available during the lifetime of tasks/processes as
+	  responses to commands. Like BSD accounting, they are sent to user
+	  space on task exit.
+
+	  Say N if unsure.
+
+config TASK_DELAY_ACCT
+	bool "Enable per-task delay accounting (EXPERIMENTAL)"
+	depends on TASKSTATS
+	help
+	  Collect information on time spent by a task waiting for system
+	  resources like cpu, synchronous block I/O completion and swapping
+	  in pages. Such statistics can help in setting a task's priorities
+	  relative to other tasks for cpu, io, rss limits etc.
+
+	  Say N if unsure.
+
+config TASK_XACCT
+	bool "Enable extended accounting over taskstats (EXPERIMENTAL)"
+	depends on TASKSTATS
+	help
+	  Collect extended task accounting data and send the data
+	  to userland for processing over the taskstats interface.
+
+	  Say N if unsure.
+
+config TASK_IO_ACCOUNTING
+	bool "Enable per-task storage I/O accounting (EXPERIMENTAL)"
+	depends on TASK_XACCT
+	help
+	  Collect information on the number of bytes of storage I/O which this
+	  task has caused.
+
+	  Say N if unsure.
+
+endmenu # "CPU/Task time and stats accounting"
+
 menu "RCU Subsystem"
 
 choice
@@ -441,6 +486,24 @@
 	  This option enables preemptible-RCU code that is common between
 	  the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
 
+config RCU_USER_QS
+	bool "Consider userspace as in RCU extended quiescent state"
+	depends on HAVE_RCU_USER_QS && SMP
+	help
+	  This option sets hooks on kernel / userspace boundaries and
+	  puts RCU in extended quiescent state when the CPU runs in
+	  userspace. It means that when a CPU runs in userspace, it is
+	  excluded from the global RCU state machine and thus doesn't
+	  to keep the timer tick on for RCU.
+
+config RCU_USER_QS_FORCE
+	bool "Force userspace extended QS by default"
+	depends on RCU_USER_QS
+	help
+	  Set the hooks in user/kernel boundaries by default in order to
+	  test this feature that treats userspace as an extended quiescent
+	  state until we have a real user like a full adaptive nohz option.
+
 config RCU_FANOUT
 	int "Tree-based hierarchical RCU fanout value"
 	range 2 64 if 64BIT
@@ -1153,7 +1216,8 @@
 
 config UID16
 	bool "Enable 16-bit UID system calls" if EXPERT
-	depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION)
+	depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) \
+		|| AARCH32_EMULATION
 	default y
 	help
 	  This enables the legacy 16-bit UID syscall wrappers.
@@ -1201,13 +1265,7 @@
 	   Say N unless you really need all symbols.
 
 config HOTPLUG
-	bool "Support for hot-pluggable devices" if EXPERT
-	default y
-	help
-	  This option is provided for the case where no hotplug or uevent
-	  capabilities is wanted by the kernel.  You should only consider
-	  disabling this option for embedded systems that do not use modules, a
-	  dynamic /dev tree, or dynamic device discovery.  Just say Y.
+	def_bool y
 
 config PRINTK
 	default y
diff --git a/init/main.c b/init/main.c
index b286730..db34c0e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -631,6 +631,11 @@
 	acpi_early_init(); /* before LAPIC and SMP init */
 	sfi_init_late();
 
+	if (efi_enabled) {
+		efi_late_init();
+		efi_free_boot_services();
+	}
+
 	ftrace_init();
 
 	/* Do the rest non-__init'ed, we're now alive */
diff --git a/kernel/Kconfig.locks b/kernel/Kconfig.locks
index 2251882..44511d1 100644
--- a/kernel/Kconfig.locks
+++ b/kernel/Kconfig.locks
@@ -87,6 +87,9 @@
 config ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
 	bool
 
+config UNINLINE_SPIN_UNLOCK
+	bool
+
 #
 # lock_* functions are inlined when:
 #   - DEBUG_SPINLOCK=n and GENERIC_LOCKBREAK=n and ARCH_INLINE_*LOCK=y
@@ -103,100 +106,120 @@
 #   - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y
 #
 
+if !DEBUG_SPINLOCK
+
 config INLINE_SPIN_TRYLOCK
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_TRYLOCK
+	def_bool y
+	depends on ARCH_INLINE_SPIN_TRYLOCK
 
 config INLINE_SPIN_TRYLOCK_BH
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_TRYLOCK_BH
+	def_bool y
+	depends on ARCH_INLINE_SPIN_TRYLOCK_BH
 
 config INLINE_SPIN_LOCK
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK
 
 config INLINE_SPIN_LOCK_BH
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_SPIN_LOCK_BH
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_BH
 
 config INLINE_SPIN_LOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_SPIN_LOCK_IRQ
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_IRQ
 
 config INLINE_SPIN_LOCK_IRQSAVE
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_SPIN_LOCK_IRQSAVE
-
-config UNINLINE_SPIN_UNLOCK
-	bool
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_IRQSAVE
 
 config INLINE_SPIN_UNLOCK_BH
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_UNLOCK_BH
+	def_bool y
+	depends on ARCH_INLINE_SPIN_UNLOCK_BH
 
 config INLINE_SPIN_UNLOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_SPIN_UNLOCK_BH)
+	def_bool y
+	depends on !PREEMPT || ARCH_INLINE_SPIN_UNLOCK_BH
 
 config INLINE_SPIN_UNLOCK_IRQRESTORE
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
+	def_bool y
+	depends on ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
 
 
 config INLINE_READ_TRYLOCK
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_TRYLOCK
+	def_bool y
+	depends on ARCH_INLINE_READ_TRYLOCK
 
 config INLINE_READ_LOCK
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK
 
 config INLINE_READ_LOCK_BH
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_READ_LOCK_BH
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_BH
 
 config INLINE_READ_LOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_READ_LOCK_IRQ
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_IRQ
 
 config INLINE_READ_LOCK_IRQSAVE
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_READ_LOCK_IRQSAVE
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_IRQSAVE
 
 config INLINE_READ_UNLOCK
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_READ_UNLOCK)
+	def_bool y
+	depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK
 
 config INLINE_READ_UNLOCK_BH
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_UNLOCK_BH
+	def_bool y
+	depends on ARCH_INLINE_READ_UNLOCK_BH
 
 config INLINE_READ_UNLOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_READ_UNLOCK_BH)
+	def_bool y
+	depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK_BH
 
 config INLINE_READ_UNLOCK_IRQRESTORE
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_UNLOCK_IRQRESTORE
+	def_bool y
+	depends on ARCH_INLINE_READ_UNLOCK_IRQRESTORE
 
 
 config INLINE_WRITE_TRYLOCK
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_TRYLOCK
+	def_bool y
+	depends on ARCH_INLINE_WRITE_TRYLOCK
 
 config INLINE_WRITE_LOCK
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK
 
 config INLINE_WRITE_LOCK_BH
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_WRITE_LOCK_BH
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_BH
 
 config INLINE_WRITE_LOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_WRITE_LOCK_IRQ
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_IRQ
 
 config INLINE_WRITE_LOCK_IRQSAVE
-	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
-		 ARCH_INLINE_WRITE_LOCK_IRQSAVE
+	def_bool y
+	depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_IRQSAVE
 
 config INLINE_WRITE_UNLOCK
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_WRITE_UNLOCK)
+	def_bool y
+	depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK
 
 config INLINE_WRITE_UNLOCK_BH
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_UNLOCK_BH
+	def_bool y
+	depends on ARCH_INLINE_WRITE_UNLOCK_BH
 
 config INLINE_WRITE_UNLOCK_IRQ
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_WRITE_UNLOCK_BH)
+	def_bool y
+	depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK_BH
 
 config INLINE_WRITE_UNLOCK_IRQRESTORE
-	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+	def_bool y
+	depends on ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+
+endif
 
 config MUTEX_SPIN_ON_OWNER
-	def_bool SMP && !DEBUG_MUTEXES
+	def_bool y
+	depends on SMP && !DEBUG_MUTEXES
diff --git a/kernel/Makefile b/kernel/Makefile
index c0cc67a..5404911 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -10,7 +10,7 @@
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
 	    notifier.o ksysfs.o cred.o \
-	    async.o range.o groups.o lglock.o
+	    async.o range.o groups.o lglock.o smpboot.o
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
@@ -46,7 +46,6 @@
 obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_SMP) += smpboot.o
 ifneq ($(CONFIG_SMP),y)
 obj-y += up.o
 endif
@@ -98,7 +97,7 @@
 obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
-obj-$(CONFIG_X86_DS) += trace/
+obj-$(CONFIG_TRACE_CLOCK) += trace/
 obj-$(CONFIG_RING_BUFFER) += trace/
 obj-$(CONFIG_TRACEPOINTS) += trace/
 obj-$(CONFIG_IRQ_WORK) += irq_work.o
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 14d3258..f560598 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -280,12 +280,13 @@
 				__func__, cpu);
 		goto out_release;
 	}
+	smpboot_park_threads(cpu);
 
 	err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
 	if (err) {
 		/* CPU didn't die: tell everyone.  Can't complain. */
+		smpboot_unpark_threads(cpu);
 		cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
-
 		goto out_release;
 	}
 	BUG_ON(cpu_online(cpu));
@@ -354,6 +355,10 @@
 		goto out;
 	}
 
+	ret = smpboot_create_threads(cpu);
+	if (ret)
+		goto out;
+
 	ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
 	if (ret) {
 		nr_calls--;
@@ -368,6 +373,9 @@
 		goto out_notify;
 	BUG_ON(!cpu_online(cpu));
 
+	/* Wake the per cpu threads */
+	smpboot_unpark_threads(cpu);
+
 	/* Now call notifier in preparation. */
 	cpu_notify(CPU_ONLINE | mod, hcpu);
 
@@ -439,14 +447,6 @@
 #ifdef CONFIG_PM_SLEEP_SMP
 static cpumask_var_t frozen_cpus;
 
-void __weak arch_disable_nonboot_cpus_begin(void)
-{
-}
-
-void __weak arch_disable_nonboot_cpus_end(void)
-{
-}
-
 int disable_nonboot_cpus(void)
 {
 	int cpu, first_cpu, error = 0;
@@ -458,7 +458,6 @@
 	 * with the userspace trying to use the CPU hotplug at the same time
 	 */
 	cpumask_clear(frozen_cpus);
-	arch_disable_nonboot_cpus_begin();
 
 	printk("Disabling non-boot CPUs ...\n");
 	for_each_online_cpu(cpu) {
@@ -474,8 +473,6 @@
 		}
 	}
 
-	arch_disable_nonboot_cpus_end();
-
 	if (!error) {
 		BUG_ON(num_online_cpus() > 1);
 		/* Make sure the CPUs won't be enabled by someone else */
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 0557f24..17e073c 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -672,6 +672,10 @@
 {
 	struct kgdb_state kgdb_var;
 	struct kgdb_state *ks = &kgdb_var;
+	int ret = 0;
+
+	if (arch_kgdb_ops.enable_nmi)
+		arch_kgdb_ops.enable_nmi(0);
 
 	ks->cpu			= raw_smp_processor_id();
 	ks->ex_vector		= evector;
@@ -681,11 +685,15 @@
 	ks->linux_regs		= regs;
 
 	if (kgdb_reenter_check(ks))
-		return 0; /* Ouch, double exception ! */
+		goto out; /* Ouch, double exception ! */
 	if (kgdb_info[ks->cpu].enter_kgdb != 0)
-		return 0;
+		goto out;
 
-	return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
+	ret = kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
+out:
+	if (arch_kgdb_ops.enable_nmi)
+		arch_kgdb_ops.enable_nmi(1);
+	return ret;
 }
 
 int kgdb_nmicallback(int cpu, void *regs)
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 31df170..1261dc7e 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -21,6 +21,7 @@
 #include <linux/smp.h>
 #include <linux/utsname.h>
 #include <linux/vmalloc.h>
+#include <linux/atomic.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -2107,6 +2108,32 @@
 	return 0;
 }
 #endif /* CONFIG_PRINTK */
+
+/* Make sure we balance enable/disable calls, must disable first. */
+static atomic_t kdb_nmi_disabled;
+
+static int kdb_disable_nmi(int argc, const char *argv[])
+{
+	if (atomic_read(&kdb_nmi_disabled))
+		return 0;
+	atomic_set(&kdb_nmi_disabled, 1);
+	arch_kgdb_ops.enable_nmi(0);
+	return 0;
+}
+
+static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
+{
+	if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
+		return -EINVAL;
+	arch_kgdb_ops.enable_nmi(1);
+	return 0;
+}
+
+static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
+	.set = kdb_param_enable_nmi,
+};
+module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
+
 /*
  * kdb_cpu - This function implements the 'cpu' command.
  *	cpu	[<cpunum>]
@@ -2851,6 +2878,10 @@
 	kdb_register_repeat("dmesg", kdb_dmesg, "[lines]",
 	  "Display syslog buffer", 0, KDB_REPEAT_NONE);
 #endif
+	if (arch_kgdb_ops.enable_nmi) {
+		kdb_register_repeat("disable_nmi", kdb_disable_nmi, "",
+		  "Disable NMI entry to KDB", 0, KDB_REPEAT_NONE);
+	}
 	kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
 	  "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
 	kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>",
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 98d4597..c772061 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -159,6 +159,11 @@
 	int rctx;
 	struct perf_callchain_entry *entry;
 
+	int kernel = !event->attr.exclude_callchain_kernel;
+	int user   = !event->attr.exclude_callchain_user;
+
+	if (!kernel && !user)
+		return NULL;
 
 	entry = get_callchain_entry(&rctx);
 	if (rctx == -1)
@@ -169,24 +174,29 @@
 
 	entry->nr = 0;
 
-	if (!user_mode(regs)) {
+	if (kernel && !user_mode(regs)) {
 		perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
 		perf_callchain_kernel(entry, regs);
-		if (current->mm)
-			regs = task_pt_regs(current);
-		else
-			regs = NULL;
 	}
 
-	if (regs) {
-		/*
-		 * Disallow cross-task user callchains.
-		 */
-		if (event->ctx->task && event->ctx->task != current)
-			goto exit_put;
+	if (user) {
+		if (!user_mode(regs)) {
+			if  (current->mm)
+				regs = task_pt_regs(current);
+			else
+				regs = NULL;
+		}
 
-		perf_callchain_store(entry, PERF_CONTEXT_USER);
-		perf_callchain_user(entry, regs);
+		if (regs) {
+			/*
+			 * Disallow cross-task user callchains.
+			 */
+			if (event->ctx->task && event->ctx->task != current)
+				goto exit_put;
+
+			perf_callchain_store(entry, PERF_CONTEXT_USER);
+			perf_callchain_user(entry, regs);
+		}
 	}
 
 exit_put:
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 7fee567..7b9df35 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -36,6 +36,7 @@
 #include <linux/perf_event.h>
 #include <linux/ftrace_event.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/mm_types.h>
 
 #include "internal.h"
 
@@ -3764,6 +3765,132 @@
 }
 EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
 
+static void
+perf_output_sample_regs(struct perf_output_handle *handle,
+			struct pt_regs *regs, u64 mask)
+{
+	int bit;
+
+	for_each_set_bit(bit, (const unsigned long *) &mask,
+			 sizeof(mask) * BITS_PER_BYTE) {
+		u64 val;
+
+		val = perf_reg_value(regs, bit);
+		perf_output_put(handle, val);
+	}
+}
+
+static void perf_sample_regs_user(struct perf_regs_user *regs_user,
+				  struct pt_regs *regs)
+{
+	if (!user_mode(regs)) {
+		if (current->mm)
+			regs = task_pt_regs(current);
+		else
+			regs = NULL;
+	}
+
+	if (regs) {
+		regs_user->regs = regs;
+		regs_user->abi  = perf_reg_abi(current);
+	}
+}
+
+/*
+ * Get remaining task size from user stack pointer.
+ *
+ * It'd be better to take stack vma map and limit this more
+ * precisly, but there's no way to get it safely under interrupt,
+ * so using TASK_SIZE as limit.
+ */
+static u64 perf_ustack_task_size(struct pt_regs *regs)
+{
+	unsigned long addr = perf_user_stack_pointer(regs);
+
+	if (!addr || addr >= TASK_SIZE)
+		return 0;
+
+	return TASK_SIZE - addr;
+}
+
+static u16
+perf_sample_ustack_size(u16 stack_size, u16 header_size,
+			struct pt_regs *regs)
+{
+	u64 task_size;
+
+	/* No regs, no stack pointer, no dump. */
+	if (!regs)
+		return 0;
+
+	/*
+	 * Check if we fit in with the requested stack size into the:
+	 * - TASK_SIZE
+	 *   If we don't, we limit the size to the TASK_SIZE.
+	 *
+	 * - remaining sample size
+	 *   If we don't, we customize the stack size to
+	 *   fit in to the remaining sample size.
+	 */
+
+	task_size  = min((u64) USHRT_MAX, perf_ustack_task_size(regs));
+	stack_size = min(stack_size, (u16) task_size);
+
+	/* Current header size plus static size and dynamic size. */
+	header_size += 2 * sizeof(u64);
+
+	/* Do we fit in with the current stack dump size? */
+	if ((u16) (header_size + stack_size) < header_size) {
+		/*
+		 * If we overflow the maximum size for the sample,
+		 * we customize the stack dump size to fit in.
+		 */
+		stack_size = USHRT_MAX - header_size - sizeof(u64);
+		stack_size = round_up(stack_size, sizeof(u64));
+	}
+
+	return stack_size;
+}
+
+static void
+perf_output_sample_ustack(struct perf_output_handle *handle, u64 dump_size,
+			  struct pt_regs *regs)
+{
+	/* Case of a kernel thread, nothing to dump */
+	if (!regs) {
+		u64 size = 0;
+		perf_output_put(handle, size);
+	} else {
+		unsigned long sp;
+		unsigned int rem;
+		u64 dyn_size;
+
+		/*
+		 * We dump:
+		 * static size
+		 *   - the size requested by user or the best one we can fit
+		 *     in to the sample max size
+		 * data
+		 *   - user stack dump data
+		 * dynamic size
+		 *   - the actual dumped size
+		 */
+
+		/* Static size. */
+		perf_output_put(handle, dump_size);
+
+		/* Data. */
+		sp = perf_user_stack_pointer(regs);
+		rem = __output_copy_user(handle, (void *) sp, dump_size);
+		dyn_size = dump_size - rem;
+
+		perf_output_skip(handle, rem);
+
+		/* Dynamic size. */
+		perf_output_put(handle, dyn_size);
+	}
+}
+
 static void __perf_event_header__init_id(struct perf_event_header *header,
 					 struct perf_sample_data *data,
 					 struct perf_event *event)
@@ -4024,6 +4151,28 @@
 			perf_output_put(handle, nr);
 		}
 	}
+
+	if (sample_type & PERF_SAMPLE_REGS_USER) {
+		u64 abi = data->regs_user.abi;
+
+		/*
+		 * If there are no regs to dump, notice it through
+		 * first u64 being zero (PERF_SAMPLE_REGS_ABI_NONE).
+		 */
+		perf_output_put(handle, abi);
+
+		if (abi) {
+			u64 mask = event->attr.sample_regs_user;
+			perf_output_sample_regs(handle,
+						data->regs_user.regs,
+						mask);
+		}
+	}
+
+	if (sample_type & PERF_SAMPLE_STACK_USER)
+		perf_output_sample_ustack(handle,
+					  data->stack_user_size,
+					  data->regs_user.regs);
 }
 
 void perf_prepare_sample(struct perf_event_header *header,
@@ -4075,6 +4224,49 @@
 		}
 		header->size += size;
 	}
+
+	if (sample_type & PERF_SAMPLE_REGS_USER) {
+		/* regs dump ABI info */
+		int size = sizeof(u64);
+
+		perf_sample_regs_user(&data->regs_user, regs);
+
+		if (data->regs_user.regs) {
+			u64 mask = event->attr.sample_regs_user;
+			size += hweight64(mask) * sizeof(u64);
+		}
+
+		header->size += size;
+	}
+
+	if (sample_type & PERF_SAMPLE_STACK_USER) {
+		/*
+		 * Either we need PERF_SAMPLE_STACK_USER bit to be allways
+		 * processed as the last one or have additional check added
+		 * in case new sample type is added, because we could eat
+		 * up the rest of the sample size.
+		 */
+		struct perf_regs_user *uregs = &data->regs_user;
+		u16 stack_size = event->attr.sample_stack_user;
+		u16 size = sizeof(u64);
+
+		if (!uregs->abi)
+			perf_sample_regs_user(uregs, regs);
+
+		stack_size = perf_sample_ustack_size(stack_size, header->size,
+						     uregs->regs);
+
+		/*
+		 * If there is something to dump, add space for the dump
+		 * itself and for the field that tells the dynamic size,
+		 * which is how many have been actually dumped.
+		 */
+		if (stack_size)
+			size += sizeof(u64) + stack_size;
+
+		data->stack_user_size = stack_size;
+		header->size += size;
+	}
 }
 
 static void perf_event_output(struct perf_event *event,
@@ -6151,6 +6343,28 @@
 			attr->branch_sample_type = mask;
 		}
 	}
+
+	if (attr->sample_type & PERF_SAMPLE_REGS_USER) {
+		ret = perf_reg_validate(attr->sample_regs_user);
+		if (ret)
+			return ret;
+	}
+
+	if (attr->sample_type & PERF_SAMPLE_STACK_USER) {
+		if (!arch_perf_have_user_stack_dump())
+			return -ENOSYS;
+
+		/*
+		 * We have __u32 type for the size, but so far
+		 * we can only use __u16 as maximum due to the
+		 * __u16 sample size limit.
+		 */
+		if (attr->sample_stack_user >= USHRT_MAX)
+			ret = -EINVAL;
+		else if (!IS_ALIGNED(attr->sample_stack_user, sizeof(u64)))
+			ret = -EINVAL;
+	}
+
 out:
 	return ret;
 
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index a096c19..d56a64c 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -2,6 +2,7 @@
 #define _KERNEL_EVENTS_INTERNAL_H
 
 #include <linux/hardirq.h>
+#include <linux/uaccess.h>
 
 /* Buffer handling */
 
@@ -76,30 +77,53 @@
 	return rb->nr_pages << (PAGE_SHIFT + page_order(rb));
 }
 
-static inline void
-__output_copy(struct perf_output_handle *handle,
-		   const void *buf, unsigned int len)
-{
-	do {
-		unsigned long size = min_t(unsigned long, handle->size, len);
-
-		memcpy(handle->addr, buf, size);
-
-		len -= size;
-		handle->addr += size;
-		buf += size;
-		handle->size -= size;
-		if (!handle->size) {
-			struct ring_buffer *rb = handle->rb;
-
-			handle->page++;
-			handle->page &= rb->nr_pages - 1;
-			handle->addr = rb->data_pages[handle->page];
-			handle->size = PAGE_SIZE << page_order(rb);
-		}
-	} while (len);
+#define DEFINE_OUTPUT_COPY(func_name, memcpy_func)			\
+static inline unsigned int						\
+func_name(struct perf_output_handle *handle,				\
+	  const void *buf, unsigned int len)				\
+{									\
+	unsigned long size, written;					\
+									\
+	do {								\
+		size = min_t(unsigned long, handle->size, len);		\
+									\
+		written = memcpy_func(handle->addr, buf, size);		\
+									\
+		len -= written;						\
+		handle->addr += written;				\
+		buf += written;						\
+		handle->size -= written;				\
+		if (!handle->size) {					\
+			struct ring_buffer *rb = handle->rb;		\
+									\
+			handle->page++;					\
+			handle->page &= rb->nr_pages - 1;		\
+			handle->addr = rb->data_pages[handle->page];	\
+			handle->size = PAGE_SIZE << page_order(rb);	\
+		}							\
+	} while (len && written == size);				\
+									\
+	return len;							\
 }
 
+static inline int memcpy_common(void *dst, const void *src, size_t n)
+{
+	memcpy(dst, src, n);
+	return n;
+}
+
+DEFINE_OUTPUT_COPY(__output_copy, memcpy_common)
+
+#define MEMCPY_SKIP(dst, src, n) (n)
+
+DEFINE_OUTPUT_COPY(__output_skip, MEMCPY_SKIP)
+
+#ifndef arch_perf_out_copy_user
+#define arch_perf_out_copy_user __copy_from_user_inatomic
+#endif
+
+DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user)
+
 /* Callchain handling */
 extern struct perf_callchain_entry *
 perf_callchain(struct perf_event *event, struct pt_regs *regs);
@@ -134,4 +158,20 @@
 	recursion[rctx]--;
 }
 
+#ifdef CONFIG_HAVE_PERF_USER_STACK_DUMP
+static inline bool arch_perf_have_user_stack_dump(void)
+{
+	return true;
+}
+
+#define perf_user_stack_pointer(regs) user_stack_pointer(regs)
+#else
+static inline bool arch_perf_have_user_stack_dump(void)
+{
+	return false;
+}
+
+#define perf_user_stack_pointer(regs) 0
+#endif /* CONFIG_HAVE_PERF_USER_STACK_DUMP */
+
 #endif /* _KERNEL_EVENTS_INTERNAL_H */
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 6ddaba4..23cb34f 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -182,10 +182,16 @@
 	return -ENOSPC;
 }
 
-void perf_output_copy(struct perf_output_handle *handle,
+unsigned int perf_output_copy(struct perf_output_handle *handle,
 		      const void *buf, unsigned int len)
 {
-	__output_copy(handle, buf, len);
+	return __output_copy(handle, buf, len);
+}
+
+unsigned int perf_output_skip(struct perf_output_handle *handle,
+			      unsigned int len)
+{
+	return __output_skip(handle, NULL, len);
 }
 
 void perf_output_end(struct perf_output_handle *handle)
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index c08a22d..912ef48 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -280,12 +280,10 @@
 	if (ret <= 0)
 		return ret;
 
-	lock_page(page);
 	vaddr_new = kmap_atomic(page);
 	vaddr &= ~PAGE_MASK;
 	memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE);
 	kunmap_atomic(vaddr_new);
-	unlock_page(page);
 
 	put_page(page);
 
@@ -334,7 +332,7 @@
 	 */
 	result = is_swbp_at_addr(mm, vaddr);
 	if (result == 1)
-		return -EEXIST;
+		return 0;
 
 	if (result)
 		return result;
@@ -347,24 +345,22 @@
  * @mm: the probed process address space.
  * @auprobe: arch specific probepoint information.
  * @vaddr: the virtual address to insert the opcode.
- * @verify: if true, verify existance of breakpoint instruction.
  *
  * For mm @mm, restore the original opcode (opcode) at @vaddr.
  * Return 0 (success) or a negative errno.
  */
 int __weak
-set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, bool verify)
+set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
 {
-	if (verify) {
-		int result;
+	int result;
 
-		result = is_swbp_at_addr(mm, vaddr);
-		if (!result)
-			return -EINVAL;
+	result = is_swbp_at_addr(mm, vaddr);
+	if (!result)
+		return -EINVAL;
 
-		if (result != 1)
-			return result;
-	}
+	if (result != 1)
+		return result;
+
 	return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
 }
 
@@ -415,11 +411,10 @@
 static struct uprobe *find_uprobe(struct inode *inode, loff_t offset)
 {
 	struct uprobe *uprobe;
-	unsigned long flags;
 
-	spin_lock_irqsave(&uprobes_treelock, flags);
+	spin_lock(&uprobes_treelock);
 	uprobe = __find_uprobe(inode, offset);
-	spin_unlock_irqrestore(&uprobes_treelock, flags);
+	spin_unlock(&uprobes_treelock);
 
 	return uprobe;
 }
@@ -466,12 +461,11 @@
  */
 static struct uprobe *insert_uprobe(struct uprobe *uprobe)
 {
-	unsigned long flags;
 	struct uprobe *u;
 
-	spin_lock_irqsave(&uprobes_treelock, flags);
+	spin_lock(&uprobes_treelock);
 	u = __insert_uprobe(uprobe);
-	spin_unlock_irqrestore(&uprobes_treelock, flags);
+	spin_unlock(&uprobes_treelock);
 
 	/* For now assume that the instruction need not be single-stepped */
 	uprobe->flags |= UPROBE_SKIP_SSTEP;
@@ -649,6 +643,7 @@
 install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 			struct vm_area_struct *vma, unsigned long vaddr)
 {
+	bool first_uprobe;
 	int ret;
 
 	/*
@@ -659,7 +654,7 @@
 	 * Hence behave as if probe already existed.
 	 */
 	if (!uprobe->consumers)
-		return -EEXIST;
+		return 0;
 
 	if (!(uprobe->flags & UPROBE_COPY_INSN)) {
 		ret = copy_insn(uprobe, vma->vm_file);
@@ -681,17 +676,18 @@
 	}
 
 	/*
-	 * Ideally, should be updating the probe count after the breakpoint
-	 * has been successfully inserted. However a thread could hit the
-	 * breakpoint we just inserted even before the probe count is
-	 * incremented. If this is the first breakpoint placed, breakpoint
-	 * notifier might ignore uprobes and pass the trap to the thread.
-	 * Hence increment before and decrement on failure.
+	 * set MMF_HAS_UPROBES in advance for uprobe_pre_sstep_notifier(),
+	 * the task can hit this breakpoint right after __replace_page().
 	 */
-	atomic_inc(&mm->uprobes_state.count);
+	first_uprobe = !test_bit(MMF_HAS_UPROBES, &mm->flags);
+	if (first_uprobe)
+		set_bit(MMF_HAS_UPROBES, &mm->flags);
+
 	ret = set_swbp(&uprobe->arch, mm, vaddr);
-	if (ret)
-		atomic_dec(&mm->uprobes_state.count);
+	if (!ret)
+		clear_bit(MMF_RECALC_UPROBES, &mm->flags);
+	else if (first_uprobe)
+		clear_bit(MMF_HAS_UPROBES, &mm->flags);
 
 	return ret;
 }
@@ -699,8 +695,12 @@
 static void
 remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
 {
-	if (!set_orig_insn(&uprobe->arch, mm, vaddr, true))
-		atomic_dec(&mm->uprobes_state.count);
+	/* can happen if uprobe_register() fails */
+	if (!test_bit(MMF_HAS_UPROBES, &mm->flags))
+		return;
+
+	set_bit(MMF_RECALC_UPROBES, &mm->flags);
+	set_orig_insn(&uprobe->arch, mm, vaddr);
 }
 
 /*
@@ -710,11 +710,9 @@
  */
 static void delete_uprobe(struct uprobe *uprobe)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&uprobes_treelock, flags);
+	spin_lock(&uprobes_treelock);
 	rb_erase(&uprobe->rb_node, &uprobes_tree);
-	spin_unlock_irqrestore(&uprobes_treelock, flags);
+	spin_unlock(&uprobes_treelock);
 	iput(uprobe->inode);
 	put_uprobe(uprobe);
 	atomic_dec(&uprobe_events);
@@ -831,17 +829,11 @@
 		    vaddr_to_offset(vma, info->vaddr) != uprobe->offset)
 			goto unlock;
 
-		if (is_register) {
+		if (is_register)
 			err = install_breakpoint(uprobe, mm, vma, info->vaddr);
-			/*
-			 * We can race against uprobe_mmap(), see the
-			 * comment near uprobe_hash().
-			 */
-			if (err == -EEXIST)
-				err = 0;
-		} else {
+		else
 			remove_breakpoint(uprobe, mm, info->vaddr);
-		}
+
  unlock:
 		up_write(&mm->mmap_sem);
  free:
@@ -908,7 +900,8 @@
 	}
 
 	mutex_unlock(uprobes_hash(inode));
-	put_uprobe(uprobe);
+	if (uprobe)
+		put_uprobe(uprobe);
 
 	return ret;
 }
@@ -978,7 +971,6 @@
 				struct list_head *head)
 {
 	loff_t min, max;
-	unsigned long flags;
 	struct rb_node *n, *t;
 	struct uprobe *u;
 
@@ -986,7 +978,7 @@
 	min = vaddr_to_offset(vma, start);
 	max = min + (end - start) - 1;
 
-	spin_lock_irqsave(&uprobes_treelock, flags);
+	spin_lock(&uprobes_treelock);
 	n = find_node_in_range(inode, min, max);
 	if (n) {
 		for (t = n; t; t = rb_prev(t)) {
@@ -1004,27 +996,20 @@
 			atomic_inc(&u->ref);
 		}
 	}
-	spin_unlock_irqrestore(&uprobes_treelock, flags);
+	spin_unlock(&uprobes_treelock);
 }
 
 /*
- * Called from mmap_region.
- * called with mm->mmap_sem acquired.
+ * Called from mmap_region/vma_adjust with mm->mmap_sem acquired.
  *
- * Return -ve no if we fail to insert probes and we cannot
- * bail-out.
- * Return 0 otherwise. i.e:
- *
- *	- successful insertion of probes
- *	- (or) no possible probes to be inserted.
- *	- (or) insertion of probes failed but we can bail-out.
+ * Currently we ignore all errors and always return 0, the callers
+ * can't handle the failure anyway.
  */
 int uprobe_mmap(struct vm_area_struct *vma)
 {
 	struct list_head tmp_list;
 	struct uprobe *uprobe, *u;
 	struct inode *inode;
-	int ret, count;
 
 	if (!atomic_read(&uprobe_events) || !valid_vma(vma, true))
 		return 0;
@@ -1036,44 +1021,35 @@
 	mutex_lock(uprobes_mmap_hash(inode));
 	build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list);
 
-	ret = 0;
-	count = 0;
-
 	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-		if (!ret) {
+		if (!fatal_signal_pending(current)) {
 			unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
-
-			ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
-			/*
-			 * We can race against uprobe_register(), see the
-			 * comment near uprobe_hash().
-			 */
-			if (ret == -EEXIST) {
-				ret = 0;
-
-				if (!is_swbp_at_addr(vma->vm_mm, vaddr))
-					continue;
-
-				/*
-				 * Unable to insert a breakpoint, but
-				 * breakpoint lies underneath. Increment the
-				 * probe count.
-				 */
-				atomic_inc(&vma->vm_mm->uprobes_state.count);
-			}
-
-			if (!ret)
-				count++;
+			install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
 		}
 		put_uprobe(uprobe);
 	}
-
 	mutex_unlock(uprobes_mmap_hash(inode));
 
-	if (ret)
-		atomic_sub(count, &vma->vm_mm->uprobes_state.count);
+	return 0;
+}
 
-	return ret;
+static bool
+vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	loff_t min, max;
+	struct inode *inode;
+	struct rb_node *n;
+
+	inode = vma->vm_file->f_mapping->host;
+
+	min = vaddr_to_offset(vma, start);
+	max = min + (end - start) - 1;
+
+	spin_lock(&uprobes_treelock);
+	n = find_node_in_range(inode, min, max);
+	spin_unlock(&uprobes_treelock);
+
+	return !!n;
 }
 
 /*
@@ -1081,37 +1057,18 @@
  */
 void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
-	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
-	struct inode *inode;
-
 	if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
 		return;
 
 	if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */
 		return;
 
-	if (!atomic_read(&vma->vm_mm->uprobes_state.count))
+	if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags) ||
+	     test_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags))
 		return;
 
-	inode = vma->vm_file->f_mapping->host;
-	if (!inode)
-		return;
-
-	mutex_lock(uprobes_mmap_hash(inode));
-	build_probe_list(inode, vma, start, end, &tmp_list);
-
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-		unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
-		/*
-		 * An unregister could have removed the probe before
-		 * unmap. So check before we decrement the count.
-		 */
-		if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
-			atomic_dec(&vma->vm_mm->uprobes_state.count);
-		put_uprobe(uprobe);
-	}
-	mutex_unlock(uprobes_mmap_hash(inode));
+	if (vma_has_uprobes(vma, start, end))
+		set_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags);
 }
 
 /* Slot allocation for XOL */
@@ -1213,13 +1170,15 @@
 	kfree(area);
 }
 
-/*
- * uprobe_reset_state - Free the area allocated for slots.
- */
-void uprobe_reset_state(struct mm_struct *mm)
+void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
 {
-	mm->uprobes_state.xol_area = NULL;
-	atomic_set(&mm->uprobes_state.count, 0);
+	newmm->uprobes_state.xol_area = NULL;
+
+	if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) {
+		set_bit(MMF_HAS_UPROBES, &newmm->flags);
+		/* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */
+		set_bit(MMF_RECALC_UPROBES, &newmm->flags);
+	}
 }
 
 /*
@@ -1437,6 +1396,25 @@
 	return false;
 }
 
+static void mmf_recalc_uprobes(struct mm_struct *mm)
+{
+	struct vm_area_struct *vma;
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!valid_vma(vma, false))
+			continue;
+		/*
+		 * This is not strictly accurate, we can race with
+		 * uprobe_unregister() and see the already removed
+		 * uprobe if delete_uprobe() was not yet called.
+		 */
+		if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end))
+			return;
+	}
+
+	clear_bit(MMF_HAS_UPROBES, &mm->flags);
+}
+
 static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
 {
 	struct mm_struct *mm = current->mm;
@@ -1458,11 +1436,24 @@
 	} else {
 		*is_swbp = -EFAULT;
 	}
+
+	if (!uprobe && test_and_clear_bit(MMF_RECALC_UPROBES, &mm->flags))
+		mmf_recalc_uprobes(mm);
 	up_read(&mm->mmap_sem);
 
 	return uprobe;
 }
 
+void __weak arch_uprobe_enable_step(struct arch_uprobe *arch)
+{
+	user_enable_single_step(current);
+}
+
+void __weak arch_uprobe_disable_step(struct arch_uprobe *arch)
+{
+	user_disable_single_step(current);
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1509,7 +1500,7 @@
 
 	utask->state = UTASK_SSTEP;
 	if (!pre_ssout(uprobe, regs, bp_vaddr)) {
-		user_enable_single_step(current);
+		arch_uprobe_enable_step(&uprobe->arch);
 		return;
 	}
 
@@ -1518,17 +1509,15 @@
 		utask->active_uprobe = NULL;
 		utask->state = UTASK_RUNNING;
 	}
-	if (uprobe) {
-		if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
+	if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
 
-			/*
-			 * cannot singlestep; cannot skip instruction;
-			 * re-execute the instruction.
-			 */
-			instruction_pointer_set(regs, bp_vaddr);
+		/*
+		 * cannot singlestep; cannot skip instruction;
+		 * re-execute the instruction.
+		 */
+		instruction_pointer_set(regs, bp_vaddr);
 
-		put_uprobe(uprobe);
-	}
+	put_uprobe(uprobe);
 }
 
 /*
@@ -1547,10 +1536,10 @@
 	else
 		WARN_ON_ONCE(1);
 
+	arch_uprobe_disable_step(&uprobe->arch);
 	put_uprobe(uprobe);
 	utask->active_uprobe = NULL;
 	utask->state = UTASK_RUNNING;
-	user_disable_single_step(current);
 	xol_free_insn_slot(current);
 
 	spin_lock_irq(&current->sighand->siglock);
@@ -1589,8 +1578,7 @@
 {
 	struct uprobe_task *utask;
 
-	if (!current->mm || !atomic_read(&current->mm->uprobes_state.count))
-		/* task is currently not uprobed */
+	if (!current->mm || !test_bit(MMF_HAS_UPROBES, &current->mm->flags))
 		return 0;
 
 	utask = current->utask;
diff --git a/kernel/fork.c b/kernel/fork.c
index 2c8857e..5a0e74d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -353,6 +353,7 @@
 
 	down_write(&oldmm->mmap_sem);
 	flush_cache_dup_mm(oldmm);
+	uprobe_dup_mmap(oldmm, mm);
 	/*
 	 * Not linked in yet - no deadlock potential:
 	 */
@@ -454,9 +455,6 @@
 
 		if (retval)
 			goto out;
-
-		if (file)
-			uprobe_mmap(tmp);
 	}
 	/* a new mm has just been created */
 	arch_dup_mmap(oldmm, mm);
@@ -839,8 +837,6 @@
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	mm->pmd_huge_pte = NULL;
 #endif
-	uprobe_reset_state(mm);
-
 	if (!mm_init(mm, tsk))
 		goto fail_nomem;
 
@@ -1280,11 +1276,7 @@
 #endif
 #ifdef CONFIG_TRACE_IRQFLAGS
 	p->irq_events = 0;
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-	p->hardirqs_enabled = 1;
-#else
 	p->hardirqs_enabled = 0;
-#endif
 	p->hardirq_enable_ip = 0;
 	p->hardirq_enable_event = 0;
 	p->hardirq_disable_ip = _THIS_IP_;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index eebd6d5..57d86d07 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -671,6 +671,7 @@
 	irq_set_chip(irq, chip);
 	__irq_set_handler(irq, handle, 0, name);
 }
+EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);
 
 void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
 {
diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c
index b5fcd96..988dc58 100644
--- a/kernel/irq/dummychip.c
+++ b/kernel/irq/dummychip.c
@@ -6,6 +6,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/export.h>
 
 #include "internals.h"
 
@@ -57,3 +58,4 @@
 	.irq_mask	= noop,
 	.irq_unmask	= noop,
 };
+EXPORT_SYMBOL_GPL(dummy_irq_chip);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index c62b854..098f396 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -561,9 +561,9 @@
 {
 	LIST_HEAD(free_list);
 
+	mutex_lock(&kprobe_mutex);
 	/* Lock modules while optimizing kprobes */
 	mutex_lock(&module_mutex);
-	mutex_lock(&kprobe_mutex);
 
 	/*
 	 * Step 1: Unoptimize kprobes and collect cleaned (unused and disarmed)
@@ -586,8 +586,8 @@
 	/* Step 4: Free cleaned kprobes after quiesence period */
 	do_free_cleaned_kprobes(&free_list);
 
-	mutex_unlock(&kprobe_mutex);
 	mutex_unlock(&module_mutex);
+	mutex_unlock(&kprobe_mutex);
 
 	/* Step 5: Kick optimizer again if needed */
 	if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list))
@@ -759,20 +759,32 @@
 	struct kprobe *ap;
 	struct optimized_kprobe *op;
 
+	/* Impossible to optimize ftrace-based kprobe */
+	if (kprobe_ftrace(p))
+		return;
+
+	/* For preparing optimization, jump_label_text_reserved() is called */
+	jump_label_lock();
+	mutex_lock(&text_mutex);
+
 	ap = alloc_aggr_kprobe(p);
 	if (!ap)
-		return;
+		goto out;
 
 	op = container_of(ap, struct optimized_kprobe, kp);
 	if (!arch_prepared_optinsn(&op->optinsn)) {
 		/* If failed to setup optimizing, fallback to kprobe */
 		arch_remove_optimized_kprobe(op);
 		kfree(op);
-		return;
+		goto out;
 	}
 
 	init_aggr_kprobe(ap, p);
-	optimize_kprobe(ap);
+	optimize_kprobe(ap);	/* This just kicks optimizer thread */
+
+out:
+	mutex_unlock(&text_mutex);
+	jump_label_unlock();
 }
 
 #ifdef CONFIG_SYSCTL
@@ -907,9 +919,64 @@
 }
 #endif /* CONFIG_OPTPROBES */
 
+#ifdef KPROBES_CAN_USE_FTRACE
+static struct ftrace_ops kprobe_ftrace_ops __read_mostly = {
+	.func = kprobe_ftrace_handler,
+	.flags = FTRACE_OPS_FL_SAVE_REGS,
+};
+static int kprobe_ftrace_enabled;
+
+/* Must ensure p->addr is really on ftrace */
+static int __kprobes prepare_kprobe(struct kprobe *p)
+{
+	if (!kprobe_ftrace(p))
+		return arch_prepare_kprobe(p);
+
+	return arch_prepare_kprobe_ftrace(p);
+}
+
+/* Caller must lock kprobe_mutex */
+static void __kprobes arm_kprobe_ftrace(struct kprobe *p)
+{
+	int ret;
+
+	ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
+				   (unsigned long)p->addr, 0, 0);
+	WARN(ret < 0, "Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret);
+	kprobe_ftrace_enabled++;
+	if (kprobe_ftrace_enabled == 1) {
+		ret = register_ftrace_function(&kprobe_ftrace_ops);
+		WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
+	}
+}
+
+/* Caller must lock kprobe_mutex */
+static void __kprobes disarm_kprobe_ftrace(struct kprobe *p)
+{
+	int ret;
+
+	kprobe_ftrace_enabled--;
+	if (kprobe_ftrace_enabled == 0) {
+		ret = unregister_ftrace_function(&kprobe_ftrace_ops);
+		WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
+	}
+	ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
+			   (unsigned long)p->addr, 1, 0);
+	WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret);
+}
+#else	/* !KPROBES_CAN_USE_FTRACE */
+#define prepare_kprobe(p)	arch_prepare_kprobe(p)
+#define arm_kprobe_ftrace(p)	do {} while (0)
+#define disarm_kprobe_ftrace(p)	do {} while (0)
+#endif
+
 /* Arm a kprobe with text_mutex */
 static void __kprobes arm_kprobe(struct kprobe *kp)
 {
+	if (unlikely(kprobe_ftrace(kp))) {
+		arm_kprobe_ftrace(kp);
+		return;
+	}
 	/*
 	 * Here, since __arm_kprobe() doesn't use stop_machine(),
 	 * this doesn't cause deadlock on text_mutex. So, we don't
@@ -921,11 +988,15 @@
 }
 
 /* Disarm a kprobe with text_mutex */
-static void __kprobes disarm_kprobe(struct kprobe *kp)
+static void __kprobes disarm_kprobe(struct kprobe *kp, bool reopt)
 {
+	if (unlikely(kprobe_ftrace(kp))) {
+		disarm_kprobe_ftrace(kp);
+		return;
+	}
 	/* Ditto */
 	mutex_lock(&text_mutex);
-	__disarm_kprobe(kp, true);
+	__disarm_kprobe(kp, reopt);
 	mutex_unlock(&text_mutex);
 }
 
@@ -1144,12 +1215,6 @@
 	if (p->post_handler && !ap->post_handler)
 		ap->post_handler = aggr_post_handler;
 
-	if (kprobe_disabled(ap) && !kprobe_disabled(p)) {
-		ap->flags &= ~KPROBE_FLAG_DISABLED;
-		if (!kprobes_all_disarmed)
-			/* Arm the breakpoint again. */
-			__arm_kprobe(ap);
-	}
 	return 0;
 }
 
@@ -1189,11 +1254,22 @@
 	int ret = 0;
 	struct kprobe *ap = orig_p;
 
+	/* For preparing optimization, jump_label_text_reserved() is called */
+	jump_label_lock();
+	/*
+	 * Get online CPUs to avoid text_mutex deadlock.with stop machine,
+	 * which is invoked by unoptimize_kprobe() in add_new_kprobe()
+	 */
+	get_online_cpus();
+	mutex_lock(&text_mutex);
+
 	if (!kprobe_aggrprobe(orig_p)) {
 		/* If orig_p is not an aggr_kprobe, create new aggr_kprobe. */
 		ap = alloc_aggr_kprobe(orig_p);
-		if (!ap)
-			return -ENOMEM;
+		if (!ap) {
+			ret = -ENOMEM;
+			goto out;
+		}
 		init_aggr_kprobe(ap, orig_p);
 	} else if (kprobe_unused(ap))
 		/* This probe is going to die. Rescue it */
@@ -1213,7 +1289,7 @@
 			 * free aggr_probe. It will be used next time, or
 			 * freed by unregister_kprobe.
 			 */
-			return ret;
+			goto out;
 
 		/* Prepare optimized instructions if possible. */
 		prepare_optimized_kprobe(ap);
@@ -1228,7 +1304,20 @@
 
 	/* Copy ap's insn slot to p */
 	copy_kprobe(ap, p);
-	return add_new_kprobe(ap, p);
+	ret = add_new_kprobe(ap, p);
+
+out:
+	mutex_unlock(&text_mutex);
+	put_online_cpus();
+	jump_label_unlock();
+
+	if (ret == 0 && kprobe_disabled(ap) && !kprobe_disabled(p)) {
+		ap->flags &= ~KPROBE_FLAG_DISABLED;
+		if (!kprobes_all_disarmed)
+			/* Arm the breakpoint again. */
+			arm_kprobe(ap);
+	}
+	return ret;
 }
 
 static int __kprobes in_kprobes_functions(unsigned long addr)
@@ -1313,13 +1402,77 @@
 	return ret;
 }
 
-int __kprobes register_kprobe(struct kprobe *p)
+static __kprobes int check_kprobe_address_safe(struct kprobe *p,
+					       struct module **probed_mod)
 {
 	int ret = 0;
+	unsigned long ftrace_addr;
+
+	/*
+	 * If the address is located on a ftrace nop, set the
+	 * breakpoint to the following instruction.
+	 */
+	ftrace_addr = ftrace_location((unsigned long)p->addr);
+	if (ftrace_addr) {
+#ifdef KPROBES_CAN_USE_FTRACE
+		/* Given address is not on the instruction boundary */
+		if ((unsigned long)p->addr != ftrace_addr)
+			return -EILSEQ;
+		p->flags |= KPROBE_FLAG_FTRACE;
+#else	/* !KPROBES_CAN_USE_FTRACE */
+		return -EINVAL;
+#endif
+	}
+
+	jump_label_lock();
+	preempt_disable();
+
+	/* Ensure it is not in reserved area nor out of text */
+	if (!kernel_text_address((unsigned long) p->addr) ||
+	    in_kprobes_functions((unsigned long) p->addr) ||
+	    jump_label_text_reserved(p->addr, p->addr)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Check if are we probing a module */
+	*probed_mod = __module_text_address((unsigned long) p->addr);
+	if (*probed_mod) {
+		/*
+		 * We must hold a refcount of the probed module while updating
+		 * its code to prohibit unexpected unloading.
+		 */
+		if (unlikely(!try_module_get(*probed_mod))) {
+			ret = -ENOENT;
+			goto out;
+		}
+
+		/*
+		 * If the module freed .init.text, we couldn't insert
+		 * kprobes in there.
+		 */
+		if (within_module_init((unsigned long)p->addr, *probed_mod) &&
+		    (*probed_mod)->state != MODULE_STATE_COMING) {
+			module_put(*probed_mod);
+			*probed_mod = NULL;
+			ret = -ENOENT;
+		}
+	}
+out:
+	preempt_enable();
+	jump_label_unlock();
+
+	return ret;
+}
+
+int __kprobes register_kprobe(struct kprobe *p)
+{
+	int ret;
 	struct kprobe *old_p;
 	struct module *probed_mod;
 	kprobe_opcode_t *addr;
 
+	/* Adjust probe address from symbol */
 	addr = kprobe_addr(p);
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
@@ -1329,56 +1482,17 @@
 	if (ret)
 		return ret;
 
-	jump_label_lock();
-	preempt_disable();
-	if (!kernel_text_address((unsigned long) p->addr) ||
-	    in_kprobes_functions((unsigned long) p->addr) ||
-	    ftrace_text_reserved(p->addr, p->addr) ||
-	    jump_label_text_reserved(p->addr, p->addr)) {
-		ret = -EINVAL;
-		goto cannot_probe;
-	}
-
 	/* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
 	p->flags &= KPROBE_FLAG_DISABLED;
-
-	/*
-	 * Check if are we probing a module.
-	 */
-	probed_mod = __module_text_address((unsigned long) p->addr);
-	if (probed_mod) {
-		/* Return -ENOENT if fail. */
-		ret = -ENOENT;
-		/*
-		 * We must hold a refcount of the probed module while updating
-		 * its code to prohibit unexpected unloading.
-		 */
-		if (unlikely(!try_module_get(probed_mod)))
-			goto cannot_probe;
-
-		/*
-		 * If the module freed .init.text, we couldn't insert
-		 * kprobes in there.
-		 */
-		if (within_module_init((unsigned long)p->addr, probed_mod) &&
-		    probed_mod->state != MODULE_STATE_COMING) {
-			module_put(probed_mod);
-			goto cannot_probe;
-		}
-		/* ret will be updated by following code */
-	}
-	preempt_enable();
-	jump_label_unlock();
-
 	p->nmissed = 0;
 	INIT_LIST_HEAD(&p->list);
+
+	ret = check_kprobe_address_safe(p, &probed_mod);
+	if (ret)
+		return ret;
+
 	mutex_lock(&kprobe_mutex);
 
-	jump_label_lock(); /* needed to call jump_label_text_reserved() */
-
-	get_online_cpus();	/* For avoiding text_mutex deadlock. */
-	mutex_lock(&text_mutex);
-
 	old_p = get_kprobe(p->addr);
 	if (old_p) {
 		/* Since this may unoptimize old_p, locking text_mutex. */
@@ -1386,7 +1500,9 @@
 		goto out;
 	}
 
-	ret = arch_prepare_kprobe(p);
+	mutex_lock(&text_mutex);	/* Avoiding text modification */
+	ret = prepare_kprobe(p);
+	mutex_unlock(&text_mutex);
 	if (ret)
 		goto out;
 
@@ -1395,26 +1511,18 @@
 		       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
 	if (!kprobes_all_disarmed && !kprobe_disabled(p))
-		__arm_kprobe(p);
+		arm_kprobe(p);
 
 	/* Try to optimize kprobe */
 	try_to_optimize_kprobe(p);
 
 out:
-	mutex_unlock(&text_mutex);
-	put_online_cpus();
-	jump_label_unlock();
 	mutex_unlock(&kprobe_mutex);
 
 	if (probed_mod)
 		module_put(probed_mod);
 
 	return ret;
-
-cannot_probe:
-	preempt_enable();
-	jump_label_unlock();
-	return ret;
 }
 EXPORT_SYMBOL_GPL(register_kprobe);
 
@@ -1451,7 +1559,7 @@
 
 		/* Try to disarm and disable this/parent probe */
 		if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
-			disarm_kprobe(orig_p);
+			disarm_kprobe(orig_p, true);
 			orig_p->flags |= KPROBE_FLAG_DISABLED;
 		}
 	}
@@ -2049,10 +2157,11 @@
 
 	if (!pp)
 		pp = p;
-	seq_printf(pi, "%s%s%s\n",
+	seq_printf(pi, "%s%s%s%s\n",
 		(kprobe_gone(p) ? "[GONE]" : ""),
 		((kprobe_disabled(p) && !kprobe_gone(p)) ?  "[DISABLED]" : ""),
-		(kprobe_optimized(pp) ? "[OPTIMIZED]" : ""));
+		(kprobe_optimized(pp) ? "[OPTIMIZED]" : ""),
+		(kprobe_ftrace(pp) ? "[FTRACE]" : ""));
 }
 
 static void __kprobes *kprobe_seq_start(struct seq_file *f, loff_t *pos)
@@ -2131,14 +2240,12 @@
 		goto already_enabled;
 
 	/* Arming kprobes doesn't optimize kprobe itself */
-	mutex_lock(&text_mutex);
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
 		head = &kprobe_table[i];
 		hlist_for_each_entry_rcu(p, node, head, hlist)
 			if (!kprobe_disabled(p))
-				__arm_kprobe(p);
+				arm_kprobe(p);
 	}
-	mutex_unlock(&text_mutex);
 
 	kprobes_all_disarmed = false;
 	printk(KERN_INFO "Kprobes globally enabled\n");
@@ -2166,15 +2273,13 @@
 	kprobes_all_disarmed = true;
 	printk(KERN_INFO "Kprobes globally disabled\n");
 
-	mutex_lock(&text_mutex);
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
 		head = &kprobe_table[i];
 		hlist_for_each_entry_rcu(p, node, head, hlist) {
 			if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p))
-				__disarm_kprobe(p, false);
+				disarm_kprobe(p, false);
 		}
 	}
-	mutex_unlock(&text_mutex);
 	mutex_unlock(&kprobe_mutex);
 
 	/* Wait for disarming all kprobes by optimizer */
diff --git a/kernel/kthread.c b/kernel/kthread.c
index b579af5..146a6fa 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -37,11 +37,20 @@
 };
 
 struct kthread {
-	int should_stop;
+	unsigned long flags;
+	unsigned int cpu;
 	void *data;
+	struct completion parked;
 	struct completion exited;
 };
 
+enum KTHREAD_BITS {
+	KTHREAD_IS_PER_CPU = 0,
+	KTHREAD_SHOULD_STOP,
+	KTHREAD_SHOULD_PARK,
+	KTHREAD_IS_PARKED,
+};
+
 #define to_kthread(tsk)	\
 	container_of((tsk)->vfork_done, struct kthread, exited)
 
@@ -52,13 +61,29 @@
  * and this will return true.  You should then return, and your return
  * value will be passed through to kthread_stop().
  */
-int kthread_should_stop(void)
+bool kthread_should_stop(void)
 {
-	return to_kthread(current)->should_stop;
+	return test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
 }
 EXPORT_SYMBOL(kthread_should_stop);
 
 /**
+ * kthread_should_park - should this kthread park now?
+ *
+ * When someone calls kthread_park() on your kthread, it will be woken
+ * and this will return true.  You should then do the necessary
+ * cleanup and call kthread_parkme()
+ *
+ * Similar to kthread_should_stop(), but this keeps the thread alive
+ * and in a park position. kthread_unpark() "restarts" the thread and
+ * calls the thread function again.
+ */
+bool kthread_should_park(void)
+{
+	return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
+}
+
+/**
  * kthread_freezable_should_stop - should this freezable kthread return now?
  * @was_frozen: optional out parameter, indicates whether %current was frozen
  *
@@ -96,6 +121,24 @@
 	return to_kthread(task)->data;
 }
 
+static void __kthread_parkme(struct kthread *self)
+{
+	__set_current_state(TASK_INTERRUPTIBLE);
+	while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
+		if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
+			complete(&self->parked);
+		schedule();
+		__set_current_state(TASK_INTERRUPTIBLE);
+	}
+	clear_bit(KTHREAD_IS_PARKED, &self->flags);
+	__set_current_state(TASK_RUNNING);
+}
+
+void kthread_parkme(void)
+{
+	__kthread_parkme(to_kthread(current));
+}
+
 static int kthread(void *_create)
 {
 	/* Copy data: it's on kthread's stack */
@@ -105,9 +148,10 @@
 	struct kthread self;
 	int ret;
 
-	self.should_stop = 0;
+	self.flags = 0;
 	self.data = data;
 	init_completion(&self.exited);
+	init_completion(&self.parked);
 	current->vfork_done = &self.exited;
 
 	/* OK, tell user we're spawned, wait for stop or wakeup */
@@ -117,9 +161,11 @@
 	schedule();
 
 	ret = -EINTR;
-	if (!self.should_stop)
-		ret = threadfn(data);
 
+	if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
+		__kthread_parkme(&self);
+		ret = threadfn(data);
+	}
 	/* we can't just return, we must preserve "self" on stack */
 	do_exit(ret);
 }
@@ -172,8 +218,7 @@
  * Returns a task_struct or ERR_PTR(-ENOMEM).
  */
 struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
-					   void *data,
-					   int node,
+					   void *data, int node,
 					   const char namefmt[],
 					   ...)
 {
@@ -210,6 +255,13 @@
 }
 EXPORT_SYMBOL(kthread_create_on_node);
 
+static void __kthread_bind(struct task_struct *p, unsigned int cpu)
+{
+	/* It's safe because the task is inactive. */
+	do_set_cpus_allowed(p, cpumask_of(cpu));
+	p->flags |= PF_THREAD_BOUND;
+}
+
 /**
  * kthread_bind - bind a just-created kthread to a cpu.
  * @p: thread created by kthread_create().
@@ -226,14 +278,112 @@
 		WARN_ON(1);
 		return;
 	}
-
-	/* It's safe because the task is inactive. */
-	do_set_cpus_allowed(p, cpumask_of(cpu));
-	p->flags |= PF_THREAD_BOUND;
+	__kthread_bind(p, cpu);
 }
 EXPORT_SYMBOL(kthread_bind);
 
 /**
+ * kthread_create_on_cpu - Create a cpu bound kthread
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @cpu: The cpu on which the thread should be bound,
+ * @namefmt: printf-style name for the thread. Format is restricted
+ *	     to "name.*%u". Code fills in cpu number.
+ *
+ * Description: This helper function creates and names a kernel thread
+ * The thread will be woken and put into park mode.
+ */
+struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
+					  void *data, unsigned int cpu,
+					  const char *namefmt)
+{
+	struct task_struct *p;
+
+	p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt,
+				   cpu);
+	if (IS_ERR(p))
+		return p;
+	set_bit(KTHREAD_IS_PER_CPU, &to_kthread(p)->flags);
+	to_kthread(p)->cpu = cpu;
+	/* Park the thread to get it out of TASK_UNINTERRUPTIBLE state */
+	kthread_park(p);
+	return p;
+}
+
+static struct kthread *task_get_live_kthread(struct task_struct *k)
+{
+	struct kthread *kthread;
+
+	get_task_struct(k);
+	kthread = to_kthread(k);
+	/* It might have exited */
+	barrier();
+	if (k->vfork_done != NULL)
+		return kthread;
+	return NULL;
+}
+
+/**
+ * kthread_unpark - unpark a thread created by kthread_create().
+ * @k:		thread created by kthread_create().
+ *
+ * Sets kthread_should_park() for @k to return false, wakes it, and
+ * waits for it to return. If the thread is marked percpu then its
+ * bound to the cpu again.
+ */
+void kthread_unpark(struct task_struct *k)
+{
+	struct kthread *kthread = task_get_live_kthread(k);
+
+	if (kthread) {
+		clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+		/*
+		 * We clear the IS_PARKED bit here as we don't wait
+		 * until the task has left the park code. So if we'd
+		 * park before that happens we'd see the IS_PARKED bit
+		 * which might be about to be cleared.
+		 */
+		if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
+			if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
+				__kthread_bind(k, kthread->cpu);
+			wake_up_process(k);
+		}
+	}
+	put_task_struct(k);
+}
+
+/**
+ * kthread_park - park a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_park() for @k to return true, wakes it, and
+ * waits for it to return. This can also be called after kthread_create()
+ * instead of calling wake_up_process(): the thread will park without
+ * calling threadfn().
+ *
+ * Returns 0 if the thread is parked, -ENOSYS if the thread exited.
+ * If called by the kthread itself just the park bit is set.
+ */
+int kthread_park(struct task_struct *k)
+{
+	struct kthread *kthread = task_get_live_kthread(k);
+	int ret = -ENOSYS;
+
+	if (kthread) {
+		if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
+			set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+			if (k != current) {
+				wake_up_process(k);
+				wait_for_completion(&kthread->parked);
+			}
+		}
+		ret = 0;
+	}
+	put_task_struct(k);
+	return ret;
+}
+
+/**
  * kthread_stop - stop a thread created by kthread_create().
  * @k: thread created by kthread_create().
  *
@@ -250,16 +400,13 @@
  */
 int kthread_stop(struct task_struct *k)
 {
-	struct kthread *kthread;
+	struct kthread *kthread = task_get_live_kthread(k);
 	int ret;
 
 	trace_sched_kthread_stop(k);
-	get_task_struct(k);
-
-	kthread = to_kthread(k);
-	barrier(); /* it might have exited */
-	if (k->vfork_done != NULL) {
-		kthread->should_stop = 1;
+	if (kthread) {
+		set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
+		clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
 		wake_up_process(k);
 		wait_for_completion(&kthread->exited);
 	}
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index ea9ee45..7981e5b 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -2998,6 +2998,42 @@
 
 struct lock_class_key __lockdep_no_validate__;
 
+static int
+print_lock_nested_lock_not_held(struct task_struct *curr,
+				struct held_lock *hlock,
+				unsigned long ip)
+{
+	if (!debug_locks_off())
+		return 0;
+	if (debug_locks_silent)
+		return 0;
+
+	printk("\n");
+	printk("==================================\n");
+	printk("[ BUG: Nested lock was not taken ]\n");
+	print_kernel_ident();
+	printk("----------------------------------\n");
+
+	printk("%s/%d is trying to lock:\n", curr->comm, task_pid_nr(curr));
+	print_lock(hlock);
+
+	printk("\nbut this task is not holding:\n");
+	printk("%s\n", hlock->nest_lock->name);
+
+	printk("\nstack backtrace:\n");
+	dump_stack();
+
+	printk("\nother info that might help us debug this:\n");
+	lockdep_print_held_locks(curr);
+
+	printk("\nstack backtrace:\n");
+	dump_stack();
+
+	return 0;
+}
+
+static int __lock_is_held(struct lockdep_map *lock);
+
 /*
  * This gets called for every mutex_lock*()/spin_lock*() operation.
  * We maintain the dependency maps and validate the locking attempt:
@@ -3139,6 +3175,9 @@
 	}
 	chain_key = iterate_chain_key(chain_key, id);
 
+	if (nest_lock && !__lock_is_held(nest_lock))
+		return print_lock_nested_lock_not_held(curr, hlock, ip);
+
 	if (!validate_chain(curr, lock, hlock, chain_head, chain_key))
 		return 0;
 
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index b3c7fd5..6144bab 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -232,15 +232,19 @@
 	 */
 
 	tmp.data = &current->nsproxy->pid_ns->last_pid;
-	return proc_dointvec(&tmp, write, buffer, lenp, ppos);
+	return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
 }
 
+extern int pid_max;
+static int zero = 0;
 static struct ctl_table pid_ns_ctl_table[] = {
 	{
 		.procname = "ns_last_pid",
 		.maxlen = sizeof(int),
 		.mode = 0666, /* permissions are checked in the handler */
 		.proc_handler = pid_ns_ctl_handler,
+		.extra1 = &zero,
+		.extra2 = &pid_max,
 	},
 	{ }
 };
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 4e6a61b..29ca1c6d 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -45,6 +45,7 @@
 #include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/hardirq.h>
+#include <linux/delay.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/rcu.h>
@@ -81,6 +82,9 @@
 	} else {
 		barrier();  /* critical section before exit code. */
 		t->rcu_read_lock_nesting = INT_MIN;
+#ifdef CONFIG_PROVE_RCU_DELAY
+		udelay(10); /* Make preemption more probable. */
+#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
 		barrier();  /* assign before ->rcu_read_unlock_special load */
 		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
 			rcu_read_unlock_special(t);
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 547b1fe..e4c6a59 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -56,25 +56,28 @@
 static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 
 /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */
-static void rcu_idle_enter_common(long long oldval)
+static void rcu_idle_enter_common(long long newval)
 {
-	if (rcu_dynticks_nesting) {
+	if (newval) {
 		RCU_TRACE(trace_rcu_dyntick("--=",
-					    oldval, rcu_dynticks_nesting));
+					    rcu_dynticks_nesting, newval));
+		rcu_dynticks_nesting = newval;
 		return;
 	}
-	RCU_TRACE(trace_rcu_dyntick("Start", oldval, rcu_dynticks_nesting));
+	RCU_TRACE(trace_rcu_dyntick("Start", rcu_dynticks_nesting, newval));
 	if (!is_idle_task(current)) {
 		struct task_struct *idle = idle_task(smp_processor_id());
 
 		RCU_TRACE(trace_rcu_dyntick("Error on entry: not idle task",
-					    oldval, rcu_dynticks_nesting));
+					    rcu_dynticks_nesting, newval));
 		ftrace_dump(DUMP_ALL);
 		WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
 			  current->pid, current->comm,
 			  idle->pid, idle->comm); /* must be idle task! */
 	}
 	rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */
+	barrier();
+	rcu_dynticks_nesting = newval;
 }
 
 /*
@@ -84,17 +87,16 @@
 void rcu_idle_enter(void)
 {
 	unsigned long flags;
-	long long oldval;
+	long long newval;
 
 	local_irq_save(flags);
-	oldval = rcu_dynticks_nesting;
 	WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0);
 	if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) ==
 	    DYNTICK_TASK_NEST_VALUE)
-		rcu_dynticks_nesting = 0;
+		newval = 0;
 	else
-		rcu_dynticks_nesting  -= DYNTICK_TASK_NEST_VALUE;
-	rcu_idle_enter_common(oldval);
+		newval = rcu_dynticks_nesting - DYNTICK_TASK_NEST_VALUE;
+	rcu_idle_enter_common(newval);
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_enter);
@@ -105,15 +107,15 @@
 void rcu_irq_exit(void)
 {
 	unsigned long flags;
-	long long oldval;
+	long long newval;
 
 	local_irq_save(flags);
-	oldval = rcu_dynticks_nesting;
-	rcu_dynticks_nesting--;
-	WARN_ON_ONCE(rcu_dynticks_nesting < 0);
-	rcu_idle_enter_common(oldval);
+	newval = rcu_dynticks_nesting - 1;
+	WARN_ON_ONCE(newval < 0);
+	rcu_idle_enter_common(newval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
 /* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */
 static void rcu_idle_exit_common(long long oldval)
@@ -171,6 +173,7 @@
 	rcu_idle_exit_common(oldval);
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_enter);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index 918fd1e..3d01902 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -278,7 +278,7 @@
 	    rcu_preempt_ctrlblk.exp_tasks == NULL)
 		return 0;  /* Nothing to boost. */
 
-	raw_local_irq_save(flags);
+	local_irq_save(flags);
 
 	/*
 	 * Recheck with irqs disabled: all tasks in need of boosting
@@ -287,7 +287,7 @@
 	 */
 	if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
 	    rcu_preempt_ctrlblk.exp_tasks == NULL) {
-		raw_local_irq_restore(flags);
+		local_irq_restore(flags);
 		return 0;
 	}
 
@@ -317,7 +317,7 @@
 	t = container_of(tb, struct task_struct, rcu_node_entry);
 	rt_mutex_init_proxy_locked(&mtx, t);
 	t->rcu_boost_mutex = &mtx;
-	raw_local_irq_restore(flags);
+	local_irq_restore(flags);
 	rt_mutex_lock(&mtx);
 	rt_mutex_unlock(&mtx);  /* Keep lockdep happy. */
 
@@ -991,9 +991,9 @@
 {
 	unsigned long flags;
 
-	raw_local_irq_save(flags);
+	local_irq_save(flags);
 	rcp->qlen -= n;
-	raw_local_irq_restore(flags);
+	local_irq_restore(flags);
 }
 
 /*
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 25b1503..aaa7b9f 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -53,10 +53,11 @@
 
 static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
 static int nfakewriters = 4;	/* # fake writer threads */
-static int stat_interval;	/* Interval between stats, in seconds. */
-				/*  Defaults to "only at end of test". */
+static int stat_interval = 60;	/* Interval between stats, in seconds. */
+				/*  Zero means "only at end of test". */
 static bool verbose;		/* Print more debug info. */
-static bool test_no_idle_hz;	/* Test RCU's support for tickless idle CPUs. */
+static bool test_no_idle_hz = true;
+				/* Test RCU support for tickless idle CPUs. */
 static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
 static int stutter = 5;		/* Start/stop testing interval (in sec) */
 static int irqreader = 1;	/* RCU readers from irq (timers). */
@@ -119,11 +120,11 @@
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
-	do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
+	do { pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_STRING(s) \
-	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
+	do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_ERRSTRING(s) \
-	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
+	do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
 
 static char printk_buf[4096];
 
@@ -176,8 +177,14 @@
 static long n_rcu_torture_timers;
 static long n_offline_attempts;
 static long n_offline_successes;
+static unsigned long sum_offline;
+static int min_offline = -1;
+static int max_offline;
 static long n_online_attempts;
 static long n_online_successes;
+static unsigned long sum_online;
+static int min_online = -1;
+static int max_online;
 static long n_barrier_attempts;
 static long n_barrier_successes;
 static struct list_head rcu_torture_removed;
@@ -235,7 +242,7 @@
 	if (fullstop == FULLSTOP_DONTSTOP)
 		fullstop = FULLSTOP_SHUTDOWN;
 	else
-		printk(KERN_WARNING /* but going down anyway, so... */
+		pr_warn(/* but going down anyway, so... */
 		       "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
 	mutex_unlock(&fullstop_mutex);
 	return NOTIFY_DONE;
@@ -248,7 +255,7 @@
 static void rcutorture_shutdown_absorb(char *title)
 {
 	if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
-		printk(KERN_NOTICE
+		pr_notice(
 		       "rcutorture thread %s parking due to system shutdown\n",
 		       title);
 		schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
@@ -1214,11 +1221,13 @@
 		       n_rcu_torture_boost_failure,
 		       n_rcu_torture_boosts,
 		       n_rcu_torture_timers);
-	cnt += sprintf(&page[cnt], "onoff: %ld/%ld:%ld/%ld ",
-		       n_online_successes,
-		       n_online_attempts,
-		       n_offline_successes,
-		       n_offline_attempts);
+	cnt += sprintf(&page[cnt],
+		       "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
+		       n_online_successes, n_online_attempts,
+		       n_offline_successes, n_offline_attempts,
+		       min_online, max_online,
+		       min_offline, max_offline,
+		       sum_online, sum_offline, HZ);
 	cnt += sprintf(&page[cnt], "barrier: %ld/%ld:%ld",
 		       n_barrier_successes,
 		       n_barrier_attempts,
@@ -1267,7 +1276,7 @@
 	int cnt;
 
 	cnt = rcu_torture_printk(printk_buf);
-	printk(KERN_ALERT "%s", printk_buf);
+	pr_alert("%s", printk_buf);
 }
 
 /*
@@ -1380,20 +1389,20 @@
 static inline void
 rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag)
 {
-	printk(KERN_ALERT "%s" TORTURE_FLAG
-		"--- %s: nreaders=%d nfakewriters=%d "
-		"stat_interval=%d verbose=%d test_no_idle_hz=%d "
-		"shuffle_interval=%d stutter=%d irqreader=%d "
-		"fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
-		"test_boost=%d/%d test_boost_interval=%d "
-		"test_boost_duration=%d shutdown_secs=%d "
-		"onoff_interval=%d onoff_holdoff=%d\n",
-		torture_type, tag, nrealreaders, nfakewriters,
-		stat_interval, verbose, test_no_idle_hz, shuffle_interval,
-		stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
-		test_boost, cur_ops->can_boost,
-		test_boost_interval, test_boost_duration, shutdown_secs,
-		onoff_interval, onoff_holdoff);
+	pr_alert("%s" TORTURE_FLAG
+		 "--- %s: nreaders=%d nfakewriters=%d "
+		 "stat_interval=%d verbose=%d test_no_idle_hz=%d "
+		 "shuffle_interval=%d stutter=%d irqreader=%d "
+		 "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
+		 "test_boost=%d/%d test_boost_interval=%d "
+		 "test_boost_duration=%d shutdown_secs=%d "
+		 "onoff_interval=%d onoff_holdoff=%d\n",
+		 torture_type, tag, nrealreaders, nfakewriters,
+		 stat_interval, verbose, test_no_idle_hz, shuffle_interval,
+		 stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
+		 test_boost, cur_ops->can_boost,
+		 test_boost_interval, test_boost_duration, shutdown_secs,
+		 onoff_interval, onoff_holdoff);
 }
 
 static struct notifier_block rcutorture_shutdown_nb = {
@@ -1460,9 +1469,9 @@
 	       !kthread_should_stop()) {
 		delta = shutdown_time - jiffies_snap;
 		if (verbose)
-			printk(KERN_ALERT "%s" TORTURE_FLAG
-			       "rcu_torture_shutdown task: %lu jiffies remaining\n",
-			       torture_type, delta);
+			pr_alert("%s" TORTURE_FLAG
+				 "rcu_torture_shutdown task: %lu jiffies remaining\n",
+				 torture_type, delta);
 		schedule_timeout_interruptible(delta);
 		jiffies_snap = ACCESS_ONCE(jiffies);
 	}
@@ -1490,8 +1499,10 @@
 rcu_torture_onoff(void *arg)
 {
 	int cpu;
+	unsigned long delta;
 	int maxcpu = -1;
 	DEFINE_RCU_RANDOM(rand);
+	unsigned long starttime;
 
 	VERBOSE_PRINTK_STRING("rcu_torture_onoff task started");
 	for_each_online_cpu(cpu)
@@ -1506,29 +1517,51 @@
 		cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
 		if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
 			if (verbose)
-				printk(KERN_ALERT "%s" TORTURE_FLAG
-				       "rcu_torture_onoff task: offlining %d\n",
-				       torture_type, cpu);
+				pr_alert("%s" TORTURE_FLAG
+					 "rcu_torture_onoff task: offlining %d\n",
+					 torture_type, cpu);
+			starttime = jiffies;
 			n_offline_attempts++;
 			if (cpu_down(cpu) == 0) {
 				if (verbose)
-					printk(KERN_ALERT "%s" TORTURE_FLAG
-					       "rcu_torture_onoff task: offlined %d\n",
-					       torture_type, cpu);
+					pr_alert("%s" TORTURE_FLAG
+						 "rcu_torture_onoff task: offlined %d\n",
+						 torture_type, cpu);
 				n_offline_successes++;
+				delta = jiffies - starttime;
+				sum_offline += delta;
+				if (min_offline < 0) {
+					min_offline = delta;
+					max_offline = delta;
+				}
+				if (min_offline > delta)
+					min_offline = delta;
+				if (max_offline < delta)
+					max_offline = delta;
 			}
 		} else if (cpu_is_hotpluggable(cpu)) {
 			if (verbose)
-				printk(KERN_ALERT "%s" TORTURE_FLAG
-				       "rcu_torture_onoff task: onlining %d\n",
-				       torture_type, cpu);
+				pr_alert("%s" TORTURE_FLAG
+					 "rcu_torture_onoff task: onlining %d\n",
+					 torture_type, cpu);
+			starttime = jiffies;
 			n_online_attempts++;
 			if (cpu_up(cpu) == 0) {
 				if (verbose)
-					printk(KERN_ALERT "%s" TORTURE_FLAG
-					       "rcu_torture_onoff task: onlined %d\n",
-					       torture_type, cpu);
+					pr_alert("%s" TORTURE_FLAG
+						 "rcu_torture_onoff task: onlined %d\n",
+						 torture_type, cpu);
 				n_online_successes++;
+				delta = jiffies - starttime;
+				sum_online += delta;
+				if (min_online < 0) {
+					min_online = delta;
+					max_online = delta;
+				}
+				if (min_online > delta)
+					min_online = delta;
+				if (max_online < delta)
+					max_online = delta;
 			}
 		}
 		schedule_timeout_interruptible(onoff_interval * HZ);
@@ -1593,14 +1626,14 @@
 	if (!kthread_should_stop()) {
 		stop_at = get_seconds() + stall_cpu;
 		/* RCU CPU stall is expected behavior in following code. */
-		printk(KERN_ALERT "rcu_torture_stall start.\n");
+		pr_alert("rcu_torture_stall start.\n");
 		rcu_read_lock();
 		preempt_disable();
 		while (ULONG_CMP_LT(get_seconds(), stop_at))
 			continue;  /* Induce RCU CPU stall warning. */
 		preempt_enable();
 		rcu_read_unlock();
-		printk(KERN_ALERT "rcu_torture_stall end.\n");
+		pr_alert("rcu_torture_stall end.\n");
 	}
 	rcutorture_shutdown_absorb("rcu_torture_stall");
 	while (!kthread_should_stop())
@@ -1716,12 +1749,12 @@
 	if (n_barrier_cbs == 0)
 		return 0;
 	if (cur_ops->call == NULL || cur_ops->cb_barrier == NULL) {
-		printk(KERN_ALERT "%s" TORTURE_FLAG
-		       " Call or barrier ops missing for %s,\n",
-		       torture_type, cur_ops->name);
-		printk(KERN_ALERT "%s" TORTURE_FLAG
-		       " RCU barrier testing omitted from run.\n",
-		       torture_type);
+		pr_alert("%s" TORTURE_FLAG
+			 " Call or barrier ops missing for %s,\n",
+			 torture_type, cur_ops->name);
+		pr_alert("%s" TORTURE_FLAG
+			 " RCU barrier testing omitted from run.\n",
+			 torture_type);
 		return 0;
 	}
 	atomic_set(&barrier_cbs_count, 0);
@@ -1814,7 +1847,7 @@
 	mutex_lock(&fullstop_mutex);
 	rcutorture_record_test_transition();
 	if (fullstop == FULLSTOP_SHUTDOWN) {
-		printk(KERN_WARNING /* but going down anyway, so... */
+		pr_warn(/* but going down anyway, so... */
 		       "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
 		mutex_unlock(&fullstop_mutex);
 		schedule_timeout_uninterruptible(10);
@@ -1938,17 +1971,17 @@
 			break;
 	}
 	if (i == ARRAY_SIZE(torture_ops)) {
-		printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"\n",
-		       torture_type);
-		printk(KERN_ALERT "rcu-torture types:");
+		pr_alert("rcu-torture: invalid torture type: \"%s\"\n",
+			 torture_type);
+		pr_alert("rcu-torture types:");
 		for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
-			printk(KERN_ALERT " %s", torture_ops[i]->name);
-		printk(KERN_ALERT "\n");
+			pr_alert(" %s", torture_ops[i]->name);
+		pr_alert("\n");
 		mutex_unlock(&fullstop_mutex);
 		return -EINVAL;
 	}
 	if (cur_ops->fqs == NULL && fqs_duration != 0) {
-		printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");
+		pr_alert("rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");
 		fqs_duration = 0;
 	}
 	if (cur_ops->init)
@@ -1996,14 +2029,15 @@
 	/* Start up the kthreads. */
 
 	VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task");
-	writer_task = kthread_run(rcu_torture_writer, NULL,
-				  "rcu_torture_writer");
+	writer_task = kthread_create(rcu_torture_writer, NULL,
+				     "rcu_torture_writer");
 	if (IS_ERR(writer_task)) {
 		firsterr = PTR_ERR(writer_task);
 		VERBOSE_PRINTK_ERRSTRING("Failed to create writer");
 		writer_task = NULL;
 		goto unwind;
 	}
+	wake_up_process(writer_task);
 	fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
 				   GFP_KERNEL);
 	if (fakewriter_tasks == NULL) {
@@ -2118,14 +2152,15 @@
 	}
 	if (shutdown_secs > 0) {
 		shutdown_time = jiffies + shutdown_secs * HZ;
-		shutdown_task = kthread_run(rcu_torture_shutdown, NULL,
-					    "rcu_torture_shutdown");
+		shutdown_task = kthread_create(rcu_torture_shutdown, NULL,
+					       "rcu_torture_shutdown");
 		if (IS_ERR(shutdown_task)) {
 			firsterr = PTR_ERR(shutdown_task);
 			VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown");
 			shutdown_task = NULL;
 			goto unwind;
 		}
+		wake_up_process(shutdown_task);
 	}
 	i = rcu_torture_onoff_init();
 	if (i != 0) {
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index f280e54..4fb2376 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -52,6 +52,7 @@
 #include <linux/prefetch.h>
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
+#include <linux/random.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -61,6 +62,7 @@
 /* Data structures. */
 
 static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
 
 #define RCU_STATE_INITIALIZER(sname, cr) { \
 	.level = { &sname##_state.node[0] }, \
@@ -72,7 +74,6 @@
 	.orphan_nxttail = &sname##_state.orphan_nxtlist, \
 	.orphan_donetail = &sname##_state.orphan_donelist, \
 	.barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
-	.fqslock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.fqslock), \
 	.name = #sname, \
 }
 
@@ -88,7 +89,7 @@
 
 /* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
 static int rcu_fanout_leaf = CONFIG_RCU_FANOUT_LEAF;
-module_param(rcu_fanout_leaf, int, 0);
+module_param(rcu_fanout_leaf, int, 0444);
 int rcu_num_lvls __read_mostly = RCU_NUM_LVLS;
 static int num_rcu_lvl[] = {  /* Number of rcu_nodes at specified level. */
 	NUM_RCU_LVL_0,
@@ -133,13 +134,12 @@
  */
 static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
 DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
-DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu);
 DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
 DEFINE_PER_CPU(char, rcu_cpu_has_work);
 
 #endif /* #ifdef CONFIG_RCU_BOOST */
 
-static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
 static void invoke_rcu_core(void);
 static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
 
@@ -175,8 +175,6 @@
 {
 	struct rcu_data *rdp = &per_cpu(rcu_sched_data, cpu);
 
-	rdp->passed_quiesce_gpnum = rdp->gpnum;
-	barrier();
 	if (rdp->passed_quiesce == 0)
 		trace_rcu_grace_period("rcu_sched", rdp->gpnum, "cpuqs");
 	rdp->passed_quiesce = 1;
@@ -186,8 +184,6 @@
 {
 	struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
 
-	rdp->passed_quiesce_gpnum = rdp->gpnum;
-	barrier();
 	if (rdp->passed_quiesce == 0)
 		trace_rcu_grace_period("rcu_bh", rdp->gpnum, "cpuqs");
 	rdp->passed_quiesce = 1;
@@ -210,15 +206,18 @@
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
 	.dynticks_nesting = DYNTICK_TASK_EXIT_IDLE,
 	.dynticks = ATOMIC_INIT(1),
+#if defined(CONFIG_RCU_USER_QS) && !defined(CONFIG_RCU_USER_QS_FORCE)
+	.ignore_user_qs = true,
+#endif
 };
 
 static int blimit = 10;		/* Maximum callbacks per rcu_do_batch. */
 static int qhimark = 10000;	/* If this many pending, ignore blimit. */
 static int qlowmark = 100;	/* Once only this many pending, use blimit. */
 
-module_param(blimit, int, 0);
-module_param(qhimark, int, 0);
-module_param(qlowmark, int, 0);
+module_param(blimit, int, 0444);
+module_param(qhimark, int, 0444);
+module_param(qlowmark, int, 0444);
 
 int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
 int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
@@ -226,7 +225,14 @@
 module_param(rcu_cpu_stall_suppress, int, 0644);
 module_param(rcu_cpu_stall_timeout, int, 0644);
 
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
+static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS;
+static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS;
+
+module_param(jiffies_till_first_fqs, ulong, 0644);
+module_param(jiffies_till_next_fqs, ulong, 0644);
+
+static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
+static void force_quiescent_state(struct rcu_state *rsp);
 static int rcu_pending(int cpu);
 
 /*
@@ -252,7 +258,7 @@
  */
 void rcu_bh_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_bh_state, 0);
+	force_quiescent_state(&rcu_bh_state);
 }
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
@@ -286,7 +292,7 @@
  */
 void rcu_sched_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_sched_state, 0);
+	force_quiescent_state(&rcu_sched_state);
 }
 EXPORT_SYMBOL_GPL(rcu_sched_force_quiescent_state);
 
@@ -305,7 +311,9 @@
 static int
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-	return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+	return *rdp->nxttail[RCU_DONE_TAIL +
+			     ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+	       !rcu_gp_in_progress(rsp);
 }
 
 /*
@@ -317,45 +325,17 @@
 }
 
 /*
- * If the specified CPU is offline, tell the caller that it is in
- * a quiescent state.  Otherwise, whack it with a reschedule IPI.
- * Grace periods can end up waiting on an offline CPU when that
- * CPU is in the process of coming online -- it will be added to the
- * rcu_node bitmasks before it actually makes it online.  The same thing
- * can happen while a CPU is in the process of coming online.  Because this
- * race is quite rare, we check for it after detecting that the grace
- * period has been delayed rather than checking each and every CPU
- * each and every time we start a new grace period.
- */
-static int rcu_implicit_offline_qs(struct rcu_data *rdp)
-{
-	/*
-	 * If the CPU is offline for more than a jiffy, it is in a quiescent
-	 * state.  We can trust its state not to change because interrupts
-	 * are disabled.  The reason for the jiffy's worth of slack is to
-	 * handle CPUs initializing on the way up and finding their way
-	 * to the idle loop on the way down.
-	 */
-	if (cpu_is_offline(rdp->cpu) &&
-	    ULONG_CMP_LT(rdp->rsp->gp_start + 2, jiffies)) {
-		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
-		rdp->offline_fqs++;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * rcu_idle_enter_common - inform RCU that current CPU is moving towards idle
+ * rcu_eqs_enter_common - current CPU is moving towards extended quiescent state
  *
  * If the new value of the ->dynticks_nesting counter now is zero,
  * we really have entered idle, and must do the appropriate accounting.
  * The caller must have disabled interrupts.
  */
-static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
+static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
+				bool user)
 {
 	trace_rcu_dyntick("Start", oldval, 0);
-	if (!is_idle_task(current)) {
+	if (!user && !is_idle_task(current)) {
 		struct task_struct *idle = idle_task(smp_processor_id());
 
 		trace_rcu_dyntick("Error on entry: not idle task", oldval, 0);
@@ -372,7 +352,7 @@
 	WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 
 	/*
-	 * The idle task is not permitted to enter the idle loop while
+	 * It is illegal to enter an extended quiescent state while
 	 * in an RCU read-side critical section.
 	 */
 	rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
@@ -383,6 +363,25 @@
 			   "Illegal idle entry in RCU-sched read-side critical section.");
 }
 
+/*
+ * Enter an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ */
+static void rcu_eqs_enter(bool user)
+{
+	long long oldval;
+	struct rcu_dynticks *rdtp;
+
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	oldval = rdtp->dynticks_nesting;
+	WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
+	if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE)
+		rdtp->dynticks_nesting = 0;
+	else
+		rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
+	rcu_eqs_enter_common(rdtp, oldval, user);
+}
+
 /**
  * rcu_idle_enter - inform RCU that current CPU is entering idle
  *
@@ -398,21 +397,70 @@
 void rcu_idle_enter(void)
 {
 	unsigned long flags;
-	long long oldval;
+
+	local_irq_save(flags);
+	rcu_eqs_enter(false);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(rcu_idle_enter);
+
+#ifdef CONFIG_RCU_USER_QS
+/**
+ * rcu_user_enter - inform RCU that we are resuming userspace.
+ *
+ * Enter RCU idle mode right before resuming userspace.  No use of RCU
+ * is permitted between this call and rcu_user_exit(). This way the
+ * CPU doesn't need to maintain the tick for RCU maintenance purposes
+ * when the CPU runs in userspace.
+ */
+void rcu_user_enter(void)
+{
+	unsigned long flags;
+	struct rcu_dynticks *rdtp;
+
+	/*
+	 * Some contexts may involve an exception occuring in an irq,
+	 * leading to that nesting:
+	 * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
+	 * This would mess up the dyntick_nesting count though. And rcu_irq_*()
+	 * helpers are enough to protect RCU uses inside the exception. So
+	 * just return immediately if we detect we are in an IRQ.
+	 */
+	if (in_interrupt())
+		return;
+
+	WARN_ON_ONCE(!current->mm);
+
+	local_irq_save(flags);
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	if (!rdtp->ignore_user_qs && !rdtp->in_user) {
+		rdtp->in_user = true;
+		rcu_eqs_enter(true);
+	}
+	local_irq_restore(flags);
+}
+
+/**
+ * rcu_user_enter_after_irq - inform RCU that we are going to resume userspace
+ * after the current irq returns.
+ *
+ * This is similar to rcu_user_enter() but in the context of a non-nesting
+ * irq. After this call, RCU enters into idle mode when the interrupt
+ * returns.
+ */
+void rcu_user_enter_after_irq(void)
+{
+	unsigned long flags;
 	struct rcu_dynticks *rdtp;
 
 	local_irq_save(flags);
 	rdtp = &__get_cpu_var(rcu_dynticks);
-	oldval = rdtp->dynticks_nesting;
-	WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
-	if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE)
-		rdtp->dynticks_nesting = 0;
-	else
-		rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
-	rcu_idle_enter_common(rdtp, oldval);
+	/* Ensure this irq is interrupting a non-idle RCU state.  */
+	WARN_ON_ONCE(!(rdtp->dynticks_nesting & DYNTICK_TASK_MASK));
+	rdtp->dynticks_nesting = 1;
 	local_irq_restore(flags);
 }
-EXPORT_SYMBOL_GPL(rcu_idle_enter);
+#endif /* CONFIG_RCU_USER_QS */
 
 /**
  * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle
@@ -444,18 +492,19 @@
 	if (rdtp->dynticks_nesting)
 		trace_rcu_dyntick("--=", oldval, rdtp->dynticks_nesting);
 	else
-		rcu_idle_enter_common(rdtp, oldval);
+		rcu_eqs_enter_common(rdtp, oldval, true);
 	local_irq_restore(flags);
 }
 
 /*
- * rcu_idle_exit_common - inform RCU that current CPU is moving away from idle
+ * rcu_eqs_exit_common - current CPU moving away from extended quiescent state
  *
  * If the new value of the ->dynticks_nesting counter was previously zero,
  * we really have exited idle, and must do the appropriate accounting.
  * The caller must have disabled interrupts.
  */
-static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
+static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
+			       int user)
 {
 	smp_mb__before_atomic_inc();  /* Force ordering w/previous sojourn. */
 	atomic_inc(&rdtp->dynticks);
@@ -464,7 +513,7 @@
 	WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
 	rcu_cleanup_after_idle(smp_processor_id());
 	trace_rcu_dyntick("End", oldval, rdtp->dynticks_nesting);
-	if (!is_idle_task(current)) {
+	if (!user && !is_idle_task(current)) {
 		struct task_struct *idle = idle_task(smp_processor_id());
 
 		trace_rcu_dyntick("Error on exit: not idle task",
@@ -476,6 +525,25 @@
 	}
 }
 
+/*
+ * Exit an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ */
+static void rcu_eqs_exit(bool user)
+{
+	struct rcu_dynticks *rdtp;
+	long long oldval;
+
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	oldval = rdtp->dynticks_nesting;
+	WARN_ON_ONCE(oldval < 0);
+	if (oldval & DYNTICK_TASK_NEST_MASK)
+		rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
+	else
+		rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
+	rcu_eqs_exit_common(rdtp, oldval, user);
+}
+
 /**
  * rcu_idle_exit - inform RCU that current CPU is leaving idle
  *
@@ -490,22 +558,68 @@
 void rcu_idle_exit(void)
 {
 	unsigned long flags;
-	struct rcu_dynticks *rdtp;
-	long long oldval;
 
 	local_irq_save(flags);
-	rdtp = &__get_cpu_var(rcu_dynticks);
-	oldval = rdtp->dynticks_nesting;
-	WARN_ON_ONCE(oldval < 0);
-	if (oldval & DYNTICK_TASK_NEST_MASK)
-		rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
-	else
-		rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
-	rcu_idle_exit_common(rdtp, oldval);
+	rcu_eqs_exit(false);
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_exit);
 
+#ifdef CONFIG_RCU_USER_QS
+/**
+ * rcu_user_exit - inform RCU that we are exiting userspace.
+ *
+ * Exit RCU idle mode while entering the kernel because it can
+ * run a RCU read side critical section anytime.
+ */
+void rcu_user_exit(void)
+{
+	unsigned long flags;
+	struct rcu_dynticks *rdtp;
+
+	/*
+	 * Some contexts may involve an exception occuring in an irq,
+	 * leading to that nesting:
+	 * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
+	 * This would mess up the dyntick_nesting count though. And rcu_irq_*()
+	 * helpers are enough to protect RCU uses inside the exception. So
+	 * just return immediately if we detect we are in an IRQ.
+	 */
+	if (in_interrupt())
+		return;
+
+	local_irq_save(flags);
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	if (rdtp->in_user) {
+		rdtp->in_user = false;
+		rcu_eqs_exit(true);
+	}
+	local_irq_restore(flags);
+}
+
+/**
+ * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace
+ * idle mode after the current non-nesting irq returns.
+ *
+ * This is similar to rcu_user_exit() but in the context of an irq.
+ * This is called when the irq has interrupted a userspace RCU idle mode
+ * context. When the current non-nesting interrupt returns after this call,
+ * the CPU won't restore the RCU idle mode.
+ */
+void rcu_user_exit_after_irq(void)
+{
+	unsigned long flags;
+	struct rcu_dynticks *rdtp;
+
+	local_irq_save(flags);
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	/* Ensure we are interrupting an RCU idle mode. */
+	WARN_ON_ONCE(rdtp->dynticks_nesting & DYNTICK_TASK_NEST_MASK);
+	rdtp->dynticks_nesting += DYNTICK_TASK_EXIT_IDLE;
+	local_irq_restore(flags);
+}
+#endif /* CONFIG_RCU_USER_QS */
+
 /**
  * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle
  *
@@ -539,7 +653,7 @@
 	if (oldval)
 		trace_rcu_dyntick("++=", oldval, rdtp->dynticks_nesting);
 	else
-		rcu_idle_exit_common(rdtp, oldval);
+		rcu_eqs_exit_common(rdtp, oldval, true);
 	local_irq_restore(flags);
 }
 
@@ -603,6 +717,21 @@
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
+#ifdef CONFIG_RCU_USER_QS
+void rcu_user_hooks_switch(struct task_struct *prev,
+			   struct task_struct *next)
+{
+	struct rcu_dynticks *rdtp;
+
+	/* Interrupts are disabled in context switch */
+	rdtp = &__get_cpu_var(rcu_dynticks);
+	if (!rdtp->ignore_user_qs) {
+		clear_tsk_thread_flag(prev, TIF_NOHZ);
+		set_tsk_thread_flag(next, TIF_NOHZ);
+	}
+}
+#endif /* #ifdef CONFIG_RCU_USER_QS */
+
 #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
 
 /*
@@ -673,7 +802,7 @@
  * Return true if the specified CPU has passed through a quiescent
  * state by virtue of being in or having passed through an dynticks
  * idle state since the last call to dyntick_save_progress_counter()
- * for this same CPU.
+ * for this same CPU, or by virtue of having been offline.
  */
 static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 {
@@ -697,8 +826,26 @@
 		return 1;
 	}
 
-	/* Go check for the CPU being offline. */
-	return rcu_implicit_offline_qs(rdp);
+	/*
+	 * Check for the CPU being offline, but only if the grace period
+	 * is old enough.  We don't need to worry about the CPU changing
+	 * state: If we see it offline even once, it has been through a
+	 * quiescent state.
+	 *
+	 * The reason for insisting that the grace period be at least
+	 * one jiffy old is that CPUs that are not quite online and that
+	 * have just gone offline can still execute RCU read-side critical
+	 * sections.
+	 */
+	if (ULONG_CMP_GE(rdp->rsp->gp_start + 2, jiffies))
+		return 0;  /* Grace period is not old enough. */
+	barrier();
+	if (cpu_is_offline(rdp->cpu)) {
+		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
+		rdp->offline_fqs++;
+		return 1;
+	}
+	return 0;
 }
 
 static int jiffies_till_stall_check(void)
@@ -755,14 +902,15 @@
 	rcu_for_each_leaf_node(rsp, rnp) {
 		raw_spin_lock_irqsave(&rnp->lock, flags);
 		ndetected += rcu_print_task_stall(rnp);
+		if (rnp->qsmask != 0) {
+			for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
+				if (rnp->qsmask & (1UL << cpu)) {
+					print_cpu_stall_info(rsp,
+							     rnp->grplo + cpu);
+					ndetected++;
+				}
+		}
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		if (rnp->qsmask == 0)
-			continue;
-		for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
-			if (rnp->qsmask & (1UL << cpu)) {
-				print_cpu_stall_info(rsp, rnp->grplo + cpu);
-				ndetected++;
-			}
 	}
 
 	/*
@@ -782,11 +930,11 @@
 	else if (!trigger_all_cpu_backtrace())
 		dump_stack();
 
-	/* If so configured, complain about tasks blocking the grace period. */
+	/* Complain about tasks blocking the grace period. */
 
 	rcu_print_detail_task_stall(rsp);
 
-	force_quiescent_state(rsp, 0);  /* Kick them all. */
+	force_quiescent_state(rsp);  /* Kick them all. */
 }
 
 static void print_cpu_stall(struct rcu_state *rsp)
@@ -827,7 +975,8 @@
 	j = ACCESS_ONCE(jiffies);
 	js = ACCESS_ONCE(rsp->jiffies_stall);
 	rnp = rdp->mynode;
-	if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && ULONG_CMP_GE(j, js)) {
+	if (rcu_gp_in_progress(rsp) &&
+	    (ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && ULONG_CMP_GE(j, js)) {
 
 		/* We haven't checked in, so go dump stack. */
 		print_cpu_stall(rsp);
@@ -889,12 +1038,8 @@
 		 */
 		rdp->gpnum = rnp->gpnum;
 		trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpustart");
-		if (rnp->qsmask & rdp->grpmask) {
-			rdp->qs_pending = 1;
-			rdp->passed_quiesce = 0;
-		} else {
-			rdp->qs_pending = 0;
-		}
+		rdp->passed_quiesce = 0;
+		rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
 		zero_cpu_stall_ticks(rdp);
 	}
 }
@@ -974,10 +1119,13 @@
 		 * our behalf. Catch up with this state to avoid noting
 		 * spurious new grace periods.  If another grace period
 		 * has started, then rnp->gpnum will have advanced, so
-		 * we will detect this later on.
+		 * we will detect this later on.  Of course, any quiescent
+		 * states we found for the old GP are now invalid.
 		 */
-		if (ULONG_CMP_LT(rdp->gpnum, rdp->completed))
+		if (ULONG_CMP_LT(rdp->gpnum, rdp->completed)) {
 			rdp->gpnum = rdp->completed;
+			rdp->passed_quiesce = 0;
+		}
 
 		/*
 		 * If RCU does not need a quiescent state from this CPU,
@@ -1021,25 +1169,220 @@
 	/* Prior grace period ended, so advance callbacks for current CPU. */
 	__rcu_process_gp_end(rsp, rnp, rdp);
 
-	/*
-	 * Because this CPU just now started the new grace period, we know
-	 * that all of its callbacks will be covered by this upcoming grace
-	 * period, even the ones that were registered arbitrarily recently.
-	 * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL.
-	 *
-	 * Other CPUs cannot be sure exactly when the grace period started.
-	 * Therefore, their recently registered callbacks must pass through
-	 * an additional RCU_NEXT_READY stage, so that they will be handled
-	 * by the next RCU grace period.
-	 */
-	rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-	rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-
 	/* Set state so that this CPU will detect the next quiescent state. */
 	__note_new_gpnum(rsp, rnp, rdp);
 }
 
 /*
+ * Initialize a new grace period.
+ */
+static int rcu_gp_init(struct rcu_state *rsp)
+{
+	struct rcu_data *rdp;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	raw_spin_lock_irq(&rnp->lock);
+	rsp->gp_flags = 0; /* Clear all flags: New grace period. */
+
+	if (rcu_gp_in_progress(rsp)) {
+		/* Grace period already in progress, don't start another.  */
+		raw_spin_unlock_irq(&rnp->lock);
+		return 0;
+	}
+
+	/* Advance to a new grace period and initialize state. */
+	rsp->gpnum++;
+	trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
+	record_gp_stall_check_time(rsp);
+	raw_spin_unlock_irq(&rnp->lock);
+
+	/* Exclude any concurrent CPU-hotplug operations. */
+	get_online_cpus();
+
+	/*
+	 * Set the quiescent-state-needed bits in all the rcu_node
+	 * structures for all currently online CPUs in breadth-first order,
+	 * starting from the root rcu_node structure, relying on the layout
+	 * of the tree within the rsp->node[] array.  Note that other CPUs
+	 * will access only the leaves of the hierarchy, thus seeing that no
+	 * grace period is in progress, at least until the corresponding
+	 * leaf node has been initialized.  In addition, we have excluded
+	 * CPU-hotplug operations.
+	 *
+	 * The grace period cannot complete until the initialization
+	 * process finishes, because this kthread handles both.
+	 */
+	rcu_for_each_node_breadth_first(rsp, rnp) {
+		raw_spin_lock_irq(&rnp->lock);
+		rdp = this_cpu_ptr(rsp->rda);
+		rcu_preempt_check_blocked_tasks(rnp);
+		rnp->qsmask = rnp->qsmaskinit;
+		rnp->gpnum = rsp->gpnum;
+		WARN_ON_ONCE(rnp->completed != rsp->completed);
+		rnp->completed = rsp->completed;
+		if (rnp == rdp->mynode)
+			rcu_start_gp_per_cpu(rsp, rnp, rdp);
+		rcu_preempt_boost_start_gp(rnp);
+		trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
+					    rnp->level, rnp->grplo,
+					    rnp->grphi, rnp->qsmask);
+		raw_spin_unlock_irq(&rnp->lock);
+#ifdef CONFIG_PROVE_RCU_DELAY
+		if ((random32() % (rcu_num_nodes * 8)) == 0)
+			schedule_timeout_uninterruptible(2);
+#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
+		cond_resched();
+	}
+
+	put_online_cpus();
+	return 1;
+}
+
+/*
+ * Do one round of quiescent-state forcing.
+ */
+int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
+{
+	int fqs_state = fqs_state_in;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	rsp->n_force_qs++;
+	if (fqs_state == RCU_SAVE_DYNTICK) {
+		/* Collect dyntick-idle snapshots. */
+		force_qs_rnp(rsp, dyntick_save_progress_counter);
+		fqs_state = RCU_FORCE_QS;
+	} else {
+		/* Handle dyntick-idle and offline CPUs. */
+		force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
+	}
+	/* Clear flag to prevent immediate re-entry. */
+	if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
+		raw_spin_lock_irq(&rnp->lock);
+		rsp->gp_flags &= ~RCU_GP_FLAG_FQS;
+		raw_spin_unlock_irq(&rnp->lock);
+	}
+	return fqs_state;
+}
+
+/*
+ * Clean up after the old grace period.
+ */
+static void rcu_gp_cleanup(struct rcu_state *rsp)
+{
+	unsigned long gp_duration;
+	struct rcu_data *rdp;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	raw_spin_lock_irq(&rnp->lock);
+	gp_duration = jiffies - rsp->gp_start;
+	if (gp_duration > rsp->gp_max)
+		rsp->gp_max = gp_duration;
+
+	/*
+	 * We know the grace period is complete, but to everyone else
+	 * it appears to still be ongoing.  But it is also the case
+	 * that to everyone else it looks like there is nothing that
+	 * they can do to advance the grace period.  It is therefore
+	 * safe for us to drop the lock in order to mark the grace
+	 * period as completed in all of the rcu_node structures.
+	 */
+	raw_spin_unlock_irq(&rnp->lock);
+
+	/*
+	 * Propagate new ->completed value to rcu_node structures so
+	 * that other CPUs don't have to wait until the start of the next
+	 * grace period to process their callbacks.  This also avoids
+	 * some nasty RCU grace-period initialization races by forcing
+	 * the end of the current grace period to be completely recorded in
+	 * all of the rcu_node structures before the beginning of the next
+	 * grace period is recorded in any of the rcu_node structures.
+	 */
+	rcu_for_each_node_breadth_first(rsp, rnp) {
+		raw_spin_lock_irq(&rnp->lock);
+		rnp->completed = rsp->gpnum;
+		raw_spin_unlock_irq(&rnp->lock);
+		cond_resched();
+	}
+	rnp = rcu_get_root(rsp);
+	raw_spin_lock_irq(&rnp->lock);
+
+	rsp->completed = rsp->gpnum; /* Declare grace period done. */
+	trace_rcu_grace_period(rsp->name, rsp->completed, "end");
+	rsp->fqs_state = RCU_GP_IDLE;
+	rdp = this_cpu_ptr(rsp->rda);
+	if (cpu_needs_another_gp(rsp, rdp))
+		rsp->gp_flags = 1;
+	raw_spin_unlock_irq(&rnp->lock);
+}
+
+/*
+ * Body of kthread that handles grace periods.
+ */
+static int __noreturn rcu_gp_kthread(void *arg)
+{
+	int fqs_state;
+	unsigned long j;
+	int ret;
+	struct rcu_state *rsp = arg;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	for (;;) {
+
+		/* Handle grace-period start. */
+		for (;;) {
+			wait_event_interruptible(rsp->gp_wq,
+						 rsp->gp_flags &
+						 RCU_GP_FLAG_INIT);
+			if ((rsp->gp_flags & RCU_GP_FLAG_INIT) &&
+			    rcu_gp_init(rsp))
+				break;
+			cond_resched();
+			flush_signals(current);
+		}
+
+		/* Handle quiescent-state forcing. */
+		fqs_state = RCU_SAVE_DYNTICK;
+		j = jiffies_till_first_fqs;
+		if (j > HZ) {
+			j = HZ;
+			jiffies_till_first_fqs = HZ;
+		}
+		for (;;) {
+			rsp->jiffies_force_qs = jiffies + j;
+			ret = wait_event_interruptible_timeout(rsp->gp_wq,
+					(rsp->gp_flags & RCU_GP_FLAG_FQS) ||
+					(!ACCESS_ONCE(rnp->qsmask) &&
+					 !rcu_preempt_blocked_readers_cgp(rnp)),
+					j);
+			/* If grace period done, leave loop. */
+			if (!ACCESS_ONCE(rnp->qsmask) &&
+			    !rcu_preempt_blocked_readers_cgp(rnp))
+				break;
+			/* If time for quiescent-state forcing, do it. */
+			if (ret == 0 || (rsp->gp_flags & RCU_GP_FLAG_FQS)) {
+				fqs_state = rcu_gp_fqs(rsp, fqs_state);
+				cond_resched();
+			} else {
+				/* Deal with stray signal. */
+				cond_resched();
+				flush_signals(current);
+			}
+			j = jiffies_till_next_fqs;
+			if (j > HZ) {
+				j = HZ;
+				jiffies_till_next_fqs = HZ;
+			} else if (j < 1) {
+				j = 1;
+				jiffies_till_next_fqs = 1;
+			}
+		}
+
+		/* Handle grace-period end. */
+		rcu_gp_cleanup(rsp);
+	}
+}
+
+/*
  * Start a new RCU grace period if warranted, re-initializing the hierarchy
  * in preparation for detecting the next grace period.  The caller must hold
  * the root node's ->lock, which is released before return.  Hard irqs must
@@ -1056,77 +1399,20 @@
 	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
-	if (!rcu_scheduler_fully_active ||
+	if (!rsp->gp_kthread ||
 	    !cpu_needs_another_gp(rsp, rdp)) {
 		/*
-		 * Either the scheduler hasn't yet spawned the first
-		 * non-idle task or this CPU does not need another
-		 * grace period.  Either way, don't start a new grace
-		 * period.
+		 * Either we have not yet spawned the grace-period
+		 * task or this CPU does not need another grace period.
+		 * Either way, don't start a new grace period.
 		 */
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 		return;
 	}
 
-	if (rsp->fqs_active) {
-		/*
-		 * This CPU needs a grace period, but force_quiescent_state()
-		 * is running.  Tell it to start one on this CPU's behalf.
-		 */
-		rsp->fqs_need_gp = 1;
-		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		return;
-	}
-
-	/* Advance to a new grace period and initialize state. */
-	rsp->gpnum++;
-	trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
-	WARN_ON_ONCE(rsp->fqs_state == RCU_GP_INIT);
-	rsp->fqs_state = RCU_GP_INIT; /* Hold off force_quiescent_state. */
-	rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
-	record_gp_stall_check_time(rsp);
-	raw_spin_unlock(&rnp->lock);  /* leave irqs disabled. */
-
-	/* Exclude any concurrent CPU-hotplug operations. */
-	raw_spin_lock(&rsp->onofflock);  /* irqs already disabled. */
-
-	/*
-	 * Set the quiescent-state-needed bits in all the rcu_node
-	 * structures for all currently online CPUs in breadth-first
-	 * order, starting from the root rcu_node structure.  This
-	 * operation relies on the layout of the hierarchy within the
-	 * rsp->node[] array.  Note that other CPUs will access only
-	 * the leaves of the hierarchy, which still indicate that no
-	 * grace period is in progress, at least until the corresponding
-	 * leaf node has been initialized.  In addition, we have excluded
-	 * CPU-hotplug operations.
-	 *
-	 * Note that the grace period cannot complete until we finish
-	 * the initialization process, as there will be at least one
-	 * qsmask bit set in the root node until that time, namely the
-	 * one corresponding to this CPU, due to the fact that we have
-	 * irqs disabled.
-	 */
-	rcu_for_each_node_breadth_first(rsp, rnp) {
-		raw_spin_lock(&rnp->lock);	/* irqs already disabled. */
-		rcu_preempt_check_blocked_tasks(rnp);
-		rnp->qsmask = rnp->qsmaskinit;
-		rnp->gpnum = rsp->gpnum;
-		rnp->completed = rsp->completed;
-		if (rnp == rdp->mynode)
-			rcu_start_gp_per_cpu(rsp, rnp, rdp);
-		rcu_preempt_boost_start_gp(rnp);
-		trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
-					    rnp->level, rnp->grplo,
-					    rnp->grphi, rnp->qsmask);
-		raw_spin_unlock(&rnp->lock);	/* irqs remain disabled. */
-	}
-
-	rnp = rcu_get_root(rsp);
-	raw_spin_lock(&rnp->lock);		/* irqs already disabled. */
-	rsp->fqs_state = RCU_SIGNAL_INIT; /* force_quiescent_state now OK. */
-	raw_spin_unlock(&rnp->lock);		/* irqs remain disabled. */
-	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+	rsp->gp_flags = RCU_GP_FLAG_INIT;
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	wake_up(&rsp->gp_wq);
 }
 
 /*
@@ -1139,57 +1425,9 @@
 static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
 	__releases(rcu_get_root(rsp)->lock)
 {
-	unsigned long gp_duration;
-	struct rcu_node *rnp = rcu_get_root(rsp);
-	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
-
 	WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
-
-	/*
-	 * Ensure that all grace-period and pre-grace-period activity
-	 * is seen before the assignment to rsp->completed.
-	 */
-	smp_mb(); /* See above block comment. */
-	gp_duration = jiffies - rsp->gp_start;
-	if (gp_duration > rsp->gp_max)
-		rsp->gp_max = gp_duration;
-
-	/*
-	 * We know the grace period is complete, but to everyone else
-	 * it appears to still be ongoing.  But it is also the case
-	 * that to everyone else it looks like there is nothing that
-	 * they can do to advance the grace period.  It is therefore
-	 * safe for us to drop the lock in order to mark the grace
-	 * period as completed in all of the rcu_node structures.
-	 *
-	 * But if this CPU needs another grace period, it will take
-	 * care of this while initializing the next grace period.
-	 * We use RCU_WAIT_TAIL instead of the usual RCU_DONE_TAIL
-	 * because the callbacks have not yet been advanced: Those
-	 * callbacks are waiting on the grace period that just now
-	 * completed.
-	 */
-	if (*rdp->nxttail[RCU_WAIT_TAIL] == NULL) {
-		raw_spin_unlock(&rnp->lock);	 /* irqs remain disabled. */
-
-		/*
-		 * Propagate new ->completed value to rcu_node structures
-		 * so that other CPUs don't have to wait until the start
-		 * of the next grace period to process their callbacks.
-		 */
-		rcu_for_each_node_breadth_first(rsp, rnp) {
-			raw_spin_lock(&rnp->lock); /* irqs already disabled. */
-			rnp->completed = rsp->gpnum;
-			raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
-		}
-		rnp = rcu_get_root(rsp);
-		raw_spin_lock(&rnp->lock); /* irqs already disabled. */
-	}
-
-	rsp->completed = rsp->gpnum;  /* Declare the grace period complete. */
-	trace_rcu_grace_period(rsp->name, rsp->completed, "end");
-	rsp->fqs_state = RCU_GP_IDLE;
-	rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
+	raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
+	wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1258,7 +1496,7 @@
  * based on quiescent states detected in an earlier grace period!
  */
 static void
-rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastgp)
+rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
 {
 	unsigned long flags;
 	unsigned long mask;
@@ -1266,7 +1504,8 @@
 
 	rnp = rdp->mynode;
 	raw_spin_lock_irqsave(&rnp->lock, flags);
-	if (lastgp != rnp->gpnum || rnp->completed == rnp->gpnum) {
+	if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum ||
+	    rnp->completed == rnp->gpnum) {
 
 		/*
 		 * The grace period in which this quiescent state was
@@ -1325,7 +1564,7 @@
 	 * Tell RCU we are done (but rcu_report_qs_rdp() will be the
 	 * judge of that).
 	 */
-	rcu_report_qs_rdp(rdp->cpu, rsp, rdp, rdp->passed_quiesce_gpnum);
+	rcu_report_qs_rdp(rdp->cpu, rsp, rdp);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1390,17 +1629,6 @@
 	int i;
 	struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
-	/*
-	 * If there is an rcu_barrier() operation in progress, then
-	 * only the task doing that operation is permitted to adopt
-	 * callbacks.  To do otherwise breaks rcu_barrier() and friends
-	 * by causing them to fail to wait for the callbacks in the
-	 * orphanage.
-	 */
-	if (rsp->rcu_barrier_in_progress &&
-	    rsp->rcu_barrier_in_progress != current)
-		return;
-
 	/* Do the accounting first. */
 	rdp->qlen_lazy += rsp->qlen_lazy;
 	rdp->qlen += rsp->qlen;
@@ -1455,9 +1683,8 @@
  * The CPU has been completely removed, and some other CPU is reporting
  * this fact from process context.  Do the remainder of the cleanup,
  * including orphaning the outgoing CPU's RCU callbacks, and also
- * adopting them, if there is no _rcu_barrier() instance running.
- * There can only be one CPU hotplug operation at a time, so no other
- * CPU can be attempting to update rcu_cpu_kthread_task.
+ * adopting them.  There can only be one CPU hotplug operation at a time,
+ * so no other CPU can be attempting to update rcu_cpu_kthread_task.
  */
 static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 {
@@ -1468,8 +1695,7 @@
 	struct rcu_node *rnp = rdp->mynode;  /* Outgoing CPU's rdp & rnp. */
 
 	/* Adjust any no-longer-needed kthreads. */
-	rcu_stop_cpu_kthread(cpu);
-	rcu_node_kthread_setaffinity(rnp, -1);
+	rcu_boost_kthread_setaffinity(rnp, -1);
 
 	/* Remove the dead CPU from the bitmasks in the rcu_node hierarchy. */
 
@@ -1515,14 +1741,13 @@
 	WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL,
 		  "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n",
 		  cpu, rdp->qlen, rdp->nxtlist);
+	init_callback_list(rdp);
+	/* Disallow further callbacks on this CPU. */
+	rdp->nxttail[RCU_NEXT_TAIL] = NULL;
 }
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
 
-static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
-{
-}
-
 static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)
 {
 }
@@ -1687,6 +1912,7 @@
 	struct rcu_node *rnp;
 
 	rcu_for_each_leaf_node(rsp, rnp) {
+		cond_resched();
 		mask = 0;
 		raw_spin_lock_irqsave(&rnp->lock, flags);
 		if (!rcu_gp_in_progress(rsp)) {
@@ -1723,72 +1949,39 @@
  * Force quiescent states on reluctant CPUs, and also detect which
  * CPUs are in dyntick-idle mode.
  */
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
+static void force_quiescent_state(struct rcu_state *rsp)
 {
 	unsigned long flags;
-	struct rcu_node *rnp = rcu_get_root(rsp);
+	bool ret;
+	struct rcu_node *rnp;
+	struct rcu_node *rnp_old = NULL;
 
-	trace_rcu_utilization("Start fqs");
-	if (!rcu_gp_in_progress(rsp)) {
-		trace_rcu_utilization("End fqs");
-		return;  /* No grace period in progress, nothing to force. */
+	/* Funnel through hierarchy to reduce memory contention. */
+	rnp = per_cpu_ptr(rsp->rda, raw_smp_processor_id())->mynode;
+	for (; rnp != NULL; rnp = rnp->parent) {
+		ret = (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) ||
+		      !raw_spin_trylock(&rnp->fqslock);
+		if (rnp_old != NULL)
+			raw_spin_unlock(&rnp_old->fqslock);
+		if (ret) {
+			rsp->n_force_qs_lh++;
+			return;
+		}
+		rnp_old = rnp;
 	}
-	if (!raw_spin_trylock_irqsave(&rsp->fqslock, flags)) {
-		rsp->n_force_qs_lh++; /* Inexact, can lose counts.  Tough! */
-		trace_rcu_utilization("End fqs");
-		return;	/* Someone else is already on the job. */
+	/* rnp_old == rcu_get_root(rsp), rnp == NULL. */
+
+	/* Reached the root of the rcu_node tree, acquire lock. */
+	raw_spin_lock_irqsave(&rnp_old->lock, flags);
+	raw_spin_unlock(&rnp_old->fqslock);
+	if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
+		rsp->n_force_qs_lh++;
+		raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
+		return;  /* Someone beat us to it. */
 	}
-	if (relaxed && ULONG_CMP_GE(rsp->jiffies_force_qs, jiffies))
-		goto unlock_fqs_ret; /* no emergency and done recently. */
-	rsp->n_force_qs++;
-	raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-	rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
-	if(!rcu_gp_in_progress(rsp)) {
-		rsp->n_force_qs_ngp++;
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-		goto unlock_fqs_ret;  /* no GP in progress, time updated. */
-	}
-	rsp->fqs_active = 1;
-	switch (rsp->fqs_state) {
-	case RCU_GP_IDLE:
-	case RCU_GP_INIT:
-
-		break; /* grace period idle or initializing, ignore. */
-
-	case RCU_SAVE_DYNTICK:
-
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-
-		/* Record dyntick-idle state. */
-		force_qs_rnp(rsp, dyntick_save_progress_counter);
-		raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-		if (rcu_gp_in_progress(rsp))
-			rsp->fqs_state = RCU_FORCE_QS;
-		break;
-
-	case RCU_FORCE_QS:
-
-		/* Check dyntick-idle state, send IPI to laggarts. */
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-		force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
-
-		/* Leave state in case more forcing is required. */
-
-		raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-		break;
-	}
-	rsp->fqs_active = 0;
-	if (rsp->fqs_need_gp) {
-		raw_spin_unlock(&rsp->fqslock); /* irqs remain disabled */
-		rsp->fqs_need_gp = 0;
-		rcu_start_gp(rsp, flags); /* releases rnp->lock */
-		trace_rcu_utilization("End fqs");
-		return;
-	}
-	raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-unlock_fqs_ret:
-	raw_spin_unlock_irqrestore(&rsp->fqslock, flags);
-	trace_rcu_utilization("End fqs");
+	rsp->gp_flags |= RCU_GP_FLAG_FQS;
+	raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
+	wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1805,13 +1998,6 @@
 	WARN_ON_ONCE(rdp->beenonline == 0);
 
 	/*
-	 * If an RCU GP has gone long enough, go check for dyntick
-	 * idle CPUs and, if needed, send resched IPIs.
-	 */
-	if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-		force_quiescent_state(rsp, 1);
-
-	/*
 	 * Advance callbacks in response to end of earlier grace
 	 * period that some other CPU ended.
 	 */
@@ -1838,6 +2024,8 @@
 {
 	struct rcu_state *rsp;
 
+	if (cpu_is_offline(smp_processor_id()))
+		return;
 	trace_rcu_utilization("Start RCU core");
 	for_each_rcu_flavor(rsp)
 		__rcu_process_callbacks(rsp);
@@ -1909,12 +2097,11 @@
 			rdp->blimit = LONG_MAX;
 			if (rsp->n_force_qs == rdp->n_force_qs_snap &&
 			    *rdp->nxttail[RCU_DONE_TAIL] != head)
-				force_quiescent_state(rsp, 0);
+				force_quiescent_state(rsp);
 			rdp->n_force_qs_snap = rsp->n_force_qs;
 			rdp->qlen_last_fqs_check = rdp->qlen;
 		}
-	} else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-		force_quiescent_state(rsp, 1);
+	}
 }
 
 static void
@@ -1929,8 +2116,6 @@
 	head->func = func;
 	head->next = NULL;
 
-	smp_mb(); /* Ensure RCU update seen before callback registry. */
-
 	/*
 	 * Opportunistically note grace-period endings and beginnings.
 	 * Note that we might see a beginning right after we see an
@@ -1941,6 +2126,12 @@
 	rdp = this_cpu_ptr(rsp->rda);
 
 	/* Add the callback to our list. */
+	if (unlikely(rdp->nxttail[RCU_NEXT_TAIL] == NULL)) {
+		/* _call_rcu() is illegal on offline CPU; leak the callback. */
+		WARN_ON_ONCE(1);
+		local_irq_restore(flags);
+		return;
+	}
 	ACCESS_ONCE(rdp->qlen)++;
 	if (lazy)
 		rdp->qlen_lazy++;
@@ -2195,17 +2386,7 @@
 	/* Is the RCU core waiting for a quiescent state from this CPU? */
 	if (rcu_scheduler_fully_active &&
 	    rdp->qs_pending && !rdp->passed_quiesce) {
-
-		/*
-		 * If force_quiescent_state() coming soon and this CPU
-		 * needs a quiescent state, and this is either RCU-sched
-		 * or RCU-bh, force a local reschedule.
-		 */
 		rdp->n_rp_qs_pending++;
-		if (!rdp->preemptible &&
-		    ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs) - 1,
-				 jiffies))
-			set_need_resched();
 	} else if (rdp->qs_pending && rdp->passed_quiesce) {
 		rdp->n_rp_report_qs++;
 		return 1;
@@ -2235,13 +2416,6 @@
 		return 1;
 	}
 
-	/* Has an RCU GP gone long enough to send resched IPIs &c? */
-	if (rcu_gp_in_progress(rsp) &&
-	    ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) {
-		rdp->n_rp_need_fqs++;
-		return 1;
-	}
-
 	/* nothing to do */
 	rdp->n_rp_need_nothing++;
 	return 0;
@@ -2326,13 +2500,10 @@
 static void _rcu_barrier(struct rcu_state *rsp)
 {
 	int cpu;
-	unsigned long flags;
 	struct rcu_data *rdp;
-	struct rcu_data rd;
 	unsigned long snap = ACCESS_ONCE(rsp->n_barrier_done);
 	unsigned long snap_done;
 
-	init_rcu_head_on_stack(&rd.barrier_head);
 	_rcu_barrier_trace(rsp, "Begin", -1, snap);
 
 	/* Take mutex to serialize concurrent rcu_barrier() requests. */
@@ -2372,70 +2543,30 @@
 	/*
 	 * Initialize the count to one rather than to zero in order to
 	 * avoid a too-soon return to zero in case of a short grace period
-	 * (or preemption of this task).  Also flag this task as doing
-	 * an rcu_barrier().  This will prevent anyone else from adopting
-	 * orphaned callbacks, which could cause otherwise failure if a
-	 * CPU went offline and quickly came back online.  To see this,
-	 * consider the following sequence of events:
-	 *
-	 * 1.	We cause CPU 0 to post an rcu_barrier_callback() callback.
-	 * 2.	CPU 1 goes offline, orphaning its callbacks.
-	 * 3.	CPU 0 adopts CPU 1's orphaned callbacks.
-	 * 4.	CPU 1 comes back online.
-	 * 5.	We cause CPU 1 to post an rcu_barrier_callback() callback.
-	 * 6.	Both rcu_barrier_callback() callbacks are invoked, awakening
-	 *	us -- but before CPU 1's orphaned callbacks are invoked!!!
+	 * (or preemption of this task).  Exclude CPU-hotplug operations
+	 * to ensure that no offline CPU has callbacks queued.
 	 */
 	init_completion(&rsp->barrier_completion);
 	atomic_set(&rsp->barrier_cpu_count, 1);
-	raw_spin_lock_irqsave(&rsp->onofflock, flags);
-	rsp->rcu_barrier_in_progress = current;
-	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+	get_online_cpus();
 
 	/*
-	 * Force every CPU with callbacks to register a new callback
-	 * that will tell us when all the preceding callbacks have
-	 * been invoked.  If an offline CPU has callbacks, wait for
-	 * it to either come back online or to finish orphaning those
-	 * callbacks.
+	 * Force each CPU with callbacks to register a new callback.
+	 * When that callback is invoked, we will know that all of the
+	 * corresponding CPU's preceding callbacks have been invoked.
 	 */
-	for_each_possible_cpu(cpu) {
-		preempt_disable();
+	for_each_online_cpu(cpu) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
-		if (cpu_is_offline(cpu)) {
-			_rcu_barrier_trace(rsp, "Offline", cpu,
-					   rsp->n_barrier_done);
-			preempt_enable();
-			while (cpu_is_offline(cpu) && ACCESS_ONCE(rdp->qlen))
-				schedule_timeout_interruptible(1);
-		} else if (ACCESS_ONCE(rdp->qlen)) {
+		if (ACCESS_ONCE(rdp->qlen)) {
 			_rcu_barrier_trace(rsp, "OnlineQ", cpu,
 					   rsp->n_barrier_done);
 			smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
-			preempt_enable();
 		} else {
 			_rcu_barrier_trace(rsp, "OnlineNQ", cpu,
 					   rsp->n_barrier_done);
-			preempt_enable();
 		}
 	}
-
-	/*
-	 * Now that all online CPUs have rcu_barrier_callback() callbacks
-	 * posted, we can adopt all of the orphaned callbacks and place
-	 * an rcu_barrier_callback() callback after them.  When that is done,
-	 * we are guaranteed to have an rcu_barrier_callback() callback
-	 * following every callback that could possibly have been
-	 * registered before _rcu_barrier() was called.
-	 */
-	raw_spin_lock_irqsave(&rsp->onofflock, flags);
-	rcu_adopt_orphan_cbs(rsp);
-	rsp->rcu_barrier_in_progress = NULL;
-	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
-	atomic_inc(&rsp->barrier_cpu_count);
-	smp_mb__after_atomic_inc(); /* Ensure atomic_inc() before callback. */
-	rd.rsp = rsp;
-	rsp->call(&rd.barrier_head, rcu_barrier_callback);
+	put_online_cpus();
 
 	/*
 	 * Now that we have an rcu_barrier_callback() callback on each
@@ -2456,8 +2587,6 @@
 
 	/* Other rcu_barrier() invocations can now safely proceed. */
 	mutex_unlock(&rsp->barrier_mutex);
-
-	destroy_rcu_head_on_stack(&rd.barrier_head);
 }
 
 /**
@@ -2497,6 +2626,9 @@
 	rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
 	WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
 	WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
+#ifdef CONFIG_RCU_USER_QS
+	WARN_ON_ONCE(rdp->dynticks->in_user);
+#endif
 	rdp->cpu = cpu;
 	rdp->rsp = rsp;
 	raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -2523,6 +2655,7 @@
 	rdp->qlen_last_fqs_check = 0;
 	rdp->n_force_qs_snap = rsp->n_force_qs;
 	rdp->blimit = blimit;
+	init_callback_list(rdp);  /* Re-enable callbacks on this CPU. */
 	rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 	atomic_set(&rdp->dynticks->dynticks,
 		   (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
@@ -2555,7 +2688,6 @@
 			rdp->completed = rnp->completed;
 			rdp->passed_quiesce = 0;
 			rdp->qs_pending = 0;
-			rdp->passed_quiesce_gpnum = rnp->gpnum - 1;
 			trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuonl");
 		}
 		raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
@@ -2594,12 +2726,10 @@
 		break;
 	case CPU_ONLINE:
 	case CPU_DOWN_FAILED:
-		rcu_node_kthread_setaffinity(rnp, -1);
-		rcu_cpu_kthread_setrt(cpu, 1);
+		rcu_boost_kthread_setaffinity(rnp, -1);
 		break;
 	case CPU_DOWN_PREPARE:
-		rcu_node_kthread_setaffinity(rnp, cpu);
-		rcu_cpu_kthread_setrt(cpu, 0);
+		rcu_boost_kthread_setaffinity(rnp, cpu);
 		break;
 	case CPU_DYING:
 	case CPU_DYING_FROZEN:
@@ -2627,6 +2757,28 @@
 }
 
 /*
+ * Spawn the kthread that handles this RCU flavor's grace periods.
+ */
+static int __init rcu_spawn_gp_kthread(void)
+{
+	unsigned long flags;
+	struct rcu_node *rnp;
+	struct rcu_state *rsp;
+	struct task_struct *t;
+
+	for_each_rcu_flavor(rsp) {
+		t = kthread_run(rcu_gp_kthread, rsp, rsp->name);
+		BUG_ON(IS_ERR(t));
+		rnp = rcu_get_root(rsp);
+		raw_spin_lock_irqsave(&rnp->lock, flags);
+		rsp->gp_kthread = t;
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	}
+	return 0;
+}
+early_initcall(rcu_spawn_gp_kthread);
+
+/*
  * This function is invoked towards the end of the scheduler's initialization
  * process.  Before this is called, the idle task might contain
  * RCU read-side critical sections (during which time, this idle
@@ -2661,7 +2813,7 @@
 	int cprv;
 	int i;
 
-	cprv = NR_CPUS;
+	cprv = nr_cpu_ids;
 	for (i = rcu_num_lvls - 1; i >= 0; i--) {
 		ccur = rsp->levelcnt[i];
 		rsp->levelspread[i] = (cprv + ccur - 1) / ccur;
@@ -2676,10 +2828,14 @@
 static void __init rcu_init_one(struct rcu_state *rsp,
 		struct rcu_data __percpu *rda)
 {
-	static char *buf[] = { "rcu_node_level_0",
-			       "rcu_node_level_1",
-			       "rcu_node_level_2",
-			       "rcu_node_level_3" };  /* Match MAX_RCU_LVLS */
+	static char *buf[] = { "rcu_node_0",
+			       "rcu_node_1",
+			       "rcu_node_2",
+			       "rcu_node_3" };  /* Match MAX_RCU_LVLS */
+	static char *fqs[] = { "rcu_node_fqs_0",
+			       "rcu_node_fqs_1",
+			       "rcu_node_fqs_2",
+			       "rcu_node_fqs_3" };  /* Match MAX_RCU_LVLS */
 	int cpustride = 1;
 	int i;
 	int j;
@@ -2704,7 +2860,11 @@
 			raw_spin_lock_init(&rnp->lock);
 			lockdep_set_class_and_name(&rnp->lock,
 						   &rcu_node_class[i], buf[i]);
-			rnp->gpnum = 0;
+			raw_spin_lock_init(&rnp->fqslock);
+			lockdep_set_class_and_name(&rnp->fqslock,
+						   &rcu_fqs_class[i], fqs[i]);
+			rnp->gpnum = rsp->gpnum;
+			rnp->completed = rsp->completed;
 			rnp->qsmask = 0;
 			rnp->qsmaskinit = 0;
 			rnp->grplo = j * cpustride;
@@ -2727,6 +2887,7 @@
 	}
 
 	rsp->rda = rda;
+	init_waitqueue_head(&rsp->gp_wq);
 	rnp = rsp->level[rcu_num_lvls - 1];
 	for_each_possible_cpu(i) {
 		while (i > rnp->grphi)
@@ -2750,7 +2911,8 @@
 	int rcu_capacity[MAX_RCU_LVLS + 1];
 
 	/* If the compile-time values are accurate, just leave. */
-	if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF)
+	if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF &&
+	    nr_cpu_ids == NR_CPUS)
 		return;
 
 	/*
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 4d29169..5faf05d 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -102,6 +102,10 @@
 				    /* idle-period nonlazy_posted snapshot. */
 	int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
 #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
+#ifdef CONFIG_RCU_USER_QS
+	bool ignore_user_qs;	    /* Treat userspace as extended QS or not */
+	bool in_user;		    /* Is the CPU in userland from RCU POV? */
+#endif
 };
 
 /* RCU's kthread states for tracing. */
@@ -196,12 +200,7 @@
 				/* Refused to boost: not sure why, though. */
 				/*  This can happen due to race conditions. */
 #endif /* #ifdef CONFIG_RCU_BOOST */
-	struct task_struct *node_kthread_task;
-				/* kthread that takes care of this rcu_node */
-				/*  structure, for example, awakening the */
-				/*  per-CPU kthreads as needed. */
-	unsigned int node_kthread_status;
-				/* State of node_kthread_task for tracing. */
+	raw_spinlock_t fqslock ____cacheline_internodealigned_in_smp;
 } ____cacheline_internodealigned_in_smp;
 
 /*
@@ -245,8 +244,6 @@
 					/*  in order to detect GP end. */
 	unsigned long	gpnum;		/* Highest gp number that this CPU */
 					/*  is aware of having started. */
-	unsigned long	passed_quiesce_gpnum;
-					/* gpnum at time of quiescent state. */
 	bool		passed_quiesce;	/* User-mode/idle loop etc. */
 	bool		qs_pending;	/* Core waits for quiesc state. */
 	bool		beenonline;	/* CPU online at least once. */
@@ -312,11 +309,13 @@
 	unsigned long n_rp_cpu_needs_gp;
 	unsigned long n_rp_gp_completed;
 	unsigned long n_rp_gp_started;
-	unsigned long n_rp_need_fqs;
 	unsigned long n_rp_need_nothing;
 
-	/* 6) _rcu_barrier() callback. */
+	/* 6) _rcu_barrier() and OOM callbacks. */
 	struct rcu_head barrier_head;
+#ifdef CONFIG_RCU_FAST_NO_HZ
+	struct rcu_head oom_head;
+#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
 
 	int cpu;
 	struct rcu_state *rsp;
@@ -375,20 +374,17 @@
 
 	u8	fqs_state ____cacheline_internodealigned_in_smp;
 						/* Force QS state. */
-	u8	fqs_active;			/* force_quiescent_state() */
-						/*  is running. */
-	u8	fqs_need_gp;			/* A CPU was prevented from */
-						/*  starting a new grace */
-						/*  period because */
-						/*  force_quiescent_state() */
-						/*  was running. */
 	u8	boost;				/* Subject to priority boost. */
 	unsigned long gpnum;			/* Current gp number. */
 	unsigned long completed;		/* # of last completed gp. */
+	struct task_struct *gp_kthread;		/* Task for grace periods. */
+	wait_queue_head_t gp_wq;		/* Where GP task waits. */
+	int gp_flags;				/* Commands for GP task. */
 
 	/* End of fields guarded by root rcu_node's lock. */
 
-	raw_spinlock_t onofflock;		/* exclude on/offline and */
+	raw_spinlock_t onofflock ____cacheline_internodealigned_in_smp;
+						/* exclude on/offline and */
 						/*  starting new GP. */
 	struct rcu_head *orphan_nxtlist;	/* Orphaned callbacks that */
 						/*  need a grace period. */
@@ -398,16 +394,11 @@
 	struct rcu_head **orphan_donetail;	/* Tail of above. */
 	long qlen_lazy;				/* Number of lazy callbacks. */
 	long qlen;				/* Total number of callbacks. */
-	struct task_struct *rcu_barrier_in_progress;
-						/* Task doing rcu_barrier(), */
-						/*  or NULL if no barrier. */
 	struct mutex barrier_mutex;		/* Guards barrier fields. */
 	atomic_t barrier_cpu_count;		/* # CPUs waiting on. */
 	struct completion barrier_completion;	/* Wake at barrier end. */
 	unsigned long n_barrier_done;		/* ++ at start and end of */
 						/*  _rcu_barrier(). */
-	raw_spinlock_t fqslock;			/* Only one task forcing */
-						/*  quiescent states. */
 	unsigned long jiffies_force_qs;		/* Time at which to invoke */
 						/*  force_quiescent_state(). */
 	unsigned long n_force_qs;		/* Number of calls to */
@@ -426,6 +417,10 @@
 	struct list_head flavors;		/* List of RCU flavors. */
 };
 
+/* Values for rcu_state structure's gp_flags field. */
+#define RCU_GP_FLAG_INIT 0x1	/* Need grace-period initialization. */
+#define RCU_GP_FLAG_FQS  0x2	/* Need grace-period quiescent-state forcing. */
+
 extern struct list_head rcu_struct_flavors;
 #define for_each_rcu_flavor(rsp) \
 	list_for_each_entry((rsp), &rcu_struct_flavors, flavors)
@@ -468,7 +463,6 @@
 #ifdef CONFIG_HOTPLUG_CPU
 static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
 				      unsigned long flags);
-static void rcu_stop_cpu_kthread(int cpu);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static int rcu_print_task_stall(struct rcu_node *rnp);
@@ -491,15 +485,9 @@
 static bool rcu_is_callbacks_kthread(void);
 #ifdef CONFIG_RCU_BOOST
 static void rcu_preempt_do_callbacks(void);
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
-					  cpumask_var_t cm);
 static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
-						 struct rcu_node *rnp,
-						 int rnp_index);
-static void invoke_rcu_node_kthread(struct rcu_node *rnp);
-static void rcu_yield(void (*f)(unsigned long), unsigned long arg);
+						 struct rcu_node *rnp);
 #endif /* #ifdef CONFIG_RCU_BOOST */
-static void rcu_cpu_kthread_setrt(int cpu, int to_rt);
 static void __cpuinit rcu_prepare_kthreads(int cpu);
 static void rcu_prepare_for_idle_init(int cpu);
 static void rcu_cleanup_after_idle(int cpu);
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 7f3244c..f921154 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -25,6 +25,8 @@
  */
 
 #include <linux/delay.h>
+#include <linux/oom.h>
+#include <linux/smpboot.h>
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -118,7 +120,7 @@
  */
 void rcu_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_preempt_state, 0);
+	force_quiescent_state(&rcu_preempt_state);
 }
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
@@ -136,8 +138,6 @@
 {
 	struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
 
-	rdp->passed_quiesce_gpnum = rdp->gpnum;
-	barrier();
 	if (rdp->passed_quiesce == 0)
 		trace_rcu_grace_period("rcu_preempt", rdp->gpnum, "cpuqs");
 	rdp->passed_quiesce = 1;
@@ -422,9 +422,11 @@
 	unsigned long flags;
 	struct task_struct *t;
 
-	if (!rcu_preempt_blocked_readers_cgp(rnp))
-		return;
 	raw_spin_lock_irqsave(&rnp->lock, flags);
+	if (!rcu_preempt_blocked_readers_cgp(rnp)) {
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+		return;
+	}
 	t = list_entry(rnp->gp_tasks,
 		       struct task_struct, rcu_node_entry);
 	list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry)
@@ -584,17 +586,23 @@
 		raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
 	}
 
+	rnp->gp_tasks = NULL;
+	rnp->exp_tasks = NULL;
 #ifdef CONFIG_RCU_BOOST
-	/* In case root is being boosted and leaf is not. */
+	rnp->boost_tasks = NULL;
+	/*
+	 * In case root is being boosted and leaf was not.  Make sure
+	 * that we boost the tasks blocking the current grace period
+	 * in this case.
+	 */
 	raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
 	if (rnp_root->boost_tasks != NULL &&
-	    rnp_root->boost_tasks != rnp_root->gp_tasks)
+	    rnp_root->boost_tasks != rnp_root->gp_tasks &&
+	    rnp_root->boost_tasks != rnp_root->exp_tasks)
 		rnp_root->boost_tasks = rnp_root->gp_tasks;
 	raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
 #endif /* #ifdef CONFIG_RCU_BOOST */
 
-	rnp->gp_tasks = NULL;
-	rnp->exp_tasks = NULL;
 	return retval;
 }
 
@@ -676,7 +684,7 @@
 EXPORT_SYMBOL_GPL(synchronize_rcu);
 
 static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq);
-static long sync_rcu_preempt_exp_count;
+static unsigned long sync_rcu_preempt_exp_count;
 static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
 
 /*
@@ -791,7 +799,7 @@
 	unsigned long flags;
 	struct rcu_node *rnp;
 	struct rcu_state *rsp = &rcu_preempt_state;
-	long snap;
+	unsigned long snap;
 	int trycount = 0;
 
 	smp_mb(); /* Caller's modifications seen first by other CPUs. */
@@ -799,33 +807,47 @@
 	smp_mb(); /* Above access cannot bleed into critical section. */
 
 	/*
+	 * Block CPU-hotplug operations.  This means that any CPU-hotplug
+	 * operation that finds an rcu_node structure with tasks in the
+	 * process of being boosted will know that all tasks blocking
+	 * this expedited grace period will already be in the process of
+	 * being boosted.  This simplifies the process of moving tasks
+	 * from leaf to root rcu_node structures.
+	 */
+	get_online_cpus();
+
+	/*
 	 * Acquire lock, falling back to synchronize_rcu() if too many
 	 * lock-acquisition failures.  Of course, if someone does the
 	 * expedited grace period for us, just leave.
 	 */
 	while (!mutex_trylock(&sync_rcu_preempt_exp_mutex)) {
+		if (ULONG_CMP_LT(snap,
+		    ACCESS_ONCE(sync_rcu_preempt_exp_count))) {
+			put_online_cpus();
+			goto mb_ret; /* Others did our work for us. */
+		}
 		if (trycount++ < 10) {
 			udelay(trycount * num_online_cpus());
 		} else {
+			put_online_cpus();
 			synchronize_rcu();
 			return;
 		}
-		if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0)
-			goto mb_ret; /* Others did our work for us. */
 	}
-	if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0)
+	if (ULONG_CMP_LT(snap, ACCESS_ONCE(sync_rcu_preempt_exp_count))) {
+		put_online_cpus();
 		goto unlock_mb_ret; /* Others did our work for us. */
+	}
 
 	/* force all RCU readers onto ->blkd_tasks lists. */
 	synchronize_sched_expedited();
 
-	raw_spin_lock_irqsave(&rsp->onofflock, flags);
-
 	/* Initialize ->expmask for all non-leaf rcu_node structures. */
 	rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) {
-		raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+		raw_spin_lock_irqsave(&rnp->lock, flags);
 		rnp->expmask = rnp->qsmaskinit;
-		raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 	}
 
 	/* Snapshot current state of ->blkd_tasks lists. */
@@ -834,7 +856,7 @@
 	if (NUM_RCU_NODES > 1)
 		sync_rcu_preempt_exp_init(rsp, rcu_get_root(rsp));
 
-	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+	put_online_cpus();
 
 	/* Wait for snapshotted ->blkd_tasks lists to drain. */
 	rnp = rcu_get_root(rsp);
@@ -1069,6 +1091,16 @@
 
 #endif /* #else #ifdef CONFIG_RCU_TRACE */
 
+static void rcu_wake_cond(struct task_struct *t, int status)
+{
+	/*
+	 * If the thread is yielding, only wake it when this
+	 * is invoked from idle
+	 */
+	if (status != RCU_KTHREAD_YIELDING || is_idle_task(current))
+		wake_up_process(t);
+}
+
 /*
  * Carry out RCU priority boosting on the task indicated by ->exp_tasks
  * or ->boost_tasks, advancing the pointer to the next task in the
@@ -1141,17 +1173,6 @@
 }
 
 /*
- * Timer handler to initiate waking up of boost kthreads that
- * have yielded the CPU due to excessive numbers of tasks to
- * boost.  We wake up the per-rcu_node kthread, which in turn
- * will wake up the booster kthread.
- */
-static void rcu_boost_kthread_timer(unsigned long arg)
-{
-	invoke_rcu_node_kthread((struct rcu_node *)arg);
-}
-
-/*
  * Priority-boosting kthread.  One per leaf rcu_node and one for the
  * root rcu_node.
  */
@@ -1174,8 +1195,9 @@
 		else
 			spincnt = 0;
 		if (spincnt > 10) {
+			rnp->boost_kthread_status = RCU_KTHREAD_YIELDING;
 			trace_rcu_utilization("End boost kthread@rcu_yield");
-			rcu_yield(rcu_boost_kthread_timer, (unsigned long)rnp);
+			schedule_timeout_interruptible(2);
 			trace_rcu_utilization("Start boost kthread@rcu_yield");
 			spincnt = 0;
 		}
@@ -1191,9 +1213,9 @@
  * kthread to start boosting them.  If there is an expedited grace
  * period in progress, it is always time to boost.
  *
- * The caller must hold rnp->lock, which this function releases,
- * but irqs remain disabled.  The ->boost_kthread_task is immortal,
- * so we don't need to worry about it going away.
+ * The caller must hold rnp->lock, which this function releases.
+ * The ->boost_kthread_task is immortal, so we don't need to worry
+ * about it going away.
  */
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
 {
@@ -1213,8 +1235,8 @@
 			rnp->boost_tasks = rnp->gp_tasks;
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 		t = rnp->boost_kthread_task;
-		if (t != NULL)
-			wake_up_process(t);
+		if (t)
+			rcu_wake_cond(t, rnp->boost_kthread_status);
 	} else {
 		rcu_initiate_boost_trace(rnp);
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -1231,8 +1253,10 @@
 	local_irq_save(flags);
 	__this_cpu_write(rcu_cpu_has_work, 1);
 	if (__this_cpu_read(rcu_cpu_kthread_task) != NULL &&
-	    current != __this_cpu_read(rcu_cpu_kthread_task))
-		wake_up_process(__this_cpu_read(rcu_cpu_kthread_task));
+	    current != __this_cpu_read(rcu_cpu_kthread_task)) {
+		rcu_wake_cond(__this_cpu_read(rcu_cpu_kthread_task),
+			      __this_cpu_read(rcu_cpu_kthread_status));
+	}
 	local_irq_restore(flags);
 }
 
@@ -1245,21 +1269,6 @@
 	return __get_cpu_var(rcu_cpu_kthread_task) == current;
 }
 
-/*
- * Set the affinity of the boost kthread.  The CPU-hotplug locks are
- * held, so no one should be messing with the existence of the boost
- * kthread.
- */
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
-					  cpumask_var_t cm)
-{
-	struct task_struct *t;
-
-	t = rnp->boost_kthread_task;
-	if (t != NULL)
-		set_cpus_allowed_ptr(rnp->boost_kthread_task, cm);
-}
-
 #define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
 
 /*
@@ -1276,15 +1285,19 @@
  * Returns zero if all is well, a negated errno otherwise.
  */
 static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
-						 struct rcu_node *rnp,
-						 int rnp_index)
+						 struct rcu_node *rnp)
 {
+	int rnp_index = rnp - &rsp->node[0];
 	unsigned long flags;
 	struct sched_param sp;
 	struct task_struct *t;
 
 	if (&rcu_preempt_state != rsp)
 		return 0;
+
+	if (!rcu_scheduler_fully_active || rnp->qsmaskinit == 0)
+		return 0;
+
 	rsp->boost = 1;
 	if (rnp->boost_kthread_task != NULL)
 		return 0;
@@ -1301,25 +1314,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-/*
- * Stop the RCU's per-CPU kthread when its CPU goes offline,.
- */
-static void rcu_stop_cpu_kthread(int cpu)
-{
-	struct task_struct *t;
-
-	/* Stop the CPU's kthread. */
-	t = per_cpu(rcu_cpu_kthread_task, cpu);
-	if (t != NULL) {
-		per_cpu(rcu_cpu_kthread_task, cpu) = NULL;
-		kthread_stop(t);
-	}
-}
-
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
 static void rcu_kthread_do_work(void)
 {
 	rcu_do_batch(&rcu_sched_state, &__get_cpu_var(rcu_sched_data));
@@ -1327,112 +1321,22 @@
 	rcu_preempt_do_callbacks();
 }
 
-/*
- * Wake up the specified per-rcu_node-structure kthread.
- * Because the per-rcu_node kthreads are immortal, we don't need
- * to do anything to keep them alive.
- */
-static void invoke_rcu_node_kthread(struct rcu_node *rnp)
-{
-	struct task_struct *t;
-
-	t = rnp->node_kthread_task;
-	if (t != NULL)
-		wake_up_process(t);
-}
-
-/*
- * Set the specified CPU's kthread to run RT or not, as specified by
- * the to_rt argument.  The CPU-hotplug locks are held, so the task
- * is not going away.
- */
-static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
-{
-	int policy;
-	struct sched_param sp;
-	struct task_struct *t;
-
-	t = per_cpu(rcu_cpu_kthread_task, cpu);
-	if (t == NULL)
-		return;
-	if (to_rt) {
-		policy = SCHED_FIFO;
-		sp.sched_priority = RCU_KTHREAD_PRIO;
-	} else {
-		policy = SCHED_NORMAL;
-		sp.sched_priority = 0;
-	}
-	sched_setscheduler_nocheck(t, policy, &sp);
-}
-
-/*
- * Timer handler to initiate the waking up of per-CPU kthreads that
- * have yielded the CPU due to excess numbers of RCU callbacks.
- * We wake up the per-rcu_node kthread, which in turn will wake up
- * the booster kthread.
- */
-static void rcu_cpu_kthread_timer(unsigned long arg)
-{
-	struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, arg);
-	struct rcu_node *rnp = rdp->mynode;
-
-	atomic_or(rdp->grpmask, &rnp->wakemask);
-	invoke_rcu_node_kthread(rnp);
-}
-
-/*
- * Drop to non-real-time priority and yield, but only after posting a
- * timer that will cause us to regain our real-time priority if we
- * remain preempted.  Either way, we restore our real-time priority
- * before returning.
- */
-static void rcu_yield(void (*f)(unsigned long), unsigned long arg)
+static void rcu_cpu_kthread_setup(unsigned int cpu)
 {
 	struct sched_param sp;
-	struct timer_list yield_timer;
-	int prio = current->rt_priority;
 
-	setup_timer_on_stack(&yield_timer, f, arg);
-	mod_timer(&yield_timer, jiffies + 2);
-	sp.sched_priority = 0;
-	sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp);
-	set_user_nice(current, 19);
-	schedule();
-	set_user_nice(current, 0);
-	sp.sched_priority = prio;
+	sp.sched_priority = RCU_KTHREAD_PRIO;
 	sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
-	del_timer(&yield_timer);
 }
 
-/*
- * Handle cases where the rcu_cpu_kthread() ends up on the wrong CPU.
- * This can happen while the corresponding CPU is either coming online
- * or going offline.  We cannot wait until the CPU is fully online
- * before starting the kthread, because the various notifier functions
- * can wait for RCU grace periods.  So we park rcu_cpu_kthread() until
- * the corresponding CPU is online.
- *
- * Return 1 if the kthread needs to stop, 0 otherwise.
- *
- * Caller must disable bh.  This function can momentarily enable it.
- */
-static int rcu_cpu_kthread_should_stop(int cpu)
+static void rcu_cpu_kthread_park(unsigned int cpu)
 {
-	while (cpu_is_offline(cpu) ||
-	       !cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)) ||
-	       smp_processor_id() != cpu) {
-		if (kthread_should_stop())
-			return 1;
-		per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
-		per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id();
-		local_bh_enable();
-		schedule_timeout_uninterruptible(1);
-		if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)))
-			set_cpus_allowed_ptr(current, cpumask_of(cpu));
-		local_bh_disable();
-	}
-	per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
-	return 0;
+	per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
+}
+
+static int rcu_cpu_kthread_should_run(unsigned int cpu)
+{
+	return __get_cpu_var(rcu_cpu_has_work);
 }
 
 /*
@@ -1440,138 +1344,35 @@
  * RCU softirq used in flavors and configurations of RCU that do not
  * support RCU priority boosting.
  */
-static int rcu_cpu_kthread(void *arg)
+static void rcu_cpu_kthread(unsigned int cpu)
 {
-	int cpu = (int)(long)arg;
-	unsigned long flags;
-	int spincnt = 0;
-	unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu);
-	char work;
-	char *workp = &per_cpu(rcu_cpu_has_work, cpu);
+	unsigned int *statusp = &__get_cpu_var(rcu_cpu_kthread_status);
+	char work, *workp = &__get_cpu_var(rcu_cpu_has_work);
+	int spincnt;
 
-	trace_rcu_utilization("Start CPU kthread@init");
-	for (;;) {
-		*statusp = RCU_KTHREAD_WAITING;
-		trace_rcu_utilization("End CPU kthread@rcu_wait");
-		rcu_wait(*workp != 0 || kthread_should_stop());
+	for (spincnt = 0; spincnt < 10; spincnt++) {
 		trace_rcu_utilization("Start CPU kthread@rcu_wait");
 		local_bh_disable();
-		if (rcu_cpu_kthread_should_stop(cpu)) {
-			local_bh_enable();
-			break;
-		}
 		*statusp = RCU_KTHREAD_RUNNING;
-		per_cpu(rcu_cpu_kthread_loops, cpu)++;
-		local_irq_save(flags);
+		this_cpu_inc(rcu_cpu_kthread_loops);
+		local_irq_disable();
 		work = *workp;
 		*workp = 0;
-		local_irq_restore(flags);
+		local_irq_enable();
 		if (work)
 			rcu_kthread_do_work();
 		local_bh_enable();
-		if (*workp != 0)
-			spincnt++;
-		else
-			spincnt = 0;
-		if (spincnt > 10) {
-			*statusp = RCU_KTHREAD_YIELDING;
-			trace_rcu_utilization("End CPU kthread@rcu_yield");
-			rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu);
-			trace_rcu_utilization("Start CPU kthread@rcu_yield");
-			spincnt = 0;
+		if (*workp == 0) {
+			trace_rcu_utilization("End CPU kthread@rcu_wait");
+			*statusp = RCU_KTHREAD_WAITING;
+			return;
 		}
 	}
-	*statusp = RCU_KTHREAD_STOPPED;
-	trace_rcu_utilization("End CPU kthread@term");
-	return 0;
-}
-
-/*
- * Spawn a per-CPU kthread, setting up affinity and priority.
- * Because the CPU hotplug lock is held, no other CPU will be attempting
- * to manipulate rcu_cpu_kthread_task.  There might be another CPU
- * attempting to access it during boot, but the locking in kthread_bind()
- * will enforce sufficient ordering.
- *
- * Please note that we cannot simply refuse to wake up the per-CPU
- * kthread because kthreads are created in TASK_UNINTERRUPTIBLE state,
- * which can result in softlockup complaints if the task ends up being
- * idle for more than a couple of minutes.
- *
- * However, please note also that we cannot bind the per-CPU kthread to its
- * CPU until that CPU is fully online.  We also cannot wait until the
- * CPU is fully online before we create its per-CPU kthread, as this would
- * deadlock the system when CPU notifiers tried waiting for grace
- * periods.  So we bind the per-CPU kthread to its CPU only if the CPU
- * is online.  If its CPU is not yet fully online, then the code in
- * rcu_cpu_kthread() will wait until it is fully online, and then do
- * the binding.
- */
-static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
-{
-	struct sched_param sp;
-	struct task_struct *t;
-
-	if (!rcu_scheduler_fully_active ||
-	    per_cpu(rcu_cpu_kthread_task, cpu) != NULL)
-		return 0;
-	t = kthread_create_on_node(rcu_cpu_kthread,
-				   (void *)(long)cpu,
-				   cpu_to_node(cpu),
-				   "rcuc/%d", cpu);
-	if (IS_ERR(t))
-		return PTR_ERR(t);
-	if (cpu_online(cpu))
-		kthread_bind(t, cpu);
-	per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
-	WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
-	sp.sched_priority = RCU_KTHREAD_PRIO;
-	sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-	per_cpu(rcu_cpu_kthread_task, cpu) = t;
-	wake_up_process(t); /* Get to TASK_INTERRUPTIBLE quickly. */
-	return 0;
-}
-
-/*
- * Per-rcu_node kthread, which is in charge of waking up the per-CPU
- * kthreads when needed.  We ignore requests to wake up kthreads
- * for offline CPUs, which is OK because force_quiescent_state()
- * takes care of this case.
- */
-static int rcu_node_kthread(void *arg)
-{
-	int cpu;
-	unsigned long flags;
-	unsigned long mask;
-	struct rcu_node *rnp = (struct rcu_node *)arg;
-	struct sched_param sp;
-	struct task_struct *t;
-
-	for (;;) {
-		rnp->node_kthread_status = RCU_KTHREAD_WAITING;
-		rcu_wait(atomic_read(&rnp->wakemask) != 0);
-		rnp->node_kthread_status = RCU_KTHREAD_RUNNING;
-		raw_spin_lock_irqsave(&rnp->lock, flags);
-		mask = atomic_xchg(&rnp->wakemask, 0);
-		rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
-		for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) {
-			if ((mask & 0x1) == 0)
-				continue;
-			preempt_disable();
-			t = per_cpu(rcu_cpu_kthread_task, cpu);
-			if (!cpu_online(cpu) || t == NULL) {
-				preempt_enable();
-				continue;
-			}
-			per_cpu(rcu_cpu_has_work, cpu) = 1;
-			sp.sched_priority = RCU_KTHREAD_PRIO;
-			sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-			preempt_enable();
-		}
-	}
-	/* NOTREACHED */
-	rnp->node_kthread_status = RCU_KTHREAD_STOPPED;
-	return 0;
+	*statusp = RCU_KTHREAD_YIELDING;
+	trace_rcu_utilization("Start CPU kthread@rcu_yield");
+	schedule_timeout_interruptible(2);
+	trace_rcu_utilization("End CPU kthread@rcu_yield");
+	*statusp = RCU_KTHREAD_WAITING;
 }
 
 /*
@@ -1583,17 +1384,17 @@
  * no outgoing CPU.  If there are no CPUs left in the affinity set,
  * this function allows the kthread to execute on any CPU.
  */
-static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
 {
+	struct task_struct *t = rnp->boost_kthread_task;
+	unsigned long mask = rnp->qsmaskinit;
 	cpumask_var_t cm;
 	int cpu;
-	unsigned long mask = rnp->qsmaskinit;
 
-	if (rnp->node_kthread_task == NULL)
+	if (!t)
 		return;
-	if (!alloc_cpumask_var(&cm, GFP_KERNEL))
+	if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
 		return;
-	cpumask_clear(cm);
 	for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1)
 		if ((mask & 0x1) && cpu != outgoingcpu)
 			cpumask_set_cpu(cpu, cm);
@@ -1603,62 +1404,36 @@
 			cpumask_clear_cpu(cpu, cm);
 		WARN_ON_ONCE(cpumask_weight(cm) == 0);
 	}
-	set_cpus_allowed_ptr(rnp->node_kthread_task, cm);
-	rcu_boost_kthread_setaffinity(rnp, cm);
+	set_cpus_allowed_ptr(t, cm);
 	free_cpumask_var(cm);
 }
 
-/*
- * Spawn a per-rcu_node kthread, setting priority and affinity.
- * Called during boot before online/offline can happen, or, if
- * during runtime, with the main CPU-hotplug locks held.  So only
- * one of these can be executing at a time.
- */
-static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
-						struct rcu_node *rnp)
-{
-	unsigned long flags;
-	int rnp_index = rnp - &rsp->node[0];
-	struct sched_param sp;
-	struct task_struct *t;
-
-	if (!rcu_scheduler_fully_active ||
-	    rnp->qsmaskinit == 0)
-		return 0;
-	if (rnp->node_kthread_task == NULL) {
-		t = kthread_create(rcu_node_kthread, (void *)rnp,
-				   "rcun/%d", rnp_index);
-		if (IS_ERR(t))
-			return PTR_ERR(t);
-		raw_spin_lock_irqsave(&rnp->lock, flags);
-		rnp->node_kthread_task = t;
-		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		sp.sched_priority = 99;
-		sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-		wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
-	}
-	return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index);
-}
+static struct smp_hotplug_thread rcu_cpu_thread_spec = {
+	.store			= &rcu_cpu_kthread_task,
+	.thread_should_run	= rcu_cpu_kthread_should_run,
+	.thread_fn		= rcu_cpu_kthread,
+	.thread_comm		= "rcuc/%u",
+	.setup			= rcu_cpu_kthread_setup,
+	.park			= rcu_cpu_kthread_park,
+};
 
 /*
  * Spawn all kthreads -- called as soon as the scheduler is running.
  */
 static int __init rcu_spawn_kthreads(void)
 {
-	int cpu;
 	struct rcu_node *rnp;
+	int cpu;
 
 	rcu_scheduler_fully_active = 1;
-	for_each_possible_cpu(cpu) {
+	for_each_possible_cpu(cpu)
 		per_cpu(rcu_cpu_has_work, cpu) = 0;
-		if (cpu_online(cpu))
-			(void)rcu_spawn_one_cpu_kthread(cpu);
-	}
+	BUG_ON(smpboot_register_percpu_thread(&rcu_cpu_thread_spec));
 	rnp = rcu_get_root(rcu_state);
-	(void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+	(void)rcu_spawn_one_boost_kthread(rcu_state, rnp);
 	if (NUM_RCU_NODES > 1) {
 		rcu_for_each_leaf_node(rcu_state, rnp)
-			(void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+			(void)rcu_spawn_one_boost_kthread(rcu_state, rnp);
 	}
 	return 0;
 }
@@ -1670,11 +1445,8 @@
 	struct rcu_node *rnp = rdp->mynode;
 
 	/* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */
-	if (rcu_scheduler_fully_active) {
-		(void)rcu_spawn_one_cpu_kthread(cpu);
-		if (rnp->node_kthread_task == NULL)
-			(void)rcu_spawn_one_node_kthread(rcu_state, rnp);
-	}
+	if (rcu_scheduler_fully_active)
+		(void)rcu_spawn_one_boost_kthread(rcu_state, rnp);
 }
 
 #else /* #ifdef CONFIG_RCU_BOOST */
@@ -1698,19 +1470,7 @@
 {
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void rcu_stop_cpu_kthread(int cpu)
-{
-}
-
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
-static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
-{
-}
-
-static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
+static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
 {
 }
 
@@ -1997,6 +1757,26 @@
 	if (!tne)
 		return;
 
+	/* Adaptive-tick mode, where usermode execution is idle to RCU. */
+	if (!is_idle_task(current)) {
+		rdtp->dyntick_holdoff = jiffies - 1;
+		if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
+			trace_rcu_prep_idle("User dyntick with callbacks");
+			rdtp->idle_gp_timer_expires =
+				round_up(jiffies + RCU_IDLE_GP_DELAY,
+					 RCU_IDLE_GP_DELAY);
+		} else if (rcu_cpu_has_callbacks(cpu)) {
+			rdtp->idle_gp_timer_expires =
+				round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
+			trace_rcu_prep_idle("User dyntick with lazy callbacks");
+		} else {
+			return;
+		}
+		tp = &rdtp->idle_gp_timer;
+		mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
+		return;
+	}
+
 	/*
 	 * If this is an idle re-entry, for example, due to use of
 	 * RCU_NONIDLE() or the new idle-loop tracing API within the idle
@@ -2075,16 +1855,16 @@
 #ifdef CONFIG_TREE_PREEMPT_RCU
 	if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
 		rcu_preempt_qs(cpu);
-		force_quiescent_state(&rcu_preempt_state, 0);
+		force_quiescent_state(&rcu_preempt_state);
 	}
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 	if (per_cpu(rcu_sched_data, cpu).nxtlist) {
 		rcu_sched_qs(cpu);
-		force_quiescent_state(&rcu_sched_state, 0);
+		force_quiescent_state(&rcu_sched_state);
 	}
 	if (per_cpu(rcu_bh_data, cpu).nxtlist) {
 		rcu_bh_qs(cpu);
-		force_quiescent_state(&rcu_bh_state, 0);
+		force_quiescent_state(&rcu_bh_state);
 	}
 
 	/*
@@ -2112,6 +1892,88 @@
 	__this_cpu_add(rcu_dynticks.nonlazy_posted, 1);
 }
 
+/*
+ * Data for flushing lazy RCU callbacks at OOM time.
+ */
+static atomic_t oom_callback_count;
+static DECLARE_WAIT_QUEUE_HEAD(oom_callback_wq);
+
+/*
+ * RCU OOM callback -- decrement the outstanding count and deliver the
+ * wake-up if we are the last one.
+ */
+static void rcu_oom_callback(struct rcu_head *rhp)
+{
+	if (atomic_dec_and_test(&oom_callback_count))
+		wake_up(&oom_callback_wq);
+}
+
+/*
+ * Post an rcu_oom_notify callback on the current CPU if it has at
+ * least one lazy callback.  This will unnecessarily post callbacks
+ * to CPUs that already have a non-lazy callback at the end of their
+ * callback list, but this is an infrequent operation, so accept some
+ * extra overhead to keep things simple.
+ */
+static void rcu_oom_notify_cpu(void *unused)
+{
+	struct rcu_state *rsp;
+	struct rcu_data *rdp;
+
+	for_each_rcu_flavor(rsp) {
+		rdp = __this_cpu_ptr(rsp->rda);
+		if (rdp->qlen_lazy != 0) {
+			atomic_inc(&oom_callback_count);
+			rsp->call(&rdp->oom_head, rcu_oom_callback);
+		}
+	}
+}
+
+/*
+ * If low on memory, ensure that each CPU has a non-lazy callback.
+ * This will wake up CPUs that have only lazy callbacks, in turn
+ * ensuring that they free up the corresponding memory in a timely manner.
+ * Because an uncertain amount of memory will be freed in some uncertain
+ * timeframe, we do not claim to have freed anything.
+ */
+static int rcu_oom_notify(struct notifier_block *self,
+			  unsigned long notused, void *nfreed)
+{
+	int cpu;
+
+	/* Wait for callbacks from earlier instance to complete. */
+	wait_event(oom_callback_wq, atomic_read(&oom_callback_count) == 0);
+
+	/*
+	 * Prevent premature wakeup: ensure that all increments happen
+	 * before there is a chance of the counter reaching zero.
+	 */
+	atomic_set(&oom_callback_count, 1);
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		smp_call_function_single(cpu, rcu_oom_notify_cpu, NULL, 1);
+		cond_resched();
+	}
+	put_online_cpus();
+
+	/* Unconditionally decrement: no need to wake ourselves up. */
+	atomic_dec(&oom_callback_count);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block rcu_oom_nb = {
+	.notifier_call = rcu_oom_notify
+};
+
+static int __init rcu_register_oom_notifier(void)
+{
+	register_oom_notifier(&rcu_oom_nb);
+	return 0;
+}
+early_initcall(rcu_register_oom_notifier);
+
 #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */
 
 #ifdef CONFIG_RCU_CPU_STALL_INFO
@@ -2122,11 +1984,15 @@
 {
 	struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
 	struct timer_list *tltp = &rdtp->idle_gp_timer;
+	char c;
 
-	sprintf(cp, "drain=%d %c timer=%lu",
-		rdtp->dyntick_drain,
-		rdtp->dyntick_holdoff == jiffies ? 'H' : '.',
-		timer_pending(tltp) ? tltp->expires - jiffies : -1);
+	c = rdtp->dyntick_holdoff == jiffies ? 'H' : '.';
+	if (timer_pending(tltp))
+		sprintf(cp, "drain=%d %c timer=%lu",
+			rdtp->dyntick_drain, c, tltp->expires - jiffies);
+	else
+		sprintf(cp, "drain=%d %c timer not pending",
+			rdtp->dyntick_drain, c);
 }
 
 #else /* #ifdef CONFIG_RCU_FAST_NO_HZ */
@@ -2194,11 +2060,10 @@
 /* Increment ->ticks_this_gp for all flavors of RCU. */
 static void increment_cpu_stall_ticks(void)
 {
-	__get_cpu_var(rcu_sched_data).ticks_this_gp++;
-	__get_cpu_var(rcu_bh_data).ticks_this_gp++;
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	__get_cpu_var(rcu_preempt_data).ticks_this_gp++;
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		__this_cpu_ptr(rsp->rda)->ticks_this_gp++;
 }
 
 #else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index abffb48..693513b 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -51,8 +51,8 @@
 	struct rcu_state *rsp;
 
 	for_each_rcu_flavor(rsp)
-		seq_printf(m, "%s: %c bcc: %d nbd: %lu\n",
-			   rsp->name, rsp->rcu_barrier_in_progress ? 'B' : '.',
+		seq_printf(m, "%s: bcc: %d nbd: %lu\n",
+			   rsp->name,
 			   atomic_read(&rsp->barrier_cpu_count),
 			   rsp->n_barrier_done);
 	return 0;
@@ -86,12 +86,11 @@
 {
 	if (!rdp->beenonline)
 		return;
-	seq_printf(m, "%3d%cc=%lu g=%lu pq=%d pgp=%lu qp=%d",
+	seq_printf(m, "%3d%cc=%lu g=%lu pq=%d qp=%d",
 		   rdp->cpu,
 		   cpu_is_offline(rdp->cpu) ? '!' : ' ',
 		   rdp->completed, rdp->gpnum,
-		   rdp->passed_quiesce, rdp->passed_quiesce_gpnum,
-		   rdp->qs_pending);
+		   rdp->passed_quiesce, rdp->qs_pending);
 	seq_printf(m, " dt=%d/%llx/%d df=%lu",
 		   atomic_read(&rdp->dynticks->dynticks),
 		   rdp->dynticks->dynticks_nesting,
@@ -108,11 +107,10 @@
 			rdp->nxttail[RCU_WAIT_TAIL]],
 		   ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]);
 #ifdef CONFIG_RCU_BOOST
-	seq_printf(m, " kt=%d/%c/%d ktl=%x",
+	seq_printf(m, " kt=%d/%c ktl=%x",
 		   per_cpu(rcu_cpu_has_work, rdp->cpu),
 		   convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
 					  rdp->cpu)),
-		   per_cpu(rcu_cpu_kthread_cpu, rdp->cpu),
 		   per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff);
 #endif /* #ifdef CONFIG_RCU_BOOST */
 	seq_printf(m, " b=%ld", rdp->blimit);
@@ -150,12 +148,11 @@
 {
 	if (!rdp->beenonline)
 		return;
-	seq_printf(m, "%d,%s,%lu,%lu,%d,%lu,%d",
+	seq_printf(m, "%d,%s,%lu,%lu,%d,%d",
 		   rdp->cpu,
 		   cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"",
 		   rdp->completed, rdp->gpnum,
-		   rdp->passed_quiesce, rdp->passed_quiesce_gpnum,
-		   rdp->qs_pending);
+		   rdp->passed_quiesce, rdp->qs_pending);
 	seq_printf(m, ",%d,%llx,%d,%lu",
 		   atomic_read(&rdp->dynticks->dynticks),
 		   rdp->dynticks->dynticks_nesting,
@@ -186,7 +183,7 @@
 	int cpu;
 	struct rcu_state *rsp;
 
-	seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\",");
+	seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pq\",");
 	seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
 	seq_puts(m, "\"of\",\"qll\",\"ql\",\"qs\"");
 #ifdef CONFIG_RCU_BOOST
@@ -386,10 +383,9 @@
 		   rdp->n_rp_report_qs,
 		   rdp->n_rp_cb_ready,
 		   rdp->n_rp_cpu_needs_gp);
-	seq_printf(m, "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
+	seq_printf(m, "gpc=%ld gps=%ld nn=%ld\n",
 		   rdp->n_rp_gp_completed,
 		   rdp->n_rp_gp_started,
-		   rdp->n_rp_need_fqs,
 		   rdp->n_rp_need_nothing);
 }
 
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 173ea52..f06d249 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -11,7 +11,7 @@
 CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
 endif
 
-obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o
+obj-y += core.o clock.o cputime.o idle_task.o fair.o rt.o stop_task.o
 obj-$(CONFIG_SMP) += cpupri.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 649c9f8..c177472 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -740,126 +740,6 @@
 	dequeue_task(rq, p, flags);
 }
 
-#ifdef CONFIG_IRQ_TIME_ACCOUNTING
-
-/*
- * There are no locks covering percpu hardirq/softirq time.
- * They are only modified in account_system_vtime, on corresponding CPU
- * with interrupts disabled. So, writes are safe.
- * They are read and saved off onto struct rq in update_rq_clock().
- * This may result in other CPU reading this CPU's irq time and can
- * race with irq/account_system_vtime on this CPU. We would either get old
- * or new value with a side effect of accounting a slice of irq time to wrong
- * task when irq is in progress while we read rq->clock. That is a worthy
- * compromise in place of having locks on each irq in account_system_time.
- */
-static DEFINE_PER_CPU(u64, cpu_hardirq_time);
-static DEFINE_PER_CPU(u64, cpu_softirq_time);
-
-static DEFINE_PER_CPU(u64, irq_start_time);
-static int sched_clock_irqtime;
-
-void enable_sched_clock_irqtime(void)
-{
-	sched_clock_irqtime = 1;
-}
-
-void disable_sched_clock_irqtime(void)
-{
-	sched_clock_irqtime = 0;
-}
-
-#ifndef CONFIG_64BIT
-static DEFINE_PER_CPU(seqcount_t, irq_time_seq);
-
-static inline void irq_time_write_begin(void)
-{
-	__this_cpu_inc(irq_time_seq.sequence);
-	smp_wmb();
-}
-
-static inline void irq_time_write_end(void)
-{
-	smp_wmb();
-	__this_cpu_inc(irq_time_seq.sequence);
-}
-
-static inline u64 irq_time_read(int cpu)
-{
-	u64 irq_time;
-	unsigned seq;
-
-	do {
-		seq = read_seqcount_begin(&per_cpu(irq_time_seq, cpu));
-		irq_time = per_cpu(cpu_softirq_time, cpu) +
-			   per_cpu(cpu_hardirq_time, cpu);
-	} while (read_seqcount_retry(&per_cpu(irq_time_seq, cpu), seq));
-
-	return irq_time;
-}
-#else /* CONFIG_64BIT */
-static inline void irq_time_write_begin(void)
-{
-}
-
-static inline void irq_time_write_end(void)
-{
-}
-
-static inline u64 irq_time_read(int cpu)
-{
-	return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu);
-}
-#endif /* CONFIG_64BIT */
-
-/*
- * Called before incrementing preempt_count on {soft,}irq_enter
- * and before decrementing preempt_count on {soft,}irq_exit.
- */
-void account_system_vtime(struct task_struct *curr)
-{
-	unsigned long flags;
-	s64 delta;
-	int cpu;
-
-	if (!sched_clock_irqtime)
-		return;
-
-	local_irq_save(flags);
-
-	cpu = smp_processor_id();
-	delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time);
-	__this_cpu_add(irq_start_time, delta);
-
-	irq_time_write_begin();
-	/*
-	 * We do not account for softirq time from ksoftirqd here.
-	 * We want to continue accounting softirq time to ksoftirqd thread
-	 * in that case, so as not to confuse scheduler with a special task
-	 * that do not consume any time, but still wants to run.
-	 */
-	if (hardirq_count())
-		__this_cpu_add(cpu_hardirq_time, delta);
-	else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
-		__this_cpu_add(cpu_softirq_time, delta);
-
-	irq_time_write_end();
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(account_system_vtime);
-
-#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
-
-#ifdef CONFIG_PARAVIRT
-static inline u64 steal_ticks(u64 steal)
-{
-	if (unlikely(steal > NSEC_PER_SEC))
-		return div_u64(steal, TICK_NSEC);
-
-	return __iter_div_u64_rem(steal, TICK_NSEC, &steal);
-}
-#endif
-
 static void update_rq_clock_task(struct rq *rq, s64 delta)
 {
 /*
@@ -920,43 +800,6 @@
 #endif
 }
 
-#ifdef CONFIG_IRQ_TIME_ACCOUNTING
-static int irqtime_account_hi_update(void)
-{
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-	unsigned long flags;
-	u64 latest_ns;
-	int ret = 0;
-
-	local_irq_save(flags);
-	latest_ns = this_cpu_read(cpu_hardirq_time);
-	if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_IRQ])
-		ret = 1;
-	local_irq_restore(flags);
-	return ret;
-}
-
-static int irqtime_account_si_update(void)
-{
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-	unsigned long flags;
-	u64 latest_ns;
-	int ret = 0;
-
-	local_irq_save(flags);
-	latest_ns = this_cpu_read(cpu_softirq_time);
-	if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_SOFTIRQ])
-		ret = 1;
-	local_irq_restore(flags);
-	return ret;
-}
-
-#else /* CONFIG_IRQ_TIME_ACCOUNTING */
-
-#define sched_clock_irqtime	(0)
-
-#endif
-
 void sched_set_stop_task(int cpu, struct task_struct *stop)
 {
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
@@ -1518,25 +1361,6 @@
 		smp_send_reschedule(cpu);
 }
 
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-static int ttwu_activate_remote(struct task_struct *p, int wake_flags)
-{
-	struct rq *rq;
-	int ret = 0;
-
-	rq = __task_rq_lock(p);
-	if (p->on_cpu) {
-		ttwu_activate(rq, p, ENQUEUE_WAKEUP);
-		ttwu_do_wakeup(rq, p, wake_flags);
-		ret = 1;
-	}
-	__task_rq_unlock(rq);
-
-	return ret;
-
-}
-#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
-
 bool cpus_share_cache(int this_cpu, int that_cpu)
 {
 	return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
@@ -1597,21 +1421,8 @@
 	 * If the owning (remote) cpu is still in the middle of schedule() with
 	 * this task as prev, wait until its done referencing the task.
 	 */
-	while (p->on_cpu) {
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-		/*
-		 * In case the architecture enables interrupts in
-		 * context_switch(), we cannot busy wait, since that
-		 * would lead to deadlocks when an interrupt hits and
-		 * tries to wake up @prev. So bail and do a complete
-		 * remote wakeup.
-		 */
-		if (ttwu_activate_remote(p, wake_flags))
-			goto stat;
-#else
+	while (p->on_cpu)
 		cpu_relax();
-#endif
-	}
 	/*
 	 * Pairs with the smp_wmb() in finish_lock_switch().
 	 */
@@ -1953,14 +1764,9 @@
 	 *		Manfred Spraul <manfred@colorfullife.com>
 	 */
 	prev_state = prev->state;
+	vtime_task_switch(prev);
 	finish_arch_switch(prev);
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-	local_irq_disable();
-#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
 	perf_event_task_sched_in(prev, current);
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-	local_irq_enable();
-#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
 	finish_lock_switch(rq, prev);
 	finish_arch_post_lock_switch();
 
@@ -2081,6 +1887,7 @@
 #endif
 
 	/* Here we just switch the register state and the stack. */
+	rcu_switch(prev, next);
 	switch_to(prev, next, prev);
 
 	barrier();
@@ -2809,404 +2616,6 @@
 	return ns;
 }
 
-#ifdef CONFIG_CGROUP_CPUACCT
-struct cgroup_subsys cpuacct_subsys;
-struct cpuacct root_cpuacct;
-#endif
-
-static inline void task_group_account_field(struct task_struct *p, int index,
-					    u64 tmp)
-{
-#ifdef CONFIG_CGROUP_CPUACCT
-	struct kernel_cpustat *kcpustat;
-	struct cpuacct *ca;
-#endif
-	/*
-	 * Since all updates are sure to touch the root cgroup, we
-	 * get ourselves ahead and touch it first. If the root cgroup
-	 * is the only cgroup, then nothing else should be necessary.
-	 *
-	 */
-	__get_cpu_var(kernel_cpustat).cpustat[index] += tmp;
-
-#ifdef CONFIG_CGROUP_CPUACCT
-	if (unlikely(!cpuacct_subsys.active))
-		return;
-
-	rcu_read_lock();
-	ca = task_ca(p);
-	while (ca && (ca != &root_cpuacct)) {
-		kcpustat = this_cpu_ptr(ca->cpustat);
-		kcpustat->cpustat[index] += tmp;
-		ca = parent_ca(ca);
-	}
-	rcu_read_unlock();
-#endif
-}
-
-
-/*
- * Account user cpu time to a process.
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in user space since the last update
- * @cputime_scaled: cputime scaled by cpu frequency
- */
-void account_user_time(struct task_struct *p, cputime_t cputime,
-		       cputime_t cputime_scaled)
-{
-	int index;
-
-	/* Add user time to process. */
-	p->utime += cputime;
-	p->utimescaled += cputime_scaled;
-	account_group_user_time(p, cputime);
-
-	index = (TASK_NICE(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
-
-	/* Add user time to cpustat. */
-	task_group_account_field(p, index, (__force u64) cputime);
-
-	/* Account for user time used */
-	acct_update_integrals(p);
-}
-
-/*
- * Account guest cpu time to a process.
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in virtual machine since the last update
- * @cputime_scaled: cputime scaled by cpu frequency
- */
-static void account_guest_time(struct task_struct *p, cputime_t cputime,
-			       cputime_t cputime_scaled)
-{
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-
-	/* Add guest time to process. */
-	p->utime += cputime;
-	p->utimescaled += cputime_scaled;
-	account_group_user_time(p, cputime);
-	p->gtime += cputime;
-
-	/* Add guest time to cpustat. */
-	if (TASK_NICE(p) > 0) {
-		cpustat[CPUTIME_NICE] += (__force u64) cputime;
-		cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime;
-	} else {
-		cpustat[CPUTIME_USER] += (__force u64) cputime;
-		cpustat[CPUTIME_GUEST] += (__force u64) cputime;
-	}
-}
-
-/*
- * Account system cpu time to a process and desired cpustat field
- * @p: the process that the cpu time gets accounted to
- * @cputime: the cpu time spent in kernel space since the last update
- * @cputime_scaled: cputime scaled by cpu frequency
- * @target_cputime64: pointer to cpustat field that has to be updated
- */
-static inline
-void __account_system_time(struct task_struct *p, cputime_t cputime,
-			cputime_t cputime_scaled, int index)
-{
-	/* Add system time to process. */
-	p->stime += cputime;
-	p->stimescaled += cputime_scaled;
-	account_group_system_time(p, cputime);
-
-	/* Add system time to cpustat. */
-	task_group_account_field(p, index, (__force u64) cputime);
-
-	/* Account for system time used */
-	acct_update_integrals(p);
-}
-
-/*
- * Account system cpu time to a process.
- * @p: the process that the cpu time gets accounted to
- * @hardirq_offset: the offset to subtract from hardirq_count()
- * @cputime: the cpu time spent in kernel space since the last update
- * @cputime_scaled: cputime scaled by cpu frequency
- */
-void account_system_time(struct task_struct *p, int hardirq_offset,
-			 cputime_t cputime, cputime_t cputime_scaled)
-{
-	int index;
-
-	if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
-		account_guest_time(p, cputime, cputime_scaled);
-		return;
-	}
-
-	if (hardirq_count() - hardirq_offset)
-		index = CPUTIME_IRQ;
-	else if (in_serving_softirq())
-		index = CPUTIME_SOFTIRQ;
-	else
-		index = CPUTIME_SYSTEM;
-
-	__account_system_time(p, cputime, cputime_scaled, index);
-}
-
-/*
- * Account for involuntary wait time.
- * @cputime: the cpu time spent in involuntary wait
- */
-void account_steal_time(cputime_t cputime)
-{
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-
-	cpustat[CPUTIME_STEAL] += (__force u64) cputime;
-}
-
-/*
- * Account for idle time.
- * @cputime: the cpu time spent in idle wait
- */
-void account_idle_time(cputime_t cputime)
-{
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-	struct rq *rq = this_rq();
-
-	if (atomic_read(&rq->nr_iowait) > 0)
-		cpustat[CPUTIME_IOWAIT] += (__force u64) cputime;
-	else
-		cpustat[CPUTIME_IDLE] += (__force u64) cputime;
-}
-
-static __always_inline bool steal_account_process_tick(void)
-{
-#ifdef CONFIG_PARAVIRT
-	if (static_key_false(&paravirt_steal_enabled)) {
-		u64 steal, st = 0;
-
-		steal = paravirt_steal_clock(smp_processor_id());
-		steal -= this_rq()->prev_steal_time;
-
-		st = steal_ticks(steal);
-		this_rq()->prev_steal_time += st * TICK_NSEC;
-
-		account_steal_time(st);
-		return st;
-	}
-#endif
-	return false;
-}
-
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-
-#ifdef CONFIG_IRQ_TIME_ACCOUNTING
-/*
- * Account a tick to a process and cpustat
- * @p: the process that the cpu time gets accounted to
- * @user_tick: is the tick from userspace
- * @rq: the pointer to rq
- *
- * Tick demultiplexing follows the order
- * - pending hardirq update
- * - pending softirq update
- * - user_time
- * - idle_time
- * - system time
- *   - check for guest_time
- *   - else account as system_time
- *
- * Check for hardirq is done both for system and user time as there is
- * no timer going off while we are on hardirq and hence we may never get an
- * opportunity to update it solely in system time.
- * p->stime and friends are only updated on system time and not on irq
- * softirq as those do not count in task exec_runtime any more.
- */
-static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
-						struct rq *rq)
-{
-	cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
-	u64 *cpustat = kcpustat_this_cpu->cpustat;
-
-	if (steal_account_process_tick())
-		return;
-
-	if (irqtime_account_hi_update()) {
-		cpustat[CPUTIME_IRQ] += (__force u64) cputime_one_jiffy;
-	} else if (irqtime_account_si_update()) {
-		cpustat[CPUTIME_SOFTIRQ] += (__force u64) cputime_one_jiffy;
-	} else if (this_cpu_ksoftirqd() == p) {
-		/*
-		 * ksoftirqd time do not get accounted in cpu_softirq_time.
-		 * So, we have to handle it separately here.
-		 * Also, p->stime needs to be updated for ksoftirqd.
-		 */
-		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
-					CPUTIME_SOFTIRQ);
-	} else if (user_tick) {
-		account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
-	} else if (p == rq->idle) {
-		account_idle_time(cputime_one_jiffy);
-	} else if (p->flags & PF_VCPU) { /* System time or guest time */
-		account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled);
-	} else {
-		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
-					CPUTIME_SYSTEM);
-	}
-}
-
-static void irqtime_account_idle_ticks(int ticks)
-{
-	int i;
-	struct rq *rq = this_rq();
-
-	for (i = 0; i < ticks; i++)
-		irqtime_account_process_tick(current, 0, rq);
-}
-#else /* CONFIG_IRQ_TIME_ACCOUNTING */
-static void irqtime_account_idle_ticks(int ticks) {}
-static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
-						struct rq *rq) {}
-#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
-
-/*
- * Account a single tick of cpu time.
- * @p: the process that the cpu time gets accounted to
- * @user_tick: indicates if the tick is a user or a system tick
- */
-void account_process_tick(struct task_struct *p, int user_tick)
-{
-	cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
-	struct rq *rq = this_rq();
-
-	if (sched_clock_irqtime) {
-		irqtime_account_process_tick(p, user_tick, rq);
-		return;
-	}
-
-	if (steal_account_process_tick())
-		return;
-
-	if (user_tick)
-		account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
-	else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
-		account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
-				    one_jiffy_scaled);
-	else
-		account_idle_time(cputime_one_jiffy);
-}
-
-/*
- * Account multiple ticks of steal time.
- * @p: the process from which the cpu time has been stolen
- * @ticks: number of stolen ticks
- */
-void account_steal_ticks(unsigned long ticks)
-{
-	account_steal_time(jiffies_to_cputime(ticks));
-}
-
-/*
- * Account multiple ticks of idle time.
- * @ticks: number of stolen ticks
- */
-void account_idle_ticks(unsigned long ticks)
-{
-
-	if (sched_clock_irqtime) {
-		irqtime_account_idle_ticks(ticks);
-		return;
-	}
-
-	account_idle_time(jiffies_to_cputime(ticks));
-}
-
-#endif
-
-/*
- * Use precise platform statistics if available:
- */
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
-	*ut = p->utime;
-	*st = p->stime;
-}
-
-void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
-	struct task_cputime cputime;
-
-	thread_group_cputime(p, &cputime);
-
-	*ut = cputime.utime;
-	*st = cputime.stime;
-}
-#else
-
-#ifndef nsecs_to_cputime
-# define nsecs_to_cputime(__nsecs)	nsecs_to_jiffies(__nsecs)
-#endif
-
-static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total)
-{
-	u64 temp = (__force u64) rtime;
-
-	temp *= (__force u64) utime;
-
-	if (sizeof(cputime_t) == 4)
-		temp = div_u64(temp, (__force u32) total);
-	else
-		temp = div64_u64(temp, (__force u64) total);
-
-	return (__force cputime_t) temp;
-}
-
-void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
-	cputime_t rtime, utime = p->utime, total = utime + p->stime;
-
-	/*
-	 * Use CFS's precise accounting:
-	 */
-	rtime = nsecs_to_cputime(p->se.sum_exec_runtime);
-
-	if (total)
-		utime = scale_utime(utime, rtime, total);
-	else
-		utime = rtime;
-
-	/*
-	 * Compare with previous values, to keep monotonicity:
-	 */
-	p->prev_utime = max(p->prev_utime, utime);
-	p->prev_stime = max(p->prev_stime, rtime - p->prev_utime);
-
-	*ut = p->prev_utime;
-	*st = p->prev_stime;
-}
-
-/*
- * Must be called with siglock held.
- */
-void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
-	struct signal_struct *sig = p->signal;
-	struct task_cputime cputime;
-	cputime_t rtime, utime, total;
-
-	thread_group_cputime(p, &cputime);
-
-	total = cputime.utime + cputime.stime;
-	rtime = nsecs_to_cputime(cputime.sum_exec_runtime);
-
-	if (total)
-		utime = scale_utime(cputime.utime, rtime, total);
-	else
-		utime = rtime;
-
-	sig->prev_utime = max(sig->prev_utime, utime);
-	sig->prev_stime = max(sig->prev_stime, rtime - sig->prev_utime);
-
-	*ut = sig->prev_utime;
-	*st = sig->prev_stime;
-}
-#endif
-
 /*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
@@ -3367,6 +2776,40 @@
 
 /*
  * __schedule() is the main scheduler function.
+ *
+ * The main means of driving the scheduler and thus entering this function are:
+ *
+ *   1. Explicit blocking: mutex, semaphore, waitqueue, etc.
+ *
+ *   2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
+ *      paths. For example, see arch/x86/entry_64.S.
+ *
+ *      To drive preemption between tasks, the scheduler sets the flag in timer
+ *      interrupt handler scheduler_tick().
+ *
+ *   3. Wakeups don't really cause entry into schedule(). They add a
+ *      task to the run-queue and that's it.
+ *
+ *      Now, if the new task added to the run-queue preempts the current
+ *      task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
+ *      called on the nearest possible occasion:
+ *
+ *       - If the kernel is preemptible (CONFIG_PREEMPT=y):
+ *
+ *         - in syscall or exception context, at the next outmost
+ *           preempt_enable(). (this might be as soon as the wake_up()'s
+ *           spin_unlock()!)
+ *
+ *         - in IRQ context, return from interrupt-handler to
+ *           preemptible context
+ *
+ *       - If the kernel is not preemptible (CONFIG_PREEMPT is not set)
+ *         then at the next:
+ *
+ *          - cond_resched() call
+ *          - explicit schedule() call
+ *          - return from syscall or exception to user-space
+ *          - return from interrupt-handler to user-space
  */
 static void __sched __schedule(void)
 {
@@ -3468,6 +2911,21 @@
 }
 EXPORT_SYMBOL(schedule);
 
+#ifdef CONFIG_RCU_USER_QS
+asmlinkage void __sched schedule_user(void)
+{
+	/*
+	 * If we come here after a random call to set_need_resched(),
+	 * or we have been woken up remotely but the IPI has not yet arrived,
+	 * we haven't yet exited the RCU idle mode. Do it here manually until
+	 * we find a better solution.
+	 */
+	rcu_user_exit();
+	schedule();
+	rcu_user_enter();
+}
+#endif
+
 /**
  * schedule_preempt_disabled - called with preemption disabled
  *
@@ -3569,6 +3027,7 @@
 	/* Catch callers which need to be fixed */
 	BUG_ON(ti->preempt_count || !irqs_disabled());
 
+	rcu_user_exit();
 	do {
 		add_preempt_count(PREEMPT_ACTIVE);
 		local_irq_enable();
@@ -4868,13 +4327,6 @@
 		 */
 		if (preempt && rq != p_rq)
 			resched_task(p_rq->curr);
-	} else {
-		/*
-		 * We might have set it in task_yield_fair(), but are
-		 * not going to schedule(), so don't want to skip
-		 * the next update.
-		 */
-		rq->skip_clock_update = 0;
 	}
 
 out:
@@ -5416,16 +4868,25 @@
 	*tablep = NULL;
 }
 
+static int min_load_idx = 0;
+static int max_load_idx = CPU_LOAD_IDX_MAX;
+
 static void
 set_table_entry(struct ctl_table *entry,
 		const char *procname, void *data, int maxlen,
-		umode_t mode, proc_handler *proc_handler)
+		umode_t mode, proc_handler *proc_handler,
+		bool load_idx)
 {
 	entry->procname = procname;
 	entry->data = data;
 	entry->maxlen = maxlen;
 	entry->mode = mode;
 	entry->proc_handler = proc_handler;
+
+	if (load_idx) {
+		entry->extra1 = &min_load_idx;
+		entry->extra2 = &max_load_idx;
+	}
 }
 
 static struct ctl_table *
@@ -5437,30 +4898,30 @@
 		return NULL;
 
 	set_table_entry(&table[0], "min_interval", &sd->min_interval,
-		sizeof(long), 0644, proc_doulongvec_minmax);
+		sizeof(long), 0644, proc_doulongvec_minmax, false);
 	set_table_entry(&table[1], "max_interval", &sd->max_interval,
-		sizeof(long), 0644, proc_doulongvec_minmax);
+		sizeof(long), 0644, proc_doulongvec_minmax, false);
 	set_table_entry(&table[2], "busy_idx", &sd->busy_idx,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, true);
 	set_table_entry(&table[3], "idle_idx", &sd->idle_idx,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, true);
 	set_table_entry(&table[4], "newidle_idx", &sd->newidle_idx,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, true);
 	set_table_entry(&table[5], "wake_idx", &sd->wake_idx,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, true);
 	set_table_entry(&table[6], "forkexec_idx", &sd->forkexec_idx,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, true);
 	set_table_entry(&table[7], "busy_factor", &sd->busy_factor,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, false);
 	set_table_entry(&table[8], "imbalance_pct", &sd->imbalance_pct,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, false);
 	set_table_entry(&table[9], "cache_nice_tries",
 		&sd->cache_nice_tries,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, false);
 	set_table_entry(&table[10], "flags", &sd->flags,
-		sizeof(int), 0644, proc_dointvec_minmax);
+		sizeof(int), 0644, proc_dointvec_minmax, false);
 	set_table_entry(&table[11], "name", sd->name,
-		CORENAME_MAX_SIZE, 0444, proc_dostring);
+		CORENAME_MAX_SIZE, 0444, proc_dostring, false);
 	/* &table[12] is terminator */
 
 	return table;
@@ -5604,7 +5065,9 @@
 		migrate_tasks(cpu);
 		BUG_ON(rq->nr_running != 1); /* the migration thread */
 		raw_spin_unlock_irqrestore(&rq->lock, flags);
+		break;
 
+	case CPU_DEAD:
 		calc_load_migrate(rq);
 		break;
 #endif
@@ -6537,7 +6000,6 @@
 					| 0*SD_BALANCE_FORK
 					| 0*SD_BALANCE_WAKE
 					| 0*SD_WAKE_AFFINE
-					| 0*SD_PREFER_LOCAL
 					| 0*SD_SHARE_CPUPOWER
 					| 0*SD_SHARE_PKG_RESOURCES
 					| 1*SD_SERIALIZE
@@ -8335,6 +7797,8 @@
  * (balbir@in.ibm.com).
  */
 
+struct cpuacct root_cpuacct;
+
 /* create a new cpu accounting group */
 static struct cgroup_subsys_state *cpuacct_create(struct cgroup *cgrp)
 {
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
new file mode 100644
index 0000000..81b763b
--- /dev/null
+++ b/kernel/sched/cputime.c
@@ -0,0 +1,530 @@
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/tsacct_kern.h>
+#include <linux/kernel_stat.h>
+#include <linux/static_key.h>
+#include "sched.h"
+
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+
+/*
+ * There are no locks covering percpu hardirq/softirq time.
+ * They are only modified in vtime_account, on corresponding CPU
+ * with interrupts disabled. So, writes are safe.
+ * They are read and saved off onto struct rq in update_rq_clock().
+ * This may result in other CPU reading this CPU's irq time and can
+ * race with irq/vtime_account on this CPU. We would either get old
+ * or new value with a side effect of accounting a slice of irq time to wrong
+ * task when irq is in progress while we read rq->clock. That is a worthy
+ * compromise in place of having locks on each irq in account_system_time.
+ */
+DEFINE_PER_CPU(u64, cpu_hardirq_time);
+DEFINE_PER_CPU(u64, cpu_softirq_time);
+
+static DEFINE_PER_CPU(u64, irq_start_time);
+static int sched_clock_irqtime;
+
+void enable_sched_clock_irqtime(void)
+{
+	sched_clock_irqtime = 1;
+}
+
+void disable_sched_clock_irqtime(void)
+{
+	sched_clock_irqtime = 0;
+}
+
+#ifndef CONFIG_64BIT
+DEFINE_PER_CPU(seqcount_t, irq_time_seq);
+#endif /* CONFIG_64BIT */
+
+/*
+ * Called before incrementing preempt_count on {soft,}irq_enter
+ * and before decrementing preempt_count on {soft,}irq_exit.
+ */
+void vtime_account(struct task_struct *curr)
+{
+	unsigned long flags;
+	s64 delta;
+	int cpu;
+
+	if (!sched_clock_irqtime)
+		return;
+
+	local_irq_save(flags);
+
+	cpu = smp_processor_id();
+	delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time);
+	__this_cpu_add(irq_start_time, delta);
+
+	irq_time_write_begin();
+	/*
+	 * We do not account for softirq time from ksoftirqd here.
+	 * We want to continue accounting softirq time to ksoftirqd thread
+	 * in that case, so as not to confuse scheduler with a special task
+	 * that do not consume any time, but still wants to run.
+	 */
+	if (hardirq_count())
+		__this_cpu_add(cpu_hardirq_time, delta);
+	else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
+		__this_cpu_add(cpu_softirq_time, delta);
+
+	irq_time_write_end();
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(vtime_account);
+
+static int irqtime_account_hi_update(void)
+{
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+	unsigned long flags;
+	u64 latest_ns;
+	int ret = 0;
+
+	local_irq_save(flags);
+	latest_ns = this_cpu_read(cpu_hardirq_time);
+	if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_IRQ])
+		ret = 1;
+	local_irq_restore(flags);
+	return ret;
+}
+
+static int irqtime_account_si_update(void)
+{
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+	unsigned long flags;
+	u64 latest_ns;
+	int ret = 0;
+
+	local_irq_save(flags);
+	latest_ns = this_cpu_read(cpu_softirq_time);
+	if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_SOFTIRQ])
+		ret = 1;
+	local_irq_restore(flags);
+	return ret;
+}
+
+#else /* CONFIG_IRQ_TIME_ACCOUNTING */
+
+#define sched_clock_irqtime	(0)
+
+#endif /* !CONFIG_IRQ_TIME_ACCOUNTING */
+
+static inline void task_group_account_field(struct task_struct *p, int index,
+					    u64 tmp)
+{
+#ifdef CONFIG_CGROUP_CPUACCT
+	struct kernel_cpustat *kcpustat;
+	struct cpuacct *ca;
+#endif
+	/*
+	 * Since all updates are sure to touch the root cgroup, we
+	 * get ourselves ahead and touch it first. If the root cgroup
+	 * is the only cgroup, then nothing else should be necessary.
+	 *
+	 */
+	__get_cpu_var(kernel_cpustat).cpustat[index] += tmp;
+
+#ifdef CONFIG_CGROUP_CPUACCT
+	if (unlikely(!cpuacct_subsys.active))
+		return;
+
+	rcu_read_lock();
+	ca = task_ca(p);
+	while (ca && (ca != &root_cpuacct)) {
+		kcpustat = this_cpu_ptr(ca->cpustat);
+		kcpustat->cpustat[index] += tmp;
+		ca = parent_ca(ca);
+	}
+	rcu_read_unlock();
+#endif
+}
+
+/*
+ * Account user cpu time to a process.
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in user space since the last update
+ * @cputime_scaled: cputime scaled by cpu frequency
+ */
+void account_user_time(struct task_struct *p, cputime_t cputime,
+		       cputime_t cputime_scaled)
+{
+	int index;
+
+	/* Add user time to process. */
+	p->utime += cputime;
+	p->utimescaled += cputime_scaled;
+	account_group_user_time(p, cputime);
+
+	index = (TASK_NICE(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
+
+	/* Add user time to cpustat. */
+	task_group_account_field(p, index, (__force u64) cputime);
+
+	/* Account for user time used */
+	acct_update_integrals(p);
+}
+
+/*
+ * Account guest cpu time to a process.
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in virtual machine since the last update
+ * @cputime_scaled: cputime scaled by cpu frequency
+ */
+static void account_guest_time(struct task_struct *p, cputime_t cputime,
+			       cputime_t cputime_scaled)
+{
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+
+	/* Add guest time to process. */
+	p->utime += cputime;
+	p->utimescaled += cputime_scaled;
+	account_group_user_time(p, cputime);
+	p->gtime += cputime;
+
+	/* Add guest time to cpustat. */
+	if (TASK_NICE(p) > 0) {
+		cpustat[CPUTIME_NICE] += (__force u64) cputime;
+		cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime;
+	} else {
+		cpustat[CPUTIME_USER] += (__force u64) cputime;
+		cpustat[CPUTIME_GUEST] += (__force u64) cputime;
+	}
+}
+
+/*
+ * Account system cpu time to a process and desired cpustat field
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in kernel space since the last update
+ * @cputime_scaled: cputime scaled by cpu frequency
+ * @target_cputime64: pointer to cpustat field that has to be updated
+ */
+static inline
+void __account_system_time(struct task_struct *p, cputime_t cputime,
+			cputime_t cputime_scaled, int index)
+{
+	/* Add system time to process. */
+	p->stime += cputime;
+	p->stimescaled += cputime_scaled;
+	account_group_system_time(p, cputime);
+
+	/* Add system time to cpustat. */
+	task_group_account_field(p, index, (__force u64) cputime);
+
+	/* Account for system time used */
+	acct_update_integrals(p);
+}
+
+/*
+ * Account system cpu time to a process.
+ * @p: the process that the cpu time gets accounted to
+ * @hardirq_offset: the offset to subtract from hardirq_count()
+ * @cputime: the cpu time spent in kernel space since the last update
+ * @cputime_scaled: cputime scaled by cpu frequency
+ */
+void account_system_time(struct task_struct *p, int hardirq_offset,
+			 cputime_t cputime, cputime_t cputime_scaled)
+{
+	int index;
+
+	if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
+		account_guest_time(p, cputime, cputime_scaled);
+		return;
+	}
+
+	if (hardirq_count() - hardirq_offset)
+		index = CPUTIME_IRQ;
+	else if (in_serving_softirq())
+		index = CPUTIME_SOFTIRQ;
+	else
+		index = CPUTIME_SYSTEM;
+
+	__account_system_time(p, cputime, cputime_scaled, index);
+}
+
+/*
+ * Account for involuntary wait time.
+ * @cputime: the cpu time spent in involuntary wait
+ */
+void account_steal_time(cputime_t cputime)
+{
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+
+	cpustat[CPUTIME_STEAL] += (__force u64) cputime;
+}
+
+/*
+ * Account for idle time.
+ * @cputime: the cpu time spent in idle wait
+ */
+void account_idle_time(cputime_t cputime)
+{
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+	struct rq *rq = this_rq();
+
+	if (atomic_read(&rq->nr_iowait) > 0)
+		cpustat[CPUTIME_IOWAIT] += (__force u64) cputime;
+	else
+		cpustat[CPUTIME_IDLE] += (__force u64) cputime;
+}
+
+static __always_inline bool steal_account_process_tick(void)
+{
+#ifdef CONFIG_PARAVIRT
+	if (static_key_false(&paravirt_steal_enabled)) {
+		u64 steal, st = 0;
+
+		steal = paravirt_steal_clock(smp_processor_id());
+		steal -= this_rq()->prev_steal_time;
+
+		st = steal_ticks(steal);
+		this_rq()->prev_steal_time += st * TICK_NSEC;
+
+		account_steal_time(st);
+		return st;
+	}
+#endif
+	return false;
+}
+
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+/*
+ * Account a tick to a process and cpustat
+ * @p: the process that the cpu time gets accounted to
+ * @user_tick: is the tick from userspace
+ * @rq: the pointer to rq
+ *
+ * Tick demultiplexing follows the order
+ * - pending hardirq update
+ * - pending softirq update
+ * - user_time
+ * - idle_time
+ * - system time
+ *   - check for guest_time
+ *   - else account as system_time
+ *
+ * Check for hardirq is done both for system and user time as there is
+ * no timer going off while we are on hardirq and hence we may never get an
+ * opportunity to update it solely in system time.
+ * p->stime and friends are only updated on system time and not on irq
+ * softirq as those do not count in task exec_runtime any more.
+ */
+static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
+						struct rq *rq)
+{
+	cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
+	u64 *cpustat = kcpustat_this_cpu->cpustat;
+
+	if (steal_account_process_tick())
+		return;
+
+	if (irqtime_account_hi_update()) {
+		cpustat[CPUTIME_IRQ] += (__force u64) cputime_one_jiffy;
+	} else if (irqtime_account_si_update()) {
+		cpustat[CPUTIME_SOFTIRQ] += (__force u64) cputime_one_jiffy;
+	} else if (this_cpu_ksoftirqd() == p) {
+		/*
+		 * ksoftirqd time do not get accounted in cpu_softirq_time.
+		 * So, we have to handle it separately here.
+		 * Also, p->stime needs to be updated for ksoftirqd.
+		 */
+		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
+					CPUTIME_SOFTIRQ);
+	} else if (user_tick) {
+		account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
+	} else if (p == rq->idle) {
+		account_idle_time(cputime_one_jiffy);
+	} else if (p->flags & PF_VCPU) { /* System time or guest time */
+		account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled);
+	} else {
+		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
+					CPUTIME_SYSTEM);
+	}
+}
+
+static void irqtime_account_idle_ticks(int ticks)
+{
+	int i;
+	struct rq *rq = this_rq();
+
+	for (i = 0; i < ticks; i++)
+		irqtime_account_process_tick(current, 0, rq);
+}
+#else /* CONFIG_IRQ_TIME_ACCOUNTING */
+static void irqtime_account_idle_ticks(int ticks) {}
+static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
+						struct rq *rq) {}
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+
+/*
+ * Account a single tick of cpu time.
+ * @p: the process that the cpu time gets accounted to
+ * @user_tick: indicates if the tick is a user or a system tick
+ */
+void account_process_tick(struct task_struct *p, int user_tick)
+{
+	cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
+	struct rq *rq = this_rq();
+
+	if (sched_clock_irqtime) {
+		irqtime_account_process_tick(p, user_tick, rq);
+		return;
+	}
+
+	if (steal_account_process_tick())
+		return;
+
+	if (user_tick)
+		account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
+	else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
+		account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
+				    one_jiffy_scaled);
+	else
+		account_idle_time(cputime_one_jiffy);
+}
+
+/*
+ * Account multiple ticks of steal time.
+ * @p: the process from which the cpu time has been stolen
+ * @ticks: number of stolen ticks
+ */
+void account_steal_ticks(unsigned long ticks)
+{
+	account_steal_time(jiffies_to_cputime(ticks));
+}
+
+/*
+ * Account multiple ticks of idle time.
+ * @ticks: number of stolen ticks
+ */
+void account_idle_ticks(unsigned long ticks)
+{
+
+	if (sched_clock_irqtime) {
+		irqtime_account_idle_ticks(ticks);
+		return;
+	}
+
+	account_idle_time(jiffies_to_cputime(ticks));
+}
+
+#endif
+
+/*
+ * Use precise platform statistics if available:
+ */
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+	*ut = p->utime;
+	*st = p->stime;
+}
+
+void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+	struct task_cputime cputime;
+
+	thread_group_cputime(p, &cputime);
+
+	*ut = cputime.utime;
+	*st = cputime.stime;
+}
+
+/*
+ * Archs that account the whole time spent in the idle task
+ * (outside irq) as idle time can rely on this and just implement
+ * vtime_account_system() and vtime_account_idle(). Archs that
+ * have other meaning of the idle time (s390 only includes the
+ * time spent by the CPU when it's in low power mode) must override
+ * vtime_account().
+ */
+#ifndef __ARCH_HAS_VTIME_ACCOUNT
+void vtime_account(struct task_struct *tsk)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	if (in_interrupt() || !is_idle_task(tsk))
+		vtime_account_system(tsk);
+	else
+		vtime_account_idle(tsk);
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(vtime_account);
+#endif /* __ARCH_HAS_VTIME_ACCOUNT */
+
+#else
+
+#ifndef nsecs_to_cputime
+# define nsecs_to_cputime(__nsecs)	nsecs_to_jiffies(__nsecs)
+#endif
+
+static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total)
+{
+	u64 temp = (__force u64) rtime;
+
+	temp *= (__force u64) utime;
+
+	if (sizeof(cputime_t) == 4)
+		temp = div_u64(temp, (__force u32) total);
+	else
+		temp = div64_u64(temp, (__force u64) total);
+
+	return (__force cputime_t) temp;
+}
+
+void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+	cputime_t rtime, utime = p->utime, total = utime + p->stime;
+
+	/*
+	 * Use CFS's precise accounting:
+	 */
+	rtime = nsecs_to_cputime(p->se.sum_exec_runtime);
+
+	if (total)
+		utime = scale_utime(utime, rtime, total);
+	else
+		utime = rtime;
+
+	/*
+	 * Compare with previous values, to keep monotonicity:
+	 */
+	p->prev_utime = max(p->prev_utime, utime);
+	p->prev_stime = max(p->prev_stime, rtime - p->prev_utime);
+
+	*ut = p->prev_utime;
+	*st = p->prev_stime;
+}
+
+/*
+ * Must be called with siglock held.
+ */
+void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+	struct signal_struct *sig = p->signal;
+	struct task_cputime cputime;
+	cputime_t rtime, utime, total;
+
+	thread_group_cputime(p, &cputime);
+
+	total = cputime.utime + cputime.stime;
+	rtime = nsecs_to_cputime(cputime.sum_exec_runtime);
+
+	if (total)
+		utime = scale_utime(cputime.utime, rtime, total);
+	else
+		utime = rtime;
+
+	sig->prev_utime = max(sig->prev_utime, utime);
+	sig->prev_stime = max(sig->prev_stime, rtime - sig->prev_utime);
+
+	*ut = sig->prev_utime;
+	*st = sig->prev_stime;
+}
+#endif
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 96e2b18..6b800a1 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -597,7 +597,7 @@
 /*
  * The idea is to set a period in which each task runs once.
  *
- * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
+ * When there are too many tasks (sched_nr_latency) we have to stretch
  * this period because otherwise the slices get too small.
  *
  * p = (nr <= nl) ? l : l*nr/nl
@@ -2700,7 +2700,6 @@
 	int prev_cpu = task_cpu(p);
 	int new_cpu = cpu;
 	int want_affine = 0;
-	int want_sd = 1;
 	int sync = wake_flags & WF_SYNC;
 
 	if (p->nr_cpus_allowed == 1)
@@ -2718,48 +2717,21 @@
 			continue;
 
 		/*
-		 * If power savings logic is enabled for a domain, see if we
-		 * are not overloaded, if so, don't balance wider.
-		 */
-		if (tmp->flags & (SD_PREFER_LOCAL)) {
-			unsigned long power = 0;
-			unsigned long nr_running = 0;
-			unsigned long capacity;
-			int i;
-
-			for_each_cpu(i, sched_domain_span(tmp)) {
-				power += power_of(i);
-				nr_running += cpu_rq(i)->cfs.nr_running;
-			}
-
-			capacity = DIV_ROUND_CLOSEST(power, SCHED_POWER_SCALE);
-
-			if (nr_running < capacity)
-				want_sd = 0;
-		}
-
-		/*
 		 * If both cpu and prev_cpu are part of this domain,
 		 * cpu is a valid SD_WAKE_AFFINE target.
 		 */
 		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
 		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
 			affine_sd = tmp;
-			want_affine = 0;
+			break;
 		}
 
-		if (!want_sd && !want_affine)
-			break;
-
-		if (!(tmp->flags & sd_flag))
-			continue;
-
-		if (want_sd)
+		if (tmp->flags & sd_flag)
 			sd = tmp;
 	}
 
 	if (affine_sd) {
-		if (cpu == prev_cpu || wake_affine(affine_sd, p, sync))
+		if (cpu != prev_cpu && wake_affine(affine_sd, p, sync))
 			prev_cpu = cpu;
 
 		new_cpu = select_idle_sibling(p, prev_cpu);
@@ -4295,7 +4267,7 @@
 		goto out_balanced;
 	}
 
-	BUG_ON(busiest == this_rq);
+	BUG_ON(busiest == env.dst_rq);
 
 	schedstat_add(sd, lb_imbalance[idle], env.imbalance);
 
@@ -4316,7 +4288,7 @@
 		update_h_load(env.src_cpu);
 more_balance:
 		local_irq_save(flags);
-		double_rq_lock(this_rq, busiest);
+		double_rq_lock(env.dst_rq, busiest);
 
 		/*
 		 * cur_ld_moved - load moved in current iteration
@@ -4324,7 +4296,7 @@
 		 */
 		cur_ld_moved = move_tasks(&env);
 		ld_moved += cur_ld_moved;
-		double_rq_unlock(this_rq, busiest);
+		double_rq_unlock(env.dst_rq, busiest);
 		local_irq_restore(flags);
 
 		if (env.flags & LBF_NEED_BREAK) {
@@ -4360,8 +4332,7 @@
 		if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0 &&
 				lb_iterations++ < max_lb_iterations) {
 
-			this_rq		 = cpu_rq(env.new_dst_cpu);
-			env.dst_rq	 = this_rq;
+			env.dst_rq	 = cpu_rq(env.new_dst_cpu);
 			env.dst_cpu	 = env.new_dst_cpu;
 			env.flags	&= ~LBF_SOME_PINNED;
 			env.loop	 = 0;
@@ -4646,7 +4617,7 @@
 	return;
 }
 
-static inline void clear_nohz_tick_stopped(int cpu)
+static inline void nohz_balance_exit_idle(int cpu)
 {
 	if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
 		cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
@@ -4686,28 +4657,23 @@
 }
 
 /*
- * This routine will record that this cpu is going idle with tick stopped.
+ * This routine will record that the cpu is going idle with tick stopped.
  * This info will be used in performing idle load balancing in the future.
  */
-void select_nohz_load_balancer(int stop_tick)
+void nohz_balance_enter_idle(int cpu)
 {
-	int cpu = smp_processor_id();
-
 	/*
 	 * If this cpu is going down, then nothing needs to be done.
 	 */
 	if (!cpu_active(cpu))
 		return;
 
-	if (stop_tick) {
-		if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
-			return;
+	if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
+		return;
 
-		cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
-		atomic_inc(&nohz.nr_cpus);
-		set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
-	}
-	return;
+	cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
+	atomic_inc(&nohz.nr_cpus);
+	set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
 }
 
 static int __cpuinit sched_ilb_notifier(struct notifier_block *nfb,
@@ -4715,7 +4681,7 @@
 {
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_DYING:
-		clear_nohz_tick_stopped(smp_processor_id());
+		nohz_balance_exit_idle(smp_processor_id());
 		return NOTIFY_OK;
 	default:
 		return NOTIFY_DONE;
@@ -4837,14 +4803,15 @@
 		if (need_resched())
 			break;
 
-		raw_spin_lock_irq(&this_rq->lock);
-		update_rq_clock(this_rq);
-		update_idle_cpu_load(this_rq);
-		raw_spin_unlock_irq(&this_rq->lock);
+		rq = cpu_rq(balance_cpu);
+
+		raw_spin_lock_irq(&rq->lock);
+		update_rq_clock(rq);
+		update_idle_cpu_load(rq);
+		raw_spin_unlock_irq(&rq->lock);
 
 		rebalance_domains(balance_cpu, CPU_IDLE);
 
-		rq = cpu_rq(balance_cpu);
 		if (time_after(this_rq->next_balance, rq->next_balance))
 			this_rq->next_balance = rq->next_balance;
 	}
@@ -4875,7 +4842,7 @@
 	* busy tick after returning from idle, we will update the busy stats.
 	*/
 	set_cpu_sd_state_busy();
-	clear_nohz_tick_stopped(cpu);
+	nohz_balance_exit_idle(cpu);
 
 	/*
 	 * None are in tickless mode and hence no need for NOHZ idle load
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index de00a48..eebefca 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -12,14 +12,6 @@
 SCHED_FEAT(START_DEBIT, true)
 
 /*
- * Based on load and program behaviour, see if it makes sense to place
- * a newly woken task on the same cpu as the task that woke it --
- * improve cache locality. Typically used with SYNC wakeups as
- * generated by pipes and the like, see also SYNC_WAKEUPS.
- */
-SCHED_FEAT(AFFINE_WAKEUPS, true)
-
-/*
  * Prefer to schedule the task we woke last (assuming it failed
  * wakeup-preemption), since its likely going to consume data we
  * touched, increases cache locality.
@@ -42,7 +34,7 @@
 /*
  * Use arch dependent cpu power functions
  */
-SCHED_FEAT(ARCH_POWER, false)
+SCHED_FEAT(ARCH_POWER, true)
 
 SCHED_FEAT(HRTICK, false)
 SCHED_FEAT(DOUBLE_TICK, false)
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index e0b7ba9..418feb0 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1632,11 +1632,6 @@
 	if (!next_task)
 		return 0;
 
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-       if (unlikely(task_running(rq, next_task)))
-               return 0;
-#endif
-
 retry:
 	if (unlikely(next_task == rq->curr)) {
 		WARN_ON(1);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0848fa3..7a7db09 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -737,11 +737,7 @@
 	 */
 	next->on_cpu = 1;
 #endif
-#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
-	raw_spin_unlock_irq(&rq->lock);
-#else
 	raw_spin_unlock(&rq->lock);
-#endif
 }
 
 static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
@@ -755,9 +751,7 @@
 	smp_wmb();
 	prev->on_cpu = 0;
 #endif
-#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW
 	local_irq_enable();
-#endif
 }
 #endif /* __ARCH_WANT_UNLOCKED_CTXSW */
 
@@ -891,6 +885,9 @@
 	struct kernel_cpustat __percpu *cpustat;
 };
 
+extern struct cgroup_subsys cpuacct_subsys;
+extern struct cpuacct root_cpuacct;
+
 /* return cpu accounting group corresponding to this container */
 static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
 {
@@ -917,6 +914,16 @@
 static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {}
 #endif
 
+#ifdef CONFIG_PARAVIRT
+static inline u64 steal_ticks(u64 steal)
+{
+	if (unlikely(steal > NSEC_PER_SEC))
+		return div_u64(steal, TICK_NSEC);
+
+	return __iter_div_u64_rem(steal, TICK_NSEC, &steal);
+}
+#endif
+
 static inline void inc_nr_running(struct rq *rq)
 {
 	rq->nr_running++;
@@ -1156,3 +1163,53 @@
 
 #define nohz_flags(cpu)	(&cpu_rq(cpu)->nohz_flags)
 #endif
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+
+DECLARE_PER_CPU(u64, cpu_hardirq_time);
+DECLARE_PER_CPU(u64, cpu_softirq_time);
+
+#ifndef CONFIG_64BIT
+DECLARE_PER_CPU(seqcount_t, irq_time_seq);
+
+static inline void irq_time_write_begin(void)
+{
+	__this_cpu_inc(irq_time_seq.sequence);
+	smp_wmb();
+}
+
+static inline void irq_time_write_end(void)
+{
+	smp_wmb();
+	__this_cpu_inc(irq_time_seq.sequence);
+}
+
+static inline u64 irq_time_read(int cpu)
+{
+	u64 irq_time;
+	unsigned seq;
+
+	do {
+		seq = read_seqcount_begin(&per_cpu(irq_time_seq, cpu));
+		irq_time = per_cpu(cpu_softirq_time, cpu) +
+			   per_cpu(cpu_hardirq_time, cpu);
+	} while (read_seqcount_retry(&per_cpu(irq_time_seq, cpu), seq));
+
+	return irq_time;
+}
+#else /* CONFIG_64BIT */
+static inline void irq_time_write_begin(void)
+{
+}
+
+static inline void irq_time_write_end(void)
+{
+}
+
+static inline u64 irq_time_read(int cpu)
+{
+	return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu);
+}
+#endif /* CONFIG_64BIT */
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+
diff --git a/kernel/signal.c b/kernel/signal.c
index be4f856..2c681f1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1971,13 +1971,8 @@
 void ptrace_notify(int exit_code)
 {
 	BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
-	if (unlikely(current->task_works)) {
-		if (test_and_clear_ti_thread_flag(current_thread_info(),
-						   TIF_NOTIFY_RESUME)) {
-			smp_mb__after_clear_bit();
-			task_work_run();
-		}
-	}
+	if (unlikely(current->task_works))
+		task_work_run();
 
 	spin_lock_irq(&current->sighand->siglock);
 	ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);
@@ -2198,13 +2193,8 @@
 	struct signal_struct *signal = current->signal;
 	int signr;
 
-	if (unlikely(current->task_works)) {
-		if (test_and_clear_ti_thread_flag(current_thread_info(),
-						   TIF_NOTIFY_RESUME)) {
-			smp_mb__after_clear_bit();
-			task_work_run();
-		}
-	}
+	if (unlikely(current->task_works))
+		task_work_run();
 
 	if (unlikely(uprobe_deny_signal()))
 		return 0;
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 98f60c5..d6c5fc0 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -1,14 +1,22 @@
 /*
  * Common SMP CPU bringup/teardown functions
  */
+#include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/export.h>
 #include <linux/percpu.h>
+#include <linux/kthread.h>
+#include <linux/smpboot.h>
 
 #include "smpboot.h"
 
+#ifdef CONFIG_SMP
+
 #ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
 /*
  * For the hotplug case we keep the task structs around and reuse
@@ -65,3 +73,228 @@
 	}
 }
 #endif
+
+#endif /* #ifdef CONFIG_SMP */
+
+static LIST_HEAD(hotplug_threads);
+static DEFINE_MUTEX(smpboot_threads_lock);
+
+struct smpboot_thread_data {
+	unsigned int			cpu;
+	unsigned int			status;
+	struct smp_hotplug_thread	*ht;
+};
+
+enum {
+	HP_THREAD_NONE = 0,
+	HP_THREAD_ACTIVE,
+	HP_THREAD_PARKED,
+};
+
+/**
+ * smpboot_thread_fn - percpu hotplug thread loop function
+ * @data:	thread data pointer
+ *
+ * Checks for thread stop and park conditions. Calls the necessary
+ * setup, cleanup, park and unpark functions for the registered
+ * thread.
+ *
+ * Returns 1 when the thread should exit, 0 otherwise.
+ */
+static int smpboot_thread_fn(void *data)
+{
+	struct smpboot_thread_data *td = data;
+	struct smp_hotplug_thread *ht = td->ht;
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		preempt_disable();
+		if (kthread_should_stop()) {
+			set_current_state(TASK_RUNNING);
+			preempt_enable();
+			if (ht->cleanup)
+				ht->cleanup(td->cpu, cpu_online(td->cpu));
+			kfree(td);
+			return 0;
+		}
+
+		if (kthread_should_park()) {
+			__set_current_state(TASK_RUNNING);
+			preempt_enable();
+			if (ht->park && td->status == HP_THREAD_ACTIVE) {
+				BUG_ON(td->cpu != smp_processor_id());
+				ht->park(td->cpu);
+				td->status = HP_THREAD_PARKED;
+			}
+			kthread_parkme();
+			/* We might have been woken for stop */
+			continue;
+		}
+
+		BUG_ON(td->cpu != smp_processor_id());
+
+		/* Check for state change setup */
+		switch (td->status) {
+		case HP_THREAD_NONE:
+			preempt_enable();
+			if (ht->setup)
+				ht->setup(td->cpu);
+			td->status = HP_THREAD_ACTIVE;
+			preempt_disable();
+			break;
+		case HP_THREAD_PARKED:
+			preempt_enable();
+			if (ht->unpark)
+				ht->unpark(td->cpu);
+			td->status = HP_THREAD_ACTIVE;
+			preempt_disable();
+			break;
+		}
+
+		if (!ht->thread_should_run(td->cpu)) {
+			preempt_enable();
+			schedule();
+		} else {
+			set_current_state(TASK_RUNNING);
+			preempt_enable();
+			ht->thread_fn(td->cpu);
+		}
+	}
+}
+
+static int
+__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
+{
+	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
+	struct smpboot_thread_data *td;
+
+	if (tsk)
+		return 0;
+
+	td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu));
+	if (!td)
+		return -ENOMEM;
+	td->cpu = cpu;
+	td->ht = ht;
+
+	tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu,
+				    ht->thread_comm);
+	if (IS_ERR(tsk)) {
+		kfree(td);
+		return PTR_ERR(tsk);
+	}
+
+	get_task_struct(tsk);
+	*per_cpu_ptr(ht->store, cpu) = tsk;
+	return 0;
+}
+
+int smpboot_create_threads(unsigned int cpu)
+{
+	struct smp_hotplug_thread *cur;
+	int ret = 0;
+
+	mutex_lock(&smpboot_threads_lock);
+	list_for_each_entry(cur, &hotplug_threads, list) {
+		ret = __smpboot_create_thread(cur, cpu);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&smpboot_threads_lock);
+	return ret;
+}
+
+static void smpboot_unpark_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
+{
+	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
+
+	kthread_unpark(tsk);
+}
+
+void smpboot_unpark_threads(unsigned int cpu)
+{
+	struct smp_hotplug_thread *cur;
+
+	mutex_lock(&smpboot_threads_lock);
+	list_for_each_entry(cur, &hotplug_threads, list)
+		smpboot_unpark_thread(cur, cpu);
+	mutex_unlock(&smpboot_threads_lock);
+}
+
+static void smpboot_park_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
+{
+	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
+
+	if (tsk)
+		kthread_park(tsk);
+}
+
+void smpboot_park_threads(unsigned int cpu)
+{
+	struct smp_hotplug_thread *cur;
+
+	mutex_lock(&smpboot_threads_lock);
+	list_for_each_entry_reverse(cur, &hotplug_threads, list)
+		smpboot_park_thread(cur, cpu);
+	mutex_unlock(&smpboot_threads_lock);
+}
+
+static void smpboot_destroy_threads(struct smp_hotplug_thread *ht)
+{
+	unsigned int cpu;
+
+	/* We need to destroy also the parked threads of offline cpus */
+	for_each_possible_cpu(cpu) {
+		struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
+
+		if (tsk) {
+			kthread_stop(tsk);
+			put_task_struct(tsk);
+			*per_cpu_ptr(ht->store, cpu) = NULL;
+		}
+	}
+}
+
+/**
+ * smpboot_register_percpu_thread - Register a per_cpu thread related to hotplug
+ * @plug_thread:	Hotplug thread descriptor
+ *
+ * Creates and starts the threads on all online cpus.
+ */
+int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread)
+{
+	unsigned int cpu;
+	int ret = 0;
+
+	mutex_lock(&smpboot_threads_lock);
+	for_each_online_cpu(cpu) {
+		ret = __smpboot_create_thread(plug_thread, cpu);
+		if (ret) {
+			smpboot_destroy_threads(plug_thread);
+			goto out;
+		}
+		smpboot_unpark_thread(plug_thread, cpu);
+	}
+	list_add(&plug_thread->list, &hotplug_threads);
+out:
+	mutex_unlock(&smpboot_threads_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread);
+
+/**
+ * smpboot_unregister_percpu_thread - Unregister a per_cpu thread related to hotplug
+ * @plug_thread:	Hotplug thread descriptor
+ *
+ * Stops all threads on all possible cpus.
+ */
+void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread)
+{
+	get_online_cpus();
+	mutex_lock(&smpboot_threads_lock);
+	list_del(&plug_thread->list);
+	smpboot_destroy_threads(plug_thread);
+	mutex_unlock(&smpboot_threads_lock);
+	put_online_cpus();
+}
+EXPORT_SYMBOL_GPL(smpboot_unregister_percpu_thread);
diff --git a/kernel/smpboot.h b/kernel/smpboot.h
index 6ef9433..72415a0 100644
--- a/kernel/smpboot.h
+++ b/kernel/smpboot.h
@@ -13,4 +13,8 @@
 static inline void idle_threads_init(void) { }
 #endif
 
+int smpboot_create_threads(unsigned int cpu);
+void smpboot_park_threads(unsigned int cpu);
+void smpboot_unpark_threads(unsigned int cpu);
+
 #endif
diff --git a/kernel/softirq.c b/kernel/softirq.c
index b73e681..cc96bdc 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/ftrace.h>
 #include <linux/smp.h>
+#include <linux/smpboot.h>
 #include <linux/tick.h>
 
 #define CREATE_TRACE_POINTS
@@ -220,7 +221,7 @@
 	current->flags &= ~PF_MEMALLOC;
 
 	pending = local_softirq_pending();
-	account_system_vtime(current);
+	vtime_account(current);
 
 	__local_bh_disable((unsigned long)__builtin_return_address(0),
 				SOFTIRQ_OFFSET);
@@ -271,7 +272,7 @@
 
 	lockdep_softirq_exit();
 
-	account_system_vtime(current);
+	vtime_account(current);
 	__local_bh_enable(SOFTIRQ_OFFSET);
 	tsk_restore_flags(current, old_flags, PF_MEMALLOC);
 }
@@ -340,7 +341,7 @@
  */
 void irq_exit(void)
 {
-	account_system_vtime(current);
+	vtime_account(current);
 	trace_hardirq_exit();
 	sub_preempt_count(IRQ_EXIT_OFFSET);
 	if (!in_interrupt() && local_softirq_pending())
@@ -742,49 +743,22 @@
 	open_softirq(HI_SOFTIRQ, tasklet_hi_action);
 }
 
-static int run_ksoftirqd(void * __bind_cpu)
+static int ksoftirqd_should_run(unsigned int cpu)
 {
-	set_current_state(TASK_INTERRUPTIBLE);
+	return local_softirq_pending();
+}
 
-	while (!kthread_should_stop()) {
-		preempt_disable();
-		if (!local_softirq_pending()) {
-			schedule_preempt_disabled();
-		}
-
-		__set_current_state(TASK_RUNNING);
-
-		while (local_softirq_pending()) {
-			/* Preempt disable stops cpu going offline.
-			   If already offline, we'll be on wrong CPU:
-			   don't process */
-			if (cpu_is_offline((long)__bind_cpu))
-				goto wait_to_die;
-			local_irq_disable();
-			if (local_softirq_pending())
-				__do_softirq();
-			local_irq_enable();
-			sched_preempt_enable_no_resched();
-			cond_resched();
-			preempt_disable();
-			rcu_note_context_switch((long)__bind_cpu);
-		}
-		preempt_enable();
-		set_current_state(TASK_INTERRUPTIBLE);
+static void run_ksoftirqd(unsigned int cpu)
+{
+	local_irq_disable();
+	if (local_softirq_pending()) {
+		__do_softirq();
+		rcu_note_context_switch(cpu);
+		local_irq_enable();
+		cond_resched();
+		return;
 	}
-	__set_current_state(TASK_RUNNING);
-	return 0;
-
-wait_to_die:
-	preempt_enable();
-	/* Wait for kthread_stop */
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (!kthread_should_stop()) {
-		schedule();
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-	__set_current_state(TASK_RUNNING);
-	return 0;
+	local_irq_enable();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -850,50 +824,14 @@
 				  unsigned long action,
 				  void *hcpu)
 {
-	int hotcpu = (unsigned long)hcpu;
-	struct task_struct *p;
-
 	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		p = kthread_create_on_node(run_ksoftirqd,
-					   hcpu,
-					   cpu_to_node(hotcpu),
-					   "ksoftirqd/%d", hotcpu);
-		if (IS_ERR(p)) {
-			printk("ksoftirqd for %i failed\n", hotcpu);
-			return notifier_from_errno(PTR_ERR(p));
-		}
-		kthread_bind(p, hotcpu);
-  		per_cpu(ksoftirqd, hotcpu) = p;
- 		break;
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		wake_up_process(per_cpu(ksoftirqd, hotcpu));
-		break;
 #ifdef CONFIG_HOTPLUG_CPU
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-		if (!per_cpu(ksoftirqd, hotcpu))
-			break;
-		/* Unbind so it can run.  Fall thru. */
-		kthread_bind(per_cpu(ksoftirqd, hotcpu),
-			     cpumask_any(cpu_online_mask));
 	case CPU_DEAD:
-	case CPU_DEAD_FROZEN: {
-		static const struct sched_param param = {
-			.sched_priority = MAX_RT_PRIO-1
-		};
-
-		p = per_cpu(ksoftirqd, hotcpu);
-		per_cpu(ksoftirqd, hotcpu) = NULL;
-		sched_setscheduler_nocheck(p, SCHED_FIFO, &param);
-		kthread_stop(p);
-		takeover_tasklets(hotcpu);
+	case CPU_DEAD_FROZEN:
+		takeover_tasklets((unsigned long)hcpu);
 		break;
-	}
 #endif /* CONFIG_HOTPLUG_CPU */
- 	}
+	}
 	return NOTIFY_OK;
 }
 
@@ -901,14 +839,19 @@
 	.notifier_call = cpu_callback
 };
 
+static struct smp_hotplug_thread softirq_threads = {
+	.store			= &ksoftirqd,
+	.thread_should_run	= ksoftirqd_should_run,
+	.thread_fn		= run_ksoftirqd,
+	.thread_comm		= "ksoftirqd/%u",
+};
+
 static __init int spawn_ksoftirqd(void)
 {
-	void *cpu = (void *)(long)smp_processor_id();
-	int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
-
-	BUG_ON(err != NOTIFY_OK);
-	cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
 	register_cpu_notifier(&cpu_nfb);
+
+	BUG_ON(smpboot_register_percpu_thread(&softirq_threads));
+
 	return 0;
 }
 early_initcall(spawn_ksoftirqd);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 87174ef5..84c76a3 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -307,7 +307,7 @@
 		.extra2		= &max_sched_tunable_scaling,
 	},
 	{
-		.procname	= "sched_migration_cost",
+		.procname	= "sched_migration_cost_ns",
 		.data		= &sysctl_sched_migration_cost,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
@@ -321,14 +321,14 @@
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "sched_time_avg",
+		.procname	= "sched_time_avg_ms",
 		.data		= &sysctl_sched_time_avg,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "sched_shares_window",
+		.procname	= "sched_shares_window_ns",
 		.data		= &sysctl_sched_shares_window,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
@@ -1544,7 +1544,7 @@
 
 static struct ctl_table debug_table[] = {
 #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \
-    defined(CONFIG_S390) || defined(CONFIG_TILE)
+    defined(CONFIG_S390) || defined(CONFIG_TILE) || defined(CONFIG_ARM64)
 	{
 		.procname	= "exception-trace",
 		.data		= &show_unhandled_signals,
diff --git a/kernel/task_work.c b/kernel/task_work.c
index d320d44..65bd3c9 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -2,26 +2,20 @@
 #include <linux/task_work.h>
 #include <linux/tracehook.h>
 
+static struct callback_head work_exited; /* all we need is ->next == NULL */
+
 int
-task_work_add(struct task_struct *task, struct callback_head *twork, bool notify)
+task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
 {
-	struct callback_head *last, *first;
-	unsigned long flags;
+	struct callback_head *head;
 
-	/*
-	 * Not inserting the new work if the task has already passed
-	 * exit_task_work() is the responisbility of callers.
-	 */
-	raw_spin_lock_irqsave(&task->pi_lock, flags);
-	last = task->task_works;
-	first = last ? last->next : twork;
-	twork->next = first;
-	if (last)
-		last->next = twork;
-	task->task_works = twork;
-	raw_spin_unlock_irqrestore(&task->pi_lock, flags);
+	do {
+		head = ACCESS_ONCE(task->task_works);
+		if (unlikely(head == &work_exited))
+			return -ESRCH;
+		work->next = head;
+	} while (cmpxchg(&task->task_works, head, work) != head);
 
-	/* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
 	if (notify)
 		set_notify_resume(task);
 	return 0;
@@ -30,52 +24,69 @@
 struct callback_head *
 task_work_cancel(struct task_struct *task, task_work_func_t func)
 {
+	struct callback_head **pprev = &task->task_works;
+	struct callback_head *work = NULL;
 	unsigned long flags;
-	struct callback_head *last, *res = NULL;
-
+	/*
+	 * If cmpxchg() fails we continue without updating pprev.
+	 * Either we raced with task_work_add() which added the
+	 * new entry before this work, we will find it again. Or
+	 * we raced with task_work_run(), *pprev == NULL/exited.
+	 */
 	raw_spin_lock_irqsave(&task->pi_lock, flags);
-	last = task->task_works;
-	if (last) {
-		struct callback_head *q = last, *p = q->next;
-		while (1) {
-			if (p->func == func) {
-				q->next = p->next;
-				if (p == last)
-					task->task_works = q == p ? NULL : q;
-				res = p;
-				break;
-			}
-			if (p == last)
-				break;
-			q = p;
-			p = q->next;
-		}
+	while ((work = ACCESS_ONCE(*pprev))) {
+		read_barrier_depends();
+		if (work->func != func)
+			pprev = &work->next;
+		else if (cmpxchg(pprev, work, work->next) == work)
+			break;
 	}
 	raw_spin_unlock_irqrestore(&task->pi_lock, flags);
-	return res;
+
+	return work;
 }
 
 void task_work_run(void)
 {
 	struct task_struct *task = current;
-	struct callback_head *p, *q;
+	struct callback_head *work, *head, *next;
 
-	while (1) {
-		raw_spin_lock_irq(&task->pi_lock);
-		p = task->task_works;
-		task->task_works = NULL;
-		raw_spin_unlock_irq(&task->pi_lock);
+	for (;;) {
+		/*
+		 * work->func() can do task_work_add(), do not set
+		 * work_exited unless the list is empty.
+		 */
+		do {
+			work = ACCESS_ONCE(task->task_works);
+			head = !work && (task->flags & PF_EXITING) ?
+				&work_exited : NULL;
+		} while (cmpxchg(&task->task_works, work, head) != work);
 
-		if (unlikely(!p))
-			return;
+		if (!work)
+			break;
+		/*
+		 * Synchronize with task_work_cancel(). It can't remove
+		 * the first entry == work, cmpxchg(task_works) should
+		 * fail, but it can play with *work and other entries.
+		 */
+		raw_spin_unlock_wait(&task->pi_lock);
+		smp_mb();
 
-		q = p->next; /* head */
-		p->next = NULL; /* cut it */
-		while (q) {
-			p = q->next;
-			q->func(q);
-			q = p;
+		/* Reverse the list to run the works in fifo order */
+		head = NULL;
+		do {
+			next = work->next;
+			work->next = head;
+			head = work;
+			work = next;
+		} while (work);
+
+		work = head;
+		do {
+			next = work->next;
+			work->func(work);
+			work = next;
 			cond_resched();
-		}
+		} while (work);
 	}
 }
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 3a9e5d5..f423bdd0 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -372,7 +372,7 @@
 		 * the scheduler tick in nohz_restart_sched_tick.
 		 */
 		if (!ts->tick_stopped) {
-			select_nohz_load_balancer(1);
+			nohz_balance_enter_idle(cpu);
 			calc_load_enter_idle();
 
 			ts->last_tick = hrtimer_get_expires(&ts->sched_timer);
@@ -436,7 +436,8 @@
 	if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
 		static int ratelimit;
 
-		if (ratelimit < 10) {
+		if (ratelimit < 10 &&
+		    (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
 			printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
 			       (unsigned int) local_softirq_pending());
 			ratelimit++;
@@ -569,7 +570,6 @@
 static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
 {
 	/* Update jiffies first */
-	select_nohz_load_balancer(0);
 	tick_do_update_jiffies64(now);
 	update_cpu_load_nohz();
 
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 34e5eac..d3b91e7 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -303,10 +303,11 @@
 		seq = read_seqbegin(&tk->lock);
 
 		ts->tv_sec = tk->xtime_sec;
-		ts->tv_nsec = timekeeping_get_ns(tk);
+		nsecs = timekeeping_get_ns(tk);
 
 	} while (read_seqretry(&tk->lock, seq));
 
+	ts->tv_nsec = 0;
 	timespec_add_ns(ts, nsecs);
 }
 EXPORT_SYMBOL(getnstimeofday);
@@ -345,6 +346,7 @@
 {
 	struct timekeeper *tk = &timekeeper;
 	struct timespec tomono;
+	s64 nsec;
 	unsigned int seq;
 
 	WARN_ON(timekeeping_suspended);
@@ -352,13 +354,14 @@
 	do {
 		seq = read_seqbegin(&tk->lock);
 		ts->tv_sec = tk->xtime_sec;
-		ts->tv_nsec = timekeeping_get_ns(tk);
+		nsec = timekeeping_get_ns(tk);
 		tomono = tk->wall_to_monotonic;
 
 	} while (read_seqretry(&tk->lock, seq));
 
-	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
-				ts->tv_nsec + tomono.tv_nsec);
+	ts->tv_sec += tomono.tv_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsec + tomono.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts);
 
@@ -1244,6 +1247,7 @@
 {
 	struct timekeeper *tk = &timekeeper;
 	struct timespec tomono, sleep;
+	s64 nsec;
 	unsigned int seq;
 
 	WARN_ON(timekeeping_suspended);
@@ -1251,14 +1255,15 @@
 	do {
 		seq = read_seqbegin(&tk->lock);
 		ts->tv_sec = tk->xtime_sec;
-		ts->tv_nsec = timekeeping_get_ns(tk);
+		nsec = timekeeping_get_ns(tk);
 		tomono = tk->wall_to_monotonic;
 		sleep = tk->total_sleep_time;
 
 	} while (read_seqretry(&tk->lock, seq));
 
-	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
-			ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec);
+	ts->tv_sec += tomono.tv_sec + sleep.tv_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsec + tomono.tv_nsec + sleep.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(get_monotonic_boottime);
 
diff --git a/kernel/timer.c b/kernel/timer.c
index 8c5e7b9..d5de1b2 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -92,24 +92,25 @@
 /* Functions below help us manage 'deferrable' flag */
 static inline unsigned int tbase_get_deferrable(struct tvec_base *base)
 {
-	return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG);
+	return ((unsigned int)(unsigned long)base & TIMER_DEFERRABLE);
+}
+
+static inline unsigned int tbase_get_irqsafe(struct tvec_base *base)
+{
+	return ((unsigned int)(unsigned long)base & TIMER_IRQSAFE);
 }
 
 static inline struct tvec_base *tbase_get_base(struct tvec_base *base)
 {
-	return ((struct tvec_base *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG));
-}
-
-static inline void timer_set_deferrable(struct timer_list *timer)
-{
-	timer->base = TBASE_MAKE_DEFERRED(timer->base);
+	return ((struct tvec_base *)((unsigned long)base & ~TIMER_FLAG_MASK));
 }
 
 static inline void
 timer_set_base(struct timer_list *timer, struct tvec_base *new_base)
 {
-	timer->base = (struct tvec_base *)((unsigned long)(new_base) |
-				      tbase_get_deferrable(timer->base));
+	unsigned long flags = (unsigned long)timer->base & TIMER_FLAG_MASK;
+
+	timer->base = (struct tvec_base *)((unsigned long)(new_base) | flags);
 }
 
 static unsigned long round_jiffies_common(unsigned long j, int cpu,
@@ -563,16 +564,14 @@
 	debug_object_assert_init(timer, &timer_debug_descr);
 }
 
-static void __init_timer(struct timer_list *timer,
-			 const char *name,
-			 struct lock_class_key *key);
+static void do_init_timer(struct timer_list *timer, unsigned int flags,
+			  const char *name, struct lock_class_key *key);
 
-void init_timer_on_stack_key(struct timer_list *timer,
-			     const char *name,
-			     struct lock_class_key *key)
+void init_timer_on_stack_key(struct timer_list *timer, unsigned int flags,
+			     const char *name, struct lock_class_key *key)
 {
 	debug_object_init_on_stack(timer, &timer_debug_descr);
-	__init_timer(timer, name, key);
+	do_init_timer(timer, flags, name, key);
 }
 EXPORT_SYMBOL_GPL(init_timer_on_stack_key);
 
@@ -613,12 +612,13 @@
 	debug_timer_assert_init(timer);
 }
 
-static void __init_timer(struct timer_list *timer,
-			 const char *name,
-			 struct lock_class_key *key)
+static void do_init_timer(struct timer_list *timer, unsigned int flags,
+			  const char *name, struct lock_class_key *key)
 {
+	struct tvec_base *base = __raw_get_cpu_var(tvec_bases);
+
 	timer->entry.next = NULL;
-	timer->base = __raw_get_cpu_var(tvec_bases);
+	timer->base = (void *)((unsigned long)base | flags);
 	timer->slack = -1;
 #ifdef CONFIG_TIMER_STATS
 	timer->start_site = NULL;
@@ -628,22 +628,10 @@
 	lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
 
-void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
-					 const char *name,
-					 struct lock_class_key *key,
-					 void (*function)(unsigned long),
-					 unsigned long data)
-{
-	timer->function = function;
-	timer->data = data;
-	init_timer_on_stack_key(timer, name, key);
-	timer_set_deferrable(timer);
-}
-EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key);
-
 /**
  * init_timer_key - initialize a timer
  * @timer: the timer to be initialized
+ * @flags: timer flags
  * @name: name of the timer
  * @key: lockdep class key of the fake lock used for tracking timer
  *       sync lock dependencies
@@ -651,24 +639,14 @@
  * init_timer_key() must be done to a timer prior calling *any* of the
  * other timer functions.
  */
-void init_timer_key(struct timer_list *timer,
-		    const char *name,
-		    struct lock_class_key *key)
+void init_timer_key(struct timer_list *timer, unsigned int flags,
+		    const char *name, struct lock_class_key *key)
 {
 	debug_init(timer);
-	__init_timer(timer, name, key);
+	do_init_timer(timer, flags, name, key);
 }
 EXPORT_SYMBOL(init_timer_key);
 
-void init_timer_deferrable_key(struct timer_list *timer,
-			       const char *name,
-			       struct lock_class_key *key)
-{
-	init_timer_key(timer, name, key);
-	timer_set_deferrable(timer);
-}
-EXPORT_SYMBOL(init_timer_deferrable_key);
-
 static inline void detach_timer(struct timer_list *timer, bool clear_pending)
 {
 	struct list_head *entry = &timer->entry;
@@ -686,7 +664,7 @@
 {
 	detach_timer(timer, true);
 	if (!tbase_get_deferrable(timer->base))
-		timer->base->active_timers--;
+		base->active_timers--;
 }
 
 static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
@@ -697,7 +675,7 @@
 
 	detach_timer(timer, clear_pending);
 	if (!tbase_get_deferrable(timer->base)) {
-		timer->base->active_timers--;
+		base->active_timers--;
 		if (timer->expires == base->next_timer)
 			base->next_timer = base->timer_jiffies;
 	}
@@ -1029,14 +1007,14 @@
  *
  * Synchronization rules: Callers must prevent restarting of the timer,
  * otherwise this function is meaningless. It must not be called from
- * interrupt contexts. The caller must not hold locks which would prevent
- * completion of the timer's handler. The timer's handler must not call
- * add_timer_on(). Upon exit the timer is not queued and the handler is
- * not running on any CPU.
+ * interrupt contexts unless the timer is an irqsafe one. The caller must
+ * not hold locks which would prevent completion of the timer's
+ * handler. The timer's handler must not call add_timer_on(). Upon exit the
+ * timer is not queued and the handler is not running on any CPU.
  *
- * Note: You must not hold locks that are held in interrupt context
- *   while calling this function. Even if the lock has nothing to do
- *   with the timer in question.  Here's why:
+ * Note: For !irqsafe timers, you must not hold locks that are held in
+ *   interrupt context while calling this function. Even if the lock has
+ *   nothing to do with the timer in question.  Here's why:
  *
  *    CPU0                             CPU1
  *    ----                             ----
@@ -1073,7 +1051,7 @@
 	 * don't use it in hardirq context, because it
 	 * could lead to deadlock.
 	 */
-	WARN_ON(in_irq());
+	WARN_ON(in_irq() && !tbase_get_irqsafe(timer->base));
 	for (;;) {
 		int ret = try_to_del_timer_sync(timer);
 		if (ret >= 0)
@@ -1180,19 +1158,27 @@
 		while (!list_empty(head)) {
 			void (*fn)(unsigned long);
 			unsigned long data;
+			bool irqsafe;
 
 			timer = list_first_entry(head, struct timer_list,entry);
 			fn = timer->function;
 			data = timer->data;
+			irqsafe = tbase_get_irqsafe(timer->base);
 
 			timer_stats_account_timer(timer);
 
 			base->running_timer = timer;
 			detach_expired_timer(timer, base);
 
-			spin_unlock_irq(&base->lock);
-			call_timer_fn(timer, fn, data);
-			spin_lock_irq(&base->lock);
+			if (irqsafe) {
+				spin_unlock(&base->lock);
+				call_timer_fn(timer, fn, data);
+				spin_lock(&base->lock);
+			} else {
+				spin_unlock_irq(&base->lock);
+				call_timer_fn(timer, fn, data);
+				spin_lock_irq(&base->lock);
+			}
 		}
 	}
 	base->running_timer = NULL;
@@ -1791,9 +1777,13 @@
 
 void __init init_timers(void)
 {
-	int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
-				(void *)(long)smp_processor_id());
+	int err;
 
+	/* ensure there are enough low bits for flags in timer->base pointer */
+	BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK);
+
+	err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
+			       (void *)(long)smp_processor_id());
 	init_timer_stats();
 
 	BUG_ON(err != NOTIFY_OK);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 8c4c070..4cea4f4 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -49,6 +49,11 @@
 	help
 	  See Documentation/trace/ftrace-design.txt
 
+config HAVE_FENTRY
+	bool
+	help
+	  Arch supports the gcc options -pg with -mfentry
+
 config HAVE_C_RECORDMCOUNT
 	bool
 	help
@@ -57,8 +62,12 @@
 config TRACER_MAX_TRACE
 	bool
 
+config TRACE_CLOCK
+	bool
+
 config RING_BUFFER
 	bool
+	select TRACE_CLOCK
 
 config FTRACE_NMI_ENTER
        bool
@@ -109,6 +118,7 @@
 	select NOP_TRACER
 	select BINARY_PRINTF
 	select EVENT_TRACING
+	select TRACE_CLOCK
 
 config GENERIC_TRACER
 	bool
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index b831087..d7e2068 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -5,10 +5,12 @@
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
 
+ifdef CONFIG_FTRACE_SELFTEST
 # selftest needs instrumentation
 CFLAGS_trace_selftest_dynamic.o = -pg
 obj-y += trace_selftest_dynamic.o
 endif
+endif
 
 # If unlikely tracing is enabled, do not trace these files
 ifdef CONFIG_TRACING_BRANCHES
@@ -17,11 +19,7 @@
 
 CFLAGS_trace_events_filter.o := -I$(src)
 
-#
-# Make the trace clocks available generally: it's infrastructure
-# relied on by ptrace for example:
-#
-obj-y += trace_clock.o
+obj-$(CONFIG_TRACE_CLOCK) += trace_clock.o
 
 obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
 obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b4f20fb..9dcf15d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -64,12 +64,20 @@
 
 #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL)
 
+static struct ftrace_ops ftrace_list_end __read_mostly = {
+	.func		= ftrace_stub,
+	.flags		= FTRACE_OPS_FL_RECURSION_SAFE,
+};
+
 /* ftrace_enabled is a method to turn ftrace on or off */
 int ftrace_enabled __read_mostly;
 static int last_ftrace_enabled;
 
 /* Quick disabling of function tracer. */
-int function_trace_stop;
+int function_trace_stop __read_mostly;
+
+/* Current function tracing op */
+struct ftrace_ops *function_trace_op __read_mostly = &ftrace_list_end;
 
 /* List for set_ftrace_pid's pids. */
 LIST_HEAD(ftrace_pids);
@@ -86,22 +94,43 @@
 
 static DEFINE_MUTEX(ftrace_lock);
 
-static struct ftrace_ops ftrace_list_end __read_mostly = {
-	.func		= ftrace_stub,
-};
-
 static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end;
 static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end;
 static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
-static ftrace_func_t __ftrace_trace_function_delay __read_mostly = ftrace_stub;
-ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
 ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
 static struct ftrace_ops control_ops;
 
-static void
-ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);
+#if ARCH_SUPPORTS_FTRACE_OPS
+static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
+				 struct ftrace_ops *op, struct pt_regs *regs);
+#else
+/* See comment below, where ftrace_ops_list_func is defined */
+static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);
+#define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops)
+#endif
+
+/**
+ * ftrace_nr_registered_ops - return number of ops registered
+ *
+ * Returns the number of ftrace_ops registered and tracing functions
+ */
+int ftrace_nr_registered_ops(void)
+{
+	struct ftrace_ops *ops;
+	int cnt = 0;
+
+	mutex_lock(&ftrace_lock);
+
+	for (ops = ftrace_ops_list;
+	     ops != &ftrace_list_end; ops = ops->next)
+		cnt++;
+
+	mutex_unlock(&ftrace_lock);
+
+	return cnt;
+}
 
 /*
  * Traverse the ftrace_global_list, invoking all entries.  The reason that we
@@ -112,29 +141,29 @@
  *
  * Silly Alpha and silly pointer-speculation compiler optimizations!
  */
-static void ftrace_global_list_func(unsigned long ip,
-				    unsigned long parent_ip)
+static void
+ftrace_global_list_func(unsigned long ip, unsigned long parent_ip,
+			struct ftrace_ops *op, struct pt_regs *regs)
 {
-	struct ftrace_ops *op;
-
 	if (unlikely(trace_recursion_test(TRACE_GLOBAL_BIT)))
 		return;
 
 	trace_recursion_set(TRACE_GLOBAL_BIT);
 	op = rcu_dereference_raw(ftrace_global_list); /*see above*/
 	while (op != &ftrace_list_end) {
-		op->func(ip, parent_ip);
+		op->func(ip, parent_ip, op, regs);
 		op = rcu_dereference_raw(op->next); /*see above*/
 	};
 	trace_recursion_clear(TRACE_GLOBAL_BIT);
 }
 
-static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip)
+static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip,
+			    struct ftrace_ops *op, struct pt_regs *regs)
 {
 	if (!test_tsk_trace_trace(current))
 		return;
 
-	ftrace_pid_function(ip, parent_ip);
+	ftrace_pid_function(ip, parent_ip, op, regs);
 }
 
 static void set_ftrace_pid_function(ftrace_func_t func)
@@ -153,25 +182,9 @@
 void clear_ftrace_function(void)
 {
 	ftrace_trace_function = ftrace_stub;
-	__ftrace_trace_function = ftrace_stub;
-	__ftrace_trace_function_delay = ftrace_stub;
 	ftrace_pid_function = ftrace_stub;
 }
 
-#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-/*
- * For those archs that do not test ftrace_trace_stop in their
- * mcount call site, we need to do it from C.
- */
-static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip)
-{
-	if (function_trace_stop)
-		return;
-
-	__ftrace_trace_function(ip, parent_ip);
-}
-#endif
-
 static void control_ops_disable_all(struct ftrace_ops *ops)
 {
 	int cpu;
@@ -230,28 +243,27 @@
 
 	/*
 	 * If we are at the end of the list and this ops is
-	 * not dynamic, then have the mcount trampoline call
-	 * the function directly
+	 * recursion safe and not dynamic and the arch supports passing ops,
+	 * then have the mcount trampoline call the function directly.
 	 */
 	if (ftrace_ops_list == &ftrace_list_end ||
 	    (ftrace_ops_list->next == &ftrace_list_end &&
-	     !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC)))
+	     !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC) &&
+	     (ftrace_ops_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) &&
+	     !FTRACE_FORCE_LIST_FUNC)) {
+		/* Set the ftrace_ops that the arch callback uses */
+		if (ftrace_ops_list == &global_ops)
+			function_trace_op = ftrace_global_list;
+		else
+			function_trace_op = ftrace_ops_list;
 		func = ftrace_ops_list->func;
-	else
+	} else {
+		/* Just use the default ftrace_ops */
+		function_trace_op = &ftrace_list_end;
 		func = ftrace_ops_list_func;
+	}
 
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	ftrace_trace_function = func;
-#else
-#ifdef CONFIG_DYNAMIC_FTRACE
-	/* do not update till all functions have been modified */
-	__ftrace_trace_function_delay = func;
-#else
-	__ftrace_trace_function = func;
-#endif
-	ftrace_trace_function =
-		(func == ftrace_stub) ? func : ftrace_test_stop_func;
-#endif
 }
 
 static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)
@@ -325,6 +337,20 @@
 	if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK)
 		return -EINVAL;
 
+#ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+	/*
+	 * If the ftrace_ops specifies SAVE_REGS, then it only can be used
+	 * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set.
+	 * Setting SAVE_REGS_IF_SUPPORTED makes SAVE_REGS irrelevant.
+	 */
+	if (ops->flags & FTRACE_OPS_FL_SAVE_REGS &&
+	    !(ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED))
+		return -EINVAL;
+
+	if (ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED)
+		ops->flags |= FTRACE_OPS_FL_SAVE_REGS;
+#endif
+
 	if (!core_kernel_data((unsigned long)ops))
 		ops->flags |= FTRACE_OPS_FL_DYNAMIC;
 
@@ -773,7 +799,8 @@
 }
 
 static void
-function_profile_call(unsigned long ip, unsigned long parent_ip)
+function_profile_call(unsigned long ip, unsigned long parent_ip,
+		      struct ftrace_ops *ops, struct pt_regs *regs)
 {
 	struct ftrace_profile_stat *stat;
 	struct ftrace_profile *rec;
@@ -803,7 +830,7 @@
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 static int profile_graph_entry(struct ftrace_graph_ent *trace)
 {
-	function_profile_call(trace->func, 0);
+	function_profile_call(trace->func, 0, NULL, NULL);
 	return 1;
 }
 
@@ -863,6 +890,7 @@
 #else
 static struct ftrace_ops ftrace_profile_ops __read_mostly = {
 	.func		= function_profile_call,
+	.flags		= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static int register_ftrace_profiler(void)
@@ -1045,6 +1073,7 @@
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static DEFINE_MUTEX(ftrace_regex_lock);
@@ -1525,6 +1554,12 @@
 			rec->flags++;
 			if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX))
 				return;
+			/*
+			 * If any ops wants regs saved for this function
+			 * then all ops will get saved regs.
+			 */
+			if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
+				rec->flags |= FTRACE_FL_REGS;
 		} else {
 			if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0))
 				return;
@@ -1616,18 +1651,59 @@
 	if (enable && (rec->flags & ~FTRACE_FL_MASK))
 		flag = FTRACE_FL_ENABLED;
 
+	/*
+	 * If enabling and the REGS flag does not match the REGS_EN, then
+	 * do not ignore this record. Set flags to fail the compare against
+	 * ENABLED.
+	 */
+	if (flag &&
+	    (!(rec->flags & FTRACE_FL_REGS) != !(rec->flags & FTRACE_FL_REGS_EN)))
+		flag |= FTRACE_FL_REGS;
+
 	/* If the state of this record hasn't changed, then do nothing */
 	if ((rec->flags & FTRACE_FL_ENABLED) == flag)
 		return FTRACE_UPDATE_IGNORE;
 
 	if (flag) {
-		if (update)
+		/* Save off if rec is being enabled (for return value) */
+		flag ^= rec->flags & FTRACE_FL_ENABLED;
+
+		if (update) {
 			rec->flags |= FTRACE_FL_ENABLED;
-		return FTRACE_UPDATE_MAKE_CALL;
+			if (flag & FTRACE_FL_REGS) {
+				if (rec->flags & FTRACE_FL_REGS)
+					rec->flags |= FTRACE_FL_REGS_EN;
+				else
+					rec->flags &= ~FTRACE_FL_REGS_EN;
+			}
+		}
+
+		/*
+		 * If this record is being updated from a nop, then
+		 *   return UPDATE_MAKE_CALL.
+		 * Otherwise, if the EN flag is set, then return
+		 *   UPDATE_MODIFY_CALL_REGS to tell the caller to convert
+		 *   from the non-save regs, to a save regs function.
+		 * Otherwise,
+		 *   return UPDATE_MODIFY_CALL to tell the caller to convert
+		 *   from the save regs, to a non-save regs function.
+		 */
+		if (flag & FTRACE_FL_ENABLED)
+			return FTRACE_UPDATE_MAKE_CALL;
+		else if (rec->flags & FTRACE_FL_REGS_EN)
+			return FTRACE_UPDATE_MODIFY_CALL_REGS;
+		else
+			return FTRACE_UPDATE_MODIFY_CALL;
 	}
 
-	if (update)
-		rec->flags &= ~FTRACE_FL_ENABLED;
+	if (update) {
+		/* If there's no more users, clear all flags */
+		if (!(rec->flags & ~FTRACE_FL_MASK))
+			rec->flags = 0;
+		else
+			/* Just disable the record (keep REGS state) */
+			rec->flags &= ~FTRACE_FL_ENABLED;
+	}
 
 	return FTRACE_UPDATE_MAKE_NOP;
 }
@@ -1662,13 +1738,17 @@
 static int
 __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 {
+	unsigned long ftrace_old_addr;
 	unsigned long ftrace_addr;
 	int ret;
 
-	ftrace_addr = (unsigned long)FTRACE_ADDR;
-
 	ret = ftrace_update_record(rec, enable);
 
+	if (rec->flags & FTRACE_FL_REGS)
+		ftrace_addr = (unsigned long)FTRACE_REGS_ADDR;
+	else
+		ftrace_addr = (unsigned long)FTRACE_ADDR;
+
 	switch (ret) {
 	case FTRACE_UPDATE_IGNORE:
 		return 0;
@@ -1678,6 +1758,15 @@
 
 	case FTRACE_UPDATE_MAKE_NOP:
 		return ftrace_make_nop(NULL, rec, ftrace_addr);
+
+	case FTRACE_UPDATE_MODIFY_CALL_REGS:
+	case FTRACE_UPDATE_MODIFY_CALL:
+		if (rec->flags & FTRACE_FL_REGS)
+			ftrace_old_addr = (unsigned long)FTRACE_ADDR;
+		else
+			ftrace_old_addr = (unsigned long)FTRACE_REGS_ADDR;
+
+		return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr);
 	}
 
 	return -1; /* unknow ftrace bug */
@@ -1882,16 +1971,6 @@
 	 */
 	arch_ftrace_update_code(command);
 
-#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	/*
-	 * For archs that call ftrace_test_stop_func(), we must
-	 * wait till after we update all the function callers
-	 * before we update the callback. This keeps different
-	 * ops that record different functions from corrupting
-	 * each other.
-	 */
-	__ftrace_trace_function = __ftrace_trace_function_delay;
-#endif
 	function_trace_stop--;
 
 	ret = ftrace_arch_code_modify_post_process();
@@ -2441,8 +2520,9 @@
 
 	seq_printf(m, "%ps", (void *)rec->ip);
 	if (iter->flags & FTRACE_ITER_ENABLED)
-		seq_printf(m, " (%ld)",
-			   rec->flags & ~FTRACE_FL_MASK);
+		seq_printf(m, " (%ld)%s",
+			   rec->flags & ~FTRACE_FL_MASK,
+			   rec->flags & FTRACE_FL_REGS ? " R" : "");
 	seq_printf(m, "\n");
 
 	return 0;
@@ -2790,8 +2870,8 @@
 }
 device_initcall(ftrace_mod_cmd_init);
 
-static void
-function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
+static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
+				      struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct ftrace_func_probe *entry;
 	struct hlist_head *hhd;
@@ -3162,8 +3242,27 @@
 }
 
 static int
-ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
-		 int reset, int enable)
+ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
+{
+	struct ftrace_func_entry *entry;
+
+	if (!ftrace_location(ip))
+		return -EINVAL;
+
+	if (remove) {
+		entry = ftrace_lookup_ip(hash, ip);
+		if (!entry)
+			return -ENOENT;
+		free_hash_entry(hash, entry);
+		return 0;
+	}
+
+	return add_hash_entry(hash, ip);
+}
+
+static int
+ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
+		unsigned long ip, int remove, int reset, int enable)
 {
 	struct ftrace_hash **orig_hash;
 	struct ftrace_hash *hash;
@@ -3192,6 +3291,11 @@
 		ret = -EINVAL;
 		goto out_regex_unlock;
 	}
+	if (ip) {
+		ret = ftrace_match_addr(hash, ip, remove);
+		if (ret < 0)
+			goto out_regex_unlock;
+	}
 
 	mutex_lock(&ftrace_lock);
 	ret = ftrace_hash_move(ops, enable, orig_hash, hash);
@@ -3208,6 +3312,37 @@
 	return ret;
 }
 
+static int
+ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove,
+		int reset, int enable)
+{
+	return ftrace_set_hash(ops, 0, 0, ip, remove, reset, enable);
+}
+
+/**
+ * ftrace_set_filter_ip - set a function to filter on in ftrace by address
+ * @ops - the ops to set the filter with
+ * @ip - the address to add to or remove from the filter.
+ * @remove - non zero to remove the ip from the filter
+ * @reset - non zero to reset all filters before applying this filter.
+ *
+ * Filters denote which functions should be enabled when tracing is enabled
+ * If @ip is NULL, it failes to update filter.
+ */
+int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
+			 int remove, int reset)
+{
+	return ftrace_set_addr(ops, ip, remove, reset, 1);
+}
+EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
+
+static int
+ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
+		 int reset, int enable)
+{
+	return ftrace_set_hash(ops, buf, len, 0, 0, reset, enable);
+}
+
 /**
  * ftrace_set_filter - set a function to filter on in ftrace
  * @ops - the ops to set the filter with
@@ -3912,6 +4047,7 @@
 
 static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static int __init ftrace_nodyn_init(void)
@@ -3942,10 +4078,9 @@
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 static void
-ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip)
+ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
+			struct ftrace_ops *op, struct pt_regs *regs)
 {
-	struct ftrace_ops *op;
-
 	if (unlikely(trace_recursion_test(TRACE_CONTROL_BIT)))
 		return;
 
@@ -3959,7 +4094,7 @@
 	while (op != &ftrace_list_end) {
 		if (!ftrace_function_local_disabled(op) &&
 		    ftrace_ops_test(op, ip))
-			op->func(ip, parent_ip);
+			op->func(ip, parent_ip, op, regs);
 
 		op = rcu_dereference_raw(op->next);
 	};
@@ -3969,13 +4104,18 @@
 
 static struct ftrace_ops control_ops = {
 	.func = ftrace_ops_control_func,
+	.flags = FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
-static void
-ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
+static inline void
+__ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
+		       struct ftrace_ops *ignored, struct pt_regs *regs)
 {
 	struct ftrace_ops *op;
 
+	if (function_trace_stop)
+		return;
+
 	if (unlikely(trace_recursion_test(TRACE_INTERNAL_BIT)))
 		return;
 
@@ -3988,13 +4128,39 @@
 	op = rcu_dereference_raw(ftrace_ops_list);
 	while (op != &ftrace_list_end) {
 		if (ftrace_ops_test(op, ip))
-			op->func(ip, parent_ip);
+			op->func(ip, parent_ip, op, regs);
 		op = rcu_dereference_raw(op->next);
 	};
 	preempt_enable_notrace();
 	trace_recursion_clear(TRACE_INTERNAL_BIT);
 }
 
+/*
+ * Some archs only support passing ip and parent_ip. Even though
+ * the list function ignores the op parameter, we do not want any
+ * C side effects, where a function is called without the caller
+ * sending a third parameter.
+ * Archs are to support both the regs and ftrace_ops at the same time.
+ * If they support ftrace_ops, it is assumed they support regs.
+ * If call backs want to use regs, they must either check for regs
+ * being NULL, or ARCH_SUPPORTS_FTRACE_SAVE_REGS.
+ * Note, ARCH_SUPPORT_SAVE_REGS expects a full regs to be saved.
+ * An architecture can pass partial regs with ftrace_ops and still
+ * set the ARCH_SUPPORT_FTARCE_OPS.
+ */
+#if ARCH_SUPPORTS_FTRACE_OPS
+static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
+				 struct ftrace_ops *op, struct pt_regs *regs)
+{
+	__ftrace_ops_list_func(ip, parent_ip, NULL, regs);
+}
+#else
+static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
+{
+	__ftrace_ops_list_func(ip, parent_ip, NULL, NULL);
+}
+#endif
+
 static void clear_ftrace_swapper(void)
 {
 	struct task_struct *p;
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 49491fa..b32ed0e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2816,7 +2816,7 @@
  * to the buffer after this will fail and return NULL.
  *
  * This is different than ring_buffer_record_disable() as
- * it works like an on/off switch, where as the disable() verison
+ * it works like an on/off switch, where as the disable() version
  * must be paired with a enable().
  */
 void ring_buffer_record_off(struct ring_buffer *buffer)
@@ -2839,7 +2839,7 @@
  * ring_buffer_record_off().
  *
  * This is different than ring_buffer_record_enable() as
- * it works like an on/off switch, where as the enable() verison
+ * it works like an on/off switch, where as the enable() version
  * must be paired with a disable().
  */
 void ring_buffer_record_on(struct ring_buffer *buffer)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 5c38c81..1ec5c1d 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -328,7 +328,7 @@
 unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
 	TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
 	TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
-	TRACE_ITER_IRQ_INFO;
+	TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS;
 
 static int trace_stop_count;
 static DEFINE_RAW_SPINLOCK(tracing_start_lock);
@@ -426,15 +426,15 @@
 
 static int __init set_tracing_thresh(char *str)
 {
-	unsigned long threshhold;
+	unsigned long threshold;
 	int ret;
 
 	if (!str)
 		return 0;
-	ret = strict_strtoul(str, 0, &threshhold);
+	ret = strict_strtoul(str, 0, &threshold);
 	if (ret < 0)
 		return 0;
-	tracing_thresh = threshhold * 1000;
+	tracing_thresh = threshold * 1000;
 	return 1;
 }
 __setup("tracing_thresh=", set_tracing_thresh);
@@ -470,6 +470,7 @@
 	"overwrite",
 	"disable_on_free",
 	"irq-info",
+	"markers",
 	NULL
 };
 
@@ -3886,6 +3887,9 @@
 	if (tracing_disabled)
 		return -EINVAL;
 
+	if (!(trace_flags & TRACE_ITER_MARKERS))
+		return -EINVAL;
+
 	if (cnt > TRACE_BUF_SIZE)
 		cnt = TRACE_BUF_SIZE;
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 55e1f7f..63a2da0 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -472,11 +472,11 @@
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 extern unsigned long ftrace_update_tot_cnt;
+#endif
 #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
 extern int DYN_FTRACE_TEST_NAME(void);
 #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
 extern int DYN_FTRACE_TEST_NAME2(void);
-#endif
 
 extern int ring_buffer_expanded;
 extern bool tracing_selftest_disabled;
@@ -680,6 +680,7 @@
 	TRACE_ITER_OVERWRITE		= 0x200000,
 	TRACE_ITER_STOP_ON_FREE		= 0x400000,
 	TRACE_ITER_IRQ_INFO		= 0x800000,
+	TRACE_ITER_MARKERS		= 0x1000000,
 };
 
 /*
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 8a6d2ee..84b1e04 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -258,7 +258,8 @@
 
 #ifdef CONFIG_FUNCTION_TRACER
 static void
-perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip)
+perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
+			  struct ftrace_ops *ops, struct pt_regs *pt_regs)
 {
 	struct ftrace_entry *entry;
 	struct hlist_head *head;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 29111da..d608d09 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1199,6 +1199,31 @@
 	return 0;
 }
 
+static void event_remove(struct ftrace_event_call *call)
+{
+	ftrace_event_enable_disable(call, 0);
+	if (call->event.funcs)
+		__unregister_ftrace_event(&call->event);
+	list_del(&call->list);
+}
+
+static int event_init(struct ftrace_event_call *call)
+{
+	int ret = 0;
+
+	if (WARN_ON(!call->name))
+		return -EINVAL;
+
+	if (call->class->raw_init) {
+		ret = call->class->raw_init(call);
+		if (ret < 0 && ret != -ENOSYS)
+			pr_warn("Could not initialize trace events/%s\n",
+				call->name);
+	}
+
+	return ret;
+}
+
 static int
 __trace_add_event_call(struct ftrace_event_call *call, struct module *mod,
 		       const struct file_operations *id,
@@ -1209,19 +1234,9 @@
 	struct dentry *d_events;
 	int ret;
 
-	/* The linker may leave blanks */
-	if (!call->name)
-		return -EINVAL;
-
-	if (call->class->raw_init) {
-		ret = call->class->raw_init(call);
-		if (ret < 0) {
-			if (ret != -ENOSYS)
-				pr_warning("Could not initialize trace events/%s\n",
-					   call->name);
-			return ret;
-		}
-	}
+	ret = event_init(call);
+	if (ret < 0)
+		return ret;
 
 	d_events = event_trace_events_dir();
 	if (!d_events)
@@ -1272,13 +1287,10 @@
  */
 static void __trace_remove_event_call(struct ftrace_event_call *call)
 {
-	ftrace_event_enable_disable(call, 0);
-	if (call->event.funcs)
-		__unregister_ftrace_event(&call->event);
-	debugfs_remove_recursive(call->dir);
-	list_del(&call->list);
+	event_remove(call);
 	trace_destroy_fields(call);
 	destroy_preds(call);
+	debugfs_remove_recursive(call->dir);
 	remove_subsystem_dir(call->class->system);
 }
 
@@ -1450,15 +1462,43 @@
 }
 __setup("trace_event=", setup_trace_event);
 
+static __init int event_trace_enable(void)
+{
+	struct ftrace_event_call **iter, *call;
+	char *buf = bootup_event_buf;
+	char *token;
+	int ret;
+
+	for_each_event(iter, __start_ftrace_events, __stop_ftrace_events) {
+
+		call = *iter;
+		ret = event_init(call);
+		if (!ret)
+			list_add(&call->list, &ftrace_events);
+	}
+
+	while (true) {
+		token = strsep(&buf, ",");
+
+		if (!token)
+			break;
+		if (!*token)
+			continue;
+
+		ret = ftrace_set_clr_event(token, 1);
+		if (ret)
+			pr_warn("Failed to enable trace event: %s\n", token);
+	}
+	return 0;
+}
+
 static __init int event_trace_init(void)
 {
-	struct ftrace_event_call **call;
+	struct ftrace_event_call *call;
 	struct dentry *d_tracer;
 	struct dentry *entry;
 	struct dentry *d_events;
 	int ret;
-	char *buf = bootup_event_buf;
-	char *token;
 
 	d_tracer = tracing_init_dentry();
 	if (!d_tracer)
@@ -1497,24 +1537,19 @@
 	if (trace_define_common_fields())
 		pr_warning("tracing: Failed to allocate common fields");
 
-	for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
-		__trace_add_event_call(*call, NULL, &ftrace_event_id_fops,
+	/*
+	 * Early initialization already enabled ftrace event.
+	 * Now it's only necessary to create the event directory.
+	 */
+	list_for_each_entry(call, &ftrace_events, list) {
+
+		ret = event_create_dir(call, d_events,
+				       &ftrace_event_id_fops,
 				       &ftrace_enable_fops,
 				       &ftrace_event_filter_fops,
 				       &ftrace_event_format_fops);
-	}
-
-	while (true) {
-		token = strsep(&buf, ",");
-
-		if (!token)
-			break;
-		if (!*token)
-			continue;
-
-		ret = ftrace_set_clr_event(token, 1);
-		if (ret)
-			pr_warning("Failed to enable trace event: %s\n", token);
+		if (ret < 0)
+			event_remove(call);
 	}
 
 	ret = register_module_notifier(&trace_module_nb);
@@ -1523,6 +1558,7 @@
 
 	return 0;
 }
+core_initcall(event_trace_enable);
 fs_initcall(event_trace_init);
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
@@ -1646,9 +1682,11 @@
 		event_test_stuff();
 
 		ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0);
-		if (WARN_ON_ONCE(ret))
+		if (WARN_ON_ONCE(ret)) {
 			pr_warning("error disabling system %s\n",
 				   system->name);
+			continue;
+		}
 
 		pr_cont("OK\n");
 	}
@@ -1681,7 +1719,8 @@
 static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable);
 
 static void
-function_test_events_call(unsigned long ip, unsigned long parent_ip)
+function_test_events_call(unsigned long ip, unsigned long parent_ip,
+			  struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct ring_buffer_event *event;
 	struct ring_buffer *buffer;
@@ -1720,6 +1759,7 @@
 static struct ftrace_ops trace_ops __initdata  =
 {
 	.func = function_test_events_call,
+	.flags = FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static __init void event_trace_self_test_with_function(void)
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 431dba8..c154797 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -2002,7 +2002,7 @@
 static int __ftrace_function_set_filter(int filter, char *buf, int len,
 					struct function_filter_data *data)
 {
-	int i, re_cnt, ret;
+	int i, re_cnt, ret = -EINVAL;
 	int *reset;
 	char **re;
 
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index a426f41..483162a 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -49,7 +49,8 @@
 }
 
 static void
-function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip)
+function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip,
+				 struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct trace_array *tr = func_trace;
 	struct trace_array_cpu *data;
@@ -84,7 +85,9 @@
 static struct tracer_flags func_flags;
 
 static void
-function_trace_call(unsigned long ip, unsigned long parent_ip)
+function_trace_call(unsigned long ip, unsigned long parent_ip,
+		    struct ftrace_ops *op, struct pt_regs *pt_regs)
+
 {
 	struct trace_array *tr = func_trace;
 	struct trace_array_cpu *data;
@@ -121,7 +124,8 @@
 }
 
 static void
-function_stack_trace_call(unsigned long ip, unsigned long parent_ip)
+function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
+			  struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct trace_array *tr = func_trace;
 	struct trace_array_cpu *data;
@@ -164,13 +168,13 @@
 static struct ftrace_ops trace_ops __read_mostly =
 {
 	.func = function_trace_call,
-	.flags = FTRACE_OPS_FL_GLOBAL,
+	.flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static struct ftrace_ops trace_stack_ops __read_mostly =
 {
 	.func = function_stack_trace_call,
-	.flags = FTRACE_OPS_FL_GLOBAL,
+	.flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static struct tracer_opt func_opts[] = {
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index ce27c8b..99b4378 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -143,7 +143,7 @@
 		return;
 	}
 
-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
+#if defined(CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST) && !defined(CC_USING_FENTRY)
 	/*
 	 * The arch may choose to record the frame pointer used
 	 * and check it here to make sure that it is what we expect it
@@ -154,6 +154,9 @@
 	 *
 	 * Currently, x86_32 with optimize for size (-Os) makes the latest
 	 * gcc do the above.
+	 *
+	 * Note, -mfentry does not use frame pointers, and this test
+	 *  is not needed if CC_USING_FENTRY is set.
 	 */
 	if (unlikely(current->ret_stack[index].fp != frame_pointer)) {
 		ftrace_graph_stop();
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 99d20e9..d98ee82 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -136,7 +136,8 @@
  * irqsoff uses its own tracer function to keep the overhead down:
  */
 static void
-irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
+irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,
+		    struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct trace_array *tr = irqsoff_trace;
 	struct trace_array_cpu *data;
@@ -153,7 +154,7 @@
 static struct ftrace_ops trace_ops __read_mostly =
 {
 	.func = irqsoff_tracer_call,
-	.flags = FTRACE_OPS_FL_GLOBAL,
+	.flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
 
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index ff791ea..02170c0 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -108,7 +108,8 @@
  * wakeup uses its own tracer function to keep the overhead down:
  */
 static void
-wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
+wakeup_tracer_call(unsigned long ip, unsigned long parent_ip,
+		   struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	struct trace_array *tr = wakeup_trace;
 	struct trace_array_cpu *data;
@@ -129,7 +130,7 @@
 static struct ftrace_ops trace_ops __read_mostly =
 {
 	.func = wakeup_tracer_call,
-	.flags = FTRACE_OPS_FL_GLOBAL,
+	.flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
 
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index 288541f..2c00a69 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -103,54 +103,67 @@
 
 static int trace_selftest_test_probe1_cnt;
 static void trace_selftest_test_probe1_func(unsigned long ip,
-					    unsigned long pip)
+					    unsigned long pip,
+					    struct ftrace_ops *op,
+					    struct pt_regs *pt_regs)
 {
 	trace_selftest_test_probe1_cnt++;
 }
 
 static int trace_selftest_test_probe2_cnt;
 static void trace_selftest_test_probe2_func(unsigned long ip,
-					    unsigned long pip)
+					    unsigned long pip,
+					    struct ftrace_ops *op,
+					    struct pt_regs *pt_regs)
 {
 	trace_selftest_test_probe2_cnt++;
 }
 
 static int trace_selftest_test_probe3_cnt;
 static void trace_selftest_test_probe3_func(unsigned long ip,
-					    unsigned long pip)
+					    unsigned long pip,
+					    struct ftrace_ops *op,
+					    struct pt_regs *pt_regs)
 {
 	trace_selftest_test_probe3_cnt++;
 }
 
 static int trace_selftest_test_global_cnt;
 static void trace_selftest_test_global_func(unsigned long ip,
-					    unsigned long pip)
+					    unsigned long pip,
+					    struct ftrace_ops *op,
+					    struct pt_regs *pt_regs)
 {
 	trace_selftest_test_global_cnt++;
 }
 
 static int trace_selftest_test_dyn_cnt;
 static void trace_selftest_test_dyn_func(unsigned long ip,
-					 unsigned long pip)
+					 unsigned long pip,
+					 struct ftrace_ops *op,
+					 struct pt_regs *pt_regs)
 {
 	trace_selftest_test_dyn_cnt++;
 }
 
 static struct ftrace_ops test_probe1 = {
 	.func			= trace_selftest_test_probe1_func,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static struct ftrace_ops test_probe2 = {
 	.func			= trace_selftest_test_probe2_func,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static struct ftrace_ops test_probe3 = {
 	.func			= trace_selftest_test_probe3_func,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static struct ftrace_ops test_global = {
-	.func			= trace_selftest_test_global_func,
-	.flags			= FTRACE_OPS_FL_GLOBAL,
+	.func		= trace_selftest_test_global_func,
+	.flags		= FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static void print_counts(void)
@@ -393,10 +406,253 @@
 
 	return ret;
 }
+
+static int trace_selftest_recursion_cnt;
+static void trace_selftest_test_recursion_func(unsigned long ip,
+					       unsigned long pip,
+					       struct ftrace_ops *op,
+					       struct pt_regs *pt_regs)
+{
+	/*
+	 * This function is registered without the recursion safe flag.
+	 * The ftrace infrastructure should provide the recursion
+	 * protection. If not, this will crash the kernel!
+	 */
+	trace_selftest_recursion_cnt++;
+	DYN_FTRACE_TEST_NAME();
+}
+
+static void trace_selftest_test_recursion_safe_func(unsigned long ip,
+						    unsigned long pip,
+						    struct ftrace_ops *op,
+						    struct pt_regs *pt_regs)
+{
+	/*
+	 * We said we would provide our own recursion. By calling
+	 * this function again, we should recurse back into this function
+	 * and count again. But this only happens if the arch supports
+	 * all of ftrace features and nothing else is using the function
+	 * tracing utility.
+	 */
+	if (trace_selftest_recursion_cnt++)
+		return;
+	DYN_FTRACE_TEST_NAME();
+}
+
+static struct ftrace_ops test_rec_probe = {
+	.func			= trace_selftest_test_recursion_func,
+};
+
+static struct ftrace_ops test_recsafe_probe = {
+	.func			= trace_selftest_test_recursion_safe_func,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE,
+};
+
+static int
+trace_selftest_function_recursion(void)
+{
+	int save_ftrace_enabled = ftrace_enabled;
+	int save_tracer_enabled = tracer_enabled;
+	char *func_name;
+	int len;
+	int ret;
+	int cnt;
+
+	/* The previous test PASSED */
+	pr_cont("PASSED\n");
+	pr_info("Testing ftrace recursion: ");
+
+
+	/* enable tracing, and record the filter function */
+	ftrace_enabled = 1;
+	tracer_enabled = 1;
+
+	/* Handle PPC64 '.' name */
+	func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
+	len = strlen(func_name);
+
+	ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1);
+	if (ret) {
+		pr_cont("*Could not set filter* ");
+		goto out;
+	}
+
+	ret = register_ftrace_function(&test_rec_probe);
+	if (ret) {
+		pr_cont("*could not register callback* ");
+		goto out;
+	}
+
+	DYN_FTRACE_TEST_NAME();
+
+	unregister_ftrace_function(&test_rec_probe);
+
+	ret = -1;
+	if (trace_selftest_recursion_cnt != 1) {
+		pr_cont("*callback not called once (%d)* ",
+			trace_selftest_recursion_cnt);
+		goto out;
+	}
+
+	trace_selftest_recursion_cnt = 1;
+
+	pr_cont("PASSED\n");
+	pr_info("Testing ftrace recursion safe: ");
+
+	ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1);
+	if (ret) {
+		pr_cont("*Could not set filter* ");
+		goto out;
+	}
+
+	ret = register_ftrace_function(&test_recsafe_probe);
+	if (ret) {
+		pr_cont("*could not register callback* ");
+		goto out;
+	}
+
+	DYN_FTRACE_TEST_NAME();
+
+	unregister_ftrace_function(&test_recsafe_probe);
+
+	/*
+	 * If arch supports all ftrace features, and no other task
+	 * was on the list, we should be fine.
+	 */
+	if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC)
+		cnt = 2; /* Should have recursed */
+	else
+		cnt = 1;
+
+	ret = -1;
+	if (trace_selftest_recursion_cnt != cnt) {
+		pr_cont("*callback not called expected %d times (%d)* ",
+			cnt, trace_selftest_recursion_cnt);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	ftrace_enabled = save_ftrace_enabled;
+	tracer_enabled = save_tracer_enabled;
+
+	return ret;
+}
 #else
 # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
+# define trace_selftest_function_recursion() ({ 0; })
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
+static enum {
+	TRACE_SELFTEST_REGS_START,
+	TRACE_SELFTEST_REGS_FOUND,
+	TRACE_SELFTEST_REGS_NOT_FOUND,
+} trace_selftest_regs_stat;
+
+static void trace_selftest_test_regs_func(unsigned long ip,
+					  unsigned long pip,
+					  struct ftrace_ops *op,
+					  struct pt_regs *pt_regs)
+{
+	if (pt_regs)
+		trace_selftest_regs_stat = TRACE_SELFTEST_REGS_FOUND;
+	else
+		trace_selftest_regs_stat = TRACE_SELFTEST_REGS_NOT_FOUND;
+}
+
+static struct ftrace_ops test_regs_probe = {
+	.func		= trace_selftest_test_regs_func,
+	.flags		= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_SAVE_REGS,
+};
+
+static int
+trace_selftest_function_regs(void)
+{
+	int save_ftrace_enabled = ftrace_enabled;
+	int save_tracer_enabled = tracer_enabled;
+	char *func_name;
+	int len;
+	int ret;
+	int supported = 0;
+
+#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+	supported = 1;
+#endif
+
+	/* The previous test PASSED */
+	pr_cont("PASSED\n");
+	pr_info("Testing ftrace regs%s: ",
+		!supported ? "(no arch support)" : "");
+
+	/* enable tracing, and record the filter function */
+	ftrace_enabled = 1;
+	tracer_enabled = 1;
+
+	/* Handle PPC64 '.' name */
+	func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
+	len = strlen(func_name);
+
+	ret = ftrace_set_filter(&test_regs_probe, func_name, len, 1);
+	/*
+	 * If DYNAMIC_FTRACE is not set, then we just trace all functions.
+	 * This test really doesn't care.
+	 */
+	if (ret && ret != -ENODEV) {
+		pr_cont("*Could not set filter* ");
+		goto out;
+	}
+
+	ret = register_ftrace_function(&test_regs_probe);
+	/*
+	 * Now if the arch does not support passing regs, then this should
+	 * have failed.
+	 */
+	if (!supported) {
+		if (!ret) {
+			pr_cont("*registered save-regs without arch support* ");
+			goto out;
+		}
+		test_regs_probe.flags |= FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED;
+		ret = register_ftrace_function(&test_regs_probe);
+	}
+	if (ret) {
+		pr_cont("*could not register callback* ");
+		goto out;
+	}
+
+
+	DYN_FTRACE_TEST_NAME();
+
+	unregister_ftrace_function(&test_regs_probe);
+
+	ret = -1;
+
+	switch (trace_selftest_regs_stat) {
+	case TRACE_SELFTEST_REGS_START:
+		pr_cont("*callback never called* ");
+		goto out;
+
+	case TRACE_SELFTEST_REGS_FOUND:
+		if (supported)
+			break;
+		pr_cont("*callback received regs without arch support* ");
+		goto out;
+
+	case TRACE_SELFTEST_REGS_NOT_FOUND:
+		if (!supported)
+			break;
+		pr_cont("*callback received NULL regs* ");
+		goto out;
+	}
+
+	ret = 0;
+out:
+	ftrace_enabled = save_ftrace_enabled;
+	tracer_enabled = save_tracer_enabled;
+
+	return ret;
+}
+
 /*
  * Simple verification test of ftrace function tracer.
  * Enable ftrace, sleep 1/10 second, and then read the trace
@@ -442,7 +698,14 @@
 
 	ret = trace_selftest_startup_dynamic_tracing(trace, tr,
 						     DYN_FTRACE_TEST_NAME);
+	if (ret)
+		goto out;
 
+	ret = trace_selftest_function_recursion();
+	if (ret)
+		goto out;
+
+	ret = trace_selftest_function_regs();
  out:
 	ftrace_enabled = save_ftrace_enabled;
 	tracer_enabled = save_tracer_enabled;
@@ -778,6 +1041,8 @@
 	set_current_state(TASK_INTERRUPTIBLE);
 	schedule();
 
+	complete(x);
+
 	/* we are awake, now wait to disappear */
 	while (!kthread_should_stop()) {
 		/*
@@ -821,24 +1086,21 @@
 	/* reset the max latency */
 	tracing_max_latency = 0;
 
-	/* sleep to let the RT thread sleep too */
-	msleep(100);
+	while (p->on_rq) {
+		/*
+		 * Sleep to make sure the RT thread is asleep too.
+		 * On virtual machines we can't rely on timings,
+		 * but we want to make sure this test still works.
+		 */
+		msleep(100);
+	}
 
-	/*
-	 * Yes this is slightly racy. It is possible that for some
-	 * strange reason that the RT thread we created, did not
-	 * call schedule for 100ms after doing the completion,
-	 * and we do a wakeup on a task that already is awake.
-	 * But that is extremely unlikely, and the worst thing that
-	 * happens in such a case, is that we disable tracing.
-	 * Honestly, if this race does happen something is horrible
-	 * wrong with the system.
-	 */
+	init_completion(&isrt);
 
 	wake_up_process(p);
 
-	/* give a little time to let the thread wake up */
-	msleep(100);
+	/* Wait for the task to wake up */
+	wait_for_completion(&isrt);
 
 	/* stop the tracing. */
 	tracing_stop();
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index d4545f4..0c1b1657 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -111,7 +111,8 @@
 }
 
 static void
-stack_trace_call(unsigned long ip, unsigned long parent_ip)
+stack_trace_call(unsigned long ip, unsigned long parent_ip,
+		 struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	int cpu;
 
@@ -136,6 +137,7 @@
 static struct ftrace_ops trace_ops __read_mostly =
 {
 	.func = stack_trace_call,
+	.flags = FTRACE_OPS_FL_RECURSION_SAFE,
 };
 
 static ssize_t
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 6b245f64..2485a7d 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -487,7 +487,7 @@
 
 	return 0;
 }
-core_initcall(init_ftrace_syscalls);
+early_initcall(init_ftrace_syscalls);
 
 #ifdef CONFIG_PERF_EVENTS
 
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 4b1dfba..9d4c8d5 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -22,6 +22,7 @@
 #include <linux/notifier.h>
 #include <linux/module.h>
 #include <linux/sysctl.h>
+#include <linux/smpboot.h>
 
 #include <asm/irq_regs.h>
 #include <linux/kvm_para.h>
@@ -29,16 +30,18 @@
 
 int watchdog_enabled = 1;
 int __read_mostly watchdog_thresh = 10;
+static int __read_mostly watchdog_disabled;
 
 static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
 static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
 static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer);
 static DEFINE_PER_CPU(bool, softlockup_touch_sync);
 static DEFINE_PER_CPU(bool, soft_watchdog_warn);
+static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 static DEFINE_PER_CPU(bool, hard_watchdog_warn);
 static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
 static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
@@ -248,13 +251,15 @@
 	__this_cpu_write(hard_watchdog_warn, false);
 	return;
 }
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
 static void watchdog_interrupt_count(void)
 {
 	__this_cpu_inc(hrtimer_interrupts);
 }
-#else
-static inline void watchdog_interrupt_count(void) { return; }
-#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
+static int watchdog_nmi_enable(unsigned int cpu);
+static void watchdog_nmi_disable(unsigned int cpu);
 
 /* watchdog kicker functions */
 static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
@@ -327,49 +332,68 @@
 	return HRTIMER_RESTART;
 }
 
-
-/*
- * The watchdog thread - touches the timestamp.
- */
-static int watchdog(void *unused)
+static void watchdog_set_prio(unsigned int policy, unsigned int prio)
 {
-	struct sched_param param = { .sched_priority = 0 };
+	struct sched_param param = { .sched_priority = prio };
+
+	sched_setscheduler(current, policy, &param);
+}
+
+static void watchdog_enable(unsigned int cpu)
+{
 	struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
-	/* initialize timestamp */
-	__touch_watchdog();
+	if (!watchdog_enabled) {
+		kthread_park(current);
+		return;
+	}
+
+	/* Enable the perf event */
+	watchdog_nmi_enable(cpu);
 
 	/* kick off the timer for the hardlockup detector */
+	hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hrtimer->function = watchdog_timer_fn;
+
 	/* done here because hrtimer_start can only pin to smp_processor_id() */
 	hrtimer_start(hrtimer, ns_to_ktime(get_sample_period()),
 		      HRTIMER_MODE_REL_PINNED);
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	/*
-	 * Run briefly (kicked by the hrtimer callback function) once every
-	 * get_sample_period() seconds (4 seconds by default) to reset the
-	 * softlockup timestamp. If this gets delayed for more than
-	 * 2*watchdog_thresh seconds then the debug-printout triggers in
-	 * watchdog_timer_fn().
-	 */
-	while (!kthread_should_stop()) {
-		__touch_watchdog();
-		schedule();
-
-		if (kthread_should_stop())
-			break;
-
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-	/*
-	 * Drop the policy/priority elevation during thread exit to avoid a
-	 * scheduling latency spike.
-	 */
-	__set_current_state(TASK_RUNNING);
-	sched_setscheduler(current, SCHED_NORMAL, &param);
-	return 0;
+	/* initialize timestamp */
+	watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);
+	__touch_watchdog();
 }
 
+static void watchdog_disable(unsigned int cpu)
+{
+	struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
+
+	watchdog_set_prio(SCHED_NORMAL, 0);
+	hrtimer_cancel(hrtimer);
+	/* disable the perf event */
+	watchdog_nmi_disable(cpu);
+}
+
+static int watchdog_should_run(unsigned int cpu)
+{
+	return __this_cpu_read(hrtimer_interrupts) !=
+		__this_cpu_read(soft_lockup_hrtimer_cnt);
+}
+
+/*
+ * The watchdog thread function - touches the timestamp.
+ *
+ * It only runs once every get_sample_period() seconds (4 seconds by
+ * default) to reset the softlockup timestamp. If this gets delayed
+ * for more than 2*watchdog_thresh seconds then the debug-printout
+ * triggers in watchdog_timer_fn().
+ */
+static void watchdog(unsigned int cpu)
+{
+	__this_cpu_write(soft_lockup_hrtimer_cnt,
+			 __this_cpu_read(hrtimer_interrupts));
+	__touch_watchdog();
+}
 
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 /*
@@ -379,7 +403,7 @@
  */
 static unsigned long cpu0_err;
 
-static int watchdog_nmi_enable(int cpu)
+static int watchdog_nmi_enable(unsigned int cpu)
 {
 	struct perf_event_attr *wd_attr;
 	struct perf_event *event = per_cpu(watchdog_ev, cpu);
@@ -433,7 +457,7 @@
 	return 0;
 }
 
-static void watchdog_nmi_disable(int cpu)
+static void watchdog_nmi_disable(unsigned int cpu)
 {
 	struct perf_event *event = per_cpu(watchdog_ev, cpu);
 
@@ -447,107 +471,35 @@
 	return;
 }
 #else
-static int watchdog_nmi_enable(int cpu) { return 0; }
-static void watchdog_nmi_disable(int cpu) { return; }
+static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
+static void watchdog_nmi_disable(unsigned int cpu) { return; }
 #endif /* CONFIG_HARDLOCKUP_DETECTOR */
 
 /* prepare/enable/disable routines */
-static void watchdog_prepare_cpu(int cpu)
-{
-	struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
-
-	WARN_ON(per_cpu(softlockup_watchdog, cpu));
-	hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	hrtimer->function = watchdog_timer_fn;
-}
-
-static int watchdog_enable(int cpu)
-{
-	struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
-	int err = 0;
-
-	/* enable the perf event */
-	err = watchdog_nmi_enable(cpu);
-
-	/* Regardless of err above, fall through and start softlockup */
-
-	/* create the watchdog thread */
-	if (!p) {
-		struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-		p = kthread_create_on_node(watchdog, NULL, cpu_to_node(cpu), "watchdog/%d", cpu);
-		if (IS_ERR(p)) {
-			pr_err("softlockup watchdog for %i failed\n", cpu);
-			if (!err) {
-				/* if hardlockup hasn't already set this */
-				err = PTR_ERR(p);
-				/* and disable the perf event */
-				watchdog_nmi_disable(cpu);
-			}
-			goto out;
-		}
-		sched_setscheduler(p, SCHED_FIFO, &param);
-		kthread_bind(p, cpu);
-		per_cpu(watchdog_touch_ts, cpu) = 0;
-		per_cpu(softlockup_watchdog, cpu) = p;
-		wake_up_process(p);
-	}
-
-out:
-	return err;
-}
-
-static void watchdog_disable(int cpu)
-{
-	struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
-	struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
-
-	/*
-	 * cancel the timer first to stop incrementing the stats
-	 * and waking up the kthread
-	 */
-	hrtimer_cancel(hrtimer);
-
-	/* disable the perf event */
-	watchdog_nmi_disable(cpu);
-
-	/* stop the watchdog thread */
-	if (p) {
-		per_cpu(softlockup_watchdog, cpu) = NULL;
-		kthread_stop(p);
-	}
-}
-
 /* sysctl functions */
 #ifdef CONFIG_SYSCTL
 static void watchdog_enable_all_cpus(void)
 {
-	int cpu;
+	unsigned int cpu;
 
-	watchdog_enabled = 0;
-
-	for_each_online_cpu(cpu)
-		if (!watchdog_enable(cpu))
-			/* if any cpu succeeds, watchdog is considered
-			   enabled for the system */
-			watchdog_enabled = 1;
-
-	if (!watchdog_enabled)
-		pr_err("failed to be enabled on some cpus\n");
-
+	if (watchdog_disabled) {
+		watchdog_disabled = 0;
+		for_each_online_cpu(cpu)
+			kthread_unpark(per_cpu(softlockup_watchdog, cpu));
+	}
 }
 
 static void watchdog_disable_all_cpus(void)
 {
-	int cpu;
+	unsigned int cpu;
 
-	for_each_online_cpu(cpu)
-		watchdog_disable(cpu);
-
-	/* if all watchdogs are disabled, then they are disabled for the system */
-	watchdog_enabled = 0;
+	if (!watchdog_disabled) {
+		watchdog_disabled = 1;
+		for_each_online_cpu(cpu)
+			kthread_park(per_cpu(softlockup_watchdog, cpu));
+	}
 }
 
-
 /*
  * proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh
  */
@@ -557,73 +509,36 @@
 {
 	int ret;
 
+	if (watchdog_disabled < 0)
+		return -ENODEV;
+
 	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 	if (ret || !write)
-		goto out;
+		return ret;
 
 	if (watchdog_enabled && watchdog_thresh)
 		watchdog_enable_all_cpus();
 	else
 		watchdog_disable_all_cpus();
 
-out:
 	return ret;
 }
 #endif /* CONFIG_SYSCTL */
 
-
-/*
- * Create/destroy watchdog threads as CPUs come and go:
- */
-static int __cpuinit
-cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
-	int hotcpu = (unsigned long)hcpu;
-
-	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		watchdog_prepare_cpu(hotcpu);
-		break;
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		if (watchdog_enabled)
-			watchdog_enable(hotcpu);
-		break;
-#ifdef CONFIG_HOTPLUG_CPU
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-		watchdog_disable(hotcpu);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		watchdog_disable(hotcpu);
-		break;
-#endif /* CONFIG_HOTPLUG_CPU */
-	}
-
-	/*
-	 * hardlockup and softlockup are not important enough
-	 * to block cpu bring up.  Just always succeed and
-	 * rely on printk output to flag problems.
-	 */
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata cpu_nfb = {
-	.notifier_call = cpu_callback
+static struct smp_hotplug_thread watchdog_threads = {
+	.store			= &softlockup_watchdog,
+	.thread_should_run	= watchdog_should_run,
+	.thread_fn		= watchdog,
+	.thread_comm		= "watchdog/%u",
+	.setup			= watchdog_enable,
+	.park			= watchdog_disable,
+	.unpark			= watchdog_enable,
 };
 
 void __init lockup_detector_init(void)
 {
-	void *cpu = (void *)(long)smp_processor_id();
-	int err;
-
-	err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
-	WARN_ON(notifier_to_errno(err));
-
-	cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
-	register_cpu_notifier(&cpu_nfb);
-
-	return;
+	if (smpboot_register_percpu_thread(&watchdog_threads)) {
+		pr_err("Failed to create watchdog threads, disabled\n");
+		watchdog_disabled = -ENODEV;
+	}
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 1e1373b..3c5a79e 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1349,8 +1349,16 @@
 	struct worker *worker = container_of(work, struct worker, rebind_work);
 	struct global_cwq *gcwq = worker->pool->gcwq;
 
-	if (worker_maybe_bind_and_lock(worker))
-		worker_clr_flags(worker, WORKER_REBIND);
+	worker_maybe_bind_and_lock(worker);
+
+	/*
+	 * %WORKER_REBIND must be cleared even if the above binding failed;
+	 * otherwise, we may confuse the next CPU_UP cycle or oops / get
+	 * stuck by calling idle_worker_rebind() prematurely.  If CPU went
+	 * down again inbetween, %WORKER_UNBOUND would be set, so clearing
+	 * %WORKER_REBIND is always safe.
+	 */
+	worker_clr_flags(worker, WORKER_REBIND);
 
 	spin_unlock_irq(&gcwq->lock);
 }
@@ -3568,18 +3576,17 @@
 #ifdef CONFIG_SMP
 
 struct work_for_cpu {
-	struct completion completion;
+	struct work_struct work;
 	long (*fn)(void *);
 	void *arg;
 	long ret;
 };
 
-static int do_work_for_cpu(void *_wfc)
+static void work_for_cpu_fn(struct work_struct *work)
 {
-	struct work_for_cpu *wfc = _wfc;
+	struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work);
+
 	wfc->ret = wfc->fn(wfc->arg);
-	complete(&wfc->completion);
-	return 0;
 }
 
 /**
@@ -3594,19 +3601,11 @@
  */
 long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
 {
-	struct task_struct *sub_thread;
-	struct work_for_cpu wfc = {
-		.completion = COMPLETION_INITIALIZER_ONSTACK(wfc.completion),
-		.fn = fn,
-		.arg = arg,
-	};
+	struct work_for_cpu wfc = { .fn = fn, .arg = arg };
 
-	sub_thread = kthread_create(do_work_for_cpu, &wfc, "work_for_cpu");
-	if (IS_ERR(sub_thread))
-		return PTR_ERR(sub_thread);
-	kthread_bind(sub_thread, cpu);
-	wake_up_process(sub_thread);
-	wait_for_completion(&wfc.completion);
+	INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
+	schedule_work_on(cpu, &wfc.work);
+	flush_work(&wfc.work);
 	return wfc.ret;
 }
 EXPORT_SYMBOL_GPL(work_on_cpu);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2403a63..35c4565 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -452,7 +452,8 @@
 config DEBUG_KMEMLEAK
 	bool "Kernel memory leak detector"
 	depends on DEBUG_KERNEL && EXPERIMENTAL && \
-		(X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
+		(X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || \
+		 MICROBLAZE || TILE || ARM64)
 
 	select DEBUG_FS
 	select STACKTRACE if STACKTRACE_SUPPORT
@@ -629,6 +630,20 @@
 
 	 Say N if you are unsure.
 
+config PROVE_RCU_DELAY
+	bool "RCU debugging: preemptible RCU race provocation"
+	depends on DEBUG_KERNEL && PREEMPT_RCU
+	default n
+	help
+	 There is a class of races that involve an unlikely preemption
+	 of __rcu_read_unlock() just after ->rcu_read_lock_nesting has
+	 been set to INT_MIN.  This feature inserts a delay at that
+	 point to increase the probability of these races.
+
+	 Say Y to increase probability of preemption of __rcu_read_unlock().
+
+	 Say N if you are unsure.
+
 config SPARSE_RCU_POINTER
 	bool "RCU debugging: sparse-based checks for pointer usage"
 	default n
@@ -739,7 +754,8 @@
 	bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
 	depends on BUG
 	depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \
-		   FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || TILE
+		   FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || \
+		   TILE || ARM64
 	default y
 	help
 	  Say Y here to make BUG() panics output the file name and line number
diff --git a/lib/bcd.c b/lib/bcd.c
index 55efaf7..40d304e 100644
--- a/lib/bcd.c
+++ b/lib/bcd.c
@@ -1,14 +1,14 @@
 #include <linux/bcd.h>
 #include <linux/export.h>
 
-unsigned bcd2bin(unsigned char val)
+unsigned _bcd2bin(unsigned char val)
 {
 	return (val & 0x0f) + (val >> 4) * 10;
 }
-EXPORT_SYMBOL(bcd2bin);
+EXPORT_SYMBOL(_bcd2bin);
 
-unsigned char bin2bcd(unsigned val)
+unsigned char _bin2bcd(unsigned val)
 {
 	return ((val / 10) << 4) + val % 10;
 }
-EXPORT_SYMBOL(bin2bcd);
+EXPORT_SYMBOL(_bin2bcd);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 7ca29a0..e7f7d99 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -521,25 +521,25 @@
 	int pos_after_tid;
 	int pos = 0;
 
-	pos += snprintf(buf + pos, remaining(pos), "%s", KERN_DEBUG);
+	*buf = '\0';
+
 	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
 		if (in_interrupt())
-			pos += snprintf(buf + pos, remaining(pos), "%s ",
-						"<intr>");
+			pos += snprintf(buf + pos, remaining(pos), "<intr> ");
 		else
 			pos += snprintf(buf + pos, remaining(pos), "[%d] ",
-						task_pid_vnr(current));
+					task_pid_vnr(current));
 	}
 	pos_after_tid = pos;
 	if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
 		pos += snprintf(buf + pos, remaining(pos), "%s:",
-					desc->modname);
+				desc->modname);
 	if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
 		pos += snprintf(buf + pos, remaining(pos), "%s:",
-					desc->function);
+				desc->function);
 	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
 		pos += snprintf(buf + pos, remaining(pos), "%d:",
-					desc->lineno);
+				desc->lineno);
 	if (pos - pos_after_tid)
 		pos += snprintf(buf + pos, remaining(pos), " ");
 	if (pos >= PREFIX_SIZE)
@@ -559,9 +559,13 @@
 	BUG_ON(!fmt);
 
 	va_start(args, fmt);
+
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	res = printk("%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
+
+	res = printk(KERN_DEBUG "%s%pV",
+		     dynamic_emit_prefix(descriptor, buf), &vaf);
+
 	va_end(args);
 
 	return res;
@@ -574,15 +578,26 @@
 	struct va_format vaf;
 	va_list args;
 	int res;
-	char buf[PREFIX_SIZE];
 
 	BUG_ON(!descriptor);
 	BUG_ON(!fmt);
 
 	va_start(args, fmt);
+
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	res = __dev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+
+	if (!dev) {
+		res = printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
+	} else {
+		char buf[PREFIX_SIZE];
+
+		res = dev_printk_emit(7, dev, "%s%s %s: %pV",
+				      dynamic_emit_prefix(descriptor, buf),
+				      dev_driver_string(dev), dev_name(dev),
+				      &vaf);
+	}
+
 	va_end(args);
 
 	return res;
@@ -592,20 +607,35 @@
 #ifdef CONFIG_NET
 
 int __dynamic_netdev_dbg(struct _ddebug *descriptor,
-		      const struct net_device *dev, const char *fmt, ...)
+			 const struct net_device *dev, const char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list args;
 	int res;
-	char buf[PREFIX_SIZE];
 
 	BUG_ON(!descriptor);
 	BUG_ON(!fmt);
 
 	va_start(args, fmt);
+
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	res = __netdev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+
+	if (dev && dev->dev.parent) {
+		char buf[PREFIX_SIZE];
+
+		res = dev_printk_emit(7, dev->dev.parent,
+				      "%s%s %s %s: %pV",
+				      dynamic_emit_prefix(descriptor, buf),
+				      dev_driver_string(dev->dev.parent),
+				      dev_name(dev->dev.parent),
+				      netdev_name(dev), &vaf);
+	} else if (dev) {
+		res = printk(KERN_DEBUG "%s: %pV", netdev_name(dev), &vaf);
+	} else {
+		res = printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
+	}
+
 	va_end(args);
 
 	return res;
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c
index c785554..ebf3bac 100644
--- a/lib/flex_proportions.c
+++ b/lib/flex_proportions.c
@@ -62,7 +62,7 @@
  */
 bool fprop_new_period(struct fprop_global *p, int periods)
 {
-	u64 events;
+	s64 events;
 	unsigned long flags;
 
 	local_irq_save(flags);
diff --git a/mm/bootmem.c b/mm/bootmem.c
index bcb63ac..f468185 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -419,7 +419,7 @@
 }
 
 /**
- * reserve_bootmem - mark a page range as usable
+ * reserve_bootmem - mark a page range as reserved
  * @addr: starting address of the range
  * @size: size of the range in bytes
  * @flags: reservation flags (see linux/bootmem.h)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 57c4b93..141dbb6 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1811,7 +1811,6 @@
 			src_page = pte_page(pteval);
 			copy_user_highpage(page, src_page, address, vma);
 			VM_BUG_ON(page_mapcount(src_page) != 1);
-			VM_BUG_ON(page_count(src_page) != 2);
 			release_pte_page(src_page);
 			/*
 			 * ptl mostly unnecessary, but preempt has to
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 45eb621..0de83b4 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1483,13 +1483,11 @@
 {
 	struct kmemleak_object *prev_obj = v;
 	struct kmemleak_object *next_obj = NULL;
-	struct list_head *n = &prev_obj->object_list;
+	struct kmemleak_object *obj = prev_obj;
 
 	++(*pos);
 
-	list_for_each_continue_rcu(n, &object_list) {
-		struct kmemleak_object *obj =
-			list_entry(n, struct kmemleak_object, object_list);
+	list_for_each_entry_continue_rcu(obj, &object_list, object_list) {
 		if (get_object(obj)) {
 			next_obj = obj;
 			break;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 3ad25f9..6a5b90d 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -126,9 +126,6 @@
 	struct mem_section *ms;
 	struct page *page, *memmap;
 
-	if (!pfn_valid(start_pfn))
-		return;
-
 	section_nr = pfn_to_section_nr(start_pfn);
 	ms = __nr_to_section(section_nr);
 
@@ -187,9 +184,16 @@
 	end_pfn = pfn + pgdat->node_spanned_pages;
 
 	/* register_section info */
-	for (; pfn < end_pfn; pfn += PAGES_PER_SECTION)
-		register_page_bootmem_info_section(pfn);
-
+	for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+		/*
+		 * Some platforms can assign the same pfn to multiple nodes - on
+		 * node0 as well as nodeN.  To avoid registering a pfn against
+		 * multiple nodes we check that this pfn does not already
+		 * reside in some other node.
+		 */
+		if (pfn_valid(pfn) && (pfn_to_nid(pfn) == node))
+			register_page_bootmem_info_section(pfn);
+	}
 }
 #endif /* !CONFIG_SPARSEMEM_VMEMMAP */
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c66fb87..c13ea75 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -584,7 +584,7 @@
 		combined_idx = buddy_idx & page_idx;
 		higher_page = page + (combined_idx - page_idx);
 		buddy_idx = __find_buddy_index(combined_idx, order + 1);
-		higher_buddy = page + (buddy_idx - combined_idx);
+		higher_buddy = higher_page + (buddy_idx - combined_idx);
 		if (page_is_buddy(higher_page, higher_buddy, order + 1)) {
 			list_add_tail(&page->lru,
 				&zone->free_area[order].free_list[migratetype]);
diff --git a/mm/slab.c b/mm/slab.c
index 811af03..c685475 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -983,7 +983,7 @@
 		}
 
 		/* The caller cannot use PFMEMALLOC objects, find another one */
-		for (i = 1; i < ac->avail; i++) {
+		for (i = 0; i < ac->avail; i++) {
 			/* If a !PFMEMALLOC object is found, swap them */
 			if (!is_obj_pfmemalloc(ac->entry[i])) {
 				objp = ac->entry[i];
@@ -1000,7 +1000,7 @@
 		l3 = cachep->nodelists[numa_mem_id()];
 		if (!list_empty(&l3->slabs_free) && force_refill) {
 			struct slab *slabp = virt_to_slab(objp);
-			ClearPageSlabPfmemalloc(virt_to_page(slabp->s_mem));
+			ClearPageSlabPfmemalloc(virt_to_head_page(slabp->s_mem));
 			clear_obj_pfmemalloc(&objp);
 			recheck_pfmemalloc_active(cachep, ac);
 			return objp;
@@ -1032,7 +1032,7 @@
 {
 	if (unlikely(pfmemalloc_active)) {
 		/* Some pfmemalloc slabs exist, check if this is one */
-		struct page *page = virt_to_page(objp);
+		struct page *page = virt_to_head_page(objp);
 		if (PageSlabPfmemalloc(page))
 			set_obj_pfmemalloc(&objp);
 	}
diff --git a/mm/slub.c b/mm/slub.c
index 8f78e25..2fdd96f 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1524,12 +1524,13 @@
 }
 
 static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain);
+static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags);
 
 /*
  * Try to allocate a partial slab from a specific node.
  */
-static void *get_partial_node(struct kmem_cache *s,
-		struct kmem_cache_node *n, struct kmem_cache_cpu *c)
+static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
+				struct kmem_cache_cpu *c, gfp_t flags)
 {
 	struct page *page, *page2;
 	void *object = NULL;
@@ -1545,9 +1546,13 @@
 
 	spin_lock(&n->list_lock);
 	list_for_each_entry_safe(page, page2, &n->partial, lru) {
-		void *t = acquire_slab(s, n, page, object == NULL);
+		void *t;
 		int available;
 
+		if (!pfmemalloc_match(page, flags))
+			continue;
+
+		t = acquire_slab(s, n, page, object == NULL);
 		if (!t)
 			break;
 
@@ -1614,7 +1619,7 @@
 
 			if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
 					n->nr_partial > s->min_partial) {
-				object = get_partial_node(s, n, c);
+				object = get_partial_node(s, n, c, flags);
 				if (object) {
 					/*
 					 * Return the object even if
@@ -1643,7 +1648,7 @@
 	void *object;
 	int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
 
-	object = get_partial_node(s, get_node(s, searchnode), c);
+	object = get_partial_node(s, get_node(s, searchnode), c, flags);
 	if (object || node != NUMA_NO_NODE)
 		return object;
 
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 8d01243..99b434b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3102,6 +3102,7 @@
 		/* failure at boot is fatal */
 		BUG_ON(system_state == SYSTEM_BOOTING);
 		printk("Failed to start kswapd on node %d\n",nid);
+		pgdat->kswapd = NULL;
 		ret = -1;
 	}
 	return ret;
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index c718fd3..4de77ea 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -105,7 +105,7 @@
 };
 
 /*
- * Proc filesystem derectory entries.
+ * Proc filesystem directory entries.
  */
 
 /* Strings */
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index e877af8..469daab 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -642,7 +642,8 @@
 	struct batadv_neigh_node *router = NULL;
 	struct batadv_orig_node *orig_node_tmp;
 	struct hlist_node *node;
-	uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
+	int if_num;
+	uint8_t sum_orig, sum_neigh;
 	uint8_t *neigh_addr;
 
 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
@@ -727,17 +728,17 @@
 	if (router && (neigh_node->tq_avg == router->tq_avg)) {
 		orig_node_tmp = router->orig_node;
 		spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
-		bcast_own_sum_orig =
-			orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+		if_num = router->if_incoming->if_num;
+		sum_orig = orig_node_tmp->bcast_own_sum[if_num];
 		spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
 
 		orig_node_tmp = neigh_node->orig_node;
 		spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
-		bcast_own_sum_neigh =
-			orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+		if_num = neigh_node->if_incoming->if_num;
+		sum_neigh = orig_node_tmp->bcast_own_sum[if_num];
 		spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
 
-		if (bcast_own_sum_orig >= bcast_own_sum_neigh)
+		if (sum_orig >= sum_neigh)
 			goto update_tt;
 	}
 
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h
index a081ce1..cebaae7 100644
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@ -20,8 +20,8 @@
 #ifndef _NET_BATMAN_ADV_BITARRAY_H_
 #define _NET_BATMAN_ADV_BITARRAY_H_
 
-/* returns true if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno
+/* Returns 1 if the corresponding bit in the given seq_bits indicates true
+ * and curr_seqno is within range of last_seqno. Otherwise returns 0.
  */
 static inline int batadv_test_bit(const unsigned long *seq_bits,
 				  uint32_t last_seqno, uint32_t curr_seqno)
@@ -32,7 +32,7 @@
 	if (diff < 0 || diff >= BATADV_TQ_LOCAL_WINDOW_SIZE)
 		return 0;
 	else
-		return  test_bit(diff, seq_bits);
+		return test_bit(diff, seq_bits) != 0;
 }
 
 /* turn corresponding bit on, so we can remember that we got the packet */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 109ea2a..21c5357 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -100,18 +100,21 @@
 {
 	struct batadv_priv *bat_priv = netdev_priv(dev);
 	struct sockaddr *addr = p;
+	uint8_t old_addr[ETH_ALEN];
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
+	memcpy(old_addr, dev->dev_addr, ETH_ALEN);
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
 	/* only modify transtable if it has been initialized before */
 	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) {
-		batadv_tt_local_remove(bat_priv, dev->dev_addr,
+		batadv_tt_local_remove(bat_priv, old_addr,
 				       "mac address changed", false);
 		batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX);
 	}
 
-	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	return 0;
 }
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 5e5f5b4..1eaacf1 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -58,7 +58,7 @@
 	switch (cmd) {
 	case BNEPCONNADD:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&ca, argp, sizeof(ca)))
 			return -EFAULT;
@@ -84,7 +84,7 @@
 
 	case BNEPCONNDEL:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&cd, argp, sizeof(cd)))
 			return -EFAULT;
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 311668d..32dc83d 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -72,7 +72,7 @@
 	switch (cmd) {
 	case CMTPCONNADD:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&ca, argp, sizeof(ca)))
 			return -EFAULT;
@@ -97,7 +97,7 @@
 
 	case CMTPCONNDEL:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&cd, argp, sizeof(cd)))
 			return -EFAULT;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d4de5db..0b997c8f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -734,6 +734,8 @@
 
 	cancel_work_sync(&hdev->le_scan);
 
+	cancel_delayed_work(&hdev->power_off);
+
 	hci_req_cancel(hdev, ENODEV);
 	hci_req_lock(hdev);
 
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 19fdac7..d5ace1e 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -490,7 +490,7 @@
 	switch (cmd) {
 	case HCISETRAW:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
 			return -EPERM;
@@ -510,12 +510,12 @@
 
 	case HCIBLOCKADDR:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_sock_blacklist_add(hdev, (void __user *) arg);
 
 	case HCIUNBLOCKADDR:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_sock_blacklist_del(hdev, (void __user *) arg);
 
 	default:
@@ -546,22 +546,22 @@
 
 	case HCIDEVUP:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_dev_open(arg);
 
 	case HCIDEVDOWN:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_dev_close(arg);
 
 	case HCIDEVRESET:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_dev_reset(arg);
 
 	case HCIDEVRESTAT:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_dev_reset_stat(arg);
 
 	case HCISETSCAN:
@@ -573,7 +573,7 @@
 	case HCISETACLMTU:
 	case HCISETSCOMTU:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 		return hci_dev_cmd(cmd, argp);
 
 	case HCIINQUIRY:
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 18b3f68..b24fb3b 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -56,7 +56,7 @@
 	switch (cmd) {
 	case HIDPCONNADD:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&ca, argp, sizeof(ca)))
 			return -EFAULT;
@@ -91,7 +91,7 @@
 
 	case HIDPCONNDEL:
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			return -EPERM;
 
 		if (copy_from_user(&cd, argp, sizeof(cd)))
 			return -EFAULT;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4ea1710..38c00f1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1008,7 +1008,7 @@
 	if (!conn)
 		return;
 
-	if (chan->mode == L2CAP_MODE_ERTM) {
+	if (chan->mode == L2CAP_MODE_ERTM && chan->state == BT_CONNECTED) {
 		__clear_retrans_timer(chan);
 		__clear_monitor_timer(chan);
 		__clear_ack_timer(chan);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ad6613d..eba022d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2875,6 +2875,22 @@
 		if (scan)
 			hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 
+		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+			u8 ssp = 1;
+
+			hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
+		}
+
+		if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+			struct hci_cp_write_le_host_supported cp;
+
+			cp.le = 1;
+			cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+
+			hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+				     sizeof(cp), &cp);
+		}
+
 		update_class(hdev);
 		update_name(hdev, hdev->dev_name);
 		update_eir(hdev);
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 24c5eea..159aa8b 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -1073,16 +1073,13 @@
 			BUG_ON(kaddr == NULL);
 			base = kaddr + con->out_msg_pos.page_pos + bio_offset;
 			crc = crc32c(crc, base, len);
+			kunmap(page);
 			msg->footer.data_crc = cpu_to_le32(crc);
 			con->out_msg_pos.did_page_crc = true;
 		}
 		ret = ceph_tcp_sendpage(con->sock, page,
 				      con->out_msg_pos.page_pos + bio_offset,
 				      len, 1);
-
-		if (do_datacrc)
-			kunmap(page);
-
 		if (ret <= 0)
 			goto out;
 
diff --git a/net/core/dev.c b/net/core/dev.c
index d7fe32c..36c4a0c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2134,7 +2134,8 @@
 static netdev_features_t harmonize_features(struct sk_buff *skb,
 	__be16 protocol, netdev_features_t features)
 {
-	if (!can_checksum_protocol(features, protocol)) {
+	if (skb->ip_summed != CHECKSUM_NONE &&
+	    !can_checksum_protocol(features, protocol)) {
 		features &= ~NETIF_F_ALL_CSUM;
 		features &= ~NETIF_F_SG;
 	} else if (illegal_highdma(skb->dev, skb)) {
@@ -3322,7 +3323,7 @@
 
 	if (pt_prev) {
 		if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
-			ret = -ENOMEM;
+			goto drop;
 		else
 			ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 	} else {
@@ -6423,22 +6424,26 @@
 	return empty;
 }
 
-int __netdev_printk(const char *level, const struct net_device *dev,
+static int __netdev_printk(const char *level, const struct net_device *dev,
 			   struct va_format *vaf)
 {
 	int r;
 
-	if (dev && dev->dev.parent)
-		r = dev_printk(level, dev->dev.parent, "%s: %pV",
-			       netdev_name(dev), vaf);
-	else if (dev)
+	if (dev && dev->dev.parent) {
+		r = dev_printk_emit(level[1] - '0',
+				    dev->dev.parent,
+				    "%s %s %s: %pV",
+				    dev_driver_string(dev->dev.parent),
+				    dev_name(dev->dev.parent),
+				    netdev_name(dev), vaf);
+	} else if (dev) {
 		r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
-	else
+	} else {
 		r = printk("%s(NULL net_device): %pV", level, vaf);
+	}
 
 	return r;
 }
-EXPORT_SYMBOL(__netdev_printk);
 
 int netdev_printk(const char *level, const struct net_device *dev,
 		  const char *format, ...)
@@ -6453,6 +6458,7 @@
 	vaf.va = &args;
 
 	r = __netdev_printk(level, dev, &vaf);
+
 	va_end(args);
 
 	return r;
@@ -6472,6 +6478,7 @@
 	vaf.va = &args;						\
 								\
 	r = __netdev_printk(level, dev, &vaf);			\
+								\
 	va_end(args);						\
 								\
 	return r;						\
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index fe00d12..e33ebae 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3502,7 +3502,9 @@
 	if (!skb_cloned(from))
 		skb_shinfo(from)->nr_frags = 0;
 
-	/* if the skb is cloned this does nothing since we set nr_frags to 0 */
+	/* if the skb is not cloned this does nothing
+	 * since we set nr_frags to 0.
+	 */
 	for (i = 0; i < skb_shinfo(from)->nr_frags; i++)
 		skb_frag_ref(from, i);
 
diff --git a/net/core/sock.c b/net/core/sock.c
index 3057920..a6000fb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -691,7 +691,8 @@
 
 	case SO_KEEPALIVE:
 #ifdef CONFIG_INET
-		if (sk->sk_protocol == IPPROTO_TCP)
+		if (sk->sk_protocol == IPPROTO_TCP &&
+		    sk->sk_type == SOCK_STREAM)
 			tcp_set_keepalive(sk, valbool);
 #endif
 		sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 77e87af..4780045 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1225,7 +1225,7 @@
 	switch (event) {
 	case NETDEV_CHANGEADDR:
 		neigh_changeaddr(&arp_tbl, dev);
-		rt_cache_flush(dev_net(dev), 0);
+		rt_cache_flush(dev_net(dev));
 		break;
 	default:
 		break;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 44bf82e..e12fad7 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -725,7 +725,7 @@
 		break;
 
 	case SIOCSIFFLAGS:
-		ret = -EACCES;
+		ret = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
 			goto out;
 		break;
@@ -733,7 +733,7 @@
 	case SIOCSIFBRDADDR:	/* Set the broadcast address */
 	case SIOCSIFDSTADDR:	/* Set the destination address */
 	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
-		ret = -EACCES;
+		ret = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
 			goto out;
 		ret = -EINVAL;
@@ -1503,7 +1503,7 @@
 		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
 		    i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
 			if ((new_value == 0) && (old_value != 0))
-				rt_cache_flush(net, 0);
+				rt_cache_flush(net);
 	}
 
 	return ret;
@@ -1537,7 +1537,7 @@
 				dev_disable_lro(idev->dev);
 			}
 			rtnl_unlock();
-			rt_cache_flush(net, 0);
+			rt_cache_flush(net);
 		}
 	}
 
@@ -1554,7 +1554,7 @@
 	struct net *net = ctl->extra2;
 
 	if (write && *valp != val)
-		rt_cache_flush(net, 0);
+		rt_cache_flush(net);
 
 	return ret;
 }
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index c43ae3f..8e2b475 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -148,7 +148,7 @@
 	}
 
 	if (flushed)
-		rt_cache_flush(net, -1);
+		rt_cache_flush(net);
 }
 
 /*
@@ -999,11 +999,11 @@
 	net->ipv4.fibnl = NULL;
 }
 
-static void fib_disable_ip(struct net_device *dev, int force, int delay)
+static void fib_disable_ip(struct net_device *dev, int force)
 {
 	if (fib_sync_down_dev(dev, force))
 		fib_flush(dev_net(dev));
-	rt_cache_flush(dev_net(dev), delay);
+	rt_cache_flush(dev_net(dev));
 	arp_ifdown(dev);
 }
 
@@ -1020,7 +1020,7 @@
 		fib_sync_up(dev);
 #endif
 		atomic_inc(&net->ipv4.dev_addr_genid);
-		rt_cache_flush(dev_net(dev), -1);
+		rt_cache_flush(dev_net(dev));
 		break;
 	case NETDEV_DOWN:
 		fib_del_ifaddr(ifa, NULL);
@@ -1029,9 +1029,9 @@
 			/* Last address was deleted from this interface.
 			 * Disable IP.
 			 */
-			fib_disable_ip(dev, 1, 0);
+			fib_disable_ip(dev, 1);
 		} else {
-			rt_cache_flush(dev_net(dev), -1);
+			rt_cache_flush(dev_net(dev));
 		}
 		break;
 	}
@@ -1045,7 +1045,7 @@
 	struct net *net = dev_net(dev);
 
 	if (event == NETDEV_UNREGISTER) {
-		fib_disable_ip(dev, 2, -1);
+		fib_disable_ip(dev, 2);
 		rt_flush_dev(dev);
 		return NOTIFY_DONE;
 	}
@@ -1062,14 +1062,14 @@
 		fib_sync_up(dev);
 #endif
 		atomic_inc(&net->ipv4.dev_addr_genid);
-		rt_cache_flush(dev_net(dev), -1);
+		rt_cache_flush(dev_net(dev));
 		break;
 	case NETDEV_DOWN:
-		fib_disable_ip(dev, 0, 0);
+		fib_disable_ip(dev, 0);
 		break;
 	case NETDEV_CHANGEMTU:
 	case NETDEV_CHANGE:
-		rt_cache_flush(dev_net(dev), 0);
+		rt_cache_flush(dev_net(dev));
 		break;
 	case NETDEV_UNREGISTER_BATCH:
 		break;
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index a83d74e..274309d 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -259,7 +259,7 @@
 
 static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
 {
-	rt_cache_flush(ops->fro_net, -1);
+	rt_cache_flush(ops->fro_net);
 }
 
 static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = {
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 57bd978..d1b9359 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1286,7 +1286,7 @@
 
 			fib_release_info(fi_drop);
 			if (state & FA_S_ACCESSED)
-				rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
+				rt_cache_flush(cfg->fc_nlinfo.nl_net);
 			rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
 				tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
 
@@ -1333,7 +1333,7 @@
 	list_add_tail_rcu(&new_fa->fa_list,
 			  (fa ? &fa->fa_list : fa_head));
 
-	rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
+	rt_cache_flush(cfg->fc_nlinfo.nl_net);
 	rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
 		  &cfg->fc_nlinfo, 0);
 succeeded:
@@ -1708,7 +1708,7 @@
 		trie_leaf_remove(t, l);
 
 	if (fa->fa_state & FA_S_ACCESSED)
-		rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
+		rt_cache_flush(cfg->fc_nlinfo.nl_net);
 
 	fib_release_info(fa->fa_info);
 	alias_free_mem_rcu(fa);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index e1e0a4e..c7527f6 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -510,7 +510,10 @@
 					secure_ipv6_id(daddr->addr.a6));
 		p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
 		p->rate_tokens = 0;
-		p->rate_last = 0;
+		/* 60*HZ is arbitrary, but chosen enough high so that the first
+		 * calculation of tokens is at its maximum.
+		 */
+		p->rate_last = jiffies - 60*HZ;
 		INIT_LIST_HEAD(&p->gc_list);
 
 		/* Link the node. */
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index ff0f071..d23c657 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -131,18 +131,20 @@
  *	0 - deliver
  *	1 - block
  */
-static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
+static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
 {
-	int type;
+	struct icmphdr _hdr;
+	const struct icmphdr *hdr;
 
-	if (!pskb_may_pull(skb, sizeof(struct icmphdr)))
+	hdr = skb_header_pointer(skb, skb_transport_offset(skb),
+				 sizeof(_hdr), &_hdr);
+	if (!hdr)
 		return 1;
 
-	type = icmp_hdr(skb)->type;
-	if (type < 32) {
+	if (hdr->type < 32) {
 		__u32 data = raw_sk(sk)->filter.data;
 
-		return ((1 << type) & data) != 0;
+		return ((1U << hdr->type) & data) != 0;
 	}
 
 	/* Do not block unknown ICMP types */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 82cf2a7..fd9af60 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -202,11 +202,6 @@
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 #define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
 
-static inline int rt_genid(struct net *net)
-{
-	return atomic_read(&net->ipv4.rt_genid);
-}
-
 #ifdef CONFIG_PROC_FS
 static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
 {
@@ -447,27 +442,9 @@
 	return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
 }
 
-/*
- * Perturbation of rt_genid by a small quantity [1..256]
- * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
- * many times (2^24) without giving recent rt_genid.
- * Jenkins hash is strong enough that litle changes of rt_genid are OK.
- */
-static void rt_cache_invalidate(struct net *net)
+void rt_cache_flush(struct net *net)
 {
-	unsigned char shuffle;
-
-	get_random_bytes(&shuffle, sizeof(shuffle));
-	atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
-}
-
-/*
- * delay < 0  : invalidate cache (fast : entries will be deleted later)
- * delay >= 0 : invalidate & flush cache (can be long)
- */
-void rt_cache_flush(struct net *net, int delay)
-{
-	rt_cache_invalidate(net);
+	rt_genid_bump(net);
 }
 
 static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
@@ -2345,7 +2322,7 @@
 
 void ip_rt_multicast_event(struct in_device *in_dev)
 {
-	rt_cache_flush(dev_net(in_dev->dev), 0);
+	rt_cache_flush(dev_net(in_dev->dev));
 }
 
 #ifdef CONFIG_SYSCTL
@@ -2354,16 +2331,7 @@
 					size_t *lenp, loff_t *ppos)
 {
 	if (write) {
-		int flush_delay;
-		ctl_table ctl;
-		struct net *net;
-
-		memcpy(&ctl, __ctl, sizeof(ctl));
-		ctl.data = &flush_delay;
-		proc_dointvec(&ctl, write, buffer, lenp, ppos);
-
-		net = (struct net *)__ctl->extra1;
-		rt_cache_flush(net, flush_delay);
+		rt_cache_flush((struct net *)__ctl->extra1);
 		return 0;
 	}
 
@@ -2533,8 +2501,7 @@
 
 static __net_init int rt_genid_init(struct net *net)
 {
-	get_random_bytes(&net->ipv4.rt_genid,
-			 sizeof(net->ipv4.rt_genid));
+	atomic_set(&net->rt_genid, 0);
 	get_random_bytes(&net->ipv4.dev_addr_genid,
 			 sizeof(net->ipv4.dev_addr_genid));
 	return 0;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2109ff4..5f64193 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1762,8 +1762,14 @@
 		}
 
 #ifdef CONFIG_NET_DMA
-		if (tp->ucopy.dma_chan)
-			dma_async_memcpy_issue_pending(tp->ucopy.dma_chan);
+		if (tp->ucopy.dma_chan) {
+			if (tp->rcv_wnd == 0 &&
+			    !skb_queue_empty(&sk->sk_async_wait_queue)) {
+				tcp_service_net_dma(sk, true);
+				tcp_cleanup_rbuf(sk, copied);
+			} else
+				dma_async_memcpy_issue_pending(tp->ucopy.dma_chan);
+		}
 #endif
 		if (copied >= target) {
 			/* Do not sleep, just process backlog. */
@@ -2325,10 +2331,17 @@
 			tp->rx_opt.mss_clamp = opt.opt_val;
 			break;
 		case TCPOPT_WINDOW:
-			if (opt.opt_val > 14)
-				return -EFBIG;
+			{
+				u16 snd_wscale = opt.opt_val & 0xFFFF;
+				u16 rcv_wscale = opt.opt_val >> 16;
 
-			tp->rx_opt.snd_wscale = opt.opt_val;
+				if (snd_wscale > 14 || rcv_wscale > 14)
+					return -EFBIG;
+
+				tp->rx_opt.snd_wscale = snd_wscale;
+				tp->rx_opt.rcv_wscale = rcv_wscale;
+				tp->rx_opt.wscale_ok = 1;
+			}
 			break;
 		case TCPOPT_SACK_PERM:
 			if (opt.opt_val != 0)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 6e38c6c..d377f48 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4661,7 +4661,7 @@
 
 		if (eaten > 0)
 			kfree_skb_partial(skb, fragstolen);
-		else if (!sock_flag(sk, SOCK_DEAD))
+		if (!sock_flag(sk, SOCK_DEAD))
 			sk->sk_data_ready(sk, 0);
 		return;
 	}
@@ -5556,8 +5556,7 @@
 #endif
 			if (eaten)
 				kfree_skb_partial(skb, fragstolen);
-			else
-				sk->sk_data_ready(sk, 0);
+			sk->sk_data_ready(sk, 0);
 			return 0;
 		}
 	}
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 0251a60..c4f9341 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -175,33 +175,12 @@
 			   const struct in6_addr *saddr)
 {
 	__ip6_dst_store(sk, dst, daddr, saddr);
-
-#ifdef CONFIG_XFRM
-	{
-		struct rt6_info *rt = (struct rt6_info  *)dst;
-		rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid);
-	}
-#endif
 }
 
 static inline
 struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
 {
-	struct dst_entry *dst;
-
-	dst = __sk_dst_check(sk, cookie);
-
-#ifdef CONFIG_XFRM
-	if (dst) {
-		struct rt6_info *rt = (struct rt6_info *)dst;
-		if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) {
-			__sk_dst_reset(sk);
-			dst = NULL;
-		}
-	}
-#endif
-
-	return dst;
+	return __sk_dst_check(sk, cookie);
 }
 
 static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 13690d6..286acfc 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -819,6 +819,10 @@
 					offsetof(struct rt6_info, rt6i_src),
 					allow_create, replace_required);
 
+			if (IS_ERR(sn)) {
+				err = PTR_ERR(sn);
+				sn = NULL;
+			}
 			if (!sn) {
 				/* If it is failed, discard just allocated
 				   root, and then (in st_failure) stale node
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 5b087c3..0f9bdc5 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -86,28 +86,30 @@
 
 static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
 {
-	struct ip6_mh *mh;
+	struct ip6_mh _hdr;
+	const struct ip6_mh *mh;
 
-	if (!pskb_may_pull(skb, (skb_transport_offset(skb)) + 8) ||
-	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
-				 ((skb_transport_header(skb)[1] + 1) << 3))))
+	mh = skb_header_pointer(skb, skb_transport_offset(skb),
+				sizeof(_hdr), &_hdr);
+	if (!mh)
 		return -1;
 
-	mh = (struct ip6_mh *)skb_transport_header(skb);
+	if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len)
+		return -1;
 
 	if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
 		LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
 			       mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
-		mip6_param_prob(skb, 0, ((&mh->ip6mh_hdrlen) -
-					 skb_network_header(skb)));
+		mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) +
+				skb_network_header_len(skb));
 		return -1;
 	}
 
 	if (mh->ip6mh_proto != IPPROTO_NONE) {
 		LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
 			       mh->ip6mh_proto);
-		mip6_param_prob(skb, 0, ((&mh->ip6mh_proto) -
-					 skb_network_header(skb)));
+		mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) +
+				skb_network_header_len(skb));
 		return -1;
 	}
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index ef0579d..4a5f78b 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -107,21 +107,20 @@
  *	0 - deliver
  *	1 - block
  */
-static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
+static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb)
 {
-	struct icmp6hdr *icmph;
-	struct raw6_sock *rp = raw6_sk(sk);
+	struct icmp6hdr *_hdr;
+	const struct icmp6hdr *hdr;
 
-	if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {
-		__u32 *data = &rp->filter.data[0];
-		int bit_nr;
+	hdr = skb_header_pointer(skb, skb_transport_offset(skb),
+				 sizeof(_hdr), &_hdr);
+	if (hdr) {
+		const __u32 *data = &raw6_sk(sk)->filter.data[0];
+		unsigned int type = hdr->icmp6_type;
 
-		icmph = (struct icmp6hdr *) skb->data;
-		bit_nr = icmph->icmp6_type;
-
-		return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0;
+		return (data[type >> 5] & (1U << (type & 31))) != 0;
 	}
-	return 0;
+	return 1;
 }
 
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8e80fd2..854e401 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -226,7 +226,7 @@
 	.dst = {
 		.__refcnt	= ATOMIC_INIT(1),
 		.__use		= 1,
-		.obsolete	= -1,
+		.obsolete	= DST_OBSOLETE_FORCE_CHK,
 		.error		= -ENETUNREACH,
 		.input		= ip6_pkt_discard,
 		.output		= ip6_pkt_discard_out,
@@ -246,7 +246,7 @@
 	.dst = {
 		.__refcnt	= ATOMIC_INIT(1),
 		.__use		= 1,
-		.obsolete	= -1,
+		.obsolete	= DST_OBSOLETE_FORCE_CHK,
 		.error		= -EACCES,
 		.input		= ip6_pkt_prohibit,
 		.output		= ip6_pkt_prohibit_out,
@@ -261,7 +261,7 @@
 	.dst = {
 		.__refcnt	= ATOMIC_INIT(1),
 		.__use		= 1,
-		.obsolete	= -1,
+		.obsolete	= DST_OBSOLETE_FORCE_CHK,
 		.error		= -EINVAL,
 		.input		= dst_discard,
 		.output		= dst_discard,
@@ -281,13 +281,14 @@
 					     struct fib6_table *table)
 {
 	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
-					0, DST_OBSOLETE_NONE, flags);
+					0, DST_OBSOLETE_FORCE_CHK, flags);
 
 	if (rt) {
 		struct dst_entry *dst = &rt->dst;
 
 		memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
 		rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
+		rt->rt6i_genid = rt_genid(net);
 	}
 	return rt;
 }
@@ -1031,6 +1032,13 @@
 
 	rt = (struct rt6_info *) dst;
 
+	/* All IPV6 dsts are created with ->obsolete set to the value
+	 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
+	 * into this function always.
+	 */
+	if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
+		return NULL;
+
 	if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
 		if (rt->rt6i_peer_genid != rt6_peer_genid()) {
 			if (!rt6_has_peer(rt))
@@ -1397,8 +1405,6 @@
 		goto out;
 	}
 
-	rt->dst.obsolete = -1;
-
 	if (cfg->fc_flags & RTF_EXPIRES)
 		rt6_set_expires(rt, jiffies +
 				clock_t_to_jiffies(cfg->fc_expires));
@@ -2080,7 +2086,6 @@
 	rt->dst.input = ip6_input;
 	rt->dst.output = ip6_output;
 	rt->rt6i_idev = idev;
-	rt->dst.obsolete = -1;
 
 	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
 	if (anycast)
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index d71cd92..6f93635 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -80,8 +80,8 @@
 
 	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
 			  &l2tp_nl_family, 0, L2TP_CMD_NOOP);
-	if (IS_ERR(hdr)) {
-		ret = PTR_ERR(hdr);
+	if (!hdr) {
+		ret = -EMSGSIZE;
 		goto err_out;
 	}
 
@@ -250,8 +250,8 @@
 
 	hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags,
 			  L2TP_CMD_TUNNEL_GET);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	if (nla_put_u8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version) ||
 	    nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) ||
@@ -617,8 +617,8 @@
 	sk = tunnel->sock;
 
 	hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	if (nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) ||
 	    nla_put_u32(skb, L2TP_ATTR_SESSION_ID, session->session_id) ||
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 5c22ce8..a4c1e45 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -117,11 +117,11 @@
 
 	/* For SMP, we only want to use one set of state. */
 	r->master = priv;
+	/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
+	   128. */
+	priv->prev = jiffies;
+	priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
 	if (r->cost == 0) {
-		/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
-		   128. */
-		priv->prev = jiffies;
-		priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
 		r->credit_cap = priv->credit; /* Credits full. */
 		r->cost = user2credits(r->avg);
 	}
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 1b9024e..7261eb8 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -601,7 +601,7 @@
 		if (!capable(CAP_NET_BIND_SERVICE)) {
 			dev_put(dev);
 			release_sock(sk);
-			return -EACCES;
+			return -EPERM;
 		}
 		nr->user_addr   = addr->fsa_digipeater[0];
 		nr->source_addr = addr->fsa_ax25.sax25_call;
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index e4723d3..211a212 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -865,7 +865,10 @@
 		if (mask) {
 			struct qfq_group *next = qfq_ffs(q, mask);
 			if (qfq_gt(roundedF, next->F)) {
-				cl->S = next->F;
+				if (qfq_gt(limit, next->F))
+					cl->S = next->F;
+				else /* preserve timestamp correctness */
+					cl->S = limit;
 				return;
 			}
 		}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2ded3c7..72d170c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -350,6 +350,9 @@
 	struct reg_regdb_search_request *request;
 	const struct ieee80211_regdomain *curdom, *regdom;
 	int i, r;
+	bool set_reg = false;
+
+	mutex_lock(&cfg80211_mutex);
 
 	mutex_lock(&reg_regdb_search_mutex);
 	while (!list_empty(&reg_regdb_search_list)) {
@@ -365,9 +368,7 @@
 				r = reg_copy_regd(&regdom, curdom);
 				if (r)
 					break;
-				mutex_lock(&cfg80211_mutex);
-				set_regdom(regdom);
-				mutex_unlock(&cfg80211_mutex);
+				set_reg = true;
 				break;
 			}
 		}
@@ -375,6 +376,11 @@
 		kfree(request);
 	}
 	mutex_unlock(&reg_regdb_search_mutex);
+
+	if (set_reg)
+		set_regdom(regdom);
+
+	mutex_unlock(&cfg80211_mutex);
 }
 
 static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5a2aa17..387848e 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -585,6 +585,7 @@
 	xfrm_pol_hold(policy);
 	net->xfrm.policy_count[dir]++;
 	atomic_inc(&flow_cache_genid);
+	rt_genid_bump(net);
 	if (delpol)
 		__xfrm_policy_unlink(delpol, dir);
 	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
@@ -1763,7 +1764,7 @@
 
 	if (!afinfo) {
 		dst_release(dst_orig);
-		ret = ERR_PTR(-EINVAL);
+		return ERR_PTR(-EINVAL);
 	} else {
 		ret = afinfo->blackhole_route(net, dst_orig);
 	}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e75d8e4..289f4bf 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -123,9 +123,21 @@
 				struct nlattr **attrs)
 {
 	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
+	struct xfrm_replay_state_esn *rs;
 
-	if ((p->flags & XFRM_STATE_ESN) && !rt)
-		return -EINVAL;
+	if (p->flags & XFRM_STATE_ESN) {
+		if (!rt)
+			return -EINVAL;
+
+		rs = nla_data(rt);
+
+		if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+			return -EINVAL;
+
+		if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
+		    nla_len(rt) != sizeof(*rs))
+			return -EINVAL;
+	}
 
 	if (!rt)
 		return 0;
@@ -370,14 +382,15 @@
 					 struct nlattr *rp)
 {
 	struct xfrm_replay_state_esn *up;
+	int ulen;
 
 	if (!replay_esn || !rp)
 		return 0;
 
 	up = nla_data(rp);
+	ulen = xfrm_replay_state_esn_len(up);
 
-	if (xfrm_replay_state_esn_len(replay_esn) !=
-			xfrm_replay_state_esn_len(up))
+	if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
 		return -EINVAL;
 
 	return 0;
@@ -388,22 +401,28 @@
 				       struct nlattr *rta)
 {
 	struct xfrm_replay_state_esn *p, *pp, *up;
+	int klen, ulen;
 
 	if (!rta)
 		return 0;
 
 	up = nla_data(rta);
+	klen = xfrm_replay_state_esn_len(up);
+	ulen = nla_len(rta) >= klen ? klen : sizeof(*up);
 
-	p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL);
+	p = kzalloc(klen, GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
-	pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL);
+	pp = kzalloc(klen, GFP_KERNEL);
 	if (!pp) {
 		kfree(p);
 		return -ENOMEM;
 	}
 
+	memcpy(p, up, ulen);
+	memcpy(pp, up, ulen);
+
 	*replay_esn = p;
 	*preplay_esn = pp;
 
@@ -442,10 +461,11 @@
  * somehow made shareable and move it to xfrm_state.c - JHS
  *
 */
-static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs)
+static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs,
+				  int update_esn)
 {
 	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
-	struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
+	struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL;
 	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
 	struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
 	struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
@@ -555,7 +575,7 @@
 		goto error;
 
 	/* override default values from above */
-	xfrm_update_ae_params(x, attrs);
+	xfrm_update_ae_params(x, attrs, 0);
 
 	return x;
 
@@ -689,6 +709,7 @@
 
 static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
 {
+	memset(p, 0, sizeof(*p));
 	memcpy(&p->id, &x->id, sizeof(p->id));
 	memcpy(&p->sel, &x->sel, sizeof(p->sel));
 	memcpy(&p->lft, &x->lft, sizeof(p->lft));
@@ -742,7 +763,7 @@
 		return -EMSGSIZE;
 
 	algo = nla_data(nla);
-	strcpy(algo->alg_name, auth->alg_name);
+	strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name));
 	memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
 	algo->alg_key_len = auth->alg_key_len;
 
@@ -878,6 +899,7 @@
 {
 	struct xfrm_dump_info info;
 	struct sk_buff *skb;
+	int err;
 
 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
 	if (!skb)
@@ -888,9 +910,10 @@
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
 
-	if (dump_one_state(x, 0, &info)) {
+	err = dump_one_state(x, 0, &info);
+	if (err) {
 		kfree_skb(skb);
-		return NULL;
+		return ERR_PTR(err);
 	}
 
 	return skb;
@@ -1317,6 +1340,7 @@
 
 static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
 {
+	memset(p, 0, sizeof(*p));
 	memcpy(&p->sel, &xp->selector, sizeof(p->sel));
 	memcpy(&p->lft, &xp->lft, sizeof(p->lft));
 	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));
@@ -1421,6 +1445,7 @@
 		struct xfrm_user_tmpl *up = &vec[i];
 		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
 
+		memset(up, 0, sizeof(*up));
 		memcpy(&up->id, &kp->id, sizeof(up->id));
 		up->family = kp->encap_family;
 		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));
@@ -1546,6 +1571,7 @@
 {
 	struct xfrm_dump_info info;
 	struct sk_buff *skb;
+	int err;
 
 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 	if (!skb)
@@ -1556,9 +1582,10 @@
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
 
-	if (dump_one_policy(xp, dir, 0, &info) < 0) {
+	err = dump_one_policy(xp, dir, 0, &info);
+	if (err) {
 		kfree_skb(skb);
-		return NULL;
+		return ERR_PTR(err);
 	}
 
 	return skb;
@@ -1822,7 +1849,7 @@
 		goto out;
 
 	spin_lock_bh(&x->lock);
-	xfrm_update_ae_params(x, attrs);
+	xfrm_update_ae_params(x, attrs, 1);
 	spin_unlock_bh(&x->lock);
 
 	c.event = nlh->nlmsg_type;
diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst
index c3f69ae2..4d908d1 100644
--- a/scripts/Makefile.fwinst
+++ b/scripts/Makefile.fwinst
@@ -27,7 +27,7 @@
 installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw))
 
 installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all))
-installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/.
+installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/./
 
 # Workaround for make < 3.81, where .SECONDEXPANSION doesn't work.
 PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs
@@ -42,7 +42,7 @@
 $(installed-fw-dirs):
 	$(call cmd,mkdir)
 
-$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $$(dir $(INSTALL_FW_PATH)/%)
+$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %)
 	$(call cmd,install)
 
 PHONY +=  __fw_install __fw_modinst FORCE
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
index d24810f..fd8fa9a 100755
--- a/scripts/checksyscalls.sh
+++ b/scripts/checksyscalls.sh
@@ -200,7 +200,7 @@
 syscall_list() {
     grep '^[0-9]' "$1" | sort -n | (
 	while read nr abi name entry ; do
-	    echo <<EOF
+	    cat <<EOF
 #if !defined(__NR_${name}) && !defined(__IGNORE_${name})
 #warning syscall ${name} not implemented
 #endif
diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci
index 2efac28..2b131a8 100644
--- a/scripts/coccinelle/api/memdup_user.cocci
+++ b/scripts/coccinelle/api/memdup_user.cocci
@@ -51,10 +51,10 @@
 p << r.p;
 @@
 
-coccilib.org.print_todo(p[0], "WARNING opportunity for memdep_user")
+coccilib.org.print_todo(p[0], "WARNING opportunity for memdup_user")
 
 @script:python depends on report@
 p << r.p;
 @@
 
-coccilib.report.print_report(p[0], "WARNING opportunity for memdep_user")
+coccilib.report.print_report(p[0], "WARNING opportunity for memdup_user")
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index 2fbbbc1..3368939 100644
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -100,7 +100,7 @@
 	},
 );
 
-sub find_config {
+sub read_config {
     foreach my $conf (@searchconfigs) {
 	my $file = $conf->{"file"};
 
@@ -115,17 +115,15 @@
 
 	print STDERR "using config: '$file'\n";
 
-	open(CIN, "$exec $file |") || die "Failed to run $exec $file";
-	return;
+	open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
+	my @x = <$infile>;
+	close $infile;
+	return @x;
     }
     die "No config file found";
 }
 
-find_config;
-
-# Read in the entire config file into config_file
-my @config_file = <CIN>;
-close CIN;
+my @config_file = read_config;
 
 # Parse options
 my $localmodconfig = 0;
@@ -135,7 +133,7 @@
 	   "localyesconfig" => \$localyesconfig);
 
 # Get the build source and top level Kconfig file (passed in)
-my $ksource = $ARGV[0];
+my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
 my $kconfig = $ARGV[1];
 my $lsmod_file = $ENV{'LSMOD'};
 
@@ -173,8 +171,8 @@
 	$source =~ s/\$$env/$ENV{$env}/;
     }
 
-    open(KIN, "$source") || die "Can't open $kconfig";
-    while (<KIN>) {
+    open(my $kinfile, '<', $source) || die "Can't open $kconfig";
+    while (<$kinfile>) {
 	chomp;
 
 	# Make sure that lines ending with \ continue
@@ -251,10 +249,10 @@
 	    $state = "NONE";
 	}
     }
-    close(KIN);
+    close($kinfile);
 
     # read in any configs that were found.
-    foreach $kconfig (@kconfigs) {
+    foreach my $kconfig (@kconfigs) {
 	if (!defined($read_kconfigs{$kconfig})) {
 	    $read_kconfigs{$kconfig} = 1;
 	    read_kconfig($kconfig);
@@ -295,8 +293,8 @@
     my $line = "";
     my %make_vars;
 
-    open(MIN,$makefile) || die "Can't open $makefile";
-    while (<MIN>) {
+    open(my $infile, '<', $makefile) || die "Can't open $makefile";
+    while (<$infile>) {
 	# if this line ends with a backslash, continue
 	chomp;
 	if (/^(.*)\\$/) {
@@ -343,10 +341,11 @@
 	    }
 	}
     }
-    close(MIN);
+    close($infile);
 }
 
 my %modules;
+my $linfile;
 
 if (defined($lsmod_file)) {
     if ( ! -f $lsmod_file) {
@@ -356,13 +355,10 @@
 		die "$lsmod_file not found";
 	}
     }
-    if ( -x $lsmod_file) {
-	# the file is executable, run it
-	open(LIN, "$lsmod_file|");
-    } else {
-	# Just read the contents
-	open(LIN, "$lsmod_file");
-    }
+
+    my $otype = ( -x $lsmod_file) ? '-|' : '<';
+    open($linfile, $otype, $lsmod_file);
+
 } else {
 
     # see what modules are loaded on this system
@@ -379,16 +375,16 @@
 	$lsmod = "lsmod";
     }
 
-    open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod";
+    open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
 }
 
-while (<LIN>) {
+while (<$linfile>) {
 	next if (/^Module/);  # Skip the first line.
 	if (/^(\S+)/) {
 		$modules{$1} = 1;
 	}
 }
-close (LIN);
+close ($linfile);
 
 # add to the configs hash all configs that are needed to enable
 # a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
@@ -605,6 +601,8 @@
 	if (defined($configs{$1})) {
 	    if ($localyesconfig) {
 	        $setconfigs{$1} = 'y';
+		print "$1=y\n";
+		next;
 	    } else {
 	        $setconfigs{$1} = $2;
 	    }
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 7ed6864..df4fc23 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -966,6 +966,21 @@
 }
 ADD_TO_DEVTABLE("isapnp", struct isapnp_device_id, do_isapnp_entry);
 
+/* Looks like: "ipack:fNvNdN". */
+static int do_ipack_entry(const char *filename,
+			  struct ipack_device_id *id, char *alias)
+{
+	id->vendor = TO_NATIVE(id->vendor);
+	id->device = TO_NATIVE(id->device);
+	strcpy(alias, "ipack:");
+	ADD(alias, "f", id->format != IPACK_ANY_FORMAT, id->format);
+	ADD(alias, "v", id->vendor != IPACK_ANY_ID, id->vendor);
+	ADD(alias, "d", id->device != IPACK_ANY_ID, id->device);
+	add_wildcard(alias);
+	return 1;
+}
+ADD_TO_DEVTABLE("ipack", struct ipack_device_id, do_ipack_entry);
+
 /*
  * Append a match expression for a single masked hex digit.
  * outp points to a pointer to the character at which to append.
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 54e35c1..9d1421e 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -261,11 +261,13 @@
 		&sym0[Elf_r_sym(relp)];
 	char const *symname = &str0[w(symp->st_name)];
 	char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
+	char const *fentry = "__fentry__";
 
 	if (symname[0] == '.')
 		++symname;  /* ppc64 hack */
 	if (strcmp(mcount, symname) == 0 ||
-	    (altmcount && strcmp(altmcount, symname) == 0))
+	    (altmcount && strcmp(altmcount, symname) == 0) ||
+	    (strcmp(fentry, symname) == 0))
 		mcountsym = Elf_r_sym(relp);
 
 	return mcountsym;
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index 6acf834..f19ddc4 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -161,7 +161,7 @@
 #define SORTEXTABLE_64
 #include "sortextable.h"
 
-static int compare_x86_table(const void *a, const void *b)
+static int compare_relative_table(const void *a, const void *b)
 {
 	int32_t av = (int32_t)r(a);
 	int32_t bv = (int32_t)r(b);
@@ -173,7 +173,7 @@
 	return 0;
 }
 
-static void sort_x86_table(char *extab_image, int image_size)
+static void sort_relative_table(char *extab_image, int image_size)
 {
 	int i;
 
@@ -188,7 +188,7 @@
 		i += 4;
 	}
 
-	qsort(extab_image, image_size / 8, 8, compare_x86_table);
+	qsort(extab_image, image_size / 8, 8, compare_relative_table);
 
 	/* Now denormalize. */
 	i = 0;
@@ -245,9 +245,9 @@
 		break;
 	case EM_386:
 	case EM_X86_64:
-		custom_sort = sort_x86_table;
-		break;
 	case EM_S390:
+		custom_sort = sort_relative_table;
+		break;
 	case EM_MIPS:
 		break;
 	}  /* end switch */
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
index 4d995ae..9cdec70 100644
--- a/security/apparmor/.gitignore
+++ b/security/apparmor/.gitignore
@@ -1,6 +1,5 @@
 #
 # Generated include files
 #
-af_names.h
 capability_names.h
 rlim_names.h
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 3364fbf..6cfc647 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1486,7 +1486,6 @@
 	oldwork = NULL;
 	parent = me->real_parent;
 
-	task_lock(parent);
 	/* the parent mustn't be init and mustn't be a kernel thread */
 	if (parent->pid <= 1 || !parent->mm)
 		goto unlock;
@@ -1530,7 +1529,6 @@
 	if (!ret)
 		newwork = NULL;
 unlock:
-	task_unlock(parent);
 	write_unlock_irq(&tasklist_lock);
 	rcu_read_unlock();
 	if (oldwork)
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index c220f31..65f67cb 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -51,6 +51,7 @@
 static inline void selinux_xfrm_notify_policyload(void)
 {
 	atomic_inc(&flow_cache_genid);
+	rt_genid_bump(&init_net);
 }
 #else
 static inline int selinux_xfrm_enabled(void)
diff --git a/sound/oss/.gitignore b/sound/oss/.gitignore
index 7efb12b..12a3920 100644
--- a/sound/oss/.gitignore
+++ b/sound/oss/.gitignore
@@ -1,4 +1,3 @@
 #Ignore generated files
-maui_boot.h
 pss_boot.h
 trix_boot.h
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 3fd5b29..a3acb7a8 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -702,7 +702,7 @@
 }
 
 static const struct regmap_config wm2000_regmap = {
-	.reg_bits = 8,
+	.reg_bits = 16,
 	.val_bits = 8,
 
 	.max_register = WM2000_REG_IF_CTL,
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index df65f98..a52e87d 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -27,7 +27,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 7d4fa8e..dc0ee76 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -32,8 +32,8 @@
 
 #include <asm/mach-types.h>
 
-#include <plat/board-ams-delta.h>
-#include <plat/mcbsp.h>
+#include <mach/board-ams-delta.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index e835781..5ed8716 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index f18e488..a681a9a 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -25,7 +25,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include <plat/cpu.h>
 
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index abac4b6..521bfc3 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -32,7 +32,7 @@
 #include <mach/hardware.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index d0ee71d..1b186277 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -34,7 +34,7 @@
 
 #include <plat/cpu.h>
 #include <plat/dma.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 2830dfd..e263188 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 3d468c9..d632bfb 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -27,7 +27,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 4c3a097..43d950a 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -31,7 +31,7 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index b1a9d64..3960e8d 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -31,7 +31,7 @@
 #include <mach/hardware.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index 6ac3e0c..502bce2 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 2712dd2..d921ddb 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -31,7 +31,7 @@
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "../codecs/tpa6130a2.h"
 
 #include <asm/mach-types.h>
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 78e1419..597cae7 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -33,8 +33,8 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <plat/mcbsp.h>
 #include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 /* Register descriptions for twl4030 codec part */
 #include <linux/mfd/twl4030-audio.h>
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 920e0d9..23de2b2 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -29,7 +29,7 @@
 #include <mach/hardware.h>
 #include <mach/gpio.h>
 #include <mach/board-zoom.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
 
 /* Register descriptions for twl4030 codec part */
 #include <linux/mfd/twl4030-audio.h>
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 02bcd30..19e5fe7 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,6 +1,6 @@
 config SND_SOC_TEGRA
 	tristate "SoC Audio for the Tegra System-on-Chip"
-	depends on ARCH_TEGRA && (TEGRA_SYSTEM_DMA || TEGRA20_APB_DMA)
+	depends on ARCH_TEGRA && TEGRA20_APB_DMA
 	select REGMAP_MMIO
 	select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA
 	help
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 8d6900c..e187339 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -57,237 +57,6 @@
 	.fifo_size		= 4,
 };
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
-{
-	struct snd_pcm_substream *substream = prtd->substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	struct tegra_dma_req *dma_req;
-	unsigned long addr;
-
-	dma_req = &prtd->dma_req[prtd->dma_req_idx];
-	prtd->dma_req_idx = 1 - prtd->dma_req_idx;
-
-	addr = buf->addr + prtd->dma_pos;
-	prtd->dma_pos += dma_req->size;
-	if (prtd->dma_pos >= prtd->dma_pos_end)
-		prtd->dma_pos = 0;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dma_req->source_addr = addr;
-	else
-		dma_req->dest_addr = addr;
-
-	tegra_dma_enqueue_req(prtd->dma_chan, dma_req);
-}
-
-static void dma_complete_callback(struct tegra_dma_req *req)
-{
-	struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
-	struct snd_pcm_substream *substream = prtd->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	spin_lock(&prtd->lock);
-
-	if (!prtd->running) {
-		spin_unlock(&prtd->lock);
-		return;
-	}
-
-	if (++prtd->period_index >= runtime->periods)
-		prtd->period_index = 0;
-
-	tegra_pcm_queue_dma(prtd);
-
-	spin_unlock(&prtd->lock);
-
-	snd_pcm_period_elapsed(substream);
-}
-
-static void setup_dma_tx_request(struct tegra_dma_req *req,
-					struct tegra_pcm_dma_params * dmap)
-{
-	req->complete = dma_complete_callback;
-	req->to_memory = false;
-	req->dest_addr = dmap->addr;
-	req->dest_wrap = dmap->wrap;
-	req->source_bus_width = 32;
-	req->source_wrap = 0;
-	req->dest_bus_width = dmap->width;
-	req->req_sel = dmap->req_sel;
-}
-
-static void setup_dma_rx_request(struct tegra_dma_req *req,
-					struct tegra_pcm_dma_params * dmap)
-{
-	req->complete = dma_complete_callback;
-	req->to_memory = true;
-	req->source_addr = dmap->addr;
-	req->dest_wrap = 0;
-	req->source_bus_width = dmap->width;
-	req->source_wrap = dmap->wrap;
-	req->dest_bus_width = 32;
-	req->req_sel = dmap->req_sel;
-}
-
-static int tegra_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct tegra_runtime_data *prtd;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct tegra_pcm_dma_params * dmap;
-	int ret = 0;
-
-	prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
-	if (prtd == NULL)
-		return -ENOMEM;
-
-	runtime->private_data = prtd;
-	prtd->substream = substream;
-
-	spin_lock_init(&prtd->lock);
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-		setup_dma_tx_request(&prtd->dma_req[0], dmap);
-		setup_dma_tx_request(&prtd->dma_req[1], dmap);
-	} else {
-		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-		setup_dma_rx_request(&prtd->dma_req[0], dmap);
-		setup_dma_rx_request(&prtd->dma_req[1], dmap);
-	}
-
-	prtd->dma_req[0].dev = prtd;
-	prtd->dma_req[1].dev = prtd;
-
-	prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
-	if (prtd->dma_chan == NULL) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	/* Set HW params now that initialization is complete */
-	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
-
-	/* Ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(runtime,
-						SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-
-err:
-	if (prtd->dma_chan) {
-		tegra_dma_free_channel(prtd->dma_chan);
-	}
-
-	kfree(prtd);
-
-	return ret;
-}
-
-static int tegra_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct tegra_runtime_data *prtd = runtime->private_data;
-
-	tegra_dma_free_channel(prtd->dma_chan);
-
-	kfree(prtd);
-
-	return 0;
-}
-
-static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct tegra_runtime_data *prtd = runtime->private_data;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-	prtd->dma_req[0].size = params_period_bytes(params);
-	prtd->dma_req[1].size = prtd->dma_req[0].size;
-
-	return 0;
-}
-
-static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	snd_pcm_set_runtime_buffer(substream, NULL);
-
-	return 0;
-}
-
-static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct tegra_runtime_data *prtd = runtime->private_data;
-	unsigned long flags;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		prtd->dma_pos = 0;
-		prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size);
-		prtd->period_index = 0;
-		prtd->dma_req_idx = 0;
-		/* Fall-through */
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		spin_lock_irqsave(&prtd->lock, flags);
-		prtd->running = 1;
-		spin_unlock_irqrestore(&prtd->lock, flags);
-		tegra_pcm_queue_dma(prtd);
-		tegra_pcm_queue_dma(prtd);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		spin_lock_irqsave(&prtd->lock, flags);
-		prtd->running = 0;
-		spin_unlock_irqrestore(&prtd->lock, flags);
-		tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]);
-		tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct tegra_runtime_data *prtd = runtime->private_data;
-
-	return prtd->period_index * runtime->period_size;
-}
-
-
-static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
-				struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-					runtime->dma_area,
-					runtime->dma_addr,
-					runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops tegra_pcm_ops = {
-	.open		= tegra_pcm_open,
-	.close		= tegra_pcm_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= tegra_pcm_hw_params,
-	.hw_free	= tegra_pcm_hw_free,
-	.trigger	= tegra_pcm_trigger,
-	.pointer	= tegra_pcm_pointer,
-	.mmap		= tegra_pcm_mmap,
-};
-#else
 static int tegra_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -399,7 +168,6 @@
 	.pointer	= snd_dmaengine_pcm_pointer,
 	.mmap		= tegra_pcm_mmap,
 };
-#endif
 
 static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index a3a4503..b40279b 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -40,20 +40,6 @@
 	unsigned long req_sel;
 };
 
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-struct tegra_runtime_data {
-	struct snd_pcm_substream *substream;
-	spinlock_t lock;
-	int running;
-	int dma_pos;
-	int dma_pos_end;
-	int period_index;
-	int dma_req_idx;
-	struct tegra_dma_req dma_req[2];
-	struct tegra_dma_channel *dma_chan;
-};
-#endif
-
 int tegra_pcm_platform_register(struct device *dev);
 void tegra_pcm_platform_unregister(struct device *dev);
 
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index d6e2bb4..060dccb 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -197,7 +197,13 @@
 			/* no data provider, so send silence */
 			unsigned int offs = 0;
 			for (i = 0; i < ctx->packets; ++i) {
-				int counts = ctx->packet_size[i];
+				int counts;
+
+				if (ctx->packet_size[i])
+					counts = ctx->packet_size[i];
+				else
+					counts = snd_usb_endpoint_next_packet_size(ep);
+
 				urb->iso_frame_desc[i].offset = offs * ep->stride;
 				urb->iso_frame_desc[i].length = counts * ep->stride;
 				offs += counts;
diff --git a/tools/hv/hv_get_dhcp_info.sh b/tools/hv/hv_get_dhcp_info.sh
new file mode 100755
index 0000000..ccd3e95
--- /dev/null
+++ b/tools/hv/hv_get_dhcp_info.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# This example script retrieves the DHCP state of a given interface.
+# In the interest of keeping the KVP daemon code free of distro specific
+# information; the kvp daemon code invokes this external script to gather
+# DHCP setting for the specific interface.
+#
+# Input: Name of the interface
+#
+# Output: The script prints the string "Enabled" to stdout to indicate
+#	that DHCP is enabled on the interface. If DHCP is not enabled,
+#	the script prints the string "Disabled" to stdout.
+#
+# Each Distro is expected to implement this script in a distro specific
+# fashion. For instance on Distros that ship with Network Manager enabled,
+# this script can be based on the Network Manager APIs for retrieving DHCP
+# information.
+
+if_file="/etc/sysconfig/network-scripts/ifcfg-"$1
+
+dhcp=$(grep "dhcp" $if_file 2>/dev/null)
+
+if [ "$dhcp" != "" ];
+then
+echo "Enabled"
+else
+echo "Disabled"
+fi
diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh
new file mode 100755
index 0000000..058c17b
--- /dev/null
+++ b/tools/hv/hv_get_dns_info.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# This example script parses /etc/resolv.conf to retrive DNS information.
+# In the interest of keeping the KVP daemon code free of distro specific
+# information; the kvp daemon code invokes this external script to gather
+# DNS information.
+# This script is expected to print the nameserver values to stdout.
+# Each Distro is expected to implement this script in a distro specific
+# fashion. For instance on Distros that ship with Network Manager enabled,
+# this script can be based on the Network Manager APIs for retrieving DNS
+# entries.
+
+cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }'
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index d9834b3..5959aff 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 #include <errno.h>
 #include <arpa/inet.h>
 #include <linux/connector.h>
@@ -41,6 +42,7 @@
 #include <syslog.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <dirent.h>
 
 /*
  * KVP protocol: The user mode component first registers with the
@@ -68,25 +70,39 @@
 	ProcessorArchitecture
 };
 
+
+enum {
+	IPADDR = 0,
+	NETMASK,
+	GATEWAY,
+	DNS
+};
+
 static char kvp_send_buffer[4096];
-static char kvp_recv_buffer[4096];
+static char kvp_recv_buffer[4096 * 2];
 static struct sockaddr_nl addr;
+static int in_hand_shake = 1;
 
 static char *os_name = "";
 static char *os_major = "";
 static char *os_minor = "";
 static char *processor_arch;
 static char *os_build;
-static char *lic_version;
+static char *lic_version = "Unknown version";
 static struct utsname uts_buf;
 
+/*
+ * The location of the interface configuration file.
+ */
+
+#define KVP_CONFIG_LOC	"/var/opt/"
 
 #define MAX_FILE_NAME 100
 #define ENTRIES_PER_BLOCK 50
 
 struct kvp_record {
-	__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-	__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
 };
 
 struct kvp_file_state {
@@ -94,7 +110,7 @@
 	int num_blocks;
 	struct kvp_record *records;
 	int num_records;
-	__u8 fname[MAX_FILE_NAME];
+	char fname[MAX_FILE_NAME];
 };
 
 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
@@ -106,7 +122,7 @@
 
 	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
 		syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 }
 
@@ -118,7 +134,7 @@
 	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
 		perror("fcntl");
 		syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 }
 
@@ -137,14 +153,19 @@
 	if (!filep) {
 		kvp_release_lock(pool);
 		syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 
 	bytes_written = fwrite(kvp_file_info[pool].records,
 				sizeof(struct kvp_record),
 				kvp_file_info[pool].num_records, filep);
 
-	fflush(filep);
+	if (ferror(filep) || fclose(filep)) {
+		kvp_release_lock(pool);
+		syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
+		exit(EXIT_FAILURE);
+	}
+
 	kvp_release_lock(pool);
 }
 
@@ -163,14 +184,19 @@
 	if (!filep) {
 		kvp_release_lock(pool);
 		syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
-	while (!feof(filep)) {
+	for (;;) {
 		readp = &record[records_read];
 		records_read += fread(readp, sizeof(struct kvp_record),
 					ENTRIES_PER_BLOCK * num_blocks,
 					filep);
 
+		if (ferror(filep)) {
+			syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
+			exit(EXIT_FAILURE);
+		}
+
 		if (!feof(filep)) {
 			/*
 			 * We have more data to read.
@@ -180,7 +206,7 @@
 
 			if (record == NULL) {
 				syslog(LOG_ERR, "malloc failed");
-				exit(-1);
+				exit(EXIT_FAILURE);
 			}
 			continue;
 		}
@@ -191,14 +217,15 @@
 	kvp_file_info[pool].records = record;
 	kvp_file_info[pool].num_records = records_read;
 
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 static int kvp_file_init(void)
 {
-	int ret, fd;
+	int  fd;
 	FILE *filep;
 	size_t records_read;
-	__u8 *fname;
+	char *fname;
 	struct kvp_record *record;
 	struct kvp_record *readp;
 	int num_blocks;
@@ -208,7 +235,7 @@
 	if (access("/var/opt/hyperv", F_OK)) {
 		if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
 			syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
-			exit(-1);
+			exit(EXIT_FAILURE);
 		}
 	}
 
@@ -232,12 +259,18 @@
 			fclose(filep);
 			return 1;
 		}
-		while (!feof(filep)) {
+		for (;;) {
 			readp = &record[records_read];
 			records_read += fread(readp, sizeof(struct kvp_record),
 					ENTRIES_PER_BLOCK,
 					filep);
 
+			if (ferror(filep)) {
+				syslog(LOG_ERR, "Failed to read file, pool: %d",
+				       i);
+				exit(EXIT_FAILURE);
+			}
+
 			if (!feof(filep)) {
 				/*
 				 * We have more data to read.
@@ -311,7 +344,6 @@
 			int value_size)
 {
 	int i;
-	int j, k;
 	int num_records;
 	struct kvp_record *record;
 	int num_blocks;
@@ -394,7 +426,7 @@
 	return 1;
 }
 
-static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
+static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
 				__u8 *value, int value_size)
 {
 	struct kvp_record *record;
@@ -406,16 +438,12 @@
 	record = kvp_file_info[pool].records;
 
 	if (index >= kvp_file_info[pool].num_records) {
-		/*
-		 * This is an invalid index; terminate enumeration;
-		 * - a NULL value will do the trick.
-		 */
-		strcpy(value, "");
-		return;
+		return 1;
 	}
 
 	memcpy(key, record[index].key, key_size);
 	memcpy(value, record[index].value, value_size);
+	return 0;
 }
 
 
@@ -426,6 +454,7 @@
 
 	uname(&uts_buf);
 	os_build = uts_buf.release;
+	os_name = uts_buf.sysname;
 	processor_arch = uts_buf.machine;
 
 	/*
@@ -437,20 +466,70 @@
 	if (p)
 		*p = '\0';
 
+	/*
+	 * Parse the /etc/os-release file if present:
+	 * http://www.freedesktop.org/software/systemd/man/os-release.html
+	 */
+	file = fopen("/etc/os-release", "r");
+	if (file != NULL) {
+		while (fgets(buf, sizeof(buf), file)) {
+			char *value, *q;
+
+			/* Ignore comments */
+			if (buf[0] == '#')
+				continue;
+
+			/* Split into name=value */
+			p = strchr(buf, '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+
+			/* Remove quotes and newline; un-escape */
+			value = p;
+			q = p;
+			while (*p) {
+				if (*p == '\\') {
+					++p;
+					if (!*p)
+						break;
+					*q++ = *p++;
+				} else if (*p == '\'' || *p == '"' ||
+					   *p == '\n') {
+					++p;
+				} else {
+					*q++ = *p++;
+				}
+			}
+			*q = 0;
+
+			if (!strcmp(buf, "NAME")) {
+				p = strdup(value);
+				if (!p)
+					break;
+				os_name = p;
+			} else if (!strcmp(buf, "VERSION_ID")) {
+				p = strdup(value);
+				if (!p)
+					break;
+				os_major = p;
+			}
+		}
+		fclose(file);
+		return;
+	}
+
+	/* Fallback for older RH/SUSE releases */
 	file = fopen("/etc/SuSE-release", "r");
 	if (file != NULL)
 		goto kvp_osinfo_found;
 	file  = fopen("/etc/redhat-release", "r");
 	if (file != NULL)
 		goto kvp_osinfo_found;
-	/*
-	 * Add code for other supported platforms.
-	 */
 
 	/*
 	 * We don't have information about the os.
 	 */
-	os_name = uts_buf.sysname;
 	return;
 
 kvp_osinfo_found:
@@ -494,82 +573,458 @@
 	return;
 }
 
+
+
+/*
+ * Retrieve an interface name corresponding to the specified guid.
+ * If there is a match, the function returns a pointer
+ * to the interface name and if not, a NULL is returned.
+ * If a match is found, the caller is responsible for
+ * freeing the memory.
+ */
+
+static char *kvp_get_if_name(char *guid)
+{
+	DIR *dir;
+	struct dirent *entry;
+	FILE    *file;
+	char    *p, *q, *x;
+	char    *if_name = NULL;
+	char    buf[256];
+	char *kvp_net_dir = "/sys/class/net/";
+	char dev_id[256];
+
+	dir = opendir(kvp_net_dir);
+	if (dir == NULL)
+		return NULL;
+
+	snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
+	q = dev_id + strlen(kvp_net_dir);
+
+	while ((entry = readdir(dir)) != NULL) {
+		/*
+		 * Set the state for the next pass.
+		 */
+		*q = '\0';
+		strcat(dev_id, entry->d_name);
+		strcat(dev_id, "/device/device_id");
+
+		file = fopen(dev_id, "r");
+		if (file == NULL)
+			continue;
+
+		p = fgets(buf, sizeof(buf), file);
+		if (p) {
+			x = strchr(p, '\n');
+			if (x)
+				*x = '\0';
+
+			if (!strcmp(p, guid)) {
+				/*
+				 * Found the guid match; return the interface
+				 * name. The caller will free the memory.
+				 */
+				if_name = strdup(entry->d_name);
+				fclose(file);
+				break;
+			}
+		}
+		fclose(file);
+	}
+
+	closedir(dir);
+	return if_name;
+}
+
+/*
+ * Retrieve the MAC address given the interface name.
+ */
+
+static char *kvp_if_name_to_mac(char *if_name)
+{
+	FILE    *file;
+	char    *p, *x;
+	char    buf[256];
+	char addr_file[256];
+	int i;
+	char *mac_addr = NULL;
+
+	snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
+		if_name, "/address");
+
+	file = fopen(addr_file, "r");
+	if (file == NULL)
+		return NULL;
+
+	p = fgets(buf, sizeof(buf), file);
+	if (p) {
+		x = strchr(p, '\n');
+		if (x)
+			*x = '\0';
+		for (i = 0; i < strlen(p); i++)
+			p[i] = toupper(p[i]);
+		mac_addr = strdup(p);
+	}
+
+	fclose(file);
+	return mac_addr;
+}
+
+
+/*
+ * Retrieve the interface name given tha MAC address.
+ */
+
+static char *kvp_mac_to_if_name(char *mac)
+{
+	DIR *dir;
+	struct dirent *entry;
+	FILE    *file;
+	char    *p, *q, *x;
+	char    *if_name = NULL;
+	char    buf[256];
+	char *kvp_net_dir = "/sys/class/net/";
+	char dev_id[256];
+	int i;
+
+	dir = opendir(kvp_net_dir);
+	if (dir == NULL)
+		return NULL;
+
+	snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
+	q = dev_id + strlen(kvp_net_dir);
+
+	while ((entry = readdir(dir)) != NULL) {
+		/*
+		 * Set the state for the next pass.
+		 */
+		*q = '\0';
+
+		strcat(dev_id, entry->d_name);
+		strcat(dev_id, "/address");
+
+		file = fopen(dev_id, "r");
+		if (file == NULL)
+			continue;
+
+		p = fgets(buf, sizeof(buf), file);
+		if (p) {
+			x = strchr(p, '\n');
+			if (x)
+				*x = '\0';
+
+			for (i = 0; i < strlen(p); i++)
+				p[i] = toupper(p[i]);
+
+			if (!strcmp(p, mac)) {
+				/*
+				 * Found the MAC match; return the interface
+				 * name. The caller will free the memory.
+				 */
+				if_name = strdup(entry->d_name);
+				fclose(file);
+				break;
+			}
+		}
+		fclose(file);
+	}
+
+	closedir(dir);
+	return if_name;
+}
+
+
+static void kvp_process_ipconfig_file(char *cmd,
+					char *config_buf, int len,
+					int element_size, int offset)
+{
+	char buf[256];
+	char *p;
+	char *x;
+	FILE *file;
+
+	/*
+	 * First execute the command.
+	 */
+	file = popen(cmd, "r");
+	if (file == NULL)
+		return;
+
+	if (offset == 0)
+		memset(config_buf, 0, len);
+	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
+		if ((len - strlen(config_buf)) < (element_size + 1))
+			break;
+
+		x = strchr(p, '\n');
+		*x = '\0';
+		strcat(config_buf, p);
+		strcat(config_buf, ";");
+	}
+	pclose(file);
+}
+
+static void kvp_get_ipconfig_info(char *if_name,
+				 struct hv_kvp_ipaddr_value *buffer)
+{
+	char cmd[512];
+	char dhcp_info[128];
+	char *p;
+	FILE *file;
+
+	/*
+	 * Get the address of default gateway (ipv4).
+	 */
+	sprintf(cmd, "%s %s", "ip route show dev", if_name);
+	strcat(cmd, " | awk '/default/ {print $3 }'");
+
+	/*
+	 * Execute the command to gather gateway info.
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
+				(MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
+
+	/*
+	 * Get the address of default gateway (ipv6).
+	 */
+	sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
+	strcat(cmd, " | awk '/default/ {print $3 }'");
+
+	/*
+	 * Execute the command to gather gateway info (ipv6).
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
+				(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
+
+
+	/*
+	 * Gather the DNS  state.
+	 * Since there is no standard way to get this information
+	 * across various distributions of interest; we just invoke
+	 * an external script that needs to be ported across distros
+	 * of interest.
+	 *
+	 * Following is the expected format of the information from the script:
+	 *
+	 * ipaddr1 (nameserver1)
+	 * ipaddr2 (nameserver2)
+	 * .
+	 * .
+	 */
+
+	sprintf(cmd, "%s",  "hv_get_dns_info");
+
+	/*
+	 * Execute the command to gather DNS info.
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
+				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
+
+	/*
+	 * Gather the DHCP state.
+	 * We will gather this state by invoking an external script.
+	 * The parameter to the script is the interface name.
+	 * Here is the expected output:
+	 *
+	 * Enabled: DHCP enabled.
+	 */
+
+	sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
+
+	file = popen(cmd, "r");
+	if (file == NULL)
+		return;
+
+	p = fgets(dhcp_info, sizeof(dhcp_info), file);
+	if (p == NULL) {
+		pclose(file);
+		return;
+	}
+
+	if (!strncmp(p, "Enabled", 7))
+		buffer->dhcp_enabled = 1;
+	else
+		buffer->dhcp_enabled = 0;
+
+	pclose(file);
+}
+
+
+static unsigned int hweight32(unsigned int *w)
+{
+	unsigned int res = *w - ((*w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res + (res >> 4)) & 0x0F0F0F0F;
+	res = res + (res >> 8);
+	return (res + (res >> 16)) & 0x000000FF;
+}
+
+static int kvp_process_ip_address(void *addrp,
+				int family, char *buffer,
+				int length,  int *offset)
+{
+	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr6;
+	int addr_length;
+	char tmp[50];
+	const char *str;
+
+	if (family == AF_INET) {
+		addr = (struct sockaddr_in *)addrp;
+		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
+		addr_length = INET_ADDRSTRLEN;
+	} else {
+		addr6 = (struct sockaddr_in6 *)addrp;
+		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
+		addr_length = INET6_ADDRSTRLEN;
+	}
+
+	if ((length - *offset) < addr_length + 1)
+		return HV_E_FAIL;
+	if (str == NULL) {
+		strcpy(buffer, "inet_ntop failed\n");
+		return HV_E_FAIL;
+	}
+	if (*offset == 0)
+		strcpy(buffer, tmp);
+	else
+		strcat(buffer, tmp);
+	strcat(buffer, ";");
+
+	*offset += strlen(str) + 1;
+	return 0;
+}
+
 static int
-kvp_get_ip_address(int family, char *buffer, int length)
+kvp_get_ip_info(int family, char *if_name, int op,
+		 void  *out_buffer, int length)
 {
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
-	int ipv4_len = strlen("255.255.255.255") + 1;
-	int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
 	int offset = 0;
-	const char *str;
-	char tmp[50];
+	int sn_offset = 0;
 	int error = 0;
+	char *buffer;
+	struct hv_kvp_ipaddr_value *ip_buffer;
+	char cidr_mask[5]; /* /xyz */
+	int weight;
+	int i;
+	unsigned int *w;
+	char *sn_str;
+	struct sockaddr_in6 *addr6;
 
+	if (op == KVP_OP_ENUMERATE) {
+		buffer = out_buffer;
+	} else {
+		ip_buffer = out_buffer;
+		buffer = (char *)ip_buffer->ip_addr;
+		ip_buffer->addr_family = 0;
+	}
 	/*
 	 * On entry into this function, the buffer is capable of holding the
-	 * maximum key value (2048 bytes).
+	 * maximum key value.
 	 */
 
 	if (getifaddrs(&ifap)) {
 		strcpy(buffer, "getifaddrs failed\n");
-		return 1;
+		return HV_E_FAIL;
 	}
 
 	curp = ifap;
 	while (curp != NULL) {
-		if ((curp->ifa_addr != NULL) &&
-		   (curp->ifa_addr->sa_family == family)) {
-			if (family == AF_INET) {
-				struct sockaddr_in *addr =
-				(struct sockaddr_in *) curp->ifa_addr;
+		if (curp->ifa_addr == NULL) {
+			curp = curp->ifa_next;
+			continue;
+		}
 
-				str = inet_ntop(family, &addr->sin_addr,
-						tmp, 50);
-				if (str == NULL) {
-					strcpy(buffer, "inet_ntop failed\n");
-					error = 1;
-					goto getaddr_done;
-				}
-				if (offset == 0)
-					strcpy(buffer, tmp);
-				else
-					strcat(buffer, tmp);
-				strcat(buffer, ";");
-
-				offset += strlen(str) + 1;
-				if ((length - offset) < (ipv4_len + 1))
-					goto getaddr_done;
-
-			} else {
-
+		if ((if_name != NULL) &&
+			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
 			/*
-			 * We only support AF_INET and AF_INET6
-			 * and the list of addresses is separated by a ";".
+			 * We want info about a specific interface;
+			 * just continue.
 			 */
-				struct sockaddr_in6 *addr =
-				(struct sockaddr_in6 *) curp->ifa_addr;
+			curp = curp->ifa_next;
+			continue;
+		}
 
-				str = inet_ntop(family,
-					&addr->sin6_addr.s6_addr,
-					tmp, 50);
-				if (str == NULL) {
-					strcpy(buffer, "inet_ntop failed\n");
-					error = 1;
-					goto getaddr_done;
-				}
-				if (offset == 0)
-					strcpy(buffer, tmp);
+		/*
+		 * We only support two address families: AF_INET and AF_INET6.
+		 * If a family value of 0 is specified, we collect both
+		 * supported address families; if not we gather info on
+		 * the specified address family.
+		 */
+		if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
+			curp = curp->ifa_next;
+			continue;
+		}
+		if ((curp->ifa_addr->sa_family != AF_INET) &&
+			(curp->ifa_addr->sa_family != AF_INET6)) {
+			curp = curp->ifa_next;
+			continue;
+		}
+
+		if (op == KVP_OP_GET_IP_INFO) {
+			/*
+			 * Gather info other than the IP address.
+			 * IP address info will be gathered later.
+			 */
+			if (curp->ifa_addr->sa_family == AF_INET) {
+				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
+				/*
+				 * Get subnet info.
+				 */
+				error = kvp_process_ip_address(
+							     curp->ifa_netmask,
+							     AF_INET,
+							     (char *)
+							     ip_buffer->sub_net,
+							     length,
+							     &sn_offset);
+				if (error)
+					goto gather_ipaddr;
+			} else {
+				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
+
+				/*
+				 * Get subnet info in CIDR format.
+				 */
+				weight = 0;
+				sn_str = (char *)ip_buffer->sub_net;
+				addr6 = (struct sockaddr_in6 *)
+					curp->ifa_netmask;
+				w = addr6->sin6_addr.s6_addr32;
+
+				for (i = 0; i < 4; i++)
+					weight += hweight32(&w[i]);
+
+				sprintf(cidr_mask, "/%d", weight);
+				if ((length - sn_offset) <
+					(strlen(cidr_mask) + 1))
+					goto gather_ipaddr;
+
+				if (sn_offset == 0)
+					strcpy(sn_str, cidr_mask);
 				else
-					strcat(buffer, tmp);
-				strcat(buffer, ";");
-				offset += strlen(str) + 1;
-				if ((length - offset) < (ipv6_len + 1))
-					goto getaddr_done;
-
+					strcat(sn_str, cidr_mask);
+				strcat((char *)ip_buffer->sub_net, ";");
+				sn_offset += strlen(sn_str) + 1;
 			}
 
+			/*
+			 * Collect other ip related configuration info.
+			 */
+
+			kvp_get_ipconfig_info(if_name, ip_buffer);
 		}
+
+gather_ipaddr:
+		error = kvp_process_ip_address(curp->ifa_addr,
+						curp->ifa_addr->sa_family,
+						buffer,
+						length, &offset);
+		if (error)
+			goto getaddr_done;
+
 		curp = curp->ifa_next;
 	}
 
@@ -579,6 +1034,315 @@
 }
 
 
+static int expand_ipv6(char *addr, int type)
+{
+	int ret;
+	struct in6_addr v6_addr;
+
+	ret = inet_pton(AF_INET6, addr, &v6_addr);
+
+	if (ret != 1) {
+		if (type == NETMASK)
+			return 1;
+		return 0;
+	}
+
+	sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+		"%02x%02x:%02x%02x:%02x%02x",
+		(int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
+		(int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
+		(int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
+		(int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
+		(int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
+		(int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
+		(int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
+		(int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
+
+	return 1;
+
+}
+
+static int is_ipv4(char *addr)
+{
+	int ret;
+	struct in_addr ipv4_addr;
+
+	ret = inet_pton(AF_INET, addr, &ipv4_addr);
+
+	if (ret == 1)
+		return 1;
+	return 0;
+}
+
+static int parse_ip_val_buffer(char *in_buf, int *offset,
+				char *out_buf, int out_len)
+{
+	char *x;
+	char *start;
+
+	/*
+	 * in_buf has sequence of characters that are seperated by
+	 * the character ';'. The last sequence does not have the
+	 * terminating ";" character.
+	 */
+	start = in_buf + *offset;
+
+	x = strchr(start, ';');
+	if (x)
+		*x = 0;
+	else
+		x = start + strlen(start);
+
+	if (strlen(start) != 0) {
+		int i = 0;
+		/*
+		 * Get rid of leading spaces.
+		 */
+		while (start[i] == ' ')
+			i++;
+
+		if ((x - start) <= out_len) {
+			strcpy(out_buf, (start + i));
+			*offset += (x - start) + 1;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
+{
+	int ret;
+
+	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
+
+	if (ret < 0)
+		return HV_E_FAIL;
+
+	return 0;
+}
+
+
+static int process_ip_string(FILE *f, char *ip_string, int type)
+{
+	int error = 0;
+	char addr[INET6_ADDRSTRLEN];
+	int i = 0;
+	int j = 0;
+	char str[256];
+	char sub_str[10];
+	int offset = 0;
+
+	memset(addr, 0, sizeof(addr));
+
+	while (parse_ip_val_buffer(ip_string, &offset, addr,
+					(MAX_IP_ADDR_SIZE * 2))) {
+
+		sub_str[0] = 0;
+		if (is_ipv4(addr)) {
+			switch (type) {
+			case IPADDR:
+				snprintf(str, sizeof(str), "%s", "IPADDR");
+				break;
+			case NETMASK:
+				snprintf(str, sizeof(str), "%s", "NETMASK");
+				break;
+			case GATEWAY:
+				snprintf(str, sizeof(str), "%s", "GATEWAY");
+				break;
+			case DNS:
+				snprintf(str, sizeof(str), "%s", "DNS");
+				break;
+			}
+			if (i != 0) {
+				if (type != DNS) {
+					snprintf(sub_str, sizeof(sub_str),
+						"_%d", i++);
+				} else {
+					snprintf(sub_str, sizeof(sub_str),
+						"%d", ++i);
+				}
+			} else if (type == DNS) {
+				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
+			}
+
+
+		} else if (expand_ipv6(addr, type)) {
+			switch (type) {
+			case IPADDR:
+				snprintf(str, sizeof(str), "%s", "IPV6ADDR");
+				break;
+			case NETMASK:
+				snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
+				break;
+			case GATEWAY:
+				snprintf(str, sizeof(str), "%s",
+					"IPV6_DEFAULTGW");
+				break;
+			case DNS:
+				snprintf(str, sizeof(str), "%s",  "DNS");
+				break;
+			}
+			if ((j != 0) || (type == DNS)) {
+				if (type != DNS) {
+					snprintf(sub_str, sizeof(sub_str),
+						"_%d", j++);
+				} else {
+					snprintf(sub_str, sizeof(sub_str),
+						"%d", ++i);
+				}
+			} else if (type == DNS) {
+				snprintf(sub_str, sizeof(sub_str),
+					"%d", ++i);
+			}
+		} else {
+			return  HV_INVALIDARG;
+		}
+
+		error = kvp_write_file(f, str, sub_str, addr);
+		if (error)
+			return error;
+		memset(addr, 0, sizeof(addr));
+	}
+
+	return 0;
+}
+
+static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
+{
+	int error = 0;
+	char if_file[128];
+	FILE *file;
+	char cmd[512];
+	char *mac_addr;
+
+	/*
+	 * Set the configuration for the specified interface with
+	 * the information provided. Since there is no standard
+	 * way to configure an interface, we will have an external
+	 * script that does the job of configuring the interface and
+	 * flushing the configuration.
+	 *
+	 * The parameters passed to this external script are:
+	 * 1. A configuration file that has the specified configuration.
+	 *
+	 * We will embed the name of the interface in the configuration
+	 * file: ifcfg-ethx (where ethx is the interface name).
+	 *
+	 * The information provided here may be more than what is needed
+	 * in a given distro to configure the interface and so are free
+	 * ignore information that may not be relevant.
+	 *
+	 * Here is the format of the ip configuration file:
+	 *
+	 * HWADDR=macaddr
+	 * IF_NAME=interface name
+	 * DHCP=yes (This is optional; if yes, DHCP is configured)
+	 *
+	 * IPADDR=ipaddr1
+	 * IPADDR_1=ipaddr2
+	 * IPADDR_x=ipaddry (where y = x + 1)
+	 *
+	 * NETMASK=netmask1
+	 * NETMASK_x=netmasky (where y = x + 1)
+	 *
+	 * GATEWAY=ipaddr1
+	 * GATEWAY_x=ipaddry (where y = x + 1)
+	 *
+	 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
+	 *
+	 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
+	 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
+	 * IPV6NETMASK.
+	 *
+	 * The host can specify multiple ipv4 and ipv6 addresses to be
+	 * configured for the interface. Furthermore, the configuration
+	 * needs to be persistent. A subsequent GET call on the interface
+	 * is expected to return the configuration that is set via the SET
+	 * call.
+	 */
+
+	snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
+		"hyperv/ifcfg-", if_name);
+
+	file = fopen(if_file, "w");
+
+	if (file == NULL) {
+		syslog(LOG_ERR, "Failed to open config file");
+		return HV_E_FAIL;
+	}
+
+	/*
+	 * First write out the MAC address.
+	 */
+
+	mac_addr = kvp_if_name_to_mac(if_name);
+	if (mac_addr == NULL) {
+		error = HV_E_FAIL;
+		goto setval_error;
+	}
+
+	error = kvp_write_file(file, "HWADDR", "", mac_addr);
+	if (error)
+		goto setval_error;
+
+	error = kvp_write_file(file, "IF_NAME", "", if_name);
+	if (error)
+		goto setval_error;
+
+	if (new_val->dhcp_enabled) {
+		error = kvp_write_file(file, "DHCP", "", "yes");
+		if (error)
+			goto setval_error;
+
+		/*
+		 * We are done!.
+		 */
+		goto setval_done;
+	}
+
+	/*
+	 * Write the configuration for ipaddress, netmask, gateway and
+	 * name servers.
+	 */
+
+	error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
+	if (error)
+		goto setval_error;
+
+	error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
+	if (error)
+		goto setval_error;
+
+	error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
+	if (error)
+		goto setval_error;
+
+	error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
+	if (error)
+		goto setval_error;
+
+setval_done:
+	free(mac_addr);
+	fclose(file);
+
+	/*
+	 * Now that we have populated the configuration file,
+	 * invoke the external script to do its magic.
+	 */
+
+	snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
+	system(cmd);
+	return 0;
+
+setval_error:
+	syslog(LOG_ERR, "Failed to write config file");
+	free(mac_addr);
+	fclose(file);
+	return error;
+}
+
+
 static int
 kvp_get_domain_name(char *buffer, int length)
 {
@@ -646,6 +1410,10 @@
 	char	*p;
 	char	*key_value;
 	char	*key_name;
+	int	op;
+	int	pool;
+	char	*if_name;
+	struct hv_kvp_ipaddr_value *kvp_ip_val;
 
 	daemon(1, 0);
 	openlog("KVP", 0, LOG_USER);
@@ -657,13 +1425,13 @@
 
 	if (kvp_file_init()) {
 		syslog(LOG_ERR, "Failed to initialize the pools");
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 
 	fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
 	if (fd < 0) {
 		syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 	addr.nl_family = AF_NETLINK;
 	addr.nl_pad = 0;
@@ -675,7 +1443,7 @@
 	if (error < 0) {
 		syslog(LOG_ERR, "bind failed; error:%d", error);
 		close(fd);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 	sock_opt = addr.nl_groups;
 	setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
@@ -687,7 +1455,7 @@
 	message->id.val = CN_KVP_VAL;
 
 	hv_msg = (struct hv_kvp_msg *)message->data;
-	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
 	message->ack = 0;
 	message->len = sizeof(struct hv_kvp_msg);
 
@@ -695,7 +1463,7 @@
 	if (len < 0) {
 		syslog(LOG_ERR, "netlink_send failed; error:%d", len);
 		close(fd);
-		exit(-1);
+		exit(EXIT_FAILURE);
 	}
 
 	pfd.fd = fd;
@@ -721,12 +1489,21 @@
 		incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
 		hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 
-		switch (hv_msg->kvp_hdr.operation) {
-		case KVP_OP_REGISTER:
+		/*
+		 * We will use the KVP header information to pass back
+		 * the error from this daemon. So, first copy the state
+		 * and set the error code to success.
+		 */
+		op = hv_msg->kvp_hdr.operation;
+		pool = hv_msg->kvp_hdr.pool;
+		hv_msg->error = HV_S_OK;
+
+		if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
 			/*
 			 * Driver is registering with us; stash away the version
 			 * information.
 			 */
+			in_hand_shake = 0;
 			p = (char *)hv_msg->body.kvp_register.version;
 			lic_version = malloc(strlen(p) + 1);
 			if (lic_version) {
@@ -737,44 +1514,82 @@
 				syslog(LOG_ERR, "malloc failed");
 			}
 			continue;
+		}
 
-		/*
-		 * The current protocol with the kernel component uses a
-		 * NULL key name to pass an error condition.
-		 * For the SET, GET and DELETE operations,
-		 * use the existing protocol to pass back error.
-		 */
+		switch (op) {
+		case KVP_OP_GET_IP_INFO:
+			kvp_ip_val = &hv_msg->body.kvp_ip_val;
+			if_name =
+			kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
+
+			if (if_name == NULL) {
+				/*
+				 * We could not map the mac address to an
+				 * interface name; return error.
+				 */
+				hv_msg->error = HV_E_FAIL;
+				break;
+			}
+			error = kvp_get_ip_info(
+						0, if_name, KVP_OP_GET_IP_INFO,
+						kvp_ip_val,
+						(MAX_IP_ADDR_SIZE * 2));
+
+			if (error)
+				hv_msg->error = error;
+
+			free(if_name);
+			break;
+
+		case KVP_OP_SET_IP_INFO:
+			kvp_ip_val = &hv_msg->body.kvp_ip_val;
+			if_name = kvp_get_if_name(
+					(char *)kvp_ip_val->adapter_id);
+			if (if_name == NULL) {
+				/*
+				 * We could not map the guid to an
+				 * interface name; return error.
+				 */
+				hv_msg->error = HV_GUID_NOTFOUND;
+				break;
+			}
+			error = kvp_set_ip_info(if_name, kvp_ip_val);
+			if (error)
+				hv_msg->error = error;
+
+			free(if_name);
+			break;
 
 		case KVP_OP_SET:
-			if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
+			if (kvp_key_add_or_modify(pool,
 					hv_msg->body.kvp_set.data.key,
 					hv_msg->body.kvp_set.data.key_size,
 					hv_msg->body.kvp_set.data.value,
 					hv_msg->body.kvp_set.data.value_size))
-				strcpy(hv_msg->body.kvp_set.data.key, "");
+					hv_msg->error = HV_S_CONT;
 			break;
 
 		case KVP_OP_GET:
-			if (kvp_get_value(hv_msg->kvp_hdr.pool,
+			if (kvp_get_value(pool,
 					hv_msg->body.kvp_set.data.key,
 					hv_msg->body.kvp_set.data.key_size,
 					hv_msg->body.kvp_set.data.value,
 					hv_msg->body.kvp_set.data.value_size))
-				strcpy(hv_msg->body.kvp_set.data.key, "");
+					hv_msg->error = HV_S_CONT;
 			break;
 
 		case KVP_OP_DELETE:
-			if (kvp_key_delete(hv_msg->kvp_hdr.pool,
+			if (kvp_key_delete(pool,
 					hv_msg->body.kvp_delete.key,
 					hv_msg->body.kvp_delete.key_size))
-				strcpy(hv_msg->body.kvp_delete.key, "");
+					hv_msg->error = HV_S_CONT;
 			break;
 
 		default:
 			break;
 		}
 
-		if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
+		if (op != KVP_OP_ENUMERATE)
 			goto kvp_done;
 
 		/*
@@ -782,13 +1597,14 @@
 		 * both the key and the value; if not read from the
 		 * appropriate pool.
 		 */
-		if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
-			kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
+		if (pool != KVP_POOL_AUTO) {
+			if (kvp_pool_enumerate(pool,
 					hv_msg->body.kvp_enum_data.index,
 					hv_msg->body.kvp_enum_data.data.key,
 					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
 					hv_msg->body.kvp_enum_data.data.value,
-					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+					HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
+					hv_msg->error = HV_S_CONT;
 			goto kvp_done;
 		}
 
@@ -807,13 +1623,13 @@
 			strcpy(key_value, lic_version);
 			break;
 		case NetworkAddressIPv4:
-			kvp_get_ip_address(AF_INET, key_value,
-					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
+				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv4");
 			break;
 		case NetworkAddressIPv6:
-			kvp_get_ip_address(AF_INET6, key_value,
-					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
+				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv6");
 			break;
 		case OSBuildNumber:
@@ -841,11 +1657,7 @@
 			strcpy(key_name, "ProcessorArchitecture");
 			break;
 		default:
-			strcpy(key_value, "Unknown Key");
-			/*
-			 * We use a null key name to terminate enumeration.
-			 */
-			strcpy(key_name, "");
+			hv_msg->error = HV_S_CONT;
 			break;
 		}
 		/*
@@ -863,7 +1675,7 @@
 		len = netlink_send(fd, incoming_cn_msg);
 		if (len < 0) {
 			syslog(LOG_ERR, "net_link send failed; error:%d", len);
-			exit(-1);
+			exit(EXIT_FAILURE);
 		}
 	}
 
diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh
new file mode 100755
index 0000000..3e9427e
--- /dev/null
+++ b/tools/hv/hv_set_ifconfig.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# This example script activates an interface based on the specified
+# configuration.
+#
+# In the interest of keeping the KVP daemon code free of distro specific
+# information; the kvp daemon code invokes this external script to configure
+# the interface.
+#
+# The only argument to this script is the configuration file that is to
+# be used to configure the interface.
+#
+# Each Distro is expected to implement this script in a distro specific
+# fashion. For instance on Distros that ship with Network Manager enabled,
+# this script can be based on the Network Manager APIs for configuring the
+# interface.
+#
+# This example script is based on a RHEL environment.
+#
+# Here is the format of the ip configuration file:
+#
+# HWADDR=macaddr
+# IF_NAME=interface name
+# DHCP=yes (This is optional; if yes, DHCP is configured)
+#
+# IPADDR=ipaddr1
+# IPADDR_1=ipaddr2
+# IPADDR_x=ipaddry (where y = x + 1)
+#
+# NETMASK=netmask1
+# NETMASK_x=netmasky (where y = x + 1)
+#
+# GATEWAY=ipaddr1
+# GATEWAY_x=ipaddry (where y = x + 1)
+#
+# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
+#
+# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
+# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
+# IPV6NETMASK.
+#
+# The host can specify multiple ipv4 and ipv6 addresses to be
+# configured for the interface. Furthermore, the configuration
+# needs to be persistent. A subsequent GET call on the interface
+# is expected to return the configuration that is set via the SET
+# call.
+#
+
+
+
+echo "IPV6INIT=yes" >> $1
+echo "NM_CONTROLLED=no" >> $1
+echo "PEERDNS=yes" >> $1
+echo "ONBOOT=yes" >> $1
+
+dhcp=$(grep "DHCP" $1 2>/dev/null)
+if [ "$dhcp" != "" ];
+then
+echo "BOOTPROTO=dhcp" >> $1;
+fi
+
+cp $1 /etc/sysconfig/network-scripts/
+
+
+interface=$(echo $1 | awk -F - '{ print $2 }')
+
+/sbin/ifdown $interface 2>/dev/null
+/sbin/ifup $interfac 2>/dev/null
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 14131cb..04d959f 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -129,7 +129,7 @@
 
 # Append required CFLAGS
 override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
-override CFLAGS += $(udis86-flags)
+override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
 
 ifeq ($(VERBOSE),1)
   Q =
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 5f34aa3..47264b4 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -24,13 +24,14 @@
  *  Frederic Weisbecker gave his permission to relicense the code to
  *  the Lesser General Public License.
  */
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <errno.h>
+#include <stdint.h>
+#include <limits.h>
 
 #include "event-parse.h"
 #include "event-utils.h"
@@ -117,14 +118,7 @@
 
 struct print_arg *alloc_arg(void)
 {
-	struct print_arg *arg;
-
-	arg = malloc_or_die(sizeof(*arg));
-	if (!arg)
-		return NULL;
-	memset(arg, 0, sizeof(*arg));
-
-	return arg;
+	return calloc(1, sizeof(struct print_arg));
 }
 
 struct cmdline {
@@ -158,7 +152,9 @@
 	struct cmdline *cmdlines;
 	int i;
 
-	cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
+	cmdlines = malloc(sizeof(*cmdlines) * pevent->cmdline_count);
+	if (!cmdlines)
+		return -1;
 
 	i = 0;
 	while (cmdlist) {
@@ -186,8 +182,8 @@
 	if (!pid)
 		return "<idle>";
 
-	if (!pevent->cmdlines)
-		cmdline_init(pevent);
+	if (!pevent->cmdlines && cmdline_init(pevent))
+		return "<not enough memory for cmdlines!>";
 
 	key.pid = pid;
 
@@ -215,8 +211,8 @@
 	if (!pid)
 		return 1;
 
-	if (!pevent->cmdlines)
-		cmdline_init(pevent);
+	if (!pevent->cmdlines && cmdline_init(pevent))
+		return 0;
 
 	key.pid = pid;
 
@@ -258,10 +254,14 @@
 		return -1;
 	}
 
-	cmdlines[pevent->cmdline_count].pid = pid;
 	cmdlines[pevent->cmdline_count].comm = strdup(comm);
-	if (!cmdlines[pevent->cmdline_count].comm)
-		die("malloc comm");
+	if (!cmdlines[pevent->cmdline_count].comm) {
+		free(cmdlines);
+		errno = ENOMEM;
+		return -1;
+	}
+
+	cmdlines[pevent->cmdline_count].pid = pid;
 		
 	if (cmdlines[pevent->cmdline_count].comm)
 		pevent->cmdline_count++;
@@ -288,10 +288,15 @@
 	if (pevent->cmdlines)
 		return add_new_comm(pevent, comm, pid);
 
-	item = malloc_or_die(sizeof(*item));
+	item = malloc(sizeof(*item));
+	if (!item)
+		return -1;
+
 	item->comm = strdup(comm);
-	if (!item->comm)
-		die("malloc comm");
+	if (!item->comm) {
+		free(item);
+		return -1;
+	}
 	item->pid = pid;
 	item->next = pevent->cmdlist;
 
@@ -355,7 +360,10 @@
 	struct func_map *func_map;
 	int i;
 
-	func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
+	func_map = malloc(sizeof(*func_map) * (pevent->func_count + 1));
+	if (!func_map)
+		return -1;
+
 	funclist = pevent->funclist;
 
 	i = 0;
@@ -455,25 +463,36 @@
 int pevent_register_function(struct pevent *pevent, char *func,
 			     unsigned long long addr, char *mod)
 {
-	struct func_list *item;
+	struct func_list *item = malloc(sizeof(*item));
 
-	item = malloc_or_die(sizeof(*item));
+	if (!item)
+		return -1;
 
 	item->next = pevent->funclist;
 	item->func = strdup(func);
-	if (mod)
+	if (!item->func)
+		goto out_free;
+
+	if (mod) {
 		item->mod = strdup(mod);
-	else
+		if (!item->mod)
+			goto out_free_func;
+	} else
 		item->mod = NULL;
 	item->addr = addr;
 
-	if (!item->func || (mod && !item->mod))
-		die("malloc func");
-
 	pevent->funclist = item;
 	pevent->func_count++;
 
 	return 0;
+
+out_free_func:
+	free(item->func);
+	item->func = NULL;
+out_free:
+	free(item);
+	errno = ENOMEM;
+	return -1;
 }
 
 /**
@@ -524,14 +543,16 @@
 	return 0;
 }
 
-static void printk_map_init(struct pevent *pevent)
+static int printk_map_init(struct pevent *pevent)
 {
 	struct printk_list *printklist;
 	struct printk_list *item;
 	struct printk_map *printk_map;
 	int i;
 
-	printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
+	printk_map = malloc(sizeof(*printk_map) * (pevent->printk_count + 1));
+	if (!printk_map)
+		return -1;
 
 	printklist = pevent->printklist;
 
@@ -549,6 +570,8 @@
 
 	pevent->printk_map = printk_map;
 	pevent->printklist = NULL;
+
+	return 0;
 }
 
 static struct printk_map *
@@ -557,8 +580,8 @@
 	struct printk_map *printk;
 	struct printk_map key;
 
-	if (!pevent->printk_map)
-		printk_map_init(pevent);
+	if (!pevent->printk_map && printk_map_init(pevent))
+		return NULL;
 
 	key.addr = addr;
 
@@ -580,21 +603,27 @@
 int pevent_register_print_string(struct pevent *pevent, char *fmt,
 				 unsigned long long addr)
 {
-	struct printk_list *item;
+	struct printk_list *item = malloc(sizeof(*item));
 
-	item = malloc_or_die(sizeof(*item));
+	if (!item)
+		return -1;
 
 	item->next = pevent->printklist;
-	item->printk = strdup(fmt);
 	item->addr = addr;
 
+	item->printk = strdup(fmt);
 	if (!item->printk)
-		die("malloc fmt");
+		goto out_free;
 
 	pevent->printklist = item;
 	pevent->printk_count++;
 
 	return 0;
+
+out_free:
+	free(item);
+	errno = ENOMEM;
+	return -1;
 }
 
 /**
@@ -619,24 +648,18 @@
 
 static struct event_format *alloc_event(void)
 {
-	struct event_format *event;
-
-	event = malloc(sizeof(*event));
-	if (!event)
-		return NULL;
-	memset(event, 0, sizeof(*event));
-
-	return event;
+	return calloc(1, sizeof(struct event_format));
 }
 
-static void add_event(struct pevent *pevent, struct event_format *event)
+static int add_event(struct pevent *pevent, struct event_format *event)
 {
 	int i;
+	struct event_format **events = realloc(pevent->events, sizeof(event) *
+					       (pevent->nr_events + 1));
+	if (!events)
+		return -1;
 
-	pevent->events = realloc(pevent->events, sizeof(event) *
-				 (pevent->nr_events + 1));
-	if (!pevent->events)
-		die("Can not allocate events");
+	pevent->events = events;
 
 	for (i = 0; i < pevent->nr_events; i++) {
 		if (pevent->events[i]->id > event->id)
@@ -651,6 +674,8 @@
 	pevent->nr_events++;
 
 	event->pevent = pevent;
+
+	return 0;
 }
 
 static int event_item_type(enum event_type type)
@@ -827,9 +852,9 @@
 	switch (type) {
 	case EVENT_NEWLINE:
 	case EVENT_DELIM:
-		*tok = malloc_or_die(2);
-		(*tok)[0] = ch;
-		(*tok)[1] = 0;
+		if (asprintf(tok, "%c", ch) < 0)
+			return EVENT_ERROR;
+
 		return type;
 
 	case EVENT_OP:
@@ -1240,8 +1265,10 @@
 
 		last_token = token;
 
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
+		field = calloc(1, sizeof(*field));
+		if (!field)
+			goto fail;
+
 		field->event = event;
 
 		/* read the rest of the type */
@@ -1282,7 +1309,7 @@
 		}
 
 		if (!field->type) {
-			die("no type found");
+			do_warning("%s: no type found", __func__);
 			goto fail;
 		}
 		field->name = last_token;
@@ -1329,7 +1356,7 @@
 				free_token(token);
 				type = read_token(&token);
 				if (type == EVENT_NONE) {
-					die("failed to find token");
+					do_warning("failed to find token");
 					goto fail;
 				}
 			}
@@ -1538,6 +1565,14 @@
 	left = alloc_arg();
 	right = alloc_arg();
 
+	if (!arg || !left || !right) {
+		do_warning("%s: not enough memory!", __func__);
+		/* arg will be freed at out_free */
+		free_arg(left);
+		free_arg(right);
+		goto out_free;
+	}
+
 	arg->type = PRINT_OP;
 	arg->op.left = left;
 	arg->op.right = right;
@@ -1580,6 +1615,12 @@
 	char *token = NULL;
 
 	arg = alloc_arg();
+	if (!arg) {
+		do_warning("%s: not enough memory!", __func__);
+		/* '*tok' is set to top->op.op.  No need to free. */
+		*tok = NULL;
+		return EVENT_ERROR;
+	}
 
 	*tok = NULL;
 	type = process_arg(event, arg, &token);
@@ -1595,8 +1636,7 @@
 	return type;
 
 out_free:
-	free_token(*tok);
-	*tok = NULL;
+	free_token(token);
 	free_arg(arg);
 	return EVENT_ERROR;
 }
@@ -1682,7 +1722,7 @@
 	if (arg->type == PRINT_OP && !arg->op.left) {
 		/* handle single op */
 		if (token[1]) {
-			die("bad op token %s", token);
+			do_warning("bad op token %s", token);
 			goto out_free;
 		}
 		switch (token[0]) {
@@ -1699,10 +1739,16 @@
 
 		/* make an empty left */
 		left = alloc_arg();
+		if (!left)
+			goto out_warn_free;
+
 		left->type = PRINT_NULL;
 		arg->op.left = left;
 
 		right = alloc_arg();
+		if (!right)
+			goto out_warn_free;
+
 		arg->op.right = right;
 
 		/* do not free the token, it belongs to an op */
@@ -1712,6 +1758,9 @@
 	} else if (strcmp(token, "?") == 0) {
 
 		left = alloc_arg();
+		if (!left)
+			goto out_warn_free;
+
 		/* copy the top arg to the left */
 		*left = *arg;
 
@@ -1720,6 +1769,7 @@
 		arg->op.left = left;
 		arg->op.prio = 0;
 
+		/* it will set arg->op.right */
 		type = process_cond(event, arg, tok);
 
 	} else if (strcmp(token, ">>") == 0 ||
@@ -1739,6 +1789,8 @@
 		   strcmp(token, "!=") == 0) {
 
 		left = alloc_arg();
+		if (!left)
+			goto out_warn_free;
 
 		/* copy the top arg to the left */
 		*left = *arg;
@@ -1746,6 +1798,7 @@
 		arg->type = PRINT_OP;
 		arg->op.op = token;
 		arg->op.left = left;
+		arg->op.right = NULL;
 
 		if (set_op_prio(arg) == -1) {
 			event->flags |= EVENT_FL_FAILED;
@@ -1762,12 +1815,14 @@
 		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
 			char *new_atom;
 
-			if (left->type != PRINT_ATOM)
-				die("bad pointer type");
+			if (left->type != PRINT_ATOM) {
+				do_warning("bad pointer type");
+				goto out_free;
+			}
 			new_atom = realloc(left->atom.atom,
 					    strlen(left->atom.atom) + 3);
 			if (!new_atom)
-				goto out_free;
+				goto out_warn_free;
 
 			left->atom.atom = new_atom;
 			strcat(left->atom.atom, " *");
@@ -1779,12 +1834,18 @@
 		}
 
 		right = alloc_arg();
+		if (!right)
+			goto out_warn_free;
+
 		type = process_arg_token(event, right, tok, type);
 		arg->op.right = right;
 
 	} else if (strcmp(token, "[") == 0) {
 
 		left = alloc_arg();
+		if (!left)
+			goto out_warn_free;
+
 		*left = *arg;
 
 		arg->type = PRINT_OP;
@@ -1793,6 +1854,7 @@
 
 		arg->op.prio = 0;
 
+		/* it will set arg->op.right */
 		type = process_array(event, arg, tok);
 
 	} else {
@@ -1816,14 +1878,16 @@
 
 	return type;
 
- out_free:
+out_warn_free:
+	do_warning("%s: not enough memory!", __func__);
+out_free:
 	free_token(token);
 	*tok = NULL;
 	return EVENT_ERROR;
 }
 
 static enum event_type
-process_entry(struct event_format *event __unused, struct print_arg *arg,
+process_entry(struct event_format *event __maybe_unused, struct print_arg *arg,
 	      char **tok)
 {
 	enum event_type type;
@@ -1880,7 +1944,11 @@
 			return val;
 		}
 
-		ref = malloc_or_die(len);
+		ref = malloc(len);
+		if (!ref) {
+			do_warning("%s: not enough memory!", __func__);
+			return val;
+		}
 		memcpy(ref, type, len);
 
 		/* chop off the " *" */
@@ -1957,8 +2025,10 @@
 static unsigned long long
 eval_type(unsigned long long val, struct print_arg *arg, int pointer)
 {
-	if (arg->type != PRINT_TYPE)
-		die("expected type argument");
+	if (arg->type != PRINT_TYPE) {
+		do_warning("expected type argument");
+		return 0;
+	}
 
 	return eval_type_str(val, arg->typecast.type, pointer);
 }
@@ -2143,7 +2213,7 @@
 	case PRINT_STRING:
 	case PRINT_BSTRING:
 	default:
-		die("invalid eval type %d", arg->type);
+		do_warning("invalid eval type %d", arg->type);
 		break;
 	}
 
@@ -2166,6 +2236,8 @@
 			break;
 
 		arg = alloc_arg();
+		if (!arg)
+			goto out_free;
 
 		free_token(token);
 		type = process_arg(event, arg, &token);
@@ -2179,30 +2251,33 @@
 		if (test_type_token(type, token, EVENT_DELIM, ","))
 			goto out_free;
 
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
+		field = calloc(1, sizeof(*field));
+		if (!field)
+			goto out_free;
 
 		value = arg_eval(arg);
 		if (value == NULL)
-			goto out_free;
+			goto out_free_field;
 		field->value = strdup(value);
 		if (field->value == NULL)
-			goto out_free;
+			goto out_free_field;
 
 		free_arg(arg);
 		arg = alloc_arg();
+		if (!arg)
+			goto out_free;
 
 		free_token(token);
 		type = process_arg(event, arg, &token);
 		if (test_type_token(type, token, EVENT_OP, "}"))
-			goto out_free;
+			goto out_free_field;
 
 		value = arg_eval(arg);
 		if (value == NULL)
-			goto out_free;
+			goto out_free_field;
 		field->str = strdup(value);
 		if (field->str == NULL)
-			goto out_free;
+			goto out_free_field;
 		free_arg(arg);
 		arg = NULL;
 
@@ -2216,6 +2291,8 @@
 	*tok = token;
 	return type;
 
+out_free_field:
+	free_flag_sym(field);
 out_free:
 	free_arg(arg);
 	free_token(token);
@@ -2235,6 +2312,10 @@
 	arg->type = PRINT_FLAGS;
 
 	field = alloc_arg();
+	if (!field) {
+		do_warning("%s: not enough memory!", __func__);
+		goto out_free;
+	}
 
 	type = process_arg(event, field, &token);
 
@@ -2243,7 +2324,7 @@
 		type = process_op(event, field, &token);
 
 	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
+		goto out_free_field;
 	free_token(token);
 
 	arg->flags.field = field;
@@ -2265,7 +2346,9 @@
 	type = read_token_item(tok);
 	return type;
 
- out_free:
+out_free_field:
+	free_arg(field);
+out_free:
 	free_token(token);
 	*tok = NULL;
 	return EVENT_ERROR;
@@ -2282,10 +2365,14 @@
 	arg->type = PRINT_SYMBOL;
 
 	field = alloc_arg();
+	if (!field) {
+		do_warning("%s: not enough memory!", __func__);
+		goto out_free;
+	}
 
 	type = process_arg(event, field, &token);
 	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
+		goto out_free_field;
 
 	arg->symbol.field = field;
 
@@ -2297,7 +2384,9 @@
 	type = read_token_item(tok);
 	return type;
 
- out_free:
+out_free_field:
+	free_arg(field);
+out_free:
 	free_token(token);
 	*tok = NULL;
 	return EVENT_ERROR;
@@ -2314,6 +2403,11 @@
 	arg->type = PRINT_HEX;
 
 	field = alloc_arg();
+	if (!field) {
+		do_warning("%s: not enough memory!", __func__);
+		goto out_free;
+	}
+
 	type = process_arg(event, field, &token);
 
 	if (test_type_token(type, token, EVENT_DELIM, ","))
@@ -2324,6 +2418,12 @@
 	free_token(token);
 
 	field = alloc_arg();
+	if (!field) {
+		do_warning("%s: not enough memory!", __func__);
+		*tok = NULL;
+		return EVENT_ERROR;
+	}
+
 	type = process_arg(event, field, &token);
 
 	if (test_type_token(type, token, EVENT_DELIM, ")"))
@@ -2381,6 +2481,12 @@
 
 	free_token(token);
 	arg = alloc_arg();
+	if (!field) {
+		do_warning("%s: not enough memory!", __func__);
+		*tok = NULL;
+		return EVENT_ERROR;
+	}
+
 	type = process_arg(event, arg, &token);
 	if (type == EVENT_ERROR)
 		goto out_free_arg;
@@ -2434,10 +2540,16 @@
 		/* make this a typecast and contine */
 
 		/* prevous must be an atom */
-		if (arg->type != PRINT_ATOM)
-			die("previous needed to be PRINT_ATOM");
+		if (arg->type != PRINT_ATOM) {
+			do_warning("previous needed to be PRINT_ATOM");
+			goto out_free;
+		}
 
 		item_arg = alloc_arg();
+		if (!item_arg) {
+			do_warning("%s: not enough memory!", __func__);
+			goto out_free;
+		}
 
 		arg->type = PRINT_TYPE;
 		arg->typecast.type = arg->atom.atom;
@@ -2457,7 +2569,8 @@
 
 
 static enum event_type
-process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
+process_str(struct event_format *event __maybe_unused, struct print_arg *arg,
+	    char **tok)
 {
 	enum event_type type;
 	char *token;
@@ -2532,6 +2645,11 @@
 	next_arg = &(arg->func.args);
 	for (i = 0; i < func->nr_args; i++) {
 		farg = alloc_arg();
+		if (!farg) {
+			do_warning("%s: not enough memory!", __func__);
+			return EVENT_ERROR;
+		}
+
 		type = process_arg(event, farg, &token);
 		if (i < (func->nr_args - 1))
 			test = ",";
@@ -2676,7 +2794,8 @@
 
 	case EVENT_ERROR ... EVENT_NEWLINE:
 	default:
-		die("unexpected type %d", type);
+		do_warning("unexpected type %d", type);
+		return EVENT_ERROR;
 	}
 	*tok = token;
 
@@ -2697,6 +2816,10 @@
 		}
 
 		arg = alloc_arg();
+		if (!arg) {
+			do_warning("%s: not enough memory!", __func__);
+			return -1;
+		}
 
 		type = process_arg(event, arg, &token);
 
@@ -2768,10 +2891,8 @@
 	if (type == EVENT_DQUOTE) {
 		char *cat;
 
-		cat = malloc_or_die(strlen(event->print_fmt.format) +
-				    strlen(token) + 1);
-		strcpy(cat, event->print_fmt.format);
-		strcat(cat, token);
+		if (asprintf(&cat, "%s%s", event->print_fmt.format, token) < 0)
+			goto fail;
 		free_token(token);
 		free_token(event->print_fmt.format);
 		event->print_fmt.format = NULL;
@@ -2925,8 +3046,10 @@
 	 * All events should have the same common elements.
 	 * Pick any event to find where the type is;
 	 */
-	if (!pevent->events)
-		die("no event_list!");
+	if (!pevent->events) {
+		do_warning("no event_list!");
+		return -1;
+	}
 
 	event = pevent->events[0];
 	field = pevent_find_common_field(event, type);
@@ -3084,7 +3207,8 @@
 		if (!arg->field.field) {
 			arg->field.field = pevent_find_any_field(event, arg->field.name);
 			if (!arg->field.field)
-				die("field %s not found", arg->field.name);
+				goto out_warning_field;
+			
 		}
 		/* must be a number */
 		val = pevent_read_number(pevent, data + arg->field.field->offset,
@@ -3145,8 +3269,10 @@
 				if (!larg->field.field) {
 					larg->field.field =
 						pevent_find_any_field(event, larg->field.name);
-					if (!larg->field.field)
-						die("field %s not found", larg->field.name);
+					if (!larg->field.field) {
+						arg = larg;
+						goto out_warning_field;
+					}
 				}
 				field_size = larg->field.field->elementsize;
 				offset = larg->field.field->offset +
@@ -3182,7 +3308,7 @@
 				val = left != right;
 				break;
 			default:
-				die("unknown op '%s'", arg->op.op);
+				goto out_warning_op;
 			}
 			break;
 		case '~':
@@ -3212,7 +3338,7 @@
 				val = left <= right;
 				break;
 			default:
-				die("unknown op '%s'", arg->op.op);
+				goto out_warning_op;
 			}
 			break;
 		case '>':
@@ -3227,12 +3353,13 @@
 				val = left >= right;
 				break;
 			default:
-				die("unknown op '%s'", arg->op.op);
+				goto out_warning_op;
 			}
 			break;
 		case '=':
 			if (arg->op.op[1] != '=')
-				die("unknown op '%s'", arg->op.op);
+				goto out_warning_op;
+
 			val = left == right;
 			break;
 		case '-':
@@ -3248,13 +3375,21 @@
 			val = left * right;
 			break;
 		default:
-			die("unknown op '%s'", arg->op.op);
+			goto out_warning_op;
 		}
 		break;
 	default: /* not sure what to do there */
 		return 0;
 	}
 	return val;
+
+out_warning_op:
+	do_warning("%s: unknown op '%s'", __func__, arg->op.op);
+	return 0;
+
+out_warning_field:
+	do_warning("%s: field %s not found", __func__, arg->field.name);
+	return 0;
 }
 
 struct flag {
@@ -3331,8 +3466,10 @@
 		field = arg->field.field;
 		if (!field) {
 			field = pevent_find_any_field(event, arg->field.name);
-			if (!field)
-				die("field %s not found", arg->field.name);
+			if (!field) {
+				str = arg->field.name;
+				goto out_warning_field;
+			}
 			arg->field.field = field;
 		}
 		/* Zero sized fields, mean the rest of the data */
@@ -3349,7 +3486,11 @@
 			trace_seq_printf(s, "%lx", addr);
 			break;
 		}
-		str = malloc_or_die(len + 1);
+		str = malloc(len + 1);
+		if (!str) {
+			do_warning("%s: not enough memory!", __func__);
+			return;
+		}
 		memcpy(str, data + field->offset, len);
 		str[len] = 0;
 		print_str_to_seq(s, format, len_arg, str);
@@ -3389,7 +3530,7 @@
 			str = arg->hex.field->field.name;
 			field = pevent_find_any_field(event, str);
 			if (!field)
-				die("field %s not found", str);
+				goto out_warning_field;
 			arg->hex.field->field.field = field;
 		}
 		hex = data + field->offset;
@@ -3441,6 +3582,11 @@
 		/* well... */
 		break;
 	}
+
+	return;
+
+out_warning_field:
+	do_warning("%s: field %s not found", __func__, arg->field.name);
 }
 
 static unsigned long long
@@ -3467,7 +3613,11 @@
 	farg = arg->func.args;
 	param = func_handle->params;
 
-	args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
+	ret = ULLONG_MAX;
+	args = malloc(sizeof(*args) * func_handle->nr_args);
+	if (!args)
+		goto out;
+
 	for (i = 0; i < func_handle->nr_args; i++) {
 		switch (param->type) {
 		case PEVENT_FUNC_ARG_INT:
@@ -3479,13 +3629,19 @@
 			trace_seq_init(&str);
 			print_str_arg(&str, data, size, event, "%s", -1, farg);
 			trace_seq_terminate(&str);
-			string = malloc_or_die(sizeof(*string));
+			string = malloc(sizeof(*string));
+			if (!string) {
+				do_warning("%s(%d): malloc str", __func__, __LINE__);
+				goto out_free;
+			}
 			string->next = strings;
 			string->str = strdup(str.buffer);
-			if (!string->str)
-				die("malloc str");
-
-			args[i] = (unsigned long long)string->str;
+			if (!string->str) {
+				free(string);
+				do_warning("%s(%d): malloc str", __func__, __LINE__);
+				goto out_free;
+			}
+			args[i] = (uintptr_t)string->str;
 			strings = string;
 			trace_seq_destroy(&str);
 			break;
@@ -3494,14 +3650,15 @@
 			 * Something went totally wrong, this is not
 			 * an input error, something in this code broke.
 			 */
-			die("Unexpected end of arguments\n");
-			break;
+			do_warning("Unexpected end of arguments\n");
+			goto out_free;
 		}
 		farg = farg->next;
 		param = param->next;
 	}
 
 	ret = (*func_handle->func)(s, args);
+out_free:
 	free(args);
 	while (strings) {
 		string = strings;
@@ -3515,6 +3672,18 @@
 	return ret;
 }
 
+static void free_args(struct print_arg *args)
+{
+	struct print_arg *next;
+
+	while (args) {
+		next = args->next;
+
+		free_arg(args);
+		args = next;
+	}
+}
+
 static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
 {
 	struct pevent *pevent = event->pevent;
@@ -3530,11 +3699,15 @@
 
 	if (!field) {
 		field = pevent_find_field(event, "buf");
-		if (!field)
-			die("can't find buffer field for binary printk");
+		if (!field) {
+			do_warning("can't find buffer field for binary printk");
+			return NULL;
+		}
 		ip_field = pevent_find_field(event, "ip");
-		if (!ip_field)
-			die("can't find ip field for binary printk");
+		if (!ip_field) {
+			do_warning("can't find ip field for binary printk");
+			return NULL;
+		}
 		pevent->bprint_buf_field = field;
 		pevent->bprint_ip_field = ip_field;
 	}
@@ -3545,13 +3718,18 @@
 	 * The first arg is the IP pointer.
 	 */
 	args = alloc_arg();
+	if (!args) {
+		do_warning("%s(%d): not enough memory!", __func__, __LINE__);
+		return NULL;
+	}
 	arg = args;
 	arg->next = NULL;
 	next = &arg->next;
 
 	arg->type = PRINT_ATOM;
-	arg->atom.atom = malloc_or_die(32);
-	sprintf(arg->atom.atom, "%lld", ip);
+		
+	if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
+		goto out_free;
 
 	/* skip the first "%pf : " */
 	for (ptr = fmt + 6, bptr = data + field->offset;
@@ -3606,10 +3784,17 @@
 				val = pevent_read_number(pevent, bptr, vsize);
 				bptr += vsize;
 				arg = alloc_arg();
+				if (!arg) {
+					do_warning("%s(%d): not enough memory!",
+						   __func__, __LINE__);
+					goto out_free;
+				}
 				arg->next = NULL;
 				arg->type = PRINT_ATOM;
-				arg->atom.atom = malloc_or_die(32);
-				sprintf(arg->atom.atom, "%lld", val);
+				if (asprintf(&arg->atom.atom, "%lld", val) < 0) {
+					free(arg);
+					goto out_free;
+				}
 				*next = arg;
 				next = &arg->next;
 				/*
@@ -3622,11 +3807,16 @@
 				break;
 			case 's':
 				arg = alloc_arg();
+				if (!arg) {
+					do_warning("%s(%d): not enough memory!",
+						   __func__, __LINE__);
+					goto out_free;
+				}
 				arg->next = NULL;
 				arg->type = PRINT_BSTRING;
 				arg->string.string = strdup(bptr);
 				if (!arg->string.string)
-					break;
+					goto out_free;
 				bptr += strlen(bptr) + 1;
 				*next = arg;
 				next = &arg->next;
@@ -3637,22 +3827,15 @@
 	}
 
 	return args;
-}
 
-static void free_args(struct print_arg *args)
-{
-	struct print_arg *next;
-
-	while (args) {
-		next = args->next;
-
-		free_arg(args);
-		args = next;
-	}
+out_free:
+	free_args(args);
+	return NULL;
 }
 
 static char *
-get_bprint_format(void *data, int size __unused, struct event_format *event)
+get_bprint_format(void *data, int size __maybe_unused,
+		  struct event_format *event)
 {
 	struct pevent *pevent = event->pevent;
 	unsigned long long addr;
@@ -3665,8 +3848,10 @@
 
 	if (!field) {
 		field = pevent_find_field(event, "fmt");
-		if (!field)
-			die("can't find format field for binary printk");
+		if (!field) {
+			do_warning("can't find format field for binary printk");
+			return NULL;
+		}
 		pevent->bprint_fmt_field = field;
 	}
 
@@ -3674,9 +3859,8 @@
 
 	printk = find_printk(pevent, addr);
 	if (!printk) {
-		format = malloc_or_die(45);
-		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
-			addr);
+		if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0)
+			return NULL;
 		return format;
 	}
 
@@ -3684,8 +3868,8 @@
 	/* Remove any quotes. */
 	if (*p == '"')
 		p++;
-	format = malloc_or_die(strlen(p) + 10);
-	sprintf(format, "%s : %s", "%pf", p);
+	if (asprintf(&format, "%s : %s", "%pf", p) < 0)
+		return NULL;
 	/* remove ending quotes and new line since we will add one too */
 	p = format + strlen(format) - 1;
 	if (*p == '"')
@@ -3720,8 +3904,11 @@
 	if (!arg->field.field) {
 		arg->field.field =
 			pevent_find_any_field(event, arg->field.name);
-		if (!arg->field.field)
-			die("field %s not found", arg->field.name);
+		if (!arg->field.field) {
+			do_warning("%s: field %s not found",
+				   __func__, arg->field.name);
+			return;
+		}
 	}
 	if (arg->field.field->size != 6) {
 		trace_seq_printf(s, "INVALIDMAC");
@@ -3888,8 +4075,11 @@
 				goto cont_process;
 			case '*':
 				/* The argument is the length. */
-				if (!arg)
-					die("no argument match");
+				if (!arg) {
+					do_warning("no argument match");
+					event->flags |= EVENT_FL_FAILED;
+					goto out_failed;
+				}
 				len_arg = eval_num_arg(data, size, event, arg);
 				len_as_arg = 1;
 				arg = arg->next;
@@ -3922,15 +4112,21 @@
 			case 'x':
 			case 'X':
 			case 'u':
-				if (!arg)
-					die("no argument match");
+				if (!arg) {
+					do_warning("no argument match");
+					event->flags |= EVENT_FL_FAILED;
+					goto out_failed;
+				}
 
 				len = ((unsigned long)ptr + 1) -
 					(unsigned long)saveptr;
 
 				/* should never happen */
-				if (len > 31)
-					die("bad format!");
+				if (len > 31) {
+					do_warning("bad format!");
+					event->flags |= EVENT_FL_FAILED;
+					len = 31;
+				}
 
 				memcpy(format, saveptr, len);
 				format[len] = 0;
@@ -3994,19 +4190,26 @@
 						trace_seq_printf(s, format, (long long)val);
 					break;
 				default:
-					die("bad count (%d)", ls);
+					do_warning("bad count (%d)", ls);
+					event->flags |= EVENT_FL_FAILED;
 				}
 				break;
 			case 's':
-				if (!arg)
-					die("no matching argument");
+				if (!arg) {
+					do_warning("no matching argument");
+					event->flags |= EVENT_FL_FAILED;
+					goto out_failed;
+				}
 
 				len = ((unsigned long)ptr + 1) -
 					(unsigned long)saveptr;
 
 				/* should never happen */
-				if (len > 31)
-					die("bad format!");
+				if (len > 31) {
+					do_warning("bad format!");
+					event->flags |= EVENT_FL_FAILED;
+					len = 31;
+				}
 
 				memcpy(format, saveptr, len);
 				format[len] = 0;
@@ -4024,6 +4227,11 @@
 			trace_seq_putc(s, *ptr);
 	}
 
+	if (event->flags & EVENT_FL_FAILED) {
+out_failed:
+		trace_seq_printf(s, "[FAILED TO PARSE]");
+	}
+
 	if (args) {
 		free_args(args);
 		free(bprint_fmt);
@@ -4356,7 +4564,10 @@
 	struct format_field *field;
 	int i = 0;
 
-	fields = malloc_or_die(sizeof(*fields) * (count + 1));
+	fields = malloc(sizeof(*fields) * (count + 1));
+	if (!fields)
+		return NULL;
+
 	for (field = list; field; field = field->next) {
 		fields[i++] = field;
 		if (i == count + 1) {
@@ -4672,6 +4883,142 @@
 }
 
 /**
+ * __pevent_parse_format - parse the event format
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+enum pevent_errno __pevent_parse_format(struct event_format **eventp,
+					struct pevent *pevent, const char *buf,
+					unsigned long size, const char *sys)
+{
+	struct event_format *event;
+	int ret;
+
+	init_input_buf(buf, size);
+
+	*eventp = event = alloc_event();
+	if (!event)
+		return PEVENT_ERRNO__MEM_ALLOC_FAILED;
+
+	event->name = event_read_name();
+	if (!event->name) {
+		/* Bad event? */
+		ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
+		goto event_alloc_failed;
+	}
+
+	if (strcmp(sys, "ftrace") == 0) {
+		event->flags |= EVENT_FL_ISFTRACE;
+
+		if (strcmp(event->name, "bprint") == 0)
+			event->flags |= EVENT_FL_ISBPRINT;
+	}
+		
+	event->id = event_read_id();
+	if (event->id < 0) {
+		ret = PEVENT_ERRNO__READ_ID_FAILED;
+		/*
+		 * This isn't an allocation error actually.
+		 * But as the ID is critical, just bail out.
+		 */
+		goto event_alloc_failed;
+	}
+
+	event->system = strdup(sys);
+	if (!event->system) {
+		ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
+		goto event_alloc_failed;
+	}
+
+	ret = event_read_format(event);
+	if (ret < 0) {
+		ret = PEVENT_ERRNO__READ_FORMAT_FAILED;
+		goto event_parse_failed;
+	}
+
+	/*
+	 * If the event has an override, don't print warnings if the event
+	 * print format fails to parse.
+	 */
+	if (pevent && find_event_handle(pevent, event))
+		show_warning = 0;
+
+	ret = event_read_print(event);
+	show_warning = 1;
+
+	if (ret < 0) {
+		ret = PEVENT_ERRNO__READ_PRINT_FAILED;
+		goto event_parse_failed;
+	}
+
+	if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
+		struct format_field *field;
+		struct print_arg *arg, **list;
+
+		/* old ftrace had no args */
+		list = &event->print_fmt.args;
+		for (field = event->format.fields; field; field = field->next) {
+			arg = alloc_arg();
+			if (!arg) {
+				event->flags |= EVENT_FL_FAILED;
+				return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED;
+			}
+			arg->type = PRINT_FIELD;
+			arg->field.name = strdup(field->name);
+			if (!arg->field.name) {
+				event->flags |= EVENT_FL_FAILED;
+				free_arg(arg);
+				return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED;
+			}
+			arg->field.field = field;
+			*list = arg;
+			list = &arg->next;
+		}
+		return 0;
+	}
+
+	return 0;
+
+ event_parse_failed:
+	event->flags |= EVENT_FL_FAILED;
+	return ret;
+
+ event_alloc_failed:
+	free(event->system);
+	free(event->name);
+	free(event);
+	*eventp = NULL;
+	return ret;
+}
+
+/**
+ * pevent_parse_format - parse the event format
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
+				      unsigned long size, const char *sys)
+{
+	return __pevent_parse_format(eventp, NULL, buf, size, sys);
+}
+
+/**
  * pevent_parse_event - parse the event format
  * @pevent: the handle to the pevent
  * @buf: the buffer storing the event format string
@@ -4685,90 +5032,21 @@
  *
  * /sys/kernel/debug/tracing/events/.../.../format
  */
-int pevent_parse_event(struct pevent *pevent,
-		       const char *buf, unsigned long size,
-		       const char *sys)
+enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
+				     unsigned long size, const char *sys)
 {
-	struct event_format *event;
-	int ret;
+	struct event_format *event = NULL;
+	int ret = __pevent_parse_format(&event, pevent, buf, size, sys);
 
-	init_input_buf(buf, size);
-
-	event = alloc_event();
-	if (!event)
-		return -ENOMEM;
-
-	event->name = event_read_name();
-	if (!event->name) {
-		/* Bad event? */
-		free(event);
-		return -1;
-	}
-
-	if (strcmp(sys, "ftrace") == 0) {
-
-		event->flags |= EVENT_FL_ISFTRACE;
-
-		if (strcmp(event->name, "bprint") == 0)
-			event->flags |= EVENT_FL_ISBPRINT;
-	}
-		
-	event->id = event_read_id();
-	if (event->id < 0)
-		die("failed to read event id");
-
-	event->system = strdup(sys);
-	if (!event->system)
-		die("failed to allocate system");
+	if (event == NULL)
+		return ret;
 
 	/* Add pevent to event so that it can be referenced */
 	event->pevent = pevent;
 
-	ret = event_read_format(event);
-	if (ret < 0) {
-		do_warning("failed to read event format for %s", event->name);
-		goto event_failed;
-	}
-
-	/*
-	 * If the event has an override, don't print warnings if the event
-	 * print format fails to parse.
-	 */
-	if (find_event_handle(pevent, event))
-		show_warning = 0;
-
-	ret = event_read_print(event);
-	if (ret < 0) {
-		do_warning("failed to read event print fmt for %s",
-			   event->name);
-		show_warning = 1;
-		goto event_failed;
-	}
-	show_warning = 1;
-
-	add_event(pevent, event);
-
-	if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
-		struct format_field *field;
-		struct print_arg *arg, **list;
-
-		/* old ftrace had no args */
-
-		list = &event->print_fmt.args;
-		for (field = event->format.fields; field; field = field->next) {
-			arg = alloc_arg();
-			*list = arg;
-			list = &arg->next;
-			arg->type = PRINT_FIELD;
-			arg->field.name = strdup(field->name);
-			if (!arg->field.name) {
-				do_warning("failed to allocate field name");
-				event->flags |= EVENT_FL_FAILED;
-				return -1;
-			}
-			arg->field.field = field;
-		}
-		return 0;
+	if (add_event(pevent, event)) {
+		ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
+		goto event_add_failed;
 	}
 
 #define PRINT_ARGS 0
@@ -4777,11 +5055,57 @@
 
 	return 0;
 
- event_failed:
-	event->flags |= EVENT_FL_FAILED;
-	/* still add it even if it failed */
-	add_event(pevent, event);
-	return -1;
+event_add_failed:
+	pevent_free_format(event);
+	return ret;
+}
+
+#undef _PE
+#define _PE(code, str) str
+static const char * const pevent_error_str[] = {
+	PEVENT_ERRORS
+};
+#undef _PE
+
+int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
+		    char *buf, size_t buflen)
+{
+	int idx;
+	const char *msg;
+
+	if (errnum >= 0) {
+		msg = strerror_r(errnum, buf, buflen);
+		if (msg != buf) {
+			size_t len = strlen(msg);
+			memcpy(buf, msg, min(buflen - 1, len));
+			*(buf + min(buflen - 1, len)) = '\0';
+		}
+		return 0;
+	}
+
+	if (errnum <= __PEVENT_ERRNO__START ||
+	    errnum >= __PEVENT_ERRNO__END)
+		return -1;
+
+	idx = errnum - __PEVENT_ERRNO__START - 1;
+	msg = pevent_error_str[idx];
+
+	switch (errnum) {
+	case PEVENT_ERRNO__MEM_ALLOC_FAILED:
+	case PEVENT_ERRNO__PARSE_EVENT_FAILED:
+	case PEVENT_ERRNO__READ_ID_FAILED:
+	case PEVENT_ERRNO__READ_FORMAT_FAILED:
+	case PEVENT_ERRNO__READ_PRINT_FAILED:
+	case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
+		snprintf(buf, buflen, "%s", msg);
+		break;
+
+	default:
+		/* cannot reach here */
+		break;
+	}
+
+	return 0;
 }
 
 int get_field_val(struct trace_seq *s, struct format_field *field,
@@ -5000,6 +5324,7 @@
 	struct pevent_func_params *param;
 	enum pevent_func_arg_type type;
 	va_list ap;
+	int ret;
 
 	func_handle = find_func_handler(pevent, name);
 	if (func_handle) {
@@ -5012,14 +5337,20 @@
 		remove_func_handler(pevent, name);
 	}
 
-	func_handle = malloc_or_die(sizeof(*func_handle));
-	memset(func_handle, 0, sizeof(*func_handle));
+	func_handle = calloc(1, sizeof(*func_handle));
+	if (!func_handle) {
+		do_warning("Failed to allocate function handler");
+		return PEVENT_ERRNO__MEM_ALLOC_FAILED;
+	}
 
 	func_handle->ret_type = ret_type;
 	func_handle->name = strdup(name);
 	func_handle->func = func;
-	if (!func_handle->name)
-		die("Failed to allocate function name");
+	if (!func_handle->name) {
+		do_warning("Failed to allocate function name");
+		free(func_handle);
+		return PEVENT_ERRNO__MEM_ALLOC_FAILED;
+	}
 
 	next_param = &(func_handle->params);
 	va_start(ap, name);
@@ -5029,11 +5360,17 @@
 			break;
 
 		if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
-			warning("Invalid argument type %d", type);
+			do_warning("Invalid argument type %d", type);
+			ret = PEVENT_ERRNO__INVALID_ARG_TYPE;
 			goto out_free;
 		}
 
-		param = malloc_or_die(sizeof(*param));
+		param = malloc(sizeof(*param));
+		if (!param) {
+			do_warning("Failed to allocate function param");
+			ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
+			goto out_free;
+		}
 		param->type = type;
 		param->next = NULL;
 
@@ -5051,7 +5388,7 @@
  out_free:
 	va_end(ap);
 	free_func_handle(func_handle);
-	return -1;
+	return ret;
 }
 
 /**
@@ -5103,8 +5440,12 @@
 
  not_found:
 	/* Save for later use. */
-	handle = malloc_or_die(sizeof(*handle));
-	memset(handle, 0, sizeof(*handle));
+	handle = calloc(1, sizeof(*handle));
+	if (!handle) {
+		do_warning("Failed to allocate event handler");
+		return PEVENT_ERRNO__MEM_ALLOC_FAILED;
+	}
+
 	handle->id = id;
 	if (event_name)
 		handle->event_name = strdup(event_name);
@@ -5113,7 +5454,11 @@
 
 	if ((event_name && !handle->event_name) ||
 	    (sys_name && !handle->sys_name)) {
-		die("Failed to allocate event/sys name");
+		do_warning("Failed to allocate event/sys name");
+		free((void *)handle->event_name);
+		free((void *)handle->sys_name);
+		free(handle);
+		return PEVENT_ERRNO__MEM_ALLOC_FAILED;
 	}
 
 	handle->func = func;
@@ -5129,13 +5474,10 @@
  */
 struct pevent *pevent_alloc(void)
 {
-	struct pevent *pevent;
+	struct pevent *pevent = calloc(1, sizeof(*pevent));
 
-	pevent = malloc(sizeof(*pevent));
-	if (!pevent)
-		return NULL;
-	memset(pevent, 0, sizeof(*pevent));
-	pevent->ref_count = 1;
+	if (pevent)
+		pevent->ref_count = 1;
 
 	return pevent;
 }
@@ -5164,7 +5506,7 @@
 	free_format_fields(format->fields);
 }
 
-static void free_event(struct event_format *event)
+void pevent_free_format(struct event_format *event)
 {
 	free(event->name);
 	free(event->system);
@@ -5250,7 +5592,7 @@
 	}
 
 	for (i = 0; i < pevent->nr_events; i++)
-		free_event(pevent->events[i]);
+		pevent_free_format(pevent->events[i]);
 
 	while (pevent->handlers) {
 		handle = pevent->handlers;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 5772ad8..24a4bba 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -24,8 +24,8 @@
 #include <stdarg.h>
 #include <regex.h>
 
-#ifndef __unused
-#define __unused __attribute__ ((unused))
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((unused))
 #endif
 
 /* ----------------------- trace_seq ----------------------- */
@@ -49,7 +49,7 @@
 	int			cpu;
 	int			ref_count;
 	int			locked;		/* Do not free, even if ref_count is zero */
-	void			*private;
+	void			*priv;
 #if DEBUG_RECORD
 	struct pevent_record	*prev;
 	struct pevent_record	*next;
@@ -106,7 +106,7 @@
 	char				*plugin_alias;
 	char				*description;
 	char				*value;
-	void				*private;
+	void				*priv;
 	int				set;
 };
 
@@ -345,6 +345,35 @@
 	PEVENT_NSEC_OUTPUT		= 1,	/* output in NSECS */
 };
 
+#define PEVENT_ERRORS 							      \
+	_PE(MEM_ALLOC_FAILED,	"failed to allocate memory"),		      \
+	_PE(PARSE_EVENT_FAILED,	"failed to parse event"),		      \
+	_PE(READ_ID_FAILED,	"failed to read event id"),		      \
+	_PE(READ_FORMAT_FAILED,	"failed to read event format"),		      \
+	_PE(READ_PRINT_FAILED,	"failed to read event print fmt"), 	      \
+	_PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
+	_PE(INVALID_ARG_TYPE,	"invalid argument type")
+
+#undef _PE
+#define _PE(__code, __str) PEVENT_ERRNO__ ## __code
+enum pevent_errno {
+	PEVENT_ERRNO__SUCCESS			= 0,
+
+	/*
+	 * Choose an arbitrary negative big number not to clash with standard
+	 * errno since SUS requires the errno has distinct positive values.
+	 * See 'Issue 6' in the link below.
+	 *
+	 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+	 */
+	__PEVENT_ERRNO__START			= -100000,
+
+	PEVENT_ERRORS,
+
+	__PEVENT_ERRNO__END,
+};
+#undef _PE
+
 struct cmdline;
 struct cmdline_list;
 struct func_map;
@@ -509,8 +538,11 @@
 int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
 			     int long_size);
 
-int pevent_parse_event(struct pevent *pevent, const char *buf,
-		       unsigned long size, const char *sys);
+enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
+				     unsigned long size, const char *sys);
+enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
+				      unsigned long size, const char *sys);
+void pevent_free_format(struct event_format *event);
 
 void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
 			   const char *name, struct pevent_record *record,
@@ -561,6 +593,8 @@
 const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
 void pevent_event_info(struct trace_seq *s, struct event_format *event,
 		       struct pevent_record *record);
+int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
+		    char *buf, size_t buflen);
 
 struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
 struct format_field **pevent_event_common_fields(struct event_format *event);
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
index 0829638..bc07500 100644
--- a/tools/lib/traceevent/event-utils.h
+++ b/tools/lib/traceevent/event-utils.h
@@ -39,6 +39,12 @@
 void __vwarning(const char *fmt, ...);
 void __vpr_stat(const char *fmt, ...);
 
+#define min(x, y) ({				\
+	typeof(x) _min1 = (x);			\
+	typeof(y) _min2 = (y);			\
+	(void) (&_min1 == &_min2);		\
+	_min1 < _min2 ? _min1 : _min2; })
+
 static inline char *strim(char *string)
 {
 	char *ret;
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 26b823b..8f8fbc2 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -21,3 +21,5 @@
 config.mak.autogen
 *-bison.*
 *-flex.*
+*.pyc
+*.pyo
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index ca600e0..9f2e44f 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -195,10 +195,10 @@
 #install-html: html
 #	'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
 
-../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
-	$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
+$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
+	$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
 
--include ../PERF-VERSION-FILE
+-include $(OUTPUT)PERF-VERSION-FILE
 
 #
 # Determine "include::" file references in asciidoc files.
diff --git a/tools/perf/Documentation/jit-interface.txt b/tools/perf/Documentation/jit-interface.txt
new file mode 100644
index 0000000..a8656f5
--- /dev/null
+++ b/tools/perf/Documentation/jit-interface.txt
@@ -0,0 +1,15 @@
+perf supports a simple JIT interface to resolve symbols for dynamic code generated
+by a JIT.
+
+The JIT has to write a /tmp/perf-%d.map  (%d = pid of process) file
+
+This is a text file.
+
+Each line has the following format, fields separated with spaces:
+
+START SIZE symbolname
+
+START and SIZE are hex numbers without 0x.
+symbolname is the rest of the line, so it could contain special characters.
+
+The ownership of the file has to match the process.
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c89f9e1..c8ffd9f 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -85,6 +85,9 @@
 -M::
 --disassembler-style=:: Set disassembler style for objdump.
 
+--objdump=<path>::
+        Path to objdump binary.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 74d7481..ab7f667 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -17,6 +17,9 @@
 
 If no parameters are passed it will assume perf.data.old and perf.data.
 
+The differential profile is displayed only for events matching both
+specified perf.data files.
+
 OPTIONS
 -------
 -M::
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index dd84cb2..326f2cb 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -12,7 +12,7 @@
 	[--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
 	{top|record|report|diff|buildid-list}
 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
-	| --guestvmlinux=<path>] {top|record|report|diff|buildid-list}
+	| --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
 
 DESCRIPTION
 -----------
@@ -38,6 +38,18 @@
   so that other tools can be used to fetch packages with matching symbol tables
   for use by perf report.
 
+  'perf kvm stat <command>' to run a command and gather performance counter
+  statistics.
+  Especially, perf 'kvm stat record/report' generates a statistical analysis
+  of KVM events. Currently, vmexit, mmio and ioport events are supported.
+  'perf kvm stat record <command>' records kvm events and the events between
+  start and end <command>.
+  And this command produces a file which contains tracing results of kvm
+  events.
+
+  'perf kvm stat report' reports statistical data which includes events
+  handled time, samples, and so on.
+
 OPTIONS
 -------
 -i::
@@ -68,7 +80,21 @@
 --guestvmlinux=<path>::
 	Guest os kernel vmlinux.
 
+STAT REPORT OPTIONS
+-------------------
+--vcpu=<value>::
+       analyze events which occures on this vcpu. (default: all vcpus)
+
+--events=<value>::
+       events to be analyzed. Possible values: vmexit, mmio, ioport.
+       (default: vmexit)
+-k::
+--key=<value>::
+       Sorting key. Possible values: sample (default, sort by samples
+       number), time (sort by average time).
+
 SEE ALSO
 --------
 linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
-linkperf:perf-diff[1], linkperf:perf-buildid-list[1]
+linkperf:perf-diff[1], linkperf:perf-buildid-list[1],
+linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index ddc2252..d1e39dc 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,24 +15,43 @@
 This command displays the symbolic event types which can be selected in the
 various perf commands with the -e option.
 
+[[EVENT_MODIFIERS]]
 EVENT MODIFIERS
 ---------------
 
 Events can optionally have a modifer by appending a colon and one or
-more modifiers.  Modifiers allow the user to restrict when events are
-counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
-Additional modifiers are 'G' for guest counting (in KVM guests) and 'H'
-for host counting (not in KVM guests).
+more modifiers. Modifiers allow the user to restrict the events to be
+counted. The following modifiers exist:
+
+ u - user-space counting
+ k - kernel counting
+ h - hypervisor counting
+ G - guest counting (in KVM guests)
+ H - host counting (not in KVM guests)
+ p - precise level
 
 The 'p' modifier can be used for specifying how precise the instruction
-address should be. The 'p' modifier is currently only implemented for
-Intel PEBS and can be specified multiple times:
-  0 - SAMPLE_IP can have arbitrary skid
-  1 - SAMPLE_IP must have constant skid
-  2 - SAMPLE_IP requested to have 0 skid
-  3 - SAMPLE_IP must have 0 skid
+address should be. The 'p' modifier can be specified multiple times:
 
-The PEBS implementation now supports up to 2.
+ 0 - SAMPLE_IP can have arbitrary skid
+ 1 - SAMPLE_IP must have constant skid
+ 2 - SAMPLE_IP requested to have 0 skid
+ 3 - SAMPLE_IP must have 0 skid
+
+For Intel systems precise event sampling is implemented with PEBS
+which supports up to precise-level 2.
+
+On AMD systems it is implemented using IBS (up to precise-level 2).
+The precise modifier works with event types 0x76 (cpu-cycles, CPU
+clocks not halted) and 0xC1 (micro-ops retired). Both events map to
+IBS execution sampling (IBS op) with the IBS Op Counter Control bit
+(IbsOpCntCtl) set respectively (see AMD64 Architecture Programmer’s
+Manual Volume 2: System Programming, 13.3 Instruction-Based
+Sampling). Examples to use IBS:
+
+ perf record -a -e cpu-cycles:p ...    # use ibs op counting cycles
+ perf record -a -e r076:p ...          # same as -e cpu-cycles:p
+ perf record -a -e r0C1:p ...          # use ibs op counting micro-ops
 
 RAW HARDWARE EVENT DESCRIPTOR
 -----------------------------
@@ -44,6 +63,11 @@
 of IA32_PERFEVTSELx MSRs) or AMD's PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System Programming], Page 344,
 Figure 13-7 Performance Event-Select Register (PerfEvtSeln)).
 
+Note: Only the following bit fields can be set in x86 counter
+registers: event, umask, edge, inv, cmask. Esp. guest/host only and
+OS/user mode flags must be setup using <<EVENT_MODIFIERS, EVENT
+MODIFIERS>>.
+
 Example:
 
 If the Intel docs for a QM720 Core i7 describe an event as:
@@ -91,4 +115,4 @@
 linkperf:perf-stat[1], linkperf:perf-top[1],
 linkperf:perf-record[1],
 http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide],
-http://support.amd.com/us/Processor_TechDocs/24593.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming]
+http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 495210a..f4d91be 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -168,6 +168,9 @@
 	branch stacks and it will automatically switch to the branch view mode,
 	unless --no-branch-stack is used.
 
+--objdump=<path>::
+        Path to objdump binary.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index 3152cca..d00bef2 100644
--- a/tools/perf/Documentation/perf-script-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -116,8 +116,8 @@
 descriptions below):
 
 ----
- use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
- use lib "./perf-script-Util/lib";
+ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+ use lib "./Perf-Trace-Util/lib";
  use Perf::Trace::Core;
  use Perf::Trace::Context;
  use Perf::Trace::Util;
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 4710220..a4027f2 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -129,7 +129,7 @@
 import sys
 
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-	'/scripts/python/perf-script-Util/lib/Perf/Trace')
+	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 
 from perf_trace_context import *
 from Core import *
@@ -216,7 +216,7 @@
 import sys
 
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-	'/scripts/python/perf-script-Util/lib/Perf/Trace')
+	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 
 from perf_trace_context import *
 from Core import *
@@ -279,7 +279,7 @@
 import sys
 
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-	'/scripts/python/perf-script-Util/lib/Perf/Trace')
+	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 
 from perf_trace_context import *
 from Core import *
@@ -391,7 +391,7 @@
 drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
 drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
 -rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
-drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util
+drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
 -rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
 ----
 
@@ -518,7 +518,7 @@
  import sys
 
  sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-	      '/scripts/python/perf-script-Util/lib/Perf/Trace')
+	      '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 
  from perf_trace_context import *
  from Core import *
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
new file mode 100644
index 0000000..3a2ae37
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -0,0 +1,53 @@
+perf-trace(1)
+=============
+
+NAME
+----
+perf-trace - strace inspired tool
+
+SYNOPSIS
+--------
+[verse]
+'perf trace'
+
+DESCRIPTION
+-----------
+This command will show the events associated with the target, initially
+syscalls, but other system events like pagefaults, task lifetime events,
+scheduling events, etc.
+
+Initially this is a live mode only tool, but eventually will work with
+perf.data files like the other tools, allowing a detached 'record' from
+analysis phases.
+
+OPTIONS
+-------
+
+--all-cpus::
+        System-wide collection from all CPUs.
+
+-p::
+--pid=::
+	Record events on existing process ID (comma separated list).
+
+--tid=::
+        Record events on existing thread ID (comma separated list).
+
+--uid=::
+        Record events in threads owned by uid. Name or number.
+
+--no-inherit::
+	Child tasks do not inherit counters.
+
+--mmap-pages=::
+	Number of mmap data pages. Must be a power of two.
+
+--cpu::
+Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
+comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
+In per-thread mode with inheritance mode on (default), Events are captured only when
+the thread executes on the designated CPUs. Default is to monitor all CPUs.
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index b4b572e..80db3f4 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -10,8 +10,12 @@
 lib/rbtree.c
 include/linux/swab.h
 arch/*/include/asm/unistd*.h
+arch/*/include/asm/perf_regs.h
 arch/*/lib/memcpy*.S
 arch/*/lib/memset*.S
 include/linux/poison.h
 include/linux/magic.h
 include/linux/hw_breakpoint.h
+arch/x86/include/asm/svm.h
+arch/x86/include/asm/vmx.h
+arch/x86/include/asm/kvm_host.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 35655c3..e5e71e7 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -37,7 +37,14 @@
 #
 # Define NO_NEWT if you do not want TUI support.
 #
+# Define NO_GTK2 if you do not want GTK+ GUI support.
+#
 # Define NO_DEMANGLE if you do not want C++ symbol demangling.
+#
+# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
+#
+# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
+# backtrace post unwind.
 
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
 	@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -50,16 +57,19 @@
 				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
 				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
 				  -e s/sh[234].*/sh/ )
+NO_PERF_REGS := 1
 
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
-        ARCH := x86
+	override ARCH := x86
+	NO_PERF_REGS := 0
+	LIBUNWIND_LIBS = -lunwind -lunwind-x86
 endif
 ifeq ($(ARCH),x86_64)
-	ARCH := x86
+	override ARCH := x86
 	IS_X86_64 := 0
 	ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
 		IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
@@ -69,6 +79,8 @@
 		ARCH_CFLAGS := -DARCH_X86_64
 		ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
 	endif
+	NO_PERF_REGS := 0
+	LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
 endif
 
 # Treat warnings as errors unless directed not to
@@ -89,7 +101,7 @@
 	PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
 endif
 
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
 EXTLIBS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 ALL_LDFLAGS = $(LDFLAGS)
@@ -186,10 +198,10 @@
 
 TRACE_EVENT_DIR = ../lib/traceevent/
 
-ifeq ("$(origin O)", "command line")
-	TE_PATH=$(OUTPUT)/
+ifneq ($(OUTPUT),)
+	TE_PATH=$(OUTPUT)
 else
-	TE_PATH=$(TRACE_EVENT_DIR)/
+	TE_PATH=$(TRACE_EVENT_DIR)
 endif
 
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -221,13 +233,13 @@
 FLEX = flex
 BISON= bison
 
-$(OUTPUT)util/parse-events-flex.c: util/parse-events.l
+$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
 	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
 
 $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
 	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
 
-$(OUTPUT)util/pmu-flex.c: util/pmu.l
+$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
 	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
 
 $(OUTPUT)util/pmu-bison.c: util/pmu.y
@@ -252,6 +264,7 @@
 LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
 LIB_H += util/include/linux/export.h
+LIB_H += util/include/linux/magic.h
 LIB_H += util/include/linux/poison.h
 LIB_H += util/include/linux/prefetch.h
 LIB_H += util/include/linux/rbtree.h
@@ -321,6 +334,10 @@
 LIB_H += util/target.h
 LIB_H += util/rblist.h
 LIB_H += util/intlist.h
+LIB_H += util/perf_regs.h
+LIB_H += util/unwind.h
+LIB_H += ui/helpline.h
+LIB_H += util/vdso.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -356,6 +373,7 @@
 LIB_OBJS += $(OUTPUT)util/wrapper.o
 LIB_OBJS += $(OUTPUT)util/sigchain.o
 LIB_OBJS += $(OUTPUT)util/symbol.o
+LIB_OBJS += $(OUTPUT)util/symbol-elf.o
 LIB_OBJS += $(OUTPUT)util/dso-test-data.o
 LIB_OBJS += $(OUTPUT)util/color.o
 LIB_OBJS += $(OUTPUT)util/pager.o
@@ -387,11 +405,15 @@
 LIB_OBJS += $(OUTPUT)util/target.o
 LIB_OBJS += $(OUTPUT)util/rblist.o
 LIB_OBJS += $(OUTPUT)util/intlist.o
+LIB_OBJS += $(OUTPUT)util/vdso.o
+LIB_OBJS += $(OUTPUT)util/stat.o
+
+LIB_OBJS += $(OUTPUT)ui/helpline.o
+LIB_OBJS += $(OUTPUT)ui/hist.o
+LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
-
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
-
 # Benchmark modules
 BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
 BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
@@ -449,13 +471,38 @@
 -include config.mak.autogen
 -include config.mak
 
-ifndef NO_DWARF
-FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
-ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
-	msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
+ifdef NO_LIBELF
 	NO_DWARF := 1
-endif # Dwarf support
-endif # NO_DWARF
+	NO_DEMANGLE := 1
+	NO_LIBUNWIND := 1
+else
+FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
+	FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
+	ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
+		msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
+	else
+		NO_LIBELF := 1
+		NO_DWARF := 1
+		NO_DEMANGLE := 1
+	endif
+endif
+endif # NO_LIBELF
+
+ifndef NO_LIBUNWIND
+# for linking with debug library, run like:
+# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
+ifdef LIBUNWIND_DIR
+	LIBUNWIND_CFLAGS  := -I$(LIBUNWIND_DIR)/include
+	LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
+endif
+
+FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y)
+	msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
+	NO_LIBUNWIND := 1
+endif # Libunwind support
+endif # NO_LIBUNWIND
 
 -include arch/$(ARCH)/Makefile
 
@@ -463,20 +510,34 @@
 	BASIC_CFLAGS += -I$(OUTPUT)
 endif
 
-FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
-ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
-	FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
-	ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
-		msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
-	else
-		msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
-	endif
-endif
+ifdef NO_LIBELF
+BASIC_CFLAGS += -DNO_LIBELF_SUPPORT
+
+EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
+
+# Remove ELF/DWARF dependent codes
+LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
+
+BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
+
+# Use minimal symbol handling
+LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
+
+else # NO_LIBELF
 
 ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
 	BASIC_CFLAGS += -DLIBELF_NO_MMAP
 endif
 
+FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
+	msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
+	NO_DWARF := 1
+endif # Dwarf support
+
 ifndef NO_DWARF
 ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
 	msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
@@ -487,6 +548,29 @@
 	LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
 endif # PERF_HAVE_DWARF_REGS
 endif # NO_DWARF
+endif # NO_LIBELF
+
+ifdef NO_LIBUNWIND
+	BASIC_CFLAGS += -DNO_LIBUNWIND_SUPPORT
+else
+	EXTLIBS += $(LIBUNWIND_LIBS)
+	BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
+	BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
+	LIB_OBJS += $(OUTPUT)util/unwind.o
+endif
+
+ifdef NO_LIBAUDIT
+	BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
+else
+	FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
+	ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y)
+		msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
+		BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
+	else
+		BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
+		EXTLIBS += -laudit
+	endif
+endif
 
 ifdef NO_NEWT
 	BASIC_CFLAGS += -DNO_NEWT_SUPPORT
@@ -504,14 +588,13 @@
 		LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
 		LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
 		LIB_OBJS += $(OUTPUT)ui/browsers/map.o
-		LIB_OBJS += $(OUTPUT)ui/helpline.o
 		LIB_OBJS += $(OUTPUT)ui/progress.o
 		LIB_OBJS += $(OUTPUT)ui/util.o
 		LIB_OBJS += $(OUTPUT)ui/tui/setup.o
 		LIB_OBJS += $(OUTPUT)ui/tui/util.o
+		LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
 		LIB_H += ui/browser.h
 		LIB_H += ui/browsers/map.h
-		LIB_H += ui/helpline.h
 		LIB_H += ui/keysyms.h
 		LIB_H += ui/libslang.h
 		LIB_H += ui/progress.h
@@ -523,7 +606,7 @@
 ifdef NO_GTK2
 	BASIC_CFLAGS += -DNO_GTK2_SUPPORT
 else
-	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0)
+	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
 	ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
 		msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
 		BASIC_CFLAGS += -DNO_GTK2_SUPPORT
@@ -531,11 +614,12 @@
 		ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
 			BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
 		endif
-		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
-		EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
+		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
+		EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
 		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/util.o
+		LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
 		# Make sure that it'd be included only once.
 		ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
 			LIB_OBJS += $(OUTPUT)ui/setup.o
@@ -644,7 +728,7 @@
 		EXTLIBS += -liberty
 		BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
         else
-		FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
+		FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
 		has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
 		ifeq ($(has_bfd),y)
 			EXTLIBS += -lbfd
@@ -674,6 +758,13 @@
 	endif
 endif
 
+ifeq ($(NO_PERF_REGS),0)
+	ifeq ($(ARCH),x86)
+		LIB_H += arch/x86/include/perf_regs.h
+	endif
+else
+	BASIC_CFLAGS += -DNO_PERF_REGS
+endif
 
 ifdef NO_STRLCPY
 	BASIC_CFLAGS += -DNO_STRLCPY
@@ -683,6 +774,14 @@
 	endif
 endif
 
+ifdef NO_BACKTRACE
+       BASIC_CFLAGS += -DNO_BACKTRACE
+else
+       ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y)
+               BASIC_CFLAGS += -DNO_BACKTRACE
+       endif
+endif
+
 ifdef ASCIIDOC8
 	export ASCIIDOC8
 endif
@@ -700,6 +799,7 @@
 template_dir_SQ = $(subst ','\'',$(template_dir))
 htmldir_SQ = $(subst ','\'',$(htmldir))
 prefix_SQ = $(subst ','\'',$(prefix))
+sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
 
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 
@@ -767,10 +867,10 @@
 # over the general rule for .o
 
 $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -w $<
+	$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $<
 
 $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -w $<
+	$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
 
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
@@ -842,7 +942,10 @@
 
 # libtraceevent.a
 $(LIBTRACEEVENT):
-	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
+	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
+
+$(LIBTRACEEVENT)-clean:
+	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
 
 help:
 	@echo 'Perf make targets:'
@@ -951,6 +1054,8 @@
 	$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
 	$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
+	$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
 
 install-python_ext:
 	$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
@@ -981,7 +1086,7 @@
 
 ### Cleaning rules
 
-clean:
+clean: $(LIBTRACEEVENT)-clean
 	$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
 	$(RM) $(ALL_PROGRAMS) perf
 	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 744e629..815841c 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,4 +2,7 @@
 PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
+ifndef NO_LIBUNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
new file mode 100644
index 0000000..46fc9f1
--- /dev/null
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -0,0 +1,80 @@
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include "../../util/types.h"
+#include "../../../../../arch/x86/include/asm/perf_regs.h"
+
+#ifndef ARCH_X86_64
+#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#else
+#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
+		       (1ULL << PERF_REG_X86_ES) | \
+		       (1ULL << PERF_REG_X86_FS) | \
+		       (1ULL << PERF_REG_X86_GS))
+#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#endif
+#define PERF_REG_IP PERF_REG_X86_IP
+#define PERF_REG_SP PERF_REG_X86_SP
+
+static inline const char *perf_reg_name(int id)
+{
+	switch (id) {
+	case PERF_REG_X86_AX:
+		return "AX";
+	case PERF_REG_X86_BX:
+		return "BX";
+	case PERF_REG_X86_CX:
+		return "CX";
+	case PERF_REG_X86_DX:
+		return "DX";
+	case PERF_REG_X86_SI:
+		return "SI";
+	case PERF_REG_X86_DI:
+		return "DI";
+	case PERF_REG_X86_BP:
+		return "BP";
+	case PERF_REG_X86_SP:
+		return "SP";
+	case PERF_REG_X86_IP:
+		return "IP";
+	case PERF_REG_X86_FLAGS:
+		return "FLAGS";
+	case PERF_REG_X86_CS:
+		return "CS";
+	case PERF_REG_X86_SS:
+		return "SS";
+	case PERF_REG_X86_DS:
+		return "DS";
+	case PERF_REG_X86_ES:
+		return "ES";
+	case PERF_REG_X86_FS:
+		return "FS";
+	case PERF_REG_X86_GS:
+		return "GS";
+#ifdef ARCH_X86_64
+	case PERF_REG_X86_R8:
+		return "R8";
+	case PERF_REG_X86_R9:
+		return "R9";
+	case PERF_REG_X86_R10:
+		return "R10";
+	case PERF_REG_X86_R11:
+		return "R11";
+	case PERF_REG_X86_R12:
+		return "R12";
+	case PERF_REG_X86_R13:
+		return "R13";
+	case PERF_REG_X86_R14:
+		return "R14";
+	case PERF_REG_X86_R15:
+		return "R15";
+#endif /* ARCH_X86_64 */
+	default:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c
new file mode 100644
index 0000000..78d956e
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind.c
@@ -0,0 +1,111 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+#ifdef ARCH_X86_64
+int unwind__arch_reg_id(int regnum)
+{
+	int id;
+
+	switch (regnum) {
+	case UNW_X86_64_RAX:
+		id = PERF_REG_X86_AX;
+		break;
+	case UNW_X86_64_RDX:
+		id = PERF_REG_X86_DX;
+		break;
+	case UNW_X86_64_RCX:
+		id = PERF_REG_X86_CX;
+		break;
+	case UNW_X86_64_RBX:
+		id = PERF_REG_X86_BX;
+		break;
+	case UNW_X86_64_RSI:
+		id = PERF_REG_X86_SI;
+		break;
+	case UNW_X86_64_RDI:
+		id = PERF_REG_X86_DI;
+		break;
+	case UNW_X86_64_RBP:
+		id = PERF_REG_X86_BP;
+		break;
+	case UNW_X86_64_RSP:
+		id = PERF_REG_X86_SP;
+		break;
+	case UNW_X86_64_R8:
+		id = PERF_REG_X86_R8;
+		break;
+	case UNW_X86_64_R9:
+		id = PERF_REG_X86_R9;
+		break;
+	case UNW_X86_64_R10:
+		id = PERF_REG_X86_R10;
+		break;
+	case UNW_X86_64_R11:
+		id = PERF_REG_X86_R11;
+		break;
+	case UNW_X86_64_R12:
+		id = PERF_REG_X86_R12;
+		break;
+	case UNW_X86_64_R13:
+		id = PERF_REG_X86_R13;
+		break;
+	case UNW_X86_64_R14:
+		id = PERF_REG_X86_R14;
+		break;
+	case UNW_X86_64_R15:
+		id = PERF_REG_X86_R15;
+		break;
+	case UNW_X86_64_RIP:
+		id = PERF_REG_X86_IP;
+		break;
+	default:
+		pr_err("unwind: invalid reg id %d\n", regnum);
+		return -EINVAL;
+	}
+
+	return id;
+}
+#else
+int unwind__arch_reg_id(int regnum)
+{
+	int id;
+
+	switch (regnum) {
+	case UNW_X86_EAX:
+		id = PERF_REG_X86_AX;
+		break;
+	case UNW_X86_EDX:
+		id = PERF_REG_X86_DX;
+		break;
+	case UNW_X86_ECX:
+		id = PERF_REG_X86_CX;
+		break;
+	case UNW_X86_EBX:
+		id = PERF_REG_X86_BX;
+		break;
+	case UNW_X86_ESI:
+		id = PERF_REG_X86_SI;
+		break;
+	case UNW_X86_EDI:
+		id = PERF_REG_X86_DI;
+		break;
+	case UNW_X86_EBP:
+		id = PERF_REG_X86_BP;
+		break;
+	case UNW_X86_ESP:
+		id = PERF_REG_X86_SP;
+		break;
+	case UNW_X86_EIP:
+		id = PERF_REG_X86_IP;
+		break;
+	default:
+		pr_err("unwind: invalid reg id %d\n", regnum);
+		return -EINVAL;
+	}
+
+	return id;
+}
+#endif /* ARCH_X86_64 */
diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion
new file mode 100644
index 0000000..1958fa5
--- /dev/null
+++ b/tools/perf/bash_completion
@@ -0,0 +1,26 @@
+# perf completion
+
+have perf &&
+_perf()
+{
+	local cur cmd
+
+	COMPREPLY=()
+	_get_comp_words_by_ref cur prev
+
+	cmd=${COMP_WORDS[0]}
+
+	# List perf subcommands
+	if [ $COMP_CWORD -eq 1 ]; then
+		cmds=$($cmd --list-cmds)
+		COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
+	# List possible events for -e option
+	elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then
+		cmds=$($cmd list --raw-dump)
+		COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
+	# Fall down to list regular files
+	else
+		_filedir
+	fi
+} &&
+complete -F _perf perf
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index a09bece..8f89998 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -3,7 +3,8 @@
 
 extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
 extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
-extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
+extern int bench_mem_memcpy(int argc, const char **argv,
+			    const char *prefix __maybe_unused);
 extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
 
 #define BENCH_FORMAT_DEFAULT_STR	"default"
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 02dad5d..93c83e3 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -177,7 +177,7 @@
 	} while (0)
 
 int bench_mem_memcpy(int argc, const char **argv,
-		     const char *prefix __used)
+		     const char *prefix __maybe_unused)
 {
 	int i;
 	size_t len;
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index 350cc95..c6e4bc5 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -171,7 +171,7 @@
 	} while (0)
 
 int bench_mem_memset(int argc, const char **argv,
-		     const char *prefix __used)
+		     const char *prefix __maybe_unused)
 {
 	int i;
 	size_t len;
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index d1d1b30..cc1190a 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -267,7 +267,7 @@
 };
 
 int bench_sched_messaging(int argc, const char **argv,
-		    const char *prefix __used)
+		    const char *prefix __maybe_unused)
 {
 	unsigned int i, total_children;
 	struct timeval start, stop, diff;
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 0c7454f..69cfba8 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -43,7 +43,7 @@
 };
 
 int bench_sched_pipe(int argc, const char **argv,
-		     const char *prefix __used)
+		     const char *prefix __maybe_unused)
 {
 	int pipe_1[2], pipe_2[2];
 	int m = 0, i;
@@ -55,14 +55,14 @@
 	 * discarding returned value of read(), write()
 	 * causes error in building environment for perf
 	 */
-	int __used ret, wait_stat;
-	pid_t pid, retpid;
+	int __maybe_unused ret, wait_stat;
+	pid_t pid, retpid __maybe_unused;
 
 	argc = parse_options(argc, argv, options,
 			     bench_sched_pipe_usage, 0);
 
-	assert(!pipe(pipe_1));
-	assert(!pipe(pipe_2));
+	BUG_ON(pipe(pipe_1));
+	BUG_ON(pipe(pipe_2));
 
 	pid = fork();
 	assert(pid >= 0);
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 67522cf..9ea3854 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -239,7 +239,7 @@
 	NULL
 };
 
-int cmd_annotate(int argc, const char **argv, const char *prefix __used)
+int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_annotate annotate = {
 		.tool = {
@@ -282,6 +282,8 @@
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
+	OPT_STRING(0, "objdump", &objdump_path, "path",
+		   "objdump binary to use for disassembly and annotations"),
 	OPT_END()
 	};
 
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 1f31002..cae9a5f 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -173,7 +173,7 @@
 		all_suite(&subsystems[i]);
 }
 
-int cmd_bench(int argc, const char **argv, const char *prefix __used)
+int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int i, j, status = 0;
 
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 29ad20e..8365455 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -43,15 +43,16 @@
 	}
 
 	build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
-	err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
+	err = build_id_cache__add_s(sbuild_id, debugdir, filename,
+				    false, false);
 	if (verbose)
 		pr_info("Adding %s %s: %s\n", sbuild_id, filename,
 			err ? "FAIL" : "Ok");
 	return err;
 }
 
-static int build_id_cache__remove_file(const char *filename __used,
-				       const char *debugdir __used)
+static int build_id_cache__remove_file(const char *filename __maybe_unused,
+				       const char *debugdir __maybe_unused)
 {
 	u8 build_id[BUILD_ID_SIZE];
 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -119,7 +120,8 @@
 	return 0;
 }
 
-int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
+int cmd_buildid_cache(int argc, const char **argv,
+		      const char *prefix __maybe_unused)
 {
 	argc = parse_options(argc, argv, buildid_cache_options,
 			     buildid_cache_usage, 0);
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 6b2bcfb..1159fee 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -16,8 +16,6 @@
 #include "util/session.h"
 #include "util/symbol.h"
 
-#include <libelf.h>
-
 static const char *input_name;
 static bool force;
 static bool show_kernel;
@@ -71,7 +69,7 @@
 {
 	struct perf_session *session;
 
-	elf_version(EV_CURRENT);
+	symbol__elf_init();
 
 	session = perf_session__new(input_name, O_RDONLY, force, false,
 				    &build_id__mark_dso_hit_ops);
@@ -105,7 +103,8 @@
 	return perf_session__list_build_ids();
 }
 
-int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
+int cmd_buildid_list(int argc, const char **argv,
+		     const char *prefix __maybe_unused)
 {
 	argc = parse_options(argc, argv, options, buildid_list_usage, 0);
 	setup_pager();
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index d29d350..761f419 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -10,6 +10,7 @@
 #include "util/event.h"
 #include "util/hist.h"
 #include "util/evsel.h"
+#include "util/evlist.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/sort.h"
@@ -24,11 +25,6 @@
 static bool  force;
 static bool show_displacement;
 
-struct perf_diff {
-	struct perf_tool tool;
-	struct perf_session *session;
-};
-
 static int hists__add_entry(struct hists *self,
 			    struct addr_location *al, u64 period)
 {
@@ -37,14 +33,12 @@
 	return -ENOMEM;
 }
 
-static int diff__process_sample_event(struct perf_tool *tool,
+static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
 				      union perf_event *event,
 				      struct perf_sample *sample,
-				      struct perf_evsel *evsel __used,
+				      struct perf_evsel *evsel,
 				      struct machine *machine)
 {
-	struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
-	struct perf_session *session = _diff->session;
 	struct addr_location al;
 
 	if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
@@ -56,26 +50,24 @@
 	if (al.filtered || al.sym == NULL)
 		return 0;
 
-	if (hists__add_entry(&session->hists, &al, sample->period)) {
+	if (hists__add_entry(&evsel->hists, &al, sample->period)) {
 		pr_warning("problem incrementing symbol period, skipping event\n");
 		return -1;
 	}
 
-	session->hists.stats.total_period += sample->period;
+	evsel->hists.stats.total_period += sample->period;
 	return 0;
 }
 
-static struct perf_diff diff = {
-	.tool = {
-		.sample	= diff__process_sample_event,
-		.mmap	= perf_event__process_mmap,
-		.comm	= perf_event__process_comm,
-		.exit	= perf_event__process_task,
-		.fork	= perf_event__process_task,
-		.lost	= perf_event__process_lost,
-		.ordered_samples = true,
-		.ordering_requires_timestamps = true,
-	},
+static struct perf_tool tool = {
+	.sample	= diff__process_sample_event,
+	.mmap	= perf_event__process_mmap,
+	.comm	= perf_event__process_comm,
+	.exit	= perf_event__process_task,
+	.fork	= perf_event__process_task,
+	.lost	= perf_event__process_lost,
+	.ordered_samples = true,
+	.ordering_requires_timestamps = true,
 };
 
 static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -146,34 +138,71 @@
 	}
 }
 
+static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
+				      struct perf_evlist *evlist)
+{
+	struct perf_evsel *e;
+
+	list_for_each_entry(e, &evlist->entries, node)
+		if (perf_evsel__match2(evsel, e))
+			return e;
+
+	return NULL;
+}
+
 static int __cmd_diff(void)
 {
 	int ret, i;
 #define older (session[0])
 #define newer (session[1])
 	struct perf_session *session[2];
+	struct perf_evlist *evlist_new, *evlist_old;
+	struct perf_evsel *evsel;
+	bool first = true;
 
 	older = perf_session__new(input_old, O_RDONLY, force, false,
-				  &diff.tool);
+				  &tool);
 	newer = perf_session__new(input_new, O_RDONLY, force, false,
-				  &diff.tool);
+				  &tool);
 	if (session[0] == NULL || session[1] == NULL)
 		return -ENOMEM;
 
 	for (i = 0; i < 2; ++i) {
-		diff.session = session[i];
-		ret = perf_session__process_events(session[i], &diff.tool);
+		ret = perf_session__process_events(session[i], &tool);
 		if (ret)
 			goto out_delete;
-		hists__output_resort(&session[i]->hists);
 	}
 
-	if (show_displacement)
-		hists__resort_entries(&older->hists);
+	evlist_old = older->evlist;
+	evlist_new = newer->evlist;
 
-	hists__match(&older->hists, &newer->hists);
-	hists__fprintf(&newer->hists, &older->hists,
-		       show_displacement, true, 0, 0, stdout);
+	list_for_each_entry(evsel, &evlist_new->entries, node)
+		hists__output_resort(&evsel->hists);
+
+	list_for_each_entry(evsel, &evlist_old->entries, node) {
+		hists__output_resort(&evsel->hists);
+
+		if (show_displacement)
+			hists__resort_entries(&evsel->hists);
+	}
+
+	list_for_each_entry(evsel, &evlist_new->entries, node) {
+		struct perf_evsel *evsel_old;
+
+		evsel_old = evsel_match(evsel, evlist_old);
+		if (!evsel_old)
+			continue;
+
+		fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
+			perf_evsel__name(evsel));
+
+		first = false;
+
+		hists__match(&evsel_old->hists, &evsel->hists);
+		hists__fprintf(&evsel->hists, &evsel_old->hists,
+			       show_displacement, true, 0, 0, stdout);
+	}
+
 out_delete:
 	for (i = 0; i < 2; ++i)
 		perf_session__delete(session[i]);
@@ -213,7 +242,7 @@
 	OPT_END()
 };
 
-int cmd_diff(int argc, const char **argv, const char *prefix __used)
+int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	sort_order = diff__default_sort_order;
 	argc = parse_options(argc, argv, options, diff_usage, 0);
@@ -235,6 +264,7 @@
 	if (symbol__init() < 0)
 		return -1;
 
+	perf_hpp__init(true, show_displacement);
 	setup_sorting(diff_usage, options);
 	setup_pager();
 
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 0dd5a05..1fb1641 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -113,7 +113,7 @@
 	NULL
 };
 
-int cmd_evlist(int argc, const char **argv, const char *prefix __used)
+int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_attr_details details = { .verbose = false, };
 	const char *input_name = NULL;
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 6d5a8a7..25c8b94 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -24,13 +24,14 @@
 } *man_viewer_info_list;
 
 enum help_format {
+	HELP_FORMAT_NONE,
 	HELP_FORMAT_MAN,
 	HELP_FORMAT_INFO,
 	HELP_FORMAT_WEB,
 };
 
 static bool show_all = false;
-static enum help_format help_format = HELP_FORMAT_MAN;
+static enum help_format help_format = HELP_FORMAT_NONE;
 static struct option builtin_help_options[] = {
 	OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
 	OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
@@ -54,7 +55,9 @@
 		return HELP_FORMAT_INFO;
 	if (!strcmp(format, "web") || !strcmp(format, "html"))
 		return HELP_FORMAT_WEB;
-	die("unrecognized help format '%s'", format);
+
+	pr_err("unrecognized help format '%s'", format);
+	return HELP_FORMAT_NONE;
 }
 
 static const char *get_man_viewer_info(const char *name)
@@ -259,6 +262,8 @@
 		if (!value)
 			return config_error_nonbool(var);
 		help_format = parse_help_format(value);
+		if (help_format == HELP_FORMAT_NONE)
+			return -1;
 		return 0;
 	}
 	if (!strcmp(var, "man.viewer")) {
@@ -352,7 +357,7 @@
 		warning("'%s': unknown man viewer.", name);
 }
 
-static void show_man_page(const char *perf_cmd)
+static int show_man_page(const char *perf_cmd)
 {
 	struct man_viewer_list *viewer;
 	const char *page = cmd_to_page(perf_cmd);
@@ -365,28 +370,35 @@
 	if (fallback)
 		exec_viewer(fallback, page);
 	exec_viewer("man", page);
-	die("no man viewer handled the request");
+
+	pr_err("no man viewer handled the request");
+	return -1;
 }
 
-static void show_info_page(const char *perf_cmd)
+static int show_info_page(const char *perf_cmd)
 {
 	const char *page = cmd_to_page(perf_cmd);
 	setenv("INFOPATH", system_path(PERF_INFO_PATH), 1);
 	execlp("info", "info", "perfman", page, NULL);
+	return -1;
 }
 
-static void get_html_page_path(struct strbuf *page_path, const char *page)
+static int get_html_page_path(struct strbuf *page_path, const char *page)
 {
 	struct stat st;
 	const char *html_path = system_path(PERF_HTML_PATH);
 
 	/* Check that we have a perf documentation directory. */
 	if (stat(mkpath("%s/perf.html", html_path), &st)
-	    || !S_ISREG(st.st_mode))
-		die("'%s': not a documentation directory.", html_path);
+	    || !S_ISREG(st.st_mode)) {
+		pr_err("'%s': not a documentation directory.", html_path);
+		return -1;
+	}
 
 	strbuf_init(page_path, 0);
 	strbuf_addf(page_path, "%s/%s.html", html_path, page);
+
+	return 0;
 }
 
 /*
@@ -401,19 +413,23 @@
 }
 #endif
 
-static void show_html_page(const char *perf_cmd)
+static int show_html_page(const char *perf_cmd)
 {
 	const char *page = cmd_to_page(perf_cmd);
 	struct strbuf page_path; /* it leaks but we exec bellow */
 
-	get_html_page_path(&page_path, page);
+	if (get_html_page_path(&page_path, page) != 0)
+		return -1;
 
 	open_html(page_path.buf);
+
+	return 0;
 }
 
-int cmd_help(int argc, const char **argv, const char *prefix __used)
+int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	const char *alias;
+	int rc = 0;
 
 	load_command_list("perf-", &main_cmds, &other_cmds);
 
@@ -444,16 +460,20 @@
 
 	switch (help_format) {
 	case HELP_FORMAT_MAN:
-		show_man_page(argv[0]);
+		rc = show_man_page(argv[0]);
 		break;
 	case HELP_FORMAT_INFO:
-		show_info_page(argv[0]);
+		rc = show_info_page(argv[0]);
 		break;
 	case HELP_FORMAT_WEB:
-		show_html_page(argv[0]);
+		rc = show_html_page(argv[0]);
+		break;
+	case HELP_FORMAT_NONE:
+		/* fall-through */
 	default:
+		rc = -1;
 		break;
 	}
 
-	return 0;
+	return rc;
 }
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3beab48..1eaa661 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,9 +17,9 @@
 static char		const *input_name = "-";
 static bool		inject_build_ids;
 
-static int perf_event__repipe_synth(struct perf_tool *tool __used,
+static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused,
 				    union perf_event *event,
-				    struct machine *machine __used)
+				    struct machine *machine __maybe_unused)
 {
 	uint32_t size;
 	void *buf = event;
@@ -40,7 +40,8 @@
 
 static int perf_event__repipe_op2_synth(struct perf_tool *tool,
 					union perf_event *event,
-					struct perf_session *session __used)
+					struct perf_session *session
+					__maybe_unused)
 {
 	return perf_event__repipe_synth(tool, event, NULL);
 }
@@ -52,13 +53,14 @@
 }
 
 static int perf_event__repipe_tracing_data_synth(union perf_event *event,
-						 struct perf_session *session __used)
+						 struct perf_session *session
+						 __maybe_unused)
 {
 	return perf_event__repipe_synth(NULL, event, NULL);
 }
 
 static int perf_event__repipe_attr(union perf_event *event,
-				   struct perf_evlist **pevlist __used)
+				   struct perf_evlist **pevlist __maybe_unused)
 {
 	int ret;
 	ret = perf_event__process_attr(event, pevlist);
@@ -70,7 +72,7 @@
 
 static int perf_event__repipe(struct perf_tool *tool,
 			      union perf_event *event,
-			      struct perf_sample *sample __used,
+			      struct perf_sample *sample __maybe_unused,
 			      struct machine *machine)
 {
 	return perf_event__repipe_synth(tool, event, machine);
@@ -78,8 +80,8 @@
 
 static int perf_event__repipe_sample(struct perf_tool *tool,
 				     union perf_event *event,
-			      struct perf_sample *sample __used,
-			      struct perf_evsel *evsel __used,
+			      struct perf_sample *sample __maybe_unused,
+			      struct perf_evsel *evsel __maybe_unused,
 			      struct machine *machine)
 {
 	return perf_event__repipe_synth(tool, event, machine);
@@ -163,7 +165,7 @@
 static int perf_event__inject_buildid(struct perf_tool *tool,
 				      union perf_event *event,
 				      struct perf_sample *sample,
-				      struct perf_evsel *evsel __used,
+				      struct perf_evsel *evsel __maybe_unused,
 				      struct machine *machine)
 {
 	struct addr_location al;
@@ -191,10 +193,13 @@
 				 * If this fails, too bad, let the other side
 				 * account this as unresolved.
 				 */
-			} else
+			} else {
+#ifndef NO_LIBELF_SUPPORT
 				pr_warning("no symbols found in %s, maybe "
 					   "install a debug package?\n",
 					   al.map->dso->long_name);
+#endif
+			}
 		}
 	}
 
@@ -221,7 +226,7 @@
 
 extern volatile int session_done;
 
-static void sig_handler(int sig __attribute__((__unused__)))
+static void sig_handler(int sig __maybe_unused)
 {
 	session_done = 1;
 }
@@ -264,7 +269,7 @@
 	OPT_END()
 };
 
-int cmd_inject(int argc, const char **argv, const char *prefix __used)
+int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	argc = parse_options(argc, argv, options, report_usage, 0);
 
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index ce35015..bc912c6 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1,6 +1,8 @@
 #include "builtin.h"
 #include "perf.h"
 
+#include "util/evlist.h"
+#include "util/evsel.h"
 #include "util/util.h"
 #include "util/cache.h"
 #include "util/symbol.h"
@@ -57,46 +59,52 @@
 
 #define PATH_SYS_NODE	"/sys/devices/system/node"
 
-struct perf_kmem {
-	struct perf_tool    tool;
-	struct perf_session *session;
-};
-
-static void init_cpunode_map(void)
+static int init_cpunode_map(void)
 {
 	FILE *fp;
-	int i;
+	int i, err = -1;
 
 	fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
 	if (!fp) {
 		max_cpu_num = 4096;
-		return;
+		return 0;
 	}
 
-	if (fscanf(fp, "%d", &max_cpu_num) < 1)
-		die("Failed to read 'kernel_max' from sysfs");
+	if (fscanf(fp, "%d", &max_cpu_num) < 1) {
+		pr_err("Failed to read 'kernel_max' from sysfs");
+		goto out_close;
+	}
+
 	max_cpu_num++;
 
 	cpunode_map = calloc(max_cpu_num, sizeof(int));
-	if (!cpunode_map)
-		die("calloc");
+	if (!cpunode_map) {
+		pr_err("%s: calloc failed\n", __func__);
+		goto out_close;
+	}
+
 	for (i = 0; i < max_cpu_num; i++)
 		cpunode_map[i] = -1;
+
+	err = 0;
+out_close:
 	fclose(fp);
+	return err;
 }
 
-static void setup_cpunode_map(void)
+static int setup_cpunode_map(void)
 {
 	struct dirent *dent1, *dent2;
 	DIR *dir1, *dir2;
 	unsigned int cpu, mem;
 	char buf[PATH_MAX];
 
-	init_cpunode_map();
+	if (init_cpunode_map())
+		return -1;
 
 	dir1 = opendir(PATH_SYS_NODE);
 	if (!dir1)
-		return;
+		return -1;
 
 	while ((dent1 = readdir(dir1)) != NULL) {
 		if (dent1->d_type != DT_DIR ||
@@ -116,10 +124,11 @@
 		closedir(dir2);
 	}
 	closedir(dir1);
+	return 0;
 }
 
-static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
-			      int bytes_req, int bytes_alloc, int cpu)
+static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
+			     int bytes_req, int bytes_alloc, int cpu)
 {
 	struct rb_node **node = &root_alloc_stat.rb_node;
 	struct rb_node *parent = NULL;
@@ -143,8 +152,10 @@
 		data->bytes_alloc += bytes_alloc;
 	} else {
 		data = malloc(sizeof(*data));
-		if (!data)
-			die("malloc");
+		if (!data) {
+			pr_err("%s: malloc failed\n", __func__);
+			return -1;
+		}
 		data->ptr = ptr;
 		data->pingpong = 0;
 		data->hit = 1;
@@ -156,9 +167,10 @@
 	}
 	data->call_site = call_site;
 	data->alloc_cpu = cpu;
+	return 0;
 }
 
-static void insert_caller_stat(unsigned long call_site,
+static int insert_caller_stat(unsigned long call_site,
 			      int bytes_req, int bytes_alloc)
 {
 	struct rb_node **node = &root_caller_stat.rb_node;
@@ -183,8 +195,10 @@
 		data->bytes_alloc += bytes_alloc;
 	} else {
 		data = malloc(sizeof(*data));
-		if (!data)
-			die("malloc");
+		if (!data) {
+			pr_err("%s: malloc failed\n", __func__);
+			return -1;
+		}
 		data->call_site = call_site;
 		data->pingpong = 0;
 		data->hit = 1;
@@ -194,39 +208,43 @@
 		rb_link_node(&data->node, parent, node);
 		rb_insert_color(&data->node, &root_caller_stat);
 	}
+
+	return 0;
 }
 
-static void process_alloc_event(void *data,
-				struct event_format *event,
-				int cpu,
-				u64 timestamp __used,
-				struct thread *thread __used,
-				int node)
+static int perf_evsel__process_alloc_event(struct perf_evsel *evsel,
+					   struct perf_sample *sample)
 {
-	unsigned long call_site;
-	unsigned long ptr;
-	int bytes_req;
-	int bytes_alloc;
-	int node1, node2;
+	unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"),
+		      call_site = perf_evsel__intval(evsel, sample, "call_site");
+	int bytes_req = perf_evsel__intval(evsel, sample, "bytes_req"),
+	    bytes_alloc = perf_evsel__intval(evsel, sample, "bytes_alloc");
 
-	ptr = raw_field_value(event, "ptr", data);
-	call_site = raw_field_value(event, "call_site", data);
-	bytes_req = raw_field_value(event, "bytes_req", data);
-	bytes_alloc = raw_field_value(event, "bytes_alloc", data);
-
-	insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
-	insert_caller_stat(call_site, bytes_req, bytes_alloc);
+	if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) ||
+	    insert_caller_stat(call_site, bytes_req, bytes_alloc))
+		return -1;
 
 	total_requested += bytes_req;
 	total_allocated += bytes_alloc;
 
-	if (node) {
-		node1 = cpunode_map[cpu];
-		node2 = raw_field_value(event, "node", data);
+	nr_allocs++;
+	return 0;
+}
+
+static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
+						struct perf_sample *sample)
+{
+	int ret = perf_evsel__process_alloc_event(evsel, sample);
+
+	if (!ret) {
+		int node1 = cpunode_map[sample->cpu],
+		    node2 = perf_evsel__intval(evsel, sample, "node");
+
 		if (node1 != node2)
 			nr_cross_allocs++;
 	}
-	nr_allocs++;
+
+	return ret;
 }
 
 static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
@@ -257,66 +275,37 @@
 	return NULL;
 }
 
-static void process_free_event(void *data,
-			       struct event_format *event,
-			       int cpu,
-			       u64 timestamp __used,
-			       struct thread *thread __used)
+static int perf_evsel__process_free_event(struct perf_evsel *evsel,
+					  struct perf_sample *sample)
 {
-	unsigned long ptr;
+	unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr");
 	struct alloc_stat *s_alloc, *s_caller;
 
-	ptr = raw_field_value(event, "ptr", data);
-
 	s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
 	if (!s_alloc)
-		return;
+		return 0;
 
-	if (cpu != s_alloc->alloc_cpu) {
+	if ((short)sample->cpu != s_alloc->alloc_cpu) {
 		s_alloc->pingpong++;
 
 		s_caller = search_alloc_stat(0, s_alloc->call_site,
 					     &root_caller_stat, callsite_cmp);
-		assert(s_caller);
+		if (!s_caller)
+			return -1;
 		s_caller->pingpong++;
 	}
 	s_alloc->alloc_cpu = -1;
+
+	return 0;
 }
 
-static void process_raw_event(struct perf_tool *tool,
-			      union perf_event *raw_event __used, void *data,
-			      int cpu, u64 timestamp, struct thread *thread)
-{
-	struct perf_kmem *kmem = container_of(tool, struct perf_kmem, tool);
-	struct event_format *event;
-	int type;
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+				  struct perf_sample *sample);
 
-	type = trace_parse_common_type(kmem->session->pevent, data);
-	event = pevent_find_event(kmem->session->pevent, type);
-
-	if (!strcmp(event->name, "kmalloc") ||
-	    !strcmp(event->name, "kmem_cache_alloc")) {
-		process_alloc_event(data, event, cpu, timestamp, thread, 0);
-		return;
-	}
-
-	if (!strcmp(event->name, "kmalloc_node") ||
-	    !strcmp(event->name, "kmem_cache_alloc_node")) {
-		process_alloc_event(data, event, cpu, timestamp, thread, 1);
-		return;
-	}
-
-	if (!strcmp(event->name, "kfree") ||
-	    !strcmp(event->name, "kmem_cache_free")) {
-		process_free_event(data, event, cpu, timestamp, thread);
-		return;
-	}
-}
-
-static int process_sample_event(struct perf_tool *tool,
+static int process_sample_event(struct perf_tool *tool __maybe_unused,
 				union perf_event *event,
 				struct perf_sample *sample,
-				struct perf_evsel *evsel __used,
+				struct perf_evsel *evsel,
 				struct machine *machine)
 {
 	struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
@@ -329,18 +318,18 @@
 
 	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 
-	process_raw_event(tool, event, sample->raw_data, sample->cpu,
-			  sample->time, thread);
+	if (evsel->handler.func != NULL) {
+		tracepoint_handler f = evsel->handler.func;
+		return f(evsel, sample);
+	}
 
 	return 0;
 }
 
-static struct perf_kmem perf_kmem = {
-	.tool = {
-		.sample			= process_sample_event,
-		.comm			= perf_event__process_comm,
-		.ordered_samples	= true,
-	},
+static struct perf_tool perf_kmem = {
+	.sample		 = process_sample_event,
+	.comm		 = perf_event__process_comm,
+	.ordered_samples = true,
 };
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -496,22 +485,32 @@
 {
 	int err = -EINVAL;
 	struct perf_session *session;
+	const struct perf_evsel_str_handler kmem_tracepoints[] = {
+		{ "kmem:kmalloc",		perf_evsel__process_alloc_event, },
+    		{ "kmem:kmem_cache_alloc",	perf_evsel__process_alloc_event, },
+		{ "kmem:kmalloc_node",		perf_evsel__process_alloc_node_event, },
+    		{ "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, },
+		{ "kmem:kfree",			perf_evsel__process_free_event, },
+    		{ "kmem:kmem_cache_free",	perf_evsel__process_free_event, },
+	};
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false,
-				    &perf_kmem.tool);
+	session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_kmem);
 	if (session == NULL)
 		return -ENOMEM;
 
-	perf_kmem.session = session;
-
 	if (perf_session__create_kernel_maps(session) < 0)
 		goto out_delete;
 
 	if (!perf_session__has_traces(session, "kmem record"))
 		goto out_delete;
 
+	if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
+		pr_err("Initializing perf session tracepoint handlers failed\n");
+		return -1;
+	}
+
 	setup_pager();
-	err = perf_session__process_events(session, &perf_kmem.tool);
+	err = perf_session__process_events(session, &perf_kmem);
 	if (err != 0)
 		goto out_delete;
 	sort_result();
@@ -635,8 +634,10 @@
 	for (i = 0; i < NUM_AVAIL_SORTS; i++) {
 		if (!strcmp(avail_sorts[i]->name, tok)) {
 			sort = malloc(sizeof(*sort));
-			if (!sort)
-				die("malloc");
+			if (!sort) {
+				pr_err("%s: malloc failed\n", __func__);
+				return -1;
+			}
 			memcpy(sort, avail_sorts[i], sizeof(*sort));
 			list_add_tail(&sort->list, list);
 			return 0;
@@ -651,8 +652,10 @@
 	char *tok;
 	char *str = strdup(arg);
 
-	if (!str)
-		die("strdup");
+	if (!str) {
+		pr_err("%s: strdup failed\n", __func__);
+		return -1;
+	}
 
 	while (true) {
 		tok = strsep(&str, ",");
@@ -669,8 +672,8 @@
 	return 0;
 }
 
-static int parse_sort_opt(const struct option *opt __used,
-			  const char *arg, int unset __used)
+static int parse_sort_opt(const struct option *opt __maybe_unused,
+			  const char *arg, int unset __maybe_unused)
 {
 	if (!arg)
 		return -1;
@@ -683,22 +686,24 @@
 	return 0;
 }
 
-static int parse_caller_opt(const struct option *opt __used,
-			  const char *arg __used, int unset __used)
+static int parse_caller_opt(const struct option *opt __maybe_unused,
+			    const char *arg __maybe_unused,
+			    int unset __maybe_unused)
 {
 	caller_flag = (alloc_flag + 1);
 	return 0;
 }
 
-static int parse_alloc_opt(const struct option *opt __used,
-			  const char *arg __used, int unset __used)
+static int parse_alloc_opt(const struct option *opt __maybe_unused,
+			   const char *arg __maybe_unused,
+			   int unset __maybe_unused)
 {
 	alloc_flag = (caller_flag + 1);
 	return 0;
 }
 
-static int parse_line_opt(const struct option *opt __used,
-			  const char *arg, int unset __used)
+static int parse_line_opt(const struct option *opt __maybe_unused,
+			  const char *arg, int unset __maybe_unused)
 {
 	int lines;
 
@@ -768,7 +773,7 @@
 	return cmd_record(i, rec_argv, NULL);
 }
 
-int cmd_kmem(int argc, const char **argv, const char *prefix __used)
+int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
 
@@ -780,7 +785,8 @@
 	if (!strncmp(argv[0], "rec", 3)) {
 		return __cmd_record(argc, argv);
 	} else if (!strcmp(argv[0], "stat")) {
-		setup_cpunode_map();
+		if (setup_cpunode_map())
+			return -1;
 
 		if (list_empty(&caller_sort))
 			setup_sorting(&caller_sort, default_sort_order);
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 9fc6e0f..a28c9ca 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1,6 +1,7 @@
 #include "builtin.h"
 #include "perf.h"
 
+#include "util/evsel.h"
 #include "util/util.h"
 #include "util/cache.h"
 #include "util/symbol.h"
@@ -10,8 +11,10 @@
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
-
 #include "util/debug.h"
+#include "util/debugfs.h"
+#include "util/tool.h"
+#include "util/stat.h"
 
 #include <sys/prctl.h>
 
@@ -19,11 +22,836 @@
 #include <pthread.h>
 #include <math.h>
 
-static const char		*file_name;
+#include "../../arch/x86/include/asm/svm.h"
+#include "../../arch/x86/include/asm/vmx.h"
+#include "../../arch/x86/include/asm/kvm.h"
+
+struct event_key {
+	#define INVALID_KEY     (~0ULL)
+	u64 key;
+	int info;
+};
+
+struct kvm_events_ops {
+	bool (*is_begin_event)(struct perf_evsel *evsel,
+			       struct perf_sample *sample,
+			       struct event_key *key);
+	bool (*is_end_event)(struct perf_evsel *evsel,
+			     struct perf_sample *sample, struct event_key *key);
+	void (*decode_key)(struct event_key *key, char decode[20]);
+	const char *name;
+};
+
+static void exit_event_get_key(struct perf_evsel *evsel,
+			       struct perf_sample *sample,
+			       struct event_key *key)
+{
+	key->info = 0;
+	key->key = perf_evsel__intval(evsel, sample, "exit_reason");
+}
+
+static bool kvm_exit_event(struct perf_evsel *evsel)
+{
+	return !strcmp(evsel->name, "kvm:kvm_exit");
+}
+
+static bool exit_event_begin(struct perf_evsel *evsel,
+			     struct perf_sample *sample, struct event_key *key)
+{
+	if (kvm_exit_event(evsel)) {
+		exit_event_get_key(evsel, sample, key);
+		return true;
+	}
+
+	return false;
+}
+
+static bool kvm_entry_event(struct perf_evsel *evsel)
+{
+	return !strcmp(evsel->name, "kvm:kvm_entry");
+}
+
+static bool exit_event_end(struct perf_evsel *evsel,
+			   struct perf_sample *sample __maybe_unused,
+			   struct event_key *key __maybe_unused)
+{
+	return kvm_entry_event(evsel);
+}
+
+struct exit_reasons_table {
+	unsigned long exit_code;
+	const char *reason;
+};
+
+struct exit_reasons_table vmx_exit_reasons[] = {
+	VMX_EXIT_REASONS
+};
+
+struct exit_reasons_table svm_exit_reasons[] = {
+	SVM_EXIT_REASONS
+};
+
+static int cpu_isa;
+
+static const char *get_exit_reason(u64 exit_code)
+{
+	int table_size = ARRAY_SIZE(svm_exit_reasons);
+	struct exit_reasons_table *table = svm_exit_reasons;
+
+	if (cpu_isa == 1) {
+		table = vmx_exit_reasons;
+		table_size = ARRAY_SIZE(vmx_exit_reasons);
+	}
+
+	while (table_size--) {
+		if (table->exit_code == exit_code)
+			return table->reason;
+		table++;
+	}
+
+	pr_err("unknown kvm exit code:%lld on %s\n",
+		(unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM");
+	return "UNKNOWN";
+}
+
+static void exit_event_decode_key(struct event_key *key, char decode[20])
+{
+	const char *exit_reason = get_exit_reason(key->key);
+
+	scnprintf(decode, 20, "%s", exit_reason);
+}
+
+static struct kvm_events_ops exit_events = {
+	.is_begin_event = exit_event_begin,
+	.is_end_event = exit_event_end,
+	.decode_key = exit_event_decode_key,
+	.name = "VM-EXIT"
+};
+
+    /*
+     * For the mmio events, we treat:
+     * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
+     * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
+     */
+static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
+			       struct event_key *key)
+{
+	key->key  = perf_evsel__intval(evsel, sample, "gpa");
+	key->info = perf_evsel__intval(evsel, sample, "type");
+}
+
+#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
+#define KVM_TRACE_MMIO_READ 1
+#define KVM_TRACE_MMIO_WRITE 2
+
+static bool mmio_event_begin(struct perf_evsel *evsel,
+			     struct perf_sample *sample, struct event_key *key)
+{
+	/* MMIO read begin event in kernel. */
+	if (kvm_exit_event(evsel))
+		return true;
+
+	/* MMIO write begin event in kernel. */
+	if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
+	    perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
+		mmio_event_get_key(evsel, sample, key);
+		return true;
+	}
+
+	return false;
+}
+
+static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
+			   struct event_key *key)
+{
+	/* MMIO write end event in kernel. */
+	if (kvm_entry_event(evsel))
+		return true;
+
+	/* MMIO read end event in kernel.*/
+	if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
+	    perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
+		mmio_event_get_key(evsel, sample, key);
+		return true;
+	}
+
+	return false;
+}
+
+static void mmio_event_decode_key(struct event_key *key, char decode[20])
+{
+	scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
+				key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
+}
+
+static struct kvm_events_ops mmio_events = {
+	.is_begin_event = mmio_event_begin,
+	.is_end_event = mmio_event_end,
+	.decode_key = mmio_event_decode_key,
+	.name = "MMIO Access"
+};
+
+ /* The time of emulation pio access is from kvm_pio to kvm_entry. */
+static void ioport_event_get_key(struct perf_evsel *evsel,
+				 struct perf_sample *sample,
+				 struct event_key *key)
+{
+	key->key  = perf_evsel__intval(evsel, sample, "port");
+	key->info = perf_evsel__intval(evsel, sample, "rw");
+}
+
+static bool ioport_event_begin(struct perf_evsel *evsel,
+			       struct perf_sample *sample,
+			       struct event_key *key)
+{
+	if (!strcmp(evsel->name, "kvm:kvm_pio")) {
+		ioport_event_get_key(evsel, sample, key);
+		return true;
+	}
+
+	return false;
+}
+
+static bool ioport_event_end(struct perf_evsel *evsel,
+			     struct perf_sample *sample __maybe_unused,
+			     struct event_key *key __maybe_unused)
+{
+	return kvm_entry_event(evsel);
+}
+
+static void ioport_event_decode_key(struct event_key *key, char decode[20])
+{
+	scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
+				key->info ? "POUT" : "PIN");
+}
+
+static struct kvm_events_ops ioport_events = {
+	.is_begin_event = ioport_event_begin,
+	.is_end_event = ioport_event_end,
+	.decode_key = ioport_event_decode_key,
+	.name = "IO Port Access"
+};
+
+static const char *report_event = "vmexit";
+struct kvm_events_ops *events_ops;
+
+static bool register_kvm_events_ops(void)
+{
+	bool ret = true;
+
+	if (!strcmp(report_event, "vmexit"))
+		events_ops = &exit_events;
+	else if (!strcmp(report_event, "mmio"))
+		events_ops = &mmio_events;
+	else if (!strcmp(report_event, "ioport"))
+		events_ops = &ioport_events;
+	else {
+		pr_err("Unknown report event:%s\n", report_event);
+		ret = false;
+	}
+
+	return ret;
+}
+
+struct kvm_event_stats {
+	u64 time;
+	struct stats stats;
+};
+
+struct kvm_event {
+	struct list_head hash_entry;
+	struct rb_node rb;
+
+	struct event_key key;
+
+	struct kvm_event_stats total;
+
+	#define DEFAULT_VCPU_NUM 8
+	int max_vcpu;
+	struct kvm_event_stats *vcpu;
+};
+
+struct vcpu_event_record {
+	int vcpu_id;
+	u64 start_time;
+	struct kvm_event *last_event;
+};
+
+#define EVENTS_BITS			12
+#define EVENTS_CACHE_SIZE	(1UL << EVENTS_BITS)
+
+static u64 total_time;
+static u64 total_count;
+static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
+
+static void init_kvm_event_record(void)
+{
+	int i;
+
+	for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++)
+		INIT_LIST_HEAD(&kvm_events_cache[i]);
+}
+
+static int kvm_events_hash_fn(u64 key)
+{
+	return key & (EVENTS_CACHE_SIZE - 1);
+}
+
+static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
+{
+	int old_max_vcpu = event->max_vcpu;
+
+	if (vcpu_id < event->max_vcpu)
+		return true;
+
+	while (event->max_vcpu <= vcpu_id)
+		event->max_vcpu += DEFAULT_VCPU_NUM;
+
+	event->vcpu = realloc(event->vcpu,
+			      event->max_vcpu * sizeof(*event->vcpu));
+	if (!event->vcpu) {
+		pr_err("Not enough memory\n");
+		return false;
+	}
+
+	memset(event->vcpu + old_max_vcpu, 0,
+	       (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
+	return true;
+}
+
+static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
+{
+	struct kvm_event *event;
+
+	event = zalloc(sizeof(*event));
+	if (!event) {
+		pr_err("Not enough memory\n");
+		return NULL;
+	}
+
+	event->key = *key;
+	return event;
+}
+
+static struct kvm_event *find_create_kvm_event(struct event_key *key)
+{
+	struct kvm_event *event;
+	struct list_head *head;
+
+	BUG_ON(key->key == INVALID_KEY);
+
+	head = &kvm_events_cache[kvm_events_hash_fn(key->key)];
+	list_for_each_entry(event, head, hash_entry)
+		if (event->key.key == key->key && event->key.info == key->info)
+			return event;
+
+	event = kvm_alloc_init_event(key);
+	if (!event)
+		return NULL;
+
+	list_add(&event->hash_entry, head);
+	return event;
+}
+
+static bool handle_begin_event(struct vcpu_event_record *vcpu_record,
+			       struct event_key *key, u64 timestamp)
+{
+	struct kvm_event *event = NULL;
+
+	if (key->key != INVALID_KEY)
+		event = find_create_kvm_event(key);
+
+	vcpu_record->last_event = event;
+	vcpu_record->start_time = timestamp;
+	return true;
+}
+
+static void
+kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
+{
+	kvm_stats->time += time_diff;
+	update_stats(&kvm_stats->stats, time_diff);
+}
+
+static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
+{
+	struct kvm_event_stats *kvm_stats = &event->total;
+
+	if (vcpu_id != -1)
+		kvm_stats = &event->vcpu[vcpu_id];
+
+	return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
+				avg_stats(&kvm_stats->stats));
+}
+
+static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
+			     u64 time_diff)
+{
+	kvm_update_event_stats(&event->total, time_diff);
+
+	if (!kvm_event_expand(event, vcpu_id))
+		return false;
+
+	kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
+	return true;
+}
+
+static bool handle_end_event(struct vcpu_event_record *vcpu_record,
+			     struct event_key *key, u64 timestamp)
+{
+	struct kvm_event *event;
+	u64 time_begin, time_diff;
+
+	event = vcpu_record->last_event;
+	time_begin = vcpu_record->start_time;
+
+	/* The begin event is not caught. */
+	if (!time_begin)
+		return true;
+
+	/*
+	 * In some case, the 'begin event' only records the start timestamp,
+	 * the actual event is recognized in the 'end event' (e.g. mmio-event).
+	 */
+
+	/* Both begin and end events did not get the key. */
+	if (!event && key->key == INVALID_KEY)
+		return true;
+
+	if (!event)
+		event = find_create_kvm_event(key);
+
+	if (!event)
+		return false;
+
+	vcpu_record->last_event = NULL;
+	vcpu_record->start_time = 0;
+
+	BUG_ON(timestamp < time_begin);
+
+	time_diff = timestamp - time_begin;
+	return update_kvm_event(event, vcpu_record->vcpu_id, time_diff);
+}
+
+static
+struct vcpu_event_record *per_vcpu_record(struct thread *thread,
+					  struct perf_evsel *evsel,
+					  struct perf_sample *sample)
+{
+	/* Only kvm_entry records vcpu id. */
+	if (!thread->priv && kvm_entry_event(evsel)) {
+		struct vcpu_event_record *vcpu_record;
+
+		vcpu_record = zalloc(sizeof(*vcpu_record));
+		if (!vcpu_record) {
+			pr_err("%s: Not enough memory\n", __func__);
+			return NULL;
+		}
+
+		vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id");
+		thread->priv = vcpu_record;
+	}
+
+	return thread->priv;
+}
+
+static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel,
+			     struct perf_sample *sample)
+{
+	struct vcpu_event_record *vcpu_record;
+	struct event_key key = {.key = INVALID_KEY};
+
+	vcpu_record = per_vcpu_record(thread, evsel, sample);
+	if (!vcpu_record)
+		return true;
+
+	if (events_ops->is_begin_event(evsel, sample, &key))
+		return handle_begin_event(vcpu_record, &key, sample->time);
+
+	if (events_ops->is_end_event(evsel, sample, &key))
+		return handle_end_event(vcpu_record, &key, sample->time);
+
+	return true;
+}
+
+typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
+struct kvm_event_key {
+	const char *name;
+	key_cmp_fun key;
+};
+
+static int trace_vcpu = -1;
+#define GET_EVENT_KEY(func, field)					\
+static u64 get_event_ ##func(struct kvm_event *event, int vcpu)		\
+{									\
+	if (vcpu == -1)							\
+		return event->total.field;				\
+									\
+	if (vcpu >= event->max_vcpu)					\
+		return 0;						\
+									\
+	return event->vcpu[vcpu].field;					\
+}
+
+#define COMPARE_EVENT_KEY(func, field)					\
+GET_EVENT_KEY(func, field)						\
+static int compare_kvm_event_ ## func(struct kvm_event *one,		\
+					struct kvm_event *two, int vcpu)\
+{									\
+	return get_event_ ##func(one, vcpu) >				\
+				get_event_ ##func(two, vcpu);		\
+}
+
+GET_EVENT_KEY(time, time);
+COMPARE_EVENT_KEY(count, stats.n);
+COMPARE_EVENT_KEY(mean, stats.mean);
+
+#define DEF_SORT_NAME_KEY(name, compare_key)				\
+	{ #name, compare_kvm_event_ ## compare_key }
+
+static struct kvm_event_key keys[] = {
+	DEF_SORT_NAME_KEY(sample, count),
+	DEF_SORT_NAME_KEY(time, mean),
+	{ NULL, NULL }
+};
+
+static const char *sort_key = "sample";
+static key_cmp_fun compare;
+
+static bool select_key(void)
+{
+	int i;
+
+	for (i = 0; keys[i].name; i++) {
+		if (!strcmp(keys[i].name, sort_key)) {
+			compare = keys[i].key;
+			return true;
+		}
+	}
+
+	pr_err("Unknown compare key:%s\n", sort_key);
+	return false;
+}
+
+static struct rb_root result;
+static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger,
+			     int vcpu)
+{
+	struct rb_node **rb = &result.rb_node;
+	struct rb_node *parent = NULL;
+	struct kvm_event *p;
+
+	while (*rb) {
+		p = container_of(*rb, struct kvm_event, rb);
+		parent = *rb;
+
+		if (bigger(event, p, vcpu))
+			rb = &(*rb)->rb_left;
+		else
+			rb = &(*rb)->rb_right;
+	}
+
+	rb_link_node(&event->rb, parent, rb);
+	rb_insert_color(&event->rb, &result);
+}
+
+static void update_total_count(struct kvm_event *event, int vcpu)
+{
+	total_count += get_event_count(event, vcpu);
+	total_time += get_event_time(event, vcpu);
+}
+
+static bool event_is_valid(struct kvm_event *event, int vcpu)
+{
+	return !!get_event_count(event, vcpu);
+}
+
+static void sort_result(int vcpu)
+{
+	unsigned int i;
+	struct kvm_event *event;
+
+	for (i = 0; i < EVENTS_CACHE_SIZE; i++)
+		list_for_each_entry(event, &kvm_events_cache[i], hash_entry)
+			if (event_is_valid(event, vcpu)) {
+				update_total_count(event, vcpu);
+				insert_to_result(event, compare, vcpu);
+			}
+}
+
+/* returns left most element of result, and erase it */
+static struct kvm_event *pop_from_result(void)
+{
+	struct rb_node *node = rb_first(&result);
+
+	if (!node)
+		return NULL;
+
+	rb_erase(node, &result);
+	return container_of(node, struct kvm_event, rb);
+}
+
+static void print_vcpu_info(int vcpu)
+{
+	pr_info("Analyze events for ");
+
+	if (vcpu == -1)
+		pr_info("all VCPUs:\n\n");
+	else
+		pr_info("VCPU %d:\n\n", vcpu);
+}
+
+static void print_result(int vcpu)
+{
+	char decode[20];
+	struct kvm_event *event;
+
+	pr_info("\n\n");
+	print_vcpu_info(vcpu);
+	pr_info("%20s ", events_ops->name);
+	pr_info("%10s ", "Samples");
+	pr_info("%9s ", "Samples%");
+
+	pr_info("%9s ", "Time%");
+	pr_info("%16s ", "Avg time");
+	pr_info("\n\n");
+
+	while ((event = pop_from_result())) {
+		u64 ecount, etime;
+
+		ecount = get_event_count(event, vcpu);
+		etime = get_event_time(event, vcpu);
+
+		events_ops->decode_key(&event->key, decode);
+		pr_info("%20s ", decode);
+		pr_info("%10llu ", (unsigned long long)ecount);
+		pr_info("%8.2f%% ", (double)ecount / total_count * 100);
+		pr_info("%8.2f%% ", (double)etime / total_time * 100);
+		pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
+			kvm_event_rel_stddev(vcpu, event));
+		pr_info("\n");
+	}
+
+	pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n",
+		(unsigned long long)total_count, total_time / 1e3);
+}
+
+static int process_sample_event(struct perf_tool *tool __maybe_unused,
+				union perf_event *event,
+				struct perf_sample *sample,
+				struct perf_evsel *evsel,
+				struct machine *machine)
+{
+	struct thread *thread = machine__findnew_thread(machine, sample->tid);
+
+	if (thread == NULL) {
+		pr_debug("problem processing %d event, skipping it.\n",
+			event->header.type);
+		return -1;
+	}
+
+	if (!handle_kvm_event(thread, evsel, sample))
+		return -1;
+
+	return 0;
+}
+
+static struct perf_tool eops = {
+	.sample			= process_sample_event,
+	.comm			= perf_event__process_comm,
+	.ordered_samples	= true,
+};
+
+static int get_cpu_isa(struct perf_session *session)
+{
+	char *cpuid = session->header.env.cpuid;
+	int isa;
+
+	if (strstr(cpuid, "Intel"))
+		isa = 1;
+	else if (strstr(cpuid, "AMD"))
+		isa = 0;
+	else {
+		pr_err("CPU %s is not supported.\n", cpuid);
+		isa = -ENOTSUP;
+	}
+
+	return isa;
+}
+
+static const char *file_name;
+
+static int read_events(void)
+{
+	struct perf_session *kvm_session;
+	int ret;
+
+	kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops);
+	if (!kvm_session) {
+		pr_err("Initializing perf session failed\n");
+		return -EINVAL;
+	}
+
+	if (!perf_session__has_traces(kvm_session, "kvm record"))
+		return -EINVAL;
+
+	/*
+	 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
+	 * traced in the old kernel.
+	 */
+	ret = get_cpu_isa(kvm_session);
+
+	if (ret < 0)
+		return ret;
+
+	cpu_isa = ret;
+
+	return perf_session__process_events(kvm_session, &eops);
+}
+
+static bool verify_vcpu(int vcpu)
+{
+	if (vcpu != -1 && vcpu < 0) {
+		pr_err("Invalid vcpu:%d.\n", vcpu);
+		return false;
+	}
+
+	return true;
+}
+
+static int kvm_events_report_vcpu(int vcpu)
+{
+	int ret = -EINVAL;
+
+	if (!verify_vcpu(vcpu))
+		goto exit;
+
+	if (!select_key())
+		goto exit;
+
+	if (!register_kvm_events_ops())
+		goto exit;
+
+	init_kvm_event_record();
+	setup_pager();
+
+	ret = read_events();
+	if (ret)
+		goto exit;
+
+	sort_result(vcpu);
+	print_result(vcpu);
+exit:
+	return ret;
+}
+
+static const char * const record_args[] = {
+	"record",
+	"-R",
+	"-f",
+	"-m", "1024",
+	"-c", "1",
+	"-e", "kvm:kvm_entry",
+	"-e", "kvm:kvm_exit",
+	"-e", "kvm:kvm_mmio",
+	"-e", "kvm:kvm_pio",
+};
+
+#define STRDUP_FAIL_EXIT(s)		\
+	({	char *_p;		\
+	_p = strdup(s);		\
+		if (!_p)		\
+			return -ENOMEM;	\
+		_p;			\
+	})
+
+static int kvm_events_record(int argc, const char **argv)
+{
+	unsigned int rec_argc, i, j;
+	const char **rec_argv;
+
+	rec_argc = ARRAY_SIZE(record_args) + argc + 2;
+	rec_argv = calloc(rec_argc + 1, sizeof(char *));
+
+	if (rec_argv == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(record_args); i++)
+		rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
+
+	rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
+	rec_argv[i++] = STRDUP_FAIL_EXIT(file_name);
+
+	for (j = 1; j < (unsigned int)argc; j++, i++)
+		rec_argv[i] = argv[j];
+
+	return cmd_record(i, rec_argv, NULL);
+}
+
+static const char * const kvm_events_report_usage[] = {
+	"perf kvm stat report [<options>]",
+	NULL
+};
+
+static const struct option kvm_events_report_options[] = {
+	OPT_STRING(0, "event", &report_event, "report event",
+		    "event for reporting: vmexit, mmio, ioport"),
+	OPT_INTEGER(0, "vcpu", &trace_vcpu,
+		    "vcpu id to report"),
+	OPT_STRING('k', "key", &sort_key, "sort-key",
+		    "key for sorting: sample(sort by samples number)"
+		    " time (sort by avg time)"),
+	OPT_END()
+};
+
+static int kvm_events_report(int argc, const char **argv)
+{
+	symbol__init();
+
+	if (argc) {
+		argc = parse_options(argc, argv,
+				     kvm_events_report_options,
+				     kvm_events_report_usage, 0);
+		if (argc)
+			usage_with_options(kvm_events_report_usage,
+					   kvm_events_report_options);
+	}
+
+	return kvm_events_report_vcpu(trace_vcpu);
+}
+
+static void print_kvm_stat_usage(void)
+{
+	printf("Usage: perf kvm stat <command>\n\n");
+
+	printf("# Available commands:\n");
+	printf("\trecord: record kvm events\n");
+	printf("\treport: report statistical data of kvm events\n");
+
+	printf("\nOtherwise, it is the alias of 'perf stat':\n");
+}
+
+static int kvm_cmd_stat(int argc, const char **argv)
+{
+	if (argc == 1) {
+		print_kvm_stat_usage();
+		goto perf_stat;
+	}
+
+	if (!strncmp(argv[1], "rec", 3))
+		return kvm_events_record(argc - 1, argv + 1);
+
+	if (!strncmp(argv[1], "rep", 3))
+		return kvm_events_report(argc - 1 , argv + 1);
+
+perf_stat:
+	return cmd_stat(argc, argv, NULL);
+}
+
 static char			name_buffer[256];
 
 static const char * const kvm_usage[] = {
-	"perf kvm [<options>] {top|record|report|diff|buildid-list}",
+	"perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
 	NULL
 };
 
@@ -102,7 +930,7 @@
 	return cmd_buildid_list(i, rec_argv, NULL);
 }
 
-int cmd_kvm(int argc, const char **argv, const char *prefix __used)
+int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	perf_host  = 0;
 	perf_guest = 1;
@@ -135,6 +963,8 @@
 		return cmd_top(argc, argv, NULL);
 	else if (!strncmp(argv[0], "buildid-list", 12))
 		return __cmd_buildid_list(argc, argv);
+	else if (!strncmp(argv[0], "stat", 4))
+		return kvm_cmd_stat(argc, argv);
 	else
 		usage_with_options(kvm_usage, kvm_options);
 
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 6313b6e..1948ece 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,20 +14,20 @@
 #include "util/parse-events.h"
 #include "util/cache.h"
 
-int cmd_list(int argc, const char **argv, const char *prefix __used)
+int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	setup_pager();
 
 	if (argc == 1)
-		print_events(NULL);
+		print_events(NULL, false);
 	else {
 		int i;
 
 		for (i = 1; i < argc; ++i) {
-			if (i > 1)
+			if (i > 2)
 				putchar('\n');
 			if (strncmp(argv[i], "tracepoint", 10) == 0)
-				print_tracepoint_events(NULL, NULL);
+				print_tracepoint_events(NULL, NULL, false);
 			else if (strcmp(argv[i], "hw") == 0 ||
 				 strcmp(argv[i], "hardware") == 0)
 				print_events_type(PERF_TYPE_HARDWARE);
@@ -36,13 +36,15 @@
 				print_events_type(PERF_TYPE_SOFTWARE);
 			else if (strcmp(argv[i], "cache") == 0 ||
 				 strcmp(argv[i], "hwcache") == 0)
-				print_hwcache_events(NULL);
+				print_hwcache_events(NULL, false);
+			else if (strcmp(argv[i], "--raw-dump") == 0)
+				print_events(NULL, true);
 			else {
 				char *sep = strchr(argv[i], ':'), *s;
 				int sep_idx;
 
 				if (sep == NULL) {
-					print_events(argv[i]);
+					print_events(argv[i], false);
 					continue;
 				}
 				sep_idx = sep - argv[i];
@@ -51,7 +53,7 @@
 					return -1;
 
 				s[sep_idx] = '\0';
-				print_tracepoint_events(s, s + sep_idx + 1);
+				print_tracepoint_events(s, s + sep_idx + 1, false);
 				free(s);
 			}
 		}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index b3c4285..7d6e099 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1,6 +1,8 @@
 #include "builtin.h"
 #include "perf.h"
 
+#include "util/evlist.h"
+#include "util/evsel.h"
 #include "util/util.h"
 #include "util/cache.h"
 #include "util/symbol.h"
@@ -40,7 +42,7 @@
 	struct rb_node		rb;		/* used for sorting */
 
 	/*
-	 * FIXME: raw_field_value() returns unsigned long long,
+	 * FIXME: perf_evsel__intval() returns u64,
 	 * so address of lockdep_map should be dealed as 64bit.
 	 * Is there more better solution?
 	 */
@@ -160,8 +162,10 @@
 		return st;
 
 	st = zalloc(sizeof(struct thread_stat));
-	if (!st)
-		die("memory allocation failed\n");
+	if (!st) {
+		pr_err("memory allocation failed\n");
+		return NULL;
+	}
 
 	st->tid = tid;
 	INIT_LIST_HEAD(&st->seq_list);
@@ -180,8 +184,10 @@
 	struct thread_stat *st;
 
 	st = zalloc(sizeof(struct thread_stat));
-	if (!st)
-		die("memory allocation failed\n");
+	if (!st) {
+		pr_err("memory allocation failed\n");
+		return NULL;
+	}
 	st->tid = tid;
 	INIT_LIST_HEAD(&st->seq_list);
 
@@ -247,18 +253,20 @@
 	{ NULL, NULL }
 };
 
-static void select_key(void)
+static int select_key(void)
 {
 	int i;
 
 	for (i = 0; keys[i].name; i++) {
 		if (!strcmp(keys[i].name, sort_key)) {
 			compare = keys[i].key;
-			return;
+			return 0;
 		}
 	}
 
-	die("Unknown compare key:%s\n", sort_key);
+	pr_err("Unknown compare key: %s\n", sort_key);
+
+	return -1;
 }
 
 static void insert_to_result(struct lock_stat *st,
@@ -323,61 +331,24 @@
 	return new;
 
 alloc_failed:
-	die("memory allocation failed\n");
+	pr_err("memory allocation failed\n");
+	return NULL;
 }
 
 static const char *input_name;
 
-struct raw_event_sample {
-	u32			size;
-	char			data[0];
-};
-
-struct trace_acquire_event {
-	void			*addr;
-	const char		*name;
-	int			flag;
-};
-
-struct trace_acquired_event {
-	void			*addr;
-	const char		*name;
-};
-
-struct trace_contended_event {
-	void			*addr;
-	const char		*name;
-};
-
-struct trace_release_event {
-	void			*addr;
-	const char		*name;
-};
-
 struct trace_lock_handler {
-	void (*acquire_event)(struct trace_acquire_event *,
-			      struct event_format *,
-			      int cpu,
-			      u64 timestamp,
-			      struct thread *thread);
+	int (*acquire_event)(struct perf_evsel *evsel,
+			     struct perf_sample *sample);
 
-	void (*acquired_event)(struct trace_acquired_event *,
-			       struct event_format *,
-			       int cpu,
-			       u64 timestamp,
-			       struct thread *thread);
+	int (*acquired_event)(struct perf_evsel *evsel,
+			      struct perf_sample *sample);
 
-	void (*contended_event)(struct trace_contended_event *,
-				struct event_format *,
-				int cpu,
-				u64 timestamp,
-				struct thread *thread);
+	int (*contended_event)(struct perf_evsel *evsel,
+			       struct perf_sample *sample);
 
-	void (*release_event)(struct trace_release_event *,
-			      struct event_format *,
-			      int cpu,
-			      u64 timestamp,
-			      struct thread *thread);
+	int (*release_event)(struct perf_evsel *evsel,
+			     struct perf_sample *sample);
 };
 
 static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
@@ -390,8 +361,10 @@
 	}
 
 	seq = zalloc(sizeof(struct lock_seq_stat));
-	if (!seq)
-		die("Not enough memory\n");
+	if (!seq) {
+		pr_err("memory allocation failed\n");
+		return NULL;
+	}
 	seq->state = SEQ_STATE_UNINITIALIZED;
 	seq->addr = addr;
 
@@ -414,33 +387,42 @@
 	READ_LOCK = 2,
 };
 
-static void
-report_lock_acquire_event(struct trace_acquire_event *acquire_event,
-			struct event_format *__event __used,
-			int cpu __used,
-			u64 timestamp __used,
-			struct thread *thread __used)
+static int report_lock_acquire_event(struct perf_evsel *evsel,
+				     struct perf_sample *sample)
 {
+	void *addr;
 	struct lock_stat *ls;
 	struct thread_stat *ts;
 	struct lock_seq_stat *seq;
+	const char *name = perf_evsel__strval(evsel, sample, "name");
+	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
+	int flag = perf_evsel__intval(evsel, sample, "flag");
 
-	ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
+	memcpy(&addr, &tmp, sizeof(void *));
+
+	ls = lock_stat_findnew(addr, name);
+	if (!ls)
+		return -1;
 	if (ls->discard)
-		return;
+		return 0;
 
-	ts = thread_stat_findnew(thread->pid);
-	seq = get_seq(ts, acquire_event->addr);
+	ts = thread_stat_findnew(sample->tid);
+	if (!ts)
+		return -1;
+
+	seq = get_seq(ts, addr);
+	if (!seq)
+		return -1;
 
 	switch (seq->state) {
 	case SEQ_STATE_UNINITIALIZED:
 	case SEQ_STATE_RELEASED:
-		if (!acquire_event->flag) {
+		if (!flag) {
 			seq->state = SEQ_STATE_ACQUIRING;
 		} else {
-			if (acquire_event->flag & TRY_LOCK)
+			if (flag & TRY_LOCK)
 				ls->nr_trylock++;
-			if (acquire_event->flag & READ_LOCK)
+			if (flag & READ_LOCK)
 				ls->nr_readlock++;
 			seq->state = SEQ_STATE_READ_ACQUIRED;
 			seq->read_count = 1;
@@ -448,7 +430,7 @@
 		}
 		break;
 	case SEQ_STATE_READ_ACQUIRED:
-		if (acquire_event->flag & READ_LOCK) {
+		if (flag & READ_LOCK) {
 			seq->read_count++;
 			ls->nr_acquired++;
 			goto end;
@@ -473,38 +455,46 @@
 	}
 
 	ls->nr_acquire++;
-	seq->prev_event_time = timestamp;
+	seq->prev_event_time = sample->time;
 end:
-	return;
+	return 0;
 }
 
-static void
-report_lock_acquired_event(struct trace_acquired_event *acquired_event,
-			 struct event_format *__event __used,
-			 int cpu __used,
-			 u64 timestamp __used,
-			 struct thread *thread __used)
+static int report_lock_acquired_event(struct perf_evsel *evsel,
+				      struct perf_sample *sample)
 {
+	void *addr;
 	struct lock_stat *ls;
 	struct thread_stat *ts;
 	struct lock_seq_stat *seq;
 	u64 contended_term;
+	const char *name = perf_evsel__strval(evsel, sample, "name");
+	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
 
-	ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
+	memcpy(&addr, &tmp, sizeof(void *));
+
+	ls = lock_stat_findnew(addr, name);
+	if (!ls)
+		return -1;
 	if (ls->discard)
-		return;
+		return 0;
 
-	ts = thread_stat_findnew(thread->pid);
-	seq = get_seq(ts, acquired_event->addr);
+	ts = thread_stat_findnew(sample->tid);
+	if (!ts)
+		return -1;
+
+	seq = get_seq(ts, addr);
+	if (!seq)
+		return -1;
 
 	switch (seq->state) {
 	case SEQ_STATE_UNINITIALIZED:
 		/* orphan event, do nothing */
-		return;
+		return 0;
 	case SEQ_STATE_ACQUIRING:
 		break;
 	case SEQ_STATE_CONTENDED:
-		contended_term = timestamp - seq->prev_event_time;
+		contended_term = sample->time - seq->prev_event_time;
 		ls->wait_time_total += contended_term;
 		if (contended_term < ls->wait_time_min)
 			ls->wait_time_min = contended_term;
@@ -529,33 +519,41 @@
 
 	seq->state = SEQ_STATE_ACQUIRED;
 	ls->nr_acquired++;
-	seq->prev_event_time = timestamp;
+	seq->prev_event_time = sample->time;
 end:
-	return;
+	return 0;
 }
 
-static void
-report_lock_contended_event(struct trace_contended_event *contended_event,
-			  struct event_format *__event __used,
-			  int cpu __used,
-			  u64 timestamp __used,
-			  struct thread *thread __used)
+static int report_lock_contended_event(struct perf_evsel *evsel,
+				       struct perf_sample *sample)
 {
+	void *addr;
 	struct lock_stat *ls;
 	struct thread_stat *ts;
 	struct lock_seq_stat *seq;
+	const char *name = perf_evsel__strval(evsel, sample, "name");
+	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
 
-	ls = lock_stat_findnew(contended_event->addr, contended_event->name);
+	memcpy(&addr, &tmp, sizeof(void *));
+
+	ls = lock_stat_findnew(addr, name);
+	if (!ls)
+		return -1;
 	if (ls->discard)
-		return;
+		return 0;
 
-	ts = thread_stat_findnew(thread->pid);
-	seq = get_seq(ts, contended_event->addr);
+	ts = thread_stat_findnew(sample->tid);
+	if (!ts)
+		return -1;
+
+	seq = get_seq(ts, addr);
+	if (!seq)
+		return -1;
 
 	switch (seq->state) {
 	case SEQ_STATE_UNINITIALIZED:
 		/* orphan event, do nothing */
-		return;
+		return 0;
 	case SEQ_STATE_ACQUIRING:
 		break;
 	case SEQ_STATE_RELEASED:
@@ -576,28 +574,36 @@
 
 	seq->state = SEQ_STATE_CONTENDED;
 	ls->nr_contended++;
-	seq->prev_event_time = timestamp;
+	seq->prev_event_time = sample->time;
 end:
-	return;
+	return 0;
 }
 
-static void
-report_lock_release_event(struct trace_release_event *release_event,
-			struct event_format *__event __used,
-			int cpu __used,
-			u64 timestamp __used,
-			struct thread *thread __used)
+static int report_lock_release_event(struct perf_evsel *evsel,
+				     struct perf_sample *sample)
 {
+	void *addr;
 	struct lock_stat *ls;
 	struct thread_stat *ts;
 	struct lock_seq_stat *seq;
+	const char *name = perf_evsel__strval(evsel, sample, "name");
+	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
 
-	ls = lock_stat_findnew(release_event->addr, release_event->name);
+	memcpy(&addr, &tmp, sizeof(void *));
+
+	ls = lock_stat_findnew(addr, name);
+	if (!ls)
+		return -1;
 	if (ls->discard)
-		return;
+		return 0;
 
-	ts = thread_stat_findnew(thread->pid);
-	seq = get_seq(ts, release_event->addr);
+	ts = thread_stat_findnew(sample->tid);
+	if (!ts)
+		return -1;
+
+	seq = get_seq(ts, addr);
+	if (!seq)
+		return -1;
 
 	switch (seq->state) {
 	case SEQ_STATE_UNINITIALIZED:
@@ -631,7 +637,7 @@
 	list_del(&seq->list);
 	free(seq);
 end:
-	return;
+	return 0;
 }
 
 /* lock oriented handlers */
@@ -645,96 +651,36 @@
 
 static struct trace_lock_handler *trace_handler;
 
-static void
-process_lock_acquire_event(void *data,
-			   struct event_format *event __used,
-			   int cpu __used,
-			   u64 timestamp __used,
-			   struct thread *thread __used)
+static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
+					     struct perf_sample *sample)
 {
-	struct trace_acquire_event acquire_event;
-	u64 tmp;		/* this is required for casting... */
-
-	tmp = raw_field_value(event, "lockdep_addr", data);
-	memcpy(&acquire_event.addr, &tmp, sizeof(void *));
-	acquire_event.name = (char *)raw_field_ptr(event, "name", data);
-	acquire_event.flag = (int)raw_field_value(event, "flag", data);
-
 	if (trace_handler->acquire_event)
-		trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
+		return trace_handler->acquire_event(evsel, sample);
+	return 0;
 }
 
-static void
-process_lock_acquired_event(void *data,
-			    struct event_format *event __used,
-			    int cpu __used,
-			    u64 timestamp __used,
-			    struct thread *thread __used)
+static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
+					      struct perf_sample *sample)
 {
-	struct trace_acquired_event acquired_event;
-	u64 tmp;		/* this is required for casting... */
-
-	tmp = raw_field_value(event, "lockdep_addr", data);
-	memcpy(&acquired_event.addr, &tmp, sizeof(void *));
-	acquired_event.name = (char *)raw_field_ptr(event, "name", data);
-
-	if (trace_handler->acquire_event)
-		trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
+	if (trace_handler->acquired_event)
+		return trace_handler->acquired_event(evsel, sample);
+	return 0;
 }
 
-static void
-process_lock_contended_event(void *data,
-			     struct event_format *event __used,
-			     int cpu __used,
-			     u64 timestamp __used,
-			     struct thread *thread __used)
+static int perf_evsel__process_lock_contended(struct perf_evsel *evsel,
+					      struct perf_sample *sample)
 {
-	struct trace_contended_event contended_event;
-	u64 tmp;		/* this is required for casting... */
-
-	tmp = raw_field_value(event, "lockdep_addr", data);
-	memcpy(&contended_event.addr, &tmp, sizeof(void *));
-	contended_event.name = (char *)raw_field_ptr(event, "name", data);
-
-	if (trace_handler->acquire_event)
-		trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
+	if (trace_handler->contended_event)
+		return trace_handler->contended_event(evsel, sample);
+	return 0;
 }
 
-static void
-process_lock_release_event(void *data,
-			   struct event_format *event __used,
-			   int cpu __used,
-			   u64 timestamp __used,
-			   struct thread *thread __used)
+static int perf_evsel__process_lock_release(struct perf_evsel *evsel,
+					    struct perf_sample *sample)
 {
-	struct trace_release_event release_event;
-	u64 tmp;		/* this is required for casting... */
-
-	tmp = raw_field_value(event, "lockdep_addr", data);
-	memcpy(&release_event.addr, &tmp, sizeof(void *));
-	release_event.name = (char *)raw_field_ptr(event, "name", data);
-
-	if (trace_handler->acquire_event)
-		trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
-}
-
-static void
-process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
-{
-	struct event_format *event;
-	int type;
-
-	type = trace_parse_common_type(session->pevent, data);
-	event = pevent_find_event(session->pevent, type);
-
-	if (!strcmp(event->name, "lock_acquire"))
-		process_lock_acquire_event(data, event, cpu, timestamp, thread);
-	if (!strcmp(event->name, "lock_acquired"))
-		process_lock_acquired_event(data, event, cpu, timestamp, thread);
-	if (!strcmp(event->name, "lock_contended"))
-		process_lock_contended_event(data, event, cpu, timestamp, thread);
-	if (!strcmp(event->name, "lock_release"))
-		process_lock_release_event(data, event, cpu, timestamp, thread);
+	if (trace_handler->release_event)
+		return trace_handler->release_event(evsel, sample);
+	return 0;
 }
 
 static void print_bad_events(int bad, int total)
@@ -836,20 +782,29 @@
 	}
 }
 
-static void dump_info(void)
+static int dump_info(void)
 {
+	int rc = 0;
+
 	if (info_threads)
 		dump_threads();
 	else if (info_map)
 		dump_map();
-	else
-		die("Unknown type of information\n");
+	else {
+		rc = -1;
+		pr_err("Unknown type of information\n");
+	}
+
+	return rc;
 }
 
-static int process_sample_event(struct perf_tool *tool __used,
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+				  struct perf_sample *sample);
+
+static int process_sample_event(struct perf_tool *tool __maybe_unused,
 				union perf_event *event,
 				struct perf_sample *sample,
-				struct perf_evsel *evsel __used,
+				struct perf_evsel *evsel,
 				struct machine *machine)
 {
 	struct thread *thread = machine__findnew_thread(machine, sample->tid);
@@ -860,7 +815,10 @@
 		return -1;
 	}
 
-	process_raw_event(sample->raw_data, sample->cpu, sample->time, thread);
+	if (evsel->handler.func != NULL) {
+		tracepoint_handler f = evsel->handler.func;
+		return f(evsel, sample);
+	}
 
 	return 0;
 }
@@ -871,11 +829,25 @@
 	.ordered_samples	= true,
 };
 
+static const struct perf_evsel_str_handler lock_tracepoints[] = {
+	{ "lock:lock_acquire",	 perf_evsel__process_lock_acquire,   }, /* CONFIG_LOCKDEP */
+	{ "lock:lock_acquired",	 perf_evsel__process_lock_acquired,  }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
+	{ "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
+	{ "lock:lock_release",	 perf_evsel__process_lock_release,   }, /* CONFIG_LOCKDEP */
+};
+
 static int read_events(void)
 {
 	session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
-	if (!session)
-		die("Initializing perf session failed\n");
+	if (!session) {
+		pr_err("Initializing perf session failed\n");
+		return -1;
+	}
+
+	if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
+		pr_err("Initializing perf session tracepoint handlers failed\n");
+		return -1;
+	}
 
 	return perf_session__process_events(session, &eops);
 }
@@ -892,13 +864,18 @@
 	}
 }
 
-static void __cmd_report(void)
+static int __cmd_report(void)
 {
 	setup_pager();
-	select_key();
-	read_events();
+
+	if ((select_key() != 0) ||
+	    (read_events() != 0))
+		return -1;
+
 	sort_result();
 	print_result();
+
+	return 0;
 }
 
 static const char * const report_usage[] = {
@@ -944,10 +921,6 @@
 	"-f",
 	"-m", "1024",
 	"-c", "1",
-	"-e", "lock:lock_acquire",
-	"-e", "lock:lock_acquired",
-	"-e", "lock:lock_contended",
-	"-e", "lock:lock_release",
 };
 
 static int __cmd_record(int argc, const char **argv)
@@ -955,15 +928,31 @@
 	unsigned int rec_argc, i, j;
 	const char **rec_argv;
 
-	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
-	rec_argv = calloc(rec_argc + 1, sizeof(char *));
+	for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
+		if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
+				pr_err("tracepoint %s is not enabled. "
+				       "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
+				       lock_tracepoints[i].name);
+				return 1;
+		}
+	}
 
+	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
+	/* factor of 2 is for -e in front of each tracepoint */
+	rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
+
+	rec_argv = calloc(rec_argc + 1, sizeof(char *));
 	if (rec_argv == NULL)
 		return -ENOMEM;
 
 	for (i = 0; i < ARRAY_SIZE(record_args); i++)
 		rec_argv[i] = strdup(record_args[i]);
 
+	for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
+		rec_argv[i++] = "-e";
+		rec_argv[i++] = strdup(lock_tracepoints[j].name);
+	}
+
 	for (j = 1; j < (unsigned int)argc; j++, i++)
 		rec_argv[i] = argv[j];
 
@@ -972,9 +961,10 @@
 	return cmd_record(i, rec_argv, NULL);
 }
 
-int cmd_lock(int argc, const char **argv, const char *prefix __used)
+int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	unsigned int i;
+	int rc = 0;
 
 	symbol__init();
 	for (i = 0; i < LOCKHASH_SIZE; i++)
@@ -1009,11 +999,13 @@
 		/* recycling report_lock_ops */
 		trace_handler = &report_lock_ops;
 		setup_pager();
-		read_events();
-		dump_info();
+		if (read_events() != 0)
+			rc = -1;
+		else
+			rc = dump_info();
 	} else {
 		usage_with_options(lock_usage, lock_options);
 	}
 
-	return 0;
+	return rc;
 }
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index e215ae6..118aa89 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -143,8 +143,8 @@
 	return ret;
 }
 
-static int opt_add_probe_event(const struct option *opt __used,
-			      const char *str, int unset __used)
+static int opt_add_probe_event(const struct option *opt __maybe_unused,
+			      const char *str, int unset __maybe_unused)
 {
 	if (str) {
 		params.mod_events = true;
@@ -153,8 +153,8 @@
 		return 0;
 }
 
-static int opt_del_probe_event(const struct option *opt __used,
-			       const char *str, int unset __used)
+static int opt_del_probe_event(const struct option *opt __maybe_unused,
+			       const char *str, int unset __maybe_unused)
 {
 	if (str) {
 		params.mod_events = true;
@@ -166,7 +166,7 @@
 }
 
 static int opt_set_target(const struct option *opt, const char *str,
-			int unset __used)
+			int unset __maybe_unused)
 {
 	int ret = -ENOENT;
 
@@ -188,8 +188,8 @@
 }
 
 #ifdef DWARF_SUPPORT
-static int opt_show_lines(const struct option *opt __used,
-			  const char *str, int unset __used)
+static int opt_show_lines(const struct option *opt __maybe_unused,
+			  const char *str, int unset __maybe_unused)
 {
 	int ret = 0;
 
@@ -209,8 +209,8 @@
 	return ret;
 }
 
-static int opt_show_vars(const struct option *opt __used,
-			 const char *str, int unset __used)
+static int opt_show_vars(const struct option *opt __maybe_unused,
+			 const char *str, int unset __maybe_unused)
 {
 	struct perf_probe_event *pev = &params.events[params.nevents];
 	int ret;
@@ -229,8 +229,8 @@
 }
 #endif
 
-static int opt_set_filter(const struct option *opt __used,
-			  const char *str, int unset __used)
+static int opt_set_filter(const struct option *opt __maybe_unused,
+			  const char *str, int unset __maybe_unused)
 {
 	const char *err;
 
@@ -327,7 +327,7 @@
 	OPT_END()
 };
 
-int cmd_probe(int argc, const char **argv, const char *prefix __used)
+int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int ret;
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4db6e1b..f14cb5f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,6 +31,15 @@
 #include <sched.h>
 #include <sys/mman.h>
 
+#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
+
+#ifdef NO_LIBUNWIND_SUPPORT
+static char callchain_help[] = CALLCHAIN_HELP "[fp]";
+#else
+static unsigned long default_stack_dump_size = 8192;
+static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
+#endif
+
 enum write_mode_t {
 	WRITE_FORCE,
 	WRITE_APPEND
@@ -62,32 +71,38 @@
 	rec->bytes_written += size;
 }
 
-static void write_output(struct perf_record *rec, void *buf, size_t size)
+static int write_output(struct perf_record *rec, void *buf, size_t size)
 {
 	while (size) {
 		int ret = write(rec->output, buf, size);
 
-		if (ret < 0)
-			die("failed to write");
+		if (ret < 0) {
+			pr_err("failed to write\n");
+			return -1;
+		}
 
 		size -= ret;
 		buf += ret;
 
 		rec->bytes_written += ret;
 	}
+
+	return 0;
 }
 
 static int process_synthesized_event(struct perf_tool *tool,
 				     union perf_event *event,
-				     struct perf_sample *sample __used,
-				     struct machine *machine __used)
+				     struct perf_sample *sample __maybe_unused,
+				     struct machine *machine __maybe_unused)
 {
 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
-	write_output(rec, event, event->header.size);
+	if (write_output(rec, event, event->header.size) < 0)
+		return -1;
+
 	return 0;
 }
 
-static void perf_record__mmap_read(struct perf_record *rec,
+static int perf_record__mmap_read(struct perf_record *rec,
 				   struct perf_mmap *md)
 {
 	unsigned int head = perf_mmap__read_head(md);
@@ -95,9 +110,10 @@
 	unsigned char *data = md->base + rec->page_size;
 	unsigned long size;
 	void *buf;
+	int rc = 0;
 
 	if (old == head)
-		return;
+		return 0;
 
 	rec->samples++;
 
@@ -108,17 +124,26 @@
 		size = md->mask + 1 - (old & md->mask);
 		old += size;
 
-		write_output(rec, buf, size);
+		if (write_output(rec, buf, size) < 0) {
+			rc = -1;
+			goto out;
+		}
 	}
 
 	buf = &data[old & md->mask];
 	size = head - old;
 	old += size;
 
-	write_output(rec, buf, size);
+	if (write_output(rec, buf, size) < 0) {
+		rc = -1;
+		goto out;
+	}
 
 	md->prev = old;
 	perf_mmap__write_tail(md, old);
+
+out:
+	return rc;
 }
 
 static volatile int done = 0;
@@ -134,7 +159,7 @@
 	signr = sig;
 }
 
-static void perf_record__sig_exit(int exit_status __used, void *arg)
+static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
 {
 	struct perf_record *rec = arg;
 	int status;
@@ -163,31 +188,32 @@
 	if (evlist->nr_entries != other->nr_entries)
 		return false;
 
-	pair = list_entry(other->entries.next, struct perf_evsel, node);
+	pair = perf_evlist__first(other);
 
 	list_for_each_entry(pos, &evlist->entries, node) {
 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
 			return false;
-		pair = list_entry(pair->node.next, struct perf_evsel, node);
+		pair = perf_evsel__next(pair);
 	}
 
 	return true;
 }
 
-static void perf_record__open(struct perf_record *rec)
+static int perf_record__open(struct perf_record *rec)
 {
-	struct perf_evsel *pos, *first;
+	struct perf_evsel *pos;
 	struct perf_evlist *evlist = rec->evlist;
 	struct perf_session *session = rec->session;
 	struct perf_record_opts *opts = &rec->opts;
-
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	int rc = 0;
 
 	perf_evlist__config_attrs(evlist, opts);
 
+	if (opts->group)
+		perf_evlist__set_leader(evlist);
+
 	list_for_each_entry(pos, &evlist->entries, node) {
 		struct perf_event_attr *attr = &pos->attr;
-		struct xyarray *group_fd = NULL;
 		/*
 		 * Check if parse_single_tracepoint_event has already asked for
 		 * PERF_SAMPLE_TIME.
@@ -202,24 +228,24 @@
 		 */
 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
 
-		if (opts->group && pos != first)
-			group_fd = first->fd;
 fallback_missing_features:
 		if (opts->exclude_guest_missing)
 			attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
 		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 try_again:
-		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
-				     opts->group, group_fd) < 0) {
+		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
 			int err = errno;
 
 			if (err == EPERM || err == EACCES) {
 				ui__error_paranoid();
-				exit(EXIT_FAILURE);
+				rc = -err;
+				goto out;
 			} else if (err ==  ENODEV && opts->target.cpu_list) {
-				die("No such device - did you specify"
-					" an out-of-range profile CPU?\n");
+				pr_err("No such device - did you specify"
+				       " an out-of-range profile CPU?\n");
+				rc = -err;
+				goto out;
 			} else if (err == EINVAL) {
 				if (!opts->exclude_guest_missing &&
 				    (attr->exclude_guest || attr->exclude_host)) {
@@ -266,42 +292,57 @@
 			if (err == ENOENT) {
 				ui__error("The %s event is not supported.\n",
 					  perf_evsel__name(pos));
-				exit(EXIT_FAILURE);
+				rc = -err;
+				goto out;
 			}
 
 			printf("\n");
-			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
-			      err, strerror(err));
+			error("sys_perf_event_open() syscall returned with %d "
+			      "(%s) for event %s. /bin/dmesg may provide "
+			      "additional information.\n",
+			      err, strerror(err), perf_evsel__name(pos));
 
 #if defined(__i386__) || defined(__x86_64__)
-			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
-				die("No hardware sampling interrupt available."
-				    " No APIC? If so then you can boot the kernel"
-				    " with the \"lapic\" boot parameter to"
-				    " force-enable it.\n");
+			if (attr->type == PERF_TYPE_HARDWARE &&
+			    err == EOPNOTSUPP) {
+				pr_err("No hardware sampling interrupt available."
+				       " No APIC? If so then you can boot the kernel"
+				       " with the \"lapic\" boot parameter to"
+				       " force-enable it.\n");
+				rc = -err;
+				goto out;
+			}
 #endif
 
-			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+			pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+			rc = -err;
+			goto out;
 		}
 	}
 
-	if (perf_evlist__set_filters(evlist)) {
+	if (perf_evlist__apply_filters(evlist)) {
 		error("failed to set filter with %d (%s)\n", errno,
 			strerror(errno));
-		exit(-1);
+		rc = -1;
+		goto out;
 	}
 
 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
-		if (errno == EPERM)
-			die("Permission error mapping pages.\n"
-			    "Consider increasing "
-			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
-			    "or try again with a smaller value of -m/--mmap_pages.\n"
-			    "(current value: %d)\n", opts->mmap_pages);
-		else if (!is_power_of_2(opts->mmap_pages))
-			die("--mmap_pages/-m value must be a power of two.");
-
-		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
+		if (errno == EPERM) {
+			pr_err("Permission error mapping pages.\n"
+			       "Consider increasing "
+			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
+			       "or try again with a smaller value of -m/--mmap_pages.\n"
+			       "(current value: %d)\n", opts->mmap_pages);
+			rc = -errno;
+		} else if (!is_power_of_2(opts->mmap_pages)) {
+			pr_err("--mmap_pages/-m value must be a power of two.");
+			rc = -EINVAL;
+		} else {
+			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
+			rc = -errno;
+		}
+		goto out;
 	}
 
 	if (rec->file_new)
@@ -309,11 +350,14 @@
 	else {
 		if (!perf_evlist__equal(session->evlist, evlist)) {
 			fprintf(stderr, "incompatible append\n");
-			exit(-1);
+			rc = -1;
+			goto out;
 		}
  	}
 
 	perf_session__set_id_hdr_size(session);
+out:
+	return rc;
 }
 
 static int process_buildids(struct perf_record *rec)
@@ -329,10 +373,13 @@
 					      size, &build_id__mark_dso_hit_ops);
 }
 
-static void perf_record__exit(int status __used, void *arg)
+static void perf_record__exit(int status, void *arg)
 {
 	struct perf_record *rec = arg;
 
+	if (status != 0)
+		return;
+
 	if (!rec->opts.pipe_output) {
 		rec->session->header.data_size += rec->bytes_written;
 
@@ -387,17 +434,26 @@
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void perf_record__mmap_read_all(struct perf_record *rec)
+static int perf_record__mmap_read_all(struct perf_record *rec)
 {
 	int i;
+	int rc = 0;
 
 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
-		if (rec->evlist->mmap[i].base)
-			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
+		if (rec->evlist->mmap[i].base) {
+			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
+				rc = -1;
+				goto out;
+			}
+		}
 	}
 
 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
-		write_output(rec, &finished_round_event, sizeof(finished_round_event));
+		rc = write_output(rec, &finished_round_event,
+				  sizeof(finished_round_event));
+
+out:
+	return rc;
 }
 
 static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
@@ -457,7 +513,7 @@
 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
 	if (output < 0) {
 		perror("failed to create output file");
-		exit(-1);
+		return -1;
 	}
 
 	rec->output = output;
@@ -497,7 +553,10 @@
 		}
 	}
 
-	perf_record__open(rec);
+	if (perf_record__open(rec) != 0) {
+		err = -1;
+		goto out_delete_session;
+	}
 
 	/*
 	 * perf_session__delete(session) will be called at perf_record__exit()
@@ -507,19 +566,20 @@
 	if (opts->pipe_output) {
 		err = perf_header__write_pipe(output);
 		if (err < 0)
-			return err;
+			goto out_delete_session;
 	} else if (rec->file_new) {
 		err = perf_session__write_header(session, evsel_list,
 						 output, false);
 		if (err < 0)
-			return err;
+			goto out_delete_session;
 	}
 
 	if (!rec->no_buildid
 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
 		pr_err("Couldn't generate buildids. "
 		       "Use --no-buildid to profile anyway.\n");
-		return -1;
+		err = -1;
+		goto out_delete_session;
 	}
 
 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
@@ -527,7 +587,8 @@
 	machine = perf_session__find_host_machine(session);
 	if (!machine) {
 		pr_err("Couldn't find native kernel information.\n");
-		return -1;
+		err = -1;
+		goto out_delete_session;
 	}
 
 	if (opts->pipe_output) {
@@ -535,14 +596,14 @@
 						   process_synthesized_event);
 		if (err < 0) {
 			pr_err("Couldn't synthesize attrs.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
 							 machine);
 		if (err < 0) {
 			pr_err("Couldn't synthesize event_types.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		if (have_tracepoints(&evsel_list->entries)) {
@@ -558,7 +619,7 @@
 								  process_synthesized_event);
 			if (err <= 0) {
 				pr_err("Couldn't record tracing data.\n");
-				return err;
+				goto out_delete_session;
 			}
 			advance_output(rec, err);
 		}
@@ -586,20 +647,24 @@
 					       perf_event__synthesize_guest_os);
 
 	if (!opts->target.system_wide)
-		perf_event__synthesize_thread_map(tool, evsel_list->threads,
+		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
 						  process_synthesized_event,
 						  machine);
 	else
-		perf_event__synthesize_threads(tool, process_synthesized_event,
+		err = perf_event__synthesize_threads(tool, process_synthesized_event,
 					       machine);
 
+	if (err != 0)
+		goto out_delete_session;
+
 	if (rec->realtime_prio) {
 		struct sched_param param;
 
 		param.sched_priority = rec->realtime_prio;
 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
 			pr_err("Could not set realtime priority.\n");
-			exit(-1);
+			err = -1;
+			goto out_delete_session;
 		}
 	}
 
@@ -614,7 +679,10 @@
 	for (;;) {
 		int hits = rec->samples;
 
-		perf_record__mmap_read_all(rec);
+		if (perf_record__mmap_read_all(rec) < 0) {
+			err = -1;
+			goto out_delete_session;
+		}
 
 		if (hits == rec->samples) {
 			if (done)
@@ -732,6 +800,106 @@
 	return ret;
 }
 
+#ifndef NO_LIBUNWIND_SUPPORT
+static int get_stack_size(char *str, unsigned long *_size)
+{
+	char *endptr;
+	unsigned long size;
+	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
+
+	size = strtoul(str, &endptr, 0);
+
+	do {
+		if (*endptr)
+			break;
+
+		size = round_up(size, sizeof(u64));
+		if (!size || size > max_size)
+			break;
+
+		*_size = size;
+		return 0;
+
+	} while (0);
+
+	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
+	       max_size, str);
+	return -1;
+}
+#endif /* !NO_LIBUNWIND_SUPPORT */
+
+static int
+parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
+		    int unset)
+{
+	struct perf_record *rec = (struct perf_record *)opt->value;
+	char *tok, *name, *saveptr = NULL;
+	char *buf;
+	int ret = -1;
+
+	/* --no-call-graph */
+	if (unset)
+		return 0;
+
+	/* We specified default option if none is provided. */
+	BUG_ON(!arg);
+
+	/* We need buffer that we know we can write to. */
+	buf = malloc(strlen(arg) + 1);
+	if (!buf)
+		return -ENOMEM;
+
+	strcpy(buf, arg);
+
+	tok = strtok_r((char *)buf, ",", &saveptr);
+	name = tok ? : (char *)buf;
+
+	do {
+		/* Framepointer style */
+		if (!strncmp(name, "fp", sizeof("fp"))) {
+			if (!strtok_r(NULL, ",", &saveptr)) {
+				rec->opts.call_graph = CALLCHAIN_FP;
+				ret = 0;
+			} else
+				pr_err("callchain: No more arguments "
+				       "needed for -g fp\n");
+			break;
+
+#ifndef NO_LIBUNWIND_SUPPORT
+		/* Dwarf style */
+		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
+			ret = 0;
+			rec->opts.call_graph = CALLCHAIN_DWARF;
+			rec->opts.stack_dump_size = default_stack_dump_size;
+
+			tok = strtok_r(NULL, ",", &saveptr);
+			if (tok) {
+				unsigned long size = 0;
+
+				ret = get_stack_size(tok, &size);
+				rec->opts.stack_dump_size = size;
+			}
+
+			if (!ret)
+				pr_debug("callchain: stack dump size %d\n",
+					 rec->opts.stack_dump_size);
+#endif /* !NO_LIBUNWIND_SUPPORT */
+		} else {
+			pr_err("callchain: Unknown -g option "
+			       "value: %s\n", arg);
+			break;
+		}
+
+	} while (0);
+
+	free(buf);
+
+	if (!ret)
+		pr_debug("callchain: type %d\n", rec->opts.call_graph);
+
+	return ret;
+}
+
 static const char * const record_usage[] = {
 	"perf record [<options>] [<command>]",
 	"perf record [<options>] -- <command> [<options>]",
@@ -803,8 +971,9 @@
 		     "number of mmap data pages"),
 	OPT_BOOLEAN(0, "group", &record.opts.group,
 		    "put the counters into a counter group"),
-	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
-		    "do call-graph (stack chain/backtrace) recording"),
+	OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]",
+			     callchain_help, &parse_callchain_opt,
+			     "fp"),
 	OPT_INCR('v', "verbose", &verbose,
 		    "be more verbose (show counter open errors, etc)"),
 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
@@ -836,7 +1005,7 @@
 	OPT_END()
 };
 
-int cmd_record(int argc, const char **argv, const char *prefix __used)
+int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int err = -ENOMEM;
 	struct perf_evsel *pos;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 7c88a24..1da243d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -69,8 +69,8 @@
 
 	if ((sort__has_parent || symbol_conf.use_callchain)
 	    && sample->callchain) {
-		err = machine__resolve_callchain(machine, al->thread,
-						 sample->callchain, &parent);
+		err = machine__resolve_callchain(machine, evsel, al->thread,
+						 sample, &parent);
 		if (err)
 			return err;
 	}
@@ -93,7 +93,7 @@
 			struct annotation *notes;
 			err = -ENOMEM;
 			bx = he->branch_info;
-			if (bx->from.sym && use_browser > 0) {
+			if (bx->from.sym && use_browser == 1 && sort__has_sym) {
 				notes = symbol__annotation(bx->from.sym);
 				if (!notes->src
 				    && symbol__alloc_hist(bx->from.sym) < 0)
@@ -107,7 +107,7 @@
 					goto out;
 			}
 
-			if (bx->to.sym && use_browser > 0) {
+			if (bx->to.sym && use_browser == 1 && sort__has_sym) {
 				notes = symbol__annotation(bx->to.sym);
 				if (!notes->src
 				    && symbol__alloc_hist(bx->to.sym) < 0)
@@ -140,8 +140,8 @@
 	struct hist_entry *he;
 
 	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
-		err = machine__resolve_callchain(machine, al->thread,
-						 sample->callchain, &parent);
+		err = machine__resolve_callchain(machine, evsel, al->thread,
+						 sample, &parent);
 		if (err)
 			return err;
 	}
@@ -162,7 +162,7 @@
 	 * so we don't allocated the extra space needed because the stdio
 	 * code will not use it.
 	 */
-	if (he->ms.sym != NULL && use_browser > 0) {
+	if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
 		struct annotation *notes = symbol__annotation(he->ms.sym);
 
 		assert(evsel != NULL);
@@ -223,9 +223,9 @@
 
 static int process_read_event(struct perf_tool *tool,
 			      union perf_event *event,
-			      struct perf_sample *sample __used,
+			      struct perf_sample *sample __maybe_unused,
 			      struct perf_evsel *evsel,
-			      struct machine *machine __used)
+			      struct machine *machine __maybe_unused)
 {
 	struct perf_report *rep = container_of(tool, struct perf_report, tool);
 
@@ -287,7 +287,7 @@
 
 extern volatile int session_done;
 
-static void sig_handler(int sig __used)
+static void sig_handler(int sig __maybe_unused)
 {
 	session_done = 1;
 }
@@ -397,17 +397,17 @@
 		desc);
 	}
 
-	if (dump_trace) {
-		perf_session__fprintf_nr_events(session, stdout);
-		goto out_delete;
-	}
-
 	if (verbose > 3)
 		perf_session__fprintf(session, stdout);
 
 	if (verbose > 2)
 		perf_session__fprintf_dsos(session, stdout);
 
+	if (dump_trace) {
+		perf_session__fprintf_nr_events(session, stdout);
+		goto out_delete;
+	}
+
 	nr_samples = 0;
 	list_for_each_entry(pos, &session->evlist->entries, node) {
 		struct hists *hists = &pos->hists;
@@ -533,13 +533,14 @@
 }
 
 static int
-parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
+parse_branch_mode(const struct option *opt __maybe_unused,
+		  const char *str __maybe_unused, int unset)
 {
 	sort__branch_mode = !unset;
 	return 0;
 }
 
-int cmd_report(int argc, const char **argv, const char *prefix __used)
+int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_session *session;
 	struct stat st;
@@ -638,6 +639,8 @@
 		    "Show a column with the sum of periods"),
 	OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
 		    "use branch records for histogram filling", parse_branch_mode),
+	OPT_STRING(0, "objdump", &objdump_path, "path",
+		   "objdump binary to use for disassembly and annotations"),
 	OPT_END()
 	};
 
@@ -686,15 +689,19 @@
 
 	if (strcmp(report.input_name, "-") != 0)
 		setup_browser(true);
-	else
+	else {
 		use_browser = 0;
+		perf_hpp__init(false, false);
+	}
+
+	setup_sorting(report_usage, options);
 
 	/*
 	 * Only in the newt browser we are doing integrated annotation,
 	 * so don't allocate extra space that won't be used in the stdio
 	 * implementation.
 	 */
-	if (use_browser > 0) {
+	if (use_browser == 1 && sort__has_sym) {
 		symbol_conf.priv_size = sizeof(struct annotation);
 		report.annotate_init  = symbol__annotate_init;
 		/*
@@ -717,8 +724,6 @@
 	if (symbol__init() < 0)
 		goto error;
 
-	setup_sorting(report_usage, options);
-
 	if (parent_pattern != default_parent_pattern) {
 		if (sort_dimension__add("parent") < 0)
 			goto error;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 7a9ad2b..9b9e32e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -23,31 +23,12 @@
 #include <pthread.h>
 #include <math.h>
 
-static const char		*input_name;
-
-static char			default_sort_order[] = "avg, max, switch, runtime";
-static const char		*sort_order = default_sort_order;
-
-static int			profile_cpu = -1;
-
 #define PR_SET_NAME		15               /* Set process name */
 #define MAX_CPUS		4096
-
-static u64			run_measurement_overhead;
-static u64			sleep_measurement_overhead;
-
 #define COMM_LEN		20
 #define SYM_LEN			129
-
 #define MAX_PID			65536
 
-static unsigned long		nr_tasks;
-
-struct perf_sched {
-	struct perf_tool    tool;
-	struct perf_session *session;
-};
-
 struct sched_atom;
 
 struct task_desc {
@@ -85,44 +66,6 @@
 	struct task_desc	*wakee;
 };
 
-static struct task_desc		*pid_to_task[MAX_PID];
-
-static struct task_desc		**tasks;
-
-static pthread_mutex_t		start_work_mutex = PTHREAD_MUTEX_INITIALIZER;
-static u64			start_time;
-
-static pthread_mutex_t		work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static unsigned long		nr_run_events;
-static unsigned long		nr_sleep_events;
-static unsigned long		nr_wakeup_events;
-
-static unsigned long		nr_sleep_corrections;
-static unsigned long		nr_run_events_optimized;
-
-static unsigned long		targetless_wakeups;
-static unsigned long		multitarget_wakeups;
-
-static u64			cpu_usage;
-static u64			runavg_cpu_usage;
-static u64			parent_cpu_usage;
-static u64			runavg_parent_cpu_usage;
-
-static unsigned long		nr_runs;
-static u64			sum_runtime;
-static u64			sum_fluct;
-static u64			run_avg;
-
-static unsigned int		replay_repeat = 10;
-static unsigned long		nr_timestamps;
-static unsigned long		nr_unordered_timestamps;
-static unsigned long		nr_state_machine_bugs;
-static unsigned long		nr_context_switch_bugs;
-static unsigned long		nr_events;
-static unsigned long		nr_lost_chunks;
-static unsigned long		nr_lost_events;
-
 #define TASK_STATE_TO_CHAR_STR "RSDTtZX"
 
 enum thread_state {
@@ -154,11 +97,79 @@
 
 typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
 
-static struct rb_root		atom_root, sorted_atom_root;
+struct perf_sched;
 
-static u64			all_runtime;
-static u64			all_count;
+struct trace_sched_handler {
+	int (*switch_event)(struct perf_sched *sched, struct perf_evsel *evsel,
+			    struct perf_sample *sample, struct machine *machine);
 
+	int (*runtime_event)(struct perf_sched *sched, struct perf_evsel *evsel,
+			     struct perf_sample *sample, struct machine *machine);
+
+	int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
+			    struct perf_sample *sample, struct machine *machine);
+
+	int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel,
+			  struct perf_sample *sample);
+
+	int (*migrate_task_event)(struct perf_sched *sched,
+				  struct perf_evsel *evsel,
+				  struct perf_sample *sample,
+				  struct machine *machine);
+};
+
+struct perf_sched {
+	struct perf_tool tool;
+	const char	 *input_name;
+	const char	 *sort_order;
+	unsigned long	 nr_tasks;
+	struct task_desc *pid_to_task[MAX_PID];
+	struct task_desc **tasks;
+	const struct trace_sched_handler *tp_handler;
+	pthread_mutex_t	 start_work_mutex;
+	pthread_mutex_t	 work_done_wait_mutex;
+	int		 profile_cpu;
+/*
+ * Track the current task - that way we can know whether there's any
+ * weird events, such as a task being switched away that is not current.
+ */
+	int		 max_cpu;
+	u32		 curr_pid[MAX_CPUS];
+	struct thread	 *curr_thread[MAX_CPUS];
+	char		 next_shortname1;
+	char		 next_shortname2;
+	unsigned int	 replay_repeat;
+	unsigned long	 nr_run_events;
+	unsigned long	 nr_sleep_events;
+	unsigned long	 nr_wakeup_events;
+	unsigned long	 nr_sleep_corrections;
+	unsigned long	 nr_run_events_optimized;
+	unsigned long	 targetless_wakeups;
+	unsigned long	 multitarget_wakeups;
+	unsigned long	 nr_runs;
+	unsigned long	 nr_timestamps;
+	unsigned long	 nr_unordered_timestamps;
+	unsigned long	 nr_state_machine_bugs;
+	unsigned long	 nr_context_switch_bugs;
+	unsigned long	 nr_events;
+	unsigned long	 nr_lost_chunks;
+	unsigned long	 nr_lost_events;
+	u64		 run_measurement_overhead;
+	u64		 sleep_measurement_overhead;
+	u64		 start_time;
+	u64		 cpu_usage;
+	u64		 runavg_cpu_usage;
+	u64		 parent_cpu_usage;
+	u64		 runavg_parent_cpu_usage;
+	u64		 sum_runtime;
+	u64		 sum_fluct;
+	u64		 run_avg;
+	u64		 all_runtime;
+	u64		 all_count;
+	u64		 cpu_last_switched[MAX_CPUS];
+	struct rb_root	 atom_root, sorted_atom_root;
+	struct list_head sort_list, cmp_pid;
+};
 
 static u64 get_nsecs(void)
 {
@@ -169,13 +180,13 @@
 	return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
 }
 
-static void burn_nsecs(u64 nsecs)
+static void burn_nsecs(struct perf_sched *sched, u64 nsecs)
 {
 	u64 T0 = get_nsecs(), T1;
 
 	do {
 		T1 = get_nsecs();
-	} while (T1 + run_measurement_overhead < T0 + nsecs);
+	} while (T1 + sched->run_measurement_overhead < T0 + nsecs);
 }
 
 static void sleep_nsecs(u64 nsecs)
@@ -188,24 +199,24 @@
 	nanosleep(&ts, NULL);
 }
 
-static void calibrate_run_measurement_overhead(void)
+static void calibrate_run_measurement_overhead(struct perf_sched *sched)
 {
 	u64 T0, T1, delta, min_delta = 1000000000ULL;
 	int i;
 
 	for (i = 0; i < 10; i++) {
 		T0 = get_nsecs();
-		burn_nsecs(0);
+		burn_nsecs(sched, 0);
 		T1 = get_nsecs();
 		delta = T1-T0;
 		min_delta = min(min_delta, delta);
 	}
-	run_measurement_overhead = min_delta;
+	sched->run_measurement_overhead = min_delta;
 
 	printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 }
 
-static void calibrate_sleep_measurement_overhead(void)
+static void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
 {
 	u64 T0, T1, delta, min_delta = 1000000000ULL;
 	int i;
@@ -218,7 +229,7 @@
 		min_delta = min(min_delta, delta);
 	}
 	min_delta -= 10000;
-	sleep_measurement_overhead = min_delta;
+	sched->sleep_measurement_overhead = min_delta;
 
 	printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 }
@@ -251,8 +262,8 @@
 	return task->atoms[task->nr_events - 1];
 }
 
-static void
-add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration)
+static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task,
+				u64 timestamp, u64 duration)
 {
 	struct sched_atom *event, *curr_event = last_event(task);
 
@@ -261,7 +272,7 @@
 	 * to it:
 	 */
 	if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
-		nr_run_events_optimized++;
+		sched->nr_run_events_optimized++;
 		curr_event->duration += duration;
 		return;
 	}
@@ -271,12 +282,11 @@
 	event->type = SCHED_EVENT_RUN;
 	event->duration = duration;
 
-	nr_run_events++;
+	sched->nr_run_events++;
 }
 
-static void
-add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
-		       struct task_desc *wakee)
+static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task,
+				   u64 timestamp, struct task_desc *wakee)
 {
 	struct sched_atom *event, *wakee_event;
 
@@ -286,11 +296,11 @@
 
 	wakee_event = last_event(wakee);
 	if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
-		targetless_wakeups++;
+		sched->targetless_wakeups++;
 		return;
 	}
 	if (wakee_event->wait_sem) {
-		multitarget_wakeups++;
+		sched->multitarget_wakeups++;
 		return;
 	}
 
@@ -299,89 +309,89 @@
 	wakee_event->specific_wait = 1;
 	event->wait_sem = wakee_event->wait_sem;
 
-	nr_wakeup_events++;
+	sched->nr_wakeup_events++;
 }
 
-static void
-add_sched_event_sleep(struct task_desc *task, u64 timestamp,
-		      u64 task_state __used)
+static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task,
+				  u64 timestamp, u64 task_state __maybe_unused)
 {
 	struct sched_atom *event = get_new_event(task, timestamp);
 
 	event->type = SCHED_EVENT_SLEEP;
 
-	nr_sleep_events++;
+	sched->nr_sleep_events++;
 }
 
-static struct task_desc *register_pid(unsigned long pid, const char *comm)
+static struct task_desc *register_pid(struct perf_sched *sched,
+				      unsigned long pid, const char *comm)
 {
 	struct task_desc *task;
 
 	BUG_ON(pid >= MAX_PID);
 
-	task = pid_to_task[pid];
+	task = sched->pid_to_task[pid];
 
 	if (task)
 		return task;
 
 	task = zalloc(sizeof(*task));
 	task->pid = pid;
-	task->nr = nr_tasks;
+	task->nr = sched->nr_tasks;
 	strcpy(task->comm, comm);
 	/*
 	 * every task starts in sleeping state - this gets ignored
 	 * if there's no wakeup pointing to this sleep state:
 	 */
-	add_sched_event_sleep(task, 0, 0);
+	add_sched_event_sleep(sched, task, 0, 0);
 
-	pid_to_task[pid] = task;
-	nr_tasks++;
-	tasks = realloc(tasks, nr_tasks*sizeof(struct task_task *));
-	BUG_ON(!tasks);
-	tasks[task->nr] = task;
+	sched->pid_to_task[pid] = task;
+	sched->nr_tasks++;
+	sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_task *));
+	BUG_ON(!sched->tasks);
+	sched->tasks[task->nr] = task;
 
 	if (verbose)
-		printf("registered task #%ld, PID %ld (%s)\n", nr_tasks, pid, comm);
+		printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm);
 
 	return task;
 }
 
 
-static void print_task_traces(void)
+static void print_task_traces(struct perf_sched *sched)
 {
 	struct task_desc *task;
 	unsigned long i;
 
-	for (i = 0; i < nr_tasks; i++) {
-		task = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		task = sched->tasks[i];
 		printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
 			task->nr, task->comm, task->pid, task->nr_events);
 	}
 }
 
-static void add_cross_task_wakeups(void)
+static void add_cross_task_wakeups(struct perf_sched *sched)
 {
 	struct task_desc *task1, *task2;
 	unsigned long i, j;
 
-	for (i = 0; i < nr_tasks; i++) {
-		task1 = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		task1 = sched->tasks[i];
 		j = i + 1;
-		if (j == nr_tasks)
+		if (j == sched->nr_tasks)
 			j = 0;
-		task2 = tasks[j];
-		add_sched_event_wakeup(task1, 0, task2);
+		task2 = sched->tasks[j];
+		add_sched_event_wakeup(sched, task1, 0, task2);
 	}
 }
 
-static void
-process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
+static void perf_sched__process_event(struct perf_sched *sched,
+				      struct sched_atom *atom)
 {
 	int ret = 0;
 
 	switch (atom->type) {
 		case SCHED_EVENT_RUN:
-			burn_nsecs(atom->duration);
+			burn_nsecs(sched, atom->duration);
 			break;
 		case SCHED_EVENT_SLEEP:
 			if (atom->wait_sem)
@@ -428,8 +438,8 @@
 	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 
 	if (fd < 0)
-		die("Error: sys_perf_event_open() syscall returned"
-		    "with %d (%s)\n", fd, strerror(errno));
+		pr_err("Error: sys_perf_event_open() syscall returned "
+		       "with %d (%s)\n", fd, strerror(errno));
 	return fd;
 }
 
@@ -444,31 +454,41 @@
 	return runtime;
 }
 
+struct sched_thread_parms {
+	struct task_desc  *task;
+	struct perf_sched *sched;
+};
+
 static void *thread_func(void *ctx)
 {
-	struct task_desc *this_task = ctx;
+	struct sched_thread_parms *parms = ctx;
+	struct task_desc *this_task = parms->task;
+	struct perf_sched *sched = parms->sched;
 	u64 cpu_usage_0, cpu_usage_1;
 	unsigned long i, ret;
 	char comm2[22];
 	int fd;
 
+	free(parms);
+
 	sprintf(comm2, ":%s", this_task->comm);
 	prctl(PR_SET_NAME, comm2);
 	fd = self_open_counters();
-
+	if (fd < 0)
+		return NULL;
 again:
 	ret = sem_post(&this_task->ready_for_work);
 	BUG_ON(ret);
-	ret = pthread_mutex_lock(&start_work_mutex);
+	ret = pthread_mutex_lock(&sched->start_work_mutex);
 	BUG_ON(ret);
-	ret = pthread_mutex_unlock(&start_work_mutex);
+	ret = pthread_mutex_unlock(&sched->start_work_mutex);
 	BUG_ON(ret);
 
 	cpu_usage_0 = get_cpu_usage_nsec_self(fd);
 
 	for (i = 0; i < this_task->nr_events; i++) {
 		this_task->curr_event = i;
-		process_sched_event(this_task, this_task->atoms[i]);
+		perf_sched__process_event(sched, this_task->atoms[i]);
 	}
 
 	cpu_usage_1 = get_cpu_usage_nsec_self(fd);
@@ -476,15 +496,15 @@
 	ret = sem_post(&this_task->work_done_sem);
 	BUG_ON(ret);
 
-	ret = pthread_mutex_lock(&work_done_wait_mutex);
+	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
 	BUG_ON(ret);
-	ret = pthread_mutex_unlock(&work_done_wait_mutex);
+	ret = pthread_mutex_unlock(&sched->work_done_wait_mutex);
 	BUG_ON(ret);
 
 	goto again;
 }
 
-static void create_tasks(void)
+static void create_tasks(struct perf_sched *sched)
 {
 	struct task_desc *task;
 	pthread_attr_t attr;
@@ -496,128 +516,129 @@
 	err = pthread_attr_setstacksize(&attr,
 			(size_t) max(16 * 1024, PTHREAD_STACK_MIN));
 	BUG_ON(err);
-	err = pthread_mutex_lock(&start_work_mutex);
+	err = pthread_mutex_lock(&sched->start_work_mutex);
 	BUG_ON(err);
-	err = pthread_mutex_lock(&work_done_wait_mutex);
+	err = pthread_mutex_lock(&sched->work_done_wait_mutex);
 	BUG_ON(err);
-	for (i = 0; i < nr_tasks; i++) {
-		task = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		struct sched_thread_parms *parms = malloc(sizeof(*parms));
+		BUG_ON(parms == NULL);
+		parms->task = task = sched->tasks[i];
+		parms->sched = sched;
 		sem_init(&task->sleep_sem, 0, 0);
 		sem_init(&task->ready_for_work, 0, 0);
 		sem_init(&task->work_done_sem, 0, 0);
 		task->curr_event = 0;
-		err = pthread_create(&task->thread, &attr, thread_func, task);
+		err = pthread_create(&task->thread, &attr, thread_func, parms);
 		BUG_ON(err);
 	}
 }
 
-static void wait_for_tasks(void)
+static void wait_for_tasks(struct perf_sched *sched)
 {
 	u64 cpu_usage_0, cpu_usage_1;
 	struct task_desc *task;
 	unsigned long i, ret;
 
-	start_time = get_nsecs();
-	cpu_usage = 0;
-	pthread_mutex_unlock(&work_done_wait_mutex);
+	sched->start_time = get_nsecs();
+	sched->cpu_usage = 0;
+	pthread_mutex_unlock(&sched->work_done_wait_mutex);
 
-	for (i = 0; i < nr_tasks; i++) {
-		task = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		task = sched->tasks[i];
 		ret = sem_wait(&task->ready_for_work);
 		BUG_ON(ret);
 		sem_init(&task->ready_for_work, 0, 0);
 	}
-	ret = pthread_mutex_lock(&work_done_wait_mutex);
+	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
 	BUG_ON(ret);
 
 	cpu_usage_0 = get_cpu_usage_nsec_parent();
 
-	pthread_mutex_unlock(&start_work_mutex);
+	pthread_mutex_unlock(&sched->start_work_mutex);
 
-	for (i = 0; i < nr_tasks; i++) {
-		task = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		task = sched->tasks[i];
 		ret = sem_wait(&task->work_done_sem);
 		BUG_ON(ret);
 		sem_init(&task->work_done_sem, 0, 0);
-		cpu_usage += task->cpu_usage;
+		sched->cpu_usage += task->cpu_usage;
 		task->cpu_usage = 0;
 	}
 
 	cpu_usage_1 = get_cpu_usage_nsec_parent();
-	if (!runavg_cpu_usage)
-		runavg_cpu_usage = cpu_usage;
-	runavg_cpu_usage = (runavg_cpu_usage*9 + cpu_usage)/10;
+	if (!sched->runavg_cpu_usage)
+		sched->runavg_cpu_usage = sched->cpu_usage;
+	sched->runavg_cpu_usage = (sched->runavg_cpu_usage * 9 + sched->cpu_usage) / 10;
 
-	parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
-	if (!runavg_parent_cpu_usage)
-		runavg_parent_cpu_usage = parent_cpu_usage;
-	runavg_parent_cpu_usage = (runavg_parent_cpu_usage*9 +
-				   parent_cpu_usage)/10;
+	sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
+	if (!sched->runavg_parent_cpu_usage)
+		sched->runavg_parent_cpu_usage = sched->parent_cpu_usage;
+	sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * 9 +
+					 sched->parent_cpu_usage)/10;
 
-	ret = pthread_mutex_lock(&start_work_mutex);
+	ret = pthread_mutex_lock(&sched->start_work_mutex);
 	BUG_ON(ret);
 
-	for (i = 0; i < nr_tasks; i++) {
-		task = tasks[i];
+	for (i = 0; i < sched->nr_tasks; i++) {
+		task = sched->tasks[i];
 		sem_init(&task->sleep_sem, 0, 0);
 		task->curr_event = 0;
 	}
 }
 
-static void run_one_test(void)
+static void run_one_test(struct perf_sched *sched)
 {
 	u64 T0, T1, delta, avg_delta, fluct;
 
 	T0 = get_nsecs();
-	wait_for_tasks();
+	wait_for_tasks(sched);
 	T1 = get_nsecs();
 
 	delta = T1 - T0;
-	sum_runtime += delta;
-	nr_runs++;
+	sched->sum_runtime += delta;
+	sched->nr_runs++;
 
-	avg_delta = sum_runtime / nr_runs;
+	avg_delta = sched->sum_runtime / sched->nr_runs;
 	if (delta < avg_delta)
 		fluct = avg_delta - delta;
 	else
 		fluct = delta - avg_delta;
-	sum_fluct += fluct;
-	if (!run_avg)
-		run_avg = delta;
-	run_avg = (run_avg*9 + delta)/10;
+	sched->sum_fluct += fluct;
+	if (!sched->run_avg)
+		sched->run_avg = delta;
+	sched->run_avg = (sched->run_avg * 9 + delta) / 10;
 
-	printf("#%-3ld: %0.3f, ",
-		nr_runs, (double)delta/1000000.0);
+	printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0);
 
-	printf("ravg: %0.2f, ",
-		(double)run_avg/1e6);
+	printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6);
 
 	printf("cpu: %0.2f / %0.2f",
-		(double)cpu_usage/1e6, (double)runavg_cpu_usage/1e6);
+		(double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6);
 
 #if 0
 	/*
 	 * rusage statistics done by the parent, these are less
-	 * accurate than the sum_exec_runtime based statistics:
+	 * accurate than the sched->sum_exec_runtime based statistics:
 	 */
 	printf(" [%0.2f / %0.2f]",
-		(double)parent_cpu_usage/1e6,
-		(double)runavg_parent_cpu_usage/1e6);
+		(double)sched->parent_cpu_usage/1e6,
+		(double)sched->runavg_parent_cpu_usage/1e6);
 #endif
 
 	printf("\n");
 
-	if (nr_sleep_corrections)
-		printf(" (%ld sleep corrections)\n", nr_sleep_corrections);
-	nr_sleep_corrections = 0;
+	if (sched->nr_sleep_corrections)
+		printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections);
+	sched->nr_sleep_corrections = 0;
 }
 
-static void test_calibrations(void)
+static void test_calibrations(struct perf_sched *sched)
 {
 	u64 T0, T1;
 
 	T0 = get_nsecs();
-	burn_nsecs(1e6);
+	burn_nsecs(sched, 1e6);
 	T1 = get_nsecs();
 
 	printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
@@ -629,236 +650,92 @@
 	printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
 }
 
-#define FILL_FIELD(ptr, field, event, data)	\
-	ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
-
-#define FILL_ARRAY(ptr, array, event, data)			\
-do {								\
-	void *__array = raw_field_ptr(event, #array, data);	\
-	memcpy(ptr.array, __array, sizeof(ptr.array));	\
-} while(0)
-
-#define FILL_COMMON_FIELDS(ptr, event, data)			\
-do {								\
-	FILL_FIELD(ptr, common_type, event, data);		\
-	FILL_FIELD(ptr, common_flags, event, data);		\
-	FILL_FIELD(ptr, common_preempt_count, event, data);	\
-	FILL_FIELD(ptr, common_pid, event, data);		\
-	FILL_FIELD(ptr, common_tgid, event, data);		\
-} while (0)
-
-
-
-struct trace_switch_event {
-	u32 size;
-
-	u16 common_type;
-	u8 common_flags;
-	u8 common_preempt_count;
-	u32 common_pid;
-	u32 common_tgid;
-
-	char prev_comm[16];
-	u32 prev_pid;
-	u32 prev_prio;
-	u64 prev_state;
-	char next_comm[16];
-	u32 next_pid;
-	u32 next_prio;
-};
-
-struct trace_runtime_event {
-	u32 size;
-
-	u16 common_type;
-	u8 common_flags;
-	u8 common_preempt_count;
-	u32 common_pid;
-	u32 common_tgid;
-
-	char comm[16];
-	u32 pid;
-	u64 runtime;
-	u64 vruntime;
-};
-
-struct trace_wakeup_event {
-	u32 size;
-
-	u16 common_type;
-	u8 common_flags;
-	u8 common_preempt_count;
-	u32 common_pid;
-	u32 common_tgid;
-
-	char comm[16];
-	u32 pid;
-
-	u32 prio;
-	u32 success;
-	u32 cpu;
-};
-
-struct trace_fork_event {
-	u32 size;
-
-	u16 common_type;
-	u8 common_flags;
-	u8 common_preempt_count;
-	u32 common_pid;
-	u32 common_tgid;
-
-	char parent_comm[16];
-	u32 parent_pid;
-	char child_comm[16];
-	u32 child_pid;
-};
-
-struct trace_migrate_task_event {
-	u32 size;
-
-	u16 common_type;
-	u8 common_flags;
-	u8 common_preempt_count;
-	u32 common_pid;
-	u32 common_tgid;
-
-	char comm[16];
-	u32 pid;
-
-	u32 prio;
-	u32 cpu;
-};
-
-struct trace_sched_handler {
-	void (*switch_event)(struct trace_switch_event *,
-			     struct machine *,
-			     struct event_format *,
-			     int cpu,
-			     u64 timestamp,
-			     struct thread *thread);
-
-	void (*runtime_event)(struct trace_runtime_event *,
-			      struct machine *,
-			      struct event_format *,
-			      int cpu,
-			      u64 timestamp,
-			      struct thread *thread);
-
-	void (*wakeup_event)(struct trace_wakeup_event *,
-			     struct machine *,
-			     struct event_format *,
-			     int cpu,
-			     u64 timestamp,
-			     struct thread *thread);
-
-	void (*fork_event)(struct trace_fork_event *,
-			   struct event_format *,
-			   int cpu,
-			   u64 timestamp,
-			   struct thread *thread);
-
-	void (*migrate_task_event)(struct trace_migrate_task_event *,
-			   struct machine *machine,
-			   struct event_format *,
-			   int cpu,
-			   u64 timestamp,
-			   struct thread *thread);
-};
-
-
-static void
-replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
-		    struct machine *machine __used,
-		    struct event_format *event,
-		    int cpu __used,
-		    u64 timestamp __used,
-		    struct thread *thread __used)
+static int
+replay_wakeup_event(struct perf_sched *sched,
+		    struct perf_evsel *evsel, struct perf_sample *sample,
+		    struct machine *machine __maybe_unused)
 {
+	const char *comm = perf_evsel__strval(evsel, sample, "comm");
+	const u32 pid	 = perf_evsel__intval(evsel, sample, "pid");
 	struct task_desc *waker, *wakee;
 
 	if (verbose) {
-		printf("sched_wakeup event %p\n", event);
+		printf("sched_wakeup event %p\n", evsel);
 
-		printf(" ... pid %d woke up %s/%d\n",
-			wakeup_event->common_pid,
-			wakeup_event->comm,
-			wakeup_event->pid);
+		printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid);
 	}
 
-	waker = register_pid(wakeup_event->common_pid, "<unknown>");
-	wakee = register_pid(wakeup_event->pid, wakeup_event->comm);
+	waker = register_pid(sched, sample->tid, "<unknown>");
+	wakee = register_pid(sched, pid, comm);
 
-	add_sched_event_wakeup(waker, timestamp, wakee);
+	add_sched_event_wakeup(sched, waker, sample->time, wakee);
+	return 0;
 }
 
-static u64 cpu_last_switched[MAX_CPUS];
-
-static void
-replay_switch_event(struct trace_switch_event *switch_event,
-		    struct machine *machine __used,
-		    struct event_format *event,
-		    int cpu,
-		    u64 timestamp,
-		    struct thread *thread __used)
+static int replay_switch_event(struct perf_sched *sched,
+			       struct perf_evsel *evsel,
+			       struct perf_sample *sample,
+			       struct machine *machine __maybe_unused)
 {
-	struct task_desc *prev, __used *next;
-	u64 timestamp0;
+	const char *prev_comm  = perf_evsel__strval(evsel, sample, "prev_comm"),
+		   *next_comm  = perf_evsel__strval(evsel, sample, "next_comm");
+	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
+		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
+	const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
+	struct task_desc *prev, __maybe_unused *next;
+	u64 timestamp0, timestamp = sample->time;
+	int cpu = sample->cpu;
 	s64 delta;
 
 	if (verbose)
-		printf("sched_switch event %p\n", event);
+		printf("sched_switch event %p\n", evsel);
 
 	if (cpu >= MAX_CPUS || cpu < 0)
-		return;
+		return 0;
 
-	timestamp0 = cpu_last_switched[cpu];
+	timestamp0 = sched->cpu_last_switched[cpu];
 	if (timestamp0)
 		delta = timestamp - timestamp0;
 	else
 		delta = 0;
 
-	if (delta < 0)
-		die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
-
-	if (verbose) {
-		printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
-			switch_event->prev_comm, switch_event->prev_pid,
-			switch_event->next_comm, switch_event->next_pid,
-			delta);
+	if (delta < 0) {
+		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
+		return -1;
 	}
 
-	prev = register_pid(switch_event->prev_pid, switch_event->prev_comm);
-	next = register_pid(switch_event->next_pid, switch_event->next_comm);
+	pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
+		 prev_comm, prev_pid, next_comm, next_pid, delta);
 
-	cpu_last_switched[cpu] = timestamp;
+	prev = register_pid(sched, prev_pid, prev_comm);
+	next = register_pid(sched, next_pid, next_comm);
 
-	add_sched_event_run(prev, timestamp, delta);
-	add_sched_event_sleep(prev, timestamp, switch_event->prev_state);
+	sched->cpu_last_switched[cpu] = timestamp;
+
+	add_sched_event_run(sched, prev, timestamp, delta);
+	add_sched_event_sleep(sched, prev, timestamp, prev_state);
+
+	return 0;
 }
 
-
-static void
-replay_fork_event(struct trace_fork_event *fork_event,
-		  struct event_format *event,
-		  int cpu __used,
-		  u64 timestamp __used,
-		  struct thread *thread __used)
+static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel,
+			     struct perf_sample *sample)
 {
-	if (verbose) {
-		printf("sched_fork event %p\n", event);
-		printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid);
-		printf("...  child: %s/%d\n", fork_event->child_comm, fork_event->child_pid);
-	}
-	register_pid(fork_event->parent_pid, fork_event->parent_comm);
-	register_pid(fork_event->child_pid, fork_event->child_comm);
-}
+	const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"),
+		   *child_comm  = perf_evsel__strval(evsel, sample, "child_comm");
+	const u32 parent_pid  = perf_evsel__intval(evsel, sample, "parent_pid"),
+		  child_pid  = perf_evsel__intval(evsel, sample, "child_pid");
 
-static struct trace_sched_handler replay_ops  = {
-	.wakeup_event		= replay_wakeup_event,
-	.switch_event		= replay_switch_event,
-	.fork_event		= replay_fork_event,
-};
+	if (verbose) {
+		printf("sched_fork event %p\n", evsel);
+		printf("... parent: %s/%d\n", parent_comm, parent_pid);
+		printf("...  child: %s/%d\n", child_comm, child_pid);
+	}
+
+	register_pid(sched, parent_pid, parent_comm);
+	register_pid(sched, child_pid, child_comm);
+	return 0;
+}
 
 struct sort_dimension {
 	const char		*name;
@@ -866,8 +743,6 @@
 	struct list_head	list;
 };
 
-static LIST_HEAD(cmp_pid);
-
 static int
 thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
 {
@@ -936,43 +811,45 @@
 	rb_insert_color(&data->node, root);
 }
 
-static void thread_atoms_insert(struct thread *thread)
+static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
 {
 	struct work_atoms *atoms = zalloc(sizeof(*atoms));
-	if (!atoms)
-		die("No memory");
+	if (!atoms) {
+		pr_err("No memory at %s\n", __func__);
+		return -1;
+	}
 
 	atoms->thread = thread;
 	INIT_LIST_HEAD(&atoms->work_list);
-	__thread_latency_insert(&atom_root, atoms, &cmp_pid);
+	__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
+	return 0;
 }
 
-static void
-latency_fork_event(struct trace_fork_event *fork_event __used,
-		   struct event_format *event __used,
-		   int cpu __used,
-		   u64 timestamp __used,
-		   struct thread *thread __used)
+static int latency_fork_event(struct perf_sched *sched __maybe_unused,
+			      struct perf_evsel *evsel __maybe_unused,
+			      struct perf_sample *sample __maybe_unused)
 {
 	/* should insert the newcomer */
+	return 0;
 }
 
-__used
-static char sched_out_state(struct trace_switch_event *switch_event)
+static char sched_out_state(u64 prev_state)
 {
 	const char *str = TASK_STATE_TO_CHAR_STR;
 
-	return str[switch_event->prev_state];
+	return str[prev_state];
 }
 
-static void
+static int
 add_sched_out_event(struct work_atoms *atoms,
 		    char run_state,
 		    u64 timestamp)
 {
 	struct work_atom *atom = zalloc(sizeof(*atom));
-	if (!atom)
-		die("Non memory");
+	if (!atom) {
+		pr_err("Non memory at %s", __func__);
+		return -1;
+	}
 
 	atom->sched_out_time = timestamp;
 
@@ -982,10 +859,12 @@
 	}
 
 	list_add_tail(&atom->list, &atoms->work_list);
+	return 0;
 }
 
 static void
-add_runtime_event(struct work_atoms *atoms, u64 delta, u64 timestamp __used)
+add_runtime_event(struct work_atoms *atoms, u64 delta,
+		  u64 timestamp __maybe_unused)
 {
 	struct work_atom *atom;
 
@@ -1028,106 +907,128 @@
 	atoms->nb_atoms++;
 }
 
-static void
-latency_switch_event(struct trace_switch_event *switch_event,
-		     struct machine *machine,
-		     struct event_format *event __used,
-		     int cpu,
-		     u64 timestamp,
-		     struct thread *thread __used)
+static int latency_switch_event(struct perf_sched *sched,
+				struct perf_evsel *evsel,
+				struct perf_sample *sample,
+				struct machine *machine)
 {
+	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
+		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
+	const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
 	struct work_atoms *out_events, *in_events;
 	struct thread *sched_out, *sched_in;
-	u64 timestamp0;
+	u64 timestamp0, timestamp = sample->time;
+	int cpu = sample->cpu;
 	s64 delta;
 
 	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
 
-	timestamp0 = cpu_last_switched[cpu];
-	cpu_last_switched[cpu] = timestamp;
+	timestamp0 = sched->cpu_last_switched[cpu];
+	sched->cpu_last_switched[cpu] = timestamp;
 	if (timestamp0)
 		delta = timestamp - timestamp0;
 	else
 		delta = 0;
 
-	if (delta < 0)
-		die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
-
-
-	sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
-	sched_in = machine__findnew_thread(machine, switch_event->next_pid);
-
-	out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
-	if (!out_events) {
-		thread_atoms_insert(sched_out);
-		out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
-		if (!out_events)
-			die("out-event: Internal tree error");
+	if (delta < 0) {
+		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
+		return -1;
 	}
-	add_sched_out_event(out_events, sched_out_state(switch_event), timestamp);
 
-	in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
+	sched_out = machine__findnew_thread(machine, prev_pid);
+	sched_in = machine__findnew_thread(machine, next_pid);
+
+	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
+	if (!out_events) {
+		if (thread_atoms_insert(sched, sched_out))
+			return -1;
+		out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
+		if (!out_events) {
+			pr_err("out-event: Internal tree error");
+			return -1;
+		}
+	}
+	if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp))
+		return -1;
+
+	in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
 	if (!in_events) {
-		thread_atoms_insert(sched_in);
-		in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
-		if (!in_events)
-			die("in-event: Internal tree error");
+		if (thread_atoms_insert(sched, sched_in))
+			return -1;
+		in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
+		if (!in_events) {
+			pr_err("in-event: Internal tree error");
+			return -1;
+		}
 		/*
 		 * Take came in we have not heard about yet,
 		 * add in an initial atom in runnable state:
 		 */
-		add_sched_out_event(in_events, 'R', timestamp);
+		if (add_sched_out_event(in_events, 'R', timestamp))
+			return -1;
 	}
 	add_sched_in_event(in_events, timestamp);
+
+	return 0;
 }
 
-static void
-latency_runtime_event(struct trace_runtime_event *runtime_event,
-		     struct machine *machine,
-		     struct event_format *event __used,
-		     int cpu,
-		     u64 timestamp,
-		     struct thread *this_thread __used)
+static int latency_runtime_event(struct perf_sched *sched,
+				 struct perf_evsel *evsel,
+				 struct perf_sample *sample,
+				 struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, runtime_event->pid);
-	struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
+	const u32 pid	   = perf_evsel__intval(evsel, sample, "pid");
+	const u64 runtime  = perf_evsel__intval(evsel, sample, "runtime");
+	struct thread *thread = machine__findnew_thread(machine, pid);
+	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
+	u64 timestamp = sample->time;
+	int cpu = sample->cpu;
 
 	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
 	if (!atoms) {
-		thread_atoms_insert(thread);
-		atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
-		if (!atoms)
-			die("in-event: Internal tree error");
-		add_sched_out_event(atoms, 'R', timestamp);
+		if (thread_atoms_insert(sched, thread))
+			return -1;
+		atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
+		if (!atoms) {
+			pr_err("in-event: Internal tree error");
+			return -1;
+		}
+		if (add_sched_out_event(atoms, 'R', timestamp))
+			return -1;
 	}
 
-	add_runtime_event(atoms, runtime_event->runtime, timestamp);
+	add_runtime_event(atoms, runtime, timestamp);
+	return 0;
 }
 
-static void
-latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
-		     struct machine *machine,
-		     struct event_format *__event __used,
-		     int cpu __used,
-		     u64 timestamp,
-		     struct thread *thread __used)
+static int latency_wakeup_event(struct perf_sched *sched,
+				struct perf_evsel *evsel,
+				struct perf_sample *sample,
+				struct machine *machine)
 {
+	const u32 pid	  = perf_evsel__intval(evsel, sample, "pid"),
+		  success = perf_evsel__intval(evsel, sample, "success");
 	struct work_atoms *atoms;
 	struct work_atom *atom;
 	struct thread *wakee;
+	u64 timestamp = sample->time;
 
 	/* Note for later, it may be interesting to observe the failing cases */
-	if (!wakeup_event->success)
-		return;
+	if (!success)
+		return 0;
 
-	wakee = machine__findnew_thread(machine, wakeup_event->pid);
-	atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
+	wakee = machine__findnew_thread(machine, pid);
+	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
 	if (!atoms) {
-		thread_atoms_insert(wakee);
-		atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
-		if (!atoms)
-			die("wakeup-event: Internal tree error");
-		add_sched_out_event(atoms, 'S', timestamp);
+		if (thread_atoms_insert(sched, wakee))
+			return -1;
+		atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
+		if (!atoms) {
+			pr_err("wakeup-event: Internal tree error");
+			return -1;
+		}
+		if (add_sched_out_event(atoms, 'S', timestamp))
+			return -1;
 	}
 
 	BUG_ON(list_empty(&atoms->work_list));
@@ -1139,27 +1040,27 @@
 	 * one CPU, or are only looking at only one, so don't
 	 * make useless noise.
 	 */
-	if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
-		nr_state_machine_bugs++;
+	if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
+		sched->nr_state_machine_bugs++;
 
-	nr_timestamps++;
+	sched->nr_timestamps++;
 	if (atom->sched_out_time > timestamp) {
-		nr_unordered_timestamps++;
-		return;
+		sched->nr_unordered_timestamps++;
+		return 0;
 	}
 
 	atom->state = THREAD_WAIT_CPU;
 	atom->wake_up_time = timestamp;
+	return 0;
 }
 
-static void
-latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
-		     struct machine *machine,
-		     struct event_format *__event __used,
-		     int cpu __used,
-		     u64 timestamp,
-		     struct thread *thread __used)
+static int latency_migrate_task_event(struct perf_sched *sched,
+				      struct perf_evsel *evsel,
+				      struct perf_sample *sample,
+				      struct machine *machine)
 {
+	const u32 pid = perf_evsel__intval(evsel, sample, "pid");
+	u64 timestamp = sample->time;
 	struct work_atoms *atoms;
 	struct work_atom *atom;
 	struct thread *migrant;
@@ -1167,18 +1068,22 @@
 	/*
 	 * Only need to worry about migration when profiling one CPU.
 	 */
-	if (profile_cpu == -1)
-		return;
+	if (sched->profile_cpu == -1)
+		return 0;
 
-	migrant = machine__findnew_thread(machine, migrate_task_event->pid);
-	atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
+	migrant = machine__findnew_thread(machine, pid);
+	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
 	if (!atoms) {
-		thread_atoms_insert(migrant);
-		register_pid(migrant->pid, migrant->comm);
-		atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
-		if (!atoms)
-			die("migration-event: Internal tree error");
-		add_sched_out_event(atoms, 'R', timestamp);
+		if (thread_atoms_insert(sched, migrant))
+			return -1;
+		register_pid(sched, migrant->pid, migrant->comm);
+		atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
+		if (!atoms) {
+			pr_err("migration-event: Internal tree error");
+			return -1;
+		}
+		if (add_sched_out_event(atoms, 'R', timestamp))
+			return -1;
 	}
 
 	BUG_ON(list_empty(&atoms->work_list));
@@ -1186,21 +1091,15 @@
 	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
 	atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
 
-	nr_timestamps++;
+	sched->nr_timestamps++;
 
 	if (atom->sched_out_time > timestamp)
-		nr_unordered_timestamps++;
+		sched->nr_unordered_timestamps++;
+
+	return 0;
 }
 
-static struct trace_sched_handler lat_ops  = {
-	.wakeup_event		= latency_wakeup_event,
-	.switch_event		= latency_switch_event,
-	.runtime_event		= latency_runtime_event,
-	.fork_event		= latency_fork_event,
-	.migrate_task_event	= latency_migrate_task_event,
-};
-
-static void output_lat_thread(struct work_atoms *work_list)
+static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list)
 {
 	int i;
 	int ret;
@@ -1214,8 +1113,8 @@
 	if (!strcmp(work_list->thread->comm, "swapper"))
 		return;
 
-	all_runtime += work_list->total_runtime;
-	all_count += work_list->nb_atoms;
+	sched->all_runtime += work_list->total_runtime;
+	sched->all_count   += work_list->nb_atoms;
 
 	ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->pid);
 
@@ -1241,11 +1140,6 @@
 	return 0;
 }
 
-static struct sort_dimension pid_sort_dimension = {
-	.name			= "pid",
-	.cmp			= pid_cmp,
-};
-
 static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
 {
 	u64 avgl, avgr;
@@ -1267,11 +1161,6 @@
 	return 0;
 }
 
-static struct sort_dimension avg_sort_dimension = {
-	.name			= "avg",
-	.cmp			= avg_cmp,
-};
-
 static int max_cmp(struct work_atoms *l, struct work_atoms *r)
 {
 	if (l->max_lat < r->max_lat)
@@ -1282,11 +1171,6 @@
 	return 0;
 }
 
-static struct sort_dimension max_sort_dimension = {
-	.name			= "max",
-	.cmp			= max_cmp,
-};
-
 static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
 {
 	if (l->nb_atoms < r->nb_atoms)
@@ -1297,11 +1181,6 @@
 	return 0;
 }
 
-static struct sort_dimension switch_sort_dimension = {
-	.name			= "switch",
-	.cmp			= switch_cmp,
-};
-
 static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
 {
 	if (l->total_runtime < r->total_runtime)
@@ -1312,28 +1191,38 @@
 	return 0;
 }
 
-static struct sort_dimension runtime_sort_dimension = {
-	.name			= "runtime",
-	.cmp			= runtime_cmp,
-};
-
-static struct sort_dimension *available_sorts[] = {
-	&pid_sort_dimension,
-	&avg_sort_dimension,
-	&max_sort_dimension,
-	&switch_sort_dimension,
-	&runtime_sort_dimension,
-};
-
-#define NB_AVAILABLE_SORTS	(int)(sizeof(available_sorts) / sizeof(struct sort_dimension *))
-
-static LIST_HEAD(sort_list);
-
 static int sort_dimension__add(const char *tok, struct list_head *list)
 {
-	int i;
+	size_t i;
+	static struct sort_dimension avg_sort_dimension = {
+		.name = "avg",
+		.cmp  = avg_cmp,
+	};
+	static struct sort_dimension max_sort_dimension = {
+		.name = "max",
+		.cmp  = max_cmp,
+	};
+	static struct sort_dimension pid_sort_dimension = {
+		.name = "pid",
+		.cmp  = pid_cmp,
+	};
+	static struct sort_dimension runtime_sort_dimension = {
+		.name = "runtime",
+		.cmp  = runtime_cmp,
+	};
+	static struct sort_dimension switch_sort_dimension = {
+		.name = "switch",
+		.cmp  = switch_cmp,
+	};
+	struct sort_dimension *available_sorts[] = {
+		&pid_sort_dimension,
+		&avg_sort_dimension,
+		&max_sort_dimension,
+		&switch_sort_dimension,
+		&runtime_sort_dimension,
+	};
 
-	for (i = 0; i < NB_AVAILABLE_SORTS; i++) {
+	for (i = 0; i < ARRAY_SIZE(available_sorts); i++) {
 		if (!strcmp(available_sorts[i]->name, tok)) {
 			list_add_tail(&available_sorts[i]->list, list);
 
@@ -1344,126 +1233,97 @@
 	return -1;
 }
 
-static void setup_sorting(void);
-
-static void sort_lat(void)
+static void perf_sched__sort_lat(struct perf_sched *sched)
 {
 	struct rb_node *node;
 
 	for (;;) {
 		struct work_atoms *data;
-		node = rb_first(&atom_root);
+		node = rb_first(&sched->atom_root);
 		if (!node)
 			break;
 
-		rb_erase(node, &atom_root);
+		rb_erase(node, &sched->atom_root);
 		data = rb_entry(node, struct work_atoms, node);
-		__thread_latency_insert(&sorted_atom_root, data, &sort_list);
+		__thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list);
 	}
 }
 
-static struct trace_sched_handler *trace_handler;
-
-static void
-process_sched_wakeup_event(struct perf_tool *tool __used,
-			   struct event_format *event,
-			   struct perf_sample *sample,
-			   struct machine *machine,
-			   struct thread *thread)
+static int process_sched_wakeup_event(struct perf_tool *tool,
+				      struct perf_evsel *evsel,
+				      struct perf_sample *sample,
+				      struct machine *machine)
 {
-	void *data = sample->raw_data;
-	struct trace_wakeup_event wakeup_event;
+	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
-	FILL_COMMON_FIELDS(wakeup_event, event, data);
+	if (sched->tp_handler->wakeup_event)
+		return sched->tp_handler->wakeup_event(sched, evsel, sample, machine);
 
-	FILL_ARRAY(wakeup_event, comm, event, data);
-	FILL_FIELD(wakeup_event, pid, event, data);
-	FILL_FIELD(wakeup_event, prio, event, data);
-	FILL_FIELD(wakeup_event, success, event, data);
-	FILL_FIELD(wakeup_event, cpu, event, data);
-
-	if (trace_handler->wakeup_event)
-		trace_handler->wakeup_event(&wakeup_event, machine, event,
-					    sample->cpu, sample->time, thread);
+	return 0;
 }
 
-/*
- * Track the current task - that way we can know whether there's any
- * weird events, such as a task being switched away that is not current.
- */
-static int max_cpu;
-
-static u32 curr_pid[MAX_CPUS] = { [0 ... MAX_CPUS-1] = -1 };
-
-static struct thread *curr_thread[MAX_CPUS];
-
-static char next_shortname1 = 'A';
-static char next_shortname2 = '0';
-
-static void
-map_switch_event(struct trace_switch_event *switch_event,
-		 struct machine *machine,
-		 struct event_format *event __used,
-		 int this_cpu,
-		 u64 timestamp,
-		 struct thread *thread __used)
+static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
+			    struct perf_sample *sample, struct machine *machine)
 {
-	struct thread *sched_out __used, *sched_in;
+	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
+		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
+	struct thread *sched_out __maybe_unused, *sched_in;
 	int new_shortname;
-	u64 timestamp0;
+	u64 timestamp0, timestamp = sample->time;
 	s64 delta;
-	int cpu;
+	int cpu, this_cpu = sample->cpu;
 
 	BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
 
-	if (this_cpu > max_cpu)
-		max_cpu = this_cpu;
+	if (this_cpu > sched->max_cpu)
+		sched->max_cpu = this_cpu;
 
-	timestamp0 = cpu_last_switched[this_cpu];
-	cpu_last_switched[this_cpu] = timestamp;
+	timestamp0 = sched->cpu_last_switched[this_cpu];
+	sched->cpu_last_switched[this_cpu] = timestamp;
 	if (timestamp0)
 		delta = timestamp - timestamp0;
 	else
 		delta = 0;
 
-	if (delta < 0)
-		die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
+	if (delta < 0) {
+		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
+		return -1;
+	}
 
+	sched_out = machine__findnew_thread(machine, prev_pid);
+	sched_in = machine__findnew_thread(machine, next_pid);
 
-	sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
-	sched_in = machine__findnew_thread(machine, switch_event->next_pid);
-
-	curr_thread[this_cpu] = sched_in;
+	sched->curr_thread[this_cpu] = sched_in;
 
 	printf("  ");
 
 	new_shortname = 0;
 	if (!sched_in->shortname[0]) {
-		sched_in->shortname[0] = next_shortname1;
-		sched_in->shortname[1] = next_shortname2;
+		sched_in->shortname[0] = sched->next_shortname1;
+		sched_in->shortname[1] = sched->next_shortname2;
 
-		if (next_shortname1 < 'Z') {
-			next_shortname1++;
+		if (sched->next_shortname1 < 'Z') {
+			sched->next_shortname1++;
 		} else {
-			next_shortname1='A';
-			if (next_shortname2 < '9') {
-				next_shortname2++;
+			sched->next_shortname1='A';
+			if (sched->next_shortname2 < '9') {
+				sched->next_shortname2++;
 			} else {
-				next_shortname2='0';
+				sched->next_shortname2='0';
 			}
 		}
 		new_shortname = 1;
 	}
 
-	for (cpu = 0; cpu <= max_cpu; cpu++) {
+	for (cpu = 0; cpu <= sched->max_cpu; cpu++) {
 		if (cpu != this_cpu)
 			printf(" ");
 		else
 			printf("*");
 
-		if (curr_thread[cpu]) {
-			if (curr_thread[cpu]->pid)
-				printf("%2s ", curr_thread[cpu]->shortname);
+		if (sched->curr_thread[cpu]) {
+			if (sched->curr_thread[cpu]->pid)
+				printf("%2s ", sched->curr_thread[cpu]->shortname);
 			else
 				printf(".  ");
 		} else
@@ -1477,134 +1337,97 @@
 	} else {
 		printf("\n");
 	}
+
+	return 0;
 }
 
-static void
-process_sched_switch_event(struct perf_tool *tool __used,
-			   struct event_format *event,
-			   struct perf_sample *sample,
-			   struct machine *machine,
-			   struct thread *thread)
+static int process_sched_switch_event(struct perf_tool *tool,
+				      struct perf_evsel *evsel,
+				      struct perf_sample *sample,
+				      struct machine *machine)
 {
-	int this_cpu = sample->cpu;
-	void *data = sample->raw_data;
-	struct trace_switch_event switch_event;
+	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
+	int this_cpu = sample->cpu, err = 0;
+	u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
+	    next_pid = perf_evsel__intval(evsel, sample, "next_pid");
 
-	FILL_COMMON_FIELDS(switch_event, event, data);
-
-	FILL_ARRAY(switch_event, prev_comm, event, data);
-	FILL_FIELD(switch_event, prev_pid, event, data);
-	FILL_FIELD(switch_event, prev_prio, event, data);
-	FILL_FIELD(switch_event, prev_state, event, data);
-	FILL_ARRAY(switch_event, next_comm, event, data);
-	FILL_FIELD(switch_event, next_pid, event, data);
-	FILL_FIELD(switch_event, next_prio, event, data);
-
-	if (curr_pid[this_cpu] != (u32)-1) {
+	if (sched->curr_pid[this_cpu] != (u32)-1) {
 		/*
 		 * Are we trying to switch away a PID that is
 		 * not current?
 		 */
-		if (curr_pid[this_cpu] != switch_event.prev_pid)
-			nr_context_switch_bugs++;
+		if (sched->curr_pid[this_cpu] != prev_pid)
+			sched->nr_context_switch_bugs++;
 	}
-	if (trace_handler->switch_event)
-		trace_handler->switch_event(&switch_event, machine, event,
-					    this_cpu, sample->time, thread);
 
-	curr_pid[this_cpu] = switch_event.next_pid;
+	if (sched->tp_handler->switch_event)
+		err = sched->tp_handler->switch_event(sched, evsel, sample, machine);
+
+	sched->curr_pid[this_cpu] = next_pid;
+	return err;
 }
 
-static void
-process_sched_runtime_event(struct perf_tool *tool __used,
-			    struct event_format *event,
-			    struct perf_sample *sample,
-			    struct machine *machine,
-			    struct thread *thread)
+static int process_sched_runtime_event(struct perf_tool *tool,
+				       struct perf_evsel *evsel,
+				       struct perf_sample *sample,
+				       struct machine *machine)
 {
-	void *data = sample->raw_data;
-	struct trace_runtime_event runtime_event;
+	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
-	FILL_ARRAY(runtime_event, comm, event, data);
-	FILL_FIELD(runtime_event, pid, event, data);
-	FILL_FIELD(runtime_event, runtime, event, data);
-	FILL_FIELD(runtime_event, vruntime, event, data);
+	if (sched->tp_handler->runtime_event)
+		return sched->tp_handler->runtime_event(sched, evsel, sample, machine);
 
-	if (trace_handler->runtime_event)
-		trace_handler->runtime_event(&runtime_event, machine, event,
-					     sample->cpu, sample->time, thread);
+	return 0;
 }
 
-static void
-process_sched_fork_event(struct perf_tool *tool __used,
-			 struct event_format *event,
-			 struct perf_sample *sample,
-			 struct machine *machine __used,
-			 struct thread *thread)
+static int process_sched_fork_event(struct perf_tool *tool,
+				    struct perf_evsel *evsel,
+				    struct perf_sample *sample,
+				    struct machine *machine __maybe_unused)
 {
-	void *data = sample->raw_data;
-	struct trace_fork_event fork_event;
+	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
-	FILL_COMMON_FIELDS(fork_event, event, data);
+	if (sched->tp_handler->fork_event)
+		return sched->tp_handler->fork_event(sched, evsel, sample);
 
-	FILL_ARRAY(fork_event, parent_comm, event, data);
-	FILL_FIELD(fork_event, parent_pid, event, data);
-	FILL_ARRAY(fork_event, child_comm, event, data);
-	FILL_FIELD(fork_event, child_pid, event, data);
-
-	if (trace_handler->fork_event)
-		trace_handler->fork_event(&fork_event, event,
-					  sample->cpu, sample->time, thread);
+	return 0;
 }
 
-static void
-process_sched_exit_event(struct perf_tool *tool __used,
-			 struct event_format *event,
-			 struct perf_sample *sample __used,
-			 struct machine *machine __used,
-			 struct thread *thread __used)
+static int process_sched_exit_event(struct perf_tool *tool __maybe_unused,
+				    struct perf_evsel *evsel,
+				    struct perf_sample *sample __maybe_unused,
+				    struct machine *machine __maybe_unused)
 {
-	if (verbose)
-		printf("sched_exit event %p\n", event);
+	pr_debug("sched_exit event %p\n", evsel);
+	return 0;
 }
 
-static void
-process_sched_migrate_task_event(struct perf_tool *tool __used,
-				 struct event_format *event,
-				 struct perf_sample *sample,
-				 struct machine *machine,
-				 struct thread *thread)
+static int process_sched_migrate_task_event(struct perf_tool *tool,
+					    struct perf_evsel *evsel,
+					    struct perf_sample *sample,
+					    struct machine *machine)
 {
-	void *data = sample->raw_data;
-	struct trace_migrate_task_event migrate_task_event;
+	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
-	FILL_COMMON_FIELDS(migrate_task_event, event, data);
+	if (sched->tp_handler->migrate_task_event)
+		return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine);
 
-	FILL_ARRAY(migrate_task_event, comm, event, data);
-	FILL_FIELD(migrate_task_event, pid, event, data);
-	FILL_FIELD(migrate_task_event, prio, event, data);
-	FILL_FIELD(migrate_task_event, cpu, event, data);
-
-	if (trace_handler->migrate_task_event)
-		trace_handler->migrate_task_event(&migrate_task_event, machine,
-						  event, sample->cpu,
-						  sample->time, thread);
+	return 0;
 }
 
-typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,
-				   struct perf_sample *sample,
-				   struct machine *machine,
-				   struct thread *thread);
+typedef int (*tracepoint_handler)(struct perf_tool *tool,
+				  struct perf_evsel *evsel,
+				  struct perf_sample *sample,
+				  struct machine *machine);
 
-static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
-						 union perf_event *event __used,
+static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused,
+						 union perf_event *event __maybe_unused,
 						 struct perf_sample *sample,
 						 struct perf_evsel *evsel,
 						 struct machine *machine)
 {
-	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
-	struct pevent *pevent = sched->session->pevent;
 	struct thread *thread = machine__findnew_thread(machine, sample->pid);
+	int err = 0;
 
 	if (thread == NULL) {
 		pr_debug("problem processing %s event, skipping it.\n",
@@ -1617,30 +1440,15 @@
 
 	if (evsel->handler.func != NULL) {
 		tracepoint_handler f = evsel->handler.func;
-
-		if (evsel->handler.data == NULL)
-			evsel->handler.data = pevent_find_event(pevent,
-							  evsel->attr.config);
-
-		f(tool, evsel->handler.data, sample, machine, thread);
+		err = f(tool, evsel, sample, machine);
 	}
 
-	return 0;
+	return err;
 }
 
-static struct perf_sched perf_sched = {
-	.tool = {
-		.sample		 = perf_sched__process_tracepoint_sample,
-		.comm		 = perf_event__process_comm,
-		.lost		 = perf_event__process_lost,
-		.fork		 = perf_event__process_task,
-		.ordered_samples = true,
-	},
-};
-
-static void read_events(bool destroy, struct perf_session **psession)
+static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
+				   struct perf_session **psession)
 {
-	int err = -EINVAL;
 	const struct perf_evsel_str_handler handlers[] = {
 		{ "sched:sched_switch",	      process_sched_switch_event, },
 		{ "sched:sched_stat_runtime", process_sched_runtime_event, },
@@ -1652,24 +1460,25 @@
 	};
 	struct perf_session *session;
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false,
-				    &perf_sched.tool);
-	if (session == NULL)
-		die("No Memory");
+	session = perf_session__new(sched->input_name, O_RDONLY, 0, false, &sched->tool);
+	if (session == NULL) {
+		pr_debug("No Memory for session\n");
+		return -1;
+	}
 
-	perf_sched.session = session;
-
-	err = perf_session__set_tracepoints_handlers(session, handlers);
-	assert(err == 0);
+	if (perf_session__set_tracepoints_handlers(session, handlers))
+		goto out_delete;
 
 	if (perf_session__has_traces(session, "record -R")) {
-		err = perf_session__process_events(session, &perf_sched.tool);
-		if (err)
-			die("Failed to process events, error %d", err);
+		int err = perf_session__process_events(session, &sched->tool);
+		if (err) {
+			pr_err("Failed to process events, error %d", err);
+			goto out_delete;
+		}
 
-		nr_events      = session->hists.stats.nr_events[0];
-		nr_lost_events = session->hists.stats.total_lost;
-		nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
+		sched->nr_events      = session->hists.stats.nr_events[0];
+		sched->nr_lost_events = session->hists.stats.total_lost;
+		sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
 	}
 
 	if (destroy)
@@ -1677,208 +1486,166 @@
 
 	if (psession)
 		*psession = session;
+
+	return 0;
+
+out_delete:
+	perf_session__delete(session);
+	return -1;
 }
 
-static void print_bad_events(void)
+static void print_bad_events(struct perf_sched *sched)
 {
-	if (nr_unordered_timestamps && nr_timestamps) {
+	if (sched->nr_unordered_timestamps && sched->nr_timestamps) {
 		printf("  INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
-			(double)nr_unordered_timestamps/(double)nr_timestamps*100.0,
-			nr_unordered_timestamps, nr_timestamps);
+			(double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0,
+			sched->nr_unordered_timestamps, sched->nr_timestamps);
 	}
-	if (nr_lost_events && nr_events) {
+	if (sched->nr_lost_events && sched->nr_events) {
 		printf("  INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
-			(double)nr_lost_events/(double)nr_events*100.0,
-			nr_lost_events, nr_events, nr_lost_chunks);
+			(double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
+			sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
 	}
-	if (nr_state_machine_bugs && nr_timestamps) {
+	if (sched->nr_state_machine_bugs && sched->nr_timestamps) {
 		printf("  INFO: %.3f%% state machine bugs (%ld out of %ld)",
-			(double)nr_state_machine_bugs/(double)nr_timestamps*100.0,
-			nr_state_machine_bugs, nr_timestamps);
-		if (nr_lost_events)
+			(double)sched->nr_state_machine_bugs/(double)sched->nr_timestamps*100.0,
+			sched->nr_state_machine_bugs, sched->nr_timestamps);
+		if (sched->nr_lost_events)
 			printf(" (due to lost events?)");
 		printf("\n");
 	}
-	if (nr_context_switch_bugs && nr_timestamps) {
+	if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
 		printf("  INFO: %.3f%% context switch bugs (%ld out of %ld)",
-			(double)nr_context_switch_bugs/(double)nr_timestamps*100.0,
-			nr_context_switch_bugs, nr_timestamps);
-		if (nr_lost_events)
+			(double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
+			sched->nr_context_switch_bugs, sched->nr_timestamps);
+		if (sched->nr_lost_events)
 			printf(" (due to lost events?)");
 		printf("\n");
 	}
 }
 
-static void __cmd_lat(void)
+static int perf_sched__lat(struct perf_sched *sched)
 {
 	struct rb_node *next;
 	struct perf_session *session;
 
 	setup_pager();
-	read_events(false, &session);
-	sort_lat();
+	if (perf_sched__read_events(sched, false, &session))
+		return -1;
+	perf_sched__sort_lat(sched);
 
 	printf("\n ---------------------------------------------------------------------------------------------------------------\n");
 	printf("  Task                  |   Runtime ms  | Switches | Average delay ms | Maximum delay ms | Maximum delay at     |\n");
 	printf(" ---------------------------------------------------------------------------------------------------------------\n");
 
-	next = rb_first(&sorted_atom_root);
+	next = rb_first(&sched->sorted_atom_root);
 
 	while (next) {
 		struct work_atoms *work_list;
 
 		work_list = rb_entry(next, struct work_atoms, node);
-		output_lat_thread(work_list);
+		output_lat_thread(sched, work_list);
 		next = rb_next(next);
 	}
 
 	printf(" -----------------------------------------------------------------------------------------\n");
 	printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
-		(double)all_runtime/1e6, all_count);
+		(double)sched->all_runtime / 1e6, sched->all_count);
 
 	printf(" ---------------------------------------------------\n");
 
-	print_bad_events();
+	print_bad_events(sched);
 	printf("\n");
 
 	perf_session__delete(session);
+	return 0;
 }
 
-static struct trace_sched_handler map_ops  = {
-	.wakeup_event		= NULL,
-	.switch_event		= map_switch_event,
-	.runtime_event		= NULL,
-	.fork_event		= NULL,
-};
-
-static void __cmd_map(void)
+static int perf_sched__map(struct perf_sched *sched)
 {
-	max_cpu = sysconf(_SC_NPROCESSORS_CONF);
+	sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
 
 	setup_pager();
-	read_events(true, NULL);
-	print_bad_events();
+	if (perf_sched__read_events(sched, true, NULL))
+		return -1;
+	print_bad_events(sched);
+	return 0;
 }
 
-static void __cmd_replay(void)
+static int perf_sched__replay(struct perf_sched *sched)
 {
 	unsigned long i;
 
-	calibrate_run_measurement_overhead();
-	calibrate_sleep_measurement_overhead();
+	calibrate_run_measurement_overhead(sched);
+	calibrate_sleep_measurement_overhead(sched);
 
-	test_calibrations();
+	test_calibrations(sched);
 
-	read_events(true, NULL);
+	if (perf_sched__read_events(sched, true, NULL))
+		return -1;
 
-	printf("nr_run_events:        %ld\n", nr_run_events);
-	printf("nr_sleep_events:      %ld\n", nr_sleep_events);
-	printf("nr_wakeup_events:     %ld\n", nr_wakeup_events);
+	printf("nr_run_events:        %ld\n", sched->nr_run_events);
+	printf("nr_sleep_events:      %ld\n", sched->nr_sleep_events);
+	printf("nr_wakeup_events:     %ld\n", sched->nr_wakeup_events);
 
-	if (targetless_wakeups)
-		printf("target-less wakeups:  %ld\n", targetless_wakeups);
-	if (multitarget_wakeups)
-		printf("multi-target wakeups: %ld\n", multitarget_wakeups);
-	if (nr_run_events_optimized)
+	if (sched->targetless_wakeups)
+		printf("target-less wakeups:  %ld\n", sched->targetless_wakeups);
+	if (sched->multitarget_wakeups)
+		printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups);
+	if (sched->nr_run_events_optimized)
 		printf("run atoms optimized: %ld\n",
-			nr_run_events_optimized);
+			sched->nr_run_events_optimized);
 
-	print_task_traces();
-	add_cross_task_wakeups();
+	print_task_traces(sched);
+	add_cross_task_wakeups(sched);
 
-	create_tasks();
+	create_tasks(sched);
 	printf("------------------------------------------------------------\n");
-	for (i = 0; i < replay_repeat; i++)
-		run_one_test();
+	for (i = 0; i < sched->replay_repeat; i++)
+		run_one_test(sched);
+
+	return 0;
 }
 
-
-static const char * const sched_usage[] = {
-	"perf sched [<options>] {record|latency|map|replay|script}",
-	NULL
-};
-
-static const struct option sched_options[] = {
-	OPT_STRING('i', "input", &input_name, "file",
-		    "input file name"),
-	OPT_INCR('v', "verbose", &verbose,
-		    "be more verbose (show symbol address, etc)"),
-	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
-		    "dump raw trace in ASCII"),
-	OPT_END()
-};
-
-static const char * const latency_usage[] = {
-	"perf sched latency [<options>]",
-	NULL
-};
-
-static const struct option latency_options[] = {
-	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
-		   "sort by key(s): runtime, switch, avg, max"),
-	OPT_INCR('v', "verbose", &verbose,
-		    "be more verbose (show symbol address, etc)"),
-	OPT_INTEGER('C', "CPU", &profile_cpu,
-		    "CPU to profile on"),
-	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
-		    "dump raw trace in ASCII"),
-	OPT_END()
-};
-
-static const char * const replay_usage[] = {
-	"perf sched replay [<options>]",
-	NULL
-};
-
-static const struct option replay_options[] = {
-	OPT_UINTEGER('r', "repeat", &replay_repeat,
-		     "repeat the workload replay N times (-1: infinite)"),
-	OPT_INCR('v', "verbose", &verbose,
-		    "be more verbose (show symbol address, etc)"),
-	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
-		    "dump raw trace in ASCII"),
-	OPT_END()
-};
-
-static void setup_sorting(void)
+static void setup_sorting(struct perf_sched *sched, const struct option *options,
+			  const char * const usage_msg[])
 {
-	char *tmp, *tok, *str = strdup(sort_order);
+	char *tmp, *tok, *str = strdup(sched->sort_order);
 
 	for (tok = strtok_r(str, ", ", &tmp);
 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
-		if (sort_dimension__add(tok, &sort_list) < 0) {
+		if (sort_dimension__add(tok, &sched->sort_list) < 0) {
 			error("Unknown --sort key: `%s'", tok);
-			usage_with_options(latency_usage, latency_options);
+			usage_with_options(usage_msg, options);
 		}
 	}
 
 	free(str);
 
-	sort_dimension__add("pid", &cmp_pid);
+	sort_dimension__add("pid", &sched->cmp_pid);
 }
 
-static const char *record_args[] = {
-	"record",
-	"-a",
-	"-R",
-	"-f",
-	"-m", "1024",
-	"-c", "1",
-	"-e", "sched:sched_switch",
-	"-e", "sched:sched_stat_wait",
-	"-e", "sched:sched_stat_sleep",
-	"-e", "sched:sched_stat_iowait",
-	"-e", "sched:sched_stat_runtime",
-	"-e", "sched:sched_process_exit",
-	"-e", "sched:sched_process_fork",
-	"-e", "sched:sched_wakeup",
-	"-e", "sched:sched_migrate_task",
-};
-
 static int __cmd_record(int argc, const char **argv)
 {
 	unsigned int rec_argc, i, j;
 	const char **rec_argv;
+	const char * const record_args[] = {
+		"record",
+		"-a",
+		"-R",
+		"-f",
+		"-m", "1024",
+		"-c", "1",
+		"-e", "sched:sched_switch",
+		"-e", "sched:sched_stat_wait",
+		"-e", "sched:sched_stat_sleep",
+		"-e", "sched:sched_stat_iowait",
+		"-e", "sched:sched_stat_runtime",
+		"-e", "sched:sched_process_exit",
+		"-e", "sched:sched_process_fork",
+		"-e", "sched:sched_wakeup",
+		"-e", "sched:sched_migrate_task",
+	};
 
 	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
@@ -1897,8 +1664,85 @@
 	return cmd_record(i, rec_argv, NULL);
 }
 
-int cmd_sched(int argc, const char **argv, const char *prefix __used)
+int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
 {
+	const char default_sort_order[] = "avg, max, switch, runtime";
+	struct perf_sched sched = {
+		.tool = {
+			.sample		 = perf_sched__process_tracepoint_sample,
+			.comm		 = perf_event__process_comm,
+			.lost		 = perf_event__process_lost,
+			.fork		 = perf_event__process_task,
+			.ordered_samples = true,
+		},
+		.cmp_pid	      = LIST_HEAD_INIT(sched.cmp_pid),
+		.sort_list	      = LIST_HEAD_INIT(sched.sort_list),
+		.start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
+		.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
+		.curr_pid	      = { [0 ... MAX_CPUS - 1] = -1 },
+		.sort_order	      = default_sort_order,
+		.replay_repeat	      = 10,
+		.profile_cpu	      = -1,
+		.next_shortname1      = 'A',
+		.next_shortname2      = '0',
+	};
+	const struct option latency_options[] = {
+	OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
+		   "sort by key(s): runtime, switch, avg, max"),
+	OPT_INCR('v', "verbose", &verbose,
+		    "be more verbose (show symbol address, etc)"),
+	OPT_INTEGER('C', "CPU", &sched.profile_cpu,
+		    "CPU to profile on"),
+	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
+		    "dump raw trace in ASCII"),
+	OPT_END()
+	};
+	const struct option replay_options[] = {
+	OPT_UINTEGER('r', "repeat", &sched.replay_repeat,
+		     "repeat the workload replay N times (-1: infinite)"),
+	OPT_INCR('v', "verbose", &verbose,
+		    "be more verbose (show symbol address, etc)"),
+	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
+		    "dump raw trace in ASCII"),
+	OPT_END()
+	};
+	const struct option sched_options[] = {
+	OPT_STRING('i', "input", &sched.input_name, "file",
+		    "input file name"),
+	OPT_INCR('v', "verbose", &verbose,
+		    "be more verbose (show symbol address, etc)"),
+	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
+		    "dump raw trace in ASCII"),
+	OPT_END()
+	};
+	const char * const latency_usage[] = {
+		"perf sched latency [<options>]",
+		NULL
+	};
+	const char * const replay_usage[] = {
+		"perf sched replay [<options>]",
+		NULL
+	};
+	const char * const sched_usage[] = {
+		"perf sched [<options>] {record|latency|map|replay|script}",
+		NULL
+	};
+	struct trace_sched_handler lat_ops  = {
+		.wakeup_event	    = latency_wakeup_event,
+		.switch_event	    = latency_switch_event,
+		.runtime_event	    = latency_runtime_event,
+		.fork_event	    = latency_fork_event,
+		.migrate_task_event = latency_migrate_task_event,
+	};
+	struct trace_sched_handler map_ops  = {
+		.switch_event	    = map_switch_event,
+	};
+	struct trace_sched_handler replay_ops  = {
+		.wakeup_event	    = replay_wakeup_event,
+		.switch_event	    = replay_switch_event,
+		.fork_event	    = replay_fork_event,
+	};
+
 	argc = parse_options(argc, argv, sched_options, sched_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	if (!argc)
@@ -1914,26 +1758,26 @@
 	if (!strncmp(argv[0], "rec", 3)) {
 		return __cmd_record(argc, argv);
 	} else if (!strncmp(argv[0], "lat", 3)) {
-		trace_handler = &lat_ops;
+		sched.tp_handler = &lat_ops;
 		if (argc > 1) {
 			argc = parse_options(argc, argv, latency_options, latency_usage, 0);
 			if (argc)
 				usage_with_options(latency_usage, latency_options);
 		}
-		setup_sorting();
-		__cmd_lat();
+		setup_sorting(&sched, latency_options, latency_usage);
+		return perf_sched__lat(&sched);
 	} else if (!strcmp(argv[0], "map")) {
-		trace_handler = &map_ops;
-		setup_sorting();
-		__cmd_map();
+		sched.tp_handler = &map_ops;
+		setup_sorting(&sched, latency_options, latency_usage);
+		return perf_sched__map(&sched);
 	} else if (!strncmp(argv[0], "rep", 3)) {
-		trace_handler = &replay_ops;
+		sched.tp_handler = &replay_ops;
 		if (argc) {
 			argc = parse_options(argc, argv, replay_options, replay_usage, 0);
 			if (argc)
 				usage_with_options(replay_usage, replay_options);
 		}
-		__cmd_replay();
+		return perf_sched__replay(&sched);
 	} else {
 		usage_with_options(sched_usage, sched_options);
 	}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 1e60ab7..1be843a 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -14,6 +14,7 @@
 #include "util/util.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
+#include "util/sort.h"
 #include <linux/bitmap.h>
 
 static char const		*script_name;
@@ -28,11 +29,6 @@
 static const char		*cpu_list;
 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 
-struct perf_script {
-	struct perf_tool    tool;
-	struct perf_session *session;
-};
-
 enum perf_output_field {
 	PERF_OUTPUT_COMM            = 1U << 0,
 	PERF_OUTPUT_TID             = 1U << 1,
@@ -262,14 +258,11 @@
 	return 0;
 }
 
-static void print_sample_start(struct pevent *pevent,
-			       struct perf_sample *sample,
+static void print_sample_start(struct perf_sample *sample,
 			       struct thread *thread,
 			       struct perf_evsel *evsel)
 {
-	int type;
 	struct perf_event_attr *attr = &evsel->attr;
-	struct event_format *event;
 	const char *evname = NULL;
 	unsigned long secs;
 	unsigned long usecs;
@@ -307,20 +300,7 @@
 	}
 
 	if (PRINT_FIELD(EVNAME)) {
-		if (attr->type == PERF_TYPE_TRACEPOINT) {
-			/*
-			 * XXX Do we really need this here?
-			 * perf_evlist__set_tracepoint_names should have done
-			 * this already
-			 */
-			type = trace_parse_common_type(pevent,
-						       sample->raw_data);
-			event = pevent_find_event(pevent, type);
-			if (event)
-				evname = event->name;
-		} else
-			evname = perf_evsel__name(evsel);
-
+		evname = perf_evsel__name(evsel);
 		printf("%s: ", evname ? evname : "[unknown]");
 	}
 }
@@ -401,7 +381,7 @@
 			printf(" ");
 		else
 			printf("\n");
-		perf_event__print_ip(event, sample, machine,
+		perf_evsel__print_ip(evsel, event, sample, machine,
 				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
 				     PRINT_FIELD(SYMOFFSET));
 	}
@@ -415,19 +395,17 @@
 	printf("\n");
 }
 
-static void process_event(union perf_event *event __unused,
-			  struct pevent *pevent,
-			  struct perf_sample *sample,
-			  struct perf_evsel *evsel,
-			  struct machine *machine,
-			  struct thread *thread)
+static void process_event(union perf_event *event, struct perf_sample *sample,
+			  struct perf_evsel *evsel, struct machine *machine,
+			  struct addr_location *al)
 {
 	struct perf_event_attr *attr = &evsel->attr;
+	struct thread *thread = al->thread;
 
 	if (output[attr->type].fields == 0)
 		return;
 
-	print_sample_start(pevent, sample, thread, evsel);
+	print_sample_start(sample, thread, evsel);
 
 	if (is_bts_event(attr)) {
 		print_sample_bts(event, sample, evsel, machine, thread);
@@ -435,9 +413,8 @@
 	}
 
 	if (PRINT_FIELD(TRACE))
-		print_trace_event(pevent, sample->cpu, sample->raw_data,
-				  sample->raw_size);
-
+		event_format__print(evsel->tp_format, sample->cpu,
+				    sample->raw_data, sample->raw_size);
 	if (PRINT_FIELD(ADDR))
 		print_sample_addr(event, sample, machine, thread, attr);
 
@@ -446,7 +423,7 @@
 			printf(" ");
 		else
 			printf("\n");
-		perf_event__print_ip(event, sample, machine,
+		perf_evsel__print_ip(evsel, event, sample, machine,
 				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
 				     PRINT_FIELD(SYMOFFSET));
 	}
@@ -454,9 +431,9 @@
 	printf("\n");
 }
 
-static int default_start_script(const char *script __unused,
-				int argc __unused,
-				const char **argv __unused)
+static int default_start_script(const char *script __maybe_unused,
+				int argc __maybe_unused,
+				const char **argv __maybe_unused)
 {
 	return 0;
 }
@@ -466,8 +443,8 @@
 	return 0;
 }
 
-static int default_generate_script(struct pevent *pevent __unused,
-				   const char *outfile __unused)
+static int default_generate_script(struct pevent *pevent __maybe_unused,
+				   const char *outfile __maybe_unused)
 {
 	return 0;
 }
@@ -498,14 +475,13 @@
 
 static const char *input_name;
 
-static int process_sample_event(struct perf_tool *tool __used,
+static int process_sample_event(struct perf_tool *tool __maybe_unused,
 				union perf_event *event,
 				struct perf_sample *sample,
 				struct perf_evsel *evsel,
 				struct machine *machine)
 {
 	struct addr_location al;
-	struct perf_script *scr = container_of(tool, struct perf_script, tool);
 	struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
 
 	if (thread == NULL) {
@@ -537,32 +513,29 @@
 	if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
 		return 0;
 
-	scripting_ops->process_event(event, scr->session->pevent,
-				     sample, evsel, machine, thread);
+	scripting_ops->process_event(event, sample, evsel, machine, &al);
 
 	evsel->hists.stats.total_period += sample->period;
 	return 0;
 }
 
-static struct perf_script perf_script = {
-	.tool = {
-		.sample		 = process_sample_event,
-		.mmap		 = perf_event__process_mmap,
-		.comm		 = perf_event__process_comm,
-		.exit		 = perf_event__process_task,
-		.fork		 = perf_event__process_task,
-		.attr		 = perf_event__process_attr,
-		.event_type	 = perf_event__process_event_type,
-		.tracing_data	 = perf_event__process_tracing_data,
-		.build_id	 = perf_event__process_build_id,
-		.ordered_samples = true,
-		.ordering_requires_timestamps = true,
-	},
+static struct perf_tool perf_script = {
+	.sample		 = process_sample_event,
+	.mmap		 = perf_event__process_mmap,
+	.comm		 = perf_event__process_comm,
+	.exit		 = perf_event__process_task,
+	.fork		 = perf_event__process_task,
+	.attr		 = perf_event__process_attr,
+	.event_type	 = perf_event__process_event_type,
+	.tracing_data	 = perf_event__process_tracing_data,
+	.build_id	 = perf_event__process_build_id,
+	.ordered_samples = true,
+	.ordering_requires_timestamps = true,
 };
 
 extern volatile int session_done;
 
-static void sig_handler(int sig __unused)
+static void sig_handler(int sig __maybe_unused)
 {
 	session_done = 1;
 }
@@ -573,7 +546,7 @@
 
 	signal(SIGINT, sig_handler);
 
-	ret = perf_session__process_events(session, &perf_script.tool);
+	ret = perf_session__process_events(session, &perf_script);
 
 	if (debug_mode)
 		pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -672,8 +645,8 @@
 	fprintf(stderr, "\n");
 }
 
-static int parse_scriptname(const struct option *opt __used,
-			    const char *str, int unset __used)
+static int parse_scriptname(const struct option *opt __maybe_unused,
+			    const char *str, int unset __maybe_unused)
 {
 	char spec[PATH_MAX];
 	const char *script, *ext;
@@ -718,8 +691,8 @@
 	return 0;
 }
 
-static int parse_output_fields(const struct option *opt __used,
-			    const char *arg, int unset __used)
+static int parse_output_fields(const struct option *opt __maybe_unused,
+			    const char *arg, int unset __maybe_unused)
 {
 	char *tok;
 	int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
@@ -1010,8 +983,9 @@
 	return script_root;
 }
 
-static int list_available_scripts(const struct option *opt __used,
-				  const char *s __used, int unset __used)
+static int list_available_scripts(const struct option *opt __maybe_unused,
+				  const char *s __maybe_unused,
+				  int unset __maybe_unused)
 {
 	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
 	char scripts_path[MAXPATHLEN];
@@ -1058,6 +1032,61 @@
 	exit(0);
 }
 
+/*
+ * Return -1 if none is found, otherwise the actual scripts number.
+ *
+ * Currently the only user of this function is the script browser, which
+ * will list all statically runnable scripts, select one, execute it and
+ * show the output in a perf browser.
+ */
+int find_scripts(char **scripts_array, char **scripts_path_array)
+{
+	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
+	char scripts_path[MAXPATHLEN];
+	DIR *scripts_dir, *lang_dir;
+	char lang_path[MAXPATHLEN];
+	char *temp;
+	int i = 0;
+
+	snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+
+	scripts_dir = opendir(scripts_path);
+	if (!scripts_dir)
+		return -1;
+
+	for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
+		snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
+			 lang_dirent.d_name);
+#ifdef NO_LIBPERL
+		if (strstr(lang_path, "perl"))
+			continue;
+#endif
+#ifdef NO_LIBPYTHON
+		if (strstr(lang_path, "python"))
+			continue;
+#endif
+
+		lang_dir = opendir(lang_path);
+		if (!lang_dir)
+			continue;
+
+		for_each_script(lang_path, lang_dir, script_dirent, script_next) {
+			/* Skip those real time scripts: xxxtop.p[yl] */
+			if (strstr(script_dirent.d_name, "top."))
+				continue;
+			sprintf(scripts_path_array[i], "%s/%s", lang_path,
+				script_dirent.d_name);
+			temp = strchr(script_dirent.d_name, '.');
+			snprintf(scripts_array[i],
+				(temp - script_dirent.d_name) + 1,
+				"%s", script_dirent.d_name);
+			i++;
+		}
+	}
+
+	return i;
+}
+
 static char *get_script_path(const char *script_root, const char *suffix)
 {
 	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
@@ -1170,6 +1199,8 @@
 		     parse_output_fields),
 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
 		     "system-wide collection from all CPUs"),
+	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
+		   "only consider these symbols"),
 	OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
 	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
 		   "only display events for these comms"),
@@ -1181,21 +1212,26 @@
 	OPT_END()
 };
 
-static bool have_cmd(int argc, const char **argv)
+static int have_cmd(int argc, const char **argv)
 {
 	char **__argv = malloc(sizeof(const char *) * argc);
 
-	if (!__argv)
-		die("malloc");
+	if (!__argv) {
+		pr_err("malloc failed\n");
+		return -1;
+	}
+
 	memcpy(__argv, argv, sizeof(const char *) * argc);
 	argc = parse_options(argc, (const char **)__argv, record_options,
 			     NULL, PARSE_OPT_STOP_AT_NON_OPTION);
 	free(__argv);
 
-	return argc != 0;
+	system_wide = (argc == 0);
+
+	return 0;
 }
 
-int cmd_script(int argc, const char **argv, const char *prefix __used)
+int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	char *rec_script_path = NULL;
 	char *rep_script_path = NULL;
@@ -1259,13 +1295,13 @@
 
 		if (pipe(live_pipe) < 0) {
 			perror("failed to create pipe");
-			exit(-1);
+			return -1;
 		}
 
 		pid = fork();
 		if (pid < 0) {
 			perror("failed to fork");
-			exit(-1);
+			return -1;
 		}
 
 		if (!pid) {
@@ -1277,13 +1313,18 @@
 			if (is_top_script(argv[0])) {
 				system_wide = true;
 			} else if (!system_wide) {
-				system_wide = !have_cmd(argc - rep_args,
-							&argv[rep_args]);
+				if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) {
+					err = -1;
+					goto out;
+				}
 			}
 
 			__argv = malloc((argc + 6) * sizeof(const char *));
-			if (!__argv)
-				die("malloc");
+			if (!__argv) {
+				pr_err("malloc failed\n");
+				err = -ENOMEM;
+				goto out;
+			}
 
 			__argv[j++] = "/bin/sh";
 			__argv[j++] = rec_script_path;
@@ -1305,8 +1346,12 @@
 		close(live_pipe[1]);
 
 		__argv = malloc((argc + 4) * sizeof(const char *));
-		if (!__argv)
-			die("malloc");
+		if (!__argv) {
+			pr_err("malloc failed\n");
+			err = -ENOMEM;
+			goto out;
+		}
+
 		j = 0;
 		__argv[j++] = "/bin/sh";
 		__argv[j++] = rep_script_path;
@@ -1331,12 +1376,20 @@
 
 		if (!rec_script_path)
 			system_wide = false;
-		else if (!system_wide)
-			system_wide = !have_cmd(argc - 1, &argv[1]);
+		else if (!system_wide) {
+			if (have_cmd(argc - 1, &argv[1]) != 0) {
+				err = -1;
+				goto out;
+			}
+		}
 
 		__argv = malloc((argc + 2) * sizeof(const char *));
-		if (!__argv)
-			die("malloc");
+		if (!__argv) {
+			pr_err("malloc failed\n");
+			err = -ENOMEM;
+			goto out;
+		}
+
 		__argv[j++] = "/bin/sh";
 		__argv[j++] = script_path;
 		if (system_wide)
@@ -1356,12 +1409,10 @@
 		setup_pager();
 
 	session = perf_session__new(input_name, O_RDONLY, 0, false,
-				    &perf_script.tool);
+				    &perf_script);
 	if (session == NULL)
 		return -ENOMEM;
 
-	perf_script.session = session;
-
 	if (cpu_list) {
 		if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
 			return -1;
@@ -1387,18 +1438,18 @@
 		input = open(session->filename, O_RDONLY);	/* input_name */
 		if (input < 0) {
 			perror("failed to open file");
-			exit(-1);
+			return -1;
 		}
 
 		err = fstat(input, &perf_stat);
 		if (err < 0) {
 			perror("failed to stat file");
-			exit(-1);
+			return -1;
 		}
 
 		if (!perf_stat.st_size) {
 			fprintf(stderr, "zero-sized file, nothing to do!\n");
-			exit(0);
+			return 0;
 		}
 
 		scripting_ops = script_spec__lookup(generate_script_lang);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 861f0ae..e8cd4d8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -51,13 +51,13 @@
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/color.h"
+#include "util/stat.h"
 #include "util/header.h"
 #include "util/cpumap.h"
 #include "util/thread.h"
 #include "util/thread_map.h"
 
 #include <sys/prctl.h>
-#include <math.h>
 #include <locale.h>
 
 #define DEFAULT_SEPARATOR	" "
@@ -199,11 +199,6 @@
 
 static volatile int done = 0;
 
-struct stats
-{
-	double n, mean, M2;
-};
-
 struct perf_stat {
 	struct stats	  res_stats[3];
 };
@@ -220,48 +215,14 @@
 	evsel->priv = NULL;
 }
 
-static void update_stats(struct stats *stats, u64 val)
+static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
 {
-	double delta;
-
-	stats->n++;
-	delta = val - stats->mean;
-	stats->mean += delta / stats->n;
-	stats->M2 += delta*(val - stats->mean);
+	return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
 }
 
-static double avg_stats(struct stats *stats)
+static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
 {
-	return stats->mean;
-}
-
-/*
- * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
- *
- *       (\Sum n_i^2) - ((\Sum n_i)^2)/n
- * s^2 = -------------------------------
- *                  n - 1
- *
- * http://en.wikipedia.org/wiki/Stddev
- *
- * The std dev of the mean is related to the std dev by:
- *
- *             s
- * s_mean = -------
- *          sqrt(n)
- *
- */
-static double stddev_stats(struct stats *stats)
-{
-	double variance, variance_mean;
-
-	if (!stats->n)
-		return 0.0;
-
-	variance = stats->M2 / (stats->n - 1);
-	variance_mean = variance / stats->n;
-
-	return sqrt(variance_mean);
+	return perf_evsel__cpus(evsel)->nr;
 }
 
 static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
@@ -281,13 +242,9 @@
 				    struct perf_evsel *first)
 {
 	struct perf_event_attr *attr = &evsel->attr;
-	struct xyarray *group_fd = NULL;
 	bool exclude_guest_missing = false;
 	int ret;
 
-	if (group && evsel != first)
-		group_fd = first->fd;
-
 	if (scale)
 		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
 				    PERF_FORMAT_TOTAL_TIME_RUNNING;
@@ -299,8 +256,7 @@
 		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
 
 	if (perf_target__has_cpu(&target)) {
-		ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
-					       group, group_fd);
+		ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
 		if (ret)
 			goto check_ret;
 		return 0;
@@ -311,8 +267,7 @@
 		attr->enable_on_exec = 1;
 	}
 
-	ret = perf_evsel__open_per_thread(evsel, evsel_list->threads,
-					  group, group_fd);
+	ret = perf_evsel__open_per_thread(evsel, evsel_list->threads);
 	if (!ret)
 		return 0;
 	/* fall through */
@@ -382,7 +337,7 @@
 	u64 *count = counter->counts->aggr.values;
 	int i;
 
-	if (__perf_evsel__read(counter, evsel_list->cpus->nr,
+	if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
 			       evsel_list->threads->nr, scale) < 0)
 		return -1;
 
@@ -411,7 +366,7 @@
 	u64 *count;
 	int cpu;
 
-	for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
+	for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
 		if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
 			return -1;
 
@@ -423,7 +378,7 @@
 	return 0;
 }
 
-static int run_perf_stat(int argc __used, const char **argv)
+static int run_perf_stat(int argc __maybe_unused, const char **argv)
 {
 	unsigned long long t0, t1;
 	struct perf_evsel *counter, *first;
@@ -434,7 +389,7 @@
 
 	if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
 		perror("failed to create pipes");
-		exit(1);
+		return -1;
 	}
 
 	if (forks) {
@@ -483,7 +438,10 @@
 		close(child_ready_pipe[0]);
 	}
 
-	first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
+	if (group)
+		perf_evlist__set_leader(evsel_list);
+
+	first = perf_evlist__first(evsel_list);
 
 	list_for_each_entry(counter, &evsel_list->entries, node) {
 		if (create_perf_stat_counter(counter, first) < 0) {
@@ -513,13 +471,14 @@
 			}
 			if (child_pid != -1)
 				kill(child_pid, SIGTERM);
-			die("Not all events could be opened.\n");
+
+			pr_err("Not all events could be opened.\n");
 			return -1;
 		}
 		counter->supported = true;
 	}
 
-	if (perf_evlist__set_filters(evsel_list)) {
+	if (perf_evlist__apply_filters(evsel_list)) {
 		error("failed to set filter with %d (%s)\n", errno,
 			strerror(errno));
 		return -1;
@@ -546,12 +505,12 @@
 	if (no_aggr) {
 		list_for_each_entry(counter, &evsel_list->entries, node) {
 			read_counter(counter);
-			perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
+			perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
 		}
 	} else {
 		list_for_each_entry(counter, &evsel_list->entries, node) {
 			read_counter_aggr(counter);
-			perf_evsel__close_fd(counter, evsel_list->cpus->nr,
+			perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
 					     evsel_list->threads->nr);
 		}
 	}
@@ -561,10 +520,7 @@
 
 static void print_noise_pct(double total, double avg)
 {
-	double pct = 0.0;
-
-	if (avg)
-		pct = 100.0*total/avg;
+	double pct = rel_stddev_stats(total, avg);
 
 	if (csv_output)
 		fprintf(output, "%s%.2f%%", csv_sep, pct);
@@ -592,7 +548,7 @@
 	if (no_aggr)
 		sprintf(cpustr, "CPU%*d%s",
 			csv_output ? 0 : -4,
-			evsel_list->cpus->map[cpu], csv_sep);
+			perf_evsel__cpus(evsel)->map[cpu], csv_sep);
 
 	fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
 
@@ -636,7 +592,9 @@
 	return color;
 }
 
-static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_stalled_cycles_frontend(int cpu,
+					  struct perf_evsel *evsel
+					  __maybe_unused, double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -653,7 +611,9 @@
 	fprintf(output, " frontend cycles idle   ");
 }
 
-static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_stalled_cycles_backend(int cpu,
+					 struct perf_evsel *evsel
+					 __maybe_unused, double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -670,7 +630,9 @@
 	fprintf(output, " backend  cycles idle   ");
 }
 
-static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_branch_misses(int cpu,
+				struct perf_evsel *evsel __maybe_unused,
+				double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -687,7 +649,9 @@
 	fprintf(output, " of all branches        ");
 }
 
-static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_l1_dcache_misses(int cpu,
+				   struct perf_evsel *evsel __maybe_unused,
+				   double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -704,7 +668,9 @@
 	fprintf(output, " of all L1-dcache hits  ");
 }
 
-static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_l1_icache_misses(int cpu,
+				   struct perf_evsel *evsel __maybe_unused,
+				   double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -721,7 +687,9 @@
 	fprintf(output, " of all L1-icache hits  ");
 }
 
-static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_dtlb_cache_misses(int cpu,
+				    struct perf_evsel *evsel __maybe_unused,
+				    double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -738,7 +706,9 @@
 	fprintf(output, " of all dTLB cache hits ");
 }
 
-static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_itlb_cache_misses(int cpu,
+				    struct perf_evsel *evsel __maybe_unused,
+				    double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -755,7 +725,9 @@
 	fprintf(output, " of all iTLB cache hits ");
 }
 
-static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
+static void print_ll_cache_misses(int cpu,
+				  struct perf_evsel *evsel __maybe_unused,
+				  double avg)
 {
 	double total, ratio = 0.0;
 	const char *color;
@@ -788,7 +760,7 @@
 	if (no_aggr)
 		sprintf(cpustr, "CPU%*d%s",
 			csv_output ? 0 : -4,
-			evsel_list->cpus->map[cpu], csv_sep);
+			perf_evsel__cpus(evsel)->map[cpu], csv_sep);
 	else
 		cpu = 0;
 
@@ -949,14 +921,14 @@
 	u64 ena, run, val;
 	int cpu;
 
-	for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
+	for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
 		val = counter->counts->cpu[cpu].val;
 		ena = counter->counts->cpu[cpu].ena;
 		run = counter->counts->cpu[cpu].run;
 		if (run == 0 || ena == 0) {
 			fprintf(output, "CPU%*d%s%*s%s%*s",
 				csv_output ? 0 : -4,
-				evsel_list->cpus->map[cpu], csv_sep,
+				perf_evsel__cpus(counter)->map[cpu], csv_sep,
 				csv_output ? 0 : 18,
 				counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 				csv_sep,
@@ -1061,8 +1033,8 @@
 	NULL
 };
 
-static int stat__set_big_num(const struct option *opt __used,
-			     const char *s __used, int unset)
+static int stat__set_big_num(const struct option *opt __maybe_unused,
+			     const char *s __maybe_unused, int unset)
 {
 	big_num_opt = unset ? 0 : 1;
 	return 0;
@@ -1156,7 +1128,7 @@
 	return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
 }
 
-int cmd_stat(int argc, const char **argv, const char *prefix __used)
+int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_evsel *pos;
 	int status = -ENOMEM;
@@ -1192,7 +1164,7 @@
 		output = fopen(output_name, mode);
 		if (!output) {
 			perror("failed to create output file");
-			exit(-1);
+			return -1;
 		}
 		clock_gettime(CLOCK_REALTIME, &tm);
 		fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
@@ -1255,7 +1227,7 @@
 
 	list_for_each_entry(pos, &evsel_list->entries, node) {
 		if (perf_evsel__alloc_stat_priv(pos) < 0 ||
-		    perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
+		    perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
 			goto out_free_fd;
 	}
 
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1d592f5..484f26c 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -14,11 +14,13 @@
 #include "util/symbol.h"
 #include "util/thread_map.h"
 #include "util/pmu.h"
+#include "event-parse.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 #include <sys/mman.h>
 
-static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
+static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
+					   struct symbol *sym)
 {
 	bool *visited = symbol__priv(sym);
 	*visited = true;
@@ -294,7 +296,7 @@
 		goto out_thread_map_delete;
 	}
 
-	if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
+	if (perf_evsel__open_per_thread(evsel, threads) < 0) {
 		pr_debug("failed to open counter: %s, "
 			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 			 strerror(errno));
@@ -369,7 +371,7 @@
 		goto out_thread_map_delete;
 	}
 
-	if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
+	if (perf_evsel__open(evsel, cpus, threads) < 0) {
 		pr_debug("failed to open counter: %s, "
 			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 			 strerror(errno));
@@ -533,7 +535,7 @@
 
 		perf_evlist__add(evlist, evsels[i]);
 
-		if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
+		if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
 			pr_debug("failed to open counter: %s, "
 				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 				 strerror(errno));
@@ -562,7 +564,7 @@
 			goto out_munmap;
 		}
 
-		err = perf_evlist__parse_sample(evlist, event, &sample, false);
+		err = perf_evlist__parse_sample(evlist, event, &sample);
 		if (err) {
 			pr_err("Can't parse sample, err = %d\n", err);
 			goto out_munmap;
@@ -710,7 +712,7 @@
 	/*
 	 * Config the evsels, setting attr->comm on the first one, etc.
 	 */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	evsel = perf_evlist__first(evlist);
 	evsel->attr.sample_type |= PERF_SAMPLE_CPU;
 	evsel->attr.sample_type |= PERF_SAMPLE_TID;
 	evsel->attr.sample_type |= PERF_SAMPLE_TIME;
@@ -737,7 +739,7 @@
 	 * Call sys_perf_event_open on all the fds on all the evsels,
 	 * grouping them if asked to.
 	 */
-	err = perf_evlist__open(evlist, opts.group);
+	err = perf_evlist__open(evlist);
 	if (err < 0) {
 		pr_debug("perf_evlist__open: %s\n", strerror(errno));
 		goto out_delete_evlist;
@@ -779,7 +781,7 @@
 				if (type < PERF_RECORD_MAX)
 					nr_events[type]++;
 
-				err = perf_evlist__parse_sample(evlist, event, &sample, false);
+				err = perf_evlist__parse_sample(evlist, event, &sample);
 				if (err < 0) {
 					if (verbose)
 						perf_event__fprintf(event, stderr);
@@ -996,7 +998,9 @@
 /*
  * If the RDPMC instruction faults then signal this back to the test parent task:
  */
-static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used)
+static void segfault_handler(int sig __maybe_unused,
+			     siginfo_t *info __maybe_unused,
+			     void *uc __maybe_unused)
 {
 	exit(-1);
 }
@@ -1023,14 +1027,16 @@
 
 	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 	if (fd < 0) {
-		die("Error: sys_perf_event_open() syscall returned "
-		    "with %d (%s)\n", fd, strerror(errno));
+		pr_err("Error: sys_perf_event_open() syscall returned "
+		       "with %d (%s)\n", fd, strerror(errno));
+		return -1;
 	}
 
 	addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
 	if (addr == (void *)(-1)) {
-		die("Error: mmap() syscall returned "
-		    "with (%s)\n", strerror(errno));
+		pr_err("Error: mmap() syscall returned with (%s)\n",
+		       strerror(errno));
+		goto out_close;
 	}
 
 	for (n = 0; n < 6; n++) {
@@ -1051,9 +1057,9 @@
 	}
 
 	munmap(addr, page_size);
-	close(fd);
-
 	pr_debug("   ");
+out_close:
+	close(fd);
 
 	if (!delta_sum)
 		return -1;
@@ -1092,6 +1098,309 @@
 	return perf_pmu__test();
 }
 
+static int perf_evsel__roundtrip_cache_name_test(void)
+{
+	char name[128];
+	int type, op, err = 0, ret = 0, i, idx;
+	struct perf_evsel *evsel;
+        struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+
+        if (evlist == NULL)
+                return -ENOMEM;
+
+	for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+		for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+			/* skip invalid cache type */
+			if (!perf_evsel__is_cache_op_valid(type, op))
+				continue;
+
+			for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+				__perf_evsel__hw_cache_type_op_res_name(type, op, i,
+									name, sizeof(name));
+				err = parse_events(evlist, name, 0);
+				if (err)
+					ret = err;
+			}
+		}
+	}
+
+	idx = 0;
+	evsel = perf_evlist__first(evlist);
+
+	for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+		for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+			/* skip invalid cache type */
+			if (!perf_evsel__is_cache_op_valid(type, op))
+				continue;
+
+			for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+				__perf_evsel__hw_cache_type_op_res_name(type, op, i,
+									name, sizeof(name));
+				if (evsel->idx != idx)
+					continue;
+
+				++idx;
+
+				if (strcmp(perf_evsel__name(evsel), name)) {
+					pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
+					ret = -1;
+				}
+
+				evsel = perf_evsel__next(evsel);
+			}
+		}
+	}
+
+	perf_evlist__delete(evlist);
+	return ret;
+}
+
+static int __perf_evsel__name_array_test(const char *names[], int nr_names)
+{
+	int i, err;
+	struct perf_evsel *evsel;
+        struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+
+        if (evlist == NULL)
+                return -ENOMEM;
+
+	for (i = 0; i < nr_names; ++i) {
+		err = parse_events(evlist, names[i], 0);
+		if (err) {
+			pr_debug("failed to parse event '%s', err %d\n",
+				 names[i], err);
+			goto out_delete_evlist;
+		}
+	}
+
+	err = 0;
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
+			--err;
+			pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
+		}
+	}
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	return err;
+}
+
+#define perf_evsel__name_array_test(names) \
+	__perf_evsel__name_array_test(names, ARRAY_SIZE(names))
+
+static int perf_evsel__roundtrip_name_test(void)
+{
+	int err = 0, ret = 0;
+
+	err = perf_evsel__name_array_test(perf_evsel__hw_names);
+	if (err)
+		ret = err;
+
+	err = perf_evsel__name_array_test(perf_evsel__sw_names);
+	if (err)
+		ret = err;
+
+	err = perf_evsel__roundtrip_cache_name_test();
+	if (err)
+		ret = err;
+
+	return ret;
+}
+
+static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
+				  int size, bool should_be_signed)
+{
+	struct format_field *field = perf_evsel__field(evsel, name);
+	int is_signed;
+	int ret = 0;
+
+	if (field == NULL) {
+		pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
+		return -1;
+	}
+
+	is_signed = !!(field->flags | FIELD_IS_SIGNED);
+	if (should_be_signed && !is_signed) {
+		pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
+			 evsel->name, name, is_signed, should_be_signed);
+		ret = -1;
+	}
+
+	if (field->size != size) {
+		pr_debug("%s: \"%s\" size (%d) should be %d!\n",
+			 evsel->name, name, field->size, size);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int perf_evsel__tp_sched_test(void)
+{
+	struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
+	int ret = 0;
+
+	if (evsel == NULL) {
+		pr_debug("perf_evsel__new\n");
+		return -1;
+	}
+
+	if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "prev_state", 8, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "next_comm", 16, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "next_pid", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "next_prio", 4, true))
+		ret = -1;
+
+	perf_evsel__delete(evsel);
+
+	evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
+
+	if (perf_evsel__test_field(evsel, "comm", 16, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "pid", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "prio", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "success", 4, true))
+		ret = -1;
+
+	if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
+		ret = -1;
+
+	return ret;
+}
+
+static int test__syscall_open_tp_fields(void)
+{
+	struct perf_record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
+		.no_delay   = true,
+		.freq	    = 1,
+		.mmap_pages = 256,
+		.raw_samples = true,
+	};
+	const char *filename = "/etc/passwd";
+	int flags = O_RDONLY | O_DIRECTORY;
+	struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+	struct perf_evsel *evsel;
+	int err = -1, i, nr_events = 0, nr_polls = 0;
+
+	if (evlist == NULL) {
+		pr_debug("%s: perf_evlist__new\n", __func__);
+		goto out;
+	}
+
+	evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
+	if (evsel == NULL) {
+		pr_debug("%s: perf_evsel__newtp\n", __func__);
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__add(evlist, evsel);
+
+	err = perf_evlist__create_maps(evlist, &opts.target);
+	if (err < 0) {
+		pr_debug("%s: perf_evlist__create_maps\n", __func__);
+		goto out_delete_evlist;
+	}
+
+	perf_evsel__config(evsel, &opts, evsel);
+
+	evlist->threads->map[0] = getpid();
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		pr_debug("perf_evlist__open: %s\n", strerror(errno));
+		goto out_delete_evlist;
+	}
+
+	err = perf_evlist__mmap(evlist, UINT_MAX, false);
+	if (err < 0) {
+		pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__enable(evlist);
+
+	/*
+ 	 * Generate the event:
+ 	 */
+	open(filename, flags);
+
+	while (1) {
+		int before = nr_events;
+
+		for (i = 0; i < evlist->nr_mmaps; i++) {
+			union perf_event *event;
+
+			while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+				const u32 type = event->header.type;
+				int tp_flags;
+				struct perf_sample sample;
+
+				++nr_events;
+
+				if (type != PERF_RECORD_SAMPLE)
+					continue;
+
+				err = perf_evsel__parse_sample(evsel, event, &sample);
+				if (err) {
+					pr_err("Can't parse sample, err = %d\n", err);
+					goto out_munmap;
+				}
+
+				tp_flags = perf_evsel__intval(evsel, &sample, "flags");
+
+				if (flags != tp_flags) {
+					pr_debug("%s: Expected flags=%#x, got %#x\n",
+						 __func__, flags, tp_flags);
+					goto out_munmap;
+				}
+
+				goto out_ok;
+			}
+		}
+
+		if (nr_events == before)
+			poll(evlist->pollfd, evlist->nr_fds, 10);
+
+		if (++nr_polls > 5) {
+			pr_debug("%s: no events!\n", __func__);
+			goto out_munmap;
+		}
+	}
+out_ok:
+	err = 0;
+out_munmap:
+	perf_evlist__munmap(evlist);
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+out:
+	return err;
+}
+
 static struct test {
 	const char *desc;
 	int (*func)(void);
@@ -1135,6 +1444,18 @@
 		.func = dso__test_data,
 	},
 	{
+		.desc = "roundtrip evsel->name check",
+		.func = perf_evsel__roundtrip_name_test,
+	},
+	{
+		.desc = "Check parsing of sched tracepoints fields",
+		.func = perf_evsel__tp_sched_test,
+	},
+	{
+		.desc = "Generate and check syscalls:sys_enter_open event fields",
+		.func = test__syscall_open_tp_fields,
+	},
+	{
 		.func = NULL,
 	},
 };
@@ -1199,7 +1520,7 @@
 	return 0;
 }
 
-int cmd_test(int argc, const char **argv, const char *prefix __used)
+int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	const char * const test_usage[] = {
 	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3b75b2e..b1a8a3b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -168,9 +168,8 @@
 			return cursor;
 		cursor = cursor->next;
 	}
-	cursor = malloc(sizeof(struct per_pid));
+	cursor = zalloc(sizeof(*cursor));
 	assert(cursor != NULL);
-	memset(cursor, 0, sizeof(struct per_pid));
 	cursor->pid = pid;
 	cursor->next = all_data;
 	all_data = cursor;
@@ -195,9 +194,8 @@
 		}
 		c = c->next;
 	}
-	c = malloc(sizeof(struct per_pidcomm));
+	c = zalloc(sizeof(*c));
 	assert(c != NULL);
-	memset(c, 0, sizeof(struct per_pidcomm));
 	c->comm = strdup(comm);
 	p->current = c;
 	c->next = p->all;
@@ -239,17 +237,15 @@
 	p = find_create_pid(pid);
 	c = p->current;
 	if (!c) {
-		c = malloc(sizeof(struct per_pidcomm));
+		c = zalloc(sizeof(*c));
 		assert(c != NULL);
-		memset(c, 0, sizeof(struct per_pidcomm));
 		p->current = c;
 		c->next = p->all;
 		p->all = c;
 	}
 
-	sample = malloc(sizeof(struct cpu_sample));
+	sample = zalloc(sizeof(*sample));
 	assert(sample != NULL);
-	memset(sample, 0, sizeof(struct cpu_sample));
 	sample->start_time = start;
 	sample->end_time = end;
 	sample->type = type;
@@ -275,28 +271,28 @@
 static u64 cpus_pstate_start_times[MAX_CPUS];
 static u64 cpus_pstate_state[MAX_CPUS];
 
-static int process_comm_event(struct perf_tool *tool __used,
+static int process_comm_event(struct perf_tool *tool __maybe_unused,
 			      union perf_event *event,
-			      struct perf_sample *sample __used,
-			      struct machine *machine __used)
+			      struct perf_sample *sample __maybe_unused,
+			      struct machine *machine __maybe_unused)
 {
 	pid_set_comm(event->comm.tid, event->comm.comm);
 	return 0;
 }
 
-static int process_fork_event(struct perf_tool *tool __used,
+static int process_fork_event(struct perf_tool *tool __maybe_unused,
 			      union perf_event *event,
-			      struct perf_sample *sample __used,
-			      struct machine *machine __used)
+			      struct perf_sample *sample __maybe_unused,
+			      struct machine *machine __maybe_unused)
 {
 	pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
 	return 0;
 }
 
-static int process_exit_event(struct perf_tool *tool __used,
+static int process_exit_event(struct perf_tool *tool __maybe_unused,
 			      union perf_event *event,
-			      struct perf_sample *sample __used,
-			      struct machine *machine __used)
+			      struct perf_sample *sample __maybe_unused,
+			      struct machine *machine __maybe_unused)
 {
 	pid_exit(event->fork.pid, event->fork.time);
 	return 0;
@@ -373,11 +369,10 @@
 
 static void c_state_end(int cpu, u64 timestamp)
 {
-	struct power_event *pwr;
-	pwr = malloc(sizeof(struct power_event));
+	struct power_event *pwr = zalloc(sizeof(*pwr));
+
 	if (!pwr)
 		return;
-	memset(pwr, 0, sizeof(struct power_event));
 
 	pwr->state = cpus_cstate_state[cpu];
 	pwr->start_time = cpus_cstate_start_times[cpu];
@@ -392,14 +387,13 @@
 static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
 {
 	struct power_event *pwr;
-	pwr = malloc(sizeof(struct power_event));
 
 	if (new_freq > 8000000) /* detect invalid data */
 		return;
 
+	pwr = zalloc(sizeof(*pwr));
 	if (!pwr)
 		return;
-	memset(pwr, 0, sizeof(struct power_event));
 
 	pwr->state = cpus_pstate_state[cpu];
 	pwr->start_time = cpus_pstate_start_times[cpu];
@@ -429,15 +423,13 @@
 static void
 sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te)
 {
-	struct wake_event *we;
 	struct per_pid *p;
 	struct wakeup_entry *wake = (void *)te;
+	struct wake_event *we = zalloc(sizeof(*we));
 
-	we = malloc(sizeof(struct wake_event));
 	if (!we)
 		return;
 
-	memset(we, 0, sizeof(struct wake_event));
 	we->time = timestamp;
 	we->waker = pid;
 
@@ -491,11 +483,11 @@
 }
 
 
-static int process_sample_event(struct perf_tool *tool __used,
-				union perf_event *event __used,
+static int process_sample_event(struct perf_tool *tool __maybe_unused,
+				union perf_event *event __maybe_unused,
 				struct perf_sample *sample,
 				struct perf_evsel *evsel,
-				struct machine *machine __used)
+				struct machine *machine __maybe_unused)
 {
 	struct trace_entry *te;
 
@@ -579,13 +571,12 @@
 	struct power_event *pwr;
 
 	for (cpu = 0; cpu <= numcpus; cpu++) {
-		pwr = malloc(sizeof(struct power_event));
-		if (!pwr)
-			return;
-		memset(pwr, 0, sizeof(struct power_event));
-
 		/* C state */
 #if 0
+		pwr = zalloc(sizeof(*pwr));
+		if (!pwr)
+			return;
+
 		pwr->state = cpus_cstate_state[cpu];
 		pwr->start_time = cpus_cstate_start_times[cpu];
 		pwr->end_time = last_time;
@@ -597,10 +588,9 @@
 #endif
 		/* P state */
 
-		pwr = malloc(sizeof(struct power_event));
+		pwr = zalloc(sizeof(*pwr));
 		if (!pwr)
 			return;
-		memset(pwr, 0, sizeof(struct power_event));
 
 		pwr->state = cpus_pstate_state[cpu];
 		pwr->start_time = cpus_pstate_start_times[cpu];
@@ -830,11 +820,9 @@
 
 static void add_process_filter(const char *string)
 {
-	struct process_filter *filt;
-	int pid;
+	int pid = strtoull(string, NULL, 10);
+	struct process_filter *filt = malloc(sizeof(*filt));
 
-	pid = strtoull(string, NULL, 10);
-	filt = malloc(sizeof(struct process_filter));
 	if (!filt)
 		return;
 
@@ -1081,7 +1069,8 @@
 }
 
 static int
-parse_process(const struct option *opt __used, const char *arg, int __used unset)
+parse_process(const struct option *opt __maybe_unused, const char *arg,
+	      int __maybe_unused unset)
 {
 	if (arg)
 		add_process_filter(arg);
@@ -1106,7 +1095,8 @@
 };
 
 
-int cmd_timechart(int argc, const char **argv, const char *prefix __used)
+int cmd_timechart(int argc, const char **argv,
+		  const char *prefix __maybe_unused)
 {
 	argc = parse_options(argc, argv, options, timechart_usage,
 			PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 68cd61e..e434a16 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -95,7 +95,8 @@
 		top->print_entries -= 9;
 }
 
-static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg)
+static void perf_top__sig_winch(int sig __maybe_unused,
+				siginfo_t *info __maybe_unused, void *arg)
 {
 	struct perf_top *top = arg;
 
@@ -509,7 +510,7 @@
 				prompt_integer(&counter, "Enter details event counter");
 
 				if (counter >= top->evlist->nr_entries) {
-					top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
+					top->sym_evsel = perf_evlist__first(top->evlist);
 					fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel));
 					sleep(1);
 					break;
@@ -518,7 +519,7 @@
 					if (top->sym_evsel->idx == counter)
 						break;
 			} else
-				top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
+				top->sym_evsel = perf_evlist__first(top->evlist);
 			break;
 		case 'f':
 			prompt_integer(&top->count_filter, "Enter display event count filter");
@@ -663,7 +664,7 @@
 	NULL
 };
 
-static int symbol_filter(struct map *map __used, struct symbol *sym)
+static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
 {
 	const char *name = sym->name;
 	int i;
@@ -783,8 +784,10 @@
 
 		if ((sort__has_parent || symbol_conf.use_callchain) &&
 		    sample->callchain) {
-			err = machine__resolve_callchain(machine, al.thread,
-							 sample->callchain, &parent);
+			err = machine__resolve_callchain(machine, evsel,
+							 al.thread, sample,
+							 &parent);
+
 			if (err)
 				return;
 		}
@@ -820,7 +823,7 @@
 	int ret;
 
 	while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
-		ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
+		ret = perf_evlist__parse_sample(top->evlist, event, &sample);
 		if (ret) {
 			pr_err("Can't parse sample, err = %d\n", ret);
 			continue;
@@ -884,17 +887,14 @@
 
 static void perf_top__start_counters(struct perf_top *top)
 {
-	struct perf_evsel *counter, *first;
+	struct perf_evsel *counter;
 	struct perf_evlist *evlist = top->evlist;
 
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	if (top->group)
+		perf_evlist__set_leader(evlist);
 
 	list_for_each_entry(counter, &evlist->entries, node) {
 		struct perf_event_attr *attr = &counter->attr;
-		struct xyarray *group_fd = NULL;
-
-		if (top->group && counter != first)
-			group_fd = first->fd;
 
 		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
@@ -925,8 +925,7 @@
 		attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
 try_again:
 		if (perf_evsel__open(counter, top->evlist->cpus,
-				     top->evlist->threads, top->group,
-				     group_fd) < 0) {
+				     top->evlist->threads) < 0) {
 			int err = errno;
 
 			if (err == EPERM || err == EACCES) {
@@ -1165,7 +1164,7 @@
 	NULL
 };
 
-int cmd_top(int argc, const char **argv, const char *prefix __used)
+int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_evsel *pos;
 	int status;
@@ -1328,7 +1327,7 @@
 			pos->attr.sample_period = top.default_interval;
 	}
 
-	top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
+	top.sym_evsel = perf_evlist__first(top.evlist);
 
 	symbol_conf.priv_size = sizeof(struct annotation);
 
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
new file mode 100644
index 0000000..8f113da
--- /dev/null
+++ b/tools/perf/builtin-trace.c
@@ -0,0 +1,310 @@
+#include "builtin.h"
+#include "util/evlist.h"
+#include "util/parse-options.h"
+#include "util/thread_map.h"
+#include "event-parse.h"
+
+#include <libaudit.h>
+#include <stdlib.h>
+
+static struct syscall_fmt {
+	const char *name;
+	const char *alias;
+	bool	   errmsg;
+	bool	   timeout;
+} syscall_fmts[] = {
+	{ .name	    = "arch_prctl", .errmsg = true, .alias = "prctl", },
+	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat", },
+	{ .name	    = "fstatat",    .errmsg = true, .alias = "newfstatat", },
+	{ .name	    = "futex",	    .errmsg = true, },
+	{ .name	    = "poll",	    .errmsg = true, .timeout = true, },
+	{ .name	    = "ppoll",	    .errmsg = true, .timeout = true, },
+	{ .name	    = "read",	    .errmsg = true, },
+	{ .name	    = "recvfrom",   .errmsg = true, },
+	{ .name	    = "select",	    .errmsg = true, .timeout = true, },
+	{ .name	    = "stat",	    .errmsg = true, .alias = "newstat", },
+};
+
+static int syscall_fmt__cmp(const void *name, const void *fmtp)
+{
+	const struct syscall_fmt *fmt = fmtp;
+	return strcmp(name, fmt->name);
+}
+
+static struct syscall_fmt *syscall_fmt__find(const char *name)
+{
+	const int nmemb = ARRAY_SIZE(syscall_fmts);
+	return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
+}
+
+struct syscall {
+	struct event_format *tp_format;
+	const char	    *name;
+	struct syscall_fmt  *fmt;
+};
+
+struct trace {
+	int			audit_machine;
+	struct {
+		int		max;
+		struct syscall  *table;
+	} syscalls;
+	struct perf_record_opts opts;
+};
+
+static int trace__read_syscall_info(struct trace *trace, int id)
+{
+	char tp_name[128];
+	struct syscall *sc;
+
+	if (id > trace->syscalls.max) {
+		struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
+
+		if (nsyscalls == NULL)
+			return -1;
+
+		if (trace->syscalls.max != -1) {
+			memset(nsyscalls + trace->syscalls.max + 1, 0,
+			       (id - trace->syscalls.max) * sizeof(*sc));
+		} else {
+			memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
+		}
+
+		trace->syscalls.table = nsyscalls;
+		trace->syscalls.max   = id;
+	}
+
+	sc = trace->syscalls.table + id;
+	sc->name = audit_syscall_to_name(id, trace->audit_machine);
+	if (sc->name == NULL)
+		return -1;
+
+	sc->fmt = syscall_fmt__find(sc->name);
+
+	snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
+	sc->tp_format = event_format__new("syscalls", tp_name);
+
+	if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
+		snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
+		sc->tp_format = event_format__new("syscalls", tp_name);
+	}
+
+	return sc->tp_format != NULL ? 0 : -1;
+}
+
+static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp)
+{
+	int i = 0;
+	size_t printed = 0;
+
+	if (sc->tp_format != NULL) {
+		struct format_field *field;
+
+		for (field = sc->tp_format->format.fields->next; field; field = field->next) {
+			printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "",
+					   field->name, args[i++]);
+		}
+	} else {
+		while (i < 6) {
+			printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]);
+			++i;
+		}
+	}
+
+	return printed;
+}
+
+static int trace__run(struct trace *trace)
+{
+	struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+	struct perf_evsel *evsel, *evsel_enter, *evsel_exit;
+	int err = -1, i, nr_events = 0, before;
+
+	if (evlist == NULL) {
+		printf("Not enough memory to run!\n");
+		goto out;
+	}
+
+	evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0);
+	if (evsel_enter == NULL) {
+		printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n");
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__add(evlist, evsel_enter);
+
+	evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1);
+	if (evsel_exit == NULL) {
+		printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n");
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__add(evlist, evsel_exit);
+
+	err = perf_evlist__create_maps(evlist, &trace->opts.target);
+	if (err < 0) {
+		printf("Problems parsing the target to trace, check your options!\n");
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__config_attrs(evlist, &trace->opts);
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		printf("Couldn't create the events: %s\n", strerror(errno));
+		goto out_delete_evlist;
+	}
+
+	err = perf_evlist__mmap(evlist, UINT_MAX, false);
+	if (err < 0) {
+		printf("Couldn't mmap the events: %s\n", strerror(errno));
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__enable(evlist);
+again:
+	before = nr_events;
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		union perf_event *event;
+
+		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+			const u32 type = event->header.type;
+			struct syscall *sc;
+			struct perf_sample sample;
+			int id;
+
+			++nr_events;
+
+			switch (type) {
+			case PERF_RECORD_SAMPLE:
+				break;
+			case PERF_RECORD_LOST:
+				printf("LOST %" PRIu64 " events!\n", event->lost.lost);
+				continue;
+			default:
+				printf("Unexpected %s event, skipping...\n",
+					perf_event__name(type));
+				continue;
+			}
+
+			err = perf_evlist__parse_sample(evlist, event, &sample);
+			if (err) {
+				printf("Can't parse sample, err = %d, skipping...\n", err);
+				continue;
+			}
+
+			evsel = perf_evlist__id2evsel(evlist, sample.id);
+			if (evsel == NULL) {
+				printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
+				continue;
+			}
+
+			id = perf_evsel__intval(evsel, &sample, "id");
+			if (id < 0) {
+				printf("Invalid syscall %d id, skipping...\n", id);
+				continue;
+			}
+
+			if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
+			    trace__read_syscall_info(trace, id))
+				continue;
+
+			if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
+				continue;
+
+			sc = &trace->syscalls.table[id];
+
+			if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1)
+				printf("%d ", sample.tid);
+
+			if (evsel == evsel_enter) {
+				void *args = perf_evsel__rawptr(evsel, &sample, "args");
+
+				printf("%s(", sc->name);
+				syscall__fprintf_args(sc, args, stdout);
+			} else if (evsel == evsel_exit) {
+				int ret = perf_evsel__intval(evsel, &sample, "ret");
+
+				if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
+					char bf[256];
+					const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
+						   *e = audit_errno_to_name(-ret);
+
+					printf(") = -1 %s %s", e, emsg);
+				} else if (ret == 0 && sc->fmt && sc->fmt->timeout)
+					printf(") = 0 Timeout");
+				else
+					printf(") = %d", ret);
+
+				putchar('\n');
+			}
+		}
+	}
+
+	if (nr_events == before)
+		poll(evlist->pollfd, evlist->nr_fds, -1);
+
+	goto again;
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+out:
+	return err;
+}
+
+int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+	const char * const trace_usage[] = {
+		"perf trace [<options>]",
+		NULL
+	};
+	struct trace trace = {
+		.audit_machine = audit_detect_machine(),
+		.syscalls = {
+			. max = -1,
+		},
+		.opts = {
+			.target = {
+				.uid	   = UINT_MAX,
+				.uses_mmap = true,
+			},
+			.user_freq     = UINT_MAX,
+			.user_interval = ULLONG_MAX,
+			.no_delay      = true,
+			.mmap_pages    = 1024,
+		},
+	};
+	const struct option trace_options[] = {
+	OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
+		    "trace events on existing process id"),
+	OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
+		    "trace events on existing thread id"),
+	OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide,
+		    "system-wide collection from all CPUs"),
+	OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu",
+		    "list of cpus to monitor"),
+	OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
+		    "child tasks do not inherit counters"),
+	OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages,
+		     "number of mmap data pages"),
+	OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
+		   "user to profile"),
+	OPT_END()
+	};
+	int err;
+
+	argc = parse_options(argc, argv, trace_options, trace_usage, 0);
+	if (argc)
+		usage_with_options(trace_usage, trace_options);
+
+	err = perf_target__parse_uid(&trace.opts.target);
+	if (err) {
+		char bf[BUFSIZ];
+		perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
+		printf("%s", bf);
+		return err;
+	}
+
+	return trace__run(&trace);
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index b382bd5..08143bd 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -34,6 +34,8 @@
 extern int cmd_lock(int argc, const char **argv, const char *prefix);
 extern int cmd_kvm(int argc, const char **argv, const char *prefix);
 extern int cmd_test(int argc, const char **argv, const char *prefix);
+extern int cmd_trace(int argc, const char **argv, const char *prefix);
 extern int cmd_inject(int argc, const char **argv, const char *prefix);
 
+extern int find_scripts(char **scripts_array, char **scripts_path_array);
 #endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index d695fe4..3e86bbd 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -17,8 +17,9 @@
 perf-stat			mainporcelain common
 perf-timechart			mainporcelain common
 perf-top			mainporcelain common
+perf-trace			mainporcelain common
 perf-script			mainporcelain common
-perf-probe			mainporcelain common
+perf-probe			mainporcelain full
 perf-kmem			mainporcelain common
 perf-lock			mainporcelain common
 perf-kvm			mainporcelain common
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 6c18785..4add41b 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -154,3 +154,53 @@
 	return 0;
 }
 endef
+
+ifndef NO_LIBUNWIND
+define SOURCE_LIBUNWIND
+#include <libunwind.h>
+#include <stdlib.h>
+
+extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+                                      unw_word_t ip,
+                                      unw_dyn_info_t *di,
+                                      unw_proc_info_t *pi,
+                                      int need_unwind_info, void *arg);
+
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+	addr_space = unw_create_addr_space(NULL, 0);
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+	return 0;
+}
+endef
+endif
+
+ifndef NO_BACKTRACE
+define SOURCE_BACKTRACE
+#include <execinfo.h>
+#include <stdio.h>
+
+int main(void)
+{
+	backtrace(NULL, 0);
+	backtrace_symbols(NULL, 0);
+	return 0;
+}
+endef
+endif
+
+ifndef NO_LIBAUDIT
+define SOURCE_LIBAUDIT
+#include <libaudit.h>
+
+int main(void)
+{
+	return audit_open();
+}
+endef
+endif
\ No newline at end of file
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 95b6f8b..e919306 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -24,7 +24,7 @@
 perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
 if [ ! -s $BUILDIDS ] ; then
 	echo "perf archive: no build-ids found"
-	rm -f $BUILDIDS
+	rm $BUILDIDS || true
 	exit 1
 fi
 
@@ -39,8 +39,8 @@
 	echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
 done
 
-tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
-rm -f $MANIFEST $BUILDIDS
+tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
+rm $MANIFEST $BUILDIDS || true
 echo -e "Now please run:\n"
 echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
 echo "wherever you need to run 'perf report' on."
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 2b2e225..fc2f770 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -14,6 +14,7 @@
 #include "util/run-command.h"
 #include "util/parse-events.h"
 #include "util/debugfs.h"
+#include <pthread.h>
 
 const char perf_usage_string[] =
 	"perf [--version] [--help] COMMAND [ARGS]";
@@ -24,6 +25,42 @@
 int use_browser = -1;
 static int use_pager = -1;
 
+struct cmd_struct {
+	const char *cmd;
+	int (*fn)(int, const char **, const char *);
+	int option;
+};
+
+static struct cmd_struct commands[] = {
+	{ "buildid-cache", cmd_buildid_cache, 0 },
+	{ "buildid-list", cmd_buildid_list, 0 },
+	{ "diff",	cmd_diff,	0 },
+	{ "evlist",	cmd_evlist,	0 },
+	{ "help",	cmd_help,	0 },
+	{ "list",	cmd_list,	0 },
+	{ "record",	cmd_record,	0 },
+	{ "report",	cmd_report,	0 },
+	{ "bench",	cmd_bench,	0 },
+	{ "stat",	cmd_stat,	0 },
+	{ "timechart",	cmd_timechart,	0 },
+	{ "top",	cmd_top,	0 },
+	{ "annotate",	cmd_annotate,	0 },
+	{ "version",	cmd_version,	0 },
+	{ "script",	cmd_script,	0 },
+	{ "sched",	cmd_sched,	0 },
+#ifndef NO_LIBELF_SUPPORT
+	{ "probe",	cmd_probe,	0 },
+#endif
+	{ "kmem",	cmd_kmem,	0 },
+	{ "lock",	cmd_lock,	0 },
+	{ "kvm",	cmd_kvm,	0 },
+	{ "test",	cmd_test,	0 },
+#ifndef NO_LIBAUDIT_SUPPORT
+	{ "trace",	cmd_trace,	0 },
+#endif
+	{ "inject",	cmd_inject,	0 },
+};
+
 struct pager_config {
 	const char *cmd;
 	int val;
@@ -160,6 +197,14 @@
 			fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
 			if (envchanged)
 				*envchanged = 1;
+		} else if (!strcmp(cmd, "--list-cmds")) {
+			unsigned int i;
+
+			for (i = 0; i < ARRAY_SIZE(commands); i++) {
+				struct cmd_struct *p = commands+i;
+				printf("%s ", p->cmd);
+			}
+			exit(0);
 		} else {
 			fprintf(stderr, "Unknown option: %s\n", cmd);
 			usage(perf_usage_string);
@@ -245,12 +290,6 @@
  */
 #define NEED_WORK_TREE	(1<<2)
 
-struct cmd_struct {
-	const char *cmd;
-	int (*fn)(int, const char **, const char *);
-	int option;
-};
-
 static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 {
 	int status;
@@ -296,30 +335,6 @@
 static void handle_internal_command(int argc, const char **argv)
 {
 	const char *cmd = argv[0];
-	static struct cmd_struct commands[] = {
-		{ "buildid-cache", cmd_buildid_cache, 0 },
-		{ "buildid-list", cmd_buildid_list, 0 },
-		{ "diff",	cmd_diff,	0 },
-		{ "evlist",	cmd_evlist,	0 },
-		{ "help",	cmd_help,	0 },
-		{ "list",	cmd_list,	0 },
-		{ "record",	cmd_record,	0 },
-		{ "report",	cmd_report,	0 },
-		{ "bench",	cmd_bench,	0 },
-		{ "stat",	cmd_stat,	0 },
-		{ "timechart",	cmd_timechart,	0 },
-		{ "top",	cmd_top,	0 },
-		{ "annotate",	cmd_annotate,	0 },
-		{ "version",	cmd_version,	0 },
-		{ "script",	cmd_script,	0 },
-		{ "sched",	cmd_sched,	0 },
-		{ "probe",	cmd_probe,	0 },
-		{ "kmem",	cmd_kmem,	0 },
-		{ "lock",	cmd_lock,	0 },
-		{ "kvm",	cmd_kvm,	0 },
-		{ "test",	cmd_test,	0 },
-		{ "inject",	cmd_inject,	0 },
-	};
 	unsigned int i;
 	static const char ext[] = STRIP_EXTENSION;
 
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index f960ccb..a89cbbb 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -88,6 +88,12 @@
 #define CPUINFO_PROC	"Processor"
 #endif
 
+#ifdef __aarch64__
+#include "../../arch/arm64/include/asm/unistd.h"
+#define rmb()		asm volatile("dmb ld" ::: "memory")
+#define cpu_relax()	asm volatile("yield" ::: "memory")
+#endif
+
 #ifdef __mips__
 #include "../../arch/mips/include/asm/unistd.h"
 #define rmb()		asm volatile(					\
@@ -209,9 +215,15 @@
 
 #include "util/target.h"
 
+enum perf_call_graph_mode {
+	CALLCHAIN_NONE,
+	CALLCHAIN_FP,
+	CALLCHAIN_DWARF
+};
+
 struct perf_record_opts {
 	struct perf_target target;
-	bool	     call_graph;
+	int	     call_graph;
 	bool	     group;
 	bool	     inherit_stat;
 	bool	     no_delay;
@@ -230,6 +242,7 @@
 	u64          branch_stack;
 	u64	     default_interval;
 	u64	     user_interval;
+	u16	     stack_dump_size;
 };
 
 #endif
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py
new file mode 100755
index 0000000..9e098579
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py
@@ -0,0 +1,94 @@
+# EventClass.py
+#
+# This is a library defining some events types classes, which could
+# be used by other scripts to analyzing the perf samples.
+#
+# Currently there are just a few classes defined for examples,
+# PerfEvent is the base class for all perf event sample, PebsEvent
+# is a HW base Intel x86 PEBS event, and user could add more SW/HW
+# event classes based on requirements.
+
+import struct
+
+# Event types, user could add more here
+EVTYPE_GENERIC  = 0
+EVTYPE_PEBS     = 1     # Basic PEBS event
+EVTYPE_PEBS_LL  = 2     # PEBS event with load latency info
+EVTYPE_IBS      = 3
+
+#
+# Currently we don't have good way to tell the event type, but by
+# the size of raw buffer, raw PEBS event with load latency data's
+# size is 176 bytes, while the pure PEBS event's size is 144 bytes.
+#
+def create_event(name, comm, dso, symbol, raw_buf):
+        if (len(raw_buf) == 144):
+                event = PebsEvent(name, comm, dso, symbol, raw_buf)
+        elif (len(raw_buf) == 176):
+                event = PebsNHM(name, comm, dso, symbol, raw_buf)
+        else:
+                event = PerfEvent(name, comm, dso, symbol, raw_buf)
+
+        return event
+
+class PerfEvent(object):
+        event_num = 0
+        def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_GENERIC):
+                self.name       = name
+                self.comm       = comm
+                self.dso        = dso
+                self.symbol     = symbol
+                self.raw_buf    = raw_buf
+                self.ev_type    = ev_type
+                PerfEvent.event_num += 1
+
+        def show(self):
+                print "PMU event: name=%12s, symbol=%24s, comm=%8s, dso=%12s" % (self.name, self.symbol, self.comm, self.dso)
+
+#
+# Basic Intel PEBS (Precise Event-based Sampling) event, whose raw buffer
+# contains the context info when that event happened: the EFLAGS and
+# linear IP info, as well as all the registers.
+#
+class PebsEvent(PerfEvent):
+        pebs_num = 0
+        def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_PEBS):
+                tmp_buf=raw_buf[0:80]
+                flags, ip, ax, bx, cx, dx, si, di, bp, sp = struct.unpack('QQQQQQQQQQ', tmp_buf)
+                self.flags = flags
+                self.ip    = ip
+                self.ax    = ax
+                self.bx    = bx
+                self.cx    = cx
+                self.dx    = dx
+                self.si    = si
+                self.di    = di
+                self.bp    = bp
+                self.sp    = sp
+
+                PerfEvent.__init__(self, name, comm, dso, symbol, raw_buf, ev_type)
+                PebsEvent.pebs_num += 1
+                del tmp_buf
+
+#
+# Intel Nehalem and Westmere support PEBS plus Load Latency info which lie
+# in the four 64 bit words write after the PEBS data:
+#       Status: records the IA32_PERF_GLOBAL_STATUS register value
+#       DLA:    Data Linear Address (EIP)
+#       DSE:    Data Source Encoding, where the latency happens, hit or miss
+#               in L1/L2/L3 or IO operations
+#       LAT:    the actual latency in cycles
+#
+class PebsNHM(PebsEvent):
+        pebs_nhm_num = 0
+        def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_PEBS_LL):
+                tmp_buf=raw_buf[144:176]
+                status, dla, dse, lat = struct.unpack('QQQQ', tmp_buf)
+                self.status = status
+                self.dla = dla
+                self.dse = dse
+                self.lat = lat
+
+                PebsEvent.__init__(self, name, comm, dso, symbol, raw_buf, ev_type)
+                PebsNHM.pebs_nhm_num += 1
+                del tmp_buf
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-record b/tools/perf/scripts/python/bin/event_analyzing_sample-record
new file mode 100644
index 0000000..5ce652d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/event_analyzing_sample-record
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+#
+# event_analyzing_sample.py can cover all type of perf samples including
+# the tracepoints, so no special record requirements, just record what
+# you want to analyze.
+#
+perf record $@
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-report b/tools/perf/scripts/python/bin/event_analyzing_sample-report
new file mode 100644
index 0000000..0941fc9
--- /dev/null
+++ b/tools/perf/scripts/python/bin/event_analyzing_sample-report
@@ -0,0 +1,3 @@
+#!/bin/bash
+# description: analyze all perf samples
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/event_analyzing_sample.py
diff --git a/tools/perf/scripts/python/event_analyzing_sample.py b/tools/perf/scripts/python/event_analyzing_sample.py
new file mode 100644
index 0000000..163c39f
--- /dev/null
+++ b/tools/perf/scripts/python/event_analyzing_sample.py
@@ -0,0 +1,189 @@
+# event_analyzing_sample.py: general event handler in python
+#
+# Current perf report is already very powerful with the annotation integrated,
+# and this script is not trying to be as powerful as perf report, but
+# providing end user/developer a flexible way to analyze the events other
+# than trace points.
+#
+# The 2 database related functions in this script just show how to gather
+# the basic information, and users can modify and write their own functions
+# according to their specific requirement.
+#
+# The first function "show_general_events" just does a basic grouping for all
+# generic events with the help of sqlite, and the 2nd one "show_pebs_ll" is
+# for a x86 HW PMU event: PEBS with load latency data.
+#
+
+import os
+import sys
+import math
+import struct
+import sqlite3
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from EventClass import *
+
+#
+# If the perf.data has a big number of samples, then the insert operation
+# will be very time consuming (about 10+ minutes for 10000 samples) if the
+# .db database is on disk. Move the .db file to RAM based FS to speedup
+# the handling, which will cut the time down to several seconds.
+#
+con = sqlite3.connect("/dev/shm/perf.db")
+con.isolation_level = None
+
+def trace_begin():
+	print "In trace_begin:\n"
+
+        #
+        # Will create several tables at the start, pebs_ll is for PEBS data with
+        # load latency info, while gen_events is for general event.
+        #
+        con.execute("""
+                create table if not exists gen_events (
+                        name text,
+                        symbol text,
+                        comm text,
+                        dso text
+                );""")
+        con.execute("""
+                create table if not exists pebs_ll (
+                        name text,
+                        symbol text,
+                        comm text,
+                        dso text,
+                        flags integer,
+                        ip integer,
+                        status integer,
+                        dse integer,
+                        dla integer,
+                        lat integer
+                );""")
+
+#
+# Create and insert event object to a database so that user could
+# do more analysis with simple database commands.
+#
+def process_event(param_dict):
+        event_attr = param_dict["attr"]
+        sample     = param_dict["sample"]
+        raw_buf    = param_dict["raw_buf"]
+        comm       = param_dict["comm"]
+        name       = param_dict["ev_name"]
+
+        # Symbol and dso info are not always resolved
+        if (param_dict.has_key("dso")):
+                dso = param_dict["dso"]
+        else:
+                dso = "Unknown_dso"
+
+        if (param_dict.has_key("symbol")):
+                symbol = param_dict["symbol"]
+        else:
+                symbol = "Unknown_symbol"
+
+        # Create the event object and insert it to the right table in database
+        event = create_event(name, comm, dso, symbol, raw_buf)
+        insert_db(event)
+
+def insert_db(event):
+        if event.ev_type == EVTYPE_GENERIC:
+                con.execute("insert into gen_events values(?, ?, ?, ?)",
+                                (event.name, event.symbol, event.comm, event.dso))
+        elif event.ev_type == EVTYPE_PEBS_LL:
+                event.ip &= 0x7fffffffffffffff
+                event.dla &= 0x7fffffffffffffff
+                con.execute("insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                        (event.name, event.symbol, event.comm, event.dso, event.flags,
+                                event.ip, event.status, event.dse, event.dla, event.lat))
+
+def trace_end():
+	print "In trace_end:\n"
+        # We show the basic info for the 2 type of event classes
+        show_general_events()
+        show_pebs_ll()
+        con.close()
+
+#
+# As the event number may be very big, so we can't use linear way
+# to show the histogram in real number, but use a log2 algorithm.
+#
+
+def num2sym(num):
+        # Each number will have at least one '#'
+        snum = '#' * (int)(math.log(num, 2) + 1)
+        return snum
+
+def show_general_events():
+
+        # Check the total record number in the table
+        count = con.execute("select count(*) from gen_events")
+        for t in count:
+                print "There is %d records in gen_events table" % t[0]
+                if t[0] == 0:
+                        return
+
+        print "Statistics about the general events grouped by thread/symbol/dso: \n"
+
+         # Group by thread
+        commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)")
+        print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)
+        for row in commq:
+             print "%16s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+        # Group by symbol
+        print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)
+        symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)")
+        for row in symbolq:
+             print "%32s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+        # Group by dso
+        print "\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74)
+        dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)")
+        for row in dsoq:
+             print "%40s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+#
+# This function just shows the basic info, and we could do more with the
+# data in the tables, like checking the function parameters when some
+# big latency events happen.
+#
+def show_pebs_ll():
+
+        count = con.execute("select count(*) from pebs_ll")
+        for t in count:
+                print "There is %d records in pebs_ll table" % t[0]
+                if t[0] == 0:
+                        return
+
+        print "Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n"
+
+        # Group by thread
+        commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)")
+        print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)
+        for row in commq:
+             print "%16s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+        # Group by symbol
+        print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)
+        symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)")
+        for row in symbolq:
+             print "%32s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+        # Group by dse
+        dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)")
+        print "\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58)
+        for row in dseq:
+             print "%32s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+        # Group by latency
+        latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat")
+        print "\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58)
+        for row in latq:
+             print "%32s %8d     %s" % (row[0], row[1], num2sym(row[1]))
+
+def trace_unhandled(event_name, context, event_fields_dict):
+		print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 1818a53..4aeb7d5 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -269,7 +269,7 @@
 	return err ? 0 : -1;
 }
 
-void ui_browser__hide(struct ui_browser *browser __used)
+void ui_browser__hide(struct ui_browser *browser __maybe_unused)
 {
 	pthread_mutex_lock(&ui__lock);
 	ui_helpline__pop();
@@ -518,7 +518,7 @@
 
 
 static int ui_browser__color_config(const char *var, const char *value,
-				    void *data __used)
+				    void *data __maybe_unused)
 {
 	char *fg = NULL, *bg;
 	int i;
@@ -602,7 +602,8 @@
 	SLsmg_set_char_set(0);
 }
 
-void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
+void ui_browser__write_graph(struct ui_browser *browser __maybe_unused,
+			     int graph)
 {
 	SLsmg_set_char_set(1);
 	SLsmg_write_char(graph);
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 67a2703..8f8cd2d 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -54,7 +54,8 @@
 	return (struct browser_disasm_line *)(dl + 1);
 }
 
-static bool disasm_line__filter(struct ui_browser *browser __used, void *entry)
+static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
+				void *entry)
 {
 	if (annotate_browser__opts.hide_src_code) {
 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
@@ -928,7 +929,8 @@
 	return strcmp(name, cfg->name);
 }
 
-static int annotate__config(const char *var, const char *value, void *data __used)
+static int annotate__config(const char *var, const char *value,
+			    void *data __maybe_unused)
 {
 	struct annotate__config *cfg;
 	const char *name;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 413bd62..a21f40b 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -24,9 +24,12 @@
 	struct hist_entry   *he_selection;
 	struct map_symbol   *selection;
 	int		     print_seq;
+	bool		     show_dso;
 	bool		     has_symbols;
 };
 
+extern void hist_browser__init_hpp(void);
+
 static int hists__browser_title(struct hists *hists, char *bf, size_t size,
 				const char *ev_name);
 
@@ -376,12 +379,19 @@
 }
 
 static char *callchain_list__sym_name(struct callchain_list *cl,
-				      char *bf, size_t bfsize)
+				      char *bf, size_t bfsize, bool show_dso)
 {
-	if (cl->ms.sym)
-		return cl->ms.sym->name;
+	int printed;
 
-	snprintf(bf, bfsize, "%#" PRIx64, cl->ip);
+	if (cl->ms.sym)
+		printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+	else
+		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
+
+	if (show_dso)
+		scnprintf(bf + printed, bfsize - printed, " %s",
+			  cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
+
 	return bf;
 }
 
@@ -417,7 +427,7 @@
 		remaining -= cumul;
 
 		list_for_each_entry(chain, &child->val, list) {
-			char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+			char bf[1024], *alloc_str;
 			const char *str;
 			int color;
 			bool was_first = first;
@@ -434,7 +444,8 @@
 			}
 
 			alloc_str = NULL;
-			str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+			str = callchain_list__sym_name(chain, bf, sizeof(bf),
+						       browser->show_dso);
 			if (was_first) {
 				double percent = cumul * 100.0 / new_total;
 
@@ -493,7 +504,7 @@
 	char folded_sign = ' ';
 
 	list_for_each_entry(chain, &node->val, list) {
-		char ipstr[BITS_PER_LONG / 4 + 1], *s;
+		char bf[1024], *s;
 		int color;
 
 		folded_sign = callchain_list__folded(chain);
@@ -510,7 +521,8 @@
 			*is_current_entry = true;
 		}
 
-		s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+		s = callchain_list__sym_name(chain, bf, sizeof(bf),
+					     browser->show_dso);
 		ui_browser__gotorc(&browser->b, row, 0);
 		ui_browser__set_color(&browser->b, color);
 		slsmg_write_nstring(" ", offset);
@@ -553,14 +565,47 @@
 	return row - first_row;
 }
 
+#define HPP__COLOR_FN(_name, _field)					\
+static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp,	\
+					     struct hist_entry *he)	\
+{									\
+	double percent = 100.0 * he->_field / hpp->total_period;	\
+	*(double *)hpp->ptr = percent;					\
+	return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);	\
+}
+
+HPP__COLOR_FN(overhead, period)
+HPP__COLOR_FN(overhead_sys, period_sys)
+HPP__COLOR_FN(overhead_us, period_us)
+HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
+HPP__COLOR_FN(overhead_guest_us, period_guest_us)
+
+#undef HPP__COLOR_FN
+
+void hist_browser__init_hpp(void)
+{
+	perf_hpp__init(false, false);
+
+	perf_hpp__format[PERF_HPP__OVERHEAD].color =
+				hist_browser__hpp_color_overhead;
+	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
+				hist_browser__hpp_color_overhead_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
+				hist_browser__hpp_color_overhead_us;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
+				hist_browser__hpp_color_overhead_guest_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
+				hist_browser__hpp_color_overhead_guest_us;
+}
+
 static int hist_browser__show_entry(struct hist_browser *browser,
 				    struct hist_entry *entry,
 				    unsigned short row)
 {
 	char s[256];
 	double percent;
-	int printed = 0;
-	int width = browser->b.width - 6; /* The percentage */
+	int i, printed = 0;
+	int width = browser->b.width;
 	char folded_sign = ' ';
 	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
 	off_t row_offset = entry->row_offset;
@@ -576,35 +621,50 @@
 	}
 
 	if (row_offset == 0) {
-		hist_entry__snprintf(entry, s, sizeof(s), browser->hists);
-		percent = (entry->period * 100.0) / browser->hists->stats.total_period;
+		struct perf_hpp hpp = {
+			.buf		= s,
+			.size		= sizeof(s),
+			.total_period	= browser->hists->stats.total_period,
+		};
 
-		ui_browser__set_percent_color(&browser->b, percent, current_entry);
 		ui_browser__gotorc(&browser->b, row, 0);
-		if (symbol_conf.use_callchain) {
-			slsmg_printf("%c ", folded_sign);
-			width -= 2;
-		}
 
-		slsmg_printf(" %5.2f%%", percent);
+		for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+			if (!perf_hpp__format[i].cond)
+				continue;
+
+			if (i) {
+				slsmg_printf("  ");
+				width -= 2;
+			}
+
+			if (perf_hpp__format[i].color) {
+				hpp.ptr = &percent;
+				/* It will set percent for us. See HPP__COLOR_FN above. */
+				width -= perf_hpp__format[i].color(&hpp, entry);
+
+				ui_browser__set_percent_color(&browser->b, percent, current_entry);
+
+				if (i == 0 && symbol_conf.use_callchain) {
+					slsmg_printf("%c ", folded_sign);
+					width -= 2;
+				}
+
+				slsmg_printf("%s", s);
+
+				if (!current_entry || !browser->b.navkeypressed)
+					ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
+			} else {
+				width -= perf_hpp__format[i].entry(&hpp, entry);
+				slsmg_printf("%s", s);
+			}
+		}
 
 		/* The scroll bar isn't being used */
 		if (!browser->b.navkeypressed)
 			width += 1;
 
-		if (!current_entry || !browser->b.navkeypressed)
-			ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
-
-		if (symbol_conf.show_nr_samples) {
-			slsmg_printf(" %11u", entry->nr_events);
-			width -= 12;
-		}
-
-		if (symbol_conf.show_total_period) {
-			slsmg_printf(" %12" PRIu64, entry->period);
-			width -= 13;
-		}
-
+		hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
 		slsmg_write_nstring(s, width);
 		++row;
 		++printed;
@@ -830,7 +890,7 @@
 		remaining -= cumul;
 
 		list_for_each_entry(chain, &child->val, list) {
-			char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+			char bf[1024], *alloc_str;
 			const char *str;
 			bool was_first = first;
 
@@ -842,7 +902,8 @@
 			folded_sign = callchain_list__folded(chain);
 
 			alloc_str = NULL;
-			str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+			str = callchain_list__sym_name(chain, bf, sizeof(bf),
+						       browser->show_dso);
 			if (was_first) {
 				double percent = cumul * 100.0 / new_total;
 
@@ -880,10 +941,10 @@
 	int printed = 0;
 
 	list_for_each_entry(chain, &node->val, list) {
-		char ipstr[BITS_PER_LONG / 4 + 1], *s;
+		char bf[1024], *s;
 
 		folded_sign = callchain_list__folded(chain);
-		s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+		s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
 		printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
 	}
 
@@ -920,7 +981,7 @@
 	if (symbol_conf.use_callchain)
 		folded_sign = hist_entry__folded(he);
 
-	hist_entry__snprintf(he, s, sizeof(s), browser->hists);
+	hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
 	percent = (he->period * 100.0) / browser->hists->stats.total_period;
 
 	if (symbol_conf.use_callchain)
@@ -1133,6 +1194,9 @@
 			continue;
 		case 'd':
 			goto zoom_dso;
+		case 'V':
+			browser->show_dso = !browser->show_dso;
+			continue;
 		case 't':
 			goto zoom_thread;
 		case '/':
@@ -1164,6 +1228,7 @@
 					"d             Zoom into current DSO\n"
 					"t             Zoom into current Thread\n"
 					"P             Print histograms to perf.hist.N\n"
+					"V             Verbose (DSO names in callchains, etc)\n"
 					"/             Filter symbol by name");
 			continue;
 		case K_ENTER:
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index ec12e0b..7ff99ec 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -3,6 +3,7 @@
 #include "../evsel.h"
 #include "../sort.h"
 #include "../hist.h"
+#include "../helpline.h"
 #include "gtk.h"
 
 #include <signal.h>
@@ -35,6 +36,57 @@
 	gtk_window_resize(GTK_WINDOW(window), width, height);
 }
 
+static const char *perf_gtk__get_percent_color(double percent)
+{
+	if (percent >= MIN_RED)
+		return "<span fgcolor='red'>";
+	if (percent >= MIN_GREEN)
+		return "<span fgcolor='dark green'>";
+	return NULL;
+}
+
+#define HPP__COLOR_FN(_name, _field)						\
+static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp,			\
+					 struct hist_entry *he)			\
+{										\
+	double percent = 100.0 * he->_field / hpp->total_period;		\
+	const char *markup;							\
+	int ret = 0;								\
+										\
+	markup = perf_gtk__get_percent_color(percent);				\
+	if (markup)								\
+		ret += scnprintf(hpp->buf, hpp->size, "%s", markup);		\
+	ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); 	\
+	if (markup)								\
+		ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); 	\
+										\
+	return ret;								\
+}
+
+HPP__COLOR_FN(overhead, period)
+HPP__COLOR_FN(overhead_sys, period_sys)
+HPP__COLOR_FN(overhead_us, period_us)
+HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
+HPP__COLOR_FN(overhead_guest_us, period_guest_us)
+
+#undef HPP__COLOR_FN
+
+void perf_gtk__init_hpp(void)
+{
+	perf_hpp__init(false, false);
+
+	perf_hpp__format[PERF_HPP__OVERHEAD].color =
+				perf_gtk__hpp_color_overhead;
+	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
+				perf_gtk__hpp_color_overhead_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
+				perf_gtk__hpp_color_overhead_us;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
+				perf_gtk__hpp_color_overhead_guest_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
+				perf_gtk__hpp_color_overhead_guest_us;
+}
+
 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
 {
 	GType col_types[MAX_COLUMNS];
@@ -42,15 +94,25 @@
 	struct sort_entry *se;
 	GtkListStore *store;
 	struct rb_node *nd;
-	u64 total_period;
 	GtkWidget *view;
-	int col_idx;
+	int i, col_idx;
 	int nr_cols;
+	char s[512];
+
+	struct perf_hpp hpp = {
+		.buf		= s,
+		.size		= sizeof(s),
+		.total_period	= hists->stats.total_period,
+	};
 
 	nr_cols = 0;
 
-	/* The percentage column */
-	col_types[nr_cols++] = G_TYPE_STRING;
+	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+		if (!perf_hpp__format[i].cond)
+			continue;
+
+		col_types[nr_cols++] = G_TYPE_STRING;
+	}
 
 	list_for_each_entry(se, &hist_entry__sort_list, list) {
 		if (se->elide)
@@ -67,11 +129,17 @@
 
 	col_idx = 0;
 
-	/* The percentage column */
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-						    -1, "Overhead (%)",
-						    renderer, "text",
-						    col_idx++, NULL);
+	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+		if (!perf_hpp__format[i].cond)
+			continue;
+
+		perf_hpp__format[i].header(&hpp);
+
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+							    -1, s,
+							    renderer, "markup",
+							    col_idx++, NULL);
+	}
 
 	list_for_each_entry(se, &hist_entry__sort_list, list) {
 		if (se->elide)
@@ -87,13 +155,9 @@
 
 	g_object_unref(GTK_TREE_MODEL(store));
 
-	total_period = hists->stats.total_period;
-
 	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
 		GtkTreeIter iter;
-		double percent;
-		char s[512];
 
 		if (h->filtered)
 			continue;
@@ -102,11 +166,17 @@
 
 		col_idx = 0;
 
-		percent = (h->period * 100.0) / total_period;
+		for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+			if (!perf_hpp__format[i].cond)
+				continue;
 
-		snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
+			if (perf_hpp__format[i].color)
+				perf_hpp__format[i].color(&hpp, h);
+			else
+				perf_hpp__format[i].entry(&hpp, h);
 
-		gtk_list_store_set(store, &iter, col_idx++, s, -1);
+			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+		}
 
 		list_for_each_entry(se, &hist_entry__sort_list, list) {
 			if (se->elide)
@@ -166,9 +236,10 @@
 }
 
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
-				  const char *help __used,
-				  void (*timer) (void *arg)__used,
-				  void *arg __used, int delay_secs __used)
+				  const char *help,
+				  void (*timer) (void *arg)__maybe_unused,
+				  void *arg __maybe_unused,
+				  int delay_secs __maybe_unused)
 {
 	struct perf_evsel *pos;
 	GtkWidget *vbox;
@@ -233,6 +304,8 @@
 
 	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 
+	ui_helpline__push(help);
+
 	gtk_main();
 
 	perf_gtk__deactivate_context(&pgctx);
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index a4d0f2b..687af0b 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -29,6 +29,9 @@
 struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
 int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
 
+void perf_gtk__init_helpline(void);
+void perf_gtk__init_hpp(void);
+
 #ifndef HAVE_GTK_INFO_BAR
 static inline GtkWidget *perf_gtk__setup_info_bar(void)
 {
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
new file mode 100644
index 0000000..5db4432
--- /dev/null
+++ b/tools/perf/ui/gtk/helpline.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "gtk.h"
+#include "../ui.h"
+#include "../helpline.h"
+#include "../../util/debug.h"
+
+static void gtk_helpline_pop(void)
+{
+	if (!perf_gtk__is_active_context(pgctx))
+		return;
+
+	gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
+			  pgctx->statbar_ctx_id);
+}
+
+static void gtk_helpline_push(const char *msg)
+{
+	if (!perf_gtk__is_active_context(pgctx))
+		return;
+
+	gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
+			   pgctx->statbar_ctx_id, msg);
+}
+
+static struct ui_helpline gtk_helpline_fns = {
+	.pop	= gtk_helpline_pop,
+	.push	= gtk_helpline_push,
+};
+
+void perf_gtk__init_helpline(void)
+{
+	helpline_fns = &gtk_helpline_fns;
+}
+
+int perf_gtk__show_helpline(const char *fmt, va_list ap)
+{
+	int ret;
+	char *ptr;
+	static int backlog;
+
+	ret = vscnprintf(ui_helpline__current + backlog,
+			 sizeof(ui_helpline__current) - backlog, fmt, ap);
+	backlog += ret;
+
+	/* only first line can be displayed */
+	ptr = strchr(ui_helpline__current, '\n');
+	if (ptr && (ptr - ui_helpline__current) <= backlog) {
+		*ptr = '\0';
+		ui_helpline__puts(ui_helpline__current);
+		backlog = 0;
+	}
+
+	return ret;
+}
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 92879ce..3c4c6ef 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -7,11 +7,15 @@
 int perf_gtk__init(void)
 {
 	perf_error__register(&perf_gtk_eops);
+	perf_gtk__init_helpline();
+	perf_gtk__init_hpp();
 	return gtk_init_check(NULL, NULL) ? 0 : -1;
 }
 
-void perf_gtk__exit(bool wait_for_ok __used)
+void perf_gtk__exit(bool wait_for_ok __maybe_unused)
 {
+	if (!perf_gtk__is_active_context(pgctx))
+		return;
 	perf_error__unregister(&perf_gtk_eops);
 	gtk_main_quit();
 }
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index 0ead373..8aada5b 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -117,13 +117,8 @@
  *        For now, just add stubs for NO_NEWT=1 build.
  */
 #ifdef NO_NEWT_SUPPORT
-int ui_helpline__show_help(const char *format __used, va_list ap __used)
-{
-	return 0;
-}
-
-void ui_progress__update(u64 curr __used, u64 total __used,
-			 const char *title __used)
+void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused,
+			 const char *title __maybe_unused)
 {
 }
 #endif
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
index 2f950c2..a49bcf3 100644
--- a/tools/perf/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
@@ -5,23 +5,32 @@
 #include "../debug.h"
 #include "helpline.h"
 #include "ui.h"
-#include "libslang.h"
-
-void ui_helpline__pop(void)
-{
-}
 
 char ui_helpline__current[512];
 
+static void nop_helpline__pop(void)
+{
+}
+
+static void nop_helpline__push(const char *msg __maybe_unused)
+{
+}
+
+static struct ui_helpline default_helpline_fns = {
+	.pop	= nop_helpline__pop,
+	.push	= nop_helpline__push,
+};
+
+struct ui_helpline *helpline_fns = &default_helpline_fns;
+
+void ui_helpline__pop(void)
+{
+	helpline_fns->pop();
+}
+
 void ui_helpline__push(const char *msg)
 {
-	const size_t sz = sizeof(ui_helpline__current);
-
-	SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
-	SLsmg_set_color(0);
-	SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
-	SLsmg_refresh();
-	strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
+	helpline_fns->push(msg);
 }
 
 void ui_helpline__vpush(const char *fmt, va_list ap)
@@ -50,30 +59,3 @@
 	ui_helpline__pop();
 	ui_helpline__push(msg);
 }
-
-void ui_helpline__init(void)
-{
-	ui_helpline__puts(" ");
-}
-
-char ui_helpline__last_msg[1024];
-
-int ui_helpline__show_help(const char *format, va_list ap)
-{
-	int ret;
-	static int backlog;
-
-	pthread_mutex_lock(&ui__lock);
-	ret = vscnprintf(ui_helpline__last_msg + backlog,
-			sizeof(ui_helpline__last_msg) - backlog, format, ap);
-	backlog += ret;
-
-	if (ui_helpline__last_msg[backlog - 1] == '\n') {
-		ui_helpline__puts(ui_helpline__last_msg);
-		SLsmg_refresh();
-		backlog = 0;
-	}
-	pthread_mutex_unlock(&ui__lock);
-
-	return ret;
-}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
index 7bab6b3..2b667ee 100644
--- a/tools/perf/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
@@ -4,13 +4,44 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#include "../util/cache.h"
+
+struct ui_helpline {
+	void (*pop)(void);
+	void (*push)(const char *msg);
+};
+
+extern struct ui_helpline *helpline_fns;
+
 void ui_helpline__init(void);
+
 void ui_helpline__pop(void);
 void ui_helpline__push(const char *msg);
 void ui_helpline__vpush(const char *fmt, va_list ap);
 void ui_helpline__fpush(const char *fmt, ...);
 void ui_helpline__puts(const char *msg);
 
-extern char ui_helpline__current[];
+extern char ui_helpline__current[512];
+
+#ifdef NO_NEWT_SUPPORT
+static inline int ui_helpline__show_help(const char *format __maybe_unused,
+					 va_list ap __maybe_unused)
+{
+	return 0;
+}
+#else
+extern char ui_helpline__last_msg[];
+int ui_helpline__show_help(const char *format, va_list ap);
+#endif /* NO_NEWT_SUPPORT */
+
+#ifdef NO_GTK2_SUPPORT
+static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
+					  va_list ap __maybe_unused)
+{
+	return 0;
+}
+#else
+int perf_gtk__show_helpline(const char *format, va_list ap);
+#endif /* NO_GTK2_SUPPORT */
 
 #endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
new file mode 100644
index 0000000..e3f8cd4
--- /dev/null
+++ b/tools/perf/ui/hist.c
@@ -0,0 +1,390 @@
+#include <math.h>
+
+#include "../util/hist.h"
+#include "../util/util.h"
+#include "../util/sort.h"
+
+
+/* hist period print (hpp) functions */
+static int hpp__header_overhead(struct perf_hpp *hpp)
+{
+	const char *fmt = hpp->ptr ? "Baseline" : "Overhead";
+
+	return scnprintf(hpp->buf, hpp->size, fmt);
+}
+
+static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
+{
+	return 8;
+}
+
+static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period / hpp->total_period;
+
+	if (hpp->ptr) {
+		struct hists *old_hists = hpp->ptr;
+		u64 total_period = old_hists->stats.total_period;
+		u64 base_period = he->pair ? he->pair->period : 0;
+
+		if (total_period)
+			percent = 100.0 * base_period / total_period;
+		else
+			percent = 0.0;
+	}
+
+	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
+}
+
+static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period / hpp->total_period;
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
+
+	if (hpp->ptr) {
+		struct hists *old_hists = hpp->ptr;
+		u64 total_period = old_hists->stats.total_period;
+		u64 base_period = he->pair ? he->pair->period : 0;
+
+		if (total_period)
+			percent = 100.0 * base_period / total_period;
+		else
+			percent = 0.0;
+	}
+
+	return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
+static int hpp__header_overhead_sys(struct perf_hpp *hpp)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, "sys");
+}
+
+static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
+{
+	return 7;
+}
+
+static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_sys / hpp->total_period;
+	return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
+}
+
+static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_sys / hpp->total_period;
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
+static int hpp__header_overhead_us(struct perf_hpp *hpp)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, "user");
+}
+
+static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
+{
+	return 7;
+}
+
+static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_us / hpp->total_period;
+	return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
+}
+
+static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_us / hpp->total_period;
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
+static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
+{
+	return scnprintf(hpp->buf, hpp->size, "guest sys");
+}
+
+static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
+{
+	return 9;
+}
+
+static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
+					 struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
+}
+
+static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
+					 struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
+static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
+{
+	return scnprintf(hpp->buf, hpp->size, "guest usr");
+}
+
+static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
+{
+	return 9;
+}
+
+static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
+					struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_guest_us / hpp->total_period;
+	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
+}
+
+static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
+					struct hist_entry *he)
+{
+	double percent = 100.0 * he->period_guest_us / hpp->total_period;
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
+static int hpp__header_samples(struct perf_hpp *hpp)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
+}
+
+static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
+{
+	return 11;
+}
+
+static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
+
+	return scnprintf(hpp->buf, hpp->size, fmt, he->nr_events);
+}
+
+static int hpp__header_period(struct perf_hpp *hpp)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, "Period");
+}
+
+static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
+{
+	return 12;
+}
+
+static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
+
+	return scnprintf(hpp->buf, hpp->size, fmt, he->period);
+}
+
+static int hpp__header_delta(struct perf_hpp *hpp)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
+
+	return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
+}
+
+static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
+{
+	return 7;
+}
+
+static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
+{
+	struct hists *pair_hists = hpp->ptr;
+	u64 old_total, new_total;
+	double old_percent = 0, new_percent = 0;
+	double diff;
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
+	char buf[32] = " ";
+
+	old_total = pair_hists->stats.total_period;
+	if (old_total > 0 && he->pair)
+		old_percent = 100.0 * he->pair->period / old_total;
+
+	new_total = hpp->total_period;
+	if (new_total > 0)
+		new_percent = 100.0 * he->period / new_total;
+
+	diff = new_percent - old_percent;
+	if (fabs(diff) >= 0.01)
+		scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
+
+	return scnprintf(hpp->buf, hpp->size, fmt, buf);
+}
+
+static int hpp__header_displ(struct perf_hpp *hpp)
+{
+	return scnprintf(hpp->buf, hpp->size, "Displ.");
+}
+
+static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
+{
+	return 6;
+}
+
+static int hpp__entry_displ(struct perf_hpp *hpp,
+			    struct hist_entry *he __maybe_unused)
+{
+	const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
+	char buf[32] = " ";
+
+	if (hpp->displacement)
+		scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement);
+
+	return scnprintf(hpp->buf, hpp->size, fmt, buf);
+}
+
+#define HPP__COLOR_PRINT_FNS(_name)		\
+	.header	= hpp__header_ ## _name,		\
+	.width	= hpp__width_ ## _name,		\
+	.color	= hpp__color_ ## _name,		\
+	.entry	= hpp__entry_ ## _name
+
+#define HPP__PRINT_FNS(_name)			\
+	.header	= hpp__header_ ## _name,		\
+	.width	= hpp__width_ ## _name,		\
+	.entry	= hpp__entry_ ## _name
+
+struct perf_hpp_fmt perf_hpp__format[] = {
+	{ .cond = true,  HPP__COLOR_PRINT_FNS(overhead) },
+	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
+	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
+	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
+	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
+	{ .cond = false, HPP__PRINT_FNS(samples) },
+	{ .cond = false, HPP__PRINT_FNS(period) },
+	{ .cond = false, HPP__PRINT_FNS(delta) },
+	{ .cond = false, HPP__PRINT_FNS(displ) }
+};
+
+#undef HPP__COLOR_PRINT_FNS
+#undef HPP__PRINT_FNS
+
+void perf_hpp__init(bool need_pair, bool show_displacement)
+{
+	if (symbol_conf.show_cpu_utilization) {
+		perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
+		perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
+
+		if (perf_guest) {
+			perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
+			perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
+		}
+	}
+
+	if (symbol_conf.show_nr_samples)
+		perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
+
+	if (symbol_conf.show_total_period)
+		perf_hpp__format[PERF_HPP__PERIOD].cond = true;
+
+	if (need_pair) {
+		perf_hpp__format[PERF_HPP__DELTA].cond = true;
+
+		if (show_displacement)
+			perf_hpp__format[PERF_HPP__DISPL].cond = true;
+	}
+}
+
+static inline void advance_hpp(struct perf_hpp *hpp, int inc)
+{
+	hpp->buf  += inc;
+	hpp->size -= inc;
+}
+
+int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
+				bool color)
+{
+	const char *sep = symbol_conf.field_sep;
+	char *start = hpp->buf;
+	int i, ret;
+
+	if (symbol_conf.exclude_other && !he->parent)
+		return 0;
+
+	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+		if (!perf_hpp__format[i].cond)
+			continue;
+
+		if (!sep || i > 0) {
+			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
+			advance_hpp(hpp, ret);
+		}
+
+		if (color && perf_hpp__format[i].color)
+			ret = perf_hpp__format[i].color(hpp, he);
+		else
+			ret = perf_hpp__format[i].entry(hpp, he);
+
+		advance_hpp(hpp, ret);
+	}
+
+	return hpp->buf - start;
+}
+
+int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
+			      struct hists *hists)
+{
+	const char *sep = symbol_conf.field_sep;
+	struct sort_entry *se;
+	int ret = 0;
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
+		ret += se->se_snprintf(he, s + ret, size - ret,
+				       hists__col_len(hists, se->se_width_idx));
+	}
+
+	return ret;
+}
+
+/*
+ * See hists__fprintf to match the column widths
+ */
+unsigned int hists__sort_list_width(struct hists *hists)
+{
+	struct sort_entry *se;
+	int i, ret = 0;
+
+	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
+		if (!perf_hpp__format[i].cond)
+			continue;
+		if (i)
+			ret += 2;
+
+		ret += perf_hpp__format[i].width(NULL);
+	}
+
+	list_for_each_entry(se, &hist_entry__sort_list, list)
+		if (!se->elide)
+			ret += 2 + hists__col_len(hists, se->se_width_idx);
+
+	if (verbose) /* Addr + origin */
+		ret += 3 + BITS_PER_LONG / 4;
+
+	return ret;
+}
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index 791fb15..bd7d460 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -1,6 +1,10 @@
-#include "../cache.h"
-#include "../debug.h"
+#include <pthread.h>
 
+#include "../util/cache.h"
+#include "../util/debug.h"
+#include "../util/hist.h"
+
+pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
 
 void setup_browser(bool fallback_to_pager)
 {
@@ -25,6 +29,8 @@
 		use_browser = 0;
 		if (fallback_to_pager)
 			setup_pager();
+
+		perf_hpp__init(false, false);
 		break;
 	}
 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
new file mode 100644
index 0000000..882461a
--- /dev/null
+++ b/tools/perf/ui/stdio/hist.c
@@ -0,0 +1,498 @@
+#include <stdio.h>
+
+#include "../../util/util.h"
+#include "../../util/hist.h"
+#include "../../util/sort.h"
+
+
+static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
+{
+	int i;
+	int ret = fprintf(fp, "            ");
+
+	for (i = 0; i < left_margin; i++)
+		ret += fprintf(fp, " ");
+
+	return ret;
+}
+
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
+					  int left_margin)
+{
+	int i;
+	size_t ret = callchain__fprintf_left_margin(fp, left_margin);
+
+	for (i = 0; i < depth; i++)
+		if (depth_mask & (1 << i))
+			ret += fprintf(fp, "|          ");
+		else
+			ret += fprintf(fp, "           ");
+
+	ret += fprintf(fp, "\n");
+
+	return ret;
+}
+
+static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
+				     int depth, int depth_mask, int period,
+				     u64 total_samples, u64 hits,
+				     int left_margin)
+{
+	int i;
+	size_t ret = 0;
+
+	ret += callchain__fprintf_left_margin(fp, left_margin);
+	for (i = 0; i < depth; i++) {
+		if (depth_mask & (1 << i))
+			ret += fprintf(fp, "|");
+		else
+			ret += fprintf(fp, " ");
+		if (!period && i == depth - 1) {
+			double percent;
+
+			percent = hits * 100.0 / total_samples;
+			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
+		} else
+			ret += fprintf(fp, "%s", "          ");
+	}
+	if (chain->ms.sym)
+		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
+	else
+		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
+
+	return ret;
+}
+
+static struct symbol *rem_sq_bracket;
+static struct callchain_list rem_hits;
+
+static void init_rem_hits(void)
+{
+	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
+	if (!rem_sq_bracket) {
+		fprintf(stderr, "Not enough memory to display remaining hits\n");
+		return;
+	}
+
+	strcpy(rem_sq_bracket->name, "[...]");
+	rem_hits.ms.sym = rem_sq_bracket;
+}
+
+static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
+					 u64 total_samples, int depth,
+					 int depth_mask, int left_margin)
+{
+	struct rb_node *node, *next;
+	struct callchain_node *child;
+	struct callchain_list *chain;
+	int new_depth_mask = depth_mask;
+	u64 remaining;
+	size_t ret = 0;
+	int i;
+	uint entries_printed = 0;
+
+	remaining = total_samples;
+
+	node = rb_first(root);
+	while (node) {
+		u64 new_total;
+		u64 cumul;
+
+		child = rb_entry(node, struct callchain_node, rb_node);
+		cumul = callchain_cumul_hits(child);
+		remaining -= cumul;
+
+		/*
+		 * The depth mask manages the output of pipes that show
+		 * the depth. We don't want to keep the pipes of the current
+		 * level for the last child of this depth.
+		 * Except if we have remaining filtered hits. They will
+		 * supersede the last child
+		 */
+		next = rb_next(node);
+		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
+			new_depth_mask &= ~(1 << (depth - 1));
+
+		/*
+		 * But we keep the older depth mask for the line separator
+		 * to keep the level link until we reach the last child
+		 */
+		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
+						   left_margin);
+		i = 0;
+		list_for_each_entry(chain, &child->val, list) {
+			ret += ipchain__fprintf_graph(fp, chain, depth,
+						      new_depth_mask, i++,
+						      total_samples,
+						      cumul,
+						      left_margin);
+		}
+
+		if (callchain_param.mode == CHAIN_GRAPH_REL)
+			new_total = child->children_hit;
+		else
+			new_total = total_samples;
+
+		ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
+						  depth + 1,
+						  new_depth_mask | (1 << depth),
+						  left_margin);
+		node = next;
+		if (++entries_printed == callchain_param.print_limit)
+			break;
+	}
+
+	if (callchain_param.mode == CHAIN_GRAPH_REL &&
+		remaining && remaining != total_samples) {
+
+		if (!rem_sq_bracket)
+			return ret;
+
+		new_depth_mask &= ~(1 << (depth - 1));
+		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
+					      new_depth_mask, 0, total_samples,
+					      remaining, left_margin);
+	}
+
+	return ret;
+}
+
+static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
+				       u64 total_samples, int left_margin)
+{
+	struct callchain_node *cnode;
+	struct callchain_list *chain;
+	u32 entries_printed = 0;
+	bool printed = false;
+	struct rb_node *node;
+	int i = 0;
+	int ret = 0;
+
+	/*
+	 * If have one single callchain root, don't bother printing
+	 * its percentage (100 % in fractal mode and the same percentage
+	 * than the hist in graph mode). This also avoid one level of column.
+	 */
+	node = rb_first(root);
+	if (node && !rb_next(node)) {
+		cnode = rb_entry(node, struct callchain_node, rb_node);
+		list_for_each_entry(chain, &cnode->val, list) {
+			/*
+			 * If we sort by symbol, the first entry is the same than
+			 * the symbol. No need to print it otherwise it appears as
+			 * displayed twice.
+			 */
+			if (!i++ && sort__first_dimension == SORT_SYM)
+				continue;
+			if (!printed) {
+				ret += callchain__fprintf_left_margin(fp, left_margin);
+				ret += fprintf(fp, "|\n");
+				ret += callchain__fprintf_left_margin(fp, left_margin);
+				ret += fprintf(fp, "---");
+				left_margin += 3;
+				printed = true;
+			} else
+				ret += callchain__fprintf_left_margin(fp, left_margin);
+
+			if (chain->ms.sym)
+				ret += fprintf(fp, " %s\n", chain->ms.sym->name);
+			else
+				ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
+
+			if (++entries_printed == callchain_param.print_limit)
+				break;
+		}
+		root = &cnode->rb_root;
+	}
+
+	ret += __callchain__fprintf_graph(fp, root, total_samples,
+					  1, 1, left_margin);
+	ret += fprintf(fp, "\n");
+
+	return ret;
+}
+
+static size_t __callchain__fprintf_flat(FILE *fp,
+					struct callchain_node *self,
+					u64 total_samples)
+{
+	struct callchain_list *chain;
+	size_t ret = 0;
+
+	if (!self)
+		return 0;
+
+	ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
+
+
+	list_for_each_entry(chain, &self->val, list) {
+		if (chain->ip >= PERF_CONTEXT_MAX)
+			continue;
+		if (chain->ms.sym)
+			ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
+		else
+			ret += fprintf(fp, "                %p\n",
+					(void *)(long)chain->ip);
+	}
+
+	return ret;
+}
+
+static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
+				      u64 total_samples)
+{
+	size_t ret = 0;
+	u32 entries_printed = 0;
+	struct rb_node *rb_node;
+	struct callchain_node *chain;
+
+	rb_node = rb_first(self);
+	while (rb_node) {
+		double percent;
+
+		chain = rb_entry(rb_node, struct callchain_node, rb_node);
+		percent = chain->hit * 100.0 / total_samples;
+
+		ret = percent_color_fprintf(fp, "           %6.2f%%\n", percent);
+		ret += __callchain__fprintf_flat(fp, chain, total_samples);
+		ret += fprintf(fp, "\n");
+		if (++entries_printed == callchain_param.print_limit)
+			break;
+
+		rb_node = rb_next(rb_node);
+	}
+
+	return ret;
+}
+
+static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
+					    u64 total_samples, int left_margin,
+					    FILE *fp)
+{
+	switch (callchain_param.mode) {
+	case CHAIN_GRAPH_REL:
+		return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
+						left_margin);
+		break;
+	case CHAIN_GRAPH_ABS:
+		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
+						left_margin);
+		break;
+	case CHAIN_FLAT:
+		return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
+		break;
+	case CHAIN_NONE:
+		break;
+	default:
+		pr_err("Bad callchain mode\n");
+	}
+
+	return 0;
+}
+
+static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
+					    struct hists *hists,
+					    u64 total_period, FILE *fp)
+{
+	int left_margin = 0;
+
+	if (sort__first_dimension == SORT_COMM) {
+		struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
+							 typeof(*se), list);
+		left_margin = hists__col_len(hists, se->se_width_idx);
+		left_margin -= thread__comm_len(he->thread);
+	}
+
+	return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
+}
+
+static int hist_entry__fprintf(struct hist_entry *he, size_t size,
+			       struct hists *hists, struct hists *pair_hists,
+			       long displacement, u64 total_period, FILE *fp)
+{
+	char bf[512];
+	int ret;
+	struct perf_hpp hpp = {
+		.buf		= bf,
+		.size		= size,
+		.total_period	= total_period,
+		.displacement	= displacement,
+		.ptr		= pair_hists,
+	};
+	bool color = !symbol_conf.field_sep;
+
+	if (size == 0 || size > sizeof(bf))
+		size = hpp.size = sizeof(bf);
+
+	ret = hist_entry__period_snprintf(&hpp, he, color);
+	hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
+
+	ret = fprintf(fp, "%s\n", bf);
+
+	if (symbol_conf.use_callchain)
+		ret += hist_entry__callchain_fprintf(he, hists,
+						     total_period, fp);
+
+	return ret;
+}
+
+size_t hists__fprintf(struct hists *hists, struct hists *pair,
+		      bool show_displacement, bool show_header, int max_rows,
+		      int max_cols, FILE *fp)
+{
+	struct sort_entry *se;
+	struct rb_node *nd;
+	size_t ret = 0;
+	u64 total_period;
+	unsigned long position = 1;
+	long displacement = 0;
+	unsigned int width;
+	const char *sep = symbol_conf.field_sep;
+	const char *col_width = symbol_conf.col_width_list_str;
+	int idx, nr_rows = 0;
+	char bf[64];
+	struct perf_hpp dummy_hpp = {
+		.buf	= bf,
+		.size	= sizeof(bf),
+		.ptr	= pair,
+	};
+
+	init_rem_hits();
+
+	if (!show_header)
+		goto print_entries;
+
+	fprintf(fp, "# ");
+	for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
+		if (!perf_hpp__format[idx].cond)
+			continue;
+
+		if (idx)
+			fprintf(fp, "%s", sep ?: "  ");
+
+		perf_hpp__format[idx].header(&dummy_hpp);
+		fprintf(fp, "%s", bf);
+	}
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+		if (sep) {
+			fprintf(fp, "%c%s", *sep, se->se_header);
+			continue;
+		}
+		width = strlen(se->se_header);
+		if (symbol_conf.col_width_list_str) {
+			if (col_width) {
+				hists__set_col_len(hists, se->se_width_idx,
+						   atoi(col_width));
+				col_width = strchr(col_width, ',');
+				if (col_width)
+					++col_width;
+			}
+		}
+		if (!hists__new_col_len(hists, se->se_width_idx, width))
+			width = hists__col_len(hists, se->se_width_idx);
+		fprintf(fp, "  %*s", width, se->se_header);
+	}
+
+	fprintf(fp, "\n");
+	if (max_rows && ++nr_rows >= max_rows)
+		goto out;
+
+	if (sep)
+		goto print_entries;
+
+	fprintf(fp, "# ");
+	for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
+		unsigned int i;
+
+		if (!perf_hpp__format[idx].cond)
+			continue;
+
+		if (idx)
+			fprintf(fp, "%s", sep ?: "  ");
+
+		width = perf_hpp__format[idx].width(&dummy_hpp);
+		for (i = 0; i < width; i++)
+			fprintf(fp, ".");
+	}
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		unsigned int i;
+
+		if (se->elide)
+			continue;
+
+		fprintf(fp, "  ");
+		width = hists__col_len(hists, se->se_width_idx);
+		if (width == 0)
+			width = strlen(se->se_header);
+		for (i = 0; i < width; i++)
+			fprintf(fp, ".");
+	}
+
+	fprintf(fp, "\n");
+	if (max_rows && ++nr_rows >= max_rows)
+		goto out;
+
+	fprintf(fp, "#\n");
+	if (max_rows && ++nr_rows >= max_rows)
+		goto out;
+
+print_entries:
+	total_period = hists->stats.total_period;
+
+	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+		if (h->filtered)
+			continue;
+
+		if (show_displacement) {
+			if (h->pair != NULL)
+				displacement = ((long)h->pair->position -
+					        (long)position);
+			else
+				displacement = 0;
+			++position;
+		}
+		ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement,
+					   total_period, fp);
+
+		if (max_rows && ++nr_rows >= max_rows)
+			goto out;
+
+		if (h->ms.map == NULL && verbose > 1) {
+			__map_groups__fprintf_maps(&h->thread->mg,
+						   MAP__FUNCTION, verbose, fp);
+			fprintf(fp, "%.10s end\n", graph_dotted_line);
+		}
+	}
+out:
+	free(rem_sq_bracket);
+
+	return ret;
+}
+
+size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
+{
+	int i;
+	size_t ret = 0;
+
+	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
+		const char *name;
+
+		if (hists->stats.nr_events[i] == 0)
+			continue;
+
+		name = perf_event__name(i);
+		if (!strcmp(name, "UNKNOWN"))
+			continue;
+
+		ret += fprintf(fp, "%16s events: %10d\n", name,
+			       hists->stats.nr_events[i]);
+	}
+
+	return ret;
+}
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
new file mode 100644
index 0000000..2884d2f
--- /dev/null
+++ b/tools/perf/ui/tui/helpline.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "../../util/debug.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../libslang.h"
+
+static void tui_helpline__pop(void)
+{
+}
+
+static void tui_helpline__push(const char *msg)
+{
+	const size_t sz = sizeof(ui_helpline__current);
+
+	SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+	SLsmg_set_color(0);
+	SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
+	SLsmg_refresh();
+	strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
+}
+
+struct ui_helpline tui_helpline_fns = {
+	.pop	= tui_helpline__pop,
+	.push	= tui_helpline__push,
+};
+
+void ui_helpline__init(void)
+{
+	helpline_fns = &tui_helpline_fns;
+	ui_helpline__puts(" ");
+}
+
+char ui_helpline__last_msg[1024];
+
+int ui_helpline__show_help(const char *format, va_list ap)
+{
+	int ret;
+	static int backlog;
+
+	pthread_mutex_lock(&ui__lock);
+	ret = vscnprintf(ui_helpline__last_msg + backlog,
+			sizeof(ui_helpline__last_msg) - backlog, format, ap);
+	backlog += ret;
+
+	if (ui_helpline__last_msg[backlog - 1] == '\n') {
+		ui_helpline__puts(ui_helpline__last_msg);
+		SLsmg_refresh();
+		backlog = 0;
+	}
+	pthread_mutex_unlock(&ui__lock);
+
+	return ret;
+}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index e813c1d..60debb8 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -11,12 +11,12 @@
 #include "../libslang.h"
 #include "../keysyms.h"
 
-pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
-
 static volatile int ui__need_resize;
 
 extern struct perf_error_ops perf_tui_eops;
 
+extern void hist_browser__init_hpp(void);
+
 void ui__refresh_dimensions(bool force)
 {
 	if (force || ui__need_resize) {
@@ -28,7 +28,7 @@
 	}
 }
 
-static void ui__sigwinch(int sig __used)
+static void ui__sigwinch(int sig __maybe_unused)
 {
 	ui__need_resize = 1;
 }
@@ -88,7 +88,7 @@
 	return SLkp_getkey();
 }
 
-static void newt_suspend(void *d __used)
+static void newt_suspend(void *d __maybe_unused)
 {
 	newtSuspend();
 	raise(SIGTSTP);
@@ -126,6 +126,8 @@
 	signal(SIGTERM, ui__signal);
 
 	perf_error__register(&perf_tui_eops);
+
+	hist_browser__init_hpp();
 out:
 	return err;
 }
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index b8144e8..e6d1347 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -3,7 +3,8 @@
 static const char *alias_key;
 static char *alias_val;
 
-static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
+static int alias_lookup_cb(const char *k, const char *v,
+			   void *cb __maybe_unused)
 {
 	if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
 		if (!v)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 3a282c0..f0a9103 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -17,6 +17,7 @@
 #include <pthread.h>
 
 const char 	*disassembler_style;
+const char	*objdump_path;
 
 static struct ins *ins__find(const char *name);
 static int disasm_line__parse(char *line, char **namep, char **rawp);
@@ -312,8 +313,8 @@
 	.scnprintf = dec__scnprintf,
 };
 
-static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
-			  struct ins_operands *ops __used)
+static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
+			  struct ins_operands *ops __maybe_unused)
 {
 	return scnprintf(bf, size, "%-6.6s", "nop");
 }
@@ -415,7 +416,7 @@
 	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
 }
 
-int symbol__annotate_init(struct map *map __used, struct symbol *sym)
+int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
 	pthread_mutex_init(&notes->lock, NULL);
@@ -820,9 +821,10 @@
 		 dso, dso->long_name, sym, sym->name);
 
 	snprintf(command, sizeof(command),
-		 "objdump %s%s --start-address=0x%016" PRIx64
+		 "%s %s%s --start-address=0x%016" PRIx64
 		 " --stop-address=0x%016" PRIx64
 		 " -d %s %s -C %s|grep -v %s|expand",
+		 objdump_path ? objdump_path : "objdump",
 		 disassembler_style ? "-M " : "",
 		 disassembler_style ? disassembler_style : "",
 		 map__rip_2objdump(map, sym->start),
@@ -982,7 +984,8 @@
 			    int context)
 {
 	struct dso *dso = map->dso;
-	const char *filename = dso->long_name, *d_filename;
+	char *filename;
+	const char *d_filename;
 	struct annotation *notes = symbol__annotation(sym);
 	struct disasm_line *pos, *queue = NULL;
 	u64 start = map__rip_2objdump(map, sym->start);
@@ -990,6 +993,10 @@
 	int more = 0;
 	u64 len;
 
+	filename = strdup(dso->long_name);
+	if (!filename)
+		return -ENOMEM;
+
 	if (full_paths)
 		d_filename = filename;
 	else
@@ -1040,6 +1047,8 @@
 		}
 	}
 
+	free(filename);
+
 	return more;
 }
 
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 78a5692..9b5b21e 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -7,6 +7,7 @@
 #include "symbol.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
+#include <pthread.h>
 
 struct ins;
 
@@ -125,7 +126,7 @@
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
-int symbol__annotate_init(struct map *map __used, struct symbol *sym);
+int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
 int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
 			    bool full_paths, int min_pcnt, int max_lines,
 			    int context);
@@ -138,11 +139,12 @@
 			 int max_lines);
 
 #ifdef NO_NEWT_SUPPORT
-static inline int symbol__tui_annotate(struct symbol *sym __used,
-				       struct map *map __used,
-				       int evidx __used,
-				       void(*timer)(void *arg) __used,
-				       void *arg __used, int delay_secs __used)
+static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
+				       struct map *map __maybe_unused,
+				       int evidx __maybe_unused,
+				       void(*timer)(void *arg) __maybe_unused,
+				       void *arg __maybe_unused,
+				       int delay_secs __maybe_unused)
 {
 	return 0;
 }
@@ -152,5 +154,6 @@
 #endif
 
 extern const char	*disassembler_style;
+extern const char	*objdump_path;
 
 #endif	/* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index fd9a594..8e3a740 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -16,10 +16,10 @@
 #include "session.h"
 #include "tool.h"
 
-static int build_id__mark_dso_hit(struct perf_tool *tool __used,
+static int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 				  union perf_event *event,
-				  struct perf_sample *sample __used,
-				  struct perf_evsel *evsel __used,
+				  struct perf_sample *sample __maybe_unused,
+				  struct perf_evsel *evsel __maybe_unused,
 				  struct machine *machine)
 {
 	struct addr_location al;
@@ -41,9 +41,10 @@
 	return 0;
 }
 
-static int perf_event__exit_del_thread(struct perf_tool *tool __used,
+static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
 				       union perf_event *event,
-				       struct perf_sample *sample __used,
+				       struct perf_sample *sample
+				       __maybe_unused,
 				       struct machine *machine)
 {
 	struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index cff18c6..ab17694 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -39,7 +39,7 @@
 	if (fallback_to_pager)
 		setup_pager();
 }
-static inline void exit_browser(bool wait_for_ok __used) {}
+static inline void exit_browser(bool wait_for_ok __maybe_unused) {}
 #else
 void setup_browser(bool fallback_to_pager);
 void exit_browser(bool wait_for_ok);
@@ -49,7 +49,7 @@
 {
 	return -1;
 }
-static inline void ui__exit(bool wait_for_ok __used) {}
+static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
 #else
 int ui__init(void);
 void ui__exit(bool wait_for_ok);
@@ -60,7 +60,7 @@
 {
 	return -1;
 }
-static inline void perf_gtk__exit(bool wait_for_ok __used) {}
+static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
 #else
 int perf_gtk__init(void);
 void perf_gtk__exit(bool wait_for_ok);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3a6bff4..d3b3f5d 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -93,7 +93,7 @@
  */
 static void
 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
-		u64 min_hit, struct callchain_param *param __used)
+		u64 min_hit, struct callchain_param *param __maybe_unused)
 {
 	__sort_chain_flat(rb_root, &root->node, min_hit);
 }
@@ -115,7 +115,7 @@
 
 static void
 sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
-		     u64 min_hit, struct callchain_param *param __used)
+		     u64 min_hit, struct callchain_param *param __maybe_unused)
 {
 	__sort_chain_graph_abs(&chain_root->node, min_hit);
 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
@@ -140,7 +140,7 @@
 
 static void
 sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
-		     u64 min_hit __used, struct callchain_param *param)
+		     u64 min_hit __maybe_unused, struct callchain_param *param)
 {
 	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 3bdb407..eb34057 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,7 +58,7 @@
 /*
  * A callchain cursor is a single linked list that
  * let one feed a callchain progressively.
- * It keeps persitent allocated entries to minimize
+ * It keeps persistent allocated entries to minimize
  * allocations.
  */
 struct callchain_cursor_node {
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index dbe2f16..96bbda1 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -138,8 +138,8 @@
 	}
 }
 
-int parse_cgroups(const struct option *opt __used, const char *str,
-		  int unset __used)
+int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
+		  int unset __maybe_unused)
 {
 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 	const char *p, *e, *eos = str + strlen(str);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 6faa3a1..3e0fdd3 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -342,13 +342,15 @@
 	return value;
 }
 
-static int perf_default_core_config(const char *var __used, const char *value __used)
+static int perf_default_core_config(const char *var __maybe_unused,
+				    const char *value __maybe_unused)
 {
 	/* Add other config variables here. */
 	return 0;
 }
 
-int perf_default_config(const char *var, const char *value, void *dummy __used)
+int perf_default_config(const char *var, const char *value,
+			void *dummy __maybe_unused)
 {
 	if (!prefixcmp(var, "core."))
 		return perf_default_core_config(var, value);
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index adc72f0..2b32ffa 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -38,24 +38,19 @@
 	return cpus;
 }
 
-static struct cpu_map *cpu_map__read_all_cpu_map(void)
+struct cpu_map *cpu_map__read(FILE *file)
 {
 	struct cpu_map *cpus = NULL;
-	FILE *onlnf;
 	int nr_cpus = 0;
 	int *tmp_cpus = NULL, *tmp;
 	int max_entries = 0;
 	int n, cpu, prev;
 	char sep;
 
-	onlnf = fopen("/sys/devices/system/cpu/online", "r");
-	if (!onlnf)
-		return cpu_map__default_new();
-
 	sep = 0;
 	prev = -1;
 	for (;;) {
-		n = fscanf(onlnf, "%u%c", &cpu, &sep);
+		n = fscanf(file, "%u%c", &cpu, &sep);
 		if (n <= 0)
 			break;
 		if (prev >= 0) {
@@ -95,6 +90,19 @@
 		cpus = cpu_map__default_new();
 out_free_tmp:
 	free(tmp_cpus);
+	return cpus;
+}
+
+static struct cpu_map *cpu_map__read_all_cpu_map(void)
+{
+	struct cpu_map *cpus = NULL;
+	FILE *onlnf;
+
+	onlnf = fopen("/sys/devices/system/cpu/online", "r");
+	if (!onlnf)
+		return cpu_map__default_new();
+
+	cpus = cpu_map__read(onlnf);
 	fclose(onlnf);
 	return cpus;
 }
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index c415185..2f68a3b 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -2,6 +2,7 @@
 #define __PERF_CPUMAP_H
 
 #include <stdio.h>
+#include <stdbool.h>
 
 struct cpu_map {
 	int nr;
@@ -11,7 +12,17 @@
 struct cpu_map *cpu_map__new(const char *cpu_list);
 struct cpu_map *cpu_map__dummy_new(void);
 void cpu_map__delete(struct cpu_map *map);
-
+struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 
+static inline int cpu_map__nr(const struct cpu_map *map)
+{
+	return map ? map->nr : 1;
+}
+
+static inline bool cpu_map__all(const struct cpu_map *map)
+{
+	return map ? map->map[0] == -1 : true;
+}
+
 #endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 4dfe0bb..66eb382 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -23,8 +23,10 @@
 
 	if (verbose >= level) {
 		va_start(args, fmt);
-		if (use_browser > 0)
+		if (use_browser == 1)
 			ret = ui_helpline__show_help(fmt, args);
+		else if (use_browser == 2)
+			ret = perf_gtk__show_helpline(fmt, args);
 		else
 			ret = vfprintf(stderr, fmt, args);
 		va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 015c91d..bb2e7d1 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -4,6 +4,7 @@
 
 #include <stdbool.h>
 #include "event.h"
+#include "../ui/helpline.h"
 
 extern int verbose;
 extern bool quiet, dump_trace;
@@ -15,32 +16,26 @@
 struct perf_error_ops;
 
 #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
-static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
-{
-	return 0;
-}
-
-static inline void ui_progress__update(u64 curr __used, u64 total __used,
-				       const char *title __used) {}
+static inline void ui_progress__update(u64 curr __maybe_unused,
+				       u64 total __maybe_unused,
+				       const char *title __maybe_unused) {}
 
 #define ui__error(format, arg...) ui__warning(format, ##arg)
 
 static inline int
-perf_error__register(struct perf_error_ops *eops __used)
+perf_error__register(struct perf_error_ops *eops __maybe_unused)
 {
 	return 0;
 }
 
 static inline int
-perf_error__unregister(struct perf_error_ops *eops __used)
+perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
 {
 	return 0;
 }
 
 #else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
 
-extern char ui_helpline__last_msg[];
-int ui_helpline__show_help(const char *format, va_list ap);
 #include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 #include "../ui/util.h"
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c
index 541cdc7..c6caede 100644
--- a/tools/perf/util/dso-test-data.c
+++ b/tools/perf/util/dso-test-data.c
@@ -23,7 +23,7 @@
 	int fd, i;
 	unsigned char *buf;
 
-	fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC);
+	fd = mkstemp(templ);
 
 	buf = malloc(size);
 	if (!buf) {
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index ee51e9b..3e5f543 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -804,6 +804,8 @@
 			tmp = "union ";
 		else if (tag == DW_TAG_structure_type)
 			tmp = "struct ";
+		else if (tag == DW_TAG_enumeration_type)
+			tmp = "enum ";
 		/* Write a base name */
 		ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
 		return (ret >= len) ? -E2BIG : ret;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2a6f33c..6715b19 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -112,7 +112,7 @@
 	event->comm.header.type = PERF_RECORD_COMM;
 
 	size = strlen(event->comm.comm) + 1;
-	size = ALIGN(size, sizeof(u64));
+	size = PERF_ALIGN(size, sizeof(u64));
 	memset(event->comm.comm + size, 0, machine->id_hdr_size);
 	event->comm.header.size = (sizeof(event->comm) -
 				(sizeof(event->comm.comm) - size) +
@@ -120,7 +120,9 @@
 	if (!full) {
 		event->comm.tid = pid;
 
-		process(tool, event, &synth_sample, machine);
+		if (process(tool, event, &synth_sample, machine) != 0)
+			return -1;
+
 		goto out;
 	}
 
@@ -143,7 +145,7 @@
 					 sizeof(event->comm.comm));
 
 		size = strlen(event->comm.comm) + 1;
-		size = ALIGN(size, sizeof(u64));
+		size = PERF_ALIGN(size, sizeof(u64));
 		memset(event->comm.comm + size, 0, machine->id_hdr_size);
 		event->comm.header.size = (sizeof(event->comm) -
 					  (sizeof(event->comm.comm) - size) +
@@ -151,7 +153,10 @@
 
 		event->comm.tid = pid;
 
-		process(tool, event, &synth_sample, machine);
+		if (process(tool, event, &synth_sample, machine) != 0) {
+			tgid = -1;
+			break;
+		}
 	}
 
 	closedir(tasks);
@@ -167,6 +172,7 @@
 {
 	char filename[PATH_MAX];
 	FILE *fp;
+	int rc = 0;
 
 	snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
 
@@ -222,7 +228,7 @@
 			size = strlen(execname);
 			execname[size - 1] = '\0'; /* Remove \n */
 			memcpy(event->mmap.filename, execname, size);
-			size = ALIGN(size, sizeof(u64));
+			size = PERF_ALIGN(size, sizeof(u64));
 			event->mmap.len -= event->mmap.start;
 			event->mmap.header.size = (sizeof(event->mmap) -
 					        (sizeof(event->mmap.filename) - size));
@@ -231,18 +237,22 @@
 			event->mmap.pid = tgid;
 			event->mmap.tid = pid;
 
-			process(tool, event, &synth_sample, machine);
+			if (process(tool, event, &synth_sample, machine) != 0) {
+				rc = -1;
+				break;
+			}
 		}
 	}
 
 	fclose(fp);
-	return 0;
+	return rc;
 }
 
 int perf_event__synthesize_modules(struct perf_tool *tool,
 				   perf_event__handler_t process,
 				   struct machine *machine)
 {
+	int rc = 0;
 	struct rb_node *nd;
 	struct map_groups *kmaps = &machine->kmaps;
 	union perf_event *event = zalloc((sizeof(event->mmap) +
@@ -272,7 +282,7 @@
 		if (pos->dso->kernel)
 			continue;
 
-		size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+		size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
 		event->mmap.header.type = PERF_RECORD_MMAP;
 		event->mmap.header.size = (sizeof(event->mmap) -
 				        (sizeof(event->mmap.filename) - size));
@@ -284,11 +294,14 @@
 
 		memcpy(event->mmap.filename, pos->dso->long_name,
 		       pos->dso->long_name_len + 1);
-		process(tool, event, &synth_sample, machine);
+		if (process(tool, event, &synth_sample, machine) != 0) {
+			rc = -1;
+			break;
+		}
 	}
 
 	free(event);
-	return 0;
+	return rc;
 }
 
 static int __event__synthesize_thread(union perf_event *comm_event,
@@ -392,12 +405,16 @@
 		if (*end) /* only interested in proper numerical dirents */
 			continue;
 
-		__event__synthesize_thread(comm_event, mmap_event, pid, 1,
-					   process, tool, machine);
+		if (__event__synthesize_thread(comm_event, mmap_event, pid, 1,
+					   process, tool, machine) != 0) {
+			err = -1;
+			goto out_closedir;
+		}
 	}
 
-	closedir(proc);
 	err = 0;
+out_closedir:
+	closedir(proc);
 out_free_mmap:
 	free(mmap_event);
 out_free_comm:
@@ -412,7 +429,7 @@
 };
 
 static int find_symbol_cb(void *arg, const char *name, char type,
-			  u64 start, u64 end __used)
+			  u64 start)
 {
 	struct process_symbol_args *args = arg;
 
@@ -477,7 +494,7 @@
 	map = machine->vmlinux_maps[MAP__FUNCTION];
 	size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
 			"%s%s", mmap_name, symbol_name) + 1;
-	size = ALIGN(size, sizeof(u64));
+	size = PERF_ALIGN(size, sizeof(u64));
 	event->mmap.header.type = PERF_RECORD_MMAP;
 	event->mmap.header.size = (sizeof(event->mmap) -
 			(sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
@@ -497,9 +514,9 @@
 	return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
 }
 
-int perf_event__process_comm(struct perf_tool *tool __used,
+int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
 			     union perf_event *event,
-			     struct perf_sample *sample __used,
+			     struct perf_sample *sample __maybe_unused,
 			     struct machine *machine)
 {
 	struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
@@ -515,10 +532,10 @@
 	return 0;
 }
 
-int perf_event__process_lost(struct perf_tool *tool __used,
+int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
 			     union perf_event *event,
-			     struct perf_sample *sample __used,
-			     struct machine *machine __used)
+			     struct perf_sample *sample __maybe_unused,
+			     struct machine *machine __maybe_unused)
 {
 	dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
 		    event->lost.id, event->lost.lost);
@@ -538,7 +555,8 @@
 		maps[MAP__FUNCTION]->end = ~0ULL;
 }
 
-static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
+static int perf_event__process_kernel_mmap(struct perf_tool *tool
+					   __maybe_unused,
 					   union perf_event *event,
 					   struct machine *machine)
 {
@@ -640,7 +658,7 @@
 
 int perf_event__process_mmap(struct perf_tool *tool,
 			     union perf_event *event,
-			     struct perf_sample *sample __used,
+			     struct perf_sample *sample __maybe_unused,
 			     struct machine *machine)
 {
 	struct thread *thread;
@@ -684,9 +702,9 @@
 		       event->fork.ppid, event->fork.ptid);
 }
 
-int perf_event__process_task(struct perf_tool *tool __used,
+int perf_event__process_task(struct perf_tool *tool __maybe_unused,
 			     union perf_event *event,
-			     struct perf_sample *sample __used,
+			     struct perf_sample *sample __maybe_unused,
 			      struct machine *machine)
 {
 	struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
@@ -886,8 +904,9 @@
 		al->sym = map__find_symbol(al->map, al->addr, filter);
 	}
 
-	if (symbol_conf.sym_list && al->sym &&
-	    !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
+	if (symbol_conf.sym_list &&
+		(!al->sym || !strlist__has_entry(symbol_conf.sym_list,
+						al->sym->name)))
 		goto out_filtered;
 
 	return 0;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d84870b..21b99e7 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -69,6 +69,16 @@
 	u64 array[];
 };
 
+struct regs_dump {
+	u64 *regs;
+};
+
+struct stack_dump {
+	u16 offset;
+	u64 size;
+	char *data;
+};
+
 struct perf_sample {
 	u64 ip;
 	u32 pid, tid;
@@ -82,6 +92,8 @@
 	void *raw_data;
 	struct ip_callchain *callchain;
 	struct branch_stack *branch_stack;
+	struct regs_dump  user_regs;
+	struct stack_dump user_stack;
 };
 
 #define BUILD_ID_SIZE 20
@@ -89,7 +101,7 @@
 struct build_id_event {
 	struct perf_event_header header;
 	pid_t			 pid;
-	u8			 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+	u8			 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))];
 	char			 filename[];
 };
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 9b38681..ae89686 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -57,7 +57,7 @@
 	if (evlist->cpus->map[0] < 0)
 		opts->no_inherit = true;
 
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	first = perf_evlist__first(evlist);
 
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		perf_evsel__config(evsel, opts, first);
@@ -108,6 +108,25 @@
 	evlist->nr_entries += nr_entries;
 }
 
+void __perf_evlist__set_leader(struct list_head *list)
+{
+	struct perf_evsel *evsel, *leader;
+
+	leader = list_entry(list->next, struct perf_evsel, node);
+	leader->leader = NULL;
+
+	list_for_each_entry(evsel, list, node) {
+		if (evsel != leader)
+			evsel->leader = leader;
+	}
+}
+
+void perf_evlist__set_leader(struct perf_evlist *evlist)
+{
+	if (evlist->nr_entries)
+		__perf_evlist__set_leader(&evlist->entries);
+}
+
 int perf_evlist__add_default(struct perf_evlist *evlist)
 {
 	struct perf_event_attr attr = {
@@ -285,7 +304,7 @@
 	int cpu, thread;
 	struct perf_evsel *pos;
 
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+	for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
 			for (thread = 0; thread < evlist->threads->nr; thread++)
 				ioctl(FD(pos, cpu, thread),
@@ -296,7 +315,7 @@
 
 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
-	int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
+	int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries;
 	evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
 	return evlist->pollfd != NULL ? 0 : -ENOMEM;
 }
@@ -357,7 +376,7 @@
 	int hash;
 
 	if (evlist->nr_entries == 1)
-		return list_entry(evlist->entries.next, struct perf_evsel, node);
+		return perf_evlist__first(evlist);
 
 	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
 	head = &evlist->heads[hash];
@@ -367,7 +386,7 @@
 			return sid->evsel;
 
 	if (!perf_evlist__sample_id_all(evlist))
-		return list_entry(evlist->entries.next, struct perf_evsel, node);
+		return perf_evlist__first(evlist);
 
 	return NULL;
 }
@@ -456,8 +475,8 @@
 
 static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 {
-	evlist->nr_mmaps = evlist->cpus->nr;
-	if (evlist->cpus->map[0] == -1)
+	evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
+	if (cpu_map__all(evlist->cpus))
 		evlist->nr_mmaps = evlist->threads->nr;
 	evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
 	return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -603,11 +622,11 @@
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
 		    evsel->sample_id == NULL &&
-		    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
+		    perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0)
 			return -ENOMEM;
 	}
 
-	if (evlist->cpus->map[0] == -1)
+	if (cpu_map__all(cpus))
 		return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@@ -647,39 +666,44 @@
 	evlist->threads = NULL;
 }
 
-int perf_evlist__set_filters(struct perf_evlist *evlist)
+int perf_evlist__apply_filters(struct perf_evlist *evlist)
 {
-	const struct thread_map *threads = evlist->threads;
-	const struct cpu_map *cpus = evlist->cpus;
 	struct perf_evsel *evsel;
-	char *filter;
-	int thread;
-	int cpu;
-	int err;
-	int fd;
+	int err = 0;
+	const int ncpus = cpu_map__nr(evlist->cpus),
+		  nthreads = evlist->threads->nr;
 
 	list_for_each_entry(evsel, &evlist->entries, node) {
-		filter = evsel->filter;
-		if (!filter)
+		if (evsel->filter == NULL)
 			continue;
-		for (cpu = 0; cpu < cpus->nr; cpu++) {
-			for (thread = 0; thread < threads->nr; thread++) {
-				fd = FD(evsel, cpu, thread);
-				err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
-				if (err)
-					return err;
-			}
-		}
+
+		err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter);
+		if (err)
+			break;
 	}
 
-	return 0;
+	return err;
 }
 
-bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
+int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
 {
-	struct perf_evsel *pos, *first;
+	struct perf_evsel *evsel;
+	int err = 0;
+	const int ncpus = cpu_map__nr(evlist->cpus),
+		  nthreads = evlist->threads->nr;
 
-	pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
+{
+	struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
 
 	list_for_each_entry_continue(pos, &evlist->entries, node) {
 		if (first->attr.sample_type != pos->attr.sample_type)
@@ -689,23 +713,19 @@
 	return true;
 }
 
-u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
+u64 perf_evlist__sample_type(struct perf_evlist *evlist)
 {
-	struct perf_evsel *first;
-
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	struct perf_evsel *first = perf_evlist__first(evlist);
 	return first->attr.sample_type;
 }
 
-u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist)
+u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
 {
-	struct perf_evsel *first;
+	struct perf_evsel *first = perf_evlist__first(evlist);
 	struct perf_sample *data;
 	u64 sample_type;
 	u16 size = 0;
 
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
-
 	if (!first->attr.sample_id_all)
 		goto out;
 
@@ -729,11 +749,9 @@
 	return size;
 }
 
-bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
+bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
 {
-	struct perf_evsel *pos, *first;
-
-	pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
 
 	list_for_each_entry_continue(pos, &evlist->entries, node) {
 		if (first->attr.sample_id_all != pos->attr.sample_id_all)
@@ -743,11 +761,9 @@
 	return true;
 }
 
-bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
+bool perf_evlist__sample_id_all(struct perf_evlist *evlist)
 {
-	struct perf_evsel *first;
-
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+	struct perf_evsel *first = perf_evlist__first(evlist);
 	return first->attr.sample_id_all;
 }
 
@@ -757,21 +773,13 @@
 	evlist->selected = evsel;
 }
 
-int perf_evlist__open(struct perf_evlist *evlist, bool group)
+int perf_evlist__open(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel, *first;
+	struct perf_evsel *evsel;
 	int err, ncpus, nthreads;
 
-	first = list_entry(evlist->entries.next, struct perf_evsel, node);
-
 	list_for_each_entry(evsel, &evlist->entries, node) {
-		struct xyarray *group_fd = NULL;
-
-		if (group && evsel != first)
-			group_fd = first->fd;
-
-		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
-				       group, group_fd);
+		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
 		if (err < 0)
 			goto out_err;
 	}
@@ -883,8 +891,21 @@
 }
 
 int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
-			      struct perf_sample *sample, bool swapped)
+			      struct perf_sample *sample)
 {
-	struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node);
-	return perf_evsel__parse_sample(e, event, sample, swapped);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
+	return perf_evsel__parse_sample(evsel, event, sample);
+}
+
+size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
+{
+	struct perf_evsel *evsel;
+	size_t printed = 0;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "",
+				   perf_evsel__name(evsel));
+	}
+
+	return printed + fprintf(fp, "\n");;
 }
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 528c1ac..3f1fb66 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include "../perf.h"
 #include "event.h"
+#include "evsel.h"
 #include "util.h"
 #include <unistd.h>
 
@@ -41,8 +42,6 @@
 	void	   *handler;
 };
 
-struct perf_evsel;
-
 struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
 				     struct thread_map *threads);
 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
@@ -73,6 +72,8 @@
 #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
 	perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
 
+int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
+
 struct perf_evsel *
 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
 
@@ -85,7 +86,7 @@
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
-int perf_evlist__open(struct perf_evlist *evlist, bool group);
+int perf_evlist__open(struct perf_evlist *evlist);
 
 void perf_evlist__config_attrs(struct perf_evlist *evlist,
 			       struct perf_record_opts *opts);
@@ -116,20 +117,34 @@
 int perf_evlist__create_maps(struct perf_evlist *evlist,
 			     struct perf_target *target);
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
-int perf_evlist__set_filters(struct perf_evlist *evlist);
+int perf_evlist__apply_filters(struct perf_evlist *evlist);
 
-u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
-bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
-u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
+void __perf_evlist__set_leader(struct list_head *list);
+void perf_evlist__set_leader(struct perf_evlist *evlist);
+
+u64 perf_evlist__sample_type(struct perf_evlist *evlist);
+bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
+u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
 
 int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
-			      struct perf_sample *sample, bool swapped);
+			      struct perf_sample *sample);
 
-bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
-bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
+bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
+bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
 
 void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
 				   struct list_head *list,
 				   int nr_entries);
 
+static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist)
+{
+	return list_entry(evlist->entries.next, struct perf_evsel, node);
+}
+
+static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
+{
+	return list_entry(evlist->entries.prev, struct perf_evsel, node);
+}
+
+size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
 #endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2eaae14..ffdd94e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -8,7 +8,10 @@
  */
 
 #include <byteswap.h>
+#include <linux/bitops.h>
 #include "asm/bug.h"
+#include "debugfs.h"
+#include "event-parse.h"
 #include "evsel.h"
 #include "evlist.h"
 #include "util.h"
@@ -16,9 +19,10 @@
 #include "thread_map.h"
 #include "target.h"
 #include "../../../include/linux/hw_breakpoint.h"
+#include "../../include/linux/perf_event.h"
+#include "perf_regs.h"
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
-#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
 
 static int __perf_evsel__sample_size(u64 sample_type)
 {
@@ -66,7 +70,80 @@
 	return evsel;
 }
 
-static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
+struct event_format *event_format__new(const char *sys, const char *name)
+{
+	int fd, n;
+	char *filename;
+	void *bf = NULL, *nbf;
+	size_t size = 0, alloc_size = 0;
+	struct event_format *format = NULL;
+
+	if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
+		goto out;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		goto out_free_filename;
+
+	do {
+		if (size == alloc_size) {
+			alloc_size += BUFSIZ;
+			nbf = realloc(bf, alloc_size);
+			if (nbf == NULL)
+				goto out_free_bf;
+			bf = nbf;
+		}
+
+		n = read(fd, bf + size, BUFSIZ);
+		if (n < 0)
+			goto out_free_bf;
+		size += n;
+	} while (n > 0);
+
+	pevent_parse_format(&format, bf, size, sys);
+
+out_free_bf:
+	free(bf);
+	close(fd);
+out_free_filename:
+	free(filename);
+out:
+	return format;
+}
+
+struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx)
+{
+	struct perf_evsel *evsel = zalloc(sizeof(*evsel));
+
+	if (evsel != NULL) {
+		struct perf_event_attr attr = {
+			.type	       = PERF_TYPE_TRACEPOINT,
+			.sample_type   = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
+					  PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),
+		};
+
+		if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
+			goto out_free;
+
+		evsel->tp_format = event_format__new(sys, name);
+		if (evsel->tp_format == NULL)
+			goto out_free;
+
+		event_attr_init(&attr);
+		attr.config = evsel->tp_format->id;
+		attr.sample_period = 1;
+		perf_evsel__init(evsel, &attr, idx);
+	}
+
+	return evsel;
+
+out_free:
+	free(evsel->name);
+	free(evsel);
+	return NULL;
+}
+
+const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
 	"cycles",
 	"instructions",
 	"cache-references",
@@ -129,12 +206,12 @@
 	return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
 }
 
-static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
+const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
 	"cpu-clock",
 	"task-clock",
 	"page-faults",
 	"context-switches",
-	"CPU-migrations",
+	"cpu-migrations",
 	"minor-faults",
 	"major-faults",
 	"alignment-faults",
@@ -317,7 +394,8 @@
 		break;
 
 	default:
-		scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
+		scnprintf(bf, sizeof(bf), "unknown attr type: %d",
+			  evsel->attr.type);
 		break;
 	}
 
@@ -367,9 +445,18 @@
 		attr->mmap_data = track;
 	}
 
-	if (opts->call_graph)
+	if (opts->call_graph) {
 		attr->sample_type	|= PERF_SAMPLE_CALLCHAIN;
 
+		if (opts->call_graph == CALLCHAIN_DWARF) {
+			attr->sample_type |= PERF_SAMPLE_REGS_USER |
+					     PERF_SAMPLE_STACK_USER;
+			attr->sample_regs_user = PERF_REGS_MASK;
+			attr->sample_stack_user = opts->stack_dump_size;
+			attr->exclude_callchain_user = 1;
+		}
+	}
+
 	if (perf_target__has_cpu(&opts->target))
 		attr->sample_type	|= PERF_SAMPLE_CPU;
 
@@ -421,6 +508,24 @@
 	return evsel->fd != NULL ? 0 : -ENOMEM;
 }
 
+int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
+			   const char *filter)
+{
+	int cpu, thread;
+
+	for (cpu = 0; cpu < ncpus; cpu++) {
+		for (thread = 0; thread < nthreads; thread++) {
+			int fd = FD(evsel, cpu, thread),
+			    err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
+
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -481,6 +586,9 @@
 {
 	perf_evsel__exit(evsel);
 	close_cgroup(evsel->cgrp);
+	free(evsel->group_name);
+	if (evsel->tp_format)
+		pevent_free_format(evsel->tp_format);
 	free(evsel->name);
 	free(evsel);
 }
@@ -556,9 +664,28 @@
 	return 0;
 }
 
+static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
+{
+	struct perf_evsel *leader = evsel->leader;
+	int fd;
+
+	if (!leader)
+		return -1;
+
+	/*
+	 * Leader must be already processed/open,
+	 * if not it's a bug.
+	 */
+	BUG_ON(!leader->fd);
+
+	fd = FD(leader, cpu, thread);
+	BUG_ON(fd == -1);
+
+	return fd;
+}
+
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-			      struct thread_map *threads, bool group,
-			      struct xyarray *group_fds)
+			      struct thread_map *threads)
 {
 	int cpu, thread;
 	unsigned long flags = 0;
@@ -574,13 +701,15 @@
 	}
 
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
-		int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
 
 		for (thread = 0; thread < threads->nr; thread++) {
+			int group_fd;
 
 			if (!evsel->cgrp)
 				pid = threads->map[thread];
 
+			group_fd = get_group_fd(evsel, cpu, thread);
+
 			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
 								     pid,
 								     cpus->map[cpu],
@@ -589,9 +718,6 @@
 				err = -errno;
 				goto out_close;
 			}
-
-			if (group && group_fd == -1)
-				group_fd = FD(evsel, cpu, thread);
 		}
 	}
 
@@ -635,8 +761,7 @@
 };
 
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-		     struct thread_map *threads, bool group,
-		     struct xyarray *group_fd)
+		     struct thread_map *threads)
 {
 	if (cpus == NULL) {
 		/* Work around old compiler warnings about strict aliasing */
@@ -646,30 +771,28 @@
 	if (threads == NULL)
 		threads = &empty_thread_map.map;
 
-	return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
+	return __perf_evsel__open(evsel, cpus, threads);
 }
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-			     struct cpu_map *cpus, bool group,
-			     struct xyarray *group_fd)
+			     struct cpu_map *cpus)
 {
-	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
-				  group_fd);
+	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
 }
 
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-				struct thread_map *threads, bool group,
-				struct xyarray *group_fd)
+				struct thread_map *threads)
 {
-	return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
-				  group_fd);
+	return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
 }
 
-static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
-				       struct perf_sample *sample,
-				       bool swapped)
+static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
+				       const union perf_event *event,
+				       struct perf_sample *sample)
 {
+	u64 type = evsel->attr.sample_type;
 	const u64 *array = event->sample.array;
+	bool swapped = evsel->needs_swap;
 	union u64_swap u;
 
 	array += ((event->header.size -
@@ -730,9 +853,11 @@
 }
 
 int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
-			     struct perf_sample *data, bool swapped)
+			     struct perf_sample *data)
 {
 	u64 type = evsel->attr.sample_type;
+	u64 regs_user = evsel->attr.sample_regs_user;
+	bool swapped = evsel->needs_swap;
 	const u64 *array;
 
 	/*
@@ -749,7 +874,7 @@
 	if (event->header.type != PERF_RECORD_SAMPLE) {
 		if (!evsel->attr.sample_id_all)
 			return 0;
-		return perf_event__parse_id_sample(event, type, data, swapped);
+		return perf_evsel__parse_id_sample(evsel, event, data);
 	}
 
 	array = event->sample.array;
@@ -869,6 +994,32 @@
 		sz /= sizeof(u64);
 		array += sz;
 	}
+
+	if (type & PERF_SAMPLE_REGS_USER) {
+		/* First u64 tells us if we have any regs in sample. */
+		u64 avail = *array++;
+
+		if (avail) {
+			data->user_regs.regs = (u64 *)array;
+			array += hweight_long(regs_user);
+		}
+	}
+
+	if (type & PERF_SAMPLE_STACK_USER) {
+		u64 size = *array++;
+
+		data->user_stack.offset = ((char *)(array - 1)
+					  - (char *) event);
+
+		if (!size) {
+			data->user_stack.size = 0;
+		} else {
+			data->user_stack.data = (char *)array;
+			array += size / sizeof(*array);
+			data->user_stack.size = *array;
+		}
+	}
+
 	return 0;
 }
 
@@ -947,3 +1098,72 @@
 
 	return 0;
 }
+
+struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name)
+{
+	return pevent_find_field(evsel->tp_format, name);
+}
+
+void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
+			 const char *name)
+{
+	struct format_field *field = perf_evsel__field(evsel, name);
+	int offset;
+
+	if (!field)
+		return NULL;
+
+	offset = field->offset;
+
+	if (field->flags & FIELD_IS_DYNAMIC) {
+		offset = *(int *)(sample->raw_data + field->offset);
+		offset &= 0xffff;
+	}
+
+	return sample->raw_data + offset;
+}
+
+u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
+		       const char *name)
+{
+	struct format_field *field = perf_evsel__field(evsel, name);
+	void *ptr;
+	u64 value;
+
+	if (!field)
+		return 0;
+
+	ptr = sample->raw_data + field->offset;
+
+	switch (field->size) {
+	case 1:
+		return *(u8 *)ptr;
+	case 2:
+		value = *(u16 *)ptr;
+		break;
+	case 4:
+		value = *(u32 *)ptr;
+		break;
+	case 8:
+		value = *(u64 *)ptr;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!evsel->needs_swap)
+		return value;
+
+	switch (field->size) {
+	case 2:
+		return bswap_16(value);
+	case 4:
+		return bswap_32(value);
+	case 8:
+		return bswap_64(value);
+	default:
+		return 0;
+	}
+
+	return 0;
+}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b559929..3ead0d5 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -53,9 +53,10 @@
 	u64			*id;
 	struct perf_counts	*counts;
 	int			idx;
-	int			ids;
+	u32			ids;
 	struct hists		hists;
 	char			*name;
+	struct event_format	*tp_format;
 	union {
 		void		*priv;
 		off_t		id_offset;
@@ -65,8 +66,14 @@
 		void		*func;
 		void		*data;
 	} handler;
+	struct cpu_map		*cpus;
 	unsigned int		sample_size;
 	bool 			supported;
+	bool 			needs_swap;
+	/* parse modifier helper */
+	int			exclude_GH;
+	struct perf_evsel	*leader;
+	char			*group_name;
 };
 
 struct cpu_map;
@@ -75,6 +82,10 @@
 struct perf_record_opts;
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
+struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx);
+
+struct event_format *event_format__new(const char *sys, const char *name);
+
 void perf_evsel__init(struct perf_evsel *evsel,
 		      struct perf_event_attr *attr, int idx);
 void perf_evsel__exit(struct perf_evsel *evsel);
@@ -92,8 +103,10 @@
 				       [PERF_EVSEL__MAX_ALIASES];
 extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
 					  [PERF_EVSEL__MAX_ALIASES];
-const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
-				       [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+					      [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX];
+extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
 int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
 					    char *bf, size_t size);
 const char *perf_evsel__name(struct perf_evsel *evsel);
@@ -105,21 +118,46 @@
 void perf_evsel__free_id(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
+int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
+			   const char *filter);
+
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-			     struct cpu_map *cpus, bool group,
-			     struct xyarray *group_fds);
+			     struct cpu_map *cpus);
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-				struct thread_map *threads, bool group,
-				struct xyarray *group_fds);
+				struct thread_map *threads);
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-		     struct thread_map *threads, bool group,
-		     struct xyarray *group_fds);
+		     struct thread_map *threads);
 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
 
+struct perf_sample;
+
+void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
+			 const char *name);
+u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
+		       const char *name);
+
+static inline char *perf_evsel__strval(struct perf_evsel *evsel,
+				       struct perf_sample *sample,
+				       const char *name)
+{
+	return perf_evsel__rawptr(evsel, sample, name);
+}
+
+struct format_field;
+
+struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name);
+
 #define perf_evsel__match(evsel, t, c)		\
 	(evsel->attr.type == PERF_TYPE_##t &&	\
 	 evsel->attr.config == PERF_COUNT_##c)
 
+static inline bool perf_evsel__match2(struct perf_evsel *e1,
+				      struct perf_evsel *e2)
+{
+	return (e1->attr.type == e2->attr.type) &&
+	       (e1->attr.config == e2->attr.config);
+}
+
 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
 			      int cpu, int thread, bool scale);
 
@@ -181,5 +219,10 @@
 void hists__init(struct hists *hists);
 
 int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
-			     struct perf_sample *sample, bool swapped);
+			     struct perf_sample *sample);
+
+static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
+{
+	return list_entry(evsel->node.next, struct perf_evsel, node);
+}
 #endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index f06f6fd..389590c 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -21,4 +21,19 @@
 	    p
      }' "Documentation/perf-$cmd.txt"
 done
+
+echo "#ifndef NO_LIBELF_SUPPORT"
+sed -n -e 's/^perf-\([^ 	]*\)[ 	].* full.*/\1/p' command-list.txt |
+sort |
+while read cmd
+do
+     sed -n '
+     /^NAME/,/perf-'"$cmd"'/H
+     ${
+            x
+            s/.*perf-'"$cmd"' - \(.*\)/  {"'"$cmd"'", "\1"},/
+	    p
+     }' "Documentation/perf-$cmd.txt"
+done
+echo "#endif /* NO_LIBELF_SUPPORT */"
 echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 74ea3c2f..7daad23 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -20,11 +20,14 @@
 #include "symbol.h"
 #include "debug.h"
 #include "cpumap.h"
+#include "pmu.h"
+#include "vdso.h"
+#include "strbuf.h"
 
 static bool no_buildid_cache = false;
 
-static int event_count;
-static struct perf_trace_event_type *events;
+static int trace_event_count;
+static struct perf_trace_event_type *trace_events;
 
 static u32 header_argc;
 static const char **header_argv;
@@ -36,24 +39,24 @@
 	if (strlen(name) > MAX_EVENT_NAME)
 		pr_warning("Event %s will be truncated\n", name);
 
-	nevents = realloc(events, (event_count + 1) * sizeof(*events));
+	nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
 	if (nevents == NULL)
 		return -ENOMEM;
-	events = nevents;
+	trace_events = nevents;
 
-	memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
-	events[event_count].event_id = id;
-	strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
-	event_count++;
+	memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
+	trace_events[trace_event_count].event_id = id;
+	strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
+	trace_event_count++;
 	return 0;
 }
 
 char *perf_header__find_event(u64 id)
 {
 	int i;
-	for (i = 0 ; i < event_count; i++) {
-		if (events[i].event_id == id)
-			return events[i].name;
+	for (i = 0 ; i < trace_event_count; i++) {
+		if (trace_events[i].event_id == id)
+			return trace_events[i].name;
 	}
 	return NULL;
 }
@@ -128,7 +131,7 @@
 	int ret;
 
 	olen = strlen(str) + 1;
-	len = ALIGN(olen, NAME_ALIGN);
+	len = PERF_ALIGN(olen, NAME_ALIGN);
 
 	/* write len, incl. \0 */
 	ret = do_write(fd, &len, sizeof(len));
@@ -206,6 +209,29 @@
 			continue;		\
 		else
 
+static int write_buildid(char *name, size_t name_len, u8 *build_id,
+			 pid_t pid, u16 misc, int fd)
+{
+	int err;
+	struct build_id_event b;
+	size_t len;
+
+	len = name_len + 1;
+	len = PERF_ALIGN(len, NAME_ALIGN);
+
+	memset(&b, 0, sizeof(b));
+	memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+	b.pid = pid;
+	b.header.misc = misc;
+	b.header.size = sizeof(b) + len;
+
+	err = do_write(fd, &b, sizeof(b));
+	if (err < 0)
+		return err;
+
+	return write_padded(fd, name, name_len + 1, len);
+}
+
 static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
 				u16 misc, int fd)
 {
@@ -213,24 +239,23 @@
 
 	dsos__for_each_with_build_id(pos, head) {
 		int err;
-		struct build_id_event b;
-		size_t len;
+		char  *name;
+		size_t name_len;
 
 		if (!pos->hit)
 			continue;
-		len = pos->long_name_len + 1;
-		len = ALIGN(len, NAME_ALIGN);
-		memset(&b, 0, sizeof(b));
-		memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
-		b.pid = pid;
-		b.header.misc = misc;
-		b.header.size = sizeof(b) + len;
-		err = do_write(fd, &b, sizeof(b));
-		if (err < 0)
-			return err;
-		err = write_padded(fd, pos->long_name,
-				   pos->long_name_len + 1, len);
-		if (err < 0)
+
+		if (is_vdso_map(pos->short_name)) {
+			name = (char *) VDSO__MAP_NAME;
+			name_len = sizeof(VDSO__MAP_NAME) + 1;
+		} else {
+			name = pos->long_name;
+			name_len = pos->long_name_len + 1;
+		}
+
+		err = write_buildid(name, name_len, pos->build_id,
+				    pid, misc, fd);
+		if (err)
 			return err;
 	}
 
@@ -276,19 +301,20 @@
 }
 
 int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
-			  const char *name, bool is_kallsyms)
+			  const char *name, bool is_kallsyms, bool is_vdso)
 {
 	const size_t size = PATH_MAX;
 	char *realname, *filename = zalloc(size),
 	     *linkname = zalloc(size), *targetname;
 	int len, err = -1;
+	bool slash = is_kallsyms || is_vdso;
 
 	if (is_kallsyms) {
 		if (symbol_conf.kptr_restrict) {
 			pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
 			return 0;
 		}
-		realname = (char *)name;
+		realname = (char *) name;
 	} else
 		realname = realpath(name, NULL);
 
@@ -296,7 +322,8 @@
 		goto out_free;
 
 	len = scnprintf(filename, size, "%s%s%s",
-		       debugdir, is_kallsyms ? "/" : "", realname);
+		       debugdir, slash ? "/" : "",
+		       is_vdso ? VDSO__MAP_NAME : realname);
 	if (mkdir_p(filename, 0755))
 		goto out_free;
 
@@ -332,13 +359,14 @@
 
 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 				 const char *name, const char *debugdir,
-				 bool is_kallsyms)
+				 bool is_kallsyms, bool is_vdso)
 {
 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
 
 	build_id__sprintf(build_id, build_id_size, sbuild_id);
 
-	return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
+	return build_id_cache__add_s(sbuild_id, debugdir, name,
+				     is_kallsyms, is_vdso);
 }
 
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
@@ -382,9 +410,11 @@
 static int dso__cache_build_id(struct dso *dso, const char *debugdir)
 {
 	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_vdso = is_vdso_map(dso->short_name);
 
 	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
-				     dso->long_name, debugdir, is_kallsyms);
+				     dso->long_name, debugdir,
+				     is_kallsyms, is_vdso);
 }
 
 static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -446,7 +476,7 @@
 	return ret;
 }
 
-static int write_tracing_data(int fd, struct perf_header *h __used,
+static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
 			    struct perf_evlist *evlist)
 {
 	return read_tracing_data(fd, &evlist->entries);
@@ -454,7 +484,7 @@
 
 
 static int write_build_id(int fd, struct perf_header *h,
-			  struct perf_evlist *evlist __used)
+			  struct perf_evlist *evlist __maybe_unused)
 {
 	struct perf_session *session;
 	int err;
@@ -475,8 +505,8 @@
 	return 0;
 }
 
-static int write_hostname(int fd, struct perf_header *h __used,
-			  struct perf_evlist *evlist __used)
+static int write_hostname(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
 {
 	struct utsname uts;
 	int ret;
@@ -488,8 +518,8 @@
 	return do_write_string(fd, uts.nodename);
 }
 
-static int write_osrelease(int fd, struct perf_header *h __used,
-			   struct perf_evlist *evlist __used)
+static int write_osrelease(int fd, struct perf_header *h __maybe_unused,
+			   struct perf_evlist *evlist __maybe_unused)
 {
 	struct utsname uts;
 	int ret;
@@ -501,8 +531,8 @@
 	return do_write_string(fd, uts.release);
 }
 
-static int write_arch(int fd, struct perf_header *h __used,
-		      struct perf_evlist *evlist __used)
+static int write_arch(int fd, struct perf_header *h __maybe_unused,
+		      struct perf_evlist *evlist __maybe_unused)
 {
 	struct utsname uts;
 	int ret;
@@ -514,14 +544,14 @@
 	return do_write_string(fd, uts.machine);
 }
 
-static int write_version(int fd, struct perf_header *h __used,
-			 struct perf_evlist *evlist __used)
+static int write_version(int fd, struct perf_header *h __maybe_unused,
+			 struct perf_evlist *evlist __maybe_unused)
 {
 	return do_write_string(fd, perf_version_string);
 }
 
-static int write_cpudesc(int fd, struct perf_header *h __used,
-		       struct perf_evlist *evlist __used)
+static int write_cpudesc(int fd, struct perf_header *h __maybe_unused,
+		       struct perf_evlist *evlist __maybe_unused)
 {
 #ifndef CPUINFO_PROC
 #define CPUINFO_PROC NULL
@@ -579,8 +609,8 @@
 	return ret;
 }
 
-static int write_nrcpus(int fd, struct perf_header *h __used,
-			struct perf_evlist *evlist __used)
+static int write_nrcpus(int fd, struct perf_header *h __maybe_unused,
+			struct perf_evlist *evlist __maybe_unused)
 {
 	long nr;
 	u32 nrc, nra;
@@ -605,15 +635,14 @@
 	return do_write(fd, &nra, sizeof(nra));
 }
 
-static int write_event_desc(int fd, struct perf_header *h __used,
+static int write_event_desc(int fd, struct perf_header *h __maybe_unused,
 			    struct perf_evlist *evlist)
 {
-	struct perf_evsel *attr;
-	u32 nre = 0, nri, sz;
+	struct perf_evsel *evsel;
+	u32 nre, nri, sz;
 	int ret;
 
-	list_for_each_entry(attr, &evlist->entries, node)
-		nre++;
+	nre = evlist->nr_entries;
 
 	/*
 	 * write number of events
@@ -625,14 +654,14 @@
 	/*
 	 * size of perf_event_attr struct
 	 */
-	sz = (u32)sizeof(attr->attr);
+	sz = (u32)sizeof(evsel->attr);
 	ret = do_write(fd, &sz, sizeof(sz));
 	if (ret < 0)
 		return ret;
 
-	list_for_each_entry(attr, &evlist->entries, node) {
+	list_for_each_entry(evsel, &evlist->entries, node) {
 
-		ret = do_write(fd, &attr->attr, sz);
+		ret = do_write(fd, &evsel->attr, sz);
 		if (ret < 0)
 			return ret;
 		/*
@@ -642,7 +671,7 @@
 		 * copy into an nri to be independent of the
 		 * type of ids,
 		 */
-		nri = attr->ids;
+		nri = evsel->ids;
 		ret = do_write(fd, &nri, sizeof(nri));
 		if (ret < 0)
 			return ret;
@@ -650,21 +679,21 @@
 		/*
 		 * write event string as passed on cmdline
 		 */
-		ret = do_write_string(fd, perf_evsel__name(attr));
+		ret = do_write_string(fd, perf_evsel__name(evsel));
 		if (ret < 0)
 			return ret;
 		/*
 		 * write unique ids for this event
 		 */
-		ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
+		ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
 		if (ret < 0)
 			return ret;
 	}
 	return 0;
 }
 
-static int write_cmdline(int fd, struct perf_header *h __used,
-			 struct perf_evlist *evlist __used)
+static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
+			 struct perf_evlist *evlist __maybe_unused)
 {
 	char buf[MAXPATHLEN];
 	char proc[32];
@@ -832,8 +861,8 @@
 	return tp;
 }
 
-static int write_cpu_topology(int fd, struct perf_header *h __used,
-			  struct perf_evlist *evlist __used)
+static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
 {
 	struct cpu_topo *tp;
 	u32 i;
@@ -868,8 +897,8 @@
 
 
 
-static int write_total_mem(int fd, struct perf_header *h __used,
-			  struct perf_evlist *evlist __used)
+static int write_total_mem(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
 {
 	char *buf = NULL;
 	FILE *fp;
@@ -954,8 +983,8 @@
 	return ret;
 }
 
-static int write_numa_topology(int fd, struct perf_header *h __used,
-			  struct perf_evlist *evlist __used)
+static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
 {
 	char *buf = NULL;
 	size_t len = 0;
@@ -1004,16 +1033,56 @@
 }
 
 /*
+ * File format:
+ *
+ * struct pmu_mappings {
+ *	u32	pmu_num;
+ *	struct pmu_map {
+ *		u32	type;
+ *		char	name[];
+ *	}[pmu_num];
+ * };
+ */
+
+static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
+			      struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_pmu *pmu = NULL;
+	off_t offset = lseek(fd, 0, SEEK_CUR);
+	__u32 pmu_num = 0;
+
+	/* write real pmu_num later */
+	do_write(fd, &pmu_num, sizeof(pmu_num));
+
+	while ((pmu = perf_pmu__scan(pmu))) {
+		if (!pmu->name)
+			continue;
+		pmu_num++;
+		do_write(fd, &pmu->type, sizeof(pmu->type));
+		do_write_string(fd, pmu->name);
+	}
+
+	if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
+		/* discard all */
+		lseek(fd, offset, SEEK_SET);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
  * default get_cpuid(): nothing gets recorded
  * actual implementation must be in arch/$(ARCH)/util/header.c
  */
-int __attribute__((weak)) get_cpuid(char *buffer __used, size_t sz __used)
+int __attribute__ ((weak)) get_cpuid(char *buffer __maybe_unused,
+				     size_t sz __maybe_unused)
 {
 	return -1;
 }
 
-static int write_cpuid(int fd, struct perf_header *h __used,
-		       struct perf_evlist *evlist __used)
+static int write_cpuid(int fd, struct perf_header *h __maybe_unused,
+		       struct perf_evlist *evlist __maybe_unused)
 {
 	char buffer[64];
 	int ret;
@@ -1027,133 +1096,113 @@
 	return do_write_string(fd, buffer);
 }
 
-static int write_branch_stack(int fd __used, struct perf_header *h __used,
-		       struct perf_evlist *evlist __used)
+static int write_branch_stack(int fd __maybe_unused,
+			      struct perf_header *h __maybe_unused,
+		       struct perf_evlist *evlist __maybe_unused)
 {
 	return 0;
 }
 
-static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
+static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
+			   FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# hostname : %s\n", str);
-	free(str);
+	fprintf(fp, "# hostname : %s\n", ph->env.hostname);
 }
 
-static void print_osrelease(struct perf_header *ph, int fd, FILE *fp)
+static void print_osrelease(struct perf_header *ph, int fd __maybe_unused,
+			    FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# os release : %s\n", str);
-	free(str);
+	fprintf(fp, "# os release : %s\n", ph->env.os_release);
 }
 
-static void print_arch(struct perf_header *ph, int fd, FILE *fp)
+static void print_arch(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# arch : %s\n", str);
-	free(str);
+	fprintf(fp, "# arch : %s\n", ph->env.arch);
 }
 
-static void print_cpudesc(struct perf_header *ph, int fd, FILE *fp)
+static void print_cpudesc(struct perf_header *ph, int fd __maybe_unused,
+			  FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# cpudesc : %s\n", str);
-	free(str);
+	fprintf(fp, "# cpudesc : %s\n", ph->env.cpu_desc);
 }
 
-static void print_nrcpus(struct perf_header *ph, int fd, FILE *fp)
+static void print_nrcpus(struct perf_header *ph, int fd __maybe_unused,
+			 FILE *fp)
 {
-	ssize_t ret;
-	u32 nr;
-
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		nr = -1; /* interpreted as error */
-
-	if (ph->needs_swap)
-		nr = bswap_32(nr);
-
-	fprintf(fp, "# nrcpus online : %u\n", nr);
-
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		nr = -1; /* interpreted as error */
-
-	if (ph->needs_swap)
-		nr = bswap_32(nr);
-
-	fprintf(fp, "# nrcpus avail : %u\n", nr);
+	fprintf(fp, "# nrcpus online : %u\n", ph->env.nr_cpus_online);
+	fprintf(fp, "# nrcpus avail : %u\n", ph->env.nr_cpus_avail);
 }
 
-static void print_version(struct perf_header *ph, int fd, FILE *fp)
+static void print_version(struct perf_header *ph, int fd __maybe_unused,
+			  FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# perf version : %s\n", str);
-	free(str);
+	fprintf(fp, "# perf version : %s\n", ph->env.version);
 }
 
-static void print_cmdline(struct perf_header *ph, int fd, FILE *fp)
+static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
+			  FILE *fp)
 {
-	ssize_t ret;
+	int nr, i;
 	char *str;
-	u32 nr, i;
 
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		return;
-
-	if (ph->needs_swap)
-		nr = bswap_32(nr);
+	nr = ph->env.nr_cmdline;
+	str = ph->env.cmdline;
 
 	fprintf(fp, "# cmdline : ");
 
 	for (i = 0; i < nr; i++) {
-		str = do_read_string(fd, ph);
 		fprintf(fp, "%s ", str);
-		free(str);
+		str += strlen(str) + 1;
 	}
 	fputc('\n', fp);
 }
 
-static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
+static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
+			       FILE *fp)
 {
-	ssize_t ret;
-	u32 nr, i;
+	int nr, i;
 	char *str;
 
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		return;
-
-	if (ph->needs_swap)
-		nr = bswap_32(nr);
+	nr = ph->env.nr_sibling_cores;
+	str = ph->env.sibling_cores;
 
 	for (i = 0; i < nr; i++) {
-		str = do_read_string(fd, ph);
 		fprintf(fp, "# sibling cores   : %s\n", str);
-		free(str);
+		str += strlen(str) + 1;
 	}
 
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		return;
-
-	if (ph->needs_swap)
-		nr = bswap_32(nr);
+	nr = ph->env.nr_sibling_threads;
+	str = ph->env.sibling_threads;
 
 	for (i = 0; i < nr; i++) {
-		str = do_read_string(fd, ph);
 		fprintf(fp, "# sibling threads : %s\n", str);
-		free(str);
+		str += strlen(str) + 1;
 	}
 }
 
-static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+static void free_event_desc(struct perf_evsel *events)
 {
-	struct perf_event_attr attr;
-	uint64_t id;
+	struct perf_evsel *evsel;
+
+	if (!events)
+		return;
+
+	for (evsel = events; evsel->attr.size; evsel++) {
+		if (evsel->name)
+			free(evsel->name);
+		if (evsel->id)
+			free(evsel->id);
+	}
+
+	free(events);
+}
+
+static struct perf_evsel *
+read_event_desc(struct perf_header *ph, int fd)
+{
+	struct perf_evsel *evsel, *events = NULL;
+	u64 *id;
 	void *buf = NULL;
-	char *str;
 	u32 nre, sz, nr, i, j;
 	ssize_t ret;
 	size_t msz;
@@ -1173,18 +1222,22 @@
 	if (ph->needs_swap)
 		sz = bswap_32(sz);
 
-	memset(&attr, 0, sizeof(attr));
-
 	/* buffer to hold on file attr struct */
 	buf = malloc(sz);
 	if (!buf)
 		goto error;
 
-	msz = sizeof(attr);
+	/* the last event terminates with evsel->attr.size == 0: */
+	events = calloc(nre + 1, sizeof(*events));
+	if (!events)
+		goto error;
+
+	msz = sizeof(evsel->attr);
 	if (sz < msz)
 		msz = sz;
 
-	for (i = 0 ; i < nre; i++) {
+	for (i = 0, evsel = events; i < nre; evsel++, i++) {
+		evsel->idx = i;
 
 		/*
 		 * must read entire on-file attr struct to
@@ -1197,146 +1250,188 @@
 		if (ph->needs_swap)
 			perf_event__attr_swap(buf);
 
-		memcpy(&attr, buf, msz);
+		memcpy(&evsel->attr, buf, msz);
 
 		ret = read(fd, &nr, sizeof(nr));
 		if (ret != (ssize_t)sizeof(nr))
 			goto error;
 
-		if (ph->needs_swap)
+		if (ph->needs_swap) {
 			nr = bswap_32(nr);
+			evsel->needs_swap = true;
+		}
 
-		str = do_read_string(fd, ph);
-		fprintf(fp, "# event : name = %s, ", str);
-		free(str);
+		evsel->name = do_read_string(fd, ph);
+
+		if (!nr)
+			continue;
+
+		id = calloc(nr, sizeof(*id));
+		if (!id)
+			goto error;
+		evsel->ids = nr;
+		evsel->id = id;
+
+		for (j = 0 ; j < nr; j++) {
+			ret = read(fd, id, sizeof(*id));
+			if (ret != (ssize_t)sizeof(*id))
+				goto error;
+			if (ph->needs_swap)
+				*id = bswap_64(*id);
+			id++;
+		}
+	}
+out:
+	if (buf)
+		free(buf);
+	return events;
+error:
+	if (events)
+		free_event_desc(events);
+	events = NULL;
+	goto out;
+}
+
+static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+{
+	struct perf_evsel *evsel, *events = read_event_desc(ph, fd);
+	u32 j;
+	u64 *id;
+
+	if (!events) {
+		fprintf(fp, "# event desc: not available or unable to read\n");
+		return;
+	}
+
+	for (evsel = events; evsel->attr.size; evsel++) {
+		fprintf(fp, "# event : name = %s, ", evsel->name);
 
 		fprintf(fp, "type = %d, config = 0x%"PRIx64
 			    ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
-				attr.type,
-				(u64)attr.config,
-				(u64)attr.config1,
-				(u64)attr.config2);
+				evsel->attr.type,
+				(u64)evsel->attr.config,
+				(u64)evsel->attr.config1,
+				(u64)evsel->attr.config2);
 
 		fprintf(fp, ", excl_usr = %d, excl_kern = %d",
-				attr.exclude_user,
-				attr.exclude_kernel);
+				evsel->attr.exclude_user,
+				evsel->attr.exclude_kernel);
 
 		fprintf(fp, ", excl_host = %d, excl_guest = %d",
-				attr.exclude_host,
-				attr.exclude_guest);
+				evsel->attr.exclude_host,
+				evsel->attr.exclude_guest);
 
-		fprintf(fp, ", precise_ip = %d", attr.precise_ip);
+		fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);
 
-		if (nr)
+		if (evsel->ids) {
 			fprintf(fp, ", id = {");
-
-		for (j = 0 ; j < nr; j++) {
-			ret = read(fd, &id, sizeof(id));
-			if (ret != (ssize_t)sizeof(id))
-				goto error;
-
-			if (ph->needs_swap)
-				id = bswap_64(id);
-
-			if (j)
-				fputc(',', fp);
-
-			fprintf(fp, " %"PRIu64, id);
-		}
-		if (nr && j == nr)
+			for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
+				if (j)
+					fputc(',', fp);
+				fprintf(fp, " %"PRIu64, *id);
+			}
 			fprintf(fp, " }");
+		}
+
 		fputc('\n', fp);
 	}
-	free(buf);
-	return;
-error:
-	fprintf(fp, "# event desc: not available or unable to read\n");
+
+	free_event_desc(events);
 }
 
-static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)
+static void print_total_mem(struct perf_header *ph, int fd __maybe_unused,
+			    FILE *fp)
 {
-	uint64_t mem;
-	ssize_t ret;
-
-	ret = read(fd, &mem, sizeof(mem));
-	if (ret != sizeof(mem))
-		goto error;
-
-	if (h->needs_swap)
-		mem = bswap_64(mem);
-
-	fprintf(fp, "# total memory : %"PRIu64" kB\n", mem);
-	return;
-error:
-	fprintf(fp, "# total memory : unknown\n");
+	fprintf(fp, "# total memory : %Lu kB\n", ph->env.total_mem);
 }
 
-static void print_numa_topology(struct perf_header *h __used, int fd, FILE *fp)
+static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused,
+				FILE *fp)
 {
-	ssize_t ret;
 	u32 nr, c, i;
-	char *str;
+	char *str, *tmp;
 	uint64_t mem_total, mem_free;
 
 	/* nr nodes */
-	ret = read(fd, &nr, sizeof(nr));
-	if (ret != (ssize_t)sizeof(nr))
-		goto error;
-
-	if (h->needs_swap)
-		nr = bswap_32(nr);
+	nr = ph->env.nr_numa_nodes;
+	str = ph->env.numa_nodes;
 
 	for (i = 0; i < nr; i++) {
-
 		/* node number */
-		ret = read(fd, &c, sizeof(c));
-		if (ret != (ssize_t)sizeof(c))
+		c = strtoul(str, &tmp, 0);
+		if (*tmp != ':')
 			goto error;
 
-		if (h->needs_swap)
-			c = bswap_32(c);
-
-		ret = read(fd, &mem_total, sizeof(u64));
-		if (ret != sizeof(u64))
+		str = tmp + 1;
+		mem_total = strtoull(str, &tmp, 0);
+		if (*tmp != ':')
 			goto error;
 
-		ret = read(fd, &mem_free, sizeof(u64));
-		if (ret != sizeof(u64))
+		str = tmp + 1;
+		mem_free = strtoull(str, &tmp, 0);
+		if (*tmp != ':')
 			goto error;
 
-		if (h->needs_swap) {
-			mem_total = bswap_64(mem_total);
-			mem_free = bswap_64(mem_free);
-		}
-
 		fprintf(fp, "# node%u meminfo  : total = %"PRIu64" kB,"
 			    " free = %"PRIu64" kB\n",
-			c,
-			mem_total,
-			mem_free);
+			c, mem_total, mem_free);
 
-		str = do_read_string(fd, h);
+		str = tmp + 1;
 		fprintf(fp, "# node%u cpu list : %s\n", c, str);
-		free(str);
 	}
 	return;
 error:
 	fprintf(fp, "# numa topology : not available\n");
 }
 
-static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
+static void print_cpuid(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
 {
-	char *str = do_read_string(fd, ph);
-	fprintf(fp, "# cpuid : %s\n", str);
-	free(str);
+	fprintf(fp, "# cpuid : %s\n", ph->env.cpuid);
 }
 
-static void print_branch_stack(struct perf_header *ph __used, int fd __used,
-			       FILE *fp)
+static void print_branch_stack(struct perf_header *ph __maybe_unused,
+			       int fd __maybe_unused, FILE *fp)
 {
 	fprintf(fp, "# contains samples with branch stack\n");
 }
 
+static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
+			       FILE *fp)
+{
+	const char *delimiter = "# pmu mappings: ";
+	char *str, *tmp;
+	u32 pmu_num;
+	u32 type;
+
+	pmu_num = ph->env.nr_pmu_mappings;
+	if (!pmu_num) {
+		fprintf(fp, "# pmu mappings: not available\n");
+		return;
+	}
+
+	str = ph->env.pmu_mappings;
+
+	while (pmu_num) {
+		type = strtoul(str, &tmp, 0);
+		if (*tmp != ':')
+			goto error;
+
+		str = tmp + 1;
+		fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type);
+
+		delimiter = ", ";
+		str += strlen(str) + 1;
+		pmu_num--;
+	}
+
+	fprintf(fp, "\n");
+
+	if (!pmu_num)
+		return;
+error:
+	fprintf(fp, "# pmu mappings: unable to read\n");
+}
+
 static int __event_process_build_id(struct build_id_event *bev,
 				    char *filename,
 				    struct perf_session *session)
@@ -1398,7 +1493,7 @@
 	struct perf_session *session = container_of(header, struct perf_session, header);
 	struct {
 		struct perf_event_header   header;
-		u8			   build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+		u8			   build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))];
 		char			   filename[0];
 	} old_bev;
 	struct build_id_event bev;
@@ -1487,28 +1582,375 @@
 	return err;
 }
 
-static int process_tracing_data(struct perf_file_section *section __unused,
-			      struct perf_header *ph __unused,
-			      int feat __unused, int fd, void *data)
+static int process_tracing_data(struct perf_file_section *section __maybe_unused,
+				struct perf_header *ph __maybe_unused,
+				int fd, void *data)
 {
 	trace_report(fd, data, false);
 	return 0;
 }
 
 static int process_build_id(struct perf_file_section *section,
-			    struct perf_header *ph,
-			    int feat __unused, int fd, void *data __used)
+			    struct perf_header *ph, int fd,
+			    void *data __maybe_unused)
 {
 	if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
 		pr_debug("Failed to read buildids, continuing...\n");
 	return 0;
 }
 
+static int process_hostname(struct perf_file_section *section __maybe_unused,
+			    struct perf_header *ph, int fd,
+			    void *data __maybe_unused)
+{
+	ph->env.hostname = do_read_string(fd, ph);
+	return ph->env.hostname ? 0 : -ENOMEM;
+}
+
+static int process_osrelease(struct perf_file_section *section __maybe_unused,
+			     struct perf_header *ph, int fd,
+			     void *data __maybe_unused)
+{
+	ph->env.os_release = do_read_string(fd, ph);
+	return ph->env.os_release ? 0 : -ENOMEM;
+}
+
+static int process_version(struct perf_file_section *section __maybe_unused,
+			   struct perf_header *ph, int fd,
+			   void *data __maybe_unused)
+{
+	ph->env.version = do_read_string(fd, ph);
+	return ph->env.version ? 0 : -ENOMEM;
+}
+
+static int process_arch(struct perf_file_section *section __maybe_unused,
+			struct perf_header *ph,	int fd,
+			void *data __maybe_unused)
+{
+	ph->env.arch = do_read_string(fd, ph);
+	return ph->env.arch ? 0 : -ENOMEM;
+}
+
+static int process_nrcpus(struct perf_file_section *section __maybe_unused,
+			  struct perf_header *ph, int fd,
+			  void *data __maybe_unused)
+{
+	size_t ret;
+	u32 nr;
+
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		return -1;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_cpus_online = nr;
+
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		return -1;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_cpus_avail = nr;
+	return 0;
+}
+
+static int process_cpudesc(struct perf_file_section *section __maybe_unused,
+			   struct perf_header *ph, int fd,
+			   void *data __maybe_unused)
+{
+	ph->env.cpu_desc = do_read_string(fd, ph);
+	return ph->env.cpu_desc ? 0 : -ENOMEM;
+}
+
+static int process_cpuid(struct perf_file_section *section __maybe_unused,
+			 struct perf_header *ph,  int fd,
+			 void *data __maybe_unused)
+{
+	ph->env.cpuid = do_read_string(fd, ph);
+	return ph->env.cpuid ? 0 : -ENOMEM;
+}
+
+static int process_total_mem(struct perf_file_section *section __maybe_unused,
+			     struct perf_header *ph, int fd,
+			     void *data __maybe_unused)
+{
+	uint64_t mem;
+	size_t ret;
+
+	ret = read(fd, &mem, sizeof(mem));
+	if (ret != sizeof(mem))
+		return -1;
+
+	if (ph->needs_swap)
+		mem = bswap_64(mem);
+
+	ph->env.total_mem = mem;
+	return 0;
+}
+
+static struct perf_evsel *
+perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
+{
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->idx == idx)
+			return evsel;
+	}
+
+	return NULL;
+}
+
+static void
+perf_evlist__set_event_name(struct perf_evlist *evlist,
+			    struct perf_evsel *event)
+{
+	struct perf_evsel *evsel;
+
+	if (!event->name)
+		return;
+
+	evsel = perf_evlist__find_by_index(evlist, event->idx);
+	if (!evsel)
+		return;
+
+	if (evsel->name)
+		return;
+
+	evsel->name = strdup(event->name);
+}
+
+static int
+process_event_desc(struct perf_file_section *section __maybe_unused,
+		   struct perf_header *header, int fd,
+		   void *data __maybe_unused)
+{
+	struct perf_session *session;
+	struct perf_evsel *evsel, *events = read_event_desc(header, fd);
+
+	if (!events)
+		return 0;
+
+	session = container_of(header, struct perf_session, header);
+	for (evsel = events; evsel->attr.size; evsel++)
+		perf_evlist__set_event_name(session->evlist, evsel);
+
+	free_event_desc(events);
+
+	return 0;
+}
+
+static int process_cmdline(struct perf_file_section *section __maybe_unused,
+			   struct perf_header *ph, int fd,
+			   void *data __maybe_unused)
+{
+	size_t ret;
+	char *str;
+	u32 nr, i;
+	struct strbuf sb;
+
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		return -1;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_cmdline = nr;
+	strbuf_init(&sb, 128);
+
+	for (i = 0; i < nr; i++) {
+		str = do_read_string(fd, ph);
+		if (!str)
+			goto error;
+
+		/* include a NULL character at the end */
+		strbuf_add(&sb, str, strlen(str) + 1);
+		free(str);
+	}
+	ph->env.cmdline = strbuf_detach(&sb, NULL);
+	return 0;
+
+error:
+	strbuf_release(&sb);
+	return -1;
+}
+
+static int process_cpu_topology(struct perf_file_section *section __maybe_unused,
+				struct perf_header *ph, int fd,
+				void *data __maybe_unused)
+{
+	size_t ret;
+	u32 nr, i;
+	char *str;
+	struct strbuf sb;
+
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		return -1;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_sibling_cores = nr;
+	strbuf_init(&sb, 128);
+
+	for (i = 0; i < nr; i++) {
+		str = do_read_string(fd, ph);
+		if (!str)
+			goto error;
+
+		/* include a NULL character at the end */
+		strbuf_add(&sb, str, strlen(str) + 1);
+		free(str);
+	}
+	ph->env.sibling_cores = strbuf_detach(&sb, NULL);
+
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		return -1;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_sibling_threads = nr;
+
+	for (i = 0; i < nr; i++) {
+		str = do_read_string(fd, ph);
+		if (!str)
+			goto error;
+
+		/* include a NULL character at the end */
+		strbuf_add(&sb, str, strlen(str) + 1);
+		free(str);
+	}
+	ph->env.sibling_threads = strbuf_detach(&sb, NULL);
+	return 0;
+
+error:
+	strbuf_release(&sb);
+	return -1;
+}
+
+static int process_numa_topology(struct perf_file_section *section __maybe_unused,
+				 struct perf_header *ph, int fd,
+				 void *data __maybe_unused)
+{
+	size_t ret;
+	u32 nr, node, i;
+	char *str;
+	uint64_t mem_total, mem_free;
+	struct strbuf sb;
+
+	/* nr nodes */
+	ret = read(fd, &nr, sizeof(nr));
+	if (ret != sizeof(nr))
+		goto error;
+
+	if (ph->needs_swap)
+		nr = bswap_32(nr);
+
+	ph->env.nr_numa_nodes = nr;
+	strbuf_init(&sb, 256);
+
+	for (i = 0; i < nr; i++) {
+		/* node number */
+		ret = read(fd, &node, sizeof(node));
+		if (ret != sizeof(node))
+			goto error;
+
+		ret = read(fd, &mem_total, sizeof(u64));
+		if (ret != sizeof(u64))
+			goto error;
+
+		ret = read(fd, &mem_free, sizeof(u64));
+		if (ret != sizeof(u64))
+			goto error;
+
+		if (ph->needs_swap) {
+			node = bswap_32(node);
+			mem_total = bswap_64(mem_total);
+			mem_free = bswap_64(mem_free);
+		}
+
+		strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":",
+			    node, mem_total, mem_free);
+
+		str = do_read_string(fd, ph);
+		if (!str)
+			goto error;
+
+		/* include a NULL character at the end */
+		strbuf_add(&sb, str, strlen(str) + 1);
+		free(str);
+	}
+	ph->env.numa_nodes = strbuf_detach(&sb, NULL);
+	return 0;
+
+error:
+	strbuf_release(&sb);
+	return -1;
+}
+
+static int process_pmu_mappings(struct perf_file_section *section __maybe_unused,
+				struct perf_header *ph, int fd,
+				void *data __maybe_unused)
+{
+	size_t ret;
+	char *name;
+	u32 pmu_num;
+	u32 type;
+	struct strbuf sb;
+
+	ret = read(fd, &pmu_num, sizeof(pmu_num));
+	if (ret != sizeof(pmu_num))
+		return -1;
+
+	if (ph->needs_swap)
+		pmu_num = bswap_32(pmu_num);
+
+	if (!pmu_num) {
+		pr_debug("pmu mappings not available\n");
+		return 0;
+	}
+
+	ph->env.nr_pmu_mappings = pmu_num;
+	strbuf_init(&sb, 128);
+
+	while (pmu_num) {
+		if (read(fd, &type, sizeof(type)) != sizeof(type))
+			goto error;
+		if (ph->needs_swap)
+			type = bswap_32(type);
+
+		name = do_read_string(fd, ph);
+		if (!name)
+			goto error;
+
+		strbuf_addf(&sb, "%u:%s", type, name);
+		/* include a NULL character at the end */
+		strbuf_add(&sb, "", 1);
+
+		free(name);
+		pmu_num--;
+	}
+	ph->env.pmu_mappings = strbuf_detach(&sb, NULL);
+	return 0;
+
+error:
+	strbuf_release(&sb);
+	return -1;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
 	int (*process)(struct perf_file_section *section,
-		       struct perf_header *h, int feat, int fd, void *data);
+		       struct perf_header *h, int fd, void *data);
 	const char *name;
 	bool full_only;
 };
@@ -1520,7 +1962,7 @@
 		.process = process_##func }
 #define FEAT_OPF(n, func) \
 	[n] = { .name = #n, .write = write_##func, .print = print_##func, \
-		.full_only = true }
+		.process = process_##func, .full_only = true }
 
 /* feature_ops not implemented: */
 #define print_tracing_data	NULL
@@ -1529,19 +1971,20 @@
 static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPP(HEADER_TRACING_DATA,	tracing_data),
 	FEAT_OPP(HEADER_BUILD_ID,	build_id),
-	FEAT_OPA(HEADER_HOSTNAME,	hostname),
-	FEAT_OPA(HEADER_OSRELEASE,	osrelease),
-	FEAT_OPA(HEADER_VERSION,	version),
-	FEAT_OPA(HEADER_ARCH,		arch),
-	FEAT_OPA(HEADER_NRCPUS,		nrcpus),
-	FEAT_OPA(HEADER_CPUDESC,	cpudesc),
-	FEAT_OPA(HEADER_CPUID,		cpuid),
-	FEAT_OPA(HEADER_TOTAL_MEM,	total_mem),
-	FEAT_OPA(HEADER_EVENT_DESC,	event_desc),
-	FEAT_OPA(HEADER_CMDLINE,	cmdline),
+	FEAT_OPP(HEADER_HOSTNAME,	hostname),
+	FEAT_OPP(HEADER_OSRELEASE,	osrelease),
+	FEAT_OPP(HEADER_VERSION,	version),
+	FEAT_OPP(HEADER_ARCH,		arch),
+	FEAT_OPP(HEADER_NRCPUS,		nrcpus),
+	FEAT_OPP(HEADER_CPUDESC,	cpudesc),
+	FEAT_OPP(HEADER_CPUID,		cpuid),
+	FEAT_OPP(HEADER_TOTAL_MEM,	total_mem),
+	FEAT_OPP(HEADER_EVENT_DESC,	event_desc),
+	FEAT_OPP(HEADER_CMDLINE,	cmdline),
 	FEAT_OPF(HEADER_CPU_TOPOLOGY,	cpu_topology),
 	FEAT_OPF(HEADER_NUMA_TOPOLOGY,	numa_topology),
 	FEAT_OPA(HEADER_BRANCH_STACK,	branch_stack),
+	FEAT_OPP(HEADER_PMU_MAPPINGS,	pmu_mappings),
 };
 
 struct header_print_data {
@@ -1683,17 +2126,17 @@
 	struct perf_file_header f_header;
 	struct perf_file_attr   f_attr;
 	struct perf_header *header = &session->header;
-	struct perf_evsel *attr, *pair = NULL;
+	struct perf_evsel *evsel, *pair = NULL;
 	int err;
 
 	lseek(fd, sizeof(f_header), SEEK_SET);
 
 	if (session->evlist != evlist)
-		pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
+		pair = perf_evlist__first(session->evlist);
 
-	list_for_each_entry(attr, &evlist->entries, node) {
-		attr->id_offset = lseek(fd, 0, SEEK_CUR);
-		err = do_write(fd, attr->id, attr->ids * sizeof(u64));
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		evsel->id_offset = lseek(fd, 0, SEEK_CUR);
+		err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
 		if (err < 0) {
 out_err_write:
 			pr_debug("failed to write perf header\n");
@@ -1703,19 +2146,19 @@
 			err = do_write(fd, pair->id, pair->ids * sizeof(u64));
 			if (err < 0)
 				goto out_err_write;
-			attr->ids += pair->ids;
-			pair = list_entry(pair->node.next, struct perf_evsel, node);
+			evsel->ids += pair->ids;
+			pair = perf_evsel__next(pair);
 		}
 	}
 
 	header->attr_offset = lseek(fd, 0, SEEK_CUR);
 
-	list_for_each_entry(attr, &evlist->entries, node) {
+	list_for_each_entry(evsel, &evlist->entries, node) {
 		f_attr = (struct perf_file_attr){
-			.attr = attr->attr,
+			.attr = evsel->attr,
 			.ids  = {
-				.offset = attr->id_offset,
-				.size   = attr->ids * sizeof(u64),
+				.offset = evsel->id_offset,
+				.size   = evsel->ids * sizeof(u64),
 			}
 		};
 		err = do_write(fd, &f_attr, sizeof(f_attr));
@@ -1726,9 +2169,9 @@
 	}
 
 	header->event_offset = lseek(fd, 0, SEEK_CUR);
-	header->event_size = event_count * sizeof(struct perf_trace_event_type);
-	if (events) {
-		err = do_write(fd, events, header->event_size);
+	header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
+	if (trace_events) {
+		err = do_write(fd, trace_events, header->event_size);
 		if (err < 0) {
 			pr_debug("failed to write perf header events\n");
 			return err;
@@ -1829,6 +2272,8 @@
 static const int attr_file_abi_sizes[] = {
 	[0] = PERF_ATTR_SIZE_VER0,
 	[1] = PERF_ATTR_SIZE_VER1,
+	[2] = PERF_ATTR_SIZE_VER2,
+	[3] = PERF_ATTR_SIZE_VER3,
 	0,
 };
 
@@ -2019,7 +2464,7 @@
 	if (!feat_ops[feat].process)
 		return 0;
 
-	return feat_ops[feat].process(section, ph, feat, fd, data);
+	return feat_ops[feat].process(section, ph, fd, data);
 }
 
 static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
@@ -2108,32 +2553,39 @@
 	return ret <= 0 ? -1 : 0;
 }
 
-static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel,
-					   struct pevent *pevent)
+static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
+						struct pevent *pevent)
 {
-	struct event_format *event = pevent_find_event(pevent,
-						       evsel->attr.config);
+	struct event_format *event;
 	char bf[128];
 
+	/* already prepared */
+	if (evsel->tp_format)
+		return 0;
+
+	event = pevent_find_event(pevent, evsel->attr.config);
 	if (event == NULL)
 		return -1;
 
-	snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
-	evsel->name = strdup(bf);
-	if (event->name == NULL)
-		return -1;
+	if (!evsel->name) {
+		snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
+		evsel->name = strdup(bf);
+		if (evsel->name == NULL)
+			return -1;
+	}
 
+	evsel->tp_format = event;
 	return 0;
 }
 
-static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist,
-					     struct pevent *pevent)
+static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
+						  struct pevent *pevent)
 {
 	struct perf_evsel *pos;
 
 	list_for_each_entry(pos, &evlist->entries, node) {
 		if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
-		    perf_evsel__set_tracepoint_name(pos, pevent))
+		    perf_evsel__prepare_tracepoint_event(pos, pevent))
 			return -1;
 	}
 
@@ -2176,6 +2628,8 @@
 
 		if (evsel == NULL)
 			goto out_delete_evlist;
+
+		evsel->needs_swap = header->needs_swap;
 		/*
 		 * Do it before so that if perf_evsel__alloc_id fails, this
 		 * entry gets purged too at perf_evlist__delete().
@@ -2207,13 +2661,13 @@
 
 	if (f_header.event_types.size) {
 		lseek(fd, f_header.event_types.offset, SEEK_SET);
-		events = malloc(f_header.event_types.size);
-		if (events == NULL)
+		trace_events = malloc(f_header.event_types.size);
+		if (trace_events == NULL)
 			return -ENOMEM;
-		if (perf_header__getbuffer64(header, fd, events,
+		if (perf_header__getbuffer64(header, fd, trace_events,
 					     f_header.event_types.size))
 			goto out_errno;
-		event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
+		trace_event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
 	}
 
 	perf_header__process_sections(header, fd, &session->pevent,
@@ -2221,7 +2675,8 @@
 
 	lseek(fd, header->data_offset, SEEK_SET);
 
-	if (perf_evlist__set_tracepoint_names(session->evlist, session->pevent))
+	if (perf_evlist__prepare_tracepoint_events(session->evlist,
+						   session->pevent))
 		goto out_delete_evlist;
 
 	header->frozen = 1;
@@ -2236,7 +2691,7 @@
 }
 
 int perf_event__synthesize_attr(struct perf_tool *tool,
-				struct perf_event_attr *attr, u16 ids, u64 *id,
+				struct perf_event_attr *attr, u32 ids, u64 *id,
 				perf_event__handler_t process)
 {
 	union perf_event *ev;
@@ -2244,7 +2699,7 @@
 	int err;
 
 	size = sizeof(struct perf_event_attr);
-	size = ALIGN(size, sizeof(u64));
+	size = PERF_ALIGN(size, sizeof(u64));
 	size += sizeof(struct perf_event_header);
 	size += ids * sizeof(u64);
 
@@ -2257,9 +2712,12 @@
 	memcpy(ev->attr.id, id, ids * sizeof(u64));
 
 	ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
-	ev->attr.header.size = size;
+	ev->attr.header.size = (u16)size;
 
-	err = process(tool, ev, NULL, NULL);
+	if (ev->attr.header.size == size)
+		err = process(tool, ev, NULL, NULL);
+	else
+		err = -E2BIG;
 
 	free(ev);
 
@@ -2270,12 +2728,12 @@
 				   struct perf_session *session,
 				   perf_event__handler_t process)
 {
-	struct perf_evsel *attr;
+	struct perf_evsel *evsel;
 	int err = 0;
 
-	list_for_each_entry(attr, &session->evlist->entries, node) {
-		err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
-						  attr->id, process);
+	list_for_each_entry(evsel, &session->evlist->entries, node) {
+		err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
+						  evsel->id, process);
 		if (err) {
 			pr_debug("failed to create perf header attribute\n");
 			return err;
@@ -2288,7 +2746,7 @@
 int perf_event__process_attr(union perf_event *event,
 			     struct perf_evlist **pevlist)
 {
-	unsigned int i, ids, n_ids;
+	u32 i, ids, n_ids;
 	struct perf_evsel *evsel;
 	struct perf_evlist *evlist = *pevlist;
 
@@ -2339,7 +2797,7 @@
 
 	ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
 	size = strlen(ev.event_type.event_type.name);
-	size = ALIGN(size, sizeof(u64));
+	size = PERF_ALIGN(size, sizeof(u64));
 	ev.event_type.header.size = sizeof(ev.event_type) -
 		(sizeof(ev.event_type.event_type.name) - size);
 
@@ -2355,8 +2813,8 @@
 	struct perf_trace_event_type *type;
 	int i, err = 0;
 
-	for (i = 0; i < event_count; i++) {
-		type = &events[i];
+	for (i = 0; i < trace_event_count; i++) {
+		type = &trace_events[i];
 
 		err = perf_event__synthesize_event_type(tool, type->event_id,
 							type->name, process,
@@ -2370,7 +2828,7 @@
 	return err;
 }
 
-int perf_event__process_event_type(struct perf_tool *tool __unused,
+int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
 				   union perf_event *event)
 {
 	if (perf_header__push_event(event->event_type.event_type.event_id,
@@ -2387,7 +2845,7 @@
 	union perf_event ev;
 	struct tracing_data *tdata;
 	ssize_t size = 0, aligned_size = 0, padding;
-	int err __used = 0;
+	int err __maybe_unused = 0;
 
 	/*
 	 * We are going to store the size of the data followed
@@ -2408,7 +2866,7 @@
 
 	ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
 	size = tdata->size;
-	aligned_size = ALIGN(size, sizeof(u64));
+	aligned_size = PERF_ALIGN(size, sizeof(u64));
 	padding = aligned_size - size;
 	ev.tracing_data.header.size = sizeof(ev.tracing_data);
 	ev.tracing_data.size = aligned_size;
@@ -2439,7 +2897,7 @@
 
 	size_read = trace_report(session->fd, &session->pevent,
 				 session->repipe);
-	padding = ALIGN(size_read, sizeof(u64)) - size_read;
+	padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
 
 	if (read(session->fd, buf, padding) < 0)
 		die("reading input file");
@@ -2452,6 +2910,9 @@
 	if (size_read + padding != size)
 		die("tracing data size mismatch");
 
+	perf_evlist__prepare_tracepoint_events(session->evlist,
+					       session->pevent);
+
 	return size_read + padding;
 }
 
@@ -2470,7 +2931,7 @@
 	memset(&ev, 0, sizeof(ev));
 
 	len = pos->long_name_len + 1;
-	len = ALIGN(len, NAME_ALIGN);
+	len = PERF_ALIGN(len, NAME_ALIGN);
 	memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
 	ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
 	ev.build_id.header.misc = misc;
@@ -2483,7 +2944,7 @@
 	return err;
 }
 
-int perf_event__process_build_id(struct perf_tool *tool __used,
+int perf_event__process_build_id(struct perf_tool *tool __maybe_unused,
 				 union perf_event *event,
 				 struct perf_session *session)
 {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2d42b3e..99bdd3a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -28,6 +28,7 @@
 	HEADER_CPU_TOPOLOGY,
 	HEADER_NUMA_TOPOLOGY,
 	HEADER_BRANCH_STACK,
+	HEADER_PMU_MAPPINGS,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
@@ -57,6 +58,29 @@
 int perf_file_header__read(struct perf_file_header *header,
 			   struct perf_header *ph, int fd);
 
+struct perf_session_env {
+	char			*hostname;
+	char			*os_release;
+	char			*version;
+	char			*arch;
+	int			nr_cpus_online;
+	int			nr_cpus_avail;
+	char			*cpu_desc;
+	char			*cpuid;
+	unsigned long long	total_mem;
+
+	int			nr_cmdline;
+	char			*cmdline;
+	int			nr_sibling_cores;
+	char			*sibling_cores;
+	int			nr_sibling_threads;
+	char			*sibling_threads;
+	int			nr_numa_nodes;
+	char			*numa_nodes;
+	int			nr_pmu_mappings;
+	char			*pmu_mappings;
+};
+
 struct perf_header {
 	int			frozen;
 	bool			needs_swap;
@@ -66,6 +90,7 @@
 	u64			event_offset;
 	u64			event_size;
 	DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
+	struct perf_session_env env;
 };
 
 struct perf_evlist;
@@ -95,11 +120,11 @@
 int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
 
 int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
-			  const char *name, bool is_kallsyms);
+			  const char *name, bool is_kallsyms, bool is_vdso);
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
 
 int perf_event__synthesize_attr(struct perf_tool *tool,
-				struct perf_event_attr *attr, u16 ids, u64 *id,
+				struct perf_event_attr *attr, u32 ids, u64 *id,
 				perf_event__handler_t process);
 int perf_event__synthesize_attrs(struct perf_tool *tool,
 				 struct perf_session *session,
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 6f2975a..8b1f6e8 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -3,6 +3,7 @@
 #include "exec_cmd.h"
 #include "levenshtein.h"
 #include "help.h"
+#include <termios.h>
 
 void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
 {
@@ -331,7 +332,8 @@
 	exit(1);
 }
 
-int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
+int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
+		const char *prefix __maybe_unused)
 {
 	printf("perf version %s\n", perf_version_string);
 	return 0;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f247ef2..236bc9d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -45,7 +45,7 @@
 	return false;
 }
 
-static void hists__reset_col_len(struct hists *hists)
+void hists__reset_col_len(struct hists *hists)
 {
 	enum hist_column col;
 
@@ -63,7 +63,7 @@
 		hists__set_col_len(hists, dso, unresolved_col_width);
 }
 
-static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
+void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 {
 	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
 	u16 len;
@@ -114,6 +114,22 @@
 	}
 }
 
+void hists__output_recalc_col_len(struct hists *hists, int max_rows)
+{
+	struct rb_node *next = rb_first(&hists->entries);
+	struct hist_entry *n;
+	int row = 0;
+
+	hists__reset_col_len(hists);
+
+	while (next && row++ < max_rows) {
+		n = rb_entry(next, struct hist_entry, rb_node);
+		if (!n->filtered)
+			hists__calc_col_len(hists, n);
+		next = rb_next(&n->rb_node);
+	}
+}
+
 static void hist_entry__add_cpumode_period(struct hist_entry *he,
 					   unsigned int cpumode, u64 period)
 {
@@ -378,7 +394,7 @@
  * collapse the histogram
  */
 
-static bool hists__collapse_insert_entry(struct hists *hists __used,
+static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
 					 struct rb_root *root,
 					 struct hist_entry *he)
 {
@@ -394,8 +410,13 @@
 		cmp = hist_entry__collapse(iter, he);
 
 		if (!cmp) {
-			iter->period += he->period;
-			iter->nr_events += he->nr_events;
+			iter->period		+= he->period;
+			iter->period_sys	+= he->period_sys;
+			iter->period_us		+= he->period_us;
+			iter->period_guest_sys	+= he->period_guest_sys;
+			iter->period_guest_us	+= he->period_guest_us;
+			iter->nr_events		+= he->nr_events;
+
 			if (symbol_conf.use_callchain) {
 				callchain_cursor_reset(&callchain_cursor);
 				callchain_merge(&callchain_cursor,
@@ -547,674 +568,6 @@
 	return __hists__output_resort(hists, true);
 }
 
-static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
-{
-	int i;
-	int ret = fprintf(fp, "            ");
-
-	for (i = 0; i < left_margin; i++)
-		ret += fprintf(fp, " ");
-
-	return ret;
-}
-
-static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
-					  int left_margin)
-{
-	int i;
-	size_t ret = callchain__fprintf_left_margin(fp, left_margin);
-
-	for (i = 0; i < depth; i++)
-		if (depth_mask & (1 << i))
-			ret += fprintf(fp, "|          ");
-		else
-			ret += fprintf(fp, "           ");
-
-	ret += fprintf(fp, "\n");
-
-	return ret;
-}
-
-static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
-				     int depth, int depth_mask, int period,
-				     u64 total_samples, u64 hits,
-				     int left_margin)
-{
-	int i;
-	size_t ret = 0;
-
-	ret += callchain__fprintf_left_margin(fp, left_margin);
-	for (i = 0; i < depth; i++) {
-		if (depth_mask & (1 << i))
-			ret += fprintf(fp, "|");
-		else
-			ret += fprintf(fp, " ");
-		if (!period && i == depth - 1) {
-			double percent;
-
-			percent = hits * 100.0 / total_samples;
-			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
-		} else
-			ret += fprintf(fp, "%s", "          ");
-	}
-	if (chain->ms.sym)
-		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
-	else
-		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
-
-	return ret;
-}
-
-static struct symbol *rem_sq_bracket;
-static struct callchain_list rem_hits;
-
-static void init_rem_hits(void)
-{
-	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
-	if (!rem_sq_bracket) {
-		fprintf(stderr, "Not enough memory to display remaining hits\n");
-		return;
-	}
-
-	strcpy(rem_sq_bracket->name, "[...]");
-	rem_hits.ms.sym = rem_sq_bracket;
-}
-
-static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
-					 u64 total_samples, int depth,
-					 int depth_mask, int left_margin)
-{
-	struct rb_node *node, *next;
-	struct callchain_node *child;
-	struct callchain_list *chain;
-	int new_depth_mask = depth_mask;
-	u64 remaining;
-	size_t ret = 0;
-	int i;
-	uint entries_printed = 0;
-
-	remaining = total_samples;
-
-	node = rb_first(root);
-	while (node) {
-		u64 new_total;
-		u64 cumul;
-
-		child = rb_entry(node, struct callchain_node, rb_node);
-		cumul = callchain_cumul_hits(child);
-		remaining -= cumul;
-
-		/*
-		 * The depth mask manages the output of pipes that show
-		 * the depth. We don't want to keep the pipes of the current
-		 * level for the last child of this depth.
-		 * Except if we have remaining filtered hits. They will
-		 * supersede the last child
-		 */
-		next = rb_next(node);
-		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
-			new_depth_mask &= ~(1 << (depth - 1));
-
-		/*
-		 * But we keep the older depth mask for the line separator
-		 * to keep the level link until we reach the last child
-		 */
-		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
-						   left_margin);
-		i = 0;
-		list_for_each_entry(chain, &child->val, list) {
-			ret += ipchain__fprintf_graph(fp, chain, depth,
-						      new_depth_mask, i++,
-						      total_samples,
-						      cumul,
-						      left_margin);
-		}
-
-		if (callchain_param.mode == CHAIN_GRAPH_REL)
-			new_total = child->children_hit;
-		else
-			new_total = total_samples;
-
-		ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
-						  depth + 1,
-						  new_depth_mask | (1 << depth),
-						  left_margin);
-		node = next;
-		if (++entries_printed == callchain_param.print_limit)
-			break;
-	}
-
-	if (callchain_param.mode == CHAIN_GRAPH_REL &&
-		remaining && remaining != total_samples) {
-
-		if (!rem_sq_bracket)
-			return ret;
-
-		new_depth_mask &= ~(1 << (depth - 1));
-		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
-					      new_depth_mask, 0, total_samples,
-					      remaining, left_margin);
-	}
-
-	return ret;
-}
-
-static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
-				       u64 total_samples, int left_margin)
-{
-	struct callchain_node *cnode;
-	struct callchain_list *chain;
-	u32 entries_printed = 0;
-	bool printed = false;
-	struct rb_node *node;
-	int i = 0;
-	int ret = 0;
-
-	/*
-	 * If have one single callchain root, don't bother printing
-	 * its percentage (100 % in fractal mode and the same percentage
-	 * than the hist in graph mode). This also avoid one level of column.
-	 */
-	node = rb_first(root);
-	if (node && !rb_next(node)) {
-		cnode = rb_entry(node, struct callchain_node, rb_node);
-		list_for_each_entry(chain, &cnode->val, list) {
-			/*
-			 * If we sort by symbol, the first entry is the same than
-			 * the symbol. No need to print it otherwise it appears as
-			 * displayed twice.
-			 */
-			if (!i++ && sort__first_dimension == SORT_SYM)
-				continue;
-			if (!printed) {
-				ret += callchain__fprintf_left_margin(fp, left_margin);
-				ret += fprintf(fp, "|\n");
-				ret += callchain__fprintf_left_margin(fp, left_margin);
-				ret += fprintf(fp, "---");
-				left_margin += 3;
-				printed = true;
-			} else
-				ret += callchain__fprintf_left_margin(fp, left_margin);
-
-			if (chain->ms.sym)
-				ret += fprintf(fp, " %s\n", chain->ms.sym->name);
-			else
-				ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
-
-			if (++entries_printed == callchain_param.print_limit)
-				break;
-		}
-		root = &cnode->rb_root;
-	}
-
-	ret += __callchain__fprintf_graph(fp, root, total_samples,
-					  1, 1, left_margin);
-	ret += fprintf(fp, "\n");
-
-	return ret;
-}
-
-static size_t __callchain__fprintf_flat(FILE *fp,
-					struct callchain_node *self,
-					u64 total_samples)
-{
-	struct callchain_list *chain;
-	size_t ret = 0;
-
-	if (!self)
-		return 0;
-
-	ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
-
-
-	list_for_each_entry(chain, &self->val, list) {
-		if (chain->ip >= PERF_CONTEXT_MAX)
-			continue;
-		if (chain->ms.sym)
-			ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
-		else
-			ret += fprintf(fp, "                %p\n",
-					(void *)(long)chain->ip);
-	}
-
-	return ret;
-}
-
-static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
-				      u64 total_samples)
-{
-	size_t ret = 0;
-	u32 entries_printed = 0;
-	struct rb_node *rb_node;
-	struct callchain_node *chain;
-
-	rb_node = rb_first(self);
-	while (rb_node) {
-		double percent;
-
-		chain = rb_entry(rb_node, struct callchain_node, rb_node);
-		percent = chain->hit * 100.0 / total_samples;
-
-		ret = percent_color_fprintf(fp, "           %6.2f%%\n", percent);
-		ret += __callchain__fprintf_flat(fp, chain, total_samples);
-		ret += fprintf(fp, "\n");
-		if (++entries_printed == callchain_param.print_limit)
-			break;
-
-		rb_node = rb_next(rb_node);
-	}
-
-	return ret;
-}
-
-static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
-					    u64 total_samples, int left_margin,
-					    FILE *fp)
-{
-	switch (callchain_param.mode) {
-	case CHAIN_GRAPH_REL:
-		return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
-						left_margin);
-		break;
-	case CHAIN_GRAPH_ABS:
-		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
-						left_margin);
-		break;
-	case CHAIN_FLAT:
-		return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
-		break;
-	case CHAIN_NONE:
-		break;
-	default:
-		pr_err("Bad callchain mode\n");
-	}
-
-	return 0;
-}
-
-void hists__output_recalc_col_len(struct hists *hists, int max_rows)
-{
-	struct rb_node *next = rb_first(&hists->entries);
-	struct hist_entry *n;
-	int row = 0;
-
-	hists__reset_col_len(hists);
-
-	while (next && row++ < max_rows) {
-		n = rb_entry(next, struct hist_entry, rb_node);
-		if (!n->filtered)
-			hists__calc_col_len(hists, n);
-		next = rb_next(&n->rb_node);
-	}
-}
-
-static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
-				     size_t size, struct hists *pair_hists,
-				     bool show_displacement, long displacement,
-				     bool color, u64 total_period)
-{
-	u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
-	u64 nr_events;
-	const char *sep = symbol_conf.field_sep;
-	int ret;
-
-	if (symbol_conf.exclude_other && !he->parent)
-		return 0;
-
-	if (pair_hists) {
-		period = he->pair ? he->pair->period : 0;
-		nr_events = he->pair ? he->pair->nr_events : 0;
-		total = pair_hists->stats.total_period;
-		period_sys = he->pair ? he->pair->period_sys : 0;
-		period_us = he->pair ? he->pair->period_us : 0;
-		period_guest_sys = he->pair ? he->pair->period_guest_sys : 0;
-		period_guest_us = he->pair ? he->pair->period_guest_us : 0;
-	} else {
-		period = he->period;
-		nr_events = he->nr_events;
-		total = total_period;
-		period_sys = he->period_sys;
-		period_us = he->period_us;
-		period_guest_sys = he->period_guest_sys;
-		period_guest_us = he->period_guest_us;
-	}
-
-	if (total) {
-		if (color)
-			ret = percent_color_snprintf(s, size,
-						     sep ? "%.2f" : "   %6.2f%%",
-						     (period * 100.0) / total);
-		else
-			ret = scnprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
-				       (period * 100.0) / total);
-		if (symbol_conf.show_cpu_utilization) {
-			ret += percent_color_snprintf(s + ret, size - ret,
-					sep ? "%.2f" : "   %6.2f%%",
-					(period_sys * 100.0) / total);
-			ret += percent_color_snprintf(s + ret, size - ret,
-					sep ? "%.2f" : "   %6.2f%%",
-					(period_us * 100.0) / total);
-			if (perf_guest) {
-				ret += percent_color_snprintf(s + ret,
-						size - ret,
-						sep ? "%.2f" : "   %6.2f%%",
-						(period_guest_sys * 100.0) /
-								total);
-				ret += percent_color_snprintf(s + ret,
-						size - ret,
-						sep ? "%.2f" : "   %6.2f%%",
-						(period_guest_us * 100.0) /
-								total);
-			}
-		}
-	} else
-		ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
-
-	if (symbol_conf.show_nr_samples) {
-		if (sep)
-			ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
-		else
-			ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
-	}
-
-	if (symbol_conf.show_total_period) {
-		if (sep)
-			ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
-		else
-			ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
-	}
-
-	if (pair_hists) {
-		char bf[32];
-		double old_percent = 0, new_percent = 0, diff;
-
-		if (total > 0)
-			old_percent = (period * 100.0) / total;
-		if (total_period > 0)
-			new_percent = (he->period * 100.0) / total_period;
-
-		diff = new_percent - old_percent;
-
-		if (fabs(diff) >= 0.01)
-			scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
-		else
-			scnprintf(bf, sizeof(bf), " ");
-
-		if (sep)
-			ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
-		else
-			ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
-
-		if (show_displacement) {
-			if (displacement)
-				scnprintf(bf, sizeof(bf), "%+4ld", displacement);
-			else
-				scnprintf(bf, sizeof(bf), " ");
-
-			if (sep)
-				ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
-			else
-				ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
-		}
-	}
-
-	return ret;
-}
-
-int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
-			 struct hists *hists)
-{
-	const char *sep = symbol_conf.field_sep;
-	struct sort_entry *se;
-	int ret = 0;
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-
-		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
-		ret += se->se_snprintf(he, s + ret, size - ret,
-				       hists__col_len(hists, se->se_width_idx));
-	}
-
-	return ret;
-}
-
-static int hist_entry__fprintf(struct hist_entry *he, size_t size,
-			       struct hists *hists, struct hists *pair_hists,
-			       bool show_displacement, long displacement,
-			       u64 total_period, FILE *fp)
-{
-	char bf[512];
-	int ret;
-
-	if (size == 0 || size > sizeof(bf))
-		size = sizeof(bf);
-
-	ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
-					show_displacement, displacement,
-					true, total_period);
-	hist_entry__snprintf(he, bf + ret, size - ret, hists);
-	return fprintf(fp, "%s\n", bf);
-}
-
-static size_t hist_entry__fprintf_callchain(struct hist_entry *he,
-					    struct hists *hists,
-					    u64 total_period, FILE *fp)
-{
-	int left_margin = 0;
-
-	if (sort__first_dimension == SORT_COMM) {
-		struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
-							 typeof(*se), list);
-		left_margin = hists__col_len(hists, se->se_width_idx);
-		left_margin -= thread__comm_len(he->thread);
-	}
-
-	return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
-}
-
-size_t hists__fprintf(struct hists *hists, struct hists *pair,
-		      bool show_displacement, bool show_header, int max_rows,
-		      int max_cols, FILE *fp)
-{
-	struct sort_entry *se;
-	struct rb_node *nd;
-	size_t ret = 0;
-	u64 total_period;
-	unsigned long position = 1;
-	long displacement = 0;
-	unsigned int width;
-	const char *sep = symbol_conf.field_sep;
-	const char *col_width = symbol_conf.col_width_list_str;
-	int nr_rows = 0;
-
-	init_rem_hits();
-
-	if (!show_header)
-		goto print_entries;
-
-	fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
-
-	if (symbol_conf.show_cpu_utilization) {
-		if (sep) {
-			ret += fprintf(fp, "%csys", *sep);
-			ret += fprintf(fp, "%cus", *sep);
-			if (perf_guest) {
-				ret += fprintf(fp, "%cguest sys", *sep);
-				ret += fprintf(fp, "%cguest us", *sep);
-			}
-		} else {
-			ret += fprintf(fp, "     sys  ");
-			ret += fprintf(fp, "      us  ");
-			if (perf_guest) {
-				ret += fprintf(fp, "  guest sys  ");
-				ret += fprintf(fp, "  guest us  ");
-			}
-		}
-	}
-
-	if (symbol_conf.show_nr_samples) {
-		if (sep)
-			fprintf(fp, "%cSamples", *sep);
-		else
-			fputs("  Samples  ", fp);
-	}
-
-	if (symbol_conf.show_total_period) {
-		if (sep)
-			ret += fprintf(fp, "%cPeriod", *sep);
-		else
-			ret += fprintf(fp, "   Period    ");
-	}
-
-	if (pair) {
-		if (sep)
-			ret += fprintf(fp, "%cDelta", *sep);
-		else
-			ret += fprintf(fp, "  Delta    ");
-
-		if (show_displacement) {
-			if (sep)
-				ret += fprintf(fp, "%cDisplacement", *sep);
-			else
-				ret += fprintf(fp, " Displ");
-		}
-	}
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-		if (sep) {
-			fprintf(fp, "%c%s", *sep, se->se_header);
-			continue;
-		}
-		width = strlen(se->se_header);
-		if (symbol_conf.col_width_list_str) {
-			if (col_width) {
-				hists__set_col_len(hists, se->se_width_idx,
-						   atoi(col_width));
-				col_width = strchr(col_width, ',');
-				if (col_width)
-					++col_width;
-			}
-		}
-		if (!hists__new_col_len(hists, se->se_width_idx, width))
-			width = hists__col_len(hists, se->se_width_idx);
-		fprintf(fp, "  %*s", width, se->se_header);
-	}
-
-	fprintf(fp, "\n");
-	if (max_rows && ++nr_rows >= max_rows)
-		goto out;
-
-	if (sep)
-		goto print_entries;
-
-	fprintf(fp, "# ........");
-	if (symbol_conf.show_cpu_utilization)
-		fprintf(fp, "   .......   .......");
-	if (symbol_conf.show_nr_samples)
-		fprintf(fp, " ..........");
-	if (symbol_conf.show_total_period)
-		fprintf(fp, " ............");
-	if (pair) {
-		fprintf(fp, " ..........");
-		if (show_displacement)
-			fprintf(fp, " .....");
-	}
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		unsigned int i;
-
-		if (se->elide)
-			continue;
-
-		fprintf(fp, "  ");
-		width = hists__col_len(hists, se->se_width_idx);
-		if (width == 0)
-			width = strlen(se->se_header);
-		for (i = 0; i < width; i++)
-			fprintf(fp, ".");
-	}
-
-	fprintf(fp, "\n");
-	if (max_rows && ++nr_rows >= max_rows)
-		goto out;
-
-	fprintf(fp, "#\n");
-	if (max_rows && ++nr_rows >= max_rows)
-		goto out;
-
-print_entries:
-	total_period = hists->stats.total_period;
-
-	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-
-		if (h->filtered)
-			continue;
-
-		if (show_displacement) {
-			if (h->pair != NULL)
-				displacement = ((long)h->pair->position -
-					        (long)position);
-			else
-				displacement = 0;
-			++position;
-		}
-		ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
-					   displacement, total_period, fp);
-
-		if (symbol_conf.use_callchain)
-			ret += hist_entry__fprintf_callchain(h, hists, total_period, fp);
-		if (max_rows && ++nr_rows >= max_rows)
-			goto out;
-
-		if (h->ms.map == NULL && verbose > 1) {
-			__map_groups__fprintf_maps(&h->thread->mg,
-						   MAP__FUNCTION, verbose, fp);
-			fprintf(fp, "%.10s end\n", graph_dotted_line);
-		}
-	}
-out:
-	free(rem_sq_bracket);
-
-	return ret;
-}
-
-/*
- * See hists__fprintf to match the column widths
- */
-unsigned int hists__sort_list_width(struct hists *hists)
-{
-	struct sort_entry *se;
-	int ret = 9; /* total % */
-
-	if (symbol_conf.show_cpu_utilization) {
-		ret += 7; /* count_sys % */
-		ret += 6; /* count_us % */
-		if (perf_guest) {
-			ret += 13; /* count_guest_sys % */
-			ret += 12; /* count_guest_us % */
-		}
-	}
-
-	if (symbol_conf.show_nr_samples)
-		ret += 11;
-
-	if (symbol_conf.show_total_period)
-		ret += 13;
-
-	list_for_each_entry(se, &hist_entry__sort_list, list)
-		if (!se->elide)
-			ret += 2 + hists__col_len(hists, se->se_width_idx);
-
-	if (verbose) /* Addr + origin */
-		ret += 3 + BITS_PER_LONG / 4;
-
-	return ret;
-}
-
 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
 				       enum hist_filter filter)
 {
@@ -1342,25 +695,3 @@
 	++hists->stats.nr_events[0];
 	++hists->stats.nr_events[type];
 }
-
-size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
-{
-	int i;
-	size_t ret = 0;
-
-	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
-		const char *name;
-
-		if (hists->stats.nr_events[i] == 0)
-			continue;
-
-		name = perf_event__name(i);
-		if (!strcmp(name, "UNKNOWN"))
-			continue;
-
-		ret += fprintf(fp, "%16s events: %10d\n", name,
-			       hists->stats.nr_events[i]);
-	}
-
-	return ret;
-}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 0b096c2..f011ad4 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -75,8 +75,8 @@
 				      struct symbol *parent, u64 period);
 int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
 int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
-int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
-			 struct hists *hists);
+int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
+			      struct hists *hists);
 void hist_entry__free(struct hist_entry *);
 
 struct hist_entry *__hists__add_branch_entry(struct hists *self,
@@ -112,25 +112,66 @@
 u16 hists__col_len(struct hists *self, enum hist_column col);
 void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
 bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
+void hists__reset_col_len(struct hists *hists);
+void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
+
+struct perf_hpp {
+	char *buf;
+	size_t size;
+	u64 total_period;
+	const char *sep;
+	long displacement;
+	void *ptr;
+};
+
+struct perf_hpp_fmt {
+	bool cond;
+	int (*header)(struct perf_hpp *hpp);
+	int (*width)(struct perf_hpp *hpp);
+	int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
+	int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
+};
+
+extern struct perf_hpp_fmt perf_hpp__format[];
+
+enum {
+	PERF_HPP__OVERHEAD,
+	PERF_HPP__OVERHEAD_SYS,
+	PERF_HPP__OVERHEAD_US,
+	PERF_HPP__OVERHEAD_GUEST_SYS,
+	PERF_HPP__OVERHEAD_GUEST_US,
+	PERF_HPP__SAMPLES,
+	PERF_HPP__PERIOD,
+	PERF_HPP__DELTA,
+	PERF_HPP__DISPL,
+
+	PERF_HPP__MAX_INDEX
+};
+
+void perf_hpp__init(bool need_pair, bool show_displacement);
+int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
+				bool color);
 
 struct perf_evlist;
 
 #ifdef NO_NEWT_SUPPORT
 static inline
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
-				  const char *help __used,
-				  void(*timer)(void *arg) __used,
-				  void *arg __used,
-				  int refresh __used)
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
+				  const char *help __maybe_unused,
+				  void(*timer)(void *arg) __maybe_unused,
+				  void *arg __maybe_unused,
+				  int refresh __maybe_unused)
 {
 	return 0;
 }
 
-static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
-					   int evidx __used,
-					   void(*timer)(void *arg) __used,
-					   void *arg __used,
-					   int delay_secs __used)
+static inline int hist_entry__tui_annotate(struct hist_entry *self
+					   __maybe_unused,
+					   int evidx __maybe_unused,
+					   void(*timer)(void *arg)
+					   __maybe_unused,
+					   void *arg __maybe_unused,
+					   int delay_secs __maybe_unused)
 {
 	return 0;
 }
@@ -148,11 +189,11 @@
 
 #ifdef NO_GTK2_SUPPORT
 static inline
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used,
-				  const char *help __used,
-				  void(*timer)(void *arg) __used,
-				  void *arg __used,
-				  int refresh __used)
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
+				  const char *help __maybe_unused,
+				  void(*timer)(void *arg) __maybe_unused,
+				  void *arg __maybe_unused,
+				  int refresh __maybe_unused)
 {
 	return 0;
 }
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 587a230..a55d8cf0 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -5,6 +5,10 @@
 #include <linux/compiler.h>
 #include <asm/hweight.h>
 
+#ifndef __WORDSIZE
+#define __WORDSIZE (__SIZEOF_LONG__ * 8)
+#endif
+
 #define BITS_PER_LONG __WORDSIZE
 #define BITS_PER_BYTE           8
 #define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 547628e..96b919d 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -9,6 +9,13 @@
 #define __attribute_const__
 #endif
 
-#define __used		__attribute__((__unused__))
+#ifndef __maybe_unused
+#define __maybe_unused		__attribute__((unused))
+#endif
+#define __packed	__attribute__((__packed__))
+
+#ifndef __force
+#define __force
+#endif
 
 #endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index b6842c1..d8c927c 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -8,8 +8,8 @@
 
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
-#define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
-#define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
+#define PERF_ALIGN(x, a)	__PERF_ALIGN_MASK(x, (typeof(x))(a)-1)
+#define __PERF_ALIGN_MASK(x, mask)	(((x)+(mask))&~(mask))
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
@@ -46,9 +46,22 @@
 	_min1 < _min2 ? _min1 : _min2; })
 #endif
 
+#ifndef roundup
+#define roundup(x, y) (                                \
+{                                                      \
+	const typeof(y) __y = y;		       \
+	(((x) + (__y - 1)) / __y) * __y;	       \
+}                                                      \
+)
+#endif
+
 #ifndef BUG_ON
+#ifdef NDEBUG
+#define BUG_ON(cond) do { if (cond) {} } while (0)
+#else
 #define BUG_ON(cond) assert(!(cond))
 #endif
+#endif
 
 /*
  * Both need more care to handle endianness
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
new file mode 100644
index 0000000..58b64ed
--- /dev/null
+++ b/tools/perf/util/include/linux/magic.h
@@ -0,0 +1,12 @@
+#ifndef _PERF_LINUX_MAGIC_H_
+#define _PERF_LINUX_MAGIC_H_
+
+#ifndef DEBUGFS_MAGIC
+#define DEBUGFS_MAGIC          0x64626720
+#endif
+
+#ifndef SYSFS_MAGIC
+#define SYSFS_MAGIC            0x62656572
+#endif
+
+#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 7a243a1..2a030c5 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1 +1,2 @@
+#include <stdbool.h>
 #include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 3b2f590..6f19c54 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1 +1,3 @@
 #include <string.h>
+
+void *memdup(const void *src, size_t len);
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
index 12de3b8..eb46478 100644
--- a/tools/perf/util/include/linux/types.h
+++ b/tools/perf/util/include/linux/types.h
@@ -3,6 +3,14 @@
 
 #include <asm/types.h>
 
+#ifndef __bitwise
+#define __bitwise
+#endif
+
+#ifndef __le32
+typedef __u32 __bitwise __le32;
+#endif
+
 #define DECLARE_BITMAP(name,bits) \
 	unsigned long name[BITS_TO_LONGS(bits)]
 
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index fd530dc..9d07400 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -11,7 +11,7 @@
 
 #include "intlist.h"
 
-static struct rb_node *intlist__node_new(struct rblist *rblist __used,
+static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
 					 const void *entry)
 {
 	int i = (int)((long)entry);
@@ -31,7 +31,7 @@
 	free(ilist);
 }
 
-static void intlist__node_delete(struct rblist *rblist __used,
+static void intlist__node_delete(struct rblist *rblist __maybe_unused,
 				 struct rb_node *rb_node)
 {
 	struct int_node *node = container_of(rb_node, struct int_node, rb_node);
@@ -52,9 +52,9 @@
 	return rblist__add_node(&ilist->rblist, (void *)((long)i));
 }
 
-void intlist__remove(struct intlist *ilist __used, struct int_node *node)
+void intlist__remove(struct intlist *ilist, struct int_node *node)
 {
-	int_node__delete(node);
+	rblist__remove_node(&ilist->rblist, &node->rb_node);
 }
 
 struct int_node *intlist__find(struct intlist *ilist, int i)
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index cc33486..ead5316 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -9,6 +9,7 @@
 #include "map.h"
 #include "thread.h"
 #include "strlist.h"
+#include "vdso.h"
 
 const char *map_type__name[MAP__NR_TYPES] = {
 	[MAP__FUNCTION] = "Functions",
@@ -23,7 +24,6 @@
 static inline int is_no_dso_memory(const char *filename)
 {
 	return !strcmp(filename, "[stack]") ||
-	       !strcmp(filename, "[vdso]")  ||
 	       !strcmp(filename, "[heap]");
 }
 
@@ -52,9 +52,10 @@
 	if (self != NULL) {
 		char newfilename[PATH_MAX];
 		struct dso *dso;
-		int anon, no_dso;
+		int anon, no_dso, vdso;
 
 		anon = is_anon_memory(filename);
+		vdso = is_vdso_map(filename);
 		no_dso = is_no_dso_memory(filename);
 
 		if (anon) {
@@ -62,7 +63,12 @@
 			filename = newfilename;
 		}
 
-		dso = __dsos__findnew(dsos__list, filename);
+		if (vdso) {
+			pgoff = 0;
+			dso = vdso__dso_findnew(dsos__list);
+		} else
+			dso = __dsos__findnew(dsos__list, filename);
+
 		if (dso == NULL)
 			goto out_delete;
 
@@ -86,6 +92,25 @@
 	return NULL;
 }
 
+/*
+ * Constructor variant for modules (where we know from /proc/modules where
+ * they are loaded) and for vmlinux, where only after we load all the
+ * symbols we'll know where it starts and ends.
+ */
+struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
+{
+	struct map *map = calloc(1, (sizeof(*map) +
+				     (dso->kernel ? sizeof(struct kmap) : 0)));
+	if (map != NULL) {
+		/*
+		 * ->end will be filled after we load all the symbols
+		 */
+		map__init(map, type, start, 0, 0, dso);
+	}
+
+	return map;
+}
+
 void map__delete(struct map *self)
 {
 	free(self);
@@ -137,6 +162,7 @@
 		pr_warning(", continuing without symbols\n");
 		return -1;
 	} else if (nr == 0) {
+#ifndef NO_LIBELF_SUPPORT
 		const size_t len = strlen(name);
 		const size_t real_len = len - sizeof(DSO__DELETED);
 
@@ -149,7 +175,7 @@
 			pr_warning("no symbols found in %s, maybe install "
 				   "a debug package?\n", name);
 		}
-
+#endif
 		return -1;
 	}
 	/*
@@ -217,15 +243,14 @@
 
 size_t map__fprintf_dsoname(struct map *map, FILE *fp)
 {
-	const char *dsoname;
+	const char *dsoname = "[unknown]";
 
 	if (map && map->dso && (map->dso->name || map->dso->long_name)) {
 		if (symbol_conf.show_kernel_path && map->dso->long_name)
 			dsoname = map->dso->long_name;
 		else if (map->dso->name)
 			dsoname = map->dso->name;
-	} else
-		dsoname = "[unknown]";
+	}
 
 	return fprintf(fp, "%s", dsoname);
 }
@@ -242,14 +267,6 @@
 	return addr;
 }
 
-u64 map__objdump_2ip(struct map *map, u64 addr)
-{
-	u64 ip = map->dso->adjust_symbols ?
-			addr :
-			map->unmap_ip(map, addr);	/* RIP -> IP */
-	return ip;
-}
-
 void map_groups__init(struct map_groups *mg)
 {
 	int i;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 03a1e9b..d2250fc 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -96,7 +96,7 @@
 	return ip + map->start - map->pgoff;
 }
 
-static inline u64 identity__map_ip(struct map *map __used, u64 ip)
+static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
 {
 	return ip;
 }
@@ -104,7 +104,6 @@
 
 /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
 u64 map__rip_2objdump(struct map *map, u64 rip);
-u64 map__objdump_2ip(struct map *map, u64 addr);
 
 struct symbol;
 
@@ -115,6 +114,7 @@
 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
 		     u64 pgoff, u32 pid, char *filename,
 		     enum map_type type);
+struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
 void map__delete(struct map *self);
 struct map *map__clone(struct map *self);
 int map__overlap(struct map *l, struct map *r);
@@ -157,9 +157,12 @@
 void machine__exit(struct machine *self);
 void machine__delete(struct machine *self);
 
+struct perf_evsel;
+struct perf_sample;
 int machine__resolve_callchain(struct machine *machine,
+			       struct perf_evsel *evsel,
 			       struct thread *thread,
-			       struct ip_callchain *chain,
+			       struct perf_sample *sample,
 			       struct symbol **parent);
 int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
 				     u64 addr);
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 127d648..28c18d1 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -18,8 +18,7 @@
 
 static int test__checkevent_tracepoint(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
@@ -48,8 +47,7 @@
 
 static int test__checkevent_raw(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
@@ -59,8 +57,7 @@
 
 static int test__checkevent_numeric(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
@@ -70,8 +67,7 @@
 
 static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
@@ -82,8 +78,7 @@
 
 static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
@@ -100,8 +95,7 @@
 
 static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
@@ -112,8 +106,7 @@
 
 static int test__checkevent_genhw(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
@@ -123,8 +116,7 @@
 
 static int test__checkevent_breakpoint(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
@@ -138,8 +130,7 @@
 
 static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
@@ -152,8 +143,7 @@
 
 static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type",
@@ -168,8 +158,7 @@
 
 static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type",
@@ -184,8 +173,7 @@
 
 static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type",
@@ -200,8 +188,7 @@
 
 static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
@@ -232,8 +219,7 @@
 
 static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
@@ -245,8 +231,7 @@
 
 static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
@@ -258,8 +243,7 @@
 
 static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
@@ -271,8 +255,7 @@
 
 static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
 	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
@@ -282,8 +265,7 @@
 
 static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
 	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
@@ -293,8 +275,7 @@
 
 static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
@@ -306,8 +287,7 @@
 
 static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
@@ -319,75 +299,71 @@
 
 static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
+
 
 	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u"));
+			!strcmp(perf_evsel__name(evsel), "mem:0:u"));
 
 	return test__checkevent_breakpoint(evlist);
 }
 
 static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "mem:0x0:x:k"));
+			!strcmp(perf_evsel__name(evsel), "mem:0:x:k"));
 
 	return test__checkevent_breakpoint_x(evlist);
 }
 
 static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp"));
+			!strcmp(perf_evsel__name(evsel), "mem:0:r:hp"));
 
 	return test__checkevent_breakpoint_r(evlist);
 }
 
 static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "mem:0x0:w:up"));
+			!strcmp(perf_evsel__name(evsel), "mem:0:w:up"));
 
 	return test__checkevent_breakpoint_w(evlist);
 }
 
 static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
 	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp"));
+			!strcmp(perf_evsel__name(evsel), "mem:0:rw:kp"));
 
 	return test__checkevent_breakpoint_rw(evlist);
 }
@@ -395,8 +371,7 @@
 static int test__checkevent_pmu(struct perf_evlist *evlist)
 {
 
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
@@ -410,12 +385,11 @@
 
 static int test__checkevent_list(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel;
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
 
 	/* r1 */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
 	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
@@ -426,7 +400,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 
 	/* syscalls:sys_enter_open:k */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	evsel = perf_evsel__next(evsel);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong sample_type",
 		PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
@@ -437,7 +411,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 
 	/* 1:1:hp */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	evsel = perf_evsel__next(evsel);
 	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
 	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
@@ -450,22 +424,21 @@
 
 static int test__checkevent_pmu_name(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel;
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
 
 	/* cpu/config=1,name=krava/u */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
 	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
 	TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
 
 	/* cpu/config=2/u" */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	evsel = perf_evsel__next(evsel);
 	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
 	TEST_ASSERT_VAL("wrong name",
-			!strcmp(perf_evsel__name(evsel), "raw 0x2:u"));
+			!strcmp(perf_evsel__name(evsel), "cpu/config=2/u"));
 
 	return 0;
 }
@@ -513,6 +486,280 @@
 	return 0;
 }
 
+static int test__group1(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+
+	/* instructions:k */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	/* cycles:upp */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	return 0;
+}
+
+static int test__group2(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* faults + :ku modifier */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	/* cache-references + :u modifier */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CACHE_REFERENCES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	/* cycles:k */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	return 0;
+}
+
+static int test__group3(struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
+
+	/* group1 syscalls:sys_enter_open:H */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+	TEST_ASSERT_VAL("wrong group name",
+		!strcmp(leader->group_name, "group1"));
+
+	/* group1 cycles:kppp */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+
+	/* group2 cycles + G modifier */
+	evsel = leader = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+	TEST_ASSERT_VAL("wrong group name",
+		!strcmp(leader->group_name, "group2"));
+
+	/* group2 1:3 + G modifier */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	/* instructions:u */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	return 0;
+}
+
+static int test__group4(struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+
+	/* cycles:u + p */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	/* instructions:kp + p */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	return 0;
+}
+
+static int test__group5(struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
+
+	/* cycles + G */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	/* instructions + G */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	/* cycles:G */
+	evsel = leader = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	/* instructions:G */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+	/* cycles */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
+
+	return 0;
+}
+
 struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -632,6 +879,26 @@
 		.name  = "mem:0:rw:kp",
 		.check = test__checkevent_breakpoint_rw_modifier,
 	},
+	[28] = {
+		.name  = "{instructions:k,cycles:upp}",
+		.check = test__group1,
+	},
+	[29] = {
+		.name  = "{faults:k,cache-references}:u,cycles:k",
+		.check = test__group2,
+	},
+	[30] = {
+		.name  = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u",
+		.check = test__group3,
+	},
+	[31] = {
+		.name  = "{cycles:u,instructions:kp}:p",
+		.check = test__group4,
+	},
+	[32] = {
+		.name  = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
+		.check = test__group5,
+	},
 };
 
 static struct test__event_st test__events_pmu[] = {
@@ -658,9 +925,6 @@
 	},
 };
 
-#define TEST__TERMS_CNT (sizeof(test__terms) / \
-			 sizeof(struct test__term))
-
 static int test_event(struct test__event_st *e)
 {
 	struct perf_evlist *evlist;
@@ -685,19 +949,19 @@
 
 static int test_events(struct test__event_st *events, unsigned cnt)
 {
-	int ret = 0;
+	int ret1, ret2 = 0;
 	unsigned i;
 
 	for (i = 0; i < cnt; i++) {
 		struct test__event_st *e = &events[i];
 
 		pr_debug("running test %d '%s'\n", i, e->name);
-		ret = test_event(e);
-		if (ret)
-			break;
+		ret1 = test_event(e);
+		if (ret1)
+			ret2 = ret1;
 	}
 
-	return ret;
+	return ret2;
 }
 
 static int test_term(struct test__term *t)
@@ -752,19 +1016,19 @@
 
 	ret = stat(path, &st);
 	if (ret)
-		pr_debug("ommiting PMU cpu tests\n");
+		pr_debug("omitting PMU cpu tests\n");
 	return !ret;
 }
 
 int parse_events__test(void)
 {
-	int ret;
+	int ret1, ret2 = 0;
 
 #define TEST_EVENTS(tests)				\
 do {							\
-	ret = test_events(tests, ARRAY_SIZE(tests));	\
-	if (ret)					\
-		return ret;				\
+	ret1 = test_events(tests, ARRAY_SIZE(tests));	\
+	if (!ret2)					\
+		ret2 = ret1;				\
 } while (0)
 
 	TEST_EVENTS(test__events);
@@ -772,5 +1036,9 @@
 	if (test_pmu())
 		TEST_EVENTS(test__events_pmu);
 
-	return test_terms(test__terms, ARRAY_SIZE(test__terms));
+	ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
+	if (!ret2)
+		ret2 = ret1;
+
+	return ret2;
 }
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 74a5af4..aed38e4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -239,8 +239,11 @@
 	return "unknown";
 }
 
-static int add_event(struct list_head **_list, int *idx,
-		     struct perf_event_attr *attr, char *name)
+
+
+static int __add_event(struct list_head **_list, int *idx,
+		       struct perf_event_attr *attr,
+		       char *name, struct cpu_map *cpus)
 {
 	struct perf_evsel *evsel;
 	struct list_head *list = *_list;
@@ -260,6 +263,7 @@
 		return -ENOMEM;
 	}
 
+	evsel->cpus = cpus;
 	if (name)
 		evsel->name = strdup(name);
 	list_add_tail(&evsel->node, list);
@@ -267,6 +271,12 @@
 	return 0;
 }
 
+static int add_event(struct list_head **_list, int *idx,
+		     struct perf_event_attr *attr, char *name)
+{
+	return __add_event(_list, idx, attr, name, NULL);
+}
+
 static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
 	int i, j;
@@ -308,7 +318,7 @@
 	for (i = 0; (i < 2) && (op_result[i]); i++) {
 		char *str = op_result[i];
 
-		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
+		n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str);
 
 		if (cache_op == -1) {
 			cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
@@ -346,42 +356,28 @@
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head **list, int *idx,
+static int add_tracepoint(struct list_head **listp, int *idx,
 			  char *sys_name, char *evt_name)
 {
-	struct perf_event_attr attr;
-	char name[MAX_NAME_LEN];
-	char evt_path[MAXPATHLEN];
-	char id_buf[4];
-	u64 id;
-	int fd;
+	struct perf_evsel *evsel;
+	struct list_head *list = *listp;
 
-	snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
-		 sys_name, evt_name);
-
-	fd = open(evt_path, O_RDONLY);
-	if (fd < 0)
-		return -1;
-
-	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
-		close(fd);
-		return -1;
+	if (!list) {
+		list = malloc(sizeof(*list));
+		if (!list)
+			return -ENOMEM;
+		INIT_LIST_HEAD(list);
 	}
 
-	close(fd);
-	id = atoll(id_buf);
+	evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
+	if (!evsel) {
+		free(list);
+		return -ENOMEM;
+	}
 
-	memset(&attr, 0, sizeof(attr));
-	attr.config = id;
-	attr.type = PERF_TYPE_TRACEPOINT;
-	attr.sample_type |= PERF_SAMPLE_RAW;
-	attr.sample_type |= PERF_SAMPLE_TIME;
-	attr.sample_type |= PERF_SAMPLE_CPU;
-	attr.sample_type |= PERF_SAMPLE_PERIOD;
-	attr.sample_period = 1;
-
-	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
-	return add_event(list, idx, &attr, name);
+	list_add_tail(&evsel->node, list);
+	*listp = list;
+	return 0;
 }
 
 static int add_tracepoint_multi(struct list_head **list, int *idx,
@@ -551,7 +547,7 @@
 }
 
 int parse_events_add_numeric(struct list_head **list, int *idx,
-			     unsigned long type, unsigned long config,
+			     u32 type, u64 config,
 			     struct list_head *head_config)
 {
 	struct perf_event_attr attr;
@@ -607,8 +603,23 @@
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr,
-			 pmu_event_name(head_config));
+	return __add_event(list, idx, &attr, pmu_event_name(head_config),
+			   pmu->cpus);
+}
+
+int parse_events__modifier_group(struct list_head *list,
+				 char *event_mod)
+{
+	return parse_events__modifier_event(list, event_mod, true);
+}
+
+void parse_events__set_leader(char *name, struct list_head *list)
+{
+	struct perf_evsel *leader;
+
+	__perf_evlist__set_leader(list);
+	leader = list_entry(list->next, struct perf_evsel, node);
+	leader->group_name = name ? strdup(name) : NULL;
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -616,21 +627,45 @@
 {
 	/*
 	 * Called for single event definition. Update the
-	 * 'all event' list, and reinit the 'signle event'
+	 * 'all event' list, and reinit the 'single event'
 	 * list, for next event definition.
 	 */
 	list_splice_tail(list_event, list_all);
 	free(list_event);
 }
 
-int parse_events_modifier(struct list_head *list, char *str)
-{
-	struct perf_evsel *evsel;
-	int exclude = 0, exclude_GH = 0;
-	int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
+struct event_modifier {
+	int eu;
+	int ek;
+	int eh;
+	int eH;
+	int eG;
+	int precise;
+	int exclude_GH;
+};
 
-	if (str == NULL)
-		return 0;
+static int get_event_modifier(struct event_modifier *mod, char *str,
+			       struct perf_evsel *evsel)
+{
+	int eu = evsel ? evsel->attr.exclude_user : 0;
+	int ek = evsel ? evsel->attr.exclude_kernel : 0;
+	int eh = evsel ? evsel->attr.exclude_hv : 0;
+	int eH = evsel ? evsel->attr.exclude_host : 0;
+	int eG = evsel ? evsel->attr.exclude_guest : 0;
+	int precise = evsel ? evsel->attr.precise_ip : 0;
+
+	int exclude = eu | ek | eh;
+	int exclude_GH = evsel ? evsel->exclude_GH : 0;
+
+	/*
+	 * We are here for group and 'GH' was not set as event
+	 * modifier and whatever event/group modifier override
+	 * default 'GH' setup.
+	 */
+	if (evsel && !exclude_GH)
+		eH = eG = 0;
+
+	memset(mod, 0, sizeof(*mod));
 
 	while (*str) {
 		if (*str == 'u') {
@@ -674,13 +709,51 @@
 	if (precise > 3)
 		return -EINVAL;
 
+	mod->eu = eu;
+	mod->ek = ek;
+	mod->eh = eh;
+	mod->eH = eH;
+	mod->eG = eG;
+	mod->precise = precise;
+	mod->exclude_GH = exclude_GH;
+	return 0;
+}
+
+int parse_events__modifier_event(struct list_head *list, char *str, bool add)
+{
+	struct perf_evsel *evsel;
+	struct event_modifier mod;
+
+	if (str == NULL)
+		return 0;
+
+	if (!add && get_event_modifier(&mod, str, NULL))
+		return -EINVAL;
+
 	list_for_each_entry(evsel, list, node) {
-		evsel->attr.exclude_user   = eu;
-		evsel->attr.exclude_kernel = ek;
-		evsel->attr.exclude_hv     = eh;
-		evsel->attr.precise_ip     = precise;
-		evsel->attr.exclude_host   = eH;
-		evsel->attr.exclude_guest  = eG;
+
+		if (add && get_event_modifier(&mod, str, evsel))
+			return -EINVAL;
+
+		evsel->attr.exclude_user   = mod.eu;
+		evsel->attr.exclude_kernel = mod.ek;
+		evsel->attr.exclude_hv     = mod.eh;
+		evsel->attr.precise_ip     = mod.precise;
+		evsel->attr.exclude_host   = mod.eH;
+		evsel->attr.exclude_guest  = mod.eG;
+		evsel->exclude_GH          = mod.exclude_GH;
+	}
+
+	return 0;
+}
+
+int parse_events_name(struct list_head *list, char *name)
+{
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, list, node) {
+		if (!evsel->name)
+			evsel->name = strdup(name);
 	}
 
 	return 0;
@@ -730,7 +803,8 @@
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+int parse_events(struct perf_evlist *evlist, const char *str,
+		 int unset __maybe_unused)
 {
 	struct parse_events_data__events data = {
 		.list = LIST_HEAD_INIT(data.list),
@@ -756,20 +830,20 @@
 }
 
 int parse_events_option(const struct option *opt, const char *str,
-			int unset __used)
+			int unset __maybe_unused)
 {
 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 	return parse_events(evlist, str, unset);
 }
 
 int parse_filter(const struct option *opt, const char *str,
-		 int unset __used)
+		 int unset __maybe_unused)
 {
 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 	struct perf_evsel *last = NULL;
 
 	if (evlist->nr_entries > 0)
-		last = list_entry(evlist->entries.prev, struct perf_evsel, node);
+		last = perf_evlist__last(evlist);
 
 	if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
 		fprintf(stderr,
@@ -799,7 +873,8 @@
  * Print the events from <debugfs_mount_point>/tracing/events
  */
 
-void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
+void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
+			     bool name_only)
 {
 	DIR *sys_dir, *evt_dir;
 	struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -829,6 +904,11 @@
 			    !strglobmatch(evt_dirent.d_name, event_glob))
 				continue;
 
+			if (name_only) {
+				printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name);
+				continue;
+			}
+
 			snprintf(evt_path, MAXPATHLEN, "%s:%s",
 				 sys_dirent.d_name, evt_dirent.d_name);
 			printf("  %-50s [%s]\n", evt_path,
@@ -906,7 +986,7 @@
 		__print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX);
 }
 
-int print_hwcache_events(const char *event_glob)
+int print_hwcache_events(const char *event_glob, bool name_only)
 {
 	unsigned int type, op, i, printed = 0;
 	char name[64];
@@ -923,8 +1003,11 @@
 				if (event_glob != NULL && !strglobmatch(name, event_glob))
 					continue;
 
-				printf("  %-50s [%s]\n", name,
-					event_type_descriptors[PERF_TYPE_HW_CACHE]);
+				if (name_only)
+					printf("%s ", name);
+				else
+					printf("  %-50s [%s]\n", name,
+					       event_type_descriptors[PERF_TYPE_HW_CACHE]);
 				++printed;
 			}
 		}
@@ -934,7 +1017,8 @@
 }
 
 static void print_symbol_events(const char *event_glob, unsigned type,
-				struct event_symbol *syms, unsigned max)
+				struct event_symbol *syms, unsigned max,
+				bool name_only)
 {
 	unsigned i, printed = 0;
 	char name[MAX_NAME_LEN];
@@ -946,6 +1030,11 @@
 		      (syms->alias && strglobmatch(syms->alias, event_glob))))
 			continue;
 
+		if (name_only) {
+			printf("%s ", syms->symbol);
+			continue;
+		}
+
 		if (strlen(syms->alias))
 			snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
 		else
@@ -963,39 +1052,42 @@
 /*
  * Print the help text for the event symbols:
  */
-void print_events(const char *event_glob)
+void print_events(const char *event_glob, bool name_only)
 {
-
-	printf("\n");
-	printf("List of pre-defined events (to be used in -e):\n");
+	if (!name_only) {
+		printf("\n");
+		printf("List of pre-defined events (to be used in -e):\n");
+	}
 
 	print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
-			    event_symbols_hw, PERF_COUNT_HW_MAX);
+			    event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
 
 	print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
-			    event_symbols_sw, PERF_COUNT_SW_MAX);
+			    event_symbols_sw, PERF_COUNT_SW_MAX, name_only);
 
-	print_hwcache_events(event_glob);
+	print_hwcache_events(event_glob, name_only);
 
 	if (event_glob != NULL)
 		return;
 
-	printf("\n");
-	printf("  %-50s [%s]\n",
-	       "rNNN",
-	       event_type_descriptors[PERF_TYPE_RAW]);
-	printf("  %-50s [%s]\n",
-	       "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
-	       event_type_descriptors[PERF_TYPE_RAW]);
-	printf("   (see 'perf list --help' on how to encode it)\n");
-	printf("\n");
+	if (!name_only) {
+		printf("\n");
+		printf("  %-50s [%s]\n",
+		       "rNNN",
+		       event_type_descriptors[PERF_TYPE_RAW]);
+		printf("  %-50s [%s]\n",
+		       "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
+		       event_type_descriptors[PERF_TYPE_RAW]);
+		printf("   (see 'perf list --help' on how to encode it)\n");
+		printf("\n");
 
-	printf("  %-50s [%s]\n",
-			"mem:<addr>[:access]",
+		printf("  %-50s [%s]\n",
+		       "mem:<addr>[:access]",
 			event_type_descriptors[PERF_TYPE_BREAKPOINT]);
-	printf("\n");
+		printf("\n");
+	}
 
-	print_tracepoint_events(NULL, NULL);
+	print_tracepoint_events(NULL, NULL, name_only);
 }
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term)
@@ -1005,7 +1097,7 @@
 
 static int new_term(struct parse_events__term **_term, int type_val,
 		    int type_term, char *config,
-		    char *str, long num)
+		    char *str, u64 num)
 {
 	struct parse_events__term *term;
 
@@ -1034,7 +1126,7 @@
 }
 
 int parse_events__term_num(struct parse_events__term **term,
-			   int type_term, char *config, long num)
+			   int type_term, char *config, u64 num)
 {
 	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
 			config, NULL, num);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ee9c218a..c356e44 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -55,7 +55,7 @@
 	char *config;
 	union {
 		char *str;
-		long  num;
+		u64  num;
 	} val;
 	int type_val;
 	int type_term;
@@ -73,17 +73,19 @@
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
 int parse_events__term_num(struct parse_events__term **_term,
-			   int type_term, char *config, long num);
+			   int type_term, char *config, u64 num);
 int parse_events__term_str(struct parse_events__term **_term,
 			   int type_term, char *config, char *str);
 int parse_events__term_clone(struct parse_events__term **new,
 			     struct parse_events__term *term);
 void parse_events__free_terms(struct list_head *terms);
-int parse_events_modifier(struct list_head *list, char *str);
+int parse_events__modifier_event(struct list_head *list, char *str, bool add);
+int parse_events__modifier_group(struct list_head *list, char *event_mod);
+int parse_events_name(struct list_head *list, char *name);
 int parse_events_add_tracepoint(struct list_head **list, int *idx,
 				char *sys, char *event);
 int parse_events_add_numeric(struct list_head **list, int *idx,
-			     unsigned long type, unsigned long config,
+			     u32 type, u64 config,
 			     struct list_head *head_config);
 int parse_events_add_cache(struct list_head **list, int *idx,
 			   char *type, char *op_result1, char *op_result2);
@@ -91,15 +93,17 @@
 				void *ptr, char *type);
 int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *pmu , struct list_head *head_config);
+void parse_events__set_leader(char *name, struct list_head *list);
 void parse_events_update_lists(struct list_head *list_event,
 			       struct list_head *list_all);
 void parse_events_error(void *data, void *scanner, char const *msg);
 int parse_events__test(void);
 
-void print_events(const char *event_glob);
+void print_events(const char *event_glob, bool name_only);
 void print_events_type(u8 type);
-void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
-int print_hwcache_events(const char *event_glob);
+void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
+			     bool name_only);
+int print_hwcache_events(const char *event_glob, bool name_only);
 extern int is_valid_tracepoint(const char *event_string);
 
 extern int valid_debugfs_mount(const char *debugfs);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 384ca74..c87efc1 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -15,10 +15,10 @@
 
 static int __value(YYSTYPE *yylval, char *str, int base, int token)
 {
-	long num;
+	u64 num;
 
 	errno = 0;
-	num = strtoul(str, NULL, base);
+	num = strtoull(str, NULL, base);
 	if (errno)
 		return PE_ERROR;
 
@@ -70,6 +70,12 @@
 %}
 
 %x mem
+%s config
+%x event
+
+group		[^,{}/]*[{][^}]*[}][^,{}/]*
+event_pmu	[^,{}/]+[/][^/]*[/][^,{}/]*
+event		[^,{}/]+
 
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
@@ -84,7 +90,13 @@
 	{
 		int start_token;
 
-		start_token = (int) parse_events_get_extra(yyscanner);
+		start_token = parse_events_get_extra(yyscanner);
+
+		if (start_token == PE_START_TERMS)
+			BEGIN(config);
+		else if (start_token == PE_START_EVENTS)
+			BEGIN(event);
+
 		if (start_token) {
 			parse_events_set_extra(NULL, yyscanner);
 			return start_token;
@@ -92,6 +104,26 @@
          }
 %}
 
+<event>{
+
+{group}		{
+			BEGIN(INITIAL); yyless(0);
+		}
+
+{event_pmu}	|
+{event}		{
+			str(yyscanner, PE_EVENT_NAME);
+			BEGIN(INITIAL); yyless(0);
+			return PE_EVENT_NAME;
+		}
+
+.		|
+<<EOF>>		{
+			BEGIN(INITIAL); yyless(0);
+		}
+
+}
+
 cpu-cycles|cycles				{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
 stalled-cycles-frontend|idle-cycles-frontend	{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
 stalled-cycles-backend|idle-cycles-backend	{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
@@ -127,18 +159,16 @@
 refs|Reference|ops|access		|
 misses|miss				{ return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
 
-	/*
-	 * These are event config hardcoded term names to be specified
-	 * within xxx/.../ syntax. So far we dont clash with other names,
-	 * so we can put them here directly. In case the we have a conflict
-	 * in future, this needs to go into '//' condition block.
-	 */
+<config>{
 config			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
 config1			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
 config2			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
 name			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
 period			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+,			{ return ','; }
+"/"			{ BEGIN(INITIAL); return '/'; }
+}
 
 mem:			{ BEGIN(mem); return PE_PREFIX_MEM; }
 r{num_raw_hex}		{ return raw(yyscanner); }
@@ -147,10 +177,12 @@
 
 {modifier_event}	{ return str(yyscanner, PE_MODIFIER_EVENT); }
 {name}			{ return str(yyscanner, PE_NAME); }
-"/"			{ return '/'; }
+"/"			{ BEGIN(config); return '/'; }
 -			{ return '-'; }
-,			{ return ','; }
+,			{ BEGIN(event); return ','; }
 :			{ return ':'; }
+"{"			{ BEGIN(event); return '{'; }
+"}"			{ return '}'; }
 =			{ return '='; }
 \n			{ }
 
@@ -175,7 +207,7 @@
 
 %%
 
-int parse_events_wrap(void *scanner __used)
+int parse_events_wrap(void *scanner __maybe_unused)
 {
 	return 1;
 }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 2bc5fbf..cd88209 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -27,10 +27,11 @@
 
 %token PE_START_EVENTS PE_START_TERMS
 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
+%token PE_EVENT_NAME
 %token PE_NAME
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
-%token PE_PREFIX_MEM PE_PREFIX_RAW
+%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
 %token PE_ERROR
 %type <num> PE_VALUE
 %type <num> PE_VALUE_SYM_HW
@@ -42,6 +43,7 @@
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
 %type <str> PE_MODIFIER_BP
+%type <str> PE_EVENT_NAME
 %type <num> value_sym
 %type <head> event_config
 %type <term> event_term
@@ -53,44 +55,125 @@
 %type <head> event_legacy_numeric
 %type <head> event_legacy_raw
 %type <head> event_def
+%type <head> event_mod
+%type <head> event_name
+%type <head> event
+%type <head> events
+%type <head> group_def
+%type <head> group
+%type <head> groups
 
 %union
 {
 	char *str;
-	unsigned long num;
+	u64 num;
 	struct list_head *head;
 	struct parse_events__term *term;
 }
 %%
 
 start:
-PE_START_EVENTS events
+PE_START_EVENTS start_events
 |
-PE_START_TERMS  terms
+PE_START_TERMS  start_terms
 
-events:
-events ',' event | event
-
-event:
-event_def PE_MODIFIER_EVENT
+start_events: groups
 {
 	struct parse_events_data__events *data = _data;
 
+	parse_events_update_lists($1, &data->list);
+}
+
+groups:
+groups ',' group
+{
+	struct list_head *list  = $1;
+	struct list_head *group = $3;
+
+	parse_events_update_lists(group, list);
+	$$ = list;
+}
+|
+groups ',' event
+{
+	struct list_head *list  = $1;
+	struct list_head *event = $3;
+
+	parse_events_update_lists(event, list);
+	$$ = list;
+}
+|
+group
+|
+event
+
+group:
+group_def ':' PE_MODIFIER_EVENT
+{
+	struct list_head *list = $1;
+
+	ABORT_ON(parse_events__modifier_group(list, $3));
+	$$ = list;
+}
+|
+group_def
+
+group_def:
+PE_NAME '{' events '}'
+{
+	struct list_head *list = $3;
+
+	parse_events__set_leader($1, list);
+	$$ = list;
+}
+|
+'{' events '}'
+{
+	struct list_head *list = $2;
+
+	parse_events__set_leader(NULL, list);
+	$$ = list;
+}
+
+events:
+events ',' event
+{
+	struct list_head *event = $3;
+	struct list_head *list  = $1;
+
+	parse_events_update_lists(event, list);
+	$$ = list;
+}
+|
+event
+
+event: event_mod
+
+event_mod:
+event_name PE_MODIFIER_EVENT
+{
+	struct list_head *list = $1;
+
 	/*
 	 * Apply modifier on all events added by single event definition
 	 * (there could be more events added for multiple tracepoint
 	 * definitions via '*?'.
 	 */
-	ABORT_ON(parse_events_modifier($1, $2));
-	parse_events_update_lists($1, &data->list);
+	ABORT_ON(parse_events__modifier_event(list, $2, false));
+	$$ = list;
+}
+|
+event_name
+
+event_name:
+PE_EVENT_NAME event_def
+{
+	ABORT_ON(parse_events_name($2, $1));
+	free($1);
+	$$ = $2;
 }
 |
 event_def
-{
-	struct parse_events_data__events *data = _data;
-
-	parse_events_update_lists($1, &data->list);
-}
 
 event_def: event_pmu |
 	   event_legacy_symbol |
@@ -207,7 +290,7 @@
 	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
 	$$ = list;
 }
 
@@ -222,7 +305,7 @@
 	$$ = list;
 }
 
-terms: event_config
+start_terms: event_config
 {
 	struct parse_events_data__terms *data = _data;
 	data->terms = $1;
@@ -282,7 +365,7 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
+	ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3));
 	$$ = term;
 }
 |
@@ -290,7 +373,7 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
+	ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3));
 	$$ = term;
 }
 |
@@ -298,7 +381,7 @@
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
+	ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1));
 	$$ = term;
 }
 
@@ -308,7 +391,7 @@
 
 %%
 
-void parse_events_error(void *data __used, void *scanner __used,
-			char const *msg __used)
+void parse_events_error(void *data __maybe_unused, void *scanner __maybe_unused,
+			char const *msg __maybe_unused)
 {
 }
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 594f8fa..443fc11 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -557,7 +557,8 @@
 }
 
 
-int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
+int parse_opt_verbosity_cb(const struct option *opt,
+			   const char *arg __maybe_unused,
 			   int unset)
 {
 	int *target = opt->value;
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
new file mode 100644
index 0000000..316dbe7
--- /dev/null
+++ b/tools/perf/util/perf_regs.h
@@ -0,0 +1,14 @@
+#ifndef __PERF_REGS_H
+#define __PERF_REGS_H
+
+#ifndef NO_PERF_REGS
+#include <perf_regs.h>
+#else
+#define PERF_REGS_MASK	0
+
+static inline const char *perf_reg_name(int id __maybe_unused)
+{
+	return NULL;
+}
+#endif /* NO_PERF_REGS */
+#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 67715a42..8a2229d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -9,6 +9,9 @@
 #include "util.h"
 #include "pmu.h"
 #include "parse-events.h"
+#include "cpumap.h"
+
+#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 
 int perf_pmu_parse(struct list_head *list, char *name);
 extern FILE *perf_pmu_in;
@@ -69,7 +72,7 @@
 		return -1;
 
 	snprintf(path, PATH_MAX,
-		 "%s/bus/event_source/devices/%s/format", sysfs, name);
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
 
 	if (stat(path, &st) < 0)
 		return 0;	/* no error if format does not exist */
@@ -206,7 +209,7 @@
 		return -1;
 
 	snprintf(path, PATH_MAX,
-		 "%s/bus/event_source/devices/%s/type", sysfs, name);
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
 
 	if (stat(path, &st) < 0)
 		return -1;
@@ -222,6 +225,62 @@
 	return ret;
 }
 
+/* Add all pmus in sysfs to pmu list: */
+static void pmu_read_sysfs(void)
+{
+	char path[PATH_MAX];
+	const char *sysfs;
+	DIR *dir;
+	struct dirent *dent;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
+
+	dir = opendir(path);
+	if (!dir)
+		return;
+
+	while ((dent = readdir(dir))) {
+		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+			continue;
+		/* add to static LIST_HEAD(pmus): */
+		perf_pmu__find(dent->d_name);
+	}
+
+	closedir(dir);
+}
+
+static struct cpu_map *pmu_cpumask(char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+	FILE *file;
+	struct cpu_map *cpus;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	file = fopen(path, "r");
+	if (!file)
+		return NULL;
+
+	cpus = cpu_map__read(file);
+	fclose(file);
+	return cpus;
+}
+
 static struct perf_pmu *pmu_lookup(char *name)
 {
 	struct perf_pmu *pmu;
@@ -244,6 +303,8 @@
 	if (!pmu)
 		return NULL;
 
+	pmu->cpus = pmu_cpumask(name);
+
 	pmu_aliases(name, &aliases);
 
 	INIT_LIST_HEAD(&pmu->format);
@@ -267,6 +328,21 @@
 	return NULL;
 }
 
+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
+{
+	/*
+	 * pmu iterator: If pmu is NULL, we start at the begin,
+	 * otherwise return the next pmu. Returns NULL on end.
+	 */
+	if (!pmu) {
+		pmu_read_sysfs();
+		pmu = list_prepare_entry(pmu, &pmus, list);
+	}
+	list_for_each_entry_continue(pmu, &pmus, list)
+		return pmu;
+	return NULL;
+}
+
 struct perf_pmu *perf_pmu__find(char *name)
 {
 	struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 535f2c5..53c7794 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -28,6 +28,7 @@
 struct perf_pmu {
 	char *name;
 	__u32 type;
+	struct cpu_map *cpus;
 	struct list_head format;
 	struct list_head aliases;
 	struct list_head list;
@@ -46,5 +47,7 @@
 			 int config, unsigned long *bits);
 void perf_pmu__set_format(unsigned long *bits, long from, long to);
 
+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
+
 int perf_pmu__test(void);
 #endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
index 20ea77e..ec89804 100644
--- a/tools/perf/util/pmu.y
+++ b/tools/perf/util/pmu.y
@@ -86,8 +86,8 @@
 
 %%
 
-void perf_pmu_error(struct list_head *list __used,
-		    char *name __used,
-		    char const *msg __used)
+void perf_pmu_error(struct list_head *list __maybe_unused,
+		    char *name __maybe_unused,
+		    char const *msg __maybe_unused)
 {
 }
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0dda25d..49a256e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -41,7 +41,7 @@
 #include "symbol.h"
 #include "thread.h"
 #include "debugfs.h"
-#include "trace-event.h"	/* For __unused */
+#include "trace-event.h"	/* For __maybe_unused */
 #include "probe-event.h"
 #include "probe-finder.h"
 #include "session.h"
@@ -647,8 +647,8 @@
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
-				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused, const char *target)
+				struct probe_trace_event **tevs __maybe_unused,
+				int max_tevs __maybe_unused, const char *target)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
@@ -661,17 +661,18 @@
 	return 0;
 }
 
-int show_line_range(struct line_range *lr __unused, const char *module __unused)
+int show_line_range(struct line_range *lr __maybe_unused,
+		    const char *module __maybe_unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
 }
 
-int show_available_vars(struct perf_probe_event *pevs __unused,
-			int npevs __unused, int max_vls __unused,
-			const char *module __unused,
-			struct strfilter *filter __unused,
-			bool externs __unused)
+int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
+			int npevs __maybe_unused, int max_vls __maybe_unused,
+			const char *module __maybe_unused,
+			struct strfilter *filter __maybe_unused,
+			bool externs __maybe_unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
@@ -1099,6 +1100,7 @@
 	struct probe_trace_point *tp = &tev->point;
 	char pr;
 	char *p;
+	char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str;
 	int ret, i, argc;
 	char **argv;
 
@@ -1115,14 +1117,27 @@
 	}
 
 	/* Scan event and group name. */
-	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
-		     &pr, (float *)(void *)&tev->group,
-		     (float *)(void *)&tev->event);
-	if (ret != 3) {
+	argv0_str = strdup(argv[0]);
+	if (argv0_str == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	fmt1_str = strtok_r(argv0_str, ":", &fmt);
+	fmt2_str = strtok_r(NULL, "/", &fmt);
+	fmt3_str = strtok_r(NULL, " \t", &fmt);
+	if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL
+	    || fmt3_str == NULL) {
 		semantic_error("Failed to parse event name: %s\n", argv[0]);
 		ret = -EINVAL;
 		goto out;
 	}
+	pr = fmt1_str[0];
+	tev->group = strdup(fmt2_str);
+	tev->event = strdup(fmt3_str);
+	if (tev->group == NULL || tev->event == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
 
 	tp->retprobe = (pr == 'r');
@@ -1134,10 +1149,17 @@
 		p++;
 	} else
 		p = argv[1];
-	ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol,
-		     &tp->offset);
-	if (ret == 1)
+	fmt1_str = strtok_r(p, "+", &fmt);
+	tp->symbol = strdup(fmt1_str);
+	if (tp->symbol == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	fmt2_str = strtok_r(NULL, "", &fmt);
+	if (fmt2_str == NULL)
 		tp->offset = 0;
+	else
+		tp->offset = strtoul(fmt2_str, NULL, 10);
 
 	tev->nargs = argc - 2;
 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1161,6 +1183,7 @@
 	}
 	ret = 0;
 out:
+	free(argv0_str);
 	argv_free(argv);
 	return ret;
 }
@@ -2183,7 +2206,7 @@
  * If a symbol corresponds to a function with global binding and
  * matches filter return 0. For all others return 1.
  */
-static int filter_available_functions(struct map *map __unused,
+static int filter_available_functions(struct map *map __maybe_unused,
 				      struct symbol *sym)
 {
 	if (sym->binding == STB_GLOBAL &&
@@ -2307,10 +2330,17 @@
 		function = NULL;
 	}
 	if (!pev->group) {
-		char *ptr1, *ptr2;
+		char *ptr1, *ptr2, *exec_copy;
 
 		pev->group = zalloc(sizeof(char *) * 64);
-		ptr1 = strdup(basename(exec));
+		exec_copy = strdup(exec);
+		if (!exec_copy) {
+			ret = -ENOMEM;
+			pr_warning("Failed to copy exec string.\n");
+			goto out;
+		}
+
+		ptr1 = strdup(basename(exec_copy));
 		if (ptr1) {
 			ptr2 = strpbrk(ptr1, "-._");
 			if (ptr2)
@@ -2319,6 +2349,7 @@
 					ptr1);
 			free(ptr1);
 		}
+		free(exec_copy);
 	}
 	free(pp->function);
 	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d448984..1daf5c1 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -207,7 +207,7 @@
 #else
 /* With older elfutils, this just support kernel module... */
 static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
-					       Dwarf_Addr addr __used)
+					       Dwarf_Addr addr __maybe_unused)
 {
 	const char *path = kernel_get_module_path("kernel");
 
@@ -525,8 +525,10 @@
 			return -ENOENT;
 		}
 		/* Verify it is a data structure  */
-		if (dwarf_tag(&type) != DW_TAG_structure_type) {
-			pr_warning("%s is not a data structure.\n", varname);
+		tag = dwarf_tag(&type);
+		if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
+			pr_warning("%s is not a data structure nor an union.\n",
+				   varname);
 			return -EINVAL;
 		}
 
@@ -539,8 +541,9 @@
 			*ref_ptr = ref;
 	} else {
 		/* Verify it is a data structure  */
-		if (tag != DW_TAG_structure_type) {
-			pr_warning("%s is not a data structure.\n", varname);
+		if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
+			pr_warning("%s is not a data structure nor an union.\n",
+				   varname);
 			return -EINVAL;
 		}
 		if (field->name[0] == '[') {
@@ -567,10 +570,15 @@
 	}
 
 	/* Get the offset of the field */
-	ret = die_get_data_member_location(die_mem, &offs);
-	if (ret < 0) {
-		pr_warning("Failed to get the offset of %s.\n", field->name);
-		return ret;
+	if (tag == DW_TAG_union_type) {
+		offs = 0;
+	} else {
+		ret = die_get_data_member_location(die_mem, &offs);
+		if (ret < 0) {
+			pr_warning("Failed to get the offset of %s.\n",
+				   field->name);
+			return ret;
+		}
 	}
 	ref->offset += (long)offs;
 
@@ -1419,7 +1427,7 @@
 }
 
 static int line_range_walk_cb(const char *fname, int lineno,
-			      Dwarf_Addr addr __used,
+			      Dwarf_Addr addr __maybe_unused,
 			      void *data)
 {
 	struct line_finder *lf = data;
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 2133628..c40c2d3 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -1,5 +1,5 @@
 #
-# List of files needed by perf python extention
+# List of files needed by perf python extension
 #
 # Each source file must be placed on its own line so that it can be
 # processed by Makefile and util/setup.py accordingly.
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 0688bfb..9181bf2 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -627,7 +627,7 @@
 	 * This will group just the fds for this single evsel, to group
 	 * multiple events, use evlist.open().
 	 */
-	if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) {
+	if (perf_evsel__open(evsel, cpus, threads) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
@@ -672,7 +672,7 @@
 };
 
 static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
-			     PyObject *args, PyObject *kwargs __used)
+			     PyObject *args, PyObject *kwargs __maybe_unused)
 {
 	PyObject *pcpus = NULL, *pthreads = NULL;
 	struct cpu_map *cpus;
@@ -733,7 +733,8 @@
 }
 
 static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
-					 PyObject *args __used, PyObject *kwargs __used)
+					 PyObject *args __maybe_unused,
+					 PyObject *kwargs __maybe_unused)
 {
 	struct perf_evlist *evlist = &pevlist->evlist;
         PyObject *list = PyList_New(0);
@@ -765,7 +766,8 @@
 
 
 static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
-				  PyObject *args, PyObject *kwargs __used)
+				  PyObject *args,
+				  PyObject *kwargs __maybe_unused)
 {
 	struct perf_evlist *evlist = &pevlist->evlist;
 	PyObject *pevsel;
@@ -803,7 +805,7 @@
 		if (pyevent == NULL)
 			return PyErr_NoMemory();
 
-		err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
+		err = perf_evlist__parse_sample(evlist, event, &pevent->sample);
 		if (err)
 			return PyErr_Format(PyExc_OSError,
 					    "perf: can't parse sample, err=%d", err);
@@ -824,7 +826,10 @@
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
 		return NULL;
 
-	if (perf_evlist__open(evlist, group) < 0) {
+	if (group)
+		perf_evlist__set_leader(evlist);
+
+	if (perf_evlist__open(evlist) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 02dfa19..f80605e 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,16 +25,16 @@
 #include <ctype.h>
 #include <errno.h>
 
-#include "../../perf.h"
 #include "../util.h"
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "../../perf.h"
 #include "../thread.h"
 #include "../event.h"
 #include "../trace-event.h"
 #include "../evsel.h"
 
-#include <EXTERN.h>
-#include <perl.h>
-
 void boot_Perf__Trace__Context(pTHX_ CV *cv);
 void boot_DynaLoader(pTHX_ CV *cv);
 typedef PerlInterpreter * INTERP;
@@ -237,16 +237,16 @@
 		define_event_symbols(event, ev_name, args->next);
 }
 
-static inline
-struct event_format *find_cache_event(struct pevent *pevent, int type)
+static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
 {
 	static char ev_name[256];
 	struct event_format *event;
+	int type = evsel->attr.config;
 
 	if (events[type])
 		return events[type];
 
-	events[type] = event = pevent_find_event(pevent, type);
+	events[type] = event = evsel->tp_format;
 	if (!event)
 		return NULL;
 
@@ -257,23 +257,22 @@
 	return event;
 }
 
-static void perl_process_tracepoint(union perf_event *perf_event __unused,
-				    struct pevent *pevent,
+static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
 				    struct perf_sample *sample,
 				    struct perf_evsel *evsel,
-				    struct machine *machine __unused,
-				    struct thread *thread)
+				    struct machine *machine __maybe_unused,
+				    struct addr_location *al)
 {
 	struct format_field *field;
 	static char handler[256];
 	unsigned long long val;
 	unsigned long s, ns;
 	struct event_format *event;
-	int type;
 	int pid;
 	int cpu = sample->cpu;
 	void *data = sample->raw_data;
 	unsigned long long nsecs = sample->time;
+	struct thread *thread = al->thread;
 	char *comm = thread->comm;
 
 	dSP;
@@ -281,13 +280,11 @@
 	if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
 		return;
 
-	type = trace_parse_common_type(pevent, data);
-
-	event = find_cache_event(pevent, type);
+	event = find_cache_event(evsel);
 	if (!event)
-		die("ug! no event found for type %d", type);
+		die("ug! no event found for type %" PRIu64, evsel->attr.config);
 
-	pid = trace_parse_common_pid(pevent, data);
+	pid = raw_field_value(event, "common_pid", data);
 
 	sprintf(handler, "%s::%s", event->system, event->name);
 
@@ -320,7 +317,7 @@
 				offset = field->offset;
 			XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
 		} else { /* FIELD_IS_NUMERIC */
-			val = read_size(pevent, data + field->offset,
+			val = read_size(event, data + field->offset,
 					field->size);
 			if (field->flags & FIELD_IS_SIGNED) {
 				XPUSHs(sv_2mortal(newSViv(val)));
@@ -349,11 +346,11 @@
 	LEAVE;
 }
 
-static void perl_process_event_generic(union perf_event *pevent __unused,
+static void perl_process_event_generic(union perf_event *event,
 				       struct perf_sample *sample,
-				       struct perf_evsel *evsel __unused,
-				       struct machine *machine __unused,
-				       struct thread *thread __unused)
+				       struct perf_evsel *evsel,
+				       struct machine *machine __maybe_unused,
+				       struct addr_location *al __maybe_unused)
 {
 	dSP;
 
@@ -363,7 +360,7 @@
 	ENTER;
 	SAVETMPS;
 	PUSHMARK(SP);
-	XPUSHs(sv_2mortal(newSVpvn((const char *)pevent, pevent->header.size)));
+	XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
 	XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr))));
 	XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
 	XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
@@ -376,14 +373,13 @@
 }
 
 static void perl_process_event(union perf_event *event,
-			       struct pevent *pevent,
 			       struct perf_sample *sample,
 			       struct perf_evsel *evsel,
 			       struct machine *machine,
-			       struct thread *thread)
+			       struct addr_location *al)
 {
-	perl_process_tracepoint(event, pevent, sample, evsel, machine, thread);
-	perl_process_event_generic(event, sample, evsel, machine, thread);
+	perl_process_tracepoint(event, sample, evsel, machine, al);
+	perl_process_event_generic(event, sample, evsel, machine, al);
 }
 
 static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index ce4d1b0..730c663 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -27,10 +27,12 @@
 #include <errno.h>
 
 #include "../../perf.h"
+#include "../evsel.h"
 #include "../util.h"
 #include "../event.h"
 #include "../thread.h"
 #include "../trace-event.h"
+#include "../evsel.h"
 
 PyMODINIT_FUNC initperf_trace_context(void);
 
@@ -194,16 +196,21 @@
 		define_event_symbols(event, ev_name, args->next);
 }
 
-static inline
-struct event_format *find_cache_event(struct pevent *pevent, int type)
+static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
 {
 	static char ev_name[256];
 	struct event_format *event;
+	int type = evsel->attr.config;
 
+	/*
+ 	 * XXX: Do we really need to cache this since now we have evsel->tp_format
+ 	 * cached already? Need to re-read this "cache" routine that as well calls
+ 	 * define_event_symbols() :-\
+ 	 */
 	if (events[type])
 		return events[type];
 
-	events[type] = event = pevent_find_event(pevent, type);
+	events[type] = event = evsel->tp_format;
 	if (!event)
 		return NULL;
 
@@ -214,12 +221,12 @@
 	return event;
 }
 
-static void python_process_event(union perf_event *perf_event __unused,
-				 struct pevent *pevent,
+static void python_process_tracepoint(union perf_event *perf_event
+				      __maybe_unused,
 				 struct perf_sample *sample,
-				 struct perf_evsel *evsel __unused,
-				 struct machine *machine __unused,
-				 struct thread *thread)
+				 struct perf_evsel *evsel,
+				 struct machine *machine __maybe_unused,
+				 struct addr_location *al)
 {
 	PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
 	static char handler_name[256];
@@ -228,24 +235,22 @@
 	unsigned long s, ns;
 	struct event_format *event;
 	unsigned n = 0;
-	int type;
 	int pid;
 	int cpu = sample->cpu;
 	void *data = sample->raw_data;
 	unsigned long long nsecs = sample->time;
+	struct thread *thread = al->thread;
 	char *comm = thread->comm;
 
 	t = PyTuple_New(MAX_FIELDS);
 	if (!t)
 		Py_FatalError("couldn't create Python tuple");
 
-	type = trace_parse_common_type(pevent, data);
-
-	event = find_cache_event(pevent, type);
+	event = find_cache_event(evsel);
 	if (!event)
-		die("ug! no event found for type %d", type);
+		die("ug! no event found for type %d", (int)evsel->attr.config);
 
-	pid = trace_parse_common_pid(pevent, data);
+	pid = raw_field_value(event, "common_pid", data);
 
 	sprintf(handler_name, "%s__%s", event->system, event->name);
 
@@ -290,7 +295,7 @@
 				offset = field->offset;
 			obj = PyString_FromString((char *)data + offset);
 		} else { /* FIELD_IS_NUMERIC */
-			val = read_size(pevent, data + field->offset,
+			val = read_size(event, data + field->offset,
 					field->size);
 			if (field->flags & FIELD_IS_SIGNED) {
 				if ((long long)val >= LONG_MIN &&
@@ -335,6 +340,84 @@
 	Py_DECREF(t);
 }
 
+static void python_process_general_event(union perf_event *perf_event
+					 __maybe_unused,
+					 struct perf_sample *sample,
+					 struct perf_evsel *evsel,
+					 struct machine *machine __maybe_unused,
+					 struct addr_location *al)
+{
+	PyObject *handler, *retval, *t, *dict;
+	static char handler_name[64];
+	unsigned n = 0;
+	struct thread *thread = al->thread;
+
+	/*
+	 * Use the MAX_FIELDS to make the function expandable, though
+	 * currently there is only one item for the tuple.
+	 */
+	t = PyTuple_New(MAX_FIELDS);
+	if (!t)
+		Py_FatalError("couldn't create Python tuple");
+
+	dict = PyDict_New();
+	if (!dict)
+		Py_FatalError("couldn't create Python dictionary");
+
+	snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
+
+	handler = PyDict_GetItemString(main_dict, handler_name);
+	if (!handler || !PyCallable_Check(handler))
+		goto exit;
+
+	PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
+	PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize(
+			(const char *)&evsel->attr, sizeof(evsel->attr)));
+	PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize(
+			(const char *)sample, sizeof(*sample)));
+	PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize(
+			(const char *)sample->raw_data, sample->raw_size));
+	PyDict_SetItemString(dict, "comm",
+			PyString_FromString(thread->comm));
+	if (al->map) {
+		PyDict_SetItemString(dict, "dso",
+			PyString_FromString(al->map->dso->name));
+	}
+	if (al->sym) {
+		PyDict_SetItemString(dict, "symbol",
+			PyString_FromString(al->sym->name));
+	}
+
+	PyTuple_SetItem(t, n++, dict);
+	if (_PyTuple_Resize(&t, n) == -1)
+		Py_FatalError("error resizing Python tuple");
+
+	retval = PyObject_CallObject(handler, t);
+	if (retval == NULL)
+		handler_call_die(handler_name);
+exit:
+	Py_DECREF(dict);
+	Py_DECREF(t);
+}
+
+static void python_process_event(union perf_event *perf_event,
+				 struct perf_sample *sample,
+				 struct perf_evsel *evsel,
+				 struct machine *machine,
+				 struct addr_location *al)
+{
+	switch (evsel->attr.type) {
+	case PERF_TYPE_TRACEPOINT:
+		python_process_tracepoint(perf_event, sample, evsel,
+					  machine, al);
+		break;
+	/* Reserve for future process_hw/sw/raw APIs */
+	default:
+		python_process_general_event(perf_event, sample, evsel,
+					     machine, al);
+	}
+}
+
 static int run_start_sub(void)
 {
 	PyObject *handler, *retval;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 2437fb0..8cdd232 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -15,6 +15,9 @@
 #include "util.h"
 #include "cpumap.h"
 #include "event-parse.h"
+#include "perf_regs.h"
+#include "unwind.h"
+#include "vdso.h"
 
 static int perf_session__open(struct perf_session *self, bool force)
 {
@@ -209,6 +212,7 @@
 	machine__exit(&self->host_machine);
 	close(self->fd);
 	free(self);
+	vdso__exit();
 }
 
 void machine__remove_thread(struct machine *self, struct thread *th)
@@ -288,10 +292,11 @@
 	return bi;
 }
 
-int machine__resolve_callchain(struct machine *self,
-			       struct thread *thread,
-			       struct ip_callchain *chain,
-			       struct symbol **parent)
+static int machine__resolve_callchain_sample(struct machine *machine,
+					     struct thread *thread,
+					     struct ip_callchain *chain,
+					     struct symbol **parent)
+
 {
 	u8 cpumode = PERF_RECORD_MISC_USER;
 	unsigned int i;
@@ -316,11 +321,14 @@
 		if (ip >= PERF_CONTEXT_MAX) {
 			switch (ip) {
 			case PERF_CONTEXT_HV:
-				cpumode = PERF_RECORD_MISC_HYPERVISOR;	break;
+				cpumode = PERF_RECORD_MISC_HYPERVISOR;
+				break;
 			case PERF_CONTEXT_KERNEL:
-				cpumode = PERF_RECORD_MISC_KERNEL;	break;
+				cpumode = PERF_RECORD_MISC_KERNEL;
+				break;
 			case PERF_CONTEXT_USER:
-				cpumode = PERF_RECORD_MISC_USER;	break;
+				cpumode = PERF_RECORD_MISC_USER;
+				break;
 			default:
 				pr_debug("invalid callchain context: "
 					 "%"PRId64"\n", (s64) ip);
@@ -335,7 +343,7 @@
 		}
 
 		al.filtered = false;
-		thread__find_addr_location(thread, self, cpumode,
+		thread__find_addr_location(thread, machine, cpumode,
 					   MAP__FUNCTION, ip, &al, NULL);
 		if (al.sym != NULL) {
 			if (sort__has_parent && !*parent &&
@@ -354,49 +362,92 @@
 	return 0;
 }
 
-static int process_event_synth_tracing_data_stub(union perf_event *event __used,
-						 struct perf_session *session __used)
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+	struct callchain_cursor *cursor = arg;
+	return callchain_cursor_append(cursor, entry->ip,
+				       entry->map, entry->sym);
+}
+
+int machine__resolve_callchain(struct machine *machine,
+			       struct perf_evsel *evsel,
+			       struct thread *thread,
+			       struct perf_sample *sample,
+			       struct symbol **parent)
+
+{
+	int ret;
+
+	callchain_cursor_reset(&callchain_cursor);
+
+	ret = machine__resolve_callchain_sample(machine, thread,
+						sample->callchain, parent);
+	if (ret)
+		return ret;
+
+	/* Can we do dwarf post unwind? */
+	if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
+	      (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
+		return 0;
+
+	/* Bail out if nothing was captured. */
+	if ((!sample->user_regs.regs) ||
+	    (!sample->user_stack.size))
+		return 0;
+
+	return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
+				   thread, evsel->attr.sample_regs_user,
+				   sample);
+
+}
+
+static int process_event_synth_tracing_data_stub(union perf_event *event
+						 __maybe_unused,
+						 struct perf_session *session
+						__maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
 }
 
-static int process_event_synth_attr_stub(union perf_event *event __used,
-					 struct perf_evlist **pevlist __used)
+static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
+					 struct perf_evlist **pevlist
+					 __maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
 }
 
-static int process_event_sample_stub(struct perf_tool *tool __used,
-				     union perf_event *event __used,
-				     struct perf_sample *sample __used,
-				     struct perf_evsel *evsel __used,
-				     struct machine *machine __used)
+static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
+				     union perf_event *event __maybe_unused,
+				     struct perf_sample *sample __maybe_unused,
+				     struct perf_evsel *evsel __maybe_unused,
+				     struct machine *machine __maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
 }
 
-static int process_event_stub(struct perf_tool *tool __used,
-			      union perf_event *event __used,
-			      struct perf_sample *sample __used,
-			      struct machine *machine __used)
+static int process_event_stub(struct perf_tool *tool __maybe_unused,
+			      union perf_event *event __maybe_unused,
+			      struct perf_sample *sample __maybe_unused,
+			      struct machine *machine __maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
 }
 
-static int process_finished_round_stub(struct perf_tool *tool __used,
-				       union perf_event *event __used,
-				       struct perf_session *perf_session __used)
+static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
+				       union perf_event *event __maybe_unused,
+				       struct perf_session *perf_session
+				       __maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
 }
 
-static int process_event_type_stub(struct perf_tool *tool __used,
-				   union perf_event *event __used)
+static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
+				   union perf_event *event __maybe_unused)
 {
 	dump_printf(": unhandled!\n");
 	return 0;
@@ -473,7 +524,7 @@
 }
 
 static void perf_event__all64_swap(union perf_event *event,
-				   bool sample_id_all __used)
+				   bool sample_id_all __maybe_unused)
 {
 	struct perf_event_header *hdr = &event->header;
 	mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
@@ -487,7 +538,7 @@
 	if (sample_id_all) {
 		void *data = &event->comm.comm;
 
-		data += ALIGN(strlen(data) + 1, sizeof(u64));
+		data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
 		swap_sample_id_all(event, data);
 	}
 }
@@ -504,7 +555,7 @@
 	if (sample_id_all) {
 		void *data = &event->mmap.filename;
 
-		data += ALIGN(strlen(data) + 1, sizeof(u64));
+		data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
 		swap_sample_id_all(event, data);
 	}
 }
@@ -584,7 +635,7 @@
 }
 
 static void perf_event__hdr_attr_swap(union perf_event *event,
-				      bool sample_id_all __used)
+				      bool sample_id_all __maybe_unused)
 {
 	size_t size;
 
@@ -596,14 +647,14 @@
 }
 
 static void perf_event__event_type_swap(union perf_event *event,
-					bool sample_id_all __used)
+					bool sample_id_all __maybe_unused)
 {
 	event->event_type.event_type.event_id =
 		bswap_64(event->event_type.event_type.event_id);
 }
 
 static void perf_event__tracing_data_swap(union perf_event *event,
-					  bool sample_id_all __used)
+					  bool sample_id_all __maybe_unused)
 {
 	event->tracing_data.size = bswap_32(event->tracing_data.size);
 }
@@ -652,7 +703,7 @@
 				      struct perf_tool *tool,
 				      u64 file_offset);
 
-static void flush_sample_queue(struct perf_session *s,
+static int flush_sample_queue(struct perf_session *s,
 			       struct perf_tool *tool)
 {
 	struct ordered_samples *os = &s->ordered_samples;
@@ -665,19 +716,21 @@
 	int ret;
 
 	if (!tool->ordered_samples || !limit)
-		return;
+		return 0;
 
 	list_for_each_entry_safe(iter, tmp, head, list) {
 		if (iter->timestamp > limit)
 			break;
 
-		ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
-						s->header.needs_swap);
+		ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
 		if (ret)
 			pr_err("Can't parse sample, err = %d\n", ret);
-		else
-			perf_session_deliver_event(s, iter->event, &sample, tool,
-						   iter->file_offset);
+		else {
+			ret = perf_session_deliver_event(s, iter->event, &sample, tool,
+							 iter->file_offset);
+			if (ret)
+				return ret;
+		}
 
 		os->last_flush = iter->timestamp;
 		list_del(&iter->list);
@@ -697,6 +750,8 @@
 	}
 
 	os->nr_samples = 0;
+
+	return 0;
 }
 
 /*
@@ -739,13 +794,14 @@
  *      etc...
  */
 static int process_finished_round(struct perf_tool *tool,
-				  union perf_event *event __used,
+				  union perf_event *event __maybe_unused,
 				  struct perf_session *session)
 {
-	flush_sample_queue(session, tool);
-	session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
+	int ret = flush_sample_queue(session, tool);
+	if (!ret)
+		session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
 
-	return 0;
+	return ret;
 }
 
 /* The queue is ordered by time */
@@ -860,6 +916,34 @@
 			sample->branch_stack->entries[i].to);
 }
 
+static void regs_dump__printf(u64 mask, u64 *regs)
+{
+	unsigned rid, i = 0;
+
+	for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) {
+		u64 val = regs[i++];
+
+		printf(".... %-5s 0x%" PRIx64 "\n",
+		       perf_reg_name(rid), val);
+	}
+}
+
+static void regs_user__printf(struct perf_sample *sample, u64 mask)
+{
+	struct regs_dump *user_regs = &sample->user_regs;
+
+	if (user_regs->regs) {
+		printf("... user regs: mask 0x%" PRIx64 "\n", mask);
+		regs_dump__printf(mask, user_regs->regs);
+	}
+}
+
+static void stack_user__printf(struct stack_dump *dump)
+{
+	printf("... ustack: size %" PRIu64 ", offset 0x%x\n",
+	       dump->size, dump->offset);
+}
+
 static void perf_session__print_tstamp(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_sample *sample)
@@ -897,7 +981,7 @@
 	       event->header.size, perf_event__name(event->header.type));
 }
 
-static void dump_sample(struct perf_session *session, union perf_event *event,
+static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
 			struct perf_sample *sample)
 {
 	u64 sample_type;
@@ -909,13 +993,19 @@
 	       event->header.misc, sample->pid, sample->tid, sample->ip,
 	       sample->period, sample->addr);
 
-	sample_type = perf_evlist__sample_type(session->evlist);
+	sample_type = evsel->attr.sample_type;
 
 	if (sample_type & PERF_SAMPLE_CALLCHAIN)
 		callchain__printf(sample);
 
 	if (sample_type & PERF_SAMPLE_BRANCH_STACK)
 		branch_stack__printf(sample);
+
+	if (sample_type & PERF_SAMPLE_REGS_USER)
+		regs_user__printf(sample, evsel->attr.sample_regs_user);
+
+	if (sample_type & PERF_SAMPLE_STACK_USER)
+		stack_user__printf(&sample->user_stack);
 }
 
 static struct machine *
@@ -973,7 +1063,7 @@
 
 	switch (event->header.type) {
 	case PERF_RECORD_SAMPLE:
-		dump_sample(session, event, sample);
+		dump_sample(evsel, event, sample);
 		if (evsel == NULL) {
 			++session->hists.stats.nr_unknown_id;
 			return 0;
@@ -1083,8 +1173,7 @@
 	/*
 	 * For all kernel events we get the sample data
 	 */
-	ret = perf_evlist__parse_sample(session->evlist, event, &sample,
-					session->header.needs_swap);
+	ret = perf_evlist__parse_sample(session->evlist, event, &sample);
 	if (ret)
 		return ret;
 
@@ -1369,7 +1458,7 @@
 	err = 0;
 	/* do the final flush for ordered samples */
 	session->ordered_samples.next_flush = ULLONG_MAX;
-	flush_sample_queue(session, tool);
+	err = flush_sample_queue(session, tool);
 out_err:
 	perf_session__warn_about_errors(session, tool);
 	perf_session_free_sample_buffers(session);
@@ -1498,9 +1587,9 @@
 	return NULL;
 }
 
-void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-			  struct machine *machine, int print_sym,
-			  int print_dso, int print_symoffset)
+void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
+			  struct perf_sample *sample, struct machine *machine,
+			  int print_sym, int print_dso, int print_symoffset)
 {
 	struct addr_location al;
 	struct callchain_cursor_node *node;
@@ -1514,8 +1603,9 @@
 
 	if (symbol_conf.use_callchain && sample->callchain) {
 
-		if (machine__resolve_callchain(machine, al.thread,
-						sample->callchain, NULL) != 0) {
+
+		if (machine__resolve_callchain(machine, evsel, al.thread,
+					       sample, NULL) != 0) {
 			if (verbose)
 				error("Failed to resolve callchain. Skipping\n");
 			return;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 1f7ec87..aab414f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -36,9 +36,7 @@
 	struct pevent		*pevent;
 	/*
 	 * FIXME: Need to split this up further, we need global
-	 *	  stats + per event stats. 'perf diff' also needs
-	 *	  to properly support multiple events in a single
-	 *	  perf.data file.
+	 *	  stats + per event stats.
 	 */
 	struct hists		hists;
 	int			fd;
@@ -129,9 +127,9 @@
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
 					    unsigned int type);
 
-void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-			  struct machine *machine, int print_sym,
-			  int print_dso, int print_symoffset);
+void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
+			  struct perf_sample *sample, struct machine *machine,
+			  int print_sym, int print_dso, int print_symoffset);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 0f5a0a4..b5b1b92 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,12 +8,11 @@
 const char	*sort_order = default_sort_order;
 int		sort__need_collapse = 0;
 int		sort__has_parent = 0;
+int		sort__has_sym = 0;
 int		sort__branch_mode = -1; /* -1 = means not set */
 
 enum sort_type	sort__first_dimension;
 
-char * field_sep;
-
 LIST_HEAD(hist_entry__sort_list);
 
 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
@@ -23,11 +22,11 @@
 
 	va_start(ap, fmt);
 	n = vsnprintf(bf, size, fmt, ap);
-	if (field_sep && n > 0) {
+	if (symbol_conf.field_sep && n > 0) {
 		char *sep = bf;
 
 		while (1) {
-			sep = strchr(sep, *field_sep);
+			sep = strchr(sep, *symbol_conf.field_sep);
 			if (sep == NULL)
 				break;
 			*sep = '.';
@@ -172,7 +171,7 @@
 
 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 				     u64 ip, char level, char *bf, size_t size,
-				     unsigned int width __used)
+				     unsigned int width __maybe_unused)
 {
 	size_t ret = 0;
 
@@ -207,7 +206,8 @@
 };
 
 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width __used)
+				    size_t size,
+				    unsigned int width __maybe_unused)
 {
 	return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
 					 self->level, bf, size, width);
@@ -250,7 +250,8 @@
 }
 
 static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
-				   size_t size, unsigned int width __used)
+					size_t size,
+					unsigned int width __maybe_unused)
 {
 	FILE *fp;
 	char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
@@ -399,7 +400,8 @@
 }
 
 static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width __used)
+					size_t size,
+					unsigned int width __maybe_unused)
 {
 	struct addr_map_symbol *from = &self->branch_info->from;
 	return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -408,7 +410,8 @@
 }
 
 static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width __used)
+				       size_t size,
+				       unsigned int width __maybe_unused)
 {
 	struct addr_map_symbol *to = &self->branch_info->to;
 	return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -509,6 +512,10 @@
 				return -EINVAL;
 			}
 			sort__has_parent = 1;
+		} else if (sd->entry == &sort_sym ||
+			   sd->entry == &sort_sym_from ||
+			   sd->entry == &sort_sym_to) {
+			sort__has_sym = 1;
 		}
 
 		if (sd->taken)
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index e724b26..12d6347 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,8 +31,8 @@
 extern const char default_sort_order[];
 extern int sort__need_collapse;
 extern int sort__has_parent;
+extern int sort__has_sym;
 extern int sort__branch_mode;
-extern char *field_sep;
 extern struct sort_entry sort_comm;
 extern struct sort_entry sort_dso;
 extern struct sort_entry sort_sym;
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
new file mode 100644
index 0000000..2374212
--- /dev/null
+++ b/tools/perf/util/stat.c
@@ -0,0 +1,57 @@
+#include <math.h>
+
+#include "stat.h"
+
+void update_stats(struct stats *stats, u64 val)
+{
+	double delta;
+
+	stats->n++;
+	delta = val - stats->mean;
+	stats->mean += delta / stats->n;
+	stats->M2 += delta*(val - stats->mean);
+}
+
+double avg_stats(struct stats *stats)
+{
+	return stats->mean;
+}
+
+/*
+ * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
+ *
+ *       (\Sum n_i^2) - ((\Sum n_i)^2)/n
+ * s^2 = -------------------------------
+ *                  n - 1
+ *
+ * http://en.wikipedia.org/wiki/Stddev
+ *
+ * The std dev of the mean is related to the std dev by:
+ *
+ *             s
+ * s_mean = -------
+ *          sqrt(n)
+ *
+ */
+double stddev_stats(struct stats *stats)
+{
+	double variance, variance_mean;
+
+	if (!stats->n)
+		return 0.0;
+
+	variance = stats->M2 / (stats->n - 1);
+	variance_mean = variance / stats->n;
+
+	return sqrt(variance_mean);
+}
+
+double rel_stddev_stats(double stddev, double avg)
+{
+	double pct = 0.0;
+
+	if (avg)
+		pct = 100.0 * stddev/avg;
+
+	return pct;
+}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
new file mode 100644
index 0000000..588367c3
--- /dev/null
+++ b/tools/perf/util/stat.h
@@ -0,0 +1,16 @@
+#ifndef __PERF_STATS_H
+#define __PERF_STATS_H
+
+#include "types.h"
+
+struct stats
+{
+	double n, mean, M2;
+};
+
+void update_stats(struct stats *stats, u64 val);
+double avg_stats(struct stats *stats);
+double stddev_stats(struct stats *stats);
+double rel_stddev_stats(double stddev, double avg);
+
+#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 199bc4d..3217059 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,5 @@
 #include "util.h"
-#include "string.h"
+#include "linux/string.h"
 
 #define K 1024LL
 /*
@@ -335,3 +335,19 @@
 
 	return s;
 }
+
+/**
+ * memdup - duplicate region of memory
+ * @src: memory region to duplicate
+ * @len: memory region length
+ */
+void *memdup(const void *src, size_t len)
+{
+	void *p;
+
+	p = malloc(len);
+	if (p)
+		memcpy(p, src, len);
+
+	return p;
+}
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 95856ff..155d8b7 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -93,7 +93,7 @@
 
 void strlist__remove(struct strlist *slist, struct str_node *snode)
 {
-	str_node__delete(snode, slist->dupstr);
+	rblist__remove_node(&slist->rblist, &snode->rb_node);
 }
 
 struct str_node *strlist__find(struct strlist *slist, const char *entry)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
new file mode 100644
index 0000000..db0cc92
--- /dev/null
+++ b/tools/perf/util/symbol-elf.c
@@ -0,0 +1,841 @@
+#include <libelf.h>
+#include <gelf.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "symbol.h"
+#include "debug.h"
+
+#ifndef NT_GNU_BUILD_ID
+#define NT_GNU_BUILD_ID 3
+#endif
+
+/**
+ * elf_symtab__for_each_symbol - iterate thru all the symbols
+ *
+ * @syms: struct elf_symtab instance to iterate
+ * @idx: uint32_t idx
+ * @sym: GElf_Sym iterator
+ */
+#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
+	for (idx = 0, gelf_getsym(syms, idx, &sym);\
+	     idx < nr_syms; \
+	     idx++, gelf_getsym(syms, idx, &sym))
+
+static inline uint8_t elf_sym__type(const GElf_Sym *sym)
+{
+	return GELF_ST_TYPE(sym->st_info);
+}
+
+static inline int elf_sym__is_function(const GElf_Sym *sym)
+{
+	return elf_sym__type(sym) == STT_FUNC &&
+	       sym->st_name != 0 &&
+	       sym->st_shndx != SHN_UNDEF;
+}
+
+static inline bool elf_sym__is_object(const GElf_Sym *sym)
+{
+	return elf_sym__type(sym) == STT_OBJECT &&
+		sym->st_name != 0 &&
+		sym->st_shndx != SHN_UNDEF;
+}
+
+static inline int elf_sym__is_label(const GElf_Sym *sym)
+{
+	return elf_sym__type(sym) == STT_NOTYPE &&
+		sym->st_name != 0 &&
+		sym->st_shndx != SHN_UNDEF &&
+		sym->st_shndx != SHN_ABS;
+}
+
+static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
+{
+	switch (type) {
+	case MAP__FUNCTION:
+		return elf_sym__is_function(sym);
+	case MAP__VARIABLE:
+		return elf_sym__is_object(sym);
+	default:
+		return false;
+	}
+}
+
+static inline const char *elf_sym__name(const GElf_Sym *sym,
+					const Elf_Data *symstrs)
+{
+	return symstrs->d_buf + sym->st_name;
+}
+
+static inline const char *elf_sec__name(const GElf_Shdr *shdr,
+					const Elf_Data *secstrs)
+{
+	return secstrs->d_buf + shdr->sh_name;
+}
+
+static inline int elf_sec__is_text(const GElf_Shdr *shdr,
+					const Elf_Data *secstrs)
+{
+	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
+}
+
+static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
+				    const Elf_Data *secstrs)
+{
+	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
+}
+
+static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
+			  enum map_type type)
+{
+	switch (type) {
+	case MAP__FUNCTION:
+		return elf_sec__is_text(shdr, secstrs);
+	case MAP__VARIABLE:
+		return elf_sec__is_data(shdr, secstrs);
+	default:
+		return false;
+	}
+}
+
+static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
+{
+	Elf_Scn *sec = NULL;
+	GElf_Shdr shdr;
+	size_t cnt = 1;
+
+	while ((sec = elf_nextscn(elf, sec)) != NULL) {
+		gelf_getshdr(sec, &shdr);
+
+		if ((addr >= shdr.sh_addr) &&
+		    (addr < (shdr.sh_addr + shdr.sh_size)))
+			return cnt;
+
+		++cnt;
+	}
+
+	return -1;
+}
+
+static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
+				    GElf_Shdr *shp, const char *name,
+				    size_t *idx)
+{
+	Elf_Scn *sec = NULL;
+	size_t cnt = 1;
+
+	/* Elf is corrupted/truncated, avoid calling elf_strptr. */
+	if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL))
+		return NULL;
+
+	while ((sec = elf_nextscn(elf, sec)) != NULL) {
+		char *str;
+
+		gelf_getshdr(sec, shp);
+		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+		if (!strcmp(name, str)) {
+			if (idx)
+				*idx = cnt;
+			break;
+		}
+		++cnt;
+	}
+
+	return sec;
+}
+
+#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
+	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
+	     idx < nr_entries; \
+	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
+
+#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
+	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
+	     idx < nr_entries; \
+	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
+
+/*
+ * We need to check if we have a .dynsym, so that we can handle the
+ * .plt, synthesizing its symbols, that aren't on the symtabs (be it
+ * .dynsym or .symtab).
+ * And always look at the original dso, not at debuginfo packages, that
+ * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
+ */
+int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map,
+				symbol_filter_t filter)
+{
+	uint32_t nr_rel_entries, idx;
+	GElf_Sym sym;
+	u64 plt_offset;
+	GElf_Shdr shdr_plt;
+	struct symbol *f;
+	GElf_Shdr shdr_rel_plt, shdr_dynsym;
+	Elf_Data *reldata, *syms, *symstrs;
+	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
+	size_t dynsym_idx;
+	GElf_Ehdr ehdr;
+	char sympltname[1024];
+	Elf *elf;
+	int nr = 0, symidx, err = 0;
+
+	if (!ss->dynsym)
+		return 0;
+
+	elf = ss->elf;
+	ehdr = ss->ehdr;
+
+	scn_dynsym = ss->dynsym;
+	shdr_dynsym = ss->dynshdr;
+	dynsym_idx = ss->dynsym_idx;
+
+	if (scn_dynsym == NULL)
+		goto out_elf_end;
+
+	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
+					  ".rela.plt", NULL);
+	if (scn_plt_rel == NULL) {
+		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
+						  ".rel.plt", NULL);
+		if (scn_plt_rel == NULL)
+			goto out_elf_end;
+	}
+
+	err = -1;
+
+	if (shdr_rel_plt.sh_link != dynsym_idx)
+		goto out_elf_end;
+
+	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
+		goto out_elf_end;
+
+	/*
+	 * Fetch the relocation section to find the idxes to the GOT
+	 * and the symbols in the .dynsym they refer to.
+	 */
+	reldata = elf_getdata(scn_plt_rel, NULL);
+	if (reldata == NULL)
+		goto out_elf_end;
+
+	syms = elf_getdata(scn_dynsym, NULL);
+	if (syms == NULL)
+		goto out_elf_end;
+
+	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
+	if (scn_symstrs == NULL)
+		goto out_elf_end;
+
+	symstrs = elf_getdata(scn_symstrs, NULL);
+	if (symstrs == NULL)
+		goto out_elf_end;
+
+	if (symstrs->d_size == 0)
+		goto out_elf_end;
+
+	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
+	plt_offset = shdr_plt.sh_offset;
+
+	if (shdr_rel_plt.sh_type == SHT_RELA) {
+		GElf_Rela pos_mem, *pos;
+
+		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
+					   nr_rel_entries) {
+			symidx = GELF_R_SYM(pos->r_info);
+			plt_offset += shdr_plt.sh_entsize;
+			gelf_getsym(syms, symidx, &sym);
+			snprintf(sympltname, sizeof(sympltname),
+				 "%s@plt", elf_sym__name(&sym, symstrs));
+
+			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
+					STB_GLOBAL, sympltname);
+			if (!f)
+				goto out_elf_end;
+
+			if (filter && filter(map, f))
+				symbol__delete(f);
+			else {
+				symbols__insert(&dso->symbols[map->type], f);
+				++nr;
+			}
+		}
+	} else if (shdr_rel_plt.sh_type == SHT_REL) {
+		GElf_Rel pos_mem, *pos;
+		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
+					  nr_rel_entries) {
+			symidx = GELF_R_SYM(pos->r_info);
+			plt_offset += shdr_plt.sh_entsize;
+			gelf_getsym(syms, symidx, &sym);
+			snprintf(sympltname, sizeof(sympltname),
+				 "%s@plt", elf_sym__name(&sym, symstrs));
+
+			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
+					STB_GLOBAL, sympltname);
+			if (!f)
+				goto out_elf_end;
+
+			if (filter && filter(map, f))
+				symbol__delete(f);
+			else {
+				symbols__insert(&dso->symbols[map->type], f);
+				++nr;
+			}
+		}
+	}
+
+	err = 0;
+out_elf_end:
+	if (err == 0)
+		return nr;
+	pr_debug("%s: problems reading %s PLT info.\n",
+		 __func__, dso->long_name);
+	return 0;
+}
+
+/*
+ * Align offset to 4 bytes as needed for note name and descriptor data.
+ */
+#define NOTE_ALIGN(n) (((n) + 3) & -4U)
+
+static int elf_read_build_id(Elf *elf, void *bf, size_t size)
+{
+	int err = -1;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	Elf_Data *data;
+	Elf_Scn *sec;
+	Elf_Kind ek;
+	void *ptr;
+
+	if (size < BUILD_ID_SIZE)
+		goto out;
+
+	ek = elf_kind(elf);
+	if (ek != ELF_K_ELF)
+		goto out;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		pr_err("%s: cannot get elf header.\n", __func__);
+		goto out;
+	}
+
+	/*
+	 * Check following sections for notes:
+	 *   '.note.gnu.build-id'
+	 *   '.notes'
+	 *   '.note' (VDSO specific)
+	 */
+	do {
+		sec = elf_section_by_name(elf, &ehdr, &shdr,
+					  ".note.gnu.build-id", NULL);
+		if (sec)
+			break;
+
+		sec = elf_section_by_name(elf, &ehdr, &shdr,
+					  ".notes", NULL);
+		if (sec)
+			break;
+
+		sec = elf_section_by_name(elf, &ehdr, &shdr,
+					  ".note", NULL);
+		if (sec)
+			break;
+
+		return err;
+
+	} while (0);
+
+	data = elf_getdata(sec, NULL);
+	if (data == NULL)
+		goto out;
+
+	ptr = data->d_buf;
+	while (ptr < (data->d_buf + data->d_size)) {
+		GElf_Nhdr *nhdr = ptr;
+		size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
+		       descsz = NOTE_ALIGN(nhdr->n_descsz);
+		const char *name;
+
+		ptr += sizeof(*nhdr);
+		name = ptr;
+		ptr += namesz;
+		if (nhdr->n_type == NT_GNU_BUILD_ID &&
+		    nhdr->n_namesz == sizeof("GNU")) {
+			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
+				size_t sz = min(size, descsz);
+				memcpy(bf, ptr, sz);
+				memset(bf + sz, 0, size - sz);
+				err = descsz;
+				break;
+			}
+		}
+		ptr += descsz;
+	}
+
+out:
+	return err;
+}
+
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+	int fd, err = -1;
+	Elf *elf;
+
+	if (size < BUILD_ID_SIZE)
+		goto out;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		goto out;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL) {
+		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+		goto out_close;
+	}
+
+	err = elf_read_build_id(elf, bf, size);
+
+	elf_end(elf);
+out_close:
+	close(fd);
+out:
+	return err;
+}
+
+int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
+{
+	int fd, err = -1;
+
+	if (size < BUILD_ID_SIZE)
+		goto out;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		goto out;
+
+	while (1) {
+		char bf[BUFSIZ];
+		GElf_Nhdr nhdr;
+		size_t namesz, descsz;
+
+		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
+			break;
+
+		namesz = NOTE_ALIGN(nhdr.n_namesz);
+		descsz = NOTE_ALIGN(nhdr.n_descsz);
+		if (nhdr.n_type == NT_GNU_BUILD_ID &&
+		    nhdr.n_namesz == sizeof("GNU")) {
+			if (read(fd, bf, namesz) != (ssize_t)namesz)
+				break;
+			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
+				size_t sz = min(descsz, size);
+				if (read(fd, build_id, sz) == (ssize_t)sz) {
+					memset(build_id + sz, 0, size - sz);
+					err = 0;
+					break;
+				}
+			} else if (read(fd, bf, descsz) != (ssize_t)descsz)
+				break;
+		} else {
+			int n = namesz + descsz;
+			if (read(fd, bf, n) != n)
+				break;
+		}
+	}
+	close(fd);
+out:
+	return err;
+}
+
+int filename__read_debuglink(const char *filename, char *debuglink,
+			     size_t size)
+{
+	int fd, err = -1;
+	Elf *elf;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	Elf_Data *data;
+	Elf_Scn *sec;
+	Elf_Kind ek;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		goto out;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL) {
+		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+		goto out_close;
+	}
+
+	ek = elf_kind(elf);
+	if (ek != ELF_K_ELF)
+		goto out_close;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		pr_err("%s: cannot get elf header.\n", __func__);
+		goto out_close;
+	}
+
+	sec = elf_section_by_name(elf, &ehdr, &shdr,
+				  ".gnu_debuglink", NULL);
+	if (sec == NULL)
+		goto out_close;
+
+	data = elf_getdata(sec, NULL);
+	if (data == NULL)
+		goto out_close;
+
+	/* the start of this section is a zero-terminated string */
+	strncpy(debuglink, data->d_buf, size);
+
+	elf_end(elf);
+
+out_close:
+	close(fd);
+out:
+	return err;
+}
+
+static int dso__swap_init(struct dso *dso, unsigned char eidata)
+{
+	static unsigned int const endian = 1;
+
+	dso->needs_swap = DSO_SWAP__NO;
+
+	switch (eidata) {
+	case ELFDATA2LSB:
+		/* We are big endian, DSO is little endian. */
+		if (*(unsigned char const *)&endian != 1)
+			dso->needs_swap = DSO_SWAP__YES;
+		break;
+
+	case ELFDATA2MSB:
+		/* We are little endian, DSO is big endian. */
+		if (*(unsigned char const *)&endian != 0)
+			dso->needs_swap = DSO_SWAP__YES;
+		break;
+
+	default:
+		pr_err("unrecognized DSO data encoding %d\n", eidata);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+bool symsrc__possibly_runtime(struct symsrc *ss)
+{
+	return ss->dynsym || ss->opdsec;
+}
+
+bool symsrc__has_symtab(struct symsrc *ss)
+{
+	return ss->symtab != NULL;
+}
+
+void symsrc__destroy(struct symsrc *ss)
+{
+	free(ss->name);
+	elf_end(ss->elf);
+	close(ss->fd);
+}
+
+int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
+		 enum dso_binary_type type)
+{
+	int err = -1;
+	GElf_Ehdr ehdr;
+	Elf *elf;
+	int fd;
+
+	fd = open(name, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL) {
+		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
+		goto out_close;
+	}
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		pr_debug("%s: cannot get elf header.\n", __func__);
+		goto out_elf_end;
+	}
+
+	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
+		goto out_elf_end;
+
+	/* Always reject images with a mismatched build-id: */
+	if (dso->has_build_id) {
+		u8 build_id[BUILD_ID_SIZE];
+
+		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
+			goto out_elf_end;
+
+		if (!dso__build_id_equal(dso, build_id))
+			goto out_elf_end;
+	}
+
+	ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
+			NULL);
+	if (ss->symshdr.sh_type != SHT_SYMTAB)
+		ss->symtab = NULL;
+
+	ss->dynsym_idx = 0;
+	ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym",
+			&ss->dynsym_idx);
+	if (ss->dynshdr.sh_type != SHT_DYNSYM)
+		ss->dynsym = NULL;
+
+	ss->opdidx = 0;
+	ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd",
+			&ss->opdidx);
+	if (ss->opdshdr.sh_type != SHT_PROGBITS)
+		ss->opdsec = NULL;
+
+	if (dso->kernel == DSO_TYPE_USER) {
+		GElf_Shdr shdr;
+		ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+				elf_section_by_name(elf, &ehdr, &shdr,
+						     ".gnu.prelink_undo",
+						     NULL) != NULL);
+	} else {
+		ss->adjust_symbols = 0;
+	}
+
+	ss->name   = strdup(name);
+	if (!ss->name)
+		goto out_elf_end;
+
+	ss->elf    = elf;
+	ss->fd     = fd;
+	ss->ehdr   = ehdr;
+	ss->type   = type;
+
+	return 0;
+
+out_elf_end:
+	elf_end(elf);
+out_close:
+	close(fd);
+	return err;
+}
+
+int dso__load_sym(struct dso *dso, struct map *map,
+		  struct symsrc *syms_ss, struct symsrc *runtime_ss,
+		  symbol_filter_t filter, int kmodule)
+{
+	struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
+	struct map *curr_map = map;
+	struct dso *curr_dso = dso;
+	Elf_Data *symstrs, *secstrs;
+	uint32_t nr_syms;
+	int err = -1;
+	uint32_t idx;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	Elf_Data *syms, *opddata = NULL;
+	GElf_Sym sym;
+	Elf_Scn *sec, *sec_strndx;
+	Elf *elf;
+	int nr = 0;
+
+	dso->symtab_type = syms_ss->type;
+
+	if (!syms_ss->symtab) {
+		syms_ss->symtab  = syms_ss->dynsym;
+		syms_ss->symshdr = syms_ss->dynshdr;
+	}
+
+	elf = syms_ss->elf;
+	ehdr = syms_ss->ehdr;
+	sec = syms_ss->symtab;
+	shdr = syms_ss->symshdr;
+
+	if (runtime_ss->opdsec)
+		opddata = elf_rawdata(runtime_ss->opdsec, NULL);
+
+	syms = elf_getdata(sec, NULL);
+	if (syms == NULL)
+		goto out_elf_end;
+
+	sec = elf_getscn(elf, shdr.sh_link);
+	if (sec == NULL)
+		goto out_elf_end;
+
+	symstrs = elf_getdata(sec, NULL);
+	if (symstrs == NULL)
+		goto out_elf_end;
+
+	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+	if (sec_strndx == NULL)
+		goto out_elf_end;
+
+	secstrs = elf_getdata(sec_strndx, NULL);
+	if (secstrs == NULL)
+		goto out_elf_end;
+
+	nr_syms = shdr.sh_size / shdr.sh_entsize;
+
+	memset(&sym, 0, sizeof(sym));
+	dso->adjust_symbols = runtime_ss->adjust_symbols;
+	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
+		struct symbol *f;
+		const char *elf_name = elf_sym__name(&sym, symstrs);
+		char *demangled = NULL;
+		int is_label = elf_sym__is_label(&sym);
+		const char *section_name;
+		bool used_opd = false;
+
+		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
+		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
+			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
+
+		if (!is_label && !elf_sym__is_a(&sym, map->type))
+			continue;
+
+		/* Reject ARM ELF "mapping symbols": these aren't unique and
+		 * don't identify functions, so will confuse the profile
+		 * output: */
+		if (ehdr.e_machine == EM_ARM) {
+			if (!strcmp(elf_name, "$a") ||
+			    !strcmp(elf_name, "$d") ||
+			    !strcmp(elf_name, "$t"))
+				continue;
+		}
+
+		if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) {
+			u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr;
+			u64 *opd = opddata->d_buf + offset;
+			sym.st_value = DSO__SWAP(dso, u64, *opd);
+			sym.st_shndx = elf_addr_to_index(runtime_ss->elf,
+					sym.st_value);
+			used_opd = true;
+		}
+
+		sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
+		if (!sec)
+			goto out_elf_end;
+
+		gelf_getshdr(sec, &shdr);
+
+		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
+			continue;
+
+		section_name = elf_sec__name(&shdr, secstrs);
+
+		/* On ARM, symbols for thumb functions have 1 added to
+		 * the symbol address as a flag - remove it */
+		if ((ehdr.e_machine == EM_ARM) &&
+		    (map->type == MAP__FUNCTION) &&
+		    (sym.st_value & 1))
+			--sym.st_value;
+
+		if (dso->kernel != DSO_TYPE_USER || kmodule) {
+			char dso_name[PATH_MAX];
+
+			if (strcmp(section_name,
+				   (curr_dso->short_name +
+				    dso->short_name_len)) == 0)
+				goto new_symbol;
+
+			if (strcmp(section_name, ".text") == 0) {
+				curr_map = map;
+				curr_dso = dso;
+				goto new_symbol;
+			}
+
+			snprintf(dso_name, sizeof(dso_name),
+				 "%s%s", dso->short_name, section_name);
+
+			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
+			if (curr_map == NULL) {
+				u64 start = sym.st_value;
+
+				if (kmodule)
+					start += map->start + shdr.sh_offset;
+
+				curr_dso = dso__new(dso_name);
+				if (curr_dso == NULL)
+					goto out_elf_end;
+				curr_dso->kernel = dso->kernel;
+				curr_dso->long_name = dso->long_name;
+				curr_dso->long_name_len = dso->long_name_len;
+				curr_map = map__new2(start, curr_dso,
+						     map->type);
+				if (curr_map == NULL) {
+					dso__delete(curr_dso);
+					goto out_elf_end;
+				}
+				curr_map->map_ip = identity__map_ip;
+				curr_map->unmap_ip = identity__map_ip;
+				curr_dso->symtab_type = dso->symtab_type;
+				map_groups__insert(kmap->kmaps, curr_map);
+				dsos__add(&dso->node, curr_dso);
+				dso__set_loaded(curr_dso, map->type);
+			} else
+				curr_dso = curr_map->dso;
+
+			goto new_symbol;
+		}
+
+		if ((used_opd && runtime_ss->adjust_symbols)
+				|| (!used_opd && syms_ss->adjust_symbols)) {
+			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
+				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
+				  (u64)sym.st_value, (u64)shdr.sh_addr,
+				  (u64)shdr.sh_offset);
+			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+		}
+		/*
+		 * We need to figure out if the object was created from C++ sources
+		 * DWARF DW_compile_unit has this, but we don't always have access
+		 * to it...
+		 */
+		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
+		if (demangled != NULL)
+			elf_name = demangled;
+new_symbol:
+		f = symbol__new(sym.st_value, sym.st_size,
+				GELF_ST_BIND(sym.st_info), elf_name);
+		free(demangled);
+		if (!f)
+			goto out_elf_end;
+
+		if (filter && filter(curr_map, f))
+			symbol__delete(f);
+		else {
+			symbols__insert(&curr_dso->symbols[curr_map->type], f);
+			nr++;
+		}
+	}
+
+	/*
+	 * For misannotated, zeroed, ASM function sizes.
+	 */
+	if (nr > 0) {
+		symbols__fixup_duplicate(&dso->symbols[map->type]);
+		symbols__fixup_end(&dso->symbols[map->type]);
+		if (kmap) {
+			/*
+			 * We need to fixup this here too because we create new
+			 * maps here, for things like vsyscall sections.
+			 */
+			__map_groups__fixup_end(kmap->kmaps, map->type);
+		}
+	}
+	err = nr;
+out_elf_end:
+	return err;
+}
+
+void symbol__elf_init(void)
+{
+	elf_version(EV_CURRENT);
+}
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
new file mode 100644
index 0000000..259f8f2
--- /dev/null
+++ b/tools/perf/util/symbol-minimal.c
@@ -0,0 +1,307 @@
+#include "symbol.h"
+
+#include <elf.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+
+
+static bool check_need_swap(int file_endian)
+{
+	const int data = 1;
+	u8 *check = (u8 *)&data;
+	int host_endian;
+
+	if (check[0] == 1)
+		host_endian = ELFDATA2LSB;
+	else
+		host_endian = ELFDATA2MSB;
+
+	return host_endian != file_endian;
+}
+
+#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
+
+#define NT_GNU_BUILD_ID	3
+
+static int read_build_id(void *note_data, size_t note_len, void *bf,
+			 size_t size, bool need_swap)
+{
+	struct {
+		u32 n_namesz;
+		u32 n_descsz;
+		u32 n_type;
+	} *nhdr;
+	void *ptr;
+
+	ptr = note_data;
+	while (ptr < (note_data + note_len)) {
+		const char *name;
+		size_t namesz, descsz;
+
+		nhdr = ptr;
+		if (need_swap) {
+			nhdr->n_namesz = bswap_32(nhdr->n_namesz);
+			nhdr->n_descsz = bswap_32(nhdr->n_descsz);
+			nhdr->n_type = bswap_32(nhdr->n_type);
+		}
+
+		namesz = NOTE_ALIGN(nhdr->n_namesz);
+		descsz = NOTE_ALIGN(nhdr->n_descsz);
+
+		ptr += sizeof(*nhdr);
+		name = ptr;
+		ptr += namesz;
+		if (nhdr->n_type == NT_GNU_BUILD_ID &&
+		    nhdr->n_namesz == sizeof("GNU")) {
+			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
+				size_t sz = min(size, descsz);
+				memcpy(bf, ptr, sz);
+				memset(bf + sz, 0, size - sz);
+				return 0;
+			}
+		}
+		ptr += descsz;
+	}
+
+	return -1;
+}
+
+int filename__read_debuglink(const char *filename __maybe_unused,
+			     char *debuglink __maybe_unused,
+			     size_t size __maybe_unused)
+{
+	return -1;
+}
+
+/*
+ * Just try PT_NOTE header otherwise fails
+ */
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+	FILE *fp;
+	int ret = -1;
+	bool need_swap = false;
+	u8 e_ident[EI_NIDENT];
+	size_t buf_size;
+	void *buf;
+	int i;
+
+	fp = fopen(filename, "r");
+	if (fp == NULL)
+		return -1;
+
+	if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
+		goto out;
+
+	if (memcmp(e_ident, ELFMAG, SELFMAG) ||
+	    e_ident[EI_VERSION] != EV_CURRENT)
+		goto out;
+
+	need_swap = check_need_swap(e_ident[EI_DATA]);
+
+	/* for simplicity */
+	fseek(fp, 0, SEEK_SET);
+
+	if (e_ident[EI_CLASS] == ELFCLASS32) {
+		Elf32_Ehdr ehdr;
+		Elf32_Phdr *phdr;
+
+		if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
+			goto out;
+
+		if (need_swap) {
+			ehdr.e_phoff = bswap_32(ehdr.e_phoff);
+			ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
+			ehdr.e_phnum = bswap_16(ehdr.e_phnum);
+		}
+
+		buf_size = ehdr.e_phentsize * ehdr.e_phnum;
+		buf = malloc(buf_size);
+		if (buf == NULL)
+			goto out;
+
+		fseek(fp, ehdr.e_phoff, SEEK_SET);
+		if (fread(buf, buf_size, 1, fp) != 1)
+			goto out_free;
+
+		for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
+			void *tmp;
+
+			if (need_swap) {
+				phdr->p_type = bswap_32(phdr->p_type);
+				phdr->p_offset = bswap_32(phdr->p_offset);
+				phdr->p_filesz = bswap_32(phdr->p_filesz);
+			}
+
+			if (phdr->p_type != PT_NOTE)
+				continue;
+
+			buf_size = phdr->p_filesz;
+			tmp = realloc(buf, buf_size);
+			if (tmp == NULL)
+				goto out_free;
+
+			buf = tmp;
+			fseek(fp, phdr->p_offset, SEEK_SET);
+			if (fread(buf, buf_size, 1, fp) != 1)
+				goto out_free;
+
+			ret = read_build_id(buf, buf_size, bf, size, need_swap);
+			if (ret == 0)
+				ret = size;
+			break;
+		}
+	} else {
+		Elf64_Ehdr ehdr;
+		Elf64_Phdr *phdr;
+
+		if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
+			goto out;
+
+		if (need_swap) {
+			ehdr.e_phoff = bswap_64(ehdr.e_phoff);
+			ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
+			ehdr.e_phnum = bswap_16(ehdr.e_phnum);
+		}
+
+		buf_size = ehdr.e_phentsize * ehdr.e_phnum;
+		buf = malloc(buf_size);
+		if (buf == NULL)
+			goto out;
+
+		fseek(fp, ehdr.e_phoff, SEEK_SET);
+		if (fread(buf, buf_size, 1, fp) != 1)
+			goto out_free;
+
+		for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
+			void *tmp;
+
+			if (need_swap) {
+				phdr->p_type = bswap_32(phdr->p_type);
+				phdr->p_offset = bswap_64(phdr->p_offset);
+				phdr->p_filesz = bswap_64(phdr->p_filesz);
+			}
+
+			if (phdr->p_type != PT_NOTE)
+				continue;
+
+			buf_size = phdr->p_filesz;
+			tmp = realloc(buf, buf_size);
+			if (tmp == NULL)
+				goto out_free;
+
+			buf = tmp;
+			fseek(fp, phdr->p_offset, SEEK_SET);
+			if (fread(buf, buf_size, 1, fp) != 1)
+				goto out_free;
+
+			ret = read_build_id(buf, buf_size, bf, size, need_swap);
+			if (ret == 0)
+				ret = size;
+			break;
+		}
+	}
+out_free:
+	free(buf);
+out:
+	fclose(fp);
+	return ret;
+}
+
+int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
+{
+	int fd;
+	int ret = -1;
+	struct stat stbuf;
+	size_t buf_size;
+	void *buf;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	if (fstat(fd, &stbuf) < 0)
+		goto out;
+
+	buf_size = stbuf.st_size;
+	buf = malloc(buf_size);
+	if (buf == NULL)
+		goto out;
+
+	if (read(fd, buf, buf_size) != (ssize_t) buf_size)
+		goto out_free;
+
+	ret = read_build_id(buf, buf_size, build_id, size, false);
+out_free:
+	free(buf);
+out:
+	close(fd);
+	return ret;
+}
+
+int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
+		 const char *name,
+	         enum dso_binary_type type)
+{
+	int fd = open(name, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	ss->name = strdup(name);
+	if (!ss->name)
+		goto out_close;
+
+	ss->type = type;
+
+	return 0;
+out_close:
+	close(fd);
+	return -1;
+}
+
+bool symsrc__possibly_runtime(struct symsrc *ss __maybe_unused)
+{
+	/* Assume all sym sources could be a runtime image. */
+	return true;
+}
+
+bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
+{
+	return false;
+}
+
+void symsrc__destroy(struct symsrc *ss)
+{
+	free(ss->name);
+	close(ss->fd);
+}
+
+int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
+				struct symsrc *ss __maybe_unused,
+				struct map *map __maybe_unused,
+				symbol_filter_t filter __maybe_unused)
+{
+	return 0;
+}
+
+int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
+		  struct symsrc *ss,
+		  struct symsrc *runtime_ss __maybe_unused,
+		  symbol_filter_t filter __maybe_unused,
+		  int kmodule __maybe_unused)
+{
+	unsigned char *build_id[BUILD_ID_SIZE];
+
+	if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
+		dso__set_build_id(dso, build_id);
+		return 1;
+	}
+	return 0;
+}
+
+void symbol__elf_init(void)
+{
+}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8b63b67..e2e8c69 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -15,8 +15,6 @@
 #include "symbol.h"
 #include "strlist.h"
 
-#include <libelf.h>
-#include <gelf.h>
 #include <elf.h>
 #include <limits.h>
 #include <sys/utsname.h>
@@ -25,15 +23,7 @@
 #define KSYM_NAME_LEN 256
 #endif
 
-#ifndef NT_GNU_BUILD_ID
-#define NT_GNU_BUILD_ID 3
-#endif
-
 static void dso_cache__free(struct rb_root *root);
-static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
-static int elf_read_build_id(Elf *elf, void *bf, size_t size);
-static void dsos__add(struct list_head *head, struct dso *dso);
-static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
 static int dso__load_kernel_sym(struct dso *dso, struct map *map,
 				symbol_filter_t filter);
 static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -170,7 +160,7 @@
 		return SYMBOL_B;
 }
 
-static void symbols__fixup_duplicate(struct rb_root *symbols)
+void symbols__fixup_duplicate(struct rb_root *symbols)
 {
 	struct rb_node *nd;
 	struct symbol *curr, *next;
@@ -199,7 +189,7 @@
 	}
 }
 
-static void symbols__fixup_end(struct rb_root *symbols)
+void symbols__fixup_end(struct rb_root *symbols)
 {
 	struct rb_node *nd, *prevnd = rb_first(symbols);
 	struct symbol *curr, *prev;
@@ -222,7 +212,7 @@
 		curr->end = roundup(curr->start, 4096);
 }
 
-static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
+void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
 {
 	struct map *prev, *curr;
 	struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
@@ -252,8 +242,7 @@
 		__map_groups__fixup_end(mg, i);
 }
 
-static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
-				  const char *name)
+struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
 {
 	size_t namelen = strlen(name) + 1;
 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
@@ -390,7 +379,7 @@
 	dso->has_build_id = 1;
 }
 
-static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
+void symbols__insert(struct rb_root *symbols, struct symbol *sym)
 {
 	struct rb_node **p = &symbols->rb_node;
 	struct rb_node *parent = NULL;
@@ -574,7 +563,7 @@
 
 int kallsyms__parse(const char *filename, void *arg,
 		    int (*process_symbol)(void *arg, const char *name,
-					  char type, u64 start, u64 end))
+					  char type, u64 start))
 {
 	char *line = NULL;
 	size_t n;
@@ -614,13 +603,8 @@
 			break;
 		}
 
-		/*
-		 * module symbols are not sorted so we add all
-		 * symbols with zero length and rely on
-		 * symbols__fixup_end() to fix it up.
-		 */
 		err = process_symbol(arg, symbol_name,
-				     symbol_type, start, start);
+				     symbol_type, start);
 		if (err)
 			break;
 	}
@@ -647,7 +631,7 @@
 }
 
 static int map__process_kallsym_symbol(void *arg, const char *name,
-				       char type, u64 start, u64 end)
+				       char type, u64 start)
 {
 	struct symbol *sym;
 	struct process_kallsyms_args *a = arg;
@@ -656,8 +640,12 @@
 	if (!symbol_type__is_a(type, a->map->type))
 		return 0;
 
-	sym = symbol__new(start, end - start + 1,
-			  kallsyms2elf_type(type), name);
+	/*
+	 * module symbols are not sorted so we add all
+	 * symbols, setting length to 0, and rely on
+	 * symbols__fixup_end() to fix it up.
+	 */
+	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
 	if (sym == NULL)
 		return -ENOMEM;
 	/*
@@ -904,556 +892,7 @@
 	return -1;
 }
 
-/**
- * elf_symtab__for_each_symbol - iterate thru all the symbols
- *
- * @syms: struct elf_symtab instance to iterate
- * @idx: uint32_t idx
- * @sym: GElf_Sym iterator
- */
-#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
-	for (idx = 0, gelf_getsym(syms, idx, &sym);\
-	     idx < nr_syms; \
-	     idx++, gelf_getsym(syms, idx, &sym))
-
-static inline uint8_t elf_sym__type(const GElf_Sym *sym)
-{
-	return GELF_ST_TYPE(sym->st_info);
-}
-
-static inline int elf_sym__is_function(const GElf_Sym *sym)
-{
-	return elf_sym__type(sym) == STT_FUNC &&
-	       sym->st_name != 0 &&
-	       sym->st_shndx != SHN_UNDEF;
-}
-
-static inline bool elf_sym__is_object(const GElf_Sym *sym)
-{
-	return elf_sym__type(sym) == STT_OBJECT &&
-		sym->st_name != 0 &&
-		sym->st_shndx != SHN_UNDEF;
-}
-
-static inline int elf_sym__is_label(const GElf_Sym *sym)
-{
-	return elf_sym__type(sym) == STT_NOTYPE &&
-		sym->st_name != 0 &&
-		sym->st_shndx != SHN_UNDEF &&
-		sym->st_shndx != SHN_ABS;
-}
-
-static inline const char *elf_sec__name(const GElf_Shdr *shdr,
-					const Elf_Data *secstrs)
-{
-	return secstrs->d_buf + shdr->sh_name;
-}
-
-static inline int elf_sec__is_text(const GElf_Shdr *shdr,
-					const Elf_Data *secstrs)
-{
-	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
-}
-
-static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
-				    const Elf_Data *secstrs)
-{
-	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
-}
-
-static inline const char *elf_sym__name(const GElf_Sym *sym,
-					const Elf_Data *symstrs)
-{
-	return symstrs->d_buf + sym->st_name;
-}
-
-static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
-				    GElf_Shdr *shp, const char *name,
-				    size_t *idx)
-{
-	Elf_Scn *sec = NULL;
-	size_t cnt = 1;
-
-	while ((sec = elf_nextscn(elf, sec)) != NULL) {
-		char *str;
-
-		gelf_getshdr(sec, shp);
-		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
-		if (!strcmp(name, str)) {
-			if (idx)
-				*idx = cnt;
-			break;
-		}
-		++cnt;
-	}
-
-	return sec;
-}
-
-#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
-	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
-	     idx < nr_entries; \
-	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
-
-#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
-	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
-	     idx < nr_entries; \
-	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
-
-/*
- * We need to check if we have a .dynsym, so that we can handle the
- * .plt, synthesizing its symbols, that aren't on the symtabs (be it
- * .dynsym or .symtab).
- * And always look at the original dso, not at debuginfo packages, that
- * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
- */
-static int
-dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
-			    symbol_filter_t filter)
-{
-	uint32_t nr_rel_entries, idx;
-	GElf_Sym sym;
-	u64 plt_offset;
-	GElf_Shdr shdr_plt;
-	struct symbol *f;
-	GElf_Shdr shdr_rel_plt, shdr_dynsym;
-	Elf_Data *reldata, *syms, *symstrs;
-	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
-	size_t dynsym_idx;
-	GElf_Ehdr ehdr;
-	char sympltname[1024];
-	Elf *elf;
-	int nr = 0, symidx, fd, err = 0;
-
-	fd = open(name, O_RDONLY);
-	if (fd < 0)
-		goto out;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL)
-		goto out_close;
-
-	if (gelf_getehdr(elf, &ehdr) == NULL)
-		goto out_elf_end;
-
-	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
-					 ".dynsym", &dynsym_idx);
-	if (scn_dynsym == NULL)
-		goto out_elf_end;
-
-	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
-					  ".rela.plt", NULL);
-	if (scn_plt_rel == NULL) {
-		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
-						  ".rel.plt", NULL);
-		if (scn_plt_rel == NULL)
-			goto out_elf_end;
-	}
-
-	err = -1;
-
-	if (shdr_rel_plt.sh_link != dynsym_idx)
-		goto out_elf_end;
-
-	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
-		goto out_elf_end;
-
-	/*
-	 * Fetch the relocation section to find the idxes to the GOT
-	 * and the symbols in the .dynsym they refer to.
-	 */
-	reldata = elf_getdata(scn_plt_rel, NULL);
-	if (reldata == NULL)
-		goto out_elf_end;
-
-	syms = elf_getdata(scn_dynsym, NULL);
-	if (syms == NULL)
-		goto out_elf_end;
-
-	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
-	if (scn_symstrs == NULL)
-		goto out_elf_end;
-
-	symstrs = elf_getdata(scn_symstrs, NULL);
-	if (symstrs == NULL)
-		goto out_elf_end;
-
-	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
-	plt_offset = shdr_plt.sh_offset;
-
-	if (shdr_rel_plt.sh_type == SHT_RELA) {
-		GElf_Rela pos_mem, *pos;
-
-		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
-					   nr_rel_entries) {
-			symidx = GELF_R_SYM(pos->r_info);
-			plt_offset += shdr_plt.sh_entsize;
-			gelf_getsym(syms, symidx, &sym);
-			snprintf(sympltname, sizeof(sympltname),
-				 "%s@plt", elf_sym__name(&sym, symstrs));
-
-			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-					STB_GLOBAL, sympltname);
-			if (!f)
-				goto out_elf_end;
-
-			if (filter && filter(map, f))
-				symbol__delete(f);
-			else {
-				symbols__insert(&dso->symbols[map->type], f);
-				++nr;
-			}
-		}
-	} else if (shdr_rel_plt.sh_type == SHT_REL) {
-		GElf_Rel pos_mem, *pos;
-		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
-					  nr_rel_entries) {
-			symidx = GELF_R_SYM(pos->r_info);
-			plt_offset += shdr_plt.sh_entsize;
-			gelf_getsym(syms, symidx, &sym);
-			snprintf(sympltname, sizeof(sympltname),
-				 "%s@plt", elf_sym__name(&sym, symstrs));
-
-			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-					STB_GLOBAL, sympltname);
-			if (!f)
-				goto out_elf_end;
-
-			if (filter && filter(map, f))
-				symbol__delete(f);
-			else {
-				symbols__insert(&dso->symbols[map->type], f);
-				++nr;
-			}
-		}
-	}
-
-	err = 0;
-out_elf_end:
-	elf_end(elf);
-out_close:
-	close(fd);
-
-	if (err == 0)
-		return nr;
-out:
-	pr_debug("%s: problems reading %s PLT info.\n",
-		 __func__, dso->long_name);
-	return 0;
-}
-
-static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
-{
-	switch (type) {
-	case MAP__FUNCTION:
-		return elf_sym__is_function(sym);
-	case MAP__VARIABLE:
-		return elf_sym__is_object(sym);
-	default:
-		return false;
-	}
-}
-
-static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
-			  enum map_type type)
-{
-	switch (type) {
-	case MAP__FUNCTION:
-		return elf_sec__is_text(shdr, secstrs);
-	case MAP__VARIABLE:
-		return elf_sec__is_data(shdr, secstrs);
-	default:
-		return false;
-	}
-}
-
-static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
-{
-	Elf_Scn *sec = NULL;
-	GElf_Shdr shdr;
-	size_t cnt = 1;
-
-	while ((sec = elf_nextscn(elf, sec)) != NULL) {
-		gelf_getshdr(sec, &shdr);
-
-		if ((addr >= shdr.sh_addr) &&
-		    (addr < (shdr.sh_addr + shdr.sh_size)))
-			return cnt;
-
-		++cnt;
-	}
-
-	return -1;
-}
-
-static int dso__swap_init(struct dso *dso, unsigned char eidata)
-{
-	static unsigned int const endian = 1;
-
-	dso->needs_swap = DSO_SWAP__NO;
-
-	switch (eidata) {
-	case ELFDATA2LSB:
-		/* We are big endian, DSO is little endian. */
-		if (*(unsigned char const *)&endian != 1)
-			dso->needs_swap = DSO_SWAP__YES;
-		break;
-
-	case ELFDATA2MSB:
-		/* We are little endian, DSO is big endian. */
-		if (*(unsigned char const *)&endian != 0)
-			dso->needs_swap = DSO_SWAP__YES;
-		break;
-
-	default:
-		pr_err("unrecognized DSO data encoding %d\n", eidata);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
-			 int fd, symbol_filter_t filter, int kmodule,
-			 int want_symtab)
-{
-	struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
-	struct map *curr_map = map;
-	struct dso *curr_dso = dso;
-	Elf_Data *symstrs, *secstrs;
-	uint32_t nr_syms;
-	int err = -1;
-	uint32_t idx;
-	GElf_Ehdr ehdr;
-	GElf_Shdr shdr, opdshdr;
-	Elf_Data *syms, *opddata = NULL;
-	GElf_Sym sym;
-	Elf_Scn *sec, *sec_strndx, *opdsec;
-	Elf *elf;
-	int nr = 0;
-	size_t opdidx = 0;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL) {
-		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
-		goto out_close;
-	}
-
-	if (gelf_getehdr(elf, &ehdr) == NULL) {
-		pr_debug("%s: cannot get elf header.\n", __func__);
-		goto out_elf_end;
-	}
-
-	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
-		goto out_elf_end;
-
-	/* Always reject images with a mismatched build-id: */
-	if (dso->has_build_id) {
-		u8 build_id[BUILD_ID_SIZE];
-
-		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
-			goto out_elf_end;
-
-		if (!dso__build_id_equal(dso, build_id))
-			goto out_elf_end;
-	}
-
-	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
-	if (sec == NULL) {
-		if (want_symtab)
-			goto out_elf_end;
-
-		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
-		if (sec == NULL)
-			goto out_elf_end;
-	}
-
-	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
-	if (opdshdr.sh_type != SHT_PROGBITS)
-		opdsec = NULL;
-	if (opdsec)
-		opddata = elf_rawdata(opdsec, NULL);
-
-	syms = elf_getdata(sec, NULL);
-	if (syms == NULL)
-		goto out_elf_end;
-
-	sec = elf_getscn(elf, shdr.sh_link);
-	if (sec == NULL)
-		goto out_elf_end;
-
-	symstrs = elf_getdata(sec, NULL);
-	if (symstrs == NULL)
-		goto out_elf_end;
-
-	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
-	if (sec_strndx == NULL)
-		goto out_elf_end;
-
-	secstrs = elf_getdata(sec_strndx, NULL);
-	if (secstrs == NULL)
-		goto out_elf_end;
-
-	nr_syms = shdr.sh_size / shdr.sh_entsize;
-
-	memset(&sym, 0, sizeof(sym));
-	if (dso->kernel == DSO_TYPE_USER) {
-		dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
-				elf_section_by_name(elf, &ehdr, &shdr,
-						     ".gnu.prelink_undo",
-						     NULL) != NULL);
-	} else {
-		dso->adjust_symbols = 0;
-	}
-	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
-		struct symbol *f;
-		const char *elf_name = elf_sym__name(&sym, symstrs);
-		char *demangled = NULL;
-		int is_label = elf_sym__is_label(&sym);
-		const char *section_name;
-
-		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
-		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
-			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
-
-		if (!is_label && !elf_sym__is_a(&sym, map->type))
-			continue;
-
-		/* Reject ARM ELF "mapping symbols": these aren't unique and
-		 * don't identify functions, so will confuse the profile
-		 * output: */
-		if (ehdr.e_machine == EM_ARM) {
-			if (!strcmp(elf_name, "$a") ||
-			    !strcmp(elf_name, "$d") ||
-			    !strcmp(elf_name, "$t"))
-				continue;
-		}
-
-		if (opdsec && sym.st_shndx == opdidx) {
-			u32 offset = sym.st_value - opdshdr.sh_addr;
-			u64 *opd = opddata->d_buf + offset;
-			sym.st_value = DSO__SWAP(dso, u64, *opd);
-			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
-		}
-
-		sec = elf_getscn(elf, sym.st_shndx);
-		if (!sec)
-			goto out_elf_end;
-
-		gelf_getshdr(sec, &shdr);
-
-		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
-			continue;
-
-		section_name = elf_sec__name(&shdr, secstrs);
-
-		/* On ARM, symbols for thumb functions have 1 added to
-		 * the symbol address as a flag - remove it */
-		if ((ehdr.e_machine == EM_ARM) &&
-		    (map->type == MAP__FUNCTION) &&
-		    (sym.st_value & 1))
-			--sym.st_value;
-
-		if (dso->kernel != DSO_TYPE_USER || kmodule) {
-			char dso_name[PATH_MAX];
-
-			if (strcmp(section_name,
-				   (curr_dso->short_name +
-				    dso->short_name_len)) == 0)
-				goto new_symbol;
-
-			if (strcmp(section_name, ".text") == 0) {
-				curr_map = map;
-				curr_dso = dso;
-				goto new_symbol;
-			}
-
-			snprintf(dso_name, sizeof(dso_name),
-				 "%s%s", dso->short_name, section_name);
-
-			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
-			if (curr_map == NULL) {
-				u64 start = sym.st_value;
-
-				if (kmodule)
-					start += map->start + shdr.sh_offset;
-
-				curr_dso = dso__new(dso_name);
-				if (curr_dso == NULL)
-					goto out_elf_end;
-				curr_dso->kernel = dso->kernel;
-				curr_dso->long_name = dso->long_name;
-				curr_dso->long_name_len = dso->long_name_len;
-				curr_map = map__new2(start, curr_dso,
-						     map->type);
-				if (curr_map == NULL) {
-					dso__delete(curr_dso);
-					goto out_elf_end;
-				}
-				curr_map->map_ip = identity__map_ip;
-				curr_map->unmap_ip = identity__map_ip;
-				curr_dso->symtab_type = dso->symtab_type;
-				map_groups__insert(kmap->kmaps, curr_map);
-				dsos__add(&dso->node, curr_dso);
-				dso__set_loaded(curr_dso, map->type);
-			} else
-				curr_dso = curr_map->dso;
-
-			goto new_symbol;
-		}
-
-		if (curr_dso->adjust_symbols) {
-			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
-				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
-				  (u64)sym.st_value, (u64)shdr.sh_addr,
-				  (u64)shdr.sh_offset);
-			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
-		}
-		/*
-		 * We need to figure out if the object was created from C++ sources
-		 * DWARF DW_compile_unit has this, but we don't always have access
-		 * to it...
-		 */
-		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
-		if (demangled != NULL)
-			elf_name = demangled;
-new_symbol:
-		f = symbol__new(sym.st_value, sym.st_size,
-				GELF_ST_BIND(sym.st_info), elf_name);
-		free(demangled);
-		if (!f)
-			goto out_elf_end;
-
-		if (filter && filter(curr_map, f))
-			symbol__delete(f);
-		else {
-			symbols__insert(&curr_dso->symbols[curr_map->type], f);
-			nr++;
-		}
-	}
-
-	/*
-	 * For misannotated, zeroed, ASM function sizes.
-	 */
-	if (nr > 0) {
-		symbols__fixup_duplicate(&dso->symbols[map->type]);
-		symbols__fixup_end(&dso->symbols[map->type]);
-		if (kmap) {
-			/*
-			 * We need to fixup this here too because we create new
-			 * maps here, for things like vsyscall sections.
-			 */
-			__map_groups__fixup_end(kmap->kmaps, map->type);
-		}
-	}
-	err = nr;
-out_elf_end:
-	elf_end(elf);
-out_close:
-	return err;
-}
-
-static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
+bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
 {
 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
 }
@@ -1480,216 +919,11 @@
 	return have_build_id;
 }
 
-/*
- * Align offset to 4 bytes as needed for note name and descriptor data.
- */
-#define NOTE_ALIGN(n) (((n) + 3) & -4U)
-
-static int elf_read_build_id(Elf *elf, void *bf, size_t size)
-{
-	int err = -1;
-	GElf_Ehdr ehdr;
-	GElf_Shdr shdr;
-	Elf_Data *data;
-	Elf_Scn *sec;
-	Elf_Kind ek;
-	void *ptr;
-
-	if (size < BUILD_ID_SIZE)
-		goto out;
-
-	ek = elf_kind(elf);
-	if (ek != ELF_K_ELF)
-		goto out;
-
-	if (gelf_getehdr(elf, &ehdr) == NULL) {
-		pr_err("%s: cannot get elf header.\n", __func__);
-		goto out;
-	}
-
-	/*
-	 * Check following sections for notes:
-	 *   '.note.gnu.build-id'
-	 *   '.notes'
-	 *   '.note' (VDSO specific)
-	 */
-	do {
-		sec = elf_section_by_name(elf, &ehdr, &shdr,
-					  ".note.gnu.build-id", NULL);
-		if (sec)
-			break;
-
-		sec = elf_section_by_name(elf, &ehdr, &shdr,
-					  ".notes", NULL);
-		if (sec)
-			break;
-
-		sec = elf_section_by_name(elf, &ehdr, &shdr,
-					  ".note", NULL);
-		if (sec)
-			break;
-
-		return err;
-
-	} while (0);
-
-	data = elf_getdata(sec, NULL);
-	if (data == NULL)
-		goto out;
-
-	ptr = data->d_buf;
-	while (ptr < (data->d_buf + data->d_size)) {
-		GElf_Nhdr *nhdr = ptr;
-		size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
-		       descsz = NOTE_ALIGN(nhdr->n_descsz);
-		const char *name;
-
-		ptr += sizeof(*nhdr);
-		name = ptr;
-		ptr += namesz;
-		if (nhdr->n_type == NT_GNU_BUILD_ID &&
-		    nhdr->n_namesz == sizeof("GNU")) {
-			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
-				size_t sz = min(size, descsz);
-				memcpy(bf, ptr, sz);
-				memset(bf + sz, 0, size - sz);
-				err = descsz;
-				break;
-			}
-		}
-		ptr += descsz;
-	}
-
-out:
-	return err;
-}
-
-int filename__read_build_id(const char *filename, void *bf, size_t size)
-{
-	int fd, err = -1;
-	Elf *elf;
-
-	if (size < BUILD_ID_SIZE)
-		goto out;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		goto out;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL) {
-		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
-		goto out_close;
-	}
-
-	err = elf_read_build_id(elf, bf, size);
-
-	elf_end(elf);
-out_close:
-	close(fd);
-out:
-	return err;
-}
-
-int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
-{
-	int fd, err = -1;
-
-	if (size < BUILD_ID_SIZE)
-		goto out;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		goto out;
-
-	while (1) {
-		char bf[BUFSIZ];
-		GElf_Nhdr nhdr;
-		size_t namesz, descsz;
-
-		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
-			break;
-
-		namesz = NOTE_ALIGN(nhdr.n_namesz);
-		descsz = NOTE_ALIGN(nhdr.n_descsz);
-		if (nhdr.n_type == NT_GNU_BUILD_ID &&
-		    nhdr.n_namesz == sizeof("GNU")) {
-			if (read(fd, bf, namesz) != (ssize_t)namesz)
-				break;
-			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
-				size_t sz = min(descsz, size);
-				if (read(fd, build_id, sz) == (ssize_t)sz) {
-					memset(build_id + sz, 0, size - sz);
-					err = 0;
-					break;
-				}
-			} else if (read(fd, bf, descsz) != (ssize_t)descsz)
-				break;
-		} else {
-			int n = namesz + descsz;
-			if (read(fd, bf, n) != n)
-				break;
-		}
-	}
-	close(fd);
-out:
-	return err;
-}
-
-static int filename__read_debuglink(const char *filename,
-				    char *debuglink, size_t size)
-{
-	int fd, err = -1;
-	Elf *elf;
-	GElf_Ehdr ehdr;
-	GElf_Shdr shdr;
-	Elf_Data *data;
-	Elf_Scn *sec;
-	Elf_Kind ek;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		goto out;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL) {
-		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
-		goto out_close;
-	}
-
-	ek = elf_kind(elf);
-	if (ek != ELF_K_ELF)
-		goto out_close;
-
-	if (gelf_getehdr(elf, &ehdr) == NULL) {
-		pr_err("%s: cannot get elf header.\n", __func__);
-		goto out_close;
-	}
-
-	sec = elf_section_by_name(elf, &ehdr, &shdr,
-				  ".gnu_debuglink", NULL);
-	if (sec == NULL)
-		goto out_close;
-
-	data = elf_getdata(sec, NULL);
-	if (data == NULL)
-		goto out_close;
-
-	/* the start of this section is a zero-terminated string */
-	strncpy(debuglink, data->d_buf, size);
-
-	elf_end(elf);
-
-out_close:
-	close(fd);
-out:
-	return err;
-}
-
 char dso__symtab_origin(const struct dso *dso)
 {
 	static const char origin[] = {
 		[DSO_BINARY_TYPE__KALLSYMS]		= 'k',
+		[DSO_BINARY_TYPE__VMLINUX]		= 'v',
 		[DSO_BINARY_TYPE__JAVA_JIT]		= 'j',
 		[DSO_BINARY_TYPE__DEBUGLINK]		= 'l',
 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]	= 'B',
@@ -1700,6 +934,7 @@
 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]	= 'K',
 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]	= 'g',
 		[DSO_BINARY_TYPE__GUEST_KMODULE]	= 'G',
+		[DSO_BINARY_TYPE__GUEST_VMLINUX]	= 'V',
 	};
 
 	if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
@@ -1775,7 +1010,9 @@
 
 	default:
 	case DSO_BINARY_TYPE__KALLSYMS:
+	case DSO_BINARY_TYPE__VMLINUX:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
+	case DSO_BINARY_TYPE__GUEST_VMLINUX:
 	case DSO_BINARY_TYPE__JAVA_JIT:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
@@ -1789,11 +1026,12 @@
 {
 	char *name;
 	int ret = -1;
-	int fd;
 	u_int i;
 	struct machine *machine;
 	char *root_dir = (char *) "";
-	int want_symtab;
+	int ss_pos = 0;
+	struct symsrc ss_[2];
+	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
 
 	dso__set_loaded(dso, map->type);
 
@@ -1835,54 +1073,69 @@
 		root_dir = machine->root_dir;
 
 	/* Iterate over candidate debug images.
-	 * On the first pass, only load images if they have a full symtab.
-	 * Failing that, do a second pass where we accept .dynsym also
+	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
+	 * and/or opd section) for processing.
 	 */
-	want_symtab = 1;
-restart:
 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
+		struct symsrc *ss = &ss_[ss_pos];
+		bool next_slot = false;
 
-		dso->symtab_type = binary_type_symtab[i];
+		enum dso_binary_type symtab_type = binary_type_symtab[i];
 
-		if (dso__binary_type_file(dso, dso->symtab_type,
+		if (dso__binary_type_file(dso, symtab_type,
 					  root_dir, name, PATH_MAX))
 			continue;
 
 		/* Name is now the name of the next image to try */
-		fd = open(name, O_RDONLY);
-		if (fd < 0)
+		if (symsrc__init(ss, dso, name, symtab_type) < 0)
 			continue;
 
-		ret = dso__load_sym(dso, map, name, fd, filter, 0,
-				    want_symtab);
-		close(fd);
-
-		/*
-		 * Some people seem to have debuginfo files _WITHOUT_ debug
-		 * info!?!?
-		 */
-		if (!ret)
-			continue;
-
-		if (ret > 0) {
-			int nr_plt;
-
-			nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
-			if (nr_plt > 0)
-				ret += nr_plt;
-			break;
+		if (!syms_ss && symsrc__has_symtab(ss)) {
+			syms_ss = ss;
+			next_slot = true;
 		}
+
+		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
+			runtime_ss = ss;
+			next_slot = true;
+		}
+
+		if (next_slot) {
+			ss_pos++;
+
+			if (syms_ss && runtime_ss)
+				break;
+		}
+
 	}
 
-	/*
-	 * If we wanted a full symtab but no image had one,
-	 * relax our requirements and repeat the search.
-	 */
-	if (ret <= 0 && want_symtab) {
-		want_symtab = 0;
-		goto restart;
+	if (!runtime_ss && !syms_ss)
+		goto out_free;
+
+	if (runtime_ss && !syms_ss) {
+		syms_ss = runtime_ss;
 	}
 
+	/* We'll have to hope for the best */
+	if (!runtime_ss && syms_ss)
+		runtime_ss = syms_ss;
+
+	if (syms_ss)
+		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
+	else
+		ret = -1;
+
+	if (ret > 0) {
+		int nr_plt;
+
+		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
+		if (nr_plt > 0)
+			ret += nr_plt;
+	}
+
+	for (; ss_pos > 0; ss_pos--)
+		symsrc__destroy(&ss_[ss_pos - 1]);
+out_free:
 	free(name);
 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
 		return 0;
@@ -2030,25 +1283,6 @@
 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
 }
 
-/*
- * Constructor variant for modules (where we know from /proc/modules where
- * they are loaded) and for vmlinux, where only after we load all the
- * symbols we'll know where it starts and ends.
- */
-static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
-{
-	struct map *map = calloc(1, (sizeof(*map) +
-				     (dso->kernel ? sizeof(struct kmap) : 0)));
-	if (map != NULL) {
-		/*
-		 * ->end will be filled after we load all the symbols
-		 */
-		map__init(map, type, start, 0, 0, dso);
-	}
-
-	return map;
-}
-
 struct map *machine__new_module(struct machine *machine, u64 start,
 				const char *filename)
 {
@@ -2141,22 +1375,30 @@
 int dso__load_vmlinux(struct dso *dso, struct map *map,
 		      const char *vmlinux, symbol_filter_t filter)
 {
-	int err = -1, fd;
+	int err = -1;
+	struct symsrc ss;
 	char symfs_vmlinux[PATH_MAX];
+	enum dso_binary_type symtab_type;
 
 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
 		 symbol_conf.symfs, vmlinux);
-	fd = open(symfs_vmlinux, O_RDONLY);
-	if (fd < 0)
+
+	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
+		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
+	else
+		symtab_type = DSO_BINARY_TYPE__VMLINUX;
+
+	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
 		return -1;
 
-	dso__set_long_name(dso, (char *)vmlinux);
-	dso__set_loaded(dso, map->type);
-	err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
-	close(fd);
+	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
+	symsrc__destroy(&ss);
 
-	if (err > 0)
+	if (err > 0) {
+		dso__set_long_name(dso, (char *)vmlinux);
+		dso__set_loaded(dso, map->type);
 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
+	}
 
 	return err;
 }
@@ -2173,10 +1415,8 @@
 	filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, filter);
-		if (err > 0) {
-			dso__set_long_name(dso, filename);
+		if (err > 0)
 			goto out;
-		}
 		free(filename);
 	}
 
@@ -2291,9 +1531,8 @@
 	free(kallsyms_allocated_filename);
 
 	if (err > 0) {
+		dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
 out_fixup:
-		if (kallsyms_filename != NULL)
-			dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
 		map__fixup_start(map);
 		map__fixup_end(map);
 	}
@@ -2352,12 +1591,12 @@
 	return err;
 }
 
-static void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct list_head *head, struct dso *dso)
 {
 	list_add_tail(&dso->node, head);
 }
 
-static struct dso *dsos__find(struct list_head *head, const char *name)
+struct dso *dsos__find(struct list_head *head, const char *name)
 {
 	struct dso *pos;
 
@@ -2516,7 +1755,7 @@
 };
 
 static int symbol__in_kernel(void *arg, const char *name,
-			     char type __used, u64 start, u64 end __used)
+			     char type __maybe_unused, u64 start)
 {
 	struct process_args *args = arg;
 
@@ -2752,9 +1991,10 @@
 	if (symbol_conf.initialized)
 		return 0;
 
-	symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
+	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
 
-	elf_version(EV_CURRENT);
+	symbol__elf_init();
+
 	if (symbol_conf.sort_by_name)
 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
 					  sizeof(struct symbol));
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 1fe733a..b441b071 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -10,22 +10,31 @@
 #include <linux/rbtree.h>
 #include <stdio.h>
 #include <byteswap.h>
+#include <libgen.h>
+
+#ifndef NO_LIBELF_SUPPORT
+#include <libelf.h>
+#include <gelf.h>
+#include <elf.h>
+#endif
 
 #ifdef HAVE_CPLUS_DEMANGLE
 extern char *cplus_demangle(const char *, int);
 
-static inline char *bfd_demangle(void __used *v, const char *c, int i)
+static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
 {
 	return cplus_demangle(c, i);
 }
 #else
 #ifdef NO_DEMANGLE
-static inline char *bfd_demangle(void __used *v, const char __used *c,
-				 int __used i)
+static inline char *bfd_demangle(void __maybe_unused *v,
+				 const char __maybe_unused *c,
+				 int __maybe_unused i)
 {
 	return NULL;
 }
 #else
+#define PACKAGE 'perf'
 #include <bfd.h>
 #endif
 #endif
@@ -158,6 +167,8 @@
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
+	DSO_BINARY_TYPE__VMLINUX,
+	DSO_BINARY_TYPE__GUEST_VMLINUX,
 	DSO_BINARY_TYPE__JAVA_JIT,
 	DSO_BINARY_TYPE__DEBUGLINK,
 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
@@ -217,6 +228,36 @@
 	char		 name[0];
 };
 
+struct symsrc {
+	char *name;
+	int fd;
+	enum dso_binary_type type;
+
+#ifndef NO_LIBELF_SUPPORT
+	Elf *elf;
+	GElf_Ehdr ehdr;
+
+	Elf_Scn *opdsec;
+	size_t opdidx;
+	GElf_Shdr opdshdr;
+
+	Elf_Scn *symtab;
+	GElf_Shdr symshdr;
+
+	Elf_Scn *dynsym;
+	size_t dynsym_idx;
+	GElf_Shdr dynshdr;
+
+	bool adjust_symbols;
+#endif
+};
+
+void symsrc__destroy(struct symsrc *ss);
+int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
+		 enum dso_binary_type type);
+bool symsrc__has_symtab(struct symsrc *ss);
+bool symsrc__possibly_runtime(struct symsrc *ss);
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -254,6 +295,8 @@
 
 void dso__sort_by_name(struct dso *dso, enum map_type type);
 
+void dsos__add(struct list_head *head, struct dso *dso);
+struct dso *dsos__find(struct list_head *head, const char *name);
 struct dso *__dsos__findnew(struct list_head *head, const char *name);
 
 int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
@@ -283,6 +326,7 @@
 char dso__symtab_origin(const struct dso *dso);
 void dso__set_long_name(struct dso *dso, char *name);
 void dso__set_build_id(struct dso *dso, void *build_id);
+bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
 void dso__read_running_kernel_build_id(struct dso *dso,
 				       struct machine *machine);
 struct map *dso__new_map(const char *name);
@@ -297,7 +341,9 @@
 int build_id__sprintf(const u8 *build_id, int len, char *bf);
 int kallsyms__parse(const char *filename, void *arg,
 		    int (*process_symbol)(void *arg, const char *name,
-					  char type, u64 start, u64 end));
+					  char type, u64 start));
+int filename__read_debuglink(const char *filename, char *debuglink,
+			     size_t size);
 
 void machine__destroy_kernel_maps(struct machine *machine);
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
@@ -309,6 +355,8 @@
 
 int symbol__init(void);
 void symbol__exit(void);
+void symbol__elf_init(void);
+struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
 size_t symbol__fprintf_symname_offs(const struct symbol *sym,
 				    const struct addr_location *al, FILE *fp);
 size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
@@ -326,4 +374,15 @@
 			    struct machine *machine, u64 addr,
 			    u8 *data, ssize_t size);
 int dso__test_data(void);
+int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
+		  struct symsrc *runtime_ss, symbol_filter_t filter,
+		  int kmodule);
+int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
+				struct map *map, symbol_filter_t filter);
+
+void symbols__insert(struct rb_root *symbols, struct symbol *sym);
+void symbols__fixup_duplicate(struct rb_root *symbols);
+void symbols__fixup_end(struct rb_root *symbols);
+void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
+
 #endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 051eaa6..065528b 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -117,8 +117,8 @@
 
 		if (err != buf) {
 			size_t len = strlen(err);
-			char *c = mempcpy(buf, err, min(buflen - 1, len));
-			*c = '\0';
+			memcpy(buf, err, min(buflen - 1, len));
+			*(buf + min(buflen - 1, len)) = '\0';
 		}
 
 		return 0;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 70c2c13..f66610b 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -16,6 +16,8 @@
 	bool			comm_set;
 	char			*comm;
 	int			comm_len;
+
+	void			*priv;
 };
 
 struct machine;
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 7eeebce..884dde9 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -58,8 +58,7 @@
 	}
 
 	if (top->evlist->nr_entries == 1) {
-		struct perf_evsel *first;
-		first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
+		struct perf_evsel *first = perf_evlist__first(top->evlist);
 		ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
 				(uint64_t)first->attr.sample_period,
 				top->freq ? "Hz" : "");
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 33347ca..86ff1b1 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -5,6 +5,7 @@
 #include "types.h"
 #include <stddef.h>
 #include <stdbool.h>
+#include <termios.h>
 
 struct perf_evlist;
 struct perf_evsel;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 0715c84..3aabcd6 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -162,25 +162,16 @@
 	return pevent_data_pid(pevent, &record);
 }
 
-unsigned long long read_size(struct pevent *pevent, void *ptr, int size)
+unsigned long long read_size(struct event_format *event, void *ptr, int size)
 {
-	return pevent_read_number(pevent, ptr, size);
+	return pevent_read_number(event->pevent, ptr, size);
 }
 
-void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
+void event_format__print(struct event_format *event,
+			 int cpu, void *data, int size)
 {
-	struct event_format *event;
 	struct pevent_record record;
 	struct trace_seq s;
-	int type;
-
-	type = trace_parse_common_type(pevent, data);
-
-	event = pevent_find_event(pevent, type);
-	if (!event) {
-		warning("ug! no event found for type %d", type);
-		return;
-	}
 
 	memset(&record, 0, sizeof(record));
 	record.cpu = cpu;
@@ -192,6 +183,19 @@
 	trace_seq_do_printf(&s);
 }
 
+void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
+{
+	int type = trace_parse_common_type(pevent, data);
+	struct event_format *event = pevent_find_event(pevent, type);
+
+	if (!event) {
+		warning("ug! no event found for type %d", type);
+		return;
+	}
+
+	event_format__print(event, cpu, data, size);
+}
+
 void print_event(struct pevent *pevent, int cpu, void *data, int size,
 		 unsigned long long nsecs, char *comm)
 {
@@ -217,7 +221,7 @@
 }
 
 void parse_proc_kallsyms(struct pevent *pevent,
-			 char *file, unsigned int size __unused)
+			 char *file, unsigned int size __maybe_unused)
 {
 	unsigned long long addr;
 	char *func;
@@ -225,31 +229,29 @@
 	char *next = NULL;
 	char *addr_str;
 	char *mod;
-	char ch;
+	char *fmt;
 
 	line = strtok_r(file, "\n", &next);
 	while (line) {
 		mod = NULL;
-		sscanf(line, "%as %c %as\t[%as",
-		       (float *)(void *)&addr_str, /* workaround gcc warning */
-		       &ch, (float *)(void *)&func, (float *)(void *)&mod);
+		addr_str = strtok_r(line, " ", &fmt);
 		addr = strtoull(addr_str, NULL, 16);
-		free(addr_str);
-
-		/* truncate the extra ']' */
+		/* skip character */
+		strtok_r(NULL, " ", &fmt);
+		func = strtok_r(NULL, "\t", &fmt);
+		mod = strtok_r(NULL, "]", &fmt);
+		/* truncate the extra '[' */
 		if (mod)
-			mod[strlen(mod) - 1] = 0;
+			mod = mod + 1;
 
 		pevent_register_function(pevent, func, addr, mod);
-		free(func);
-		free(mod);
 
 		line = strtok_r(NULL, "\n", &next);
 	}
 }
 
 void parse_ftrace_printk(struct pevent *pevent,
-			 char *file, unsigned int size __unused)
+			 char *file, unsigned int size __maybe_unused)
 {
 	unsigned long long addr;
 	char *printk;
@@ -289,7 +291,7 @@
 {
 	static int idx;
 
-	if (!pevent->events)
+	if (!pevent || !pevent->events)
 		return NULL;
 
 	if (!event) {
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 474aa7a..8715a10 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -35,12 +35,11 @@
 	return 0;
 }
 
-static void process_event_unsupported(union perf_event *event __unused,
-				      struct pevent *pevent __unused,
-				      struct perf_sample *sample __unused,
-				      struct perf_evsel *evsel __unused,
-				      struct machine *machine __unused,
-				      struct thread *thread __unused)
+static void process_event_unsupported(union perf_event *event __maybe_unused,
+				      struct perf_sample *sample __maybe_unused,
+				      struct perf_evsel *evsel __maybe_unused,
+				      struct machine *machine __maybe_unused,
+				      struct addr_location *al __maybe_unused)
 {
 }
 
@@ -53,17 +52,19 @@
 		"\n  etc.\n");
 }
 
-static int python_start_script_unsupported(const char *script __unused,
-					   int argc __unused,
-					   const char **argv __unused)
+static int python_start_script_unsupported(const char *script __maybe_unused,
+					   int argc __maybe_unused,
+					   const char **argv __maybe_unused)
 {
 	print_python_unsupported_msg();
 
 	return -1;
 }
 
-static int python_generate_script_unsupported(struct pevent *pevent __unused,
-					      const char *outfile __unused)
+static int python_generate_script_unsupported(struct pevent *pevent
+					      __maybe_unused,
+					      const char *outfile
+					      __maybe_unused)
 {
 	print_python_unsupported_msg();
 
@@ -115,17 +116,18 @@
 		"\n  etc.\n");
 }
 
-static int perl_start_script_unsupported(const char *script __unused,
-					 int argc __unused,
-					 const char **argv __unused)
+static int perl_start_script_unsupported(const char *script __maybe_unused,
+					 int argc __maybe_unused,
+					 const char **argv __maybe_unused)
 {
 	print_perl_unsupported_msg();
 
 	return -1;
 }
 
-static int perl_generate_script_unsupported(struct pevent *pevent __unused,
-					    const char *outfile __unused)
+static int perl_generate_script_unsupported(struct pevent *pevent
+					    __maybe_unused,
+					    const char *outfile __maybe_unused)
 {
 	print_perl_unsupported_msg();
 
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 8fef1d6..a55fd37 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -9,7 +9,6 @@
 struct perf_sample;
 union perf_event;
 struct perf_tool;
-struct thread;
 
 extern int header_page_size_size;
 extern int header_page_ts_size;
@@ -32,6 +31,8 @@
 
 struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
 void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
+void event_format__print(struct event_format *event,
+			 int cpu, void *data, int size);
 
 void print_event(struct pevent *pevent, int cpu, void *data, int size,
 		 unsigned long long nsecs, char *comm);
@@ -56,7 +57,7 @@
 
 struct event_format *trace_find_next_event(struct pevent *pevent,
 					   struct event_format *event);
-unsigned long long read_size(struct pevent *pevent, void *ptr, int size);
+unsigned long long read_size(struct event_format *event, void *ptr, int size);
 unsigned long long eval_flag(const char *flag);
 
 struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
@@ -74,16 +75,19 @@
 void tracing_data_put(struct tracing_data *tdata);
 
 
+struct addr_location;
+
+struct perf_session;
+
 struct scripting_ops {
 	const char *name;
 	int (*start_script) (const char *script, int argc, const char **argv);
 	int (*stop_script) (void);
 	void (*process_event) (union perf_event *event,
-			       struct pevent *pevent,
 			       struct perf_sample *sample,
 			       struct perf_evsel *evsel,
 			       struct machine *machine,
-			       struct thread *thread);
+			       struct addr_location *al);
 	int (*generate_script) (struct pevent *pevent, const char *outfile);
 };
 
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
new file mode 100644
index 0000000..958723b
--- /dev/null
+++ b/tools/perf/util/unwind.c
@@ -0,0 +1,571 @@
+/*
+ * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
+ *
+ * Lots of this code have been borrowed or heavily inspired from parts of
+ * the libunwind 0.99 code which are (amongst other contributors I may have
+ * forgotten):
+ *
+ * Copyright (C) 2002-2007 Hewlett-Packard Co
+ *	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * And the bugs have been added by:
+ *
+ * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
+ * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
+ *
+ */
+
+#include <elf.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/list.h>
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+#include "thread.h"
+#include "session.h"
+#include "perf_regs.h"
+#include "unwind.h"
+#include "util.h"
+
+extern int
+UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+				    unw_word_t ip,
+				    unw_dyn_info_t *di,
+				    unw_proc_info_t *pi,
+				    int need_unwind_info, void *arg);
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+#define DW_EH_PE_FORMAT_MASK	0x0f	/* format of the encoded value */
+#define DW_EH_PE_APPL_MASK	0x70	/* how the value is to be applied */
+
+/* Pointer-encoding formats: */
+#define DW_EH_PE_omit		0xff
+#define DW_EH_PE_ptr		0x00	/* pointer-sized unsigned value */
+#define DW_EH_PE_udata4		0x03	/* unsigned 32-bit value */
+#define DW_EH_PE_udata8		0x04	/* unsigned 64-bit value */
+#define DW_EH_PE_sdata4		0x0b	/* signed 32-bit value */
+#define DW_EH_PE_sdata8		0x0c	/* signed 64-bit value */
+
+/* Pointer-encoding application: */
+#define DW_EH_PE_absptr		0x00	/* absolute value */
+#define DW_EH_PE_pcrel		0x10	/* rel. to addr. of encoded value */
+
+/*
+ * The following are not documented by LSB v1.3, yet they are used by
+ * GCC, presumably they aren't documented by LSB since they aren't
+ * used on Linux:
+ */
+#define DW_EH_PE_funcrel	0x40	/* start-of-procedure-relative */
+#define DW_EH_PE_aligned	0x50	/* aligned pointer */
+
+/* Flags intentionaly not handled, since they're not needed:
+ * #define DW_EH_PE_indirect      0x80
+ * #define DW_EH_PE_uleb128       0x01
+ * #define DW_EH_PE_udata2        0x02
+ * #define DW_EH_PE_sleb128       0x09
+ * #define DW_EH_PE_sdata2        0x0a
+ * #define DW_EH_PE_textrel       0x20
+ * #define DW_EH_PE_datarel       0x30
+ */
+
+struct unwind_info {
+	struct perf_sample	*sample;
+	struct machine		*machine;
+	struct thread		*thread;
+	u64			sample_uregs;
+};
+
+#define dw_read(ptr, type, end) ({	\
+	type *__p = (type *) ptr;	\
+	type  __v;			\
+	if ((__p + 1) > (type *) end)	\
+		return -EINVAL;		\
+	__v = *__p++;			\
+	ptr = (typeof(ptr)) __p;	\
+	__v;				\
+	})
+
+static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
+				   u8 encoding)
+{
+	u8 *cur = *p;
+	*val = 0;
+
+	switch (encoding) {
+	case DW_EH_PE_omit:
+		*val = 0;
+		goto out;
+	case DW_EH_PE_ptr:
+		*val = dw_read(cur, unsigned long, end);
+		goto out;
+	default:
+		break;
+	}
+
+	switch (encoding & DW_EH_PE_APPL_MASK) {
+	case DW_EH_PE_absptr:
+		break;
+	case DW_EH_PE_pcrel:
+		*val = (unsigned long) cur;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((encoding & 0x07) == 0x00)
+		encoding |= DW_EH_PE_udata4;
+
+	switch (encoding & DW_EH_PE_FORMAT_MASK) {
+	case DW_EH_PE_sdata4:
+		*val += dw_read(cur, s32, end);
+		break;
+	case DW_EH_PE_udata4:
+		*val += dw_read(cur, u32, end);
+		break;
+	case DW_EH_PE_sdata8:
+		*val += dw_read(cur, s64, end);
+		break;
+	case DW_EH_PE_udata8:
+		*val += dw_read(cur, u64, end);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+ out:
+	*p = cur;
+	return 0;
+}
+
+#define dw_read_encoded_value(ptr, end, enc) ({			\
+	u64 __v;						\
+	if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {	\
+		return -EINVAL;                                 \
+	}                                                       \
+	__v;                                                    \
+	})
+
+static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
+				    GElf_Shdr *shp, const char *name)
+{
+	Elf_Scn *sec = NULL;
+
+	while ((sec = elf_nextscn(elf, sec)) != NULL) {
+		char *str;
+
+		gelf_getshdr(sec, shp);
+		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+		if (!strcmp(name, str))
+			break;
+	}
+
+	return sec;
+}
+
+static u64 elf_section_offset(int fd, const char *name)
+{
+	Elf *elf;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	u64 offset = 0;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return 0;
+
+	do {
+		if (gelf_getehdr(elf, &ehdr) == NULL)
+			break;
+
+		if (!elf_section_by_name(elf, &ehdr, &shdr, name))
+			break;
+
+		offset = shdr.sh_offset;
+	} while (0);
+
+	elf_end(elf);
+	return offset;
+}
+
+struct table_entry {
+	u32 start_ip_offset;
+	u32 fde_offset;
+};
+
+struct eh_frame_hdr {
+	unsigned char version;
+	unsigned char eh_frame_ptr_enc;
+	unsigned char fde_count_enc;
+	unsigned char table_enc;
+
+	/*
+	 * The rest of the header is variable-length and consists of the
+	 * following members:
+	 *
+	 *	encoded_t eh_frame_ptr;
+	 *	encoded_t fde_count;
+	 */
+
+	/* A single encoded pointer should not be more than 8 bytes. */
+	u64 enc[2];
+
+	/*
+	 * struct {
+	 *    encoded_t start_ip;
+	 *    encoded_t fde_addr;
+	 * } binary_search_table[fde_count];
+	 */
+	char data[0];
+} __packed;
+
+static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
+			       u64 offset, u64 *table_data, u64 *segbase,
+			       u64 *fde_count)
+{
+	struct eh_frame_hdr hdr;
+	u8 *enc = (u8 *) &hdr.enc;
+	u8 *end = (u8 *) &hdr.data;
+	ssize_t r;
+
+	r = dso__data_read_offset(dso, machine, offset,
+				  (u8 *) &hdr, sizeof(hdr));
+	if (r != sizeof(hdr))
+		return -EINVAL;
+
+	/* We dont need eh_frame_ptr, just skip it. */
+	dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
+
+	*fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
+	*segbase    = offset;
+	*table_data = (enc - (u8 *) &hdr) + offset;
+	return 0;
+}
+
+static int read_unwind_spec(struct dso *dso, struct machine *machine,
+			    u64 *table_data, u64 *segbase, u64 *fde_count)
+{
+	int ret = -EINVAL, fd;
+	u64 offset;
+
+	fd = dso__data_fd(dso, machine);
+	if (fd < 0)
+		return -EINVAL;
+
+	offset = elf_section_offset(fd, ".eh_frame_hdr");
+	close(fd);
+
+	if (offset)
+		ret = unwind_spec_ehframe(dso, machine, offset,
+					  table_data, segbase,
+					  fde_count);
+
+	/* TODO .debug_frame check if eh_frame_hdr fails */
+	return ret;
+}
+
+static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
+{
+	struct addr_location al;
+
+	thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+			      MAP__FUNCTION, ip, &al);
+	return al.map;
+}
+
+static int
+find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+	       int need_unwind_info, void *arg)
+{
+	struct unwind_info *ui = arg;
+	struct map *map;
+	unw_dyn_info_t di;
+	u64 table_data, segbase, fde_count;
+
+	map = find_map(ip, ui);
+	if (!map || !map->dso)
+		return -EINVAL;
+
+	pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
+
+	if (read_unwind_spec(map->dso, ui->machine,
+			     &table_data, &segbase, &fde_count))
+		return -EINVAL;
+
+	memset(&di, 0, sizeof(di));
+	di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
+	di.start_ip = map->start;
+	di.end_ip   = map->end;
+	di.u.rti.segbase    = map->start + segbase;
+	di.u.rti.table_data = map->start + table_data;
+	di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
+			      / sizeof(unw_word_t);
+	return dwarf_search_unwind_table(as, ip, &di, pi,
+					 need_unwind_info, arg);
+}
+
+static int access_fpreg(unw_addr_space_t __maybe_unused as,
+			unw_regnum_t __maybe_unused num,
+			unw_fpreg_t __maybe_unused *val,
+			int __maybe_unused __write,
+			void __maybe_unused *arg)
+{
+	pr_err("unwind: access_fpreg unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
+				  unw_word_t __maybe_unused *dil_addr,
+				  void __maybe_unused *arg)
+{
+	return -UNW_ENOINFO;
+}
+
+static int resume(unw_addr_space_t __maybe_unused as,
+		  unw_cursor_t __maybe_unused *cu,
+		  void __maybe_unused *arg)
+{
+	pr_err("unwind: resume unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int
+get_proc_name(unw_addr_space_t __maybe_unused as,
+	      unw_word_t __maybe_unused addr,
+		char __maybe_unused *bufp, size_t __maybe_unused buf_len,
+		unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
+{
+	pr_err("unwind: get_proc_name unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
+			  unw_word_t *data)
+{
+	struct addr_location al;
+	ssize_t size;
+
+	thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+			      MAP__FUNCTION, addr, &al);
+	if (!al.map) {
+		pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+		return -1;
+	}
+
+	if (!al.map->dso)
+		return -1;
+
+	size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+				   addr, (u8 *) data, sizeof(*data));
+
+	return !(size == sizeof(*data));
+}
+
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
+		     u64 sample_regs)
+{
+	int i, idx = 0;
+
+	if (!(sample_regs & (1 << id)))
+		return -EINVAL;
+
+	for (i = 0; i < id; i++) {
+		if (sample_regs & (1 << i))
+			idx++;
+	}
+
+	*valp = regs->regs[idx];
+	return 0;
+}
+
+static int access_mem(unw_addr_space_t __maybe_unused as,
+		      unw_word_t addr, unw_word_t *valp,
+		      int __write, void *arg)
+{
+	struct unwind_info *ui = arg;
+	struct stack_dump *stack = &ui->sample->user_stack;
+	unw_word_t start, end;
+	int offset;
+	int ret;
+
+	/* Don't support write, probably not needed. */
+	if (__write || !stack || !ui->sample->user_regs.regs) {
+		*valp = 0;
+		return 0;
+	}
+
+	ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
+			ui->sample_uregs);
+	if (ret)
+		return ret;
+
+	end = start + stack->size;
+
+	/* Check overflow. */
+	if (addr + sizeof(unw_word_t) < addr)
+		return -EINVAL;
+
+	if (addr < start || addr + sizeof(unw_word_t) >= end) {
+		ret = access_dso_mem(ui, addr, valp);
+		if (ret) {
+			pr_debug("unwind: access_mem %p not inside range %p-%p\n",
+				(void *)addr, (void *)start, (void *)end);
+			*valp = 0;
+			return ret;
+		}
+		return 0;
+	}
+
+	offset = addr - start;
+	*valp  = *(unw_word_t *)&stack->data[offset];
+	pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
+		 (void *)addr, (unsigned long)*valp, offset);
+	return 0;
+}
+
+static int access_reg(unw_addr_space_t __maybe_unused as,
+		      unw_regnum_t regnum, unw_word_t *valp,
+		      int __write, void *arg)
+{
+	struct unwind_info *ui = arg;
+	int id, ret;
+
+	/* Don't support write, I suspect we don't need it. */
+	if (__write) {
+		pr_err("unwind: access_reg w %d\n", regnum);
+		return 0;
+	}
+
+	if (!ui->sample->user_regs.regs) {
+		*valp = 0;
+		return 0;
+	}
+
+	id = unwind__arch_reg_id(regnum);
+	if (id < 0)
+		return -EINVAL;
+
+	ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
+	if (ret) {
+		pr_err("unwind: can't read reg %d\n", regnum);
+		return ret;
+	}
+
+	pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
+	return 0;
+}
+
+static void put_unwind_info(unw_addr_space_t __maybe_unused as,
+			    unw_proc_info_t *pi __maybe_unused,
+			    void *arg __maybe_unused)
+{
+	pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int entry(u64 ip, struct thread *thread, struct machine *machine,
+		 unwind_entry_cb_t cb, void *arg)
+{
+	struct unwind_entry e;
+	struct addr_location al;
+
+	thread__find_addr_location(thread, machine,
+				   PERF_RECORD_MISC_USER,
+				   MAP__FUNCTION, ip, &al, NULL);
+
+	e.ip = ip;
+	e.map = al.map;
+	e.sym = al.sym;
+
+	pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+		 al.sym ? al.sym->name : "''",
+		 ip,
+		 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+	return cb(&e, arg);
+}
+
+static void display_error(int err)
+{
+	switch (err) {
+	case UNW_EINVAL:
+		pr_err("unwind: Only supports local.\n");
+		break;
+	case UNW_EUNSPEC:
+		pr_err("unwind: Unspecified error.\n");
+		break;
+	case UNW_EBADREG:
+		pr_err("unwind: Register unavailable.\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static unw_accessors_t accessors = {
+	.find_proc_info		= find_proc_info,
+	.put_unwind_info	= put_unwind_info,
+	.get_dyn_info_list_addr	= get_dyn_info_list_addr,
+	.access_mem		= access_mem,
+	.access_reg		= access_reg,
+	.access_fpreg		= access_fpreg,
+	.resume			= resume,
+	.get_proc_name		= get_proc_name,
+};
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+		       void *arg)
+{
+	unw_addr_space_t addr_space;
+	unw_cursor_t c;
+	int ret;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (!addr_space) {
+		pr_err("unwind: Can't create unwind address space.\n");
+		return -ENOMEM;
+	}
+
+	ret = unw_init_remote(&c, addr_space, ui);
+	if (ret)
+		display_error(ret);
+
+	while (!ret && (unw_step(&c) > 0)) {
+		unw_word_t ip;
+
+		unw_get_reg(&c, UNW_REG_IP, &ip);
+		ret = entry(ip, ui->thread, ui->machine, cb, arg);
+	}
+
+	unw_destroy_addr_space(addr_space);
+	return ret;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			struct machine *machine, struct thread *thread,
+			u64 sample_uregs, struct perf_sample *data)
+{
+	unw_word_t ip;
+	struct unwind_info ui = {
+		.sample       = data,
+		.sample_uregs = sample_uregs,
+		.thread       = thread,
+		.machine      = machine,
+	};
+	int ret;
+
+	if (!data->user_regs.regs)
+		return -EINVAL;
+
+	ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
+	if (ret)
+		return ret;
+
+	ret = entry(ip, thread, machine, cb, arg);
+	if (ret)
+		return -ENOMEM;
+
+	return get_entries(&ui, cb, arg);
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
new file mode 100644
index 0000000..a78c8b3
--- /dev/null
+++ b/tools/perf/util/unwind.h
@@ -0,0 +1,35 @@
+#ifndef __UNWIND_H
+#define __UNWIND_H
+
+#include "types.h"
+#include "event.h"
+#include "symbol.h"
+
+struct unwind_entry {
+	struct map	*map;
+	struct symbol	*sym;
+	u64		ip;
+};
+
+typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
+
+#ifndef NO_LIBUNWIND_SUPPORT
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			struct machine *machine,
+			struct thread *thread,
+			u64 sample_uregs,
+			struct perf_sample *data);
+int unwind__arch_reg_id(int regnum);
+#else
+static inline int
+unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
+		    void *arg __maybe_unused,
+		    struct machine *machine __maybe_unused,
+		    struct thread *thread __maybe_unused,
+		    u64 sample_uregs __maybe_unused,
+		    struct perf_sample *data __maybe_unused)
+{
+	return 0;
+}
+#endif /* NO_LIBUNWIND_SUPPORT */
+#endif /* __UNWIND_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index d03599f..2055cf3 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,6 +1,11 @@
 #include "../perf.h"
 #include "util.h"
 #include <sys/mman.h>
+#ifndef NO_BACKTRACE
+#include <execinfo.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
 
 /*
  * XXX We need to find a better place for these things...
@@ -158,3 +163,23 @@
 
 	return n;
 }
+
+/* Obtain a backtrace and print it to stdout. */
+#ifndef NO_BACKTRACE
+void dump_stack(void)
+{
+	void *array[16];
+	size_t size = backtrace(array, ARRAY_SIZE(array));
+	char **strings = backtrace_symbols(array, size);
+	size_t i;
+
+	printf("Obtained %zd stack frames.\n", size);
+
+	for (i = 0; i < size; i++)
+		printf("%s\n", strings[i]);
+
+	free(strings);
+}
+#else
+void dump_stack(void) {}
+#endif
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b13c733..70fa70b 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -69,13 +69,8 @@
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <sys/select.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 #include <inttypes.h>
-#include "../../../include/linux/magic.h"
+#include <linux/magic.h>
 #include "types.h"
 #include <sys/ttydefaults.h>
 
@@ -266,4 +261,6 @@
 
 char *rtrim(char *s);
 
+void dump_stack(void);
+
 #endif
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
new file mode 100644
index 0000000..e60951f
--- /dev/null
+++ b/tools/perf/util/vdso.c
@@ -0,0 +1,111 @@
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <linux/kernel.h>
+
+#include "vdso.h"
+#include "util.h"
+#include "symbol.h"
+#include "linux/string.h"
+
+static bool vdso_found;
+static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
+
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		pr_err("vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
+
+	fclose(maps);
+	return !found;
+}
+
+static char *get_file(void)
+{
+	char *vdso = NULL;
+	char *buf = NULL;
+	void *start, *end;
+	size_t size;
+	int fd;
+
+	if (vdso_found)
+		return vdso_file;
+
+	if (find_vdso_map(&start, &end))
+		return NULL;
+
+	size = end - start;
+
+	buf = memdup(start, size);
+	if (!buf)
+		return NULL;
+
+	fd = mkstemp(vdso_file);
+	if (fd < 0)
+		goto out;
+
+	if (size == (size_t) write(fd, buf, size))
+		vdso = vdso_file;
+
+	close(fd);
+
+ out:
+	free(buf);
+
+	vdso_found = (vdso != NULL);
+	return vdso;
+}
+
+void vdso__exit(void)
+{
+	if (vdso_found)
+		unlink(vdso_file);
+}
+
+struct dso *vdso__dso_findnew(struct list_head *head)
+{
+	struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
+
+	if (!dso) {
+		char *file;
+
+		file = get_file();
+		if (!file)
+			return NULL;
+
+		dso = dso__new(VDSO__MAP_NAME);
+		if (dso != NULL) {
+			dsos__add(head, dso);
+			dso__set_long_name(dso, file);
+		}
+	}
+
+	return dso;
+}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
new file mode 100644
index 0000000..0f76e7c
--- /dev/null
+++ b/tools/perf/util/vdso.h
@@ -0,0 +1,18 @@
+#ifndef __PERF_VDSO__
+#define __PERF_VDSO__
+
+#include <linux/types.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+static inline bool is_vdso_map(const char *filename)
+{
+	return !strcmp(filename, VDSO__MAP_NAME);
+}
+
+struct dso *vdso__dso_findnew(struct list_head *head);
+void vdso__exit(void);
+
+#endif /* __PERF_VDSO__ */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 73e900e..19f15b6 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -7,7 +7,8 @@
  * There's no pack memory to release - but stay close to the Git
  * version so wrap this away:
  */
-static inline void release_pack_memory(size_t size __used, int flag __used)
+static inline void release_pack_memory(size_t size __maybe_unused,
+				       int flag __maybe_unused)
 {
 }
 
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index bde8521..96ce80a 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -1,6 +1,8 @@
 ifeq ("$(origin O)", "command line")
-	OUTPUT := $(O)/
-	COMMAND_O := O=$(O)
+	dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
+	ABSOLUTE_O := $(shell cd $(O) ; pwd)
+	OUTPUT := $(ABSOLUTE_O)/
+	COMMAND_O := O=$(ABSOLUTE_O)
 endif
 
 ifneq ($(OUTPUT),)
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf
index 323a552c..63a1a83 100644
--- a/tools/testing/ktest/examples/include/defaults.conf
+++ b/tools/testing/ktest/examples/include/defaults.conf
@@ -33,7 +33,7 @@
 THIS_DIR := ${PWD}
 
 
-# to orginize your configs, having each machine save their configs
+# to organize your configs, having each machine save their configs
 # into a separate directly is useful.
 CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE}
 
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf
index 4fdb811..60cedb1 100644
--- a/tools/testing/ktest/examples/include/tests.conf
+++ b/tools/testing/ktest/examples/include/tests.conf
@@ -47,7 +47,7 @@
 # Build, install, boot and test with a randconfg 10 times.
 # It is important that you have set MIN_CONFIG in the config
 # that includes this file otherwise it is likely that the
-# randconfig will not have the neccessary configs needed to
+# randconfig will not have the necessary configs needed to
 # boot your box. This version of the test requires a min
 # config that has enough to make sure the target has network
 # working.
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 52b7959..c05bcd2 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -840,7 +840,9 @@
 
 		if ($rest =~ /\sIF\s+(.*)/) {
 		    # May be a ELSE IF section.
-		    if (!process_if($name, $1)) {
+		    if (process_if($name, $1)) {
+			$if_set = 1;
+		    } else {
 			$skip = 1;
 		    }
 		    $rest = "";
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index 8b40bd5..4c53cae 100644
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -36,7 +36,7 @@
 mount -t hugetlbfs none $mnt
 
 echo "--------------------"
-echo "runing hugepage-mmap"
+echo "running hugepage-mmap"
 echo "--------------------"
 ./hugepage-mmap
 if [ $? -ne 0 ]; then
@@ -50,7 +50,7 @@
 echo 268435456 > /proc/sys/kernel/shmmax
 echo 4194304 > /proc/sys/kernel/shmall
 echo "--------------------"
-echo "runing hugepage-shm"
+echo "running hugepage-shm"
 echo "--------------------"
 ./hugepage-shm
 if [ $? -ne 0 ]; then
@@ -62,7 +62,7 @@
 echo $shmall > /proc/sys/kernel/shmall
 
 echo "--------------------"
-echo "runing map_hugetlb"
+echo "running map_hugetlb"
 echo "--------------------"
 ./map_hugetlb
 if [ $? -ne 0 ]; then
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index b0adb27..68d0734 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -253,9 +253,6 @@
 
 	if (flag != FTW_F)
 		return 0;
-	/* ignore /proc/bus/usb/{devices,drivers} */
-	if (strrchr(name, '/')[1] == 'd')
-		return 0;
 
 	fd = fopen(name, "rb");
 	if (!fd) {
@@ -356,28 +353,8 @@
 
 static const char *usbfs_dir_find(void)
 {
-	static char usbfs_path_0[] = "/dev/usb/devices";
-	static char usbfs_path_1[] = "/proc/bus/usb/devices";
 	static char udev_usb_path[] = "/dev/bus/usb";
 
-	static char *const usbfs_paths[] = {
-		usbfs_path_0, usbfs_path_1
-	};
-
-	static char *const *
-		end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths;
-
-	char *const *it = usbfs_paths;
-	do {
-		int fd = open(*it, O_RDONLY);
-		close(fd);
-		if (fd >= 0) {
-			strrchr(*it, '/')[0] = '\0';
-			return *it;
-		}
-	} while (++it != end);
-
-	/* real device-nodes managed by udev */
 	if (access(udev_usb_path, F_OK) == 0)
 		return udev_usb_path;
 
@@ -489,7 +466,7 @@
 		goto usage;
 	if (!all && !device) {
 		fprintf (stderr, "must specify '-a' or '-D dev', "
-			"or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
+			"or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
 		goto usage;
 	}